diff -Nru a/Documentation/driver-model/binding.txt b/Documentation/driver-model/binding.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/driver-model/binding.txt	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,102 @@
+
+Driver Binding
+
+Driver binding is the process of associating a device with a device
+driver that can control it. Bus drivers have typically handled this
+because there have been bus-specific structures to represent the
+devices and the drivers. With generic device and device driver
+structures, most of the binding can take place using common code.
+
+
+Bus
+~~~
+
+The bus type structure contains a list of all devices that on that bus
+type in the system. When device_register is called for a device, it is
+inserted into the end of this list. The bus object also contains a
+list of all drivers of that bus type. When driver_register is called
+for a driver, it is inserted into the end of this list. These are the
+two events which trigger driver binding.
+
+
+device_register
+~~~~~~~~~~~~~~~
+
+When a new device is added, the bus's list of drivers is iterated over
+to find one that supports it. In order to determine that, the device
+ID of the device must match one of the device IDs that the driver
+supports. The format and semantics for comparing IDs is bus-specific. 
+Instead of trying to derive a complex state machine and matching
+algorithm, it is up to the bus driver to provide a callback to compare
+a device against the IDs of a driver. The bus returns 1 if a match was
+found; 0 otherwise.
+
+int match(struct device * dev, struct device_driver * drv);
+
+If a match is found, the device's driver field is set to the driver
+and the driver's probe callback is called. This gives the driver a
+chance to verify that it really does support the hardware, and that
+it's in a working state. 
+
+Device Class
+~~~~~~~~~~~~
+
+Upon the successful completion of probe, the device is registered with
+the class to which it belongs. Device drivers belong to one and only
+class, and that is set in the driver's devclass field. 
+devclass_add_device is called to enumerate the device within the class
+and actually register it with the class, which happens with the
+class's register_dev callback.
+
+NOTE: The device class structures and core routines to manipulate them
+are not in the mainline kernel, so the discussion is still a bit
+speculative. 
+
+
+Driver
+~~~~~~
+
+When a driver is attached to a device, the device is inserted into the
+driver's list of devices. 
+
+
+driverfs
+~~~~~~~~
+
+A symlink is created in the bus's 'devices' directory that points to
+the device's directory in the physical hierarchy.
+
+A symlink is created in the driver's 'devices' directory that points
+to the device's directory in the physical hierarchy.
+
+A directory for the device is created in the class's directory. A
+symlink is created in that directory that points to the device's
+physical location in the driverfs tree. 
+
+A symlink can be created (though this isn't done yet) in the device's
+physical directory to either its class directory, or the class's
+top-level directory. One can also be created to point to its driver's
+directory also. 
+
+
+driver_register
+~~~~~~~~~~~~~~~
+
+The process is almost identical for when a new driver is added. 
+The bus's list of devices is iterated over to find a match. Devices
+that already have a driver are skipped. All the devices are iterated
+over, to bind as many devices as possible to the driver.
+
+
+Removal
+~~~~~~~
+
+When a device is removed, the reference count for it will eventually
+go to 0. When it does, the remove callback of the driver is called. It
+is removed from the driver's list of devices and the reference count
+of the driver is decremented. All symlinks between the two are removed.
+
+When a driver is removed, the list of devices that it supports is
+iterated over, and the driver's remove callback is called for each
+one. The device is removed from that list and the symlinks removed. 
+
diff -Nru a/Documentation/driver-model/bus.txt b/Documentation/driver-model/bus.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/driver-model/bus.txt	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,192 @@
+
+Bus Types 
+
+Definition
+~~~~~~~~~~
+
+struct bus_type {
+        char                    * name;
+        rwlock_t                lock;
+        atomic_t                refcount;
+
+        struct list_head        node;
+        struct list_head        devices;
+        struct list_head        drivers;
+
+        struct driver_dir_entry dir;
+        struct driver_dir_entry device_dir;
+        struct driver_dir_entry driver_dir;
+
+        int     (*match)        (struct device * dev, struct device_driver * drv);
+	struct device (*add)	(struct device * parent, char * bus_id);
+};
+
+int bus_register(struct bus_type * bus);
+
+
+Declaration
+~~~~~~~~~~~
+
+Each bus type in the kernel (PCI, USB, etc) should declare one static
+object of this type. They must initialize the name field, and may
+optionally initialize the match callback.
+
+struct bus_type pci_bus_type = {
+       name:	"pci",
+       match:	pci_bus_match,
+};
+
+The structure should be exported to drivers in a header file:
+
+extern struct bus_type pci_bus_type;
+
+
+Registration
+~~~~~~~~~~~~
+
+When a bus driver is initialized, it calls bus_register. This
+initializes the rest of the fields in the bus object and inserts it
+into a global list of bus types. Once the bus object is registered, 
+the fields in it (e.g. the rwlock_t) are usable by the bus driver. 
+
+
+Callbacks
+~~~~~~~~~
+
+match(): Attaching Drivers to Devices
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The format of device ID structures and the semantics for comparing
+them are inherently bus-specific. Drivers typically declare an array
+of device IDs of device they support that reside in a bus-specific
+driver structure. 
+
+The purpose of the match callback is provide the bus an opportunity to
+determine if a particular driver supports a particular device by
+comparing the device IDs the driver supports with the device ID of a
+particular device, without sacrificing bus-specific functionality or
+type-safety. 
+
+When a driver is registered with the bus, the bus's list of devices is
+iterated over, and the match callback is called for each device that
+does not have a driver associated with it. 
+
+add(): Adding a child device
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The add callback is available to notify the bus about a child device
+at a particular location. 
+
+The parent parameter is the parent device of the child to be added. If
+parent == NULL, the bus should add the device as a child of a default
+parent device or as a child of the root. This policy decision is up to
+the bus driver.
+
+The format of the bus_id field should be consistent with the format of
+the bus_id field of the rest of the devices on the bus. This requires
+the caller to know the format.
+
+On return, the bus driver should return a pointer to the device that
+was created. If the device was not created, the bus driver should
+return an appropriate error code. Refer to include/linux/err.h for
+helper functions to encode errors. Some sample code:
+
+struct device * pci_bus_add(struct device * parent, char * bus_id)
+{
+	...
+	/* the device already exists */
+	return ERR_PTR(-EEXIST);
+	...
+}
+
+The caller can check the return value using IS_ERR():
+
+    struct device * newdev = pci_bus_type.add(parent,bus_id);
+    if (IS_ERR(newdev)) {
+	...
+    }
+
+
+Device and Driver Lists
+~~~~~~~~~~~~~~~~~~~~~~~
+
+The lists of devices and drivers are intended to replace the local
+lists that many buses keep. They are lists of struct devices and
+struct device_drivers, respectively. Bus drivers are free to use the
+lists as they please, but conversion to the bus-specific type may be
+necessary. 
+
+The LDM core provides helper functions for iterating over each list.
+
+int bus_for_each_dev(struct bus_type * bus, void * data, 
+		     int (*callback)(struct device * dev, void * data));
+int bus_for_each_drv(struct bus_type * bus, void * data,
+		     int (*callback)(struct device_driver * drv, void * data));
+
+These helpers iterate over the respective list, and call the callback
+for each device or driver in the list. All list accesses are
+synchronized by taking the bus's lock (read currently). The reference
+count on each object in the list is incremented before the callback is
+called; it is decremented after the next object has been obtained. The
+lock is not held when calling the callback. 
+
+
+driverfs
+~~~~~~~~
+There is a top-level directory named 'bus'.
+
+Each bus gets a directory in the bus directory, along with two default
+directories:
+
+	/sys/bus/pci/
+	|-- devices
+	`-- drivers
+
+Drivers registered with the bus get a directory in the bus's drivers
+directory:
+
+	/sys/bus/pci/
+	|-- devices
+	`-- drivers
+	    |-- Intel ICH
+	    |-- Intel ICH Joystick
+	    |-- agpgart
+	    `-- e100
+
+Each device that is discovered a bus of that type gets a symlink in
+the bus's devices directory to the device's directory in the physical
+hierarchy:
+
+	/sys/bus/pci/
+	|-- devices
+	|   |-- 00:00.0 -> ../../../root/pci0/00:00.0
+	|   |-- 00:01.0 -> ../../../root/pci0/00:01.0
+	|   `-- 00:02.0 -> ../../../root/pci0/00:02.0
+	`-- drivers
+
+
+Exporting Attributes
+~~~~~~~~~~~~~~~~~~~~
+struct bus_attribute {
+        struct attribute        attr;
+        ssize_t (*show)(struct bus_type *, char * buf, size_t count, loff_t off);
+        ssize_t (*store)(struct bus_type *, const char * buf, size_t count, loff_t off);
+};
+
+Bus drivers can export attributes using the BUS_ATTR macro that works
+similarly to the DEVICE_ATTR macro for devices. For example, a definition 
+like this:
+
+static BUS_ATTR(debug,0644,show_debug,store_debug);
+
+is equivalent to declaring:
+
+static bus_attribute bus_attr_debug;
+
+This can then be used to add and remove the attribute from the bus's
+driverfs directory using:
+
+int bus_create_file(struct bus_type *, struct bus_attribute *);
+void bus_remove_file(struct bus_type *, struct bus_attribute *);
+
+
diff -Nru a/Documentation/driver-model/class.txt b/Documentation/driver-model/class.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/driver-model/class.txt	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,162 @@
+
+Device Classes
+
+
+Introduction
+~~~~~~~~~~~~
+A device class describes a type of device, like an audio or network
+device. The following device classes have been identified:
+
+<Insert List of Device Classes Here>
+
+
+Each device class defines a set of semantics and a programming interface
+that devices of that class adhere to. Device drivers are the
+implemention of that programming interface for a particular device on
+a particular bus. 
+
+Device classes are agnostic with respect to what bus a device resides
+on. 
+
+
+Programming Interface
+~~~~~~~~~~~~~~~~~~~~~
+The device class structure looks like: 
+
+
+typedef int (*devclass_add)(struct device *);
+typedef void (*devclass_remove)(struct device *);
+
+struct device_class {
+	char			* name;
+	rwlock_t		lock;
+	u32			devnum;
+	struct list_head	node;
+
+	struct list_head	drivers;
+	struct list_head	intf_list;
+
+	struct driver_dir_entry	dir;
+	struct driver_dir_entry	device_dir;
+	struct driver_dir_entry	driver_dir;
+
+	devclass_add		add_device;
+	devclass_remove		remove_device;
+};
+
+A typical device class definition would look like: 
+
+struct device_class input_devclass = {
+        .name		= "input",
+        .add_device	= input_add_device,
+	.remove_device	= input_remove_device,
+};
+
+Each device class structure should be exported in a header file so it
+can be used by drivers, extensions and interfaces.
+
+Device classes are registered and unregistered with the core using: 
+
+int devclass_register(struct device_class * cls);
+void devclass_unregister(struct device_class * cls);
+
+
+Devices
+~~~~~~~
+As devices are bound to drivers, they are added to the device class
+that the driver belongs to. Before the driver model core, this would
+typically happen during the driver's probe() callback, once the device
+has been initialized. It now happens after the probe() callback
+finishes from the core. 
+
+The device is enumerated in the class. Each time a device is added to
+the class, the class's devnum field is incremented and assigned to the
+device. The field is never decremented, so if the device is removed
+from the class and re-added, it will receive a different enumerated
+value. 
+
+The class is allowed to create a class-specific structure for the
+device and store it in the device's class_data pointer. 
+
+There is no list of devices in the device class. Each driver has a
+list of devices that it supports. The device class has a list of
+drivers of that particular class. To access all of the devices in the
+class, iterate over the device lists of each driver in the class.
+
+
+Device Drivers
+~~~~~~~~~~~~~~
+Device drivers are added to device classes when they are registered
+with the core. A driver specifies the class it belongs to by setting
+the struct device_driver::devclass field. 
+
+
+driverfs directory structure
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+There is a top-level driverfs directory named 'class'. 
+
+Each class gets a directory in the class directory, along with two
+default subdirectories:
+
+        class/
+        `-- input
+            |-- devices
+            `-- drivers
+
+
+Drivers registered with the class get a symlink in the drivers/ directory 
+that points the driver's directory (under its bus directory):
+
+   class/
+   `-- input
+       |-- devices
+       `-- drivers
+           `-- usb:usb_mouse -> ../../../bus/drivers/usb_mouse/
+
+
+Each device gets a symlink in the devices/ directory that points to the 
+device's directory in the physical hierarchy:
+
+   class/
+   `-- input
+       |-- devices
+       |   `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/
+       `-- drivers
+
+
+Exporting Attributes
+~~~~~~~~~~~~~~~~~~~~
+struct devclass_attribute {
+        struct attribute        attr;
+        ssize_t (*show)(struct device_class *, char * buf, size_t count, loff_t off);
+        ssize_t (*store)(struct device_class *, const char * buf, size_t count, loff_t off);
+};
+
+Class drivers can export attributes using the DEVCLASS_ATTR macro that works
+similarly to the DEVICE_ATTR macro for devices. For example, a definition 
+like this:
+
+static DEVCLASS_ATTR(debug,0644,show_debug,store_debug);
+
+is equivalent to declaring:
+
+static devclass_attribute devclass_attr_debug;
+
+The bus driver can add and remove the attribute from the class's
+driverfs directory using:
+
+int devclass_create_file(struct device_class *, struct devclass_attribute *);
+void devclass_remove_file(struct device_class *, struct devclass_attribute *);
+
+In the example above, the file will be named 'debug' in placed in the
+class's directory in driverfs. 
+
+
+Interfaces
+~~~~~~~~~~
+There may exist multiple mechanisms for accessing the same device of a
+particular class type. Device interfaces describe these mechanisms. 
+
+When a device is added to a device class, the core attempts to add it
+to every interface that is registered with the device class.
+
diff -Nru a/Documentation/driver-model/device.txt b/Documentation/driver-model/device.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/driver-model/device.txt	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,152 @@
+
+The Basic Device Structure
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+struct device {
+        struct list_head g_list;
+        struct list_head node;
+        struct list_head bus_list;
+        struct list_head driver_list;
+        struct list_head intf_list;
+        struct list_head children;
+        struct device   * parent;
+
+        char    name[DEVICE_NAME_SIZE];
+        char    bus_id[BUS_ID_SIZE];
+
+        spinlock_t      lock;
+        atomic_t        refcount;
+
+        struct bus_type * bus;
+        struct driver_dir_entry dir;
+
+	u32		class_num;
+
+        struct device_driver *driver;
+        void            *driver_data;
+        void            *platform_data;
+
+        u32             current_state;
+        unsigned char *saved_state;
+
+        void    (*release)(struct device * dev);
+};
+
+Fields 
+~~~~~~
+g_list:	Node in the global device list.
+
+node:	Node in device's parent's children list.
+
+bus_list: Node in device's bus's devices list.
+
+driver_list:   Node in device's driver's devices list.
+
+intf_list:     List of intf_data. There is one structure allocated for
+	       each interface that the device supports.
+
+children:      List of child devices.
+
+name:	       ASCII description of device. 
+	       Example: " 3Com Corporation 3c905 100BaseTX [Boomerang]"
+
+bus_id:	       ASCII representation of device's bus position. This 
+	       field should a name unique across all devices on the
+	       bus type the device belongs to. 
+
+	       Example: PCI bus_ids are in the form of
+	       <bus number>:<slot number>.<function number> 
+	       This name is unique across all PCI devices in the system.
+
+lock:	       Spinlock for the device. 
+
+refcount:      Reference count on the device.
+
+bus:	       Pointer to struct bus_type that device belongs to.
+
+dir:	       Device's driverfs directory.
+
+driver:	       Pointer to struct device_driver that controls the device.
+
+driver_data:   Driver-specific data.
+
+class_num:     Class-enumerated value of the device.
+
+platform_data: Platform data specific to the device.
+
+current_state: Current power state of the device.
+
+saved_state:   Pointer to saved state of the device. This is usable by
+	       the device driver controlling the device.
+
+release:       Callback to free the device after all references have 
+	       gone away. This should be set by the allocator of the 
+	       device (i.e. the bus driver that discovered the device).
+
+
+Programming Interface
+~~~~~~~~~~~~~~~~~~~~~
+The bus driver that discovers the device uses this to register the
+device with the core:
+
+int device_register(struct device * dev);
+
+The bus should initialize the following fields:
+
+    - parent
+    - name
+    - bus_id
+    - bus
+
+A device is removed from the core when its reference count goes to
+0. The reference count can be adjusted using:
+
+struct device * get_device(struct device * dev);
+void put_device(struct device * dev);
+
+get_device() will return a pointer to the struct device passed to it
+if the reference is not already 0 (if it's in the process of being
+removed already).
+
+A driver can take use the lock in the device structure using: 
+
+void lock_device(struct device * dev);
+void unlock_device(struct device * dev);
+
+
+Attributes
+~~~~~~~~~~
+struct device_attribute {
+        struct attribute        attr;
+        ssize_t (*show)(struct device * dev, char * buf, size_t count, loff_t off);
+        ssize_t (*store)(struct device * dev, const char * buf, size_t count, loff_t off);
+};
+
+Attributes of devices can be exported via drivers using a simple
+procfs-like interface. 
+
+Please see Documentation/filesystems/driverfs.txt for more information
+on how driverfs works.
+
+Attributes are declared using a macro called DEVICE_ATTR:
+
+#define DEVICE_ATTR(name,mode,show,store)
+
+Example:
+
+DEVICE_ATTR(power,0644,show_power,store_power);
+
+This declares a structure of type struct device_attribute named
+'dev_attr_power'. This can then be added and removed to the device's
+directory using:
+
+int device_create_file(struct device *device, struct device_attribute * entry);
+void device_remove_file(struct device * dev, struct device_attribute * attr);
+
+Example:
+
+device_create_file(dev,&dev_attr_power);
+device_remove_file(dev,&dev_attr_power);
+
+The file name will be 'power' with a mode of 0644 (-rw-r--r--).
+
diff -Nru a/Documentation/driver-model/driver.txt b/Documentation/driver-model/driver.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/driver-model/driver.txt	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,287 @@
+
+Device Drivers
+
+struct device_driver {
+        char                    * name;
+        struct bus_type         * bus;
+
+        rwlock_t                lock;
+        atomic_t                refcount;
+
+        list_t                  bus_list;
+        list_t                  devices;
+
+        struct driver_dir_entry dir;
+
+        int     (*probe)        (struct device * dev);
+        int     (*remove)       (struct device * dev);
+
+        int     (*suspend)      (struct device * dev, u32 state, u32 level);
+        int     (*resume)       (struct device * dev, u32 level);
+
+        void    (*release)      (struct device_driver * drv);
+};
+
+
+
+Allocation
+~~~~~~~~~~
+
+Device drivers are statically allocated structures. Though there may
+be multiple devices in a system that a driver supports, struct
+device_driver represents the driver as a whole (not a particular
+device instance).
+
+Initialization
+~~~~~~~~~~~~~~
+
+The driver must initialize at least the name and bus fields. It should
+also initalize the devclass field (when it arrives), so it may obtain
+the proper linkage internally. It should also initialize as many of
+the callbacks as possible, though each is optional.
+
+Declaration
+~~~~~~~~~~~
+
+As stated above, struct device_driver objects are statically
+allocated. Below is an example declaration of the eepro100
+driver. This declaration is hypothetical only; it relies on the driver
+being converted completely to the new model. 
+
+static struct device_driver eepro100_driver = {
+       name:		"eepro100",
+       bus:		&pci_bus_type,
+       devclass:	&ethernet_devclass,	/* when it's implemented */
+       
+       probe:		eepro100_probe,
+       remove:		eepro100_remove,
+       suspend:		eepro100_suspend,
+       resume:		eepro100_resume,
+};
+
+Most drivers will not be able to be converted completely to the new
+model because the bus they belong to has a bus-specific structure with
+bus-specific fields that cannot be generalized. 
+
+The most common example this are device ID structures. A driver
+typically defines an array of device IDs that it supports. The format
+of this structure and the semantics for comparing device IDs is
+completely bus-specific. Defining them as bus-specific entities would
+sacrifice type-safety, so we keep bus-specific structures around. 
+
+Bus-specific drivers should include a generic struct device_driver in
+the definition of the bus-specific driver. Like this:
+
+struct pci_driver {
+       const struct pci_device_id *id_table;
+       struct device_driver	  driver;
+};
+
+A definition that included bus-specific fields would look something
+like (using the eepro100 driver again):
+
+static struct pci_driver eepro100_driver = {
+       id_table:       eepro100_pci_tbl,
+       driver:	       {
+		name:		"eepro100",
+		bus:		&pci_bus_type,
+		devclass:	&ethernet_devclass,	/* when it's implemented */
+		probe:		eepro100_probe,
+		remove:		eepro100_remove,
+		suspend:		eepro100_suspend,
+		resume:		eepro100_resume,
+       },
+};
+
+Some may find the syntax of embedded struct intialization awkward or
+even a bit ugly. So far, it's the best way we've found to do what we want...
+
+Registration
+~~~~~~~~~~~~
+
+int driver_register(struct device_driver * drv);
+
+The driver registers the structure on startup. For drivers that have
+no bus-specific fields (i.e. don't have a bus-specific driver
+structure), they would use driver_register and pass a pointer to their
+struct device_driver object. 
+
+Most drivers, however, will have a bus-specific structure and will
+need to register with the bus using something like pci_driver_register.
+
+It is important that drivers register their drivers as early as
+possible. Registration with the core initializes several fields in the
+struct device_driver object, including the reference count and the
+lock. These fields are assumed to be valid at all times and may be
+used by the device model core or the bus driver.
+
+
+Transition Bus Drivers
+~~~~~~~~~~~~~~~~~~~~~~
+
+By defining wrapper functions, the transition to the new model can be
+made easier. Drivers can ignore the generic structure altogether and
+let the bus wrapper fill in the fields. For the callbacks, the bus can
+define generic callbacks that forward the call to the bus-specific
+callbacks of the drivers. 
+
+This solution is intended to be only temporary. In order to get class
+information in the driver, the drivers must be modified anyway. Since
+converting drivers to the new model should reduce some infrastructural
+complexity and code size, it is recommended that they are converted as
+class information is added.
+
+Access
+~~~~~~
+
+Once the object has been registered, it may access the common fields of
+the object, like the lock and the list of devices. 
+
+int driver_for_each_dev(struct device_driver * drv, void * data, 
+		        int (*callback)(struct device * dev, void * data));
+
+The devices field is a list of all the devices that have been bound to
+the driver. The LDM core provides a helper function to operate on all
+the devices a driver controls. This helper locks the driver on each
+node access, and does proper reference counting on each device as it
+accesses it. 
+
+
+driverfs
+~~~~~~~~
+
+When a driver is registered, a driverfs directory is created in its
+bus's directory. In this directory, the driver can export an interface
+to userspace to control operation of the driver on a global basis;
+e.g. toggling debugging output in the driver.
+
+A future feature of this directory will be a 'devices' directory. This
+directory will contain symlinks to the directories of devices it
+supports.
+
+
+
+Callbacks
+~~~~~~~~~
+
+	int	(*probe)	(struct device * dev);
+
+probe is called to verify the existence of a certain type of
+hardware. This is called during the driver binding process, after the
+bus has verified that the device ID of a device matches one of the
+device IDs supported by the driver. 
+
+This callback only verifies that there actually is supported hardware
+present. It may allocate a driver-specific structure, but it should
+not do any initialization of the hardware itself. The device-specific
+structure may be stored in the device's driver_data field. 
+
+	int	(*init)		(struct device * dev);
+
+init is called during the binding stage. It is called after probe has
+successfully returned and the device has been registered with its
+class. It is responsible for initializing the hardware.
+
+	int 	(*remove)	(struct device * dev);
+
+remove is called to dissociate a driver with a device. This may be
+called if a device is physically removed from the system, if the
+driver module is being unloaded, or during a reboot sequence. 
+
+It is up to the driver to determine if the device is present or
+not. It should free any resources allocated specifically for the
+device; i.e. anything in the device's driver_data field. 
+
+If the device is still present, it should quiesce the device and place
+it into a supported low-power state.
+
+	int	(*suspend)	(struct device * dev, u32 state, u32 level);
+
+suspend is called to put the device in a low power state. There are
+several stages to sucessfully suspending a device, which is denoted in
+the @level parameter. Breaking the suspend transition into several
+stages affords the platform flexibility in performing device power
+management based on the requirements of the system and the
+user-defined policy.
+
+SUSPEND_NOTIFY notifies the device that a suspend transition is about
+to happen. This happens on system power state transition to verify
+that all devices can sucessfully suspend.
+
+A driver may choose to fail on this call, which should cause the
+entire suspend transition to fail. A driver should fail only if it
+knows that the device will not be able to be resumed properly when the
+system wakes up again. It could also fail if it somehow determines it
+is in the middle of an operation too important to stop.
+
+SUSPEND_DISABLE tells the device to stop I/O transactions. When it
+stops transactions, or what it should do with unfinished transactions
+is a policy of the driver. After this call, the driver should not
+accept any other I/O requests.
+
+SUSPEND_SAVE_STATE tells the device to save the context of the
+hardware. This includes any bus-specific hardware state and
+device-specific hardware state. A pointer to this saved state can be
+stored in the device's saved_state field.
+
+SUSPEND_POWER_DOWN tells the driver to place the device in the low
+power state requested. 
+
+Whether suspend is called with a given level is a policy of the
+platform. Some levels may be omitted; drivers must not assume the
+reception of any level. However, all levels must be called in the
+order above; i.e. notification will always come before disabling;
+disabling the device will come before suspending the device.
+
+All calls are made with interrupts enabled, except for the
+SUSPEND_POWER_DOWN level.
+
+	int	(*resume)	(struct device * dev, u32 level);
+
+Resume is used to bring a device back from a low power state. Like the
+suspend transition, it happens in several stages. 
+
+RESUME_POWER_ON tells the driver to set the power state to the state
+before the suspend call (The device could have already been in a low
+power state before the suspend call to put in a lower power state). 
+
+RESUME_RESTORE_STATE tells the driver to restore the state saved by
+the SUSPEND_SAVE_STATE suspend call. 
+
+RESUME_ENABLE tells the driver to start accepting I/O transactions
+again. Depending on driver policy, the device may already have pending
+I/O requests. 
+
+RESUME_POWER_ON is called with interrupts disabled. The other resume
+levels are called with interrupts enabled. 
+
+As with the various suspend stages, the driver must not assume that
+any other resume calls have been or will be made. Each call should be
+self-contained and not dependent on any external state.
+
+
+Attributes
+~~~~~~~~~~
+struct driver_attribute {
+        struct attribute        attr;
+        ssize_t (*show)(struct device_driver *, char * buf, size_t count, loff_t off);
+        ssize_t (*store)(struct device_driver *, const char * buf, size_t count, loff_t off);
+};
+
+Device drivers can export attributes via their driverfs directories. 
+Drivers can declare attributes using a DRIVER_ATTR macro that works
+identically to the DEVICE_ATTR macro. 
+
+Example:
+
+DRIVER_ATTR(debug,0644,show_debug,store_debug);
+
+This is equivalent to declaring:
+
+struct driver_attribute driver_attr_debug;
+
+This can then be used to add and remove the attribute from the
+driver's directory using:
+
+int driver_create_file(struct device_driver *, struct driver_attribute *);
+void driver_remove_file(struct device_driver *, struct driver_attribute *);
diff -Nru a/Documentation/driver-model/interface.txt b/Documentation/driver-model/interface.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/driver-model/interface.txt	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,129 @@
+
+Device Interfaces
+
+Introduction
+~~~~~~~~~~~~
+
+Device interfaces are the logical interfaces of device classes that correlate
+directly to userspace interfaces, like device nodes. 
+   
+Each device class may have multiple interfaces through which you can 
+access the same device. An input device may support the mouse interface, 
+the 'evdev' interface, and the touchscreen interface. A SCSI disk would 
+support the disk interface, the SCSI generic interface, and possibly a raw 
+device interface. 
+
+Device interfaces are registered with the class they belong to. As devices
+are added to the class, they are added to each interface registered with
+the class. The interface is responsible for determining whether the device
+supports the interface or not. 
+
+
+Programming Interface
+~~~~~~~~~~~~~~~~~~~~~
+
+struct device_interface {
+	char			* name;
+	rwlock_t		lock;
+	u32			devnum;
+	struct device_class	* devclass;
+
+	struct list_head	node;
+	struct driver_dir_entry	dir;
+
+	int (*add_device)(struct device *);
+	int (*add_device)(struct intf_data *);
+};
+
+int interface_register(struct device_interface *);
+void interface_unregister(struct device_interface *);
+
+
+An interface must specify the device class it belongs to. It is added
+to that class's list of interfaces on registration.
+
+
+Interfaces can be added to a device class at any time. Whenever it is
+added, each device in the class is passed to the interface's
+add_device callback. When an interface is removed, each device is
+removed from the interface.
+
+
+Devices
+~~~~~~~
+Once a device is added to a device class, it is added to each
+interface that is registered with the device class. The class
+is expected to place a class-specific data structure in 
+struct device::class_data. The interface can use that (along with
+other fields of struct device) to determine whether or not the driver
+and/or device support that particular interface.
+
+
+Data
+~~~~
+
+struct intf_data {
+	struct list_head	node;
+	struct device_interface	* intf;
+	struct device 		* dev;
+	u32			intf_num;
+};
+
+int interface_add_data(struct interface_data *);
+
+The interface is responsible for allocating and initializing a struct 
+intf_data and calling interface_add_data() to add it to the device's list
+of interfaces it belongs to. This list will be iterated over when the device
+is removed from the class (instead of all possible interfaces for a class).
+This structure should probably be embedded in whatever per-device data 
+structure the interface is allocating anyway.
+   
+Devices are enumerated within the interface. This happens in interface_add_data()
+and the enumerated value is stored in the struct intf_data for that device. 
+
+driverfs
+~~~~~~~~
+Each interface is given a directory in the directory of the device
+class it belongs to:
+
+Interfaces get a directory in the class's directory as well:
+
+   class/
+   `-- input
+       |-- devices
+       |-- drivers
+       |-- mouse
+       `-- evdev
+
+When a device is added to the interface, a symlink is created that points 
+to the device's directory in the physical hierarchy:
+
+   class/
+   `-- input
+       |-- devices
+       |   `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/
+       |-- drivers
+       |   `-- usb:usb_mouse -> ../../../bus/drivers/usb_mouse/
+       |-- mouse
+       |   `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/
+       `-- evdev
+           `-- 1 -> ../../../root/pci0/00:1f.0/usb_bus/00:1f.2-1:0/
+
+
+Future Plans
+~~~~~~~~~~~~
+A device interface is correlated directly with a userspace interface
+for a device, specifically a device node. For instance, a SCSI disk
+exposes at least two interfaces to userspace: the standard SCSI disk
+interface and the SCSI generic interface. It might also export a raw
+device interface. 
+
+Many interfaces have a major number associated with them and each
+device gets a minor number. Or, multiple interfaces might share one
+major number, and each get receive a range of minor numbers (like in
+the case of input devices).
+
+These major and minor numbers could be stored in the interface
+structure. Major and minor allocation could happen when the interface
+is registered with the class, or via a helper function. 
+
diff -Nru a/Documentation/driver-model/overview.txt b/Documentation/driver-model/overview.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/driver-model/overview.txt	Fri Sep 20 08:20:44 2002
@@ -0,0 +1,114 @@
+The Linux Kernel Device Model
+
+Patrick Mochel	<mochel@osdl.org>
+
+26 August 2002
+
+
+Overview
+~~~~~~~~
+
+This driver model is a unification of all the current, disparate driver models
+that are currently in the kernel. It is intended is to augment the
+bus-specific drivers for bridges and devices by consolidating a set of data
+and operations into globally accessible data structures.
+
+Current driver models implement some sort of tree-like structure (sometimes
+just a list) for the devices they control. But, there is no linkage between
+the different bus types.
+
+A common data structure can provide this linkage with little overhead: when a
+bus driver discovers a particular device, it can insert it into the global
+tree as well as its local tree. In fact, the local tree becomes just a subset
+of the global tree.
+
+Common data fields can also be moved out of the local bus models into the
+global model. Some of the manipulation of these fields can also be
+consolidated. Most likely, manipulation functions will become a set
+of helper functions, which the bus drivers wrap around to include any
+bus-specific items.
+
+The common device and bridge interface currently reflects the goals of the
+modern PC: namely the ability to do seamless Plug and Play, power management,
+and hot plug. (The model dictated by Intel and Microsoft (read: ACPI) ensures
+us that any device in the system may fit any of these criteria.)
+
+In reality, not every bus will be able to support such operations. But, most
+buses will support a majority of those operations, and all future buses will.
+In other words, a bus that doesn't support an operation is the exception,
+instead of the other way around.
+
+
+
+Downstream Access
+~~~~~~~~~~~~~~~~~
+
+Common data fields have been moved out of individual bus layers into a common
+data structure. But, these fields must still be accessed by the bus layers,
+and sometimes by the device-specific drivers.
+
+Other bus layers are encouraged to do what has been done for the PCI layer.
+struct pci_dev now looks like this:
+
+struct pci_dev {
+	...
+
+	struct device device;
+};
+
+Note first that it is statically allocated. This means only one allocation on
+device discovery. Note also that it is at the _end_ of struct pci_dev. This is
+to make people think about what they're doing when switching between the bus
+driver and the global driver; and to prevent against mindless casts between
+the two.
+
+The PCI bus layer freely accesses the fields of struct device. It knows about
+the structure of struct pci_dev, and it should know the structure of struct
+device. PCI devices that have been converted generally do not touch the fields
+of struct device. More precisely, device-specific drivers should not touch
+fields of struct device unless there is a strong compelling reason to do so.
+
+This abstraction is prevention of unnecessary pain during transitional phases.
+If the name of the field changes or is removed, then every downstream driver
+will break. On the other hand, if only the bus layer (and not the device
+layer) accesses struct device, it is only those that need to change.
+
+
+User Interface
+~~~~~~~~~~~~~~
+
+By virtue of having a complete hierarchical view of all the devices in the
+system, exporting a complete hierarchical view to userspace becomes relatively
+easy. This has been accomplished by implementing a special purpose virtual
+file system named driverfs. It is hence possible for the user to mount the
+whole driverfs filesystem anywhere in userspace.
+
+This can be done permanently by providing the following entry into the
+/etc/fstab (under the provision that the mount point does exist, of course):
+
+none     	/devices	driverfs    defaults		0	0
+
+Or by hand on the command line:
+
+~: mount -t driverfs none /devices
+
+Whenever a device is inserted into the tree, a directory is created for it.
+This directory may be populated at each layer of discovery - the global layer,
+the bus layer, or the device layer.
+
+The global layer currently creates two files - name and 'power'. The
+former only reports the name of the device. The latter reports the
+current power state of the device. It also be used to set the current
+power state. 
+
+The bus layer may also create files for the devices it finds while probing the
+bus. For example, the PCI layer currently creates 'irq' and 'resource' files
+for each PCI device.
+
+A device-specific driver may also export files in its directory to expose
+device-specific data or tunable interfaces.
+
+More information about the driverfs directory layout can be found in
+the other documents in this directory and in the file 
+Documentation/filesystems/driverfs.txt.
+
diff -Nru a/Documentation/driver-model/platform.txt b/Documentation/driver-model/platform.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/driver-model/platform.txt	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,99 @@
+Platform Devices and Drivers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Platform devices
+~~~~~~~~~~~~~~~~
+Platform devices are devices that typically appear as autonomous
+entities in the system. This includes legacy port-based devices and
+host bridges to peripheral buses. 
+
+
+Platform drivers
+~~~~~~~~~~~~~~~~
+Drivers for platform devices have typically very simple and
+unstructured. Either the device was present at a particular I/O port
+and the driver was loaded, or there was not. There was no possibility
+of hotplugging or alternative discovery besides probing at a specific
+I/O address and expecting a specific response.
+
+
+Other Architectures, Modern Firmware, and new Platforms
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+These devices are not always at the legacy I/O ports. This is true on
+other architectures and on some modern architectures. In most cases,
+the drivers are modified to discover the devices at other well-known
+ports for the given platform. However, the firmware in these systems
+does usually know where exactly these devices reside, and in some
+cases, it's the only way of discovering them. 
+
+
+The Platform Bus
+~~~~~~~~~~~~~~~~
+A platform bus has been created to deal with these issues. First and
+foremost, it groups all the legacy devices under a common bus, and
+gives them a common parent if they don't already have one. 
+
+But, besides the organizational benefits, the platform bus can also
+accomodate firmware-based enumeration. 
+
+
+Device Discovery
+~~~~~~~~~~~~~~~~
+The platform bus has no concept of probing for devices. Devices
+discovery is left up to either the legacy drivers or the
+firmware. These entities are expected to notify the platform of
+devices that it discovers via the bus's add() callback:
+
+	platform_bus.add(parent,bus_id).
+
+
+Bus IDs
+~~~~~~~
+Bus IDs are the canonical name for the device. There is no globally
+standard addressing mechanism for legacy devices. In the IA-32 world,
+we have Pnp IDs to use, as well as the legacy I/O ports. However,
+neither tell what the device really is or have any meaning on other
+platforms. 
+
+Since both PnP IDs and the legacy I/O ports (and other standard I/O
+ports for specific devices) have a 1:1 mapping, we map the
+platform-specific name or identifier to a generic name (at least
+within the scope of the kernel).
+
+For example, a serial driver might find a device at I/O 0x3f8. The
+ACPI firmware might also discover a device with PnP ID (_HID)
+PNP0501. Both correspond to the same device should be mapped to the
+canonical name 'serial'. 
+
+The bus_id field should be a concatenation of the canonical name and
+the instance of that type of device. For example, the device at I/O
+port 0x3f8 should have a bus_id of "serial0". This places the
+responsibility of enumerating devices of a particular type up to the
+discovery mechanism. But, they are the entity that should know best
+(as opposed to the platform bus driver).
+
+
+Drivers 
+~~~~~~~
+Drivers for platform devices should have a name that is the same as
+the canonical name of the devices they support. This allows the
+platform bus driver to do simple matching with the basic data
+structures to determine if a driver supports a certain device. 
+
+For example, a legacy serial driver should have a name of 'serial' and
+register itself with the platform bus. 
+
+
+Driver Binding
+~~~~~~~~~~~~~~
+Legacy drivers assume they are bound to the device once they start up
+and probe an I/O port. Divorcing them from this will be a difficult
+process. However, that shouldn't prevent us from impelementing
+firmware-based enumeration. 
+
+The firmware should notify the platform bus about devices before the
+legacy drivers have had a chance to load. Once the drivers are loaded,
+they driver model core will attempt to bind the driver to any
+previously-discovered devices. Once that has happened, it will be free
+to discover any other devices it pleases.
+
diff -Nru a/Documentation/driver-model.txt b/Documentation/driver-model.txt
--- a/Documentation/driver-model.txt	Fri Sep 20 08:20:44 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,624 +0,0 @@
-The (New) Linux Kernel Driver Model
-
-Version 0.04
-
-Patrick Mochel	<mochel@osdl.org>
-
-03 December 2001
-
-
-Overview
-~~~~~~~~
-
-This driver model is a unification of all the current, disparate driver models
-that are currently in the kernel. It is intended is to augment the
-bus-specific drivers for bridges and devices by consolidating a set of data
-and operations into globally accessible data structures.
-
-Current driver models implement some sort of tree-like structure (sometimes
-just a list) for the devices they control. But, there is no linkage between
-the different bus types.
-
-A common data structure can provide this linkage with little overhead: when a
-bus driver discovers a particular device, it can insert it into the global
-tree as well as its local tree. In fact, the local tree becomes just a subset
-of the global tree.
-
-Common data fields can also be moved out of the local bus models into the
-global model. Some of the manipulation of these fields can also be
-consolidated. Most likely, manipulation functions will become a set
-of helper functions, which the bus drivers wrap around to include any
-bus-specific items.
-
-The common device and bridge interface currently reflects the goals of the
-modern PC: namely the ability to do seamless Plug and Play, power management,
-and hot plug. (The model dictated by Intel and Microsoft (read: ACPI) ensures
-us that any device in the system may fit any of these criteria.)
-
-In reality, not every bus will be able to support such operations. But, most
-buses will support a majority of those operations, and all future buses will.
-In other words, a bus that doesn't support an operation is the exception,
-instead of the other way around.
-
-
-Drivers
-~~~~~~~
-
-The callbacks for bridges and devices are intended to be singular for a
-particular type of bus. For each type of bus that has support compiled in the
-kernel, there should be one statically allocated structure with the
-appropriate callbacks that each device (or bridge) of that type share.
-
-Each bus layer should implement the callbacks for these drivers. It then
-forwards the calls on to the device-specific callbacks. This means that
-device-specific drivers must still implement callbacks for each operation.
-But, they are not called from the top level driver layer. [So for example
-PCI devices will not call device_register but pci_device_register.]
-
-This does add another layer of indirection for calling one of these functions,
-but there are benefits that are believed to outweigh this slowdown.
-
-First, it prevents device-specific drivers from having to know about the
-global device layer. This speeds up integration time incredibly. It also
-allows drivers to be more portable across kernel versions. Note that the
-former was intentional, the latter is an added bonus. 
-
-Second, this added indirection allows the bus to perform any additional logic
-necessary for its child devices. A bus layer may add additional information to
-the call, or translate it into something meaningful for its children.
-
-This could be done in the driver, but if it happens for every object of a
-particular type, it is best done at a higher level.
-
-Recap
-~~~~~
-
-Instances of devices and bridges are allocated dynamically as the system
-discovers their existence. Their fields describe the individual object.
-Drivers - in the global sense - are statically allocated and singular for a
-particular type of bus. They describe a set of operations that every type of
-bus could implement, the implementation following the bus's semantics.
-
-
-Downstream Access
-~~~~~~~~~~~~~~~~~
-
-Common data fields have been moved out of individual bus layers into a common
-data structure. But, these fields must still be accessed by the bus layers,
-and sometimes by the device-specific drivers.
-
-Other bus layers are encouraged to do what has been done for the PCI layer.
-struct pci_dev now looks like this:
-
-struct pci_dev {
-	...
-
-	struct device device;
-};
-
-Note first that it is statically allocated. This means only one allocation on
-device discovery. Note also that it is at the _end_ of struct pci_dev. This is
-to make people think about what they're doing when switching between the bus
-driver and the global driver; and to prevent against mindless casts between
-the two.
-
-The PCI bus layer freely accesses the fields of struct device. It knows about
-the structure of struct pci_dev, and it should know the structure of struct
-device. PCI devices that have been converted generally do not touch the fields
-of struct device. More precisely, device-specific drivers should not touch
-fields of struct device unless there is a strong compelling reason to do so.
-
-This abstraction is prevention of unnecessary pain during transitional phases.
-If the name of the field changes or is removed, then every downstream driver
-will break. On the other hand, if only the bus layer (and not the device
-layer) accesses struct device, it is only those that need to change.
-
-
-User Interface
-~~~~~~~~~~~~~~
-
-By virtue of having a complete hierarchical view of all the devices in the
-system, exporting a complete hierarchical view to userspace becomes relatively
-easy. This has been accomplished by implementing a special purpose virtual
-file system named driverfs. It is hence possible for the user to mount the
-whole driverfs on a particular mount point in the unified UNIX file hierarchy.
-
-This can be done permanently by providing the following entry into the
-/dev/fstab (under the provision that the mount point does exist, of course):
-
-none     	/devices	driverfs    defaults		0	0
-
-Or by hand on the command line:
-
-~: mount -t driverfs none /devices
-
-Whenever a device is inserted into the tree, a directory is created for it.
-This directory may be populated at each layer of discovery - the global layer,
-the bus layer, or the device layer.
-
-The global layer currently creates two files - 'status' and 'power'. The
-former only reports the name of the device and its bus ID. The latter reports
-the current power state of the device. It also be used to set the current
-power state.
-
-The bus layer may also create files for the devices it finds while probing the
-bus. For example, the PCI layer currently creates 'wake' and 'resource' files
-for each PCI device.
-
-A device-specific driver may also export files in its directory to expose
-device-specific data or tunable interfaces.
-
-These features were initially implemented using procfs. However, after one
-conversation with Linus, a new filesystem - driverfs - was created to
-implement these features. It is an in-memory filesystem, based heavily off of
-ramfs, though it uses procfs as inspiration for its callback functionality.
-
-Each struct device has a 'struct driver_dir_entry' which encapsulates the
-device's directory and the files within.
-
-Device Structures
-~~~~~~~~~~~~~~~~~
-
-struct device {
-	struct list_head 	bus_list;
-	struct iobus		*parent;
-	struct iobus		*subordinate;
-
-	char    		name[DEVICE_NAME_SIZE];
-	char    		bus_id[BUS_ID_SIZE];
-
-	struct driver_dir_entry	* dir;
-
-	spinlock_t		lock;
-	atomic_t		refcount;
-
-	struct device_driver 	*driver;
-	void            	*driver_data;
-	void    		*platform_data;
-
-	u32             	current_state;
-	unsigned char 		*saved_state;
-};
-
-bus_list:
-	List of all devices on a particular bus; i.e. the device's siblings
-
-parent:
-	The parent bridge for the device.
-
-subordinate:
-	If the device is a bridge itself, this points to the struct io_bus that is
-	created for it.
-
-name:
-	Human readable (descriptive) name of device. E.g. "Intel EEPro 100"
-
-bus_id:
-	Parsable (yet ASCII) bus id. E.g. "00:04.00" (PCI Bus 0, Device 4, Function
-	0). It is necessary to have a searchable bus id for each device; making it
-	ASCII allows us to use it for its directory name without translating it.
-
-dir:
-	Driver's driverfs directory.
-
-lock:
-	Driver specific lock.
-
-refcount:
-	Driver's usage count.
-	When this goes to 0, the device is assumed to be removed. It will be removed
-	from its parent's list of children. It's remove() callback will be called to
-	inform the driver to clean up after itself.
-
-driver:
-	Pointer to a struct device_driver, the common operations for each device. See
-	next section.
-
-driver_data:
-	Private data for the driver.
-	Much like the PCI implementation of this field, this allows device-specific
-	drivers to keep a pointer to a device-specific data.
-
-platform_data:
-	Data that the platform (firmware) provides about the device.
-	For example, the ACPI BIOS or EFI may have additional information about the
-	device that is not directly mappable to any existing kernel data structure.
-	It also allows the platform driver (e.g. ACPI) to a driver without the driver
-	having to have explicit knowledge of (atrocities like) ACPI.
-
-current_state:
-	Current power state of the device. For PCI and other modern devices, this is
-	0-3, though it's not necessarily limited to those values.
-
-saved_state:
-	Pointer to driver-specific set of saved state.
-	Having it here allows modules to be unloaded on system suspend and reloaded
-	on resume and maintain state across transitions.
-	It also allows generic drivers to maintain state across system state
-	transitions.
-	(I've implemented a generic PCI driver for devices that don't have a
-	device-specific driver. Instead of managing some vector of saved state
-	for each device the generic driver supports, it can simply store it here.)
-
-
-
-struct device_driver {
-        int     (*probe)        (struct device *dev);
-        int     (*remove)       (struct device *dev);
-
-        int     (*suspend)      (struct device *dev, u32 state, u32 level);
-        int     (*resume)       (struct device *dev, u32 level);
-}
-
-probe:
-	Check for device existence and associate driver with it. In case of device 
-	insertion, *all* drivers are called. Struct device has parent and bus_id 
-	valid at this point. probe() may only be called from process context. Returns
-	0 if it handles that device, -ESRCH if this driver does not know how to handle
-	this device, valid error otherwise.
-
-remove:
-	Dissociate driver with device. Releases device so that it could be used by
-	another driver. Also, if it is a hotplug device (hotplug PCI, Cardbus), an
-	ejection event could take place here. remove() can be called from interrupt 
-	context. [Fixme: Is that good?] Returns 0 on success. [Can we recover from
-	failed remove or should I define that remove() never fails?]
-
-suspend:
-	Perform one step of the device suspend process. Returns 0 on success.
-
-resume:
-	Perform one step of the device resume process. Returns 0 on success.
-
-The probe() and remove() callbacks are intended to be much simpler than the
-current PCI correspondents.
-
-probe() should do the following only:
-
-- Check if hardware is present
-- Register device interface
-- Disable DMA/interrupts, etc, just in case.
-
-Some device initialisation was done in probe(). This should not be the case
-anymore. All initialisation should take place in the open() call for the
-device. [FIXME: How do you "open" uhci?]
-
-Breaking initialisation code out must also be done for the resume() callback,
-as most devices will have to be completely reinitialised when coming back from
-a suspend state.
-
-remove() should simply unregister the device interface.
-
-
-Device power management can be quite complicated, based exactly what is
-desired to be done. Four operations sum up most of it:
-
-- OS directed power management.
-  The OS takes care of notifying all drivers that a suspend is requested,
-  saving device state, and powering devices down.
-- Firmware controlled power management.
-  The OS only wants to notify devices that a suspend is requested.
-- Device power management.
-  A user wants to place only one device in a low power state, and maybe save
-  state.
-- System reboot.
-  The system wants to place devices in a quiescent state before the system is
-  reset.
-
-In an attempt to please all of these scenarios, the power management
-transition for any device is broken up into several stages - notify, save
-state, and power down. The disable stage, which should happen after notify and
-before save state has been considered and may be implemented in the future.
-
-Depending on what the system-wide policy is (usually dictated by the power
-management scheme present), each driver's suspend callback may be called
-multiple times, each with a different stage.
-
-On all power management transitions, the stages should be called sequentially
-(notify before save state; save state before power down). However, drivers
-should not assume that any stage was called before hand. (If a driver gets a
-power down call, it shouldn't assume notify or save state was called first.)
-This allows the framework to be used seamlessly by all power management
-actions. Hopefully.
-
-Resume transitions happen in a similar manner. They are broken up into two
-stages currently (power on and restore state), though a third stage (enable)
-may be added later.
-
-For suspend and resume transitions, the following values are defined to denote
-the stage:
-
-enum{
-	SUSPEND_NOTIFY,
-	SUSPEND_DISABLE,
-	SUSPEND_SAVE_STATE,
-	SUSPEND_POWER_DOWN,
-};
-
-enum {
-	RESUME_POWER_ON,
-	RESUME_RESTORE_STATE,
-	RESUME_ENABLE,
-};
-
-
-During a system power transition, the device tree must be walked in order,
-calling the suspend() or resume() callback for each node. This may happen
-several times.
-
-Initially, this was done in kernel space. However, it has occurred to me that
-doing recursion to a non-bounded depth is dangerous, and that there are a lot
-of inherent race conditions in such an operation.
-
-Non-recursive walking of the device tree is possible. However, this makes for
-convoluted code.
-
-No matter what, if the transition happens in kernel space, it is difficult to
-gracefully recover from errors or to implement a policy that prevents one from
-shutting down the device(s) you want to save state to.
-
-Instead, the walking of the device tree has been moved to userspace. When a
-user requests the system to suspend, it will walk the device tree, as exported
-via driverfs, and tell each device to go to sleep. It will do this multiple
-times based on what the system policy is. [Not possible. Take ACPI enabled 
-system, with battery critically low. In such state, you want to suspend-to-disk,
-*fast*. User maybe is not even running powerd (think system startup)!]
-
-Device resume should happen in the same manner when the system awakens.
-
-Each suspend stage is described below:
-
-SUSPEND_NOTIFY:
-
-This level to notify the driver that it is going to sleep. If it knows that it
-cannot resume the hardware from the requested level, or it feels that it is
-too important to be put to sleep, it should return an error from this function.
-
-It does not have to stop I/O requests or actually save state at this point. Called
-from process context.
-
-SUSPEND_DISABLE:
-
-The driver should stop taking I/O requests at this stage. Because the save
-state stage happens afterwards, the driver may not want to physically disable
-the device; only mark itself unavailable if possible. Called from process 
-context.
-
-SUSPEND_SAVE_STATE:
-
-The driver should allocate memory and save any device state that is relevant
-for the state it is going to enter. Called from process context.
-
-SUSPEND_POWER_DOWN:
-
-The driver should place the device in the power state requested. May be called
-from interrupt context.
-
-
-For resume, the stages are defined as follows:
-
-RESUME_POWER_ON:
-
-Devices should be powered on and reinitialised to some known working state.
-Called from process context.
-
-RESUME_RESTORE_STATE:
-
-The driver should restore device state to its pre-suspend state and free any
-memory allocated for its saved state. Called from process context.
-
-RESUME_ENABLE:
-
-The device should start taking I/O requests again. Called from process context.
-
-
-Each driver does not have to implement each stage. But, it if it does
-implement a stage, it should do what is described above. It should not assume
-that it performed any stage previously, or that it will perform any stage
-later. [Really? It makes sense to support SAVE_STATE only after DISABLE].
-
-It is quite possible that a driver can fail during the suspend process, for
-whatever reason. In this event, the calling process must gracefully recover
-and restore everything to their states before the suspend transition began. 
-[Suspend may not fail, think battery low.]
-
-If a driver knows that it cannot suspend or resume properly, it should fail
-during the notify stage. Properly implemented power management schemes should
-make sure that this is the first stage that is called.
-
-If a driver gets a power down request, it should obey it, as it may very
-likely be during a reboot.
-
-
-Bus Structures
-~~~~~~~~~~~~~~
-
-struct iobus {
-	struct	list_head 	node;
-	struct 	iobus 		*parent;
-	struct 	list_head 	children;
-	struct 	list_head 	devices;
-
-	struct 	list_head 	bus_list;
-
-	spinlock_t		lock;
-	atomic_t		refcount;
-
-	struct 	device 		*self;
-	struct	driver_dir_entry * dir;
-
-	char    name[DEVICE_NAME_SIZE];
-	char    bus_id[BUS_ID_SIZE];
-
-	struct  bus_driver	*driver;
-};
-
-node:
-	Bus's node in sibling list (its parent's list of child buses).
-
-parent:
-	Pointer to parent bridge.
-
-children:
-	List of subordinate buses.
-	In the children, this correlates to their 'node' field.
-
-devices:
-	List of devices on the bus this bridge controls.
-	This field corresponds to the 'bus_list' field in each child device.
-
-bus_list:
-	Each type of bus keeps a list of all bridges that it finds. This is the
-	bridges entry in that list.
-
-self:
-	Pointer to the struct device for this bridge.
-
-lock:
-	Lock for the bus.
-
-refcount:
-	Usage count for the bus.
-
-dir:
-	Driverfs directory.
-
-name:
-	Human readable ASCII name of bus.
-
-bus_id:
-	Machine readable (though ASCII) description of position on parent bus.
-
-driver:
-	Pointer to operations for bus.
-
-
-struct iobus_driver {
-	char    name[16];
-	struct  list_head node;
-
-	int     (*scan)         (struct io_bus*);
-	int     (*add_device)   (struct io_bus*, char*);
-};
-
-name:
-	ASCII name of bus.
-
-node:
-	List of buses of this type in system.
-
-scan:
-	Search the bus for new devices. This may happen either at boot - where every
-	device discovered will be new - or later on - in which there may only be a few
-	(or no) new devices.
-
-add_device:
-	Trigger a device insertion at a particular location.
-
-
-
-The API
-~~~~~~~
-
-There are several functions exported by the global device layer, including
-several optional helper functions, written solely to try and make your life
-easier.
-
-void device_init_dev(struct device * dev);
-
-Initialise a device structure. It first zeros the device, the initialises all
-of the lists. (Note that this would have been called device_init(), but that
-name was already taken. :/)
-
-
-struct device * device_alloc(void)
-
-Allocate memory for a device structure and initialise it.
-First, allocates memory, then calls device_init_dev() with the new pointer.
-
-
-int device_register(struct device * dev);
-
-Register a device with the global device layer.
-The bus layer should call this function upon device discovery, e.g. when
-probing the bus.
-dev should be fully initialised when this is called.
-If dev->parent is not set, it sets its parent to be the device root.
-It then does the following:
-	- inserts it into its parent's list of children
-	- creates a driverfs directory for it
-	- creates a set of default files for the device in its directory
-	- calls platform_notify() to notify the firmware driver of its existence.
-
-
-void get_device(struct device * dev);
-
-Increment the refcount for a device.
-
-
-int valid_device(struct device * dev);
-
-Check if reference count is positive for a device (it's not waiting to be
-freed). If it is positive, it increments the reference count for the device.
-It returns whether or not the device is usable.
-
-
-void put_device(struct device * dev);
-
-Decrement the reference count for the device. If it hits 0, it removes the
-device from its parent's list of children and calls the remove() callback for
-the device.
-
-
-void lock_device(struct device * dev);
-
-Take the spinlock for the device.
-
-
-void unlock_device(struct device * dev);
-
-Release the spinlock for the device.
-
-
-
-void 	iobus_init(struct iobus * iobus);
-struct 	iobus * iobus_alloc(void);
-int 	iobus_register(struct iobus * iobus);
-void	get_iobus(struct iobus * iobus);
-int	valid_iobus(struct iobus * iobus);
-void	put_iobus(struct iobus * iobus);
-void	lock_iobus(struct iobus * iobus);
-void	unlock_iobus(struct iobus * iobus);
-
-These functions provide the same functionality as the device_*
-counterparts, only operating on a struct iobus. One important thing to note,
-though is that iobus_register() and iobus_unregister() operate recursively. It
-is possible to add an entire tree in one call.
-
-
-
-int device_driver_init(void);
-
-Main initialisation routine.
-
-This makes sure driverfs is up and running and initialises the device tree.
-
-
-void device_driver_exit(void);
-
-This frees up the device tree.
-
-
-
-
-Credits
-~~~~~~~
-
-The following people have been extremely helpful in solidifying this document
-and the driver model.
-
-Randy Dunlap		rddunlap@osdl.org
-Jeff Garzik		jgarzik@mandrakesoft.com
-Ben Herrenschmidt	benh@kernel.crashing.org
-
-
diff -Nru a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
--- a/Documentation/filesystems/proc.txt	Fri Sep 20 08:20:44 2002
+++ b/Documentation/filesystems/proc.txt	Fri Sep 20 08:20:44 2002
@@ -963,13 +963,6 @@
 a process which is generating disk writes will itself start writing out dirty
 data.
 
-dirty_sync_ratio
-----------------
-
-Contains, as a percentage of total system memory, the number of pages at which
-a process which is generating disk writes will itself start writing out dirty
-data and waiting upon completion of that writeout.
-
 dirty_writeback_centisecs
 -------------------------
 
diff -Nru a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
--- a/Documentation/sysctl/vm.txt	Fri Sep 20 08:20:47 2002
+++ b/Documentation/sysctl/vm.txt	Fri Sep 20 08:20:47 2002
@@ -21,13 +21,12 @@
 - dirty_async_ratio
 - dirty_background_ratio
 - dirty_expire_centisecs
-- dirty_sync_ratio
 - dirty_writeback_centisecs
 
 ==============================================================
 
 dirty_async_ratio, dirty_background_ratio, dirty_expire_centisecs,
-dirty_sync_ratio dirty_writeback_centisecs:
+dirty_writeback_centisecs:
 
 See Documentation/filesystems/proc.txt
 
diff -Nru a/MAINTAINERS b/MAINTAINERS
--- a/MAINTAINERS	Fri Sep 20 08:20:47 2002
+++ b/MAINTAINERS	Fri Sep 20 08:20:47 2002
@@ -240,8 +240,8 @@
 S:	Maintained
 
 AX.25 NETWORK LAYER
-P:	Matthias Welwarsky
-M:	dg2fef@afthd.tu-darmstadt.de
+P:	Ralf Baechle
+M:	ralf@linux-mips.org
 L:	linux-hams@vger.kernel.org
 S:	Maintained
 
@@ -531,6 +531,14 @@
 L:	linux-eata@i-connect.net, linux-scsi@vger.kernel.org
 S:	Maintained
 
+EBTABLES
+P:	Bart De Schuymer
+M:	bart.de.schuymer@pandora.be
+L:	ebtables-user@lists.sourceforge.net
+L:	ebtables-devel@lists.sourceforge.net
+W:	http://ebtables.sourceforge.net/
+S:	Maintained
+
 EEPRO100 NETWORK DRIVER
 P:	Andrey V. Savochkin
 M:	saw@saw.sw.com.sg
@@ -733,12 +741,9 @@
 S:	Supported 
 
 IDE DRIVER [GENERAL]
-P:	Martin Dalecki
-M:	martin@dalecki.de
-I:	pl_PL.ISO8859-2, de_DE.ISO8859-15, (en_US.ISO8859-1)
 L:	linux-kernel@vger.kernel.org
-W:	http://www.dalecki.de
-S:	Developement
+L:	linux-ide@vger.kernel.org
+S:	Maintained
 
 IDE/ATAPI CDROM DRIVER
 P:	Jens Axboe
@@ -912,8 +917,6 @@
 S:	Maintained
 
 KERNEL BUILD (Makefile, Rules.make, scripts/*)
-P:	Keith Owens
-M:	kaos@ocs.com.au
 P:	Michael Elizabeth Chastain
 M:	mec@shout.net
 L:	kbuild-devel@lists.sourceforge.net
@@ -1056,12 +1059,6 @@
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
-MODULE SUPPORT [GENERAL], KMOD
-P:	Keith Owens
-M:	kaos@ocs.com.au
-L:	linux-kernel@vger.kernel.org
-S:	Maintained
-
 MOUSE AND MISC DEVICES [GENERAL]
 P:	Alessandro Rubini
 M:	rubini@ipvvis.unipv.it
@@ -1113,8 +1110,8 @@
 S:	Supported
 
 NETROM NETWORK LAYER
-P:	Tomi Manninen
-M:	Tomi.Manninen@hut.fi
+P:	Ralf Baechle
+M:	ralf@linux-mips.org
 L:	linux-hams@vger.kernel.org
 S:	Maintained
 
@@ -1363,8 +1360,8 @@
 S:	Supported
 
 ROSE NETWORK LAYER
-P:	Jean-Paul Roubelat
-M:	jpr@f6fbb.org
+P:	Ralf Baechle
+M:	ralf@linux-mips.org
 L:	linux-hams@vger.kernel.org
 S:	Maintained
 
diff -Nru a/Makefile b/Makefile
--- a/Makefile	Fri Sep 20 08:20:41 2002
+++ b/Makefile	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 5
-SUBLEVEL = 36
+SUBLEVEL = 37
 EXTRAVERSION =
 
 # *DOCUMENTATION*
@@ -162,8 +162,6 @@
 
 export srctree objtree
 
-SUBDIRS		:= init kernel mm fs ipc lib drivers sound net security
-
 # The temporary file to save gcc -MD generated dependencies must not
 # contain a comma
 depfile = $(subst $(comma),_,$(@D)/.$(@F).d)
@@ -246,15 +244,33 @@
 # Link components for vmlinux
 # ---------------------------------------------------------------------------
 
-INIT		:= init/init.o
-CORE_FILES	:= kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o security/built-in.o
-LIBS		:= lib/lib.a
-DRIVERS		:= drivers/built-in.o sound/sound.o
-NETWORKS	:= net/network.o
+init-y		:= init/
+drivers-y	:= drivers/ sound/
+networks-y	:= net/
+libs-y		:= lib/
+
+CORE_FILES	:= kernel/built-in.o mm/built-in.o fs/built-in.o \
+		   ipc/built-in.o security/built-in.o
+SUBDIRS		+= kernel mm fs ipc security
 
 include arch/$(ARCH)/Makefile
 
-export	NETWORKS DRIVERS LIBS HEAD LDFLAGS MAKEBOOT ASFLAGS
+SUBDIRS		+= $(patsubst %/,%,$(filter %/, $(init-y) $(init-m)))
+INIT		+= $(patsubst %/, %/built-in.o, $(init-y))
+
+SUBDIRS		+= $(patsubst %/,%,$(filter %/, $(core-y) $(core-m)))
+CORE_FILES	:= $(patsubst %/, %/built-in.o, $(core-y)) $(CORE_FILES)
+
+SUBDIRS		+= $(patsubst %/,%,$(filter %/, $(drivers-y) $(drivers-m)))
+DRIVERS		+= $(patsubst %/, %/built-in.o, $(drivers-y))
+
+SUBDIRS		+= $(patsubst %/,%,$(filter %/, $(networks-y) $(networks-m)))
+NETWORKS	+= $(patsubst %/, %/built-in.o, $(networks-y))
+
+SUBDIRS		+= $(patsubst %/,%,$(filter %/, $(libs-y) $(libs-m)))
+LIBS		+= $(patsubst %/, %/lib.a, $(libs-y))
+
+export	NETWORKS DRIVERS LIBS HEAD LDFLAGS MAKEBOOT
 
 # boot target
 # ---------------------------------------------------------------------------
diff -Nru a/arch/alpha/mm/numa.c b/arch/alpha/mm/numa.c
--- a/arch/alpha/mm/numa.c	Fri Sep 20 08:20:41 2002
+++ b/arch/alpha/mm/numa.c	Fri Sep 20 08:20:41 2002
@@ -286,7 +286,6 @@
 	for (nid = 0; nid < numnodes; nid++) {
 		unsigned long start_pfn = plat_node_bdata[nid].node_boot_start >> PAGE_SHIFT;
 		unsigned long end_pfn = plat_node_bdata[nid].node_low_pfn;
-		unsigned long lmax_mapnr;
 
 		if (dma_local_pfn >= end_pfn - start_pfn)
 			zones_size[ZONE_DMA] = end_pfn - start_pfn;
@@ -295,11 +294,6 @@
 			zones_size[ZONE_NORMAL] = (end_pfn - start_pfn) - dma_local_pfn;
 		}
 		free_area_init_node(nid, NODE_DATA(nid), NULL, zones_size, start_pfn, NULL);
-		lmax_mapnr = PLAT_NODE_DATA_STARTNR(nid) + PLAT_NODE_DATA_SIZE(nid);
-		if (lmax_mapnr > max_mapnr) {
-			max_mapnr = lmax_mapnr;
-			DBGDCONT("Grow max_mapnr to %ld\n", max_mapnr);
-		}
 	}
 
 	/* Initialize the kernel's ZERO_PGE. */
diff -Nru a/arch/i386/Makefile b/arch/i386/Makefile
--- a/arch/i386/Makefile	Fri Sep 20 08:20:44 2002
+++ b/arch/i386/Makefile	Fri Sep 20 08:20:44 2002
@@ -85,22 +85,21 @@
 CFLAGS += -march=i586
 endif
 
-HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o
-
-SUBDIRS += arch/i386/kernel arch/i386/mm arch/i386/lib
+ifdef CONFIG_VISWS
+MACHINE	:= mach-visws
+else
+MACHINE	:= mach-generic
+endif
 
-CORE_FILES := arch/i386/kernel/kernel.o arch/i386/mm/mm.o $(CORE_FILES)
-LIBS := $(TOPDIR)/arch/i386/lib/lib.a $(LIBS) $(TOPDIR)/arch/i386/lib/lib.a
+HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o
 
-ifdef CONFIG_MATH_EMULATION
-SUBDIRS += arch/i386/math-emu
-DRIVERS += arch/i386/math-emu/math.o
-endif
+libs-y 					+= arch/i386/lib/
+core-y					+= arch/i386/kernel/ arch/i386/mm/ arch/i386/$(MACHINE)/
+drivers-$(CONFIG_MATH_EMULATION)	+= arch/i386/math-emu/
+drivers-$(CONFIG_PCI)			+= arch/i386/pci/
 
-ifdef CONFIG_PCI
-SUBDIRS	+= arch/i386/pci
-DRIVERS	+= arch/i386/pci/pci.o
-endif
+CFLAGS += -I$(TOPDIR)/arch/i386/$(MACHINE)
+AFLAGS += -I$(TOPDIR)/arch/i386/$(MACHINE)
 
 MAKEBOOT = +$(MAKE) -C arch/$(ARCH)/boot
 
diff -Nru a/arch/i386/config.in b/arch/i386/config.in
--- a/arch/i386/config.in	Fri Sep 20 08:20:44 2002
+++ b/arch/i386/config.in	Fri Sep 20 08:20:44 2002
@@ -154,7 +154,7 @@
    define_bool CONFIG_X86_OOSTORE y
 fi
 
-bool 'IA-32 Huge TLB Page Support (if available on processor)' CONFIG_HUGETLB_PAGE
+bool 'Huge TLB Page Support' CONFIG_HUGETLB_PAGE
 
 bool 'Symmetric multi-processing support' CONFIG_SMP
 bool 'Preemptible Kernel' CONFIG_PREEMPT
@@ -260,6 +260,7 @@
    if [ "$CONFIG_SMP" = "y" ]; then
       define_bool CONFIG_X86_IO_APIC y
       define_bool CONFIG_X86_LOCAL_APIC y
+      define_bool CONFIG_X86_MPPARSE y
    fi
    bool 'PCI support' CONFIG_PCI
    if [ "$CONFIG_PCI" = "y" ]; then
@@ -437,7 +438,19 @@
    fi
 fi
 
+if [ "$CONFIG_X86_LOCAL_APIC" = "y" ]; then
+   define_bool CONFIG_X86_EXTRA_IRQS y
+   define_bool CONFIG_X86_FIND_SMP_CONFIG y
+fi
+
 endmenu
 
 source security/Config.in
 source lib/Config.in
+
+if [ "$CONFIG_SMP" = "y" ]; then
+   define_bool CONFIG_X86_SMP y
+   define_bool CONFIG_X86_HT y
+fi
+
+define_bool CONFIG_X86_BIOS_REBOOT y
diff -Nru a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
--- a/arch/i386/kernel/Makefile	Fri Sep 20 08:20:43 2002
+++ b/arch/i386/kernel/Makefile	Fri Sep 20 08:20:43 2002
@@ -2,9 +2,7 @@
 # Makefile for the linux kernel.
 #
 
-EXTRA_TARGETS := kernel.o head.o init_task.o
-
-O_TARGET := kernel.o
+EXTRA_TARGETS := head.o init_task.o
 
 export-objs     := mca.o i386_ksyms.o time.o
 
@@ -14,6 +12,7 @@
 		bootflag.o
 
 obj-y				+= cpu/
+obj-$(CONFIG_X86_BIOS_REBOOT)	+= reboot.o
 obj-$(CONFIG_MCA)		+= mca.o
 obj-$(CONFIG_X86_MSR)		+= msr.o
 obj-$(CONFIG_X86_CPUID)		+= cpuid.o
@@ -21,15 +20,12 @@
 obj-$(CONFIG_APM)		+= apm.o
 obj-$(CONFIG_ACPI)		+= acpi.o
 obj-$(CONFIG_ACPI_SLEEP)	+= acpi_wakeup.o
-obj-$(CONFIG_SMP)		+= smp.o smpboot.o trampoline.o
-obj-$(CONFIG_X86_LOCAL_APIC)	+= mpparse.o apic.o nmi.o
+obj-$(CONFIG_X86_SMP)		+= smp.o smpboot.o trampoline.o
+obj-$(CONFIG_X86_MPPARSE)	+= mpparse.o
+obj-$(CONFIG_X86_LOCAL_APIC)	+= apic.o nmi.o
 obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o
 obj-$(CONFIG_SOFTWARE_SUSPEND)	+= suspend.o
 obj-$(CONFIG_X86_NUMAQ)		+= numaq.o
-ifdef CONFIG_VISWS
-obj-y += setup-visws.o
-obj-$(CONFIG_X86_VISWS_APIC)	+= visws_apic.o
-endif
 
 EXTRA_AFLAGS   := -traditional
 
diff -Nru a/arch/i386/kernel/acpi.c b/arch/i386/kernel/acpi.c
--- a/arch/i386/kernel/acpi.c	Fri Sep 20 08:20:47 2002
+++ b/arch/i386/kernel/acpi.c	Fri Sep 20 08:20:47 2002
@@ -47,6 +47,7 @@
 
 #define PREFIX			"ACPI: "
 
+extern int acpi_disabled;
 
 /* --------------------------------------------------------------------------
                               Boot-time Configuration
@@ -56,42 +57,40 @@
 
 #ifdef CONFIG_ACPI_BOOT
 /*
- * Use reserved fixmap pages for physical-to-virtual mappings of ACPI tables.
- * Note that the same range is used for each table, so tables that need to
- * persist should be memcpy'd.
+ * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END,
+ * to map the target physical address. The problem is that set_fixmap()
+ * provides a single page, and it is possible that the page is not
+ * sufficient.
+ * By using this area, we can map up to MAX_IO_APICS pages temporarily,
+ * i.e. until the next __va_range() call.
+ *
+ * Important Safety Note:  The fixed I/O APIC page numbers are *subtracted*
+ * from the fixed base.  That's why we start at FIX_IO_APIC_BASE_END and
+ * count idx down while incrementing the phys address.
  */
-char *
-__acpi_map_table (
-	unsigned long	phys_addr,
-	unsigned long	size)
-{
-	unsigned long	base = 0;
-	unsigned long	mapped_phys = phys_addr;
-	unsigned long	offset = phys_addr & (PAGE_SIZE - 1);
-	unsigned long	mapped_size = PAGE_SIZE - offset;
-	unsigned long	avail_size = mapped_size + (PAGE_SIZE * FIX_ACPI_PAGES);
-	int		idx = FIX_ACPI_BEGIN;
-
-	if (!phys_addr || !size)
-		return NULL;
-
-	base = fix_to_virt(FIX_ACPI_BEGIN);
+char *__acpi_map_table(unsigned long phys, unsigned long size)
+{
+	unsigned long base, offset, mapped_size;
+	int idx;
 
-	set_fixmap(idx, mapped_phys);
+	if (phys + size < 8*1024*1024) 
+		return __va(phys); 
 
-	if (size > avail_size)
-		return NULL;
+	offset = phys & (PAGE_SIZE - 1);
+	mapped_size = PAGE_SIZE - offset;
+	set_fixmap(FIX_ACPI_END, phys);
+	base = fix_to_virt(FIX_ACPI_END);
 
-	/* If the table doesn't map completely into the fist page... */
-	if (size > mapped_size) {
-		do {
-			/* Make sure we don't go past our range */
-			if (idx++ == FIX_ACPI_END)
-				return NULL;
-			mapped_phys = mapped_phys + PAGE_SIZE;
-			set_fixmap(idx, mapped_phys);
-			mapped_size = mapped_size + PAGE_SIZE;
-		} while (mapped_size < size);
+	/*
+	 * Most cases can be covered by the below.
+	 */
+	idx = FIX_ACPI_END;
+	while (mapped_size < size) {
+		if (--idx < FIX_ACPI_BEGIN)
+			return 0;	/* cannot handle this */
+		phys += PAGE_SIZE;
+		set_fixmap(idx, phys);
+		mapped_size += PAGE_SIZE;
 	}
 
 	return ((unsigned char *) base + offset);
@@ -317,6 +316,14 @@
 	result = acpi_table_init(cmdline);
 	if (result)
 		return result;
+
+	result = acpi_blacklisted();
+	if (result) {
+		acpi_disabled = 1;
+		return result;
+	}
+	else
+		printk(KERN_NOTICE PREFIX "BIOS passes blacklist\n");
 
 #ifdef CONFIG_X86_LOCAL_APIC
 
diff -Nru a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
--- a/arch/i386/kernel/apic.c	Fri Sep 20 08:20:48 2002
+++ b/arch/i386/kernel/apic.c	Fri Sep 20 08:20:48 2002
@@ -29,6 +29,21 @@
 #include <asm/mtrr.h>
 #include <asm/mpspec.h>
 #include <asm/pgalloc.h>
+#include <asm/desc.h>
+#include <asm/arch_hooks.h>
+
+void __init apic_intr_init(void)
+{
+#ifdef CONFIG_SMP
+	smp_intr_init();
+#endif
+	/* self generated IPI for local APIC timer */
+	set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
+
+	/* IPI vectors for APIC spurious and error interrupts */
+	set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
+	set_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
+}
 
 /* Using APIC to generate smp_local_timer_interrupt? */
 int using_apic_timer = 0;
diff -Nru a/arch/i386/kernel/cpu/amd.c b/arch/i386/kernel/cpu/amd.c
--- a/arch/i386/kernel/cpu/amd.c	Fri Sep 20 08:20:48 2002
+++ b/arch/i386/kernel/cpu/amd.c	Fri Sep 20 08:20:48 2002
@@ -25,7 +25,7 @@
 static void __init init_amd(struct cpuinfo_x86 *c)
 {
 	u32 l, h;
-	int mbytes = max_mapnr >> (20-PAGE_SHIFT);
+	int mbytes = num_physpages >> (20-PAGE_SHIFT);
 	int r;
 
 	/*
diff -Nru a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c
--- a/arch/i386/kernel/cpu/intel.c	Fri Sep 20 08:20:44 2002
+++ b/arch/i386/kernel/cpu/intel.c	Fri Sep 20 08:20:44 2002
@@ -257,7 +257,7 @@
 	if ( p )
 		strcpy(c->x86_model_id, p);
 	
-#ifdef CONFIG_SMP
+#ifdef CONFIG_X86_HT
 	if (test_bit(X86_FEATURE_HT, c->x86_capability) && !disable_P4_HT) {
 		extern	int phys_proc_id[NR_CPUS];
 		
diff -Nru a/arch/i386/kernel/cpu/mtrr/mtrr.h b/arch/i386/kernel/cpu/mtrr/mtrr.h
--- a/arch/i386/kernel/cpu/mtrr/mtrr.h	Fri Sep 20 08:20:43 2002
+++ b/arch/i386/kernel/cpu/mtrr/mtrr.h	Fri Sep 20 08:20:43 2002
@@ -96,4 +96,7 @@
 
 extern unsigned int num_var_ranges;
 
+void finalize_mtrr_state(void);
+void mtrr_state_warn(void);
+
 extern char * mtrr_if_name[];
diff -Nru a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
--- a/arch/i386/kernel/entry.S	Fri Sep 20 08:20:44 2002
+++ b/arch/i386/kernel/entry.S	Fri Sep 20 08:20:44 2002
@@ -47,7 +47,7 @@
 #include <asm/errno.h>
 #include <asm/segment.h>
 #include <asm/smp.h>
-#include <asm/irq_vectors.h>
+#include "irq_vectors.h"
 
 EBX		= 0x00
 ECX		= 0x04
@@ -344,34 +344,8 @@
 	call smp_/**/name;	\
 	jmp ret_from_intr;
 
-/*
- * The following vectors are part of the Linux architecture, there
- * is no hardware IRQ pin equivalent for them, they are triggered
- * through the ICC by us (IPIs)
- */
-#ifdef CONFIG_SMP
-BUILD_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR)
-BUILD_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR)
-BUILD_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR)
-#endif
-
-/*
- * every pentium local APIC has two 'local interrupts', with a
- * soft-definable vector attached to both interrupts, one of
- * which is a timer interrupt, the other one is error counter
- * overflow. Linux uses the local APIC timer interrupt to get
- * a much simpler SMP time architecture:
- */
-#ifdef CONFIG_X86_LOCAL_APIC
-BUILD_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR)
-BUILD_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR)
-BUILD_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR)
-
-#ifdef CONFIG_X86_MCE_P4THERMAL
-BUILD_INTERRUPT(thermal_interrupt,THERMAL_APIC_VECTOR)
-#endif
-
-#endif
+/* The include is where all of the SMP etc. interrupts come from */
+#include "entry_arch.h"
 
 ENTRY(divide_error)
 	pushl $0			# no error code
diff -Nru a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
--- a/arch/i386/kernel/i386_ksyms.c	Fri Sep 20 08:20:46 2002
+++ b/arch/i386/kernel/i386_ksyms.c	Fri Sep 20 08:20:46 2002
@@ -58,7 +58,11 @@
 EXPORT_SYMBOL(EISA_bus);
 #endif
 EXPORT_SYMBOL(MCA_bus);
-#ifdef CONFIG_MULTIQUAD
+#ifdef CONFIG_DISCONTIGMEM
+EXPORT_SYMBOL(node_data);
+EXPORT_SYMBOL(pfn_to_nid);
+#endif
+#ifdef CONFIG_X86_NUMAQ
 EXPORT_SYMBOL(xquad_portio);
 #endif
 EXPORT_SYMBOL(__verify_write);
diff -Nru a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c
--- a/arch/i386/kernel/i8259.c	Fri Sep 20 08:20:47 2002
+++ b/arch/i386/kernel/i8259.c	Fri Sep 20 08:20:47 2002
@@ -21,6 +21,7 @@
 #include <asm/delay.h>
 #include <asm/desc.h>
 #include <asm/apic.h>
+#include <asm/arch_hooks.h>
 
 #include <linux/irq.h>
 
@@ -332,15 +333,6 @@
  */
 static struct irqaction irq13 = { math_error_irq, 0, 0, "fpu", NULL, NULL };
 
-/*
- * IRQ2 is cascade interrupt to second interrupt controller
- */
-
-#ifndef CONFIG_VISWS
-static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL};
-#endif
-
-
 void __init init_ISA_irqs (void)
 {
 	int i;
@@ -373,11 +365,9 @@
 {
 	int i;
 
-#ifndef CONFIG_X86_VISWS_APIC
-	init_ISA_irqs();
-#else
-	init_VISWS_APIC_irqs();
-#endif
+	/* all the set up before the call gates are initialised */
+	pre_intr_init_hook();
+
 	/*
 	 * Cover the whole vector space, no vector can escape
 	 * us. (some of these will be overridden and become
@@ -389,39 +379,9 @@
 			set_intr_gate(vector, interrupt[i]);
 	}
 
-#ifdef CONFIG_SMP
-	/*
-	 * IRQ0 must be given a fixed assignment and initialized,
-	 * because it's used before the IO-APIC is set up.
-	 */
-	set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]);
-
-	/*
-	 * The reschedule interrupt is a CPU-to-CPU reschedule-helper
-	 * IPI, driven by wakeup.
-	 */
-	set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
-
-	/* IPI for invalidation */
-	set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt);
-
-	/* IPI for generic function call */
-	set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
-#endif	
-
-#ifdef CONFIG_X86_LOCAL_APIC
-	/* self generated IPI for local APIC timer */
-	set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
-
-	/* IPI vectors for APIC spurious and error interrupts */
-	set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
-	set_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
-
-	/* thermal monitor LVT interrupt */
-#ifdef CONFIG_X86_MCE_P4THERMAL
-	set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
-#endif
-#endif
+	/* setup after call gates are initialised (usually add in
+	 * the architecture specific gates */
+	intr_init_hook();
 
 	/*
 	 * Set the clock to HZ Hz, we already have a valid
@@ -430,10 +390,6 @@
 	outb_p(0x34,0x43);		/* binary, mode 2, LSB/MSB, ch 0 */
 	outb_p(LATCH & 0xff , 0x40);	/* LSB */
 	outb(LATCH >> 8 , 0x40);	/* MSB */
-
-#ifndef CONFIG_VISWS
-	setup_irq(2, &irq2);
-#endif
 
 	/*
 	 * External FPU? Set up irq13 if so, for
diff -Nru a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
--- a/arch/i386/kernel/io_apic.c	Fri Sep 20 08:20:44 2002
+++ b/arch/i386/kernel/io_apic.c	Fri Sep 20 08:20:44 2002
@@ -1885,7 +1885,7 @@
 	io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0));
 	spin_unlock_irqrestore(&ioapic_lock, flags);
 
-	return entry.vector;
+	return 0;
 }
 
 #endif /*CONFIG_ACPI_BOOT*/
diff -Nru a/arch/i386/kernel/mca.c b/arch/i386/kernel/mca.c
--- a/arch/i386/kernel/mca.c	Fri Sep 20 08:20:43 2002
+++ b/arch/i386/kernel/mca.c	Fri Sep 20 08:20:43 2002
@@ -52,6 +52,7 @@
 #include <linux/ioport.h>
 #include <asm/uaccess.h>
 #include <linux/init.h>
+#include <asm/arch_hooks.h>
 
 /* This structure holds MCA information. Each (plug-in) adapter has
  * eight POS registers. Then the machine may have integrated video and
@@ -379,12 +380,7 @@
 		}
 	}
 
-	/* If I recall correctly, there's a whole bunch of other things that
-	 * we can do to check for NMI problems, but that's all I know about
-	 * at the moment.
-	 */
-
-	printk("NMI generated from unknown source!\n");
+	mca_nmi_hook();
 } /* mca_handle_nmi */
 
 /*--------------------------------------------------------------------*/
diff -Nru a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
--- a/arch/i386/kernel/mpparse.c	Fri Sep 20 08:20:44 2002
+++ b/arch/i386/kernel/mpparse.c	Fri Sep 20 08:20:44 2002
@@ -73,7 +73,7 @@
  * Intel MP BIOS table parsing routines:
  */
 
-#ifndef CONFIG_X86_VISWS_APIC
+
 /*
  * Checksum an MP configuration block.
  */
@@ -737,7 +737,7 @@
 	return 0;
 }
 
-void __init find_intel_smp (void)
+void __init find_smp_config (void)
 {
 	unsigned int address;
 
@@ -777,40 +777,6 @@
 		printk(KERN_WARNING "WARNING: MP table in the EBDA can be UNSAFE, contact linux-smp@vger.kernel.org if you experience SMP problems!\n");
 }
 
-#else
-
-/*
- * The Visual Workstation is Intel MP compliant in the hardware
- * sense, but it doesn't have a BIOS(-configuration table).
- * No problem for Linux.
- */
-void __init find_visws_smp(void)
-{
-	smp_found_config = 1;
-
-	phys_cpu_present_map |= 2; /* or in id 1 */
-	apic_version[1] |= 0x10; /* integrated APIC */
-	apic_version[0] |= 0x10;
-
-	mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
-}
-
-#endif
-
-/*
- * - Intel MP Configuration Table
- * - or SGI Visual Workstation configuration
- */
-void __init find_smp_config (void)
-{
-#ifdef CONFIG_X86_LOCAL_APIC
-	find_intel_smp();
-#endif
-#ifdef CONFIG_VISWS
-	find_visws_smp();
-#endif
-}
-
 
 /* --------------------------------------------------------------------------
                             ACPI-based MP Configuration
@@ -976,7 +942,7 @@
 	intsrc.mpc_dstapic = mp_ioapics[ioapic].mpc_apicid;	   /* APIC ID */
 	intsrc.mpc_dstirq = pin;				    /* INTIN# */
 
-	Dprintk("Int: type %d, pol %d, trig %d, bus %d, irq %d, %d-%d\n", 
+	Dprintk("Int: type %d, pol %d, trig %d, bus %d, irq %d, %d-%d\n",
 		intsrc.mpc_irqtype, intsrc.mpc_irqflag & 3, 
 		(intsrc.mpc_irqflag >> 2) & 3, intsrc.mpc_srcbus, 
 		intsrc.mpc_srcbusirq, intsrc.mpc_dstapic, intsrc.mpc_dstirq);
@@ -1049,8 +1015,20 @@
 		if (++mp_irq_entries == MAX_IRQ_SOURCES)
 			panic("Max # of irq sources exceeded!\n");
 	}
+}
 
-	return;
+/* Ensure the ACPI SCI interrupt level is active low, edge-triggered */
+
+void __init mp_config_ioapic_for_sci(int irq)
+{
+	int ioapic;
+	int ioapic_pin;
+
+	ioapic = mp_find_ioapic(irq);
+
+	ioapic_pin = irq - mp_ioapic_routing[ioapic].irq_start;
+
+	io_apic_set_pci_routing(ioapic, ioapic_pin, irq);
 }
 
 #ifdef CONFIG_ACPI_PCI
@@ -1059,7 +1037,6 @@
 {
 	struct list_head	*node = NULL;
 	struct acpi_prt_entry	*entry = NULL;
-	int			vector = 0;
 	int			ioapic = -1;
 	int			ioapic_pin = 0;
 	int			irq = 0;
@@ -1104,14 +1081,13 @@
 
 		mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
 
-		vector = io_apic_set_pci_routing(ioapic, ioapic_pin, irq);
-		if (vector)
+		if (!io_apic_set_pci_routing(ioapic, ioapic_pin, irq))
 			entry->irq = irq;
 
-		printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> vector 0x%02x"
-			" -> IRQ %d\n", entry->id.segment, entry->id.bus, 
+		printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> IRQ %d\n",
+			entry->id.segment, entry->id.bus, 
 			entry->id.device, ('A' + entry->pin), 
-			mp_ioapic_routing[ioapic].apic_id, ioapic_pin, vector, 
+			mp_ioapic_routing[ioapic].apic_id, ioapic_pin, 
 			entry->irq);
 	}
 	
diff -Nru a/arch/i386/kernel/numaq.c b/arch/i386/kernel/numaq.c
--- a/arch/i386/kernel/numaq.c	Fri Sep 20 08:20:43 2002
+++ b/arch/i386/kernel/numaq.c	Fri Sep 20 08:20:43 2002
@@ -82,27 +82,19 @@
  */
 int physnode_map[MAX_ELEMENTS] = { [0 ... (MAX_ELEMENTS - 1)] = -1};
 
-#define MB_TO_ELEMENT(x) (x >> ELEMENT_REPRESENTS)
-#define PA_TO_MB(pa) (pa >> 20) 	/* assumption: a physical address is in bytes */
+#define PFN_TO_ELEMENT(pfn) (pfn / PAGES_PER_ELEMENT)
+#define PA_TO_ELEMENT(pa) (PFN_TO_ELEMENT(pa >> PAGE_SHIFT))
 
-int pa_to_nid(u64 pa)
+int pfn_to_nid(unsigned long pfn)
 {
-	int nid;
-	
-	nid = physnode_map[MB_TO_ELEMENT(PA_TO_MB(pa))];
+	int nid = physnode_map[PFN_TO_ELEMENT(pfn)];
 
-	/* the physical address passed in is not in the map for the system */
 	if (nid == -1)
-		BUG();
+		BUG(); /* address is not present */
 
 	return nid;
 }
 
-int pfn_to_nid(unsigned long pfn)
-{
-	return pa_to_nid(((u64)pfn) << PAGE_SHIFT);
-}
-
 /*
  * for each node mark the regions
  *        TOPOFMEM = hi_shrd_mem_start + hi_shrd_mem_size
@@ -132,7 +124,7 @@
 			topofmem = eq->hi_shrd_mem_start + eq->hi_shrd_mem_size;
 			while (cur < topofmem) {
 				physnode_map[cur >> 8] = nid;
-				cur += (ELEMENT_REPRESENTS - 1);
+				cur ++;
 			}
 		}
 	}
diff -Nru a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
--- a/arch/i386/kernel/process.c	Fri Sep 20 08:20:41 2002
+++ b/arch/i386/kernel/process.c	Fri Sep 20 08:20:41 2002
@@ -66,11 +66,6 @@
  */
 void (*pm_idle)(void);
 
-/*
- * Power off function, if any
- */
-void (*pm_power_off)(void);
-
 void disable_hlt(void)
 {
 	hlt_counter++;
@@ -159,282 +154,6 @@
 }
 
 __setup("idle=", idle_setup);
-
-static long no_idt[2];
-static int reboot_mode;
-int reboot_thru_bios;
-
-#ifdef CONFIG_SMP
-int reboot_smp = 0;
-static int reboot_cpu = -1;
-/* shamelessly grabbed from lib/vsprintf.c for readability */
-#define is_digit(c)	((c) >= '0' && (c) <= '9')
-#endif
-static int __init reboot_setup(char *str)
-{
-	while(1) {
-		switch (*str) {
-		case 'w': /* "warm" reboot (no memory testing etc) */
-			reboot_mode = 0x1234;
-			break;
-		case 'c': /* "cold" reboot (with memory testing etc) */
-			reboot_mode = 0x0;
-			break;
-		case 'b': /* "bios" reboot by jumping through the BIOS */
-			reboot_thru_bios = 1;
-			break;
-		case 'h': /* "hard" reboot by toggling RESET and/or crashing the CPU */
-			reboot_thru_bios = 0;
-			break;
-#ifdef CONFIG_SMP
-		case 's': /* "smp" reboot by executing reset on BSP or other CPU*/
-			reboot_smp = 1;
-			if (is_digit(*(str+1))) {
-				reboot_cpu = (int) (*(str+1) - '0');
-				if (is_digit(*(str+2))) 
-					reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
-			}
-				/* we will leave sorting out the final value 
-				when we are ready to reboot, since we might not
- 				have set up boot_cpu_id or smp_num_cpu */
-			break;
-#endif
-		}
-		if((str = strchr(str,',')) != NULL)
-			str++;
-		else
-			break;
-	}
-	return 1;
-}
-
-__setup("reboot=", reboot_setup);
-
-/* The following code and data reboots the machine by switching to real
-   mode and jumping to the BIOS reset entry point, as if the CPU has
-   really been reset.  The previous version asked the keyboard
-   controller to pulse the CPU reset line, which is more thorough, but
-   doesn't work with at least one type of 486 motherboard.  It is easy
-   to stop this code working; hence the copious comments. */
-
-static unsigned long long
-real_mode_gdt_entries [3] =
-{
-	0x0000000000000000ULL,	/* Null descriptor */
-	0x00009a000000ffffULL,	/* 16-bit real-mode 64k code at 0x00000000 */
-	0x000092000100ffffULL	/* 16-bit real-mode 64k data at 0x00000100 */
-};
-
-static struct
-{
-	unsigned short       size __attribute__ ((packed));
-	unsigned long long * base __attribute__ ((packed));
-}
-real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, real_mode_gdt_entries },
-real_mode_idt = { 0x3ff, 0 };
-
-/* This is 16-bit protected mode code to disable paging and the cache,
-   switch to real mode and jump to the BIOS reset code.
-
-   The instruction that switches to real mode by writing to CR0 must be
-   followed immediately by a far jump instruction, which set CS to a
-   valid value for real mode, and flushes the prefetch queue to avoid
-   running instructions that have already been decoded in protected
-   mode.
-
-   Clears all the flags except ET, especially PG (paging), PE
-   (protected-mode enable) and TS (task switch for coprocessor state
-   save).  Flushes the TLB after paging has been disabled.  Sets CD and
-   NW, to disable the cache on a 486, and invalidates the cache.  This
-   is more like the state of a 486 after reset.  I don't know if
-   something else should be done for other chips.
-
-   More could be done here to set up the registers as if a CPU reset had
-   occurred; hopefully real BIOSs don't assume much. */
-
-static unsigned char real_mode_switch [] =
-{
-	0x66, 0x0f, 0x20, 0xc0,			/*    movl  %cr0,%eax        */
-	0x66, 0x83, 0xe0, 0x11,			/*    andl  $0x00000011,%eax */
-	0x66, 0x0d, 0x00, 0x00, 0x00, 0x60,	/*    orl   $0x60000000,%eax */
-	0x66, 0x0f, 0x22, 0xc0,			/*    movl  %eax,%cr0        */
-	0x66, 0x0f, 0x22, 0xd8,			/*    movl  %eax,%cr3        */
-	0x66, 0x0f, 0x20, 0xc3,			/*    movl  %cr0,%ebx        */
-	0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60,	/*    andl  $0x60000000,%ebx */
-	0x74, 0x02,				/*    jz    f                */
-	0x0f, 0x08,				/*    invd                   */
-	0x24, 0x10,				/* f: andb  $0x10,al         */
-	0x66, 0x0f, 0x22, 0xc0			/*    movl  %eax,%cr0        */
-};
-static unsigned char jump_to_bios [] =
-{
-	0xea, 0x00, 0x00, 0xff, 0xff		/*    ljmp  $0xffff,$0x0000  */
-};
-
-static inline void kb_wait(void)
-{
-	int i;
-
-	for (i=0; i<0x10000; i++)
-		if ((inb_p(0x64) & 0x02) == 0)
-			break;
-}
-
-/*
- * Switch to real mode and then execute the code
- * specified by the code and length parameters.
- * We assume that length will aways be less that 100!
- */
-void machine_real_restart(unsigned char *code, int length)
-{
-	unsigned long flags;
-
-	local_irq_disable();
-
-	/* Write zero to CMOS register number 0x0f, which the BIOS POST
-	   routine will recognize as telling it to do a proper reboot.  (Well
-	   that's what this book in front of me says -- it may only apply to
-	   the Phoenix BIOS though, it's not clear).  At the same time,
-	   disable NMIs by setting the top bit in the CMOS address register,
-	   as we're about to do peculiar things to the CPU.  I'm not sure if
-	   `outb_p' is needed instead of just `outb'.  Use it to be on the
-	   safe side.  (Yes, CMOS_WRITE does outb_p's. -  Paul G.)
-	 */
-
-	spin_lock_irqsave(&rtc_lock, flags);
-	CMOS_WRITE(0x00, 0x8f);
-	spin_unlock_irqrestore(&rtc_lock, flags);
-
-	/* Remap the kernel at virtual address zero, as well as offset zero
-	   from the kernel segment.  This assumes the kernel segment starts at
-	   virtual address PAGE_OFFSET. */
-
-	memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
-		sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS);
-
-	/*
-	 * Use `swapper_pg_dir' as our page directory.
-	 */
-	load_cr3(swapper_pg_dir);
-
-	/* Write 0x1234 to absolute memory location 0x472.  The BIOS reads
-	   this on booting to tell it to "Bypass memory test (also warm
-	   boot)".  This seems like a fairly standard thing that gets set by
-	   REBOOT.COM programs, and the previous reset routine did this
-	   too. */
-
-	*((unsigned short *)0x472) = reboot_mode;
-
-	/* For the switch to real mode, copy some code to low memory.  It has
-	   to be in the first 64k because it is running in 16-bit mode, and it
-	   has to have the same physical and virtual address, because it turns
-	   off paging.  Copy it near the end of the first page, out of the way
-	   of BIOS variables. */
-
-	memcpy ((void *) (0x1000 - sizeof (real_mode_switch) - 100),
-		real_mode_switch, sizeof (real_mode_switch));
-	memcpy ((void *) (0x1000 - 100), code, length);
-
-	/* Set up the IDT for real mode. */
-
-	__asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt));
-
-	/* Set up a GDT from which we can load segment descriptors for real
-	   mode.  The GDT is not used in real mode; it is just needed here to
-	   prepare the descriptors. */
-
-	__asm__ __volatile__ ("lgdt %0" : : "m" (real_mode_gdt));
-
-	/* Load the data segment registers, and thus the descriptors ready for
-	   real mode.  The base address of each segment is 0x100, 16 times the
-	   selector value being loaded here.  This is so that the segment
-	   registers don't have to be reloaded after switching to real mode:
-	   the values are consistent for real mode operation already. */
-
-	__asm__ __volatile__ ("movl $0x0010,%%eax\n"
-				"\tmovl %%eax,%%ds\n"
-				"\tmovl %%eax,%%es\n"
-				"\tmovl %%eax,%%fs\n"
-				"\tmovl %%eax,%%gs\n"
-				"\tmovl %%eax,%%ss" : : : "eax");
-
-	/* Jump to the 16-bit code that we copied earlier.  It disables paging
-	   and the cache, switches to real mode, and jumps to the BIOS reset
-	   entry point. */
-
-	__asm__ __volatile__ ("ljmp $0x0008,%0"
-				:
-				: "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100)));
-}
-
-void machine_restart(char * __unused)
-{
-#if CONFIG_SMP
-	int cpuid;
-	
-	cpuid = GET_APIC_ID(apic_read(APIC_ID));
-
-	if (reboot_smp) {
-
-		/* check to see if reboot_cpu is valid 
-		   if its not, default to the BSP */
-		if ((reboot_cpu == -1) ||  
-		      (reboot_cpu > (NR_CPUS -1))  || 
-		      !(phys_cpu_present_map & (1<<cpuid))) 
-			reboot_cpu = boot_cpu_physical_apicid;
-
-		reboot_smp = 0;  /* use this as a flag to only go through this once*/
-		/* re-run this function on the other CPUs
-		   it will fall though this section since we have 
-		   cleared reboot_smp, and do the reboot if it is the
-		   correct CPU, otherwise it halts. */
-		if (reboot_cpu != cpuid)
-			smp_call_function((void *)machine_restart , NULL, 1, 0);
-	}
-
-	/* if reboot_cpu is still -1, then we want a tradional reboot, 
-	   and if we are not running on the reboot_cpu,, halt */
-	if ((reboot_cpu != -1) && (cpuid != reboot_cpu)) {
-		for (;;)
-		__asm__ __volatile__ ("hlt");
-	}
-	/*
-	 * Stop all CPUs and turn off local APICs and the IO-APIC, so
-	 * other OSs see a clean IRQ state.
-	 */
-	smp_send_stop();
-	disable_IO_APIC();
-#endif
-
-	if(!reboot_thru_bios) {
-		/* rebooting needs to touch the page at absolute addr 0 */
-		*((unsigned short *)__va(0x472)) = reboot_mode;
-		for (;;) {
-			int i;
-			for (i=0; i<100; i++) {
-				kb_wait();
-				udelay(50);
-				outb(0xfe,0x64);         /* pulse reset low */
-				udelay(50);
-			}
-			/* That didn't work - force a triple fault.. */
-			__asm__ __volatile__("lidt %0": :"m" (no_idt));
-			__asm__ __volatile__("int3");
-		}
-	}
-
-	machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
-}
-
-void machine_halt(void)
-{
-}
-
-void machine_power_off(void)
-{
-	if (pm_power_off)
-		pm_power_off();
-}
 
 extern void show_trace(unsigned long* esp);
 
diff -Nru a/arch/i386/kernel/reboot.c b/arch/i386/kernel/reboot.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/reboot.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,324 @@
+/*
+ *  linux/arch/i386/kernel/reboot.c
+ */
+
+#define __KERNEL_SYSCALLS__
+#include <stdarg.h>
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/interrupt.h>
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/mc146818rtc.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/ldt.h>
+#include <asm/processor.h>
+#include <asm/i387.h>
+#include <asm/desc.h>
+#ifdef CONFIG_MATH_EMULATION
+#include <asm/math_emu.h>
+#endif
+
+#include <linux/irq.h>
+#include <linux/err.h>
+
+/*
+ * Power off function, if any
+ */
+void (*pm_power_off)(void);
+
+static long no_idt[2];
+static int reboot_mode;
+int reboot_thru_bios;
+
+#ifdef CONFIG_SMP
+int reboot_smp = 0;
+static int reboot_cpu = -1;
+/* shamelessly grabbed from lib/vsprintf.c for readability */
+#define is_digit(c)	((c) >= '0' && (c) <= '9')
+#endif
+static int __init reboot_setup(char *str)
+{
+	while(1) {
+		switch (*str) {
+		case 'w': /* "warm" reboot (no memory testing etc) */
+			reboot_mode = 0x1234;
+			break;
+		case 'c': /* "cold" reboot (with memory testing etc) */
+			reboot_mode = 0x0;
+			break;
+		case 'b': /* "bios" reboot by jumping through the BIOS */
+			reboot_thru_bios = 1;
+			break;
+		case 'h': /* "hard" reboot by toggling RESET and/or crashing the CPU */
+			reboot_thru_bios = 0;
+			break;
+#ifdef CONFIG_SMP
+		case 's': /* "smp" reboot by executing reset on BSP or other CPU*/
+			reboot_smp = 1;
+			if (is_digit(*(str+1))) {
+				reboot_cpu = (int) (*(str+1) - '0');
+				if (is_digit(*(str+2))) 
+					reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
+			}
+				/* we will leave sorting out the final value 
+				when we are ready to reboot, since we might not
+ 				have set up boot_cpu_id or smp_num_cpu */
+			break;
+#endif
+		}
+		if((str = strchr(str,',')) != NULL)
+			str++;
+		else
+			break;
+	}
+	return 1;
+}
+
+__setup("reboot=", reboot_setup);
+
+/* The following code and data reboots the machine by switching to real
+   mode and jumping to the BIOS reset entry point, as if the CPU has
+   really been reset.  The previous version asked the keyboard
+   controller to pulse the CPU reset line, which is more thorough, but
+   doesn't work with at least one type of 486 motherboard.  It is easy
+   to stop this code working; hence the copious comments. */
+
+static unsigned long long
+real_mode_gdt_entries [3] =
+{
+	0x0000000000000000ULL,	/* Null descriptor */
+	0x00009a000000ffffULL,	/* 16-bit real-mode 64k code at 0x00000000 */
+	0x000092000100ffffULL	/* 16-bit real-mode 64k data at 0x00000100 */
+};
+
+static struct
+{
+	unsigned short       size __attribute__ ((packed));
+	unsigned long long * base __attribute__ ((packed));
+}
+real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, real_mode_gdt_entries },
+real_mode_idt = { 0x3ff, 0 };
+
+/* This is 16-bit protected mode code to disable paging and the cache,
+   switch to real mode and jump to the BIOS reset code.
+
+   The instruction that switches to real mode by writing to CR0 must be
+   followed immediately by a far jump instruction, which set CS to a
+   valid value for real mode, and flushes the prefetch queue to avoid
+   running instructions that have already been decoded in protected
+   mode.
+
+   Clears all the flags except ET, especially PG (paging), PE
+   (protected-mode enable) and TS (task switch for coprocessor state
+   save).  Flushes the TLB after paging has been disabled.  Sets CD and
+   NW, to disable the cache on a 486, and invalidates the cache.  This
+   is more like the state of a 486 after reset.  I don't know if
+   something else should be done for other chips.
+
+   More could be done here to set up the registers as if a CPU reset had
+   occurred; hopefully real BIOSs don't assume much. */
+
+static unsigned char real_mode_switch [] =
+{
+	0x66, 0x0f, 0x20, 0xc0,			/*    movl  %cr0,%eax        */
+	0x66, 0x83, 0xe0, 0x11,			/*    andl  $0x00000011,%eax */
+	0x66, 0x0d, 0x00, 0x00, 0x00, 0x60,	/*    orl   $0x60000000,%eax */
+	0x66, 0x0f, 0x22, 0xc0,			/*    movl  %eax,%cr0        */
+	0x66, 0x0f, 0x22, 0xd8,			/*    movl  %eax,%cr3        */
+	0x66, 0x0f, 0x20, 0xc3,			/*    movl  %cr0,%ebx        */
+	0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60,	/*    andl  $0x60000000,%ebx */
+	0x74, 0x02,				/*    jz    f                */
+	0x0f, 0x08,				/*    invd                   */
+	0x24, 0x10,				/* f: andb  $0x10,al         */
+	0x66, 0x0f, 0x22, 0xc0			/*    movl  %eax,%cr0        */
+};
+static unsigned char jump_to_bios [] =
+{
+	0xea, 0x00, 0x00, 0xff, 0xff		/*    ljmp  $0xffff,$0x0000  */
+};
+
+static inline void kb_wait(void)
+{
+	int i;
+
+	for (i=0; i<0x10000; i++)
+		if ((inb_p(0x64) & 0x02) == 0)
+			break;
+}
+
+/*
+ * Switch to real mode and then execute the code
+ * specified by the code and length parameters.
+ * We assume that length will aways be less that 100!
+ */
+void machine_real_restart(unsigned char *code, int length)
+{
+	unsigned long flags;
+
+	local_irq_disable();
+
+	/* Write zero to CMOS register number 0x0f, which the BIOS POST
+	   routine will recognize as telling it to do a proper reboot.  (Well
+	   that's what this book in front of me says -- it may only apply to
+	   the Phoenix BIOS though, it's not clear).  At the same time,
+	   disable NMIs by setting the top bit in the CMOS address register,
+	   as we're about to do peculiar things to the CPU.  I'm not sure if
+	   `outb_p' is needed instead of just `outb'.  Use it to be on the
+	   safe side.  (Yes, CMOS_WRITE does outb_p's. -  Paul G.)
+	 */
+
+	spin_lock_irqsave(&rtc_lock, flags);
+	CMOS_WRITE(0x00, 0x8f);
+	spin_unlock_irqrestore(&rtc_lock, flags);
+
+	/* Remap the kernel at virtual address zero, as well as offset zero
+	   from the kernel segment.  This assumes the kernel segment starts at
+	   virtual address PAGE_OFFSET. */
+
+	memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
+		sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS);
+
+	/*
+	 * Use `swapper_pg_dir' as our page directory.
+	 */
+	load_cr3(swapper_pg_dir);
+
+	/* Write 0x1234 to absolute memory location 0x472.  The BIOS reads
+	   this on booting to tell it to "Bypass memory test (also warm
+	   boot)".  This seems like a fairly standard thing that gets set by
+	   REBOOT.COM programs, and the previous reset routine did this
+	   too. */
+
+	*((unsigned short *)0x472) = reboot_mode;
+
+	/* For the switch to real mode, copy some code to low memory.  It has
+	   to be in the first 64k because it is running in 16-bit mode, and it
+	   has to have the same physical and virtual address, because it turns
+	   off paging.  Copy it near the end of the first page, out of the way
+	   of BIOS variables. */
+
+	memcpy ((void *) (0x1000 - sizeof (real_mode_switch) - 100),
+		real_mode_switch, sizeof (real_mode_switch));
+	memcpy ((void *) (0x1000 - 100), code, length);
+
+	/* Set up the IDT for real mode. */
+
+	__asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt));
+
+	/* Set up a GDT from which we can load segment descriptors for real
+	   mode.  The GDT is not used in real mode; it is just needed here to
+	   prepare the descriptors. */
+
+	__asm__ __volatile__ ("lgdt %0" : : "m" (real_mode_gdt));
+
+	/* Load the data segment registers, and thus the descriptors ready for
+	   real mode.  The base address of each segment is 0x100, 16 times the
+	   selector value being loaded here.  This is so that the segment
+	   registers don't have to be reloaded after switching to real mode:
+	   the values are consistent for real mode operation already. */
+
+	__asm__ __volatile__ ("movl $0x0010,%%eax\n"
+				"\tmovl %%eax,%%ds\n"
+				"\tmovl %%eax,%%es\n"
+				"\tmovl %%eax,%%fs\n"
+				"\tmovl %%eax,%%gs\n"
+				"\tmovl %%eax,%%ss" : : : "eax");
+
+	/* Jump to the 16-bit code that we copied earlier.  It disables paging
+	   and the cache, switches to real mode, and jumps to the BIOS reset
+	   entry point. */
+
+	__asm__ __volatile__ ("ljmp $0x0008,%0"
+				:
+				: "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100)));
+}
+
+void machine_restart(char * __unused)
+{
+#if CONFIG_SMP
+	int cpuid;
+	
+	cpuid = GET_APIC_ID(apic_read(APIC_ID));
+
+	if (reboot_smp) {
+
+		/* check to see if reboot_cpu is valid 
+		   if its not, default to the BSP */
+		if ((reboot_cpu == -1) ||  
+		      (reboot_cpu > (NR_CPUS -1))  || 
+		      !(phys_cpu_present_map & (1<<cpuid))) 
+			reboot_cpu = boot_cpu_physical_apicid;
+
+		reboot_smp = 0;  /* use this as a flag to only go through this once*/
+		/* re-run this function on the other CPUs
+		   it will fall though this section since we have 
+		   cleared reboot_smp, and do the reboot if it is the
+		   correct CPU, otherwise it halts. */
+		if (reboot_cpu != cpuid)
+			smp_call_function((void *)machine_restart , NULL, 1, 0);
+	}
+
+	/* if reboot_cpu is still -1, then we want a tradional reboot, 
+	   and if we are not running on the reboot_cpu,, halt */
+	if ((reboot_cpu != -1) && (cpuid != reboot_cpu)) {
+		for (;;)
+		__asm__ __volatile__ ("hlt");
+	}
+	/*
+	 * Stop all CPUs and turn off local APICs and the IO-APIC, so
+	 * other OSs see a clean IRQ state.
+	 */
+	smp_send_stop();
+	disable_IO_APIC();
+#endif
+
+	if(!reboot_thru_bios) {
+		/* rebooting needs to touch the page at absolute addr 0 */
+		*((unsigned short *)__va(0x472)) = reboot_mode;
+		for (;;) {
+			int i;
+			for (i=0; i<100; i++) {
+				kb_wait();
+				udelay(50);
+				outb(0xfe,0x64);         /* pulse reset low */
+				udelay(50);
+			}
+			/* That didn't work - force a triple fault.. */
+			__asm__ __volatile__("lidt %0": :"m" (no_idt));
+			__asm__ __volatile__("int3");
+		}
+	}
+
+	machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
+}
+
+void machine_halt(void)
+{
+}
+
+void machine_power_off(void)
+{
+	if (pm_power_off)
+		pm_power_off();
+}
+
diff -Nru a/arch/i386/kernel/setup-visws.c b/arch/i386/kernel/setup-visws.c
--- a/arch/i386/kernel/setup-visws.c	Fri Sep 20 08:20:43 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,128 +0,0 @@
-/*
- *  Unmaintained SGI Visual Workstation support.
- *  Split out from setup.c by davej@suse.de
- */
-
-#include <linux/init.h>
-
-char visws_board_type = -1;
-char visws_board_rev = -1;
-
-#define	PIIX_PM_START		0x0F80
-
-#define	SIO_GPIO_START		0x0FC0
-
-#define	SIO_PM_START		0x0FC8
-
-#define	PMBASE			PIIX_PM_START
-#define	GPIREG0			(PMBASE+0x30)
-#define	GPIREG(x)		(GPIREG0+((x)/8))
-#define	PIIX_GPI_BD_ID1		18
-#define	PIIX_GPI_BD_REG		GPIREG(PIIX_GPI_BD_ID1)
-
-#define	PIIX_GPI_BD_SHIFT	(PIIX_GPI_BD_ID1 % 8)
-
-#define	SIO_INDEX	0x2e
-#define	SIO_DATA	0x2f
-
-#define	SIO_DEV_SEL	0x7
-#define	SIO_DEV_ENB	0x30
-#define	SIO_DEV_MSB	0x60
-#define	SIO_DEV_LSB	0x61
-
-#define	SIO_GP_DEV	0x7
-
-#define	SIO_GP_BASE	SIO_GPIO_START
-#define	SIO_GP_MSB	(SIO_GP_BASE>>8)
-#define	SIO_GP_LSB	(SIO_GP_BASE&0xff)
-
-#define	SIO_GP_DATA1	(SIO_GP_BASE+0)
-
-#define	SIO_PM_DEV	0x8
-
-#define	SIO_PM_BASE	SIO_PM_START
-#define	SIO_PM_MSB	(SIO_PM_BASE>>8)
-#define	SIO_PM_LSB	(SIO_PM_BASE&0xff)
-#define	SIO_PM_INDEX	(SIO_PM_BASE+0)
-#define	SIO_PM_DATA	(SIO_PM_BASE+1)
-
-#define	SIO_PM_FER2	0x1
-
-#define	SIO_PM_GP_EN	0x80
-
-void __init visws_get_board_type_and_rev(void)
-{
-	int raw;
-
-	visws_board_type = (char)(inb_p(PIIX_GPI_BD_REG) & PIIX_GPI_BD_REG)
-							 >> PIIX_GPI_BD_SHIFT;
-/*
- * Get Board rev.
- * First, we have to initialize the 307 part to allow us access
- * to the GPIO registers.  Let's map them at 0x0fc0 which is right
- * after the PIIX4 PM section.
- */
-	outb_p(SIO_DEV_SEL, SIO_INDEX);
-	outb_p(SIO_GP_DEV, SIO_DATA);	/* Talk to GPIO regs. */
-
-	outb_p(SIO_DEV_MSB, SIO_INDEX);
-	outb_p(SIO_GP_MSB, SIO_DATA);	/* MSB of GPIO base address */
-
-	outb_p(SIO_DEV_LSB, SIO_INDEX);
-	outb_p(SIO_GP_LSB, SIO_DATA);	/* LSB of GPIO base address */
-
-	outb_p(SIO_DEV_ENB, SIO_INDEX);
-	outb_p(1, SIO_DATA);		/* Enable GPIO registers. */
-
-/*
- * Now, we have to map the power management section to write
- * a bit which enables access to the GPIO registers.
- * What lunatic came up with this shit?
- */
-	outb_p(SIO_DEV_SEL, SIO_INDEX);
-	outb_p(SIO_PM_DEV, SIO_DATA);	/* Talk to GPIO regs. */
-
-	outb_p(SIO_DEV_MSB, SIO_INDEX);
-	outb_p(SIO_PM_MSB, SIO_DATA);	/* MSB of PM base address */
-
-	outb_p(SIO_DEV_LSB, SIO_INDEX);
-	outb_p(SIO_PM_LSB, SIO_DATA);	/* LSB of PM base address */
-
-	outb_p(SIO_DEV_ENB, SIO_INDEX);
-	outb_p(1, SIO_DATA);		/* Enable PM registers. */
-
-/*
- * Now, write the PM register which enables the GPIO registers.
- */
-	outb_p(SIO_PM_FER2, SIO_PM_INDEX);
-	outb_p(SIO_PM_GP_EN, SIO_PM_DATA);
-
-/*
- * Now, initialize the GPIO registers.
- * We want them all to be inputs which is the
- * power on default, so let's leave them alone.
- * So, let's just read the board rev!
- */
-	raw = inb_p(SIO_GP_DATA1);
-	raw &= 0x7f;	/* 7 bits of valid board revision ID. */
-
-	if (visws_board_type == VISWS_320) {
-		if (raw < 0x6) {
-			visws_board_rev = 4;
-		} else if (raw < 0xc) {
-			visws_board_rev = 5;
-		} else {
-			visws_board_rev = 6;
-		}
-	} else if (visws_board_type == VISWS_540) {
-			visws_board_rev = 2;
-		} else {
-			visws_board_rev = raw;
-		}
-
-		printk(KERN_INFO "Silicon Graphics %s (rev %d)\n",
-			visws_board_type == VISWS_320 ? "320" :
-			(visws_board_type == VISWS_540 ? "540" :
-					"unknown"), visws_board_rev);
-	}
-}
diff -Nru a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
--- a/arch/i386/kernel/setup.c	Fri Sep 20 08:20:46 2002
+++ b/arch/i386/kernel/setup.c	Fri Sep 20 08:20:46 2002
@@ -37,6 +37,10 @@
 #include <asm/e820.h>
 #include <asm/mpspec.h>
 #include <asm/setup.h>
+#include <asm/arch_hooks.h>
+#include "setup_arch_pre.h"
+
+static inline char * __init machine_specific_memory_setup(void);
 
 /*
  * Machine setup..
@@ -470,31 +474,8 @@
 
 static void __init setup_memory_region(void)
 {
-	char *who = "BIOS-e820";
+	char *who = machine_specific_memory_setup();
 
-	/*
-	 * Try to copy the BIOS-supplied E820-map.
-	 *
-	 * Otherwise fake a memory map; one section from 0k->640k,
-	 * the next section from 1mb->appropriate_mem_k
-	 */
-	sanitize_e820_map(E820_MAP, &E820_MAP_NR);
-	if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
-		unsigned long mem_size;
-
-		/* compare results from other methods and take the greater */
-		if (ALT_MEM_K < EXT_MEM_K) {
-			mem_size = EXT_MEM_K;
-			who = "BIOS-88";
-		} else {
-			mem_size = ALT_MEM_K;
-			who = "BIOS-e801";
-		}
-
-		e820.nr_map = 0;
-		add_memory_region(0, LOWMEMSIZE(), E820_RAM);
-		add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
-  	}
 	printk(KERN_INFO "BIOS-provided physical RAM map:\n");
 	print_memory_map(who);
 } /* setup_memory_region */
@@ -757,7 +738,7 @@
 	 */
 	acpi_reserve_bootmem();
 #endif
-#ifdef CONFIG_X86_LOCAL_APIC
+#ifdef CONFIG_X86_FIND_SMP_CONFIG
 	/*
 	 * Find and reserve possible boot-time SMP configuration:
 	 */
@@ -838,12 +819,9 @@
 {
 	unsigned long max_low_pfn;
 
+	pre_setup_arch_hook();
 	early_cpu_init();
 
-#ifdef CONFIG_VISWS
-	visws_get_board_type_and_rev();
-#endif
-
  	ROOT_DEV = ORIG_ROOT_DEV;
  	drive_info = DRIVE_INFO;
  	screen_info = SCREEN_INFO;
@@ -863,6 +841,7 @@
 	rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
 	rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
 #endif
+	ARCH_SETUP
 	setup_memory_region();
 
 	if (!MOUNT_ROOT_RDONLY)
@@ -922,6 +901,8 @@
 }
 __setup("nohighio", highio_setup);
  
+
+#include "setup_arch_post.h"
 /*
  * Local Variables:
  * mode:c
diff -Nru a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
--- a/arch/i386/kernel/smpboot.c	Fri Sep 20 08:20:46 2002
+++ b/arch/i386/kernel/smpboot.c	Fri Sep 20 08:20:46 2002
@@ -48,6 +48,9 @@
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 #include <asm/smpboot.h>
+#include <asm/desc.h>
+#include <asm/arch_hooks.h>
+#include "smpboot_hooks.h"
 
 /* Set if we find a B stepping CPU */
 static int __initdata smp_b_stepping;
@@ -1003,9 +1006,7 @@
 	 */
 	if (!smp_found_config) {
 		printk(KERN_NOTICE "SMP motherboard not detected.\n");
-#ifndef CONFIG_VISWS
-		io_apic_irqs = 0;
-#endif
+		smpboot_clear_io_apic_irqs();
 		phys_cpu_present_map = 1;
 		if (APIC_init_uniprocessor())
 			printk(KERN_NOTICE "Local APIC not detected."
@@ -1032,9 +1033,7 @@
 		printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
 			boot_cpu_physical_apicid);
 		printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n");
-#ifndef CONFIG_VISWS
-		io_apic_irqs = 0;
-#endif
+		smpboot_clear_io_apic_irqs();
 		phys_cpu_present_map = 1;
 		return;
 	}
@@ -1047,9 +1046,7 @@
 	if (!max_cpus) {
 		smp_found_config = 0;
 		printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n");
-#ifndef CONFIG_VISWS
-		io_apic_irqs = 0;
-#endif
+		smpboot_clear_io_apic_irqs();
 		phys_cpu_present_map = 1;
 		return;
 	}
@@ -1106,22 +1103,7 @@
 	/*
 	 * Cleanup possible dangling ends...
 	 */
-#ifndef CONFIG_VISWS
-	{
-		/*
-		 * Install writable page 0 entry to set BIOS data area.
-		 */
-		local_flush_tlb();
-
-		/*
-		 * Paranoid:  Set warm reset code and vector here back
-		 * to default values.
-		 */
-		CMOS_WRITE(0, 0xf);
-
-		*((volatile long *) phys_to_virt(0x467)) = 0;
-	}
-#endif
+	smpboot_setup_warm_reset_vector();
 
 	/*
 	 * Allow the user to impress friends.
@@ -1173,15 +1155,8 @@
 			}
 		}
 	}
-	     
-#ifndef CONFIG_VISWS
-	/*
-	 * Here we can be sure that there is an IO-APIC in the system. Let's
-	 * go and set it up:
-	 */
-	if (!skip_ioapic_setup && nr_ioapics)
-		setup_IO_APIC();
-#endif
+
+	smpboot_setup_io_apic();
 
 	setup_boot_APIC_clock();
 
@@ -1219,4 +1194,30 @@
 void __init smp_cpus_done(unsigned int max_cpus)
 {
 	zap_low_mappings();
+}
+
+void __init smp_intr_init()
+{
+	/*
+	 * IRQ0 must be given a fixed assignment and initialized,
+	 * because it's used before the IO-APIC is set up.
+	 */
+	set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]);
+
+	/*
+	 * The reschedule interrupt is a CPU-to-CPU reschedule-helper
+	 * IPI, driven by wakeup.
+	 */
+	set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
+
+	/* IPI for invalidation */
+	set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt);
+
+	/* IPI for generic function call */
+	set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
+
+	/* thermal monitor LVT interrupt */
+#ifdef CONFIG_X86_MCE_P4THERMAL
+	set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
+#endif
 }
diff -Nru a/arch/i386/kernel/suspend.c b/arch/i386/kernel/suspend.c
--- a/arch/i386/kernel/suspend.c	Fri Sep 20 08:20:47 2002
+++ b/arch/i386/kernel/suspend.c	Fri Sep 20 08:20:47 2002
@@ -22,6 +22,7 @@
 #include <linux/pm.h>
 #include <linux/device.h>
 #include <linux/suspend.h>
+#include <linux/acpi.h>
 #include <asm/uaccess.h>
 #include <asm/acpi.h>
 #include <asm/tlbflush.h>
diff -Nru a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
--- a/arch/i386/kernel/time.c	Fri Sep 20 08:20:46 2002
+++ b/arch/i386/kernel/time.c	Fri Sep 20 08:20:46 2002
@@ -57,8 +57,11 @@
 #include <linux/timex.h>
 #include <linux/config.h>
 
-#include <asm/fixmap.h>
-#include <asm/cobalt.h>
+#include <asm/arch_hooks.h>
+
+extern spinlock_t i8259A_lock;
+
+#include "do_timer.h"
 
 /*
  * for x86_do_profile()
@@ -120,8 +123,6 @@
 spinlock_t i8253_lock = SPIN_LOCK_UNLOCKED;
 EXPORT_SYMBOL(i8253_lock);
 
-extern spinlock_t i8259A_lock;
-
 #ifndef CONFIG_X86_TSC
 
 /* This function must be called with interrupts disabled 
@@ -202,47 +203,11 @@
 	 *     (see c't 95/10 page 335 for Neptun bug.)
 	 */
 
-/* you can safely undefine this if you don't have the Neptune chipset */
-
-#define BUGGY_NEPTUN_TIMER
 
 	if( jiffies_t == jiffies_p ) {
 		if( count > count_p ) {
 			/* the nutcase */
-
-			int i;
-
-			spin_lock(&i8259A_lock);
-			/*
-			 * This is tricky when I/O APICs are used;
-			 * see do_timer_interrupt().
-			 */
-			i = inb(0x20);
-			spin_unlock(&i8259A_lock);
-
-			/* assumption about timer being IRQ0 */
-			if (i & 0x01) {
-				/*
-				 * We cannot detect lost timer interrupts ... 
-				 * well, that's why we call them lost, don't we? :)
-				 * [hmm, on the Pentium and Alpha we can ... sort of]
-				 */
-				count -= LATCH;
-			} else {
-#ifdef BUGGY_NEPTUN_TIMER
-				/*
-				 * for the Neptun bug we know that the 'latch'
-				 * command doesnt latch the high and low value
-				 * of the counter atomically. Thus we have to 
-				 * substract 256 from the counter 
-				 * ... funny, isnt it? :)
-				 */
-
-				count -= 256;
-#else
-				printk("do_slow_gettimeoffset(): hardware timer problem?\n");
-#endif
-			}
+			count = do_timer_overflow(count);
 		}
 	} else
 		jiffies_p = jiffies_t;
@@ -413,23 +378,7 @@
 	}
 #endif
 
-#ifdef CONFIG_VISWS
-	/* Clear the interrupt */
-	co_cpu_write(CO_CPU_STAT,co_cpu_read(CO_CPU_STAT) & ~CO_STAT_TIMEINTR);
-#endif
-	do_timer(regs);
-/*
- * In the SMP case we use the local APIC timer interrupt to do the
- * profiling, except when we simulate SMP mode on a uniprocessor
- * system, in that case we have to call the local interrupt handler.
- */
-#ifndef CONFIG_X86_LOCAL_APIC
-	if (!user_mode(regs))
-		x86_do_profile(regs->eip);
-#else
-	if (!using_apic_timer)
-		smp_local_timer_interrupt(regs);
-#endif
+	do_timer_interrupt_hook(regs);
 
 	/*
 	 * If we have an externally synchronized Linux clock, then update
@@ -470,7 +419,7 @@
  * Time Stamp Counter value at the time of the timer interrupt, so that
  * we later on can estimate the time of day more exactly.
  */
-static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	int count;
 
@@ -560,8 +509,6 @@
 	return mktime(year, mon, day, hour, min, sec);
 }
 
-static struct irqaction irq0  = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL};
-
 /* ------ Calibrate the TSC ------- 
  * Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset().
  * Too much 64-bit arithmetic here to do this cleanly in C, and for
@@ -574,6 +521,7 @@
 #define CALIBRATE_LATCH	(5 * LATCH)
 #define CALIBRATE_TIME	(5 * 1000020/HZ)
 
+#ifdef CONFIG_X86_TSC
 static unsigned long __init calibrate_tsc(void)
 {
        /* Set the Gate high, disable speaker */
@@ -638,6 +586,7 @@
 bad_ctc:
 	return 0;
 }
+#endif /* CONFIG_X86_TSC */
 
 static struct device device_i8253 = {
 	.name	       	= "i8253",
@@ -653,7 +602,9 @@
 
 void __init time_init(void)
 {
+#ifdef CONFIG_X86_TSC
 	extern int x86_udelay_tsc;
+#endif
 	
 	xtime.tv_sec = get_cmos_time();
 	xtime.tv_nsec = 0;
@@ -672,6 +623,7 @@
  * to disk; this won't break the kernel, though, 'cuz we're
  * smart.  See arch/i386/kernel/apm.c.
  */
+#ifdef CONFIG_X86_TSC
  	/*
  	 *	Firstly we have to do a CPU check for chips with
  	 * 	a potentially buggy TSC. At this point we haven't run
@@ -712,22 +664,7 @@
 			}
 		}
 	}
+#endif /* CONFIG_X86_TSC */
 
-#ifdef CONFIG_VISWS
-	printk("Starting Cobalt Timer system clock\n");
-
-	/* Set the countdown value */
-	co_cpu_write(CO_CPU_TIMEVAL, CO_TIME_HZ/HZ);
-
-	/* Start the timer */
-	co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) | CO_CTRL_TIMERUN);
-
-	/* Enable (unmask) the timer interrupt */
-	co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK);
-
-	/* Wire cpu IDT entry to s/w handler (and Cobalt APIC to IDT) */
-	setup_irq(CO_IRQ_TIMER, &irq0);
-#else
-	setup_irq(0, &irq0);
-#endif
+	time_init_hook();
 }
diff -Nru a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
--- a/arch/i386/kernel/traps.c	Fri Sep 20 08:20:43 2002
+++ b/arch/i386/kernel/traps.c	Fri Sep 20 08:20:43 2002
@@ -43,12 +43,7 @@
 
 #include <asm/smp.h>
 #include <asm/pgalloc.h>
-
-#ifdef CONFIG_X86_VISWS_APIC
-#include <asm/fixmap.h>
-#include <asm/cobalt.h>
-#include <asm/lithium.h>
-#endif
+#include <asm/arch_hooks.h>
 
 #include <linux/irq.h>
 #include <linux/module.h>
@@ -840,96 +835,6 @@
 	_set_gate(a,12,3,addr);
 }
 
-#ifdef CONFIG_X86_VISWS_APIC
-
-/*
- * On Rev 005 motherboards legacy device interrupt lines are wired directly
- * to Lithium from the 307.  But the PROM leaves the interrupt type of each
- * 307 logical device set appropriate for the 8259.  Later we'll actually use
- * the 8259, but for now we have to flip the interrupt types to
- * level triggered, active lo as required by Lithium.
- */
-
-#define	REG	0x2e	/* The register to read/write */
-#define	DEV	0x07	/* Register: Logical device select */
-#define	VAL	0x2f	/* The value to read/write */
-
-static void
-superio_outb(int dev, int reg, int val)
-{
-	outb(DEV, REG);
-	outb(dev, VAL);
-	outb(reg, REG);
-	outb(val, VAL);
-}
-
-static int __attribute__ ((unused))
-superio_inb(int dev, int reg)
-{
-	outb(DEV, REG);
-	outb(dev, VAL);
-	outb(reg, REG);
-	return inb(VAL);
-}
-
-#define	FLOP	3	/* floppy logical device */
-#define	PPORT	4	/* parallel logical device */
-#define	UART5	5	/* uart2 logical device (not wired up) */
-#define	UART6	6	/* uart1 logical device (THIS is the serial port!) */
-#define	IDEST	0x70	/* int. destination (which 307 IRQ line) reg. */
-#define	ITYPE	0x71	/* interrupt type register */
-
-/* interrupt type bits */
-#define	LEVEL	0x01	/* bit 0, 0 == edge triggered */
-#define	ACTHI	0x02	/* bit 1, 0 == active lo */
-
-static void
-superio_init(void)
-{
-	if (visws_board_type == VISWS_320 && visws_board_rev == 5) {
-		superio_outb(UART6, IDEST, 0);	/* 0 means no intr propagated */
-		printk("SGI 320 rev 5: disabling 307 uart1 interrupt\n");
-	}
-}
-
-static void
-lithium_init(void)
-{
-	set_fixmap(FIX_LI_PCIA, LI_PCI_A_PHYS);
-	printk("Lithium PCI Bridge A, Bus Number: %d\n",
-				li_pcia_read16(LI_PCI_BUSNUM) & 0xff);
-	set_fixmap(FIX_LI_PCIB, LI_PCI_B_PHYS);
-	printk("Lithium PCI Bridge B (PIIX4), Bus Number: %d\n",
-				li_pcib_read16(LI_PCI_BUSNUM) & 0xff);
-
-	/* XXX blindly enables all interrupts */
-	li_pcia_write16(LI_PCI_INTEN, 0xffff);
-	li_pcib_write16(LI_PCI_INTEN, 0xffff);
-}
-
-static void
-cobalt_init(void)
-{
-	/*
-	 * On normal SMP PC this is used only with SMP, but we have to
-	 * use it and set it up here to start the Cobalt clock
-	 */
-	set_fixmap(FIX_APIC_BASE, APIC_DEFAULT_PHYS_BASE);
-	printk("Local APIC ID %lx\n", apic_read(APIC_ID));
-	printk("Local APIC Version %lx\n", apic_read(APIC_LVR));
-
-	set_fixmap(FIX_CO_CPU, CO_CPU_PHYS);
-	printk("Cobalt Revision %lx\n", co_cpu_read(CO_CPU_REV));
-
-	set_fixmap(FIX_CO_APIC, CO_APIC_PHYS);
-	printk("Cobalt APIC ID %lx\n", co_apic_read(CO_APIC_ID));
-
-	/* Enable Cobalt APIC being careful to NOT change the ID! */
-	co_apic_write(CO_APIC_ID, co_apic_read(CO_APIC_ID)|CO_APIC_ENABLE);
-
-	printk("Cobalt APIC enabled: ID reg %lx\n", co_apic_read(CO_APIC_ID));
-}
-#endif
 
 #ifdef CONFIG_EISA
 int EISA_bus;
@@ -985,9 +890,5 @@
 	 */
 	cpu_init();
 
-#ifdef CONFIG_X86_VISWS_APIC
-	superio_init();
-	lithium_init();
-	cobalt_init();
-#endif
+	trap_init_hook();
 }
diff -Nru a/arch/i386/kernel/visws_apic.c b/arch/i386/kernel/visws_apic.c
--- a/arch/i386/kernel/visws_apic.c	Fri Sep 20 08:20:41 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,410 +0,0 @@
-/*
- *	linux/arch/i386/kernel/visws_apic.c
- *
- *	Copyright (C) 1999 Bent Hagemark, Ingo Molnar
- *
- *  SGI Visual Workstation interrupt controller
- *
- *  The Cobalt system ASIC in the Visual Workstation contains a "Cobalt" APIC
- *  which serves as the main interrupt controller in the system.  Non-legacy
- *  hardware in the system uses this controller directly.  Legacy devices
- *  are connected to the PIIX4 which in turn has its 8259(s) connected to
- *  a of the Cobalt APIC entry.
- */
-
-#include <linux/ptrace.h>
-#include <linux/errno.h>
-#include <linux/kernel_stat.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/timex.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/init.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/bitops.h>
-#include <asm/smp.h>
-#include <asm/pgtable.h>
-#include <asm/delay.h>
-#include <asm/desc.h>
-
-#include <asm/cobalt.h>
-
-#include <linux/irq.h>
-
-/*
- * This is the PIIX4-based 8259 that is wired up indirectly to Cobalt
- * -- not the manner expected by the normal 8259 code in irq.c.
- *
- * there is a 'master' physical interrupt source that gets sent to
- * the CPU. But in the chipset there are various 'virtual' interrupts
- * waiting to be handled. We represent this to Linux through a 'master'
- * interrupt controller type, and through a special virtual interrupt-
- * controller. Device drivers only see the virtual interrupt sources.
- */
-
-#define	CO_IRQ_BASE	0x20	/* This is the 0x20 in init_IRQ()! */
-
-static void startup_piix4_master_irq(unsigned int irq);
-static void shutdown_piix4_master_irq(unsigned int irq);
-static void do_piix4_master_IRQ(unsigned int irq, struct pt_regs * regs);
-#define enable_piix4_master_irq startup_piix4_master_irq
-#define disable_piix4_master_irq shutdown_piix4_master_irq
-
-static struct hw_interrupt_type piix4_master_irq_type = {
-	"PIIX4-master",
-	startup_piix4_master_irq,
-	shutdown_piix4_master_irq,
-	do_piix4_master_IRQ,
-	enable_piix4_master_irq,
-	disable_piix4_master_irq
-};
-
-static void enable_piix4_virtual_irq(unsigned int irq);
-static void disable_piix4_virtual_irq(unsigned int irq);
-#define startup_piix4_virtual_irq enable_piix4_virtual_irq
-#define shutdown_piix4_virtual_irq disable_piix4_virtual_irq
-
-static struct hw_interrupt_type piix4_virtual_irq_type = {
-	"PIIX4-virtual",
-	startup_piix4_virtual_irq,
-	shutdown_piix4_virtual_irq,
-	0, /* no handler, it's never called physically */
-	enable_piix4_virtual_irq,
-	disable_piix4_virtual_irq
-};
-
-/*
- * This is the SGI Cobalt (IO-)APIC:
- */
-
-static void do_cobalt_IRQ(unsigned int irq, struct pt_regs * regs);
-static void enable_cobalt_irq(unsigned int irq);
-static void disable_cobalt_irq(unsigned int irq);
-static void startup_cobalt_irq(unsigned int irq);
-#define shutdown_cobalt_irq disable_cobalt_irq
-
-static spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED;
-
-static struct hw_interrupt_type cobalt_irq_type = {
-	"Cobalt-APIC",
-	startup_cobalt_irq,
-	shutdown_cobalt_irq,
-	do_cobalt_IRQ,
-	enable_cobalt_irq,
-	disable_cobalt_irq
-};
-
-
-/*
- * Not an __init, needed by the reboot code
- */
-void disable_IO_APIC(void)
-{
-	/* Nop on Cobalt */
-} 
-
-/*
- * Cobalt (IO)-APIC functions to handle PCI devices.
- */
-
-static void disable_cobalt_irq(unsigned int irq)
-{
-	/* XXX undo the APIC entry here? */
-
-	/*
-	 * definitely, we do not want to have IRQ storms from
-	 * unused devices --mingo
-	 */
-}
-
-static void enable_cobalt_irq(unsigned int irq)
-{
-}
-
-/*
- * Set the given Cobalt APIC Redirection Table entry to point
- * to the given IDT vector/index.
- */
-static void co_apic_set(int entry, int idtvec)
-{
-	co_apic_write(CO_APIC_LO(entry), CO_APIC_LEVEL | (CO_IRQ_BASE+idtvec));
-	co_apic_write(CO_APIC_HI(entry), 0);
-
-	printk("Cobalt APIC Entry %d IDT Vector %d\n", entry, idtvec);
-}
-
-/*
- * "irq" really just serves to identify the device.  Here is where we
- * map this to the Cobalt APIC entry where it's physically wired.
- * This is called via request_irq -> setup_x86_irq -> irq_desc->startup()
- */
-static void startup_cobalt_irq(unsigned int irq)
-{
-	/*
-	 * These "irq"'s are wired to the same Cobalt APIC entries
-	 * for all (known) motherboard types/revs
-	 */
-	switch (irq) {
-	case CO_IRQ_TIMER:	co_apic_set(CO_APIC_CPU, CO_IRQ_TIMER);
-				return;
-
-	case CO_IRQ_ENET:	co_apic_set(CO_APIC_ENET, CO_IRQ_ENET);
-				return;
-
-	case CO_IRQ_SERIAL:	return; /* XXX move to piix4-8259 "virtual" */
-
-	case CO_IRQ_8259:	co_apic_set(CO_APIC_8259, CO_IRQ_8259);
-				return;
-
-	case CO_IRQ_IDE:
-		switch (visws_board_type) {
-		case VISWS_320:
-			switch (visws_board_rev) {
-			case 5:
-				co_apic_set(CO_APIC_0_5_IDE0, CO_IRQ_IDE);
-				co_apic_set(CO_APIC_0_5_IDE1, CO_IRQ_IDE);
-					return;
-			case 6:
-				co_apic_set(CO_APIC_0_6_IDE0, CO_IRQ_IDE);
-				co_apic_set(CO_APIC_0_6_IDE1, CO_IRQ_IDE);
-					return;
-			}
-		case VISWS_540:
-			switch (visws_board_rev) {
-			case 2:
-				co_apic_set(CO_APIC_1_2_IDE0, CO_IRQ_IDE);
-					return;
-			}
-		}
-		break;
-	default:
-		panic("huh?");
-	}
-}
-
-/*
- * This is the handle() op in do_IRQ()
- */
-static void do_cobalt_IRQ(unsigned int irq, struct pt_regs * regs)
-{
-	struct irqaction * action;
-	irq_desc_t *desc = irq_desc + irq;
-
-	spin_lock(&irq_controller_lock);
-	{
-		unsigned int status;
-		/* XXX APIC EOI? */
-		status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
-		action = NULL;
-		if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
-			action = desc->action;
-			status |= IRQ_INPROGRESS;
-		}
-		desc->status = status;
-	}
-	spin_unlock(&irq_controller_lock);
-
-	/* Exit early if we had no action or it was disabled */
-	if (!action)
-		return;
-
-	handle_IRQ_event(irq, regs, action);
-
-	(void)co_cpu_read(CO_CPU_REV); /* Sync driver ack to its h/w */
-	apic_write(APIC_EOI, APIC_EIO_ACK); /* Send EOI to Cobalt APIC */
-
-	spin_lock(&irq_controller_lock);
-	{
-		unsigned int status = desc->status & ~IRQ_INPROGRESS;
-		desc->status = status;
-		if (!(status & IRQ_DISABLED))
-			enable_cobalt_irq(irq);
-	}
-	spin_unlock(&irq_controller_lock);
-}
-
-/*
- * PIIX4-8259 master/virtual functions to handle:
- *
- *	floppy
- *	parallel
- *	serial
- *	audio (?)
- *
- * None of these get Cobalt APIC entries, neither do they have IDT
- * entries. These interrupts are purely virtual and distributed from
- * the 'master' interrupt source: CO_IRQ_8259.
- *
- * When the 8259 interrupts its handler figures out which of these
- * devices is interrupting and dispatches to it's handler.
- *
- * CAREFUL: devices see the 'virtual' interrupt only. Thus disable/
- * enable_irq gets the right irq. This 'master' irq is never directly
- * manipulated by any driver.
- */
-
-static void startup_piix4_master_irq(unsigned int irq)
-{
-	/* ICW1 */
-	outb(0x11, 0x20);
-	outb(0x11, 0xa0);
-
-	/* ICW2 */
-	outb(0x08, 0x21);
-	outb(0x70, 0xa1);
-
-	/* ICW3 */
-	outb(0x04, 0x21);
-	outb(0x02, 0xa1);
-
-	/* ICW4 */
-	outb(0x01, 0x21);
-	outb(0x01, 0xa1);
-
-	/* OCW1 - disable all interrupts in both 8259's */
-	outb(0xff, 0x21);
-	outb(0xff, 0xa1);
-
-	startup_cobalt_irq(irq);
-}
-
-static void shutdown_piix4_master_irq(unsigned int irq)
-{
-	/*
-	 * [we skip the 8259 magic here, not strictly necessary]
-	 */
-
-	shutdown_cobalt_irq(irq);
-}
-
-static void do_piix4_master_IRQ(unsigned int irq, struct pt_regs * regs)
-{
-	int realirq, mask;
-
-	/* Find out what's interrupting in the PIIX4 8259 */
-
-	spin_lock(&irq_controller_lock);
-	outb(0x0c, 0x20);		/* OCW3 Poll command */
-	realirq = inb(0x20);
-
-	if (!(realirq & 0x80)) {
-		/*
-		 * Bit 7 == 0 means invalid/spurious
-		 */
-		goto out_unlock;
-	}
-	realirq &= 0x7f;
-
-	/*
-	 * mask and ack the 8259
-	 */
-	mask = inb(0x21);
-	if ((mask >> realirq) & 0x01)
-		/*
-		 * This IRQ is masked... ignore
-		 */
-		goto out_unlock;
-
-	outb(mask | (1<<realirq), 0x21);
-	/*
-	 * OCW2 - non-specific EOI
-	 */
-	outb(0x20, 0x20);
-
-	spin_unlock(&irq_controller_lock);
-
-	/*
-	 * handle this 'virtual interrupt' as a Cobalt one now.
-	 */
-	kstat.irqs[smp_processor_id()][irq]++;
-	do_cobalt_IRQ(realirq, regs);
-
-	spin_lock(&irq_controller_lock);
-	{
-		irq_desc_t *desc = irq_desc + realirq;
-
-		if (!(desc->status & IRQ_DISABLED))
-			enable_piix4_virtual_irq(realirq);
-	}
-	spin_unlock(&irq_controller_lock);
-	return;
-
-out_unlock:
-	spin_unlock(&irq_controller_lock);
-	return;
-}
-
-static void enable_piix4_virtual_irq(unsigned int irq)
-{
-	/*
-	 * assumes this irq is one of the legacy devices
-	 */
-
-	unsigned int mask = inb(0x21);
- 	mask &= ~(1 << irq);
-	outb(mask, 0x21);
-	enable_cobalt_irq(irq);
-}
-
-/*
- * assumes this irq is one of the legacy devices
- */
-static void disable_piix4_virtual_irq(unsigned int irq)
-{
-	unsigned int mask;
-
-	disable_cobalt_irq(irq);
-
-	mask = inb(0x21);
- 	mask &= ~(1 << irq);
-	outb(mask, 0x21);
-}
-
-static struct irqaction master_action =
-		{ no_action, 0, 0, "PIIX4-8259", NULL, NULL };
-
-void init_VISWS_APIC_irqs(void)
-{
-	int i;
-
-	for (i = 0; i < 16; i++) {
-		irq_desc[i].status = IRQ_DISABLED;
-		irq_desc[i].action = 0;
-		irq_desc[i].depth = 1;
-
-		/*
-		 * Cobalt IRQs are mapped to standard ISA
-		 * interrupt vectors:
-		 */
-		switch (i) {
-			/*
-			 * Only CO_IRQ_8259 will be raised
-			 * externally.
-			 */
-		case CO_IRQ_8259:
-			irq_desc[i].handler = &piix4_master_irq_type;
-			break;
-		case CO_IRQ_FLOPPY:
-		case CO_IRQ_PARLL:
-			irq_desc[i].handler = &piix4_virtual_irq_type;
-			break;
-		default:
-			irq_desc[i].handler = &cobalt_irq_type;
-			break;
-		}
-	}
-
-	/*
-	 * The master interrupt is always present:
-	 */
-	setup_x86_irq(CO_IRQ_8259, &master_action);
-}
-
diff -Nru a/arch/i386/lib/checksum.S b/arch/i386/lib/checksum.S
--- a/arch/i386/lib/checksum.S	Fri Sep 20 08:20:44 2002
+++ b/arch/i386/lib/checksum.S	Fri Sep 20 08:20:44 2002
@@ -55,8 +55,21 @@
 	movl 20(%esp),%eax	# Function arg: unsigned int sum
 	movl 16(%esp),%ecx	# Function arg: int len
 	movl 12(%esp),%esi	# Function arg: unsigned char *buff
-	testl $2, %esi		# Check alignment.
+	testl $3, %esi		# Check alignment.
 	jz 2f			# Jump if alignment is ok.
+	testl $1, %esi		# Check alignment.
+	jz 10f			# Jump if alignment is boundary of 2bytes.
+
+	# buf is odd
+	dec %ecx
+	jl 8f
+	movzbl (%esi), %ebx
+	adcl %ebx, %eax
+	roll $8, %eax
+	inc %esi
+	testl $2, %esi
+	jz 2f
+10:
 	subl $2, %ecx		# Alignment uses up two bytes.
 	jae 1f			# Jump if we had at least two bytes.
 	addl $2, %ecx		# ecx was < 2.  Deal with it.
@@ -111,6 +124,10 @@
 6:	addl %ecx,%eax
 	adcl $0, %eax 
 7:	
+	testl $1, 12(%esp)
+	jz 8f
+	roll $8, %eax
+8:
 	popl %ebx
 	popl %esi
 	ret
@@ -126,8 +143,8 @@
 	movl 16(%esp),%ecx	# Function arg: int len
 	movl 12(%esp),%esi	# Function arg:	const unsigned char *buf
 
-	testl $2, %esi         
-	jnz 30f                 
+	testl $3, %esi         
+	jnz 25f                 
 10:
 	movl %ecx, %edx
 	movl %ecx, %ebx
@@ -145,6 +162,19 @@
 	lea 2(%esi), %esi
 	adcl $0, %eax
 	jmp 10b
+25:
+	testl $1, %esi         
+	jz 30f                 
+	# buf is odd
+	dec %ecx
+	jl 90f
+	movzbl (%esi), %ebx
+	addl %ebx, %eax
+	adcl $0, %eax
+	roll $8, %eax
+	inc %esi
+	testl $2, %esi
+	jz 10b
 
 30:	subl $2, %ecx          
 	ja 20b                 
@@ -211,6 +241,10 @@
 	addl %ebx,%eax
 	adcl $0,%eax
 80: 
+	testl $1, 12(%esp)
+	jz 90f
+	roll $8, %eax
+90: 
 	popl %ebx
 	popl %esi
 	ret
diff -Nru a/arch/i386/mach-generic/Makefile b/arch/i386/mach-generic/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-generic/Makefile	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,15 @@
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+EXTRA_CFLAGS	+= -I../kernel
+export-objs     := 
+
+obj-y				:= setup.o
+
+include $(TOPDIR)/Rules.make
diff -Nru a/arch/i386/mach-generic/do_timer.h b/arch/i386/mach-generic/do_timer.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-generic/do_timer.h	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,81 @@
+/* defines for inline arch setup functions */
+
+/**
+ * do_timer_interrupt_hook - hook into timer tick
+ * @regs:	standard registers from interrupt
+ *
+ * Description:
+ *	This hook is called immediately after the timer interrupt is ack'd.
+ *	It's primary purpose is to allow architectures that don't possess
+ *	individual per CPU clocks (like the CPU APICs supply) to broadcast the
+ *	timer interrupt as a means of triggering reschedules etc.
+ **/
+
+static inline void do_timer_interrupt_hook(struct pt_regs *regs)
+{
+	do_timer(regs);
+/*
+ * In the SMP case we use the local APIC timer interrupt to do the
+ * profiling, except when we simulate SMP mode on a uniprocessor
+ * system, in that case we have to call the local interrupt handler.
+ */
+#ifndef CONFIG_X86_LOCAL_APIC
+	if (!user_mode(regs))
+		x86_do_profile(regs->eip);
+#else
+	if (!using_apic_timer)
+		smp_local_timer_interrupt(regs);
+#endif
+}
+
+
+/* you can safely undefine this if you don't have the Neptune chipset */
+
+#define BUGGY_NEPTUN_TIMER
+
+/**
+ * do_timer_overflow - process a detected timer overflow condition
+ * @count:	hardware timer interrupt count on overflow
+ *
+ * Description:
+ *	This call is invoked when the jiffies count has not incremented but
+ *	the hardware timer interrupt has.  It means that a timer tick interrupt
+ *	came along while the previous one was pending, thus a tick was missed
+ **/
+static inline int do_timer_overflow(int count)
+{
+	int i;
+
+	spin_lock(&i8259A_lock);
+	/*
+	 * This is tricky when I/O APICs are used;
+	 * see do_timer_interrupt().
+	 */
+	i = inb(0x20);
+	spin_unlock(&i8259A_lock);
+	
+	/* assumption about timer being IRQ0 */
+	if (i & 0x01) {
+		/*
+		 * We cannot detect lost timer interrupts ... 
+		 * well, that's why we call them lost, don't we? :)
+		 * [hmm, on the Pentium and Alpha we can ... sort of]
+		 */
+		count -= LATCH;
+	} else {
+#ifdef BUGGY_NEPTUN_TIMER
+		/*
+		 * for the Neptun bug we know that the 'latch'
+		 * command doesnt latch the high and low value
+		 * of the counter atomically. Thus we have to 
+		 * substract 256 from the counter 
+		 * ... funny, isnt it? :)
+		 */
+		
+		count -= 256;
+#else
+		printk("do_slow_gettimeoffset(): hardware timer problem?\n");
+#endif
+	}
+	return count;
+}
diff -Nru a/arch/i386/mach-generic/entry_arch.h b/arch/i386/mach-generic/entry_arch.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-generic/entry_arch.h	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,34 @@
+/*
+ * This file is designed to contain the BUILD_INTERRUPT specifications for
+ * all of the extra named interrupt vectors used by the architecture.
+ * Usually this is the Inter Process Interrupts (IPIs)
+ */
+
+/*
+ * The following vectors are part of the Linux architecture, there
+ * is no hardware IRQ pin equivalent for them, they are triggered
+ * through the ICC by us (IPIs)
+ */
+#ifdef CONFIG_X86_SMP
+BUILD_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR)
+BUILD_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR)
+BUILD_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR)
+#endif
+
+/*
+ * every pentium local APIC has two 'local interrupts', with a
+ * soft-definable vector attached to both interrupts, one of
+ * which is a timer interrupt, the other one is error counter
+ * overflow. Linux uses the local APIC timer interrupt to get
+ * a much simpler SMP time architecture:
+ */
+#ifdef CONFIG_X86_LOCAL_APIC
+BUILD_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR)
+BUILD_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR)
+BUILD_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR)
+
+#ifdef CONFIG_X86_MCE_P4THERMAL
+BUILD_INTERRUPT(thermal_interrupt,THERMAL_APIC_VECTOR)
+#endif
+
+#endif
diff -Nru a/arch/i386/mach-generic/irq_vectors.h b/arch/i386/mach-generic/irq_vectors.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-generic/irq_vectors.h	Fri Sep 20 08:20:43 2002
@@ -0,0 +1,85 @@
+/*
+ * This file should contain #defines for all of the interrupt vector
+ * numbers used by this architecture.
+ *
+ * In addition, there are some standard defines:
+ *
+ *	FIRST_EXTERNAL_VECTOR:
+ *		The first free place for external interrupts
+ *
+ *	SYSCALL_VECTOR:
+ *		The IRQ vector a syscall makes the user to kernel transition
+ *		under.
+ *
+ *	TIMER_IRQ:
+ *		The IRQ number the timer interrupt comes in at.
+ *
+ *	NR_IRQS:
+ *		The total number of interrupt vectors (including all the
+ *		architecture specific interrupts) needed.
+ *
+ */			
+#ifndef _ASM_IRQ_VECTORS_H
+#define _ASM_IRQ_VECTORS_H
+
+/*
+ * IDT vectors usable for external interrupt sources start
+ * at 0x20:
+ */
+#define FIRST_EXTERNAL_VECTOR	0x20
+
+#define SYSCALL_VECTOR		0x80
+
+/*
+ * Vectors 0x20-0x2f are used for ISA interrupts.
+ */
+
+/*
+ * Special IRQ vectors used by the SMP architecture, 0xf0-0xff
+ *
+ *  some of the following vectors are 'rare', they are merged
+ *  into a single vector (CALL_FUNCTION_VECTOR) to save vector space.
+ *  TLB, reschedule and local APIC vectors are performance-critical.
+ *
+ *  Vectors 0xf0-0xfa are free (reserved for future Linux use).
+ */
+#define SPURIOUS_APIC_VECTOR	0xff
+#define ERROR_APIC_VECTOR	0xfe
+#define INVALIDATE_TLB_VECTOR	0xfd
+#define RESCHEDULE_VECTOR	0xfc
+#define CALL_FUNCTION_VECTOR	0xfb
+
+#define THERMAL_APIC_VECTOR	0xf0
+/*
+ * Local APIC timer IRQ vector is on a different priority level,
+ * to work around the 'lost local interrupt if more than 2 IRQ
+ * sources per level' errata.
+ */
+#define LOCAL_TIMER_VECTOR	0xef
+
+/*
+ * First APIC vector available to drivers: (vectors 0x30-0xee)
+ * we start at 0x31 to spread out vectors evenly between priority
+ * levels. (0x80 is the syscall vector)
+ */
+#define FIRST_DEVICE_VECTOR	0x31
+#define FIRST_SYSTEM_VECTOR	0xef
+
+#define TIMER_IRQ 0
+
+/*
+ * 16 8259A IRQ's, 208 potential APIC interrupt sources.
+ * Right now the APIC is mostly only used for SMP.
+ * 256 vectors is an architectural limit. (we can have
+ * more than 256 devices theoretically, but they will
+ * have to use shared interrupts)
+ * Since vectors 0x00-0x1f are used/reserved for the CPU,
+ * the usable vector space is 0x20-0xff (224 vectors)
+ */
+#ifdef CONFIG_X86_IO_APIC
+#define NR_IRQS 224
+#else
+#define NR_IRQS 16
+#endif
+
+#endif /* _ASM_IRQ_VECTORS_H */
diff -Nru a/arch/i386/mach-generic/setup.c b/arch/i386/mach-generic/setup.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-generic/setup.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,104 @@
+/*
+ *	Machine specific setup for generic
+ */
+
+#include <linux/config.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <asm/arch_hooks.h>
+
+/**
+ * pre_intr_init_hook - initialisation prior to setting up interrupt vectors
+ *
+ * Description:
+ *	Perform any necessary interrupt initialisation prior to setting up
+ *	the "ordinary" interrupt call gates.  For legacy reasons, the ISA
+ *	interrupts should be initialised here if the machine emulates a PC
+ *	in any way.
+ **/
+void __init pre_intr_init_hook(void)
+{
+	init_ISA_irqs();
+}
+
+/*
+ * IRQ2 is cascade interrupt to second interrupt controller
+ */
+static struct irqaction irq2 = { no_action, 0, 0, "cascade", NULL, NULL};
+
+/**
+ * intr_init_hook - post gate setup interrupt initialisation
+ *
+ * Description:
+ *	Fill in any interrupts that may have been left out by the general
+ *	init_IRQ() routine.  interrupts having to do with the machine rather
+ *	than the devices on the I/O bus (like APIC interrupts in intel MP
+ *	systems) are started here.
+ **/
+void __init intr_init_hook(void)
+{
+#ifdef CONFIG_X86_LOCAL_APIC
+	apic_intr_init();
+#endif
+
+	setup_irq(2, &irq2);
+}
+
+/**
+ * pre_setup_arch_hook - hook called prior to any setup_arch() execution
+ *
+ * Description:
+ *	generally used to activate any machine specific identification
+ *	routines that may be needed before setup_arch() runs.  On VISWS
+ *	this is used to get the board revision and type.
+ **/
+void __init pre_setup_arch_hook(void)
+{
+}
+
+/**
+ * trap_init_hook - initialise system specific traps
+ *
+ * Description:
+ *	Called as the final act of trap_init().  Used in VISWS to initialise
+ *	the various board specific APIC traps.
+ **/
+void __init trap_init_hook(void)
+{
+}
+
+static struct irqaction irq0  = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL};
+
+/**
+ * time_init_hook - do any specific initialisations for the system timer.
+ *
+ * Description:
+ *	Must plug the system timer interrupt source at HZ into the IRQ listed
+ *	in irq_vectors.h:TIMER_IRQ
+ **/
+void __init time_init_hook(void)
+{
+	setup_irq(0, &irq0);
+}
+
+#ifdef CONFIG_MCA
+/**
+ * mca_nmi_hook - hook into MCA specific NMI chain
+ *
+ * Description:
+ *	The MCA (Microchannel Arcitecture) has an NMI chain for NMI sources
+ *	along the MCA bus.  Use this to hook into that chain if you will need
+ *	it.
+ **/
+void __init mca_nmi_hook(void)
+{
+	/* If I recall correctly, there's a whole bunch of other things that
+	 * we can do to check for NMI problems, but that's all I know about
+	 * at the moment.
+	 */
+
+	printk("NMI generated from unknown source!\n");
+}
+#endif
diff -Nru a/arch/i386/mach-generic/setup_arch_post.h b/arch/i386/mach-generic/setup_arch_post.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-generic/setup_arch_post.h	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,40 @@
+/**
+ * machine_specific_memory_setup - Hook for machine specific memory setup.
+ *
+ * Description:
+ *	This is included late in kernel/setup.c so that it can make
+ *	use of all of the static functions.
+ **/
+
+static inline char * __init machine_specific_memory_setup(void)
+{
+	char *who;
+
+
+	who = "BIOS-e820";
+
+	/*
+	 * Try to copy the BIOS-supplied E820-map.
+	 *
+	 * Otherwise fake a memory map; one section from 0k->640k,
+	 * the next section from 1mb->appropriate_mem_k
+	 */
+	sanitize_e820_map(E820_MAP, &E820_MAP_NR);
+	if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
+		unsigned long mem_size;
+
+		/* compare results from other methods and take the greater */
+		if (ALT_MEM_K < EXT_MEM_K) {
+			mem_size = EXT_MEM_K;
+			who = "BIOS-88";
+		} else {
+			mem_size = ALT_MEM_K;
+			who = "BIOS-e801";
+		}
+
+		e820.nr_map = 0;
+		add_memory_region(0, LOWMEMSIZE(), E820_RAM);
+		add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
+  	}
+	return who;
+}
diff -Nru a/arch/i386/mach-generic/setup_arch_pre.h b/arch/i386/mach-generic/setup_arch_pre.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-generic/setup_arch_pre.h	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,5 @@
+/* Hook to call BIOS initialisation function */
+
+/* no action for generic */
+
+#define ARCH_SETUP
diff -Nru a/arch/i386/mach-generic/smpboot_hooks.h b/arch/i386/mach-generic/smpboot_hooks.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-generic/smpboot_hooks.h	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,33 @@
+/* two abstractions specific to kernel/smpboot.c, mainly to cater to visws
+ * which needs to alter them. */
+
+static inline void smpboot_clear_io_apic_irqs(void)
+{
+	io_apic_irqs = 0;
+}
+
+static inline void smpboot_setup_warm_reset_vector(void)
+{
+	/*
+	 * Install writable page 0 entry to set BIOS data area.
+	 */
+	local_flush_tlb();
+
+	/*
+	 * Paranoid:  Set warm reset code and vector here back
+	 * to default values.
+	 */
+	CMOS_WRITE(0, 0xf);
+
+	*((volatile long *) phys_to_virt(0x467)) = 0;
+}
+
+static inline void smpboot_setup_io_apic(void)
+{
+	/*
+	 * Here we can be sure that there is an IO-APIC in the system. Let's
+	 * go and set it up:
+	 */
+	if (!skip_ioapic_setup && nr_ioapics)
+		setup_IO_APIC();
+}
diff -Nru a/arch/i386/mach-visws/Makefile b/arch/i386/mach-visws/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-visws/Makefile	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,25 @@
+#
+# Makefile for the linux kernel.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+.S.o:
+	$(CC) $(AFLAGS) -traditional -c $< -o $*.o
+
+all: mach-visws.o
+
+O_TARGET 	:= mach-visws.o
+EXTRA_CFLAGS	+= -I../kernel
+export-objs     := 
+
+obj-y				:= setup.o traps.o
+
+obj-$(CONFIG_PCI)		+= pci-visws.o
+obj-$(CONFIG_X86_VISWS_APIC)	+= visws_apic.o
+obj-$(CONFIG_X86_LOCAL_APIC)	+= mpparse.o
+
+include $(TOPDIR)/Rules.make
diff -Nru a/arch/i386/mach-visws/do_timer.h b/arch/i386/mach-visws/do_timer.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-visws/do_timer.h	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,50 @@
+/* defines for inline arch setup functions */
+
+#include <asm/fixmap.h>
+#include <asm/cobalt.h>
+
+static inline void do_timer_interrupt_hook(struct pt_regs *regs)
+{
+	/* Clear the interrupt */
+	co_cpu_write(CO_CPU_STAT,co_cpu_read(CO_CPU_STAT) & ~CO_STAT_TIMEINTR);
+
+	do_timer(regs);
+/*
+ * In the SMP case we use the local APIC timer interrupt to do the
+ * profiling, except when we simulate SMP mode on a uniprocessor
+ * system, in that case we have to call the local interrupt handler.
+ */
+#ifndef CONFIG_X86_LOCAL_APIC
+	if (!user_mode(regs))
+		x86_do_profile(regs->eip);
+#else
+	if (!using_apic_timer)
+		smp_local_timer_interrupt(regs);
+#endif
+}
+
+static inline int do_timer_overflow(int count)
+{
+	int i;
+
+	spin_lock(&i8259A_lock);
+	/*
+	 * This is tricky when I/O APICs are used;
+	 * see do_timer_interrupt().
+	 */
+	i = inb(0x20);
+	spin_unlock(&i8259A_lock);
+	
+	/* assumption about timer being IRQ0 */
+	if (i & 0x01) {
+		/*
+		 * We cannot detect lost timer interrupts ... 
+		 * well, that's why we call them lost, don't we? :)
+		 * [hmm, on the Pentium and Alpha we can ... sort of]
+		 */
+		count -= LATCH;
+	} else {
+		printk("do_slow_gettimeoffset(): hardware timer problem?\n");
+	}
+	return count;
+}
diff -Nru a/arch/i386/mach-visws/entry_arch.h b/arch/i386/mach-visws/entry_arch.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-visws/entry_arch.h	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,23 @@
+/*
+ * The following vectors are part of the Linux architecture, there
+ * is no hardware IRQ pin equivalent for them, they are triggered
+ * through the ICC by us (IPIs)
+ */
+#ifdef CONFIG_X86_SMP
+BUILD_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR)
+BUILD_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR)
+BUILD_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR)
+#endif
+
+/*
+ * every pentium local APIC has two 'local interrupts', with a
+ * soft-definable vector attached to both interrupts, one of
+ * which is a timer interrupt, the other one is error counter
+ * overflow. Linux uses the local APIC timer interrupt to get
+ * a much simpler SMP time architecture:
+ */
+#ifdef CONFIG_X86_LOCAL_APIC
+BUILD_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR)
+BUILD_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR)
+BUILD_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR)
+#endif
diff -Nru a/arch/i386/mach-visws/irq_vectors.h b/arch/i386/mach-visws/irq_vectors.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-visws/irq_vectors.h	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,64 @@
+#ifndef _ASM_IRQ_VECTORS_H
+#define _ASM_IRQ_VECTORS_H
+
+/*
+ * IDT vectors usable for external interrupt sources start
+ * at 0x20:
+ */
+#define FIRST_EXTERNAL_VECTOR	0x20
+
+#define SYSCALL_VECTOR		0x80
+
+/*
+ * Vectors 0x20-0x2f are used for ISA interrupts.
+ */
+
+/*
+ * Special IRQ vectors used by the SMP architecture, 0xf0-0xff
+ *
+ *  some of the following vectors are 'rare', they are merged
+ *  into a single vector (CALL_FUNCTION_VECTOR) to save vector space.
+ *  TLB, reschedule and local APIC vectors are performance-critical.
+ *
+ *  Vectors 0xf0-0xfa are free (reserved for future Linux use).
+ */
+#define SPURIOUS_APIC_VECTOR	0xff
+#define ERROR_APIC_VECTOR	0xfe
+#define INVALIDATE_TLB_VECTOR	0xfd
+#define RESCHEDULE_VECTOR	0xfc
+#define CALL_FUNCTION_VECTOR	0xfb
+
+#define THERMAL_APIC_VECTOR	0xf0
+/*
+ * Local APIC timer IRQ vector is on a different priority level,
+ * to work around the 'lost local interrupt if more than 2 IRQ
+ * sources per level' errata.
+ */
+#define LOCAL_TIMER_VECTOR	0xef
+
+/*
+ * First APIC vector available to drivers: (vectors 0x30-0xee)
+ * we start at 0x31 to spread out vectors evenly between priority
+ * levels. (0x80 is the syscall vector)
+ */
+#define FIRST_DEVICE_VECTOR	0x31
+#define FIRST_SYSTEM_VECTOR	0xef
+
+#define TIMER_IRQ 0
+
+/*
+ * 16 8259A IRQ's, 208 potential APIC interrupt sources.
+ * Right now the APIC is mostly only used for SMP.
+ * 256 vectors is an architectural limit. (we can have
+ * more than 256 devices theoretically, but they will
+ * have to use shared interrupts)
+ * Since vectors 0x00-0x1f are used/reserved for the CPU,
+ * the usable vector space is 0x20-0xff (224 vectors)
+ */
+#ifdef CONFIG_X86_IO_APIC
+#define NR_IRQS 224
+#else
+#define NR_IRQS 16
+#endif
+
+#endif /* _ASM_IRQ_VECTORS_H */
diff -Nru a/arch/i386/mach-visws/mpparse.c b/arch/i386/mach-visws/mpparse.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-visws/mpparse.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,67 @@
+#include <linux/mm.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/config.h>
+#include <linux/bootmem.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel_stat.h>
+#include <linux/mc146818rtc.h>
+
+#include <asm/smp.h>
+#include <asm/mtrr.h>
+#include <asm/mpspec.h>
+#include <asm/pgalloc.h>
+
+/* Have we found an MP table */
+int smp_found_config;
+
+/*
+ * Various Linux-internal data structures created from the
+ * MP-table.
+ */
+int apic_version [MAX_APICS];
+int mp_bus_id_to_type [MAX_MP_BUSSES];
+int mp_bus_id_to_node [MAX_MP_BUSSES];
+int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 };
+int mp_current_pci_id;
+
+/* I/O APIC entries */
+struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS];
+
+/* # of MP IRQ source entries */
+struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
+
+/* MP IRQ source entries */
+int mp_irq_entries;
+
+int nr_ioapics;
+
+int pic_mode;
+unsigned long mp_lapic_addr;
+
+/* Processor that is doing the boot up */
+unsigned int boot_cpu_physical_apicid = -1U;
+unsigned int boot_cpu_logical_apicid = -1U;
+/* Internal processor count */
+static unsigned int num_processors;
+
+/* Bitmask of physically existing CPUs */
+unsigned long phys_cpu_present_map;
+
+/*
+ * The Visual Workstation is Intel MP compliant in the hardware
+ * sense, but it doesn't have a BIOS(-configuration table).
+ * No problem for Linux.
+ */
+void __init find_smp_config(void)
+{
+	smp_found_config = 1;
+
+	phys_cpu_present_map |= 2; /* or in id 1 */
+	apic_version[1] |= 0x10; /* integrated APIC */
+	apic_version[0] |= 0x10;
+
+	mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
+}
+
diff -Nru a/arch/i386/mach-visws/pci-visws.c b/arch/i386/mach-visws/pci-visws.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-visws/pci-visws.c	Fri Sep 20 08:20:47 2002
@@ -0,0 +1,141 @@
+/*
+ *	Low-Level PCI Support for SGI Visual Workstation
+ *
+ *	(c) 1999--2000 Martin Mares <mj@ucw.cz>
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+
+#include <asm/smp.h>
+#include <asm/lithium.h>
+#include <asm/io.h>
+
+#include "pci-i386.h"
+
+unsigned int pci_probe = 0;
+
+/*
+ *  The VISWS uses configuration access type 1 only.
+ */
+
+#define CONFIG_CMD(dev, where)   (0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | (where & ~3))
+
+static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);
+	*value = inb(0xCFC + (where&3));
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);    
+	*value = inw(0xCFC + (where&2));
+	return PCIBIOS_SUCCESSFUL;    
+}
+
+static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);
+	*value = inl(0xCFC);
+	return PCIBIOS_SUCCESSFUL;    
+}
+
+static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);    
+	outb(value, 0xCFC + (where&3));
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);
+	outw(value, 0xCFC + (where&2));
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value)
+{
+	outl(CONFIG_CMD(dev,where), 0xCF8);
+	outl(value, 0xCFC);
+	return PCIBIOS_SUCCESSFUL;
+}
+
+#undef CONFIG_CMD
+
+static struct pci_ops visws_pci_ops = {
+	pci_conf1_read_config_byte,
+	pci_conf1_read_config_word,
+	pci_conf1_read_config_dword,
+	pci_conf1_write_config_byte,
+	pci_conf1_write_config_word,
+	pci_conf1_write_config_dword
+};
+
+static void __init pcibios_fixup_irqs(void)
+{
+	struct pci_dev *dev, *p;
+	u8 pin;
+	int irq;
+
+	pci_for_each_dev(dev) {
+		pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+		dev->irq = 0;
+		if (!pin)
+			continue;
+		pin--;
+		if (dev->bus->parent) {
+			p = dev->bus->parent->self;
+			pin = (pin + PCI_SLOT(dev->devfn)) % 4;
+		} else
+			p = dev;
+		irq = visws_get_PCI_irq_vector(p->bus->number, PCI_SLOT(p->devfn), pin+1);
+		if (irq >= 0)
+			dev->irq = irq;
+		DBG("PCI IRQ: %s pin %d -> %d\n", dev->slot_name, pin, irq);
+	}
+}
+
+void __init pcibios_fixup_bus(struct pci_bus *b)
+{
+	pci_read_bridge_bases(b);
+}
+
+#if 0
+static struct resource visws_pci_bus_resources[2] = {
+	{ "Host bus 1", 0xf4000000, 0xf7ffffff, 0 },
+	{ "Host bus 2", 0xf0000000, 0xf3ffffff, 0 }
+};
+#endif
+
+void __init pcibios_init(void)
+{
+	unsigned int sec_bus = li_pcib_read16(LI_PCI_BUSNUM) & 0xff;
+
+	printk("PCI: Probing PCI hardware on host buses 00 and %02x\n", sec_bus);
+	pci_scan_bus(0, &visws_pci_ops, NULL);
+	pci_scan_bus(sec_bus, &visws_pci_ops, NULL);
+	pcibios_fixup_irqs();
+	pcibios_resource_survey();
+}
+
+char * __init pcibios_setup(char *str)
+{
+	return str;
+}
+
+int pcibios_enable_device(struct pci_dev *dev, int mask)
+{
+	return pcibios_enable_resources(dev, mask);
+}
+
+void __init pcibios_penalize_isa_irq(irq)
+{
+}
diff -Nru a/arch/i386/mach-visws/setup.c b/arch/i386/mach-visws/setup.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-visws/setup.c	Fri Sep 20 08:20:43 2002
@@ -0,0 +1,170 @@
+/*
+ *  Unmaintained SGI Visual Workstation support.
+ *  Split out from setup.c by davej@suse.de
+ */
+
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+
+#include <asm/fixmap.h>
+#include <asm/cobalt.h>
+#include <asm/arch_hooks.h>
+#include <asm/io.h>
+
+char visws_board_type = -1;
+char visws_board_rev = -1;
+
+#define	PIIX_PM_START		0x0F80
+
+#define	SIO_GPIO_START		0x0FC0
+
+#define	SIO_PM_START		0x0FC8
+
+#define	PMBASE			PIIX_PM_START
+#define	GPIREG0			(PMBASE+0x30)
+#define	GPIREG(x)		(GPIREG0+((x)/8))
+#define	PIIX_GPI_BD_ID1		18
+#define	PIIX_GPI_BD_REG		GPIREG(PIIX_GPI_BD_ID1)
+
+#define	PIIX_GPI_BD_SHIFT	(PIIX_GPI_BD_ID1 % 8)
+
+#define	SIO_INDEX	0x2e
+#define	SIO_DATA	0x2f
+
+#define	SIO_DEV_SEL	0x7
+#define	SIO_DEV_ENB	0x30
+#define	SIO_DEV_MSB	0x60
+#define	SIO_DEV_LSB	0x61
+
+#define	SIO_GP_DEV	0x7
+
+#define	SIO_GP_BASE	SIO_GPIO_START
+#define	SIO_GP_MSB	(SIO_GP_BASE>>8)
+#define	SIO_GP_LSB	(SIO_GP_BASE&0xff)
+
+#define	SIO_GP_DATA1	(SIO_GP_BASE+0)
+
+#define	SIO_PM_DEV	0x8
+
+#define	SIO_PM_BASE	SIO_PM_START
+#define	SIO_PM_MSB	(SIO_PM_BASE>>8)
+#define	SIO_PM_LSB	(SIO_PM_BASE&0xff)
+#define	SIO_PM_INDEX	(SIO_PM_BASE+0)
+#define	SIO_PM_DATA	(SIO_PM_BASE+1)
+
+#define	SIO_PM_FER2	0x1
+
+#define	SIO_PM_GP_EN	0x80
+
+void __init visws_get_board_type_and_rev(void)
+{
+	int raw;
+
+	visws_board_type = (char)(inb_p(PIIX_GPI_BD_REG) & PIIX_GPI_BD_REG)
+							 >> PIIX_GPI_BD_SHIFT;
+/*
+ * Get Board rev.
+ * First, we have to initialize the 307 part to allow us access
+ * to the GPIO registers.  Let's map them at 0x0fc0 which is right
+ * after the PIIX4 PM section.
+ */
+	outb_p(SIO_DEV_SEL, SIO_INDEX);
+	outb_p(SIO_GP_DEV, SIO_DATA);	/* Talk to GPIO regs. */
+
+	outb_p(SIO_DEV_MSB, SIO_INDEX);
+	outb_p(SIO_GP_MSB, SIO_DATA);	/* MSB of GPIO base address */
+
+	outb_p(SIO_DEV_LSB, SIO_INDEX);
+	outb_p(SIO_GP_LSB, SIO_DATA);	/* LSB of GPIO base address */
+
+	outb_p(SIO_DEV_ENB, SIO_INDEX);
+	outb_p(1, SIO_DATA);		/* Enable GPIO registers. */
+
+/*
+ * Now, we have to map the power management section to write
+ * a bit which enables access to the GPIO registers.
+ * What lunatic came up with this shit?
+ */
+	outb_p(SIO_DEV_SEL, SIO_INDEX);
+	outb_p(SIO_PM_DEV, SIO_DATA);	/* Talk to GPIO regs. */
+
+	outb_p(SIO_DEV_MSB, SIO_INDEX);
+	outb_p(SIO_PM_MSB, SIO_DATA);	/* MSB of PM base address */
+
+	outb_p(SIO_DEV_LSB, SIO_INDEX);
+	outb_p(SIO_PM_LSB, SIO_DATA);	/* LSB of PM base address */
+
+	outb_p(SIO_DEV_ENB, SIO_INDEX);
+	outb_p(1, SIO_DATA);		/* Enable PM registers. */
+
+/*
+ * Now, write the PM register which enables the GPIO registers.
+ */
+	outb_p(SIO_PM_FER2, SIO_PM_INDEX);
+	outb_p(SIO_PM_GP_EN, SIO_PM_DATA);
+
+/*
+ * Now, initialize the GPIO registers.
+ * We want them all to be inputs which is the
+ * power on default, so let's leave them alone.
+ * So, let's just read the board rev!
+ */
+	raw = inb_p(SIO_GP_DATA1);
+	raw &= 0x7f;	/* 7 bits of valid board revision ID. */
+
+	if (visws_board_type == VISWS_320) {
+		if (raw < 0x6) {
+			visws_board_rev = 4;
+		} else if (raw < 0xc) {
+			visws_board_rev = 5;
+		} else {
+			visws_board_rev = 6;
+		}
+	} else if (visws_board_type == VISWS_540) {
+			visws_board_rev = 2;
+		} else {
+			visws_board_rev = raw;
+		}
+
+	printk(KERN_INFO "Silicon Graphics %s (rev %d)\n",
+	       visws_board_type == VISWS_320 ? "320" :
+	       (visws_board_type == VISWS_540 ? "540" :
+		"unknown"), visws_board_rev);
+}
+
+void __init pre_intr_init_hook(void)
+{
+	init_VISWS_APIC_irqs();
+}
+
+void __init intr_init_hook(void)
+{
+#ifdef CONFIG_X86_LOCAL_APIC
+	apic_intr_init();
+#endif
+}
+
+void __init pre_setup_arch_hook()
+{
+	visws_get_board_type_and_rev();
+}
+static struct irqaction irq0  = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL};
+
+void __init time_init_hook(void)
+{
+	printk("Starting Cobalt Timer system clock\n");
+
+	/* Set the countdown value */
+	co_cpu_write(CO_CPU_TIMEVAL, CO_TIME_HZ/HZ);
+
+	/* Start the timer */
+	co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) | CO_CTRL_TIMERUN);
+
+	/* Enable (unmask) the timer interrupt */
+	co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK);
+
+	/* Wire cpu IDT entry to s/w handler (and Cobalt APIC to IDT) */
+	setup_irq(CO_IRQ_TIMER, &irq0);
+}
diff -Nru a/arch/i386/mach-visws/setup_arch_post.h b/arch/i386/mach-visws/setup_arch_post.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-visws/setup_arch_post.h	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,37 @@
+/* Hook for machine specific memory setup.
+ *
+ * This is included late in kernel/setup.c so that it can make use of all of
+ * the static functions. */
+
+static inline char * __init machine_specific_memory_setup(void)
+{
+	char *who;
+
+
+	who = "BIOS-e820";
+
+	/*
+	 * Try to copy the BIOS-supplied E820-map.
+	 *
+	 * Otherwise fake a memory map; one section from 0k->640k,
+	 * the next section from 1mb->appropriate_mem_k
+	 */
+	sanitize_e820_map(E820_MAP, &E820_MAP_NR);
+	if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) {
+		unsigned long mem_size;
+
+		/* compare results from other methods and take the greater */
+		if (ALT_MEM_K < EXT_MEM_K) {
+			mem_size = EXT_MEM_K;
+			who = "BIOS-88";
+		} else {
+			mem_size = ALT_MEM_K;
+			who = "BIOS-e801";
+		}
+
+		e820.nr_map = 0;
+		add_memory_region(0, LOWMEMSIZE(), E820_RAM);
+		add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM);
+  	}
+	return who;
+}
diff -Nru a/arch/i386/mach-visws/setup_arch_pre.h b/arch/i386/mach-visws/setup_arch_pre.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-visws/setup_arch_pre.h	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,5 @@
+/* Hook to call BIOS initialisation function */
+
+/* no action for visws */
+
+#define ARCH_SETUP
diff -Nru a/arch/i386/mach-visws/smpboot_hooks.h b/arch/i386/mach-visws/smpboot_hooks.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-visws/smpboot_hooks.h	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,13 @@
+/* for visws do nothing for any of these */
+
+static inline void smpboot_clear_io_apic_irqs(void)
+{
+}
+
+static inline void smpboot_setup_warm_reset_vector(void)
+{
+}
+
+static inline void smpboot_setup_io_apic(void)
+{
+}
diff -Nru a/arch/i386/mach-visws/traps.c b/arch/i386/mach-visws/traps.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-visws/traps.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,134 @@
+/* VISWS traps */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/timer.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/highmem.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/debugreg.h>
+#include <asm/desc.h>
+#include <asm/i387.h>
+
+#include <asm/smp.h>
+#include <asm/pgalloc.h>
+#include <asm/arch_hooks.h>
+
+#ifdef CONFIG_X86_VISWS_APIC
+#include <asm/fixmap.h>
+#include <asm/cobalt.h>
+#include <asm/lithium.h>
+#endif
+
+#ifdef CONFIG_X86_VISWS_APIC
+
+/*
+ * On Rev 005 motherboards legacy device interrupt lines are wired directly
+ * to Lithium from the 307.  But the PROM leaves the interrupt type of each
+ * 307 logical device set appropriate for the 8259.  Later we'll actually use
+ * the 8259, but for now we have to flip the interrupt types to
+ * level triggered, active lo as required by Lithium.
+ */
+
+#define	REG	0x2e	/* The register to read/write */
+#define	DEV	0x07	/* Register: Logical device select */
+#define	VAL	0x2f	/* The value to read/write */
+
+static void
+superio_outb(int dev, int reg, int val)
+{
+	outb(DEV, REG);
+	outb(dev, VAL);
+	outb(reg, REG);
+	outb(val, VAL);
+}
+
+static int __attribute__ ((unused))
+superio_inb(int dev, int reg)
+{
+	outb(DEV, REG);
+	outb(dev, VAL);
+	outb(reg, REG);
+	return inb(VAL);
+}
+
+#define	FLOP	3	/* floppy logical device */
+#define	PPORT	4	/* parallel logical device */
+#define	UART5	5	/* uart2 logical device (not wired up) */
+#define	UART6	6	/* uart1 logical device (THIS is the serial port!) */
+#define	IDEST	0x70	/* int. destination (which 307 IRQ line) reg. */
+#define	ITYPE	0x71	/* interrupt type register */
+
+/* interrupt type bits */
+#define	LEVEL	0x01	/* bit 0, 0 == edge triggered */
+#define	ACTHI	0x02	/* bit 1, 0 == active lo */
+
+static __init void
+superio_init(void)
+{
+	if (visws_board_type == VISWS_320 && visws_board_rev == 5) {
+		superio_outb(UART6, IDEST, 0);	/* 0 means no intr propagated */
+		printk("SGI 320 rev 5: disabling 307 uart1 interrupt\n");
+	}
+}
+
+static __init void
+lithium_init(void)
+{
+	set_fixmap(FIX_LI_PCIA, LI_PCI_A_PHYS);
+	printk("Lithium PCI Bridge A, Bus Number: %d\n",
+				li_pcia_read16(LI_PCI_BUSNUM) & 0xff);
+	set_fixmap(FIX_LI_PCIB, LI_PCI_B_PHYS);
+	printk("Lithium PCI Bridge B (PIIX4), Bus Number: %d\n",
+				li_pcib_read16(LI_PCI_BUSNUM) & 0xff);
+
+	/* XXX blindly enables all interrupts */
+	li_pcia_write16(LI_PCI_INTEN, 0xffff);
+	li_pcib_write16(LI_PCI_INTEN, 0xffff);
+}
+
+static __init void
+cobalt_init(void)
+{
+	/*
+	 * On normal SMP PC this is used only with SMP, but we have to
+	 * use it and set it up here to start the Cobalt clock
+	 */
+	set_fixmap(FIX_APIC_BASE, APIC_DEFAULT_PHYS_BASE);
+	printk("Local APIC ID %lx\n", apic_read(APIC_ID));
+	printk("Local APIC Version %lx\n", apic_read(APIC_LVR));
+
+	set_fixmap(FIX_CO_CPU, CO_CPU_PHYS);
+	printk("Cobalt Revision %lx\n", co_cpu_read(CO_CPU_REV));
+
+	set_fixmap(FIX_CO_APIC, CO_APIC_PHYS);
+	printk("Cobalt APIC ID %lx\n", co_apic_read(CO_APIC_ID));
+
+	/* Enable Cobalt APIC being careful to NOT change the ID! */
+	co_apic_write(CO_APIC_ID, co_apic_read(CO_APIC_ID)|CO_APIC_ENABLE);
+
+	printk("Cobalt APIC enabled: ID reg %lx\n", co_apic_read(CO_APIC_ID));
+}
+#endif
+
+void __init trap_init_hook()
+{
+#ifdef CONFIG_X86_VISWS_APIC
+	superio_init();
+	lithium_init();
+	cobalt_init();
+#endif
+}
diff -Nru a/arch/i386/mach-visws/visws_apic.c b/arch/i386/mach-visws/visws_apic.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-visws/visws_apic.c	Fri Sep 20 08:20:41 2002
@@ -0,0 +1,410 @@
+/*
+ *	linux/arch/i386/kernel/visws_apic.c
+ *
+ *	Copyright (C) 1999 Bent Hagemark, Ingo Molnar
+ *
+ *  SGI Visual Workstation interrupt controller
+ *
+ *  The Cobalt system ASIC in the Visual Workstation contains a "Cobalt" APIC
+ *  which serves as the main interrupt controller in the system.  Non-legacy
+ *  hardware in the system uses this controller directly.  Legacy devices
+ *  are connected to the PIIX4 which in turn has its 8259(s) connected to
+ *  a of the Cobalt APIC entry.
+ */
+
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/timex.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/bitops.h>
+#include <asm/smp.h>
+#include <asm/pgtable.h>
+#include <asm/delay.h>
+#include <asm/desc.h>
+
+#include <asm/cobalt.h>
+
+#include <linux/irq.h>
+
+/*
+ * This is the PIIX4-based 8259 that is wired up indirectly to Cobalt
+ * -- not the manner expected by the normal 8259 code in irq.c.
+ *
+ * there is a 'master' physical interrupt source that gets sent to
+ * the CPU. But in the chipset there are various 'virtual' interrupts
+ * waiting to be handled. We represent this to Linux through a 'master'
+ * interrupt controller type, and through a special virtual interrupt-
+ * controller. Device drivers only see the virtual interrupt sources.
+ */
+
+#define	CO_IRQ_BASE	0x20	/* This is the 0x20 in init_IRQ()! */
+
+static void startup_piix4_master_irq(unsigned int irq);
+static void shutdown_piix4_master_irq(unsigned int irq);
+static void do_piix4_master_IRQ(unsigned int irq, struct pt_regs * regs);
+#define enable_piix4_master_irq startup_piix4_master_irq
+#define disable_piix4_master_irq shutdown_piix4_master_irq
+
+static struct hw_interrupt_type piix4_master_irq_type = {
+	"PIIX4-master",
+	startup_piix4_master_irq,
+	shutdown_piix4_master_irq,
+	do_piix4_master_IRQ,
+	enable_piix4_master_irq,
+	disable_piix4_master_irq
+};
+
+static void enable_piix4_virtual_irq(unsigned int irq);
+static void disable_piix4_virtual_irq(unsigned int irq);
+#define startup_piix4_virtual_irq enable_piix4_virtual_irq
+#define shutdown_piix4_virtual_irq disable_piix4_virtual_irq
+
+static struct hw_interrupt_type piix4_virtual_irq_type = {
+	"PIIX4-virtual",
+	startup_piix4_virtual_irq,
+	shutdown_piix4_virtual_irq,
+	0, /* no handler, it's never called physically */
+	enable_piix4_virtual_irq,
+	disable_piix4_virtual_irq
+};
+
+/*
+ * This is the SGI Cobalt (IO-)APIC:
+ */
+
+static void do_cobalt_IRQ(unsigned int irq, struct pt_regs * regs);
+static void enable_cobalt_irq(unsigned int irq);
+static void disable_cobalt_irq(unsigned int irq);
+static void startup_cobalt_irq(unsigned int irq);
+#define shutdown_cobalt_irq disable_cobalt_irq
+
+static spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED;
+
+static struct hw_interrupt_type cobalt_irq_type = {
+	"Cobalt-APIC",
+	startup_cobalt_irq,
+	shutdown_cobalt_irq,
+	do_cobalt_IRQ,
+	enable_cobalt_irq,
+	disable_cobalt_irq
+};
+
+
+/*
+ * Not an __init, needed by the reboot code
+ */
+void disable_IO_APIC(void)
+{
+	/* Nop on Cobalt */
+} 
+
+/*
+ * Cobalt (IO)-APIC functions to handle PCI devices.
+ */
+
+static void disable_cobalt_irq(unsigned int irq)
+{
+	/* XXX undo the APIC entry here? */
+
+	/*
+	 * definitely, we do not want to have IRQ storms from
+	 * unused devices --mingo
+	 */
+}
+
+static void enable_cobalt_irq(unsigned int irq)
+{
+}
+
+/*
+ * Set the given Cobalt APIC Redirection Table entry to point
+ * to the given IDT vector/index.
+ */
+static void co_apic_set(int entry, int idtvec)
+{
+	co_apic_write(CO_APIC_LO(entry), CO_APIC_LEVEL | (CO_IRQ_BASE+idtvec));
+	co_apic_write(CO_APIC_HI(entry), 0);
+
+	printk("Cobalt APIC Entry %d IDT Vector %d\n", entry, idtvec);
+}
+
+/*
+ * "irq" really just serves to identify the device.  Here is where we
+ * map this to the Cobalt APIC entry where it's physically wired.
+ * This is called via request_irq -> setup_x86_irq -> irq_desc->startup()
+ */
+static void startup_cobalt_irq(unsigned int irq)
+{
+	/*
+	 * These "irq"'s are wired to the same Cobalt APIC entries
+	 * for all (known) motherboard types/revs
+	 */
+	switch (irq) {
+	case CO_IRQ_TIMER:	co_apic_set(CO_APIC_CPU, CO_IRQ_TIMER);
+				return;
+
+	case CO_IRQ_ENET:	co_apic_set(CO_APIC_ENET, CO_IRQ_ENET);
+				return;
+
+	case CO_IRQ_SERIAL:	return; /* XXX move to piix4-8259 "virtual" */
+
+	case CO_IRQ_8259:	co_apic_set(CO_APIC_8259, CO_IRQ_8259);
+				return;
+
+	case CO_IRQ_IDE:
+		switch (visws_board_type) {
+		case VISWS_320:
+			switch (visws_board_rev) {
+			case 5:
+				co_apic_set(CO_APIC_0_5_IDE0, CO_IRQ_IDE);
+				co_apic_set(CO_APIC_0_5_IDE1, CO_IRQ_IDE);
+					return;
+			case 6:
+				co_apic_set(CO_APIC_0_6_IDE0, CO_IRQ_IDE);
+				co_apic_set(CO_APIC_0_6_IDE1, CO_IRQ_IDE);
+					return;
+			}
+		case VISWS_540:
+			switch (visws_board_rev) {
+			case 2:
+				co_apic_set(CO_APIC_1_2_IDE0, CO_IRQ_IDE);
+					return;
+			}
+		}
+		break;
+	default:
+		panic("huh?");
+	}
+}
+
+/*
+ * This is the handle() op in do_IRQ()
+ */
+static void do_cobalt_IRQ(unsigned int irq, struct pt_regs * regs)
+{
+	struct irqaction * action;
+	irq_desc_t *desc = irq_desc + irq;
+
+	spin_lock(&irq_controller_lock);
+	{
+		unsigned int status;
+		/* XXX APIC EOI? */
+		status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
+		action = NULL;
+		if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
+			action = desc->action;
+			status |= IRQ_INPROGRESS;
+		}
+		desc->status = status;
+	}
+	spin_unlock(&irq_controller_lock);
+
+	/* Exit early if we had no action or it was disabled */
+	if (!action)
+		return;
+
+	handle_IRQ_event(irq, regs, action);
+
+	(void)co_cpu_read(CO_CPU_REV); /* Sync driver ack to its h/w */
+	apic_write(APIC_EOI, APIC_EIO_ACK); /* Send EOI to Cobalt APIC */
+
+	spin_lock(&irq_controller_lock);
+	{
+		unsigned int status = desc->status & ~IRQ_INPROGRESS;
+		desc->status = status;
+		if (!(status & IRQ_DISABLED))
+			enable_cobalt_irq(irq);
+	}
+	spin_unlock(&irq_controller_lock);
+}
+
+/*
+ * PIIX4-8259 master/virtual functions to handle:
+ *
+ *	floppy
+ *	parallel
+ *	serial
+ *	audio (?)
+ *
+ * None of these get Cobalt APIC entries, neither do they have IDT
+ * entries. These interrupts are purely virtual and distributed from
+ * the 'master' interrupt source: CO_IRQ_8259.
+ *
+ * When the 8259 interrupts its handler figures out which of these
+ * devices is interrupting and dispatches to it's handler.
+ *
+ * CAREFUL: devices see the 'virtual' interrupt only. Thus disable/
+ * enable_irq gets the right irq. This 'master' irq is never directly
+ * manipulated by any driver.
+ */
+
+static void startup_piix4_master_irq(unsigned int irq)
+{
+	/* ICW1 */
+	outb(0x11, 0x20);
+	outb(0x11, 0xa0);
+
+	/* ICW2 */
+	outb(0x08, 0x21);
+	outb(0x70, 0xa1);
+
+	/* ICW3 */
+	outb(0x04, 0x21);
+	outb(0x02, 0xa1);
+
+	/* ICW4 */
+	outb(0x01, 0x21);
+	outb(0x01, 0xa1);
+
+	/* OCW1 - disable all interrupts in both 8259's */
+	outb(0xff, 0x21);
+	outb(0xff, 0xa1);
+
+	startup_cobalt_irq(irq);
+}
+
+static void shutdown_piix4_master_irq(unsigned int irq)
+{
+	/*
+	 * [we skip the 8259 magic here, not strictly necessary]
+	 */
+
+	shutdown_cobalt_irq(irq);
+}
+
+static void do_piix4_master_IRQ(unsigned int irq, struct pt_regs * regs)
+{
+	int realirq, mask;
+
+	/* Find out what's interrupting in the PIIX4 8259 */
+
+	spin_lock(&irq_controller_lock);
+	outb(0x0c, 0x20);		/* OCW3 Poll command */
+	realirq = inb(0x20);
+
+	if (!(realirq & 0x80)) {
+		/*
+		 * Bit 7 == 0 means invalid/spurious
+		 */
+		goto out_unlock;
+	}
+	realirq &= 0x7f;
+
+	/*
+	 * mask and ack the 8259
+	 */
+	mask = inb(0x21);
+	if ((mask >> realirq) & 0x01)
+		/*
+		 * This IRQ is masked... ignore
+		 */
+		goto out_unlock;
+
+	outb(mask | (1<<realirq), 0x21);
+	/*
+	 * OCW2 - non-specific EOI
+	 */
+	outb(0x20, 0x20);
+
+	spin_unlock(&irq_controller_lock);
+
+	/*
+	 * handle this 'virtual interrupt' as a Cobalt one now.
+	 */
+	kstat.irqs[smp_processor_id()][irq]++;
+	do_cobalt_IRQ(realirq, regs);
+
+	spin_lock(&irq_controller_lock);
+	{
+		irq_desc_t *desc = irq_desc + realirq;
+
+		if (!(desc->status & IRQ_DISABLED))
+			enable_piix4_virtual_irq(realirq);
+	}
+	spin_unlock(&irq_controller_lock);
+	return;
+
+out_unlock:
+	spin_unlock(&irq_controller_lock);
+	return;
+}
+
+static void enable_piix4_virtual_irq(unsigned int irq)
+{
+	/*
+	 * assumes this irq is one of the legacy devices
+	 */
+
+	unsigned int mask = inb(0x21);
+ 	mask &= ~(1 << irq);
+	outb(mask, 0x21);
+	enable_cobalt_irq(irq);
+}
+
+/*
+ * assumes this irq is one of the legacy devices
+ */
+static void disable_piix4_virtual_irq(unsigned int irq)
+{
+	unsigned int mask;
+
+	disable_cobalt_irq(irq);
+
+	mask = inb(0x21);
+ 	mask &= ~(1 << irq);
+	outb(mask, 0x21);
+}
+
+static struct irqaction master_action =
+		{ no_action, 0, 0, "PIIX4-8259", NULL, NULL };
+
+void init_VISWS_APIC_irqs(void)
+{
+	int i;
+
+	for (i = 0; i < 16; i++) {
+		irq_desc[i].status = IRQ_DISABLED;
+		irq_desc[i].action = 0;
+		irq_desc[i].depth = 1;
+
+		/*
+		 * Cobalt IRQs are mapped to standard ISA
+		 * interrupt vectors:
+		 */
+		switch (i) {
+			/*
+			 * Only CO_IRQ_8259 will be raised
+			 * externally.
+			 */
+		case CO_IRQ_8259:
+			irq_desc[i].handler = &piix4_master_irq_type;
+			break;
+		case CO_IRQ_FLOPPY:
+		case CO_IRQ_PARLL:
+			irq_desc[i].handler = &piix4_virtual_irq_type;
+			break;
+		default:
+			irq_desc[i].handler = &cobalt_irq_type;
+			break;
+		}
+	}
+
+	/*
+	 * The master interrupt is always present:
+	 */
+	setup_x86_irq(CO_IRQ_8259, &master_action);
+}
+
diff -Nru a/arch/i386/math-emu/Makefile b/arch/i386/math-emu/Makefile
--- a/arch/i386/math-emu/Makefile	Fri Sep 20 08:20:41 2002
+++ b/arch/i386/math-emu/Makefile	Fri Sep 20 08:20:41 2002
@@ -2,8 +2,6 @@
 #               Makefile for wm-FPU-emu
 #
 
-O_TARGET := math.o
-
 #DEBUG	= -DDEBUGGING
 DEBUG	=
 PARANOID = -DPARANOID
diff -Nru a/arch/i386/mm/Makefile b/arch/i386/mm/Makefile
--- a/arch/i386/mm/Makefile	Fri Sep 20 08:20:43 2002
+++ b/arch/i386/mm/Makefile	Fri Sep 20 08:20:43 2002
@@ -1,17 +1,11 @@
 #
 # Makefile for the linux i386-specific parts of the memory manager.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definition is now in the main makefile...
 
-O_TARGET := mm.o
+export-objs := pageattr.o
 
-obj-y	 := init.o pgtable.o fault.o ioremap.o extable.o pageattr.o 
+obj-y	:= init.o pgtable.o fault.o ioremap.o extable.o pageattr.o 
 obj-$(CONFIG_DISCONTIGMEM)	+= discontig.o
-export-objs := pageattr.o
 obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/i386/mm/discontig.c b/arch/i386/mm/discontig.c
--- a/arch/i386/mm/discontig.c	Fri Sep 20 08:20:46 2002
+++ b/arch/i386/mm/discontig.c	Fri Sep 20 08:20:46 2002
@@ -275,20 +275,9 @@
 void __init set_max_mapnr_init(void)
 {
 #ifdef CONFIG_HIGHMEM
-	unsigned long lmax_mapnr;
-	int nid;
-	
-	highmem_start_page = mem_map + NODE_DATA(0)->node_zones[ZONE_HIGHMEM].zone_start_mapnr;
+	highmem_start_page = NODE_DATA(0)->node_zones[ZONE_HIGHMEM].zone_mem_map;
 	num_physpages = highend_pfn;
-
-	for (nid = 0; nid < numnodes; nid++) {
-		lmax_mapnr = node_startnr(nid) + node_size(nid);
-		if (lmax_mapnr > max_mapnr) {
-			max_mapnr = lmax_mapnr;
-		}
-	}
-	
 #else
-	max_mapnr = num_physpages = max_low_pfn;
+	num_physpages = max_low_pfn;
 #endif
 }
diff -Nru a/arch/i386/mm/hugetlbpage.c b/arch/i386/mm/hugetlbpage.c
--- a/arch/i386/mm/hugetlbpage.c	Fri Sep 20 08:20:47 2002
+++ b/arch/i386/mm/hugetlbpage.c	Fri Sep 20 08:20:47 2002
@@ -319,7 +319,7 @@
 	}
 	if (i == MAX_ID)
 		return NULL;
-	inode = kmalloc(sizeof (struct inode), GFP_KERNEL);
+	inode = kmalloc(sizeof (struct inode), GFP_ATOMIC);
 	if (inode == NULL)
 		return NULL;
 
@@ -502,7 +502,7 @@
 
 	if (lcount > 0) {	/* Increase the mem size. */
 		while (lcount--) {
-			page = alloc_pages(GFP_ATOMIC, HUGETLB_PAGE_ORDER);
+			page = alloc_pages(__GFP_HIGHMEM, HUGETLB_PAGE_ORDER);
 			if (page == NULL)
 				break;
 			map = page;
diff -Nru a/arch/i386/mm/init.c b/arch/i386/mm/init.c
--- a/arch/i386/mm/init.c	Fri Sep 20 08:20:43 2002
+++ b/arch/i386/mm/init.c	Fri Sep 20 08:20:43 2002
@@ -440,8 +440,10 @@
 	int tmp;
 	int bad_ppro;
 
+#ifndef CONFIG_DISCONTIGMEM
 	if (!mem_map)
 		BUG();
+#endif
 	
 	bad_ppro = ppro_with_ram_bug();
 
@@ -471,7 +473,7 @@
 
 	printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n",
 		(unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
-		max_mapnr << (PAGE_SHIFT-10),
+		num_physpages << (PAGE_SHIFT-10),
 		codesize >> 10,
 		reservedpages << (PAGE_SHIFT-10),
 		datasize >> 10,
@@ -504,7 +506,7 @@
 		/*Will make this kernel command line. */
 		INIT_LIST_HEAD(&htlbpage_freelist);
 		for (i=0; i<htlbzone_pages; i++) {
-			page = alloc_pages(GFP_ATOMIC, HUGETLB_PAGE_ORDER);
+			page = alloc_pages(__GFP_HIGHMEM, HUGETLB_PAGE_ORDER);
 			if (page == NULL)
 				break;
 			map = page;
diff -Nru a/arch/i386/mm/pgtable.c b/arch/i386/mm/pgtable.c
--- a/arch/i386/mm/pgtable.c	Fri Sep 20 08:20:49 2002
+++ b/arch/i386/mm/pgtable.c	Fri Sep 20 08:20:49 2002
@@ -22,26 +22,29 @@
 
 void show_mem(void)
 {
-	int pfn, total = 0, reserved = 0;
+	int total = 0, reserved = 0;
 	int shared = 0, cached = 0;
 	int highmem = 0;
 	struct page *page;
+	pg_data_t *pgdat;
+	unsigned long i;
 
 	printk("Mem-info:\n");
 	show_free_areas();
 	printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
-	pfn = max_mapnr;
-	while (pfn-- > 0) {
-		page = pfn_to_page(pfn);
-		total++;
-		if (PageHighMem(page))
-			highmem++;
-		if (PageReserved(page))
-			reserved++;
-		else if (PageSwapCache(page))
-			cached++;
-		else if (page_count(page))
-			shared += page_count(page) - 1;
+	for_each_pgdat(pgdat) {
+		for (i = 0; i < pgdat->node_size; ++i) {
+			page = pgdat->node_mem_map + i;
+			total++;
+			if (PageHighMem(page))
+				highmem++;
+			if (PageReserved(page))
+				reserved++;
+			else if (PageSwapCache(page))
+				cached++;
+			else if (page_count(page))
+				shared += page_count(page) - 1;
+		}
 	}
 	printk("%d pages of RAM\n", total);
 	printk("%d pages of HIGHMEM\n",highmem);
diff -Nru a/arch/i386/pci/Makefile b/arch/i386/pci/Makefile
--- a/arch/i386/pci/Makefile	Fri Sep 20 08:20:46 2002
+++ b/arch/i386/pci/Makefile	Fri Sep 20 08:20:46 2002
@@ -1,11 +1,5 @@
-O_TARGET        := pci.o
-
 obj-y		:= i386.o
 
-ifdef	CONFIG_VISWS
-obj-y		+= visws.o
-else
-
 obj-$(CONFIG_PCI_BIOS)		+= pcbios.o
 obj-$(CONFIG_PCI_DIRECT)	+= direct.o
 
@@ -22,6 +16,5 @@
 
 endif		# CONFIG_MULTIQUAD
 obj-y		+= irq.o common.o
-endif		# CONFIG_VISWS
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/i386/pci/acpi.c b/arch/i386/pci/acpi.c
--- a/arch/i386/pci/acpi.c	Fri Sep 20 08:20:47 2002
+++ b/arch/i386/pci/acpi.c	Fri Sep 20 08:20:47 2002
@@ -11,7 +11,7 @@
 	if (!(pci_probe & PCI_NO_ACPI_ROUTING)) {
 		if (!acpi_pci_irq_init()) {
 			printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
-			printk(KERN_INFO "PCI: if you experience problems, try using option 'pci=noacpi'\n");
+			printk(KERN_INFO "PCI: if you experience problems, try using option 'pci=noacpi' or even 'acpi=off'\n");
 			pcibios_scanned++;
 			pcibios_enable_irq = acpi_pci_irq_enable;
 		} else
diff -Nru a/arch/i386/pci/visws.c b/arch/i386/pci/visws.c
--- a/arch/i386/pci/visws.c	Fri Sep 20 08:20:47 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,141 +0,0 @@
-/*
- *	Low-Level PCI Support for SGI Visual Workstation
- *
- *	(c) 1999--2000 Martin Mares <mj@ucw.cz>
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/irq.h>
-
-#include <asm/smp.h>
-#include <asm/lithium.h>
-#include <asm/io.h>
-
-#include "pci-i386.h"
-
-unsigned int pci_probe = 0;
-
-/*
- *  The VISWS uses configuration access type 1 only.
- */
-
-#define CONFIG_CMD(dev, where)   (0x80000000 | (dev->bus->number << 16) | (dev->devfn << 8) | (where & ~3))
-
-static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value)
-{
-	outl(CONFIG_CMD(dev,where), 0xCF8);
-	*value = inb(0xCFC + (where&3));
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value)
-{
-	outl(CONFIG_CMD(dev,where), 0xCF8);    
-	*value = inw(0xCFC + (where&2));
-	return PCIBIOS_SUCCESSFUL;    
-}
-
-static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value)
-{
-	outl(CONFIG_CMD(dev,where), 0xCF8);
-	*value = inl(0xCFC);
-	return PCIBIOS_SUCCESSFUL;    
-}
-
-static int pci_conf1_write_config_byte(struct pci_dev *dev, int where, u8 value)
-{
-	outl(CONFIG_CMD(dev,where), 0xCF8);    
-	outb(value, 0xCFC + (where&3));
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int pci_conf1_write_config_word(struct pci_dev *dev, int where, u16 value)
-{
-	outl(CONFIG_CMD(dev,where), 0xCF8);
-	outw(value, 0xCFC + (where&2));
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int pci_conf1_write_config_dword(struct pci_dev *dev, int where, u32 value)
-{
-	outl(CONFIG_CMD(dev,where), 0xCF8);
-	outl(value, 0xCFC);
-	return PCIBIOS_SUCCESSFUL;
-}
-
-#undef CONFIG_CMD
-
-static struct pci_ops visws_pci_ops = {
-	pci_conf1_read_config_byte,
-	pci_conf1_read_config_word,
-	pci_conf1_read_config_dword,
-	pci_conf1_write_config_byte,
-	pci_conf1_write_config_word,
-	pci_conf1_write_config_dword
-};
-
-static void __init pcibios_fixup_irqs(void)
-{
-	struct pci_dev *dev, *p;
-	u8 pin;
-	int irq;
-
-	pci_for_each_dev(dev) {
-		pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
-		dev->irq = 0;
-		if (!pin)
-			continue;
-		pin--;
-		if (dev->bus->parent) {
-			p = dev->bus->parent->self;
-			pin = (pin + PCI_SLOT(dev->devfn)) % 4;
-		} else
-			p = dev;
-		irq = visws_get_PCI_irq_vector(p->bus->number, PCI_SLOT(p->devfn), pin+1);
-		if (irq >= 0)
-			dev->irq = irq;
-		DBG("PCI IRQ: %s pin %d -> %d\n", dev->slot_name, pin, irq);
-	}
-}
-
-void __init pcibios_fixup_bus(struct pci_bus *b)
-{
-	pci_read_bridge_bases(b);
-}
-
-#if 0
-static struct resource visws_pci_bus_resources[2] = {
-	{ "Host bus 1", 0xf4000000, 0xf7ffffff, 0 },
-	{ "Host bus 2", 0xf0000000, 0xf3ffffff, 0 }
-};
-#endif
-
-void __init pcibios_init(void)
-{
-	unsigned int sec_bus = li_pcib_read16(LI_PCI_BUSNUM) & 0xff;
-
-	printk("PCI: Probing PCI hardware on host buses 00 and %02x\n", sec_bus);
-	pci_scan_bus(0, &visws_pci_ops, NULL);
-	pci_scan_bus(sec_bus, &visws_pci_ops, NULL);
-	pcibios_fixup_irqs();
-	pcibios_resource_survey();
-}
-
-char * __init pcibios_setup(char *str)
-{
-	return str;
-}
-
-int pcibios_enable_device(struct pci_dev *dev, int mask)
-{
-	return pcibios_enable_resources(dev, mask);
-}
-
-void __init pcibios_penalize_isa_irq(irq)
-{
-}
diff -Nru a/arch/m68k/vmlinux.lds.S b/arch/m68k/vmlinux.lds.S
--- a/arch/m68k/vmlinux.lds.S	Fri Sep 20 08:20:44 2002
+++ b/arch/m68k/vmlinux.lds.S	Fri Sep 20 08:20:44 2002
@@ -4,4 +4,4 @@
 #include "vmlinux-sun3.lds"
 #else
 #include "vmlinux-std.lds"
-#endif
\ No newline at end of file
+#endif
diff -Nru a/arch/mips/Makefile b/arch/mips/Makefile
--- a/arch/mips/Makefile	Fri Sep 20 08:20:41 2002
+++ b/arch/mips/Makefile	Fri Sep 20 08:20:41 2002
@@ -112,7 +112,7 @@
 ifdef CONFIG_DECSTATION
 CORE_FILES    += arch/mips/dec/dec.o
 SUBDIRS       += arch/mips/dec arch/mips/dec/prom
-LIBS          += arch/mips/dec/prom/rexlib.a
+LIBS          += arch/mips/dec/prom/lib.a
 LOADADDR      += 0x80040000
 endif
 
@@ -134,20 +134,20 @@
 ifdef CONFIG_MIPS_JAZZ
 CORE_FILES    += arch/mips/jazz/jazz.o
 SUBDIRS       += arch/mips/jazz arch/mips/arc
-LIBS          += arch/mips/arc/arclib.a
+LIBS          += arch/mips/arc/lib.a
 LOADADDR      += 0x80080000
 endif
 
 ifdef CONFIG_SNI_RM200_PCI
 CORE_FILES    += arch/mips/sni/sni.o
 SUBDIRS       += arch/mips/sni arch/mips/arc
-LIBS          += arch/mips/arc/arclib.a
+LIBS          += arch/mips/arc/lib.a
 LOADADDR      += 0x80080000
 endif
 
 ifdef CONFIG_SGI_IP22
 CORE_FILES    += arch/mips/sgi/kernel/ip22-kern.o
-LIBS          += arch/mips/arc/arclib.a
+LIBS          += arch/mips/arc/lib.a
 SUBDIRS       += arch/mips/sgi/kernel arch/mips/arc
 #
 # Set LOADADDR to >= 0x88069000 if you want to leave space for symmon,
@@ -162,7 +162,7 @@
 #
 ifdef CONFIG_BAGET_MIPS
 SUBDIRS       += arch/mips/baget arch/mips/baget/prom
-LIBS          += arch/mips/baget/baget.a arch/mips/baget/prom/bagetlib.a
+LIBS          += arch/mips/baget/baget.a arch/mips/baget/prom/lib.a
 LOADADDR      += 0x80001000
 endif
 
diff -Nru a/arch/mips/arc/Makefile b/arch/mips/arc/Makefile
--- a/arch/mips/arc/Makefile	Fri Sep 20 08:20:44 2002
+++ b/arch/mips/arc/Makefile	Fri Sep 20 08:20:44 2002
@@ -2,13 +2,8 @@
 # Makefile for the SGI arcs prom monitor library routines
 # under Linux.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
 
-L_TARGET = arclib.a
+L_TARGET = lib.a
 
 obj-y		+= console.o init.o memory.o tree.o env.o cmdline.o misc.o \
 		   time.o file.o identify.o
diff -Nru a/arch/mips/baget/prom/Makefile b/arch/mips/baget/prom/Makefile
--- a/arch/mips/baget/prom/Makefile	Fri Sep 20 08:20:47 2002
+++ b/arch/mips/baget/prom/Makefile	Fri Sep 20 08:20:47 2002
@@ -1,13 +1,8 @@
 #
 # Makefile for the Baget/MIPS prom emulator library routines.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
 
-L_TARGET := bagetlib.a
+L_TARGET := lib.a
 
 obj-y	:= init.o
 
diff -Nru a/arch/mips/dec/prom/Makefile b/arch/mips/dec/prom/Makefile
--- a/arch/mips/dec/prom/Makefile	Fri Sep 20 08:20:44 2002
+++ b/arch/mips/dec/prom/Makefile	Fri Sep 20 08:20:44 2002
@@ -3,7 +3,7 @@
 # under Linux.
 #
 
-L_TARGET := rexlib.a
+L_TARGET := lib.a
 
 obj-y := init.o memory.o cmdline.o identify.o locore.o
 
diff -Nru a/arch/mips64/Makefile b/arch/mips64/Makefile
--- a/arch/mips64/Makefile	Fri Sep 20 08:20:43 2002
+++ b/arch/mips64/Makefile	Fri Sep 20 08:20:43 2002
@@ -72,7 +72,7 @@
 # Board-dependent options and extra files
 #
 ifdef CONFIG_SGI_IP22
-LIBS          += arch/mips64/sgi-ip22/ip22.a arch/mips64/arc/arclib.a
+LIBS          += arch/mips64/sgi-ip22/lib.a arch/mips64/arc/lib.a
 SUBDIRS       += arch/mips64/sgi-ip22 arch/mips64/arc
 #
 # Set LOADADDR to >= 0x88069000 if you want to leave space for symmon,
@@ -84,7 +84,7 @@
 
 ifdef CONFIG_SGI_IP27
 CORE_FILES    += arch/mips64/sgi-ip27/ip27.o
-LIBS          += arch/mips64/arc/arclib.a
+LIBS          += arch/mips64/arc/lib.a
 SUBDIRS       += arch/mips64/sgi-ip27 arch/mips64/arc
 #
 # Set LOADADDR to >= 0xc000000000300000 if you want to leave space for
@@ -100,7 +100,7 @@
 endif
 
 ifdef CONFIG_SGI_IP32
-LIBS		+= arch/mips64/sgi-ip32/ip32-kern.a arch/mips64/arc/arclib.a
+LIBS		+= arch/mips64/sgi-ip32/ip32-kern.a arch/mips64/arc/lib.a
 SUBDIRS		+= arch/mips64/sgi-ip32 arch/mips64/arc
 #
 # Set LOADADDR to >= 0x????????? if you want to leave space for symmon,
diff -Nru a/arch/mips64/arc/Makefile b/arch/mips64/arc/Makefile
--- a/arch/mips64/arc/Makefile	Fri Sep 20 08:20:48 2002
+++ b/arch/mips64/arc/Makefile	Fri Sep 20 08:20:48 2002
@@ -2,7 +2,7 @@
 # Makefile for the ARC prom monitor library routines under Linux.
 #
 
-L_TARGET = arclib.a
+L_TARGET = lib.a
 obj-y	:= console.o init.o identify.o tree.o env.o cmdline.o misc.o time.o \
 	   file.o
 
diff -Nru a/arch/mips64/sgi-ip22/Makefile b/arch/mips64/sgi-ip22/Makefile
--- a/arch/mips64/sgi-ip22/Makefile	Fri Sep 20 08:20:41 2002
+++ b/arch/mips64/sgi-ip22/Makefile	Fri Sep 20 08:20:41 2002
@@ -5,7 +5,7 @@
 
 EXTRA_AFLAGS := $(CFLAGS)
 
-L_TARGET = ip22.a
+L_TARGET = lib.a
 
 obj-y	+= ip22-berr.o ip22-mc.o ip22-sc.o ip22-hpc.o ip22-int.o ip22-rtc.o \
 	   ip22-setup.o system.o ip22-timer.o ip22-irq.o ip22-reset.o time.o
diff -Nru a/arch/mips64/sgi-ip27/ip27-memory.c b/arch/mips64/sgi-ip27/ip27-memory.c
--- a/arch/mips64/sgi-ip27/ip27-memory.c	Fri Sep 20 08:20:44 2002
+++ b/arch/mips64/sgi-ip27/ip27-memory.c	Fri Sep 20 08:20:44 2002
@@ -254,10 +254,6 @@
 		zones_size[ZONE_DMA] = end_pfn + 1 - start_pfn;
 		free_area_init_node(node, NODE_DATA(node), 0, zones_size, 
 						start_pfn, 0);
-		if ((PLAT_NODE_DATA_STARTNR(node) + 
-					PLAT_NODE_DATA_SIZE(node)) > pagenr)
-			pagenr = PLAT_NODE_DATA_STARTNR(node) +
-					PLAT_NODE_DATA_SIZE(node);
 	}
 }
 
@@ -271,7 +267,6 @@
 	unsigned long codesize, datasize, initsize;
 	int slot, numslots;
 	struct page *pg, *pslot;
-	pfn_t pgnr;
 
 	num_physpages = numpages;	/* memory already sized by szmem */
 	max_mapnr = pagenr;		/* already found during paging_init */
@@ -293,7 +288,6 @@
 		 * We need to manually do the other slots.
 		 */
 		pg = NODE_DATA(nid)->node_mem_map + slot_getsize(nid, 0);
-		pgnr = PLAT_NODE_DATA_STARTNR(nid) + slot_getsize(nid, 0);
 		numslots = node_getlastslot(nid);
 		for (slot = 1; slot <= numslots; slot++) {
 			pslot = NODE_DATA(nid)->node_mem_map + 
@@ -304,7 +298,7 @@
 			 * free up the pages that hold the memmap entries.
 			 */
 			while (pg < pslot) {
-				pg++; pgnr++;
+				pg++;
 			}
 
 			/*
@@ -312,8 +306,8 @@
 			 */
 			pslot += slot_getsize(nid, slot);
 			while (pg < pslot) {
-				if (!page_is_ram(pgnr))
-					continue;
+				/* if (!page_is_ram(pgnr)) continue; */
+				/* commented out until page_is_ram works */
 				ClearPageReserved(pg);
 				atomic_set(&pg->count, 1);
 				__free_page(pg);
diff -Nru a/arch/ppc/8260_io/Makefile b/arch/ppc/8260_io/Makefile
--- a/arch/ppc/8260_io/Makefile	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/8260_io/Makefile	Fri Sep 20 08:20:47 2002
@@ -1,5 +1,3 @@
-# BK Id: SCCS/s.Makefile 1.3 05/17/01 18:14:19 cort
-#
 #
 # Makefile for the linux MPC8xx ppc-specific parts of comm processor
 #
diff -Nru a/arch/ppc/8260_io/commproc.c b/arch/ppc/8260_io/commproc.c
--- a/arch/ppc/8260_io/commproc.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/8260_io/commproc.c	Fri Sep 20 08:20:41 2002
@@ -1,8 +1,4 @@
 /*
- * BK Id: SCCS/s.commproc.c 1.10 10/16/01 16:21:52 trini
- */
-
-/*
  * General Purpose functions for the global management of the
  * 8260 Communication Processor Module.
  * Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
diff -Nru a/arch/ppc/8260_io/enet.c b/arch/ppc/8260_io/enet.c
--- a/arch/ppc/8260_io/enet.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/8260_io/enet.c	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.enet.c 1.9 09/14/01 18:01:16 trini
- */
-/*
  * Ethernet driver for Motorola MPC8260.
  * Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
  * Copyright (c) 2000 MontaVista Software Inc. (source@mvista.com)
diff -Nru a/arch/ppc/8260_io/fcc_enet.c b/arch/ppc/8260_io/fcc_enet.c
--- a/arch/ppc/8260_io/fcc_enet.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/8260_io/fcc_enet.c	Fri Sep 20 08:20:46 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Fast Ethernet Controller (FCC) driver for Motorola MPC8260.
  * Copyright (c) 2000 MontaVista Software, Inc.   Dan Malek (dmalek@jlc.net)
  *
diff -Nru a/arch/ppc/8260_io/uart.c b/arch/ppc/8260_io/uart.c
--- a/arch/ppc/8260_io/uart.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/8260_io/uart.c	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  UART driver for MPC8260 CPM SCC or SMC
  *  Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
  *  Copyright (c) 2000 MontaVista Software, Inc. (source@mvista.com)
diff -Nru a/arch/ppc/8xx_io/Makefile b/arch/ppc/8xx_io/Makefile
--- a/arch/ppc/8xx_io/Makefile	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/8xx_io/Makefile	Fri Sep 20 08:20:46 2002
@@ -1,5 +1,3 @@
-# BK Id: %F% %I% %G% %U% %#%
-#
 #
 # Makefile for the linux MPC8xx ppc-specific parts of comm processor
 #
diff -Nru a/arch/ppc/8xx_io/commproc.c b/arch/ppc/8xx_io/commproc.c
--- a/arch/ppc/8xx_io/commproc.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/8xx_io/commproc.c	Fri Sep 20 08:20:46 2002
@@ -1,8 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
-/*
  * General Purpose functions for the global management of the
  * Communication Processor Module.
  * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
diff -Nru a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c
--- a/arch/ppc/8xx_io/enet.c	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/8xx_io/enet.c	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Ethernet driver for Motorola MPC8xx.
  * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
  *
diff -Nru a/arch/ppc/8xx_io/fec.c b/arch/ppc/8xx_io/fec.c
--- a/arch/ppc/8xx_io/fec.c	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc/8xx_io/fec.c	Fri Sep 20 08:20:48 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Fast Ethernet Controller (FEC) driver for Motorola MPC8xx.
  * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
  *
diff -Nru a/arch/ppc/8xx_io/uart.c b/arch/ppc/8xx_io/uart.c
--- a/arch/ppc/8xx_io/uart.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/8xx_io/uart.c	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  UART driver for MPC860 CPM SCC or SMC
  *  Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
  *
diff -Nru a/arch/ppc/Makefile b/arch/ppc/Makefile
--- a/arch/ppc/Makefile	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/Makefile	Fri Sep 20 08:20:41 2002
@@ -1,5 +1,3 @@
-# BK Id: %F% %I% %G% %U% %#%
-#
 # This file is included by the global makefile so that you can add your own
 # architecture-specific flags and dependencies. Remember to do have actions
 # for "archclean" and "archdep" for cleaning up and making dependencies for
@@ -24,9 +22,8 @@
 LDFLAGS_vmlinux	= -Ttext $(KERNELLOAD) -Bstatic
 CPPFLAGS	:= $(CPPFLAGS) -I$(TOPDIR)/arch/$(ARCH)
 AFLAGS		:= $(AFLAGS) -I$(TOPDIR)/arch/$(ARCH)
-CFLAGS		:= $(CFLAGS) -I$(TOPDIR)/arch/$(ARCH) -fsigned-char \
-		-msoft-float -pipe -ffixed-r2 -Wno-uninitialized \
-		-mmultiple -mstring
+CFLAGS		:= $(CFLAGS) -I$(TOPDIR)/arch/$(ARCH) -msoft-float -pipe \
+		-ffixed-r2 -Wno-uninitialized -mmultiple -mstring
 CPP		= $(CC) -E $(CFLAGS)
 
 ifdef CONFIG_4xx
@@ -99,6 +96,8 @@
 endif
 
 BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd pImage vmlinux.sm
+
+AFLAGS_vmlinux.lds.o	:= -Upowerpc
 
 # All the instructions talk about "make bzImage".
 bzImage: zImage
diff -Nru a/arch/ppc/amiga/Makefile b/arch/ppc/amiga/Makefile
--- a/arch/ppc/amiga/Makefile	Fri Sep 20 08:20:45 2002
+++ b/arch/ppc/amiga/Makefile	Fri Sep 20 08:20:45 2002
@@ -1,5 +1,3 @@
-# BK Id: %F% %I% %G% %U% %#%
-#
 #
 # Makefile for Linux arch/m68k/amiga source directory
 #
diff -Nru a/arch/ppc/amiga/amiga_ksyms.c b/arch/ppc/amiga/amiga_ksyms.c
--- a/arch/ppc/amiga/amiga_ksyms.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/amiga/amiga_ksyms.c	Fri Sep 20 08:20:41 2002
@@ -1,4 +1 @@
-/*
- * BK Id: SCCS/s.amiga_ksyms.c 1.5 05/17/01 18:14:20 cort
- */
 #include "../../m68k/amiga/amiga_ksyms.c"
diff -Nru a/arch/ppc/amiga/amiints.c b/arch/ppc/amiga/amiints.c
--- a/arch/ppc/amiga/amiints.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/amiga/amiints.c	Fri Sep 20 08:20:41 2002
@@ -1,8 +1,5 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- * linux/arch/m68k/amiga/amiints.c -- Amiga Linux interrupt handling code
+ * arch/ppc/amiga/amiints.c -- Amiga Linux interrupt handling code
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file COPYING in the main directory of this archive
diff -Nru a/arch/ppc/amiga/amisound.c b/arch/ppc/amiga/amisound.c
--- a/arch/ppc/amiga/amisound.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/amiga/amisound.c	Fri Sep 20 08:20:47 2002
@@ -1,4 +1 @@
-/*
- * BK Id: SCCS/s.amisound.c 1.5 05/17/01 18:14:20 cort
- */
 #include "../../m68k/amiga/amisound.c"
diff -Nru a/arch/ppc/amiga/bootinfo.c b/arch/ppc/amiga/bootinfo.c
--- a/arch/ppc/amiga/bootinfo.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/amiga/bootinfo.c	Fri Sep 20 08:20:47 2002
@@ -1,8 +1,5 @@
 /*
- * BK Id: SCCS/s.bootinfo.c 1.5 05/17/01 18:14:20 cort
- */
-/*
- *  linux/arch/ppc/amiga/bootinfo.c
+ *  arch/ppc/amiga/bootinfo.c
  *
  *  Extracted from arch/m68k/kernel/setup.c.
  *  Should be properly generalized and put somewhere else.
diff -Nru a/arch/ppc/amiga/chipram.c b/arch/ppc/amiga/chipram.c
--- a/arch/ppc/amiga/chipram.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/amiga/chipram.c	Fri Sep 20 08:20:47 2002
@@ -1,4 +1 @@
-/*
- * BK Id: SCCS/s.chipram.c 1.7 05/21/01 00:49:49 cort
- */
 #include "../../m68k/amiga/chipram.c"
diff -Nru a/arch/ppc/amiga/cia.c b/arch/ppc/amiga/cia.c
--- a/arch/ppc/amiga/cia.c	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc/amiga/cia.c	Fri Sep 20 08:20:43 2002
@@ -1,8 +1,5 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- *  linux/arch/m68k/amiga/cia.c - CIA support
+ *  arch/ppc/amiga/cia.c - CIA support
  *
  *  Copyright (C) 1996 Roman Zippel
  *
diff -Nru a/arch/ppc/amiga/config.c b/arch/ppc/amiga/config.c
--- a/arch/ppc/amiga/config.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/amiga/config.c	Fri Sep 20 08:20:47 2002
@@ -1,10 +1,7 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #define m68k_debug_device debug_device
 
 /*
- *  linux/arch/m68k/amiga/config.c
+ *  arch/ppc/amiga/config.c
  *
  *  Copyright (C) 1993 Hamish Macdonald
  *
diff -Nru a/arch/ppc/amiga/ints.c b/arch/ppc/amiga/ints.c
--- a/arch/ppc/amiga/ints.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/amiga/ints.c	Fri Sep 20 08:20:41 2002
@@ -1,8 +1,5 @@
 /*
- * BK Id: SCCS/s.ints.c 1.5 05/17/01 18:14:20 cort
- */
-/*
- *  linux/arch/ppc/amiga/ints.c
+ *  arch/ppc/amiga/ints.c
  *
  *  Linux/m68k general interrupt handling code from arch/m68k/kernel/ints.c
  *  Needed to drive the m68k emulating IRQ hardware on the PowerUp boards.
diff -Nru a/arch/ppc/amiga/pcmcia.c b/arch/ppc/amiga/pcmcia.c
--- a/arch/ppc/amiga/pcmcia.c	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/amiga/pcmcia.c	Fri Sep 20 08:20:44 2002
@@ -1,4 +1 @@
-/*
- * BK Id: SCCS/s.pcmcia.c 1.5 05/17/01 18:14:20 cort
- */
 #include "../../m68k/amiga/pcmcia.c"
diff -Nru a/arch/ppc/amiga/time.c b/arch/ppc/amiga/time.c
--- a/arch/ppc/amiga/time.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/amiga/time.c	Fri Sep 20 08:20:46 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.time.c 1.5 05/17/01 18:14:20 cort
- */
 #include <linux/config.h> /* CONFIG_HEARTBEAT */
 #include <linux/errno.h>
 #include <linux/sched.h>
diff -Nru a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile
--- a/arch/ppc/boot/Makefile	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/boot/Makefile	Fri Sep 20 08:20:47 2002
@@ -19,7 +19,7 @@
 
 MKIMAGE				:= ./utils/mkimage.wrapper
 
-lib/zlib.a: lib/zlib.c
+lib/lib.a: lib/zlib.c
 	$(MAKE) -C lib
 
 images/vmlinux.gz: $(TOPDIR)/vmlinux
@@ -28,7 +28,7 @@
 # Subdirs and tools needed for each.  Assume we always need to go into
 # 'simple' unless told otherwise.
 subdir-y			:= lib common simple
-subdir-$(CONFIG_ALL_PPC)	:= chrp pmac prep
+subdir-$(CONFIG_ALL_PPC)	:= openfirmware prep
 tools-$(CONFIG_ALL_PPC)		:= addnote mknote hack-coff mkprep
 tools-$(CONFIG_PPLUS)		:= mkbugboot mkprep
 tools-$(CONFIG_4xx)		:= mktree
@@ -47,6 +47,9 @@
 # These are the subdirs we want to use
 BOOTDIRS			= $(filter-out $(NONBOOT), $(subdir-y))
 
+makeof1275:
+	$(MAKE) -C of1275
+
 # This will make the tools we need.  We do it like this to ensure that we use
 # HOSTCC. -- Tom
 maketools:
@@ -55,7 +58,7 @@
 # The targets all boards support for boot images.
 BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd
 
-$(BOOT_TARGETS): vmapus lib/zlib.a images/vmlinux.gz maketools
+$(BOOT_TARGETS): vmapus lib/lib.a images/vmlinux.gz makeof1275 maketools
 ifneq ($(BOOTDIRS),)
 	for d in $(BOOTDIRS); do $(MAKE) -C $$d $@; done
 endif
@@ -80,5 +83,6 @@
 clean:
 	$(MAKE) -C images clean
 	$(MAKE) -C utils clean
+	$(MAKE) -C openfirmware clean
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/ppc/boot/chrp/Makefile b/arch/ppc/boot/chrp/Makefile
--- a/arch/ppc/boot/chrp/Makefile	Fri Sep 20 08:20:47 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,69 +0,0 @@
-# BK Id: %F% %I% %G% %U% %#%
-#
-# Makefile for making ELF bootable images for booting on CHRP
-# using Open Firmware.
-#
-# Geert Uytterhoeven	September 1997
-#
-# Based on coffboot by Paul Mackerras
-
-LD_ARGS = -T ../ld.script -Ttext 0x00400000
-
-OBJS = ../common/crt0.o start.o main.o misc.o ../common/string.o image.o \
-	../common/ofcommon.o
-
-EXTRA_TARGETS	:= $(OBJS)
-LIBS = $(TOPDIR)/lib/lib.a ../lib/zlib.a
-
-# Utils
-ADDNOTE = ../utils/addnote
-PIGGYBACK = ../utils/piggyback
-
-ifeq ($(CONFIG_PPC64BRIDGE),y)
-END += .64
-AFLAGS += -Wa,-mppc64bridge
-endif
-ifeq ($(CONFIG_SMP),y)
-END += .smp
-endif
-
-TFTPIMAGE=/tftpboot/zImage.chrp$(END)
-
-all: zImage
-
-znetboot: zImage
-	cp -f $(TOPDIR)/vmlinux /tftpboot/vmlinux$(END)
-	cp ../images/zImage.chrp $(TFTPIMAGE)
-
-znetboot.initrd: zImage.initrd
-	cp ../images/zImage.initrd.chrp $(TFTPIMAGE)
-
-floppy: zImage
-	mcopy zImage a:zImage
-
-image.o: ../images/vmlinux.gz ../common/dummy.o
-	$(OBJCOPY) ../common/dummy.o $@ \
-		--add-section=.image=../images/vmlinux.gz \
-		--set-section-flags=.image=contents,alloc,load,readonly,data
-ifdef CONFIG_XMON
-	$(OBJCOPY) $@ $@ \
-		--add-section=.sysmap=$(TOPDIR)/System.map \
-		--set-section-flags=.sysmap=contents,alloc,load,readonly,data
-endif
-
-zImage: $(OBJS) $(LIBS) $(ADDNOTE)
-	$(LD) $(LD_ARGS) -o ../images/$@.chrp $(OBJS) $(LIBS)
-	$(OBJCOPY) ../images/$@.chrp ../images/$@.chrp -R .comment -R .ramdisk
-	cp ../images/$@.chrp ../images/$@.chrp-rs6k
-	$(ADDNOTE) ../images/$@.chrp-rs6k
-
-zImage.initrd: $(OBJS) $(LIBS) $(ADDNOTE) ../images/ramdisk.image.gz
-	$(OBJCOPY) image.o image.o \
-		--add-section=.ramdisk=../images/ramdisk.image.gz \
-		--set-section-flags=.ramdisk=contents,alloc,load,readonly,data
-	$(LD) $(LD_ARGS) -o ../images/$@.chrp $(OBJS) $(LIBS)
-	$(OBJCOPY) ../images/$@.chrp ../images/$@.chrp -R .comment
-	cp ../images/$@.chrp ../images/$@.chrp-rs6k
-	$(ADDNOTE) ../images/$@.chrp-rs6k
-
-include $(TOPDIR)/Rules.make
diff -Nru a/arch/ppc/boot/chrp/main.c b/arch/ppc/boot/chrp/main.c
--- a/arch/ppc/boot/chrp/main.c	Fri Sep 20 08:20:41 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,106 +0,0 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- * Copyright (C) Paul Mackerras 1997.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include "nonstdio.h"
-#include <asm/processor.h>
-#include <asm/page.h>
-
-/* Passed from the linker */
-extern char __image_begin, __image_end;
-extern char __ramdisk_begin[], __ramdisk_end;
-extern char _start, _end;
-
-extern int getprop(void *, const char *, void *, int);
-extern unsigned int heap_max;
-extern void claim(unsigned int virt, unsigned int size, unsigned int align);
-extern void *finddevice(const char *);
-extern void flush_cache(void *, unsigned long);
-extern void gunzip(void *, int, unsigned char *, int *);
-extern void make_bi_recs(unsigned long addr, char *name, unsigned int mach,
-		unsigned int progend);
-extern void pause(void);
-
-char *avail_ram;
-char *begin_avail, *end_avail;
-char *avail_high;
-
-#define RAM_START	0x00000000
-#define RAM_END		(64<<20)
-
-#define BOOT_START	((unsigned long)_start)
-#define BOOT_END	((unsigned long)(_end + 0xFFF) & ~0xFFF)
-
-#define RAM_FREE	((unsigned long)(_end+0x1000)&~0xFFF)
-#define PROG_START	0x00010000
-#define PROG_SIZE	0x00400000 /* 4MB */
-
-#define SCRATCH_SIZE	(128 << 10)
-
-static char scratch[SCRATCH_SIZE];	/* 1MB of scratch space for gunzip */
-
-typedef void (*kernel_start_t)(int, int, void *, unsigned int, unsigned int);
-
-void
-chrpboot(int a1, int a2, void *prom)
-{
-    unsigned sa, len;
-    void *dst;
-    unsigned char *im;
-    unsigned int initrd_size, initrd_start;
-    
-    printf("chrpboot starting: loaded at 0x%p\n\r", &_start);
-
-    initrd_size = (char *)(&__ramdisk_end) - (char *)(&__ramdisk_begin);
-    if (initrd_size) {
-	initrd_start = (RAM_END - initrd_size) & ~0xFFF;
-	a1 = initrd_start;
-	a2 = initrd_size;
-	claim(initrd_start, RAM_END - initrd_start, 0);
-	printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n\r",
-	       initrd_start, (char *)(&__ramdisk_begin), initrd_size);
-	memcpy((char *)initrd_start, (char *)(&__ramdisk_begin), initrd_size);
-    } else {
-	initrd_start = 0;
-	initrd_size = 0;
-	a2 = 0xdeadbeef;
-    }
-
-    im = (char *)(&__image_begin);
-    len = (char *)(&__image_end) - (char *)(&__image_begin);
-    /* claim 4MB starting at PROG_START */
-    claim(PROG_START, PROG_SIZE - PROG_START, 0);
-    dst = (void *) PROG_START;
-    if (im[0] == 0x1f && im[1] == 0x8b) {
-	avail_ram = scratch;
-	begin_avail = avail_high = avail_ram;
-	end_avail = scratch + sizeof(scratch);
-	printf("gunzipping (0x%p <- 0x%p:0x%p)...", dst, im, im+len);
-	gunzip(dst, 0x400000, im, &len);
-	printf("done %u bytes\n\r", len);
-	printf("%u bytes of heap consumed, max in use %u\n\r",
-	       avail_high - begin_avail, heap_max);
-    } else {
-	memmove(dst, im, len);
-    }
-
-    flush_cache(dst, len);
-    make_bi_recs(((unsigned long) dst + len), "chrpboot", _MACH_chrp,
-		    (PROG_START + PROG_SIZE));
-    
-    sa = PROG_START;
-    printf("start address = 0x%x\n\r", sa);
-
-    (*(kernel_start_t)sa)(a1, a2, prom, initrd_start, initrd_size);
-
-    printf("returned?\n\r");
-
-    pause();
-}
diff -Nru a/arch/ppc/boot/chrp/misc.S b/arch/ppc/boot/chrp/misc.S
--- a/arch/ppc/boot/chrp/misc.S	Fri Sep 20 08:20:41 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,53 +0,0 @@
-/*
- * BK Id: SCCS/s.misc.S 1.6 05/18/01 15:16:59 cort
- */
-/*
- * Copyright (C) Paul Mackerras 1997.
- *
- * 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.
- */
-	.text
-
-/*
- * Use the BAT0 registers to map the 1st 8MB of RAM to 0x90000000.
- */
-	.globl	setup_bats
-setup_bats:
-	mfpvr	3
-	rlwinm	3,3,16,16,31		/* r3 = 1 for 601, 4 for 604 */
-	cmpi	0,3,1
-	lis	4,0x9000
-	bne	4f
-	ori	4,4,4			/* set up BAT registers for 601 */
-	li	5,0x7f
-	b	5f
-4:	ori	4,4,0xff		/* set up BAT registers for 604 */
-	li	5,2
-	mtdbatu	3,4
-	mtdbatl	3,5
-5:	mtibatu	3,4
-	mtibatl	3,5
-	isync
-	blr
-
-/*
- * Flush the dcache and invalidate the icache for a range of addresses.
- *
- * flush_cache(addr, len)
- */
-	.global	flush_cache
-flush_cache:
-	addi	4,4,0x1f	/* len = (len + 0x1f) / 0x20 */
-	rlwinm.	4,4,27,5,31
-	mtctr	4
-	beqlr
-1:	dcbf	0,3
-	icbi	0,3
-	addi	3,3,0x20
-	bdnz	1b
-	sync
-	isync
-	blr
diff -Nru a/arch/ppc/boot/chrp/start.c b/arch/ppc/boot/chrp/start.c
--- a/arch/ppc/boot/chrp/start.c	Fri Sep 20 08:20:41 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,311 +0,0 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- * Copyright (C) Paul Mackerras 1997.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <stdarg.h>
-
-int (*prom)(void *args);
-
-void *chosen_handle;
-void *stdin;
-void *stdout;
-void *stderr;
-
-void exit(void);
-void *finddevice(const char *name);
-int getprop(void *phandle, const char *name, void *buf, int buflen);
-
-void printk(char *fmt, ...);
-
-extern void chrpboot(int a1, int a2, void *prom);
-extern int strlen(const char *s);
-
-void
-start(int a1, int a2, void *promptr)
-{
-    prom = promptr;
-    chosen_handle = finddevice("/chosen");
-    if (chosen_handle == (void *) -1)
-	exit();
-    if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4)
-	exit();
-    stderr = stdout;
-    if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4)
-	exit();
-
-    chrpboot(a1, a2, promptr);
-    for (;;)
-	exit();
-}
-
-int
-write(void *handle, void *ptr, int nb)
-{
-    struct prom_args {
-	char *service;
-	int nargs;
-	int nret;
-	void *ihandle;
-	void *addr;
-	int len;
-	int actual;
-    } args;
-
-    args.service = "write";
-    args.nargs = 3;
-    args.nret = 1;
-    args.ihandle = handle;
-    args.addr = ptr;
-    args.len = nb;
-    args.actual = -1;
-    prom(&args);
-    return args.actual;
-}
-
-int
-read(void *handle, void *ptr, int nb)
-{
-    struct prom_args {
-	char *service;
-	int nargs;
-	int nret;
-	void *ihandle;
-	void *addr;
-	int len;
-	int actual;
-    } args;
-
-    args.service = "read";
-    args.nargs = 3;
-    args.nret = 1;
-    args.ihandle = handle;
-    args.addr = ptr;
-    args.len = nb;
-    args.actual = -1;
-    (*prom)(&args);
-    return args.actual;
-}
-
-void
-exit(void)
-{
-    struct prom_args {
-	char *service;
-    } args;
-
-    for (;;) {
-	args.service = "exit";
-	(*prom)(&args);
-    }
-}
-
-void
-pause(void)
-{
-    struct prom_args {
-	char *service;
-    } args;
-
-    args.service = "enter";
-    (*prom)(&args);
-}
-
-void *
-finddevice(const char *name)
-{
-    struct prom_args {
-	char *service;
-	int nargs;
-	int nret;
-	const char *devspec;
-	void *phandle;
-    } args;
-
-    args.service = "finddevice";
-    args.nargs = 1;
-    args.nret = 1;
-    args.devspec = name;
-    args.phandle = (void *) -1;
-    (*prom)(&args);
-    return args.phandle;
-}
-
-void *
-claim(unsigned int virt, unsigned int size, unsigned int align)
-{
-    struct prom_args {
-	char *service;
-	int nargs;
-	int nret;
-	unsigned int virt;
-	unsigned int size;
-	unsigned int align;
-	void *ret;
-    } args;
-
-    args.service = "claim";
-    args.nargs = 3;
-    args.nret = 1;
-    args.virt = virt;
-    args.size = size;
-    args.align = align;
-    (*prom)(&args);
-    return args.ret;
-}
-
-int
-getprop(void *phandle, const char *name, void *buf, int buflen)
-{
-    struct prom_args {
-	char *service;
-	int nargs;
-	int nret;
-	void *phandle;
-	const char *name;
-	void *buf;
-	int buflen;
-	int size;
-    } args;
-
-    args.service = "getprop";
-    args.nargs = 4;
-    args.nret = 1;
-    args.phandle = phandle;
-    args.name = name;
-    args.buf = buf;
-    args.buflen = buflen;
-    args.size = -1;
-    (*prom)(&args);
-    return args.size;
-}
-
-int
-putc(int c, void *f)
-{
-    char ch = c;
-
-    if (c == '\n')
-	putc('\r', f);
-    return write(f, &ch, 1) == 1? c: -1;
-}
-
-int
-putchar(int c)
-{
-    return putc(c, stdout);
-}
-
-int
-fputs(char *str, void *f)
-{
-    int n = strlen(str);
-
-    return write(f, str, n) == n? 0: -1;
-}
-
-int
-readchar(void)
-{
-    char ch;
-
-    for (;;) {
-	switch (read(stdin, &ch, 1)) {
-	case 1:
-	    return ch;
-	case -1:
-	    printk("read(stdin) returned -1\r\n");
-	    return -1;
-	}
-    }
-}
-
-static char line[256];
-static char *lineptr;
-static int lineleft;
-
-int
-getchar(void)
-{
-    int c;
-
-    if (lineleft == 0) {
-	lineptr = line;
-	for (;;) {
-	    c = readchar();
-	    if (c == -1 || c == 4)
-		break;
-	    if (c == '\r' || c == '\n') {
-		*lineptr++ = '\n';
-		putchar('\n');
-		break;
-	    }
-	    switch (c) {
-	    case 0177:
-	    case '\b':
-		if (lineptr > line) {
-		    putchar('\b');
-		    putchar(' ');
-		    putchar('\b');
-		    --lineptr;
-		}
-		break;
-	    case 'U' & 0x1F:
-		while (lineptr > line) {
-		    putchar('\b');
-		    putchar(' ');
-		    putchar('\b');
-		    --lineptr;
-		}
-		break;
-	    default:
-		if (lineptr >= &line[sizeof(line) - 1])
-		    putchar('\a');
-		else {
-		    putchar(c);
-		    *lineptr++ = c;
-		}
-	    }
-	}
-	lineleft = lineptr - line;
-	lineptr = line;
-    }
-    if (lineleft == 0)
-	return -1;
-    --lineleft;
-    return *lineptr++;
-}
-
-extern int vsprintf(char *buf, const char *fmt, va_list args);
-static char sprint_buf[1024];
-
-void
-printk(char *fmt, ...)
-{
-	va_list args;
-	int n;
-
-	va_start(args, fmt);
-	n = vsprintf(sprint_buf, fmt, args);
-	va_end(args);
-	write(stdout, sprint_buf, n);
-}
-
-int
-printf(char *fmt, ...)
-{
-	va_list args;
-	int n;
-
-	va_start(args, fmt);
-	n = vsprintf(sprint_buf, fmt, args);
-	va_end(args);
-	write(stdout, sprint_buf, n);
-	return n;
-}
diff -Nru a/arch/ppc/boot/common/cpc700_memory.c b/arch/ppc/boot/common/cpc700_memory.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/common/cpc700_memory.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,38 @@
+/*
+ * arch/ppc/boot/common/cpc700_memory.c
+ *
+ * Find memory based upon settings in the CPC700 bridge
+ *
+ * Author: Dan Cox
+ *
+ * Copyright 2001-2002 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <asm/types.h>
+#include <asm/io.h>
+#include "cpc700.h"
+
+unsigned long
+cpc700_get_mem_size(void)
+{
+	int i;
+	unsigned long len, amt;
+
+	/* Start at MB1EA, since MB0EA will most likely be the ending address
+	   for ROM space. */
+	for(len = 0, i = CPC700_MB1EA; i <= CPC700_MB4EA; i+=4) {
+		amt = cpc700_read_memreg(i);
+		if (amt == 0)
+			break;
+		len = amt;
+	}
+
+	return len;
+}
+
+
diff -Nru a/arch/ppc/boot/common/crt0.S b/arch/ppc/boot/common/crt0.S
--- a/arch/ppc/boot/common/crt0.S	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/boot/common/crt0.S	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 /*    Copyright (c) 1997 Paul Mackerras <paulus@cs.anu.edu.au>
  *      Initial Power Macintosh COFF version.
  *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
diff -Nru a/arch/ppc/boot/common/dummy.c b/arch/ppc/boot/common/dummy.c
--- a/arch/ppc/boot/common/dummy.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/boot/common/dummy.c	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 int main(void)
 {
 	return 0;
diff -Nru a/arch/ppc/boot/common/misc-simple.c b/arch/ppc/boot/common/misc-simple.c
--- a/arch/ppc/boot/common/misc-simple.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/boot/common/misc-simple.c	Fri Sep 20 08:20:47 2002
@@ -64,6 +64,7 @@
 extern unsigned long start;
 
 extern int CRT_tstc(void);
+extern unsigned long get_mem_size(void);
 extern unsigned long serial_init(int chan, void *ignored);
 extern void serial_close(unsigned long com_port);
 extern void gunzip(void *, int, unsigned char *, int *);
@@ -75,10 +76,19 @@
 	int timer = 0;
 	char *cp, ch;
 	struct bi_record *rec, *birecs;
+	unsigned long TotalMemory = 0;
 
 	serial_fixups();
 	com_port = serial_init(0, NULL);
 
+#if defined(CONFIG_LOPEC) || defined(CONFIG_PAL4)
+	/*
+	 * Call get_mem_size(), which is memory controller dependant,
+	 * and we must have the correct file linked in here.
+	 */
+	TotalMemory = get_mem_size();
+#endif
+
 	/* assume the chunk below 8M is free */
 	end_avail = (char *)0x00800000;
 
@@ -193,6 +203,13 @@
 	rec->tag = BI_FIRST;
 	rec->size = sizeof(struct bi_record);
 	rec = (struct bi_record *)((unsigned long)rec + rec->size);
+
+	if ( TotalMemory ) {
+		rec->tag = BI_MEMSIZE;
+		rec->data[0] = TotalMemory;
+		rec->size = sizeof(struct bi_record) + sizeof(unsigned long);
+		rec = (struct bi_record *)((unsigned long)rec + rec->size);
+	}
 
 	rec->tag = BI_CMD_LINE;
 	memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1);
diff -Nru a/arch/ppc/boot/common/mpc10x_memory.c b/arch/ppc/boot/common/mpc10x_memory.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/common/mpc10x_memory.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,109 @@
+/*
+ * arch/ppc/boot/common/mpc10x_common.c
+ * 
+ * A routine to find out how much memory the machine has.
+ *
+ * Based on:
+ * arch/ppc/kernel/mpc10x_common.c
+ *
+ * Author: Mark A. Greer
+ *         mgreer@mvista.com
+ *
+ * Copyright 2001-2002 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/pci.h>
+#include <asm/types.h>
+#include <asm/io.h>
+#include "mpc10x.h"
+
+/*
+ * *** WARNING - A BAT MUST be set to access the PCI config addr/data regs ***
+ */
+
+/*
+ * PCI config space macros, similar to indirect_xxx and early_xxx macros.
+ * We assume bus 0.
+ */
+#define MPC10X_CFG_read(val, addr, type, op)	*val = op((type)(addr))
+#define MPC10X_CFG_write(val, addr, type, op)	op((type *)(addr), (val))
+
+#define MPC10X_PCI_OP(rw, size, type, op, mask)			 	\
+static void								\
+mpc10x_##rw##_config_##size(unsigned int *cfg_addr, 			\
+		unsigned int *cfg_data, int devfn, int offset,		\
+		type val)						\
+{									\
+	out_be32(cfg_addr, 						\
+		 ((offset & 0xfc) << 24) | (devfn << 16)		\
+		 | (0 << 8) | 0x80);					\
+	MPC10X_CFG_##rw(val, cfg_data + (offset & mask), type, op);	\
+	return;    					 		\
+}
+
+MPC10X_PCI_OP(read, byte,  u8 *, in_8, 3)
+MPC10X_PCI_OP(read, dword, u32 *, in_le32, 0)
+
+/*
+ * Read the memory controller registers to determine the amount of memory in
+ * the system.  This assumes that the firmware has correctly set up the memory
+ * controller registers.  On CONFIG_ALL_PPC, we know we are being called
+ * under a PReP memory map. On all other machines, we assume we are under
+ * a CHRP memory map.
+ */
+unsigned long
+get_mem_size(void)
+{
+	unsigned int *config_addr, *config_data, val;
+	unsigned long start, end, total, offset;
+	int i;
+	unsigned char bank_enables;
+
+#ifdef CONFIG_ALL_PPC
+	config_addr = (unsigned int *)MPC10X_MAPA_CNFG_ADDR;
+	config_data = (unsigned int *)MPC10X_MAPA_CNFG_DATA;
+#else
+	config_addr = (unsigned int *)MPC10X_MAPB_CNFG_ADDR;
+	config_data = (unsigned int *)MPC10X_MAPB_CNFG_DATA;
+#endif
+
+	mpc10x_read_config_byte(config_addr, config_data, PCI_DEVFN(0,0),
+			MPC10X_MCTLR_MEM_BANK_ENABLES, &bank_enables);
+
+	total = 0;
+
+	for (i = 0; i < 8; i++) {
+		if (bank_enables & (1 << i)) {
+			offset = MPC10X_MCTLR_MEM_START_1 + ((i > 3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr, config_data,
+					PCI_DEVFN(0,0), offset, &val);
+			start = (val >> ((i & 3) << 3)) & 0xff;
+
+			offset = MPC10X_MCTLR_EXT_MEM_START_1 + ((i>3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr, config_data,
+					PCI_DEVFN(0,0), offset, &val);
+			val = (val >> ((i & 3) << 3)) & 0x03;
+			start = (val << 28) | (start << 20);
+
+			offset = MPC10X_MCTLR_MEM_END_1 + ((i > 3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr, config_data,
+					PCI_DEVFN(0,0), offset, &val);
+			end = (val >> ((i & 3) << 3)) & 0xff;
+
+			offset = MPC10X_MCTLR_EXT_MEM_END_1 + ((i > 3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr, config_data,
+					PCI_DEVFN(0,0), offset, &val);
+			val = (val >> ((i & 3) << 3)) & 0x03;
+			end = (val << 28) | (end << 20) | 0xfffff;
+
+			total += (end - start + 1);
+		}
+	}
+
+	return total;
+}
diff -Nru a/arch/ppc/boot/common/ns16550.c b/arch/ppc/boot/common/ns16550.c
--- a/arch/ppc/boot/common/ns16550.c	Fri Sep 20 08:20:45 2002
+++ b/arch/ppc/boot/common/ns16550.c	Fri Sep 20 08:20:45 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * COM1 NS16550 support
  */
 
diff -Nru a/arch/ppc/boot/common/ofcommon.c b/arch/ppc/boot/common/ofcommon.c
--- a/arch/ppc/boot/common/ofcommon.c	Fri Sep 20 08:20:45 2002
+++ b/arch/ppc/boot/common/ofcommon.c	Fri Sep 20 08:20:45 2002
@@ -1,6 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- *
  * Copyright (C) Paul Mackerras 1997.
  *
  * This program is free software; you can redistribute it and/or
diff -Nru a/arch/ppc/boot/common/string.S b/arch/ppc/boot/common/string.S
--- a/arch/ppc/boot/common/string.S	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/boot/common/string.S	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.string.S 1.8 05/18/01 06:20:29 patch
- */
-/*
  * String handling functions for PowerPC.
  *
  * Copyright (C) 1996 Paul Mackerras.
diff -Nru a/arch/ppc/boot/common/util.S b/arch/ppc/boot/common/util.S
--- a/arch/ppc/boot/common/util.S	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc/boot/common/util.S	Fri Sep 20 08:20:48 2002
@@ -160,11 +160,6 @@
 	blt	2b
 3:	blr
 
-.globl _put_MSR
-_put_MSR:
-	mtmsr	r3
-	blr
-
 	.section ".relocate_code","xa"
 /*
  * Flush and enable instruction cache
diff -Nru a/arch/ppc/boot/include/cpc700.h b/arch/ppc/boot/include/cpc700.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/include/cpc700.h	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,26 @@
+
+#ifndef __PPC_BOOT_CPC700_H
+#define __PPC_BOOT_CPC700_H
+
+#define CPC700_MEM_CFGADDR    0xff500008
+#define CPC700_MEM_CFGDATA    0xff50000c
+
+#define CPC700_MB0SA            0x38
+#define CPC700_MB0EA            0x58
+#define CPC700_MB1SA            0x3c
+#define CPC700_MB1EA            0x5c
+#define CPC700_MB2SA            0x40
+#define CPC700_MB2EA            0x60
+#define CPC700_MB3SA            0x44
+#define CPC700_MB3EA            0x64
+#define CPC700_MB4SA            0x48
+#define CPC700_MB4EA            0x68
+
+static inline long
+cpc700_read_memreg(int reg)
+{
+	out_be32((volatile unsigned int *) CPC700_MEM_CFGADDR, reg);
+	return in_be32((volatile unsigned int *) CPC700_MEM_CFGDATA);
+}
+
+#endif
diff -Nru a/arch/ppc/boot/include/mpc10x.h b/arch/ppc/boot/include/mpc10x.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/include/mpc10x.h	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,67 @@
+/*
+ * arch/ppc/boot/include/mpc10.h
+ *
+ * Common defines for the Motorola SPS MPC106/8240/107 Host bridge/Mem
+ * ctrl/EPIC/etc.
+ *
+ * Author: Tom Rini <trini@mvista.com>
+ *
+ * This is a heavily stripped down version of:
+ * include/asm-ppc/mpc10x.h
+ *
+ * Author: Mark A. Greer
+ *         mgreer@mvista.com
+ *
+ * Copyright 2001-2002 MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#ifndef __BOOT_MPC10X_H__
+#define __BOOT_MPC10X_H__
+
+/*
+ * The values here don't completely map everything but should work in most
+ * cases.
+ *
+ * MAP A (PReP Map)
+ *   Processor: 0x80000000 - 0x807fffff -> PCI I/O: 0x00000000 - 0x007fffff
+ *   Processor: 0xc0000000 - 0xdfffffff -> PCI MEM: 0x00000000 - 0x1fffffff
+ *   PCI MEM:   0x80000000 -> Processor System Memory: 0x00000000
+ *   EUMB mapped to: ioremap_base - 0x00100000 (ioremap_base - 1 MB)
+ *
+ * MAP B (CHRP Map)
+ *   Processor: 0xfe000000 - 0xfebfffff -> PCI I/O: 0x00000000 - 0x00bfffff
+ *   Processor: 0x80000000 - 0xbfffffff -> PCI MEM: 0x80000000 - 0xbfffffff
+ *   PCI MEM:   0x00000000 -> Processor System Memory: 0x00000000
+ *   EUMB mapped to: ioremap_base - 0x00100000 (ioremap_base - 1 MB)
+ */
+
+/* Define the type of map to use */
+#define	MPC10X_MEM_MAP_A		1
+#define	MPC10X_MEM_MAP_B		2
+
+/* Map A (PReP Map) Defines */
+#define	MPC10X_MAPA_CNFG_ADDR		0x80000cf8
+#define	MPC10X_MAPA_CNFG_DATA		0x80000cfc
+
+/* Map B (CHRP Map) Defines */
+#define	MPC10X_MAPB_CNFG_ADDR		0xfec00000
+#define	MPC10X_MAPB_CNFG_DATA		0xfee00000
+
+/* Define offsets for the memory controller registers in the config space */
+#define MPC10X_MCTLR_MEM_START_1	0x80	/* Banks 0-3 */
+#define MPC10X_MCTLR_MEM_START_2	0x84	/* Banks 4-7 */
+#define MPC10X_MCTLR_EXT_MEM_START_1	0x88	/* Banks 0-3 */
+#define MPC10X_MCTLR_EXT_MEM_START_2	0x8c	/* Banks 4-7 */
+
+#define MPC10X_MCTLR_MEM_END_1		0x90	/* Banks 0-3 */
+#define MPC10X_MCTLR_MEM_END_2i		0x94	/* Banks 4-7 */
+#define MPC10X_MCTLR_EXT_MEM_END_1	0x98	/* Banks 0-3 */
+#define MPC10X_MCTLR_EXT_MEM_END_2	0x9c	/* Banks 4-7 */
+
+#define MPC10X_MCTLR_MEM_BANK_ENABLES	0xa0
+
+#endif	/* __BOOT_MPC10X_H__ */
diff -Nru a/arch/ppc/boot/include/nonstdio.h b/arch/ppc/boot/include/nonstdio.h
--- a/arch/ppc/boot/include/nonstdio.h	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/boot/include/nonstdio.h	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.nonstdio.h 1.9 07/25/01 18:13:07 trini
- */
-/*
  * Copyright (C) Paul Mackerras 1997.
  *
  * This program is free software; you can redistribute it and/or
diff -Nru a/arch/ppc/boot/include/of1275.h b/arch/ppc/boot/include/of1275.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/include/of1275.h	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ * Copyright (C) Leigh Brown 2002.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+typedef void *prom_handle;
+typedef void *ihandle;
+typedef void *phandle;
+typedef int (*prom_entry)(void *);
+
+#define OF_INVALID_HANDLE	((prom_handle)-1UL)
+
+extern prom_entry of_prom_entry;
+
+/* function declarations */
+
+void *	claim(unsigned int virt, unsigned int size, unsigned int align);
+void	enter(void);
+void	exit(void);
+phandle	finddevice(const char *name);
+int	getprop(phandle node, const char *name, void *buf, int buflen);
+void	ofinit(prom_entry entry);
+int	ofstdio(ihandle *stdin, ihandle *stdout, ihandle *stderr);
+int	read(ihandle instance, void *buf, int buflen);
+void	release(void *virt, unsigned int size);
+int	write(ihandle instance, void *buf, int buflen);
+
+/* inlines */
+
+extern inline void pause(void)
+{
+	enter();
+}
diff -Nru a/arch/ppc/boot/include/rs6000.h b/arch/ppc/boot/include/rs6000.h
--- a/arch/ppc/boot/include/rs6000.h	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/boot/include/rs6000.h	Fri Sep 20 08:20:46 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.rs6000.h 1.7 05/18/01 15:17:23 cort
- */
 /* IBM RS/6000 "XCOFF" file definitions for BFD.
    Copyright (C) 1990, 1991 Free Software Foundation, Inc.
    FIXME: Can someone provide a transliteration of this name into ASCII?
diff -Nru a/arch/ppc/boot/include/zlib.h b/arch/ppc/boot/include/zlib.h
--- a/arch/ppc/boot/include/zlib.h	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc/boot/include/zlib.h	Fri Sep 20 08:20:43 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.zlib.h 1.8 05/18/01 15:17:23 cort
- */
-/*
  * This file is derived from zlib.h and zconf.h from the zlib-0.95
  * distribution by Jean-loup Gailly and Mark Adler, with some additions
  * by Paul Mackerras to aid in implementing Deflate compression and
diff -Nru a/arch/ppc/boot/ld.script b/arch/ppc/boot/ld.script
--- a/arch/ppc/boot/ld.script	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/boot/ld.script	Fri Sep 20 08:20:41 2002
@@ -39,7 +39,7 @@
   PROVIDE (etext = .);
 
   /* Read-write section, merged into data segment: */
-  . = (. + 0x0FFF) & 0xFFFFF000;
+  . = ALIGN(8);
   .data    :
   {
     *(.data)
@@ -69,6 +69,7 @@
   _edata  =  .;
   PROVIDE (edata = .);
 
+  . = ALIGN(8);
   __bss_start = .;
   .bss       :
   {
diff -Nru a/arch/ppc/boot/lib/Makefile b/arch/ppc/boot/lib/Makefile
--- a/arch/ppc/boot/lib/Makefile	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/boot/lib/Makefile	Fri Sep 20 08:20:44 2002
@@ -2,7 +2,7 @@
 # Makefile for some libs needed by zImage.
 #
 
-L_TARGET := zlib.a
+L_TARGET := lib.a
 
 obj-y := zlib.o
 
diff -Nru a/arch/ppc/boot/lib/zlib.c b/arch/ppc/boot/lib/zlib.c
--- a/arch/ppc/boot/lib/zlib.c	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/boot/lib/zlib.c	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * This file is derived from various .h and .c files from the zlib-0.95
  * distribution by Jean-loup Gailly and Mark Adler, with some additions
  * by Paul Mackerras to aid in implementing Deflate compression and
diff -Nru a/arch/ppc/boot/of1275/Makefile b/arch/ppc/boot/of1275/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/of1275/Makefile	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,10 @@
+#
+# Makefile of1275 stuff
+#
+
+L_TARGET := of1275.a
+
+obj-y := claim.o enter.o exit.o finddevice.o getprop.o ofinit.o	\
+	 ofstdio.o read.o release.o write.o
+
+include $(TOPDIR)/Rules.make
diff -Nru a/arch/ppc/boot/of1275/claim.c b/arch/ppc/boot/of1275/claim.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/of1275/claim.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ * Copyright (C) Leigh Brown 2002.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "of1275.h"
+
+void *
+claim(unsigned int virt, unsigned int size, unsigned int align)
+{
+    struct prom_args {
+	char *service;
+	int nargs;
+	int nret;
+	unsigned int virt;
+	unsigned int size;
+	unsigned int align;
+	void *ret;
+    } args;
+
+    args.service = "claim";
+    args.nargs = 3;
+    args.nret = 1;
+    args.virt = virt;
+    args.size = size;
+    args.align = align;
+    (*of_prom_entry)(&args);
+    return args.ret;
+}
diff -Nru a/arch/ppc/boot/of1275/enter.c b/arch/ppc/boot/of1275/enter.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/of1275/enter.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ * Copyright (C) Leigh Brown 2002.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "of1275.h"
+
+void
+enter(void)
+{
+    struct prom_args {
+	char *service;
+    } args;
+
+    args.service = "enter";
+    (*of_prom_entry)(&args);
+}
diff -Nru a/arch/ppc/boot/of1275/exit.c b/arch/ppc/boot/of1275/exit.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/of1275/exit.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ * Copyright (C) Leigh Brown 2002.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "of1275.h"
+
+void
+exit(void)
+{
+    struct prom_args {
+	char *service;
+    } args;
+
+    for (;;) {
+	args.service = "exit";
+	(*of_prom_entry)(&args);
+    }
+}
diff -Nru a/arch/ppc/boot/of1275/finddevice.c b/arch/ppc/boot/of1275/finddevice.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/of1275/finddevice.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ * Copyright (C) Leigh Brown 2002.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "of1275.h"
+
+phandle
+finddevice(const char *name)
+{
+    struct prom_args {
+	char *service;
+	int nargs;
+	int nret;
+	const char *devspec;
+	phandle device;
+    } args;
+
+    args.service = "finddevice";
+    args.nargs = 1;
+    args.nret = 1;
+    args.devspec = name;
+    args.device = OF_INVALID_HANDLE;
+    (*of_prom_entry)(&args);
+    return args.device;
+}
diff -Nru a/arch/ppc/boot/of1275/getprop.c b/arch/ppc/boot/of1275/getprop.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/of1275/getprop.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ * Copyright (C) Leigh Brown 2002.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "of1275.h"
+
+int
+getprop(phandle node, const char *name, void *buf, int buflen)
+{
+    struct prom_args {
+	char *service;
+	int nargs;
+	int nret;
+	phandle node;
+	const char *name;
+	void *buf;
+	int buflen;
+	int size;
+    } args;
+
+    args.service = "getprop";
+    args.nargs = 4;
+    args.nret = 1;
+    args.node = node;
+    args.name = name;
+    args.buf = buf;
+    args.buflen = buflen;
+    args.size = -1;
+    (*of_prom_entry)(&args);
+    return args.size;
+}
diff -Nru a/arch/ppc/boot/of1275/ofinit.c b/arch/ppc/boot/of1275/ofinit.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/of1275/ofinit.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ * Copyright (C) Leigh Brown 2002.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "of1275.h"
+
+prom_entry of_prom_entry;
+
+void
+ofinit(prom_entry prom_ptr)
+{
+    of_prom_entry = prom_ptr;
+}
diff -Nru a/arch/ppc/boot/of1275/ofstdio.c b/arch/ppc/boot/of1275/ofstdio.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/of1275/ofstdio.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ * Copyright (C) Leigh Brown 2002.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "of1275.h"
+
+int
+ofstdio(ihandle *stdin, ihandle *stdout, ihandle *stderr)
+{
+    ihandle in, out;
+    phandle chosen;
+   
+    if ((chosen = finddevice("/chosen")) == OF_INVALID_HANDLE)
+	goto err;
+    if (getprop(chosen, "stdout", &out, sizeof(out)) != 4)
+	goto err;
+    if (getprop(chosen, "stdin", &in, sizeof(in)) != 4)
+	goto err;
+
+    *stdin  = in;
+    *stdout = out;
+    *stderr = out;
+    return 0;
+err:
+    return -1;
+}
diff -Nru a/arch/ppc/boot/of1275/read.c b/arch/ppc/boot/of1275/read.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/of1275/read.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ * Copyright (C) Leigh Brown 2002.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "of1275.h"
+
+int
+read(ihandle instance, void *buf, int buflen)
+{
+    struct prom_args {
+	char *service;
+	int nargs;
+	int nret;
+	ihandle instance;
+	void *buf;
+	int buflen;
+	int actual;
+    } args;
+
+    args.service = "read";
+    args.nargs = 3;
+    args.nret = 1;
+    args.instance = instance;
+    args.buf = buf;
+    args.buflen = buflen;
+    args.actual = -1;
+    (*of_prom_entry)(&args);
+    return args.actual;
+}
diff -Nru a/arch/ppc/boot/of1275/release.c b/arch/ppc/boot/of1275/release.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/of1275/release.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ * Copyright (C) Leigh Brown 2002.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "of1275.h"
+
+void
+release(void *virt, unsigned int size)
+{
+    struct prom_args {
+	char *service;
+	int nargs;
+	int nret;
+	void *virt;
+	unsigned int size;
+    } args;
+
+    args.service = "release";
+    args.nargs = 2;
+    args.nret = 0;
+    args.virt = virt;
+    args.size = size;
+    (*of_prom_entry)(&args);
+}
diff -Nru a/arch/ppc/boot/of1275/write.c b/arch/ppc/boot/of1275/write.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/of1275/write.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ * Copyright (C) Leigh Brown 2002.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "of1275.h"
+
+int
+write(ihandle instance, void *buf, int buflen)
+{
+    struct prom_args {
+	char *service;
+	int nargs;
+	int nret;
+	ihandle instance;
+	void *buf;
+	int buflen;
+	int actual;
+    } args;
+
+    args.service = "write";
+    args.nargs = 3;
+    args.nret = 1;
+    args.instance = instance;
+    args.buf = buf;
+    args.buflen = buflen;
+    args.actual = -1;
+    (*of_prom_entry)(&args);
+    return args.actual;
+}
diff -Nru a/arch/ppc/boot/openfirmware/Makefile b/arch/ppc/boot/openfirmware/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/openfirmware/Makefile	Fri Sep 20 08:20:44 2002
@@ -0,0 +1,137 @@
+# Makefile for making bootable images on various OpenFirmware machines.
+#
+# Paul Mackerras	January 1997
+#	XCOFF bootable images for PowerMacs
+# Geert Uytterhoeven	September 1997
+#	ELF bootable iamges for CHRP machines.
+# Tom Rini		January 2001
+# 	Cleaned up, moved into arch/ppc/boot/pmac
+# Tom Rini		July/August 2002
+#	Merged 'chrp' and 'pmac' into 'openfirmware', and cleaned up the
+#	rules.
+
+OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment
+COFF_LD_ARGS = -T ../ld.script -e _start -Ttext 0x00500000 -Bstatic
+CHRP_LD_ARGS = -T ../ld.script -e _start -Ttext 0x00400000
+NEWWORLD_LD_ARGS = -T ../ld.script -e _start -Ttext 0x01000000
+
+COMMONOBJS = start.o misc.o ../common/string.o common.o
+COFFOBJS = ../common/coffcrt0.o $(COMMONOBJS) coffmain.o
+CHRPOBJS = ../common/crt0.o $(COMMONOBJS) chrpmain.o
+NEWWORLDOBJS = ../common/crt0.o $(COMMONOBJS) newworldmain.o
+
+EXTRA_TARGETS	:= $(COFFOBJS) $(CHRPOBJS) $(NEWWORLDOBJS)
+LIBS = $(TOPDIR)/lib/lib.a ../lib/zlib.a ../of1275/of1275.a
+
+ADDNOTE := ../utils/addnote
+MKNOTE := ../utils/mknote
+SIZE := ../utils/size
+OFFSET := ../utils/offset
+HACKCOFF := ../utils/hack-coff
+
+ifdef CONFIG_SMP
+END := .smp
+endif
+ifdef CONFIG_PPC64BRIDGE
+END += .64
+endif
+
+TFTPIMAGE=/tftpboot/zImage.
+
+../common/coffcrt0.o:
+	$(MAKE) -C ../common coffcrt0.o
+
+image.o: ../images/vmlinux.gz ../common/dummy.o
+	$(OBJCOPY) ../common/dummy.o $@ -R .comment \
+		--add-section=.image=../images/vmlinux.gz \
+		--set-section-flags=.image=contents,alloc,load,readonly,data
+ifdef CONFIG_XMON
+	$(OBJCOPY) $@ $@ \
+		--add-section=.sysmap=$(TOPDIR)/System.map \
+		--set-section-flags=.sysmap=contents,alloc,load,readonly,data
+endif
+
+# Place the ramdisk in the initrd image.
+image-initrd.o: image.o ../images/ramdisk.image.gz
+	$(OBJCOPY) image.o $@ \
+		--add-section=.ramdisk=../images/ramdisk.image.gz \
+		--set-section-flags=.ramdisk=contents,alloc,load,readonly,data
+
+# Create the note section for New-World PowerMacs.
+note: $(MKNOTE)
+	$(MKNOTE) > note
+
+znetboot: vmlinux.coff vmlinux.elf-pmac zImage
+	cp ../images/vmlinux.coff $(TFTPIMAGE).pmac$(END)
+	cp ../images/vmlinux.elf-pmac $(TFTPIMAGE).pmac$(END)elf
+	cp ../images/zImage.chrp $(TFTPIMAGE).chrp$(END)
+
+znetboot.initrd: vmlinux.initrd.coff vmlinux.initrd.elf-pmac
+	cp ../images/vmlinux.initrd.coff $(TFTPIMAGE).pmac$(END)
+	cp ../images/vmlinux.initrd.elf-pmac $(TFTPIMAGE).pmac$(END).elf
+	cp ../images/zImage.initrd.chrp $(TFTPIMAGE).chrp$(END)
+
+miboot.image: ../common/dummy.o ../images/vmlinux.gz
+	$(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=../images/vmlinux.gz \
+		../common/dummy.o ../images/$@
+
+miboot.initrd.image: miboot.image ../images/ramdisk.image.gz
+	$(OBJCOPY) $(OBJCOPY_ARGS) \
+		--add-section=initrd=../images/ramdisk.image.gz \
+		../images/miboot.image ../images/$@
+
+coffboot: $(COFFOBJS) image.o $(LIBS)
+	$(LD) -o $@ $(COFF_LD_ARGS) $^
+	$(OBJCOPY) $@ $@ -R .comment -R .ramdisk
+
+coffboot.initrd: $(COFFOBJS) image-initrd.o $(LIBS)
+	$(LD) -o $@ $(COFF_LD_ARGS) $^
+	$(OBJCOPY) $@ $@ -R .comment
+
+vmlinux.coff: coffboot $(HACKCOFF)
+	$(OBJCOPY) $(OBJCOPY_ARGS) coffboot ../images/$@
+	$(HACKCOFF) ../images/$@
+	rm -f coffboot
+	ln -sf vmlinux.coff ../images/zImage.pmac
+
+vmlinux.initrd.coff: coffboot.initrd $(HACKCOFF)
+	$(OBJCOPY) $(OBJCOPY_ARGS) coffboot.initrd ../images/$@
+	$(HACKCOFF) ../images/$@
+	rm -f coffboot.initrd
+	ln -sf vmlinux.initrd.coff ../images/zImage.initrd.pmac
+
+vmlinux.elf-pmac: $(NEWWORLDOBJS) $(LIBS) image.o
+	$(LD) $(NEWWORLD_LD_ARGS) -o ../images/$@ $^
+
+vmlinux.initrd.elf-pmac: $(NEWWORLDOBJS) $(LIBS) image-initrd.o
+	$(LD) $(NEWWORLD_LD_ARGS) -o ../images/$@ $^
+
+zImage.chrp: $(CHRPOBJS) image.o $(LIBS)
+	$(LD) $(CHRP_LD_ARGS) -o ../images/$@ $^
+
+zImage.initrd.chrp: $(CHRPOBJS) image-initrd.o $(LIBS)
+	$(LD) $(CHRP_LD_ARGS) -o ../images/$@ $^
+
+zImage: vmlinux.coff vmlinux.elf-pmac zImage.chrp miboot.image $(ADDNOTE) \
+	note
+	$(OBJCOPY) ../images/vmlinux.elf-pmac ../images/vmlinux.elf-pmac \
+		--add-section=.note=note -R .comment -R .ramdisk
+	$(OBJCOPY) ../images/zImage.chrp ../images/zImage.chrp \
+		-R .comment -R .ramdisk
+	cp ../images/zImage.chrp ../images/zImage.chrp-rs6k
+	$(ADDNOTE) ../images/zImage.chrp-rs6k
+
+zImage.initrd: vmlinux.initrd.coff vmlinux.initrd.elf-pmac zImage.initrd.chrp \
+	miboot.initrd.image $(ADDNOTE) note
+	$(OBJCOPY) ../images/vmlinux.initrd.elf-pmac \
+		../images/vmlinux.initrd.elf-pmac --add-section=.note=note \
+		-R .comment
+	$(OBJCOPY) ../images/zImage.initrd.chrp ../images/zImage.initrd.chrp \
+		-R .comment
+	cp ../images/zImage.initrd.chrp ../images/zImage.initrd.chrp-rs6k
+	$(ADDNOTE) ../images/zImage.initrd.chrp-rs6k
+
+clean:
+	rm -f note
+
+include $(TOPDIR)/Rules.make
diff -Nru a/arch/ppc/boot/openfirmware/chrpmain.c b/arch/ppc/boot/openfirmware/chrpmain.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/openfirmware/chrpmain.c	Fri Sep 20 08:20:41 2002
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include "nonstdio.h"
+#include "of1275.h"
+#include <asm/processor.h>
+#include <asm/page.h>
+
+/* Passed from the linker */
+extern char __image_begin, __image_end;
+extern char __ramdisk_begin, __ramdisk_end;
+extern char _start, _end;
+
+extern unsigned int heap_max;
+extern void flush_cache(void *, unsigned long);
+extern void gunzip(void *, int, unsigned char *, int *);
+extern void make_bi_recs(unsigned long addr, char *name, unsigned int mach,
+		unsigned int progend);
+
+char *avail_ram;
+char *begin_avail, *end_avail;
+char *avail_high;
+
+#define RAM_START	0x00000000
+#define RAM_END		(64<<20)
+
+#define BOOT_START	((unsigned long)_start)
+#define BOOT_END	((unsigned long)(_end + 0xFFF) & ~0xFFF)
+
+#define RAM_FREE	((unsigned long)(_end+0x1000)&~0xFFF)
+#define PROG_START	0x00010000
+#define PROG_SIZE	0x00400000 /* 4MB */
+
+#define SCRATCH_SIZE	(128 << 10)
+
+static char scratch[SCRATCH_SIZE];	/* 1MB of scratch space for gunzip */
+
+typedef void (*kernel_start_t)(int, int, void *, unsigned int, unsigned int);
+
+void
+boot(int a1, int a2, void *prom)
+{
+    unsigned sa, len;
+    void *dst;
+    unsigned char *im;
+    unsigned int initrd_size, initrd_start;
+    
+    printf("chrpboot starting: loaded at 0x%p\n\r", &_start);
+
+    initrd_size = &__ramdisk_end - &__ramdisk_begin;
+    if (initrd_size) {
+	initrd_start = (RAM_END - initrd_size) & ~0xFFF;
+	a1 = initrd_start;
+	a2 = initrd_size;
+	claim(initrd_start, RAM_END - initrd_start, 0);
+	printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n\r",
+	       initrd_start, &__ramdisk_begin, initrd_size);
+	memcpy((char *)initrd_start, &__ramdisk_begin, initrd_size);
+    } else {
+	initrd_start = 0;
+	initrd_size = 0;
+	a2 = 0xdeadbeef;
+    }
+
+    im = &__image_begin;
+    len = &__image_end - &__image_begin;
+    /* claim 4MB starting at PROG_START */
+    claim(PROG_START, PROG_SIZE - PROG_START, 0);
+    dst = (void *) PROG_START;
+    if (im[0] == 0x1f && im[1] == 0x8b) {
+	avail_ram = scratch;
+	begin_avail = avail_high = avail_ram;
+	end_avail = scratch + sizeof(scratch);
+	printf("gunzipping (0x%p <- 0x%p:0x%p)...", dst, im, im+len);
+	gunzip(dst, 0x400000, im, &len);
+	printf("done %u bytes\n\r", len);
+	printf("%u bytes of heap consumed, max in use %u\n\r",
+	       avail_high - begin_avail, heap_max);
+    } else {
+	memmove(dst, im, len);
+    }
+
+    flush_cache(dst, len);
+    make_bi_recs(((unsigned long) dst + len), "chrpboot", _MACH_chrp,
+		    (PROG_START + PROG_SIZE));
+    
+    sa = PROG_START;
+    printf("start address = 0x%x\n\r", sa);
+
+    (*(kernel_start_t)sa)(a1, a2, prom, initrd_start, initrd_size);
+
+    printf("returned?\n\r");
+
+    pause();
+}
diff -Nru a/arch/ppc/boot/openfirmware/coffmain.c b/arch/ppc/boot/openfirmware/coffmain.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/openfirmware/coffmain.c	Fri Sep 20 08:20:46 2002
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <asm/processor.h>
+#include <asm/page.h>
+
+#include "nonstdio.h"
+#include "of1275.h"
+#include "zlib.h"
+
+/* Passed from the linker */
+extern char __image_begin, __image_end;
+extern char __ramdisk_begin[], __ramdisk_end;
+extern char _start, _end;
+
+extern char image_data[], initrd_data[];
+extern int initrd_len, image_len;
+extern unsigned int heap_max;
+extern void flush_cache(void *start, unsigned int len);
+extern void gunzip(void *, int, unsigned char *, int *);
+extern void make_bi_recs(unsigned long addr, char *name, unsigned int mach,
+		unsigned int progend);
+extern void setup_bats(unsigned long start);
+
+char *avail_ram;
+char *begin_avail, *end_avail;
+char *avail_high;
+
+#define RAM_START	0
+#define RAM_END		(RAM_START + 0x800000)	/* only 8M mapped with BATs */
+
+#define PROG_START	RAM_START
+#define PROG_SIZE	0x00400000
+
+#define SCRATCH_SIZE	(128 << 10)
+
+static char heap[SCRATCH_SIZE];
+
+typedef void (*kernel_start_t)(int, int, void *);
+
+void boot(int a1, int a2, void *prom)
+{
+    unsigned sa, len;
+    void *dst;
+    unsigned char *im;
+    unsigned initrd_start, initrd_size;
+    
+    printf("coffboot starting: loaded at 0x%p\n", &_start);
+    setup_bats(RAM_START);
+
+    initrd_size = (char *)(&__ramdisk_end) - (char *)(&__ramdisk_begin);
+    if (initrd_size) {
+	initrd_start = (RAM_END - initrd_size) & ~0xFFF;
+	a1 = initrd_start;
+	a2 = initrd_size;
+	claim(initrd_start, RAM_END - initrd_start, 0);
+	printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n\r",
+	       initrd_start, (char *)(&__ramdisk_begin), initrd_size);
+	memcpy((char *)initrd_start, (char *)(&__ramdisk_begin), initrd_size);
+    } else
+	a2 = 0xdeadbeef;
+
+    im = (char *)(&__image_begin);
+    len = (char *)(&__image_end) - (char *)(&__image_begin);
+    /* claim 4MB starting at 0 */
+    claim(0, PROG_SIZE, 0);
+    dst = (void *) RAM_START;
+    if (im[0] == 0x1f && im[1] == 0x8b) {
+	/* set up scratch space */
+	begin_avail = avail_high = avail_ram = heap;
+	end_avail = heap + sizeof(heap);
+	printf("heap at 0x%p\n", avail_ram);
+	printf("gunzipping (0x%p <- 0x%p:0x%p)...", dst, im, im+len);
+	gunzip(dst, PROG_SIZE, im, &len);
+	printf("done %u bytes\n", len);
+	printf("%u bytes of heap consumed, max in use %u\n",
+	       avail_high - begin_avail, heap_max);
+    } else {
+	memmove(dst, im, len);
+    }
+
+    flush_cache(dst, len);
+    make_bi_recs(((unsigned long) dst + len), "coffboot", _MACH_Pmac,
+		    (PROG_START + PROG_SIZE));
+
+    sa = (unsigned long)PROG_START;
+    printf("start address = 0x%x\n", sa);
+
+    (*(kernel_start_t)sa)(a1, a2, prom);
+
+    printf("returned?\n");
+
+    pause();
+}
diff -Nru a/arch/ppc/boot/openfirmware/common.c b/arch/ppc/boot/openfirmware/common.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/openfirmware/common.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "zlib.h"
+#include "nonstdio.h"
+#include "of1275.h"
+#include <asm/bootinfo.h>
+#include <asm/page.h>
+
+/* Information from the linker */
+extern char __sysmap_begin, __sysmap_end;
+
+extern int strcmp(const char *s1, const char *s2);
+extern char *avail_ram, *avail_high;
+extern char *end_avail;
+
+unsigned int heap_use, heap_max;
+
+struct memchunk {
+    unsigned int size;
+    struct memchunk *next;
+};
+
+static struct memchunk *freechunks;
+
+static void *zalloc(void *x, unsigned items, unsigned size)
+{
+    void *p;
+    struct memchunk **mpp, *mp;
+
+    size *= items;
+    size = (size + 7) & -8;
+    heap_use += size;
+    if (heap_use > heap_max)
+	heap_max = heap_use;
+    for (mpp = &freechunks; (mp = *mpp) != 0; mpp = &mp->next) {
+	if (mp->size == size) {
+	    *mpp = mp->next;
+	    return mp;
+	}
+    }
+    p = avail_ram;
+    avail_ram += size;
+    if (avail_ram > avail_high)
+	avail_high = avail_ram;
+    if (avail_ram > end_avail) {
+	printf("oops... out of memory\n\r");
+	pause();
+    }
+    return p;
+}
+
+static void zfree(void *x, void *addr, unsigned nb)
+{
+    struct memchunk *mp = addr;
+
+    nb = (nb + 7) & -8;
+    heap_use -= nb;
+    if (avail_ram == addr + nb) {
+	avail_ram = addr;
+	return;
+    }
+    mp->size = nb;
+    mp->next = freechunks;
+    freechunks = mp;
+}
+
+#define HEAD_CRC	2
+#define EXTRA_FIELD	4
+#define ORIG_NAME	8
+#define COMMENT		0x10
+#define RESERVED	0xe0
+
+#define DEFLATED	8
+
+void gunzip(void *dst, int dstlen, unsigned char *src, int *lenp)
+{
+    z_stream s;
+    int r, i, flags;
+
+    /* skip header */
+    i = 10;
+    flags = src[3];
+    if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
+	printf("bad gzipped data\n\r");
+	exit();
+    }
+    if ((flags & EXTRA_FIELD) != 0)
+	i = 12 + src[10] + (src[11] << 8);
+    if ((flags & ORIG_NAME) != 0)
+	while (src[i++] != 0)
+	    ;
+    if ((flags & COMMENT) != 0)
+	while (src[i++] != 0)
+	    ;
+    if ((flags & HEAD_CRC) != 0)
+	i += 2;
+    if (i >= *lenp) {
+	printf("gunzip: ran out of data in header\n\r");
+	exit();
+    }
+
+    s.zalloc = zalloc;
+    s.zfree = zfree;
+    r = inflateInit2(&s, -MAX_WBITS);
+    if (r != Z_OK) {
+	printf("inflateInit2 returned %d\n\r", r);
+	exit();
+    }
+    s.next_in = src + i;
+    s.avail_in = *lenp - i;
+    s.next_out = dst;
+    s.avail_out = dstlen;
+    r = inflate(&s, Z_FINISH);
+    if (r != Z_OK && r != Z_STREAM_END) {
+	printf("inflate returned %d msg: %s\n\r", r, s.msg);
+	exit();
+    }
+    *lenp = s.next_out - (unsigned char *) dst;
+    inflateEnd(&s);
+}
+
+/* Make a bi_rec in OF.  We need to be passed a name for BI_BOOTLOADER_ID,
+ * a machine type for BI_MACHTYPE, and the location where the end of the
+ * bootloader is (PROG_START + PROG_SIZE)
+ */
+void make_bi_recs(unsigned long addr, char *name, unsigned int mach,
+		unsigned long progend)
+{
+	unsigned long sysmap_size;
+	struct bi_record *rec;
+
+	/* Figure out the size of a possible System.map we're going to
+	 * pass along.
+	 * */
+	sysmap_size = (unsigned long)(&__sysmap_end) -
+		(unsigned long)(&__sysmap_begin);
+
+	/* leave a 1MB gap then align to the next 1MB boundary */
+	addr = _ALIGN(addr+ (1<<20) - 1, (1<<20));
+	/* oldworld machine seem very unhappy about this. -- Tom */
+	if (addr >= progend)
+		claim(addr, 0x1000, 0);
+
+	rec = (struct bi_record *)addr;
+	rec->tag = BI_FIRST;
+	rec->size = sizeof(struct bi_record);
+	rec = (struct bi_record *)((unsigned long)rec + rec->size);
+
+	rec->tag = BI_BOOTLOADER_ID;
+	sprintf( (char *)rec->data, name);
+	rec->size = sizeof(struct bi_record) + strlen(name) + 1;
+	rec = (struct bi_record *)((unsigned long)rec + rec->size);
+
+	rec->tag = BI_MACHTYPE;
+	rec->data[0] = mach;
+	rec->data[1] = 1;
+	rec->size = sizeof(struct bi_record) + 2 * sizeof(unsigned long);
+	rec = (struct bi_record *)((unsigned long)rec + rec->size);
+
+	if (sysmap_size) {
+		rec->tag = BI_SYSMAP;
+		rec->data[0] = (unsigned long)(&__sysmap_begin);
+		rec->data[1] = sysmap_size;
+		rec->size = sizeof(struct bi_record) + 2 *
+			sizeof(unsigned long);
+		rec = (struct bi_record *)((unsigned long)rec + rec->size);
+	}
+
+	rec->tag = BI_LAST;
+	rec->size = sizeof(struct bi_record);
+	rec = (struct bi_record *)((unsigned long)rec + rec->size);
+}
diff -Nru a/arch/ppc/boot/openfirmware/misc.S b/arch/ppc/boot/openfirmware/misc.S
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/openfirmware/misc.S	Fri Sep 20 08:20:47 2002
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * 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.
+ */
+	.text
+
+/*
+ * Use the BAT3 registers to map the 1st 8MB of RAM to
+ * the address given as the 1st argument.
+ */
+	.globl	setup_bats
+setup_bats:
+	mfpvr	5
+	rlwinm	5,5,16,16,31		/* r3 = 1 for 601, 4 for 604 */
+	cmpi	0,5,1
+	li	0,0
+	bne	4f
+	mtibatl	3,0			/* invalidate BAT first */
+	ori	3,3,4			/* set up BAT registers for 601 */
+	li	4,0x7f
+	mtibatu	3,3
+	mtibatl	3,4
+	b	5f
+4:	mtdbatu	3,0			/* invalidate BATs first */
+	mtibatu	3,0
+	ori	3,3,0xff		/* set up BAT registers for 604 */
+	li	4,2
+	mtdbatl	3,4
+	mtdbatu	3,3
+	mtibatl	3,4
+	mtibatu	3,3
+5:	sync
+	isync
+	blr
+
+/*
+ * Flush the dcache and invalidate the icache for a range of addresses.
+ *
+ * flush_cache(addr, len)
+ */
+	.global	flush_cache
+flush_cache:
+	addi	4,4,0x1f	/* len = (len + 0x1f) / 0x20 */
+	rlwinm.	4,4,27,5,31
+	mtctr	4
+	beqlr
+1:	dcbf	0,3
+	icbi	0,3
+	addi	3,3,0x20
+	bdnz	1b
+	sync
+	isync
+	blr
diff -Nru a/arch/ppc/boot/openfirmware/newworldmain.c b/arch/ppc/boot/openfirmware/newworldmain.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/openfirmware/newworldmain.c	Fri Sep 20 08:20:41 2002
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include "nonstdio.h"
+#include "of1275.h"
+#include <asm/processor.h>
+#include <asm/page.h>
+
+/* Passed from the linker */
+extern char __image_begin, __image_end;
+extern char __ramdisk_begin[], __ramdisk_end;
+extern char _start, _end;
+
+extern unsigned int heap_max;
+extern void flush_cache(void *start, unsigned int len);
+extern void gunzip(void *, int, unsigned char *, int *);
+extern void make_bi_recs(unsigned long addr, char *name, unsigned int mach,
+		unsigned int progend);
+
+char *avail_ram;
+char *begin_avail, *end_avail;
+char *avail_high;
+
+
+#define RAM_END		(16 << 20)
+
+#define PROG_START	0x00010000
+#define PROG_SIZE	0x003f0000
+
+#define SCRATCH_SIZE	(128 << 10)
+
+typedef void (*kernel_start_t)(int, int, void *);
+
+void boot(int a1, int a2, void *prom)
+{
+    unsigned sa, len;
+    void *dst;
+    unsigned char *im;
+    unsigned initrd_start, initrd_size;
+    
+    printf("chrpboot starting: loaded at 0x%p\n", &_start);
+
+    initrd_size = (char *)(&__ramdisk_end) - (char *)(&__ramdisk_begin);
+    if (initrd_size) {
+	initrd_start = (RAM_END - initrd_size) & ~0xFFF;
+	a1 = initrd_start;
+	a2 = initrd_size;
+	claim(initrd_start, RAM_END - initrd_start, 0);
+	printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n\r",
+	       initrd_start, (char *)(&__ramdisk_begin), initrd_size);
+	memcpy((char *)initrd_start, (char *)(&__ramdisk_begin), initrd_size);
+    } else
+	a2 = 0xdeadbeef;
+
+    im = (char *)(&__image_begin);
+    len = (char *)(&__image_end) - (char *)(&__image_begin);
+    /* claim 3MB starting at PROG_START */
+    claim(PROG_START, PROG_SIZE, 0);
+    dst = (void *) PROG_START;
+    if (im[0] == 0x1f && im[1] == 0x8b) {
+	/* claim some memory for scratch space */
+	avail_ram = (char *) claim(0, SCRATCH_SIZE, 0x10);
+	begin_avail = avail_high = avail_ram;
+	end_avail = avail_ram + SCRATCH_SIZE;
+	printf("heap at 0x%p\n", avail_ram);
+	printf("gunzipping (0x%p <- 0x%p:0x%p)...", dst, im, im+len);
+	gunzip(dst, PROG_SIZE, im, &len);
+	printf("done %u bytes\n", len);
+	printf("%u bytes of heap consumed, max in use %u\n",
+	       avail_high - begin_avail, heap_max);
+	release(begin_avail, SCRATCH_SIZE);
+    } else {
+	memmove(dst, im, len);
+    }
+
+    flush_cache(dst, len);
+    make_bi_recs(((unsigned long) dst + len), "chrpboot", _MACH_Pmac,
+		    (PROG_START + PROG_SIZE));
+
+    sa = (unsigned long)PROG_START;
+    printf("start address = 0x%x\n", sa);
+
+    (*(kernel_start_t)sa)(a1, a2, prom);
+
+    printf("returned?\n");
+
+    pause();
+}
diff -Nru a/arch/ppc/boot/openfirmware/start.c b/arch/ppc/boot/openfirmware/start.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/boot/openfirmware/start.c	Fri Sep 20 08:20:47 2002
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) Paul Mackerras 1997.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <stdarg.h>
+#include "of1275.h"
+
+extern int strlen(const char *s);
+extern void boot(int a1, int a2, void *prom);
+
+phandle stdin;
+phandle stdout;
+phandle stderr;
+
+void printk(char *fmt, ...);
+
+void
+start(int a1, int a2, void *promptr)
+{
+    ofinit(promptr);
+    if (ofstdio(&stdin, &stdout, &stderr))
+	exit();
+
+    boot(a1, a2, promptr);
+    for (;;)
+	exit();
+}
+
+int writestring(void *f, char *ptr, int nb)
+{
+	int w = 0, i;
+	char *ret = "\r";
+
+	for (i = 0; i < nb; ++i) {
+		if (ptr[i] == '\n') {
+			if (i > w) {
+				write(f, ptr + w, i - w);
+				w = i;
+			}
+			write(f, ret, 1);
+		}
+	}
+	if (w < nb)
+		write(f, ptr + w, nb - w);
+	return nb;
+}
+
+int
+putc(int c, void *f)
+{
+    char ch = c;
+
+    return writestring(f, &ch, 1) == 1? c: -1;
+}
+
+int
+putchar(int c)
+{
+    return putc(c, stdout);
+}
+
+int
+fputs(char *str, void *f)
+{
+    int n = strlen(str);
+
+    return writestring(f, str, n) == n? 0: -1;
+}
+
+int
+readchar(void)
+{
+    char ch;
+
+    for (;;) {
+	switch (read(stdin, &ch, 1)) {
+	case 1:
+	    return ch;
+	case -1:
+	    printk("read(stdin) returned -1\n");
+	    return -1;
+	}
+    }
+}
+
+static char line[256];
+static char *lineptr;
+static int lineleft;
+
+int
+getchar(void)
+{
+    int c;
+
+    if (lineleft == 0) {
+	lineptr = line;
+	for (;;) {
+	    c = readchar();
+	    if (c == -1 || c == 4)
+		break;
+	    if (c == '\r' || c == '\n') {
+		*lineptr++ = '\n';
+		putchar('\n');
+		break;
+	    }
+	    switch (c) {
+	    case 0177:
+	    case '\b':
+		if (lineptr > line) {
+		    putchar('\b');
+		    putchar(' ');
+		    putchar('\b');
+		    --lineptr;
+		}
+		break;
+	    case 'U' & 0x1F:
+		while (lineptr > line) {
+		    putchar('\b');
+		    putchar(' ');
+		    putchar('\b');
+		    --lineptr;
+		}
+		break;
+	    default:
+		if (lineptr >= &line[sizeof(line) - 1])
+		    putchar('\a');
+		else {
+		    putchar(c);
+		    *lineptr++ = c;
+		}
+	    }
+	}
+	lineleft = lineptr - line;
+	lineptr = line;
+    }
+    if (lineleft == 0)
+	return -1;
+    --lineleft;
+    return *lineptr++;
+}
+
+extern int vsprintf(char *buf, const char *fmt, va_list args);
+static char sprint_buf[1024];
+
+void
+printk(char *fmt, ...)
+{
+	va_list args;
+	int n;
+
+	va_start(args, fmt);
+	n = vsprintf(sprint_buf, fmt, args);
+	va_end(args);
+	writestring(stdout, sprint_buf, n);
+}
+
+int
+printf(char *fmt, ...)
+{
+	va_list args;
+	int n;
+
+	va_start(args, fmt);
+	n = vsprintf(sprint_buf, fmt, args);
+	va_end(args);
+	writestring(stdout, sprint_buf, n);
+	return n;
+}
diff -Nru a/arch/ppc/boot/pmac/Makefile b/arch/ppc/boot/pmac/Makefile
--- a/arch/ppc/boot/pmac/Makefile	Fri Sep 20 08:20:44 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,112 +0,0 @@
-# BK Id: %F% %I% %G% %U% %#%
-#
-# Makefile for making XCOFF bootable images for booting on PowerMacs
-# using Open Firmware.
-#
-# Paul Mackerras	January 1997
-#
-# Cleaned up, moved into arch/ppc/boot/pmac
-# Tom Rini		January 2001
-
-OBJCOPY_ARGS = -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment
-COFF_LD_ARGS = -T ../ld.script -e _start -Ttext 0x00500000 -Bstatic
-CHRP_LD_ARGS = -T ../ld.script -Ttext 0x01000000
-
-COMMONOBJS = start.o misc.o ../common/string.o ../common/ofcommon.o
-COFFOBJS = ../common/coffcrt0.o $(COMMONOBJS) coffmain.o
-CHRPOBJS = ../common/crt0.o $(COMMONOBJS) chrpmain.o
-
-EXTRA_TARGETS	:= $(COFFOBJS) $(CHRPOBJS)
-LIBS = $(TOPDIR)/lib/lib.a ../lib/zlib.a
-
-MKNOTE := ../utils/mknote
-SIZE := ../utils/size
-OFFSET := ../utils/offset
-HACKCOFF := ../utils/hack-coff
-
-ifdef CONFIG_SMP
-END := .smp
-endif
-ifdef CONFIG_PPC64BRIDGE
-END += .64
-endif
-
-TFTPIMAGE=/tftpboot/zImage.pmac$(END)
-
-../common/coffcrt0.o:
-	$(MAKE) -C ../common coffcrt0.o
-
-image.o: ../images/vmlinux.gz ../common/dummy.o
-	$(OBJCOPY) ../common/dummy.o $@ -R .comment \
-		--add-section=.image=../images/vmlinux.gz \
-		--set-section-flags=.image=contents,alloc,load,readonly,data
-ifdef CONFIG_XMON
-	$(OBJCOPY) $@ $@ \
-		--add-section=.sysmap=$(TOPDIR)/System.map \
-		--set-section-flags=.sysmap=contents,alloc,load,readonly,data
-endif
-
-znetboot: vmlinux.coff vmlinux.elf-pmac zImage
-	cp ../images/vmlinux.coff $(TFTPIMAGE)
-	cp ../images/vmlinux.elf-pmac $(TFTPIMAGE).elf
-
-znetboot.initrd: vmlinux.initrd.coff vmlinux.initrd.elf-pmac
-	cp ../images/vmlinux.initrd.coff $(TFTPIMAGE)
-	cp ../images/vmlinux.initrd.elf-pmac $(TFTPIMAGE).elf
-
-miboot.image: ../common/dummy.o ../images/vmlinux.gz
-	$(OBJCOPY) $(OBJCOPY_ARGS) --add-section=image=../images/vmlinux.gz \
-		../common/dummy.o ../images/$@
-
-miboot.initrd.image: miboot.image ../images/ramdisk.image.gz
-	$(OBJCOPY) $(OBJCOPY_ARGS) --add-section=initrd=../images/ramdisk.image.gz \
-		../images/miboot.image ../images/$@
-
-coffboot: $(COFFOBJS) image.o $(LIBS) ../ld.script
-	$(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) image.o $(LIBS)
-	$(OBJCOPY) $@ $@ -R .comment
-
-coffboot.initrd: $(COFFOBJS) image.o $(LIBS) ../ld.script \
-		../images/ramdisk.image.gz
-	$(OBJCOPY) image.o image-coff.o \
-		--add-section=.ramdisk=../images/ramdisk.image.gz \
-		--set-section-flags=.ramdisk=contents,alloc,load,readonly,data
-	$(LD) -o $@ $(COFF_LD_ARGS) $(COFFOBJS) image-coff.o $(LIBS)
-	$(OBJCOPY) $@ $@ -R .comment
-	rm -f image-coff.o
-
-vmlinux.coff: coffboot $(HACKCOFF)
-	$(OBJCOPY) $(OBJCOPY_ARGS) coffboot ../images/$@
-	$(HACKCOFF) ../images/$@
-	rm -f coffboot
-	ln -sf vmlinux.coff ../images/zImage.pmac
-
-vmlinux.initrd.coff: coffboot.initrd $(HACKCOFF)
-	$(OBJCOPY) $(OBJCOPY_ARGS) coffboot.initrd ../images/$@
-	$(HACKCOFF) ../images/$@
-	rm -f coffboot.initrd
-	ln -sf vmlinux.initrd.coff ../images/zImage.initrd.pmac
-
-vmlinux.elf-pmac: $(CHRPOBJS) $(LIBS) $(MKNOTE) image.o
-	$(LD) $(CHRP_LD_ARGS) -o ../images/$@ $(CHRPOBJS) $(LIBS) image.o
-	$(MKNOTE) > note
-	$(OBJCOPY) ../images/$@ ../images/$@ --add-section=.note=note \
-		-R .comment -R .ramdisk
-	rm -f note
-
-vmlinux.initrd.elf-pmac: $(CHRPOBJS) $(LIBS) $(MKNOTE) image.o \
-		../images/ramdisk.image.gz
-	$(OBJCOPY) image.o image-elf.o \
-		--add-section=.ramdisk=../images/ramdisk.image.gz \
-		--set-section-flags=.ramdisk=contents,alloc,load,readonly,data
-	$(LD) $(CHRP_LD_ARGS) -o ../images/$@ $(CHRPOBJS) $(LIBS) image-elf.o
-	$(MKNOTE) > note
-	$(OBJCOPY) ../images/$@ ../images/$@ --add-section=.note=note \
-		-R .comment
-	rm -f note image-elf.o
-
-zImage: vmlinux.coff vmlinux.elf-pmac miboot.image
-
-zImage.initrd: vmlinux.initrd.coff vmlinux.initrd.elf-pmac miboot.initrd.image
-
-include $(TOPDIR)/Rules.make
diff -Nru a/arch/ppc/boot/pmac/chrpmain.c b/arch/ppc/boot/pmac/chrpmain.c
--- a/arch/ppc/boot/pmac/chrpmain.c	Fri Sep 20 08:20:41 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,100 +0,0 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- * Copyright (C) Paul Mackerras 1997.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include "nonstdio.h"
-#include <asm/processor.h>
-#include <asm/page.h>
-
-/* Passed from the linker */
-extern char __image_begin, __image_end;
-extern char __ramdisk_begin[], __ramdisk_end;
-extern char _start, _end;
-
-extern int getprop(void *, const char *, void *, int);
-extern unsigned int heap_max;
-extern void *claim(unsigned int virt, unsigned int size, unsigned int align);
-extern void *finddevice(const char *);
-extern void flush_cache(void *start, unsigned int len);
-extern void gunzip(void *, int, unsigned char *, int *);
-extern void make_bi_recs(unsigned long addr, char *name, unsigned int mach,
-		unsigned int progend);
-extern void pause(void);
-extern void release(void *ptr, unsigned int len);
-
-char *avail_ram;
-char *begin_avail, *end_avail;
-char *avail_high;
-
-
-#define RAM_END		(16 << 20)
-
-#define PROG_START	0x00010000
-#define PROG_SIZE	0x003f0000
-
-#define SCRATCH_SIZE	(128 << 10)
-
-typedef void (*kernel_start_t)(int, int, void *);
-
-void boot(int a1, int a2, void *prom)
-{
-    unsigned sa, len;
-    void *dst;
-    unsigned char *im;
-    unsigned initrd_start, initrd_size;
-    
-    printf("chrpboot starting: loaded at 0x%p\n", &_start);
-
-    initrd_size = (char *)(&__ramdisk_end) - (char *)(&__ramdisk_begin);
-    if (initrd_size) {
-	initrd_start = (RAM_END - initrd_size) & ~0xFFF;
-	a1 = initrd_start;
-	a2 = initrd_size;
-	claim(initrd_start, RAM_END - initrd_start, 0);
-	printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n\r",
-	       initrd_start, (char *)(&__ramdisk_begin), initrd_size);
-	memcpy((char *)initrd_start, (char *)(&__ramdisk_begin), initrd_size);
-    } else
-	a2 = 0xdeadbeef;
-
-    im = (char *)(&__image_begin);
-    len = (char *)(&__image_end) - (char *)(&__image_begin);
-    /* claim 3MB starting at PROG_START */
-    claim(PROG_START, PROG_SIZE, 0);
-    dst = (void *) PROG_START;
-    if (im[0] == 0x1f && im[1] == 0x8b) {
-	/* claim some memory for scratch space */
-	avail_ram = (char *) claim(0, SCRATCH_SIZE, 0x10);
-	begin_avail = avail_high = avail_ram;
-	end_avail = avail_ram + SCRATCH_SIZE;
-	printf("heap at 0x%p\n", avail_ram);
-	printf("gunzipping (0x%p <- 0x%p:0x%p)...", dst, im, im+len);
-	gunzip(dst, PROG_SIZE, im, &len);
-	printf("done %u bytes\n", len);
-	printf("%u bytes of heap consumed, max in use %u\n",
-	       avail_high - begin_avail, heap_max);
-	release(begin_avail, SCRATCH_SIZE);
-    } else {
-	memmove(dst, im, len);
-    }
-
-    flush_cache(dst, len);
-    make_bi_recs(((unsigned long) dst + len), "chrpboot", _MACH_Pmac,
-		    (PROG_START + PROG_SIZE));
-
-    sa = (unsigned long)PROG_START;
-    printf("start address = 0x%x\n", sa);
-
-    (*(kernel_start_t)sa)(a1, a2, prom);
-
-    printf("returned?\n");
-
-    pause();
-}
diff -Nru a/arch/ppc/boot/pmac/coffmain.c b/arch/ppc/boot/pmac/coffmain.c
--- a/arch/ppc/boot/pmac/coffmain.c	Fri Sep 20 08:20:46 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,105 +0,0 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- * Copyright (C) Paul Mackerras 1997.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <asm/processor.h>
-#include <asm/page.h>
-
-#include "nonstdio.h"
-#include "zlib.h"
-
-/* Passed from the linker */
-extern char __image_begin, __image_end;
-extern char __ramdisk_begin[], __ramdisk_end;
-extern char _start, _end;
-
-extern char *claim(unsigned, unsigned, unsigned);
-extern char image_data[], initrd_data[];
-extern int initrd_len, image_len;
-extern int getprop(void *, const char *, void *, int);
-extern unsigned int heap_max;
-extern void *finddevice(const char *);
-extern void flush_cache(void *start, unsigned int len);
-extern void gunzip(void *, int, unsigned char *, int *);
-extern void make_bi_recs(unsigned long addr, char *name, unsigned int mach,
-		unsigned int progend);
-extern void pause(void);
-extern void setup_bats(unsigned long start);
-
-char *avail_ram;
-char *begin_avail, *end_avail;
-char *avail_high;
-
-#define RAM_START	0
-#define RAM_END		(RAM_START + 0x800000)	/* only 8M mapped with BATs */
-
-#define PROG_START	RAM_START
-#define PROG_SIZE	0x00400000
-
-#define SCRATCH_SIZE	(128 << 10)
-
-static char heap[SCRATCH_SIZE];
-
-typedef void (*kernel_start_t)(int, int, void *);
-
-void boot(int a1, int a2, void *prom)
-{
-    unsigned sa, len;
-    void *dst;
-    unsigned char *im;
-    unsigned initrd_start, initrd_size;
-    
-    printf("coffboot starting: loaded at 0x%p\n", &_start);
-    setup_bats(RAM_START);
-
-    initrd_size = (char *)(&__ramdisk_end) - (char *)(&__ramdisk_begin);
-    if (initrd_size) {
-	initrd_start = (RAM_END - initrd_size) & ~0xFFF;
-	a1 = initrd_start;
-	a2 = initrd_size;
-	claim(initrd_start, RAM_END - initrd_start, 0);
-	printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n\r",
-	       initrd_start, (char *)(&__ramdisk_begin), initrd_size);
-	memcpy((char *)initrd_start, (char *)(&__ramdisk_begin), initrd_size);
-    } else
-	a2 = 0xdeadbeef;
-
-    im = (char *)(&__image_begin);
-    len = (char *)(&__image_end) - (char *)(&__image_begin);
-    /* claim 4MB starting at 0 */
-    claim(0, PROG_SIZE, 0);
-    dst = (void *) RAM_START;
-    if (im[0] == 0x1f && im[1] == 0x8b) {
-	/* set up scratch space */
-	begin_avail = avail_high = avail_ram = heap;
-	end_avail = heap + sizeof(heap);
-	printf("heap at 0x%p\n", avail_ram);
-	printf("gunzipping (0x%p <- 0x%p:0x%p)...", dst, im, im+len);
-	gunzip(dst, PROG_SIZE, im, &len);
-	printf("done %u bytes\n", len);
-	printf("%u bytes of heap consumed, max in use %u\n",
-	       avail_high - begin_avail, heap_max);
-    } else {
-	memmove(dst, im, len);
-    }
-
-    flush_cache(dst, len);
-    make_bi_recs(((unsigned long) dst + len), "coffboot", _MACH_Pmac,
-		    (PROG_START + PROG_SIZE));
-
-    sa = (unsigned long)PROG_START;
-    printf("start address = 0x%x\n", sa);
-
-    (*(kernel_start_t)sa)(a1, a2, prom);
-
-    printf("returned?\n");
-
-    pause();
-}
diff -Nru a/arch/ppc/boot/pmac/misc.S b/arch/ppc/boot/pmac/misc.S
--- a/arch/ppc/boot/pmac/misc.S	Fri Sep 20 08:20:47 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,60 +0,0 @@
-/*
- * BK Id: SCCS/s.misc.S 1.6 05/18/01 15:17:15 cort
- */
-/*
- * Copyright (C) Paul Mackerras 1997.
- *
- * 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.
- */
-	.text
-
-/*
- * Use the BAT3 registers to map the 1st 8MB of RAM to
- * the address given as the 1st argument.
- */
-	.globl	setup_bats
-setup_bats:
-	mfpvr	5
-	rlwinm	5,5,16,16,31		/* r3 = 1 for 601, 4 for 604 */
-	cmpi	0,5,1
-	li	0,0
-	bne	4f
-	mtibatl	3,0			/* invalidate BAT first */
-	ori	3,3,4			/* set up BAT registers for 601 */
-	li	4,0x7f
-	mtibatu	3,3
-	mtibatl	3,4
-	b	5f
-4:	mtdbatu	3,0			/* invalidate BATs first */
-	mtibatu	3,0
-	ori	3,3,0xff		/* set up BAT registers for 604 */
-	li	4,2
-	mtdbatl	3,4
-	mtdbatu	3,3
-	mtibatl	3,4
-	mtibatu	3,3
-5:	sync
-	isync
-	blr
-
-/*
- * Flush the dcache and invalidate the icache for a range of addresses.
- *
- * flush_cache(addr, len)
- */
-	.global	flush_cache
-flush_cache:
-	addi	4,4,0x1f	/* len = (len + 0x1f) / 0x20 */
-	rlwinm.	4,4,27,5,31
-	mtctr	4
-	beqlr
-1:	dcbf	0,3
-	icbi	0,3
-	addi	3,3,0x20
-	bdnz	1b
-	sync
-	isync
-	blr
diff -Nru a/arch/ppc/boot/pmac/start.c b/arch/ppc/boot/pmac/start.c
--- a/arch/ppc/boot/pmac/start.c	Fri Sep 20 08:20:47 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,346 +0,0 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- * Copyright (C) Paul Mackerras 1997.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <stdarg.h>
-
-extern int strlen(const char *s);
-extern void boot(int a1, int a2, void *prom);
-
-int (*prom)(void *);
-
-void *chosen_handle;
-void *stdin;
-void *stdout;
-void *stderr;
-
-void exit(void);
-void *finddevice(const char *name);
-int getprop(void *phandle, const char *name, void *buf, int buflen);
-void printk(char *fmt, ...);
-
-void
-start(int a1, int a2, void *promptr)
-{
-    prom = (int (*)(void *)) promptr;
-    chosen_handle = finddevice("/chosen");
-    if (chosen_handle == (void *) -1)
-	exit();
-    if (getprop(chosen_handle, "stdout", &stdout, sizeof(stdout)) != 4)
-	exit();
-    stderr = stdout;
-    if (getprop(chosen_handle, "stdin", &stdin, sizeof(stdin)) != 4)
-	exit();
-
-    boot(a1, a2, promptr);
-    for (;;)
-	exit();
-}
-
-int
-write(void *handle, void *ptr, int nb)
-{
-    struct prom_args {
-	char *service;
-	int nargs;
-	int nret;
-	void *ihandle;
-	void *addr;
-	int len;
-	int actual;
-    } args;
-
-    args.service = "write";
-    args.nargs = 3;
-    args.nret = 1;
-    args.ihandle = handle;
-    args.addr = ptr;
-    args.len = nb;
-    args.actual = -1;
-    (*prom)(&args);
-    return args.actual;
-}
-
-int writestring(void *f, char *ptr, int nb)
-{
-	int w = 0, i;
-	char *ret = "\r";
-
-	for (i = 0; i < nb; ++i) {
-		if (ptr[i] == '\n') {
-			if (i > w) {
-				write(f, ptr + w, i - w);
-				w = i;
-			}
-			write(f, ret, 1);
-		}
-	}
-	if (w < nb)
-		write(f, ptr + w, nb - w);
-	return nb;
-}
-
-int
-read(void *handle, void *ptr, int nb)
-{
-    struct prom_args {
-	char *service;
-	int nargs;
-	int nret;
-	void *ihandle;
-	void *addr;
-	int len;
-	int actual;
-    } args;
-
-    args.service = "read";
-    args.nargs = 3;
-    args.nret = 1;
-    args.ihandle = handle;
-    args.addr = ptr;
-    args.len = nb;
-    args.actual = -1;
-    (*prom)(&args);
-    return args.actual;
-}
-
-void
-exit(void)
-{
-    struct prom_args {
-	char *service;
-    } args;
-
-    for (;;) {
-	args.service = "exit";
-	(*prom)(&args);
-    }
-}
-
-void
-pause(void)
-{
-    struct prom_args {
-	char *service;
-    } args;
-
-    args.service = "enter";
-    (*prom)(&args);
-}
-
-void *
-finddevice(const char *name)
-{
-    struct prom_args {
-	char *service;
-	int nargs;
-	int nret;
-	const char *devspec;
-	void *phandle;
-    } args;
-
-    args.service = "finddevice";
-    args.nargs = 1;
-    args.nret = 1;
-    args.devspec = name;
-    args.phandle = (void *) -1;
-    (*prom)(&args);
-    return args.phandle;
-}
-
-void *
-claim(unsigned int virt, unsigned int size, unsigned int align)
-{
-    struct prom_args {
-	char *service;
-	int nargs;
-	int nret;
-	unsigned int virt;
-	unsigned int size;
-	unsigned int align;
-	void *ret;
-    } args;
-
-    args.service = "claim";
-    args.nargs = 3;
-    args.nret = 1;
-    args.virt = virt;
-    args.size = size;
-    args.align = align;
-    (*prom)(&args);
-    return args.ret;
-}
-
-void
-release(void *virt, unsigned int size)
-{
-    struct prom_args {
-	char *service;
-	int nargs;
-	int nret;
-	void *virt;
-	unsigned int size;
-    } args;
-
-    args.service = "release";
-    args.nargs = 2;
-    args.nret = 0;
-    args.virt = virt;
-    args.size = size;
-    (*prom)(&args);
-}
-
-int
-getprop(void *phandle, const char *name, void *buf, int buflen)
-{
-    struct prom_args {
-	char *service;
-	int nargs;
-	int nret;
-	void *phandle;
-	const char *name;
-	void *buf;
-	int buflen;
-	int size;
-    } args;
-
-    args.service = "getprop";
-    args.nargs = 4;
-    args.nret = 1;
-    args.phandle = phandle;
-    args.name = name;
-    args.buf = buf;
-    args.buflen = buflen;
-    args.size = -1;
-    (*prom)(&args);
-    return args.size;
-}
-
-int
-putc(int c, void *f)
-{
-    char ch = c;
-
-    return writestring(f, &ch, 1) == 1? c: -1;
-}
-
-int
-putchar(int c)
-{
-    return putc(c, stdout);
-}
-
-int
-fputs(char *str, void *f)
-{
-    int n = strlen(str);
-
-    return writestring(f, str, n) == n? 0: -1;
-}
-
-int
-readchar(void)
-{
-    char ch;
-
-    for (;;) {
-	switch (read(stdin, &ch, 1)) {
-	case 1:
-	    return ch;
-	case -1:
-	    printk("read(stdin) returned -1\n");
-	    return -1;
-	}
-    }
-}
-
-static char line[256];
-static char *lineptr;
-static int lineleft;
-
-int
-getchar(void)
-{
-    int c;
-
-    if (lineleft == 0) {
-	lineptr = line;
-	for (;;) {
-	    c = readchar();
-	    if (c == -1 || c == 4)
-		break;
-	    if (c == '\r' || c == '\n') {
-		*lineptr++ = '\n';
-		putchar('\n');
-		break;
-	    }
-	    switch (c) {
-	    case 0177:
-	    case '\b':
-		if (lineptr > line) {
-		    putchar('\b');
-		    putchar(' ');
-		    putchar('\b');
-		    --lineptr;
-		}
-		break;
-	    case 'U' & 0x1F:
-		while (lineptr > line) {
-		    putchar('\b');
-		    putchar(' ');
-		    putchar('\b');
-		    --lineptr;
-		}
-		break;
-	    default:
-		if (lineptr >= &line[sizeof(line) - 1])
-		    putchar('\a');
-		else {
-		    putchar(c);
-		    *lineptr++ = c;
-		}
-	    }
-	}
-	lineleft = lineptr - line;
-	lineptr = line;
-    }
-    if (lineleft == 0)
-	return -1;
-    --lineleft;
-    return *lineptr++;
-}
-
-extern int vsprintf(char *buf, const char *fmt, va_list args);
-static char sprint_buf[1024];
-
-void
-printk(char *fmt, ...)
-{
-	va_list args;
-	int n;
-
-	va_start(args, fmt);
-	n = vsprintf(sprint_buf, fmt, args);
-	va_end(args);
-	writestring(stdout, sprint_buf, n);
-}
-
-int
-printf(char *fmt, ...)
-{
-	va_list args;
-	int n;
-
-	va_start(args, fmt);
-	n = vsprintf(sprint_buf, fmt, args);
-	va_end(args);
-	writestring(stdout, sprint_buf, n);
-	return n;
-}
diff -Nru a/arch/ppc/boot/prep/Makefile b/arch/ppc/boot/prep/Makefile
--- a/arch/ppc/boot/prep/Makefile	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/boot/prep/Makefile	Fri Sep 20 08:20:47 2002
@@ -1,5 +1,3 @@
-# BK Id: %F% %I% %G% %U% %#%
-#
 # arch/ppc/boot/Makefile
 #
 # This file is subject to the terms and conditions of the GNU General Public
@@ -21,13 +19,14 @@
 endif
 
 LD_ARGS				= -T ../ld.script -Ttext 0x00800000 -Bstatic
-boot-y				:= head.o ../simple/legacy.o misc.o of1275.o \
+boot-y				:= head.o ../simple/legacy.o misc.o \
 					../common/util.o ../common/string.o \
-					../common/misc-common.o
+					../common/misc-common.o \
+					../common/mpc10x_memory.o
 OBJCOPY_ARGS			= -O elf32-powerpc
 LIBS 				= ../lib/zlib.a
 
-boot-$($CONFIG_SERIAL_8250_CONSOLE) += ../common/ns16550.o
+boot-$(CONFIG_SERIAL_8250_CONSOLE) += ../common/ns16550.o
 boot-$(CONFIG_VGA_CONSOLE)	+= vreset.o kbd.o
 
 EXTRA_TARGETS			:= $(boot-y)
diff -Nru a/arch/ppc/boot/prep/head.S b/arch/ppc/boot/prep/head.S
--- a/arch/ppc/boot/prep/head.S	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc/boot/prep/head.S	Fri Sep 20 08:20:43 2002
@@ -1,7 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
 #include <asm/ppc_asm.h>
 #include <asm/processor.h>
 #include <asm/cache.h>
@@ -38,10 +34,6 @@
 	isync
 
 	mr	r11,r3		/* Save pointer to residual/board data */
-	mr      r25,r5		/* Save OFW pointer */
-
-	/* Save the original MSR value */
-	mfmsr	r26
 
 	/* Establish default MSR value */
 	li	r3,MSR_IP|MSR_FP
@@ -114,17 +106,11 @@
 	li	r2,0x000F		/* Mask pointer to 16-byte boundary */
 	andc	r1,r1,r2
 
-	/* Store the original MSR into 'orig_MSR' */
-	lis	r3,orig_MSR@h
-	ori	r3,r3,orig_MSR@l
-	stw	r26,0(r3)
-
 /* Run loader */
 	mr	r3,r8			/* Load point */
 	mr	r4,r7			/* Program length */
 	mr	r5,r6			/* Checksum */
 	mr	r6,r11			/* Residual data */
-	mr      r7,r25                  /* OFW interfaces */
 	bl	decompress_kernel
 
 	/*
diff -Nru a/arch/ppc/boot/prep/iso_font.h b/arch/ppc/boot/prep/iso_font.h
--- a/arch/ppc/boot/prep/iso_font.h	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/boot/prep/iso_font.h	Fri Sep 20 08:20:46 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.iso_font.h 1.6 05/18/01 15:16:42 cort
- */
 static const unsigned char font[] = {
 /* 0x00 */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 /* 0x01 */ 0x00,0x00,0x7E,0x81,0xA5,0x81,0x81,0xBD,0x99,0x81,0x81,0x7E,0x00,0x00,0x00,0x00,
diff -Nru a/arch/ppc/boot/prep/kbd.c b/arch/ppc/boot/prep/kbd.c
--- a/arch/ppc/boot/prep/kbd.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/boot/prep/kbd.c	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
 #include <linux/keyboard.h>
 
 #include "defkeymap.c"	/* yeah I know it's bad -- Cort */
diff -Nru a/arch/ppc/boot/prep/misc.c b/arch/ppc/boot/prep/misc.c
--- a/arch/ppc/boot/prep/misc.c	Fri Sep 20 08:20:42 2002
+++ b/arch/ppc/boot/prep/misc.c	Fri Sep 20 08:20:42 2002
@@ -1,6 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- *
  * arch/ppc/boot/prep/misc.c
  *
  * Adapted for PowerPC by Gary Thomas
@@ -20,6 +18,7 @@
 #include <asm/bootinfo.h>
 #include <asm/mmu.h>
 #include <asm/byteorder.h>
+
 #include "nonstdio.h"
 #include "zlib.h"
 
@@ -51,7 +50,6 @@
 RESIDUAL hold_resid_buf;
 RESIDUAL *hold_residual = &hold_resid_buf;
 unsigned long initrd_size = 0;
-unsigned long orig_MSR;
 
 char *zimage_start;
 int zimage_size;
@@ -66,16 +64,11 @@
 #endif /* CONFIG_VGA_CONSOLE */
 
 extern int CRT_tstc(void);
-extern void of_init(void *handler);
-extern int of_finddevice(const char *device_specifier, int *phandle);
-extern int of_getprop(int phandle, const char *name, void *buf, int buflen,
-		int *size);
 extern int vga_init(unsigned char *ISA_mem);
 extern void gunzip(void *, int, unsigned char *, int *);
-
-extern void _put_MSR(unsigned int val);
 extern unsigned long serial_init(int chan, void *ignored);
 extern void serial_fixups(void);
+extern unsigned long get_mem_size(void);
 
 void
 writel(unsigned int val, unsigned int address)
@@ -120,15 +113,12 @@
 
 unsigned long
 decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum,
-		  RESIDUAL *residual, void *OFW_interface)
+		  RESIDUAL *residual)
 {
 	int timer = 0;
 	extern unsigned long start;
 	char *cp, ch;
 	unsigned long TotalMemory;
-	int dev_handle;
-	int mem_info[2];
-	int res, size;
 	unsigned char board_type;
 	unsigned char base_mod;
 	int start_multi = 0;
@@ -142,6 +132,11 @@
 	vga_init((unsigned char *)0xC0000000);
 #endif /* CONFIG_VGA_CONSOLE */
 
+	/* 
+	 * Find out how much memory we have.
+	 */
+	TotalMemory = get_mem_size();
+
 	/*
 	 * Tell the user where we were loaded at and where we were relocated
 	 * to for debugging this process.
@@ -218,47 +213,6 @@
 	} else {
 		/* Tell the user we didn't find anything. */
 		puts("No residual data found.\n");
-
-		/* Assume 32M in the absence of more info... */
-		TotalMemory = 0x02000000;
-
-		/*
-		 * This is a 'best guess' check.  We want to make sure
-		 * we don't try this on a PReP box without OF
-		 *     -- Cort
-		 */
-		while (OFW_interface && ((unsigned long)OFW_interface < 0x10000000) )
-		{
-			/* We need to restore the slightly inaccurate
-			 * MSR so that OpenFirmware will behave. -- Tom
-			 */
-			_put_MSR(orig_MSR);
-			of_init(OFW_interface);
-
-			/* get handle to memory description */
-			res = of_finddevice("/memory@0",
-					    &dev_handle);
-			if (res)
-				break;
-
-			/* get the info */
-			res = of_getprop(dev_handle,
-					 "reg",
-					 mem_info,
-					 sizeof(mem_info),
-					 &size);
-			if (res)
-				break;
-
-			TotalMemory = mem_info[1];
-			break;
-		}
-
-		hold_residual->TotalMemory = TotalMemory;
-		residual = hold_residual;
-
-		/* Enforce a sane MSR for booting. */
-		_put_MSR(MSR_IP);
         }
 
 	/* assume the chunk below 8M is free */
@@ -361,6 +315,11 @@
 		rec->data[1] = 0;
 		rec->size = sizeof(struct bi_record) + 2 *
 			sizeof(unsigned long);
+		rec = (struct bi_record *)((unsigned long)rec + rec->size);
+
+		rec->tag = BI_MEMSIZE;
+		rec->data[0] = TotalMemory;
+		rec->size = sizeof(struct bi_record) + sizeof(unsigned long);
 		rec = (struct bi_record *)((unsigned long)rec + rec->size);
 
 		rec->tag = BI_CMD_LINE;
diff -Nru a/arch/ppc/boot/prep/of1275.c b/arch/ppc/boot/prep/of1275.c
--- a/arch/ppc/boot/prep/of1275.c	Fri Sep 20 08:20:45 2002
+++ b/arch/ppc/boot/prep/of1275.c	Fri Sep 20 08:20:45 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.of1275.c 1.6 05/18/01 15:16:42 cort
- */
 /* Open Firmware Client Interface */
 
 
diff -Nru a/arch/ppc/boot/prep/of1275.h b/arch/ppc/boot/prep/of1275.h
--- a/arch/ppc/boot/prep/of1275.h	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/boot/prep/of1275.h	Fri Sep 20 08:20:44 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.of1275.h 1.6 05/18/01 15:16:42 cort
- */
 /* 6.3.2.1 Client interface */
 
 
diff -Nru a/arch/ppc/boot/prep/vreset.c b/arch/ppc/boot/prep/vreset.c
--- a/arch/ppc/boot/prep/vreset.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/boot/prep/vreset.c	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * vreset.c
  *
  * Initialize the VGA control registers to 80x25 text mode.
diff -Nru a/arch/ppc/boot/simple/Makefile b/arch/ppc/boot/simple/Makefile
--- a/arch/ppc/boot/simple/Makefile	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/boot/simple/Makefile	Fri Sep 20 08:20:41 2002
@@ -3,11 +3,21 @@
 #
 # Author: Tom Rini <trini@mvista.com>
 #
-# Copyright 2001 MontaVista Software Inc.
+# Copyright 2001-2002 MontaVista Software Inc.
 #
-# Notes: For machine targets which produce more than one image, define
+# Notes:
+# (1) For machine targets which produce more than one image, define
 # ZNETBOOT and ZNETBOOTRD to the image which should be available for
 # 'znetboot' and 'znetboot.initrd`
+# (2) Also, for machine targets which just need to remove the ELF header,
+# define END to be the machine name you want in the image.
+# (3) For machine targets which use the mktree program, define END to be
+# the machine name you want in the image, and you can optionally set
+# ENTRYPOINT which the image should be loaded at.  The optimal setting
+# for ENTRYPOINT is the link address.
+# (4) It is advisable to pass in the memory size using BI_MEMSIZE and
+# get_mem_size(), which is memory controller dependant.  Add in the correct
+# XXX_memory.o file for this to work, as well as editing the $(MISC) file.
 #
 # 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
@@ -17,40 +27,36 @@
 # Normally, we use the 'misc-simple.c' file for decompress_kernel and
 # whatnot.  Sometimes we need to override this however.
 MISC				:= ../common/misc-simple.o
-ifeq ($(CONFIG_TREEBOOT),y)
+ifeq ($(CONFIG_IBM_OPENBIOS),y)
 ZIMAGE				:= zImage-TREE
 ZIMAGEINITRD			:= zImage.initrd-TREE
-TFTPIMAGE			:= /tftpboot/zImage.embedded
+END				:= treeboot
+TFTPIMAGE			:= /tftpboot/zImage.$(END)
 MISC				:= misc-embedded.o
 endif
 ifeq ($(CONFIG_EMBEDDEDBOOT),y)
-ZIMAGE				:= zImage-EMBEDDED
-ZIMAGEINITRD			:= zImage.initrd-EMBEDDED
 TFTPIMAGE			:= /tftpboot/zImage.embedded
 MISC				:= misc-embedded.o
 endif
 ifeq ($(CONFIG_EV64260),y)
-ZIMAGE				:= zImage-EV64260
-ZIMAGEINITRD			:= zImage.initrd-EV64260
-HEADHELP			:= direct.o misc-ev64260.o
+EXTRA				:= direct.o misc-ev64260.o
 TFTPIMAGE			:= /tftpboot/zImage.ev64260
 endif
 ifeq ($(CONFIG_GEMINI),y)
-ZIMAGE				:= zImage-SMON
-ZIMAGEINITRD			:= zImage.initrd-SMON
-HEADHELP			:= direct.o
-TFTPIMAGE			:= /tftpboot/zImage.gemini
+ZIMAGE				:= zImage-STRIPELF
+ZIMAGEINITRD			:= zImage.initrd-STRIPELF
+EXTRA				:= direct.o
+END				:= gemini
+TFTPIMAGE			:= /tftpboot/zImage.$(END)
 endif
 ifeq ($(CONFIG_MENF1),y)
 ZIMAGE				:= zImage-MENF1
 ZIMAGEINITRD			:= zImage.initrd-MENF1
-HEADHELP			:= chrpmap.o
+EXTRA				:= chrpmap.o
 TFTPIMAGE			:= /tftpboot/zImage.menf1
 endif
 ifeq ($(CONFIG_K2),y)
-ZIMAGE				:= zImage-K2
-ZIMAGEINITRD			:= zImage.initrd-K2
-HEADHELP			:= legacy.o
+EXTRA				:= legacy.o
 TFTPIMAGE			:= /tftpboot/zImage.k2
 endif
 # kbuild-2.4 'feature', only one of these will ever by 'y' at a time.
@@ -58,45 +64,50 @@
 ifeq ($(CONFIG_MCPN765)$(CONFIG_MVME5100)$(CONFIG_PRPMC750)$(CONFIG_PRPMC800)$(CONFIG_LOPEC)$(CONFIG_PPLUS),y)
 ZIMAGE				:= zImage-PPLUS
 ZIMAGEINITRD			:= zImage.initrd-PPLUS
-HEADHELP			:= direct.o
+EXTRA				:= direct.o
 TFTPIMAGE			:= /tftpboot/zImage.pplus
 ZNETBOOT			:= zImage.pplus
 ZNETBOOTRD			:= zImage.initrd.pplus
 endif
 ifeq ($(CONFIG_PPLUS),y)
-HEADHELP			:= legacy.o
+EXTRA				:= legacy.o
+endif
+ifeq ($(CONFIG_LOPEC),y)
+EXTRA				+= ../common/mpc10x_memory.o
+endif
+ifeq ($(CONFIG_PAL4),y)
+EXTRA				:= direct.o ../common/cpc700_memory.o
 endif
-ifeq ($(CONFIG_PCORE),y)
-ZIMAGE				:= zImage-PCORE
-ZIMAGEINITRD			:= zImage.initrd-PCORE
-HEADHELP			:= chrpmap.o
-TFTPIMAGE			:= /tftpboot/zImage.pcore
+ifeq ($(CONFIG_PCORE)$(CONFIG_POWERPMC250),y)
+ZIMAGE				:= zImage-STRIPELF
+ZIMAGEINITRD			:= zImage.initrd-STRIPELF
+EXTRA				:= chrpmap.o
+END				:= pcore
+TFTPIMAGE			:= /tftpboot/zImage.$(END)
 endif
-#Ugh, should come up with a better nameing convention..
+# The PowerPMC 250 needs the dummy serial_fixups()
 ifeq ($(CONFIG_POWERPMC250),y)
-ZIMAGE				:= zImage-PCORE
-ZIMAGEINITRD			:= zImage.initrd-PCORE
-HEADHELP			:= direct.o
-TFTPIMAGE			:= /tftpboot/zImage.pcore
+EXTRA				:= direct.o
 endif
 ifeq ($(CONFIG_SANDPOINT),y)
-ZIMAGE				:= zImage-SP
-ZIMAGEINITRD			:= zImage.initrd-SP
-HEADHELP			:= direct.o
+EXTRA				:= direct.o
 TFTPIMAGE			:= /tftpboot/zImage.sandpoint
 endif
 ifeq ($(CONFIG_SPRUCE),y)
-ZIMAGE				:= zImage-SPRUCE
-ZIMAGEINITRD			:= zImage.initrd-SPRUCE
-HEADHELP			:= direct.o
+ZIMAGE				:= zImage-TREE
+ZIMAGEINITRD			:= zImage.initrd-TREE
+EXTRA				:= direct.o
+END				:= spruce
+ENTRYPOINT			:= 0x00800000
 MISC				:= misc-spruce.o
-TFTPIMAGE			:= /tftpboot/zImage.spruce
+TFTPIMAGE			:= /tftpboot/zImage.$(END)
 endif
 ifeq ($(CONFIG_ZX4500),y)
-ZIMAGE				:= zImage-ZX4500
-ZIMAGEINITRD			:= zImage.initrd-ZX4500
-HEADHELP			:= direct.o
-TFTPIMAGE			:= /tftpboot/zImage.zx4500
+ZIMAGE				:= zImage-STRIPELF
+ZIMAGEINITRD			:= zImage.initrd-STRIPELF
+EXTRA				:= direct.o
+END				:= zx4500
+TFTPIMAGE			:= /tftpboot/zImage.$(END)
 endif
 ifeq ($(CONFIG_SMP),y)
 TFTPIMAGE			+= .smp
@@ -105,7 +116,7 @@
 # This is a treeboot that needs init functions until the
 # boot rom is sorted out (i.e. this is short lived)
 EXTRA_AFLAGS			:= -Wa,-m405
-HEADHELP			:= rw4/rw4_init.o rw4/rw4_init_brd.o
+EXTRA				:= rw4/rw4_init.o rw4/rw4_init_brd.o
 endif
 
 # Default linker args.  Link at 0x00800000 or 0x00400000 by default, but
@@ -122,7 +133,7 @@
 OBJCOPY_ARGS			:= -O elf32-powerpc
 
 # head.o and ../common/relocate.o must be at the start.
-boot-y				:= head.o ../common/relocate.o $(HEADHELP) \
+boot-y				:= head.o ../common/relocate.o $(EXTRA) \
 				$(MISC) ../common/misc-common.o \
 				../common/string.o ../common/util.o
 boot-$(CONFIG_4xx)		+= embed_config.o
@@ -170,9 +181,12 @@
 		-R .sysmap
 
 # Sort-of dummy rules, that let us format the image we want.
-zImage: $(ZIMAGE)
+zImage: $(ZIMAGE) zvmlinux
+	cp -f zvmlinux ../images/zImage.elf
 	rm -f zvmlinux
-zImage.initrd: $(ZIMAGEINITRD)
+
+zImage.initrd: $(ZIMAGEINITRD) zvmlinux.initrd
+	cp -f zvmlinux.initrd ../images/zImage.initrd.elf
 	rm -f zvmlinux.initrd
 
 znetboot: zImage
@@ -189,23 +203,17 @@
 	cp ../images/zImage.* $(TFTPIMAGE)
 endif
 
-zImage-EMBEDDED: zvmlinux
-	mv zvmlinux ../images/zImage.embedded
+zImage-STRIPELF: zvmlinux
+	dd if=zvmlinux of=../images/zImage.$(END) skip=64 bs=1k
 
-zImage.initrd-EMBEDDED: zvmlinux.initrd
-	mv zvmlinux.initrd ../images/zImage.initrd.embedded
+zImage.initrd-STRIPELF: zvmlinux.initrd
+	dd if=zvmlinux.initrd of=../images/zImage.initrd.$(END) skip=64 bs=1k
 
-zImage-K2: zvmlinux 
-	mv zvmlinux ../images/zImage.k2
-
-zImage.initrd-K2: zvmlinux.initrd 
-	mv zvmlinux.initrd ../images/zImage.initrd.k2
-
-zImage-EV64260: zvmlinux
-	mv zvmlinux ../images/zImage.ev64260
+zImage-TREE: zvmlinux
+	$(MKTREE) zvmlinux ../images/zImage.$(END) $(ENTRYPOINT)
 
-zImage.initrd-EV64260: zvmlinux.initrd
-	mv zvmlinux.initrd ../images/zImage.initrd.ev64260
+zImage.initrd-TREE: zvmlinux.initrd
+	$(MKTREE) zvmlinux.initrd ../images/zImage.initrd.$(END) $(ENTRYPOINT)
 
 zImage-MENF1: zvmlinux
 	$(MKPREP) -pbp zvmlinux ../images/zImage.menf1
@@ -213,12 +221,6 @@
 zImage.initrd-MENF1: zvmlinux.initrd
 	$(MKPREP) -pbp zvmlinux.initrd ../images/zImage.initrd.menf1
 
-zImage-PCORE: zvmlinux
-	dd if=zvmlinux of=../images/zImage.pcore skip=64 bs=1k
-
-zImage.initrd-PCORE: zvmlinux.initrd
-	dd if=zvmlinux.initrd of=../images/zImage.initrd.pcore skip=64 bs=1k
-
 zImage-PPLUS: zvmlinux $(MKPREP) $(MKBUGBOOT)
 	$(MKPREP) -pbp zvmlinux ../images/zImage.pplus
 	$(MKBUGBOOT) zvmlinux ../images/zImage.bugboot
@@ -226,35 +228,5 @@
 zImage.initrd-PPLUS: zvmlinux.initrd $(MKPREP) $(MKBUGBOOT)
 	$(MKPREP) -pbp zvmlinux.initrd ../images/zImage.initrd.pplus
 	$(MKBUGBOOT) zvmlinux.initrd ../images/zImage.initrd.bugboot
-
-zImage-SMON: zvmlinux
-	dd if=zvmlinux of=../images/zImage.gemini skip=64 bs=1k
-
-zImage.initrd-SMON: zvmlinux.initrd
-	dd if=zvmlinux.initrd of=../images/zImage.initrd.gemini skip=64 bs=1k
-
-zImage-SP: zvmlinux
-	mv zvmlinux ../images/zImage.sandpoint
-
-zImage.initrd-SP: zvmlinux.initrd
-	mv zvmlinux.initrd ../images/zImage.initrd.sandpoint
-
-zImage-SPRUCE: zvmlinux
-	$(MKTREE) zvmlinux ../images/zImage.spruce 0x800000
-
-zImage.initrd-SPRUCE: zvmlinux.initrd
-	$(MKTREE) zvmlinux.initrd ../images/zImage.initrd.spruce 0x800000
-
-zImage-TREE: zvmlinux
-	$(MKTREE) zvmlinux ../images/zImage.treeboot
-
-zImage.initrd-TREE: zvmlinux.initrd
-	$(MKTREE) zvmlinux.initrd ../images/zImage.initrd.treeboot
-
-zImage-ZX4500: zvmlinux
-	dd if=zvmlinux of=../images/zImage.zx4500 skip=64 bs=1k
-
-zImage.initrd-ZX4500: zvmlinux.initrd
-	dd if=zvmlinux.initrd of=../images/zImage.initrd.zx4500 skip=64 bs=1k
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/ppc/boot/simple/embed_config.c b/arch/ppc/boot/simple/embed_config.c
--- a/arch/ppc/boot/simple/embed_config.c	Fri Sep 20 08:20:42 2002
+++ b/arch/ppc/boot/simple/embed_config.c	Fri Sep 20 08:20:42 2002
@@ -1,7 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
 /* Board specific functions for those embedded 8xx boards that do
  * not have boot monitor support for board information.
  *
@@ -14,7 +10,6 @@
 #include <linux/types.h>
 #include <linux/config.h>
 #include <linux/string.h>
-#include <asm/io.h>
 #ifdef CONFIG_8xx
 #include <asm/mpc8xx.h>
 #endif
@@ -22,6 +17,9 @@
 #include <asm/mpc8260.h>
 #include <asm/immap_8260.h>
 #endif
+#ifdef CONFIG_40x
+#include <asm/io.h>
+#endif
 
 /* For those boards that don't provide one.
 */
@@ -657,15 +655,65 @@
 }
 #endif /* WILLOW */
 
-#ifdef CONFIG_TREEBOOT
+void
+embed_config(bd_t ** bdp)
+{
+	static const unsigned long line_size = 32;
+	static const unsigned long congruence_classes = 256;
+	unsigned long addr;
+	u_char *cp;
+	int i;
+	bd_t *bd;
+
+	/*
+	 * At one point, we were getting machine checks.  Linux was not
+	 * invalidating the data cache before it was enabled.  The
+	 * following code was added to do that.  Soon after we had done
+	 * that, we found the real reasons for the machine checks.  I've
+	 * run the kernel a few times with the following code
+	 * temporarily removed without any apparent problems.  However,
+	 * I objdump'ed the kernel and boot code and found out that
+	 * there were no other dccci's anywhere, so I put the code back
+	 * in and have been reluctant to remove it.  It seems safer to
+	 * just leave it here.
+	 */
+	for (addr = 0;
+	     addr < (congruence_classes * line_size); addr += line_size) {
+	      __asm__("dccci 0,%0": :"b"(addr));
+	}
+
+	bd = &bdinfo;
+	*bdp = bd;
+	bd->bi_memsize = XPAR_DDR_0_SIZE;
+	bd->bi_intfreq = XPAR_CORE_CLOCK_FREQ_HZ;
+	bd->bi_busfreq = XPAR_PLB_CLOCK_FREQ_HZ;
+}
+
+#ifdef CONFIG_IBM_OPENBIOS
 /* This could possibly work for all treeboot roms.
 */
-#if defined(CONFIG_ASH)
+#if defined(CONFIG_ASH) || defined(CONFIG_BEECH)
 #define BOARD_INFO_VECTOR       0xFFF80B50 /* openbios 1.19 moved this vector down  - armin */
 #else
-#define	BOARD_INFO_VECTOR	0xFFFE0B50
+#define BOARD_INFO_VECTOR	0xFFFE0B50
 #endif
 
+#ifdef CONFIG_BEECH
+static void
+get_board_info(bd_t **bdp)
+{
+	typedef void (*PFV)(bd_t *bd);
+	((PFV)(*(unsigned long *)BOARD_INFO_VECTOR))(*bdp);
+	return;
+}
+
+void
+embed_config(bd_t **bdp)
+{
+        *bdp = &bdinfo;
+	get_board_info(bdp);
+}
+#else /* !CONFIG_BEECH */
 void
 embed_config(bd_t **bdp)
 {
@@ -675,16 +723,13 @@
 	bd_t *(*get_board_info)(void) =
 	    (bd_t *(*)(void))(*(unsigned long *)BOARD_INFO_VECTOR);
 #if !defined(CONFIG_STB03xxx)
-	volatile emac_t *emacp;
-	emacp = (emac_t *)EMAC0_BASE;  /* assume 1st emac - armin */
 
 	/* shut down the Ethernet controller that the boot rom
 	 * sometimes leaves running.
 	 */
 	mtdcr(DCRN_MALCR(DCRN_MAL_BASE), MALCR_MMSR);     /* 1st reset MAL */
 	while (mfdcr(DCRN_MALCR(DCRN_MAL_BASE)) & MALCR_MMSR) {}; /* wait for the reset */	
-	emacp->em0mr0 = 0x20000000;        /* then reset EMAC */
-	eieio();
+	out_be32(EMAC0_BASE,0x20000000);        /* then reset EMAC */
 #endif
 
 	bd = &bdinfo;
@@ -715,14 +760,15 @@
 #endif
 	}
 	/* Yeah, this look weird, but on Redwood 4 they are
-	 * different object in the structure.  When RW5 uses
-	 * OpenBIOS, it requires a special value.
+	 * different object in the structure.  Sincr Redwwood 5
+	 * and Redwood 6 use OpenBIOS, it requires a special value.
 	 */
-#ifdef CONFIG_REDWOOD_5
+#if defined(CONFIG_REDWOOD_5) || defined (CONFIG_REDWOOD_6)
 	bd->bi_tbfreq = 27 * 1000 * 1000;
 #endif
 }
-#endif
+#endif /* CONFIG_BEECH */
+#endif /* CONFIG_IBM_OPENBIOS */
 
 #ifdef CONFIG_EP405
 #include <linux/serial_reg.h>
@@ -749,6 +795,14 @@
 		writeb(0, UART0_IO_BASE + UART_LCR);
 	}
 
+	/* We haven't seen actual problems with the EP405 leaving the
+	 * EMAC running (as we have on Walnut).  But the registers
+	 * suggest it may not be left completely quiescent.  Reset it
+	 * just to be sure. */
+	mtdcr(DCRN_MALCR(DCRN_MAL_BASE), MALCR_MMSR);     /* 1st reset MAL */
+	while (mfdcr(DCRN_MALCR(DCRN_MAL_BASE)) & MALCR_MMSR) {}; /* wait for the reset */	
+	out_be32(EMAC0_BASE,0x20000000);        /* then reset EMAC */
+
 	bd = &bdinfo;
 	*bdp = bd;
 #if 1
@@ -808,6 +862,16 @@
 	
 	bd = &bdinfo;
 	*bdp = bd;
+	
+	for(i=0;i<8192;i+=32) {
+		__asm__("dccci 0,%0" :: "r" (i));
+	}
+	__asm__("iccci 0,0");
+	__asm__("sync;isync");
+
+	/* init ram for parity */
+	memset(0, 0,0x400000);  /* Lo memory */
+
 
 	bd->bi_memsize   = (32 * 1024 * 1024) ;
 	bd->bi_intfreq = 133000000; //the internal clock is 133 MHz
diff -Nru a/arch/ppc/boot/simple/gt64260_tty.c b/arch/ppc/boot/simple/gt64260_tty.c
--- a/arch/ppc/boot/simple/gt64260_tty.c	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/boot/simple/gt64260_tty.c	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * arch/ppc/boot/simple/gt64260_tty.c
  * 
  * Bootloader version of the embedded MPSC/UART driver for the GT64260[A].
diff -Nru a/arch/ppc/boot/simple/head.S b/arch/ppc/boot/simple/head.S
--- a/arch/ppc/boot/simple/head.S	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/boot/simple/head.S	Fri Sep 20 08:20:47 2002
@@ -37,7 +37,7 @@
 	.globl	start
 start:
 	bl	start_
-#ifdef CONFIG_TREEBOOT
+#ifdef CONFIG_IBM_OPENBIOS
 	/* The IBM "Tree" bootrom knows that the address of the bootrom
 	 * read only structure is 4 bytes after _start.
 	 */
@@ -73,7 +73,8 @@
 #ifdef CONFIG_6xx
 	bl	disable_6xx_mmu
 	bl	disable_6xx_l1cache
-#if defined(CONFIG_FORCE) || defined(CONFIG_K2) || defined(CONFIG_EV64260)
+#if defined(CONFIG_FORCE) || defined(CONFIG_K2)		\
+		|| defined(CONFIG_EV64260) || defined(CONFIG_PAL4)
 	bl	_setup_L2CR
 #endif
 #endif
diff -Nru a/arch/ppc/boot/simple/iic.c b/arch/ppc/boot/simple/iic.c
--- a/arch/ppc/boot/simple/iic.c	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/boot/simple/iic.c	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
 /* Minimal support functions to read configuration from IIC EEPROMS
  * on MPC8xx boards.  Originally written for RPGC RPX-Lite.
  * Dan Malek (dmalek@jlc.net).
diff -Nru a/arch/ppc/boot/simple/m8260_tty.c b/arch/ppc/boot/simple/m8260_tty.c
--- a/arch/ppc/boot/simple/m8260_tty.c	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/boot/simple/m8260_tty.c	Fri Sep 20 08:20:44 2002
@@ -1,8 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
-
 /* Minimal serial functions needed to send messages out the serial
  * port on SMC1.
  */
diff -Nru a/arch/ppc/boot/simple/m8xx_tty.c b/arch/ppc/boot/simple/m8xx_tty.c
--- a/arch/ppc/boot/simple/m8xx_tty.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/boot/simple/m8xx_tty.c	Fri Sep 20 08:20:41 2002
@@ -1,8 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
-
 /* Minimal serial functions needed to send messages out the serial
  * port on the MBX console.
  *
diff -Nru a/arch/ppc/boot/simple/misc-embedded.c b/arch/ppc/boot/simple/misc-embedded.c
--- a/arch/ppc/boot/simple/misc-embedded.c	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc/boot/simple/misc-embedded.c	Fri Sep 20 08:20:43 2002
@@ -1,6 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- *
  * Originally adapted by Gary Thomas.  Much additional work by
  * Cort Dougan <cort@fsmlabs.com>.  On top of that still more work by
  * Dan Malek <dmalek@jlc.net>.
@@ -82,7 +80,7 @@
 	 * initialize the serial console port.
 	 */
 	embed_config(&bp);
-#ifdef CONFIG_SERIAL_CONSOLE
+#if defined(CONFIG_SERIAL_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE)
 	com_port = serial_init(0, bp);
 #endif
 
diff -Nru a/arch/ppc/boot/simple/pci.c b/arch/ppc/boot/simple/pci.c
--- a/arch/ppc/boot/simple/pci.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/boot/simple/pci.c	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 /* Stand alone funtions for QSpan Tundra support.
  */
 #include <linux/types.h>
diff -Nru a/arch/ppc/boot/simple/qspan_pci.c b/arch/ppc/boot/simple/qspan_pci.c
--- a/arch/ppc/boot/simple/qspan_pci.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/boot/simple/qspan_pci.c	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * LinuxPPC arch/ppc/kernel/qspan_pci.c   Dan Malek (dmalek@jlc.net)
  *
  * QSpan Motorola bus to PCI bridge.  The config address register
diff -Nru a/arch/ppc/boot/utils/addnote.c b/arch/ppc/boot/utils/addnote.c
--- a/arch/ppc/boot/utils/addnote.c	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc/boot/utils/addnote.c	Fri Sep 20 08:20:48 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.addnote.c 1.7 05/18/01 15:17:23 cort
- */
-/*
  * Program to hack in a PT_NOTE program header entry in an ELF file.
  * This is needed for OF on RS/6000s to load an image correctly.
  * Note that OF needs a program header entry for the note, not an
diff -Nru a/arch/ppc/boot/utils/hack-coff.c b/arch/ppc/boot/utils/hack-coff.c
--- a/arch/ppc/boot/utils/hack-coff.c	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc/boot/utils/hack-coff.c	Fri Sep 20 08:20:43 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.hack-coff.c 1.8 05/18/01 06:20:29 patch
- */
-/*
  * hack-coff.c - hack the header of an xcoff file to fill in
  * a few fields needed by the Open Firmware xcoff loader on
  * Power Macs but not initialized by objcopy.
diff -Nru a/arch/ppc/boot/utils/mknote.c b/arch/ppc/boot/utils/mknote.c
--- a/arch/ppc/boot/utils/mknote.c	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc/boot/utils/mknote.c	Fri Sep 20 08:20:48 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.mknote.c 1.7 05/18/01 15:17:23 cort
- */
-/*
  * Copyright (C) Cort Dougan 1999.
  *
  * This program is free software; you can redistribute it and/or
diff -Nru a/arch/ppc/boot/utils/mkprep.c b/arch/ppc/boot/utils/mkprep.c
--- a/arch/ppc/boot/utils/mkprep.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/boot/utils/mkprep.c	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.mkprep.c 1.7 05/18/01 06:20:29 patch
- */
-/*
  * Makes a prep bootable image which can be dd'd onto
  * a disk device to make a bootdisk.  Will take
  * as input a elf executable, strip off the header
diff -Nru a/arch/ppc/boot/utils/mktree.c b/arch/ppc/boot/utils/mktree.c
--- a/arch/ppc/boot/utils/mktree.c	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/boot/utils/mktree.c	Fri Sep 20 08:20:44 2002
@@ -1,6 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- * 
  * Makes a tree bootable image for IBM Evaluation boards.
  * Basically, just take a zImage, skip the ELF header, and stuff
  * a 32 byte header on the front.
diff -Nru a/arch/ppc/config.in b/arch/ppc/config.in
--- a/arch/ppc/config.in	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/config.in	Fri Sep 20 08:20:46 2002
@@ -1,5 +1,3 @@
-# BK Id: %F% %I% %G% %U% %#%
-#
 # For a description of the syntax of this configuration file,
 # see Documentation/kbuild/config-language.txt.
 #
@@ -7,7 +5,6 @@
 define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
 define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
 define_bool CONFIG_HAVE_DEC_LOCK y
-define_bool CONFIG_GENERIC_ISA_DMA y
 
 mainmenu_name "Linux/PowerPC Kernel Configuration"
 
@@ -30,9 +27,13 @@
 
 if [ "$CONFIG_6xx" = "y" ]; then
    bool 'MPC8260 CPM Support' CONFIG_8260
+   if [ "$CONFIG_8260" = "n" ]; then
+      define_bool CONFIG_GENERIC_ISA_DMA y
+   fi
 fi
 
 if [ "$CONFIG_POWER3" = "y" ]; then
+   define_bool CONFIG_GENERIC_ISA_DMA y
    define_bool CONFIG_PPC64BRIDGE y
    define_bool CONFIG_ALL_PPC y
 fi
@@ -264,38 +265,6 @@
 comment 'General setup'
 
 bool 'High memory support' CONFIG_HIGHMEM
-bool 'Prompt for advanced kernel configuration options' CONFIG_ADVANCED_OPTIONS
-if [ "$CONFIG_ADVANCED_OPTIONS" = "y" ]; then
-   if [ "$CONFIG_HIGHMEM" = "y" ]; then
-      bool "  Set high memory pool address" CONFIG_HIGHMEM_START_BOOL
-      if [ "$CONFIG_HIGHMEM_START_BOOL" = "y" ]; then
-         hex "    Virtual start address of high memory pool" CONFIG_HIGHMEM_START 0xfe000000
-      fi
-      bool "  Set maximum low memory" CONFIG_LOWMEM_SIZE_BOOL
-      if [ "$CONFIG_LOWMEM_SIZE_BOOL" = "y" ]; then
-         hex "    Maximum low memory size (in bytes)" CONFIG_LOWMEM_SIZE 0x20000000
-      fi
-   fi
-
-   bool "Set custom kernel base address" CONFIG_KERNEL_START_BOOL
-   if [ "$CONFIG_KERNEL_START_BOOL" = "y" ]; then
-      hex "  Virtual address of kernel base" CONFIG_KERNEL_START 0xc0000000
-   fi
-   bool "Set custom user task size" CONFIG_TASK_SIZE_BOOL
-   if [ "$CONFIG_TASK_SIZE_BOOL" = "y" ]; then
-      hex "  Size of user task space" CONFIG_TASK_SIZE 0x80000000
-   fi
-   if [ "$CONFIG_8xx" = "y" ]; then
-      bool "Pinned Kernel TLBs (860 ONLY)" CONFIG_PIN_TLB
-   fi
-   if [ "$CONFIG_ALL_PPC" != "y" ]; then
-      bool "Set the boot link/load address" CONFIG_BOOT_LOAD_BOOL
-      if [ "$CONFIG_BOOT_LOAD_BOOL" = "y" ]; then
-         hex "  Link/load address for booting" CONFIG_BOOT_LOAD 0x00400000
-      fi
-   fi
-fi
-
 if [ "$CONFIG_ALL_PPC" = "y" ]; then
    bool 'Support for ISA-bus hardware' CONFIG_ISA
 else
@@ -349,14 +318,6 @@
 
 source drivers/parport/Config.in
 
-if [ "$CONFIG_PPC_ISERIES" != "y" ]; then
-   if [ "$CONFIG_APUS" != "y" ]; then
-      tristate 'Support for /dev/rtc' CONFIG_PPC_RTC
-   else
-      bool 'Generic /dev/rtc emulation' CONFIG_GEN_RTC
-   fi
-fi
-
 if [ "$CONFIG_ALL_PPC" = "y" -a "$CONFIG_POWER3" = "n" ] ; then
    bool 'Workarounds for PPC601 bugs' CONFIG_PPC601_SYNC_FIX
 fi
@@ -381,11 +342,7 @@
    define_bool CONFIG_FB_CONSOLE y
    define_bool CONFIG_AMIGA y
    define_bool CONFIG_ZORRO y
-   define_bool CONFIG_AMIGAMOUSE y
    define_bool CONFIG_ABSTRACT_CONSOLE y
-   define_bool CONFIG_FB y
-   define_bool CONFIG_MOUSE y
-   define_bool CONFIG_BUSMOUSE y
    define_bool CONFIG_APUS_FAST_EXCEPT y
 
    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
@@ -412,8 +369,43 @@
    bool '/proc/hardware support' CONFIG_PROC_HARDWARE
    source drivers/zorro/Config.in
 fi
+endmenu
+
+mainmenu_option next_comment
+comment 'Advanced setup'
+bool 'Prompt for advanced kernel configuration options' CONFIG_ADVANCED_OPTIONS
+if [ "$CONFIG_ADVANCED_OPTIONS" = "y" ]; then
+   if [ "$CONFIG_HIGHMEM" = "y" ]; then
+      bool "  Set high memory pool address" CONFIG_HIGHMEM_START_BOOL
+      if [ "$CONFIG_HIGHMEM_START_BOOL" = "y" ]; then
+         hex "    Virtual start address of high memory pool" CONFIG_HIGHMEM_START 0xfe000000
+      fi
+      bool "  Set maximum low memory" CONFIG_LOWMEM_SIZE_BOOL
+      if [ "$CONFIG_LOWMEM_SIZE_BOOL" = "y" ]; then
+         hex "    Maximum low memory size (in bytes)" CONFIG_LOWMEM_SIZE 0x20000000
+      fi
+   fi
 
+   bool "Set custom kernel base address" CONFIG_KERNEL_START_BOOL
+   if [ "$CONFIG_KERNEL_START_BOOL" = "y" ]; then
+      hex "  Virtual address of kernel base" CONFIG_KERNEL_START 0xc0000000
+   fi
+   bool "Set custom user task size" CONFIG_TASK_SIZE_BOOL
+   if [ "$CONFIG_TASK_SIZE_BOOL" = "y" ]; then
+      hex "  Size of user task space" CONFIG_TASK_SIZE 0x80000000
+   fi
+   if [ "$CONFIG_8xx" = "y" ]; then
+      bool "Pinned Kernel TLBs (860 ONLY)" CONFIG_PIN_TLB
+   fi
+   if [ "$CONFIG_ALL_PPC" != "y" ]; then
+      bool "Set the boot link/load address" CONFIG_BOOT_LOAD_BOOL
+      if [ "$CONFIG_BOOT_LOAD_BOOL" = "y" ]; then
+         hex "  Link/load address for booting" CONFIG_BOOT_LOAD 0x00400000
+      fi
+   fi
+fi
 endmenu
+
 source drivers/mtd/Config.in
 source drivers/pnp/Config.in
 source drivers/block/Config.in
@@ -467,14 +459,6 @@
 source drivers/isdn/Config.in
 
 mainmenu_option next_comment
-comment 'Old CD-ROM drivers (not SCSI, not IDE)'
-bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
-if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
-   source drivers/cdrom/Config.in
-fi
-endmenu
-
-mainmenu_option next_comment
 comment 'Console drivers'
 if [ "$CONFIG_4xx" != "y" -a "$CONFIG_8xx" != "y" ]; then
    bool 'VGA text console' CONFIG_VGA_CONSOLE
@@ -504,6 +488,14 @@
    if [ "$CONFIG_VIOCD" = "y" ]; then
       define_bool CONFIG_CD_NO_IDESCSI y
       define_bool CONFIG_BLK_DEV_IDECD y
+   fi
+   endmenu
+else
+   mainmenu_option next_comment
+   comment 'Old CD-ROM drivers (not SCSI, not IDE)'
+   bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
+   if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
+      source drivers/cdrom/Config.in
    fi
    endmenu
 fi
diff -Nru a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
--- a/arch/ppc/kernel/Makefile	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/kernel/Makefile	Fri Sep 20 08:20:47 2002
@@ -1,5 +1,3 @@
-# BK Id: %F% %I% %G% %U% %#%
-#
 #
 # Makefile for the linux kernel.
 #
diff -Nru a/arch/ppc/kernel/align.c b/arch/ppc/kernel/align.c
--- a/arch/ppc/kernel/align.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/kernel/align.c	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * align.c - handle alignment exceptions for the Power PC.
  *
  * Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
diff -Nru a/arch/ppc/kernel/bitops.c b/arch/ppc/kernel/bitops.c
--- a/arch/ppc/kernel/bitops.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/kernel/bitops.c	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Copyright (C) 1996 Paul Mackerras.
  */
 
diff -Nru a/arch/ppc/kernel/btext.c b/arch/ppc/kernel/btext.c
--- a/arch/ppc/kernel/btext.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/kernel/btext.c	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Procedures for drawing on the screen early on in the boot process.
  *
  * Benjamin Herrenschmidt <benh@kernel.crashing.org>
diff -Nru a/arch/ppc/kernel/cputable.c b/arch/ppc/kernel/cputable.c
--- a/arch/ppc/kernel/cputable.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/kernel/cputable.c	Fri Sep 20 08:20:46 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/kernel/cputable.c
  *
  *  Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org)
diff -Nru a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S
--- a/arch/ppc/kernel/entry.S	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/kernel/entry.S	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  *  Rewritten by Cort Dougan (cort@fsmlabs.com) for PReP
diff -Nru a/arch/ppc/kernel/find_name.c b/arch/ppc/kernel/find_name.c
--- a/arch/ppc/kernel/find_name.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/kernel/find_name.c	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.find_name.c 1.5 05/17/01 18:14:21 cort
- */
 #include <stdio.h>
 #include <asm/page.h>
 #include <sys/mman.h>
diff -Nru a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
--- a/arch/ppc/kernel/head.S	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/kernel/head.S	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  *
diff -Nru a/arch/ppc/kernel/head_8xx.S b/arch/ppc/kernel/head_8xx.S
--- a/arch/ppc/kernel/head_8xx.S	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/kernel/head_8xx.S	Fri Sep 20 08:20:46 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/kernel/except_8xx.S
  *
  *  PowerPC version 
diff -Nru a/arch/ppc/kernel/i8259.c b/arch/ppc/kernel/i8259.c
--- a/arch/ppc/kernel/i8259.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/kernel/i8259.c	Fri Sep 20 08:20:46 2002
@@ -1,7 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
 #include <linux/stddef.h>
 #include <linux/init.h>
 #include <linux/irq.h>
diff -Nru a/arch/ppc/kernel/iSeries_asm.h b/arch/ppc/kernel/iSeries_asm.h
--- a/arch/ppc/kernel/iSeries_asm.h	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/kernel/iSeries_asm.h	Fri Sep 20 08:20:46 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * arch/ppc/kernel/iSeries_asm.h
  *
  * Definitions used by various bits of low-level assembly code on iSeries.
diff -Nru a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c
--- a/arch/ppc/kernel/idle.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/kernel/idle.c	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Idle daemon for PowerPC.  Idle daemon will handle any action
  * that needs to be taken when the system becomes idle.
  *
diff -Nru a/arch/ppc/kernel/indirect_pci.c b/arch/ppc/kernel/indirect_pci.c
--- a/arch/ppc/kernel/indirect_pci.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/kernel/indirect_pci.c	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Support for indirect PCI bridges.
  *
  * Copyright (C) 1998 Gabriel Paubert.
diff -Nru a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c
--- a/arch/ppc/kernel/irq.c	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/kernel/irq.c	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/kernel/irq.c
  *
  *  Derived from arch/i386/kernel/irq.c
diff -Nru a/arch/ppc/kernel/m8260_setup.c b/arch/ppc/kernel/m8260_setup.c
--- a/arch/ppc/kernel/m8260_setup.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/kernel/m8260_setup.c	Fri Sep 20 08:20:46 2002
@@ -1,8 +1,5 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- *  linux/arch/ppc/kernel/setup.c
+ *  arch/ppc/kernel/setup.c
  *
  *  Copyright (C) 1995  Linus Torvalds
  *  Adapted from 'alpha' version by Gary Thomas
diff -Nru a/arch/ppc/kernel/m8xx_setup.c b/arch/ppc/kernel/m8xx_setup.c
--- a/arch/ppc/kernel/m8xx_setup.c	Fri Sep 20 08:20:45 2002
+++ b/arch/ppc/kernel/m8xx_setup.c	Fri Sep 20 08:20:45 2002
@@ -1,7 +1,5 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- *
- *  linux/arch/ppc/kernel/setup.c
+ *  arch/ppc/kernel/setup.c
  *
  *  Copyright (C) 1995  Linus Torvalds
  *  Adapted from 'alpha' version by Gary Thomas
diff -Nru a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
--- a/arch/ppc/kernel/misc.S	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/kernel/misc.S	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * This file contains miscellaneous low-level functions.
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  *
diff -Nru a/arch/ppc/kernel/mk_defs.c b/arch/ppc/kernel/mk_defs.c
--- a/arch/ppc/kernel/mk_defs.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/kernel/mk_defs.c	Fri Sep 20 08:20:46 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * This program is used to generate definitions needed by
  * assembly language modules.
  *
diff -Nru a/arch/ppc/kernel/open_pic.c b/arch/ppc/kernel/open_pic.c
--- a/arch/ppc/kernel/open_pic.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/kernel/open_pic.c	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling
  *
  *  Copyright (C) 1997 Geert Uytterhoeven
diff -Nru a/arch/ppc/kernel/open_pic_defs.h b/arch/ppc/kernel/open_pic_defs.h
--- a/arch/ppc/kernel/open_pic_defs.h	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/kernel/open_pic_defs.h	Fri Sep 20 08:20:47 2002
@@ -1,8 +1,5 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- *  linux/openpic.h -- OpenPIC definitions
+ *  arch/ppc/kernel/open_pic_defs.h -- OpenPIC definitions
  *
  *  Copyright (C) 1997 Geert Uytterhoeven
  *
diff -Nru a/arch/ppc/kernel/pci-dma.c b/arch/ppc/kernel/pci-dma.c
--- a/arch/ppc/kernel/pci-dma.c	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc/kernel/pci-dma.c	Fri Sep 20 08:20:43 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Copyright (C) 2000   Ani Joshi <ajoshi@unixbox.com>
  *
  *
diff -Nru a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
--- a/arch/ppc/kernel/pci.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/kernel/pci.c	Fri Sep 20 08:20:46 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Common pmac/prep/chrp pci routines. -- Cort
  */
 
diff -Nru a/arch/ppc/kernel/ppc-stub.c b/arch/ppc/kernel/ppc-stub.c
--- a/arch/ppc/kernel/ppc-stub.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/kernel/ppc-stub.c	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * ppc-stub.c:  KGDB support for the Linux kernel.
  *
  * adapted from arch/sparc/kernel/sparc-stub.c for the PowerPC
diff -Nru a/arch/ppc/kernel/ppc8260_pic.c b/arch/ppc/kernel/ppc8260_pic.c
--- a/arch/ppc/kernel/ppc8260_pic.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/kernel/ppc8260_pic.c	Fri Sep 20 08:20:46 2002
@@ -1,7 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
 #include <linux/stddef.h>
 #include <linux/init.h>
 #include <linux/sched.h>
diff -Nru a/arch/ppc/kernel/ppc8260_pic.h b/arch/ppc/kernel/ppc8260_pic.h
--- a/arch/ppc/kernel/ppc8260_pic.h	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc/kernel/ppc8260_pic.h	Fri Sep 20 08:20:48 2002
@@ -1,7 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
 #ifndef _PPC_KERNEL_PPC8260_H
 #define _PPC_KERNEL_PPC8260_H
 
diff -Nru a/arch/ppc/kernel/ppc8xx_pic.c b/arch/ppc/kernel/ppc8xx_pic.c
--- a/arch/ppc/kernel/ppc8xx_pic.c	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/kernel/ppc8xx_pic.c	Fri Sep 20 08:20:44 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/init.h>
diff -Nru a/arch/ppc/kernel/ppc8xx_pic.h b/arch/ppc/kernel/ppc8xx_pic.h
--- a/arch/ppc/kernel/ppc8xx_pic.h	Fri Sep 20 08:20:45 2002
+++ b/arch/ppc/kernel/ppc8xx_pic.h	Fri Sep 20 08:20:45 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifndef _PPC_KERNEL_PPC8xx_H
 #define _PPC_KERNEL_PPC8xx_H
 
diff -Nru a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c
--- a/arch/ppc/kernel/ppc_htab.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/kernel/ppc_htab.c	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.ppc_htab.c 1.19 10/16/01 15:58:42 trini
- */
-/*
  * PowerPC hash table management proc entry.  Will show information
  * about the current hash table and will allow changes to it.
  *
@@ -118,10 +115,8 @@
 	unsigned long mmcr0 = 0, pmc1 = 0, pmc2 = 0;
 	int n = 0;
 #ifdef CONFIG_PPC_STD_MMU
-	int valid;
-	unsigned int kptes = 0, uptes = 0, zombie_ptes = 0;
+	unsigned int kptes = 0, uptes = 0;
 	PTE *ptr;
-	struct task_struct *p;
 #endif /* CONFIG_PPC_STD_MMU */
 	char buffer[512];
 
@@ -154,32 +149,18 @@
 		goto return_string;
 	}
 
-	for ( ptr = Hash ; ptr < Hash_end ; ptr++)
-	{
-		unsigned int ctx, mctx, vsid;
+	for (ptr = Hash; ptr < Hash_end; ptr++) {
+		unsigned int mctx, vsid;
 
 		if (!ptr->v)
 			continue;
-		/* make sure someone is using this context/vsid */
-		/* first undo the esid skew */
+		/* undo the esid skew */
 		vsid = ptr->vsid;
 		mctx = ((vsid - (vsid & 0xf) * 0x111) >> 4) & 0xfffff;
-		if (mctx == 0) {
+		if (mctx == 0)
 			kptes++;
-			continue;
-		}
-		/* now undo the context skew; 801921 * 897 == 1 mod 2^20 */
-		ctx = (mctx * 801921) & 0xfffff;
-		valid = 0;
-		for_each_task(p) {
-			if (p->mm != NULL && ctx == p->mm->context) {
-				valid = 1;
-				uptes++;
-				break;
-			}
-		}
-		if (!valid)
-			zombie_ptes++;
+		else
+			uptes++;
 	}
 	
 	n += sprintf( buffer + n,
@@ -190,7 +171,6 @@
 		      "Entries\t\t: %lu\n"
 		      "User ptes\t: %u\n"
 		      "Kernel ptes\t: %u\n"
-		      "Zombies\t\t: %u\n"
 		      "Percent full\t: %lu%%\n",
                       (unsigned long)(Hash_size>>10),
 		      (Hash_size/(sizeof(PTE)*8)),
@@ -198,7 +178,6 @@
 		      Hash_size/sizeof(PTE),
                       uptes,
 		      kptes,
-		      zombie_ptes,
 		      ((kptes+uptes)*100) / (Hash_size/sizeof(PTE))
 		);
 
@@ -212,7 +191,7 @@
 		      primary_pteg_full, htab_evicts);
 return_string:
 #endif /* CONFIG_PPC_STD_MMU */
-	
+
 	n += sprintf( buffer + n,
 		      "Non-error misses: %lu\n"
 		      "Error misses\t: %lu\n",
diff -Nru a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
--- a/arch/ppc/kernel/ppc_ksyms.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/kernel/ppc_ksyms.c	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/threads.h>
diff -Nru a/arch/ppc/kernel/prep_nvram.c b/arch/ppc/kernel/prep_nvram.c
--- a/arch/ppc/kernel/prep_nvram.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/kernel/prep_nvram.c	Fri Sep 20 08:20:46 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * arch/ppc/kernel/prep_nvram.c
  *
  * Copyright (C) 1998  Corey Minyard
diff -Nru a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
--- a/arch/ppc/kernel/process.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/kernel/process.c	Fri Sep 20 08:20:46 2002
@@ -1,8 +1,5 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- *  linux/arch/ppc/kernel/process.c
+ *  arch/ppc/kernel/process.c
  *
  *  Derived from "arch/i386/kernel/process.c"
  *    Copyright (C) 1995  Linus Torvalds
diff -Nru a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c
--- a/arch/ppc/kernel/prom.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/kernel/prom.c	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Procedures for interfacing to the Open Firmware PROM on
  * Power Macintosh computers.
  *
diff -Nru a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c
--- a/arch/ppc/kernel/ptrace.c	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/kernel/ptrace.c	Fri Sep 20 08:20:44 2002
@@ -1,8 +1,5 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- *  linux/arch/ppc/kernel/ptrace.c
+ *  arch/ppc/kernel/ptrace.c
  *
  *  PowerPC version
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
diff -Nru a/arch/ppc/kernel/qspan_pci.c b/arch/ppc/kernel/qspan_pci.c
--- a/arch/ppc/kernel/qspan_pci.c	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc/kernel/qspan_pci.c	Fri Sep 20 08:20:43 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * QSpan pci routines.
  * Most 8xx boards use the QSpan PCI bridge.  The config address register
  * is located 0x500 from the base of the bridge control/status registers.
diff -Nru a/arch/ppc/kernel/semaphore.c b/arch/ppc/kernel/semaphore.c
--- a/arch/ppc/kernel/semaphore.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/kernel/semaphore.c	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * PowerPC-specific semaphore code.
  *
  * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
diff -Nru a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
--- a/arch/ppc/kernel/setup.c	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc/kernel/setup.c	Fri Sep 20 08:20:48 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Common prep/pmac/chrp boot and setup code.
  */
 
diff -Nru a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c
--- a/arch/ppc/kernel/signal.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/kernel/signal.c	Fri Sep 20 08:20:46 2002
@@ -1,8 +1,5 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- *  linux/arch/ppc/kernel/signal.c
+ *  arch/ppc/kernel/signal.c
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
diff -Nru a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
--- a/arch/ppc/kernel/smp.c	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc/kernel/smp.c	Fri Sep 20 08:20:48 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Smp support for ppc.
  *
  * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great
diff -Nru a/arch/ppc/kernel/softemu8xx.c b/arch/ppc/kernel/softemu8xx.c
--- a/arch/ppc/kernel/softemu8xx.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/kernel/softemu8xx.c	Fri Sep 20 08:20:46 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Software emulation of some PPC instructions for the 8xx core.
  *
  * Copyright (C) 1998 Dan Malek (dmalek@jlc.net)
diff -Nru a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c
--- a/arch/ppc/kernel/syscalls.c	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc/kernel/syscalls.c	Fri Sep 20 08:20:48 2002
@@ -1,8 +1,5 @@
 /*
- * BK Id: SCCS/s.syscalls.c 1.11 10/16/01 15:58:42 trini
- */
-/*
- * linux/arch/ppc/kernel/sys_ppc.c
+ * arch/ppc/kernel/sys_ppc.c
  *
  *  PowerPC version 
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
diff -Nru a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c
--- a/arch/ppc/kernel/time.c	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc/kernel/time.c	Fri Sep 20 08:20:43 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Common time routines among all ppc machines.
  *
  * Written by Cort Dougan (cort@cs.nmt.edu) to merge
diff -Nru a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
--- a/arch/ppc/kernel/traps.c	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc/kernel/traps.c	Fri Sep 20 08:20:43 2002
@@ -1,8 +1,5 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- *  linux/arch/ppc/kernel/traps.c
+ *  arch/ppc/kernel/traps.c
  *
  *  Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
  *
diff -Nru a/arch/ppc/lib/Makefile b/arch/ppc/lib/Makefile
--- a/arch/ppc/lib/Makefile	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/lib/Makefile	Fri Sep 20 08:20:41 2002
@@ -1,5 +1,3 @@
-# BK Id: SCCS/s.Makefile 1.10 11/08/01 07:57:40 paulus
-#
 #
 # Makefile for ppc-specific library files..
 #
diff -Nru a/arch/ppc/lib/checksum.S b/arch/ppc/lib/checksum.S
--- a/arch/ppc/lib/checksum.S	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/lib/checksum.S	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * This file contains assembly-language implementations
  * of IP-style 1's complement checksum routines.
  *	
diff -Nru a/arch/ppc/lib/locks.c b/arch/ppc/lib/locks.c
--- a/arch/ppc/lib/locks.c	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc/lib/locks.c	Fri Sep 20 08:20:43 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Locks for smp ppc 
  * 
  * Written by Cort Dougan (cort@cs.nmt.edu)
diff -Nru a/arch/ppc/lib/strcase.c b/arch/ppc/lib/strcase.c
--- a/arch/ppc/lib/strcase.c	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc/lib/strcase.c	Fri Sep 20 08:20:48 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.strcase.c 1.5 05/17/01 18:14:22 cort
- */
 #include <linux/ctype.h>
 
 int strcasecmp(const char *s1, const char *s2)
diff -Nru a/arch/ppc/lib/string.S b/arch/ppc/lib/string.S
--- a/arch/ppc/lib/string.S	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/lib/string.S	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * String handling functions for PowerPC.
  *
  * Copyright (C) 1996 Paul Mackerras.
diff -Nru a/arch/ppc/math-emu/Makefile b/arch/ppc/math-emu/Makefile
--- a/arch/ppc/math-emu/Makefile	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/math-emu/Makefile	Fri Sep 20 08:20:47 2002
@@ -1,9 +1,3 @@
-# BK Id: SCCS/s.Makefile 1.3 05/17/01 18:14:22 cort
-#
-#
-#
-#
-
 O_TARGET			:= math-emu.o
 
 obj-y				:= math.o fmr.o lfd.o stfd.o
diff -Nru a/arch/ppc/math-emu/double.h b/arch/ppc/math-emu/double.h
--- a/arch/ppc/math-emu/double.h	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/math-emu/double.h	Fri Sep 20 08:20:46 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.double.h 1.5 05/17/01 18:14:22 cort
- */
-/*
  * Definitions for IEEE Double Precision
  */
 
diff -Nru a/arch/ppc/math-emu/fabs.c b/arch/ppc/math-emu/fabs.c
--- a/arch/ppc/math-emu/fabs.c	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc/math-emu/fabs.c	Fri Sep 20 08:20:43 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fabs.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fadd.c b/arch/ppc/math-emu/fadd.c
--- a/arch/ppc/math-emu/fadd.c	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc/math-emu/fadd.c	Fri Sep 20 08:20:48 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fadd.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fadds.c b/arch/ppc/math-emu/fadds.c
--- a/arch/ppc/math-emu/fadds.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/math-emu/fadds.c	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fadds.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fcmpo.c b/arch/ppc/math-emu/fcmpo.c
--- a/arch/ppc/math-emu/fcmpo.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/math-emu/fcmpo.c	Fri Sep 20 08:20:46 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fcmpo.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fcmpu.c b/arch/ppc/math-emu/fcmpu.c
--- a/arch/ppc/math-emu/fcmpu.c	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc/math-emu/fcmpu.c	Fri Sep 20 08:20:43 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fcmpu.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fctiw.c b/arch/ppc/math-emu/fctiw.c
--- a/arch/ppc/math-emu/fctiw.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/math-emu/fctiw.c	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fctiw.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fctiwz.c b/arch/ppc/math-emu/fctiwz.c
--- a/arch/ppc/math-emu/fctiwz.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/math-emu/fctiwz.c	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fctiwz.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fdiv.c b/arch/ppc/math-emu/fdiv.c
--- a/arch/ppc/math-emu/fdiv.c	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/math-emu/fdiv.c	Fri Sep 20 08:20:44 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fdiv.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fdivs.c b/arch/ppc/math-emu/fdivs.c
--- a/arch/ppc/math-emu/fdivs.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/math-emu/fdivs.c	Fri Sep 20 08:20:46 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fdivs.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fmadd.c b/arch/ppc/math-emu/fmadd.c
--- a/arch/ppc/math-emu/fmadd.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/math-emu/fmadd.c	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fmadd.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fmadds.c b/arch/ppc/math-emu/fmadds.c
--- a/arch/ppc/math-emu/fmadds.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/math-emu/fmadds.c	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fmadds.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fmr.c b/arch/ppc/math-emu/fmr.c
--- a/arch/ppc/math-emu/fmr.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/math-emu/fmr.c	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fmr.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fmsub.c b/arch/ppc/math-emu/fmsub.c
--- a/arch/ppc/math-emu/fmsub.c	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc/math-emu/fmsub.c	Fri Sep 20 08:20:48 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fmsub.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fmsubs.c b/arch/ppc/math-emu/fmsubs.c
--- a/arch/ppc/math-emu/fmsubs.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/math-emu/fmsubs.c	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fmsubs.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fmul.c b/arch/ppc/math-emu/fmul.c
--- a/arch/ppc/math-emu/fmul.c	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/math-emu/fmul.c	Fri Sep 20 08:20:44 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fmul.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fmuls.c b/arch/ppc/math-emu/fmuls.c
--- a/arch/ppc/math-emu/fmuls.c	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/math-emu/fmuls.c	Fri Sep 20 08:20:44 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fmuls.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fnabs.c b/arch/ppc/math-emu/fnabs.c
--- a/arch/ppc/math-emu/fnabs.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/math-emu/fnabs.c	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fnabs.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fneg.c b/arch/ppc/math-emu/fneg.c
--- a/arch/ppc/math-emu/fneg.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/math-emu/fneg.c	Fri Sep 20 08:20:46 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fneg.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fnmadd.c b/arch/ppc/math-emu/fnmadd.c
--- a/arch/ppc/math-emu/fnmadd.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/math-emu/fnmadd.c	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fnmadd.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fnmadds.c b/arch/ppc/math-emu/fnmadds.c
--- a/arch/ppc/math-emu/fnmadds.c	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/math-emu/fnmadds.c	Fri Sep 20 08:20:44 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fnmadds.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fnmsub.c b/arch/ppc/math-emu/fnmsub.c
--- a/arch/ppc/math-emu/fnmsub.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/math-emu/fnmsub.c	Fri Sep 20 08:20:46 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fnmsub.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fnmsubs.c b/arch/ppc/math-emu/fnmsubs.c
--- a/arch/ppc/math-emu/fnmsubs.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/math-emu/fnmsubs.c	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fnmsubs.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fres.c b/arch/ppc/math-emu/fres.c
--- a/arch/ppc/math-emu/fres.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/math-emu/fres.c	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fres.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/frsp.c b/arch/ppc/math-emu/frsp.c
--- a/arch/ppc/math-emu/frsp.c	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc/math-emu/frsp.c	Fri Sep 20 08:20:43 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.frsp.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/frsqrte.c b/arch/ppc/math-emu/frsqrte.c
--- a/arch/ppc/math-emu/frsqrte.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/math-emu/frsqrte.c	Fri Sep 20 08:20:46 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.frsqrte.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fsel.c b/arch/ppc/math-emu/fsel.c
--- a/arch/ppc/math-emu/fsel.c	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc/math-emu/fsel.c	Fri Sep 20 08:20:43 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fsel.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fsqrt.c b/arch/ppc/math-emu/fsqrt.c
--- a/arch/ppc/math-emu/fsqrt.c	Fri Sep 20 08:20:42 2002
+++ b/arch/ppc/math-emu/fsqrt.c	Fri Sep 20 08:20:42 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fsqrt.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fsqrts.c b/arch/ppc/math-emu/fsqrts.c
--- a/arch/ppc/math-emu/fsqrts.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/math-emu/fsqrts.c	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fsqrts.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fsub.c b/arch/ppc/math-emu/fsub.c
--- a/arch/ppc/math-emu/fsub.c	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc/math-emu/fsub.c	Fri Sep 20 08:20:48 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fsub.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/fsubs.c b/arch/ppc/math-emu/fsubs.c
--- a/arch/ppc/math-emu/fsubs.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/math-emu/fsubs.c	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fsubs.c 1.6 05/17/01 18:14:22 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/lfd.c b/arch/ppc/math-emu/lfd.c
--- a/arch/ppc/math-emu/lfd.c	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc/math-emu/lfd.c	Fri Sep 20 08:20:43 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.lfd.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/lfs.c b/arch/ppc/math-emu/lfs.c
--- a/arch/ppc/math-emu/lfs.c	Fri Sep 20 08:20:49 2002
+++ b/arch/ppc/math-emu/lfs.c	Fri Sep 20 08:20:49 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.lfs.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/math.c b/arch/ppc/math-emu/math.c
--- a/arch/ppc/math-emu/math.c	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/math-emu/math.c	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.math.c 1.6 05/17/01 18:14:23 cort
- */
-/*
  * arch/ppc/math-emu/math.c
  *
  * Copyright (C) 1999  Eddie C. Dost  (ecd@atecom.com)
diff -Nru a/arch/ppc/math-emu/mcrfs.c b/arch/ppc/math-emu/mcrfs.c
--- a/arch/ppc/math-emu/mcrfs.c	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc/math-emu/mcrfs.c	Fri Sep 20 08:20:43 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.mcrfs.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/mffs.c b/arch/ppc/math-emu/mffs.c
--- a/arch/ppc/math-emu/mffs.c	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc/math-emu/mffs.c	Fri Sep 20 08:20:48 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.mffs.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/mtfsb0.c b/arch/ppc/math-emu/mtfsb0.c
--- a/arch/ppc/math-emu/mtfsb0.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/math-emu/mtfsb0.c	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.mtfsb0.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/mtfsb1.c b/arch/ppc/math-emu/mtfsb1.c
--- a/arch/ppc/math-emu/mtfsb1.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/math-emu/mtfsb1.c	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.mtfsb1.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/mtfsf.c b/arch/ppc/math-emu/mtfsf.c
--- a/arch/ppc/math-emu/mtfsf.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/math-emu/mtfsf.c	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.mtfsf.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/mtfsfi.c b/arch/ppc/math-emu/mtfsfi.c
--- a/arch/ppc/math-emu/mtfsfi.c	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc/math-emu/mtfsfi.c	Fri Sep 20 08:20:48 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.mtfsfi.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/op-1.h b/arch/ppc/math-emu/op-1.h
--- a/arch/ppc/math-emu/op-1.h	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/math-emu/op-1.h	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.op-1.h 1.5 05/17/01 18:14:23 cort
- */
-/*
  * Basic one-word fraction declaration and manipulation.
  */
 
diff -Nru a/arch/ppc/math-emu/op-2.h b/arch/ppc/math-emu/op-2.h
--- a/arch/ppc/math-emu/op-2.h	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/math-emu/op-2.h	Fri Sep 20 08:20:46 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.op-2.h 1.5 05/17/01 18:14:23 cort
- */
-/*
  * Basic two-word fraction declaration and manipulation.
  */
 
diff -Nru a/arch/ppc/math-emu/op-4.h b/arch/ppc/math-emu/op-4.h
--- a/arch/ppc/math-emu/op-4.h	Fri Sep 20 08:20:45 2002
+++ b/arch/ppc/math-emu/op-4.h	Fri Sep 20 08:20:45 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.op-4.h 1.5 05/17/01 18:14:23 cort
- */
-/*
  * Basic four-word fraction declaration and manipulation.
  *
  * When adding quadword support for 32 bit machines, we need
diff -Nru a/arch/ppc/math-emu/op-common.h b/arch/ppc/math-emu/op-common.h
--- a/arch/ppc/math-emu/op-common.h	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/math-emu/op-common.h	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,3 @@
-/*
- * BK Id: SCCS/s.op-common.h 1.5 05/17/01 18:14:23 cort
- */
-
 #define _FP_DECL(wc, X)			\
   _FP_I_TYPE X##_c, X##_s, X##_e;	\
   _FP_FRAC_DECL_##wc(X)
diff -Nru a/arch/ppc/math-emu/sfp-machine.h b/arch/ppc/math-emu/sfp-machine.h
--- a/arch/ppc/math-emu/sfp-machine.h	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc/math-emu/sfp-machine.h	Fri Sep 20 08:20:43 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.sfp-machine.h 1.5 05/17/01 18:14:23 cort
- */
 /* Machine-dependent software floating-point definitions.  PPC version.
    Copyright (C) 1997 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
diff -Nru a/arch/ppc/math-emu/single.h b/arch/ppc/math-emu/single.h
--- a/arch/ppc/math-emu/single.h	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/math-emu/single.h	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.single.h 1.5 05/17/01 18:14:23 cort
- */
-/*
  * Definitions for IEEE Single Precision
  */
 
diff -Nru a/arch/ppc/math-emu/soft-fp.h b/arch/ppc/math-emu/soft-fp.h
--- a/arch/ppc/math-emu/soft-fp.h	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc/math-emu/soft-fp.h	Fri Sep 20 08:20:43 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.soft-fp.h 1.5 05/17/01 18:14:23 cort
- */
 #ifndef SOFT_FP_H
 #define SOFT_FP_H
 
diff -Nru a/arch/ppc/math-emu/stfd.c b/arch/ppc/math-emu/stfd.c
--- a/arch/ppc/math-emu/stfd.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/math-emu/stfd.c	Fri Sep 20 08:20:46 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.stfd.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/stfiwx.c b/arch/ppc/math-emu/stfiwx.c
--- a/arch/ppc/math-emu/stfiwx.c	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/math-emu/stfiwx.c	Fri Sep 20 08:20:44 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.stfiwx.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/stfs.c b/arch/ppc/math-emu/stfs.c
--- a/arch/ppc/math-emu/stfs.c	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc/math-emu/stfs.c	Fri Sep 20 08:20:43 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.stfs.c 1.6 05/17/01 18:14:23 cort
- */
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc/math-emu/types.c b/arch/ppc/math-emu/types.c
--- a/arch/ppc/math-emu/types.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/math-emu/types.c	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,3 @@
-/*
- * BK Id: SCCS/s.types.c 1.5 05/17/01 18:14:23 cort
- */
-
 #include "soft-fp.h"
 #include "double.h"
 #include "single.h"
diff -Nru a/arch/ppc/math-emu/udivmodti4.c b/arch/ppc/math-emu/udivmodti4.c
--- a/arch/ppc/math-emu/udivmodti4.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/math-emu/udivmodti4.c	Fri Sep 20 08:20:46 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.udivmodti4.c 1.5 05/17/01 18:14:23 cort
- */
 /* This has so very few changes over libgcc2's __udivmoddi4 it isn't funny.  */
 
 #include "soft-fp.h"
diff -Nru a/arch/ppc/mm/4xx_mmu.c b/arch/ppc/mm/4xx_mmu.c
--- a/arch/ppc/mm/4xx_mmu.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/mm/4xx_mmu.c	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * This file contains the routines for initializing the MMU
  * on the 4xx series of chips.
  *  -- paulus
diff -Nru a/arch/ppc/mm/Makefile b/arch/ppc/mm/Makefile
--- a/arch/ppc/mm/Makefile	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc/mm/Makefile	Fri Sep 20 08:20:43 2002
@@ -1,5 +1,3 @@
-# BK Id: %F% %I% %G% %U% %#%
-#
 #
 # Makefile for the linux ppc-specific parts of the memory manager.
 #
diff -Nru a/arch/ppc/mm/cachemap.c b/arch/ppc/mm/cachemap.c
--- a/arch/ppc/mm/cachemap.c	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc/mm/cachemap.c	Fri Sep 20 08:20:48 2002
@@ -1,10 +1,8 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- *
  *  PowerPC version derived from arch/arm/mm/consistent.c
  *    Copyright (C) 2001 Dan Malek (dmalek@jlc.net)
  *
- *  linux/arch/arm/mm/consistent.c
+ *  arch/arm/mm/consistent.c
  *
  *  Copyright (C) 2000 Russell King
  *
diff -Nru a/arch/ppc/mm/extable.c b/arch/ppc/mm/extable.c
--- a/arch/ppc/mm/extable.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/mm/extable.c	Fri Sep 20 08:20:47 2002
@@ -1,10 +1,7 @@
 /*
- * BK Id: SCCS/s.extable.c 1.5 05/17/01 18:14:23 cort
- */
-/*
- * linux/arch/ppc/mm/extable.c
+ * arch/ppc/mm/extable.c
  *
- * from linux/arch/i386/mm/extable.c
+ * from arch/i386/mm/extable.c
  */
 
 #include <linux/config.h>
diff -Nru a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c
--- a/arch/ppc/mm/fault.c	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/mm/fault.c	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/mm/fault.c
  *
  *  PowerPC version 
diff -Nru a/arch/ppc/mm/hashtable.S b/arch/ppc/mm/hashtable.S
--- a/arch/ppc/mm/hashtable.S	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/mm/hashtable.S	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/kernel/hashtable.S
  *
  *  $Id: hashtable.S,v 1.6 1999/10/08 01:56:15 paulus Exp $
diff -Nru a/arch/ppc/mm/iSeries_mmu.c b/arch/ppc/mm/iSeries_mmu.c
--- a/arch/ppc/mm/iSeries_mmu.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/mm/iSeries_mmu.c	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Procedures for MMU handling on iSeries systems, where we
  * have to call the hypervisor to change things in the hash
  * table.
diff -Nru a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
--- a/arch/ppc/mm/init.c	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc/mm/init.c	Fri Sep 20 08:20:43 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  PowerPC version
  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  *
diff -Nru a/arch/ppc/mm/mem_pieces.c b/arch/ppc/mm/mem_pieces.c
--- a/arch/ppc/mm/mem_pieces.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/mm/mem_pieces.c	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *    Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
  *      Changes to accomodate Power Macintoshes.
  *    Cort Dougan <cort@cs.nmt.edu>
diff -Nru a/arch/ppc/mm/mem_pieces.h b/arch/ppc/mm/mem_pieces.h
--- a/arch/ppc/mm/mem_pieces.h	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/mm/mem_pieces.h	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.mem_pieces.h 1.5 05/17/01 18:14:23 cort
- */
-/*
  *    Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
  *      Changes to accomodate Power Macintoshes.
  *    Cort Dougan <cort@cs.nmt.edu>
diff -Nru a/arch/ppc/mm/mmu_context.c b/arch/ppc/mm/mmu_context.c
--- a/arch/ppc/mm/mmu_context.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/mm/mmu_context.c	Fri Sep 20 08:20:46 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * This file contains the routines for handling the MMU on those
  * PowerPC implementations where the MMU substantially follows the
  * architecture specification.  This includes the 6xx, 7xx, 7xxx,
diff -Nru a/arch/ppc/mm/mmu_decl.h b/arch/ppc/mm/mmu_decl.h
--- a/arch/ppc/mm/mmu_decl.h	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/mm/mmu_decl.h	Fri Sep 20 08:20:46 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Declarations of procedures and variables shared between files
  * in arch/ppc/mm/.
  * 
diff -Nru a/arch/ppc/mm/pgtable.c b/arch/ppc/mm/pgtable.c
--- a/arch/ppc/mm/pgtable.c	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc/mm/pgtable.c	Fri Sep 20 08:20:43 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * This file contains the routines setting up the linux page tables.
  *  -- paulus
  * 
diff -Nru a/arch/ppc/mm/ppc_mmu.c b/arch/ppc/mm/ppc_mmu.c
--- a/arch/ppc/mm/ppc_mmu.c	Fri Sep 20 08:20:42 2002
+++ b/arch/ppc/mm/ppc_mmu.c	Fri Sep 20 08:20:42 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * This file contains the routines for handling the MMU on those
  * PowerPC implementations where the MMU substantially follows the
  * architecture specification.  This includes the 6xx, 7xx, 7xxx,
diff -Nru a/arch/ppc/mm/tlb.c b/arch/ppc/mm/tlb.c
--- a/arch/ppc/mm/tlb.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/mm/tlb.c	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * This file contains the routines for TLB flushing.
  * On machines where the MMU uses a hash table to store virtual to
  * physical translations, these routines flush entries from the 
diff -Nru a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile
--- a/arch/ppc/platforms/Makefile	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc/platforms/Makefile	Fri Sep 20 08:20:48 2002
@@ -1,5 +1,3 @@
-# BK Id: %F% %I% %G% %U% %#%
-#
 #
 # Makefile for the linux kernel.
 #
diff -Nru a/arch/ppc/platforms/apus_pci.c b/arch/ppc/platforms/apus_pci.c
--- a/arch/ppc/platforms/apus_pci.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/platforms/apus_pci.c	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Copyright (C) Michel Dänzer <michdaen@iiic.ethz.ch>
  *
  * APUS PCI routines.
diff -Nru a/arch/ppc/platforms/apus_pci.h b/arch/ppc/platforms/apus_pci.h
--- a/arch/ppc/platforms/apus_pci.h	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/platforms/apus_pci.h	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Phase5 CybervisionPPC (TVP4020) definitions for the Permedia2 framebuffer
  * driver.
  *
diff -Nru a/arch/ppc/platforms/apus_setup.c b/arch/ppc/platforms/apus_setup.c
--- a/arch/ppc/platforms/apus_setup.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/platforms/apus_setup.c	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platforms/apus_setup.c
  *
  *  Copyright (C) 1998, 1999  Jesper Skov
diff -Nru a/arch/ppc/platforms/bseip.h b/arch/ppc/platforms/bseip.h
--- a/arch/ppc/platforms/bseip.h	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/platforms/bseip.h	Fri Sep 20 08:20:41 2002
@@ -1,8 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
-/*
  * A collection of structures, addresses, and values associated with
  * the Bright Star Engineering ip-Engine board.  Copied from the MBX stuff.
  *
diff -Nru a/arch/ppc/platforms/chrp_pci.c b/arch/ppc/platforms/chrp_pci.c
--- a/arch/ppc/platforms/chrp_pci.c	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc/platforms/chrp_pci.c	Fri Sep 20 08:20:48 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * CHRP pci routines.
  */
 
diff -Nru a/arch/ppc/platforms/chrp_setup.c b/arch/ppc/platforms/chrp_setup.c
--- a/arch/ppc/platforms/chrp_setup.c	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/platforms/chrp_setup.c	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platforms/setup.c
  *
  *  Copyright (C) 1995  Linus Torvalds
diff -Nru a/arch/ppc/platforms/chrp_smp.c b/arch/ppc/platforms/chrp_smp.c
--- a/arch/ppc/platforms/chrp_smp.c	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/platforms/chrp_smp.c	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Smp support for CHRP machines.
  *
  * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great
diff -Nru a/arch/ppc/platforms/chrp_time.c b/arch/ppc/platforms/chrp_time.c
--- a/arch/ppc/platforms/chrp_time.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/platforms/chrp_time.c	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platforms/chrp_time.c
  *
  *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
diff -Nru a/arch/ppc/platforms/ep405.c b/arch/ppc/platforms/ep405.c
--- a/arch/ppc/platforms/ep405.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/platforms/ep405.c	Fri Sep 20 08:20:41 2002
@@ -1,19 +1,8 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- *
  *    Copyright 2001 MontaVista Software Inc.
  *        <mlocke@mvista.com>
  *
- * 	Not much needed for the Embedded Planet 405gp board
- *
- *  	History: 11/09/2001 - armin
- *      added board_init to add in additional instuctions needed during platfrom_init
- *	cleaned up map_irq.
- *	 
- *	1/22/2002 - Armin
- *      converted pci to ocp
- *
-
+ * 	Not much is needed for the Embedded Planet 405gp board
  *
  */
 #include <linux/config.h>
diff -Nru a/arch/ppc/platforms/error_log.c b/arch/ppc/platforms/error_log.c
--- a/arch/ppc/platforms/error_log.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/platforms/error_log.c	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.error_log.c 1.6 05/17/01 18:14:21 cort
- */
-/*
  *  arch/ppc/kernel/error_log.c
  *  
  *  Copyright (c) 2000 Tilmann Bitterberg
diff -Nru a/arch/ppc/platforms/error_log.h b/arch/ppc/platforms/error_log.h
--- a/arch/ppc/platforms/error_log.h	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/platforms/error_log.h	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.error_log.h 1.5 05/17/01 18:14:21 cort
- */
 #ifndef __ERROR_LOG_H__
 #define __ERROR_LOG_H__
 
diff -Nru a/arch/ppc/platforms/est8260.h b/arch/ppc/platforms/est8260.h
--- a/arch/ppc/platforms/est8260.h	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/platforms/est8260.h	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,3 @@
-/*
- * BK Id: SCCS/s.est8260.h 1.5 05/17/01 18:14:24 cort
- */
-
 /* Board information for the EST8260, which should be generic for
  * all 8260 boards.  The IMMR is now given to us so the hard define
  * will soon be removed.  All of the clock values are computed from
diff -Nru a/arch/ppc/platforms/fads.h b/arch/ppc/platforms/fads.h
--- a/arch/ppc/platforms/fads.h	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/platforms/fads.h	Fri Sep 20 08:20:41 2002
@@ -1,8 +1,4 @@
 /*
- * BK Id: SCCS/s.fads.h 1.14 10/26/01 10:14:09 trini
- */
-
-/*
  * A collection of structures, addresses, and values associated with
  * the Motorola 860T FADS board.  Copied from the MBX stuff.
  *
diff -Nru a/arch/ppc/platforms/gemini.h b/arch/ppc/platforms/gemini.h
--- a/arch/ppc/platforms/gemini.h	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/platforms/gemini.h	Fri Sep 20 08:20:46 2002
@@ -1,8 +1,5 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- *  include/asm-ppc/platforms/gemini.h
+ *  arch/ppc/platforms/gemini.h
  *
  *
  *  Onboard registers and descriptions for Synergy Microsystems' 
diff -Nru a/arch/ppc/platforms/gemini_pci.c b/arch/ppc/platforms/gemini_pci.c
--- a/arch/ppc/platforms/gemini_pci.c	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/platforms/gemini_pci.c	Fri Sep 20 08:20:44 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/pci.h>
diff -Nru a/arch/ppc/platforms/gemini_prom.S b/arch/ppc/platforms/gemini_prom.S
--- a/arch/ppc/platforms/gemini_prom.S	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/platforms/gemini_prom.S	Fri Sep 20 08:20:47 2002
@@ -1,8 +1,5 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- *  arch/ppc/kernel/gemini_prom.S
+ *  arch/ppc/platforms/gemini_prom.S
  *
  *  Not really prom support code (yet), but sort of anti-prom code.  The current
  *  bootloader does a number of things it shouldn't and doesn't do things that it
diff -Nru a/arch/ppc/platforms/gemini_serial.h b/arch/ppc/platforms/gemini_serial.h
--- a/arch/ppc/platforms/gemini_serial.h	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/platforms/gemini_serial.h	Fri Sep 20 08:20:44 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifdef __KERNEL__
 #ifndef __ASMPPC_GEMINI_SERIAL_H
 #define __ASMPPC_GEMINI_SERIAL_H
diff -Nru a/arch/ppc/platforms/gemini_setup.c b/arch/ppc/platforms/gemini_setup.c
--- a/arch/ppc/platforms/gemini_setup.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/platforms/gemini_setup.c	Fri Sep 20 08:20:46 2002
@@ -1,8 +1,5 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- *  arch/ppc/platforms/setup.c
+ *  arch/ppc/platforms/gemini_setup.c
  *
  *  Copyright (C) 1995 Linus Torvalds
  *  Adapted from 'alpha' version by Gary Thomas
diff -Nru a/arch/ppc/platforms/iSeries_pic.c b/arch/ppc/platforms/iSeries_pic.c
--- a/arch/ppc/platforms/iSeries_pic.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/platforms/iSeries_pic.c	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platforms/iSeries_pic.c
  *
  */
diff -Nru a/arch/ppc/platforms/iSeries_smp.c b/arch/ppc/platforms/iSeries_smp.c
--- a/arch/ppc/platforms/iSeries_smp.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/platforms/iSeries_smp.c	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * SMP support for iSeries/LPAR.
  *
  * Copyright (C) 2001 IBM Corp.
diff -Nru a/arch/ppc/platforms/iSeries_time.c b/arch/ppc/platforms/iSeries_time.c
--- a/arch/ppc/platforms/iSeries_time.c	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/platforms/iSeries_time.c	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Time routes for iSeries LPAR.
  *
  * Copyright (C) 2001 IBM Corp.
diff -Nru a/arch/ppc/platforms/ivms8.h b/arch/ppc/platforms/ivms8.h
--- a/arch/ppc/platforms/ivms8.h	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/platforms/ivms8.h	Fri Sep 20 08:20:46 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.ivms8.h 1.8 10/26/01 10:14:09 trini
- */
-/*
  * Speech Design Integrated Voicemail board specific definitions
  * - IVMS8  (small,  8 channels)
  * - IVML24 (large, 24 channels)
diff -Nru a/arch/ppc/platforms/mbx.h b/arch/ppc/platforms/mbx.h
--- a/arch/ppc/platforms/mbx.h	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/platforms/mbx.h	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.mbx.h 1.11 08/17/01 15:23:17 paulus
- */
-/*
  * A collection of structures, addresses, and values associated with
  * the Motorola MBX boards.  This was originally created for the
  * MBX860, and probably needs revisions for other boards (like the 821).
diff -Nru a/arch/ppc/platforms/oak.h b/arch/ppc/platforms/oak.h
--- a/arch/ppc/platforms/oak.h	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/platforms/oak.h	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *
  *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
  *
diff -Nru a/arch/ppc/platforms/oak_setup.c b/arch/ppc/platforms/oak_setup.c
--- a/arch/ppc/platforms/oak_setup.c	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc/platforms/oak_setup.c	Fri Sep 20 08:20:43 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *
  *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
  *
diff -Nru a/arch/ppc/platforms/oak_setup.h b/arch/ppc/platforms/oak_setup.h
--- a/arch/ppc/platforms/oak_setup.h	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/platforms/oak_setup.h	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.oak_setup.h 1.5 05/17/01 18:14:21 cort
- */
-/*
  *
  *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
  *
diff -Nru a/arch/ppc/platforms/pmac_backlight.c b/arch/ppc/platforms/pmac_backlight.c
--- a/arch/ppc/platforms/pmac_backlight.c	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc/platforms/pmac_backlight.c	Fri Sep 20 08:20:48 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Miscellaneous procedures for dealing with the PowerMac hardware.
  * Contains support for the backlight.
  * 
diff -Nru a/arch/ppc/platforms/pmac_feature.c b/arch/ppc/platforms/pmac_feature.c
--- a/arch/ppc/platforms/pmac_feature.c	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/platforms/pmac_feature.c	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platforms/pmac_feature.c
  *
  *  Copyright (C) 1996-2001 Paul Mackerras (paulus@cs.anu.edu.au)
diff -Nru a/arch/ppc/platforms/pmac_nvram.c b/arch/ppc/platforms/pmac_nvram.c
--- a/arch/ppc/platforms/pmac_nvram.c	Fri Sep 20 08:20:45 2002
+++ b/arch/ppc/platforms/pmac_nvram.c	Fri Sep 20 08:20:45 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platforms/pmac_nvram.c
  *
  *  Copyright (C) 2002 Benjamin Herrenschmidt (benh@kernel.crashing.org)
diff -Nru a/arch/ppc/platforms/pmac_pci.c b/arch/ppc/platforms/pmac_pci.c
--- a/arch/ppc/platforms/pmac_pci.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/platforms/pmac_pci.c	Fri Sep 20 08:20:46 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Support for PCI bridges found on Power Macintoshes.
  * 
  * This includes support for bandit, chaos, grackle (motorola
diff -Nru a/arch/ppc/platforms/pmac_pic.c b/arch/ppc/platforms/pmac_pic.c
--- a/arch/ppc/platforms/pmac_pic.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/platforms/pmac_pic.c	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  Support for the interrupt controllers found on Power Macintosh,
  *  currently Apple's "Grand Central" interrupt controller in all
  *  it's incarnations. OpenPIC support used on newer machines is
diff -Nru a/arch/ppc/platforms/pmac_pic.h b/arch/ppc/platforms/pmac_pic.h
--- a/arch/ppc/platforms/pmac_pic.h	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/platforms/pmac_pic.h	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifndef __PPC_PLATFORMS_PMAC_PIC_H
 #define __PPC_PLATFORMS_PMAC_PIC_H
 
diff -Nru a/arch/ppc/platforms/pmac_setup.c b/arch/ppc/platforms/pmac_setup.c
--- a/arch/ppc/platforms/pmac_setup.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/platforms/pmac_setup.c	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platforms/setup.c
  *
  *  PowerPC version 
diff -Nru a/arch/ppc/platforms/pmac_smp.c b/arch/ppc/platforms/pmac_smp.c
--- a/arch/ppc/platforms/pmac_smp.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/platforms/pmac_smp.c	Fri Sep 20 08:20:46 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * SMP support for power macintosh.
  *
  * We support both the old "powersurge" SMP architecture
diff -Nru a/arch/ppc/platforms/pmac_time.c b/arch/ppc/platforms/pmac_time.c
--- a/arch/ppc/platforms/pmac_time.c	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/platforms/pmac_time.c	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Support for periodic interrupts (100 per second) and for getting
  * the current time from the RTC on Power Macintoshes.
  *
diff -Nru a/arch/ppc/platforms/prep_pci.c b/arch/ppc/platforms/prep_pci.c
--- a/arch/ppc/platforms/prep_pci.c	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc/platforms/prep_pci.c	Fri Sep 20 08:20:48 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * PReP pci functions.
  * Originally by Gary Thomas
  * rewritten and updated by Cort Dougan (cort@cs.nmt.edu)
diff -Nru a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c
--- a/arch/ppc/platforms/prep_setup.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/platforms/prep_setup.c	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platforms/setup.c
  *
  *  Copyright (C) 1995  Linus Torvalds
diff -Nru a/arch/ppc/platforms/prep_time.c b/arch/ppc/platforms/prep_time.c
--- a/arch/ppc/platforms/prep_time.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/platforms/prep_time.c	Fri Sep 20 08:20:46 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  arch/ppc/platforms/prep_time.c
  *
  *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
diff -Nru a/arch/ppc/platforms/proc_rtas.c b/arch/ppc/platforms/proc_rtas.c
--- a/arch/ppc/platforms/proc_rtas.c	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc/platforms/proc_rtas.c	Fri Sep 20 08:20:48 2002
@@ -1,8 +1,5 @@
 /*
- * BK Id: SCCS/s.proc_rtas.c 1.5 05/17/01 18:14:22 cort
- */
-/*
- *   arch/ppc/kernel/proc_rtas.c
+ *   arch/ppc/platforms/proc_rtas.c
  *   Copyright (C) 2000 Tilmann Bitterberg
  *   (tilmann@bitterberg.de)
  *
diff -Nru a/arch/ppc/platforms/residual.c b/arch/ppc/platforms/residual.c
--- a/arch/ppc/platforms/residual.c	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc/platforms/residual.c	Fri Sep 20 08:20:43 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.residual.c 1.13 09/11/01 16:54:34 trini
- */
-/*
  * Code to deal with the PReP residual data.
  *
  * Written by: Cort Dougan (cort@cs.nmt.edu)
diff -Nru a/arch/ppc/platforms/rpxclassic.h b/arch/ppc/platforms/rpxclassic.h
--- a/arch/ppc/platforms/rpxclassic.h	Fri Sep 20 08:20:42 2002
+++ b/arch/ppc/platforms/rpxclassic.h	Fri Sep 20 08:20:42 2002
@@ -1,8 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
-/*
  * A collection of structures, addresses, and values associated with
  * the RPCG RPX-Classic board.  Copied from the RPX-Lite stuff.
  *
diff -Nru a/arch/ppc/platforms/rpxhiox.h b/arch/ppc/platforms/rpxhiox.h
--- a/arch/ppc/platforms/rpxhiox.h	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/platforms/rpxhiox.h	Fri Sep 20 08:20:47 2002
@@ -1,8 +1,4 @@
 /*
- * BK Id: SCCS/s.rpxhiox.h 1.3 05/17/01 18:14:25 cort
- */
-
-/*
  * The Embedded Planet HIOX expansion card definitions.
  * There were a few different versions of these cards, but only
  * the one that escaped real production is defined here.
diff -Nru a/arch/ppc/platforms/rpxlite.h b/arch/ppc/platforms/rpxlite.h
--- a/arch/ppc/platforms/rpxlite.h	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/platforms/rpxlite.h	Fri Sep 20 08:20:41 2002
@@ -1,8 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
-/*
  * A collection of structures, addresses, and values associated with
  * the RPCG RPX-Lite board.  Copied from the MBX stuff.
  *
diff -Nru a/arch/ppc/platforms/sleep.S b/arch/ppc/platforms/sleep.S
--- a/arch/ppc/platforms/sleep.S	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/platforms/sleep.S	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * This file contains sleep low-level functions for PowerBook G3.
  *    Copyright (C) 1999 Benjamin Herrenschmidt (benh@kernel.crashing.org)
  *    and Paul Mackerras (paulus@samba.org).
diff -Nru a/arch/ppc/platforms/spd8xx.h b/arch/ppc/platforms/spd8xx.h
--- a/arch/ppc/platforms/spd8xx.h	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/platforms/spd8xx.h	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.spd8xx.h 1.8 10/27/01 13:39:41 trini
- */
-/*
  * Speech Design SPD8xxTS board specific definitions
  * 
  * Copyright (c) 2000,2001 Wolfgang Denk (wd@denx.de)
diff -Nru a/arch/ppc/platforms/tqm8xx.h b/arch/ppc/platforms/tqm8xx.h
--- a/arch/ppc/platforms/tqm8xx.h	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/platforms/tqm8xx.h	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.tqm8xx.h 1.8 08/30/01 09:01:04 trini
- */
-/*
  * TQM8xx(L) board specific definitions
  * 
  * Copyright (c) 1999,2000,2001 Wolfgang Denk (wd@denx.de)
diff -Nru a/arch/ppc/xmon/Makefile b/arch/ppc/xmon/Makefile
--- a/arch/ppc/xmon/Makefile	Fri Sep 20 08:20:42 2002
+++ b/arch/ppc/xmon/Makefile	Fri Sep 20 08:20:42 2002
@@ -1,5 +1,3 @@
-# BK Id: SCCS/s.Makefile 1.6 06/27/01 14:49:58 trini
-#
 # Makefile for xmon
 
 O_TARGET	:= x.o
diff -Nru a/arch/ppc/xmon/adb.c b/arch/ppc/xmon/adb.c
--- a/arch/ppc/xmon/adb.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/xmon/adb.c	Fri Sep 20 08:20:46 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.adb.c 1.5 05/17/01 18:14:23 cort
- */
-/*
  * Copyright (C) 1996 Paul Mackerras.
  */
 #include "nonstdio.h"
diff -Nru a/arch/ppc/xmon/ansidecl.h b/arch/ppc/xmon/ansidecl.h
--- a/arch/ppc/xmon/ansidecl.h	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc/xmon/ansidecl.h	Fri Sep 20 08:20:48 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.ansidecl.h 1.5 05/17/01 18:14:23 cort
- */
 /* ANSI and traditional C compatability macros
    Copyright 1991, 1992 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
diff -Nru a/arch/ppc/xmon/nonstdio.h b/arch/ppc/xmon/nonstdio.h
--- a/arch/ppc/xmon/nonstdio.h	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc/xmon/nonstdio.h	Fri Sep 20 08:20:46 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 typedef int	FILE;
 extern FILE *xmon_stdin, *xmon_stdout;
 #define EOF	(-1)
diff -Nru a/arch/ppc/xmon/ppc-dis.c b/arch/ppc/xmon/ppc-dis.c
--- a/arch/ppc/xmon/ppc-dis.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/xmon/ppc-dis.c	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.ppc-dis.c 1.5 05/17/01 18:14:23 cort
- */
 /* ppc-dis.c -- Disassemble PowerPC instructions
    Copyright 1994 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support
diff -Nru a/arch/ppc/xmon/ppc-opc.c b/arch/ppc/xmon/ppc-opc.c
--- a/arch/ppc/xmon/ppc-opc.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/xmon/ppc-opc.c	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.ppc-opc.c 1.5 05/17/01 18:14:23 cort
- */
 /* ppc-opc.c -- PowerPC opcode list
    Copyright 1994 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support
diff -Nru a/arch/ppc/xmon/ppc.h b/arch/ppc/xmon/ppc.h
--- a/arch/ppc/xmon/ppc.h	Fri Sep 20 08:20:45 2002
+++ b/arch/ppc/xmon/ppc.h	Fri Sep 20 08:20:45 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.ppc.h 1.5 05/17/01 18:14:23 cort
- */
 /* ppc.h -- Header file for PowerPC opcode table
    Copyright 1994 Free Software Foundation, Inc.
    Written by Ian Lance Taylor, Cygnus Support
diff -Nru a/arch/ppc/xmon/privinst.h b/arch/ppc/xmon/privinst.h
--- a/arch/ppc/xmon/privinst.h	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc/xmon/privinst.h	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.privinst.h 1.5 05/17/01 18:14:23 cort
- */
-/*
  * Copyright (C) 1996 Paul Mackerras.
  */
 #include <linux/config.h>
diff -Nru a/arch/ppc/xmon/setjmp.c b/arch/ppc/xmon/setjmp.c
--- a/arch/ppc/xmon/setjmp.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/xmon/setjmp.c	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.setjmp.c 1.5 05/17/01 18:14:23 cort
- */
-/*
  * Copyright (C) 1996 Paul Mackerras.
  *
  * NB this file must be compiled with -O2.
diff -Nru a/arch/ppc/xmon/start.c b/arch/ppc/xmon/start.c
--- a/arch/ppc/xmon/start.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/xmon/start.c	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Copyright (C) 1996 Paul Mackerras.
  */
 #include <linux/config.h>
diff -Nru a/arch/ppc/xmon/start_8xx.c b/arch/ppc/xmon/start_8xx.c
--- a/arch/ppc/xmon/start_8xx.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/xmon/start_8xx.c	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.start_8xx.c 1.10 09/14/01 18:01:17 trini
- */
-/*
  * Copyright (C) 1996 Paul Mackerras.
  * Copyright (C) 2000 Dan Malek.
  * Quick hack of Paul's code to make XMON work on 8xx processors.  Lots
diff -Nru a/arch/ppc/xmon/subr_prf.c b/arch/ppc/xmon/subr_prf.c
--- a/arch/ppc/xmon/subr_prf.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc/xmon/subr_prf.c	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Written by Cort Dougan to replace the version originally used
  * by Paul Mackerras, which came from NetBSD and thus had copyright
  * conflicts with Linux.
diff -Nru a/arch/ppc/xmon/xmon.c b/arch/ppc/xmon/xmon.c
--- a/arch/ppc/xmon/xmon.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc/xmon/xmon.c	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Routines providing a simple monitor for use on the PowerMac.
  *
  * Copyright (C) 1996 Paul Mackerras.
diff -Nru a/arch/ppc64/Makefile b/arch/ppc64/Makefile
--- a/arch/ppc64/Makefile	Fri Sep 20 08:20:42 2002
+++ b/arch/ppc64/Makefile	Fri Sep 20 08:20:42 2002
@@ -62,7 +62,22 @@
 	cp -f arch/ppc64/configs/$(@:config=defconfig) arch/ppc64/defconfig
 
 archclean:
-	rm -f arch/ppc64/kernel/{ppc_defs.h,mk_defs.s,mk_defs_out.c,mk_defs_tpl}
 	@$(MAKEBOOT) clean
 
 archmrproper:
+
+
+prepare: include/asm-$(ARCH)/offsets.h
+
+arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \
+				   include/config/MARKER
+
+include/asm-$(ARCH)/offsets.h.tmp: arch/$(ARCH)/kernel/asm-offsets.s
+	@$(generate-asm-offsets.h) < $< > $@
+
+include/asm-$(ARCH)/offsets.h: include/asm-$(ARCH)/offsets.h.tmp
+	@echo -n '  Generating $@'
+	@$(update-if-changed)
+
+CLEAN_FILES += include/asm-$(ARCH)/offsets.h.tmp \
+	       include/asm-$(ARCH)/offsets.h
diff -Nru a/arch/ppc64/kernel/LparData.c b/arch/ppc64/kernel/LparData.c
--- a/arch/ppc64/kernel/LparData.c	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc64/kernel/LparData.c	Fri Sep 20 08:20:43 2002
@@ -6,7 +6,6 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
-#define __KERNEL__ 1
 #include <asm/types.h>
 #include <asm/page.h>
 #include <stddef.h>
@@ -248,8 +247,3 @@
 
 	return mem;
 }
-
-
-
-
-
diff -Nru a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile
--- a/arch/ppc64/kernel/Makefile	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc64/kernel/Makefile	Fri Sep 20 08:20:48 2002
@@ -40,25 +40,3 @@
 
 include $(TOPDIR)/Rules.make
 
-#
-# This is just to get the dependencies...
-#
-
-head.o: head.S ppc_defs.h
-misc.o: misc.S ppc_defs.h
-entry.o: entry.S ppc_defs.h
-hvCall.o: hvCall.S ppc_defs.h
-pSeries_hvCall.o: pSeries_hvCall.S ppc_defs.h
-sys32.o: sys32.S ppc_defs.h
-
-ppc_defs.h: mk_defs.c ppc_defs.head \
-		$(TOPDIR)/include/asm/mmu.h \
-		$(TOPDIR)/include/asm/processor.h \
-		$(TOPDIR)/include/asm/pgtable.h \
-		$(TOPDIR)/include/asm/ptrace.h
-	$(CC) $(CFLAGS) -S mk_defs.c
-	cp ppc_defs.head ppc_defs.h
-# for bk, this way we can write to the file even if it's not checked out
-	chmod u+w ppc_defs.h
-	grep '^#define' mk_defs.s >> ppc_defs.h
-	rm mk_defs.s
diff -Nru a/arch/ppc64/kernel/asm-offsets.c b/arch/ppc64/kernel/asm-offsets.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc64/kernel/asm-offsets.c	Fri Sep 20 08:20:47 2002
@@ -0,0 +1,162 @@
+/*
+ * This program is used to generate definitions needed by
+ * assembly language modules.
+ *
+ * We use the technique used in the OSF Mach kernel code:
+ * generate asm statements containing #defines,
+ * compile this file to assembler, and then extract the
+ * #defines from the assembly-language output.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/hardirq.h>
+
+#include <asm/naca.h>
+#include <asm/paca.h>
+#include <asm/iSeries/ItLpPaca.h>
+#include <asm/iSeries/ItLpQueue.h>
+#include <asm/iSeries/HvLpEvent.h>
+#include <asm/prom.h>
+#include <asm/rtas.h>
+
+#define DEFINE(sym, val) \
+	asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define BLANK() asm volatile("\n->" : : )
+
+int main(void)
+{
+	/* thread struct on stack */
+	DEFINE(THREAD_SHIFT, THREAD_SHIFT);
+	DEFINE(THREAD_SIZE, THREAD_SIZE);
+	DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
+
+	/* task_struct->thread */
+	DEFINE(THREAD, offsetof(struct task_struct, thread));
+	DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
+	DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode));
+	DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0]));
+	DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr));
+	DEFINE(KSP, offsetof(struct thread_struct, ksp));
+
+	DEFINE(MM, offsetof(struct task_struct, mm));
+
+	/* naca */
+        DEFINE(PACA, offsetof(struct naca_struct, paca));
+	DEFINE(DCACHEL1LINESIZE, offsetof(struct naca_struct, dCacheL1LineSize));
+        DEFINE(DCACHEL1LOGLINESIZE, offsetof(struct naca_struct, dCacheL1LogLineSize));
+        DEFINE(DCACHEL1LINESPERPAGE, offsetof(struct naca_struct, dCacheL1LinesPerPage));
+        DEFINE(ICACHEL1LINESIZE, offsetof(struct naca_struct, iCacheL1LineSize));
+        DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct naca_struct, iCacheL1LogLineSize));
+        DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct naca_struct, iCacheL1LinesPerPage));
+	DEFINE(SLBSIZE, offsetof(struct naca_struct, slb_size));
+	DEFINE(PLATFORM, offsetof(struct naca_struct, platform));
+
+	/* paca */
+        DEFINE(PACA_SIZE, sizeof(struct paca_struct));
+        DEFINE(PACAPACAINDEX, offsetof(struct paca_struct, xPacaIndex));
+        DEFINE(PACAPROCSTART, offsetof(struct paca_struct, xProcStart));
+        DEFINE(PACAKSAVE, offsetof(struct paca_struct, xKsave));
+	DEFINE(PACACURRENT, offsetof(struct paca_struct, xCurrent));
+        DEFINE(PACASAVEDMSR, offsetof(struct paca_struct, xSavedMsr));
+        DEFINE(PACASTABREAL, offsetof(struct paca_struct, xStab_data.real));
+        DEFINE(PACASTABVIRT, offsetof(struct paca_struct, xStab_data.virt));
+	DEFINE(PACASTABRR, offsetof(struct paca_struct, xStab_data.next_round_robin));
+        DEFINE(PACAR1, offsetof(struct paca_struct, xR1));
+        DEFINE(PACALPQUEUE, offsetof(struct paca_struct, lpQueuePtr));
+	DEFINE(PACATOC, offsetof(struct paca_struct, xTOC));
+	DEFINE(PACAEXCSP, offsetof(struct paca_struct, exception_sp));
+	DEFINE(PACAHRDWINTSTACK, offsetof(struct paca_struct, xHrdIntStack));
+	DEFINE(PACAPROCENABLED, offsetof(struct paca_struct, xProcEnabled));
+	DEFINE(PACAHRDWINTCOUNT, offsetof(struct paca_struct, xHrdIntCount));
+	DEFINE(PACADEFAULTDECR, offsetof(struct paca_struct, default_decr));
+	DEFINE(PACAPROFENABLED, offsetof(struct paca_struct, prof_enabled));
+	DEFINE(PACAPROFLEN, offsetof(struct paca_struct, prof_len));
+	DEFINE(PACAPROFSHIFT, offsetof(struct paca_struct, prof_shift));
+	DEFINE(PACAPROFBUFFER, offsetof(struct paca_struct, prof_buffer));
+	DEFINE(PACAPROFSTEXT, offsetof(struct paca_struct, prof_stext));
+	DEFINE(PACALPPACA, offsetof(struct paca_struct, xLpPaca));
+        DEFINE(LPPACA, offsetof(struct paca_struct, xLpPaca));
+        DEFINE(PACAREGSAV, offsetof(struct paca_struct, xRegSav));
+        DEFINE(PACAEXC, offsetof(struct paca_struct, exception_stack));
+        DEFINE(PACAGUARD, offsetof(struct paca_struct, guard));
+        DEFINE(LPPACASRR0, offsetof(struct ItLpPaca, xSavedSrr0));
+        DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1));
+	DEFINE(LPPACAANYINT, offsetof(struct ItLpPaca, xIntDword.xAnyInt));
+	DEFINE(LPPACADECRINT, offsetof(struct ItLpPaca, xIntDword.xFields.xDecrInt));
+        DEFINE(LPQCUREVENTPTR, offsetof(struct ItLpQueue, xSlicCurEventPtr));
+        DEFINE(LPQOVERFLOW, offsetof(struct ItLpQueue, xPlicOverflowIntPending));
+        DEFINE(LPEVENTFLAGS, offsetof(struct HvLpEvent, xFlags));
+	DEFINE(PROMENTRY, offsetof(struct prom_t, entry));
+
+	/* RTAS */
+	DEFINE(RTASBASE, offsetof(struct rtas_t, base));
+	DEFINE(RTASENTRY, offsetof(struct rtas_t, entry));
+	DEFINE(RTASSIZE, offsetof(struct rtas_t, size));
+
+	/* Interrupt register frame */
+	DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
+
+	DEFINE(SWITCH_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs));
+
+	/* 288 = # of volatile regs, int & fp, for leaf routines */
+	/* which do not stack a frame.  See the PPC64 ABI.       */
+	DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 288);
+	/* Create extra stack space for SRR0 and SRR1 when calling prom/rtas. */
+	DEFINE(PROM_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16);
+	DEFINE(RTAS_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16);
+	DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0]));
+	DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1]));
+	DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2]));
+	DEFINE(GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[3]));
+	DEFINE(GPR4, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[4]));
+	DEFINE(GPR5, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[5]));
+	DEFINE(GPR6, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[6]));
+	DEFINE(GPR7, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[7]));
+	DEFINE(GPR8, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[8]));
+	DEFINE(GPR9, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[9]));
+	DEFINE(GPR20, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[20]));
+	DEFINE(GPR21, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[21]));
+	DEFINE(GPR22, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[22]));
+	DEFINE(GPR23, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[23]));
+	/*
+	 * Note: these symbols include _ because they overlap with special
+	 * register names
+	 */
+	DEFINE(_NIP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, nip));
+	DEFINE(_MSR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, msr));
+	DEFINE(_CTR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ctr));
+	DEFINE(_LINK, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, link));
+	DEFINE(_CCR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ccr));
+	DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer));
+	DEFINE(_DAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar));
+	DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr));
+	DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3));
+	DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result));
+	DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap));
+	DEFINE(SOFTE, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, softe));
+
+	/* These _only_ to be used with {PROM,RTAS}_FRAME_SIZE!!! */
+	DEFINE(_SRR0, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs));
+	DEFINE(_SRR1, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)+8);
+
+	DEFINE(CLONE_VM, CLONE_VM);
+
+	return 0;
+}
diff -Nru a/arch/ppc64/kernel/chrp_setup.c b/arch/ppc64/kernel/chrp_setup.c
--- a/arch/ppc64/kernel/chrp_setup.c	Fri Sep 20 08:20:42 2002
+++ b/arch/ppc64/kernel/chrp_setup.c	Fri Sep 20 08:20:42 2002
@@ -58,7 +58,6 @@
 #include <asm/naca.h>
 #include <asm/time.h>
 
-#include "local_irq.h"
 #include "i8259.h"
 #include "open_pic.h"
 #include "xics.h"
@@ -66,7 +65,6 @@
 
 extern volatile unsigned char *chrp_int_ack_special;
 
-void chrp_setup_pci_ptrs(void);
 void chrp_progress(char *, unsigned short);
 void chrp_request_regions(void);
 
@@ -237,8 +235,6 @@
 #endif /* CONFIG_BLK_DEV_INITRD */
 #endif
 
-	ppc_md.ppc_machine = naca->platform;
-
 	ppc_md.setup_arch     = chrp_setup_arch;
 	ppc_md.setup_residual = NULL;
 	ppc_md.get_cpuinfo    = chrp_get_cpuinfo;
@@ -265,7 +261,6 @@
 	ppc_md.power_off      = rtas_power_off;
 	ppc_md.halt           = rtas_halt;
 
-	ppc_md.time_init      = NULL;
 	ppc_md.get_boot_time  = pSeries_get_rtc_time;
 	ppc_md.get_rtc_time   = pSeries_get_rtc_time;
 	ppc_md.set_rtc_time   = pSeries_set_rtc_time;
diff -Nru a/arch/ppc64/kernel/entry.S b/arch/ppc64/kernel/entry.S
--- a/arch/ppc64/kernel/entry.S	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc64/kernel/entry.S	Fri Sep 20 08:20:41 2002
@@ -20,14 +20,15 @@
  *  2 of the License, or (at your option) any later version.
  */
 
-#include "ppc_asm.h"
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sys.h>
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/mmu.h>
 #include <asm/thread_info.h>
-#include <linux/errno.h>
-#include <linux/sys.h>
-#include <linux/config.h>
+#include <asm/ppc_asm.h>
+#include <asm/offsets.h>
 
 #ifdef CONFIG_PPC_ISERIES
 #define DO_SOFT_DISABLE
diff -Nru a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S
--- a/arch/ppc64/kernel/head.S	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc64/kernel/head.S	Fri Sep 20 08:20:46 2002
@@ -25,12 +25,12 @@
 
 #define SECONDARY_PROCESSORS
 
-#include "ppc_asm.h"
-#include "ppc_defs.h"
+#include <linux/config.h>
 #include <asm/processor.h>
 #include <asm/page.h>
-#include <linux/config.h>
 #include <asm/mmu.h>
+#include <asm/ppc_asm.h>
+#include <asm/offsets.h>
 
 #ifdef CONFIG_PPC_ISERIES
 #define DO_SOFT_DISABLE
@@ -90,7 +90,9 @@
 	 * between physical addresses and absolute addresses) and
 	 * to the pidhash table (also used by the debugger) */
 	.llong msChunks-KERNELBASE
+#ifdef CONFIG_PPC_ISERIES
 	.llong pidhash-KERNELBASE
+#endif
 
 	/* Offset 0x38 - Pointer to start of embedded System.map */
 	.globl	embedded_sysmap_start
diff -Nru a/arch/ppc64/kernel/htab.c b/arch/ppc64/kernel/htab.c
--- a/arch/ppc64/kernel/htab.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc64/kernel/htab.c	Fri Sep 20 08:20:47 2002
@@ -43,6 +43,7 @@
 #include <asm/lmb.h>
 #include <asm/abs_addr.h>
 #include <asm/tlbflush.h>
+#include <asm/io.h>
 #include <asm/eeh.h>
 #include <asm/tlb.h>
 
diff -Nru a/arch/ppc64/kernel/hvCall.S b/arch/ppc64/kernel/hvCall.S
--- a/arch/ppc64/kernel/hvCall.S	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc64/kernel/hvCall.S	Fri Sep 20 08:20:46 2002
@@ -11,9 +11,8 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#include "ppc_asm.h"
+#include <asm/ppc_asm.h>
 #include <asm/processor.h>
-#include <linux/config.h>
 
 	.text
 
diff -Nru a/arch/ppc64/kernel/i8259.h b/arch/ppc64/kernel/i8259.h
--- a/arch/ppc64/kernel/i8259.h	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc64/kernel/i8259.h	Fri Sep 20 08:20:43 2002
@@ -9,8 +9,6 @@
 #ifndef _PPC_KERNEL_i8259_H
 #define _PPC_KERNEL_i8259_H
 
-#include "local_irq.h"
-
 extern struct hw_interrupt_type i8259_pic;
 
 void i8259_init(void);
diff -Nru a/arch/ppc64/kernel/iSeries_VpdInfo.c b/arch/ppc64/kernel/iSeries_VpdInfo.c
--- a/arch/ppc64/kernel/iSeries_VpdInfo.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc64/kernel/iSeries_VpdInfo.c	Fri Sep 20 08:20:41 2002
@@ -34,7 +34,6 @@
 #include <asm/iSeries/HvTypes.h>
 #include <asm/iSeries/mf.h>
 #include <asm/iSeries/LparData.h>
-#include <asm/iSeries/HvCallPci.h>
 //#include <asm/iSeries/iSeries_VpdInfo.h>
 #include <asm/iSeries/iSeries_pci.h>
 #include "pci.h"
diff -Nru a/arch/ppc64/kernel/iSeries_pci.c b/arch/ppc64/kernel/iSeries_pci.c
--- a/arch/ppc64/kernel/iSeries_pci.c	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc64/kernel/iSeries_pci.c	Fri Sep 20 08:20:48 2002
@@ -55,7 +55,6 @@
 extern int    panic_timeout;
 
 extern struct device_node *allnodes;
-extern unsigned long phb_tce_table_init(struct pci_controller *phb);
 extern unsigned long iSeries_Base_Io_Memory;    
 
 extern struct pci_ops iSeries_pci_ops;
diff -Nru a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c
--- a/arch/ppc64/kernel/iSeries_setup.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc64/kernel/iSeries_setup.c	Fri Sep 20 08:20:47 2002
@@ -312,7 +312,6 @@
 	ppc_md.setup_arch	 	= iSeries_setup_arch;
 	ppc_md.setup_residual	 	= iSeries_setup_residual;
 	ppc_md.get_cpuinfo	 	= iSeries_get_cpuinfo;
-	ppc_md.irq_cannonicalize 	= NULL;
 	ppc_md.init_IRQ		 	= iSeries_init_IRQ;
 	ppc_md.init_ras_IRQ		= NULL;
 	ppc_md.get_irq		 	= iSeries_get_irq;
@@ -325,8 +324,7 @@
 	ppc_md.power_off	 	= iSeries_power_off;
 	ppc_md.halt		 	= iSeries_halt;
 
-	ppc_md.time_init	 	= NULL;
-	ppc_md.get_boot_time    = iSeries_get_boot_time;
+	ppc_md.get_boot_time		= iSeries_get_boot_time;
 	ppc_md.set_rtc_time	 	= iSeries_set_rtc_time;
 	ppc_md.get_rtc_time	 	= iSeries_get_rtc_time;
 	ppc_md.calibrate_decr	 	= iSeries_calibrate_decr;
@@ -782,15 +780,6 @@
 iSeries_halt(void)
 {
 	mf_powerOff();
-}
-
-/*
- * Nothing to do here.
- */
-void __init
-iSeries_time_init(void)
-{
-	/* Nothing to do */
 }
 
 /* JDH Hack */
diff -Nru a/arch/ppc64/kernel/irq.c b/arch/ppc64/kernel/irq.c
--- a/arch/ppc64/kernel/irq.c	Fri Sep 20 08:20:45 2002
+++ b/arch/ppc64/kernel/irq.c	Fri Sep 20 08:20:45 2002
@@ -53,8 +53,6 @@
 #include <asm/machdep.h>
 #include <asm/paca.h>
 
-#include "local_irq.h"
-
 void enable_irq(unsigned int irq_nr);
 void disable_irq(unsigned int irq_nr);
 
@@ -69,7 +67,6 @@
 	{ [0 ... NR_IRQS-1] = { 0, NULL, NULL, 0, SPIN_LOCK_UNLOCKED}};
 	
 int ppc_spurious_interrupts = 0;
-struct irqaction *ppc_irq_action[NR_IRQS];
 unsigned long lpEvent_count = 0;
 
 /* nasty hack for shared irq's since we need to do kmalloc calls but
diff -Nru a/arch/ppc64/kernel/lmb.c b/arch/ppc64/kernel/lmb.c
--- a/arch/ppc64/kernel/lmb.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc64/kernel/lmb.c	Fri Sep 20 08:20:46 2002
@@ -287,7 +287,7 @@
 			continue;
 
 		if ( max_addr == LMB_ALLOC_ANYWHERE )
-		base = _ALIGN_DOWN(lmbbase+lmbsize-size, align);
+			base = _ALIGN_DOWN(lmbbase+lmbsize-size, align);
 		else if ( lmbbase < max_addr )
 			base = _ALIGN_DOWN(min(lmbbase+lmbsize,max_addr)-size, align);
 		else
diff -Nru a/arch/ppc64/kernel/local_irq.h b/arch/ppc64/kernel/local_irq.h
--- a/arch/ppc64/kernel/local_irq.h	Fri Sep 20 08:20:42 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,26 +0,0 @@
-/*
- *      c 2001 PowerPC 64 Team, IBM Corp
- *
- *      This program is free software; you can redistribute it and/or
- *      modify it under the terms of the GNU General Public License
- *      as published by the Free Software Foundation; either version
- *      2 of the License, or (at your option) any later version.
- */
-#ifndef _PPC_KERNEL_LOCAL_IRQ_H
-#define _PPC_KERNEL_LOCAL_IRQ_H
-
-#include <linux/kernel_stat.h>
-#include <linux/interrupt.h>
-#include <linux/cache.h>
-#include <linux/spinlock.h>
-#include <linux/irq.h>
-
-void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq);
-
-#define NR_MASK_WORDS	((NR_IRQS + 63) / 64)
-
-extern int ppc_spurious_interrupts;
-extern int ppc_second_irq;
-extern struct irqaction *ppc_irq_action[NR_IRQS];
-
-#endif /* _PPC_KERNEL_LOCAL_IRQ_H */
diff -Nru a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S
--- a/arch/ppc64/kernel/misc.S	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc64/kernel/misc.S	Fri Sep 20 08:20:44 2002
@@ -25,7 +25,8 @@
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/cache.h>
-#include "ppc_asm.h"
+#include <asm/ppc_asm.h>
+#include <asm/offsets.h>
 
 	.text
 
@@ -563,7 +564,7 @@
 	.llong .sys_ni_syscall		/* old mpx syscall */
 	.llong .sys32_setpgid
 	.llong .sys_ni_syscall		/* old ulimit syscall */
-	.llong .sys_olduname
+	.llong .sys32_olduname
 	.llong .sys32_umask		/* 60 */
 	.llong .sys_chroot
 	.llong .sys_ustat
@@ -736,8 +737,11 @@
 	.llong .sys_ni_syscall		/* reserved for sys_io_getevents */
 	.llong .sys_ni_syscall		/* 230 - reserved for sys_io_submit */
 	.llong .sys_ni_syscall		/* reserved for sys_io_cancel */
+	.llong .sys_ni_syscall		/* reserved for alloc_hugepages */
+	.llong .sys_ni_syscall		/* reserved for free_hugepages */
+	.llong .sys_exit_group
 
-	.rept NR_syscalls-231
+	.rept NR_syscalls-234
 		.llong .sys_ni_syscall
 	.endr
 #endif
@@ -766,7 +770,7 @@
 	.llong .sys_lseek
 	.llong .sys_getpid		/* 20 */
 	.llong .sys_mount
-	.llong .sys_oldumount
+	.llong .sys_ni_syscall		/* old umount syscall */
 	.llong .sys_setuid
 	.llong .sys_getuid
 	.llong .ppc64_sys_stime		/* 25 */
@@ -803,7 +807,7 @@
 	.llong .sys_ni_syscall		/* old mpx syscall */
 	.llong .sys_setpgid
 	.llong .sys_ni_syscall		/* old ulimit syscall */
-	.llong .sys_olduname
+	.llong .sys_ni_syscall		/* old uname syscall */
 	.llong .sys_umask		/* 60 */
 	.llong .sys_chroot
 	.llong .sys_ustat
@@ -820,7 +824,7 @@
 	.llong .sys_sigpending
 	.llong .sys_sethostname
 	.llong .sys_setrlimit		/* 75 */
-	.llong .sys_old_getrlimit
+	.llong .sys_ni_syscall		/* old getrlimit syscall */
 	.llong .sys_getrusage
 	.llong .sys_gettimeofday
 	.llong .sys_settimeofday
@@ -833,7 +837,7 @@
 	.llong .sys_uselib
 	.llong .sys_swapon
 	.llong .sys_reboot
-	.llong .old_readdir
+	.llong .sys_ni_syscall		/* old readdir syscall */
 	.llong .sys_mmap		/* 90 */
 	.llong .sys_munmap
 	.llong .sys_truncate
@@ -942,8 +946,8 @@
 	.llong .sys_ni_syscall		/* 195 - 32bit only stat64 */
 	.llong .sys_ni_syscall		/* 32bit only lstat64 */
 	.llong .sys_ni_syscall		/* 32bit only fstat64 */
-	.llong .sys_pciconfig_read
-	.llong .sys_pciconfig_write
+	.llong .sys_ni_syscall		/* 32bit only pciconfig_read */
+	.llong .sys_ni_syscall		/* 32bit only pciconfig_write */
 	.llong .sys_ni_syscall		/* 200 - reserved - sys_pciconfig_iobase */
 	.llong .sys_ni_syscall		/* reserved for MacOnLinux */
 	.llong .sys_getdents64
@@ -976,7 +980,10 @@
 	.llong .sys_io_getevents
 	.llong .sys_io_submit		/* 230 */
 	.llong .sys_io_cancel
+	.llong .sys_ni_syscall		/* reserved for alloc_hugepages */
+	.llong .sys_ni_syscall		/* reserved for free_hugepages */
+	.llong .sys_exit_group
 
-	.rept NR_syscalls-231
+	.rept NR_syscalls-234
 		.llong .sys_ni_syscall
 	.endr
diff -Nru a/arch/ppc64/kernel/mk_defs.c b/arch/ppc64/kernel/mk_defs.c
--- a/arch/ppc64/kernel/mk_defs.c	Fri Sep 20 08:20:47 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,162 +0,0 @@
-/*
- * This program is used to generate definitions needed by
- * assembly language modules.
- *
- * We use the technique used in the OSF Mach kernel code:
- * generate asm statements containing #defines,
- * compile this file to assembler, and then extract the
- * #defines from the assembly-language output.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <stddef.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/mman.h>
-#include <linux/mm.h>
-#include <asm/io.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/processor.h>
-#include <asm/hardirq.h>
-
-#include <asm/naca.h>
-#include <asm/paca.h>
-#include <asm/iSeries/ItLpPaca.h>
-#include <asm/iSeries/ItLpQueue.h>
-#include <asm/iSeries/HvLpEvent.h>
-#include <asm/prom.h>
-#include <asm/rtas.h>
-
-#define DEFINE(sym, val) \
-	        asm volatile("\n#define\t" #sym "\t%0" : : "i" (val))
-
-int
-main(void)
-{
-	/* thread struct on stack */
-	DEFINE(THREAD_SHIFT, THREAD_SHIFT);
-	DEFINE(THREAD_SIZE, THREAD_SIZE);
-	DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
-
-	/* task_struct->thread */
-	DEFINE(THREAD, offsetof(struct task_struct, thread));
-	DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
-	DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode));
-	DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0]));
-	DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr));
-	DEFINE(KSP, offsetof(struct thread_struct, ksp));
-
-	DEFINE(MM, offsetof(struct task_struct, mm));
-
-	/* naca */
-        DEFINE(PACA, offsetof(struct naca_struct, paca));
-	DEFINE(DCACHEL1LINESIZE, offsetof(struct naca_struct, dCacheL1LineSize));
-        DEFINE(DCACHEL1LOGLINESIZE, offsetof(struct naca_struct, dCacheL1LogLineSize));
-        DEFINE(DCACHEL1LINESPERPAGE, offsetof(struct naca_struct, dCacheL1LinesPerPage));
-        DEFINE(ICACHEL1LINESIZE, offsetof(struct naca_struct, iCacheL1LineSize));
-        DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct naca_struct, iCacheL1LogLineSize));
-        DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct naca_struct, iCacheL1LinesPerPage));
-	DEFINE(SLBSIZE, offsetof(struct naca_struct, slb_size));
-	DEFINE(PLATFORM, offsetof(struct naca_struct, platform));
-
-	/* paca */
-        DEFINE(PACA_SIZE, sizeof(struct paca_struct));
-        DEFINE(PACAPACAINDEX, offsetof(struct paca_struct, xPacaIndex));
-        DEFINE(PACAPROCSTART, offsetof(struct paca_struct, xProcStart));
-        DEFINE(PACAKSAVE, offsetof(struct paca_struct, xKsave));
-	DEFINE(PACACURRENT, offsetof(struct paca_struct, xCurrent));
-        DEFINE(PACASAVEDMSR, offsetof(struct paca_struct, xSavedMsr));
-        DEFINE(PACASTABREAL, offsetof(struct paca_struct, xStab_data.real));
-        DEFINE(PACASTABVIRT, offsetof(struct paca_struct, xStab_data.virt));
-	DEFINE(PACASTABRR, offsetof(struct paca_struct, xStab_data.next_round_robin));
-        DEFINE(PACAR1, offsetof(struct paca_struct, xR1));
-        DEFINE(PACALPQUEUE, offsetof(struct paca_struct, lpQueuePtr));
-	DEFINE(PACATOC, offsetof(struct paca_struct, xTOC));
-	DEFINE(PACAEXCSP, offsetof(struct paca_struct, exception_sp));
-	DEFINE(PACAHRDWINTSTACK, offsetof(struct paca_struct, xHrdIntStack));
-	DEFINE(PACAPROCENABLED, offsetof(struct paca_struct, xProcEnabled));
-	DEFINE(PACAHRDWINTCOUNT, offsetof(struct paca_struct, xHrdIntCount));
-	DEFINE(PACADEFAULTDECR, offsetof(struct paca_struct, default_decr));
-	DEFINE(PACAPROFENABLED, offsetof(struct paca_struct, prof_enabled));
-	DEFINE(PACAPROFLEN, offsetof(struct paca_struct, prof_len));
-	DEFINE(PACAPROFSHIFT, offsetof(struct paca_struct, prof_shift));
-	DEFINE(PACAPROFBUFFER, offsetof(struct paca_struct, prof_buffer));
-	DEFINE(PACAPROFSTEXT, offsetof(struct paca_struct, prof_stext));
-	DEFINE(PACALPPACA, offsetof(struct paca_struct, xLpPaca));
-        DEFINE(LPPACA, offsetof(struct paca_struct, xLpPaca));
-        DEFINE(PACAREGSAV, offsetof(struct paca_struct, xRegSav));
-        DEFINE(PACAEXC, offsetof(struct paca_struct, exception_stack));
-        DEFINE(PACAGUARD, offsetof(struct paca_struct, guard));
-        DEFINE(LPPACASRR0, offsetof(struct ItLpPaca, xSavedSrr0));
-        DEFINE(LPPACASRR1, offsetof(struct ItLpPaca, xSavedSrr1));
-	DEFINE(LPPACAANYINT, offsetof(struct ItLpPaca, xIntDword.xAnyInt));
-	DEFINE(LPPACADECRINT, offsetof(struct ItLpPaca, xIntDword.xFields.xDecrInt));
-        DEFINE(LPQCUREVENTPTR, offsetof(struct ItLpQueue, xSlicCurEventPtr));
-        DEFINE(LPQOVERFLOW, offsetof(struct ItLpQueue, xPlicOverflowIntPending));
-        DEFINE(LPEVENTFLAGS, offsetof(struct HvLpEvent, xFlags));
-	DEFINE(PROMENTRY, offsetof(struct prom_t, entry));
-
-	/* RTAS */
-	DEFINE(RTASBASE, offsetof(struct rtas_t, base));
-	DEFINE(RTASENTRY, offsetof(struct rtas_t, entry));
-	DEFINE(RTASSIZE, offsetof(struct rtas_t, size));
-
-	/* Interrupt register frame */
-	DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD);
-
-	DEFINE(SWITCH_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs));
-
-	/* 288 = # of volatile regs, int & fp, for leaf routines */
-	/* which do not stack a frame.  See the PPC64 ABI.       */
-	DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 288);
-	/* Create extra stack space for SRR0 and SRR1 when calling prom/rtas. */
-	DEFINE(PROM_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16);
-	DEFINE(RTAS_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16);
-	DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0]));
-	DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1]));
-	DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2]));
-	DEFINE(GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[3]));
-	DEFINE(GPR4, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[4]));
-	DEFINE(GPR5, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[5]));
-	DEFINE(GPR6, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[6]));
-	DEFINE(GPR7, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[7]));
-	DEFINE(GPR8, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[8]));
-	DEFINE(GPR9, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[9]));
-	DEFINE(GPR20, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[20]));
-	DEFINE(GPR21, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[21]));
-	DEFINE(GPR22, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[22]));
-	DEFINE(GPR23, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[23]));
-	/*
-	 * Note: these symbols include _ because they overlap with special
-	 * register names
-	 */
-	DEFINE(_NIP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, nip));
-	DEFINE(_MSR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, msr));
-	DEFINE(_CTR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ctr));
-	DEFINE(_LINK, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, link));
-	DEFINE(_CCR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ccr));
-	DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer));
-	DEFINE(_DAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar));
-	DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr));
-	DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3));
-	DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result));
-	DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap));
-	DEFINE(SOFTE, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, softe));
-
-	/* These _only_ to be used with {PROM,RTAS}_FRAME_SIZE!!! */
-	DEFINE(_SRR0, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs));
-	DEFINE(_SRR1, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)+8);
-
-	DEFINE(CLONE_VM, CLONE_VM);
-
-	return 0;
-}
diff -Nru a/arch/ppc64/kernel/open_pic.c b/arch/ppc64/kernel/open_pic.c
--- a/arch/ppc64/kernel/open_pic.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc64/kernel/open_pic.c	Fri Sep 20 08:20:47 2002
@@ -23,7 +23,6 @@
 
 #include <asm/machdep.h>
 
-#include "local_irq.h"
 #include "open_pic.h"
 #include "open_pic_defs.h"
 #include "i8259.h"
diff -Nru a/arch/ppc64/kernel/pSeries_hvCall.S b/arch/ppc64/kernel/pSeries_hvCall.S
--- a/arch/ppc64/kernel/pSeries_hvCall.S	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc64/kernel/pSeries_hvCall.S	Fri Sep 20 08:20:48 2002
@@ -11,14 +11,13 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
-#include <linux/config.h>
 #include <linux/sys.h>
 #include <asm/unistd.h>
 #include <asm/errno.h>
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/cache.h>
-#include "ppc_asm.h"
+#include <asm/ppc_asm.h>
 	
 /*
  * hcall interface to pSeries LPAR
diff -Nru a/arch/ppc64/kernel/pSeries_pci.c b/arch/ppc64/kernel/pSeries_pci.c
--- a/arch/ppc64/kernel/pSeries_pci.c	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc64/kernel/pSeries_pci.c	Fri Sep 20 08:20:48 2002
@@ -45,15 +45,13 @@
 #include "open_pic.h"
 #include "pci.h"
 
-extern struct device_node *allnodes;
-
 /*******************************************************************
  * Forward declares of prototypes. 
  *******************************************************************/
-unsigned long find_and_init_phbs(void);
-struct pci_controller* alloc_phb(struct device_node *dev, char *model, unsigned int addr_size_words) ;
-void pSeries_pcibios_fixup(void);
-static int rtas_fake_read(struct device_node *dn, int offset, int nbytes, unsigned long *returnval);
+struct pci_controller *alloc_phb(struct device_node *dev, char *model,
+				 unsigned int addr_size_words) ;
+static int rtas_fake_read(struct device_node *dn, int offset, int nbytes,
+			  unsigned long *returnval);
 
 /* RTAS tokens */
 static int read_pci_config;
@@ -467,44 +465,37 @@
 	* Python
 	***************************************************************/
 	if (strstr(model, "Python")) {
+		unsigned long chip_regs;
+		volatile u32 *tmp, i;
+
 		PPCDBG(PPCDBG_PHBINIT, "\tCreate python\n");
-	        phb = pci_alloc_pci_controller("PHB PY",phb_type_python);
-		if (phb == NULL) return NULL;
-	
-       		phb->cfg_addr = (volatile unsigned long *) 
-			ioremap(reg_struct.address + 0xf8000, PAGE_SIZE);
-		PPCDBG(PPCDBG_PHBINIT, "\tcfg_addr_r = 0x%lx\n", 
-		       reg_struct.address + 0xf8000);
-		PPCDBG(PPCDBG_PHBINIT, "\tcfg_addr_v = 0x%lx\n", 
-		       phb->cfg_addr);
-		phb->cfg_data = (char*)(phb->cfg_addr + 0x02);
-       		phb->phb_regs = (volatile unsigned long *) 
-			ioremap(reg_struct.address + 0xf7000, PAGE_SIZE);
+
+		phb = pci_alloc_pci_controller("PHB PY", phb_type_python);
+		if (phb == NULL)
+			return NULL;
+
 		/* Python's register file is 1 MB in size. */
-		phb->chip_regs = ioremap(reg_struct.address & ~(0xfffffUL), 
-					 0x100000); 
+		chip_regs = ioremap(reg_struct.address & ~(0xfffffUL),
+				    0x100000); 
 
 		/* 
 		 * Firmware doesn't always clear this bit which is critical
 		 * for good performance - Anton
 		 */
-		{
-			volatile u32 *tmp, i;
 
 #define PRG_CL_RESET_VALID 0x00010000
 
-			tmp = (u32 *)((unsigned long)phb->chip_regs + 0xf6030);
+		tmp = (u32 *)((unsigned long)chip_regs + 0xf6030);
 
-			if (*tmp & PRG_CL_RESET_VALID) {
-				printk("Python workaround: ");
-				*tmp &= ~PRG_CL_RESET_VALID;
-				/*
-				 * We must read it back for changes to
-				 * take effect
-				 */
-				i = *tmp;
-				printk("reg0: %x\n", i);
-			}
+		if (*tmp & PRG_CL_RESET_VALID) {
+			printk("Python workaround: ");
+			*tmp &= ~PRG_CL_RESET_VALID;
+			/*
+			 * We must read it back for changes to
+			 * take effect
+			 */
+			i = *tmp;
+			printk("reg0: %x\n", i);
 		}
 
 	/***************************************************************
@@ -514,28 +505,12 @@
 	} else if ((strstr(model, "Speedwagon")) || 
 		   (strstr(model, "Winnipeg"))) {
 		PPCDBG(PPCDBG_PHBINIT, "\tCreate speedwagon\n");
-	        phb = pci_alloc_pci_controller("PHB SW",phb_type_speedwagon);
-		if (phb == NULL) return NULL;
-
-		if (naca->platform == PLATFORM_PSERIES) {
-			phb->cfg_addr = (volatile unsigned long *) 
-			  ioremap(reg_struct.address + 0x140, PAGE_SIZE);
-			phb->cfg_data = (char*)(phb->cfg_addr - 0x02); /* minus is correct */
-			phb->phb_regs = (volatile unsigned long *) 
-			  ioremap(reg_struct.address, PAGE_SIZE);
-			/* Speedwagon's register file is 1 MB in size. */
-			phb->chip_regs = ioremap(reg_struct.address & ~(0xfffffUL),
-						 0x100000); 
-			PPCDBG(PPCDBG_PHBINIT, "\tmapping chip_regs from 0x%lx -> 0x%lx\n", 
-			       reg_struct.address & 0xfffff, phb->chip_regs);
-		} else {
-			phb->cfg_addr = NULL;
-			phb->cfg_data = NULL; 
-			phb->phb_regs = NULL;
-			phb->chip_regs = NULL;
-		}
+	        phb = pci_alloc_pci_controller("PHB SW", phb_type_speedwagon);
+		if (phb == NULL)
+			return NULL;
 
 		phb->local_number = ((reg_struct.address >> 12) & 0xf) - 0x8;
+
 	/***************************************************************
 	* Trying to build a known just gets the code in trouble.
 	***************************************************************/
@@ -563,7 +538,7 @@
 
 	buid_vals = (int *) get_property(dev, "ibm,fw-phb-id", &len);
 	
-  if (buid_vals == NULL) {
+	if (buid_vals == NULL) {
 		phb->buid = 0;
 	} else {
 		struct pci_bus check;
diff -Nru a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c
--- a/arch/ppc64/kernel/pci.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc64/kernel/pci.c	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,4 @@
 /*
- * 
- *
  * Port for PPC64 David Engebretsen, IBM Corp.
  *   Contains common pci routines for ppc64 platform, pSeries and iSeries brands. 
  * 
@@ -128,7 +126,6 @@
 {
 }
 
-
 void
 pcibios_update_resource(struct pci_dev *dev, struct resource *root,
 			     struct resource *res, int resource)
@@ -200,7 +197,6 @@
 	}
 }
 
-
 /*
  *  Handle resources of PCI devices.  If the world were perfect, we could
  *  just allocate all the resource regions and do nothing more.  It isn't.
@@ -333,64 +329,27 @@
 		if (!class || class == PCI_CLASS_BRIDGE_HOST)
 			continue;
 
-		for(idx=0; idx<6; idx++) {
+		for (idx = 0; idx < 6; idx++) {
 			r = &dev->resource[idx];
 
 			/*
-			 *  Don't touch IDE controllers and I/O ports of video cards!
-			 */
-			if ((class == PCI_CLASS_STORAGE_IDE && idx < 4) ||
-			    (class == PCI_CLASS_DISPLAY_VGA && (r->flags & IORESOURCE_IO)))
-				continue;
-
-			/*
-			 *  We shall assign a new address to this resource, either because
-			 *  the BIOS forgot to do so or because we have decided the old
-			 *  address was unusable for some reason.
+			 * We shall assign a new address to this resource,
+			 * either because the BIOS (sic) forgot to do so
+			 * or because we have decided the old address was
+			 * unusable for some reason.
 			 */
-			if (!r->start && r->end && ppc_md.pcibios_enable_device_hook &&
-			    !ppc_md.pcibios_enable_device_hook(dev, 1))
+			if (!r->start && r->end)
 				pci_assign_resource(dev, idx);
 		}
 
-		if (0) { /* don't assign ROMs */
-			r = &dev->resource[PCI_ROM_RESOURCE];
-			r->end -= r->start;
-			r->start = 0;
-			if (r->end)
-				pci_assign_resource(dev, PCI_ROM_RESOURCE);
-		}
-	}
-}
-
-
-int
-pcibios_enable_resources(struct pci_dev *dev)
-{
-	u16 cmd, old_cmd;
-	int idx;
-	struct resource *r;
-
-	pci_read_config_word(dev, PCI_COMMAND, &cmd);
-	old_cmd = cmd;
-	for(idx=0; idx<6; idx++) {
-		r = &dev->resource[idx];
-		if (!r->start && r->end) {
-			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
-			return -EINVAL;
-		}
-		if (r->flags & IORESOURCE_IO)
-			cmd |= PCI_COMMAND_IO;
-		if (r->flags & IORESOURCE_MEM)
-			cmd |= PCI_COMMAND_MEMORY;
-	}
-	if (dev->resource[PCI_ROM_RESOURCE].start)
-		cmd |= PCI_COMMAND_MEMORY;
-	if (cmd != old_cmd) {
-		printk("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
-		pci_write_config_word(dev, PCI_COMMAND, cmd);
+#if 0 /* don't assign ROMs */
+		r = &dev->resource[PCI_ROM_RESOURCE];
+		r->end -= r->start;
+		r->start = 0;
+		if (r->end)
+			pci_assign_resource(dev, PCI_ROM_RESOURCE);
+#endif
 	}
-	return 0;
 }
 
 /* 
@@ -407,8 +366,10 @@
                 return NULL;
         }
         memset(hose, 0, sizeof(struct pci_controller));
-        if(strlen(model) < 8) strcpy(hose->what,model);
-        else                  memcpy(hose->what,model,7);
+        if(strlen(model) < 8)
+		strcpy(hose->what,model);
+        else
+		memcpy(hose->what,model,7);
         hose->type = controller_type;
         hose->global_number = global_phb_number;
 	phbtab[global_phb_number++] = hose;
@@ -418,34 +379,12 @@
         return hose;
 }
 
-/*
- * This fixup is arch independent and probably should go somewhere else.
- */
-void __init
-pcibios_generic_fixup(void)
-{
-	struct pci_dev *dev;
-
-	/* Fix miss-identified vendor AMD pcnet32 adapters. */
-	dev = NULL;
-	while ((dev = pci_find_device(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_AMD_LANCE, dev)) != NULL &&
-	       dev->class == (PCI_CLASS_NETWORK_ETHERNET << 8))
-		dev->vendor = PCI_VENDOR_ID_AMD;
-}
-
-
-
-/*********************************************************************** 
- *
- *
- * 
- ***********************************************************************/
-void __init
+static int __init
 pcibios_init(void)
 {
 	struct pci_controller *hose;
 	struct pci_bus *bus;
-	int    next_busno;
+	int next_busno;
 
 #ifndef CONFIG_PPC_ISERIES
 	pSeries_pcibios_init();
@@ -455,7 +394,6 @@
 
 	printk("PCI: Probing PCI hardware\n");
 	PPCDBG(PPCDBG_BUSWALK,"PCI: Probing PCI hardware\n");
-				
 
 	/* Scan all of the recorded PCI controllers.  */
 	for (next_busno = 0, hose = hose_head; hose; hose = hose->next) {
@@ -467,15 +405,12 @@
 			next_busno = hose->last_busno+1;
 	}
 	pci_bus_count = next_busno;
-		
+
 	/* Call machine dependant fixup */
 	if (ppc_md.pcibios_fixup) {
 		ppc_md.pcibios_fixup();
 	}
 
-	/* Generic fixups */
-	pcibios_generic_fixup();
-
 	/* Allocate and assign resources */
 	pcibios_allocate_bus_resources(&pci_root_buses);
 	pcibios_allocate_resources(0);
@@ -577,20 +512,22 @@
 	return str;
 }
 
-int pcibios_enable_device(struct pci_dev *dev)
+int pcibios_enable_device(struct pci_dev *dev, int mask)
 {
 	u16 cmd, old_cmd;
 	int idx;
 	struct resource *r;
 
-	PPCDBG(PPCDBG_BUSWALK,"PCI: %s for device %s \n",__FUNCTION__,dev->slot_name);
-	if (ppc_md.pcibios_enable_device_hook)
-		if (ppc_md.pcibios_enable_device_hook(dev, 0))
-			return -EINVAL;
-			
+	PPCDBG(PPCDBG_BUSWALK,"PCI: %s for device %s \n", __FUNCTION__,
+	       dev->slot_name);
+
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 	old_cmd = cmd;
-	for (idx=0; idx<6; idx++) {
+	for (idx = 0; idx < 6; idx++) {
+		/* Only set up the requested stuff */
+		if (!(mask & (1<<idx)))
+			continue;
+
 		r = &dev->resource[idx];
 		if (!r->start && r->end) {
 			printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name);
@@ -604,7 +541,8 @@
 	if (cmd != old_cmd) {
 		printk("PCI: Enabling device %s (%04x -> %04x)\n",
 		       dev->slot_name, old_cmd, cmd);
-		PPCDBG(PPCDBG_BUSWALK,"PCI: Enabling device %s \n",dev->slot_name);
+		PPCDBG(PPCDBG_BUSWALK,"PCI: Enabling device %s \n",
+		       dev->slot_name);
 		pci_write_config_word(dev, PCI_COMMAND, cmd);
 	}
 	return 0;
@@ -985,12 +923,6 @@
 		udbg_printf("\tio_base_phys  = 0x%016LX\n", phb->io_base_phys);
 		udbg_printf("\tpci_mem_offset= 0x%016LX\n", phb->pci_mem_offset);
 		udbg_printf("\tpci_io_offset = 0x%016LX\n", phb->pci_io_offset);
-
-		udbg_printf("\tcfg_addr      = 0x%016LX\n", phb->cfg_addr);
-		udbg_printf("\tcfg_data      = 0x%016LX\n", phb->cfg_data);
-		udbg_printf("\tphb_regs      = 0x%016LX\n", phb->phb_regs);
-		udbg_printf("\tchip_regs     = 0x%016LX\n", phb->chip_regs);
-
 
 		udbg_printf("\tResources\n");
 		dumpResources(&phb->io_resource);
diff -Nru a/arch/ppc64/kernel/pci_dma.c b/arch/ppc64/kernel/pci_dma.c
--- a/arch/ppc64/kernel/pci_dma.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc64/kernel/pci_dma.c	Fri Sep 20 08:20:47 2002
@@ -1438,69 +1438,6 @@
 }
 #endif
 
-/*
- * phb_tce_table_init
- * 
- * Function: Display TCE config registers.  Could be easily changed
- *           to initialize the hardware to use TCEs.
- */
-unsigned long phb_tce_table_init(struct pci_controller *phb) {
-	unsigned int r, cfg_rw, i;	
-	unsigned long r64;	
-	phandle node;
-
-	PPCDBG(PPCDBG_TCE, "phb_tce_table_init: start.\n"); 
-
-	node = ((struct device_node *)(phb->arch_data))->node;
-
-	PPCDBG(PPCDBG_TCEINIT, "\tphb            = 0x%lx\n", phb); 
-	PPCDBG(PPCDBG_TCEINIT, "\tphb->type      = 0x%lx\n", phb->type); 
-	PPCDBG(PPCDBG_TCEINIT, "\tphb->phb_regs  = 0x%lx\n", phb->phb_regs); 
-	PPCDBG(PPCDBG_TCEINIT, "\tphb->chip_regs = 0x%lx\n", phb->chip_regs); 
-	PPCDBG(PPCDBG_TCEINIT, "\tphb: node      = 0x%lx\n", node);
-	PPCDBG(PPCDBG_TCEINIT, "\tphb->arch_data = 0x%lx\n", phb->arch_data); 
-
-	i = 0;
-	while(of_tce_table[i].node) {
-		if(of_tce_table[i].node == node) {
-			if(phb->type == phb_type_python) {
-				r = *(((unsigned int *)phb->phb_regs) + (0xf10>>2)); 
-				PPCDBG(PPCDBG_TCEINIT, "\tTAR(low)    = 0x%x\n", r);
-				r = *(((unsigned int *)phb->phb_regs) + (0xf00>>2)); 
-				PPCDBG(PPCDBG_TCEINIT, "\tTAR(high)   = 0x%x\n", r);
-				r = *(((unsigned int *)phb->phb_regs) + (0xfd0>>2)); 
-				PPCDBG(PPCDBG_TCEINIT, "\tPHB cfg(rw) = 0x%x\n", r);
-				break;
-			} else if(phb->type == phb_type_speedwagon) {
-				r64 = *(((unsigned long *)phb->chip_regs) + 
-					(0x800>>3)); 
-				PPCDBG(PPCDBG_TCEINIT, "\tNCFG    = 0x%lx\n", r64);
-				r64 = *(((unsigned long *)phb->chip_regs) + 
-					(0x580>>3)); 
-				PPCDBG(PPCDBG_TCEINIT, "\tTAR0    = 0x%lx\n", r64);
-				r64 = *(((unsigned long *)phb->chip_regs) + 
-					(0x588>>3)); 
-				PPCDBG(PPCDBG_TCEINIT, "\tTAR1    = 0x%lx\n", r64);
-				r64 = *(((unsigned long *)phb->chip_regs) + 
-					(0x590>>3)); 
-				PPCDBG(PPCDBG_TCEINIT, "\tTAR2    = 0x%lx\n", r64);
-				r64 = *(((unsigned long *)phb->chip_regs) + 
-					(0x598>>3)); 
-				PPCDBG(PPCDBG_TCEINIT, "\tTAR3    = 0x%lx\n", r64);
-				cfg_rw = *(((unsigned int *)phb->chip_regs) + 
-					   ((0x160 +
-					     (((phb->local_number)+8)<<12))>>2)); 
-				PPCDBG(PPCDBG_TCEINIT, "\tcfg_rw = 0x%x\n", cfg_rw);
-			}
-		}
-		i++;
-	}
-
-	PPCDBG(PPCDBG_TCEINIT, "phb_tce_table_init: done\n"); 
-
-	return(0); 
-}
-
 /* These are called very early. */
 void tce_init_pSeries(void)
 {
diff -Nru a/arch/ppc64/kernel/pci_dn.c b/arch/ppc64/kernel/pci_dn.c
--- a/arch/ppc64/kernel/pci_dn.c	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc64/kernel/pci_dn.c	Fri Sep 20 08:20:48 2002
@@ -215,6 +215,7 @@
 	return NULL;
 }
 
+
 /* Traversal func that looks for a <busno,devfcn> value.
  * If found, the device_node is returned (thus terminating the traversal).
  */
@@ -223,7 +224,6 @@
 {
 	int busno = ((unsigned long)data >> 8) & 0xff;
 	int devfn = ((unsigned long)data) & 0xff;
-
 	return (devfn == dn->devfn && busno == dn->busno) ? dn : NULL;
 }
 
@@ -249,8 +249,9 @@
 	*eads = *other_eads;
 	eads->devfn &= ~7;	/* make it function zero */
 	eads->tce_table = NULL;
-	/* NOTE: share properties.  We could copy but for now this should suffice.
-	 * The full_name is also incorrect...but seems harmless.
+	/*
+	 * NOTE: share properties.  We could copy but for now this should
+	 * suffice.  The full_name is also incorrect...but seems harmless.
 	 */
 	eads->child = NULL;
 	eads->next = NULL;
@@ -285,21 +286,25 @@
 		dev->sysdata = dn;
 		/* ToDo: call some device init hook here */
 	} else {
-		/* Now it is very possible that we can't find the device because it is
-		 * not the zero'th device of a mutifunction device and we don't have
-		 * permission to read the zero'th device.  If this is the case, Linux
-		 * would ordinarily skip all the other functions.
+		/* Now it is very possible that we can't find the device
+		 * because it is not the zero'th device of a mutifunction
+		 * device and we don't have permission to read the zero'th
+		 * device.  If this is the case, Linux would ordinarily skip
+		 * all the other functions.
 		 */
 		if ((searchval & 0x7) == 0) {
 			struct device_node *thisdevdn;
 			/* Ok, we are looking for fn == 0.  Let's check for other functions. */
 			thisdevdn = (struct device_node *)traverse_pci_devices(phb_dn, is_devfn_sub_node, NULL, (void *)searchval);
 			if (thisdevdn) {
-				/* Ah ha!  There does exist a sub function.  Now this isn't an exact
-				 * match for searchval, but in order to get Linux to believe the sub
-				 * functions exist we will need to manufacture a fake device_node
-				 * for this zero'th function.  To keept this simple for now we only
-				 * handle pci bridges and we just hand back the found node which
+				/* Ah ha!  There does exist a sub function.
+				 * Now this isn't an exact match for
+				 * searchval, but in order to get Linux to
+				 * believe the sub functions exist we will
+				 * need to manufacture a fake device_node for
+				 * this zero'th function.  To keept this
+				 * simple for now we only handle pci bridges
+				 * and we just hand back the found node which
 				 * isn't correct, but Linux won't care.
 				 */
 				char *device_type = (char *)get_property(thisdevdn, "device_type", 0);
@@ -367,7 +372,6 @@
 		pci_fixup_bus_sysdata_list(&bus->children);
 	}
 }
-
 
 /******************************************************************
  * Fixup the bus->sysdata ptrs to point to the bus' device_node.
diff -Nru a/arch/ppc64/kernel/ppc_asm.h b/arch/ppc64/kernel/ppc_asm.h
--- a/arch/ppc64/kernel/ppc_asm.h	Fri Sep 20 08:20:44 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,115 +0,0 @@
-/*
- * arch/ppc64/kernel/ppc_asm.h
- *
- * Definitions used by various bits of low-level assembly code on PowerPC.
- *
- * Copyright (C) 1995-1999 Gary Thomas, Paul Mackerras, Cort Dougan.
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU General Public License
- *  as published by the Free Software Foundation; either version
- *  2 of the License, or (at your option) any later version.
- */
-
-#include <asm/ppc_asm.tmpl>
-#include "ppc_defs.h"
-
-/*
- * Macros for storing registers into and loading registers from
- * exception frames.
- */
-#define SAVE_GPR(n, base)	std	n,GPR0+8*(n)(base)
-#define SAVE_2GPRS(n, base)	SAVE_GPR(n, base); SAVE_GPR(n+1, base)
-#define SAVE_4GPRS(n, base)	SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
-#define SAVE_8GPRS(n, base)	SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
-#define SAVE_10GPRS(n, base)	SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
-#define REST_GPR(n, base)	ld	n,GPR0+8*(n)(base)
-#define REST_2GPRS(n, base)	REST_GPR(n, base); REST_GPR(n+1, base)
-#define REST_4GPRS(n, base)	REST_2GPRS(n, base); REST_2GPRS(n+2, base)
-#define REST_8GPRS(n, base)	REST_4GPRS(n, base); REST_4GPRS(n+4, base)
-#define REST_10GPRS(n, base)	REST_8GPRS(n, base); REST_2GPRS(n+8, base)
-
-#define SAVE_FPR(n, base)	stfd	n,THREAD_FPR0+8*(n)(base)
-#define SAVE_2FPRS(n, base)	SAVE_FPR(n, base); SAVE_FPR(n+1, base)
-#define SAVE_4FPRS(n, base)	SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base)
-#define SAVE_8FPRS(n, base)	SAVE_4FPRS(n, base); SAVE_4FPRS(n+4, base)
-#define SAVE_16FPRS(n, base)	SAVE_8FPRS(n, base); SAVE_8FPRS(n+8, base)
-#define SAVE_32FPRS(n, base)	SAVE_16FPRS(n, base); SAVE_16FPRS(n+16, base)
-#define REST_FPR(n, base)	lfd	n,THREAD_FPR0+8*(n)(base)
-#define REST_2FPRS(n, base)	REST_FPR(n, base); REST_FPR(n+1, base)
-#define REST_4FPRS(n, base)	REST_2FPRS(n, base); REST_2FPRS(n+2, base)
-#define REST_8FPRS(n, base)	REST_4FPRS(n, base); REST_4FPRS(n+4, base)
-#define REST_16FPRS(n, base)	REST_8FPRS(n, base); REST_8FPRS(n+8, base)
-#define REST_32FPRS(n, base)	REST_16FPRS(n, base); REST_16FPRS(n+16, base)
-
-#define CHECKANYINT(ra,rb)			\
-	mfspr	rb,SPRG3;		/* Get Paca address */\
-	ld	ra,PACALPPACA+LPPACAANYINT(rb); /* Get pending interrupt flags */\
-	cmpldi	0,ra,0;
-
-/* Macros to adjust thread priority for Iseries hardware multithreading */
-#define HMT_LOW		or 1,1,1
-#define HMT_MEDIUM	or 2,2,2
-#define HMT_HIGH	or 3,3,3
-
-/* Insert the high 32 bits of the MSR into what will be the new
-   MSR (via SRR1 and rfid)  This preserves the MSR.SF and MSR.ISF
-   bits. */
-
-#define FIX_SRR1(ra, rb)	\
-	mr	rb,ra;		\
-	mfmsr	ra;		\
-	rldimi	ra,rb,0,32
-
-#define CLR_TOP32(r)	rlwinm	(r),(r),0,0,31	/* clear top 32 bits */
-
-/* 
- * LOADADDR( rn, name )
- *   loads the address of 'name' into 'rn'
- *
- * LOADBASE( rn, name )
- *   loads the address (less the low 16 bits) of 'name' into 'rn'
- *   suitable for base+disp addressing
- */
-#define LOADADDR(rn,name) \
-	lis	rn,name##@highest;	\
-	ori	rn,rn,name##@higher;	\
-	rldicr	rn,rn,32,31;		\
-	oris	rn,rn,name##@h;		\
-	ori	rn,rn,name##@l
-
-#define LOADBASE(rn,name) \
-	lis	rn,name@highest;	\
-	ori	rn,rn,name@higher;	\
-	rldicr	rn,rn,32,31;		\
-	oris	rn,rn,name@ha
-
-
-#define SET_REG_TO_CONST(reg, value)	         	\
-	lis     reg,(((value)>>48)&0xFFFF);             \
-	ori     reg,reg,(((value)>>32)&0xFFFF);         \
-	rldicr  reg,reg,32,31;                          \
-	oris    reg,reg,(((value)>>16)&0xFFFF);         \
-	ori     reg,reg,((value)&0xFFFF);
-
-#define SET_REG_TO_LABEL(reg, label)	         	\
-	lis     reg,(label)@highest;                    \
-	ori     reg,reg,(label)@higher;                 \
-	rldicr  reg,reg,32,31;                          \
-	oris    reg,reg,(label)@h;                      \
-	ori     reg,reg,(label)@l;
-
-
-/* PPPBBB - DRENG  If KERNELBASE is always 0xC0...,
- * Then we can easily do this with one asm insn. -Peter
- */
-#define tophys(rd,rs)                           \
-        lis     rd,((KERNELBASE>>48)&0xFFFF);   \
-        rldicr  rd,rd,32,31;                    \
-        sub     rd,rs,rd
-
-#define tovirt(rd,rs)                           \
-        lis     rd,((KERNELBASE>>48)&0xFFFF);   \
-        rldicr  rd,rd,32,31;                    \
-        add     rd,rs,rd
-
diff -Nru a/arch/ppc64/kernel/ppc_defs.head b/arch/ppc64/kernel/ppc_defs.head
--- a/arch/ppc64/kernel/ppc_defs.head	Fri Sep 20 08:20:44 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,3 +0,0 @@
-/*
- * WARNING! This file is automatically generated - DO NOT EDIT!
- */
diff -Nru a/arch/ppc64/kernel/proc_pmc.c b/arch/ppc64/kernel/proc_pmc.c
--- a/arch/ppc64/kernel/proc_pmc.c	Fri Sep 20 08:20:44 2002
+++ b/arch/ppc64/kernel/proc_pmc.c	Fri Sep 20 08:20:44 2002
@@ -24,7 +24,6 @@
  * End Change Activity 
  */
 
-#include <linux/config.h>
 #include <linux/proc_fs.h>
 #include <linux/spinlock.h>
 
diff -Nru a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c
--- a/arch/ppc64/kernel/process.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc64/kernel/process.c	Fri Sep 20 08:20:47 2002
@@ -169,6 +169,8 @@
 	extern void ret_from_fork(void);
 	unsigned long sp = (unsigned long)p->thread_info + THREAD_SIZE;
 
+	p->user_tid = NULL;
+
 	/* Copy registers */
 	sp -= sizeof(struct pt_regs);
 	childregs = (struct pt_regs *) sp;
@@ -260,13 +262,19 @@
 	      u32 p6, struct pt_regs *regs)
 {
 	struct task_struct *p;
-	int *user_tid = (int *)p3;
+	unsigned long tid_ptr = 0;
+
+	if (clone_flags & (CLONE_SETTID | CLONE_CLEARTID)) {
+		tid_ptr = p3;
+		if (test_thread_flag(TIF_32BIT))
+			tid_ptr &= 0xffffffff;
+	}
 
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
 
 	p = do_fork(clone_flags & ~CLONE_IDLETASK, regs->gpr[1], regs, 0,
-		    user_tid);
+		    (int *)tid_ptr);
 	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
 }
 
diff -Nru a/arch/ppc64/kernel/rtas.c b/arch/ppc64/kernel/rtas.c
--- a/arch/ppc64/kernel/rtas.c	Fri Sep 20 08:20:42 2002
+++ b/arch/ppc64/kernel/rtas.c	Fri Sep 20 08:20:42 2002
@@ -141,7 +141,7 @@
 	rtas_args->rets  = (rtas_arg_t *)&(rtas_args->args[nargs]);
 	va_start(list, outputs);
 	for (i = 0; i < nargs; ++i) {
-	  rtas_args->args[i] = (rtas_arg_t)LONG_LSW(va_arg(list, ulong));
+		rtas_args->args[i] = (rtas_arg_t)LONG_LSW(va_arg(list, ulong));
 		PPCDBG(PPCDBG_RTAS, "\tnarg[%d] = 0x%lx\n", i, rtas_args->args[i]);
 	}
 	va_end(list);
@@ -164,8 +164,8 @@
 	spin_unlock_irqrestore(&rtas.lock, s);
 #endif
 	ifppcdebug(PPCDBG_RTAS) {
-	for(i=0; i < nret ;i++)
-	  udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]);
+		for(i=0; i < nret ;i++)
+			udbg_printf("\tnret[%d] = 0x%lx\n", i, (ulong)rtas_args->rets[i]);
 	}
 
 	if (nret > 1 && outputs != NULL)
diff -Nru a/arch/ppc64/kernel/rtas_flash.c b/arch/ppc64/kernel/rtas_flash.c
--- a/arch/ppc64/kernel/rtas_flash.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc64/kernel/rtas_flash.c	Fri Sep 20 08:20:47 2002
@@ -14,8 +14,6 @@
  */
 
 #include <linux/module.h>
-
-#include <linux/config.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/ppc64/kernel/signal.c b/arch/ppc64/kernel/signal.c
--- a/arch/ppc64/kernel/signal.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc64/kernel/signal.c	Fri Sep 20 08:20:41 2002
@@ -159,11 +159,10 @@
 	}
 }
 
-
-
-long sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+long sys_sigaltstack(const stack_t *uss, stack_t *uoss, unsigned long r5,
+		     unsigned long r6, unsigned long r7, unsigned long r8,
+		     struct pt_regs *regs)
 {
-	struct pt_regs *regs = (struct pt_regs *)&uss;
 	return do_sigaltstack(uss, uoss, regs->gpr[1]);
 }
 
@@ -250,7 +249,7 @@
 		goto badframe;
 	/* This function sets back the stack flags into
 	   the current task structure.  */
-	sys_sigaltstack(&st, NULL);
+	sys_sigaltstack(&st, NULL, 0, 0, 0, 0, regs);
 
 	return regs->result;
 
diff -Nru a/arch/ppc64/kernel/signal32.c b/arch/ppc64/kernel/signal32.c
--- a/arch/ppc64/kernel/signal32.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc64/kernel/signal32.c	Fri Sep 20 08:20:47 2002
@@ -298,7 +298,8 @@
 	regs->dsisr = 0;
 	regs->result = (u64)(saved_regs[PT_RESULT]) & 0xFFFFFFFF;
 
-	if (copy_from_user(current->thread.fpr, &sr->fp_regs, sizeof(sr->fp_regs)))
+	if (copy_from_user(current->thread.fpr, &sr->fp_regs,
+			   sizeof(sr->fp_regs)))
 		goto badframe;
 
 	ret = regs->result;
@@ -392,7 +393,6 @@
 	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);
@@ -421,7 +421,6 @@
  *        siginfo32to64
  */
 
-
 /*
  * This code executes after the rt signal handler in 32 bit mode has
  * completed and returned  
@@ -438,6 +437,7 @@
 	sigset_t set; 
 	stack_t st;
 	int i;
+	mm_segment_t old_fs;
 
 	/* Adjust the inputted reg1 to point to the first rt signal frame */
 	rt_sf = (struct rt_sigframe_32 *)(regs->gpr[1] + __SIGNAL_FRAMESIZE32);
@@ -509,6 +509,16 @@
 	regs->dar = 0; 
 	regs->dsisr = 0;
 	regs->result = (u64)(saved_regs[PT_RESULT]) & 0xFFFFFFFF;
+	if (copy_from_user(current->thread.fpr, &sr->fp_regs,
+			   sizeof(sr->fp_regs)))
+		goto badframe;
+	/* This function sets back the stack flags into
+	   the current task structure.  */
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	do_sigaltstack(&st, NULL, regs->gpr[1]);
+	set_fs(old_fs);
+
 	ret = regs->result;
 	return ret;
 
@@ -933,7 +943,6 @@
 	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);
@@ -1036,7 +1045,7 @@
  */
 
 int sys32_sigaltstack(u32 newstack, u32 oldstack, int p3,
-		int p4, int p6, int p7, struct pt_regs *regs)
+		      int p4, int p6, int p7, struct pt_regs *regs)
 {
 	stack_t uss, uoss;
 	int ret;
diff -Nru a/arch/ppc64/kernel/stab.c b/arch/ppc64/kernel/stab.c
--- a/arch/ppc64/kernel/stab.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc64/kernel/stab.c	Fri Sep 20 08:20:47 2002
@@ -303,11 +303,13 @@
  */
 static void preload_stab(struct task_struct *tsk, struct mm_struct *mm)
 {
-	if (ppc64_preload_all_segments && test_tsk_thread_flag(tsk, TIF_32BIT)) {
+	if (ppc64_preload_all_segments &&
+	    test_tsk_thread_flag(tsk, TIF_32BIT)) {
 		unsigned long esid, vsid;
 
 		for (esid = 0; esid < 16; esid++) {
-			vsid = get_vsid(mm->context, esid << SID_SHIFT);
+			unsigned long ea = esid << SID_SHIFT;
+			vsid = get_vsid(mm->context, ea);
 			__ste_allocate(esid, vsid, 0);
 		}
 	} else {
@@ -318,15 +320,17 @@
 		unsigned long vsid;
 
 		if (pc) {
-			if (REGION_ID(pc) >= KERNEL_REGION_ID)
-				BUG();
+			if (!IS_VALID_EA(pc) || 
+			    (REGION_ID(pc) >= KERNEL_REGION_ID))
+				return;
 			vsid = get_vsid(mm->context, pc);
 			__ste_allocate(GET_ESID(pc), vsid, 0);
 		}
 
 		if (stack && (pc_segment != stack_segment)) {
-			if (REGION_ID(stack) >= KERNEL_REGION_ID)
-				BUG();
+			if (!IS_VALID_EA(stack) || 
+			    (REGION_ID(stack) >= KERNEL_REGION_ID))
+				return;
 			vsid = get_vsid(mm->context, stack);
 			__ste_allocate(GET_ESID(stack), vsid, 0);
 		}
diff -Nru a/arch/ppc64/kernel/sys32.S b/arch/ppc64/kernel/sys32.S
--- a/arch/ppc64/kernel/sys32.S	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc64/kernel/sys32.S	Fri Sep 20 08:20:47 2002
@@ -15,7 +15,7 @@
  *      2 of the License, or (at your option) any later version.
  */
 
-#include "ppc_asm.h"
+#include <asm/ppc_asm.h>
 #include <asm/errno.h>
 #include <asm/processor.h>
 
diff -Nru a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c
--- a/arch/ppc64/kernel/sys_ppc32.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc64/kernel/sys_ppc32.c	Fri Sep 20 08:20:47 2002
@@ -213,7 +213,7 @@
 		goto bad_file;
 
 	if (file->f_op && (file->f_mode & FMODE_READ) &&
-     (file->f_op->readv || file->f_op->read))
+	    (file->f_op->readv || file->f_op->read))
 		ret = do_readv_writev32(VERIFY_WRITE, file, vector, count);
 	fput(file);
 
@@ -238,8 +238,6 @@
 	return ret;
 }
 
-
-
 static inline int get_flock(struct flock *kfl, struct flock32 *ufl)
 {
 	int err;
@@ -656,8 +654,8 @@
 	char *bits;
 	unsigned long nn;
 	long timeout;
-	int ret, size;
-	
+	int ret, size, max_fdset;
+
 	timeout = MAX_SCHEDULE_TIMEOUT;
 	if (tvp) {
 		time_t sec, usec;
@@ -679,8 +677,11 @@
 	ret = -EINVAL;
 	if (n < 0)
 		goto out_nofds;
-	if (n > current->files->max_fdset)
-		n = current->files->max_fdset;
+
+	/* max_fdset can increase, so grab it once to avoid race */
+	max_fdset = current->files->max_fdset;
+	if (n > max_fdset)
+		n = max_fdset;
 
 	/*
 	 * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
@@ -4285,6 +4286,32 @@
 	return ret;
 }
 
+int sys32_olduname(struct oldold_utsname * name)
+{
+	int error;
+	
+	if (!name)
+		return -EFAULT;
+	if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
+		return -EFAULT;
+  
+	down_read(&uts_sem);
+	error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
+	error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
+	error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
+	error -= __put_user(0,name->nodename+__OLD_UTS_LEN);
+	error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
+	error -= __put_user(0,name->release+__OLD_UTS_LEN);
+	error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
+	error -= __put_user(0,name->version+__OLD_UTS_LEN);
+	error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
+	error = __put_user(0,name->machine+__OLD_UTS_LEN);
+	up_read(&uts_sem);
+
+	error = error ? -EFAULT : 0;
+	
+	return error;
+}
 extern unsigned long sys_mmap(unsigned long addr, size_t len,
 			      unsigned long prot, unsigned long flags,
 			      unsigned long fd, off_t offset);
diff -Nru a/arch/ppc64/kernel/syscalls.c b/arch/ppc64/kernel/syscalls.c
--- a/arch/ppc64/kernel/syscalls.c	Fri Sep 20 08:20:42 2002
+++ b/arch/ppc64/kernel/syscalls.c	Fri Sep 20 08:20:42 2002
@@ -218,32 +218,6 @@
 	return err;
 }
 
-asmlinkage int sys_olduname(struct oldold_utsname * name)
-{
-	int error;
-	
-	if (!name)
-		return -EFAULT;
-	if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
-		return -EFAULT;
-  
-	down_read(&uts_sem);
-	error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
-	error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
-	error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
-	error -= __put_user(0,name->nodename+__OLD_UTS_LEN);
-	error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
-	error -= __put_user(0,name->release+__OLD_UTS_LEN);
-	error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
-	error -= __put_user(0,name->version+__OLD_UTS_LEN);
-	error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
-	error = __put_user(0,name->machine+__OLD_UTS_LEN);
-	up_read(&uts_sem);
-
-	error = error ? -EFAULT : 0;
-	
-	return error;
-}
 
 asmlinkage time_t sys64_time(time_t* tloc)
 {
diff -Nru a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c
--- a/arch/ppc64/kernel/time.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc64/kernel/time.c	Fri Sep 20 08:20:47 2002
@@ -469,11 +469,6 @@
 	last_rtc_update = xtime.tv_sec;
 	write_unlock_irqrestore(&xtime_lock, flags);
 
-#ifdef CONFIG_PPC_ISERIES
-	/* HACK HACK This allows the iSeries profiling to use /proc/profile */
-	prof_shift = 0;
-#endif
-
 	/* Not exact, but the timer interrupt takes care of this */
 	set_dec(tb_ticks_per_jiffy);
 }
diff -Nru a/arch/ppc64/kernel/traps.c b/arch/ppc64/kernel/traps.c
--- a/arch/ppc64/kernel/traps.c	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc64/kernel/traps.c	Fri Sep 20 08:20:46 2002
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/ppc/kernel/traps.c
+ *  linux/arch/ppc64/kernel/traps.c
  *
  *  Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org)
  *
diff -Nru a/arch/ppc64/kernel/xics.c b/arch/ppc64/kernel/xics.c
--- a/arch/ppc64/kernel/xics.c	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc64/kernel/xics.c	Fri Sep 20 08:20:41 2002
@@ -13,6 +13,7 @@
 #include <linux/threads.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/irq.h>
 #include <asm/prom.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
diff -Nru a/arch/ppc64/kernel/xics.h b/arch/ppc64/kernel/xics.h
--- a/arch/ppc64/kernel/xics.h	Fri Sep 20 08:20:46 2002
+++ b/arch/ppc64/kernel/xics.h	Fri Sep 20 08:20:46 2002
@@ -12,8 +12,6 @@
 #ifndef _PPC_KERNEL_XICS_H
 #define _PPC_KERNEL_XICS_H
 
-#include "local_irq.h"
-
 extern struct hw_interrupt_type xics_pic;
 extern struct hw_interrupt_type xics_8259_pic;
 
diff -Nru a/arch/ppc64/lib/checksum.S b/arch/ppc64/lib/checksum.S
--- a/arch/ppc64/lib/checksum.S	Fri Sep 20 08:20:45 2002
+++ b/arch/ppc64/lib/checksum.S	Fri Sep 20 08:20:45 2002
@@ -15,7 +15,7 @@
 #include <linux/sys.h>
 #include <asm/processor.h>
 #include <asm/errno.h>
-#include <asm/ppc_asm.tmpl>
+#include <asm/ppc_asm.h>
 
 /*
  * ip_fast_csum(r3=buf, r4=len) -- Optimized for IP header
diff -Nru a/arch/ppc64/lib/copypage.S b/arch/ppc64/lib/copypage.S
--- a/arch/ppc64/lib/copypage.S	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc64/lib/copypage.S	Fri Sep 20 08:20:41 2002
@@ -9,7 +9,7 @@
  * 2 of the License, or (at your option) any later version.
  */
 #include <asm/processor.h>
-#include "../kernel/ppc_asm.h"
+#include <asm/ppc_asm.h>
 
 _GLOBAL(copy_page)
 	std	r31,-8(1)
diff -Nru a/arch/ppc64/lib/copyuser.S b/arch/ppc64/lib/copyuser.S
--- a/arch/ppc64/lib/copyuser.S	Fri Sep 20 08:20:48 2002
+++ b/arch/ppc64/lib/copyuser.S	Fri Sep 20 08:20:48 2002
@@ -9,7 +9,7 @@
  * 2 of the License, or (at your option) any later version.
  */
 #include <asm/processor.h>
-#include "../kernel/ppc_asm.h"
+#include <asm/ppc_asm.h>
 
 	.align	7
 _GLOBAL(__copy_tofrom_user)
diff -Nru a/arch/ppc64/lib/memcpy.S b/arch/ppc64/lib/memcpy.S
--- a/arch/ppc64/lib/memcpy.S	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc64/lib/memcpy.S	Fri Sep 20 08:20:41 2002
@@ -9,7 +9,7 @@
  * 2 of the License, or (at your option) any later version.
  */
 #include <asm/processor.h>
-#include "../kernel/ppc_asm.h"
+#include <asm/ppc_asm.h>
 
 	.align	7
 _GLOBAL(memcpy)
diff -Nru a/arch/ppc64/lib/string.S b/arch/ppc64/lib/string.S
--- a/arch/ppc64/lib/string.S	Fri Sep 20 08:20:43 2002
+++ b/arch/ppc64/lib/string.S	Fri Sep 20 08:20:43 2002
@@ -8,9 +8,9 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
-#include <asm/ppc_asm.tmpl>
 #include <asm/processor.h>
 #include <asm/errno.h>
+#include <asm/ppc_asm.h>
 
 _GLOBAL(strcpy)
 	addi	r5,r3,-1
diff -Nru a/arch/ppc64/mm/Makefile b/arch/ppc64/mm/Makefile
--- a/arch/ppc64/mm/Makefile	Fri Sep 20 08:20:41 2002
+++ b/arch/ppc64/mm/Makefile	Fri Sep 20 08:20:41 2002
@@ -12,5 +12,6 @@
 O_TARGET := mm.o
 
 obj-y           := fault.o init.o extable.o imalloc.o
+obj-$(CONFIG_DISCONTIGMEM) += numa.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c
--- a/arch/ppc64/mm/init.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc64/mm/init.c	Fri Sep 20 08:20:47 2002
@@ -99,23 +99,26 @@
 
 void show_mem(void)
 {
-	int pfn, total = 0, reserved = 0;
+	int total = 0, reserved = 0;
 	int shared = 0, cached = 0;
 	struct page *page;
+	pg_data_t *pgdat;
+	unsigned long i;
 
 	printk("Mem-info:\n");
 	show_free_areas();
 	printk("Free swap:       %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
-	pfn = max_mapnr;
-	while (pfn-- > 0) {
-		page = pfn_to_page(pfn);
-		total++;
-		if (PageReserved(page))
-			reserved++;
-		else if (PageSwapCache(page))
-			cached++;
-		else if (page_count(page))
-			shared += page_count(page) - 1;
+	for_each_pgdat(pgdat) {
+		for (i = 0; i < pgdat->node_size; i++) {
+			page = pgdat->node_mem_map + i;
+			total++;
+			if (PageReserved(page))
+				reserved++;
+			else if (PageSwapCache(page))
+				cached++;
+			else if (page_count(page))
+				shared += page_count(page) - 1;
+		}
 	}
 	printk("%d pages of RAM\n",total);
 	printk("%d reserved pages\n",reserved);
@@ -382,7 +385,7 @@
 		free_page(addr);
 		totalram_pages++;
 	}
-	printk ("Freeing unused kernel memory: %dk freed\n",
+	printk ("Freeing unused kernel memory: %luk freed\n",
 		(&__init_end - &__init_begin) >> 10);
 }
 
@@ -498,13 +501,6 @@
 }
 #endif
 
-extern unsigned long prof_shift;
-extern unsigned long prof_len;
-extern unsigned int * prof_buffer;
-extern unsigned long dprof_shift;
-extern unsigned long dprof_len;
-extern unsigned int * dprof_buffer;
-
 void initialize_paca_hardware_interrupt_stack(void);
 
 void __init mem_init(void)
@@ -518,9 +514,8 @@
 	int datapages = 0;
 	int initpages = 0;
 
-	max_mapnr = max_low_pfn;
+	num_physpages = max_low_pfn;	/* RAM is assumed contiguous */
 	high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
-	num_physpages = max_mapnr;	/* RAM is assumed contiguous */
 	max_pfn = max_low_pfn;
 
 #ifdef CONFIG_DISCONTIGMEM
@@ -542,6 +537,8 @@
 	       PAGE_OFFSET, (unsigned long)__va(lmb_end_of_DRAM()));
 }
 #else
+	max_mapnr = num_physpages;
+
 	totalram_pages += free_all_bootmem();
 
 	if ( sysmap_size )
@@ -577,10 +574,6 @@
 
 #ifdef CONFIG_PPC_ISERIES
 	create_virtual_bus_tce_table();
-	/* HACK HACK This allows the iSeries profiling to use /proc/profile */
-	prof_shift = dprof_shift;
-	prof_len = dprof_len;
-	prof_buffer = dprof_buffer;
 #endif
 }
 
diff -Nru a/arch/ppc64/mm/numa.c b/arch/ppc64/mm/numa.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc64/mm/numa.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,171 @@
+/*
+ * NUMA support
+ *
+ * Copyright (C) 2002 Anton Blanchard <anton@au.ibm.com>, IBM
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/threads.h>
+#include <linux/bootmem.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/mmzone.h>
+#include <asm/lmb.h>
+
+#if 0
+#define dbg(format, arg...) udbg_printf(format, arg)
+#else
+#define dbg(format, arg...)
+#endif
+
+int numa_cpu_lookup_table[NR_CPUS] = { [ 0 ... (NR_CPUS - 1)] = -1};
+int numa_memory_lookup_table[MAX_MEMORY >> MEMORY_INCREMENT_SHIFT] =
+	{ [ 0 ... ((MAX_MEMORY >> MEMORY_INCREMENT_SHIFT) - 1)] = -1};
+int numa_node_exists[MAX_NUMNODES];
+
+struct pglist_data node_data[MAX_NUMNODES];
+bootmem_data_t plat_node_bdata[MAX_NUMNODES];
+
+static int __init parse_numa_properties(void)
+{
+	/* XXX implement */
+	return -1;
+}
+
+void __init do_init_bootmem(void)
+{
+	int nid;
+
+	min_low_pfn = 0;
+	max_low_pfn = lmb_end_of_DRAM() >> PAGE_SHIFT;
+
+	if (parse_numa_properties())
+		BUG();
+
+	for (nid = 0; nid < MAX_NUMNODES; nid++) {
+		unsigned long start, end;
+		unsigned long start_paddr, end_paddr;
+		int i;
+		unsigned long bootmem_paddr;
+		unsigned long bootmap_size;
+
+		if (!numa_node_exists[nid])
+			continue;
+
+		/* Find start and end of this zone */
+		start = 0;
+		while (numa_memory_lookup_table[start] != nid)
+			start++;
+
+		end = (MAX_MEMORY >> MEMORY_INCREMENT_SHIFT) - 1;
+		while (numa_memory_lookup_table[end] != nid)
+			end--;
+		end++;
+
+		start_paddr = start << MEMORY_INCREMENT_SHIFT;
+		end_paddr = end << MEMORY_INCREMENT_SHIFT;
+
+		dbg("node %d\n", nid);
+		dbg("start_paddr = %lx\n", start_paddr);
+		dbg("end_paddr = %lx\n", end_paddr);
+
+		NODE_DATA(nid)->bdata = &plat_node_bdata[nid];
+
+		/* XXX FIXME: first bitmap hardwired to 1G */
+		if (start_paddr == 0)
+			bootmem_paddr = (1 << 30);
+		else
+			bootmem_paddr = start_paddr;
+
+		dbg("bootmap_paddr = %lx\n", bootmem_paddr);
+
+		bootmap_size = init_bootmem_node(NODE_DATA(nid),
+						 bootmem_paddr >> PAGE_SHIFT,
+						 start_paddr >> PAGE_SHIFT,
+						 end_paddr >> PAGE_SHIFT);
+
+		dbg("bootmap_size = %lx\n", bootmap_size);
+
+		for (i = 0; i < lmb.memory.cnt; i++) {
+			unsigned long physbase, size;
+			unsigned long type = lmb.memory.region[i].type;
+
+			if (type != LMB_MEMORY_AREA)
+				continue;
+
+			physbase = lmb.memory.region[i].physbase;
+			size = lmb.memory.region[i].size;
+
+			if (physbase < end_paddr &&
+			    (physbase+size) > start_paddr) {
+				/* overlaps */
+				if (physbase < start_paddr) {
+					size -= start_paddr - physbase;
+					physbase = start_paddr;
+				}
+
+				if (size > end_paddr - start_paddr)
+					size = end_paddr - start_paddr;
+
+				dbg("free_bootmem %lx %lx\n", physbase, size);
+				free_bootmem_node(NODE_DATA(nid), physbase,
+						  size);
+			}
+		}
+
+		for (i = 0; i < lmb.reserved.cnt; i++) {
+			unsigned long physbase = lmb.reserved.region[i].physbase;
+			unsigned long size = lmb.reserved.region[i].size;
+
+			if (physbase < end_paddr &&
+			    (physbase+size) > start_paddr) {
+				/* overlaps */
+				if (physbase < start_paddr) {
+					size -= start_paddr - physbase;
+					physbase = start_paddr;
+				}
+
+				if (size > end_paddr - start_paddr)
+					size = end_paddr - start_paddr;
+
+				dbg("reserve_bootmem %lx %lx\n", physbase,
+				    size);
+				reserve_bootmem_node(NODE_DATA(nid), physbase,
+						     size);
+			}
+		}
+
+		dbg("reserve_bootmem %lx %lx\n", bootmem_paddr, bootmap_size);
+		reserve_bootmem_node(NODE_DATA(nid), bootmem_paddr,
+				     bootmap_size);
+	}
+}
+
+void __init paging_init(void)
+{
+	unsigned long zones_size[MAX_NR_ZONES];
+	int i, nid;
+
+	for (i = 1; i < MAX_NR_ZONES; i++)
+		zones_size[i] = 0;
+
+	for (nid = 0; nid < MAX_NUMNODES; nid++) {
+		unsigned long start_pfn;
+		unsigned long end_pfn;
+
+		if (!numa_node_exists[nid])
+			continue;
+
+		start_pfn = plat_node_bdata[nid].node_boot_start >> PAGE_SHIFT;
+		end_pfn = plat_node_bdata[nid].node_low_pfn;
+
+		zones_size[ZONE_DMA] = end_pfn - start_pfn;
+		dbg("free_area_init node %d %lx %lx\n", nid, zones_size,
+		    start_pfn);
+		free_area_init_node(nid, NODE_DATA(nid), NULL, zones_size,
+				    start_pfn, NULL);
+	}
+}
diff -Nru a/arch/ppc64/xmon/xmon.c b/arch/ppc64/xmon/xmon.c
--- a/arch/ppc64/xmon/xmon.c	Fri Sep 20 08:20:47 2002
+++ b/arch/ppc64/xmon/xmon.c	Fri Sep 20 08:20:47 2002
@@ -332,10 +332,10 @@
 	cmd = cmds(excp);
 	if (cmd == 's') {
 		xmon_trace[smp_processor_id()] = SSTEP;
-		excp->msr |= 0x400;
+		excp->msr |= MSR_SE;
 	} else if (at_breakpoint(excp->nip)) {
 		xmon_trace[smp_processor_id()] = BRSTEP;
-		excp->msr |= 0x400;
+		excp->msr |= MSR_SE;
 	} else {
 		xmon_trace[smp_processor_id()] = 0;
 		insert_bpts();
@@ -450,7 +450,7 @@
 		remove_bpts();
 		excprint(regs);
 		xmon_trace[smp_processor_id()] = BRSTEP;
-		regs->msr |= 0x400;
+		regs->msr |= MSR_SE;
 	} else {
 		printf("Stopped at breakpoint %x (%lx %s)\n", (bp - bpts)+1, bp->address, bp->funcname);
 		xmon(regs);
@@ -480,7 +480,7 @@
 		remove_bpts();
 		excprint(regs);
 		xmon_trace[smp_processor_id()] = BRSTEP;
-		regs->msr |= 0x400;
+		regs->msr |= MSR_SE;
 	} else {
 		dabr.instr = regs->nip;
 		xmon(regs);
@@ -496,7 +496,7 @@
 		remove_bpts();
 		excprint(regs);
 		xmon_trace[smp_processor_id()] = BRSTEP;
-		regs->msr |= 0x400;
+		regs->msr |= MSR_SE;
 	} else {
 		xmon(regs);
 	}
@@ -734,7 +734,7 @@
 		printf("cpus stopped:");
 		for (cpu = 0; cpu < NR_CPUS; ++cpu) {
 			if (test_bit(cpu, &cpus_in_xmon)) {
-				printf(" %d", cpu);
+				printf(" %x", cpu);
 				if (cpu == smp_processor_id())
 					printf("*", cpu);
 			}
diff -Nru a/arch/s390/vmlinux.lds.S b/arch/s390/vmlinux.lds.S
--- a/arch/s390/vmlinux.lds.S	Fri Sep 20 08:20:44 2002
+++ b/arch/s390/vmlinux.lds.S	Fri Sep 20 08:20:44 2002
@@ -4,4 +4,4 @@
 #include "vmlinux-shared.lds"
 #else
 #include "vmlinux.lds"
-#endif
\ No newline at end of file
+#endif
diff -Nru a/arch/s390x/vmlinux.lds.S b/arch/s390x/vmlinux.lds.S
--- a/arch/s390x/vmlinux.lds.S	Fri Sep 20 08:20:44 2002
+++ b/arch/s390x/vmlinux.lds.S	Fri Sep 20 08:20:44 2002
@@ -4,4 +4,4 @@
 #include "vmlinux-shared.lds"
 #else
 #include "vmlinux.lds"
-#endif
\ No newline at end of file
+#endif
diff -Nru a/arch/sparc/Makefile b/arch/sparc/Makefile
--- a/arch/sparc/Makefile	Fri Sep 20 08:20:42 2002
+++ b/arch/sparc/Makefile	Fri Sep 20 08:20:42 2002
@@ -40,7 +40,7 @@
 CORE_FILES := arch/sparc/kernel/kernel.o arch/sparc/mm/mm.o $(CORE_FILES) \
 	arch/sparc/math-emu/math-emu.o
 
-LIBS := $(LIBS) arch/sparc/prom/promlib.a arch/sparc/lib/lib.a
+LIBS := $(LIBS) arch/sparc/prom/lib.a arch/sparc/lib/lib.a
 
 # This one has to come last
 SUBDIRS += arch/sparc/boot
diff -Nru a/arch/sparc/config.in b/arch/sparc/config.in
--- a/arch/sparc/config.in	Fri Sep 20 08:20:41 2002
+++ b/arch/sparc/config.in	Fri Sep 20 08:20:41 2002
@@ -208,6 +208,8 @@
    endmenu
 fi
 
+source net/ax25/Config.in
+
 # This one must be before the filesystem configs. -DaveM
 mainmenu_option next_comment
 comment 'Unix98 PTY support'
diff -Nru a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
--- a/arch/sparc/kernel/setup.c	Fri Sep 20 08:20:41 2002
+++ b/arch/sparc/kernel/setup.c	Fri Sep 20 08:20:41 2002
@@ -171,31 +171,23 @@
 		/* Process any command switches, otherwise skip it. */
 		if (*commands == '\0')
 			break;
-		else if (*commands == '-') {
+		if (*commands == '-') {
 			commands++;
 			while (*commands && *commands != ' ')
 				process_switch(*commands++);
 		} else {
 			if (!strncmp(commands, "console=", 8)) {
 				commands += 8;
-				if (!strncmp (commands, "ttya", 4)) {
-					console_fb = 2;
-					prom_printf ("Using /dev/ttya as console.\n");
-				} else if (!strncmp (commands, "ttyb", 4)) {
-					console_fb = 3;
-					prom_printf ("Using /dev/ttyb as console.\n");
 #if defined(CONFIG_PROM_CONSOLE)
-				} else if (!strncmp (commands, "prom", 4)) {
+				if (!strncmp (commands, "prom", 4)) {
 					char *p;
 					
 					for (p = commands - 8; *p && *p != ' '; p++)
 						*p = ' ';
 					conswitchp = &prom_con;
 					console_fb = 1;
-#endif
-				} else {
-					console_fb = 1;
 				}
+#endif
 			} else if (!strncmp(commands, "mem=", 4)) {
 				/*
 				 * "mem=XXX[kKmM] overrides the PROM-reported
@@ -342,33 +334,28 @@
 #ifndef CONFIG_SERIAL_CONSOLE	/* Not CONFIG_SERIAL_SUNCORE: to be gone. */
 	serial_console = 0;
 #else
-	switch (console_fb) {
-	case 0: /* Let get our io devices from prom */
-		{
-			int idev = prom_query_input_device();
-			int odev = prom_query_output_device();
-			if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
-				serial_console = 0;
-			} else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
-				serial_console = 1;
-			} else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
-				serial_console = 2;
-			} else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OTTYA) {
-				prom_printf("MrCoffee ttya\n");
-				serial_console = 1;
-			} else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OSCREEN) {
-				serial_console = 0;
-				prom_printf("MrCoffee keyboard\n");
-			} else {
-				prom_printf("Inconsistent or unknown console\n");
-				prom_printf("You cannot mix serial and non serial input/output devices\n");
-				prom_halt();
-			}
+	if (console_fb != 0) {
+		serial_console = 0;
+	} else {
+		int idev = prom_query_input_device();
+		int odev = prom_query_output_device();
+		if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
+			serial_console = 0;
+		} else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
+			serial_console = 1;
+		} else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
+			serial_console = 2;
+		} else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OTTYA) {
+			prom_printf("MrCoffee ttya\n");
+			serial_console = 1;
+		} else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OSCREEN) {
+			serial_console = 0;
+			prom_printf("MrCoffee keyboard\n");
+		} else {
+			prom_printf("Confusing console (idev %d, odev %d)\n",
+			    idev, odev);
+			serial_console = 1;
 		}
-		break;
-	case 1: serial_console = 0; break; /* Force one of the framebuffers as console */
-	case 2: serial_console = 1; break; /* Force ttya as console */
-	case 3: serial_console = 2; break; /* Force ttyb as console */
 	}
 #endif
 
diff -Nru a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
--- a/arch/sparc/kernel/sparc_ksyms.c	Fri Sep 20 08:20:41 2002
+++ b/arch/sparc/kernel/sparc_ksyms.c	Fri Sep 20 08:20:41 2002
@@ -46,6 +46,9 @@
 #include <asm/sbus.h>
 #include <asm/dma.h>
 #endif
+#ifdef CONFIG_PCI
+#include <asm/ebus.h>
+#endif
 #include <asm/a.out.h>
 #include <asm/io-unit.h>
 
@@ -183,10 +186,7 @@
 EXPORT_SYMBOL(sbus_ioremap);
 #endif
 #if CONFIG_PCI
-/* Actually, ioremap/iounmap are not PCI specific. But it is ok for drivers. */
-EXPORT_SYMBOL(ioremap);
-EXPORT_SYMBOL(iounmap);
-
+EXPORT_SYMBOL(ebus_chain);
 EXPORT_SYMBOL(insl);
 EXPORT_SYMBOL(outsl);
 EXPORT_SYMBOL(pci_alloc_consistent);
@@ -194,6 +194,9 @@
 EXPORT_SYMBOL(pci_map_single);
 EXPORT_SYMBOL(pci_unmap_single);
 EXPORT_SYMBOL(pci_dma_sync_single);
+/* Actually, ioremap/iounmap are not PCI specific. But it is ok for drivers. */
+EXPORT_SYMBOL(ioremap);
+EXPORT_SYMBOL(iounmap);
 #endif
 
 /* Solaris/SunOS binary compatibility */
diff -Nru a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
--- a/arch/sparc/mm/srmmu.c	Fri Sep 20 08:20:46 2002
+++ b/arch/sparc/mm/srmmu.c	Fri Sep 20 08:20:47 2002
@@ -316,6 +316,14 @@
 	unsigned long va_tmp, phys_tmp;
 	int lowest_failed = 0;
 
+	if (size < SRMMU_NOCACHE_BITMAP_SHIFT) {
+		printk("Size 0x%x too small for nocache request\n", size);
+		size = SRMMU_NOCACHE_BITMAP_SHIFT;
+	}
+	if (size & (SRMMU_NOCACHE_BITMAP_SHIFT-1)) {
+		printk("Size 0x%x unaligned int nocache request\n", size);
+		size += SRMMU_NOCACHE_BITMAP_SHIFT-1;
+	}
 	size = size >> SRMMU_NOCACHE_BITMAP_SHIFT;
 
 	spin_lock(&srmmu_nocache_spinlock);
@@ -376,8 +384,32 @@
 
 void srmmu_free_nocache(unsigned long vaddr, int size)
 {
-	int offset = (vaddr - SRMMU_NOCACHE_VADDR) >> SRMMU_NOCACHE_BITMAP_SHIFT;
+	int offset;
 
+	if (vaddr < SRMMU_NOCACHE_VADDR) {
+		printk("Vaddr %x is smaller than nocache base 0x%x\n",
+		    vaddr, SRMMU_NOCACHE_VADDR);
+		BUG();
+	}
+	if (vaddr >= SRMMU_NOCACHE_END) {
+		printk("Vaddr %x is bigger than nocache end 0x%x\n",
+		    vaddr, SRMMU_NOCACHE_END);
+		BUG();
+	}
+	if (size & (size-1)) {
+		printk("Size 0x%x is not a power of 2\n", size);
+		BUG();
+	}
+	if (size < SRMMU_NOCACHE_BITMAP_SHIFT) {
+		printk("Size 0x%x is too small\n", size);
+		BUG();
+	}
+	if (vaddr & (size-1)) {
+		printk("Vaddr 0x%x is not aligned to size 0x%x\n", vaddr, size);
+		BUG();
+	}
+
+	offset = (vaddr - SRMMU_NOCACHE_VADDR) >> SRMMU_NOCACHE_BITMAP_SHIFT;
 	size = size >> SRMMU_NOCACHE_BITMAP_SHIFT;
 
 	spin_lock(&srmmu_nocache_spinlock);
@@ -501,9 +533,13 @@
 
 static void srmmu_pte_free(struct page *pte)
 {
-	unsigned long p = (unsigned long)page_address(pte);
+	unsigned long p;
+
+	p = (unsigned long)page_address(pte);	/* Cached address (for test) */
 	if (p == 0)
 		BUG();
+	p = ((pte - mem_map) << PAGE_SHIFT);	/* Physical address */
+	p = (unsigned long) __nocache_va(p);	/* Nocached virtual */
 	srmmu_free_nocache(p, SRMMU_PTE_SZ_SOFT);
 }
 
diff -Nru a/arch/sparc/prom/Makefile b/arch/sparc/prom/Makefile
--- a/arch/sparc/prom/Makefile	Fri Sep 20 08:20:45 2002
+++ b/arch/sparc/prom/Makefile	Fri Sep 20 08:20:46 2002
@@ -2,13 +2,8 @@
 # Makefile for the Sun Boot PROM interface library under
 # Linux.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
 
-L_TARGET = promlib.a
+L_TARGET = lib.a
 
 obj-y := bootstr.o devmap.o devops.o init.o memory.o misc.o mp.o \
 	 palloc.o ranges.o segment.o console.o printf.o tree.o
diff -Nru a/arch/sparc64/Config.help b/arch/sparc64/Config.help
--- a/arch/sparc64/Config.help	Fri Sep 20 08:20:48 2002
+++ b/arch/sparc64/Config.help	Fri Sep 20 08:20:48 2002
@@ -25,6 +25,14 @@
 
   If you don't know what to do here, say N.
 
+CONFIG_HUGETLB_PAGE
+  This enables support for huge pages.  User space applications
+  can make use of this support with the sys_alloc_hugepages and
+  sys_free_hugepages system calls.  If your applications are
+  huge page aware, then say Y here.
+
+  Otherwise, say N.
+
 CONFIG_PREEMPT
   This option reduces the latency of the kernel when reacting to
   real-time or interactive events by allowing a low priority process to
diff -Nru a/arch/sparc64/Makefile b/arch/sparc64/Makefile
--- a/arch/sparc64/Makefile	Fri Sep 20 08:20:48 2002
+++ b/arch/sparc64/Makefile	Fri Sep 20 08:20:48 2002
@@ -8,6 +8,8 @@
 # Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
 #
 
+AFLAGS_vmlinux.lds.o += -Usparc
+
 # If the solaris /bin/sh wasn't so broken, I wouldn't need the following
 # line...
 SHELL  =/bin/bash
@@ -72,7 +74,7 @@
 
 CORE_FILES += arch/sparc64/math-emu/math-emu.o
 
-LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc64/prom/promlib.a \
+LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc64/prom/lib.a \
 	$(TOPDIR)/arch/sparc64/lib/lib.a
 
 vmlinux.aout: vmlinux
diff -Nru a/arch/sparc64/config.in b/arch/sparc64/config.in
--- a/arch/sparc64/config.in	Fri Sep 20 08:20:44 2002
+++ b/arch/sparc64/config.in	Fri Sep 20 08:20:44 2002
@@ -15,6 +15,8 @@
 define_bool CONFIG_VT_CONSOLE y
 define_bool CONFIG_HW_CONSOLE y
 
+bool 'SPARC64 Huge TLB Page Support' CONFIG_HUGETLB_PAGE
+
 bool 'Symmetric multi-processing support' CONFIG_SMP
 bool 'Preemptible Kernel' CONFIG_PREEMPT
 
@@ -218,6 +220,8 @@
    fi
    endmenu
 fi
+
+source net/ax25/Config.in
 
 # This one must be before the filesystem configs. -DaveM
 mainmenu_option next_comment
diff -Nru a/arch/sparc64/defconfig b/arch/sparc64/defconfig
--- a/arch/sparc64/defconfig	Fri Sep 20 08:20:44 2002
+++ b/arch/sparc64/defconfig	Fri Sep 20 08:20:44 2002
@@ -19,7 +19,7 @@
 # Loadable module support
 #
 CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
+CONFIG_MODVERSIONS=y
 CONFIG_KMOD=y
 
 #
@@ -29,6 +29,7 @@
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 CONFIG_HW_CONSOLE=y
+CONFIG_HUGETLB_PAGE=y
 CONFIG_SMP=y
 # CONFIG_PREEMPT is not set
 CONFIG_SPARC64=y
@@ -209,18 +210,8 @@
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
 # CONFIG_IDEDISK_STROKE is not set
-# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
-# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
-# CONFIG_BLK_DEV_IDEDISK_IBM is not set
-# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
-# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
-# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
-# CONFIG_BLK_DEV_IDEDISK_WD is not set
-# CONFIG_BLK_DEV_COMMERIAL is not set
-# CONFIG_BLK_DEV_TIVO is not set
 # CONFIG_BLK_DEV_IDECS is not set
 CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDECD_BAILOUT is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
 # CONFIG_IDE_TASK_IOCTL is not set
@@ -254,6 +245,7 @@
 # CONFIG_BLK_DEV_HPT34X is not set
 # CONFIG_HPT34X_AUTODMA is not set
 # CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_PIIX is not set
 # CONFIG_BLK_DEV_NFORCE is not set
 CONFIG_BLK_DEV_NS87415=y
 # CONFIG_BLK_DEV_OPTI621 is not set
@@ -493,7 +485,6 @@
 # CONFIG_LNE390 is not set
 CONFIG_FEALNX=m
 CONFIG_NATSEMI=m
-# CONFIG_NATSEMI_CABLE_MAGIC is not set
 CONFIG_NE2K_PCI=m
 # CONFIG_NE3210 is not set
 # CONFIG_ES3210 is not set
@@ -575,6 +566,34 @@
 # CONFIG_DM9102 is not set
 
 #
+# Amateur Radio support
+#
+CONFIG_HAMRADIO=y
+
+#
+# Packet Radio protocols
+#
+CONFIG_AX25=m
+CONFIG_AX25_DAMA_SLAVE=y
+CONFIG_NETROM=m
+CONFIG_ROSE=m
+
+#
+# AX.25 network device drivers
+#
+# CONFIG_MKISS is not set
+# CONFIG_6PACK is not set
+# CONFIG_BPQETHER is not set
+# CONFIG_SCC_DELAY is not set
+# CONFIG_SCC_TRXECHO is not set
+# CONFIG_BAYCOM_SER_FDX is not set
+# CONFIG_BAYCOM_SER_HDX is not set
+# CONFIG_BAYCOM_PAR is not set
+# CONFIG_BAYCOM_EPP is not set
+# CONFIG_SOUNDMODEM is not set
+# CONFIG_YAM is not set
+
+#
 # Unix 98 PTY support
 #
 CONFIG_UNIX98_PTYS=y
@@ -727,6 +746,10 @@
 CONFIG_UDF_RW=y
 CONFIG_UFS_FS=m
 CONFIG_UFS_FS_WRITE=y
+CONFIG_XFS_FS=m
+# CONFIG_XFS_RT is not set
+CONFIG_XFS_QUOTA=y
+CONFIG_QUOTACTL=y
 
 #
 # Network File Systems
diff -Nru a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
--- a/arch/sparc64/kernel/setup.c	Fri Sep 20 08:20:44 2002
+++ b/arch/sparc64/kernel/setup.c	Fri Sep 20 08:20:44 2002
@@ -151,7 +151,7 @@
 			pmd_t *pmdp;
 			pte_t *ptep;
 
-			for_each_task(p) {
+			for_each_process(p) {
 				mm = p->mm;
 				if (CTX_HWBITS(mm->context) == ctx)
 					break;
diff -Nru a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
--- a/arch/sparc64/kernel/sparc64_ksyms.c	Fri Sep 20 08:20:47 2002
+++ b/arch/sparc64/kernel/sparc64_ksyms.c	Fri Sep 20 08:20:47 2002
@@ -363,7 +363,6 @@
 EXPORT_SYMBOL(sun_do_break);
 EXPORT_SYMBOL(serial_console);
 EXPORT_SYMBOL(stop_a_enabled);
-EXPORT_SYMBOL(kbd_pt_regs);
 
 #ifdef CONFIG_DEBUG_BUGVERBOSE
 EXPORT_SYMBOL(do_BUG);
diff -Nru a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
--- a/arch/sparc64/kernel/sys_sparc.c	Fri Sep 20 08:20:46 2002
+++ b/arch/sparc64/kernel/sys_sparc.c	Fri Sep 20 08:20:46 2002
@@ -681,3 +681,100 @@
 	};
 	return err;
 }
+
+#ifdef CONFIG_HUGETLB_PAGE
+#define HPAGE_ALIGN(x)  (((unsigned long)x + (HPAGE_SIZE -1)) & HPAGE_MASK)
+extern long     sys_munmap(unsigned long, size_t);
+
+/* get_addr function gets the currently unused virtual range in
+ * the current process's address space.  It returns the LARGE_PAGE_SIZE
+ * aligned address (in cases of success).  Other kernel generic
+ * routines only could gurantee that allocated address is PAGE_SIZE aligned.
+ */
+static long get_addr(unsigned long addr, unsigned long len)
+{
+	struct vm_area_struct   *vma;
+	if (addr) {
+		addr = HPAGE_ALIGN(addr);
+		vma = find_vma(current->mm, addr);
+		if (((TASK_SIZE - len) >= addr) &&
+				(!vma || addr + len <= vma->vm_start))
+			goto found_addr;
+	}
+	addr = HPAGE_ALIGN(TASK_UNMAPPED_BASE);
+	for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
+		if (TASK_SIZE - len < addr)
+			return -ENOMEM;
+		if (!vma || ((addr + len) < vma->vm_start))
+			goto found_addr;
+		addr = vma->vm_end;
+	}
+found_addr:
+	addr = HPAGE_ALIGN(addr);
+	return addr;
+}
+
+extern int alloc_hugetlb_pages(int, unsigned long, unsigned long, int, int);
+
+asmlinkage long
+sys_alloc_hugepages(int key, unsigned long addr, unsigned long len, int prot, int flag)
+{
+	struct mm_struct *mm = current->mm;
+	unsigned long raddr;
+	int retval;
+
+	if (key < 0)
+		return -EINVAL;
+	if (len & (HPAGE_SIZE - 1))
+		return -EINVAL;
+	down_write(&mm->mmap_sem);
+	raddr = get_addr(addr, len);
+	retval = 0;
+	if (raddr == -ENOMEM) {
+		retval = -ENOMEM;
+		goto raddr_out;
+	}
+	retval = alloc_hugetlb_pages(key, raddr, len, prot, flag);
+
+raddr_out:
+	up_write(&mm->mmap_sem);
+	if (retval < 0)
+		return (long) retval;
+
+	return raddr;
+}
+
+extern int free_hugepages(struct vm_area_struct *);
+
+asmlinkage int
+sys_free_hugepages(unsigned long addr)
+{
+	struct mm_struct *mm = current->mm;
+	struct vm_area_struct *vma;
+	int retval;
+
+	vma = find_vma(current->mm, addr);
+	if ((!vma) || (!is_vm_hugetlb_page(vma)) || (vma->vm_start!=addr))
+		return -EINVAL;
+	down_write(&mm->mmap_sem);
+	spin_lock(&mm->page_table_lock);
+	retval = free_hugepages(vma);
+	spin_unlock(&mm->page_table_lock);
+	up_write(&mm->mmap_sem);
+	return retval;
+}
+
+#else
+
+asmlinkage long
+sys_alloc_hugepages(int key, unsigned long addr, size_t len, int prot, int flag)
+{
+	return -ENOSYS;
+}
+asmlinkage int
+sys_free_hugepages(unsigned long addr)
+{
+	return -ENOSYS;
+}
+
+#endif
diff -Nru a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
--- a/arch/sparc64/kernel/systbls.S	Fri Sep 20 08:20:45 2002
+++ b/arch/sparc64/kernel/systbls.S	Fri Sep 20 08:20:45 2002
@@ -65,8 +65,8 @@
 	.word sys32_ipc, sys32_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex
 /*220*/	.word sys32_sigprocmask, sys32_create_module, sys32_delete_module, sys32_get_kernel_syms, sys_getpgid
 	.word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys32_setfsuid16, sys32_setfsgid16
-/*230*/	.word sys32_select, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall
-	.word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
+/*230*/	.word sys32_select, sys_time, sys_nis_syscall, sys_stime, sys_alloc_hugepages
+	.word sys_free_hugepages, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
 /*240*/	.word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
 	.word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep
 /*250*/	.word sys32_mremap, sys32_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
diff -Nru a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
--- a/arch/sparc64/kernel/traps.c	Fri Sep 20 08:20:48 2002
+++ b/arch/sparc64/kernel/traps.c	Fri Sep 20 08:20:48 2002
@@ -1566,17 +1566,14 @@
 	printk("\n");
 }
 
-void show_trace_task(struct task_struct *tsk)
+void show_trace_raw(struct thread_info *tp, unsigned long ksp)
 {
-	unsigned long pc, fp;
-	unsigned long thread_base = (unsigned long) tsk->thread_info;
+	unsigned long pc, fp, thread_base;
 	struct reg_window *rw;
 	int count = 0;
 
-	if (!tsk)
-		return;
-
-	fp = tsk->thread_info->ksp + STACK_BIAS;
+	fp = ksp + STACK_BIAS;
+	thread_base = (unsigned long) tp;
 	do {
 		/* Bogus frame pointer? */
 		if (fp < (thread_base + sizeof(struct thread_info)) ||
@@ -1588,6 +1585,13 @@
 		fp = rw->ins[6] + STACK_BIAS;
 	} while (++count < 16);
 	printk("\n");
+}
+
+void show_trace_task(struct task_struct *tsk)
+{
+	if (tsk)
+		show_trace_raw(tsk->thread_info,
+			       tsk->thread_info->ksp);
 }
 
 void die_if_kernel(char *str, struct pt_regs *regs)
diff -Nru a/arch/sparc64/mm/Makefile b/arch/sparc64/mm/Makefile
--- a/arch/sparc64/mm/Makefile	Fri Sep 20 08:20:47 2002
+++ b/arch/sparc64/mm/Makefile	Fri Sep 20 08:20:47 2002
@@ -7,4 +7,6 @@
 O_TARGET := mm.o
 obj-y    := ultra.o fault.o init.o generic.o extable.o modutil.o
 
+obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
+
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
--- a/arch/sparc64/mm/fault.c	Fri Sep 20 08:20:48 2002
+++ b/arch/sparc64/mm/fault.c	Fri Sep 20 08:20:48 2002
@@ -130,8 +130,8 @@
 	return tally;
 }
 
-void unhandled_fault(unsigned long address, struct task_struct *tsk,
-                     struct pt_regs *regs)
+static void unhandled_fault(unsigned long address, struct task_struct *tsk,
+			    struct pt_regs *regs)
 {
 	if ((unsigned long) address < PAGE_SIZE) {
 		printk(KERN_ALERT "Unable to handle kernel NULL "
@@ -148,6 +148,19 @@
 	die_if_kernel("Oops", regs);
 }
 
+extern void show_trace_raw(struct thread_info *, unsigned long);
+
+static void bad_kernel_pc(struct pt_regs *regs)
+{
+	unsigned long ksp;
+
+	printk(KERN_CRIT "OOPS: Bogus kernel PC [%016lx] in fault handler\n",
+	       regs->tpc);
+	__asm__("mov %%sp, %0" : "=r" (ksp));
+	show_trace_raw(current_thread_info(), ksp);
+	unhandled_fault(regs->tpc, current, regs);
+}
+
 /*
  * We now make sure that mmap_sem is held in all paths that call 
  * this. Additionally, to prevent kswapd from ripping ptes from
@@ -215,7 +228,7 @@
 		if (!regs->tpc || (regs->tpc & 0x3))
 			return 0;
 		if (regs->tstate & TSTATE_PRIV) {
-			insn = *(unsigned int *)regs->tpc;
+			insn = *(unsigned int *) regs->tpc;
 		} else {
 			insn = get_user_insn(regs->tpc);
 		}
@@ -306,6 +319,20 @@
 	    (fault_code & FAULT_CODE_DTLB))
 		BUG();
 
+	if (regs->tstate & TSTATE_PRIV) {
+		unsigned long tpc = regs->tpc;
+		extern unsigned int _etext;
+
+		/* Sanity check the PC. */
+		if ((tpc >= KERNBASE && tpc < (unsigned long) &_etext) ||
+		    (tpc >= MODULES_VADDR && tpc < MODULES_END)) {
+			/* Valid, no problems... */
+		} else {
+			bad_kernel_pc(regs);
+			return;
+		}
+	}
+
 	/*
 	 * If we're in an interrupt or have no user
 	 * context, we must not take the fault..
@@ -314,7 +341,8 @@
 		goto intr_or_no_mm;
 
 	if (test_thread_flag(TIF_32BIT)) {
-		regs->tpc &= 0xffffffff;
+		if (!(regs->tstate & TSTATE_PRIV))
+			regs->tpc &= 0xffffffff;
 		address &= 0xffffffff;
 	}
 
diff -Nru a/arch/sparc64/mm/hugetlbpage.c b/arch/sparc64/mm/hugetlbpage.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/sparc64/mm/hugetlbpage.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,621 @@
+/*
+ * SPARC64 Huge TLB page support.
+ *
+ * Copyright (C) 2002 David S. Miller (davem@redhat.com)
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/smp_lock.h>
+#include <linux/slab.h>
+
+#include <asm/mman.h>
+#include <asm/pgalloc.h>
+#include <asm/tlb.h>
+#include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
+
+static struct vm_operations_struct hugetlb_vm_ops;
+struct list_head htlbpage_freelist;
+spinlock_t htlbpage_lock = SPIN_LOCK_UNLOCKED;
+extern long htlbpagemem;
+
+static void zap_hugetlb_resources(struct vm_area_struct *);
+
+#define MAX_ID 	32
+struct htlbpagekey {
+	struct inode *in;
+	int key;
+} htlbpagek[MAX_ID];
+
+static struct inode *find_key_inode(int key)
+{
+	int i;
+
+	for (i = 0; i < MAX_ID; i++) {
+		if (htlbpagek[i].key == key)
+			return htlbpagek[i].in;
+	}
+	return NULL;
+}
+
+static struct page *alloc_hugetlb_page(void)
+{
+	struct list_head *curr, *head;
+	struct page *page;
+
+	spin_lock(&htlbpage_lock);
+
+	head = &htlbpage_freelist;
+	curr = head->next;
+
+	if (curr == head) {
+		spin_unlock(&htlbpage_lock);
+		return NULL;
+	}
+	page = list_entry(curr, struct page, list);
+	list_del(curr);
+	htlbpagemem--;
+
+	spin_unlock(&htlbpage_lock);
+
+	set_page_count(page, 1);
+	memset(page_address(page), 0, HPAGE_SIZE);
+
+	return page;
+}
+
+static void free_hugetlb_page(struct page *page)
+{
+	spin_lock(&htlbpage_lock);
+	if ((page->mapping != NULL) && (page_count(page) == 2)) {
+		struct inode *inode = page->mapping->host;
+		int i;
+
+		ClearPageDirty(page);
+		remove_from_page_cache(page);
+		set_page_count(page, 1);
+		if ((inode->i_size -= HPAGE_SIZE) == 0) {
+			for (i = 0; i < MAX_ID; i++) {
+				if (htlbpagek[i].key == inode->i_ino) {
+					htlbpagek[i].key = 0;
+					htlbpagek[i].in = NULL;
+					break;
+				}
+			}
+			kfree(inode);
+		}
+	}
+	if (put_page_testzero(page)) {
+		list_add(&page->list, &htlbpage_freelist);
+		htlbpagemem++;
+	}
+	spin_unlock(&htlbpage_lock);
+}
+
+static pte_t *huge_pte_alloc_map(struct mm_struct *mm, unsigned long addr)
+{
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte = NULL;
+
+	pgd = pgd_offset(mm, addr);
+	if (pgd) {
+		pmd = pmd_alloc(mm, pgd, addr);
+		if (pmd)
+			pte = pte_alloc_map(mm, pmd, addr);
+	}
+	return pte;
+}
+
+static pte_t *huge_pte_offset_map(struct mm_struct *mm, unsigned long addr)
+{
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte = NULL;
+
+	pgd = pgd_offset(mm, addr);
+	if (pgd) {
+		pmd = pmd_offset(pgd, addr);
+		if (pmd)
+			pte = pte_offset_map(pmd, addr);
+	}
+	return pte;
+}
+
+static pte_t *huge_pte_offset_map_nested(struct mm_struct *mm, unsigned long addr)
+{
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte = NULL;
+
+	pgd = pgd_offset(mm, addr);
+	if (pgd) {
+		pmd = pmd_offset(pgd, addr);
+		if (pmd)
+			pte = pte_offset_map_nested(pmd, addr);
+	}
+	return pte;
+}
+
+#define mk_pte_huge(entry) do { pte_val(entry) |= _PAGE_SZ4MB; } while (0)
+
+static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma,
+			 struct page *page, pte_t * page_table, int write_access)
+{
+	pte_t entry;
+	unsigned long i;
+
+	mm->rss += (HPAGE_SIZE / PAGE_SIZE);
+
+	for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
+		if (write_access)
+			entry = pte_mkwrite(pte_mkdirty(mk_pte(page,
+							       vma->vm_page_prot)));
+		else
+			entry = pte_wrprotect(mk_pte(page, vma->vm_page_prot));
+		entry = pte_mkyoung(entry);
+		mk_pte_huge(entry);
+		pte_val(entry) += (i << PAGE_SHIFT);
+		set_pte(page_table, entry);
+		page_table++;
+	}
+}
+
+static int anon_get_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
+				 int write_access, pte_t * page_table)
+{
+	struct page *page;
+
+	page = alloc_hugetlb_page();
+	if (page == NULL)
+		return -1;
+	set_huge_pte(mm, vma, page, page_table, write_access);
+	return 1;
+}
+
+static int
+make_hugetlb_pages_present(unsigned long addr, unsigned long end, int flags)
+{
+	struct mm_struct *mm = current->mm;
+	struct vm_area_struct *vma;
+	pte_t *pte;
+	int write;
+
+	vma = find_vma(mm, addr);
+	if (!vma)
+		goto out_error1;
+
+	write = (vma->vm_flags & VM_WRITE) != 0;
+	if ((vma->vm_end - vma->vm_start) & (HPAGE_SIZE - 1))
+		goto out_error1;
+
+	spin_lock(&mm->page_table_lock);
+	do {
+		int err;
+
+		pte = huge_pte_alloc_map(mm, addr);
+		err = (!pte ||
+		       !pte_none(*pte) ||
+		       (anon_get_hugetlb_page(mm, vma,
+					      write ? VM_WRITE : VM_READ,
+					      pte) == -1));
+		if (pte)
+			pte_unmap(pte);
+		if (err)
+			goto out_error;
+
+		addr += HPAGE_SIZE;
+	} while (addr < end);
+	spin_unlock(&mm->page_table_lock);
+
+	vma->vm_flags |= (VM_HUGETLB | VM_RESERVED);
+	if (flags & MAP_PRIVATE)
+		vma->vm_flags |= VM_DONTCOPY;
+	vma->vm_ops = &hugetlb_vm_ops;
+	return 0;
+
+out_error:
+	if (addr > vma->vm_start) {
+		vma->vm_end = addr;
+		flush_cache_range(vma, vma->vm_start, vma->vm_end);
+		zap_hugetlb_resources(vma);
+		flush_tlb_range(vma, vma->vm_start, vma->vm_end);
+		vma->vm_end = end;
+	}
+	spin_unlock(&mm->page_table_lock);
+ out_error1:
+	return -1;
+}
+
+int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
+			    struct vm_area_struct *vma)
+{
+	pte_t *src_pte, *dst_pte, entry;
+	struct page *ptepage;
+	unsigned long addr = vma->vm_start;
+	unsigned long end = vma->vm_end;
+
+	while (addr < end) {
+		unsigned long i;
+
+		dst_pte = huge_pte_alloc_map(dst, addr);
+		if (!dst_pte)
+			goto nomem;
+
+		src_pte = huge_pte_offset_map_nested(src, addr);
+		entry = *src_pte;
+		pte_unmap_nested(src_pte);
+
+		ptepage = pte_page(entry);
+		get_page(ptepage);
+		for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
+			set_pte(dst_pte, entry);
+			pte_val(entry) += PAGE_SIZE;
+			dst_pte++;
+		}
+		pte_unmap(dst_pte - (1 << HUGETLB_PAGE_ORDER));
+
+		dst->rss += (HPAGE_SIZE / PAGE_SIZE);
+		addr += HPAGE_SIZE;
+	}
+	return 0;
+
+nomem:
+	return -ENOMEM;
+}
+
+int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
+			struct page **pages, struct vm_area_struct **vmas,
+			unsigned long *st, int *length, int i)
+{
+	pte_t *ptep, pte;
+	unsigned long start = *st;
+	unsigned long pstart;
+	int len = *length;
+	struct page *page;
+
+	do {
+		pstart = start;
+		ptep = huge_pte_offset_map(mm, start);
+		pte = *ptep;
+
+back1:
+		page = pte_page(pte);
+		if (pages) {
+			page += ((start & ~HPAGE_MASK) >> PAGE_SHIFT);
+			pages[i] = page;
+		}
+		if (vmas)
+			vmas[i] = vma;
+		i++;
+		len--;
+		start += PAGE_SIZE;
+		if (((start & HPAGE_MASK) == pstart) && len &&
+				(start < vma->vm_end))
+			goto back1;
+
+		pte_unmap(ptep);
+	} while (len && start < vma->vm_end);
+
+	*length = len;
+	*st = start;
+	return i;
+}
+
+static void zap_hugetlb_resources(struct vm_area_struct *mpnt)
+{
+	struct mm_struct *mm = mpnt->vm_mm;
+	unsigned long len, addr, end;
+	struct page *page;
+	pte_t *ptep;
+
+	addr = mpnt->vm_start;
+	end = mpnt->vm_end;
+	len = end - addr;
+	do {
+		unsigned long i;
+
+		ptep = huge_pte_offset_map(mm, addr);
+		page = pte_page(*ptep);
+		for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
+			pte_clear(ptep);
+			ptep++;
+		}
+		pte_unmap(ptep - (1 << HUGETLB_PAGE_ORDER));
+		free_hugetlb_page(page);
+		addr += HPAGE_SIZE;
+	} while (addr < end);
+	mm->rss -= (len >> PAGE_SHIFT);
+	mpnt->vm_ops = NULL;
+}
+
+static void unlink_vma(struct vm_area_struct *mpnt)
+{
+	struct mm_struct *mm = current->mm;
+	struct vm_area_struct *vma;
+
+	vma = mm->mmap;
+	if (vma == mpnt) {
+		mm->mmap = vma->vm_next;
+	} else {
+		while (vma->vm_next != mpnt) {
+			vma = vma->vm_next;
+		}
+		vma->vm_next = mpnt->vm_next;
+	}
+	rb_erase(&mpnt->vm_rb, &mm->mm_rb);
+	mm->mmap_cache = NULL;
+	mm->map_count--;
+}
+
+int free_hugepages(struct vm_area_struct *mpnt)
+{
+	unlink_vma(mpnt);
+
+	flush_cache_range(mpnt, mpnt->vm_start, mpnt->vm_end);
+	zap_hugetlb_resources(mpnt);
+	flush_tlb_range(mpnt, mpnt->vm_start, mpnt->vm_end);
+
+	kmem_cache_free(vm_area_cachep, mpnt);
+	return 1;
+}
+
+static struct inode *set_new_inode(unsigned long len, int prot, int flag, int key)
+{
+	struct inode *inode;
+	int i;
+
+	for (i = 0; i < MAX_ID; i++) {
+		if (htlbpagek[i].key == 0)
+			break;
+	}
+	if (i == MAX_ID)
+		return NULL;
+	inode = kmalloc(sizeof (struct inode), GFP_KERNEL);
+	if (inode == NULL)
+		return NULL;
+
+	inode_init_once(inode);
+	atomic_inc(&inode->i_writecount);
+	inode->i_mapping = &inode->i_data;
+	inode->i_mapping->host = inode;
+	inode->i_ino = (unsigned long)key;
+
+	htlbpagek[i].key = key;
+	htlbpagek[i].in = inode;
+	inode->i_uid = current->fsuid;
+	inode->i_gid = current->fsgid;
+	inode->i_mode = prot;
+	inode->i_size = len;
+	return inode;
+}
+
+static int check_size_prot(struct inode *inode, unsigned long len, int prot, int flag)
+{
+	if (inode->i_uid != current->fsuid)
+		return -1;
+	if (inode->i_gid != current->fsgid)
+		return -1;
+	if (inode->i_size != len)
+		return -1;
+	return 0;
+}
+
+static int alloc_shared_hugetlb_pages(int key, unsigned long addr, unsigned long len,
+				      int prot, int flag)
+{
+	struct mm_struct *mm = current->mm;
+	struct vm_area_struct *vma;
+	struct inode *inode;
+	struct address_space *mapping;
+	struct page *page;
+	int idx;
+	int retval = -ENOMEM;
+	int newalloc = 0;
+
+try_again:
+	spin_lock(&htlbpage_lock);
+
+	inode = find_key_inode(key);
+	if (inode == NULL) {
+		if (!capable(CAP_SYS_ADMIN)) {
+			if (!in_group_p(0)) {
+				retval = -EPERM;
+				goto out_err;
+			}
+		}
+		if (!(flag & IPC_CREAT)) {
+			retval = -ENOENT;
+			goto out_err;
+		}
+		inode = set_new_inode(len, prot, flag, key);
+		if (inode == NULL)
+			goto out_err;
+		newalloc = 1;
+	} else {
+		if (check_size_prot(inode, len, prot, flag) < 0) {
+			retval = -EINVAL;
+			goto out_err;
+		} else if (atomic_read(&inode->i_writecount)) {
+			spin_unlock(&htlbpage_lock);
+			goto try_again;
+		}
+	}
+	spin_unlock(&htlbpage_lock);
+	mapping = inode->i_mapping;
+
+	addr = do_mmap_pgoff(NULL, addr, len, (unsigned long) prot,
+			     MAP_NORESERVE|MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, 0);
+	if (IS_ERR((void *) addr))
+		goto freeinode;
+
+	vma = find_vma(mm, addr);
+	if (!vma) {
+		retval = -EINVAL;
+		goto freeinode;
+	}
+
+	spin_lock(&mm->page_table_lock);
+	do {
+		pte_t *pte = huge_pte_alloc_map(mm, addr);
+
+		if (!pte || !pte_none(pte)) {
+			if (pte)
+				pte_unmap(pte);
+			goto out;
+		}
+
+		idx = (addr - vma->vm_start) >> HPAGE_SHIFT;
+		page = find_get_page(mapping, idx);
+		if (page == NULL) {
+			page = alloc_hugetlb_page();
+			if (page == NULL) {
+				pte_unmap(pte);
+				goto out;
+			}
+			add_to_page_cache(page, mapping, idx);
+		}
+		set_huge_pte(mm, vma, page, pte,
+			     (vma->vm_flags & VM_WRITE));
+		pte_unmap(pte);
+
+		addr += HPAGE_SIZE;
+	} while (addr < vma->vm_end);
+
+	retval = 0;
+	vma->vm_flags |= (VM_HUGETLB | VM_RESERVED);
+	vma->vm_ops = &hugetlb_vm_ops;
+	spin_unlock(&mm->page_table_lock);
+	spin_lock(&htlbpage_lock);
+	atomic_set(&inode->i_writecount, 0);
+	spin_unlock(&htlbpage_lock);
+
+	return retval;
+
+out:
+	if (addr > vma->vm_start) {
+		unsigned long raddr;
+		raddr = vma->vm_end;
+		vma->vm_end = addr;
+
+		flush_cache_range(vma, vma->vm_start, vma->vm_end);
+		zap_hugetlb_resources(vma);
+		flush_tlb_range(vma, vma->vm_start, vma->vm_end);
+
+		vma->vm_end = raddr;
+	}
+	spin_unlock(&mm->page_table_lock);
+	do_munmap(mm, vma->vm_start, len);
+	if (newalloc)
+		goto freeinode;
+
+	return retval;
+
+out_err:
+	spin_unlock(&htlbpage_lock);
+
+freeinode:
+	if (newalloc) {
+		for (idx = 0; idx < MAX_ID; idx++) {
+			if (htlbpagek[idx].key == inode->i_ino) {
+				htlbpagek[idx].key = 0;
+				htlbpagek[idx].in = NULL;
+				break;
+			}
+		}
+		kfree(inode);
+	}
+	return retval;
+}
+
+static int alloc_private_hugetlb_pages(int key, unsigned long addr, unsigned long len,
+				       int prot, int flag)
+{
+	if (!capable(CAP_SYS_ADMIN)) {
+		if (!in_group_p(0))
+			return -EPERM;
+	}
+	addr = do_mmap_pgoff(NULL, addr, len, prot,
+			     MAP_NORESERVE|MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, 0);
+	if (IS_ERR((void *) addr))
+		return -ENOMEM;
+	if (make_hugetlb_pages_present(addr, (addr + len), flag) < 0) {
+		do_munmap(current->mm, addr, len);
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+int alloc_hugetlb_pages(int key, unsigned long addr, unsigned long len, int prot,
+		    int flag)
+{
+	if (key > 0)
+		return alloc_shared_hugetlb_pages(key, addr, len, prot, flag);
+	return alloc_private_hugetlb_pages(key, addr, len, prot, flag);
+}
+
+extern long htlbzone_pages;
+extern struct list_head htlbpage_freelist;
+
+int set_hugetlb_mem_size(int count)
+{
+	int j, lcount;
+	struct page *page, *map;
+
+	if (count < 0)
+		lcount = count;
+	else
+		lcount = count - htlbzone_pages;
+
+	if (lcount > 0) {	/* Increase the mem size. */
+		while (lcount--) {
+			page = alloc_pages(GFP_ATOMIC, HUGETLB_PAGE_ORDER);
+			if (page == NULL)
+				break;
+			map = page;
+			for (j = 0; j < (HPAGE_SIZE / PAGE_SIZE); j++) {
+				SetPageReserved(map);
+				map++;
+			}
+			spin_lock(&htlbpage_lock);
+			list_add(&page->list, &htlbpage_freelist);
+			htlbpagemem++;
+			htlbzone_pages++;
+			spin_unlock(&htlbpage_lock);
+		}
+		return (int) htlbzone_pages;
+	}
+
+	/* Shrink the memory size. */
+	while (lcount++) {
+		page = alloc_hugetlb_page();
+		if (page == NULL)
+			break;
+
+		spin_lock(&htlbpage_lock);
+		htlbzone_pages--;
+		spin_unlock(&htlbpage_lock);
+
+		map = page;
+		for (j = 0; j < (HPAGE_SIZE / PAGE_SIZE); j++) {
+			map->flags &= ~(1UL << PG_locked | 1UL << PG_error |
+					1UL << PG_referenced |
+					1UL << PG_dirty | 1UL << PG_active |
+					1UL << PG_reserved |
+					1UL << PG_private | 1UL << PG_writeback);
+			set_page_count(page, 0);
+			map++;
+		}
+		set_page_count(page, 1);
+		__free_pages(page, HUGETLB_PAGE_ORDER);
+	}
+	return (int) htlbzone_pages;
+}
+
+static struct vm_operations_struct hugetlb_vm_ops = {
+	.close	= zap_hugetlb_resources,
+};
diff -Nru a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
--- a/arch/sparc64/mm/init.c	Fri Sep 20 08:20:44 2002
+++ b/arch/sparc64/mm/init.c	Fri Sep 20 08:20:44 2002
@@ -1690,6 +1690,13 @@
 	}
 }
 
+#ifdef CONFIG_HUGETLB_PAGE
+long htlbpagemem = 0;
+long htlbpage_max;
+long htlbzone_pages;
+extern struct list_head htlbpage_freelist;
+#endif
+
 void __init mem_init(void)
 {
 	unsigned long codepages, datapages, initpages;
@@ -1726,7 +1733,7 @@
 	 * Set up the zero page, mark it reserved, so that page count
 	 * is not manipulated when freeing the page from user ptes.
 	 */
-	mem_map_zero = _alloc_pages(GFP_KERNEL, 0);
+	mem_map_zero = alloc_pages(GFP_KERNEL, 0);
 	if (mem_map_zero == NULL) {
 		prom_printf("paging_init: Cannot alloc zero page.\n");
 		prom_halt();
@@ -1766,6 +1773,32 @@
 
 	if (tlb_type == cheetah || tlb_type == cheetah_plus)
 		cheetah_ecache_flush_init();
+#ifdef CONFIG_HUGETLB_PAGE
+	{
+		long i, j;
+		struct page *page, *map;
+
+		/* For now reserve quarter for hugetlb_pages. */
+		htlbzone_pages = (num_physpages >> ((HPAGE_SHIFT - PAGE_SHIFT) + 2)) ;
+
+		/* Will make this kernel command line. */
+		INIT_LIST_HEAD(&htlbpage_freelist);
+		for (i = 0; i < htlbzone_pages; i++) {
+			page = alloc_pages(GFP_ATOMIC, HUGETLB_PAGE_ORDER);
+			if (page == NULL)
+				break;
+			map = page;
+			for (j = 0; j < (HPAGE_SIZE / PAGE_SIZE); j++) {
+				SetPageReserved(map);
+				map++;
+			}
+			list_add(&page->list, &htlbpage_freelist);
+		}
+		printk("Total Huge_TLB_Page memory pages allocated %ld\n", i);
+		htlbzone_pages = htlbpagemem = i;
+		htlbpage_max = i;
+	}
+#endif
 }
 
 void free_initmem (void)
diff -Nru a/arch/sparc64/prom/Makefile b/arch/sparc64/prom/Makefile
--- a/arch/sparc64/prom/Makefile	Fri Sep 20 08:20:44 2002
+++ b/arch/sparc64/prom/Makefile	Fri Sep 20 08:20:44 2002
@@ -5,7 +5,7 @@
 
 EXTRA_AFLAGS := -ansi
 
-L_TARGET = promlib.a
+L_TARGET = lib.a
 obj-y   := bootstr.o devops.o init.o memory.o misc.o \
 	   tree.o console.o printf.o p1275.o map.o
 
diff -Nru a/drivers/acpi/Config.help b/drivers/acpi/Config.help
--- a/drivers/acpi/Config.help	Fri Sep 20 08:20:46 2002
+++ b/drivers/acpi/Config.help	Fri Sep 20 08:20:46 2002
@@ -86,6 +86,23 @@
   This driver will enable your system to shut down using ACPI, and
   dump your ACPI DSDT table using /proc/acpi/dsdt.
 
+CONFIG_ACPI_SLEEP
+  This option adds support for ACPI suspend states. 
+
+  With this option, you will be able to put the system "to sleep". 
+  Sleep states are low power states for the system and devices. All
+  of the system operating state is saved to either memory or disk
+  (depending on the state), to allow the system to resume operation
+  quickly at your request.
+
+  Although this option sounds really nifty, barely any of the device
+  drivers have been converted to the new driver model and hence few
+  have proper power management support. 
+
+  This option is not recommended for anyone except those doing driver
+  power management development.
+
+
 CONFIG_ACPI_DEBUG
   The ACPI driver can optionally report errors with a great deal
   of verbosity. Saying Y enables these statements. This will increase
diff -Nru a/drivers/acpi/Config.in b/drivers/acpi/Config.in
--- a/drivers/acpi/Config.in	Fri Sep 20 08:20:47 2002
+++ b/drivers/acpi/Config.in	Fri Sep 20 08:20:47 2002
@@ -15,6 +15,7 @@
       define_bool CONFIG_ACPI_BOOT y
 
       if [ "$CONFIG_ACPI_HT_ONLY" != "y" ]; then
+	 bool     '  Sleep States' CONFIG_ACPI_SLEEP
          tristate '  AC Adapter' CONFIG_ACPI_AC
          tristate '  Battery' CONFIG_ACPI_BATTERY
          tristate '  Button' CONFIG_ACPI_BUTTON
@@ -33,7 +34,6 @@
          define_bool CONFIG_ACPI_EC y
          define_bool CONFIG_ACPI_POWER y
          define_bool CONFIG_ACPI_PCI $CONFIG_PCI
-         define_bool CONFIG_ACPI_SLEEP $CONFIG_SOFTWARE_SUSPEND
          define_bool CONFIG_ACPI_SYSTEM	y
       fi
    fi
@@ -49,6 +49,7 @@
       define_bool CONFIG_ACPI_PCI n
       define_bool CONFIG_ACPI_POWER n
       define_bool CONFIG_ACPI_SYSTEM n
+      define_bool CONFIG_ACPI_SLEEP n
       define_bool CONFIG_ACPI_BUTTON n
       define_bool CONFIG_ACPI_FAN n
       define_bool CONFIG_ACPI_PROCESSOR n
diff -Nru a/drivers/acpi/Makefile b/drivers/acpi/Makefile
--- a/drivers/acpi/Makefile	Fri Sep 20 08:20:48 2002
+++ b/drivers/acpi/Makefile	Fri Sep 20 08:20:48 2002
@@ -19,7 +19,7 @@
 #
 # ACPI Boot-Time Table Parsing
 #
-obj-$(CONFIG_ACPI_BOOT)		+= tables.o
+obj-$(CONFIG_ACPI_BOOT)		+= tables.o blacklist.o
 
 #
 # ACPI Core Subsystem (Interpreter)
@@ -32,7 +32,7 @@
 #
 # ACPI Bus and Device Drivers
 #
-obj-$(CONFIG_ACPI_BUS)		+= bus.o 
+obj-$(CONFIG_ACPI_BUS)		+= bus.o driverfs.o
 obj-$(CONFIG_ACPI_AC) 		+= ac.o
 obj-$(CONFIG_ACPI_BATTERY)	+= battery.o
 obj-$(CONFIG_ACPI_BUTTON)	+= button.o
@@ -42,8 +42,11 @@
 obj-$(CONFIG_ACPI_POWER)	+= power.o
 obj-$(CONFIG_ACPI_PROCESSOR)	+= processor.o
 obj-$(CONFIG_ACPI_THERMAL)	+= thermal.o
-obj-$(CONFIG_ACPI_SYSTEM)	+= system.o
+obj-$(CONFIG_ACPI_SYSTEM)	+= system.o event.o
+obj-$(CONFIG_ACPI_DEBUG)	+= debug.o
+obj-$(CONFIG_ACPI_SLEEP)	+= sleep.o
 obj-$(CONFIG_ACPI_NUMA)		+= numa.o
 obj-$(CONFIG_ACPI_TOSHIBA)	+= toshiba_acpi.o
+obj-$(CONFIG_ACPI_BUS)		+= scan.o 
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/acpi/ac.c b/drivers/acpi/ac.c
--- a/drivers/acpi/ac.c	Fri Sep 20 08:20:44 2002
+++ b/drivers/acpi/ac.c	Fri Sep 20 08:20:44 2002
@@ -40,8 +40,16 @@
 MODULE_DESCRIPTION(ACPI_AC_DRIVER_NAME);
 MODULE_LICENSE("GPL");
 
-#define PREFIX			"ACPI: "
-
+#define ACPI_AC_COMPONENT		0x00020000
+#define ACPI_AC_CLASS			"ac_adapter"
+#define ACPI_AC_HID 			"ACPI0003"
+#define ACPI_AC_DRIVER_NAME		"ACPI AC Adapter Driver"
+#define ACPI_AC_DEVICE_NAME		"AC Adapter"
+#define ACPI_AC_FILE_STATE		"state"
+#define ACPI_AC_NOTIFY_STATUS		0x80
+#define ACPI_AC_STATUS_OFFLINE		0x00
+#define ACPI_AC_STATUS_ONLINE		0x01
+#define ACPI_AC_STATUS_UNKNOWN		0xFF
 
 int acpi_ac_add (struct acpi_device *device);
 int acpi_ac_remove (struct acpi_device *device, int type);
diff -Nru a/drivers/acpi/acpi_bus.h b/drivers/acpi/acpi_bus.h
--- a/drivers/acpi/acpi_bus.h	Fri Sep 20 08:20:44 2002
+++ b/drivers/acpi/acpi_bus.h	Fri Sep 20 08:20:44 2002
@@ -27,14 +27,13 @@
 #define __ACPI_BUS_H__
 
 #include <linux/version.h>
-
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,4))
-#include <linux/device.h>
-#define CONFIG_LDM
-#endif
+#include <linux/driverfs_fs.h>
 
 #include "include/acpi.h"
 
+#define PREFIX			"ACPI: "
+
+extern int			acpi_disabled;
 
 /* TBD: Make dynamic */
 #define ACPI_MAX_HANDLES	10
@@ -49,7 +48,6 @@
 acpi_status acpi_evaluate_integer (acpi_handle, acpi_string, acpi_object_list *, unsigned long *);
 acpi_status acpi_evaluate_reference (acpi_handle, acpi_string, acpi_object_list *, struct acpi_handle_list *);
 
-
 #ifdef CONFIG_ACPI_BUS
 
 #include <linux/proc_fs.h>
@@ -111,31 +109,11 @@
 	struct list_head	node;
 	char			name[80];
 	char			class[80];
-	int			references;
+	atomic_t		references;
 	char			*ids;		/* Supported Hardware IDs */
 	struct acpi_device_ops	ops;
 };
 
-enum acpi_blacklist_predicates
-{
-	all_versions,
-	less_than_or_equal,
-	equal,
-	greater_than_or_equal,
-};
-
-struct acpi_blacklist_item
-{
-	char		oem_id[7];
-	char		oem_table_id[9];
-	u32		oem_revision;
-	acpi_table_type table;
-	enum acpi_blacklist_predicates oem_revision_predicate;
-	char		*reason;
-	u32		is_critical_error;
-};
-
-
 /*
  * ACPI Device
  * -----------
@@ -267,6 +245,7 @@
 	struct acpi_device	*parent;
 	struct list_head	children;
 	struct list_head	node;
+	struct list_head	g_list;
 	struct acpi_device_status status;
 	struct acpi_device_flags flags;
 	struct acpi_device_pnp	pnp;
@@ -276,9 +255,7 @@
 	struct acpi_device_ops	ops;
 	struct acpi_driver	*driver;
 	void			*driver_data;
-#ifdef CONFIG_LDM
-	struct device		dev;
-#endif
+	struct driver_dir_entry	driverfs_dir;
 };
 
 #define acpi_driver_data(d)	((d)->driver_data)
@@ -310,10 +287,9 @@
 int acpi_bus_receive_event (struct acpi_bus_event *event);
 int acpi_bus_register_driver (struct acpi_driver *driver);
 int acpi_bus_unregister_driver (struct acpi_driver *driver);
-int acpi_bus_scan (struct acpi_device *device);
-int acpi_init (void);
-void acpi_exit (void);
 
+int acpi_create_dir(struct acpi_device *);
+void acpi_remove_dir(struct acpi_device *);
 
 #endif /*CONFIG_ACPI_BUS*/
 
diff -Nru a/drivers/acpi/acpi_drivers.h b/drivers/acpi/acpi_drivers.h
--- a/drivers/acpi/acpi_drivers.h	Fri Sep 20 08:20:47 2002
+++ b/drivers/acpi/acpi_drivers.h	Fri Sep 20 08:20:47 2002
@@ -32,116 +32,17 @@
 
 #define ACPI_MAX_STRING			80
 
-
-/* --------------------------------------------------------------------------
-                                    ACPI Bus
-   -------------------------------------------------------------------------- */
-
 #define ACPI_BUS_COMPONENT		0x00010000
-#define ACPI_BUS_CLASS			"system_bus"
-#define ACPI_BUS_HID			"ACPI_BUS"
-#define ACPI_BUS_DRIVER_NAME		"ACPI Bus Driver"
-#define ACPI_BUS_DEVICE_NAME		"System Bus"
-
-
-/* --------------------------------------------------------------------------
-                                  AC Adapter
-   -------------------------------------------------------------------------- */
-
-#define ACPI_AC_COMPONENT		0x00020000
-#define ACPI_AC_CLASS			"ac_adapter"
-#define ACPI_AC_HID 			"ACPI0003"
-#define ACPI_AC_DRIVER_NAME		"ACPI AC Adapter Driver"
-#define ACPI_AC_DEVICE_NAME		"AC Adapter"
-#define ACPI_AC_FILE_STATE		"state"
-#define ACPI_AC_NOTIFY_STATUS		0x80
-#define ACPI_AC_STATUS_OFFLINE		0x00
-#define ACPI_AC_STATUS_ONLINE		0x01
-#define ACPI_AC_STATUS_UNKNOWN		0xFF
-
-
-/* --------------------------------------------------------------------------
-                                     Battery
-   -------------------------------------------------------------------------- */
-
-#define ACPI_BATTERY_COMPONENT		0x00040000
-#define ACPI_BATTERY_CLASS		"battery"
-#define ACPI_BATTERY_HID		"PNP0C0A"
-#define ACPI_BATTERY_DRIVER_NAME	"ACPI Battery Driver"
-#define ACPI_BATTERY_DEVICE_NAME	"Battery"
-#define ACPI_BATTERY_FILE_INFO		"info"
-#define ACPI_BATTERY_FILE_STATUS	"state"
-#define ACPI_BATTERY_FILE_ALARM		"alarm"
-#define ACPI_BATTERY_NOTIFY_STATUS	0x80
-#define ACPI_BATTERY_NOTIFY_INFO	0x81
-#define ACPI_BATTERY_UNITS_WATTS	"mW"
-#define ACPI_BATTERY_UNITS_AMPS		"mA"
-
-
-/* --------------------------------------------------------------------------
-                                      Button
-   -------------------------------------------------------------------------- */
+#define ACPI_SYSTEM_COMPONENT		0x02000000
 
-#define ACPI_BUTTON_COMPONENT		0x00080000
-#define ACPI_BUTTON_DRIVER_NAME		"ACPI Button Driver"
-#define ACPI_BUTTON_CLASS		"button"
-#define ACPI_BUTTON_FILE_INFO		"info"
-#define ACPI_BUTTON_TYPE_UNKNOWN	0x00
-#define ACPI_BUTTON_NOTIFY_STATUS	0x80
+/* _HID definitions */
 
-#define ACPI_BUTTON_SUBCLASS_POWER	"power"
-#define ACPI_BUTTON_HID_POWER		"PNP0C0C"	
+#define ACPI_POWER_HID			"ACPI_PWR"
+#define ACPI_PROCESSOR_HID		"ACPI_CPU"
+#define ACPI_SYSTEM_HID			"ACPI_SYS"
+#define ACPI_THERMAL_HID		"ACPI_THM"
 #define ACPI_BUTTON_HID_POWERF		"ACPI_FPB"
-#define ACPI_BUTTON_DEVICE_NAME_POWER	"Power Button (CM)"
-#define ACPI_BUTTON_DEVICE_NAME_POWERF	"Power Button (FF)"
-#define ACPI_BUTTON_TYPE_POWER		0x01
-#define ACPI_BUTTON_TYPE_POWERF		0x02
-
-#define ACPI_BUTTON_SUBCLASS_SLEEP	"sleep"
-#define ACPI_BUTTON_HID_SLEEP		"PNP0C0E"
 #define ACPI_BUTTON_HID_SLEEPF		"ACPI_FSB"
-#define ACPI_BUTTON_DEVICE_NAME_SLEEP	"Sleep Button (CM)"
-#define ACPI_BUTTON_DEVICE_NAME_SLEEPF	"Sleep Button (FF)"
-#define ACPI_BUTTON_TYPE_SLEEP		0x03
-#define ACPI_BUTTON_TYPE_SLEEPF		0x04
-
-#define ACPI_BUTTON_SUBCLASS_LID	"lid"
-#define ACPI_BUTTON_HID_LID		"PNP0C0D"
-#define ACPI_BUTTON_DEVICE_NAME_LID	"Lid Switch"
-#define ACPI_BUTTON_TYPE_LID		0x05
-
-
-/* --------------------------------------------------------------------------
-                                Embedded Controller
-   -------------------------------------------------------------------------- */
-
-#define ACPI_EC_COMPONENT		0x00100000
-#define ACPI_EC_CLASS			"embedded_controller"
-#define ACPI_EC_HID			"PNP0C09"
-#define ACPI_EC_DRIVER_NAME		"ACPI Embedded Controller Driver"
-#define ACPI_EC_DEVICE_NAME		"Embedded Controller"
-#define ACPI_EC_FILE_INFO		"info"
-
-#ifdef CONFIG_ACPI_EC
-
-int acpi_ec_ecdt_probe (void);
-int acpi_ec_init (void);
-void acpi_ec_exit (void);
-
-#endif
-
-
-/* --------------------------------------------------------------------------
-                                       Fan
-   -------------------------------------------------------------------------- */
-
-#define ACPI_FAN_COMPONENT		0x00200000
-#define ACPI_FAN_CLASS			"fan"
-#define ACPI_FAN_HID			"PNP0C0B"
-#define ACPI_FAN_DRIVER_NAME		"ACPI Fan Driver"
-#define ACPI_FAN_DEVICE_NAME		"Fan"
-#define ACPI_FAN_FILE_STATE		"state"
-#define ACPI_FAN_NOTIFY_STATUS		0x80
 
 
 /* --------------------------------------------------------------------------
@@ -154,28 +55,12 @@
 
 /* ACPI PCI Root Bridge (pci_root.c) */
 
-#define ACPI_PCI_ROOT_CLASS		"pci_bridge"
-#define ACPI_PCI_ROOT_HID		"PNP0A03"
-#define ACPI_PCI_ROOT_DRIVER_NAME	"ACPI PCI Root Bridge Driver"
-#define ACPI_PCI_ROOT_DEVICE_NAME	"PCI Root Bridge"
-
-int acpi_pci_root_init (void);
-void acpi_pci_root_exit (void);
 void acpi_pci_get_translations (acpi_pci_id* id, u64* mem_tra, u64* io_tra);
 
 /* ACPI PCI Interrupt Link (pci_link.c) */
 
-#define ACPI_PCI_LINK_CLASS		"pci_irq_routing"
-#define ACPI_PCI_LINK_HID		"PNP0C0F"
-#define ACPI_PCI_LINK_DRIVER_NAME	"ACPI PCI Interrupt Link Driver"
-#define ACPI_PCI_LINK_DEVICE_NAME	"PCI Interrupt Link"
-#define ACPI_PCI_LINK_FILE_INFO		"info"
-#define ACPI_PCI_LINK_FILE_STATUS	"state"
-
 int acpi_pci_link_check (void);
 int acpi_pci_link_get_irq (acpi_handle handle, int index);
-int acpi_pci_link_init (void);
-void acpi_pci_link_exit (void);
 
 /* ACPI PCI Interrupt Routing (pci_irq.c) */
 
@@ -195,98 +80,29 @@
                                   Power Resource
    -------------------------------------------------------------------------- */
 
-#define ACPI_POWER_COMPONENT		0x00800000
-#define ACPI_POWER_CLASS		"power_resource"
-#define ACPI_POWER_HID			"ACPI_PWR"
-#define ACPI_POWER_DRIVER_NAME		"ACPI Power Resource Driver"
-#define ACPI_POWER_DEVICE_NAME		"Power Resource"
-#define ACPI_POWER_FILE_INFO		"info"
-#define ACPI_POWER_FILE_STATUS		"state"
-#define ACPI_POWER_RESOURCE_STATE_OFF	0x00
-#define ACPI_POWER_RESOURCE_STATE_ON	0x01
-#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
-
 #ifdef CONFIG_ACPI_POWER
 
 int acpi_power_get_inferred_state (struct acpi_device *device);
 int acpi_power_transition (struct acpi_device *device, int state);
-int acpi_power_init (void);
-void acpi_power_exit (void);
-
 #endif
 
 
 /* --------------------------------------------------------------------------
+                                  Embedded Controller
+   -------------------------------------------------------------------------- */
+#ifdef CONFIG_ACPI_EC
+int acpi_ec_ecdt_probe (void);
+#endif
+
+/* --------------------------------------------------------------------------
                                     Processor
    -------------------------------------------------------------------------- */
 
-#define ACPI_PROCESSOR_COMPONENT	0x01000000
-#define ACPI_PROCESSOR_CLASS		"processor"
-#define ACPI_PROCESSOR_HID		"ACPI_CPU"
-#define ACPI_PROCESSOR_DRIVER_NAME	"ACPI Processor Driver"
-#define ACPI_PROCESSOR_DEVICE_NAME	"Processor"
-#define ACPI_PROCESSOR_FILE_INFO	"info"
-#define ACPI_PROCESSOR_FILE_POWER	"power"
-#define ACPI_PROCESSOR_FILE_PERFORMANCE	"performance"
-#define ACPI_PROCESSOR_FILE_THROTTLING	"throttling"
-#define ACPI_PROCESSOR_FILE_LIMIT	"limit"
-#define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80
-#define ACPI_PROCESSOR_NOTIFY_POWER	0x81
 #define ACPI_PROCESSOR_LIMIT_NONE	0x00
 #define ACPI_PROCESSOR_LIMIT_INCREMENT	0x01
 #define ACPI_PROCESSOR_LIMIT_DECREMENT	0x02
 
 int acpi_processor_set_thermal_limit(acpi_handle handle, int type);
-
-
-/* --------------------------------------------------------------------------
-                                     System
-   -------------------------------------------------------------------------- */
-
-#define ACPI_SYSTEM_COMPONENT		0x02000000
-#define ACPI_SYSTEM_CLASS		"system"
-#define ACPI_SYSTEM_HID			"ACPI_SYS"
-#define ACPI_SYSTEM_DRIVER_NAME		"ACPI System Driver"
-#define ACPI_SYSTEM_DEVICE_NAME		"System"
-#define ACPI_SYSTEM_FILE_INFO		"info"
-#define ACPI_SYSTEM_FILE_EVENT		"event"
-#define ACPI_SYSTEM_FILE_ALARM		"alarm"
-#define ACPI_SYSTEM_FILE_DSDT		"dsdt"
-#define ACPI_SYSTEM_FILE_FADT		"fadt"
-#define ACPI_SYSTEM_FILE_SLEEP		"sleep"
-#define ACPI_SYSTEM_FILE_DEBUG_LAYER	"debug_layer"
-#define ACPI_SYSTEM_FILE_DEBUG_LEVEL	"debug_level"
-
-#ifdef CONFIG_ACPI_SYSTEM
-
-int acpi_system_init (void);
-void acpi_system_exit (void);
-
-#endif
-
-
-/* --------------------------------------------------------------------------
-                                 Thermal Zone
-   -------------------------------------------------------------------------- */
-
-#define ACPI_THERMAL_COMPONENT		0x04000000
-#define ACPI_THERMAL_CLASS		"thermal_zone"
-#define ACPI_THERMAL_HID		"ACPI_THM"
-#define ACPI_THERMAL_DRIVER_NAME	"ACPI Thermal Zone Driver"
-#define ACPI_THERMAL_DEVICE_NAME	"Thermal Zone"
-#define ACPI_THERMAL_FILE_STATE		"state"
-#define ACPI_THERMAL_FILE_TEMPERATURE	"temperature"
-#define ACPI_THERMAL_FILE_TRIP_POINTS	"trip_points"
-#define ACPI_THERMAL_FILE_COOLING_MODE	"cooling_mode"
-#define ACPI_THERMAL_FILE_POLLING_FREQ	"polling_frequency"
-#define ACPI_THERMAL_NOTIFY_TEMPERATURE	0x80
-#define ACPI_THERMAL_NOTIFY_THRESHOLDS	0x81
-#define ACPI_THERMAL_NOTIFY_DEVICES	0x82
-#define ACPI_THERMAL_NOTIFY_CRITICAL	0xF0
-#define ACPI_THERMAL_NOTIFY_HOT		0xF1
-#define ACPI_THERMAL_MODE_ACTIVE	0x00
-#define ACPI_THERMAL_MODE_PASSIVE	0x01
-#define ACPI_THERMAL_PATH_POWEROFF	"/sbin/poweroff"
 
 
 /* --------------------------------------------------------------------------
diff -Nru a/drivers/acpi/acpi_ksyms.c b/drivers/acpi/acpi_ksyms.c
--- a/drivers/acpi/acpi_ksyms.c	Fri Sep 20 08:20:44 2002
+++ b/drivers/acpi/acpi_ksyms.c	Fri Sep 20 08:20:44 2002
@@ -124,7 +124,5 @@
 EXPORT_SYMBOL(acpi_bus_receive_event);
 EXPORT_SYMBOL(acpi_bus_register_driver);
 EXPORT_SYMBOL(acpi_bus_unregister_driver);
-EXPORT_SYMBOL(acpi_bus_scan);
-EXPORT_SYMBOL(acpi_init);
 
 #endif /*CONFIG_ACPI_BUS*/
diff -Nru a/drivers/acpi/battery.c b/drivers/acpi/battery.c
--- a/drivers/acpi/battery.c	Fri Sep 20 08:20:43 2002
+++ b/drivers/acpi/battery.c	Fri Sep 20 08:20:43 2002
@@ -40,13 +40,24 @@
 MODULE_DESCRIPTION(ACPI_BATTERY_DRIVER_NAME);
 MODULE_LICENSE("GPL");
 
-#define PREFIX			"ACPI: "
-
 
 #define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF
 
 #define ACPI_BATTERY_FORMAT_BIF	"NNNNNNNNNSSSS"
 #define ACPI_BATTERY_FORMAT_BST	"NNNN"
+
+#define ACPI_BATTERY_COMPONENT		0x00040000
+#define ACPI_BATTERY_CLASS		"battery"
+#define ACPI_BATTERY_HID		"PNP0C0A"
+#define ACPI_BATTERY_DRIVER_NAME	"ACPI Battery Driver"
+#define ACPI_BATTERY_DEVICE_NAME	"Battery"
+#define ACPI_BATTERY_FILE_INFO		"info"
+#define ACPI_BATTERY_FILE_STATUS	"state"
+#define ACPI_BATTERY_FILE_ALARM		"alarm"
+#define ACPI_BATTERY_NOTIFY_STATUS	0x80
+#define ACPI_BATTERY_NOTIFY_INFO	0x81
+#define ACPI_BATTERY_UNITS_WATTS	"mW"
+#define ACPI_BATTERY_UNITS_AMPS		"mA"
 
 static int acpi_battery_add (struct acpi_device *device);
 static int acpi_battery_remove (struct acpi_device *device, int type);
diff -Nru a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/acpi/blacklist.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,141 @@
+/*
+ *  blacklist.c
+ *
+ *  Check to see if the given machine has a known bad ACPI BIOS
+ *
+ *  Copyright (C) 2002 Andy Grover <andrew.grover@intel.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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include "acpi_bus.h"
+
+enum acpi_blacklist_predicates
+{
+        all_versions,
+        less_than_or_equal,
+        equal,
+        greater_than_or_equal,
+};
+
+struct acpi_blacklist_item
+{
+        char            oem_id[7];
+        char            oem_table_id[9];
+        u32             oem_revision;
+        acpi_table_type table;
+        enum acpi_blacklist_predicates oem_revision_predicate;
+        char            *reason;
+        u32             is_critical_error;
+};
+
+/*
+ * POLICY: If *anything* doesn't work, put it on the blacklist.
+ *	   If they are critical errors, mark it critical, and abort driver load.
+ */
+static struct acpi_blacklist_item acpi_blacklist[] __initdata =
+{
+	/* Portege 7020, BIOS 8.10 */
+	{"TOSHIB", "7020CT  ", 0x19991112, ACPI_DSDT, all_versions, "Implicit Return", 0},
+	/* Portege 4030 */
+	{"TOSHIB", "4030    ", 0x19991112, ACPI_DSDT, all_versions, "Implicit Return", 0},
+	/* Portege 310/320, BIOS 7.1 */
+	{"TOSHIB", "310     ", 0x19990511, ACPI_DSDT, all_versions, "Implicit Return", 0},
+	/* Seattle 2, old bios rev. */
+	{"INTEL ", "440BX   ", 0x00001000, ACPI_DSDT, less_than_or_equal, "Field beyond end of region", 0},
+	/* ASUS K7M */
+	{"ASUS  ", "K7M     ", 0x00001000, ACPI_DSDT, less_than_or_equal, "Field beyond end of region", 0},
+	/* Intel 810 Motherboard? */
+	{"MNTRAL", "MO81010A", 0x00000012, ACPI_DSDT, less_than_or_equal, "Field beyond end of region", 0},
+	/* Compaq Presario 711FR */
+	{"COMAPQ", "EAGLES", 0x06040000, ACPI_DSDT, less_than_or_equal, "SCI issues (C2 disabled)", 0},
+	/* Compaq Presario 1700 */
+	{"PTLTD ", "  DSDT  ", 0x06040000, ACPI_DSDT, less_than_or_equal, "Multiple problems", 1},
+	/* Sony FX120, FX140, FX150? */
+	{"SONY  ", "U0      ", 0x20010313, ACPI_DSDT, less_than_or_equal, "ACPI driver problem", 1},
+	/* Compaq Presario 800, Insyde BIOS */
+	{"INT440", "SYSFexxx", 0x00001001, ACPI_DSDT, less_than_or_equal, "Does not use _REG to protect EC OpRegions", 1},
+	/* IBM 600E - _ADR should return 7, but it returns 1 */
+	{"IBM   ", "TP600E  ", 0x00000105, ACPI_DSDT, less_than_or_equal, "Incorrect _ADR", 1},
+	{"VIA694", "AWRDACPI", 0, ACPI_DSDT, all_versions, "Bogus table", 1},
+	{"ASUS\0\0", "P2B-S   ", 0, ACPI_DSDT, all_versions, "Bogus PCI routing", 1},
+	{"COMPAQ", "DSDT", 0, ACPI_DSDT, all_versions, "Bogus PCI routing", 1},
+
+	{""}
+};
+
+
+int __init
+acpi_blacklisted(void)
+{
+	int i = 0;
+	int blacklisted = 0;
+	struct acpi_table_header *table_header;
+
+	while (acpi_blacklist[i].oem_id[0] != '\0')
+	{
+		if (!acpi_get_table_header_early(acpi_blacklist[i].table, &table_header)) {
+			i++;
+			continue;
+		}
+
+		if (strncmp(acpi_blacklist[i].oem_id, table_header->oem_id, 6)) {
+			i++;
+			continue;
+		}
+
+		if (strncmp(acpi_blacklist[i].oem_table_id, table_header->oem_table_id, 8)) {
+			i++;
+			continue;
+		}
+
+		if ((acpi_blacklist[i].oem_revision_predicate == all_versions)
+		    || (acpi_blacklist[i].oem_revision_predicate == less_than_or_equal
+		        && table_header->oem_revision <= acpi_blacklist[i].oem_revision)
+		    || (acpi_blacklist[i].oem_revision_predicate == greater_than_or_equal
+		        && table_header->oem_revision >= acpi_blacklist[i].oem_revision)
+		    || (acpi_blacklist[i].oem_revision_predicate == equal
+		        && table_header->oem_revision == acpi_blacklist[i].oem_revision)) {
+
+			printk(KERN_ERR PREFIX "Vendor \"%6.6s\" System \"%8.8s\" "
+				"Revision 0x%x has a known ACPI BIOS problem.\n",
+				acpi_blacklist[i].oem_id,
+				acpi_blacklist[i].oem_table_id,
+				acpi_blacklist[i].oem_revision);
+
+			printk(KERN_ERR PREFIX "Reason: %s. This is a %s error\n",
+				acpi_blacklist[i].reason,
+				(acpi_blacklist[i].is_critical_error ? "non-recoverable" : "recoverable"));
+
+			blacklisted = acpi_blacklist[i].is_critical_error;
+			break;
+		}
+		else {
+			i++;
+		}
+	}
+
+	return blacklisted;
+}
+
diff -Nru a/drivers/acpi/bus.c b/drivers/acpi/bus.c
--- a/drivers/acpi/bus.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/acpi/bus.c	Fri Sep 20 08:20:47 2002
@@ -22,11 +22,7 @@
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
 
-#include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/init.h>
-#include <linux/types.h>
-#include <linux/version.h>
 #include <linux/ioport.h>
 #include <linux/list.h>
 #include <linux/sched.h>
@@ -37,244 +33,27 @@
 #endif
 #include "acpi_bus.h"
 #include "acpi_drivers.h"
-#include "include/acinterp.h"	/* for acpi_ex_eisa_id_to_string() */
 
 
 #define _COMPONENT		ACPI_BUS_COMPONENT
 ACPI_MODULE_NAME		("acpi_bus")
 
-MODULE_AUTHOR("Paul Diefenbaugh");
-MODULE_DESCRIPTION(ACPI_BUS_DRIVER_NAME);
-MODULE_LICENSE("GPL");
-
-#define	PREFIX			"ACPI: "
-
 extern void eisa_set_level_irq(unsigned int irq);
 
-extern int			acpi_disabled;
-
 FADT_DESCRIPTOR			acpi_fadt;
 struct acpi_device		*acpi_root;
 struct proc_dir_entry		*acpi_root_dir;
 
 #define STRUCT_TO_INT(s)	(*((int*)&s))
 
-/*
- * POLICY: If *anything* doesn't work, put it on the blacklist.
- *	   If they are critical errors, mark it critical, and abort driver load.
- */
-static struct acpi_blacklist_item acpi_blacklist[] __initdata =
-{
-	/* Portege 7020, BIOS 8.10 */
-	{"TOSHIB", "7020CT  ", 0x19991112, ACPI_TABLE_DSDT, all_versions, "Implicit Return", 0},
-	/* Portege 4030 */
-	{"TOSHIB", "4030    ", 0x19991112, ACPI_TABLE_DSDT, all_versions, "Implicit Return", 0},
-	/* Portege 310/320, BIOS 7.1 */
-	{"TOSHIB", "310     ", 0x19990511, ACPI_TABLE_DSDT, all_versions, "Implicit Return", 0},
-	/* Seattle 2, old bios rev. */
-	{"INTEL ", "440BX   ", 0x00001000, ACPI_TABLE_DSDT, less_than_or_equal, "Field beyond end of region", 0},
-	/* ASUS K7M */
-	{"ASUS  ", "K7M     ", 0x00001000, ACPI_TABLE_DSDT, less_than_or_equal, "Field beyond end of region", 0},
-	/* Intel 810 Motherboard? */
-	{"MNTRAL", "MO81010A", 0x00000012, ACPI_TABLE_DSDT, less_than_or_equal, "Field beyond end of region", 0},
-	/* Compaq Presario 711FR */
-	{"COMAPQ", "EAGLES", 0x06040000, ACPI_TABLE_DSDT, less_than_or_equal, "SCI issues (C2 disabled)", 0},
-	/* Compaq Presario 1700 */
-	{"PTLTD ", "  DSDT  ", 0x06040000, ACPI_TABLE_DSDT, less_than_or_equal, "Multiple problems", 1},
-	/* Sony FX120, FX140, FX150? */
-	{"SONY  ", "U0      ", 0x20010313, ACPI_TABLE_DSDT, less_than_or_equal, "ACPI driver problem", 1},
-	/* Compaq Presario 800, Insyde BIOS */
-	{"INT440", "SYSFexxx", 0x00001001, ACPI_TABLE_DSDT, less_than_or_equal, "Does not use _REG to protect EC OpRegions", 1},
-	/* IBM 600E - _ADR should return 7, but it returns 1 */
-	{"IBM   ", "TP600E  ", 0x00000105, ACPI_TABLE_DSDT, less_than_or_equal, "Incorrect _ADR", 1},
-	{""}
-};
-
-
-/* --------------------------------------------------------------------------
-                          Linux Driver Model (LDM) Support
-   -------------------------------------------------------------------------- */
-
-#ifdef CONFIG_LDM
-
-static int acpi_device_probe(struct device *dev);
-static int acpi_device_remove(struct device *dev);
-static int acpi_device_suspend(struct device *dev, u32 state, u32 stage);
-static int acpi_device_resume(struct device *dev, u32 stage);
-
-static struct device_driver acpi_bus_driver = {
-	.probe = acpi_device_probe,
-	.remove = acpi_device_remove,	
-	.suspend = acpi_device_suspend,
-	.resume = acpi_device_resume,
-};
-
-
-static int
-acpi_device_probe (
-	struct device		*dev)
-{
-	ACPI_FUNCTION_TRACE("acpi_device_probe");
-
-	if (!dev)
-		return_VALUE(-EINVAL);
-
-	/* TBD */
-
-	return_VALUE(0);
-}
-
-
-static int
-acpi_device_remove (
-	struct device		*dev)
-{
-	ACPI_FUNCTION_TRACE("acpi_device_remove");
-
-	if (!dev)
-		return_VALUE(-EINVAL);
-
-	/* TBD */
-
-	return_VALUE(0);
-}
-
-
-static int
-acpi_device_suspend (
-	struct device		*dev,
-	u32			state,
-	u32			stage)
-{
-	ACPI_FUNCTION_TRACE("acpi_device_suspend");
-
-	if (!dev)
-		return_VALUE(-EINVAL);
-
-	/* TBD */
-
-	return_VALUE(0);
-}
-
-
-static int
-acpi_device_resume (
-	struct device		*dev,
-	u32			stage)
-{
-	ACPI_FUNCTION_TRACE("acpi_device_resume");
-
-	if (!dev)
-		return_VALUE(-EINVAL);
-
-	/* TBD */
-
-	return_VALUE(0);
-}
-
-#if 0 /* not used ATM */
-static int
-acpi_platform_add (
-	struct device		*dev)
-{
-	ACPI_FUNCTION_TRACE("acpi_platform_add");
-
-	if (!dev)
-		return -EINVAL;
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device %s (%s) added\n",
-		dev->name, dev->bus_id));
-
-	/* TBD */
-
-	return_VALUE(0);
-}
-
-
-static int
-acpi_platform_remove (
-	struct device		*dev)
-{
-	ACPI_FUNCTION_TRACE("acpi_platform_add");
-
-	if (!dev)
-		return -EINVAL;
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device %s (%s) removed\n",
-		dev->name, dev->bus_id));
-
-	/* TBD */
-
-	return_VALUE(0);
-}
-#endif /* unused */
-
-
-#endif /*CONFIG_LDM*/
-
-
-static int
-acpi_device_register (
-	struct acpi_device	*device,
-	struct acpi_device	*parent)
-{
-	int			result = 0;
-
-	ACPI_FUNCTION_TRACE("acpi_device_register");
-
-	if (!device)
-		return_VALUE(-EINVAL);
-
-#ifdef CONFIG_LDM
-	sprintf(device->dev.name, "ACPI device %s:%s", 
-		device->pnp.hardware_id, device->pnp.unique_id);
-	strncpy(device->dev.bus_id, device->pnp.bus_id, sizeof(acpi_bus_id));
-	if (parent)
-		device->dev.parent = &parent->dev;
-	device->dev.driver = &acpi_bus_driver;
-
-	result = device_register(&device->dev);
-#endif /*CONFIG_LDM*/
-
-	return_VALUE(result);
-}
-
-
-static int
-acpi_device_unregister (
-	struct acpi_device	*device)
-{
-	ACPI_FUNCTION_TRACE("acpi_device_unregister");
-
-	if (!device)
-		return_VALUE(-EINVAL);
-
-#ifdef CONFIG_LDM
-	put_device(&device->dev);
-#endif /*CONFIG_LDM*/
-
-	return_VALUE(0);
-}
-
-
 /* --------------------------------------------------------------------------
                                 Device Management
    -------------------------------------------------------------------------- */
 
-static void
-acpi_bus_data_handler (
+extern void acpi_bus_data_handler (
 	acpi_handle		handle,
 	u32			function,
-	void			*context)
-{
-	ACPI_FUNCTION_TRACE("acpi_bus_data_handler");
-
-	/* TBD */
-
-	return_VOID;
-}
-
-
+	void			*context);
 int
 acpi_bus_get_device (
 	acpi_handle		handle,
@@ -337,57 +116,6 @@
 }
 
 
-/*
-static int
-acpi_bus_create_device_fs (struct device *device)
-{
-	ACPI_FUNCTION_TRACE("acpi_bus_create_device_fs");
-
-	if (!device)
-		return_VALUE(-EINVAL);
-
-	if (device->dir.entry)
-		return_VALUE(-EEXIST);
-
-	if (!device->parent)
-		device->dir.entry = proc_mkdir(device->pnp.bus_id, NULL);
-	else
-		device->dir.entry = proc_mkdir(device->pnp.bus_id,
-			device->parent->fs.entry);
-
-	if (!device->dir.entry) {
-		printk(KERN_ERR PREFIX "Unable to create fs entry '%s'\n",
-			device->pnp.bus_id);
-		return_VALUE(-ENODEV);
-	}
-
-	return_VALUE(0);
-}
-
-
-static int
-acpi_bus_remove_device_fs (struct device *device)
-{
-	ACPI_FUNCTION_TRACE("acpi_bus_create_device_fs");
-
-	if (!device)
-		return_VALUE(-EINVAL);
-
-	if (!device->dir.entry)
-		return_VALUE(-ENODEV);
-
-	if (!device->parent)
-		remove_proc_entry(device->pnp_bus_id, NULL);
-	else
-		remove_proc_entry(device->pnp.bus_id, device->parent->fs.entry);
-
-	device->dir.entry = NULL;
-
-	return_VALUE(0);
-}
-*/
-
-
 /* --------------------------------------------------------------------------
                                  Power Management
    -------------------------------------------------------------------------- */
@@ -533,110 +261,6 @@
 }
 
 
-static int
-acpi_bus_get_power_flags (
-	struct acpi_device	*device)
-{
-	acpi_status             status = 0;
-	acpi_handle		handle = 0;
-	u32                     i = 0;
-
-	ACPI_FUNCTION_TRACE("acpi_bus_get_power_flags");
-
-	if (!device)
-		return -ENODEV;
-
-	/*
-	 * Power Management Flags
-	 */
-	status = acpi_get_handle(device->handle, "_PSC", &handle);
-	if (ACPI_SUCCESS(status))
-		device->power.flags.explicit_get = 1;
-	status = acpi_get_handle(device->handle, "_IRC", &handle);
-	if (ACPI_SUCCESS(status))
-		device->power.flags.inrush_current = 1;
-	status = acpi_get_handle(device->handle, "_PRW", &handle);
-	if (ACPI_SUCCESS(status))
-		device->power.flags.wake_capable = 1;
-
-	/*
-	 * Enumerate supported power management states
-	 */
-	for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) {
-		struct acpi_device_power_state *ps = &device->power.states[i];
-		char		object_name[5] = {'_','P','R','0'+i,'\0'};
-
-		/* Evaluate "_PRx" to se if power resources are referenced */
-		acpi_evaluate_reference(device->handle, object_name, NULL,
-			&ps->resources);
-		if (ps->resources.count) {
-			device->power.flags.power_resources = 1;
-			ps->flags.valid = 1;
-		}
-
-		/* Evaluate "_PSx" to see if we can do explicit sets */
-		object_name[2] = 'S';
-		status = acpi_get_handle(device->handle, object_name, &handle);
-		if (ACPI_SUCCESS(status)) {
-			ps->flags.explicit_set = 1;
-			ps->flags.valid = 1;
-		}
-
-		/* State is valid if we have some power control */
-		if (ps->resources.count || ps->flags.explicit_set)
-			ps->flags.valid = 1;
-
-		ps->power = -1;		/* Unknown - driver assigned */
-		ps->latency = -1;	/* Unknown - driver assigned */
-	}
-
-	/* Set defaults for D0 and D3 states (always valid) */
-	device->power.states[ACPI_STATE_D0].flags.valid = 1;
-	device->power.states[ACPI_STATE_D0].power = 100;
-	device->power.states[ACPI_STATE_D3].flags.valid = 1;
-	device->power.states[ACPI_STATE_D3].power = 0;
-
-	/*
-	 * System Power States
-	 * -------------------
-	 */
-	/* TBD: S1-S4 power state support and resource requirements. */
-	/*
-	for (i=ACPI_STATE_S1; i<ACPI_STATE_S5; i++) {
-		char name[5] = {'_','S',('0'+i),'D','\0'};
-		status = acpi_evaluate_integer(device->handle, name, NULL,
-			&state);
-		if (ACPI_FAILURE(status))
-			continue;
-	}
-	*/
-
-	/* TBD: System wake support and resource requirements. */
-
-	device->power.state = ACPI_STATE_UNKNOWN;
-
-	return 0;
-}
-
-
-/* --------------------------------------------------------------------------
-                              Performance Management
-   -------------------------------------------------------------------------- */
-
-static int
-acpi_bus_get_perf_flags (
-	struct acpi_device	*device)
-{
-	ACPI_FUNCTION_TRACE("acpi_bus_get_perf_flags");
-
-	if (!device)
-		return -ENODEV;
-
-	device->performance.state = ACPI_STATE_UNKNOWN;
-
-	return 0;
-}
-
 
 /* --------------------------------------------------------------------------
                                 Event Management
@@ -732,100 +356,6 @@
 
 
 /* --------------------------------------------------------------------------
-                               Namespace Management
-   -------------------------------------------------------------------------- */
-
-#define WALK_UP			0
-#define WALK_DOWN		1
-
-typedef int (*acpi_bus_walk_callback)(struct acpi_device*, int, void*);
-
-#define HAS_CHILDREN(d)		((d)->children.next != &((d)->children))
-#define HAS_SIBLINGS(d)		(((d)->parent) && ((d)->node.next != &(d)->parent->children))
-#define NODE_TO_DEVICE(n)	(list_entry(n, struct acpi_device, node))
-
-
-/**
- * acpi_bus_walk
- * -------------
- * Used to walk the ACPI Bus's device namespace.  Can walk down (depth-first)
- * or up.  Able to parse starting at any node in the namespace.  Note that a
- * callback return value of -ELOOP will terminate the walk.
- *
- * @start:	starting point
- * callback:	function to call for every device encountered while parsing
- * direction:	direction to parse (up or down)
- * @data:	context for this search operation
- */
-static int
-acpi_bus_walk (
-	struct acpi_device	*start, 
-	acpi_bus_walk_callback	callback, 
-	int			direction, 
-	void			*data)
-{
-	int			result = 0;
-	int			level = 0;
-	struct acpi_device	*device = NULL;
-
-	if (!start || !callback)
-		return -EINVAL;
-
-	device = start;
-
-	/*
-	 * Parse Namespace
-	 * ---------------
-	 * Parse a given subtree (specified by start) in the given direction.
-	 * Walking 'up' simply means that we execute the callback on leaf
-	 * devices prior to their parents (useful for things like removing
-	 * or powering down a subtree).
-	 */
-
-	while (device) {
-
-		if (direction == WALK_DOWN)
-			if (-ELOOP == callback(device, level, data))
-				break;
-
-		/* Depth First */
-
-		if (HAS_CHILDREN(device)) {
-			device = NODE_TO_DEVICE(device->children.next);
-			++level;
-			continue;
-		}
-
-		if (direction == WALK_UP)
-			if (-ELOOP == callback(device, level, data))
-				break;
-
-		/* Now Breadth */
-
-		if (HAS_SIBLINGS(device)) {
-			device = NODE_TO_DEVICE(device->node.next);
-			continue;
-		}
-
-		/* Scope Exhausted - Find Next */
-
-		while ((device = device->parent)) {
-			--level;
-			if (HAS_SIBLINGS(device)) {
-				device = NODE_TO_DEVICE(device->node.next);
-				break;
-			}
-		}
-	}
-
-	if ((direction == WALK_UP) && (result == 0))
-		callback(start, level, data);
-
-	return result;
-}
-
-
-/* --------------------------------------------------------------------------
                              Notification Handling
    -------------------------------------------------------------------------- */
 
@@ -1001,896 +531,10 @@
 	return_VOID;
 }
 
-
-/* --------------------------------------------------------------------------
-                                 Driver Management
-   -------------------------------------------------------------------------- */
-
-static LIST_HEAD(acpi_bus_drivers);
-static DECLARE_MUTEX(acpi_bus_drivers_lock);
-
-
-/**
- * acpi_bus_match 
- * --------------
- * Checks the device's hardware (_HID) or compatible (_CID) ids to see if it
- * matches the specified driver's criteria.
- */
-static int
-acpi_bus_match (
-	struct acpi_device	*device,
-	struct acpi_driver	*driver)
-{
-
-	if (!device || !driver)
-		return -EINVAL;
-
-	if (device->flags.hardware_id) {
-		if (strstr(driver->ids, device->pnp.hardware_id))
-			return 0;
-	}
-
-	if (device->flags.compatible_ids) {
-		acpi_status	status = AE_OK;
-		acpi_buffer	buffer = {ACPI_ALLOCATE_BUFFER, NULL};
-		acpi_object	*object = NULL;
-		char		cid[256];
-
-		memset(cid, 0, sizeof(cid));
-
-		status = acpi_evaluate_object(device->handle, "_CID", NULL, 
-			&buffer);
-		if (ACPI_FAILURE(status) || !buffer.pointer)
-			return -ENOENT;
-
-		object = (acpi_object *) buffer.pointer;
-
-		switch (object->type) {
-		case ACPI_TYPE_INTEGER:
-			acpi_ex_eisa_id_to_string((u32) object->integer.value, 
-				cid);
-			break;
-		case ACPI_TYPE_STRING:
-			strncpy(cid, object->string.pointer, sizeof(cid) - 1);
-			break;
-		case ACPI_TYPE_PACKAGE:
-			/* TBD: Support CID packages */
-			break;
-		}
-
-		if (!cid[0]) {
-			acpi_os_free(buffer.pointer);
-			return -ENOENT;
-		}
-
-		if (strstr(driver->ids, cid)) {
-			acpi_os_free(buffer.pointer);
-			return 0;
-		}
-
-		acpi_os_free(buffer.pointer);
-	}
-
-	return -ENOENT;
-}
-
-
-/**
- * acpi_bus_driver_init 
- * --------------------
- * Used to initialize a device via its device driver.  Called whenever a 
- * driver is bound to a device.  Invokes the driver's add() and start() ops.
- */
-static int
-acpi_bus_driver_init (
-	struct acpi_device	*device, 
-	struct acpi_driver	*driver)
-{
-	int			result = 0;
-
-	ACPI_FUNCTION_TRACE("acpi_bus_driver_init");
-
-	if (!device || !driver)
-		return_VALUE(-EINVAL);
-
-	if (!driver->ops.add)
-		return_VALUE(-ENOSYS);
-
-	result = driver->ops.add(device);
-	if (result) {
-		device->driver = NULL;
-		acpi_driver_data(device) = NULL;
-		return_VALUE(result);
-	}
-
-	/*
-	 * TBD - Configuration Management: Assign resources to device based
-	 * upon possible configuration and currently allocated resources.
-	 */
-
-	if (driver->ops.start) {
-		result = driver->ops.start(device);
-		if (result && driver->ops.remove)
-			driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL);
-		return_VALUE(result);
-	}
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Driver successfully bound to device\n"));
-
-#ifdef CONFIG_LDM
-	/* 
-	 * Update the device information (in the global device hierarchy) now
-	 * that there's a driver bound to it.
-	 */
-	strncpy(device->dev.name, device->pnp.device_name, 
-		sizeof(device->dev.name));
-#endif
-
-	if (driver->ops.scan) {
-		driver->ops.scan(device);
-	}
-
-	return_VALUE(0);
-}
-
-
-/**
- * acpi_bus_attach 
- * -------------
- * Callback for acpi_bus_walk() used to find devices that match a specific 
- * driver's criteria and then attach the driver.
- */
-static int
-acpi_bus_attach (
-	struct acpi_device	*device, 
-	int			level, 
-	void			*data)
-{
-	int			result = 0;
-	struct acpi_driver	*driver = NULL;
-
-	ACPI_FUNCTION_TRACE("acpi_bus_attach");
-
-	if (!device || !data)
-		return_VALUE(-EINVAL);
-
-	driver = (struct acpi_driver *) data;
-
-	if (device->driver)
-		return_VALUE(-EEXIST);
-
-	if (!device->status.present)
-		return_VALUE(-ENODEV);
-
-	result = acpi_bus_match(device, driver);
-	if (result)
-		return_VALUE(result);
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n",
-		driver->name, device->pnp.bus_id));
-	
-	result = acpi_bus_driver_init(device, driver);
-	if (result)
-		return_VALUE(result);
-
-	down(&acpi_bus_drivers_lock);
-	++driver->references;
-	up(&acpi_bus_drivers_lock);
-
-	return_VALUE(0);
-}
-
-
-/**
- * acpi_bus_unattach 
- * -----------------
- * Callback for acpi_bus_walk() used to find devices that match a specific 
- * driver's criteria and unattach the driver.
- */
-static int
-acpi_bus_unattach (
-	struct acpi_device	*device, 
-	int			level, 
-	void			*data)
-{
-	int			result = 0;
-	struct acpi_driver	*driver = (struct acpi_driver *) data;
-
-	ACPI_FUNCTION_TRACE("acpi_bus_unattach");
-
-	if (!device || !driver)
-		return_VALUE(-EINVAL);
-
-	if (device->driver != driver)
-		return_VALUE(-ENOENT);
-
-	if (!driver->ops.remove)
-		return_VALUE(-ENOSYS);
-
-	result = driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL);
-	if (result)
-		return_VALUE(result);
-
-	device->driver = NULL;
-	acpi_driver_data(device) = NULL;
-
-	down(&acpi_bus_drivers_lock);
-	driver->references--;
-	up(&acpi_bus_drivers_lock);
-
-	return_VALUE(0);
-}
-
-
-/**
- * acpi_bus_find_driver 
- * --------------------
- * Parses the list of registered drivers looking for a driver applicable for
- * the specified device.
- */
-static int
-acpi_bus_find_driver (
-	struct acpi_device	*device)
-{
-	int			result = -ENODEV;
-	struct list_head	*entry = NULL;
-	struct acpi_driver	*driver = NULL;
-
-	ACPI_FUNCTION_TRACE("acpi_bus_find_driver");
-
-	if (!device || device->driver)
-		return_VALUE(-EINVAL);
-
-	down(&acpi_bus_drivers_lock);
-
-	list_for_each(entry, &acpi_bus_drivers) {
-
-		driver = list_entry(entry, struct acpi_driver, node);
-
-		if (acpi_bus_match(device, driver))
-			continue;
-
-		result = acpi_bus_driver_init(device, driver);
-		if (!result)
-			++driver->references;
-
-		break;
-	}
-
-	up(&acpi_bus_drivers_lock);
-
-	return_VALUE(result);
-}
-
-
-/**
- * acpi_bus_register_driver 
- * ------------------------ 
- * Registers a driver with the ACPI bus.  Searches the namespace for all
- * devices that match the driver's criteria and binds.
- */
-int
-acpi_bus_register_driver (
-	struct acpi_driver	*driver)
-{
-	ACPI_FUNCTION_TRACE("acpi_bus_register_driver");
-
-	if (!driver)
-		return_VALUE(-EINVAL);
-
-	down(&acpi_bus_drivers_lock);
-	list_add_tail(&driver->node, &acpi_bus_drivers);
-	up(&acpi_bus_drivers_lock);
-
-	acpi_bus_walk(acpi_root, acpi_bus_attach, 
-		WALK_DOWN, driver);
-
-	return_VALUE(driver->references);
-}
-
-
-/**
- * acpi_bus_unregister_driver 
- * --------------------------
- * Unregisters a driver with the ACPI bus.  Searches the namespace for all
- * devices that match the driver's criteria and unbinds.
- */
-int
-acpi_bus_unregister_driver (
-	struct acpi_driver	*driver)
-{
-	ACPI_FUNCTION_TRACE("acpi_bus_unregister_driver");
-
-	if (!driver)
-		return_VALUE(-EINVAL);
-
-	acpi_bus_walk(acpi_root, acpi_bus_unattach, WALK_UP, driver);
-
-	if (driver->references)
-		return_VALUE(driver->references);
-
-	down(&acpi_bus_drivers_lock);
-	list_del(&driver->node);
-	up(&acpi_bus_drivers_lock);
-
-	return_VALUE(0);
-}
-
-
-/* --------------------------------------------------------------------------
-                                 Device Enumeration
-   -------------------------------------------------------------------------- */
-
-static int 
-acpi_bus_get_flags (
-	struct acpi_device	*device)
-{
-	acpi_status		status = AE_OK;
-	acpi_handle		temp = NULL;
-
-	ACPI_FUNCTION_TRACE("acpi_bus_get_flags");
-
-	/* Presence of _STA indicates 'dynamic_status' */
-	status = acpi_get_handle(device->handle, "_STA", &temp);
-	if (ACPI_SUCCESS(status))
-		device->flags.dynamic_status = 1;
-
-	/* Presence of _CID indicates 'compatible_ids' */
-	status = acpi_get_handle(device->handle, "_CID", &temp);
-	if (ACPI_SUCCESS(status))
-		device->flags.compatible_ids = 1;
-
-	/* Presence of _RMV indicates 'removable' */
-	status = acpi_get_handle(device->handle, "_RMV", &temp);
-	if (ACPI_SUCCESS(status))
-		device->flags.removable = 1;
-
-	/* Presence of _EJD|_EJ0 indicates 'ejectable' */
-	status = acpi_get_handle(device->handle, "_EJD", &temp);
-	if (ACPI_SUCCESS(status))
-		device->flags.ejectable = 1;
-	else {
-		status = acpi_get_handle(device->handle, "_EJ0", &temp);
-		if (ACPI_SUCCESS(status))
-			device->flags.ejectable = 1;
-	}
-
-	/* Presence of _LCK indicates 'lockable' */
-	status = acpi_get_handle(device->handle, "_LCK", &temp);
-	if (ACPI_SUCCESS(status))
-		device->flags.lockable = 1;
-
-	/* Presence of _PS0|_PR0 indicates 'power manageable' */
-	status = acpi_get_handle(device->handle, "_PS0", &temp);
-	if (ACPI_FAILURE(status))
-		status = acpi_get_handle(device->handle, "_PR0", &temp);
-	if (ACPI_SUCCESS(status))
-		device->flags.power_manageable = 1;
-
-	/* TBD: Peformance management */
-
-	return_VALUE(0);
-}
-
-
-static int 
-acpi_bus_add (
-	struct acpi_device	**child,
-	struct acpi_device	*parent,
-	acpi_handle		handle,
-	int			type)
-{
-	int			result = 0;
-	acpi_status		status = AE_OK;
-	struct acpi_device	*device = NULL;
-	char			bus_id[5] = {'?',0};
-	acpi_buffer		buffer = {sizeof(bus_id), bus_id};
-	acpi_device_info	info;
-	char			*hid = NULL;
-	char			*uid = NULL;
-	int			i = 0;
-
-	ACPI_FUNCTION_TRACE("acpi_bus_add");
-
-	if (!child)
-		return_VALUE(-EINVAL);
-
-	device = kmalloc(sizeof(struct acpi_device), GFP_KERNEL);
-	if (!device) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Memory allocation error\n"));
-		return_VALUE(-ENOMEM);
-	}
-	memset(device, 0, sizeof(struct acpi_device));
-
-	device->handle = handle;
-	device->parent = parent;
-
-	memset(&info, 0, sizeof(acpi_device_info));
-
-	/*
-	 * Bus ID
-	 * ------
-	 * The device's Bus ID is simply the object name.
-	 * TBD: Shouldn't this value be unique (within the ACPI namespace)?
-	 */
-	switch (type) {
-	case ACPI_BUS_TYPE_SYSTEM:
-		sprintf(device->pnp.bus_id, "%s", "ACPI");
-		break;
-	case ACPI_BUS_TYPE_POWER_BUTTON:
-		sprintf(device->pnp.bus_id, "%s", "PWRF");
-		break;
-	case ACPI_BUS_TYPE_SLEEP_BUTTON:
-		sprintf(device->pnp.bus_id, "%s", "SLPF");
-		break;
-	default:
-		acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
-		/* Clean up trailing underscores (if any) */
-		for (i = 3; i > 1; i--) {
-			if (bus_id[i] == '_')
-				bus_id[i] = '\0';
-			else
-				break;
-		}
-		sprintf(device->pnp.bus_id, "%s", bus_id);
-		break;
-	}
-
-	/*
-	 * Flags
-	 * -----
-	 * Get prior to calling acpi_bus_get_status() so we know whether
-	 * or not _STA is present.  Note that we only look for object
-	 * handles -- cannot evaluate objects until we know the device is
-	 * present and properly initialized.
-	 */
-	result = acpi_bus_get_flags(device);
-	if (result)
-		goto end;
-
-	/*
-	 * Status
-	 * ------
-	 * See if the device is present.  We always assume that non-Device()
-	 * objects (e.g. thermal zones, power resources, processors, etc.) are
-	 * present, functioning, etc. (at least when parent object is present).
-	 * Note that _STA has a different meaning for some objects (e.g.
-	 * power resources) so we need to be careful how we use it.
-	 */
-	switch (type) {
-	case ACPI_BUS_TYPE_DEVICE:
-		result = acpi_bus_get_status(device);
-		if (result)
-			goto end;
-		break;
-	default:
-		STRUCT_TO_INT(device->status) = 0x0F;
-		break;
-	}
-	if (!device->status.present) {
-		result = -ENOENT;
-		goto end;
-	}
-
-	/*
-	 * Initialize Device
-	 * -----------------
-	 * TBD: Synch with Core's enumeration/initialization process.
-	 */
-
-	/*
-	 * Hardware ID, Unique ID, & Bus Address
-	 * -------------------------------------
-	 */
-	switch (type) {
-	case ACPI_BUS_TYPE_DEVICE:
-		status = acpi_get_object_info(handle, &info);
-		if (ACPI_FAILURE(status)) {
-			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-				"Error reading device info\n"));
-			result = -ENODEV;
-			goto end;
-		}
-		/* Clean up info strings (not NULL terminated) */
-		info.hardware_id[sizeof(info.hardware_id)-1] = '\0';
-		info.unique_id[sizeof(info.unique_id)-1] = '\0';
-		if (info.valid & ACPI_VALID_HID)
-			hid = info.hardware_id;
-		if (info.valid & ACPI_VALID_UID)
-			uid = info.unique_id;
-		if (info.valid & ACPI_VALID_ADR) {
-			device->pnp.bus_address = info.address;
-			device->flags.bus_address = 1;
-		}
-		break;
-	case ACPI_BUS_TYPE_POWER:
-		hid = ACPI_POWER_HID;
-		break;
-	case ACPI_BUS_TYPE_PROCESSOR:
-		hid = ACPI_PROCESSOR_HID;
-		break;
-	case ACPI_BUS_TYPE_SYSTEM:
-		hid = ACPI_SYSTEM_HID;
-		break;
-	case ACPI_BUS_TYPE_THERMAL:
-		hid = ACPI_THERMAL_HID;
-		break;
-	case ACPI_BUS_TYPE_POWER_BUTTON:
-		hid = ACPI_BUTTON_HID_POWERF;
-		break;
-	case ACPI_BUS_TYPE_SLEEP_BUTTON:
-		hid = ACPI_BUTTON_HID_SLEEPF;
-		break;
-	}
-
-	/* 
-	 * \_SB
-	 * ----
-	 * Fix for the system root bus device -- the only root-level device.
-	 */
-	if ((parent == ACPI_ROOT_OBJECT) && (type == ACPI_BUS_TYPE_DEVICE)) {
-		hid = ACPI_BUS_HID;
-		sprintf(device->pnp.device_name, "%s", ACPI_BUS_DEVICE_NAME);
-		sprintf(device->pnp.device_class, "%s", ACPI_BUS_CLASS);
-	}
-
-	if (hid) {
-		sprintf(device->pnp.hardware_id, "%s", hid);
-		device->flags.hardware_id = 1;
-	}
-	if (uid) {
-		sprintf(device->pnp.unique_id, "%s", uid);
-		device->flags.unique_id = 1;
-	}
-
-	/*
-	 * Power Management
-	 * ----------------
-	 */
-	if (device->flags.power_manageable) {
-		result = acpi_bus_get_power_flags(device);
-		if (result)
-			goto end;
-	}
-
-	/*
-	 * Performance Management
-	 * ----------------------
-	 */
-	if (device->flags.performance_manageable) {
-		result = acpi_bus_get_perf_flags(device);
-		if (result)
-			goto end;
-	}
-
-	/*
-	 * Context
-	 * -------
-	 * Attach this 'struct acpi_device' to the ACPI object.  This makes
-	 * resolutions from handle->device very efficient.  Note that we need
-	 * to be careful with fixed-feature devices as they all attach to the
-	 * root object.
-	 */
-	switch (type) {
-	case ACPI_BUS_TYPE_POWER_BUTTON:
-	case ACPI_BUS_TYPE_SLEEP_BUTTON:
-		break;
-	default:
-		status = acpi_attach_data(device->handle,
-			acpi_bus_data_handler, device);
-		break;
-	}
-	if (ACPI_FAILURE(status)) {
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-			"Error attaching device data\n"));
-		result = -ENODEV;
-		goto end;
-	}
-
-	/*
-	 * Linkage
-	 * -------
-	 * Link this device to its parent and siblings.
-	 */
-	INIT_LIST_HEAD(&device->children);
-	if (!device->parent)
-		INIT_LIST_HEAD(&device->node);
-	else
-		list_add_tail(&device->node, &device->parent->children);
-
-#ifdef CONFIG_ACPI_DEBUG
-	{
-		char		*type_string = NULL;
-		char		name[80] = {'?','\0'};
-		acpi_buffer	buffer = {sizeof(name), name};
-
-		acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-
-		switch (type) {
-		case ACPI_BUS_TYPE_DEVICE:
-			type_string = "Device";
-			break;
-		case ACPI_BUS_TYPE_POWER:
-			type_string = "Power Resource";
-			break;
-		case ACPI_BUS_TYPE_PROCESSOR:
-			type_string = "Processor";
-			break;
-		case ACPI_BUS_TYPE_SYSTEM:
-			type_string = "System";
-			break;
-		case ACPI_BUS_TYPE_THERMAL:
-			type_string = "Thermal Zone";
-			break;
-		case ACPI_BUS_TYPE_POWER_BUTTON:
-			type_string = "Power Button";
-			sprintf(name, "PWRB");
-			break;
-		case ACPI_BUS_TYPE_SLEEP_BUTTON:
-			type_string = "Sleep Button";
-			sprintf(name, "SLPB");
-			break;
-		}
-
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %s %s [%p]\n", 
-			type_string, name, handle));
-	}
-#endif /*CONFIG_ACPI_DEBUG*/
-
-	/*
-	 * Global Device Hierarchy:
-	 * ------------------------
-	 * Register this device with the global device hierarchy.
-	 */
-	acpi_device_register(device, parent);
-
-	/*
-	 * Bind _ADR-Based Devices
-	 * -----------------------
-	 * If there's a a bus address (_ADR) then we utilize the parent's 
-	 * 'bind' function (if exists) to bind the ACPI- and natively-
-	 * enumerated device representations.
-	 */
-	if (device->flags.bus_address) {
-		if (device->parent && device->parent->ops.bind)
-			device->parent->ops.bind(device);
-	}
-
-	/*
-	 * Locate & Attach Driver
-	 * ----------------------
-	 * If there's a hardware id (_HID) or compatible ids (_CID) we check
-	 * to see if there's a driver installed for this kind of device.  Note
-	 * that drivers can install before or after a device in enumerated.
-	 *
-	 * TBD: Assumes LDM provides driver hot-plug capability.
-	 */
-	if (device->flags.hardware_id || device->flags.compatible_ids)
-		acpi_bus_find_driver(device);
-
-end:
-	if (result) {
-		kfree(device);
-		return_VALUE(result);
-	}
-
-	*child = device;
-
-	return_VALUE(0);
-}
-
-
-static int
-acpi_bus_remove (
-	struct acpi_device	*device, 
-	int			type)
-{
-	ACPI_FUNCTION_TRACE("acpi_bus_remove");
-
-	if (!device)
-		return_VALUE(-ENODEV);
-
-	acpi_device_unregister(device);
-
-	kfree(device);
-
-	return_VALUE(0);
-}
-
-
-int
-acpi_bus_scan (
-	struct acpi_device	*start)
-{
-	acpi_status		status = AE_OK;
-	struct acpi_device	*parent = NULL;
-	struct acpi_device	*child = NULL;
-	acpi_handle		phandle = 0;
-	acpi_handle		chandle = 0;
-	acpi_object_type	type = 0;
-	u32			level = 1;
-
-	ACPI_FUNCTION_TRACE("acpi_bus_scan");
-
-	if (!start)
-		return_VALUE(-EINVAL);
-
-	parent = start;
-	phandle = start->handle;
-	
-	/*
-	 * Parse through the ACPI namespace, identify all 'devices', and
-	 * create a new 'struct acpi_device' for each.
-	 */
-	while ((level > 0) && parent) {
-
-		status = acpi_get_next_object(ACPI_TYPE_ANY, phandle,
-			chandle, &chandle);
-
-		/*
-		 * If this scope is exhausted then move our way back up.
-		 */
-		if (ACPI_FAILURE(status)) {
-			level--;
-			chandle = phandle;
-			acpi_get_parent(phandle, &phandle);
-			if (parent->parent)
-				parent = parent->parent;
-			continue;
-		}
-
-		status = acpi_get_type(chandle, &type);
-		if (ACPI_FAILURE(status))
-			continue;
-
-		/*
-		 * If this is a scope object then parse it (depth-first).
-		 */
-		if (type == ACPI_TYPE_ANY) {
-			/* Hack to get around scope identity problem */
-			status = acpi_get_next_object(ACPI_TYPE_ANY, chandle, 0, NULL);
-			if (ACPI_SUCCESS(status)) {
-				level++;
-				phandle = chandle;
-				chandle = 0;
-			}
-			continue;
-		}
-
-		/*
-		 * We're only interested in objects that we consider 'devices'.
-		 */
-		switch (type) {
-		case ACPI_TYPE_DEVICE:
-			type = ACPI_BUS_TYPE_DEVICE;
-			break;
-		case ACPI_TYPE_PROCESSOR:
-			type = ACPI_BUS_TYPE_PROCESSOR;
-			break;
-		case ACPI_TYPE_THERMAL:
-			type = ACPI_BUS_TYPE_THERMAL;
-			break;
-		case ACPI_TYPE_POWER:
-			type = ACPI_BUS_TYPE_POWER;
-			break;
-		default:
-			continue;
-		}
-
-		status = acpi_bus_add(&child, parent, chandle, type);
-		if (ACPI_FAILURE(status))
-			continue;
-
-		/*
-		 * If the device is present, enabled, and functioning then
-		 * parse its scope (depth-first).  Note that we need to
-		 * represent absent devices to facilitate PnP notifications
-		 * -- but only the subtree head (not all of its children,
-		 * which will be enumerated when the parent is inserted).
-		 *
-		 * TBD: Need notifications and other detection mechanisms
-		 *	in place before we can fully implement this.
-		 */
-		if (child->status.present) {
-			status = acpi_get_next_object(ACPI_TYPE_ANY, chandle,
-				0, NULL);
-			if (ACPI_SUCCESS(status)) {
-				level++;
-				phandle = chandle;
-				chandle = 0;
-				parent = child;
-			}
-		}
-	}
-
-	return_VALUE(0);
-}
-
-
-static int
-acpi_bus_scan_fixed (
-	struct acpi_device	*root)
-{
-	int			result = 0;
-	struct acpi_device	*device = NULL;
-
-	ACPI_FUNCTION_TRACE("acpi_bus_scan_fixed");
-
-	if (!root)
-		return_VALUE(-ENODEV);
-
-	/*
-	 * Enumerate all fixed-feature devices.
-	 */
-	if (acpi_fadt.pwr_button == 0)
-		result = acpi_bus_add(&device, acpi_root, 
-			ACPI_ROOT_OBJECT, ACPI_BUS_TYPE_POWER_BUTTON);
-
-	if (acpi_fadt.sleep_button == 0)
-		result = acpi_bus_add(&device, acpi_root, 
-			ACPI_ROOT_OBJECT, ACPI_BUS_TYPE_SLEEP_BUTTON);
-
-	return_VALUE(result);
-}
-
-
 /* --------------------------------------------------------------------------
                              Initialization/Cleanup
    -------------------------------------------------------------------------- */
 
-int __init
-acpi_blacklisted(void)
-{
-	int i = 0;
-	int blacklisted = 0;
-	acpi_table_header table_header;
-
-	while (acpi_blacklist[i].oem_id[0] != '\0')
-	{
-		if (!ACPI_SUCCESS(acpi_get_table_header(acpi_blacklist[i].table, 1, &table_header))) {
-			i++;
-			continue;
-		}
-
-		if (strncmp(acpi_blacklist[i].oem_id, table_header.oem_id, 6)) {
-			i++;
-			continue;
-		}
-
-		if (strncmp(acpi_blacklist[i].oem_table_id, table_header.oem_table_id, 8)) {
-			i++;
-			continue;
-		}
-
-		if ((acpi_blacklist[i].oem_revision_predicate == all_versions)
-		    || (acpi_blacklist[i].oem_revision_predicate == less_than_or_equal
-		        && table_header.oem_revision <= acpi_blacklist[i].oem_revision)
-		    || (acpi_blacklist[i].oem_revision_predicate == greater_than_or_equal
-		        && table_header.oem_revision >= acpi_blacklist[i].oem_revision)
-		    || (acpi_blacklist[i].oem_revision_predicate == equal
-		        && table_header.oem_revision == acpi_blacklist[i].oem_revision)) {
-
-			printk(KERN_ERR PREFIX "Vendor \"%6.6s\" System \"%8.8s\" "
-				"Revision 0x%x has a known ACPI BIOS problem.\n",
-				acpi_blacklist[i].oem_id,
-				acpi_blacklist[i].oem_table_id,
-				acpi_blacklist[i].oem_revision);
-
-			printk(KERN_ERR PREFIX "Reason: %s. This is a %s error\n",
-				acpi_blacklist[i].reason,
-				(acpi_blacklist[i].is_critical_error ? "non-recoverable" : "recoverable"));
-
-			blacklisted = acpi_blacklist[i].is_critical_error;
-			break;
-		}
-		else {
-			i++;
-		}
-	}
-
-	return blacklisted;
-}
-
 static int __init
 acpi_bus_init_irq (void)
 {
@@ -1956,10 +600,6 @@
 		goto error0;
 	}
 
-	if (acpi_blacklisted()) {
-		goto error1;
-	}
-
 	/*
 	 * Get a separate copy of the FADT for use by other drivers.
 	 */
@@ -1972,7 +612,7 @@
 #ifdef CONFIG_X86
 	/* Ensure the SCI is set to level-triggered, active-low */
 	if (acpi_ioapic)
-		mp_override_legacy_irq(acpi_fadt.sci_int, 3, 3, acpi_fadt.sci_int);
+		mp_config_ioapic_for_sci(acpi_fadt.sci_int);
 	else
 		eisa_set_level_irq(acpi_fadt.sci_int);
 #endif
@@ -1986,14 +626,15 @@
 #ifdef CONFIG_ACPI_EC
 	/*
 	 * ACPI 2.0 requires the EC driver to be loaded and work before
-	 * the EC device is found in the namespace. This is accomplished
-	 * by looking for the ECDT table, and getting the EC parameters out
-	 * of that.
+	 * the EC device is found in the namespace (i.e. before acpi_initialize_objects()
+	 * is called).
+	 *
+	 * This is accomplished by looking for the ECDT table, and getting 
+	 * the EC parameters out of that.
 	 */
-	result = acpi_ec_ecdt_probe();
-	if (result) {
+	status = acpi_ec_ecdt_probe();
+	if (ACPI_FAILURE(status))
 		goto error1;
-	}
 #endif
 
 	status = acpi_initialize_objects(ACPI_FULL_INITIALIZATION);
@@ -2017,61 +658,17 @@
 	status = acpi_install_notify_handler(ACPI_ROOT_OBJECT, ACPI_SYSTEM_NOTIFY, &acpi_bus_notify, NULL);
 	if (ACPI_FAILURE(status)) {
 		printk(KERN_ERR PREFIX "Unable to register for device notifications\n");
-		result = -ENODEV;
 		goto error1;
 	}
 
 	/*
-	 * Create the root device in the bus's device tree
-	 */
-	result = acpi_bus_add(&acpi_root, NULL, ACPI_ROOT_OBJECT, 
-		ACPI_BUS_TYPE_SYSTEM);
-	if (result)
-		goto error2;
-
-	/*
 	 * Create the top ACPI proc directory
 	 */
-	acpi_device_dir(acpi_root) = proc_mkdir(ACPI_BUS_FILE_ROOT, NULL);
-	if (!acpi_root) {
-		result = -ENODEV;
-		goto error3;
-	}
-	acpi_root_dir = acpi_device_dir(acpi_root);
-
-	/*
-	 * Install drivers required for proper enumeration of the
-	 * ACPI namespace.
-	 */
-	acpi_system_init();	/* ACPI System */
-	acpi_power_init();	/* ACPI Bus Power Management */
-#ifdef CONFIG_ACPI_EC
-	acpi_ec_init();		/* ACPI Embedded Controller */
-#endif
-#ifdef CONFIG_ACPI_PCI
-	acpi_pci_link_init();	/* ACPI PCI Interrupt Link */
-	acpi_pci_root_init();	/* ACPI PCI Root Bridge */
-#endif
-	/*
-	 * Enumerate devices in the ACPI namespace.
-	 */
-	result = acpi_bus_scan_fixed(acpi_root);
-	if (result)
-		goto error4;
-	result = acpi_bus_scan(acpi_root);
-	if (result)
-		goto error4;
+	acpi_root_dir = proc_mkdir(ACPI_BUS_FILE_ROOT, NULL);
 
 	return_VALUE(0);
 
 	/* Mimic structured exception handling */
-error4:
-	remove_proc_entry(ACPI_BUS_FILE_ROOT, NULL);
-error3:
-	acpi_bus_remove(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
-error2:
-	acpi_remove_notify_handler(ACPI_ROOT_OBJECT,
-		ACPI_SYSTEM_NOTIFY, &acpi_bus_notify);
 error1:
 	acpi_terminate();
 error0:
@@ -2079,45 +676,7 @@
 }
 
 
-static void __exit
-acpi_bus_exit (void)
-{
-	acpi_status		status = AE_OK;
-
-	ACPI_FUNCTION_TRACE("acpi_bus_exit");
-
-	status = acpi_remove_notify_handler(ACPI_ROOT_OBJECT,
-		ACPI_SYSTEM_NOTIFY, acpi_bus_notify);
-	if (ACPI_FAILURE(status))
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-			"Error removing notify handler\n"));
-
-#ifdef CONFIG_ACPI_PCI
-	acpi_pci_root_exit();
-	acpi_pci_link_exit();
-#endif
-#ifdef CONFIG_ACPI_EC
-	acpi_ec_exit();
-#endif
-	acpi_power_exit();
-	acpi_system_exit();
-
-	acpi_bus_remove(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
-
-	remove_proc_entry(ACPI_BUS_FILE_ROOT, NULL);
-
-	status = acpi_terminate();
-	if (ACPI_FAILURE(status))
-		printk(KERN_ERR PREFIX "Unable to terminate the ACPI Interpreter\n");
-	else
-		printk(KERN_ERR PREFIX "Interpreter disabled\n");
-
-	return_VOID;
-}
-
-
-int __init
-acpi_init (void)
+static int __init acpi_init (void)
 {
 	int			result = 0;
 
@@ -2134,42 +693,26 @@
 		return -ENODEV;
 	}
 
-#ifdef CONFIG_PM
-	if (PM_IS_ACTIVE()) {
-		printk(KERN_INFO PREFIX "APM is already active, exiting\n");
-		return -ENODEV;
-	}
-#endif
-
 	result = acpi_bus_init();
-	if (result)
-		return_VALUE(result);
-
-#ifdef CONFIG_PM
-	pm_active = 1;
-#endif
-
-	return_VALUE(0);
-}
-
-
-void __exit
-acpi_exit (void)
-{
-	ACPI_FUNCTION_TRACE("acpi_exit");
 
+	if (!result) {
 #ifdef CONFIG_PM
-	pm_active = 0;
+		if (!PM_IS_ACTIVE())
+			pm_active = 1;
+		else {
+			printk(KERN_INFO PREFIX "APM is already active, exiting\n");
+			acpi_disabled = 1;
+			result = -ENODEV;
+		}
 #endif
+	} else
+		acpi_disabled = 1;
 
-	acpi_bus_exit();
-
-	return_VOID;
+	return_VALUE(result);
 }
 
 
-int __init
-acpi_setup(char *str)
+static int __init acpi_setup(char *str)
 {
 	while (str && *str) {
 		if (strncmp(str, "off", 3) == 0)
diff -Nru a/drivers/acpi/button.c b/drivers/acpi/button.c
--- a/drivers/acpi/button.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/acpi/button.c	Fri Sep 20 08:20:41 2002
@@ -40,7 +40,31 @@
 MODULE_DESCRIPTION(ACPI_BUTTON_DRIVER_NAME);
 MODULE_LICENSE("GPL");
 
-#define PREFIX			"ACPI: "
+#define ACPI_BUTTON_COMPONENT		0x00080000
+#define ACPI_BUTTON_DRIVER_NAME		"ACPI Button Driver"
+#define ACPI_BUTTON_CLASS		"button"
+#define ACPI_BUTTON_FILE_INFO		"info"
+#define ACPI_BUTTON_TYPE_UNKNOWN	0x00
+#define ACPI_BUTTON_NOTIFY_STATUS	0x80
+
+#define ACPI_BUTTON_SUBCLASS_POWER	"power"
+#define ACPI_BUTTON_HID_POWER		"PNP0C0C"	
+#define ACPI_BUTTON_DEVICE_NAME_POWER	"Power Button (CM)"
+#define ACPI_BUTTON_DEVICE_NAME_POWERF	"Power Button (FF)"
+#define ACPI_BUTTON_TYPE_POWER		0x01
+#define ACPI_BUTTON_TYPE_POWERF		0x02
+
+#define ACPI_BUTTON_SUBCLASS_SLEEP	"sleep"
+#define ACPI_BUTTON_HID_SLEEP		"PNP0C0E"
+#define ACPI_BUTTON_DEVICE_NAME_SLEEP	"Sleep Button (CM)"
+#define ACPI_BUTTON_DEVICE_NAME_SLEEPF	"Sleep Button (FF)"
+#define ACPI_BUTTON_TYPE_SLEEP		0x03
+#define ACPI_BUTTON_TYPE_SLEEPF		0x04
+
+#define ACPI_BUTTON_SUBCLASS_LID	"lid"
+#define ACPI_BUTTON_HID_LID		"PNP0C0D"
+#define ACPI_BUTTON_DEVICE_NAME_LID	"Lid Switch"
+#define ACPI_BUTTON_TYPE_LID		0x05
 
 
 int acpi_button_add (struct acpi_device *device);
diff -Nru a/drivers/acpi/debug.c b/drivers/acpi/debug.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/acpi/debug.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,130 @@
+/*
+ * debug.c - ACPI debug interface to userspace.
+ */
+
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include "acpi_drivers.h"
+
+#define _COMPONENT		ACPI_SYSTEM_COMPONENT
+ACPI_MODULE_NAME		("debug")
+
+#define ACPI_SYSTEM_FILE_DEBUG_LAYER	"debug_layer"
+#define ACPI_SYSTEM_FILE_DEBUG_LEVEL	"debug_level"
+
+static int
+acpi_system_read_debug (
+	char			*page,
+	char			**start,
+	off_t			off,
+	int 			count,
+	int 			*eof,
+	void			*data)
+{
+	char			*p = page;
+	int 			size = 0;
+
+	if (off != 0)
+		goto end;
+
+	switch ((unsigned long) data) {
+	case 0:
+		p += sprintf(p, "0x%08x\n", acpi_dbg_layer);
+		break;
+	case 1:
+		p += sprintf(p, "0x%08x\n", acpi_dbg_level);
+		break;
+	default:
+		p += sprintf(p, "Invalid debug option\n");
+		break;
+	}
+	
+end:
+	size = (p - page);
+	if (size <= off+count) *eof = 1;
+	*start = page + off;
+	size -= off;
+	if (size>count) size = count;
+	if (size<0) size = 0;
+
+	return size;
+}
+
+
+static int
+acpi_system_write_debug (
+	struct file             *file,
+        const char              *buffer,
+	unsigned long           count,
+        void                    *data)
+{
+	char			debug_string[12] = {'\0'};
+
+	ACPI_FUNCTION_TRACE("acpi_system_write_debug");
+
+	if (count > sizeof(debug_string) - 1)
+		return_VALUE(-EINVAL);
+
+	if (copy_from_user(debug_string, buffer, count))
+		return_VALUE(-EFAULT);
+
+	debug_string[count] = '\0';
+
+	switch ((unsigned long) data) {
+	case 0:
+		acpi_dbg_layer = simple_strtoul(debug_string, NULL, 0);
+		break;
+	case 1:
+		acpi_dbg_level = simple_strtoul(debug_string, NULL, 0);
+		break;
+	default:
+		return_VALUE(-EINVAL);
+	}
+
+	return_VALUE(count);
+}
+
+static int __init acpi_debug_init(void)
+{
+	struct proc_dir_entry	*entry;
+	int error = 0;
+	char * name;
+
+	ACPI_FUNCTION_TRACE("acpi_debug_init");
+
+	if (acpi_disabled)
+		return_VALUE(0);
+
+	/* 'debug_layer' [R/W] */
+	name = ACPI_SYSTEM_FILE_DEBUG_LAYER;
+	entry = create_proc_read_entry(name, S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir,
+				       acpi_system_read_debug,(void *)0);
+	if (entry)
+		entry->write_proc = acpi_system_write_debug;
+	else
+		goto Error;
+
+	/* 'debug_level' [R/W] */
+	name = ACPI_SYSTEM_FILE_DEBUG_LEVEL;
+	entry = create_proc_read_entry(name, S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir,
+				       acpi_system_read_debug, (void *)1);
+	if (entry) 
+		entry->write_proc = acpi_system_write_debug;
+	else
+		goto Error;
+
+ Done:
+	return_VALUE(error);
+
+ Error:
+	ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
+			 "Unable to create '%s' proc fs entry\n", name));
+
+	remove_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LEVEL, acpi_root_dir);
+	remove_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LAYER, acpi_root_dir);
+	error = -EFAULT;
+	goto Done;
+}
+
+subsys_initcall(acpi_debug_init);
diff -Nru a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c
--- a/drivers/acpi/dispatcher/dsfield.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/acpi/dispatcher/dsfield.c	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: dsfield - Dispatcher field routines
- *              $Revision: 66 $
+ *              $Revision: 67 $
  *
  *****************************************************************************/
 
@@ -250,7 +250,7 @@
 				}
 
 				ACPI_REPORT_ERROR (("Field name [%4.4s] already exists in current scope\n",
-						  &arg->named.name));
+						(char *) &arg->named.name));
 			}
 			else {
 				arg->common.node = info->field_node;
@@ -271,7 +271,7 @@
 
 			if (position > ACPI_UINT32_MAX) {
 				ACPI_REPORT_ERROR (("Field [%4.4s] bit offset too large (> 0xFFFFFFFF)\n",
-					&info->field_node->name));
+						(char *) &info->field_node->name));
 				return_ACPI_STATUS (AE_SUPPORT);
 			}
 
@@ -417,7 +417,7 @@
 				}
 
 				ACPI_REPORT_ERROR (("Field name [%4.4s] already exists in current scope\n",
-						  &arg->named.name));
+						(char *) &arg->named.name));
 
 				/* Name already exists, just ignore this error */
 
diff -Nru a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c
--- a/drivers/acpi/dispatcher/dsobject.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/acpi/dispatcher/dsobject.c	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: dsobject - Dispatcher object management routines
- *              $Revision: 106 $
+ *              $Revision: 107 $
  *
  *****************************************************************************/
 
@@ -746,9 +746,10 @@
 
 			obj_desc->reference.opcode = AML_LOCAL_OP;
 			obj_desc->reference.offset = opcode - AML_LOCAL_OP;
+
 #ifndef ACPI_NO_METHOD_EXECUTION
-			acpi_ds_method_data_get_node (AML_LOCAL_OP, obj_desc->reference.offset,
-				walk_state, (acpi_namespace_node **) &obj_desc->reference.object);
+			status = acpi_ds_method_data_get_node (AML_LOCAL_OP, obj_desc->reference.offset,
+					 walk_state, (acpi_namespace_node **) &obj_desc->reference.object);
 #endif
 			break;
 
diff -Nru a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c
--- a/drivers/acpi/dispatcher/dswload.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/acpi/dispatcher/dswload.c	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: dswload - Dispatcher namespace load callbacks
- *              $Revision: 71 $
+ *              $Revision: 73 $
  *
  *****************************************************************************/
 
@@ -202,7 +202,26 @@
 			/* These are acceptable types */
 			break;
 
-		default:
+		case ACPI_TYPE_INTEGER:
+		case ACPI_TYPE_STRING:
+		case ACPI_TYPE_BUFFER:
+
+			/*
+			 * These types we will allow, but we will change the type.  This
+			 * enables some existing code of the form:
+			 *
+			 *  Name (DEB, 0)
+			 *  Scope (DEB) { ... }
+			 */
+
+			ACPI_REPORT_WARNING (("Invalid type (%s) for target of Scope operator [%4.4s], changing type to ANY\n",
+				acpi_ut_get_type_name (node->type), path));
+
+			node->type = ACPI_TYPE_ANY;
+			walk_state->scope_info->common.value = ACPI_TYPE_ANY;
+			break;
+
+	   default:
 
 			/* All other types are an error */
 
@@ -440,6 +459,51 @@
 	}
 
 	if (ACPI_SUCCESS (status)) {
+		/*
+		 * For the scope op, we must check to make sure that the target is
+		 * one of the opcodes that actually opens a scope
+		 */
+		if (walk_state->opcode == AML_SCOPE_OP) {
+			switch (node->type) {
+			case ACPI_TYPE_ANY:         /* Scope nodes are untyped (ANY) */
+			case ACPI_TYPE_DEVICE:
+			case ACPI_TYPE_METHOD:
+			case ACPI_TYPE_POWER:
+			case ACPI_TYPE_PROCESSOR:
+			case ACPI_TYPE_THERMAL:
+
+				/* These are acceptable types */
+				break;
+
+			case ACPI_TYPE_INTEGER:
+			case ACPI_TYPE_STRING:
+			case ACPI_TYPE_BUFFER:
+
+				/*
+				 * These types we will allow, but we will change the type.  This
+				 * enables some existing code of the form:
+				 *
+				 *  Name (DEB, 0)
+				 *  Scope (DEB) { ... }
+				 */
+
+				ACPI_REPORT_WARNING (("Invalid type (%s) for target of Scope operator [%4.4s], changing type to ANY\n",
+					acpi_ut_get_type_name (node->type), buffer_ptr));
+
+				node->type = ACPI_TYPE_ANY;
+				walk_state->scope_info->common.value = ACPI_TYPE_ANY;
+				break;
+
+		   default:
+
+				/* All other types are an error */
+
+				ACPI_REPORT_ERROR (("Invalid type (%s) for target of Scope operator [%4.4s]\n",
+					acpi_ut_get_type_name (node->type), buffer_ptr));
+
+				return (AE_AML_OPERAND_TYPE);
+			}
+		}
 		if (!op) {
 			/* Create a new op */
 
diff -Nru a/drivers/acpi/driverfs.c b/drivers/acpi/driverfs.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/acpi/driverfs.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,46 @@
+/*
+ * driverfs.c - ACPI bindings for driverfs.
+ *
+ * Copyright (c) 2002 Patrick Mochel
+ * Copyright (c) 2002 The Open Source Development Lab
+ *
+ */
+
+#include <linux/stat.h>
+#include <linux/init.h>
+#include <linux/driverfs_fs.h>
+
+#include "acpi_bus.h"
+
+static struct driver_dir_entry acpi_dir = {
+	.name		= "acpi",
+	.mode	= (S_IRWXU | S_IRUGO | S_IXUGO),
+};
+ 
+/* driverfs ops for ACPI attribute files go here, when/if
+ * there are ACPI attribute files. 
+ * For now, we just have directory creation and removal.
+ */
+
+void acpi_remove_dir(struct acpi_device * dev)
+{
+	if (dev)
+		driverfs_remove_dir(&dev->driverfs_dir);
+}
+
+int acpi_create_dir(struct acpi_device * dev)
+{
+	struct driver_dir_entry * parent;
+
+	parent = dev->parent ? &dev->parent->driverfs_dir : &acpi_dir;
+	dev->driverfs_dir.name = dev->pnp.bus_id;
+	dev->driverfs_dir.mode  = (S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO);
+	return driverfs_create_dir(&dev->driverfs_dir,parent);
+}
+
+static int __init acpi_driverfs_init(void)
+{
+	return driverfs_create_dir(&acpi_dir,NULL);
+}
+
+subsys_initcall(acpi_driverfs_init);
diff -Nru a/drivers/acpi/ec.c b/drivers/acpi/ec.c
--- a/drivers/acpi/ec.c	Fri Sep 20 08:20:46 2002
+++ b/drivers/acpi/ec.c	Fri Sep 20 08:20:46 2002
@@ -38,7 +38,12 @@
 #define _COMPONENT		ACPI_EC_COMPONENT
 ACPI_MODULE_NAME		("acpi_ec")
 
-#define PREFIX			"ACPI: "
+#define ACPI_EC_COMPONENT		0x00100000
+#define ACPI_EC_CLASS			"embedded_controller"
+#define ACPI_EC_HID			"PNP0C09"
+#define ACPI_EC_DRIVER_NAME		"ACPI Embedded Controller Driver"
+#define ACPI_EC_DEVICE_NAME		"Embedded Controller"
+#define ACPI_EC_FILE_INFO		"info"
 
 
 #define ACPI_EC_FLAG_OBF	0x01	/* Output buffer full */
@@ -784,23 +789,23 @@
 }
 
 
-int __init
-acpi_ec_init (void)
+static int __init acpi_ec_init (void)
 {
 	int			result = 0;
 
 	ACPI_FUNCTION_TRACE("acpi_ec_init");
 
-	result = acpi_bus_register_driver(&acpi_ec_driver);
-	if (result < 0) {
-		remove_proc_entry(ACPI_EC_CLASS, acpi_root_dir);
-		return_VALUE(-ENODEV);
-	}
+	if (acpi_disabled)
+		return_VALUE(0);
 
-	return_VALUE(0);
+	/* Now register the driver for the EC */
+	result = acpi_bus_register_driver(&acpi_ec_driver);
+	return_VALUE(result);
 }
 
-void __exit
+subsys_initcall(acpi_ec_init);
+
+static void __exit
 acpi_ec_ecdt_exit (void)
 {
 	if (!ec_ecdt)
@@ -814,7 +819,7 @@
 	kfree(ec_ecdt);
 }
 
-void __exit
+static void __exit
 acpi_ec_exit (void)
 {
 	int			result = 0;
diff -Nru a/drivers/acpi/event.c b/drivers/acpi/event.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/acpi/event.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,140 @@
+/*
+ * event.c - exporting ACPI events via procfs
+ *
+ *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ *
+ */
+
+#include <linux/spinlock.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include "acpi_drivers.h"
+
+#define _COMPONENT		ACPI_SYSTEM_COMPONENT
+ACPI_MODULE_NAME		("event")
+
+/* Global vars for handling event proc entry */
+static spinlock_t		acpi_system_event_lock = SPIN_LOCK_UNLOCKED;
+int				event_is_open = 0;
+extern struct list_head		acpi_bus_event_list;
+extern wait_queue_head_t	acpi_bus_event_queue;
+
+static int
+acpi_system_open_event(struct inode *inode, struct file *file)
+{
+	spin_lock_irq (&acpi_system_event_lock);
+
+	if(event_is_open)
+		goto out_busy;
+
+	event_is_open = 1;
+
+	spin_unlock_irq (&acpi_system_event_lock);
+	return 0;
+
+out_busy:
+	spin_unlock_irq (&acpi_system_event_lock);
+	return -EBUSY;
+}
+
+static ssize_t
+acpi_system_read_event (
+	struct file		*file,
+	char			*buffer,
+	size_t			count,
+	loff_t			*ppos)
+{
+	int			result = 0;
+	struct acpi_bus_event	event;
+	static char		str[ACPI_MAX_STRING];
+	static int		chars_remaining = 0;
+	static char		*ptr;
+
+
+	ACPI_FUNCTION_TRACE("acpi_system_read_event");
+
+	if (!chars_remaining) {
+		memset(&event, 0, sizeof(struct acpi_bus_event));
+
+		if ((file->f_flags & O_NONBLOCK)
+		    && (list_empty(&acpi_bus_event_list)))
+			return_VALUE(-EAGAIN);
+
+		result = acpi_bus_receive_event(&event);
+		if (result) {
+			return_VALUE(-EIO);
+		}
+
+		chars_remaining = sprintf(str, "%s %s %08x %08x\n", 
+			event.device_class?event.device_class:"<unknown>",
+			event.bus_id?event.bus_id:"<unknown>", 
+			event.type, event.data);
+		ptr = str;
+	}
+
+	if (chars_remaining < count) {
+		count = chars_remaining;
+	}
+
+	if (copy_to_user(buffer, ptr, count))
+		return_VALUE(-EFAULT);
+
+	*ppos += count;
+	chars_remaining -= count;
+	ptr += count;
+
+	return_VALUE(count);
+}
+
+static int
+acpi_system_close_event(struct inode *inode, struct file *file)
+{
+	spin_lock_irq (&acpi_system_event_lock);
+	event_is_open = 0;
+	spin_unlock_irq (&acpi_system_event_lock);
+	return 0;
+}
+
+static unsigned int
+acpi_system_poll_event(
+	struct file		*file,
+	poll_table		*wait)
+{
+	poll_wait(file, &acpi_bus_event_queue, wait);
+	if (!list_empty(&acpi_bus_event_list))
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+static struct file_operations acpi_system_event_ops = {
+	.open =		acpi_system_open_event,
+	.read =		acpi_system_read_event,
+	.release =	acpi_system_close_event,
+	.poll =		acpi_system_poll_event,
+};
+
+static int __init acpi_event_init(void)
+{
+	struct proc_dir_entry	*entry;
+	int error = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_event_init");
+
+	if (acpi_disabled)
+		return_VALUE(0);
+
+	/* 'event' [R] */
+	entry = create_proc_entry("event", S_IRUSR, acpi_root_dir);
+	if (entry)
+		entry->proc_fops = &acpi_system_event_ops;
+	else {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
+				  "Unable to create '%s' proc fs entry\n","event" ));
+		error = -EFAULT;
+	}
+	return_VALUE(error);
+}
+
+subsys_initcall(acpi_event_init);
diff -Nru a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c
--- a/drivers/acpi/executer/exconvrt.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/acpi/executer/exconvrt.c	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: exconvrt - Object conversion routines
- *              $Revision: 37 $
+ *              $Revision: 38 $
  *
  *****************************************************************************/
 
@@ -230,7 +230,33 @@
 
 
 	case ACPI_TYPE_STRING:
-		*result_desc = obj_desc;
+		/*
+		 * Create a new Buffer object
+		 */
+		ret_desc = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER);
+		if (!ret_desc) {
+			return_ACPI_STATUS (AE_NO_MEMORY);
+		}
+
+		/* Need enough space for one integer */
+
+		new_buf = ACPI_MEM_CALLOCATE (obj_desc->string.length);
+		if (!new_buf) {
+			ACPI_REPORT_ERROR
+				(("Ex_convert_to_buffer: Buffer allocation failure\n"));
+			acpi_ut_remove_reference (ret_desc);
+			return_ACPI_STATUS (AE_NO_MEMORY);
+		}
+
+		ACPI_STRNCPY ((char *) new_buf, (char *) obj_desc->string.pointer, obj_desc->string.length);
+		ret_desc->buffer.flags |= AOPOBJ_DATA_VALID;
+		ret_desc->buffer.pointer = new_buf;
+		ret_desc->buffer.length = obj_desc->string.length;
+
+		/* Return the new buffer descriptor */
+
+		*result_desc = ret_desc;
+
 		break;
 
 
diff -Nru a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c
--- a/drivers/acpi/executer/exmisc.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/acpi/executer/exmisc.c	Fri Sep 20 08:20:47 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes
- *              $Revision: 108 $
+ *              $Revision: 109 $
  *
  *****************************************************************************/
 
@@ -28,7 +28,6 @@
 #include "acpi.h"
 #include "acinterp.h"
 #include "amlcode.h"
-#include "acdispat.h"
 
 
 #define _COMPONENT          ACPI_EXECUTER
diff -Nru a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c
--- a/drivers/acpi/executer/exoparg1.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/acpi/executer/exoparg1.c	Fri Sep 20 08:20:47 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exoparg1 - AML execution - opcodes with 1 argument
- *              $Revision: 142 $
+ *              $Revision: 143 $
  *
  *****************************************************************************/
 
@@ -59,7 +59,6 @@
  * fully resolved operands.
 !*/
 
-
 /*******************************************************************************
  *
  * FUNCTION:    Acpi_ex_opcode_1A_0T_0R
@@ -561,73 +560,11 @@
 
 	case AML_TYPE_OP:               /* Object_type (Source_object) */
 
-		if (ACPI_GET_OBJECT_TYPE (operand[0]) == INTERNAL_TYPE_REFERENCE) {
-			/*
-			 * Not a Name -- an indirect name pointer would have
-			 * been converted to a direct name pointer in Resolve_operands
-			 */
-			switch (operand[0]->reference.opcode) {
-			case AML_DEBUG_OP:
-
-				/* The Debug Object is of type "Debug_object" */
-
-				type = ACPI_TYPE_DEBUG_OBJECT;
-				break;
-
-
-			case AML_INDEX_OP:
-
-				/* Get the type of this reference (index into another object) */
-
-				type = operand[0]->reference.target_type;
-				if (type == ACPI_TYPE_PACKAGE) {
-					/*
-					 * The main object is a package, we want to get the type
-					 * of the individual package element that is referenced by
-					 * the index.
-					 */
-					type = ACPI_GET_OBJECT_TYPE (*(operand[0]->reference.where));
-				}
-				break;
-
-
-			case AML_LOCAL_OP:
-			case AML_ARG_OP:
-
-				type = acpi_ds_method_data_get_type (operand[0]->reference.opcode,
-						  operand[0]->reference.offset, walk_state);
-				break;
-
-
-			default:
-
-				ACPI_REPORT_ERROR (("Acpi_ex_opcode_1A_0T_1R/Type_op: Unknown Reference subtype %X\n",
-					operand[0]->reference.opcode));
-				status = AE_AML_INTERNAL;
-				goto cleanup;
-			}
-		}
-		else {
-			/*
-			 * It's not a Reference, so it must be a direct name pointer.
-			 */
-			type = acpi_ns_get_type ((acpi_namespace_node *) operand[0]);
-
-			/* Convert internal types to external types */
-
-			switch (type) {
-			case INTERNAL_TYPE_REGION_FIELD:
-			case INTERNAL_TYPE_BANK_FIELD:
-			case INTERNAL_TYPE_INDEX_FIELD:
-
-				type = ACPI_TYPE_FIELD_UNIT;
-				break;
-
-			default:
-				/* No change to Type required */
-				break;
-			}
+		/* Get the type of the base object */
 
+		status = acpi_ex_resolve_multiple (walk_state, operand[0], &type, NULL);
+		if (ACPI_FAILURE (status)) {
+			goto cleanup;
 		}
 
 		/* Allocate a descriptor to hold the type. */
@@ -644,39 +581,36 @@
 
 	case AML_SIZE_OF_OP:            /* Size_of (Source_object) */
 
-		temp_desc = operand[0];
-		if (ACPI_GET_DESCRIPTOR_TYPE (operand[0]) == ACPI_DESC_TYPE_NAMED) {
-			temp_desc = acpi_ns_get_attached_object ((acpi_namespace_node *) operand[0]);
-		}
+		/* Get the base object */
 
-		if (!temp_desc) {
-			value = 0;
+		status = acpi_ex_resolve_multiple (walk_state, operand[0], &type, &temp_desc);
+		if (ACPI_FAILURE (status)) {
+			goto cleanup;
 		}
-		else {
-			/*
-			 * Type is guaranteed to be a buffer, string, or package at this
-			 * point (even if the original operand was an object reference, it
-			 * will be resolved and typechecked during operand resolution.)
-			 */
-			switch (ACPI_GET_OBJECT_TYPE (temp_desc)) {
-			case ACPI_TYPE_BUFFER:
-				value = temp_desc->buffer.length;
-				break;
-
-			case ACPI_TYPE_STRING:
-				value = temp_desc->string.length;
-				break;
-
-			case ACPI_TYPE_PACKAGE:
-				value = temp_desc->package.count;
-				break;
-
-			default:
-				ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Size_of, Not Buf/Str/Pkg - found type %s\n",
-					acpi_ut_get_object_type_name (temp_desc)));
-				status = AE_AML_OPERAND_TYPE;
-				goto cleanup;
-			}
+
+		/*
+		 * Type is guaranteed to be a buffer, string, or package at this
+		 * point (even if the original operand was an object reference, it
+		 * will be resolved and typechecked during operand resolution.)
+		 */
+		switch (type) {
+		case ACPI_TYPE_BUFFER:
+			value = temp_desc->buffer.length;
+			break;
+
+		case ACPI_TYPE_STRING:
+			value = temp_desc->string.length;
+			break;
+
+		case ACPI_TYPE_PACKAGE:
+			value = temp_desc->package.count;
+			break;
+
+		default:
+			ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Size_of, Not Buf/Str/Pkg - found type %s\n",
+				acpi_ut_get_type_name (type)));
+			status = AE_AML_OPERAND_TYPE;
+			goto cleanup;
 		}
 
 		/*
diff -Nru a/drivers/acpi/executer/exresnte.c b/drivers/acpi/executer/exresnte.c
--- a/drivers/acpi/executer/exresnte.c	Fri Sep 20 08:20:43 2002
+++ b/drivers/acpi/executer/exresnte.c	Fri Sep 20 08:20:43 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exresnte - AML Interpreter object resolution
- *              $Revision: 57 $
+ *              $Revision: 58 $
  *
  *****************************************************************************/
 
@@ -26,7 +26,6 @@
 
 
 #include "acpi.h"
-#include "amlcode.h"
 #include "acdispat.h"
 #include "acinterp.h"
 #include "acnamesp.h"
diff -Nru a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c
--- a/drivers/acpi/executer/exresolv.c	Fri Sep 20 08:20:44 2002
+++ b/drivers/acpi/executer/exresolv.c	Fri Sep 20 08:20:44 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exresolv - AML Interpreter object resolution
- *              $Revision: 115 $
+ *              $Revision: 116 $
  *
  *****************************************************************************/
 
@@ -29,6 +29,7 @@
 #include "amlcode.h"
 #include "acdispat.h"
 #include "acinterp.h"
+#include "acnamesp.h"
 
 
 #define _COMPONENT          ACPI_EXECUTER
@@ -277,6 +278,172 @@
 	}
 
 	return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION:    Acpi_ex_resolve_multiple
+ *
+ * PARAMETERS:  Walk_state          - Current state (contains AML opcode)
+ *              Operand             - Starting point for resolution
+ *              Return_type         - Where the object type is returned
+ *              Return_desc         - Where the resolved object is returned
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Return the base object and type.  Traverse a reference list if
+ *              necessary to get to the base object.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_resolve_multiple (
+	acpi_walk_state         *walk_state,
+	acpi_operand_object     *operand,
+	acpi_object_type        *return_type,
+	acpi_operand_object     **return_desc)
+{
+	acpi_operand_object     *obj_desc = (void *) operand;
+	acpi_namespace_node     *node;
+	acpi_object_type        type;
+
+
+	ACPI_FUNCTION_TRACE ("Ex_get_object_type");
+
+
+	/*
+	 * For reference objects created via the Ref_of or Index operators,
+	 * we need to get to the base object (as per the ACPI specification
+	 * of the Object_type and Size_of operators). This means traversing
+	 * the list of possibly many nested references.
+	 */
+	while (ACPI_GET_OBJECT_TYPE (obj_desc) == INTERNAL_TYPE_REFERENCE) {
+		switch (obj_desc->reference.opcode) {
+		case AML_REF_OF_OP:
+
+			/* Dereference the reference pointer */
+
+			node = obj_desc->reference.object;
+
+			/* All "References" point to a NS node */
+
+			if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) {
+				return_ACPI_STATUS (AE_AML_INTERNAL);
+			}
+
+			/* Get the attached object */
+
+			obj_desc = acpi_ns_get_attached_object (node);
+			if (!obj_desc) {
+				/* No object, use the NS node type */
+
+				type = acpi_ns_get_type (node);
+				goto exit;
+			}
+
+			/* Check for circular references */
+
+			if (obj_desc == operand) {
+				return_ACPI_STATUS (AE_AML_CIRCULAR_REFERENCE);
+			}
+			break;
+
+
+		case AML_INDEX_OP:
+
+			/* Get the type of this reference (index into another object) */
+
+			type = obj_desc->reference.target_type;
+			if (type != ACPI_TYPE_PACKAGE) {
+				goto exit;
+			}
+
+			/*
+			 * The main object is a package, we want to get the type
+			 * of the individual package element that is referenced by
+			 * the index.
+			 *
+			 * This could of course in turn be another reference object.
+			 */
+			obj_desc = *(obj_desc->reference.where);
+			break;
+
+
+		case AML_INT_NAMEPATH_OP:
+
+			/* Dereference the reference pointer */
+
+			node = obj_desc->reference.node;
+
+			/* All "References" point to a NS node */
+
+			if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) {
+				return_ACPI_STATUS (AE_AML_INTERNAL);
+			}
+
+			/* Get the attached object */
+
+			obj_desc = acpi_ns_get_attached_object (node);
+			if (!obj_desc) {
+				/* No object, use the NS node type */
+
+				type = acpi_ns_get_type (node);
+				goto exit;
+			}
+
+			/* Check for circular references */
+
+			if (obj_desc == operand) {
+				return_ACPI_STATUS (AE_AML_CIRCULAR_REFERENCE);
+			}
+			break;
+
+
+		case AML_DEBUG_OP:
+
+			/* The Debug Object is of type "Debug_object" */
+
+			type = ACPI_TYPE_DEBUG_OBJECT;
+			goto exit;
+
+
+		default:
+
+			ACPI_REPORT_ERROR (("Acpi_ex_resolve_multiple: Unknown Reference subtype %X\n",
+				obj_desc->reference.opcode));
+			return_ACPI_STATUS (AE_AML_INTERNAL);
+		}
+	}
+
+	/*
+	 * Now we are guaranteed to have an object that has not been created
+	 * via the Ref_of or Index operators.
+	 */
+	type = ACPI_GET_OBJECT_TYPE (obj_desc);
+
+
+exit:
+	/* Convert internal types to external types */
+
+	switch (type) {
+	case INTERNAL_TYPE_REGION_FIELD:
+	case INTERNAL_TYPE_BANK_FIELD:
+	case INTERNAL_TYPE_INDEX_FIELD:
+
+		type = ACPI_TYPE_FIELD_UNIT;
+		break;
+
+	default:
+		/* No change to Type required */
+		break;
+	}
+
+	*return_type = type;
+	if (return_desc) {
+		*return_desc = obj_desc;
+	}
+	return_ACPI_STATUS (AE_OK);
 }
 
 
diff -Nru a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c
--- a/drivers/acpi/executer/exresop.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/acpi/executer/exresop.c	Fri Sep 20 08:20:47 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exresop - AML Interpreter operand/object resolution
- *              $Revision: 55 $
+ *              $Revision: 57 $
  *
  *****************************************************************************/
 
@@ -29,7 +29,6 @@
 #include "amlcode.h"
 #include "acparser.h"
 #include "acinterp.h"
-#include "acnamesp.h"
 
 
 #define _COMPONENT          ACPI_EXECUTER
@@ -463,11 +462,12 @@
 		case ARGI_DATAOBJECT:
 			/*
 			 * ARGI_DATAOBJECT is only used by the Size_of operator.
-			 * Need a buffer, string, package, or Node reference.
+			 * Need a buffer, string, package, or Ref_of reference.
 			 *
 			 * The only reference allowed here is a direct reference to
 			 * a namespace node.
 			 */
+#if 0
 			if (ACPI_GET_OBJECT_TYPE (*stack_ptr) == INTERNAL_TYPE_REFERENCE) {
 				if (!(*stack_ptr)->reference.node) {
 					ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
@@ -497,13 +497,14 @@
 				acpi_ut_remove_reference (*stack_ptr);
 				(*stack_ptr) = temp_node;
 			}
-
+#endif
 			/* Need a buffer, string, package */
 
 			switch (ACPI_GET_OBJECT_TYPE (*stack_ptr)) {
 			case ACPI_TYPE_PACKAGE:
 			case ACPI_TYPE_STRING:
 			case ACPI_TYPE_BUFFER:
+			case INTERNAL_TYPE_REFERENCE:
 
 				/* Valid operand */
 				break;
diff -Nru a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c
--- a/drivers/acpi/executer/exstore.c	Fri Sep 20 08:20:45 2002
+++ b/drivers/acpi/executer/exstore.c	Fri Sep 20 08:20:45 2002
@@ -2,7 +2,7 @@
 /******************************************************************************
  *
  * Module Name: exstore - AML Interpreter object store support
- *              $Revision: 169 $
+ *              $Revision: 171 $
  *
  *****************************************************************************/
 
@@ -103,7 +103,7 @@
 			return_ACPI_STATUS (AE_OK);
 		}
 
-		/*lint: -fallthrough */
+		/*lint -fallthrough */
 
 	default:
 
@@ -286,6 +286,12 @@
 		if (new_desc != obj_desc) {
 			acpi_ut_remove_reference (obj_desc);
 			*(index_desc->reference.where) = new_desc;
+
+			/* If same as the original source, add a reference */
+
+			if (new_desc == source_desc) {
+				acpi_ut_add_reference (new_desc);
+			}
 		}
 		break;
 
diff -Nru a/drivers/acpi/executer/exstoren.c b/drivers/acpi/executer/exstoren.c
--- a/drivers/acpi/executer/exstoren.c	Fri Sep 20 08:20:42 2002
+++ b/drivers/acpi/executer/exstoren.c	Fri Sep 20 08:20:42 2002
@@ -3,7 +3,7 @@
  *
  * Module Name: exstoren - AML Interpreter object store support,
  *                        Store to Node (namespace object)
- *              $Revision: 50 $
+ *              $Revision: 51 $
  *
  *****************************************************************************/
 
@@ -209,6 +209,15 @@
 				  &actual_src_desc, walk_state);
 		if (ACPI_FAILURE (status)) {
 			return_ACPI_STATUS (status);
+		}
+
+		if (source_desc == actual_src_desc) {
+			/*
+			 * No conversion was performed.  Return the Source_desc as the
+			 * new object.
+			 */
+			*new_desc = source_desc;
+			return_ACPI_STATUS (AE_OK);
 		}
 	}
 
diff -Nru a/drivers/acpi/fan.c b/drivers/acpi/fan.c
--- a/drivers/acpi/fan.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/acpi/fan.c	Fri Sep 20 08:20:41 2002
@@ -40,8 +40,13 @@
 MODULE_DESCRIPTION(ACPI_FAN_DRIVER_NAME);
 MODULE_LICENSE("GPL");
 
-#define PREFIX			"ACPI: "
-
+#define ACPI_FAN_COMPONENT		0x00200000
+#define ACPI_FAN_CLASS			"fan"
+#define ACPI_FAN_HID			"PNP0C0B"
+#define ACPI_FAN_DRIVER_NAME		"ACPI Fan Driver"
+#define ACPI_FAN_DEVICE_NAME		"Fan"
+#define ACPI_FAN_FILE_STATE		"state"
+#define ACPI_FAN_NOTIFY_STATUS		0x80
 
 int acpi_fan_add (struct acpi_device *device);
 int acpi_fan_remove (struct acpi_device *device, int type);
diff -Nru a/drivers/acpi/include/acconfig.h b/drivers/acpi/include/acconfig.h
--- a/drivers/acpi/include/acconfig.h	Fri Sep 20 08:20:43 2002
+++ b/drivers/acpi/include/acconfig.h	Fri Sep 20 08:20:43 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acconfig.h - Global configuration constants
- *       $Revision: 110 $
+ *       $Revision: 111 $
  *
  *****************************************************************************/
 
@@ -54,7 +54,7 @@
 
 /* Version string */
 
-#define ACPI_CA_VERSION                 0x20020829
+#define ACPI_CA_VERSION                 0x20020918
 
 /* Version of ACPI supported */
 
diff -Nru a/drivers/acpi/include/acdebug.h b/drivers/acpi/include/acdebug.h
--- a/drivers/acpi/include/acdebug.h	Fri Sep 20 08:20:43 2002
+++ b/drivers/acpi/include/acdebug.h	Fri Sep 20 08:20:43 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acdebug.h - ACPI/AML debugger
- *       $Revision: 63 $
+ *       $Revision: 64 $
  *
  *****************************************************************************/
 
@@ -196,6 +196,10 @@
 acpi_db_decode_and_display_object (
 	NATIVE_CHAR             *target,
 	NATIVE_CHAR             *output_type);
+
+void
+acpi_db_decode_node (
+	acpi_namespace_node     *node);
 
 void
 acpi_db_display_result_object (
diff -Nru a/drivers/acpi/include/acexcep.h b/drivers/acpi/include/acexcep.h
--- a/drivers/acpi/include/acexcep.h	Fri Sep 20 08:20:41 2002
+++ b/drivers/acpi/include/acexcep.h	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acexcep.h - Exception codes returned by the ACPI subsystem
- *       $Revision: 63 $
+ *       $Revision: 64 $
  *
  *****************************************************************************/
 
@@ -142,8 +142,9 @@
 #define AE_AML_ALIGNMENT                (acpi_status) (0x001D | AE_CODE_AML)
 #define AE_AML_NO_RESOURCE_END_TAG      (acpi_status) (0x001E | AE_CODE_AML)
 #define AE_AML_BAD_RESOURCE_VALUE       (acpi_status) (0x001F | AE_CODE_AML)
+#define AE_AML_CIRCULAR_REFERENCE       (acpi_status) (0x0020 | AE_CODE_AML)
 
-#define AE_CODE_AML_MAX                 0x001F
+#define AE_CODE_AML_MAX                 0x0020
 
 /*
  * Internal exceptions used for control
@@ -158,8 +159,9 @@
 #define AE_CTRL_TRANSFER                (acpi_status) (0x0008 | AE_CODE_CONTROL)
 #define AE_CTRL_BREAK                   (acpi_status) (0x0009 | AE_CODE_CONTROL)
 #define AE_CTRL_CONTINUE                (acpi_status) (0x000A | AE_CODE_CONTROL)
+#define AE_CTRL_SKIP                    (acpi_status) (0x000B | AE_CODE_CONTROL)
 
-#define AE_CODE_CTRL_MAX                0x000A
+#define AE_CODE_CTRL_MAX                0x000B
 
 
 #ifdef DEFINE_ACPI_GLOBALS
@@ -255,7 +257,8 @@
 	"AE_AML_NO_WHILE",
 	"AE_AML_ALIGNMENT",
 	"AE_AML_NO_RESOURCE_END_TAG",
-	"AE_AML_BAD_RESOURCE_VALUE"
+	"AE_AML_BAD_RESOURCE_VALUE",
+	"AE_AML_CIRCULAR_REFERENCE"
 };
 
 NATIVE_CHAR const   *acpi_gbl_exception_names_ctrl[] =
@@ -269,7 +272,8 @@
 	"AE_CTRL_END",
 	"AE_CTRL_TRANSFER",
 	"AE_CTRL_BREAK",
-	"AE_CTRL_CONTINUE"
+	"AE_CTRL_CONTINUE",
+	"AE_CTRL_SKIP"
 };
 
 #endif /* ACPI GLOBALS */
diff -Nru a/drivers/acpi/include/acinterp.h b/drivers/acpi/include/acinterp.h
--- a/drivers/acpi/include/acinterp.h	Fri Sep 20 08:20:47 2002
+++ b/drivers/acpi/include/acinterp.h	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acinterp.h - Interpreter subcomponent prototypes and defines
- *       $Revision: 138 $
+ *       $Revision: 139 $
  *
  *****************************************************************************/
 
@@ -193,6 +193,13 @@
 	acpi_operand_object     *obj_desc,
 	acpi_operand_object     **return_desc,
 	acpi_walk_state         *walk_state);
+
+acpi_status
+acpi_ex_resolve_multiple (
+	acpi_walk_state         *walk_state,
+	acpi_operand_object     *operand,
+	acpi_object_type        *return_type,
+	acpi_operand_object     **return_desc);
 
 acpi_status
 acpi_ex_concat_template (
diff -Nru a/drivers/acpi/include/acpiosxf.h b/drivers/acpi/include/acpiosxf.h
--- a/drivers/acpi/include/acpiosxf.h	Fri Sep 20 08:20:41 2002
+++ b/drivers/acpi/include/acpiosxf.h	Fri Sep 20 08:20:41 2002
@@ -261,6 +261,10 @@
 	void                    *pointer,
 	u32                     length);
 
+u32
+acpi_os_get_timer (
+	void);
+
 acpi_status
 acpi_os_signal (
 	u32                     function,
@@ -280,6 +284,10 @@
 	const NATIVE_CHAR       *format,
 	va_list                 args);
 
+void
+acpi_os_redirect_output (
+	void                    *destination);
+
 
 /*
  * Debug input
@@ -288,6 +296,18 @@
 u32
 acpi_os_get_line (
 	NATIVE_CHAR             *buffer);
+
+
+/*
+ * Debug
+ */
+
+void
+acpi_os_dbg_assert(
+	void                    *failed_assertion,
+	void                    *file_name,
+	u32                     line_number,
+	NATIVE_CHAR             *message);
 
 
 #endif /* __ACPIOSXF_H__ */
diff -Nru a/drivers/acpi/include/actypes.h b/drivers/acpi/include/actypes.h
--- a/drivers/acpi/include/actypes.h	Fri Sep 20 08:20:47 2002
+++ b/drivers/acpi/include/actypes.h	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: actypes.h - Common data types for the entire ACPI subsystem
- *       $Revision: 238 $
+ *       $Revision: 239 $
  *
  *****************************************************************************/
 
diff -Nru a/drivers/acpi/include/acutils.h b/drivers/acpi/include/acutils.h
--- a/drivers/acpi/include/acutils.h	Fri Sep 20 08:20:41 2002
+++ b/drivers/acpi/include/acutils.h	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Name: acutils.h -- prototypes for the common (subsystem-wide) procedures
- *       $Revision: 143 $
+ *       $Revision: 144 $
  *
  *****************************************************************************/
 
@@ -138,7 +138,7 @@
 
 #ifndef ACPI_USE_SYSTEM_CLIBRARY
 
-u32
+ACPI_SIZE
 acpi_ut_strlen (
 	const NATIVE_CHAR       *string);
 
@@ -151,15 +151,15 @@
 acpi_ut_strncpy (
 	NATIVE_CHAR             *dst_string,
 	const NATIVE_CHAR       *src_string,
-	NATIVE_UINT             count);
+	ACPI_SIZE               count);
 
 int
 acpi_ut_strncmp (
 	const NATIVE_CHAR       *string1,
 	const NATIVE_CHAR       *string2,
-	NATIVE_UINT             count);
+	ACPI_SIZE               count);
 
-u32
+int
 acpi_ut_strcmp (
 	const NATIVE_CHAR       *string1,
 	const NATIVE_CHAR       *string2);
@@ -173,7 +173,7 @@
 acpi_ut_strncat (
 	NATIVE_CHAR             *dst_string,
 	const NATIVE_CHAR       *src_string,
-	NATIVE_UINT             count);
+	ACPI_SIZE               count);
 
 u32
 acpi_ut_strtoul (
@@ -190,13 +190,13 @@
 acpi_ut_memcpy (
 	void                    *dest,
 	const void              *src,
-	NATIVE_UINT             count);
+	ACPI_SIZE               count);
 
 void *
 acpi_ut_memset (
 	void                    *dest,
 	NATIVE_UINT             value,
-	NATIVE_UINT             count);
+	ACPI_SIZE               count);
 
 int
 acpi_ut_to_upper (
diff -Nru a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c
--- a/drivers/acpi/namespace/nsdump.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/acpi/namespace/nsdump.c	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: nsdump - table dumping routines for debug
- *              $Revision: 139 $
+ *              $Revision: 140 $
  *
  *****************************************************************************/
 
@@ -116,7 +116,7 @@
 
 	status = acpi_ns_handle_to_pathname (handle, &buffer);
 	if (ACPI_SUCCESS (status)) {
-		acpi_os_printf ("%s %s (Node %p)\n", msg, buffer.pointer, handle);
+		acpi_os_printf ("%s %s (Node %p)\n", msg, (char *) buffer.pointer, handle);
 		ACPI_MEM_FREE (buffer.pointer);
 	}
 
@@ -254,10 +254,10 @@
 		switch (type) {
 		case ACPI_TYPE_PROCESSOR:
 
-			acpi_os_printf (" ID %hd Addr %.4X Len %.4X\n",
+			acpi_os_printf (" ID %X Len %.4X Addr %p\n",
 					 obj_desc->processor.proc_id,
-					 obj_desc->processor.address,
-					 obj_desc->processor.length);
+					 obj_desc->processor.length,
+					 (char *) obj_desc->processor.address);
 			break;
 
 
@@ -269,8 +269,8 @@
 
 		case ACPI_TYPE_METHOD:
 
-			acpi_os_printf (" Args %hd Len %.4X Aml %p \n",
-					 obj_desc->method.param_count,
+			acpi_os_printf (" Args %X Len %.4X Aml %p\n",
+					 (u32) obj_desc->method.param_count,
 					 obj_desc->method.aml_length,
 					 obj_desc->method.aml_start);
 			break;
diff -Nru a/drivers/acpi/namespace/nsdumpdv.c b/drivers/acpi/namespace/nsdumpdv.c
--- a/drivers/acpi/namespace/nsdumpdv.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/acpi/namespace/nsdumpdv.c	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: nsdump - table dumping routines for debug
- *              $Revision: 3 $
+ *              $Revision: 4 $
  *
  *****************************************************************************/
 
@@ -26,7 +26,6 @@
 
 #include "acpi.h"
 #include "acnamesp.h"
-#include "acparser.h"
 
 
 #define _COMPONENT          ACPI_NAMESPACE
diff -Nru a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c
--- a/drivers/acpi/namespace/nsload.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/acpi/namespace/nsload.c	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: nsload - namespace loading/expanding/contracting procedures
- *              $Revision: 58 $
+ *              $Revision: 59 $
  *
  *****************************************************************************/
 
@@ -26,7 +26,6 @@
 
 #include "acpi.h"
 #include "acnamesp.h"
-#include "amlcode.h"
 #include "acparser.h"
 #include "acdispat.h"
 
diff -Nru a/drivers/acpi/numa.c b/drivers/acpi/numa.c
--- a/drivers/acpi/numa.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/acpi/numa.c	Fri Sep 20 08:20:47 2002
@@ -30,8 +30,6 @@
 #include <linux/errno.h>
 #include <linux/acpi.h>
 
-#define PREFIX			"ACPI: "
-
 extern int __init acpi_table_parse_madt_family (enum acpi_table_id id, unsigned long madt_size, int entry_id, acpi_madt_entry_handler handler);
 
 void __init
diff -Nru a/drivers/acpi/parser/psxface.c b/drivers/acpi/parser/psxface.c
--- a/drivers/acpi/parser/psxface.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/acpi/parser/psxface.c	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: psxface - Parser external interfaces
- *              $Revision: 65 $
+ *              $Revision: 66 $
  *
  *****************************************************************************/
 
@@ -28,7 +28,6 @@
 #include "acparser.h"
 #include "acdispat.h"
 #include "acinterp.h"
-#include "amlcode.h"
 #include "acnamesp.h"
 
 
diff -Nru a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c
--- a/drivers/acpi/pci_bind.c	Fri Sep 20 08:20:43 2002
+++ b/drivers/acpi/pci_bind.c	Fri Sep 20 08:20:43 2002
@@ -39,9 +39,6 @@
 #define _COMPONENT		ACPI_PCI_COMPONENT
 ACPI_MODULE_NAME		("pci_bind")
 
-#define PREFIX			"ACPI: "
-
-
 struct acpi_pci_data {
 	acpi_pci_id		id;
 	struct pci_bus		*bus;
diff -Nru a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
--- a/drivers/acpi/pci_irq.c	Fri Sep 20 08:20:46 2002
+++ b/drivers/acpi/pci_irq.c	Fri Sep 20 08:20:46 2002
@@ -41,8 +41,6 @@
 #define _COMPONENT		ACPI_PCI_COMPONENT
 ACPI_MODULE_NAME		("pci_irq")
 
-#define PREFIX			"PCI: "
-
 struct acpi_prt_list		acpi_prt;
 
 #ifdef CONFIG_X86
diff -Nru a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
--- a/drivers/acpi/pci_link.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/acpi/pci_link.c	Fri Sep 20 08:20:41 2002
@@ -45,8 +45,12 @@
 #define _COMPONENT		ACPI_PCI_COMPONENT
 ACPI_MODULE_NAME		("pci_link")
 
-#define PREFIX			"ACPI: "
-
+#define ACPI_PCI_LINK_CLASS		"pci_irq_routing"
+#define ACPI_PCI_LINK_HID		"PNP0C0F"
+#define ACPI_PCI_LINK_DRIVER_NAME	"ACPI PCI Interrupt Link Driver"
+#define ACPI_PCI_LINK_DEVICE_NAME	"PCI Interrupt Link"
+#define ACPI_PCI_LINK_FILE_INFO		"info"
+#define ACPI_PCI_LINK_FILE_STATUS	"state"
 
 #define ACPI_PCI_LINK_MAX_POSSIBLE 16
 
@@ -570,11 +574,13 @@
 }
 
 
-int __init
-acpi_pci_link_init (void)
+static int __init acpi_pci_link_init (void)
 {
 	ACPI_FUNCTION_TRACE("acpi_pci_link_init");
 
+	if (acpi_disabled)
+		return_VALUE(0);
+
 	acpi_link.count = 0;
 	INIT_LIST_HEAD(&acpi_link.entries);
 
@@ -583,3 +589,5 @@
 
 	return_VALUE(0);
 }
+
+subsys_initcall(acpi_pci_link_init);
diff -Nru a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
--- a/drivers/acpi/pci_root.c	Fri Sep 20 08:20:44 2002
+++ b/drivers/acpi/pci_root.c	Fri Sep 20 08:20:44 2002
@@ -39,9 +39,12 @@
 #define _COMPONENT		ACPI_PCI_COMPONENT
 ACPI_MODULE_NAME		("pci_root")
 
-extern struct pci_ops *pci_root_ops;
+#define ACPI_PCI_ROOT_CLASS		"pci_bridge"
+#define ACPI_PCI_ROOT_HID		"PNP0A03"
+#define ACPI_PCI_ROOT_DRIVER_NAME	"ACPI PCI Root Bridge Driver"
+#define ACPI_PCI_ROOT_DEVICE_NAME	"PCI Root Bridge"
 
-#define PREFIX			"ACPI: "
+extern struct pci_ops *pci_root_ops;
 
 static int acpi_pci_root_add (struct acpi_device *device);
 static int acpi_pci_root_remove (struct acpi_device *device, int type);
@@ -318,11 +321,13 @@
 }
 
 
-int __init
-acpi_pci_root_init (void)
+static int __init acpi_pci_root_init (void)
 {
 	ACPI_FUNCTION_TRACE("acpi_pci_root_init");
 
+	if (acpi_disabled)
+		return_VALUE(0);
+
 	/* DEBUG:
 	acpi_dbg_layer = ACPI_PCI_COMPONENT;
 	acpi_dbg_level = 0xFFFFFFFF;
@@ -336,13 +341,5 @@
 	return_VALUE(0);
 }
 
+subsys_initcall(acpi_pci_root_init);
 
-void __exit
-acpi_pci_root_exit (void)
-{
-	ACPI_FUNCTION_TRACE("acpi_pci_root_exit");
-
-	acpi_bus_unregister_driver(&acpi_pci_root_driver);
-
-	return_VOID;
-}
diff -Nru a/drivers/acpi/power.c b/drivers/acpi/power.c
--- a/drivers/acpi/power.c	Fri Sep 20 08:20:46 2002
+++ b/drivers/acpi/power.c	Fri Sep 20 08:20:46 2002
@@ -36,8 +36,15 @@
 #define _COMPONENT		ACPI_POWER_COMPONENT
 ACPI_MODULE_NAME		("acpi_power")
 
-#define PREFIX			"ACPI: "
-
+#define ACPI_POWER_COMPONENT		0x00800000
+#define ACPI_POWER_CLASS		"power_resource"
+#define ACPI_POWER_DRIVER_NAME		"ACPI Power Resource Driver"
+#define ACPI_POWER_DEVICE_NAME		"Power Resource"
+#define ACPI_POWER_FILE_INFO		"info"
+#define ACPI_POWER_FILE_STATUS		"state"
+#define ACPI_POWER_RESOURCE_STATE_OFF	0x00
+#define ACPI_POWER_RESOURCE_STATE_ON	0x01
+#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
 
 int acpi_power_add (struct acpi_device *device);
 int acpi_power_remove (struct acpi_device *device, int type);
@@ -573,13 +580,15 @@
 }
 
 
-int __init
-acpi_power_init (void)
+static int __init acpi_power_init (void)
 {
 	int			result = 0;
 
 	ACPI_FUNCTION_TRACE("acpi_power_init");
 
+	if (acpi_disabled)
+		return_VALUE(0);
+
 	INIT_LIST_HEAD(&acpi_power_resource_list);
 
 	result = acpi_bus_register_driver(&acpi_power_driver);
@@ -591,19 +600,5 @@
 	return_VALUE(0);
 }
 
+subsys_initcall(acpi_power_init);
 
-void __exit
-acpi_power_exit (void)
-{
-	int			result = 0;
-
-	ACPI_FUNCTION_TRACE("acpi_power_exit");
-
-	/* TBD: Empty acpi_power_resource_list */
-
-	result = acpi_bus_unregister_driver(&acpi_power_driver);
-	if (!result)
-		remove_proc_entry(ACPI_POWER_CLASS, acpi_root_dir);
-
-	return_VOID;
-}
diff -Nru a/drivers/acpi/processor.c b/drivers/acpi/processor.c
--- a/drivers/acpi/processor.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/acpi/processor.c	Fri Sep 20 08:20:47 2002
@@ -51,7 +51,17 @@
 MODULE_DESCRIPTION(ACPI_PROCESSOR_DRIVER_NAME);
 MODULE_LICENSE("GPL");
 
-#define PREFIX				"ACPI: "
+#define ACPI_PROCESSOR_COMPONENT	0x01000000
+#define ACPI_PROCESSOR_CLASS		"processor"
+#define ACPI_PROCESSOR_DRIVER_NAME	"ACPI Processor Driver"
+#define ACPI_PROCESSOR_DEVICE_NAME	"Processor"
+#define ACPI_PROCESSOR_FILE_INFO	"info"
+#define ACPI_PROCESSOR_FILE_POWER	"power"
+#define ACPI_PROCESSOR_FILE_PERFORMANCE	"performance"
+#define ACPI_PROCESSOR_FILE_THROTTLING	"throttling"
+#define ACPI_PROCESSOR_FILE_LIMIT	"limit"
+#define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80
+#define ACPI_PROCESSOR_NOTIFY_POWER	0x81
 
 #define US_TO_PM_TIMER_TICKS(t)		((t * (PM_TIMER_FREQUENCY/1000)) / 1000)
 #define C2_OVERHEAD			4	/* 1us (3.579 ticks per us) */
diff -Nru a/drivers/acpi/resources/rsdump.c b/drivers/acpi/resources/rsdump.c
--- a/drivers/acpi/resources/rsdump.c	Fri Sep 20 08:20:46 2002
+++ b/drivers/acpi/resources/rsdump.c	Fri Sep 20 08:20:46 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: rsdump - Functions to display the resource structures.
- *              $Revision: 33 $
+ *              $Revision: 34 $
  *
  ******************************************************************************/
 
@@ -865,20 +865,25 @@
 			 ACPI_ADDRESS_FIXED == address64_data->max_address_fixed ?
 			 "" : "not ");
 
-	acpi_os_printf ("  Granularity: %16X\n",
-			 address64_data->granularity);
-
-	acpi_os_printf ("  Address range min: %16X\n",
-			 address64_data->min_address_range);
-
-	acpi_os_printf ("  Address range max: %16X\n",
-			 address64_data->max_address_range);
-
-	acpi_os_printf ("  Address translation offset: %16X\n",
-			 address64_data->address_translation_offset);
-
-	acpi_os_printf ("  Address Length: %16X\n",
-			 address64_data->address_length);
+	acpi_os_printf ("  Granularity: %8.8X%8.8X\n",
+			 ACPI_HIDWORD (address64_data->granularity),
+			 ACPI_LODWORD (address64_data->granularity));
+
+	acpi_os_printf ("  Address range min: %8.8X%8.8X\n",
+			 ACPI_HIDWORD (address64_data->min_address_range),
+			 ACPI_HIDWORD (address64_data->min_address_range));
+
+	acpi_os_printf ("  Address range max: %8.8X%8.8X\n",
+			 ACPI_HIDWORD (address64_data->max_address_range),
+			 ACPI_HIDWORD (address64_data->max_address_range));
+
+	acpi_os_printf ("  Address translation offset: %8.8X%8.8X\n",
+			 ACPI_HIDWORD (address64_data->address_translation_offset),
+			 ACPI_HIDWORD (address64_data->address_translation_offset));
+
+	acpi_os_printf ("  Address Length: %8.8X%8.8X\n",
+			 ACPI_HIDWORD (address64_data->address_length),
+			 ACPI_HIDWORD (address64_data->address_length));
 
 	if(0xFF != address64_data->resource_source.index) {
 		acpi_os_printf ("  Resource Source Index: %X\n",
diff -Nru a/drivers/acpi/scan.c b/drivers/acpi/scan.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/acpi/scan.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,944 @@
+/*
+ * scan.c - support for transforming the ACPI namespace into individual objects
+ */
+
+#include <linux/init.h>
+#include <linux/acpi.h>
+
+#include "acpi_drivers.h"
+#include "include/acinterp.h"	/* for acpi_ex_eisa_id_to_string() */
+
+
+#define _COMPONENT		ACPI_BUS_COMPONENT
+ACPI_MODULE_NAME		("scan")
+
+#define STRUCT_TO_INT(s)	(*((int*)&s))
+
+extern struct acpi_device		*acpi_root;
+
+
+#define ACPI_BUS_CLASS			"system_bus"
+#define ACPI_BUS_HID			"ACPI_BUS"
+#define ACPI_BUS_DRIVER_NAME		"ACPI Bus Driver"
+#define ACPI_BUS_DEVICE_NAME		"System Bus"
+
+static LIST_HEAD(acpi_device_list);
+static spinlock_t acpi_device_lock = SPIN_LOCK_UNLOCKED;
+
+static int
+acpi_device_register (
+	struct acpi_device	*device,
+	struct acpi_device	*parent)
+{
+	return acpi_create_dir(device);
+}
+
+
+static int
+acpi_device_unregister (
+	struct acpi_device	*device)
+{
+	acpi_remove_dir(device);
+	return 0;
+}
+
+void
+acpi_bus_data_handler (
+	acpi_handle		handle,
+	u32			function,
+	void			*context)
+{
+	ACPI_FUNCTION_TRACE("acpi_bus_data_handler");
+
+	/* TBD */
+
+	return_VOID;
+}
+
+static int
+acpi_bus_get_power_flags (
+	struct acpi_device	*device)
+{
+	acpi_status             status = 0;
+	acpi_handle		handle = 0;
+	u32                     i = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_bus_get_power_flags");
+
+	/*
+	 * Power Management Flags
+	 */
+	status = acpi_get_handle(device->handle, "_PSC", &handle);
+	if (ACPI_SUCCESS(status))
+		device->power.flags.explicit_get = 1;
+	status = acpi_get_handle(device->handle, "_IRC", &handle);
+	if (ACPI_SUCCESS(status))
+		device->power.flags.inrush_current = 1;
+	status = acpi_get_handle(device->handle, "_PRW", &handle);
+	if (ACPI_SUCCESS(status))
+		device->power.flags.wake_capable = 1;
+
+	/*
+	 * Enumerate supported power management states
+	 */
+	for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) {
+		struct acpi_device_power_state *ps = &device->power.states[i];
+		char		object_name[5] = {'_','P','R','0'+i,'\0'};
+
+		/* Evaluate "_PRx" to se if power resources are referenced */
+		acpi_evaluate_reference(device->handle, object_name, NULL,
+			&ps->resources);
+		if (ps->resources.count) {
+			device->power.flags.power_resources = 1;
+			ps->flags.valid = 1;
+		}
+
+		/* Evaluate "_PSx" to see if we can do explicit sets */
+		object_name[2] = 'S';
+		status = acpi_get_handle(device->handle, object_name, &handle);
+		if (ACPI_SUCCESS(status)) {
+			ps->flags.explicit_set = 1;
+			ps->flags.valid = 1;
+		}
+
+		/* State is valid if we have some power control */
+		if (ps->resources.count || ps->flags.explicit_set)
+			ps->flags.valid = 1;
+
+		ps->power = -1;		/* Unknown - driver assigned */
+		ps->latency = -1;	/* Unknown - driver assigned */
+	}
+
+	/* Set defaults for D0 and D3 states (always valid) */
+	device->power.states[ACPI_STATE_D0].flags.valid = 1;
+	device->power.states[ACPI_STATE_D0].power = 100;
+	device->power.states[ACPI_STATE_D3].flags.valid = 1;
+	device->power.states[ACPI_STATE_D3].power = 0;
+
+	/* TBD: System wake support and resource requirements. */
+
+	device->power.state = ACPI_STATE_UNKNOWN;
+
+	return 0;
+}
+
+
+/* --------------------------------------------------------------------------
+                              Performance Management
+   -------------------------------------------------------------------------- */
+
+static int
+acpi_bus_get_perf_flags (
+	struct acpi_device	*device)
+{
+	device->performance.state = ACPI_STATE_UNKNOWN;
+	return 0;
+}
+
+/* --------------------------------------------------------------------------
+                                 Driver Management
+   -------------------------------------------------------------------------- */
+
+static LIST_HEAD(acpi_bus_drivers);
+static DECLARE_MUTEX(acpi_bus_drivers_lock);
+
+
+/**
+ * acpi_bus_match 
+ * --------------
+ * Checks the device's hardware (_HID) or compatible (_CID) ids to see if it
+ * matches the specified driver's criteria.
+ */
+static int
+acpi_bus_match (
+	struct acpi_device	*device,
+	struct acpi_driver	*driver)
+{
+	int error = 0;
+	acpi_buffer	buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+
+	if (device->flags.hardware_id)
+		if (strstr(driver->ids, device->pnp.hardware_id))
+			goto Done;
+
+	if (device->flags.compatible_ids) {
+		acpi_status	status = AE_OK;
+		acpi_object	*object = NULL;
+		char		cid[256] = {};
+
+		status = acpi_evaluate_object(device->handle, "_CID", NULL, 
+			&buffer);
+		if (ACPI_FAILURE(status) || !buffer.pointer)
+			return -ENOENT;
+
+		object = (acpi_object *) buffer.pointer;
+
+		switch (object->type) {
+		case ACPI_TYPE_INTEGER:
+			acpi_ex_eisa_id_to_string((u32) object->integer.value, 
+				cid);
+			break;
+		case ACPI_TYPE_STRING:
+			strncpy(cid, object->string.pointer, sizeof(cid) - 1);
+			break;
+		case ACPI_TYPE_PACKAGE:
+			/* TBD: Support CID packages */
+			break;
+		}
+
+		if (strlen(cid) && strstr(driver->ids,cid))
+			goto Done;
+	}
+	error = -ENOENT;
+
+ Done:
+	if (buffer.pointer)
+		acpi_os_free(buffer.pointer);
+	return error;
+}
+
+
+/**
+ * acpi_bus_driver_init 
+ * --------------------
+ * Used to initialize a device via its device driver.  Called whenever a 
+ * driver is bound to a device.  Invokes the driver's add() and start() ops.
+ */
+static int
+acpi_bus_driver_init (
+	struct acpi_device	*device, 
+	struct acpi_driver	*driver)
+{
+	int			result = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_bus_driver_init");
+
+	if (!device || !driver)
+		return_VALUE(-EINVAL);
+
+	if (!driver->ops.add)
+		return_VALUE(-ENOSYS);
+
+	result = driver->ops.add(device);
+	if (result) {
+		device->driver = NULL;
+		acpi_driver_data(device) = NULL;
+		return_VALUE(result);
+	}
+
+	/*
+	 * TBD - Configuration Management: Assign resources to device based
+	 * upon possible configuration and currently allocated resources.
+	 */
+
+	if (driver->ops.start) {
+		result = driver->ops.start(device);
+		if (result && driver->ops.remove)
+			driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL);
+		return_VALUE(result);
+	}
+
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Driver successfully bound to device\n"));
+
+	if (driver->ops.scan) {
+		driver->ops.scan(device);
+	}
+
+	return_VALUE(0);
+}
+
+static int acpi_driver_attach(struct acpi_driver * drv)
+{
+	struct list_head * node, * next;
+
+	ACPI_FUNCTION_TRACE("acpi_driver_attach");
+
+	spin_lock(&acpi_device_lock);
+	list_for_each_safe(node,next,&acpi_device_list) {
+		struct acpi_device * dev = container_of(node,struct acpi_device,g_list);
+
+		if (dev->driver || !dev->status.present)
+			continue;
+		spin_unlock(&acpi_device_lock);
+
+		if (!acpi_bus_match(dev,drv)) {
+			if (!acpi_bus_driver_init(dev,drv)) {
+				atomic_inc(&drv->references);
+				ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n",
+						  drv->name, dev->pnp.bus_id));
+			}
+		}
+		spin_lock(&acpi_device_lock);
+	}
+	spin_unlock(&acpi_device_lock);
+	return_VALUE(0);
+}
+
+static int acpi_driver_detach(struct acpi_driver * drv)
+{
+	struct list_head * node, * next;
+
+	ACPI_FUNCTION_TRACE("acpi_driver_detach");
+
+	spin_lock(&acpi_device_lock);
+	list_for_each_safe(node,next,&acpi_device_list) {
+		struct acpi_device * dev = container_of(node,struct acpi_device,g_list);
+
+		if (dev->driver == drv) {
+			if (drv->ops.remove)
+				drv->ops.remove(dev,ACPI_BUS_REMOVAL_NORMAL);
+			dev->driver = NULL;
+			dev->driver_data = NULL;
+			atomic_dec(&drv->references);
+		}
+	}
+	spin_unlock(&acpi_device_lock);
+	return_VALUE(0);
+}
+
+/**
+ * acpi_bus_register_driver 
+ * ------------------------ 
+ * Registers a driver with the ACPI bus.  Searches the namespace for all
+ * devices that match the driver's criteria and binds.
+ */
+int
+acpi_bus_register_driver (
+	struct acpi_driver	*driver)
+{
+	int error = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_bus_register_driver");
+
+	if (driver) {
+		spin_lock(&acpi_device_lock);
+		list_add_tail(&driver->node, &acpi_bus_drivers);
+		spin_unlock(&acpi_device_lock);
+		acpi_driver_attach(driver);
+	} else
+		error = -EINVAL;
+
+	return_VALUE(error);
+}
+
+
+/**
+ * acpi_bus_unregister_driver 
+ * --------------------------
+ * Unregisters a driver with the ACPI bus.  Searches the namespace for all
+ * devices that match the driver's criteria and unbinds.
+ */
+int
+acpi_bus_unregister_driver (
+	struct acpi_driver	*driver)
+{
+	int error = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_bus_unregister_driver");
+
+	if (driver) {
+		acpi_driver_detach(driver);
+
+		if (!atomic_read(&driver->references)) {
+			spin_lock(&acpi_device_lock);
+			list_del_init(&driver->node);
+			spin_unlock(&acpi_device_lock);
+		} 
+	} else 
+		error = -EINVAL;
+	return_VALUE(error);
+}
+
+/**
+ * acpi_bus_find_driver 
+ * --------------------
+ * Parses the list of registered drivers looking for a driver applicable for
+ * the specified device.
+ */
+static int
+acpi_bus_find_driver (
+	struct acpi_device	*device)
+{
+	int			result = 0;
+	struct list_head	* node, *next;
+
+	ACPI_FUNCTION_TRACE("acpi_bus_find_driver");
+
+	if (!device->flags.hardware_id && !device->flags.compatible_ids)
+		goto Done;
+
+	spin_lock(&acpi_device_lock);
+	list_for_each_safe(node,next,&acpi_bus_drivers) {
+		struct acpi_driver * driver = container_of(node,struct acpi_driver,node);
+
+		atomic_inc(&driver->references);
+		spin_unlock(&acpi_device_lock);
+		if (!acpi_bus_match(device, driver)) {
+			result = acpi_bus_driver_init(device, driver);
+			if (!result)
+				goto Done;
+		}
+		atomic_dec(&driver->references);
+		spin_lock(&acpi_device_lock);
+	}
+	spin_unlock(&acpi_device_lock);
+
+ Done:
+	return_VALUE(result);
+}
+
+
+/* --------------------------------------------------------------------------
+                                 Device Enumeration
+   -------------------------------------------------------------------------- */
+
+static int 
+acpi_bus_get_flags (
+	struct acpi_device	*device)
+{
+	acpi_status		status = AE_OK;
+	acpi_handle		temp = NULL;
+
+	ACPI_FUNCTION_TRACE("acpi_bus_get_flags");
+
+	/* Presence of _STA indicates 'dynamic_status' */
+	status = acpi_get_handle(device->handle, "_STA", &temp);
+	if (ACPI_SUCCESS(status))
+		device->flags.dynamic_status = 1;
+
+	/* Presence of _CID indicates 'compatible_ids' */
+	status = acpi_get_handle(device->handle, "_CID", &temp);
+	if (ACPI_SUCCESS(status))
+		device->flags.compatible_ids = 1;
+
+	/* Presence of _RMV indicates 'removable' */
+	status = acpi_get_handle(device->handle, "_RMV", &temp);
+	if (ACPI_SUCCESS(status))
+		device->flags.removable = 1;
+
+	/* Presence of _EJD|_EJ0 indicates 'ejectable' */
+	status = acpi_get_handle(device->handle, "_EJD", &temp);
+	if (ACPI_SUCCESS(status))
+		device->flags.ejectable = 1;
+	else {
+		status = acpi_get_handle(device->handle, "_EJ0", &temp);
+		if (ACPI_SUCCESS(status))
+			device->flags.ejectable = 1;
+	}
+
+	/* Presence of _LCK indicates 'lockable' */
+	status = acpi_get_handle(device->handle, "_LCK", &temp);
+	if (ACPI_SUCCESS(status))
+		device->flags.lockable = 1;
+
+	/* Presence of _PS0|_PR0 indicates 'power manageable' */
+	status = acpi_get_handle(device->handle, "_PS0", &temp);
+	if (ACPI_FAILURE(status))
+		status = acpi_get_handle(device->handle, "_PR0", &temp);
+	if (ACPI_SUCCESS(status))
+		device->flags.power_manageable = 1;
+
+	/* TBD: Peformance management */
+
+	return_VALUE(0);
+}
+
+static int
+acpi_bus_remove (
+	struct acpi_device	*device, 
+	int			type)
+{
+	acpi_device_unregister(device);
+	kfree(device);
+	return 0;
+}
+
+static void acpi_device_get_busid(struct acpi_device * device, acpi_handle handle, int type)
+{
+	char			bus_id[5] = {'?',0};
+	acpi_buffer		buffer = {sizeof(bus_id), bus_id};
+	int			i = 0;
+
+	/*
+	 * Bus ID
+	 * ------
+	 * The device's Bus ID is simply the object name.
+	 * TBD: Shouldn't this value be unique (within the ACPI namespace)?
+	 */
+	switch (type) {
+	case ACPI_BUS_TYPE_SYSTEM:
+		sprintf(device->pnp.bus_id, "%s", "ACPI");
+		break;
+	case ACPI_BUS_TYPE_POWER_BUTTON:
+		sprintf(device->pnp.bus_id, "%s", "PWRF");
+		break;
+	case ACPI_BUS_TYPE_SLEEP_BUTTON:
+		sprintf(device->pnp.bus_id, "%s", "SLPF");
+		break;
+	default:
+		acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
+		/* Clean up trailing underscores (if any) */
+		for (i = 3; i > 1; i--) {
+			if (bus_id[i] == '_')
+				bus_id[i] = '\0';
+			else
+				break;
+		}
+		sprintf(device->pnp.bus_id, "%s", bus_id);
+		break;
+	}
+}
+
+static void acpi_device_set_id(struct acpi_device * device, struct acpi_device * parent,
+			       acpi_handle handle, int type)
+{
+	acpi_device_info	info;
+	char			*hid = NULL;
+	char			*uid = NULL;
+	acpi_status		status;
+
+	switch (type) {
+	case ACPI_BUS_TYPE_DEVICE:
+		status = acpi_get_object_info(handle, &info);
+		if (ACPI_FAILURE(status)) {
+			printk("%s: Error reading device info\n",__FUNCTION__);
+			return;
+		}
+		/* Clean up info strings (not NULL terminated) */
+		info.hardware_id[sizeof(info.hardware_id)-1] = '\0';
+		info.unique_id[sizeof(info.unique_id)-1] = '\0';
+		if (info.valid & ACPI_VALID_HID)
+			hid = info.hardware_id;
+		if (info.valid & ACPI_VALID_UID)
+			uid = info.unique_id;
+		if (info.valid & ACPI_VALID_ADR) {
+			device->pnp.bus_address = info.address;
+			device->flags.bus_address = 1;
+		}
+		break;
+	case ACPI_BUS_TYPE_POWER:
+		hid = ACPI_POWER_HID;
+		break;
+	case ACPI_BUS_TYPE_PROCESSOR:
+		hid = ACPI_PROCESSOR_HID;
+		break;
+	case ACPI_BUS_TYPE_SYSTEM:
+		hid = ACPI_SYSTEM_HID;
+		break;
+	case ACPI_BUS_TYPE_THERMAL:
+		hid = ACPI_THERMAL_HID;
+		break;
+	case ACPI_BUS_TYPE_POWER_BUTTON:
+		hid = ACPI_BUTTON_HID_POWERF;
+		break;
+	case ACPI_BUS_TYPE_SLEEP_BUTTON:
+		hid = ACPI_BUTTON_HID_SLEEPF;
+		break;
+	}
+
+	/* 
+	 * \_SB
+	 * ----
+	 * Fix for the system root bus device -- the only root-level device.
+	 */
+	if ((parent == ACPI_ROOT_OBJECT) && (type == ACPI_BUS_TYPE_DEVICE)) {
+		hid = ACPI_BUS_HID;
+		sprintf(device->pnp.device_name, "%s", ACPI_BUS_DEVICE_NAME);
+		sprintf(device->pnp.device_class, "%s", ACPI_BUS_CLASS);
+	}
+
+	if (hid) {
+		sprintf(device->pnp.hardware_id, "%s", hid);
+		device->flags.hardware_id = 1;
+	}
+	if (uid) {
+		sprintf(device->pnp.unique_id, "%s", uid);
+		device->flags.unique_id = 1;
+	}
+}
+
+int acpi_device_set_context(struct acpi_device * device, int type)
+{
+	acpi_status status = AE_OK;
+	int result = 0;
+	/*
+	 * Context
+	 * -------
+	 * Attach this 'struct acpi_device' to the ACPI object.  This makes
+	 * resolutions from handle->device very efficient.  Note that we need
+	 * to be careful with fixed-feature devices as they all attach to the
+	 * root object.
+	 */
+	if (type != ACPI_BUS_TYPE_POWER_BUTTON && 
+	    type != ACPI_BUS_TYPE_SLEEP_BUTTON) {
+		status = acpi_attach_data(device->handle,
+			acpi_bus_data_handler, device);
+
+		if (ACPI_FAILURE(status)) {
+			printk("Error attaching device data\n");
+			result = -ENODEV;
+		}
+	}
+	return result;
+}
+
+void acpi_device_get_debug_info(struct acpi_device * device, acpi_handle handle, int type)
+{
+#ifdef CONFIG_ACPI_DEBUG
+	char		*type_string = NULL;
+	char		name[80] = {'?','\0'};
+	acpi_buffer	buffer = {sizeof(name), name};
+
+	acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+
+	switch (type) {
+	case ACPI_BUS_TYPE_DEVICE:
+		type_string = "Device";
+		break;
+	case ACPI_BUS_TYPE_POWER:
+		type_string = "Power Resource";
+		break;
+	case ACPI_BUS_TYPE_PROCESSOR:
+		type_string = "Processor";
+		break;
+	case ACPI_BUS_TYPE_SYSTEM:
+		type_string = "System";
+		break;
+	case ACPI_BUS_TYPE_THERMAL:
+		type_string = "Thermal Zone";
+		break;
+	case ACPI_BUS_TYPE_POWER_BUTTON:
+		type_string = "Power Button";
+		sprintf(name, "PWRB");
+		break;
+	case ACPI_BUS_TYPE_SLEEP_BUTTON:
+		type_string = "Sleep Button";
+		sprintf(name, "SLPB");
+		break;
+	}
+
+	pr_debug("Found %s %s [%p]\n", type_string, name, handle);
+#endif /*CONFIG_ACPI_DEBUG*/
+}
+
+static void acpi_device_attach(struct acpi_device * device, struct acpi_device * parent)
+{
+	/*
+	 * Linkage
+	 * -------
+	 * Link this device to its parent and siblings.
+	 */
+	INIT_LIST_HEAD(&device->children);
+	INIT_LIST_HEAD(&device->node);
+	INIT_LIST_HEAD(&device->g_list);
+
+	spin_lock(&acpi_device_lock);
+	if (device->parent) {
+		list_add_tail(&device->node, &device->parent->children);
+		list_add_tail(&device->g_list,&device->parent->g_list);
+	} else
+		list_add_tail(&device->g_list,&acpi_device_list);
+	spin_unlock(&acpi_device_lock);
+
+	acpi_device_register(device, parent);
+}
+
+static int 
+acpi_bus_add (
+	struct acpi_device	**child,
+	struct acpi_device	*parent,
+	acpi_handle		handle,
+	int			type)
+{
+	int			result = 0;
+	struct acpi_device	*device = NULL;
+
+	ACPI_FUNCTION_TRACE("acpi_bus_add");
+
+	if (!child)
+		return_VALUE(-EINVAL);
+
+	device = kmalloc(sizeof(struct acpi_device), GFP_KERNEL);
+	if (!device) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Memory allocation error\n"));
+		return_VALUE(-ENOMEM);
+	}
+	memset(device, 0, sizeof(struct acpi_device));
+
+	device->handle = handle;
+	device->parent = parent;
+
+	acpi_device_get_busid(device,handle,type);
+
+	/*
+	 * Flags
+	 * -----
+	 * Get prior to calling acpi_bus_get_status() so we know whether
+	 * or not _STA is present.  Note that we only look for object
+	 * handles -- cannot evaluate objects until we know the device is
+	 * present and properly initialized.
+	 */
+	result = acpi_bus_get_flags(device);
+	if (result)
+		goto end;
+
+	/*
+	 * Status
+	 * ------
+	 * See if the device is present.  We always assume that non-Device()
+	 * objects (e.g. thermal zones, power resources, processors, etc.) are
+	 * present, functioning, etc. (at least when parent object is present).
+	 * Note that _STA has a different meaning for some objects (e.g.
+	 * power resources) so we need to be careful how we use it.
+	 */
+	switch (type) {
+	case ACPI_BUS_TYPE_DEVICE:
+		result = acpi_bus_get_status(device);
+		if (!result)
+			break;
+		if (!device->status.present) 
+			result = -ENOENT;
+		goto end;
+	default:
+		STRUCT_TO_INT(device->status) = 0x0F;
+		break;
+	}
+
+	/*
+	 * Initialize Device
+	 * -----------------
+	 * TBD: Synch with Core's enumeration/initialization process.
+	 */
+
+	/*
+	 * Hardware ID, Unique ID, & Bus Address
+	 * -------------------------------------
+	 */
+	acpi_device_set_id(device,parent,handle,type);
+
+	/*
+	 * Power Management
+	 * ----------------
+	 */
+	if (device->flags.power_manageable) {
+		result = acpi_bus_get_power_flags(device);
+		if (result)
+			goto end;
+	}
+
+	/*
+	 * Performance Management
+	 * ----------------------
+	 */
+	if (device->flags.performance_manageable) {
+		result = acpi_bus_get_perf_flags(device);
+		if (result)
+			goto end;
+	}
+
+	if ((result = acpi_device_set_context(device,type)))
+		goto end;
+
+	acpi_device_get_debug_info(device,handle,type);
+
+	acpi_device_attach(device,parent);
+
+	/*
+	 * Bind _ADR-Based Devices
+	 * -----------------------
+	 * If there's a a bus address (_ADR) then we utilize the parent's 
+	 * 'bind' function (if exists) to bind the ACPI- and natively-
+	 * enumerated device representations.
+	 */
+	if (device->flags.bus_address) {
+		if (device->parent && device->parent->ops.bind)
+			device->parent->ops.bind(device);
+	}
+
+	/*
+	 * Locate & Attach Driver
+	 * ----------------------
+	 * If there's a hardware id (_HID) or compatible ids (_CID) we check
+	 * to see if there's a driver installed for this kind of device.  Note
+	 * that drivers can install before or after a device in enumerated.
+	 *
+	 * TBD: Assumes LDM provides driver hot-plug capability.
+	 */
+	acpi_bus_find_driver(device);
+
+end:
+	if (!result)
+		*child = device;
+	else
+		kfree(device);
+	return_VALUE(result);
+}
+
+
+
+static int acpi_bus_scan (struct acpi_device	*start)
+{
+	acpi_status		status = AE_OK;
+	struct acpi_device	*parent = NULL;
+	struct acpi_device	*child = NULL;
+	acpi_handle		phandle = 0;
+	acpi_handle		chandle = 0;
+	acpi_object_type	type = 0;
+	u32			level = 1;
+
+	ACPI_FUNCTION_TRACE("acpi_bus_scan");
+
+	if (!start)
+		return_VALUE(-EINVAL);
+
+	parent = start;
+	phandle = start->handle;
+	
+	/*
+	 * Parse through the ACPI namespace, identify all 'devices', and
+	 * create a new 'struct acpi_device' for each.
+	 */
+	while ((level > 0) && parent) {
+
+		status = acpi_get_next_object(ACPI_TYPE_ANY, phandle,
+			chandle, &chandle);
+
+		/*
+		 * If this scope is exhausted then move our way back up.
+		 */
+		if (ACPI_FAILURE(status)) {
+			level--;
+			chandle = phandle;
+			acpi_get_parent(phandle, &phandle);
+			if (parent->parent)
+				parent = parent->parent;
+			continue;
+		}
+
+		status = acpi_get_type(chandle, &type);
+		if (ACPI_FAILURE(status))
+			continue;
+
+		/*
+		 * If this is a scope object then parse it (depth-first).
+		 */
+		if (type == ACPI_TYPE_ANY) {
+			/* Hack to get around scope identity problem */
+			status = acpi_get_next_object(ACPI_TYPE_ANY, chandle, 0, NULL);
+			if (ACPI_SUCCESS(status)) {
+				level++;
+				phandle = chandle;
+				chandle = 0;
+			}
+			continue;
+		}
+
+		/*
+		 * We're only interested in objects that we consider 'devices'.
+		 */
+		switch (type) {
+		case ACPI_TYPE_DEVICE:
+			type = ACPI_BUS_TYPE_DEVICE;
+			break;
+		case ACPI_TYPE_PROCESSOR:
+			type = ACPI_BUS_TYPE_PROCESSOR;
+			break;
+		case ACPI_TYPE_THERMAL:
+			type = ACPI_BUS_TYPE_THERMAL;
+			break;
+		case ACPI_TYPE_POWER:
+			type = ACPI_BUS_TYPE_POWER;
+			break;
+		default:
+			continue;
+		}
+
+		status = acpi_bus_add(&child, parent, chandle, type);
+		if (ACPI_FAILURE(status))
+			continue;
+
+		/*
+		 * If the device is present, enabled, and functioning then
+		 * parse its scope (depth-first).  Note that we need to
+		 * represent absent devices to facilitate PnP notifications
+		 * -- but only the subtree head (not all of its children,
+		 * which will be enumerated when the parent is inserted).
+		 *
+		 * TBD: Need notifications and other detection mechanisms
+		 *	in place before we can fully implement this.
+		 */
+		if (child->status.present) {
+			status = acpi_get_next_object(ACPI_TYPE_ANY, chandle,
+				0, NULL);
+			if (ACPI_SUCCESS(status)) {
+				level++;
+				phandle = chandle;
+				chandle = 0;
+				parent = child;
+			}
+		}
+	}
+
+	return_VALUE(0);
+}
+
+
+static int
+acpi_bus_scan_fixed (
+	struct acpi_device	*root)
+{
+	int			result = 0;
+	struct acpi_device	*device = NULL;
+
+	ACPI_FUNCTION_TRACE("acpi_bus_scan_fixed");
+
+	if (!root)
+		return_VALUE(-ENODEV);
+
+	/*
+	 * Enumerate all fixed-feature devices.
+	 */
+	if (acpi_fadt.pwr_button == 0)
+		result = acpi_bus_add(&device, acpi_root, 
+			ACPI_ROOT_OBJECT, ACPI_BUS_TYPE_POWER_BUTTON);
+
+	if (acpi_fadt.sleep_button == 0)
+		result = acpi_bus_add(&device, acpi_root, 
+			ACPI_ROOT_OBJECT, ACPI_BUS_TYPE_SLEEP_BUTTON);
+
+	return_VALUE(result);
+}
+
+
+static int __init acpi_scan_init(void)
+{
+	int result;
+
+	ACPI_FUNCTION_TRACE("acpi_scan_init");
+
+	if (acpi_disabled)
+		return_VALUE(0);
+
+	/*
+	 * Create the root device in the bus's device tree
+	 */
+	result = acpi_bus_add(&acpi_root, NULL, ACPI_ROOT_OBJECT, 
+		ACPI_BUS_TYPE_SYSTEM);
+	if (result)
+		goto Done;
+
+	/*
+	 * Enumerate devices in the ACPI namespace.
+	 */
+	result = acpi_bus_scan_fixed(acpi_root);
+	if (!result) 
+		result = acpi_bus_scan(acpi_root);
+
+	if (result)
+		acpi_bus_remove(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
+
+ Done:
+	return_VALUE(result);
+}
+
+subsys_initcall(acpi_scan_init);
diff -Nru a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/acpi/sleep.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,718 @@
+/*
+ * sleep.c - ACPI sleep support.
+ * 
+ *  Copyright (c) 2000-2002 Patrick Mochel
+ *
+ *  Portions are
+ *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ */
+
+#include <linux/proc_fs.h>
+#include <linux/sysrq.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/pm.h>
+#include <linux/device.h>
+#include <linux/suspend.h>
+
+#include <asm/uaccess.h>
+#include <asm/acpi.h>
+
+#include "acpi_bus.h"
+#include "acpi_drivers.h"
+
+#ifdef CONFIG_X86
+#include <linux/mc146818rtc.h>
+#endif
+
+#define _COMPONENT		ACPI_SYSTEM_COMPONENT
+ACPI_MODULE_NAME		("sleep")
+
+#define ACPI_SYSTEM_FILE_SLEEP		"sleep"
+#define ACPI_SYSTEM_FILE_ALARM		"alarm"
+
+static u8 sleep_states[ACPI_S_STATE_COUNT];
+
+static void
+acpi_power_off (void)
+{
+	acpi_enter_sleep_state_prep(ACPI_STATE_S5);
+	ACPI_DISABLE_IRQS();
+	acpi_enter_sleep_state(ACPI_STATE_S5);
+}
+
+/**
+ * acpi_system_restore_state - OS-specific restoration of state
+ * @state:	sleep state we're exiting
+ *
+ * Note that if we're coming back from S4, the memory image should have already
+ * been loaded from the disk and is already in place. (Otherwise how else would we
+ * be here?).
+ */
+acpi_status
+acpi_system_restore_state (
+	u32			state)
+{
+	/* restore processor state
+	 * We should only be here if we're coming back from STR or STD.
+	 * And, in the case of the latter, the memory image should have already
+	 * been loaded from disk.
+	 */
+	if (state > ACPI_STATE_S1)
+		acpi_restore_state_mem();
+
+	/* wait for power to come back */
+	mdelay(10);
+
+	/* turn all the devices back on */
+	device_resume(RESUME_POWER_ON);
+
+	/* enable interrupts once again */
+	ACPI_ENABLE_IRQS();
+
+	/* restore device context */
+	device_resume(RESUME_RESTORE_STATE);
+
+	if (dmi_broken & BROKEN_INIT_AFTER_S1) {
+		printk("Broken toshiba laptop -> kicking interrupts\n");
+		init_8259A(0);
+	}
+
+	return AE_OK;
+}
+
+/**
+ * acpi_system_save_state - save OS specific state and power down devices
+ * @state:	sleep state we're entering.
+ *
+ * This handles saving all context to memory, and possibly disk.
+ * First, we call to the device driver layer to save device state.
+ * Once we have that, we save whatevery processor and kernel state we
+ * need to memory.
+ * If we're entering S4, we then write the memory image to disk.
+ *
+ * Only then is it safe for us to power down devices, since we may need
+ * the disks and upstream buses to write to.
+ */
+acpi_status
+acpi_system_save_state(
+	u32			state)
+{
+	int			error = 0;
+
+	/* Send notification to devices that they will be suspended.
+	 * If any device or driver cannot make the transition, either up
+	 * or down, we'll get an error back.
+	 */
+	error = device_suspend(state, SUSPEND_NOTIFY);
+	if (error)
+		return AE_ERROR;
+
+	if (state < ACPI_STATE_S5) {
+
+		/* Tell devices to stop I/O and actually save their state.
+		 * It is theoretically possible that something could fail,
+		 * so handle that gracefully..
+		 */
+		error = device_suspend(state, SUSPEND_SAVE_STATE);
+		if (error) {
+			/* tell devices to restore state if they have
+			 * it saved and to start taking I/O requests.
+			 */
+			device_resume(RESUME_RESTORE_STATE);
+			return error;
+		}
+
+		/* flush caches */
+		ACPI_FLUSH_CPU_CACHE();
+
+		/* Do arch specific saving of state. */
+		if (state > ACPI_STATE_S1) {
+			error = acpi_save_state_mem();
+
+			if (!error && (state == ACPI_STATE_S4))
+				error = acpi_save_state_disk();
+
+			if (error) {
+				device_resume(RESUME_RESTORE_STATE);
+				return error;
+			}
+		}
+	}
+
+	/* disable interrupts
+	 * Note that acpi_suspend -- our caller -- will do this once we return.
+	 * But, we want it done early, so we don't get any suprises during
+	 * the device suspend sequence.
+	 */
+	ACPI_DISABLE_IRQS();
+
+	/* Unconditionally turn off devices.
+	 * Obvious if we enter a sleep state.
+	 * If entering S5 (soft off), this should put devices in a
+	 * quiescent state.
+	 */
+	error = device_suspend(state, SUSPEND_POWER_DOWN);
+
+	/* We're pretty screwed if we got an error from this.
+	 * We try to recover by simply calling our own restore_state
+	 * function; see above for definition.
+	 *
+	 * If it's S5 though, go through with it anyway..
+	 */
+	if (error && state != ACPI_STATE_S5)
+		acpi_system_restore_state(state);
+
+	return error ? AE_ERROR : AE_OK;
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION:    acpi_system_suspend
+ *
+ * PARAMETERS:  %state: Sleep state to enter.
+ *
+ * RETURN:      acpi_status, whether or not we successfully entered and
+ *              exited sleep.
+ *
+ * DESCRIPTION: Perform OS-specific action to enter sleep state.
+ *              This is the final step in going to sleep, per spec.  If we
+ *              know we're coming back (i.e. not entering S5), we save the
+ *              processor flags. [ We'll have to save and restore them anyway,
+ *              so we use the arch-agnostic save_flags and restore_flags
+ *              here.]  We then set the place to return to in arch-specific
+ *              globals using arch_set_return_point. Finally, we call the
+ *              ACPI function to write the proper values to I/O ports.
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_system_suspend(
+	u32			state)
+{
+	acpi_status		status = AE_ERROR;
+	unsigned long		flags = 0;
+
+	local_irq_save(flags);
+	
+	switch (state)
+	{
+	case ACPI_STATE_S1:
+		barrier();
+		status = acpi_enter_sleep_state(state);
+		break;
+
+	case ACPI_STATE_S2:
+	case ACPI_STATE_S3:
+		do_suspend_lowlevel(0);
+		break;
+	}
+	local_irq_restore(flags);
+
+	return status;
+}
+
+
+/**
+ * acpi_suspend - OS-agnostic system suspend/resume support (S? states)
+ * @state:	state we're entering
+ *
+ */
+acpi_status
+acpi_suspend (
+	u32			state)
+{
+	acpi_status status;
+
+	/* get out if state is invalid */
+	if (state < ACPI_STATE_S1 || state > ACPI_STATE_S5)
+		return AE_ERROR;
+
+	freeze_processes();		/* device_suspend needs processes to be stopped */
+
+	/* do we have a wakeup address for S2 and S3? */
+	if (state == ACPI_STATE_S2 || state == ACPI_STATE_S3) {
+		if (!acpi_wakeup_address)
+			return AE_ERROR;
+		acpi_set_firmware_waking_vector((ACPI_PHYSICAL_ADDRESS) acpi_wakeup_address);
+	}
+
+	acpi_enter_sleep_state_prep(state);
+
+	status = acpi_system_save_state(state);
+	if (!ACPI_SUCCESS(status))
+		return status;
+
+	/* disable interrupts and flush caches */
+	ACPI_DISABLE_IRQS();
+	ACPI_FLUSH_CPU_CACHE();
+
+	/* perform OS-specific sleep actions */
+	status = acpi_system_suspend(state);
+
+	/* Even if we failed to go to sleep, all of the devices are in an suspended
+	 * mode. So, we run these unconditionaly to make sure we have a usable system
+	 * no matter what.
+	 */
+	acpi_system_restore_state(state);
+	acpi_leave_sleep_state(state);
+
+	/* make sure interrupts are enabled */
+	ACPI_ENABLE_IRQS();
+
+	/* reset firmware waking vector */
+	acpi_set_firmware_waking_vector((ACPI_PHYSICAL_ADDRESS) 0);
+	thaw_processes();
+
+	return status;
+}
+
+
+static int
+acpi_system_read_sleep (
+        char                    *page,
+        char                    **start,
+        off_t                   off,
+        int                     count,
+        int                     *eof,
+        void                    *data)
+{
+	char			*p = page;
+	int			size;
+	int			i;
+
+	ACPI_FUNCTION_TRACE("acpi_system_read_sleep");
+
+	if (off != 0)
+		goto end;
+
+	for (i = 0; i <= ACPI_STATE_S5; i++) {
+		if (sleep_states[i])
+			p += sprintf(p,"S%d ", i);
+	}
+
+	p += sprintf(p, "\n");
+
+end:
+	size = (p - page);
+	if (size <= off+count) *eof = 1;
+	*start = page + off;
+	size -= off;
+	if (size>count) size = count;
+	if (size<0) size = 0;
+
+	return_VALUE(size);
+}
+
+
+static int
+acpi_system_write_sleep (
+	struct file		*file,
+	const char		*buffer,
+	unsigned long		count,
+	void			*data)
+{
+	acpi_status		status = AE_OK;
+	char			state_string[12] = {'\0'};
+	u32			state = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_system_write_sleep");
+
+	if (count > sizeof(state_string) - 1)
+		return_VALUE(-EINVAL);
+
+	if (copy_from_user(state_string, buffer, count))
+		return_VALUE(-EFAULT);
+	
+	state_string[count] = '\0';
+	
+	state = simple_strtoul(state_string, NULL, 0);
+	
+	if (sleep_states[state])
+		return_VALUE(-ENODEV);
+
+#ifdef CONFIG_SOFTWARE_SUSPEND
+	if (state == 4) {
+		software_suspend();
+		return_VALUE(count);
+	}
+#endif
+	status = acpi_suspend(state);
+
+	if (ACPI_FAILURE(status))
+		return_VALUE(-ENODEV);
+	
+	return_VALUE(count);
+}
+
+
+static int
+acpi_system_read_alarm (
+	char                    *page,
+	char                    **start,
+	off_t                   off,
+	int                     count,
+	int                     *eof,
+	void                    *context)
+{
+	char			*p = page;
+	int			size = 0;
+	u32			sec, min, hr;
+	u32			day, mo, yr;
+
+	ACPI_FUNCTION_TRACE("acpi_system_read_alarm");
+
+	if (off != 0)
+		goto end;
+
+	spin_lock(&rtc_lock);
+
+	sec = CMOS_READ(RTC_SECONDS_ALARM);
+	min = CMOS_READ(RTC_MINUTES_ALARM);
+	hr = CMOS_READ(RTC_HOURS_ALARM);
+
+#if 0	/* If we ever get an FACP with proper values... */
+	if (acpi_gbl_FADT->day_alrm)
+		day = CMOS_READ(acpi_gbl_FADT->day_alrm);
+	else
+		day =  CMOS_READ(RTC_DAY_OF_MONTH);
+	if (acpi_gbl_FADT->mon_alrm)
+		mo = CMOS_READ(acpi_gbl_FADT->mon_alrm);
+	else
+		mo = CMOS_READ(RTC_MONTH);;
+	if (acpi_gbl_FADT->century)
+		yr = CMOS_READ(acpi_gbl_FADT->century) * 100 + CMOS_READ(RTC_YEAR);
+	else
+		yr = CMOS_READ(RTC_YEAR);
+#else
+	day = CMOS_READ(RTC_DAY_OF_MONTH);
+	mo = CMOS_READ(RTC_MONTH);
+	yr = CMOS_READ(RTC_YEAR);
+#endif
+
+	spin_unlock(&rtc_lock);
+
+	BCD_TO_BIN(sec);
+	BCD_TO_BIN(min);
+	BCD_TO_BIN(hr);
+	BCD_TO_BIN(day);
+	BCD_TO_BIN(mo);
+	BCD_TO_BIN(yr);
+
+#if 0
+	/* we're trusting the FADT (see above)*/
+#else
+	/* If we're not trusting the FADT, we should at least make it
+	 * right for _this_ century... ehm, what is _this_ century?
+	 *
+	 * TBD:
+	 *  ASAP: find piece of code in the kernel, e.g. star tracker driver,
+	 *        which we can trust to determine the century correctly. Atom
+	 *        watch driver would be nice, too...
+	 *
+	 *  if that has not happened, change for first release in 2050:
+ 	 *        if (yr<50)
+	 *                yr += 2100;
+	 *        else
+	 *                yr += 2000;   // current line of code
+	 *
+	 *  if that has not happened either, please do on 2099/12/31:23:59:59
+	 *        s/2000/2100
+	 *
+	 */
+	yr += 2000;
+#endif
+
+	p += sprintf(p,"%4.4u-", yr);
+	p += (mo > 12)  ? sprintf(p, "**-")  : sprintf(p, "%2.2u-", mo);
+	p += (day > 31) ? sprintf(p, "** ")  : sprintf(p, "%2.2u ", day);
+	p += (hr > 23)  ? sprintf(p, "**:")  : sprintf(p, "%2.2u:", hr);
+	p += (min > 59) ? sprintf(p, "**:")  : sprintf(p, "%2.2u:", min);
+	p += (sec > 59) ? sprintf(p, "**\n") : sprintf(p, "%2.2u\n", sec);
+
+ end:
+	size = p - page;
+	if (size < count) *eof = 1;
+	else if (size > count) size = count;
+	if (size < 0) size = 0;
+	*start = page;
+
+	return_VALUE(size);
+}
+
+
+static int
+get_date_field (
+	char			**p,
+	u32			*value)
+{
+	char			*next = NULL;
+	char			*string_end = NULL;
+	int			result = -EINVAL;
+
+	/*
+	 * Try to find delimeter, only to insert null.  The end of the
+	 * string won't have one, but is still valid.
+	 */
+	next = strpbrk(*p, "- :");
+	if (next)
+		*next++ = '\0';
+
+	*value = simple_strtoul(*p, &string_end, 10);
+
+	/* Signal success if we got a good digit */
+	if (string_end != *p)
+		result = 0;
+
+	if (next)
+		*p = next;
+
+	return result;
+}
+
+
+static int
+acpi_system_write_alarm (
+	struct file		*file,
+	const char		*buffer,
+	unsigned long		count,
+	void			*data)
+{
+	int			result = 0;
+	char			alarm_string[30] = {'\0'};
+	char			*p = alarm_string;
+	u32			sec, min, hr, day, mo, yr;
+	int			adjust = 0;
+	unsigned char		rtc_control = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_system_write_alarm");
+
+	if (count > sizeof(alarm_string) - 1)
+		return_VALUE(-EINVAL);
+	
+	if (copy_from_user(alarm_string, buffer, count))
+		return_VALUE(-EFAULT);
+
+	alarm_string[count] = '\0';
+
+	/* check for time adjustment */
+	if (alarm_string[0] == '+') {
+		p++;
+		adjust = 1;
+	}
+
+	if ((result = get_date_field(&p, &yr)))
+		goto end;
+	if ((result = get_date_field(&p, &mo)))
+		goto end;
+	if ((result = get_date_field(&p, &day)))
+		goto end;
+	if ((result = get_date_field(&p, &hr)))
+		goto end;
+	if ((result = get_date_field(&p, &min)))
+		goto end;
+	if ((result = get_date_field(&p, &sec)))
+		goto end;
+
+	if (sec > 59) {
+		min += 1;
+		sec -= 60;
+	}
+	if (min > 59) {
+		hr += 1;
+		min -= 60;
+	}
+	if (hr > 23) {
+		day += 1;
+		hr -= 24;
+	}
+	if (day > 31) {
+		mo += 1;
+		day -= 31;
+	}
+	if (mo > 12) {
+		yr += 1;
+		mo -= 12;
+	}
+
+	spin_lock_irq(&rtc_lock);
+
+	rtc_control = CMOS_READ(RTC_CONTROL);
+	if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+		BIN_TO_BCD(yr);
+		BIN_TO_BCD(mo);
+		BIN_TO_BCD(day);
+		BIN_TO_BCD(hr);
+		BIN_TO_BCD(min);
+		BIN_TO_BCD(sec);
+	}
+
+	if (adjust) {
+		yr  += CMOS_READ(RTC_YEAR);
+		mo  += CMOS_READ(RTC_MONTH);
+		day += CMOS_READ(RTC_DAY_OF_MONTH);
+		hr  += CMOS_READ(RTC_HOURS);
+		min += CMOS_READ(RTC_MINUTES);
+		sec += CMOS_READ(RTC_SECONDS);
+	}
+
+	spin_unlock_irq(&rtc_lock);
+
+	if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+		BCD_TO_BIN(yr);
+		BCD_TO_BIN(mo);
+		BCD_TO_BIN(day);
+		BCD_TO_BIN(hr);
+		BCD_TO_BIN(min);
+		BCD_TO_BIN(sec);
+	}
+
+	if (sec > 59) {
+		min++;
+		sec -= 60;
+	}
+	if (min > 59) {
+		hr++;
+		min -= 60;
+	}
+	if (hr > 23) {
+		day++;
+		hr -= 24;
+	}
+	if (day > 31) {
+		mo++;
+		day -= 31;
+	}
+	if (mo > 12) {
+		yr++;
+		mo -= 12;
+	}
+	if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+		BIN_TO_BCD(yr);
+		BIN_TO_BCD(mo);
+		BIN_TO_BCD(day);
+		BIN_TO_BCD(hr);
+		BIN_TO_BCD(min);
+		BIN_TO_BCD(sec);
+	}
+
+	spin_lock_irq(&rtc_lock);
+
+	/* write the fields the rtc knows about */
+	CMOS_WRITE(hr, RTC_HOURS_ALARM);
+	CMOS_WRITE(min, RTC_MINUTES_ALARM);
+	CMOS_WRITE(sec, RTC_SECONDS_ALARM);
+
+	/*
+	 * If the system supports an enhanced alarm it will have non-zero
+	 * offsets into the CMOS RAM here -- which for some reason are pointing
+	 * to the RTC area of memory.
+	 */
+#if 0
+	if (acpi_gbl_FADT->day_alrm)
+		CMOS_WRITE(day, acpi_gbl_FADT->day_alrm);
+	if (acpi_gbl_FADT->mon_alrm)
+		CMOS_WRITE(mo, acpi_gbl_FADT->mon_alrm);
+	if (acpi_gbl_FADT->century)
+		CMOS_WRITE(yr/100, acpi_gbl_FADT->century);
+#endif
+	/* enable the rtc alarm interrupt */
+	if (!(rtc_control & RTC_AIE)) {
+		rtc_control |= RTC_AIE;
+		CMOS_WRITE(rtc_control,RTC_CONTROL);
+		CMOS_READ(RTC_INTR_FLAGS);
+	}
+
+	spin_unlock_irq(&rtc_lock);
+
+	acpi_set_register(ACPI_BITREG_RT_CLOCK_ENABLE, 1, ACPI_MTX_LOCK);
+
+	file->f_pos += count;
+
+	result = 0;
+end:
+	return_VALUE(result ? result : count);
+}
+
+
+#if defined(CONFIG_MAGIC_SYSRQ) && defined(CONFIG_PM)
+
+/* Simple wrapper calling power down function. */
+static void acpi_sysrq_power_off(int key, struct pt_regs *pt_regs,
+	struct tty_struct *tty)
+{
+	acpi_power_off();
+}
+
+struct sysrq_key_op sysrq_acpi_poweroff_op = {
+	.handler =	&acpi_sysrq_power_off,
+	.help_msg =	"Off",
+	.action_msg =	"Power Off\n"
+};
+
+#endif  /* CONFIG_MAGIC_SYSRQ */
+
+static int __init acpi_sleep_init(void)
+{
+	struct proc_dir_entry	*entry = NULL;
+	acpi_status		status = AE_OK;
+	int			i = 0;
+
+	ACPI_FUNCTION_TRACE("acpi_system_add_fs");
+
+	if (acpi_disabled)
+		return_VALUE(0);
+
+	printk(KERN_INFO PREFIX "(supports");
+	for (i=0; i<ACPI_S_STATE_COUNT; i++) {
+		u8 type_a, type_b;
+		status = acpi_get_sleep_type_data(i, &type_a, &type_b);
+		if (ACPI_SUCCESS(status)) {
+			sleep_states[i] = 1;
+			printk(" S%d", i);
+		}
+	}
+	printk(")\n");
+
+
+	/* 'sleep' [R/W]*/
+	entry = create_proc_entry(ACPI_SYSTEM_FILE_SLEEP,
+		S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir);
+	if (!entry)
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+			"Unable to create '%s' fs entry\n",
+			ACPI_SYSTEM_FILE_SLEEP));
+	else {
+		entry->read_proc = acpi_system_read_sleep;
+		entry->write_proc = acpi_system_write_sleep;
+	}
+
+	/* 'alarm' [R/W] */
+	entry = create_proc_entry(ACPI_SYSTEM_FILE_ALARM,
+		S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir);
+	if (!entry)
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+			"Unable to create '%s' fs entry\n",
+			ACPI_SYSTEM_FILE_ALARM));
+	else {
+		entry->read_proc = acpi_system_read_alarm;
+		entry->write_proc = acpi_system_write_alarm;
+	}
+
+	/* Install the soft-off (S5) handler. */
+	if (sleep_states[ACPI_STATE_S5]) {
+		pm_power_off = acpi_power_off;
+		register_sysrq_key('o', &sysrq_acpi_poweroff_op);
+
+		/* workaround: some systems don't claim S4 support, but they
+                   do support S5 (power-down). That is all we need, so
+		   indicate support. */
+		sleep_states[ACPI_STATE_S4] = 1;
+	}
+
+	return_VALUE(0);
+}
+
+subsys_initcall(acpi_sleep_init);
diff -Nru a/drivers/acpi/system.c b/drivers/acpi/system.c
--- a/drivers/acpi/system.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/acpi/system.c	Fri Sep 20 08:20:47 2002
@@ -23,314 +23,26 @@
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
 
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/spinlock.h>
-#include <linux/poll.h>
-#include <linux/delay.h>
-#include <linux/sysrq.h>
-#include <linux/compatmac.h>
 #include <linux/proc_fs.h>
-#include <linux/irq.h>
-#include <linux/pm.h>
-#include <linux/device.h>
-#include <linux/suspend.h>
+#include <linux/init.h>
 #include <asm/uaccess.h>
-#include <asm/acpi.h>
-#include "acpi_bus.h"
-#include "acpi_drivers.h"
 
-#ifdef CONFIG_X86
-#ifdef CONFIG_ACPI_SLEEP
-#include <linux/mc146818rtc.h>
-#endif
-#endif
+#include "acpi_drivers.h"
 
 
 #define _COMPONENT		ACPI_SYSTEM_COMPONENT
 ACPI_MODULE_NAME		("acpi_system")
 
-#define PREFIX			"ACPI: "
+#define ACPI_SYSTEM_CLASS		"system"
+#define ACPI_SYSTEM_DRIVER_NAME		"ACPI System Driver"
+#define ACPI_SYSTEM_DEVICE_NAME		"System"
+#define ACPI_SYSTEM_FILE_INFO		"info"
+#define ACPI_SYSTEM_FILE_EVENT		"event"
+#define ACPI_SYSTEM_FILE_DSDT		"dsdt"
+#define ACPI_SYSTEM_FILE_FADT		"fadt"
 
 extern FADT_DESCRIPTOR		acpi_fadt;
 
-static int acpi_system_add (struct acpi_device *device);
-static int acpi_system_remove (struct acpi_device *device, int type);
-
-static struct acpi_driver acpi_system_driver = {
-	.name =		ACPI_SYSTEM_DRIVER_NAME,
-	.class =	ACPI_SYSTEM_CLASS,
-	.ids =		ACPI_SYSTEM_HID,
-	.ops =		{
-				.add =		acpi_system_add,
-				.remove =	acpi_system_remove
-			},
-};
-
-struct acpi_system
-{
-	acpi_handle		handle;
-	u8			states[ACPI_S_STATE_COUNT];
-};
-
-/* Global vars for handling event proc entry */
-static spinlock_t		acpi_system_event_lock = SPIN_LOCK_UNLOCKED;
-int				event_is_open = 0;
-extern struct list_head		acpi_bus_event_list;
-extern wait_queue_head_t	acpi_bus_event_queue;
-
-/* --------------------------------------------------------------------------
-                                  System Sleep
-   -------------------------------------------------------------------------- */
-
-#ifdef CONFIG_PM
-
-static void
-acpi_power_off (void)
-{
-	acpi_enter_sleep_state_prep(ACPI_STATE_S5);
-	ACPI_DISABLE_IRQS();
-	acpi_enter_sleep_state(ACPI_STATE_S5);
-}
-
-#endif /*CONFIG_PM*/
-
-
-#ifdef CONFIG_ACPI_SLEEP
-
-/**
- * acpi_system_restore_state - OS-specific restoration of state
- * @state:	sleep state we're exiting
- *
- * Note that if we're coming back from S4, the memory image should have already
- * been loaded from the disk and is already in place. (Otherwise how else would we
- * be here?).
- */
-acpi_status
-acpi_system_restore_state (
-	u32			state)
-{
-	/* restore processor state
-	 * We should only be here if we're coming back from STR or STD.
-	 * And, in the case of the latter, the memory image should have already
-	 * been loaded from disk.
-	 */
-	if (state > ACPI_STATE_S1)
-		acpi_restore_state_mem();
-
-	/* wait for power to come back */
-	mdelay(10);
-
-	/* turn all the devices back on */
-	device_resume(RESUME_POWER_ON);
-
-	/* enable interrupts once again */
-	ACPI_ENABLE_IRQS();
-
-	/* restore device context */
-	device_resume(RESUME_RESTORE_STATE);
-
-	if (dmi_broken & BROKEN_INIT_AFTER_S1) {
-		printk("Broken toshiba laptop -> kicking interrupts\n");
-		init_8259A(0);
-	}
-
-	return AE_OK;
-}
-
-/**
- * acpi_system_save_state - save OS specific state and power down devices
- * @state:	sleep state we're entering.
- *
- * This handles saving all context to memory, and possibly disk.
- * First, we call to the device driver layer to save device state.
- * Once we have that, we save whatevery processor and kernel state we
- * need to memory.
- * If we're entering S4, we then write the memory image to disk.
- *
- * Only then is it safe for us to power down devices, since we may need
- * the disks and upstream buses to write to.
- */
-acpi_status
-acpi_system_save_state(
-	u32			state)
-{
-	int			error = 0;
-
-	/* Send notification to devices that they will be suspended.
-	 * If any device or driver cannot make the transition, either up
-	 * or down, we'll get an error back.
-	 */
-	error = device_suspend(state, SUSPEND_NOTIFY);
-	if (error)
-		return AE_ERROR;
-
-	if (state < ACPI_STATE_S5) {
-
-		/* Tell devices to stop I/O and actually save their state.
-		 * It is theoretically possible that something could fail,
-		 * so handle that gracefully..
-		 */
-		error = device_suspend(state, SUSPEND_SAVE_STATE);
-		if (error) {
-			/* tell devices to restore state if they have
-			 * it saved and to start taking I/O requests.
-			 */
-			device_resume(RESUME_RESTORE_STATE);
-			return error;
-		}
-
-		/* flush caches */
-		ACPI_FLUSH_CPU_CACHE();
-
-		/* Do arch specific saving of state. */
-		if (state > ACPI_STATE_S1) {
-			error = acpi_save_state_mem();
-
-			if (!error && (state == ACPI_STATE_S4))
-				error = acpi_save_state_disk();
-
-			if (error) {
-				device_resume(RESUME_RESTORE_STATE);
-				return error;
-			}
-		}
-	}
-
-	/* disable interrupts
-	 * Note that acpi_suspend -- our caller -- will do this once we return.
-	 * But, we want it done early, so we don't get any suprises during
-	 * the device suspend sequence.
-	 */
-	ACPI_DISABLE_IRQS();
-
-	/* Unconditionally turn off devices.
-	 * Obvious if we enter a sleep state.
-	 * If entering S5 (soft off), this should put devices in a
-	 * quiescent state.
-	 */
-	error = device_suspend(state, SUSPEND_POWER_DOWN);
-
-	/* We're pretty screwed if we got an error from this.
-	 * We try to recover by simply calling our own restore_state
-	 * function; see above for definition.
-	 *
-	 * If it's S5 though, go through with it anyway..
-	 */
-	if (error && state != ACPI_STATE_S5)
-		acpi_system_restore_state(state);
-
-	return error ? AE_ERROR : AE_OK;
-}
-
-
-/****************************************************************************
- *
- * FUNCTION:    acpi_system_suspend
- *
- * PARAMETERS:  %state: Sleep state to enter.
- *
- * RETURN:      acpi_status, whether or not we successfully entered and
- *              exited sleep.
- *
- * DESCRIPTION: Perform OS-specific action to enter sleep state.
- *              This is the final step in going to sleep, per spec.  If we
- *              know we're coming back (i.e. not entering S5), we save the
- *              processor flags. [ We'll have to save and restore them anyway,
- *              so we use the arch-agnostic save_flags and restore_flags
- *              here.]  We then set the place to return to in arch-specific
- *              globals using arch_set_return_point. Finally, we call the
- *              ACPI function to write the proper values to I/O ports.
- *
- ****************************************************************************/
-
-acpi_status
-acpi_system_suspend(
-	u32			state)
-{
-	acpi_status		status = AE_ERROR;
-	unsigned long		flags = 0;
-
-	local_irq_save(flags);
-	
-	switch (state)
-	{
-	case ACPI_STATE_S1:
-		barrier();
-		status = acpi_enter_sleep_state(state);
-		break;
-
-	case ACPI_STATE_S2:
-	case ACPI_STATE_S3:
-		do_suspend_lowlevel(0);
-		break;
-	}
-	local_irq_restore(flags);
-
-	return status;
-}
-
-
-/**
- * acpi_suspend - OS-agnostic system suspend/resume support (S? states)
- * @state:	state we're entering
- *
- */
-acpi_status
-acpi_suspend (
-	u32			state)
-{
-	acpi_status status;
-
-	/* get out if state is invalid */
-	if (state < ACPI_STATE_S1 || state > ACPI_STATE_S5)
-		return AE_ERROR;
-
-	freeze_processes();		/* device_suspend needs processes to be stopped */
-
-	/* do we have a wakeup address for S2 and S3? */
-	if (state == ACPI_STATE_S2 || state == ACPI_STATE_S3) {
-		if (!acpi_wakeup_address)
-			return AE_ERROR;
-		acpi_set_firmware_waking_vector((ACPI_PHYSICAL_ADDRESS) acpi_wakeup_address);
-	}
-
-	acpi_enter_sleep_state_prep(state);
-
-	status = acpi_system_save_state(state);
-	if (!ACPI_SUCCESS(status))
-		return status;
-
-	/* disable interrupts and flush caches */
-	ACPI_DISABLE_IRQS();
-	ACPI_FLUSH_CPU_CACHE();
-
-	/* perform OS-specific sleep actions */
-	status = acpi_system_suspend(state);
-
-	/* Even if we failed to go to sleep, all of the devices are in an suspended
-	 * mode. So, we run these unconditionaly to make sure we have a usable system
-	 * no matter what.
-	 */
-	acpi_system_restore_state(state);
-	acpi_leave_sleep_state(state);
-
-	/* make sure interrupts are enabled */
-	ACPI_ENABLE_IRQS();
-
-	/* reset firmware waking vector */
-	acpi_set_firmware_waking_vector((ACPI_PHYSICAL_ADDRESS) 0);
-	thaw_processes();
-
-	return status;
-}
-
-#endif /* CONFIG_ACPI_SLEEP */
-
-
 /* --------------------------------------------------------------------------
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
@@ -344,25 +56,16 @@
 	int 			*eof,
 	void			*data)
 {
-	struct acpi_system	*system = (struct acpi_system *) data;
 	char			*p = page;
 	int			size = 0;
-	u32			i = 0;
 
 	ACPI_FUNCTION_TRACE("acpi_system_read_info");
 
-	if (!system || (off != 0))
+	if (off != 0)
 		goto end;
 
 	p += sprintf(p, "version:                 %x\n", ACPI_CA_VERSION);
 
-	p += sprintf(p, "states:                  ");
-	for (i=0; i<ACPI_S_STATE_COUNT; i++) {
-		if (system->states[i])
-			p += sprintf(p, "S%d ", i);
-	}
-	p += sprintf(p, "\n");
-
 end:
 	size = (p - page);
 	if (size <= off+count) *eof = 1;
@@ -374,106 +77,6 @@
 	return_VALUE(size);
 }
 
-static int acpi_system_open_event(struct inode *inode, struct file *file);
-static ssize_t acpi_system_read_event (struct file*, char*, size_t, loff_t*);
-static int acpi_system_close_event(struct inode *inode, struct file *file);
-static unsigned int acpi_system_poll_event(struct file *file, poll_table *wait);
-
-
-static struct file_operations acpi_system_event_ops = {
-	.open =		acpi_system_open_event,
-	.read =		acpi_system_read_event,
-	.release =	acpi_system_close_event,
-	.poll =		acpi_system_poll_event,
-};
-
-static int
-acpi_system_open_event(struct inode *inode, struct file *file)
-{
-	spin_lock_irq (&acpi_system_event_lock);
-
-	if(event_is_open)
-		goto out_busy;
-
-	event_is_open = 1;
-
-	spin_unlock_irq (&acpi_system_event_lock);
-	return 0;
-
-out_busy:
-	spin_unlock_irq (&acpi_system_event_lock);
-	return -EBUSY;
-}
-
-static ssize_t
-acpi_system_read_event (
-	struct file		*file,
-	char			*buffer,
-	size_t			count,
-	loff_t			*ppos)
-{
-	int			result = 0;
-	struct acpi_bus_event	event;
-	static char		str[ACPI_MAX_STRING];
-	static int		chars_remaining = 0;
-	static char		*ptr;
-
-
-	ACPI_FUNCTION_TRACE("acpi_system_read_event");
-
-	if (!chars_remaining) {
-		memset(&event, 0, sizeof(struct acpi_bus_event));
-
-		if ((file->f_flags & O_NONBLOCK)
-		    && (list_empty(&acpi_bus_event_list)))
-			return_VALUE(-EAGAIN);
-
-		result = acpi_bus_receive_event(&event);
-		if (result) {
-			return_VALUE(-EIO);
-		}
-
-		chars_remaining = sprintf(str, "%s %s %08x %08x\n", 
-			event.device_class?event.device_class:"<unknown>",
-			event.bus_id?event.bus_id:"<unknown>", 
-			event.type, event.data);
-		ptr = str;
-	}
-
-	if (chars_remaining < count) {
-		count = chars_remaining;
-	}
-
-	if (copy_to_user(buffer, ptr, count))
-		return_VALUE(-EFAULT);
-
-	*ppos += count;
-	chars_remaining -= count;
-	ptr += count;
-
-	return_VALUE(count);
-}
-
-static int
-acpi_system_close_event(struct inode *inode, struct file *file)
-{
-	spin_lock_irq (&acpi_system_event_lock);
-	event_is_open = 0;
-	spin_unlock_irq (&acpi_system_event_lock);
-	return 0;
-}
-
-static unsigned int
-acpi_system_poll_event(
-	struct file		*file,
-	poll_table		*wait)
-{
-	poll_wait(file, &acpi_bus_event_queue, wait);
-	if (!list_empty(&acpi_bus_event_list))
-		return POLLIN | POLLRDNORM;
-	return 0;
-}
-
 static ssize_t acpi_system_read_dsdt (struct file*, char*, size_t, loff_t*);
 
 static struct file_operations acpi_system_dsdt_ops = {
@@ -560,732 +163,54 @@
 }
 
 
-#ifdef ACPI_DEBUG
-
-static int
-acpi_system_read_debug (
-	char			*page,
-	char			**start,
-	off_t			off,
-	int 			count,
-	int 			*eof,
-	void			*data)
-{
-	char			*p = page;
-	int 			size = 0;
-
-	if (off != 0)
-		goto end;
-
-	switch ((unsigned long) data) {
-	case 0:
-		p += sprintf(p, "0x%08x\n", acpi_dbg_layer);
-		break;
-	case 1:
-		p += sprintf(p, "0x%08x\n", acpi_dbg_level);
-		break;
-	default:
-		p += sprintf(p, "Invalid debug option\n");
-		break;
-	}
-	
-end:
-	size = (p - page);
-	if (size <= off+count) *eof = 1;
-	*start = page + off;
-	size -= off;
-	if (size>count) size = count;
-	if (size<0) size = 0;
-
-	return size;
-}
-
-
-static int
-acpi_system_write_debug (
-	struct file             *file,
-        const char              *buffer,
-	unsigned long           count,
-        void                    *data)
-{
-	char			debug_string[12] = {'\0'};
-
-	ACPI_FUNCTION_TRACE("acpi_system_write_debug");
-
-	if (count > sizeof(debug_string) - 1)
-		return_VALUE(-EINVAL);
-
-	if (copy_from_user(debug_string, buffer, count))
-		return_VALUE(-EFAULT);
-
-	debug_string[count] = '\0';
-
-	switch ((unsigned long) data) {
-	case 0:
-		acpi_dbg_layer = simple_strtoul(debug_string, NULL, 0);
-		break;
-	case 1:
-		acpi_dbg_level = simple_strtoul(debug_string, NULL, 0);
-		break;
-	default:
-		return_VALUE(-EINVAL);
-	}
-
-	return_VALUE(count);
-}
-
-#endif /* ACPI_DEBUG */
-
-
-#ifdef CONFIG_ACPI_SLEEP
-
-static int
-acpi_system_read_sleep (
-        char                    *page,
-        char                    **start,
-        off_t                   off,
-        int                     count,
-        int                     *eof,
-        void                    *data)
-{
-	struct acpi_system	*system = (struct acpi_system *) data;
-	char			*p = page;
-	int			size;
-	int			i;
-
-	ACPI_FUNCTION_TRACE("acpi_system_read_sleep");
-
-	if (!system || (off != 0))
-		goto end;
-
-	for (i = 0; i <= ACPI_STATE_S5; i++) {
-		if (system->states[i])
-			p += sprintf(p,"S%d ", i);
-	}
-
-	p += sprintf(p, "\n");
-
-end:
-	size = (p - page);
-	if (size <= off+count) *eof = 1;
-	*start = page + off;
-	size -= off;
-	if (size>count) size = count;
-	if (size<0) size = 0;
-
-	return_VALUE(size);
-}
-
-
-static int
-acpi_system_write_sleep (
-	struct file		*file,
-	const char		*buffer,
-	unsigned long		count,
-	void			*data)
-{
-	acpi_status		status = AE_OK;
-	struct acpi_system	*system = (struct acpi_system *) data;
-	char			state_string[12] = {'\0'};
-	u32			state = 0;
-
-	ACPI_FUNCTION_TRACE("acpi_system_write_sleep");
-
-	if (!system || (count > sizeof(state_string) - 1))
-		return_VALUE(-EINVAL);
-
-	if (copy_from_user(state_string, buffer, count))
-		return_VALUE(-EFAULT);
-	
-	state_string[count] = '\0';
-	
-	state = simple_strtoul(state_string, NULL, 0);
-	
-	if (!system->states[state])
-		return_VALUE(-ENODEV);
-
-	
-#ifdef CONFIG_SOFTWARE_SUSPEND
-	if (state == 4) {
-		software_suspend();
-		return_VALUE(count);
-	}
-#endif
-	status = acpi_suspend(state);
-
-	if (ACPI_FAILURE(status))
-		return_VALUE(-ENODEV);
-	
-	return_VALUE(count);
-}
-
-
-static int
-acpi_system_read_alarm (
-	char                    *page,
-	char                    **start,
-	off_t                   off,
-	int                     count,
-	int                     *eof,
-	void                    *context)
-{
-	char			*p = page;
-	int			size = 0;
-	u32			sec, min, hr;
-	u32			day, mo, yr;
-
-	ACPI_FUNCTION_TRACE("acpi_system_read_alarm");
-
-	if (off != 0)
-		goto end;
-
-	spin_lock(&rtc_lock);
-
-	sec = CMOS_READ(RTC_SECONDS_ALARM);
-	min = CMOS_READ(RTC_MINUTES_ALARM);
-	hr = CMOS_READ(RTC_HOURS_ALARM);
-
-#if 0	/* If we ever get an FACP with proper values... */
-	if (acpi_gbl_FADT->day_alrm)
-		day = CMOS_READ(acpi_gbl_FADT->day_alrm);
-	else
-		day =  CMOS_READ(RTC_DAY_OF_MONTH);
-	if (acpi_gbl_FADT->mon_alrm)
-		mo = CMOS_READ(acpi_gbl_FADT->mon_alrm);
-	else
-		mo = CMOS_READ(RTC_MONTH);;
-	if (acpi_gbl_FADT->century)
-		yr = CMOS_READ(acpi_gbl_FADT->century) * 100 + CMOS_READ(RTC_YEAR);
-	else
-		yr = CMOS_READ(RTC_YEAR);
-#else
-	day = CMOS_READ(RTC_DAY_OF_MONTH);
-	mo = CMOS_READ(RTC_MONTH);
-	yr = CMOS_READ(RTC_YEAR);
-#endif
-
-	spin_unlock(&rtc_lock);
-
-	BCD_TO_BIN(sec);
-	BCD_TO_BIN(min);
-	BCD_TO_BIN(hr);
-	BCD_TO_BIN(day);
-	BCD_TO_BIN(mo);
-	BCD_TO_BIN(yr);
-
-#if 0
-	/* we're trusting the FADT (see above)*/
-#else
-	/* If we're not trusting the FADT, we should at least make it
-	 * right for _this_ century... ehm, what is _this_ century?
-	 *
-	 * TBD:
-	 *  ASAP: find piece of code in the kernel, e.g. star tracker driver,
-	 *        which we can trust to determine the century correctly. Atom
-	 *        watch driver would be nice, too...
-	 *
-	 *  if that has not happened, change for first release in 2050:
- 	 *        if (yr<50)
-	 *                yr += 2100;
-	 *        else
-	 *                yr += 2000;   // current line of code
-	 *
-	 *  if that has not happened either, please do on 2099/12/31:23:59:59
-	 *        s/2000/2100
-	 *
-	 */
-	yr += 2000;
-#endif
-
-	p += sprintf(p,"%4.4u-", yr);
-	p += (mo > 12)  ? sprintf(p, "**-")  : sprintf(p, "%2.2u-", mo);
-	p += (day > 31) ? sprintf(p, "** ")  : sprintf(p, "%2.2u ", day);
-	p += (hr > 23)  ? sprintf(p, "**:")  : sprintf(p, "%2.2u:", hr);
-	p += (min > 59) ? sprintf(p, "**:")  : sprintf(p, "%2.2u:", min);
-	p += (sec > 59) ? sprintf(p, "**\n") : sprintf(p, "%2.2u\n", sec);
-
- end:
-	size = p - page;
-	if (size < count) *eof = 1;
-	else if (size > count) size = count;
-	if (size < 0) size = 0;
-	*start = page;
-
-	return_VALUE(size);
-}
-
-
-static int
-get_date_field (
-	char			**p,
-	u32			*value)
-{
-	char			*next = NULL;
-	char			*string_end = NULL;
-	int			result = -EINVAL;
-
-	/*
-	 * Try to find delimeter, only to insert null.  The end of the
-	 * string won't have one, but is still valid.
-	 */
-	next = strpbrk(*p, "- :");
-	if (next)
-		*next++ = '\0';
-
-	*value = simple_strtoul(*p, &string_end, 10);
-
-	/* Signal success if we got a good digit */
-	if (string_end != *p)
-		result = 0;
-
-	if (next)
-		*p = next;
-
-	return result;
-}
-
-
-static int
-acpi_system_write_alarm (
-	struct file		*file,
-	const char		*buffer,
-	unsigned long		count,
-	void			*data)
-{
-	int			result = 0;
-	char			alarm_string[30] = {'\0'};
-	char			*p = alarm_string;
-	u32			sec, min, hr, day, mo, yr;
-	int			adjust = 0;
-	unsigned char		rtc_control = 0;
-
-	ACPI_FUNCTION_TRACE("acpi_system_write_alarm");
-
-	if (count > sizeof(alarm_string) - 1)
-		return_VALUE(-EINVAL);
-	
-	if (copy_from_user(alarm_string, buffer, count))
-		return_VALUE(-EFAULT);
-
-	alarm_string[count] = '\0';
-
-	/* check for time adjustment */
-	if (alarm_string[0] == '+') {
-		p++;
-		adjust = 1;
-	}
-
-	if ((result = get_date_field(&p, &yr)))
-		goto end;
-	if ((result = get_date_field(&p, &mo)))
-		goto end;
-	if ((result = get_date_field(&p, &day)))
-		goto end;
-	if ((result = get_date_field(&p, &hr)))
-		goto end;
-	if ((result = get_date_field(&p, &min)))
-		goto end;
-	if ((result = get_date_field(&p, &sec)))
-		goto end;
-
-	if (sec > 59) {
-		min += 1;
-		sec -= 60;
-	}
-	if (min > 59) {
-		hr += 1;
-		min -= 60;
-	}
-	if (hr > 23) {
-		day += 1;
-		hr -= 24;
-	}
-	if (day > 31) {
-		mo += 1;
-		day -= 31;
-	}
-	if (mo > 12) {
-		yr += 1;
-		mo -= 12;
-	}
-
-	spin_lock_irq(&rtc_lock);
-
-	rtc_control = CMOS_READ(RTC_CONTROL);
-	if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-		BIN_TO_BCD(yr);
-		BIN_TO_BCD(mo);
-		BIN_TO_BCD(day);
-		BIN_TO_BCD(hr);
-		BIN_TO_BCD(min);
-		BIN_TO_BCD(sec);
-	}
-
-	if (adjust) {
-		yr  += CMOS_READ(RTC_YEAR);
-		mo  += CMOS_READ(RTC_MONTH);
-		day += CMOS_READ(RTC_DAY_OF_MONTH);
-		hr  += CMOS_READ(RTC_HOURS);
-		min += CMOS_READ(RTC_MINUTES);
-		sec += CMOS_READ(RTC_SECONDS);
-	}
-
-	spin_unlock_irq(&rtc_lock);
-
-	if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-		BCD_TO_BIN(yr);
-		BCD_TO_BIN(mo);
-		BCD_TO_BIN(day);
-		BCD_TO_BIN(hr);
-		BCD_TO_BIN(min);
-		BCD_TO_BIN(sec);
-	}
-
-	if (sec > 59) {
-		min++;
-		sec -= 60;
-	}
-	if (min > 59) {
-		hr++;
-		min -= 60;
-	}
-	if (hr > 23) {
-		day++;
-		hr -= 24;
-	}
-	if (day > 31) {
-		mo++;
-		day -= 31;
-	}
-	if (mo > 12) {
-		yr++;
-		mo -= 12;
-	}
-	if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
-		BIN_TO_BCD(yr);
-		BIN_TO_BCD(mo);
-		BIN_TO_BCD(day);
-		BIN_TO_BCD(hr);
-		BIN_TO_BCD(min);
-		BIN_TO_BCD(sec);
-	}
-
-	spin_lock_irq(&rtc_lock);
-
-	/* write the fields the rtc knows about */
-	CMOS_WRITE(hr, RTC_HOURS_ALARM);
-	CMOS_WRITE(min, RTC_MINUTES_ALARM);
-	CMOS_WRITE(sec, RTC_SECONDS_ALARM);
-
-	/*
-	 * If the system supports an enhanced alarm it will have non-zero
-	 * offsets into the CMOS RAM here -- which for some reason are pointing
-	 * to the RTC area of memory.
-	 */
-#if 0
-	if (acpi_gbl_FADT->day_alrm)
-		CMOS_WRITE(day, acpi_gbl_FADT->day_alrm);
-	if (acpi_gbl_FADT->mon_alrm)
-		CMOS_WRITE(mo, acpi_gbl_FADT->mon_alrm);
-	if (acpi_gbl_FADT->century)
-		CMOS_WRITE(yr/100, acpi_gbl_FADT->century);
-#endif
-	/* enable the rtc alarm interrupt */
-	if (!(rtc_control & RTC_AIE)) {
-		rtc_control |= RTC_AIE;
-		CMOS_WRITE(rtc_control,RTC_CONTROL);
-		CMOS_READ(RTC_INTR_FLAGS);
-	}
-
-	spin_unlock_irq(&rtc_lock);
-
-	acpi_set_register(ACPI_BITREG_RT_CLOCK_ENABLE, 1, ACPI_MTX_LOCK);
-
-	file->f_pos += count;
-
-	result = 0;
-end:
-	return_VALUE(result ? result : count);
-}
-
-#endif /*CONFIG_ACPI_SLEEP*/
-
-
-static int
-acpi_system_add_fs (
-	struct acpi_device	*device)
+static int __init acpi_system_init (void)
 {
-	struct proc_dir_entry	*entry = NULL;
+	struct proc_dir_entry	*entry;
+	int error = 0;
+	char * name;
 
-	ACPI_FUNCTION_TRACE("acpi_system_add_fs");
+	ACPI_FUNCTION_TRACE("acpi_system_init");
 
-	if (!device)
-		return_VALUE(-EINVAL);
+	if (acpi_disabled)
+		return_VALUE(0);
 
 	/* 'info' [R] */
-	entry = create_proc_entry(ACPI_SYSTEM_FILE_INFO,
-		S_IRUGO, acpi_device_dir(device));
+	name = ACPI_SYSTEM_FILE_INFO;
+	entry = create_proc_read_entry(name,
+		S_IRUGO, acpi_root_dir, acpi_system_read_info,NULL);
 	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-			"Unable to create '%s' fs entry\n",
-			ACPI_SYSTEM_FILE_INFO));
-	else {
-		entry->read_proc = acpi_system_read_info;
-		entry->data = acpi_driver_data(device);
-	}
+		goto Error;
 
 	/* 'dsdt' [R] */
-	entry = create_proc_entry(ACPI_SYSTEM_FILE_DSDT,
-		S_IRUSR, acpi_device_dir(device));
-	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-			"Unable to create '%s' fs entry\n",
-			ACPI_SYSTEM_FILE_DSDT));
-	else
+	name = ACPI_SYSTEM_FILE_DSDT;
+	entry = create_proc_entry(name, S_IRUSR, acpi_root_dir);
+	if (entry)
 		entry->proc_fops = &acpi_system_dsdt_ops;
+	else 
+		goto Error;
 
 	/* 'fadt' [R] */
-	entry = create_proc_entry(ACPI_SYSTEM_FILE_FADT,
-		S_IRUSR, acpi_device_dir(device));
-	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-			"Unable to create '%s' fs entry\n",
-			ACPI_SYSTEM_FILE_FADT));
-	else
+	name = ACPI_SYSTEM_FILE_FADT;
+	entry = create_proc_entry(name, S_IRUSR, acpi_root_dir);
+	if (entry)
 		entry->proc_fops = &acpi_system_fadt_ops;
-
-	/* 'event' [R] */
-	entry = create_proc_entry(ACPI_SYSTEM_FILE_EVENT,
-		S_IRUSR, acpi_device_dir(device));
-	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-			"Unable to create '%s' fs entry\n",
-			ACPI_SYSTEM_FILE_EVENT));
 	else
-		entry->proc_fops = &acpi_system_event_ops;
+		goto Error;
 
-#ifdef CONFIG_ACPI_SLEEP
+ Done:
+	return_VALUE(error);
 
-	/* 'sleep' [R/W]*/
-	entry = create_proc_entry(ACPI_SYSTEM_FILE_SLEEP,
-		S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
-	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-			"Unable to create '%s' fs entry\n",
-			ACPI_SYSTEM_FILE_SLEEP));
-	else {
-		entry->read_proc = acpi_system_read_sleep;
-		entry->write_proc = acpi_system_write_sleep;
-		entry->data = acpi_driver_data(device);
-	}
+ Error:
+	ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 
+			 "Unable to create '%s' proc fs entry\n", name));
 
-	/* 'alarm' [R/W] */
-	entry = create_proc_entry(ACPI_SYSTEM_FILE_ALARM,
-		S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
-	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-			"Unable to create '%s' fs entry\n",
-			ACPI_SYSTEM_FILE_ALARM));
-	else {
-		entry->read_proc = acpi_system_read_alarm;
-		entry->write_proc = acpi_system_write_alarm;
-		entry->data = acpi_driver_data(device);
-	}
+	remove_proc_entry(ACPI_SYSTEM_FILE_FADT, acpi_root_dir);
+	remove_proc_entry(ACPI_SYSTEM_FILE_DSDT, acpi_root_dir);
+	remove_proc_entry(ACPI_SYSTEM_FILE_INFO, acpi_root_dir);
 
-#endif /*CONFIG_ACPI_SLEEP*/
-
-#ifdef ACPI_DEBUG
-
-	/* 'debug_layer' [R/W] */
-	entry = create_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LAYER,
-		S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
-	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-			"Unable to create '%s' fs entry\n",
-			ACPI_SYSTEM_FILE_DEBUG_LAYER));
-	else {
-		entry->read_proc  = acpi_system_read_debug;
-		entry->write_proc = acpi_system_write_debug;
-		entry->data = (void *) 0;
-	}
-
-	/* 'debug_level' [R/W] */
-	entry = create_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LEVEL,
-		S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
-	if (!entry)
-		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-			"Unable to create '%s' fs entry\n",
-			ACPI_SYSTEM_FILE_DEBUG_LEVEL));
-	else {
-		entry->read_proc  = acpi_system_read_debug;
-		entry->write_proc = acpi_system_write_debug;
-		entry->data = (void *) 1;
-	}
-
-#endif /*ACPI_DEBUG*/
-
-	return_VALUE(0);
+	error = -EFAULT;
+	goto Done;
 }
 
 
-static int
-acpi_system_remove_fs (
-	struct acpi_device	*device)
-{
-	ACPI_FUNCTION_TRACE("acpi_system_remove_fs");
-
-	if (!device)
-		return_VALUE(-EINVAL);
-
-	remove_proc_entry(ACPI_SYSTEM_FILE_INFO, acpi_device_dir(device));
-	remove_proc_entry(ACPI_SYSTEM_FILE_DSDT, acpi_device_dir(device));
-	remove_proc_entry(ACPI_SYSTEM_FILE_EVENT, acpi_device_dir(device));
-#ifdef CONFIG_ACPI_SLEEP
-	remove_proc_entry(ACPI_SYSTEM_FILE_SLEEP, acpi_device_dir(device));
-	remove_proc_entry(ACPI_SYSTEM_FILE_ALARM, acpi_device_dir(device));
-#endif
-#ifdef ACPI_DEBUG
-	remove_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LAYER,
-		acpi_device_dir(device));
-	remove_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LEVEL,
-		acpi_device_dir(device));
-#endif
-
-	return_VALUE(0);
-}
-
-
-/* --------------------------------------------------------------------------
-                                 Driver Interface
-   -------------------------------------------------------------------------- */
-
-#if defined(CONFIG_MAGIC_SYSRQ) && defined(CONFIG_PM)
-
-/* Simple wrapper calling power down function. */
-static void acpi_sysrq_power_off(int key, struct pt_regs *pt_regs,
-	struct tty_struct *tty)
-{
-	acpi_power_off();
-}
-
-struct sysrq_key_op sysrq_acpi_poweroff_op = {
-	.handler =	&acpi_sysrq_power_off,
-	.help_msg =	"Off",
-	.action_msg =	"Power Off\n"
-};
-
-#endif  /* CONFIG_MAGIC_SYSRQ */
-
-static int
-acpi_system_add (
-	struct acpi_device	*device)
-{
-	int			result = 0;
-	acpi_status		status = AE_OK;
-	struct acpi_system	*system = NULL;
-	u8			i = 0;
-
-	ACPI_FUNCTION_TRACE("acpi_system_add");
-
-	if (!device)
-		return_VALUE(-EINVAL);
-
-	system = kmalloc(sizeof(struct acpi_system), GFP_KERNEL);
-	if (!system)
-		return_VALUE(-ENOMEM);
-	memset(system, 0, sizeof(struct acpi_system));
-
-	system->handle = device->handle;
-	sprintf(acpi_device_name(device), "%s", ACPI_SYSTEM_DEVICE_NAME);
-	sprintf(acpi_device_class(device), "%s", ACPI_SYSTEM_CLASS);
-	acpi_driver_data(device) = system;
-
-	result = acpi_system_add_fs(device);
-	if (result)
-		goto end;
-
-	printk(KERN_INFO PREFIX "%s [%s] (supports", 
-		acpi_device_name(device), acpi_device_bid(device));
-	for (i=0; i<ACPI_S_STATE_COUNT; i++) {
-		u8 type_a, type_b;
-		status = acpi_get_sleep_type_data(i, &type_a, &type_b);
-		if (ACPI_SUCCESS(status)) {
-			system->states[i] = 1;
-			printk(" S%d", i);
-		}
-	}
-	printk(")\n");
-
-#ifdef CONFIG_PM
-	/* Install the soft-off (S5) handler. */
-	if (system->states[ACPI_STATE_S5]) {
-		pm_power_off = acpi_power_off;
-		register_sysrq_key('o', &sysrq_acpi_poweroff_op);
-
-		/* workaround: some systems don't claim S4 support, but they
-                   do support S5 (power-down). That is all we need, so
-		   indicate support. */
-		system->states[ACPI_STATE_S4] = 1;
-	}
-#endif
-
-end:
-	if (result)
-		kfree(system);
-
-	return_VALUE(result);
-}
-
-
-static int
-acpi_system_remove (
-	struct acpi_device	*device,
-	int			type)
-{
-	struct acpi_system	*system = NULL;
-
-	ACPI_FUNCTION_TRACE("acpi_system_remove");
-
-	if (!device || !acpi_driver_data(device))
-		return_VALUE(-EINVAL);
-
-	system = (struct acpi_system *) acpi_driver_data(device);
-
-#ifdef CONFIG_PM
-	/* Remove the soft-off (S5) handler. */
-	if (system->states[ACPI_STATE_S5]) {
-		unregister_sysrq_key('o', &sysrq_acpi_poweroff_op);
-		pm_power_off = NULL;
-	}
-#endif
-
-	acpi_system_remove_fs(device);
-
-	kfree(system);
-
-	return 0;
-}
-
-
-int __init
-acpi_system_init (void)
-{
-	int			result = 0;
-
-	ACPI_FUNCTION_TRACE("acpi_system_init");
-
-	result = acpi_bus_register_driver(&acpi_system_driver);
-	if (result < 0)
-		return_VALUE(-ENODEV);
-
-	return_VALUE(0);
-}
-
-
-void __exit
-acpi_system_exit (void)
-{
-	ACPI_FUNCTION_TRACE("acpi_system_exit");
-	acpi_bus_unregister_driver(&acpi_system_driver);
-	return_VOID;
-}
+subsys_initcall(acpi_system_init);
diff -Nru a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c
--- a/drivers/acpi/tables/tbget.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/acpi/tables/tbget.c	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: tbget - ACPI Table get* routines
- *              $Revision: 79 $
+ *              $Revision: 80 $
  *
  *****************************************************************************/
 
@@ -129,8 +129,10 @@
 		status = acpi_os_map_memory (address->pointer.physical, sizeof (acpi_table_header),
 				  (void **) &header);
 		if (ACPI_FAILURE (status)) {
-			ACPI_REPORT_ERROR (("Could not map memory at %p for length %X\n",
-				address->pointer.physical, sizeof (acpi_table_header)));
+			ACPI_REPORT_ERROR (("Could not map memory at %8.8X%8.8X for length %X\n",
+				ACPI_HIDWORD (address->pointer.physical),
+				ACPI_LODWORD (address->pointer.physical),
+				sizeof (acpi_table_header)));
 			return_ACPI_STATUS (status);
 		}
 
@@ -343,8 +345,10 @@
 		status = acpi_os_map_memory (address->pointer.physical, (ACPI_SIZE) header->length,
 				  (void **) &full_table);
 		if (ACPI_FAILURE (status)) {
-			ACPI_REPORT_ERROR (("Could not map memory for table [%4.4s] at %p for length %X\n",
-				header->signature, address->pointer.physical, header->length));
+			ACPI_REPORT_ERROR (("Could not map memory for table [%4.4s] at %8.8X%8.8X for length %X\n",
+				header->signature,
+				ACPI_HIDWORD (address->pointer.physical),
+				ACPI_LODWORD (address->pointer.physical), header->length));
 			return (status);
 		}
 
diff -Nru a/drivers/acpi/tables.c b/drivers/acpi/tables.c
--- a/drivers/acpi/tables.c	Fri Sep 20 08:20:44 2002
+++ b/drivers/acpi/tables.c	Fri Sep 20 08:20:44 2002
@@ -46,7 +46,7 @@
 	[ACPI_DSDT]		= "DSDT",
 	[ACPI_ECDT]		= "ECDT",
 	[ACPI_ETDT]		= "ETDT",
-	[ACPI_FACP]		= "FACP",
+	[ACPI_FADT]		= "FACP",
 	[ACPI_FACS]		= "FACS",
 	[ACPI_OEMX]		= "OEM",
 	[ACPI_PSDT]		= "PSDT",
@@ -71,9 +71,6 @@
 
 static struct acpi_table_sdt	sdt;
 
-acpi_madt_entry_handler		madt_handlers[ACPI_MADT_ENTRY_COUNT];
-
-
 void
 acpi_table_print (
 	struct acpi_table_header *header,
@@ -92,7 +89,7 @@
 		name = "MADT";
 	}
 	else if (!strncmp((char *) &header->signature,
-		acpi_table_signatures[ACPI_FACP],
+		acpi_table_signatures[ACPI_FADT],
 		sizeof(header->signature))) {
 		name = "FADT";
 	}
@@ -222,6 +219,56 @@
 	return (sum & 0xFF);
 }
 
+int __init
+acpi_get_table_header_early (
+	enum acpi_table_id	id,
+	struct acpi_table_header **header)
+{
+	int i;
+	enum acpi_table_id temp_id;
+
+	/* DSDT is different from the rest */
+	if (id == ACPI_DSDT)
+		temp_id = ACPI_FADT;
+	else
+		temp_id = id;
+
+	/* Locate the table. */
+
+	for (i = 0; i < sdt.count; i++) {
+		if (sdt.entry[i].id != temp_id)
+			continue;
+		*header = (void *)
+			__acpi_map_table(sdt.entry[i].pa, sdt.entry[i].size);
+		if (!*header) {
+			printk(KERN_WARNING PREFIX "Unable to map %s\n",
+			       acpi_table_signatures[temp_id]);
+			return -ENODEV;
+		}
+		break;
+	}
+
+	if (!*header) {
+		printk(KERN_WARNING PREFIX "%s not present\n",
+		       acpi_table_signatures[id]);
+		return -ENODEV;
+	}
+
+	/* Map the DSDT header via the pointer in the FADT */
+	if (id == ACPI_DSDT) {
+		struct acpi_table_fadt *fadt = (struct acpi_table_fadt *) *header;
+
+		*header = (void *) __acpi_map_table(fadt->dsdt_addr,
+				sizeof(struct acpi_table_header));
+		if (!*header) {
+			printk(KERN_WARNING PREFIX "Unable to map DSDT\n");
+			return -ENODEV;
+		}
+	}
+
+	return 0;
+}
+	 
 
 int __init
 acpi_table_parse_madt_family (
@@ -447,6 +494,15 @@
 		}
 	}
 
+	/* 
+	 * The DSDT is *not* in the RSDT (why not? no idea.) but we want
+	 * to print its info, because this is what people usually blacklist
+	 * against. Unfortunately, we don't know the phys_addr, so just
+	 * print 0. Maybe no one will notice.
+	 */
+	if(!acpi_get_table_header_early(ACPI_DSDT, &header))
+		acpi_table_print(header, 0);
+
 	return 0;
 }
 
@@ -460,7 +516,6 @@
 	int			result = 0;
 
 	memset(&sdt, 0, sizeof(struct acpi_table_sdt));
-	memset(&madt_handlers, 0, sizeof(madt_handlers));
 
 	/* Locate and map the Root System Description Table (RSDP) */
 
diff -Nru a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
--- a/drivers/acpi/thermal.c	Fri Sep 20 08:20:44 2002
+++ b/drivers/acpi/thermal.c	Fri Sep 20 08:20:44 2002
@@ -54,8 +54,23 @@
 MODULE_PARM(tzp, "i");
 MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.\n");
 
-#define PREFIX			"ACPI: "
-
+#define ACPI_THERMAL_COMPONENT		0x04000000
+#define ACPI_THERMAL_CLASS		"thermal_zone"
+#define ACPI_THERMAL_DRIVER_NAME	"ACPI Thermal Zone Driver"
+#define ACPI_THERMAL_DEVICE_NAME	"Thermal Zone"
+#define ACPI_THERMAL_FILE_STATE		"state"
+#define ACPI_THERMAL_FILE_TEMPERATURE	"temperature"
+#define ACPI_THERMAL_FILE_TRIP_POINTS	"trip_points"
+#define ACPI_THERMAL_FILE_COOLING_MODE	"cooling_mode"
+#define ACPI_THERMAL_FILE_POLLING_FREQ	"polling_frequency"
+#define ACPI_THERMAL_NOTIFY_TEMPERATURE	0x80
+#define ACPI_THERMAL_NOTIFY_THRESHOLDS	0x81
+#define ACPI_THERMAL_NOTIFY_DEVICES	0x82
+#define ACPI_THERMAL_NOTIFY_CRITICAL	0xF0
+#define ACPI_THERMAL_NOTIFY_HOT		0xF1
+#define ACPI_THERMAL_MODE_ACTIVE	0x00
+#define ACPI_THERMAL_MODE_PASSIVE	0x01
+#define ACPI_THERMAL_PATH_POWEROFF	"/sbin/poweroff"
 
 #define ACPI_THERMAL_MAX_ACTIVE	10
 
diff -Nru a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c
--- a/drivers/acpi/utilities/utcopy.c	Fri Sep 20 08:20:45 2002
+++ b/drivers/acpi/utilities/utcopy.c	Fri Sep 20 08:20:45 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: utcopy - Internal to external object translation utilities
- *              $Revision: 103 $
+ *              $Revision: 104 $
  *
  *****************************************************************************/
 
@@ -25,7 +25,6 @@
 
 
 #include "acpi.h"
-#include "acnamesp.h"
 #include "amlcode.h"
 
 
diff -Nru a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c
--- a/drivers/acpi/utilities/utdebug.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/acpi/utilities/utdebug.c	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: utdebug - Debug print routines
- *              $Revision: 104 $
+ *              $Revision: 105 $
  *
  *****************************************************************************/
 
@@ -152,7 +152,7 @@
 	acpi_os_printf ("%8s-%04ld ", dbg_info->module_name, line_number);
 
 	if (ACPI_LV_THREADS & acpi_dbg_level) {
-		acpi_os_printf ("[%04lX] ", thread_id, acpi_gbl_nesting_level, dbg_info->proc_name);
+		acpi_os_printf ("[%04lX] ", thread_id);
 	}
 
 	acpi_os_printf ("[%02ld] %-22.22s: ", acpi_gbl_nesting_level, dbg_info->proc_name);
@@ -516,7 +516,7 @@
 	while (i < count) {
 		/* Print current offset */
 
-		acpi_os_printf ("%05X  ", i);
+		acpi_os_printf ("%05X  ", (u32) i);
 
 		/* Print 16 hex chars */
 
diff -Nru a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c
--- a/drivers/acpi/utilities/utglobal.c	Fri Sep 20 08:20:42 2002
+++ b/drivers/acpi/utilities/utglobal.c	Fri Sep 20 08:20:42 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: utglobal - Global variables for the ACPI subsystem
- *              $Revision: 170 $
+ *              $Revision: 171 $
  *
  *****************************************************************************/
 
@@ -27,7 +27,6 @@
 
 #include "acpi.h"
 #include "acnamesp.h"
-#include "amlcode.h"
 
 #define _COMPONENT          ACPI_UTILITIES
 	 ACPI_MODULE_NAME    ("utglobal")
diff -Nru a/drivers/acpi/utilities/utinit.c b/drivers/acpi/utilities/utinit.c
--- a/drivers/acpi/utilities/utinit.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/acpi/utilities/utinit.c	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,7 @@
 /******************************************************************************
  *
  * Module Name: utinit - Common ACPI subsystem initialization
- *              $Revision: 113 $
+ *              $Revision: 114 $
  *
  *****************************************************************************/
 
@@ -56,7 +56,7 @@
 
 	ACPI_REPORT_WARNING (
 		("Invalid FADT value %s=%X at offset %X FADT=%p\n",
-		register_name, value, offset, acpi_gbl_FADT));
+		register_name, value, (u32) offset, acpi_gbl_FADT));
 }
 
 
diff -Nru a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c
--- a/drivers/acpi/utilities/utmisc.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/acpi/utilities/utmisc.c	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,7 @@
 /*******************************************************************************
  *
  * Module Name: utmisc - common utility procedures
- *              $Revision: 80 $
+ *              $Revision: 81 $
  *
  ******************************************************************************/
 
@@ -26,8 +26,6 @@
 
 #include "acpi.h"
 #include "acnamesp.h"
-#include "amlcode.h"
-#include "acinterp.h"
 
 
 #define _COMPONENT          ACPI_UTILITIES
diff -Nru a/drivers/base/Makefile b/drivers/base/Makefile
--- a/drivers/base/Makefile	Fri Sep 20 08:20:44 2002
+++ b/drivers/base/Makefile	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,7 @@
 # Makefile for the Linux device tree
 
 obj-y		:= core.o sys.o interface.o power.o bus.o \
-			driver.o class.o intf.o
+			driver.o class.o intf.o platform.o
 
 obj-y		+= fs/
 
diff -Nru a/drivers/base/core.c b/drivers/base/core.c
--- a/drivers/base/core.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/base/core.c	Fri Sep 20 08:20:41 2002
@@ -97,15 +97,10 @@
 
 static void device_detach(struct device * dev)
 {
-	struct device_driver * drv; 
+	struct device_driver * drv = dev->driver;
 
-	if (dev->driver) {
+	if (drv) {
 		devclass_remove_device(dev);
-		spin_lock(&device_lock);
-		drv = dev->driver;
-		spin_unlock(&device_lock);
-
-		/* detach from driver */
 		if (drv && drv->remove)
 			drv->remove(dev);
 
diff -Nru a/drivers/base/platform.c b/drivers/base/platform.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/base/platform.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,27 @@
+/*
+ * platform.c - platform 'psuedo' bus for legacy devices
+ *
+ * Please see Documentation/driver-model/platform.txt for more
+ * information.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+static int platform_match(struct device * dev, struct device_driver * drv)
+{
+	return 0;
+}
+
+struct bus_type platform_bus = {
+	.name		= "platform",
+	.match		= platform_match,
+};
+
+static int __init platform_bus_init(void)
+{
+	return bus_register(&platform_bus);
+}
+
+postcore_initcall(platform_bus_init);
diff -Nru a/drivers/base/power.c b/drivers/base/power.c
--- a/drivers/base/power.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/base/power.c	Fri Sep 20 08:20:41 2002
@@ -92,13 +92,13 @@
  */
 void device_shutdown(void)
 {
-	struct list_head * node;
+	struct list_head * node, * next;
 	struct device * prev = NULL;
 
 	printk(KERN_EMERG "Shutting down devices\n");
 
 	spin_lock(&device_lock);
-	list_for_each(node,&global_device_list) {
+	list_for_each_safe(node,next,&global_device_list) {
 		struct device * dev = get_device_locked(to_dev(node));
 		if (dev) {
 			spin_unlock(&device_lock);
@@ -111,6 +111,8 @@
 		}
 	}
 	spin_unlock(&device_lock);
+	if (prev)
+		put_device(prev);
 }
 
 EXPORT_SYMBOL(device_suspend);
diff -Nru a/drivers/block/DAC960.c b/drivers/block/DAC960.c
--- a/drivers/block/DAC960.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/block/DAC960.c	Fri Sep 20 08:20:47 2002
@@ -2909,10 +2909,8 @@
 static inline void DAC960_ProcessCompletedBuffer(BufferHeader_T *BufferHeader,
 						 boolean SuccessfulIO)
 {
-  if (SuccessfulIO)
-    set_bit(BIO_UPTODATE, &BufferHeader->bi_flags);
+  bio_endio(BufferHeader, BufferHeader->bi_size, SuccessfulIO ? 0 : -EIO);
   blk_finished_io(bio_sectors(BufferHeader));
-  BufferHeader->bi_end_io(BufferHeader);
 }
 
 static inline int DAC960_PartitionByCommand(DAC960_Command_T *Command)
diff -Nru a/drivers/block/cciss.c b/drivers/block/cciss.c
--- a/drivers/block/cciss.c	Fri Sep 20 08:20:48 2002
+++ b/drivers/block/cciss.c	Fri Sep 20 08:20:48 2002
@@ -1567,10 +1567,11 @@
 {
 	while (bio) {
 		struct bio *xbh = bio->bi_next; 
+		int nr_sectors = bio_sectors(bio);
 
 		bio->bi_next = NULL; 
-		blk_finished_io(bio_sectors(bio));
-		bio_endio(bio, status);
+		blk_finished_io(len);
+		bio_endio(bio, nr_sectors << 9, status ? 0 : -EIO);
 		bio = xbh;
 	}
 
diff -Nru a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
--- a/drivers/block/cpqarray.c	Fri Sep 20 08:20:42 2002
+++ b/drivers/block/cpqarray.c	Fri Sep 20 08:20:42 2002
@@ -911,11 +911,13 @@
 {
 	struct bio *xbh;
 	while(bio) {
+		int nr_sectors = bio_sectors(bio);
+
 		xbh = bio->bi_next;
 		bio->bi_next = NULL;
 		
-		blk_finished_io(bio_sectors(bio));
-		bio_endio(bio, ok);
+		blk_finished_io(nr_sectors);
+		bio_endio(bio, nr_sectors << 9, ok ? 0 : -EIO);
 
 		bio = xbh;
 	}
diff -Nru a/drivers/block/floppy.c b/drivers/block/floppy.c
--- a/drivers/block/floppy.c	Fri Sep 20 08:20:43 2002
+++ b/drivers/block/floppy.c	Fri Sep 20 08:20:43 2002
@@ -3846,9 +3846,13 @@
  * a disk in the drive, and whether that disk is writable.
  */
 
-static void floppy_rb0_complete(struct bio *bio)
+static int floppy_rb0_complete(struct bio *bio, unsigned int bytes_done, int err)
 {
+	if (bio->bi_size)
+		return 1;
+
 	complete((struct completion*)bio->bi_private);
+	return 0;
 }
 
 static int __floppy_read_block_0(struct block_device *bdev)
diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
--- a/drivers/block/ll_rw_blk.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/block/ll_rw_blk.c	Fri Sep 20 08:20:41 2002
@@ -12,38 +12,21 @@
 /*
  * This handles all read/write requests to block devices
  */
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/kernel_stat.h>
-#include <linux/errno.h>
-#include <linux/string.h>
 #include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/backing-dev.h>
 #include <linux/bio.h>
+#include <linux/blk.h>
+#include <linux/highmem.h>
 #include <linux/mm.h>
-#include <linux/swap.h>
+#include <linux/kernel_stat.h>
+#include <linux/string.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
-#include <linux/bootmem.h>
+#include <linux/bootmem.h>	/* for max_pfn/max_low_pfn */
 #include <linux/completion.h>
-#include <linux/compiler.h>
-#include <linux/buffer_head.h>
-#include <scsi/scsi.h>
-#include <linux/backing-dev.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <linux/blk.h>
-#include <linux/highmem.h>
 #include <linux/slab.h>
-#include <linux/module.h>
-
-/*
- * MAC Floppy IWM hooks
- */
 
-#ifdef CONFIG_MAC_FLOPPY_IWM
-extern int mac_floppy_init(void);
-#endif
 
 /*
  * For the allocated request tables
@@ -53,7 +36,7 @@
 /*
  * plug management
  */
-static struct list_head blk_plug_list;
+static LIST_HEAD(blk_plug_list);
 static spinlock_t blk_plug_lock __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
 /* blk_dev_struct is:
@@ -221,6 +204,11 @@
  **/
 void blk_queue_max_sectors(request_queue_t *q, unsigned short max_sectors)
 {
+	if ((max_sectors << 9) < PAGE_CACHE_SIZE) {
+		max_sectors = 1 << (PAGE_CACHE_SHIFT - 9);
+		printk("%s: set to minimum %d\n", __FUNCTION__, max_sectors);
+	}
+
 	q->max_sectors = max_sectors;
 }
 
@@ -236,6 +224,11 @@
  **/
 void blk_queue_max_phys_segments(request_queue_t *q, unsigned short max_segments)
 {
+	if (!max_segments) {
+		max_segments = 1;
+		printk("%s: set to minimum %d\n", __FUNCTION__, max_segments);
+	}
+
 	q->max_phys_segments = max_segments;
 }
 
@@ -252,6 +245,11 @@
  **/
 void blk_queue_max_hw_segments(request_queue_t *q, unsigned short max_segments)
 {
+	if (!max_segments) {
+		max_segments = 1;
+		printk("%s: set to minimum %d\n", __FUNCTION__, max_segments);
+	}
+
 	q->max_hw_segments = max_segments;
 }
 
@@ -266,6 +264,11 @@
  **/
 void blk_queue_max_segment_size(request_queue_t *q, unsigned int max_size)
 {
+	if (max_size < PAGE_CACHE_SIZE) {
+		max_size = PAGE_CACHE_SIZE;
+		printk("%s: set to minimum %d\n", __FUNCTION__, max_size);
+	}
+
 	q->max_segment_size = max_size;
 }
 
@@ -292,6 +295,11 @@
  **/
 void blk_queue_segment_boundary(request_queue_t *q, unsigned long mask)
 {
+	if (mask < PAGE_CACHE_SIZE - 1) {
+		mask = PAGE_CACHE_SIZE - 1;
+		printk("%s: set to minimum %lx\n", __FUNCTION__, mask);
+	}
+
 	q->seg_boundary_mask = mask;
 }
 
@@ -1568,10 +1576,8 @@
 		/*
 		 * READA bit set
 		 */
-		if (bio->bi_rw & (1 << BIO_RW_AHEAD)) {
-			set_bit(BIO_RW_BLOCK, &bio->bi_flags);
+		if (bio_flagged(bio, BIO_RW_AHEAD))
 			goto end_io;
-		}
 
 		freereq = get_request_wait(q, rw);
 		spin_lock_irq(q->queue_lock);
@@ -1608,7 +1614,7 @@
 	return 0;
 
 end_io:
-	bio->bi_end_io(bio);
+	bio_endio(bio, nr_sectors << 9, -EWOULDBLOCK);
 	return 0;
 }
 
@@ -1697,7 +1703,7 @@
 			       bdevname(bio->bi_bdev),
 			       (long long) bio->bi_sector);
 end_io:
-			bio->bi_end_io(bio);
+			bio_endio(bio, 0, -EIO);
 			break;
 		}
 
@@ -1715,17 +1721,6 @@
 	} while (ret);
 }
 
-/*
- * our default bio end_io callback handler for a buffer_head mapping.
- */
-static void end_bio_bh_io_sync(struct bio *bio)
-{
-	struct buffer_head *bh = bio->bi_private;
-
-	bh->b_end_io(bh, test_bit(BIO_UPTODATE, &bio->bi_flags));
-	bio_put(bio);
-}
-
 /**
  * submit_bio: submit a bio to the block device layer for I/O
  * @rw: whether to %READ or %WRITE, or maybe to %READA (read ahead)
@@ -1759,161 +1754,6 @@
 	return 1;
 }
 
-/**
- * submit_bh: submit a buffer_head to the block device layer for I/O
- * @rw: whether to %READ or %WRITE, or maybe to %READA (read ahead)
- * @bh: The &struct buffer_head which describes the I/O
- *
- **/
-int submit_bh(int rw, struct buffer_head * bh)
-{
-	struct bio *bio;
-
-	BUG_ON(!buffer_locked(bh));
-	BUG_ON(!buffer_mapped(bh));
-	BUG_ON(!bh->b_end_io);
-
-	if ((rw == READ || rw == READA) && buffer_uptodate(bh))
-		buffer_error();
-	if (rw == WRITE && !buffer_uptodate(bh))
-		buffer_error();
-	if (rw == READ && buffer_dirty(bh))
-		buffer_error();
-				
-	set_buffer_req(bh);
-
-	/*
-	 * from here on down, it's all bio -- do the initial mapping,
-	 * submit_bio -> generic_make_request may further map this bio around
-	 */
-	bio = bio_alloc(GFP_NOIO, 1);
-
-	bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9);
-	bio->bi_bdev = bh->b_bdev;
-	bio->bi_io_vec[0].bv_page = bh->b_page;
-	bio->bi_io_vec[0].bv_len = bh->b_size;
-	bio->bi_io_vec[0].bv_offset = bh_offset(bh);
-
-	bio->bi_vcnt = 1;
-	bio->bi_idx = 0;
-	bio->bi_size = bh->b_size;
-
-	bio->bi_end_io = end_bio_bh_io_sync;
-	bio->bi_private = bh;
-
-	return submit_bio(rw, bio);
-}
-
-/**
- * ll_rw_block: low-level access to block devices
- * @rw: whether to %READ or %WRITE or maybe %READA (readahead)
- * @nr: number of &struct buffer_heads in the array
- * @bhs: array of pointers to &struct buffer_head
- *
- * ll_rw_block() takes an array of pointers to &struct buffer_heads,
- * and requests an I/O operation on them, either a %READ or a %WRITE.
- * The third %READA option is described in the documentation for
- * generic_make_request() which ll_rw_block() calls.
- *
- * This function provides extra functionality that is not in
- * generic_make_request() that is relevant to buffers in the buffer
- * cache or page cache.  In particular it drops any buffer that it
- * cannot get a lock on (with the BH_Lock state bit), any buffer that
- * appears to be clean when doing a write request, and any buffer that
- * appears to be up-to-date when doing read request.  Further it marks
- * as clean buffers that are processed for writing (the buffer cache
- * wont assume that they are actually clean until the buffer gets
- * unlocked).
- *
- * ll_rw_block sets b_end_io to simple completion handler that marks
- * the buffer up-to-date (if approriate), unlocks the buffer and wakes
- * any waiters.  As client that needs a more interesting completion
- * routine should call submit_bh() (or generic_make_request())
- * directly.
- *
- * Caveat:
- *  All of the buffers must be for the same device, and must also be
- *  a multiple of the current approved size for the device.
- *
- **/
-
-void ll_rw_block(int rw, int nr, struct buffer_head * bhs[])
-{
-	unsigned int major;
-	int correct_size;
-	int i;
-
-	if (!nr)
-		return;
-
-	major = major(to_kdev_t(bhs[0]->b_bdev->bd_dev));
-
-	/* Determine correct block size for this device. */
-	correct_size = bdev_hardsect_size(bhs[0]->b_bdev);
-
-	/* Verify requested block sizes. */
-	for (i = 0; i < nr; i++) {
-		struct buffer_head *bh = bhs[i];
-		if (bh->b_size & (correct_size - 1)) {
-			printk(KERN_NOTICE "ll_rw_block: device %s: "
-			       "only %d-char blocks implemented (%u)\n",
-			       bdevname(bhs[0]->b_bdev),
-			       correct_size, bh->b_size);
-			goto sorry;
-		}
-	}
-
-	if ((rw & WRITE) && bdev_read_only(bhs[0]->b_bdev)) {
-		printk(KERN_NOTICE "Can't write to read-only device %s\n",
-		       bdevname(bhs[0]->b_bdev));
-		goto sorry;
-	}
-
-	for (i = 0; i < nr; i++) {
-		struct buffer_head *bh = bhs[i];
-
-		/* Only one thread can actually submit the I/O. */
-		if (test_set_buffer_locked(bh))
-			continue;
-
-		/* We have the buffer lock */
-		atomic_inc(&bh->b_count);
-		bh->b_end_io = end_buffer_io_sync;
-
-		switch(rw) {
-		case WRITE:
-			if (!test_clear_buffer_dirty(bh))
-				/* Hmmph! Nothing to write */
-				goto end_io;
-			break;
-
-		case READA:
-		case READ:
-			if (buffer_uptodate(bh))
-				/* Hmmph! Already have it */
-				goto end_io;
-			break;
-		default:
-			BUG();
-	end_io:
-			bh->b_end_io(bh, buffer_uptodate(bh));
-			continue;
-		}
-
-		submit_bh(rw, bh);
-	}
-	return;
-
-sorry:
-	/* Make sure we don't get infinite dirty retries.. */
-	for (i = 0; i < nr; i++)
-		clear_buffer_dirty(bhs[i]);
-}
-
-#ifdef CONFIG_STRAM_SWAP
-extern int stram_device_init (void);
-#endif
-
 inline void blk_recalc_rq_segments(struct request *rq)
 {
 	struct bio *bio;
@@ -1962,8 +1802,8 @@
  * @nr_sectors: number of sectors to end I/O on
  *
  * Description:
- *     Ends I/O on the first buffer attached to @req, and sets it up
- *     for the next buffer_head (if any) in the cluster.
+ *     Ends I/O on a number of sectors attached to @req, and sets it up
+ *     for the next range of segments (if any) in the cluster.
  *
  * Return:
  *     0 - we are done with this request, call end_that_request_last()
@@ -1983,6 +1823,7 @@
 	total_nsect = 0;
 	while ((bio = req->bio)) {
 		nsect = bio_iovec(bio)->bv_len >> 9;
+		total_nsect += nsect;
 
 		BIO_BUG_ON(bio_iovec(bio)->bv_len > bio->bi_size);
 
@@ -1992,38 +1833,31 @@
 		if (unlikely(nsect > nr_sectors)) {
 			int partial = nr_sectors << 9;
 
-			bio->bi_size -= partial;
 			bio_iovec(bio)->bv_offset += partial;
 			bio_iovec(bio)->bv_len -= partial;
-			blk_recalc_rq_sectors(req, nr_sectors);
+			blk_recalc_rq_sectors(req, total_nsect);
 			blk_recalc_rq_segments(req);
+			bio_endio(bio, partial, !uptodate ? -EIO : 0);
 			return 1;
 		}
 
 		/*
-		 * account transfer
+		 * if bio->bi_end_io returns 0, this bio is done. move on
 		 */
-		bio->bi_size -= bio_iovec(bio)->bv_len;
-		bio->bi_idx++;
+		req->bio = bio->bi_next;
+		if (bio_endio(bio, nsect << 9, !uptodate ? -EIO : 0)) {
+			bio->bi_idx++;
+			req->bio = bio;
+		}
 
 		nr_sectors -= nsect;
-		total_nsect += nsect;
-
-		if (!bio->bi_size) {
-			req->bio = bio->bi_next;
-
-			bio_endio(bio, uptodate);
-
-			total_nsect = 0;
-		}
 
 		if ((bio = req->bio)) {
-			blk_recalc_rq_sectors(req, nsect);
-
 			/*
 			 * end more in this run, or just return 'not-done'
 			 */
 			if (unlikely(nr_sectors <= 0)) {
+				blk_recalc_rq_sectors(req, total_nsect);
 				blk_recalc_rq_segments(req);
 				return 1;
 			}
@@ -2041,27 +1875,16 @@
 	blk_put_request(req);
 }
 
-#define MB(kb)	((kb) << 10)
-
 int __init blk_dev_init(void)
 {
-	struct blk_dev_struct *dev;
-	int total_ram;
+	int total_ram = nr_free_pages() << (PAGE_SHIFT - 10);
 
 	request_cachep = kmem_cache_create("blkdev_requests",
-					   sizeof(struct request),
-					   0, SLAB_HWCACHE_ALIGN, NULL, NULL);
-
+			sizeof(struct request), 0,
+			SLAB_HWCACHE_ALIGN, NULL, NULL);
 	if (!request_cachep)
 		panic("Can't create request pool slab cache\n");
 
-	for (dev = blk_dev + MAX_BLKDEV; dev-- != blk_dev;)
-		dev->queue = NULL;
-
-	memset(ro_bits,0,sizeof(ro_bits));
-
-	total_ram = nr_free_pages() << (PAGE_SHIFT - 10);
-
 	/*
 	 * Free request slots per queue.
 	 * (Half for reads, half for writes)
@@ -2077,16 +1900,11 @@
 	 */
 	if ((batch_requests = queue_nr_requests / 4) > 32)
 		batch_requests = 32;
-	printk("block: %d slots per queue, batch=%d\n", queue_nr_requests, batch_requests);
+	printk("block: %d slots per queue, batch=%d\n",
+			queue_nr_requests, batch_requests);
 
 	blk_max_low_pfn = max_low_pfn;
 	blk_max_pfn = max_pfn;
-
-	INIT_LIST_HEAD(&blk_plug_list);
-
-#if defined(CONFIG_IDE) && defined(CONFIG_BLK_DEV_HD)
-	hd_init();
-#endif
 
 	return 0;
 };
diff -Nru a/drivers/block/loop.c b/drivers/block/loop.c
--- a/drivers/block/loop.c	Fri Sep 20 08:20:46 2002
+++ b/drivers/block/loop.c	Fri Sep 20 08:20:46 2002
@@ -374,7 +374,7 @@
 	return ret;
 }
 
-static void loop_end_io_transfer(struct bio *);
+static int loop_end_io_transfer(struct bio *, unsigned int, int);
 static void loop_put_buffer(struct bio *bio)
 {
 	/*
@@ -382,6 +382,7 @@
 	 */
 	if (bio && bio->bi_end_io == loop_end_io_transfer) {
 		int i;
+
 		for (i = 0; i < bio->bi_vcnt; i++)
 			__free_page(bio->bi_io_vec[i].bv_page);
 
@@ -432,19 +433,23 @@
  * bi_end_io context (we don't want to do decrypt of a page with irqs
  * disabled)
  */
-static void loop_end_io_transfer(struct bio *bio)
+static int loop_end_io_transfer(struct bio *bio, unsigned int bytes_done, int err)
 {
 	struct bio *rbh = bio->bi_private;
 	struct loop_device *lo = &loop_dev[minor(to_kdev_t(rbh->bi_bdev->bd_dev))];
-	int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
 
-	if (!uptodate || bio_rw(bio) == WRITE) {
-		bio_endio(rbh, uptodate);
+	if (bio->bi_size)
+		return 1;
+
+	if (!err || bio_rw(bio) == WRITE) {
+		bio_endio(rbh, rbh->bi_size, err);
 		if (atomic_dec_and_test(&lo->lo_pending))
 			up(&lo->lo_bh_mutex);
 		loop_put_buffer(bio);
 	} else
 		loop_add_bio(lo, bio);
+
+	return 0;
 }
 
 static struct bio *loop_get_buffer(struct loop_device *lo, struct bio *rbh)
@@ -553,7 +558,7 @@
 		up(&lo->lo_bh_mutex);
 	loop_put_buffer(new_bio);
 out:
-	bio_io_error(old_bio);
+	bio_io_error(old_bio, old_bio->bi_size);
 	return 0;
 inactive:
 	spin_unlock_irq(&lo->lo_lock);
@@ -569,13 +574,13 @@
 	 */
 	if (lo->lo_flags & LO_FLAGS_DO_BMAP) {
 		ret = do_bio_filebacked(lo, bio);
-		bio_endio(bio, !ret);
+		bio_endio(bio, bio->bi_size, ret);
 	} else {
 		struct bio *rbh = bio->bi_private;
 
 		ret = bio_transfer(lo, bio, rbh);
 
-		bio_endio(rbh, !ret);
+		bio_endio(rbh, rbh->bi_size, ret);
 		loop_put_buffer(bio);
 	}
 }
diff -Nru a/drivers/block/rd.c b/drivers/block/rd.c
--- a/drivers/block/rd.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/block/rd.c	Fri Sep 20 08:20:47 2002
@@ -277,11 +277,10 @@
 	if (rd_blkdev_bio_IO(sbh, minor))
 		goto fail;
 
-	set_bit(BIO_UPTODATE, &sbh->bi_flags);
-	sbh->bi_end_io(sbh);
+	bio_endio(sbh, sbh->bi_size, 0);
 	return 0;
  fail:
-	bio_io_error(sbh);
+	bio_io_error(sbh, sbh->bi_size);
 	return 0;
 } 
 
diff -Nru a/drivers/block/umem.c b/drivers/block/umem.c
--- a/drivers/block/umem.c	Fri Sep 20 08:20:48 2002
+++ b/drivers/block/umem.c	Fri Sep 20 08:20:48 2002
@@ -544,9 +544,16 @@
 
 	while(return_bio) {
 		struct bio *bio = return_bio;
+		int bytes = bio->bi_size;
+
 		return_bio = bio->bi_next;
 		bio->bi_next = NULL;
-		bio->bi_end_io(bio);
+		/* should use bio_endio(), however already cleared
+		 * BIO_UPTODATE. so set bio->bi_size = 0 manually to indicate
+		 * completely done
+		 */
+		bio->bi_size = 0;
+		bio->bi_end_io(bio, bytes, 0);
 	}
 }
 
@@ -560,8 +567,6 @@
 	struct cardinfo *card = q->queuedata;
 	PRINTK("mm_make_request %ld %d\n", bh->b_rsector, bh->b_size);
 
-	/* set uptodate now, and clear it if there are any errors */
-	set_bit(BIO_UPTODATE, &bio->bi_flags);
 	bio->bi_phys_segments = bio->bi_idx; /* count of completed segments*/
 	spin_lock_bh(&card->lock);
 	*card->biotail = bio;
diff -Nru a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c
--- a/drivers/bluetooth/hci_h4.c	Fri Sep 20 08:20:46 2002
+++ b/drivers/bluetooth/hci_h4.c	Fri Sep 20 08:20:46 2002
@@ -253,13 +253,13 @@
 }
 
 static struct hci_uart_proto h4p = {
-	id:    HCI_UART_H4,
-	open:  h4_open,
-	close: h4_close,
-	send:  h4_send,
-	recv:  h4_recv,
-	preq:  h4_preq,
-	flush: h4_flush,
+	.id    = HCI_UART_H4,
+	.open  = h4_open,
+	.close = h4_close,
+	.send  = h4_send,
+	.recv  = h4_recv,
+	.preq  = h4_preq,
+	.flush = h4_flush,
 };
 	      
 int h4_init(void)
diff -Nru a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
--- a/drivers/bluetooth/hci_usb.c	Fri Sep 20 08:20:48 2002
+++ b/drivers/bluetooth/hci_usb.c	Fri Sep 20 08:20:48 2002
@@ -828,10 +828,10 @@
 }
 
 static struct usb_driver hci_usb_driver = {
-	name:           "hci_usb",
-	probe:          hci_usb_probe,
-	disconnect:     hci_usb_disconnect,
-	id_table:       usb_bluetooth_ids,
+	.name           = "hci_usb",
+	.probe          = hci_usb_probe,
+	.disconnect     = hci_usb_disconnect,
+	.id_table       = usb_bluetooth_ids,
 };
 
 int hci_usb_init(void)
diff -Nru a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
--- a/drivers/bluetooth/hci_vhci.c	Fri Sep 20 08:20:48 2002
+++ b/drivers/bluetooth/hci_vhci.c	Fri Sep 20 08:20:48 2002
@@ -311,15 +311,15 @@
 }
 
 static struct file_operations hci_vhci_fops = {
-	owner:	THIS_MODULE,	
-	llseek:	hci_vhci_chr_lseek,
-	read:	hci_vhci_chr_read,
-	write:	hci_vhci_chr_write,
-	poll:	hci_vhci_chr_poll,
-	ioctl:	hci_vhci_chr_ioctl,
-	open:	hci_vhci_chr_open,
-	release:hci_vhci_chr_close,
-	fasync:	hci_vhci_chr_fasync		
+	.owner	= THIS_MODULE,	
+	.llseek	= hci_vhci_chr_lseek,
+	.read	= hci_vhci_chr_read,
+	.write	= hci_vhci_chr_write,
+	.poll	= hci_vhci_chr_poll,
+	.ioctl	= hci_vhci_chr_ioctl,
+	.open	= hci_vhci_chr_open,
+	.release	= hci_vhci_chr_close,
+	.fasync	= hci_vhci_chr_fasync		
 };
 
 static struct miscdevice hci_vhci_miscdev=
diff -Nru a/drivers/char/eurotechwdt.c b/drivers/char/eurotechwdt.c
--- a/drivers/char/eurotechwdt.c	Fri Sep 20 08:20:42 2002
+++ b/drivers/char/eurotechwdt.c	Fri Sep 20 08:20:42 2002
@@ -46,7 +46,6 @@
 #include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
-#include <linux/smp_lock.h>
 
 static int eurwdt_is_open;
 static spinlock_t eurwdt_lock;
diff -Nru a/drivers/char/random.c b/drivers/char/random.c
--- a/drivers/char/random.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/char/random.c	Fri Sep 20 08:20:41 2002
@@ -2033,57 +2033,103 @@
 
 /* This should not be decreased so low that ISNs wrap too fast. */
 #define REKEY_INTERVAL	300
-#define HASH_BITS 24
+/*
+ * Bit layout of the tcp sequence numbers (before adding current time):
+ * bit 24-31: increased after every key exchange
+ * bit 0-23: hash(source,dest)
+ *
+ * The implementation is similar to the algorithm described
+ * in the Appendix of RFC 1185, except that
+ * - it uses a 1 MHz clock instead of a 250 kHz clock
+ * - it performs a rekey every 5 minutes, which is equivalent
+ * 	to a (source,dest) tulple dependent forward jump of the
+ * 	clock by 0..2^(HASH_BITS+1)
+ *
+ * Thus the average ISN wraparound time is 68 minutes instead of
+ * 4.55 hours.
+ *
+ * SMP cleanup and lock avoidance with poor man's RCU.
+ * 			Manfred Spraul <manfred@colorfullife.com>
+ * 		
+ */
+#define COUNT_BITS	8
+#define COUNT_MASK	( (1<<COUNT_BITS)-1)
+#define HASH_BITS	24
+#define HASH_MASK	( (1<<HASH_BITS)-1 )
+
+static struct keydata {
+	time_t rekey_time;
+	__u32	count;		// already shifted to the final position
+	__u32	secret[12];
+} ____cacheline_aligned ip_keydata[2];
+
+static spinlock_t ip_lock = SPIN_LOCK_UNLOCKED;
+static unsigned int ip_cnt;
+
+static struct keydata *__check_and_rekey(time_t time)
+{
+	struct keydata *keyptr;
+	spin_lock(&ip_lock);
+	keyptr = &ip_keydata[ip_cnt&1];
+	if (!keyptr->rekey_time || (time - keyptr->rekey_time) > REKEY_INTERVAL) {
+		keyptr = &ip_keydata[1^(ip_cnt&1)];
+		keyptr->rekey_time = time;
+		get_random_bytes(keyptr->secret, sizeof(keyptr->secret));
+		keyptr->count = (ip_cnt&COUNT_MASK)<<HASH_BITS;
+		mb();
+		ip_cnt++;
+	}
+	spin_unlock(&ip_lock);
+	return keyptr;
+}
+
+static inline struct keydata *check_and_rekey(time_t time)
+{
+	struct keydata *keyptr = &ip_keydata[ip_cnt&1];
+
+	rmb();
+	if (!keyptr->rekey_time || (time - keyptr->rekey_time) > REKEY_INTERVAL) {
+		keyptr = __check_and_rekey(time);
+	}
+
+	return keyptr;
+}
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 __u32 secure_tcpv6_sequence_number(__u32 *saddr, __u32 *daddr,
 				   __u16 sport, __u16 dport)
 {
-	static __u32	rekey_time;
-	static __u32	count;
-	static __u32	secret[12];
 	struct timeval 	tv;
 	__u32		seq;
+	__u32		hash[12];
+	struct keydata *keyptr;
 
-	/* The procedure is the same as for IPv4, but addresses are longer. */
+	/* The procedure is the same as for IPv4, but addresses are longer.
+	 * Thus we must use twothirdsMD4Transform.
+	 */
 
 	do_gettimeofday(&tv);	/* We need the usecs below... */
+	keyptr = check_and_rekey(tv.tv_sec);
 
-	if (!rekey_time || (tv.tv_sec - rekey_time) > REKEY_INTERVAL) {
-		rekey_time = tv.tv_sec;
-		/* First five words are overwritten below. */
-		get_random_bytes(&secret[5], sizeof(secret)-5*4);
-		count = (tv.tv_sec/REKEY_INTERVAL) << HASH_BITS;
-	}
-
-	memcpy(secret, saddr, 16);
-	secret[4]=(sport << 16) + dport;
-
-	seq = (twothirdsMD4Transform(daddr, secret) &
-	       ((1<<HASH_BITS)-1)) + count;
+	memcpy(hash, saddr, 16);
+	hash[4]=(sport << 16) + dport;
+	memcpy(&hash[5],keyptr->secret,sizeof(__u32)*7);
 
+	seq = twothirdsMD4Transform(daddr, hash) & HASH_MASK;
+	seq += keyptr->count;
 	seq += tv.tv_usec + tv.tv_sec*1000000;
+
 	return seq;
 }
 EXPORT_SYMBOL(secure_tcpv6_sequence_number);
 
 __u32 secure_ipv6_id(__u32 *daddr)
 {
-	static time_t	rekey_time;
-	static __u32	secret[12];
-	time_t		t;
+	struct keydata *keyptr;
 
-	/*
-	 * Pick a random secret every REKEY_INTERVAL seconds.
-	 */
-	t = CURRENT_TIME;
-	if (!rekey_time || (t - rekey_time) > REKEY_INTERVAL) {
-		rekey_time = t;
-		/* First word is overwritten below. */
-		get_random_bytes(secret, sizeof(secret));
-	}
+	keyptr = check_and_rekey(CURRENT_TIME);
 
-	return twothirdsMD4Transform(daddr, secret);
+	return halfMD4Transform(daddr, keyptr->secret);
 }
 
 EXPORT_SYMBOL(secure_ipv6_id);
@@ -2093,40 +2139,30 @@
 __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr,
 				 __u16 sport, __u16 dport)
 {
-	static __u32	rekey_time;
-	static __u32	count;
-	static __u32	secret[12];
 	struct timeval 	tv;
 	__u32		seq;
+	__u32	hash[4];
+	struct keydata *keyptr;
 
 	/*
 	 * Pick a random secret every REKEY_INTERVAL seconds.
 	 */
 	do_gettimeofday(&tv);	/* We need the usecs below... */
-
-	if (!rekey_time || (tv.tv_sec - rekey_time) > REKEY_INTERVAL) {
-		rekey_time = tv.tv_sec;
-		/* First three words are overwritten below. */
-		get_random_bytes(&secret[3], sizeof(secret)-12);
-		count = (tv.tv_sec/REKEY_INTERVAL) << HASH_BITS;
-	}
+	keyptr = check_and_rekey(tv.tv_sec);
 
 	/*
 	 *  Pick a unique starting offset for each TCP connection endpoints
 	 *  (saddr, daddr, sport, dport).
-	 *  Note that the words are placed into the first words to be
-	 *  mixed in with the halfMD4.  This is because the starting
-	 *  vector is also a random secret (at secret+8), and further
-	 *  hashing fixed data into it isn't going to improve anything,
-	 *  so we should get started with the variable data.
+	 *  Note that the words are placed into the starting vector, which is 
+	 *  then mixed with a partial MD4 over random data.
 	 */
-	secret[0]=saddr;
-	secret[1]=daddr;
-	secret[2]=(sport << 16) + dport;
-
-	seq = (halfMD4Transform(secret+8, secret) &
-	       ((1<<HASH_BITS)-1)) + count;
+	hash[0]=saddr;
+	hash[1]=daddr;
+	hash[2]=(sport << 16) + dport;
+	hash[3]=keyptr->secret[11];
 
+	seq = halfMD4Transform(hash, keyptr->secret) & HASH_MASK;
+	seq += keyptr->count;
 	/*
 	 *	As close as possible to RFC 793, which
 	 *	suggests using a 250 kHz clock.
@@ -2148,31 +2184,22 @@
  */
 __u32 secure_ip_id(__u32 daddr)
 {
-	static time_t	rekey_time;
-	static __u32	secret[12];
-	time_t		t;
+	struct keydata *keyptr;
+	__u32 hash[4];
 
-	/*
-	 * Pick a random secret every REKEY_INTERVAL seconds.
-	 */
-	t = CURRENT_TIME;
-	if (!rekey_time || (t - rekey_time) > REKEY_INTERVAL) {
-		rekey_time = t;
-		/* First word is overwritten below. */
-		get_random_bytes(secret+1, sizeof(secret)-4);
-	}
+	keyptr = check_and_rekey(CURRENT_TIME);
 
 	/*
 	 *  Pick a unique starting offset for each IP destination.
-	 *  Note that the words are placed into the first words to be
-	 *  mixed in with the halfMD4.  This is because the starting
-	 *  vector is also a random secret (at secret+8), and further
-	 *  hashing fixed data into it isn't going to improve anything,
-	 *  so we should get started with the variable data.
+	 *  The dest ip address is placed in the starting vector,
+	 *  which is then hashed with random data.
 	 */
-	secret[0]=daddr;
+	hash[0] = daddr;
+	hash[1] = keyptr->secret[9];
+	hash[2] = keyptr->secret[10];
+	hash[3] = keyptr->secret[11];
 
-	return halfMD4Transform(secret+8, secret);
+	return halfMD4Transform(hash, keyptr->secret);
 }
 
 #ifdef CONFIG_SYN_COOKIES
diff -Nru a/drivers/char/raw.c b/drivers/char/raw.c
--- a/drivers/char/raw.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/char/raw.c	Fri Sep 20 08:20:47 2002
@@ -241,7 +241,7 @@
 static ssize_t
 raw_write(struct file *filp, const char *buf, size_t size, loff_t *offp)
 {
-	struct iovec local_iov = { .iov_base = buf, .iov_len = size};
+	struct iovec local_iov = { .iov_base = (char *)buf, .iov_len = size};
 
 	return rw_raw_dev(WRITE, filp, &local_iov, 1, offp);
 }
diff -Nru a/drivers/char/rtc.c b/drivers/char/rtc.c
--- a/drivers/char/rtc.c	Fri Sep 20 08:20:44 2002
+++ b/drivers/char/rtc.c	Fri Sep 20 08:20:44 2002
@@ -76,6 +76,7 @@
 #include <asm/system.h>
 
 #ifdef __sparc__
+#include <linux/pci.h>
 #include <asm/ebus.h>
 #ifdef __sparc_v9__
 #include <asm/isa.h>
diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c
--- a/drivers/char/tty_io.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/char/tty_io.c	Fri Sep 20 08:20:47 2002
@@ -432,6 +432,7 @@
 	struct file * cons_filp = NULL;
 	struct task_struct *p;
 	struct list_head *l;
+	struct pid *pid;
 	int    closecount = 0, n;
 
 	if (!tty)
@@ -496,17 +497,17 @@
 	}
 	
 	read_lock(&tasklist_lock);
- 	for_each_process(p) {
-		if ((tty->session > 0) && (p->session == tty->session) &&
-		    p->leader) {
-			send_sig(SIGHUP,p,1);
-			send_sig(SIGCONT,p,1);
+	if (tty->session > 0)
+		for_each_task_pid(tty->session, PIDTYPE_SID, p, l, pid) {
+			if (p->tty == tty)
+				p->tty = NULL;
+			if (!p->leader)
+				continue;
+			send_sig(SIGHUP, p, 1);
+			send_sig(SIGCONT, p, 1);
 			if (tty->pgrp > 0)
 				p->tty_old_pgrp = tty->pgrp;
 		}
-		if (p->tty == tty)
-			p->tty = NULL;
-	}
 	read_unlock(&tasklist_lock);
 
 	tty->flags = 0;
@@ -571,6 +572,8 @@
 {
 	struct tty_struct *tty = current->tty;
 	struct task_struct *p;
+	struct list_head *l;
+	struct pid *pid;
 	int tty_pgrp = -1;
 
 	lock_kernel();
@@ -598,9 +601,8 @@
 	tty->pgrp = -1;
 
 	read_lock(&tasklist_lock);
-	for_each_process(p)
-	  	if (p->session == current->session)
-			p->tty = NULL;
+	for_each_task_pid(current->session, PIDTYPE_SID, p, l, pid)
+		p->tty = NULL;
 	read_unlock(&tasklist_lock);
 	unlock_kernel();
 }
@@ -1221,12 +1223,15 @@
 	 */
 	if (tty_closing || o_tty_closing) {
 		struct task_struct *p;
+		struct list_head *l;
+		struct pid *pid;
 
 		read_lock(&tasklist_lock);
-		for_each_process(p) {
-			if (p->tty == tty || (o_tty && p->tty == o_tty))
+		for_each_task_pid(tty->session, PIDTYPE_SID, p, l, pid)
+			p->tty = NULL;
+		if (o_tty)
+			for_each_task_pid(o_tty->session, PIDTYPE_SID, p,l, pid)
 				p->tty = NULL;
-		}
 		read_unlock(&tasklist_lock);
 
 		if (redirect == tty || (o_tty && redirect == o_tty))
@@ -1540,6 +1545,10 @@
 
 static int tiocsctty(struct tty_struct *tty, int arg)
 {
+	struct list_head *l;
+	struct pid *pid;
+	task_t *p;
+
 	if (current->leader &&
 	    (current->session == tty->session))
 		return 0;
@@ -1558,12 +1567,10 @@
 			/*
 			 * Steal it away
 			 */
-			struct task_struct *p;
 
 			read_lock(&tasklist_lock);
-			for_each_process(p)
-				if (p->tty == tty)
-					p->tty = NULL;
+			for_each_task_pid(tty->session, PIDTYPE_SID, p, l, pid)
+				p->tty = NULL;
 			read_unlock(&tasklist_lock);
 		} else
 			return -EPERM;
diff -Nru a/drivers/hotplug/cpqphp.h b/drivers/hotplug/cpqphp.h
--- a/drivers/hotplug/cpqphp.h	Fri Sep 20 08:20:44 2002
+++ b/drivers/hotplug/cpqphp.h	Fri Sep 20 08:20:44 2002
@@ -305,8 +305,8 @@
 	u8 first_slot;
 	u8 add_support;
 	u8 push_flag;
-	u8 speed;			/* 0 = 33MHz, 1 = 66MHz */
-	u8 speed_capability;		/* 0 = 33MHz, 1 = 66MHz */
+	enum pci_bus_speed speed;
+	enum pci_bus_speed speed_capability;
 	u8 push_button;			/* 0 = no pushbutton, 1 = pushbutton present */
 	u8 slot_switch_type;		/* 0 = no switch, 1 = switch present */
 	u8 defeature_PHP;		/* 0 = PHP not supported, 1 = PHP supported */
@@ -321,9 +321,6 @@
 	wait_queue_head_t queue;	/* sleep & wake process */
 };
 
-#define CTRL_SPEED_33MHz	0
-#define CTRL_SPEED_66MHz	1
-
 struct irq_mapping {
 	u8 barber_pole;
 	u8 valid_INT;
@@ -635,7 +632,7 @@
 	u16 misc;
 	
 	misc = readw(ctrl->hpc_reg + MISC);
-	return (misc & 0x0800) ? 1 : 0;
+	return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz;
 }
 
 
diff -Nru a/drivers/hotplug/cpqphp_core.c b/drivers/hotplug/cpqphp_core.c
--- a/drivers/hotplug/cpqphp_core.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/hotplug/cpqphp_core.c	Fri Sep 20 08:20:41 2002
@@ -79,6 +79,8 @@
 static int get_attention_status	(struct hotplug_slot *slot, u8 *value);
 static int get_latch_status	(struct hotplug_slot *slot, u8 *value);
 static int get_adapter_status	(struct hotplug_slot *slot, u8 *value);
+static int get_max_bus_speed	(struct hotplug_slot *slot, enum pci_bus_speed *value);
+static int get_cur_bus_speed	(struct hotplug_slot *slot, enum pci_bus_speed *value);
 
 static struct hotplug_slot_ops cpqphp_hotplug_slot_ops = {
 	.owner =		THIS_MODULE,
@@ -90,6 +92,8 @@
 	.get_attention_status =	get_attention_status,
 	.get_latch_status =	get_latch_status,
 	.get_adapter_status =	get_adapter_status,
+  	.get_max_bus_speed =	get_max_bus_speed,
+  	.get_cur_bus_speed =	get_cur_bus_speed,
 };
 
 
@@ -378,7 +382,7 @@
 			new_slot->capabilities |= PCISLOT_64_BIT_SUPPORTED;
 		if (is_slot66mhz(new_slot))
 			new_slot->capabilities |= PCISLOT_66_MHZ_SUPPORTED;
-		if (ctrl->speed == 1)
+		if (ctrl->speed == PCI_SPEED_66MHz)
 			new_slot->capabilities |= PCISLOT_66_MHZ_OPERATION;
 
 		ctrl_slot = slot_device - (readb(ctrl->hpc_reg + SLOT_MASK) >> 4);
@@ -782,6 +786,44 @@
 	return 0;
 }
 
+static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct controller *ctrl;
+	
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	ctrl = slot->ctrl;
+	if (ctrl == NULL)
+		return -ENODEV;
+	
+	*value = ctrl->speed_capability;
+
+	return 0;
+}
+
+static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
+{
+	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	struct controller *ctrl;
+	
+	if (slot == NULL)
+		return -ENODEV;
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	ctrl = slot->ctrl;
+	if (ctrl == NULL)
+		return -ENODEV;
+	
+	*value = ctrl->speed;
+
+	return 0;
+}
+
 static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	u8 num_of_slots = 0;
@@ -853,28 +895,28 @@
 					case PCI_SUB_HPC_ID:
 						/* Original 6500/7000 implementation */
 						ctrl->slot_switch_type = 1;		// Switch is present
-						ctrl->speed_capability = CTRL_SPEED_33MHz;
+						ctrl->speed_capability = PCI_SPEED_33MHz;
 						ctrl->push_button = 0;			// No pushbutton
 						ctrl->pci_config_space = 1;		// Index/data access to working registers 0 = not supported, 1 = supported
-						ctrl->defeature_PHP = 1;			// PHP is supported
+						ctrl->defeature_PHP = 1;		// PHP is supported
 						ctrl->pcix_support = 0;			// PCI-X not supported
-						ctrl->pcix_speed_capability = 0;		// N/A since PCI-X not supported
+						ctrl->pcix_speed_capability = 0;	// N/A since PCI-X not supported
 						break;
 					case PCI_SUB_HPC_ID2:
 						/* First Pushbutton implementation */
 						ctrl->push_flag = 1;
 						ctrl->slot_switch_type = 1;		// Switch is present
-						ctrl->speed_capability = CTRL_SPEED_33MHz;
+						ctrl->speed_capability = PCI_SPEED_33MHz;
 						ctrl->push_button = 1;			// Pushbutton is present
 						ctrl->pci_config_space = 1;		// Index/data access to working registers 0 = not supported, 1 = supported
-						ctrl->defeature_PHP = 1;			// PHP is supported
+						ctrl->defeature_PHP = 1;		// PHP is supported
 						ctrl->pcix_support = 0;			// PCI-X not supported
-						ctrl->pcix_speed_capability = 0;		// N/A since PCI-X not supported
+						ctrl->pcix_speed_capability = 0;	// N/A since PCI-X not supported
 						break;
 					case PCI_SUB_HPC_ID_INTC:
 						/* Third party (6500/7000) */
 						ctrl->slot_switch_type = 1;		// Switch is present
-						ctrl->speed_capability = CTRL_SPEED_33MHz;
+						ctrl->speed_capability = PCI_SPEED_33MHz;
 						ctrl->push_button = 0;			// No pushbutton
 						ctrl->pci_config_space = 1;		// Index/data access to working registers 0 = not supported, 1 = supported
 						ctrl->defeature_PHP = 1;			// PHP is supported
@@ -885,7 +927,7 @@
 						/* First 66 Mhz implementation */
 						ctrl->push_flag = 1;
 						ctrl->slot_switch_type = 1;		// Switch is present
-						ctrl->speed_capability = CTRL_SPEED_66MHz;
+						ctrl->speed_capability = PCI_SPEED_66MHz;
 						ctrl->push_button = 1;			// Pushbutton is present
 						ctrl->pci_config_space = 1;		// Index/data access to working registers 0 = not supported, 1 = supported
 						ctrl->defeature_PHP = 1;		// PHP is supported
@@ -903,9 +945,9 @@
 			case PCI_VENDOR_ID_INTEL:
 				/* Check for speed capability (0=33, 1=66) */
 				if (subsystem_deviceid & 0x0001) {
-					ctrl->speed_capability = CTRL_SPEED_66MHz;
+					ctrl->speed_capability = PCI_SPEED_66MHz;
 				} else {
-					ctrl->speed_capability = CTRL_SPEED_33MHz;
+					ctrl->speed_capability = PCI_SPEED_33MHz;
 				}
 
 				/* Check for push button */
@@ -982,7 +1024,7 @@
 	info("Initializing the PCI hot plug controller residing on PCI bus %d\n", pdev->bus->number);
 
 	dbg ("Hotplug controller capabilities:\n");
-	dbg ("    speed_capability       %s\n", ctrl->speed_capability == CTRL_SPEED_33MHz ? "33MHz" : "66Mhz");
+	dbg ("    speed_capability       %s\n", ctrl->speed_capability == PCI_SPEED_33MHz ? "33MHz" : "66Mhz");
 	dbg ("    slot_switch_type       %s\n", ctrl->slot_switch_type == 0 ? "no switch" : "switch present");
 	dbg ("    defeature_PHP          %s\n", ctrl->defeature_PHP == 0 ? "PHP not supported" : "PHP supported");
 	dbg ("    alternate_base_address %s\n", ctrl->alternate_base_address == 0 ? "not supported" : "supported");
diff -Nru a/drivers/hotplug/cpqphp_ctrl.c b/drivers/hotplug/cpqphp_ctrl.c
--- a/drivers/hotplug/cpqphp_ctrl.c	Fri Sep 20 08:20:44 2002
+++ b/drivers/hotplug/cpqphp_ctrl.c	Fri Sep 20 08:20:44 2002
@@ -1187,7 +1187,7 @@
 		//*********************************
 		rc = CARD_FUNCTIONING;
 	} else {
-		if (ctrl->speed == 1) {
+		if (ctrl->speed == PCI_SPEED_66MHz) {
 			// Wait for exclusive access to hardware
 			down(&ctrl->crit_sect);
 
@@ -1385,7 +1385,7 @@
 	dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n",
 	    __FUNCTION__, func->device, ctrl->slot_device_offset, hp_slot);
 
-	if (ctrl->speed == 1) {
+	if (ctrl->speed == PCI_SPEED_66MHz) {
 		// Wait for exclusive access to hardware
 		down(&ctrl->crit_sect);
 
diff -Nru a/drivers/hotplug/ibmphp_core.c b/drivers/hotplug/ibmphp_core.c
--- a/drivers/hotplug/ibmphp_core.c	Fri Sep 20 08:20:48 2002
+++ b/drivers/hotplug/ibmphp_core.c	Fri Sep 20 08:20:48 2002
@@ -384,14 +384,15 @@
 	debug ("get_adapter_present - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value);
 	return rc;
 }
-/*
-static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, u8 * value)
+
+static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
 {
 	int rc = -ENODEV;
 	struct slot *pslot;
 	u8 mode = 0;
 
-	debug ("get_max_bus_speed - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value);
+	debug ("%s - Entry hotplug_slot[%p] pvalue[%p]\n", __FUNCTION__,
+		hotplug_slot, value);
 
 	ibmphp_lock_operations ();
 
@@ -413,25 +414,26 @@
 				*value = pslot->supported_speed + 0x01;
 				break;
 			default:
-*/				/* Note (will need to change): there would be soon 256, 512 also */
-/*				rc = -ENODEV;
+				/* Note (will need to change): there would be soon 256, 512 also */
+				rc = -ENODEV;
 			}
 		}
 	} else
 		rc = -ENODEV;
 
 	ibmphp_unlock_operations ();
-	debug ("get_max_bus_speed - Exit rc[%d] value[%x]\n", rc, *value);
+	debug ("%s - Exit rc[%d] value[%x]\n", __FUNCTION__, rc, *value);
 	return rc;
 }
 
-static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, u8 * value)
+static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
 {
 	int rc = -ENODEV;
 	struct slot *pslot;
 	u8 mode = 0;
 
-	debug ("get_cur_bus_speed - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value);
+	debug ("%s - Entry hotplug_slot[%p] pvalue[%p]\n", __FUNCTION__,
+		hotplug_slot, value);
 
 	ibmphp_lock_operations ();
 
@@ -458,8 +460,8 @@
 					*value += 0x01;
 					break;
 				default:
-*/					/* Note of change: there would also be 256, 512 soon */
-/*					rc = -ENODEV;
+					/* Note of change: there would also be 256, 512 soon */
+					rc = -ENODEV;
 				}
 			}
 		}
@@ -467,10 +469,10 @@
 		rc = -ENODEV;
 
 	ibmphp_unlock_operations ();
-	debug ("get_cur_bus_speed - Exit rc[%d] value[%x]\n", rc, *value);
+	debug ("%s - Exit rc[%d] value[%x]\n", __FUNCTION__, rc, *value);
 	return rc;
 }
-
+/*
 static int get_max_adapter_speed_1 (struct hotplug_slot *hotplug_slot, u8 * value, u8 flag)
 {
 	int rc = -ENODEV;
@@ -1584,9 +1586,9 @@
 	.get_attention_status =		get_attention_status,
 	.get_latch_status =		get_latch_status,
 	.get_adapter_status =		get_adapter_present,
-/*	.get_max_bus_speed_status =	get_max_bus_speed,
-	.get_max_adapter_speed_status =	get_max_adapter_speed,
-	.get_cur_bus_speed_status =	get_cur_bus_speed,
+	.get_max_bus_speed =		get_max_bus_speed,
+	.get_cur_bus_speed =		get_cur_bus_speed,
+/*	.get_max_adapter_speed =	get_max_adapter_speed,
 	.get_bus_name_status =		get_bus_name,
 */
 };
diff -Nru a/drivers/hotplug/pci_hotplug.h b/drivers/hotplug/pci_hotplug.h
--- a/drivers/hotplug/pci_hotplug.h	Fri Sep 20 08:20:44 2002
+++ b/drivers/hotplug/pci_hotplug.h	Fri Sep 20 08:20:44 2002
@@ -29,6 +29,22 @@
 #define _PCI_HOTPLUG_H
 
 
+/* These values come from the PCI Hotplug Spec */
+enum pci_bus_speed {
+	PCI_SPEED_33MHz			= 0x00,
+	PCI_SPEED_66MHz			= 0x01,
+	PCI_SPEED_66MHz_PCIX		= 0x02,
+	PCI_SPEED_100MHz_PCIX		= 0x03,
+	PCI_SPEED_133MHz_PCIX		= 0x04,
+	PCI_SPEED_66MHz_PCIX_266	= 0x09,
+	PCI_SPEED_100MHz_PCIX_266	= 0x0a,
+	PCI_SPEED_133MHz_PCIX_266	= 0x0b,
+	PCI_SPEED_66MHz_PCIX_533	= 0x11,
+	PCI_SPEED_100MHz_PCIX_533	= 0X12,
+	PCI_SPEED_133MHz_PCIX_533	= 0x13,
+	PCI_SPEED_UNKNOWN		= 0xff,
+};
+
 struct hotplug_slot;
 struct hotplug_slot_core;
 
@@ -50,7 +66,13 @@
  * @get_latch_status: Called to get the current latch status of a slot.
  *	If this field is NULL, the value passed in the struct hotplug_slot_info
  *	will be used when this value is requested by a user.
- * @get_adapter_present: Called to get see if an adapter is present in the slot or not.
+ * @get_adapter_status: Called to get see if an adapter is present in the slot or not.
+ *	If this field is NULL, the value passed in the struct hotplug_slot_info
+ *	will be used when this value is requested by a user.
+ * @get_max_bus_speed: Called to get the max bus speed for a slot.
+ *	If this field is NULL, the value passed in the struct hotplug_slot_info
+ *	will be used when this value is requested by a user.
+ * @get_cur_bus_speed: Called to get the current bus speed for a slot.
  *	If this field is NULL, the value passed in the struct hotplug_slot_info
  *	will be used when this value is requested by a user.
  *
@@ -69,6 +91,8 @@
 	int (*get_attention_status)	(struct hotplug_slot *slot, u8 *value);
 	int (*get_latch_status)		(struct hotplug_slot *slot, u8 *value);
 	int (*get_adapter_status)	(struct hotplug_slot *slot, u8 *value);
+	int (*get_max_bus_speed)	(struct hotplug_slot *slot, enum pci_bus_speed *value);
+	int (*get_cur_bus_speed)	(struct hotplug_slot *slot, enum pci_bus_speed *value);
 };
 
 /**
@@ -85,6 +109,8 @@
 	u8	attention_status;
 	u8	latch_status;
 	u8	adapter_status;
+	enum pci_bus_speed	max_bus_speed;
+	enum pci_bus_speed	cur_bus_speed;
 };
 
 /**
diff -Nru a/drivers/hotplug/pci_hotplug_core.c b/drivers/hotplug/pci_hotplug_core.c
--- a/drivers/hotplug/pci_hotplug_core.c	Fri Sep 20 08:20:44 2002
+++ b/drivers/hotplug/pci_hotplug_core.c	Fri Sep 20 08:20:44 2002
@@ -38,6 +38,8 @@
 #include <linux/init.h>
 #include <linux/namei.h>
 #include <linux/pci.h>
+#include <linux/dnotify.h>
+#include <linux/proc_fs.h>
 #include <asm/uaccess.h>
 #include "pci_hotplug.h"
 
@@ -74,6 +76,8 @@
 	struct dentry	*latch_dentry;
 	struct dentry	*adapter_dentry;
 	struct dentry	*test_dentry;
+	struct dentry	*max_bus_speed_dentry;
+	struct dentry	*cur_bus_speed_dentry;
 };
 
 static struct super_operations pcihpfs_ops;
@@ -86,6 +90,35 @@
 
 LIST_HEAD(pci_hotplug_slot_list);
 
+/* these strings match up with the values in pci_bus_speed */
+static char *pci_bus_speed_strings[] = {
+	"33 MHz PCI",		/* 0x00 */
+	"66 MHz PCI",		/* 0x01 */
+	"66 MHz PCIX", 		/* 0x02 */
+	"100 MHz PCIX",		/* 0x03 */
+	"133 MHz PCIX",		/* 0x04 */
+	NULL,			/* 0x05 */
+	NULL,			/* 0x06 */
+	NULL,			/* 0x07 */
+	NULL,			/* 0x08 */
+	"66 MHz PCIX 266",	/* 0x09 */
+	"100 MHz PCIX 266",	/* 0x0a */
+	"133 MHz PCIX 266",	/* 0x0b */
+	NULL,			/* 0x0c */
+	NULL,			/* 0x0d */
+	NULL,			/* 0x0e */
+	NULL,			/* 0x0f */
+	NULL,			/* 0x10 */
+	"66 MHz PCIX 533",	/* 0x11 */
+	"100 MHz PCIX 533",	/* 0x12 */
+	"133 MHz PCIX 533",	/* 0x13 */
+};
+
+#ifdef CONFIG_PROC_FS		
+extern struct proc_dir_entry *proc_bus_pci_dir;
+static struct proc_dir_entry *slotdir = NULL;
+static const char *slotdir_name = "slots";
+#endif
 
 static struct inode *pcihpfs_get_inode (struct super_block *sb, int mode, int dev)
 {
@@ -274,6 +307,24 @@
 	.llseek =	default_file_lseek,
 };
 
+/* file ops for the "max bus speed" files */
+static ssize_t max_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset);
+static struct file_operations max_bus_speed_file_operations = {
+	read:		max_bus_speed_read_file,
+	write:		default_write_file,
+	open:		default_open,
+	llseek:		default_file_lseek,
+};
+
+/* file ops for the "current bus speed" files */
+static ssize_t cur_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset);
+static struct file_operations cur_bus_speed_file_operations = {
+	read:		cur_bus_speed_read_file,
+	write:		default_write_file,
+	open:		default_open,
+	llseek:		default_file_lseek,
+};
+
 /* file ops for the "test" files */
 static ssize_t test_write_file (struct file *file, const char *buf, size_t count, loff_t *ppos);
 static struct file_operations test_file_operations = {
@@ -501,26 +552,28 @@
 	up(&parent->d_inode->i_sem);
 }
 
-#define GET_STATUS(name)	\
-static int get_##name##_status (struct hotplug_slot *slot, u8 *value)	\
+#define GET_STATUS(name,type)	\
+static int get_##name (struct hotplug_slot *slot, type *value)		\
 {									\
 	struct hotplug_slot_ops *ops = slot->ops;			\
 	int retval = 0;							\
 	if (ops->owner)							\
 		__MOD_INC_USE_COUNT(ops->owner);			\
-	if (ops->get_##name##_status)					\
-		retval = ops->get_##name##_status (slot, value);	\
+	if (ops->get_##name)						\
+		retval = ops->get_##name (slot, value);			\
 	else								\
-		*value = slot->info->name##_status;			\
+		*value = slot->info->name;				\
 	if (ops->owner)							\
 		__MOD_DEC_USE_COUNT(ops->owner);			\
 	return retval;							\
 }
 
-GET_STATUS(power)
-GET_STATUS(attention)
-GET_STATUS(latch)
-GET_STATUS(adapter)
+GET_STATUS(power_status, u8)
+GET_STATUS(attention_status, u8)
+GET_STATUS(latch_status, u8)
+GET_STATUS(adapter_status, u8)
+GET_STATUS(max_bus_speed, enum pci_bus_speed)
+GET_STATUS(cur_bus_speed, enum pci_bus_speed)
 
 static ssize_t power_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
 {
@@ -575,7 +628,7 @@
 
 	if (*offset < 0)
 		return -EINVAL;
-	if (count <= 0)
+	if (count == 0 || count > 16384)
 		return 0;
 	if (*offset != 0)
 		return 0;
@@ -686,7 +739,7 @@
 
 	if (*offset < 0)
 		return -EINVAL;
-	if (count <= 0)
+	if (count == 0 || count > 16384)
 		return 0;
 	if (*offset != 0)
 		return 0;
@@ -769,7 +822,6 @@
 	return retval;
 }
 
-
 static ssize_t presence_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
 {
 	struct hotplug_slot *slot = file->private_data;
@@ -813,6 +865,108 @@
 	return retval;
 }
 
+static char *unknown_speed = "Unknown bus speed";
+
+static ssize_t max_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
+{
+	struct hotplug_slot *slot = file->private_data;
+	unsigned char *page;
+	char *speed_string;
+	int retval;
+	int len = 0;
+	enum pci_bus_speed value;
+	
+	dbg ("count = %d, offset = %lld\n", count, *offset);
+
+	if (*offset < 0)
+		return -EINVAL;
+	if (count <= 0)
+		return 0;
+	if (*offset != 0)
+		return 0;
+
+	if (slot == NULL) {
+		dbg("slot == NULL???\n");
+		return -ENODEV;
+	}
+
+	page = (unsigned char *)__get_free_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+
+	retval = get_max_bus_speed (slot, &value);
+	if (retval)
+		goto exit;
+
+	if (value == PCI_SPEED_UNKNOWN)
+		speed_string = unknown_speed;
+	else
+		speed_string = pci_bus_speed_strings[value];
+	
+	len = sprintf (page, "%s\n", speed_string);
+
+	if (copy_to_user (buf, page, len)) {
+		retval = -EFAULT;
+		goto exit;
+	}
+	*offset += len;
+	retval = len;
+
+exit:
+	free_page((unsigned long)page);
+	return retval;
+}
+
+static ssize_t cur_bus_speed_read_file (struct file *file, char *buf, size_t count, loff_t *offset)
+{
+	struct hotplug_slot *slot = file->private_data;
+	unsigned char *page;
+	char *speed_string;
+	int retval;
+	int len = 0;
+	enum pci_bus_speed value;
+
+	dbg ("count = %d, offset = %lld\n", count, *offset);
+
+	if (*offset < 0)
+		return -EINVAL;
+	if (count <= 0)
+		return 0;
+	if (*offset != 0)
+		return 0;
+
+	if (slot == NULL) {
+		dbg("slot == NULL???\n");
+		return -ENODEV;
+	}
+
+	page = (unsigned char *)__get_free_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+
+	retval = get_cur_bus_speed (slot, &value);
+	if (retval)
+		goto exit;
+
+	if (value == PCI_SPEED_UNKNOWN)
+		speed_string = unknown_speed;
+	else
+		speed_string = pci_bus_speed_strings[value];
+	
+	len = sprintf (page, "%s\n", speed_string);
+
+	if (copy_to_user (buf, page, len)) {
+		retval = -EFAULT;
+		goto exit;
+	}
+	*offset += len;
+	retval = len;
+
+exit:
+	free_page((unsigned long)page);
+	return retval;
+}
+
 static ssize_t test_write_file (struct file *file, const char *ubuff, size_t count, loff_t *offset)
 {
 	struct hotplug_slot *slot = file->private_data;
@@ -823,7 +977,7 @@
 
 	if (*offset < 0)
 		return -EINVAL;
-	if (count <= 0)
+	if (count == 0 || count > 16384)
 		return 0;
 	if (*offset != 0)
 		return 0;
@@ -876,30 +1030,57 @@
 					   S_IFDIR | S_IXUGO | S_IRUGO,
 					   NULL, NULL, NULL);
 	if (core->dir_dentry != NULL) {
-		core->power_dentry = fs_create_file ("power",
-						     S_IFREG | S_IRUGO | S_IWUSR,
-						     core->dir_dentry, slot,
-						     &power_file_operations);
-
-		core->attention_dentry = fs_create_file ("attention",
-							 S_IFREG | S_IRUGO | S_IWUSR,
-							 core->dir_dentry, slot,
-							 &attention_file_operations);
-
-		core->latch_dentry = fs_create_file ("latch",
-						     S_IFREG | S_IRUGO,
-						     core->dir_dentry, slot,
-						     &latch_file_operations);
-
-		core->adapter_dentry = fs_create_file ("adapter",
-						       S_IFREG | S_IRUGO,
-						       core->dir_dentry, slot,
-						       &presence_file_operations);
-
-		core->test_dentry = fs_create_file ("test",
-						    S_IFREG | S_IRUGO | S_IWUSR,
-						    core->dir_dentry, slot,
-						    &test_file_operations);
+		if ((slot->ops->enable_slot) ||
+		    (slot->ops->disable_slot) ||
+		    (slot->ops->get_power_status))
+			core->power_dentry = 
+				fs_create_file ("power",
+						S_IFREG | S_IRUGO | S_IWUSR,
+						core->dir_dentry, slot,
+						&power_file_operations);
+
+		if ((slot->ops->set_attention_status) ||
+		    (slot->ops->get_attention_status))
+			core->attention_dentry =
+				fs_create_file ("attention",
+						S_IFREG | S_IRUGO | S_IWUSR,
+						core->dir_dentry, slot,
+						&attention_file_operations);
+
+		if (slot->ops->get_latch_status)
+			core->latch_dentry = 
+				fs_create_file ("latch",
+						S_IFREG | S_IRUGO,
+						core->dir_dentry, slot,
+						&latch_file_operations);
+
+		if (slot->ops->get_adapter_status)
+			core->adapter_dentry = 
+				fs_create_file ("adapter",
+						S_IFREG | S_IRUGO,
+						core->dir_dentry, slot,
+						&presence_file_operations);
+
+		if (slot->ops->get_max_bus_speed)
+			core->max_bus_speed_dentry = 
+				fs_create_file ("max_bus_speed",
+						S_IFREG | S_IRUGO,
+						core->dir_dentry, slot,
+						&max_bus_speed_file_operations);
+
+		if (slot->ops->get_cur_bus_speed)
+			core->cur_bus_speed_dentry =
+				fs_create_file ("cur_bus_speed",
+						S_IFREG | S_IRUGO,
+						core->dir_dentry, slot,
+						&cur_bus_speed_file_operations);
+
+		if (slot->ops->hardware_test)
+			core->test_dentry =
+				fs_create_file ("test",
+						S_IFREG | S_IRUGO | S_IWUSR,
+						core->dir_dentry, slot,
+						&test_file_operations);
 	}
 	return 0;
 }
@@ -917,6 +1098,10 @@
 			fs_remove_file (core->latch_dentry);
 		if (core->adapter_dentry)
 			fs_remove_file (core->adapter_dentry);
+		if (core->max_bus_speed_dentry)
+			fs_remove_file (core->max_bus_speed_dentry);
+		if (core->cur_bus_speed_dentry)
+			fs_remove_file (core->cur_bus_speed_dentry);
 		if (core->test_dentry)
 			fs_remove_file (core->test_dentry);
 		fs_remove_file (core->dir_dentry);
@@ -969,6 +1154,7 @@
 		return -EINVAL;
 	}
 
+	memset (core, 0, sizeof (struct hotplug_slot_core));
 	slot->core_priv = core;
 
 	list_add (&slot->slot_list, &pci_hotplug_slot_list);
@@ -1012,10 +1198,13 @@
 	return 0;
 }
 
-static inline void update_inode_time (struct inode *inode)
+static inline void update_dentry_inode_time (struct dentry *dentry)
 {
-	if (inode)
-		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	struct inode *inode = dentry->d_inode;
+	if (inode) {
+		inode->i_mtime = CURRENT_TIME;
+		dnotify_parent(dentry, DN_MODIFY);
+	}
 }
 
 /**
@@ -1050,16 +1239,19 @@
 	core = temp->core_priv;
 	if ((core->power_dentry) &&
 	    (temp->info->power_status != info->power_status))
-		update_inode_time (core->power_dentry->d_inode);
+		update_dentry_inode_time (core->power_dentry);
 	if ((core->attention_dentry) &&
 	    (temp->info->attention_status != info->attention_status))
-		update_inode_time (core->attention_dentry->d_inode);
+		update_dentry_inode_time (core->attention_dentry);
 	if ((core->latch_dentry) &&
 	    (temp->info->latch_status != info->latch_status))
-		update_inode_time (core->latch_dentry->d_inode);
+		update_dentry_inode_time (core->latch_dentry);
 	if ((core->adapter_dentry) &&
 	    (temp->info->adapter_status != info->adapter_status))
-		update_inode_time (core->adapter_dentry->d_inode);
+		update_dentry_inode_time (core->adapter_dentry);
+	if ((core->cur_bus_speed_dentry) &&
+	    (temp->info->cur_bus_speed != info->cur_bus_speed))
+		update_dentry_inode_time (core->cur_bus_speed_dentry);
 
 	memcpy (temp->info, info, sizeof (struct hotplug_slot_info));
 	spin_unlock (&list_lock);
@@ -1080,6 +1272,11 @@
 		goto exit;
 	}
 
+#ifdef CONFIG_PROC_FS
+	/* create mount point for pcihpfs */
+	slotdir = proc_mkdir(slotdir_name, proc_bus_pci_dir);
+#endif
+
 	info (DRIVER_DESC " version: " DRIVER_VERSION "\n");
 
 exit:
@@ -1089,6 +1286,11 @@
 static void __exit pci_hotplug_exit (void)
 {
 	unregister_filesystem(&pcihpfs_type);
+
+#ifdef CONFIG_PROC_FS
+	if (slotdir)
+		remove_proc_entry(slotdir_name, proc_bus_pci_dir);
+#endif
 }
 
 module_init(pci_hotplug_init);
diff -Nru a/drivers/i2c/i2c-philips-par.c b/drivers/i2c/i2c-philips-par.c
--- a/drivers/i2c/i2c-philips-par.c	Fri Sep 20 08:20:42 2002
+++ b/drivers/i2c/i2c-philips-par.c	Fri Sep 20 08:20:42 2002
@@ -201,6 +201,7 @@
 						NULL);
 	if (!adapter->pdev) {
 		printk(KERN_ERR "i2c-philips-par: Unable to register with parport.\n");
+		kfree(adapter);
 		return;
 	}
 
@@ -211,6 +212,7 @@
 
 	if (parport_claim_or_block(adapter->pdev) < 0 ) {
 		printk(KERN_ERR "i2c-philips-par: Could not claim parallel port.\n");
+		kfree(adapter);
 		return;
 	}
 	/* reset hardware to sane state */
diff -Nru a/drivers/ide/Makefile b/drivers/ide/Makefile
--- a/drivers/ide/Makefile	Fri Sep 20 08:20:46 2002
+++ b/drivers/ide/Makefile	Fri Sep 20 08:20:46 2002
@@ -9,18 +9,8 @@
 #
 export-objs := ide-iops.o ide-taskfile.o ide-proc.o ide.o ide-probe.o ide-dma.o ide-lib.o setup-pci.o
 
-all-subdirs	:= arm legacy pci ppc
-mod-subdirs	:= arm legacy pci ppc
-
-obj-y		:=
-obj-m		:=
-ide-obj-y	:=
-
-subdir-$(CONFIG_BLK_DEV_IDEPCI)	+= pci
-subdir-$(CONFIG_BLK_DEV_IDE) += legacy ppc arm pci
-
 # First come modules that register themselves with the core
-obj-y		+=	pci/idedriver-pci.o
+obj-$(CONFIG_BLK_DEV_IDEPCI)		+= pci/
 
 # Core IDE code - must come before legacy
 
@@ -35,13 +25,9 @@
 obj-$(CONFIG_BLK_DEV_ISAPNP)		+= ide-pnp.o
 
 ifeq ($(CONFIG_BLK_DEV_IDE),y)
-obj-$(CONFIG_PROC_FS)                  += ide-proc.o
+obj-$(CONFIG_PROC_FS)			+= ide-proc.o
 endif
 
-ifeq ($(CONFIG_BLK_DEV_IDE),y)
-  obj-y		+= legacy/idedriver-legacy.o
-  obj-y		+= ppc/idedriver-ppc.o
-  obj-y		+= arm/idedriver-arm.o
-endif
+obj-$(CONFIG_BLK_DEV_IDE)		+= legacy/ ppc/ arm/
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/ide/arm/Makefile b/drivers/ide/arm/Makefile
--- a/drivers/ide/arm/Makefile	Fri Sep 20 08:20:41 2002
+++ b/drivers/ide/arm/Makefile	Fri Sep 20 08:20:41 2002
@@ -1,9 +1,4 @@
 
-O_TARGET := idedriver-arm.o
-
-obj-y		:=
-obj-m		:=
-
 obj-$(CONFIG_BLK_DEV_IDE_ICSIDE)	+= icside.o
 obj-$(CONFIG_BLK_DEV_IDE_RAPIDE)	+= rapide.o
 
diff -Nru a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
--- a/drivers/ide/ide-dma.c	Fri Sep 20 08:20:46 2002
+++ b/drivers/ide/ide-dma.c	Fri Sep 20 08:20:46 2002
@@ -445,20 +445,6 @@
 	return 0;
 }
 
-static void ide_toggle_bounce(ide_drive_t *drive, int on)
-{
-	u64 addr = BLK_BOUNCE_HIGH;	/* dma64_addr_t */
-
-	if (on && drive->media == ide_disk) {
-		if (!PCI_DMA_BUS_IS_PHYS)
-			addr = BLK_BOUNCE_ANY;
-		else
-			addr = HWIF(drive)->pci_dev->dma_mask;
-	}
-
-	blk_queue_bounce_limit(&drive->queue, addr);
-}
-
 int __ide_dma_host_off (ide_drive_t *drive)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
diff -Nru a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
--- a/drivers/ide/ide-lib.c	Fri Sep 20 08:20:48 2002
+++ b/drivers/ide/ide-lib.c	Fri Sep 20 08:20:48 2002
@@ -386,3 +386,19 @@
 }
 
 EXPORT_SYMBOL_GPL(ide_get_best_pio_mode);
+
+void ide_toggle_bounce(ide_drive_t *drive, int on)
+{
+	u64 addr = BLK_BOUNCE_HIGH;	/* dma64_addr_t */
+
+	if (on && drive->media == ide_disk) {
+		if (!PCI_DMA_BUS_IS_PHYS)
+			addr = BLK_BOUNCE_ANY;
+		else
+			addr = HWIF(drive)->pci_dev->dma_mask;
+	}
+
+	blk_queue_bounce_limit(&drive->queue, addr);
+}
+
+EXPORT_SYMBOL(ide_toggle_bounce);
diff -Nru a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
--- a/drivers/ide/ide-probe.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/ide/ide-probe.c	Fri Sep 20 08:20:47 2002
@@ -778,6 +778,8 @@
 
 	/* This is a driver limit and could be eliminated. */
 	blk_queue_max_phys_segments(q, PRD_ENTRIES);
+
+	ide_toggle_bounce(drive, 1);
 }
 
 /*
diff -Nru a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
--- a/drivers/ide/ide-proc.c	Fri Sep 20 08:20:46 2002
+++ b/drivers/ide/ide-proc.c	Fri Sep 20 08:20:46 2002
@@ -548,7 +548,7 @@
 		len = sprintf(page, "(none)\n");
         else
 		len = sprintf(page,"%llu\n",
-			      (u64) ((ide_driver_t *)drive->driver)->capacity(drive));
+			      (long long) ((ide_driver_t *)drive->driver)->capacity(drive));
 	PROC_IDE_READ_RETURN(page,start,off,count,eof,len);
 }
 
diff -Nru a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
--- a/drivers/ide/ide-taskfile.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/ide/ide-taskfile.c	Fri Sep 20 08:20:41 2002
@@ -271,7 +271,7 @@
 				hwif->OUTB(0x80, IDE_CONTROL_REG);
 				high = task_read_24(drive);
 				sectors = ((u64)high << 24) | low;
-				printk(", LBAsect=%lld", sectors);
+				printk(", LBAsect=%lld", (long long) sectors);
 			} else {
 				u8 cur  = hwif->INB(IDE_SELECT_REG);
 				u8 low  = hwif->INB(IDE_LCYL_REG);
diff -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c
--- a/drivers/ide/ide.c	Fri Sep 20 08:20:44 2002
+++ b/drivers/ide/ide.c	Fri Sep 20 08:20:44 2002
@@ -567,7 +567,7 @@
 
 					sectors = ((u64)high << 24) | low;
 					printk(", LBAsect=%llu, high=%d, low=%d",
-					       (u64) sectors,
+					       (long long) sectors,
 					       high, low);
 				} else {
 					u8 cur = hwif->INB(IDE_SELECT_REG);
diff -Nru a/drivers/ide/legacy/Makefile b/drivers/ide/legacy/Makefile
--- a/drivers/ide/legacy/Makefile	Fri Sep 20 08:20:43 2002
+++ b/drivers/ide/legacy/Makefile	Fri Sep 20 08:20:43 2002
@@ -1,9 +1,4 @@
 
-O_TARGET := idedriver-legacy.o
-
-obj-y		:=
-obj-m		:=
-
 obj-$(CONFIG_BLK_DEV_ALI14XX)		+= ali14xx.o
 obj-$(CONFIG_BLK_DEV_DTC2278)		+= dtc2278.o
 obj-$(CONFIG_BLK_DEV_HT6560B)		+= ht6560b.o
diff -Nru a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c
--- a/drivers/ide/legacy/hd.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/ide/legacy/hd.c	Fri Sep 20 08:20:41 2002
@@ -846,7 +846,7 @@
 	}
 }
 
-int __init hd_init(void)
+static int __init hd_init(void)
 {
 	if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
 		printk("hd: unable to get major %d for hard disk\n",MAJOR_NR);
diff -Nru a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile
--- a/drivers/ide/pci/Makefile	Fri Sep 20 08:20:43 2002
+++ b/drivers/ide/pci/Makefile	Fri Sep 20 08:20:43 2002
@@ -1,9 +1,4 @@
 
-O_TARGET := idedriver-pci.o
-
-obj-y		:=
-obj-m		:=
-
 obj-$(CONFIG_BLK_DEV_ADMA100)		+= adma100.o
 obj-$(CONFIG_BLK_DEV_AEC62XX)		+= aec62xx.o
 obj-$(CONFIG_BLK_DEV_ALI15X3)		+= alim15x3.o
diff -Nru a/drivers/ide/ppc/Makefile b/drivers/ide/ppc/Makefile
--- a/drivers/ide/ppc/Makefile	Fri Sep 20 08:20:47 2002
+++ b/drivers/ide/ppc/Makefile	Fri Sep 20 08:20:47 2002
@@ -1,9 +1,4 @@
 
-O_TARGET := idedriver-ppc.o
-
-obj-y		:=
-obj-m		:=
-
 obj-$(CONFIG_BLK_DEV_MPC8xx_IDE)	+= mpc8xx.o
 obj-$(CONFIG_BLK_DEV_IDE_PMAC)		+= pmac.o
 obj-$(CONFIG_BLK_DEV_IDE_SWARM)		+= swarm.o
diff -Nru a/drivers/ieee1394/Makefile b/drivers/ieee1394/Makefile
--- a/drivers/ieee1394/Makefile	Fri Sep 20 08:20:48 2002
+++ b/drivers/ieee1394/Makefile	Fri Sep 20 08:20:48 2002
@@ -2,11 +2,8 @@
 # Makefile for the Linux IEEE 1394 implementation
 #
 
-O_TARGET := ieee1394drv.o
-
 export-objs := ieee1394_core.o ohci1394.o cmp.o
 
-list-multi := ieee1394.o
 ieee1394-objs := ieee1394_core.o ieee1394_transactions.o hosts.o \
 		 highlevel.o csr.o nodemgr.o
 
@@ -22,6 +19,3 @@
 obj-$(CONFIG_IEEE1394_CMP) += cmp.o
 
 include $(TOPDIR)/Rules.make
-
-ieee1394.o: $(ieee1394-objs)
-	$(LD) $(LDFLAGS) -r -o $@ $(ieee1394-objs)
diff -Nru a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
--- a/drivers/ieee1394/dv1394.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/ieee1394/dv1394.c	Fri Sep 20 08:20:47 2002
@@ -170,15 +170,6 @@
 
 static struct hpsb_highlevel *hl_handle; /* = NULL; */
 
-static LIST_HEAD(dv1394_devfs);
-struct dv1394_devfs_entry {
-	struct list_head list;
-    devfs_handle_t devfs;
-	char name[32];
-	struct dv1394_devfs_entry *parent;
-};
-static spinlock_t dv1394_devfs_lock = SPIN_LOCK_UNLOCKED;
-
 /* translate from a struct file* to the corresponding struct video_card* */
 
 static inline struct video_card* file_to_video_card(struct file *file)
@@ -2564,6 +2555,17 @@
 
 /*** DEVFS HELPERS *********************************************************/
 
+#ifdef CONFIG_DEVFS_FS
+
+static LIST_HEAD(dv1394_devfs);
+struct dv1394_devfs_entry {
+	struct list_head list;
+    devfs_handle_t devfs;
+	char name[32];
+	struct dv1394_devfs_entry *parent;
+};
+static spinlock_t dv1394_devfs_lock = SPIN_LOCK_UNLOCKED;
+
 struct dv1394_devfs_entry *
 dv1394_devfs_find( char *name)
 {
@@ -2693,6 +2695,7 @@
 		kfree(p);
 	}
 }
+#endif /* CONFIG_DEVFS */
 
 /*** IEEE1394 HPSB CALLBACKS ***********************************************/
 
@@ -2851,7 +2854,6 @@
 {
 	struct ti_ohci *ohci;
 	char buf[16];
-	struct dv1394_devfs_entry *devfs_entry;
 
 	/* We only work with the OHCI-1394 driver */
 	if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME))
@@ -2873,6 +2875,8 @@
 #endif
 
 #ifdef CONFIG_DEVFS_FS
+{
+	struct dv1394_devfs_entry *devfs_entry;
 	devfs_entry = dv1394_devfs_find("dv");
 	if (devfs_entry != NULL) {
 		snprintf(buf, sizeof(buf), "host%d", ohci->id);
@@ -2880,6 +2884,7 @@
 		dv1394_devfs_add_dir("NTSC", devfs_entry, NULL);
 		dv1394_devfs_add_dir("PAL", devfs_entry, NULL);
 	}
+}
 #endif
 	
 	dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE);
diff -Nru a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c
--- a/drivers/isdn/hisax/st5481_init.c	Fri Sep 20 08:20:48 2002
+++ b/drivers/isdn/hisax/st5481_init.c	Fri Sep 20 08:20:48 2002
@@ -59,7 +59,7 @@
  * This function will be called when the adapter is plugged
  * into the USB bus.
  */
-static int probe_st5481(struct usb_interface *intf
+static int probe_st5481(struct usb_interface *intf,
 			const struct usb_device_id *id)
 {
 	struct usb_device *dev = interface_to_usbdev(intf);
@@ -115,7 +115,7 @@
 	st5481_start(adapter);
 
 	dev_set_drvdata(&intf->dev, adapter);
-	return adapter;
+	return 0;
 
  err_b:
 	st5481_release_b(&adapter->bcs[0]);
diff -Nru a/drivers/md/linear.c b/drivers/md/linear.c
--- a/drivers/md/linear.c	Fri Sep 20 08:20:45 2002
+++ b/drivers/md/linear.c	Fri Sep 20 08:20:45 2002
@@ -144,7 +144,7 @@
 		if (!hash->dev1) {
 			printk ("linear_make_request : hash->dev1==NULL for block %ld\n",
 						block);
-			bio_io_error(bio);
+			bio_io_error(bio, bio->bi_size);
 			return 0;
 		}
 		tmp_dev = hash->dev1;
@@ -154,7 +154,7 @@
 	if (block >= (tmp_dev->size + tmp_dev->offset)
 				|| block < tmp_dev->offset) {
 		printk ("linear_make_request: Block %ld out of bounds on dev %s size %ld offset %ld\n", block, bdevname(tmp_dev->rdev->bdev), tmp_dev->size, tmp_dev->offset);
-		bio_io_error(bio);
+		bio_io_error(bio, bio->bi_size);
 		return 0;
 	}
 	bio->bi_bdev = tmp_dev->rdev->bdev;
diff -Nru a/drivers/md/md.c b/drivers/md/md.c
--- a/drivers/md/md.c	Fri Sep 20 08:20:44 2002
+++ b/drivers/md/md.c	Fri Sep 20 08:20:44 2002
@@ -144,7 +144,7 @@
 
 static int md_fail_request (request_queue_t *q, struct bio *bio)
 {
-	bio_io_error(bio);
+	bio_io_error(bio, bio->bi_size);
 	return 0;
 }
 
@@ -361,9 +361,13 @@
 }
 
 
-static void bi_complete(struct bio *bio)
+static int bi_complete(struct bio *bio, unsigned int bytes_done, int error)
 {
+	if (bio->bi_size)
+		return 1;
+
 	complete((struct completion*)bio->bi_private);
+	return 0;
 }
 
 static int sync_page_io(struct block_device *bdev, sector_t sector, int size,
diff -Nru a/drivers/md/multipath.c b/drivers/md/multipath.c
--- a/drivers/md/multipath.c	Fri Sep 20 08:20:46 2002
+++ b/drivers/md/multipath.c	Fri Sep 20 08:20:46 2002
@@ -109,17 +109,20 @@
 	struct bio *bio = mp_bh->master_bio;
 	multipath_conf_t *conf = mddev_to_conf(mp_bh->mddev);
 
-	bio_endio(bio, uptodate);
+	bio_endio(bio, bio->bi_size, uptodate ? 0 : -EIO);
 	mempool_free(mp_bh, conf->pool);
 }
 
-void multipath_end_request(struct bio *bio)
+int multipath_end_request(struct bio *bio, unsigned int bytes_done, int error)
 {
 	int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
 	struct multipath_bh * mp_bh = (struct multipath_bh *)(bio->bi_private);
 	multipath_conf_t *conf = mddev_to_conf(mp_bh->mddev);
 	mdk_rdev_t *rdev = conf->multipaths[mp_bh->path].rdev;
 
+	if (bio->bi_size)
+		return 1;
+
 	if (uptodate)
 		multipath_end_bh_io(mp_bh, uptodate);
 	else {
@@ -132,7 +135,7 @@
 		multipath_reschedule_retry(mp_bh);
 	}
 	atomic_dec(&rdev->nr_pending);
-	return;
+	return 0;
 }
 
 /*
diff -Nru a/drivers/md/raid0.c b/drivers/md/raid0.c
--- a/drivers/md/raid0.c	Fri Sep 20 08:20:46 2002
+++ b/drivers/md/raid0.c	Fri Sep 20 08:20:46 2002
@@ -323,7 +323,7 @@
 bad_zone1:
 	printk ("raid0_make_request bug: hash->zone1==NULL for block %ld\n", block);
  outerr:
-	bio_io_error(bio);
+	bio_io_error(bio, bio->bi_size);
 	return 0;
 }
 			   
diff -Nru a/drivers/md/raid1.c b/drivers/md/raid1.c
--- a/drivers/md/raid1.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/md/raid1.c	Fri Sep 20 08:20:41 2002
@@ -236,7 +236,7 @@
 {
 	struct bio *bio = r1_bio->master_bio;
 
-	bio_endio(bio, uptodate);
+	bio_endio(bio, bio->bi_size, uptodate ? 0 : -EIO);
 	free_r1bio(r1_bio);
 }
 
@@ -251,12 +251,15 @@
 		r1_bio->sector + (r1_bio->master_bio->bi_size >> 9);
 }
 
-static void end_request(struct bio *bio)
+static int end_request(struct bio *bio, unsigned int bytes_done, int error)
 {
 	int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
 	r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private);
 	int mirror;
 	conf_t *conf = mddev_to_conf(r1_bio->mddev);
+
+	if (bio->bi_size)
+		return 1;
 	
 	if (r1_bio->cmd == READ || r1_bio->cmd == READA)
 		mirror = r1_bio->read_disk;
@@ -313,6 +316,7 @@
 			raid_end_bio_io(r1_bio, uptodate);
 	}
 	atomic_dec(&conf->mirrors[mirror].rdev->nr_pending);
+	return 0;
 }
 
 /*
@@ -748,12 +752,15 @@
 #define REDIRECT_SECTOR KERN_ERR \
 "raid1: %s: redirecting sector %lu to another mirror\n"
 
-static void end_sync_read(struct bio *bio)
+static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error)
 {
 	int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
 	r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private);
 	conf_t *conf = mddev_to_conf(r1_bio->mddev);
 
+	if (bio->bi_size)
+		return 1;
+
 	if (r1_bio->read_bio != bio)
 		BUG();
 	update_head_pos(r1_bio->read_disk, r1_bio);
@@ -769,9 +776,10 @@
 		set_bit(R1BIO_Uptodate, &r1_bio->state);
 	atomic_dec(&conf->mirrors[r1_bio->read_disk].rdev->nr_pending);
 	reschedule_retry(r1_bio);
+	return 0;
 }
 
-static void end_sync_write(struct bio *bio)
+static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error)
 {
 	int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
 	r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private);
@@ -780,6 +788,9 @@
 	int i;
 	int mirror=0;
 
+	if (bio->bi_size)
+		return 1;
+
 	for (i = 0; i < conf->raid_disks; i++)
 		if (r1_bio->write_bios[i] == bio) {
 			mirror = i;
@@ -795,6 +806,7 @@
 		put_buf(r1_bio);
 	}
 	atomic_dec(&conf->mirrors[mirror].rdev->nr_pending);
+	return 0;
 }
 
 static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
diff -Nru a/drivers/md/raid5.c b/drivers/md/raid5.c
--- a/drivers/md/raid5.c	Fri Sep 20 08:20:43 2002
+++ b/drivers/md/raid5.c	Fri Sep 20 08:20:43 2002
@@ -321,13 +321,17 @@
 	conf->slab_cache = NULL;
 }
 
-static void raid5_end_read_request (struct bio * bi)
+static int raid5_end_read_request (struct bio * bi, unsigned int bytes_done,
+				   int error)
 {
  	struct stripe_head *sh = bi->bi_private;
 	raid5_conf_t *conf = sh->raid_conf;
 	int disks = conf->raid_disks, i;
 	int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
 
+	if (bi->bi_size)
+		return 1;
+
 	for (i=0 ; i<disks; i++)
 		if (bi == &sh->dev[i].req)
 			break;
@@ -335,7 +339,7 @@
 	PRINTK("end_read_request %lu/%d, count: %d, uptodate %d.\n", sh->sector, i, atomic_read(&sh->count), uptodate);
 	if (i == disks) {
 		BUG();
-		return;
+		return 0;
 	}
 
 	if (uptodate) {
@@ -384,9 +388,11 @@
 	clear_bit(R5_LOCKED, &sh->dev[i].flags);
 	set_bit(STRIPE_HANDLE, &sh->state);
 	release_stripe(sh);
+	return 0;
 }
 
-static void raid5_end_write_request (struct bio *bi)
+static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done,
+				    int error)
 {
  	struct stripe_head *sh = bi->bi_private;
 	raid5_conf_t *conf = sh->raid_conf;
@@ -394,6 +400,9 @@
 	unsigned long flags;
 	int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
 
+	if (bi->bi_size)
+		return 1;
+
 	for (i=0 ; i<disks; i++)
 		if (bi == &sh->dev[i].req)
 			break;
@@ -401,7 +410,7 @@
 	PRINTK("end_write_request %lu/%d, count %d, uptodate: %d.\n", sh->sector, i, atomic_read(&sh->count), uptodate);
 	if (i == disks) {
 		BUG();
-		return;
+		return 0;
 	}
 
 	spin_lock_irqsave(&conf->device_lock, flags);
@@ -414,6 +423,7 @@
 	set_bit(STRIPE_HANDLE, &sh->state);
 	__release_stripe(conf, sh);
 	spin_unlock_irqrestore(&conf->device_lock, flags);
+	return 0;
 }
 
 
@@ -1135,9 +1145,12 @@
 	spin_unlock(&sh->lock);
 
 	while ((bi=return_bi)) {
+		int bytes = bi->bi_size;
+
 		return_bi = bi->bi_next;
 		bi->bi_next = NULL;
-		bi->bi_end_io(bi);
+		bi->bi_size = 0;
+		bi->bi_end_io(bi, bytes, 0);
 	}
 	for (i=disks; i-- ;) 
 		if (sh->dev[i].flags & ((1<<R5_Wantwrite)|(1<<R5_Wantread))) {
@@ -1236,7 +1249,6 @@
 	last_sector = bi->bi_sector + (bi->bi_size>>9);
 
 	bi->bi_next = NULL;
-	set_bit(BIO_UPTODATE, &bi->bi_flags); /* will be cleared if error detected */
 	bi->bi_phys_segments = 1;	/* over-loaded to count active stripes */
 	for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) {
 		
@@ -1257,8 +1269,12 @@
 		}
 	}
 	spin_lock_irq(&conf->device_lock);
-	if (--bi->bi_phys_segments == 0) 
-		bi->bi_end_io(bi);
+	if (--bi->bi_phys_segments == 0) {
+		int bytes = bi->bi_size;
+
+		bi->bi_size = 0;
+		bi->bi_end_io(bi, bytes, 0);
+	}
 	spin_unlock_irq(&conf->device_lock);
 	return 0;
 }
diff -Nru a/drivers/message/fusion/Makefile b/drivers/message/fusion/Makefile
--- a/drivers/message/fusion/Makefile	Fri Sep 20 08:20:47 2002
+++ b/drivers/message/fusion/Makefile	Fri Sep 20 08:20:47 2002
@@ -1,14 +1,7 @@
 #
 # Makefile for the LSI Logic Fusion MPT (Message Passing Technology) drivers.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definition is now inherited from the
-# parent makefile.
-#
-# Note 3! If you want to turn on various debug defines for an extended period of
+# Note! If you want to turn on various debug defines for an extended period of
 # time but don't want them lingering around in the Makefile when you pass it on 
 # to someone else, use the MPT_CFLAGS env variable (thanks Steve). -nromer
 
@@ -53,27 +46,11 @@
 
 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC
 
-O_TARGET := fusion.o
-
 export-objs	:= mptbase.o mptscsih.o mptlan.o mptctl.o isense.o
 
-# ? what's list-multi for?
-#list-multi	:= fusion.o mptscsih.o
-
 obj-$(CONFIG_FUSION)		+= mptbase.o mptscsih.o
 obj-$(CONFIG_FUSION_ISENSE)	+= isense.o
 obj-$(CONFIG_FUSION_CTL)	+= mptctl.o
 obj-$(CONFIG_FUSION_LAN)	+= mptlan.o
 
-O_OBJS		:= $(filter-out		$(export-objs), $(obj-y))
-OX_OBJS		:= $(filter		$(export-objs), $(obj-y))
-M_OBJS		:= $(sort $(filter-out	$(export-objs), $(obj-m)))
-MX_OBJS		:= $(sort $(filter	$(export-objs), $(obj-m)))
-
 include $(TOPDIR)/Rules.make
-
-
-#  EXP...
-## Fusion MPT extra's...
-##mptscsih.o: $(mptscsih-objs)
-##	$(LD) -r -o $@ $(mptscsih-objs)
diff -Nru a/drivers/net/3c509.c b/drivers/net/3c509.c
--- a/drivers/net/3c509.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/net/3c509.c	Fri Sep 20 08:20:41 2002
@@ -692,7 +692,7 @@
 	outw(0x00, ioaddr + TX_FIFO);
 	/* ... and the packet rounded to a doubleword. */
 #ifdef  __powerpc__
-	outsl_unswapped(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
+	outsl_ns(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
 #else
 	outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
 #endif
@@ -903,7 +903,7 @@
 
 				/* 'skb->data' points to the start of sk_buff data area. */
 #ifdef  __powerpc__
-				insl_unswapped(ioaddr+RX_FIFO, skb_put(skb,pkt_len),
+				insl_ns(ioaddr+RX_FIFO, skb_put(skb,pkt_len),
 							   (pkt_len + 3) >> 2);
 #else
 				insl(ioaddr + RX_FIFO, skb_put(skb,pkt_len),
diff -Nru a/drivers/net/3c59x.c b/drivers/net/3c59x.c
--- a/drivers/net/3c59x.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/net/3c59x.c	Fri Sep 20 08:20:41 2002
@@ -1483,12 +1483,13 @@
 		mii_reg1 = mdio_read(dev, vp->phys[0], 1);
 		mii_reg5 = mdio_read(dev, vp->phys[0], 5);
 		if (mii_reg5 == 0xffff  ||  mii_reg5 == 0x0000) {
-			;					/* No MII device or no link partner report */
+			netif_carrier_off(dev); /* No MII device or no link partner report */
 		} else {
 			mii_reg5 &= vp->advertising;
 			if ((mii_reg5 & 0x0100) != 0	/* 100baseTx-FD */
 				 || (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */
 			vp->full_duplex = 1;
+			netif_carrier_on(dev);
 		}
 		vp->partner_flow_ctrl = ((mii_reg5 & 0x0400) != 0);
 		if (vortex_debug > 1)
@@ -1692,13 +1693,16 @@
 	switch (dev->if_port) {
 	case XCVR_10baseT:  case XCVR_100baseTx:  case XCVR_100baseFx:
 		if (media_status & Media_LnkBeat) {
+			netif_carrier_on(dev);
 			ok = 1;
 			if (vortex_debug > 1)
 				printk(KERN_DEBUG "%s: Media %s has link beat, %x.\n",
 					   dev->name, media_tbl[dev->if_port].name, media_status);
-		} else if (vortex_debug > 1)
+		} else if (vortex_debug > 1) {
+			netif_carrier_off(dev);
 			printk(KERN_DEBUG "%s: Media %s has no link beat, %x.\n",
 				   dev->name, media_tbl[dev->if_port].name, media_status);
+		}
 		break;
 	case XCVR_MII: case XCVR_NWAY:
 		{
@@ -1707,7 +1711,7 @@
 			if (vortex_debug > 2)
 				printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n",
 					dev->name, mii_status);
-			if (mii_status & 0x0004) {
+			if (mii_status & BMSR_LSTATUS) {
 				int mii_reg5 = mdio_read(dev, vp->phys[0], 5);
 				if (! vp->force_fd  &&  mii_reg5 != 0xffff) {
 					int duplex;
@@ -1731,6 +1735,9 @@
 						/* AKPM: bug: should reset Tx and Rx after setting Duplex.  Page 180 */
 					}
 				}
+				netif_carrier_on(dev);
+			} else {
+				netif_carrier_off(dev);
 			}
 		}
 		break;
diff -Nru a/drivers/net/8139cp.c b/drivers/net/8139cp.c
--- a/drivers/net/8139cp.c	Fri Sep 20 08:20:46 2002
+++ b/drivers/net/8139cp.c	Fri Sep 20 08:20:46 2002
@@ -639,13 +639,13 @@
 		cp_rx_skb(cp, skb, desc);
 
 rx_next:
+		cp->rx_ring[rx_tail].opts2 = 0;
+		cp->rx_ring[rx_tail].addr = cpu_to_le64(mapping);
 		if (rx_tail == (CP_RX_RING_SIZE - 1))
 			desc->opts1 = cpu_to_le32(DescOwn | RingEnd |
 						  cp->rx_buf_sz);
 		else
 			desc->opts1 = cpu_to_le32(DescOwn | cp->rx_buf_sz);
-		cp->rx_ring[rx_tail].opts2 = 0;
-		cp->rx_ring[rx_tail].addr = cpu_to_le64(mapping);
 		rx_tail = NEXT_RX(rx_tail);
 	}
 
@@ -669,6 +669,8 @@
 		printk(KERN_DEBUG "%s: intr, status %04x cmd %02x cpcmd %04x\n",
 		        dev->name, status, cpr8(Cmd), cpr16(CpCmd));
 
+	cpw16_f(IntrStatus, status);
+
 	spin_lock(&cp->lock);
 
 	if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr))
@@ -676,8 +678,6 @@
 	if (status & (TxOK | TxErr | TxEmpty | SWInt))
 		cp_tx(cp);
 
-	cpw16_f(IntrStatus, status);
-
 	if (status & PciErr) {
 		u16 pci_status;
 
@@ -781,7 +781,6 @@
 
 		len = skb->len;
 		mapping = pci_map_single(cp->pdev, skb->data, len, PCI_DMA_TODEVICE);
-		eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
 		CP_VLAN_TX_TAG(txd, vlan_tag);
 		txd->addr = cpu_to_le64(mapping);
 		wmb();
@@ -811,7 +810,7 @@
 		entry = NEXT_TX(entry);
 	} else {
 		struct cp_desc *txd;
-		u32 first_len;
+		u32 first_len, first_eor;
 		dma_addr_t first_mapping;
 		int frag, first_entry = entry;
 #ifdef CP_TX_CHECKSUM
@@ -821,6 +820,7 @@
 		/* We must give this initial chunk to the device last.
 		 * Otherwise we could race with the device.
 		 */
+		first_eor = eor;
 		first_len = skb->len - skb->data_len;
 		first_mapping = pci_map_single(cp->pdev, skb->data,
 					       first_len, PCI_DMA_TODEVICE);
@@ -879,17 +879,19 @@
 #ifdef CP_TX_CHECKSUM
 		if (skb->ip_summed == CHECKSUM_HW) {
 			if (ip->protocol == IPPROTO_TCP)
-				txd->opts1 = cpu_to_le32(first_len | FirstFrag |
-							DescOwn | IPCS | TCPCS);
+				txd->opts1 = cpu_to_le32(first_eor | first_len |
+							 FirstFrag | DescOwn |
+							 IPCS | TCPCS);
 			else if (ip->protocol == IPPROTO_UDP)
-				txd->opts1 = cpu_to_le32(first_len | FirstFrag |
-							DescOwn | IPCS | UDPCS);
+				txd->opts1 = cpu_to_le32(first_eor | first_len |
+							 FirstFrag | DescOwn |
+							 IPCS | UDPCS);
 			else
 				BUG();
 		} else
 #endif
-			txd->opts1 = cpu_to_le32(first_len | FirstFrag |
-						 DescOwn);
+			txd->opts1 = cpu_to_le32(first_eor | first_len |
+						 FirstFrag | DescOwn);
 		wmb();
 	}
 	cp->tx_head = entry;
@@ -1088,14 +1090,14 @@
 		cp->rx_skb[i].skb = skb;
 		cp->rx_skb[i].frag = 0;
 
+		cp->rx_ring[i].opts2 = 0;
+		cp->rx_ring[i].addr = cpu_to_le64(cp->rx_skb[i].mapping);
 		if (i == (CP_RX_RING_SIZE - 1))
 			cp->rx_ring[i].opts1 =
 				cpu_to_le32(DescOwn | RingEnd | cp->rx_buf_sz);
 		else
 			cp->rx_ring[i].opts1 =
 				cpu_to_le32(DescOwn | cp->rx_buf_sz);
-		cp->rx_ring[i].opts2 = 0;
-		cp->rx_ring[i].addr = cpu_to_le64(cp->rx_skb[i].mapping);
 	}
 
 	return 0;
@@ -1208,7 +1210,11 @@
 		printk(KERN_DEBUG "%s: disabling interface\n", dev->name);
 
 	netif_stop_queue(dev);
+
+	spin_lock_irq(&cp->lock);
 	cp_stop_hw(cp);
+	spin_unlock_irq(&cp->lock);
+
 	free_irq(dev->irq, dev);
 	cp_free_rings(cp);
 	return 0;
diff -Nru a/drivers/net/8139too.c b/drivers/net/8139too.c
--- a/drivers/net/8139too.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/net/8139too.c	Fri Sep 20 08:20:41 2002
@@ -1746,10 +1746,6 @@
 				tp->stats.tx_carrier_errors++;
 			if (txstatus & TxOutOfWindow)
 				tp->stats.tx_window_errors++;
-#ifdef ETHER_STATS
-			if ((txstatus & 0x0f000000) == 0x0f000000)
-				tp->stats.collisions16++;
-#endif
 		} else {
 			if (txstatus & TxUnderrun) {
 				/* Add 64 to the Tx FIFO threshold. */
diff -Nru a/drivers/net/Config.help b/drivers/net/Config.help
--- a/drivers/net/Config.help	Fri Sep 20 08:20:41 2002
+++ b/drivers/net/Config.help	Fri Sep 20 08:20:41 2002
@@ -1226,17 +1226,6 @@
   More specific information and updates are available from
   <http://www.scyld.com/network/natsemi.html>.
 
-CONFIG_NATSEMI_CABLE_MAGIC
-  Some systems see lots of errors with NatSemi ethernet controllers
-  on certain cables.  If you are seeing lots of errors, try turning
-  this option on.  Some boards have incorrect values for supporting
-  resistors that can cause this change to break.  If you turn this
-  option on and your network suddenly stops working, turn this
-  option off.
-
-  Say N unless you are certain you need this option.
-  Vendors should not enable this option by default.
-
 CONFIG_SK_G16
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available from
@@ -1535,6 +1524,13 @@
   This driver is for the Sundance "Alta" chip.
   More specific information and updates are available from
   <http://www.scyld.com/network/sundance.html>.
+
+CONFIG_SUNDANCE_MMIO
+  Enable memory-mapped I/O for interaction with Sundance NIC registers.
+  Do NOT enable this by default, PIO (enabled when MMIO is disabled)
+  is known to solve bugs on certain chips.
+
+  If unsure, say N.
 
 CONFIG_ZNET
   The Zenith Z-Note notebook computer has a built-in network
diff -Nru a/drivers/net/Config.in b/drivers/net/Config.in
--- a/drivers/net/Config.in	Fri Sep 20 08:20:41 2002
+++ b/drivers/net/Config.in	Fri Sep 20 08:20:41 2002
@@ -165,9 +165,6 @@
       dep_tristate '    Mylex EISA LNE390A/B support (EXPERIMENTAL)' CONFIG_LNE390 $CONFIG_EISA $CONFIG_EXPERIMENTAL
       dep_tristate '    Myson MTD-8xx PCI Ethernet support' CONFIG_FEALNX $CONFIG_PCI
       dep_tristate '    National Semiconductor DP8381x series PCI Ethernet support' CONFIG_NATSEMI $CONFIG_PCI
-      if [ "$CONFIG_NATSEMI" = "y" -o "$CONFIG_NATSEMI" = "m" ]; then
-        bool       '      NatSemi workaround for high errors' CONFIG_NATSEMI_CABLE_MAGIC
-      fi
       dep_tristate '    PCI NE2000 and clones support (see help)' CONFIG_NE2K_PCI $CONFIG_PCI
       dep_tristate '    Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL
       dep_tristate '    Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL
@@ -180,6 +177,7 @@
       dep_tristate '    SiS 900/7016 PCI Fast Ethernet Adapter support' CONFIG_SIS900 $CONFIG_PCI
       dep_tristate '    SMC EtherPower II' CONFIG_EPIC100 $CONFIG_PCI
       dep_tristate '    Sundance Alta support' CONFIG_SUNDANCE $CONFIG_PCI
+      dep_mbool '      Use MMIO instead of PIO' CONFIG_SUNDANCE_MMIO $CONFIG_SUNDANCE
       if [ "$CONFIG_PCI" = "y" -o "$CONFIG_EISA" = "y" ]; then
          tristate '    TI ThunderLAN support' CONFIG_TLAN
       fi
diff -Nru a/drivers/net/Makefile b/drivers/net/Makefile
--- a/drivers/net/Makefile	Fri Sep 20 08:20:44 2002
+++ b/drivers/net/Makefile	Fri Sep 20 08:20:44 2002
@@ -70,7 +70,7 @@
 obj-$(CONFIG_AIRONET4500_CS)	+= aironet4500_proc.o
 
 obj-$(CONFIG_WINBOND_840) += mii.o
-obj-$(CONFIG_SUNDANCE) += sundance.o
+obj-$(CONFIG_SUNDANCE) += sundance.o mii.o
 obj-$(CONFIG_HAMACHI) += hamachi.o
 obj-$(CONFIG_NET) += Space.o setup.o net_init.o loopback.o
 obj-$(CONFIG_SEEQ8005) += seeq8005.o
diff -Nru a/drivers/net/acenic.c b/drivers/net/acenic.c
--- a/drivers/net/acenic.c	Fri Sep 20 08:20:46 2002
+++ b/drivers/net/acenic.c	Fri Sep 20 08:20:46 2002
@@ -47,6 +47,7 @@
  *                                       flushing the Jumbo ring.
  *   Hans Grobler <grobh@sun.ac.za>:     Memory leak fixes in the
  *                                       driver init path.
+ *   Grant Grundler <grundler@cup.hp.com>: PCI write posting fixes.
  */
 
 #include <linux/config.h>
@@ -120,6 +121,9 @@
 #ifndef PCI_DEVICE_ID_FARALLON_PN9000SX
 #define PCI_DEVICE_ID_FARALLON_PN9000SX	0x1a
 #endif
+#ifndef PCI_DEVICE_ID_FARALLON_PN9100T
+#define PCI_DEVICE_ID_FARALLON_PN9100T  0xfa
+#endif
 #ifndef PCI_VENDOR_ID_SGI
 #define PCI_VENDOR_ID_SGI		0x10a9
 #endif
@@ -140,10 +144,13 @@
 	{ PCI_VENDOR_ID_NETGEAR, PCI_DEVICE_ID_NETGEAR_GA620T,
 	  PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
 	/*
-	 * Farallon used the DEC vendor ID on their cards incorrectly.
+	 * Farallon used the DEC vendor ID on their cards incorrectly,
+	 * then later Alteon's ID.
 	 */
 	{ PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_FARALLON_PN9000SX,
 	  PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
+	{ PCI_VENDOR_ID_ALTEON, PCI_DEVICE_ID_FARALLON_PN9100T,
+	  PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
 	{ PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_ACENIC,
 	  PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, },
 	{ }
@@ -173,15 +180,27 @@
 #endif
 
 #ifndef SET_MODULE_OWNER
-#define SET_MODULE_OWNER(dev)		{do{} while(0);}
+#define SET_MODULE_OWNER(dev)		do{} while(0)
 #define ACE_MOD_INC_USE_COUNT		MOD_INC_USE_COUNT
 #define ACE_MOD_DEC_USE_COUNT		MOD_DEC_USE_COUNT
 #else
-#define ACE_MOD_INC_USE_COUNT		{do{} while(0);}
-#define ACE_MOD_DEC_USE_COUNT		{do{} while(0);}
+#define ACE_MOD_INC_USE_COUNT		do{} while(0)
+#define ACE_MOD_DEC_USE_COUNT		do{} while(0)
 #endif
 
 
+#if LINUX_VERSION_CODE >= 0x2051c
+#define ace_sync_irq(irq)	synchronize_irq(irq)
+#else
+#define ace_sync_irq(irq)	synchronize_irq()
+#endif
+
+#if LINUX_VERSION_CODE < 0x2051e
+#define local_irq_save(flags)		do{__save_flags(flags) ; \
+					   __cli();} while(0)
+#define local_irq_restore(flags)	__restore_flags(flags)
+#endif
+
 #if (LINUX_VERSION_CODE < 0x02030d)
 #define pci_resource_start(dev, bar)	dev->base_address[bar]
 #elif (LINUX_VERSION_CODE < 0x02032c)
@@ -192,6 +211,7 @@
 #define net_device device
 #endif
 
+
 #if (LINUX_VERSION_CODE < 0x02032a)
 typedef u32 dma_addr_t;
 
@@ -215,8 +235,6 @@
 	(((u64)(mask) & 0xffffffff00000000) == 0 ? 0 : -EIO)
 #define pci_dma_supported(dev, mask)		\
 	(((u64)(mask) & 0xffffffff00000000) == 0 ? 1 : 0)
-#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
-#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
 
 #elif (LINUX_VERSION_CODE < 0x02040d)
 
@@ -240,8 +258,15 @@
 }
 #define pci_unmap_page(cookie, dma_addr, size, dir)	\
 	pci_unmap_single(cookie, dma_addr, size, dir)
+#endif
+
+#if (LINUX_VERSION_CODE < 0x020412)
 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
 #define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
+#define pci_unmap_addr(PTR, ADDR_NAME)		0
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL)	do{} while(0)
+#define pci_unmap_len(PTR, LEN_NAME)		0
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL)	do{} while(0)
 #endif
 
 
@@ -259,7 +284,7 @@
 #define dev_kfree_skb_irq(a)			dev_kfree_skb(a)
 #define netif_wake_queue(dev)			clear_bit(0, &dev->tbusy)
 #define netif_stop_queue(dev)			set_bit(0, &dev->tbusy)
-#define late_stop_netif_stop_queue(dev)		{do{} while(0);}
+#define late_stop_netif_stop_queue(dev)		do{} while(0)
 #define early_stop_netif_stop_queue(dev)	test_and_set_bit(0,&dev->tbusy)
 #define early_stop_netif_wake_queue(dev)	netif_wake_queue(dev)
 
@@ -273,7 +298,7 @@
 #define ace_mark_net_bh()			mark_bh(NET_BH)
 #define netif_queue_stopped(dev)		dev->tbusy
 #define netif_running(dev)			dev->start
-#define ace_if_down(dev)			{do{dev->start = 0;} while(0);}
+#define ace_if_down(dev)			do{dev->start = 0;} while(0)
 
 #define tasklet_struct				tq_struct
 static inline void tasklet_schedule(struct tasklet_struct *tasklet)
@@ -291,13 +316,13 @@
 	tasklet->routine = (void (*)(void *))func;
 	tasklet->data = (void *)data;
 }
-#define tasklet_kill(tasklet)			{do{} while(0);}
+#define tasklet_kill(tasklet)			do{} while(0)
 #else
 #define late_stop_netif_stop_queue(dev)		netif_stop_queue(dev)
 #define early_stop_netif_stop_queue(dev)	0
-#define early_stop_netif_wake_queue(dev)	{do{} while(0);}
-#define ace_mark_net_bh()			{do{} while(0);}
-#define ace_if_down(dev)			{do{} while(0);}
+#define early_stop_netif_wake_queue(dev)	do{} while(0)
+#define ace_mark_net_bh()			do{} while(0)
+#define ace_if_down(dev)			do{} while(0)
 #endif
 
 #if (LINUX_VERSION_CODE >= 0x02031b)
@@ -313,7 +338,7 @@
 
 #ifndef ARCH_HAS_PREFETCHW
 #ifndef prefetchw
-#define prefetchw(x)				{do{} while(0);}
+#define prefetchw(x)				do{} while(0)
 #endif
 #endif
 
@@ -568,7 +593,7 @@
 static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1};
 
 static char version[] __initdata = 
-  "acenic.c: v0.89 03/15/2002  Jes Sorensen, linux-acenic@SunSITE.dk\n"
+  "acenic.c: v0.92 08/05/2002  Jes Sorensen, linux-acenic@SunSITE.dk\n"
   "                            http://home.cern.ch/~jes/gige/acenic.html\n";
 
 static struct net_device *root_dev;
@@ -611,6 +636,8 @@
 		 */
 		    !((pdev->vendor == PCI_VENDOR_ID_DEC) &&
 		      (pdev->device == PCI_DEVICE_ID_FARALLON_PN9000SX)) &&
+		    !((pdev->vendor == PCI_VENDOR_ID_ALTEON) &&
+		      (pdev->device == PCI_DEVICE_ID_FARALLON_PN9100T)) &&
 		    !((pdev->vendor == PCI_VENDOR_ID_SGI) &&
 		      (pdev->device == PCI_DEVICE_ID_SGI_ACENIC)))
 			continue;
@@ -664,6 +691,11 @@
 			printk(version);
 		}
 
+		if (pci_enable_device(pdev)) {
+			kfree(dev);
+			continue;
+		}
+
 		/*
 		 * Enable master mode before we start playing with the
 		 * pci_command word since pci_set_master() will modify
@@ -708,9 +740,17 @@
 
 		switch(pdev->vendor) {
 		case PCI_VENDOR_ID_ALTEON:
-			strncpy(ap->name, "AceNIC Gigabit Ethernet",
-				sizeof (ap->name));
-			printk(KERN_INFO "%s: Alteon AceNIC ", dev->name);
+			if (pdev->device == PCI_DEVICE_ID_FARALLON_PN9100T) {
+				strncpy(ap->name, "Farallon PN9100-T "
+					"Gigabit Ethernet", sizeof (ap->name));
+				printk(KERN_INFO "%s: Farallon PN9100-T ",
+				       dev->name);
+			} else {
+				strncpy(ap->name, "AceNIC Gigabit Ethernet",
+					sizeof (ap->name));
+				printk(KERN_INFO "%s: Alteon AceNIC ",
+				       dev->name);
+			}
 			break;
 		case PCI_VENDOR_ID_3COM:
 			strncpy(ap->name, "3Com 3C985 Gigabit Ethernet",
@@ -846,6 +886,7 @@
 		 * This clears any pending interrupts
 		 */
 		writel(1, &regs->Mb0Lo);
+		readl(&regs->CpuCtrl);	/* flush */
 
 		/*
 		 * Make sure no other CPUs are processing interrupts
@@ -856,7 +897,7 @@
 		 * Then release the RX buffers - jumbo buffers were
 		 * already released in ace_close().
 		 */
-		synchronize_irq();
+		ace_sync_irq(root_dev->irq);
 
 		for (i = 0; i < RX_STD_RING_ENTRIES; i++) {
 			struct sk_buff *skb = ap->skb->rx_std_skbuff[i].skb;
@@ -1138,34 +1179,30 @@
 	 * to any crashes involving the NIC
 	 */
 	writel(HW_RESET | (HW_RESET << 24), &regs->HostCtrl);
-	wmb();
+	readl(&regs->HostCtrl);		/* PCI write posting */
+	udelay(5);
 
 	/*
-	 * Don't access any other registes before this point!
+	 * Don't access any other registers before this point!
 	 */
 #ifdef __BIG_ENDIAN
 	/*
 	 * This will most likely need BYTE_SWAP once we switch
 	 * to using __raw_writel()
 	 */
-#ifdef __parisc__
-	writel((WORD_SWAP | BYTE_SWAP | CLR_INT |
-		((WORD_SWAP | BYTE_SWAP | CLR_INT) << 24)),
-	       &regs->HostCtrl);
-#else
 	writel((WORD_SWAP | CLR_INT | ((WORD_SWAP | CLR_INT) << 24)),
 	       &regs->HostCtrl);
-#endif
 #else
 	writel((CLR_INT | WORD_SWAP | ((CLR_INT | WORD_SWAP) << 24)),
 	       &regs->HostCtrl);
 #endif
-	mb();
+	readl(&regs->HostCtrl);		/* PCI write posting */
 
 	/*
 	 * Stop the NIC CPU and clear pending interrupts
 	 */
 	writel(readl(&regs->CpuCtrl) | CPU_HALT, &regs->CpuCtrl);
+	readl(&regs->CpuCtrl);		/* PCI write posting */
 	writel(0, &regs->Mb0Lo);
 
 	tig_ver = readl(&regs->HostCtrl) >> 28;
@@ -1186,6 +1223,7 @@
 		       tig_ver, tigon2FwReleaseMajor, tigon2FwReleaseMinor,
 		       tigon2FwReleaseFix);
 		writel(readl(&regs->CpuBCtrl) | CPU_HALT, &regs->CpuBCtrl);
+		readl(&regs->CpuBCtrl);		/* PCI write posting */
 		/*
 		 * The SRAM bank size does _not_ indicate the amount
 		 * of memory on the card, it controls the _bank_ size!
@@ -1217,7 +1255,7 @@
 	writel(ACE_BYTE_SWAP_DMA | ACE_WARN | ACE_FATAL |
 	       ACE_WORD_SWAP_BD | ACE_NO_JUMBO_FRAG, &regs->ModeStat);
 #endif
-	mb();
+	readl(&regs->ModeStat);		/* PCI write posting */
 
 	mac1 = 0;
 	for(i = 0; i < 4; i++) {
@@ -1355,7 +1393,7 @@
 	tmp &= ~DMA_READ_WRITE_MASK;
 	tmp |= DMA_READ_MAX_128;
 	/*
-	 * All the docs sy MUST NOT. Well, I did.
+	 * All the docs say MUST NOT. Well, I did.
 	 * Nothing terrible happens, if we load wrong size.
 	 * Bit w&i still works better!
 	 */
@@ -1365,6 +1403,13 @@
 
 #if 0
 	/*
+	 * The Host PCI bus controller driver has to set FBB.
+	 * If all devices on that PCI bus support FBB, then the controller
+	 * can enable FBB support in the Host PCI Bus controller (or on
+	 * the PCI-PCI bridge if that applies).
+	 * -ggg
+	 */
+	/*
 	 * I have received reports from people having problems when this
 	 * bit is enabled.
 	 */
@@ -1445,9 +1490,9 @@
 	set_aceaddr(&info->evt_ctrl.rngptr, ap->evt_ring_dma);
 	info->evt_ctrl.flags = 0;
 
-	set_aceaddr(&info->evt_prd_ptr, ap->evt_prd_dma);
 	*(ap->evt_prd) = 0;
 	wmb();
+	set_aceaddr(&info->evt_prd_ptr, ap->evt_prd_dma);
 	writel(0, &regs->EvtCsm);
 
 	set_aceaddr(&info->cmd_ctrl.rngptr, 0x100);
@@ -1579,7 +1624,13 @@
 
 	writel(0, &regs->MaskInt);
 	writel(1, &regs->IfIdx);
+#if 0
+	/*
+	 * McKinley boxes do not like us fiddling with AssistState
+	 * this early
+	 */
 	writel(1, &regs->AssistState);
+#endif
 
 	writel(DEF_STAT, &regs->TuneStatTicks);
 	writel(DEF_TRACE, &regs->TuneTrace);
@@ -1689,10 +1740,19 @@
 	 */
 	memset(&ap->stats, 0, sizeof(ap->stats));
 
+       /*
+	* Enable DMA engine now.
+	* If we do this sooner, Mckinley box pukes.
+	* I assume it's because Tigon II DMA engine wants to check
+	* *something* even before the CPU is started.
+	*/
+       writel(1, &regs->AssistState);  /* enable DMA */
+
 	/*
 	 * Start the NIC CPU
 	 */
 	writel(readl(&regs->CpuCtrl) & ~(CPU_HALT|CPU_TRACE), &regs->CpuCtrl);
+	readl(&regs->CpuCtrl);
 
 	/*
 	 * Wait for the firmware to spin up - max 3 seconds.
@@ -1705,6 +1765,7 @@
 
 		ace_dump_trace(ap);
 		writel(readl(&regs->CpuCtrl) | CPU_HALT, &regs->CpuCtrl);
+		readl(&regs->CpuCtrl);
 
 		/* aman@sgi.com - account for badly behaving firmware/NIC:
 		 * - have observed that the NIC may continue to generate
@@ -1719,6 +1780,7 @@
 			writel(readl(&regs->CpuBCtrl) | CPU_HALT,
 			       &regs->CpuBCtrl);
 		writel(0, &regs->Mb0Lo);
+		readl(&regs->Mb0Lo);
 
 		ecode = -EBUSY;
 		goto init_error;
@@ -2393,6 +2455,7 @@
 	 * threads and it is wrong even for that case.
 	 */
 	writel(0, &regs->Mb0Lo);
+	readl(&regs->Mb0Lo);
 
 	/*
 	 * There is no conflict between transmit handling in
@@ -2496,12 +2559,13 @@
 	struct ace_private *ap = dev->priv;
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	local_irq_save(flags);
+	ace_mask_irq(dev);
 
 	ap->vlgrp = grp;
 
-	restore_flags(flags);
+	ace_unmask_irq(dev);
+	local_irq_restore(flags);
 }
 
 
@@ -2510,13 +2574,14 @@
 	struct ace_private *ap = dev->priv;
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	local_irq_save(flags);
+	ace_mask_irq(dev);
 
 	if (ap->vlgrp)
 		ap->vlgrp->vlan_devices[vid] = NULL;
 
-	restore_flags(flags);
+	ace_unmask_irq(dev);
+	local_irq_restore(flags);
 }
 #endif /* ACENIC_DO_VLAN */
 
@@ -2620,8 +2685,9 @@
 	 * Make sure one CPU is not processing packets while
 	 * buffers are being released by another.
 	 */
-	save_flags(flags);
-	cli();
+
+	local_irq_save(flags);
+	ace_mask_irq(dev);
 
 	for (i = 0; i < ACE_TX_RING_ENTRIES(ap); i++) {
 		struct sk_buff *skb;
@@ -2658,7 +2724,8 @@
 		ace_issue_cmd(regs, &cmd);
 	}
 
-	restore_flags(flags);
+	ace_unmask_irq(dev);
+	local_irq_restore(flags);
 
 	ACE_MOD_DEC_USE_COUNT;
 	return 0;
@@ -2877,7 +2944,7 @@
 		}
 	} else {
 		while (test_and_set_bit(0, &ap->jumbo_refill_busy));
-		synchronize_irq();
+		ace_sync_irq(dev->irq);
 		ace_set_rxtx_parms(dev, 0);
 		if (ap->jumbo) {
 			struct cmd cmd;
@@ -3259,22 +3326,27 @@
 {
 	u32 local;
 
+	readl(&regs->LocalCtrl);
 	udelay(ACE_SHORT_DELAY);
 	local = readl(&regs->LocalCtrl);
 	local |= EEPROM_DATA_OUT | EEPROM_WRITE_ENABLE;
 	writel(local, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 	udelay(ACE_SHORT_DELAY);
 	local |= EEPROM_CLK_OUT;
 	writel(local, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 	udelay(ACE_SHORT_DELAY);
 	local &= ~EEPROM_DATA_OUT;
 	writel(local, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 	udelay(ACE_SHORT_DELAY);
 	local &= ~EEPROM_CLK_OUT;
 	writel(local, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 }
 
@@ -3289,6 +3361,7 @@
 	local &= ~EEPROM_DATA_OUT;
 	local |= EEPROM_WRITE_ENABLE;
 	writel(local, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 
 	for (i = 0; i < 8; i++, magic <<= 1) {
@@ -3298,15 +3371,18 @@
 		else
 			local &= ~EEPROM_DATA_OUT;
 		writel(local, &regs->LocalCtrl);
+		readl(&regs->LocalCtrl);
 		mb();
 
 		udelay(ACE_SHORT_DELAY);
 		local |= EEPROM_CLK_OUT;
 		writel(local, &regs->LocalCtrl);
+		readl(&regs->LocalCtrl);
 		mb();
 		udelay(ACE_SHORT_DELAY);
 		local &= ~(EEPROM_CLK_OUT | EEPROM_DATA_OUT);
 		writel(local, &regs->LocalCtrl);
+		readl(&regs->LocalCtrl);
 		mb();
 	}
 }
@@ -3320,10 +3396,12 @@
 	local = readl(&regs->LocalCtrl);
 	local &= ~EEPROM_WRITE_ENABLE;
 	writel(local, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 	udelay(ACE_LONG_DELAY);
 	local |= EEPROM_CLK_OUT;
 	writel(local, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 	udelay(ACE_SHORT_DELAY);
 	/* sample data in middle of high clk */
@@ -3331,6 +3409,7 @@
 	udelay(ACE_SHORT_DELAY);
 	mb();
 	writel(readl(&regs->LocalCtrl) & ~EEPROM_CLK_OUT, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 
 	return state;
@@ -3345,18 +3424,22 @@
 	local = readl(&regs->LocalCtrl);
 	local |= EEPROM_WRITE_ENABLE;
 	writel(local, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 	udelay(ACE_SHORT_DELAY);
 	local &= ~EEPROM_DATA_OUT;
 	writel(local, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 	udelay(ACE_SHORT_DELAY);
 	local |= EEPROM_CLK_OUT;
 	writel(local, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 	udelay(ACE_SHORT_DELAY);
 	local |= EEPROM_DATA_OUT;
 	writel(local, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 	udelay(ACE_LONG_DELAY);
 	local &= ~EEPROM_CLK_OUT;
@@ -3433,10 +3516,12 @@
 		local = readl(&regs->LocalCtrl);
 		local &= ~EEPROM_WRITE_ENABLE;
 		writel(local, &regs->LocalCtrl);
+		readl(&regs->LocalCtrl);
 		udelay(ACE_LONG_DELAY);
 		mb();
 		local |= EEPROM_CLK_OUT;
 		writel(local, &regs->LocalCtrl);
+		readl(&regs->LocalCtrl);
 		mb();
 		udelay(ACE_SHORT_DELAY);
 		/* sample data mid high clk */
@@ -3447,11 +3532,13 @@
 		local = readl(&regs->LocalCtrl);
 		local &= ~EEPROM_CLK_OUT;
 		writel(local, &regs->LocalCtrl);
+		readl(&regs->LocalCtrl);
 		udelay(ACE_SHORT_DELAY);
 		mb();
 		if (i == 7) {
 			local |= EEPROM_WRITE_ENABLE;
 			writel(local, &regs->LocalCtrl);
+			readl(&regs->LocalCtrl);
 			mb();
 			udelay(ACE_SHORT_DELAY);
 		}
@@ -3459,11 +3546,14 @@
 
 	local |= EEPROM_DATA_OUT;
 	writel(local, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 	udelay(ACE_SHORT_DELAY);
 	writel(readl(&regs->LocalCtrl) | EEPROM_CLK_OUT, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	udelay(ACE_LONG_DELAY);
 	writel(readl(&regs->LocalCtrl) & ~EEPROM_CLK_OUT, &regs->LocalCtrl);
+	readl(&regs->LocalCtrl);
 	mb();
 	udelay(ACE_SHORT_DELAY);
 	eeprom_stop(regs);
diff -Nru a/drivers/net/acenic.h b/drivers/net/acenic.h
--- a/drivers/net/acenic.h	Fri Sep 20 08:20:46 2002
+++ b/drivers/net/acenic.h	Fri Sep 20 08:20:46 2002
@@ -748,6 +748,32 @@
 }
 
 
+static inline void ace_mask_irq(struct net_device *dev)
+{
+	struct ace_private *ap = dev->priv;
+	struct ace_regs *regs = ap->regs;
+
+	if (ACE_IS_TIGON_I(ap))
+		writel(1, &regs->MaskInt);
+	else
+		writel(readl(&regs->HostCtrl) | MASK_INTS, &regs->HostCtrl);
+
+	ace_sync_irq(dev->irq);
+}
+
+
+static inline void ace_unmask_irq(struct net_device *dev)
+{
+	struct ace_private *ap = dev->priv;
+	struct ace_regs *regs = ap->regs;
+ 
+	if (ACE_IS_TIGON_I(ap))
+		writel(0, &regs->MaskInt);
+	else
+		writel(readl(&regs->HostCtrl) &= ~MASK_INTS, &regs->HostCtrl);
+}
+
+
 /*
  * Prototypes
  */
diff -Nru a/drivers/net/dl2k.c b/drivers/net/dl2k.c
--- a/drivers/net/dl2k.c	Fri Sep 20 08:20:44 2002
+++ b/drivers/net/dl2k.c	Fri Sep 20 08:20:44 2002
@@ -809,13 +809,8 @@
 		/* Let TxStartThresh stay default value */
 	}
 	/* Maximum Collisions */
-#ifdef ETHER_STATS	
-	if (tx_status & 0x08) 
-		np->stats.collisions16++;
-#else
 	if (tx_status & 0x08) 
 		np->stats.collisions++;
-#endif
 	/* Restart the Tx */
 	writel (readw (dev->base_addr + MACCtrl) | TxEnable, ioaddr + MACCtrl);
 }
diff -Nru a/drivers/net/e100/e100_main.c b/drivers/net/e100/e100_main.c
--- a/drivers/net/e100/e100_main.c	Fri Sep 20 08:20:46 2002
+++ b/drivers/net/e100/e100_main.c	Fri Sep 20 08:20:46 2002
@@ -114,8 +114,10 @@
 static int e100_ethtool_gregs(struct net_device *, struct ifreq *);
 static int e100_ethtool_nway_rst(struct net_device *, struct ifreq *);
 static int e100_ethtool_wol(struct net_device *, struct ifreq *);
+#ifdef CONFIG_PM
 static unsigned char e100_setup_filter(struct e100_private *bdp);
 static void e100_do_wol(struct pci_dev *pcid, struct e100_private *bdp);
+#endif
 static u16 e100_get_ip_lbytes(struct net_device *dev);
 extern void e100_config_wol(struct e100_private *bdp);
 extern u32 e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags);
@@ -3740,8 +3742,8 @@
 
 	set_current_state(TASK_INTERRUPTIBLE);
 
-	if ((!ecmd.data) || (ecmd.data > MAX_SCHEDULE_TIMEOUT / HZ))
-		ecmd.data = MAX_SCHEDULE_TIMEOUT / HZ;
+	if ((!ecmd.data) || (ecmd.data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)))
+		ecmd.data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
 
 	schedule_timeout(ecmd.data * HZ);
 
@@ -3799,6 +3801,7 @@
 
 }
 
+#ifdef CONFIG_PM
 static unsigned char
 e100_setup_filter(struct e100_private *bdp)
 {
@@ -3853,6 +3856,7 @@
 		printk(KERN_ERR "e100: config WOL failed\n");
 	}
 }
+#endif
 
 static u16
 e100_get_ip_lbytes(struct net_device *dev)
diff -Nru a/drivers/net/eepro100.c b/drivers/net/eepro100.c
--- a/drivers/net/eepro100.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/net/eepro100.c	Fri Sep 20 08:20:47 2002
@@ -459,8 +459,8 @@
    Unfortunately, all the positions have been shifted since there.
    A new re-alignment is required.  2000/03/06  SAW */
 struct speedo_private {
-	struct TxFD	*tx_ring;				/* Commands (usually CmdTxPacket). */
-	struct RxFD *rx_ringp[RX_RING_SIZE];/* Rx descriptor, used as ring. */
+	struct TxFD	*tx_ring;		/* Commands (usually CmdTxPacket). */
+	struct RxFD *rx_ringp[RX_RING_SIZE];	/* Rx descriptor, used as ring. */
 	/* The addresses of a Tx/Rx-in-place packets/buffers. */
 	struct sk_buff *tx_skbuff[TX_RING_SIZE];
 	struct sk_buff *rx_skbuff[RX_RING_SIZE];
@@ -470,9 +470,9 @@
 	dma_addr_t rx_ring_dma[RX_RING_SIZE];
 	struct descriptor *last_cmd;		/* Last command sent. */
 	unsigned int cur_tx, dirty_tx;		/* The ring entries to be free()ed. */
-	spinlock_t lock;					/* Group with Tx control cache line. */
-	u32 tx_threshold;					/* The value for txdesc.count. */
-	struct RxFD *last_rxf;				/* Last filled RX buffer. */
+	spinlock_t lock;			/* Group with Tx control cache line. */
+	u32 tx_threshold;			/* The value for txdesc.count. */
+	struct RxFD *last_rxf;			/* Last filled RX buffer. */
 	dma_addr_t last_rxf_dma;
 	unsigned int cur_rx, dirty_rx;		/* The next free ring entry */
 	long last_rx_time;			/* Last Rx, in jiffies, to handle Rx hang. */
@@ -481,21 +481,21 @@
 	dma_addr_t lstats_dma;
 	int chip_id;
 	struct pci_dev *pdev;
-	struct timer_list timer;			/* Media selection timer. */
-	struct speedo_mc_block *mc_setup_head;/* Multicast setup frame list head. */
-	struct speedo_mc_block *mc_setup_tail;/* Multicast setup frame list tail. */
-	long in_interrupt;					/* Word-aligned dev->interrupt */
+	struct timer_list timer;		/* Media selection timer. */
+	struct speedo_mc_block *mc_setup_head;	/* Multicast setup frame list head. */
+	struct speedo_mc_block *mc_setup_tail;	/* Multicast setup frame list tail. */
+	long in_interrupt;			/* Word-aligned dev->interrupt */
 	unsigned char acpi_pwr;
-	signed char rx_mode;					/* Current PROMISC/ALLMULTI setting. */
-	unsigned int tx_full:1;				/* The Tx queue is full. */
-	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
-	unsigned int flow_ctrl:1;			/* Use 802.3x flow control. */
-	unsigned int rx_bug:1;				/* Work around receiver hang errata. */
+	signed char rx_mode;			/* Current PROMISC/ALLMULTI setting. */
+	unsigned int tx_full:1;			/* The Tx queue is full. */
+	unsigned int full_duplex:1;		/* Full-duplex operation requested. */
+	unsigned int flow_ctrl:1;		/* Use 802.3x flow control. */
+	unsigned int rx_bug:1;			/* Work around receiver hang errata. */
 	unsigned char default_port:8;		/* Last dev->if_port value. */
 	unsigned char rx_ring_state;		/* RX ring status flags. */
-	unsigned short phy[2];				/* PHY media interfaces available. */
-	unsigned short advertising;			/* Current PHY advertised caps. */
-	unsigned short partner;				/* Link partner caps. */
+	unsigned short phy[2];			/* PHY media interfaces available. */
+	unsigned short partner;			/* Link partner caps. */
+	struct mii_if_info mii_if;		/* MII API hooks, info */
 #ifdef CONFIG_PM
 	u32 pm_state[16];
 #endif
@@ -532,8 +532,8 @@
 static void eepro100_remove_one (struct pci_dev *pdev);
 
 static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len);
-static int mdio_read(long ioaddr, int phy_id, int location);
-static int mdio_write(long ioaddr, int phy_id, int location, int value);
+static int mdio_read(struct net_device *dev, int phy_id, int location);
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
 static int speedo_open(struct net_device *dev);
 static void speedo_resume(struct net_device *dev);
 static void speedo_timer(unsigned long data);
@@ -658,6 +658,8 @@
 		return -1;
 	}
 
+	SET_MODULE_OWNER(dev);
+
 	if (dev->mem_start > 0)
 		option = dev->mem_start;
 	else if (card_idx >= 0  &&  options[card_idx] >= 0)
@@ -728,6 +730,9 @@
 #endif
 	printk("IRQ %d.\n", pdev->irq);
 
+	/* we must initialize base_addr early, for mdio_{read,write} */
+	dev->base_addr = ioaddr;
+
 #if 1 || defined(kernel_bloat)
 	/* OK, this is pure kernel bloat.  I don't like it when other drivers
 	   waste non-pageable kernel space to emit similar messages, but I need
@@ -753,18 +758,18 @@
 				   phys[(eeprom[7]>>8)&7]);
 		if (((eeprom[6]>>8) & 0x3f) == DP83840
 			||  ((eeprom[6]>>8) & 0x3f) == DP83840A) {
-			int mdi_reg23 = mdio_read(ioaddr, eeprom[6] & 0x1f, 23) | 0x0422;
+			int mdi_reg23 = mdio_read(dev, eeprom[6] & 0x1f, 23) | 0x0422;
 			if (congenb)
 			  mdi_reg23 |= 0x0100;
 			printk(KERN_INFO"  DP83840 specific setup, setting register 23 to %4.4x.\n",
 				   mdi_reg23);
-			mdio_write(ioaddr, eeprom[6] & 0x1f, 23, mdi_reg23);
+			mdio_write(dev, eeprom[6] & 0x1f, 23, mdi_reg23);
 		}
 		if ((option >= 0) && (option & 0x70)) {
 			printk(KERN_INFO "  Forcing %dMbs %s-duplex operation.\n",
 				   (option & 0x20 ? 100 : 10),
 				   (option & 0x10 ? "full" : "half"));
-			mdio_write(ioaddr, eeprom[6] & 0x1f, 0,
+			mdio_write(dev, eeprom[6] & 0x1f, MII_BMCR,
 					   ((option & 0x20) ? 0x2000 : 0) | 	/* 100mbps? */
 					   ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */
 		}
@@ -806,7 +811,6 @@
 
 	pci_set_drvdata (pdev, dev);
 
-	dev->base_addr = ioaddr;
 	dev->irq = pdev->irq;
 
 	sp = dev->priv;
@@ -818,15 +822,21 @@
 	sp->lstats_dma = TX_RING_ELEM_DMA(sp, TX_RING_SIZE);
 	init_timer(&sp->timer); /* used in ioctl() */
 
-	sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0;
+	sp->mii_if.full_duplex = option >= 0 && (option & 0x10) ? 1 : 0;
 	if (card_idx >= 0) {
 		if (full_duplex[card_idx] >= 0)
-			sp->full_duplex = full_duplex[card_idx];
+			sp->mii_if.full_duplex = full_duplex[card_idx];
 	}
 	sp->default_port = option >= 0 ? (option & 0x0f) : 0;
 
 	sp->phy[0] = eeprom[6];
 	sp->phy[1] = eeprom[7];
+
+	sp->mii_if.phy_id = eeprom[6];
+	sp->mii_if.dev = dev;
+	sp->mii_if.mdio_read = mdio_read;
+	sp->mii_if.mdio_write = mdio_write;
+	
 	sp->rx_bug = (eeprom[3] & 0x03) == 3 ? 0 : 1;
 	if (((pdev->device > 0x1030 && (pdev->device < 0x103F))) 
 	    || (pdev->device == 0x2449) || (pdev->device == 0x2459) 
@@ -848,7 +858,30 @@
 
 	return 0;
 }
-
+
+static void do_slow_command(struct net_device *dev, int cmd)
+{
+	long cmd_ioaddr = dev->base_addr + SCBCmd;
+	int wait = 0;
+	do
+		if (inb(cmd_ioaddr) == 0) break;
+	while(++wait <= 200);
+	if (wait > 100)
+		printk(KERN_ERR "Command %4.4x never accepted (%d polls)!\n",
+		       inb(cmd_ioaddr), wait);
+
+	outb(cmd, cmd_ioaddr);
+
+	for (wait = 0; wait <= 100; wait++)
+		if (inb(cmd_ioaddr) == 0) return;
+	for (; wait <= 20000; wait++)
+		if (inb(cmd_ioaddr) == 0) return;
+		else udelay(1);
+	printk(KERN_ERR "Command %4.4x was not accepted after %d polls!"
+	       "  Current status %8.8x.\n",
+	       cmd, wait, inl(dev->base_addr + SCBStatus));
+}
+
 /* Serial EEPROM section.
    A "bit" grungy, but we work our way through bit-by-bit :->. */
 /*  EEPROM_Ctrl bits. */
@@ -890,8 +923,9 @@
 	return retval;
 }
 
-static int mdio_read(long ioaddr, int phy_id, int location)
+static int mdio_read(struct net_device *dev, int phy_id, int location)
 {
+	long ioaddr = dev->base_addr;
 	int val, boguscnt = 64*10;		/* <64 usec. to complete, typ 27 ticks */
 	outl(0x08000000 | (location<<16) | (phy_id<<21), ioaddr + SCBCtrlMDI);
 	do {
@@ -904,8 +938,9 @@
 	return val & 0xffff;
 }
 
-static int mdio_write(long ioaddr, int phy_id, int location, int value)
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
 {
+	long ioaddr = dev->base_addr;
 	int val, boguscnt = 64*10;		/* <64 usec. to complete, typ 27 ticks */
 	outl(0x04000000 | (location<<16) | (phy_id<<21) | value,
 		 ioaddr + SCBCtrlMDI);
@@ -916,10 +951,8 @@
 			break;
 		}
 	} while (! (val & 0x10000000));
-	return val & 0xffff;
 }
 
-
 static int
 speedo_open(struct net_device *dev)
 {
@@ -930,8 +963,6 @@
 	if (speedo_debug > 1)
 		printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq);
 
-	MOD_INC_USE_COUNT;
-
 	pci_set_power_state(sp->pdev, 0);
 
 	/* Set up the Tx queue early.. */
@@ -945,7 +976,6 @@
 	/* .. we can safely take handler calls during init. */
 	retval = request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev);
 	if (retval) {
-		MOD_DEC_USE_COUNT;
 		return retval;
 	}
 
@@ -962,9 +992,9 @@
 		   0x2100 100-FD
 		*/
 #ifdef honor_default_port
-		mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]);
+		mdio_write(dev, phy_addr, MII_BMCR, mii_ctrl[dev->default_port & 7]);
 #else
-		mdio_write(ioaddr, phy_addr, 0, 0x3300);
+		mdio_write(dev, phy_addr, MII_BMCR, 0x3300);
 #endif
 	}
 #endif
@@ -985,9 +1015,9 @@
 	sp->rx_mode = -1;			/* Invalid -> always reset the mode. */
 	set_rx_mode(dev);
 	if ((sp->phy[0] & 0x8000) == 0)
-		sp->advertising = mdio_read(ioaddr, sp->phy[0] & 0x1f, 4);
+		sp->mii_if.advertising = mdio_read(dev, sp->phy[0] & 0x1f, MII_ADVERTISE);
 
-	if (mdio_read(ioaddr, sp->phy[0] & 0x1f, MII_BMSR) & BMSR_LSTATUS)
+	if (mdio_read(dev, sp->phy[0] & 0x1f, MII_BMSR) & BMSR_LSTATUS)
 		netif_carrier_on(dev);
 	else
 		netif_carrier_off(dev);
@@ -1009,7 +1039,7 @@
 
 	/* No need to wait for the command unit to accept here. */
 	if ((sp->phy[0] & 0x8000) == 0)
-		mdio_read(ioaddr, sp->phy[0] & 0x1f, 0);
+		mdio_read(dev, sp->phy[0] & 0x1f, MII_BMCR);
 
 	return 0;
 }
@@ -1017,7 +1047,7 @@
 /* Start the chip hardware after a full reset. */
 static void speedo_resume(struct net_device *dev)
 {
-	struct speedo_private *sp = (struct speedo_private *)dev->priv;
+	struct speedo_private *sp = dev->priv;
 	long ioaddr = dev->base_addr;
 
 	/* Start with a Tx threshold of 256 (0x..20.... 8 byte units). */
@@ -1025,34 +1055,40 @@
 
 	/* Set the segment registers to '0'. */
 	wait_for_cmd_done(ioaddr + SCBCmd);
-	outl(0, ioaddr + SCBPointer);
-	/* impose a delay to avoid a bug */
-	inl(ioaddr + SCBPointer);
-	udelay(10);
-	outb(RxAddrLoad, ioaddr + SCBCmd);
-	wait_for_cmd_done(ioaddr + SCBCmd);
-	outb(CUCmdBase, ioaddr + SCBCmd);
+	if (inb(ioaddr + SCBCmd)) {
+		outl(PortPartialReset, ioaddr + SCBPort);
+		udelay(10);
+	}
+
+        outl(0, ioaddr + SCBPointer);
+        inl(ioaddr + SCBPointer);			/* Flush to PCI. */
+        udelay(10);			/* Bogus, but it avoids the bug. */
+
+        /* Note: these next two operations can take a while. */
+        do_slow_command(dev, RxAddrLoad);
+        do_slow_command(dev, CUCmdBase);
 
 	/* Load the statistics block and rx ring addresses. */
-	wait_for_cmd_done(ioaddr + SCBCmd);
 	outl(sp->lstats_dma, ioaddr + SCBPointer);
+	inl(ioaddr + SCBPointer);			/* Flush to PCI */
+
 	outb(CUStatsAddr, ioaddr + SCBCmd);
 	sp->lstats->done_marker = 0;
+	wait_for_cmd_done(ioaddr + SCBCmd);
 
 	if (sp->rx_ringp[sp->cur_rx % RX_RING_SIZE] == NULL) {
 		if (speedo_debug > 2)
 			printk(KERN_DEBUG "%s: NULL cur_rx in speedo_resume().\n",
 					dev->name);
 	} else {
-		wait_for_cmd_done(ioaddr + SCBCmd);
 		outl(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE],
 			 ioaddr + SCBPointer);
-		outb(RxStart, ioaddr + SCBCmd);
+		inl(ioaddr + SCBPointer);		/* Flush to PCI */
 	}
 
-	wait_for_cmd_done(ioaddr + SCBCmd);
-	outb(CUDumpStats, ioaddr + SCBCmd);
-	udelay(30);
+	/* Note: RxStart should complete instantly. */
+	do_slow_command(dev, RxStart);
+	do_slow_command(dev, CUDumpStats);
 
 	/* Fill the first command with our physical address. */
 	{
@@ -1065,11 +1101,12 @@
 		ias_cmd->link =
 			cpu_to_le32(TX_RING_ELEM_DMA(sp, sp->cur_tx % TX_RING_SIZE));
 		memcpy(ias_cmd->params, dev->dev_addr, 6);
+		if (sp->last_cmd)
+			clear_suspend(sp->last_cmd);
 		sp->last_cmd = ias_cmd;
 	}
 
 	/* Start the chip's Tx process and unmask interrupts. */
-	wait_for_cmd_done(ioaddr + SCBCmd);
 	outl(TX_RING_ELEM_DMA(sp, sp->dirty_tx % TX_RING_SIZE),
 		 ioaddr + SCBPointer);
 	/* We are not ACK-ing FCP and ER in the interrupt handler yet so they should
@@ -1132,13 +1169,13 @@
 
 	/* We have MII and lost link beat. */
 	if ((sp->phy[0] & 0x8000) == 0) {
-		int partner = mdio_read(ioaddr, phy_num, 5);
+		int partner = mdio_read(dev, phy_num, MII_LPA);
 		if (partner != sp->partner) {
-			int flow_ctrl = sp->advertising & partner & 0x0400 ? 1 : 0;
+			int flow_ctrl = sp->mii_if.advertising & partner & 0x0400 ? 1 : 0;
 			if (speedo_debug > 2) {
 				printk(KERN_DEBUG "%s: Link status change.\n", dev->name);
 				printk(KERN_DEBUG "%s: Old partner %x, new %x, adv %x.\n",
-					   dev->name, sp->partner, partner, sp->advertising);
+					   dev->name, sp->partner, partner, sp->mii_if.advertising);
 			}
 			sp->partner = partner;
 			if (flow_ctrl != sp->flow_ctrl) {
@@ -1146,9 +1183,9 @@
 				sp->rx_mode = -1;	/* Trigger a reload. */
 			}
 			/* Clear sticky bit. */
-			mdio_read(ioaddr, phy_num, 1);
+			mdio_read(dev, phy_num, MII_BMSR);
 			/* If link beat has returned... */
-			if (mdio_read(ioaddr, phy_num, MII_BMSR) & BMSR_LSTATUS)
+			if (mdio_read(dev, phy_num, MII_BMSR) & BMSR_LSTATUS)
 				netif_carrier_on(dev);
 			else
 				netif_carrier_off(dev);
@@ -1214,7 +1251,7 @@
 			/* FIXME: what does it mean?  --SAW */
 			if (i == 6) i = 21;
 			printk(KERN_DEBUG "%s:  PHY index %d register %d is %4.4x.\n",
-				   dev->name, phy_num, i, mdio_read(ioaddr, phy_num, i));
+				   dev->name, phy_num, i, mdio_read(dev, phy_num, i));
 		}
 	}
 #endif
@@ -1306,22 +1343,22 @@
 static void reset_mii(struct net_device *dev)
 {
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
-	long ioaddr = dev->base_addr;
+
 	/* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */
 	if ((sp->phy[0] & 0x8000) == 0) {
 		int phy_addr = sp->phy[0] & 0x1f;
-		int advertising = mdio_read(ioaddr, phy_addr, 4);
-		int mii_bmcr = mdio_read(ioaddr, phy_addr, 0);
-		mdio_write(ioaddr, phy_addr, 0, 0x0400);
-		mdio_write(ioaddr, phy_addr, 1, 0x0000);
-		mdio_write(ioaddr, phy_addr, 4, 0x0000);
-		mdio_write(ioaddr, phy_addr, 0, 0x8000);
+		int advertising = mdio_read(dev, phy_addr, MII_ADVERTISE);
+		int mii_bmcr = mdio_read(dev, phy_addr, MII_BMCR);
+		mdio_write(dev, phy_addr, MII_BMCR, 0x0400);
+		mdio_write(dev, phy_addr, MII_BMSR, 0x0000);
+		mdio_write(dev, phy_addr, MII_ADVERTISE, 0x0000);
+		mdio_write(dev, phy_addr, MII_BMCR, 0x8000);
 #ifdef honor_default_port
-		mdio_write(ioaddr, phy_addr, 0, mii_ctrl[dev->default_port & 7]);
+		mdio_write(dev, phy_addr, MII_BMCR, mii_ctrl[dev->default_port & 7]);
 #else
-		mdio_read(ioaddr, phy_addr, 0);
-		mdio_write(ioaddr, phy_addr, 0, mii_bmcr);
-		mdio_write(ioaddr, phy_addr, 4, advertising);
+		mdio_read(dev, phy_addr, MII_BMCR);
+		mdio_write(dev, phy_addr, MII_BMCR, mii_bmcr);
+		mdio_write(dev, phy_addr, MII_ADVERTISE, advertising);
 #endif
 	}
 }
@@ -1886,8 +1923,6 @@
 
 	pci_set_power_state(sp->pdev, 2);
 
-	MOD_DEC_USE_COUNT;
-
 	return 0;
 }
 
@@ -1941,6 +1976,7 @@
 		return -EFAULT;
 	
         switch (ethcmd) {
+	/* get driver-specific version/etc. info */
 	case ETHTOOL_GDRVINFO: {
 		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
 		strncpy(info.driver, "eepro100", sizeof(info.driver)-1);
@@ -1952,19 +1988,48 @@
 		return 0;
 	}
 	
+	/* get settings */
+	case ETHTOOL_GSET: {
+		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+		spin_lock_irq(&sp->lock);
+		mii_ethtool_gset(&sp->mii_if, &ecmd);
+		spin_unlock_irq(&sp->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(&sp->lock);
+		r = mii_ethtool_sset(&sp->mii_if, &ecmd);
+		spin_unlock_irq(&sp->lock);
+		return r;
+	}
+	/* restart autonegotiation */
+	case ETHTOOL_NWAY_RST: {
+		return mii_nway_restart(&sp->mii_if);
+	}
+	/* get link status */
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = {ETHTOOL_GLINK};
+		edata.data = mii_link_ok(&sp->mii_if);
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+
         }
 	
 	return -EOPNOTSUPP;
 }
 
-
-
-
-
 static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct speedo_private *sp = (struct speedo_private *)dev->priv;
-	long ioaddr = dev->base_addr;
 	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data;
 	int phy = sp->phy[0] & 0x1f;
 	int saved_acpi;
@@ -1981,7 +2046,7 @@
 		   timer routine.  2000/05/09 SAW */
 		saved_acpi = pci_set_power_state(sp->pdev, 0);
 		t = del_timer_sync(&sp->timer);
-		data->val_out = mdio_read(ioaddr, data->phy_id & 0x1f, data->reg_num & 0x1f);
+		data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f);
 		if (t)
 			add_timer(&sp->timer); /* may be set to the past  --SAW */
 		pci_set_power_state(sp->pdev, saved_acpi);
@@ -1992,7 +2057,7 @@
 			return -EPERM;
 		saved_acpi = pci_set_power_state(sp->pdev, 0);
 		t = del_timer_sync(&sp->timer);
-		mdio_write(ioaddr, data->phy_id, data->reg_num, data->val_in);
+		mdio_write(dev, data->phy_id, data->reg_num, data->val_in);
 		if (t)
 			add_timer(&sp->timer); /* may be set to the past  --SAW */
 		pci_set_power_state(sp->pdev, saved_acpi);
@@ -2064,7 +2129,7 @@
 		   Disable Flow control since we are not ACK-ing any FC interrupts
 		   for now. --Dragan */
 		config_cmd_data[19] = 0x84;
-		config_cmd_data[19] |= sp->full_duplex ? 0x40 : 0;
+		config_cmd_data[19] |= sp->mii_if.full_duplex ? 0x40 : 0;
 		config_cmd_data[21] = (new_rx_mode & 1) ? 0x0D : 0x05;
 		if (sp->phy[0] & 0x8000) {			/* Use the AUI port instead. */
 			config_cmd_data[15] |= 0x80;
diff -Nru a/drivers/net/epic100.c b/drivers/net/epic100.c
--- a/drivers/net/epic100.c	Fri Sep 20 08:20:46 2002
+++ b/drivers/net/epic100.c	Fri Sep 20 08:20:46 2002
@@ -1072,13 +1072,7 @@
 					if (txstatus & 0x0008) ep->stats.tx_carrier_errors++;
 					if (txstatus & 0x0040) ep->stats.tx_window_errors++;
 					if (txstatus & 0x0010) ep->stats.tx_fifo_errors++;
-#ifdef ETHER_STATS
-					if (txstatus & 0x1000) ep->stats.collisions16++;
-#endif
 				} else {
-#ifdef ETHER_STATS
-					if ((txstatus & 0x0002) != 0) ep->stats.tx_deferred++;
-#endif
 					ep->stats.collisions += (txstatus >> 8) & 15;
 					ep->stats.tx_packets++;
 					ep->stats.tx_bytes += ep->tx_skbuff[entry]->len;
diff -Nru a/drivers/net/fealnx.c b/drivers/net/fealnx.c
--- a/drivers/net/fealnx.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/net/fealnx.c	Fri Sep 20 08:20:47 2002
@@ -1493,16 +1493,7 @@
 					if ((tx_status & HF) && np->mii.full_duplex == 0)
 						np->stats.tx_heartbeat_errors++;
 
-#ifdef ETHER_STATS
-					if (tx_status & EC)
-						np->stats.collisions16++;
-#endif
 				} else {
-#ifdef ETHER_STATS
-					if (tx_status & DFR)
-						np->stats.tx_deferred++;
-#endif
-
 					np->stats.tx_bytes +=
 					    ((tx_control & PKTSMask) >> PKTSShift);
 
@@ -1544,9 +1535,6 @@
 			np->stats.tx_errors += (data & 0xff000000) >> 24;
 			np->stats.tx_aborted_errors += (data & 0xff000000) >> 24;
 			np->stats.tx_window_errors += (data & 0x00ff0000) >> 16;
-#ifdef ETHER_STATS
-			np->stats.collisions16 += (data & 0xff000000) >> 24;
-#endif
 			np->stats.collisions += (data & 0x0000ffff);
 		}
 
diff -Nru a/drivers/net/hp100.c b/drivers/net/hp100.c
--- a/drivers/net/hp100.c	Fri Sep 20 08:20:44 2002
+++ b/drivers/net/hp100.c	Fri Sep 20 08:20:44 2002
@@ -236,6 +236,9 @@
 	/* 10/100 ISA card with Cascade chip */
 	{0x5019F022, "HP J2573", HP100_BUS_ISA},
 
+	/* 10/100 EISA card with AT&T chip */
+	{0x9019f022, "HP J2577", HP100_BUS_EISA },
+
 	/* 10/100 PCI card - old J2585A */
 	{0x1030103c, "HP J2585A", HP100_BUS_PCI},
 
@@ -1879,7 +1882,7 @@
 #endif
 
 		/* Now we allocate the skb and transfer the data into it. */
-		skb = dev_alloc_skb(pkt_len);
+		skb = dev_alloc_skb(pkt_len+2);
 		if (skb == NULL) {	/* Not enough memory->drop packet */
 #ifdef HP100_DEBUG
 			printk("hp100: %s: rx: couldn't allocate a sk_buff of size %d\n",
@@ -1890,10 +1893,12 @@
 
 			u_char *ptr;
 
+			skb_reserve(skb,2);
 			skb->dev = dev;
 
 			/* ptr to start of the sk_buff data area */
-			ptr = (u_char *) skb_put(skb, pkt_len);
+			skb_put(skb, pkt_len);
+			ptr = skb->data;
 
 			/* Now transfer the data from the card into that area */
 			if (lp->mode == 2) {
diff -Nru a/drivers/net/irda/act200l.c b/drivers/net/irda/act200l.c
--- a/drivers/net/irda/act200l.c	Fri Sep 20 08:20:46 2002
+++ b/drivers/net/irda/act200l.c	Fri Sep 20 08:20:46 2002
@@ -158,7 +158,7 @@
 		}
 		break;
 	case IRDA_TASK_CHILD_WAIT:
-		WARNING(__FUNCTION__ "(), resetting dongle timed out!\n");
+		WARNING("%s(), resetting dongle timed out!\n", __FUNCTION__);
 		ret = -1;
 		break;
 	case IRDA_TASK_CHILD_DONE:
@@ -203,7 +203,7 @@
 		self->speed_task = NULL;
 		break;
 	default:
-		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		self->speed_task = NULL;
 		ret = -1;
@@ -269,7 +269,7 @@
 		self->reset_task = NULL;
 		break;
 	default:
-		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		self->reset_task = NULL;
 		ret = -1;
diff -Nru a/drivers/net/irda/actisys.c b/drivers/net/irda/actisys.c
--- a/drivers/net/irda/actisys.c	Fri Sep 20 08:20:49 2002
+++ b/drivers/net/irda/actisys.c	Fri Sep 20 08:20:49 2002
@@ -259,7 +259,7 @@
 		self->speed = 9600;	/* That's the default */
 		break;
 	default:
-		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		self->reset_task = NULL;
 		ret = -1;
diff -Nru a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
--- a/drivers/net/irda/ali-ircc.c	Fri Sep 20 08:20:44 2002
+++ b/drivers/net/irda/ali-ircc.c	Fri Sep 20 08:20:44 2002
@@ -141,12 +141,12 @@
 	int reg, revision;
 	int i = 0;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 	
 	/* Probe for all the ALi chipsets we know about */
 	for (chip= chips; chip->name; chip++, i++) 
 	{
-		IRDA_DEBUG(2, __FUNCTION__"(), Probing for %s ...\n", chip->name);
+		IRDA_DEBUG(2, "%s(), Probing for %s ...\n", __FUNCTION__, chip->name);
 				
 		/* Try all config registers for this chip */
 		for (cfg=0; cfg<2; cfg++)
@@ -176,13 +176,11 @@
 				
 			if (reg == chip->cid_value)
 			{
-				IRDA_DEBUG(2, __FUNCTION__
-					"(), Chip found at 0x%03x\n", cfg_base);
+				IRDA_DEBUG(2, "%s(), Chip found at 0x%03x\n", __FUNCTION__, cfg_base);
 					   
 				outb(0x1F, cfg_base);
 				revision = inb(cfg_base+1);
-				IRDA_DEBUG(2, __FUNCTION__ 
-					   "(), Found %s chip, revision=%d\n",
+				IRDA_DEBUG(2, "%s(), Found %s chip, revision=%d\n", __FUNCTION__,
 					   chip->name, revision);					
 				
 				/* 
@@ -205,15 +203,14 @@
 			}
 			else
 			{
-				IRDA_DEBUG(2, __FUNCTION__ 
-					   "(), No %s chip at 0x%03x\n", chip->name, cfg_base);
+				IRDA_DEBUG(2, "%s(), No %s chip at 0x%03x\n", __FUNCTION__, chip->name, cfg_base);
 			}
 			/* Exit configuration */
 			outb(0xbb, cfg_base);
 		}
 	}		
 		
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End -----------------\n");					   		
+	IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__);					   		
 	return ret;
 }
 
@@ -227,7 +224,7 @@
 {
 	int i;
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");	
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);	
 	
 	pm_unregister_all(ali_ircc_pmproc);
 
@@ -236,7 +233,7 @@
 			ali_ircc_close(dev_self[i]);
 	}
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End -----------------\n");
+	IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__);
 }
 
 /*
@@ -251,9 +248,10 @@
 	struct ali_ircc_cb *self;
 	struct pm_dev *pmdev;
 	int dongle_id;
+	int ret;
 	int err;
 			
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");	
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);	
 	
 	/* Set FIR FIFO and DMA Threshold */
 	if ((ali_ircc_setup(info)) == -1)
@@ -263,7 +261,7 @@
 	self = kmalloc(sizeof(struct ali_ircc_cb), GFP_KERNEL);
 	if (self == NULL) 
 	{
-		ERROR(__FUNCTION__ "(), can't allocate memory for control block!\n");
+		ERROR("%s(), can't allocate memory for control block!\n", __FUNCTION__);
 		return -ENOMEM;
 	}
 	memset(self, 0, sizeof(struct ali_ircc_cb));
@@ -285,7 +283,7 @@
 	/* Reserve the ioports that we need */
 	ret = check_region(self->io.fir_base, self->io.fir_ext);
 	if (ret < 0) { 
-		WARNING(__FUNCTION__ "(), can't get iobase of 0x%03x\n",
+		WARNING("%s(), can't get iobase of 0x%03x\n", __FUNCTION__,
 			self->io.fir_base);
 		dev_self[i] = NULL;
 		kfree(self);
@@ -339,7 +337,7 @@
 	self->tx_fifo.tail = self->tx_buff.head;
 
 	if (!(dev = dev_alloc("irda%d", &err))) {
-		ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+		ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__);
 		return -ENOMEM;
 	}
 
@@ -358,14 +356,14 @@
 	err = register_netdevice(dev);
 	rtnl_unlock();
 	if (err) {
-		ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
+		ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
 		return -1;
 	}
 	MESSAGE("IrDA: Registered device %s\n", dev->name);
 
 	/* Check dongle id */
 	dongle_id = ali_ircc_read_dongle_id(i, info);
-	MESSAGE(__FUNCTION__ "(), %s, Found dongle: %s\n", driver_name, dongle_types[dongle_id]);
+	MESSAGE("%s(), %s, Found dongle: %s\n", __FUNCTION__, driver_name, dongle_types[dongle_id]);
 		
 	self->io.dongle_id = dongle_id;
 	
@@ -373,7 +371,7 @@
         if (pmdev)
                 pmdev->data = self;
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End -----------------\n");
+	IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__);
 	
 	return 0;
 }
@@ -389,7 +387,7 @@
 {
 	int iobase;
 
-	IRDA_DEBUG(4, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(4, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return -1;);
 
@@ -403,7 +401,7 @@
 	}
 
 	/* Release the PORT that this driver is using */
-	IRDA_DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", self->io.fir_base);
+	IRDA_DEBUG(4, "%s(), Releasing Region %03x\n", __FUNCTION__, self->io.fir_base);
 	release_region(self->io.fir_base, self->io.fir_ext);
 
 	if (self->tx_buff.head)
@@ -415,7 +413,7 @@
 	dev_self[self->index] = NULL;
 	kfree(self);
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End -----------------\n");
+	IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__);
 	
 	return 0;
 }
@@ -458,7 +456,7 @@
 	int cfg_base = info->cfg_base;
 	int hi, low, reg;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 	
 	/* Enter Configuration */
 	outb(chip->entr1, cfg_base);
@@ -477,13 +475,13 @@
 	
 	info->sir_base = info->fir_base;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), probing fir_base=0x%03x\n", info->fir_base);
+	IRDA_DEBUG(2, "%s(), probing fir_base=0x%03x\n", __FUNCTION__, info->fir_base);
 		
 	/* Read IRQ control register */
 	outb(0x70, cfg_base);
 	reg = inb(cfg_base+1);
 	info->irq = reg & 0x0f;
-	IRDA_DEBUG(2, __FUNCTION__ "(), probing irq=%d\n", info->irq);
+	IRDA_DEBUG(2, "%s(), probing irq=%d\n", __FUNCTION__, info->irq);
 	
 	/* Read DMA channel */
 	outb(0x74, cfg_base);
@@ -491,26 +489,26 @@
 	info->dma = reg & 0x07;
 	
 	if(info->dma == 0x04)
-		WARNING(__FUNCTION__ "(), No DMA channel assigned !\n");
+		WARNING("%s(), No DMA channel assigned !\n", __FUNCTION__);
 	else
-		IRDA_DEBUG(2, __FUNCTION__ "(), probing dma=%d\n", info->dma);
+		IRDA_DEBUG(2, "%s(), probing dma=%d\n", __FUNCTION__, info->dma);
 	
 	/* Read Enabled Status */
 	outb(0x30, cfg_base);
 	reg = inb(cfg_base+1);
 	info->enabled = (reg & 0x80) && (reg & 0x01);
-	IRDA_DEBUG(2, __FUNCTION__ "(), probing enabled=%d\n", info->enabled);
+	IRDA_DEBUG(2, "%s(), probing enabled=%d\n", __FUNCTION__, info->enabled);
 	
 	/* Read Power Status */
 	outb(0x22, cfg_base);
 	reg = inb(cfg_base+1);
 	info->suspended = (reg & 0x20);
-	IRDA_DEBUG(2, __FUNCTION__ "(), probing suspended=%d\n", info->suspended);
+	IRDA_DEBUG(2, "%s(), probing suspended=%d\n", __FUNCTION__, info->suspended);
 	
 	/* Exit configuration */
 	outb(0xbb, cfg_base);
 		
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End -----------------\n");	
+	IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __FUNCTION__);	
 	
 	return 0;	
 }
@@ -528,8 +526,13 @@
 	int version;
 	int iobase = info->fir_base;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 	
+	/* Locking comments :
+	 * Most operations here need to be protected. We are called before
+	 * the device instance is created in ali_ircc_open(), therefore 
+	 * nobody can bother us - Jean II */
+
 	/* Switch to FIR space */
 	SIR2FIR(iobase);
 	
@@ -584,7 +587,7 @@
 	// outb(UART_IER_RDI, iobase+UART_IER); //benjamin 2000/11/23 01:25PM
 	// Turn on the interrupts in ali_ircc_net_open
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 	
 	return 0;
 }
@@ -601,7 +604,7 @@
 	int dongle_id, reg;
 	int cfg_base = info->cfg_base;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 		
 	/* Enter Configuration */
 	outb(chips[i].entr1, cfg_base);
@@ -615,13 +618,13 @@
 	outb(0xf0, cfg_base);
 	reg = inb(cfg_base+1);	
 	dongle_id = ((reg>>6)&0x02) | ((reg>>5)&0x01);
-	IRDA_DEBUG(2, __FUNCTION__ "(), probing dongle_id=%d, dongle_types=%s\n", 
+	IRDA_DEBUG(2, "%s(), probing dongle_id=%d, dongle_types=%s\n", __FUNCTION__, 
 		dongle_id, dongle_types[dongle_id]);
 	
 	/* Exit configuration */
 	outb(0xbb, cfg_base);
 			
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 	
 	return dongle_id;
 }
@@ -637,7 +640,7 @@
 	struct net_device *dev = (struct net_device *) dev_id;
 	struct ali_ircc_cb *self;
 		
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 		
  	if (!dev) {
 		WARNING("%s: irq %d for unknown device.\n", driver_name, irq);
@@ -656,7 +659,7 @@
 		
 	spin_unlock(&self->lock);
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");		
+	IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__);		
 }
 /*
  * Function ali_ircc_fir_interrupt(irq, struct ali_ircc_cb *self, regs)
@@ -669,7 +672,7 @@
 	__u8 eir, OldMessageCount;
 	int iobase, tmp;
 	
-	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(1, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 	
 	iobase = self->io.fir_base;
 	
@@ -682,10 +685,10 @@
 	//self->ier = inb(iobase+FIR_IER); 		2000/12/1 04:32PM
 	eir = self->InterruptID & self->ier; /* Mask out the interesting ones */ 
 	
-	IRDA_DEBUG(1, __FUNCTION__ "(), self->InterruptID = %x\n",self->InterruptID);
-	IRDA_DEBUG(1, __FUNCTION__ "(), self->LineStatus = %x\n",self->LineStatus);
-	IRDA_DEBUG(1, __FUNCTION__ "(), self->ier = %x\n",self->ier);
-	IRDA_DEBUG(1, __FUNCTION__ "(), eir = %x\n",eir);
+	IRDA_DEBUG(1, "%s(), self->InterruptID = %x\n", __FUNCTION__,self->InterruptID);
+	IRDA_DEBUG(1, "%s(), self->LineStatus = %x\n", __FUNCTION__,self->LineStatus);
+	IRDA_DEBUG(1, "%s(), self->ier = %x\n", __FUNCTION__,self->ier);
+	IRDA_DEBUG(1, "%s(), eir = %x\n", __FUNCTION__,eir);
 	
 	/* Disable interrupts */
 	 SetCOMInterrupts(self, FALSE);
@@ -696,7 +699,7 @@
 	{		
 		if (self->io.direction == IO_XMIT) /* TX */
 		{
-			IRDA_DEBUG(1, __FUNCTION__ "(), ******* IIR_EOM (Tx) *******\n");
+			IRDA_DEBUG(1, "%s(), ******* IIR_EOM (Tx) *******\n", __FUNCTION__);
 			
 			if(ali_ircc_dma_xmit_complete(self))
 			{
@@ -715,23 +718,23 @@
 		}	
 		else /* RX */
 		{
-			IRDA_DEBUG(1, __FUNCTION__ "(), ******* IIR_EOM (Rx) *******\n");
+			IRDA_DEBUG(1, "%s(), ******* IIR_EOM (Rx) *******\n", __FUNCTION__);
 			
 			if(OldMessageCount > ((self->LineStatus+1) & 0x07))
 			{
 				self->rcvFramesOverflow = TRUE;	
-				IRDA_DEBUG(1, __FUNCTION__ "(), ******* self->rcvFramesOverflow = TRUE ******** \n");
+				IRDA_DEBUG(1, "%s(), ******* self->rcvFramesOverflow = TRUE ******** \n", __FUNCTION__);
 			}
 						
 			if (ali_ircc_dma_receive_complete(self))
 			{
-				IRDA_DEBUG(1, __FUNCTION__ "(), ******* receive complete ******** \n");
+				IRDA_DEBUG(1, "%s(), ******* receive complete ******** \n", __FUNCTION__);
 				
 				self->ier = IER_EOM;				
 			}
 			else
 			{
-				IRDA_DEBUG(1, __FUNCTION__ "(), ******* Not receive complete ******** \n");
+				IRDA_DEBUG(1, "%s(), ******* Not receive complete ******** \n", __FUNCTION__);
 				
 				self->ier = IER_EOM | IER_TIMER;								
 			}	
@@ -744,7 +747,7 @@
 		if(OldMessageCount > ((self->LineStatus+1) & 0x07))
 		{
 			self->rcvFramesOverflow = TRUE;	
-			IRDA_DEBUG(1, __FUNCTION__ "(), ******* self->rcvFramesOverflow = TRUE ******* \n");
+			IRDA_DEBUG(1, "%s(), ******* self->rcvFramesOverflow = TRUE ******* \n", __FUNCTION__);
 		}
 		/* Disable Timer */
 		switch_bank(iobase, BANK1);
@@ -776,7 +779,7 @@
 	/* Restore Interrupt */	
 	SetCOMInterrupts(self, TRUE);	
 		
-	IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ---------------\n");
+	IRDA_DEBUG(1, "%s(), ----------------- End ---------------\n", __FUNCTION__);
 }
 
 /*
@@ -790,7 +793,7 @@
 	int iobase;
 	int iir, lsr;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 	
 	iobase = self->io.sir_base;
 
@@ -799,14 +802,13 @@
 		/* Clear interrupt */
 		lsr = inb(iobase+UART_LSR);
 
-		IRDA_DEBUG(4, __FUNCTION__ 
-			   "(), iir=%02x, lsr=%02x, iobase=%#x\n", 
+		IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n", __FUNCTION__, 
 			   iir, lsr, iobase);
 
 		switch (iir) 
 		{
 			case UART_IIR_RLSI:
-				IRDA_DEBUG(2, __FUNCTION__ "(), RLSI\n");
+				IRDA_DEBUG(2, "%s(), RLSI\n", __FUNCTION__);
 				break;
 			case UART_IIR_RDI:
 				/* Receive interrupt */
@@ -820,14 +822,14 @@
 				}				
 				break;
 			default:
-				IRDA_DEBUG(0, __FUNCTION__ "(), unhandled IIR=%#x\n", iir);
+				IRDA_DEBUG(0, "%s(), unhandled IIR=%#x\n", __FUNCTION__, iir);
 				break;
 		} 
 		
 	}
 	
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
+	IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __FUNCTION__);	
 }
 
 
@@ -842,7 +844,7 @@
 	int boguscount = 0;
 	int iobase;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
+	IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
 	ASSERT(self != NULL, return;);
 
 	iobase = self->io.sir_base;
@@ -857,7 +859,7 @@
 
 		/* Make sure we don't stay here to long */
 		if (boguscount++ > 32) {
-			IRDA_DEBUG(2,__FUNCTION__ "(), breaking!\n");
+			IRDA_DEBUG(2,"%s(), breaking!\n", __FUNCTION__);
 			break;
 		}
 	} while (inb(iobase+UART_LSR) & UART_LSR_DR);	
@@ -937,6 +939,9 @@
 	
 	IRDA_DEBUG(2, __FUNCTION__ "(), setting speed = %d \n", baud);
 	
+	/* This function *must* be called with irq off and spin-lock.
+	 * - Jean II */
+
 	iobase = self->io.fir_base;
 	
 	SetCOMInterrupts(self, FALSE); // 2000/11/24 11:43AM
@@ -1084,7 +1089,6 @@
 	
 	struct ali_ircc_cb *self = (struct ali_ircc_cb *) priv;
 	int iobase,dongle_id;
-	unsigned long flags;
 	int tmp = 0;
 			
 	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n");	
@@ -1092,8 +1096,7 @@
 	iobase = self->io.fir_base; 	/* or iobase = self->io.sir_base; */
 	dongle_id = self->io.dongle_id;
 	
-	save_flags(flags);
-	cli();
+	/* We are already locked, no need to do it again */
 		
 	IRDA_DEBUG(1, __FUNCTION__ "(), Set Speed for %s , Speed = %d\n", dongle_types[dongle_id], speed);		
 	
@@ -1259,8 +1262,6 @@
 			
 	switch_bank(iobase, BANK0);
 	
-	restore_flags(flags);
-		
 	IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n");		
 }
 
@@ -1440,20 +1441,26 @@
 
 	netif_stop_queue(dev);
 	
+	/* Make sure tests *& speed change are atomic */
+	spin_lock_irqsave(&self->lock, flags);
+	
+	/* Note : you should make sure that speed changes are not going
+	 * to corrupt any outgoing frame. Look at nsc-ircc for the gory
+	 * details - Jean II */
+
 	/* Check if we need to change the speed */
 	speed = irda_get_next_speed(skb);
 	if ((speed != self->io.speed) && (speed != -1)) {
 		/* Check for empty frame */
 		if (!skb->len) {
 			ali_ircc_change_speed(self, speed); 
+			spin_unlock_irqrestore(&self->lock, flags);
 			dev_kfree_skb(skb);
 			return 0;
 		} else
 			self->new_speed = speed;
 	}
 
-	spin_lock_irqsave(&self->lock, flags);
-	
 	/* Register and copy this frame to DMA memory */
 	self->tx_fifo.queue[self->tx_fifo.free].start = self->tx_fifo.tail;
 	self->tx_fifo.queue[self->tx_fifo.free].len = skb->len;
@@ -1651,7 +1658,7 @@
 	if((inb(iobase+FIR_LSR) & LSR_FRAME_ABORT) == LSR_FRAME_ABORT)
 	
 	{
-		ERROR(__FUNCTION__ "(), ********* LSR_FRAME_ABORT *********\n");	
+		ERROR("%s(), ********* LSR_FRAME_ABORT *********\n", __FUNCTION__);	
 		self->stats.tx_errors++;
 		self->stats.tx_fifo_errors++;		
 	}
@@ -1898,8 +1905,8 @@
 			skb = dev_alloc_skb(len+1);
 			if (skb == NULL)  
 			{
-				WARNING(__FUNCTION__ "(), memory squeeze, "
-					"dropping frame.\n");
+				WARNING("%s(), memory squeeze, "
+					"dropping frame.\n", __FUNCTION__);
 				self->stats.rx_dropped++;
 
 				return FALSE;
@@ -1957,20 +1964,26 @@
 
 	netif_stop_queue(dev);
 	
+	/* Make sure tests *& speed change are atomic */
+	spin_lock_irqsave(&self->lock, flags);
+
+	/* Note : you should make sure that speed changes are not going
+	 * to corrupt any outgoing frame. Look at nsc-ircc for the gory
+	 * details - Jean II */
+
 	/* Check if we need to change the speed */
 	speed = irda_get_next_speed(skb);
 	if ((speed != self->io.speed) && (speed != -1)) {
 		/* Check for empty frame */
 		if (!skb->len) {
 			ali_ircc_change_speed(self, speed); 
+			spin_unlock_irqrestore(&self->lock, flags);
 			dev_kfree_skb(skb);
 			return 0;
 		} else
 			self->new_speed = speed;
 	}
 
-	spin_lock_irqsave(&self->lock, flags);
-
 	/* Init tx buffer */
 	self->tx_buff.data = self->tx_buff.head;
 
@@ -2016,10 +2029,6 @@
 
 	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
 	
-	/* Disable interrupts & save flags */
-	save_flags(flags);
-	cli();	
-	
 	switch (cmd) {
 	case SIOCSBANDWIDTH: /* Set bandwidth */
 		IRDA_DEBUG(1, __FUNCTION__ "(), SIOCSBANDWIDTH\n");
@@ -2031,7 +2040,9 @@
 		if (!in_interrupt() && !capable(CAP_NET_ADMIN))
 			return -EPERM;
 		
+		spin_lock_irqsave(&self->lock, flags);
 		ali_ircc_change_speed(self, irq->ifr_baudrate);		
+		spin_unlock_irqrestore(&self->lock, flags);
 		break;
 	case SIOCSMEDIABUSY: /* Set media busy */
 		IRDA_DEBUG(1, __FUNCTION__ "(), SIOCSMEDIABUSY\n");
@@ -2041,14 +2052,13 @@
 		break;
 	case SIOCGRECEIVING: /* Check if we are receiving right now */
 		IRDA_DEBUG(2, __FUNCTION__ "(), SIOCGRECEIVING\n");
+		/* This is protected */
 		irq->ifr_receiving = ali_ircc_is_receiving(self);
 		break;
 	default:
 		ret = -EOPNOTSUPP;
 	}
 	
-	restore_flags(flags);
-	
 	IRDA_DEBUG(2, __FUNCTION__ "(), ----------------- End ------------------\n");	
 	
 	return ret;
@@ -2219,19 +2229,16 @@
 static void SIR2FIR(int iobase)
 {
 	//unsigned char tmp;
-	unsigned long flags;
 		
 	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n");
 	
-	save_flags(flags);
-	cli();
+	/* Already protected (change_speed() or setup()), no need to lock.
+	 * Jean II */
 	
 	outb(0x28, iobase+UART_MCR);
 	outb(0x68, iobase+UART_MCR);
 	outb(0x88, iobase+UART_MCR);		
 	
-	restore_flags(flags);
-		
 	outb(0x60, iobase+FIR_MCR); 	/*  Master Reset */
 	outb(0x20, iobase+FIR_MCR); 	/*  Master Interrupt Enable */
 	
@@ -2245,12 +2252,11 @@
 static void FIR2SIR(int iobase)
 {
 	unsigned char val;
-	unsigned long flags;
 	
 	IRDA_DEBUG(1, __FUNCTION__ "(), ---------------- Start ----------------\n");
 	
-	save_flags(flags);
-	cli();
+	/* Already protected (change_speed() or setup()), no need to lock.
+	 * Jean II */
 	
 	outb(0x20, iobase+FIR_MCR); 	/* IRQ to low */
 	outb(0x00, iobase+UART_IER); 	
@@ -2262,8 +2268,6 @@
 	val = inb(iobase+UART_RX);
 	val = inb(iobase+UART_LSR);
 	val = inb(iobase+UART_MSR);
-	
-	restore_flags(flags);
 	
 	IRDA_DEBUG(1, __FUNCTION__ "(), ----------------- End ------------------\n");
 }
diff -Nru a/drivers/net/irda/girbil.c b/drivers/net/irda/girbil.c
--- a/drivers/net/irda/girbil.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/net/irda/girbil.c	Fri Sep 20 08:20:41 2002
@@ -129,7 +129,7 @@
 		}
 		break;
 	case IRDA_TASK_CHILD_WAIT:
-		WARNING(__FUNCTION__ "(), resetting dongle timed out!\n");
+		WARNING("%s(), resetting dongle timed out!\n", __FUNCTION__);
 		ret = -1;
 		break;
 	case IRDA_TASK_CHILD_DONE:
@@ -168,7 +168,7 @@
 		self->speed_task = NULL;
 		break;
 	default:
-		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		self->speed_task = NULL;
 		ret = -1;
@@ -221,7 +221,7 @@
 		self->reset_task = NULL;
 		break;
 	default:
-		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		self->reset_task = NULL;
 		ret = -1;
diff -Nru a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
--- a/drivers/net/irda/irda-usb.c	Fri Sep 20 08:20:46 2002
+++ b/drivers/net/irda/irda-usb.c	Fri Sep 20 08:20:46 2002
@@ -1171,7 +1171,7 @@
 	irda_usb_init_qos(self);
 	
 	/* Initialise list of skb beeing curently transmitted */
-	self->tx_list = hashbin_new(HB_GLOBAL);
+	self->tx_list = hashbin_new(HB_NOLOCK);	/* unused */
 
 	/* Allocate the buffer for speed changes */
 	/* Don't change this buffer size and allocation without doing
diff -Nru a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c
--- a/drivers/net/irda/irport.c	Fri Sep 20 08:20:42 2002
+++ b/drivers/net/irda/irport.c	Fri Sep 20 08:20:42 2002
@@ -124,7 +124,7 @@
 {
  	int i;
 
-        IRDA_DEBUG( 4, __FUNCTION__ "()\n");
+        IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
 
 	for (i=0; i < 4; i++) {
  		if (dev_self[i])
@@ -140,15 +140,15 @@
 	void *ret;
 	int err;
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 
 	/*
 	 *  Allocate new instance of the driver
 	 */
 	self = kmalloc(sizeof(struct irport_cb), GFP_KERNEL);
 	if (!self) {
-		ERROR(__FUNCTION__ "(), can't allocate memory for "
-		      "control block!\n");
+		ERROR("%s(), can't allocate memory for "
+		      "control block!\n", __FUNCTION__);
 		return NULL;
 	}
 	memset(self, 0, sizeof(struct irport_cb));
@@ -168,8 +168,8 @@
 	/* Lock the port that we need */
 	ret = request_region(self->io.sir_base, self->io.sir_ext, driver_name);
 	if (!ret) { 
-		IRDA_DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
-			   self->io.sir_base);
+		IRDA_DEBUG(0, "%s(), can't get iobase of 0x%03x\n",
+			   __FUNCTION__, self->io.sir_base);
 		return NULL;
 	}
 
@@ -212,7 +212,7 @@
 	self->mode = IRDA_IRLAP;
 
 	if (!(dev = dev_alloc("irda%d", &err))) {
-		ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+		ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__);
 		return NULL;
 	}
 	self->netdev = dev;
@@ -240,7 +240,7 @@
 	err = register_netdevice(dev);
 	rtnl_unlock();
 	if (err) {
-		ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
+		ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
 		return NULL;
 	}
 	MESSAGE("IrDA: Registered device %s\n", dev->name);
@@ -265,8 +265,8 @@
 	}
 
 	/* Release the IO-port that this driver is using */
-	IRDA_DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n", 
-		   self->io.sir_base);
+	IRDA_DEBUG(0 , "%s(), Releasing Region %03x\n", 
+		   __FUNCTION__, self->io.sir_base);
 	release_region(self->io.sir_base, self->io.sir_ext);
 
 	if (self->tx_buff.head)
@@ -284,14 +284,13 @@
 
 void irport_start(struct irport_cb *self)
 {
-	unsigned long flags;
 	int iobase;
 
 	iobase = self->io.sir_base;
 
 	irport_stop(self);
 	
-	spin_lock_irqsave(&self->lock, flags);
+	/* We can't lock, we may be called from a FIR driver - Jean II */
 
 	/* Initialize UART */
 	outb(UART_LCR_WLEN8, iobase+UART_LCR);  /* Reset DLAB */
@@ -299,26 +298,21 @@
 	
 	/* Turn on interrups */
 	outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, iobase+UART_IER);
-
-	spin_unlock_irqrestore(&self->lock, flags);
 }
 
 void irport_stop(struct irport_cb *self)
 {
-	unsigned long flags;
 	int iobase;
 
 	iobase = self->io.sir_base;
 
-	spin_lock_irqsave(&self->lock, flags);
+	/* We can't lock, we may be called from a FIR driver - Jean II */
 
 	/* Reset UART */
 	outb(0, iobase+UART_MCR);
 	
 	/* Turn off interrupts */
 	outb(0, iobase+UART_IER);
-
-	spin_unlock_irqrestore(&self->lock, flags);
 }
 
 /*
@@ -329,7 +323,7 @@
  */
 int irport_probe(int iobase)
 {
-	IRDA_DEBUG(4, __FUNCTION__ "(), iobase=%#x\n", iobase);
+	IRDA_DEBUG(4, "%s(), iobase=%#x\n", __FUNCTION__, iobase);
 
 	return 0;
 }
@@ -339,27 +333,28 @@
  *
  *    Set speed of IrDA port to specified baudrate
  *
+ * This function should be called with irq off and spin-lock.
  */
 void irport_change_speed(void *priv, __u32 speed)
 {
 	struct irport_cb *self = (struct irport_cb *) priv;
-	unsigned long flags;
 	int iobase; 
 	int fcr;    /* FIFO control reg */
 	int lcr;    /* Line control reg */
 	int divisor;
 
-	IRDA_DEBUG(0, __FUNCTION__ "(), Setting speed to: %d\n", speed);
-
 	ASSERT(self != NULL, return;);
 
+	IRDA_DEBUG(1, "%s(), Setting speed to: %d - iobase=%#x\n",
+		    __FUNCTION__, speed, self->io.sir_base);
+
+	/* We can't lock, we may be called from a FIR driver - Jean II */
+
 	iobase = self->io.sir_base;
 	
 	/* Update accounting for new speed */
 	self->io.speed = speed;
 
-	spin_lock_irqsave(&self->lock, flags);
-
 	/* Turn off interrupts */
 	outb(0, iobase+UART_IER); 
 
@@ -387,9 +382,9 @@
 	outb(fcr,		  iobase+UART_FCR); /* Enable FIFO's */
 
 	/* Turn on interrups */
-	outb(/*UART_IER_RLSI|*/UART_IER_RDI/*|UART_IER_THRI*/, iobase+UART_IER);
-
-	spin_unlock_irqrestore(&self->lock, flags);
+	/* This will generate a fata interrupt storm.
+	 * People calling us will do that properly - Jean II */
+	//outb(/*UART_IER_RLSI|*/UART_IER_RDI/*|UART_IER_THRI*/, iobase+UART_IER);
 }
 
 /*
@@ -397,19 +392,33 @@
  *
  *    State machine for changing speed of the device. We do it this way since
  *    we cannot use schedule_timeout() when we are in interrupt context
+ *
  */
 int __irport_change_speed(struct irda_task *task)
 {
 	struct irport_cb *self;
 	__u32 speed = (__u32) task->param;
+	unsigned long flags = 0;
+	int wasunlocked = 0;
 	int ret = 0;
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), <%ld>\n", jiffies); 
+	IRDA_DEBUG(2, "%s(), <%ld>\n", __FUNCTION__, jiffies); 
 
 	self = (struct irport_cb *) task->instance;
 
 	ASSERT(self != NULL, return -1;);
 
+	/* Locking notes : this function may be called from irq context with
+	 * spinlock, via irport_write_wakeup(), or from non-interrupt without
+	 * spinlock (from the task timer). Yuck !
+	 * This is ugly, and unsafe is the spinlock is not already aquired.
+	 * This will be fixed when irda-task get rewritten.
+	 * Jean II */
+	if (!spin_is_locked(&self->lock)) {
+		spin_lock_irqsave(&self->lock, flags);
+		wasunlocked = 1;
+	}
+
 	switch (task->state) {
 	case IRDA_TASK_INIT:
 	case IRDA_TASK_WAIT:
@@ -446,8 +455,7 @@
 			irda_task_next_state(task, IRDA_TASK_CHILD_DONE);
 		break;
 	case IRDA_TASK_CHILD_WAIT:
-		WARNING(__FUNCTION__ 
-			"(), changing speed of dongle timed out!\n");
+		WARNING("%s(), changing speed of dongle timed out!\n", __FUNCTION__);
 		ret = -1;		
 		break;
 	case IRDA_TASK_CHILD_DONE:
@@ -457,11 +465,16 @@
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		break;
 	default:
-		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		ret = -1;
 		break;
 	}	
+	/* Put stuff in the sate we found them - Jean II */
+	if(wasunlocked) {
+		spin_unlock_irqrestore(&self->lock, flags);
+	}
+
 	return ret;
 }
 
@@ -480,7 +493,7 @@
 
 	ASSERT(self != NULL, return;);
 
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	iobase = self->io.sir_base;
 
@@ -491,6 +504,9 @@
 				      self->tx_buff.data, self->tx_buff.len);
 		self->tx_buff.data += actual;
 		self->tx_buff.len  -= actual;
+
+		/* Turn on transmit finished interrupt. */
+		outb(UART_IER_THRI, iobase+UART_IER); 
 	} else {
 		/* 
 		 *  Now serial buffer is almost free & we can start 
@@ -498,11 +514,12 @@
 		 *  if we need to change the speed of the hardware
 		 */
 		if (self->new_speed) {
-			IRDA_DEBUG(5, __FUNCTION__ "(), Changing speed!\n");
+			IRDA_DEBUG(5, "%s(), Changing speed!\n", __FUNCTION__);
 			irda_task_execute(self, __irport_change_speed, 
 					  irport_change_speed_complete, 
 					  NULL, (void *) self->new_speed);
 			self->new_speed = 0;
+			IRDA_DEBUG(5, "%s(), Speed changed!\n", __FUNCTION__ );
 		} else {
 			/* Tell network layer that we want more frames */
 			netif_wake_queue(self->netdev);
@@ -538,7 +555,7 @@
 
 	/* Tx FIFO should be empty! */
 	if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), failed, fifo not empty!\n");
+		IRDA_DEBUG(0, "%s(), failed, fifo not empty!\n", __FUNCTION__);
 		return 0;
 	}
         
@@ -563,7 +580,7 @@
 {
 	struct irport_cb *self;
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 
 	self = (struct irport_cb *) task->instance;
 
@@ -589,13 +606,19 @@
 {
 	struct irport_cb *self;
 	int iobase;
+	unsigned long flags;
 
 	self = (struct irport_cb *) dev->priv;
 	iobase = self->io.sir_base;
 	
 	WARNING("%s: transmit timed out\n", dev->name);
+	spin_lock_irqsave(&self->lock, flags);
 	irport_start(self);
 	self->change_speed(self->priv, self->io.speed);
+	/* This will re-enable irqs */
+	outb(/*UART_IER_RLSI|*/UART_IER_RDI/*|UART_IER_THRI*/, iobase+UART_IER);
+	spin_unlock_irqrestore(&self->lock, flags);
+
 	dev->trans_start = jiffies;
 	netif_wake_queue(dev);
 }
@@ -614,7 +637,7 @@
 	int iobase;
 	s32 speed;
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 
 	ASSERT(dev != NULL, return 0;);
 	
@@ -625,22 +648,25 @@
 
 	netif_stop_queue(dev);
 	
+	/* Make sure tests *& speed change are atomic */
+	spin_lock_irqsave(&self->lock, flags);
+
 	/* Check if we need to change the speed */
 	speed = irda_get_next_speed(skb);
 	if ((speed != self->io.speed) && (speed != -1)) {
 		/* Check for empty frame */
 		if (!skb->len) {
+			/* Better go there already locked - Jean II */
 			irda_task_execute(self, __irport_change_speed, 
 					  irport_change_speed_complete, 
 					  NULL, (void *) speed);
+			spin_unlock_irqrestore(&self->lock, flags);
 			dev_kfree_skb(skb);
 			return 0;
 		} else
 			self->new_speed = speed;
 	}
 
-	spin_lock_irqsave(&self->lock, flags);
-
 	/* Init tx buffer */
 	self->tx_buff.data = self->tx_buff.head;
 
@@ -685,7 +711,7 @@
 
 		/* Make sure we don't stay here to long */
 		if (boguscount++ > 32) {
-			IRDA_DEBUG(2,__FUNCTION__ "(), breaking!\n");
+			IRDA_DEBUG(2,"%s(), breaking!\n", __FUNCTION__);
 			break;
 		}
 	} while (inb(iobase+UART_LSR) & UART_LSR_DR);	
@@ -705,7 +731,7 @@
 	int iir, lsr;
 
 	if (!dev) {
-		WARNING(__FUNCTION__ "() irq %d for unknown device.\n", irq);
+		WARNING("%s() irq %d for unknown device.\n", __FUNCTION__, irq);
 		return;
 	}
 	self = (struct irport_cb *) dev->priv;
@@ -719,13 +745,12 @@
 		/* Clear interrupt */
 		lsr = inb(iobase+UART_LSR);
 
-		IRDA_DEBUG(4, __FUNCTION__ 
-			   "(), iir=%02x, lsr=%02x, iobase=%#x\n", 
-			   iir, lsr, iobase);
+		IRDA_DEBUG(4, "%s(), iir=%02x, lsr=%02x, iobase=%#x\n", 
+			   __FUNCTION__, iir, lsr, iobase);
 
 		switch (iir) {
 		case UART_IIR_RLSI:
-			IRDA_DEBUG(2, __FUNCTION__ "(), RLSI\n");
+			IRDA_DEBUG(2, "%s(), RLSI\n", __FUNCTION__);
 			break;
 		case UART_IIR_RDI:
 			/* Receive interrupt */
@@ -737,7 +762,7 @@
 				irport_write_wakeup(self);
 			break;
 		default:
-			IRDA_DEBUG(0, __FUNCTION__ "(), unhandled IIR=%#x\n", iir);
+			IRDA_DEBUG(0, "%s(), unhandled IIR=%#x\n", __FUNCTION__, iir);
 			break;
 		} 
 		
@@ -771,8 +796,9 @@
 	struct irport_cb *self;
 	int iobase;
 	char hwname[16];
+	unsigned long flags;
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, "%s()\n", __FUNCTION__);
 	
 	ASSERT(dev != NULL, return -1;);
 	self = (struct irport_cb *) dev->priv;
@@ -781,12 +807,14 @@
 
 	if (request_irq(self->io.irq, self->interrupt, 0, dev->name, 
 			(void *) dev)) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), unable to allocate irq=%d\n",
-			   self->io.irq);
+		IRDA_DEBUG(0, "%s(), unable to allocate irq=%d\n",
+			   __FUNCTION__, self->io.irq);
 		return -EAGAIN;
 	}
 
+	spin_lock_irqsave(&self->lock, flags);
 	irport_start(self);
+	spin_unlock_irqrestore(&self->lock, flags);
 
 
 	/* Give self a hardware name */
@@ -818,8 +846,9 @@
 {
 	struct irport_cb *self;
 	int iobase;
+	unsigned long flags;
 
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	ASSERT(dev != NULL, return -1;);
 	self = (struct irport_cb *) dev->priv;
@@ -836,7 +865,9 @@
 		irlap_close(self->irlap);
 	self->irlap = NULL;
 
+	spin_lock_irqsave(&self->lock, flags);
 	irport_stop(self);
+	spin_unlock_irqrestore(&self->lock, flags);
 
 	free_irq(self->io.irq, dev);
 
@@ -860,7 +891,7 @@
 
 	/* Wait until Tx FIFO is empty */
 	while (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
-		IRDA_DEBUG(2, __FUNCTION__ "(), waiting!\n");
+		IRDA_DEBUG(2, "%s(), waiting!\n", __FUNCTION__);
 		current->state = TASK_INTERRUPTIBLE;
 		schedule_timeout(MSECS_TO_JIFFIES(60));
 	}
@@ -915,7 +946,7 @@
 
 	/* Tx FIFO should be empty! */
 	if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
-		IRDA_DEBUG( 0, __FUNCTION__ "(), failed, fifo not empty!\n");
+		IRDA_DEBUG( 0, "%s(), failed, fifo not empty!\n", __FUNCTION__);
 		return -1;
 	}
         
@@ -949,11 +980,7 @@
 
 	ASSERT(self != NULL, return -1;);
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
-	
-	/* Disable interrupts & save flags */
-	save_flags(flags);
-	cli();
+	IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, dev->name, cmd);
 	
 	switch (cmd) {
 	case SIOCSBANDWIDTH: /* Set bandwidth */
@@ -979,14 +1006,16 @@
 		dongle->write       = irport_raw_write;
 		dongle->set_dtr_rts = irport_set_dtr_rts;
 		
-		self->dongle = dongle;
-
 		/* Now initialize the dongle!  */
 		dongle->issue->open(dongle, &self->qos);
 		
 		/* Reset dongle */
 		irda_task_execute(dongle, dongle->issue->reset, NULL, NULL, 
 				  NULL);	
+
+		/* Make dongle available to driver only now to avoid
+		 * race conditions - Jean II */
+		self->dongle = dongle;
 		break;
 	case SIOCSMEDIABUSY: /* Set media busy */
 		if (!capable(CAP_NET_ADMIN)) {
@@ -1005,13 +1034,14 @@
 			break;
 		}
 
+		/* No real need to lock... */
+		spin_lock_irqsave(&self->lock, flags);
 		irport_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
+		spin_unlock_irqrestore(&self->lock, flags);
 		break;
 	default:
 		ret = -EOPNOTSUPP;
 	}
-	
-	restore_flags(flags);
 	
 	return ret;
 }
diff -Nru a/drivers/net/irda/irtty.c b/drivers/net/irda/irtty.c
--- a/drivers/net/irda/irtty.c	Fri Sep 20 08:20:43 2002
+++ b/drivers/net/irda/irtty.c	Fri Sep 20 08:20:43 2002
@@ -74,8 +74,10 @@
 int __init irtty_init(void)
 {
 	int status;
-	
-	irtty = hashbin_new( HB_LOCAL);
+
+	/* Probably no need to lock here because all operations done in
+	 * open()/close() which are already safe - Jean II */
+	irtty = hashbin_new( HB_NOLOCK);
 	if ( irtty == NULL) {
 		printk( KERN_WARNING "IrDA: Can't allocate irtty hashbin!\n");
 		return -ENOMEM;
@@ -118,9 +120,8 @@
 	
 	/* Unregister tty line-discipline */
 	if ((ret = tty_register_ldisc(N_IRDA, NULL))) {
-		ERROR(__FUNCTION__ 
-		      "(), can't unregister line discipline (err = %d)\n",
-		      ret);
+		ERROR("%s(), can't unregister line discipline (err = %d)\n",
+		      __FUNCTION__, ret);
 	}
 
 	/*
@@ -163,6 +164,7 @@
 		return -ENOMEM;
 	}
 	memset(self, 0, sizeof(struct irtty_cb));
+	spin_lock_init(&self->lock);
 	
 	self->tty = tty;
 	tty->disc_data = self;
@@ -226,7 +228,7 @@
 	self->rx_buff.data = self->rx_buff.head;
 	
 	if (!(dev = dev_alloc("irda%d", &err))) {
-		ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+		ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__);
 		return -ENOMEM;
 	}
 
@@ -245,7 +247,7 @@
 	err = register_netdevice(dev);
 	rtnl_unlock();
 	if (err) {
-		ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
+		ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
 		return -1;
 	}
 
@@ -266,11 +268,12 @@
 static void irtty_close(struct tty_struct *tty) 
 {
 	struct irtty_cb *self = (struct irtty_cb *) tty->disc_data;
+	unsigned long flags;
 	
 	/* First make sure we're connected. */
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRTTY_MAGIC, return;);
-	
+
 	/* Stop tty */
 	tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
 	tty->disc_data = 0;
@@ -287,6 +290,11 @@
 		rtnl_unlock();
 	}
 	
+	self = hashbin_remove(irtty, (int) self, NULL);
+
+	/* Protect access to self->task and self->?x_buff - Jean II */
+	spin_lock_irqsave(&self->lock, flags);
+
 	/* Remove speed changing task if any */
 	if (self->task)
 		irda_task_delete(self->task);
@@ -294,13 +302,12 @@
 	self->tty = NULL;
 	self->magic = 0;
 	
-	self = hashbin_remove(irtty, (int) self, NULL);
-
 	if (self->tx_buff.head)
 		kfree(self->tx_buff.head);
 	
 	if (self->rx_buff.head)
 		kfree(self->rx_buff.head);
+	spin_unlock_irqrestore(&self->lock, flags);
 	
 	kfree(self);
 	
@@ -326,6 +333,7 @@
 	else
 		cflag |= CREAD;
 
+	/* This is unsafe, but currently under discussion - Jean II */
 	self->tty->termios->c_cflag = cflag;
 	self->tty->driver.set_termios(self->tty, &old_termios);
 }
@@ -378,6 +386,7 @@
 		break;
 	}	
 
+	/* This is unsafe, but currently under discussion - Jean II */
 	self->tty->termios->c_cflag = cflag;
 	self->tty->driver.set_termios(self->tty, &old_termios);
 
@@ -393,6 +402,7 @@
 static int irtty_change_speed(struct irda_task *task)
 {
 	struct irtty_cb *self;
+	unsigned long flags;
 	__u32 speed = (__u32) task->param;
 	int ret = 0;
 
@@ -401,12 +411,17 @@
 	self = (struct irtty_cb *) task->instance;
 	ASSERT(self != NULL, return -1;);
 
+	/* Protect access to self->task - Jean II */
+	spin_lock_irqsave(&self->lock, flags);
+
 	/* Check if busy */
 	if (self->task && self->task != task) {
 		IRDA_DEBUG(0, __FUNCTION__ "(), busy!\n");
+		spin_unlock_irqrestore(&self->lock, flags);
 		return MSECS_TO_JIFFIES(10);
 	} else
 		self->task = task;
+	spin_unlock_irqrestore(&self->lock, flags);
 
 	switch (task->state) {
 	case IRDA_TASK_INIT:
@@ -451,8 +466,7 @@
 			irda_task_next_state(task, IRDA_TASK_CHILD_DONE);
 		break;
 	case IRDA_TASK_CHILD_WAIT:
-		WARNING(__FUNCTION__ 
-			"(), changing speed of dongle timed out!\n");
+		WARNING("%s(), changing speed of dongle timed out!\n", __FUNCTION__);
 		ret = -1;		
 		break;
 	case IRDA_TASK_CHILD_DONE:
@@ -463,7 +477,7 @@
 		self->task = NULL;
 		break;
 	default:
-		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		self->task = NULL;
 		ret = -1;
@@ -501,6 +515,7 @@
 	switch (cmd) {
 	case TCGETS:
 	case TCGETA:
+		/* Unsure about locking here, to check - Jean II */
 		return n_tty_ioctl(tty, (struct file *) file, cmd, 
 				   (unsigned long) arg);
 		break;
@@ -516,15 +531,16 @@
 		dongle->write       = irtty_raw_write;
 		dongle->set_dtr_rts = irtty_set_dtr_rts;
 		
-		/* Bind dongle */
-		self->dongle = dongle;
-		
 		/* Now initialize the dongle!  */
 		dongle->issue->open(dongle, &self->qos);
 		
 		/* Reset dongle */
 		irda_task_execute(dongle, dongle->issue->reset, NULL, NULL, 
 				  NULL);		
+
+		/* Make dongle available to driver only now to avoid
+		 * race conditions - Jean II */
+		self->dongle = dongle;
 		break;
 	case IRTTY_IOCGET:
 		ASSERT(self->netdev != NULL, return -1;);
@@ -559,6 +575,9 @@
 		return;
 	}
 
+	// Are we in interrupt context ? What locking is done ? - Jean II
+	//spin_lock_irqsave(&self->lock, flags);
+
 	/* Read the characters out of the buffer */
  	while (count--) {
 		/* 
@@ -589,6 +608,7 @@
 			break;
 		}
 	}
+	//spin_unlock_irqrestore(&self->lock, flags);
 }
 
 /*
@@ -626,11 +646,13 @@
 	struct irtty_cb *self;
 	int actual = 0;
 	__s32 speed;
+	unsigned long flags;
 
 	self = (struct irtty_cb *) dev->priv;
 	ASSERT(self != NULL, return 0;);
 
-	/* Lock transmit buffer */
+	/* Lock transmit buffer
+	 * this serialise operations, no need to spinlock - Jean II */
 	netif_stop_queue(dev);
 	
 	/* Check if we need to change the speed */
@@ -647,6 +669,9 @@
 			self->new_speed = speed;
 	}
 
+	/* Protect access to self->tx_buff - Jean II */
+	spin_lock_irqsave(&self->lock, flags);
+
 	/* Init tx buffer*/
 	self->tx_buff.data = self->tx_buff.head;
 	
@@ -667,6 +692,8 @@
 	self->tx_buff.data += actual;
 	self->tx_buff.len -= actual;
 
+	spin_unlock_irqrestore(&self->lock, flags);
+
 	dev_kfree_skb(skb);
 
 	return 0;
@@ -695,6 +722,7 @@
 {
 	struct irtty_cb *self = (struct irtty_cb *) tty->disc_data;
 	int actual = 0;
+	unsigned long flags;
 	
 	/* 
 	 *  First make sure we're connected. 
@@ -702,6 +730,11 @@
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRTTY_MAGIC, return;);
 
+	/* Protected via netif_stop_queue(dev); - Jean II */
+
+	/* Protect access to self->tx_buff - Jean II */
+	spin_lock_irqsave(&self->lock, flags);
+
 	/* Finished with frame?  */
 	if (self->tx_buff.len > 0)  {
 		/* Write data left in transmit buffer */
@@ -710,6 +743,7 @@
 
 		self->tx_buff.data += actual;
 		self->tx_buff.len  -= actual;
+		spin_unlock_irqrestore(&self->lock, flags);
 	} else {		
 		/* 
 		 *  Now serial buffer is almost free & we can start 
@@ -721,6 +755,9 @@
 
 		tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
 
+		/* Don't change speed with irq off */
+		spin_unlock_irqrestore(&self->lock, flags);
+
 		if (self->new_speed) {
 			IRDA_DEBUG(5, __FUNCTION__ "(), Changing speed!\n");
 			irda_task_execute(self, irtty_change_speed, 
@@ -755,12 +792,17 @@
 {
 	struct irtty_cb *self;
 	struct tty_struct *tty;
+	//unsigned long flags;
 	mm_segment_t fs;
 	int arg = 0;
 
 	self = (struct irtty_cb *) dev->priv;
 	tty = self->tty;
 
+	/* Was protected in ioctl handler, but the serial driver doesn't
+	 * like it. This may need to change. - Jean II */
+	//spin_lock_irqsave(&self->lock, flags);
+
 #ifdef TIOCM_OUT2 /* Not defined for ARM */
 	arg = TIOCM_OUT2;
 #endif
@@ -780,11 +822,14 @@
 	fs = get_fs();
 	set_fs(get_ds());
 	
+	/* This is probably unsafe, but currently under discussion - Jean II */
 	if (tty->driver.ioctl(tty, NULL, TIOCMSET, (unsigned long) &arg)) { 
 		IRDA_DEBUG(2, __FUNCTION__ "(), error doing ioctl!\n");
 	}
 	set_fs(fs);
 
+	//spin_unlock_irqrestore(&self->lock, flags);
+
 	return 0;
 }
 
@@ -799,13 +844,17 @@
 int irtty_set_mode(struct net_device *dev, int mode)
 {
 	struct irtty_cb *self;
+	unsigned long flags;
 
 	self = (struct irtty_cb *) dev->priv;
 
 	ASSERT(self != NULL, return -1;);
 
 	IRDA_DEBUG(2, __FUNCTION__ "(), mode=%s\n", infrared_mode[mode]);
-	
+
+	/* Protect access to self->rx_buff - Jean II */
+	spin_lock_irqsave(&self->lock, flags);
+
 	/* save status for driver */
 	self->mode = mode;
 	
@@ -814,6 +863,8 @@
 	self->rx_buff.len = 0;
 	self->rx_buff.state = OUTSIDE_FRAME;
 
+	spin_unlock_irqrestore(&self->lock, flags);
+
 	return 0;
 }
 
@@ -955,7 +1006,6 @@
 	struct if_irda_req *irq = (struct if_irda_req *) rq;
 	struct irtty_cb *self;
 	dongle_t *dongle;
-	unsigned long flags;
 	int ret = 0;
 
 	ASSERT(dev != NULL, return -1;);
@@ -971,8 +1021,7 @@
 	 * irda_device_dongle_init() can't be locked.
 	 * irda_task_execute() doesn't need to be locked (but
 	 * irtty_change_speed() should protect itself).
-	 * As this driver doesn't have spinlock protection, keep
-	 * old fashion locking :-(
+	 * Other calls protect themselves.
 	 * Jean II
 	 */
 	
@@ -1025,20 +1074,14 @@
 		if (!capable(CAP_NET_ADMIN))
 			ret = -EPERM;
 		else {
-			save_flags(flags);
-			cli();
 			irtty_set_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
-			restore_flags(flags);
 		}
 		break;
 	case SIOCSMODE:
 		if (!capable(CAP_NET_ADMIN))
 			ret = -EPERM;
 		else {
-			save_flags(flags);
-			cli();
 			irtty_set_mode(dev, irq->ifr_mode);
-			restore_flags(flags);
 		}
 		break;
 	default:
diff -Nru a/drivers/net/irda/mcp2120.c b/drivers/net/irda/mcp2120.c
--- a/drivers/net/irda/mcp2120.c	Fri Sep 20 08:20:48 2002
+++ b/drivers/net/irda/mcp2120.c	Fri Sep 20 08:20:48 2002
@@ -109,7 +109,7 @@
 		}
 		break;
 	case IRDA_TASK_CHILD_WAIT:
-		WARNING(__FUNCTION__ "(), resetting dongle timed out!\n");
+		WARNING("%s(), resetting dongle timed out!\n", __FUNCTION__);
 		ret = -1;
 		break;
 	case IRDA_TASK_CHILD_DONE:
@@ -157,7 +157,7 @@
                 //printk("mcp2120_change_speed irda_task_wait\n");
 		break;
 	default:
-		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		self->speed_task = NULL;
 		ret = -1;
@@ -212,7 +212,7 @@
 		self->reset_task = NULL;
 		break;
 	default:
-		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		self->reset_task = NULL;
 		ret = -1;
diff -Nru a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
--- a/drivers/net/irda/nsc-ircc.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/net/irda/nsc-ircc.c	Fri Sep 20 08:20:41 2002
@@ -161,7 +161,7 @@
 
 	/* Probe for all the NSC chipsets we know about */
 	for (chip=chips; chip->name ; chip++) {
-		IRDA_DEBUG(2, __FUNCTION__"(), Probing for %s ...\n", 
+		IRDA_DEBUG(2, "%s(), Probing for %s ...\n", __FUNCTION__,
 			   chip->name);
 		
 		/* Try all config registers for this chip */
@@ -179,8 +179,7 @@
 			/* Read index register */
 			reg = inb(cfg_base);
 			if (reg == 0xff) {
-				IRDA_DEBUG(2, __FUNCTION__ 
-					   "() no chip at 0x%03x\n", cfg_base);
+				IRDA_DEBUG(2, "%s() no chip at 0x%03x\n", __FUNCTION__, cfg_base);
 				continue;
 			}
 			
@@ -188,9 +187,8 @@
 			outb(chip->cid_index, cfg_base);
 			id = inb(cfg_base+1);
 			if ((id & chip->cid_mask) == chip->cid_value) {
-				IRDA_DEBUG(2, __FUNCTION__ 
-					   "() Found %s chip, revision=%d\n",
-					   chip->name, id & ~chip->cid_mask);
+				IRDA_DEBUG(2, "%s() Found %s chip, revision=%d\n",
+					   __FUNCTION__, chip->name, id & ~chip->cid_mask);
 				/* 
 				 * If the user supplies the base address, then
 				 * we init the chip, if not we probe the values
@@ -205,8 +203,7 @@
 					ret = 0;
 				i++;
 			} else {
-				IRDA_DEBUG(2, __FUNCTION__ 
-					   "(), Wrong chip id=0x%02x\n", id);
+				IRDA_DEBUG(2, "%s(), Wrong chip id=0x%02x\n", __FUNCTION__, id);
 			}
 		} 
 		
@@ -247,7 +244,7 @@
 	void *ret;
 	int err;
 
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
 
 	MESSAGE("%s, Found chip at base=0x%03x\n", driver_name,
 		info->cfg_base);
@@ -260,8 +257,8 @@
 	/* Allocate new instance of the driver */
 	self = kmalloc(sizeof(struct nsc_ircc_cb), GFP_KERNEL);
 	if (self == NULL) {
-		ERROR(__FUNCTION__ "(), can't allocate memory for "
-		       "control block!\n");
+		ERROR("%s(), can't allocate memory for "
+		       "control block!\n", __FUNCTION__);
 		return -ENOMEM;
 	}
 	memset(self, 0, sizeof(struct nsc_ircc_cb));
@@ -282,8 +279,8 @@
 	/* Reserve the ioports that we need */
 	ret = request_region(self->io.fir_base, self->io.fir_ext, driver_name);
 	if (!ret) {
-		WARNING(__FUNCTION__ "(), can't get iobase of 0x%03x\n",
-			self->io.fir_base);
+		WARNING("%s(), can't get iobase of 0x%03x\n",
+			__FUNCTION__, self->io.fir_base);
 		dev_self[i] = NULL;
 		kfree(self);
 		return -ENODEV;
@@ -333,7 +330,7 @@
 	self->tx_fifo.tail = self->tx_buff.head;
 
 	if (!(dev = dev_alloc("irda%d", &err))) {
-		ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+		ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__);
 		return -ENOMEM;
 	}
 
@@ -352,7 +349,7 @@
 	err = register_netdevice(dev);
 	rtnl_unlock();
 	if (err) {
-		ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
+		ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
 		return -1;
 	}
 	MESSAGE("IrDA: Registered device %s\n", dev->name);
@@ -388,7 +385,7 @@
 {
 	int iobase;
 
-	IRDA_DEBUG(4, __FUNCTION__ "()\n");
+	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
 
 	ASSERT(self != NULL, return -1;);
 
@@ -402,8 +399,8 @@
 	}
 
 	/* Release the PORT that this driver is using */
-	IRDA_DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", 
-		   self->io.fir_base);
+	IRDA_DEBUG(4, "%s(), Releasing Region %03x\n", 
+		   __FUNCTION__, self->io.fir_base);
 	release_region(self->io.fir_base, self->io.fir_ext);
 
 	if (self->tx_buff.head)
@@ -439,7 +436,7 @@
 	case 0x2e8: outb(0x15, cfg_base+1); break;
 	case 0x3f8: outb(0x16, cfg_base+1); break;
 	case 0x2f8: outb(0x17, cfg_base+1); break;
-	default: ERROR(__FUNCTION__ "(), invalid base_address");
+	default: ERROR("%s(), invalid base_address", __FUNCTION__);
 	}
 	
 	/* Control Signal Routing Register (CSRT) */
@@ -451,7 +448,7 @@
 	case 9:  temp = 0x05; break;
 	case 11: temp = 0x06; break;
 	case 15: temp = 0x07; break;
-	default: ERROR(__FUNCTION__ "(), invalid irq");
+	default: ERROR("%s(), invalid irq", __FUNCTION__);
 	}
 	outb(1, cfg_base);
 	
@@ -459,7 +456,7 @@
 	case 0: outb(0x08+temp, cfg_base+1); break;
 	case 1: outb(0x10+temp, cfg_base+1); break;
 	case 3: outb(0x18+temp, cfg_base+1); break;
-	default: ERROR(__FUNCTION__ "(), invalid dma");
+	default: ERROR("%s(), invalid dma", __FUNCTION__);
 	}
 	
 	outb(2, cfg_base);      /* Mode Control Register (MCTL) */
@@ -498,7 +495,7 @@
 		break;
 	}
 	info->sir_base = info->fir_base;
-	IRDA_DEBUG(2, __FUNCTION__ "(), probing fir_base=0x%03x\n", 
+	IRDA_DEBUG(2, "%s(), probing fir_base=0x%03x\n", __FUNCTION__,
 		   info->fir_base);
 
 	/* Read control signals routing register (CSRT) */
@@ -531,7 +528,7 @@
 		info->irq = 15;
 		break;
 	}
-	IRDA_DEBUG(2, __FUNCTION__ "(), probing irq=%d\n", info->irq);
+	IRDA_DEBUG(2, "%s(), probing irq=%d\n", __FUNCTION__, info->irq);
 
 	/* Currently we only read Rx DMA but it will also be used for Tx */
 	switch ((reg >> 3) & 0x03) {
@@ -548,7 +545,7 @@
 		info->dma = 3;
 		break;
 	}
-	IRDA_DEBUG(2, __FUNCTION__ "(), probing dma=%d\n", info->dma);
+	IRDA_DEBUG(2, "%s(), probing dma=%d\n", __FUNCTION__, info->dma);
 
 	/* Read mode control register (MCTL) */
 	outb(CFG_MCTL, cfg_base);
@@ -694,8 +691,8 @@
 	switch_bank(iobase, BANK3);
 	version = inb(iobase+MID);
 
-	IRDA_DEBUG(2, __FUNCTION__  "() Driver %s Found chip version %02x\n",
-		   driver_name, version);
+	IRDA_DEBUG(2, "%s() Driver %s Found chip version %02x\n",
+		   __FUNCTION__, driver_name, version);
 
 	/* Should be 0x2? */
 	if (0x20 != (version & 0xf0)) {
@@ -797,39 +794,39 @@
 	switch (dongle_id) {
 	case 0x00: /* same as */
 	case 0x01: /* Differential serial interface */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
+			   __FUNCTION__, dongle_types[dongle_id]); 
 		break;
 	case 0x02: /* same as */
 	case 0x03: /* Reserved */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
+			   __FUNCTION__, dongle_types[dongle_id]); 
 		break;
 	case 0x04: /* Sharp RY5HD01 */
 		break;
 	case 0x05: /* Reserved, but this is what the Thinkpad reports */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
+			   __FUNCTION__, dongle_types[dongle_id]); 
 		break;
 	case 0x06: /* Single-ended serial interface */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
+			   __FUNCTION__, dongle_types[dongle_id]); 
 		break;
 	case 0x07: /* Consumer-IR only */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n",
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s is not for IrDA mode\n",
+			   __FUNCTION__, dongle_types[dongle_id]); 
 		break;
 	case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s\n",
-			   dongle_types[dongle_id]);
+		IRDA_DEBUG(0, "%s(), %s\n",
+			   __FUNCTION__, dongle_types[dongle_id]);
 		break;
 	case 0x09: /* IBM31T1100 or Temic TFDS6000/TFDS6500 */
 		outb(0x28, iobase+7); /* Set irsl[0-2] as output */
 		break;
 	case 0x0A: /* same as */
 	case 0x0B: /* Reserved */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
+			   __FUNCTION__, dongle_types[dongle_id]); 
 		break;
 	case 0x0C: /* same as */
 	case 0x0D: /* HP HSDL-1100/HSDL-2100 */
@@ -843,15 +840,15 @@
 		outb(0x28, iobase+7); /* Set irsl[0-2] as output */
 		break;
 	case 0x0F: /* No dongle connected */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s\n",
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s\n",
+			   __FUNCTION__, dongle_types[dongle_id]); 
 
 		switch_bank(iobase, BANK0);
 		outb(0x62, iobase+MCR);
 		break;
 	default: 
-		IRDA_DEBUG(0, __FUNCTION__ "(), invalid dongle_id %#x", 
-			   dongle_id);
+		IRDA_DEBUG(0, "%s(), invalid dongle_id %#x", 
+			   __FUNCTION__, dongle_id);
 	}
 	
 	/* IRCFG1: IRSL1 and 2 are set to IrDA mode */
@@ -870,7 +867,6 @@
  */
 static void nsc_ircc_change_dongle_speed(int iobase, int speed, int dongle_id)
 {
-	unsigned long flags;
 	__u8 bank;
 
 	/* Save current bank */
@@ -883,31 +879,31 @@
 	switch (dongle_id) {
 	case 0x00: /* same as */
 	case 0x01: /* Differential serial interface */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
+			   __FUNCTION__, dongle_types[dongle_id]); 
 		break;
 	case 0x02: /* same as */
 	case 0x03: /* Reserved */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
+			   __FUNCTION__, dongle_types[dongle_id]); 
 		break;
 	case 0x04: /* Sharp RY5HD01 */
 		break;
 	case 0x05: /* Reserved */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
+			   __FUNCTION__, dongle_types[dongle_id]); 
 		break;
 	case 0x06: /* Single-ended serial interface */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s not defined by irda yet\n",
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s not defined by irda yet\n",
+			   __FUNCTION__, dongle_types[dongle_id]); 
 		break;
 	case 0x07: /* Consumer-IR only */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s is not for IrDA mode\n",
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s is not for IrDA mode\n",
+			   __FUNCTION__, dongle_types[dongle_id]); 
 		break;
 	case 0x08: /* HP HSDL-2300, HP HSDL-3600/HSDL-3610 */
-		IRDA_DEBUG(0, __FUNCTION__ "(), %s\n", 
-			   dongle_types[dongle_id]); 
+		IRDA_DEBUG(0, "%s(), %s\n", 
+			   __FUNCTION__, dongle_types[dongle_id]); 
 		outb(0x00, iobase+4);
 		if (speed > 115200)
 			outb(0x01, iobase+4);
@@ -916,11 +912,10 @@
 		outb(0x01, iobase+4);
 
 		if (speed == 4000000) {
-			save_flags(flags);
-			cli();
+			/* There was a cli() there, but we now are already
+			 * under spin_lock_irqsave() - JeanII */
 			outb(0x81, iobase+4);
 			outb(0x80, iobase+4);
-			restore_flags(flags);
 		} else
 			outb(0x00, iobase+4);
 		break;
@@ -1538,8 +1533,8 @@
 
 			skb = dev_alloc_skb(len+1);
 			if (skb == NULL)  {
-				WARNING(__FUNCTION__ "(), memory squeeze, "
-					"dropping frame.\n");
+				WARNING("%s(), memory squeeze, "
+					"dropping frame.\n", __FUNCTION__);
 				self->stats.rx_dropped++;
 
 				/* Restore bank register */
@@ -1960,33 +1955,30 @@
 
 	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
 	
-	/* Disable interrupts & save flags */
-	save_flags(flags);
-	cli();
-
 	switch (cmd) {
 	case SIOCSBANDWIDTH: /* Set bandwidth */
 		if (!capable(CAP_NET_ADMIN)) {
 			ret = -EPERM;
-			goto out;
+			break;
 		}
+		spin_lock_irqsave(&self->lock, flags);
 		nsc_ircc_change_speed(self, irq->ifr_baudrate);
+		spin_unlock_irqrestore(&self->lock, flags);
 		break;
 	case SIOCSMEDIABUSY: /* Set media busy */
 		if (!capable(CAP_NET_ADMIN)) {
 			ret = -EPERM;
-			goto out;
+			break;
 		}
 		irda_device_set_media_busy(self->netdev, TRUE);
 		break;
 	case SIOCGRECEIVING: /* Check if we are receiving right now */
+		/* This is already protected */
 		irq->ifr_receiving = nsc_ircc_is_receiving(self);
 		break;
 	default:
 		ret = -EOPNOTSUPP;
 	}
-out:
-	restore_flags(flags);
 	return ret;
 }
 
diff -Nru a/drivers/net/irda/smc-ircc.c b/drivers/net/irda/smc-ircc.c
--- a/drivers/net/irda/smc-ircc.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/net/irda/smc-ircc.c	Fri Sep 20 08:20:41 2002
@@ -431,6 +431,7 @@
 	struct ircc_cb *self;
         struct irport_cb *irport;
 	unsigned char low, high, chip, config, dma, irq, version;
+	unsigned long flags;
 
 
 	IRDA_DEBUG(0, __FUNCTION__ "\n");
@@ -484,7 +485,6 @@
 		return -ENOMEM;
 	}
 	memset(self, 0, sizeof(struct ircc_cb));
-	spin_lock_init(&self->lock);
 
 	/* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
 	self->rx_buff.truesize = 4000; 
@@ -555,6 +555,9 @@
 
 	request_region(self->io->fir_base, CHIP_IO_EXTENT, driver_name);
 
+	/* Don't allow irport to change under us - Jean II */
+	spin_lock_irqsave(&self->irport->lock, flags);
+
 	/* Initialize QoS for this device */
 	irda_init_max_qos_capabilies(&irport->qos);
 	
@@ -581,6 +584,7 @@
 	self->netdev->stop   = &ircc_net_close;
 
 	irport_start(self->irport);
+	spin_unlock_irqrestore(&self->irport->lock, flags);
 
         self->pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, ircc_pmproc);
         if (self->pmdev)
@@ -598,6 +602,7 @@
  *
  *    Change the speed of the device
  *
+ * This function should be called with irq off and spin-lock.
  */
 static void ircc_change_speed(void *priv, u32 speed)
 {
@@ -658,6 +663,7 @@
 
 	/* Make special FIR init if necessary */
 	if (speed > 115200) {
+		/* No need to lock, already locked - Jean II */
 		irport_stop(self->irport);
 
 		/* Install FIR transmit handler */
@@ -674,6 +680,7 @@
 	} else {
 		/* Install SIR transmit handler */
 		dev->hard_start_xmit = &irport_hard_xmit;
+		/* No need to lock, already locked - Jean II */
 		irport_start(self->irport);
 		
 	        IRDA_DEBUG(0, __FUNCTION__ 
@@ -727,20 +734,26 @@
 
 	netif_stop_queue(dev);
 
+	/* Make sure tests *& speed change are atomic */
+	spin_lock_irqsave(&self->irport->lock, flags);
+
+	/* Note : you should make sure that speed changes are not going
+	 * to corrupt any outgoing frame. Look at nsc-ircc for the gory
+	 * details - Jean II */
+
 	/* Check if we need to change the speed after this frame */
 	speed = irda_get_next_speed(skb);
 	if ((speed != self->io->speed) && (speed != -1)) {
 		/* Check for empty frame */
 		if (!skb->len) {
 			ircc_change_speed(self, speed); 
+			spin_unlock_irqrestore(&self->irport->lock, flags);
 			dev_kfree_skb(skb);
 			return 0;
 		} else
 			self->new_speed = speed;
 	}
 	
-	spin_lock_irqsave(&self->lock, flags);
-
 	memcpy(self->tx_buff.head, skb->data, skb->len);
 
 	self->tx_buff.len = skb->len;
@@ -763,7 +776,7 @@
 		/* Transmit frame */
 		ircc_dma_xmit(self, iobase, 0);
 	}
-	spin_unlock_irqrestore(&self->lock, flags);
+	spin_unlock_irqrestore(&self->irport->lock, flags);
 	dev_kfree_skb(skb);
 
 	return 0;
@@ -936,14 +949,14 @@
 		len -= 4;
 
 	if ((len < 2) || (len > 2050)) {
-		WARNING(__FUNCTION__ "(), bogus len=%d\n", len);
+		WARNING("%s(), bogus len=%d\n", __FUNCTION__, len);
 		return;
 	}
 	IRDA_DEBUG(2, __FUNCTION__ ": msgcnt = %d, len=%d\n", msgcnt, len);
 
 	skb = dev_alloc_skb(len+1);
 	if (!skb)  {
-		WARNING(__FUNCTION__ "(), memory squeeze, dropping frame.\n");
+		WARNING("%s(), memory squeeze, dropping frame.\n", __FUNCTION__);
 		return;
 	}			
 	/* Make sure IP header gets aligned */
@@ -985,12 +998,13 @@
 
 	/* Check if we should use the SIR interrupt handler */
 	if (self->io->speed < 576000) {
+		/* Will spinlock itself - Jean II */
 		irport_interrupt(irq, dev_id, regs);
 		return;
 	}
 	iobase = self->io->fir_base;
 
-	spin_lock(&self->lock);	
+	spin_lock(&self->irport->lock);	
 
 	register_bank(iobase, 0);
 	iir = inb(iobase+IRCC_IIR);
@@ -1013,7 +1027,7 @@
 	register_bank(iobase, 0);
 	outb(IRCC_IER_ACTIVE_FRAME|IRCC_IER_EOM, iobase+IRCC_IER);
 
-	spin_unlock(&self->lock);
+	spin_unlock(&self->irport->lock);
 }
 
 #if 0 /* unused */
@@ -1072,7 +1086,7 @@
 	if (request_dma(self->io->dma, dev->name)) {
 		irport_net_close(dev);
 
-		WARNING(__FUNCTION__ "(), unable to allocate DMA=%d\n", self->io->dma);
+		WARNING("%s(), unable to allocate DMA=%d\n", __FUNCTION__, self->io->dma);
 		return -EAGAIN;
 	}
 	
@@ -1093,7 +1107,7 @@
 	struct ircc_cb *self;
 	int iobase;
 
-	IRDA_DEBUG(0, __FUNCTION__ "\n");
+	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
 	
 	ASSERT(dev != NULL, return -1;);
 	irport = (struct irport_cb *) dev->priv;
@@ -1128,17 +1142,15 @@
 
 static void ircc_wakeup(struct ircc_cb *self)
 {
-	unsigned long flags;
-
 	if (!self->io->suspended)
 		return;
 
-	save_flags(flags);
-	cli();
+	/* The code was doing a "cli()" here, but this can't be right.
+	 * If you need protection, do it in net_open with a spinlock
+	 * or give a good reason. - Jean II */
 
 	ircc_net_open(self->netdev);
 	
-	restore_flags(flags);
 	MESSAGE("%s, Waking up\n", driver_name);
 }
 
@@ -1174,6 +1186,7 @@
 
         iobase = self->irport->io.fir_base;
 
+	/* This will destroy irport */
 	irport_close(self->irport);
 
 	/* Stop interrupts */
@@ -1187,6 +1200,7 @@
         outb(IRCC_CFGA_IRDA_SIR_A|IRCC_CFGA_TX_POLARITY, iobase+IRCC_SCE_CFGA);
         outb(IRCC_CFGB_IR, iobase+IRCC_SCE_CFGB);
 #endif
+
 	/* Release the PORT that this driver is using */
 	IRDA_DEBUG(0, __FUNCTION__ "(), releasing 0x%03x\n", iobase);
 
@@ -1203,7 +1217,7 @@
 	return 0;
 }
 
-int __init smc_init(void)
+static int __init smc_init(void)
 {
 	return ircc_init();
 }
diff -Nru a/drivers/net/irda/tekram.c b/drivers/net/irda/tekram.c
--- a/drivers/net/irda/tekram.c	Fri Sep 20 08:20:46 2002
+++ b/drivers/net/irda/tekram.c	Fri Sep 20 08:20:46 2002
@@ -161,7 +161,7 @@
 			irda_task_next_state(task, IRDA_TASK_CHILD_DONE);
 		break;
 	case IRDA_TASK_CHILD_WAIT:
-		WARNING(__FUNCTION__ "(), resetting dongle timed out!\n");
+		WARNING("%s(), resetting dongle timed out!\n", __FUNCTION__);
 		ret = -1;
 		break;
 	case IRDA_TASK_CHILD_DONE:
@@ -187,7 +187,7 @@
 		self->speed_task = NULL;
 		break;
 	default:
-		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);
 		self->speed_task = NULL;
 		ret = -1;
@@ -255,7 +255,7 @@
 		self->reset_task = NULL;
 		break;
 	default:
-		ERROR(__FUNCTION__ "(), unknown state %d\n", task->state);
+		ERROR("%s(), unknown state %d\n", __FUNCTION__, task->state);
 		irda_task_next_state(task, IRDA_TASK_DONE);		
 		self->reset_task = NULL;
 		ret = -1;
diff -Nru a/drivers/net/irda/toshoboe.c b/drivers/net/irda/toshoboe.c
--- a/drivers/net/irda/toshoboe.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/net/irda/toshoboe.c	Fri Sep 20 08:20:41 2002
@@ -421,8 +421,8 @@
             }
           else
             {
-              printk (KERN_INFO __FUNCTION__
-                      "(), memory squeeze, dropping frame.\n");
+              printk (KERN_INFO
+                      "%s(), memory squeeze, dropping frame.\n", __FUNCTION__);
             }
 
           self->taskfile->recv[self->rxs].control = 0x83;
@@ -824,7 +824,7 @@
 
 
   if (!(dev = dev_alloc("irda%d", &err))) {
-      ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+      ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__);
       err = -ENOMEM;
       goto freebufs;
   }
@@ -843,7 +843,7 @@
   err = register_netdevice(dev);
   rtnl_unlock();
   if (err) {
-	  ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
+	  ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
 	  /* XXX there is not freeing for dev? */
           goto freebufs;
   }
diff -Nru a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c
--- a/drivers/net/irda/w83977af_ir.c	Fri Sep 20 08:20:44 2002
+++ b/drivers/net/irda/w83977af_ir.c	Fri Sep 20 08:20:44 2002
@@ -175,6 +175,7 @@
 		return -ENOMEM;
 	}
 	memset(self, 0, sizeof(struct w83977af_ir));
+	spin_lock_init(&self->lock);
    
 	/* Need to store self somewhere */
 	dev_self[i] = self;
@@ -236,7 +237,7 @@
 	self->rx_buff.data = self->rx_buff.head;
 	
 	if (!(dev = dev_alloc("irda%d", &err))) {
-		ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+		ERROR("%s(), dev_alloc() failed!\n", __FUNCTION__);
 		return -ENOMEM;
 	}
 	dev->priv = (void *) self;
@@ -254,7 +255,7 @@
 	err = register_netdevice(dev);
 	rtnl_unlock();
 	if (err) {
-		ERROR(__FUNCTION__ "(), register_netdevice() failed!\n");
+		ERROR("%s(), register_netdevice() failed!\n", __FUNCTION__);
 		return -1;
 	}
 	MESSAGE("IrDA: Registered device %s\n", dev->name);
@@ -603,8 +604,7 @@
 	switch_bank(iobase, SET2);
 	outb(ADCR1_D_CHSW|/*ADCR1_DMA_F|*/ADCR1_ADV_SL, iobase+ADCR1);
 #ifdef CONFIG_NETWINDER_TX_DMA_PROBLEMS
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&self->lock, flags);
 
 	disable_dma(self->io.dma);
 	clear_dma_ff(self->io.dma);
@@ -623,7 +623,7 @@
 	hcr = inb(iobase+HCR);
 	outb(hcr | HCR_EN_DMA, iobase+HCR);
 	enable_dma(self->io.dma);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&self->lock, flags);
 #else	
 	outb(inb(iobase+HCR) | HCR_EN_DMA | HCR_TX_WT, iobase+HCR);
 #endif
@@ -761,8 +761,7 @@
 	self->rx_buff.data = self->rx_buff.head;
 
 #ifdef CONFIG_NETWINDER_RX_DMA_PROBLEMS
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&self->lock, flags);
 
 	disable_dma(self->io.dma);
 	clear_dma_ff(self->io.dma);
@@ -788,7 +787,7 @@
 	hcr = inb(iobase+HCR);
 	outb(hcr | HCR_EN_DMA, iobase+HCR);
 	enable_dma(self->io.dma);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&self->lock, flags);
 #else	
 	outb(inb(iobase+HCR) | HCR_EN_DMA, iobase+HCR);
 #endif
@@ -892,8 +891,8 @@
 						
 			skb = dev_alloc_skb(len+1);
 			if (skb == NULL)  {
-				printk(KERN_INFO __FUNCTION__ 
-				       "(), memory squeeze, dropping frame.\n");
+				printk(KERN_INFO
+				       "%s(), memory squeeze, dropping frame.\n", __FUNCTION__);
 				/* Restore set register */
 				outb(set, iobase+SSR);
 
@@ -1334,10 +1333,8 @@
 
 	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
 	
-	/* Disable interrupts & save flags */
-	save_flags(flags);
-	cli();
-	
+	spin_lock_irqsave(&self->lock, flags);
+
 	switch (cmd) {
 	case SIOCSBANDWIDTH: /* Set bandwidth */
 		if (!capable(CAP_NET_ADMIN)) {
@@ -1360,7 +1357,7 @@
 		ret = -EOPNOTSUPP;
 	}
 out:
-	restore_flags(flags);
+	spin_unlock_irqrestore(&self->lock, flags);
 	return ret;
 }
 
diff -Nru a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c
--- a/drivers/net/lasi_82596.c	Fri Sep 20 08:20:42 2002
+++ b/drivers/net/lasi_82596.c	Fri Sep 20 08:20:42 2002
@@ -73,6 +73,7 @@
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
+#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
@@ -83,6 +84,7 @@
 #include <linux/skbuff.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/types.h>
 
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -94,8 +96,8 @@
 #include <asm/gsc.h>
 #include <asm/cache.h>
 
-static char version[] __initdata =
-	"82596.c $Revision: 1.20 $\n";
+static char version[] __devinitdata =
+	"82596.c $Revision: 1.29 $\n";
 
 /* DEBUG flags
  */
@@ -119,7 +121,7 @@
 #define DEB_ANY		0xffff
 
 
-#define DEB(x,y)	if (i596_debug & (x)) y
+#define DEB(x,y)	if (i596_debug & (x)) { y; }
 
 
 #define  CHECK_WBACK(addr,len) \
@@ -143,13 +145,13 @@
  */
 
 #ifdef __BIG_ENDIAN
-#define WSWAPrfd(x)  ((struct i596_rfd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPrbd(x)  ((struct i596_rbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPiscp(x) ((struct i596_iscp *)(((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPscb(x)  ((struct i596_scb *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPcmd(x)  ((struct i596_cmd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPtbd(x)  ((struct i596_tbd *) (((u32)(x)<<16) | ((((u32)(x)))>>16)))
-#define WSWAPchar(x) ((char *)            (((u32)(x)<<16) | ((((u32)(x)))>>16)))
+#define WSWAPrfd(x)  (((u32)(x)<<16) | ((((u32)(x)))>>16))
+#define WSWAPrbd(x)  (((u32)(x)<<16) | ((((u32)(x)))>>16))
+#define WSWAPiscp(x) (((u32)(x)<<16) | ((((u32)(x)))>>16))
+#define WSWAPscb(x)  (((u32)(x)<<16) | ((((u32)(x)))>>16))
+#define WSWAPcmd(x)  (((u32)(x)<<16) | ((((u32)(x)))>>16))
+#define WSWAPtbd(x)  (((u32)(x)<<16) | ((((u32)(x)))>>16))
+#define WSWAPchar(x) (((u32)(x)<<16) | ((((u32)(x)))>>16))
 #define ISCP_BUSY	0x00010000
 #define MACH_IS_APRICOT	0
 #else
@@ -182,18 +184,19 @@
 MODULE_LICENSE("GPL");
 MODULE_PARM(i596_debug, "i");
 MODULE_PARM_DESC(i596_debug, "lasi_82596 debug mask");
+EXPORT_NO_SYMBOLS;
 
 /* Copy frames shorter than rx_copybreak, otherwise pass on up in
  * a full sized sk_buff.  Value of 100 stolen from tulip.c (!alpha).
  */
 static int rx_copybreak = 100;
 
+#define MAX_DRIVERS	4	/* max count of drivers */
+
 #define PKT_BUF_SZ	1536
 #define MAX_MC_CNT	64
 
-#define I596_TOTAL_SIZE 17
-
-#define I596_NULL ((void *)0xffffffff)
+#define I596_NULL ((u32)0xffffffff)
 
 #define CMD_EOL		0x8000	/* The last command of the list, stop. */
 #define CMD_SUSP	0x4000	/* Suspend after doing cmd. */
@@ -228,7 +231,7 @@
 struct i596_reg {
 	unsigned short porthi;
 	unsigned short portlo;
-	unsigned long ca;
+	u32            ca;
 };
 
 #define EOF		0x8000
@@ -237,9 +240,9 @@
 struct i596_tbd {
 	unsigned short size;
 	unsigned short pad;
-	struct i596_tbd *next;
-	char *data;
-	long cache_pad[5];		/* Total 32 bytes... */
+	dma_addr_t     next;
+	dma_addr_t     data;
+	u32 cache_pad[5];		/* Total 32 bytes... */
 };
 
 /* The command structure has two 'next' pointers; v_next is the address of
@@ -256,17 +259,21 @@
 	struct i596_cmd *v_next;	/* Address from CPUs viewpoint */
 	unsigned short status;
 	unsigned short command;
-	struct i596_cmd *b_next;	/* Address from i596 viewpoint */
+	dma_addr_t     b_next;	/* Address from i596 viewpoint */
 };
 
 struct tx_cmd {
 	struct i596_cmd cmd;
-	struct i596_tbd *tbd;
+	dma_addr_t     tbd;
 	unsigned short size;
 	unsigned short pad;
 	struct sk_buff *skb;		/* So we can free it after tx */
 	dma_addr_t dma_addr;
-	long cache_pad[1];		/* Total 32 bytes... */
+#ifdef __LP64__
+	u32 cache_pad[6];		/* Total 64 bytes... */
+#else    
+	u32 cache_pad[1];		/* Total 32 bytes... */
+#endif    
 };
 
 struct tdr_cmd {
@@ -294,27 +301,34 @@
 struct i596_rfd {
 	unsigned short stat;
 	unsigned short cmd;
-	struct i596_rfd *b_next;	/* Address from i596 viewpoint */
-	struct i596_rbd *rbd;
+	dma_addr_t     b_next;	/* Address from i596 viewpoint */
+	dma_addr_t     rbd;
 	unsigned short count;
 	unsigned short size;
 	struct i596_rfd *v_next;	/* Address from CPUs viewpoint */
 	struct i596_rfd *v_prev;
-	long cache_pad[2];		/* Total 32 bytes... */
+#ifndef __LP64__    
+	u32 cache_pad[2];		/* Total 32 bytes... */
+#endif    
 };
 
 struct i596_rbd {
+    /* hardware data */
     unsigned short count;
     unsigned short zero1;
-    struct i596_rbd *b_next;
-    unsigned char *b_data;		/* Address from i596 viewpoint */
+    dma_addr_t     b_next;
+    dma_addr_t     b_data;		/* Address from i596 viewpoint */
     unsigned short size;
     unsigned short zero2;
+    /* driver data */
     struct sk_buff *skb;
     struct i596_rbd *v_next;
-    struct i596_rbd *b_addr;		/* This rbd addr from i596 view */
+    dma_addr_t     b_addr;		/* This rbd addr from i596 view */
     unsigned char *v_data;		/* Address from CPUs viewpoint */
 					/* Total 32 bytes... */
+#ifdef __LP64__
+    u32 cache_pad[4];
+#endif    
 };
 
 /* These values as chosen so struct i596_private fits in one page... */
@@ -325,27 +339,27 @@
 struct i596_scb {
 	unsigned short status;
 	unsigned short command;
-	struct i596_cmd *cmd;
-	struct i596_rfd *rfd;
-	unsigned long crc_err;
-	unsigned long align_err;
-	unsigned long resource_err;
-	unsigned long over_err;
-	unsigned long rcvdt_err;
-	unsigned long short_err;
+	dma_addr_t    cmd;
+	dma_addr_t    rfd;
+	u32           crc_err;
+	u32           align_err;
+	u32           resource_err;
+	u32           over_err;
+	u32           rcvdt_err;
+	u32           short_err;
 	unsigned short t_on;
 	unsigned short t_off;
 };
 
 struct i596_iscp {
-	unsigned long stat;
-	struct i596_scb *scb;
+	u32           stat;
+	dma_addr_t    scb;
 };
 
 struct i596_scp {
-	unsigned long sysbus;
-	unsigned long pad;
-	struct i596_iscp *iscp;
+	u32           sysbus;
+	u32            pad;
+	dma_addr_t    iscp;
 };
 
 struct i596_private {
@@ -360,14 +374,14 @@
 	struct i596_rbd rbds[RX_RING_SIZE]	__attribute__((aligned(32)));
 	struct tx_cmd tx_cmds[TX_RING_SIZE]	__attribute__((aligned(32)));
 	struct i596_tbd tbds[TX_RING_SIZE]	__attribute__((aligned(32)));
-	unsigned long stat;
+	u32    stat;
 	int last_restart;
 	struct i596_rfd *rfd_head;
 	struct i596_rbd *rbd_head;
 	struct i596_cmd *cmd_tail;
 	struct i596_cmd *cmd_head;
 	int cmd_backlog;
-	unsigned long last_cmd;
+	u32    last_cmd;
 	struct net_device_stats stats;
 	int next_tx_cmd;
 	int options;
@@ -392,6 +406,8 @@
 	0x00,
 	0x7f /*  *multi IA */ };
 
+static struct pci_dev *fake_pci_dev; /* The fake pci_dev needed for 
+					pci_* functions under ccio. */
 static int dma_consistent = 1;	/* Zero if pci_alloc_consistent() fails */
 
 static int i596_open(struct net_device *dev);
@@ -411,22 +427,28 @@
 
 static inline void CA(struct net_device *dev)
 {
-	gsc_writel(0, (void*)(dev->base_addr + PA_CHANNEL_ATTENTION));
+	gsc_writel(0, dev->base_addr + PA_CHANNEL_ATTENTION);
 }
 
 
-static inline void MPU_PORT(struct net_device *dev, int c, volatile void *x)
+static inline void MPU_PORT(struct net_device *dev, int c, dma_addr_t x)
 {
 	struct i596_private *lp = (struct i596_private *) dev->priv;
 
 	u32 v = (u32) (c) | (u32) (x);
+	u16 a, b;
 
-	if (lp->options & OPT_SWAP_PORT)
-		v = ((u32) (v) << 16) | ((u32) (v) >> 16);
+	if (lp->options & OPT_SWAP_PORT) {
+		a = v >> 16;
+		b = v & 0xffff;
+	} else {
+		a = v & 0xffff;
+		b = v >> 16;
+	}
 
-	gsc_writel(v & 0xffff, (void*)(dev->base_addr + PA_CPU_PORT_L_ACCESS));
+	gsc_writel(a, dev->base_addr + PA_CPU_PORT_L_ACCESS);
 	udelay(1);
-	gsc_writel(v >> 16,    (void*)(dev->base_addr + PA_CPU_PORT_L_ACCESS));
+	gsc_writel(b, dev->base_addr + PA_CPU_PORT_L_ACCESS);
 }
 
 
@@ -438,7 +460,7 @@
 		CHECK_INV(&(lp->iscp), sizeof(struct i596_iscp));
 	}
 	if (!delcnt) {
-		printk("%s: %s, iscp.stat %04lx, didn't clear\n",
+		printk("%s: %s, iscp.stat %04x, didn't clear\n",
 		     dev->name, str, lp->iscp.stat);
 		return -1;
 	}
@@ -471,28 +493,28 @@
 	struct i596_rfd *rfd;
 	struct i596_rbd *rbd;
 
-	printk("lp and scp at %p, .sysbus = %08lx, .iscp = %p\n",
+	printk("lp and scp at %p, .sysbus = %08x, .iscp = %08x\n",
 	       &lp->scp, lp->scp.sysbus, lp->scp.iscp);
-	printk("iscp at %p, iscp.stat = %08lx, .scb = %p\n",
+	printk("iscp at %p, iscp.stat = %08x, .scb = %08x\n",
 	       &lp->iscp, lp->iscp.stat, lp->iscp.scb);
 	printk("scb at %p, scb.status = %04x, .command = %04x,"
-		" .cmd = %p, .rfd = %p\n",
+		" .cmd = %08x, .rfd = %08x\n",
 	       &lp->scb, lp->scb.status, lp->scb.command,
 		lp->scb.cmd, lp->scb.rfd);
-	printk("   errors: crc %lx, align %lx, resource %lx,"
-               " over %lx, rcvdt %lx, short %lx\n",
+	printk("   errors: crc %x, align %x, resource %x,"
+               " over %x, rcvdt %x, short %x\n",
 		lp->scb.crc_err, lp->scb.align_err, lp->scb.resource_err,
 		lp->scb.over_err, lp->scb.rcvdt_err, lp->scb.short_err);
 	cmd = lp->cmd_head;
-	while (cmd != I596_NULL) {
-		printk("cmd at %p, .status = %04x, .command = %04x, .b_next = %p\n",
+	while (cmd != NULL) {
+		printk("cmd at %p, .status = %04x, .command = %04x, .b_next = %08x\n",
 		  cmd, cmd->status, cmd->command, cmd->b_next);
 		cmd = cmd->v_next;
 	}
 	rfd = lp->rfd_head;
 	printk("rfd_head = %p\n", rfd);
 	do {
-		printk ("   %p .stat %04x, .cmd %04x, b_next %p, rbd %p,"
+		printk ("   %p .stat %04x, .cmd %04x, b_next %08x, rbd %08x,"
                         " count %04x\n",
 			rfd, rfd->stat, rfd->cmd, rfd->b_next, rfd->rbd,
 			rfd->count);
@@ -501,7 +523,7 @@
 	rbd = lp->rbd_head;
 	printk("rbd_head = %p\n", rbd);
 	do {
-		printk("   %p .count %04x, b_next %p, b_data %p, size %04x\n",
+		printk("   %p .count %04x, b_next %08x, b_data %08x, size %04x\n",
 			rbd, rbd->count, rbd->b_next, rbd->b_data, rbd->size);
 		rbd = rbd->v_next;
 	} while (rbd != lp->rbd_head);
@@ -522,7 +544,7 @@
 }
 #endif
 
-#define virt_to_dma(lp,v) ((char *)(v)-(char *)(lp)+(char *)((lp)->dma_addr))
+#define virt_to_dma(lp,v) ((lp)->dma_addr + (dma_addr_t)((unsigned long)(v)-(unsigned long)(lp)))
 
 static inline void init_rx_bufs(struct net_device *dev)
 {
@@ -540,7 +562,7 @@
 		if (skb == NULL)
 			panic("82596: alloc_skb() failed");
 		skb_reserve(skb, 2);
-		dma_addr = pci_map_single(NULL, skb->tail,PKT_BUF_SZ,
+		dma_addr = pci_map_single(fake_pci_dev, skb->tail,PKT_BUF_SZ,
 					PCI_DMA_FROMDEVICE);
 		skb->dev = dev;
 		rbd->v_next = rbd+1;
@@ -568,7 +590,7 @@
 	lp->rfd_head = lp->rfds;
 	lp->scb.rfd = WSWAPrfd(virt_to_dma(lp,lp->rfds));
 	rfd = lp->rfds;
-	rfd->rbd = lp->rbd_head;
+	rfd->rbd = WSWAPrbd(virt_to_dma(lp,lp->rbd_head));
 	rfd->v_prev = lp->rfds + rx_ring_size - 1;
 	rfd = lp->rfds + rx_ring_size - 1;
 	rfd->v_next = lp->rfds;
@@ -587,7 +609,9 @@
 	for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
 		if (rbd->skb == NULL)
 			break;
-		pci_unmap_single(NULL,(dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+		pci_unmap_single(fake_pci_dev,
+				 (dma_addr_t)WSWAPchar(rbd->b_data), 
+				 PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
 		dev_kfree_skb(rbd->skb);
 	}
 }
@@ -639,14 +663,15 @@
 	lp->iscp.stat = ISCP_BUSY;
 	lp->cmd_backlog = 0;
 
-	lp->cmd_head = lp->scb.cmd = I596_NULL;
+	lp->cmd_head = NULL;
+        lp->scb.cmd = I596_NULL;
 
 	DEB(DEB_INIT,printk("%s: starting i82596.\n", dev->name));
 
 	CHECK_WBACK(&(lp->scp), sizeof(struct i596_scp));
 	CHECK_WBACK(&(lp->iscp), sizeof(struct i596_iscp));
 
-	MPU_PORT(dev, PORT_ALTSCP, (void *)virt_to_dma(lp,&lp->scp));	
+	MPU_PORT(dev, PORT_ALTSCP, virt_to_dma(lp,&lp->scp));	
 
 	CA(dev);
 
@@ -723,7 +748,7 @@
 	CHECK_INV(rfd, sizeof(struct i596_rfd));
 	while ((rfd->stat) & STAT_C) {	/* Loop while complete frames */
 		if (rfd->rbd == I596_NULL)
-			rbd = I596_NULL;
+			rbd = NULL;
 		else if (rfd->rbd == lp->rbd_head->b_addr) {
 			rbd = lp->rbd_head;
 			CHECK_INV(rbd, sizeof(struct i596_rbd));
@@ -731,12 +756,12 @@
 		else {
 			printk("%s: rbd chain broken!\n", dev->name);
 			/* XXX Now what? */
-			rbd = I596_NULL;
+			rbd = NULL;
 		}
-		DEB(DEB_RXFRAME, printk("  rfd %p, rfd.rbd %p, rfd.stat %04x\n",
+		DEB(DEB_RXFRAME, printk("  rfd %p, rfd.rbd %08x, rfd.stat %04x\n",
 			rfd, rfd->rbd, rfd->stat));
 		
-		if (rbd != I596_NULL && ((rfd->stat) & STAT_OK)) {
+		if (rbd != NULL && ((rfd->stat) & STAT_OK)) {
 			/* a good frame */
 			int pkt_len = rbd->count & 0x3fff;
 			struct sk_buff *skb = rbd->skb;
@@ -753,7 +778,7 @@
 				struct sk_buff *newskb;
 				dma_addr_t dma_addr;
 
-				pci_unmap_single(NULL,(dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+				pci_unmap_single(fake_pci_dev,(dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
 				/* Get fresh skbuff to replace filled one. */
 				newskb = dev_alloc_skb(PKT_BUF_SZ + 4);
 				if (newskb == NULL) {
@@ -767,7 +792,7 @@
 				rx_in_place = 1;
 				rbd->skb = newskb;
 				newskb->dev = dev;
-				dma_addr = pci_map_single(NULL, newskb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+				dma_addr = pci_map_single(fake_pci_dev, newskb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
 				rbd->v_data = newskb->tail;
 				rbd->b_data = WSWAPchar(dma_addr);
 				CHECK_WBACK_INV(rbd, sizeof(struct i596_rbd));
@@ -784,7 +809,7 @@
 				skb->dev = dev;
 				if (!rx_in_place) {
 					/* 16 byte align the data fields */
-					pci_dma_sync_single(NULL, (dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
+					pci_dma_sync_single(fake_pci_dev, (dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
 					skb_reserve(skb, 2);
 					memcpy(skb_put(skb,pkt_len), rbd->v_data, pkt_len);
 				}
@@ -818,7 +843,7 @@
 
 		/* Clear the buffer descriptor count and EOF + F flags */
 
-		if (rbd != I596_NULL && (rbd->count & 0x4000)) {
+		if (rbd != NULL && (rbd->count & 0x4000)) {
 			rbd->count = 0;
 			lp->rbd_head = rbd->v_next;
 			CHECK_WBACK_INV(rbd, sizeof(struct i596_rbd));
@@ -855,7 +880,7 @@
 {
 	struct i596_cmd *ptr;
 
-	while (lp->cmd_head != I596_NULL) {
+	while (lp->cmd_head != NULL) {
 		ptr = lp->cmd_head;
 		lp->cmd_head = ptr->v_next;
 		lp->cmd_backlog--;
@@ -865,19 +890,21 @@
 			{
 				struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;
 				struct sk_buff *skb = tx_cmd->skb;
-				pci_unmap_single(NULL, tx_cmd->dma_addr, skb->len, PCI_DMA_TODEVICE);
+				pci_unmap_single(fake_pci_dev, tx_cmd->dma_addr, skb->len, PCI_DMA_TODEVICE);
 
 				dev_kfree_skb(skb);
 
 				lp->stats.tx_errors++;
 				lp->stats.tx_aborted_errors++;
 
-				ptr->v_next = ptr->b_next = I596_NULL;
+				ptr->v_next = NULL;
+				ptr->b_next = I596_NULL;
 				tx_cmd->cmd.command = 0;  /* Mark as free */
 				break;
 			}
 		default:
-			ptr->v_next = ptr->b_next = I596_NULL;
+			ptr->v_next = NULL;
+			ptr->b_next = I596_NULL;
 		}
 		CHECK_WBACK_INV(ptr, sizeof(struct i596_cmd));
 	}
@@ -888,7 +915,7 @@
 }
 
 
-static inline void i596_reset(struct net_device *dev, struct i596_private *lp, int ioaddr)
+static inline void i596_reset(struct net_device *dev, struct i596_private *lp)
 {
 	unsigned long flags;
 
@@ -920,19 +947,19 @@
 static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd)
 {
 	struct i596_private *lp = (struct i596_private *) dev->priv;
-	int ioaddr = dev->base_addr;
 	unsigned long flags;
 
 	DEB(DEB_ADDCMD,printk("i596_add_cmd cmd_head %p\n", lp->cmd_head));
 
 	cmd->status = 0;
 	cmd->command |= (CMD_EOL | CMD_INTR);
-	cmd->v_next = cmd->b_next = I596_NULL;
+	cmd->v_next = NULL;
+	cmd->b_next = I596_NULL;
 	CHECK_WBACK(cmd, sizeof(struct i596_cmd));
 
 	spin_lock_irqsave (&lp->lock, flags);
 
-	if (lp->cmd_head != I596_NULL) {
+	if (lp->cmd_head != NULL) {
 		lp->cmd_tail->v_next = cmd;
 		lp->cmd_tail->b_next = WSWAPcmd(virt_to_dma(lp,&cmd->status));
 		CHECK_WBACK(lp->cmd_tail, sizeof(struct i596_cmd));
@@ -957,7 +984,7 @@
 
 		printk("%s: command unit timed out, status resetting.\n", dev->name);
 #if 1
-		i596_reset(dev, lp, ioaddr);
+		i596_reset(dev, lp);
 #endif
 	}
 }
@@ -1010,8 +1037,6 @@
 		goto out_remove_rx_bufs;
 	}
 
-	request_mem_region(dev->base_addr, I596_TOTAL_SIZE, "i82596");
-
 	netif_start_queue(dev);
 
 	return 0;
@@ -1028,7 +1053,6 @@
 static void i596_tx_timeout (struct net_device *dev)
 {
 	struct i596_private *lp = (struct i596_private *) dev->priv;
-	int ioaddr = dev->base_addr;
 
 	/* Transmitter timeout, serious problems. */
 	DEB(DEB_ERRORS,printk("%s: transmit timed out, status resetting.\n",
@@ -1040,7 +1064,7 @@
 	if (lp->last_restart == lp->stats.tx_packets) {
 		DEB(DEB_ERRORS,printk ("Resetting board.\n"));
 		/* Shutdown and restart */
-		i596_reset (dev, lp, ioaddr);
+		i596_reset (dev, lp);
 	} else {
 		/* Issue a channel attention signal */
 		DEB(DEB_ERRORS,printk ("Kicking board.\n"));
@@ -1063,8 +1087,8 @@
 	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
 	dev->trans_start = jiffies;
 
-	DEB(DEB_STARTTX,printk("%s: i596_start_xmit(%x,%x) called\n", dev->name,
-				skb->len, (unsigned int)skb->data));
+	DEB(DEB_STARTTX,printk("%s: i596_start_xmit(%x,%p) called\n", dev->name,
+				skb->len, skb->data));
 
 	netif_stop_queue(dev);
 
@@ -1091,7 +1115,7 @@
 		tbd->pad = 0;
 		tbd->size = EOF | length;
 
-		tx_cmd->dma_addr = pci_map_single(NULL, skb->data, skb->len, 
+		tx_cmd->dma_addr = pci_map_single(fake_pci_dev, skb->data, skb->len, 
 				PCI_DMA_TODEVICE);
 		tbd->data = WSWAPchar(tx_cmd->dma_addr);
 
@@ -1125,7 +1149,7 @@
 
 #define LAN_PROM_ADDR	0xF0810000
 
-static int __init i82596_probe(struct net_device *dev, int options)
+static int __devinit i82596_probe(struct net_device *dev)
 {
 	int i;
 	struct i596_private *lp;
@@ -1138,12 +1162,12 @@
 			    sizeof(struct i596_rfd));
 	    return -ENODEV;
 	}
-	if (sizeof(struct i596_rbd) != 32) {
+	if ((sizeof(struct i596_rbd) % 32) != 0) {
 	    printk("82596: sizeof(struct i596_rbd) = %d\n",
 			    sizeof(struct i596_rbd));
 	    return -ENODEV;
 	}
-	if (sizeof(struct tx_cmd) != 32) {
+	if ((sizeof(struct tx_cmd) % 32) != 0) {
 	    printk("82596: sizeof(struct tx_cmd) = %d\n",
 			    sizeof(struct tx_cmd));
 	    return -ENODEV;
@@ -1153,27 +1177,25 @@
 			    sizeof(struct i596_tbd));
 	    return -ENODEV;
 	}
+#ifndef __LP64__
 	if (sizeof(struct i596_private) > 4096) {
 	    printk("82596: sizeof(struct i596_private) = %d\n",
 			    sizeof(struct i596_private));
 	    return -ENODEV;
 	}
-
-	/* FIXME:
-	    Currently this works only, if set-up from lasi.c.
-	    This should be changed to use probing too !
-	*/
+#endif
 
 	if (!dev->base_addr || !dev->irq)
-	    return -ENODEV;
+		return -ENODEV;
 
-	if (pdc_lan_station_id( (char*)&eth_addr, (void*)dev->base_addr)) {
-	    for(i=0;i<6;i++)
-		eth_addr[i] = gsc_readb(LAN_PROM_ADDR+i);
-	    printk("82596.c: MAC of HP700 LAN blindely read from the prom!\n");
+	if (pdc_lan_station_id(eth_addr, dev->base_addr)) {
+		for (i=0; i < 6; i++) {
+			eth_addr[i] = gsc_readb(LAN_PROM_ADDR + i);
+		}
+		printk("82596.c: MAC of HP700 LAN read from EEPROM\n");
 	}
 
-	dev->mem_start = (int)pci_alloc_consistent( NULL, 
+	dev->mem_start = (unsigned long) pci_alloc_consistent(fake_pci_dev, 
 		sizeof(struct i596_private), &dma_addr);
 	if (!dev->mem_start) {
 		printk("%s: Couldn't get consistent shared memory\n", dev->name);
@@ -1183,7 +1205,7 @@
 			printk("%s: Couldn't get shared memory\n", dev->name);
 			return -ENOMEM;
 		}
-		dma_addr = virt_to_phys(dev->mem_start);
+		dma_addr = virt_to_bus(dev->mem_start);
 	}
 
 	ether_setup(dev);
@@ -1209,11 +1231,10 @@
 
 	lp = (struct i596_private *) dev->priv;
 	DEB(DEB_INIT,printk ("%s: lp at 0x%08lx (%d bytes), lp->scb at 0x%08lx\n",
-			dev->name, (unsigned long)lp,
-			sizeof(struct i596_private), (unsigned long)&lp->scb));
-	memset((void *) lp, 0, sizeof(struct i596_private));
+		dev->name, (unsigned long)lp,
+		sizeof(struct i596_private), (unsigned long)&lp->scb));
+	memset(lp, 0, sizeof(struct i596_private));
 
-	lp->options = options;
 	lp->scb.command = 0;
 	lp->scb.cmd = I596_NULL;
 	lp->scb.rfd = I596_NULL;
@@ -1226,18 +1247,6 @@
 }
 
 
-int __init lasi_i82596_probe(struct net_device *dev)
-{
-	return i82596_probe(dev, 0);
-}
-
-
-int __init asp_i82596_probe(struct net_device *dev)
-{
-	return i82596_probe(dev, OPT_SWAP_PORT);
-}
-
-
 static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = dev_id;
@@ -1275,7 +1284,7 @@
 		if ((status & 0x2000))
 			DEB(DEB_INTS,printk("%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700));
 
-		while (lp->cmd_head != I596_NULL) {
+		while (lp->cmd_head != NULL) {
 			CHECK_INV(lp->cmd_head, sizeof(struct i596_cmd));
 			if (!(lp->cmd_head->status & STAT_C))
 				break;
@@ -1308,7 +1317,7 @@
 					if ((ptr->status) & 0x1000)
 						lp->stats.tx_aborted_errors++;
 				}
-				pci_unmap_single(NULL, tx_cmd->dma_addr, skb->len, PCI_DMA_TODEVICE);
+				pci_unmap_single(fake_pci_dev, tx_cmd->dma_addr, skb->len, PCI_DMA_TODEVICE);
 				dev_kfree_skb_irq(skb);
 
 				tx_cmd->cmd.command = 0; /* Mark free */
@@ -1337,7 +1346,8 @@
 				ptr->command = 0;
 				break;
 			}
-			ptr->v_next = ptr->b_next = I596_NULL;
+			ptr->v_next = NULL;
+		        ptr->b_next = I596_NULL;
 			CHECK_WBACK(ptr, sizeof(struct i596_cmd));
 			lp->last_cmd = jiffies;
 		}
@@ -1347,7 +1357,7 @@
 		 * only add to the cmd queue when the CU is stopped.
 		 */
 		ptr = lp->cmd_head;
-		while ((ptr != I596_NULL) && (ptr != lp->cmd_tail)) {
+		while ((ptr != NULL) && (ptr != lp->cmd_tail)) {
 			struct i596_cmd *prev = ptr;
 
 			ptr->command &= 0x1fff;
@@ -1355,7 +1365,7 @@
 			CHECK_WBACK_INV(prev, sizeof(struct i596_cmd));
 		}
 
-		if ((lp->cmd_head != I596_NULL))
+		if ((lp->cmd_head != NULL))
 			ack_cmd |= CUC_START;
 		lp->scb.cmd = WSWAPcmd(virt_to_dma(lp,&lp->cmd_head->status));
 		CHECK_WBACK_INV(&lp->scb, sizeof(struct i596_scb));
@@ -1421,8 +1431,6 @@
 	free_irq(dev->irq, dev);
 	remove_rx_bufs(dev);
 
-	release_mem_region(dev->base_addr, I596_TOTAL_SIZE);
-
 	MOD_DEC_USE_COUNT;
 
 	return 0;
@@ -1502,48 +1510,106 @@
 	}
 }
 
-#ifdef HAVE_DEVLIST
-static unsigned int i596_portlist[] __initdata =
-{0x300, 0};
-struct netdev_entry i596_drv =
-{"lasi_i82596", lasi_i82596_probe, I596_TOTAL_SIZE, i596_portlist};
-#endif
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "lasi_82596 debug mask");
+static int debug = -1;
+
+static int num_drivers;
+static struct net_device *netdevs[MAX_DRIVERS];
 
-#ifdef MODULE
-static char devicename[9] =
-{0,};
-static struct net_device dev_82596 =
+static int __devinit
+lan_init_chip(struct parisc_device *dev)
 {
-	.name = devicename,	/* device name inserted by drivers/net/net_init.c */
-	.init = lasi_i82596_probe,
+	struct	net_device *netdevice;
+	int	retval;
+
+	if (num_drivers >= MAX_DRIVERS) {
+		/* max count of possible i82596 drivers reached */
+		return -ENODEV;
+	}
+	
+	fake_pci_dev = ccio_get_fake(dev);
+
+	if (!dev->irq) {
+		printk(KERN_ERR __FILE__ ": IRQ not found for i82596 at 0x%lx\n", dev->hpa);
+		return -ENODEV;
+	}
+
+	printk(KERN_INFO "Found i82596 at 0x%lx, IRQ %d\n", dev->hpa, dev->irq);
+
+	netdevice = alloc_etherdev(0);
+	if (!netdevice)
+		return -ENOMEM;
+
+	netdevice->base_addr = dev->hpa;
+	netdevice->irq = dev->irq;
+	netdevice->init = i82596_probe;
+
+	retval = register_netdev(netdevice);
+	if (retval) {
+		printk(KERN_WARNING __FILE__ ": register_netdevice ret'd %d\n", retval);
+		kfree(netdevice);
+		return -ENODEV;
+	};
+	if (dev->id.sversion == 0x72) {
+		((struct i596_private *)netdevice->priv)->options = OPT_SWAP_PORT;
+	}
+
+	netdevs[num_drivers++] = netdevice;
+
+	return retval;
+}
+
+
+static struct parisc_device_id lan_tbl[] = {
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008a },
+	{ HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00072 },
+	{ 0, }
 };
 
+MODULE_DEVICE_TABLE(parisc, lan_tbl);
 
-MODULE_PARM(debug, "i");
-MODULE_PARM_DESC(debug, "lasi_82596 debug mask");
-static int debug = -1;
+static struct parisc_driver lan_driver = {
+	name:		"Apricot",
+	id_table:	lan_tbl,
+	probe:		lan_init_chip,
+};
 
-int init_module(void)
+static int __devinit lasi_82596_init(void)
 {
 	if (debug >= 0)
 		i596_debug = debug;
-	if (register_netdev(&dev_82596) != 0)
-		return -EIO;
-	return 0;
+	return register_parisc_driver(&lan_driver);
 }
 
-void cleanup_module(void)
+module_init(lasi_82596_init);
+
+static void __exit lasi_82596_exit(void)
 {
-	unregister_netdev(&dev_82596);
-	lp = (struct i596_private *) dev_82596.priv;
+	int i;
 
-	if (dma_consistent)
-		pci_free_consistent( NULL, sizeof( struct i596_private), 
-			dev_82596.mem_start, lp->dma_addr);
-	else
-		free_page ((u32)(dev_82596.mem_start));
+	for (i=0; i<MAX_DRIVERS; i++) {
+		struct i596_private *lp;
+		struct net_device *netdevice;
+		
+		netdevice = netdevs[i];
+		if (!netdevice) 
+			continue;
+		
+		unregister_netdev(netdevice);
+
+		lp = (struct i596_private *) netdevice->priv;
+		if (dma_consistent)
+			pci_free_consistent(fake_pci_dev, 
+					    sizeof(struct i596_private), 
+				(void *)netdevice->mem_start, lp->dma_addr);
+		else
+			free_page(netdevice->mem_start);
+
+		netdevice->priv = NULL;
+	}
 
-	dev_82596.priv = NULL;
+	unregister_parisc_driver(&lan_driver);
 }
 
-#endif				/* MODULE */
+module_exit(lasi_82596_exit);
diff -Nru a/drivers/net/natsemi.c b/drivers/net/natsemi.c
--- a/drivers/net/natsemi.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/net/natsemi.c	Fri Sep 20 08:20:41 2002
@@ -100,20 +100,65 @@
 		* ETHTOOL_* further support (Tim Hockin)
 
 	version 1.0.13:
-		* ETHTOOL_[GS]EEPROM support (Tim Hockin)
+		* ETHTOOL_[G]EEPROM support (Tim Hockin)
 
 	version 1.0.13:
 		* crc cleanup (Matt Domsch <Matt_Domsch@dell.com>)
 
+	version 1.0.14:
+		* Cleanup some messages and autoneg in ethtool (Tim Hockin)
+
+	version 1.0.15:
+		* Get rid of cable_magic flag
+		* use new (National provided) solution for cable magic issue
+
+	version 1.0.16:
+		* call netdev_rx() for RxErrors (Manfred Spraul)
+		* formatting and cleanups
+		* change options and full_duplex arrays to be zero
+		  initialized
+		* enable only the WoL and PHY interrupts in wol mode
+
 	TODO:
 	* big endian support with CFG:BEM instead of cpu_to_le32
 	* support for an external PHY
 	* flow control
 */
 
+#if !defined(__OPTIMIZE__)
+#warning  You must compile this file with the correct options!
+#warning  See the last lines of the source file.
+#error You must compile this driver with "-O".
+#endif
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include <linux/rtnetlink.h>
+#include <linux/mii.h>
+#include <asm/processor.h>	/* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
 #define DRV_NAME	"natsemi"
-#define DRV_VERSION	"1.07+LK1.0.13"
-#define DRV_RELDATE	"Nov 12, 2001"
+#define DRV_VERSION	"1.07+LK1.0.16"
+#define DRV_RELDATE	"Aug 28, 2002"
 
 /* Updated to recommendations in pci-skeleton v2.03. */
 
@@ -132,7 +177,12 @@
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
 
-static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
+#define NATSEMI_DEF_MSG		(NETIF_MSG_DRV		| \
+				 NETIF_MSG_LINK		| \
+				 NETIF_MSG_WOL		| \
+				 NETIF_MSG_RX_ERR	| \
+				 NETIF_MSG_TX_ERR)
+static int debug = NATSEMI_DEF_MSG;
 
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
 static int max_interrupt_work = 20;
@@ -152,8 +202,8 @@
    The media type is usually passed in 'options[]'.
 */
 #define MAX_UNITS 8		/* More are supported, limit only on options */
-static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int options[MAX_UNITS];
+static int full_duplex[MAX_UNITS];
 
 /* Operational parameters that are set at compile time. */
 
@@ -164,7 +214,7 @@
    There are no ill effects from too-large receive rings. */
 #define TX_RING_SIZE	16
 #define TX_QUEUE_LEN	10 /* Limit ring entries actually used, min 4. */
-#define RX_RING_SIZE	64
+#define RX_RING_SIZE	32
 
 /* Operational parameters that usually are not changed. */
 /* Time in jiffies before concluding the transmitter is hung. */
@@ -183,37 +233,6 @@
 
 #define PKT_BUF_SZ		1536 /* Size of each temporary Rx buffer. */
 
-#if !defined(__OPTIMIZE__)
-#warning  You must compile this file with the correct options!
-#warning  See the last lines of the source file.
-#error You must compile this driver with "-O".
-#endif
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/ethtool.h>
-#include <linux/delay.h>
-#include <linux/rtnetlink.h>
-#include <linux/mii.h>
-#include <asm/processor.h>	/* Processor type for cache alignment. */
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-
 /* These identify the driver base version and may not be removed. */
 static char version[] __devinitdata =
 KERN_INFO DRV_NAME ".c:v1.07 1/9/2001  Written by Donald Becker <becker@scyld.com>\n"
@@ -232,7 +251,7 @@
 MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
 MODULE_PARM_DESC(max_interrupt_work, "DP8381x maximum events handled per interrupt");
 MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)");
-MODULE_PARM_DESC(debug, "DP8381x debug level (0-5)");
+MODULE_PARM_DESC(debug, "DP8381x default debug bitmask");
 MODULE_PARM_DESC(rx_copybreak, "DP8381x copy breakpoint for copy-only-tiny-frames");
 MODULE_PARM_DESC(options, "DP8381x: Bits 0-3: media type, bit 17: full duplex");
 MODULE_PARM_DESC(full_duplex, "DP8381x full duplex setting(s) (1)");
@@ -394,14 +413,12 @@
 	SDCFG			= 0xF8
 };
 /* the values for the 'magic' registers above (PGSEL=1) */
-#ifdef CONFIG_NATSEMI_CABLE_MAGIC
-#define PMDCSR_VAL	0x1898
-#else
-#define PMDCSR_VAL	0x189C
-#endif
+#define PMDCSR_VAL	0x189c	/* enable preferred adaptation circuitry */
 #define TSTDAT_VAL	0x0
 #define DSPCFG_VAL	0x5040
-#define SDCFG_VAL	0x008c
+#define SDCFG_VAL	0x008c	/* set voltage thresholds for Signal Detect */
+#define DSPCFG_LOCK	0x20	/* coefficient lock bit in DSPCFG */
+#define TSTDAT_FIXED	0xe8	/* magic number for bad coefficients */
 
 /* misc PCI space registers */
 enum pci_register_offsets {
@@ -421,6 +438,7 @@
 enum ChipConfig_bits {
 	CfgPhyDis		= 0x200,
 	CfgPhyRst		= 0x400,
+	CfgExtPhy		= 0x1000,
 	CfgAnegEnable		= 0x2000,
 	CfgAneg100		= 0x4000,
 	CfgAnegFull		= 0x8000,
@@ -630,10 +648,13 @@
 	u32 SavedClkRun;
 	/* silicon revision */
 	u32 srr;
+	/* expected DSPCFG value */
+	u16 dspcfg;
 	/* MII transceiver section. */
 	u16 advertising; /* NWay media advertisement */
 	unsigned int iosize;
 	spinlock_t lock;
+	u32 msg_enable;
 };
 
 static int eeprom_read(long ioaddr, int location);
@@ -643,6 +664,8 @@
 static void natsemi_reload_eeprom(struct net_device *dev);
 static void natsemi_stop_rxtx(struct net_device *dev);
 static int netdev_open(struct net_device *dev);
+static void do_cable_magic(struct net_device *dev);
+static void undo_cable_magic(struct net_device *dev);
 static void check_link(struct net_device *dev);
 static void netdev_timer(unsigned long data);
 static void tx_timeout(struct net_device *dev);
@@ -753,6 +776,7 @@
 	pci_set_drvdata(pdev, dev);
 	np->iosize = iosize;
 	spin_lock_init(&np->lock);
+	np->msg_enable = debug;
 
 	/* Reset the chip to erase previous misconfiguration. */
 	natsemi_reload_eeprom(dev);
@@ -763,14 +787,15 @@
 		option = dev->mem_start;
 
 	/* The lower four bits are the media type. */
-	if (option > 0) {
+	if (option) {
 		if (option & 0x200)
 			np->full_duplex = 1;
 		if (option & 15)
-			printk(KERN_INFO "%s: ignoring user supplied media type %d",
+			printk(KERN_INFO 
+				"%s: ignoring user supplied media type %d",
 				dev->name, option & 15);
 	}
-	if (find_cnt < MAX_UNITS  &&  full_duplex[find_cnt] > 0)
+	if (find_cnt < MAX_UNITS  &&  full_duplex[find_cnt])
 		np->full_duplex = 1;
 
 	/* The chip-specific entries in the device structure. */
@@ -796,14 +821,17 @@
 	}
 	netif_carrier_off(dev);
 
-	printk(KERN_INFO "%s: %s at 0x%lx, ",
-		   dev->name, natsemi_pci_info[chip_idx].name, ioaddr);
-	for (i = 0; i < ETH_ALEN-1; i++)
-			printk("%2.2x:", dev->dev_addr[i]);
-	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+	if (netif_msg_drv(np)) {
+		printk(KERN_INFO "%s: %s at %#08lx, ",
+			   dev->name, natsemi_pci_info[chip_idx].name, ioaddr);
+		for (i = 0; i < ETH_ALEN-1; i++)
+				printk("%02x:", dev->dev_addr[i]);
+		printk("%02x, IRQ %d.\n", dev->dev_addr[i], irq);
+	}
 
 	np->advertising = mdio_read(dev, 1, MII_ADVERTISE);
-	if ((readl(ioaddr + ChipConfig) & 0xe000) != 0xe000) {
+	if ((readl(ioaddr + ChipConfig) & 0xe000) != 0xe000 
+	 && netif_msg_probe(np)) {
 		u32 chip_config = readl(ioaddr + ChipConfig);
 		printk(KERN_INFO "%s: Transceiver default autonegotiation %s "
 			   "10%s %s duplex.\n",
@@ -812,12 +840,18 @@
 			   chip_config & CfgAneg100 ? "0" : "",
 			   chip_config & CfgAnegFull ? "full" : "half");
 	}
-	printk(KERN_INFO "%s: Transceiver status 0x%4.4x advertising %4.4x.\n",
-		   dev->name, mdio_read(dev, 1, MII_BMSR), 
-		   np->advertising);
+	if (netif_msg_probe(np))
+		printk(KERN_INFO 
+			"%s: Transceiver status %#04x advertising %#04x.\n",
+			dev->name, mdio_read(dev, 1, MII_BMSR), 
+			np->advertising);
 
 	/* save the silicon revision for later querying */
 	np->srr = readl(ioaddr + SiliconRev);
+	if (netif_msg_hw(np))
+		printk(KERN_INFO "%s: silicon revision %#04x.\n",
+				dev->name, np->srr);
+
 
 	return 0;
 }
@@ -914,6 +948,7 @@
 	u32 rfcr;
 	u16 pmatch[3];
 	u16 sopass[3];
+	struct netdev_private *np = dev->priv;
 
 	/* 
 	 * Resetting the chip causes some registers to be lost.
@@ -947,10 +982,10 @@
 			break;
 		udelay(5);
 	}
-	if (i==NATSEMI_HW_TIMEOUT && debug) {
+	if (i==NATSEMI_HW_TIMEOUT && netif_msg_hw(np)) {
 		printk(KERN_INFO "%s: reset did not complete in %d usec.\n",
 		   dev->name, i*5);
-	} else if (debug > 2) {
+	} else if (netif_msg_hw(np)) {
 		printk(KERN_DEBUG "%s: reset completed in %d usec.\n",
 		   dev->name, i*5);
 	}
@@ -979,6 +1014,7 @@
 
 static void natsemi_reload_eeprom(struct net_device *dev)
 {
+	struct netdev_private *np = dev->priv;
 	int i;
 
 	writel(EepromReload, dev->base_addr + PCIBusCfg);
@@ -987,10 +1023,10 @@
 			break;
 		udelay(5);
 	}
-	if (i==NATSEMI_HW_TIMEOUT && debug) {
+	if (i==NATSEMI_HW_TIMEOUT && netif_msg_hw(np)) {
 		printk(KERN_INFO "%s: EEPROM did not reload in %d usec.\n",
 		   dev->name, i*5);
-	} else if (debug > 2) {
+	} else if (netif_msg_hw(np)) {
 		printk(KERN_DEBUG "%s: EEPROM reloaded in %d usec.\n",
 		   dev->name, i*5);
 	}
@@ -999,6 +1035,7 @@
 static void natsemi_stop_rxtx(struct net_device *dev)
 {
 	long ioaddr = dev->base_addr;
+	struct netdev_private *np = dev->priv;
 	int i;
 
 	writel(RxOff | TxOff, ioaddr + ChipCmd);
@@ -1007,10 +1044,10 @@
 			break;
 		udelay(5);
 	}
-	if (i==NATSEMI_HW_TIMEOUT && debug) {
+	if (i==NATSEMI_HW_TIMEOUT && netif_msg_hw(np)) {
 		printk(KERN_INFO "%s: Tx/Rx process did not stop in %d usec.\n",
 				dev->name, i*5);
-	} else if (debug > 2) {
+	} else if (netif_msg_hw(np)) {
 		printk(KERN_DEBUG "%s: Tx/Rx process stopped in %d usec.\n",
 				dev->name, i*5);
 	}
@@ -1028,7 +1065,7 @@
 	i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev);
 	if (i) return i;
 
-	if (debug > 1)
+	if (netif_msg_ifup(np))
 		printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
 			   dev->name, dev->irq);
 	i = alloc_ring(dev);
@@ -1043,8 +1080,8 @@
 
 	netif_start_queue(dev);
 
-	if (debug > 2)
-		printk(KERN_DEBUG "%s: Done netdev_open(), status: %x.\n",
+	if (netif_msg_ifup(np))
+		printk(KERN_DEBUG "%s: Done netdev_open(), status: %#08x.\n",
 			   dev->name, (int)readl(ioaddr + ChipCmd));
 
 	/* Set the timer to check for link beat. */
@@ -1057,6 +1094,54 @@
 	return 0;
 }
 
+static void do_cable_magic(struct net_device *dev)
+{
+	/*
+	 * 100 MBit links with short cables can trip an issue with the chip.
+	 * The problem manifests as lots of CRC errors and/or flickering
+	 * activity LED while idle.  This process is based on instructions
+	 * from engineers at National.
+	 */
+	if (readl(dev->base_addr + ChipConfig) & CfgSpeed100) {
+		u16 data;
+
+		writew(1, dev->base_addr + PGSEL);
+		/*
+		 * coefficient visibility should already be enabled via
+		 * DSPCFG | 0x1000
+		 */
+		data = readw(dev->base_addr + TSTDAT) & 0xff;
+		/*
+		 * the value must be negative, and within certain values
+		 * (these values all come from National)
+		 */
+		if (!(data & 0x80) || ((data >= 0xd8) && (data <= 0xff))) {
+			struct netdev_private *np = dev->priv;
+
+			/* the bug has been triggered - fix the coefficient */
+			writew(TSTDAT_FIXED, dev->base_addr + TSTDAT);
+			/* lock the value */
+			data = readw(dev->base_addr + DSPCFG);
+			np->dspcfg = data | DSPCFG_LOCK;
+			writew(np->dspcfg, dev->base_addr + DSPCFG);
+		}
+		writew(0, dev->base_addr + PGSEL);
+	}
+}
+
+static void undo_cable_magic(struct net_device *dev)
+{
+	u16 data;
+	struct netdev_private *np = dev->priv;
+
+	writew(1, dev->base_addr + PGSEL);
+	/* make sure the lock bit is clear */
+	data = readw(dev->base_addr + DSPCFG);
+	np->dspcfg = data & ~DSPCFG_LOCK;
+	writew(np->dspcfg, dev->base_addr + DSPCFG);
+	writew(0, dev->base_addr + PGSEL);
+}
+
 static void check_link(struct net_device *dev)
 {
 	struct netdev_private *np = dev->priv;
@@ -1064,30 +1149,32 @@
 	int duplex;
 	int chipcfg = readl(ioaddr + ChipConfig);
 
-	if(!(chipcfg & CfgLink)) {
+	if (!(chipcfg & CfgLink)) {
 		if (netif_carrier_ok(dev)) {
-			if (debug)
-				printk(KERN_INFO "%s: no link. Disabling watchdog.\n",
+			if (netif_msg_link(np))
+				printk(KERN_NOTICE "%s: link down.\n", 
 					dev->name);
 			netif_carrier_off(dev);
+			undo_cable_magic(dev);
 		}
 		return;
 	}
 	if (!netif_carrier_ok(dev)) {
-		if (debug)
-			printk(KERN_INFO "%s: link is back. Enabling watchdog.\n",
-					dev->name);
+		if (netif_msg_link(np))
+			printk(KERN_NOTICE "%s: link up.\n", dev->name);
 		netif_carrier_on(dev);
+		do_cable_magic(dev);
 	}
 
 	duplex = np->full_duplex || (chipcfg & CfgFullDuplex ? 1 : 0);
 
 	/* if duplex is set then bit 28 must be set, too */
 	if (duplex ^ !!(np->rx_config & RxAcceptTx)) {
-		if (debug)
-			printk(KERN_INFO "%s: Setting %s-duplex based on negotiated link"
-				   " capability.\n", dev->name,
-				   duplex ? "full" : "half");
+		if (netif_msg_link(np))
+			printk(KERN_INFO 
+				"%s: Setting %s-duplex based on negotiated "
+				"link capability.\n", dev->name,
+				duplex ? "full" : "half");
 		if (duplex) {
 			np->rx_config |= RxAcceptTx;
 			np->tx_config |= TxCarrierIgn | TxHeartIgn;
@@ -1106,17 +1193,12 @@
 	long ioaddr = dev->base_addr;
 	int i;
 
-	/* save the silicon revision for later */
-	if (debug > 4)
-		printk(KERN_DEBUG "%s: found silicon revision %xh.\n",
-				dev->name, np->srr);
-
 	for (i=0;i<NATSEMI_HW_TIMEOUT;i++) {
 		if (readl(dev->base_addr + ChipConfig) & CfgAnegDone)
 			break;
 		udelay(10);
 	}
-	if (i==NATSEMI_HW_TIMEOUT && debug) {
+	if (i==NATSEMI_HW_TIMEOUT && netif_msg_link(np)) {
 		printk(KERN_INFO 
 			"%s: autonegotiation did not complete in %d usec.\n",
 			dev->name, i*10);
@@ -1135,6 +1217,7 @@
 	writew(DSPCFG_VAL, ioaddr + DSPCFG);
 	writew(SDCFG_VAL, ioaddr + SDCFG);
 	writew(0, ioaddr + PGSEL);
+	np->dspcfg = DSPCFG_VAL;
 
 	/* Enable PHY Specific event based interrupts.  Link state change
 	   and Auto-Negotiation Completion are among the affected.
@@ -1181,8 +1264,8 @@
 	 * nothing will be written to memory. */
 	np->SavedClkRun = readl(ioaddr + ClkRun);
 	writel(np->SavedClkRun & ~PMEEnable, ioaddr + ClkRun);
-	if (np->SavedClkRun & PMEStatus) {
-		printk(KERN_NOTICE "%s: Wake-up event %8.8x\n", 
+	if (np->SavedClkRun & PMEStatus && netif_msg_wol(np)) {
+		printk(KERN_NOTICE "%s: Wake-up event %#08x\n", 
 			dev->name, readl(ioaddr + WOLCmd));
 	}
 
@@ -1197,8 +1280,10 @@
 	writel(StatsClear, ioaddr + StatsCtrl); /* Clear Stats */
 }
 
-/* 
- * The frequency on this has been increased because of a nasty little problem.
+/*
+ * Purpose:
+ * check for sudden death of the NIC:
+ *
  * It seems that a reference set for this chip went out with incorrect info,
  * and there exist boards that aren't quite right.  An unexpected voltage drop
  * can cause the PHY to get itself in a weird state (basically reset..).
@@ -1212,7 +1297,7 @@
 	long ioaddr = dev->base_addr;
 	u16 dspcfg;
 
-	if (debug > 3) {
+	if (netif_msg_timer(np)) {
 		/* DO NOT read the IntrStatus register, 
 		 * a read clears any pending interrupts.
 		 */
@@ -1220,15 +1305,18 @@
 			   dev->name);
 	}
 
+	spin_lock_irq(&np->lock);
+
 	/* check for a nasty random phy-reset - use dspcfg as a flag */
 	writew(1, ioaddr+PGSEL);
 	dspcfg = readw(ioaddr+DSPCFG);
 	writew(0, ioaddr+PGSEL);
-	if (dspcfg != DSPCFG_VAL) {
+	if (dspcfg != np->dspcfg) {
 		if (!netif_queue_stopped(dev)) {
-			printk(KERN_INFO 
-				"%s: possible phy reset: re-initializing\n",
-				dev->name);
+			spin_unlock_irq(&np->lock);
+			if (netif_msg_hw(np))
+				printk(KERN_NOTICE "%s: possible phy reset: "
+					"re-initializing\n", dev->name);
 			disable_irq(dev->irq);
 			spin_lock_irq(&np->lock);
 			init_registers(dev);
@@ -1237,10 +1325,10 @@
 		} else {
 			/* hurry back */
 			next_tick = HZ;
+			spin_unlock_irq(&np->lock);
 		}
 	} else {
 		/* init_registers() calls check_link() for the above case */
-		spin_lock_irq(&np->lock);
 		check_link(dev);
 		spin_unlock_irq(&np->lock);
 	}
@@ -1251,18 +1339,18 @@
 {
 	struct netdev_private *np = dev->priv;
 
-	if (debug > 2) {
+	if (netif_msg_pktdata(np)) {
 		int i;
 		printk(KERN_DEBUG "  Tx ring at %p:\n", np->tx_ring);
 		for (i = 0; i < TX_RING_SIZE; i++) {
-			printk(KERN_DEBUG " #%d desc. %8.8x %8.8x %8.8x.\n",
+			printk(KERN_DEBUG " #%d desc. %#08x %#08x %#08x.\n",
 				   i, np->tx_ring[i].next_desc,
 				   np->tx_ring[i].cmd_status, 
 				   np->tx_ring[i].addr);
 		}
 		printk(KERN_DEBUG "  Rx ring %p:\n", np->rx_ring);
 		for (i = 0; i < RX_RING_SIZE; i++) {
-			printk(KERN_DEBUG " #%d desc. %8.8x %8.8x %8.8x.\n",
+			printk(KERN_DEBUG " #%d desc. %#08x %#08x %#08x.\n",
 				   i, np->rx_ring[i].next_desc,
 				   np->rx_ring[i].cmd_status, 
 				   np->rx_ring[i].addr);
@@ -1278,9 +1366,11 @@
 	disable_irq(dev->irq);
 	spin_lock_irq(&np->lock);
 	if (netif_device_present(dev)) {
-		printk(KERN_WARNING "%s: Transmit timed out, status %8.8x,"
-			" resetting...\n", 
-			dev->name, readl(ioaddr + IntrStatus));
+		if (netif_msg_tx_err(np))
+			printk(KERN_WARNING 
+				"%s: Transmit timed out, status %#08x,"
+				" resetting...\n", 
+				dev->name, readl(ioaddr + IntrStatus));
 		dump_ring(dev);
 
 		natsemi_reset(dev);
@@ -1304,8 +1394,8 @@
 {
 	struct netdev_private *np = dev->priv;
 	np->rx_ring = pci_alloc_consistent(np->pci_dev,
-				sizeof(struct netdev_desc) * (RX_RING_SIZE+TX_RING_SIZE),
-				&np->ring_dma);
+	    sizeof(struct netdev_desc) * (RX_RING_SIZE+TX_RING_SIZE),
+	    &np->ring_dma);
 	if (!np->rx_ring)
 		return -ENOMEM;
 	np->tx_ring = &np->rx_ring[RX_RING_SIZE];
@@ -1438,7 +1528,7 @@
 
 	dev->trans_start = jiffies;
 
-	if (debug > 4) {
+	if (netif_msg_tx_queued(np)) {
 		printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
 			   dev->name, np->cur_tx, entry);
 	}
@@ -1451,14 +1541,11 @@
 
 	for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
 		int entry = np->dirty_tx % TX_RING_SIZE;
-		if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescOwn)) {
-			if (debug > 4)
-				printk(KERN_DEBUG "%s: tx frame #%d is busy.\n",
-						dev->name, np->dirty_tx);
+		if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescOwn))
 			break;
-		}
-		if (debug > 4)
-			printk(KERN_DEBUG "%s: tx frame #%d finished with status %8.8xh.\n",
+		if (netif_msg_tx_done(np))
+			printk(KERN_DEBUG 
+				"%s: tx frame #%d finished, status %#08x.\n",
 					dev->name, np->dirty_tx,
 					le32_to_cpu(np->tx_ring[entry].cmd_status));
 		if (np->tx_ring[entry].cmd_status & cpu_to_le32(DescPktOK)) {
@@ -1495,30 +1582,31 @@
 static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
 {
 	struct net_device *dev = dev_instance;
-	struct netdev_private *np;
-	long ioaddr;
+	struct netdev_private *np = dev->priv;
+	long ioaddr = dev->base_addr;
 	int boguscnt = max_interrupt_work;
 
-	ioaddr = dev->base_addr;
-	np = dev->priv;
-	
 	if (!netif_device_present(dev))
 		return;
 	do {
 		/* Reading automatically acknowledges all int sources. */
 		u32 intr_status = readl(ioaddr + IntrStatus);
 
-		if (debug > 4)
-			printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n",
+		if (netif_msg_intr(np))
+			printk(KERN_DEBUG "%s: Interrupt, status %#08x.\n",
 				   dev->name, intr_status);
 
 		if (intr_status == 0)
 			break;
 
-		if (intr_status & (IntrRxDone | IntrRxIntr | RxStatusFIFOOver | IntrRxErr | IntrRxOverrun ))
+		if (intr_status &
+		   (IntrRxDone | IntrRxIntr | RxStatusFIFOOver |
+		    IntrRxErr | IntrRxOverrun)) {
 			netdev_rx(dev);
+		}
 
-		if (intr_status & (IntrTxDone | IntrTxIntr | IntrTxIdle | IntrTxErr) ) {
+		if (intr_status &
+		   (IntrTxDone | IntrTxIntr | IntrTxIdle | IntrTxErr)) {
 			spin_lock(&np->lock);
 			netdev_tx_done(dev);
 			spin_unlock(&np->lock);
@@ -1529,16 +1617,16 @@
 			netdev_error(dev, intr_status);
 
 		if (--boguscnt < 0) {
-			printk(KERN_WARNING "%s: Too much work at interrupt, "
-				   "status=0x%4.4x.\n",
-				   dev->name, intr_status);
+			if (netif_msg_intr(np))
+				printk(KERN_WARNING 
+				    "%s: Too much work at interrupt, "
+				    "status=%#08x.\n", dev->name, intr_status);
 			break;
 		}
 	} while (1);
 
-	if (debug > 4)
-		printk(KERN_DEBUG "%s: exiting interrupt.\n",
-			   dev->name);
+	if (netif_msg_intr(np))
+		printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name);
 }
 
 /* This routine is logically part of the interrupt handler, but separated
@@ -1552,22 +1640,24 @@
 
 	/* If the driver owns the next entry it's a new packet. Send it up. */
 	while (desc_status < 0) {        /* e.g. & DescOwn */
-		if (debug > 4)
-			printk(KERN_DEBUG "  In netdev_rx() entry %d status was %8.8x.\n",
-				   entry, desc_status);
+		if (netif_msg_rx_status(np))
+			printk(KERN_DEBUG 
+				"  netdev_rx() entry %d status was %#08x.\n",
+				entry, desc_status);
 		if (--boguscnt < 0)
 			break;
-		if ((desc_status & (DescMore|DescPktOK|DescRxLong)) != DescPktOK) {
+		if ((desc_status&(DescMore|DescPktOK|DescRxLong)) != DescPktOK){
 			if (desc_status & DescMore) {
-				printk(KERN_WARNING "%s: Oversized(?) Ethernet frame spanned "
-					   "multiple buffers, entry %#x status %x.\n",
-					   dev->name, np->cur_rx, desc_status);
+				if (netif_msg_rx_err(np))
+					printk(KERN_WARNING 
+						"%s: Oversized(?) Ethernet "
+						"frame spanned multiple "
+						"buffers, entry %#08x "
+						"status %#08x.\n", dev->name, 
+						np->cur_rx, desc_status);
 				np->stats.rx_length_errors++;
 			} else {
-				/* There was a error. */
-				if (debug > 2)
-					printk(KERN_DEBUG "  netdev_rx() Rx error was %8.8x.\n",
-						   desc_status);
+				/* There was an error. */
 				np->stats.rx_errors++;
 				if (desc_status & (DescRxAbort|DescRxOver)) 
 					np->stats.rx_over_errors++;
@@ -1582,8 +1672,8 @@
 			struct sk_buff *skb;
 			/* Omit CRC size. */
 			int pkt_len = (desc_status & DescSizeMask) - 4;
-			/* Check if the packet is long enough to accept without copying
-			   to a minimally-sized skbuff. */
+			/* Check if the packet is long enough to accept 
+			 * without copying to a minimally-sized skbuff. */
 			if (pkt_len < rx_copybreak
 				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
 				skb->dev = dev;
@@ -1646,11 +1736,16 @@
 
 	spin_lock(&np->lock);
 	if (intr_status & LinkChange) {
-		printk(KERN_NOTICE 
-			"%s: Link changed: Autonegotiation advertising"
-			" %4.4x  partner %4.4x.\n", dev->name,
-			(int)mdio_read(dev, 1, MII_ADVERTISE), 
-			(int)mdio_read(dev, 1, MII_LPA));
+		u16 adv = mdio_read(dev, 1, MII_ADVERTISE);
+		u16 lpa = mdio_read(dev, 1, MII_LPA);
+		if (mdio_read(dev, 1, MII_BMCR) & BMCR_ANENABLE 
+		 && netif_msg_link(np)) {
+			printk(KERN_INFO 
+				"%s: Autonegotiation advertising"
+				" %#04x  partner %#04x.\n", dev->name,
+				adv, lpa);
+		}
+
 		/* read MII int status to clear the flag */
 		readw(ioaddr + MIntrStatus);
 		check_link(dev);
@@ -1661,29 +1756,28 @@
 	if (intr_status & IntrTxUnderrun) {
 		if ((np->tx_config & TxDrthMask) < 62)
 			np->tx_config += 2;
-		if (debug > 2)
-			printk(KERN_NOTICE "%s: increasing Tx threshold, new tx cfg %8.8xh.\n",
-					dev->name, np->tx_config);
+		if (netif_msg_tx_err(np))
+			printk(KERN_NOTICE
+				"%s: increased Tx threshold, txcfg %#08x.\n",
+				dev->name, np->tx_config);
 		writel(np->tx_config, ioaddr + TxConfig);
 	}
-	if (intr_status & WOLPkt) {
+	if (intr_status & WOLPkt && netif_msg_wol(np)) {
 		int wol_status = readl(ioaddr + WOLCmd);
-		printk(KERN_NOTICE "%s: Link wake-up event %8.8x\n",
+		printk(KERN_NOTICE "%s: Link wake-up event %#08x\n",
 			   dev->name, wol_status);
 	}
 	if (intr_status & RxStatusFIFOOver) {
-		if (debug >= 2) {
-			printk(KERN_NOTICE "%s: Rx status FIFO overrun\n", 
+		if (netif_msg_rx_err(np) && netif_msg_intr(np)) {
+			printk(KERN_NOTICE "%s: Rx status FIFO overrun\n",
 				dev->name);
 		}
 		np->stats.rx_fifo_errors++;
 	}
 	/* Hmmmmm, it's not clear how to recover from PCI faults. */
 	if (intr_status & IntrPCIErr) {
-		if (debug) {
-			printk(KERN_NOTICE "%s: PCI error %08x\n", dev->name,
-				intr_status & IntrPCIErr);
-		}
+		printk(KERN_NOTICE "%s: PCI error %#08x\n", dev->name,
+			intr_status & IntrPCIErr);
 		np->stats.tx_fifo_errors++;
 		np->stats.rx_fifo_errors++;
 	}
@@ -1761,7 +1855,8 @@
 
 	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */
 		/* Unconditionally log net taps. */
-		printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
+		printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", 
+			dev->name);
 		rx_mode = RxFilterEnable | AcceptBroadcast 
 			| AcceptAllMulticast | AcceptAllPhys | AcceptMyPhys;
 	} else if ((dev->mc_count > multicast_filter_limit)
@@ -1896,7 +1991,7 @@
 	/* get message-level */
 	case ETHTOOL_GMSGLVL: {
 		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
-		edata.data = debug;
+		edata.data = np->msg_enable;
 		if (copy_to_user(useraddr, &edata, sizeof(edata)))
 			return -EFAULT;
 		return 0;
@@ -1906,7 +2001,7 @@
 		struct ethtool_value edata;
 		if (copy_from_user(&edata, useraddr, sizeof(edata)))
 			return -EFAULT;
-		debug = edata.data;
+		np->msg_enable = edata.data;
 		return 0;
 	}
 	/* restart autonegotiation */
@@ -1941,6 +2036,9 @@
 		if (copy_from_user(&eeprom, useraddr, sizeof(eeprom)))
 			return -EFAULT;
 		
+		if (eeprom.offset > eeprom.offset+eeprom.len)
+			return -EINVAL;
+
 		if ((eeprom.offset+eeprom.len) > NATSEMI_EEPROM_SIZE) {
 			eeprom.len = NATSEMI_EEPROM_SIZE-eeprom.offset;
 		}
@@ -2096,18 +2194,22 @@
 	ecmd->supported = 
 		(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
 		SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
-		SUPPORTED_Autoneg | SUPPORTED_TP);
+		SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
 	
-	/* only supports twisted-pair */
-	ecmd->port = PORT_TP;
+	/* only supports twisted-pair or MII */
+	tmp = readl(dev->base_addr + ChipConfig);
+	if (tmp & CfgExtPhy)
+		ecmd->port = PORT_MII;
+	else
+		ecmd->port = PORT_TP;
 
 	/* only supports internal transceiver */
 	ecmd->transceiver = XCVR_INTERNAL;
 
-	/* this isn't fully supported at higher layers */
+	/* not sure what this is for */
 	ecmd->phy_address = readw(dev->base_addr + PhyCtrl) & PhyAddrMask;
 
-	ecmd->advertising = ADVERTISED_TP;
+	ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
 	tmp = mdio_read(dev, 1, MII_ADVERTISE);
 	if (tmp & ADVERTISE_10HALF)
 		ecmd->advertising |= ADVERTISED_10baseT_Half;
@@ -2118,20 +2220,21 @@
 	if (tmp & ADVERTISE_100FULL)
 		ecmd->advertising |= ADVERTISED_100baseT_Full;
 
-	tmp = readl(dev->base_addr + ChipConfig);
-	if (tmp & CfgAnegEnable) {
+	tmp = mdio_read(dev, 1, MII_BMCR);
+	if (tmp & BMCR_ANENABLE) {
 		ecmd->advertising |= ADVERTISED_Autoneg;
 		ecmd->autoneg = AUTONEG_ENABLE;
 	} else {
 		ecmd->autoneg = AUTONEG_DISABLE;
 	}
 
+	tmp = readl(dev->base_addr + ChipConfig);
 	if (tmp & CfgSpeed100) {
 		ecmd->speed = SPEED_100;
 	} else {
 		ecmd->speed = SPEED_10;
 	}
-
+		
 	if (tmp & CfgFullDuplex) {
 		ecmd->duplex = DUPLEX_FULL;
 	} else {
@@ -2152,7 +2255,7 @@
 		return -EINVAL;
 	if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
 		return -EINVAL;
-	if (ecmd->port != PORT_TP)
+	if (ecmd->port != PORT_TP && ecmd->port != PORT_MII)
 		return -EINVAL;
 	if (ecmd->transceiver != XCVR_INTERNAL)
 		return -EINVAL;
@@ -2162,39 +2265,22 @@
 	
 	/* WHEW! now lets bang some bits */
 	
+	tmp = mdio_read(dev, 1, MII_BMCR);
 	if (ecmd->autoneg == AUTONEG_ENABLE) {
-		/* advertise only what has been requested */
-		tmp = readl(dev->base_addr + ChipConfig);
-		tmp &= ~(CfgAneg100 | CfgAnegFull);
-		tmp |= CfgAnegEnable;
-		if (ecmd->advertising & ADVERTISED_100baseT_Half 
-		 || ecmd->advertising & ADVERTISED_100baseT_Full) {
-			tmp |= CfgAneg100;
-		}
-		if (ecmd->advertising & ADVERTISED_10baseT_Full 
-		 || ecmd->advertising & ADVERTISED_100baseT_Full) {
-			tmp |= CfgAnegFull;
-		}
-		writel(tmp, dev->base_addr + ChipConfig);
-		/* turn on autonegotiation, and force a renegotiate */
-		tmp = mdio_read(dev, 1, MII_BMCR);
-		tmp |= (BMCR_ANENABLE | BMCR_ANRESTART);
-		mdio_write(dev, 1, MII_BMCR, tmp);
+		/* turn on autonegotiation */
+		tmp |= BMCR_ANENABLE;
 		np->advertising = mdio_read(dev, 1, MII_ADVERTISE);
 	} else {
 		/* turn off auto negotiation, set speed and duplexity */
-		tmp = mdio_read(dev, 1, MII_BMCR);
 		tmp &= ~(BMCR_ANENABLE | BMCR_SPEED100 | BMCR_FULLDPLX);
-		if (ecmd->speed == SPEED_100) {
+		if (ecmd->speed == SPEED_100)
 			tmp |= BMCR_SPEED100;
-		}
-		if (ecmd->duplex == DUPLEX_FULL) {
+		if (ecmd->duplex == DUPLEX_FULL)
 			tmp |= BMCR_FULLDPLX;
-		} else {
+		else
 			np->full_duplex = 0;
-		}
-		mdio_write(dev, 1, MII_BMCR, tmp);
 	}
+	mdio_write(dev, 1, MII_BMCR, tmp);
 	return 0;
 }
 
@@ -2229,7 +2315,7 @@
 	/* the interrupt status is clear-on-read - see if we missed any */
 	if (rbuf[4] & rbuf[5]) {
 		printk(KERN_WARNING 
-			"%s: shoot, we dropped an interrupt (0x%x)\n", 
+			"%s: shoot, we dropped an interrupt (%#08x)\n", 
 			dev->name, rbuf[4] & rbuf[5]);
 	}
 
@@ -2296,7 +2382,7 @@
 	long ioaddr = dev->base_addr;
 	struct netdev_private *np = dev->priv;
 
-	if (debug > 1)
+	if (netif_msg_wol(np))
 		printk(KERN_INFO "%s: remaining active for wake-on-lan\n", 
 			dev->name);
 
@@ -2319,7 +2405,8 @@
 		/* enable the WOL interrupt.
 		 * Could be used to send a netlink message.
 		 */
-		writel(readl(ioaddr + IntrMask) | WOLPkt, ioaddr + IntrMask);
+		writel(WOLPkt | LinkChange, ioaddr + IntrMask);
+		writel(1, ioaddr + IntrEnable);
 	}
 }
 
@@ -2331,12 +2418,15 @@
 	netif_stop_queue(dev);
 	netif_carrier_off(dev);
 
-	if (debug > 1) {
-		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n",
-			   dev->name, (int)readl(ioaddr + ChipCmd));
-		printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d,  Rx %d / %d.\n",
-			   dev->name, np->cur_tx, np->dirty_tx, np->cur_rx, np->dirty_rx);
-	}
+	if (netif_msg_ifdown(np))
+		printk(KERN_DEBUG 
+			"%s: Shutting down ethercard, status was %#04x.\n",
+			dev->name, (int)readl(ioaddr + ChipCmd));
+	if (netif_msg_pktdata(np))
+		printk(KERN_DEBUG 
+			"%s: Queue pointers were Tx %d / %d,  Rx %d / %d.\n",
+			dev->name, np->cur_tx, np->dirty_tx, 
+			np->cur_rx, np->dirty_rx);
 
 	del_timer_sync(&np->timer);
 
@@ -2375,7 +2465,7 @@
 	drain_ring(dev);
 	free_ring(dev);
 
-	 {
+	{
 		u32 wol = readl(ioaddr + WOLCmd) & WakeOptsSummary;
 		if (wol) {
 			/* restart the NIC in WOL mode.
diff -Nru a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c
--- a/drivers/net/pci-skeleton.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/net/pci-skeleton.c	Fri Sep 20 08:20:41 2002
@@ -1411,10 +1411,6 @@
 				tp->stats.tx_carrier_errors++;
 			if (txstatus & TxOutOfWindow)
 				tp->stats.tx_window_errors++;
-#ifdef ETHER_STATS
-			if ((txstatus & 0x0f000000) == 0x0f000000)
-				tp->stats.collisions16++;
-#endif
 		} else {
 			if (txstatus & TxUnderrun) {
 				/* Add 64 to the Tx FIFO threshold. */
diff -Nru a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
--- a/drivers/net/pcmcia/axnet_cs.c	Fri Sep 20 08:20:46 2002
+++ b/drivers/net/pcmcia/axnet_cs.c	Fri Sep 20 08:20:46 2002
@@ -33,6 +33,8 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/byteorder.h>
@@ -817,6 +819,27 @@
     add_timer(&info->watchdog);
 }
 
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+    u32 ethcmd;
+
+    if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+	return -EFAULT;
+
+    switch (ethcmd) {
+    case ETHTOOL_GDRVINFO: {
+	struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+
+	strncpy(info.driver, "axnet_cs", sizeof(info.driver)-1);
+	if (copy_to_user(useraddr, &info, sizeof(info)))
+	    return -EFAULT;
+	return 0;
+    }
+    }
+
+    return -EOPNOTSUPP;
+}
+
 /*====================================================================*/
 
 static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
@@ -825,6 +848,8 @@
     u16 *data = (u16 *)&rq->ifr_data;
     ioaddr_t mii_addr = dev->base_addr + AXNET_MII_EEP;
     switch (cmd) {
+    case SIOCETHTOOL:
+	return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
     case SIOCDEVPRIVATE:
 	data[0] = info->phy_id;
     case SIOCDEVPRIVATE+1:
diff -Nru a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
--- a/drivers/net/pcmcia/pcnet_cs.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/net/pcmcia/pcnet_cs.c	Fri Sep 20 08:20:47 2002
@@ -66,7 +66,7 @@
 #define SOCKET_START_PG	0x01
 #define SOCKET_STOP_PG	0xff
 
-#define PCNET_RDC_TIMEOUT 0x02	/* Max wait in jiffies for Tx RDC */
+#define PCNET_RDC_TIMEOUT (2*HZ/100)	/* Max wait in jiffies for Tx RDC */
 
 static char *if_names[] = { "auto", "10baseT", "10base2"};
 
@@ -1188,7 +1188,7 @@
 	}
 	info->link_status = link;
     }
-    if (info->pna_phy && (jiffies - info->mii_reset > 6*HZ)) {
+    if (info->pna_phy && time_after(jiffies, info->mii_reset + 6*HZ)) {
 	link = mdio_read(mii_addr, info->eth_phy, 1) & 0x0004;
 	if (((info->phy_id == info->pna_phy) && link) ||
 	    ((info->phy_id != info->pna_phy) && !link)) {
@@ -1426,7 +1426,7 @@
 #endif
 
     while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0)
-	if (jiffies - dma_start > PCNET_RDC_TIMEOUT) {
+	if (time_after(jiffies, dma_start + PCNET_RDC_TIMEOUT)) {
 	    printk(KERN_NOTICE "%s: timeout waiting for Tx RDC.\n",
 		   dev->name);
 	    pcnet_reset_8390(dev);
diff -Nru a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
--- a/drivers/net/ppp_generic.c	Fri Sep 20 08:20:48 2002
+++ b/drivers/net/ppp_generic.c	Fri Sep 20 08:20:48 2002
@@ -1401,7 +1401,7 @@
 	if (skb->len > 0)
 		/* note: a 0-length skb is used as an error indication */
 		++ppp->stats.rx_length_errors;
-err:
+
 	kfree_skb(skb);
 	ppp_receive_error(ppp);
 }
diff -Nru a/drivers/net/sundance.c b/drivers/net/sundance.c
--- a/drivers/net/sundance.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/net/sundance.c	Fri Sep 20 08:20:47 2002
@@ -18,26 +18,62 @@
 	http://www.scyld.com/network/sundance.html
 
 
-	Version 1.01a (jgarzik):
+	Version LK1.01a (jgarzik):
 	- Replace some MII-related magic numbers with constants
 
-	Version 1.02 (D-Link):
+	Version LK1.02 (D-Link):
 	- Add new board to PCI ID list
 	- Fix multicast bug
 
+	Version LK1.03 (D-Link):
+	- New Rx scheme, reduce Rx congestion
+	- Option to disable flow control
+
+	Version LK1.04 (D-Link):
+	- Tx timeout recovery
+	- More support for ethtool.
+
+	Version LK1.04a:
+	- Remove unused/constant members from struct pci_id_info
+	(which then allows removal of 'drv_flags' from private struct)
+	(jgarzik)
+	- If no phy is found, fail to load that board (jgarzik)
+	- Always start phy id scan at id 1 to avoid problems (Donald Becker)
+	- Autodetect where mii_preable_required is needed,
+	default to not needed.  (Donald Becker)
+
+	Version LK1.04b:
+	- Remove mii_preamble_required module parameter (Donald Becker)
+	- Add per-interface mii_preamble_required (setting is autodetected)
+	  (Donald Becker)
+	- Remove unnecessary cast from void pointer (jgarzik)
+	- Re-align comments in private struct (jgarzik)
+
+	Version LK1.04c (jgarzik):
+	- Support bitmapped message levels (NETIF_MSG_xxx), and the
+	  two ethtool ioctls that get/set them
+	- Don't hand-code MII ethtool support, use standard API/lib
+
+	Version LK1.04d:
+	- Merge from Donald Becker's sundance.c: (Jason Lunz)
+		* proper support for variably-sized MTUs
+		* default to PIO, to fix chip bugs
+	- Add missing unregister_netdev (Jason Lunz)
+	- Add CONFIG_SUNDANCE_MMIO config option (jgarzik)
+	- Better rx buf size calculation (Donald Becker)
+
 */
 
 #define DRV_NAME	"sundance"
-#define DRV_VERSION	"1.02"
-#define DRV_RELDATE	"17-Jan-2002"
+#define DRV_VERSION	"1.01+LK1.04d"
+#define DRV_RELDATE	"19-Sep-2002"
 
 
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
 static int debug = 1;			/* 1 normal messages, 0 quiet .. 7 verbose. */
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 30;
-static int mtu;
+static int max_interrupt_work = 0;
 /* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
    Typical is a 64 element hash table based on the Ethernet CRC.  */
 static int multicast_filter_limit = 32;
@@ -47,6 +83,8 @@
    This chip can receive into offset buffers, so the Alpha does not
    need a copy-align. */
 static int rx_copybreak;
+static int tx_coalesce=1;
+static int flowctrl=1;
 
 /* media[] specifies the media type the NIC operates at.
 		 autosense	Autosensing active media.
@@ -60,8 +98,10 @@
 		 3	 	100Mbps half duplex.
 		 4	 	100Mbps full duplex.
 */
-#define MAX_UNITS 8	
+#define MAX_UNITS 8
 static char *media[MAX_UNITS];
+
+
 /* Operational parameters that are set at compile time. */
 
 /* Keep the ring sizes a power of two for compile efficiency.
@@ -70,9 +110,10 @@
    bonding and packet priority, and more than 128 requires modifying the
    Tx error recovery.
    Large receive rings merely waste memory. */
-#define TX_RING_SIZE	16
-#define TX_QUEUE_LEN	10		/* Limit ring entries actually used.  */
-#define RX_RING_SIZE	32
+#define TX_RING_SIZE	64
+#define TX_QUEUE_LEN	(TX_RING_SIZE - 1) /* Limit ring entries actually used.  */
+#define RX_RING_SIZE	64
+#define RX_BUDGET	32
 #define TX_TOTAL_SIZE	TX_RING_SIZE*sizeof(struct netdev_desc)
 #define RX_TOTAL_SIZE	RX_RING_SIZE*sizeof(struct netdev_desc)
 
@@ -107,13 +148,17 @@
 #include <linux/init.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
-#include <linux/crc32.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>		/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
+#ifndef _LOCAL_CRC32
+#include <linux/crc32.h>
+#else
+#include "crc32.h"
+#endif
 
 /* These identify the driver base version and may not be removed. */
 static char version[] __devinitdata =
@@ -125,14 +170,15 @@
 MODULE_LICENSE("GPL");
 
 MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(mtu, "i");
 MODULE_PARM(debug, "i");
 MODULE_PARM(rx_copybreak, "i");
 MODULE_PARM(media, "1-" __MODULE_STRING(MAX_UNITS) "s");
+MODULE_PARM(flowctrl, "i");
 MODULE_PARM_DESC(max_interrupt_work, "Sundance Alta maximum events handled per interrupt");
-MODULE_PARM_DESC(mtu, "Sundance Alta MTU (all boards)");
 MODULE_PARM_DESC(debug, "Sundance Alta debug level (0-5)");
 MODULE_PARM_DESC(rx_copybreak, "Sundance Alta copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(flowctrl, "Sundance Alta flow control [0|1]");
+
 /*
 				Theory of Operation
 
@@ -207,20 +253,9 @@
 
 */
 
-
-
-enum pci_id_flags_bits {
-        /* Set PCI command register bits before calling probe1(). */
-        PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
-        /* Read and map the single following PCI BAR. */
-        PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4,
-        PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400,
-};
-enum chip_capability_flags {CanHaveMII=1, };
-#ifdef USE_IO_OPS
-#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO  | PCI_ADDR0)
-#else
-#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
+/* Work-around for Kendin chip bugs. */
+#ifndef CONFIG_SUNDANCE_MMIO
+#define USE_IO_OPS 1
 #endif
 
 static struct pci_device_id sundance_pci_tbl[] __devinitdata = {
@@ -234,31 +269,20 @@
 };
 MODULE_DEVICE_TABLE(pci, sundance_pci_tbl);
 
+enum {
+	netdev_io_size = 128
+};
+
 struct pci_id_info {
         const char *name;
-        struct match_info {
-                int     pci, pci_mask, subsystem, subsystem_mask;
-                int revision, revision_mask;                            /* Only 8 bits. */
-        } id;
-        enum pci_id_flags_bits pci_flags;
-        int io_size;                            /* Needed for I/O region check or ioremap(). */
-        int drv_flags;                          /* Driver use, intended as capability flags. */
 };
 static struct pci_id_info pci_id_tbl[] = {
-	{"D-Link DFE-550TX FAST Ethernet Adapter", {0x10021186, 0xffffffff,},
-	 PCI_IOTYPE, 128, CanHaveMII},
-	{"D-Link DFE-550FX 100Mbps Fiber-optics Adapter",
-	 {0x10031186, 0xffffffff,},
-	 PCI_IOTYPE, 128, CanHaveMII},
-	{"D-Link DFE-580TX 4 port Server Adapter", {0x10121186, 0xffffffff,},
-	 PCI_IOTYPE, 128, CanHaveMII},
-	{"D-Link DFE-530TXS FAST Ethernet Adapter", {0x10021186, 0xffffffff,},
-	 PCI_IOTYPE, 128, CanHaveMII},
-	{"D-Link DL10050-based FAST Ethernet Adapter",
-	 {0x10021186, 0xffffffff,},
-	 PCI_IOTYPE, 128, CanHaveMII},
-	{"Sundance Technology Alta", {0x020113F0, 0xffffffff,},
-	 PCI_IOTYPE, 128, CanHaveMII},
+	{"D-Link DFE-550TX FAST Ethernet Adapter"},
+	{"D-Link DFE-550FX 100Mbps Fiber-optics Adapter"},
+	{"D-Link DFE-580TX 4 port Server Adapter"},
+	{"D-Link DFE-530TXS FAST Ethernet Adapter"},
+	{"D-Link DL10050-based FAST Ethernet Adapter"},
+	{"Sundance Technology Alta"},
 	{0,},			/* 0 terminated list. */
 };
 
@@ -290,20 +314,24 @@
 enum alta_offsets {
 	DMACtrl = 0x00,
 	TxListPtr = 0x04,
-	TxDMACtrl = 0x08,
-	TxDescPoll = 0x0a,
+	TxDMABurstThresh = 0x08,
+	TxDMAUrgentThresh = 0x09,
+	TxDMAPollPeriod = 0x0a,
 	RxDMAStatus = 0x0c,
 	RxListPtr = 0x10,
-	RxDMACtrl = 0x14,
-	RxDescPoll = 0x16,
+	RxDMABurstThresh = 0x14,
+	RxDMAUrgentThresh = 0x15,
+	RxDMAPollPeriod = 0x16,
 	LEDCtrl = 0x1a,
 	ASICCtrl = 0x30,
 	EEData = 0x34,
 	EECtrl = 0x36,
-	TxThreshold = 0x3c,
+	TxStartThresh = 0x3c,
+	RxEarlyThresh = 0x3e,
 	FlashAddr = 0x40,
 	FlashData = 0x44,
 	TxStatus = 0x46,
+	TxFrameId = 0x47,
 	DownCounter = 0x18,
 	IntrClear = 0x4a,
 	IntrEnable = 0x4c,
@@ -311,7 +339,7 @@
 	MACCtrl0 = 0x50,
 	MACCtrl1 = 0x52,
 	StationAddr = 0x54,
-	MaxTxSize = 0x5A,
+	MaxFrameSize = 0x5A,
 	RxMode = 0x5c,
 	MIICtrl = 0x5e,
 	MulticastFilter0 = 0x60,
@@ -337,6 +365,16 @@
 	/* Aliased and bogus values! */
 	RxStatus = 0x0c,
 };
+enum ASICCtrl_HiWord_bit {
+	GlobalReset = 0x0001,
+	RxReset = 0x0002,
+	TxReset = 0x0004,
+	DMAReset = 0x0008,
+	FIFOReset = 0x0010,
+	NetworkReset = 0x0020,
+	HostReset = 0x0040,
+	ResetBusy = 0x0400,
+};
 
 /* Bits in the interrupt status/mask registers. */
 enum intr_status_bits {
@@ -396,35 +434,40 @@
         dma_addr_t tx_ring_dma;
         dma_addr_t rx_ring_dma;
 	struct net_device_stats stats;
-	struct timer_list timer;	/* Media monitoring timer. */
+	struct timer_list timer;		/* Media monitoring timer. */
 	/* Frequently used values: keep some adjacent for cache effect. */
 	spinlock_t lock;
-	int chip_id, drv_flags;
+	spinlock_t rx_lock;			/* Group with Tx control cache line. */
+	int msg_enable;
+	int chip_id;
 	unsigned int cur_rx, dirty_rx;		/* Producer/consumer ring indices */
-	unsigned int rx_buf_sz;				/* Based on MTU+slack. */
-	spinlock_t txlock;					/* Group with Tx control cache line. */
+	unsigned int rx_buf_sz;			/* Based on MTU+slack. */
 	struct netdev_desc *last_tx;		/* Last Tx descriptor used. */
 	unsigned int cur_tx, dirty_tx;
-	unsigned int tx_full:1;				/* The Tx queue is full. */
 	/* These values are keep track of the transceiver/media in use. */
-	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
-	unsigned int medialock:1;			/* Do not sense media. */
+	unsigned int flowctrl:1;
 	unsigned int default_port:4;		/* Last dev->if_port value. */
 	unsigned int an_enable:1;
 	unsigned int speed;
+	struct tasklet_struct rx_tasklet;
+	int budget;
 	/* Multicast and receive mode. */
-	spinlock_t mcastlock;				/* SMP lock multicast updates. */
+	spinlock_t mcastlock;			/* SMP lock multicast updates. */
 	u16 mcast_filter[4];
 	/* MII transceiver section. */
-	int mii_cnt;						/* MII device addresses. */
-	u16 advertising;					/* NWay media advertisement */
+	struct mii_if_info mii_if;
+	int mii_preamble_required;
 	unsigned char phys[MII_CNT];		/* MII device addresses, only first one used. */
 	struct pci_dev *pci_dev;
 };
 
 /* The station address location in the EEPROM. */
 #define EEPROM_SA_OFFSET	0x10
+#define DEFAULT_INTR (IntrRxDMADone | IntrPCIErr | \
+			IntrDrvRqst | IntrTxDone | StatsMax | \
+			LinkChange)
 
+static int  change_mtu(struct net_device *dev, int new_mtu);
 static int  eeprom_read(long ioaddr, int location);
 static int  mdio_read(struct net_device *dev, int phy_id, int location);
 static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
@@ -434,16 +477,18 @@
 static void tx_timeout(struct net_device *dev);
 static void init_ring(struct net_device *dev);
 static int  start_tx(struct sk_buff *skb, struct net_device *dev);
+static int reset_tx (struct net_device *dev, int irq);
 static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
+static void rx_poll(unsigned long data);
+static void refill_rx (struct net_device *dev);
 static void netdev_error(struct net_device *dev, int intr_status);
-static int  netdev_rx(struct net_device *dev);
 static void netdev_error(struct net_device *dev, int intr_status);
 static void set_rx_mode(struct net_device *dev);
 static struct net_device_stats *get_stats(struct net_device *dev);
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int  netdev_close(struct net_device *dev);
 
-
+
 
 static int __devinit sundance_probe1 (struct pci_dev *pdev,
 				      const struct pci_device_id *ent)
@@ -485,7 +530,7 @@
 	ioaddr = pci_resource_start(pdev, 0);
 #else
 	ioaddr = pci_resource_start(pdev, 1);
-	ioaddr = (long) ioremap (ioaddr, pci_id_tbl[chip_idx].io_size);
+	ioaddr = (long) ioremap (ioaddr, netdev_io_size);
 	if (!ioaddr)
 		goto err_out_res;
 #endif
@@ -498,10 +543,11 @@
 	dev->irq = irq;
 
 	np = dev->priv;
-	np->chip_id = chip_idx;
-	np->drv_flags = pci_id_tbl[chip_idx].drv_flags;
 	np->pci_dev = pdev;
+	np->chip_id = chip_idx;
+	np->msg_enable = (1 << debug) - 1;
 	spin_lock_init(&np->lock);
+	tasklet_init(&np->rx_tasklet, rx_poll, (unsigned long)dev);
 
 	ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma);
 	if (!ring_space)
@@ -515,6 +561,10 @@
 	np->rx_ring = (struct netdev_desc *)ring_space;
 	np->rx_ring_dma = ring_dma;
 
+	np->mii_if.dev = dev;
+	np->mii_if.mdio_read = mdio_read;
+	np->mii_if.mdio_write = mdio_write;
+
 	/* The chip-specific entries in the device structure. */
 	dev->open = &netdev_open;
 	dev->hard_start_xmit = &start_tx;
@@ -524,11 +574,9 @@
 	dev->do_ioctl = &netdev_ioctl;
 	dev->tx_timeout = &tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
+	dev->change_mtu = &change_mtu;
 	pci_set_drvdata(pdev, dev);
 
-	if (mtu)
-		dev->mtu = mtu;
-
 	i = register_netdev(dev);
 	if (i)
 		goto err_out_unmap_rx;
@@ -542,21 +590,30 @@
 	if (1) {
 		int phy, phy_idx = 0;
 		np->phys[0] = 1;		/* Default setting */
-		for (phy = 0; phy < 32 && phy_idx < MII_CNT; phy++) {
-			int mii_status = mdio_read(dev, phy, 1);
+		np->mii_preamble_required++;
+		for (phy = 1; phy < 32 && phy_idx < MII_CNT; phy++) {
+			int mii_status = mdio_read(dev, phy, MII_BMSR);
 			if (mii_status != 0xffff  &&  mii_status != 0x0000) {
 				np->phys[phy_idx++] = phy;
-				np->advertising = mdio_read(dev, phy, 4);
+				np->mii_if.advertising = mdio_read(dev, phy, MII_ADVERTISE);
+				if ((mii_status & 0x0040) == 0)
+					np->mii_preamble_required++;
 				printk(KERN_INFO "%s: MII PHY found at address %d, status "
 					   "0x%4.4x advertising %4.4x.\n",
-					   dev->name, phy, mii_status, np->advertising);
+					   dev->name, phy, mii_status, np->mii_if.advertising);
 			}
 		}
-		np->mii_cnt = phy_idx;
-		if (phy_idx == 0)
-			printk(KERN_INFO "%s: No MII transceiver found!, ASIC status %x\n",
+		np->mii_preamble_required--;
+
+		if (phy_idx == 0) {
+			printk(KERN_INFO "%s: No MII transceiver found, aborting.  ASIC status %x\n",
 				   dev->name, readl(ioaddr + ASICCtrl));
+			goto err_out_unregister;
+		}
+
+		np->mii_if.phy_id = np->phys[0];
 	}
+
 	/* Parse override configuration */
 	np->an_enable = 1;
 	if (card_idx < MAX_UNITS) {
@@ -565,23 +622,29 @@
 			if (strcmp (media[card_idx], "100mbps_fd") == 0 ||
 			    strcmp (media[card_idx], "4") == 0) {
 				np->speed = 100;
-				np->full_duplex = 1;
+				np->mii_if.full_duplex = 1;
 			} else if (strcmp (media[card_idx], "100mbps_hd") == 0
 				   || strcmp (media[card_idx], "3") == 0) {
 				np->speed = 100;
-				np->full_duplex = 0;
+				np->mii_if.full_duplex = 0;
 			} else if (strcmp (media[card_idx], "10mbps_fd") == 0 ||
 				   strcmp (media[card_idx], "2") == 0) {
 				np->speed = 10;
-				np->full_duplex = 1;
+				np->mii_if.full_duplex = 1;
 			} else if (strcmp (media[card_idx], "10mbps_hd") == 0 ||
 				   strcmp (media[card_idx], "1") == 0) {
 				np->speed = 10;
-				np->full_duplex = 0;
+				np->mii_if.full_duplex = 0;
 			} else {
 				np->an_enable = 1;
 			}
 		}
+		if (tx_coalesce < 1)
+			tx_coalesce = 1;
+		else if (tx_coalesce > TX_QUEUE_LEN - 1)
+			tx_coalesce = TX_QUEUE_LEN - 1;
+		if (flowctrl == 0)
+			np->flowctrl = 0;
 	}
 
 	/* Fibre PHY? */
@@ -589,7 +652,7 @@
 		/* Default 100Mbps Full */
 		if (np->an_enable) {
 			np->speed = 100;
-			np->full_duplex = 1;
+			np->mii_if.full_duplex = 1;
 			np->an_enable = 0;
 		}
 	}
@@ -601,24 +664,26 @@
 	if (!np->an_enable) {
 		mii_ctl = 0;
 		mii_ctl |= (np->speed == 100) ? BMCR_SPEED100 : 0;
-		mii_ctl |= (np->full_duplex) ? BMCR_FULLDPLX : 0;
+		mii_ctl |= (np->mii_if.full_duplex) ? BMCR_FULLDPLX : 0;
 		mdio_write (dev, np->phys[0], MII_BMCR, mii_ctl);
 		printk (KERN_INFO "Override speed=%d, %s duplex\n",
-			np->speed, np->full_duplex ? "Full" : "Half");
+			np->speed, np->mii_if.full_duplex ? "Full" : "Half");
 
 	}
 
 	/* Perhaps move the reset here? */
 	/* Reset the chip to erase previous misconfiguration. */
-	if (debug > 1)
+	if (netif_msg_hw(np))
 		printk("ASIC Control is %x.\n", readl(ioaddr + ASICCtrl));
 	writew(0x007f, ioaddr + ASICCtrl + 2);
-	if (debug > 1)
+	if (netif_msg_hw(np))
 		printk("ASIC Control is now %x.\n", readl(ioaddr + ASICCtrl));
 
 	card_idx++;
 	return 0;
 
+err_out_unregister:
+	unregister_netdev(dev);
 err_out_unmap_rx:
         pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma);
 err_out_unmap_tx:
@@ -635,7 +700,16 @@
 	return -ENODEV;
 }
 
-
+static int change_mtu(struct net_device *dev, int new_mtu)
+{
+	if ((new_mtu < 68) || (new_mtu > 8191)) /* Set by RxDMAFrameLen */
+		return -EINVAL;
+	if (netif_running(dev))
+		return -EBUSY;
+	dev->mtu = new_mtu;
+	return 0;
+}
+
 /* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. */
 static int __devinit eeprom_read(long ioaddr, int location)
 {
@@ -658,11 +732,6 @@
 	met by back-to-back 33Mhz PCI cycles. */
 #define mdio_delay() readb(mdio_addr)
 
-/* Set iff a MII transceiver on any interface requires mdio preamble.
-   This only set with older tranceivers, so the extra
-   code size of a per-interface flag is not worthwhile. */
-static const char mii_preamble_required = 1;
-
 enum mii_reg_bits {
 	MDIO_ShiftClk=0x0001, MDIO_Data=0x0002, MDIO_EnbOutput=0x0004,
 };
@@ -687,11 +756,12 @@
 
 static int mdio_read(struct net_device *dev, int phy_id, int location)
 {
+	struct netdev_private *np = dev->priv;
 	long mdio_addr = dev->base_addr + MIICtrl;
 	int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;
 	int i, retval = 0;
 
-	if (mii_preamble_required)
+	if (np->mii_preamble_required)
 		mdio_sync(mdio_addr);
 
 	/* Shift the read command bits out. */
@@ -716,11 +786,12 @@
 
 static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
 {
+	struct netdev_private *np = dev->priv;
 	long mdio_addr = dev->base_addr + MIICtrl;
 	int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
 	int i;
 
-	if (mii_preamble_required)
+	if (np->mii_preamble_required)
 		mdio_sync(mdio_addr);
 
 	/* Shift the command bits out. */
@@ -742,7 +813,6 @@
 	return;
 }
 
-
 static int netdev_open(struct net_device *dev)
 {
 	struct netdev_private *np = dev->priv;
@@ -755,7 +825,7 @@
 	if (i)
 		return i;
 
-	if (debug > 1)
+	if (netif_msg_ifup(np))
 		printk(KERN_DEBUG "%s: netdev_open() irq %d.\n",
 			   dev->name, dev->irq);
 
@@ -768,6 +838,10 @@
 		writeb(dev->dev_addr[i], ioaddr + StationAddr + i);
 
 	/* Initialize other registers. */
+	writew(dev->mtu + 14, ioaddr + MaxFrameSize);
+	if (dev->mtu > 2047)
+		writel(readl(ioaddr + ASICCtrl) | 0x0C, ioaddr + ASICCtrl);
+
 	/* Configure the PCI bus bursts and FIFO thresholds. */
 
 	if (dev->if_port == 0)
@@ -779,17 +853,13 @@
 	writew(0, ioaddr + IntrEnable);
 	writew(0, ioaddr + DownCounter);
 	/* Set the chip to poll every N*320nsec. */
-	writeb(100, ioaddr + RxDescPoll);
-	writeb(127, ioaddr + TxDescPoll);
+	writeb(100, ioaddr + RxDMAPollPeriod);
+	writeb(127, ioaddr + TxDMAPollPeriod);
 	netif_start_queue(dev);
 
-	/* Enable interrupts by setting the interrupt mask. */
-	writew(IntrRxDone | IntrRxDMADone | IntrPCIErr | IntrDrvRqst | IntrTxDone
-		   | StatsMax | LinkChange, ioaddr + IntrEnable);
-
 	writew(StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1);
 
-	if (debug > 2)
+	if (netif_msg_ifup(np))
 		printk(KERN_DEBUG "%s: Done netdev_open(), status: Rx %x Tx %x "
 			   "MAC Control %x, %4.4x %4.4x.\n",
 			   dev->name, readl(ioaddr + RxStatus), readb(ioaddr + TxStatus),
@@ -803,6 +873,9 @@
 	np->timer.function = &netdev_timer;				/* timer handler */
 	add_timer(&np->timer);
 
+	/* Enable interrupts by setting the interrupt mask. */
+	writew(DEFAULT_INTR, ioaddr + IntrEnable);
+
 	return 0;
 }
 
@@ -811,21 +884,22 @@
 	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	int mii_lpa = mdio_read(dev, np->phys[0], MII_LPA);
-	int negotiated = mii_lpa & np->advertising;
+	int negotiated = mii_lpa & np->mii_if.advertising;
 	int duplex;
-	
+
 	/* Force media */
 	if (!np->an_enable || mii_lpa == 0xffff) {
-		if (np->full_duplex)
+		if (np->mii_if.full_duplex)
 			writew (readw (ioaddr + MACCtrl0) | EnbFullDuplex,
 				ioaddr + MACCtrl0);
 		return;
 	}
+
 	/* Autonegotiation */
 	duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
-	if (np->full_duplex != duplex) {
-		np->full_duplex = duplex;
-		if (debug)
+	if (np->mii_if.full_duplex != duplex) {
+		np->mii_if.full_duplex = duplex;
+		if (netif_msg_link(np))
 			printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d "
 				   "negotiated capability %4.4x.\n", dev->name,
 				   duplex ? "full" : "half", np->phys[0], negotiated);
@@ -840,7 +914,7 @@
 	long ioaddr = dev->base_addr;
 	int next_tick = 10*HZ;
 
-	if (debug > 3) {
+	if (netif_msg_timer(np)) {
 		printk(KERN_DEBUG "%s: Media selection timer tick, intr status %4.4x, "
 			   "Tx %x Rx %x.\n",
 			   dev->name, readw(ioaddr + IntrEnable),
@@ -855,9 +929,12 @@
 {
 	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
+	long flag;
 
-	printk(KERN_WARNING "%s: Transmit timed out, status %2.2x,"
-		   " resetting...\n", dev->name, readb(ioaddr + TxStatus));
+	printk(KERN_WARNING "%s: Transmit timed out, TxStatus %2.2x "
+		   "TxFrameId %2.2x,"
+		   " resetting...\n", dev->name, readb(ioaddr + TxStatus),
+		   readb(ioaddr + TxFrameId));
 
 	{
 		int i;
@@ -866,22 +943,24 @@
 			printk(" %8.8x", (unsigned int)np->rx_ring[i].status);
 		printk("\n"KERN_DEBUG"  Tx ring %p: ", np->tx_ring);
 		for (i = 0; i < TX_RING_SIZE; i++)
-			printk(" %4.4x", np->tx_ring[i].status);
+			printk(" %8.8x", np->tx_ring[i].status);
 		printk("\n");
 	}
+	spin_lock_irqsave(&np->lock, flag);
+	reset_tx(dev, 0);
+	spin_unlock_irqrestore(&np->lock, flag);
 
 	/* Perhaps we should reinitialize the hardware here. */
 	dev->if_port = 0;
 	/* Stop and restart the chip's Tx processes . */
 
 	/* Trigger an immediate transmit demand. */
-	writew(IntrRxDone | IntrRxDMADone | IntrPCIErr | IntrDrvRqst | IntrTxDone
-		   | StatsMax | LinkChange, ioaddr + IntrEnable);
+	writew(DEFAULT_INTR, ioaddr + IntrEnable);
 
 	dev->trans_start = jiffies;
 	np->stats.tx_errors++;
 
-	if (!np->tx_full)
+	if (!netif_queue_stopped(dev))
 		netif_wake_queue(dev);
 }
 
@@ -892,15 +971,14 @@
 	struct netdev_private *np = dev->priv;
 	int i;
 
-	np->tx_full = 0;
 	np->cur_rx = np->cur_tx = 0;
 	np->dirty_rx = np->dirty_tx = 0;
 
-	np->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
+	np->rx_buf_sz = (dev->mtu <= 1520 ? PKT_BUF_SZ : dev->mtu + 16);
 
 	/* Initialize all Rx descriptors. */
 	for (i = 0; i < RX_RING_SIZE; i++) {
-		np->rx_ring[i].next_desc = cpu_to_le32(np->rx_ring_dma + 
+		np->rx_ring[i].next_desc = cpu_to_le32(np->rx_ring_dma +
 			((i+1)%RX_RING_SIZE)*sizeof(*np->rx_ring));
 		np->rx_ring[i].status = 0;
 		np->rx_ring[i].frag[0].length = 0;
@@ -916,7 +994,7 @@
 		skb->dev = dev;		/* Mark as being used by this device. */
 		skb_reserve(skb, 2);	/* 16 byte align the IP header. */
 		np->rx_ring[i].frag[0].addr = cpu_to_le32(
-			pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, 
+			pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz,
 				PCI_DMA_FROMDEVICE));
 		np->rx_ring[i].frag[0].length = cpu_to_le32(np->rx_buf_sz | LastFrag);
 	}
@@ -929,15 +1007,16 @@
 	return;
 }
 
-static int start_tx(struct sk_buff *skb, struct net_device *dev)
+static int
+start_tx (struct sk_buff *skb, struct net_device *dev)
 {
 	struct netdev_private *np = dev->priv;
 	struct netdev_desc *txdesc;
 	unsigned entry;
+	long ioaddr = dev->base_addr;
 
 	/* Note: Ordering is important here, set the field with the
 	   "ownership" bit last, and only then increment cur_tx. */
-
 	/* Calculate the next Tx descriptor entry. */
 	entry = np->cur_tx % TX_RING_SIZE;
 	np->tx_skbuff[entry] = skb;
@@ -945,11 +1024,17 @@
 
 	txdesc->next_desc = 0;
 	/* Note: disable the interrupt generation here before releasing. */
-	txdesc->status =
-		cpu_to_le32((entry<<2) | DescIntrOnDMADone | DescIntrOnTx | DisableAlign);
-	txdesc->frag[0].addr = cpu_to_le32(pci_map_single(np->pci_dev, 
-		skb->data, skb->len, PCI_DMA_TODEVICE));
-	txdesc->frag[0].length = cpu_to_le32(skb->len | LastFrag);
+	if (entry % tx_coalesce == 0) {
+		txdesc->status = cpu_to_le32 ((entry << 2) |
+				 DescIntrOnTx | DisableAlign);
+
+	} else {
+		txdesc->status = cpu_to_le32 ((entry << 2) | DisableAlign);
+	}
+	txdesc->frag[0].addr = cpu_to_le32 (pci_map_single (np->pci_dev, skb->data,
+							skb->len,
+							PCI_DMA_TODEVICE));
+	txdesc->frag[0].length = cpu_to_le32 (skb->len | LastFrag);
 	if (np->last_tx)
 		np->last_tx->next_desc = cpu_to_le32(np->tx_ring_dma +
 			entry*sizeof(struct netdev_desc));
@@ -957,24 +1042,63 @@
 	np->cur_tx++;
 
 	/* On some architectures: explicitly flush cache lines here. */
-
-	if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 1) {
+	if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 1
+			&& !netif_queue_stopped(dev)) {
 		/* do nothing */
 	} else {
-		np->tx_full = 1;
-		netif_stop_queue(dev);
+		netif_stop_queue (dev);
 	}
 	/* Side effect: The read wakes the potentially-idle transmit channel. */
-	if (readl(dev->base_addr + TxListPtr) == 0)
-		writel(np->tx_ring_dma + entry*sizeof(*np->tx_ring),
+	if (readl (dev->base_addr + TxListPtr) == 0)
+		writel (np->tx_ring_dma + entry*sizeof(*np->tx_ring),
 			dev->base_addr + TxListPtr);
 
 	dev->trans_start = jiffies;
 
-	if (debug > 4) {
-		printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
-			   dev->name, np->cur_tx, entry);
+	if (netif_msg_tx_queued(np)) {
+		printk (KERN_DEBUG
+			"%s: Transmit frame #%d queued in slot %d.\n",
+			dev->name, np->cur_tx, entry);
+	}
+	if (tx_coalesce > 1)
+		writel (1000, ioaddr + DownCounter);
+	return 0;
+}
+static int
+reset_tx (struct net_device *dev, int irq)
+{
+	struct netdev_private *np = (struct netdev_private*) dev->priv;
+	long ioaddr = dev->base_addr;
+	int i;
+	int frame_id;
+
+	frame_id = readb(ioaddr + TxFrameId);
+	writew (TxReset | DMAReset | FIFOReset | NetworkReset,
+			ioaddr + ASICCtrl + 2);
+	for (i=50; i > 0; i--) {
+		if ((readw(ioaddr + ASICCtrl + 2) & ResetBusy) == 0)
+			break;
+		mdelay(1);
+	}
+	for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
+		int entry = np->dirty_tx % TX_RING_SIZE;
+		struct sk_buff *skb;
+		if (!(np->tx_ring[entry].status & 0x00010000))
+			break;
+		skb = np->tx_skbuff[entry];
+		/* Free the original skb. */
+		pci_unmap_single(np->pci_dev,
+			np->tx_ring[entry].frag[0].addr,
+			skb->len, PCI_DMA_TODEVICE);
+		if (irq)
+			dev_kfree_skb_irq (np->tx_skbuff[entry]);
+		else
+			dev_kfree_skb (np->tx_skbuff[entry]);
+
+		np->tx_skbuff[entry] = 0;
 	}
+	writel (np->tx_ring_dma + frame_id * sizeof(*np->tx_ring),
+			dev->base_addr + TxListPtr);
 	return 0;
 }
 
@@ -989,139 +1113,131 @@
 
 	ioaddr = dev->base_addr;
 	np = dev->priv;
-	spin_lock(&np->lock);
 
 	do {
 		int intr_status = readw(ioaddr + IntrStatus);
-		writew(intr_status & (IntrRxDone | IntrRxDMADone | IntrPCIErr |
-			IntrDrvRqst | IntrTxDone | IntrTxDMADone | StatsMax | 
-			LinkChange), ioaddr + IntrStatus);
+		writew(intr_status, ioaddr + IntrStatus);
 
-		if (debug > 4)
+		if (netif_msg_intr(np))
 			printk(KERN_DEBUG "%s: Interrupt, status %4.4x.\n",
 				   dev->name, intr_status);
 
-		if (intr_status == 0)
+		if (!(intr_status & DEFAULT_INTR))
 			break;
 
-		if (intr_status & (IntrRxDone|IntrRxDMADone))
-			netdev_rx(dev);
+		if (intr_status & (IntrRxDMADone)) {
+			writew(DEFAULT_INTR & ~(IntrRxDone|IntrRxDMADone),
+					ioaddr + IntrEnable);
+			if (np->budget < 0)
+				np->budget = RX_BUDGET;
+			tasklet_schedule(&np->rx_tasklet);
+		}
 
-		if (intr_status & IntrTxDone) {
+		if (intr_status & (IntrTxDone | IntrDrvRqst)) {
 			int boguscnt = 32;
-			int tx_status = readw(ioaddr + TxStatus);
+			int tx_status = readw (ioaddr + TxStatus);
 			while (tx_status & 0x80) {
-				if (debug > 4)
-					printk("%s: Transmit status is %2.2x.\n",
-						   dev->name, tx_status);
+				if (netif_msg_tx_done(np))
+					printk
+					    ("%s: Transmit status is %2.2x.\n",
+					     dev->name, tx_status);
 				if (tx_status & 0x1e) {
 					np->stats.tx_errors++;
-					if (tx_status & 0x10)  np->stats.tx_fifo_errors++;
-#ifdef ETHER_STATS
-					if (tx_status & 0x08)  np->stats.collisions16++;
-#else
-					if (tx_status & 0x08)  np->stats.collisions++;
-#endif
-					if (tx_status & 0x04)  np->stats.tx_fifo_errors++;
-					if (tx_status & 0x02)  np->stats.tx_window_errors++;
+					if (tx_status & 0x10)
+						np->stats.tx_fifo_errors++;
+					if (tx_status & 0x08)
+						np->stats.collisions++;
+					if (tx_status & 0x02)
+						np->stats.tx_window_errors++;
 					/* This reset has not been verified!. */
-					if (tx_status & 0x10) {			/* Reset the Tx. */
-						writew(0x001c, ioaddr + ASICCtrl + 2);
-#if 0					/* Do we need to reset the Tx pointer here? */
-						writel(np->tx_ring_dma
-							+ np->dirty_tx*sizeof(*np->tx_ring),
-							dev->base_addr + TxListPtr);
-#endif
+					if (tx_status & 0x10) {	/* Reset the Tx. */
+						np->stats.tx_fifo_errors++;
+						spin_lock(&np->lock);
+						reset_tx(dev, 1);
+						spin_unlock(&np->lock);
 					}
-					if (tx_status & 0x1e) 		/* Restart the Tx. */
-						writew(TxEnable, ioaddr + MACCtrl1);
+					if (tx_status & 0x1e)	/* Restart the Tx. */
+						writew (TxEnable,
+							ioaddr + MACCtrl1);
 				}
 				/* Yup, this is a documentation bug.  It cost me *hours*. */
-				writew(0, ioaddr + TxStatus);
-				tx_status = readb(ioaddr + TxStatus);
+				writew (0, ioaddr + TxStatus);
+				tx_status = readw (ioaddr + TxStatus);
 				if (--boguscnt < 0)
 					break;
 			}
 		}
+		spin_lock(&np->lock);
 		for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
 			int entry = np->dirty_tx % TX_RING_SIZE;
 			struct sk_buff *skb;
-
-			if ( ! (np->tx_ring[entry].status & 0x00010000))
+			if (!(np->tx_ring[entry].status & 0x00010000))
 				break;
 			skb = np->tx_skbuff[entry];
 			/* Free the original skb. */
-			pci_unmap_single(np->pci_dev, 
-				np->tx_ring[entry].frag[0].addr, 
+			pci_unmap_single(np->pci_dev,
+				np->tx_ring[entry].frag[0].addr,
 				skb->len, PCI_DMA_TODEVICE);
-			dev_kfree_skb_irq(skb);
+			dev_kfree_skb_irq (np->tx_skbuff[entry]);
 			np->tx_skbuff[entry] = 0;
 		}
-		if (np->tx_full
-			&& np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
+		spin_unlock(&np->lock);
+		if (netif_queue_stopped(dev) &&
+			np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
 			/* The ring is no longer full, clear tbusy. */
-			np->tx_full = 0;
-			netif_wake_queue(dev);
+			netif_wake_queue (dev);
 		}
 
 		/* Abnormal error summary/uncommon events handlers. */
-		if (intr_status & (IntrDrvRqst | IntrPCIErr | LinkChange | StatsMax))
+		if (intr_status & (IntrPCIErr | LinkChange | StatsMax))
 			netdev_error(dev, intr_status);
 		if (--boguscnt < 0) {
 			get_stats(dev);
-			if (debug > 1) 
+			if (netif_msg_hw(np))
 				printk(KERN_WARNING "%s: Too much work at interrupt, "
 				   "status=0x%4.4x / 0x%4.4x.\n",
 				   dev->name, intr_status, readw(ioaddr + IntrClear));
-			/* Re-enable us in 3.2msec. */
-			writew(0, ioaddr + IntrEnable);
-			writew(1000, ioaddr + DownCounter);
-			writew(IntrDrvRqst, ioaddr + IntrEnable);
 			break;
 		}
 	} while (1);
-
-	if (debug > 3)
+	if (netif_msg_intr(np))
 		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
 			   dev->name, readw(ioaddr + IntrStatus));
+	if (np->cur_tx - np->dirty_tx > 0 && tx_coalesce > 1)
+		writel(100, ioaddr + DownCounter);
 
-	spin_unlock(&np->lock);
 }
 
-/* This routine is logically part of the interrupt handler, but separated
-   for clarity and better register allocation. */
-static int netdev_rx(struct net_device *dev)
+static void rx_poll(unsigned long data)
 {
+	struct net_device *dev = (struct net_device *)data;
 	struct netdev_private *np = dev->priv;
 	int entry = np->cur_rx % RX_RING_SIZE;
-	int boguscnt = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
-
-	if (debug > 4) {
-		printk(KERN_DEBUG " In netdev_rx(), entry %d status %4.4x.\n",
-			   entry, np->rx_ring[entry].status);
-	}
+	int boguscnt = np->budget;
+	long ioaddr = dev->base_addr;
+	int received = 0;
 
 	/* If EOP is set on the next entry, it's a new packet. Send it up. */
 	while (1) {
 		struct netdev_desc *desc = &(np->rx_ring[entry]);
-		u32 frame_status;
+		u32 frame_status = le32_to_cpu(desc->status);
 		int pkt_len;
 
+		if (--boguscnt < 0) {
+			goto not_done;
+		}
 		if (!(desc->status & DescOwn))
 			break;
-		frame_status = le32_to_cpu(desc->status);
 		pkt_len = frame_status & 0x1fff;	/* Chip omits the CRC. */
-		if (debug > 4)
+		if (netif_msg_rx_status(np))
 			printk(KERN_DEBUG "  netdev_rx() status was %8.8x.\n",
 				   frame_status);
-		if (--boguscnt < 0)
-			break;
 		pci_dma_sync_single(np->pci_dev, desc->frag[0].addr,
 			np->rx_buf_sz, PCI_DMA_FROMDEVICE);
-		
+
 		if (frame_status & 0x001f4000) {
 			/* There was a error. */
-			if (debug > 2)
+			if (netif_msg_rx_err(np))
 				printk(KERN_DEBUG "  netdev_rx() Rx error was %8.8x.\n",
 					   frame_status);
 			np->stats.rx_errors++;
@@ -1136,9 +1252,8 @@
 			}
 		} else {
 			struct sk_buff *skb;
-
 #ifndef final_version
-			if (debug > 4)
+			if (netif_msg_rx_status(np))
 				printk(KERN_DEBUG "  netdev_rx() normal Rx pkt length %d"
 					   ", bogus_cnt %d.\n",
 					   pkt_len, boguscnt);
@@ -1152,9 +1267,9 @@
 				eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
 				skb_put(skb, pkt_len);
 			} else {
-				pci_unmap_single(np->pci_dev, 
+				pci_unmap_single(np->pci_dev,
 					desc->frag[0].addr,
-					np->rx_buf_sz, 
+					np->rx_buf_sz,
 					PCI_DMA_FROMDEVICE);
 				skb_put(skb = np->rx_skbuff[entry], pkt_len);
 				np->rx_skbuff[entry] = NULL;
@@ -1164,11 +1279,36 @@
 			netif_rx(skb);
 			dev->last_rx = jiffies;
 		}
-		entry = (++np->cur_rx) % RX_RING_SIZE;
+		entry = (entry + 1) % RX_RING_SIZE;
+		received++;
 	}
+	np->cur_rx = entry;
+	refill_rx (dev);
+	np->budget -= received;
+	writew(DEFAULT_INTR, ioaddr + IntrEnable);
+	return;
+
+not_done:
+	np->cur_rx = entry;
+	refill_rx (dev);
+	if (!received)
+		received = 1;
+	np->budget -= received;
+	if (np->budget <= 0)
+		np->budget = RX_BUDGET;
+	tasklet_schedule(&np->rx_tasklet);
+	return;
+}
+
+static void refill_rx (struct net_device *dev)
+{
+	struct netdev_private *np = dev->priv;
+	int entry;
+	int cnt = 0;
 
 	/* Refill the Rx ring buffers. */
-	for (; np->cur_rx - np->dirty_rx > 0; np->dirty_rx++) {
+	for (;(np->cur_rx - np->dirty_rx + RX_RING_SIZE) % RX_RING_SIZE > 0;
+		np->dirty_rx = (np->dirty_rx + 1) % RX_RING_SIZE) {
 		struct sk_buff *skb;
 		entry = np->dirty_rx % RX_RING_SIZE;
 		if (np->rx_skbuff[entry] == NULL) {
@@ -1179,19 +1319,17 @@
 			skb->dev = dev;		/* Mark as being used by this device. */
 			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
 			np->rx_ring[entry].frag[0].addr = cpu_to_le32(
-				pci_map_single(np->pci_dev, skb->tail, 
+				pci_map_single(np->pci_dev, skb->tail,
 					np->rx_buf_sz, PCI_DMA_FROMDEVICE));
 		}
 		/* Perhaps we need not reset this field. */
 		np->rx_ring[entry].frag[0].length =
 			cpu_to_le32(np->rx_buf_sz | LastFrag);
 		np->rx_ring[entry].status = 0;
+		cnt++;
 	}
-
-	/* No need to restart Rx engine, it will poll. */
-	return 0;
+	return;
 }
-
 static void netdev_error(struct net_device *dev, int intr_status)
 {
 	long ioaddr = dev->base_addr;
@@ -1199,43 +1337,40 @@
 	u16 mii_ctl, mii_advertise, mii_lpa;
 	int speed;
 
-	if (intr_status & IntrDrvRqst) {
-		/* Stop the down counter and turn interrupts back on. */
-		if (debug > 1)
-			printk("%s: Turning interrupts back on.\n", dev->name);
-		writew(0, ioaddr + IntrEnable);
-		writew(0, ioaddr + DownCounter);
-		writew(IntrRxDone | IntrRxDMADone | IntrPCIErr | IntrDrvRqst |
-			   IntrTxDone | StatsMax | LinkChange, ioaddr + IntrEnable);
-		/* Ack buggy InRequest */
-		writew (IntrDrvRqst, ioaddr + IntrStatus);
-	}
 	if (intr_status & LinkChange) {
 		if (np->an_enable) {
 			mii_advertise = mdio_read (dev, np->phys[0], MII_ADVERTISE);
 			mii_lpa= mdio_read (dev, np->phys[0], MII_LPA);
 			mii_advertise &= mii_lpa;
 			printk (KERN_INFO "%s: Link changed: ", dev->name);
-			if (mii_advertise & ADVERTISE_100FULL)
+			if (mii_advertise & ADVERTISE_100FULL) {
+				np->speed = 100;
 				printk ("100Mbps, full duplex\n");
-			else if (mii_advertise & ADVERTISE_100HALF)
+			} else if (mii_advertise & ADVERTISE_100HALF) {
+				np->speed = 100;
 				printk ("100Mbps, half duplex\n");
-			else if (mii_advertise & ADVERTISE_10FULL)
+			} else if (mii_advertise & ADVERTISE_10FULL) {
+				np->speed = 10;
 				printk ("10Mbps, full duplex\n");
-			else if (mii_advertise & ADVERTISE_10HALF)
+			} else if (mii_advertise & ADVERTISE_10HALF) {
+				np->speed = 10;
 				printk ("10Mbps, half duplex\n");
-			else
+			} else
 				printk ("\n");
 
 		} else {
 			mii_ctl = mdio_read (dev, np->phys[0], MII_BMCR);
 			speed = (mii_ctl & BMCR_SPEED100) ? 100 : 10;
+			np->speed = speed;
 			printk (KERN_INFO "%s: Link changed: %dMbps ,",
 				dev->name, speed);
 			printk ("%s duplex.\n", (mii_ctl & BMCR_FULLDPLX) ?
 				"full" : "half");
 		}
 		check_duplex (dev);
+		if (np->flowctrl == 0)
+			writew(readw(ioaddr + MACCtrl0) & ~EnbFlowCtrl,
+				ioaddr + MACCtrl0);
 	}
 	if (intr_status & StatsMax) {
 		get_stats(dev);
@@ -1319,24 +1454,80 @@
 {
 	struct netdev_private *np = dev->priv;
 	u32 ethcmd;
-		
+
 	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
 		return -EFAULT;
 
         switch (ethcmd) {
-        case ETHTOOL_GDRVINFO: {
-		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-		strcpy(info.driver, DRV_NAME);
-		strcpy(info.version, DRV_VERSION);
-		strcpy(info.bus_info, np->pci_dev->slot_name);
-		if (copy_to_user(useraddr, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
+		/* get constant driver settings/info */
+        	case ETHTOOL_GDRVINFO: {
+			struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+			strcpy(info.driver, DRV_NAME);
+			strcpy(info.version, DRV_VERSION);
+			strcpy(info.bus_info, np->pci_dev->slot_name);
+			memset(&info.fw_version, 0, sizeof(info.fw_version));
+			if (copy_to_user(useraddr, &info, sizeof(info)))
+				return -EFAULT;
+			return 0;
+		}
+
+		/* get media settings */
+		case ETHTOOL_GSET: {
+			struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+			spin_lock_irq(&np->lock);
+			mii_ethtool_gset(&np->mii_if, &ecmd);
+			spin_unlock_irq(&np->lock);
+			if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+				return -EFAULT;
+			return 0;
+		}
+		/* set media settings */
+		case ETHTOOL_SSET: {
+			int r;
+			struct ethtool_cmd ecmd;
+			if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+				return -EFAULT;
+			spin_lock_irq(&np->lock);
+			r = mii_ethtool_sset(&np->mii_if, &ecmd);
+			spin_unlock_irq(&np->lock);
+			return r;
+		}
+
+		/* restart autonegotiation */
+		case ETHTOOL_NWAY_RST: {
+			return mii_nway_restart(&np->mii_if);
+		}
+
+		/* get link status */
+		case ETHTOOL_GLINK: {
+			struct ethtool_value edata = {ETHTOOL_GLINK};
+			edata.data = mii_link_ok(&np->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 = np->msg_enable;
+			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;
+			np->msg_enable = edata.data;
+			return 0;
+		}
+
+		default:
+		return -EOPNOTSUPP;
 
         }
-	
-	return -EOPNOTSUPP;
 }
 
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
@@ -1373,7 +1564,7 @@
 
 	netif_stop_queue(dev);
 
-	if (debug > 1) {
+	if (netif_msg_ifdown(np)) {
 		printk(KERN_DEBUG "%s: Shutting down ethercard, status was Tx %2.2x "
 			   "Rx %4.4x Int %2.2x.\n",
 			   dev->name, readb(ioaddr + TxStatus),
@@ -1389,7 +1580,7 @@
 	writew(TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl1);
 
 #ifdef __i386__
-	if (debug > 2) {
+	if (netif_msg_hw(np)) {
 		printk("\n"KERN_DEBUG"  Tx ring at %8.8x:\n",
 			   (int)(np->tx_ring_dma));
 		for (i = 0; i < TX_RING_SIZE; i++)
@@ -1416,8 +1607,8 @@
 		np->rx_ring[i].frag[0].addr = 0xBADF00D0; /* An invalid address. */
 		skb = np->rx_skbuff[i];
 		if (skb) {
-			pci_unmap_single(np->pci_dev, 
-				np->rx_ring[i].frag[0].addr, np->rx_buf_sz, 
+			pci_unmap_single(np->pci_dev,
+				np->rx_ring[i].frag[0].addr, np->rx_buf_sz,
 				PCI_DMA_FROMDEVICE);
 			dev_kfree_skb(skb);
 			np->rx_skbuff[i] = 0;
@@ -1426,7 +1617,7 @@
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		skb = np->tx_skbuff[i];
 		if (skb) {
-			pci_unmap_single(np->pci_dev, 
+			pci_unmap_single(np->pci_dev,
 				np->tx_ring[i].frag[0].addr, skb->len,
 				PCI_DMA_TODEVICE);
 			dev_kfree_skb(skb);
@@ -1440,15 +1631,15 @@
 static void __devexit sundance_remove1 (struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	
+
 	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
 	if (dev) {
 		struct netdev_private *np = dev->priv;
 
 		unregister_netdev(dev);
-        	pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, 
+        	pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring,
 			np->rx_ring_dma);
-	        pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring, 
+	        pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring,
 			np->tx_ring_dma);
 		pci_release_regions(pdev);
 #ifndef USE_IO_OPS
@@ -1460,10 +1651,10 @@
 }
 
 static struct pci_driver sundance_driver = {
-	.name		= DRV_NAME,
-	.id_table	= sundance_pci_tbl,
-	.probe		= sundance_probe1,
-	.remove		= __devexit_p(sundance_remove1),
+	name:		DRV_NAME,
+	id_table:	sundance_pci_tbl,
+	probe:		sundance_probe1,
+	remove:		__devexit_p(sundance_remove1),
 };
 
 static int __init sundance_init(void)
@@ -1482,3 +1673,5 @@
 
 module_init(sundance_init);
 module_exit(sundance_exit);
+
+
diff -Nru a/drivers/net/tg3.c b/drivers/net/tg3.c
--- a/drivers/net/tg3.c	Fri Sep 20 08:20:46 2002
+++ b/drivers/net/tg3.c	Fri Sep 20 08:20:46 2002
@@ -23,6 +23,8 @@
 #include <linux/ethtool.h>
 #include <linux/mii.h>
 #include <linux/if_vlan.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -49,7 +51,9 @@
 #endif
 
 #ifdef NETIF_F_TSO
-/* XXX some bug in tso firmware hangs tx cpu, disabled until fixed */
+/* XXX Works but still disabled, decreases TCP performance to 7MB/sec even
+ * XXX over gigabit.
+ */
 #define TG3_DO_TSO	0
 #else
 #define TG3_DO_TSO	0
@@ -237,6 +241,39 @@
 	tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
 }
 
+static inline void tg3_mask_ints(struct tg3 *tp)
+{
+	tw32(TG3PCI_MISC_HOST_CTRL,
+	     (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT));
+}
+
+static inline void tg3_unmask_ints(struct tg3 *tp)
+{
+	tw32(TG3PCI_MISC_HOST_CTRL,
+	     (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));
+	if (tp->hw_status->status & SD_STATUS_UPDATED) {
+		tw32(GRC_LOCAL_CTRL,
+		     tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
+	}
+}
+
+static void tg3_switch_clocks(struct tg3 *tp)
+{
+	if (tr32(TG3PCI_CLOCK_CTRL) & CLOCK_CTRL_44MHZ_CORE) {
+		tw32(TG3PCI_CLOCK_CTRL,
+		     (CLOCK_CTRL_44MHZ_CORE | CLOCK_CTRL_ALTCLK));
+		tr32(TG3PCI_CLOCK_CTRL);
+		udelay(40);
+		tw32(TG3PCI_CLOCK_CTRL,
+		     (CLOCK_CTRL_ALTCLK));
+		tr32(TG3PCI_CLOCK_CTRL);
+		udelay(40);
+	}
+	tw32(TG3PCI_CLOCK_CTRL, 0);
+	tr32(TG3PCI_CLOCK_CTRL);
+	udelay(40);
+}
+
 #define PHY_BUSY_LOOPS	5000
 
 static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
@@ -443,10 +480,12 @@
 		tp->link_config.orig_autoneg = tp->link_config.autoneg;
 	}
 
-	tp->link_config.speed = SPEED_10;
-	tp->link_config.duplex = DUPLEX_HALF;
-	tp->link_config.autoneg = AUTONEG_ENABLE;
-	tg3_setup_phy(tp);
+	if (tp->phy_id != PHY_ID_SERDES) {
+		tp->link_config.speed = SPEED_10;
+		tp->link_config.duplex = DUPLEX_HALF;
+		tp->link_config.autoneg = AUTONEG_ENABLE;
+		tg3_setup_phy(tp);
+	}
 
 	tg3_halt(tp);
 
@@ -455,14 +494,19 @@
 	if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE) {
 		u32 mac_mode;
 
-		tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a);
-		udelay(40);
+		if (tp->phy_id != PHY_ID_SERDES) {
+			tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a);
+			udelay(40);
 
-		mac_mode = MAC_MODE_PORT_MODE_MII;
+			mac_mode = MAC_MODE_PORT_MODE_MII;
+
+			if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 ||
+			    !(tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB))
+				mac_mode |= MAC_MODE_LINK_POLARITY;
+		} else {
+			mac_mode = MAC_MODE_PORT_MODE_TBI;
+		}
 
-		if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 ||
-		    !(tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB))
-			mac_mode |= MAC_MODE_LINK_POLARITY;
 
 		if (((power_caps & PCI_PM_CAP_PME_D3cold) &&
 		     (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)))
@@ -470,7 +514,7 @@
 
 		tw32(MAC_MODE, mac_mode);
 		tr32(MAC_MODE);
-		udelay(40);
+		udelay(100);
 
 		tw32(MAC_RX_MODE, RX_MODE_ENABLE);
 		tr32(MAC_RX_MODE);
@@ -1033,16 +1077,15 @@
 		tp->mac_mode |= MAC_MODE_HALF_DUPLEX;
 
 	tp->mac_mode &= ~MAC_MODE_LINK_POLARITY;
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) {
-		if (current_link_up == 1)
-			tp->mac_mode |= MAC_MODE_LINK_POLARITY;
-		tw32(MAC_LED_CTRL, LED_CTRL_PHY_MODE_1);
-	} else {
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) {
 		if ((tp->led_mode == led_mode_link10) ||
 		    (current_link_up == 1 &&
 		     tp->link_config.active_speed == SPEED_10))
 			tp->mac_mode |= MAC_MODE_LINK_POLARITY;
+	} else {
+		if (current_link_up == 1)
+			tp->mac_mode |= MAC_MODE_LINK_POLARITY;
+		tw32(MAC_LED_CTRL, LED_CTRL_PHY_MODE_1);
 	}
 
 	/* ??? Without this setting Netgear GA302T PHY does not
@@ -2068,7 +2111,7 @@
 
 	if (done) {
 		netif_rx_complete(netdev);
-		tg3_enable_ints(tp);
+		tg3_unmask_ints(tp);
 	}
 
 	spin_unlock_irq(&tp->lock);
@@ -2095,11 +2138,10 @@
 		return;
 
 	if (netif_rx_schedule_prep(dev)) {
-		/* NOTE: This write is posted by the readback of
+		/* NOTE: These writes are posted by the readback of
 		 *       the mailbox register done by our caller.
 		 */
-		tw32(TG3PCI_MISC_HOST_CTRL,
-		     (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT));
+		tg3_mask_ints(tp);
 		__netif_rx_schedule(dev);
 	} else {
 		printk(KERN_ERR PFX "%s: Error, poll already scheduled\n",
@@ -2352,9 +2394,20 @@
 	if (skb->ip_summed == CHECKSUM_HW)
 		base_flags |= TXD_FLAG_TCPUDP_CSUM;
 #if TG3_DO_TSO != 0
-	if ((mss = skb_shinfo(skb)->tso_size) != 0)
+	if ((mss = skb_shinfo(skb)->tso_size) != 0) {
+		static int times = 0;
+
+		mss += ((skb->h.th->doff * 4) - 20);
 		base_flags |= (TXD_FLAG_CPU_PRE_DMA |
 			       TXD_FLAG_CPU_POST_DMA);
+
+		if (times++ < 5) {
+			printk("tg3_xmit: tso_size[%u] tso_segs[%u] len[%u]\n",
+			       (unsigned int) skb_shinfo(skb)->tso_size,
+			       (unsigned int) skb_shinfo(skb)->tso_segs,
+			       skb->len);
+		}
+	}
 #else
 	mss = 0;
 #endif
@@ -2405,7 +2458,7 @@
 			}
 
 			tg3_set_txd(tp, entry, mapping, len,
-				    base_flags, (i == last) | (mss << 1));
+				    base_flags, (i == last));
 
 			entry = NEXT_TX(entry);
 		}
@@ -2517,9 +2570,24 @@
 	if (skb->ip_summed == CHECKSUM_HW)
 		base_flags |= TXD_FLAG_TCPUDP_CSUM;
 #if TG3_DO_TSO != 0
-	if ((mss = skb_shinfo(skb)->tso_size) != 0)
+	if ((mss = skb_shinfo(skb)->tso_size) != 0) {
+		static int times = 0;
+
+		/* TSO firmware wants TCP options included in
+		 * tx descriptor MSS value.
+		 */
+		mss += ((skb->h.th->doff * 4) - 20);
+
 		base_flags |= (TXD_FLAG_CPU_PRE_DMA |
 			       TXD_FLAG_CPU_POST_DMA);
+
+		if (times++ < 5) {
+			printk("tg3_xmit: tso_size[%u] tso_segs[%u] len[%u]\n",
+			       (unsigned int) skb_shinfo(skb)->tso_size,
+			       (unsigned int) skb_shinfo(skb)->tso_segs,
+			       skb->len);
+		}
+	}
 #else
 	mss = 0;
 #endif
@@ -2559,7 +2627,7 @@
 			pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping);
 
 			tg3_set_txd(tp, entry, mapping, len,
-				    base_flags, (i == last) | (mss << 1));
+				    base_flags, (i == last));
 
 			entry = NEXT_TX(entry);
 		}
@@ -4291,9 +4359,11 @@
 	}
 
 #if TG3_DO_TSO != 0
-	err = tg3_load_tso_firmware(tp);
-	if (err)
-		return err;
+	if (tp->dev->features & NETIF_F_TSO) {
+		err = tg3_load_tso_firmware(tp);
+		if (err)
+			return err;
+	}
 #endif
 
 	tp->tx_mode = TX_MODE_ENABLE;
@@ -4385,6 +4455,8 @@
 	if (err)
 		goto out;
 
+	tg3_switch_clocks(tp);
+
 	tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0);
 
 	err = tg3_reset_hw(tp);
@@ -5259,6 +5331,11 @@
 			return -EFAULT;
 		if (wol.wolopts & ~WAKE_MAGIC)
 			return -EINVAL;
+		if ((wol.wolopts & WAKE_MAGIC) &&
+		    tp->phy_id == PHY_ID_SERDES &&
+		    !(tp->tg3_flags & TG3_FLAG_SERDES_WOL_CAP))
+			return -EINVAL;
+
 		spin_lock_irq(&tp->lock);
 		if (wol.wolopts & WAKE_MAGIC)
 			tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
@@ -5793,6 +5870,8 @@
 
 		if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE)
 			tp->tg3_flags |= TG3_FLAG_ENABLE_ASF;
+		if (nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL)
+			tp->tg3_flags |= TG3_FLAG_SERDES_WOL_CAP;
 	}
 
 	/* Now read the physical PHY_ID from the chip and verify
@@ -6131,8 +6210,9 @@
 	/* Initialize data/descriptor byte/word swapping. */
 	tw32(GRC_MODE, tp->grc_mode);
 
-	/* Clear these out for sanity. */
-	tw32(TG3PCI_CLOCK_CTRL, 0);
+	tg3_switch_clocks(tp);
+
+	/* Clear this out for sanity. */
 	tw32(TG3PCI_MEM_WIN_BASE_ADDR, 0);
 
 	pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE,
@@ -6704,9 +6784,6 @@
 	dev->vlan_rx_register = tg3_vlan_rx_register;
 	dev->vlan_rx_kill_vid = tg3_vlan_rx_kill_vid;
 #endif
-#if TG3_DO_TSO != 0
-	dev->features |= NETIF_F_TSO;
-#endif
 
 	tp = dev->priv;
 	tp->pdev = pdev;
@@ -6806,6 +6883,17 @@
 		tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
 	} else
 		tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS;
+
+#if TG3_DO_TSO != 0
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
+	     tp->pci_chip_rev_id <= CHIPREV_ID_5701_B2)) {
+		/* Not TSO capable. */
+		dev->features &= ~NETIF_F_TSO;
+	} else {
+		dev->features |= NETIF_F_TSO;
+	}
+#endif
 
 	err = register_netdev(dev);
 	if (err) {
diff -Nru a/drivers/net/tg3.h b/drivers/net/tg3.h
--- a/drivers/net/tg3.h	Fri Sep 20 08:20:43 2002
+++ b/drivers/net/tg3.h	Fri Sep 20 08:20:43 2002
@@ -1274,6 +1274,7 @@
 #define  NIC_SRAM_DATA_CFG_WOL_ENABLE		 0x00000040
 #define  NIC_SRAM_DATA_CFG_ASF_ENABLE		 0x00000080
 #define  NIC_SRAM_DATA_CFG_EEPROM_WP		 0x00000100
+#define  NIC_SRAM_DATA_CFG_FIBER_WOL		 0x00004000
 
 #define NIC_SRAM_DATA_PHY_ID		0x00000b74
 #define  NIC_SRAM_DATA_PHY_ID1_MASK	 0xffff0000
@@ -1311,7 +1312,7 @@
 #define NIC_SRAM_RX_JUMBO_BUFFER_DESC	0x00007000 /* 256 entries */
 #define NIC_SRAM_MBUF_POOL_BASE		0x00008000
 #define  NIC_SRAM_MBUF_POOL_SIZE96	 0x00018000
-#define  NIC_SRAM_MBUF_POOL_SIZE64	 0x00018000
+#define  NIC_SRAM_MBUF_POOL_SIZE64	 0x00010000
 
 /* Currently this is fixed. */
 #define PHY_ADDR		0x01
@@ -1779,7 +1780,7 @@
 #define TG3_FLAG_PCI_32BIT		0x00080000
 #define TG3_FLAG_NO_TX_PSEUDO_CSUM	0x00100000
 #define TG3_FLAG_NO_RX_PSEUDO_CSUM	0x00200000
-#define TG3_FLAG_AUTONEG_DISABLE	0x00400000
+#define TG3_FLAG_SERDES_WOL_CAP		0x00400000
 #define TG3_FLAG_JUMBO_ENABLE		0x00800000
 #define TG3_FLAG_10_100_ONLY		0x01000000
 #define TG3_FLAG_PAUSE_AUTONEG		0x02000000
diff -Nru a/drivers/net/tulip/ChangeLog b/drivers/net/tulip/ChangeLog
--- a/drivers/net/tulip/ChangeLog	Fri Sep 20 08:20:43 2002
+++ b/drivers/net/tulip/ChangeLog	Fri Sep 20 08:20:43 2002
@@ -1,3 +1,14 @@
+2002-09-18  Ryan Bradetich  <rbradetich@uswest.net>
+
+	tulip hppa support:
+	* eeprom.c (tulip_build_fake_mediatable): new function
+	(tulip_parse_eeprom): call it, when no media table
+	* interrupt.c (phy_interrupt): new function
+	(tulip_interrupt): call it, before checking for no-irq-work
+	* tulip.c: add HAS_PHY_IRQ chip feature flag.
+	add csr12_shadow to tulip_private struct, only for hppa currently.
+	* tulip_core (tulip_init_one): support hppa wonky eeproms
+
 2002-05-11  Juan Quintela  <quintela@mandrakesoft.com>
 
 	* 21142.c (t21142_lnk_change): Revert earlier patch
diff -Nru a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c
--- a/drivers/net/tulip/eeprom.c	Fri Sep 20 08:20:48 2002
+++ b/drivers/net/tulip/eeprom.c	Fri Sep 20 08:20:48 2002
@@ -75,6 +75,61 @@
 };
 
 
+/**
+ * tulip_build_fake_mediatable - Build a fake mediatable entry.
+ * @tp: Ptr to the tulip private data.
+ *
+ * Some cards like the 3x5 HSC cards (J3514A) do not have a standard 
+ * srom and can not be handled under the fixup routine.  These cards
+ * still need a valid mediatable entry for correct csr12 setup and 
+ * mii handling.
+ * 
+ * Since this is currently a parisc-linux specific function, the
+ * #ifdef __hppa__ should completely optimize this function away for
+ * non-parisc hardware.
+ */
+static void __devinit tulip_build_fake_mediatable(struct tulip_private *tp)
+{
+#ifdef __hppa__
+	unsigned char *ee_data = tp->eeprom;
+
+	if (ee_data[0] == 0x3c && ee_data[1] == 0x10 && 
+		(ee_data[2] == 0x63 || ee_data[2] == 0x61) && ee_data[3] == 0x10) {
+
+		static unsigned char leafdata[] =
+			{ 0x01,       /* phy number */
+			  0x02,       /* gpr setup sequence length */
+			  0x02, 0x00, /* gpr setup sequence */
+			  0x02,       /* phy reset sequence length */
+			  0x01, 0x00, /* phy reset sequence */
+			  0x00, 0x78, /* media capabilities */
+			  0x00, 0xe0, /* nway advertisment */
+			  0x00, 0x05, /* fdx bit map */
+			  0x00, 0x06  /* ttm bit map */
+			};
+
+		tp->mtable = (struct mediatable *)
+			kmalloc(sizeof(struct mediatable) + sizeof(struct medialeaf), GFP_KERNEL);
+
+		if (tp->mtable == NULL)
+			return; /* Horrible, impossible failure. */
+
+		tp->mtable->defaultmedia = 0x800;
+		tp->mtable->leafcount = 1;
+		tp->mtable->csr12dir = 0x3f; /* inputs on bit7 for hsc-pci, bit6 for pci-fx */
+		tp->mtable->has_nonmii = 0;
+		tp->mtable->has_reset = 0;
+		tp->mtable->has_mii = 1;
+		tp->mtable->csr15dir = tp->mtable->csr15val = 0;
+		tp->mtable->mleaf[0].type = 1;
+		tp->mtable->mleaf[0].media = 11;
+		tp->mtable->mleaf[0].leafdata = &leafdata[0];
+		tp->flags |= HAS_PHY_IRQ;
+		tp->csr12_shadow = -1;
+	}
+#endif 
+}
+
 void __devinit tulip_parse_eeprom(struct net_device *dev)
 {
 	/* The last media info list parsed, for multiport boards.  */
@@ -136,6 +191,7 @@
 subsequent_board:
 
 	if (ee_data[27] == 0) {		/* No valid media table. */
+		tulip_build_fake_mediatable(tp);
 	} else {
 		unsigned char *p = (void *)ee_data + ee_data[27];
 		unsigned char csr12dir = 0;
diff -Nru a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
--- a/drivers/net/tulip/interrupt.c	Fri Sep 20 08:20:43 2002
+++ b/drivers/net/tulip/interrupt.c	Fri Sep 20 08:20:43 2002
@@ -291,6 +291,25 @@
 #endif
 }
 
+static inline void phy_interrupt (struct net_device *dev)
+{
+#ifdef __hppa__
+	int csr12 = inl(dev->base_addr + CSR12) & 0xff;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+
+	if (csr12 != tp->csr12_shadow) {
+		/* ack interrupt */
+		outl(csr12 | 0x02, dev->base_addr + CSR12);
+		tp->csr12_shadow = csr12;
+		/* do link change stuff */
+		spin_lock(&tp->lock);
+		tulip_check_duplex(dev);
+		spin_unlock(&tp->lock);
+		/* clear irq ack bit */
+		outl(csr12 & ~0x02, dev->base_addr + CSR12);
+	}
+#endif
+}
 
 /* The interrupt handler does all of the Rx thread work and cleans up
    after the Tx thread. */
@@ -313,6 +332,9 @@
 	/* Let's see whether the interrupt really is for us */
 	csr5 = inl(ioaddr + CSR5);
 
+        if (tp->flags & HAS_PHY_IRQ)
+	        phy_interrupt (dev);
+    
 	if ((csr5 & (NormalIntr|AbnormalIntr)) == 0)
 		return;
 
diff -Nru a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
--- a/drivers/net/tulip/tulip.h	Fri Sep 20 08:20:48 2002
+++ b/drivers/net/tulip/tulip.h	Fri Sep 20 08:20:48 2002
@@ -63,6 +63,7 @@
 	HAS_8023X		= 0x0400,
 	COMET_MAC_ADDR		= 0x0800,
 	HAS_PCI_MWI		= 0x1000,
+	HAS_PHY_IRQ		= 0x2000,
 };
 
 
@@ -388,7 +389,8 @@
 	int susp_rx;
 	unsigned long nir;
 	unsigned long base_addr;
-	int pad0, pad1;		/* Used for 8-byte alignment */
+	int csr12_shadow;
+	int pad0;		/* Used for 8-byte alignment */
 };
 
 
diff -Nru a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
--- a/drivers/net/tulip/tulip_core.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/net/tulip/tulip_core.c	Fri Sep 20 08:20:47 2002
@@ -1490,6 +1490,25 @@
                        tp->flags &= ~HAS_MEDIA_TABLE;
                }
 #endif
+#ifdef __hppa__
+		/* 3x5 HSC (J3514A) has a broken srom */
+		if(ee_data[0] == 0x61 && ee_data[1] == 0x10) {
+			/* pci_vendor_id and subsystem_id are swapped */
+			ee_data[0] = ee_data[2];
+			ee_data[1] = ee_data[3];
+			ee_data[2] = 0x61;
+			ee_data[3] = 0x10;
+
+			/* srom need to be byte-swaped and shifted up 1 word.  
+			 * This shift needs to happen at the end of the MAC
+			 * first because of the 2 byte overlap.
+			 */
+			for(i = 4; i >= 0; i -= 2) {
+				ee_data[17 + i + 3] = ee_data[17 + i];
+				ee_data[16 + i + 5] = ee_data[16 + i];
+			}
+		}
+#endif
 		for (i = 0; i < 6; i ++) {
 			dev->dev_addr[i] = ee_data[i + sa_offset];
 			sum += ee_data[i + sa_offset];
diff -Nru a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
--- a/drivers/net/tulip/winbond-840.c	Fri Sep 20 08:20:43 2002
+++ b/drivers/net/tulip/winbond-840.c	Fri Sep 20 08:20:43 2002
@@ -1136,13 +1136,7 @@
 			if (tx_status & 0x0002) np->stats.tx_fifo_errors++;
 			if ((tx_status & 0x0080) && np->mii_if.full_duplex == 0)
 				np->stats.tx_heartbeat_errors++;
-#ifdef ETHER_STATS
-			if (tx_status & 0x0100) np->stats.collisions16++;
-#endif
 		} else {
-#ifdef ETHER_STATS
-			if (tx_status & 0x0001) np->stats.tx_deferred++;
-#endif
 #ifndef final_version
 			if (debug > 3)
 				printk(KERN_DEBUG "%s: Transmit slot %d ok, Tx status %8.8x.\n",
diff -Nru a/drivers/net/tulip/xircom_tulip_cb.c b/drivers/net/tulip/xircom_tulip_cb.c
--- a/drivers/net/tulip/xircom_tulip_cb.c	Fri Sep 20 08:20:42 2002
+++ b/drivers/net/tulip/xircom_tulip_cb.c	Fri Sep 20 08:20:43 2002
@@ -1105,9 +1105,6 @@
 					tp->stats.tx_errors++;
 					if (status & Tx0ManyColl) {
 						tp->stats.tx_aborted_errors++;
-#ifdef ETHER_STATS
-						tp->stats.collisions16++;
-#endif
 					}
 					if (status & Tx0NoCarrier) tp->stats.tx_carrier_errors++;
 					if (status & Tx0LateColl) tp->stats.tx_window_errors++;
diff -Nru a/drivers/net/tun.c b/drivers/net/tun.c
--- a/drivers/net/tun.c	Fri Sep 20 08:20:46 2002
+++ b/drivers/net/tun.c	Fri Sep 20 08:20:46 2002
@@ -275,7 +275,7 @@
 		total += sizeof(pi);
 	}       
 
-	len = min(skb->len, len);
+	len = min_t(int, skb->len, len);
 
 	skb_copy_datagram_iovec(skb, 0, iv, len);
 	total += len;
@@ -306,6 +306,8 @@
 			return -EFAULT;
 		len += iv[i].iov_len;
 	}
+	if (len < 0)
+		return -EINVAL;
 
 	add_wait_queue(&tun->read_wait, &wait);
 	while (len) {
diff -Nru a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c
--- a/drivers/net/wan/c101.c	Fri Sep 20 08:20:43 2002
+++ b/drivers/net/wan/c101.c	Fri Sep 20 08:20:43 2002
@@ -1,7 +1,7 @@
 /*
  * Moxa C101 synchronous serial card driver for Linux
  *
- * Copyright (C) 2000-2001 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 2000-2002 Krzysztof Halasa <khc@pm.waw.pl>
  *
  * 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
@@ -31,7 +31,7 @@
 #include "hd64570.h"
 
 
-static const char* version = "Moxa C101 driver version: 1.09";
+static const char* version = "Moxa C101 driver version: 1.10";
 static const char* devname = "C101";
 
 #define C101_PAGE 0x1D00
@@ -107,18 +107,13 @@
 #include "hd6457x.c"
 
 
-static int c101_set_iface(port_t *port)
+static void c101_set_iface(port_t *port)
 {
 	u8 msci = get_msci(port);
 	u8 rxs = port->rxs & CLK_BRG_MASK;
 	u8 txs = port->txs & CLK_BRG_MASK;
 
 	switch(port->settings.clock_type) {
-	case CLOCK_EXT:
-		rxs |= CLK_LINE_RX; /* RXC input */
-		txs |= CLK_LINE_TX; /* TXC input */
-		break;
-
 	case CLOCK_INT:
 		rxs |= CLK_BRG_RX; /* TX clock */
 		txs |= CLK_RXCLK_TX; /* BRG output */
@@ -134,8 +129,9 @@
 		txs |= CLK_RXCLK_TX; /* RX clock */
 		break;
 
-	default:
-		return -EINVAL;
+	default:	/* EXTernal clock */
+		rxs |= CLK_LINE_RX; /* RXC input */
+		txs |= CLK_LINE_TX; /* TXC input */
 	}
 
 	port->rxs = rxs;
@@ -143,7 +139,6 @@
 	sca_out(rxs, msci + RXS, port);
 	sca_out(txs, msci + TXS, port);
 	sca_set_port(port);
-	return 0;
 }
 
 
@@ -159,7 +154,8 @@
 	writeb(1, port->win0base + C101_DTR);
 	sca_out(0, MSCI1_OFFSET + CTL, port); /* RTS uses ch#2 output */
 	sca_open(hdlc);
-	return c101_set_iface(port);
+	c101_set_iface(port);
+	return 0;
 }
 
 
@@ -181,6 +177,7 @@
 {
 	union line_settings *line = &ifr->ifr_settings->ifs_line;
 	const size_t size = sizeof(sync_serial_settings);
+	sync_serial_settings new_line;
 	hdlc_device *hdlc = dev_to_hdlc(dev);
 	port_t *port = hdlc_to_port(hdlc);
 
@@ -204,10 +201,21 @@
 		if(!capable(CAP_NET_ADMIN))
 			return -EPERM;
 
-		if (copy_from_user(&port->settings, &line->sync, size))
+		if (copy_from_user(&new_line, &line->sync, size))
 			return -EFAULT;
-		/* FIXME - put sanity checks here */
-		return c101_set_iface(port);
+
+		if (new_line.clock_type != CLOCK_EXT &&
+		    new_line.clock_type != CLOCK_TXFROMRX &&
+		    new_line.clock_type != CLOCK_INT &&
+		    new_line.clock_type != CLOCK_TXINT)
+		return -EINVAL;	/* No such clock setting */
+
+		if (new_line.loopback != 0 && new_line.loopback != 1)
+			return -EINVAL;
+
+		memcpy(&port->settings, &new_line, size); /* Update settings */
+		c101_set_iface(port);
+		return 0;
 
 	default:
 		return hdlc_ioctl(dev, ifr, cmd);
diff -Nru a/drivers/net/wan/comx-hw-munich.c b/drivers/net/wan/comx-hw-munich.c
--- a/drivers/net/wan/comx-hw-munich.c	Fri Sep 20 08:20:43 2002
+++ b/drivers/net/wan/comx-hw-munich.c	Fri Sep 20 08:20:43 2002
@@ -55,11 +55,9 @@
 #include "falc-lh.h"
 #endif
 
-MODULE_AUTHOR
-    ("Bartok Istvan <bartoki@itc.hu>, Gergely Madarasz <gorgo@itc.hu>, Szilard Pasztor <don@itc.hu>");
-MODULE_DESCRIPTION
-    ("Hardware-level driver for the SliceCOM and PciCOM (WelCOM) adapters");
-
+MODULE_AUTHOR("Bartok Istvan <bartoki@itc.hu>, Gergely Madarasz <gorgo@itc.hu>, Szilard Pasztor <don@itc.hu>");
+MODULE_DESCRIPTION("Hardware-level driver for the SliceCOM and PciCOM (WelCOM) adapters");
+MODULE_LICENSE("GPL");
 /*
  *	TODO: az ilyenek a comxhw.h -ban szoktak lenni, idovel menjenek majd oda:
  */
@@ -1253,8 +1251,6 @@
 	/* jon interrupt, de nincs mit feldolgozni, akkor torlom a STAT-ot.     */
 	/* 'needs a rewrite', de elso megoldasnak jo lesz                       */
 //              {
-
-udelay(10000);
 	int_info = board->tiq[board->tiq_ptr];
 	if (int_info.all & 0xF0000000)	/* ha ez nem 0, akkor itt interrupt_info van    */
 	{
@@ -2779,8 +2775,6 @@
 static int BOARD_exit(struct net_device *dev)
 {
     struct comx_channel *ch = (struct comx_channel *)dev->priv;
-    struct slicecom_privdata *hw = ch->HW_privdata;
-//    munich_board_t *board;
 
     /* Free private data area */
 //    board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards);
diff -Nru a/drivers/net/wan/hd6457x.c b/drivers/net/wan/hd6457x.c
--- a/drivers/net/wan/hd6457x.c	Fri Sep 20 08:20:43 2002
+++ b/drivers/net/wan/hd6457x.c	Fri Sep 20 08:20:43 2002
@@ -291,9 +291,9 @@
 #endif
 	port->hdlc.stats.rx_packets++;
 	port->hdlc.stats.rx_bytes += skb->len;
-	skb->dev->last_rx = jiffies;
 	skb->mac.raw = skb->data;
 	skb->dev = hdlc_to_dev(&port->hdlc);
+	skb->dev->last_rx = jiffies;
 	skb->protocol = htons(ETH_P_HDLC);
 	netif_rx(skb);
 }
diff -Nru a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c
--- a/drivers/net/wan/hdlc_cisco.c	Fri Sep 20 08:20:44 2002
+++ b/drivers/net/wan/hdlc_cisco.c	Fri Sep 20 08:20:44 2002
@@ -249,6 +249,7 @@
 {
 	cisco_proto *cisco_s = &ifr->ifr_settings->ifs_hdlc.cisco;
 	const size_t size = sizeof(cisco_proto);
+	cisco_proto new_settings;
 	struct net_device *dev = hdlc_to_dev(hdlc);
 	int result;
 
@@ -266,17 +267,20 @@
 		if(dev->flags & IFF_UP)
 			return -EBUSY;
 
-		if (copy_from_user(&hdlc->state.cisco.settings, cisco_s, size))
+		if (copy_from_user(&new_settings, cisco_s, size))
 			return -EFAULT;
 
-		/* FIXME - put sanity checks here */
-		hdlc_detach(hdlc);
+		if (new_settings.interval < 1 ||
+		    new_settings.timeout < 2)
+			return -EINVAL;
 
 		result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
-		if (result) {
-			hdlc->proto = -1;
+
+		if (result)
 			return result;
-		}
+
+		hdlc_proto_detach(hdlc);
+		memcpy(&hdlc->state.cisco.settings, &new_settings, size);
 
 		hdlc->open = cisco_open;
 		hdlc->stop = cisco_close;
diff -Nru a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
--- a/drivers/net/wan/hdlc_fr.c	Fri Sep 20 08:20:44 2002
+++ b/drivers/net/wan/hdlc_fr.c	Fri Sep 20 08:20:44 2002
@@ -602,13 +602,15 @@
 	}
 
 	if (data[3] == FR_PAD && data[4] == NLPID_SNAP && data[5] == FR_PAD) {
-		u16 oui = ntohl(*(u16*)(data + 6));
-		u16 pid = ntohl(*(u16*)(data + 8));
+		u16 oui = ntohs(*(u16*)(data + 6));
+		u16 pid = ntohs(*(u16*)(data + 8));
 		skb_pull(skb, 10);
 
 		switch ((((u32)oui) << 16) | pid) {
 		case ETH_P_ARP: /* routed frame with SNAP */
 		case ETH_P_IPX:
+		case ETH_P_IP:	/* a long variant */
+		case ETH_P_IPV6:
 			skb->protocol = htons(pid);
 			break;
 
@@ -762,7 +764,7 @@
 	pvc_device *pvc = hdlc->state.fr.first_pvc;
 	while(pvc) {
 		pvc_device *next = pvc->next;
-		unregister_netdevice(&pvc->netdev);
+		unregister_netdev(&pvc->netdev);
 		kfree(pvc);
 		pvc = next;
 	}
@@ -778,6 +780,7 @@
 {
 	fr_proto *fr_s = &ifr->ifr_settings->ifs_hdlc.fr;
 	const size_t size = sizeof(fr_proto);
+	fr_proto new_settings;
 	struct net_device *dev = hdlc_to_dev(hdlc);
 	fr_proto_pvc pvc;
 	int result;
@@ -796,26 +799,40 @@
 		if(dev->flags & IFF_UP)
 			return -EBUSY;
 
-		if (copy_from_user(&hdlc->state.fr.settings, fr_s, size))
+		if (copy_from_user(&new_settings, fr_s, size))
 			return -EFAULT;
 
-		/* FIXME - put sanity checks here */
-		if (hdlc->proto != IF_PROTO_FR) {
-			hdlc_detach(hdlc);
-			hdlc->state.fr.first_pvc = NULL;
-			hdlc->state.fr.pvc_count = 0;
-		}
+		if (new_settings.lmi == LMI_DEFAULT)
+			new_settings.lmi = LMI_ANSI;
+
+		if ((new_settings.lmi != LMI_NONE &&
+		     new_settings.lmi != LMI_ANSI &&
+		     new_settings.lmi != LMI_CCITT) ||
+		    new_settings.t391 < 1 ||
+		    new_settings.t392 < 2 ||
+		    new_settings.n391 < 1 ||
+		    new_settings.n392 < 1 ||
+		    new_settings.n393 < new_settings.n392 ||
+		    new_settings.n393 > 32 ||
+		    (new_settings.dce != 0 &&
+		     new_settings.dce != 1))
+			return -EINVAL;
 
 		result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
-		if (result) {
-			hdlc->proto = -1;
+		if (result)
 			return result;
+
+		if (hdlc->proto != IF_PROTO_FR) {
+			hdlc_proto_detach(hdlc);
+			hdlc->state.fr.first_pvc = NULL;
+			hdlc->state.fr.pvc_count = 0;
 		}
+		memcpy(&hdlc->state.fr.settings, &new_settings, size);
 
 		hdlc->open = fr_open;
 		hdlc->stop = fr_close;
 		hdlc->netif_rx = fr_rx;
-		hdlc->detach = fr_destroy;
+		hdlc->proto_detach = fr_destroy;
 		hdlc->proto = IF_PROTO_FR;
 		dev->hard_start_xmit = hdlc->xmit;
 		dev->hard_header = fr_hard_header;
diff -Nru a/drivers/net/wan/hdlc_generic.c b/drivers/net/wan/hdlc_generic.c
--- a/drivers/net/wan/hdlc_generic.c	Fri Sep 20 08:20:42 2002
+++ b/drivers/net/wan/hdlc_generic.c	Fri Sep 20 08:20:42 2002
@@ -38,7 +38,7 @@
 #include <linux/hdlc.h>
 
 
-static const char* version = "HDLC support module revision 1.08";
+static const char* version = "HDLC support module revision 1.10";
 
 
 static int hdlc_change_mtu(struct net_device *dev, int new_mtu)
@@ -66,6 +66,26 @@
 }
 
 
+#ifndef CONFIG_HDLC_RAW
+#define hdlc_raw_ioctl(hdlc, ifr)	-ENOSYS
+#endif
+
+#ifndef CONFIG_HDLC_PPP
+#define hdlc_ppp_ioctl(hdlc, ifr)	-ENOSYS
+#endif
+
+#ifndef CONFIG_HDLC_CISCO
+#define hdlc_cisco_ioctl(hdlc, ifr)	-ENOSYS
+#endif
+
+#ifndef CONFIG_HDLC_FR
+#define hdlc_fr_ioctl(hdlc, ifr)	-ENOSYS
+#endif
+
+#ifndef CONFIG_HDLC_X25
+#define hdlc_x25_ioctl(hdlc, ifr)	-ENOSYS
+#endif
+
 
 int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
@@ -89,22 +109,12 @@
 	}
 
 	switch(proto) {
-#ifdef CONFIG_HDLC_RAW
 	case IF_PROTO_HDLC:	return hdlc_raw_ioctl(hdlc, ifr);
-#endif
-#ifdef CONFIG_HDLC_PPP
 	case IF_PROTO_PPP:	return hdlc_ppp_ioctl(hdlc, ifr);
-#endif
-#ifdef CONFIG_HDLC_CISCO
 	case IF_PROTO_CISCO:	return hdlc_cisco_ioctl(hdlc, ifr);
-#endif
-#ifdef CONFIG_HDLC_FR
 	case IF_PROTO_FR:	return hdlc_fr_ioctl(hdlc, ifr);
-#endif
-#ifdef CONFIG_HDLC_X25
 	case IF_PROTO_X25:	return hdlc_x25_ioctl(hdlc, ifr);
-#endif
-	default:		return -ENOSYS;
+	default:		return -EINVAL;
 	}
 }
 
@@ -125,7 +135,7 @@
 	dev->flags = IFF_POINTOPOINT | IFF_NOARP;
 
 	hdlc->proto = -1;
-	hdlc->detach = NULL;
+	hdlc->proto_detach = NULL;
 
 	result = dev_alloc_name(dev, "hdlc%d");
 	if (result<0)
@@ -143,7 +153,7 @@
 
 void unregister_hdlc_device(hdlc_device *hdlc)
 {
-	hdlc_detach(hdlc);
+	hdlc_proto_detach(hdlc);
 
 	unregister_netdev(hdlc_to_dev(hdlc));
 	MOD_DEC_USE_COUNT;
diff -Nru a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c
--- a/drivers/net/wan/hdlc_ppp.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/net/wan/hdlc_ppp.c	Fri Sep 20 08:20:41 2002
@@ -96,13 +96,11 @@
 
 		/* no settable parameters */
 
-		hdlc_detach(hdlc);
-
 		result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
-		if (result) {
-			hdlc->proto = -1;
+		if (result)
 			return result;
-		}
+
+		hdlc_proto_detach(hdlc);
 
 		hdlc->open = ppp_open;
 		hdlc->stop = ppp_close;
diff -Nru a/drivers/net/wan/hdlc_raw.c b/drivers/net/wan/hdlc_raw.c
--- a/drivers/net/wan/hdlc_raw.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/net/wan/hdlc_raw.c	Fri Sep 20 08:20:47 2002
@@ -39,35 +39,40 @@
 {
 	raw_hdlc_proto *raw_s = &ifr->ifr_settings->ifs_hdlc.raw_hdlc;
 	const size_t size = sizeof(raw_hdlc_proto);
+	raw_hdlc_proto new_settings;
 	struct net_device *dev = hdlc_to_dev(hdlc);
 	int result;
 
 	switch (ifr->ifr_settings->type) {
 	case IF_GET_PROTO:
+		ifr->ifr_settings->type = IF_PROTO_HDLC;
 		if (copy_to_user(raw_s, &hdlc->state.raw_hdlc.settings, size))
 			return -EFAULT;
 		return 0;
 
 	case IF_PROTO_HDLC:
-		if(!capable(CAP_NET_ADMIN))
+		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 
-		if(dev->flags & IFF_UP)
+		if (dev->flags & IFF_UP)
 			return -EBUSY;
 
-		if (copy_from_user(&hdlc->state.raw_hdlc.settings, raw_s, size))
+		if (copy_from_user(&new_settings, raw_s, size))
 			return -EFAULT;
 
+		if (new_settings.encoding == ENCODING_DEFAULT)
+			new_settings.encoding = ENCODING_NRZ;
 
-		/* FIXME - put sanity checks here */
-		hdlc_detach(hdlc);
+		if (new_settings.parity == PARITY_DEFAULT)
+			new_settings.parity = PARITY_NONE;
 
-		result=hdlc->attach(hdlc, hdlc->state.raw_hdlc.settings.encoding,
-				    hdlc->state.raw_hdlc.settings.parity);
-		if (result) {
-			hdlc->proto = -1;
+		result = hdlc->attach(hdlc, new_settings.encoding,
+				      new_settings.parity);
+		if (result)
 			return result;
-		}
+
+		hdlc_proto_detach(hdlc);
+		memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size);
 
 		hdlc->open = NULL;
 		hdlc->stop = NULL;
diff -Nru a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c
--- a/drivers/net/wan/hdlc_x25.c	Fri Sep 20 08:20:48 2002
+++ b/drivers/net/wan/hdlc_x25.c	Fri Sep 20 08:20:48 2002
@@ -196,13 +196,11 @@
 		if(dev->flags & IFF_UP)
 			return -EBUSY;
 
-		hdlc_detach(hdlc);
-
 		result=hdlc->attach(hdlc, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
-		if (result) {
-			hdlc->proto = -1;
+		if (result)
 			return result;
-		}
+
+		hdlc_proto_detach(hdlc);
 
 		hdlc->open = x25_open;
 		hdlc->stop = x25_close;
diff -Nru a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c
--- a/drivers/net/wan/n2.c	Fri Sep 20 08:20:43 2002
+++ b/drivers/net/wan/n2.c	Fri Sep 20 08:20:43 2002
@@ -1,7 +1,7 @@
 /*
  * SDL Inc. RISCom/N2 synchronous serial card driver for Linux
  *
- * Copyright (C) 1998-2001 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 1998-2002 Krzysztof Halasa <khc@pm.waw.pl>
  *
  * 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
@@ -35,7 +35,7 @@
 #include "hd64570.h"
 
 
-static const char* version = "SDL RISCom/N2 driver version: 1.09";
+static const char* version = "SDL RISCom/N2 driver version: 1.10";
 static const char* devname = "RISCom/N2";
 
 #define USE_WINDOWSIZE 16384
@@ -159,7 +159,7 @@
 
 
 
-static int n2_set_iface(port_t *port)
+static void n2_set_iface(port_t *port)
 {
 	card_t *card = port->card;
 	int io = card->io;
@@ -169,12 +169,6 @@
 	u8 txs = port->txs & CLK_BRG_MASK;
 
 	switch(port->settings.clock_type) {
-	case CLOCK_EXT:
-		mcr &= port->phy_node ? ~CLOCK_OUT_PORT1 : ~CLOCK_OUT_PORT0;
-		rxs |= CLK_LINE_RX; /* RXC input */
-		txs |= CLK_LINE_TX; /* TXC input */
-		break;
-
 	case CLOCK_INT:
 		mcr |= port->phy_node ? CLOCK_OUT_PORT1 : CLOCK_OUT_PORT0;
 		rxs |= CLK_BRG_RX; /* BRG output */
@@ -193,8 +187,10 @@
 		txs |= CLK_RXCLK_TX; /* RX clock */
 		break;
 
-	default:
-		return -EINVAL;
+	default:		/* Clock EXTernal */
+		mcr &= port->phy_node ? ~CLOCK_OUT_PORT1 : ~CLOCK_OUT_PORT0;
+		rxs |= CLK_LINE_RX; /* RXC input */
+		txs |= CLK_LINE_TX; /* TXC input */
 	}
 
 	outb(mcr, io + N2_MCR);
@@ -203,7 +199,6 @@
 	sca_out(rxs, msci + RXS, card);
 	sca_out(txs, msci + TXS, card);
 	sca_set_port(port);
-	return 0;
 }
 
 
@@ -226,7 +221,8 @@
 	outb(inb(io + N2_PCR) | PCR_ENWIN, io + N2_PCR); /* open window */
 	outb(inb(io + N2_PSR) | PSR_DMAEN, io + N2_PSR); /* enable dma */
 	sca_open(hdlc);
-	return n2_set_iface(port);
+	n2_set_iface(port);
+	return 0;
 }
 
 
@@ -252,6 +248,7 @@
 {
 	union line_settings *line = &ifr->ifr_settings->ifs_line;
 	const size_t size = sizeof(sync_serial_settings);
+	sync_serial_settings new_line;
 	hdlc_device *hdlc = dev_to_hdlc(dev);
 	port_t *port = hdlc_to_port(hdlc);
 
@@ -275,10 +272,21 @@
 		if(!capable(CAP_NET_ADMIN))
 			return -EPERM;
 
-		if (copy_from_user(&port->settings, &line->sync, size))
+		if (copy_from_user(&new_line, &line->sync, size))
 			return -EFAULT;
-		/* FIXME - put sanity checks here */
-		return n2_set_iface(port);
+
+		if (new_line.clock_type != CLOCK_EXT &&
+		    new_line.clock_type != CLOCK_TXFROMRX &&
+		    new_line.clock_type != CLOCK_INT &&
+		    new_line.clock_type != CLOCK_TXINT)
+		return -EINVAL;	/* No such clock setting */
+
+		if (new_line.loopback != 0 && new_line.loopback != 1)
+			return -EINVAL;
+
+		memcpy(&port->settings, &new_line, size); /* Update settings */
+		n2_set_iface(port);
+		return 0;
 
 	default:
 		return hdlc_ioctl(dev, ifr, cmd);
diff -Nru a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
--- a/drivers/net/wireless/airo.c	Fri Sep 20 08:20:42 2002
+++ b/drivers/net/wireless/airo.c	Fri Sep 20 08:20:42 2002
@@ -273,26 +273,76 @@
 #define NO_PACKET -2
 
 /* Commands */
-#define NOP 0x0010
-#define MAC_ENABLE 0x0001
-#define MAC_DISABLE 0x0002
-#define CMD_LOSE_SYNC 0x0003 /* Not sure what this does... */
-#define CMD_MAGIC_PKT 0x0006
-#define CMD_ACCESS 0x0021
-#define CMD_ALLOCATETX 0x000a
-#define CMD_TRANSMIT 0x000b
-#define CMD_DEALLOCATETX 0x000c
-#define HOSTSLEEP 0x85
-#define CMD_SETMODE 0x0009
-#define CMD_ENABLEAUX 0x0111
-#define CMD_SOFTRESET 0x0004
-#define CMD_ALLOCBUF 0x0028
-#define CMD_PSPNODES 0x0030
-#define CMD_SETPHYREG 0x003e
-#define CMD_TXTEST 0x003f
-#define CMD_READCFG 0x0008
-#define CMD_SAVECFG 0x0108
-#define CMD_LISTBSS 0x0103
+#define NOP2 0x00    
+#define MAC_ENABLE 0x01
+#define MAC_ENABLETX 0x101
+#define CMD_ENABLEAUX 0x111
+#define MAC_ENABLERX 0x201   
+#define MAC_DISABLE 0x02    
+#define CMD_LOSE_SYNC 0x03    
+#define CMD_LOSE_SYNC_BSS 0x103
+#define CMD_SOFTRESET 0x04    
+#define HOSTSLEEP 0x05    
+#define CMD_MAGICPACKET 0x06
+#define CMD_SETWAKEMASK 0x07
+#define CMD_SAVECONFIG 0x108   
+#define CMD_READCONFIG 0x08
+#define CMD_SETMODE 0x09    
+#define CMD_ALLOCATETX 0x0A
+#define CMD_TRANSMIT 0x0B    
+#define CMD_DEALLOC 0x0C
+#define CMD_LISTBSS 0x103
+#define NOP 0x10    
+#define CMD_WORKAROUND 0x11
+#define CMD_ACCESS 0x21
+#define CMD_WRITERID 0x121
+#define CMD_PCIBAP 0x22
+#define CMD_PCIAUX 0x23
+#define CMD_ALLOCTLV 0x28
+#define CMD_GETTLV 0x29
+#define CMD_PUTTLV 0x2A
+#define CMD_DELTLV 0x2B    
+#define CMD_FINDNEXTTLV 0x2C    
+#define CMD_SETPHYREG 0x3E
+#define CMD_TXTEST 0x3F    
+#define CMD_NOPSPNODES 0x30    
+#define CMD_USEPSPNODES 0x130
+#define CMD_SETCW 0x31    
+#define CMD_SETPCF 0x32    
+
+/* Command errors */
+#define ERROR_QUALIF 0x00
+#define ERROR_ILLCMD 0x01
+#define ERROR_ILLFMT 0x02
+#define ERROR_INVFID 0x03
+#define ERROR_INVRID 0x04
+#define ERROR_LARGE 0x05
+#define ERROR_NDISABL 0x06
+#define ERROR_ALLOCBSY 0x07
+#define ERROR_NORD 0x0B
+#define ERROR_NOWR 0x0C
+#define ERROR_INVFIDTX 0x0D
+#define ERROR_TESTACT 0x0E
+#define ERROR_TAGNFND 0x12
+#define ERROR_DECODE 0x20
+#define ERROR_DESCUNAV 0x21
+#define ERROR_BADLEN 0x22
+#define ERROR_MODE 0x80
+#define ERROR_HOP 0x81
+#define ERROR_BINTER 0x82
+#define ERROR_RXMODE 0x83
+#define ERROR_MACADDR 0x84
+#define ERROR_RATES 0x85
+#define ERROR_ORDER 0x86
+#define ERROR_SCAN 0x87
+#define ERROR_AUTH 0x88
+#define ERROR_PSMODE 0x89
+#define ERROR_RTYPE 0x8A
+#define ERROR_DIVER 0x8B
+#define ERROR_SSID 0x8C
+#define ERROR_APLIST 0x8D
+#define ERROR_AUTOWAKE 0x8E
+#define ERROR_LEAP 0x8F
 
 /* Registers */
 #define COMMAND 0x00
@@ -386,8 +436,8 @@
 #define RID_STATS      0xFF68
 #define RID_STATSDELTA 0xFF69
 #define RID_STATSDELTACLEAR 0xFF6A
-#define RID_UNKNOWN70  0xFF70
-#define RID_UNKNOWN71  0xFF71
+#define RID_ECHOTEST_RID 0xFF70
+#define RID_ECHOTEST_RESULTS 0xFF71
 #define RID_BSSLISTFIRST 0xFF72
 #define RID_BSSLISTNEXT  0xFF73
 
diff -Nru a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c
--- a/drivers/net/wireless/netwave_cs.c	Fri Sep 20 08:20:45 2002
+++ b/drivers/net/wireless/netwave_cs.c	Fri Sep 20 08:20:45 2002
@@ -324,6 +324,7 @@
 typedef struct netwave_private {
     dev_link_t link;
     struct net_device      dev;
+    spinlock_t	spinlock;	/* Serialize access to the hardware (SMP) */
     dev_node_t node;
     u_char     *ramBase;
     int        timeoutCounter;
@@ -415,8 +416,7 @@
 	
     wstats = &priv->iw_stats;
 
-    save_flags(flags);
-    cli();
+    spin_lock_irqsave(&priv->spinlock, flags);
 	
     netwave_snapshot( priv, ramBase, iobase);
 
@@ -428,7 +428,7 @@
     wstats->discard.code = 0L;
     wstats->discard.misc = 0L;
 
-    restore_flags(flags);
+    spin_unlock_irqrestore(&priv->spinlock, flags);
     
     return &priv->iw_stats;
 }
@@ -491,6 +491,10 @@
     link->conf.ConfigIndex = 1;
     link->conf.Present = PRESENT_OPTION;
 
+    /* Netwave private struct init. link/dev/node already taken care of,
+     * other stuff zero'd - Jean II */
+    spin_lock_init(&priv->spinlock);
+
     /* Netwave specific entries in the device structure */
     dev->hard_start_xmit = &netwave_start_xmit;
     dev->set_config = &netwave_config;
@@ -640,8 +644,7 @@
 	u_char *ramBase = priv->ramBase;
 
 	/* Disable interrupts & save flags */
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&priv->spinlock, flags);
 
 #if WIRELESS_EXT > 8
 	if(!wrqu->nwid.disabled) {
@@ -660,7 +663,7 @@
 	}
 
 	/* ReEnable interrupts & restore flags */
-	restore_flags(flags);
+	spin_unlock_irqrestore(&priv->spinlock, flags);
     
 	return 0;
 }
@@ -699,8 +702,7 @@
 	u_char *ramBase = priv->ramBase;
 
 	/* Disable interrupts & save flags */
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&priv->spinlock, flags);
 
 	scramble_key = (key[0] << 8) | key[1];
 	wait_WOC(iobase);
@@ -710,7 +712,7 @@
 	writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
 
 	/* ReEnable interrupts & restore flags */
-	restore_flags(flags);
+	spin_unlock_irqrestore(&priv->spinlock, flags);
     
 	return 0;
 }
@@ -816,8 +818,7 @@
 	u_char *ramBase = priv->ramBase;
 
 	/* Disable interrupts & save flags */
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&priv->spinlock, flags);
 
 	/* Take snapshot of environment */
 	netwave_snapshot( priv, ramBase, iobase);
@@ -827,7 +828,7 @@
 	priv->lastExec = jiffies;
 
 	/* ReEnable interrupts & restore flags */
-	restore_flags(flags);
+	spin_unlock_irqrestore(&priv->spinlock, flags);
     
 	return(0);
 }
@@ -1376,8 +1377,7 @@
     ioaddr_t iobase = dev->base_addr;
 
     /* Disable interrupts & save flags */
-    save_flags(flags);
-    cli();
+    spin_lock_irqsave(&priv->spinlock, flags);
 
     /* Check if there are transmit buffers available */
     wait_WOC(iobase);
@@ -1385,7 +1385,7 @@
 	/* No buffers available */
 	printk(KERN_DEBUG "netwave_hw_xmit: %s - no xmit buffers available.\n",
 	       dev->name);
-	restore_flags(flags);
+	spin_unlock_irqrestore(&priv->spinlock, flags);
 	return 1;
     }
 
@@ -1426,7 +1426,7 @@
     writeb((len>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2);
     writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
 
-    restore_flags( flags);
+    spin_unlock_irqrestore(&priv->spinlock, flags);
     return 0;
 }
 
@@ -1618,16 +1618,15 @@
 }
 
 static void update_stats(struct net_device *dev) {
-    unsigned long flags;
+    //unsigned long flags;
+/*     netwave_private *priv = (netwave_private*) dev->priv; */
 
-    save_flags(flags);
-    cli();
+    //spin_lock_irqsave(&priv->spinlock, flags);
 
-/*     netwave_private *priv = (netwave_private*) dev->priv;
-    priv->stats.rx_packets = readb(priv->ramBase + 0x18e); 
+/*    priv->stats.rx_packets = readb(priv->ramBase + 0x18e); 
     priv->stats.tx_packets = readb(priv->ramBase + 0x18f); */
 
-    restore_flags(flags);
+    //spin_unlock_irqrestore(&priv->spinlock, flags);
 }
 
 static int netwave_rx(struct net_device *dev) {
diff -Nru a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
--- a/drivers/net/wireless/wavelan.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/net/wireless/wavelan.c	Fri Sep 20 08:20:47 2002
@@ -312,8 +312,11 @@
  */
 static inline void mmc_out(unsigned long ioaddr, u16 o, u8 d)
 {
+	int count = 0;
+
 	/* Wait for MMC to go idle */
-	while (inw(HASR(ioaddr)) & HASR_MMC_BUSY);
+	while ((count++ < 100) && (inw(HASR(ioaddr)) & HASR_MMC_BUSY))
+		udelay(10);
 
 	outw((u16) (((u16) d << 8) | (o << 1) | 1), MMCR(ioaddr));
 }
@@ -339,10 +342,14 @@
  */
 static inline u8 mmc_in(unsigned long ioaddr, u16 o)
 {
-	while (inw(HASR(ioaddr)) & HASR_MMC_BUSY);
+	int count = 0;
+
+	while ((count++ < 100) && (inw(HASR(ioaddr)) & HASR_MMC_BUSY))
+		udelay(10);
 	outw(o << 1, MMCR(ioaddr));
 
-	while (inw(HASR(ioaddr)) & HASR_MMC_BUSY);
+	while ((count++ < 100) && (inw(HASR(ioaddr)) & HASR_MMC_BUSY))
+		udelay(10);
 	return (u8) (inw(MMCR(ioaddr)) >> 8);
 }
 
@@ -2958,6 +2965,9 @@
 		    (unsigned char *) &nop.nop_h.ac_link,
 		    sizeof(nop.nop_h.ac_link));
 
+	/* Make sure the watchdog will keep quiet for a while */
+	dev->trans_start = jiffies;
+
 	/* Keep stats up to date. */
 	lp->stats.tx_bytes += length;
 
@@ -3874,29 +3884,48 @@
 	 * the spinlock. */
 	spin_lock(&lp->spinlock);
 
+	/* We always had spurious interrupts at startup, but lately I
+	 * saw them comming *between* the request_irq() and the
+	 * spin_lock_irqsave() in wavelan_open(), so the spinlock
+	 * protection is no enough.
+	 * So, we also check lp->hacr that will tell us is we enabled
+	 * irqs or not (see wv_ints_on()).
+	 * We can't use netif_running(dev) because we depend on the
+	 * proper processing of the irq generated during the config. */
+
+	/* Which interrupt it is ? */
+	hasr = hasr_read(ioaddr);
+
+#ifdef DEBUG_INTERRUPT_INFO
+	printk(KERN_INFO
+	       "%s: wavelan_interrupt(): hasr 0x%04x; hacr 0x%04x.\n",
+	       dev->name, hasr, lp->hacr);
+#endif
+
 	/* Check modem interrupt */
-	if ((hasr = hasr_read(ioaddr)) & HASR_MMC_INTR) {
+	if ((hasr & HASR_MMC_INTR) && (lp->hacr & HACR_MMC_INT_ENABLE)) {
 		u8 dce_status;
 
+#ifdef DEBUG_INTERRUPT_ERROR
+		printk(KERN_INFO
+		       "%s: wavelan_interrupt(): unexpected mmc interrupt: status 0x%04x.\n",
+		       dev->name, dce_status);
+#endif
 		/*
 		 * Interrupt from the modem management controller.
 		 * This will clear it -- ignored for now.
 		 */
 		mmc_read(ioaddr, mmroff(0, mmr_dce_status), &dce_status,
 			 sizeof(dce_status));
-#ifdef DEBUG_INTERRUPT_ERROR
-		printk(KERN_INFO
-		       "%s: wavelan_interrupt(): unexpected mmc interrupt: status 0x%04x.\n",
-		       dev->name, dce_status);
-#endif
 	}
 
 	/* Check if not controller interrupt */
-	if ((hasr & HASR_82586_INTR) == 0) {
+	if (((hasr & HASR_82586_INTR) == 0) ||
+	    ((lp->hacr & HACR_82586_INT_ENABLE) == 0)) {
 #ifdef DEBUG_INTERRUPT_ERROR
 		printk(KERN_INFO
-		       "%s: wavelan_interrupt(): interrupt not coming from i82586\n",
-		       dev->name);
+		       "%s: wavelan_interrupt(): interrupt not coming from i82586 - hasr 0x%04x.\n",
+		       dev->name, hasr);
 #endif
 		spin_unlock (&lp->spinlock);
 		return;
diff -Nru a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h
--- a/drivers/net/wireless/wavelan.p.h	Fri Sep 20 08:20:47 2002
+++ b/drivers/net/wireless/wavelan.p.h	Fri Sep 20 08:20:47 2002
@@ -351,6 +351,12 @@
  *		o got rid of wavelan_ioctl()
  *		o use a bunch of iw_handler instead
  *
+ * Changes made for release in 2.5.35 :
+ * ----------------------------------
+ *	- Set dev->trans_start to avoid filling the logs
+ *	- Handle better spurious/bogus interrupt
+ *	- Avoid deadlocks in mmc_out()/mmc_in()
+ *
  * Wishes & dreams:
  * ----------------
  *	- roaming (see Pcmcia driver)
diff -Nru a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
--- a/drivers/net/wireless/wavelan_cs.c	Fri Sep 20 08:20:46 2002
+++ b/drivers/net/wireless/wavelan_cs.c	Fri Sep 20 08:20:46 2002
@@ -56,6 +56,8 @@
  *
  */
 
+#include <linux/ethtool.h>
+#include <asm/uaccess.h>
 #include "wavelan_cs.p.h"		/* Private header */
 
 /************************* MISC SUBROUTINES **************************/
@@ -282,9 +284,11 @@
 	u_short		o,
 	u_char		d)
 {
+  int count = 0;
+
   /* Wait for MMC to go idle */
-  while(inb(HASR(base)) & HASR_MMI_BUSY)
-    ;
+  while((count++ < 100) && (inb(HASR(base)) & HASR_MMI_BUSY))
+    udelay(10);
 
   outb((u_char)((o << 1) | MMR_MMI_WR), MMR(base));
   outb(d, MMD(base));
@@ -317,14 +321,16 @@
 mmc_in(u_long	base,
        u_short	o)
 {
-  while(inb(HASR(base)) & HASR_MMI_BUSY)
-    ;
+  int count = 0;
+
+  while((count++ < 100) && (inb(HASR(base)) & HASR_MMI_BUSY))
+    udelay(10);
   outb(o << 1, MMR(base));		/* Set the read address */
 
   outb(0, MMD(base));			/* Required dummy write */
 
-  while(inb(HASR(base)) & HASR_MMI_BUSY)
-    ;
+  while((count++ < 100) && (inb(HASR(base)) & HASR_MMI_BUSY))
+    udelay(10);
   return (u_char) (inb(MMD(base)));	/* Now do the actual read */
 }
 
@@ -1854,6 +1860,27 @@
 }
 #endif	/* HISTOGRAM */
 
+static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+
+		strncpy(info.driver, "wavelan_cs", sizeof(info.driver)-1);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	}
+
+	return -EOPNOTSUPP;
+}
+
 /*------------------------------------------------------------------*/
 /*
  * Wireless Handler : get protocol name
@@ -2885,6 +2912,10 @@
   /* Look what is the request */
   switch(cmd)
     {
+    case SIOCETHTOOL:
+      ret = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+      break;
+
       /* --------------- WIRELESS EXTENSIONS --------------- */
 
     case SIOCGIWNAME:
@@ -3581,6 +3612,9 @@
   /* Send the transmit command */
   wv_82593_cmd(dev, "wv_packet_write(): transmit",
 	       OP0_TRANSMIT, SR0_NO_RESULT);
+
+  /* Make sure the watchdog will keep quiet for a while */
+  dev->trans_start = jiffies;
 
   /* Keep stats up to date */
   lp->stats.tx_bytes += length;
diff -Nru a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h
--- a/drivers/net/wireless/wavelan_cs.p.h	Fri Sep 20 08:20:44 2002
+++ b/drivers/net/wireless/wavelan_cs.p.h	Fri Sep 20 08:20:44 2002
@@ -400,6 +400,12 @@
  *		o got rid of wavelan_ioctl()
  *		o use a bunch of iw_handler instead
  *
+ * Changes made for release in 3.2.1 :
+ * ---------------------------------
+ *	- Set dev->trans_start to avoid filling the logs
+ *		(and generating useless abort commands)
+ *	- Avoid deadlocks in mmc_out()/mmc_in()
+ *
  * Wishes & dreams:
  * ----------------
  *	- Cleanup and integrate the roaming code
diff -Nru a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
--- a/drivers/net/yellowfin.c	Fri Sep 20 08:20:44 2002
+++ b/drivers/net/yellowfin.c	Fri Sep 20 08:20:44 2002
@@ -1025,17 +1025,11 @@
 					if (tx_errs & 0x0800) yp->stats.tx_carrier_errors++;
 					if (tx_errs & 0x2000) yp->stats.tx_window_errors++;
 					if (tx_errs & 0x8000) yp->stats.tx_fifo_errors++;
-#ifdef ETHER_STATS
-					if (tx_errs & 0x1000) yp->stats.collisions16++;
-#endif
 				} else {
 #ifndef final_version
 					if (yellowfin_debug > 4)
 						printk(KERN_DEBUG "%s: Normal transmit, Tx status %4.4x.\n",
 							   dev->name, tx_errs);
-#endif
-#ifdef ETHER_STATS
-					if (tx_errs & 0x0400) yp->stats.tx_deferred++;
 #endif
 					yp->stats.tx_bytes += skb->len;
 					yp->stats.collisions += tx_errs & 15;
diff -Nru a/drivers/pci/pool.c b/drivers/pci/pool.c
--- a/drivers/pci/pool.c	Fri Sep 20 08:20:48 2002
+++ b/drivers/pci/pool.c	Fri Sep 20 08:20:48 2002
@@ -69,7 +69,7 @@
 		}
 
 		/* per-pool info, no real statistics yet */
-		temp = snprintf (next, size, "%-16s %4u %4u %4u %2u\n",
+		temp = snprintf (next, size, "%-16s %4u %4Zu %4Zu %2u\n",
 				pool->name,
 				blocks, pages * pool->blocks_per_page,
 				pool->size, pages);
diff -Nru a/drivers/pci/probe.c b/drivers/pci/probe.c
--- a/drivers/pci/probe.c	Fri Sep 20 08:20:43 2002
+++ b/drivers/pci/probe.c	Fri Sep 20 08:20:43 2002
@@ -444,6 +444,8 @@
 		return NULL;
 	}
 
+	pci_name_device(dev);
+
 	/* now put in global tree */
 	strcpy(dev->dev.name,dev->name);
 	strcpy(dev->dev.bus_id,dev->slot_name);
@@ -471,7 +473,6 @@
 		dev = pci_scan_device(temp);
 		if (!dev)
 			continue;
-		pci_name_device(dev);
 		if (!func) {
 			is_multi = hdr_type & 0x80;
 			first_dev = dev;
diff -Nru a/drivers/pci/proc.c b/drivers/pci/proc.c
--- a/drivers/pci/proc.c	Fri Sep 20 08:20:46 2002
+++ b/drivers/pci/proc.c	Fri Sep 20 08:20:46 2002
@@ -371,7 +371,7 @@
 	show:	show_device
 };
 
-static struct proc_dir_entry *proc_bus_pci_dir;
+struct proc_dir_entry *proc_bus_pci_dir;
 
 /* driverfs files */
 static ssize_t pci_show_irq(struct device * dev, char * buf, size_t count, loff_t off)
@@ -621,5 +621,6 @@
 EXPORT_SYMBOL(pci_proc_detach_device);
 EXPORT_SYMBOL(pci_proc_attach_bus);
 EXPORT_SYMBOL(pci_proc_detach_bus);
+EXPORT_SYMBOL(proc_bus_pci_dir);
 #endif
 
diff -Nru a/drivers/pcmcia/sa1100.h b/drivers/pcmcia/sa1100.h
--- a/drivers/pcmcia/sa1100.h	Fri Sep 20 08:20:47 2002
+++ b/drivers/pcmcia/sa1100.h	Fri Sep 20 08:20:47 2002
@@ -160,7 +160,7 @@
    */
   socket_state_t        cs_state;
   pccard_io_map         io_map[MAX_IO_WIN];
-  pccard_mem_map        mem_map[MAX_WIN];
+  pccard_mem_map        pc_mem_map[MAX_WIN];
   void                  (*handler)(void *, unsigned int);
   void                  *handler_info;
 
diff -Nru a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c
--- a/drivers/pcmcia/sa1100_generic.c	Fri Sep 20 08:20:47 2002
+++ b/drivers/pcmcia/sa1100_generic.c	Fri Sep 20 08:20:47 2002
@@ -686,7 +686,7 @@
   DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock);
 
   if (map->map < MAX_WIN) {
-    *map = skt->mem_map[map->map];
+    *map = skt->pc_mem_map[map->map];
     ret = 0;
   }
 
@@ -754,7 +754,7 @@
   map->sys_stop += start;
   map->sys_start = start;
 
-  skt->mem_map[map->map] = *map;
+  skt->pc_mem_map[map->map] = *map;
 
   return 0;
 }  /* sa1100_pcmcia_set_mem_map() */
diff -Nru a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c
--- a/drivers/s390/net/iucv.c	Fri Sep 20 08:20:41 2002
+++ b/drivers/s390/net/iucv.c	Fri Sep 20 08:20:41 2002
@@ -418,7 +418,7 @@
 /**
  * grab_param: - Get a parameter buffer from the pre-allocated pool.
  *
- * This function searches for an unused element in the the pre-allocated pool
+ * This function searches for an unused element in the pre-allocated pool
  * of parameter buffers. If one is found, it marks it "in use" and returns
  * a pointer to it. The calling function is responsible for releasing it
  * when it has finished its usage.
@@ -1525,7 +1525,7 @@
  *        buflen - length of reply buffer
  * Output: ipbfadr2 - Address of buffer updated by the number
  *                    of bytes you have moved.
- *         ipbfln2f - Contains on the the following values
+ *         ipbfln2f - Contains one of the following values:
  *              If the answer buffer is the same length as the reply, this field
  *               contains zero.
  *              If the answer buffer is longer than the reply, this field contains
@@ -1590,7 +1590,7 @@
  *        buffer - address of array of reply buffers
  *        buflen - total length of reply buffers
  * Output: ipbfadr2 - Address of buffer which IUCV is currently working on.
- *         ipbfln2f - Contains on the the following values
+ *         ipbfln2f - Contains one of the following values:
  *              If the answer buffer is the same length as the reply, this field
  *               contains zero.
  *              If the answer buffer is longer than the reply, this field contains
diff -Nru a/drivers/sbus/char/Config.in b/drivers/sbus/char/Config.in
--- a/drivers/sbus/char/Config.in	Fri Sep 20 08:20:42 2002
+++ b/drivers/sbus/char/Config.in	Fri Sep 20 08:20:42 2002
@@ -18,7 +18,7 @@
       # XXX Why don't we do "source drivers/char/Config.in" somewhere?
       if [ "$CONFIG_PCI" = "y" ]; then
 	 define_bool CONFIG_APM_RTC_IS_GMT y		# no shit
-	 bool 'PC-style RTC' CONFIG_RTC
+         tristate 'PC-style Real Time Clock Support' CONFIG_RTC
       fi
    fi
 fi
diff -Nru a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c
--- a/drivers/sbus/char/bbc_envctrl.c	Fri Sep 20 08:20:44 2002
+++ b/drivers/sbus/char/bbc_envctrl.c	Fri Sep 20 08:20:44 2002
@@ -612,7 +612,7 @@
 			int found = 0;
 
 			read_lock(&tasklist_lock);
-			for_each_task(p) {
+			for_each_process(p) {
 				if (p == kenvctrld_task) {
 					found = 1;
 					break;
diff -Nru a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c
--- a/drivers/sbus/char/envctrl.c	Fri Sep 20 08:20:43 2002
+++ b/drivers/sbus/char/envctrl.c	Fri Sep 20 08:20:43 2002
@@ -1141,7 +1141,7 @@
 			int found = 0;
 
 			read_lock(&tasklist_lock);
-			for_each_task(p) {
+			for_each_process(p) {
 				if (p == kenvctrld_task) {
 					found = 1;
 					break;
diff -Nru a/drivers/scsi/Makefile b/drivers/scsi/Makefile
--- a/drivers/scsi/Makefile	Fri Sep 20 08:20:44 2002
+++ b/drivers/scsi/Makefile	Fri Sep 20 08:20:44 2002
@@ -120,8 +120,9 @@
 obj-$(CONFIG_CHR_DEV_SG)	+= sg.o
 
 scsi_mod-objs	:= scsi.o hosts.o scsi_ioctl.o constants.o scsicam.o \
-			scsi_proc.o scsi_error.o scsi_queue.o scsi_lib.o \
-			scsi_merge.o scsi_scan.o scsi_syms.o
+			scsi_proc.o scsi_error.o scsi_lib.o scsi_merge.o \
+			scsi_scan.o scsi_syms.o
+			
 sd_mod-objs	:= sd.o
 sr_mod-objs	:= sr.o sr_ioctl.o sr_vendor.o
 initio-objs	:= ini9100u.o i91uscsi.o
diff -Nru a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
--- a/drivers/scsi/scsi.c	Fri Sep 20 08:20:46 2002
+++ b/drivers/scsi/scsi.c	Fri Sep 20 08:20:46 2002
@@ -594,6 +594,90 @@
 }
 
 /*
+ * Function:    scsi_mlqueue_insert()
+ *
+ * Purpose:     Insert a command in the midlevel queue.
+ *
+ * Arguments:   cmd    - command that we are adding to queue.
+ *              reason - why we are inserting command to queue.
+ *
+ * Lock status: Assumed that lock is not held upon entry.
+ *
+ * Returns:     Nothing.
+ *
+ * Notes:       We do this for one of two cases.  Either the host is busy
+ *              and it cannot accept any more commands for the time being,
+ *              or the device returned QUEUE_FULL and can accept no more
+ *              commands.
+ * Notes:       This could be called either from an interrupt context or a
+ *              normal process context.
+ */
+static int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason)
+{
+	struct Scsi_Host *host = cmd->host;
+	unsigned long flags;
+
+	SCSI_LOG_MLQUEUE(1,
+		 printk("Inserting command %p into mlqueue\n", cmd));
+
+	/*
+	 * We are inserting the command into the ml queue.  First, we
+	 * cancel the timer, so it doesn't time out.
+	 */
+	scsi_delete_timer(cmd);
+
+	/*
+	 * Next, set the appropriate busy bit for the device/host.
+	 *
+	 * If the host/device isn't busy, assume that something actually
+	 * completed, and that we should be able to queue a command now.
+	 *
+	 * Note that there is an implicit assumption that every host can
+	 * always queue at least one command.  If a host is inactive and
+	 * cannot queue any commands, I don't see how things could
+	 * possibly work anyways.
+	 */
+	if (reason == SCSI_MLQUEUE_HOST_BUSY) {
+		if (host->host_busy == 0) {
+			if (scsi_retry_command(cmd) == 0) {
+				return 0;
+			}
+		}
+		host->host_blocked = TRUE;
+	} else {
+		if (cmd->device->device_busy == 0) {
+			if (scsi_retry_command(cmd) == 0) {
+				return 0;
+			}
+		}
+		cmd->device->device_blocked = TRUE;
+	}
+
+	/*
+	 * Register the fact that we own the thing for now.
+	 */
+	cmd->state = SCSI_STATE_MLQUEUE;
+	cmd->owner = SCSI_OWNER_MIDLEVEL;
+	cmd->bh_next = NULL;
+
+	/*
+	 * Decrement the counters, since these commands are no longer
+	 * active on the host/device.
+	 */
+	spin_lock_irqsave(cmd->host->host_lock, flags);
+	cmd->host->host_busy--;
+	cmd->device->device_busy--;
+	spin_unlock_irqrestore(cmd->host->host_lock, flags);
+
+	/*
+	 * Insert this command at the head of the queue for it's device.
+	 * It will go before all other commands that are already in the queue.
+	 */
+	scsi_insert_special_cmd(cmd, 1);
+	return 0;
+}
+
+/*
  * Function:    scsi_release_command
  *
  * Purpose:     Release a command block.
@@ -2453,6 +2537,7 @@
 {
 	struct scsi_host_sg_pool *sgp;
 	struct scatterlist *sgl;
+	int pf_flags;
 
 	BUG_ON(!SCpnt->use_sg);
 
@@ -2467,9 +2552,10 @@
 
 	sgp = scsi_sg_pools + SCpnt->sglist_len;
 
+	pf_flags = current->flags;
 	current->flags |= PF_NOWARN;
 	sgl = mempool_alloc(sgp->pool, gfp_mask);
-	current->flags &= ~PF_NOWARN;
+	current->flags = pf_flags;
 	if (sgl) {
 		memset(sgl, 0, sgp->size);
 		return sgl;
diff -Nru a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h
--- a/drivers/scsi/scsi.h	Fri Sep 20 08:20:43 2002
+++ b/drivers/scsi/scsi.h	Fri Sep 20 08:20:43 2002
@@ -461,11 +461,6 @@
 extern int scsi_init_io(Scsi_Cmnd *SCpnt);
 
 /*
- * Prototypes for functions in scsi_queue.c
- */
-extern int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason);
-
-/*
  * Prototypes for functions in scsi_lib.c
  */
 extern int scsi_maybe_unblock_host(Scsi_Device * SDpnt);
diff -Nru a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
--- a/drivers/scsi/scsi_lib.c	Fri Sep 20 08:20:46 2002
+++ b/drivers/scsi/scsi_lib.c	Fri Sep 20 08:20:46 2002
@@ -317,13 +317,11 @@
 
 	ASSERT_LOCK(q->queue_lock, 0);
 
-	spin_lock_irqsave(q->queue_lock, flags);
 	/*
 	 * If there are blocks left over at the end, set up the command
 	 * to queue the remainder of them.
 	 */
 	if (end_that_request_first(req, uptodate, sectors)) {
-		spin_unlock_irqrestore(q->queue_lock, flags);
 		if (!requeue)
 			return SCpnt;
 
@@ -337,7 +335,9 @@
 
 	add_blkdev_randomness(major(req->rq_dev));
 
-	if(blk_rq_tagged(req))
+	spin_lock_irqsave(q->queue_lock, flags);
+
+	if (blk_rq_tagged(req))
 		blk_queue_end_tag(q, req);
 
 	end_that_request_last(req);
diff -Nru a/drivers/scsi/scsi_queue.c b/drivers/scsi/scsi_queue.c
--- a/drivers/scsi/scsi_queue.c	Fri Sep 20 08:20:47 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,149 +0,0 @@
-/*
- *  scsi_queue.c Copyright (C) 1997 Eric Youngdale
- *
- *  generic mid-level SCSI queueing.
- *
- *  The point of this is that we need to track when hosts are unable to
- *  accept a command because they are busy.  In addition, we track devices
- *  that cannot accept a command because of a QUEUE_FULL condition.  In both
- *  of these cases, we enter the command in the queue.  At some later point,
- *  we attempt to remove commands from the queue and retry them.
- */
-
-#include <linux/module.h>
-
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/stat.h>
-#include <linux/blk.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/smp_lock.h>
-
-#define __KERNEL_SYSCALLS__
-
-#include <linux/unistd.h>
-
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/dma.h>
-
-#include "scsi.h"
-#include "hosts.h"
-
-/*
- * TODO:
- *      1) Prevent multiple traversals of list to look for commands to
- *         queue.
- *      2) Protect against multiple insertions of list at the same time.
- * DONE:
- *      1) Set state of scsi command to a new state value for ml queue.
- *      2) Insert into queue when host rejects command.
- *      3) Make sure status code is properly passed from low-level queue func
- *         so that internal_cmnd properly returns the right value.
- *      4) Insert into queue when QUEUE_FULL.
- *      5) Cull queue in bottom half handler.
- *      6) Check usage count prior to queue insertion.  Requeue if usage
- *         count is 0.
- *      7) Don't send down any more commands if the host/device is busy.
- */
-
-static const char RCSid[] = "$Header: /mnt/ide/home/eric/CVSROOT/linux/drivers/scsi/scsi_queue.c,v 1.1 1997/10/21 11:16:38 eric Exp $";
-
-
-/*
- * Function:    scsi_mlqueue_insert()
- *
- * Purpose:     Insert a command in the midlevel queue.
- *
- * Arguments:   cmd    - command that we are adding to queue.
- *              reason - why we are inserting command to queue.
- *
- * Lock status: Assumed that lock is not held upon entry.
- *
- * Returns:     Nothing.
- *
- * Notes:       We do this for one of two cases.  Either the host is busy
- *              and it cannot accept any more commands for the time being,
- *              or the device returned QUEUE_FULL and can accept no more
- *              commands.
- * Notes:       This could be called either from an interrupt context or a
- *              normal process context.
- */
-int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason)
-{
-	struct Scsi_Host *host;
-	unsigned long flags;
-
-	SCSI_LOG_MLQUEUE(1, printk("Inserting command %p into mlqueue\n", cmd));
-
-	/*
-	 * We are inserting the command into the ml queue.  First, we
-	 * cancel the timer, so it doesn't time out.
-	 */
-	scsi_delete_timer(cmd);
-
-	host = cmd->host;
-
-	/*
-	 * Next, set the appropriate busy bit for the device/host.
-	 */
-	if (reason == SCSI_MLQUEUE_HOST_BUSY) {
-		/*
-		 * Protect against race conditions.  If the host isn't busy,
-		 * assume that something actually completed, and that we should
-		 * be able to queue a command now.  Note that there is an implicit
-		 * assumption that every host can always queue at least one command.
-		 * If a host is inactive and cannot queue any commands, I don't see
-		 * how things could possibly work anyways.
-		 */
-		if (host->host_busy == 0) {
-			if (scsi_retry_command(cmd) == 0) {
-				return 0;
-			}
-		}
-		host->host_blocked = TRUE;
-	} else {
-		/*
-		 * Protect against race conditions.  If the device isn't busy,
-		 * assume that something actually completed, and that we should
-		 * be able to queue a command now.  Note that there is an implicit
-		 * assumption that every host can always queue at least one command.
-		 * If a host is inactive and cannot queue any commands, I don't see
-		 * how things could possibly work anyways.
-		 */
-		if (cmd->device->device_busy == 0) {
-			if (scsi_retry_command(cmd) == 0) {
-				return 0;
-			}
-		}
-		cmd->device->device_blocked = TRUE;
-	}
-
-	/*
-	 * Register the fact that we own the thing for now.
-	 */
-	cmd->state = SCSI_STATE_MLQUEUE;
-	cmd->owner = SCSI_OWNER_MIDLEVEL;
-	cmd->bh_next = NULL;
-
-	/*
-	 * Decrement the counters, since these commands are no longer
-	 * active on the host/device.
-	 */
-	spin_lock_irqsave(cmd->host->host_lock, flags);
-	cmd->host->host_busy--;
-	cmd->device->device_busy--;
-	spin_unlock_irqrestore(cmd->host->host_lock, flags);
-
-	/*
-	 * Insert this command at the head of the queue for it's device.
-	 * It will go before all other commands that are already in the queue.
-	 */
-	scsi_insert_special_cmd(cmd, 1);
-	return 0;
-}
diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c
--- a/drivers/scsi/sd.c	Fri Sep 20 08:20:43 2002
+++ b/drivers/scsi/sd.c	Fri Sep 20 08:20:43 2002
@@ -1314,6 +1314,7 @@
 	p = kmalloc(sizeof(*p), GFP_KERNEL);
 	if (!p)
 		return 1;
+	memset(p, 0, sizeof(*p));
 	gd = &p->disk;
 
 	SCSI_LOG_HLQUEUE(3, printk("sd_attach: scsi device: <%d,%d,%d,%d>\n", 
diff -Nru a/drivers/scsi/sg.c b/drivers/scsi/sg.c
--- a/drivers/scsi/sg.c	Fri Sep 20 08:20:46 2002
+++ b/drivers/scsi/sg.c	Fri Sep 20 08:20:46 2002
@@ -1462,6 +1462,7 @@
 	}
 
 	SCSI_LOG_TIMEOUT(3, printk("sg_attach: dev=%d \n", k));
+	memset(sdp, 0, sizeof(*sdp));
 	sdp->device = scsidp;
 	init_waitqueue_head(&sdp->o_excl_wait);
 	sdp->headfp = NULL;
diff -Nru a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
--- a/drivers/serial/sunsu.c	Fri Sep 20 08:20:43 2002
+++ b/drivers/serial/sunsu.c	Fri Sep 20 08:20:43 2002
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/spinlock.h>
 #include <linux/errno.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
@@ -28,11 +29,12 @@
 #include <linux/ioport.h>
 #include <linux/circ_buf.h>
 #include <linux/serial.h>
+#include <linux/sysrq.h>
 #include <linux/console.h>
-#include <linux/spinlock.h>
 #ifdef CONFIG_SERIO
 #include <linux/serio.h>
 #endif
+#include <linux/serial_reg.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 
@@ -44,8 +46,12 @@
 #include <asm/isa.h>
 #endif
 
+/* #if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) */
+#if defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
 #include <linux/serial_core.h>
-#include <linux/serial_reg.h>
 
 #include "suncore.h"
 
@@ -88,6 +94,7 @@
 
 	/* Probing information.  */
 	enum su_type		su_type;
+	unsigned int		type_probed;	/* XXX Stupid */
 	int			port_node;
 	unsigned int		irq;
 
@@ -333,7 +340,8 @@
 			if (*status & UART_LSR_BI) {
 				*status &= ~(UART_LSR_FE | UART_LSR_PE);
 				up->port.icount.brk++;
-				if (up->port.line == up->port.cons->index)
+				if (up->port.cons != NULL &&
+				    up->port.line == up->port.cons->index)
 					saw_console_brk = 1;
 				/*
 				 * We do the SysRQ and SAK checking
@@ -355,7 +363,8 @@
 			 */
 			*status &= up->port.read_status_mask;
 
-			if (up->port.line == up->port.cons->index) {
+			if (up->port.cons != NULL &&
+			    up->port.line == up->port.cons->index) {
 				/* Recover the break flag from console xmit */
 				*status |= up->lsr_break_flag;
 				up->lsr_break_flag = 0;
@@ -910,6 +919,16 @@
 
 static void sunsu_config_port(struct uart_port *port, int flags)
 {
+	struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
+
+	if (flags & UART_CONFIG_TYPE) {
+		/*
+		 * We are supposed to call autoconfig here, but this requires
+		 * splitting all the OBP probing crap from the UART probing.
+		 * We'll do it when we kill sunsu.c altogether.
+		 */
+		port->type = up->type_probed;	/* XXX */
+	}
 }
 
 static int
@@ -1020,6 +1039,7 @@
 	if (!up->port_node || !up->su_type)
 		return;
 
+	up->type_probed = PORT_UNKNOWN;
 	up->port.iotype = SERIAL_IO_MEM;
 
 	/*
@@ -1028,7 +1048,16 @@
 	for_each_ebus(ebus) {
 		for_each_ebusdev(dev, ebus) {
 			if (dev->prom_node == up->port_node) {
+				/*
+				 * The EBus is broken on sparc; it delivers
+				 * virtual addresses in resources. Oh well...
+				 * This is correct on sparc64, though.
+				 */
 				up->port.membase = (char *) dev->resource[0].start;
+				/*
+				 * This is correct on both architectures.
+				 */
+				up->port.mapbase = dev->resource[0].start;
 				up->irq = dev->irqs[0];
 				goto ebus_done;
 			}
@@ -1039,7 +1068,9 @@
 	for_each_isa(isa_br) {
 		for_each_isadev(isa_dev, isa_br) {
 			if (isa_dev->prom_node == up->port_node) {
+				/* Same on sparc64. Cool architecure... */
 				up->port.membase = (char *) isa_dev->resource.start;
+				up->port.mapbase = isa_dev->resource.start;
 				up->irq = isa_dev->irq;
 				goto ebus_done;
 			}
@@ -1067,6 +1098,7 @@
 		    reg0.which_io, reg0.phys_addr);
 		return;
 	}
+	up->port.mapbase = reg0.phys_addr;
 	if ((up->port.membase = ioremap(reg0.phys_addr, reg0.reg_size)) == 0) {
 		prom_printf("sunsu: Cannot map registers.\n");
 		return;
@@ -1203,6 +1235,7 @@
 
 	if (up->port.type == PORT_UNKNOWN)
 		goto out;
+	up->type_probed = up->port.type;	/* XXX */
 
 	/*
 	 * Reset the UART.
@@ -1454,6 +1487,7 @@
 		    up->su_type == SU_PORT_KBD)
 			continue;
 
+		up->port.flags |= ASYNC_BOOT_AUTOCONF;
 		up->port.type = PORT_UNKNOWN;
 		up->port.uartclk = (SU_BASE_BAUD * 16);
 
@@ -1475,7 +1509,6 @@
 	if (ret < 0)
 		return ret;
 
-	instance = 0;
 	for (i = 0; i < UART_NR; i++) {
 		struct uart_sunsu_port *up = &sunsu_ports[i];
 
@@ -1645,9 +1678,6 @@
 	/*
 	 * Console must be initiated after the generic initialization.
 	 */
-	sunsu_reg.cons = &sunsu_cons;
-	sunsu_reg.nr = scan.devices;
-
        	sunsu_serial_init();
 	sunsu_serial_console_init();
 
diff -Nru a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
--- a/drivers/usb/serial/visor.c	Fri Sep 20 08:20:44 2002
+++ b/drivers/usb/serial/visor.c	Fri Sep 20 08:20:44 2002
@@ -591,7 +591,7 @@
 			info("%s: port %d, is for %s use", serial->type->name,
 			     connection_info->connections[i].port, string);
 		/* save off our num_ports info so that we can use it in the calc_num_ports call */
-		serial->private = (void *)num_ports;
+		serial->private = (void *)(long)num_ports;
 		}
 	}
 
@@ -637,7 +637,7 @@
 	int num_ports = 0;
 
 	if (serial->private) {
-		num_ports = (int)serial->private;
+		num_ports = (int)(long)serial->private;
 		serial->private = NULL;
 	}
 	return num_ports;
diff -Nru a/drivers/video/clgenfb.c b/drivers/video/clgenfb.c
--- a/drivers/video/clgenfb.c	Fri Sep 20 08:20:44 2002
+++ b/drivers/video/clgenfb.c	Fri Sep 20 08:20:44 2002
@@ -280,6 +280,7 @@
 	{ BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5434_4 },
 	{ BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_5430 }, /* GD-5440 has identical id */
 	{ BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_7543 },
+	{ BT_ALPINE, NULL, PCI_DEVICE_ID_CIRRUS_7548 },
 	{ BT_GD5480, NULL, PCI_DEVICE_ID_CIRRUS_5480 }, /* MacPicasso probably */
 	{ BT_PICASSO4, NULL, PCI_DEVICE_ID_CIRRUS_5446 }, /* Picasso 4 is a GD5446 */
 	{ BT_LAGUNA, "CL Laguna", PCI_DEVICE_ID_CIRRUS_5462 },
diff -Nru a/fs/Makefile b/fs/Makefile
--- a/fs/Makefile	Fri Sep 20 08:20:46 2002
+++ b/fs/Makefile	Fri Sep 20 08:20:46 2002
@@ -5,8 +5,6 @@
 # Rewritten to use lists instead of if-statements.
 # 
 
-O_TARGET := fs.o
-
 export-objs :=	open.o dcache.o buffer.o bio.o inode.o dquot.o mpage.o aio.o \
                 fcntl.o
 
diff -Nru a/fs/aio.c b/fs/aio.c
--- a/fs/aio.c	Fri Sep 20 08:20:46 2002
+++ b/fs/aio.c	Fri Sep 20 08:20:46 2002
@@ -53,7 +53,7 @@
 /* Used for rare fput completion. */
 static void aio_fput_routine(void *);
 static struct tq_struct	fput_tqueue = {
-	routine:	aio_fput_routine,
+	.routine	= aio_fput_routine,
 };
 
 static spinlock_t	fput_lock = SPIN_LOCK_UNLOCKED;
diff -Nru a/fs/bad_inode.c b/fs/bad_inode.c
--- a/fs/bad_inode.c	Fri Sep 20 08:20:43 2002
+++ b/fs/bad_inode.c	Fri Sep 20 08:20:43 2002
@@ -30,37 +30,37 @@
 
 static struct file_operations bad_file_ops =
 {
-	llseek:		EIO_ERROR,
-	read:		EIO_ERROR,
-	write:		EIO_ERROR,
-	readdir:	EIO_ERROR,
-	poll:		EIO_ERROR,
-	ioctl:		EIO_ERROR,
-	mmap:		EIO_ERROR,
-	open:		EIO_ERROR,
-	flush:		EIO_ERROR,
-	release:	EIO_ERROR,
-	fsync:		EIO_ERROR,
-	fasync:		EIO_ERROR,
-	lock:		EIO_ERROR,
+	.llseek		= EIO_ERROR,
+	.read		= EIO_ERROR,
+	.write		= EIO_ERROR,
+	.readdir	= EIO_ERROR,
+	.poll		= EIO_ERROR,
+	.ioctl		= EIO_ERROR,
+	.mmap		= EIO_ERROR,
+	.open		= EIO_ERROR,
+	.flush		= EIO_ERROR,
+	.release	= EIO_ERROR,
+	.fsync		= EIO_ERROR,
+	.fasync		= EIO_ERROR,
+	.lock		= EIO_ERROR,
 };
 
 struct inode_operations bad_inode_ops =
 {
-	create:		EIO_ERROR,
-	lookup:		EIO_ERROR,
-	link:		EIO_ERROR,
-	unlink:		EIO_ERROR,
-	symlink:	EIO_ERROR,
-	mkdir:		EIO_ERROR,
-	rmdir:		EIO_ERROR,
-	mknod:		EIO_ERROR,
-	rename:		EIO_ERROR,
-	readlink:	EIO_ERROR,
-	follow_link:	bad_follow_link,
-	truncate:	EIO_ERROR,
-	permission:	EIO_ERROR,
-	getattr:	EIO_ERROR,
+	.create		= EIO_ERROR,
+	.lookup		= EIO_ERROR,
+	.link		= EIO_ERROR,
+	.unlink		= EIO_ERROR,
+	.symlink	= EIO_ERROR,
+	.mkdir		= EIO_ERROR,
+	.rmdir		= EIO_ERROR,
+	.mknod		= EIO_ERROR,
+	.rename		= EIO_ERROR,
+	.readlink	= EIO_ERROR,
+	.follow_link	= bad_follow_link,
+	.truncate	= EIO_ERROR,
+	.permission	= EIO_ERROR,
+	.getattr	= EIO_ERROR,
 };
 
 
diff -Nru a/fs/binfmt_aout.c b/fs/binfmt_aout.c
--- a/fs/binfmt_aout.c	Fri Sep 20 08:20:43 2002
+++ b/fs/binfmt_aout.c	Fri Sep 20 08:20:43 2002
@@ -37,11 +37,11 @@
 extern void dump_thread(struct pt_regs *, struct user *);
 
 static struct linux_binfmt aout_format = {
-	module:		THIS_MODULE,
-	load_binary:	load_aout_binary,
-	load_shlib:	load_aout_library,
-	core_dump:	aout_core_dump,
-	min_coredump:	PAGE_SIZE
+	.module		= THIS_MODULE,
+	.load_binary	= load_aout_binary,
+	.load_shlib	= load_aout_library,
+	.core_dump	= aout_core_dump,
+	.min_coredump	= PAGE_SIZE
 };
 
 static void set_brk(unsigned long start, unsigned long end)
diff -Nru a/fs/binfmt_elf.c b/fs/binfmt_elf.c
--- a/fs/binfmt_elf.c	Fri Sep 20 08:20:46 2002
+++ b/fs/binfmt_elf.c	Fri Sep 20 08:20:46 2002
@@ -71,11 +71,11 @@
 #define ELF_PAGEALIGN(_v) (((_v) + ELF_MIN_ALIGN - 1) & ~(ELF_MIN_ALIGN - 1))
 
 static struct linux_binfmt elf_format = {
-		module:		THIS_MODULE,
-		load_binary:	load_elf_binary,
-		load_shlib:	load_elf_library,
-		core_dump:	elf_core_dump,
-		min_coredump:	ELF_EXEC_PAGESIZE
+		.module		= THIS_MODULE,
+		.load_binary	= load_elf_binary,
+		.load_shlib	= load_elf_library,
+		.core_dump	= elf_core_dump,
+		.min_coredump	= ELF_EXEC_PAGESIZE
 };
 
 #define BAD_ADDR(x)	((unsigned long)(x) > TASK_SIZE)
@@ -146,7 +146,7 @@
 	if (k_platform) {
 		size_t len = strlen(k_platform) + 1;
 
-#if defined(__i386__) && defined(CONFIG_SMP)
+#ifdef CONFIG_X86_HT
 		/*
 		 * In some cases (e.g. Hyper-Threading), we want to avoid L1
 		 * evictions by the processes running on the same package. One
diff -Nru a/fs/binfmt_em86.c b/fs/binfmt_em86.c
--- a/fs/binfmt_em86.c	Fri Sep 20 08:20:47 2002
+++ b/fs/binfmt_em86.c	Fri Sep 20 08:20:47 2002
@@ -96,8 +96,8 @@
 }
 
 struct linux_binfmt em86_format = {
-	module:		THIS_MODULE,
-	load_binary:	load_em86,
+	.module		= THIS_MODULE,
+	.load_binary	= load_em86,
 };
 
 static int __init init_em86_binfmt(void)
diff -Nru a/fs/binfmt_misc.c b/fs/binfmt_misc.c
--- a/fs/binfmt_misc.c	Fri Sep 20 08:20:44 2002
+++ b/fs/binfmt_misc.c	Fri Sep 20 08:20:44 2002
@@ -485,8 +485,8 @@
 }
 
 static struct file_operations bm_entry_operations = {
-	read:		bm_entry_read,
-	write:		bm_entry_write,
+	.read		= bm_entry_read,
+	.write		= bm_entry_write,
 };
 
 static struct file_system_type bm_fs_type;
@@ -566,7 +566,7 @@
 }
 
 static struct file_operations bm_register_operations = {
-	write:		bm_register_write,
+	.write		= bm_register_write,
 };
 
 /* /status */
@@ -613,21 +613,21 @@
 }
 
 static struct file_operations bm_status_operations = {
-	read:		bm_status_read,
-	write:		bm_status_write,
+	.read		= bm_status_read,
+	.write		= bm_status_write,
 };
 
 /* Superblock handling */
 
 static struct super_operations s_ops = {
-	statfs:		simple_statfs,
-	drop_inode:	generic_delete_inode,
-	clear_inode:	bm_clear_inode,
+	.statfs		= simple_statfs,
+	.drop_inode	= generic_delete_inode,
+	.clear_inode	= bm_clear_inode,
 };
 
 static int bm_fill_super(struct super_block * sb, void * data, int silent)
 {
-	struct qstr names[2] = {{name:"status"}, {name:"register"}};
+	struct qstr names[2] = {{.name = "status"}, {.name = "register"}};
 	struct inode * inode;
 	struct dentry * dentry[3];
 	int i;
@@ -688,15 +688,15 @@
 }
 
 static struct linux_binfmt misc_format = {
-	module: THIS_MODULE,
-	load_binary: load_misc_binary,
+	.module = THIS_MODULE,
+	.load_binary = load_misc_binary,
 };
 
 static struct file_system_type bm_fs_type = {
-	owner:		THIS_MODULE,
-	name:		"binfmt_misc",
-	get_sb:		bm_get_sb,
-	kill_sb:	kill_litter_super,
+	.owner		= THIS_MODULE,
+	.name		= "binfmt_misc",
+	.get_sb		= bm_get_sb,
+	.kill_sb	= kill_litter_super,
 };
 
 static int __init init_misc_binfmt(void)
diff -Nru a/fs/binfmt_script.c b/fs/binfmt_script.c
--- a/fs/binfmt_script.c	Fri Sep 20 08:20:42 2002
+++ b/fs/binfmt_script.c	Fri Sep 20 08:20:42 2002
@@ -95,8 +95,8 @@
 }
 
 struct linux_binfmt script_format = {
-	module:		THIS_MODULE,
-	load_binary:	load_script,
+	.module		= THIS_MODULE,
+	.load_binary	= load_script,
 };
 
 static int __init init_script_binfmt(void)
diff -Nru a/fs/bio.c b/fs/bio.c
--- a/fs/bio.c	Fri Sep 20 08:20:47 2002
+++ b/fs/bio.c	Fri Sep 20 08:20:47 2002
@@ -46,13 +46,11 @@
  */
 
 #define BV(x) { x, "biovec-" #x }
-static struct biovec_pool bvec_array[BIOVEC_NR_POOLS] = { 
-	BV(1), BV(4), BV(16), BV(64), BV(128), BV(256)
-}; 
+static struct biovec_pool bvec_array[BIOVEC_NR_POOLS] = {
+	BV(1), BV(4), BV(16), BV(64), BV(128), BV(BIO_MAX_PAGES),
+};
 #undef BV
 
-#define BIO_MAX_PAGES	(bvec_array[BIOVEC_NR_POOLS - 1].size)
-
 static void *slab_pool_alloc(int gfp_mask, void *data)
 {
 	return kmem_cache_alloc(data, gfp_mask);
@@ -77,7 +75,7 @@
 		case   5 ...  16: *idx = 2; break;
 		case  17 ...  64: *idx = 3; break;
 		case  65 ... 128: *idx = 4; break;
-		case 129 ... 256: *idx = 5; break;
+		case 129 ... BIO_MAX_PAGES: *idx = 5; break;
 		default:
 			return NULL;
 	}
@@ -103,7 +101,7 @@
 	/*
 	 * cloned bio doesn't own the veclist
 	 */
-	if (!(bio->bi_flags & (1 << BIO_CLONED)))
+	if (!bio_flagged(bio, BIO_CLONED))
 		mempool_free(bio->bi_io_vec, bp->pool);
 
 	mempool_free(bio, bio_pool);
@@ -112,7 +110,7 @@
 inline void bio_init(struct bio *bio)
 {
 	bio->bi_next = NULL;
-	bio->bi_flags = 0;
+	bio->bi_flags = 1 << BIO_UPTODATE;
 	bio->bi_rw = 0;
 	bio->bi_vcnt = 0;
 	bio->bi_idx = 0;
@@ -137,6 +135,7 @@
 {
 	struct bio *bio;
 	struct bio_vec *bvl = NULL;
+	int pf_flags = current->flags;
 
 	current->flags |= PF_NOWARN;
 	bio = mempool_alloc(bio_pool, gfp_mask);
@@ -153,7 +152,7 @@
 	mempool_free(bio, bio_pool);
 	bio = NULL;
 out:
-	current->flags &= ~PF_NOWARN;
+	current->flags = pf_flags;
 	return bio;
 }
 
@@ -180,7 +179,7 @@
 
 inline int bio_phys_segments(request_queue_t *q, struct bio *bio)
 {
-	if (unlikely(!(bio->bi_flags & (1 << BIO_SEG_VALID))))
+	if (unlikely(!bio_flagged(bio, BIO_SEG_VALID)))
 		blk_recount_segments(q, bio);
 
 	return bio->bi_phys_segments;
@@ -188,7 +187,7 @@
 
 inline int bio_hw_segments(request_queue_t *q, struct bio *bio)
 {
-	if (unlikely(!(bio->bi_flags & (1 << BIO_SEG_VALID))))
+	if (unlikely(!bio_flagged(bio, BIO_SEG_VALID)))
 		blk_recount_segments(q, bio);
 
 	return bio->bi_hw_segments;
@@ -218,7 +217,7 @@
 	 */
 	bio->bi_vcnt = bio_src->bi_vcnt;
 	bio->bi_idx = bio_src->bi_idx;
-	if (bio_src->bi_flags & (1 << BIO_SEG_VALID)) {
+	if (bio_flagged(bio, BIO_SEG_VALID)) {
 		bio->bi_phys_segments = bio_src->bi_phys_segments;
 		bio->bi_hw_segments = bio_src->bi_hw_segments;
 		bio->bi_flags |= (1 << BIO_SEG_VALID);
@@ -322,12 +321,97 @@
 	return NULL;
 }
 
-static void bio_end_io_kio(struct bio *bio)
+/**
+ *	bio_add_page	-	attempt to add page to bio
+ *	@bio: destination bio
+ *	@page: page to add
+ *	@len: vec entry length
+ *	@offset: vec entry offset
+ *
+ *	Attempt to add a page to the bio_vec maplist. This can fail for a
+ *	number of reasons, such as the bio being full or target block
+ *	device limitations.
+ */
+int bio_add_page(struct bio *bio, struct page *page, unsigned int len,
+		 unsigned int offset)
+{
+	request_queue_t *q = bdev_get_queue(bio->bi_bdev);
+	int fail_segments = 0, retried_segments = 0;
+	struct bio_vec *bvec;
+
+	/*
+	 * cloned bio must not modify vec list
+	 */
+	if (unlikely(bio_flagged(bio, BIO_CLONED)))
+		return 1;
+
+	/*
+	 * FIXME: change bi_max?
+	 */
+	BUG_ON(bio->bi_max > BIOVEC_NR_POOLS);
+
+	if (bio->bi_vcnt >= bvec_array[bio->bi_max].nr_vecs)
+		return 1;
+
+	if (((bio->bi_size + len) >> 9) > q->max_sectors)
+		return 1;
+
+	/*
+	 * we might loose a segment or two here, but rather that than
+	 * make this too complex.
+	 */
+retry_segments:
+	if (bio_phys_segments(q, bio) >= q->max_phys_segments
+	    || bio_hw_segments(q, bio) >= q->max_hw_segments)
+		fail_segments = 1;
+
+	if (fail_segments) {
+		if (retried_segments)
+			return 1;
+
+		bio->bi_flags &= ~(1 << BIO_SEG_VALID);
+		retried_segments = 1;
+		goto retry_segments;
+	}
+
+	/*
+	 * setup the new entry, we might clear it again later if we
+	 * cannot add the page
+	 */
+	bvec = &bio->bi_io_vec[bio->bi_vcnt];
+	bvec->bv_page = page;
+	bvec->bv_len = len;
+	bvec->bv_offset = offset;
+
+	/*
+	 * if queue has other restrictions (eg varying max sector size
+	 * depending on offset), it can specify a merge_bvec_fn in the
+	 * queue to get further control
+	 */
+	if (q->merge_bvec_fn && q->merge_bvec_fn(q, bio, bvec)) {
+		bvec->bv_page = NULL;
+		bvec->bv_len = 0;
+		bvec->bv_offset = 0;
+		return 1;
+	}
+
+	bio->bi_vcnt++;
+	bio->bi_phys_segments++;
+	bio->bi_hw_segments++;
+	bio->bi_size += len;
+	return 0;
+}
+
+static int bio_end_io_kio(struct bio *bio, unsigned int bytes_done, int error)
 {
 	struct kiobuf *kio = (struct kiobuf *) bio->bi_private;
 
-	end_kio_request(kio, test_bit(BIO_UPTODATE, &bio->bi_flags));
+	if (bio->bi_size)
+		return 1;
+
+	end_kio_request(kio, error);
 	bio_put(bio);
+	return 0;
 }
 
 /**
@@ -345,7 +429,6 @@
 void ll_rw_kio(int rw, struct kiobuf *kio, struct block_device *bdev, sector_t sector)
 {
 	int i, offset, size, err, map_i, total_nr_pages, nr_pages;
-	struct bio_vec *bvec;
 	struct bio *bio;
 
 	err = 0;
@@ -373,7 +456,7 @@
 	map_i = 0;
 
 next_chunk:
-	nr_pages = BIO_MAX_SECTORS >> (PAGE_SHIFT - 9);
+	nr_pages = BIO_MAX_PAGES;
 	if (nr_pages > total_nr_pages)
 		nr_pages = total_nr_pages;
 
@@ -393,8 +476,7 @@
 	bio->bi_end_io = bio_end_io_kio;
 	bio->bi_private = kio;
 
-	bvec = bio->bi_io_vec;
-	for (i = 0; i < nr_pages; i++, bvec++, map_i++) {
+	for (i = 0; i < nr_pages; i++, map_i++) {
 		int nbytes = PAGE_SIZE - offset;
 
 		if (nbytes > size)
@@ -402,15 +484,12 @@
 
 		BUG_ON(kio->maplist[map_i] == NULL);
 
-		if (bio->bi_size + nbytes > (BIO_MAX_SECTORS << 9))
-			goto queue_io;
-
-		bio->bi_vcnt++;
-		bio->bi_size += nbytes;
-
-		bvec->bv_page = kio->maplist[map_i];
-		bvec->bv_len = nbytes;
-		bvec->bv_offset = offset;
+		/*
+		 * if we can't add this page to the bio, submit for i/o
+		 * and alloc a new one if needed
+		 */
+		if (bio_add_page(bio, kio->maplist[map_i], nbytes, offset))
+			break;
 
 		/*
 		 * kiobuf only has an offset into the first page
@@ -423,7 +502,6 @@
 		kio->offset += nbytes;
 	}
 
-queue_io:
 	submit_bio(rw, bio);
 
 	if (total_nr_pages)
@@ -446,15 +524,33 @@
 	end_kio_request(kio, !err);
 }
 
-void bio_endio(struct bio *bio, int uptodate)
+/**
+ * bio_endio - end I/O on a bio
+ * @bio:	bio
+ * @bytes_done:	number of bytes completed
+ * @error:	error, if any
+ *
+ * Description:
+ *   bio_endio() will end I/O @bytes_done number of bytes. This may be just
+ *   a partial part of the bio, or it may be the whole bio. bio_endio() is
+ *   the preferred way to end I/O on a bio, it takes care of decrementing
+ *   bi_size and clearing BIO_UPTODATE on error. @error is 0 on success, and
+ *   and one of the established -Exxxx (-EIO, for instance) error values in
+ *   case something went wrong.
+ **/
+int bio_endio(struct bio *bio, unsigned int bytes_done, int error)
 {
-	if (uptodate)
-		set_bit(BIO_UPTODATE, &bio->bi_flags);
-	else
+	if (error)
 		clear_bit(BIO_UPTODATE, &bio->bi_flags);
 
-	if (bio->bi_end_io)
-		bio->bi_end_io(bio);
+	if (unlikely(bytes_done > bio->bi_size)) {
+		printk("%s: want %u bytes done, only %u left\n", __FUNCTION__,
+						bytes_done, bio->bi_size);
+		bytes_done = bio->bi_size;
+	}
+
+	bio->bi_size -= bytes_done;
+	return bio->bi_end_io(bio, bytes_done, error);
 }
 
 static void __init biovec_init_pools(void)
@@ -538,3 +634,4 @@
 EXPORT_SYMBOL(bio_clone);
 EXPORT_SYMBOL(bio_phys_segments);
 EXPORT_SYMBOL(bio_hw_segments);
+EXPORT_SYMBOL(bio_add_page);
diff -Nru a/fs/block_dev.c b/fs/block_dev.c
--- a/fs/block_dev.c	Fri Sep 20 08:20:48 2002
+++ b/fs/block_dev.c	Fri Sep 20 08:20:48 2002
@@ -198,9 +198,9 @@
 }
 
 static struct file_system_type bd_type = {
-	name:		"bdev",
-	get_sb:		bd_get_sb,
-	kill_sb:	kill_anon_super,
+	.name		= "bdev",
+	.get_sb		= bd_get_sb,
+	.kill_sb	= kill_anon_super,
 };
 
 static struct vfsmount *bd_mnt;
diff -Nru a/fs/buffer.c b/fs/buffer.c
--- a/fs/buffer.c	Fri Sep 20 08:20:46 2002
+++ b/fs/buffer.c	Fri Sep 20 08:20:46 2002
@@ -35,6 +35,7 @@
 #include <linux/hash.h>
 #include <linux/suspend.h>
 #include <linux/buffer_head.h>
+#include <linux/bio.h>
 #include <asm/bitops.h>
 
 static void invalidate_bh_lrus(void);
@@ -936,9 +937,11 @@
 	head = NULL;
 	offset = PAGE_SIZE;
 	while ((offset -= size) >= 0) {
+		int pf_flags = current->flags;
+
 		current->flags |= PF_NOWARN;
 		bh = alloc_buffer_head();
-		current->flags &= ~PF_NOWARN;
+		current->flags = pf_flags;
 		if (!bh)
 			goto no_grow;
 
@@ -1622,6 +1625,7 @@
 		__brelse(old_bh);
 	}
 }
+EXPORT_SYMBOL(unmap_underlying_metadata);
 
 /*
  * NOTE! All mapped/uptodate combinations are valid:
@@ -2409,6 +2413,155 @@
 	}
 
 	return err ? err : transferred;
+}
+
+static int end_bio_bh_io_sync(struct bio *bio, unsigned int bytes_done, int err)
+{
+	struct buffer_head *bh = bio->bi_private;
+
+	if (bio->bi_size)
+		return 1;
+
+	bh->b_end_io(bh, test_bit(BIO_UPTODATE, &bio->bi_flags));
+	bio_put(bio);
+	return 0;
+}
+
+int submit_bh(int rw, struct buffer_head * bh)
+{
+	struct bio *bio;
+
+	BUG_ON(!buffer_locked(bh));
+	BUG_ON(!buffer_mapped(bh));
+	BUG_ON(!bh->b_end_io);
+
+	if ((rw == READ || rw == READA) && buffer_uptodate(bh))
+		buffer_error();
+	if (rw == WRITE && !buffer_uptodate(bh))
+		buffer_error();
+	if (rw == READ && buffer_dirty(bh))
+		buffer_error();
+				
+	set_buffer_req(bh);
+
+	/*
+	 * from here on down, it's all bio -- do the initial mapping,
+	 * submit_bio -> generic_make_request may further map this bio around
+	 */
+	bio = bio_alloc(GFP_NOIO, 1);
+
+	bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9);
+	bio->bi_bdev = bh->b_bdev;
+	bio->bi_io_vec[0].bv_page = bh->b_page;
+	bio->bi_io_vec[0].bv_len = bh->b_size;
+	bio->bi_io_vec[0].bv_offset = bh_offset(bh);
+
+	bio->bi_vcnt = 1;
+	bio->bi_idx = 0;
+	bio->bi_size = bh->b_size;
+
+	bio->bi_end_io = end_bio_bh_io_sync;
+	bio->bi_private = bh;
+
+	return submit_bio(rw, bio);
+}
+
+/**
+ * ll_rw_block: low-level access to block devices (DEPRECATED)
+ * @rw: whether to %READ or %WRITE or maybe %READA (readahead)
+ * @nr: number of &struct buffer_heads in the array
+ * @bhs: array of pointers to &struct buffer_head
+ *
+ * ll_rw_block() takes an array of pointers to &struct buffer_heads,
+ * and requests an I/O operation on them, either a %READ or a %WRITE.
+ * The third %READA option is described in the documentation for
+ * generic_make_request() which ll_rw_block() calls.
+ *
+ * This function drops any buffer that it cannot get a lock on (with the
+ * BH_Lock state bit), any buffer that appears to be clean when doing a
+ * write request, and any buffer that appears to be up-to-date when doing
+ * read request.  Further it marks as clean buffers that are processed for
+ * writing (the buffer cache wont assume that they are actually clean until
+ * the buffer gets unlocked).
+ *
+ * ll_rw_block sets b_end_io to simple completion handler that marks
+ * the buffer up-to-date (if approriate), unlocks the buffer and wakes
+ * any waiters. 
+ *
+ * All of the buffers must be for the same device, and must also be a
+ * multiple of the current approved size for the device.
+ */
+void ll_rw_block(int rw, int nr, struct buffer_head * bhs[])
+{
+	unsigned int major;
+	int correct_size;
+	int i;
+
+	if (!nr)
+		return;
+
+	major = major(to_kdev_t(bhs[0]->b_bdev->bd_dev));
+
+	/* Determine correct block size for this device. */
+	correct_size = bdev_hardsect_size(bhs[0]->b_bdev);
+
+	/* Verify requested block sizes. */
+	for (i = 0; i < nr; i++) {
+		struct buffer_head *bh = bhs[i];
+		if (bh->b_size & (correct_size - 1)) {
+			printk(KERN_NOTICE "ll_rw_block: device %s: "
+			       "only %d-char blocks implemented (%u)\n",
+			       bdevname(bhs[0]->b_bdev),
+			       correct_size, bh->b_size);
+			goto sorry;
+		}
+	}
+
+	if ((rw & WRITE) && bdev_read_only(bhs[0]->b_bdev)) {
+		printk(KERN_NOTICE "Can't write to read-only device %s\n",
+		       bdevname(bhs[0]->b_bdev));
+		goto sorry;
+	}
+
+	for (i = 0; i < nr; i++) {
+		struct buffer_head *bh = bhs[i];
+
+		/* Only one thread can actually submit the I/O. */
+		if (test_set_buffer_locked(bh))
+			continue;
+
+		/* We have the buffer lock */
+		atomic_inc(&bh->b_count);
+		bh->b_end_io = end_buffer_io_sync;
+
+		switch(rw) {
+		case WRITE:
+			if (!test_clear_buffer_dirty(bh))
+				/* Hmmph! Nothing to write */
+				goto end_io;
+			break;
+
+		case READA:
+		case READ:
+			if (buffer_uptodate(bh))
+				/* Hmmph! Already have it */
+				goto end_io;
+			break;
+		default:
+			BUG();
+	end_io:
+			bh->b_end_io(bh, buffer_uptodate(bh));
+			continue;
+		}
+
+		submit_bh(rw, bh);
+	}
+	return;
+
+sorry:
+	/* Make sure we don't get infinite dirty retries.. */
+	for (i = 0; i < nr; i++)
+		clear_buffer_dirty(bhs[i]);
 }
 
 /*
diff -Nru a/fs/devices.c b/fs/devices.c
--- a/fs/devices.c	Fri Sep 20 08:20:46 2002
+++ b/fs/devices.c	Fri Sep 20 08:20:46 2002
@@ -168,7 +168,7 @@
  * depending on the special file...
  */
 static struct file_operations def_chr_fops = {
-	open:		chrdev_open,
+	.open		= chrdev_open,
 };
 
 /*
@@ -199,7 +199,7 @@
 }
 
 static struct file_operations bad_sock_fops = {
-	open:		sock_no_open
+	.open		= sock_no_open
 };
 
 void init_special_inode(struct inode *inode, umode_t mode, int rdev)
diff -Nru a/fs/direct-io.c b/fs/direct-io.c
--- a/fs/direct-io.c	Fri Sep 20 08:20:46 2002
+++ b/fs/direct-io.c	Fri Sep 20 08:20:46 2002
@@ -151,17 +151,21 @@
  * During I/O bi_private points at the dio.  After I/O, bi_private is used to
  * implement a singly-linked list of completed BIOs, at dio->bio_list.
  */
-static void dio_bio_end_io(struct bio *bio)
+static int dio_bio_end_io(struct bio *bio, unsigned int bytes_done, int error)
 {
 	struct dio *dio = bio->bi_private;
 	unsigned long flags;
 
+	if (bio->bi_size)
+		return 1;
+
 	spin_lock_irqsave(&dio->bio_list_lock, flags);
 	bio->bi_private = dio->bio_list;
 	dio->bio_list = bio;
 	if (dio->waiter)
 		wake_up_process(dio->waiter);
 	spin_unlock_irqrestore(&dio->bio_list_lock, flags);
+	return 0;
 }
 
 static int
diff -Nru a/fs/dquot.c b/fs/dquot.c
--- a/fs/dquot.c	Fri Sep 20 08:20:47 2002
+++ b/fs/dquot.c	Fri Sep 20 08:20:47 2002
@@ -1211,13 +1211,13 @@
  * Definitions of diskquota operations.
  */
 struct dquot_operations dquot_operations = {
-	initialize:	dquot_initialize,		/* mandatory */
-	drop:		dquot_drop,			/* mandatory */
-	alloc_space:	dquot_alloc_space,
-	alloc_inode:	dquot_alloc_inode,
-	free_space:	dquot_free_space,
-	free_inode:	dquot_free_inode,
-	transfer:	dquot_transfer
+	.initialize	= dquot_initialize,		/* mandatory */
+	.drop		= dquot_drop,			/* mandatory */
+	.alloc_space	= dquot_alloc_space,
+	.alloc_inode	= dquot_alloc_inode,
+	.free_space	= dquot_free_space,
+	.free_inode	= dquot_free_inode,
+	.transfer	= dquot_transfer
 };
 
 static inline void set_enable_flags(struct quota_info *dqopt, int type)
@@ -1471,13 +1471,13 @@
 }
 
 struct quotactl_ops vfs_quotactl_ops = {
-	quota_on:	vfs_quota_on,
-	quota_off:	vfs_quota_off,
-	quota_sync:	vfs_quota_sync,
-	get_info:	vfs_get_dqinfo,
-	set_info:	vfs_set_dqinfo,
-	get_dqblk:	vfs_get_dqblk,
-	set_dqblk:	vfs_set_dqblk
+	.quota_on	= vfs_quota_on,
+	.quota_off	= vfs_quota_off,
+	.quota_sync	= vfs_quota_sync,
+	.get_info	= vfs_get_dqinfo,
+	.set_info	= vfs_set_dqinfo,
+	.get_dqblk	= vfs_get_dqblk,
+	.set_dqblk	= vfs_set_dqblk
 };
 
 static ctl_table fs_dqstats_table[] = {
diff -Nru a/fs/driverfs/inode.c b/fs/driverfs/inode.c
--- a/fs/driverfs/inode.c	Fri Sep 20 08:20:42 2002
+++ b/fs/driverfs/inode.c	Fri Sep 20 08:20:42 2002
@@ -150,7 +150,6 @@
 	inode = driverfs_get_inode(dir->i_sb, mode, dev);
 	if (inode) {
 		d_instantiate(dentry, inode);
-		dget(dentry);
 		error = 0;
 	}
 	return error;
@@ -223,48 +222,10 @@
 	struct inode *inode = dentry->d_inode;
 	down(&inode->i_sem);
 	dentry->d_inode->i_nlink--;
-	dput(dentry);
 	up(&inode->i_sem);
-	d_delete(dentry);
-	return 0;
-}
-
-static void d_unhash(struct dentry *dentry)
-{
-	dget(dentry);
-	spin_lock(&dcache_lock);
-	switch (atomic_read(&dentry->d_count)) {
-	default:
-		spin_unlock(&dcache_lock);
-		shrink_dcache_parent(dentry);
-		spin_lock(&dcache_lock);
-		if (atomic_read(&dentry->d_count) != 2)
-			break;
-	case 2:
-		list_del_init(&dentry->d_hash);
-	}
-	spin_unlock(&dcache_lock);
-}
-
-static int driverfs_rmdir(struct inode *dir, struct dentry *dentry)
-{
-	int error = -ENOTEMPTY;
-	struct inode * inode = dentry->d_inode;
-
-	down(&inode->i_sem);
-	d_unhash(dentry);
-	if (driverfs_empty(dentry)) {
-		dentry->d_inode->i_nlink -= 2;
-		dput(dentry);
-		inode->i_flags |= S_DEAD;
-		dir->i_nlink--;
-		error = 0;
-	}
-	up(&inode->i_sem);
-	if (!error)
-		d_delete(dentry);
+	d_invalidate(dentry);
 	dput(dentry);
-	return error;
+	return 0;
 }
 
 /**
@@ -622,9 +583,6 @@
 	if (!entry || !parent)
 		return -EINVAL;
 
-	/* make sure we're mounted */
-	get_mount();
-
 	if (!parent->dentry) {
 		put_mount();
 		return -EINVAL;
@@ -638,8 +596,6 @@
 	} else
 		error = PTR_ERR(dentry);
 	up(&parent->dentry->d_inode->i_sem);
-	if (error)
-		put_mount();
 	return error;
 }
 
@@ -659,8 +615,6 @@
 	if (!parent)
 		return -EINVAL;
 
-	get_mount();
-
 	if (!parent->dentry) {
 		put_mount();
 		return -EINVAL;
@@ -672,8 +626,6 @@
 	else
 		error = PTR_ERR(dentry);
 	up(&parent->dentry->d_inode->i_sem);
-	if (error)
-		put_mount();
 	return error;
 }
 
@@ -699,8 +651,6 @@
 		if (dentry->d_inode && 
 		    (dentry->d_parent->d_inode == dir->dentry->d_inode)) {
 			driverfs_unlink(dir->dentry->d_inode,dentry);
-			dput(dentry);
-			put_mount();
 		}
 	}
 	up(&dir->dentry->d_inode->i_sem);
@@ -711,33 +661,39 @@
  * @dir:	directory to remove
  *
  * To make sure we don't orphan anyone, first remove
- * all the children in the list, then do vfs_rmdir() to remove it
- * and decrement the refcount..
+ * all the children in the list, then do clean up the directory.
  */
 void driverfs_remove_dir(struct driver_dir_entry * dir)
 {
-	struct list_head * node;
+	struct list_head * node, * next;
 	struct dentry * dentry = dir->dentry;
+	struct dentry * parent;
 
 	if (!dentry)
 		goto done;
 
-	down(&dentry->d_parent->d_inode->i_sem);
+	parent = dget(dentry->d_parent);
+	down(&parent->d_inode->i_sem);
 	down(&dentry->d_inode->i_sem);
 
-	node = dentry->d_subdirs.next;
-	while (node != &dentry->d_subdirs) {
+	list_for_each_safe(node,next,&dentry->d_subdirs) {
 		struct dentry * d = list_entry(node,struct dentry,d_child);
+		/* make sure dentry is still there */
+		if (d->d_inode)
+			driverfs_unlink(dentry->d_inode,d);
+	}
 
-		node = node->next;
-		driverfs_unlink(dentry->d_inode,d);
-		dput(d);
-		put_mount();
+	d_invalidate(dentry);
+	if (driverfs_empty(dentry)) {
+		dentry->d_inode->i_nlink -= 2;
+		dentry->d_inode->i_flags |= S_DEAD;
+		parent->d_inode->i_nlink--;
 	}
 	up(&dentry->d_inode->i_sem);
-	driverfs_rmdir(dentry->d_parent->d_inode,dentry);
-	up(&dentry->d_parent->d_inode->i_sem);
 	dput(dentry);
+
+	up(&parent->d_inode->i_sem);
+	dput(parent);
  done:
 	put_mount();
 }
diff -Nru a/fs/exec.c b/fs/exec.c
--- a/fs/exec.c	Fri Sep 20 08:20:44 2002
+++ b/fs/exec.c	Fri Sep 20 08:20:44 2002
@@ -609,8 +609,6 @@
 
 		ptrace_unlink(leader);
 		ptrace_unlink(current);
-		unhash_pid(current);
-		unhash_pid(leader);
 		remove_parent(current);
 		remove_parent(leader);
 		/*
@@ -631,8 +629,6 @@
 			current->ptrace = ptrace;
 			__ptrace_link(current, parent);
 		}
-		hash_pid(current);
-		hash_pid(leader);
 		
 		list_add_tail(&current->tasks, &init_task.tasks);
 		state = leader->state;
diff -Nru a/fs/ext2/inode.c b/fs/ext2/inode.c
--- a/fs/ext2/inode.c	Fri Sep 20 08:20:41 2002
+++ b/fs/ext2/inode.c	Fri Sep 20 08:20:41 2002
@@ -627,13 +627,13 @@
 }
 
 static int
-ext2_writepages(struct address_space *mapping, int *nr_to_write)
+ext2_writepages(struct address_space *mapping, struct writeback_control *wbc)
 {
 	int ret;
 	int err;
 
 	ret = write_mapping_buffers(mapping);
-	err = mpage_writepages(mapping, nr_to_write, ext2_get_block);
+	err = mpage_writepages(mapping, wbc, ext2_get_block);
 	if (!ret)
 		ret = err;
 	return ret;
diff -Nru a/fs/ext3/inode.c b/fs/ext3/inode.c
--- a/fs/ext3/inode.c	Fri Sep 20 08:20:47 2002
+++ b/fs/ext3/inode.c	Fri Sep 20 08:20:47 2002
@@ -1475,13 +1475,13 @@
 /* For writeback mode, we can use mpage_writepages() */
 
 static int
-ext3_writepages(struct address_space *mapping, int *nr_to_write)
+ext3_writepages(struct address_space *mapping, struct writeback_control *wbc)
 {
 	int ret;
 	int err;
 
 	ret = write_mapping_buffers(mapping);
-	err = mpage_writepages(mapping, nr_to_write, ext3_get_block);
+	err = mpage_writepages(mapping, wbc, ext3_get_block);
 	if (!ret)
 		ret = err;
 	return ret;
diff -Nru a/fs/fcntl.c b/fs/fcntl.c
--- a/fs/fcntl.c	Fri Sep 20 08:20:41 2002
+++ b/fs/fcntl.c	Fri Sep 20 08:20:41 2002
@@ -480,7 +480,9 @@
 
 void send_sigio(struct fown_struct *fown, int fd, int band)
 {
-	struct task_struct * p;
+	struct task_struct *p;
+	struct list_head *l;
+	struct pid *pidptr;
 	int pid;
 	
 	read_lock(&fown->lock);
@@ -493,14 +495,8 @@
 		send_sigio_to_task(p, fown, fd, band);
 		goto out_unlock_task;
 	}
-	for_each_process(p) {
-		int match = p->pid;
-		if (pid < 0)
-			match = -p->pgrp;
-		if (pid != match)
-			continue;
-		send_sigio_to_task(p, fown, fd, band);
-	}
+	for_each_task_pid(-pid, PIDTYPE_PGID, p, l, pidptr)
+		send_sigio_to_task(p, fown,fd,band);
 out_unlock_task:
 	read_unlock(&tasklist_lock);
 out_unlock_fown:
diff -Nru a/fs/fifo.c b/fs/fifo.c
--- a/fs/fifo.c	Fri Sep 20 08:20:44 2002
+++ b/fs/fifo.c	Fri Sep 20 08:20:44 2002
@@ -154,5 +154,5 @@
  * depending on the access mode of the file...
  */
 struct file_operations def_fifo_fops = {
-	open:		fifo_open,	/* will set read or write pipe_fops */
+	.open		= fifo_open,	/* will set read or write pipe_fops */
 };
diff -Nru a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c
--- a/fs/freevxfs/vxfs_super.c	Fri Sep 20 08:20:47 2002
+++ b/fs/freevxfs/vxfs_super.c	Fri Sep 20 08:20:47 2002
@@ -235,11 +235,11 @@
 }
 
 static struct file_system_type vxfs_fs_type = {
-	owner:		THIS_MODULE,
-	name:		"vxfs",
-	get_sb:		vxfs_get_sb,
-	kill_sb:	kill_block_super,
-	fs_flags:	FS_REQUIRES_DEV,
+	.owner		= THIS_MODULE,
+	.name		= "vxfs",
+	.get_sb		= vxfs_get_sb,
+	.kill_sb	= kill_block_super,
+	.fs_flags	= FS_REQUIRES_DEV,
 };
 
 static int __init
diff -Nru a/fs/fs-writeback.c b/fs/fs-writeback.c
--- a/fs/fs-writeback.c	Fri Sep 20 08:20:46 2002
+++ b/fs/fs-writeback.c	Fri Sep 20 08:20:46 2002
@@ -111,8 +111,7 @@
 /*
  * Write a single inode's dirty pages and inode data out to disk.
  * If `sync' is set, wait on the writeout.
- * If `nr_to_write' is not NULL, subtract the number of written pages
- * from *nr_to_write.
+ * Subtract the number of written pages from nr_to_write.
  *
  * Normally it is not legal for a single process to lock more than one
  * page at a time, due to ab/ba deadlock problems.  But writepages()
@@ -127,7 +126,9 @@
  *
  * Called under inode_lock.
  */
-static void __sync_single_inode(struct inode *inode, int wait, int *nr_to_write)
+static void
+__sync_single_inode(struct inode *inode, int wait,
+			struct writeback_control *wbc)
 {
 	unsigned dirty;
 	unsigned long orig_dirtied_when;
@@ -144,7 +145,7 @@
 	mapping->dirtied_when = 0;	/* assume it's whole-file writeback */
 	spin_unlock(&inode_lock);
 
-	do_writepages(mapping, nr_to_write);
+	do_writepages(mapping, wbc);
 
 	/* Don't write the inode if only I_DIRTY_PAGES was set */
 	if (dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC))
@@ -181,7 +182,8 @@
  * Write out an inode's dirty pages.  Called under inode_lock.
  */
 static void
-__writeback_single_inode(struct inode *inode, int sync, int *nr_to_write)
+__writeback_single_inode(struct inode *inode, int sync,
+			struct writeback_control *wbc)
 {
 	if (current_is_pdflush() && (inode->i_state & I_LOCK))
 		return;
@@ -193,7 +195,7 @@
 		iput(inode);
 		spin_lock(&inode_lock);
 	}
-	__sync_single_inode(inode, sync, nr_to_write);
+	__sync_single_inode(inode, sync, wbc);
 }
 
 /*
@@ -226,8 +228,7 @@
  * thrlttled threads: we don't want them all piling up on __wait_on_inode.
  */
 static void
-sync_sb_inodes(struct backing_dev_info *single_bdi, struct super_block *sb,
-	int sync_mode, int *nr_to_write, unsigned long *older_than_this)
+sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc)
 {
 	struct list_head *tmp;
 	struct list_head *head;
@@ -241,7 +242,7 @@
 		struct backing_dev_info *bdi;
 		int really_sync;
 
-		if (single_bdi && mapping->backing_dev_info != single_bdi) {
+		if (wbc->bdi && mapping->backing_dev_info != wbc->bdi) {
 			if (sb != blockdev_superblock)
 				break;		/* inappropriate superblock */
 			list_move(&inode->i_list, &sb->s_dirty);
@@ -252,23 +253,20 @@
 		if (time_after(mapping->dirtied_when, start))
 			break;
 
-		if (older_than_this &&
-			time_after(mapping->dirtied_when, *older_than_this))
+		if (wbc->older_than_this && time_after(mapping->dirtied_when,
+						*wbc->older_than_this))
 			goto out;
 
 		bdi = mapping->backing_dev_info;
 		if (current_is_pdflush() && !writeback_acquire(bdi))
 			break;
 
-		really_sync = (sync_mode == WB_SYNC_ALL);
-		if ((sync_mode == WB_SYNC_LAST) && (head->prev == head))
-			really_sync = 1;
-
+		really_sync = (wbc->sync_mode == WB_SYNC_ALL);
 		BUG_ON(inode->i_state & I_FREEING);
 		__iget(inode);
 		list_move(&inode->i_list, &sb->s_dirty);
-		__writeback_single_inode(inode, really_sync, nr_to_write);
-		if (sync_mode == WB_SYNC_HOLD) {
+		__writeback_single_inode(inode, really_sync, wbc);
+		if (wbc->sync_mode == WB_SYNC_HOLD) {
 			mapping->dirtied_when = jiffies;
 			list_move(&inode->i_list, &sb->s_dirty);
 		}
@@ -277,7 +275,7 @@
 		spin_unlock(&inode_lock);
 		iput(inode);
 		spin_lock(&inode_lock);
-		if (nr_to_write && *nr_to_write <= 0)
+		if (wbc->nr_to_write <= 0)
 			break;
 	}
 out:
@@ -288,16 +286,26 @@
 }
 
 /*
+ * Start writeback of dirty pagecache data against all unlocked inodes.
+ *
+ * Note:
+ * We don't need to grab a reference to superblock here. If it has non-empty
+ * ->s_dirty it's hadn't been killed yet and kill_super() won't proceed
+ * past sync_inodes_sb() until both the ->s_dirty and ->s_io lists are
+ * empty. Since __sync_single_inode() regains inode_lock before it finally moves
+ * inode from superblock lists we are OK.
+ *
+ * If `older_than_this' is non-zero then only flush inodes which have a
+ * flushtime older than *older_than_this.
+ *
  * If `bdi' is non-zero then we will scan the first inode against each
  * superblock until we find the matching ones.  One group will be the dirty
  * inodes against a filesystem.  Then when we hit the dummy blockdev superblock,
  * sync_sb_inodes will seekout the blockdev which matches `bdi'.  Maybe not
  * super-efficient but we're about to do a ton of I/O...
  */
-static void
-__writeback_unlocked_inodes(struct backing_dev_info *bdi, int *nr_to_write,
-				enum writeback_sync_modes sync_mode,
-				unsigned long *older_than_this)
+void
+writeback_inodes(struct writeback_control *wbc)
 {
 	struct super_block *sb;
 
@@ -307,11 +315,10 @@
 	for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.prev)) {
 		if (!list_empty(&sb->s_dirty) || !list_empty(&sb->s_io)) {
 			spin_unlock(&sb_lock);
-			sync_sb_inodes(bdi, sb, sync_mode, nr_to_write,
-					older_than_this);
+			sync_sb_inodes(sb, wbc);
 			spin_lock(&sb_lock);
 		}
-		if (nr_to_write && *nr_to_write <= 0)
+		if (wbc->nr_to_write <= 0)
 			break;
 	}
 	spin_unlock(&sb_lock);
@@ -319,43 +326,6 @@
 }
 
 /*
- * Start writeback of dirty pagecache data against all unlocked inodes.
- *
- * Note:
- * We don't need to grab a reference to superblock here. If it has non-empty
- * ->s_dirty it's hadn't been killed yet and kill_super() won't proceed
- * past sync_inodes_sb() until both the ->s_dirty and ->s_io lists are
- * empty. Since __sync_single_inode() regains inode_lock before it finally moves
- * inode from superblock lists we are OK.
- *
- * If `older_than_this' is non-zero then only flush inodes which have a
- * flushtime older than *older_than_this.
- *
- * This is a "memory cleansing" operation, not a "data integrity" operation.
- */
-void writeback_unlocked_inodes(int *nr_to_write,
-				enum writeback_sync_modes sync_mode,
-				unsigned long *older_than_this)
-{
-	__writeback_unlocked_inodes(NULL, nr_to_write,
-				sync_mode, older_than_this);
-}
-/*
- * Perform writeback of dirty data against a particular queue.
- *
- * This is for writer throttling.  We don't want processes to write back
- * other process's data, espsecially when the other data belongs to a
- * different spindle.
- */
-void writeback_backing_dev(struct backing_dev_info *bdi, int *nr_to_write,
-			enum writeback_sync_modes sync_mode,
-			unsigned long *older_than_this)
-{
-	__writeback_unlocked_inodes(bdi, nr_to_write,
-				sync_mode, older_than_this);
-}
-
-/*
  * writeback and wait upon the filesystem's dirty inodes.  The caller will
  * do this in two passes - one to write, and one to wait.  WB_SYNC_HOLD is
  * used to park the written inodes on sb->s_dirty for the wait pass.
@@ -366,14 +336,17 @@
 void sync_inodes_sb(struct super_block *sb, int wait)
 {
 	struct page_state ps;
-	int nr_to_write;
+	struct writeback_control wbc = {
+		.bdi		= NULL,
+		.sync_mode	= wait ? WB_SYNC_ALL : WB_SYNC_HOLD,
+		.older_than_this = NULL,
+		.nr_to_write	= 0,
+	};
 
 	get_page_state(&ps);
-	nr_to_write = ps.nr_dirty + ps.nr_dirty / 4;
-
+	wbc.nr_to_write = ps.nr_dirty + ps.nr_dirty / 4;
 	spin_lock(&inode_lock);
-	sync_sb_inodes(NULL, sb, wait ? WB_SYNC_ALL : WB_SYNC_HOLD,
-				&nr_to_write, NULL);
+	sync_sb_inodes(sb, &wbc);
 	spin_unlock(&inode_lock);
 }
 
@@ -466,8 +439,12 @@
  
 void write_inode_now(struct inode *inode, int sync)
 {
+	struct writeback_control wbc = {
+		.nr_to_write = LONG_MAX,
+	};
+
 	spin_lock(&inode_lock);
-	__writeback_single_inode(inode, sync, NULL);
+	__writeback_single_inode(inode, sync, &wbc);
 	spin_unlock(&inode_lock);
 	if (sync)
 		wait_on_inode(inode);
diff -Nru a/fs/jfs/inode.c b/fs/jfs/inode.c
--- a/fs/jfs/inode.c	Fri Sep 20 08:20:41 2002
+++ b/fs/jfs/inode.c	Fri Sep 20 08:20:41 2002
@@ -282,9 +282,10 @@
 	return block_write_full_page(page, jfs_get_block);
 }
 
-static int jfs_writepages(struct address_space *mapping, int *nr_to_write)
+static int jfs_writepages(struct address_space *mapping,
+			struct writeback_control *wbc)
 {
-	return mpage_writepages(mapping, nr_to_write, jfs_get_block);
+	return mpage_writepages(mapping, wbc, jfs_get_block);
 }
 
 static int jfs_readpage(struct file *file, struct page *page)
diff -Nru a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
--- a/fs/jfs/jfs_logmgr.c	Fri Sep 20 08:20:46 2002
+++ b/fs/jfs/jfs_logmgr.c	Fri Sep 20 08:20:46 2002
@@ -1969,13 +1969,16 @@
  *
  * executed at INTIODONE level
  */
-static void lbmIODone(struct bio *bio)
+static int lbmIODone(struct bio *bio, unsigned int bytes_done, int error)
 {
 	struct lbuf *bp = bio->bi_private;
 	struct lbuf *nextbp, *tail;
 	struct jfs_log *log;
 	unsigned long flags;
 
+	if (bio->bi_size)
+		return 1;
+
 	/*
 	 * get back jfs buffer bound to the i/o buffer
 	 */
@@ -2004,7 +2007,7 @@
 		/* wakeup I/O initiator */
 		LCACHE_WAKEUP(&bp->l_ioevent);
 
-		return;
+		return 0;
 	}
 
 	/*
@@ -2029,7 +2032,7 @@
 	if (bp->l_flag & lbmDIRECT) {
 		LCACHE_WAKEUP(&bp->l_ioevent);
 		LCACHE_UNLOCK(flags);
-		return;
+		return 0;
 	}
 
 	tail = log->wqueue;
@@ -2108,6 +2111,8 @@
 
 		LCACHE_UNLOCK(flags);	/* unlock+enable */
 	}
+
+	return 0;
 }
 
 int jfsIOWait(void *arg)
diff -Nru a/fs/libfs.c b/fs/libfs.c
--- a/fs/libfs.c	Fri Sep 20 08:20:41 2002
+++ b/fs/libfs.c	Fri Sep 20 08:20:41 2002
@@ -32,7 +32,7 @@
  
 int dcache_dir_open(struct inode *inode, struct file *file)
 {
-	static struct qstr cursor_name = {len:1, name:"."};
+	static struct qstr cursor_name = {.len = 1, .name = "."};
 
 	file->private_data = d_alloc(file->f_dentry, &cursor_name);
 
@@ -151,15 +151,15 @@
 }
 
 struct file_operations simple_dir_operations = {
-	open:		dcache_dir_open,
-	release:	dcache_dir_close,
-	llseek:		dcache_dir_lseek,
-	read:		generic_read_dir,
-	readdir:	dcache_readdir,
+	.open		= dcache_dir_open,
+	.release	= dcache_dir_close,
+	.llseek		= dcache_dir_lseek,
+	.read		= generic_read_dir,
+	.readdir	= dcache_readdir,
 };
 
 struct inode_operations simple_dir_inode_operations = {
-	lookup:		simple_lookup,
+	.lookup		= simple_lookup,
 };
 
 /*
@@ -171,10 +171,10 @@
 	struct super_operations *ops, unsigned long magic)
 {
 	struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);
-	static struct super_operations default_ops = {statfs: simple_statfs};
+	static struct super_operations default_ops = {.statfs = simple_statfs};
 	struct dentry *dentry;
 	struct inode *root;
-	struct qstr d_name = {name:name, len:strlen(name)};
+	struct qstr d_name = {.name = name, .len = strlen(name)};
 
 	if (IS_ERR(s))
 		return s;
diff -Nru a/fs/mpage.c b/fs/mpage.c
--- a/fs/mpage.c	Fri Sep 20 08:20:43 2002
+++ b/fs/mpage.c	Fri Sep 20 08:20:43 2002
@@ -8,6 +8,8 @@
  *
  * 15May2002	akpm@zip.com.au
  *		Initial version
+ * 27Jun2002	axboe@suse.de
+ *		use bio_add_page() to build bio's just the right size
  */
 
 #include <linux/kernel.h>
@@ -23,12 +25,6 @@
 #include <linux/pagevec.h>
 
 /*
- * The largest-sized BIO which this code will assemble, in bytes.  Set this
- * to PAGE_CACHE_SIZE if your drivers are broken.
- */
-#define MPAGE_BIO_MAX_SIZE BIO_MAX_SIZE
-
-/*
  * I/O completion handler for multipage BIOs.
  *
  * The mpage code never puts partial pages into a BIO (except for end-of-file).
@@ -40,11 +36,14 @@
  * status of that page is hard.  See end_buffer_async_read() for the details.
  * There is no point in duplicating all that complexity.
  */
-static void mpage_end_io_read(struct bio *bio)
+static int mpage_end_io_read(struct bio *bio, unsigned int bytes_done, int err)
 {
 	const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
 	struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
 
+	if (bio->bi_size)
+		return 1;
+
 	do {
 		struct page *page = bvec->bv_page;
 
@@ -60,13 +59,17 @@
 		unlock_page(page);
 	} while (bvec >= bio->bi_io_vec);
 	bio_put(bio);
+	return 0;
 }
 
-static void mpage_end_io_write(struct bio *bio)
+static int mpage_end_io_write(struct bio *bio, unsigned int bytes_done, int err)
 {
 	const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
 	struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
 
+	if (bio->bi_size)
+		return 1;
+
 	do {
 		struct page *page = bvec->bv_page;
 
@@ -78,12 +81,11 @@
 		end_page_writeback(page);
 	} while (bvec >= bio->bi_io_vec);
 	bio_put(bio);
+	return 0;
 }
 
 struct bio *mpage_bio_submit(int rw, struct bio *bio)
 {
-	bio->bi_vcnt = bio->bi_idx;
-	bio->bi_idx = 0;
 	bio->bi_end_io = mpage_end_io_read;
 	if (rw == WRITE)
 		bio->bi_end_io = mpage_end_io_write;
@@ -106,11 +108,7 @@
 
 	if (bio) {
 		bio->bi_bdev = bdev;
-		bio->bi_vcnt = nr_vecs;
-		bio->bi_idx = 0;
-		bio->bi_size = 0;
 		bio->bi_sector = first_sector;
-		bio->bi_io_vec[0].bv_page = NULL;
 	}
 	return bio;
 }
@@ -169,7 +167,6 @@
 	const unsigned blkbits = inode->i_blkbits;
 	const unsigned blocks_per_page = PAGE_CACHE_SIZE >> blkbits;
 	const unsigned blocksize = 1 << blkbits;
-	struct bio_vec *bvec;
 	sector_t block_in_file;
 	sector_t last_block;
 	sector_t blocks[MAX_BUF_PER_PAGE];
@@ -223,26 +220,22 @@
 	/*
 	 * This page will go to BIO.  Do we need to send this BIO off first?
 	 */
-	if (bio && (bio->bi_idx == bio->bi_vcnt ||
-			*last_block_in_bio != blocks[0] - 1))
+	if (bio && (*last_block_in_bio != blocks[0] - 1))
 		bio = mpage_bio_submit(READ, bio);
 
+alloc_new:
 	if (bio == NULL) {
-		unsigned nr_bvecs = MPAGE_BIO_MAX_SIZE / PAGE_CACHE_SIZE;
-
-		if (nr_bvecs > nr_pages)
-			nr_bvecs = nr_pages;
 		bio = mpage_alloc(bdev, blocks[0] << (blkbits - 9),
-					nr_bvecs, GFP_KERNEL);
+					nr_pages, GFP_KERNEL);
 		if (bio == NULL)
 			goto confused;
 	}
 
-	bvec = &bio->bi_io_vec[bio->bi_idx++];
-	bvec->bv_page = page;
-	bvec->bv_len = (first_hole << blkbits);
-	bvec->bv_offset = 0;
-	bio->bi_size += bvec->bv_len;
+	if (bio_add_page(bio, page, first_hole << blkbits, 0)) {
+		bio = mpage_bio_submit(READ, bio);
+		goto alloc_new;
+	}
+
 	if (buffer_boundary(&bh) || (first_hole != blocks_per_page))
 		bio = mpage_bio_submit(READ, bio);
 	else
@@ -330,7 +323,6 @@
 	const unsigned blkbits = inode->i_blkbits;
 	unsigned long end_index;
 	const unsigned blocks_per_page = PAGE_CACHE_SIZE >> blkbits;
-	struct bio_vec *bvec;
 	sector_t last_block;
 	sector_t block_in_file;
 	sector_t blocks[MAX_BUF_PER_PAGE];
@@ -432,15 +424,15 @@
 	/*
 	 * This page will go to BIO.  Do we need to send this BIO off first?
 	 */
-	if (bio && (bio->bi_idx == bio->bi_vcnt ||
-				*last_block_in_bio != blocks[0] - 1))
+	if (bio && *last_block_in_bio != blocks[0] - 1)
 		bio = mpage_bio_submit(WRITE, bio);
 
+alloc_new:
 	if (bio == NULL) {
-		unsigned nr_bvecs = MPAGE_BIO_MAX_SIZE / PAGE_CACHE_SIZE;
+		const unsigned __nr_pages = 64;	/* FIXME */
 
 		bio = mpage_alloc(bdev, blocks[0] << (blkbits - 9),
-					nr_bvecs, GFP_NOFS|__GFP_HIGH);
+					__nr_pages, GFP_NOFS|__GFP_HIGH);
 		if (bio == NULL)
 			goto confused;
 	}
@@ -465,11 +457,11 @@
 			try_to_free_buffers(page);
 	}
 
-	bvec = &bio->bi_io_vec[bio->bi_idx++];
-	bvec->bv_page = page;
-	bvec->bv_len = (first_unmapped << blkbits);
-	bvec->bv_offset = 0;
-	bio->bi_size += bvec->bv_len;
+	if (bio_add_page(bio, page, first_unmapped << blkbits, 0)) {
+		bio = mpage_bio_submit(WRITE, bio);
+		goto alloc_new;
+	}
+
 	BUG_ON(PageWriteback(page));
 	SetPageWriteback(page);
 	unlock_page(page);
@@ -492,7 +484,7 @@
  * address space and writepage() all of them.
  * 
  * @mapping: address space structure to write
- * @nr_to_write: subtract the number of written pages from *@nr_to_write
+ * @wbc: subtract the number of written pages from *@wbc->nr_to_write
  * @get_block: the filesystem's block mapper function.
  *             If this is NULL then use a_ops->writepage.  Otherwise, go
  *             direct-to-BIO.
@@ -528,7 +520,7 @@
  */
 int
 mpage_writepages(struct address_space *mapping,
-			int *nr_to_write, get_block_t get_block)
+		struct writeback_control *wbc, get_block_t get_block)
 {
 	struct bio *bio = NULL;
 	sector_t last_block_in_bio = 0;
@@ -591,7 +583,7 @@
 				__set_page_dirty_nobuffers(page);
 				ret = 0;
 			}
-			if (ret || (nr_to_write && --(*nr_to_write) <= 0))
+			if (ret || (--(wbc->nr_to_write) <= 0))
 				done = 1;
 		} else {
 			unlock_page(page);
diff -Nru a/fs/namei.c b/fs/namei.c
--- a/fs/namei.c	Fri Sep 20 08:20:44 2002
+++ b/fs/namei.c	Fri Sep 20 08:20:44 2002
@@ -2230,6 +2230,6 @@
 }
 
 struct inode_operations page_symlink_inode_operations = {
-	readlink:	page_readlink,
-	follow_link:	page_follow_link,
+	.readlink	= page_readlink,
+	.follow_link	= page_follow_link,
 };
diff -Nru a/fs/namespace.c b/fs/namespace.c
--- a/fs/namespace.c	Fri Sep 20 08:20:47 2002
+++ b/fs/namespace.c	Fri Sep 20 08:20:47 2002
@@ -239,10 +239,10 @@
 }
 
 struct seq_operations mounts_op = {
-	start:	m_start,
-	next:	m_next,
-	stop:	m_stop,
-	show:	show_vfsmnt
+	.start	= m_start,
+	.next	= m_next,
+	.stop	= m_stop,
+	.show	= show_vfsmnt
 };
 
 /*
diff -Nru a/fs/nfs/inode.c b/fs/nfs/inode.c
--- a/fs/nfs/inode.c	Fri Sep 20 08:20:47 2002
+++ b/fs/nfs/inode.c	Fri Sep 20 08:20:47 2002
@@ -245,7 +245,7 @@
 	struct rpc_xprt		*xprt = NULL;
 	struct rpc_clnt		*clnt = NULL;
 	struct inode		*root_inode = NULL;
-	unsigned int		authflavor;
+	rpc_authflavor_t	authflavor;
 	struct rpc_timeout	timeparms;
 	struct nfs_fsinfo	fsinfo;
 	int			tcp, version, maxlen;
diff -Nru a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
--- a/fs/nfs/nfs2xdr.c	Fri Sep 20 08:20:44 2002
+++ b/fs/nfs/nfs2xdr.c	Fri Sep 20 08:20:44 2002
@@ -251,7 +251,7 @@
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 	if (iov->iov_len < hdrlen) {
 		printk(KERN_WARNING "NFS: READ reply header overflowed:"
-				"length %d > %d\n", hdrlen, iov->iov_len);
+				"length %d > %Zu\n", hdrlen, iov->iov_len);
 		return -errno_NFSERR_IO;
 	} else if (iov->iov_len != hdrlen) {
 		dprintk("NFS: READ header is short. iovec will be shifted.\n");
@@ -404,7 +404,7 @@
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 	if (iov->iov_len < hdrlen) {
 		printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
-				"length %d > %d\n", hdrlen, iov->iov_len);
+				"length %d > %Zu\n", hdrlen, iov->iov_len);
 		return -errno_NFSERR_IO;
 	} else if (iov->iov_len != hdrlen) {
 		dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
diff -Nru a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
--- a/fs/nfs/nfs3xdr.c	Fri Sep 20 08:20:48 2002
+++ b/fs/nfs/nfs3xdr.c	Fri Sep 20 08:20:48 2002
@@ -525,7 +525,7 @@
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 	if (iov->iov_len < hdrlen) {
 		printk(KERN_WARNING "NFS: READDIR reply header overflowed:"
-				"length %d > %d\n", hdrlen, iov->iov_len);
+				"length %d > %Zu\n", hdrlen, iov->iov_len);
 		return -errno_NFSERR_IO;
 	} else if (iov->iov_len != hdrlen) {
 		dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
@@ -808,7 +808,7 @@
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 	if (iov->iov_len < hdrlen) {
 		printk(KERN_WARNING "NFS: READ reply header overflowed:"
-				"length %d > %d\n", hdrlen, iov->iov_len);
+				"length %d > %Zu\n", hdrlen, iov->iov_len);
        		return -errno_NFSERR_IO;
 	} else if (iov->iov_len != hdrlen) {
 		dprintk("NFS: READ header is short. iovec will be shifted.\n");
diff -Nru a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c
--- a/fs/nfsd/nfscache.c	Fri Sep 20 08:20:48 2002
+++ b/fs/nfsd/nfscache.c	Fri Sep 20 08:20:48 2002
@@ -272,7 +272,7 @@
 	case RC_NOCACHE:
 		break;
 	case RC_REPLSTAT:
-		svc_putlong(&rqstp->rq_resbuf, rp->c_replstat);
+		svc_putu32(&rqstp->rq_resbuf, rp->c_replstat);
 		rtn = RC_REPLY;
 		break;
 	case RC_REPLBUFF:
diff -Nru a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
--- a/fs/nfsd/nfssvc.c	Fri Sep 20 08:20:41 2002
+++ b/fs/nfsd/nfssvc.c	Fri Sep 20 08:20:41 2002
@@ -302,7 +302,7 @@
 	}
 		
 	if (rqstp->rq_proc != 0)
-		svc_putlong(&rqstp->rq_resbuf, nfserr);
+		svc_putu32(&rqstp->rq_resbuf, nfserr);
 
 	/* Encode result.
 	 * For NFSv2, additional info is never returned in case of an error.
diff -Nru a/fs/pipe.c b/fs/pipe.c
--- a/fs/pipe.c	Fri Sep 20 08:20:41 2002
+++ b/fs/pipe.c	Fri Sep 20 08:20:41 2002
@@ -444,69 +444,69 @@
  * are also used in linux/fs/fifo.c to do operations on FIFOs.
  */
 struct file_operations read_fifo_fops = {
-	llseek:		no_llseek,
-	read:		pipe_read,
-	write:		bad_pipe_w,
-	poll:		fifo_poll,
-	ioctl:		pipe_ioctl,
-	open:		pipe_read_open,
-	release:	pipe_read_release,
-	fasync:         pipe_read_fasync,
+	.llseek		= no_llseek,
+	.read		= pipe_read,
+	.write		= bad_pipe_w,
+	.poll		= fifo_poll,
+	.ioctl		= pipe_ioctl,
+	.open		= pipe_read_open,
+	.release	= pipe_read_release,
+	.fasync         = pipe_read_fasync,
 };
 
 struct file_operations write_fifo_fops = {
-	llseek:		no_llseek,
-	read:		bad_pipe_r,
-	write:		pipe_write,
-	poll:		fifo_poll,
-	ioctl:		pipe_ioctl,
-	open:		pipe_write_open,
-	release:	pipe_write_release,
-	fasync:         pipe_write_fasync,
+	.llseek		= no_llseek,
+	.read		= bad_pipe_r,
+	.write		= pipe_write,
+	.poll		= fifo_poll,
+	.ioctl		= pipe_ioctl,
+	.open		= pipe_write_open,
+	.release	= pipe_write_release,
+	.fasync         = pipe_write_fasync,
 };
 
 struct file_operations rdwr_fifo_fops = {
-	llseek:		no_llseek,
-	read:		pipe_read,
-	write:		pipe_write,
-	poll:		fifo_poll,
-	ioctl:		pipe_ioctl,
-	open:		pipe_rdwr_open,
-	release:	pipe_rdwr_release,
-	fasync:         pipe_rdwr_fasync,
+	.llseek		= no_llseek,
+	.read		= pipe_read,
+	.write		= pipe_write,
+	.poll		= fifo_poll,
+	.ioctl		= pipe_ioctl,
+	.open		= pipe_rdwr_open,
+	.release	= pipe_rdwr_release,
+	.fasync         = pipe_rdwr_fasync,
 };
 
 struct file_operations read_pipe_fops = {
-	llseek:		no_llseek,
-	read:		pipe_read,
-	write:		bad_pipe_w,
-	poll:		pipe_poll,
-	ioctl:		pipe_ioctl,
-	open:		pipe_read_open,
-	release:	pipe_read_release,
-	fasync:         pipe_read_fasync,
+	.llseek		= no_llseek,
+	.read		= pipe_read,
+	.write		= bad_pipe_w,
+	.poll		= pipe_poll,
+	.ioctl		= pipe_ioctl,
+	.open		= pipe_read_open,
+	.release	= pipe_read_release,
+	.fasync         = pipe_read_fasync,
 };
 
 struct file_operations write_pipe_fops = {
-	llseek:		no_llseek,
-	read:		bad_pipe_r,
-	write:		pipe_write,
-	poll:		pipe_poll,
-	ioctl:		pipe_ioctl,
-	open:		pipe_write_open,
-	release:	pipe_write_release,
-	fasync:         pipe_write_fasync,
+	.llseek		= no_llseek,
+	.read		= bad_pipe_r,
+	.write		= pipe_write,
+	.poll		= pipe_poll,
+	.ioctl		= pipe_ioctl,
+	.open		= pipe_write_open,
+	.release	= pipe_write_release,
+	.fasync         = pipe_write_fasync,
 };
 
 struct file_operations rdwr_pipe_fops = {
-	llseek:		no_llseek,
-	read:		pipe_read,
-	write:		pipe_write,
-	poll:		pipe_poll,
-	ioctl:		pipe_ioctl,
-	open:		pipe_rdwr_open,
-	release:	pipe_rdwr_release,
-	fasync:         pipe_rdwr_fasync,
+	.llseek		= no_llseek,
+	.read		= pipe_read,
+	.write		= pipe_write,
+	.poll		= pipe_poll,
+	.ioctl		= pipe_ioctl,
+	.open		= pipe_rdwr_open,
+	.release	= pipe_rdwr_release,
+	.fasync         = pipe_rdwr_fasync,
 };
 
 struct inode* pipe_new(struct inode* inode)
@@ -541,7 +541,7 @@
 	return 1;
 }
 static struct dentry_operations pipefs_dentry_operations = {
-	d_delete:	pipefs_delete_dentry,
+	.d_delete	= pipefs_delete_dentry,
 };
 
 static struct inode * get_pipe_inode(void)
@@ -672,9 +672,9 @@
 }
 
 static struct file_system_type pipe_fs_type = {
-	name:		"pipefs",
-	get_sb:		pipefs_get_sb,
-	kill_sb:	kill_anon_super,
+	.name		= "pipefs",
+	.get_sb		= pipefs_get_sb,
+	.kill_sb	= kill_anon_super,
 };
 
 static int __init init_pipe_fs(void)
diff -Nru a/fs/proc/array.c b/fs/proc/array.c
--- a/fs/proc/array.c	Fri Sep 20 08:20:47 2002
+++ b/fs/proc/array.c	Fri Sep 20 08:20:47 2002
@@ -394,131 +394,40 @@
 	return res;
 }
 		
-static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size, int * pages, int * shared, int * dirty, int * total)
+int proc_pid_statm(task_t *task, char *buffer)
 {
-	unsigned long end, pmd_end;
-	pte_t *pte;
-
-	if (pmd_none(*pmd))
-		return;
-	if (pmd_bad(*pmd)) {
-		pmd_ERROR(*pmd);
-		pmd_clear(pmd);
-		return;
-	}
-	preempt_disable();
-	pte = pte_offset_map(pmd, address);
-	end = address + size;
-	pmd_end = (address + PMD_SIZE) & PMD_MASK;
-	if (end > pmd_end)
-		end = pmd_end;
-	do {
-		pte_t page = *pte;
-		struct page *ptpage;
-		unsigned long pfn;
-
-		address += PAGE_SIZE;
-		pte++;
-		if (pte_none(page))
-			continue;
-		++*total;
-		if (!pte_present(page))
-			continue;
-		pfn = pte_pfn(page);
-		if (!pfn_valid(pfn))
-			continue;
-		ptpage = pfn_to_page(pfn);
-		if (PageReserved(ptpage))
-			continue;
-		++*pages;
-		if (pte_dirty(page))
-			++*dirty;
-		if (page_count(pte_page(page)) > 1)
-			++*shared;
-	} while (address < end);
-	pte_unmap(pte - 1);
-	preempt_enable();
-}
-
-static inline void statm_pmd_range(pgd_t * pgd, unsigned long address, unsigned long size,
-	int * pages, int * shared, int * dirty, int * total)
-{
-	pmd_t * pmd;
-	unsigned long end;
-
-	if (pgd_none(*pgd))
-		return;
-	if (pgd_bad(*pgd)) {
-		pgd_ERROR(*pgd);
-		pgd_clear(pgd);
-		return;
-	}
-	pmd = pmd_offset(pgd, address);
-	address &= ~PGDIR_MASK;
-	end = address + size;
-	if (end > PGDIR_SIZE)
-		end = PGDIR_SIZE;
-	do {
-		statm_pte_range(pmd, address, end - address, pages, shared, dirty, total);
-		address = (address + PMD_SIZE) & PMD_MASK;
-		pmd++;
-	} while (address < end);
-}
-
-static void statm_pgd_range(pgd_t * pgd, unsigned long address, unsigned long end,
-	int * pages, int * shared, int * dirty, int * total)
-{
-	while (address < end) {
-		statm_pmd_range(pgd, address, end - address, pages, shared, dirty, total);
-		address = (address + PGDIR_SIZE) & PGDIR_MASK;
-		pgd++;
-	}
-}
-
-int proc_pid_statm(struct task_struct *task, char * buffer)
-{
-	int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0;
+	int size, resident, shared, text, lib, data, dirty;
 	struct mm_struct *mm = get_task_mm(task);
+	struct vm_area_struct * vma;
 
-	if (mm) {
-		struct vm_area_struct * vma;
-		down_read(&mm->mmap_sem);
-		vma = mm->mmap;
-		while (vma) {
-			pgd_t *pgd = pgd_offset(mm, vma->vm_start);
-			int pages = 0, shared = 0, dirty = 0, total = 0;
-			if (is_vm_hugetlb_page(vma)) {
-				int num_pages = ((vma->vm_end - vma->vm_start)/PAGE_SIZE);
+	size = resident = shared = text = lib = data = dirty = 0;
 
-				resident += num_pages;
-				if (!(vma->vm_flags & VM_DONTCOPY))
-					share += num_pages;
-				if (vma->vm_flags & VM_WRITE)
-					dt += num_pages;
-				drs += num_pages;
-				vma = vma->vm_next;
-				continue;
-			}
-			statm_pgd_range(pgd, vma->vm_start, vma->vm_end, &pages, &shared, &dirty, &total);
-			resident += pages;
-			share += shared;
-			dt += dirty;
-			size += total;
-			if (vma->vm_flags & VM_EXECUTABLE)
-				trs += pages;	/* text */
-			else if (vma->vm_flags & VM_GROWSDOWN)
-				drs += pages;	/* stack */
-			else if (vma->vm_end > 0x60000000)
-				lrs += pages;	/* library */
-			else
-				drs += pages;
-			vma = vma->vm_next;
+	if (!mm)
+		goto out;
+
+	down_read(&mm->mmap_sem);
+	resident = mm->rss;
+	for (vma = mm->mmap; vma; vma = vma->vm_next) {
+		int pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+
+		size += pages;
+		if (is_vm_hugetlb_page(vma)) {
+			if (!(vma->vm_flags & VM_DONTCOPY))
+				shared += pages;
+			continue;
 		}
-		up_read(&mm->mmap_sem);
-		mmput(mm);
+		if (vma->vm_flags & VM_SHARED || !list_empty(&vma->shared))
+			shared += pages;
+		if (vma->vm_flags & VM_EXECUTABLE)
+			text += pages;
+		else
+			data += pages;
 	}
+	up_read(&mm->mmap_sem);
+	mmput(mm);
+out:
 	return sprintf(buffer,"%d %d %d %d %d %d %d\n",
-		       size, resident, share, trs, lrs, drs, dt);
+		       size, resident, shared, text, lib, data, dirty);
 }
 
 /*
diff -Nru a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
--- a/fs/proc/proc_misc.c	Fri Sep 20 08:20:42 2002
+++ b/fs/proc/proc_misc.c	Fri Sep 20 08:20:42 2002
@@ -171,6 +171,7 @@
 		"Dirty:        %8lu kB\n"
 		"Writeback:    %8lu kB\n"
 		"Mapped:       %8lu kB\n"
+		"Slab:         %8lu kB\n"
 		"Committed_AS: %8u kB\n"
 		"PageTables:   %8lu kB\n"
 		"ReverseMaps:  %8lu\n",
@@ -191,6 +192,7 @@
 		K(ps.nr_dirty),
 		K(ps.nr_writeback),
 		K(ps.nr_mapped),
+		K(ps.nr_slab),
 		K(committed),
 		K(ps.nr_page_table_pages),
 		ps.nr_reverse_maps
diff -Nru a/fs/quota_v1.c b/fs/quota_v1.c
--- a/fs/quota_v1.c	Fri Sep 20 08:20:47 2002
+++ b/fs/quota_v1.c	Fri Sep 20 08:20:47 2002
@@ -210,18 +210,18 @@
 }
 
 static struct quota_format_ops v1_format_ops = {
-	check_quota_file:	v1_check_quota_file,
-	read_file_info:		v1_read_file_info,
-	write_file_info:	v1_write_file_info,
-	free_file_info:		NULL,
-	read_dqblk:		v1_read_dqblk,
-	commit_dqblk:		v1_commit_dqblk,
+	.check_quota_file	= v1_check_quota_file,
+	.read_file_info		= v1_read_file_info,
+	.write_file_info	= v1_write_file_info,
+	.free_file_info		= NULL,
+	.read_dqblk		= v1_read_dqblk,
+	.commit_dqblk		= v1_commit_dqblk,
 };
 
 static struct quota_format_type v1_quota_format = {
-	qf_fmt_id:	QFMT_VFS_OLD,
-	qf_ops:		&v1_format_ops,
-	qf_owner:	THIS_MODULE
+	.qf_fmt_id	= QFMT_VFS_OLD,
+	.qf_ops		= &v1_format_ops,
+	.qf_owner	= THIS_MODULE
 };
 
 static int __init init_v1_quota_format(void)
diff -Nru a/fs/quota_v2.c b/fs/quota_v2.c
--- a/fs/quota_v2.c	Fri Sep 20 08:20:44 2002
+++ b/fs/quota_v2.c	Fri Sep 20 08:20:44 2002
@@ -662,18 +662,18 @@
 }
 
 static struct quota_format_ops v2_format_ops = {
-	check_quota_file:	v2_check_quota_file,
-	read_file_info:		v2_read_file_info,
-	write_file_info:	v2_write_file_info,
-	free_file_info:		NULL,
-	read_dqblk:		v2_read_dquot,
-	commit_dqblk:		v2_commit_dquot,
+	.check_quota_file	= v2_check_quota_file,
+	.read_file_info		= v2_read_file_info,
+	.write_file_info	= v2_write_file_info,
+	.free_file_info		= NULL,
+	.read_dqblk		= v2_read_dquot,
+	.commit_dqblk		= v2_commit_dquot,
 };
 
 static struct quota_format_type v2_quota_format = {
-	qf_fmt_id:	QFMT_VFS_V0,
-	qf_ops:		&v2_format_ops,
-	qf_owner:	THIS_MODULE
+	.qf_fmt_id	= QFMT_VFS_V0,
+	.qf_ops		= &v2_format_ops,
+	.qf_owner	= THIS_MODULE
 };
 
 static int __init init_v2_quota_format(void)
diff -Nru a/fs/read_write.c b/fs/read_write.c
--- a/fs/read_write.c	Fri Sep 20 08:20:47 2002
+++ b/fs/read_write.c	Fri Sep 20 08:20:47 2002
@@ -16,10 +16,10 @@
 #include <asm/uaccess.h>
 
 struct file_operations generic_ro_fops = {
-	llseek:		generic_file_llseek,
-	read:		generic_file_read,
-	mmap:		generic_file_mmap,
-	sendfile:	generic_file_sendfile,
+	.llseek		= generic_file_llseek,
+	.read		= generic_file_read,
+	.mmap		= generic_file_mmap,
+	.sendfile	= generic_file_sendfile,
 };
 
 loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
diff -Nru a/fs/smbfs/dir.c b/fs/smbfs/dir.c
--- a/fs/smbfs/dir.c	Fri Sep 20 08:20:45 2002
+++ b/fs/smbfs/dir.c	Fri Sep 20 08:20:45 2002
@@ -33,22 +33,22 @@
 
 struct file_operations smb_dir_operations =
 {
-	read:		generic_read_dir,
-	readdir:	smb_readdir,
-	ioctl:		smb_ioctl,
-	open:		smb_dir_open,
+	.read		= generic_read_dir,
+	.readdir	= smb_readdir,
+	.ioctl		= smb_ioctl,
+	.open		= smb_dir_open,
 };
 
 struct inode_operations smb_dir_inode_operations =
 {
-	create:		smb_create,
-	lookup:		smb_lookup,
-	unlink:		smb_unlink,
-	mkdir:		smb_mkdir,
-	rmdir:		smb_rmdir,
-	rename:		smb_rename,
-	getattr:	smb_getattr,
-	setattr:	smb_notify_change,
+	.create		= smb_create,
+	.lookup		= smb_lookup,
+	.unlink		= smb_unlink,
+	.mkdir		= smb_mkdir,
+	.rmdir		= smb_rmdir,
+	.rename		= smb_rename,
+	.getattr	= smb_getattr,
+	.setattr	= smb_notify_change,
 };
 
 /*
@@ -257,16 +257,16 @@
 
 static struct dentry_operations smbfs_dentry_operations =
 {
-	d_revalidate:	smb_lookup_validate,
-	d_hash:		smb_hash_dentry,
-	d_compare:	smb_compare_dentry,
-	d_delete:	smb_delete_dentry,
+	.d_revalidate	= smb_lookup_validate,
+	.d_hash		= smb_hash_dentry,
+	.d_compare	= smb_compare_dentry,
+	.d_delete	= smb_delete_dentry,
 };
 
 static struct dentry_operations smbfs_dentry_operations_case =
 {
-	d_revalidate:	smb_lookup_validate,
-	d_delete:	smb_delete_dentry,
+	.d_revalidate	= smb_lookup_validate,
+	.d_delete	= smb_delete_dentry,
 };
 
 
diff -Nru a/fs/smbfs/file.c b/fs/smbfs/file.c
--- a/fs/smbfs/file.c	Fri Sep 20 08:20:47 2002
+++ b/fs/smbfs/file.c	Fri Sep 20 08:20:47 2002
@@ -287,10 +287,10 @@
 }
 
 struct address_space_operations smb_file_aops = {
-	readpage: smb_readpage,
-	writepage: smb_writepage,
-	prepare_write: smb_prepare_write,
-	commit_write: smb_commit_write
+	.readpage = smb_readpage,
+	.writepage = smb_writepage,
+	.prepare_write = smb_prepare_write,
+	.commit_write = smb_commit_write
 };
 
 /* 
@@ -382,19 +382,19 @@
 
 struct file_operations smb_file_operations =
 {
-	llseek:		remote_llseek,
-	read:		smb_file_read,
-	write:		smb_file_write,
-	ioctl:		smb_ioctl,
-	mmap:		smb_file_mmap,
-	open:		smb_file_open,
-	release:	smb_file_release,
-	fsync:		smb_fsync,
+	.llseek		= remote_llseek,
+	.read		= smb_file_read,
+	.write		= smb_file_write,
+	.ioctl		= smb_ioctl,
+	.mmap		= smb_file_mmap,
+	.open		= smb_file_open,
+	.release	= smb_file_release,
+	.fsync		= smb_fsync,
 };
 
 struct inode_operations smb_file_inode_operations =
 {
-	permission:	smb_file_permission,
-	getattr:	smb_getattr,
-	setattr:	smb_notify_change,
+	.permission	= smb_file_permission,
+	.getattr	= smb_getattr,
+	.setattr	= smb_notify_change,
 };
diff -Nru a/fs/smbfs/inode.c b/fs/smbfs/inode.c
--- a/fs/smbfs/inode.c	Fri Sep 20 08:20:42 2002
+++ b/fs/smbfs/inode.c	Fri Sep 20 08:20:42 2002
@@ -92,13 +92,13 @@
 
 static struct super_operations smb_sops =
 {
-	alloc_inode:	smb_alloc_inode,
-	destroy_inode:	smb_destroy_inode,
-	drop_inode:	generic_delete_inode,
-	delete_inode:	smb_delete_inode,
-	put_super:	smb_put_super,
-	statfs:		smb_statfs,
-	show_options:	smb_show_options,
+	.alloc_inode	= smb_alloc_inode,
+	.destroy_inode	= smb_destroy_inode,
+	.drop_inode	= generic_delete_inode,
+	.delete_inode	= smb_delete_inode,
+	.put_super	= smb_put_super,
+	.statfs		= smb_statfs,
+	.show_options	= smb_show_options,
 };
 
 
@@ -738,10 +738,10 @@
 }
 
 static struct file_system_type smb_fs_type = {
-	owner:		THIS_MODULE,
-	name:		"smbfs",
-	get_sb:		smb_get_sb,
-	kill_sb:	kill_anon_super,
+	.owner		= THIS_MODULE,
+	.name		= "smbfs",
+	.get_sb		= smb_get_sb,
+	.kill_sb	= kill_anon_super,
 };
 
 static int __init init_smb_fs(void)
diff -Nru a/fs/smbfs/proc.c b/fs/smbfs/proc.c
--- a/fs/smbfs/proc.c	Fri Sep 20 08:20:42 2002
+++ b/fs/smbfs/proc.c	Fri Sep 20 08:20:42 2002
@@ -1882,8 +1882,8 @@
 	__u16 count;
 	char status[SMB_STATUS_SIZE];
 	static struct qstr mask = {
-		name:	"*.*",
-		len:	3,
+		.name	= "*.*",
+		.len	= 3,
 	};
 	unsigned char *last_status;
 	struct smb_request *req;
@@ -2159,8 +2159,8 @@
 	struct smb_request *req;
 	unsigned char *name_buf;
 	static struct qstr star = {
-		name:	"*",
-		len:	1,
+		.name	= "*",
+		.len	= 1,
 	};
 
 	lock_kernel();
@@ -2917,39 +2917,39 @@
 /* < LANMAN2 */
 static struct smb_ops smb_ops_core =
 {
-	read:		smb_proc_read,
-	write:		smb_proc_write,
-	readdir:	smb_proc_readdir_short,
-	getattr:	smb_proc_getattr_core,
-	truncate:	smb_proc_trunc32,
+	.read		= smb_proc_read,
+	.write		= smb_proc_write,
+	.readdir	= smb_proc_readdir_short,
+	.getattr	= smb_proc_getattr_core,
+	.truncate	= smb_proc_trunc32,
 };
 
 /* LANMAN2, OS/2, others? */
 static struct smb_ops smb_ops_os2 =
 {
-	read:		smb_proc_read,
-	write:		smb_proc_write,
-	readdir:	smb_proc_readdir_long,
-	getattr:	smb_proc_getattr_trans2_std,
-	truncate:	smb_proc_trunc32,
+	.read		= smb_proc_read,
+	.write		= smb_proc_write,
+	.readdir	= smb_proc_readdir_long,
+	.getattr	= smb_proc_getattr_trans2_std,
+	.truncate	= smb_proc_trunc32,
 };
 
 /* Win95, and possibly some NetApp versions too */
 static struct smb_ops smb_ops_win95 =
 {
-	read:		smb_proc_read,	/* does not support 12word readX */
-	write:		smb_proc_write,
-	readdir:	smb_proc_readdir_long,
-	getattr:	smb_proc_getattr_95,
-	truncate:	smb_proc_trunc95,
+	.read		= smb_proc_read,    /* does not support 12word readX */
+	.write		= smb_proc_write,
+	.readdir	= smb_proc_readdir_long,
+	.getattr	= smb_proc_getattr_95,
+	.truncate	= smb_proc_trunc95,
 };
 
 /* Samba, NT4 and NT5 */
 static struct smb_ops smb_ops_winNT =
 {
-	read:		smb_proc_readX,
-	write:		smb_proc_writeX,
-	readdir:	smb_proc_readdir_long,
-	getattr:	smb_proc_getattr_trans2_all,
-	truncate:	smb_proc_trunc64,
+	.read		= smb_proc_readX,
+	.write		= smb_proc_writeX,
+	.readdir	= smb_proc_readdir_long,
+	.getattr	= smb_proc_getattr_trans2_all,
+	.truncate	= smb_proc_trunc64,
 };
diff -Nru a/fs/xfs/linux/xfs_aops.c b/fs/xfs/linux/xfs_aops.c
--- a/fs/xfs/linux/xfs_aops.c	Fri Sep 20 08:20:47 2002
+++ b/fs/xfs/linux/xfs_aops.c	Fri Sep 20 08:20:47 2002
@@ -609,7 +609,7 @@
 
 	if (blocks) {
 		size = (pbmap.pbm_bsize - pbmap.pbm_delta); 
-		bh_result->b_size = min(size, blocks << inode->i_blkbits);
+		bh_result->b_size = min_t(ssize_t, size, blocks << inode->i_blkbits);
 	}
 
 	return 0;
diff -Nru a/fs/xfs/pagebuf/page_buf.c b/fs/xfs/pagebuf/page_buf.c
--- a/fs/xfs/pagebuf/page_buf.c	Fri Sep 20 08:20:41 2002
+++ b/fs/xfs/pagebuf/page_buf.c	Fri Sep 20 08:20:41 2002
@@ -1291,14 +1291,19 @@
 /*
  * Helper routine for pagebuf_iorequest
  */
-STATIC void
+STATIC int
 bio_end_io_pagebuf(
-	struct bio		*bio)
+	struct bio		*bio,
+	unsigned int		bytes_done,
+	int			error)
 {
 	page_buf_t		*pb = (page_buf_t *)bio->bi_private;
 	unsigned int		i, blocksize = pb->pb_target->pbr_blocksize;
 	struct bio_vec		*bvec = bio->bi_io_vec;
 
+	if (bio->bi_size)
+		return 1;
+
 	if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
 		pb->pb_error = EIO;
 
@@ -1335,6 +1340,7 @@
 	}
 
 	bio_put(bio);
+	return 0;
 }
 
 /*
@@ -1447,7 +1453,6 @@
 	bio = bio_alloc(GFP_NOIO, nr_pages);
 
 	BUG_ON(bio == NULL);
-	bio_init(bio);
 	bio->bi_bdev = pb->pb_target->pbr_bdev;
 	bio->bi_sector = sector;
 	bio->bi_end_io = bio_end_io_pagebuf;
@@ -1461,12 +1466,8 @@
 		if (nbytes > size)
 			nbytes = size;
 
-		bio->bi_vcnt++;
-		bio->bi_size += nbytes;
-
-		bvec->bv_page = pb->pb_pages[map_i];
-		bvec->bv_len = nbytes;
-		bvec->bv_offset = offset;
+		if (bio_add_page(bio, pb->pb_pages[map_i], nbytes, offset))
+			break;
 
 		offset = 0;
 
diff -Nru a/include/asm-alpha/mmzone.h b/include/asm-alpha/mmzone.h
--- a/include/asm-alpha/mmzone.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-alpha/mmzone.h	Fri Sep 20 08:20:47 2002
@@ -36,18 +36,14 @@
 
 #ifdef CONFIG_ALPHA_WILDFIRE
 # define ALPHA_PA_TO_NID(pa)	((pa) >> 36)	/* 16 nodes max due 43bit kseg */
-#define NODE_MAX_MEM_SIZE	(64L * 1024L * 1024L * 1024L) /* 64 GB */
-#define MAX_NUMNODES		WILDFIRE_MAX_QBB
+# define NODE_MAX_MEM_SIZE	(64L * 1024L * 1024L * 1024L) /* 64 GB */
 #else
 # define ALPHA_PA_TO_NID(pa)	(0)
-#define NODE_MAX_MEM_SIZE	(~0UL)
-#define MAX_NUMNODES		1
+# define NODE_MAX_MEM_SIZE	(~0UL)
 #endif
 
 #define PHYSADDR_TO_NID(pa)		ALPHA_PA_TO_NID(pa)
 #define PLAT_NODE_DATA(n)		(plat_node_data[(n)])
-#define PLAT_NODE_DATA_STARTNR(n)	\
-	(PLAT_NODE_DATA(n)->gendata.node_start_mapnr)
 #define PLAT_NODE_DATA_SIZE(n)		(PLAT_NODE_DATA(n)->gendata.node_size)
 
 #if 1
diff -Nru a/include/asm-alpha/numnodes.h b/include/asm-alpha/numnodes.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-alpha/numnodes.h	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,12 @@
+#ifndef _ASM_MAX_NUMNODES_H
+#define _ASM_MAX_NUMNODES_H
+
+/*
+ * Currently the Wildfire is the only discontigmem/NUMA capable Alpha core.
+ */
+#if defined(CONFIG_ALPHA_WILDFIRE) || defined(CONFIG_ALPHA_GENERIC)
+# include <asm/core_wildfire.h>
+# define MAX_NUMNODES		WILDFIRE_MAX_QBB
+#endif
+
+#endif /* _ASM_MAX_NUMNODES_H */
diff -Nru a/include/asm-i386/arch_hooks.h b/include/asm-i386/arch_hooks.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-i386/arch_hooks.h	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,25 @@
+#ifndef _ASM_ARCH_HOOKS_H
+#define _ASM_ARCH_HOOKS_H
+
+/*
+ *	linux/include/asm/arch_hooks.h
+ *
+ *	define the architecture specific hooks 
+ */
+
+/* these aren't arch hooks, they are generic routines
+ * that can be used by the hooks */
+extern void init_ISA_irqs(void);
+extern void apic_intr_init(void);
+extern void smp_intr_init(void);
+extern void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
+/* these are the defined hooks */
+extern void intr_init_hook(void);
+extern void pre_intr_init_hook(void);
+extern void pre_setup_arch_hook(void);
+extern void trap_init_hook(void);
+extern void time_init_hook(void);
+extern void mca_nmi_hook(void);
+
+#endif
diff -Nru a/include/asm-i386/irq.h b/include/asm-i386/irq.h
--- a/include/asm-i386/irq.h	Fri Sep 20 08:20:42 2002
+++ b/include/asm-i386/irq.h	Fri Sep 20 08:20:42 2002
@@ -12,7 +12,8 @@
 
 #include <linux/config.h>
 #include <linux/sched.h>
-#include <asm/irq_vectors.h>
+/* include comes from machine specific directory */
+#include "irq_vectors.h"
 
 static __inline__ int irq_cannonicalize(int irq)
 {
diff -Nru a/include/asm-i386/irq_vectors.h b/include/asm-i386/irq_vectors.h
--- a/include/asm-i386/irq_vectors.h	Fri Sep 20 08:20:43 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,64 +0,0 @@
-#ifndef _ASM_IRQ_VECTORS_H
-#define _ASM_IRQ_VECTORS_H
-
-/*
- * IDT vectors usable for external interrupt sources start
- * at 0x20:
- */
-#define FIRST_EXTERNAL_VECTOR	0x20
-
-#define SYSCALL_VECTOR		0x80
-
-/*
- * Vectors 0x20-0x2f are used for ISA interrupts.
- */
-
-/*
- * Special IRQ vectors used by the SMP architecture, 0xf0-0xff
- *
- *  some of the following vectors are 'rare', they are merged
- *  into a single vector (CALL_FUNCTION_VECTOR) to save vector space.
- *  TLB, reschedule and local APIC vectors are performance-critical.
- *
- *  Vectors 0xf0-0xfa are free (reserved for future Linux use).
- */
-#define SPURIOUS_APIC_VECTOR	0xff
-#define ERROR_APIC_VECTOR	0xfe
-#define INVALIDATE_TLB_VECTOR	0xfd
-#define RESCHEDULE_VECTOR	0xfc
-#define CALL_FUNCTION_VECTOR	0xfb
-
-#define THERMAL_APIC_VECTOR	0xf0
-/*
- * Local APIC timer IRQ vector is on a different priority level,
- * to work around the 'lost local interrupt if more than 2 IRQ
- * sources per level' errata.
- */
-#define LOCAL_TIMER_VECTOR	0xef
-
-/*
- * First APIC vector available to drivers: (vectors 0x30-0xee)
- * we start at 0x31 to spread out vectors evenly between priority
- * levels. (0x80 is the syscall vector)
- */
-#define FIRST_DEVICE_VECTOR	0x31
-#define FIRST_SYSTEM_VECTOR	0xef
-
-#define TIMER_IRQ 0
-
-/*
- * 16 8259A IRQ's, 208 potential APIC interrupt sources.
- * Right now the APIC is mostly only used for SMP.
- * 256 vectors is an architectural limit. (we can have
- * more than 256 devices theoretically, but they will
- * have to use shared interrupts)
- * Since vectors 0x00-0x1f are used/reserved for the CPU,
- * the usable vector space is 0x20-0xff (224 vectors)
- */
-#ifdef CONFIG_X86_IO_APIC
-#define NR_IRQS 224
-#else
-#define NR_IRQS 16
-#endif
-
-#endif /* _ASM_IRQ_VECTORS_H */
diff -Nru a/include/asm-i386/max_numnodes.h b/include/asm-i386/max_numnodes.h
--- a/include/asm-i386/max_numnodes.h	Fri Sep 20 08:20:43 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,12 +0,0 @@
-#ifndef _ASM_MAX_NUMNODES_H
-#define _ASM_MAX_NUMNODES_H
-
-#include <linux/config.h>
-
-#ifdef CONFIG_X86_NUMAQ
-#include <asm/numaq.h>
-#else
-#define MAX_NUMNODES	1
-#endif /* CONFIG_X86_NUMAQ */
-
-#endif /* _ASM_MAX_NUMNODES_H */
diff -Nru a/include/asm-i386/mmzone.h b/include/asm-i386/mmzone.h
--- a/include/asm-i386/mmzone.h	Fri Sep 20 08:20:46 2002
+++ b/include/asm-i386/mmzone.h	Fri Sep 20 08:20:46 2002
@@ -6,12 +6,13 @@
 #ifndef _ASM_MMZONE_H_
 #define _ASM_MMZONE_H_
 
+#include <asm/smp.h>
+
 #ifdef CONFIG_DISCONTIGMEM
 
 #ifdef CONFIG_X86_NUMAQ
 #include <asm/numaq.h>
 #else
-#define pa_to_nid(pa)	(0)
 #define pfn_to_nid(pfn)		(0)
 #ifdef CONFIG_NUMA
 #define _cpu_to_node(cpu) 0
@@ -44,7 +45,6 @@
 #define alloc_bootmem_low_pages_node(ignore, x) \
 	__alloc_bootmem_node(NODE_DATA(0), (x), PAGE_SIZE, 0)
 
-#define node_startnr(nid)	(node_data[nid]->node_start_mapnr)
 #define node_size(nid)		(node_data[nid]->node_size)
 #define node_localnr(pfn, nid)	((pfn) - node_data[nid]->node_start_pfn)
 
@@ -55,7 +55,7 @@
 /*
  * Given a kernel address, find the home node of the underlying memory.
  */
-#define kvaddr_to_nid(kaddr)	pa_to_nid(__pa(kaddr))
+#define kvaddr_to_nid(kaddr)	pfn_to_nid(__pa(kaddr) >> PAGE_SHIFT)
 
 /*
  * Return a pointer to the node data for node n.
@@ -64,6 +64,8 @@
 
 #define node_mem_map(nid)	(NODE_DATA(nid)->node_mem_map)
 #define node_start_pfn(nid)	(NODE_DATA(nid)->node_start_pfn)
+#define node_end_pfn(nid)       (NODE_DATA(nid)->node_start_pfn + \
+				 NODE_DATA(nid)->node_size)
 
 #define local_mapnr(kvaddr) \
 	( (__pa(kvaddr) >> PAGE_SHIFT) - node_start_pfn(kvaddr_to_nid(kvaddr)) )
@@ -74,5 +76,13 @@
 #define pfn_to_page(pfn)	(node_mem_map(pfn_to_nid(pfn)) + node_localnr(pfn, pfn_to_nid(pfn)))
 #define page_to_pfn(page)	((page - page_zone(page)->zone_mem_map) + page_zone(page)->zone_start_pfn)
 #define pmd_page(pmd)		(pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT))
+/*
+ * pfn_valid should be made as fast as possible, and the current definition 
+ * is valid for machines that are NUMA, but still contiguous, which is what
+ * is currently supported. A more generalised, but slower definition would
+ * be something like this - mbligh:
+ * ( pfn_to_pgdat(pfn) && (pfn < node_end_pfn(pfn_to_nid(pfn))) ) 
+ */ 
+#define pfn_valid(pfn)          (pfn < num_physpages)
 #endif /* CONFIG_DISCONTIGMEM */
 #endif /* _ASM_MMZONE_H_ */
diff -Nru a/include/asm-i386/mpspec.h b/include/asm-i386/mpspec.h
--- a/include/asm-i386/mpspec.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-i386/mpspec.h	Fri Sep 20 08:20:41 2002
@@ -226,6 +226,7 @@
 extern void mp_register_ioapic (u8 id, u32 address, u32 irq_base);
 extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity, u8 trigger, u32 global_irq);
 extern void mp_config_acpi_legacy_irqs (void);
+extern void mp_config_ioapic_for_sci(int irq);
 extern void mp_parse_prt (void);
 #endif /*CONFIG_ACPI_BOOT*/
 
diff -Nru a/include/asm-i386/numaq.h b/include/asm-i386/numaq.h
--- a/include/asm-i386/numaq.h	Fri Sep 20 08:20:46 2002
+++ b/include/asm-i386/numaq.h	Fri Sep 20 08:20:46 2002
@@ -32,17 +32,18 @@
 
 /*
  * for now assume that 64Gb is max amount of RAM for whole system
- *    64Gb * 1024Mb/Gb = 65536 Mb
- *    65536 Mb / 256Mb = 256
+ *    64Gb / 4096bytes/page = 16777216 pages
  */
+#define MAX_NR_PAGES 16777216
 #define MAX_ELEMENTS 256
-#define ELEMENT_REPRESENTS 8 /* 256 Mb */
+#define PAGES_PER_ELEMENT (16777216/256)
 
+#define pfn_to_pgdat(pfn) NODE_DATA(pfn_to_nid(pfn))
+#define PHYSADDR_TO_NID(pa) pfn_to_nid(pa >> PAGE_SHIFT)
 #define MAX_NUMNODES		8
 #ifdef CONFIG_NUMA
 #define _cpu_to_node(cpu) (cpu_to_logical_apicid(cpu) >> 4)
 #endif /* CONFIG_NUMA */
-extern int pa_to_nid(u64);
 extern int pfn_to_nid(unsigned long);
 extern void get_memcfg_numaq(void);
 #define get_memcfg_numa() get_memcfg_numaq()
diff -Nru a/include/asm-i386/numnodes.h b/include/asm-i386/numnodes.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-i386/numnodes.h	Fri Sep 20 08:20:43 2002
@@ -0,0 +1,12 @@
+#ifndef _ASM_MAX_NUMNODES_H
+#define _ASM_MAX_NUMNODES_H
+
+#include <linux/config.h>
+
+#ifdef CONFIG_X86_NUMAQ
+#include <asm/numaq.h>
+#else
+#define MAX_NUMNODES	1
+#endif /* CONFIG_X86_NUMAQ */
+
+#endif /* _ASM_MAX_NUMNODES_H */
diff -Nru a/include/asm-i386/page.h b/include/asm-i386/page.h
--- a/include/asm-i386/page.h	Fri Sep 20 08:20:43 2002
+++ b/include/asm-i386/page.h	Fri Sep 20 08:20:43 2002
@@ -145,10 +145,10 @@
 #ifndef CONFIG_DISCONTIGMEM
 #define pfn_to_page(pfn)	(mem_map + (pfn))
 #define page_to_pfn(page)	((unsigned long)((page) - mem_map))
+#define pfn_valid(pfn)		((pfn) < max_mapnr)
 #endif /* !CONFIG_DISCONTIGMEM */
 #define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
 
-#define pfn_valid(pfn)		((pfn) < max_mapnr)
 #define virt_addr_valid(kaddr)	pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
 
 #define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | VM_EXEC | \
diff -Nru a/include/asm-mips64/mmzone.h b/include/asm-mips64/mmzone.h
--- a/include/asm-mips64/mmzone.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-mips64/mmzone.h	Fri Sep 20 08:20:41 2002
@@ -24,7 +24,6 @@
 
 #define PHYSADDR_TO_NID(pa)		NASID_TO_COMPACT_NODEID(NASID_GET(pa))
 #define PLAT_NODE_DATA(n)		(plat_node_data[n])
-#define PLAT_NODE_DATA_STARTNR(n)    (PLAT_NODE_DATA(n)->gendata.node_start_mapnr)
 #define PLAT_NODE_DATA_SIZE(n)	     (PLAT_NODE_DATA(n)->gendata.node_size)
 #define PLAT_NODE_DATA_LOCALNR(p, n) \
 		(((p) >> PAGE_SHIFT) - PLAT_NODE_DATA(n)->gendata.node_start_pfn)
diff -Nru a/include/asm-mips64/pgtable.h b/include/asm-mips64/pgtable.h
--- a/include/asm-mips64/pgtable.h	Fri Sep 20 08:20:48 2002
+++ b/include/asm-mips64/pgtable.h	Fri Sep 20 08:20:48 2002
@@ -373,10 +373,10 @@
 #ifndef CONFIG_DISCONTIGMEM
 #define pte_page(x)		(mem_map+(unsigned long)((pte_val(x) >> PAGE_SHIFT)))
 #else
-#define mips64_pte_pagenr(x) \
-	(PLAT_NODE_DATA_STARTNR(PHYSADDR_TO_NID(pte_val(x))) + \
-	PLAT_NODE_DATA_LOCALNR(pte_val(x), PHYSADDR_TO_NID(pte_val(x))))
-#define pte_page(x)		(mem_map+mips64_pte_pagenr(x))
+
+#define pte_page(x) ( NODE_MEM_MAP(PHYSADDR_TO_NID(pte_val(x))) +
+	PLAT_NODE_DATA_LOCALNR(pte_val(x), PHYSADDR_TO_NID(pte_val(x))) )
+				  
 #endif
 
 /*
diff -Nru a/include/asm-ppc/8xx_immap.h b/include/asm-ppc/8xx_immap.h
--- a/include/asm-ppc/8xx_immap.h	Fri Sep 20 08:20:45 2002
+++ b/include/asm-ppc/8xx_immap.h	Fri Sep 20 08:20:45 2002
@@ -1,8 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
-/*
  * MPC8xx Internal Memory Map
  * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
  *
diff -Nru a/include/asm-ppc/a.out.h b/include/asm-ppc/a.out.h
--- a/include/asm-ppc/a.out.h	Fri Sep 20 08:20:46 2002
+++ b/include/asm-ppc/a.out.h	Fri Sep 20 08:20:46 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.a.out.h 1.5 05/17/01 18:14:24 cort
- */
 #ifndef __PPC_A_OUT_H__
 #define __PPC_A_OUT_H__
 
diff -Nru a/include/asm-ppc/amigahw.h b/include/asm-ppc/amigahw.h
--- a/include/asm-ppc/amigahw.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc/amigahw.h	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.amigahw.h 1.5 05/17/01 18:14:24 cort
- */
 #ifdef __KERNEL__
 #ifndef __ASMPPC_AMIGAHW_H
 #define __ASMPPC_AMIGAHW_H
diff -Nru a/include/asm-ppc/amigaints.h b/include/asm-ppc/amigaints.h
--- a/include/asm-ppc/amigaints.h	Fri Sep 20 08:20:46 2002
+++ b/include/asm-ppc/amigaints.h	Fri Sep 20 08:20:46 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
 ** amigaints.h -- Amiga Linux interrupt handling structs and prototypes
 **
 ** Copyright 1992 by Greg Harp
diff -Nru a/include/asm-ppc/amigappc.h b/include/asm-ppc/amigappc.h
--- a/include/asm-ppc/amigappc.h	Fri Sep 20 08:20:43 2002
+++ b/include/asm-ppc/amigappc.h	Fri Sep 20 08:20:43 2002
@@ -1,8 +1,5 @@
 /*
- * BK Id: SCCS/s.amigappc.h 1.5 05/17/01 18:14:24 cort
- */
-/*
-** asm-m68k/amigappc.h -- This header defines some values and pointers for
+** asm-ppc/amigappc.h -- This header defines some values and pointers for
 **                        the Phase 5 PowerUp card.
 **
 ** Copyright 1997, 1998 by Phase5, Germany.
diff -Nru a/include/asm-ppc/amigayle.h b/include/asm-ppc/amigayle.h
--- a/include/asm-ppc/amigayle.h	Fri Sep 20 08:20:43 2002
+++ b/include/asm-ppc/amigayle.h	Fri Sep 20 08:20:43 2002
@@ -1,4 +1 @@
-/*
- * BK Id: SCCS/s.amigayle.h 1.5 05/17/01 18:14:24 cort
- */
 #include <asm-m68k/amigayle.h>
diff -Nru a/include/asm-ppc/amipcmcia.h b/include/asm-ppc/amipcmcia.h
--- a/include/asm-ppc/amipcmcia.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/amipcmcia.h	Fri Sep 20 08:20:47 2002
@@ -1,4 +1 @@
-/*
- * BK Id: SCCS/s.amipcmcia.h 1.5 05/17/01 18:14:24 cort
- */
 #include <asm-m68k/amipcmcia.h>
diff -Nru a/include/asm-ppc/atomic.h b/include/asm-ppc/atomic.h
--- a/include/asm-ppc/atomic.h	Fri Sep 20 08:20:43 2002
+++ b/include/asm-ppc/atomic.h	Fri Sep 20 08:20:43 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * PowerPC atomic operations
  */
 
diff -Nru a/include/asm-ppc/backlight.h b/include/asm-ppc/backlight.h
--- a/include/asm-ppc/backlight.h	Fri Sep 20 08:20:48 2002
+++ b/include/asm-ppc/backlight.h	Fri Sep 20 08:20:48 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.backlight.h 1.5 05/17/01 18:14:24 cort
- */
-/*
  * Routines for handling backlight control on PowerBooks
  * 
  * For now, implementation resides in arch/ppc/kernel/pmac_support.c
diff -Nru a/include/asm-ppc/bitops.h b/include/asm-ppc/bitops.h
--- a/include/asm-ppc/bitops.h	Fri Sep 20 08:20:46 2002
+++ b/include/asm-ppc/bitops.h	Fri Sep 20 08:20:46 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * bitops.h: Bit string operations on the ppc
  */
 
diff -Nru a/include/asm-ppc/bootinfo.h b/include/asm-ppc/bootinfo.h
--- a/include/asm-ppc/bootinfo.h	Fri Sep 20 08:20:44 2002
+++ b/include/asm-ppc/bootinfo.h	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Non-machine dependent bootinfo structure.  Basic idea
  * borrowed from the m68k.
  *
diff -Nru a/include/asm-ppc/bootx.h b/include/asm-ppc/bootx.h
--- a/include/asm-ppc/bootx.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/bootx.h	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.bootx.h 1.5 05/17/01 18:14:24 cort
- */
-/*
  * This file describes the structure passed from the BootX application
  * (for MacOS) when it is used to boot Linux.
  *
diff -Nru a/include/asm-ppc/bseip.h b/include/asm-ppc/bseip.h
--- a/include/asm-ppc/bseip.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc/bseip.h	Fri Sep 20 08:20:41 2002
@@ -1,8 +1,4 @@
 /*
- * BK Id: SCCS/s.bseip.h 1.10 08/17/01 15:23:17 paulus
- */
-
-/*
  * A collection of structures, addresses, and values associated with
  * the Bright Star Engineering ip-Engine board.  Copied from the MBX stuff.
  *
diff -Nru a/include/asm-ppc/btext.h b/include/asm-ppc/btext.h
--- a/include/asm-ppc/btext.h	Fri Sep 20 08:20:44 2002
+++ b/include/asm-ppc/btext.h	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Definitions for using the procedures in btext.c.
  *
  * Benjamin Herrenschmidt <benh@kernel.crashing.org>
diff -Nru a/include/asm-ppc/bugs.h b/include/asm-ppc/bugs.h
--- a/include/asm-ppc/bugs.h	Fri Sep 20 08:20:45 2002
+++ b/include/asm-ppc/bugs.h	Fri Sep 20 08:20:45 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.bugs.h 1.5 05/17/01 18:14:24 cort
- */
-/*
  * This file is included by 'init/main.c'
  */
 
diff -Nru a/include/asm-ppc/byteorder.h b/include/asm-ppc/byteorder.h
--- a/include/asm-ppc/byteorder.h	Fri Sep 20 08:20:46 2002
+++ b/include/asm-ppc/byteorder.h	Fri Sep 20 08:20:46 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifndef _PPC_BYTEORDER_H
 #define _PPC_BYTEORDER_H
 
diff -Nru a/include/asm-ppc/cache.h b/include/asm-ppc/cache.h
--- a/include/asm-ppc/cache.h	Fri Sep 20 08:20:48 2002
+++ b/include/asm-ppc/cache.h	Fri Sep 20 08:20:48 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * include/asm-ppc/cache.h
  */
 #ifdef __KERNEL__
diff -Nru a/include/asm-ppc/cacheflush.h b/include/asm-ppc/cacheflush.h
--- a/include/asm-ppc/cacheflush.h	Fri Sep 20 08:20:43 2002
+++ b/include/asm-ppc/cacheflush.h	Fri Sep 20 08:20:43 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * include/asm-ppc/cacheflush.h
  *
  *  This program is free software; you can redistribute it and/or
diff -Nru a/include/asm-ppc/checksum.h b/include/asm-ppc/checksum.h
--- a/include/asm-ppc/checksum.h	Fri Sep 20 08:20:44 2002
+++ b/include/asm-ppc/checksum.h	Fri Sep 20 08:20:44 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.checksum.h 1.8 05/17/01 18:14:24 cort
- */
 #ifdef __KERNEL__
 #ifndef _PPC_CHECKSUM_H
 #define _PPC_CHECKSUM_H
diff -Nru a/include/asm-ppc/commproc.h b/include/asm-ppc/commproc.h
--- a/include/asm-ppc/commproc.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/commproc.h	Fri Sep 20 08:20:47 2002
@@ -1,8 +1,4 @@
 /*
- * BK Id: SCCS/s.commproc.h 1.16 09/27/01 12:41:09 trini
- */
-
-/*
  * MPC8xx Communication Processor Module.
  * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
  *
diff -Nru a/include/asm-ppc/cpm_8260.h b/include/asm-ppc/cpm_8260.h
--- a/include/asm-ppc/cpm_8260.h	Fri Sep 20 08:20:46 2002
+++ b/include/asm-ppc/cpm_8260.h	Fri Sep 20 08:20:46 2002
@@ -1,8 +1,4 @@
 /*
- * BK Id: SCCS/s.cpm_8260.h 1.7 05/17/01 18:14:24 cort
- */
-
-/*
  * MPC8260 Communication Processor Module.
  * Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
  *
diff -Nru a/include/asm-ppc/cputable.h b/include/asm-ppc/cputable.h
--- a/include/asm-ppc/cputable.h	Fri Sep 20 08:20:45 2002
+++ b/include/asm-ppc/cputable.h	Fri Sep 20 08:20:45 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.cputable.h 1.3 08/19/01 22:31:46 paulus
- */
-/*
  *  include/asm-ppc/cputable.h
  *
  *  Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org)
diff -Nru a/include/asm-ppc/current.h b/include/asm-ppc/current.h
--- a/include/asm-ppc/current.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/current.h	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.current.h 1.5 05/17/01 18:14:24 cort
- */
 #ifdef __KERNEL__
 #ifndef _PPC_CURRENT_H
 #define _PPC_CURRENT_H
diff -Nru a/include/asm-ppc/dbdma.h b/include/asm-ppc/dbdma.h
--- a/include/asm-ppc/dbdma.h	Fri Sep 20 08:20:48 2002
+++ b/include/asm-ppc/dbdma.h	Fri Sep 20 08:20:48 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Definitions for using the Apple Descriptor-Based DMA controller
  * in Power Macintosh computers.
  *
diff -Nru a/include/asm-ppc/delay.h b/include/asm-ppc/delay.h
--- a/include/asm-ppc/delay.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/delay.h	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifdef __KERNEL__
 #ifndef _PPC_DELAY_H
 #define _PPC_DELAY_H
diff -Nru a/include/asm-ppc/div64.h b/include/asm-ppc/div64.h
--- a/include/asm-ppc/div64.h	Fri Sep 20 08:20:48 2002
+++ b/include/asm-ppc/div64.h	Fri Sep 20 08:20:48 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.div64.h 1.5 05/17/01 18:14:24 cort
- */
 #ifndef __PPC_DIV64
 #define __PPC_DIV64
 
diff -Nru a/include/asm-ppc/dma.h b/include/asm-ppc/dma.h
--- a/include/asm-ppc/dma.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/dma.h	Fri Sep 20 08:20:47 2002
@@ -1,8 +1,5 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- * linux/include/asm/dma.h: Defines for using and allocating dma channels.
+ * include/asm-ppc/dma.h: Defines for using and allocating dma channels.
  * Written by Hennus Bergman, 1992.
  * High DMA channel support & info by Hannu Savolainen
  * and John Boyd, Nov. 1992.
diff -Nru a/include/asm-ppc/elf.h b/include/asm-ppc/elf.h
--- a/include/asm-ppc/elf.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc/elf.h	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifndef __PPC_ELF_H
 #define __PPC_ELF_H
 
diff -Nru a/include/asm-ppc/errno.h b/include/asm-ppc/errno.h
--- a/include/asm-ppc/errno.h	Fri Sep 20 08:20:44 2002
+++ b/include/asm-ppc/errno.h	Fri Sep 20 08:20:44 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.errno.h 1.7 05/17/01 18:14:24 cort
- */
 #ifndef _PPC_ERRNO_H
 #define _PPC_ERRNO_H
 
diff -Nru a/include/asm-ppc/fcntl.h b/include/asm-ppc/fcntl.h
--- a/include/asm-ppc/fcntl.h	Fri Sep 20 08:20:46 2002
+++ b/include/asm-ppc/fcntl.h	Fri Sep 20 08:20:46 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.fcntl.h 1.8 09/19/01 23:06:01 paulus
- */
 #ifndef _PPC_FCNTL_H
 #define _PPC_FCNTL_H
 
diff -Nru a/include/asm-ppc/floppy.h b/include/asm-ppc/floppy.h
--- a/include/asm-ppc/floppy.h	Fri Sep 20 08:20:44 2002
+++ b/include/asm-ppc/floppy.h	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.floppy.h 1.5 05/17/01 18:14:24 cort
- */
-/*
  * Architecture specific parts of the Floppy driver
  *
  * This file is subject to the terms and conditions of the GNU General Public
diff -Nru a/include/asm-ppc/gg2.h b/include/asm-ppc/gg2.h
--- a/include/asm-ppc/gg2.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/gg2.h	Fri Sep 20 08:20:47 2002
@@ -1,8 +1,5 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- *  asm-ppc/gg2.h -- VLSI VAS96011/12 `Golden Gate 2' register definitions
+ *  include/asm-ppc/gg2.h -- VLSI VAS96011/12 `Golden Gate 2' register definitions
  *
  *  Copyright (C) 1997 Geert Uytterhoeven
  *
diff -Nru a/include/asm-ppc/hardirq.h b/include/asm-ppc/hardirq.h
--- a/include/asm-ppc/hardirq.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc/hardirq.h	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifdef __KERNEL__
 #ifndef __ASM_HARDIRQ_H
 #define __ASM_HARDIRQ_H
diff -Nru a/include/asm-ppc/hdreg.h b/include/asm-ppc/hdreg.h
--- a/include/asm-ppc/hdreg.h	Fri Sep 20 08:20:43 2002
+++ b/include/asm-ppc/hdreg.h	Fri Sep 20 08:20:43 2002
@@ -1,8 +1,5 @@
 /*
- * BK Id: SCCS/s.hdreg.h 1.5 05/17/01 18:14:24 cort
- */
-/*
- *  linux/include/asm-ppc/hdreg.h
+ *  include/asm-ppc/hdreg.h
  *
  *  Copyright (C) 1994-1996  Linus Torvalds & authors
  */
diff -Nru a/include/asm-ppc/heathrow.h b/include/asm-ppc/heathrow.h
--- a/include/asm-ppc/heathrow.h	Fri Sep 20 08:20:43 2002
+++ b/include/asm-ppc/heathrow.h	Fri Sep 20 08:20:43 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * heathrow.h: definitions for using the "Heathrow" I/O controller chip.
  *
  * Grabbed from Open Firmware definitions on a PowerBook G3 Series
diff -Nru a/include/asm-ppc/highmem.h b/include/asm-ppc/highmem.h
--- a/include/asm-ppc/highmem.h	Fri Sep 20 08:20:45 2002
+++ b/include/asm-ppc/highmem.h	Fri Sep 20 08:20:45 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * highmem.h: virtual kernel memory mappings for high memory
  *
  * PowerPC version, stolen from the i386 version.
diff -Nru a/include/asm-ppc/hw_irq.h b/include/asm-ppc/hw_irq.h
--- a/include/asm-ppc/hw_irq.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/hw_irq.h	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
  */
 #ifdef __KERNEL__
diff -Nru a/include/asm-ppc/hydra.h b/include/asm-ppc/hydra.h
--- a/include/asm-ppc/hydra.h	Fri Sep 20 08:20:46 2002
+++ b/include/asm-ppc/hydra.h	Fri Sep 20 08:20:46 2002
@@ -1,8 +1,5 @@
 /*
- * BK Id: SCCS/s.hydra.h 1.5 05/17/01 18:14:24 cort
- */
-/*
- *  asm-ppc/hydra.h -- Mac I/O `Hydra' definitions
+ *  include/asm-ppc/hydra.h -- Mac I/O `Hydra' definitions
  *
  *  Copyright (C) 1997 Geert Uytterhoeven
  *
diff -Nru a/include/asm-ppc/i8259.h b/include/asm-ppc/i8259.h
--- a/include/asm-ppc/i8259.h	Fri Sep 20 08:20:42 2002
+++ b/include/asm-ppc/i8259.h	Fri Sep 20 08:20:42 2002
@@ -1,7 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
 #ifndef _PPC_KERNEL_i8259_H
 #define _PPC_KERNEL_i8259_H
 
diff -Nru a/include/asm-ppc/ide.h b/include/asm-ppc/ide.h
--- a/include/asm-ppc/ide.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/ide.h	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *  linux/include/asm-ppc/ide.h
  *
  *  Copyright (C) 1994-1996 Linus Torvalds & authors */
diff -Nru a/include/asm-ppc/immap_8260.h b/include/asm-ppc/immap_8260.h
--- a/include/asm-ppc/immap_8260.h	Fri Sep 20 08:20:46 2002
+++ b/include/asm-ppc/immap_8260.h	Fri Sep 20 08:20:46 2002
@@ -1,8 +1,4 @@
 /*
- * BK Id: SCCS/s.immap_8260.h 1.8 07/18/01 15:46:50 trini
- */
-
-/*
  * MPC8260 Internal Memory Map
  * Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
  *
diff -Nru a/include/asm-ppc/io.h b/include/asm-ppc/io.h
--- a/include/asm-ppc/io.h	Fri Sep 20 08:20:44 2002
+++ b/include/asm-ppc/io.h	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
 #ifdef __KERNEL__
 #ifndef _PPC_IO_H
 #define _PPC_IO_H
diff -Nru a/include/asm-ppc/ioctl.h b/include/asm-ppc/ioctl.h
--- a/include/asm-ppc/ioctl.h	Fri Sep 20 08:20:46 2002
+++ b/include/asm-ppc/ioctl.h	Fri Sep 20 08:20:46 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.ioctl.h 1.5 05/17/01 18:14:24 cort
- */
 #ifndef _PPC_IOCTL_H
 #define _PPC_IOCTL_H
 
diff -Nru a/include/asm-ppc/ioctls.h b/include/asm-ppc/ioctls.h
--- a/include/asm-ppc/ioctls.h	Fri Sep 20 08:20:44 2002
+++ b/include/asm-ppc/ioctls.h	Fri Sep 20 08:20:44 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.ioctls.h 1.7 05/17/01 18:14:24 cort
- */
 #ifndef _ASM_PPC_IOCTLS_H
 #define _ASM_PPC_IOCTLS_H
 
diff -Nru a/include/asm-ppc/ipc.h b/include/asm-ppc/ipc.h
--- a/include/asm-ppc/ipc.h	Fri Sep 20 08:20:48 2002
+++ b/include/asm-ppc/ipc.h	Fri Sep 20 08:20:48 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.ipc.h 1.5 05/17/01 18:14:24 cort
- */
 #ifndef __PPC_IPC_H__
 #define __PPC_IPC_H__
 
diff -Nru a/include/asm-ppc/ipcbuf.h b/include/asm-ppc/ipcbuf.h
--- a/include/asm-ppc/ipcbuf.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc/ipcbuf.h	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.ipcbuf.h 1.5 05/17/01 18:14:24 cort
- */
 #ifndef __PPC_IPCBUF_H__
 #define __PPC_IPCBUF_H__
 
diff -Nru a/include/asm-ppc/irq.h b/include/asm-ppc/irq.h
--- a/include/asm-ppc/irq.h	Fri Sep 20 08:20:42 2002
+++ b/include/asm-ppc/irq.h	Fri Sep 20 08:20:42 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifdef __KERNEL__
 #ifndef _ASM_IRQ_H
 #define _ASM_IRQ_H
diff -Nru a/include/asm-ppc/keylargo.h b/include/asm-ppc/keylargo.h
--- a/include/asm-ppc/keylargo.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/keylargo.h	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * keylargo.h: definitions for using the "KeyLargo" I/O controller chip.
  *
  */
diff -Nru a/include/asm-ppc/kgdb.h b/include/asm-ppc/kgdb.h
--- a/include/asm-ppc/kgdb.h	Fri Sep 20 08:20:42 2002
+++ b/include/asm-ppc/kgdb.h	Fri Sep 20 08:20:42 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * kgdb.h: Defines and declarations for serial line source level
  *         remote debugging of the Linux kernel using gdb.
  *
diff -Nru a/include/asm-ppc/kmap_types.h b/include/asm-ppc/kmap_types.h
--- a/include/asm-ppc/kmap_types.h	Fri Sep 20 08:20:43 2002
+++ b/include/asm-ppc/kmap_types.h	Fri Sep 20 08:20:43 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifdef __KERNEL__
 #ifndef _ASM_KMAP_TYPES_H
 #define _ASM_KMAP_TYPES_H
diff -Nru a/include/asm-ppc/linux_logo.h b/include/asm-ppc/linux_logo.h
--- a/include/asm-ppc/linux_logo.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/linux_logo.h	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.linux_logo.h 1.7 05/17/01 18:14:24 cort
- */
-/*
  * include/asm-ppc/linux_logo.h: A linux logo to be displayed on boot
  * (pinched from the sparc port).
  *
diff -Nru a/include/asm-ppc/m48t35.h b/include/asm-ppc/m48t35.h
--- a/include/asm-ppc/m48t35.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc/m48t35.h	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.m48t35.h 1.8 10/16/01 15:58:42 trini
- */
-/*
  *  Registers for the SGS-Thomson M48T35 Timekeeper RAM chip
  *  and
  *  Registers for the SGS-Thomson M48T37 Timekeeper RAM chip
diff -Nru a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h
--- a/include/asm-ppc/machdep.h	Fri Sep 20 08:20:44 2002
+++ b/include/asm-ppc/machdep.h	Fri Sep 20 08:20:44 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifdef __KERNEL__
 #ifndef _PPC_MACHDEP_H
 #define _PPC_MACHDEP_H
diff -Nru a/include/asm-ppc/mc146818rtc.h b/include/asm-ppc/mc146818rtc.h
--- a/include/asm-ppc/mc146818rtc.h	Fri Sep 20 08:20:44 2002
+++ b/include/asm-ppc/mc146818rtc.h	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.mc146818rtc.h 1.5 05/17/01 18:14:25 cort
- */
-/*
  * Machine dependent access functions for RTC registers.
  */
 #ifdef __KERNEL__
diff -Nru a/include/asm-ppc/md.h b/include/asm-ppc/md.h
--- a/include/asm-ppc/md.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/md.h	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.md.h 1.5 05/17/01 18:14:25 cort
- */
-/*
  * md.h: High speed xor_block operation for RAID4/5 
  *
  */
diff -Nru a/include/asm-ppc/mediabay.h b/include/asm-ppc/mediabay.h
--- a/include/asm-ppc/mediabay.h	Fri Sep 20 08:20:42 2002
+++ b/include/asm-ppc/mediabay.h	Fri Sep 20 08:20:42 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * mediabay.h: definitions for using the media bay
  * on PowerBook 3400 and similar computers.
  *
diff -Nru a/include/asm-ppc/mk48t59.h b/include/asm-ppc/mk48t59.h
--- a/include/asm-ppc/mk48t59.h	Fri Sep 20 08:20:44 2002
+++ b/include/asm-ppc/mk48t59.h	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.mk48t59.h 1.5 05/17/01 18:14:25 cort
- */
-/*
  * Registers for the mk48t59 real-time-clock
  */
 
diff -Nru a/include/asm-ppc/mman.h b/include/asm-ppc/mman.h
--- a/include/asm-ppc/mman.h	Fri Sep 20 08:20:49 2002
+++ b/include/asm-ppc/mman.h	Fri Sep 20 08:20:49 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.mman.h 1.7 05/17/01 18:14:25 cort
- */
 #ifndef __PPC_MMAN_H__
 #define __PPC_MMAN_H__
 
diff -Nru a/include/asm-ppc/mmu.h b/include/asm-ppc/mmu.h
--- a/include/asm-ppc/mmu.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/mmu.h	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * PowerPC memory management structures
  */
 
diff -Nru a/include/asm-ppc/mmu_context.h b/include/asm-ppc/mmu_context.h
--- a/include/asm-ppc/mmu_context.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc/mmu_context.h	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifdef __KERNEL__
 #ifndef __PPC_MMU_CONTEXT_H
 #define __PPC_MMU_CONTEXT_H
diff -Nru a/include/asm-ppc/module.h b/include/asm-ppc/module.h
--- a/include/asm-ppc/module.h	Fri Sep 20 08:20:44 2002
+++ b/include/asm-ppc/module.h	Fri Sep 20 08:20:44 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.module.h 1.5 05/17/01 18:14:25 cort
- */
 #ifndef _ASM_PPC_MODULE_H
 #define _ASM_PPC_MODULE_H
 /*
diff -Nru a/include/asm-ppc/mpc8260.h b/include/asm-ppc/mpc8260.h
--- a/include/asm-ppc/mpc8260.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc/mpc8260.h	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
 /* This is the single file included by all MPC8260 build options.
  * Since there are many different boards and no standard configuration,
  * we have a unique include file for each.  Rather than change every
diff -Nru a/include/asm-ppc/mpc8xx.h b/include/asm-ppc/mpc8xx.h
--- a/include/asm-ppc/mpc8xx.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/mpc8xx.h	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
-
 /* This is the single file included by all MPC8xx build options.
  * Since there are many different boards and no standard configuration,
  * we have a unique include file for each.  Rather than change every
diff -Nru a/include/asm-ppc/msgbuf.h b/include/asm-ppc/msgbuf.h
--- a/include/asm-ppc/msgbuf.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc/msgbuf.h	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.msgbuf.h 1.5 05/17/01 18:14:25 cort
- */
 #ifndef _PPC_MSGBUF_H
 #define _PPC_MSGBUF_H
 
diff -Nru a/include/asm-ppc/namei.h b/include/asm-ppc/namei.h
--- a/include/asm-ppc/namei.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/namei.h	Fri Sep 20 08:20:47 2002
@@ -1,10 +1,8 @@
 /*
- * BK Id: SCCS/s.namei.h 1.5 05/17/01 18:14:25 cort
- */
-/* linux/include/asm-ppc/namei.h
- * Adapted from linux/include/asm-alpha/namei.h
+ * include/asm-ppc/namei.h
+ * Adapted from include/asm-alpha/namei.h
  *
- * Included from linux/fs/namei.c
+ * Included from fs/namei.c
  */
 
 #ifdef __KERNEL__
diff -Nru a/include/asm-ppc/nvram.h b/include/asm-ppc/nvram.h
--- a/include/asm-ppc/nvram.h	Fri Sep 20 08:20:48 2002
+++ b/include/asm-ppc/nvram.h	Fri Sep 20 08:20:48 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.nvram.h 1.5 05/17/01 18:14:25 cort
- */
-/*
  * PreP compliant NVRAM access
  */
 
diff -Nru a/include/asm-ppc/ohare.h b/include/asm-ppc/ohare.h
--- a/include/asm-ppc/ohare.h	Fri Sep 20 08:20:43 2002
+++ b/include/asm-ppc/ohare.h	Fri Sep 20 08:20:43 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * ohare.h: definitions for using the "O'Hare" I/O controller chip.
  *
  * Copyright (C) 1997 Paul Mackerras.
diff -Nru a/include/asm-ppc/open_pic.h b/include/asm-ppc/open_pic.h
--- a/include/asm-ppc/open_pic.h	Fri Sep 20 08:20:44 2002
+++ b/include/asm-ppc/open_pic.h	Fri Sep 20 08:20:44 2002
@@ -1,8 +1,5 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
- *  arch/ppc/kernel/open_pic.h -- OpenPIC Interrupt Handling
+ *  include/asm-ppc/open_pic.h -- OpenPIC Interrupt Handling
  *
  *  Copyright (C) 1997 Geert Uytterhoeven
  *
diff -Nru a/include/asm-ppc/page.h b/include/asm-ppc/page.h
--- a/include/asm-ppc/page.h	Fri Sep 20 08:20:44 2002
+++ b/include/asm-ppc/page.h	Fri Sep 20 08:20:44 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifndef _PPC_PAGE_H
 #define _PPC_PAGE_H
 
diff -Nru a/include/asm-ppc/param.h b/include/asm-ppc/param.h
--- a/include/asm-ppc/param.h	Fri Sep 20 08:20:44 2002
+++ b/include/asm-ppc/param.h	Fri Sep 20 08:20:44 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifndef _ASM_PPC_PARAM_H
 #define _ASM_PPC_PARAM_H
 
diff -Nru a/include/asm-ppc/parport.h b/include/asm-ppc/parport.h
--- a/include/asm-ppc/parport.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/parport.h	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.parport.h 1.5 05/17/01 18:14:25 cort
- */
-/*
  * parport.h: platform-specific PC-style parport initialisation
  *
  * Copyright (C) 1999, 2000  Tim Waugh <tim@cyberelk.demon.co.uk>
diff -Nru a/include/asm-ppc/pc_serial.h b/include/asm-ppc/pc_serial.h
--- a/include/asm-ppc/pc_serial.h	Fri Sep 20 08:20:43 2002
+++ b/include/asm-ppc/pc_serial.h	Fri Sep 20 08:20:43 2002
@@ -1,6 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- *
  * include/asm-ppc/pc_serial.h
  *
  * This is basically a copy of include/asm-i386/serial.h.
diff -Nru a/include/asm-ppc/pci-bridge.h b/include/asm-ppc/pci-bridge.h
--- a/include/asm-ppc/pci-bridge.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc/pci-bridge.h	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifdef __KERNEL__
 #ifndef _ASM_PCI_BRIDGE_H
 #define _ASM_PCI_BRIDGE_H
diff -Nru a/include/asm-ppc/pci.h b/include/asm-ppc/pci.h
--- a/include/asm-ppc/pci.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/pci.h	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifndef __PPC_PCI_H
 #define __PPC_PCI_H
 #ifdef __KERNEL__
diff -Nru a/include/asm-ppc/pgalloc.h b/include/asm-ppc/pgalloc.h
--- a/include/asm-ppc/pgalloc.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc/pgalloc.h	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifdef __KERNEL__
 #ifndef _PPC_PGALLOC_H
 #define _PPC_PGALLOC_H
diff -Nru a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h
--- a/include/asm-ppc/pgtable.h	Fri Sep 20 08:20:43 2002
+++ b/include/asm-ppc/pgtable.h	Fri Sep 20 08:20:43 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifdef __KERNEL__
 #ifndef _PPC_PGTABLE_H
 #define _PPC_PGTABLE_H
diff -Nru a/include/asm-ppc/pnp.h b/include/asm-ppc/pnp.h
--- a/include/asm-ppc/pnp.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc/pnp.h	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.pnp.h 1.5 05/17/01 18:14:25 cort
- */
 #ifdef __KERNEL__
 /* 11/02/95                                                                   */
 /*----------------------------------------------------------------------------*/
diff -Nru a/include/asm-ppc/poll.h b/include/asm-ppc/poll.h
--- a/include/asm-ppc/poll.h	Fri Sep 20 08:20:45 2002
+++ b/include/asm-ppc/poll.h	Fri Sep 20 08:20:45 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.poll.h 1.5 05/17/01 18:14:25 cort
- */
 #ifndef __PPC_POLL_H
 #define __PPC_POLL_H
 
diff -Nru a/include/asm-ppc/posix_types.h b/include/asm-ppc/posix_types.h
--- a/include/asm-ppc/posix_types.h	Fri Sep 20 08:20:45 2002
+++ b/include/asm-ppc/posix_types.h	Fri Sep 20 08:20:45 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifndef _PPC_POSIX_TYPES_H
 #define _PPC_POSIX_TYPES_H
 
diff -Nru a/include/asm-ppc/ppc4xx_pic.h b/include/asm-ppc/ppc4xx_pic.h
--- a/include/asm-ppc/ppc4xx_pic.h	Fri Sep 20 08:20:44 2002
+++ b/include/asm-ppc/ppc4xx_pic.h	Fri Sep 20 08:20:44 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  *
  *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
  *
diff -Nru a/include/asm-ppc/ppc_asm.h b/include/asm-ppc/ppc_asm.h
--- a/include/asm-ppc/ppc_asm.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc/ppc_asm.h	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * include/asm-ppc/ppc_asm.h
  *
  * Definitions used by various bits of low-level assembly code on PowerPC.
diff -Nru a/include/asm-ppc/prep_nvram.h b/include/asm-ppc/prep_nvram.h
--- a/include/asm-ppc/prep_nvram.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/prep_nvram.h	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.prep_nvram.h 1.7 05/17/01 18:14:25 cort
- */
-/*
  * PreP compliant NVRAM access
  */
 
diff -Nru a/include/asm-ppc/processor.h b/include/asm-ppc/processor.h
--- a/include/asm-ppc/processor.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc/processor.h	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifdef __KERNEL__
 #ifndef __ASM_PPC_PROCESSOR_H
 #define __ASM_PPC_PROCESSOR_H
diff -Nru a/include/asm-ppc/prom.h b/include/asm-ppc/prom.h
--- a/include/asm-ppc/prom.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/prom.h	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Definitions for talking to the Open Firmware PROM on
  * Power Macintosh computers.
  *
diff -Nru a/include/asm-ppc/ptrace.h b/include/asm-ppc/ptrace.h
--- a/include/asm-ppc/ptrace.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc/ptrace.h	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifndef _PPC_PTRACE_H
 #define _PPC_PTRACE_H
 
diff -Nru a/include/asm-ppc/raven.h b/include/asm-ppc/raven.h
--- a/include/asm-ppc/raven.h	Fri Sep 20 08:20:46 2002
+++ b/include/asm-ppc/raven.h	Fri Sep 20 08:20:46 2002
@@ -1,8 +1,5 @@
 /*
- * BK Id: SCCS/s.raven.h 1.7 05/17/01 18:14:25 cort
- */
-/*
- *  asm-ppc/raven.h -- Raven MPIC chip.
+ *  include/asm-ppc/raven.h -- Raven MPIC chip.
  *
  *  Copyright (C) 1998 Johnnie Peters
  *
diff -Nru a/include/asm-ppc/residual.h b/include/asm-ppc/residual.h
--- a/include/asm-ppc/residual.h	Fri Sep 20 08:20:46 2002
+++ b/include/asm-ppc/residual.h	Fri Sep 20 08:20:46 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.residual.h 1.8 08/09/01 09:11:24 trini
- */
 /* 7/18/95                                                                    */
 /*----------------------------------------------------------------------------*/
 /*      Residual Data header definitions and prototypes                       */
diff -Nru a/include/asm-ppc/resource.h b/include/asm-ppc/resource.h
--- a/include/asm-ppc/resource.h	Fri Sep 20 08:20:44 2002
+++ b/include/asm-ppc/resource.h	Fri Sep 20 08:20:44 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.resource.h 1.5 05/17/01 18:14:25 cort
- */
 #ifndef _PPC_RESOURCE_H
 #define _PPC_RESOURCE_H
 
diff -Nru a/include/asm-ppc/rwsem.h b/include/asm-ppc/rwsem.h
--- a/include/asm-ppc/rwsem.h	Fri Sep 20 08:20:48 2002
+++ b/include/asm-ppc/rwsem.h	Fri Sep 20 08:20:48 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * include/asm-ppc/rwsem.h: R/W semaphores for PPC using the stuff
  * in lib/rwsem.c.  Adapted largely from include/asm-i386/rwsem.h
  * by Paul Mackerras <paulus@samba.org>.
diff -Nru a/include/asm-ppc/scatterlist.h b/include/asm-ppc/scatterlist.h
--- a/include/asm-ppc/scatterlist.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc/scatterlist.h	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifdef __KERNEL__
 #ifndef _PPC_SCATTERLIST_H
 #define _PPC_SCATTERLIST_H
diff -Nru a/include/asm-ppc/sections.h b/include/asm-ppc/sections.h
--- a/include/asm-ppc/sections.h	Fri Sep 20 08:20:48 2002
+++ b/include/asm-ppc/sections.h	Fri Sep 20 08:20:48 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.sections.h 1.11 09/08/01 15:47:43 paulus
- */
 #ifdef __KERNEL__
 #ifndef _PPC_SECTIONS_H
 #define _PPC_SECTIONS_H
diff -Nru a/include/asm-ppc/segment.h b/include/asm-ppc/segment.h
--- a/include/asm-ppc/segment.h	Fri Sep 20 08:20:44 2002
+++ b/include/asm-ppc/segment.h	Fri Sep 20 08:20:44 2002
@@ -1,4 +1 @@
-/*
- * BK Id: SCCS/s.segment.h 1.7 05/17/01 18:14:25 cort
- */
 #include <asm/uaccess.h>
diff -Nru a/include/asm-ppc/semaphore.h b/include/asm-ppc/semaphore.h
--- a/include/asm-ppc/semaphore.h	Fri Sep 20 08:20:46 2002
+++ b/include/asm-ppc/semaphore.h	Fri Sep 20 08:20:46 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifndef _PPC_SEMAPHORE_H
 #define _PPC_SEMAPHORE_H
 
diff -Nru a/include/asm-ppc/sembuf.h b/include/asm-ppc/sembuf.h
--- a/include/asm-ppc/sembuf.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/sembuf.h	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.sembuf.h 1.5 05/17/01 18:14:25 cort
- */
 #ifndef _PPC_SEMBUF_H
 #define _PPC_SEMBUF_H
 
diff -Nru a/include/asm-ppc/serial.h b/include/asm-ppc/serial.h
--- a/include/asm-ppc/serial.h	Fri Sep 20 08:20:48 2002
+++ b/include/asm-ppc/serial.h	Fri Sep 20 08:20:48 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * include/asm-ppc/serial.h
  */
 
diff -Nru a/include/asm-ppc/setup.h b/include/asm-ppc/setup.h
--- a/include/asm-ppc/setup.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/setup.h	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.setup.h 1.5 05/17/01 18:14:25 cort
- */
 #ifdef __KERNEL__
 #ifndef _PPC_SETUP_H
 #define _PPC_SETUP_H
diff -Nru a/include/asm-ppc/shmbuf.h b/include/asm-ppc/shmbuf.h
--- a/include/asm-ppc/shmbuf.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/shmbuf.h	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.shmbuf.h 1.5 05/17/01 18:14:25 cort
- */
 #ifndef _PPC_SHMBUF_H
 #define _PPC_SHMBUF_H
 
diff -Nru a/include/asm-ppc/shmparam.h b/include/asm-ppc/shmparam.h
--- a/include/asm-ppc/shmparam.h	Fri Sep 20 08:20:43 2002
+++ b/include/asm-ppc/shmparam.h	Fri Sep 20 08:20:43 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.shmparam.h 1.5 05/17/01 18:14:25 cort
- */
 #ifndef _PPC_SHMPARAM_H
 #define _PPC_SHMPARAM_H
 
diff -Nru a/include/asm-ppc/sigcontext.h b/include/asm-ppc/sigcontext.h
--- a/include/asm-ppc/sigcontext.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc/sigcontext.h	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.sigcontext.h 1.5 05/17/01 18:14:25 cort
- */
 #ifndef _ASM_PPC_SIGCONTEXT_H
 #define _ASM_PPC_SIGCONTEXT_H
 
diff -Nru a/include/asm-ppc/siginfo.h b/include/asm-ppc/siginfo.h
--- a/include/asm-ppc/siginfo.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc/siginfo.h	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.siginfo.h 1.5 05/17/01 18:14:25 cort
- */
 #ifndef _PPC_SIGINFO_H
 #define _PPC_SIGINFO_H
 
diff -Nru a/include/asm-ppc/signal.h b/include/asm-ppc/signal.h
--- a/include/asm-ppc/signal.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc/signal.h	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.signal.h 1.5 05/17/01 18:14:25 cort
- */
 #ifndef _ASMPPC_SIGNAL_H
 #define _ASMPPC_SIGNAL_H
 
diff -Nru a/include/asm-ppc/smp.h b/include/asm-ppc/smp.h
--- a/include/asm-ppc/smp.h	Fri Sep 20 08:20:43 2002
+++ b/include/asm-ppc/smp.h	Fri Sep 20 08:20:43 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 /* smp.h: PPC specific SMP stuff.
  *
  * Original was a copy of sparc smp.h.  Now heavily modified
diff -Nru a/include/asm-ppc/socket.h b/include/asm-ppc/socket.h
--- a/include/asm-ppc/socket.h	Fri Sep 20 08:20:45 2002
+++ b/include/asm-ppc/socket.h	Fri Sep 20 08:20:45 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.socket.h 1.6 05/17/01 18:14:25 cort
- */
 #ifndef _ASM_SOCKET_H
 #define _ASM_SOCKET_H
 
diff -Nru a/include/asm-ppc/sockios.h b/include/asm-ppc/sockios.h
--- a/include/asm-ppc/sockios.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc/sockios.h	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.sockios.h 1.5 05/17/01 18:14:25 cort
- */
 #ifndef _ASM_PPC_SOCKIOS_H
 #define _ASM_PPC_SOCKIOS_H
 
diff -Nru a/include/asm-ppc/softirq.h b/include/asm-ppc/softirq.h
--- a/include/asm-ppc/softirq.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/softirq.h	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifdef __KERNEL__
 #ifndef __ASM_SOFTIRQ_H
 #define __ASM_SOFTIRQ_H
diff -Nru a/include/asm-ppc/spinlock.h b/include/asm-ppc/spinlock.h
--- a/include/asm-ppc/spinlock.h	Fri Sep 20 08:20:44 2002
+++ b/include/asm-ppc/spinlock.h	Fri Sep 20 08:20:44 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifndef __ASM_SPINLOCK_H
 #define __ASM_SPINLOCK_H
 
diff -Nru a/include/asm-ppc/stat.h b/include/asm-ppc/stat.h
--- a/include/asm-ppc/stat.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc/stat.h	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.stat.h 1.5 05/17/01 18:14:26 cort
- */
 #ifndef _PPC_STAT_H
 #define _PPC_STAT_H
 
diff -Nru a/include/asm-ppc/statfs.h b/include/asm-ppc/statfs.h
--- a/include/asm-ppc/statfs.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc/statfs.h	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.statfs.h 1.5 05/17/01 18:14:26 cort
- */
 #ifndef _PPC_STATFS_H
 #define _PPC_STATFS_H
 
diff -Nru a/include/asm-ppc/string.h b/include/asm-ppc/string.h
--- a/include/asm-ppc/string.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/string.h	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.string.h 1.5 05/17/01 18:14:26 cort
- */
 #ifndef _PPC_STRING_H_
 #define _PPC_STRING_H_
 
diff -Nru a/include/asm-ppc/system.h b/include/asm-ppc/system.h
--- a/include/asm-ppc/system.h	Fri Sep 20 08:20:44 2002
+++ b/include/asm-ppc/system.h	Fri Sep 20 08:20:45 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
  */
 #ifndef __PPC_SYSTEM_H
diff -Nru a/include/asm-ppc/termbits.h b/include/asm-ppc/termbits.h
--- a/include/asm-ppc/termbits.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/termbits.h	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.termbits.h 1.5 05/17/01 18:14:26 cort
- */
 #ifndef _PPC_TERMBITS_H
 #define _PPC_TERMBITS_H
 
diff -Nru a/include/asm-ppc/termios.h b/include/asm-ppc/termios.h
--- a/include/asm-ppc/termios.h	Fri Sep 20 08:20:48 2002
+++ b/include/asm-ppc/termios.h	Fri Sep 20 08:20:48 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.termios.h 1.8 05/17/01 18:14:26 cort
- */
 #ifndef _PPC_TERMIOS_H
 #define _PPC_TERMIOS_H
 
diff -Nru a/include/asm-ppc/time.h b/include/asm-ppc/time.h
--- a/include/asm-ppc/time.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc/time.h	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * Common time prototypes and such for all ppc machines.
  *
  * Written by Cort Dougan (cort@fsmlabs.com) to merge
diff -Nru a/include/asm-ppc/timex.h b/include/asm-ppc/timex.h
--- a/include/asm-ppc/timex.h	Fri Sep 20 08:20:46 2002
+++ b/include/asm-ppc/timex.h	Fri Sep 20 08:20:46 2002
@@ -1,8 +1,5 @@
 /*
- * BK Id: SCCS/s.timex.h 1.8 08/15/01 22:43:07 paulus
- */
-/*
- * linux/include/asm-ppc/timex.h
+ * include/asm-ppc/timex.h
  *
  * ppc architecture timex specifications
  */
diff -Nru a/include/asm-ppc/tlbflush.h b/include/asm-ppc/tlbflush.h
--- a/include/asm-ppc/tlbflush.h	Fri Sep 20 08:20:43 2002
+++ b/include/asm-ppc/tlbflush.h	Fri Sep 20 08:20:43 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: %F% %I% %G% %U% %#%
- */
-/*
  * include/asm-ppc/tlbflush.h
  *
  *  This program is free software; you can redistribute it and/or
diff -Nru a/include/asm-ppc/traps.h b/include/asm-ppc/traps.h
--- a/include/asm-ppc/traps.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/traps.h	Fri Sep 20 08:20:47 2002
@@ -1,4 +1 @@
-/*
- * BK Id: SCCS/s.traps.h 1.5 05/17/01 18:14:26 cort
- */
 #include <asm-m68k/traps.h>
diff -Nru a/include/asm-ppc/types.h b/include/asm-ppc/types.h
--- a/include/asm-ppc/types.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/types.h	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.types.h 1.10 10/15/01 22:51:33 paulus
- */
 #ifndef _PPC_TYPES_H
 #define _PPC_TYPES_H
 
diff -Nru a/include/asm-ppc/uaccess.h b/include/asm-ppc/uaccess.h
--- a/include/asm-ppc/uaccess.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc/uaccess.h	Fri Sep 20 08:20:41 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifdef __KERNEL__
 #ifndef _PPC_UACCESS_H
 #define _PPC_UACCESS_H
diff -Nru a/include/asm-ppc/ucontext.h b/include/asm-ppc/ucontext.h
--- a/include/asm-ppc/ucontext.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/ucontext.h	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.ucontext.h 1.5 05/17/01 18:14:26 cort
- */
 #ifndef _ASMPPC_UCONTEXT_H
 #define _ASMPPC_UCONTEXT_H
 
diff -Nru a/include/asm-ppc/unaligned.h b/include/asm-ppc/unaligned.h
--- a/include/asm-ppc/unaligned.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/unaligned.h	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.unaligned.h 1.5 05/17/01 18:14:26 cort
- */
 #ifdef __KERNEL__
 #ifndef __PPC_UNALIGNED_H
 #define __PPC_UNALIGNED_H
diff -Nru a/include/asm-ppc/uninorth.h b/include/asm-ppc/uninorth.h
--- a/include/asm-ppc/uninorth.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/uninorth.h	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.uninorth.h 1.13 10/23/01 08:09:35 trini
- */
-/*
  * uninorth.h: definitions for using the "UniNorth" host bridge chip
  *             from Apple. This chip is used on "Core99" machines
  *
diff -Nru a/include/asm-ppc/unistd.h b/include/asm-ppc/unistd.h
--- a/include/asm-ppc/unistd.h	Fri Sep 20 08:20:43 2002
+++ b/include/asm-ppc/unistd.h	Fri Sep 20 08:20:43 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: %F% %I% %G% %U% %#%
- */
 #ifndef _ASM_PPC_UNISTD_H_
 #define _ASM_PPC_UNISTD_H_
 
diff -Nru a/include/asm-ppc/user.h b/include/asm-ppc/user.h
--- a/include/asm-ppc/user.h	Fri Sep 20 08:20:47 2002
+++ b/include/asm-ppc/user.h	Fri Sep 20 08:20:47 2002
@@ -1,6 +1,3 @@
-/*
- * BK Id: SCCS/s.user.h 1.5 05/17/01 18:14:26 cort
- */
 #ifdef __KERNEL__
 #ifndef _PPC_USER_H
 #define _PPC_USER_H
diff -Nru a/include/asm-ppc/vga.h b/include/asm-ppc/vga.h
--- a/include/asm-ppc/vga.h	Fri Sep 20 08:20:48 2002
+++ b/include/asm-ppc/vga.h	Fri Sep 20 08:20:48 2002
@@ -1,7 +1,4 @@
 /*
- * BK Id: SCCS/s.vga.h 1.5 05/17/01 18:14:26 cort
- */
-/*
  *	Access to VGA videoram
  *
  *	(c) 1998 Martin Mares <mj@ucw.cz>
diff -Nru a/include/asm-ppc/xor.h b/include/asm-ppc/xor.h
--- a/include/asm-ppc/xor.h	Fri Sep 20 08:20:46 2002
+++ b/include/asm-ppc/xor.h	Fri Sep 20 08:20:46 2002
@@ -1,4 +1 @@
-/*
- * BK Id: SCCS/s.xor.h 1.5 05/17/01 18:14:26 cort
- */
 #include <asm-generic/xor.h>
diff -Nru a/include/asm-ppc64/hardirq.h b/include/asm-ppc64/hardirq.h
--- a/include/asm-ppc64/hardirq.h	Fri Sep 20 08:20:43 2002
+++ b/include/asm-ppc64/hardirq.h	Fri Sep 20 08:20:43 2002
@@ -112,4 +112,6 @@
 		print_backtrace(_get_SP());	\
 } while (0)
 
+#define dump_stack()	show_stack()
+
 #endif /* __ASM_HARDIRQ_H */
diff -Nru a/include/asm-ppc64/hw_irq.h b/include/asm-ppc64/hw_irq.h
--- a/include/asm-ppc64/hw_irq.h	Fri Sep 20 08:20:46 2002
+++ b/include/asm-ppc64/hw_irq.h	Fri Sep 20 08:20:46 2002
@@ -16,6 +16,7 @@
 #include <asm/irq.h>
 
 int timer_interrupt(struct pt_regs *);
+extern void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq);
 
 #ifdef CONFIG_PPC_ISERIES
 
diff -Nru a/include/asm-ppc64/iSeries/LparData.h b/include/asm-ppc64/iSeries/LparData.h
--- a/include/asm-ppc64/iSeries/LparData.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc64/iSeries/LparData.h	Fri Sep 20 08:20:41 2002
@@ -17,10 +17,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#ifndef	_PPC_TYPES_H
-#include	<asm/types.h>
-#endif
-
 #ifndef _LPARDATA_H
 #define _LPARDATA_H
 
@@ -40,7 +36,6 @@
 #include <asm/iSeries/ItExtVpdPanel.h>
 #include <asm/iSeries/ItLpQueue.h>
 #include <asm/iSeries/IoHriProcessorVpd.h>
-#include <asm/page.h>
 
 extern struct LparMap	xLparMap;
 extern struct HvReleaseData hvReleaseData;
diff -Nru a/include/asm-ppc64/irq.h b/include/asm-ppc64/irq.h
--- a/include/asm-ppc64/irq.h	Fri Sep 20 08:20:48 2002
+++ b/include/asm-ppc64/irq.h	Fri Sep 20 08:20:48 2002
@@ -51,5 +51,7 @@
 	return irq;
 }
 
+#define NR_MASK_WORDS	((NR_IRQS + 63) / 64)
+
 #endif /* _ASM_IRQ_H */
 #endif /* __KERNEL__ */
diff -Nru a/include/asm-ppc64/machdep.h b/include/asm-ppc64/machdep.h
--- a/include/asm-ppc64/machdep.h	Fri Sep 20 08:20:44 2002
+++ b/include/asm-ppc64/machdep.h	Fri Sep 20 08:20:44 2002
@@ -1,6 +1,6 @@
 #ifdef __KERNEL__
-#ifndef _PPC_MACHDEP_H
-#define _PPC_MACHDEP_H
+#ifndef _PPC64_MACHDEP_H
+#define _PPC64_MACHDEP_H
 
 /*
  * This program is free software; you can redistribute it and/or
@@ -14,7 +14,6 @@
 
 struct pt_regs;
 struct pci_bus;	
-struct pci_dev;
 struct device_node;
 struct TceTable;
 struct rtc_time;
@@ -70,30 +69,25 @@
 	void		(*setup_residual)(struct seq_file *m, int cpu_id);
 	/* Optional, may be NULL. */
 	void		(*get_cpuinfo)(struct seq_file *m);
-	/* Optional, may be NULL. */
-	unsigned int	(*irq_cannonicalize)(unsigned int irq);
+
 	void		(*init_IRQ)(void);
 	void		(*init_ras_IRQ)(void);
 	int		(*get_irq)(struct pt_regs *);
-	
-	/* A general init function, called by ppc_init in init/main.c.
-	   May be NULL. */
+
+	/* Optional, may be NULL. */
 	void		(*init)(void);
 
 	void		(*restart)(char *cmd);
 	void		(*power_off)(void);
 	void		(*halt)(void);
 
-	long		(*time_init)(void); /* Optional, may be NULL */
 	int		(*set_rtc_time)(struct rtc_time *);
 	void		(*get_rtc_time)(struct rtc_time *);
 	void		(*get_boot_time)(struct rtc_time *);
-	void		(*calibrate_decr)(void);
 
-  	void		(*progress)(char *, unsigned short);
+	void		(*calibrate_decr)(void);
 
-	unsigned char 	(*nvram_read_val)(int addr);
-	void		(*nvram_write_val)(int addr, unsigned char val);
+	void		(*progress)(char *, unsigned short);
 
 	/* Debug interface.  Low level I/O to some terminal device */
 	void		(*udbg_putc)(unsigned char c);
@@ -101,32 +95,21 @@
 	int		(*udbg_getc_poll)(void);
 
 	/* PCI interfaces */
-	int (*pcibios_read_config)(struct device_node *dn, int where, int size, u32 *val);
-	int (*pcibios_write_config)(struct device_node *dn, int where, int size, u32 val);
+	int (*pcibios_read_config)(struct device_node *dn, int where, int size,
+				   u32 *val);
+	int (*pcibios_write_config)(struct device_node *dn, int where,
+				    int size, u32 val);
 
 	/* Called after scanning the bus, before allocating
 	 * resources
 	 */
 	void (*pcibios_fixup)(void);
 
-       /* Called for each PCI bus in the system
-        * when it's probed
-        */
+	/* Called for each PCI bus in the system
+	 * when it's probed
+	 */
 	void (*pcibios_fixup_bus)(struct pci_bus *);
 
-       /* Called when pci_enable_device() is called (initial=0) or
-        * when a device with no assigned resource is found (initial=1).
-        * Returns 0 to allow assignement/enabling of the device
-        */
-        int  (*pcibios_enable_device_hook)(struct pci_dev *, int initial);
-
-	void* (*pci_dev_io_base)(unsigned char bus, unsigned char devfn, int physical);
-	void* (*pci_dev_mem_base)(unsigned char bus, unsigned char devfn);
-	int (*pci_dev_root_bridge)(unsigned char bus, unsigned char devfn);
-
-	/* this is for modules, since _machine can be a define -- Cort */
-	int ppc_machine;
-
 #ifdef CONFIG_SMP
 	/* functions for dealing with other cpus */
 	struct smp_ops_t smp_ops;
@@ -136,7 +119,5 @@
 extern struct machdep_calls ppc_md;
 extern char cmd_line[512];
 
-extern void setup_pci_ptrs(void);
-
-#endif /* _PPC_MACHDEP_H */
+#endif /* _PPC64_MACHDEP_H */
 #endif /* __KERNEL__ */
diff -Nru a/include/asm-ppc64/mman.h b/include/asm-ppc64/mman.h
--- a/include/asm-ppc64/mman.h	Fri Sep 20 08:20:45 2002
+++ b/include/asm-ppc64/mman.h	Fri Sep 20 08:20:45 2002
@@ -21,6 +21,7 @@
 #define MAP_ANONYMOUS	0x20		/* don't use a file */
 #define MAP_RENAME      MAP_ANONYMOUS   /* In SunOS terminology */
 #define MAP_NORESERVE   0x40            /* don't reserve swap pages */
+#define MAP_LOCKED	0x80
 
 #define MAP_GROWSDOWN	0x0100		/* stack-like segment */
 #define MAP_DENYWRITE	0x0800		/* ETXTBSY */
diff -Nru a/include/asm-ppc64/mmzone.h b/include/asm-ppc64/mmzone.h
--- a/include/asm-ppc64/mmzone.h	Fri Sep 20 08:20:48 2002
+++ b/include/asm-ppc64/mmzone.h	Fri Sep 20 08:20:48 2002
@@ -8,10 +8,11 @@
 #define _ASM_MMZONE_H_
 
 #include <linux/config.h>
+#include <asm/smp.h>
 
 #ifdef CONFIG_DISCONTIGMEM
 
-extern struct pglist_data *node_data[];
+extern struct pglist_data node_data[];
 
 /*
  * Following are specific to this numa platform.
@@ -21,51 +22,54 @@
 extern int numa_cpu_lookup_table[];
 extern int numa_memory_lookup_table[];
 
-#define MAX_NUMNODES 16
 #define MAX_MEMORY (1UL << 41)
 /* 256MB regions */
 #define MEMORY_INCREMENT_SHIFT 28
 #define MEMORY_INCREMENT (1UL << MEMORY_INCREMENT_SHIFT)
 
-#undef DEBUG_NUMA
+#define DEBUG_NUMA
 
 static inline int pa_to_nid(unsigned long pa)
 {
-        int nid;
+	int nid;
 
-        nid = numa_memory_lookup_table[pa >> MEMORY_INCREMENT_SHIFT];
+	nid = numa_memory_lookup_table[pa >> MEMORY_INCREMENT_SHIFT];
 
 #ifdef DEBUG_NUMA
-        /* the physical address passed in is not in the map for the system */
-        if (nid == -1) {
-                printk("bad address: %lx\n", pa);
-                BUG();
-        }
+	/* the physical address passed in is not in the map for the system */
+	if (nid == -1) {
+		printk("bad address: %lx\n", pa);
+		BUG();
+	}
 #endif
 
-        return nid;
+	return nid;
 }
 
 #define pfn_to_nid(pfn)		pa_to_nid((pfn) << PAGE_SHIFT)
 
-#define node_startnr(nid)	(node_data[nid]->node_start_mapnr)
-#define node_size(nid)		(node_data[nid]->node_size)
-#define node_localnr(pfn, nid)	((pfn) - node_data[nid]->node_start_pfn)
+/*
+ * Return a pointer to the node data for node n.
+ */
+#define NODE_DATA(nid)		(&node_data[nid])
+
+#define node_size(nid)		(NODE_DATA(nid)->node_size)
+#define node_localnr(pfn, nid)	((pfn) - NODE_DATA(nid)->node_start_pfn)
 
 #ifdef CONFIG_NUMA
 
 static inline int __cpu_to_node(int cpu)
 {
-        int node;
+	int node;
 
-        node = numa_cpu_lookup_table[cpu];
+	node = numa_cpu_lookup_table[cpu];
 
 #ifdef DEBUG_NUMA
-        if (node == -1)
-                BUG();
+	if (node == -1)
+		BUG();
 #endif
 
-        return node;
+	return node;
 }
 
 #define numa_node_id()	__cpu_to_node(smp_processor_id())
@@ -80,13 +84,9 @@
  */
 #define kvaddr_to_nid(kaddr)	pa_to_nid(__pa(kaddr))
 
-/*
- * Return a pointer to the node data for node n.
- */
-#define NODE_DATA(nid)		(node_data[nid])
-
 #define node_mem_map(nid)	(NODE_DATA(nid)->node_mem_map)
 #define node_start_pfn(nid)	(NODE_DATA(nid)->node_start_pfn)
+#define node_end_pfn(nid)	(NODE_DATA(nid)->node_end_pfn)
 
 #define local_mapnr(kvaddr) \
 	( (__pa(kvaddr) >> PAGE_SHIFT) - node_start_pfn(kvaddr_to_nid(kvaddr)) 
@@ -105,12 +105,15 @@
 	 node_localnr(__tmp, pfn_to_nid(__tmp))); \
 })
 
-#define discontigmem_page_to_pfn(p)	\
+#define discontigmem_page_to_pfn(p) \
 ({ \
 	struct page *__tmp = p; \
 	(((__tmp) - page_zone(__tmp)->zone_mem_map) + \
 	 page_zone(__tmp)->zone_start_pfn); \
 })
+
+/* XXX fix for discontiguous physical memory */
+#define discontigmem_pfn_valid(pfn)		((pfn) < num_physpages)
 
 #endif /* CONFIG_DISCONTIGMEM */
 #endif /* _ASM_MMZONE_H_ */
diff -Nru a/include/asm-ppc64/numnodes.h b/include/asm-ppc64/numnodes.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc64/numnodes.h	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,6 @@
+#ifndef _ASM_MAX_NUMNODES_H
+#define _ASM_MAX_NUMNODES_H
+
+#define MAX_NUMNODES 16
+
+#endif /* _ASM_MAX_NUMNODES_H */
diff -Nru a/include/asm-ppc64/page.h b/include/asm-ppc64/page.h
--- a/include/asm-ppc64/page.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc64/page.h	Fri Sep 20 08:20:41 2002
@@ -207,13 +207,15 @@
 #ifdef CONFIG_DISCONTIGMEM
 #define page_to_pfn(page)	discontigmem_page_to_pfn(page)
 #define pfn_to_page(pfn)	discontigmem_pfn_to_page(pfn)
+#define pfn_valid(pfn)		discontigmem_pfn_valid(pfn)
 #else
 #define pfn_to_page(pfn)	(mem_map + (pfn))
 #define page_to_pfn(page)	((unsigned long)((page) - mem_map))
+#define pfn_valid(pfn)		((pfn) < max_mapnr)
 #endif
+
 #define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
 
-#define pfn_valid(pfn)		((pfn) < max_mapnr)
 #define virt_addr_valid(kaddr)	pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
 
 #define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | VM_EXEC | \
diff -Nru a/include/asm-ppc64/pci-bridge.h b/include/asm-ppc64/pci-bridge.h
--- a/include/asm-ppc64/pci-bridge.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc64/pci-bridge.h	Fri Sep 20 08:20:41 2002
@@ -57,10 +57,6 @@
 	unsigned long pci_io_offset;
 
 	struct pci_ops *ops;
-	volatile unsigned long *cfg_addr;
-	volatile unsigned char *cfg_data;
-	volatile unsigned long *phb_regs;
-	volatile unsigned long *chip_regs;
 
 	/* Currently, we limit ourselves to 1 IO range and 3 mem
 	 * ranges since the common pci_bus structure can't handle more
@@ -68,29 +64,13 @@
 	struct resource io_resource;
 	struct resource mem_resources[3];
 	int mem_resource_count;
-	int    global_number;		
-	int    local_number;		
-	int    system_bus_number;	
+	int global_number;		
+	int local_number;		
 	unsigned long buid;
 	unsigned long dma_window_base_cur;
 	unsigned long dma_window_size;
 };
 
-
-/* This version handles the new Uni-N host bridge, the iobase is now
- * a per-device thing. I also added the memory base so PReP can
- * be fixed to return 0xc0000000 (I didn't actually implement it)
- *
- * pci_dev_io_base() returns either a virtual (ioremap'ed) address or
- * a physical address. In-kernel clients will use logical while the
- * sys_pciconfig_iobase syscall returns a physical one to userland.
- */
-void *pci_dev_io_base(unsigned char bus, unsigned char devfn, int physical);
-void *pci_dev_mem_base(unsigned char bus, unsigned char devfn);
-
-/* Returns the root-bridge number (Uni-N number) of a device */
-int pci_dev_root_bridge(unsigned char bus, unsigned char devfn);
-
 /*
  * pci_device_loc returns the bus number and device/function number
  * for a device on a PCI bus, given its device_node struct.
@@ -98,17 +78,6 @@
  */
 int pci_device_loc(struct device_node *dev, unsigned char *bus_ptr,
 		   unsigned char *devfn_ptr);
-
-struct bridge_data {
-	volatile unsigned int *cfg_addr;
-	volatile unsigned char *cfg_data;
-	void *io_base;		/* virtual */
-	unsigned long io_base_phys;
-	int bus_number;
-	int max_bus;
-	struct bridge_data *next;
-	struct device_node *node;
-};
 
 #endif
 #endif /* __KERNEL__ */
diff -Nru a/include/asm-ppc64/pgtable.h b/include/asm-ppc64/pgtable.h
--- a/include/asm-ppc64/pgtable.h	Fri Sep 20 08:20:48 2002
+++ b/include/asm-ppc64/pgtable.h	Fri Sep 20 08:20:48 2002
@@ -35,12 +35,7 @@
 #define PTRS_PER_PMD	(1 << PMD_INDEX_SIZE)
 #define PTRS_PER_PGD	(1 << PGD_INDEX_SIZE)
 
-#if 0
-/* DRENG / PPPBBB This is a compiler bug!!! */
-#define USER_PTRS_PER_PGD	(TASK_SIZE / PGDIR_SIZE)
-#else
-#define USER_PTRS_PER_PGD	(1024)
-#endif
+#define USER_PTRS_PER_PGD	(TASK_SIZE_USER64 / PGDIR_SIZE)
 #define FIRST_USER_PGD_NR	0
 
 #define EADDR_SIZE (PTE_INDEX_SIZE + PMD_INDEX_SIZE + \
diff -Nru a/include/asm-ppc64/ppc_asm.h b/include/asm-ppc64/ppc_asm.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc64/ppc_asm.h	Fri Sep 20 08:20:44 2002
@@ -0,0 +1,227 @@
+/*
+ * arch/ppc64/kernel/ppc_asm.h
+ *
+ * Definitions used by various bits of low-level assembly code on PowerPC.
+ *
+ * Copyright (C) 1995-1999 Gary Thomas, Paul Mackerras, Cort Dougan.
+ *
+ *  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.
+ */
+
+/*
+ * Macros for storing registers into and loading registers from
+ * exception frames.
+ */
+#define SAVE_GPR(n, base)	std	n,GPR0+8*(n)(base)
+#define SAVE_2GPRS(n, base)	SAVE_GPR(n, base); SAVE_GPR(n+1, base)
+#define SAVE_4GPRS(n, base)	SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
+#define SAVE_8GPRS(n, base)	SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
+#define SAVE_10GPRS(n, base)	SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
+#define REST_GPR(n, base)	ld	n,GPR0+8*(n)(base)
+#define REST_2GPRS(n, base)	REST_GPR(n, base); REST_GPR(n+1, base)
+#define REST_4GPRS(n, base)	REST_2GPRS(n, base); REST_2GPRS(n+2, base)
+#define REST_8GPRS(n, base)	REST_4GPRS(n, base); REST_4GPRS(n+4, base)
+#define REST_10GPRS(n, base)	REST_8GPRS(n, base); REST_2GPRS(n+8, base)
+
+#define SAVE_FPR(n, base)	stfd	n,THREAD_FPR0+8*(n)(base)
+#define SAVE_2FPRS(n, base)	SAVE_FPR(n, base); SAVE_FPR(n+1, base)
+#define SAVE_4FPRS(n, base)	SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base)
+#define SAVE_8FPRS(n, base)	SAVE_4FPRS(n, base); SAVE_4FPRS(n+4, base)
+#define SAVE_16FPRS(n, base)	SAVE_8FPRS(n, base); SAVE_8FPRS(n+8, base)
+#define SAVE_32FPRS(n, base)	SAVE_16FPRS(n, base); SAVE_16FPRS(n+16, base)
+#define REST_FPR(n, base)	lfd	n,THREAD_FPR0+8*(n)(base)
+#define REST_2FPRS(n, base)	REST_FPR(n, base); REST_FPR(n+1, base)
+#define REST_4FPRS(n, base)	REST_2FPRS(n, base); REST_2FPRS(n+2, base)
+#define REST_8FPRS(n, base)	REST_4FPRS(n, base); REST_4FPRS(n+4, base)
+#define REST_16FPRS(n, base)	REST_8FPRS(n, base); REST_8FPRS(n+8, base)
+#define REST_32FPRS(n, base)	REST_16FPRS(n, base); REST_16FPRS(n+16, base)
+
+#define CHECKANYINT(ra,rb)			\
+	mfspr	rb,SPRG3;		/* Get Paca address */\
+	ld	ra,PACALPPACA+LPPACAANYINT(rb); /* Get pending interrupt flags */\
+	cmpldi	0,ra,0;
+
+/* Macros to adjust thread priority for Iseries hardware multithreading */
+#define HMT_LOW		or 1,1,1
+#define HMT_MEDIUM	or 2,2,2
+#define HMT_HIGH	or 3,3,3
+
+/* Insert the high 32 bits of the MSR into what will be the new
+   MSR (via SRR1 and rfid)  This preserves the MSR.SF and MSR.ISF
+   bits. */
+
+#define FIX_SRR1(ra, rb)	\
+	mr	rb,ra;		\
+	mfmsr	ra;		\
+	rldimi	ra,rb,0,32
+
+#define CLR_TOP32(r)	rlwinm	(r),(r),0,0,31	/* clear top 32 bits */
+
+/* 
+ * LOADADDR( rn, name )
+ *   loads the address of 'name' into 'rn'
+ *
+ * LOADBASE( rn, name )
+ *   loads the address (less the low 16 bits) of 'name' into 'rn'
+ *   suitable for base+disp addressing
+ */
+#define LOADADDR(rn,name) \
+	lis	rn,name##@highest;	\
+	ori	rn,rn,name##@higher;	\
+	rldicr	rn,rn,32,31;		\
+	oris	rn,rn,name##@h;		\
+	ori	rn,rn,name##@l
+
+#define LOADBASE(rn,name) \
+	lis	rn,name@highest;	\
+	ori	rn,rn,name@higher;	\
+	rldicr	rn,rn,32,31;		\
+	oris	rn,rn,name@ha
+
+
+#define SET_REG_TO_CONST(reg, value)	         	\
+	lis     reg,(((value)>>48)&0xFFFF);             \
+	ori     reg,reg,(((value)>>32)&0xFFFF);         \
+	rldicr  reg,reg,32,31;                          \
+	oris    reg,reg,(((value)>>16)&0xFFFF);         \
+	ori     reg,reg,((value)&0xFFFF);
+
+#define SET_REG_TO_LABEL(reg, label)	         	\
+	lis     reg,(label)@highest;                    \
+	ori     reg,reg,(label)@higher;                 \
+	rldicr  reg,reg,32,31;                          \
+	oris    reg,reg,(label)@h;                      \
+	ori     reg,reg,(label)@l;
+
+
+/* PPPBBB - DRENG  If KERNELBASE is always 0xC0...,
+ * Then we can easily do this with one asm insn. -Peter
+ */
+#define tophys(rd,rs)                           \
+        lis     rd,((KERNELBASE>>48)&0xFFFF);   \
+        rldicr  rd,rd,32,31;                    \
+        sub     rd,rs,rd
+
+#define tovirt(rd,rs)                           \
+        lis     rd,((KERNELBASE>>48)&0xFFFF);   \
+        rldicr  rd,rd,32,31;                    \
+        add     rd,rs,rd
+
+/* Condition Register Bit Fields */
+
+#define	cr0	0
+#define	cr1	1
+#define	cr2	2
+#define	cr3	3
+#define	cr4	4
+#define	cr5	5
+#define	cr6	6
+#define	cr7	7
+
+
+/* General Purpose Registers (GPRs) */
+
+#define	r0	0
+#define	r1	1
+#define	r2	2
+#define	r3	3
+#define	r4	4
+#define	r5	5
+#define	r6	6
+#define	r7	7
+#define	r8	8
+#define	r9	9
+#define	r10	10
+#define	r11	11
+#define	r12	12
+#define	r13	13
+#define	r14	14
+#define	r15	15
+#define	r16	16
+#define	r17	17
+#define	r18	18
+#define	r19	19
+#define	r20	20
+#define	r21	21
+#define	r22	22
+#define	r23	23
+#define	r24	24
+#define	r25	25
+#define	r26	26
+#define	r27	27
+#define	r28	28
+#define	r29	29
+#define	r30	30
+#define	r31	31
+
+
+/* Floating Point Registers (FPRs) */
+
+#define	fr0	0
+#define	fr1	1
+#define	fr2	2
+#define	fr3	3
+#define	fr4	4
+#define	fr5	5
+#define	fr6	6
+#define	fr7	7
+#define	fr8	8
+#define	fr9	9
+#define	fr10	10
+#define	fr11	11
+#define	fr12	12
+#define	fr13	13
+#define	fr14	14
+#define	fr15	15
+#define	fr16	16
+#define	fr17	17
+#define	fr18	18
+#define	fr19	19
+#define	fr20	20
+#define	fr21	21
+#define	fr22	22
+#define	fr23	23
+#define	fr24	24
+#define	fr25	25
+#define	fr26	26
+#define	fr27	27
+#define	fr28	28
+#define	fr29	29
+#define	fr30	30
+#define	fr31	31
+
+#define	vr0	0
+#define	vr1	1
+#define	vr2	2
+#define	vr3	3
+#define	vr4	4
+#define	vr5	5
+#define	vr6	6
+#define	vr7	7
+#define	vr8	8
+#define	vr9	9
+#define	vr10	10
+#define	vr11	11
+#define	vr12	12
+#define	vr13	13
+#define	vr14	14
+#define	vr15	15
+#define	vr16	16
+#define	vr17	17
+#define	vr18	18
+#define	vr19	19
+#define	vr20	20
+#define	vr21	21
+#define	vr22	22
+#define	vr23	23
+#define	vr24	24
+#define	vr25	25
+#define	vr26	26
+#define	vr27	27
+#define	vr28	28
+#define	vr29	29
+#define	vr30	30
+#define	vr31	31
diff -Nru a/include/asm-ppc64/ppc_asm.tmpl b/include/asm-ppc64/ppc_asm.tmpl
--- a/include/asm-ppc64/ppc_asm.tmpl	Fri Sep 20 08:20:44 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,115 +0,0 @@
-/* Condition Register Bit Fields */
-
-#define	cr0	0
-#define	cr1	1
-#define	cr2	2
-#define	cr3	3
-#define	cr4	4
-#define	cr5	5
-#define	cr6	6
-#define	cr7	7
-
-
-/* General Purpose Registers (GPRs) */
-
-#define	r0	0
-#define	r1	1
-#define	r2	2
-#define	r3	3
-#define	r4	4
-#define	r5	5
-#define	r6	6
-#define	r7	7
-#define	r8	8
-#define	r9	9
-#define	r10	10
-#define	r11	11
-#define	r12	12
-#define	r13	13
-#define	r14	14
-#define	r15	15
-#define	r16	16
-#define	r17	17
-#define	r18	18
-#define	r19	19
-#define	r20	20
-#define	r21	21
-#define	r22	22
-#define	r23	23
-#define	r24	24
-#define	r25	25
-#define	r26	26
-#define	r27	27
-#define	r28	28
-#define	r29	29
-#define	r30	30
-#define	r31	31
-
-
-/* Floating Point Registers (FPRs) */
-
-#define	fr0	0
-#define	fr1	1
-#define	fr2	2
-#define	fr3	3
-#define	fr4	4
-#define	fr5	5
-#define	fr6	6
-#define	fr7	7
-#define	fr8	8
-#define	fr9	9
-#define	fr10	10
-#define	fr11	11
-#define	fr12	12
-#define	fr13	13
-#define	fr14	14
-#define	fr15	15
-#define	fr16	16
-#define	fr17	17
-#define	fr18	18
-#define	fr19	19
-#define	fr20	20
-#define	fr21	21
-#define	fr22	22
-#define	fr23	23
-#define	fr24	24
-#define	fr25	25
-#define	fr26	26
-#define	fr27	27
-#define	fr28	28
-#define	fr29	29
-#define	fr30	30
-#define	fr31	31
-
-#define	vr0	0
-#define	vr1	1
-#define	vr2	2
-#define	vr3	3
-#define	vr4	4
-#define	vr5	5
-#define	vr6	6
-#define	vr7	7
-#define	vr8	8
-#define	vr9	9
-#define	vr10	10
-#define	vr11	11
-#define	vr12	12
-#define	vr13	13
-#define	vr14	14
-#define	vr15	15
-#define	vr16	16
-#define	vr17	17
-#define	vr18	18
-#define	vr19	19
-#define	vr20	20
-#define	vr21	21
-#define	vr22	22
-#define	vr23	23
-#define	vr24	24
-#define	vr25	25
-#define	vr26	26
-#define	vr27	27
-#define	vr28	28
-#define	vr29	29
-#define	vr30	30
-#define	vr31	31
diff -Nru a/include/asm-ppc64/semaphore.h b/include/asm-ppc64/semaphore.h
--- a/include/asm-ppc64/semaphore.h	Fri Sep 20 08:20:46 2002
+++ b/include/asm-ppc64/semaphore.h	Fri Sep 20 08:20:46 2002
@@ -3,7 +3,7 @@
 
 /*
  * Remove spinlock-based RW semaphores; RW semaphore definitions are
- * now in rwsem.h and we use the the generic lib/rwsem.c implementation.
+ * now in rwsem.h and we use the generic lib/rwsem.c implementation.
  * Rework semaphores to use atomic_dec_if_positive.
  * -- Paul Mackerras (paulus@samba.org)
  */
diff -Nru a/include/asm-ppc64/tlb.h b/include/asm-ppc64/tlb.h
--- a/include/asm-ppc64/tlb.h	Fri Sep 20 08:20:44 2002
+++ b/include/asm-ppc64/tlb.h	Fri Sep 20 08:20:44 2002
@@ -20,6 +20,9 @@
 struct free_pte_ctx;
 static inline void tlb_flush(struct free_pte_ctx *tlb);
 
+/* Avoid pulling in another include just for this */
+#define check_pgt_cache()	do { } while (0)
+
 /* Get the generic bits... */
 #include <asm-generic/tlb.h>
 
@@ -51,16 +54,17 @@
 	if (pte_val(*ptep) & _PAGE_HASHPTE) {
 		pte = __pte(pte_update(ptep, _PAGE_HPTEFLAGS, 0));
 		if (pte_val(pte) & _PAGE_HASHPTE) {
-			int local = 0;
-
-			if (tlb->mm->cpu_vm_mask == (1 << cpu))
-				local = 1;
 
 			batch->pte[i] = pte;
 			batch->addr[i] = address;
 			i++;
 
 			if (i == PPC64_TLB_BATCH_NR) {
+				int local = 0;
+
+				if (tlb->mm->cpu_vm_mask == (1 << cpu))
+					local = 1;
+
 				flush_hash_range(tlb->mm->context, i, local);
 				i = 0;
 			}
diff -Nru a/include/asm-ppc64/unistd.h b/include/asm-ppc64/unistd.h
--- a/include/asm-ppc64/unistd.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-ppc64/unistd.h	Fri Sep 20 08:20:41 2002
@@ -241,6 +241,9 @@
 #define __NR_io_getevents	229
 #define __NR_io_submit		230
 #define __NR_io_cancel		231
+#define __NR_alloc_hugepages	232
+#define __NR_free_hugepages	233
+#define __NR_exit_group		234
 
 #define __NR(n)	#n
 
diff -Nru a/include/asm-sparc/io.h b/include/asm-sparc/io.h
--- a/include/asm-sparc/io.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-sparc/io.h	Fri Sep 20 08:20:41 2002
@@ -25,38 +25,17 @@
 
 /*
  * Memory mapped I/O to PCI
+ *
+ * Observe that ioremap returns void* cookie, but accessors, such
+ * as readb, take unsigned long as address, by API. This mismatch
+ * happened historically. The ioremap is much older than accessors,
+ * so at one time ioremap's cookie was used as address (*a = val).
+ * When accessors came about, they were designed to be compatible across
+ * buses, so that drivers can select proper ones like sunhme.c did.
+ * To make that easier, they use same aruments (ulong) for sbus, pci, isa.
+ * The offshot is, we must cast readb et. al. arguments with a #define.
  */
-static __inline__ u8 readb(unsigned long addr)
-{
-	return *(volatile u8 *)addr;
-}
 
-static __inline__ u16 readw(unsigned long addr)
-{
-	return flip_word(*(volatile u16 *)addr);
-}
-
-static __inline__ u32 readl(unsigned long addr)
-{
-	return flip_dword(*(volatile u32 *)addr);
-}
-
-static __inline__ void writeb(u8 b, unsigned long addr)
-{
-	*(volatile u8 *)addr = b;
-}
-
-static __inline__ void writew(u16 b, unsigned long addr)
-{
-	*(volatile u16 *)addr = flip_word(b);
-}
-
-static __inline__ void writel(u32 b, unsigned long addr)
-{
-	*(volatile u32 *)addr = flip_dword(b);
-}
-
-/* Now the 'raw' versions. */
 static __inline__ u8 __raw_readb(unsigned long addr)
 {
 	return *(volatile u8 *)addr;
@@ -87,6 +66,14 @@
 	*(volatile u32 *)addr = b;
 }
 
+#define readb(addr)	(*(volatile u8 *)(addr))
+#define readw(addr)	flip_word(*(volatile u16 *)(addr))
+#define readl(addr)	flip_dword(*(volatile u32 *)(addr))
+
+#define writeb(b, a)	(*(volatile u8 *)(a) = b)
+#define writew(b, a)	(*(volatile u16 *)(a) = flip_word(b))
+#define writel(b, a)	(*(volatile u32 *)(a) = flip_dword(b))
+
 /*
  * I/O space operations
  *
@@ -163,7 +150,6 @@
 
 /*
  * The only reason for #define's is to hide casts to unsigned long.
- * XXX Rewrite drivers without structures for registers.
  */
 #define sbus_readb(a)		_sbus_readb((unsigned long)(a))
 #define sbus_readw(a)		_sbus_readw((unsigned long)(a))
@@ -193,13 +179,11 @@
 #define ioremap_nocache(X,Y)	ioremap((X),(Y))
 extern void iounmap(void *addr);
 
-/* P3: talk davem into dropping "name" argument in favor of res->name */
 /*
  * Bus number may be in res->flags... somewhere.
  */
 extern unsigned long sbus_ioremap(struct resource *res, unsigned long offset,
     unsigned long size, char *name);
-/* XXX Partial deallocations? I think not! */
 extern void sbus_iounmap(unsigned long vaddr, unsigned long size);
 
 
@@ -215,7 +199,7 @@
 #define RTC_ALWAYS_BCD  0
 
 /* Nothing to do */
-/* P3: Only IDE DMA may need these. */
+/* P3: Only IDE DMA may need these. XXX Verify that it still does... */
 
 #define dma_cache_inv(_start,_size)		do { } while (0)
 #define dma_cache_wback(_start,_size)		do { } while (0)
diff -Nru a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h
--- a/include/asm-sparc/unistd.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-sparc/unistd.h	Fri Sep 20 08:20:41 2002
@@ -249,8 +249,8 @@
 #define __NR_time               231 /* Linux Specific                              */
 /* #define __NR_oldstat         232    Linux Specific                              */
 #define __NR_stime              233 /* Linux Specific                              */
-/* #define __NR_oldfstat        234    Linux Specific                              */
-/* #define __NR_phys            235    Linux Specific                              */
+#define __NR_alloc_hugepages    234 /* Linux Specific                              */
+#define __NR_free_hugepages     235 /* Linux Specific                              */
 #define __NR__llseek            236 /* Linux Specific                              */
 #define __NR_mlock              237
 #define __NR_munlock            238
diff -Nru a/include/asm-sparc64/page.h b/include/asm-sparc64/page.h
--- a/include/asm-sparc64/page.h	Fri Sep 20 08:20:45 2002
+++ b/include/asm-sparc64/page.h	Fri Sep 20 08:20:45 2002
@@ -3,6 +3,8 @@
 #ifndef _SPARC64_PAGE_H
 #define _SPARC64_PAGE_H
 
+#include <linux/config.h>
+
 #define PAGE_SHIFT   13
 #ifndef __ASSEMBLY__
 /* I have my suspicions... -DaveM */
@@ -98,6 +100,14 @@
 #define __iopgprot(x)	(x)
 
 #endif /* (STRICT_MM_TYPECHECKS) */
+
+#define HPAGE_SHIFT		22
+
+#ifdef CONFIG_HUGETLB_PAGE
+#define HPAGE_SIZE		((1UL) << HPAGE_SHIFT)
+#define HPAGE_MASK		(~(HPAGE_SIZE - 1UL))
+#define HUGETLB_PAGE_ORDER	(HPAGE_SHIFT - PAGE_SHIFT)
+#endif
 
 #define TASK_UNMAPPED_BASE	(test_thread_flag(TIF_32BIT) ? \
 				 (0x0000000070000000UL) : (PAGE_OFFSET))
diff -Nru a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h
--- a/include/asm-sparc64/system.h	Fri Sep 20 08:20:41 2002
+++ b/include/asm-sparc64/system.h	Fri Sep 20 08:20:41 2002
@@ -152,24 +152,6 @@
 #define task_running(rq, p) \
 	((rq)->curr == (p) || spin_is_locked(&(p)->switch_lock))
 
-#ifndef CONFIG_DEBUG_SPINLOCK
-#define CHECK_LOCKS(PREV)	do { } while(0)
-#else /* CONFIG_DEBUG_SPINLOCK */
-#define CHECK_LOCKS(PREV)						\
-if ((PREV)->thread.smp_lock_count) {					\
-	unsigned long rpc;						\
-	__asm__ __volatile__("mov %%i7, %0" : "=r" (rpc));		\
-	printk(KERN_CRIT "(%s)[%d]: Sleeping with %d locks held!\n",	\
-	       (PREV)->comm, (PREV)->pid,				\
-	       (PREV)->thread.smp_lock_count);				\
-	printk(KERN_CRIT "(%s)[%d]: Last lock at %08x\n",		\
-	       (PREV)->comm, (PREV)->pid,				\
-	       (PREV)->thread.smp_lock_pc);				\
-	printk(KERN_CRIT "(%s)[%d]: Sched caller %016lx\n",		\
-	       (PREV)->comm, (PREV)->pid, rpc);				\
-}
-#endif /* !(CONFIG_DEBUG_SPINLOCK) */
-
 	/* See what happens when you design the chip correctly?
 	 *
 	 * We tell gcc we clobber all non-fixed-usage registers except
@@ -180,8 +162,7 @@
 	 * and 2 stores in this critical code path.  -DaveM
 	 */
 #define switch_to(prev, next, last)					\
-do {	CHECK_LOCKS(prev);						\
-	if (test_thread_flag(TIF_PERFCTR)) {				\
+do {	if (test_thread_flag(TIF_PERFCTR)) {				\
 		unsigned long __tmp;					\
 		read_pcr(__tmp);					\
 		current_thread_info()->pcr_reg = __tmp;			\
diff -Nru a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h
--- a/include/asm-sparc64/unistd.h	Fri Sep 20 08:20:43 2002
+++ b/include/asm-sparc64/unistd.h	Fri Sep 20 08:20:43 2002
@@ -251,8 +251,8 @@
 #endif
 /* #define __NR_oldstat         232    Linux Specific                              */
 #define __NR_stime              233 /* Linux Specific                              */
-/* #define __NR_oldfstat        234    Linux Specific                              */
-/* #define __NR_phys            235    Linux Specific                              */
+#define __NR_alloc_hugepages    234 /* Linux Specific                              */
+#define __NR_free_hugepages     235 /* Linux Specific                              */
 #define __NR__llseek            236 /* Linux Specific                              */
 #define __NR_mlock              237
 #define __NR_munlock            238
diff -Nru a/include/linux/acpi.h b/include/linux/acpi.h
--- a/include/linux/acpi.h	Fri Sep 20 08:20:41 2002
+++ b/include/linux/acpi.h	Fri Sep 20 08:20:41 2002
@@ -106,6 +106,15 @@
 	u64			entry[1];
 } __attribute__ ((packed));
 
+/* Fixed ACPI Description Table (FADT) */
+
+struct acpi_table_fadt {
+	struct acpi_table_header header;
+	u32 facs_addr;
+	u32 dsdt_addr;
+	/* ... */
+} __attribute__ ((packed));
+
 /* Multiple APIC Description Table (MADT) */
 
 struct acpi_table_madt {
@@ -314,7 +323,7 @@
 	ACPI_DSDT,
 	ACPI_ECDT,
 	ACPI_ETDT,
-	ACPI_FACP,
+	ACPI_FADT,
 	ACPI_FACS,
 	ACPI_OEMX,
 	ACPI_PSDT,
@@ -340,6 +349,7 @@
 
 int acpi_table_init (char *cmdline);
 int acpi_table_parse (enum acpi_table_id id, acpi_table_handler handler);
+int acpi_get_table_header_early (enum acpi_table_id id, struct acpi_table_header **header);
 int acpi_table_parse_madt (enum acpi_madt_entry_id id, acpi_madt_entry_handler handler);
 int acpi_table_parse_srat (enum acpi_srat_entry_id id, acpi_madt_entry_handler handler);
 void acpi_table_print (struct acpi_table_header *header, unsigned long phys_addr);
@@ -391,9 +401,8 @@
 
 #ifdef CONFIG_ACPI
 
-int acpi_init(void);
+int acpi_blacklisted(void);
 
 #endif /*CONFIG_ACPI*/
-
 
 #endif /*_LINUX_ACPI_H*/
diff -Nru a/include/linux/bio.h b/include/linux/bio.h
--- a/include/linux/bio.h	Fri Sep 20 08:20:47 2002
+++ b/include/linux/bio.h	Fri Sep 20 08:20:47 2002
@@ -37,8 +37,9 @@
 #define BIO_BUG_ON
 #endif
 
-#define BIO_MAX_SECTORS	128
-#define BIO_MAX_SIZE	(BIO_MAX_SECTORS << 9)
+#define BIO_MAX_PAGES		(256)
+#define BIO_MAX_SIZE		(BIO_MAX_PAGES << PAGE_CACHE_SHIFT)
+#define BIO_MAX_SECTORS		(BIO_MAX_SIZE >> 9)
 
 /*
  * was unsigned short, but we might as well be ready for > 64kB I/O pages
@@ -50,7 +51,7 @@
 };
 
 struct bio;
-typedef void (bio_end_io_t) (struct bio *);
+typedef int (bio_end_io_t) (struct bio *, unsigned int, int);
 typedef void (bio_destructor_t) (struct bio *);
 
 /*
@@ -101,6 +102,7 @@
 #define BIO_EOF		2	/* out-out-bounds error */
 #define BIO_SEG_VALID	3	/* nr_hw_seg valid */
 #define BIO_CLONED	4	/* doesn't own data */
+#define bio_flagged(bio, flag)	((bio)->bi_flags & (1 << (flag)))
 
 /*
  * bio bi_rw flags
@@ -123,7 +125,7 @@
 #define bio_offset(bio)		bio_iovec((bio))->bv_offset
 #define bio_sectors(bio)	((bio)->bi_size >> 9)
 #define bio_data(bio)		(page_address(bio_page((bio))) + bio_offset((bio)))
-#define bio_barrier(bio)	((bio)->bi_rw & (1 << BIO_BARRIER))
+#define bio_barrier(bio)	((bio)->bi_rw & (1 << BIO_RW_BARRIER))
 
 /*
  * will die
@@ -159,7 +161,7 @@
 #define BIO_SEG_BOUNDARY(q, b1, b2) \
 	BIOVEC_SEG_BOUNDARY((q), __BVEC_END((b1)), __BVEC_START((b2)))
 
-#define bio_io_error(bio) bio_endio((bio), 0)
+#define bio_io_error(bio, bytes) bio_endio((bio), (bytes), -EIO)
 
 /*
  * drivers should not use the __ version unless they _really_ want to
@@ -192,7 +194,7 @@
 extern struct bio *bio_alloc(int, int);
 extern void bio_put(struct bio *);
 
-extern void bio_endio(struct bio *, int);
+extern int bio_endio(struct bio *, unsigned int, int);
 struct request_queue;
 extern inline int bio_phys_segments(struct request_queue *, struct bio *);
 extern inline int bio_hw_segments(struct request_queue *, struct bio *);
@@ -202,6 +204,8 @@
 extern struct bio *bio_copy(struct bio *, int, int);
 
 extern inline void bio_init(struct bio *);
+
+extern int bio_add_page(struct bio *, struct page *, unsigned int,unsigned int);
 
 #ifdef CONFIG_HIGHMEM
 /*
diff -Nru a/include/linux/blkdev.h b/include/linux/blkdev.h
--- a/include/linux/blkdev.h	Fri Sep 20 08:20:43 2002
+++ b/include/linux/blkdev.h	Fri Sep 20 08:20:43 2002
@@ -120,6 +120,9 @@
 typedef int (prep_rq_fn) (request_queue_t *, struct request *);
 typedef void (unplug_fn) (void *q);
 
+struct bio_vec;
+typedef int (merge_bvec_fn) (request_queue_t *, struct bio *, struct bio_vec *);
+
 enum blk_queue_state {
 	Queue_down,
 	Queue_up,
@@ -163,6 +166,7 @@
 	make_request_fn		*make_request_fn;
 	prep_rq_fn		*prep_rq_fn;
 	unplug_fn		*unplug_fn;
+	merge_bvec_fn		*merge_bvec_fn;
 
 	struct backing_dev_info	backing_dev_info;
 
diff -Nru a/include/linux/buffer_head.h b/include/linux/buffer_head.h
--- a/include/linux/buffer_head.h	Fri Sep 20 08:20:41 2002
+++ b/include/linux/buffer_head.h	Fri Sep 20 08:20:41 2002
@@ -167,6 +167,8 @@
 struct buffer_head *alloc_buffer_head(void);
 void free_buffer_head(struct buffer_head * bh);
 void FASTCALL(unlock_buffer(struct buffer_head *bh));
+void ll_rw_block(int, int, struct buffer_head * bh[]);
+int submit_bh(int, struct buffer_head *);
 extern int buffer_heads_over_limit;
 
 /*
diff -Nru a/include/linux/cyclades.h b/include/linux/cyclades.h
--- a/include/linux/cyclades.h	Fri Sep 20 08:20:48 2002
+++ b/include/linux/cyclades.h	Fri Sep 20 08:20:48 2002
@@ -503,6 +503,7 @@
 #endif
 
 /* Per card data structure */
+struct resource;
 struct cyclades_card {
     unsigned long base_phys;
     unsigned long ctl_phys;
@@ -514,10 +515,13 @@
     int nports;		/* Number of ports in the card */
     int bus_index;	/* address shift - 0 for ISA, 1 for PCI */
     int	intr_enabled;	/* FW Interrupt flag - 0 disabled, 1 enabled */
+    struct resource *resource;
+    unsigned long res_start;
+	unsigned long res_len;
 #ifdef __KERNEL__
     spinlock_t card_lock;
 #else
-    uclong filler;
+    unsigned long filler;
 #endif
 };
 
diff -Nru a/include/linux/device.h b/include/linux/device.h
--- a/include/linux/device.h	Fri Sep 20 08:20:47 2002
+++ b/include/linux/device.h	Fri Sep 20 08:20:47 2002
@@ -65,7 +65,8 @@
 	struct driver_dir_entry	device_dir;
 	struct driver_dir_entry	driver_dir;
 
-	int	(*match)	(struct device * dev, struct device_driver * drv);
+	int		(*match)(struct device * dev, struct device_driver * drv);
+	struct device * (*add)	(struct device * parent, char * bus_id);
 };
 
 
@@ -281,6 +282,8 @@
 	void		*driver_data;	/* data private to the driver */
 
 	u32		class_num;	/* class-enumerated value */
+	void		* class_data;	/* class-specific data */
+
 	void		*platform_data;	/* Platform specific data (e.g. ACPI,
 					   BIOS data relevant to device) */
 
@@ -377,6 +380,9 @@
 /* drivers/base/sys.c */
 extern int register_sys_device(struct device * dev);
 extern void unregister_sys_device(struct device * dev);
+
+/* drivers/base/platform.c */
+extern struct bus_type platform_bus;
 
 /* drivers/base/power.c */
 extern int device_suspend(u32 state, u32 level);
diff -Nru a/include/linux/fs.h b/include/linux/fs.h
--- a/include/linux/fs.h	Fri Sep 20 08:20:44 2002
+++ b/include/linux/fs.h	Fri Sep 20 08:20:44 2002
@@ -279,6 +279,7 @@
  */
 struct page;
 struct address_space;
+struct writeback_control;
 
 struct address_space_operations {
 	int (*writepage)(struct page *);
@@ -286,10 +287,10 @@
 	int (*sync_page)(struct page *);
 
 	/* Write back some dirty pages from this mapping. */
-	int (*writepages)(struct address_space *, int *nr_to_write);
+	int (*writepages)(struct address_space *, struct writeback_control *);
 
 	/* Perform a writeback as a memory-freeing operation. */
-	int (*vm_writeback)(struct page *, int *nr_to_write);
+	int (*vm_writeback)(struct page *, struct writeback_control *);
 
 	/* Set a page dirty */
 	int (*set_page_dirty)(struct page *page);
@@ -1231,8 +1232,6 @@
 
 extern struct file * get_empty_filp(void);
 extern void file_move(struct file *f, struct list_head *list);
-extern void ll_rw_block(int, int, struct buffer_head * bh[]);
-extern int submit_bh(int, struct buffer_head *);
 struct bio;
 extern int submit_bio(int, struct bio *);
 extern int bdev_read_only(struct block_device *);
@@ -1261,7 +1260,8 @@
 extern loff_t remote_llseek(struct file *file, loff_t offset, int origin);
 extern int generic_file_open(struct inode * inode, struct file * filp);
 
-extern int generic_vm_writeback(struct page *page, int *nr_to_write);
+extern int generic_vm_writeback(struct page *page,
+				struct writeback_control *wbc);
 
 extern struct file_operations generic_ro_fops;
 
diff -Nru a/include/linux/gfp.h b/include/linux/gfp.h
--- a/include/linux/gfp.h	Fri Sep 20 08:20:43 2002
+++ b/include/linux/gfp.h	Fri Sep 20 08:20:43 2002
@@ -39,18 +39,25 @@
  * can allocate highmem pages, the *get*page*() variants return
  * virtual kernel addresses to the allocated page(s).
  */
-extern struct page * FASTCALL(_alloc_pages(unsigned int gfp_mask, unsigned int order));
 extern struct page * FASTCALL(__alloc_pages(unsigned int gfp_mask, unsigned int order, struct zonelist *zonelist));
 extern struct page * alloc_pages_node(int nid, unsigned int gfp_mask, unsigned int order);
 
+/*
+ * We get the zone list from the current node and the gfp_mask.
+ * This zone list contains a maximum of MAXNODES*MAX_NR_ZONES zones.
+ *
+ * For the normal case of non-DISCONTIGMEM systems the NODE_DATA() gets
+ * optimized to &contig_page_data at compile-time.
+ */
 static inline struct page * alloc_pages(unsigned int gfp_mask, unsigned int order)
 {
-	/*
-	 * Gets optimized away by the compiler.
-	 */
-	if (order >= MAX_ORDER)
+	pg_data_t *pgdat = NODE_DATA(numa_node_id());
+	unsigned int idx = (gfp_mask & GFP_ZONEMASK);
+
+	if (unlikely(order >= MAX_ORDER))
 		return NULL;
-	return _alloc_pages(gfp_mask, order);
+
+	return __alloc_pages(gfp_mask, order, pgdat->node_zonelists + idx);
 }
 
 #define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0)
diff -Nru a/include/linux/hdlc.h b/include/linux/hdlc.h
--- a/include/linux/hdlc.h	Fri Sep 20 08:20:48 2002
+++ b/include/linux/hdlc.h	Fri Sep 20 08:20:48 2002
@@ -12,14 +12,16 @@
 #ifndef __HDLC_H
 #define __HDLC_H
 
-#define CLOCK_DEFAULT   0	/* Default (current) setting */
+#define GENERIC_HDLC_VERSION 3	/* For synchronization with sethdlc utility */
+
+#define CLOCK_DEFAULT   0	/* Default setting */
 #define CLOCK_EXT	1	/* External TX and RX clock - DTE */
 #define CLOCK_INT	2	/* Internal TX and RX clock - DCE */
 #define CLOCK_TXINT	3	/* Internal TX and external RX clock */
 #define CLOCK_TXFROMRX	4	/* TX clock derived from external RX clock */
 
 
-#define ENCODING_DEFAULT	0 /* Default (current) setting */
+#define ENCODING_DEFAULT	0 /* Default setting */
 #define ENCODING_NRZ		1
 #define ENCODING_NRZI		2
 #define ENCODING_FM_MARK	3
@@ -27,7 +29,7 @@
 #define ENCODING_MANCHESTER	5
 
 
-#define PARITY_DEFAULT		0 /* Default (current) setting */
+#define PARITY_DEFAULT		0 /* Default setting */
 #define PARITY_NONE		1 /* No parity */
 #define PARITY_CRC16_PR0	2 /* CRC16, initial value 0x0000 */
 #define PARITY_CRC16_PR1	3 /* CRC16, initial value 0xFFFF */
@@ -36,13 +38,11 @@
 #define PARITY_CRC32_PR0_CCITT	6 /* CRC32, initial value 0x00000000 */
 #define PARITY_CRC32_PR1_CCITT	7 /* CRC32, initial value 0xFFFFFFFF */
 
-#define LMI_DEFAULT		0 /* Default (current) setting */
+#define LMI_DEFAULT		0 /* Default setting */
 #define LMI_NONE		1 /* No LMI, all PVCs are static */
 #define LMI_ANSI		2 /* ANSI Annex D */
 #define LMI_CCITT		3 /* ITU-T Annex A */
 
-/* PPP doesn't need any info now - supply length = 0 to ioctl */
-
 
 #ifdef __KERNEL__
 
@@ -178,7 +178,7 @@
 	int (*ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd);
 	int (*open)(struct hdlc_device_struct *hdlc);
 	void (*stop)(struct hdlc_device_struct *hdlc);
-	void (*detach)(struct hdlc_device_struct *hdlc);
+	void (*proto_detach)(struct hdlc_device_struct *hdlc);
 	void (*netif_rx)(struct sk_buff *skb);
 	int proto;		/* IF_PROTO_HDLC/CISCO/FR/etc. */
 
@@ -337,11 +337,11 @@
 
 
 /* May be used by hardware driver to gain control over HDLC device */
-static __inline__ void hdlc_detach(hdlc_device *hdlc)
+static __inline__ void hdlc_proto_detach(hdlc_device *hdlc)
 {
-	if (hdlc->detach)
-		hdlc->detach(hdlc);
-	hdlc->detach = NULL;
+	if (hdlc->proto_detach)
+		hdlc->proto_detach(hdlc);
+	hdlc->proto_detach = NULL;
 }
 
 
diff -Nru a/include/linux/ide.h b/include/linux/ide.h
--- a/include/linux/ide.h	Fri Sep 20 08:20:44 2002
+++ b/include/linux/ide.h	Fri Sep 20 08:20:44 2002
@@ -1753,6 +1753,7 @@
 extern u8 ide_rate_filter(u8 mode, u8 speed); 
 extern int ide_dma_enable(ide_drive_t *drive);
 extern char *ide_xfer_verbose(u8 xfer_rate);
+extern void ide_toggle_bounce(ide_drive_t *drive, int on);
 
 extern spinlock_t ide_lock;
 
diff -Nru a/include/linux/if_bridge.h b/include/linux/if_bridge.h
--- a/include/linux/if_bridge.h	Fri Sep 20 08:20:46 2002
+++ b/include/linux/if_bridge.h	Fri Sep 20 08:20:46 2002
@@ -102,7 +102,8 @@
 struct net_bridge_port;
 
 extern int (*br_ioctl_hook)(unsigned long arg);
-extern void (*br_handle_frame_hook)(struct sk_buff *skb);
+extern int (*br_handle_frame_hook)(struct sk_buff *skb);
+extern int (*br_should_route_hook)(struct sk_buff **pskb);
 
 #endif
 
diff -Nru a/include/linux/list.h b/include/linux/list.h
--- a/include/linux/list.h	Fri Sep 20 08:20:41 2002
+++ b/include/linux/list.h	Fri Sep 20 08:20:41 2002
@@ -195,6 +195,10 @@
 #define list_for_each(pos, head) \
 	for (pos = (head)->next, prefetch(pos->next); pos != (head); \
         	pos = pos->next, prefetch(pos->next))
+
+#define list_for_each_noprefetch(pos, head) \
+	for (pos = (head)->next; pos != (head); pos = pos->next)
+
 /**
  * list_for_each_prev	-	iterate over a list backwards
  * @pos:	the &struct list_head to use as a loop counter.
diff -Nru a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
--- a/include/linux/lockd/lockd.h	Fri Sep 20 08:20:43 2002
+++ b/include/linux/lockd/lockd.h	Fri Sep 20 08:20:43 2002
@@ -42,8 +42,8 @@
 	struct rpc_clnt	*	h_rpcclnt;	/* RPC client to talk to peer */
 	char			h_name[20];	/* remote hostname */
 	u32			h_version;	/* interface version */
+	rpc_authflavor_t	h_authflavor;	/* RPC authentication type */
 	unsigned short		h_proto;	/* transport proto */
-	unsigned short		h_authflavor;	/* RPC authentication type */
 	unsigned short		h_reclaiming : 1,
 				h_server     : 1, /* server side, not client side */
 				h_inuse      : 1,
diff -Nru a/include/linux/mm.h b/include/linux/mm.h
--- a/include/linux/mm.h	Fri Sep 20 08:20:41 2002
+++ b/include/linux/mm.h	Fri Sep 20 08:20:41 2002
@@ -15,7 +15,10 @@
 #include <linux/rbtree.h>
 #include <linux/fs.h>
 
+#ifndef CONFIG_DISCONTIGMEM          /* Don't use mapnrs, do it properly */
 extern unsigned long max_mapnr;
+#endif
+
 extern unsigned long num_physpages;
 extern void * high_memory;
 extern int page_cluster;
@@ -345,8 +348,10 @@
 #define VM_FAULT_MINOR	1
 #define VM_FAULT_MAJOR	2
 
-/* The array of struct pages */
+#ifndef CONFIG_DISCONTIGMEM
+/* The array of struct pages - for discontigmem use pgdat->lmem_map */
 extern struct page *mem_map;
+#endif 
 
 extern void show_free_areas(void);
 
@@ -431,10 +436,7 @@
 extern int remove_exclusive_swap_page(struct page *);
 
 /* 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 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 *);
 
@@ -504,6 +506,8 @@
 extern struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr);
 extern struct vm_area_struct * find_vma_prev(struct mm_struct * mm, unsigned long addr,
 					     struct vm_area_struct **pprev);
+extern int split_vma(struct mm_struct * mm, struct vm_area_struct * vma,
+		     unsigned long addr, int new_below);
 
 /* Look up the first VMA which intersects the interval start_addr..end_addr-1,
    NULL if none.  Assume start_addr < end_addr. */
diff -Nru a/include/linux/mmzone.h b/include/linux/mmzone.h
--- a/include/linux/mmzone.h	Fri Sep 20 08:20:41 2002
+++ b/include/linux/mmzone.h	Fri Sep 20 08:20:41 2002
@@ -10,11 +10,14 @@
 #include <linux/wait.h>
 #include <linux/cache.h>
 #include <asm/atomic.h>
+#ifdef CONFIG_DISCONTIGMEM
+#include <asm/numnodes.h>
+#endif
+#ifndef MAX_NUMNODES
+#define MAX_NUMNODES 1
+#endif
 
-/*
- * Free memory management - zoned buddy allocator.
- */
-
+/* Free memory management - zoned buddy allocator.  */
 #ifndef CONFIG_FORCE_MAX_ZONEORDER
 #define MAX_ORDER 11
 #else
@@ -112,7 +115,6 @@
 	struct page		*zone_mem_map;
 	/* zone_start_pfn == zone_start_paddr >> PAGE_SHIFT */
 	unsigned long		zone_start_pfn;
-	unsigned long		zone_start_mapnr;
 
 	/*
 	 * rarely used fields:
@@ -138,7 +140,7 @@
  * footprint of this construct is very small.
  */
 struct zonelist {
-	struct zone *zones[MAX_NR_ZONES+1]; // NULL delimited
+	struct zone *zones[MAX_NUMNODES * MAX_NR_ZONES + 1]; // NULL delimited
 };
 
 #define GFP_ZONEMASK	0x0f
@@ -163,7 +165,6 @@
 	unsigned long *valid_addr_bitmap;
 	struct bootmem_data *bdata;
 	unsigned long node_start_pfn;
-	unsigned long node_start_mapnr;
 	unsigned long node_size;
 	int node_id;
 	struct pglist_data *pgdat_next;
@@ -187,10 +188,12 @@
  * prototypes for the discontig memory code.
  */
 struct page;
-void free_area_init_core(int nid, pg_data_t *pgdat, struct page **gmap,
-  unsigned long *zones_size, unsigned long paddr, unsigned long *zholes_size,
-  struct page *pmap);
+extern void calculate_totalpages (pg_data_t *pgdat, unsigned long *zones_size,
+		unsigned long *zholes_size);
+extern void free_area_init_core(pg_data_t *pgdat, unsigned long *zones_size,
+		unsigned long *zholes_size);
 void get_zone_counts(unsigned long *active, unsigned long *inactive);
+extern void build_all_zonelists(void);
 
 extern pg_data_t contig_page_data;
 
diff -Nru a/include/linux/mpage.h b/include/linux/mpage.h
--- a/include/linux/mpage.h	Fri Sep 20 08:20:44 2002
+++ b/include/linux/mpage.h	Fri Sep 20 08:20:44 2002
@@ -10,14 +10,16 @@
  * nested includes.  Get it right in the .c file).
  */
 
+struct writeback_control;
+
 int mpage_readpages(struct address_space *mapping, struct list_head *pages,
 				unsigned nr_pages, get_block_t get_block);
 int mpage_readpage(struct page *page, get_block_t get_block);
 int mpage_writepages(struct address_space *mapping,
-		int *nr_to_write, get_block_t get_block);
+		struct writeback_control *wbc, get_block_t get_block);
 
 static inline int
-generic_writepages(struct address_space *mapping, int *nr_to_write)
+generic_writepages(struct address_space *mapping, struct writeback_control *wbc)
 {
-	return mpage_writepages(mapping, nr_to_write, NULL);
+	return mpage_writepages(mapping, wbc, NULL);
 }
diff -Nru a/include/linux/nbd.h b/include/linux/nbd.h
--- a/include/linux/nbd.h	Fri Sep 20 08:20:47 2002
+++ b/include/linux/nbd.h	Fri Sep 20 08:20:47 2002
@@ -59,7 +59,7 @@
 		blk_finished_io(nsect);
 		req->bio = bio->bi_next;
 		bio->bi_next = NULL;
-		bio_endio(bio, uptodate);
+		bio_endio(bio, nsect << 9, uptodate ? 0 : -EIO);
 	}
 	blk_put_request(req);
 	spin_unlock_irqrestore(q->queue_lock, flags);
diff -Nru a/include/linux/netdevice.h b/include/linux/netdevice.h
--- a/include/linux/netdevice.h	Fri Sep 20 08:20:48 2002
+++ b/include/linux/netdevice.h	Fri Sep 20 08:20:48 2002
@@ -691,6 +691,8 @@
 	NETIF_MSG_TX_DONE	= 0x0400,
 	NETIF_MSG_RX_STATUS	= 0x0800,
 	NETIF_MSG_PKTDATA	= 0x1000,
+	NETIF_MSG_HW		= 0x2000,
+	NETIF_MSG_WOL		= 0x4000,
 };
 
 #define netif_msg_drv(p)	((p)->msg_enable & NETIF_MSG_DRV)
@@ -706,6 +708,8 @@
 #define netif_msg_tx_done(p)	((p)->msg_enable & NETIF_MSG_TX_DONE)
 #define netif_msg_rx_status(p)	((p)->msg_enable & NETIF_MSG_RX_STATUS)
 #define netif_msg_pktdata(p)	((p)->msg_enable & NETIF_MSG_PKTDATA)
+#define netif_msg_hw(p)		((p)->msg_enable & NETIF_MSG_HW)
+#define netif_msg_wol(p)	((p)->msg_enable & NETIF_MSG_WOL)
 
 /* Schedule rx intr now? */
 
diff -Nru a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h
--- a/include/linux/netfilter_bridge.h	Fri Sep 20 08:20:46 2002
+++ b/include/linux/netfilter_bridge.h	Fri Sep 20 08:20:46 2002
@@ -18,7 +18,18 @@
 #define NF_BR_LOCAL_OUT		3
 /* Packets about to hit the wire. */
 #define NF_BR_POST_ROUTING	4
-#define NF_BR_NUMHOOKS		5
+/* Not really a hook, but used for the ebtables broute table */
+#define NF_BR_BROUTING		5
+#define NF_BR_NUMHOOKS		6
 
+enum nf_br_hook_priorities {
+	NF_BR_PRI_FIRST = INT_MIN,
+	NF_BR_PRI_FILTER_BRIDGED = -200,
+	NF_BR_PRI_FILTER_OTHER = 200,
+	NF_BR_PRI_NAT_DST_BRIDGED = -300,
+	NF_BR_PRI_NAT_DST_OTHER = 100,
+	NF_BR_PRI_NAT_SRC = 300,
+	NF_BR_PRI_LAST = INT_MAX,
+};
 
 #endif
diff -Nru a/include/linux/page-flags.h b/include/linux/page-flags.h
--- a/include/linux/page-flags.h	Fri Sep 20 08:20:47 2002
+++ b/include/linux/page-flags.h	Fri Sep 20 08:20:47 2002
@@ -79,6 +79,7 @@
 	unsigned long nr_page_table_pages;
 	unsigned long nr_reverse_maps;
 	unsigned long nr_mapped;
+	unsigned long nr_slab;
 } ____cacheline_aligned_in_smp page_states[NR_CPUS];
 
 extern void get_page_state(struct page_state *ret);
diff -Nru a/include/linux/percpu.h b/include/linux/percpu.h
--- a/include/linux/percpu.h	Fri Sep 20 08:20:47 2002
+++ b/include/linux/percpu.h	Fri Sep 20 08:20:47 2002
@@ -3,7 +3,8 @@
 #include <linux/spinlock.h> /* For preempt_disable() */
 #include <asm/percpu.h>
 
-#define get_cpu_var(var) ({ preempt_disable(); __get_cpu_var(var); })
+/* Must be an lvalue. */
+#define get_cpu_var(var) (*({ preempt_disable(); &__get_cpu_var(var); }))
 #define put_cpu_var(var) preempt_enable()
 
 #endif /* __LINUX_PERCPU_H */
diff -Nru a/include/linux/pid.h b/include/linux/pid.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/pid.h	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,63 @@
+#ifndef _LINUX_PID_H
+#define _LINUX_PID_H
+
+enum pid_type
+{
+	PIDTYPE_PID,
+	PIDTYPE_PGID,
+	PIDTYPE_SID,
+	PIDTYPE_MAX
+};
+
+struct pid
+{
+	int nr;
+	atomic_t count;
+	struct task_struct *task;
+	struct list_head task_list;
+	struct list_head hash_chain;
+};
+
+struct pid_link
+{
+	struct list_head pid_chain;
+	struct pid *pidptr;
+	struct pid pid;
+};
+
+#define pid_task(elem, type) \
+	list_entry(elem, struct task_struct, pids[type].pid_chain)
+
+/*
+ * attach_pid() must be called with the tasklist_lock write-held.
+ *
+ * It might unlock the tasklist_lock for allocation, so this
+ * function must be called after installing all other links of
+ * a new task.
+ */
+extern int FASTCALL(attach_pid(struct task_struct *, enum pid_type, int));
+
+/*
+ * detach_pid() must be called with the tasklist_lock write-held.
+ */
+extern void FASTCALL(detach_pid(struct task_struct *task, enum pid_type));
+
+/*
+ * look up a PID in the hash table. Must be called with the tasklist_lock
+ * held.
+ */
+extern struct pid *FASTCALL(find_pid(enum pid_type, int));
+
+extern int alloc_pidmap(void);
+extern void FASTCALL(free_pidmap(int));
+
+#define for_each_task_pid(who, type, task, elem, pid)		\
+	if ((pid = find_pid(type, who)))			\
+	        for (elem = pid->task_list.next,			\
+			prefetch(elem->next),				\
+			task = pid_task(elem, type);			\
+			elem != &pid->task_list;			\
+			elem = elem->next, prefetch(elem->next), 	\
+			task = pid_task(elem, type))
+
+#endif /* _LINUX_PID_H */
diff -Nru a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h	Fri Sep 20 08:20:41 2002
+++ b/include/linux/sched.h	Fri Sep 20 08:20:41 2002
@@ -28,6 +28,7 @@
 #include <linux/fs_struct.h>
 #include <linux/compiler.h>
 #include <linux/completion.h>
+#include <linux/pid.h>
 
 struct exec_domain;
 
@@ -266,6 +267,8 @@
 	atomic_inc(&__user->__count);			\
 	__user; })
 
+extern struct user_struct *find_user(uid_t);
+
 extern struct user_struct root_user;
 #define INIT_USER (&root_user)
 
@@ -326,9 +329,8 @@
 	struct task_struct *group_leader;
 	struct list_head thread_group;
 
-	/* PID hash table linkage. */
-	struct task_struct *pidhash_next;
-	struct task_struct **pidhash_pprev;
+	/* PID/PID hash table linkage. */
+	struct pid_link pids[PIDTYPE_MAX];
 
 	wait_queue_head_t wait_chldexit;	/* for wait4() */
 	struct completion *vfork_done;		/* for vfork() */
@@ -474,38 +476,7 @@
 
 extern struct   mm_struct init_mm;
 
-/* PID hashing. (shouldnt this be dynamic?) */
-#define PIDHASH_SZ 8192
-extern struct task_struct *pidhash[PIDHASH_SZ];
-
-#define pid_hashfn(x)	((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
-
-static inline void hash_pid(struct task_struct *p)
-{
-	struct task_struct **htable = &pidhash[pid_hashfn(p->pid)];
-
-	if((p->pidhash_next = *htable) != NULL)
-		(*htable)->pidhash_pprev = &p->pidhash_next;
-	*htable = p;
-	p->pidhash_pprev = htable;
-}
-
-static inline void unhash_pid(struct task_struct *p)
-{
-	if(p->pidhash_next)
-		p->pidhash_next->pidhash_pprev = p->pidhash_pprev;
-	*p->pidhash_pprev = p->pidhash_next;
-}
-
-static inline struct task_struct *find_task_by_pid(int pid)
-{
-	struct task_struct *p, **htable = &pidhash[pid_hashfn(pid)];
-
-	for(p = *htable; p && p->pid != pid; p = p->pidhash_next)
-		;
-
-	return p;
-}
+extern struct task_struct *find_task_by_pid(int pid);
 
 /* per-UID process charging. */
 extern struct user_struct * alloc_uid(uid_t);
diff -Nru a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h
--- a/include/linux/sunrpc/auth.h	Fri Sep 20 08:20:46 2002
+++ b/include/linux/sunrpc/auth.h	Fri Sep 20 08:20:46 2002
@@ -1,7 +1,7 @@
 /*
- * linux/include/linux/auth.h
+ * linux/include/linux/sunrpc/auth.h
  *
- * Declarations for the RPC authentication machinery.
+ * Declarations for the RPC client authentication machinery.
  *
  * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
  */
@@ -67,7 +67,7 @@
  * Client authentication ops
  */
 struct rpc_authops {
-	unsigned int		au_flavor;	/* flavor (RPC_AUTH_*) */
+	rpc_authflavor_t	au_flavor;	/* flavor (RPC_AUTH_*) */
 #ifdef RPC_DEBUG
 	char *			au_name;
 #endif
@@ -94,7 +94,7 @@
 
 int			rpcauth_register(struct rpc_authops *);
 int			rpcauth_unregister(struct rpc_authops *);
-struct rpc_auth *	rpcauth_create(unsigned int, struct rpc_clnt *);
+struct rpc_auth *	rpcauth_create(rpc_authflavor_t, struct rpc_clnt *);
 void			rpcauth_destroy(struct rpc_auth *);
 struct rpc_cred *	rpcauth_lookupcred(struct rpc_auth *, int);
 struct rpc_cred *	rpcauth_bindcred(struct rpc_task *);
diff -Nru a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
--- a/include/linux/sunrpc/clnt.h	Fri Sep 20 08:20:47 2002
+++ b/include/linux/sunrpc/clnt.h	Fri Sep 20 08:20:47 2002
@@ -111,7 +111,7 @@
 
 struct rpc_clnt *rpc_create_client(struct rpc_xprt *xprt, char *servname,
 				struct rpc_program *info,
-				u32 version, int authflavor);
+				u32 version, rpc_authflavor_t authflavor);
 int		rpc_shutdown_client(struct rpc_clnt *);
 int		rpc_destroy_client(struct rpc_clnt *);
 void		rpc_release_client(struct rpc_clnt *);
diff -Nru a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h
--- a/include/linux/sunrpc/msg_prot.h	Fri Sep 20 08:20:47 2002
+++ b/include/linux/sunrpc/msg_prot.h	Fri Sep 20 08:20:47 2002
@@ -11,12 +11,16 @@
 
 #define RPC_VERSION 2
 
-enum rpc_auth_flavor {
+/* spec defines authentication flavor as an unsigned 32 bit integer */
+typedef u32	rpc_authflavor_t;
+
+enum rpc_auth_flavors {
 	RPC_AUTH_NULL  = 0,
 	RPC_AUTH_UNIX  = 1,
 	RPC_AUTH_SHORT = 2,
 	RPC_AUTH_DES   = 3,
 	RPC_AUTH_KRB   = 4,
+	RPC_AUTH_MAXFLAVOR = 8,
 };
 
 enum rpc_msg_type {
diff -Nru a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
--- a/include/linux/sunrpc/svc.h	Fri Sep 20 08:20:46 2002
+++ b/include/linux/sunrpc/svc.h	Fri Sep 20 08:20:46 2002
@@ -82,8 +82,8 @@
 	struct iovec		iov[RPCSVC_MAXIOV];
 	int			nriov;
 };
-#define svc_getlong(argp, val)	{ (val) = *(argp)->buf++; (argp)->len--; }
-#define svc_putlong(resp, val)	{ *(resp)->buf++ = (val); (resp)->len++; }
+#define svc_getu32(argp, val)	{ (val) = *(argp)->buf++; (argp)->len--; }
+#define svc_putu32(resp, val)	{ *(resp)->buf++ = (val); (resp)->len++; }
 
 /*
  * The context of a single thread, including the request currently being
diff -Nru a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h
--- a/include/linux/sunrpc/svcauth.h	Fri Sep 20 08:20:44 2002
+++ b/include/linux/sunrpc/svcauth.h	Fri Sep 20 08:20:44 2002
@@ -14,7 +14,7 @@
 #include <linux/sunrpc/msg_prot.h>
 
 struct svc_cred {
-	u32			cr_flavor;
+	rpc_authflavor_t	cr_flavor;
 	uid_t			cr_uid;
 	gid_t			cr_gid;
 	gid_t			cr_groups[NGROUPS];
@@ -23,8 +23,9 @@
 struct svc_rqst;		/* forward decl */
 
 void	svc_authenticate(struct svc_rqst *rqstp, u32 *statp, u32 *authp);
-int	svc_auth_register(u32 flavor, void (*)(struct svc_rqst *,u32 *,u32 *));
-void	svc_auth_unregister(u32 flavor);
+int	svc_auth_register(rpc_authflavor_t flavor,
+				void (*)(struct svc_rqst *,u32 *,u32 *));
+void	svc_auth_unregister(rpc_authflavor_t flavor);
 
 #if 0
 /*
@@ -39,7 +40,7 @@
 	u32		aup_gids[NGRPS];
 };
 
-struct svc_authops *	auth_getops(u32 flavor);
+struct svc_authops *	auth_getops(rpc_authflavor_t flavor);
 #endif
 
 
diff -Nru a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
--- a/include/linux/sunrpc/xprt.h	Fri Sep 20 08:20:47 2002
+++ b/include/linux/sunrpc/xprt.h	Fri Sep 20 08:20:47 2002
@@ -44,6 +44,19 @@
 #define RPC_MAX_UDP_TIMEOUT	(60*HZ)
 #define RPC_MAX_TCP_TIMEOUT	(600*HZ)
 
+/*
+ * Wait duration for an RPC TCP connection to be established.  Solaris
+ * NFS over TCP uses 60 seconds, for example, which is in line with how
+ * long a server takes to reboot.
+ */
+#define RPC_CONNECT_TIMEOUT	(60*HZ)
+
+/*
+ * Delay an arbitrary number of seconds before attempting to reconnect
+ * after an error.
+ */
+#define RPC_REESTABLISH_TIMEOUT	(15*HZ)
+
 /* RPC call and reply header size as number of 32bit words (verifier
  * size computed separately)
  */
@@ -177,7 +190,7 @@
 void			xprt_receive(struct rpc_task *);
 int			xprt_adjust_timeout(struct rpc_timeout *);
 void			xprt_release(struct rpc_task *);
-void			xprt_reconnect(struct rpc_task *);
+void			xprt_connect(struct rpc_task *);
 int			xprt_clear_backlog(struct rpc_xprt *);
 void			xprt_sock_setbufsize(struct rpc_xprt *);
 
diff -Nru a/include/linux/sysctl.h b/include/linux/sysctl.h
--- a/include/linux/sysctl.h	Fri Sep 20 08:20:41 2002
+++ b/include/linux/sysctl.h	Fri Sep 20 08:20:41 2002
@@ -128,7 +128,6 @@
 	KERN_TAINTED=53,	/* int: various kernel tainted flags */
 	KERN_CADPID=54,		/* int: PID of the process to notify on CAD */
 	KERN_PIDMAX=55,		/* int: PID # limit */
-	KERN_HUGETLB_PAGE_NUM=56, /* int: Number of available Huge Pages */
 };
 
 
@@ -147,12 +146,12 @@
 	VM_PAGE_CLUSTER=10,	/* int: set number of pages to swap together */
 	VM_DIRTY_BACKGROUND=11,	/* dirty_background_ratio */
 	VM_DIRTY_ASYNC=12,	/* dirty_async_ratio */
-	VM_DIRTY_SYNC=13,	/* dirty_sync_ratio */
-	VM_DIRTY_WB_CS=14,	/* dirty_writeback_centisecs */
-	VM_DIRTY_EXPIRE_CS=15,	/* dirty_expire_centisecs */
-	VM_NR_PDFLUSH_THREADS=16, /* nr_pdflush_threads */
-	VM_OVERCOMMIT_RATIO=17, /* percent of RAM to allow overcommit in */
-	VM_PAGEBUF=18		/* struct: Control pagebuf parameters */
+	VM_DIRTY_WB_CS=13,	/* dirty_writeback_centisecs */
+	VM_DIRTY_EXPIRE_CS=14,	/* dirty_expire_centisecs */
+	VM_NR_PDFLUSH_THREADS=15, /* nr_pdflush_threads */
+	VM_OVERCOMMIT_RATIO=16, /* percent of RAM to allow overcommit in */
+	VM_PAGEBUF=17,		/* struct: Control pagebuf parameters */
+	VM_HUGETLB_PAGES=18,	/* int: Number of available Huge Pages */
 };
 
 
diff -Nru a/include/linux/threads.h b/include/linux/threads.h
--- a/include/linux/threads.h	Fri Sep 20 08:20:41 2002
+++ b/include/linux/threads.h	Fri Sep 20 08:20:41 2002
@@ -17,8 +17,13 @@
 #define MIN_THREADS_LEFT_FOR_ROOT 4
 
 /*
- * This controls the maximum pid allocated to a process
+ * This controls the default maximum pid allocated to a process
  */
-#define DEFAULT_PID_MAX 0x8000
+#define PID_MAX_DEFAULT 0x8000
+
+/*
+ * A maximum of 4 million PIDs should be enough for a while:
+ */
+#define PID_MAX_LIMIT (4*1024*1024)
 
 #endif
diff -Nru a/include/linux/uio.h b/include/linux/uio.h
--- a/include/linux/uio.h	Fri Sep 20 08:20:41 2002
+++ b/include/linux/uio.h	Fri Sep 20 08:20:41 2002
@@ -35,7 +35,11 @@
 #endif
 
 /*
- * Total number of bytes covered by an iovec
+ * Total number of bytes covered by an iovec.
+ *
+ * NOTE that it is not safe to use this function until all the iovec's
+ * segment lengths have been validated.  Because the individual lengths can
+ * overflow a size_t when added together.
  */
 static inline size_t iov_length(const struct iovec *iov, unsigned long nr_segs)
 {
diff -Nru a/include/linux/wireless.h b/include/linux/wireless.h
--- a/include/linux/wireless.h	Fri Sep 20 08:20:47 2002
+++ b/include/linux/wireless.h	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,7 @@
 /*
  * This file define a set of standard wireless extensions
  *
- * Version :	14	25.1.02
+ * Version :	15	12.7.02
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
  * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
@@ -80,7 +80,7 @@
  * (there is some stuff that will be added in the future...)
  * I just plan to increment with each new version.
  */
-#define WIRELESS_EXT	14
+#define WIRELESS_EXT	15
 
 /*
  * Changes :
@@ -153,17 +153,32 @@
  *	- Define additional specific event numbers
  *	- Add "addr" and "param" fields in union iwreq_data
  *	- AP scanning stuff (SIOCSIWSCAN and friends)
+ *
+ * V14 to V15
+ * ----------
+ *	- Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg
+ *	- Make struct iw_freq signed (both m & e), add explicit padding
+ *	- Add IWEVCUSTOM for driver specific event/scanning token
+ *	- Add IW_MAX_GET_SPY for driver returning a lot of addresses
+ *	- Add IW_TXPOW_RANGE for range of Tx Powers
+ *	- Add IWEVREGISTERED & IWEVEXPIRED events for Access Points
+ *	- Add IW_MODE_MONITOR for passive monitor
  */
 
 /**************************** CONSTANTS ****************************/
 
 /* -------------------------- IOCTL LIST -------------------------- */
 
-/* Basic operations */
+/* Wireless Identification */
 #define SIOCSIWCOMMIT	0x8B00		/* Commit pending changes to driver */
 #define SIOCGIWNAME	0x8B01		/* get name == wireless protocol */
-#define SIOCSIWNWID	0x8B02		/* set network id (the cell) */
-#define SIOCGIWNWID	0x8B03		/* get network id */
+/* SIOCGIWNAME is used to verify the presence of Wireless Extensions.
+ * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"...
+ * Don't put the name of your driver there, it's useless. */
+
+/* Basic operations */
+#define SIOCSIWNWID	0x8B02		/* set network id (pre-802.11) */
+#define SIOCGIWNWID	0x8B03		/* get network id (the cell) */
 #define SIOCSIWFREQ	0x8B04		/* set channel/frequency (Hz) */
 #define SIOCGIWFREQ	0x8B05		/* get channel/frequency (Hz) */
 #define SIOCSIWMODE	0x8B06		/* set operation mode */
@@ -178,16 +193,18 @@
 #define SIOCGIWPRIV	0x8B0D		/* get private ioctl interface info */
 #define SIOCSIWSTATS	0x8B0E		/* Unused */
 #define SIOCGIWSTATS	0x8B0F		/* Get /proc/net/wireless stats */
+/* SIOCGIWSTATS is strictly used between user space and the kernel, and
+ * is never passed to the driver (i.e. the driver will never see it). */
 
-/* Mobile IP support */
+/* Mobile IP support (statistics per MAC address) */
 #define SIOCSIWSPY	0x8B10		/* set spy addresses */
 #define SIOCGIWSPY	0x8B11		/* get spy info (quality of link) */
 
 /* Access Point manipulation */
 #define SIOCSIWAP	0x8B14		/* set access point MAC addresses */
 #define SIOCGIWAP	0x8B15		/* get access point MAC addresses */
-#define SIOCGIWAPLIST	0x8B17		/* get list of access point in range */
-#define SIOCSIWSCAN	0x8B18		/* trigger scanning */
+#define SIOCGIWAPLIST	0x8B17		/* Deprecated in favor of scanning */
+#define SIOCSIWSCAN	0x8B18		/* trigger scanning (list cells) */
 #define SIOCGIWSCAN	0x8B19		/* get scanning results */
 
 /* 802.11 specific support */
@@ -197,9 +214,7 @@
 #define SIOCGIWNICKN	0x8B1D		/* get node name/nickname */
 /* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit
  * within the 'iwreq' structure, so we need to use the 'data' member to
- * point to a string in user space, like it is done for RANGE...
- * The "flags" member indicate if the ESSID is active or not (promiscuous).
- */
+ * point to a string in user space, like it is done for RANGE... */
 
 /* Other parameters useful in 802.11 and some other devices */
 #define SIOCSIWRATE	0x8B20		/* set default bit rate (bps) */
@@ -257,7 +272,10 @@
 /* Most events use the same identifier as ioctl requests */
 
 #define IWEVTXDROP	0x8C00		/* Packet dropped to excessive retry */
-#define IWEVQUAL	0x8C01		/* Quality part of statistics */
+#define IWEVQUAL	0x8C01		/* Quality part of statistics (scan) */
+#define IWEVCUSTOM	0x8C02		/* Driver specific ascii string */
+#define IWEVREGISTERED	0x8C03		/* Discovered a new node (AP mode) */
+#define IWEVEXPIRED	0x8C04		/* Expired a node (AP mode) */
 
 #define IWEVFIRST	0x8C00
 
@@ -273,7 +291,8 @@
 #define IW_PRIV_TYPE_BYTE	0x1000	/* Char as number */
 #define IW_PRIV_TYPE_CHAR	0x2000	/* Char as character */
 #define IW_PRIV_TYPE_INT	0x4000	/* 32 bits int */
-#define IW_PRIV_TYPE_FLOAT	0x5000
+#define IW_PRIV_TYPE_FLOAT	0x5000	/* struct iw_freq */
+#define IW_PRIV_TYPE_ADDR	0x6000	/* struct sockaddr */
 
 #define IW_PRIV_SIZE_FIXED	0x0800	/* Variable or fixed nuber of args */
 
@@ -297,9 +316,12 @@
 
 /* Maximum tx powers in the range struct */
 #define IW_MAX_TXPOWER		8
+/* Note : if you more than 8 TXPowers, just set the max and min or
+ * a few of them in the struct iw_range. */
 
 /* Maximum of address that you may set with SPY */
-#define IW_MAX_SPY		8
+#define IW_MAX_SPY		8	/* set */
+#define IW_MAX_GET_SPY		64	/* get */
 
 /* Maximum of address that you may get in the
    list of access points in range */
@@ -315,6 +337,7 @@
 #define IW_MODE_MASTER	3	/* Synchronisation master or Access Point */
 #define IW_MODE_REPEAT	4	/* Wireless Repeater (forwarder) */
 #define IW_MODE_SECOND	5	/* Secondary master/repeater (backup) */
+#define IW_MODE_MONITOR	6	/* Passive monitor (listen only) */
 
 /* Maximum number of size of encoding token available
  * they are listed in the range structure */
@@ -350,8 +373,10 @@
 #define IW_POWER_RELATIVE	0x0004	/* Value is not in seconds/ms/us */
 
 /* Transmit Power flags available */
+#define IW_TXPOW_TYPE		0x00FF	/* Type of value */
 #define IW_TXPOW_DBM		0x0000	/* Value is in dBm */
 #define IW_TXPOW_MWATT		0x0001	/* Value is in mW */
+#define IW_TXPOW_RANGE		0x1000	/* Range of value between min/max */
 
 /* Retry limits and lifetime flags available */
 #define IW_RETRY_ON		0x0000	/* No details... */
@@ -376,6 +401,9 @@
 /* Maximum size of returned data */
 #define IW_SCAN_MAX_DATA	4096	/* In bytes */
 
+/* Max number of char in custom event - use multiple of them if needed */
+#define IW_CUSTOM_MAX		256	/* In bytes */
+
 /****************************** TYPES ******************************/
 
 /* --------------------------- SUBTYPES --------------------------- */
@@ -411,9 +439,10 @@
  */
 struct	iw_freq
 {
-	__u32		m;		/* Mantissa */
-	__u16		e;		/* Exponent */
+	__s32		m;		/* Mantissa */
+	__s16		e;		/* Exponent */
 	__u8		i;		/* List index (when in range struct) */
+	__u8		pad;		/* Unused - just for alignement */
 };
 
 /*
diff -Nru a/include/linux/writeback.h b/include/linux/writeback.h
--- a/include/linux/writeback.h	Fri Sep 20 08:20:41 2002
+++ b/include/linux/writeback.h	Fri Sep 20 08:20:41 2002
@@ -27,22 +27,29 @@
  * fs/fs-writeback.c
  */
 enum writeback_sync_modes {
-	WB_SYNC_NONE =  0,	/* Don't wait on anything */
-	WB_SYNC_LAST =  1,	/* Wait on the last-written mapping */
-	WB_SYNC_ALL =   2,	/* Wait on every mapping */
-	WB_SYNC_HOLD =  3,	/* Hold the inode on sb_dirty for sys_sync() */
+	WB_SYNC_NONE,	/* Don't wait on anything */
+	WB_SYNC_ALL,	/* Wait on every mapping */
+	WB_SYNC_HOLD,	/* Hold the inode on sb_dirty for sys_sync() */
 };
 
-void writeback_unlocked_inodes(int *nr_to_write,
-			       enum writeback_sync_modes sync_mode,
-			       unsigned long *older_than_this);
+/*
+ * A control structure which tells the writeback code what to do
+ */
+struct writeback_control {
+	struct backing_dev_info *bdi;	/* If !NULL, only write back this
+					   queue */
+	enum writeback_sync_modes sync_mode;
+	unsigned long *older_than_this;	/* If !NULL, only write back inodes
+					   older than this */
+	long nr_to_write;		/* Write this many pages, and decrement
+					   this for each page written */
+};
+	
+void writeback_inodes(struct writeback_control *wbc);
 void wake_up_inode(struct inode *inode);
 void __wait_on_inode(struct inode * inode);
 void sync_inodes_sb(struct super_block *, int wait);
 void sync_inodes(int wait);
-void writeback_backing_dev(struct backing_dev_info *bdi, int *nr_to_write,
-			enum writeback_sync_modes sync_mode,
-			unsigned long *older_than_this);
 
 /* writeback.h requires fs.h; it, too, is not included from here. */
 static inline void wait_on_inode(struct inode *inode)
@@ -57,7 +64,6 @@
 /* These 5 are exported to sysctl. */
 extern int dirty_background_ratio;
 extern int dirty_async_ratio;
-extern int dirty_sync_ratio;
 extern int dirty_writeback_centisecs;
 extern int dirty_expire_centisecs;
 
@@ -65,7 +71,7 @@
 void balance_dirty_pages(struct address_space *mapping);
 void balance_dirty_pages_ratelimited(struct address_space *mapping);
 int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0);
-int do_writepages(struct address_space *mapping, int *nr_to_write);
+int do_writepages(struct address_space *mapping, struct writeback_control *wbc);
 
 /* pdflush.c */
 extern int nr_pdflush_threads;	/* Global so it can be exported to sysctl
diff -Nru a/include/net/ax25.h b/include/net/ax25.h
--- a/include/net/ax25.h	Fri Sep 20 08:20:47 2002
+++ b/include/net/ax25.h	Fri Sep 20 08:20:47 2002
@@ -3,11 +3,14 @@
  *
  *	Alan Cox (GW4PTS) 	10/11/93
  */
- 
 #ifndef _AX25_H
 #define _AX25_H 
+
 #include <linux/config.h>
 #include <linux/ax25.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <asm/atomic.h>
 
 #define	AX25_T1CLAMPLO  		1
 #define	AX25_T1CLAMPHI 			(30 * HZ)
@@ -66,6 +69,8 @@
 #define	AX25_UA			0x63	/* Unnumbered acknowledge */
 #define	AX25_FRMR		0x87	/* Frame reject */
 #define	AX25_UI			0x03	/* Unnumbered information */
+#define	AX25_XID		0xaf	/* Exchange information */
+#define	AX25_TEST		0xe3	/* Test */
 
 #define	AX25_PF			0x10	/* Poll/final bit for standard AX.25 */
 #define	AX25_EPF		0x01	/* Poll/final bit for extended AX.25 */
@@ -147,10 +152,12 @@
 
 typedef struct ax25_route {
 	struct ax25_route	*next;
+	atomic_t		ref;
 	ax25_address		callsign;
-	struct net_device		*dev;
+	struct net_device	*dev;
 	ax25_digi		*digipeat;
 	char			ip_mode;
+	struct timer_list	timer;
 } ax25_route;
 
 typedef struct {
@@ -197,11 +204,12 @@
 #define ax25_sk(__sk) ((ax25_cb *)(__sk)->protinfo)
 
 /* af_ax25.c */
-extern ax25_cb *volatile ax25_list;
+extern ax25_cb *ax25_list;
+extern spinlock_t ax25_list_lock;
 extern void ax25_free_cb(ax25_cb *);
 extern void ax25_insert_socket(ax25_cb *);
 struct sock *ax25_find_listener(ax25_address *, int, struct net_device *, int);
-struct sock *ax25_find_socket(ax25_address *, ax25_address *, int);
+struct sock *ax25_get_socket(ax25_address *, ax25_address *, int);
 extern ax25_cb *ax25_find_cb(ax25_address *, ax25_address *, ax25_digi *, struct net_device *);
 extern struct sock *ax25_addr_match(ax25_address *);
 extern void ax25_send_to_raw(struct sock *, struct sk_buff *, int);
@@ -224,6 +232,7 @@
 
 /* ax25_dev.c */
 extern ax25_dev *ax25_dev_list;
+extern spinlock_t ax25_dev_lock;
 extern ax25_dev *ax25_dev_ax25dev(struct net_device *);
 extern ax25_dev *ax25_addr_ax25dev(ax25_address *);
 extern void ax25_dev_device_up(struct net_device *);
@@ -286,9 +295,15 @@
 extern int  ax25_rt_ioctl(unsigned int, void *);
 extern int  ax25_rt_get_info(char *, char **, off_t, int);
 extern int  ax25_rt_autobind(ax25_cb *, ax25_address *);
-extern ax25_route *ax25_rt_find_route(ax25_address *, struct net_device *);
+extern ax25_route *ax25_rt_find_route(ax25_route *, ax25_address *,
+	struct net_device *);
 extern struct sk_buff *ax25_rt_build_path(struct sk_buff *, ax25_address *, ax25_address *, ax25_digi *);
 extern void ax25_rt_free(void);
+
+static inline void ax25_put_route(ax25_route *ax25_rt)
+{
+	atomic_dec(&ax25_rt->ref);
+}
 
 /* ax25_std_in.c */
 extern int  ax25_std_frame_in(ax25_cb *, struct sk_buff *, int);
diff -Nru a/include/net/irda/af_irda.h b/include/net/irda/af_irda.h
--- a/include/net/irda/af_irda.h	Fri Sep 20 08:20:47 2002
+++ b/include/net/irda/af_irda.h	Fri Sep 20 08:20:47 2002
@@ -55,8 +55,8 @@
 	__u16 mask;           /* Hint bits mask */
 	__u16 hints;          /* Hint bits */
 
-	__u32 ckey;           /* IrLMP client handle */
-	__u32 skey;           /* IrLMP service handle */
+	void *ckey;           /* IrLMP client handle */
+	void *skey;           /* IrLMP service handle */
 
 	struct ias_object *ias_obj;   /* Our service name + lsap in IAS */
 	struct iriap_cb *iriap;	      /* Used to query remote IAS */
diff -Nru a/include/net/irda/ircomm_tty.h b/include/net/irda/ircomm_tty.h
--- a/include/net/irda/ircomm_tty.h	Fri Sep 20 08:20:44 2002
+++ b/include/net/irda/ircomm_tty.h	Fri Sep 20 08:20:44 2002
@@ -86,8 +86,8 @@
 
 	struct iriap_cb *iriap; /* Instance used for querying remote IAS */
 	struct ias_object* obj;
-	int skey;
-	int ckey;
+	void *skey;
+	void *ckey;
 
 	struct termios	  normal_termios;
 	struct termios	  callout_termios;
@@ -104,6 +104,14 @@
 	long pgrp;		/* pgrp of opening process */
 	int  open_count;
 	int  blocked_open;	/* # of blocked opens */
+
+	/* Protect concurent access to :
+	 *	o self->open_count
+	 *	o self->ctrl_skb
+	 *	o self->tx_skb
+	 * Maybe other things may gain to be protected as well...
+	 * Jean II */
+	spinlock_t spinlock;
 };
 
 void ircomm_tty_start(struct tty_struct *tty);
diff -Nru a/include/net/irda/irlmp.h b/include/net/irda/irlmp.h
--- a/include/net/irda/irlmp.h	Fri Sep 20 08:20:41 2002
+++ b/include/net/irda/irlmp.h	Fri Sep 20 08:20:41 2002
@@ -183,7 +183,6 @@
 	hashbin_t *services;
 
 	hashbin_t *cachelog;	/* Current discovery log */
-	spinlock_t log_lock;	/* discovery log spinlock */
 
 	int running;
 
@@ -197,12 +196,12 @@
 void irlmp_close_lsap( struct lsap_cb *self);
 
 __u16 irlmp_service_to_hint(int service);
-__u32 irlmp_register_service(__u16 hints);
-int irlmp_unregister_service(__u32 handle);
-__u32 irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb,
+void *irlmp_register_service(__u16 hints);
+int irlmp_unregister_service(void *handle);
+void *irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb,
 			    DISCOVERY_CALLBACK1 expir_clb, void *priv);
-int irlmp_unregister_client(__u32 handle);
-int irlmp_update_client(__u32 handle, __u16 hint_mask, 
+int irlmp_unregister_client(void *handle);
+int irlmp_update_client(void *handle, __u16 hint_mask, 
 			DISCOVERY_CALLBACK1 disco_clb,
 			DISCOVERY_CALLBACK1 expir_clb, void *priv);
 
@@ -221,7 +220,7 @@
 				 struct sk_buff *userdata);
 int  irlmp_disconnect_request(struct lsap_cb *, struct sk_buff *userdata);
 
-void irlmp_discovery_confirm(hashbin_t *discovery_log, DISCOVERY_MODE);
+void irlmp_discovery_confirm(hashbin_t *discovery_log, DISCOVERY_MODE mode);
 void irlmp_discovery_request(int nslots);
 struct irda_device_info *irlmp_get_discoveries(int *pn, __u16 mask, int nslots);
 void irlmp_do_expiry(void);
@@ -257,8 +256,6 @@
 extern int sysctl_discovery;
 extern int sysctl_lap_keepalive_time;	/* in ms, default is LM_IDLE_TIMEOUT */
 extern struct irlmp_cb *irlmp;
-
-static inline hashbin_t *irlmp_get_cachelog(void) { return irlmp->cachelog; }
 
 /* Check if LAP queue is full.
  * Used by IrTTP for low control, see comments in irlap.h - Jean II */
diff -Nru a/include/net/irda/irqueue.h b/include/net/irda/irqueue.h
--- a/include/net/irda/irqueue.h	Fri Sep 20 08:20:47 2002
+++ b/include/net/irda/irqueue.h	Fri Sep 20 08:20:47 2002
@@ -36,12 +36,12 @@
 #define NAME_SIZE      32
 
 /*
- * Hash types
+ * Hash types (some flags can be xored)
+ * See comments in irqueue.c for which one to use...
  */
-#define HB_NOLOCK      0
-#define HB_GLOBAL      1
-#define HB_LOCAL       2
-#define HB_SORTED      4
+#define HB_NOLOCK	0	/* No concurent access prevention */
+#define HB_LOCK		1	/* Prevent concurent write with global lock */
+#define HB_SORTED	4	/* Not yet supported */
 
 /*
  * Hash defines
@@ -57,17 +57,12 @@
 
 typedef void (*FREE_FUNC)(void *arg);
 
-/*
- * Hashbin
- */
-#define GET_HASHBIN(x) ( x & HASHBIN_MASK )
-
 struct irda_queue {
 	struct irda_queue *q_next;
 	struct irda_queue *q_prev;
 
 	char   q_name[NAME_SIZE];
-	__u32  q_hash;
+	long   q_hash;			/* Must be able to cast a (void *) */
 };
 typedef struct irda_queue irda_queue_t;
 
@@ -75,8 +70,9 @@
 	__u32      magic;
 	int        hb_type;
 	int        hb_size;
-	spinlock_t hb_mutex[HASHBIN_SIZE] IRDA_ALIGN;
-	irda_queue_t   *hb_queue[HASHBIN_SIZE] IRDA_ALIGN;
+	spinlock_t hb_spinlock;		/* HB_LOCK - Can be used by the user */
+
+	irda_queue_t* hb_queue[HASHBIN_SIZE] IRDA_ALIGN;
 
 	irda_queue_t* hb_current;
 } hashbin_t;
@@ -84,18 +80,17 @@
 hashbin_t *hashbin_new(int type);
 int      hashbin_delete(hashbin_t* hashbin, FREE_FUNC func);
 int      hashbin_clear(hashbin_t* hashbin, FREE_FUNC free_func);
-void     hashbin_insert(hashbin_t* hashbin, irda_queue_t* entry, __u32 hashv, 
+void     hashbin_insert(hashbin_t* hashbin, irda_queue_t* entry, long hashv, 
 			char* name);
-void*    hashbin_find(hashbin_t* hashbin, __u32 hashv, char* name);
-void*    hashbin_remove(hashbin_t* hashbin, __u32 hashv, char* name);
+void*    hashbin_remove(hashbin_t* hashbin, long hashv, char* name);
 void*    hashbin_remove_first(hashbin_t *hashbin);
 void*	 hashbin_remove_this( hashbin_t* hashbin, irda_queue_t* entry);
+void*    hashbin_find(hashbin_t* hashbin, long hashv, char* name);
+void*    hashbin_lock_find(hashbin_t* hashbin, long hashv, char* name);
+void*    hashbin_find_next(hashbin_t* hashbin, long hashv, char* name,
+			   void ** pnext);
 irda_queue_t *hashbin_get_first(hashbin_t *hashbin);
 irda_queue_t *hashbin_get_next(hashbin_t *hashbin);
-
-void enqueue_last(irda_queue_t **queue, irda_queue_t* element);
-void enqueue_first(irda_queue_t **queue, irda_queue_t* element);
-irda_queue_t *dequeue_first(irda_queue_t **queue);
 
 #define HASHBIN_GET_SIZE(hashbin) hashbin->hb_size
 
diff -Nru a/include/net/irda/irtty.h b/include/net/irda/irtty.h
--- a/include/net/irda/irtty.h	Fri Sep 20 08:20:47 2002
+++ b/include/net/irda/irtty.h	Fri Sep 20 08:20:47 2002
@@ -62,6 +62,9 @@
 	struct qos_info qos;       /* QoS capabilities for this device */
 	dongle_t *dongle;          /* Dongle driver */
 
+
+	spinlock_t lock;           /* For serializing operations */
+
 	__u32 new_speed;
  	__u32 flags;               /* Interface flags */
 
diff -Nru a/include/net/irda/smc-ircc.h b/include/net/irda/smc-ircc.h
--- a/include/net/irda/smc-ircc.h	Fri Sep 20 08:20:43 2002
+++ b/include/net/irda/smc-ircc.h	Fri Sep 20 08:20:43 2002
@@ -165,7 +165,9 @@
 
 	struct irport_cb *irport;
 
-	spinlock_t lock;           /* For serializing operations */
+	/* Locking : half of our operations are done with irport, so we
+	 * use the irport spinlock to make sure *everything* is properly
+	 * synchronised - Jean II */
 	
 	__u32 new_speed;
 	__u32 flags;               /* Interface flags */
diff -Nru a/include/net/irda/w83977af_ir.h b/include/net/irda/w83977af_ir.h
--- a/include/net/irda/w83977af_ir.h	Fri Sep 20 08:20:41 2002
+++ b/include/net/irda/w83977af_ir.h	Fri Sep 20 08:20:41 2002
@@ -179,6 +179,11 @@
 	chipio_t io;               /* IrDA controller information */
 	iobuff_t tx_buff;          /* Transmit buffer */
 	iobuff_t rx_buff;          /* Receive buffer */
+
+	/* Note : currently locking is *very* incomplete, but this
+	 * will get you started. Check in nsc-ircc.c for a proper
+	 * locking strategy. - Jean II */
+	spinlock_t lock;           /* For serializing operations */
 	
 	__u32 flags;               /* Interface flags */
 	__u32 new_speed;
diff -Nru a/include/net/iw_handler.h b/include/net/iw_handler.h
--- a/include/net/iw_handler.h	Fri Sep 20 08:20:42 2002
+++ b/include/net/iw_handler.h	Fri Sep 20 08:20:42 2002
@@ -1,7 +1,7 @@
 /*
  * This file define the new driver API for Wireless Extensions
  *
- * Version :	3	17.1.02
+ * Version :	4	21.6.02
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
  * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved.
@@ -206,7 +206,7 @@
  * will be needed...
  * I just plan to increment with each new version.
  */
-#define IW_HANDLER_VERSION	3
+#define IW_HANDLER_VERSION	4
 
 /*
  * Changes :
@@ -217,6 +217,9 @@
  *	- Add Wireless Event support :
  *		o wireless_send_event() prototype
  *		o iwe_stream_add_event/point() inline functions
+ * V3 to V4
+ * --------
+ *	- Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
  */
 
 /**************************** CONSTANTS ****************************/
@@ -233,10 +236,10 @@
 #define IW_HEADER_TYPE_CHAR	2	/* char [IFNAMSIZ] */
 #define IW_HEADER_TYPE_UINT	4	/* __u32 */
 #define IW_HEADER_TYPE_FREQ	5	/* struct iw_freq */
-#define IW_HEADER_TYPE_POINT	6	/* struct iw_point */
-#define IW_HEADER_TYPE_PARAM	7	/* struct iw_param */
-#define IW_HEADER_TYPE_ADDR	8	/* struct sockaddr */
-#define IW_HEADER_TYPE_QUAL	9	/* struct iw_quality */
+#define IW_HEADER_TYPE_ADDR	6	/* struct sockaddr */
+#define IW_HEADER_TYPE_POINT	8	/* struct iw_point */
+#define IW_HEADER_TYPE_PARAM	9	/* struct iw_param */
+#define IW_HEADER_TYPE_QUAL	10	/* struct iw_quality */
 
 /* Handling flags */
 /* Most are not implemented. I just use them as a reminder of some
diff -Nru a/include/net/llc_actn.h b/include/net/llc_actn.h
--- a/include/net/llc_actn.h	Fri Sep 20 08:20:42 2002
+++ b/include/net/llc_actn.h	Fri Sep 20 08:20:42 2002
@@ -45,4 +45,5 @@
 					struct sk_buff *skb);
 extern int llc_station_ac_report_status(struct llc_station *station,
 					struct sk_buff *skb);
+extern void llc_station_ack_tmr_cb(unsigned long timeout_data);
 #endif /* LLC_ACTN_H */
diff -Nru a/include/net/llc_c_ac.h b/include/net/llc_c_ac.h
--- a/include/net/llc_c_ac.h	Fri Sep 20 08:20:48 2002
+++ b/include/net/llc_c_ac.h	Fri Sep 20 08:20:48 2002
@@ -211,4 +211,9 @@
 					      struct sk_buff *skb);
 extern int llc_conn_ac_send_i_rsp_as_ack(struct sock* sk, struct sk_buff *skb);
 extern int llc_conn_ac_send_i_as_ack(struct sock* sk, struct sk_buff *skb);
+
+extern void llc_conn_busy_tmr_cb(unsigned long timeout_data);
+extern void llc_conn_pf_cycle_tmr_cb(unsigned long timeout_data);
+extern void llc_conn_ack_tmr_cb(unsigned long timeout_data);
+extern void llc_conn_rej_tmr_cb(unsigned long timeout_data);
 #endif /* LLC_C_AC_H */
diff -Nru a/include/net/llc_c_ev.h b/include/net/llc_c_ev.h
--- a/include/net/llc_c_ev.h	Fri Sep 20 08:20:42 2002
+++ b/include/net/llc_c_ev.h	Fri Sep 20 08:20:42 2002
@@ -11,6 +11,9 @@
  *
  * See the GNU General Public License for more details.
  */
+
+#include <net/sock.h>
+
 /* Connection component state transition event qualifiers */
 /* Types of events (possible values in 'ev->type') */
 #define LLC_CONN_EV_TYPE_SIMPLE		 1
@@ -293,4 +296,10 @@
 						struct sk_buff *skb);
 extern int llc_conn_ev_qlfy_set_status_rst_done(struct sock *sk,
 						struct sk_buff *skb);
+
+static __inline__ int llc_conn_space(struct sock *sk, struct sk_buff *skb)
+{
+	return atomic_read(&sk->rmem_alloc) + skb->truesize <
+	       (unsigned)sk->rcvbuf;
+}
 #endif /* LLC_C_EV_H */
diff -Nru a/include/net/llc_main.h b/include/net/llc_main.h
--- a/include/net/llc_main.h	Fri Sep 20 08:20:44 2002
+++ b/include/net/llc_main.h	Fri Sep 20 08:20:44 2002
@@ -16,7 +16,7 @@
 #define LLC_TYPE_1		 1
 #define LLC_TYPE_2		 2
 #define LLC_P_TIME		 2
-#define LLC_ACK_TIME		 3
+#define LLC_ACK_TIME		 1
 #define LLC_REJ_TIME		 3
 #define LLC_BUSY_TIME		 3
 #define LLC_DEST_INVALID	 0	/* Invalid LLC PDU type */
diff -Nru a/init/Makefile b/init/Makefile
--- a/init/Makefile	Fri Sep 20 08:20:44 2002
+++ b/init/Makefile	Fri Sep 20 08:20:44 2002
@@ -2,8 +2,6 @@
 # Makefile for the linux kernel.
 #
 
-O_TARGET := init.o
-
 obj-y    := main.o version.o do_mounts.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/init/main.c b/init/main.c
--- a/init/main.c	Fri Sep 20 08:20:43 2002
+++ b/init/main.c	Fri Sep 20 08:20:43 2002
@@ -66,6 +66,7 @@
 extern void sysctl_init(void);
 extern void signals_init(void);
 extern void buffer_init(void);
+extern void pidhash_init(void);
 extern void pte_chain_init(void);
 extern void radix_tree_init(void);
 extern void free_initmem(void);
@@ -392,6 +393,7 @@
 	printk(linux_banner);
 	setup_arch(&command_line);
 	setup_per_cpu_areas();
+	build_all_zonelists();
 	printk("Kernel command line: %s\n", saved_command_line);
 	parse_options(command_line);
 	trap_init();
@@ -432,6 +434,7 @@
 #endif
 	mem_init();
 	kmem_cache_sizes_init();
+	pidhash_init();
 	pgtable_cache_init();
 	pte_chain_init();
 	fork_init(num_physpages);
diff -Nru a/ipc/Makefile b/ipc/Makefile
--- a/ipc/Makefile	Fri Sep 20 08:20:43 2002
+++ b/ipc/Makefile	Fri Sep 20 08:20:43 2002
@@ -1,13 +1,6 @@
 #
 # Makefile for the linux ipc.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definition is now in the main makefile...
-
-O_TARGET := ipc.o
 
 obj-y   := util.o
 
diff -Nru a/kernel/Makefile b/kernel/Makefile
--- a/kernel/Makefile	Fri Sep 20 08:20:43 2002
+++ b/kernel/Makefile	Fri Sep 20 08:20:43 2002
@@ -1,13 +1,6 @@
 #
 # Makefile for the linux kernel.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
-
-O_TARGET := kernel.o
 
 export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o \
 		printk.o platform.o suspend.o dma.o
@@ -15,7 +8,7 @@
 obj-y     = sched.o fork.o exec_domain.o panic.o printk.o \
 	    module.o exit.o itimer.o time.o softirq.o resource.o \
 	    sysctl.o capability.o ptrace.o timer.o user.o \
-	    signal.o sys.o kmod.o context.o futex.o platform.o
+	    signal.o sys.o kmod.o context.o futex.o platform.o pid.o
 
 obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
 obj-$(CONFIG_SMP) += cpu.o
diff -Nru a/kernel/exit.c b/kernel/exit.c
--- a/kernel/exit.c	Fri Sep 20 08:20:44 2002
+++ b/kernel/exit.c	Fri Sep 20 08:20:44 2002
@@ -33,7 +33,12 @@
 {
 	struct dentry *proc_dentry;
 	nr_threads--;
-	unhash_pid(p);
+	detach_pid(p, PIDTYPE_PID);
+	if (thread_group_leader(p)) {
+		detach_pid(p, PIDTYPE_PGID);
+		detach_pid(p, PIDTYPE_SID);
+	}
+
 	REMOVE_LINKS(p);
 	p->pid = 0;
 	proc_dentry = p->proc_dentry;
@@ -109,22 +114,18 @@
 int session_of_pgrp(int pgrp)
 {
 	struct task_struct *p;
-	int fallback;
+	struct list_head *l;
+	struct pid *pid;
+	int sid = -1;
 
-	fallback = -1;
 	read_lock(&tasklist_lock);
-	for_each_process(p) {
- 		if (p->session <= 0)
- 			continue;
-		if (p->pgrp == pgrp) {
-			fallback = p->session;
+	for_each_task_pid(pgrp, PIDTYPE_PGID, p, l, pid)
+		if (p->session > 0) {
+			sid = p->session;
 			break;
 		}
-		if (p->pid == pgrp)
-			fallback = p->session;
-	}
 	read_unlock(&tasklist_lock);
-	return fallback;
+	return sid;
 }
 
 /*
@@ -135,21 +136,25 @@
  *
  * "I ask you, have you ever known what it is to be an orphan?"
  */
-static int __will_become_orphaned_pgrp(int pgrp, struct task_struct * ignored_task)
+static int __will_become_orphaned_pgrp(int pgrp, task_t *ignored_task)
 {
 	struct task_struct *p;
-
-	for_each_process(p) {
-		if ((p == ignored_task) || (p->pgrp != pgrp) ||
-		    (p->state == TASK_ZOMBIE) ||
-		    (p->parent->pid == 1))
+	struct list_head *l;
+	struct pid *pid;
+	int ret = 1;
+
+	for_each_task_pid(pgrp, PIDTYPE_PGID, p, l, pid) {
+		if (p == ignored_task
+				|| p->state == TASK_ZOMBIE 
+				|| p->real_parent->pid == 1)
 			continue;
-		if ((p->parent->pgrp != pgrp) &&
-		    (p->parent->session == p->session)) {
- 			return 0;
+		if (p->real_parent->pgrp != pgrp
+			    && p->real_parent->session == p->session) {
+			ret = 0;
+			break;
 		}
 	}
-	return 1;	/* (sighing) "Often!" */
+	return ret;	/* (sighing) "Often!" */
 }
 
 static int will_become_orphaned_pgrp(int pgrp, struct task_struct * ignored_task)
@@ -171,11 +176,11 @@
 static inline int __has_stopped_jobs(int pgrp)
 {
 	int retval = 0;
-	struct task_struct * p;
+	struct task_struct *p;
+	struct list_head *l;
+	struct pid *pid;
 
-	for_each_process(p) {
-		if (p->pgrp != pgrp)
-			continue;
+	for_each_task_pid(pgrp, PIDTYPE_PGID, p, l, pid) {
 		if (p->state != TASK_STOPPED)
 			continue;
 		retval = 1;
@@ -221,7 +226,6 @@
 	/* Set the exit signal to SIGCHLD so we signal init on exit */
 	current->exit_signal = SIGCHLD;
 
-	current->ptrace = 0;
 	if ((current->policy == SCHED_NORMAL) && (task_nice(current) < 0))
 		set_user_nice(current, 0);
 	/* cpus_allowed? */
@@ -268,25 +272,6 @@
 	reparent_to_init();
 }
 
-static void reparent_thread(task_t *p, task_t *reaper, task_t *child_reaper)
-{
-	/* We dont want people slaying init */
-	if (p->exit_signal != -1)
-		p->exit_signal = SIGCHLD;
-	p->self_exec_id++;
-
-	/* Make sure we're not reparenting to ourselves */
-	if (p == reaper)
-		p->real_parent = child_reaper;
-	else
-		p->real_parent = reaper;
-	if (p->parent == p->real_parent)
-		BUG();
-
-	if (p->pdeath_signal)
-		send_sig(p->pdeath_signal, p, 0);
-}
-
 static inline void close_files(struct files_struct * files)
 {
 	int i, j;
@@ -434,6 +419,66 @@
 	__exit_mm(tsk);
 }
 
+static inline void choose_new_parent(task_t *p, task_t *reaper, task_t *child_reaper)
+{
+	/* Make sure we're not reparenting to ourselves.  */
+	if (p == reaper)
+		p->real_parent = child_reaper;
+	else
+		p->real_parent = reaper;
+	if (p->parent == p->real_parent)
+		BUG();
+}
+
+static inline void reparent_thread(task_t *p, task_t *father, int traced)
+{
+	/* We dont want people slaying init.  */
+	if (p->exit_signal != -1)
+		p->exit_signal = SIGCHLD;
+	p->self_exec_id++;
+
+	if (p->pdeath_signal)
+		send_sig(p->pdeath_signal, p, 0);
+
+	/* Move the child from its dying parent to the new one.  */
+	if (unlikely(traced)) {
+		/* Preserve ptrace links if someone else is tracing this child.  */
+		list_del_init(&p->ptrace_list);
+		if (p->parent != p->real_parent)
+			list_add(&p->ptrace_list, &p->real_parent->ptrace_children);
+	} else {
+		/* If this child is being traced, then we're the one tracing it
+		 * anyway, so let go of it.
+		 */
+		p->ptrace = 0;
+		list_del_init(&p->sibling);
+		p->parent = p->real_parent;
+		list_add_tail(&p->sibling, &p->parent->children);
+
+		/* If we'd notified the old parent about this child's death,
+		 * also notify the new parent.
+		 */
+		if (p->state == TASK_ZOMBIE && p->exit_signal != -1)
+			do_notify_parent(p, p->exit_signal);
+	}
+
+	/*
+	 * process group orphan check
+	 * Case ii: Our child is in a different pgrp
+	 * than we are, and it was the only connection
+	 * outside, so the child pgrp is now orphaned.
+	 */
+	if ((p->pgrp != father->pgrp) &&
+	    (p->session == father->session)) {
+		int pgrp = p->pgrp;
+
+		if (__will_become_orphaned_pgrp(pgrp, 0) && __has_stopped_jobs(pgrp)) {
+			__kill_pg_info(SIGHUP, (void *)1, pgrp);
+			__kill_pg_info(SIGCONT, (void *)1, pgrp);
+		}
+	}
+}
+
 /*
  * When we die, we re-parent all our children.
  * Try to give them to another thread in our thread
@@ -443,7 +488,7 @@
 static inline void forget_original_parent(struct task_struct * father)
 {
 	struct task_struct *p, *reaper = father;
-	struct list_head *_p;
+	struct list_head *_p, *_n;
 
 	reaper = father->group_leader;
 	if (reaper == father)
@@ -457,60 +502,21 @@
 	 *
 	 * Search them and reparent children.
 	 */
-	list_for_each(_p, &father->children) {
+	list_for_each_safe(_p, _n, &father->children) {
 		p = list_entry(_p,struct task_struct,sibling);
-		if (father == p->real_parent)
-			reparent_thread(p, reaper, child_reaper);
-	}
-	list_for_each(_p, &father->ptrace_children) {
-		p = list_entry(_p,struct task_struct,ptrace_list);
-		reparent_thread(p, reaper, child_reaper);
-	}
-}
-
-static inline void zap_thread(task_t *p, task_t *father, int traced)
-{
-	/* If someone else is tracing this thread, preserve the ptrace links.  */
-	if (unlikely(traced)) {
-		task_t *trace_task = p->parent;
-		int ptrace_flag = p->ptrace;
-		BUG_ON (ptrace_flag == 0);
-
-		__ptrace_unlink(p);
-		p->ptrace = ptrace_flag;
-		__ptrace_link(p, trace_task);
-	} else {
-		/*
-		 * Otherwise, if we were tracing this thread, untrace it.
-		 * If we were only tracing the thread (i.e. not its real
-		 * parent), stop here.
-		 */
-		ptrace_unlink (p);
-		if (p->parent != father) {
-			BUG_ON(p->parent != p->real_parent);
-			return;
+		if (father == p->real_parent) {
+			choose_new_parent(p, reaper, child_reaper);
+			reparent_thread(p, father, 0);
+		} else {
+			ptrace_unlink (p);
+			if (p->state == TASK_ZOMBIE && p->exit_signal != -1)
+				do_notify_parent(p, p->exit_signal);
 		}
-		list_del_init(&p->sibling);
-		p->parent = p->real_parent;
-		list_add_tail(&p->sibling, &p->parent->children);
 	}
-
-	if (p->state == TASK_ZOMBIE && p->exit_signal != -1)
-		do_notify_parent(p, p->exit_signal);
-	/*
-	 * process group orphan check
-	 * Case ii: Our child is in a different pgrp
-	 * than we are, and it was the only connection
-	 * outside, so the child pgrp is now orphaned.
-	 */
-	if ((p->pgrp != current->pgrp) &&
-	    (p->session == current->session)) {
-		int pgrp = p->pgrp;
-
-		if (__will_become_orphaned_pgrp(pgrp, 0) && __has_stopped_jobs(pgrp)) {
-			__kill_pg_info(SIGHUP, (void *)1, pgrp);
-			__kill_pg_info(SIGCONT, (void *)1, pgrp);
-		}
+	list_for_each_safe(_p, _n, &father->ptrace_children) {
+		p = list_entry(_p,struct task_struct,ptrace_list);
+		choose_new_parent(p, reaper, child_reaper);
+		reparent_thread(p, father, 1);
 	}
 }
 
@@ -524,7 +530,18 @@
 
 	write_lock_irq(&tasklist_lock);
 
+	/*
+	 * This does two things:
+	 *
+  	 * A.  Make init inherit all the child processes
+	 * B.  Check to see if any process groups have become orphaned
+	 *	as a result of our exiting, and if they have any stopped
+	 *	jobs, send them a SIGHUP and then a SIGCONT.  (POSIX 3.2.2.2)
+	 */
+
 	forget_original_parent(current);
+	BUG_ON(!list_empty(&current->children));
+
 	/*
 	 * Check to see if any process groups have become orphaned
 	 * as a result of our exiting, and if they have any stopped
@@ -568,23 +585,8 @@
 		current->exit_signal = SIGCHLD;
 
 
-	/*
-	 * This loop does two things:
-	 *
-  	 * A.  Make init inherit all the child processes
-	 * B.  Check to see if any process groups have become orphaned
-	 *	as a result of our exiting, and if they have any stopped
-	 *	jobs, send them a SIGHUP and then a SIGCONT.  (POSIX 3.2.2.2)
-	 */
-
 	if (current->exit_signal != -1)
 		do_notify_parent(current, current->exit_signal);
-
-	while (!list_empty(&current->children))
-		zap_thread(list_entry(current->children.next,struct task_struct,sibling), current, 0);
-	while (!list_empty(&current->ptrace_children))
-		zap_thread(list_entry(current->ptrace_children.next,struct task_struct,ptrace_list), current, 1);
-	BUG_ON(!list_empty(&current->children));
 
 	current->state = TASK_ZOMBIE;
 	/*
diff -Nru a/kernel/fork.c b/kernel/fork.c
--- a/kernel/fork.c	Fri Sep 20 08:20:41 2002
+++ b/kernel/fork.c	Fri Sep 20 08:20:41 2002
@@ -47,17 +47,6 @@
 int max_threads;
 unsigned long total_forks;	/* Handle normal Linux uptimes. */
 
-/*
- * Protects next_safe, last_pid and pid_max:
- */
-spinlock_t lastpid_lock = SPIN_LOCK_UNLOCKED;
-
-static int next_safe = DEFAULT_PID_MAX;
-int pid_max = DEFAULT_PID_MAX;
-int last_pid;
-
-struct task_struct *pidhash[PIDHASH_SZ];
-
 rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED;  /* outer */
 
 /*
@@ -75,16 +64,14 @@
 	} else {
 		int cpu = smp_processor_id();
 
-		tsk = task_cache[cpu];
+		tsk = xchg(task_cache + cpu, tsk);
 		if (tsk) {
 			free_thread_info(tsk->thread_info);
 			kmem_cache_free(task_struct_cachep,tsk);
 		}
-		task_cache[cpu] = current;
 	}
 }
 
-/* Protects next_safe and last_pid. */
 void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
 {
 	unsigned long flags;
@@ -140,71 +127,28 @@
 	struct task_struct *tsk;
 	struct thread_info *ti;
 
-	ti = alloc_thread_info();
-	if (!ti)
-		return NULL;
-
-	tsk = kmem_cache_alloc(task_struct_cachep, GFP_KERNEL);
+	tsk = xchg(task_cache + smp_processor_id(), NULL);
 	if (!tsk) {
-		free_thread_info(ti);
-		return NULL;
-	}
+		ti = alloc_thread_info();
+		if (!ti)
+			return NULL;
+
+		tsk = kmem_cache_alloc(task_struct_cachep, GFP_KERNEL);
+		if (!tsk) {
+			free_thread_info(ti);
+			return NULL;
+		}
+	} else
+		ti = tsk->thread_info;
 
 	*ti = *orig->thread_info;
 	*tsk = *orig;
 	tsk->thread_info = ti;
 	ti->task = tsk;
 	atomic_set(&tsk->usage,1);
-
 	return tsk;
 }
 
-static int get_pid(unsigned long flags)
-{
-	struct task_struct *g, *p;
-	int pid;
-
-	if (flags & CLONE_IDLETASK)
-		return 0;
-
-	spin_lock(&lastpid_lock);
-	if (++last_pid > pid_max) {
-		last_pid = 300;		/* Skip daemons etc. */
-		goto inside;
-	}
-
-	if (last_pid >= next_safe) {
-inside:
-		next_safe = pid_max;
-		read_lock(&tasklist_lock);
-	repeat:
-		do_each_thread(g, p) {
-			if (p->pid == last_pid	||
-			   p->pgrp == last_pid	||
-			   p->session == last_pid) {
-				if (++last_pid >= next_safe) {
-					if (last_pid >= pid_max)
-						last_pid = 300;
-					next_safe = pid_max;
-				}
-				goto repeat;
-			}
-			if (p->pid > last_pid && next_safe > p->pid)
-				next_safe = p->pid;
-			if (p->pgrp > last_pid && next_safe > p->pgrp)
-				next_safe = p->pgrp;
-			if (p->session > last_pid && next_safe > p->session)
-				next_safe = p->session;
-		} while_each_thread(g, p);
-
-		read_unlock(&tasklist_lock);
-	}
-	pid = last_pid;
-	spin_unlock(&lastpid_lock);
-
-	return pid;
-}
-
 static inline int dup_mmap(struct mm_struct * mm)
 {
 	struct vm_area_struct * mpnt, *tmp, **pprev;
@@ -724,7 +668,13 @@
 	p->state = TASK_UNINTERRUPTIBLE;
 
 	copy_flags(clone_flags, p);
-	p->pid = get_pid(clone_flags);
+	if (clone_flags & CLONE_IDLETASK)
+		p->pid = 0;
+	else {
+		p->pid = alloc_pidmap();
+		if (p->pid == -1)
+			goto bad_fork_cleanup;
+	}
 	p->proc_dentry = NULL;
 
 	INIT_LIST_HEAD(&p->run_list);
@@ -887,7 +837,13 @@
 	SET_LINKS(p);
 	if (p->ptrace & PT_PTRACED)
 		__ptrace_link(p, current->parent);
-	hash_pid(p);
+
+	attach_pid(p, PIDTYPE_PID, p->pid);
+	if (thread_group_leader(p)) {
+		attach_pid(p, PIDTYPE_PGID, p->pgrp);
+		attach_pid(p, PIDTYPE_SID, p->session);
+	}
+
 	nr_threads++;
 	write_unlock_irq(&tasklist_lock);
 	retval = 0;
@@ -912,6 +868,8 @@
 bad_fork_cleanup_security:
 	security_ops->task_free_security(p);
 bad_fork_cleanup:
+	if (p->pid > 0)
+		free_pidmap(p->pid);
 	put_exec_domain(p->thread_info->exec_domain);
 	if (p->binfmt && p->binfmt->module)
 		__MOD_DEC_USE_COUNT(p->binfmt->module);
diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c
--- a/kernel/ksyms.c	Fri Sep 20 08:20:41 2002
+++ b/kernel/ksyms.c	Fri Sep 20 08:20:41 2002
@@ -53,6 +53,7 @@
 #include <linux/root_dev.h>
 #include <linux/percpu.h>
 #include <linux/smp_lock.h>
+#include <linux/dnotify.h>
 #include <asm/checksum.h>
 
 #if defined(CONFIG_PROC_FS)
@@ -90,7 +91,6 @@
 EXPORT_SYMBOL(exit_mm);
 
 /* internal kernel memory management */
-EXPORT_SYMBOL(_alloc_pages);
 EXPORT_SYMBOL(__alloc_pages);
 EXPORT_SYMBOL(alloc_pages_node);
 EXPORT_SYMBOL(__get_free_pages);
@@ -115,9 +115,12 @@
 EXPORT_SYMBOL(vmap);
 EXPORT_SYMBOL(vunmap);
 EXPORT_SYMBOL(vmalloc_to_page);
-EXPORT_SYMBOL(mem_map);
 EXPORT_SYMBOL(remap_page_range);
+#ifndef CONFIG_DISCONTIGMEM
+EXPORT_SYMBOL(contig_page_data);
+EXPORT_SYMBOL(mem_map);
 EXPORT_SYMBOL(max_mapnr);
+#endif
 EXPORT_SYMBOL(high_memory);
 EXPORT_SYMBOL(vmtruncate);
 EXPORT_SYMBOL(find_vma);
@@ -560,6 +563,7 @@
 EXPORT_SYMBOL(make_bad_inode);
 EXPORT_SYMBOL(is_bad_inode);
 EXPORT_SYMBOL(event);
+EXPORT_SYMBOL(__inode_dir_notify);
 
 #ifdef CONFIG_UID16
 EXPORT_SYMBOL(overflowuid);
@@ -602,7 +606,6 @@
 EXPORT_SYMBOL(init_thread_union);
 
 EXPORT_SYMBOL(tasklist_lock);
-EXPORT_SYMBOL(pidhash);
 #if defined(CONFIG_SMP) && defined(__GENERIC_PER_CPU)
 EXPORT_SYMBOL(__per_cpu_offset);
 #endif
diff -Nru a/kernel/pid.c b/kernel/pid.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/kernel/pid.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,219 @@
+/*
+ * Generic pidhash and scalable, time-bounded PID allocator
+ *
+ * (C) 2002 William Irwin, IBM
+ * (C) 2002 Ingo Molnar, Red Hat
+ *
+ * pid-structures are backing objects for tasks sharing a given ID to chain
+ * against. There is very little to them aside from hashing them and
+ * parking tasks using given ID's on a list.
+ *
+ * The hash is always changed with the tasklist_lock write-acquired,
+ * and the hash is only accessed with the tasklist_lock at least
+ * read-acquired, so there's no additional SMP locking needed here.
+ *
+ * We have a list of bitmap pages, which bitmaps represent the PID space.
+ * Allocating and freeing PIDs is completely lockless. The worst-case
+ * allocation scenario when all but one out of 1 million PIDs possible are
+ * allocated already: the scanning of 32 list entries and at most PAGE_SIZE
+ * bytes. The typical fastpath is a single successful setbit. Freeing is O(1).
+ */
+
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+
+#define PIDHASH_SIZE 4096
+#define pid_hashfn(nr) ((nr >> 8) ^ nr) & (PIDHASH_SIZE - 1)
+static struct list_head pid_hash[PIDTYPE_MAX][PIDHASH_SIZE];
+
+int pid_max = PID_MAX_DEFAULT;
+int last_pid;
+
+#define RESERVED_PIDS		300
+
+#define PIDMAP_ENTRIES		(PID_MAX_LIMIT/PAGE_SIZE/8)
+#define BITS_PER_PAGE		(PAGE_SIZE*8)
+#define BITS_PER_PAGE_MASK	(BITS_PER_PAGE-1)
+
+/*
+ * PID-map pages start out as NULL, they get allocated upon
+ * first use and are never deallocated. This way a low pid_max
+ * value does not cause lots of bitmaps to be allocated, but
+ * the scheme scales to up to 4 million PIDs, runtime.
+ */
+typedef struct pidmap {
+	atomic_t nr_free;
+	void *page;
+} pidmap_t;
+
+static pidmap_t pidmap_array[PIDMAP_ENTRIES] =
+	 { [ 0 ... PIDMAP_ENTRIES-1 ] = { ATOMIC_INIT(BITS_PER_PAGE), NULL } };
+
+static pidmap_t *map_limit = pidmap_array + PIDMAP_ENTRIES;
+
+inline void free_pidmap(int pid)
+{
+	pidmap_t *map = pidmap_array + pid / BITS_PER_PAGE;
+	int offset = pid & BITS_PER_PAGE_MASK;
+
+	clear_bit(offset, map->page);
+	atomic_inc(&map->nr_free);
+}
+
+/*
+ * Here we search for the next map that has free bits left.
+ * Normally the next map has free PIDs.
+ */
+static inline pidmap_t *next_free_map(pidmap_t *map, int *max_steps)
+{
+	while (--*max_steps) {
+		if (++map == map_limit)
+			map = pidmap_array;
+		if (unlikely(!map->page)) {
+			unsigned long page = get_zeroed_page(GFP_KERNEL);
+			/*
+			 * Free the page if someone raced with us
+			 * installing it:
+			 */
+			if (cmpxchg(&map->page, NULL, (void *) page))
+				free_page(page);
+			if (!map->page)
+				break;
+		}
+		if (atomic_read(&map->nr_free))
+			return map;
+	}
+	return NULL;
+}
+
+int alloc_pidmap(void)
+{
+	int pid, offset, max_steps = PIDMAP_ENTRIES + 1;
+	pidmap_t *map;
+
+	pid = last_pid + 1;
+	if (pid >= pid_max)
+		pid = RESERVED_PIDS;
+
+	offset = pid & BITS_PER_PAGE_MASK;
+	map = pidmap_array + pid / BITS_PER_PAGE;
+
+	if (likely(map->page && !test_and_set_bit(offset, map->page))) {
+		/*
+		 * There is a small window for last_pid updates to race,
+		 * but in that case the next allocation will go into the
+		 * slowpath and that fixes things up.
+		 */
+return_pid:
+		atomic_dec(&map->nr_free);
+		last_pid = pid;
+		return pid;
+	}
+	
+	if (!offset || !atomic_read(&map->nr_free)) {
+next_map:
+		map = next_free_map(map, &max_steps);
+		if (!map)
+			goto failure;
+		offset = 0;
+	}
+	/*
+	 * Find the next zero bit:
+	 */
+scan_more:
+	offset = find_next_zero_bit(map->page, BITS_PER_PAGE, offset);
+	if (offset == BITS_PER_PAGE)
+		goto next_map;
+	if (test_and_set_bit(offset, map->page))
+		goto scan_more;
+
+	/* we got the PID: */
+	pid = (map - pidmap_array) * BITS_PER_PAGE + offset;
+	goto return_pid;
+
+failure:
+	return -1;
+}
+
+inline struct pid *find_pid(enum pid_type type, int nr)
+{
+	struct list_head *elem, *bucket = &pid_hash[type][pid_hashfn(nr)];
+	struct pid *pid;
+
+	list_for_each_noprefetch(elem, bucket) {
+		pid = list_entry(elem, struct pid, hash_chain);
+		if (pid->nr == nr)
+			return pid;
+	}
+	return NULL;
+}
+
+int attach_pid(task_t *task, enum pid_type type, int nr)
+{
+	struct pid *pid = find_pid(type, nr);
+
+	if (pid)
+		atomic_inc(&pid->count);
+	else {
+		pid = &task->pids[type].pid;
+		pid->nr = nr;
+		atomic_set(&pid->count, 1);
+		INIT_LIST_HEAD(&pid->task_list);
+		pid->task = task;
+		get_task_struct(task);
+		list_add(&pid->hash_chain, &pid_hash[type][pid_hashfn(nr)]);
+	}
+	list_add(&task->pids[type].pid_chain, &pid->task_list);
+	task->pids[type].pidptr = pid;
+
+	return 0;
+}
+
+void detach_pid(task_t *task, enum pid_type type)
+{
+	struct pid_link *link = task->pids + type;
+	struct pid *pid = link->pidptr;
+	int nr;
+
+	list_del(&link->pid_chain);
+	if (!atomic_dec_and_test(&pid->count))
+		return;
+
+	nr = pid->nr;
+	list_del(&pid->hash_chain);
+	put_task_struct(pid->task);
+
+	for (type = 0; type < PIDTYPE_MAX; ++type)
+		if (find_pid(type, nr))
+			return;
+	free_pidmap(nr);
+}
+
+extern task_t *find_task_by_pid(int nr)
+{
+	struct pid *pid = find_pid(PIDTYPE_PID, nr);
+
+	if (!pid)
+		return NULL;
+	return pid_task(pid->task_list.next, PIDTYPE_PID);
+}
+
+void __init pidhash_init(void)
+{
+	int i, j;
+
+	/*
+	 * Allocate PID 0, and hash it via all PID types:
+	 */
+	pidmap_array->page = (void *)get_zeroed_page(GFP_KERNEL);
+	set_bit(0, pidmap_array->page);
+	atomic_dec(&pidmap_array->nr_free);
+
+	for (i = 0; i < PIDTYPE_MAX; i++) {
+		for (j = 0; j < PIDHASH_SIZE; j++)
+			INIT_LIST_HEAD(&pid_hash[i][j]);
+		attach_pid(current, i, 0);
+	}
+}
diff -Nru a/kernel/printk.c b/kernel/printk.c
--- a/kernel/printk.c	Fri Sep 20 08:20:48 2002
+++ b/kernel/printk.c	Fri Sep 20 08:20:48 2002
@@ -525,11 +525,11 @@
 {
 	unsigned long flags;
 	unsigned long _con_start, _log_end;
-	unsigned long must_wake_klogd = 0;
+	unsigned long wake_klogd = 0;
 
 	for ( ; ; ) {
 		spin_lock_irqsave(&logbuf_lock, flags);
-		must_wake_klogd |= log_start - log_end;
+		wake_klogd |= log_start - log_end;
 		if (con_start == log_end)
 			break;			/* Nothing to print */
 		_con_start = con_start;
@@ -541,7 +541,7 @@
 	console_may_schedule = 0;
 	up(&console_sem);
 	spin_unlock_irqrestore(&logbuf_lock, flags);
-	if (must_wake_klogd && !oops_in_progress)
+	if (wake_klogd && !oops_in_progress && waitqueue_active(&log_wait))
 		wake_up_interruptible(&log_wait);
 }
 
diff -Nru a/kernel/signal.c b/kernel/signal.c
--- a/kernel/signal.c	Fri Sep 20 08:20:44 2002
+++ b/kernel/signal.c	Fri Sep 20 08:20:44 2002
@@ -71,6 +71,14 @@
 |  SIGPWR            |  load-balance    |  kill-all      |
 |  SIGRTMIN-SIGRTMAX |  load-balance    |  kill-all      |
 ----------------------------------------------------------
+
+    non-POSIX signal thread group behavior:
+
+----------------------------------------------------------
+|                    |  userspace       |  kernel        |
+----------------------------------------------------------
+|  SIGEMT            |  specific        |  kill-all+core |
+----------------------------------------------------------
 */
 
 /* Some systems do not have a SIGSTKFLT and the kernel never
@@ -82,12 +90,19 @@
 #define M_SIGSTKFLT	0
 #endif
 
+#ifdef SIGEMT
+#define M_SIGEMT	M(SIGEMT)
+#else
+#define M_SIGEMT	0
+#endif
+
 #define M(sig) (1UL << (sig))
 
 #define SIG_USER_SPECIFIC_MASK (\
 	M(SIGILL)    |  M(SIGTRAP)   |  M(SIGABRT)   |  M(SIGBUS)    | \
 	M(SIGFPE)    |  M(SIGSEGV)   |  M(SIGPIPE)   |  M(SIGXFSZ)   | \
-	M(SIGPROF)   |  M(SIGSYS)    |  M_SIGSTKFLT |  M(SIGCONT)   )
+	M(SIGPROF)   |  M(SIGSYS)    |  M_SIGSTKFLT  |  M(SIGCONT)   | \
+        M_SIGEMT )
 
 #define SIG_USER_LOAD_BALANCE_MASK (\
         M(SIGHUP)    |  M(SIGINT)    |  M(SIGQUIT)   |  M(SIGUSR1)   | \
@@ -105,7 +120,8 @@
 	M(SIGPIPE)   |  M(SIGALRM)   |  M(SIGTERM)   |  M(SIGXCPU)   | \
 	M(SIGXFSZ)   |  M(SIGVTALRM) |  M(SIGPROF)   |  M(SIGPOLL)   | \
 	M(SIGSYS)    |  M_SIGSTKFLT  |  M(SIGPWR)    |  M(SIGCONT)   | \
-        M(SIGSTOP)   |  M(SIGTSTP)   |  M(SIGTTIN)   |  M(SIGTTOU)   )
+        M(SIGSTOP)   |  M(SIGTSTP)   |  M(SIGTTIN)   |  M(SIGTTOU)   | \
+        M_SIGEMT )
 
 #define SIG_KERNEL_ONLY_MASK (\
 	M(SIGKILL)   |  M(SIGSTOP)                                   )
@@ -113,7 +129,7 @@
 #define SIG_KERNEL_COREDUMP_MASK (\
         M(SIGQUIT)   |  M(SIGILL)    |  M(SIGTRAP)   |  M(SIGABRT)   | \
         M(SIGFPE)    |  M(SIGSEGV)   |  M(SIGBUS)    |  M(SIGSYS)    | \
-        M(SIGXCPU)   |  M(SIGXFSZ)                                   )
+        M(SIGXCPU)   |  M(SIGXFSZ)   |  M_SIGEMT                     )
 
 #define T(sig, mask) \
 	((1UL << (sig)) & mask)
@@ -943,18 +959,18 @@
 
 int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp)
 {
-	int retval = -EINVAL;
-	if (pgrp > 0) {
-		struct task_struct *p;
-
-		retval = -ESRCH;
-		for_each_process(p) {
-			if (p->pgrp == pgrp) {
-				int err = send_sig_info(sig, info, p);
-				if (retval)
-					retval = err;
-			}
-		}
+	struct task_struct *p;
+	struct list_head *l;
+	struct pid *pid;
+	int err, retval = -ESRCH;
+
+	if (pgrp <= 0)
+		return -EINVAL;
+
+	for_each_task_pid(pgrp, PIDTYPE_PGID, p, l, pid) {
+		err = send_sig_info(sig, info, p);
+		if (retval)
+			retval = err;
 	}
 	return retval;
 }
@@ -977,28 +993,33 @@
  * the connection is lost.
  */
 
+
 int
-kill_sl_info(int sig, struct siginfo *info, pid_t sess)
+kill_sl_info(int sig, struct siginfo *info, pid_t sid)
 {
-	int retval = -EINVAL;
-	if (sess > 0) {
-		struct task_struct *p;
-
-		retval = -ESRCH;
-		read_lock(&tasklist_lock);
-		for_each_process(p) {
-			if (p->leader && p->session == sess) {
-				int err = send_sig_info(sig, info, p);
-				if (retval)
-					retval = err;
-			}
-		}
-		read_unlock(&tasklist_lock);
+	int err, retval = -EINVAL;
+	struct pid *pid;
+	struct list_head *l;
+	struct task_struct *p;
+
+	if (sid <= 0)
+		goto out;
+
+	retval = -ESRCH;
+	read_lock(&tasklist_lock);
+	for_each_task_pid(sid, PIDTYPE_SID, p, l, pid) {
+		if (!p->leader)
+			continue;
+		err = send_sig_info(sig, info, p);
+		if (retval)
+			retval = err;
 	}
+	read_unlock(&tasklist_lock);
+out:
 	return retval;
 }
 
-inline int
+int
 kill_proc_info(int sig, struct siginfo *info, pid_t pid)
 {
 	int error;
diff -Nru a/kernel/suspend.c b/kernel/suspend.c
--- a/kernel/suspend.c	Fri Sep 20 08:20:43 2002
+++ b/kernel/suspend.c	Fri Sep 20 08:20:43 2002
@@ -471,10 +471,12 @@
 	int nr_copy_pages = 0;
 	int pfn;
 	struct page *page;
-	
+
+#ifndef CONFIG_DISCONTIGMEM	
 	if (max_mapnr != num_physpages)
 		panic("mapnr is not expected");
-	for (pfn = 0; pfn < max_mapnr; pfn++) {
+#endif
+	for (pfn = 0; pfn < num_physpages; pfn++) {
 		page = pfn_to_page(pfn);
 		if (PageHighMem(page))
 			panic("Swsusp not supported on highmem boxes. Send 1GB of RAM to <pavel@ucw.cz> and try again ;-).");
@@ -514,19 +516,20 @@
 
 static void free_suspend_pagedir(unsigned long this_pagedir)
 {
-	struct page *page = mem_map;
-	int i;
+	struct page *page;
+	int pfn;
 	unsigned long this_pagedir_end = this_pagedir +
 		(PAGE_SIZE << pagedir_order);
 
-	for(i=0; i < num_physpages; i++, page++) {
+	for(pfn = 0; pfn < num_physpages; pfn++) {
+		page = pfn_to_page(pfn);
 		if (!TestClearPageNosave(page))
 			continue;
 
-		if (ADDRESS(i) >= this_pagedir && ADDRESS(i) < this_pagedir_end)
+		if (ADDRESS(pfn) >= this_pagedir && ADDRESS(pfn) < this_pagedir_end)
 			continue; /* old pagedir gets freed in one */
 		
-		free_page(ADDRESS(i));
+		free_page(ADDRESS(pfn));
 	}
 	free_pages(this_pagedir, pagedir_order);
 }
diff -Nru a/kernel/sys.c b/kernel/sys.c
--- a/kernel/sys.c	Fri Sep 20 08:20:41 2002
+++ b/kernel/sys.c	Fri Sep 20 08:20:41 2002
@@ -203,35 +203,34 @@
 cond_syscall(sys_quotactl)
 cond_syscall(sys_acct)
 
-static int proc_sel(struct task_struct *p, int which, int who)
+static int set_one_prio(struct task_struct *p, int niceval, int error)
 {
-	if(p->pid)
-	{
-		switch (which) {
-			case PRIO_PROCESS:
-				if (!who && p == current)
-					return 1;
-				return(p->pid == who);
-			case PRIO_PGRP:
-				if (!who)
-					who = current->pgrp;
-				return(p->pgrp == who);
-			case PRIO_USER:
-				if (!who)
-					who = current->uid;
-				return(p->uid == who);
-		}
+	if (p->uid != current->euid &&
+		p->uid != current->uid && !capable(CAP_SYS_NICE)) {
+		error = -EPERM;
+		goto out;
 	}
-	return 0;
+
+	if (error == -ESRCH)
+		error = 0;
+	if (niceval < task_nice(p) && !capable(CAP_SYS_NICE))
+		error = -EACCES;
+	else
+		set_user_nice(p, niceval);
+out:
+	return error;
 }
 
 asmlinkage long sys_setpriority(int which, int who, int niceval)
 {
 	struct task_struct *g, *p;
-	int error;
+	struct user_struct *user;
+	struct pid *pid;
+	struct list_head *l;
+	int error = -EINVAL;
 
 	if (which > 2 || which < 0)
-		return -EINVAL;
+		goto out;
 
 	/* normalize: avoid signed division (rounding problems) */
 	error = -ESRCH;
@@ -241,31 +240,38 @@
 		niceval = 19;
 
 	read_lock(&tasklist_lock);
-	do_each_thread(g, p) {
-		int no_nice;
-		if (!proc_sel(p, which, who))
-			continue;
-		if (p->uid != current->euid &&
-			p->uid != current->uid && !capable(CAP_SYS_NICE)) {
-			error = -EPERM;
-			continue;
-		}
-		if (error == -ESRCH)
-			error = 0;
-		if (niceval < task_nice(p) && !capable(CAP_SYS_NICE)) {
-			error = -EACCES;
-			continue;
-		}
-		no_nice = security_ops->task_setnice(p, niceval);
-		if (no_nice) {
-			error = no_nice;
-			continue;
-		}
-		set_user_nice(p, niceval);
-	} while_each_thread(g, p);
-
+	switch (which) {
+		case PRIO_PROCESS:
+			if (!who)
+				who = current->pid;
+			p = find_task_by_pid(who);
+			if (p)
+				error = set_one_prio(p, niceval, error);
+			break;
+		case PRIO_PGRP:
+			if (!who)
+				who = current->pgrp;
+			for_each_task_pid(who, PIDTYPE_PGID, p, l, pid)
+				error = set_one_prio(p, niceval, error);
+			break;
+		case PRIO_USER:
+			if (!who)
+				user = current->user;
+			else
+				user = find_user(who);
+
+			if (!user)
+				goto out_unlock;
+
+			do_each_thread(g, p)
+				if (p->uid == who)
+					error = set_one_prio(p, niceval, error);
+			while_each_thread(g, p);
+			break;
+	}
+out_unlock:
 	read_unlock(&tasklist_lock);
-
+out:
 	return error;
 }
 
@@ -278,20 +284,54 @@
 asmlinkage long sys_getpriority(int which, int who)
 {
 	struct task_struct *g, *p;
-	long retval = -ESRCH;
+	struct list_head *l;
+	struct pid *pid;
+	struct user_struct *user;
+	long niceval, retval = -ESRCH;
 
 	if (which > 2 || which < 0)
 		return -EINVAL;
 
 	read_lock(&tasklist_lock);
-	do_each_thread(g, p) {
-		long niceval;
-		if (!proc_sel(p, which, who))
-			continue;
-		niceval = 20 - task_nice(p);
-		if (niceval > retval)
-			retval = niceval;
-	} while_each_thread(g, p);
+	switch (which) {
+		case PRIO_PROCESS:
+			if (!who)
+				who = current->pid;
+			p = find_task_by_pid(who);
+			if (p) {
+				niceval = 20 - task_nice(p);
+				if (niceval > retval)
+					retval = niceval;
+			}
+			break;
+		case PRIO_PGRP:
+			if (!who)
+				who = current->pgrp;
+			for_each_task_pid(who, PIDTYPE_PGID, p, l, pid) {
+				niceval = 20 - task_nice(p);
+				if (niceval > retval)
+					retval = niceval;
+			}
+			break;
+		case PRIO_USER:
+			if (!who)
+				user = current->user;
+			else
+				user = find_user(who);
+
+			if (!user)
+				goto out_unlock;
+
+			do_each_thread(g, p)
+				if (p->uid == who) {
+					niceval = 20 - task_nice(p);
+					if (niceval > retval)
+						retval = niceval;
+				}
+			while_each_thread(g, p);
+			break;
+	}
+out_unlock:
 	read_unlock(&tasklist_lock);
 
 	return retval;
@@ -849,7 +889,7 @@
 
 asmlinkage long sys_setpgid(pid_t pid, pid_t pgid)
 {
-	struct task_struct * p;
+	struct task_struct *p;
 	int err = -EINVAL;
 
 	if (!pid)
@@ -862,12 +902,15 @@
 	/* From this point forward we keep holding onto the tasklist lock
 	 * so that our parent does not change from under us. -DaveM
 	 */
-	read_lock(&tasklist_lock);
+	write_lock_irq(&tasklist_lock);
 
 	err = -ESRCH;
 	p = find_task_by_pid(pid);
 	if (!p)
 		goto out;
+	err = -EINVAL;
+	if (!thread_group_leader(p))
+		goto out;
 
 	if (p->parent == current || p->real_parent == current) {
 		err = -EPERM;
@@ -882,25 +925,26 @@
 	if (p->leader)
 		goto out;
 	if (pgid != pid) {
-		struct task_struct *g, *tmp;
-		do_each_thread(g, tmp) {
-			if (tmp->pgrp == pgid &&
-			    tmp->session == current->session)
+		struct task_struct *p;
+		struct pid *pid;
+		struct list_head *l;
+
+		for_each_task_pid(pgid, PIDTYPE_PGID, p, l, pid)
+			if (p->session == current->session)
 				goto ok_pgid;
-		} while_each_thread(g, tmp);
 		goto out;
 	}
 
 ok_pgid:
-	err = security_ops->task_setpgid(p, pgid);
-	if (err)
-		goto out;
-
-	p->pgrp = pgid;
+	if (p->pgrp != pgid) {
+		detach_pid(p, PIDTYPE_PGID);
+		p->pgrp = pgid;
+		attach_pid(p, PIDTYPE_PGID, pgid);
+	}
 	err = 0;
 out:
 	/* All paths lead to here, thus we are safe. -DaveM */
-	read_unlock(&tasklist_lock);
+	write_unlock_irq(&tasklist_lock);
 	return err;
 }
 
@@ -956,22 +1000,34 @@
 
 asmlinkage long sys_setsid(void)
 {
-	struct task_struct *g, *p;
+	struct pid *pid;
 	int err = -EPERM;
 
-	read_lock(&tasklist_lock);
-	do_each_thread(g, p)
-		if (p->pgrp == current->pid)
-			goto out;
-	while_each_thread(g, p);
+	if (!thread_group_leader(current))
+		return -EINVAL;
+
+	write_lock_irq(&tasklist_lock);
+
+	pid = find_pid(PIDTYPE_PGID, current->pid);
+	if (pid)
+		goto out;
 
 	current->leader = 1;
-	current->session = current->pgrp = current->pid;
+	if (current->session != current->pid) {
+		detach_pid(current, PIDTYPE_SID);
+		current->session = current->pid;
+		attach_pid(current, PIDTYPE_SID, current->pid);
+	}
+	if (current->pgrp != current->pid) {
+		detach_pid(current, PIDTYPE_PGID);
+		current->pgrp = current->pid;
+		attach_pid(current, PIDTYPE_PGID, current->pid);
+	}
 	current->tty = NULL;
 	current->tty_old_pgrp = 0;
 	err = current->pgrp;
 out:
-	read_unlock(&tasklist_lock);
+	write_unlock_irq(&tasklist_lock);
 	return err;
 }
 
diff -Nru a/kernel/sysctl.c b/kernel/sysctl.c
--- a/kernel/sysctl.c	Fri Sep 20 08:20:41 2002
+++ b/kernel/sysctl.c	Fri Sep 20 08:20:41 2002
@@ -99,8 +99,8 @@
 #endif
 
 #ifdef CONFIG_HUGETLB_PAGE
-extern	int htlbpage_max;
-extern	int	set_hugetlb_mem_size(int);
+extern int htlbpage_max;
+extern int set_hugetlb_mem_size(int);
 #endif
 
 static int parse_table(int *, int, void *, size_t *, void *, size_t,
@@ -263,10 +263,6 @@
 #endif
 	{KERN_PIDMAX, "pid_max", &pid_max, sizeof (int),
 	 0600, NULL, &proc_dointvec},
-#ifdef CONFIG_HUGETLB_PAGE
-	 {KERN_HUGETLB_PAGE_NUM, "numhugepages", &htlbpage_max, sizeof(int), 0644, NULL, 
-	  &proc_dointvec},
-#endif
 	{0}
 };
 
@@ -292,9 +288,6 @@
 	{VM_DIRTY_ASYNC, "dirty_async_ratio", &dirty_async_ratio,
 	 sizeof(dirty_async_ratio), 0644, NULL, &proc_dointvec_minmax,
 	 &sysctl_intvec, NULL, &zero, &one_hundred },
-	{VM_DIRTY_SYNC, "dirty_sync_ratio", &dirty_sync_ratio,
-	 sizeof(dirty_sync_ratio), 0644, NULL, &proc_dointvec_minmax,
-	 &sysctl_intvec, NULL, &zero, &one_hundred },
 	{VM_DIRTY_WB_CS, "dirty_writeback_centisecs",
 	 &dirty_writeback_centisecs, sizeof(dirty_writeback_centisecs), 0644,
 	 NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL,
@@ -317,6 +310,10 @@
 	{ VM_NR_PDFLUSH_THREADS, "nr_pdflush_threads",
 	  &nr_pdflush_threads, sizeof nr_pdflush_threads,
 	  0444 /* read-only*/, NULL, &proc_dointvec},
+#ifdef CONFIG_HUGETLB_PAGE
+	 {VM_HUGETLB_PAGES, "nr_hugepages", &htlbpage_max, sizeof(int), 0644, NULL, 
+	  &proc_dointvec},
+#endif
 	{0}
 };
 
diff -Nru a/kernel/user.c b/kernel/user.c
--- a/kernel/user.c	Fri Sep 20 08:20:44 2002
+++ b/kernel/user.c	Fri Sep 20 08:20:44 2002
@@ -64,6 +64,11 @@
 	return NULL;
 }
 
+struct user_struct *find_user(uid_t uid)
+{
+	return uid_hash_find(uid, uidhashentry(uid));
+}
+
 void free_uid(struct user_struct *up)
 {
 	if (up && atomic_dec_and_lock(&up->__count, &uidhash_lock)) {
diff -Nru a/mm/Makefile b/mm/Makefile
--- a/mm/Makefile	Fri Sep 20 08:20:47 2002
+++ b/mm/Makefile	Fri Sep 20 08:20:47 2002
@@ -1,13 +1,6 @@
 #
 # Makefile for the linux memory manager.
 #
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definition is now in the main makefile...
-
-O_TARGET := mm.o
 
 export-objs := shmem.o filemap.o mempool.o page_alloc.o \
 		page-writeback.o
@@ -16,6 +9,6 @@
 	    vmalloc.o slab.o bootmem.o swap.o vmscan.o page_io.o \
 	    page_alloc.o swap_state.o swapfile.o numa.o oom_kill.o \
 	    shmem.o highmem.o mempool.o msync.o mincore.o readahead.o \
-	    pdflush.o page-writeback.o rmap.o
+	    pdflush.o page-writeback.o rmap.o madvise.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/mm/filemap.c b/mm/filemap.c
--- a/mm/filemap.c	Fri Sep 20 08:20:44 2002
+++ b/mm/filemap.c	Fri Sep 20 08:20:44 2002
@@ -487,9 +487,13 @@
 int filemap_fdatawrite(struct address_space *mapping)
 {
 	int ret;
+	struct writeback_control wbc = {
+		.sync_mode = WB_SYNC_ALL,
+		.nr_to_write = mapping->nrpages * 2,
+	};
 
 	current->flags |= PF_SYNC;
-	ret = do_writepages(mapping, NULL);
+	ret = do_writepages(mapping, &wbc);
 	current->flags &= ~PF_SYNC;
 	return ret;
 }
@@ -1130,10 +1134,26 @@
 	struct file *filp = iocb->ki_filp;
 	ssize_t retval;
 	unsigned long seg;
-	size_t count = iov_length(iov, nr_segs);
+	size_t count;
 
-	if ((ssize_t) count < 0)
-		return -EINVAL;
+	count = 0;
+	for (seg = 0; seg < nr_segs; seg++) {
+		const struct iovec *iv = &iov[seg];
+
+		/*
+		 * If any segment has a negative length, or the cumulative
+		 * length ever wraps negative then return -EINVAL.
+		 */
+		count += iv->iov_len;
+		if (unlikely((ssize_t)(count|iv->iov_len) < 0))
+			return -EINVAL;
+		if (access_ok(VERIFY_WRITE, iv->iov_base, iv->iov_len))
+			continue;
+		if (seg == 0)
+			return -EFAULT;
+		nr_segs = seg;
+		break;
+	}
 
 	/* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
 	if (filp->f_flags & O_DIRECT) {
@@ -1162,11 +1182,6 @@
 		goto out;
 	}
 
-	for (seg = 0; seg < nr_segs; seg++) {
-		if (!access_ok(VERIFY_WRITE,iov[seg].iov_base,iov[seg].iov_len))
-			return -EFAULT;
-	}
-
 	retval = 0;
 	if (count) {
 		for (seg = 0; seg < nr_segs; seg++) {
@@ -1482,337 +1497,7 @@
 	return 0;
 }
 
-static inline void setup_read_behavior(struct vm_area_struct * vma,
-	int behavior)
-{
-	VM_ClearReadHint(vma);
-	switch(behavior) {
-		case MADV_SEQUENTIAL:
-			vma->vm_flags |= VM_SEQ_READ;
-			break;
-		case MADV_RANDOM:
-			vma->vm_flags |= VM_RAND_READ;
-			break;
-		default:
-			break;
-	}
-	return;
-}
-
-static long madvise_fixup_start(struct vm_area_struct * vma,
-	unsigned long end, int behavior)
-{
-	struct vm_area_struct * n;
-	struct mm_struct * mm = vma->vm_mm;
-
-	n = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
-	if (!n)
-		return -EAGAIN;
-	*n = *vma;
-	n->vm_end = end;
-	setup_read_behavior(n, behavior);
-	n->vm_raend = 0;
-	if (n->vm_file)
-		get_file(n->vm_file);
-	if (n->vm_ops && n->vm_ops->open)
-		n->vm_ops->open(n);
-	vma->vm_pgoff += (end - vma->vm_start) >> PAGE_SHIFT;
-	lock_vma_mappings(vma);
-	spin_lock(&mm->page_table_lock);
-	vma->vm_start = end;
-	__insert_vm_struct(mm, n);
-	spin_unlock(&mm->page_table_lock);
-	unlock_vma_mappings(vma);
-	return 0;
-}
-
-static long madvise_fixup_end(struct vm_area_struct * vma,
-	unsigned long start, int behavior)
-{
-	struct vm_area_struct * n;
-	struct mm_struct * mm = vma->vm_mm;
-
-	n = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
-	if (!n)
-		return -EAGAIN;
-	*n = *vma;
-	n->vm_start = start;
-	n->vm_pgoff += (n->vm_start - vma->vm_start) >> PAGE_SHIFT;
-	setup_read_behavior(n, behavior);
-	n->vm_raend = 0;
-	if (n->vm_file)
-		get_file(n->vm_file);
-	if (n->vm_ops && n->vm_ops->open)
-		n->vm_ops->open(n);
-	lock_vma_mappings(vma);
-	spin_lock(&mm->page_table_lock);
-	vma->vm_end = start;
-	__insert_vm_struct(mm, n);
-	spin_unlock(&mm->page_table_lock);
-	unlock_vma_mappings(vma);
-	return 0;
-}
-
-static long madvise_fixup_middle(struct vm_area_struct * vma,
-	unsigned long start, unsigned long end, int behavior)
-{
-	struct vm_area_struct * left, * right;
-	struct mm_struct * mm = vma->vm_mm;
-
-	left = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
-	if (!left)
-		return -EAGAIN;
-	right = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
-	if (!right) {
-		kmem_cache_free(vm_area_cachep, left);
-		return -EAGAIN;
-	}
-	*left = *vma;
-	*right = *vma;
-	left->vm_end = start;
-	right->vm_start = end;
-	right->vm_pgoff += (right->vm_start - left->vm_start) >> PAGE_SHIFT;
-	left->vm_raend = 0;
-	right->vm_raend = 0;
-	if (vma->vm_file)
-		atomic_add(2, &vma->vm_file->f_count);
-
-	if (vma->vm_ops && vma->vm_ops->open) {
-		vma->vm_ops->open(left);
-		vma->vm_ops->open(right);
-	}
-	vma->vm_pgoff += (start - vma->vm_start) >> PAGE_SHIFT;
-	vma->vm_raend = 0;
-	lock_vma_mappings(vma);
-	spin_lock(&mm->page_table_lock);
-	vma->vm_start = start;
-	vma->vm_end = end;
-	setup_read_behavior(vma, behavior);
-	__insert_vm_struct(mm, left);
-	__insert_vm_struct(mm, right);
-	spin_unlock(&mm->page_table_lock);
-	unlock_vma_mappings(vma);
-	return 0;
-}
-
-/*
- * We can potentially split a vm area into separate
- * areas, each area with its own behavior.
- */
-static long madvise_behavior(struct vm_area_struct * vma,
-	unsigned long start, unsigned long end, int behavior)
-{
-	int error = 0;
-
-	/* This caps the number of vma's this process can own */
-	if (vma->vm_mm->map_count > MAX_MAP_COUNT)
-		return -ENOMEM;
-
-	if (start == vma->vm_start) {
-		if (end == vma->vm_end) {
-			setup_read_behavior(vma, behavior);
-			vma->vm_raend = 0;
-		} else
-			error = madvise_fixup_start(vma, end, behavior);
-	} else {
-		if (end == vma->vm_end)
-			error = madvise_fixup_end(vma, start, behavior);
-		else
-			error = madvise_fixup_middle(vma, start, end, behavior);
-	}
-
-	return error;
-}
-
-/*
- * Schedule all required I/O operations, then run the disk queue
- * to make sure they are started.  Do not wait for completion.
- */
-static long madvise_willneed(struct vm_area_struct * vma,
-				unsigned long start, unsigned long end)
-{
-	long error = -EBADF;
-	struct file * file;
-	unsigned long size, rlim_rss;
-
-	/* Doesn't work if there's no mapped file. */
-	if (!vma->vm_file)
-		return error;
-	file = vma->vm_file;
-	size = (file->f_dentry->d_inode->i_size + PAGE_CACHE_SIZE - 1) >>
-							PAGE_CACHE_SHIFT;
-
-	start = ((start - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
-	if (end > vma->vm_end)
-		end = vma->vm_end;
-	end = ((end - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
-
-	/* Make sure this doesn't exceed the process's max rss. */
-	error = -EIO;
-	rlim_rss = current->rlim ?  current->rlim[RLIMIT_RSS].rlim_cur :
-				LONG_MAX; /* default: see resource.h */
-	if ((vma->vm_mm->rss + (end - start)) > rlim_rss)
-		return error;
-
-	do_page_cache_readahead(file, start, end - start);
-	return 0;
-}
-
-/*
- * Application no longer needs these pages.  If the pages are dirty,
- * it's OK to just throw them away.  The app will be more careful about
- * data it wants to keep.  Be sure to free swap resources too.  The
- * zap_page_range call sets things up for refill_inactive to actually free
- * these pages later if no one else has touched them in the meantime,
- * although we could add these pages to a global reuse list for
- * refill_inactive to pick up before reclaiming other pages.
- *
- * NB: This interface discards data rather than pushes it out to swap,
- * as some implementations do.  This has performance implications for
- * applications like large transactional databases which want to discard
- * pages in anonymous maps after committing to backing store the data
- * that was kept in them.  There is no reason to write this data out to
- * the swap area if the application is discarding it.
- *
- * An interface that causes the system to free clean pages and flush
- * dirty pages is already available as msync(MS_INVALIDATE).
- */
-static long madvise_dontneed(struct vm_area_struct * vma,
-	unsigned long start, unsigned long end)
-{
-	if (vma->vm_flags & VM_LOCKED)
-		return -EINVAL;
-
-	zap_page_range(vma, start, end - start);
-	return 0;
-}
-
-static long madvise_vma(struct vm_area_struct * vma, unsigned long start,
-	unsigned long end, int behavior)
-{
-	long error = -EBADF;
-
-	switch (behavior) {
-	case MADV_NORMAL:
-	case MADV_SEQUENTIAL:
-	case MADV_RANDOM:
-		error = madvise_behavior(vma, start, end, behavior);
-		break;
-
-	case MADV_WILLNEED:
-		error = madvise_willneed(vma, start, end);
-		break;
-
-	case MADV_DONTNEED:
-		error = madvise_dontneed(vma, start, end);
-		break;
-
-	default:
-		error = -EINVAL;
-		break;
-	}
-		
-	return error;
-}
-
-/*
- * The madvise(2) system call.
- *
- * Applications can use madvise() to advise the kernel how it should
- * handle paging I/O in this VM area.  The idea is to help the kernel
- * use appropriate read-ahead and caching techniques.  The information
- * provided is advisory only, and can be safely disregarded by the
- * kernel without affecting the correct operation of the application.
- *
- * behavior values:
- *  MADV_NORMAL - the default behavior is to read clusters.  This
- *		results in some read-ahead and read-behind.
- *  MADV_RANDOM - the system should read the minimum amount of data
- *		on any access, since it is unlikely that the appli-
- *		cation will need more than what it asks for.
- *  MADV_SEQUENTIAL - pages in the given range will probably be accessed
- *		once, so they can be aggressively read ahead, and
- *		can be freed soon after they are accessed.
- *  MADV_WILLNEED - the application is notifying the system to read
- *		some pages ahead.
- *  MADV_DONTNEED - the application is finished with the given range,
- *		so the kernel can free resources associated with it.
- *
- * return values:
- *  zero    - success
- *  -EINVAL - start + len < 0, start is not page-aligned,
- *		"behavior" is not a valid value, or application
- *		is attempting to release locked or shared pages.
- *  -ENOMEM - addresses in the specified range are not currently
- *		mapped, or are outside the AS of the process.
- *  -EIO    - an I/O error occurred while paging in data.
- *  -EBADF  - map exists, but area maps something that isn't a file.
- *  -EAGAIN - a kernel resource was temporarily unavailable.
- */
-asmlinkage long sys_madvise(unsigned long start, size_t len, int behavior)
-{
-	unsigned long end;
-	struct vm_area_struct * vma;
-	int unmapped_error = 0;
-	int error = -EINVAL;
-
-	down_write(&current->mm->mmap_sem);
-
-	if (start & ~PAGE_MASK)
-		goto out;
-	len = (len + ~PAGE_MASK) & PAGE_MASK;
-	end = start + len;
-	if (end < start)
-		goto out;
-
-	error = 0;
-	if (end == start)
-		goto out;
-
-	/*
-	 * If the interval [start,end) covers some unmapped address
-	 * ranges, just ignore them, but return -ENOMEM at the end.
-	 */
-	vma = find_vma(current->mm, start);
-	for (;;) {
-		/* Still start < end. */
-		error = -ENOMEM;
-		if (!vma)
-			goto out;
-
-		/* Here start < vma->vm_end. */
-		if (start < vma->vm_start) {
-			unmapped_error = -ENOMEM;
-			start = vma->vm_start;
-		}
-
-		/* Here vma->vm_start <= start < vma->vm_end. */
-		if (end <= vma->vm_end) {
-			if (start < end) {
-				error = madvise_vma(vma, start, end,
-							behavior);
-				if (error)
-					goto out;
-			}
-			error = unmapped_error;
-			goto out;
-		}
-
-		/* Here vma->vm_start <= start < vma->vm_end < end. */
-		error = madvise_vma(vma, start, vma->vm_end, behavior);
-		if (error)
-			goto out;
-		start = vma->vm_end;
-		vma = vma->vm_next;
-	}
-
-out:
-	up_write(&current->mm->mmap_sem);
-	return error;
-}
-
-static inline
-struct page *__read_cache_page(struct address_space *mapping,
+static inline struct page *__read_cache_page(struct address_space *mapping,
 				unsigned long index,
 				int (*filler)(void *,struct page*),
 				void *data)
@@ -1956,6 +1641,63 @@
 	return left;
 }
 
+static inline int
+__filemap_copy_from_user_iovec(char *vaddr, 
+			const struct iovec *iov, size_t base, unsigned bytes)
+{
+	int left = 0;
+
+	while (bytes) {
+		char *buf = iov->iov_base + base;
+		int copy = min(bytes, iov->iov_len - base);
+		base = 0;
+		if ((left = __copy_from_user(vaddr, buf, copy)))
+			break;
+		bytes -= copy;
+		vaddr += copy;
+		iov++;
+	}
+	return left;
+}
+
+static inline int
+filemap_copy_from_user_iovec(struct page *page, unsigned long offset,
+			const struct iovec *iov, size_t base, unsigned bytes)
+{
+	char *kaddr;
+	int left;
+
+	kaddr = kmap_atomic(page, KM_USER0);
+	left = __filemap_copy_from_user_iovec(kaddr + offset, iov, base, bytes);
+	kunmap_atomic(kaddr, KM_USER0);
+	if (left != 0) {
+		kaddr = kmap(page);
+		left = __filemap_copy_from_user_iovec(kaddr + offset, iov, base, bytes);
+		kunmap(page);
+	}
+	return left;
+}
+
+static inline void
+filemap_set_next_iovec(const struct iovec **iovp, size_t *basep, unsigned bytes)
+{
+	const struct iovec *iov = *iovp;
+	size_t base = *basep;
+
+	while (bytes) {
+		int copy = min(bytes, iov->iov_len - base);
+		bytes -= copy;
+		base += copy;
+		if (iov->iov_len == base) {
+			iov++;
+			base = 0;
+		}
+	}
+	*iovp = iov;
+	*basep = base;
+}
+
+
 /*
  * Write to a file through the page cache. 
  *
@@ -1971,8 +1713,8 @@
 {
 	struct address_space * mapping = file->f_dentry->d_inode->i_mapping;
 	struct address_space_operations *a_ops = mapping->a_ops;
-	const size_t ocount = iov_length(iov, nr_segs);
-	size_t count =	ocount;
+	size_t ocount;		/* original count */
+	size_t count;		/* after file limit checks */
 	struct inode 	*inode = mapping->host;
 	unsigned long	limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
 	long		status = 0;
@@ -1984,19 +1726,30 @@
 	unsigned	bytes;
 	time_t		time_now;
 	struct pagevec	lru_pvec;
-	struct iovec	*cur_iov;
-	unsigned	iov_bytes;	/* Cumulative count to the end of the
-					   current iovec */
+	const struct iovec *cur_iov = iov; /* current iovec */
+	unsigned	iov_base = 0;	   /* offset in the current iovec */
 	unsigned long	seg;
 	char		*buf;
 
-	if (unlikely((ssize_t)count < 0))
-		return -EINVAL;
-
+	ocount = 0;
 	for (seg = 0; seg < nr_segs; seg++) {
-		if (!access_ok(VERIFY_READ,iov[seg].iov_base,iov[seg].iov_len))
+		const struct iovec *iv = &iov[seg];
+
+		/*
+		 * If any segment has a negative length, or the cumulative
+		 * length ever wraps negative then return -EINVAL.
+		 */
+		ocount += iv->iov_len;
+		if (unlikely((ssize_t)(ocount|iv->iov_len) < 0))
+			return -EINVAL;
+		if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len))
+			continue;
+		if (seg == 0)
 			return -EFAULT;
+		nr_segs = seg;
+		break;
 	}
+	count = ocount;
 
 	pos = *ppos;
 	if (unlikely(pos < 0))
@@ -2118,9 +1871,7 @@
 		goto out_status;
 	}
 
-	cur_iov = (struct iovec *)iov;
-	iov_bytes = cur_iov->iov_len;
-	buf = cur_iov->iov_base;
+	buf = iov->iov_base;
 	do {
 		unsigned long index;
 		unsigned long offset;
@@ -2131,8 +1882,6 @@
 		bytes = PAGE_CACHE_SIZE - offset;
 		if (bytes > count)
 			bytes = count;
-		if (bytes + written > iov_bytes)
-			bytes = iov_bytes - written;
 
 		/*
 		 * Bring in the user page that we will copy from _first_.
@@ -2160,7 +1909,12 @@
 				vmtruncate(inode, inode->i_size);
 			break;
 		}
-		page_fault = filemap_copy_from_user(page, offset, buf, bytes);
+		if (likely(nr_segs == 1))
+			page_fault = filemap_copy_from_user(page, offset,
+							buf, bytes);
+		else
+			page_fault = filemap_copy_from_user_iovec(page, offset,
+						cur_iov, iov_base, bytes);
 		flush_dcache_page(page);
 		status = a_ops->commit_write(file, page, offset, offset+bytes);
 		if (unlikely(page_fault)) {
@@ -2174,11 +1928,9 @@
 				count -= status;
 				pos += status;
 				buf += status;
-				if (written == iov_bytes && count) {
-					cur_iov++;
-					iov_bytes += cur_iov->iov_len;
-					buf = cur_iov->iov_base;
-				}
+				if (unlikely(nr_segs > 1))
+					filemap_set_next_iovec(&cur_iov,
+							&iov_base, status);
 			}
 		}
 		if (!PageReferenced(page))
diff -Nru a/mm/highmem.c b/mm/highmem.c
--- a/mm/highmem.c	Fri Sep 20 08:20:47 2002
+++ b/mm/highmem.c	Fri Sep 20 08:20:47 2002
@@ -291,7 +291,7 @@
 	}
 }
 
-static inline void bounce_end_io(struct bio *bio, mempool_t *pool)
+static void bounce_end_io(struct bio *bio, mempool_t *pool)
 {
 	struct bio *bio_orig = bio->bi_private;
 	struct bio_vec *bvec, *org_vec;
@@ -314,18 +314,26 @@
 	}
 
 out_eio:
-	bio_orig->bi_end_io(bio_orig);
+	bio_endio(bio_orig, bio_orig->bi_size, 0);
 	bio_put(bio);
 }
 
-static void bounce_end_io_write(struct bio *bio)
+static int bounce_end_io_write(struct bio *bio, unsigned int bytes_done,int err)
 {
+	if (bio->bi_size)
+		return 1;
+
 	bounce_end_io(bio, page_pool);
+	return 0;
 }
 
-static void bounce_end_io_write_isa(struct bio *bio)
+static int bounce_end_io_write_isa(struct bio *bio, unsigned int bytes_done, int err)
 {
+	if (bio->bi_size)
+		return 1;
+
 	bounce_end_io(bio, isa_page_pool);
+	return 0;
 }
 
 static inline void __bounce_end_io_read(struct bio *bio, mempool_t *pool)
@@ -338,14 +346,22 @@
 	bounce_end_io(bio, pool);
 }
 
-static void bounce_end_io_read(struct bio *bio)
+static int bounce_end_io_read(struct bio *bio, unsigned int bytes_done, int err)
 {
+	if (bio->bi_size)
+		return 1;
+
 	__bounce_end_io_read(bio, page_pool);
+	return 0;
 }
 
-static void bounce_end_io_read_isa(struct bio *bio)
+static int bounce_end_io_read_isa(struct bio *bio, unsigned int bytes_done, int err)
 {
-	return __bounce_end_io_read(bio, isa_page_pool);
+	if (bio->bi_size)
+		return 1;
+
+	__bounce_end_io_read(bio, isa_page_pool);
+	return 0;
 }
 
 void blk_queue_bounce(request_queue_t *q, struct bio **bio_orig)
diff -Nru a/mm/madvise.c b/mm/madvise.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/mm/madvise.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,238 @@
+/*
+ *	linux/mm/madvise.c
+ *
+ * Copyright (C) 1999  Linus Torvalds
+ * Copyright (C) 2002  Christoph Hellwig
+ */
+
+#include <linux/mman.h>
+#include <linux/pagemap.h>
+
+
+/*
+ * We can potentially split a vm area into separate
+ * areas, each area with its own behavior.
+ */
+static long madvise_behavior(struct vm_area_struct * vma, unsigned long start,
+			     unsigned long end, int behavior)
+{
+	struct mm_struct * mm = vma->vm_mm;
+	int error;
+
+	if (start != vma->vm_start) {
+		error = split_vma(mm, vma, start, 1);
+		if (error)
+			return -EAGAIN;
+	}
+
+	if (end != vma->vm_end) {
+		error = split_vma(mm, vma, end, 0);
+		if (error)
+			return -EAGAIN;
+	}
+
+	spin_lock(&mm->page_table_lock);
+	vma->vm_raend = 0;
+	VM_ClearReadHint(vma);
+
+	switch (behavior) {
+	case MADV_SEQUENTIAL:
+		vma->vm_flags |= VM_SEQ_READ;
+		break;
+	case MADV_RANDOM:
+		vma->vm_flags |= VM_RAND_READ;
+		break;
+	default:
+		break;
+	}
+	spin_unlock(&mm->page_table_lock);
+
+	return 0;
+}
+
+/*
+ * Schedule all required I/O operations, then run the disk queue
+ * to make sure they are started.  Do not wait for completion.
+ */
+static long madvise_willneed(struct vm_area_struct * vma,
+			     unsigned long start, unsigned long end)
+{
+	long error = -EBADF;
+	struct file * file;
+	unsigned long size, rlim_rss;
+
+	/* Doesn't work if there's no mapped file. */
+	if (!vma->vm_file)
+		return error;
+	file = vma->vm_file;
+	size = (file->f_dentry->d_inode->i_size + PAGE_CACHE_SIZE - 1) >>
+							PAGE_CACHE_SHIFT;
+
+	start = ((start - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
+	if (end > vma->vm_end)
+		end = vma->vm_end;
+	end = ((end - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
+
+	/* Make sure this doesn't exceed the process's max rss. */
+	error = -EIO;
+	rlim_rss = current->rlim ?  current->rlim[RLIMIT_RSS].rlim_cur :
+				LONG_MAX; /* default: see resource.h */
+	if ((vma->vm_mm->rss + (end - start)) > rlim_rss)
+		return error;
+
+	do_page_cache_readahead(file, start, end - start);
+	return 0;
+}
+
+/*
+ * Application no longer needs these pages.  If the pages are dirty,
+ * it's OK to just throw them away.  The app will be more careful about
+ * data it wants to keep.  Be sure to free swap resources too.  The
+ * zap_page_range call sets things up for refill_inactive to actually free
+ * these pages later if no one else has touched them in the meantime,
+ * although we could add these pages to a global reuse list for
+ * refill_inactive to pick up before reclaiming other pages.
+ *
+ * NB: This interface discards data rather than pushes it out to swap,
+ * as some implementations do.  This has performance implications for
+ * applications like large transactional databases which want to discard
+ * pages in anonymous maps after committing to backing store the data
+ * that was kept in them.  There is no reason to write this data out to
+ * the swap area if the application is discarding it.
+ *
+ * An interface that causes the system to free clean pages and flush
+ * dirty pages is already available as msync(MS_INVALIDATE).
+ */
+static long madvise_dontneed(struct vm_area_struct * vma,
+			     unsigned long start, unsigned long end)
+{
+	if (vma->vm_flags & VM_LOCKED)
+		return -EINVAL;
+
+	zap_page_range(vma, start, end - start);
+	return 0;
+}
+
+static long madvise_vma(struct vm_area_struct * vma, unsigned long start,
+			unsigned long end, int behavior)
+{
+	long error = -EBADF;
+
+	switch (behavior) {
+	case MADV_NORMAL:
+	case MADV_SEQUENTIAL:
+	case MADV_RANDOM:
+		error = madvise_behavior(vma, start, end, behavior);
+		break;
+
+	case MADV_WILLNEED:
+		error = madvise_willneed(vma, start, end);
+		break;
+
+	case MADV_DONTNEED:
+		error = madvise_dontneed(vma, start, end);
+		break;
+
+	default:
+		error = -EINVAL;
+		break;
+	}
+		
+	return error;
+}
+
+/*
+ * The madvise(2) system call.
+ *
+ * Applications can use madvise() to advise the kernel how it should
+ * handle paging I/O in this VM area.  The idea is to help the kernel
+ * use appropriate read-ahead and caching techniques.  The information
+ * provided is advisory only, and can be safely disregarded by the
+ * kernel without affecting the correct operation of the application.
+ *
+ * behavior values:
+ *  MADV_NORMAL - the default behavior is to read clusters.  This
+ *		results in some read-ahead and read-behind.
+ *  MADV_RANDOM - the system should read the minimum amount of data
+ *		on any access, since it is unlikely that the appli-
+ *		cation will need more than what it asks for.
+ *  MADV_SEQUENTIAL - pages in the given range will probably be accessed
+ *		once, so they can be aggressively read ahead, and
+ *		can be freed soon after they are accessed.
+ *  MADV_WILLNEED - the application is notifying the system to read
+ *		some pages ahead.
+ *  MADV_DONTNEED - the application is finished with the given range,
+ *		so the kernel can free resources associated with it.
+ *
+ * return values:
+ *  zero    - success
+ *  -EINVAL - start + len < 0, start is not page-aligned,
+ *		"behavior" is not a valid value, or application
+ *		is attempting to release locked or shared pages.
+ *  -ENOMEM - addresses in the specified range are not currently
+ *		mapped, or are outside the AS of the process.
+ *  -EIO    - an I/O error occurred while paging in data.
+ *  -EBADF  - map exists, but area maps something that isn't a file.
+ *  -EAGAIN - a kernel resource was temporarily unavailable.
+ */
+asmlinkage long sys_madvise(unsigned long start, size_t len, int behavior)
+{
+	unsigned long end;
+	struct vm_area_struct * vma;
+	int unmapped_error = 0;
+	int error = -EINVAL;
+
+	down_write(&current->mm->mmap_sem);
+
+	if (start & ~PAGE_MASK)
+		goto out;
+	len = (len + ~PAGE_MASK) & PAGE_MASK;
+	end = start + len;
+	if (end < start)
+		goto out;
+
+	error = 0;
+	if (end == start)
+		goto out;
+
+	/*
+	 * If the interval [start,end) covers some unmapped address
+	 * ranges, just ignore them, but return -ENOMEM at the end.
+	 */
+	vma = find_vma(current->mm, start);
+	for (;;) {
+		/* Still start < end. */
+		error = -ENOMEM;
+		if (!vma)
+			goto out;
+
+		/* Here start < vma->vm_end. */
+		if (start < vma->vm_start) {
+			unmapped_error = -ENOMEM;
+			start = vma->vm_start;
+		}
+
+		/* Here vma->vm_start <= start < vma->vm_end. */
+		if (end <= vma->vm_end) {
+			if (start < end) {
+				error = madvise_vma(vma, start, end,
+							behavior);
+				if (error)
+					goto out;
+			}
+			error = unmapped_error;
+			goto out;
+		}
+
+		/* Here vma->vm_start <= start < vma->vm_end < end. */
+		error = madvise_vma(vma, start, vma->vm_end, behavior);
+		if (error)
+			goto out;
+		start = vma->vm_end;
+		vma = vma->vm_next;
+	}
+
+out:
+	up_write(&current->mm->mmap_sem);
+	return error;
+}
diff -Nru a/mm/memory.c b/mm/memory.c
--- a/mm/memory.c	Fri Sep 20 08:20:46 2002
+++ b/mm/memory.c	Fri Sep 20 08:20:46 2002
@@ -40,7 +40,6 @@
 #include <linux/mm.h>
 #include <linux/mman.h>
 #include <linux/swap.h>
-#include <linux/smp_lock.h>
 #include <linux/iobuf.h>
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
@@ -53,7 +52,12 @@
 
 #include <linux/swapops.h>
 
+#ifndef CONFIG_DISCONTIGMEM
+/* use the per-pgdat data instead for discontigmem - mbligh */
 unsigned long max_mapnr;
+struct page *mem_map;
+#endif
+
 unsigned long num_physpages;
 void * high_memory;
 struct page *highmem_start_page;
@@ -71,8 +75,6 @@
 	}
 	copy_user_highpage(to, from, address);
 }
-
-struct page *mem_map;
 
 /*
  * Note: this doesn't free the actual pages themselves. That
diff -Nru a/mm/mempool.c b/mm/mempool.c
--- a/mm/mempool.c	Fri Sep 20 08:20:47 2002
+++ b/mm/mempool.c	Fri Sep 20 08:20:47 2002
@@ -187,11 +187,12 @@
 	int curr_nr;
 	DECLARE_WAITQUEUE(wait, current);
 	int gfp_nowait = gfp_mask & ~(__GFP_WAIT | __GFP_IO);
+	int pf_flags = current->flags;
 
 repeat_alloc:
 	current->flags |= PF_NOWARN;
 	element = pool->alloc(gfp_nowait, pool->pool_data);
-	current->flags &= ~PF_NOWARN;
+	current->flags = pf_flags;
 	if (likely(element != NULL))
 		return element;
 
diff -Nru a/mm/mlock.c b/mm/mlock.c
--- a/mm/mlock.c	Fri Sep 20 08:20:41 2002
+++ b/mm/mlock.c	Fri Sep 20 08:20:41 2002
@@ -2,147 +2,49 @@
  *	linux/mm/mlock.c
  *
  *  (C) Copyright 1995 Linus Torvalds
+ *  (C) Copyright 2002 Christoph Hellwig
  */
-#include <linux/slab.h>
-#include <linux/shm.h>
-#include <linux/mman.h>
-#include <linux/smp_lock.h>
-#include <linux/pagemap.h>
-
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>
-
-static inline int mlock_fixup_all(struct vm_area_struct * vma, int newflags)
-{
-	spin_lock(&vma->vm_mm->page_table_lock);
-	vma->vm_flags = newflags;
-	spin_unlock(&vma->vm_mm->page_table_lock);
-	return 0;
-}
-
-static inline int mlock_fixup_start(struct vm_area_struct * vma,
-	unsigned long end, int newflags)
-{
-	struct vm_area_struct * n;
-
-	n = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
-	if (!n)
-		return -EAGAIN;
-	*n = *vma;
-	n->vm_end = end;
-	n->vm_flags = newflags;
-	n->vm_raend = 0;
-	if (n->vm_file)
-		get_file(n->vm_file);
-	if (n->vm_ops && n->vm_ops->open)
-		n->vm_ops->open(n);
-	vma->vm_pgoff += (end - vma->vm_start) >> PAGE_SHIFT;
-	lock_vma_mappings(vma);
-	spin_lock(&vma->vm_mm->page_table_lock);
-	vma->vm_start = end;
-	__insert_vm_struct(current->mm, n);
-	spin_unlock(&vma->vm_mm->page_table_lock);
-	unlock_vma_mappings(vma);
-	return 0;
-}
-
-static inline int mlock_fixup_end(struct vm_area_struct * vma,
-	unsigned long start, int newflags)
-{
-	struct vm_area_struct * n;
-
-	n = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
-	if (!n)
-		return -EAGAIN;
-	*n = *vma;
-	n->vm_start = start;
-	n->vm_pgoff += (n->vm_start - vma->vm_start) >> PAGE_SHIFT;
-	n->vm_flags = newflags;
-	n->vm_raend = 0;
-	if (n->vm_file)
-		get_file(n->vm_file);
-	if (n->vm_ops && n->vm_ops->open)
-		n->vm_ops->open(n);
-	lock_vma_mappings(vma);
-	spin_lock(&vma->vm_mm->page_table_lock);
-	vma->vm_end = start;
-	__insert_vm_struct(current->mm, n);
-	spin_unlock(&vma->vm_mm->page_table_lock);
-	unlock_vma_mappings(vma);
-	return 0;
-}
 
-static inline int mlock_fixup_middle(struct vm_area_struct * vma,
-	unsigned long start, unsigned long end, int newflags)
-{
-	struct vm_area_struct * left, * right;
+#include <linux/mman.h>
+#include <linux/mm.h>
 
-	left = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
-	if (!left)
-		return -EAGAIN;
-	right = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
-	if (!right) {
-		kmem_cache_free(vm_area_cachep, left);
-		return -EAGAIN;
-	}
-	*left = *vma;
-	*right = *vma;
-	left->vm_end = start;
-	right->vm_start = end;
-	right->vm_pgoff += (right->vm_start - left->vm_start) >> PAGE_SHIFT;
-	vma->vm_flags = newflags;
-	left->vm_raend = 0;
-	right->vm_raend = 0;
-	if (vma->vm_file)
-		atomic_add(2, &vma->vm_file->f_count);
-
-	if (vma->vm_ops && vma->vm_ops->open) {
-		vma->vm_ops->open(left);
-		vma->vm_ops->open(right);
-	}
-	vma->vm_raend = 0;
-	vma->vm_pgoff += (start - vma->vm_start) >> PAGE_SHIFT;
-	lock_vma_mappings(vma);
-	spin_lock(&vma->vm_mm->page_table_lock);
-	vma->vm_start = start;
-	vma->vm_end = end;
-	vma->vm_flags = newflags;
-	__insert_vm_struct(current->mm, left);
-	__insert_vm_struct(current->mm, right);
-	spin_unlock(&vma->vm_mm->page_table_lock);
-	unlock_vma_mappings(vma);
-	return 0;
-}
 
 static int mlock_fixup(struct vm_area_struct * vma, 
 	unsigned long start, unsigned long end, unsigned int newflags)
 {
-	int pages, retval;
+	struct mm_struct * mm = vma->vm_mm;
+	int pages, error;
 
 	if (newflags == vma->vm_flags)
 		return 0;
 
-	if (start == vma->vm_start) {
-		if (end == vma->vm_end)
-			retval = mlock_fixup_all(vma, newflags);
-		else
-			retval = mlock_fixup_start(vma, end, newflags);
-	} else {
-		if (end == vma->vm_end)
-			retval = mlock_fixup_end(vma, start, newflags);
-		else
-			retval = mlock_fixup_middle(vma, start, end, newflags);
+	if (start != vma->vm_start) {
+		error = split_vma(mm, vma, start, 1);
+		if (error)
+			return -EAGAIN;
 	}
-	if (!retval) {
-		/* keep track of amount of locked VM */
-		pages = (end - start) >> PAGE_SHIFT;
-		if (newflags & VM_LOCKED) {
-			pages = -pages;
-			make_pages_present(start, end);
-		}
-		vma->vm_mm->locked_vm -= pages;
+
+	if (end != vma->vm_end) {
+		error = split_vma(mm, vma, end, 0);
+		if (error)
+			return -EAGAIN;
+	}
+	
+	spin_lock(&mm->page_table_lock);
+	vma->vm_flags = newflags;
+	spin_unlock(&mm->page_table_lock);
+
+	/*
+	 * Keep track of amount of locked VM.
+	 */
+	pages = (end - start) >> PAGE_SHIFT;
+	if (newflags & VM_LOCKED) {
+		pages = -pages;
+		make_pages_present(start, end);
 	}
-	return retval;
+
+	vma->vm_mm->locked_vm -= pages;
+	return 0;
 }
 
 static int do_mlock(unsigned long start, size_t len, int on)
diff -Nru a/mm/mmap.c b/mm/mmap.c
--- a/mm/mmap.c	Fri Sep 20 08:20:41 2002
+++ b/mm/mmap.c	Fri Sep 20 08:20:41 2002
@@ -11,7 +11,6 @@
 #include <linux/mman.h>
 #include <linux/pagemap.h>
 #include <linux/swap.h>
-#include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/file.h>
 #include <linux/fs.h>
@@ -132,47 +131,21 @@
 }
 
 /* Remove one vm structure from the inode's i_mapping address space. */
-static inline void __remove_shared_vm_struct(struct vm_area_struct *vma)
+static inline void remove_shared_vm_struct(struct vm_area_struct *vma)
 {
-	struct file * file = vma->vm_file;
+	struct file *file = vma->vm_file;
 
 	if (file) {
 		struct inode *inode = file->f_dentry->d_inode;
+
+		spin_lock(&inode->i_mapping->i_shared_lock);
 		if (vma->vm_flags & VM_DENYWRITE)
 			atomic_inc(&inode->i_writecount);
 		list_del_init(&vma->shared);
+		spin_unlock(&inode->i_mapping->i_shared_lock);
 	}
 }
 
-static inline void remove_shared_vm_struct(struct vm_area_struct *vma)
-{
-	lock_vma_mappings(vma);
-	__remove_shared_vm_struct(vma);
-	unlock_vma_mappings(vma);
-}
-
-void lock_vma_mappings(struct vm_area_struct *vma)
-{
-	struct address_space *mapping;
-
-	mapping = NULL;
-	if (vma->vm_file)
-		mapping = vma->vm_file->f_dentry->d_inode->i_mapping;
-	if (mapping)
-		spin_lock(&mapping->i_shared_lock);
-}
-
-void unlock_vma_mappings(struct vm_area_struct *vma)
-{
-	struct address_space *mapping;
-
-	mapping = NULL;
-	if (vma->vm_file)
-		mapping = vma->vm_file->f_dentry->d_inode->i_mapping;
-	if (mapping)
-		spin_unlock(&mapping->i_shared_lock);
-}
-
 /*
  *  sys_brk() for the most part doesn't need the global kernel
  *  lock, except when an application is doing something nasty
@@ -364,11 +337,18 @@
 static inline void vma_link(struct mm_struct * mm, struct vm_area_struct * vma, struct vm_area_struct * prev,
 			    struct rb_node ** rb_link, struct rb_node * rb_parent)
 {
+	struct address_space *mapping = NULL;
+
+	if (vma->vm_file)
+		mapping = vma->vm_file->f_dentry->d_inode->i_mapping;
+
+	if (mapping)
+		spin_lock(&mapping->i_shared_lock);
 	spin_lock(&mm->page_table_lock);
-	lock_vma_mappings(vma);
 	__vma_link(mm, vma, prev, rb_link, rb_parent);
-	unlock_vma_mappings(vma);
 	spin_unlock(&mm->page_table_lock);
+	if (mapping)
+		spin_unlock(&mapping->i_shared_lock);
 
 	mm->map_count++;
 	validate_mm(mm);
@@ -463,6 +443,11 @@
 	 */
 	vm_flags = calc_vm_flags(prot,flags) | mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
 
+	if (flags & MAP_LOCKED) {
+		if (!capable(CAP_IPC_LOCK))
+			return -EPERM;
+		vm_flags |= VM_LOCKED;
+	}
 	/* mlock MCL_FUTURE? */
 	if (vm_flags & VM_LOCKED) {
 		unsigned long locked = mm->locked_vm << PAGE_SHIFT;
@@ -1049,10 +1034,11 @@
 }
 
 /*
- * Split a vma into two pieces at address 'addr', the original vma
- * will contain the first part, a new vma is allocated for the tail.
+ * Split a vma into two pieces at address 'addr', a new vma is allocated
+ * either for the first part or the the tail.
  */
-static int splitvma(struct mm_struct *mm, struct vm_area_struct *mpnt, unsigned long addr)
+int split_vma(struct mm_struct * mm, struct vm_area_struct * vma,
+	      unsigned long addr, int new_below)
 {
 	struct vm_area_struct *new;
 
@@ -1064,31 +1050,34 @@
 		return -ENOMEM;
 
 	/* most fields are the same, copy all, and then fixup */
-	*new = *mpnt;
+	*new = *vma;
+
+	if (new_below) {
+		new->vm_end = addr;
+		vma->vm_start = addr;
+		vma->vm_pgoff += ((addr - vma->vm_start) >> PAGE_SHIFT);
+	} else {
+		vma->vm_end = addr;
+		new->vm_start = addr;
+		new->vm_pgoff += ((addr - vma->vm_start) >> PAGE_SHIFT);
+	}
 
-	new->vm_start = addr;
-	new->vm_pgoff = mpnt->vm_pgoff + ((addr - mpnt->vm_start) >> PAGE_SHIFT);
 	new->vm_raend = 0;
-	if (mpnt->vm_file)
-		get_file(mpnt->vm_file);
 
-	if (mpnt->vm_ops && mpnt->vm_ops->open)
-		mpnt->vm_ops->open(mpnt);
-	mpnt->vm_end = addr;	/* Truncate area */
+	if (new->vm_file)
+		get_file(new->vm_file);
 
-	spin_lock(&mm->page_table_lock);
-	lock_vma_mappings(mpnt);
-	__insert_vm_struct(mm, new);
-	unlock_vma_mappings(mpnt);
-	spin_unlock(&mm->page_table_lock);
+	if (new->vm_ops && new->vm_ops->open)
+		new->vm_ops->open(new);
 
+	insert_vm_struct(mm, new);
 	return 0;
 }
 
 /* Munmap is split into 2 main parts -- this part which finds
  * what needs doing, and the areas themselves, which do the
  * work.  This now handles partial unmappings.
- * Jeremy Fitzhardine <jeremy@sw.oz.au>
+ * Jeremy Fitzhardinge <jeremy@goop.org>
  */
 int do_munmap(struct mm_struct *mm, unsigned long start, size_t len)
 {
@@ -1116,7 +1105,7 @@
 	 * If we need to split any vma, do it now to save pain later.
 	 */
 	if (start > mpnt->vm_start) {
-		if (splitvma(mm, mpnt, start))
+		if (split_vma(mm, mpnt, start, 0))
 			return -ENOMEM;
 		prev = mpnt;
 		mpnt = mpnt->vm_next;
@@ -1125,7 +1114,7 @@
 	/* Does it split the last one? */
 	last = find_vma(mm, end);
 	if (last && end > last->vm_start) {
-		if (splitvma(mm, last, end))
+		if (split_vma(mm, last, end, 0))
 			return -ENOMEM;
 	}
 
@@ -1325,19 +1314,6 @@
  * and into the inode's i_mmap ring.  If vm_file is non-NULL
  * then the i_shared_lock must be held here.
  */
-void __insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma)
-{
-	struct vm_area_struct * __vma, * prev;
-	struct rb_node ** 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();
-	__vma_link(mm, vma, prev, rb_link, rb_parent);
-	mm->map_count++;
-	validate_mm(mm);
-}
-
 void insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma)
 {
 	struct vm_area_struct * __vma, * prev;
diff -Nru a/mm/mprotect.c b/mm/mprotect.c
--- a/mm/mprotect.c	Fri Sep 20 08:20:44 2002
+++ b/mm/mprotect.c	Fri Sep 20 08:20:44 2002
@@ -2,13 +2,14 @@
  *  mm/mprotect.c
  *
  *  (C) Copyright 1994 Linus Torvalds
+ *  (C) Copyright 2002 Christoph Hellwig
  *
  *  Address space accounting code	<alan@redhat.com>
  *  (C) Copyright 2002 Red Hat Inc, All Rights Reserved
  */
+
 #include <linux/mm.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/shm.h>
 #include <linux/mman.h>
 #include <linux/fs.h>
@@ -21,8 +22,9 @@
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 
-static inline void change_pte_range(pmd_t * pmd, unsigned long address,
-	unsigned long size, pgprot_t newprot)
+static inline void
+change_pte_range(pmd_t *pmd, unsigned long address,
+		unsigned long size, pgprot_t newprot)
 {
 	pte_t * pte;
 	unsigned long end;
@@ -56,8 +58,9 @@
 	pte_unmap(pte - 1);
 }
 
-static inline void change_pmd_range(pgd_t * pgd, unsigned long address,
-	unsigned long size, pgprot_t newprot)
+static inline void
+change_pmd_range(pgd_t *pgd, unsigned long address,
+		unsigned long size, pgprot_t newprot)
 {
 	pmd_t * pmd;
 	unsigned long end;
@@ -81,7 +84,9 @@
 	} while (address && (address < end));
 }
 
-static void change_protection(struct vm_area_struct *vma, unsigned long start, unsigned long end, pgprot_t newprot)
+static void
+change_protection(struct vm_area_struct *vma, unsigned long start,
+		unsigned long end, pgprot_t newprot)
 {
 	pgd_t *dir;
 	unsigned long beg = start;
@@ -100,158 +105,58 @@
 	spin_unlock(&current->mm->page_table_lock);
 	return;
 }
-
-static inline int mprotect_fixup_all(struct vm_area_struct * vma, struct vm_area_struct ** pprev,
-	int newflags, pgprot_t prot)
+/*
+ * Try to merge a vma with the previous flag, return 1 if successful or 0 if it
+ * was impossible.
+ */
+static int
+mprotect_attempt_merge(struct vm_area_struct *vma, struct vm_area_struct *prev,
+		unsigned long end, int newflags)
 {
-	struct vm_area_struct * prev = *pprev;
 	struct mm_struct * mm = vma->vm_mm;
 
-	if (prev && prev->vm_end == vma->vm_start && can_vma_merge(prev, newflags) &&
-	    !vma->vm_file && !(vma->vm_flags & VM_SHARED)) {
+	if (!prev || !vma)
+		return 0;
+	if (prev->vm_end != vma->vm_start)
+		return 0;
+	if (!can_vma_merge(prev, newflags))
+		return 0;
+	if (vma->vm_file || (vma->vm_flags & VM_SHARED))
+		return 0;
+
+	/*
+	 * If the whole area changes to the protection of the previous one
+	 * we can just get rid of it.
+	 */
+	if (end == vma->vm_end) {
 		spin_lock(&mm->page_table_lock);
-		prev->vm_end = vma->vm_end;
+		prev->vm_end = end;
 		__vma_unlink(mm, vma, prev);
 		spin_unlock(&mm->page_table_lock);
 
 		kmem_cache_free(vm_area_cachep, vma);
 		mm->map_count--;
+		return 1;
+	} 
 
-		return 0;
-	}
-
+	/*
+	 * Otherwise extend it.
+	 */
 	spin_lock(&mm->page_table_lock);
-	vma->vm_flags = newflags;
-	vma->vm_page_prot = prot;
-	spin_unlock(&mm->page_table_lock);
-
-	*pprev = vma;
-
-	return 0;
-}
-
-static inline int mprotect_fixup_start(struct vm_area_struct * vma, struct vm_area_struct ** pprev,
-	unsigned long end,
-	int newflags, pgprot_t prot)
-{
-	struct vm_area_struct * n, * prev = *pprev;
-
-	*pprev = vma;
-
-	if (prev && prev->vm_end == vma->vm_start && can_vma_merge(prev, newflags) &&
-	    !vma->vm_file && !(vma->vm_flags & VM_SHARED)) {
-		spin_lock(&vma->vm_mm->page_table_lock);
-		prev->vm_end = end;
-		vma->vm_start = end;
-		spin_unlock(&vma->vm_mm->page_table_lock);
-
-		return 0;
-	}
-	n = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
-	if (!n)
-		return -ENOMEM;
-	*n = *vma;
-	n->vm_end = end;
-	n->vm_flags = newflags;
-	n->vm_raend = 0;
-	n->vm_page_prot = prot;
-	if (n->vm_file)
-		get_file(n->vm_file);
-	if (n->vm_ops && n->vm_ops->open)
-		n->vm_ops->open(n);
-	vma->vm_pgoff += (end - vma->vm_start) >> PAGE_SHIFT;
-	lock_vma_mappings(vma);
-	spin_lock(&vma->vm_mm->page_table_lock);
+	prev->vm_end = end;
 	vma->vm_start = end;
-	__insert_vm_struct(current->mm, n);
-	spin_unlock(&vma->vm_mm->page_table_lock);
-	unlock_vma_mappings(vma);
-
-	return 0;
-}
-
-static inline int mprotect_fixup_end(struct vm_area_struct * vma, struct vm_area_struct ** pprev,
-	unsigned long start,
-	int newflags, pgprot_t prot)
-{
-	struct vm_area_struct * n;
-
-	n = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL);
-	if (!n)
-		return -ENOMEM;
-	*n = *vma;
-	n->vm_start = start;
-	n->vm_pgoff += (n->vm_start - vma->vm_start) >> PAGE_SHIFT;
-	n->vm_flags = newflags;
-	n->vm_raend = 0;
-	n->vm_page_prot = prot;
-	if (n->vm_file)
-		get_file(n->vm_file);
-	if (n->vm_ops && n->vm_ops->open)
-		n->vm_ops->open(n);
-	lock_vma_mappings(vma);
-	spin_lock(&vma->vm_mm->page_table_lock);
-	vma->vm_end = start;
-	__insert_vm_struct(current->mm, n);
-	spin_unlock(&vma->vm_mm->page_table_lock);
-	unlock_vma_mappings(vma);
-
-	*pprev = n;
-
-	return 0;
-}
-
-static inline int mprotect_fixup_middle(struct vm_area_struct * vma, struct vm_area_struct ** pprev,
-	unsigned long start, unsigned long end,
-	int newflags, pgprot_t prot)
-{
-	struct vm_area_struct * left, * right;
-
-	left = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
-	if (!left)
-		return -ENOMEM;
-	right = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
-	if (!right) {
-		kmem_cache_free(vm_area_cachep, left);
-		return -ENOMEM;
-	}
-	*left = *vma;
-	*right = *vma;
-	left->vm_end = start;
-	right->vm_start = end;
-	right->vm_pgoff += (right->vm_start - left->vm_start) >> PAGE_SHIFT;
-	left->vm_raend = 0;
-	right->vm_raend = 0;
-	if (vma->vm_file)
-		atomic_add(2,&vma->vm_file->f_count);
-	if (vma->vm_ops && vma->vm_ops->open) {
-		vma->vm_ops->open(left);
-		vma->vm_ops->open(right);
-	}
-	vma->vm_pgoff += (start - vma->vm_start) >> PAGE_SHIFT;
-	vma->vm_raend = 0;
-	vma->vm_page_prot = prot;
-	lock_vma_mappings(vma);
-	spin_lock(&vma->vm_mm->page_table_lock);
-	vma->vm_start = start;
-	vma->vm_end = end;
-	vma->vm_flags = newflags;
-	__insert_vm_struct(current->mm, left);
-	__insert_vm_struct(current->mm, right);
-	spin_unlock(&vma->vm_mm->page_table_lock);
-	unlock_vma_mappings(vma);
-
-	*pprev = right;
-
-	return 0;
+	spin_unlock(&mm->page_table_lock);
+	return 1;
 }
 
-static int mprotect_fixup(struct vm_area_struct * vma, struct vm_area_struct ** pprev,
+static int
+mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev,
 	unsigned long start, unsigned long end, unsigned int newflags)
 {
+	struct mm_struct * mm = vma->vm_mm;
+	unsigned long charged = 0;
 	pgprot_t newprot;
 	int error;
-	unsigned long charged = 0;
 
 	if (newflags == vma->vm_flags) {
 		*pprev = vma;
@@ -266,32 +171,50 @@
 	 * FIXME? We haven't defined a VM_NORESERVE flag, so mprotecting
 	 * a MAP_NORESERVE private mapping to writable will now reserve.
 	 */
-	if ((newflags & VM_WRITE) &&
-	    !(vma->vm_flags & (VM_ACCOUNT|VM_WRITE|VM_SHARED))) {
-		charged = (end - start) >> PAGE_SHIFT;
-		if (!vm_enough_memory(charged))
-			return -ENOMEM;
-		newflags |= VM_ACCOUNT;
+	if (newflags & VM_WRITE) {
+		if (!(vma->vm_flags & (VM_ACCOUNT|VM_WRITE|VM_SHARED))) {
+			charged = (end - start) >> PAGE_SHIFT;
+			if (!vm_enough_memory(charged))
+				return -ENOMEM;
+			newflags |= VM_ACCOUNT;
+		}
 	}
+
 	newprot = protection_map[newflags & 0xf];
+
 	if (start == vma->vm_start) {
-		if (end == vma->vm_end)
-			error = mprotect_fixup_all(vma, pprev, newflags, newprot);
-		else
-			error = mprotect_fixup_start(vma, pprev, end, newflags, newprot);
-	} else if (end == vma->vm_end)
-		error = mprotect_fixup_end(vma, pprev, start, newflags, newprot);
-	else
-		error = mprotect_fixup_middle(vma, pprev, start, end, newflags, newprot);
-	if (error) {
-		vm_unacct_memory(charged);
-		return error;
+		/*
+		 * Try to merge with the previous vma.
+		 */
+		if (mprotect_attempt_merge(vma, *pprev, end, newflags))
+			return 0;
+	} else {
+		error = split_vma(mm, vma, start, 1);
+		if (error)
+			goto fail;
+	}
+
+	if (end != vma->vm_end) {
+		error = split_vma(mm, vma, end, 0);
+		if (error)
+			goto fail;
 	}
+
+	spin_lock(&mm->page_table_lock);
+	vma->vm_flags = newflags;
+	vma->vm_page_prot = newprot;
+	spin_unlock(&mm->page_table_lock);
+
 	change_protection(vma, start, end, newprot);
 	return 0;
+
+fail:
+	vm_unacct_memory(charged);
+	return error;
 }
 
-asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot)
+asmlinkage long
+sys_mprotect(unsigned long start, size_t len, unsigned long prot)
 {
 	unsigned long nstart, end, tmp;
 	struct vm_area_struct * vma, * next, * prev;
@@ -357,8 +280,10 @@
 			goto out;
 		}
 	}
-	if (next && prev->vm_end == next->vm_start && can_vma_merge(next, prev->vm_flags) &&
-	    !prev->vm_file && !(prev->vm_flags & VM_SHARED)) {
+
+	if (next && prev->vm_end == next->vm_start &&
+			can_vma_merge(next, prev->vm_flags) &&
+			!prev->vm_file && !(prev->vm_flags & VM_SHARED)) {
 		spin_lock(&prev->vm_mm->page_table_lock);
 		prev->vm_end = next->vm_end;
 		__vma_unlink(prev->vm_mm, next, prev);
diff -Nru a/mm/mremap.c b/mm/mremap.c
--- a/mm/mremap.c	Fri Sep 20 08:20:46 2002
+++ b/mm/mremap.c	Fri Sep 20 08:20:46 2002
@@ -9,7 +9,6 @@
 
 #include <linux/mm.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/shm.h>
 #include <linux/mman.h>
 #include <linux/swap.h>
diff -Nru a/mm/numa.c b/mm/numa.c
--- a/mm/numa.c	Fri Sep 20 08:20:47 2002
+++ b/mm/numa.c	Fri Sep 20 08:20:47 2002
@@ -22,11 +22,21 @@
  * Should be invoked with paramters (0, 0, unsigned long *[], start_paddr).
  */
 void __init free_area_init_node(int nid, pg_data_t *pgdat, struct page *pmap,
-	unsigned long *zones_size, unsigned long zone_start_pfn, 
+	unsigned long *zones_size, unsigned long node_start_pfn, 
 	unsigned long *zholes_size)
 {
-	free_area_init_core(0, &contig_page_data, &mem_map, zones_size, 
-				zone_start_pfn, zholes_size, pmap);
+	unsigned long size;
+
+	contig_page_data.node_id = 0;
+	contig_page_data.node_start_pfn = node_start_pfn;
+	calculate_totalpages (&contig_page_data, zones_size, zholes_size);
+	if (pmap == (struct page *)0) {
+		size = (pgdat->node_size + 1) * sizeof(struct page);
+		pmap = (struct page *) alloc_bootmem_node(pgdat, size);
+	}
+	contig_page_data.node_mem_map = pmap;
+	free_area_init_core(&contig_page_data, zones_size, zholes_size);
+	mem_map = contig_page_data.node_mem_map;
 }
 
 #endif /* !CONFIG_DISCONTIGMEM */
@@ -48,71 +58,31 @@
  * Nodes can be initialized parallely, in no particular order.
  */
 void __init free_area_init_node(int nid, pg_data_t *pgdat, struct page *pmap,
-	unsigned long *zones_size, unsigned long zone_start_pfn, 
+	unsigned long *zones_size, unsigned long node_start_pfn, 
 	unsigned long *zholes_size)
 {
-	int i, size = 0;
-	struct page *discard;
-
-	if (mem_map == NULL)
-		mem_map = (struct page *)PAGE_OFFSET;
+	int i;
+	unsigned long size;
 
-	free_area_init_core(nid, pgdat, &discard, zones_size, zone_start_pfn,
-					zholes_size, pmap);
 	pgdat->node_id = nid;
+	pgdat->node_start_pfn = node_start_pfn;
+	calculate_totalpages (pgdat, zones_size, zholes_size);
+	if (pmap == (struct page *)0) {
+		size = (pgdat->node_size + 1) * sizeof(struct page); 
+		pmap = (struct page *) alloc_bootmem_node(pgdat, size);
+	}
+	pgdat->node_mem_map = pmap;
+	free_area_init_core(pgdat, zones_size, zholes_size);
 
 	/*
 	 * Get space for the valid bitmap.
 	 */
+	size = 0;
 	for (i = 0; i < MAX_NR_ZONES; i++)
 		size += zones_size[i];
 	size = LONG_ALIGN((size + 7) >> 3);
 	pgdat->valid_addr_bitmap = (unsigned long *)alloc_bootmem_node(pgdat, size);
 	memset(pgdat->valid_addr_bitmap, 0, size);
-}
-
-static struct page * alloc_pages_pgdat(pg_data_t *pgdat, unsigned int gfp_mask,
-	unsigned int order)
-{
-	return __alloc_pages(gfp_mask, order, pgdat->node_zonelists + (gfp_mask & GFP_ZONEMASK));
-}
-
-/*
- * This can be refined. Currently, tries to do round robin, instead
- * should do concentratic circle search, starting from current node.
- */
-struct page * _alloc_pages(unsigned int gfp_mask, unsigned int order)
-{
-	struct page *ret = 0;
-	pg_data_t *start, *temp;
-#ifndef CONFIG_NUMA
-	unsigned long flags;
-	static pg_data_t *next = 0;
-#endif
-
-	if (order >= MAX_ORDER)
-		return NULL;
-#ifdef CONFIG_NUMA
-	temp = NODE_DATA(numa_node_id());
-#else
-	if (!next)
-		next = pgdat_list;
-	temp = next;
-	next = next->pgdat_next;
-#endif
-	start = temp;
-	while (temp) {
-		if ((ret = alloc_pages_pgdat(temp, gfp_mask, order)))
-			return(ret);
-		temp = temp->pgdat_next;
-	}
-	temp = pgdat_list;
-	while (temp != start) {
-		if ((ret = alloc_pages_pgdat(temp, gfp_mask, order)))
-			return(ret);
-		temp = temp->pgdat_next;
-	}
-	return(0);
 }
 
 #endif /* CONFIG_DISCONTIGMEM */
diff -Nru a/mm/page-writeback.c b/mm/page-writeback.c
--- a/mm/page-writeback.c	Fri Sep 20 08:20:47 2002
+++ b/mm/page-writeback.c	Fri Sep 20 08:20:47 2002
@@ -51,7 +51,7 @@
  * It should be somewhat larger than RATELIMIT_PAGES to ensure that reasonably
  * large amounts of I/O are submitted.
  */
-static inline int sync_writeback_pages(void)
+static inline long sync_writeback_pages(void)
 {
 	return ratelimit_pages + ratelimit_pages / 2;
 }
@@ -73,11 +73,6 @@
 int dirty_async_ratio = 40;
 
 /*
- * The generator of dirty data performs sync writeout at this level
- */
-int dirty_sync_ratio = 50;
-
-/*
  * The interval between `kupdate'-style writebacks, in centiseconds
  * (hundredths of a second)
  */
@@ -105,15 +100,11 @@
  * - Does nothing at all.
  *
  * balance_dirty_pages() can sleep.
- *
- * FIXME: WB_SYNC_LAST doesn't actually work.  It waits on the last dirty
- * inode on the superblock list.  It should wait when nr_to_write is
- * exhausted.  Doesn't seem to matter.
  */
 void balance_dirty_pages(struct address_space *mapping)
 {
 	struct page_state ps;
-	long background_thresh, async_thresh, sync_thresh;
+	long background_thresh, async_thresh;
 	unsigned long dirty_and_writeback;
 	struct backing_dev_info *bdi;
 
@@ -122,18 +113,17 @@
 
 	background_thresh = (dirty_background_ratio * total_pages) / 100;
 	async_thresh = (dirty_async_ratio * total_pages) / 100;
-	sync_thresh = (dirty_sync_ratio * total_pages) / 100;
 	bdi = mapping->backing_dev_info;
 
-	if (dirty_and_writeback > sync_thresh) {
-		int nr_to_write = sync_writeback_pages();
+	if (dirty_and_writeback > async_thresh) {
+		struct writeback_control wbc = {
+			.bdi		= bdi,
+			.sync_mode	= WB_SYNC_NONE,
+			.older_than_this = NULL,
+			.nr_to_write	= sync_writeback_pages(),
+		};
 
-		writeback_backing_dev(bdi, &nr_to_write, WB_SYNC_LAST, NULL);
-		get_page_state(&ps);
-	} else if (dirty_and_writeback > async_thresh) {
-		int nr_to_write = sync_writeback_pages();
-
-		writeback_backing_dev(bdi, &nr_to_write, WB_SYNC_NONE, NULL);
+		writeback_inodes(&wbc);
 		get_page_state(&ps);
 	}
 
@@ -177,7 +167,12 @@
 {
 	long min_pages = _min_pages;
 	long background_thresh;
-	int nr_to_write;
+	struct writeback_control wbc = {
+		.bdi		= NULL,
+		.sync_mode	= WB_SYNC_NONE,
+		.older_than_this = NULL,
+		.nr_to_write	= 0,
+	};
 
 	CHECK_EMERGENCY_SYNC
 
@@ -185,14 +180,13 @@
 
 	do {
 		struct page_state ps;
-
 		get_page_state(&ps);
 		if (ps.nr_dirty < background_thresh && min_pages <= 0)
 			break;
-		nr_to_write = MAX_WRITEBACK_PAGES;
-		writeback_unlocked_inodes(&nr_to_write, WB_SYNC_NONE, NULL);
-		min_pages -= MAX_WRITEBACK_PAGES - nr_to_write;
-	} while (nr_to_write <= 0);
+		wbc.nr_to_write = MAX_WRITEBACK_PAGES;
+		writeback_inodes(&wbc);
+		min_pages -= MAX_WRITEBACK_PAGES - wbc.nr_to_write;
+	} while (wbc.nr_to_write <= 0);
 	blk_run_queues();
 }
 
@@ -230,7 +224,12 @@
 	unsigned long start_jif;
 	unsigned long next_jif;
 	struct page_state ps;
-	int nr_to_write;
+	struct writeback_control wbc = {
+		.bdi		= NULL,
+		.sync_mode	= WB_SYNC_NONE,
+		.older_than_this = &oldest_jif,
+		.nr_to_write	= 0,
+	};
 
 	sync_supers();
 	get_page_state(&ps);
@@ -238,8 +237,8 @@
 	oldest_jif = jiffies - (dirty_expire_centisecs * HZ) / 100;
 	start_jif = jiffies;
 	next_jif = start_jif + (dirty_writeback_centisecs * HZ) / 100;
-	nr_to_write = ps.nr_dirty;
-	writeback_unlocked_inodes(&nr_to_write, WB_SYNC_NONE, &oldest_jif);
+	wbc.nr_to_write = ps.nr_dirty;
+	writeback_inodes(&wbc);
 	blk_run_queues();
 	yield();
 
@@ -312,8 +311,6 @@
 		dirty_background_ratio /= 100;
 		dirty_async_ratio *= correction;
 		dirty_async_ratio /= 100;
-		dirty_sync_ratio *= correction;
-		dirty_sync_ratio /= 100;
 	}
 
 	init_timer(&wb_timer);
@@ -351,7 +348,7 @@
  * So.  The proper fix is to leave the page locked-and-dirty and to pass
  * it all the way down.
  */
-int generic_vm_writeback(struct page *page, int *nr_to_write)
+int generic_vm_writeback(struct page *page, struct writeback_control *wbc)
 {
 	struct inode *inode = page->mapping->host;
 
@@ -363,7 +360,7 @@
 	unlock_page(page);
 
 	if (inode) {
-		do_writepages(inode->i_mapping, nr_to_write);
+		do_writepages(inode->i_mapping, wbc);
 
 		/*
 		 * This iput() will internally call ext2_discard_prealloc(),
@@ -392,11 +389,11 @@
 }
 EXPORT_SYMBOL(generic_vm_writeback);
 
-int do_writepages(struct address_space *mapping, int *nr_to_write)
+int do_writepages(struct address_space *mapping, struct writeback_control *wbc)
 {
 	if (mapping->a_ops->writepages)
-		return mapping->a_ops->writepages(mapping, nr_to_write);
-	return generic_writepages(mapping, nr_to_write);
+		return mapping->a_ops->writepages(mapping, wbc);
+	return generic_writepages(mapping, wbc);
 }
 
 /**
diff -Nru a/mm/page_alloc.c b/mm/page_alloc.c
--- a/mm/page_alloc.c	Fri Sep 20 08:20:41 2002
+++ b/mm/page_alloc.c	Fri Sep 20 08:20:41 2002
@@ -256,14 +256,6 @@
 }
 #endif /* CONFIG_SOFTWARE_SUSPEND */
 
-#ifndef CONFIG_DISCONTIGMEM
-struct page *_alloc_pages(unsigned int gfp_mask, unsigned int order)
-{
-	return __alloc_pages(gfp_mask, order,
-		contig_page_data.node_zonelists+(gfp_mask & GFP_ZONEMASK));
-}
-#endif
-
 static /* inline */ struct page *
 balance_classzone(struct zone* classzone, unsigned int gfp_mask,
 			unsigned int order, int * freed)
@@ -563,6 +555,7 @@
 		ret->nr_page_table_pages += ps->nr_page_table_pages;
 		ret->nr_reverse_maps += ps->nr_reverse_maps;
 		ret->nr_mapped += ps->nr_mapped;
+		ret->nr_slab += ps->nr_slab;
 	}
 }
 
@@ -679,13 +672,41 @@
 /*
  * Builds allocation fallback zone lists.
  */
-static inline void build_zonelists(pg_data_t *pgdat)
+static int __init build_zonelists_node(pg_data_t *pgdat, struct zonelist *zonelist, int j, int k)
+{
+	switch (k) {
+		struct zone *zone;
+	default:
+		BUG();
+	case ZONE_HIGHMEM:
+		zone = pgdat->node_zones + ZONE_HIGHMEM;
+		if (zone->size) {
+#ifndef CONFIG_HIGHMEM
+			BUG();
+#endif
+			zonelist->zones[j++] = zone;
+		}
+	case ZONE_NORMAL:
+		zone = pgdat->node_zones + ZONE_NORMAL;
+		if (zone->size)
+			zonelist->zones[j++] = zone;
+	case ZONE_DMA:
+		zone = pgdat->node_zones + ZONE_DMA;
+		if (zone->size)
+			zonelist->zones[j++] = zone;
+	}
+
+	return j;
+}
+
+static void __init build_zonelists(pg_data_t *pgdat)
 {
-	int i, j, k;
+	int i, j, k, node, local_node;
 
+	local_node = pgdat->node_id;
+	printk("Building zonelist for node : %d\n", local_node);
 	for (i = 0; i <= GFP_ZONEMASK; i++) {
 		struct zonelist *zonelist;
-		struct zone *zone;
 
 		zonelist = pgdat->node_zonelists + i;
 		memset(zonelist, 0, sizeof(*zonelist));
@@ -697,33 +718,49 @@
 		if (i & __GFP_DMA)
 			k = ZONE_DMA;
 
-		switch (k) {
-			default:
-				BUG();
-			/*
-			 * fallthrough:
-			 */
-			case ZONE_HIGHMEM:
-				zone = pgdat->node_zones + ZONE_HIGHMEM;
-				if (zone->size) {
-#ifndef CONFIG_HIGHMEM
-					BUG();
-#endif
-					zonelist->zones[j++] = zone;
-				}
-			case ZONE_NORMAL:
-				zone = pgdat->node_zones + ZONE_NORMAL;
-				if (zone->size)
-					zonelist->zones[j++] = zone;
-			case ZONE_DMA:
-				zone = pgdat->node_zones + ZONE_DMA;
-				if (zone->size)
-					zonelist->zones[j++] = zone;
-		}
+ 		j = build_zonelists_node(pgdat, zonelist, j, k);
+ 		/*
+ 		 * Now we build the zonelist so that it contains the zones
+ 		 * of all the other nodes.
+ 		 * We don't want to pressure a particular node, so when
+ 		 * building the zones for node N, we make sure that the
+ 		 * zones coming right after the local ones are those from
+ 		 * node N+1 (modulo N)
+ 		 */
+ 		for (node = local_node + 1; node < numnodes; node++)
+ 			j = build_zonelists_node(NODE_DATA(node), zonelist, j, k);
+ 		for (node = 0; node < local_node; node++)
+ 			j = build_zonelists_node(NODE_DATA(node), zonelist, j, k);
+ 
 		zonelist->zones[j++] = NULL;
 	} 
 }
 
+void __init build_all_zonelists(void)
+{
+	int i;
+
+	for(i = 0 ; i < numnodes ; i++)
+		build_zonelists(NODE_DATA(i));
+}
+
+void __init calculate_totalpages (pg_data_t *pgdat, unsigned long *zones_size,
+	unsigned long *zholes_size)
+{
+	unsigned long realtotalpages, totalpages = 0;
+	int i;
+
+	for (i = 0; i < MAX_NR_ZONES; i++)
+		totalpages += zones_size[i];
+	pgdat->node_size = totalpages;
+
+	realtotalpages = totalpages;
+	if (zholes_size)
+		for (i = 0; i < MAX_NR_ZONES; i++)
+			realtotalpages -= zholes_size[i];
+	printk("On node %d totalpages: %lu\n", pgdat->node_id, realtotalpages);
+}
+
 /*
  * Helper functions to size the waitqueue hash table.
  * Essentially these want to choose hash table sizes sufficiently
@@ -774,46 +811,18 @@
  *   - mark all memory queues empty
  *   - clear the memory bitmaps
  */
-void __init free_area_init_core(int nid, pg_data_t *pgdat, struct page **gmap,
-	unsigned long *zones_size, unsigned long zone_start_pfn, 
-	unsigned long *zholes_size, struct page *lmem_map)
+void __init free_area_init_core(pg_data_t *pgdat,
+		unsigned long *zones_size, unsigned long *zholes_size)
 {
 	unsigned long i, j;
-	unsigned long map_size;
-	unsigned long totalpages, offset, realtotalpages;
+	unsigned long local_offset;
 	const unsigned long zone_required_alignment = 1UL << (MAX_ORDER-1);
+	int nid = pgdat->node_id;
+	struct page *lmem_map = pgdat->node_mem_map;
+	unsigned long zone_start_pfn = pgdat->node_start_pfn;
 
-	totalpages = 0;
-	for (i = 0; i < MAX_NR_ZONES; i++)
-		totalpages += zones_size[i];
-
-	realtotalpages = totalpages;
-	if (zholes_size)
-		for (i = 0; i < MAX_NR_ZONES; i++)
-			realtotalpages -= zholes_size[i];
-			
-	printk("On node %d totalpages: %lu\n", nid, realtotalpages);
-
-	/*
-	 * Some architectures (with lots of mem and discontinous memory
-	 * maps) have to search for a good mem_map area:
-	 * For discontigmem, the conceptual mem map array starts from 
-	 * PAGE_OFFSET, we need to align the actual array onto a mem map 
-	 * boundary, so that MAP_NR works.
-	 */
-	map_size = (totalpages + 1)*sizeof(struct page);
-	if (lmem_map == (struct page *)0) {
-		lmem_map = (struct page *) alloc_bootmem_node(pgdat, map_size);
-		lmem_map = (struct page *)(PAGE_OFFSET + 
-			MAP_ALIGN((unsigned long)lmem_map - PAGE_OFFSET));
-	}
-	*gmap = pgdat->node_mem_map = lmem_map;
-	pgdat->node_size = totalpages;
-	pgdat->node_start_pfn = zone_start_pfn;
-	pgdat->node_start_mapnr = (lmem_map - mem_map);
 	pgdat->nr_zones = 0;
-
-	offset = lmem_map - mem_map;	
+	local_offset = 0;                /* offset within lmem_map */
 	for (j = 0; j < MAX_NR_ZONES; j++) {
 		struct zone *zone = pgdat->node_zones + j;
 		unsigned long mask;
@@ -865,8 +874,7 @@
 		zone->pages_low = mask*2;
 		zone->pages_high = mask*3;
 
-		zone->zone_mem_map = mem_map + offset;
-		zone->zone_start_mapnr = offset;
+		zone->zone_mem_map = lmem_map + local_offset;
 		zone->zone_start_pfn = zone_start_pfn;
 
 		if ((zone_start_pfn) & (zone_required_alignment-1))
@@ -878,7 +886,7 @@
 		 * done. Non-atomic initialization, single-pass.
 		 */
 		for (i = 0; i < size; i++) {
-			struct page *page = mem_map + offset + i;
+			struct page *page = lmem_map + local_offset + i;
 			set_page_zone(page, nid * MAX_NR_ZONES + j);
 			set_page_count(page, 0);
 			SetPageReserved(page);
@@ -892,7 +900,7 @@
 			zone_start_pfn++;
 		}
 
-		offset += size;
+		local_offset += size;
 		for (i = 0; ; i++) {
 			unsigned long bitmap_size;
 
@@ -931,13 +939,15 @@
 			  (unsigned long *) alloc_bootmem_node(pgdat, bitmap_size);
 		}
 	}
-	build_zonelists(pgdat);
 }
 
+#ifndef CONFIG_DISCONTIGMEM
 void __init free_area_init(unsigned long *zones_size)
 {
-	free_area_init_core(0, &contig_page_data, &mem_map, zones_size, 0, 0, 0);
+	free_area_init_node(0, &contig_page_data, NULL, zones_size, 0, NULL);
+	mem_map = contig_page_data.node_mem_map;
 }
+#endif
 
 static int __init setup_mem_frac(char *str)
 {
diff -Nru a/mm/page_io.c b/mm/page_io.c
--- a/mm/page_io.c	Fri Sep 20 08:20:42 2002
+++ b/mm/page_io.c	Fri Sep 20 08:20:42 2002
@@ -47,22 +47,29 @@
 	return bio;
 }
 
-static void end_swap_bio_write(struct bio *bio)
+static int end_swap_bio_write(struct bio *bio, unsigned int bytes_done, int err)
 {
 	const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
 	struct page *page = bio->bi_io_vec[0].bv_page;
 
+	if (bio->bi_size)
+		return 1;
+
 	if (!uptodate)
 		SetPageError(page);
 	end_page_writeback(page);
 	bio_put(bio);
+	return 0;
 }
 
-static void end_swap_bio_read(struct bio *bio)
+static int end_swap_bio_read(struct bio *bio, unsigned int bytes_done, int err)
 {
 	const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
 	struct page *page = bio->bi_io_vec[0].bv_page;
 
+	if (bio->bi_size)
+		return 1;
+
 	if (!uptodate) {
 		SetPageError(page);
 		ClearPageUptodate(page);
@@ -71,6 +78,7 @@
 	}
 	unlock_page(page);
 	bio_put(bio);
+	return 0;
 }
 
 /*
@@ -123,12 +131,12 @@
  * Swap pages are !PageLocked and PageWriteback while under writeout so that
  * memory allocators will throttle against them.
  */
-static int swap_vm_writeback(struct page *page, int *nr_to_write)
+static int swap_vm_writeback(struct page *page, struct writeback_control *wbc)
 {
 	struct address_space *mapping = page->mapping;
 
 	unlock_page(page);
-	return generic_writepages(mapping, nr_to_write);
+	return generic_writepages(mapping, wbc);
 }
 
 struct address_space_operations swap_aops = {
diff -Nru a/mm/shmem.c b/mm/shmem.c
--- a/mm/shmem.c	Fri Sep 20 08:20:45 2002
+++ b/mm/shmem.c	Fri Sep 20 08:20:45 2002
@@ -28,7 +28,6 @@
 #include <linux/pagemap.h>
 #include <linux/string.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/backing-dev.h>
 #include <linux/shmem_fs.h>
 
diff -Nru a/mm/slab.c b/mm/slab.c
--- a/mm/slab.c	Fri Sep 20 08:20:47 2002
+++ b/mm/slab.c	Fri Sep 20 08:20:47 2002
@@ -545,6 +545,7 @@
 	 */
 	while (i--) {
 		ClearPageSlab(page);
+		dec_page_state(nr_slab);
 		page++;
 	}
 	free_pages((unsigned long)addr, cachep->gfporder);
@@ -1203,6 +1204,7 @@
 		SET_PAGE_CACHE(page, cachep);
 		SET_PAGE_SLAB(page, slabp);
 		SetPageSlab(page);
+		inc_page_state(nr_slab);
 		page++;
 	} while (--i);
 
@@ -1545,8 +1547,7 @@
 		STATS_INC_FREEMISS(cachep);
 		batchcount = cachep->batchcount;
 		cc->avail -= batchcount;
-		free_block(cachep,
-					&cc_entry(cc)[cc->avail],batchcount);
+		free_block(cachep, &cc_entry(cc)[cc->avail], batchcount);
 		cc_entry(cc)[cc->avail++] = objp;
 		return;
 	} else {
@@ -1727,8 +1728,13 @@
 	return 0;
 }
 
+/* 
+ * If slab debugging is enabled, don't batch slabs
+ * on the per-cpu lists by defaults.
+ */
 static void enable_cpucache (kmem_cache_t *cachep)
 {
+#ifndef CONFIG_DEBUG_SLAB
 	int err;
 	int limit;
 
@@ -1746,6 +1752,7 @@
 	if (err)
 		printk(KERN_ERR "enable_cpucache failed for %s, error %d.\n",
 					cachep->name, -err);
+#endif
 }
 
 static void enable_all_cpucaches (void)
diff -Nru a/mm/swap.c b/mm/swap.c
--- a/mm/swap.c	Fri Sep 20 08:20:44 2002
+++ b/mm/swap.c	Fri Sep 20 08:20:44 2002
@@ -124,9 +124,9 @@
 		if (page_count(page) == 0) {
 			if (!pagevec_add(&pages_to_free, page)) {
 				spin_unlock_irq(&zone->lru_lock);
-				pagevec_free(&pages_to_free);
+				__pagevec_free(&pages_to_free);
 				pagevec_init(&pages_to_free);
-				spin_lock_irq(&zone->lru_lock);
+				zone = NULL;	/* No lock is held */
 			}
 		}
 	}
@@ -165,8 +165,8 @@
 }
 
 /*
- * Move all the inactive pages to the head of the inactive list
- * and release them.  Reinitialises the caller's pagevec.
+ * Move all the inactive pages to the head of the inactive list and release
+ * them.  Reinitialises the caller's pagevec.
  */
 void pagevec_deactivate_inactive(struct pagevec *pvec)
 {
@@ -180,8 +180,6 @@
 		struct zone *pagezone = page_zone(page);
 
 		if (pagezone != zone) {
-			if (PageActive(page) || !PageLRU(page))
-				continue;
 			if (zone)
 				spin_unlock_irq(&zone->lru_lock);
 			zone = pagezone;
diff -Nru a/mm/swap_state.c b/mm/swap_state.c
--- a/mm/swap_state.c	Fri Sep 20 08:20:45 2002
+++ b/mm/swap_state.c	Fri Sep 20 08:20:45 2002
@@ -12,7 +12,6 @@
 #include <linux/swap.h>
 #include <linux/init.h>
 #include <linux/pagemap.h>
-#include <linux/smp_lock.h>
 #include <linux/backing-dev.h>
 #include <linux/buffer_head.h>	/* block_sync_page() */
 
@@ -119,7 +118,7 @@
 int add_to_swap(struct page * page)
 {
 	swp_entry_t entry;
-	int flags;
+	int pf_flags;
 
 	if (!PageLocked(page))
 		BUG();
@@ -142,7 +141,7 @@
 		 * just not all of them.
 		 */
 
-		flags = current->flags;
+		pf_flags = current->flags;
 		current->flags &= ~PF_MEMALLOC;
 		current->flags |= PF_NOWARN;
 		ClearPageUptodate(page);		/* why? */
@@ -154,20 +153,20 @@
 		 */
 		switch (add_to_swap_cache(page, entry)) {
 		case 0:				/* Success */
-			current->flags = flags;
+			current->flags = pf_flags;
 			SetPageUptodate(page);
 			set_page_dirty(page);
 			swap_free(entry);
 			return 1;
 		case -ENOMEM:			/* radix-tree allocation */
-			current->flags = flags;
+			current->flags = pf_flags;
 			swap_free(entry);
 			return 0;
 		default:			/* ENOENT: raced */
 			break;
 		}
 		/* Raced with "speculative" read_swap_cache_async */
-		current->flags = flags;
+		current->flags = pf_flags;
 		swap_free(entry);
 	}
 }
diff -Nru a/mm/swapfile.c b/mm/swapfile.c
--- a/mm/swapfile.c	Fri Sep 20 08:20:43 2002
+++ b/mm/swapfile.c	Fri Sep 20 08:20:43 2002
@@ -7,7 +7,6 @@
 
 #include <linux/mm.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/kernel_stat.h>
 #include <linux/swap.h>
 #include <linux/vmalloc.h>
diff -Nru a/mm/vmscan.c b/mm/vmscan.c
--- a/mm/vmscan.c	Fri Sep 20 08:20:42 2002
+++ b/mm/vmscan.c	Fri Sep 20 08:20:42 2002
@@ -15,7 +15,6 @@
 #include <linux/slab.h>
 #include <linux/kernel_stat.h>
 #include <linux/swap.h>
-#include <linux/smp_lock.h>
 #include <linux/pagemap.h>
 #include <linux/init.h>
 #include <linux/highmem.h>
@@ -145,6 +144,7 @@
 			if (!add_to_swap(page))
 				goto activate_locked;
 			pte_chain_lock(page);
+			mapping = page->mapping;
 		}
 
 		/*
@@ -174,15 +174,18 @@
 		 */
 		if (PageDirty(page) && is_page_cache_freeable(page) &&
 					mapping && may_enter_fs) {
-			int (*writeback)(struct page *, int *);
+			int (*writeback)(struct page *,
+					struct writeback_control *);
 			const int cluster_size = SWAP_CLUSTER_MAX;
-			int nr_to_write = cluster_size;
+			struct writeback_control wbc = {
+				.nr_to_write = cluster_size,
+			};
 
 			writeback = mapping->a_ops->vm_writeback;
 			if (writeback == NULL)
 				writeback = generic_vm_writeback;
-			(*writeback)(page, &nr_to_write);
-			*max_scan -= (cluster_size - nr_to_write);
+			(*writeback)(page, &wbc);
+			*max_scan -= (cluster_size - wbc.nr_to_write);
 			goto keep;
 		}
 
diff -Nru a/net/Config.in b/net/Config.in
--- a/net/Config.in	Fri Sep 20 08:20:43 2002
+++ b/net/Config.in	Fri Sep 20 08:20:43 2002
@@ -65,6 +65,9 @@
    source net/decnet/Config.in
 fi
 dep_tristate '802.1d Ethernet Bridging' CONFIG_BRIDGE $CONFIG_INET
+if [ "$CONFIG_BRIDGE" != "n" -a "$CONFIG_NETFILTER" != "n" ]; then
+   source net/bridge/netfilter/Config.in
+fi
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25
    tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB
diff -Nru a/net/Makefile b/net/Makefile
--- a/net/Makefile	Fri Sep 20 08:20:45 2002
+++ b/net/Makefile	Fri Sep 20 08:20:45 2002
@@ -5,9 +5,6 @@
 # Rewritten to use lists instead of if-statements.
 #
 
-O_TARGET :=	network.o
-
-
 export-objs :=	netsyms.o
 
 obj-y	:= socket.o core/
diff -Nru a/net/ax25/Config.in b/net/ax25/Config.in
--- a/net/ax25/Config.in	Fri Sep 20 08:20:47 2002
+++ b/net/ax25/Config.in	Fri Sep 20 08:20:47 2002
@@ -1,7 +1,7 @@
 #
 # Amateur Radio protocols and AX.25 device configuration
 #
-# 19971130	Now in an own category to make correct compilation of the 
+# 19971130	Now in an own category to make correct compilation of the
 #		AX.25 stuff easier...
 #		Joerg Reuter DL1BKE <jreuter@yaina.de>
 # 19980129	Moved to net/ax25/Config.in, sourcing device drivers.
diff -Nru a/net/ax25/TODO b/net/ax25/TODO
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ax25/TODO	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,24 @@
+Do the ax25_list_lock, ax25_dev_lock, linkfail_lockreally, ax25_frag_lock and
+listen_lock have to be bh-safe?
+
+Do the netrom and rose locks have to be bh-safe?
+
+A device might be deleted after lookup in the SIOCADDRT ioctl but before it's
+being used.
+
+Routes to a device being taken down might be deleted by ax25_rt_device_down
+but added by somebody else before the device has been deleted fully.
+
+Massive amounts of lock_kernel / unlock_kernel are just a temporary solution to
+get around the removal of SOCKOPS_WRAP.  A serious locking strategy has to be
+implemented.
+
+The ax25_rt_find_route synopsys is pervert but I somehow had to deal with
+the race caused by the static variable in it's previous implementation.
+
+Implement proper socket locking in netrom and rose.
+
+Check socket locking when ax25_rcv is sending to raw sockets.  In particular
+ax25_send_to_raw() seems fishy.  Heck - ax25_rcv is fishy.
+
+Handle XID and TEST frames properly.
diff -Nru a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
--- a/net/ax25/af_ax25.c	Fri Sep 20 08:20:47 2002
+++ b/net/ax25/af_ax25.c	Fri Sep 20 08:20:47 2002
@@ -1,109 +1,18 @@
 /*
- *	AX.25 release 038
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	History
- *	AX.25 006	Alan(GW4PTS)		Nearly died of shock - it's working 8-)
- *	AX.25 007	Alan(GW4PTS)		Removed the silliest bugs
- *	AX.25 008	Alan(GW4PTS)		Cleaned up, fixed a few state machine problems, added callbacks
- *	AX.25 009	Alan(GW4PTS)		Emergency patch kit to fix memory corruption
- * 	AX.25 010	Alan(GW4PTS)		Added RAW sockets/Digipeat.
- *	AX.25 011	Alan(GW4PTS)		RAW socket and datagram fixes (thanks) - Raw sendto now gets PID right
- *						datagram sendto uses correct target address.
- *	AX.25 012	Alan(GW4PTS)		Correct incoming connection handling, send DM to failed connects.
- *						Use skb->data not skb+1. Support sk->priority correctly.
- *						Correct receive on SOCK_DGRAM.
- *	AX.25 013	Alan(GW4PTS)		Send DM to all unknown frames, missing initialiser fixed
- *						Leave spare SSID bits set (DAMA etc) - thanks for bug report,
- *						removed device registration (it's not used or needed). Clean up for
- *						gcc 2.5.8. PID to AX25_P_
- *	AX.25 014	Alan(GW4PTS)		Cleanup and NET3 merge
- *	AX.25 015	Alan(GW4PTS)		Internal test version.
- *	AX.25 016	Alan(GW4PTS)		Semi Internal version for PI card
- *						work.
- *	AX.25 017	Alan(GW4PTS)		Fixed some small bugs reported by
- *						G4KLX
- *	AX.25 018	Alan(GW4PTS)		Fixed a small error in SOCK_DGRAM
- *	AX.25 019	Alan(GW4PTS)		Clean ups for the non INET kernel and device ioctls in AX.25
- *	AX.25 020	Jonathan(G4KLX)		/proc support and other changes.
- *	AX.25 021	Alan(GW4PTS)		Added AX25_T1, AX25_N2, AX25_T3 as requested.
- *	AX.25 022	Jonathan(G4KLX)		More work on the ax25 auto router and /proc improved (again)!
- *			Alan(GW4PTS)		Added TIOCINQ/OUTQ
- *	AX.25 023	Alan(GW4PTS)		Fixed shutdown bug
- *	AX.25 023	Alan(GW4PTS)		Linus changed timers
- *	AX.25 024	Alan(GW4PTS)		Small bug fixes
- *	AX.25 025	Alan(GW4PTS)		More fixes, Linux 1.1.51 compatibility stuff, timers again!
- *	AX.25 026	Alan(GW4PTS)		Small state fix.
- *	AX.25 027	Alan(GW4PTS)		Socket close crash fixes.
- *	AX.25 028	Alan(GW4PTS)		Callsign control including settings per uid.
- *						Small bug fixes.
- *						Protocol set by sockets only.
- *						Small changes to allow for start of NET/ROM layer.
- *	AX.25 028a	Jonathan(G4KLX)		Changes to state machine.
- *	AX.25 028b	Jonathan(G4KLX)		Extracted ax25 control block
- *						from sock structure.
- *	AX.25 029	Alan(GW4PTS)		Combined 028b and some KA9Q code
- *			Jonathan(G4KLX)		and removed all the old Berkeley, added IP mode registration.
- *			Darryl(G7LED)		stuff. Cross-port digipeating. Minor fixes and enhancements.
- *			Alan(GW4PTS)		Missed suser() on axassociate checks
- *	AX.25 030	Alan(GW4PTS)		Added variable length headers.
- *			Jonathan(G4KLX)		Added BPQ Ethernet interface.
- *			Steven(GW7RRM)		Added digi-peating control ioctl.
- *						Added extended AX.25 support.
- *						Added AX.25 frame segmentation.
- *			Darryl(G7LED)		Changed connect(), recvfrom(), sendto() sockaddr/addrlen to
- *						fall inline with bind() and new policy.
- *						Moved digipeating ctl to new ax25_dev structs.
- *						Fixed ax25_release(), set TCP_CLOSE, wakeup app
- *						context, THEN make the sock dead.
- *			Alan(GW4PTS)		Cleaned up for single recvmsg methods.
- *			Alan(GW4PTS)		Fixed not clearing error on connect failure.
- *	AX.25 031	Jonathan(G4KLX)		Added binding to any device.
- *			Joerg(DL1BKE)		Added DAMA support, fixed (?) digipeating, fixed buffer locking
- *						for "virtual connect" mode... Result: Probably the
- *						"Most Buggiest Code You've Ever Seen" (TM)
- *			HaJo(DD8NE)		Implementation of a T5 (idle) timer
- *			Joerg(DL1BKE)		Renamed T5 to IDLE and changed behaviour:
- *						the timer gets reloaded on every received or transmitted
- *						I frame for IP or NETROM. The idle timer is not active
- *						on "vanilla AX.25" connections. Furthermore added PACLEN
- *						to provide AX.25-layer based fragmentation (like WAMPES)
- *      AX.25 032	Joerg(DL1BKE)		Fixed DAMA timeout error.
- *						ax25_send_frame() limits the number of enqueued
- *						datagrams per socket.
- *	AX.25 033	Jonathan(G4KLX)		Removed auto-router.
- *			Hans(PE1AYX)		Converted to Module.
- *			Joerg(DL1BKE)		Moved BPQ Ethernet to separate driver.
- *	AX.25 034	Jonathan(G4KLX)		2.1 changes
- *			Alan(GW4PTS)		Small POSIXisations
- *	AX.25 035	Alan(GW4PTS)		Started fixing to the new
- *						format.
- *			Hans(PE1AYX)		Fixed interface to IP layer.
- *			Alan(GW4PTS)		Added asynchronous support.
- *			Frederic(F1OAT)		Support for pseudo-digipeating.
- *			Jonathan(G4KLX)		Support for packet forwarding.
- *	AX.25 036	Jonathan(G4KLX)		Major restructuring.
- *			Joerg(DL1BKE)		Fixed DAMA Slave.
- *			Jonathan(G4KLX)		Fix wildcard listen parameter setting.
- *	AX.25 037	Jonathan(G4KLX)		New timer architecture.
- *      AX.25 038       Matthias(DG2FEF)        Small fixes to the syscall interface to make kernel
- *                                              independent of AX25_MAX_DIGIS used by applications.
- *                      Tomi(OH2BNS)            Fixed ax25_getname().
- *			Joerg(DL1BKE)		Starting to phase out the support for full_sockaddr_ax25
- *						with only 6 digipeaters and sockaddr_ax25 in ax25_bind(),
- *						ax25_connect() and ax25_sendmsg()
- *			Joerg(DL1BKE)		Added support for SO_BINDTODEVICE
- *			Arnaldo C. Melo		s/suser/capable(CAP_NET_ADMIN)/, some more cleanups
- *			Michal Ostrowski	Module initialization cleanup.
+ * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright (C) Darryl Miles G7LED (dlm@g7led.demon.co.uk)
+ * Copyright (C) Steven Whitehouse GW7RRM (stevew@acm.org)
+ * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
+ * Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
+ * Copyright (C) Hans Alblas PE1AYX (hans@esrac.ele.tue.nl)
+ * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
  */
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/errno.h>
@@ -114,6 +23,7 @@
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/string.h>
+#include <linux/smp_lock.h>
 #include <linux/sockios.h>
 #include <linux/net.h>
 #include <net/ax25.h>
@@ -134,13 +44,15 @@
 #include <linux/netfilter.h>
 #include <linux/sysctl.h>
 #include <linux/init.h>
+#include <linux/spinlock.h>
 #include <net/tcp.h>
 #include <net/ip.h>
 #include <net/arp.h>
 
 
 
-ax25_cb *volatile ax25_list;
+ax25_cb *ax25_list;
+spinlock_t ax25_list_lock = SPIN_LOCK_UNLOCKED;
 
 static struct proto_ops ax25_proto_ops;
 
@@ -171,27 +83,24 @@
 static void ax25_remove_socket(ax25_cb *ax25)
 {
 	ax25_cb *s;
-	unsigned long flags;
-
-	save_flags(flags); cli();
 
+	spin_lock_bh(&ax25_list_lock);
 	if ((s = ax25_list) == ax25) {
 		ax25_list = s->next;
-		restore_flags(flags);
+		spin_unlock_bh(&ax25_list_lock);
 		return;
 	}
 
 	while (s != NULL && s->next != NULL) {
 		if (s->next == ax25) {
 			s->next = ax25->next;
-			restore_flags(flags);
+			spin_unlock_bh(&ax25_list_lock);
 			return;
 		}
 
 		s = s->next;
 	}
-
-	restore_flags(flags);
+	spin_unlock_bh(&ax25_list_lock);
 }
 
 /*
@@ -205,18 +114,21 @@
 	if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
 		return;
 
+	spin_lock_bh(&ax25_list_lock);
 	for (s = ax25_list; s != NULL; s = s->next) {
 		if (s->ax25_dev == ax25_dev) {
 			s->ax25_dev = NULL;
 			ax25_disconnect(s, ENETUNREACH);
 		}
 	}
+	spin_unlock_bh(&ax25_list_lock);
 }
 
 /*
  *	Handle device status changes.
  */
-static int ax25_device_event(struct notifier_block *this,unsigned long event, void *ptr)
+static int ax25_device_event(struct notifier_block *this, unsigned long event,
+	void *ptr)
 {
 	struct net_device *dev = (struct net_device *)ptr;
 
@@ -225,16 +137,16 @@
 		return NOTIFY_DONE;
 
 	switch (event) {
-		case NETDEV_UP:
-			ax25_dev_device_up(dev);
-			break;
-		case NETDEV_DOWN:
-			ax25_kill_by_device(dev);
-			ax25_rt_device_down(dev);
-			ax25_dev_device_down(dev);
-			break;
-		default:
-			break;
+	case NETDEV_UP:
+		ax25_dev_device_up(dev);
+		break;
+	case NETDEV_DOWN:
+		ax25_kill_by_device(dev);
+		ax25_rt_device_down(dev);
+		ax25_dev_device_down(dev);
+		break;
+	default:
+		break;
 	}
 
 	return NOTIFY_DONE;
@@ -245,80 +157,73 @@
  */
 void ax25_insert_socket(ax25_cb *ax25)
 {
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-
+	spin_lock_bh(&ax25_list_lock);
 	ax25->next = ax25_list;
 	ax25_list  = ax25;
-
-	restore_flags(flags);
+	spin_unlock_bh(&ax25_list_lock);
 }
 
 /*
  *	Find a socket that wants to accept the SABM we have just
  *	received.
  */
-struct sock *ax25_find_listener(ax25_address *addr, int digi, struct net_device *dev, int type)
+struct sock *ax25_find_listener(ax25_address *addr, int digi,
+	struct net_device *dev, int type)
 {
-	unsigned long flags;
 	ax25_cb *s;
 
-	save_flags(flags);
-	cli();
-
+	spin_lock_bh(&ax25_list_lock);
 	for (s = ax25_list; s != NULL; s = s->next) {
 		if ((s->iamdigi && !digi) || (!s->iamdigi && digi))
 			continue;
 		if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 && s->sk->type == type && s->sk->state == TCP_LISTEN) {
 			/* If device is null we match any device */
 			if (s->ax25_dev == NULL || s->ax25_dev->dev == dev) {
-				restore_flags(flags);
+				spin_unlock_bh(&ax25_list_lock);
+
 				return s->sk;
 			}
 		}
 	}
+	spin_unlock_bh(&ax25_list_lock);
 
-	restore_flags(flags);
 	return NULL;
 }
 
 /*
  *	Find an AX.25 socket given both ends.
  */
-struct sock *ax25_find_socket(ax25_address *my_addr, ax25_address *dest_addr, int type)
+struct sock *ax25_get_socket(ax25_address *my_addr, ax25_address *dest_addr,
+	int type)
 {
+	struct sock *sk = NULL;
 	ax25_cb *s;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
 
+	spin_lock_bh(&ax25_list_lock);
 	for (s = ax25_list; s != NULL; s = s->next) {
 		if (s->sk != NULL && ax25cmp(&s->source_addr, my_addr) == 0 && ax25cmp(&s->dest_addr, dest_addr) == 0 && s->sk->type == type) {
-			restore_flags(flags);
-			return s->sk;
+			sk = s->sk;
+			/* XXX Sleeps with spinlock held, use refcounts instead. XXX */
+			lock_sock(sk);
+			break;
 		}
 	}
 
-	restore_flags(flags);
+	spin_unlock_bh(&ax25_list_lock);
 
-	return NULL;
+	return sk;
 }
 
 /*
  *	Find an AX.25 control block given both ends. It will only pick up
  *	floating AX.25 control blocks or non Raw socket bound control blocks.
  */
-ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr, ax25_digi *digi, struct net_device *dev)
+ax25_cb *ax25_find_cb(ax25_address *src_addr, ax25_address *dest_addr,
+	ax25_digi *digi, struct net_device *dev)
 {
 	ax25_cb *s;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
 
+	spin_lock_bh(&ax25_list_lock);
 	for (s = ax25_list; s != NULL; s = s->next) {
 		if (s->sk != NULL && s->sk->type != SOCK_SEQPACKET)
 			continue;
@@ -334,12 +239,12 @@
 				if (s->digipeat != NULL && s->digipeat->ndigi != 0)
 					continue;
 			}
-			restore_flags(flags);
+			spin_unlock_bh(&ax25_list_lock);
+
 			return s;
 		}
 	}
-
-	restore_flags(flags);
+	spin_unlock_bh(&ax25_list_lock);
 
 	return NULL;
 }
@@ -349,22 +254,21 @@
  */
 struct sock *ax25_addr_match(ax25_address *addr)
 {
-	unsigned long flags;
+	struct sock *sk = NULL;
 	ax25_cb *s;
 
-	save_flags(flags);
-	cli();
-
+	spin_lock_bh(&ax25_list_lock);
 	for (s = ax25_list; s != NULL; s = s->next) {
-		if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 && s->sk->type == SOCK_RAW) {
-			restore_flags(flags);
-			return s->sk;
+		if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 &&
+		    s->sk->type == SOCK_RAW) {
+			sk = s->sk;
+			lock_sock(sk);
+			break;
 		}
 	}
+	spin_unlock_bh(&ax25_list_lock);
 
-	restore_flags(flags);
-
-	return NULL;
+	return sk;
 }
 
 void ax25_send_to_raw(struct sock *sk, struct sk_buff *skb, int proto)
@@ -400,17 +304,16 @@
 }
 
 /*
- *	This is called from user mode and the timers. Thus it protects itself against
- *	interrupt users but doesn't worry about being called during work.
- *	Once it is removed from the queue no interrupt or bottom half will
- *	touch it and we are (fairly 8-) ) safe.
+ *	This is called from user mode and the timers. Thus it protects itself
+ *	against interrupt users but doesn't worry about being called during
+ *	work. Once it is removed from the queue no interrupt or bottom half
+ *	will touch it and we are (fairly 8-) ) safe.
  */
-void ax25_destroy_socket(ax25_cb *ax25)	/* Not static as it's used by the timer */
+void ax25_destroy_socket(ax25_cb *ax25)
 {
 	struct sk_buff *skb;
-	unsigned long flags;
 
-	save_flags(flags); cli();
+	ax25_remove_socket(ax25);
 
 	ax25_stop_heartbeat(ax25);
 	ax25_stop_t1timer(ax25);
@@ -418,15 +321,17 @@
 	ax25_stop_t3timer(ax25);
 	ax25_stop_idletimer(ax25);
 
-	ax25_remove_socket(ax25);
 	ax25_clear_queues(ax25);	/* Flush the queues */
 
 	if (ax25->sk != NULL) {
 		while ((skb = skb_dequeue(&ax25->sk->receive_queue)) != NULL) {
-			if (skb->sk != ax25->sk) {			/* A pending connection */
+			if (skb->sk != ax25->sk) {
+				/* A pending connection */
 				ax25_cb *sax25 = ax25_sk(skb->sk);
 
-				skb->sk->dead = 1;	/* Queue the unaccepted socket for death */
+				/* Queue the unaccepted socket for death */
+				skb->sk->dead = 1;
+
 				ax25_start_heartbeat(sax25);
 				sax25->state = AX25_STATE_0;
 			}
@@ -450,8 +355,6 @@
 	} else {
 		ax25_free_cb(ax25);
 	}
-
-	restore_flags(flags);
 }
 
 /*
@@ -484,66 +387,66 @@
 		return -ENOTCONN;
 
 	switch (ax25_ctl.cmd) {
-		case AX25_KILL:
-			ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+	case AX25_KILL:
+		ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
 #ifdef CONFIG_AX25_DAMA_SLAVE
-			if (ax25_dev->dama.slave && ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE)
-				ax25_dama_off(ax25);
+		if (ax25_dev->dama.slave && ax25->ax25_dev->values[AX25_VALUES_PROTOCOL] == AX25_PROTO_DAMA_SLAVE)
+			ax25_dama_off(ax25);
 #endif
-			ax25_disconnect(ax25, ENETRESET);
-			break;
-
-	  	case AX25_WINDOW:
-	  		if (ax25->modulus == AX25_MODULUS) {
-	  			if (ax25_ctl.arg < 1 || ax25_ctl.arg > 7)
-	  				return -EINVAL;
-	  		} else {
-	  			if (ax25_ctl.arg < 1 || ax25_ctl.arg > 63)
-	  				return -EINVAL;
-	  		}
-	  		ax25->window = ax25_ctl.arg;
-	  		break;
+		ax25_disconnect(ax25, ENETRESET);
+		break;
 
-	  	case AX25_T1:
-  			if (ax25_ctl.arg < 1)
+  	case AX25_WINDOW:
+  		if (ax25->modulus == AX25_MODULUS) {
+  			if (ax25_ctl.arg < 1 || ax25_ctl.arg > 7)
   				return -EINVAL;
-  			ax25->rtt = (ax25_ctl.arg * HZ) / 2;
-  			ax25->t1  = ax25_ctl.arg * HZ;
-  			break;
-
-	  	case AX25_T2:
-	  		if (ax25_ctl.arg < 1)
-	  			return -EINVAL;
-	  		ax25->t2 = ax25_ctl.arg * HZ;
-	  		break;
-
-	  	case AX25_N2:
-	  		if (ax25_ctl.arg < 1 || ax25_ctl.arg > 31)
-	  			return -EINVAL;
-	  		ax25->n2count = 0;
-	  		ax25->n2 = ax25_ctl.arg;
-	  		break;
-
-	  	case AX25_T3:
-	  		if (ax25_ctl.arg < 0)
-	  			return -EINVAL;
-	  		ax25->t3 = ax25_ctl.arg * HZ;
-	  		break;
-
-	  	case AX25_IDLE:
-	  		if (ax25_ctl.arg < 0)
-	  			return -EINVAL;
-	  		ax25->idle = ax25_ctl.arg * 60 * HZ;
-	  		break;
-
-	  	case AX25_PACLEN:
-	  		if (ax25_ctl.arg < 16 || ax25_ctl.arg > 65535)
-	  			return -EINVAL;
-	  		ax25->paclen = ax25_ctl.arg;
-	  		break;
+  		} else {
+  			if (ax25_ctl.arg < 1 || ax25_ctl.arg > 63)
+  				return -EINVAL;
+  		}
+  		ax25->window = ax25_ctl.arg;
+  		break;
+
+  	case AX25_T1:
+		if (ax25_ctl.arg < 1)
+  			return -EINVAL;
+  		ax25->rtt = (ax25_ctl.arg * HZ) / 2;
+  		ax25->t1  = ax25_ctl.arg * HZ;
+  		break;
+
+  	case AX25_T2:
+  		if (ax25_ctl.arg < 1)
+  			return -EINVAL;
+  		ax25->t2 = ax25_ctl.arg * HZ;
+  		break;
+
+  	case AX25_N2:
+  		if (ax25_ctl.arg < 1 || ax25_ctl.arg > 31)
+  			return -EINVAL;
+  		ax25->n2count = 0;
+  		ax25->n2 = ax25_ctl.arg;
+  		break;
+
+  	case AX25_T3:
+  		if (ax25_ctl.arg < 0)
+  			return -EINVAL;
+  		ax25->t3 = ax25_ctl.arg * HZ;
+  		break;
+
+  	case AX25_IDLE:
+  		if (ax25_ctl.arg < 0)
+  			return -EINVAL;
+  		ax25->idle = ax25_ctl.arg * 60 * HZ;
+  		break;
+
+  	case AX25_PACLEN:
+  		if (ax25_ctl.arg < 16 || ax25_ctl.arg > 65535)
+  			return -EINVAL;
+  		ax25->paclen = ax25_ctl.arg;
+  		break;
 
-	  	default:
-	  		return -EINVAL;
+  	default:
+  		return -EINVAL;
 	  }
 
 	  return 0;
@@ -631,13 +534,14 @@
  *	AX25 socket object
  */
 
-static int ax25_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
+static int ax25_setsockopt(struct socket *sock, int level, int optname,
+	char *optval, int optlen)
 {
 	struct sock *sk = sock->sk;
-	ax25_cb *ax25 = ax25_sk(sk);
+	ax25_cb *ax25;
 	struct net_device *dev;
 	char devname[IFNAMSIZ];
-	int opt;
+	int opt, res = 0;
 
 	if (level != SOL_AX25)
 		return -ENOPROTOOPT;
@@ -648,98 +552,131 @@
 	if (get_user(opt, (int *)optval))
 		return -EFAULT;
 
+	lock_sock(sk);
+	ax25 = ax25_sk(sk);
+
 	switch (optname) {
-		case AX25_WINDOW:
-			if (ax25->modulus == AX25_MODULUS) {
-				if (opt < 1 || opt > 7)
-					return -EINVAL;
-			} else {
-				if (opt < 1 || opt > 63)
-					return -EINVAL;
+	case AX25_WINDOW:
+		if (ax25->modulus == AX25_MODULUS) {
+			if (opt < 1 || opt > 7) {
+				res = -EINVAL;
+				break;
 			}
-			ax25->window = opt;
-			return 0;
+		} else {
+			if (opt < 1 || opt > 63) {
+				res = -EINVAL;
+				break;
+			}
+		}
+		ax25->window = opt;
+		break;
+
+	case AX25_T1:
+		if (opt < 1) {
+			res = -EINVAL;
+			break;
+		}
+		ax25->rtt = (opt * HZ) / 2;
+		ax25->t1  = opt * HZ;
+		break;
 
-		case AX25_T1:
-			if (opt < 1)
-				return -EINVAL;
-			ax25->rtt = (opt * HZ) / 2;
-			ax25->t1  = opt * HZ;
-			return 0;
-
-		case AX25_T2:
-			if (opt < 1)
-				return -EINVAL;
-			ax25->t2 = opt * HZ;
-			return 0;
-
-		case AX25_N2:
-			if (opt < 1 || opt > 31)
-				return -EINVAL;
-			ax25->n2 = opt;
-			return 0;
-
-		case AX25_T3:
-			if (opt < 1)
-				return -EINVAL;
-			ax25->t3 = opt * HZ;
-			return 0;
-
-		case AX25_IDLE:
-			if (opt < 0)
-				return -EINVAL;
-			ax25->idle = opt * 60 * HZ;
-			return 0;
-
-		case AX25_BACKOFF:
-			if (opt < 0 || opt > 2)
-				return -EINVAL;
-			ax25->backoff = opt;
-			return 0;
-
-		case AX25_EXTSEQ:
-			ax25->modulus = opt ? AX25_EMODULUS : AX25_MODULUS;
-			return 0;
-
-		case AX25_PIDINCL:
-			ax25->pidincl = opt ? 1 : 0;
-			return 0;
-
-		case AX25_IAMDIGI:
-			ax25->iamdigi = opt ? 1 : 0;
-			return 0;
-
-		case AX25_PACLEN:
-			if (opt < 16 || opt > 65535)
-				return -EINVAL;
-			ax25->paclen = opt;
-			return 0;
-
-		case SO_BINDTODEVICE:
-			if (optlen > IFNAMSIZ) optlen=IFNAMSIZ;
-			if (copy_from_user(devname, optval, optlen))
-				return -EFAULT;
-
-			dev = dev_get_by_name(devname);
-			if (dev == NULL) return -ENODEV;
-
-			if (sk->type == SOCK_SEQPACKET && 
-			   (sock->state != SS_UNCONNECTED || sk->state == TCP_LISTEN))
-				return -EADDRNOTAVAIL;
-		
-			ax25->ax25_dev = ax25_dev_ax25dev(dev);
-			ax25_fillin_cb(ax25, ax25->ax25_dev);
-			return 0;
+	case AX25_T2:
+		if (opt < 1) {
+			res = -EINVAL;
+			break;
+		}
+		ax25->t2 = opt * HZ;
+		break;
 
-		default:
-			return -ENOPROTOOPT;
+	case AX25_N2:
+		if (opt < 1 || opt > 31) {
+			res = -EINVAL;
+			break;
+		}
+		ax25->n2 = opt;
+		break;
+
+	case AX25_T3:
+		if (opt < 1) {
+			res = -EINVAL;
+			break;
+		}
+		ax25->t3 = opt * HZ;
+		break;
+
+	case AX25_IDLE:
+		if (opt < 0) {
+			res = -EINVAL;
+			break;
+		}
+		ax25->idle = opt * 60 * HZ;
+		break;
+
+	case AX25_BACKOFF:
+		if (opt < 0 || opt > 2) {
+			res = -EINVAL;
+			break;
+		}
+		ax25->backoff = opt;
+		break;
+
+	case AX25_EXTSEQ:
+		ax25->modulus = opt ? AX25_EMODULUS : AX25_MODULUS;
+		break;
+
+	case AX25_PIDINCL:
+		ax25->pidincl = opt ? 1 : 0;
+		break;
+
+	case AX25_IAMDIGI:
+		ax25->iamdigi = opt ? 1 : 0;
+		break;
+
+	case AX25_PACLEN:
+		if (opt < 16 || opt > 65535) {
+			res = -EINVAL;
+			break;
+		}
+		ax25->paclen = opt;
+		break;
+
+	case SO_BINDTODEVICE:
+		if (optlen > IFNAMSIZ)
+			optlen=IFNAMSIZ;
+		if (copy_from_user(devname, optval, optlen)) {
+		res = -EFAULT;
+			break;
+		}
+
+		dev = dev_get_by_name(devname);
+		if (dev == NULL) {
+			res = -ENODEV;
+			break;
+		}
+
+		if (sk->type == SOCK_SEQPACKET &&
+		   (sock->state != SS_UNCONNECTED || sk->state == TCP_LISTEN)) {
+			res = -EADDRNOTAVAIL;
+			break;
+		}
+
+		ax25->ax25_dev = ax25_dev_ax25dev(dev);
+		ax25_fillin_cb(ax25, ax25->ax25_dev);
+		break;
+
+	default:
+		res = -ENOPROTOOPT;
 	}
+	release_sock(sk);
+
+	return res;
 }
 
-static int ax25_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
+static int ax25_getsockopt(struct socket *sock, int level, int optname,
+	char *optval, int *optlen)
 {
 	struct sock *sk = sock->sk;
-	ax25_cb *ax25 = ax25_sk(sk);
+	ax25_cb *ax25;
 	struct ax25_dev *ax25_dev;
 	char devname[IFNAMSIZ];
 	void *valptr;
@@ -751,76 +688,81 @@
 
 	if (get_user(maxlen, optlen))
 		return -EFAULT;
-		
+
 	if (maxlen < 1)
 		return -EFAULT;
 
 	valptr = (void *) &val;
 	length = min_t(unsigned int, maxlen, sizeof(int));
 
-	switch (optname) {
-		case AX25_WINDOW:
-			val = ax25->window;
-			break;
-
-		case AX25_T1:
-			val = ax25->t1 / HZ;
-			break;
-
-		case AX25_T2:
-			val = ax25->t2 / HZ;
-			break;
-
-		case AX25_N2:
-			val = ax25->n2;
-			break;
-
-		case AX25_T3:
-			val = ax25->t3 / HZ;
-			break;
-
-		case AX25_IDLE:
-			val = ax25->idle / (60 * HZ);
-			break;
-
-		case AX25_BACKOFF:
-			val = ax25->backoff;
-			break;
-
-		case AX25_EXTSEQ:
-			val = (ax25->modulus == AX25_EMODULUS);
-			break;
-
-		case AX25_PIDINCL:
-			val = ax25->pidincl;
-			break;
-
-		case AX25_IAMDIGI:
-			val = ax25->iamdigi;
-			break;
-
-		case AX25_PACLEN:
-			val = ax25->paclen;
-			break;
-			
-		case SO_BINDTODEVICE:
-			ax25_dev = ax25->ax25_dev;
+	lock_sock(sk);
+	ax25 = ax25_sk(sk);
 
-			if (ax25_dev != NULL && ax25_dev->dev != NULL) {
-				strncpy(devname, ax25_dev->dev->name, IFNAMSIZ);
-				length = min_t(unsigned int, strlen(ax25_dev->dev->name)+1, maxlen);
-				devname[length-1] = '\0';
-			} else {
-				*devname = '\0';
-				length = 1;
-			}
+	switch (optname) {
+	case AX25_WINDOW:
+		val = ax25->window;
+		break;
+
+	case AX25_T1:
+		val = ax25->t1 / HZ;
+		break;
+
+	case AX25_T2:
+		val = ax25->t2 / HZ;
+		break;
+
+	case AX25_N2:
+		val = ax25->n2;
+		break;
+
+	case AX25_T3:
+		val = ax25->t3 / HZ;
+		break;
+
+	case AX25_IDLE:
+		val = ax25->idle / (60 * HZ);
+		break;
+
+	case AX25_BACKOFF:
+		val = ax25->backoff;
+		break;
+
+	case AX25_EXTSEQ:
+		val = (ax25->modulus == AX25_EMODULUS);
+		break;
+
+	case AX25_PIDINCL:
+		val = ax25->pidincl;
+		break;
+
+	case AX25_IAMDIGI:
+		val = ax25->iamdigi;
+		break;
+
+	case AX25_PACLEN:
+		val = ax25->paclen;
+		break;
+
+	case SO_BINDTODEVICE:
+		ax25_dev = ax25->ax25_dev;
+
+		if (ax25_dev != NULL && ax25_dev->dev != NULL) {
+			strncpy(devname, ax25_dev->dev->name, IFNAMSIZ);
+			length = min_t(unsigned int, strlen(ax25_dev->dev->name)+1, maxlen);
+			devname[length-1] = '\0';
+		} else {
+			*devname = '\0';
+			length = 1;
+		}
 
-			valptr = (void *) devname;
-			break;
+		valptr = (void *) devname;
+		break;
 
-		default:
-			return -ENOPROTOOPT;
+	default:
+		release_sock(sk);
+		return -ENOPROTOOPT;
 	}
+	release_sock(sk);
 
 	if (put_user(length, optlen))
 		return -EFAULT;
@@ -831,14 +773,20 @@
 static int ax25_listen(struct socket *sock, int backlog)
 {
 	struct sock *sk = sock->sk;
+	int res = 0;
 
+	lock_sock(sk);
 	if (sk->type == SOCK_SEQPACKET && sk->state != TCP_LISTEN) {
 		sk->max_ack_backlog = backlog;
 		sk->state           = TCP_LISTEN;
-		return 0;
+		goto out;
 	}
+	res = -EOPNOTSUPP;
 
-	return -EOPNOTSUPP;
+out:
+	release_sock(sk);
+
+	return res;
 }
 
 int ax25_create(struct socket *sock, int protocol)
@@ -847,46 +795,48 @@
 	ax25_cb *ax25;
 
 	switch (sock->type) {
-		case SOCK_DGRAM:
-			if (protocol == 0 || protocol == PF_AX25)
-				protocol = AX25_P_TEXT;
-			break;
-		case SOCK_SEQPACKET:
-			switch (protocol) {
-				case 0:
-				case PF_AX25:	/* For CLX */
-					protocol = AX25_P_TEXT;
-					break;
-				case AX25_P_SEGMENT:
+	case SOCK_DGRAM:
+		if (protocol == 0 || protocol == PF_AX25)
+			protocol = AX25_P_TEXT;
+		break;
+
+	case SOCK_SEQPACKET:
+		switch (protocol) {
+		case 0:
+		case PF_AX25:	/* For CLX */
+			protocol = AX25_P_TEXT;
+			break;
+		case AX25_P_SEGMENT:
 #ifdef CONFIG_INET
-				case AX25_P_ARP:
-				case AX25_P_IP:
+		case AX25_P_ARP:
+		case AX25_P_IP:
 #endif
 #ifdef CONFIG_NETROM
-				case AX25_P_NETROM:
+		case AX25_P_NETROM:
 #endif
 #ifdef CONFIG_ROSE
-				case AX25_P_ROSE:
+		case AX25_P_ROSE:
 #endif
-					return -ESOCKTNOSUPPORT;
+			return -ESOCKTNOSUPPORT;
 #ifdef CONFIG_NETROM_MODULE
-				case AX25_P_NETROM:
-					if (ax25_protocol_is_registered(AX25_P_NETROM))
-						return -ESOCKTNOSUPPORT;
+		case AX25_P_NETROM:
+			if (ax25_protocol_is_registered(AX25_P_NETROM))
+				return -ESOCKTNOSUPPORT;
 #endif
 #ifdef CONFIG_ROSE_MODULE
-				case AX25_P_ROSE:
-					if (ax25_protocol_is_registered(AX25_P_ROSE))
-						return -ESOCKTNOSUPPORT;
+		case AX25_P_ROSE:
+			if (ax25_protocol_is_registered(AX25_P_ROSE))
+				return -ESOCKTNOSUPPORT;
 #endif
-				default:
-					break;
-			}
-			break;
-		case SOCK_RAW:
-			break;
 		default:
-			return -ESOCKTNOSUPPORT;
+			break;
+		}
+		break;
+
+	case SOCK_RAW:
+		break;
+	default:
+		return -ESOCKTNOSUPPORT;
 	}
 
 	if ((sk = sk_alloc(PF_AX25, GFP_ATOMIC, 1, NULL)) == NULL)
@@ -923,14 +873,14 @@
 	}
 
 	switch (osk->type) {
-		case SOCK_DGRAM:
-			break;
-		case SOCK_SEQPACKET:
-			break;
-		default:
-			sk_free(sk);
-			ax25_free_cb(ax25);
-			return NULL;
+	case SOCK_DGRAM:
+		break;
+	case SOCK_SEQPACKET:
+		break;
+	default:
+		sk_free(sk);
+		ax25_free_cb(ax25);
+		return NULL;
 	}
 
 	sock_init_data(NULL, sk);
@@ -985,58 +935,61 @@
 	struct sock *sk = sock->sk;
 	ax25_cb *ax25;
 
-	if (sk == NULL) return 0;
+	if (sk == NULL)
+		return 0;
 
+	lock_sock(sk);
 	ax25 = ax25_sk(sk);
 
 	if (sk->type == SOCK_SEQPACKET) {
 		switch (ax25->state) {
-			case AX25_STATE_0:
-				ax25_disconnect(ax25, 0);
-				ax25_destroy_socket(ax25);
-				break;
+		case AX25_STATE_0:
+			ax25_disconnect(ax25, 0);
+			ax25_destroy_socket(ax25);
+			break;
 
-			case AX25_STATE_1:
-			case AX25_STATE_2:
-				ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
-				ax25_disconnect(ax25, 0);
-				ax25_destroy_socket(ax25);
-				break;
+		case AX25_STATE_1:
+		case AX25_STATE_2:
+			ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+			ax25_disconnect(ax25, 0);
+			ax25_destroy_socket(ax25);
+			break;
 
-			case AX25_STATE_3:
-			case AX25_STATE_4:
-				ax25_clear_queues(ax25);
-				ax25->n2count = 0;
-				switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
-					case AX25_PROTO_STD_SIMPLEX:
-					case AX25_PROTO_STD_DUPLEX:
-						ax25_send_control(ax25,
-								  AX25_DISC,
-								  AX25_POLLON,
-								  AX25_COMMAND);
-						ax25_stop_t2timer(ax25);
-						ax25_stop_t3timer(ax25);
-						ax25_stop_idletimer(ax25);
-						break;
+		case AX25_STATE_3:
+		case AX25_STATE_4:
+			ax25_clear_queues(ax25);
+			ax25->n2count = 0;
+
+			switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
+			case AX25_PROTO_STD_SIMPLEX:
+			case AX25_PROTO_STD_DUPLEX:
+				ax25_send_control(ax25,
+						  AX25_DISC,
+						  AX25_POLLON,
+						  AX25_COMMAND);
+				ax25_stop_t2timer(ax25);
+				ax25_stop_t3timer(ax25);
+				ax25_stop_idletimer(ax25);
+				break;
 #ifdef CONFIG_AX25_DAMA_SLAVE
-					case AX25_PROTO_DAMA_SLAVE:
-						ax25_stop_t3timer(ax25);
-						ax25_stop_idletimer(ax25);
-						break;
-#endif
-				}
-				ax25_calculate_t1(ax25);
-				ax25_start_t1timer(ax25);
-				ax25->state = AX25_STATE_2;
-				sk->state                = TCP_CLOSE;
-				sk->shutdown            |= SEND_SHUTDOWN;
-				sk->state_change(sk);
-				sk->dead                 = 1;
-				sk->destroy              = 1;
+			case AX25_PROTO_DAMA_SLAVE:
+				ax25_stop_t3timer(ax25);
+				ax25_stop_idletimer(ax25);
 				break;
+#endif
+			}
+			ax25_calculate_t1(ax25);
+			ax25_start_t1timer(ax25);
+			ax25->state = AX25_STATE_2;
+			sk->state                = TCP_CLOSE;
+			sk->shutdown            |= SEND_SHUTDOWN;
+			sk->state_change(sk);
+			sk->dead                 = 1;
+			sk->destroy              = 1;
+			break;
 
-			default:
-				break;
+		default:
+			break;
 		}
 	} else {
 		sk->state     = TCP_CLOSE;
@@ -1046,8 +999,9 @@
 		ax25_destroy_socket(ax25);
 	}
 
-	sock->sk   = NULL;	
+	sock->sk   = NULL;
 	sk->socket = NULL;	/* Not used, but we should do this */
+	release_sock(sk);
 
 	return 0;
 }
@@ -1055,26 +1009,25 @@
 /*
  *	We support a funny extension here so you can (as root) give any callsign
  *	digipeated via a local address as source. This hack is obsolete now
- *	that we've implemented support for SO_BINDTODEVICE. It is however small 
+ *	that we've implemented support for SO_BINDTODEVICE. It is however small
  *	and trivially backward compatible.
  */
 static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
 	struct sock *sk = sock->sk;
-	ax25_cb *ax25 = ax25_sk(sk);
 	struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr;
-	ax25_address *call;
 	ax25_dev *ax25_dev = NULL;
+	ax25_address *call;
+	ax25_cb *ax25;
+	int err = 0;
 
-	if (sk->zapped == 0)
-		return -EINVAL;
-
-	if (addr_len != sizeof(struct sockaddr_ax25) && 
+	if (addr_len != sizeof(struct sockaddr_ax25) &&
 	    addr_len != sizeof(struct full_sockaddr_ax25)) {
 		/* support for old structure may go away some time */
 		if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||
-		    (addr_len > sizeof(struct full_sockaddr_ax25)))
+		    (addr_len > sizeof(struct full_sockaddr_ax25))) {
 			return -EINVAL;
+	}
 
 		printk(KERN_WARNING "ax25_bind(): %s uses old (6 digipeater) socket structure.\n",
 			current->comm);
@@ -1084,8 +1037,17 @@
 		return -EINVAL;
 
 	call = ax25_findbyuid(current->euid);
-	if (call == NULL && ax25_uid_policy && !capable(CAP_NET_ADMIN))
+	if (call == NULL && ax25_uid_policy && !capable(CAP_NET_ADMIN)) {
 		return -EACCES;
+	}
+
+	lock_sock(sk);
+
+	ax25 = ax25_sk(sk);
+	if (sk->zapped == 0) {
+		err = -EINVAL;
+		goto out;
+	}
 
 	if (call == NULL)
 		ax25->source_addr = addr->fsa_ax25.sax25_call;
@@ -1095,17 +1057,20 @@
 	/*
 	 * User already set interface with SO_BINDTODEVICE
 	 */
-
 	if (ax25->ax25_dev != NULL)
 		goto done;
 
 	if (addr_len > sizeof(struct sockaddr_ax25) && addr->fsa_ax25.sax25_ndigis == 1) {
 		if (ax25cmp(&addr->fsa_digipeater[0], &null_ax25_address) != 0 &&
-		    (ax25_dev = ax25_addr_ax25dev(&addr->fsa_digipeater[0])) == NULL)
-			return -EADDRNOTAVAIL;
-	}  else {
-		if ((ax25_dev = ax25_addr_ax25dev(&addr->fsa_ax25.sax25_call)) == NULL)
-			return -EADDRNOTAVAIL;
+		    (ax25_dev = ax25_addr_ax25dev(&addr->fsa_digipeater[0])) == NULL) {
+			err = -EADDRNOTAVAIL;
+			goto out;
+		}
+	} else {
+		if ((ax25_dev = ax25_addr_ax25dev(&addr->fsa_ax25.sax25_call)) == NULL) {
+			err = -EADDRNOTAVAIL;
+			goto out;
+		}
 	}
 
 	if (ax25_dev != NULL)
@@ -1114,41 +1079,24 @@
 done:
 	ax25_insert_socket(ax25);
 	sk->zapped = 0;
+
+out:
+	release_sock(sk);
+
 	return 0;
 }
 
 /*
  *	FIXME: nonblock behaviour looks like it may have a bug.
  */
-static int ax25_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags)
+static int ax25_connect(struct socket *sock, struct sockaddr *uaddr,
+	int addr_len, int flags)
 {
 	struct sock *sk = sock->sk;
 	ax25_cb *ax25 = ax25_sk(sk);
 	struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr;
 	ax25_digi *digi = NULL;
-	int ct = 0, err;
-
-	/* deal with restarts */
-	if (sock->state == SS_CONNECTING) {
-		switch (sk->state) {
-		case TCP_SYN_SENT: /* still trying */
-			return -EINPROGRESS;
-
-		case TCP_ESTABLISHED: /* connection established */
-			sock->state = SS_CONNECTED;
-			return 0;
-
-		case TCP_CLOSE: /* connection refused */
-			sock->state = SS_UNCONNECTED;
-			return -ECONNREFUSED;
-		}
-	}
-
-	if (sk->state == TCP_ESTABLISHED && sk->type == SOCK_SEQPACKET)
-		return -EISCONN;	/* No reconnect on a seqpacket socket */
-
-	sk->state   = TCP_CLOSE;
-	sock->state = SS_UNCONNECTED;
+	int ct = 0, err = 0;
 
 	/*
 	 * some sanity checks. code further down depends on this
@@ -1162,8 +1110,9 @@
 	else if (addr_len != sizeof(struct full_sockaddr_ax25)) {
 		/* support for old structure may go away some time */
 		if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||
-		    (addr_len > sizeof(struct full_sockaddr_ax25)))
+		    (addr_len > sizeof(struct full_sockaddr_ax25))) {
 			return -EINVAL;
+		}
 
 		printk(KERN_WARNING "ax25_connect(): %s uses old (6 digipeater) socket structure.\n",
 			current->comm);
@@ -1172,21 +1121,54 @@
 	if (fsa->fsa_ax25.sax25_family != AF_AX25)
 		return -EINVAL;
 
+	lock_sock(sk);
+
+	/* deal with restarts */
+	if (sock->state == SS_CONNECTING) {
+		switch (sk->state) {
+		case TCP_SYN_SENT: /* still trying */
+			err = -EINPROGRESS;
+			goto out;
+
+		case TCP_ESTABLISHED: /* connection established */
+			sock->state = SS_CONNECTED;
+			goto out;
+
+		case TCP_CLOSE: /* connection refused */
+			sock->state = SS_UNCONNECTED;
+			err = -ECONNREFUSED;
+			goto out;
+		}
+	}
+
+	if (sk->state == TCP_ESTABLISHED && sk->type == SOCK_SEQPACKET) {
+		err = -EISCONN;	/* No reconnect on a seqpacket socket */
+		goto out;
+	}
+
+	sk->state   = TCP_CLOSE;
+	sock->state = SS_UNCONNECTED;
+
 	if (ax25->digipeat != NULL) {
 		kfree(ax25->digipeat);
 		ax25->digipeat = NULL;
 	}
-	
+
 	/*
 	 *	Handle digi-peaters to be used.
 	 */
-	if (addr_len > sizeof(struct sockaddr_ax25) && fsa->fsa_ax25.sax25_ndigis != 0) {
+	if (addr_len > sizeof(struct sockaddr_ax25) &&
+	    fsa->fsa_ax25.sax25_ndigis != 0) {
 		/* Valid number of digipeaters ? */
-		if (fsa->fsa_ax25.sax25_ndigis < 1 || fsa->fsa_ax25.sax25_ndigis > AX25_MAX_DIGIS)
-			return -EINVAL;
+		if (fsa->fsa_ax25.sax25_ndigis < 1 || fsa->fsa_ax25.sax25_ndigis > AX25_MAX_DIGIS) {
+			err = -EINVAL;
+			goto out;
+		}
 
-		if ((digi = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL)
-			return -ENOBUFS;
+		if ((digi = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) {
+			err = -ENOBUFS;
+			goto out;
+		}
 
 		digi->ndigi      = fsa->fsa_ax25.sax25_ndigis;
 		digi->lastrepeat = -1;
@@ -1214,19 +1196,24 @@
 		printk(KERN_WARNING "ax25_connect(): %s uses autobind, please contact jreuter@yaina.de\n",
 			current->comm);
 		if ((err = ax25_rt_autobind(ax25, &fsa->fsa_ax25.sax25_call)) < 0)
-			return err;
+			goto out;
+
 		ax25_fillin_cb(ax25, ax25->ax25_dev);
 		ax25_insert_socket(ax25);
 	} else {
-		if (ax25->ax25_dev == NULL)
-			return -EHOSTUNREACH;
+		if (ax25->ax25_dev == NULL) {
+			err = -EHOSTUNREACH;
+			goto out;
+		}
 	}
 
 	if (sk->type == SOCK_SEQPACKET &&
 	    ax25_find_cb(&ax25->source_addr, &fsa->fsa_ax25.sax25_call, digi,
 		    	 ax25->ax25_dev->dev)) {
-		if (digi != NULL) kfree(digi);
-		return -EADDRINUSE;			/* Already such a connection */
+		if (digi != NULL)
+			kfree(digi);
+		err = -EADDRINUSE;		/* Already such a connection */
+		goto out;
 	}
 
 	ax25->dest_addr = fsa->fsa_ax25.sax25_call;
@@ -1236,7 +1223,7 @@
 	if (sk->type != SOCK_SEQPACKET) {
 		sock->state = SS_CONNECTED;
 		sk->state   = TCP_ESTABLISHED;
-		return 0;
+		goto out;
 	}
 
 	/* Move to connecting socket, ax.25 lapb WAIT_UA.. */
@@ -1244,21 +1231,20 @@
 	sk->state          = TCP_SYN_SENT;
 
 	switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
-		case AX25_PROTO_STD_SIMPLEX:
-		case AX25_PROTO_STD_DUPLEX:
-			ax25_std_establish_data_link(ax25);
-			break;
+	case AX25_PROTO_STD_SIMPLEX:
+	case AX25_PROTO_STD_DUPLEX:
+		ax25_std_establish_data_link(ax25);
+		break;
 
 #ifdef CONFIG_AX25_DAMA_SLAVE
-		case AX25_PROTO_DAMA_SLAVE:
-			ax25->modulus = AX25_MODULUS;
-			ax25->window  =
-				ax25->ax25_dev->values[AX25_VALUES_WINDOW];
-			if (ax25->ax25_dev->dama.slave)
-				ax25_ds_establish_data_link(ax25);
-			else
-				ax25_std_establish_data_link(ax25);
-			break;
+	case AX25_PROTO_DAMA_SLAVE:
+		ax25->modulus = AX25_MODULUS;
+		ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
+		if (ax25->ax25_dev->dama.slave)
+			ax25_ds_establish_data_link(ax25);
+		else
+			ax25_std_establish_data_link(ax25);
+		break;
 #endif
 	}
 
@@ -1267,30 +1253,43 @@
 	ax25_start_heartbeat(ax25);
 
 	/* Now the loop */
-	if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
-		return -EINPROGRESS;
-
-	cli();	/* To avoid races on the sleep */
+	if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) {
+		err = -EINPROGRESS;
+		goto out;
+	}
 
-	/* A DM or timeout will go to closed, a UA will go to ABM */
-	while (sk->state == TCP_SYN_SENT) {
-		interruptible_sleep_on(sk->sleep);
-		if (signal_pending(current)) {
-			sti();
+	if (sk->state == TCP_SYN_SENT) {
+		struct task_struct *tsk = current;
+		DECLARE_WAITQUEUE(wait, tsk);
+
+		add_wait_queue(sk->sleep, &wait);
+		for (;;) {
+			if (sk->state != TCP_SYN_SENT)
+				break;
+			set_current_state(TASK_INTERRUPTIBLE);
+			release_sock(sk);
+			if (!signal_pending(tsk)) {
+				schedule();
+				lock_sock(sk);
+				continue;
+			}
 			return -ERESTARTSYS;
 		}
+		current->state = TASK_RUNNING;
+		remove_wait_queue(sk->sleep, &wait);
 	}
 
 	if (sk->state != TCP_ESTABLISHED) {
 		/* Not in ABM, not in WAIT_UA -> failed */
-		sti();
 		sock->state = SS_UNCONNECTED;
-		return sock_error(sk);	/* Always set at this point */
+		err = sock_error(sk);	/* Always set at this point */
+		goto out;
 	}
 
 	sock->state = SS_CONNECTED;
 
-	sti();
+out:
+	release_sock(sk);
 
 	return 0;
 }
@@ -1298,9 +1297,12 @@
 
 static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
 {
-	struct sock *sk;
-	struct sock *newsk;
+	struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
 	struct sk_buff *skb;
+	struct sock *newsk;
+	struct sock *sk;
+	int err = 0;
 
 	if (sock->state != SS_UNCONNECTED)
 		return -EINVAL;
@@ -1308,26 +1310,40 @@
 	if ((sk = sock->sk) == NULL)
 		return -EINVAL;
 
-	if (sk->type != SOCK_SEQPACKET)
-		return -EOPNOTSUPP;
+	lock_sock(sk);
+	if (sk->type != SOCK_SEQPACKET) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
 
-	if (sk->state != TCP_LISTEN)
-		return -EINVAL;
+	if (sk->state != TCP_LISTEN) {
+		err = -EINVAL;
+		goto out;
+	}
 
 	/*
 	 *	The read queue this time is holding sockets ready to use
 	 *	hooked into the SABM we saved
 	 */
-	do {
-		if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {
-			if (flags & O_NONBLOCK)
-				return -EWOULDBLOCK;
-
-			interruptible_sleep_on(sk->sleep);
-			if (signal_pending(current)) 
-				return -ERESTARTSYS;
+	add_wait_queue(sk->sleep, &wait);
+	for (;;) {
+		skb = skb_dequeue(&sk->receive_queue);
+		if (skb)
+			break;
+
+		current->state = TASK_INTERRUPTIBLE;
+		release_sock(sk);
+		if (flags & O_NONBLOCK)
+			return -EWOULDBLOCK;
+		if (!signal_pending(tsk)) {
+			schedule();
+			lock_sock(sk);
+			continue;
 		}
-	} while (skb == NULL);
+		return -ERESTARTSYS;
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(sk->sleep, &wait);
 
 	newsk = skb->sk;
 	newsk->pair = NULL;
@@ -1340,19 +1356,29 @@
 	newsock->sk    = newsk;
 	newsock->state = SS_CONNECTED;
 
-	return 0;
+out:
+	release_sock(sk);
+
+	return err;
 }
 
-static int ax25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer)
+static int ax25_getname(struct socket *sock, struct sockaddr *uaddr,
+	int *uaddr_len, int peer)
 {
-	struct sock *sk = sock->sk;
-	ax25_cb *ax25 = ax25_sk(sk);
 	struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr;
+	struct sock *sk = sock->sk;
 	unsigned char ndigi, i;
+	ax25_cb *ax25;
+	int err = 0;
+
+	lock_sock(sk);
+	ax25 = ax25_sk(sk);
 
 	if (peer != 0) {
-		if (sk->state != TCP_ESTABLISHED)
-			return -ENOTCONN;
+		if (sk->state != TCP_ESTABLISHED) {
+			err = -ENOTCONN;
+			goto out;
+		}
 
 		fsa->fsa_ax25.sax25_family = AF_AX25;
 		fsa->fsa_ax25.sax25_call   = ax25->dest_addr;
@@ -1377,41 +1403,53 @@
 		}
 	}
 	*uaddr_len = sizeof (struct full_sockaddr_ax25);
-	return 0;
+
+out:
+	release_sock(sk);
+
+	return err;
 }
 
-static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
+static int ax25_sendmsg(struct socket *sock, struct msghdr *msg, int len,
+	struct scm_cookie *scm)
 {
-	struct sock *sk = sock->sk;
-	ax25_cb *ax25 = ax25_sk(sk);
 	struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)msg->msg_name;
-	int err;
+	struct sock *sk = sock->sk;
 	struct sockaddr_ax25 sax;
 	struct sk_buff *skb;
+	ax25_digi dtmp, *dp;
 	unsigned char *asmptr;
-	int size;
-	ax25_digi *dp;
-	ax25_digi dtmp;
-	int lv;
-	int addr_len = msg->msg_namelen;
+	ax25_cb *ax25;
+	int lv, size, err, addr_len = msg->msg_namelen;
 
-	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR))
+	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR)) {
 		return -EINVAL;
+	}
+
+	lock_sock(sk);
+	ax25 = ax25_sk(sk);
 
-	if (sk->zapped)
-		return -EADDRNOTAVAIL;
+	if (sk->zapped) {
+		err = -EADDRNOTAVAIL;
+		goto out;
+	}
 
 	if (sk->shutdown & SEND_SHUTDOWN) {
 		send_sig(SIGPIPE, current, 0);
-		return -EPIPE;
+		err = -EPIPE;
+		goto out;
 	}
 
-	if (ax25->ax25_dev == NULL)
-		return -ENETUNREACH;
+	if (ax25->ax25_dev == NULL) {
+		err = -ENETUNREACH;
+		goto out;
+	}
 
 	if (usax != NULL) {
-		if (usax->sax25_family != AF_AX25)
-			return -EINVAL;
+		if (usax->sax25_family != AF_AX25) {
+			err = -EINVAL;
+			goto out;
+		}
 
 		if (addr_len == sizeof(struct sockaddr_ax25)) {
 			printk(KERN_WARNING "ax25_sendmsg(): %s uses obsolete socket structure\n",
@@ -1420,8 +1458,10 @@
 		else if (addr_len != sizeof(struct full_sockaddr_ax25)) {
 			/* support for old structure may go away some time */
 			if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||
-		    	    (addr_len > sizeof(struct full_sockaddr_ax25)))
-		    		return -EINVAL;
+		    	    (addr_len > sizeof(struct full_sockaddr_ax25))) {
+		    		err = -EINVAL;
+				goto out;
+			}
 
 			printk(KERN_WARNING "ax25_sendmsg(): %s uses old (6 digipeater) socket structure.\n",
 				current->comm);
@@ -1432,8 +1472,10 @@
 			struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)usax;
 
 			/* Valid number of digipeaters ? */
-			if (usax->sax25_ndigis < 1 || usax->sax25_ndigis > AX25_MAX_DIGIS)
-				return -EINVAL;
+			if (usax->sax25_ndigis < 1 || usax->sax25_ndigis > AX25_MAX_DIGIS) {
+				err = -EINVAL;
+				goto out;
+			}
 
 			dtmp.ndigi      = usax->sax25_ndigis;
 
@@ -1447,8 +1489,10 @@
 		}
 
 		sax = *usax;
-		if (sk->type == SOCK_SEQPACKET && ax25cmp(&ax25->dest_addr, &sax.sax25_call) != 0)
-			return -EISCONN;
+		if (sk->type == SOCK_SEQPACKET && ax25cmp(&ax25->dest_addr, &sax.sax25_call) != 0) {
+			err = -EISCONN;
+			goto out;
+		}
 		if (usax->sax25_ndigis == 0)
 			dp = NULL;
 		else
@@ -1459,8 +1503,10 @@
 		 *	it has become closed (not started closed) and is VC
 		 *	we ought to SIGPIPE, EPIPE
 		 */
-		if (sk->state != TCP_ESTABLISHED)
-			return -ENOTCONN;
+		if (sk->state != TCP_ESTABLISHED) {
+			err = -ENOTCONN;
+			goto out;
+		}
 		sax.sax25_family = AF_AX25;
 		sax.sax25_call   = ax25->dest_addr;
 		dp = ax25->digipeat;
@@ -1474,8 +1520,9 @@
 	/* Assume the worst case */
 	size = len + 3 + ax25_addr_size(dp) + AX25_BPQ_HEADER_LEN;
 
-	if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)
-		return err;
+	skb = sock_alloc_send_skb(sk, size, msg->msg_flags&MSG_DONTWAIT, &err);
+	if (skb == NULL)
+		goto out;
 
 	skb_reserve(skb, size - len);
 
@@ -1497,60 +1544,73 @@
 		/* Connected mode sockets go via the LAPB machine */
 		if (sk->state != TCP_ESTABLISHED) {
 			kfree_skb(skb);
-			return -ENOTCONN;
+			err = -ENOTCONN;
+			goto out;
 		}
 
 		/* Shove it onto the queue and kick */
 		ax25_output(ax25, ax25->paclen, skb);
 
-		return len;
-	} else {
-		asmptr = skb_push(skb, 1 + ax25_addr_size(dp));
+		err = len;
+		goto out;
+	}
 
-		SOCK_DEBUG(sk, "Building AX.25 Header (dp=%p).\n", dp);
+	asmptr = skb_push(skb, 1 + ax25_addr_size(dp));
 
-		if (dp != NULL)
-			SOCK_DEBUG(sk, "Num digipeaters=%d\n", dp->ndigi);
+	SOCK_DEBUG(sk, "Building AX.25 Header (dp=%p).\n", dp);
 
-		/* Build an AX.25 header */
-		asmptr += (lv = ax25_addr_build(asmptr, &ax25->source_addr,
-						&sax.sax25_call, dp,
-						AX25_COMMAND, AX25_MODULUS));
+	if (dp != NULL)
+		SOCK_DEBUG(sk, "Num digipeaters=%d\n", dp->ndigi);
 
-		SOCK_DEBUG(sk, "Built header (%d bytes)\n",lv);
+	/* Build an AX.25 header */
+	asmptr += (lv = ax25_addr_build(asmptr, &ax25->source_addr,
+					&sax.sax25_call, dp,
+					AX25_COMMAND, AX25_MODULUS));
 
-		skb->h.raw = asmptr;
+	SOCK_DEBUG(sk, "Built header (%d bytes)\n",lv);
 
-		SOCK_DEBUG(sk, "base=%p pos=%p\n", skb->data, asmptr);
+	skb->h.raw = asmptr;
 
-		*asmptr = AX25_UI;
+	SOCK_DEBUG(sk, "base=%p pos=%p\n", skb->data, asmptr);
 
-		/* Datagram frames go straight out of the door as UI */
-		skb->dev = ax25->ax25_dev->dev;
+	*asmptr = AX25_UI;
 
-		ax25_queue_xmit(skb);
+	/* Datagram frames go straight out of the door as UI */
+	skb->dev = ax25->ax25_dev->dev;
 
-		return len;
-	}
+	ax25_queue_xmit(skb);
+
+	err = len;
+
+out:
+	release_sock(sk);
+
+	return err;
 }
 
-static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm)
+static int ax25_recvmsg(struct socket *sock, struct msghdr *msg, int size,
+	int flags, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
-	int copied;
 	struct sk_buff *skb;
-	int er;
+	int copied;
+	int err = 0;
 
+	lock_sock(sk);
 	/*
 	 * 	This works for seqpacket too. The receiver has ordered the
 	 *	queue for us! We do one quick check first though
 	 */
-	if (sk->type == SOCK_SEQPACKET && sk->state != TCP_ESTABLISHED)
-		return -ENOTCONN;
+	if (sk->type == SOCK_SEQPACKET && sk->state != TCP_ESTABLISHED) {
+		err =  -ENOTCONN;
+		goto out;
+	}
 
 	/* Now we can treat all alike */
-	if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL)
-		return er;
+	skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
+	                        flags & MSG_DONTWAIT, &err);
+	if (skb == NULL)
+		goto out;
 
 	if (!ax25_sk(sk)->pidincl)
 		skb_pull(skb, 1);		/* Remove PID */
@@ -1561,7 +1621,7 @@
 	if (copied > size) {
 		copied = size;
 		msg->msg_flags |= MSG_TRUNC;
-	}		
+	}
 
 	skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 
@@ -1590,8 +1650,12 @@
 	}
 
 	skb_free_datagram(sk, skb);
+	err = copied;
+
+out:
+	release_sock(sk);
 
-	return copied;
+	return err;
 }
 
 static int ax25_shutdown(struct socket *sk, int how)
@@ -1603,137 +1667,173 @@
 static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
 	struct sock *sk = sock->sk;
+	int res = 0;
 
+	lock_sock(sk);
 	switch (cmd) {
-		case TIOCOUTQ: {
-			long amount;
-			amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
-			if (amount < 0)
-				amount = 0;
-			return put_user(amount, (int *)arg);
-		}
-
-		case TIOCINQ: {
-			struct sk_buff *skb;
-			long amount = 0L;
-			/* These two are safe on a single CPU system as only user tasks fiddle here */
-			if ((skb = skb_peek(&sk->receive_queue)) != NULL)
-				amount = skb->len;
-			return put_user(amount, (int *)arg);
-		}
-
-		case SIOCGSTAMP:
-			if (sk != NULL) {
-				if (sk->stamp.tv_sec == 0)
-					return -ENOENT;
-				return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0;
-	 		}
-			return -EINVAL;
+	case TIOCOUTQ: {
+		long amount;
+		amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
+		if (amount < 0)
+			amount = 0;
+		res = put_user(amount, (int *)arg);
+		break;
+	}
+
+	case TIOCINQ: {
+		struct sk_buff *skb;
+		long amount = 0L;
+		/* These two are safe on a single CPU system as only user tasks fiddle here */
+		if ((skb = skb_peek(&sk->receive_queue)) != NULL)
+			amount = skb->len;
+		res = put_user(amount, (int *)arg);
+		break;
+	}
+
+	case SIOCGSTAMP:
+		if (sk != NULL) {
+			if (sk->stamp.tv_sec == 0) {
+				res = -ENOENT;
+				break;
+			}
+			res = copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0;
+			break;
+	 	}
+		res = -EINVAL;
+		break;
 
-		case SIOCAX25ADDUID:	/* Add a uid to the uid/call map table */
-		case SIOCAX25DELUID:	/* Delete a uid from the uid/call map table */
-		case SIOCAX25GETUID: {
-			struct sockaddr_ax25 sax25;
-			if (copy_from_user(&sax25, (void *)arg, sizeof(sax25)))
-				return -EFAULT;
-			return ax25_uid_ioctl(cmd, &sax25);
-		}
-
-		case SIOCAX25NOUID: {	/* Set the default policy (default/bar) */
-			long amount;
-			if (!capable(CAP_NET_ADMIN))
-				return -EPERM;
-			if (get_user(amount, (long *)arg))
-				return -EFAULT;
-			if (amount > AX25_NOUID_BLOCK)
-				return -EINVAL;
-			ax25_uid_policy = amount;
-			return 0;
-		}
-
-		case SIOCADDRT:
-		case SIOCDELRT:
-		case SIOCAX25OPTRT:
-			if (!capable(CAP_NET_ADMIN))
-				return -EPERM;
-			return ax25_rt_ioctl(cmd, (void *)arg);
-
-		case SIOCAX25CTLCON:
-			if (!capable(CAP_NET_ADMIN))
-				return -EPERM;
-			return ax25_ctl_ioctl(cmd, (void *)arg);
-
-		case SIOCAX25GETINFO: 
-		case SIOCAX25GETINFOOLD: {
-			ax25_cb *ax25 = ax25_sk(sk);
-			struct ax25_info_struct ax25_info;
-
-			ax25_info.t1        = ax25->t1   / HZ;
-			ax25_info.t2        = ax25->t2   / HZ;
-			ax25_info.t3        = ax25->t3   / HZ;
-			ax25_info.idle      = ax25->idle / (60 * HZ);
-			ax25_info.n2        = ax25->n2;
-			ax25_info.t1timer   = ax25_display_timer(&ax25->t1timer)   / HZ;
-			ax25_info.t2timer   = ax25_display_timer(&ax25->t2timer)   / HZ;
-			ax25_info.t3timer   = ax25_display_timer(&ax25->t3timer)   / HZ;
-			ax25_info.idletimer = ax25_display_timer(&ax25->idletimer) / (60 * HZ);
-			ax25_info.n2count   = ax25->n2count;
-			ax25_info.state     = ax25->state;
-			ax25_info.rcv_q     = atomic_read(&sk->rmem_alloc);
-			ax25_info.snd_q     = atomic_read(&sk->wmem_alloc);
-			ax25_info.vs        = ax25->vs;
-			ax25_info.vr        = ax25->vr;
-			ax25_info.va        = ax25->va;
-			ax25_info.vs_max    = ax25->vs; /* reserved */
-			ax25_info.paclen    = ax25->paclen;
-			ax25_info.window    = ax25->window;
-
-			/* old structure? */
-			if (cmd == SIOCAX25GETINFOOLD) {
-				static int warned = 0;
-				if (!warned) {
-					printk(KERN_INFO "%s uses old SIOCAX25GETINFO\n",
-						current->comm);
-					warned=1;
-				}
+	case SIOCAX25ADDUID:	/* Add a uid to the uid/call map table */
+	case SIOCAX25DELUID:	/* Delete a uid from the uid/call map table */
+	case SIOCAX25GETUID: {
+		struct sockaddr_ax25 sax25;
+		if (copy_from_user(&sax25, (void *)arg, sizeof(sax25))) {
+			res = -EFAULT;
+			break;
+		}
+		res = ax25_uid_ioctl(cmd, &sax25);
+		break;
+	}
 
-				if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct_depreciated)))
-					return -EFAULT;
-			} else {
-				if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct)))
-					return -EINVAL;
-			} 
-			return 0;
-		}
-
-		case SIOCAX25ADDFWD:
-		case SIOCAX25DELFWD: {
-			struct ax25_fwd_struct ax25_fwd;
-			if (!capable(CAP_NET_ADMIN))
-				return -EPERM;
-			if (copy_from_user(&ax25_fwd, (void *)arg, sizeof(ax25_fwd)))
-				return -EFAULT;
-			return ax25_fwd_ioctl(cmd, &ax25_fwd);
-		}
-
-		case SIOCGIFADDR:
-		case SIOCSIFADDR:
-		case SIOCGIFDSTADDR:
-		case SIOCSIFDSTADDR:
-		case SIOCGIFBRDADDR:
-		case SIOCSIFBRDADDR:
-		case SIOCGIFNETMASK:
-		case SIOCSIFNETMASK:
-		case SIOCGIFMETRIC:
-		case SIOCSIFMETRIC:
-			return -EINVAL;
+	case SIOCAX25NOUID: {	/* Set the default policy (default/bar) */
+		long amount;
+		if (!capable(CAP_NET_ADMIN)) {
+			res = -EPERM;
+			break;
+		}
+		if (get_user(amount, (long *)arg)) {
+			res = -EFAULT;
+			break;
+		}
+		if (amount > AX25_NOUID_BLOCK) {
+			res = -EINVAL;
+			break;
+		}
+		ax25_uid_policy = amount;
+		res = 0;
+		break;
+	}
 
-		default:
-			return dev_ioctl(cmd, (void *)arg);
+	case SIOCADDRT:
+	case SIOCDELRT:
+	case SIOCAX25OPTRT:
+		if (!capable(CAP_NET_ADMIN)) {
+			res = -EPERM;
+			break;
+		}
+		res = ax25_rt_ioctl(cmd, (void *)arg);
+		break;
+
+	case SIOCAX25CTLCON:
+		if (!capable(CAP_NET_ADMIN)) {
+			res = -EPERM;
+			break;
+		}
+		res = ax25_ctl_ioctl(cmd, (void *)arg);
+		break;
+
+	case SIOCAX25GETINFO:
+	case SIOCAX25GETINFOOLD: {
+		ax25_cb *ax25 = ax25_sk(sk);
+		struct ax25_info_struct ax25_info;
+
+		ax25_info.t1        = ax25->t1   / HZ;
+		ax25_info.t2        = ax25->t2   / HZ;
+		ax25_info.t3        = ax25->t3   / HZ;
+		ax25_info.idle      = ax25->idle / (60 * HZ);
+		ax25_info.n2        = ax25->n2;
+		ax25_info.t1timer   = ax25_display_timer(&ax25->t1timer)   / HZ;
+		ax25_info.t2timer   = ax25_display_timer(&ax25->t2timer)   / HZ;
+		ax25_info.t3timer   = ax25_display_timer(&ax25->t3timer)   / HZ;
+		ax25_info.idletimer = ax25_display_timer(&ax25->idletimer) / (60 * HZ);
+		ax25_info.n2count   = ax25->n2count;
+		ax25_info.state     = ax25->state;
+		ax25_info.rcv_q     = atomic_read(&sk->rmem_alloc);
+		ax25_info.snd_q     = atomic_read(&sk->wmem_alloc);
+		ax25_info.vs        = ax25->vs;
+		ax25_info.vr        = ax25->vr;
+		ax25_info.va        = ax25->va;
+		ax25_info.vs_max    = ax25->vs; /* reserved */
+		ax25_info.paclen    = ax25->paclen;
+		ax25_info.window    = ax25->window;
+
+		/* old structure? */
+		if (cmd == SIOCAX25GETINFOOLD) {
+			static int warned = 0;
+			if (!warned) {
+				printk(KERN_INFO "%s uses old SIOCAX25GETINFO\n",
+					current->comm);
+				warned=1;
+			}
+
+			if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct_depreciated))) {
+				res = -EFAULT;
+				break;
+			}
+		} else {
+			if (copy_to_user((void *)arg, &ax25_info, sizeof(struct ax25_info_struct))) {
+				res = -EINVAL;
+				break;
+			}
+		}
+		res = 0;
+		break;
 	}
 
-	/*NOTREACHED*/
-	return 0;
+	case SIOCAX25ADDFWD:
+	case SIOCAX25DELFWD: {
+		struct ax25_fwd_struct ax25_fwd;
+		if (!capable(CAP_NET_ADMIN)) {
+			res = -EPERM;
+			break;
+		}
+		if (copy_from_user(&ax25_fwd, (void *)arg, sizeof(ax25_fwd))) {
+			res = -EFAULT;
+			break;
+		}
+		res = ax25_fwd_ioctl(cmd, &ax25_fwd);
+		break;
+	}
+
+	case SIOCGIFADDR:
+	case SIOCSIFADDR:
+	case SIOCGIFDSTADDR:
+	case SIOCSIFDSTADDR:
+	case SIOCGIFBRDADDR:
+	case SIOCSIFBRDADDR:
+	case SIOCGIFNETMASK:
+	case SIOCSIFNETMASK:
+	case SIOCGIFMETRIC:
+	case SIOCSIFMETRIC:
+		res = -EINVAL;
+		break;
+
+	default:
+		res = dev_ioctl(cmd, (void *)arg);
+		break;
+	}
+	release_sock(sk);
+
+	return res;
 }
 
 static int ax25_get_info(char *buffer, char **start, off_t offset, int length)
@@ -1744,28 +1844,28 @@
 	off_t pos = 0;
 	off_t begin = 0;
 
-	cli();
+	spin_lock_bh(&ax25_list_lock);
 
 	/*
 	 * New format:
-	 * magic dev src_addr dest_addr,digi1,digi2,.. st vs vr va t1 t1 t2 t2 t3 t3 idle idle n2 n2 rtt window paclen Snd-Q Rcv-Q inode 
+	 * magic dev src_addr dest_addr,digi1,digi2,.. st vs vr va t1 t1 t2 t2 t3 t3 idle idle n2 n2 rtt window paclen Snd-Q Rcv-Q inode
 	 */
-	
+
 	for (ax25 = ax25_list; ax25 != NULL; ax25 = ax25->next) {
-		len += sprintf(buffer+len, "%8.8lx %s %s%s ", 
-				(long) ax25, 
+		len += sprintf(buffer+len, "%8.8lx %s %s%s ",
+				(long) ax25,
 				ax25->ax25_dev == NULL? "???" : ax25->ax25_dev->dev->name,
 				ax2asc(&ax25->source_addr),
 				ax25->iamdigi? "*":"");
 
 		len += sprintf(buffer+len, "%s", ax2asc(&ax25->dest_addr));
-				
+
 		for (k=0; (ax25->digipeat != NULL) && (k < ax25->digipeat->ndigi); k++) {
 			len += sprintf(buffer+len, ",%s%s",
 					ax2asc(&ax25->digipeat->calls[k]),
 					ax25->digipeat->repeated[k]? "*":"");
 		}
-		
+
 		len += sprintf(buffer+len, " %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %d %d",
 			ax25->state,
 			ax25->vs, ax25->vr, ax25->va,
@@ -1799,7 +1899,7 @@
 			break;
 	}
 
-	sti();
+	spin_unlock_bh(&ax25_list_lock);
 
 	*start = buffer + (offset - begin);
 	len   -= (offset - begin);
@@ -1814,7 +1914,7 @@
 	.create =	ax25_create,
 };
 
-static struct proto_ops SOCKOPS_WRAPPED(ax25_proto_ops) = {
+static struct proto_ops ax25_proto_ops = {
 	.family =	PF_AX25,
 
 	.release =	ax25_release,
@@ -1835,15 +1935,14 @@
 	.sendpage =	sock_no_sendpage,
 };
 
-#include <linux/smp_lock.h>
-SOCKOPS_WRAP(ax25_proto, PF_AX25);
-
 /*
  *	Called by socket.c on kernel start up
  */
 static struct packet_type ax25_packet_type = {
-	.type =		__constant_htons(ETH_P_AX25),
-	.func =		ax25_kiss_rcv,
+	.type	=	__constant_htons(ETH_P_AX25),
+	.dev	=	NULL,				/* All devices */
+	.func	=	ax25_kiss_rcv,
+	.data	=	(void *) 1
 };
 
 static struct notifier_block ax25_dev_notifier = {
diff -Nru a/net/ax25/ax25_addr.c b/net/ax25/ax25_addr.c
--- a/net/ax25/ax25_addr.c	Fri Sep 20 08:20:48 2002
+++ b/net/ax25/ax25_addr.c	Fri Sep 20 08:20:48 2002
@@ -1,24 +1,11 @@
 /*
- *	AX.25 release 037
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	Most of this code is based on the SDL diagrams published in the 7th
- *	ARRL Computer Networking Conference papers. The diagrams have mistakes
- *	in them, but are mostly correct. Before you modify the code could you
- *	read the SDL diagrams as the code is not obvious and probably very
- *	easy to break;
- *
- *	History
- *	AX.25 036	Jonathan(G4KLX)	Split from ax25_subr.c.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
  */
-
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -165,14 +152,14 @@
 
 	if (flags != NULL) {
 		*flags = 0;
-		
+
 		if (buf[6] & AX25_CBIT)
 			*flags = AX25_COMMAND;
 		if (buf[13] & AX25_CBIT)
 			*flags = AX25_RESPONSE;
 	}
 
-	if (dama != NULL) 
+	if (dama != NULL)
 		*dama = ~buf[13] & AX25_DAMA_FLAG;
 
 	/* Copy to, from */
@@ -243,7 +230,7 @@
 	if (d == NULL || d->ndigi == 0) {
 		buf[6] |= AX25_EBIT;
 		return 2 * AX25_ADDR_LEN;
-	}	
+	}
 
 	buf += AX25_ADDR_LEN;
 	len += AX25_ADDR_LEN;
@@ -277,7 +264,7 @@
 	return AX25_ADDR_LEN * (2 + dp->ndigi);
 }
 
-/* 
+/*
  *	Reverse Digipeat List. May not pass both parameters as same struct
  */
 void ax25_digi_invert(ax25_digi *in, ax25_digi *out)
diff -Nru a/net/ax25/ax25_dev.c b/net/ax25/ax25_dev.c
--- a/net/ax25/ax25_dev.c	Fri Sep 20 08:20:42 2002
+++ b/net/ax25/ax25_dev.c	Fri Sep 20 08:20:42 2002
@@ -1,21 +1,11 @@
 /*
- *	AX.25 release 037
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	Other kernels modules in this kit are generally BSD derived. See the copyright headers.
- *
- *
- *	History
- *	AX.25 036	Jonathan(G4KLX)	Split from ax25_route.c.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
  */
-
 #include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/types.h>
@@ -27,6 +17,7 @@
 #include <linux/string.h>
 #include <linux/sockios.h>
 #include <linux/net.h>
+#include <linux/spinlock.h>
 #include <net/ax25.h>
 #include <linux/inet.h>
 #include <linux/netdevice.h>
@@ -41,27 +32,35 @@
 #include <linux/init.h>
 
 ax25_dev *ax25_dev_list;
+spinlock_t ax25_dev_lock = SPIN_LOCK_UNLOCKED;
 
 ax25_dev *ax25_dev_ax25dev(struct net_device *dev)
 {
-	ax25_dev *ax25_dev;
+	ax25_dev *ax25_dev, *res = NULL;
 
+	spin_lock_bh(&ax25_dev_lock);
 	for (ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next)
-		if (ax25_dev->dev == dev)
-			return ax25_dev;
+		if (ax25_dev->dev == dev) {
+			res = ax25_dev;
+			break;
+		}
+	spin_unlock_bh(&ax25_dev_lock);
 
-	return NULL;
+	return res;
 }
 
 ax25_dev *ax25_addr_ax25dev(ax25_address *addr)
 {
-	ax25_dev *ax25_dev;
+	ax25_dev *ax25_dev, *res = NULL;
 
+	spin_lock_bh(&ax25_dev_lock);
 	for (ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next)
-		if (ax25cmp(addr, (ax25_address *)ax25_dev->dev->dev_addr) == 0)
-			return ax25_dev;
+		if (ax25cmp(addr, (ax25_address *)ax25_dev->dev->dev_addr) == 0) {
+			res = ax25_dev;
+		}
+	spin_unlock_bh(&ax25_dev_lock);
 
-	return NULL;
+	return res;
 }
 
 /*
@@ -71,7 +70,6 @@
 void ax25_dev_device_up(struct net_device *dev)
 {
 	ax25_dev *ax25_dev;
-	unsigned long flags;
 
 	if ((ax25_dev = kmalloc(sizeof(*ax25_dev), GFP_ATOMIC)) == NULL) {
 		printk(KERN_ERR "AX.25: ax25_dev_device_up - out of memory\n");
@@ -100,10 +98,10 @@
 	ax25_dev->values[AX25_VALUES_PROTOCOL]  = AX25_DEF_PROTOCOL;
 	ax25_dev->values[AX25_VALUES_DS_TIMEOUT]= AX25_DEF_DS_TIMEOUT;
 
-	save_flags(flags); cli();
+	spin_lock_bh(&ax25_dev_lock);
 	ax25_dev->next = ax25_dev_list;
 	ax25_dev_list  = ax25_dev;
-	restore_flags(flags);
+	spin_unlock_bh(&ax25_dev_lock);
 
 	ax25_register_sysctl();
 }
@@ -111,14 +109,13 @@
 void ax25_dev_device_down(struct net_device *dev)
 {
 	ax25_dev *s, *ax25_dev;
-	unsigned long flags;
 
 	if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
 		return;
 
 	ax25_unregister_sysctl();
 
-	save_flags(flags); cli();
+	spin_lock_bh(&ax25_dev_lock);
 
 #ifdef CONFIG_AX25_DAMA_SLAVE
 	ax25_ds_del_timer(ax25_dev);
@@ -133,7 +130,7 @@
 
 	if ((s = ax25_dev_list) == ax25_dev) {
 		ax25_dev_list = s->next;
-		restore_flags(flags);
+		spin_unlock_bh(&ax25_dev_lock);
 		kfree(ax25_dev);
 		ax25_register_sysctl();
 		return;
@@ -142,7 +139,7 @@
 	while (s != NULL && s->next != NULL) {
 		if (s->next == ax25_dev) {
 			s->next = ax25_dev->next;
-			restore_flags(flags);
+			spin_unlock_bh(&ax25_dev_lock);
 			kfree(ax25_dev);
 			ax25_register_sysctl();
 			return;
@@ -150,8 +147,8 @@
 
 		s = s->next;
 	}
+	spin_unlock_bh(&ax25_dev_lock);
 
-	restore_flags(flags);
 	ax25_register_sysctl();
 }
 
@@ -163,22 +160,22 @@
 		return -EINVAL;
 
 	switch (cmd) {
-		case SIOCAX25ADDFWD:
-			if ((fwd_dev = ax25_addr_ax25dev(&fwd->port_to)) == NULL)
-				return -EINVAL;
-			if (ax25_dev->forward != NULL)
-				return -EINVAL;
-			ax25_dev->forward = fwd_dev->dev;
-			break;
-
-		case SIOCAX25DELFWD:
-			if (ax25_dev->forward == NULL)
-				return -EINVAL;
-			ax25_dev->forward = NULL;
-			break;
+	case SIOCAX25ADDFWD:
+		if ((fwd_dev = ax25_addr_ax25dev(&fwd->port_to)) == NULL)
+			return -EINVAL;
+		if (ax25_dev->forward != NULL)
+			return -EINVAL;
+		ax25_dev->forward = fwd_dev->dev;
+		break;
 
-		default:
+	case SIOCAX25DELFWD:
+		if (ax25_dev->forward == NULL)
 			return -EINVAL;
+		ax25_dev->forward = NULL;
+		break;
+
+	default:
+		return -EINVAL;
 	}
 
 	return 0;
@@ -202,12 +199,16 @@
  */
 void __exit ax25_dev_free(void)
 {
-	ax25_dev *s, *ax25_dev = ax25_dev_list;
+	ax25_dev *s, *ax25_dev;
 
+	spin_lock_bh(&ax25_dev_lock);
+	ax25_dev = ax25_dev_list;
 	while (ax25_dev != NULL) {
 		s        = ax25_dev;
 		ax25_dev = ax25_dev->next;
 
 		kfree(s);
 	}
+	ax25_dev_list = NULL;
+	spin_unlock_bh(&ax25_dev_lock);
 }
diff -Nru a/net/ax25/ax25_ds_in.c b/net/ax25/ax25_ds_in.c
--- a/net/ax25/ax25_ds_in.c	Fri Sep 20 08:20:42 2002
+++ b/net/ax25/ax25_ds_in.c	Fri Sep 20 08:20:42 2002
@@ -1,27 +1,12 @@
 /*
- *	AX.25 release 037
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	Most of this code is based on the SDL diagrams published in the 7th
- *	ARRL Computer Networking Conference papers. The diagrams have mistakes
- *	in them, but are mostly correct. Before you modify the code could you
- *	read the SDL diagrams as the code is not obvious and probably very
- *	easy to break;
- *
- *	History
- *	AX.25 036	Jonathan(G4KLX)	Cloned from ax25_in.c
- *			Joerg(DL1BKE)	Fixed it.
- *	AX.25 037	Jonathan(G4KLX)	New timer architecture.
- *			Joerg(DL1BKE)	ax25->n2count never got reset
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
  */
-
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -53,54 +38,56 @@
 static int ax25_ds_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type)
 {
 	switch (frametype) {
-		case AX25_SABM:
-			ax25->modulus = AX25_MODULUS;
-			ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
-			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
-			break;
-			
-		case AX25_SABME:
-			ax25->modulus = AX25_EMODULUS;
-			ax25->window  =  ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
-			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
-			break;
-
-		case AX25_DISC:
-			ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE);
-			break;
-
-		case AX25_UA:
-			ax25_calculate_rtt(ax25);
-			ax25_stop_t1timer(ax25);
-			ax25_start_t3timer(ax25);
-			ax25_start_idletimer(ax25);
-			ax25->vs      = 0;
-			ax25->va      = 0;
-			ax25->vr      = 0;
-			ax25->state   = AX25_STATE_3;
-			ax25->n2count = 0;
-			if (ax25->sk != NULL) {
-				ax25->sk->state = TCP_ESTABLISHED;
-				/* For WAIT_SABM connections we will produce an accept ready socket here */
-				if (!ax25->sk->dead)
-					ax25->sk->state_change(ax25->sk);
-			}
-			ax25_dama_on(ax25);
-
-			/* according to DK4EG´s spec we are required to
-			 * send a RR RESPONSE FINAL NR=0. 
-			 */
-
-			ax25_std_enquiry_response(ax25);
-			break;
-
-		case AX25_DM:
-			if (pf) ax25_disconnect(ax25, ECONNREFUSED);
-			break;
-
-		default:
-			if (pf) ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
-			break;
+	case AX25_SABM:
+		ax25->modulus = AX25_MODULUS;
+		ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
+		ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+		break;
+
+	case AX25_SABME:
+		ax25->modulus = AX25_EMODULUS;
+		ax25->window  =  ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
+		ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+		break;
+
+	case AX25_DISC:
+		ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE);
+		break;
+
+	case AX25_UA:
+		ax25_calculate_rtt(ax25);
+		ax25_stop_t1timer(ax25);
+		ax25_start_t3timer(ax25);
+		ax25_start_idletimer(ax25);
+		ax25->vs      = 0;
+		ax25->va      = 0;
+		ax25->vr      = 0;
+		ax25->state   = AX25_STATE_3;
+		ax25->n2count = 0;
+		if (ax25->sk != NULL) {
+			ax25->sk->state = TCP_ESTABLISHED;
+			/* For WAIT_SABM connections we will produce an accept ready socket here */
+			if (!ax25->sk->dead)
+				ax25->sk->state_change(ax25->sk);
+		}
+		ax25_dama_on(ax25);
+
+		/* according to DK4EG´s spec we are required to
+		 * send a RR RESPONSE FINAL NR=0.
+		 */
+
+		ax25_std_enquiry_response(ax25);
+		break;
+
+	case AX25_DM:
+		if (pf)
+			ax25_disconnect(ax25, ECONNREFUSED);
+		break;
+
+	default:
+		if (pf)
+			ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
+		break;
 	}
 
 	return 0;
@@ -114,38 +101,38 @@
 static int ax25_ds_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type)
 {
 	switch (frametype) {
-		case AX25_SABM:
-		case AX25_SABME:
-			ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
-			ax25_dama_off(ax25);
-			break;
-
-		case AX25_DISC:
-			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+	case AX25_SABM:
+	case AX25_SABME:
+		ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+		ax25_dama_off(ax25);
+		break;
+
+	case AX25_DISC:
+		ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+		ax25_dama_off(ax25);
+		ax25_disconnect(ax25, 0);
+		break;
+
+	case AX25_DM:
+	case AX25_UA:
+		if (pf) {
 			ax25_dama_off(ax25);
 			ax25_disconnect(ax25, 0);
-			break;
+		}
+		break;
 
-		case AX25_DM:
-		case AX25_UA:
-			if (pf) {
-				ax25_dama_off(ax25);
-				ax25_disconnect(ax25, 0);
-			}
-			break;
-
-		case AX25_I:
-		case AX25_REJ:
-		case AX25_RNR:
-		case AX25_RR:
-			if (pf) {
-				ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
-				ax25_dama_off(ax25);
-			}
-			break;
+	case AX25_I:
+	case AX25_REJ:
+	case AX25_RNR:
+	case AX25_RR:
+		if (pf) {
+			ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+			ax25_dama_off(ax25);
+		}
+		break;
 
-		default:
-			break;
+	default:
+		break;
 	}
 
 	return 0;
@@ -161,127 +148,127 @@
 	int queued = 0;
 
 	switch (frametype) {
-		case AX25_SABM:
-		case AX25_SABME:
-			if (frametype == AX25_SABM) {
-				ax25->modulus   = AX25_MODULUS;
-				ax25->window    = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
-			} else {
-				ax25->modulus   = AX25_EMODULUS;
-				ax25->window    = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
-			}
-			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
-			ax25_stop_t1timer(ax25);
-			ax25_start_t3timer(ax25);
-			ax25_start_idletimer(ax25);
-			ax25->condition = 0x00;
-			ax25->vs        = 0;
-			ax25->va        = 0;
-			ax25->vr        = 0;
-			ax25_requeue_frames(ax25);
-			ax25_dama_on(ax25);
-			break;
+	case AX25_SABM:
+	case AX25_SABME:
+		if (frametype == AX25_SABM) {
+			ax25->modulus   = AX25_MODULUS;
+			ax25->window    = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
+		} else {
+			ax25->modulus   = AX25_EMODULUS;
+			ax25->window    = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
+		}
+		ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+		ax25_stop_t1timer(ax25);
+		ax25_start_t3timer(ax25);
+		ax25_start_idletimer(ax25);
+		ax25->condition = 0x00;
+		ax25->vs        = 0;
+		ax25->va        = 0;
+		ax25->vr        = 0;
+		ax25_requeue_frames(ax25);
+		ax25_dama_on(ax25);
+		break;
+
+	case AX25_DISC:
+		ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+		ax25_dama_off(ax25);
+		ax25_disconnect(ax25, 0);
+		break;
+
+	case AX25_DM:
+		ax25_dama_off(ax25);
+		ax25_disconnect(ax25, ECONNRESET);
+		break;
+
+	case AX25_RR:
+	case AX25_RNR:
+		if (frametype == AX25_RR)
+			ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
+		else
+			ax25->condition |= AX25_COND_PEER_RX_BUSY;
 
-		case AX25_DISC:
-			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
-			ax25_dama_off(ax25);
-			ax25_disconnect(ax25, 0);
-			break;
+		if (ax25_validate_nr(ax25, nr)) {
+			if (ax25_check_iframes_acked(ax25, nr))
+				ax25->n2count=0;
+			if (type == AX25_COMMAND && pf)
+				ax25_ds_enquiry_response(ax25);
+		} else {
+			ax25_ds_nr_error_recovery(ax25);
+			ax25->state = AX25_STATE_1;
+		}
+		break;
 
-		case AX25_DM:
-			ax25_dama_off(ax25);
-			ax25_disconnect(ax25, ECONNRESET);
-			break;
+	case AX25_REJ:
+		ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
 
-		case AX25_RR:
-		case AX25_RNR:
-			if (frametype == AX25_RR)
-				ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
-			else
-				ax25->condition |= AX25_COND_PEER_RX_BUSY;
-
-			if (ax25_validate_nr(ax25, nr)) {
-				if (ax25_check_iframes_acked(ax25, nr))
-					ax25->n2count=0;
-				if (type == AX25_COMMAND && pf)
-					ax25_ds_enquiry_response(ax25);
-			} else {
-				ax25_ds_nr_error_recovery(ax25);
-				ax25->state = AX25_STATE_1;
-			}
-			break;
+		if (ax25_validate_nr(ax25, nr)) {
+			if (ax25->va != nr)
+				ax25->n2count=0;
 
-		case AX25_REJ:
-			ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
+			ax25_frames_acked(ax25, nr);
+			ax25_calculate_rtt(ax25);
+			ax25_stop_t1timer(ax25);
+			ax25_start_t3timer(ax25);
+			ax25_requeue_frames(ax25);
 
-			if (ax25_validate_nr(ax25, nr)) {
-				if (ax25->va != nr)
-					ax25->n2count=0;
-
-				ax25_frames_acked(ax25, nr);
-				ax25_calculate_rtt(ax25);
-				ax25_stop_t1timer(ax25);
-				ax25_start_t3timer(ax25);
-				ax25_requeue_frames(ax25);
+			if (type == AX25_COMMAND && pf)
+				ax25_ds_enquiry_response(ax25);
+		} else {
+			ax25_ds_nr_error_recovery(ax25);
+			ax25->state = AX25_STATE_1;
+		}
+		break;
 
-				if (type == AX25_COMMAND && pf)
-					ax25_ds_enquiry_response(ax25);
-			} else {
-				ax25_ds_nr_error_recovery(ax25);
-				ax25->state = AX25_STATE_1;
-			}
+	case AX25_I:
+		if (!ax25_validate_nr(ax25, nr)) {
+			ax25_ds_nr_error_recovery(ax25);
+			ax25->state = AX25_STATE_1;
 			break;
-
-		case AX25_I:
-			if (!ax25_validate_nr(ax25, nr)) {
-				ax25_ds_nr_error_recovery(ax25);
-				ax25->state = AX25_STATE_1;
-				break;
-			}
-			if (ax25->condition & AX25_COND_PEER_RX_BUSY) {
-				ax25_frames_acked(ax25, nr);
+		}
+		if (ax25->condition & AX25_COND_PEER_RX_BUSY) {
+			ax25_frames_acked(ax25, nr);
+			ax25->n2count = 0;
+		} else {
+			if (ax25_check_iframes_acked(ax25, nr))
 				ax25->n2count = 0;
+		}
+		if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
+			if (pf) ax25_ds_enquiry_response(ax25);
+			break;
+		}
+		if (ns == ax25->vr) {
+			ax25->vr = (ax25->vr + 1) % ax25->modulus;
+			queued = ax25_rx_iframe(ax25, skb);
+			if (ax25->condition & AX25_COND_OWN_RX_BUSY)
+				ax25->vr = ns;	/* ax25->vr - 1 */
+			ax25->condition &= ~AX25_COND_REJECT;
+			if (pf) {
+				ax25_ds_enquiry_response(ax25);
 			} else {
-				if (ax25_check_iframes_acked(ax25, nr))
-					ax25->n2count = 0;
+				if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
+					ax25->condition |= AX25_COND_ACK_PENDING;
+					ax25_start_t2timer(ax25);
+				}
 			}
-			if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
+		} else {
+			if (ax25->condition & AX25_COND_REJECT) {
 				if (pf) ax25_ds_enquiry_response(ax25);
-				break;
-			}
-			if (ns == ax25->vr) {
-				ax25->vr = (ax25->vr + 1) % ax25->modulus;
-				queued = ax25_rx_iframe(ax25, skb);
-				if (ax25->condition & AX25_COND_OWN_RX_BUSY)
-					ax25->vr = ns;	/* ax25->vr - 1 */
-				ax25->condition &= ~AX25_COND_REJECT;
-				if (pf) {
-					ax25_ds_enquiry_response(ax25);
-				} else {
-					if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
-						ax25->condition |= AX25_COND_ACK_PENDING;
-						ax25_start_t2timer(ax25);
-					}
-				}
 			} else {
-				if (ax25->condition & AX25_COND_REJECT) {
-					if (pf) ax25_ds_enquiry_response(ax25);
-				} else {
-					ax25->condition |= AX25_COND_REJECT;
-					ax25_ds_enquiry_response(ax25);
-					ax25->condition &= ~AX25_COND_ACK_PENDING;
-				}
+				ax25->condition |= AX25_COND_REJECT;
+				ax25_ds_enquiry_response(ax25);
+				ax25->condition &= ~AX25_COND_ACK_PENDING;
 			}
-			break;
+		}
+		break;
 
-		case AX25_FRMR:
-		case AX25_ILLEGAL:
-			ax25_ds_establish_data_link(ax25);
-			ax25->state = AX25_STATE_1;
-			break;
+	case AX25_FRMR:
+	case AX25_ILLEGAL:
+		ax25_ds_establish_data_link(ax25);
+		ax25->state = AX25_STATE_1;
+		break;
 
-		default:
-			break;
+	default:
+		break;
 	}
 
 	return queued;
@@ -297,15 +284,15 @@
 	frametype = ax25_decode(ax25, skb, &ns, &nr, &pf);
 
 	switch (ax25->state) {
-		case AX25_STATE_1:
-			queued = ax25_ds_state1_machine(ax25, skb, frametype, pf, type);
-			break;
-		case AX25_STATE_2:
-			queued = ax25_ds_state2_machine(ax25, skb, frametype, pf, type);
-			break;
-		case AX25_STATE_3:
-			queued = ax25_ds_state3_machine(ax25, skb, frametype, ns, nr, pf, type);
-			break;
+	case AX25_STATE_1:
+		queued = ax25_ds_state1_machine(ax25, skb, frametype, pf, type);
+		break;
+	case AX25_STATE_2:
+		queued = ax25_ds_state2_machine(ax25, skb, frametype, pf, type);
+		break;
+	case AX25_STATE_3:
+		queued = ax25_ds_state3_machine(ax25, skb, frametype, ns, nr, pf, type);
+		break;
 	}
 
 	return queued;
diff -Nru a/net/ax25/ax25_ds_subr.c b/net/ax25/ax25_ds_subr.c
--- a/net/ax25/ax25_ds_subr.c	Fri Sep 20 08:20:47 2002
+++ b/net/ax25/ax25_ds_subr.c	Fri Sep 20 08:20:47 2002
@@ -1,27 +1,12 @@
 /*
- *	AX.25 release 037
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	Most of this code is based on the SDL diagrams published in the 7th
- *	ARRL Computer Networking Conference papers. The diagrams have mistakes
- *	in them, but are mostly correct. Before you modify the code could you
- *	read the SDL diagrams as the code is not obvious and probably very
- *	easy to break;
- *
- *	History
- *	AX.25 036	Jonathan(G4KLX)	Cloned from ax25_out.c and ax25_subr.c.
- *			Joerg(DL1BKE)	Changed ax25_ds_enquiry_response(),
- *					fixed ax25_dama_on() and ax25_dama_off().
- *	AX.25 037	Jonathan(G4KLX)	New timer architecture.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
  */
-
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -31,6 +16,7 @@
 #include <linux/timer.h>
 #include <linux/string.h>
 #include <linux/sockios.h>
+#include <linux/spinlock.h>
 #include <linux/net.h>
 #include <net/ax25.h>
 #include <linux/inet.h>
@@ -73,7 +59,7 @@
 	 *	DL1BKE-7->DB0PRA-6 DB0ACH <I C S3 R5>
 	 *
 	 * Flexnet refuses to send us *any* I frame if we send
-	 * a REJ in case AX25_COND_REJECT is set. It is superfluous in 
+	 * a REJ in case AX25_COND_REJECT is set. It is superfluous in
 	 * this mode anyway (a RR or RNR invokes the retransmission).
 	 * Is this a Flexnet bug?
 	 */
@@ -93,6 +79,7 @@
 	ax25_start_t3timer(ax25);
 	ax25_ds_set_timer(ax25->ax25_dev);
 
+	spin_lock_bh(&ax25_list_lock);
 	for (ax25o = ax25_list; ax25o != NULL; ax25o = ax25o->next) {
 		if (ax25o == ax25)
 			continue;
@@ -118,6 +105,7 @@
 		if (ax25o->state != AX25_STATE_0)
 			ax25_start_t3timer(ax25o);
 	}
+	spin_unlock_bh(&ax25_list_lock);
 }
 
 void ax25_ds_establish_data_link(ax25_cb *ax25)
@@ -132,8 +120,8 @@
 
 /*
  *	:::FIXME:::
- *	This is a kludge. Not all drivers recognize kiss commands. 
- *	We need a driver level  request to switch duplex mode, that does 
+ *	This is a kludge. Not all drivers recognize kiss commands.
+ *	We need a driver level  request to switch duplex mode, that does
  *	either SCC changing, PI config or KISS as required. Currently
  *	this request isn't reliable.
  */
@@ -164,19 +152,24 @@
  *	A nasty problem arises if we count the number of DAMA connections
  *	wrong, especially when connections on the device already existed
  *	and our network node (or the sysop) decides to turn on DAMA Master
- *	mode. We thus flag the 'real' slave connections with 
+ *	mode. We thus flag the 'real' slave connections with
  *	ax25->dama_slave=1 and look on every disconnect if still slave
  *	connections exist.
  */
 static int ax25_check_dama_slave(ax25_dev *ax25_dev)
 {
 	ax25_cb *ax25;
+	int res = 0;
 
+	spin_lock_bh(&ax25_list_lock);
 	for (ax25 = ax25_list; ax25 != NULL ; ax25 = ax25->next)
-		if (ax25->ax25_dev == ax25_dev && (ax25->condition & AX25_COND_DAMA_MODE) && ax25->state > AX25_STATE_1)
-			return 1;
+		if (ax25->ax25_dev == ax25_dev && (ax25->condition & AX25_COND_DAMA_MODE) && ax25->state > AX25_STATE_1) {
+			res = 1;
+			break;
+		}
+	spin_unlock_bh(&ax25_list_lock);
 
-	return 0;
+	return res;
 }
 
 void ax25_dev_dama_on(ax25_dev *ax25_dev)
diff -Nru a/net/ax25/ax25_ds_timer.c b/net/ax25/ax25_ds_timer.c
--- a/net/ax25/ax25_ds_timer.c	Fri Sep 20 08:20:47 2002
+++ b/net/ax25/ax25_ds_timer.c	Fri Sep 20 08:20:47 2002
@@ -1,23 +1,16 @@
 /*
- *	AX.25 release 037
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	History
- *	AX.25 036	Jonathan(G4KLX)	Cloned from ax25_timer.c.
- *			Joerg(DL1BKE)	Added DAMA Slave Timeout timer
- *	AX.25 037	Jonathan(G4KLX)	New timer architecture.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
  */
-
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
+#include <linux/spinlock.h>
 #include <linux/in.h>
 #include <linux/kernel.h>
 #include <linux/jiffies.h>
@@ -41,7 +34,7 @@
 
 /*
  *	Add DAMA slave timeout timer to timer list.
- *	Unlike the connection based timers the timeout function gets 
+ *	Unlike the connection based timers the timeout function gets
  *	triggered every second. Please note that NET_AX25_DAMA_SLAVE_TIMEOUT
  *	(aka /proc/sys/net/ax25/{dev}/dama_slave_timeout) is still in
  *	1/10th of a second.
@@ -58,7 +51,8 @@
 
 void ax25_ds_del_timer(ax25_dev *ax25_dev)
 {
-	if (ax25_dev) del_timer(&ax25_dev->dama.slave_timer);
+	if (ax25_dev)
+		del_timer(&ax25_dev->dama.slave_timer);
 }
 
 void ax25_ds_set_timer(ax25_dev *ax25_dev)
@@ -80,15 +74,16 @@
 {
 	ax25_dev *ax25_dev = (struct ax25_dev *) arg;
 	ax25_cb *ax25;
-	
+
 	if (ax25_dev == NULL || !ax25_dev->dama.slave)
 		return;			/* Yikes! */
-	
+
 	if (!ax25_dev->dama.slave_timeout || --ax25_dev->dama.slave_timeout) {
 		ax25_ds_set_timer(ax25_dev);
 		return;
 	}
-	
+
+	spin_lock_bh(&ax25_list_lock);
 	for (ax25=ax25_list; ax25 != NULL; ax25 = ax25->next) {
 		if (ax25->ax25_dev != ax25_dev || !(ax25->condition & AX25_COND_DAMA_MODE))
 			continue;
@@ -96,7 +91,8 @@
 		ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
 		ax25_disconnect(ax25, ETIMEDOUT);
 	}
-	
+	spin_unlock_bh(&ax25_list_lock);
+
 	ax25_dev_dama_off(ax25_dev);
 }
 
@@ -104,33 +100,33 @@
 {
 	switch (ax25->state) {
 
-		case AX25_STATE_0:
-			/* Magic here: If we listen() and a new link dies before it
-			   is accepted() it isn't 'dead' so doesn't get removed. */
-			if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) {
-				ax25_destroy_socket(ax25);
-				return;
+	case AX25_STATE_0:
+		/* Magic here: If we listen() and a new link dies before it
+		   is accepted() it isn't 'dead' so doesn't get removed. */
+		if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) {
+			ax25_destroy_socket(ax25);
+			return;
+		}
+		break;
+
+	case AX25_STATE_3:
+		/*
+		 * Check the state of the receive buffer.
+		 */
+		if (ax25->sk != NULL) {
+			if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) &&
+			    (ax25->condition & AX25_COND_OWN_RX_BUSY)) {
+				ax25->condition &= ~AX25_COND_OWN_RX_BUSY;
+				ax25->condition &= ~AX25_COND_ACK_PENDING;
+				break;
 			}
-			break;
-
-		case AX25_STATE_3:
-			/*
-			 * Check the state of the receive buffer.
-			 */
-			if (ax25->sk != NULL) {
-				if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) && 
-				    (ax25->condition & AX25_COND_OWN_RX_BUSY)) {
-					ax25->condition &= ~AX25_COND_OWN_RX_BUSY;
-					ax25->condition &= ~AX25_COND_ACK_PENDING;
-					break;
-				}
-			}
-			break;
+		}
+		break;
 	}
 
 	ax25_start_heartbeat(ax25);
 }
-	
+
 /* dl1bke 960114: T3 works much like the IDLE timeout, but
  *                gets reloaded with every frame for this
  *		  connection.
@@ -168,7 +164,7 @@
 }
 
 /* dl1bke 960114: The DAMA protocol requires to send data and SABM/DISC
- *                within the poll of any connected channel. Remember 
+ *                within the poll of any connected channel. Remember
  *                that we are not allowed to send anything unless we
  *                get polled by the Master.
  *
@@ -176,48 +172,47 @@
  *                ax25_enquiry_response().
  */
 void ax25_ds_t1_timeout(ax25_cb *ax25)
-{	
+{
 	switch (ax25->state) {
-
-		case AX25_STATE_1: 
-			if (ax25->n2count == ax25->n2) {
-				if (ax25->modulus == AX25_MODULUS) {
-					ax25_disconnect(ax25, ETIMEDOUT);
-					return;
-				} else {
-					ax25->modulus = AX25_MODULUS;
-					ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
-					ax25->n2count = 0;
-					ax25_send_control(ax25, AX25_SABM, AX25_POLLOFF, AX25_COMMAND);
-				}
-			} else {
-				ax25->n2count++;
-				if (ax25->modulus == AX25_MODULUS)
-					ax25_send_control(ax25, AX25_SABM, AX25_POLLOFF, AX25_COMMAND);
-				else
-					ax25_send_control(ax25, AX25_SABME, AX25_POLLOFF, AX25_COMMAND);
-			}
-			break;
-
-		case AX25_STATE_2:
-			if (ax25->n2count == ax25->n2) {
-				ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
-				ax25_disconnect(ax25, ETIMEDOUT);
-				return;
-			} else {
-				ax25->n2count++;
-			}
-			break;
-
-		case AX25_STATE_3:
-			if (ax25->n2count == ax25->n2) {
-				ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
+	case AX25_STATE_1:
+		if (ax25->n2count == ax25->n2) {
+			if (ax25->modulus == AX25_MODULUS) {
 				ax25_disconnect(ax25, ETIMEDOUT);
 				return;
 			} else {
-				ax25->n2count++;
+				ax25->modulus = AX25_MODULUS;
+				ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
+				ax25->n2count = 0;
+				ax25_send_control(ax25, AX25_SABM, AX25_POLLOFF, AX25_COMMAND);
 			}
-			break;
+		} else {
+			ax25->n2count++;
+			if (ax25->modulus == AX25_MODULUS)
+				ax25_send_control(ax25, AX25_SABM, AX25_POLLOFF, AX25_COMMAND);
+			else
+				ax25_send_control(ax25, AX25_SABME, AX25_POLLOFF, AX25_COMMAND);
+		}
+		break;
+
+	case AX25_STATE_2:
+		if (ax25->n2count == ax25->n2) {
+			ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+			ax25_disconnect(ax25, ETIMEDOUT);
+			return;
+		} else {
+			ax25->n2count++;
+		}
+		break;
+
+	case AX25_STATE_3:
+		if (ax25->n2count == ax25->n2) {
+			ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
+			ax25_disconnect(ax25, ETIMEDOUT);
+			return;
+		} else {
+			ax25->n2count++;
+		}
+		break;
 	}
 
 	ax25_calculate_t1(ax25);
diff -Nru a/net/ax25/ax25_iface.c b/net/ax25/ax25_iface.c
--- a/net/ax25/ax25_iface.c	Fri Sep 20 08:20:46 2002
+++ b/net/ax25/ax25_iface.c	Fri Sep 20 08:20:46 2002
@@ -1,18 +1,11 @@
 /*
- *	AX.25 release 037
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	History
- *	AX.25 036	Jonathan(G4KLX)	Split from ax25_timer.c.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
  */
-
 #include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/types.h>
@@ -20,6 +13,7 @@
 #include <linux/in.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/spinlock.h>
 #include <linux/timer.h>
 #include <linux/string.h>
 #include <linux/sockios.h>
@@ -40,22 +34,25 @@
 	unsigned int pid;
 	int (*func)(struct sk_buff *, ax25_cb *);
 } *protocol_list;
+static rwlock_t protocol_list_lock = RW_LOCK_UNLOCKED;
 
 static struct linkfail_struct {
 	struct linkfail_struct *next;
 	void (*func)(ax25_cb *, int);
 } *linkfail_list;
+static spinlock_t linkfail_lock = SPIN_LOCK_UNLOCKED;
 
 static struct listen_struct {
 	struct listen_struct *next;
 	ax25_address  callsign;
 	struct net_device *dev;
 } *listen_list;
+static spinlock_t listen_lock = SPIN_LOCK_UNLOCKED;
 
-int ax25_protocol_register(unsigned int pid, int (*func)(struct sk_buff *, ax25_cb *))
+int ax25_protocol_register(unsigned int pid,
+	int (*func)(struct sk_buff *, ax25_cb *))
 {
 	struct protocol_struct *protocol;
-	unsigned long flags;
 
 	if (pid == AX25_P_TEXT || pid == AX25_P_SEGMENT)
 		return 0;
@@ -69,31 +66,28 @@
 	protocol->pid  = pid;
 	protocol->func = func;
 
-	save_flags(flags);
-	cli();
-
+	write_lock(&protocol_list_lock);
 	protocol->next = protocol_list;
 	protocol_list  = protocol;
-
-	restore_flags(flags);
+	write_unlock(&protocol_list_lock);
 
 	return 1;
 }
 
 void ax25_protocol_release(unsigned int pid)
 {
-	struct protocol_struct *s, *protocol = protocol_list;
-	unsigned long flags;
+	struct protocol_struct *s, *protocol;
 
-	if (protocol == NULL)
+	write_lock(&protocol_list_lock);
+	protocol = protocol_list;
+	if (protocol == NULL) {
+		write_unlock(&protocol_list_lock);
 		return;
-
-	save_flags(flags);
-	cli();
+	}
 
 	if (protocol->pid == pid) {
 		protocol_list = protocol->next;
-		restore_flags(flags);
+		write_unlock(&protocol_list_lock);
 		kfree(protocol);
 		return;
 	}
@@ -102,52 +96,45 @@
 		if (protocol->next->pid == pid) {
 			s = protocol->next;
 			protocol->next = protocol->next->next;
-			restore_flags(flags);
+			write_unlock(&protocol_list_lock);
 			kfree(s);
 			return;
 		}
 
 		protocol = protocol->next;
 	}
-
-	restore_flags(flags);
+	write_unlock(&protocol_list_lock);
 }
 
 int ax25_linkfail_register(void (*func)(ax25_cb *, int))
 {
 	struct linkfail_struct *linkfail;
-	unsigned long flags;
 
 	if ((linkfail = kmalloc(sizeof(*linkfail), GFP_ATOMIC)) == NULL)
 		return 0;
 
 	linkfail->func = func;
 
-	save_flags(flags);
-	cli();
-
+	spin_lock_bh(&linkfail_lock);
 	linkfail->next = linkfail_list;
 	linkfail_list  = linkfail;
-
-	restore_flags(flags);
+	spin_unlock_bh(&linkfail_lock);
 
 	return 1;
 }
 
 void ax25_linkfail_release(void (*func)(ax25_cb *, int))
 {
-	struct linkfail_struct *s, *linkfail = linkfail_list;
-	unsigned long flags;
+	struct linkfail_struct *s, *linkfail;
 
+	spin_lock_bh(&linkfail_lock);
+	linkfail = linkfail_list;
 	if (linkfail == NULL)
 		return;
 
-	save_flags(flags);
-	cli();
-
 	if (linkfail->func == func) {
 		linkfail_list = linkfail->next;
-		restore_flags(flags);
+		spin_unlock_bh(&linkfail_lock);
 		kfree(linkfail);
 		return;
 	}
@@ -156,21 +143,19 @@
 		if (linkfail->next->func == func) {
 			s = linkfail->next;
 			linkfail->next = linkfail->next->next;
-			restore_flags(flags);
+			spin_unlock_bh(&linkfail_lock);
 			kfree(s);
 			return;
 		}
 
 		linkfail = linkfail->next;
 	}
-
-	restore_flags(flags);
+	spin_unlock_bh(&linkfail_lock);
 }
 
 int ax25_listen_register(ax25_address *callsign, struct net_device *dev)
 {
 	struct listen_struct *listen;
-	unsigned long flags;
 
 	if (ax25_listen_mine(callsign, dev))
 		return 0;
@@ -181,31 +166,26 @@
 	listen->callsign = *callsign;
 	listen->dev      = dev;
 
-	save_flags(flags);
-	cli();
-
+	spin_lock_bh(&listen_lock);
 	listen->next = listen_list;
 	listen_list  = listen;
-
-	restore_flags(flags);
+	spin_unlock_bh(&listen_lock);
 
 	return 1;
 }
 
 void ax25_listen_release(ax25_address *callsign, struct net_device *dev)
 {
-	struct listen_struct *s, *listen = listen_list;
-	unsigned long flags;
+	struct listen_struct *s, *listen;
 
+	spin_lock_bh(&listen_lock);
+	listen = listen_list;
 	if (listen == NULL)
 		return;
 
-	save_flags(flags);
-	cli();
-
 	if (ax25cmp(&listen->callsign, callsign) == 0 && listen->dev == dev) {
 		listen_list = listen->next;
-		restore_flags(flags);
+		spin_unlock_bh(&listen_lock);
 		kfree(listen);
 		return;
 	}
@@ -214,35 +194,41 @@
 		if (ax25cmp(&listen->next->callsign, callsign) == 0 && listen->next->dev == dev) {
 			s = listen->next;
 			listen->next = listen->next->next;
-			restore_flags(flags);
+			spin_unlock_bh(&listen_lock);
 			kfree(s);
 			return;
 		}
 
 		listen = listen->next;
 	}
-
-	restore_flags(flags);
+	spin_unlock_bh(&listen_lock);
 }
 
 int (*ax25_protocol_function(unsigned int pid))(struct sk_buff *, ax25_cb *)
 {
+	int (*res)(struct sk_buff *, ax25_cb *) = NULL;
 	struct protocol_struct *protocol;
 
+	read_lock(&protocol_list_lock);
 	for (protocol = protocol_list; protocol != NULL; protocol = protocol->next)
-		if (protocol->pid == pid)
-			return protocol->func;
+		if (protocol->pid == pid) {
+			res = protocol->func;
+			break;
+		}
+	read_unlock(&protocol_list_lock);
 
-	return NULL;
+	return res;
 }
 
 int ax25_listen_mine(ax25_address *callsign, struct net_device *dev)
 {
 	struct listen_struct *listen;
 
+	spin_lock_bh(&listen_lock);
 	for (listen = listen_list; listen != NULL; listen = listen->next)
 		if (ax25cmp(&listen->callsign, callsign) == 0 && (listen->dev == dev || listen->dev == NULL))
 			return 1;
+	spin_unlock_bh(&listen_lock);
 
 	return 0;
 }
@@ -251,18 +237,24 @@
 {
 	struct linkfail_struct *linkfail;
 
+	spin_lock_bh(&linkfail_lock);
 	for (linkfail = linkfail_list; linkfail != NULL; linkfail = linkfail->next)
 		(linkfail->func)(ax25, reason);
+	spin_unlock_bh(&linkfail_lock);
 }
 
 int ax25_protocol_is_registered(unsigned int pid)
 {
 	struct protocol_struct *protocol;
+	int res = 0;
 
+	read_lock(&protocol_list_lock);
 	for (protocol = protocol_list; protocol != NULL; protocol = protocol->next)
-		if (protocol->pid == pid)
-			return 1;
+		if (protocol->pid == pid) {
+			res = 1;
+			break;
+		}
+	read_unlock(&protocol_list_lock);
 
-	return 0;
+	return res;
 }
-
diff -Nru a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c
--- a/net/ax25/ax25_in.c	Fri Sep 20 08:20:43 2002
+++ b/net/ax25/ax25_in.c	Fri Sep 20 08:20:43 2002
@@ -1,44 +1,14 @@
 /*
- *	AX.25 release 037
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	Most of this code is based on the SDL diagrams published in the 7th
- *	ARRL Computer Networking Conference papers. The diagrams have mistakes
- *	in them, but are mostly correct. Before you modify the code could you
- *	read the SDL diagrams as the code is not obvious and probably very
- *	easy to break;
- *
- *	History
- *	AX.25 028a	Jonathan(G4KLX)	New state machine based on SDL diagrams.
- *	AX.25 028b	Jonathan(G4KLX) Extracted AX25 control block from
- *					the sock structure.
- *	AX.25 029	Alan(GW4PTS)	Switched to KA9Q constant names.
- *			Jonathan(G4KLX)	Added IP mode registration.
- *	AX.25 030	Jonathan(G4KLX)	Added AX.25 fragment reception.
- *					Upgraded state machine for SABME.
- *					Added arbitrary protocol id support.
- *	AX.25 031	Joerg(DL1BKE)	Added DAMA support
- *			HaJo(DD8NE)	Added Idle Disc Timer T5
- *			Joerg(DL1BKE)   Renamed it to "IDLE" with a slightly
- *					different behaviour. Fixed defrag
- *					routine (I hope)
- *	AX.25 032	Darryl(G7LED)	AX.25 segmentation fixed.
- *	AX.25 033	Jonathan(G4KLX)	Remove auto-router.
- *					Modularisation changes.
- *	AX.25 035	Hans(PE1AYX)	Fixed interface to IP layer.
- *	AX.25 036	Jonathan(G4KLX)	Move DAMA code into own file.
- *			Joerg(DL1BKE)	Fixed DAMA Slave.
- *	AX.25 037	Jonathan(G4KLX)	New timer architecture.
- *			Thomas(DL9SAU)  Fixed missing initialization of skb->protocol.
+ * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
+ * Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
  */
-
 #include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/types.h>
@@ -146,7 +116,7 @@
 
 #ifdef CONFIG_INET
 	if (pid == AX25_P_IP) {
-		/* working around a TCP bug to keep additional listeners 
+		/* working around a TCP bug to keep additional listeners
 		 * happy. TCP re-uses the buffer and destroys the original
 		 * content.
 		 */
@@ -199,37 +169,33 @@
 		return 0;
 
 	switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
-		case AX25_PROTO_STD_SIMPLEX:
-		case AX25_PROTO_STD_DUPLEX:
-			queued = ax25_std_frame_in(ax25, skb, type);
-			break;
+	case AX25_PROTO_STD_SIMPLEX:
+	case AX25_PROTO_STD_DUPLEX:
+		queued = ax25_std_frame_in(ax25, skb, type);
+		break;
 
 #ifdef CONFIG_AX25_DAMA_SLAVE
-		case AX25_PROTO_DAMA_SLAVE:
-			if (dama || ax25->ax25_dev->dama.slave)
-				queued = ax25_ds_frame_in(ax25, skb, type);
-			else
-				queued = ax25_std_frame_in(ax25, skb, type);
-			break;
+	case AX25_PROTO_DAMA_SLAVE:
+		if (dama || ax25->ax25_dev->dama.slave)
+			queued = ax25_ds_frame_in(ax25, skb, type);
+		else
+			queued = ax25_std_frame_in(ax25, skb, type);
+		break;
 #endif
 	}
 
 	return queued;
 }
 
-static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_address *dev_addr, struct packet_type *ptype)
+static int ax25_rcv(struct sk_buff *skb, struct net_device *dev,
+	ax25_address *dev_addr, struct packet_type *ptype)
 {
-	struct sock *make;
-	struct sock *sk;
-	int type = 0;
+	ax25_address src, dest, *next_digi = NULL;
+	int type = 0, mine = 0, dama;
+	struct sock *make, *sk, *raw;
 	ax25_digi dp, reverse_dp;
 	ax25_cb *ax25;
-	ax25_address src, dest;
-	ax25_address *next_digi = NULL;
 	ax25_dev *ax25_dev;
-	struct sock *raw;
-	int mine = 0;
-	int dama;
 
 	/*
 	 *	Process the AX.25/LAPB frame.
@@ -274,8 +240,10 @@
 	if ((*skb->data & ~0x10) == AX25_UI && dp.lastrepeat + 1 == dp.ndigi) {
 		skb->h.raw = skb->data + 2;		/* skip control and pid */
 
-		if ((raw = ax25_addr_match(&dest)) != NULL)
+		if ((raw = ax25_addr_match(&dest)) != NULL) {
 			ax25_send_to_raw(raw, skb, skb->data[1]);
+			release_sock(raw);
+		}
 
 		if (!mine && ax25cmp(&dest, (ax25_address *)dev->broadcast) != 0) {
 			kfree_skb(skb);
@@ -285,47 +253,49 @@
 		/* Now we are pointing at the pid byte */
 		switch (skb->data[1]) {
 #ifdef CONFIG_INET
-			case AX25_P_IP:
-				skb_pull(skb,2);		/* drop PID/CTRL */
-				skb->h.raw    = skb->data;
-				skb->nh.raw   = skb->data;
-				skb->dev      = dev;
-				skb->pkt_type = PACKET_HOST;
-				skb->protocol = htons(ETH_P_IP);
-				ip_rcv(skb, dev, ptype);	/* Note ptype here is the wrong one, fix me later */
-				break;
-
-			case AX25_P_ARP:
-				skb_pull(skb,2);
-				skb->h.raw    = skb->data;
-				skb->nh.raw   = skb->data;
-				skb->dev      = dev;
-				skb->pkt_type = PACKET_HOST;
-				skb->protocol = htons(ETH_P_ARP);
-				arp_rcv(skb, dev, ptype);	/* Note ptype here is wrong... */
-				break;
+		case AX25_P_IP:
+			skb_pull(skb,2);		/* drop PID/CTRL */
+			skb->h.raw    = skb->data;
+			skb->nh.raw   = skb->data;
+			skb->dev      = dev;
+			skb->pkt_type = PACKET_HOST;
+			skb->protocol = htons(ETH_P_IP);
+			ip_rcv(skb, dev, ptype);	/* Note ptype here is the wrong one, fix me later */
+			break;
+
+		case AX25_P_ARP:
+			skb_pull(skb,2);
+			skb->h.raw    = skb->data;
+			skb->nh.raw   = skb->data;
+			skb->dev      = dev;
+			skb->pkt_type = PACKET_HOST;
+			skb->protocol = htons(ETH_P_ARP);
+			arp_rcv(skb, dev, ptype);	/* Note ptype here is wrong... */
+			break;
 #endif
-			case AX25_P_TEXT:
-				/* Now find a suitable dgram socket */
-				if ((sk = ax25_find_socket(&dest, &src, SOCK_DGRAM)) != NULL) {
-					if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf) {
-						kfree_skb(skb);
-					} else {
-						/*
-						 *	Remove the control and PID.
-						 */
-						skb_pull(skb, 2);
-						if (sock_queue_rcv_skb(sk, skb) != 0)
-							kfree_skb(skb);
-					}
-				} else {
+		case AX25_P_TEXT:
+			/* Now find a suitable dgram socket */
+			sk = ax25_get_socket(&dest, &src, SOCK_DGRAM);
+			if (sk != NULL) {
+				if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf) {
 					kfree_skb(skb);
+				} else {
+					/*
+					 *	Remove the control and PID.
+					 */
+					skb_pull(skb, 2);
+					if (sock_queue_rcv_skb(sk, skb) != 0)
+						kfree_skb(skb);
 				}
-				break;
+				release_sock(sk);
+			} else {
+				kfree_skb(skb);
+			}
+			break;
 
-			default:
-				kfree_skb(skb);	/* Will scan SOCK_AX25 RAW sockets */
-				break;
+		default:
+			kfree_skb(skb);	/* Will scan SOCK_AX25 RAW sockets */
+			break;
 		}
 
 		return 0;
@@ -349,9 +319,10 @@
 
 	if ((ax25 = ax25_find_cb(&dest, &src, &reverse_dp, dev)) != NULL) {
 		/*
-		 *	Process the frame. If it is queued up internally it returns one otherwise we
-		 *	free it immediately. This routine itself wakes the user context layers so we
-		 *	do no further work
+		 *	Process the frame. If it is queued up internally it
+		 *	returns one otherwise we free it immediately. This
+		 *	routine itself wakes the user context layers so we do
+		 *	no further work
 		 */
 		if (ax25_process_rx_frame(ax25, skb, type, dama) == 0)
 			kfree_skb(skb);
@@ -363,7 +334,8 @@
 
 	/* a) received not a SABM(E) */
 
-	if ((*skb->data & ~AX25_PF) != AX25_SABM && (*skb->data & ~AX25_PF) != AX25_SABME) {
+	if ((*skb->data & ~AX25_PF) != AX25_SABM &&
+	    (*skb->data & ~AX25_PF) != AX25_SABME) {
 		/*
 		 *	Never reply to a DM. Also ignore any connects for
 		 *	addresses that are not our interfaces and not a socket.
@@ -383,9 +355,12 @@
 		sk = ax25_find_listener(next_digi, 1, dev, SOCK_SEQPACKET);
 
 	if (sk != NULL) {
-		if (sk->ack_backlog == sk->max_ack_backlog || (make = ax25_make_new(sk, ax25_dev)) == NULL) {
-			if (mine) ax25_return_dm(dev, &src, &dest, &dp);
+		if (sk->ack_backlog == sk->max_ack_backlog ||
+		    (make = ax25_make_new(sk, ax25_dev)) == NULL) {
+			if (mine)
+				ax25_return_dm(dev, &src, &dest, &dp);
 			kfree_skb(skb);
+
 			return 0;
 		}
 
@@ -486,4 +461,3 @@
 
 	return ax25_rcv(skb, dev, (ax25_address *)dev->dev_addr, ptype);
 }
-
diff -Nru a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c
--- a/net/ax25/ax25_ip.c	Fri Sep 20 08:20:44 2002
+++ b/net/ax25/ax25_ip.c	Fri Sep 20 08:20:44 2002
@@ -1,18 +1,11 @@
 /*
- *	AX.25 release 037
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	History
- *	AX.25 036	Jonathan(G4KLX)	Split from af_ax25.c.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
  */
-
 #include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/types.h>
@@ -88,16 +81,16 @@
 
   	/* Append a suitable AX.25 PID */
   	switch (type) {
-  		case ETH_P_IP:
-  			*buff++ = AX25_P_IP;
- 			break;
-  		case ETH_P_ARP:
-  			*buff++ = AX25_P_ARP;
-  			break;
-  		default:
-  			printk(KERN_ERR "AX.25: ax25_encapsulate - wrong protocol type 0x%2.2x\n", type);
-  			*buff++ = 0;
-  			break;
+  	case ETH_P_IP:
+  		*buff++ = AX25_P_IP;
+ 		break;
+  	case ETH_P_ARP:
+  		*buff++ = AX25_P_ARP;
+  		break;
+  	default:
+  		printk(KERN_ERR "AX.25: ax25_encapsulate - wrong protocol type 0x%2.2x\n", type);
+  		*buff++ = 0;
+  		break;
  	}
 
 	if (daddr != NULL)
@@ -112,8 +105,8 @@
 	unsigned char *bp  = skb->data;
 	struct net_device *dev;
 	ax25_address *src, *dst;
-	ax25_route *route;
 	ax25_dev *ax25_dev;
+	ax25_route _route, *route = &_route;
 
 	dst = (ax25_address *)(bp + 1);
 	src = (ax25_address *)(bp + 8);
@@ -121,14 +114,15 @@
   	if (arp_find(bp + 1, skb))
   		return 1;
 
-	route    = ax25_rt_find_route(dst, NULL);
+	route = ax25_rt_find_route(route, dst, NULL);
 	dev      = route->dev;
 
 	if (dev == NULL)
 		dev = skb->dev;
 
-        if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
-                return 1;
+        if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) {
+                goto put;
+	}
 
 	if (bp[16] == AX25_P_IP) {
 		if (route->ip_mode == 'V' || (route->ip_mode == ' ' && ax25_dev->values[AX25_VALUES_IPDEFMODE])) {
@@ -153,7 +147,7 @@
 
 			if ((ourskb = skb_copy(skb, GFP_ATOMIC)) == NULL) {
 				kfree_skb(skb);
-				return 1;
+				goto put;
 			}
 
 			if (skb->sk != NULL)
@@ -167,10 +161,10 @@
 			skb_pull(ourskb, AX25_HEADER_LEN - 1);	/* Keep PID */
 			ourskb->nh.raw = ourskb->data;
 
-			ax25_send_frame(ourskb, ax25_dev->values[AX25_VALUES_PACLEN], &src_c, 
+			ax25_send_frame(ourskb, ax25_dev->values[AX25_VALUES_PACLEN], &src_c,
 &dst_c, route->digipeat, dev);
 
-			return 1;
+			goto put;
 		}
 	}
 
@@ -187,7 +181,7 @@
 	if (route->digipeat != NULL) {
 		if ((ourskb = ax25_rt_build_path(skb, src, dst, route->digipeat)) == NULL) {
 			kfree_skb(skb);
-			return 1;
+			goto put;
 		}
 
 		skb = ourskb;
@@ -196,6 +190,9 @@
 	skb->dev      = dev;
 
 	ax25_queue_xmit(skb);
+
+put:
+	ax25_put_route(route);
 
   	return 1;
 }
diff -Nru a/net/ax25/ax25_out.c b/net/ax25/ax25_out.c
--- a/net/ax25/ax25_out.c	Fri Sep 20 08:20:47 2002
+++ b/net/ax25/ax25_out.c	Fri Sep 20 08:20:47 2002
@@ -1,39 +1,13 @@
 /*
- *	AX.25 release 037
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	Most of this code is based on the SDL diagrams published in the 7th
- *	ARRL Computer Networking Conference papers. The diagrams have mistakes
- *	in them, but are mostly correct. Before you modify the code could you
- *	read the SDL diagrams as the code is not obvious and probably very
- *	easy to break;
- *
- *	History
- *	AX.25 028a	Jonathan(G4KLX)	New state machine based on SDL diagrams.
- *	AX.25 029	Alan(GW4PTS)	Switched to KA9Q constant names.
- *			Jonathan(G4KLX)	Only poll when window is full.
- *	AX.25 030	Jonathan(G4KLX)	Added fragmentation to ax25_output.
- *					Added support for extended AX.25.
- *	AX.25 031	Joerg(DL1BKE)	Added DAMA support
- *			Joerg(DL1BKE)	Modified fragmenter to fragment vanilla 
- *					AX.25 I-Frames. Added PACLEN parameter.
- *			Joerg(DL1BKE)	Fixed a problem with buffer allocation
- *					for fragments.
- *	AX.25 037	Jonathan(G4KLX)	New timer architecture.
- *			Joerg(DL1BKE)	Fixed DAMA Slave mode: will work
- *					on non-DAMA interfaces like AX25L2V2
- *					again (this behaviour is _required_).
- *			Joerg(DL1BKE)	ax25_check_iframes_acked() returns a 
- *					value now (for DAMA n2count handling)
+ * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
  */
-
 #include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/types.h>
@@ -44,6 +18,7 @@
 #include <linux/timer.h>
 #include <linux/string.h>
 #include <linux/sockios.h>
+#include <linux/spinlock.h>
 #include <linux/net.h>
 #include <net/ax25.h>
 #include <linux/inet.h>
@@ -57,6 +32,8 @@
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 
+static spinlock_t ax25_frag_lock = SPIN_LOCK_UNLOCKED;
+
 ax25_cb *ax25_send_frame(struct sk_buff *skb, int paclen, ax25_address *src, ax25_address *dest, ax25_digi *digi, struct net_device *dev)
 {
 	ax25_dev *ax25_dev;
@@ -101,18 +78,18 @@
 	}
 
 	switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
-		case AX25_PROTO_STD_SIMPLEX:
-		case AX25_PROTO_STD_DUPLEX:
-			ax25_std_establish_data_link(ax25);
-			break;
+	case AX25_PROTO_STD_SIMPLEX:
+	case AX25_PROTO_STD_DUPLEX:
+		ax25_std_establish_data_link(ax25);
+		break;
 
 #ifdef CONFIG_AX25_DAMA_SLAVE
-		case AX25_PROTO_DAMA_SLAVE:
-			if (ax25_dev->dama.slave)
-				ax25_ds_establish_data_link(ax25);
-			else
-				ax25_std_establish_data_link(ax25);
-			break;
+	case AX25_PROTO_DAMA_SLAVE:
+		if (ax25_dev->dama.slave)
+			ax25_ds_establish_data_link(ax25);
+		else
+			ax25_std_establish_data_link(ax25);
+		break;
 #endif
 	}
 
@@ -138,7 +115,6 @@
 	struct sk_buff *skbn;
 	unsigned char *p;
 	int frontlen, len, fragno, ka9qfrag, first = 1;
-	long flags;
 
 	if ((skb->len - 1) > paclen) {
 		if (*skb->data == AX25_P_TEXT) {
@@ -155,20 +131,18 @@
 		frontlen = skb_headroom(skb);	/* Address space + CTRL */
 
 		while (skb->len > 0) {
-			save_flags(flags); 
-			cli();
-
+			spin_lock_bh(&ax25_frag_lock);
 			if ((skbn = alloc_skb(paclen + 2 + frontlen, GFP_ATOMIC)) == NULL) {
-				restore_flags(flags);
+				spin_unlock_bh(&ax25_frag_lock);
 				printk(KERN_CRIT "AX.25: ax25_output - out of memory\n");
 				return;
 			}
 
 			if (skb->sk != NULL)
 				skb_set_owner_w(skbn, skb->sk);
-			
-			restore_flags(flags);
-			
+
+			spin_unlock_bh(&ax25_frag_lock);
+
 			len = (paclen > skb->len) ? skb->len : paclen;
 
 			if (ka9qfrag == 1) {
@@ -202,24 +176,24 @@
 	}
 
 	switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
-		case AX25_PROTO_STD_SIMPLEX:
-		case AX25_PROTO_STD_DUPLEX:
-			ax25_kick(ax25);
-			break;
+	case AX25_PROTO_STD_SIMPLEX:
+	case AX25_PROTO_STD_DUPLEX:
+		ax25_kick(ax25);
+		break;
 
 #ifdef CONFIG_AX25_DAMA_SLAVE
-		/* 
-		 * A DAMA slave is _required_ to work as normal AX.25L2V2
-		 * if no DAMA master is available.
-		 */
-		case AX25_PROTO_DAMA_SLAVE:
-			if (!ax25->ax25_dev->dama.slave) ax25_kick(ax25);
-			break;
+	/*
+	 * A DAMA slave is _required_ to work as normal AX.25L2V2
+	 * if no DAMA master is available.
+	 */
+	case AX25_PROTO_DAMA_SLAVE:
+		if (!ax25->ax25_dev->dama.slave) ax25_kick(ax25);
+		break;
 #endif
 	}
 }
 
-/* 
+/*
  *  This procedure is passed a buffer descriptor for an iframe. It builds
  *  the rest of the control part of the frame and then writes it out.
  */
@@ -305,15 +279,15 @@
 		 * in DAMA mode.
 		 */
 		switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
-			case AX25_PROTO_STD_SIMPLEX:
-			case AX25_PROTO_STD_DUPLEX:
-				ax25_send_iframe(ax25, skbn, (last) ? AX25_POLLON : AX25_POLLOFF);
-				break;
+		case AX25_PROTO_STD_SIMPLEX:
+		case AX25_PROTO_STD_DUPLEX:
+			ax25_send_iframe(ax25, skbn, (last) ? AX25_POLLON : AX25_POLLOFF);
+			break;
 
 #ifdef CONFIG_AX25_DAMA_SLAVE
-			case AX25_PROTO_DAMA_SLAVE:
-				ax25_send_iframe(ax25, skbn, AX25_POLLOFF);
-				break;
+		case AX25_PROTO_DAMA_SLAVE:
+			ax25_send_iframe(ax25, skbn, AX25_POLLOFF);
+			break;
 #endif
 		}
 
diff -Nru a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c
--- a/net/ax25/ax25_route.c	Fri Sep 20 08:20:47 2002
+++ b/net/ax25/ax25_route.c	Fri Sep 20 08:20:47 2002
@@ -1,49 +1,20 @@
 /*
- *	AX.25 release 037
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	Other kernels modules in this kit are generally BSD derived. See the copyright headers.
- *
- *
- *	History
- *	AX.25 020	Jonathan(G4KLX)	First go.
- *	AX.25 022	Jonathan(G4KLX)	Added the actual meat to this - we now have a nice heard list.
- *	AX.25 025	Alan(GW4PTS)	First cut at autobinding by route scan.
- *	AX.25 028b	Jonathan(G4KLX)	Extracted AX25 control block from the
- *					sock structure. Device removal now
- *					removes the heard structure.
- *	AX.25 029	Steven(GW7RRM)	Added /proc information for uid/callsign mapping.
- *			Jonathan(G4KLX)	Handling of IP mode in the routing list and /proc entry.
- *	AX.25 030	Jonathan(G4KLX)	Added digi-peaters to routing table, and
- *					ioctls to manipulate them. Added port
- *					configuration.
- *	AX.25 031	Jonathan(G4KLX)	Added concept of default route.
- *			Joerg(DL1BKE)	ax25_rt_build_path() find digipeater list and device by 
- *					destination call. Needed for IP routing via digipeater
- *			Jonathan(G4KLX)	Added routing for IP datagram packets.
- *			Joerg(DL1BKE)	Changed routing for IP datagram and VC to use a default
- *					route if available. Does not overwrite default routes
- *					on route-table overflow anymore.
- *			Joerg(DL1BKE)	Fixed AX.25 routing of IP datagram and VC, new ioctl()
- *					"SIOCAX25OPTRT" to set IP mode and a 'permanent' flag
- *					on routes.
- *	AX.25 033	Jonathan(G4KLX)	Remove auto-router.
- *			Joerg(DL1BKE)	Moved BPQ Ethernet driver to separate device.
- *	AX.25 035	Frederic(F1OAT)	Support for pseudo-digipeating.
- *			Jonathan(G4KLX)	Support for packet forwarding.
- *			Arnaldo C. Melo s/suser/capable/
+ * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright (C) Steven Whitehouse GW7RRM (stevew@acm.org)
+ * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
+ * Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
+ * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
  */
-
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
+#include <linux/timer.h>
 #include <linux/in.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -56,6 +27,7 @@
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
+#include <linux/spinlock.h>
 #include <net/sock.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -65,8 +37,9 @@
 #include <linux/init.h>
 
 static ax25_route *ax25_route_list;
+static rwlock_t ax25_route_lock = RW_LOCK_UNLOCKED;
 
-static ax25_route *ax25_find_route(ax25_address *, struct net_device *);
+static ax25_route *ax25_get_route(ax25_address *, struct net_device *);
 
 /*
  * small macro to drop non-digipeated digipeaters and reverse path
@@ -86,8 +59,10 @@
 
 void ax25_rt_device_down(struct net_device *dev)
 {
-	ax25_route *s, *t, *ax25_rt = ax25_route_list;
-	
+	ax25_route *s, *t, *ax25_rt;
+
+	write_lock(&ax25_route_lock);
+	ax25_rt = ax25_route_list;
 	while (ax25_rt != NULL) {
 		s       = ax25_rt;
 		ax25_rt = ax25_rt->next;
@@ -111,129 +86,196 @@
 			}
 		}
 	}
+	write_unlock(&ax25_route_lock);
 }
 
-int ax25_rt_ioctl(unsigned int cmd, void *arg)
+static int ax25_rt_add(struct ax25_routes_struct *route)
 {
-	unsigned long flags;
-	ax25_route *s, *t, *ax25_rt;
-	struct ax25_routes_struct route;
-	struct ax25_route_opt_struct rt_option;
+	ax25_route *ax25_rt;
 	ax25_dev *ax25_dev;
 	int i;
 
-	switch (cmd) {
-		case SIOCADDRT:
-			if (copy_from_user(&route, arg, sizeof(route)))
-				return -EFAULT;
-			if ((ax25_dev = ax25_addr_ax25dev(&route.port_addr)) == NULL)
-				return -EINVAL;
-			if (route.digi_count > AX25_MAX_DIGIS)
-				return -EINVAL;
-			for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
-				if (ax25cmp(&ax25_rt->callsign, &route.dest_addr) == 0 && ax25_rt->dev == ax25_dev->dev) {
-					if (ax25_rt->digipeat != NULL) {
-						kfree(ax25_rt->digipeat);
-						ax25_rt->digipeat = NULL;
-					}
-					if (route.digi_count != 0) {
-						if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
-							return -ENOMEM;
-						ax25_rt->digipeat->lastrepeat = -1;
-						ax25_rt->digipeat->ndigi      = route.digi_count;
-						for (i = 0; i < route.digi_count; i++) {
-							ax25_rt->digipeat->repeated[i] = 0;
-							ax25_rt->digipeat->calls[i]    = route.digi_addr[i];
-						}
-					}
-					return 0;
-				}
+	if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL)
+		return -EINVAL;
+	if (route->digi_count > AX25_MAX_DIGIS)
+		return -EINVAL;
+
+	write_lock(&ax25_route_lock);
+
+	ax25_rt = ax25_route_list;
+	while (ax25_rt != NULL) {
+		if (ax25cmp(&ax25_rt->callsign, &route->dest_addr) == 0 &&
+		            ax25_rt->dev == ax25_dev->dev) {
+			if (ax25_rt->digipeat != NULL) {
+				kfree(ax25_rt->digipeat);
+				ax25_rt->digipeat = NULL;
 			}
-			if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL)
-				return -ENOMEM;
-			ax25_rt->callsign     = route.dest_addr;
-			ax25_rt->dev          = ax25_dev->dev;
-			ax25_rt->digipeat     = NULL;
-			ax25_rt->ip_mode      = ' ';
-			if (route.digi_count != 0) {
+			if (route->digi_count != 0) {
 				if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
-					kfree(ax25_rt);
+					write_unlock(&ax25_route_lock);
 					return -ENOMEM;
 				}
 				ax25_rt->digipeat->lastrepeat = -1;
-				ax25_rt->digipeat->ndigi      = route.digi_count;
-				for (i = 0; i < route.digi_count; i++) {
+				ax25_rt->digipeat->ndigi      = route->digi_count;
+				for (i = 0; i < route->digi_count; i++) {
 					ax25_rt->digipeat->repeated[i] = 0;
-					ax25_rt->digipeat->calls[i]    = route.digi_addr[i];
+					ax25_rt->digipeat->calls[i]    = route->digi_addr[i];
 				}
 			}
-			save_flags(flags); cli();
-			ax25_rt->next   = ax25_route_list;
-			ax25_route_list = ax25_rt;
-			restore_flags(flags);
-			break;
+			return 0;
+		}
+		ax25_rt = ax25_rt->next;
+	}
 
-		case SIOCDELRT:
-			if (copy_from_user(&route, arg, sizeof(route)))
-				return -EFAULT;
-			if ((ax25_dev = ax25_addr_ax25dev(&route.port_addr)) == NULL)
-				return -EINVAL;
-			ax25_rt = ax25_route_list;
-			while (ax25_rt != NULL) {
-				s       = ax25_rt;
-				ax25_rt = ax25_rt->next;
-				if (s->dev == ax25_dev->dev && ax25cmp(&route.dest_addr, &s->callsign) == 0) {
-					if (ax25_route_list == s) {
-						ax25_route_list = s->next;
-						if (s->digipeat != NULL)
-							kfree(s->digipeat);
-						kfree(s);
-					} else {
-						for (t = ax25_route_list; t != NULL; t = t->next) {
-							if (t->next == s) {
-								t->next = s->next;
-								if (s->digipeat != NULL)
-									kfree(s->digipeat);
-								kfree(s);
-								break;
-							}
-						}				
+	if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL) {
+		write_unlock(&ax25_route_lock);
+		return -ENOMEM;
+	}
+
+	atomic_set(&ax25_rt->ref, 0);
+	ax25_rt->callsign     = route->dest_addr;
+	ax25_rt->dev          = ax25_dev->dev;
+	ax25_rt->digipeat     = NULL;
+	ax25_rt->ip_mode      = ' ';
+	if (route->digi_count != 0) {
+		if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
+			write_unlock(&ax25_route_lock);
+			kfree(ax25_rt);
+			return -ENOMEM;
+		}
+		ax25_rt->digipeat->lastrepeat = -1;
+		ax25_rt->digipeat->ndigi      = route->digi_count;
+		for (i = 0; i < route->digi_count; i++) {
+			ax25_rt->digipeat->repeated[i] = 0;
+			ax25_rt->digipeat->calls[i]    = route->digi_addr[i];
+		}
+	}
+	ax25_rt->next   = ax25_route_list;
+	ax25_route_list = ax25_rt;
+	write_unlock(&ax25_route_lock);
+
+	return 0;
+}
+
+static void ax25_rt_destroy(ax25_route *ax25_rt)
+{
+	if (atomic_read(&ax25_rt->ref) == 0) {
+		if (ax25_rt->digipeat != NULL)
+			kfree(ax25_rt->digipeat);
+		kfree(ax25_rt);
+	}
+
+	/*
+	 * Uh...  Route is still in use; we can't yet destroy it.  Retry later.
+	 */
+	init_timer(&ax25_rt->timer);
+	ax25_rt->timer.data	= (unsigned long) ax25_rt;
+	ax25_rt->timer.function	= (void *) ax25_rt_destroy;
+	ax25_rt->timer.expires	= jiffies + 5 * HZ;
+
+	add_timer(&ax25_rt->timer);
+}
+
+static int ax25_rt_del(struct ax25_routes_struct *route)
+{
+	ax25_route *s, *t, *ax25_rt;
+	ax25_dev *ax25_dev;
+
+	if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL)
+		return -EINVAL;
+
+	write_lock(&ax25_route_lock);
+
+	ax25_rt = ax25_route_list;
+	while (ax25_rt != NULL) {
+		s       = ax25_rt;
+		ax25_rt = ax25_rt->next;
+		if (s->dev == ax25_dev->dev &&
+		    ax25cmp(&route->dest_addr, &s->callsign) == 0) {
+			if (ax25_route_list == s) {
+				ax25_route_list = s->next;
+				ax25_rt_destroy(s);
+			} else {
+				for (t = ax25_route_list; t != NULL; t = t->next) {
+					if (t->next == s) {
+						t->next = s->next;
+						ax25_rt_destroy(s);
+						break;
 					}
 				}
 			}
-			break;
+		}
+	}
+	write_unlock(&ax25_route_lock);
 
-		case SIOCAX25OPTRT:
-			if (copy_from_user(&rt_option, arg, sizeof(rt_option)))
-				return -EFAULT;
-			if ((ax25_dev = ax25_addr_ax25dev(&rt_option.port_addr)) == NULL)
-				return -EINVAL;
-			for (ax25_rt = ax25_route_list; ax25_rt != NULL; ax25_rt = ax25_rt->next) {
-				if (ax25_rt->dev == ax25_dev->dev && ax25cmp(&rt_option.dest_addr, &ax25_rt->callsign) == 0) {
-					switch (rt_option.cmd) {
-						case AX25_SET_RT_IPMODE:
-							switch (rt_option.arg) {
-								case ' ':
-								case 'D':
-								case 'V':
-									ax25_rt->ip_mode = rt_option.arg;
-									break;
-								default:
-									return -EINVAL;
-							}
-							break;
-						default:
-							return -EINVAL;
-					}
+	return 0;
+}
+
+static int ax25_rt_opt(struct ax25_route_opt_struct *rt_option)
+{
+	ax25_route *ax25_rt;
+	ax25_dev *ax25_dev;
+	int err = 0;
+
+	if ((ax25_dev = ax25_addr_ax25dev(&rt_option->port_addr)) == NULL)
+		return -EINVAL;
+
+	write_lock(&ax25_route_lock);
+
+	ax25_rt = ax25_route_list;
+	while (ax25_rt != NULL) {
+		if (ax25_rt->dev == ax25_dev->dev &&
+		    ax25cmp(&rt_option->dest_addr, &ax25_rt->callsign) == 0) {
+			switch (rt_option->cmd) {
+			case AX25_SET_RT_IPMODE:
+				switch (rt_option->arg) {
+				case ' ':
+				case 'D':
+				case 'V':
+					ax25_rt->ip_mode = rt_option->arg;
+					break;
+				default:
+					err = -EINVAL;
+					goto out;
 				}
+				break;
+			default:
+				err = -EINVAL;
+				goto out;
 			}
-			break;
-
-		default:
-			return -EINVAL;
+		}
+		ax25_rt = ax25_rt->next;
 	}
 
-	return 0;
+out:
+	write_unlock(&ax25_route_lock);
+	return err;
+}
+
+int ax25_rt_ioctl(unsigned int cmd, void *arg)
+{
+	struct ax25_route_opt_struct rt_option;
+	struct ax25_routes_struct route;
+
+	switch (cmd) {
+	case SIOCADDRT:
+		if (copy_from_user(&route, arg, sizeof(route)))
+			return -EFAULT;
+		return ax25_rt_add(&route);
+
+	case SIOCDELRT:
+		if (copy_from_user(&route, arg, sizeof(route)))
+			return -EFAULT;
+		return ax25_rt_del(&route);
+
+	case SIOCAX25OPTRT:
+		if (copy_from_user(&rt_option, arg, sizeof(rt_option)))
+			return -EFAULT;
+		return ax25_rt_opt(&rt_option);
+
+	default:
+		return -EINVAL;
+	}
 }
 
 int ax25_rt_get_info(char *buffer, char **start, off_t offset, int length)
@@ -244,8 +286,8 @@
 	off_t begin = 0;
 	char *callsign;
 	int i;
-  
-	cli();
+
+	read_lock(&ax25_route_lock);
 
 	len += sprintf(buffer, "callsign  dev  mode digipeaters\n");
 
@@ -259,15 +301,15 @@
 			ax25_rt->dev ? ax25_rt->dev->name : "???");
 
 		switch (ax25_rt->ip_mode) {
-			case 'V':
-				len += sprintf(buffer + len, "   vc");
-				break;
-			case 'D':
-				len += sprintf(buffer + len, "   dg");
-				break;
-			default:
-				len += sprintf(buffer + len, "    *");
-				break;
+		case 'V':
+			len += sprintf(buffer + len, "   vc");
+			break;
+		case 'D':
+			len += sprintf(buffer + len, "   dg");
+			break;
+		default:
+			len += sprintf(buffer + len, "    *");
+			break;
 		}
 
 		if (ax25_rt->digipeat != NULL)
@@ -286,26 +328,29 @@
 		if (pos > offset + length)
 			break;
 	}
-
-	sti();
+	read_unlock(&ax25_route_lock);
 
 	*start = buffer + (offset - begin);
 	len   -= (offset - begin);
 
-	if (len > length) len = length;
+	if (len > length)
+		len = length;
 
 	return len;
-} 
+}
 
 /*
  *	Find AX.25 route
+ *
+ *	Only routes with a refernce rout of zero can be destroyed.
  */
-static ax25_route *ax25_find_route(ax25_address *addr, struct net_device *dev)
+static ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev)
 {
 	ax25_route *ax25_spe_rt = NULL;
 	ax25_route *ax25_def_rt = NULL;
 	ax25_route *ax25_rt;
 
+	read_lock(&ax25_route_lock);
 	/*
 	 *	Bind to the physical interface we heard them on, or the default
 	 *	route if none is found;
@@ -324,10 +369,16 @@
 		}
 	}
 
+	ax25_rt = ax25_def_rt;
 	if (ax25_spe_rt != NULL)
-		return ax25_spe_rt;
+		ax25_rt = ax25_spe_rt;
 
-	return ax25_def_rt;
+	if (ax25_rt != NULL)
+		atomic_inc(&ax25_rt->ref);
+
+	read_unlock(&ax25_route_lock);
+
+	return ax25_rt;
 }
 
 /*
@@ -346,7 +397,7 @@
 
 	digipeat->ndigi = k;
 }
- 
+
 
 /*
  *	Find which interface to use.
@@ -355,24 +406,31 @@
 {
 	ax25_route *ax25_rt;
 	ax25_address *call;
+	int err;
 
-	if ((ax25_rt = ax25_find_route(addr, NULL)) == NULL)
+	if ((ax25_rt = ax25_get_route(addr, NULL)) == NULL)
 		return -EHOSTUNREACH;
 
-	if ((ax25->ax25_dev = ax25_dev_ax25dev(ax25_rt->dev)) == NULL)
-		return -EHOSTUNREACH;
+	if ((ax25->ax25_dev = ax25_dev_ax25dev(ax25_rt->dev)) == NULL) {
+		err = -EHOSTUNREACH;
+		goto put;
+	}
 
 	if ((call = ax25_findbyuid(current->euid)) == NULL) {
-		if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE))
-			return -EPERM;
+		if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) {
+			err = -EPERM;
+			goto put;
+		}
 		call = (ax25_address *)ax25->ax25_dev->dev->dev_addr;
 	}
 
 	ax25->source_addr = *call;
 
 	if (ax25_rt->digipeat != NULL) {
-		if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL)
-			return -ENOMEM;
+		if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
+			err = -ENOMEM;
+			goto put;
+		}
 		memcpy(ax25->digipeat, ax25_rt->digipeat, sizeof(ax25_digi));
 		ax25_adjust_path(addr, ax25->digipeat);
 	}
@@ -380,31 +438,32 @@
 	if (ax25->sk != NULL)
 		ax25->sk->zapped = 0;
 
+put:
+	ax25_put_route(ax25_rt);
+
 	return 0;
 }
 
-/*
- *	dl1bke 960117: build digipeater path
- *	dl1bke 960301: use the default route if it exists
- */
-ax25_route *ax25_rt_find_route(ax25_address *addr, struct net_device *dev)
+ax25_route *ax25_rt_find_route(ax25_route * route, ax25_address *addr,
+	struct net_device *dev)
 {
-	static ax25_route route;
 	ax25_route *ax25_rt;
 
-	if ((ax25_rt = ax25_find_route(addr, dev)) == NULL) {
-		route.next     = NULL;
-		route.callsign = *addr;
-		route.dev      = dev;
-		route.digipeat = NULL;
-		route.ip_mode  = ' ';
-		return &route;
-	}
+	if ((ax25_rt = ax25_get_route(addr, dev)))
+		return ax25_rt;
 
-	return ax25_rt;
+	route->next     = NULL;
+	atomic_set(&route->ref, 1);
+	route->callsign = *addr;
+	route->dev      = dev;
+	route->digipeat = NULL;
+	route->ip_mode  = ' ';
+
+	return route;
 }
 
-struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src, ax25_address *dest, ax25_digi *digi)
+struct sk_buff *ax25_rt_build_path(struct sk_buff *skb, ax25_address *src,
+	ax25_address *dest, ax25_digi *digi)
 {
 	struct sk_buff *skbn;
 	unsigned char *bp;
@@ -440,6 +499,7 @@
 {
 	ax25_route *s, *ax25_rt = ax25_route_list;
 
+	write_unlock(&ax25_route_lock);
 	while (ax25_rt != NULL) {
 		s       = ax25_rt;
 		ax25_rt = ax25_rt->next;
@@ -449,4 +509,5 @@
 
 		kfree(s);
 	}
+	write_unlock(&ax25_route_lock);
 }
diff -Nru a/net/ax25/ax25_std_in.c b/net/ax25/ax25_std_in.c
--- a/net/ax25/ax25_std_in.c	Fri Sep 20 08:20:43 2002
+++ b/net/ax25/ax25_std_in.c	Fri Sep 20 08:20:43 2002
@@ -1,42 +1,19 @@
 /*
- *	AX.25 release 037
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
+ * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
+ * Copyright (C) Hans-Joachim Hetscher DD8NE (dd8ne@bnv-bamberg.de)
  *
- *	This module:
- *		This module 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.
- *
- *	Most of this code is based on the SDL diagrams published in the 7th
- *	ARRL Computer Networking Conference papers. The diagrams have mistakes
- *	in them, but are mostly correct. Before you modify the code could you
- *	read the SDL diagrams as the code is not obvious and probably very
- *	easy to break;
- *
- *	History
- *	AX.25 028a	Jonathan(G4KLX)	New state machine based on SDL diagrams.
- *	AX.25 028b	Jonathan(G4KLX) Extracted AX25 control block from
- *					the sock structure.
- *	AX.25 029	Alan(GW4PTS)	Switched to KA9Q constant names.
- *			Jonathan(G4KLX)	Added IP mode registration.
- *	AX.25 030	Jonathan(G4KLX)	Added AX.25 fragment reception.
- *					Upgraded state machine for SABME.
- *					Added arbitrary protocol id support.
- *	AX.25 031	Joerg(DL1BKE)	Added DAMA support
- *			HaJo(DD8NE)	Added Idle Disc Timer T5
- *			Joerg(DL1BKE)   Renamed it to "IDLE" with a slightly
- *					different behaviour. Fixed defrag
- *					routine (I hope)
- *	AX.25 032	Darryl(G7LED)	AX.25 segmentation fixed.
- *	AX.25 033	Jonathan(G4KLX)	Remove auto-router.
- *					Modularisation changes.
- *	AX.25 035	Hans(PE1AYX)	Fixed interface to IP layer.
- *	AX.25 036	Jonathan(G4KLX)	Cloned from ax25_in.c.
- *	AX.25 037	Jonathan(G4KLX)	New timer architecture.
+ * Most of this code is based on the SDL diagrams published in the 7th ARRL
+ * Computer Networking Conference papers. The diagrams have mistakes in them,
+ * but are mostly correct. Before you modify the code could you read the SDL
+ * diagrams as the code is not obvious and probably very easy to break.
  */
-
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -68,55 +45,55 @@
 static int ax25_std_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type)
 {
 	switch (frametype) {
-		case AX25_SABM:
-			ax25->modulus = AX25_MODULUS;
-			ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
-			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
-			break;
-
-		case AX25_SABME:
-			ax25->modulus = AX25_EMODULUS;
-			ax25->window  = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
-			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
-			break;
-
-		case AX25_DISC:
-			ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE);
-			break;
-
-		case AX25_UA:
-			if (pf) {
-				ax25_calculate_rtt(ax25);
-				ax25_stop_t1timer(ax25);
-				ax25_start_t3timer(ax25);
-				ax25_start_idletimer(ax25);
-				ax25->vs      = 0;
-				ax25->va      = 0;
-				ax25->vr      = 0;
-				ax25->state   = AX25_STATE_3;
-				ax25->n2count = 0;
-				if (ax25->sk != NULL) {
-					ax25->sk->state = TCP_ESTABLISHED;
-					/* For WAIT_SABM connections we will produce an accept ready socket here */
-					if (!ax25->sk->dead)
-						ax25->sk->state_change(ax25->sk);
-				}
-			}
-			break;
-
-		case AX25_DM:
-			if (pf) {
-				if (ax25->modulus == AX25_MODULUS) {
-					ax25_disconnect(ax25, ECONNREFUSED);
-				} else {
-					ax25->modulus = AX25_MODULUS;
-					ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
-				}
+	case AX25_SABM:
+		ax25->modulus = AX25_MODULUS;
+		ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
+		ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+		break;
+
+	case AX25_SABME:
+		ax25->modulus = AX25_EMODULUS;
+		ax25->window  = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
+		ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+		break;
+
+	case AX25_DISC:
+		ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE);
+		break;
+
+	case AX25_UA:
+		if (pf) {
+			ax25_calculate_rtt(ax25);
+			ax25_stop_t1timer(ax25);
+			ax25_start_t3timer(ax25);
+			ax25_start_idletimer(ax25);
+			ax25->vs      = 0;
+			ax25->va      = 0;
+			ax25->vr      = 0;
+			ax25->state   = AX25_STATE_3;
+			ax25->n2count = 0;
+			if (ax25->sk != NULL) {
+				ax25->sk->state = TCP_ESTABLISHED;
+				/* For WAIT_SABM connections we will produce an accept ready socket here */
+				if (!ax25->sk->dead)
+					ax25->sk->state_change(ax25->sk);
+			}
+		}
+		break;
+
+	case AX25_DM:
+		if (pf) {
+			if (ax25->modulus == AX25_MODULUS) {
+				ax25_disconnect(ax25, ECONNREFUSED);
+			} else {
+				ax25->modulus = AX25_MODULUS;
+				ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
 			}
-			break;
+		}
+		break;
 
-		default:
-			break;
+	default:
+		break;
 	}
 
 	return 0;
@@ -130,30 +107,31 @@
 static int ax25_std_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int pf, int type)
 {
 	switch (frametype) {
-		case AX25_SABM:
-		case AX25_SABME:
-			ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE);
-			break;
-
-		case AX25_DISC:
-			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+	case AX25_SABM:
+	case AX25_SABME:
+		ax25_send_control(ax25, AX25_DM, pf, AX25_RESPONSE);
+		break;
+
+	case AX25_DISC:
+		ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+		ax25_disconnect(ax25, 0);
+		break;
+
+	case AX25_DM:
+	case AX25_UA:
+		if (pf)
 			ax25_disconnect(ax25, 0);
-			break;
+		break;
 
-		case AX25_DM:
-		case AX25_UA:
-			if (pf) ax25_disconnect(ax25, 0);
-			break;
-
-		case AX25_I:
-		case AX25_REJ:
-		case AX25_RNR:
-		case AX25_RR:
-			if (pf) ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
-			break;
+	case AX25_I:
+	case AX25_REJ:
+	case AX25_RNR:
+	case AX25_RR:
+		if (pf) ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
+		break;
 
-		default:
-			break;
+	default:
+		break;
 	}
 
 	return 0;
@@ -169,116 +147,116 @@
 	int queued = 0;
 
 	switch (frametype) {
-		case AX25_SABM:
-		case AX25_SABME:
-			if (frametype == AX25_SABM) {
-				ax25->modulus = AX25_MODULUS;
-				ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
-			} else {
-				ax25->modulus = AX25_EMODULUS;
-				ax25->window  = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
-			}
-			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+	case AX25_SABM:
+	case AX25_SABME:
+		if (frametype == AX25_SABM) {
+			ax25->modulus = AX25_MODULUS;
+			ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
+		} else {
+			ax25->modulus = AX25_EMODULUS;
+			ax25->window  = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
+		}
+		ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+		ax25_stop_t1timer(ax25);
+		ax25_stop_t2timer(ax25);
+		ax25_start_t3timer(ax25);
+		ax25_start_idletimer(ax25);
+		ax25->condition = 0x00;
+		ax25->vs        = 0;
+		ax25->va        = 0;
+		ax25->vr        = 0;
+		ax25_requeue_frames(ax25);
+		break;
+
+	case AX25_DISC:
+		ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+		ax25_disconnect(ax25, 0);
+		break;
+
+	case AX25_DM:
+		ax25_disconnect(ax25, ECONNRESET);
+		break;
+
+	case AX25_RR:
+	case AX25_RNR:
+		if (frametype == AX25_RR)
+			ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
+		else
+			ax25->condition |= AX25_COND_PEER_RX_BUSY;
+		if (type == AX25_COMMAND && pf)
+			ax25_std_enquiry_response(ax25);
+		if (ax25_validate_nr(ax25, nr)) {
+			ax25_check_iframes_acked(ax25, nr);
+		} else {
+			ax25_std_nr_error_recovery(ax25);
+			ax25->state = AX25_STATE_1;
+		}
+		break;
+
+	case AX25_REJ:
+		ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
+		if (type == AX25_COMMAND && pf)
+			ax25_std_enquiry_response(ax25);
+		if (ax25_validate_nr(ax25, nr)) {
+			ax25_frames_acked(ax25, nr);
+			ax25_calculate_rtt(ax25);
 			ax25_stop_t1timer(ax25);
-			ax25_stop_t2timer(ax25);
 			ax25_start_t3timer(ax25);
-			ax25_start_idletimer(ax25);
-			ax25->condition = 0x00;
-			ax25->vs        = 0;
-			ax25->va        = 0;
-			ax25->vr        = 0;
 			ax25_requeue_frames(ax25);
-			break;
-
-		case AX25_DISC:
-			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
-			ax25_disconnect(ax25, 0);
-			break;
-
-		case AX25_DM:
-			ax25_disconnect(ax25, ECONNRESET);
-			break;
+		} else {
+			ax25_std_nr_error_recovery(ax25);
+			ax25->state = AX25_STATE_1;
+		}
+		break;
 
-		case AX25_RR:
-		case AX25_RNR:
-			if (frametype == AX25_RR)
-				ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
-			else
-				ax25->condition |= AX25_COND_PEER_RX_BUSY;
-			if (type == AX25_COMMAND && pf)
-				ax25_std_enquiry_response(ax25);
-			if (ax25_validate_nr(ax25, nr)) {
-				ax25_check_iframes_acked(ax25, nr);
-			} else {
-				ax25_std_nr_error_recovery(ax25);
-				ax25->state = AX25_STATE_1;
-			}
+	case AX25_I:
+		if (!ax25_validate_nr(ax25, nr)) {
+			ax25_std_nr_error_recovery(ax25);
+			ax25->state = AX25_STATE_1;
 			break;
-
-		case AX25_REJ:
-			ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
-			if (type == AX25_COMMAND && pf)
+		}
+		if (ax25->condition & AX25_COND_PEER_RX_BUSY) {
+			ax25_frames_acked(ax25, nr);
+		} else {
+			ax25_check_iframes_acked(ax25, nr);
+		}
+		if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
+			if (pf) ax25_std_enquiry_response(ax25);
+			break;
+		}
+		if (ns == ax25->vr) {
+			ax25->vr = (ax25->vr + 1) % ax25->modulus;
+			queued = ax25_rx_iframe(ax25, skb);
+			if (ax25->condition & AX25_COND_OWN_RX_BUSY)
+				ax25->vr = ns;	/* ax25->vr - 1 */
+			ax25->condition &= ~AX25_COND_REJECT;
+			if (pf) {
 				ax25_std_enquiry_response(ax25);
-			if (ax25_validate_nr(ax25, nr)) {
-				ax25_frames_acked(ax25, nr);
-				ax25_calculate_rtt(ax25);
-				ax25_stop_t1timer(ax25);
-				ax25_start_t3timer(ax25);
-				ax25_requeue_frames(ax25);
 			} else {
-				ax25_std_nr_error_recovery(ax25);
-				ax25->state = AX25_STATE_1;
-			}
-			break;
-
-		case AX25_I:
-			if (!ax25_validate_nr(ax25, nr)) {
-				ax25_std_nr_error_recovery(ax25);
-				ax25->state = AX25_STATE_1;
-				break;
-			}
-			if (ax25->condition & AX25_COND_PEER_RX_BUSY) {
-				ax25_frames_acked(ax25, nr);
-			} else {
-				ax25_check_iframes_acked(ax25, nr);
+				if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
+					ax25->condition |= AX25_COND_ACK_PENDING;
+					ax25_start_t2timer(ax25);
+				}
 			}
-			if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
+		} else {
+			if (ax25->condition & AX25_COND_REJECT) {
 				if (pf) ax25_std_enquiry_response(ax25);
-				break;
-			}
-			if (ns == ax25->vr) {
-				ax25->vr = (ax25->vr + 1) % ax25->modulus;
-				queued = ax25_rx_iframe(ax25, skb);
-				if (ax25->condition & AX25_COND_OWN_RX_BUSY)
-					ax25->vr = ns;	/* ax25->vr - 1 */
-				ax25->condition &= ~AX25_COND_REJECT;
-				if (pf) {
-					ax25_std_enquiry_response(ax25);
-				} else {
-					if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
-						ax25->condition |= AX25_COND_ACK_PENDING;
-						ax25_start_t2timer(ax25);
-					}
-				}
 			} else {
-				if (ax25->condition & AX25_COND_REJECT) {
-					if (pf) ax25_std_enquiry_response(ax25);
-				} else {
-					ax25->condition |= AX25_COND_REJECT;
-					ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE);
-					ax25->condition &= ~AX25_COND_ACK_PENDING;
-				}
-			}
-			break;
-
-		case AX25_FRMR:
-		case AX25_ILLEGAL:
-			ax25_std_establish_data_link(ax25);
-			ax25->state = AX25_STATE_1;
-			break;
+				ax25->condition |= AX25_COND_REJECT;
+				ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE);
+				ax25->condition &= ~AX25_COND_ACK_PENDING;
+			}
+		}
+		break;
+
+	case AX25_FRMR:
+	case AX25_ILLEGAL:
+		ax25_std_establish_data_link(ax25);
+		ax25->state = AX25_STATE_1;
+		break;
 
-		default:
-			break;
+	default:
+		break;
 	}
 
 	return queued;
@@ -294,145 +272,146 @@
 	int queued = 0;
 
 	switch (frametype) {
-		case AX25_SABM:
-		case AX25_SABME:
-			if (frametype == AX25_SABM) {
-				ax25->modulus = AX25_MODULUS;
-				ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
-			} else {
-				ax25->modulus = AX25_EMODULUS;
-				ax25->window  = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
-			}
-			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+	case AX25_SABM:
+	case AX25_SABME:
+		if (frametype == AX25_SABM) {
+			ax25->modulus = AX25_MODULUS;
+			ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
+		} else {
+			ax25->modulus = AX25_EMODULUS;
+			ax25->window  = ax25->ax25_dev->values[AX25_VALUES_EWINDOW];
+		}
+		ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+		ax25_stop_t1timer(ax25);
+		ax25_stop_t2timer(ax25);
+		ax25_start_t3timer(ax25);
+		ax25_start_idletimer(ax25);
+		ax25->condition = 0x00;
+		ax25->vs        = 0;
+		ax25->va        = 0;
+		ax25->vr        = 0;
+		ax25->state     = AX25_STATE_3;
+		ax25->n2count   = 0;
+		ax25_requeue_frames(ax25);
+		break;
+
+	case AX25_DISC:
+		ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
+		ax25_disconnect(ax25, 0);
+		break;
+
+	case AX25_DM:
+		ax25_disconnect(ax25, ECONNRESET);
+		break;
+
+	case AX25_RR:
+	case AX25_RNR:
+		if (frametype == AX25_RR)
+			ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
+		else
+			ax25->condition |= AX25_COND_PEER_RX_BUSY;
+		if (type == AX25_RESPONSE && pf) {
 			ax25_stop_t1timer(ax25);
-			ax25_stop_t2timer(ax25);
-			ax25_start_t3timer(ax25);
-			ax25_start_idletimer(ax25);
-			ax25->condition = 0x00;
-			ax25->vs        = 0;
-			ax25->va        = 0;
-			ax25->vr        = 0;
-			ax25->state     = AX25_STATE_3;
-			ax25->n2count   = 0;
-			ax25_requeue_frames(ax25);
-			break;
-
-		case AX25_DISC:
-			ax25_send_control(ax25, AX25_UA, pf, AX25_RESPONSE);
-			ax25_disconnect(ax25, 0);
-			break;
-
-		case AX25_DM:
-			ax25_disconnect(ax25, ECONNRESET);
-			break;
-
-		case AX25_RR:
-		case AX25_RNR:
-			if (frametype == AX25_RR)
-				ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
-			else
-				ax25->condition |= AX25_COND_PEER_RX_BUSY;
-			if (type == AX25_RESPONSE && pf) {
-				ax25_stop_t1timer(ax25);
-				ax25->n2count = 0;
-				if (ax25_validate_nr(ax25, nr)) {
-					ax25_frames_acked(ax25, nr);
-					if (ax25->vs == ax25->va) {
-						ax25_start_t3timer(ax25);
-						ax25->state   = AX25_STATE_3;
-					} else {
-						ax25_requeue_frames(ax25);
-					}
-				} else {
-					ax25_std_nr_error_recovery(ax25);
-					ax25->state = AX25_STATE_1;
-				}
-				break;
-			}
-			if (type == AX25_COMMAND && pf)
-				ax25_std_enquiry_response(ax25);
+			ax25->n2count = 0;
 			if (ax25_validate_nr(ax25, nr)) {
 				ax25_frames_acked(ax25, nr);
+				if (ax25->vs == ax25->va) {
+					ax25_start_t3timer(ax25);
+					ax25->state   = AX25_STATE_3;
+				} else {
+					ax25_requeue_frames(ax25);
+				}
 			} else {
 				ax25_std_nr_error_recovery(ax25);
 				ax25->state = AX25_STATE_1;
 			}
 			break;
+		}
+		if (type == AX25_COMMAND && pf)
+			ax25_std_enquiry_response(ax25);
+		if (ax25_validate_nr(ax25, nr)) {
+			ax25_frames_acked(ax25, nr);
+		} else {
+			ax25_std_nr_error_recovery(ax25);
+			ax25->state = AX25_STATE_1;
+		}
+		break;
 
-		case AX25_REJ:
-			ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
-			if (pf && type == AX25_RESPONSE) {
-				ax25_stop_t1timer(ax25);
-				ax25->n2count = 0;
-				if (ax25_validate_nr(ax25, nr)) {
-					ax25_frames_acked(ax25, nr);
-					if (ax25->vs == ax25->va) {
-						ax25_start_t3timer(ax25);
-						ax25->state   = AX25_STATE_3;
-					} else {
-						ax25_requeue_frames(ax25);
-					}
-				} else {
-					ax25_std_nr_error_recovery(ax25);
-					ax25->state = AX25_STATE_1;
-				}
-				break;
-			}
-			if (type == AX25_COMMAND && pf)
-				ax25_std_enquiry_response(ax25);
+	case AX25_REJ:
+		ax25->condition &= ~AX25_COND_PEER_RX_BUSY;
+		if (pf && type == AX25_RESPONSE) {
+			ax25_stop_t1timer(ax25);
+			ax25->n2count = 0;
 			if (ax25_validate_nr(ax25, nr)) {
 				ax25_frames_acked(ax25, nr);
-				ax25_requeue_frames(ax25);
+				if (ax25->vs == ax25->va) {
+					ax25_start_t3timer(ax25);
+					ax25->state   = AX25_STATE_3;
+				} else {
+					ax25_requeue_frames(ax25);
+				}
 			} else {
 				ax25_std_nr_error_recovery(ax25);
 				ax25->state = AX25_STATE_1;
 			}
 			break;
-
-		case AX25_I:
-			if (!ax25_validate_nr(ax25, nr)) {
-				ax25_std_nr_error_recovery(ax25);
-				ax25->state = AX25_STATE_1;
-				break;
-			}
+		}
+		if (type == AX25_COMMAND && pf)
+			ax25_std_enquiry_response(ax25);
+		if (ax25_validate_nr(ax25, nr)) {
 			ax25_frames_acked(ax25, nr);
-			if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
-				if (pf) ax25_std_enquiry_response(ax25);
-				break;
-			}
-			if (ns == ax25->vr) {
-				ax25->vr = (ax25->vr + 1) % ax25->modulus;
-				queued = ax25_rx_iframe(ax25, skb);
-				if (ax25->condition & AX25_COND_OWN_RX_BUSY)
-					ax25->vr = ns;	/* ax25->vr - 1 */
-				ax25->condition &= ~AX25_COND_REJECT;
-				if (pf) {
-					ax25_std_enquiry_response(ax25);
-				} else {
-					if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
-						ax25->condition |= AX25_COND_ACK_PENDING;
-						ax25_start_t2timer(ax25);
-					}
-				}
-			} else {
-				if (ax25->condition & AX25_COND_REJECT) {
-					if (pf) ax25_std_enquiry_response(ax25);
-				} else {
-					ax25->condition |= AX25_COND_REJECT;
-					ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE);
-					ax25->condition &= ~AX25_COND_ACK_PENDING;
-				}
-			}
-			break;
+			ax25_requeue_frames(ax25);
+		} else {
+			ax25_std_nr_error_recovery(ax25);
+			ax25->state = AX25_STATE_1;
+		}
+		break;
 
-		case AX25_FRMR:
-		case AX25_ILLEGAL:
-			ax25_std_establish_data_link(ax25);
+	case AX25_I:
+		if (!ax25_validate_nr(ax25, nr)) {
+			ax25_std_nr_error_recovery(ax25);
 			ax25->state = AX25_STATE_1;
 			break;
-
-		default:
+		}
+		ax25_frames_acked(ax25, nr);
+		if (ax25->condition & AX25_COND_OWN_RX_BUSY) {
+			if (pf)
+				ax25_std_enquiry_response(ax25);
 			break;
+		}
+		if (ns == ax25->vr) {
+			ax25->vr = (ax25->vr + 1) % ax25->modulus;
+			queued = ax25_rx_iframe(ax25, skb);
+			if (ax25->condition & AX25_COND_OWN_RX_BUSY)
+				ax25->vr = ns;	/* ax25->vr - 1 */
+			ax25->condition &= ~AX25_COND_REJECT;
+			if (pf) {
+				ax25_std_enquiry_response(ax25);
+			} else {
+				if (!(ax25->condition & AX25_COND_ACK_PENDING)) {
+					ax25->condition |= AX25_COND_ACK_PENDING;
+					ax25_start_t2timer(ax25);
+				}
+			}
+		} else {
+			if (ax25->condition & AX25_COND_REJECT) {
+				if (pf) ax25_std_enquiry_response(ax25);
+			} else {
+				ax25->condition |= AX25_COND_REJECT;
+				ax25_send_control(ax25, AX25_REJ, pf, AX25_RESPONSE);
+				ax25->condition &= ~AX25_COND_ACK_PENDING;
+			}
+		}
+		break;
+
+	case AX25_FRMR:
+	case AX25_ILLEGAL:
+		ax25_std_establish_data_link(ax25);
+		ax25->state = AX25_STATE_1;
+		break;
+
+	default:
+		break;
 	}
 
 	return queued;
@@ -448,18 +427,18 @@
 	frametype = ax25_decode(ax25, skb, &ns, &nr, &pf);
 
 	switch (ax25->state) {
-		case AX25_STATE_1:
-			queued = ax25_std_state1_machine(ax25, skb, frametype, pf, type);
-			break;
-		case AX25_STATE_2:
-			queued = ax25_std_state2_machine(ax25, skb, frametype, pf, type);
-			break;
-		case AX25_STATE_3:
-			queued = ax25_std_state3_machine(ax25, skb, frametype, ns, nr, pf, type);
-			break;
-		case AX25_STATE_4:
-			queued = ax25_std_state4_machine(ax25, skb, frametype, ns, nr, pf, type);
-			break;
+	case AX25_STATE_1:
+		queued = ax25_std_state1_machine(ax25, skb, frametype, pf, type);
+		break;
+	case AX25_STATE_2:
+		queued = ax25_std_state2_machine(ax25, skb, frametype, pf, type);
+		break;
+	case AX25_STATE_3:
+		queued = ax25_std_state3_machine(ax25, skb, frametype, ns, nr, pf, type);
+		break;
+	case AX25_STATE_4:
+		queued = ax25_std_state4_machine(ax25, skb, frametype, ns, nr, pf, type);
+		break;
 	}
 
 	ax25_kick(ax25);
diff -Nru a/net/ax25/ax25_std_subr.c b/net/ax25/ax25_std_subr.c
--- a/net/ax25/ax25_std_subr.c	Fri Sep 20 08:20:41 2002
+++ b/net/ax25/ax25_std_subr.c	Fri Sep 20 08:20:41 2002
@@ -1,25 +1,11 @@
 /*
- *	AX.25 release 037
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	Most of this code is based on the SDL diagrams published in the 7th
- *	ARRL Computer Networking Conference papers. The diagrams have mistakes
- *	in them, but are mostly correct. Before you modify the code could you
- *	read the SDL diagrams as the code is not obvious and probably very
- *	easy to break;
- *
- *	History
- *	AX.25 036	Jonathan(G4KLX)	Split from ax25_out.c.
- *	AX.25 037	Jonathan(G4KLX)	New timer architecture.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
  */
-
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -80,7 +66,7 @@
 	ax25_calculate_t1(ax25);
 	ax25_start_t1timer(ax25);
 }
- 	
+
 void ax25_std_enquiry_response(ax25_cb *ax25)
 {
 	if (ax25->condition & AX25_COND_OWN_RX_BUSY)
diff -Nru a/net/ax25/ax25_std_timer.c b/net/ax25/ax25_std_timer.c
--- a/net/ax25/ax25_std_timer.c	Fri Sep 20 08:20:44 2002
+++ b/net/ax25/ax25_std_timer.c	Fri Sep 20 08:20:44 2002
@@ -1,27 +1,14 @@
 /*
- *	AX.25 release 037
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	History
- *	AX.25 028a	Jonathan(G4KLX)	New state machine based on SDL diagrams.
- *	AX.25 028b	Jonathan(G4KLX)	Extracted AX25 control block from the
- *					sock structure.
- *	AX.25 029	Alan(GW4PTS)	Switched to KA9Q constant names.
- *	AX.25 031	Joerg(DL1BKE)	Added DAMA support
- *	AX.25 032	Joerg(DL1BKE)	Fixed DAMA timeout bug
- *	AX.25 033	Jonathan(G4KLX)	Modularisation functions.
- *	AX.25 035	Frederic(F1OAT)	Support for pseudo-digipeating.
- *	AX.25 036	Jonathan(G4KLX)	Split from ax25_timer.c.
- *	AX.25 037	Jonathan(G4KLX)	New timer architecture.
+ * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
+ * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
  */
-
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -47,30 +34,29 @@
 void ax25_std_heartbeat_expiry(ax25_cb *ax25)
 {
 	switch (ax25->state) {
-
-		case AX25_STATE_0:
-			/* Magic here: If we listen() and a new link dies before it
-			   is accepted() it isn't 'dead' so doesn't get removed. */
-			if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) {
-				ax25_destroy_socket(ax25);
-				return;
-			}
-			break;
-
-		case AX25_STATE_3:
-		case AX25_STATE_4:
-			/*
-			 * Check the state of the receive buffer.
-			 */
-			if (ax25->sk != NULL) {
-				if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) &&
-				    (ax25->condition & AX25_COND_OWN_RX_BUSY)) {
-					ax25->condition &= ~AX25_COND_OWN_RX_BUSY;
-					ax25->condition &= ~AX25_COND_ACK_PENDING;
-					ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE);
-					break;
-				}
+	case AX25_STATE_0:
+		/* Magic here: If we listen() and a new link dies before it
+		   is accepted() it isn't 'dead' so doesn't get removed. */
+		if (ax25->sk == NULL || ax25->sk->destroy || (ax25->sk->state == TCP_LISTEN && ax25->sk->dead)) {
+			ax25_destroy_socket(ax25);
+			return;
+		}
+		break;
+
+	case AX25_STATE_3:
+	case AX25_STATE_4:
+		/*
+		 * Check the state of the receive buffer.
+		 */
+		if (ax25->sk != NULL) {
+			if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) &&
+			    (ax25->condition & AX25_COND_OWN_RX_BUSY)) {
+				ax25->condition &= ~AX25_COND_OWN_RX_BUSY;
+				ax25->condition &= ~AX25_COND_ACK_PENDING;
+				ax25_send_control(ax25, AX25_RR, AX25_POLLOFF, AX25_RESPONSE);
+				break;
 			}
+		}
 	}
 
 	ax25_start_heartbeat(ax25);
@@ -117,53 +103,53 @@
 void ax25_std_t1timer_expiry(ax25_cb *ax25)
 {
 	switch (ax25->state) {
-		case AX25_STATE_1: 
-			if (ax25->n2count == ax25->n2) {
-				if (ax25->modulus == AX25_MODULUS) {
-					ax25_disconnect(ax25, ETIMEDOUT);
-					return;
-				} else {
-					ax25->modulus = AX25_MODULUS;
-					ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
-					ax25->n2count = 0;
-					ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
-				}
-			} else {
-				ax25->n2count++;
-				if (ax25->modulus == AX25_MODULUS)
-					ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
-				else
-					ax25_send_control(ax25, AX25_SABME, AX25_POLLON, AX25_COMMAND);
-			}
-			break;
-
-		case AX25_STATE_2:
-			if (ax25->n2count == ax25->n2) {
-				ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+	case AX25_STATE_1:
+		if (ax25->n2count == ax25->n2) {
+			if (ax25->modulus == AX25_MODULUS) {
 				ax25_disconnect(ax25, ETIMEDOUT);
 				return;
 			} else {
-				ax25->n2count++;
-				ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+				ax25->modulus = AX25_MODULUS;
+				ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
+				ax25->n2count = 0;
+				ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
 			}
-			break;
-
-		case AX25_STATE_3: 
-			ax25->n2count = 1;
+		} else {
+			ax25->n2count++;
+			if (ax25->modulus == AX25_MODULUS)
+				ax25_send_control(ax25, AX25_SABM, AX25_POLLON, AX25_COMMAND);
+			else
+				ax25_send_control(ax25, AX25_SABME, AX25_POLLON, AX25_COMMAND);
+		}
+		break;
+
+	case AX25_STATE_2:
+		if (ax25->n2count == ax25->n2) {
+			ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+			ax25_disconnect(ax25, ETIMEDOUT);
+			return;
+		} else {
+			ax25->n2count++;
+			ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);
+		}
+		break;
+
+	case AX25_STATE_3:
+		ax25->n2count = 1;
+		ax25_std_transmit_enquiry(ax25);
+		ax25->state   = AX25_STATE_4;
+		break;
+
+	case AX25_STATE_4:
+		if (ax25->n2count == ax25->n2) {
+			ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
+			ax25_disconnect(ax25, ETIMEDOUT);
+			return;
+		} else {
+			ax25->n2count++;
 			ax25_std_transmit_enquiry(ax25);
-			ax25->state   = AX25_STATE_4;
-			break;
-
-		case AX25_STATE_4:
-			if (ax25->n2count == ax25->n2) {
-				ax25_send_control(ax25, AX25_DM, AX25_POLLON, AX25_RESPONSE);
-				ax25_disconnect(ax25, ETIMEDOUT);
-				return;
-			} else {
-				ax25->n2count++;
-				ax25_std_transmit_enquiry(ax25);
-			}
-			break;
+		}
+		break;
 	}
 
 	ax25_calculate_t1(ax25);
diff -Nru a/net/ax25/ax25_subr.c b/net/ax25/ax25_subr.c
--- a/net/ax25/ax25_subr.c	Fri Sep 20 08:20:48 2002
+++ b/net/ax25/ax25_subr.c	Fri Sep 20 08:20:48 2002
@@ -1,38 +1,14 @@
 /*
- *	AX.25 release 037
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	Most of this code is based on the SDL diagrams published in the 7th
- *	ARRL Computer Networking Conference papers. The diagrams have mistakes
- *	in them, but are mostly correct. Before you modify the code could you
- *	read the SDL diagrams as the code is not obvious and probably very
- *	easy to break;
- *
- *	History
- *	AX.25 029	Alan(GW4PTS)	Switched to KA9Q constant names. Removed
- *					old BSD code.
- *	AX.25 030	Jonathan(G4KLX)	Added support for extended AX.25.
- *					Added fragmentation support.
- *			Darryl(G7LED)	Added function ax25_requeue_frames() to split
- *					it up from ax25_frames_acked().
- *	AX.25 031	Joerg(DL1BKE)	DAMA needs KISS Fullduplex ON/OFF.
- *					Thus we have ax25_kiss_cmd() now... ;-)
- *			Dave Brown(N2RJT)
- *					Killed a silly bug in the DAMA code.
- *			Joerg(DL1BKE)	Found the real bug in ax25.h, sri.
- *	AX.25 032	Joerg(DL1BKE)	Added ax25_queue_length to count the number of
- *					enqueued buffers of a socket..
- *	AX.25 035	Frederic(F1OAT)	Support for pseudo-digipeating.
- *	AX.25 037	Jonathan(G4KLX)	New timer architecture.
+ * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
+ * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
  */
-
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -172,9 +148,9 @@
 	return frametype;
 }
 
-/* 
+/*
  *	This routine is called when the HDLC layer internally  generates a
- *	command or  response  for  the remote machine ( eg. RR, UA etc. ). 
+ *	command or  response  for  the remote machine ( eg. RR, UA etc. ).
  *	Only supervisory or unnumbered frames are processed.
  */
 void ax25_send_control(ax25_cb *ax25, int frametype, int poll_bit, int type)
@@ -231,7 +207,7 @@
 
 	skb_reserve(skb, AX25_BPQ_HEADER_LEN + ax25_addr_size(digi));
 	skb->nh.raw = skb->data;
-	
+
 	ax25_digi_invert(digi, &retdigi);
 
 	dptr = skb_put(skb, 1);
@@ -257,18 +233,18 @@
 	int n, t = 2;
 
 	switch (ax25->backoff) {
-		case 0:
-			break;
+	case 0:
+		break;
 
-		case 1:
-			t += 2 * ax25->n2count;
-			break;
-
-		case 2:
-			for (n = 0; n < ax25->n2count; n++)
-				t *= 2;
-			if (t > 8) t = 8;
-			break;
+	case 1:
+		t += 2 * ax25->n2count;
+		break;
+
+	case 2:
+		for (n = 0; n < ax25->n2count; n++)
+			t *= 2;
+		if (t > 8) t = 8;
+		break;
 	}
 
 	ax25->t1 = t * ax25->rtt;
diff -Nru a/net/ax25/ax25_timer.c b/net/ax25/ax25_timer.c
--- a/net/ax25/ax25_timer.c	Fri Sep 20 08:20:47 2002
+++ b/net/ax25/ax25_timer.c	Fri Sep 20 08:20:47 2002
@@ -1,30 +1,17 @@
 /*
- *	AX.25 release 037
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	History
- *	AX.25 028a	Jonathan(G4KLX)	New state machine based on SDL diagrams.
- *	AX.25 028b	Jonathan(G4KLX)	Extracted AX25 control block from the
- *					sock structure.
- *	AX.25 029	Alan(GW4PTS)	Switched to KA9Q constant names.
- *	AX.25 031	Joerg(DL1BKE)	Added DAMA support
- *	AX.25 032	Joerg(DL1BKE)	Fixed DAMA timeout bug
- *	AX.25 033	Jonathan(G4KLX)	Modularisation functions.
- *	AX.25 035	Frederic(F1OAT)	Support for pseudo-digipeating.
- *	AX.25 036	Jonathan(G4KLX)	Split Standard and DAMA code into separate files.
- *			Joerg(DL1BKE)	Fixed DAMA Slave. We are *required* to start with
- *					standard AX.25 mode.
- *	AX.25 037	Jonathan(G4KLX)	New timer architecture.
- *                      Tomi(OH2BNS)    Fixed heartbeat expiry (check ax25_dev).
+ * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright (C) Tomi Manninen OH2BNS (oh2bns@sral.fi)
+ * Copyright (C) Darryl Miles G7LED (dlm@g7led.demon.co.uk)
+ * Copyright (C) Joerg Reuter DL1BKE (jreuter@yaina.de)
+ * Copyright (C) Frederic Rible F1OAT (frible@teaser.fr)
+ * Copyright (C) 2002 Ralf Baechle DO1GRB (ralf@gnu.org)
  */
-
 #include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/types.h>
@@ -152,105 +139,121 @@
 
 static void ax25_heartbeat_expiry(unsigned long param)
 {
-	ax25_cb *ax25 = (ax25_cb *)param;
 	int proto = AX25_PROTO_STD_SIMPLEX;
+	ax25_cb *ax25 = (ax25_cb *)param;
+	struct sock *sk = ax25->sk;
 
 	if (ax25->ax25_dev)
 		proto = ax25->ax25_dev->values[AX25_VALUES_PROTOCOL];
 
+	bh_lock_sock(sk);
+
 	switch (proto) {
-		case AX25_PROTO_STD_SIMPLEX:
-		case AX25_PROTO_STD_DUPLEX:
-			ax25_std_heartbeat_expiry(ax25);
-			break;
+	case AX25_PROTO_STD_SIMPLEX:
+	case AX25_PROTO_STD_DUPLEX:
+		ax25_std_heartbeat_expiry(ax25);
+		break;
 
 #ifdef CONFIG_AX25_DAMA_SLAVE
-		case AX25_PROTO_DAMA_SLAVE:
-			if (ax25->ax25_dev->dama.slave)
-				ax25_ds_heartbeat_expiry(ax25);
-			else
-				ax25_std_heartbeat_expiry(ax25);
-			break;
+	case AX25_PROTO_DAMA_SLAVE:
+		if (ax25->ax25_dev->dama.slave)
+			ax25_ds_heartbeat_expiry(ax25);
+		else
+			ax25_std_heartbeat_expiry(ax25);
+		break;
 #endif
 	}
+	bh_unlock_sock(sk);
 }
 
 static void ax25_t1timer_expiry(unsigned long param)
 {
 	ax25_cb *ax25 = (ax25_cb *)param;
+	struct sock *sk = ax25->sk;
 
+	bh_lock_sock(sk);
 	switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
-		case AX25_PROTO_STD_SIMPLEX:
-		case AX25_PROTO_STD_DUPLEX:
-			ax25_std_t1timer_expiry(ax25);
-			break;
+	case AX25_PROTO_STD_SIMPLEX:
+	case AX25_PROTO_STD_DUPLEX:
+		ax25_std_t1timer_expiry(ax25);
+		break;
 
 #ifdef CONFIG_AX25_DAMA_SLAVE
-		case AX25_PROTO_DAMA_SLAVE:
-			if (!ax25->ax25_dev->dama.slave)
-				ax25_std_t1timer_expiry(ax25);
-			break;
+	case AX25_PROTO_DAMA_SLAVE:
+		if (!ax25->ax25_dev->dama.slave)
+			ax25_std_t1timer_expiry(ax25);
+		break;
 #endif
 	}
+	bh_unlock_sock(sk);
 }
 
 static void ax25_t2timer_expiry(unsigned long param)
 {
 	ax25_cb *ax25 = (ax25_cb *)param;
+	struct sock *sk = ax25->sk;
 
+	bh_lock_sock(sk);
 	switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
-		case AX25_PROTO_STD_SIMPLEX:
-		case AX25_PROTO_STD_DUPLEX:
-			ax25_std_t2timer_expiry(ax25);
-			break;
+	case AX25_PROTO_STD_SIMPLEX:
+	case AX25_PROTO_STD_DUPLEX:
+		ax25_std_t2timer_expiry(ax25);
+		break;
 
 #ifdef CONFIG_AX25_DAMA_SLAVE
-		case AX25_PROTO_DAMA_SLAVE:
-			if (!ax25->ax25_dev->dama.slave)
-				ax25_std_t2timer_expiry(ax25);
-			break;
+	case AX25_PROTO_DAMA_SLAVE:
+		if (!ax25->ax25_dev->dama.slave)
+			ax25_std_t2timer_expiry(ax25);
+		break;
 #endif
 	}
+	bh_unlock_sock(sk);
 }
 
 static void ax25_t3timer_expiry(unsigned long param)
 {
 	ax25_cb *ax25 = (ax25_cb *)param;
+	struct sock *sk = ax25->sk;
 
+	bh_lock_sock(sk);
 	switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
-		case AX25_PROTO_STD_SIMPLEX:
-		case AX25_PROTO_STD_DUPLEX:
-			ax25_std_t3timer_expiry(ax25);
-			break;
+	case AX25_PROTO_STD_SIMPLEX:
+	case AX25_PROTO_STD_DUPLEX:
+		ax25_std_t3timer_expiry(ax25);
+		break;
 
 #ifdef CONFIG_AX25_DAMA_SLAVE
-		case AX25_PROTO_DAMA_SLAVE:
-			if (ax25->ax25_dev->dama.slave)
-				ax25_ds_t3timer_expiry(ax25);
-			else
-				ax25_std_t3timer_expiry(ax25);
-			break;
+	case AX25_PROTO_DAMA_SLAVE:
+		if (ax25->ax25_dev->dama.slave)
+			ax25_ds_t3timer_expiry(ax25);
+		else
+			ax25_std_t3timer_expiry(ax25);
+		break;
 #endif
 	}
+	bh_unlock_sock(sk);
 }
 
 static void ax25_idletimer_expiry(unsigned long param)
 {
 	ax25_cb *ax25 = (ax25_cb *)param;
+	struct sock *sk = ax25->sk;
 
+	bh_lock_sock(sk);
 	switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {
-		case AX25_PROTO_STD_SIMPLEX:
-		case AX25_PROTO_STD_DUPLEX:
-			ax25_std_idletimer_expiry(ax25);
-			break;
+	case AX25_PROTO_STD_SIMPLEX:
+	case AX25_PROTO_STD_DUPLEX:
+		ax25_std_idletimer_expiry(ax25);
+		break;
 
 #ifdef CONFIG_AX25_DAMA_SLAVE
-		case AX25_PROTO_DAMA_SLAVE:
-			if (ax25->ax25_dev->dama.slave)
-				ax25_ds_idletimer_expiry(ax25);
-			else
-				ax25_std_idletimer_expiry(ax25);
-			break;
+	case AX25_PROTO_DAMA_SLAVE:
+		if (ax25->ax25_dev->dama.slave)
+			ax25_ds_idletimer_expiry(ax25);
+		else
+			ax25_std_idletimer_expiry(ax25);
+		break;
 #endif
 	}
+	bh_unlock_sock(sk);
 }
diff -Nru a/net/ax25/ax25_uid.c b/net/ax25/ax25_uid.c
--- a/net/ax25/ax25_uid.c	Fri Sep 20 08:20:43 2002
+++ b/net/ax25/ax25_uid.c	Fri Sep 20 08:20:43 2002
@@ -1,18 +1,11 @@
 /*
- *	AX.25 release 037
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	History
- *	AX.25 036	Jonathan(G4KLX)	Split from af_ax25.c.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
  */
-
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -23,6 +16,7 @@
 #include <linux/string.h>
 #include <linux/sockios.h>
 #include <linux/net.h>
+#include <linux/spinlock.h>
 #include <net/ax25.h>
 #include <linux/inet.h>
 #include <linux/netdevice.h>
@@ -47,17 +41,23 @@
  */
 
 static ax25_uid_assoc *ax25_uid_list;
+static rwlock_t ax25_uid_lock = RW_LOCK_UNLOCKED;
 
 int ax25_uid_policy = 0;
 
 ax25_address *ax25_findbyuid(uid_t uid)
 {
 	ax25_uid_assoc *ax25_uid;
+	ax25_address *res = NULL;
 
+	read_lock(&ax25_uid_lock);
 	for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) {
-		if (ax25_uid->uid == uid)
-			return &ax25_uid->call;
+		if (ax25_uid->uid == uid) {
+			res = &ax25_uid->call;
+			break;
+		}
 	}
+	read_unlock(&ax25_uid_lock);
 
 	return NULL;
 }
@@ -65,63 +65,77 @@
 int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
 {
 	ax25_uid_assoc *s, *ax25_uid;
-	unsigned long flags;
+	unsigned long res;
 
 	switch (cmd) {
-		case SIOCAX25GETUID:
-			for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) {
-				if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0)
-					return ax25_uid->uid;
+	case SIOCAX25GETUID:
+		res = -ENOENT;
+		read_lock(&ax25_uid_lock);
+		for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) {
+			if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) {
+				res = ax25_uid->uid;
+				break;
 			}
-			return -ENOENT;
+		}
+		read_unlock(&ax25_uid_lock);
 
-		case SIOCAX25ADDUID:
-			if (!capable(CAP_NET_ADMIN))
-				return -EPERM;
-			if (ax25_findbyuid(sax->sax25_uid))
-				return -EEXIST;
-			if (sax->sax25_uid == 0)
-				return -EINVAL;
-			if ((ax25_uid = kmalloc(sizeof(*ax25_uid), GFP_KERNEL)) == NULL)
-				return -ENOMEM;
-			ax25_uid->uid  = sax->sax25_uid;
-			ax25_uid->call = sax->sax25_call;
-			save_flags(flags); cli();
-			ax25_uid->next = ax25_uid_list;
-			ax25_uid_list  = ax25_uid;
-			restore_flags(flags);
-			return 0;
+		return res;
+
+	case SIOCAX25ADDUID:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (ax25_findbyuid(sax->sax25_uid))
+			return -EEXIST;
+		if (sax->sax25_uid == 0)
+			return -EINVAL;
+		if ((ax25_uid = kmalloc(sizeof(*ax25_uid), GFP_KERNEL)) == NULL)
+			return -ENOMEM;
+
+		ax25_uid->uid  = sax->sax25_uid;
+		ax25_uid->call = sax->sax25_call;
 
-		case SIOCAX25DELUID:
-			if (!capable(CAP_NET_ADMIN))
-				return -EPERM;
-			for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) {
-				if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0)
-					break;
+		write_lock(&ax25_uid_lock);
+		ax25_uid->next = ax25_uid_list;
+		ax25_uid_list  = ax25_uid;
+		write_unlock(&ax25_uid_lock);
+
+		return 0;
+
+	case SIOCAX25DELUID:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		write_lock(&ax25_uid_lock);
+		for (ax25_uid = ax25_uid_list; ax25_uid != NULL; ax25_uid = ax25_uid->next) {
+			if (ax25cmp(&sax->sax25_call, &ax25_uid->call) == 0) {
+				break;
 			}
-			if (ax25_uid == NULL)
-				return -ENOENT;
-			save_flags(flags); cli();
-			if ((s = ax25_uid_list) == ax25_uid) {
-				ax25_uid_list = s->next;
-				restore_flags(flags);
+		}
+		if (ax25_uid == NULL) {
+			write_unlock(&ax25_uid_lock);
+			return -ENOENT;
+		}
+		if ((s = ax25_uid_list) == ax25_uid) {
+			ax25_uid_list = s->next;
+			write_unlock(&ax25_uid_lock);
+			kfree(ax25_uid);
+			return 0;
+		}
+		while (s != NULL && s->next != NULL) {
+			if (s->next == ax25_uid) {
+				s->next = ax25_uid->next;
+				write_unlock(&ax25_uid_lock);
 				kfree(ax25_uid);
 				return 0;
 			}
-			while (s != NULL && s->next != NULL) {
-				if (s->next == ax25_uid) {
-					s->next = ax25_uid->next;
-					restore_flags(flags);
-					kfree(ax25_uid);
-					return 0;
-				}
-				s = s->next;
-			}
-			restore_flags(flags);
-			return -ENOENT;
+			s = s->next;
+		}
+		write_unlock(&ax25_uid_lock);
 
-		default:
-			return -EINVAL;
+		return -ENOENT;
+
+	default:
+		return -EINVAL;
 	}
 
 	return -EINVAL;	/*NOTREACHED */
@@ -134,8 +148,7 @@
 	off_t pos   = 0;
 	off_t begin = 0;
 
-	cli();
-
+	read_lock(&ax25_uid_lock);
 	len += sprintf(buffer, "Policy: %d\n", ax25_uid_policy);
 
 	for (pt = ax25_uid_list; pt != NULL; pt = pt->next) {
@@ -151,13 +164,13 @@
 		if (pos > offset + length)
 			break;
 	}
-
-	sti();
+	read_unlock(&ax25_uid_lock);
 
 	*start = buffer + (offset - begin);
 	len   -= offset - begin;
 
-	if (len > length) len = length;
+	if (len > length)
+		len = length;
 
 	return len;
 }
@@ -167,12 +180,16 @@
  */
 void __exit ax25_uid_free(void)
 {
-	ax25_uid_assoc *s, *ax25_uid = ax25_uid_list;
+	ax25_uid_assoc *s, *ax25_uid;
 
+	write_lock(&ax25_uid_lock);
+	ax25_uid = ax25_uid_list;
 	while (ax25_uid != NULL) {
 		s        = ax25_uid;
 		ax25_uid = ax25_uid->next;
 
 		kfree(s);
 	}
+	ax25_uid_list = NULL;
+	write_unlock(&ax25_uid_lock);
 }
diff -Nru a/net/ax25/sysctl_net_ax25.c b/net/ax25/sysctl_net_ax25.c
--- a/net/ax25/sysctl_net_ax25.c	Fri Sep 20 08:20:44 2002
+++ b/net/ax25/sysctl_net_ax25.c	Fri Sep 20 08:20:44 2002
@@ -1,13 +1,15 @@
-/* -*- linux-c -*-
- * sysctl_net_ax25.c: sysctl interface to net AX.25 subsystem.
+/*
+ * 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.
  *
- * Begun April 1, 1996, Mike Shaver.
- * Added /proc/sys/net/ax25 directory entry (empty =) ). [MS]
+ * Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com)
  */
-
 #include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/sysctl.h>
+#include <linux/spinlock.h>
 #include <net/ax25.h>
 
 static int min_ipdefmode[] = {0},	max_ipdefmode[] = {1};
@@ -105,6 +107,7 @@
 	ax25_dev *ax25_dev;
 	int n, k;
 
+	spin_lock_bh(&ax25_dev_lock);
 	for (ax25_table_size = sizeof(ctl_table), ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next)
 		ax25_table_size += sizeof(ctl_table);
 
@@ -119,6 +122,7 @@
 			while (n--)
 				kfree(ax25_table[n].child);
 			kfree(ax25_table);
+			spin_unlock_bh(&ax25_dev_lock);
 			return;
 		}
 		memcpy(child, ax25_param_table, sizeof(ax25_param_table));
@@ -128,7 +132,7 @@
 		ax25_table[n].mode         = 0555;
 
 #ifndef CONFIG_AX25_DAMA_SLAVE
-		/* 
+		/*
 		 * We do not wish to have a representation of this parameter
 		 * in /proc/sys/ when configured *not* to include the
 		 * AX.25 DAMA slave code, do we?
@@ -144,6 +148,7 @@
 
 		n++;
 	}
+	spin_unlock_bh(&ax25_dev_lock);
 
 	ax25_dir_table[0].child = ax25_table;
 
diff -Nru a/net/bridge/Makefile b/net/bridge/Makefile
--- a/net/bridge/Makefile	Fri Sep 20 08:20:48 2002
+++ b/net/bridge/Makefile	Fri Sep 20 08:20:48 2002
@@ -2,10 +2,13 @@
 # Makefile for the IEEE 802.1d ethernet bridging layer.
 #
 
+export-objs := br.o
+
 obj-$(CONFIG_BRIDGE) += bridge.o
 
 bridge-objs	:= br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \
 			br_ioctl.o br_notify.o br_stp.o br_stp_bpdu.o \
 			br_stp_if.o br_stp_timer.o
+obj-$(CONFIG_BRIDGE_NF_EBTABLES) += netfilter/
 
 include $(TOPDIR)/Rules.make
diff -Nru a/net/bridge/br.c b/net/bridge/br.c
--- a/net/bridge/br.c	Fri Sep 20 08:20:43 2002
+++ b/net/bridge/br.c	Fri Sep 20 08:20:43 2002
@@ -28,6 +28,8 @@
 #include "../atm/lec.h"
 #endif
 
+int (*br_should_route_hook) (struct sk_buff **pskb) = NULL;
+
 void br_dec_use_count()
 {
 	MOD_DEC_USE_COUNT;
@@ -73,6 +75,8 @@
 	br_fdb_put_hook = NULL;
 #endif
 }
+
+EXPORT_SYMBOL(br_should_route_hook);
 
 module_init(br_init)
 module_exit(br_deinit)
diff -Nru a/net/bridge/br_forward.c b/net/bridge/br_forward.c
--- a/net/bridge/br_forward.c	Fri Sep 20 08:20:44 2002
+++ b/net/bridge/br_forward.c	Fri Sep 20 08:20:44 2002
@@ -49,6 +49,9 @@
 static void __br_deliver(struct net_bridge_port *to, struct sk_buff *skb)
 {
 	skb->dev = to->dev;
+#ifdef CONFIG_NETFILTER_DEBUG
+	skb->nf_debug = 0;
+#endif
 	NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
 			__br_forward_finish);
 }
diff -Nru a/net/bridge/br_input.c b/net/bridge/br_input.c
--- a/net/bridge/br_input.c	Fri Sep 20 08:20:43 2002
+++ b/net/bridge/br_input.c	Fri Sep 20 08:20:43 2002
@@ -24,6 +24,9 @@
 
 static int br_pass_frame_up_finish(struct sk_buff *skb)
 {
+#ifdef CONFIG_NETFILTER_DEBUG
+	skb->nf_debug = 0;
+#endif
 	netif_rx(skb);
 
 	return 0;
@@ -112,7 +115,7 @@
 	return 0;
 }
 
-void br_handle_frame(struct sk_buff *skb)
+int br_handle_frame(struct sk_buff *skb)
 {
 	struct net_bridge *br;
 	unsigned char *dest;
@@ -146,25 +149,29 @@
 		goto handle_special_frame;
 
 	if (p->state == BR_STATE_FORWARDING) {
+		if (br_should_route_hook && br_should_route_hook(&skb))
+			return -1;
+
 		NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
 			br_handle_frame_finish);
 		read_unlock(&br->lock);
-		return;
+		return 0;
 	}
 
 err:
 	read_unlock(&br->lock);
 err_nolock:
 	kfree_skb(skb);
-	return;
+	return 0;
 
 handle_special_frame:
 	if (!dest[5]) {
 		br_stp_handle_bpdu(skb);
 		read_unlock(&br->lock);
-		return;
+		return 0;
 	}
 
 	kfree_skb(skb);
 	read_unlock(&br->lock);
+	return 0;
 }
diff -Nru a/net/bridge/br_private.h b/net/bridge/br_private.h
--- a/net/bridge/br_private.h	Fri Sep 20 08:20:43 2002
+++ b/net/bridge/br_private.h	Fri Sep 20 08:20:43 2002
@@ -166,7 +166,7 @@
 			   int *ifindices);
 
 /* br_input.c */
-extern void br_handle_frame(struct sk_buff *skb);
+extern int br_handle_frame(struct sk_buff *skb);
 
 /* br_ioctl.c */
 extern void br_call_ioctl_atomic(void (*fn)(void));
diff -Nru a/net/bridge/netfilter/Config.help b/net/bridge/netfilter/Config.help
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/bridge/netfilter/Config.help	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,105 @@
+CONFIG_BRIDGE_EBT
+  ebtables is an extendable frame filtering system for the Linux
+  Ethernet bridge. Its usage and implementation is very similar to that
+  of iptables.
+  The difference is that ebtables works on the Link Layer, while iptables
+  works on the Network Layer. ebtables can filter all frames that come
+  into contact with a logical bridge device.
+  Apart from filtering, ebtables also allows MAC source and destination
+  alterations (we call it MAC SNAT and MAC DNAT) and also provides
+  functionality for making Linux a brouter.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_BRIDGE_EBT_T_FILTER
+  The ebtables filter table is used to define frame filtering rules at
+  local input, forwarding and local output. See the man page for
+  ebtables(8).
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_BRIDGE_EBT_T_NAT
+  The ebtables nat table is used to define rules that alter the MAC
+  source address (MAC SNAT) or the MAC destination address (MAC DNAT).
+  See the man page for ebtables(8).
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_BRIDGE_EBT_BROUTE
+  The ebtables broute table is used to define rules that decide between
+  bridging and routing frames, giving Linux the functionality of a
+  brouter. See the man page for ebtables(8) and examples on the ebtables
+  website.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_BRIDGE_EBT_LOG
+  This option adds the log target, that you can use in any rule in
+  any ebtables table. It records the frame header to the syslog.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_BRIDGE_EBT_IPF
+  This option adds the IP match, which allows basic IP header field
+  filtering.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_BRIDGE_EBT_ARPF
+  This option adds the ARP match, which allows ARP and RARP header field
+  filtering.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_BRIDGE_EBT_VLANF
+  This option adds the 802.1Q vlan match, which allows the filtering of
+  802.1Q vlan fields.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_BRIDGE_EBT_MARKF
+  This option adds the mark match, which allows matching frames based on
+  the 'nfmark' value in the frame. This can be set by the mark target.
+  This value is the same as the one used in the iptables mark match and
+  target.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_BRIDGE_EBT_SNAT
+  This option adds the MAC SNAT target, which allows altering the MAC
+  source address of frames.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_BRIDGE_EBT_DNAT
+  This option adds the MAC DNAT target, which allows altering the MAC
+  destination address of frames.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_BRIDGE_EBT_REDIRECT
+  This option adds the MAC redirect target, which allows altering the MAC
+  destination address of a frame to that of the device it arrived on.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
+
+CONFIG_BRIDGE_EBT_MARK_T
+  This option adds the mark target, which allows marking frames by
+  setting the 'nfmark' value in the frame.
+  This value is the same as the one used in the iptables mark match and
+  target.
+
+  If you want to compile it as a module, say M here and read
+  <file:Documentation/modules.txt>.  If unsure, say `N'.
diff -Nru a/net/bridge/netfilter/Config.in b/net/bridge/netfilter/Config.in
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/bridge/netfilter/Config.in	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,17 @@
+#
+# Bridge netfilter configuration
+#
+dep_tristate '  Bridge: ebtables' CONFIG_BRIDGE_NF_EBTABLES $CONFIG_BRIDGE
+dep_tristate '    ebt: filter table support' CONFIG_BRIDGE_EBT_T_FILTER $CONFIG_BRIDGE_NF_EBTABLES
+dep_tristate '    ebt: nat table support' CONFIG_BRIDGE_EBT_T_NAT $CONFIG_BRIDGE_NF_EBTABLES
+dep_tristate '    ebt: broute table support' CONFIG_BRIDGE_EBT_BROUTE $CONFIG_BRIDGE_NF_EBTABLES
+dep_tristate '    ebt: log support' CONFIG_BRIDGE_EBT_LOG $CONFIG_BRIDGE_NF_EBTABLES
+dep_tristate '    ebt: IP filter support' CONFIG_BRIDGE_EBT_IPF $CONFIG_BRIDGE_NF_EBTABLES
+dep_tristate '    ebt: ARP filter support' CONFIG_BRIDGE_EBT_ARPF $CONFIG_BRIDGE_NF_EBTABLES
+dep_tristate '    ebt: 802.1Q VLAN filter support (EXPERIMENTAL)' CONFIG_BRIDGE_EBT_VLANF $CONFIG_BRIDGE_NF_EBTABLES
+dep_tristate '    ebt: mark filter support' CONFIG_BRIDGE_EBT_MARKF $CONFIG_BRIDGE_NF_EBTABLES
+dep_tristate '    ebt: snat target support' CONFIG_BRIDGE_EBT_SNAT $CONFIG_BRIDGE_NF_EBTABLES
+dep_tristate '    ebt: dnat target support' CONFIG_BRIDGE_EBT_DNAT $CONFIG_BRIDGE_NF_EBTABLES
+dep_tristate '    ebt: redirect target support' CONFIG_BRIDGE_EBT_REDIRECT $CONFIG_BRIDGE_NF_EBTABLES
+dep_tristate '    ebt: mark target support' CONFIG_BRIDGE_EBT_MARK_T $CONFIG_BRIDGE_NF_EBTABLES
+
diff -Nru a/net/bridge/netfilter/Makefile b/net/bridge/netfilter/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/bridge/netfilter/Makefile	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,20 @@
+#
+# Makefile for the netfilter modules for Link Layer filtering on a bridge.
+#
+
+export-objs := ebtables.o
+
+obj-$(CONFIG_BRIDGE_NF_EBTABLES) += ebtables.o
+obj-$(CONFIG_BRIDGE_EBT_T_FILTER) += ebtable_filter.o
+obj-$(CONFIG_BRIDGE_EBT_T_NAT) += ebtable_nat.o
+obj-$(CONFIG_BRIDGE_EBT_BROUTE) += ebtable_broute.o
+obj-$(CONFIG_BRIDGE_EBT_IPF) += ebt_ip.o
+obj-$(CONFIG_BRIDGE_EBT_ARPF) += ebt_arp.o
+obj-$(CONFIG_BRIDGE_EBT_VLANF) += ebt_vlan.o
+obj-$(CONFIG_BRIDGE_EBT_MARKF) += ebt_mark_m.o
+obj-$(CONFIG_BRIDGE_EBT_LOG) += ebt_log.o
+obj-$(CONFIG_BRIDGE_EBT_SNAT) += ebt_snat.o
+obj-$(CONFIG_BRIDGE_EBT_DNAT) += ebt_dnat.o
+obj-$(CONFIG_BRIDGE_EBT_REDIRECT) += ebt_redirect.o
+obj-$(CONFIG_BRIDGE_EBT_MARK_T) += ebt_mark.o
+include $(TOPDIR)/Rules.make
diff -Nru a/net/bridge/netfilter/ebt_arp.c b/net/bridge/netfilter/ebt_arp.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/bridge/netfilter/ebt_arp.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,101 @@
+/*
+ *  ebt_arp
+ *
+ *	Authors:
+ *	Bart De Schuymer <bart.de.schuymer@pandora.be>
+ *	Tim Gardner <timg@tpi.com>
+ *
+ *  April, 2002
+ *
+ */
+
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_arp.h>
+#include <linux/if_arp.h>
+#include <linux/module.h>
+
+static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in,
+   const struct net_device *out, const void *data, unsigned int datalen)
+{
+	struct ebt_arp_info *info = (struct ebt_arp_info *)data;
+
+	if (info->bitmask & EBT_ARP_OPCODE && FWINV(info->opcode !=
+	   ((*skb).nh.arph)->ar_op, EBT_ARP_OPCODE))
+		return EBT_NOMATCH;
+	if (info->bitmask & EBT_ARP_HTYPE && FWINV(info->htype !=
+	   ((*skb).nh.arph)->ar_hrd, EBT_ARP_HTYPE))
+		return EBT_NOMATCH;
+	if (info->bitmask & EBT_ARP_PTYPE && FWINV(info->ptype !=
+	   ((*skb).nh.arph)->ar_pro, EBT_ARP_PTYPE))
+		return EBT_NOMATCH;
+
+	if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP))
+	{
+		uint32_t arp_len = sizeof(struct arphdr) +
+		   (2 * (((*skb).nh.arph)->ar_hln)) +
+		   (2 * (((*skb).nh.arph)->ar_pln));
+		uint32_t dst;
+		uint32_t src;
+
+		// Make sure the packet is long enough.
+		if ((((*skb).nh.raw) + arp_len) > (*skb).tail)
+			return EBT_NOMATCH;
+		// IPv4 addresses are always 4 bytes.
+		if (((*skb).nh.arph)->ar_pln != sizeof(uint32_t))
+			return EBT_NOMATCH;
+
+		if (info->bitmask & EBT_ARP_SRC_IP) {
+			memcpy(&src, ((*skb).nh.raw) + sizeof(struct arphdr) +
+			   ((*skb).nh.arph)->ar_hln, sizeof(uint32_t));
+			if (FWINV(info->saddr != (src & info->smsk),
+			   EBT_ARP_SRC_IP))
+				return EBT_NOMATCH;
+		}
+
+		if (info->bitmask & EBT_ARP_DST_IP) {
+			memcpy(&dst, ((*skb).nh.raw)+sizeof(struct arphdr) +
+			   (2*(((*skb).nh.arph)->ar_hln)) +
+			   (((*skb).nh.arph)->ar_pln), sizeof(uint32_t));
+			if (FWINV(info->daddr != (dst & info->dmsk),
+			   EBT_ARP_DST_IP))
+				return EBT_NOMATCH;
+		}
+	}
+	return EBT_MATCH;
+}
+
+static int ebt_arp_check(const char *tablename, unsigned int hookmask,
+   const struct ebt_entry *e, void *data, unsigned int datalen)
+{
+	struct ebt_arp_info *info = (struct ebt_arp_info *)data;
+
+	if (datalen != sizeof(struct ebt_arp_info))
+		return -EINVAL;
+	if ((e->ethproto != __constant_htons(ETH_P_ARP) &&
+	   e->ethproto != __constant_htons(ETH_P_RARP)) ||
+	   e->invflags & EBT_IPROTO)
+		return -EINVAL;
+	if (info->bitmask & ~EBT_ARP_MASK || info->invflags & ~EBT_ARP_MASK)
+		return -EINVAL;
+	return 0;
+}
+
+static struct ebt_match filter_arp =
+{
+	{NULL, NULL}, EBT_ARP_MATCH, ebt_filter_arp, ebt_arp_check, NULL,
+	THIS_MODULE
+};
+
+static int __init init(void)
+{
+	return ebt_register_match(&filter_arp);
+}
+
+static void __exit fini(void)
+{
+	ebt_unregister_match(&filter_arp);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
diff -Nru a/net/bridge/netfilter/ebt_dnat.c b/net/bridge/netfilter/ebt_dnat.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/bridge/netfilter/ebt_dnat.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,64 @@
+/*
+ *  ebt_dnat
+ *
+ *	Authors:
+ *	Bart De Schuymer <bart.de.schuymer@pandora.be>
+ *
+ *  June, 2002
+ *
+ */
+
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_nat.h>
+#include <linux/module.h>
+#include <net/sock.h>
+
+static int ebt_target_dnat(struct sk_buff **pskb, unsigned int hooknr,
+   const struct net_device *in, const struct net_device *out,
+   const void *data, unsigned int datalen)
+{
+	struct ebt_nat_info *info = (struct ebt_nat_info *)data;
+
+	memcpy(((**pskb).mac.ethernet)->h_dest, info->mac,
+	   ETH_ALEN * sizeof(unsigned char));
+	return info->target;
+}
+
+static int ebt_target_dnat_check(const char *tablename, unsigned int hookmask,
+   const struct ebt_entry *e, void *data, unsigned int datalen)
+{
+	struct ebt_nat_info *info = (struct ebt_nat_info *)data;
+
+	if (BASE_CHAIN && info->target == EBT_RETURN)
+		return -EINVAL;
+	CLEAR_BASE_CHAIN_BIT;
+	if ( (strcmp(tablename, "nat") ||
+	   (hookmask & ~((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT)))) &&
+	   (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) )
+		return -EINVAL;
+	if (datalen != sizeof(struct ebt_nat_info))
+		return -EINVAL;
+	if (INVALID_TARGET)
+		return -EINVAL;
+	return 0;
+}
+
+static struct ebt_target dnat =
+{
+	{NULL, NULL}, EBT_DNAT_TARGET, ebt_target_dnat, ebt_target_dnat_check,
+	NULL, THIS_MODULE
+};
+
+static int __init init(void)
+{
+	return ebt_register_target(&dnat);
+}
+
+static void __exit fini(void)
+{
+	ebt_unregister_target(&dnat);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
diff -Nru a/net/bridge/netfilter/ebt_ip.c b/net/bridge/netfilter/ebt_ip.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/bridge/netfilter/ebt_ip.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,72 @@
+/*
+ *  ebt_ip
+ *
+ *	Authors:
+ *	Bart De Schuymer <bart.de.schuymer@pandora.be>
+ *
+ *  April, 2002
+ *
+ */
+
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_ip.h>
+#include <linux/ip.h>
+#include <linux/module.h>
+
+static int ebt_filter_ip(const struct sk_buff *skb, const struct net_device *in,
+   const struct net_device *out, const void *data,
+   unsigned int datalen)
+{
+	struct ebt_ip_info *info = (struct ebt_ip_info *)data;
+
+	if (info->bitmask & EBT_IP_TOS &&
+	   FWINV(info->tos != ((*skb).nh.iph)->tos, EBT_IP_TOS))
+		return EBT_NOMATCH;
+	if (info->bitmask & EBT_IP_PROTO && FWINV(info->protocol !=
+	   ((*skb).nh.iph)->protocol, EBT_IP_PROTO))
+		return EBT_NOMATCH;
+	if (info->bitmask & EBT_IP_SOURCE &&
+	   FWINV((((*skb).nh.iph)->saddr & info->smsk) !=
+	   info->saddr, EBT_IP_SOURCE))
+		return EBT_NOMATCH;
+	if ((info->bitmask & EBT_IP_DEST) &&
+	   FWINV((((*skb).nh.iph)->daddr & info->dmsk) !=
+	   info->daddr, EBT_IP_DEST))
+		return EBT_NOMATCH;
+	return EBT_MATCH;
+}
+
+static int ebt_ip_check(const char *tablename, unsigned int hookmask,
+   const struct ebt_entry *e, void *data, unsigned int datalen)
+{
+	struct ebt_ip_info *info = (struct ebt_ip_info *)data;
+
+	if (datalen != sizeof(struct ebt_ip_info))
+		return -EINVAL;
+	if (e->ethproto != __constant_htons(ETH_P_IP) ||
+	   e->invflags & EBT_IPROTO)
+		return -EINVAL;
+	if (info->bitmask & ~EBT_IP_MASK || info->invflags & ~EBT_IP_MASK)
+		return -EINVAL;
+	return 0;
+}
+
+static struct ebt_match filter_ip =
+{
+	{NULL, NULL}, EBT_IP_MATCH, ebt_filter_ip, ebt_ip_check, NULL,
+	THIS_MODULE
+};
+
+static int __init init(void)
+{
+	return ebt_register_match(&filter_ip);
+}
+
+static void __exit fini(void)
+{
+	ebt_unregister_match(&filter_ip);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
diff -Nru a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/bridge/netfilter/ebt_log.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,99 @@
+/*
+ *  ebt_log
+ *
+ *	Authors:
+ *	Bart De Schuymer <bart.de.schuymer@pandora.be>
+ *
+ *  April, 2002
+ *
+ */
+
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_log.h>
+#include <linux/module.h>
+#include <linux/ip.h>
+#include <linux/if_arp.h>
+#include <linux/spinlock.h>
+
+static spinlock_t ebt_log_lock = SPIN_LOCK_UNLOCKED;
+
+static int ebt_log_check(const char *tablename, unsigned int hookmask,
+   const struct ebt_entry *e, void *data, unsigned int datalen)
+{
+	struct ebt_log_info *info = (struct ebt_log_info *)data;
+
+	if (datalen != sizeof(struct ebt_log_info))
+		return -EINVAL;
+	if (info->bitmask & ~EBT_LOG_MASK)
+		return -EINVAL;
+	if (info->loglevel >= 8)
+		return -EINVAL;
+	info->prefix[EBT_LOG_PREFIX_SIZE - 1] = '\0';
+	return 0;
+}
+
+static void ebt_log(const struct sk_buff *skb, const struct net_device *in,
+   const struct net_device *out, const void *data, unsigned int datalen)
+{
+	struct ebt_log_info *info = (struct ebt_log_info *)data;
+	char level_string[4] = "< >";
+	level_string[1] = '0' + info->loglevel;
+
+	spin_lock_bh(&ebt_log_lock);
+	printk(level_string);
+	printk("%s IN=%s OUT=%s ", info->prefix, in ? in->name : "",
+	   out ? out->name : "");
+
+	if (skb->dev->hard_header_len) {
+		int i;
+		unsigned char *p = (skb->mac.ethernet)->h_source;
+
+		printk("MAC source = ");
+		for (i = 0; i < ETH_ALEN; i++,p++)
+			printk("%02x%c", *p, i == ETH_ALEN - 1 ? ' ':':');
+		printk("MAC dest = ");
+		p = (skb->mac.ethernet)->h_dest;
+		for (i = 0; i < ETH_ALEN; i++,p++)
+			printk("%02x%c", *p, i == ETH_ALEN - 1 ? ' ':':');
+	}
+	printk("proto = 0x%04x", ntohs(((*skb).mac.ethernet)->h_proto));
+
+	if ((info->bitmask & EBT_LOG_IP) && skb->mac.ethernet->h_proto ==
+	   htons(ETH_P_IP)){
+		struct iphdr *iph = skb->nh.iph;
+		printk(" IP SRC=%u.%u.%u.%u IP DST=%u.%u.%u.%u,",
+		   NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
+		printk(" IP tos=0x%02X, IP proto=%d", iph->tos, iph->protocol);
+	}
+
+	if ((info->bitmask & EBT_LOG_ARP) &&
+	    ((skb->mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) ||
+	    (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_RARP)))) {
+		struct arphdr * arph = skb->nh.arph;
+		printk(" ARP HTYPE=%d, PTYPE=0x%04x, OPCODE=%d",
+		   ntohs(arph->ar_hrd), ntohs(arph->ar_pro),
+		   ntohs(arph->ar_op));
+	}
+	printk("\n");
+	spin_unlock_bh(&ebt_log_lock);
+}
+
+struct ebt_watcher log =
+{
+	{NULL, NULL}, EBT_LOG_WATCHER, ebt_log, ebt_log_check, NULL,
+	THIS_MODULE
+};
+
+static int __init init(void)
+{
+	return ebt_register_watcher(&log);
+}
+
+static void __exit fini(void)
+{
+	ebt_unregister_watcher(&log);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
diff -Nru a/net/bridge/netfilter/ebt_mark.c b/net/bridge/netfilter/ebt_mark.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/bridge/netfilter/ebt_mark.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,65 @@
+/*
+ *  ebt_mark
+ *
+ *	Authors:
+ *	Bart De Schuymer <bart.de.schuymer@pandora.be>
+ *
+ *  July, 2002
+ *
+ */
+
+// The mark target can be used in any chain
+// I believe adding a mangle table just for marking is total overkill
+// Marking a frame doesn't really change anything in the frame anyway
+
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_mark_t.h>
+#include <linux/module.h>
+
+static int ebt_target_mark(struct sk_buff **pskb, unsigned int hooknr,
+   const struct net_device *in, const struct net_device *out,
+   const void *data, unsigned int datalen)
+{
+	struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data;
+
+	if ((*pskb)->nfmark != info->mark) {
+		(*pskb)->nfmark = info->mark;
+		(*pskb)->nfcache |= NFC_ALTERED;
+	}
+	return info->target;
+}
+
+static int ebt_target_mark_check(const char *tablename, unsigned int hookmask,
+   const struct ebt_entry *e, void *data, unsigned int datalen)
+{
+	struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data;
+
+	if (datalen != sizeof(struct ebt_mark_t_info))
+		return -EINVAL;
+	if (BASE_CHAIN && info->target == EBT_RETURN)
+		return -EINVAL;
+	CLEAR_BASE_CHAIN_BIT;
+	if (INVALID_TARGET)
+		return -EINVAL;
+	return 0;
+}
+
+static struct ebt_target mark_target =
+{
+	{NULL, NULL}, EBT_MARK_TARGET, ebt_target_mark,
+	ebt_target_mark_check, NULL, THIS_MODULE
+};
+
+static int __init init(void)
+{
+	return ebt_register_target(&mark_target);
+}
+
+static void __exit fini(void)
+{
+	ebt_unregister_target(&mark_target);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
diff -Nru a/net/bridge/netfilter/ebt_mark_m.c b/net/bridge/netfilter/ebt_mark_m.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/bridge/netfilter/ebt_mark_m.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,60 @@
+/*
+ *  ebt_mark_m
+ *
+ *	Authors:
+ *	Bart De Schuymer <bart.de.schuymer@pandora.be>
+ *
+ *  July, 2002
+ *
+ */
+
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_mark_m.h>
+#include <linux/module.h>
+
+static int ebt_filter_mark(const struct sk_buff *skb,
+   const struct net_device *in, const struct net_device *out, const void *data,
+   unsigned int datalen)
+{
+	struct ebt_mark_m_info *info = (struct ebt_mark_m_info *) data;
+
+	if (info->bitmask & EBT_MARK_OR)
+		return !(!!(skb->nfmark & info->mask) ^ info->invert);
+	return !(((skb->nfmark & info->mask) == info->mark) ^ info->invert);
+}
+
+static int ebt_mark_check(const char *tablename, unsigned int hookmask,
+   const struct ebt_entry *e, void *data, unsigned int datalen)
+{
+        struct ebt_mark_m_info *info = (struct ebt_mark_m_info *) data;
+
+	if (datalen != sizeof(struct ebt_mark_m_info))
+		return -EINVAL;
+	if (info->bitmask & ~EBT_MARK_MASK)
+		return -EINVAL;
+	if ((info->bitmask & EBT_MARK_OR) && (info->bitmask & EBT_MARK_AND))
+		return -EINVAL;
+	if (!info->bitmask)
+		return -EINVAL;
+	return 0;
+}
+
+static struct ebt_match filter_mark =
+{
+	{NULL, NULL}, EBT_MARK_MATCH, ebt_filter_mark, ebt_mark_check, NULL,
+	THIS_MODULE
+};
+
+static int __init init(void)
+{
+	return ebt_register_match(&filter_mark);
+}
+
+static void __exit fini(void)
+{
+	ebt_unregister_match(&filter_mark);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
diff -Nru a/net/bridge/netfilter/ebt_redirect.c b/net/bridge/netfilter/ebt_redirect.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/bridge/netfilter/ebt_redirect.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,70 @@
+/*
+ *  ebt_redirect
+ *
+ *	Authors:
+ *	Bart De Schuymer <bart.de.schuymer@pandora.be>
+ *
+ *  April, 2002
+ *
+ */
+
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_redirect.h>
+#include <linux/module.h>
+#include <net/sock.h>
+#include "../br_private.h"
+
+static int ebt_target_redirect(struct sk_buff **pskb, unsigned int hooknr,
+   const struct net_device *in, const struct net_device *out,
+   const void *data, unsigned int datalen)
+{
+	struct ebt_redirect_info *info = (struct ebt_redirect_info *)data;
+
+	if (hooknr != NF_BR_BROUTING)
+		memcpy((**pskb).mac.ethernet->h_dest,
+		   in->br_port->br->dev.dev_addr, ETH_ALEN);
+	else {
+		memcpy((**pskb).mac.ethernet->h_dest,
+		   in->dev_addr, ETH_ALEN);
+		(*pskb)->pkt_type = PACKET_HOST;
+	}
+	return info->target;
+}
+
+static int ebt_target_redirect_check(const char *tablename, unsigned int hookmask,
+   const struct ebt_entry *e, void *data, unsigned int datalen)
+{
+	struct ebt_redirect_info *info = (struct ebt_redirect_info *)data;
+
+	if (datalen != sizeof(struct ebt_redirect_info))
+		return -EINVAL;
+	if (BASE_CHAIN && info->target == EBT_RETURN)
+		return -EINVAL;
+	CLEAR_BASE_CHAIN_BIT;
+	if ( (strcmp(tablename, "nat") || hookmask & ~(1 << NF_BR_PRE_ROUTING)) &&
+	     (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) )
+		return -EINVAL;
+	if (INVALID_TARGET)
+		return -EINVAL;
+	return 0;
+}
+
+static struct ebt_target redirect_target =
+{
+	{NULL, NULL}, EBT_REDIRECT_TARGET, ebt_target_redirect,
+	ebt_target_redirect_check, NULL, THIS_MODULE
+};
+
+static int __init init(void)
+{
+	return ebt_register_target(&redirect_target);
+}
+
+static void __exit fini(void)
+{
+	ebt_unregister_target(&redirect_target);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
diff -Nru a/net/bridge/netfilter/ebt_snat.c b/net/bridge/netfilter/ebt_snat.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/bridge/netfilter/ebt_snat.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,63 @@
+/*
+ *  ebt_snat
+ *
+ *	Authors:
+ *	Bart De Schuymer <bart.de.schuymer@pandora.be>
+ *
+ *  June, 2002
+ *
+ */
+
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_nat.h>
+#include <linux/module.h>
+
+static int ebt_target_snat(struct sk_buff **pskb, unsigned int hooknr,
+   const struct net_device *in, const struct net_device *out,
+   const void *data, unsigned int datalen)
+{
+	struct ebt_nat_info *info = (struct ebt_nat_info *) data;
+
+	memcpy(((**pskb).mac.ethernet)->h_source, info->mac,
+	   ETH_ALEN * sizeof(unsigned char));
+	return info->target;
+}
+
+static int ebt_target_snat_check(const char *tablename, unsigned int hookmask,
+   const struct ebt_entry *e, void *data, unsigned int datalen)
+{
+	struct ebt_nat_info *info = (struct ebt_nat_info *) data;
+
+	if (datalen != sizeof(struct ebt_nat_info))
+		return -EINVAL;
+	if (BASE_CHAIN && info->target == EBT_RETURN)
+		return -EINVAL;
+	CLEAR_BASE_CHAIN_BIT;
+	if (strcmp(tablename, "nat"))
+		return -EINVAL;
+	if (hookmask & ~(1 << NF_BR_POST_ROUTING))
+		return -EINVAL;
+	if (INVALID_TARGET)
+		return -EINVAL;
+	return 0;
+}
+
+static struct ebt_target snat =
+{
+	{NULL, NULL}, EBT_SNAT_TARGET, ebt_target_snat, ebt_target_snat_check,
+	NULL, THIS_MODULE
+};
+
+static int __init init(void)
+{
+	return ebt_register_target(&snat);
+}
+
+static void __exit fini(void)
+{
+	ebt_unregister_target(&snat);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
diff -Nru a/net/bridge/netfilter/ebt_vlan.c b/net/bridge/netfilter/ebt_vlan.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/bridge/netfilter/ebt_vlan.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,316 @@
+/*
+ * Description: EBTables 802.1Q match extension kernelspace module.
+ * Authors: Nick Fedchik <nick@fedchik.org.ua>
+ *          Bart De Schuymer <bart.de.schuymer@pandora.be>
+ *    
+ * 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
+ */
+
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/module.h>
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/netfilter_bridge/ebt_vlan.h>
+
+static unsigned char debug;
+#define MODULE_VERSION "0.4 (" __DATE__ " " __TIME__ ")"
+
+MODULE_PARM (debug, "0-1b");
+MODULE_PARM_DESC (debug, "debug=1 is turn on debug messages");
+MODULE_AUTHOR ("Nick Fedchik <nick@fedchik.org.ua>");
+MODULE_DESCRIPTION ("802.1Q match module (ebtables extension), v"
+		    MODULE_VERSION);
+MODULE_LICENSE ("GPL");
+
+
+#define DEBUG_MSG(...) if (debug) printk (KERN_DEBUG __FILE__ ":" __VA_ARGS__)
+#define INV_FLAG(_inv_flag_) (info->invflags & _inv_flag_) ? "!" : ""
+#define GET_BITMASK(_BIT_MASK_) info->bitmask & _BIT_MASK_
+#define SET_BITMASK(_BIT_MASK_) info->bitmask |= _BIT_MASK_
+#define EXIT_ON_MISMATCH(_MATCH_,_MASK_) if (!((info->_MATCH_ == _MATCH_)^!!(info->invflags & _MASK_))) return 1;
+
+/*
+ * Function description: ebt_filter_vlan() is main engine for 
+ * checking passed 802.1Q frame according to 
+ * the passed extension parameters (in the *data buffer)
+ * ebt_filter_vlan() is called after successfull check the rule params
+ * by ebt_check_vlan() function.
+ * Parameters:
+ * const struct sk_buff *skb - pointer to passed ethernet frame buffer
+ * const void *data - pointer to passed extension parameters
+ * unsigned int datalen - length of passed *data buffer
+ * const struct net_device *in  -
+ * const struct net_device *out -
+ * const struct ebt_counter *c -
+ * Returned values:
+ * 0 - ok (all rule params matched)
+ * 1 - miss (rule params not acceptable to the parsed frame)
+ */
+static int
+ebt_filter_vlan (const struct sk_buff *skb,
+		 const struct net_device *in,
+		 const struct net_device *out,
+		 const void *data,
+		 unsigned int datalen)
+{
+	struct ebt_vlan_info *info = (struct ebt_vlan_info *) data;	/* userspace data */
+	struct vlan_ethhdr *frame = (struct vlan_ethhdr *) skb->mac.raw;	/* Passed tagged frame */
+
+	unsigned short TCI;	/* Whole TCI, given from parsed frame */
+	unsigned short id;	/* VLAN ID, given from frame TCI */
+	unsigned char prio;	/* user_priority, given from frame TCI */
+	unsigned short encap;	/* VLAN encapsulated Type/Length field, given from orig frame */
+
+	/*
+	 * Tag Control Information (TCI) consists of the following elements:
+	 * - User_priority. This field allows the tagged frame to carry user_priority
+	 * information across Bridged LANs in which individual LAN segments may be unable to signal
+	 * priority information (e.g., 802.3/Ethernet segments). 
+	 * The user_priority field is three bits in length, 
+	 * interpreted as a binary number. The user_priority is therefore
+	 * capable of representing eight priority levels, 0 through 7. 
+	 * The use and interpretation of this field is defined in ISO/IEC 15802-3.
+	 * - Canonical Format Indicator (CFI). This field is used,
+	 * in 802.3/Ethernet, to signal the presence or absence
+	 * of a RIF field, and, in combination with the Non-canonical Format Indicator (NCFI) carried
+	 * in the RIF, to signal the bit order of address information carried in the encapsulated
+	 * frame. The Canonical Format Indicator (CFI) is a single bit flag value.
+	 * - VLAN Identifier (VID). This field uniquely identifies the VLAN to
+	 * which the frame belongs. The twelve-bit VLAN Identifier (VID) field 
+	 * uniquely identify the VLAN to which the frame belongs. 
+	 * The VID is encoded as an unsigned binary number. 
+	 */
+	TCI = ntohs (frame->h_vlan_TCI);
+	id = TCI & 0xFFF;
+	prio = TCI >> 13;
+	encap = frame->h_vlan_encapsulated_proto;
+
+	/*
+	 * First step is to check is null VLAN ID present
+	 * in the parsed frame
+	 */
+	if (!(id)) {
+		/*
+		 * Checking VLAN Identifier (VID)
+		 */
+		if (GET_BITMASK (EBT_VLAN_ID)) {	/* Is VLAN ID parsed? */
+			EXIT_ON_MISMATCH (id, EBT_VLAN_ID);
+			DEBUG_MSG
+			    ("matched rule id=%s%d for frame id=%d\n",
+			     INV_FLAG (EBT_VLAN_ID), info->id, id);
+		}
+	} else {
+		/*
+		 * Checking user_priority
+		 */
+		if (GET_BITMASK (EBT_VLAN_PRIO)) {	/* Is VLAN user_priority parsed? */
+			EXIT_ON_MISMATCH (prio, EBT_VLAN_PRIO);
+			DEBUG_MSG
+			    ("matched rule prio=%s%d for frame prio=%d\n",
+			     INV_FLAG (EBT_VLAN_PRIO), info->prio,
+			     prio);
+		}
+	}
+	/*
+	 * Checking Encapsulated Proto (Length/Type) field
+	 */
+	if (GET_BITMASK (EBT_VLAN_ENCAP)) {	/* Is VLAN Encap parsed? */
+		EXIT_ON_MISMATCH (encap, EBT_VLAN_ENCAP);
+		DEBUG_MSG ("matched encap=%s%2.4X for frame encap=%2.4X\n",
+			   INV_FLAG (EBT_VLAN_ENCAP),
+			   ntohs (info->encap), ntohs (encap));
+	}
+	/*
+	 * All possible extension parameters was parsed.
+	 * If rule never returned by missmatch, then all ok.
+	 */
+	return 0;
+}
+
+/*
+ * Function description: ebt_vlan_check() is called when userspace 
+ * delivers the table to the kernel, 
+ * and to check that userspace doesn't give a bad table.
+ * Parameters:
+ * const char *tablename - table name string
+ * unsigned int hooknr - hook number
+ * const struct ebt_entry *e - ebtables entry basic set
+ * const void *data - pointer to passed extension parameters
+ * unsigned int datalen - length of passed *data buffer
+ * Returned values:
+ * 0 - ok (all delivered rule params are correct)
+ * 1 - miss (rule params is out of range, invalid, incompatible, etc.)
+ */
+static int
+ebt_check_vlan (const char *tablename,
+		unsigned int hooknr,
+		const struct ebt_entry *e, void *data,
+		unsigned int datalen)
+{
+	struct ebt_vlan_info *info = (struct ebt_vlan_info *) data;
+
+	/*
+	 * Parameters buffer overflow check 
+	 */
+	if (datalen != sizeof (struct ebt_vlan_info)) {
+		DEBUG_MSG
+		    ("params size %d is not eq to ebt_vlan_info (%d)\n",
+		     datalen, sizeof (struct ebt_vlan_info));
+		return -EINVAL;
+	}
+
+	/*
+	 * Is it 802.1Q frame checked?
+	 */
+	if (e->ethproto != __constant_htons (ETH_P_8021Q)) {
+		DEBUG_MSG ("passed entry proto %2.4X is not 802.1Q (8100)\n",
+			   (unsigned short) ntohs (e->ethproto));
+		return -EINVAL;
+	}
+
+	/*
+	 * Check for bitmask range 
+	 * True if even one bit is out of mask
+	 */
+	if (info->bitmask & ~EBT_VLAN_MASK) {
+		DEBUG_MSG ("bitmask %2X is out of mask (%2X)\n",
+			   info->bitmask, EBT_VLAN_MASK);
+		return -EINVAL;
+	}
+
+	/*
+	 * Check for inversion flags range 
+	 */
+	if (info->invflags & ~EBT_VLAN_MASK) {
+		DEBUG_MSG ("inversion flags %2X is out of mask (%2X)\n",
+			   info->invflags, EBT_VLAN_MASK);
+		return -EINVAL;
+	}
+
+	/*
+	 * Reserved VLAN ID (VID) values
+	 * -----------------------------
+	 * 0 - The null VLAN ID. Indicates that the tag header contains only user_priority information;
+	 * no VLAN identifier is present in the frame. This VID value shall not be
+	 * configured as a PVID, configured in any Filtering Database entry, or used in any
+	 * Management operation.
+	 * 
+	 * 1 - The default Port VID (PVID) value used for classifying frames on ingress through a Bridge
+	 * Port. The PVID value can be changed by management on a per-Port basis.
+	 * 
+	 * 0x0FFF - Reserved for implementation use. This VID value shall not be configured as a
+	 * PVID or transmitted in a tag header.
+	 * 
+	 * The remaining values of VID are available for general use as VLAN identifiers.
+	 * A Bridge may implement the ability to support less than the full range of VID values; 
+	 * i.e., for a given implementation,
+	 * an upper limit, N, is defined for the VID values supported, where N is less than or equal to 4094.
+	 * All implementations shall support the use of all VID values in the range 0 through their defined maximum
+	 * VID, N.
+	 * 
+	 * For Linux, N = 4094.
+	 */
+	if (GET_BITMASK (EBT_VLAN_ID)) {	/* when vlan-id param was spec-ed */
+		if (!!info->id) {	/* if id!=0 => check vid range */
+			if (info->id > 4094) {	/* check if id > than (0x0FFE) */
+				DEBUG_MSG
+				    ("vlan id %d is out of range (1-4094)\n",
+				     info->id);
+				return -EINVAL;
+			}
+			/*
+			 * Note: This is valid VLAN-tagged frame point.
+			 * Any value of user_priority are acceptable, but could be ignored
+			 * according to 802.1Q Std.
+			 */
+		} else {
+			/*
+			 * if id=0 (null VLAN ID)  => Check for user_priority range 
+			 */
+			if (GET_BITMASK (EBT_VLAN_PRIO)) {
+				if ((unsigned char) info->prio > 7) {
+					DEBUG_MSG
+					    ("prio %d is out of range (0-7)\n",
+					     info->prio);
+					return -EINVAL;
+				}
+			}
+			/*
+			 * Note2: This is valid priority-tagged frame point
+			 * with null VID field.
+			 */
+		}
+	} else {		/* VLAN Id not set */
+		if (GET_BITMASK (EBT_VLAN_PRIO)) {	/* But user_priority is set - abnormal! */
+			info->id = 0;	/* Set null VID (case for Priority-tagged frames) */
+			SET_BITMASK (EBT_VLAN_ID);	/* and set id flag */
+		}
+	}
+	/*
+	 * Check for encapsulated proto range - it is possible to be any value for u_short range.
+	 * When relaying a tagged frame between 802.3/Ethernet MACs, 
+	 * a Bridge may adjust the padding field such that
+	 * the minimum size of a transmitted tagged frame is 68 octets (7.2).
+	 * if_ether.h:  ETH_ZLEN        60   -  Min. octets in frame sans FCS
+	 */
+	if (GET_BITMASK (EBT_VLAN_ENCAP)) {
+		if ((unsigned short) ntohs (info->encap) < ETH_ZLEN) {
+			DEBUG_MSG
+			    ("encap packet length %d is less than minimal %d\n",
+			     ntohs (info->encap), ETH_ZLEN);
+			return -EINVAL;
+		}
+	}
+
+	/*
+	 * Otherwise is all correct 
+	 */
+	DEBUG_MSG ("802.1Q tagged frame checked (%s table, %d hook)\n",
+		   tablename, hooknr);
+	return 0;
+}
+
+static struct ebt_match filter_vlan = {
+	{NULL, NULL},
+	EBT_VLAN_MATCH,
+	ebt_filter_vlan,
+	ebt_check_vlan,
+	NULL,
+	THIS_MODULE
+};
+
+/*
+ * Module initialization function.
+ * Called when module is loaded to kernelspace
+ */
+static int __init init (void)
+{
+	DEBUG_MSG ("ebtables 802.1Q extension module v"
+		   MODULE_VERSION "\n");
+	DEBUG_MSG ("module debug=%d\n", !!debug);
+	return ebt_register_match (&filter_vlan);
+}
+
+/*
+ * Module "finalization" function
+ * Called when download module from kernelspace
+ */
+static void __exit fini (void)
+{
+	ebt_unregister_match (&filter_vlan);
+}
+
+module_init (init);
+module_exit (fini);
diff -Nru a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/bridge/netfilter/ebtable_broute.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,78 @@
+/*
+ *  ebtable_broute
+ *
+ *	Authors:
+ *	Bart De Schuymer <bart.de.schuymer@pandora.be>
+ *
+ *  April, 2002
+ *
+ *  This table lets you choose between routing and bridging for frames
+ *  entering on a bridge enslaved nic. This table is traversed before any
+ *  other ebtables table. See net/bridge/br_input.c.
+ */
+
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/module.h>
+#include <linux/if_bridge.h>
+#include <linux/brlock.h>
+
+// EBT_ACCEPT means the frame will be bridged
+// EBT_DROP means the frame will be routed
+static struct ebt_entries initial_chain =
+  {0, "BROUTING", 0, EBT_ACCEPT, 0};
+
+static struct ebt_replace initial_table =
+{
+  "broute", 1 << NF_BR_BROUTING, 0, sizeof(struct ebt_entries),
+  { [NF_BR_BROUTING]&initial_chain}, 0, NULL, (char *)&initial_chain
+};
+
+static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
+{
+	if (valid_hooks & ~(1 << NF_BR_BROUTING))
+		return -EINVAL;
+	return 0;
+}
+
+static struct ebt_table broute_table =
+{
+  {NULL, NULL}, "broute", &initial_table, 1 << NF_BR_BROUTING,
+  RW_LOCK_UNLOCKED, check, NULL
+};
+
+static int ebt_broute(struct sk_buff **pskb)
+{
+	int ret;
+
+	ret = ebt_do_table(NF_BR_BROUTING, pskb, (*pskb)->dev, NULL,
+	   &broute_table);
+	if (ret == NF_DROP)
+		return 1; // route it
+	return 0; // bridge it
+}
+
+static int __init init(void)
+{
+	int ret;
+
+	ret = ebt_register_table(&broute_table);
+	if (ret < 0)
+		return ret;
+	br_write_lock_bh(BR_NETPROTO_LOCK);
+	// see br_input.c
+	br_should_route_hook = ebt_broute;
+	br_write_unlock_bh(BR_NETPROTO_LOCK);
+	return ret;
+}
+
+static void __exit fini(void)
+{
+	br_write_lock_bh(BR_NETPROTO_LOCK);
+	br_should_route_hook = NULL;
+	br_write_unlock_bh(BR_NETPROTO_LOCK);
+	ebt_unregister_table(&broute_table);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
diff -Nru a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/bridge/netfilter/ebtable_filter.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,89 @@
+/*
+ *  ebtable_filter
+ *
+ *	Authors:
+ *	Bart De Schuymer <bart.de.schuymer@pandora.be>
+ *
+ *  April, 2002
+ *
+ */
+
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/module.h>
+
+#define FILTER_VALID_HOOKS ((1 << NF_BR_LOCAL_IN) | (1 << NF_BR_FORWARD) | \
+   (1 << NF_BR_LOCAL_OUT))
+
+static struct ebt_entries initial_chains[] =
+{
+  {0, "INPUT", 0, EBT_ACCEPT, 0},
+  {0, "FORWARD", 0, EBT_ACCEPT, 0},
+  {0, "OUTPUT", 0, EBT_ACCEPT, 0}
+};
+
+static struct ebt_replace initial_table =
+{
+  "filter", FILTER_VALID_HOOKS, 0, 3 * sizeof(struct ebt_entries),
+  { [NF_BR_LOCAL_IN]&initial_chains[0], [NF_BR_FORWARD]&initial_chains[1],
+    [NF_BR_LOCAL_OUT]&initial_chains[2] }, 0, NULL, (char *)initial_chains
+};
+
+static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
+{
+	if (valid_hooks & ~FILTER_VALID_HOOKS)
+		return -EINVAL;
+	return 0;
+}
+
+static struct ebt_table frame_filter =
+{ 
+  {NULL, NULL}, "filter", &initial_table, FILTER_VALID_HOOKS, 
+  RW_LOCK_UNLOCKED, check, NULL
+};
+
+static unsigned int
+ebt_hook (unsigned int hook, struct sk_buff **pskb, const struct net_device *in,
+   const struct net_device *out, int (*okfn)(struct sk_buff *))
+{
+	return ebt_do_table(hook, pskb, in, out, &frame_filter);
+}
+
+static struct nf_hook_ops ebt_ops_filter[] = {
+	{ { NULL, NULL }, ebt_hook, PF_BRIDGE, NF_BR_LOCAL_IN,
+	   NF_BR_PRI_FILTER_BRIDGED},
+	{ { NULL, NULL }, ebt_hook, PF_BRIDGE, NF_BR_FORWARD,
+	   NF_BR_PRI_FILTER_BRIDGED},
+	{ { NULL, NULL }, ebt_hook, PF_BRIDGE, NF_BR_LOCAL_OUT,
+	   NF_BR_PRI_FILTER_OTHER}
+};
+
+static int __init init(void)
+{
+	int i, j, ret;
+
+	ret = ebt_register_table(&frame_filter);
+	if (ret < 0)
+		return ret;
+	for (i = 0; i < sizeof(ebt_ops_filter) / sizeof(ebt_ops_filter[0]); i++)
+		if ((ret = nf_register_hook(&ebt_ops_filter[i])) < 0)
+			goto cleanup;
+	return ret;
+cleanup:
+	for (j = 0; j < i; j++)
+		nf_unregister_hook(&ebt_ops_filter[j]);
+	ebt_unregister_table(&frame_filter);
+	return ret;
+}
+
+static void __exit fini(void)
+{
+	int i;
+
+	for (i = 0; i < sizeof(ebt_ops_filter) / sizeof(ebt_ops_filter[0]); i++)
+		nf_unregister_hook(&ebt_ops_filter[i]);
+	ebt_unregister_table(&frame_filter);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
diff -Nru a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/bridge/netfilter/ebtable_nat.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,95 @@
+/*
+ *  ebtable_nat
+ *
+ *	Authors:
+ *	Bart De Schuymer <bart.de.schuymer@pandora.be>
+ *
+ *  April, 2002
+ *
+ */
+
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/module.h>
+#define NAT_VALID_HOOKS ((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT) | \
+   (1 << NF_BR_POST_ROUTING))
+
+static struct ebt_entries initial_chains[] =
+{
+  {0, "PREROUTING", 0, EBT_ACCEPT, 0},
+  {0, "OUTPUT", 0, EBT_ACCEPT, 0},
+  {0, "POSTROUTING", 0, EBT_ACCEPT, 0}
+};
+
+static struct ebt_replace initial_table =
+{
+  "nat", NAT_VALID_HOOKS, 0, 3 * sizeof(struct ebt_entries),
+  { [NF_BR_PRE_ROUTING]&initial_chains[0], [NF_BR_LOCAL_OUT]&initial_chains[1],
+    [NF_BR_POST_ROUTING]&initial_chains[2] }, 0, NULL, (char *)initial_chains
+};
+
+static int check(const struct ebt_table_info *info, unsigned int valid_hooks)
+{
+	if (valid_hooks & ~NAT_VALID_HOOKS)
+		return -EINVAL;
+	return 0;
+}
+
+static struct ebt_table frame_nat =
+{
+  {NULL, NULL}, "nat", &initial_table, NAT_VALID_HOOKS,
+  RW_LOCK_UNLOCKED, check, NULL
+};
+
+static unsigned int
+ebt_nat_dst(unsigned int hook, struct sk_buff **pskb, const struct net_device *in
+   , const struct net_device *out, int (*okfn)(struct sk_buff *))
+{
+	return ebt_do_table(hook, pskb, in, out, &frame_nat);
+}
+
+static unsigned int
+ebt_nat_src(unsigned int hook, struct sk_buff **pskb, const struct net_device *in
+   , const struct net_device *out, int (*okfn)(struct sk_buff *))
+{
+	return ebt_do_table(hook, pskb, in, out, &frame_nat);
+}
+
+static struct nf_hook_ops ebt_ops_nat[] = {
+	{ { NULL, NULL }, ebt_nat_dst, PF_BRIDGE, NF_BR_LOCAL_OUT,
+	   NF_BR_PRI_NAT_DST_OTHER},
+	{ { NULL, NULL }, ebt_nat_src, PF_BRIDGE, NF_BR_POST_ROUTING,
+	   NF_BR_PRI_NAT_SRC},
+	{ { NULL, NULL }, ebt_nat_dst, PF_BRIDGE, NF_BR_PRE_ROUTING,
+	   NF_BR_PRI_NAT_DST_BRIDGED},
+};
+
+static int __init init(void)
+{
+	int i, ret, j;
+
+	ret = ebt_register_table(&frame_nat);
+	if (ret < 0)
+		return ret;
+	for (i = 0; i < sizeof(ebt_ops_nat) / sizeof(ebt_ops_nat[0]); i++)
+		if ((ret = nf_register_hook(&ebt_ops_nat[i])) < 0)
+			goto cleanup;
+	return ret;
+cleanup:
+	for (j = 0; j < i; j++)
+		nf_unregister_hook(&ebt_ops_nat[j]);
+	ebt_unregister_table(&frame_nat);
+	return ret;
+}
+
+static void __exit fini(void)
+{
+	int i;
+
+	for (i = 0; i < sizeof(ebt_ops_nat) / sizeof(ebt_ops_nat[0]); i++)
+		nf_unregister_hook(&ebt_ops_nat[i]);
+	ebt_unregister_table(&frame_nat);
+}
+
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
diff -Nru a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/bridge/netfilter/ebtables.c	Fri Sep 20 08:20:49 2002
@@ -0,0 +1,1484 @@
+/*
+ *  ebtables
+ *
+ *  Author:
+ *  Bart De Schuymer		<bart.de.schuymer@pandora.be>
+ *
+ *  ebtables.c,v 2.0, July, 2002
+ *
+ *  This code is stongly inspired on the iptables code which is
+ *  Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
+ *
+ *  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.
+ */
+
+// used for print_string
+#include <linux/sched.h>
+#include <linux/tty.h>
+
+#include <linux/kmod.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/netfilter_bridge/ebtables.h>
+#include <linux/spinlock.h>
+#include <asm/uaccess.h>
+#include <linux/smp.h>
+#include <net/sock.h>
+// needed for logical [in,out]-dev filtering
+#include "../br_private.h"
+
+// list_named_find
+#define ASSERT_READ_LOCK(x)
+#define ASSERT_WRITE_LOCK(x)
+#include <linux/netfilter_ipv4/listhelp.h>
+
+#if 0 // use this for remote debugging
+// Copyright (C) 1998 by Ori Pomerantz
+// Print the string to the appropriate tty, the one
+// the current task uses
+static void print_string(char *str)
+{
+	struct tty_struct *my_tty;
+
+	/* The tty for the current task */
+	my_tty = current->tty;
+	if (my_tty != NULL) {
+		(*(my_tty->driver).write)(my_tty, 0, str, strlen(str));
+		(*(my_tty->driver).write)(my_tty, 0, "\015\012", 2);
+	}
+}
+
+#define BUGPRINT(args) print_string(args);
+#else
+#define BUGPRINT(format, args...) printk("kernel msg: ebtables bug: please "\
+                                         "report to author: "format, ## args)
+// #define BUGPRINT(format, args...)
+#endif
+#define MEMPRINT(format, args...) printk("kernel msg: ebtables "\
+                                         ": out of memory: "format, ## args)
+// #define MEMPRINT(format, args...)
+
+
+
+// Each cpu has its own set of counters, so there is no need for write_lock in
+// the softirq
+// For reading or updating the counters, the user context needs to
+// get a write_lock
+
+// The size of each set of counters is altered to get cache alignment
+#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
+#define COUNTER_OFFSET(n) (SMP_ALIGN(n * sizeof(struct ebt_counter)))
+#define COUNTER_BASE(c, n, cpu) ((struct ebt_counter *)(((char *)c) + \
+   COUNTER_OFFSET(n) * cpu))
+
+
+
+static DECLARE_MUTEX(ebt_mutex);
+static LIST_HEAD(ebt_tables);
+static LIST_HEAD(ebt_targets);
+static LIST_HEAD(ebt_matches);
+static LIST_HEAD(ebt_watchers);
+
+static struct ebt_target ebt_standard_target =
+{ {NULL, NULL}, EBT_STANDARD_TARGET, NULL, NULL, NULL, NULL};
+
+static inline int ebt_do_watcher (struct ebt_entry_watcher *w,
+   const struct sk_buff *skb, const struct net_device *in,
+   const struct net_device *out)
+{
+	w->u.watcher->watcher(skb, in, out, w->data,
+	   w->watcher_size);
+	// watchers don't give a verdict
+	return 0;
+}
+
+static inline int ebt_do_match (struct ebt_entry_match *m,
+   const struct sk_buff *skb, const struct net_device *in,
+   const struct net_device *out)
+{
+	return m->u.match->match(skb, in, out, m->data,
+	   m->match_size);
+}
+
+static inline int ebt_dev_check(char *entry, const struct net_device *device)
+{
+	if (*entry == '\0')
+		return 0;
+	if (!device)
+		return 1;
+	return !!strcmp(entry, device->name);
+}
+
+#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg))
+// process standard matches
+static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h,
+   const struct net_device *in, const struct net_device *out)
+{
+	int verdict, i;
+
+	if (e->bitmask & EBT_802_3) {
+		if (FWINV2(ntohs(h->h_proto) >= 1536, EBT_IPROTO))
+			return 1;
+	} else if (!(e->bitmask & EBT_NOPROTO) &&
+	   FWINV2(e->ethproto != h->h_proto, EBT_IPROTO))
+		return 1;
+
+	if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN))
+		return 1;
+	if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT))
+		return 1;
+	if ((!in || !in->br_port) ? 0 : FWINV2(ebt_dev_check(
+	   e->logical_in, &in->br_port->br->dev), EBT_ILOGICALIN))
+		return 1;
+	if ((!out || !out->br_port) ? 0 : FWINV2(ebt_dev_check(
+	   e->logical_out, &out->br_port->br->dev), EBT_ILOGICALOUT))
+		return 1;
+
+	if (e->bitmask & EBT_SOURCEMAC) {
+		verdict = 0;
+		for (i = 0; i < 6; i++)
+			verdict |= (h->h_source[i] ^ e->sourcemac[i]) &
+			   e->sourcemsk[i];
+		if (FWINV2(verdict != 0, EBT_ISOURCE) )
+			return 1;
+	}
+	if (e->bitmask & EBT_DESTMAC) {
+		verdict = 0;
+		for (i = 0; i < 6; i++)
+			verdict |= (h->h_dest[i] ^ e->destmac[i]) &
+			   e->destmsk[i];
+		if (FWINV2(verdict != 0, EBT_IDEST) )
+			return 1;
+	}
+	return 0;
+}
+
+// Do some firewalling
+unsigned int ebt_do_table (unsigned int hook, struct sk_buff **pskb,
+   const struct net_device *in, const struct net_device *out,
+   struct ebt_table *table)
+{
+	int i, nentries;
+	struct ebt_entry *point;
+	struct ebt_counter *counter_base, *cb_base;
+	struct ebt_entry_target *t;
+	int verdict, sp = 0;
+	struct ebt_chainstack *cs;
+	struct ebt_entries *chaininfo;
+	char *base;
+	struct ebt_table_info *private = table->private;
+
+	read_lock_bh(&table->lock);
+	cb_base = COUNTER_BASE(private->counters, private->nentries,
+	   smp_processor_id());
+	if (private->chainstack)
+		cs = private->chainstack[smp_processor_id()];
+	else
+		cs = NULL;
+	chaininfo = private->hook_entry[hook];
+	nentries = private->hook_entry[hook]->nentries;
+	point = (struct ebt_entry *)(private->hook_entry[hook]->data);
+	counter_base = cb_base + private->hook_entry[hook]->counter_offset;
+	// base for chain jumps
+	base = (char *)chaininfo;
+	i = 0;
+	while (i < nentries) {
+		if (ebt_basic_match(point, (**pskb).mac.ethernet, in, out))
+			goto letscontinue;
+
+		if (EBT_MATCH_ITERATE(point, ebt_do_match, *pskb, in, out) != 0)
+			goto letscontinue;
+
+		// increase counter
+		(*(counter_base + i)).pcnt++;
+
+		// these should only watch: not modify, nor tell us
+		// what to do with the packet
+		EBT_WATCHER_ITERATE(point, ebt_do_watcher, *pskb, in,
+		   out);
+
+		t = (struct ebt_entry_target *)
+		   (((char *)point) + point->target_offset);
+		// standard target
+		if (!t->u.target->target)
+			verdict = ((struct ebt_standard_target *)t)->verdict;
+		else
+			verdict = t->u.target->target(pskb, hook,
+			   in, out, t->data, t->target_size);
+		if (verdict == EBT_ACCEPT) {
+			read_unlock_bh(&table->lock);
+			return NF_ACCEPT;
+		}
+		if (verdict == EBT_DROP) {
+			read_unlock_bh(&table->lock);
+			return NF_DROP;
+		}
+		if (verdict == EBT_RETURN) {
+letsreturn:
+#ifdef CONFIG_NETFILTER_DEBUG
+			if (sp == 0) {
+				BUGPRINT("RETURN on base chain");
+				// act like this is EBT_CONTINUE
+				goto letscontinue;
+			}
+#endif
+			sp--;
+			// put all the local variables right
+			i = cs[sp].n;
+			chaininfo = cs[sp].chaininfo;
+			nentries = chaininfo->nentries;
+			point = cs[sp].e;
+			counter_base = cb_base +
+			   chaininfo->counter_offset;
+			continue;
+		}
+		if (verdict == EBT_CONTINUE)
+			goto letscontinue;
+#ifdef CONFIG_NETFILTER_DEBUG
+		if (verdict < 0) {
+			BUGPRINT("bogus standard verdict\n");
+			read_unlock_bh(&table->lock);
+			return NF_DROP;
+		}
+#endif
+		// jump to a udc
+		cs[sp].n = i + 1;
+		cs[sp].chaininfo = chaininfo;
+		cs[sp].e = (struct ebt_entry *)
+		   (((char *)point) + point->next_offset);
+		i = 0;
+		chaininfo = (struct ebt_entries *) (base + verdict);
+#ifdef CONFIG_NETFILTER_DEBUG
+		if (chaininfo->distinguisher) {
+			BUGPRINT("jump to non-chain\n");
+			read_unlock_bh(&table->lock);
+			return NF_DROP;
+		}
+#endif
+		nentries = chaininfo->nentries;
+		point = (struct ebt_entry *)chaininfo->data;
+		counter_base = cb_base + chaininfo->counter_offset;
+		sp++;
+		continue;
+letscontinue:
+		point = (struct ebt_entry *)
+		   (((char *)point) + point->next_offset);
+		i++;
+	}
+
+	// I actually like this :)
+	if (chaininfo->policy == EBT_RETURN)
+		goto letsreturn;
+	if (chaininfo->policy == EBT_ACCEPT) {
+		read_unlock_bh(&table->lock);
+		return NF_ACCEPT;
+	}
+	read_unlock_bh(&table->lock);
+	return NF_DROP;
+}
+
+// If it succeeds, returns element and locks mutex
+static inline void *
+find_inlist_lock_noload(struct list_head *head, const char *name, int *error,
+   struct semaphore *mutex)
+{
+	void *ret;
+
+	*error = down_interruptible(mutex);
+	if (*error != 0)
+		return NULL;
+
+	ret = list_named_find(head, name);
+	if (!ret) {
+		*error = -ENOENT;
+		up(mutex);
+	}
+	return ret;
+}
+
+#ifndef CONFIG_KMOD
+#define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
+#else
+static void *
+find_inlist_lock(struct list_head *head, const char *name, const char *prefix,
+   int *error, struct semaphore *mutex)
+{
+	void *ret;
+
+	ret = find_inlist_lock_noload(head, name, error, mutex);
+	if (!ret) {
+		char modulename[EBT_FUNCTION_MAXNAMELEN + strlen(prefix) + 1];
+		strcpy(modulename, prefix);
+		strcat(modulename, name);
+		request_module(modulename);
+		ret = find_inlist_lock_noload(head, name, error, mutex);
+	}
+	return ret;
+}
+#endif
+
+static inline struct ebt_table *
+find_table_lock(const char *name, int *error, struct semaphore *mutex)
+{
+	return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex);
+}
+
+static inline struct ebt_match *
+find_match_lock(const char *name, int *error, struct semaphore *mutex)
+{
+	return find_inlist_lock(&ebt_matches, name, "ebt_", error, mutex);
+}
+
+static inline struct ebt_watcher *
+find_watcher_lock(const char *name, int *error, struct semaphore *mutex)
+{
+	return find_inlist_lock(&ebt_watchers, name, "ebt_", error, mutex);
+}
+
+static inline struct ebt_target *
+find_target_lock(const char *name, int *error, struct semaphore *mutex)
+{
+	return find_inlist_lock(&ebt_targets, name, "ebt_", error, mutex);
+}
+
+static inline int
+ebt_check_match(struct ebt_entry_match *m, struct ebt_entry *e,
+   const char *name, unsigned int hookmask, unsigned int *cnt)
+{
+	struct ebt_match *match;
+	int ret;
+
+	if (((char *)m) + m->match_size + sizeof(struct ebt_entry_match) >
+	   ((char *)e) + e->watchers_offset)
+		return -EINVAL;
+	match = find_match_lock(m->u.name, &ret, &ebt_mutex);
+	if (!match)
+		return ret;
+	m->u.match = match;
+	if (match->me)
+		__MOD_INC_USE_COUNT(match->me);
+	up(&ebt_mutex);
+	if (match->check &&
+	   match->check(name, hookmask, e, m->data, m->match_size) != 0) {
+		BUGPRINT("match->check failed\n");
+		if (match->me)
+			__MOD_DEC_USE_COUNT(match->me);
+		return -EINVAL;
+	}
+	(*cnt)++;
+	return 0;
+}
+
+static inline int
+ebt_check_watcher(struct ebt_entry_watcher *w, struct ebt_entry *e,
+   const char *name, unsigned int hookmask, unsigned int *cnt)
+{
+	struct ebt_watcher *watcher;
+	int ret;
+
+	if (((char *)w) + w->watcher_size + sizeof(struct ebt_entry_watcher) >
+	   ((char *)e) + e->target_offset)
+		return -EINVAL;
+	watcher = find_watcher_lock(w->u.name, &ret, &ebt_mutex);
+	if (!watcher)
+		return ret;
+	w->u.watcher = watcher;
+	if (watcher->me)
+		__MOD_INC_USE_COUNT(watcher->me);
+	up(&ebt_mutex);
+	if (watcher->check &&
+	   watcher->check(name, hookmask, e, w->data, w->watcher_size) != 0) {
+		BUGPRINT("watcher->check failed\n");
+		if (watcher->me)
+			__MOD_DEC_USE_COUNT(watcher->me);
+		return -EINVAL;
+	}
+	(*cnt)++;
+	return 0;
+}
+
+// this one is very careful, as it is the first function
+// to parse the userspace data
+static inline int
+ebt_check_entry_size_and_hooks(struct ebt_entry *e,
+   struct ebt_table_info *newinfo, char *base, char *limit,
+   struct ebt_entries **hook_entries, unsigned int *n, unsigned int *cnt,
+   unsigned int *totalcnt, unsigned int *udc_cnt, unsigned int valid_hooks)
+{
+	int i;
+
+	for (i = 0; i < NF_BR_NUMHOOKS; i++) {
+		if ((valid_hooks & (1 << i)) == 0)
+			continue;
+		if ( (char *)hook_entries[i] - base ==
+		   (char *)e - newinfo->entries)
+			break;
+	}
+	// beginning of a new chain
+	// if i == NF_BR_NUMHOOKS it must be a user defined chain
+	if (i != NF_BR_NUMHOOKS || !(e->bitmask & EBT_ENTRY_OR_ENTRIES)) {
+		if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) != 0) {
+			// we make userspace set this right,
+			// so there is no misunderstanding
+			BUGPRINT("EBT_ENTRY_OR_ENTRIES shouldn't be set "
+			         "in distinguisher\n");
+			return -EINVAL;
+		}
+		// this checks if the previous chain has as many entries
+		// as it said it has
+		if (*n != *cnt) {
+			BUGPRINT("nentries does not equal the nr of entries "
+		                 "in the chain\n");
+			return -EINVAL;
+		}
+		// before we look at the struct, be sure it is not too big
+		if ((char *)hook_entries[i] + sizeof(struct ebt_entries)
+		   > limit) {
+			BUGPRINT("entries_size too small\n");
+			return -EINVAL;
+		}
+		if (((struct ebt_entries *)e)->policy != EBT_DROP &&
+		   ((struct ebt_entries *)e)->policy != EBT_ACCEPT) {
+			// only RETURN from udc
+			if (i != NF_BR_NUMHOOKS ||
+			   ((struct ebt_entries *)e)->policy != EBT_RETURN) {
+				BUGPRINT("bad policy\n");
+				return -EINVAL;
+			}
+		}
+		if (i == NF_BR_NUMHOOKS) // it's a user defined chain
+			(*udc_cnt)++;
+		else
+			newinfo->hook_entry[i] = (struct ebt_entries *)e;
+		if (((struct ebt_entries *)e)->counter_offset != *totalcnt) {
+			BUGPRINT("counter_offset != totalcnt");
+			return -EINVAL;
+		}
+		*n = ((struct ebt_entries *)e)->nentries;
+		*cnt = 0;
+		return 0;
+	}
+	// a plain old entry, heh
+	if (sizeof(struct ebt_entry) > e->watchers_offset ||
+	   e->watchers_offset > e->target_offset ||
+	   e->target_offset >= e->next_offset) {
+		BUGPRINT("entry offsets not in right order\n");
+		return -EINVAL;
+	}
+	// this is not checked anywhere else
+	if (e->next_offset - e->target_offset < sizeof(struct ebt_entry_target)) {
+		BUGPRINT("target size too small\n");
+		return -EINVAL;
+	}
+
+	(*cnt)++;
+	(*totalcnt)++;
+	return 0;
+}
+
+struct ebt_cl_stack
+{
+	struct ebt_chainstack cs;
+	int from;
+	unsigned int hookmask;
+};
+
+// we need these positions to check that the jumps to a different part of the
+// entries is a jump to the beginning of a new chain.
+static inline int
+ebt_get_udc_positions(struct ebt_entry *e, struct ebt_table_info *newinfo,
+   struct ebt_entries **hook_entries, unsigned int *n, unsigned int valid_hooks,
+   struct ebt_cl_stack *udc)
+{
+	int i;
+
+	// we're only interested in chain starts
+	if (e->bitmask & EBT_ENTRY_OR_ENTRIES)
+		return 0;
+	for (i = 0; i < NF_BR_NUMHOOKS; i++) {
+		if ((valid_hooks & (1 << i)) == 0)
+			continue;
+		if (newinfo->hook_entry[i] == (struct ebt_entries *)e)
+			break;
+	}
+	// only care about udc
+	if (i != NF_BR_NUMHOOKS)
+		return 0;
+
+	udc[*n].cs.chaininfo = (struct ebt_entries *)e;
+	// these initialisations are depended on later in check_chainloops()
+	udc[*n].cs.n = 0;
+	udc[*n].hookmask = 0;
+
+	(*n)++;
+	return 0;
+}
+
+static inline int
+ebt_cleanup_match(struct ebt_entry_match *m, unsigned int *i)
+{
+	if (i && (*i)-- == 0)
+		return 1;
+	if (m->u.match->destroy)
+		m->u.match->destroy(m->data, m->match_size);
+	if (m->u.match->me)
+		__MOD_DEC_USE_COUNT(m->u.match->me);
+
+	return 0;
+}
+
+static inline int
+ebt_cleanup_watcher(struct ebt_entry_watcher *w, unsigned int *i)
+{
+	if (i && (*i)-- == 0)
+		return 1;
+	if (w->u.watcher->destroy)
+		w->u.watcher->destroy(w->data, w->watcher_size);
+	if (w->u.watcher->me)
+		__MOD_DEC_USE_COUNT(w->u.watcher->me);
+
+	return 0;
+}
+
+static inline int
+ebt_cleanup_entry(struct ebt_entry *e, unsigned int *cnt)
+{
+	struct ebt_entry_target *t;
+
+	if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0)
+		return 0;
+	// we're done
+	if (cnt && (*cnt)-- == 0)
+		return 1;
+	EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, NULL);
+	EBT_MATCH_ITERATE(e, ebt_cleanup_match, NULL);
+	t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
+	if (t->u.target->destroy)
+		t->u.target->destroy(t->data, t->target_size);
+	if (t->u.target->me)
+		__MOD_DEC_USE_COUNT(t->u.target->me);
+
+	return 0;
+}
+
+static inline int
+ebt_check_entry(struct ebt_entry *e, struct ebt_table_info *newinfo,
+   const char *name, unsigned int *cnt, unsigned int valid_hooks,
+   struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
+{
+	struct ebt_entry_target *t;
+	struct ebt_target *target;
+	unsigned int i, j, hook = 0, hookmask = 0;
+	int ret;
+
+	// Don't mess with the struct ebt_entries
+	if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0)
+		return 0;
+
+	if (e->bitmask & ~EBT_F_MASK) {
+		BUGPRINT("Unknown flag for bitmask\n");
+		return -EINVAL;
+	}
+	if (e->invflags & ~EBT_INV_MASK) {
+		BUGPRINT("Unknown flag for inv bitmask\n");
+		return -EINVAL;
+	}
+	if ( (e->bitmask & EBT_NOPROTO) && (e->bitmask & EBT_802_3) ) {
+		BUGPRINT("NOPROTO & 802_3 not allowed\n");
+		return -EINVAL;
+	}
+	// what hook do we belong to?
+	for (i = 0; i < NF_BR_NUMHOOKS; i++) {
+		if ((valid_hooks & (1 << i)) == 0)
+			continue;
+		if ((char *)newinfo->hook_entry[i] < (char *)e)
+			hook = i;
+		else
+			break;
+	}
+	// (1 << NF_BR_NUMHOOKS) tells the check functions the rule is on
+	// a base chain
+	if (i < NF_BR_NUMHOOKS)
+		hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
+	else {
+		for (i = 0; i < udc_cnt; i++)
+			if ((char *)(cl_s[i].cs.chaininfo) > (char *)e)
+				break;
+		if (i == 0)
+			hookmask = (1 << hook) | (1 << NF_BR_NUMHOOKS);
+		else
+			hookmask = cl_s[i - 1].hookmask;
+	}
+	i = 0;
+	ret = EBT_MATCH_ITERATE(e, ebt_check_match, e, name, hookmask, &i);
+	if (ret != 0)
+		goto cleanup_matches;
+	j = 0;
+	ret = EBT_WATCHER_ITERATE(e, ebt_check_watcher, e, name, hookmask, &j);
+	if (ret != 0)
+		goto cleanup_watchers;
+	t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
+	target = find_target_lock(t->u.name, &ret, &ebt_mutex);
+	if (!target)
+		goto cleanup_watchers;
+	if (target->me)
+		__MOD_INC_USE_COUNT(target->me);
+	up(&ebt_mutex);
+
+	t->u.target = target;
+	if (t->u.target == &ebt_standard_target) {
+		if (e->target_offset + sizeof(struct ebt_standard_target) >
+		   e->next_offset) {
+			BUGPRINT("Standard target size too big\n");
+			ret = -EFAULT;
+			goto cleanup_watchers;
+		}
+		if (((struct ebt_standard_target *)t)->verdict <
+		   -NUM_STANDARD_TARGETS) {
+			BUGPRINT("Invalid standard target\n");
+			ret = -EFAULT;
+			goto cleanup_watchers;
+		}
+	} else if ((e->target_offset + t->target_size +
+	   sizeof(struct ebt_entry_target) > e->next_offset) ||
+	   (t->u.target->check &&
+	   t->u.target->check(name, hookmask, e, t->data, t->target_size) != 0)){
+		if (t->u.target->me)
+			__MOD_DEC_USE_COUNT(t->u.target->me);
+		ret = -EFAULT;
+		goto cleanup_watchers;
+	}
+	(*cnt)++;
+	return 0;
+cleanup_watchers:
+	EBT_WATCHER_ITERATE(e, ebt_cleanup_watcher, &j);
+cleanup_matches:
+	EBT_MATCH_ITERATE(e, ebt_cleanup_match, &i);
+	return ret;
+}
+
+// checks for loops and sets the hook mask for udc
+// the hook mask for udc tells us from which base chains the udc can be
+// accessed. This mask is a parameter to the check() functions of the extensions
+int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
+   unsigned int udc_cnt, unsigned int hooknr, char *base)
+{
+	int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
+	struct ebt_entry *e = (struct ebt_entry *)chain->data;
+	struct ebt_entry_target *t;
+
+	while (pos < nentries || chain_nr != -1) {
+		// end of udc, go back one 'recursion' step
+		if (pos == nentries) {
+			// put back values of the time when this chain was called
+			e = cl_s[chain_nr].cs.e;
+			if (cl_s[chain_nr].from != -1)
+				nentries =
+				cl_s[cl_s[chain_nr].from].cs.chaininfo->nentries;
+			else
+				nentries = chain->nentries;
+			pos = cl_s[chain_nr].cs.n;
+			// make sure we won't see a loop that isn't one
+			cl_s[chain_nr].cs.n = 0;
+			chain_nr = cl_s[chain_nr].from;
+			if (pos == nentries)
+				continue;
+		}
+		t = (struct ebt_entry_target *)
+		   (((char *)e) + e->target_offset);
+		if (strcmp(t->u.name, EBT_STANDARD_TARGET))
+			goto letscontinue;
+		if (e->target_offset + sizeof(struct ebt_standard_target) >
+		   e->next_offset) {
+			BUGPRINT("Standard target size too big\n");
+			return -1;
+		}
+		verdict = ((struct ebt_standard_target *)t)->verdict;
+		if (verdict >= 0) { // jump to another chain
+			struct ebt_entries *hlp2 =
+			   (struct ebt_entries *)(base + verdict);
+			for (i = 0; i < udc_cnt; i++)
+				if (hlp2 == cl_s[i].cs.chaininfo)
+					break;
+			// bad destination or loop
+			if (i == udc_cnt) {
+				BUGPRINT("bad destination\n");
+				return -1;
+			}
+			if (cl_s[i].cs.n) {
+				BUGPRINT("loop\n");
+				return -1;
+			}
+			// this can't be 0, so the above test is correct
+			cl_s[i].cs.n = pos + 1;
+			pos = 0;
+			cl_s[i].cs.e = ((void *)e + e->next_offset);
+			e = (struct ebt_entry *)(hlp2->data);
+			nentries = hlp2->nentries;
+			cl_s[i].from = chain_nr;
+			chain_nr = i;
+			// this udc is accessible from the base chain for hooknr
+			cl_s[i].hookmask |= (1 << hooknr);
+			continue;
+		}
+letscontinue:
+		e = (void *)e + e->next_offset;
+		pos++;
+	}
+	return 0;
+}
+
+// do the parsing of the table/chains/entries/matches/watchers/targets, heh
+static int translate_table(struct ebt_replace *repl,
+   struct ebt_table_info *newinfo)
+{
+	unsigned int i, j, k, udc_cnt;
+	int ret;
+	struct ebt_cl_stack *cl_s = NULL; // used in the checking for chain loops
+
+	i = 0;
+	while (i < NF_BR_NUMHOOKS && !(repl->valid_hooks & (1 << i)))
+		i++;
+	if (i == NF_BR_NUMHOOKS) {
+		BUGPRINT("No valid hooks specified\n");
+		return -EINVAL;
+	}
+	if (repl->hook_entry[i] != (struct ebt_entries *)repl->entries) {
+		BUGPRINT("Chains don't start at beginning\n");
+		return -EINVAL;
+	}
+	// make sure chains are ordered after each other in same order
+	// as their corresponding hooks
+	for (j = i + 1; j < NF_BR_NUMHOOKS; j++) {
+		if (!(repl->valid_hooks & (1 << j)))
+			continue;
+		if ( repl->hook_entry[j] <= repl->hook_entry[i] ) {
+			BUGPRINT("Hook order must be followed\n");
+			return -EINVAL;
+		}
+		i = j;
+	}
+
+	for (i = 0; i < NF_BR_NUMHOOKS; i++)
+		newinfo->hook_entry[i] = NULL;
+
+	newinfo->entries_size = repl->entries_size;
+	newinfo->nentries = repl->nentries;
+
+	// do some early checkings and initialize some things
+	i = 0; // holds the expected nr. of entries for the chain
+	j = 0; // holds the up to now counted entries for the chain
+	k = 0; // holds the total nr. of entries, should equal
+	       // newinfo->nentries afterwards
+	udc_cnt = 0; // will hold the nr. of user defined chains (udc)
+	ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
+	   ebt_check_entry_size_and_hooks, newinfo, repl->entries,
+	   repl->entries + repl->entries_size, repl->hook_entry, &i, &j, &k,
+	   &udc_cnt, repl->valid_hooks);
+
+	if (ret != 0)
+		return ret;
+
+	if (i != j) {
+		BUGPRINT("nentries does not equal the nr of entries in the "
+		         "(last) chain\n");
+		return -EINVAL;
+	}
+	if (k != newinfo->nentries) {
+		BUGPRINT("Total nentries is wrong\n");
+		return -EINVAL;
+	}
+
+	// check if all valid hooks have a chain
+	for (i = 0; i < NF_BR_NUMHOOKS; i++) {
+		if (newinfo->hook_entry[i] == NULL &&
+		   (repl->valid_hooks & (1 << i))) {
+			BUGPRINT("Valid hook without chain\n");
+			return -EINVAL;
+		}
+	}
+
+	// Get the location of the udc, put them in an array
+	// While we're at it, allocate the chainstack
+	if (udc_cnt) {
+		// this will get free'd in do_replace()/ebt_register_table()
+		// if an error occurs
+		newinfo->chainstack = (struct ebt_chainstack **)
+		   vmalloc(NR_CPUS * sizeof(struct ebt_chainstack));
+		if (!newinfo->chainstack)
+			return -ENOMEM;
+		for (i = 0; i < NR_CPUS; i++) {
+			newinfo->chainstack[i] =
+			   vmalloc(udc_cnt * sizeof(struct ebt_chainstack));
+			if (!newinfo->chainstack[i]) {
+				while (i)
+					vfree(newinfo->chainstack[--i]);
+				vfree(newinfo->chainstack);
+				newinfo->chainstack = NULL;
+				return -ENOMEM;
+			}
+		}
+
+		cl_s = (struct ebt_cl_stack *)
+		   vmalloc(udc_cnt * sizeof(struct ebt_cl_stack));
+		if (!cl_s)
+			return -ENOMEM;
+		i = 0; // the i'th udc
+		EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
+		   ebt_get_udc_positions, newinfo, repl->hook_entry, &i,
+		   repl->valid_hooks, cl_s);
+		// sanity check
+		if (i != udc_cnt) {
+			BUGPRINT("i != udc_cnt\n");
+			vfree(cl_s);
+			return -EFAULT;
+		}
+	}
+
+	// Check for loops
+	for (i = 0; i < NF_BR_NUMHOOKS; i++)
+		if (repl->valid_hooks & (1 << i))
+			if (check_chainloops(newinfo->hook_entry[i],
+			   cl_s, udc_cnt, i, newinfo->entries)) {
+				if (cl_s)
+					vfree(cl_s);
+				return -EINVAL;
+			}
+
+	// we now know the following (along with E=mc²):
+	// - the nr of entries in each chain is right
+	// - the size of the allocated space is right
+	// - all valid hooks have a corresponding chain
+	// - there are no loops
+	// - wrong data can still be on the level of a single entry
+	// - could be there are jumps to places that are not the
+	//   beginning of a chain. This can only occur in chains that
+	//   are not accessible from any base chains, so we don't care.
+
+	// used to know what we need to clean up if something goes wrong
+	i = 0;
+	ret = EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
+	   ebt_check_entry, newinfo, repl->name, &i, repl->valid_hooks,
+	   cl_s, udc_cnt);
+	if (ret != 0) {
+		EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
+		   ebt_cleanup_entry, &i);
+	}
+	if (cl_s)
+		vfree(cl_s);
+	return ret;
+}
+
+// called under write_lock
+static void get_counters(struct ebt_counter *oldcounters,
+   struct ebt_counter *counters, unsigned int nentries)
+{
+	int i, cpu;
+	struct ebt_counter *counter_base;
+
+	// counters of cpu 0
+	memcpy(counters, oldcounters,
+	   sizeof(struct ebt_counter) * nentries);
+	// add other counters to those of cpu 0
+	for (cpu = 1; cpu < NR_CPUS; cpu++) {
+		counter_base = COUNTER_BASE(oldcounters, nentries, cpu);
+		for (i = 0; i < nentries; i++)
+			counters[i].pcnt += counter_base[i].pcnt;
+	}
+}
+
+// replace the table
+static int do_replace(void *user, unsigned int len)
+{
+	int ret, i, countersize;
+	struct ebt_table_info *newinfo;
+	struct ebt_replace tmp;
+	struct ebt_table *t;
+	struct ebt_counter *counterstmp = NULL;
+	// used to be able to unlock earlier
+	struct ebt_table_info *table;
+
+	if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
+		return -EFAULT;
+
+	if (len != sizeof(tmp) + tmp.entries_size) {
+		BUGPRINT("Wrong len argument\n");
+		return -EINVAL;
+	}
+
+	if (tmp.entries_size == 0) {
+		BUGPRINT("Entries_size never zero\n");
+		return -EINVAL;
+	}
+	countersize = COUNTER_OFFSET(tmp.nentries) * NR_CPUS;
+	newinfo = (struct ebt_table_info *)
+	   vmalloc(sizeof(struct ebt_table_info) + countersize);
+	if (!newinfo)
+		return -ENOMEM;
+
+	if (countersize)
+		memset(newinfo->counters, 0, countersize);
+
+	newinfo->entries = (char *)vmalloc(tmp.entries_size);
+	if (!newinfo->entries) {
+		ret = -ENOMEM;
+		goto free_newinfo;
+	}
+	if (copy_from_user(
+	   newinfo->entries, tmp.entries, tmp.entries_size) != 0) {
+		BUGPRINT("Couldn't copy entries from userspace\n");
+		ret = -EFAULT;
+		goto free_entries;
+	}
+
+	// the user wants counters back
+	// the check on the size is done later, when we have the lock
+	if (tmp.num_counters) {
+		counterstmp = (struct ebt_counter *)
+		   vmalloc(tmp.num_counters * sizeof(struct ebt_counter));
+		if (!counterstmp) {
+			ret = -ENOMEM;
+			goto free_entries;
+		}
+	}
+	else
+		counterstmp = NULL;
+
+	// this can get initialized by translate_table()
+	newinfo->chainstack = NULL;
+	ret = translate_table(&tmp, newinfo);
+
+	if (ret != 0)
+		goto free_counterstmp;
+
+	t = find_table_lock(tmp.name, &ret, &ebt_mutex);
+	if (!t)
+		goto free_iterate;
+
+	// the table doesn't like it
+	if (t->check && (ret = t->check(newinfo, tmp.valid_hooks)))
+		goto free_unlock;
+
+	if (tmp.num_counters && tmp.num_counters != t->private->nentries) {
+		BUGPRINT("Wrong nr. of counters requested\n");
+		ret = -EINVAL;
+		goto free_unlock;
+	}
+
+	// we have the mutex lock, so no danger in reading this pointer
+	table = t->private;
+	// we need an atomic snapshot of the counters
+	write_lock_bh(&t->lock);
+	if (tmp.num_counters)
+		get_counters(t->private->counters, counterstmp,
+		   t->private->nentries);
+
+	t->private = newinfo;
+	write_unlock_bh(&t->lock);
+	up(&ebt_mutex);
+	// So, a user can change the chains while having messed up her counter
+	// allocation. Only reason why this is done is because this way the lock
+	// is held only once, while this doesn't bring the kernel into a
+	// dangerous state.
+	if (tmp.num_counters &&
+	   copy_to_user(tmp.counters, counterstmp,
+	   tmp.num_counters * sizeof(struct ebt_counter))) {
+		BUGPRINT("Couldn't copy counters to userspace\n");
+		ret = -EFAULT;
+	}
+	else
+		ret = 0;
+
+	// decrease module count and free resources
+	EBT_ENTRY_ITERATE(table->entries, table->entries_size,
+	   ebt_cleanup_entry, NULL);
+
+	vfree(table->entries);
+	if (table->chainstack) {
+		for (i = 0; i < NR_CPUS; i++)
+			vfree(table->chainstack[i]);
+		vfree(table->chainstack);
+	}
+	vfree(table);
+
+	if (counterstmp)
+		vfree(counterstmp);
+	return ret;
+
+free_unlock:
+	up(&ebt_mutex);
+free_iterate:
+	EBT_ENTRY_ITERATE(newinfo->entries, newinfo->entries_size,
+	   ebt_cleanup_entry, NULL);
+free_counterstmp:
+	if (counterstmp)
+		vfree(counterstmp);
+	// can be initialized in translate_table()
+	if (newinfo->chainstack) {
+		for (i = 0; i < NR_CPUS; i++)
+			vfree(newinfo->chainstack[i]);
+		vfree(newinfo->chainstack);
+	}
+free_entries:
+	if (newinfo->entries)
+		vfree(newinfo->entries);
+free_newinfo:
+	if (newinfo)
+		vfree(newinfo);
+	return ret;
+}
+
+int ebt_register_target(struct ebt_target *target)
+{
+	int ret;
+
+	ret = down_interruptible(&ebt_mutex);
+	if (ret != 0)
+		return ret;
+	if (!list_named_insert(&ebt_targets, target)) {
+		up(&ebt_mutex);
+		return -EEXIST;
+	}
+	up(&ebt_mutex);
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+void ebt_unregister_target(struct ebt_target *target)
+{
+	down(&ebt_mutex);
+	LIST_DELETE(&ebt_targets, target);
+	up(&ebt_mutex);
+	MOD_DEC_USE_COUNT;
+}
+
+int ebt_register_match(struct ebt_match *match)
+{
+	int ret;
+
+	ret = down_interruptible(&ebt_mutex);
+	if (ret != 0)
+		return ret;
+	if (!list_named_insert(&ebt_matches, match)) {
+		up(&ebt_mutex);
+		return -EEXIST;
+	}
+	up(&ebt_mutex);
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+void ebt_unregister_match(struct ebt_match *match)
+{
+	down(&ebt_mutex);
+	LIST_DELETE(&ebt_matches, match);
+	up(&ebt_mutex);
+	MOD_DEC_USE_COUNT;
+}
+
+int ebt_register_watcher(struct ebt_watcher *watcher)
+{
+	int ret;
+
+	ret = down_interruptible(&ebt_mutex);
+	if (ret != 0)
+		return ret;
+	if (!list_named_insert(&ebt_watchers, watcher)) {
+		up(&ebt_mutex);
+		return -EEXIST;
+	}
+	up(&ebt_mutex);
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+void ebt_unregister_watcher(struct ebt_watcher *watcher)
+{
+	down(&ebt_mutex);
+	LIST_DELETE(&ebt_watchers, watcher);
+	up(&ebt_mutex);
+	MOD_DEC_USE_COUNT;
+}
+
+int ebt_register_table(struct ebt_table *table)
+{
+	struct ebt_table_info *newinfo;
+	int ret, i, countersize;
+
+	if (!table || !table->table ||!table->table->entries ||
+	    table->table->entries_size == 0 ||
+	    table->table->counters || table->private) {
+		BUGPRINT("Bad table data for ebt_register_table!!!\n");
+		return -EINVAL;
+	}
+
+	countersize = COUNTER_OFFSET(table->table->nentries) * NR_CPUS;
+	newinfo = (struct ebt_table_info *)
+	   vmalloc(sizeof(struct ebt_table_info) + countersize);
+	ret = -ENOMEM;
+	if (!newinfo)
+		return -ENOMEM;
+
+	newinfo->entries = (char *)vmalloc(table->table->entries_size);
+	if (!(newinfo->entries))
+		goto free_newinfo;
+
+	memcpy(newinfo->entries, table->table->entries,
+	   table->table->entries_size);
+
+	if (countersize)
+		memset(newinfo->counters, 0, countersize);
+
+	// fill in newinfo and parse the entries
+	newinfo->chainstack = NULL;
+	ret = translate_table(table->table, newinfo);
+	if (ret != 0) {
+		BUGPRINT("Translate_table failed\n");
+		goto free_chainstack;
+	}
+
+	if (table->check && table->check(newinfo, table->valid_hooks)) {
+		BUGPRINT("The table doesn't like its own initial data, lol\n");
+		return -EINVAL;
+	}
+
+	table->private = newinfo;
+	table->lock = RW_LOCK_UNLOCKED;
+	ret = down_interruptible(&ebt_mutex);
+	if (ret != 0)
+		goto free_chainstack;
+
+	if (list_named_find(&ebt_tables, table->name)) {
+		ret = -EEXIST;
+		BUGPRINT("Table name already exists\n");
+		goto free_unlock;
+	}
+
+	list_prepend(&ebt_tables, table);
+	up(&ebt_mutex);
+	MOD_INC_USE_COUNT;
+	return 0;
+free_unlock:
+	up(&ebt_mutex);
+free_chainstack:
+	if (newinfo->chainstack) {
+		for (i = 0; i < NR_CPUS; i++)
+			vfree(newinfo->chainstack[i]);
+		vfree(newinfo->chainstack);
+	}
+	vfree(newinfo->entries);
+free_newinfo:
+	vfree(newinfo);
+	return ret;
+}
+
+void ebt_unregister_table(struct ebt_table *table)
+{
+	int i;
+
+	if (!table) {
+		BUGPRINT("Request to unregister NULL table!!!\n");
+		return;
+	}
+	down(&ebt_mutex);
+	LIST_DELETE(&ebt_tables, table);
+	up(&ebt_mutex);
+	EBT_ENTRY_ITERATE(table->private->entries,
+	   table->private->entries_size, ebt_cleanup_entry, NULL);
+	if (table->private->entries)
+		vfree(table->private->entries);
+	if (table->private->chainstack) {
+		for (i = 0; i < NR_CPUS; i++)
+			vfree(table->private->chainstack[i]);
+		vfree(table->private->chainstack);
+	}
+	vfree(table->private);
+	MOD_DEC_USE_COUNT;
+}
+
+// userspace just supplied us with counters
+static int update_counters(void *user, unsigned int len)
+{
+	int i, ret;
+	struct ebt_counter *tmp;
+	struct ebt_replace hlp;
+	struct ebt_table *t;
+
+	if (copy_from_user(&hlp, user, sizeof(hlp)))
+		return -EFAULT;
+
+	if (len != sizeof(hlp) + hlp.num_counters * sizeof(struct ebt_counter))
+		return -EINVAL;
+	if (hlp.num_counters == 0)
+		return -EINVAL;
+
+	if ( !(tmp = (struct ebt_counter *)
+	   vmalloc(hlp.num_counters * sizeof(struct ebt_counter))) ){
+		MEMPRINT("Update_counters && nomemory\n");
+		return -ENOMEM;
+	}
+
+	t = find_table_lock(hlp.name, &ret, &ebt_mutex);
+	if (!t)
+		goto free_tmp;
+
+	if (hlp.num_counters != t->private->nentries) {
+		BUGPRINT("Wrong nr of counters\n");
+		ret = -EINVAL;
+		goto unlock_mutex;
+	}
+
+	if ( copy_from_user(tmp, hlp.counters,
+	   hlp.num_counters * sizeof(struct ebt_counter)) ) {
+		BUGPRINT("Updata_counters && !cfu\n");
+		ret = -EFAULT;
+		goto unlock_mutex;
+	}
+
+	// we want an atomic add of the counters
+	write_lock_bh(&t->lock);
+
+	// we add to the counters of the first cpu
+	for (i = 0; i < hlp.num_counters; i++)
+		t->private->counters[i].pcnt += tmp[i].pcnt;
+
+	write_unlock_bh(&t->lock);
+	ret = 0;
+unlock_mutex:
+	up(&ebt_mutex);
+free_tmp:
+	vfree(tmp);
+	return ret;
+}
+
+static inline int ebt_make_matchname(struct ebt_entry_match *m,
+   char *base, char *ubase)
+{
+	char *hlp = ubase - base + (char *)m;
+	if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
+		return -EFAULT;
+	return 0;
+}
+
+static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
+   char *base, char *ubase)
+{
+	char *hlp = ubase - base + (char *)w;
+	if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
+		return -EFAULT;
+	return 0;
+}
+
+static inline int ebt_make_names(struct ebt_entry *e, char *base, char *ubase)
+{
+	int ret;
+	char *hlp;
+	struct ebt_entry_target *t;
+
+	if ((e->bitmask & EBT_ENTRY_OR_ENTRIES) == 0)
+		return 0;
+
+	hlp = ubase - base + (char *)e + e->target_offset;
+	t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
+	
+	ret = EBT_MATCH_ITERATE(e, ebt_make_matchname, base, ubase);
+	if (ret != 0)
+		return ret;
+	ret = EBT_WATCHER_ITERATE(e, ebt_make_watchername, base, ubase);
+	if (ret != 0)
+		return ret;
+	if (copy_to_user(hlp, t->u.target->name, EBT_FUNCTION_MAXNAMELEN))
+		return -EFAULT;
+	return 0;
+}
+
+// called with ebt_mutex down
+static int copy_everything_to_user(struct ebt_table *t, void *user,
+   int *len, int cmd)
+{
+	struct ebt_replace tmp;
+	struct ebt_counter *counterstmp, *oldcounters;
+	unsigned int entries_size, nentries;
+	char *entries;
+
+	if (cmd == EBT_SO_GET_ENTRIES) {
+		entries_size = t->private->entries_size;
+		nentries = t->private->nentries;
+		entries = t->private->entries;
+		oldcounters = t->private->counters;
+	} else {
+		entries_size = t->table->entries_size;
+		nentries = t->table->nentries;
+		entries = t->table->entries;
+		oldcounters = t->table->counters;
+	}
+
+	if (copy_from_user(&tmp, user, sizeof(tmp))) {
+		BUGPRINT("Cfu didn't work\n");
+		return -EFAULT;
+	}
+
+	if (*len != sizeof(struct ebt_replace) + entries_size +
+	   (tmp.num_counters? nentries * sizeof(struct ebt_counter): 0)) {
+		BUGPRINT("Wrong size\n");
+		return -EINVAL;
+	}
+
+	if (tmp.nentries != nentries) {
+		BUGPRINT("Nentries wrong\n");
+		return -EINVAL;
+	}
+
+	if (tmp.entries_size != entries_size) {
+		BUGPRINT("Wrong size\n");
+		return -EINVAL;
+	}
+
+	// userspace might not need the counters
+	if (tmp.num_counters) {
+		if (tmp.num_counters != nentries) {
+			BUGPRINT("Num_counters wrong\n");
+			return -EINVAL;
+		}
+		counterstmp = (struct ebt_counter *)
+		   vmalloc(nentries * sizeof(struct ebt_counter));
+		if (!counterstmp) {
+			MEMPRINT("Couldn't copy counters, out of memory\n");
+			return -ENOMEM;
+		}
+		write_lock_bh(&t->lock);
+		get_counters(oldcounters, counterstmp, nentries);
+		write_unlock_bh(&t->lock);
+
+		if (copy_to_user(tmp.counters, counterstmp,
+		   nentries * sizeof(struct ebt_counter))) {
+			BUGPRINT("Couldn't copy counters to userspace\n");
+			vfree(counterstmp);
+			return -EFAULT;
+		}
+		vfree(counterstmp);
+	}
+
+	if (copy_to_user(tmp.entries, entries, entries_size)) {
+		BUGPRINT("Couldn't copy entries to userspace\n");
+		return -EFAULT;
+	}
+	// set the match/watcher/target names right
+	return EBT_ENTRY_ITERATE(entries, entries_size,
+	   ebt_make_names, entries, tmp.entries);
+}
+
+static int do_ebt_set_ctl(struct sock *sk,
+	int cmd, void *user, unsigned int len)
+{
+	int ret;
+
+	switch(cmd) {
+	case EBT_SO_SET_ENTRIES:
+		ret = do_replace(user, len);
+		break;
+	case EBT_SO_SET_COUNTERS:
+		ret = update_counters(user, len);
+		break;
+	default:
+		ret = -EINVAL;
+  }
+	return ret;
+}
+
+static int do_ebt_get_ctl(struct sock *sk, int cmd, void *user, int *len)
+{
+	int ret;
+	struct ebt_replace tmp;
+	struct ebt_table *t;
+
+	if (copy_from_user(&tmp, user, sizeof(tmp)))
+		return -EFAULT;
+
+	t = find_table_lock(tmp.name, &ret, &ebt_mutex);
+	if (!t)
+		return ret;
+
+	switch(cmd) {
+	case EBT_SO_GET_INFO:
+	case EBT_SO_GET_INIT_INFO:
+		if (*len != sizeof(struct ebt_replace)){
+			ret = -EINVAL;
+			up(&ebt_mutex);
+			break;
+		}
+		if (cmd == EBT_SO_GET_INFO) {
+			tmp.nentries = t->private->nentries;
+			tmp.entries_size = t->private->entries_size;
+			tmp.valid_hooks = t->valid_hooks;
+		} else {
+			tmp.nentries = t->table->nentries;
+			tmp.entries_size = t->table->entries_size;
+			tmp.valid_hooks = t->table->valid_hooks;
+		}
+		up(&ebt_mutex);
+		if (copy_to_user(user, &tmp, *len) != 0){
+			BUGPRINT("c2u Didn't work\n");
+			ret = -EFAULT;
+			break;
+		}
+		ret = 0;
+		break;
+
+	case EBT_SO_GET_ENTRIES:
+	case EBT_SO_GET_INIT_ENTRIES:
+		ret = copy_everything_to_user(t, user, len, cmd);
+		up(&ebt_mutex);
+		break;
+
+	default:
+		up(&ebt_mutex);
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static struct nf_sockopt_ops ebt_sockopts =
+{ { NULL, NULL }, PF_INET, EBT_BASE_CTL, EBT_SO_SET_MAX + 1, do_ebt_set_ctl,
+    EBT_BASE_CTL, EBT_SO_GET_MAX + 1, do_ebt_get_ctl, 0, NULL
+};
+
+static int __init init(void)
+{
+	int ret;
+
+	down(&ebt_mutex);
+	list_named_insert(&ebt_targets, &ebt_standard_target);
+	up(&ebt_mutex);
+	if ((ret = nf_register_sockopt(&ebt_sockopts)) < 0)
+		return ret;
+
+	printk("Ebtables v2.0 registered");
+	return 0;
+}
+
+static void __exit fini(void)
+{
+	nf_unregister_sockopt(&ebt_sockopts);
+	printk("Ebtables v2.0 unregistered");
+}
+
+EXPORT_SYMBOL(ebt_register_table);
+EXPORT_SYMBOL(ebt_unregister_table);
+EXPORT_SYMBOL(ebt_register_match);
+EXPORT_SYMBOL(ebt_unregister_match);
+EXPORT_SYMBOL(ebt_register_watcher);
+EXPORT_SYMBOL(ebt_unregister_watcher);
+EXPORT_SYMBOL(ebt_register_target);
+EXPORT_SYMBOL(ebt_unregister_target);
+EXPORT_SYMBOL(ebt_do_table);
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
diff -Nru a/net/core/dev.c b/net/core/dev.c
--- a/net/core/dev.c	Fri Sep 20 08:20:46 2002
+++ b/net/core/dev.c	Fri Sep 20 08:20:46 2002
@@ -1397,7 +1397,7 @@
 }
 
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-void (*br_handle_frame_hook)(struct sk_buff *skb) = NULL;
+int (*br_handle_frame_hook)(struct sk_buff *skb) = NULL;
 #endif
 
 static __inline__ int handle_bridge(struct sk_buff *skb,
@@ -1414,7 +1414,6 @@
 		}
 	}
 
-	br_handle_frame_hook(skb);
 	return ret;
 }
 
@@ -1475,7 +1474,12 @@
 
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
 	if (skb->dev->br_port && br_handle_frame_hook) {
-		return handle_bridge(skb, pt_prev);
+		int ret;
+
+		ret = handle_bridge(skb, pt_prev);
+		if (br_handle_frame_hook(skb) == 0)
+			return ret;
+		pt_prev = NULL;
 	}
 #endif
 
diff -Nru a/net/core/wireless.c b/net/core/wireless.c
--- a/net/core/wireless.c	Fri Sep 20 08:20:47 2002
+++ b/net/core/wireless.c	Fri Sep 20 08:20:47 2002
@@ -33,8 +33,16 @@
  *	o Propagate events as rtnetlink IFLA_WIRELESS option
  *	o Generate event on selected SET requests
  *
- * v4 - 18.04.01 - Jean II
+ * v4 - 18.04.02 - Jean II
  *	o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1
+ *
+ * v5 - 21.06.02 - Jean II
+ *	o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup)
+ *	o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
+ *	o Add IWEVCUSTOM for driver specific event/scanning token
+ *	o Turn on WE_STRICT_WRITE by default + kernel warning
+ *	o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num)
+ *	o Fix off-by-one in test (extra_size <= IFNAMSIZ)
  */
 
 /***************************** INCLUDES *****************************/
@@ -50,8 +58,9 @@
 
 /**************************** CONSTANTS ****************************/
 
-/* This will be turned on later on... */
-#undef WE_STRICT_WRITE		/* Check write buffer size */
+/* Enough lenience, let's make sure things are proper... */
+#define WE_STRICT_WRITE		/* Check write buffer size */
+/* I'll probably drop both the define and kernel message in the next version */
 
 /* Debuging stuff */
 #undef WE_IOCTL_DEBUG		/* Debug IOCTL API */
@@ -106,7 +115,7 @@
 	/* SIOCSIWSPY */
 	{ IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0},
 	/* SIOCGIWSPY */
-	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0},
+	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_GET_SPY, 0},
 	/* -- hole -- */
 	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
 	/* -- hole -- */
@@ -176,25 +185,41 @@
 	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
 	/* IWEVQUAL */
 	{ IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0},
+	/* IWEVCUSTOM */
+	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_CUSTOM_MAX, 0},
+	/* IWEVREGISTERED */
+	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
+	/* IWEVEXPIRED */
+	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
 };
 static const int standard_event_num = (sizeof(standard_event) /
 				       sizeof(struct iw_ioctl_description));
 
 /* Size (in bytes) of the various private data types */
-static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
+static const char priv_type_size[] = {
+	0,				/* IW_PRIV_TYPE_NONE */
+	1,				/* IW_PRIV_TYPE_BYTE */
+	1,				/* IW_PRIV_TYPE_CHAR */
+	0,				/* Not defined */
+	sizeof(__u32),			/* IW_PRIV_TYPE_INT */
+	sizeof(struct iw_freq),		/* IW_PRIV_TYPE_FLOAT */
+	sizeof(struct sockaddr),	/* IW_PRIV_TYPE_ADDR */
+	0,				/* Not defined */
+};
 
 /* Size (in bytes) of various events */
 static const int event_type_size[] = {
-	IW_EV_LCP_LEN,
+	IW_EV_LCP_LEN,			/* IW_HEADER_TYPE_NULL */
+	0,
+	IW_EV_CHAR_LEN,			/* IW_HEADER_TYPE_CHAR */
 	0,
-	IW_EV_CHAR_LEN,
+	IW_EV_UINT_LEN,			/* IW_HEADER_TYPE_UINT */
+	IW_EV_FREQ_LEN,			/* IW_HEADER_TYPE_FREQ */
+	IW_EV_ADDR_LEN,			/* IW_HEADER_TYPE_ADDR */
 	0,
-	IW_EV_UINT_LEN,
-	IW_EV_FREQ_LEN,
 	IW_EV_POINT_LEN,		/* Without variable payload */
-	IW_EV_PARAM_LEN,
-	IW_EV_ADDR_LEN,
-	IW_EV_QUAL_LEN,
+	IW_EV_PARAM_LEN,		/* IW_HEADER_TYPE_PARAM */
+	IW_EV_QUAL_LEN,			/* IW_HEADER_TYPE_QUAL */
 };
 
 /************************ COMMON SUBROUTINES ************************/
@@ -440,8 +465,10 @@
 		return -EFAULT;
 #ifdef WE_STRICT_WRITE
 	/* Check if there is enough buffer up there */
-	if(iwr->u.data.length < (SIOCIWLASTPRIV - SIOCIWFIRSTPRIV + 1))
+	if(iwr->u.data.length < dev->wireless_handlers->num_private_args) {
+		printk(KERN_ERR "%s (WE) : Buffer for request SIOCGIWPRIV too small (%d<%d)\n", dev->name, iwr->u.data.length, dev->wireless_handlers->num_private_args);
 		return -E2BIG;
+	}
 #endif	/* WE_STRICT_WRITE */
 
 	/* Set the number of available ioctls. */
@@ -471,6 +498,7 @@
 	const struct iw_ioctl_description *	descr;
 	struct iw_request_info			info;
 	int					ret = -EINVAL;
+	int					user_size = 0;
 
 	/* Get the description of the IOCTL */
 	if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
@@ -518,11 +546,8 @@
 			/* Check NULL pointer */
 			if(iwr->u.data.pointer == NULL)
 				return -EFAULT;
-#ifdef WE_STRICT_WRITE
-			/* Check if there is enough buffer up there */
-			if(iwr->u.data.length < descr->max_tokens)
-				return -E2BIG;
-#endif	/* WE_STRICT_WRITE */
+			/* Save user space buffer size for checking */
+			user_size = iwr->u.data.length;
 		}
 
 #ifdef WE_IOCTL_DEBUG
@@ -559,6 +584,15 @@
 
 		/* If we have something to return to the user */
 		if (!ret && IW_IS_GET(cmd)) {
+#ifdef WE_STRICT_WRITE
+			/* Check if there is enough buffer up there */
+			if(user_size < iwr->u.data.length) {
+				printk(KERN_ERR "%s (WE) : Buffer for request %04X too small (%d<%d)\n", dev->name, cmd, user_size, iwr->u.data.length);
+				kfree(extra);
+				return -E2BIG;
+			}
+#endif	/* WE_STRICT_WRITE */
+
 			err = copy_to_user(iwr->u.data.pointer, extra,
 					   iwr->u.data.length *
 					   descr->token_size);
@@ -646,12 +680,18 @@
 	/* Compute the size of the set/get arguments */
 	if(descr != NULL) {
 		if(IW_IS_SET(cmd)) {
+			int	offset = 0;	/* For sub-ioctls */
+			/* Check for sub-ioctl handler */
+			if(descr->name[0] == '\0')
+				/* Reserve one int for sub-ioctl index */
+				offset = sizeof(__u32);
+
 			/* Size of set arguments */
 			extra_size = get_priv_size(descr->set_args);
 
 			/* Does it fits in iwr ? */
 			if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
-			   (extra_size < IFNAMSIZ))
+			   ((extra_size + offset) <= IFNAMSIZ))
 				extra_size = 0;
 		} else {
 			/* Size of set arguments */
@@ -659,7 +699,7 @@
 
 			/* Does it fits in iwr ? */
 			if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
-			   (extra_size < IFNAMSIZ))
+			   (extra_size <= IFNAMSIZ))
 				extra_size = 0;
 		}
 	}
@@ -925,7 +965,7 @@
 		 * The best the driver could do is to log an error message.
 		 * We will do it ourselves instead...
 		 */
-	  	printk(KERN_ERR "%s (WE) : Invalid Wireless Event (0x%04X)\n",
+	  	printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n",
 		       dev->name, cmd);
 		return;
 	}
diff -Nru a/net/irda/discovery.c b/net/irda/discovery.c
--- a/net/irda/discovery.c	Fri Sep 20 08:20:43 2002
+++ b/net/irda/discovery.c	Fri Sep 20 08:20:43 2002
@@ -61,7 +61,7 @@
 	/* Set time of first discovery if node is new (see below) */
 	new->first_timestamp = new->timestamp;
 
-	spin_lock_irqsave(&irlmp->log_lock, flags);
+	spin_lock_irqsave(&cachelog->hb_spinlock, flags);
 
 	/* 
 	 * Remove all discoveries of devices that has previously been 
@@ -95,13 +95,13 @@
 	/* Insert the new and updated version */
 	hashbin_insert(cachelog, (irda_queue_t *) new, new->daddr, NULL);
 
-	spin_unlock_irqrestore(&irlmp->log_lock, flags);
+	spin_unlock_irqrestore(&cachelog->hb_spinlock, flags);
 }
 
 /*
  * Function irlmp_add_discovery_log (cachelog, log)
  *
- *    Merge a disovery log into the cachlog.
+ *    Merge a disovery log into the cachelog.
  *
  */
 void irlmp_add_discovery_log(hashbin_t *cachelog, hashbin_t *log)
@@ -115,11 +115,17 @@
 	 *  discovery, so restart discovery again with just the half timeout
 	 *  of the normal one.
 	 */
+	/* Well... It means that there was nobody out there - Jean II */
 	if (log == NULL) {
 		/* irlmp_start_discovery_timer(irlmp, 150); */
 		return;
 	}
 
+	/*
+	 * Locking : we are the only owner of this discovery log, so
+	 * no need to lock it.
+	 * We just need to lock the global log in irlmp_add_discovery().
+	 */
 	discovery = (discovery_t *) hashbin_remove_first(log);
 	while (discovery != NULL) {
 		irlmp_add_discovery(cachelog, discovery);
@@ -146,7 +152,7 @@
 
 	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
-	spin_lock_irqsave(&irlmp->log_lock, flags);
+	spin_lock_irqsave(&log->hb_spinlock, flags);
 
 	discovery = (discovery_t *) hashbin_get_first(log);
 	while (discovery != NULL) {
@@ -169,7 +175,7 @@
 		}
 	}
 
-	spin_unlock_irqrestore(&irlmp->log_lock, flags);
+	spin_unlock_irqrestore(&log->hb_spinlock, flags);
 }
 
 /*
@@ -230,13 +236,13 @@
 		return NULL;
 
 	/* Save spin lock - spinlock should be discovery specific */
-	spin_lock_irqsave(&irlmp->log_lock, flags);
+	spin_lock_irqsave(&log->hb_spinlock, flags);
 
 	/* Create the client specific buffer */
 	n = HASHBIN_GET_SIZE(log);
 	buffer = kmalloc(n * sizeof(struct irda_device_info), GFP_ATOMIC);
 	if (buffer == NULL) {
-		spin_unlock_irqrestore(&irlmp->log_lock, flags);
+		spin_unlock_irqrestore(&log->hb_spinlock, flags);
 		return NULL;
 	}
 
@@ -257,7 +263,7 @@
 		discovery = (discovery_t *) hashbin_get_next(log);
 	}
 
-	spin_unlock_irqrestore(&irlmp->log_lock, flags);
+	spin_unlock_irqrestore(&log->hb_spinlock, flags);
 
 	/* Get the actual number of device in the buffer and return */
 	*pn = i;
@@ -276,7 +282,7 @@
 	unsigned long flags;
 	discovery_t *d;
 
-	spin_lock_irqsave(&irlmp->log_lock, flags);
+	spin_lock_irqsave(&cachelog->hb_spinlock, flags);
 
 	/* Look at all discoveries for that link */
 	d = (discovery_t *) hashbin_get_first(cachelog);
@@ -288,13 +294,13 @@
 		if (strcmp(name, d->nickname) == 0) {
 			*saddr = d->saddr;
 			
-			spin_unlock_irqrestore(&irlmp->log_lock, flags);
+			spin_unlock_irqrestore(&cachelog->hb_spinlock, flags);
 			return d->daddr;
 		}
 		d = (discovery_t *) hashbin_get_next(cachelog);
 	}
 
-	spin_unlock_irqrestore(&irlmp->log_lock, flags);
+	spin_unlock_irqrestore(&cachelog->hb_spinlock, flags);
 
 	return 0;
 }
@@ -310,7 +316,7 @@
 {
 	discovery_t *discovery;
 	unsigned long flags;
-	hashbin_t *cachelog = irlmp_get_cachelog();
+	hashbin_t *cachelog = irlmp->cachelog;
 	int		len = 0;
 
 	if (!irlmp)
@@ -318,7 +324,7 @@
 
 	len = sprintf(buf, "IrLMP: Discovery log:\n\n");	
 	
-	spin_lock_irqsave(&irlmp->log_lock, flags);
+	spin_lock_irqsave(&cachelog->hb_spinlock, flags);
 
 	discovery = (discovery_t *) hashbin_get_first(cachelog);
 	while (( discovery != NULL) && (len < length)) {
@@ -362,7 +368,7 @@
 		
 		discovery = (discovery_t *) hashbin_get_next(cachelog);
 	}
-	spin_unlock_irqrestore(&irlmp->log_lock, flags);
+	spin_unlock_irqrestore(&cachelog->hb_spinlock, flags);
 
 	return len;
 }
diff -Nru a/net/irda/ircomm/ircomm_core.c b/net/irda/ircomm/ircomm_core.c
--- a/net/irda/ircomm/ircomm_core.c	Fri Sep 20 08:20:41 2002
+++ b/net/irda/ircomm/ircomm_core.c	Fri Sep 20 08:20:41 2002
@@ -61,7 +61,7 @@
 
 int __init ircomm_init(void)
 {
-	ircomm = hashbin_new(HB_LOCAL); 
+	ircomm = hashbin_new(HB_LOCK); 
 	if (ircomm == NULL) {
 		ERROR(__FUNCTION__ "(), can't allocate hashbin!\n");
 		return -ENOMEM;
@@ -505,11 +505,10 @@
 	struct ircomm_cb *self;
 	unsigned long flags;
 	
-	save_flags(flags);
-	cli();
-
 	len = 0;
 
+	spin_lock_irqsave(&ircomm->hb_spinlock, flags);
+
 	self = (struct ircomm_cb *) hashbin_get_first(ircomm);
 	while (self != NULL) {
 		ASSERT(self->magic == IRCOMM_MAGIC, break;);
@@ -535,7 +534,7 @@
 
 		self = (struct ircomm_cb *) hashbin_get_next(ircomm);
  	} 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&ircomm->hb_spinlock, flags);
 
 	return len;
 }
diff -Nru a/net/irda/ircomm/ircomm_lmp.c b/net/irda/ircomm/ircomm_lmp.c
--- a/net/irda/ircomm/ircomm_lmp.c	Fri Sep 20 08:20:41 2002
+++ b/net/irda/ircomm/ircomm_lmp.c	Fri Sep 20 08:20:41 2002
@@ -177,7 +177,7 @@
  
         line = cb->line;
 
-	self = (struct ircomm_cb *) hashbin_find(ircomm, line, NULL);
+	self = (struct ircomm_cb *) hashbin_lock_find(ircomm, line, NULL);
         if (!self) {
 		IRDA_DEBUG(2, __FUNCTION__ "(), didn't find myself\n");
                 return;
diff -Nru a/net/irda/ircomm/ircomm_param.c b/net/irda/ircomm/ircomm_param.c
--- a/net/irda/ircomm/ircomm_param.c	Fri Sep 20 08:20:46 2002
+++ b/net/irda/ircomm/ircomm_param.c	Fri Sep 20 08:20:46 2002
@@ -99,6 +99,8 @@
  */
 int ircomm_param_flush(struct ircomm_tty_cb *self)
 {
+	/* we should lock here, but I guess this function is unused...
+	 * Jean II */
 	if (self->ctrl_skb) {
 		ircomm_control_request(self->ircomm, self->ctrl_skb);
 		self->ctrl_skb = NULL;	
@@ -132,14 +134,13 @@
 	if (self->service_type == IRCOMM_3_WIRE_RAW)
 		return 0;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&self->spinlock, flags);
 
 	skb = self->ctrl_skb;	
 	if (!skb) {
 		skb = dev_alloc_skb(256);
 		if (!skb) {
-			restore_flags(flags);
+			spin_unlock_irqrestore(&self->spinlock, flags);
 			return -ENOMEM;
 		}
 		
@@ -154,12 +155,12 @@
 				  &ircomm_param_info);
 	if (count < 0) {
 		WARNING(__FUNCTION__ "(), no room for parameter!\n");
-		restore_flags(flags);
+		spin_unlock_irqrestore(&self->spinlock, flags);
 		return -1;
 	}
 	skb_put(skb, count);
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&self->spinlock, flags);
 
 	IRDA_DEBUG(2, __FUNCTION__ "(), skb->len=%d\n", skb->len);
 
diff -Nru a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c
--- a/net/irda/ircomm/ircomm_tty.c	Fri Sep 20 08:20:44 2002
+++ b/net/irda/ircomm/ircomm_tty.c	Fri Sep 20 08:20:44 2002
@@ -90,7 +90,7 @@
  */
 int __init ircomm_tty_init(void)
 {	
-	ircomm_tty = hashbin_new(HB_LOCAL); 
+	ircomm_tty = hashbin_new(HB_LOCK); 
 	if (ircomm_tty == NULL) {
 		ERROR(__FUNCTION__ "(), can't allocate hashbin!\n");
 		return -ENOMEM;
@@ -308,22 +308,25 @@
 	IRDA_DEBUG(2, "%s(%d):block_til_ready before block on %s open_count=%d\n",
 	      __FILE__,__LINE__, tty->driver.name, self->open_count );
 
-	save_flags(flags); cli();
+	/* As far as I can see, we protect open_count - Jean II */
+	spin_lock_irqsave(&self->spinlock, flags);
 	if (!tty_hung_up_p(filp)) {
 		extra_count = 1;
 		self->open_count--;
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&self->spinlock, flags);
 	self->blocked_open++;
 	
 	while (1) {
 		if (!(self->flags & ASYNC_CALLOUT_ACTIVE) &&
  		    (tty->termios->c_cflag & CBAUD)) {
-			save_flags(flags); cli();
+			/* Here, we use to lock those two guys, but
+			 * as ircomm_param_request() does it itself,
+			 * I don't see the point (and I see the deadlock).
+			 * Jean II */
 			self->settings.dte |= IRCOMM_RTS + IRCOMM_DTR;
 		 	
 			ircomm_param_request(self, IRCOMM_DTE, TRUE);
-			restore_flags(flags);
 		}
 		
 		current->state = TASK_INTERRUPTIBLE;
@@ -361,8 +364,12 @@
 	__set_current_state(TASK_RUNNING);
 	remove_wait_queue(&self->open_wait, &wait);
 	
-	if (extra_count)
+	if (extra_count) {
+		/* ++ is not atomic, so this should be protected - Jean II */
+		spin_lock_irqsave(&self->spinlock, flags);
 		self->open_count++;
+		spin_unlock_irqrestore(&self->spinlock, flags);
+	}
 	self->blocked_open--;
 	
 	IRDA_DEBUG(1, "%s(%d):block_til_ready after blocking on %s open_count=%d\n",
@@ -385,6 +392,7 @@
 {
 	struct ircomm_tty_cb *self;
 	unsigned int line;
+	unsigned long	flags;
 	int ret;
 
 	IRDA_DEBUG(2, __FUNCTION__ "()\n");
@@ -397,7 +405,7 @@
 	}
 
 	/* Check if instance already exists */
-	self = hashbin_find(ircomm_tty, line, NULL);
+	self = hashbin_lock_find(ircomm_tty, line, NULL);
 	if (!self) {
 		/* No, so make new instance */
 		self = kmalloc(sizeof(struct ircomm_tty_cb), GFP_KERNEL);
@@ -423,6 +431,7 @@
 		init_timer(&self->watchdog_timer);
 		init_waitqueue_head(&self->open_wait);
  		init_waitqueue_head(&self->close_wait);
+		spin_lock_init(&self->spinlock);
 
 		/* 
 		 * Force TTY into raw mode by default which is usually what
@@ -435,10 +444,13 @@
 		/* Insert into hash */
 		hashbin_insert(ircomm_tty, (irda_queue_t *) self, line, NULL);
 	}
+	/* ++ is not atomic, so this should be protected - Jean II */
+	spin_lock_irqsave(&self->spinlock, flags);
 	self->open_count++;
 
 	tty->driver_data = self;
 	self->tty = tty;
+	spin_unlock_irqrestore(&self->spinlock, flags);
 
 	IRDA_DEBUG(1, __FUNCTION__"(), %s%d, count = %d\n", tty->driver.name, 
 		   self->line, self->open_count);
@@ -526,12 +538,11 @@
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
-	save_flags(flags); 
-	cli();
+	spin_lock_irqsave(&self->spinlock, flags);
 
 	if (tty_hung_up_p(filp)) {
 		MOD_DEC_USE_COUNT;
-		restore_flags(flags);
+		spin_unlock_irqrestore(&self->spinlock, flags);
 
 		IRDA_DEBUG(0, __FUNCTION__ "(), returning 1\n");
 		return;
@@ -559,13 +570,19 @@
 	}
 	if (self->open_count) {
 		MOD_DEC_USE_COUNT;
-		restore_flags(flags);
+		spin_unlock_irqrestore(&self->spinlock, flags);
 
 		IRDA_DEBUG(0, __FUNCTION__ "(), open count > 0\n");
 		return;
 	}
 	self->flags |= ASYNC_CLOSING;
 
+	/* We need to unlock here (we were unlocking at the end of this
+	 * function), because tty_wait_until_sent() may schedule.
+	 * I don't know if the rest should be locked somehow,
+	 * so someone should check. - Jean II */
+	spin_unlock_irqrestore(&self->spinlock, flags);
+
 	/*
 	 * Now we wait for the transmit buffer to clear; and we notify 
 	 * the line discipline to only process XON/XOFF characters.
@@ -597,7 +614,6 @@
 	wake_up_interruptible(&self->close_wait);
 
 	MOD_DEC_USE_COUNT;
-	restore_flags(flags);
 }
 
 /*
@@ -645,13 +661,12 @@
 		return;
 
 	/* Unlink control buffer */
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&self->spinlock, flags);
 
 	ctrl_skb = self->ctrl_skb;
 	self->ctrl_skb = NULL;
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&self->spinlock, flags);
 
 	/* Flush control buffer if any */
 	if (ctrl_skb && self->flow == FLOW_START)
@@ -661,13 +676,12 @@
 		return;
 
 	/* Unlink transmit buffer */
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&self->spinlock, flags);
 	
 	skb = self->tx_skb;
 	self->tx_skb = NULL;
 
-	restore_flags(flags);	
+	spin_unlock_irqrestore(&self->spinlock, flags);
 
 	/* Flush transmit buffer if any */
 	if (skb)
@@ -720,8 +734,7 @@
 		return len;
 	}
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&self->spinlock, flags);
 
 	/* Fetch current transmit buffer */
 	skb = self->tx_skb;
@@ -768,7 +781,7 @@
 			skb = dev_alloc_skb(self->max_data_size+
 					    self->max_header_size);
 			if (!skb) {
-				restore_flags(flags);
+				spin_unlock_irqrestore(&self->spinlock, flags);
 				return -ENOBUFS;
 			}
 			skb_reserve(skb, self->max_header_size);
@@ -785,7 +798,7 @@
 		len += size;
 	}
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&self->spinlock, flags);
 
 	/*     
 	 * Schedule a new thread which will transmit the frame as soon
@@ -824,13 +837,12 @@
 	    (self->max_header_size == IRCOMM_TTY_HDR_UNITIALISED))
 		ret = 0;
 	else {
-		save_flags(flags);
-		cli();
+		spin_lock_irqsave(&self->spinlock, flags);
 		if (self->tx_skb)
 			ret = self->max_data_size - self->tx_skb->len;
 		else
 			ret = self->max_data_size;
-		restore_flags(flags);
+		spin_unlock_irqrestore(&self->spinlock, flags);
 	}
 	IRDA_DEBUG(2, __FUNCTION__ "(), ret=%d\n", ret);
 
@@ -946,13 +958,12 @@
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&self->spinlock, flags);
 
 	if (self->tx_skb)
 		len = self->tx_skb->len;
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&self->spinlock, flags);
 
 	return len;
 }
@@ -969,8 +980,7 @@
 	if (!(self->flags & ASYNC_INITIALIZED))
 		return;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&self->spinlock, flags);
 
 	del_timer(&self->watchdog_timer);
 	
@@ -994,7 +1004,7 @@
 	}
 	self->flags &= ~ASYNC_INITIALIZED;
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&self->spinlock, flags);
 }
 
 /*
@@ -1007,6 +1017,7 @@
 static void ircomm_tty_hangup(struct tty_struct *tty)
 {
 	struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
+	unsigned long	flags;
 
 	IRDA_DEBUG(0, __FUNCTION__"()\n");
 
@@ -1019,9 +1030,13 @@
 	/* ircomm_tty_flush_buffer(tty); */
 	ircomm_tty_shutdown(self);
 
+	/* I guess we need to lock here - Jean II */
+	spin_lock_irqsave(&self->spinlock, flags);
 	self->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
 	self->tty = 0;
 	self->open_count = 0;
+	spin_unlock_irqrestore(&self->spinlock, flags);
+
 	wake_up_interruptible(&self->open_wait);
 }
 
@@ -1362,11 +1377,14 @@
 	struct ircomm_tty_cb *self;
         int count = 0, l;
         off_t begin = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ircomm_tty->hb_spinlock, flags);
 
 	self = (struct ircomm_tty_cb *) hashbin_get_first(ircomm_tty);
 	while ((self != NULL) && (count < 4000)) {
 		if (self->magic != IRCOMM_TTY_MAGIC)
-			return 0;
+			break;
 
                 l = ircomm_tty_line_info(self, buf + count);
                 count += l;
@@ -1381,6 +1399,8 @@
         }
         *eof = 1;
 done:
+	spin_unlock_irqrestore(&ircomm_tty->hb_spinlock, flags);
+
         if (offset >= count+begin)
                 return 0;
         *start = buf + (offset-begin);
diff -Nru a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c
--- a/net/irda/ircomm/ircomm_tty_attach.c	Fri Sep 20 08:20:47 2002
+++ b/net/irda/ircomm/ircomm_tty_attach.c	Fri Sep 20 08:20:47 2002
@@ -331,6 +331,8 @@
 	info.daddr = discovery->daddr;
 	info.saddr = discovery->saddr;
 
+	/* FIXME. We probably need to use hashbin_find_next(), but we first
+	 * need to ensure that "line" is unique. - Jean II */
 	self = (struct ircomm_tty_cb *) hashbin_get_first(ircomm_tty);
 	while (self != NULL) {
 		ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
diff -Nru a/net/irda/irda_device.c b/net/irda/irda_device.c
--- a/net/irda/irda_device.c	Fri Sep 20 08:20:46 2002
+++ b/net/irda/irda_device.c	Fri Sep 20 08:20:46 2002
@@ -91,13 +91,13 @@
 
 int __init irda_device_init( void)
 {
-	dongles = hashbin_new(HB_GLOBAL);
+	dongles = hashbin_new(HB_LOCK);
 	if (dongles == NULL) {
 		printk(KERN_WARNING "IrDA: Can't allocate dongles hashbin!\n");
 		return -ENOMEM;
 	}
 
-	tasks = hashbin_new(HB_GLOBAL);
+	tasks = hashbin_new(HB_LOCK);
 	if (tasks == NULL) {
 		printk(KERN_WARNING "IrDA: Can't allocate tasks hashbin!\n");
 		return -ENOMEM;
@@ -438,7 +438,7 @@
 	}
 #endif
 
-	if (!(reg = hashbin_find(dongles, type, NULL))) {
+	if (!(reg = hashbin_lock_find(dongles, type, NULL))) {
 		ERROR("IrDA: Unable to find requested dongle\n");
 		return NULL;
 	}
@@ -477,7 +477,7 @@
 int irda_device_register_dongle(struct dongle_reg *new)
 {
 	/* Check if this dongle has been registred before */
-	if (hashbin_find(dongles, new->type, NULL)) {
+	if (hashbin_lock_find(dongles, new->type, NULL)) {
 		MESSAGE("%s: Dongle already registered\n", __FUNCTION__);
                 return 0;
         }
diff -Nru a/net/irda/iriap.c b/net/irda/iriap.c
--- a/net/irda/iriap.c	Fri Sep 20 08:20:44 2002
+++ b/net/irda/iriap.c	Fri Sep 20 08:20:44 2002
@@ -58,7 +58,7 @@
 #endif	/* CONFIG_IRDA_DEBUG */
 
 static hashbin_t *iriap = NULL;
-static __u32 service_handle;
+static void *service_handle;
 
 extern char *lmp_reasons[];
 
@@ -91,11 +91,12 @@
 	__u16 hints;
 
 	/* Allocate master array */
-	iriap = hashbin_new(HB_LOCAL);
+	iriap = hashbin_new(HB_LOCK);
 	if (!iriap)
 		return -ENOMEM;
 
-	objects = hashbin_new(HB_LOCAL);
+	/* Object repository - defined in irias_object.c */
+	objects = hashbin_new(HB_LOCK);
 	if (!objects) {
 		WARNING("%s: Can't allocate objects hashbin!\n", __FUNCTION__);
 		return -ENOMEM;
@@ -182,7 +183,7 @@
 
 	init_timer(&self->watchdog_timer);
 
-	hashbin_insert(iriap, (irda_queue_t *) self, (int) self, NULL);
+	hashbin_insert(iriap, (irda_queue_t *) self, (long) self, NULL);
 
 	/* Initialize state machines */
 	iriap_next_client_state(self, S_DISCONNECT);
@@ -235,7 +236,7 @@
 		self->lsap = NULL;
 	}
 
-	entry = (struct iriap_cb *) hashbin_remove(iriap, (int) self, NULL);
+	entry = (struct iriap_cb *) hashbin_remove(iriap, (long) self, NULL);
 	ASSERT(entry == self, return;);
 
 	__iriap_close(self);
@@ -973,13 +974,12 @@
 
 	ASSERT( objects != NULL, return 0;);
 
-	save_flags( flags);
-	cli();
-
 	len = 0;
 
 	len += sprintf(buf+len, "LM-IAS Objects:\n");
 
+	spin_lock_irqsave(&objects->hb_spinlock, flags);
+
 	/* List all objects */
 	obj = (struct ias_object *) hashbin_get_first(objects);
 	while ( obj != NULL) {
@@ -989,6 +989,11 @@
 		len += sprintf(buf+len, "id=%d", obj->id);
 		len += sprintf(buf+len, "\n");
 
+		/* Careful for priority inversions here !
+		 * All other uses of attrib spinlock are independant of
+		 * the object spinlock, so we are safe. Jean II */
+		spin_lock(&obj->attribs->hb_spinlock);
+
 		/* List all attributes for this object */
 		attrib = (struct ias_attrib *)
 			hashbin_get_first(obj->attribs);
@@ -1025,9 +1030,11 @@
 			attrib = (struct ias_attrib *)
 				hashbin_get_next(obj->attribs);
 		}
+		spin_unlock(&obj->attribs->hb_spinlock);
+
 	        obj = (struct ias_object *) hashbin_get_next(objects);
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&objects->hb_spinlock, flags);
 
 	return len;
 }
diff -Nru a/net/irda/irias_object.c b/net/irda/irias_object.c
--- a/net/irda/irias_object.c	Fri Sep 20 08:20:41 2002
+++ b/net/irda/irias_object.c	Fri Sep 20 08:20:41 2002
@@ -93,7 +93,10 @@
 	obj->name = strndup(name, IAS_MAX_CLASSNAME);
 	obj->id = id;
 
-	obj->attribs = hashbin_new(HB_LOCAL);
+	/* Locking notes : the attrib spinlock has lower precendence
+	 * than the objects spinlock. Never grap the objects spinlock
+	 * while holding any attrib spinlock (risk of deadlock). Jean II */
+	obj->attribs = hashbin_new(HB_LOCK);
 
 	return obj;
 }
@@ -147,7 +150,7 @@
 	ASSERT(obj != NULL, return -1;);
 	ASSERT(obj->magic == IAS_OBJECT_MAGIC, return -1;);
 
-	node = hashbin_remove(objects, 0, obj->name);
+	node = hashbin_remove_this(objects, (irda_queue_t *) obj);
 	if (!node)
 		return 0; /* Already removed */
 
@@ -172,7 +175,7 @@
 	ASSERT(attrib != NULL, return -1;);
 
 	/* Remove attribute from object */
-	node = hashbin_remove(obj->attribs, 0, attrib->name);
+	node = hashbin_remove_this(obj->attribs, (irda_queue_t *) attrib);
 	if (!node)
 		return 0; /* Already removed or non-existent */
 
@@ -211,7 +214,8 @@
 {
 	ASSERT(name != NULL, return NULL;);
 
-	return hashbin_find(objects, 0, name);
+	/* Unsafe (locking), object might change */
+	return hashbin_lock_find(objects, 0, name);
 }
 
 /*
@@ -228,10 +232,11 @@
 	ASSERT(obj->magic == IAS_OBJECT_MAGIC, return NULL;);
 	ASSERT(name != NULL, return NULL;);
 
-	attrib = hashbin_find(obj->attribs, 0, name);
+	attrib = hashbin_lock_find(obj->attribs, 0, name);
 	if (attrib == NULL)
 		return NULL;
 
+	/* Unsafe (locking), attrib might change */
 	return attrib;
 }
 
@@ -267,26 +272,32 @@
 {
 	struct ias_object *obj;
 	struct ias_attrib *attrib;
+	unsigned long flags;
 
 	/* Find object */
-	obj = hashbin_find(objects, 0, obj_name);
+	obj = hashbin_lock_find(objects, 0, obj_name);
 	if (obj == NULL) {
 		WARNING("%s: Unable to find object: %s\n", __FUNCTION__,
 			obj_name);
 		return -1;
 	}
 
+	/* Slightly unsafe (obj might get removed under us) */
+	spin_lock_irqsave(&obj->attribs->hb_spinlock, flags);
+
 	/* Find attribute */
 	attrib = hashbin_find(obj->attribs, 0, attrib_name);
 	if (attrib == NULL) {
 		WARNING("%s: Unable to find attribute: %s\n", __FUNCTION__,
 			attrib_name);
+		spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags);
 		return -1;
 	}
 
 	if ( attrib->value->type != new_value->type) {
 		IRDA_DEBUG( 0, __FUNCTION__
 		       "(), changing value type not allowed!\n");
+		spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags);
 		return -1;
 	}
 
@@ -297,6 +308,7 @@
 	attrib->value = new_value;
 
 	/* Success */
+	spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags);
 	return 0;
 }
 
diff -Nru a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c
--- a/net/irda/irlan/irlan_common.c	Fri Sep 20 08:20:46 2002
+++ b/net/irda/irlan/irlan_common.c	Fri Sep 20 08:20:46 2002
@@ -124,7 +124,7 @@
 
 	IRDA_DEBUG(0, __FUNCTION__ "()\n");
 	/* Allocate master structure */
-	irlan = hashbin_new(HB_LOCAL); 
+	irlan = hashbin_new(HB_LOCK);	/* protect from /proc */
 	if (irlan == NULL) {
 		printk(KERN_WARNING "IrLAN: Can't allocate hashbin!\n");
 		return -ENOMEM;
@@ -1089,11 +1089,10 @@
 	unsigned long flags;
 	ASSERT(irlan != NULL, return 0;);
      
-	save_flags(flags);
-	cli();
-
 	len = 0;
 	
+	spin_lock_irqsave(&irlan->hb_spinlock, flags);
+
 	len += sprintf(buf+len, "IrLAN instances:\n");
 	
 	self = (struct irlan_cb *) hashbin_get_first(irlan);
@@ -1129,7 +1128,7 @@
 
 		self = (struct irlan_cb *) hashbin_get_next(irlan);
  	} 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&irlan->hb_spinlock, flags);
 
 	return len;
 }
diff -Nru a/net/irda/irlap.c b/net/irda/irlap.c
--- a/net/irda/irlap.c	Fri Sep 20 08:20:47 2002
+++ b/net/irda/irlap.c	Fri Sep 20 08:20:47 2002
@@ -80,7 +80,7 @@
 int __init irlap_init(void)
 {
 	/* Allocate master array */
-	irlap = hashbin_new(HB_LOCAL);
+	irlap = hashbin_new(HB_LOCK);
 	if (irlap == NULL) {
 	        ERROR("%s: can't allocate irlap hashbin!\n", __FUNCTION__);
 		return -ENOMEM;
@@ -139,7 +139,15 @@
 	skb_queue_head_init(&self->wx_list);
 
 	/* My unique IrLAP device address! */
-	get_random_bytes(&self->saddr, sizeof(self->saddr));
+	/* We don't want the broadcast address, neither the NULL address
+	 * (most often used to signify "invalid"), and we don't want an
+	 * address already in use (otherwise connect won't be able
+	 * to select the proper link). - Jean II */
+	do {
+		get_random_bytes(&self->saddr, sizeof(self->saddr));
+	} while ((self->saddr == 0x0) || (self->saddr == BROADCAST) ||
+		 (hashbin_lock_find(irlap, self->saddr, NULL)) );
+	/* Copy to the driver */
 	memcpy(dev->dev_addr, &self->saddr, 4);
 
 	init_timer(&self->slot_timer);
@@ -522,7 +530,8 @@
 		self->discovery_log = NULL;
 	}
 
-	self->discovery_log= hashbin_new(HB_LOCAL);
+	/* All operations will occur at predictable time, no need to lock */
+	self->discovery_log= hashbin_new(HB_NOLOCK);
 
 	info.S = discovery->nslots; /* Number of slots */
 	info.s = 0; /* Current slot */
@@ -1084,15 +1093,14 @@
 	unsigned long flags;
 	int i = 0;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&irlap->hb_spinlock, flags);
 
 	len = 0;
 
 	self = (struct irlap_cb *) hashbin_get_first(irlap);
 	while (self != NULL) {
-		ASSERT(self != NULL, return -ENODEV;);
-		ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
+		ASSERT(self != NULL, break;);
+		ASSERT(self->magic == LAP_MAGIC, break;);
 
 		len += sprintf(buf+len, "irlap%d ", i++);
 		len += sprintf(buf+len, "state: %s\n",
@@ -1164,7 +1172,7 @@
 
 		self = (struct irlap_cb *) hashbin_get_next(irlap);
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&irlap->hb_spinlock, flags);
 
 	return len;
 }
diff -Nru a/net/irda/irlmp.c b/net/irda/irlmp.c
--- a/net/irda/irlmp.c	Fri Sep 20 08:20:47 2002
+++ b/net/irda/irlmp.c	Fri Sep 20 08:20:47 2002
@@ -83,13 +83,13 @@
 	memset(irlmp, 0, sizeof(struct irlmp_cb));
 
 	irlmp->magic = LMP_MAGIC;
-	spin_lock_init(&irlmp->log_lock);
 
-	irlmp->clients = hashbin_new(HB_GLOBAL);
-	irlmp->services = hashbin_new(HB_GLOBAL);
-	irlmp->links = hashbin_new(HB_GLOBAL);
-	irlmp->unconnected_lsaps = hashbin_new(HB_GLOBAL);
-	irlmp->cachelog = hashbin_new(HB_GLOBAL);
+	irlmp->clients = hashbin_new(HB_LOCK);
+	irlmp->services = hashbin_new(HB_LOCK);
+	irlmp->links = hashbin_new(HB_LOCK);
+	irlmp->unconnected_lsaps = hashbin_new(HB_LOCK);
+	irlmp->cachelog = hashbin_new(HB_NOLOCK);
+	spin_lock_init(&irlmp->cachelog->hb_spinlock);
 
 	irlmp->free_lsap_sel = 0x10; /* Reserved 0x00-0x0f */
 	strcpy(sysctl_devname, "Linux");
@@ -177,8 +177,8 @@
 	self->lsap_state = LSAP_DISCONNECTED;
 
 	/* Insert into queue of unconnected LSAPs */
-	hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self, (int) self, 
-		       NULL);
+	hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self,
+		       (long) self, NULL);
 
 	return self;
 }
@@ -238,7 +238,7 @@
 					   LM_LAP_DISCONNECT_REQUEST, NULL);
 		}
 		/* Now, remove from the link */
-		lsap = hashbin_remove(lap->lsaps, (int) self, NULL);
+		lsap = hashbin_remove(lap->lsaps, (long) self, NULL);
 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
 		lap->cache.valid = FALSE;
 #endif
@@ -246,7 +246,7 @@
 	self->lap = NULL;
 	/* Check if we found the LSAP! If not then try the unconnected lsaps */
 	if (!lsap) {
-		lsap = hashbin_remove(irlmp->unconnected_lsaps, (int) self,
+		lsap = hashbin_remove(irlmp->unconnected_lsaps, (long) self,
 				      NULL);
 	}
 	if (!lsap) {
@@ -286,7 +286,7 @@
 	lap->magic = LMP_LAP_MAGIC;
 	lap->saddr = saddr;
 	lap->daddr = DEV_ADDR_ANY;
-	lap->lsaps = hashbin_new(HB_GLOBAL);
+	lap->lsaps = hashbin_new(HB_LOCK);
 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
 	lap->cache.valid = FALSE;
 #endif
@@ -347,7 +347,6 @@
 	struct sk_buff *skb = NULL;
 	struct lap_cb *lap;
 	struct lsap_cb *lsap;
-	discovery_t *discovery;
 
 	ASSERT(self != NULL, return -EBADR;);
 	ASSERT(self->magic == LMP_LSAP_MAGIC, return -EBADR;);
@@ -388,6 +387,10 @@
 	 * device with the given daddr
 	 */
 	if ((!saddr) || (saddr == DEV_ADDR_ANY)) {
+		discovery_t *discovery;
+		unsigned long flags;
+
+		spin_lock_irqsave(&irlmp->cachelog->hb_spinlock, flags);
 		if (daddr != DEV_ADDR_ANY)
 			discovery = hashbin_find(irlmp->cachelog, daddr, NULL);
 		else {
@@ -400,8 +403,9 @@
 			saddr = discovery->saddr;
 			daddr = discovery->daddr;
 		}
+		spin_unlock_irqrestore(&irlmp->cachelog->hb_spinlock, flags);
 	}
-	lap = hashbin_find(irlmp->links, saddr, NULL);
+	lap = hashbin_lock_find(irlmp->links, saddr, NULL);
 	if (lap == NULL) {
 		IRDA_DEBUG(1, __FUNCTION__ "(), Unable to find a usable link!\n");
 		return -EHOSTUNREACH;
@@ -411,11 +415,8 @@
 	if (lap->daddr == DEV_ADDR_ANY)
 		lap->daddr = daddr;
 	else if (lap->daddr != daddr) {
-		struct lsap_cb *any_lsap;
-
 		/* Check if some LSAPs are active on this LAP */
-		any_lsap = (struct lsap_cb *) hashbin_get_first(lap->lsaps);
-		if (any_lsap == NULL) {
+		if (HASHBIN_GET_SIZE(lap->lsaps) == 0) {
 			/* No active connection, but LAP hasn't been
 			 * disconnected yet (waiting for timeout in LAP).
 			 * Maybe we could give LAP a bit of help in this case.
@@ -436,14 +437,15 @@
 	 *  Remove LSAP from list of unconnected LSAPs and insert it into the
 	 *  list of connected LSAPs for the particular link
 	 */
-	lsap = hashbin_remove(irlmp->unconnected_lsaps, (int) self, NULL);
+	lsap = hashbin_remove(irlmp->unconnected_lsaps, (long) self, NULL);
 
 	ASSERT(lsap != NULL, return -1;);
 	ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;);
 	ASSERT(lsap->lap != NULL, return -1;);
 	ASSERT(lsap->lap->magic == LMP_LAP_MAGIC, return -1;);
 
-	hashbin_insert(self->lap->lsaps, (irda_queue_t *) self, (int) self, NULL);
+	hashbin_insert(self->lap->lsaps, (irda_queue_t *) self, (long) self,
+		       NULL);
 
 	set_bit(0, &self->connected);	/* TRUE */
 
@@ -574,29 +576,41 @@
 struct lsap_cb *irlmp_dup(struct lsap_cb *orig, void *instance)
 {
 	struct lsap_cb *new;
+	unsigned long flags;
 
 	IRDA_DEBUG(1, __FUNCTION__ "()\n");
 
+	spin_lock_irqsave(&irlmp->unconnected_lsaps->hb_spinlock, flags);
+
 	/* Only allowed to duplicate unconnected LSAP's */
-	if (!hashbin_find(irlmp->unconnected_lsaps, (int) orig, NULL)) {
+	if (!hashbin_find(irlmp->unconnected_lsaps, (long) orig, NULL)) {
 		IRDA_DEBUG(0, __FUNCTION__ "(), unable to find LSAP\n");
+		spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock,
+				       flags);
 		return NULL;
 	}
+	/* Allocate a new instance */
 	new = kmalloc(sizeof(struct lsap_cb), GFP_ATOMIC);
 	if (!new)  {
 		IRDA_DEBUG(0, __FUNCTION__ "(), unable to kmalloc\n");
+		spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock,
+				       flags);
 		return NULL;
 	}
 	/* Dup */
 	memcpy(new, orig, sizeof(struct lsap_cb));
-	new->notify.instance = instance;
 	/* new->lap = orig->lap; => done in the memcpy() */
 	/* new->slsap_sel = orig->slsap_sel; => done in the memcpy() */
 
+	spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags);
+
+	/* Not everything is the same */
+	new->notify.instance = instance;
+
 	init_timer(&new->watchdog_timer);
 
-	hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) new, (int) new,
-		       NULL);
+	hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) new,
+		       (long) new, NULL);
 
 	/* Make sure that we invalidate the cache */
 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
@@ -646,7 +660,7 @@
 	ASSERT(self->lap->magic == LMP_LAP_MAGIC, return -1;);
 	ASSERT(self->lap->lsaps != NULL, return -1;);
 
-	lsap = hashbin_remove(self->lap->lsaps, (int) self, NULL);
+	lsap = hashbin_remove(self->lap->lsaps, (long) self, NULL);
 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
 	self->lap->cache.valid = FALSE;
 #endif
@@ -655,8 +669,8 @@
 	ASSERT(lsap->magic == LMP_LSAP_MAGIC, return -1;);
 	ASSERT(lsap == self, return -1;);
 
-	hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self, (int) self,
-		       NULL);
+	hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) self,
+		       (long) self, NULL);
 
 	/* Reset some values */
 	self->dlsap_sel = LSAP_ANY;
@@ -699,15 +713,15 @@
 	ASSERT(self->lap != NULL, return;);
 	ASSERT(self->lap->lsaps != NULL, return;);
 
-	lsap = hashbin_remove(self->lap->lsaps, (int) self, NULL);
+	lsap = hashbin_remove(self->lap->lsaps, (long) self, NULL);
 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
 	self->lap->cache.valid = FALSE;
 #endif
 
 	ASSERT(lsap != NULL, return;);
 	ASSERT(lsap == self, return;);
-	hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) lsap, (int) lsap,
-		       NULL);
+	hashbin_insert(irlmp->unconnected_lsaps, (irda_queue_t *) lsap,
+		       (long) lsap, NULL);
 
 	self->dlsap_sel = LSAP_ANY;
 	self->lap = NULL;
@@ -886,7 +900,7 @@
 	 */
 	while ((service = service_log[i++]) != S_END) {
 		IRDA_DEBUG( 4, "service=%02x\n", service);
-		client = hashbin_find(irlmp->registry, service, NULL);
+		client = hashbin_lock_find(irlmp->registry, service, NULL);
 		if (entry && entry->discovery_callback) {
 			IRDA_DEBUG( 4, "discovery_callback!\n");
 
@@ -903,6 +917,7 @@
 	kfree(service_log);
 }
 #endif
+
 /*
  * Function irlmp_notify_client (log)
  *
@@ -930,6 +945,12 @@
 	/*
 	 * Now, check all discovered devices (if any), and notify client
 	 * only about the services that the client is interested in
+	 * Note : most often, we will get called immediately following
+	 * a discovery, so the log is not going to expire.
+	 * On the other hand, comming here through irlmp_discovery_request()
+	 * is *very* problematic - Jean II
+	 * Can't use hashbin_find_next(), key is not unique. I'm running
+	 * out of options :-( - Jean II
 	 */
 	discovery = (discovery_t *) hashbin_get_first(log);
 	while (discovery != NULL) {
@@ -956,6 +977,7 @@
 void irlmp_discovery_confirm(hashbin_t *log, DISCOVERY_MODE mode)
 {
 	irlmp_client_t *client;
+	irlmp_client_t *client_next;
 
 	IRDA_DEBUG(3, __FUNCTION__ "()\n");
 
@@ -965,11 +987,12 @@
 		return;
 
 	client = (irlmp_client_t *) hashbin_get_first(irlmp->clients);
-	while (client != NULL) {
+	while (NULL != hashbin_find_next(irlmp->clients, (long) client, NULL,
+					 (void *) &client_next) ) {
 		/* Check if we should notify client */
 		irlmp_notify_client(client, log, mode);
 
-		client = (irlmp_client_t *) hashbin_get_next(irlmp->clients);
+		client = client_next;
 	}
 }
 
@@ -987,13 +1010,15 @@
 void irlmp_discovery_expiry(discovery_t *expiry)
 {
 	irlmp_client_t *client;
+	irlmp_client_t *client_next;
 
 	IRDA_DEBUG(3, __FUNCTION__ "()\n");
 
 	ASSERT(expiry != NULL, return;);
 
 	client = (irlmp_client_t *) hashbin_get_first(irlmp->clients);
-	while (client != NULL) {
+	while (NULL != hashbin_find_next(irlmp->clients, (long) client, NULL,
+					 (void *) &client_next) ) {
 		/* Check if we should notify client */
 		if ((client->expir_callback) &&
 		    (client->hint_mask & expiry->hints.word & 0x7f7f))
@@ -1001,7 +1026,7 @@
 					       client->priv);
 
 		/* Next client */
-		client = (irlmp_client_t *) hashbin_get_next(irlmp->clients);
+		client = client_next;
 	}
 }
 
@@ -1196,11 +1221,9 @@
 	struct lsap_cb *curr;
 
 	/* Send status_indication to all LSAPs using this link */
-	next = (struct lsap_cb *) hashbin_get_first( self->lsaps);
-	while (next != NULL ) {
-		curr = next;
-		next = (struct lsap_cb *) hashbin_get_next(self->lsaps);
-
+	curr = (struct lsap_cb *) hashbin_get_first( self->lsaps);
+	while (NULL != hashbin_find_next(self->lsaps, (long) curr, NULL,
+					 (void *) &next) ) {
 		ASSERT(curr->magic == LMP_LSAP_MAGIC, return;);
 		/*
 		 *  Inform service user if he has requested it
@@ -1210,6 +1233,8 @@
 						       link, lock);
 		else
 			IRDA_DEBUG(2, __FUNCTION__ "(), no handler\n");
+
+		curr = next;
 	}
 }
 
@@ -1245,29 +1270,15 @@
 	      (IRLAP_GET_TX_QUEUE_LEN(self->irlap) < LAP_HIGH_THRESHOLD)) {
 		/* Try to find the next lsap we should poll. */
 		next = self->flow_next;
-		if(next != NULL) {
-			/* Note that if there is only one LSAP on the LAP
-			 * (most common case), self->flow_next is always NULL,
-			 * so we always avoid this loop. - Jean II */
-			IRDA_DEBUG(4, __FUNCTION__ "() : searching my LSAP\n");
-
-			/* We look again in hashbins, because the lsap
-			 * might have gone away... - Jean II */
-			curr = (struct lsap_cb *) hashbin_get_first(self->lsaps);
-			while((curr != NULL ) && (curr != next))
-				curr = (struct lsap_cb *) hashbin_get_next(self->lsaps);
-		} else
-			curr = NULL;
-
 		/* If we have no lsap, restart from first one */
-		if(curr == NULL)
-			curr = (struct lsap_cb *) hashbin_get_first(self->lsaps);
+		if(next == NULL)
+			next = (struct lsap_cb *) hashbin_get_first(self->lsaps);
+		/* Verify current one and find the next one */
+		curr = hashbin_find_next(self->lsaps, (long) next, NULL,
+					 (void *) &self->flow_next);
 		/* Uh-oh... Paranoia */
 		if(curr == NULL)
 			break;
-
-		/* Next time, we will get the next one (or the first one) */
-		self->flow_next = (struct lsap_cb *) hashbin_get_next(self->lsaps);
 		IRDA_DEBUG(4, __FUNCTION__ "() : curr is %p, next was %p and is now %p, still %d to go - queue len = %d\n", curr, next, self->flow_next, lsap_todo, IRLAP_GET_TX_QUEUE_LEN(self->irlap));
 
 		/* Inform lsap user that it can send one more packet. */
@@ -1414,20 +1425,12 @@
  *    Register local service with IrLMP
  *
  */
-__u32 irlmp_register_service(__u16 hints)
+void *irlmp_register_service(__u16 hints)
 {
 	irlmp_service_t *service;
-	__u32 handle;
 
 	IRDA_DEBUG(4, __FUNCTION__ "(), hints = %04x\n", hints);
 
-	/* Get a unique handle for this service */
-	get_random_bytes(&handle, sizeof(handle));
-	while (hashbin_find(irlmp->services, handle, NULL) || !handle)
-		get_random_bytes(&handle, sizeof(handle));
-
-	irlmp->hints.word |= hints;
-
 	/* Make a new registration */
 	service = kmalloc(sizeof(irlmp_service_t), GFP_ATOMIC);
 	if (!service) {
@@ -1435,9 +1438,12 @@
 		return 0;
 	}
 	service->hints = hints;
-	hashbin_insert(irlmp->services, (irda_queue_t *) service, handle, NULL);
+	hashbin_insert(irlmp->services, (irda_queue_t *) service,
+		       (long) service, NULL);
+
+	irlmp->hints.word |= hints;
 
-	return handle;
+	return (void *)service;
 }
 
 /*
@@ -1447,35 +1453,38 @@
  *
  *    Returns: 0 on success, -1 on error
  */
-int irlmp_unregister_service(__u32 handle)
+int irlmp_unregister_service(void *handle)
 {
 	irlmp_service_t *service;
+	unsigned long flags;
 
 	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	if (!handle)
 		return -1;
 
-	service = hashbin_find(irlmp->services, handle, NULL);
+	/* Caller may call with invalid handle (it's legal) - Jean II */
+	service = hashbin_lock_find(irlmp->services, (long) handle, NULL);
 	if (!service) {
 		IRDA_DEBUG(1, __FUNCTION__ "(), Unknown service!\n");
 		return -1;
 	}
 
-	service = hashbin_remove(irlmp->services, handle, NULL);
-	if (service)
-		kfree(service);
+	hashbin_remove_this(irlmp->services, (irda_queue_t *) service);
+	kfree(service);
 
 	/* Remove old hint bits */
 	irlmp->hints.word = 0;
 
 	/* Refresh current hint bits */
+	spin_lock_irqsave(&irlmp->services->hb_spinlock, flags);
         service = (irlmp_service_t *) hashbin_get_first(irlmp->services);
         while (service) {
 		irlmp->hints.word |= service->hints;
 
                 service = (irlmp_service_t *)hashbin_get_next(irlmp->services);
         }
+	spin_unlock_irqrestore(&irlmp->services->hb_spinlock, flags);
 	return 0;
 }
 
@@ -1488,20 +1497,14 @@
  *
  *    Returns: handle > 0 on success, 0 on error
  */
-__u32 irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb,
+void *irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb,
 			    DISCOVERY_CALLBACK1 expir_clb, void *priv)
 {
 	irlmp_client_t *client;
-	__u32 handle;
 
 	IRDA_DEBUG(1, __FUNCTION__ "()\n");
 	ASSERT(irlmp != NULL, return 0;);
 
-	/* Get a unique handle for this client */
-	get_random_bytes(&handle, sizeof(handle));
-	while (hashbin_find(irlmp->clients, handle, NULL) || !handle)
-		get_random_bytes(&handle, sizeof(handle));
-
 	/* Make a new registration */
 	client = kmalloc(sizeof(irlmp_client_t), GFP_ATOMIC);
 	if (!client) {
@@ -1515,9 +1518,10 @@
 	client->expir_callback = expir_clb;
 	client->priv = priv;
 
-	hashbin_insert(irlmp->clients, (irda_queue_t *) client, handle, NULL);
+	hashbin_insert(irlmp->clients, (irda_queue_t *) client,
+		       (long) client, NULL);
 
-	return handle;
+	return (void *) client;
 }
 
 /*
@@ -1528,7 +1532,7 @@
  *
  *    Returns: 0 on success, -1 on error
  */
-int irlmp_update_client(__u32 handle, __u16 hint_mask,
+int irlmp_update_client(void *handle, __u16 hint_mask,
 			DISCOVERY_CALLBACK1 disco_clb,
 			DISCOVERY_CALLBACK1 expir_clb, void *priv)
 {
@@ -1537,7 +1541,7 @@
 	if (!handle)
 		return -1;
 
-	client = hashbin_find(irlmp->clients, handle, NULL);
+	client = hashbin_lock_find(irlmp->clients, (long) handle, NULL);
 	if (!client) {
 		IRDA_DEBUG(1, __FUNCTION__ "(), Unknown client!\n");
 		return -1;
@@ -1557,7 +1561,7 @@
  *    Returns: 0 on success, -1 on error
  *
  */
-int irlmp_unregister_client(__u32 handle)
+int irlmp_unregister_client(void *handle)
 {
 	struct irlmp_client *client;
 
@@ -1566,16 +1570,16 @@
 	if (!handle)
 		return -1;
 
-	client = hashbin_find(irlmp->clients, handle, NULL);
+	/* Caller may call with invalid handle (it's legal) - Jean II */
+	client = hashbin_lock_find(irlmp->clients, (long) handle, NULL);
 	if (!client) {
 		IRDA_DEBUG(1, __FUNCTION__ "(), Unknown client!\n");
 		return -1;
 	}
 
 	IRDA_DEBUG( 4, __FUNCTION__ "(), removing client!\n");
-	client = hashbin_remove( irlmp->clients, handle, NULL);
-	if (client)
-		kfree(client);
+	hashbin_remove_this(irlmp->clients, (irda_queue_t *) client);
+	kfree(client);
 
 	return 0;
 }
@@ -1589,6 +1593,7 @@
 {
 	struct lsap_cb *self;
 	struct lap_cb *lap;
+	unsigned long flags;
 
 	ASSERT(irlmp != NULL, return TRUE;);
 	ASSERT(irlmp->magic == LMP_MAGIC, return TRUE;);
@@ -1611,10 +1616,16 @@
 	 *  every IrLAP connection and check every LSAP assosiated with each
 	 *  the connection.
 	 */
+	spin_lock_irqsave(&irlmp->links->hb_spinlock, flags);
 	lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
 	while (lap != NULL) {
 		ASSERT(lap->magic == LMP_LAP_MAGIC, return TRUE;);
 
+		/* Careful for priority inversions here !
+		 * All other uses of attrib spinlock are independant of
+		 * the object spinlock, so we are safe. Jean II */
+		spin_lock(&lap->lsaps->hb_spinlock);
+
 		self = (struct lsap_cb *) hashbin_get_first(lap->lsaps);
 		while (self != NULL) {
 			ASSERT(self->magic == LMP_LSAP_MAGIC, return TRUE;);
@@ -1626,8 +1637,11 @@
 			}
 			self = (struct lsap_cb*) hashbin_get_next(lap->lsaps);
 		}
+		spin_unlock(&lap->lsaps->hb_spinlock);
+		/* Next LAP */
 		lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
 	}
+	spin_unlock_irqrestore(&irlmp->links->hb_spinlock, flags);
 	return FALSE;
 }
 
@@ -1736,15 +1750,13 @@
 
 	ASSERT(irlmp != NULL, return 0;);
 
-	save_flags( flags);
-	cli();
-
 	len = 0;
 
 	len += sprintf( buf+len, "Unconnected LSAPs:\n");
+	spin_lock_irqsave(&irlmp->unconnected_lsaps->hb_spinlock, flags);
 	self = (struct lsap_cb *) hashbin_get_first( irlmp->unconnected_lsaps);
 	while (self != NULL) {
-		ASSERT(self->magic == LMP_LSAP_MAGIC, return 0;);
+		ASSERT(self->magic == LMP_LSAP_MAGIC, break;);
 		len += sprintf(buf+len, "lsap state: %s, ",
 			       irlsap_state[ self->lsap_state]);
 		len += sprintf(buf+len,
@@ -1756,9 +1768,10 @@
 		self = (struct lsap_cb *) hashbin_get_next(
 			irlmp->unconnected_lsaps);
 	}
+	spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags);
 
 	len += sprintf(buf+len, "\nRegistred Link Layers:\n");
-
+	spin_lock_irqsave(&irlmp->links->hb_spinlock, flags);
 	lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
 	while (lap != NULL) {
 		len += sprintf(buf+len, "lap state: %s, ",
@@ -1770,10 +1783,15 @@
 			       HASHBIN_GET_SIZE(lap->lsaps));
 		len += sprintf(buf+len, "\n");
 
+		/* Careful for priority inversions here !
+		 * All other uses of attrib spinlock are independant of
+		 * the object spinlock, so we are safe. Jean II */
+		spin_lock(&lap->lsaps->hb_spinlock);
+
 		len += sprintf(buf+len, "\n  Connected LSAPs:\n");
 		self = (struct lsap_cb *) hashbin_get_first(lap->lsaps);
 		while (self != NULL) {
-			ASSERT(self->magic == LMP_LSAP_MAGIC, return 0;);
+			ASSERT(self->magic == LMP_LSAP_MAGIC, break;);
 			len += sprintf(buf+len, "  lsap state: %s, ",
 				       irlsap_state[ self->lsap_state]);
 			len += sprintf(buf+len,
@@ -1785,11 +1803,12 @@
 			self = (struct lsap_cb *) hashbin_get_next(
 				lap->lsaps);
 		}
+		spin_unlock(&lap->lsaps->hb_spinlock);
 		len += sprintf(buf+len, "\n");
 
 		lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&irlmp->links->hb_spinlock, flags);
 
 	return len;
 }
diff -Nru a/net/irda/irlmp_event.c b/net/irda/irlmp_event.c
--- a/net/irda/irlmp_event.c	Fri Sep 20 08:20:43 2002
+++ b/net/irda/irlmp_event.c	Fri Sep 20 08:20:43 2002
@@ -207,6 +207,43 @@
 	irlmp_do_lap_event(self, LM_LAP_IDLE_TIMEOUT, NULL);
 }
 
+/*
+ * Send an event on all LSAPs attached to this LAP.
+ */
+static inline void
+irlmp_do_all_lsap_event(hashbin_t *	lsap_hashbin,
+			IRLMP_EVENT	event)
+{
+	struct lsap_cb *lsap;
+	struct lsap_cb *lsap_next;
+
+	/* Note : this function use the new hashbin_find_next()
+	 * function, instead of the old hashbin_get_next().
+	 * This make sure that we are always pointing one lsap
+	 * ahead, so that if the current lsap is removed as the
+	 * result of sending the event, we don't care.
+	 * Also, as we store the context ourselves, if an enumeration
+	 * of the same lsap hashbin happens as the result of sending the
+	 * event, we don't care.
+	 * The only problem is if the next lsap is removed. In that case,
+	 * hashbin_find_next() will return NULL and we will abort the
+	 * enumeration. - Jean II */
+
+	/* Also : we don't accept any skb in input. We can *NOT* pass
+	 * the same skb to multiple clients safely, we would need to
+	 * skb_clone() it. - Jean II */
+
+	lsap = (struct lsap_cb *) hashbin_get_first(lsap_hashbin);
+
+	while (NULL != hashbin_find_next(lsap_hashbin,
+					 (long) lsap,
+					 NULL,
+					 (void *) &lsap_next) ) {
+		irlmp_do_lsap_event(lsap, event, NULL);
+		lsap = lsap_next;
+	}
+}
+
 /*********************************************************************
  *
  *    LAP connection control states
@@ -274,9 +311,6 @@
 static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event,
 				  struct sk_buff *skb)
 {
-	struct lsap_cb *lsap;
-	struct lsap_cb *lsap_current;
-
 	IRDA_DEBUG(2, __FUNCTION__ "(), event=%s\n", irlmp_event[event]);
 
 	switch (event) {
@@ -290,11 +324,9 @@
 		/* Just accept connection TODO, this should be fixed */
 		irlap_connect_response(self->irlap, skb);
 
-		lsap = (struct lsap_cb *) hashbin_get_first(self->lsaps);
-		while (lsap != NULL) {
-			irlmp_do_lsap_event(lsap, LM_LAP_CONNECT_CONFIRM, NULL);
-			lsap = (struct lsap_cb*) hashbin_get_next(self->lsaps);
-		}
+		/* Tell LSAPs that they can start sending data */
+		irlmp_do_all_lsap_event(self->lsaps, LM_LAP_CONNECT_CONFIRM);
+
 		/* Note : by the time we get there (LAP retries and co),
 		 * the lsaps may already have gone. This avoid getting stuck
 		 * forever in LAP_ACTIVE state - Jean II */
@@ -310,11 +342,9 @@
 		/* For all lsap_ce E Associated do LS_Connect_confirm */
 		irlmp_next_lap_state(self, LAP_ACTIVE);
 
-		lsap = (struct lsap_cb *) hashbin_get_first(self->lsaps);
-		while (lsap != NULL) {
-			irlmp_do_lsap_event(lsap, LM_LAP_CONNECT_CONFIRM, NULL);
-			lsap = (struct lsap_cb*) hashbin_get_next(self->lsaps);
-		}
+		/* Tell LSAPs that they can start sending data */
+		irlmp_do_all_lsap_event(self->lsaps, LM_LAP_CONNECT_CONFIRM);
+
 		/* Note : by the time we get there (LAP retries and co),
 		 * the lsaps may already have gone. This avoid getting stuck
 		 * forever in LAP_ACTIVE state - Jean II */
@@ -328,18 +358,8 @@
 		irlmp_next_lap_state(self, LAP_STANDBY);
 
 		/* Send disconnect event to all LSAPs using this link */
-		lsap = (struct lsap_cb *) hashbin_get_first( self->lsaps);
-		while (lsap != NULL ) {
-			ASSERT(lsap->magic == LMP_LSAP_MAGIC, return;);
-
-			lsap_current = lsap;
-
-			/* Be sure to stay one item ahead */
-			lsap = (struct lsap_cb *) hashbin_get_next(self->lsaps);
-			irlmp_do_lsap_event(lsap_current,
-					    LM_LAP_DISCONNECT_INDICATION,
-					    NULL);
-		}
+		irlmp_do_all_lsap_event(self->lsaps,
+					LM_LAP_DISCONNECT_INDICATION);
 		break;
 	case LM_LAP_DISCONNECT_REQUEST:
 		IRDA_DEBUG(4, __FUNCTION__ "(), LM_LAP_DISCONNECT_REQUEST\n");
@@ -368,9 +388,6 @@
 static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event,
 			       struct sk_buff *skb)
 {
-	struct lsap_cb *lsap;
-	struct lsap_cb *lsap_current;
-
 	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
 	switch (event) {
@@ -383,22 +400,11 @@
 		 *  notify all LSAPs using this LAP, but that should be safe to
 		 *  do anyway.
 		 */
-		lsap = (struct lsap_cb *) hashbin_get_first(self->lsaps);
-		while (lsap != NULL) {
-			irlmp_do_lsap_event(lsap, LM_LAP_CONNECT_CONFIRM, NULL);
-			lsap = (struct lsap_cb*) hashbin_get_next(self->lsaps);
-		}
+		irlmp_do_all_lsap_event(self->lsaps, LM_LAP_CONNECT_CONFIRM);
 
 		/* Needed by connect indication */
-		lsap = (struct lsap_cb *) hashbin_get_first(irlmp->unconnected_lsaps);
-		while (lsap != NULL) {
-			lsap_current = lsap;
-
-			/* Be sure to stay one item ahead */
-			lsap = (struct lsap_cb*) hashbin_get_next(irlmp->unconnected_lsaps);
-			irlmp_do_lsap_event(lsap_current,
-					    LM_LAP_CONNECT_CONFIRM, NULL);
-		}
+		irlmp_do_all_lsap_event(irlmp->unconnected_lsaps,
+					LM_LAP_CONNECT_CONFIRM);
 		/* Keep state */
 		break;
 	case LM_LAP_DISCONNECT_REQUEST:
@@ -447,18 +453,8 @@
 		/*
 		 *  Inform all connected LSAP's using this link
 		 */
-		lsap = (struct lsap_cb *) hashbin_get_first(self->lsaps);
-		while (lsap != NULL ) {
-			ASSERT(lsap->magic == LMP_LSAP_MAGIC, return;);
-
-			lsap_current = lsap;
-
-			/* Be sure to stay one item ahead */
-			lsap = (struct lsap_cb *) hashbin_get_next(self->lsaps);
-			irlmp_do_lsap_event(lsap_current,
-					    LM_LAP_DISCONNECT_INDICATION,
-					    NULL);
-		}
+		irlmp_do_all_lsap_event(self->lsaps,
+					LM_LAP_DISCONNECT_INDICATION);
 
 		/* Force an expiry of the discovery log.
 		 * Now that the LAP is free, the system may attempt to
@@ -581,15 +577,15 @@
 		 *  Bind this LSAP to the IrLAP link where the connect was
 		 *  received
 		 */
-		lsap = hashbin_remove(irlmp->unconnected_lsaps, (int) self,
+		lsap = hashbin_remove(irlmp->unconnected_lsaps, (long) self,
 				      NULL);
 
 		ASSERT(lsap == self, return -1;);
 		ASSERT(self->lap != NULL, return -1;);
 		ASSERT(self->lap->lsaps != NULL, return -1;);
 
-		hashbin_insert(self->lap->lsaps, (irda_queue_t *) self, (int) self,
-			       NULL);
+		hashbin_insert(self->lap->lsaps, (irda_queue_t *) self,
+			       (long) self, NULL);
 
 		irlmp_send_lcf_pdu(self->lap, self->dlsap_sel,
 				   self->slsap_sel, CONNECT_CNF, skb);
diff -Nru a/net/irda/irlmp_frame.c b/net/irda/irlmp_frame.c
--- a/net/irda/irlmp_frame.c	Fri Sep 20 08:20:47 2002
+++ b/net/irda/irlmp_frame.c	Fri Sep 20 08:20:47 2002
@@ -210,6 +210,7 @@
 	__u8   dlsap_sel;   /* Destination LSAP address */
 	__u8   pid;         /* Protocol identifier */
 	__u8   *fp;
+	unsigned long flags;
 	
 	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 
@@ -242,6 +243,8 @@
 		return;
 	}
 	
+	/* Search the connectionless LSAP */
+	spin_lock_irqsave(&irlmp->unconnected_lsaps->hb_spinlock, flags);
 	lsap = (struct lsap_cb *) hashbin_get_first(irlmp->unconnected_lsaps);
 	while (lsap != NULL) {
 		/*
@@ -255,6 +258,8 @@
 		}
 		lsap = (struct lsap_cb *) hashbin_get_next(irlmp->unconnected_lsaps);
 	}
+	spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags);
+
 	if (lsap)
 		irlmp_connless_data_indication(lsap, skb);
 	else {
@@ -374,6 +379,7 @@
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
 
+	/* Add to main log, cleanup */
 	irlmp_add_discovery(irlmp->cachelog, discovery);
 	
 	/* Just handle it the same way as a discovery confirm,
@@ -396,6 +402,7 @@
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
 	
+	/* Add to main log, cleanup */
 	irlmp_add_discovery_log(irlmp->cachelog, log);
 
 	/* Propagate event to various LSAPs registered for it.
@@ -411,6 +418,8 @@
 static inline void irlmp_update_cache(struct lap_cb *lap,
 				      struct lsap_cb *lsap)
 {
+	/* Prevent concurent read to get garbage */
+	lap->cache.valid = FALSE;
 	/* Update cache entry */
 	lap->cache.dlsap_sel = lsap->dlsap_sel;
 	lap->cache.slsap_sel = lsap->slsap_sel;
@@ -441,6 +450,7 @@
 				       hashbin_t *queue) 
 {
 	struct lsap_cb *lsap;
+	unsigned long flags;
 	
 	/* 
 	 *  Optimize for the common case. We assume that the last frame
@@ -455,6 +465,9 @@
 		return (self->cache.lsap);
 	}
 #endif
+
+	spin_lock_irqsave(&queue->hb_spinlock, flags);
+
 	lsap = (struct lsap_cb *) hashbin_get_first(queue);
 	while (lsap != NULL) {
 		/* 
@@ -465,29 +478,27 @@
 		 */
 		if ((status == CONNECT_CMD) && 
 		    (lsap->slsap_sel == slsap_sel) &&      
-		    (lsap->dlsap_sel == LSAP_ANY)) 
-		{
+		    (lsap->dlsap_sel == LSAP_ANY)) {
+			/* This is where the dest lsap sel is set on incomming
+			 * lsaps */
 			lsap->dlsap_sel = dlsap_sel;
-			
-#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
-			irlmp_update_cache(self, lsap);
-#endif
-			return lsap;
+			break;
 		}
 		/*
 		 *  Check if source LSAP and dest LSAP selectors match.
 		 */
 		if ((lsap->slsap_sel == slsap_sel) && 
 		    (lsap->dlsap_sel == dlsap_sel)) 
-		{
-#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
-			irlmp_update_cache(self, lsap);
-#endif
-			return lsap;
-		}
+			break;
+
 		lsap = (struct lsap_cb *) hashbin_get_next(queue);
 	}
+#ifdef CONFIG_IRDA_CACHE_LAST_LSAP
+	if(lsap)
+		irlmp_update_cache(self, lsap);
+#endif
+	spin_unlock_irqrestore(&queue->hb_spinlock, flags);
 
-	/* Sorry not found! */
-	return NULL;
+	/* Return what we've found or NULL */
+	return lsap;
 }
diff -Nru a/net/irda/irqueue.c b/net/irda/irqueue.c
--- a/net/irda/irqueue.c	Fri Sep 20 08:20:43 2002
+++ b/net/irda/irqueue.c	Fri Sep 20 08:20:43 2002
@@ -34,11 +34,412 @@
  *     
  ********************************************************************/
 
+/*
+ * NOTE :
+ * There are various problems with this package :
+ *	o the hash function for ints is pathetic (but could be changed)
+ *	o locking is sometime suspicious (especially during enumeration)
+ *	o most users have only a few elements (== overhead)
+ *	o most users never use seach, so don't benefit from hashing
+ * Problem already fixed :
+ *	o not 64 bit compliant (most users do hashv = (int) self)
+ *	o hashbin_remove() is broken => use hashbin_remove_this()
+ * I think most users would be better served by a simple linked list
+ * (like include/linux/list.h) with a global spinlock per list.
+ * Jean II
+ */
+
+/*
+ * Notes on the concurent access to hashbin and other SMP issues
+ * -------------------------------------------------------------
+ *	Hashbins are very often in the IrDA stack a global repository of
+ * information, and therefore used in a very asynchronous manner following
+ * various events (driver calls, timers, user calls...).
+ *	Therefore, very often it is highly important to consider the
+ * management of concurent access to the hashbin and how to guarantee the
+ * consistency of the operations on it.
+ *
+ *	First, we need to define the objective of locking :
+ *		1) Protect user data (content pointed by the hashbin)
+ *		2) Protect hashbin structure itself (linked list in each bin)
+ *
+ *			     OLD LOCKING
+ *			     -----------
+ *
+ *	The previous locking strategy, either HB_LOCAL or HB_GLOBAL were
+ * both inadequate in *both* aspect.
+ *		o HB_GLOBAL was using a spinlock for each bin (local locking).
+ *		o HB_LOCAL was disabling irq on *all* CPUs, so use a single
+ *		  global semaphore.
+ *	The problems were :
+ *		A) Global irq disabling is no longer supported by the kernel
+ *		B) No protection for the hashbin struct global data
+ *			o hashbin_delete()
+ *			o hb_current
+ *		C) No protection for user data in some cases
+ *
+ *	A) HB_LOCAL use global irq disabling, so doesn't work on kernel
+ * 2.5.X. Even when it is supported (kernel 2.4.X and earlier), its
+ * performance is not satisfactory on SMP setups. Most hashbins were
+ * HB_LOCAL, so (A) definitely need fixing.
+ *	B) HB_LOCAL could be modified to fix (B). However, because HB_GLOBAL
+ * lock only the individual bins, it will never be able to lock the
+ * global data, so can't do (B).
+ *	C) Some functions return pointer to data that is still in the
+ * hashbin :
+ *		o hashbin_find()
+ *		o hashbin_get_first()
+ *		o hashbin_get_next()
+ *	As the data is still in the hashbin, it may be changed or free'd
+ * while the caller is examinimg the data. In those case, locking can't
+ * be done within the hashbin, but must include use of the data within
+ * the caller.
+ *	The caller can easily do this with HB_LOCAL (just disable irqs).
+ * However, this is impossible with HB_GLOBAL because the caller has no
+ * way to know the proper bin, so don't know which spinlock to use.
+ *
+ *	Quick summary : can no longer use HB_LOCAL, and HB_GLOBAL is
+ * fundamentally broken and will never work.
+ *
+ *			     NEW LOCKING
+ *			     -----------
+ *
+ *	To fix those problems, I've introduce a few changes in the
+ * hashbin locking :
+ *		1) New HB_LOCK scheme
+ *		2) hashbin->hb_spinlock
+ *		3) New hashbin usage policy
+ *
+ * HB_LOCK :
+ * -------
+ *	HB_LOCK is a locking scheme intermediate between the old HB_LOCAL
+ * and HB_GLOBAL. It uses a single spinlock to protect the whole content
+ * of the hashbin. As it is a single spinlock, it can protect the global
+ * data of the hashbin and not only the bins themselves.
+ *	HB_LOCK can only protect some of the hashbin calls, so it only lock
+ * call that can be made 100% safe and leave other call unprotected.
+ *	HB_LOCK in theory is slower than HB_GLOBAL, but as the hashbin
+ * content is always small contention is not high, so it doesn't matter
+ * much. HB_LOCK is probably faster than HB_LOCAL.
+ *
+ * hashbin->hb_spinlock :
+ * --------------------
+ *	The spinlock that HB_LOCK uses is available for caller, so that
+ * the caller can protect unprotected calls (see below).
+ *	If the caller want to do entirely its own locking (HB_NOLOCK), he
+ * can do so and may use safely this spinlock.
+ *	Locking is done like this :
+ *		spin_lock_irqsave(&hashbin->hb_spinlock, flags);
+ *	Releasing the lock :
+ *		spin_unlock_irqrestore(&hashbin->hb_spinlock, flags);
+ *
+ * Safe & Protected calls :
+ * ----------------------
+ *	The following calls are safe or protected via HB_LOCK :
+ *		o hashbin_new()		-> safe
+ *		o hashbin_delete()
+ *		o hashbin_insert()
+ *		o hashbin_remove_first()
+ *		o hashbin_remove()
+ *		o hashbin_remove_this()
+ *		o HASHBIN_GET_SIZE()	-> atomic
+ *
+ *	The following calls only protect the hashbin itself :
+ *		o hashbin_lock_find()
+ *		o hashbin_find_next()
+ *
+ * Unprotected calls :
+ * -----------------
+ *	The following calls need to be protected by the caller :
+ *		o hashbin_find()
+ *		o hashbin_get_first()
+ *		o hashbin_get_next()
+ *
+ * Locking Policy :
+ * --------------
+ *	If the hashbin is used only in a single thread of execution
+ * (explicitely or implicitely), you can use HB_NOLOCK
+ *	If the calling module already provide concurent access protection,
+ * you may use HB_NOLOCK.
+ *
+ *	In all other cases, you need to use HB_LOCK and lock the hashbin
+ * everytime before calling one of the unprotected calls. You also must
+ * use the pointer returned by the unprotected call within the locked
+ * region.
+ *
+ * Extra care for enumeration :
+ * --------------------------
+ *	hashbin_get_first() and hashbin_get_next() use the hashbin to
+ * store the current position, in hb_current.
+ *	As long as the hashbin remains locked, this is safe. If you unlock
+ * the hashbin, the current position may change if anybody else modify
+ * or enumerate the hashbin.
+ *	Summary : do the full enumeration while locked.
+ *
+ *	Alternatively, you may use hashbin_find_next(). But, this will
+ * be slower, is more complex to use and doesn't protect the hashbin
+ * content. So, care is needed here as well.
+ *
+ * Other issues :
+ * ------------
+ *	I believe that we are overdoing it by using spin_lock_irqsave()
+ * and we should use only spin_lock_bh() or similar. But, I don't have
+ * the balls to try it out.
+ *	Don't believe that because hashbin are now (somewhat) SMP safe
+ * that the rest of the code is. Higher layers tend to be safest,
+ * but LAP and LMP would need some serious dedicated love.
+ *
+ * Jean II
+ */
+
 #include <net/irda/irda.h>
 #include <net/irda/irqueue.h>
 
-static irda_queue_t *dequeue_general( irda_queue_t **queue, irda_queue_t* element);
-static __u32 hash( char* name);
+/************************ QUEUE SUBROUTINES ************************/
+
+/*
+ * Hashbin
+ */
+#define GET_HASHBIN(x) ( x & HASHBIN_MASK )
+
+/*
+ * Function hash (name)
+ *
+ *    This function hash the input string 'name' using the ELF hash
+ *    function for strings.
+ */
+static __u32 hash( char* name)
+{
+	__u32 h = 0;
+	__u32 g;
+	
+	while(*name) {
+		h = (h<<4) + *name++;
+		if ((g = (h & 0xf0000000)))
+			h ^=g>>24;
+		h &=~g;
+	}
+	return h;
+}
+
+/*
+ * Function enqueue_first (queue, proc)
+ *
+ *    Insert item first in queue.
+ *
+ */
+static void enqueue_first(irda_queue_t **queue, irda_queue_t* element)
+{
+	
+	IRDA_DEBUG( 4, __FUNCTION__ "()\n");
+
+	/*
+	 * Check if queue is empty.
+	 */
+	if ( *queue == NULL ) {
+		/*
+		 * Queue is empty.  Insert one element into the queue.
+		 */
+		element->q_next = element->q_prev = *queue = element;
+		
+	} else {
+		/*
+		 * Queue is not empty.  Insert element into front of queue.
+		 */
+		element->q_next          = (*queue);
+		(*queue)->q_prev->q_next = element;
+		element->q_prev          = (*queue)->q_prev;
+		(*queue)->q_prev         = element;
+		(*queue)                 = element;
+	}
+}
+
+#ifdef HASHBIN_UNUSED
+/*
+ * Function enqueue_last (queue, proc)
+ *
+ *    Insert item into end of queue.
+ *
+ */
+static void __enqueue_last( irda_queue_t **queue, irda_queue_t* element)
+{
+	IRDA_DEBUG( 4, __FUNCTION__ "()\n");
+
+	/*
+	 * Check if queue is empty.
+	 */
+	if ( *queue == NULL ) {
+		/*
+		 * Queue is empty.  Insert one element into the queue.
+		 */
+		element->q_next = element->q_prev = *queue = element;
+		
+	} else {
+		/*
+		 * Queue is not empty.  Insert element into end of queue.
+		 */
+		element->q_prev         = (*queue)->q_prev;
+		element->q_prev->q_next = element;
+		(*queue)->q_prev        = element;
+		element->q_next         = *queue;
+	}	
+}
+
+static inline void enqueue_last( irda_queue_t **queue, irda_queue_t* element)
+{
+	unsigned long flags;
+	
+        save_flags(flags);
+        cli();
+
+        __enqueue_last( queue, element);
+
+        restore_flags(flags);
+}
+
+/*
+ * Function enqueue_queue (queue, list)
+ *
+ *    Insert a queue (list) into the start of the first queue
+ *
+ */
+static void enqueue_queue( irda_queue_t** queue, irda_queue_t** list )
+{
+	irda_queue_t* tmp;
+	
+	/*
+	 * Check if queue is empty
+	 */ 
+	if ( *queue ) {
+		(*list)->q_prev->q_next  = (*queue);
+		(*queue)->q_prev->q_next = (*list); 
+		tmp                      = (*list)->q_prev;
+		(*list)->q_prev          = (*queue)->q_prev;
+		(*queue)->q_prev         = tmp;
+	} else {
+		*queue                   = (*list); 
+	}
+	
+	(*list) = NULL;
+}
+
+/*
+ * Function enqueue_second (queue, proc)
+ *
+ *    Insert item behind head of queue.
+ *
+ */
+static void enqueue_second(irda_queue_t **queue, irda_queue_t* element)
+{
+	IRDA_DEBUG( 0, "enqueue_second()\n");
+
+	/*
+	 * Check if queue is empty.
+	 */
+	if ( *queue == NULL ) {
+		/*
+		 * Queue is empty.  Insert one element into the queue.
+		 */
+		element->q_next = element->q_prev = *queue = element;
+		
+	} else {
+		/*
+		 * Queue is not empty.  Insert element into ..
+		 */
+		element->q_prev = (*queue);
+		(*queue)->q_next->q_prev = element;
+		element->q_next = (*queue)->q_next;
+		(*queue)->q_next = element;
+	}
+}
+#endif /* HASHBIN_UNUSED */
+
+/*
+ * Function dequeue (queue)
+ *
+ *    Remove first entry in queue
+ *
+ */
+static irda_queue_t *dequeue_first(irda_queue_t **queue)
+{
+	irda_queue_t *ret;
+
+	IRDA_DEBUG( 4, "dequeue_first()\n");
+	
+	/*
+	 * Set return value
+	 */
+	ret =  *queue;
+	
+	if ( *queue == NULL ) {
+		/*
+		 * Queue was empty.
+		 */
+	} else if ( (*queue)->q_next == *queue ) {
+		/* 
+		 *  Queue only contained a single element. It will now be
+		 *  empty.  
+		 */
+		*queue = NULL;
+	} else {
+		/*
+		 * Queue contained several element.  Remove the first one.
+		 */
+		(*queue)->q_prev->q_next = (*queue)->q_next;
+		(*queue)->q_next->q_prev = (*queue)->q_prev;
+		*queue = (*queue)->q_next;
+	}
+	
+	/*
+	 * Return the removed entry (or NULL of queue was empty).
+	 */
+	return ret;
+}
+
+/*
+ * Function dequeue_general (queue, element)
+ *
+ *
+ */
+static irda_queue_t *dequeue_general(irda_queue_t **queue, irda_queue_t* element)
+{
+	irda_queue_t *ret;
+	
+	IRDA_DEBUG( 4, "dequeue_general()\n");
+	
+	/*
+	 * Set return value
+	 */
+	ret =  *queue;
+		
+	if ( *queue == NULL ) {
+		/*
+		 * Queue was empty.
+		 */
+	} else if ( (*queue)->q_next == *queue ) {
+		/* 
+		 *  Queue only contained a single element. It will now be
+		 *  empty.  
+		 */
+		*queue = NULL;
+		
+	} else {
+		/*
+		 *  Remove specific element.
+		 */
+		element->q_prev->q_next = element->q_next;
+		element->q_next->q_prev = element->q_prev;
+		if ( (*queue) == element)
+			(*queue) = element->q_next;
+	}
+	
+	/*
+	 * Return the removed entry (or NULL of queue was empty).
+	 */
+	return ret;
+}
+
+/************************ HASHBIN MANAGEMENT ************************/
 
 /*
  * Function hashbin_create ( type, name )
@@ -49,7 +450,6 @@
 hashbin_t *hashbin_new(int type)
 {
 	hashbin_t* hashbin;
-	int i;
 	
 	/*
 	 * Allocate new hashbin
@@ -64,14 +464,17 @@
 	memset(hashbin, 0, sizeof(hashbin_t));
 	hashbin->hb_type = type;
 	hashbin->magic = HB_MAGIC;
+	//hashbin->hb_current = NULL;
 
 	/* Make sure all spinlock's are unlocked */
-	for (i=0;i<HASHBIN_SIZE;i++)
-		hashbin->hb_mutex[i] = SPIN_LOCK_UNLOCKED;
-	
+	if ( hashbin->hb_type & HB_LOCK ) {
+		spin_lock_init(&hashbin->hb_spinlock);
+	}
+
 	return hashbin;
 }
 
+#ifdef HASHBIN_UNUSED
 /*
  * Function hashbin_clear (hashbin, free_func)
  *
@@ -102,7 +505,7 @@
 
 	return 0;
 }
-
+#endif /* HASHBIN_UNUSED */
 
 /*
  * Function hashbin_delete (hashbin, free_func)
@@ -114,11 +517,17 @@
 int hashbin_delete( hashbin_t* hashbin, FREE_FUNC free_func)
 {
 	irda_queue_t* queue;
+	unsigned long flags = 0;
 	int i;
 
 	ASSERT(hashbin != NULL, return -1;);
 	ASSERT(hashbin->magic == HB_MAGIC, return -1;);
 	
+	/* Synchronize */
+	if ( hashbin->hb_type & HB_LOCK ) {
+		spin_lock_irqsave(&hashbin->hb_spinlock, flags);
+	}
+
 	/*
 	 *  Free the entries in the hashbin, TODO: use hashbin_clear when
 	 *  it has been shown to work
@@ -133,22 +542,32 @@
 		}
 	}
 	
+	/* Cleanup local data */
+	hashbin->hb_current = NULL;
+	hashbin->magic = ~HB_MAGIC;
+
+	/* Release lock */
+	if ( hashbin->hb_type & HB_LOCK) {
+		spin_unlock_irqrestore(&hashbin->hb_spinlock, flags);
+	}
+
 	/*
 	 *  Free the hashbin structure
 	 */
-	hashbin->magic = ~HB_MAGIC;
 	kfree(hashbin);
 
 	return 0;
 }
 
+/********************* HASHBIN LIST OPERATIONS *********************/
+
 /*
  * Function hashbin_insert (hashbin, entry, name)
  *
  *    Insert an entry into the hashbin
  *
  */
-void hashbin_insert(hashbin_t* hashbin, irda_queue_t* entry, __u32 hashv, char* name)
+void hashbin_insert(hashbin_t* hashbin, irda_queue_t* entry, long hashv, char* name)
 {
 	unsigned long flags = 0;
 	int bin;
@@ -166,12 +585,8 @@
 	bin = GET_HASHBIN( hashv );
 
 	/* Synchronize */
-	if ( hashbin->hb_type & HB_GLOBAL ) {
-		spin_lock_irqsave( &hashbin->hb_mutex[ bin ], flags);
-
-	} else if ( hashbin->hb_type & HB_LOCAL ) {
-		save_flags(flags);
-		cli();
+	if ( hashbin->hb_type & HB_LOCK ) {
+		spin_lock_irqsave(&hashbin->hb_spinlock, flags);
 	} /* Default is no-lock  */
 	
 	/*
@@ -194,102 +609,61 @@
 	hashbin->hb_size++;
 
 	/* Release lock */
-	if ( hashbin->hb_type & HB_GLOBAL) {
-
-		spin_unlock_irqrestore( &hashbin->hb_mutex[ bin], flags);
-
-	} else if ( hashbin->hb_type & HB_LOCAL) {
-		restore_flags( flags);
-	}
+	if ( hashbin->hb_type & HB_LOCK ) {
+		spin_unlock_irqrestore(&hashbin->hb_spinlock, flags);
+	} /* Default is no-lock  */
 }
 
-/*
- * Function hashbin_find (hashbin, hashv, name)
+/* 
+ *  Function hashbin_remove_first (hashbin)
  *
- *    Find item with the given hashv or name
+ *    Remove first entry of the hashbin
  *
+ * Note : this function no longer use hashbin_remove(), but does things
+ * similar to hashbin_remove_this(), so can be considered safe.
+ * Jean II
  */
-void* hashbin_find( hashbin_t* hashbin, __u32 hashv, char* name )
+void *hashbin_remove_first( hashbin_t *hashbin)
 {
-	int bin, found = FALSE;
 	unsigned long flags = 0;
-	irda_queue_t* entry;
-
-	IRDA_DEBUG( 4, "hashbin_find()\n");
-
-	ASSERT( hashbin != NULL, return NULL;);
-	ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
+	irda_queue_t *entry = NULL;
 
-	/*
-	 * Locate hashbin
-	 */
-	if ( name )
-		hashv = hash( name );
-	bin = GET_HASHBIN( hashv );
-	
 	/* Synchronize */
-	if ( hashbin->hb_type & HB_GLOBAL ) {
-		spin_lock_irqsave( &hashbin->hb_mutex[ bin ], flags);
-
-	} else if ( hashbin->hb_type & HB_LOCAL ) {
-		save_flags(flags);
-		cli();
+	if ( hashbin->hb_type & HB_LOCK ) {
+		spin_lock_irqsave(&hashbin->hb_spinlock, flags);
 	} /* Default is no-lock  */
-	
-	/*
-	 * Search for entry
-	 */
-	entry = hashbin->hb_queue[ bin];
-	if ( entry ) {
-		do {
-			/*
-			 * Check for key
-			 */
-			if ( entry->q_hash == hashv ) {
-				/*
-				 * Name compare too?
-				 */
-				if ( name ) {
-					if ( strcmp( entry->q_name, name ) == 0 ) {
-						found = TRUE;
-						break;
-					}
-				} else {
-					found = TRUE;
-					break;
-				}
-			}
-			entry = entry->q_next;
-		} while ( entry != hashbin->hb_queue[ bin ] );
-	}
-	
-	/* Release lock */
-	if ( hashbin->hb_type & HB_GLOBAL) {
-		spin_unlock_irqrestore( &hashbin->hb_mutex[ bin], flags);
-
-	} else if ( hashbin->hb_type & HB_LOCAL) {
-		restore_flags( flags);
-	}
-	
-	if ( found ) 
-		return entry;
-	else
-		return NULL;
-}
 
-void *hashbin_remove_first( hashbin_t *hashbin)
-{
-	unsigned long flags;
-	irda_queue_t *entry = NULL;
+	entry = hashbin_get_first( hashbin);
+	if ( entry != NULL) {
+		int	bin;
+		long	hashv;
+		/*
+		 * Locate hashbin
+		 */
+		hashv = entry->q_hash;
+		bin = GET_HASHBIN( hashv );
 
-	save_flags(flags);
-	cli();
+		/*
+		 * Dequeue the entry...
+		 */
+		dequeue_general( (irda_queue_t**) &hashbin->hb_queue[ bin ],
+				 (irda_queue_t*) entry );
+		hashbin->hb_size--;
+		entry->q_next = NULL;
+		entry->q_prev = NULL;
 
-	entry = hashbin_get_first( hashbin);
-	if ( entry != NULL)
-		hashbin_remove( hashbin, entry->q_hash, NULL);
+		/*
+		 *  Check if this item is the currently selected item, and in
+		 *  that case we must reset hb_current
+		 */
+		if ( entry == hashbin->hb_current)
+			hashbin->hb_current = NULL;
+	}
 
-	restore_flags( flags);
+	/* Release lock */
+	if ( hashbin->hb_type & HB_LOCK ) {
+		spin_unlock_irqrestore(&hashbin->hb_spinlock, flags);
+	} /* Default is no-lock  */
 
 	return entry;
 }
@@ -300,8 +674,16 @@
  *
  *    Remove entry with the given name
  *
+ *  The use of this function is highly discouraged, because the whole
+ *  concept behind hashbin_remove() is broken. In many cases, it's not
+ *  possible to guarantee the unicity of the index (either hashv or name),
+ *  leading to removing the WRONG entry.
+ *  The only simple safe use is :
+ *		hashbin_remove(hasbin, (int) self, NULL);
+ *  In other case, you must think hard to guarantee unicity of the index.
+ *  Jean II
  */
-void* hashbin_remove( hashbin_t* hashbin, __u32 hashv, char* name)
+void* hashbin_remove( hashbin_t* hashbin, long hashv, char* name)
 {
 	int bin, found = FALSE;
 	unsigned long flags = 0;
@@ -320,12 +702,8 @@
 	bin = GET_HASHBIN( hashv );
 
 	/* Synchronize */
-	if ( hashbin->hb_type & HB_GLOBAL ) {
-		spin_lock_irqsave( &hashbin->hb_mutex[ bin ], flags);
-
-	} else if ( hashbin->hb_type & HB_LOCAL ) {
-		save_flags(flags);
-		cli();
+	if ( hashbin->hb_type & HB_LOCK ) {
+		spin_lock_irqsave(&hashbin->hb_spinlock, flags);
 	} /* Default is no-lock  */
 
 	/*
@@ -373,12 +751,9 @@
 	}
 
 	/* Release lock */
-	if ( hashbin->hb_type & HB_GLOBAL) {
-		spin_unlock_irqrestore( &hashbin->hb_mutex[ bin], flags);
-
-	} else if ( hashbin->hb_type & HB_LOCAL) {
-		restore_flags( flags);
-	}
+	if ( hashbin->hb_type & HB_LOCK ) {
+		spin_unlock_irqrestore(&hashbin->hb_spinlock, flags);
+	} /* Default is no-lock  */
        
 	
 	/* Return */
@@ -390,7 +765,7 @@
 }
 
 /* 
- *  Function hashbin_remove (hashbin, hashv, name)
+ *  Function hashbin_remove_this (hashbin, entry)
  *
  *    Remove entry with the given name
  *
@@ -404,7 +779,7 @@
 {
 	unsigned long flags = 0;
 	int	bin;
-	__u32	hashv;
+	long	hashv;
 
 	IRDA_DEBUG( 4, __FUNCTION__ "()\n");
 
@@ -412,6 +787,11 @@
 	ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
 	ASSERT( entry != NULL, return NULL;);
 	
+	/* Synchronize */
+	if ( hashbin->hb_type & HB_LOCK ) {
+		spin_lock_irqsave(&hashbin->hb_spinlock, flags);
+	} /* Default is no-lock  */
+
 	/* Check if valid and not already removed... */
 	if((entry->q_next == NULL) || (entry->q_prev == NULL))
 		return NULL;
@@ -422,15 +802,6 @@
 	hashv = entry->q_hash;
 	bin = GET_HASHBIN( hashv );
 
-	/* Synchronize */
-	if ( hashbin->hb_type & HB_GLOBAL ) {
-		spin_lock_irqsave( &hashbin->hb_mutex[ bin ], flags);
-
-	} else if ( hashbin->hb_type & HB_LOCAL ) {
-		save_flags(flags);
-		cli();
-	} /* Default is no-lock  */
-
 	/*
 	 * Dequeue the entry...
 	 */
@@ -448,13 +819,132 @@
 		hashbin->hb_current = NULL;
 
 	/* Release lock */
-	if ( hashbin->hb_type & HB_GLOBAL) {
-		spin_unlock_irqrestore( &hashbin->hb_mutex[ bin], flags);
+	if ( hashbin->hb_type & HB_LOCK ) {
+		spin_unlock_irqrestore(&hashbin->hb_spinlock, flags);
+	} /* Default is no-lock  */
+
+	return entry;
+}
+
+/*********************** HASHBIN ENUMERATION ***********************/
+
+/*
+ * Function hashbin_common_find (hashbin, hashv, name)
+ *
+ *    Find item with the given hashv or name
+ *
+ */
+void* hashbin_find( hashbin_t* hashbin, long hashv, char* name )
+{
+	int bin;
+	irda_queue_t* entry;
 
-	} else if ( hashbin->hb_type & HB_LOCAL) {
-		restore_flags( flags);
+	IRDA_DEBUG( 4, "hashbin_find()\n");
+
+	ASSERT( hashbin != NULL, return NULL;);
+	ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
+
+	/*
+	 * Locate hashbin
+	 */
+	if ( name )
+		hashv = hash( name );
+	bin = GET_HASHBIN( hashv );
+	
+	/*
+	 * Search for entry
+	 */
+	entry = hashbin->hb_queue[ bin];
+	if ( entry ) {
+		do {
+			/*
+			 * Check for key
+			 */
+			if ( entry->q_hash == hashv ) {
+				/*
+				 * Name compare too?
+				 */
+				if ( name ) {
+					if ( strcmp( entry->q_name, name ) == 0 ) {
+						return entry;
+					}
+				} else {
+					return entry;
+				}
+			}
+			entry = entry->q_next;
+		} while ( entry != hashbin->hb_queue[ bin ] );
 	}
 
+	return NULL;
+}
+
+/*
+ * Function hashbin_lock_find (hashbin, hashv, name)
+ *
+ *    Find item with the given hashv or name
+ *
+ * Same, but with spinlock protection...
+ * I call it safe, but it's only safe with respect to the hashbin, not its
+ * content. - Jean II
+ */
+void* hashbin_lock_find( hashbin_t* hashbin, long hashv, char* name )
+{
+	unsigned long flags = 0;
+	irda_queue_t* entry;
+
+	/* Synchronize */
+	spin_lock_irqsave(&hashbin->hb_spinlock, flags);
+
+	/*
+	 * Search for entry
+	 */
+	entry = (irda_queue_t* ) hashbin_find( hashbin, hashv, name );
+
+	/* Release lock */
+	spin_unlock_irqrestore(&hashbin->hb_spinlock, flags);
+
+	return entry;
+}
+
+/*
+ * Function hashbin_find (hashbin, hashv, name, pnext)
+ *
+ *    Find an item with the given hashv or name, and its successor
+ *
+ * This function allow to do concurent enumerations without the
+ * need to lock over the whole session, because the caller keep the
+ * context of the search. On the other hand, it might fail and return
+ * NULL if the entry is removed. - Jean II
+ */
+void* hashbin_find_next( hashbin_t* hashbin, long hashv, char* name,
+			 void ** pnext)
+{
+	unsigned long flags = 0;
+	irda_queue_t* entry;
+
+	/* Synchronize */
+	spin_lock_irqsave(&hashbin->hb_spinlock, flags);
+
+	/*
+	 * Search for current entry
+	 * This allow to check if the current item is still in the
+	 * hashbin or has been removed.
+	 */
+	entry = (irda_queue_t* ) hashbin_find( hashbin, hashv, name );
+
+	/*
+	 * Trick hashbin_get_next() to return what we want
+	 */
+	if(entry) {
+		hashbin->hb_current = entry;
+		*pnext = hashbin_get_next( hashbin );
+	} else
+		*pnext = NULL;
+
+	/* Release lock */
+	spin_unlock_irqrestore(&hashbin->hb_spinlock, flags);
+
 	return entry;
 }
 
@@ -496,6 +986,8 @@
  *    be started by a call to hashbin_get_first(). The function returns
  *    NULL when all items have been traversed
  * 
+ * The context of the search is stored within the hashbin, so you must
+ * protect yourself from concurent enumerations. - Jean II
  */
 irda_queue_t *hashbin_get_next( hashbin_t *hashbin)
 {
@@ -542,241 +1034,4 @@
 		}
 	}
 	return NULL;
-}
-
-/*
- * Function enqueue_last (queue, proc)
- *
- *    Insert item into end of queue.
- *
- */
-static void __enqueue_last( irda_queue_t **queue, irda_queue_t* element)
-{
-	IRDA_DEBUG( 4, __FUNCTION__ "()\n");
-
-	/*
-	 * Check if queue is empty.
-	 */
-	if ( *queue == NULL ) {
-		/*
-		 * Queue is empty.  Insert one element into the queue.
-		 */
-		element->q_next = element->q_prev = *queue = element;
-		
-	} else {
-		/*
-		 * Queue is not empty.  Insert element into end of queue.
-		 */
-		element->q_prev         = (*queue)->q_prev;
-		element->q_prev->q_next = element;
-		(*queue)->q_prev        = element;
-		element->q_next         = *queue;
-	}	
-}
-
-inline void enqueue_last( irda_queue_t **queue, irda_queue_t* element)
-{
-	unsigned long flags;
-	
-        save_flags(flags);
-        cli();
-
-        __enqueue_last( queue, element);
-
-        restore_flags(flags);
-}
-
-/*
- * Function enqueue_first (queue, proc)
- *
- *    Insert item first in queue.
- *
- */
-void enqueue_first(irda_queue_t **queue, irda_queue_t* element)
-{
-	
-	IRDA_DEBUG( 4, __FUNCTION__ "()\n");
-
-	/*
-	 * Check if queue is empty.
-	 */
-	if ( *queue == NULL ) {
-		/*
-		 * Queue is empty.  Insert one element into the queue.
-		 */
-		element->q_next = element->q_prev = *queue = element;
-		
-	} else {
-		/*
-		 * Queue is not empty.  Insert element into front of queue.
-		 */
-		element->q_next          = (*queue);
-		(*queue)->q_prev->q_next = element;
-		element->q_prev          = (*queue)->q_prev;
-		(*queue)->q_prev         = element;
-		(*queue)                 = element;
-	}
-}
-
-/*
- * Function enqueue_queue (queue, list)
- *
- *    Insert a queue (list) into the start of the first queue
- *
- */
-void enqueue_queue( irda_queue_t** queue, irda_queue_t** list )
-{
-	irda_queue_t* tmp;
-	
-	/*
-	 * Check if queue is empty
-	 */ 
-	if ( *queue ) {
-		(*list)->q_prev->q_next  = (*queue);
-		(*queue)->q_prev->q_next = (*list); 
-		tmp                      = (*list)->q_prev;
-		(*list)->q_prev          = (*queue)->q_prev;
-		(*queue)->q_prev         = tmp;
-	} else {
-		*queue                   = (*list); 
-	}
-	
-	(*list) = NULL;
-}
-
-/*
- * Function enqueue_second (queue, proc)
- *
- *    Insert item behind head of queue.
- *
- */
-#if 0
-static void enqueue_second(irda_queue_t **queue, irda_queue_t* element)
-{
-	IRDA_DEBUG( 0, "enqueue_second()\n");
-
-	/*
-	 * Check if queue is empty.
-	 */
-	if ( *queue == NULL ) {
-		/*
-		 * Queue is empty.  Insert one element into the queue.
-		 */
-		element->q_next = element->q_prev = *queue = element;
-		
-	} else {
-		/*
-		 * Queue is not empty.  Insert element into ..
-		 */
-		element->q_prev = (*queue);
-		(*queue)->q_next->q_prev = element;
-		element->q_next = (*queue)->q_next;
-		(*queue)->q_next = element;
-	}
-}
-#endif
-
-/*
- * Function dequeue (queue)
- *
- *    Remove first entry in queue
- *
- */
-irda_queue_t *dequeue_first(irda_queue_t **queue)
-{
-	irda_queue_t *ret;
-
-	IRDA_DEBUG( 4, "dequeue_first()\n");
-	
-	/*
-	 * Set return value
-	 */
-	ret =  *queue;
-	
-	if ( *queue == NULL ) {
-		/*
-		 * Queue was empty.
-		 */
-	} else if ( (*queue)->q_next == *queue ) {
-		/* 
-		 *  Queue only contained a single element. It will now be
-		 *  empty.  
-		 */
-		*queue = NULL;
-	} else {
-		/*
-		 * Queue contained several element.  Remove the first one.
-		 */
-		(*queue)->q_prev->q_next = (*queue)->q_next;
-		(*queue)->q_next->q_prev = (*queue)->q_prev;
-		*queue = (*queue)->q_next;
-	}
-	
-	/*
-	 * Return the removed entry (or NULL of queue was empty).
-	 */
-	return ret;
-}
-
-/*
- * Function dequeue_general (queue, element)
- *
- *
- */
-static irda_queue_t *dequeue_general(irda_queue_t **queue, irda_queue_t* element)
-{
-	irda_queue_t *ret;
-	
-	IRDA_DEBUG( 4, "dequeue_general()\n");
-	
-	/*
-	 * Set return value
-	 */
-	ret =  *queue;
-		
-	if ( *queue == NULL ) {
-		/*
-		 * Queue was empty.
-		 */
-	} else if ( (*queue)->q_next == *queue ) {
-		/* 
-		 *  Queue only contained a single element. It will now be
-		 *  empty.  
-		 */
-		*queue = NULL;
-		
-	} else {
-		/*
-		 *  Remove specific element.
-		 */
-		element->q_prev->q_next = element->q_next;
-		element->q_next->q_prev = element->q_prev;
-		if ( (*queue) == element)
-			(*queue) = element->q_next;
-	}
-	
-	/*
-	 * Return the removed entry (or NULL of queue was empty).
-	 */
-	return ret;
-}
-
-/*
- * Function hash (name)
- *
- *    This function hash the input string 'name' using the ELF hash
- *    function for strings.
- */
-static __u32 hash( char* name)
-{
-	__u32 h = 0;
-	__u32 g;
-	
-	while(*name) {
-		h = (h<<4) + *name++;
-		if ((g = (h & 0xf0000000)))
-			h ^=g>>24;
-		h &=~g;
-	}
-	return h;
 }
diff -Nru a/net/irda/irsyms.c b/net/irda/irsyms.c
--- a/net/irda/irsyms.c	Fri Sep 20 08:20:47 2002
+++ b/net/irda/irsyms.c	Fri Sep 20 08:20:47 2002
@@ -132,12 +132,14 @@
 EXPORT_SYMBOL(lmp_reasons);
 
 /* Queue */
-EXPORT_SYMBOL(hashbin_find);
 EXPORT_SYMBOL(hashbin_new);
 EXPORT_SYMBOL(hashbin_insert);
 EXPORT_SYMBOL(hashbin_delete);
 EXPORT_SYMBOL(hashbin_remove);
 EXPORT_SYMBOL(hashbin_remove_this);
+EXPORT_SYMBOL(hashbin_find);
+EXPORT_SYMBOL(hashbin_lock_find);
+EXPORT_SYMBOL(hashbin_find_next);
 EXPORT_SYMBOL(hashbin_get_next);
 EXPORT_SYMBOL(hashbin_get_first);
 
@@ -328,7 +330,8 @@
  * On the other hand, it needs to be initialised *after* the basic
  * networking, the /proc/net filesystem and sysctl module. Those are
  * currently initialised in .../init/main.c (before initcalls).
- * Also, it needs to be initialised *after* the random number generator.
+ * Also, IrDA drivers needs to be initialised *after* the random number
+ * generator (main stack and higher layer init don't need it anymore).
  *
  * Jean II
  */
diff -Nru a/net/irda/irttp.c b/net/irda/irttp.c
--- a/net/irda/irttp.c	Fri Sep 20 08:20:47 2002
+++ b/net/irda/irttp.c	Fri Sep 20 08:20:47 2002
@@ -91,7 +91,7 @@
 
 	irttp->magic = TTP_MAGIC;
 
-	irttp->tsaps = hashbin_new(HB_LOCAL);
+	irttp->tsaps = hashbin_new(HB_LOCK);
 	if (!irttp->tsaps) {
 		ERROR("%s: can't allocate IrTTP hashbin!\n", __FUNCTION__);
 		return -ENOMEM;
@@ -433,7 +433,7 @@
 	self->notify = *notify;
 	self->lsap = lsap;
 
-	hashbin_insert(irttp->tsaps, (irda_queue_t *) self, (int) self, NULL);
+	hashbin_insert(irttp->tsaps, (irda_queue_t *) self, (long) self, NULL);
 
 	if (credit > TTP_RX_MAX_CREDIT)
 		self->initial_credit = TTP_RX_MAX_CREDIT;
@@ -503,7 +503,7 @@
 		return 0; /* Will be back! */
 	}
 
-	tsap = hashbin_remove(irttp->tsaps, (int) self, NULL);
+	tsap = hashbin_remove(irttp->tsaps, (long) self, NULL);
 
 	ASSERT(tsap == self, return -1;);
 
@@ -1365,31 +1365,44 @@
 struct tsap_cb *irttp_dup(struct tsap_cb *orig, void *instance)
 {
 	struct tsap_cb *new;
+	unsigned long flags;
 
 	IRDA_DEBUG(1, __FUNCTION__ "()\n");
 
+	/* Protect our access to the old tsap instance */
+	spin_lock_irqsave(&irttp->tsaps->hb_spinlock, flags);
+
+	/* Find the old instance */
 	if (!hashbin_find(irttp->tsaps, (int) orig, NULL)) {
 		IRDA_DEBUG(0, __FUNCTION__ "(), unable to find TSAP\n");
+		spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags);
 		return NULL;
 	}
+
+	/* Allocate a new instance */
 	new = kmalloc(sizeof(struct tsap_cb), GFP_ATOMIC);
 	if (!new) {
 		IRDA_DEBUG(0, __FUNCTION__ "(), unable to kmalloc\n");
+		spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags);
 		return NULL;
 	}
 	/* Dup */
 	memcpy(new, orig, sizeof(struct tsap_cb));
-	new->notify.instance = instance;
-	new->lsap = irlmp_dup(orig->lsap, new);
+
+	/* We don't need the old instance any more */
+	spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags);
 
 	/* Not everything should be copied */
+	new->notify.instance = instance;
+	new->lsap = irlmp_dup(orig->lsap, new);
 	init_timer(&new->todo_timer);
 
 	skb_queue_head_init(&new->rx_queue);
 	skb_queue_head_init(&new->tx_queue);
 	skb_queue_head_init(&new->rx_fragments);
 
-	hashbin_insert(irttp->tsaps, (irda_queue_t *) new, (int) new, NULL);
+	/* This is locked */
+	hashbin_insert(irttp->tsaps, (irda_queue_t *) new, (long) new, NULL);
 
 	return new;
 }
@@ -1723,8 +1736,8 @@
 
 	len = 0;
 
-	save_flags(flags);
-	cli();
+	/* Protect our access to the tsap list */
+	spin_lock_irqsave(&irttp->tsaps->hb_spinlock, flags);
 
 	self = (struct tsap_cb *) hashbin_get_first(irttp->tsaps);
 	while (self != NULL) {
@@ -1770,7 +1783,7 @@
 
 		self = (struct tsap_cb *) hashbin_get_next(irttp->tsaps);
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags);
 
 	return len;
 }
diff -Nru a/net/llc/llc_actn.c b/net/llc/llc_actn.c
--- a/net/llc/llc_actn.c	Fri Sep 20 08:20:43 2002
+++ b/net/llc/llc_actn.c	Fri Sep 20 08:20:43 2002
@@ -24,16 +24,10 @@
 #include <net/llc_pdu.h>
 #include <net/llc_mac.h>
 
-static void llc_station_ack_tmr_callback(unsigned long timeout_data);
-
 int llc_station_ac_start_ack_timer(struct llc_station *station,
 				   struct sk_buff *skb)
 {
-	del_timer(&station->ack_timer);
-	station->ack_timer.expires  = jiffies + LLC_ACK_TIME * HZ;
-	station->ack_timer.data     = (unsigned long)station;
-	station->ack_timer.function = llc_station_ack_tmr_callback;
-	add_timer(&station->ack_timer);
+	mod_timer(&station->ack_timer, jiffies + LLC_ACK_TIME * HZ);
 	return 0;
 }
 
@@ -130,7 +124,7 @@
 	return 0;
 }
 
-static void llc_station_ack_tmr_callback(unsigned long timeout_data)
+void llc_station_ack_tmr_cb(unsigned long timeout_data)
 {
 	struct llc_station *station = (struct llc_station *)timeout_data;
 	struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
diff -Nru a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c
--- a/net/llc/llc_c_ac.c	Fri Sep 20 08:20:48 2002
+++ b/net/llc/llc_c_ac.c	Fri Sep 20 08:20:48 2002
@@ -28,10 +28,6 @@
 #include <net/llc_pdu.h>
 #include <net/llc_mac.h>
 
-static void llc_conn_pf_cycle_tmr_cb(unsigned long timeout_data);
-static void llc_conn_ack_tmr_cb(unsigned long timeout_data);
-static void llc_conn_rej_tmr_cb(unsigned long timeout_data);
-static void llc_conn_busy_tmr_cb(unsigned long timeout_data);
 static int llc_conn_ac_inc_vs_by_1(struct sock *sk, struct sk_buff *skb);
 static void llc_process_tmr_ev(struct sock *sk, struct sk_buff *skb);
 static int llc_conn_ac_data_confirm(struct sock *sk, struct sk_buff *ev);
@@ -664,11 +660,8 @@
 
 	if (!llc->remote_busy_flag) {
 		llc->remote_busy_flag = 1;
-		llc->busy_state_timer.timer.expires = jiffies +
-					llc->busy_state_timer.expire * HZ;
-		llc->busy_state_timer.timer.data     = (unsigned long)sk;
-		llc->busy_state_timer.timer.function = llc_conn_busy_tmr_cb;
-		add_timer(&llc->busy_state_timer.timer);
+		mod_timer(&llc->busy_state_timer.timer,
+			 jiffies + llc->busy_state_timer.expire * HZ);
 	}
 	return 0;
 }
@@ -905,12 +898,8 @@
 	struct llc_opt *llc = llc_sk(sk);
 
 	llc->p_flag = 1;
-	del_timer(&llc->pf_cycle_timer.timer);
-	llc->pf_cycle_timer.timer.expires  = jiffies +
-						llc->pf_cycle_timer.expire * HZ;
-	llc->pf_cycle_timer.timer.data     = (unsigned long)sk;
-	llc->pf_cycle_timer.timer.function = llc_conn_pf_cycle_tmr_cb;
-	add_timer(&llc->pf_cycle_timer.timer);
+	mod_timer(&llc->pf_cycle_timer.timer,
+		  jiffies + llc->pf_cycle_timer.expire * HZ);
 	return 0;
 }
 
@@ -1181,11 +1170,7 @@
 {
 	struct llc_opt *llc = llc_sk(sk);
 
-	del_timer(&llc->ack_timer.timer);
-	llc->ack_timer.timer.expires  = jiffies + llc->ack_timer.expire * HZ;
-	llc->ack_timer.timer.data     = (unsigned long)sk;
-	llc->ack_timer.timer.function = llc_conn_ack_tmr_cb;
-	add_timer(&llc->ack_timer.timer);
+	mod_timer(&llc->ack_timer.timer, jiffies + llc->ack_timer.expire * HZ);
 	return 0;
 }
 
@@ -1193,12 +1178,8 @@
 {
 	struct llc_opt *llc = llc_sk(sk);
 
-	del_timer(&llc->rej_sent_timer.timer);
-	llc->rej_sent_timer.timer.expires = jiffies +
-					    llc->rej_sent_timer.expire * HZ;
-	llc->rej_sent_timer.timer.data     = (unsigned long)sk;
-	llc->rej_sent_timer.timer.function = llc_conn_rej_tmr_cb;
-	add_timer(&llc->rej_sent_timer.timer);
+	mod_timer(&llc->rej_sent_timer.timer,
+		  jiffies + llc->rej_sent_timer.expire * HZ);
 	return 0;
 }
 
@@ -1207,13 +1188,9 @@
 {
 	struct llc_opt *llc = llc_sk(sk);
 
-	if (!timer_pending(&llc->ack_timer.timer)) {
-		llc->ack_timer.timer.expires  = jiffies +
-						llc->ack_timer.expire * HZ;
-		llc->ack_timer.timer.data     = (unsigned long)sk;
-		llc->ack_timer.timer.function = llc_conn_ack_tmr_cb;
-		add_timer(&llc->ack_timer.timer);
-	}
+	if (!timer_pending(&llc->ack_timer.timer))
+		mod_timer(&llc->ack_timer.timer,
+			  jiffies + llc->ack_timer.expire * HZ);
 	return 0;
 }
 
@@ -1260,13 +1237,9 @@
 			llc->failed_data_req = 0;
 			llc_conn_ac_data_confirm(sk, skb);
 		}
-		if (unacked) {
-			llc->ack_timer.timer.expires  = jiffies +
-						   llc->ack_timer.expire * HZ;
-			llc->ack_timer.timer.data     = (unsigned long)sk;
-			llc->ack_timer.timer.function = llc_conn_ack_tmr_cb;
-			add_timer(&llc->ack_timer.timer);
-	       }
+		if (unacked)
+			mod_timer(&llc->ack_timer.timer,
+				  jiffies + llc->ack_timer.expire * HZ);
 	} else if (llc->failed_data_req) {
 		llc_pdu_decode_pf_bit(skb, &fbit);
 		if (fbit == 1) {
@@ -1413,7 +1386,7 @@
 	bh_unlock_sock(sk);
 }
 
-static void llc_conn_busy_tmr_cb(unsigned long timeout_data)
+void llc_conn_busy_tmr_cb(unsigned long timeout_data)
 {
 	struct sock *sk = (struct sock *)timeout_data;
 	struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
@@ -1445,7 +1418,7 @@
 	bh_unlock_sock(sk);
 }
 
-static void llc_conn_rej_tmr_cb(unsigned long timeout_data)
+void llc_conn_rej_tmr_cb(unsigned long timeout_data)
 {
 	struct sock *sk = (struct sock *)timeout_data;
 	struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
diff -Nru a/net/llc/llc_c_ev.c b/net/llc/llc_c_ev.c
--- a/net/llc/llc_c_ev.c	Fri Sep 20 08:20:41 2002
+++ b/net/llc/llc_c_ev.c	Fri Sep 20 08:20:41 2002
@@ -194,7 +194,8 @@
 {
 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
-	return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) &&
+	return llc_conn_space(sk, skb) &&
+	       !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) &&
 	       !LLC_I_PF_IS_0(pdu) &&
 	       LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1;
 }
@@ -203,7 +204,8 @@
 {
 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
-	return !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) &&
+	return llc_conn_space(sk, skb) &&
+	       !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) &&
 	       !LLC_I_PF_IS_1(pdu) &&
 	       LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1;
 }
@@ -250,7 +252,8 @@
 {
 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
-	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) &&
+	return llc_conn_space(sk, skb) &&
+	       !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) &&
 	       !LLC_I_PF_IS_0(pdu) &&
 	       LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1;
 }
@@ -268,7 +271,8 @@
 {
 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
-	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) &&
+	return llc_conn_space(sk, skb) &&
+	       !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) &&
 	       LLC_I_GET_NS(pdu) == llc_sk(sk)->vR ? 0 : 1;
 }
 
@@ -423,7 +427,8 @@
 {
 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
-	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
+	return llc_conn_space(sk, skb) &&
+	       !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
 	       !LLC_S_PF_IS_0(pdu) &&
 	       LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RR ? 0 : 1;
 }
@@ -432,7 +437,8 @@
 {
 	struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
 
-	return !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
+	return llc_conn_space(sk, skb) &&
+	       !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_S(pdu) &&
 	       !LLC_S_PF_IS_1(pdu) &&
 	       LLC_S_PDU_RSP(pdu) == LLC_2_PDU_RSP_RR ? 0 : 1;
 }
diff -Nru a/net/llc/llc_main.c b/net/llc/llc_main.c
--- a/net/llc/llc_main.c	Fri Sep 20 08:20:44 2002
+++ b/net/llc/llc_main.c	Fri Sep 20 08:20:44 2002
@@ -184,19 +184,32 @@
 		goto out;
 	memset(llc, 0, sizeof(*llc));
 	rc = 0;
-	llc->sk			     = sk;
-	llc->state		     = LLC_CONN_STATE_ADM;
-	llc->inc_cntr		     = llc->dec_cntr = 2;
-	llc->dec_step		     = llc->connect_step = 1;
-	llc->ack_timer.expire	     = LLC_ACK_TIME;
-	llc->pf_cycle_timer.expire   = LLC_P_TIME;
-	llc->rej_sent_timer.expire   = LLC_REJ_TIME;
-	llc->busy_state_timer.expire = LLC_BUSY_TIME;
-	llc->n2			     = 2;   /* max retransmit */
-	llc->k			     = 2;   /* tx win size, will adjust dynam */
-	llc->rw			     = 128; /* rx win size (opt and equal to
-					     * tx_win of remote LLC)
-					     */
+
+	llc->sk	      = sk;
+	llc->state    = LLC_CONN_STATE_ADM;
+	llc->inc_cntr = llc->dec_cntr = 2;
+	llc->dec_step = llc->connect_step = 1;
+
+	llc->ack_timer.expire	      = LLC_ACK_TIME;
+	llc->ack_timer.timer.data     = (unsigned long)sk;
+	llc->ack_timer.timer.function = llc_conn_ack_tmr_cb;
+
+	llc->pf_cycle_timer.expire	   = LLC_P_TIME;
+	llc->pf_cycle_timer.timer.data     = (unsigned long)sk;
+	llc->pf_cycle_timer.timer.function = llc_conn_pf_cycle_tmr_cb;
+
+	llc->rej_sent_timer.expire	   = LLC_REJ_TIME;
+	llc->rej_sent_timer.timer.data     = (unsigned long)sk;
+	llc->rej_sent_timer.timer.function = llc_conn_rej_tmr_cb;
+
+	llc->busy_state_timer.expire	     = LLC_BUSY_TIME;
+	llc->busy_state_timer.timer.data     = (unsigned long)sk;
+	llc->busy_state_timer.timer.function = llc_conn_busy_tmr_cb;
+
+	llc->n2 = 2;   /* max retransmit */
+	llc->k  = 2;   /* tx win size, will adjust dynam */
+	llc->rw = 128; /* rx win size (opt and equal to
+		        * tx_win of remote LLC) */
 	skb_queue_head_init(&llc->pdu_unack_q);
 	sk->backlog_rcv = llc_backlog_rcv;
 	llc_sk(sk) = llc;
@@ -534,6 +547,21 @@
 	return skb;
 }
 
+static char *llc_conn_state_names[] = {
+	[LLC_CONN_STATE_ADM] =        "adm", 
+	[LLC_CONN_STATE_SETUP] =      "setup", 
+	[LLC_CONN_STATE_NORMAL] =     "normal",
+	[LLC_CONN_STATE_BUSY] =       "busy", 
+	[LLC_CONN_STATE_REJ] =        "rej", 
+	[LLC_CONN_STATE_AWAIT] =      "await", 
+	[LLC_CONN_STATE_AWAIT_BUSY] = "await_busy",
+	[LLC_CONN_STATE_AWAIT_REJ] =  "await_rej",
+	[LLC_CONN_STATE_D_CONN]	=     "d_conn",
+	[LLC_CONN_STATE_RESET] =      "reset", 
+	[LLC_CONN_STATE_ERROR] =      "error", 
+	[LLC_CONN_STATE_TEMP] =       "temp", 
+};
+
 static int llc_proc_get_info(char *bf, char **start, off_t offset, int length)
 {
 	struct llc_opt *llc;
@@ -546,19 +574,34 @@
 		struct llc_sap *sap = list_entry(sap_entry, struct llc_sap,
 						 node);
 
-		len += sprintf(bf + len, "lsap=%d\n", sap->laddr.lsap);
+		len += sprintf(bf + len, "lsap=%02X\n", sap->laddr.lsap);
 		spin_lock_bh(&sap->sk_list.lock);
 		if (list_empty(&sap->sk_list.list)) {
 			len += sprintf(bf + len, "no connections\n");
 			goto unlock;
 		}
-		len += sprintf(bf + len,
-				"connection list:\nstate  retr txwin rxwin\n");
+		len += sprintf(bf + len, "connection list:\n"
+					 "dsap state      retr txw rxw "
+					 "pf ff sf df rs cs "
+					 "tack tpfc trs tbs blog busr\n");
 		list_for_each(llc_entry, &sap->sk_list.list) {
 			llc = list_entry(llc_entry, struct llc_opt, node);
-			len += sprintf(bf + len, "  %-5d%-5d%-6d%-5d\n",
-					llc->state, llc->retry_count, llc->k,
-					llc->rw);
+			len += sprintf(bf + len, " %02X  %-10s %3d  %3d %3d "
+						 "%2d %2d %2d "
+						 "%2d %2d %2d "
+						 "%4d %4d %3d %3d %4d %4d\n",
+				       llc->daddr.lsap,
+				       llc_conn_state_names[llc->state],
+				       llc->retry_count, llc->k, llc->rw,
+				       llc->p_flag, llc->f_flag, llc->s_flag,
+				       llc->data_flag, llc->remote_busy_flag,
+				       llc->cause_flag,
+				       timer_pending(&llc->ack_timer.timer),
+				       timer_pending(&llc->pf_cycle_timer.timer),
+				       timer_pending(&llc->rej_sent_timer.timer),
+				       timer_pending(&llc->busy_state_timer.timer),
+				       !!llc->sk->backlog.tail,
+				       llc->sk->lock.users);
 		}
 unlock:	
 		spin_unlock_bh(&sap->sk_list.lock);
@@ -608,6 +651,9 @@
 	skb_queue_head_init(&llc_main_station.mac_pdu_q);
 	skb_queue_head_init(&llc_main_station.ev_q.list);
 	spin_lock_init(&llc_main_station.ev_q.lock);
+	llc_main_station.ack_timer.data     = (unsigned long)&llc_main_station;
+	llc_main_station.ack_timer.function = llc_station_ack_tmr_cb;
+
 	skb = alloc_skb(0, GFP_ATOMIC);
 	if (!skb)
 		goto err;
diff -Nru a/net/llc/llc_sock.c b/net/llc/llc_sock.c
--- a/net/llc/llc_sock.c	Fri Sep 20 08:20:41 2002
+++ b/net/llc/llc_sock.c	Fri Sep 20 08:20:41 2002
@@ -360,11 +360,11 @@
 		llc->laddr.lsap, llc->daddr.lsap);
 	if (!llc_send_disc(sk))
 		llc_ui_wait_for_disc(sk, sk->rcvtimeo);
-	release_sock(sk);
 	if (!sk->zapped) {
 		llc_sap_unassign_sock(llc->sap, sk);
 		llc_ui_remove_socket(sk);
 	}
+	release_sock(sk);
 	if (llc->sap && list_empty(&llc->sap->sk_list.list))
 		llc_sap_close(llc->sap);
 	sock_put(sk);
@@ -484,10 +484,10 @@
 	llc->daddr.lsap = addr->sllc_dsap;
 	memcpy(llc->daddr.mac, addr->sllc_dmac, IFHWADDRLEN);
 	memcpy(&llc->addr, addr, sizeof(llc->addr));
-	rc = sk->zapped = 0;
 	llc_ui_insert_socket(sk);
 	/* assign new connection to it's SAP */
 	llc_sap_assign_sock(sap, sk);
+	rc = sk->zapped = 0;
 out:
 	return rc;
 }
@@ -878,18 +878,22 @@
 	if (!skb) /* shutdown */
 		goto out;
 	copied = skb->len;
-	if (copied > size) {
+	if (copied > size)
 		copied = size;
-		msg->msg_flags |= MSG_TRUNC;
-	}
 	rc = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
 	if (rc)
 		goto dgram_free;
+	if (skb->len > copied) {
+		skb_pull(skb, copied);
+		skb_queue_head(&sk->receive_queue, skb);
+	}
 	if (uaddr)
 		memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr));
 	msg->msg_namelen = sizeof(*uaddr);
+	if (!skb->list) {
 dgram_free:
-	kfree_skb(skb);
+		kfree_skb(skb);
+	}
 out:
 	release_sock(sk);
 	return rc ? : copied;
@@ -915,7 +919,7 @@
 	int noblock = flags & MSG_DONTWAIT;
 	struct net_device *dev;
 	struct sk_buff *skb;
-	int rc = -EINVAL, size = 0;
+	int rc = -EINVAL, size = 0, copied = 0, hdrlen;
 
 	dprintk("%s: sending from %02X to %02X\n", __FUNCTION__, llc->laddr.lsap, llc->daddr.lsap);
 	lock_sock(sk);
@@ -943,20 +947,28 @@
 			goto release;
 	} else
 		dev = llc->dev;
-	size = dev->hard_header_len + len + llc_ui_header_len(sk, addr);
-	rc = -EMSGSIZE;
+	hdrlen = dev->hard_header_len + llc_ui_header_len(sk, addr);
+	size = hdrlen + len;
 	if (size > dev->mtu)
-		goto release;
+		size = dev->mtu;
+	copied = size - hdrlen;
+	release_sock(sk);
 	skb = sock_alloc_send_skb(sk, size, noblock, &rc);
+	lock_sock(sk);
 	if (!skb)
 		goto release;
 	skb->sk	      = sk;
 	skb->dev      = dev;
 	skb->protocol = llc_proto_type(addr->sllc_arphrd);
-	skb_reserve(skb, dev->hard_header_len + llc_ui_header_len(sk, addr));
-	rc = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
+	skb_reserve(skb, hdrlen); 
+	rc = memcpy_fromiovec(skb_put(skb, copied), msg->msg_iov, copied);
 	if (rc)
 		goto out;
+	if (sk->type == SOCK_DGRAM || addr->sllc_ua) {
+		llc_build_and_send_ui_pkt(llc->sap, skb, addr->sllc_dmac,
+					  addr->sllc_dsap);
+		goto out;
+	}
 	if (addr->sllc_test) {
 		llc_build_and_send_test_pkt(llc->sap, skb, addr->sllc_dmac,
 					    addr->sllc_dsap);
@@ -967,11 +979,6 @@
 					   addr->sllc_dsap);
 		goto out;
 	}
-	if (sk->type == SOCK_DGRAM || addr->sllc_ua) {
-		llc_build_and_send_ui_pkt(llc->sap, skb, addr->sllc_dmac,
-					  addr->sllc_dsap);
-		goto out;
-	}
 	rc = -ENOPROTOOPT;
 	if (!(sk->type == SOCK_STREAM && !addr->sllc_ua))
 		goto out;
@@ -986,7 +993,7 @@
 		dprintk("%s: failed sending from %02X to %02X: %d\n",
 			__FUNCTION__, llc->laddr.lsap, llc->daddr.lsap, rc);
 	release_sock(sk);
-	return rc ? : len;
+	return rc ? : copied;
 }
 
 /**
diff -Nru a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c
--- a/net/netrom/af_netrom.c	Fri Sep 20 08:20:46 2002
+++ b/net/netrom/af_netrom.c	Fri Sep 20 08:20:46 2002
@@ -1,38 +1,13 @@
 /*
- *	NET/ROM release 007
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	History
- *	NET/ROM 001	Jonathan(G4KLX)	Cloned from the AX25 code.
- *	NET/ROM 002	Darryl(G7LED)	Fixes and address enhancement.
- *			Jonathan(G4KLX)	Complete bind re-think.
- *			Alan(GW4PTS)	Trivial tweaks into new format.
- *	NET/ROM	003	Jonathan(G4KLX)	Added G8BPQ extensions.
- *					Added NET/ROM routing ioctl.
- *			Darryl(G7LED)	Fix autobinding (on connect).
- *					Fixed nr_release(), set TCP_CLOSE, wakeup app
- *					context, THEN make the sock dead.
- *					Circuit ID check before allocating it on
- *					a connection.
- *			Alan(GW4PTS)	sendmsg/recvmsg only. Fixed connect clear bug
- *					inherited from AX.25
- *	NET/ROM 004	Jonathan(G4KLX)	Converted to module.
- *	NET/ROM 005	Jonathan(G4KLX) Linux 2.1
- *			Alan(GW4PTS)	Started POSIXisms
- *	NET/ROM 006	Alan(GW4PTS)	Brought in line with the ANK changes
- *			Jonathan(G4KLX)	Removed hdrincl.
- *	NET/ROM 007	Jonathan(G4KLX)	New timer architecture.
- *					Implemented Idle timer.
- *			Arnaldo C. Melo s/suser/capable/, micro cleanups
+ * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
+ * Copyright Darryl Miles G7LED (dlm@g7led.demon.co.uk)
  */
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/errno.h>
@@ -82,7 +57,8 @@
 
 static unsigned short circuit = 0x101;
 
-static struct sock *volatile nr_list;
+static struct sock *nr_list;
+static spinlock_t nr_list_lock;
 
 static struct proto_ops nr_proto_ops;
 
@@ -123,27 +99,26 @@
 static void nr_remove_socket(struct sock *sk)
 {
 	struct sock *s;
-	unsigned long flags;
 
-	save_flags(flags); cli();
+	spin_lock_bh(&nr_list_lock);
 
 	if ((s = nr_list) == sk) {
 		nr_list = s->next;
-		restore_flags(flags);
+		spin_unlock_bh(&nr_list_lock);
 		return;
 	}
 
 	while (s != NULL && s->next != NULL) {
 		if (s->next == sk) {
 			s->next = sk->next;
-			restore_flags(flags);
+			spin_unlock_bh(&nr_list_lock);
 			return;
 		}
 
 		s = s->next;
 	}
 
-	restore_flags(flags);
+	spin_unlock_bh(&nr_list_lock);
 }
 
 /*
@@ -153,10 +128,12 @@
 {
 	struct sock *s;
 
+	spin_lock_bh(&nr_list_lock);
 	for (s = nr_list; s != NULL; s = s->next) {
 		if (nr_sk(s)->device == dev)
 			nr_disconnect(s, ENETUNREACH);
 	}
+	spin_unlock_bh(&nr_list_lock);
 }
 
 /*
@@ -180,14 +157,10 @@
  */
 static void nr_insert_socket(struct sock *sk)
 {
-	unsigned long flags;
-
-	save_flags(flags); cli();
-
+	spin_lock_bh(&nr_list_lock);
 	sk->next = nr_list;
 	nr_list  = sk;
-
-	restore_flags(flags);
+	spin_unlock_bh(&nr_list_lock);
 }
 
 /*
@@ -196,21 +169,18 @@
  */
 static struct sock *nr_find_listener(ax25_address *addr)
 {
-	unsigned long flags;
 	struct sock *s;
 
-	save_flags(flags);
-	cli();
-
+	spin_lock_bh(&nr_list_lock);
 	for (s = nr_list; s != NULL; s = s->next) {
 		if (!ax25cmp(&nr_sk(s)->source_addr, addr) &&
 		    s->state == TCP_LISTEN) {
-			restore_flags(flags);
+			spin_unlock_bh(&nr_list_lock);
 			return s;
 		}
 	}
+	spin_unlock_bh(&nr_list_lock);
 
-	restore_flags(flags);
 	return NULL;
 }
 
@@ -220,21 +190,17 @@
 static struct sock *nr_find_socket(unsigned char index, unsigned char id)
 {
 	struct sock *s;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
 
+	spin_lock_bh(&nr_list_lock);
 	for (s = nr_list; s != NULL; s = s->next) {
 		nr_cb *nr = nr_sk(s);
 		
 		if (nr->my_index == index && nr->my_id == id) {
-			restore_flags(flags);
+			spin_unlock_bh(&nr_list_lock);
 			return s;
 		}
 	}
-
-	restore_flags(flags);
+	spin_unlock_bh(&nr_list_lock);
 
 	return NULL;
 }
@@ -242,25 +208,22 @@
 /*
  *	Find a connected NET/ROM socket given their circuit IDs.
  */
-static struct sock *nr_find_peer(unsigned char index, unsigned char id, ax25_address *dest)
+static struct sock *nr_find_peer(unsigned char index, unsigned char id,
+	ax25_address *dest)
 {
 	struct sock *s;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
 
+	spin_lock_bh(&nr_list_lock);
 	for (s = nr_list; s != NULL; s = s->next) {
 		nr_cb *nr = nr_sk(s);
 		
 		if (nr->your_index == index && nr->your_id == id &&
 		    !ax25cmp(&nr->dest_addr, dest)) {
-			restore_flags(flags);
+			spin_unlock_bh(&nr_list_lock);
 			return s;
 		}
 	}
-
-	restore_flags(flags);
+	spin_unlock_bh(&nr_list_lock);
 
 	return NULL;
 }
@@ -301,17 +264,16 @@
 }
 
 /*
- *	This is called from user mode and the timers. Thus it protects itself against
- *	interrupt users but doesn't worry about being called during work.
- *	Once it is removed from the queue no interrupt or bottom half will
- *	touch it and we are (fairly 8-) ) safe.
+ *	This is called from user mode and the timers. Thus it protects itself
+ *	against interrupt users but doesn't worry about being called during
+ *	work. Once it is removed from the queue no interrupt or bottom half
+ *	will touch it and we are (fairly 8-) ) safe.
  */
-void nr_destroy_socket(struct sock *sk)	/* Not static as it's used by the timer */
+void nr_destroy_socket(struct sock *sk)
 {
 	struct sk_buff *skb;
-	unsigned long flags;
 
-	save_flags(flags); cli();
+	nr_remove_socket(sk);
 
 	nr_stop_heartbeat(sk);
 	nr_stop_t1timer(sk);
@@ -319,7 +281,6 @@
 	nr_stop_t4timer(sk);
 	nr_stop_idletimer(sk);
 
-	nr_remove_socket(sk);
 	nr_clear_queues(sk);		/* Flush the queues */
 
 	while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
@@ -342,8 +303,6 @@
 	} else {
 		nr_free_sock(sk);
 	}
-
-	restore_flags(flags);
 }
 
 /*
@@ -368,38 +327,38 @@
 		return -EFAULT;
 
 	switch (optname) {
-		case NETROM_T1:
-			if (opt < 1)
-				return -EINVAL;
-			nr->t1 = opt * HZ;
-			return 0;
-
-		case NETROM_T2:
-			if (opt < 1)
-				return -EINVAL;
-			nr->t2 = opt * HZ;
-			return 0;
-
-		case NETROM_N2:
-			if (opt < 1 || opt > 31)
-				return -EINVAL;
-			nr->n2 = opt;
-			return 0;
-
-		case NETROM_T4:
-			if (opt < 1)
-				return -EINVAL;
-			nr->t4 = opt * HZ;
-			return 0;
-
-		case NETROM_IDLE:
-			if (opt < 0)
-				return -EINVAL;
-			nr->idle = opt * 60 * HZ;
-			return 0;
+	case NETROM_T1:
+		if (opt < 1)
+			return -EINVAL;
+		nr->t1 = opt * HZ;
+		return 0;
+
+	case NETROM_T2:
+		if (opt < 1)
+			return -EINVAL;
+		nr->t2 = opt * HZ;
+		return 0;
 
-		default:
-			return -ENOPROTOOPT;
+	case NETROM_N2:
+		if (opt < 1 || opt > 31)
+			return -EINVAL;
+		nr->n2 = opt;
+		return 0;
+
+	case NETROM_T4:
+		if (opt < 1)
+			return -EINVAL;
+		nr->t4 = opt * HZ;
+		return 0;
+
+	case NETROM_IDLE:
+		if (opt < 0)
+			return -EINVAL;
+		nr->idle = opt * 60 * HZ;
+		return 0;
+
+	default:
+		return -ENOPROTOOPT;
 	}
 }
 
@@ -421,28 +380,28 @@
 		return -EINVAL;
 		
 	switch (optname) {
-		case NETROM_T1:
-			val = nr->t1 / HZ;
-			break;
-
-		case NETROM_T2:
-			val = nr->t2 / HZ;
-			break;
-
-		case NETROM_N2:
-			val = nr->n2;
-			break;
-
-		case NETROM_T4:
-			val = nr->t4 / HZ;
-			break;
-
-		case NETROM_IDLE:
-			val = nr->idle / (60 * HZ);
-			break;
+	case NETROM_T1:
+		val = nr->t1 / HZ;
+		break;
+
+	case NETROM_T2:
+		val = nr->t2 / HZ;
+		break;
+
+	case NETROM_N2:
+		val = nr->n2;
+		break;
+
+	case NETROM_T4:
+		val = nr->t4 / HZ;
+		break;
+
+	case NETROM_IDLE:
+		val = nr->idle / (60 * HZ);
+		break;
 
-		default:
-			return -ENOPROTOOPT;
+	default:
+		return -ENOPROTOOPT;
 	}
 
 	len = min_t(unsigned int, len, sizeof(int));
@@ -567,34 +526,33 @@
 	nr = nr_sk(sk);
 
 	switch (nr->state) {
-
-		case NR_STATE_0:
-		case NR_STATE_1:
-		case NR_STATE_2:
-			nr_disconnect(sk, 0);
-			nr_destroy_socket(sk);
-			break;
-
-		case NR_STATE_3:
-			nr_clear_queues(sk);
-			nr->n2count = 0;
-			nr_write_internal(sk, NR_DISCREQ);
-			nr_start_t1timer(sk);
-			nr_stop_t2timer(sk);
-			nr_stop_t4timer(sk);
-			nr_stop_idletimer(sk);
-			nr->state    = NR_STATE_2;
-			sk->state    = TCP_CLOSE;
-			sk->shutdown |= SEND_SHUTDOWN;
-			sk->state_change(sk);
-			sk->dead     = 1;
-			sk->destroy  = 1;
-			sk->socket   = NULL;
-			break;
-
-		default:
-			sk->socket = NULL;
-			break;
+	case NR_STATE_0:
+	case NR_STATE_1:
+	case NR_STATE_2:
+		nr_disconnect(sk, 0);
+		nr_destroy_socket(sk);
+		break;
+
+	case NR_STATE_3:
+		nr_clear_queues(sk);
+		nr->n2count = 0;
+		nr_write_internal(sk, NR_DISCREQ);
+		nr_start_t1timer(sk);
+		nr_stop_t2timer(sk);
+		nr_stop_t4timer(sk);
+		nr_stop_idletimer(sk);
+		nr->state    = NR_STATE_2;
+		sk->state    = TCP_CLOSE;
+		sk->shutdown |= SEND_SHUTDOWN;
+		sk->state_change(sk);
+		sk->dead     = 1;
+		sk->destroy  = 1;
+		sk->socket   = NULL;
+		break;
+
+	default:
+		sk->socket = NULL;
+		break;
 	}
 
 	sock->sk   = NULL;	
@@ -732,78 +690,98 @@
 	if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
 		return -EINPROGRESS;
 		
-	cli();	/* To avoid races on the sleep */
-
 	/*
-	 * A Connect Ack with Choke or timeout or failed routing will go to closed.
+	 * A Connect Ack with Choke or timeout or failed routing will go to
+	 * closed.
 	 */
-	while (sk->state == TCP_SYN_SENT) {
-		interruptible_sleep_on(sk->sleep);
-		if (signal_pending(current)) {
-			sti();
+	if (sk->state == TCP_SYN_SENT) {
+		struct task_struct *tsk = current;
+		DECLARE_WAITQUEUE(wait, tsk);
+
+		add_wait_queue(sk->sleep, &wait);
+		for (;;) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			if (sk->state != TCP_SYN_SENT)
+				break;
+			if (!signal_pending(tsk)) {
+				schedule();
+				continue;
+			}
 			return -ERESTARTSYS;
 		}
+		current->state = TASK_RUNNING;
+		remove_wait_queue(sk->sleep, &wait);
 	}
 
 	if (sk->state != TCP_ESTABLISHED) {
-		sti();
 		sock->state = SS_UNCONNECTED;
 		return sock_error(sk);	/* Always set at this point */
 	}
 
 	sock->state = SS_CONNECTED;
 
-	sti();
-
 	return 0;
 }
 
 static int nr_accept(struct socket *sock, struct socket *newsock, int flags)
 {
-	struct sock *sk;
-	struct sock *newsk;
+	struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
 	struct sk_buff *skb;
+	struct sock *newsk;
+	struct sock *sk;
+	int err = 0;
 
 	if ((sk = sock->sk) == NULL)
 		return -EINVAL;
 
-	if (sk->type != SOCK_SEQPACKET)
-		return -EOPNOTSUPP;
+	lock_sock(sk);
+	if (sk->type != SOCK_SEQPACKET) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
 
-	if (sk->state != TCP_LISTEN)
-		return -EINVAL;
+	if (sk->state != TCP_LISTEN) {
+		err = -EINVAL;
+		goto out;
+	}
 
 	/*
 	 *	The write queue this time is holding sockets ready to use
 	 *	hooked into the SABM we saved
 	 */
-	do {
-		cli();
-		if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {
-			if (flags & O_NONBLOCK) {
-				sti();
-				return -EWOULDBLOCK;
-			}
-			interruptible_sleep_on(sk->sleep);
-			if (signal_pending(current)) {
-				sti();
-				return -ERESTARTSYS;
-			}
+	add_wait_queue(sk->sleep, &wait);
+	for (;;) {
+		skb = skb_dequeue(&sk->receive_queue);
+		if (skb)
+			break;
+
+		current->state = TASK_INTERRUPTIBLE;
+		release_sock(sk);
+		if (flags & O_NONBLOCK)
+			return -EWOULDBLOCK;
+		if (!signal_pending(tsk)) {
+			schedule();
+			lock_sock(sk);
+			continue;
 		}
-	} while (skb == NULL);
+		return -ERESTARTSYS;
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(sk->sleep, &wait);
 
 	newsk = skb->sk;
 	newsk->pair = NULL;
 	newsk->socket = newsock;
 	newsk->sleep = &newsock->wait;
-	sti();
 
 	/* Now attach up the new socket */
 	kfree_skb(skb);
 	sk->ack_backlog--;
 	newsock->sk = newsk;
 
-	return 0;
+out:
+	return err;
 }
 
 static int nr_getname(struct socket *sock, struct sockaddr *uaddr,
@@ -1127,54 +1105,53 @@
 	struct sock *sk = sock->sk;
 
 	switch (cmd) {
-		case TIOCOUTQ: {
-			long amount;
-			amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
-			if (amount < 0)
-				amount = 0;
-			return put_user(amount, (int *)arg);
-		}
-
-		case TIOCINQ: {
-			struct sk_buff *skb;
-			long amount = 0L;
-			/* These two are safe on a single CPU system as only user tasks fiddle here */
-			if ((skb = skb_peek(&sk->receive_queue)) != NULL)
-				amount = skb->len;
-			return put_user(amount, (int *)arg);
+	case TIOCOUTQ: {
+		long amount;
+		amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
+		if (amount < 0)
+			amount = 0;
+		return put_user(amount, (int *)arg);
+	}
+
+	case TIOCINQ: {
+		struct sk_buff *skb;
+		long amount = 0L;
+		/* These two are safe on a single CPU system as only user tasks fiddle here */
+		if ((skb = skb_peek(&sk->receive_queue)) != NULL)
+			amount = skb->len;
+		return put_user(amount, (int *)arg);
+	}
+
+	case SIOCGSTAMP:
+		if (sk != NULL) {
+			if (sk->stamp.tv_sec == 0)
+				return -ENOENT;
+			return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0;
 		}
+		return -EINVAL;
 
-		case SIOCGSTAMP:
-			if (sk != NULL) {
-				if (sk->stamp.tv_sec == 0)
-					return -ENOENT;
-				return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0;
-			}
-			return -EINVAL;
-
-		case SIOCGIFADDR:
-		case SIOCSIFADDR:
-		case SIOCGIFDSTADDR:
-		case SIOCSIFDSTADDR:
-		case SIOCGIFBRDADDR:
-		case SIOCSIFBRDADDR:
-		case SIOCGIFNETMASK:
-		case SIOCSIFNETMASK:
-		case SIOCGIFMETRIC:
-		case SIOCSIFMETRIC:
-			return -EINVAL;
+	case SIOCGIFADDR:
+	case SIOCSIFADDR:
+	case SIOCGIFDSTADDR:
+	case SIOCSIFDSTADDR:
+	case SIOCGIFBRDADDR:
+	case SIOCSIFBRDADDR:
+	case SIOCGIFNETMASK:
+	case SIOCSIFNETMASK:
+	case SIOCGIFMETRIC:
+	case SIOCSIFMETRIC:
+		return -EINVAL;
 
-		case SIOCADDRT:
-		case SIOCDELRT:
-		case SIOCNRDECOBS:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return nr_rt_ioctl(cmd, (void *)arg);
+	case SIOCADDRT:
+	case SIOCDELRT:
+	case SIOCNRDECOBS:
+		if (!capable(CAP_NET_ADMIN)) return -EPERM;
+		return nr_rt_ioctl(cmd, (void *)arg);
 
- 		default:
-			return dev_ioctl(cmd, (void *)arg);
+	default:
+		return dev_ioctl(cmd, (void *)arg);
 	}
 
-	/*NOTREACHED*/
 	return 0;
 }
 
@@ -1187,7 +1164,7 @@
 	off_t pos = 0;
 	off_t begin = 0;
 
-	cli();
+	spin_lock_bh(&nr_list_lock);
 
 	len += sprintf(buffer, "user_addr dest_node src_node  dev    my  your  st  vs  vr  va    t1     t2     t4      idle   n2  wnd Snd-Q Rcv-Q inode\n");
 
@@ -1240,47 +1217,45 @@
 			break;
 	}
 
-	sti();
+	spin_unlock_bh(&nr_list_lock);
 
 	*start = buffer + (offset - begin);
 	len   -= (offset - begin);
 
-	if (len > length) len = length;
+	if (len > length)
+		len = length;
 
-	return(len);
-} 
+	return len;
+}
 
 static struct net_proto_family nr_family_ops = {
-	.family =	PF_NETROM,
-	.create =	nr_create,
+	.family		=	PF_NETROM,
+	.create		=	nr_create,
 };
 
-static struct proto_ops SOCKOPS_WRAPPED(nr_proto_ops) = {
-	.family =	PF_NETROM,
+static struct proto_ops nr_proto_ops = {
+	.family		=	PF_NETROM,
 
-	.release =	nr_release,
-	.bind =		nr_bind,
-	.connect =	nr_connect,
-	.socketpair =	sock_no_socketpair,
-	.accept =	nr_accept,
-	.getname =	nr_getname,
-	.poll =		datagram_poll,
-	.ioctl =	nr_ioctl,
-	.listen =	nr_listen,
-	.shutdown =	sock_no_shutdown,
-	.setsockopt =	nr_setsockopt,
-	.getsockopt =	nr_getsockopt,
-	.sendmsg =	nr_sendmsg,
-	.recvmsg =	nr_recvmsg,
-	.mmap =		sock_no_mmap,
-	.sendpage =	sock_no_sendpage,
+	.release	=	nr_release,
+	.bind		=	nr_bind,
+	.connect	=	nr_connect,
+	.socketpair	=	sock_no_socketpair,
+	.accept		=	nr_accept,
+	.getname	=	nr_getname,
+	.poll		=	datagram_poll,
+	.ioctl		=	nr_ioctl,
+	.listen		=	nr_listen,
+	.shutdown	=	sock_no_shutdown,
+	.setsockopt	=	nr_setsockopt,
+	.getsockopt	=	nr_getsockopt,
+	.sendmsg	=	nr_sendmsg,
+	.recvmsg	=	nr_recvmsg,
+	.mmap		=	sock_no_mmap,
+	.sendpage	=	sock_no_sendpage,
 };
 
-#include <linux/smp_lock.h>
-SOCKOPS_WRAP(nr_proto, PF_NETROM);
-
 static struct notifier_block nr_dev_notifier = {
-	.notifier_call =nr_device_event,
+	.notifier_call	=	nr_device_event,
 };
 
 static struct net_device *dev_nr;
diff -Nru a/net/netrom/nr_dev.c b/net/netrom/nr_dev.c
--- a/net/netrom/nr_dev.c	Fri Sep 20 08:20:47 2002
+++ b/net/netrom/nr_dev.c	Fri Sep 20 08:20:47 2002
@@ -1,23 +1,11 @@
 /*
- *	NET/ROM release 007
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	History
- *	NET/ROM 001	Jonathan(G4KLX)	Cloned from loopback.c
- *	NET/ROM 002	Steve Whitehouse(GW7RRM) fixed the set_mac_address
- *	NET/ROM 003	Jonathan(G4KLX)	Put nr_rebuild_header into line with
- *					ax25_rebuild_header
- *	NET/ROM 004	Jonathan(G4KLX)	Callsign registration with AX.25.
- *	NET/ROM 006	Hans(PE1AYX)	Fixed interface to IP layer.
+ * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
  */
-
 #include <linux/config.h>
 #define __NO_VERSION__
 #include <linux/module.h>
@@ -115,7 +103,7 @@
 	kfree_skb(skb);
 
 	len = skbn->len;
-	
+
 	if (!nr_route_frame(skbn, NULL)) {
 		kfree_skb(skbn);
 		stats->tx_errors++;
diff -Nru a/net/netrom/nr_in.c b/net/netrom/nr_in.c
--- a/net/netrom/nr_in.c	Fri Sep 20 08:20:44 2002
+++ b/net/netrom/nr_in.c	Fri Sep 20 08:20:44 2002
@@ -1,29 +1,12 @@
 /*
- *	NET/ROM release 007
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	Most of this code is based on the SDL diagrams published in the 7th
- *	ARRL Computer Networking Conference papers. The diagrams have mistakes
- *	in them, but are mostly correct. Before you modify the code could you
- *	read the SDL diagrams as the code is not obvious and probably very
- *	easy to break;
- *
- *	History
- *	NET/ROM 001	Jonathan(G4KLX)	Cloned from ax25_in.c
- *	NET/ROM 003	Jonathan(G4KLX)	Added NET/ROM fragment reception.
- *			Darryl(G7LED)	Added missing INFO with NAK case, optimized
- *					INFOACK handling, removed reconnect on error.
- *	NET/ROM 006	Jonathan(G4KLX)	Hdrincl removal changes.
- *	NET/ROM 007	Jonathan(G4KLX)	New timer architecture.
+ * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright Darryl Miles G7LED (dlm@g7led.demon.co.uk)
  */
-
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -77,7 +60,7 @@
 			kfree_skb(skbo);
 		}
 
-		nr->fraglen = 0;		
+		nr->fraglen = 0;
 	}
 
 	return sock_queue_rcv_skb(sk, skbn);
@@ -88,36 +71,36 @@
  * The handling of the timer(s) is in file nr_timer.c.
  * Handling of state 0 and connection release is in netrom.c.
  */
-static int nr_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype)
+static int nr_state1_machine(struct sock *sk, struct sk_buff *skb,
+	int frametype)
 {
 	switch (frametype) {
+	case NR_CONNACK: {
+		nr_cb *nr = nr_sk(sk);
 
-		case NR_CONNACK: {
-			nr_cb *nr = nr_sk(sk);
-
-			nr_stop_t1timer(sk);
-			nr_start_idletimer(sk);
-			nr->your_index = skb->data[17];
-			nr->your_id    = skb->data[18];
-			nr->vs	       = 0;
-			nr->va	       = 0;
-			nr->vr	       = 0;
-			nr->vl	       = 0;
-			nr->state      = NR_STATE_3;
-			nr->n2count    = 0;
-			nr->window     = skb->data[20];
-			sk->state      = TCP_ESTABLISHED;
-			if (!sk->dead)
-				sk->state_change(sk);
-			break;
-		}
+		nr_stop_t1timer(sk);
+		nr_start_idletimer(sk);
+		nr->your_index = skb->data[17];
+		nr->your_id    = skb->data[18];
+		nr->vs	       = 0;
+		nr->va	       = 0;
+		nr->vr	       = 0;
+		nr->vl	       = 0;
+		nr->state      = NR_STATE_3;
+		nr->n2count    = 0;
+		nr->window     = skb->data[20];
+		sk->state      = TCP_ESTABLISHED;
+		if (!sk->dead)
+			sk->state_change(sk);
+		break;
+	}
 
-		case NR_CONNACK | NR_CHOKE_FLAG:
-			nr_disconnect(sk, ECONNREFUSED);
-			break;
+	case NR_CONNACK | NR_CHOKE_FLAG:
+		nr_disconnect(sk, ECONNREFUSED);
+		break;
 
-		default:
-			break;
+	default:
+		break;
 	}
 
 	return 0;
@@ -128,23 +111,23 @@
  * The handling of the timer(s) is in file nr_timer.c
  * Handling of state 0 and connection release is in netrom.c.
  */
-static int nr_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype)
+static int nr_state2_machine(struct sock *sk, struct sk_buff *skb,
+	int frametype)
 {
 	switch (frametype) {
+	case NR_CONNACK | NR_CHOKE_FLAG:
+		nr_disconnect(sk, ECONNRESET);
+		break;
+
+	case NR_DISCREQ:
+		nr_write_internal(sk, NR_DISCACK);
+
+	case NR_DISCACK:
+		nr_disconnect(sk, 0);
+		break;
 
-		case NR_CONNACK | NR_CHOKE_FLAG:
-			nr_disconnect(sk, ECONNRESET);
-			break;
-
-		case NR_DISCREQ:
-			nr_write_internal(sk, NR_DISCACK);
-
-		case NR_DISCACK:
-			nr_disconnect(sk, 0);
-			break;
-
-		default:
-			break;
+	default:
+		break;
 	}
 
 	return 0;
@@ -168,35 +151,62 @@
 	ns = skb->data[17];
 
 	switch (frametype) {
-
-		case NR_CONNREQ:
-			nr_write_internal(sk, NR_CONNACK);
-			break;
-
-		case NR_DISCREQ:
-			nr_write_internal(sk, NR_DISCACK);
-			nr_disconnect(sk, 0);
-			break;
-
-		case NR_CONNACK | NR_CHOKE_FLAG:
-		case NR_DISCACK:
-			nr_disconnect(sk, ECONNRESET);
+	case NR_CONNREQ:
+		nr_write_internal(sk, NR_CONNACK);
+		break;
+
+	case NR_DISCREQ:
+		nr_write_internal(sk, NR_DISCACK);
+		nr_disconnect(sk, 0);
+		break;
+
+	case NR_CONNACK | NR_CHOKE_FLAG:
+	case NR_DISCACK:
+		nr_disconnect(sk, ECONNRESET);
+		break;
+
+	case NR_INFOACK:
+	case NR_INFOACK | NR_CHOKE_FLAG:
+	case NR_INFOACK | NR_NAK_FLAG:
+	case NR_INFOACK | NR_NAK_FLAG | NR_CHOKE_FLAG:
+		if (frametype & NR_CHOKE_FLAG) {
+			nrom->condition |= NR_COND_PEER_RX_BUSY;
+			nr_start_t4timer(sk);
+		} else {
+			nrom->condition &= ~NR_COND_PEER_RX_BUSY;
+			nr_stop_t4timer(sk);
+		}
+		if (!nr_validate_nr(sk, nr)) {
 			break;
-
-		case NR_INFOACK:
-		case NR_INFOACK | NR_CHOKE_FLAG:
-		case NR_INFOACK | NR_NAK_FLAG:
-		case NR_INFOACK | NR_NAK_FLAG | NR_CHOKE_FLAG:
-			if (frametype & NR_CHOKE_FLAG) {
-				nrom->condition |= NR_COND_PEER_RX_BUSY;
-				nr_start_t4timer(sk);
+		}
+		if (frametype & NR_NAK_FLAG) {
+			nr_frames_acked(sk, nr);
+			nr_send_nak_frame(sk);
+		} else {
+			if (nrom->condition & NR_COND_PEER_RX_BUSY) {
+				nr_frames_acked(sk, nr);
 			} else {
-				nrom->condition &= ~NR_COND_PEER_RX_BUSY;
-				nr_stop_t4timer(sk);
-			}
-			if (!nr_validate_nr(sk, nr)) {
-				break;
+				nr_check_iframes_acked(sk, nr);
 			}
+		}
+		break;
+
+	case NR_INFO:
+	case NR_INFO | NR_NAK_FLAG:
+	case NR_INFO | NR_CHOKE_FLAG:
+	case NR_INFO | NR_MORE_FLAG:
+	case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG:
+	case NR_INFO | NR_CHOKE_FLAG | NR_MORE_FLAG:
+	case NR_INFO | NR_NAK_FLAG | NR_MORE_FLAG:
+	case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG | NR_MORE_FLAG:
+		if (frametype & NR_CHOKE_FLAG) {
+			nrom->condition |= NR_COND_PEER_RX_BUSY;
+			nr_start_t4timer(sk);
+		} else {
+			nrom->condition &= ~NR_COND_PEER_RX_BUSY;
+			nr_stop_t4timer(sk);
+		}
+		if (nr_validate_nr(sk, nr)) {
 			if (frametype & NR_NAK_FLAG) {
 				nr_frames_acked(sk, nr);
 				nr_send_nak_frame(sk);
@@ -207,76 +217,48 @@
 					nr_check_iframes_acked(sk, nr);
 				}
 			}
-			break;
-
-		case NR_INFO:
-		case NR_INFO | NR_NAK_FLAG:
-		case NR_INFO | NR_CHOKE_FLAG:
-		case NR_INFO | NR_MORE_FLAG:
-		case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG:
-		case NR_INFO | NR_CHOKE_FLAG | NR_MORE_FLAG:
-		case NR_INFO | NR_NAK_FLAG | NR_MORE_FLAG:
-		case NR_INFO | NR_NAK_FLAG | NR_CHOKE_FLAG | NR_MORE_FLAG:
-			if (frametype & NR_CHOKE_FLAG) {
-				nrom->condition |= NR_COND_PEER_RX_BUSY;
-				nr_start_t4timer(sk);
-			} else {
-				nrom->condition &= ~NR_COND_PEER_RX_BUSY;
-				nr_stop_t4timer(sk);
-			}
-			if (nr_validate_nr(sk, nr)) {
-				if (frametype & NR_NAK_FLAG) {
-					nr_frames_acked(sk, nr);
-					nr_send_nak_frame(sk);
-				} else {
-					if (nrom->condition & NR_COND_PEER_RX_BUSY) {
-						nr_frames_acked(sk, nr);
+		}
+		queued = 1;
+		skb_queue_head(&nrom->reseq_queue, skb);
+		if (nrom->condition & NR_COND_OWN_RX_BUSY)
+			break;
+		skb_queue_head_init(&temp_queue);
+		do {
+			save_vr = nrom->vr;
+			while ((skbn = skb_dequeue(&nrom->reseq_queue)) != NULL) {
+				ns = skbn->data[17];
+				if (ns == nrom->vr) {
+					if (nr_queue_rx_frame(sk, skbn, frametype & NR_MORE_FLAG) == 0) {
+						nrom->vr = (nrom->vr + 1) % NR_MODULUS;
 					} else {
-						nr_check_iframes_acked(sk, nr);
-					}
-				}
-			}
-			queued = 1;
-			skb_queue_head(&nrom->reseq_queue, skb);
-			if (nrom->condition & NR_COND_OWN_RX_BUSY)
-				break;
-			skb_queue_head_init(&temp_queue);
-			do {
-				save_vr = nrom->vr;
-				while ((skbn = skb_dequeue(&nrom->reseq_queue)) != NULL) {
-					ns = skbn->data[17];
-					if (ns == nrom->vr) {
-						if (nr_queue_rx_frame(sk, skbn, frametype & NR_MORE_FLAG) == 0) {
-							nrom->vr = (nrom->vr + 1) % NR_MODULUS;
-						} else {
-							nrom->condition |= NR_COND_OWN_RX_BUSY;
-							skb_queue_tail(&temp_queue, skbn);
-						}
-					} else if (nr_in_rx_window(sk, ns)) {
+						nrom->condition |= NR_COND_OWN_RX_BUSY;
 						skb_queue_tail(&temp_queue, skbn);
-					} else {
-						kfree_skb(skbn);
 					}
-				}
-				while ((skbn = skb_dequeue(&temp_queue)) != NULL) {
-					skb_queue_tail(&nrom->reseq_queue, skbn);
-				}
-			} while (save_vr != nrom->vr);
-			/*
-			 * Window is full, ack it immediately.
-			 */
-			if (((nrom->vl + nrom->window) % NR_MODULUS) == nrom->vr) {
-				nr_enquiry_response(sk);
-			} else {
-				if (!(nrom->condition & NR_COND_ACK_PENDING)) {
-					nrom->condition |= NR_COND_ACK_PENDING;
-					nr_start_t2timer(sk);
+				} else if (nr_in_rx_window(sk, ns)) {
+					skb_queue_tail(&temp_queue, skbn);
+				} else {
+					kfree_skb(skbn);
 				}
 			}
-			break;
+			while ((skbn = skb_dequeue(&temp_queue)) != NULL) {
+				skb_queue_tail(&nrom->reseq_queue, skbn);
+			}
+		} while (save_vr != nrom->vr);
+		/*
+		 * Window is full, ack it immediately.
+		 */
+		if (((nrom->vl + nrom->window) % NR_MODULUS) == nrom->vr) {
+			nr_enquiry_response(sk);
+		} else {
+			if (!(nrom->condition & NR_COND_ACK_PENDING)) {
+				nrom->condition |= NR_COND_ACK_PENDING;
+				nr_start_t2timer(sk);
+			}
+		}
+		break;
 
-		default:
-			break;
+	default:
+		break;
 	}
 
 	return queued;
@@ -294,15 +276,15 @@
 	frametype = skb->data[19];
 
 	switch (nr->state) {
-		case NR_STATE_1:
-			queued = nr_state1_machine(sk, skb, frametype);
-			break;
-		case NR_STATE_2:
-			queued = nr_state2_machine(sk, skb, frametype);
-			break;
-		case NR_STATE_3:
-			queued = nr_state3_machine(sk, skb, frametype);
-			break;
+	case NR_STATE_1:
+		queued = nr_state1_machine(sk, skb, frametype);
+		break;
+	case NR_STATE_2:
+		queued = nr_state2_machine(sk, skb, frametype);
+		break;
+	case NR_STATE_3:
+		queued = nr_state3_machine(sk, skb, frametype);
+		break;
 	}
 
 	nr_kick(sk);
diff -Nru a/net/netrom/nr_loopback.c b/net/netrom/nr_loopback.c
--- a/net/netrom/nr_loopback.c	Fri Sep 20 08:20:47 2002
+++ b/net/netrom/nr_loopback.c	Fri Sep 20 08:20:47 2002
@@ -1,20 +1,11 @@
 /*
- *	NET/ROM release 007
- *
- *	This code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	History
- *	NET/ROM 007	Tomi(OH2BNS)	Created this file.
- *                                      Small change in nr_loopback_queue().
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
+ * Copyright Tomi Manninen OH2BNS (oh2bns@sral.fi)
  */
-
 #include <linux/types.h>
 #include <linux/socket.h>
 #include <linux/timer.h>
diff -Nru a/net/netrom/nr_out.c b/net/netrom/nr_out.c
--- a/net/netrom/nr_out.c	Fri Sep 20 08:20:46 2002
+++ b/net/netrom/nr_out.c	Fri Sep 20 08:20:46 2002
@@ -1,21 +1,12 @@
 /*
- *	NET/ROM release 007
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	History
- *	NET/ROM 001	Jonathan(G4KLX)	Cloned from ax25_out.c
- *	NET/ROM 003	Jonathan(G4KLX)	Added NET/ROM fragmentation.
- *			Darryl(G7LED)	Fixed NAK, to give out correct reponse.
- *	NET/ROM 007	Jonathan(G4KLX)	New timer architecture.
+ * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright Darryl Miles G7LED (dlm@g7led.demon.co.uk)
  */
-
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -85,7 +76,7 @@
 	nr_kick(sk);
 }
 
-/* 
+/*
  *	This procedure is passed a buffer descriptor for an iframe. It builds
  *	the rest of the control part of the frame and then writes it out.
  */
@@ -104,7 +95,7 @@
 
 	nr_start_idletimer(sk);
 
-	nr_transmit_buffer(sk, skb);	
+	nr_transmit_buffer(sk, skb);
 }
 
 void nr_send_nak_frame(struct sock *sk)
@@ -196,7 +187,7 @@
 
 void nr_transmit_buffer(struct sock *sk, struct sk_buff *skb)
 {
-	nr_cb *nr = nr;
+	nr_cb *nr = nr_sk(sk);
 	unsigned char *dptr;
 
 	/*
diff -Nru a/net/netrom/nr_route.c b/net/netrom/nr_route.c
--- a/net/netrom/nr_route.c	Fri Sep 20 08:20:48 2002
+++ b/net/netrom/nr_route.c	Fri Sep 20 08:20:48 2002
@@ -1,26 +1,13 @@
 /*
- *	NET/ROM release 007
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	History
- *	NET/ROM 001	Jonathan(G4KLX)	First attempt.
- *	NET/ROM	003	Jonathan(G4KLX)	Use SIOCADDRT/SIOCDELRT ioctl values
- *					for NET/ROM routes.
- *					Use '*' for a blank mnemonic in /proc/net/nr_nodes.
- *					Change default quality for new neighbour when same
- *					as node callsign.
- *			Alan Cox(GW4PTS) Added the firewall hooks.
- *	NET/ROM 006	Jonathan(G4KLX)	Added the setting of digipeated neighbours.
- *			Tomi(OH2BNS)	Routing quality and link failure changes.
+ * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
+ * Copyright Tomi Manninen OH2BNS (oh2bns@sral.fi)
  */
-
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -47,12 +34,15 @@
 #include <linux/notifier.h>
 #include <linux/netfilter.h>
 #include <linux/init.h>
+#include <linux/spinlock.h>
 #include <net/netrom.h>
 
 static unsigned int nr_neigh_no = 1;
 
 static struct nr_node  *nr_node_list;
+static spinlock_t nr_node_lock;
 static struct nr_neigh *nr_neigh_list;
+static spinlock_t nr_neigh_lock;
 
 static void nr_remove_neigh(struct nr_neigh *);
 
@@ -66,7 +56,6 @@
 	struct nr_node  *nr_node;
 	struct nr_neigh *nr_neigh;
 	struct nr_route nr_route;
-	unsigned long flags;
 	int i, found;
 
 	if (nr_dev_get(nr) != NULL)	/* Can't add routes to ourself */
@@ -124,13 +113,10 @@
 			memcpy(nr_neigh->digipeat, ax25_digi, sizeof(ax25_digi));
 		}
 
-		save_flags(flags);
-		cli();
-
+		spin_lock_bh(&nr_neigh_lock);
 		nr_neigh->next = nr_neigh_list;
 		nr_neigh_list  = nr_neigh;
-
-		restore_flags(flags);
+		spin_unlock_bh(&nr_neigh_lock);
 	}
 
 	if (quality != 0 && ax25cmp(nr, ax25) == 0 && !nr_neigh->locked)
@@ -150,13 +136,10 @@
 		nr_node->routes[0].obs_count = obs_count;
 		nr_node->routes[0].neighbour = nr_neigh;
 
-		save_flags(flags);
-		cli();
-
+		spin_lock_bh(&nr_node_lock);
 		nr_node->next = nr_node_list;
 		nr_node_list  = nr_node;
-
-		restore_flags(flags);
+		spin_unlock_bh(&nr_node_lock);
 
 		nr_neigh->count++;
 
@@ -207,40 +190,49 @@
 
 	/* Now re-sort the routes in quality order */
 	switch (nr_node->count) {
-		case 3:
-			if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
-				switch (nr_node->which) {
-					case 0:  nr_node->which = 1; break;
-					case 1:  nr_node->which = 0; break;
-					default: break;
-				}
-				nr_route           = nr_node->routes[0];
-				nr_node->routes[0] = nr_node->routes[1];
-				nr_node->routes[1] = nr_route;
+	case 3:
+		if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
+			switch (nr_node->which) {
+				case 0:  nr_node->which = 1; break;
+				case 1:  nr_node->which = 0; break;
+				default: break;
 			}
-			if (nr_node->routes[2].quality > nr_node->routes[1].quality) {
-				switch (nr_node->which) {
-					case 1:  nr_node->which = 2; break;
-					case 2:  nr_node->which = 1; break;
-					default: break;
-				}
-				nr_route           = nr_node->routes[1];
-				nr_node->routes[1] = nr_node->routes[2];
-				nr_node->routes[2] = nr_route;
+			nr_route           = nr_node->routes[0];
+			nr_node->routes[0] = nr_node->routes[1];
+			nr_node->routes[1] = nr_route;
+		}
+		if (nr_node->routes[2].quality > nr_node->routes[1].quality) {
+			switch (nr_node->which) {
+			case 1:  nr_node->which = 2;
+				break;
+
+			case 2:  nr_node->which = 1;
+				break;
+
+			default:
+				break;
 			}
-		case 2:
-			if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
-				switch (nr_node->which) {
-					case 0:  nr_node->which = 1; break;
-					case 1:  nr_node->which = 0; break;
-					default: break;
-				}
-				nr_route           = nr_node->routes[0];
-				nr_node->routes[0] = nr_node->routes[1];
-				nr_node->routes[1] = nr_route;
+			nr_route           = nr_node->routes[1];
+			nr_node->routes[1] = nr_node->routes[2];
+			nr_node->routes[2] = nr_route;
+		}
+	case 2:
+		if (nr_node->routes[1].quality > nr_node->routes[0].quality) {
+			switch (nr_node->which) {
+			case 0:  nr_node->which = 1;
+				break;
+
+			case 1:  nr_node->which = 0;
+				break;
+
+			default: break;
 			}
-		case 1:
-			break;
+			nr_route           = nr_node->routes[0];
+			nr_node->routes[0] = nr_node->routes[1];
+			nr_node->routes[1] = nr_route;
+			}
+	case 1:
+		break;
 	}
 
 	for (i = 0; i < nr_node->count; i++) {
@@ -257,14 +249,11 @@
 static void nr_remove_node(struct nr_node *nr_node)
 {
 	struct nr_node *s;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
 
+	spin_lock_bh(&nr_node_lock);
 	if ((s = nr_node_list) == nr_node) {
 		nr_node_list = nr_node->next;
-		restore_flags(flags);
+		spin_unlock_bh(&nr_node_lock);
 		kfree(nr_node);
 		return;
 	}
@@ -272,7 +261,7 @@
 	while (s != NULL && s->next != NULL) {
 		if (s->next == nr_node) {
 			s->next = nr_node->next;
-			restore_flags(flags);
+			spin_unlock_bh(&nr_node_lock);
 			kfree(nr_node);
 			return;
 		}
@@ -280,20 +269,17 @@
 		s = s->next;
 	}
 
-	restore_flags(flags);
+	spin_unlock_bh(&nr_node_lock);
 }
 
 static void nr_remove_neigh(struct nr_neigh *nr_neigh)
 {
 	struct nr_neigh *s;
-	unsigned long flags;
-	
-	save_flags(flags);
-	cli();
 
+	spin_lock_bh(&nr_neigh_lock);
 	if ((s = nr_neigh_list) == nr_neigh) {
 		nr_neigh_list = nr_neigh->next;
-		restore_flags(flags);
+		spin_unlock_bh(&nr_neigh_lock);
 		if (nr_neigh->digipeat != NULL)
 			kfree(nr_neigh->digipeat);
 		kfree(nr_neigh);
@@ -303,7 +289,7 @@
 	while (s != NULL && s->next != NULL) {
 		if (s->next == nr_neigh) {
 			s->next = nr_neigh->next;
-			restore_flags(flags);
+			spin_unlock_bh(&nr_neigh_lock);
 			if (nr_neigh->digipeat != NULL)
 				kfree(nr_neigh->digipeat);
 			kfree(nr_neigh);
@@ -312,8 +298,7 @@
 
 		s = s->next;
 	}
-
-	restore_flags(flags);
+	spin_unlock_bh(&nr_neigh_lock);
 }
 
 /*
@@ -330,13 +315,15 @@
 		if (ax25cmp(callsign, &nr_node->callsign) == 0)
 			break;
 
-	if (nr_node == NULL) return -EINVAL;
+	if (nr_node == NULL)
+		return -EINVAL;
 
 	for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next)
 		if (ax25cmp(neighbour, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev)
 			break;
 
-	if (nr_neigh == NULL) return -EINVAL;
+	if (nr_neigh == NULL)
+		return -EINVAL;
 
 	for (i = 0; i < nr_node->count; i++) {
 		if (nr_node->routes[i].neighbour == nr_neigh) {
@@ -351,12 +338,12 @@
 				nr_remove_node(nr_node);
 			} else {
 				switch (i) {
-					case 0:
-						nr_node->routes[0] = nr_node->routes[1];
-					case 1:
-						nr_node->routes[1] = nr_node->routes[2];
-					case 2:
-						break;
+				case 0:
+					nr_node->routes[0] = nr_node->routes[1];
+				case 1:
+					nr_node->routes[1] = nr_node->routes[2];
+				case 2:
+					break;
 				}
 			}
 
@@ -373,7 +360,6 @@
 static int nr_add_neigh(ax25_address *callsign, ax25_digi *ax25_digi, struct net_device *dev, unsigned int quality)
 {
 	struct nr_neigh *nr_neigh;
-	unsigned long flags;
 
 	for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) {
 		if (ax25cmp(callsign, &nr_neigh->callsign) == 0 && nr_neigh->dev == dev) {
@@ -404,15 +390,12 @@
 		memcpy(nr_neigh->digipeat, ax25_digi, sizeof(ax25_digi));
 	}
 
-	save_flags(flags);
-	cli();
-
+	spin_lock_bh(&nr_neigh_lock);
 	nr_neigh->next = nr_neigh_list;
 	nr_neigh_list  = nr_neigh;
+	spin_unlock_bh(&nr_neigh_lock);
 
-	restore_flags(flags);
-
-	return 0;	
+	return 0;
 }
 
 /*
@@ -457,7 +440,6 @@
 
 		for (i = 0; i < s->count; i++) {
 			switch (s->routes[i].obs_count) {
-
 			case 0:		/* A locked entry */
 				break;
 
@@ -520,12 +502,12 @@
 						t->count--;
 
 						switch (i) {
-							case 0:
-								t->routes[0] = t->routes[1];
-							case 1:
-								t->routes[1] = t->routes[2];
-							case 2:
-								break;
+						case 0:
+							t->routes[0] = t->routes[1];
+						case 1:
+							t->routes[1] = t->routes[2];
+						case 2:
+							break;
 						}
 					}
 				}
@@ -622,51 +604,50 @@
 	struct net_device *dev;
 
 	switch (cmd) {
+	case SIOCADDRT:
+		if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
+			return -EFAULT;
+		if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
+			return -EINVAL;
+		if (nr_route.ndigis < 0 || nr_route.ndigis > AX25_MAX_DIGIS)
+			return -EINVAL;
+		switch (nr_route.type) {
+		case NETROM_NODE:
+			return nr_add_node(&nr_route.callsign,
+				nr_route.mnemonic,
+				&nr_route.neighbour,
+				nr_call_to_digi(nr_route.ndigis, nr_route.digipeaters),
+				dev, nr_route.quality,
+				nr_route.obs_count);
+		case NETROM_NEIGH:
+			return nr_add_neigh(&nr_route.callsign,
+				nr_call_to_digi(nr_route.ndigis, nr_route.digipeaters),
+				dev, nr_route.quality);
+		default:
+			return -EINVAL;
+		}
 
-		case SIOCADDRT:
-			if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
-				return -EFAULT;
-			if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
-				return -EINVAL;
-			if (nr_route.ndigis < 0 || nr_route.ndigis > AX25_MAX_DIGIS)
-				return -EINVAL;
-			switch (nr_route.type) {
-				case NETROM_NODE:
-					return nr_add_node(&nr_route.callsign,
-						nr_route.mnemonic,
-						&nr_route.neighbour,
-						nr_call_to_digi(nr_route.ndigis, nr_route.digipeaters),
-						dev, nr_route.quality,
-						nr_route.obs_count);
-				case NETROM_NEIGH:
-					return nr_add_neigh(&nr_route.callsign,
-						nr_call_to_digi(nr_route.ndigis, nr_route.digipeaters),
-						dev, nr_route.quality);
-				default:
-					return -EINVAL;
-			}
-
-		case SIOCDELRT:
-			if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
-				return -EFAULT;
-			if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
-				return -EINVAL;
-			switch (nr_route.type) {
-				case NETROM_NODE:
-					return nr_del_node(&nr_route.callsign,
-						&nr_route.neighbour, dev);
-				case NETROM_NEIGH:
-					return nr_del_neigh(&nr_route.callsign,
-						dev, nr_route.quality);
-				default:
-					return -EINVAL;
-			}
-
-		case SIOCNRDECOBS:
-			return nr_dec_obs();
-
+	case SIOCDELRT:
+		if (copy_from_user(&nr_route, arg, sizeof(struct nr_route_struct)))
+			return -EFAULT;
+		if ((dev = nr_ax25_dev_get(nr_route.device)) == NULL)
+			return -EINVAL;
+		switch (nr_route.type) {
+		case NETROM_NODE:
+			return nr_del_node(&nr_route.callsign,
+				&nr_route.neighbour, dev);
+		case NETROM_NEIGH:
+			return nr_del_neigh(&nr_route.callsign,
+				dev, nr_route.quality);
 		default:
 			return -EINVAL;
+		}
+
+	case SIOCNRDECOBS:
+		return nr_dec_obs();
+
+	default:
+		return -EINVAL;
 	}
 
 	return 0;
@@ -758,8 +739,7 @@
 	off_t begin = 0;
 	int i;
 
-	cli();
-
+	spin_lock_bh(&nr_node_lock);
 	len += sprintf(buffer, "callsign  mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n");
 
 	for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) {
@@ -767,7 +747,7 @@
 			ax2asc(&nr_node->callsign),
 			(nr_node->mnemonic[0] == '\0') ? "*" : nr_node->mnemonic,
 			nr_node->which + 1,
-			nr_node->count);			
+			nr_node->count);
 
 		for (i = 0; i < nr_node->count; i++) {
 			len += sprintf(buffer + len, "  %3d   %d %05d",
@@ -788,8 +768,7 @@
 		if (pos > offset + length)
 			break;
 	}
-
-	sti();
+	spin_unlock_bh(&nr_node_lock);
 
 	*start = buffer + (offset - begin);
 	len   -= (offset - begin);
@@ -797,7 +776,7 @@
 	if (len > length) len = length;
 
 	return len;
-} 
+}
 
 int nr_neigh_get_info(char *buffer, char **start, off_t offset, int length)
 {
@@ -807,8 +786,7 @@
 	off_t begin = 0;
 	int i;
 
-	cli();
-
+	spin_lock_bh(&nr_neigh_lock);
 	len += sprintf(buffer, "addr  callsign  dev  qual lock count failed digipeaters\n");
 
 	for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) {
@@ -839,7 +817,7 @@
 			break;
 	}
 
-	sti();
+	spin_unlock_bh(&nr_neigh_lock);
 
 	*start = buffer + (offset - begin);
 	len   -= (offset - begin);
@@ -847,7 +825,7 @@
 	if (len > length) len = length;
 
 	return len;
-} 
+}
 
 /*
  *	Free all memory associated with the nodes and routes lists.
diff -Nru a/net/netrom/nr_subr.c b/net/netrom/nr_subr.c
--- a/net/netrom/nr_subr.c	Fri Sep 20 08:20:49 2002
+++ b/net/netrom/nr_subr.c	Fri Sep 20 08:20:49 2002
@@ -1,20 +1,11 @@
 /*
- *	NET/ROM release 007
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	History
- *	NET/ROM 001	Jonathan(G4KLX)	Cloned from ax25_subr.c
- *	NET/ROM	003	Jonathan(G4KLX)	Added G8BPQ NET/ROM extensions.
- *	NET/ROM 007	Jonathan(G4KLX)	New timer architecture.
+ * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
  */
-
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -125,7 +116,7 @@
 	return 0;
 }
 
-/* 
+/*
  *  This routine is called when the HDLC layer internally generates a
  *  control frame.
  */
@@ -139,19 +130,19 @@
 	len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN + NR_TRANSPORT_LEN;
 
 	switch (frametype & 0x0F) {
-		case NR_CONNREQ:
-			len += 17;
-			break;
-		case NR_CONNACK:
-			len += (nr->bpqext) ? 2 : 1;
-			break;
-		case NR_DISCREQ:
-		case NR_DISCACK:
-		case NR_INFOACK:
-			break;
-		default:
-			printk(KERN_ERR "NET/ROM: nr_write_internal - invalid frame type %d\n", frametype);
-			return;
+	case NR_CONNREQ:
+		len += 17;
+		break;
+	case NR_CONNACK:
+		len += (nr->bpqext) ? 2 : 1;
+		break;
+	case NR_DISCREQ:
+	case NR_DISCACK:
+	case NR_INFOACK:
+		break;
+	default:
+		printk(KERN_ERR "NET/ROM: nr_write_internal - invalid frame type %d\n", frametype);
+		return;
 	}
 
 	if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
@@ -161,59 +152,58 @@
 	 *	Space for AX.25 and NET/ROM network header
 	 */
 	skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + NR_NETWORK_LEN);
-	
+
 	dptr = skb_put(skb, skb_tailroom(skb));
 
 	switch (frametype & 0x0F) {
-
-		case NR_CONNREQ:
-			timeout  = nr->t1 / HZ;
-			*dptr++  = nr->my_index;
-			*dptr++  = nr->my_id;
-			*dptr++  = 0;
-			*dptr++  = 0;
-			*dptr++  = frametype;
-			*dptr++  = nr->window;
-			memcpy(dptr, &nr->user_addr, AX25_ADDR_LEN);
-			dptr[6] &= ~AX25_CBIT;
-			dptr[6] &= ~AX25_EBIT;
-			dptr[6] |= AX25_SSSID_SPARE;
-			dptr    += AX25_ADDR_LEN;
-			memcpy(dptr, &nr->source_addr, AX25_ADDR_LEN);
-			dptr[6] &= ~AX25_CBIT;
-			dptr[6] &= ~AX25_EBIT;
-			dptr[6] |= AX25_SSSID_SPARE;
-			dptr    += AX25_ADDR_LEN;
-			*dptr++  = timeout % 256;
-			*dptr++  = timeout / 256;
-			break;
-
-		case NR_CONNACK:
-			*dptr++ = nr->your_index;
-			*dptr++ = nr->your_id;
-			*dptr++ = nr->my_index;
-			*dptr++ = nr->my_id;
-			*dptr++ = frametype;
-			*dptr++ = nr->window;
-			if (nr->bpqext) *dptr++ = sysctl_netrom_network_ttl_initialiser;
-			break;
-
-		case NR_DISCREQ:
-		case NR_DISCACK:
-			*dptr++ = nr->your_index;
-			*dptr++ = nr->your_id;
-			*dptr++ = 0;
-			*dptr++ = 0;
-			*dptr++ = frametype;
-			break;
-
-		case NR_INFOACK:
-			*dptr++ = nr->your_index;
-			*dptr++ = nr->your_id;
-			*dptr++ = 0;
-			*dptr++ = nr->vr;
-			*dptr++ = frametype;
-			break;
+	case NR_CONNREQ:
+		timeout  = nr->t1 / HZ;
+		*dptr++  = nr->my_index;
+		*dptr++  = nr->my_id;
+		*dptr++  = 0;
+		*dptr++  = 0;
+		*dptr++  = frametype;
+		*dptr++  = nr->window;
+		memcpy(dptr, &nr->user_addr, AX25_ADDR_LEN);
+		dptr[6] &= ~AX25_CBIT;
+		dptr[6] &= ~AX25_EBIT;
+		dptr[6] |= AX25_SSSID_SPARE;
+		dptr    += AX25_ADDR_LEN;
+		memcpy(dptr, &nr->source_addr, AX25_ADDR_LEN);
+		dptr[6] &= ~AX25_CBIT;
+		dptr[6] &= ~AX25_EBIT;
+		dptr[6] |= AX25_SSSID_SPARE;
+		dptr    += AX25_ADDR_LEN;
+		*dptr++  = timeout % 256;
+		*dptr++  = timeout / 256;
+		break;
+
+	case NR_CONNACK:
+		*dptr++ = nr->your_index;
+		*dptr++ = nr->your_id;
+		*dptr++ = nr->my_index;
+		*dptr++ = nr->my_id;
+		*dptr++ = frametype;
+		*dptr++ = nr->window;
+		if (nr->bpqext) *dptr++ = sysctl_netrom_network_ttl_initialiser;
+		break;
+
+	case NR_DISCREQ:
+	case NR_DISCACK:
+		*dptr++ = nr->your_index;
+		*dptr++ = nr->your_id;
+		*dptr++ = 0;
+		*dptr++ = 0;
+		*dptr++ = frametype;
+		break;
+
+	case NR_INFOACK:
+		*dptr++ = nr->your_index;
+		*dptr++ = nr->your_id;
+		*dptr++ = 0;
+		*dptr++ = nr->vr;
+		*dptr++ = frametype;
+		break;
 	}
 
 	nr_transmit_buffer(sk, skb);
@@ -243,7 +233,7 @@
 	dptr[6] &= ~AX25_EBIT;
 	dptr[6] |= AX25_SSSID_SPARE;
 	dptr += AX25_ADDR_LEN;
-	
+
 	memcpy(dptr, skb->data + 0, AX25_ADDR_LEN);
 	dptr[6] &= ~AX25_CBIT;
 	dptr[6] |= AX25_EBIT;
diff -Nru a/net/netrom/nr_timer.c b/net/netrom/nr_timer.c
--- a/net/netrom/nr_timer.c	Fri Sep 20 08:20:47 2002
+++ b/net/netrom/nr_timer.c	Fri Sep 20 08:20:47 2002
@@ -1,20 +1,12 @@
 /*
- *	NET/ROM release 007
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	History
- *	NET/ROM 001	Jonathan(G4KLX)	Cloned from ax25_timer.c
- *	NET/ROM 007	Jonathan(G4KLX)	New timer architecture.
- *					Implemented idle timer.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright (C) 2002 Ralf Baechle DO1GRB (ralf@gnu.org)
  */
-
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -144,33 +136,34 @@
 	struct sock *sk = (struct sock *)param;
 	nr_cb *nr = nr_sk(sk);
 
+	bh_lock_sock(sk);
 	switch (nr->state) {
-
-		case NR_STATE_0:
-			/* Magic here: If we listen() and a new link dies before it
-			   is accepted() it isn't 'dead' so doesn't get removed. */
-			if (sk->destroy || (sk->state == TCP_LISTEN && sk->dead)) {
-				nr_destroy_socket(sk);
-				return;
-			}
-			break;
-
-		case NR_STATE_3:
-			/*
-			 * Check for the state of the receive buffer.
-			 */
-			if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) &&
-			    (nr->condition & NR_COND_OWN_RX_BUSY)) {
-				nr->condition &= ~NR_COND_OWN_RX_BUSY;
-				nr->condition &= ~NR_COND_ACK_PENDING;
-				nr->vl         = nr->vr;
-				nr_write_internal(sk, NR_INFOACK);
-				break;
-			}
+	case NR_STATE_0:
+		/* Magic here: If we listen() and a new link dies before it
+		   is accepted() it isn't 'dead' so doesn't get removed. */
+		if (sk->destroy || (sk->state == TCP_LISTEN && sk->dead)) {
+			nr_destroy_socket(sk);
+			return;
+		}
+		break;
+
+	case NR_STATE_3:
+		/*
+		 * Check for the state of the receive buffer.
+		 */
+		if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) &&
+		    (nr->condition & NR_COND_OWN_RX_BUSY)) {
+			nr->condition &= ~NR_COND_OWN_RX_BUSY;
+			nr->condition &= ~NR_COND_ACK_PENDING;
+			nr->vl         = nr->vr;
+			nr_write_internal(sk, NR_INFOACK);
 			break;
+		}
+		break;
 	}
 
 	nr_start_heartbeat(sk);
+	bh_unlock_sock(sk);
 }
 
 static void nr_t2timer_expiry(unsigned long param)
@@ -178,17 +171,21 @@
 	struct sock *sk = (struct sock *)param;
 	nr_cb *nr = nr_sk(sk);
 
+	bh_lock_sock(sk);
 	if (nr->condition & NR_COND_ACK_PENDING) {
 		nr->condition &= ~NR_COND_ACK_PENDING;
 		nr_enquiry_response(sk);
 	}
+	bh_unlock_sock(sk);
 }
 
 static void nr_t4timer_expiry(unsigned long param)
 {
 	struct sock *sk = (struct sock *)param;
 
+	bh_lock_sock(sk);
 	nr_sk(sk)->condition &= ~NR_COND_PEER_RX_BUSY;
+	bh_unlock_sock(sk);
 }
 
 static void nr_idletimer_expiry(unsigned long param)
@@ -196,6 +193,8 @@
 	struct sock *sk = (struct sock *)param;
 	nr_cb *nr = nr_sk(sk);
 
+	bh_lock_sock(sk);
+
 	nr_clear_queues(sk);
 
 	nr->n2count = 0;
@@ -214,6 +213,7 @@
 		sk->state_change(sk);
 
 	sk->dead = 1;
+	bh_unlock_sock(sk);
 }
 
 static void nr_t1timer_expiry(unsigned long param)
@@ -221,38 +221,39 @@
 	struct sock *sk = (struct sock *)param;
 	nr_cb *nr = nr_sk(sk);
 
+	bh_lock_sock(sk);
 	switch (nr->state) {
-
-		case NR_STATE_1: 
-			if (nr->n2count == nr->n2) {
-				nr_disconnect(sk, ETIMEDOUT);
-				return;
-			} else {
-				nr->n2count++;
-				nr_write_internal(sk, NR_CONNREQ);
-			}
-			break;
-
-		case NR_STATE_2:
-			if (nr->n2count == nr->n2) {
-				nr_disconnect(sk, ETIMEDOUT);
-				return;
-			} else {
-				nr->n2count++;
-				nr_write_internal(sk, NR_DISCREQ);
-			}
-			break;
-
-		case NR_STATE_3:
-			if (nr->n2count == nr->n2) {
-				nr_disconnect(sk, ETIMEDOUT);
-				return;
-			} else {
-				nr->n2count++;
-				nr_requeue_frames(sk);
-			}
-			break;
+	case NR_STATE_1:
+		if (nr->n2count == nr->n2) {
+			nr_disconnect(sk, ETIMEDOUT);
+			return;
+		} else {
+			nr->n2count++;
+			nr_write_internal(sk, NR_CONNREQ);
+		}
+		break;
+
+	case NR_STATE_2:
+		if (nr->n2count == nr->n2) {
+			nr_disconnect(sk, ETIMEDOUT);
+			return;
+		} else {
+			nr->n2count++;
+			nr_write_internal(sk, NR_DISCREQ);
+		}
+		break;
+
+	case NR_STATE_3:
+		if (nr->n2count == nr->n2) {
+			nr_disconnect(sk, ETIMEDOUT);
+			return;
+		} else {
+			nr->n2count++;
+			nr_requeue_frames(sk);
+		}
+		break;
 	}
 
 	nr_start_t1timer(sk);
+	bh_unlock_sock(sk);
 }
diff -Nru a/net/netrom/sysctl_net_netrom.c b/net/netrom/sysctl_net_netrom.c
--- a/net/netrom/sysctl_net_netrom.c	Fri Sep 20 08:20:43 2002
+++ b/net/netrom/sysctl_net_netrom.c	Fri Sep 20 08:20:43 2002
@@ -1,10 +1,11 @@
-/* -*- linux-c -*-
- * sysctl_net_netrom.c: sysctl interface to net NET/ROM subsystem.
+/*
+ * 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.
  *
- * Begun April 1, 1996, Mike Shaver.
- * Added /proc/sys/net/netrom directory entry (empty =) ). [MS]
+ * Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com)
  */
-
 #include <linux/mm.h>
 #include <linux/sysctl.h>
 #include <linux/init.h>
diff -Nru a/net/rose/af_rose.c b/net/rose/af_rose.c
--- a/net/rose/af_rose.c	Fri Sep 20 08:20:46 2002
+++ b/net/rose/af_rose.c	Fri Sep 20 08:20:46 2002
@@ -1,29 +1,14 @@
 /*
- *	ROSE release 003
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	History
- *	ROSE 001	Jonathan(G4KLX)	Cloned from af_netrom.c.
- *			Alan(GW4PTS)	Hacked up for newer API stuff
- *			Terry (VK2KTJ)	Added support for variable length
- * 					address masks.
- *	ROSE 002	Jonathan(G4KLX)	Changed hdrincl to qbitincl.
- *					Added random number facilities entry.
- *					Variable number of ROSE devices.
- *	ROSE 003	Jonathan(G4KLX)	New timer architecture.
- *					Implemented idle timer.
- *					Added use count to neighbour.
- *                      Tomi(OH2BNS)    Fixed rose_getname().
- *                      Arnaldo C. Melo s/suser/capable/ + micro cleanups
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright (C) Alan Cox GW4PTS (alan@lxorguk.ukuu.org.uk)
+ * Copyright (C) Terry Dawson VK2KTJ (terry@animats.net)
+ * Copyright (C) Tomi Manninen OH2BNS (oh2bns@sral.fi)
  */
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -33,6 +18,7 @@
 #include <linux/in.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/spinlock.h>
 #include <linux/timer.h>
 #include <linux/string.h>
 #include <linux/sockios.h>
@@ -47,7 +33,7 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <linux/fcntl.h>
-#include <linux/termios.h>	/* For TIOCINQ/OUTQ */
+#include <linux/termios.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
 #include <linux/notifier.h>
@@ -71,6 +57,7 @@
 int sysctl_rose_window_size             = ROSE_DEFAULT_WINDOW_SIZE;
 
 static struct sock *rose_list;
+static spinlock_t rose_list_lock = SPIN_LOCK_UNLOCKED;
 
 static struct proto_ops rose_proto_ops;
 
@@ -173,27 +160,24 @@
 static void rose_remove_socket(struct sock *sk)
 {
 	struct sock *s;
-	unsigned long flags;
-
-	save_flags(flags); cli();
 
+	spin_lock_bh(&rose_list_lock);
 	if ((s = rose_list) == sk) {
 		rose_list = s->next;
-		restore_flags(flags);
+		spin_unlock_bh(&rose_list_lock);
 		return;
 	}
 
 	while (s != NULL && s->next != NULL) {
 		if (s->next == sk) {
 			s->next = sk->next;
-			restore_flags(flags);
+			spin_unlock_bh(&rose_list_lock);
 			return;
 		}
 
 		s = s->next;
 	}
-
-	restore_flags(flags);
+	spin_unlock_bh(&rose_list_lock);
 }
 
 /*
@@ -204,6 +188,7 @@
 {
 	struct sock *s;
 
+	spin_lock_bh(&rose_list_lock);
 	for (s = rose_list; s != NULL; s = s->next) {
 		rose_cb *rose = rose_sk(s);
 
@@ -213,6 +198,7 @@
 			rose->neighbour = NULL;
 		}
 	}
+	spin_unlock_bh(&rose_list_lock);
 }
 
 /*
@@ -221,7 +207,8 @@
 static void rose_kill_by_device(struct net_device *dev)
 {
 	struct sock *s;
-	
+
+	spin_lock_bh(&rose_list_lock);
 	for (s = rose_list; s != NULL; s = s->next) {
 		rose_cb *rose = rose_sk(s);
 
@@ -231,12 +218,14 @@
 			rose->device = NULL;
 		}
 	}
+	spin_unlock_bh(&rose_list_lock);
 }
 
 /*
  *	Handle device status changes.
  */
-static int rose_device_event(struct notifier_block *this, unsigned long event, void *ptr)
+static int rose_device_event(struct notifier_block *this, unsigned long event,
+	void *ptr)
 {
 	struct net_device *dev = (struct net_device *)ptr;
 
@@ -244,13 +233,13 @@
 		return NOTIFY_DONE;
 
 	switch (dev->type) {
-		case ARPHRD_ROSE:
-			rose_kill_by_device(dev);
-			break;
-		case ARPHRD_AX25:
-			rose_link_device_down(dev);
-			rose_rt_device_down(dev);
-			break;
+	case ARPHRD_ROSE:
+		rose_kill_by_device(dev);
+		break;
+	case ARPHRD_AX25:
+		rose_link_device_down(dev);
+		rose_rt_device_down(dev);
+		break;
 	}
 
 	return NOTIFY_DONE;
@@ -261,14 +250,11 @@
  */
 static void rose_insert_socket(struct sock *sk)
 {
-	unsigned long flags;
-
-	save_flags(flags); cli();
 
+	spin_lock_bh(&rose_list_lock);
 	sk->next  = rose_list;
 	rose_list = sk;
-
-	restore_flags(flags);
+	spin_unlock_bh(&rose_list_lock);
 }
 
 /*
@@ -277,18 +263,16 @@
  */
 static struct sock *rose_find_listener(rose_address *addr, ax25_address *call)
 {
-	unsigned long flags;
 	struct sock *s;
 
-	save_flags(flags); cli();
-
+	spin_lock_bh(&rose_list_lock);
 	for (s = rose_list; s != NULL; s = s->next) {
 		rose_cb *rose = rose_sk(s);
 
 		if (!rosecmp(&rose->source_addr, addr) &&
 		    !ax25cmp(&rose->source_call, call) &&
 		    !rose->source_ndigis && s->state == TCP_LISTEN) {
-			restore_flags(flags);
+			spin_unlock_bh(&rose_list_lock);
 			return s;
 		}
 	}
@@ -299,12 +283,12 @@
 		if (!rosecmp(&rose->source_addr, addr) &&
 		    !ax25cmp(&rose->source_call, &null_ax25_address) &&
 		    s->state == TCP_LISTEN) {
-			restore_flags(flags);
+			spin_unlock_bh(&rose_list_lock);
 			return s;
 		}
 	}
+	spin_unlock_bh(&rose_list_lock);
 
-	restore_flags(flags);
 	return NULL;
 }
 
@@ -314,20 +298,17 @@
 struct sock *rose_find_socket(unsigned int lci, struct rose_neigh *neigh)
 {
 	struct sock *s;
-	unsigned long flags;
-
-	save_flags(flags); cli();
 
+	spin_lock_bh(&rose_list_lock);
 	for (s = rose_list; s != NULL; s = s->next) {
 		rose_cb *rose = rose_sk(s);
 
 		if (rose->lci == lci && rose->neighbour == neigh) {
-			restore_flags(flags);
+			spin_unlock_bh(&rose_list_lock);
 			return s;
 		}
 	}
-
-	restore_flags(flags);
+	spin_unlock_bh(&rose_list_lock);
 
 	return NULL;
 }
@@ -366,23 +347,20 @@
 }
 
 /*
- *	This is called from user mode and the timers. Thus it protects itself against
- *	interrupt users but doesn't worry about being called during work.
- *	Once it is removed from the queue no interrupt or bottom half will
- *	touch it and we are (fairly 8-) ) safe.
+ *	This is called from user mode and the timers. Thus it protects itself
+ *	against interrupt users but doesn't worry about being called during
+ *	work.  Once it is removed from the queue no interrupt or bottom half
+ *	will touch it and we are (fairly 8-) ) safe.
  */
-void rose_destroy_socket(struct sock *sk)	/* Not static as it's used by the timer */
+void rose_destroy_socket(struct sock *sk)
 {
 	struct sk_buff *skb;
-	unsigned long flags;
-
-	save_flags(flags); cli();
 
+	rose_remove_socket(sk);
 	rose_stop_heartbeat(sk);
 	rose_stop_idletimer(sk);
 	rose_stop_timer(sk);
 
-	rose_remove_socket(sk);
 	rose_clear_queues(sk);		/* Flush the queues */
 
 	while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
@@ -405,8 +383,6 @@
 	} else {
 		rose_free_sock(sk);
 	}
-
-	restore_flags(flags);
 }
 
 /*
@@ -431,46 +407,46 @@
 		return -EFAULT;
 
 	switch (optname) {
-		case ROSE_DEFER:
-			rose->defer = opt ? 1 : 0;
-			return 0;
-
-		case ROSE_T1:
-			if (opt < 1)
-				return -EINVAL;
-			rose->t1 = opt * HZ;
-			return 0;
-
-		case ROSE_T2:
-			if (opt < 1)
-				return -EINVAL;
-			rose->t2 = opt * HZ;
-			return 0;
-
-		case ROSE_T3:
-			if (opt < 1)
-				return -EINVAL;
-			rose->t3 = opt * HZ;
-			return 0;
-
-		case ROSE_HOLDBACK:
-			if (opt < 1)
-				return -EINVAL;
-			rose->hb = opt * HZ;
-			return 0;
-
-		case ROSE_IDLE:
-			if (opt < 0)
-				return -EINVAL;
-			rose->idle = opt * 60 * HZ;
-			return 0;
-
-		case ROSE_QBITINCL:
-			rose->qbitincl = opt ? 1 : 0;
-			return 0;
+	case ROSE_DEFER:
+		rose->defer = opt ? 1 : 0;
+		return 0;
+
+	case ROSE_T1:
+		if (opt < 1)
+			return -EINVAL;
+		rose->t1 = opt * HZ;
+		return 0;
+
+	case ROSE_T2:
+		if (opt < 1)
+			return -EINVAL;
+		rose->t2 = opt * HZ;
+		return 0;
+
+	case ROSE_T3:
+		if (opt < 1)
+			return -EINVAL;
+		rose->t3 = opt * HZ;
+		return 0;
+
+	case ROSE_HOLDBACK:
+		if (opt < 1)
+			return -EINVAL;
+		rose->hb = opt * HZ;
+		return 0;
+
+	case ROSE_IDLE:
+		if (opt < 0)
+			return -EINVAL;
+		rose->idle = opt * 60 * HZ;
+		return 0;
 
-		default:
-			return -ENOPROTOOPT;
+	case ROSE_QBITINCL:
+		rose->qbitincl = opt ? 1 : 0;
+		return 0;
+
+	default:
+		return -ENOPROTOOPT;
 	}
 }
 
@@ -484,44 +460,44 @@
 
 	if (level != SOL_ROSE)
 		return -ENOPROTOOPT;
-		
+
 	if (get_user(len, optlen))
 		return -EFAULT;
 
 	if (len < 0)
 		return -EINVAL;
-			
-	switch (optname) {
-		case ROSE_DEFER:
-			val = rose->defer;
-			break;
 
-		case ROSE_T1:
-			val = rose->t1 / HZ;
-			break;
-
-		case ROSE_T2:
-			val = rose->t2 / HZ;
-			break;
-
-		case ROSE_T3:
-			val = rose->t3 / HZ;
-			break;
-
-		case ROSE_HOLDBACK:
-			val = rose->hb / HZ;
-			break;
-
-		case ROSE_IDLE:
-			val = rose->idle / (60 * HZ);
-			break;
-
-		case ROSE_QBITINCL:
-			val = rose->qbitincl;
-			break;
+	switch (optname) {
+	case ROSE_DEFER:
+		val = rose->defer;
+		break;
+
+	case ROSE_T1:
+		val = rose->t1 / HZ;
+		break;
+
+	case ROSE_T2:
+		val = rose->t2 / HZ;
+		break;
+
+	case ROSE_T3:
+		val = rose->t3 / HZ;
+		break;
+
+	case ROSE_HOLDBACK:
+		val = rose->hb / HZ;
+		break;
+
+	case ROSE_IDLE:
+		val = rose->idle / (60 * HZ);
+		break;
+
+	case ROSE_QBITINCL:
+		val = rose->qbitincl;
+		break;
 
-		default:
-			return -ENOPROTOOPT;
+	default:
+		return -ENOPROTOOPT;
 	}
 
 	len = min_t(unsigned int, len, sizeof(int));
@@ -565,7 +541,7 @@
 	rose = rose_sk(sk);
 
 	sock_init_data(sock, sk);
-	
+
 	skb_queue_head_init(&rose->ack_queue);
 #ifdef M_BIT
 	skb_queue_head_init(&rose->frag_queue);
@@ -647,39 +623,38 @@
 	rose = rose_sk(sk);
 
 	switch (rose->state) {
+	case ROSE_STATE_0:
+		rose_disconnect(sk, 0, -1, -1);
+		rose_destroy_socket(sk);
+		break;
+
+	case ROSE_STATE_2:
+		rose->neighbour->use--;
+		rose_disconnect(sk, 0, -1, -1);
+		rose_destroy_socket(sk);
+		break;
+
+	case ROSE_STATE_1:
+	case ROSE_STATE_3:
+	case ROSE_STATE_4:
+	case ROSE_STATE_5:
+		rose_clear_queues(sk);
+		rose_stop_idletimer(sk);
+		rose_write_internal(sk, ROSE_CLEAR_REQUEST);
+		rose_start_t3timer(sk);
+		rose->state  = ROSE_STATE_2;
+		sk->state    = TCP_CLOSE;
+		sk->shutdown |= SEND_SHUTDOWN;
+		sk->state_change(sk);
+		sk->dead     = 1;
+		sk->destroy  = 1;
+		break;
 
-		case ROSE_STATE_0:
-			rose_disconnect(sk, 0, -1, -1);
-			rose_destroy_socket(sk);
-			break;
-
-		case ROSE_STATE_2:
-			rose->neighbour->use--;
-			rose_disconnect(sk, 0, -1, -1);
-			rose_destroy_socket(sk);
-			break;
-
-		case ROSE_STATE_1:
-		case ROSE_STATE_3:
-		case ROSE_STATE_4:
-		case ROSE_STATE_5:
-			rose_clear_queues(sk);
-			rose_stop_idletimer(sk);
-			rose_write_internal(sk, ROSE_CLEAR_REQUEST);
-			rose_start_t3timer(sk);
-			rose->state  = ROSE_STATE_2;
-			sk->state    = TCP_CLOSE;
-			sk->shutdown |= SEND_SHUTDOWN;
-			sk->state_change(sk);
-			sk->dead     = 1;
-			sk->destroy  = 1;
-			break;
-
-		default:
-			break;
+	default:
+		break;
 	}
 
-	sock->sk = NULL;	
+	sock->sk = NULL;
 	sk->socket = NULL;	/* Not used, but we should do this. **/
 
 	return 0;
@@ -813,7 +788,7 @@
 
 	rose->dest_addr   = addr->srose_addr;
 	rose->dest_call   = addr->srose_call;
-	rose->rand        = ((int)rose & 0xFFFF) + rose->lci;
+	rose->rand        = ((long)rose & 0xFFFF) + rose->lci;
 	rose->dest_ndigis = addr->srose_ndigis;
 
 	if (addr_len == sizeof(struct full_sockaddr_rose)) {
@@ -842,71 +817,90 @@
 	if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
 		return -EINPROGRESS;
 
-	cli();	/* To avoid races on the sleep */
-
 	/*
-	 * A Connect Ack with Choke or timeout or failed routing will go to closed.
+	 * A Connect Ack with Choke or timeout or failed routing will go to
+	 * closed.
 	 */
-	while (sk->state == TCP_SYN_SENT) {
-		interruptible_sleep_on(sk->sleep);
-		if (signal_pending(current)) {
-			sti();
+	if (sk->state == TCP_SYN_SENT) {
+		struct task_struct *tsk = current;
+		DECLARE_WAITQUEUE(wait, tsk);
+
+		add_wait_queue(sk->sleep, &wait);
+		for (;;) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			if (sk->state != TCP_SYN_SENT)
+				break;
+			if (!signal_pending(tsk)) {
+				schedule();
+				continue;
+			}
 			return -ERESTARTSYS;
 		}
+		current->state = TASK_RUNNING;
+		remove_wait_queue(sk->sleep, &wait);
 	}
 
 	if (sk->state != TCP_ESTABLISHED) {
-		sti();
 		sock->state = SS_UNCONNECTED;
 		return sock_error(sk);	/* Always set at this point */
 	}
 
 	sock->state = SS_CONNECTED;
 
-	sti();
-
 	return 0;
 }
 
 static int rose_accept(struct socket *sock, struct socket *newsock, int flags)
 {
-	struct sock *sk;
-	struct sock *newsk;
+	struct task_struct *tsk = current;
+	DECLARE_WAITQUEUE(wait, tsk);
 	struct sk_buff *skb;
+	struct sock *newsk;
+	struct sock *sk;
+	int err = 0;
 
 	if ((sk = sock->sk) == NULL)
 		return -EINVAL;
 
-	if (sk->type != SOCK_SEQPACKET)
-		return -EOPNOTSUPP;
+	lock_sock(sk);
+	if (sk->type != SOCK_SEQPACKET) {
+		err = -EOPNOTSUPP;
+		goto out;
+	}
 
-	if (sk->state != TCP_LISTEN)
-		return -EINVAL;
+	if (sk->state != TCP_LISTEN) {
+		err = -EINVAL;
+		goto out;
+	}
 
 	/*
 	 *	The write queue this time is holding sockets ready to use
 	 *	hooked into the SABM we saved
 	 */
-	do {
-		cli();
-		if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {
-			if (flags & O_NONBLOCK) {
-				sti();
-				return -EWOULDBLOCK;
-			}
-			interruptible_sleep_on(sk->sleep);
-			if (signal_pending(current)) {
-				sti();
-				return -ERESTARTSYS;
-			}
+	add_wait_queue(sk->sleep, &wait);
+	for (;;) {
+		skb = skb_dequeue(&sk->receive_queue);
+		if (skb)
+			break;
+
+		current->state = TASK_INTERRUPTIBLE;
+		release_sock(sk);
+		if (flags & O_NONBLOCK)
+			return -EWOULDBLOCK;
+		if (!signal_pending(tsk)) {
+			schedule();
+			lock_sock(sk);
+			continue;
 		}
-	} while (skb == NULL);
+		return -ERESTARTSYS;
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(sk->sleep, &wait);
 
 	newsk = skb->sk;
 	newsk->pair = NULL;
 	newsk->socket = newsock;
 	newsk->sleep = &newsock->wait;
-	sti();
 
 	/* Now attach up the new socket */
 	skb->sk = NULL;
@@ -914,7 +908,10 @@
 	sk->ack_backlog--;
 	newsock->sk = newsk;
 
-	return 0;
+out:
+	release_sock(sk);
+
+	return err;
 }
 
 static int rose_getname(struct socket *sock, struct sockaddr *uaddr,
@@ -961,7 +958,7 @@
 	 *	skb->data points to the rose frame start
 	 */
 	memset(&facilities, 0x00, sizeof(struct rose_facilities_struct));
-	
+
 	len  = (((skb->data[3] >> 4) & 0x0F) + 1) / 2;
 	len += (((skb->data[3] >> 0) & 0x0F) + 1) / 2;
 	if (!rose_parse_facilities(skb->data + len + 4, &facilities)) {
@@ -1028,7 +1025,7 @@
 	return 1;
 }
 
-static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len, 
+static int rose_sendmsg(struct socket *sock, struct msghdr *msg, int len,
 				struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
@@ -1131,7 +1128,7 @@
 	SOCK_DEBUG(sk, "ROSE: Built header.\n");
 
 	SOCK_DEBUG(sk, "ROSE: Transmitting buffer\n");
-	
+
 	if (sk->state != TCP_ESTABLISHED) {
 		kfree_skb(skb);
 		return -ENOTCONN;
@@ -1144,7 +1141,7 @@
 		struct sk_buff *skbn;
 		int frontlen;
 		int lg;
-		
+
 		/* Save a copy of the Header */
 		memcpy(header, skb->data, ROSE_MIN_LEN);
 		skb_pull(skb, ROSE_MIN_LEN);
@@ -1173,10 +1170,10 @@
 
 			if (skb->len > 0)
 				skbn->data[2] |= M_BIT;
-		
+
 			skb_queue_tail(&sk->write_queue, skbn); /* Throw it on the queue */
 		}
-		
+
 		skb->free = 1;
 		kfree_skb(skb, FREE_WRITE);
 	} else {
@@ -1192,7 +1189,7 @@
 }
 
 
-static int rose_recvmsg(struct socket *sock, struct msghdr *msg, int size, 
+static int rose_recvmsg(struct socket *sock, struct msghdr *msg, int size,
 		   int flags, struct scm_cookie *scm)
 {
 	struct sock *sk = sock->sk;
@@ -1264,96 +1261,96 @@
 	rose_cb *rose = rose_sk(sk);
 
 	switch (cmd) {
-		case TIOCOUTQ: {
-			long amount;
-			amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
-			if (amount < 0)
-				amount = 0;
-			return put_user(amount, (unsigned int *)arg);
+	case TIOCOUTQ: {
+		long amount;
+		amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);
+		if (amount < 0)
+			amount = 0;
+		return put_user(amount, (unsigned int *)arg);
+	}
+
+	case TIOCINQ: {
+		struct sk_buff *skb;
+		long amount = 0L;
+		/* These two are safe on a single CPU system as only user tasks fiddle here */
+		if ((skb = skb_peek(&sk->receive_queue)) != NULL)
+			amount = skb->len;
+		return put_user(amount, (unsigned int *)arg);
+	}
+
+	case SIOCGSTAMP:
+		if (sk != NULL) {
+			if (sk->stamp.tv_sec == 0)
+				return -ENOENT;
+			return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0;
 		}
+		return -EINVAL;
 
-		case TIOCINQ: {
-			struct sk_buff *skb;
-			long amount = 0L;
-			/* These two are safe on a single CPU system as only user tasks fiddle here */
-			if ((skb = skb_peek(&sk->receive_queue)) != NULL)
-				amount = skb->len;
-			return put_user(amount, (unsigned int *)arg);
-		}
+	case SIOCGIFADDR:
+	case SIOCSIFADDR:
+	case SIOCGIFDSTADDR:
+	case SIOCSIFDSTADDR:
+	case SIOCGIFBRDADDR:
+	case SIOCSIFBRDADDR:
+	case SIOCGIFNETMASK:
+	case SIOCSIFNETMASK:
+	case SIOCGIFMETRIC:
+	case SIOCSIFMETRIC:
+		return -EINVAL;
 
-		case SIOCGSTAMP:
-			if (sk != NULL) {
-				if (sk->stamp.tv_sec == 0)
-					return -ENOENT;
-				return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0;
-			}
-			return -EINVAL;
+	case SIOCADDRT:
+	case SIOCDELRT:
+	case SIOCRSCLRRT:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		return rose_rt_ioctl(cmd, (void *)arg);
+
+	case SIOCRSGCAUSE: {
+		struct rose_cause_struct rose_cause;
+		rose_cause.cause      = rose->cause;
+		rose_cause.diagnostic = rose->diagnostic;
+		return copy_to_user((void *)arg, &rose_cause, sizeof(struct rose_cause_struct)) ? -EFAULT : 0;
+	}
+
+	case SIOCRSSCAUSE: {
+		struct rose_cause_struct rose_cause;
+		if (copy_from_user(&rose_cause, (void *)arg, sizeof(struct rose_cause_struct)))
+			return -EFAULT;
+		rose->cause      = rose_cause.cause;
+		rose->diagnostic = rose_cause.diagnostic;
+		return 0;
+	}
 
-		case SIOCGIFADDR:
-		case SIOCSIFADDR:
-		case SIOCGIFDSTADDR:
-		case SIOCSIFDSTADDR:
-		case SIOCGIFBRDADDR:
-		case SIOCSIFBRDADDR:
-		case SIOCGIFNETMASK:
-		case SIOCSIFNETMASK:
-		case SIOCGIFMETRIC:
-		case SIOCSIFMETRIC:
-			return -EINVAL;
+	case SIOCRSSL2CALL:
+		if (!capable(CAP_NET_ADMIN)) return -EPERM;
+		if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)
+			ax25_listen_release(&rose_callsign, NULL);
+		if (copy_from_user(&rose_callsign, (void *)arg, sizeof(ax25_address)))
+			return -EFAULT;
+		if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)
+			ax25_listen_register(&rose_callsign, NULL);
+		return 0;
 
-		case SIOCADDRT:
-		case SIOCDELRT:
-		case SIOCRSCLRRT:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			return rose_rt_ioctl(cmd, (void *)arg);
-
-		case SIOCRSGCAUSE: {
-			struct rose_cause_struct rose_cause;
-			rose_cause.cause      = rose->cause;
-			rose_cause.diagnostic = rose->diagnostic;
-			return copy_to_user((void *)arg, &rose_cause, sizeof(struct rose_cause_struct)) ? -EFAULT : 0;
-		}
+	case SIOCRSGL2CALL:
+		return copy_to_user((void *)arg, &rose_callsign, sizeof(ax25_address)) ? -EFAULT : 0;
 
-		case SIOCRSSCAUSE: {
-			struct rose_cause_struct rose_cause;
-			if (copy_from_user(&rose_cause, (void *)arg, sizeof(struct rose_cause_struct)))
-				return -EFAULT;
-			rose->cause      = rose_cause.cause;
-			rose->diagnostic = rose_cause.diagnostic;
-			return 0;
+	case SIOCRSACCEPT:
+		if (rose->state == ROSE_STATE_5) {
+			rose_write_internal(sk, ROSE_CALL_ACCEPTED);
+			rose_start_idletimer(sk);
+			rose->condition = 0x00;
+			rose->vs        = 0;
+			rose->va        = 0;
+			rose->vr        = 0;
+			rose->vl        = 0;
+			rose->state     = ROSE_STATE_3;
 		}
+		return 0;
 
-		case SIOCRSSL2CALL:
-			if (!capable(CAP_NET_ADMIN)) return -EPERM;
-			if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)
-				ax25_listen_release(&rose_callsign, NULL);
-			if (copy_from_user(&rose_callsign, (void *)arg, sizeof(ax25_address)))
-				return -EFAULT;
-			if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)
-				ax25_listen_register(&rose_callsign, NULL);
-			return 0;
-
-		case SIOCRSGL2CALL:
-			return copy_to_user((void *)arg, &rose_callsign, sizeof(ax25_address)) ? -EFAULT : 0;
-
-		case SIOCRSACCEPT:
-			if (rose->state == ROSE_STATE_5) {
-				rose_write_internal(sk, ROSE_CALL_ACCEPTED);
-				rose_start_idletimer(sk);
-				rose->condition = 0x00;
-				rose->vs        = 0;
-				rose->va        = 0;
-				rose->vr        = 0;
-				rose->vl        = 0;
-				rose->state     = ROSE_STATE_3;
-			}
-			return 0;
-
-		default:
-			return dev_ioctl(cmd, (void *)arg);
+	default:
+		return dev_ioctl(cmd, (void *)arg);
 	}
 
-	/*NOTREACHED*/
 	return 0;
 }
 
@@ -1366,7 +1363,7 @@
 	off_t pos = 0;
 	off_t begin = 0;
 
-	cli();
+	spin_lock_bh(&rose_list_lock);
 
 	len += sprintf(buffer, "dest_addr  dest_call src_addr   src_call  dev   lci neigh st vs vr va   t  t1  t2  t3  hb    idle Snd-Q Rcv-Q inode\n");
 
@@ -1390,7 +1387,7 @@
 		len += sprintf(buffer + len, "%-10s %-9s %-5s %3.3X %05d  %d  %d  %d  %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d %ld\n",
 			rose2asc(&rose->source_addr),
 			callsign,
-			devname, 
+			devname,
 			rose->lci & 0x0FFF,
 			(rose->neighbour) ? rose->neighbour->number : 0,
 			rose->state,
@@ -1418,48 +1415,44 @@
 		if (pos > offset + length)
 			break;
 	}
-
-	sti();
+	spin_unlock_bh(&rose_list_lock);
 
 	*start = buffer + (offset - begin);
 	len   -= (offset - begin);
 
 	if (len > length) len = length;
 
-	return(len);
-} 
+	return len;
+}
 
 static struct net_proto_family rose_family_ops = {
-	.family =	PF_ROSE,
-	.create =	rose_create,
+	.family		=	PF_ROSE,
+	.create		=	rose_create,
 };
 
-static struct proto_ops SOCKOPS_WRAPPED(rose_proto_ops) = {
-	.family =	PF_ROSE,
+static struct proto_ops rose_proto_ops = {
+	.family		=	PF_ROSE,
 
-	.release =	rose_release,
-	.bind =		rose_bind,
-	.connect =	rose_connect,
-	.socketpair =	sock_no_socketpair,
-	.accept =	rose_accept,
-	.getname =	rose_getname,
-	.poll =		datagram_poll,
-	.ioctl =	rose_ioctl,
-	.listen =	rose_listen,
-	.shutdown =	sock_no_shutdown,
-	.setsockopt =	rose_setsockopt,
-	.getsockopt =	rose_getsockopt,
-	.sendmsg =	rose_sendmsg,
-	.recvmsg =	rose_recvmsg,
-	.mmap =		sock_no_mmap,
-	.sendpage =	sock_no_sendpage,
+	.release	=	rose_release,
+	.bind		=		rose_bind,
+	.connect	=	rose_connect,
+	.socketpair	=	sock_no_socketpair,
+	.accept		=	rose_accept,
+	.getname	=	rose_getname,
+	.poll		=	datagram_poll,
+	.ioctl		=	rose_ioctl,
+	.listen		=	rose_listen,
+	.shutdown	=	sock_no_shutdown,
+	.setsockopt	=	rose_setsockopt,
+	.getsockopt	=	rose_getsockopt,
+	.sendmsg	=	rose_sendmsg,
+	.recvmsg	=	rose_recvmsg,
+	.mmap		=	sock_no_mmap,
+	.sendpage	=	sock_no_sendpage,
 };
 
-#include <linux/smp_lock.h>
-SOCKOPS_WRAP(rose_proto, PF_ROSE);
-
 static struct notifier_block rose_dev_notifier = {
-	.notifier_call =rose_device_event,
+	.notifier_call	=	rose_device_event,
 };
 
 static struct net_device *dev_rose;
@@ -1555,5 +1548,5 @@
 
 	kfree(dev_rose);
 }
-module_exit(rose_exit);
 
+module_exit(rose_exit);
diff -Nru a/net/rose/rose_dev.c b/net/rose/rose_dev.c
--- a/net/rose/rose_dev.c	Fri Sep 20 08:20:43 2002
+++ b/net/rose/rose_dev.c	Fri Sep 20 08:20:43 2002
@@ -1,19 +1,11 @@
 /*
- *	ROSE release 003
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	History
- *	ROSE 001	Jonathan(G4KLX)	Cloned from nr_dev.c.
- *			Hans(PE1AYX)	Fixed interface to IP layer.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
  */
-
 #include <linux/config.h>
 #define __NO_VERSION__
 #include <linux/module.h>
@@ -29,7 +21,7 @@
 #include <linux/errno.h>
 #include <linux/fcntl.h>
 #include <linux/in.h>
-#include <linux/if_ether.h>	/* For the statistics structure. */
+#include <linux/if_ether.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
diff -Nru a/net/rose/rose_in.c b/net/rose/rose_in.c
--- a/net/rose/rose_in.c	Fri Sep 20 08:20:47 2002
+++ b/net/rose/rose_in.c	Fri Sep 20 08:20:47 2002
@@ -1,27 +1,16 @@
 /*
- *	ROSE release 003
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
  *
- *	This module:
- *		This module 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.
- *
- *	Most of this code is based on the SDL diagrams published in the 7th
- *	ARRL Computer Networking Conference papers. The diagrams have mistakes
- *	in them, but are mostly correct. Before you modify the code could you
- *	read the SDL diagrams as the code is not obvious and probably very
- *	easy to break;
- *
- *	History
- *	ROSE 001	Jonathan(G4KLX)	Cloned from nr_in.c
- *	ROSE 002	Jonathan(G4KLX)	Return cause and diagnostic codes from Clear Requests.
- *	ROSE 003	Jonathan(G4KLX)	New timer architecture.
- *					Removed M bit processing.
+ * Most of this code is based on the SDL diagrams published in the 7th ARRL
+ * Computer Networking Conference papers. The diagrams have mistakes in them,
+ * but are mostly correct. Before you modify the code could you read the SDL
+ * diagrams as the code is not obvious and probably very easy to break.
  */
-
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -55,29 +44,28 @@
 	rose_cb *rose = rose_sk(sk);
 
 	switch (frametype) {
+	case ROSE_CALL_ACCEPTED:
+		rose_stop_timer(sk);
+		rose_start_idletimer(sk);
+		rose->condition = 0x00;
+		rose->vs        = 0;
+		rose->va        = 0;
+		rose->vr        = 0;
+		rose->vl        = 0;
+		rose->state     = ROSE_STATE_3;
+		sk->state                    = TCP_ESTABLISHED;
+		if (!sk->dead)
+			sk->state_change(sk);
+		break;
 
-		case ROSE_CALL_ACCEPTED:
-			rose_stop_timer(sk);
-			rose_start_idletimer(sk);
-			rose->condition = 0x00;
-			rose->vs        = 0;
-			rose->va        = 0;
-			rose->vr        = 0;
-			rose->vl        = 0;
-			rose->state     = ROSE_STATE_3;
-			sk->state                    = TCP_ESTABLISHED;
-			if (!sk->dead)
-				sk->state_change(sk);
-			break;
-
-		case ROSE_CLEAR_REQUEST:
-			rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
-			rose_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]);
-			rose->neighbour->use--;
-			break;
+	case ROSE_CLEAR_REQUEST:
+		rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
+		rose_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]);
+		rose->neighbour->use--;
+		break;
 
-		default:
-			break;
+	default:
+		break;
 	}
 
 	return 0;
@@ -93,20 +81,19 @@
 	rose_cb *rose = rose_sk(sk);
 
 	switch (frametype) {
+	case ROSE_CLEAR_REQUEST:
+		rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
+		rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
+		rose->neighbour->use--;
+		break;
 
-		case ROSE_CLEAR_REQUEST:
-			rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
-			rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
-			rose->neighbour->use--;
-			break;
+	case ROSE_CLEAR_CONFIRMATION:
+		rose_disconnect(sk, 0, -1, -1);
+		rose->neighbour->use--;
+		break;
 
-		case ROSE_CLEAR_CONFIRMATION:
-			rose_disconnect(sk, 0, -1, -1);
-			rose->neighbour->use--;
-			break;
-
-		default:
-			break;
+	default:
+		break;
 	}
 
 	return 0;
@@ -123,50 +110,68 @@
 	int queued = 0;
 
 	switch (frametype) {
+	case ROSE_RESET_REQUEST:
+		rose_stop_timer(sk);
+		rose_start_idletimer(sk);
+		rose_write_internal(sk, ROSE_RESET_CONFIRMATION);
+		rose->condition = 0x00;
+		rose->vs        = 0;
+		rose->vr        = 0;
+		rose->va        = 0;
+		rose->vl        = 0;
+		rose_requeue_frames(sk);
+		break;
 
-		case ROSE_RESET_REQUEST:
-			rose_stop_timer(sk);
-			rose_start_idletimer(sk);
-			rose_write_internal(sk, ROSE_RESET_CONFIRMATION);
+	case ROSE_CLEAR_REQUEST:
+		rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
+		rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
+		rose->neighbour->use--;
+		break;
+
+	case ROSE_RR:
+	case ROSE_RNR:
+		if (!rose_validate_nr(sk, nr)) {
+			rose_write_internal(sk, ROSE_RESET_REQUEST);
 			rose->condition = 0x00;
 			rose->vs        = 0;
 			rose->vr        = 0;
 			rose->va        = 0;
 			rose->vl        = 0;
-			rose_requeue_frames(sk);
-			break;
-
-		case ROSE_CLEAR_REQUEST:
-			rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
-			rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
-			rose->neighbour->use--;
-			break;
-
-		case ROSE_RR:
-		case ROSE_RNR:
-			if (!rose_validate_nr(sk, nr)) {
-				rose_write_internal(sk, ROSE_RESET_REQUEST);
-				rose->condition = 0x00;
-				rose->vs        = 0;
-				rose->vr        = 0;
-				rose->va        = 0;
-				rose->vl        = 0;
-				rose->state     = ROSE_STATE_4;
-				rose_start_t2timer(sk);
-				rose_stop_idletimer(sk);
+			rose->state     = ROSE_STATE_4;
+			rose_start_t2timer(sk);
+			rose_stop_idletimer(sk);
+		} else {
+			rose_frames_acked(sk, nr);
+			if (frametype == ROSE_RNR) {
+				rose->condition |= ROSE_COND_PEER_RX_BUSY;
 			} else {
-				rose_frames_acked(sk, nr);
-				if (frametype == ROSE_RNR) {
-					rose->condition |= ROSE_COND_PEER_RX_BUSY;
-				} else {
-					rose->condition &= ~ROSE_COND_PEER_RX_BUSY;
-				}
+				rose->condition &= ~ROSE_COND_PEER_RX_BUSY;
 			}
-			break;
+		}
+		break;
 
-		case ROSE_DATA:	/* XXX */
-			rose->condition &= ~ROSE_COND_PEER_RX_BUSY;
-			if (!rose_validate_nr(sk, nr)) {
+	case ROSE_DATA:	/* XXX */
+		rose->condition &= ~ROSE_COND_PEER_RX_BUSY;
+		if (!rose_validate_nr(sk, nr)) {
+			rose_write_internal(sk, ROSE_RESET_REQUEST);
+			rose->condition = 0x00;
+			rose->vs        = 0;
+			rose->vr        = 0;
+			rose->va        = 0;
+			rose->vl        = 0;
+			rose->state     = ROSE_STATE_4;
+			rose_start_t2timer(sk);
+			rose_stop_idletimer(sk);
+			break;
+		}
+		rose_frames_acked(sk, nr);
+		if (ns == rose->vr) {
+			rose_start_idletimer(sk);
+			if (sock_queue_rcv_skb(sk, skb) == 0) {
+				rose->vr = (rose->vr + 1) % ROSE_MODULUS;
+				queued = 1;
+			} else {
+				/* Should never happen ! */
 				rose_write_internal(sk, ROSE_RESET_REQUEST);
 				rose->condition = 0x00;
 				rose->vs        = 0;
@@ -178,45 +183,26 @@
 				rose_stop_idletimer(sk);
 				break;
 			}
-			rose_frames_acked(sk, nr);
-			if (ns == rose->vr) {
-				rose_start_idletimer(sk);
-				if (sock_queue_rcv_skb(sk, skb) == 0) {
-					rose->vr = (rose->vr + 1) % ROSE_MODULUS;
-					queued = 1;
-				} else {
-					/* Should never happen ! */
-					rose_write_internal(sk, ROSE_RESET_REQUEST);
-					rose->condition = 0x00;
-					rose->vs        = 0;
-					rose->vr        = 0;
-					rose->va        = 0;
-					rose->vl        = 0;
-					rose->state     = ROSE_STATE_4;
-					rose_start_t2timer(sk);
-					rose_stop_idletimer(sk);
-					break;
-				}
-				if (atomic_read(&sk->rmem_alloc) > (sk->rcvbuf / 2))
-					rose->condition |= ROSE_COND_OWN_RX_BUSY;
-			}
-			/*
-			 * If the window is full, ack the frame, else start the
-			 * acknowledge hold back timer.
-			 */
-			if (((rose->vl + sysctl_rose_window_size) % ROSE_MODULUS) == rose->vr) {
-				rose->condition &= ~ROSE_COND_ACK_PENDING;
-				rose_stop_timer(sk);
-				rose_enquiry_response(sk);
-			} else {
-				rose->condition |= ROSE_COND_ACK_PENDING;
-				rose_start_hbtimer(sk);
-			}
-			break;
-
-		default:
-			printk(KERN_WARNING "ROSE: unknown %02X in state 3\n", frametype);
-			break;
+			if (atomic_read(&sk->rmem_alloc) > (sk->rcvbuf / 2))
+				rose->condition |= ROSE_COND_OWN_RX_BUSY;
+		}
+		/*
+		 * If the window is full, ack the frame, else start the
+		 * acknowledge hold back timer.
+		 */
+		if (((rose->vl + sysctl_rose_window_size) % ROSE_MODULUS) == rose->vr) {
+			rose->condition &= ~ROSE_COND_ACK_PENDING;
+			rose_stop_timer(sk);
+			rose_enquiry_response(sk);
+		} else {
+			rose->condition |= ROSE_COND_ACK_PENDING;
+			rose_start_hbtimer(sk);
+		}
+		break;
+
+	default:
+		printk(KERN_WARNING "ROSE: unknown %02X in state 3\n", frametype);
+		break;
 	}
 
 	return queued;
@@ -232,29 +218,28 @@
 	rose_cb *rose = rose_sk(sk);
 
 	switch (frametype) {
+	case ROSE_RESET_REQUEST:
+		rose_write_internal(sk, ROSE_RESET_CONFIRMATION);
+	case ROSE_RESET_CONFIRMATION:
+		rose_stop_timer(sk);
+		rose_start_idletimer(sk);
+		rose->condition = 0x00;
+		rose->va        = 0;
+		rose->vr        = 0;
+		rose->vs        = 0;
+		rose->vl        = 0;
+		rose->state     = ROSE_STATE_3;
+		rose_requeue_frames(sk);
+		break;
 
-		case ROSE_RESET_REQUEST:
-			rose_write_internal(sk, ROSE_RESET_CONFIRMATION);
-		case ROSE_RESET_CONFIRMATION:
-			rose_stop_timer(sk);
-			rose_start_idletimer(sk);
-			rose->condition = 0x00;
-			rose->va        = 0;
-			rose->vr        = 0;
-			rose->vs        = 0;
-			rose->vl        = 0;
-			rose->state     = ROSE_STATE_3;
-			rose_requeue_frames(sk);
-			break;
-
-		case ROSE_CLEAR_REQUEST:
-			rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
-			rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
-			rose->neighbour->use--;
-			break;
+	case ROSE_CLEAR_REQUEST:
+		rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION);
+		rose_disconnect(sk, 0, skb->data[3], skb->data[4]);
+		rose->neighbour->use--;
+		break;
 
-		default:
-			break;
+	default:
+		break;
 	}
 
 	return 0;
@@ -288,21 +273,21 @@
 	frametype = rose_decode(skb, &ns, &nr, &q, &d, &m);
 
 	switch (rose->state) {
-		case ROSE_STATE_1:
-			queued = rose_state1_machine(sk, skb, frametype);
-			break;
-		case ROSE_STATE_2:
-			queued = rose_state2_machine(sk, skb, frametype);
-			break;
-		case ROSE_STATE_3:
-			queued = rose_state3_machine(sk, skb, frametype, ns, nr, q, d, m);
-			break;
-		case ROSE_STATE_4:
-			queued = rose_state4_machine(sk, skb, frametype);
-			break;
-		case ROSE_STATE_5:
-			queued = rose_state5_machine(sk, skb, frametype);
-			break;
+	case ROSE_STATE_1:
+		queued = rose_state1_machine(sk, skb, frametype);
+		break;
+	case ROSE_STATE_2:
+		queued = rose_state2_machine(sk, skb, frametype);
+		break;
+	case ROSE_STATE_3:
+		queued = rose_state3_machine(sk, skb, frametype, ns, nr, q, d, m);
+		break;
+	case ROSE_STATE_4:
+		queued = rose_state4_machine(sk, skb, frametype);
+		break;
+	case ROSE_STATE_5:
+		queued = rose_state5_machine(sk, skb, frametype);
+		break;
 	}
 
 	rose_kick(sk);
diff -Nru a/net/rose/rose_link.c b/net/rose/rose_link.c
--- a/net/rose/rose_link.c	Fri Sep 20 08:20:47 2002
+++ b/net/rose/rose_link.c	Fri Sep 20 08:20:47 2002
@@ -1,19 +1,11 @@
 /*
- *	ROSE release 003
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	History
- *	ROSE 001	Jonathan(G4KLX)	Cloned from rose_timer.c
- *	ROSE 003	Jonathan(G4KLX)	New timer architecture.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
  */
-
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -142,25 +134,25 @@
 	struct sk_buff *skbn;
 
 	switch (frametype) {
-		case ROSE_RESTART_REQUEST:
-			rose_stop_t0timer(neigh);
-			neigh->restarted = 1;
-			neigh->dce_mode  = (skb->data[3] == ROSE_DTE_ORIGINATED);
-			rose_transmit_restart_confirmation(neigh);
-			break;
-
-		case ROSE_RESTART_CONFIRMATION:
-			rose_stop_t0timer(neigh);
-			neigh->restarted = 1;
-			break;
-
-		case ROSE_DIAGNOSTIC:
-			printk(KERN_WARNING "ROSE: received diagnostic #%d - %02X %02X %02X\n", skb->data[3], skb->data[4], skb->data[5], skb->data[6]);
-			break;
-
-		default:
-			printk(KERN_WARNING "ROSE: received unknown %02X with LCI 000\n", frametype);
-			break;
+	case ROSE_RESTART_REQUEST:
+		rose_stop_t0timer(neigh);
+		neigh->restarted = 1;
+		neigh->dce_mode  = (skb->data[3] == ROSE_DTE_ORIGINATED);
+		rose_transmit_restart_confirmation(neigh);
+		break;
+
+	case ROSE_RESTART_CONFIRMATION:
+		rose_stop_t0timer(neigh);
+		neigh->restarted = 1;
+		break;
+
+	case ROSE_DIAGNOSTIC:
+		printk(KERN_WARNING "ROSE: received diagnostic #%d - %02X %02X %02X\n", skb->data[3], skb->data[4], skb->data[5], skb->data[6]);
+		break;
+
+	default:
+		printk(KERN_WARNING "ROSE: received unknown %02X with LCI 000\n", frametype);
+		break;
 	}
 
 	if (neigh->restarted) {
diff -Nru a/net/rose/rose_loopback.c b/net/rose/rose_loopback.c
--- a/net/rose/rose_loopback.c	Fri Sep 20 08:20:43 2002
+++ b/net/rose/rose_loopback.c	Fri Sep 20 08:20:43 2002
@@ -1,19 +1,11 @@
 /*
- *	ROSE release 003
- *
- *	This code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	History
- *	ROSE 003	Jonathan(G4KLX)	Created this file from nr_loopback.c.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
  */
-
 #include <linux/types.h>
 #include <linux/socket.h>
 #include <linux/timer.h>
diff -Nru a/net/rose/rose_out.c b/net/rose/rose_out.c
--- a/net/rose/rose_out.c	Fri Sep 20 08:20:46 2002
+++ b/net/rose/rose_out.c	Fri Sep 20 08:20:46 2002
@@ -1,20 +1,11 @@
 /*
- *	ROSE release 003
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	History
- *	ROSE 001	Jonathan(G4KLX)	Cloned from nr_out.c
- *	ROSE 003	Jonathan(G4KLX)	New timer architecture.
- *					Removed M bit processing.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
  */
-
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -36,7 +27,7 @@
 #include <linux/interrupt.h>
 #include <net/rose.h>
 
-/* 
+/*
  *	This procedure is passed a buffer descriptor for an iframe. It builds
  *	the rest of the control part of the frame and then writes it out.
  */
@@ -52,7 +43,7 @@
 
 	rose_start_idletimer(sk);
 
-	rose_transmit_link(skb, rose->neighbour);	
+	rose_transmit_link(skb, rose->neighbour);
 }
 
 void rose_kick(struct sock *sk)
diff -Nru a/net/rose/rose_route.c b/net/rose/rose_route.c
--- a/net/rose/rose_route.c	Fri Sep 20 08:20:45 2002
+++ b/net/rose/rose_route.c	Fri Sep 20 08:20:45 2002
@@ -1,24 +1,12 @@
 /*
- *	ROSE release 003
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	History
- *	ROSE 001	Jonathan(G4KLX)	Cloned from nr_route.c.
- *			Terry(VK2KTJ)	Added support for variable length
- *					address masks.
- *	ROSE 002	Jonathan(G4KLX)	Uprated through routing of packets.
- *					Routing loop detection.
- *	ROSE 003	Jonathan(G4KLX)	New timer architecture.
- *					Added use count to neighbours.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright (C) Terry Dawson VK2KTJ (terry@animats.net)
  */
-
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -51,8 +39,11 @@
 static unsigned int rose_neigh_no = 1;
 
 static struct rose_node  *rose_node_list;
+static spinlock_t rose_node_list_lock = SPIN_LOCK_UNLOCKED;
 static struct rose_neigh *rose_neigh_list;
+static spinlock_t rose_neigh_list_lock = SPIN_LOCK_UNLOCKED;
 static struct rose_route *rose_route_list;
+static spinlock_t rose_route_list_lock = SPIN_LOCK_UNLOCKED;
 
 struct rose_neigh *rose_loopback_neigh;
 
@@ -62,27 +53,44 @@
  *	Add a new route to a node, and in the process add the node and the
  *	neighbour if it is new.
  */
-static int rose_add_node(struct rose_route_struct *rose_route, struct net_device *dev)
+static int rose_add_node(struct rose_route_struct *rose_route,
+	struct net_device *dev)
 {
 	struct rose_node  *rose_node, *rose_tmpn, *rose_tmpp;
 	struct rose_neigh *rose_neigh;
-	unsigned long flags;
-	int i;
+	int i, res = 0;
+
+	spin_lock_bh(&rose_node_list_lock);
+	spin_lock_bh(&rose_neigh_list_lock);
 
-	for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
-		if ((rose_node->mask == rose_route->mask) && (rosecmpm(&rose_route->address, &rose_node->address, rose_route->mask) == 0))
+	rose_node = rose_node_list;
+	while (rose_node != NULL) {
+		if ((rose_node->mask == rose_route->mask) &&
+		    (rosecmpm(&rose_route->address, &rose_node->address,
+		              rose_route->mask) == 0))
 			break;
+		rose_node = rose_node->next;
+	}
 
-	if (rose_node != NULL && rose_node->loopback)
-		return -EINVAL;
+	if (rose_node != NULL && rose_node->loopback) {
+		res = -EINVAL;
+		goto out;
+	}
 
-	for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
-		if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0 && rose_neigh->dev == dev)
+	rose_neigh = rose_neigh_list;
+	while (rose_neigh != NULL) {
+		if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0
+		    && rose_neigh->dev == dev)
 			break;
+		rose_neigh = rose_neigh->next;
+	}
 
 	if (rose_neigh == NULL) {
-		if ((rose_neigh = kmalloc(sizeof(*rose_neigh), GFP_ATOMIC)) == NULL)
-			return -ENOMEM;
+		rose_neigh = kmalloc(sizeof(*rose_neigh), GFP_ATOMIC);
+		if (rose_neigh == NULL) {
+			res = -ENOMEM;
+			goto out;
+		}
 
 		rose_neigh->callsign  = rose_route->neighbour;
 		rose_neigh->digipeat  = NULL;
@@ -103,22 +111,22 @@
 		if (rose_route->ndigis != 0) {
 			if ((rose_neigh->digipeat = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) {
 				kfree(rose_neigh);
-				return -ENOMEM;
+				res = -ENOMEM;
+				goto out;
 			}
 
 			rose_neigh->digipeat->ndigi      = rose_route->ndigis;
 			rose_neigh->digipeat->lastrepeat = -1;
 
 			for (i = 0; i < rose_route->ndigis; i++) {
-				rose_neigh->digipeat->calls[i]    = rose_route->digipeaters[i];
+				rose_neigh->digipeat->calls[i]    =
+					rose_route->digipeaters[i];
 				rose_neigh->digipeat->repeated[i] = 0;
 			}
 		}
 
-		save_flags(flags); cli();
 		rose_neigh->next = rose_neigh_list;
 		rose_neigh_list  = rose_neigh;
-		restore_flags(flags);
 	}
 
 	/*
@@ -142,8 +150,11 @@
 		}
 
 		/* create new node */
-		if ((rose_node = kmalloc(sizeof(*rose_node), GFP_ATOMIC)) == NULL)
-			return -ENOMEM;
+		rose_node = kmalloc(sizeof(*rose_node), GFP_ATOMIC);
+		if (rose_node == NULL) {
+			res = -ENOMEM;
+			goto out;
+		}
 
 		rose_node->address      = rose_route->address;
 		rose_node->mask         = rose_route->mask;
@@ -151,8 +162,6 @@
 		rose_node->loopback     = 0;
 		rose_node->neighbour[0] = rose_neigh;
 
-		save_flags(flags); cli();
-
 		if (rose_tmpn == NULL) {
 			if (rose_tmpp == NULL) {	/* Empty list */
 				rose_node_list  = rose_node;
@@ -170,12 +179,9 @@
 				rose_node->next = rose_tmpn;
 			}
 		}
-
-		restore_flags(flags);
-
 		rose_neigh->count++;
 
-		return 0;
+		goto out;
 	}
 
 	/* We have space, slot it in */
@@ -185,20 +191,23 @@
 		rose_neigh->count++;
 	}
 
-	return 0;
+out:
+	spin_unlock_bh(&rose_neigh_list_lock);
+	spin_unlock_bh(&rose_node_list_lock);
+
+	return res;
 }
 
+/*
+ * Caller is holding rose_node_list_lock.
+ */
 static void rose_remove_node(struct rose_node *rose_node)
 {
 	struct rose_node *s;
-	unsigned long flags;
-	
-	save_flags(flags);
-	cli();
 
+	spin_lock_bh(&rose_node_list_lock);
 	if ((s = rose_node_list) == rose_node) {
 		rose_node_list = rose_node->next;
-		restore_flags(flags);
 		kfree(rose_node);
 		return;
 	}
@@ -206,32 +215,31 @@
 	while (s != NULL && s->next != NULL) {
 		if (s->next == rose_node) {
 			s->next = rose_node->next;
-			restore_flags(flags);
 			kfree(rose_node);
 			return;
 		}
 
 		s = s->next;
 	}
-
-	restore_flags(flags);
 }
 
+/*
+ * Caller is holding rose_neigh_list_lock.
+ */
 static void rose_remove_neigh(struct rose_neigh *rose_neigh)
 {
 	struct rose_neigh *s;
-	unsigned long flags;
 
 	rose_stop_ftimer(rose_neigh);
 	rose_stop_t0timer(rose_neigh);
 
 	skb_queue_purge(&rose_neigh->queue);
 
-	save_flags(flags); cli();
+	spin_lock_bh(&rose_neigh_list_lock);
 
 	if ((s = rose_neigh_list) == rose_neigh) {
 		rose_neigh_list = rose_neigh->next;
-		restore_flags(flags);
+		spin_unlock_bh(&rose_neigh_list_lock);
 		if (rose_neigh->digipeat != NULL)
 			kfree(rose_neigh->digipeat);
 		kfree(rose_neigh);
@@ -241,7 +249,7 @@
 	while (s != NULL && s->next != NULL) {
 		if (s->next == rose_neigh) {
 			s->next = rose_neigh->next;
-			restore_flags(flags);
+			spin_unlock_bh(&rose_neigh_list_lock);
 			if (rose_neigh->digipeat != NULL)
 				kfree(rose_neigh->digipeat);
 			kfree(rose_neigh);
@@ -250,14 +258,15 @@
 
 		s = s->next;
 	}
-
-	restore_flags(flags);
+	spin_unlock_bh(&rose_neigh_list_lock);
 }
 
+/*
+ * Caller is holding rose_route_list_lock.
+ */
 static void rose_remove_route(struct rose_route *rose_route)
 {
 	struct rose_route *s;
-	unsigned long flags;
 
 	if (rose_route->neigh1 != NULL)
 		rose_route->neigh1->use--;
@@ -265,11 +274,8 @@
 	if (rose_route->neigh2 != NULL)
 		rose_route->neigh2->use--;
 
-	save_flags(flags); cli();
-
 	if ((s = rose_route_list) == rose_route) {
 		rose_route_list = rose_route->next;
-		restore_flags(flags);
 		kfree(rose_route);
 		return;
 	}
@@ -277,40 +283,54 @@
 	while (s != NULL && s->next != NULL) {
 		if (s->next == rose_route) {
 			s->next = rose_route->next;
-			restore_flags(flags);
 			kfree(rose_route);
 			return;
 		}
 
 		s = s->next;
 	}
-
-	restore_flags(flags);
 }
 
 /*
  *	"Delete" a node. Strictly speaking remove a route to a node. The node
  *	is only deleted if no routes are left to it.
  */
-static int rose_del_node(struct rose_route_struct *rose_route, struct net_device *dev)
+static int rose_del_node(struct rose_route_struct *rose_route,
+	struct net_device *dev)
 {
 	struct rose_node  *rose_node;
 	struct rose_neigh *rose_neigh;
-	int i;
+	int i, err = 0;
 
-	for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
-		if ((rose_node->mask == rose_route->mask) && (rosecmpm(&rose_route->address, &rose_node->address, rose_route->mask) == 0))
-			break;
+	spin_lock_bh(&rose_node_list_lock);
+	spin_lock_bh(&rose_neigh_list_lock);
 
-	if (rose_node == NULL) return -EINVAL;
+	rose_node = rose_node_list;
+	while (rose_node != NULL) {
+		if ((rose_node->mask == rose_route->mask) &&
+		    (rosecmpm(&rose_route->address, &rose_node->address,
+		              rose_route->mask) == 0))
+			break;
+		rose_node = rose_node->next;
+	}
 
-	if (rose_node->loopback) return -EINVAL;
+	if (rose_node == NULL || rose_node->loopback) {
+		err = -EINVAL;
+		goto out;
+	}
 
-	for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
-		if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0 && rose_neigh->dev == dev)
+	rose_neigh = rose_neigh_list;
+	while (rose_neigh != NULL) {
+		if (ax25cmp(&rose_route->neighbour, &rose_neigh->callsign) == 0
+		    && rose_neigh->dev == dev)
 			break;
+		rose_neigh = rose_neigh->next;
+	}
 
-	if (rose_neigh == NULL) return -EINVAL;
+	if (rose_neigh == NULL) {
+		err = -EINVAL;
+		goto out;
+	}
 
 	for (i = 0; i < rose_node->count; i++) {
 		if (rose_node->neighbour[i] == rose_neigh) {
@@ -325,20 +345,26 @@
 				rose_remove_node(rose_node);
 			} else {
 				switch (i) {
-					case 0:
-						rose_node->neighbour[0] = rose_node->neighbour[1];
-					case 1:
-						rose_node->neighbour[1] = rose_node->neighbour[2];
-					case 2:
-						break;
+				case 0:
+					rose_node->neighbour[0] =
+						rose_node->neighbour[1];
+				case 1:
+					rose_node->neighbour[1] =
+						rose_node->neighbour[2];
+				case 2:
+					break;
 				}
 			}
-
-			return 0;
+			goto out;
 		}
 	}
+	err = -EINVAL;
+
+out:
+	spin_unlock_bh(&rose_neigh_list_lock);
+	spin_unlock_bh(&rose_node_list_lock);
 
-	return -EINVAL;
+	return err;
 }
 
 /*
@@ -346,8 +372,6 @@
  */
 int rose_add_loopback_neigh(void)
 {
-	unsigned long flags;
-
 	if ((rose_loopback_neigh = kmalloc(sizeof(struct rose_neigh), GFP_ATOMIC)) == NULL)
 		return -ENOMEM;
 
@@ -367,10 +391,10 @@
 	init_timer(&rose_loopback_neigh->ftimer);
 	init_timer(&rose_loopback_neigh->t0timer);
 
-	save_flags(flags); cli();
+	spin_lock_bh(&rose_neigh_list_lock);
 	rose_loopback_neigh->next = rose_neigh_list;
 	rose_neigh_list           = rose_loopback_neigh;
-	restore_flags(flags);
+	spin_unlock_bh(&rose_neigh_list_lock);
 
 	return 0;
 }
@@ -381,16 +405,26 @@
 int rose_add_loopback_node(rose_address *address)
 {
 	struct rose_node *rose_node;
-	unsigned long flags;
+	unsigned int err = 0;
+
+	spin_lock_bh(&rose_node_list_lock);
 
-	for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
-		if ((rose_node->mask == 10) && (rosecmpm(address, &rose_node->address, 10) == 0) && rose_node->loopback)
+	rose_node = rose_node_list;
+	while (rose_node != NULL) {
+		if ((rose_node->mask == 10) &&
+		     (rosecmpm(address, &rose_node->address, 10) == 0) &&
+		     rose_node->loopback)
 			break;
+		rose_node = rose_node->next;
+	}
 
-	if (rose_node != NULL) return 0;
-	
-	if ((rose_node = kmalloc(sizeof(*rose_node), GFP_ATOMIC)) == NULL)
-		return -ENOMEM;
+	if (rose_node != NULL)
+		goto out;
+
+	if ((rose_node = kmalloc(sizeof(*rose_node), GFP_ATOMIC)) == NULL) {
+		err = -ENOMEM;
+		goto out;
+	}
 
 	rose_node->address      = *address;
 	rose_node->mask         = 10;
@@ -399,13 +433,14 @@
 	rose_node->neighbour[0] = rose_loopback_neigh;
 
 	/* Insert at the head of list. Address is always mask=10 */
-	save_flags(flags); cli();
 	rose_node->next = rose_node_list;
 	rose_node_list  = rose_node;
-	restore_flags(flags);
 
 	rose_loopback_neigh->count++;
 
+out:
+	spin_unlock_bh(&rose_node_list_lock);
+
 	return 0;
 }
 
@@ -416,15 +451,26 @@
 {
 	struct rose_node *rose_node;
 
-	for (rose_node = rose_node_list; rose_node != NULL; rose_node = rose_node->next)
-		if ((rose_node->mask == 10) && (rosecmpm(address, &rose_node->address, 10) == 0) && rose_node->loopback)
+	spin_lock_bh(&rose_node_list_lock);
+
+	rose_node = rose_node_list;
+	while (rose_node != NULL) {
+		if ((rose_node->mask == 10) &&
+		    (rosecmpm(address, &rose_node->address, 10) == 0) &&
+		    rose_node->loopback)
 			break;
+		rose_node = rose_node->next;
+	}
 
-	if (rose_node == NULL) return;
+	if (rose_node == NULL)
+		goto out;
 
 	rose_remove_node(rose_node);
 
 	rose_loopback_neigh->count--;
+
+out:
+	spin_unlock_bh(&rose_node_list_lock);
 }
 
 /*
@@ -432,52 +478,62 @@
  */
 void rose_rt_device_down(struct net_device *dev)
 {
-	struct rose_neigh *s, *rose_neigh = rose_neigh_list;
+	struct rose_neigh *s, *rose_neigh;
 	struct rose_node  *t, *rose_node;
 	int i;
 
+	spin_lock_bh(&rose_node_list_lock);
+	spin_lock_bh(&rose_neigh_list_lock);
+	rose_neigh = rose_neigh_list;
 	while (rose_neigh != NULL) {
 		s          = rose_neigh;
 		rose_neigh = rose_neigh->next;
 
-		if (s->dev == dev) {
-			rose_node = rose_node_list;
+		if (s->dev != dev)
+			continue;
 
-			while (rose_node != NULL) {
-				t         = rose_node;
-				rose_node = rose_node->next;
-
-				for (i = 0; i < t->count; i++) {
-					if (t->neighbour[i] == s) {
-						t->count--;
-
-						switch (i) {
-							case 0:
-								t->neighbour[0] = t->neighbour[1];
-							case 1:
-								t->neighbour[1] = t->neighbour[2];
-							case 2:
-								break;
-						}
-					}
-				}
+		rose_node = rose_node_list;
+
+		while (rose_node != NULL) {
+			t         = rose_node;
+			rose_node = rose_node->next;
+
+			for (i = 0; i < t->count; i++) {
+				if (t->neighbour[i] != s)
+					continue;
+
+				t->count--;
 
-				if (t->count <= 0)
-					rose_remove_node(t);
+				switch (i) {
+				case 0:
+					t->neighbour[0] = t->neighbour[1];
+				case 1:
+					t->neighbour[1] = t->neighbour[2];
+				case 2:
+					break;
+				}
 			}
 
-			rose_remove_neigh(s);
+			if (t->count <= 0)
+				rose_remove_node(t);
 		}
+
+		rose_remove_neigh(s);
 	}
+	spin_unlock_bh(&rose_neigh_list_lock);
+	spin_unlock_bh(&rose_node_list_lock);
 }
 
+#if 0 /* Currently unused */
 /*
  *	A device has been removed. Remove its links.
  */
 void rose_route_device_down(struct net_device *dev)
 {
-	struct rose_route *s, *rose_route = rose_route_list;
+	struct rose_route *s, *rose_route;
 
+	spin_lock_bh(&rose_route_list_lock);
+	rose_route = rose_route_list;
 	while (rose_route != NULL) {
 		s          = rose_route;
 		rose_route = rose_route->next;
@@ -485,7 +541,9 @@
 		if (s->neigh1->dev == dev || s->neigh2->dev == dev)
 			rose_remove_route(s);
 	}
+	spin_unlock_bh(&rose_route_list_lock);
 }
+#endif
 
 /*
  *	Clear all nodes and neighbours out, except for neighbours with
@@ -494,8 +552,14 @@
  */
 static int rose_clear_routes(void)
 {
-	struct rose_neigh *s, *rose_neigh = rose_neigh_list;
-	struct rose_node  *t, *rose_node  = rose_node_list;
+	struct rose_neigh *s, *rose_neigh;
+	struct rose_node  *t, *rose_node;
+
+	spin_lock_bh(&rose_node_list_lock);
+	spin_lock_bh(&rose_neigh_list_lock);
+
+	rose_neigh = rose_neigh_list;
+	rose_node  = rose_node_list;
 
 	while (rose_node != NULL) {
 		t         = rose_node;
@@ -514,6 +578,9 @@
 		}
 	}
 
+	spin_unlock_bh(&rose_neigh_list_lock);
+	spin_unlock_bh(&rose_node_list_lock);
+
 	return 0;
 }
 
@@ -603,18 +670,22 @@
 /*
  *	Find a neighbour given a ROSE address.
  */
-struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause, unsigned char *diagnostic)
+struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause,
+	unsigned char *diagnostic)
 {
+	struct rose_neigh *res = NULL;
 	struct rose_node *node;
 	int failed = 0;
 	int i;
 
+	spin_lock_bh(&rose_node_list_lock);
 	for (node = rose_node_list; node != NULL; node = node->next) {
 		if (rosecmpm(addr, &node->address, node->mask) == 0) {
 			for (i = 0; i < node->count; i++) {
 				if (!rose_ftimer_running(node->neighbour[i])) {
-					return node->neighbour[i]; }
-				else
+					res = node->neighbour[i];
+					goto out;
+				} else
 					failed = 1;
 			}
 			break;
@@ -629,7 +700,10 @@
 		*diagnostic = 0;
 	}
 
-	return NULL;
+out:
+	spin_unlock_bh(&rose_node_list_lock);
+
+	return res;
 }
 
 /*
@@ -642,38 +716,36 @@
 	int err;
 
 	switch (cmd) {
-
-		case SIOCADDRT:
-			if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct)))
-				return -EFAULT;
-			if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL)
-				return -EINVAL;
-			if (rose_dev_exists(&rose_route.address)) { /* Can't add routes to ourself */
-				dev_put(dev);
-				return -EINVAL;
-			}
-			if (rose_route.mask > 10) /* Mask can't be more than 10 digits */
-				return -EINVAL;
-
-			err = rose_add_node(&rose_route, dev);
+	case SIOCADDRT:
+		if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct)))
+			return -EFAULT;
+		if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL)
+			return -EINVAL;
+		if (rose_dev_exists(&rose_route.address)) { /* Can't add routes to ourself */
 			dev_put(dev);
-			return err;
+			return -EINVAL;
+		}
+		if (rose_route.mask > 10) /* Mask can't be more than 10 digits */
+			return -EINVAL;
 
-		case SIOCDELRT:
-			if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct)))
-				return -EFAULT;
-			if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL)
-				return -EINVAL;
-			err = rose_del_node(&rose_route, dev);
-			dev_put(dev);
-			return err;
-				
+		err = rose_add_node(&rose_route, dev);
+		dev_put(dev);
+		return err;
+
+	case SIOCDELRT:
+		if (copy_from_user(&rose_route, arg, sizeof(struct rose_route_struct)))
+			return -EFAULT;
+		if ((dev = rose_ax25_dev_get(rose_route.device)) == NULL)
+			return -EINVAL;
+		err = rose_del_node(&rose_route, dev);
+		dev_put(dev);
+		return err;
 
-		case SIOCRSCLRRT:
-			return rose_clear_routes();
+	case SIOCRSCLRRT:
+		return rose_clear_routes();
 
-		default:
-			return -EINVAL;
+	default:
+		return -EINVAL;
 	}
 
 	return 0;
@@ -690,6 +762,8 @@
 
 	skb_queue_purge(&rose_neigh->queue);
 
+	spin_lock_bh(&rose_route_list_lock);
+
 	rose_route = rose_route_list;
 
 	while (rose_route != NULL) {
@@ -716,6 +790,7 @@
 
 		rose_route = rose_route->next;
 	}
+	spin_unlock_bh(&rose_route_list_lock);
 }
 
 /*
@@ -727,16 +802,21 @@
 {
 	struct rose_neigh *rose_neigh;
 
-	for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
+	spin_lock_bh(&rose_neigh_list_lock);
+	rose_neigh = rose_neigh_list;
+	while (rose_neigh != NULL) {
 		if (rose_neigh->ax25 == ax25)
 			break;
+		rose_neigh = rose_neigh->next;
+	}
 
-	if (rose_neigh == NULL) return;
-
-	rose_neigh->ax25 = NULL;
+	if (rose_neigh != NULL) {
+		rose_neigh->ax25 = NULL;
 
-	rose_del_route_by_neigh(rose_neigh);
-	rose_kill_by_neigh(rose_neigh);
+		rose_del_route_by_neigh(rose_neigh);
+		rose_kill_by_neigh(rose_neigh);
+	}
+	spin_unlock_bh(&rose_neigh_list_lock);
 }
 
 /*
@@ -769,12 +849,11 @@
 	unsigned int lci, new_lci;
 	unsigned char cause, diagnostic;
 	struct net_device *dev;
-	unsigned long flags;
-	int len;
+	int len, res = 0;
 
 #if 0
 	if (call_in_firewall(PF_ROSE, skb->dev, skb->data, NULL, &skb) != FW_ACCEPT)
-		return 0;
+		return res;
 #endif
 
 	frametype = skb->data[2];
@@ -782,13 +861,22 @@
 	src_addr  = (rose_address *)(skb->data + 9);
 	dest_addr = (rose_address *)(skb->data + 4);
 
-	for (rose_neigh = rose_neigh_list; rose_neigh != NULL; rose_neigh = rose_neigh->next)
-		if (ax25cmp(&ax25->dest_addr, &rose_neigh->callsign) == 0 && ax25->ax25_dev->dev == rose_neigh->dev)
+	spin_lock_bh(&rose_node_list_lock);
+	spin_lock_bh(&rose_neigh_list_lock);
+	spin_lock_bh(&rose_route_list_lock);
+
+	rose_neigh = rose_neigh_list;
+	while (rose_neigh != NULL) {
+		if (ax25cmp(&ax25->dest_addr, &rose_neigh->callsign) == 0 &&
+		    ax25->ax25_dev->dev == rose_neigh->dev)
 			break;
+		rose_neigh = rose_neigh->next;
+	}
 
 	if (rose_neigh == NULL) {
-		printk("rose_route : unknown neighbour or device %s\n", ax2asc(&ax25->dest_addr));
-		return 0;
+		printk("rose_route : unknown neighbour or device %s\n",
+		       ax2asc(&ax25->dest_addr));
+		goto out;
 	}
 
 	/*
@@ -802,7 +890,7 @@
 	 */
 	if (lci == 0) {
 		rose_link_rx_restart(skb, rose_neigh, frametype);
-		return 0;
+		goto out;
 	}
 
 	/*
@@ -828,7 +916,8 @@
 		}
 		else {
 			skb->h.raw = skb->data;
-			return rose_process_rx_frame(sk, skb);
+			res = rose_process_rx_frame(sk, skb);
+			goto out;
 		}
 	}
 
@@ -837,21 +926,23 @@
 	 */
 	if (frametype == ROSE_CALL_REQUEST)
 		if ((dev = rose_dev_get(dest_addr)) != NULL) {
-			int err = rose_rx_call_request(skb, dev, rose_neigh, lci);
+			res = rose_rx_call_request(skb, dev, rose_neigh, lci);
 			dev_put(dev);
-			return err;
+			goto out;
 		}
 
 	if (!sysctl_rose_routing_control) {
 		rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 0);
-		return 0;
+		goto out;
 	}
 
 	/*
 	 *	Route it to the next in line if we have an entry for it.
 	 */
-	for (rose_route = rose_route_list; rose_route != NULL; rose_route = rose_route->next) {
-		if (rose_route->lci1 == lci && rose_route->neigh1 == rose_neigh) {
+	rose_route = rose_route_list;
+	while (rose_route != NULL) {
+		if (rose_route->lci1 == lci &&
+		    rose_route->neigh1 == rose_neigh) {
 			if (frametype == ROSE_CALL_REQUEST) {
 				/* F6FBB - Remove an existing unused route */
 				rose_remove_route(rose_route);
@@ -863,14 +954,16 @@
 				rose_transmit_link(skb, rose_route->neigh2);
 				if (frametype == ROSE_CLEAR_CONFIRMATION)
 					rose_remove_route(rose_route);
-				return 1;
+				res = 1;
+				goto out;
 			} else {
 				if (frametype == ROSE_CLEAR_CONFIRMATION)
 					rose_remove_route(rose_route);
-				return 0;
+				goto out;
 			}
 		}
-		if (rose_route->lci2 == lci && rose_route->neigh2 == rose_neigh) {
+		if (rose_route->lci2 == lci &&
+		    rose_route->neigh2 == rose_neigh) {
 			if (frametype == ROSE_CALL_REQUEST) {
 				/* F6FBB - Remove an existing unused route */
 				rose_remove_route(rose_route);
@@ -882,13 +975,15 @@
 				rose_transmit_link(skb, rose_route->neigh1);
 				if (frametype == ROSE_CLEAR_CONFIRMATION)
 					rose_remove_route(rose_route);
-				return 1;
+				res = 1;
+				goto out;
 			} else {
 				if (frametype == ROSE_CLEAR_CONFIRMATION)
 					rose_remove_route(rose_route);
-				return 0;
+				goto out;
 			}
 		}
+		rose_route = rose_route->next;
 	}
 
 	/*
@@ -903,38 +998,40 @@
 	len += (((skb->data[3] >> 0) & 0x0F) + 1) / 2;
 
 	memset(&facilities, 0x00, sizeof(struct rose_facilities_struct));
-	
+
 	if (!rose_parse_facilities(skb->data + len + 4, &facilities)) {
 		rose_transmit_clear_request(rose_neigh, lci, ROSE_INVALID_FACILITY, 76);
-		return 0;
+		goto out;
 	}
 
 	/*
 	 *	Check for routing loops.
 	 */
-	for (rose_route = rose_route_list; rose_route != NULL; rose_route = rose_route->next) {
+	rose_route = rose_route_list;
+	while (rose_route != NULL) {
 		if (rose_route->rand == facilities.rand &&
 		    rosecmp(src_addr, &rose_route->src_addr) == 0 &&
 		    ax25cmp(&facilities.dest_call, &rose_route->src_call) == 0 &&
 		    ax25cmp(&facilities.source_call, &rose_route->dest_call) == 0) {
 			rose_transmit_clear_request(rose_neigh, lci, ROSE_NOT_OBTAINABLE, 120);
-			return 0;
+			goto out;
 		}
+		rose_route = rose_route->next;
 	}
 
 	if ((new_neigh = rose_get_neigh(dest_addr, &cause, &diagnostic)) == NULL) {
 		rose_transmit_clear_request(rose_neigh, lci, cause, diagnostic);
-		return 0;
+		goto out;
 	}
 
 	if ((new_lci = rose_new_lci(new_neigh)) == 0) {
 		rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 71);
-		return 0;
+		goto out;
 	}
 
 	if ((rose_route = kmalloc(sizeof(*rose_route), GFP_ATOMIC)) == NULL) {
 		rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 120);
-		return 0;
+		goto out;
 	}
 
 	rose_route->lci1      = lci;
@@ -950,18 +1047,22 @@
 	rose_route->neigh1->use++;
 	rose_route->neigh2->use++;
 
-	save_flags(flags); cli();
 	rose_route->next = rose_route_list;
 	rose_route_list  = rose_route;
-	restore_flags(flags);
 
 	skb->data[0] &= 0xF0;
 	skb->data[0] |= (rose_route->lci2 >> 8) & 0x0F;
 	skb->data[1]  = (rose_route->lci2 >> 0) & 0xFF;
 
 	rose_transmit_link(skb, rose_route->neigh2);
+	res = 1;
+
+out:
+	spin_unlock_bh(&rose_route_list_lock);
+	spin_unlock_bh(&rose_neigh_list_lock);
+	spin_unlock_bh(&rose_node_list_lock);
 
-	return 1;
+	return res;
 }
 
 int rose_nodes_get_info(char *buffer, char **start, off_t offset, int length)
@@ -972,7 +1073,7 @@
 	off_t begin = 0;
 	int i;
 
-	cli();
+	spin_lock_bh(&rose_neigh_list_lock);
 
 	len += sprintf(buffer, "address    mask n neigh neigh neigh\n");
 
@@ -1004,16 +1105,16 @@
 		if (pos > offset + length)
 			break;
 	}
-
-	sti();
+	spin_unlock_bh(&rose_neigh_list_lock);
 
 	*start = buffer + (offset - begin);
 	len   -= (offset - begin);
 
-	if (len > length) len = length;
+	if (len > length)
+		len = length;
 
 	return len;
-} 
+}
 
 int rose_neigh_get_info(char *buffer, char **start, off_t offset, int length)
 {
@@ -1023,7 +1124,7 @@
 	off_t begin = 0;
 	int i;
 
-	cli();
+	spin_lock_bh(&rose_neigh_list_lock);
 
 	len += sprintf(buffer, "addr  callsign  dev  count use mode restart  t0  tf digipeaters\n");
 
@@ -1059,15 +1160,16 @@
 		/* } */
 	}
 
-	sti();
+	spin_unlock_bh(&rose_neigh_list_lock);
 
 	*start = buffer + (offset - begin);
 	len   -= (offset - begin);
 
-	if (len > length) len = length;
+	if (len > length)
+		len = length;
 
 	return len;
-} 
+}
 
 int rose_routes_get_info(char *buffer, char **start, off_t offset, int length)
 {
@@ -1076,7 +1178,7 @@
 	off_t pos   = 0;
 	off_t begin = 0;
 
-	cli();
+	spin_lock_bh(&rose_route_list_lock);
 
 	len += sprintf(buffer, "lci  address     callsign   neigh  <-> lci  address     callsign   neigh\n");
 
@@ -1112,15 +1214,16 @@
 			break;
 	}
 
-	sti();
+	spin_unlock_bh(&rose_route_list_lock);
 
 	*start = buffer + (offset - begin);
 	len   -= (offset - begin);
 
-	if (len > length) len = length;
+	if (len > length)
+		len = length;
 
 	return len;
-} 
+}
 
 /*
  *	Release all memory associated with ROSE routing structures.
diff -Nru a/net/rose/rose_subr.c b/net/rose/rose_subr.c
--- a/net/rose/rose_subr.c	Fri Sep 20 08:20:46 2002
+++ b/net/rose/rose_subr.c	Fri Sep 20 08:20:46 2002
@@ -1,20 +1,11 @@
 /*
- *	ROSE release 003
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	History
- *	ROSE 001	Jonathan(G4KLX)	Cloned from nr_subr.c
- *	ROSE 002	Jonathan(G4KLX)	Centralised disconnect processing.
- *	ROSE 003	Jonathan(G4KLX)	Added use count to neighbours.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
  */
-
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -103,7 +94,7 @@
 	return nr == rose->vs;
 }
 
-/* 
+/*
  *  This routine is called when the packet layer internally generates a
  *  control frame.
  */
@@ -119,16 +110,16 @@
 	len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN + 1;
 
 	switch (frametype) {
-		case ROSE_CALL_REQUEST:
-			len   += 1 + ROSE_ADDR_LEN + ROSE_ADDR_LEN;
-			faclen = rose_create_facilities(buffer, rose);
-			len   += faclen;
-			break;
-		case ROSE_CALL_ACCEPTED:
-		case ROSE_CLEAR_REQUEST:
-		case ROSE_RESET_REQUEST:
-			len   += 2;
-			break;
+	case ROSE_CALL_REQUEST:
+		len   += 1 + ROSE_ADDR_LEN + ROSE_ADDR_LEN;
+		faclen = rose_create_facilities(buffer, rose);
+		len   += faclen;
+		break;
+	case ROSE_CALL_ACCEPTED:
+	case ROSE_CLEAR_REQUEST:
+	case ROSE_RESET_REQUEST:
+		len   += 2;
+		break;
 	}
 
 	if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
@@ -138,70 +129,69 @@
 	 *	Space for AX.25 header and PID.
 	 */
 	skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 1);
-	
+
 	dptr = skb_put(skb, skb_tailroom(skb));
 
 	lci1 = (rose->lci >> 8) & 0x0F;
 	lci2 = (rose->lci >> 0) & 0xFF;
 
 	switch (frametype) {
-
-		case ROSE_CALL_REQUEST:
-			*dptr++ = ROSE_GFI | lci1;
-			*dptr++ = lci2;
-			*dptr++ = frametype;
-			*dptr++ = 0xAA;
-			memcpy(dptr, &rose->dest_addr,  ROSE_ADDR_LEN);
-			dptr   += ROSE_ADDR_LEN;
-			memcpy(dptr, &rose->source_addr, ROSE_ADDR_LEN);
-			dptr   += ROSE_ADDR_LEN;
-			memcpy(dptr, buffer, faclen);
-			dptr   += faclen;
-			break;
-
-		case ROSE_CALL_ACCEPTED:
-			*dptr++ = ROSE_GFI | lci1;
-			*dptr++ = lci2;
-			*dptr++ = frametype;
-			*dptr++ = 0x00;		/* Address length */
-			*dptr++ = 0;		/* Facilities length */
-			break;
-
-		case ROSE_CLEAR_REQUEST:
-			*dptr++ = ROSE_GFI | lci1;
-			*dptr++ = lci2;
-			*dptr++ = frametype;
-			*dptr++ = rose->cause;
-			*dptr++ = rose->diagnostic;
-			break;
-
-		case ROSE_RESET_REQUEST:
-			*dptr++ = ROSE_GFI | lci1;
-			*dptr++ = lci2;
-			*dptr++ = frametype;
-			*dptr++ = ROSE_DTE_ORIGINATED;
-			*dptr++ = 0;
-			break;
-
-		case ROSE_RR:
-		case ROSE_RNR:
-			*dptr++ = ROSE_GFI | lci1;
-			*dptr++ = lci2;
-			*dptr   = frametype;
-			*dptr++ |= (rose->vr << 5) & 0xE0;
-			break;
-
-		case ROSE_CLEAR_CONFIRMATION:
-		case ROSE_RESET_CONFIRMATION:
-			*dptr++ = ROSE_GFI | lci1;
-			*dptr++ = lci2;
-			*dptr++  = frametype;
-			break;
-
-		default:
-			printk(KERN_ERR "ROSE: rose_write_internal - invalid frametype %02X\n", frametype);
-			kfree_skb(skb);
-			return;
+	case ROSE_CALL_REQUEST:
+		*dptr++ = ROSE_GFI | lci1;
+		*dptr++ = lci2;
+		*dptr++ = frametype;
+		*dptr++ = 0xAA;
+		memcpy(dptr, &rose->dest_addr,  ROSE_ADDR_LEN);
+		dptr   += ROSE_ADDR_LEN;
+		memcpy(dptr, &rose->source_addr, ROSE_ADDR_LEN);
+		dptr   += ROSE_ADDR_LEN;
+		memcpy(dptr, buffer, faclen);
+		dptr   += faclen;
+		break;
+
+	case ROSE_CALL_ACCEPTED:
+		*dptr++ = ROSE_GFI | lci1;
+		*dptr++ = lci2;
+		*dptr++ = frametype;
+		*dptr++ = 0x00;		/* Address length */
+		*dptr++ = 0;		/* Facilities length */
+		break;
+
+	case ROSE_CLEAR_REQUEST:
+		*dptr++ = ROSE_GFI | lci1;
+		*dptr++ = lci2;
+		*dptr++ = frametype;
+		*dptr++ = rose->cause;
+		*dptr++ = rose->diagnostic;
+		break;
+
+	case ROSE_RESET_REQUEST:
+		*dptr++ = ROSE_GFI | lci1;
+		*dptr++ = lci2;
+		*dptr++ = frametype;
+		*dptr++ = ROSE_DTE_ORIGINATED;
+		*dptr++ = 0;
+		break;
+
+	case ROSE_RR:
+	case ROSE_RNR:
+		*dptr++ = ROSE_GFI | lci1;
+		*dptr++ = lci2;
+		*dptr   = frametype;
+		*dptr++ |= (rose->vr << 5) & 0xE0;
+		break;
+
+	case ROSE_CLEAR_CONFIRMATION:
+	case ROSE_RESET_CONFIRMATION:
+		*dptr++ = ROSE_GFI | lci1;
+		*dptr++ = lci2;
+		*dptr++  = frametype;
+		break;
+
+	default:
+		printk(KERN_ERR "ROSE: rose_write_internal - invalid frametype %02X\n", frametype);
+		kfree_skb(skb);
+		return;
 	}
 
 	rose_transmit_link(skb, rose->neighbour);
@@ -216,15 +206,15 @@
 	*ns = *nr = *q = *d = *m = 0;
 
 	switch (frame[2]) {
-		case ROSE_CALL_REQUEST:
-		case ROSE_CALL_ACCEPTED:
-		case ROSE_CLEAR_REQUEST:
-		case ROSE_CLEAR_CONFIRMATION:
-		case ROSE_RESET_REQUEST:
-		case ROSE_RESET_CONFIRMATION:
-			return frame[2];
-		default:
-			break;
+	case ROSE_CALL_REQUEST:
+	case ROSE_CALL_ACCEPTED:
+	case ROSE_CLEAR_REQUEST:
+	case ROSE_CLEAR_CONFIRMATION:
+	case ROSE_RESET_REQUEST:
+	case ROSE_RESET_CONFIRMATION:
+		return frame[2];
+	default:
+		break;
 	}
 
 	if ((frame[2] & 0x1F) == ROSE_RR  ||
@@ -253,61 +243,61 @@
 
 	do {
 		switch (*p & 0xC0) {
-			case 0x00:
-				p   += 2;
-				n   += 2;
-				len -= 2;
-				break;
+		case 0x00:
+			p   += 2;
+			n   += 2;
+			len -= 2;
+			break;
 
-			case 0x40:
-				if (*p == FAC_NATIONAL_RAND)
-					facilities->rand = ((p[1] << 8) & 0xFF00) + ((p[2] << 0) & 0x00FF);
-				p   += 3;
-				n   += 3;
-				len -= 3;
-				break;
+		case 0x40:
+			if (*p == FAC_NATIONAL_RAND)
+				facilities->rand = ((p[1] << 8) & 0xFF00) + ((p[2] << 0) & 0x00FF);
+			p   += 3;
+			n   += 3;
+			len -= 3;
+			break;
 
-			case 0x80:
-				p   += 4;
-				n   += 4;
-				len -= 4;
-				break;
+		case 0x80:
+			p   += 4;
+			n   += 4;
+			len -= 4;
+			break;
 
-			case 0xC0:
-				l = p[1];
-				if (*p == FAC_NATIONAL_DEST_DIGI) {
-					if (!fac_national_digis_received) {
-						memcpy(&facilities->source_digis[0], p + 2, AX25_ADDR_LEN);
-						facilities->source_ndigis = 1;
-					}
-				}
-				else if (*p == FAC_NATIONAL_SRC_DIGI) {
-					if (!fac_national_digis_received) {
-						memcpy(&facilities->dest_digis[0], p + 2, AX25_ADDR_LEN);
-						facilities->dest_ndigis = 1;
-					}
+		case 0xC0:
+			l = p[1];
+			if (*p == FAC_NATIONAL_DEST_DIGI) {
+				if (!fac_national_digis_received) {
+					memcpy(&facilities->source_digis[0], p + 2, AX25_ADDR_LEN);
+					facilities->source_ndigis = 1;
 				}
-				else if (*p == FAC_NATIONAL_FAIL_CALL) {
-					memcpy(&facilities->fail_call, p + 2, AX25_ADDR_LEN);
-				}
-				else if (*p == FAC_NATIONAL_FAIL_ADD) {
-					memcpy(&facilities->fail_addr, p + 3, ROSE_ADDR_LEN);
+			}
+			else if (*p == FAC_NATIONAL_SRC_DIGI) {
+				if (!fac_national_digis_received) {
+					memcpy(&facilities->dest_digis[0], p + 2, AX25_ADDR_LEN);
+					facilities->dest_ndigis = 1;
 				}
-				else if (*p == FAC_NATIONAL_DIGIS) {
-					fac_national_digis_received = 1;
-					facilities->source_ndigis = 0;
-					facilities->dest_ndigis   = 0;
-					for (pt = p + 2, lg = 0 ; lg < l ; pt += AX25_ADDR_LEN, lg += AX25_ADDR_LEN) {
-						if (pt[6] & AX25_HBIT)
-							memcpy(&facilities->dest_digis[facilities->dest_ndigis++], pt, AX25_ADDR_LEN);
-						else
-							memcpy(&facilities->source_digis[facilities->source_ndigis++], pt, AX25_ADDR_LEN);
-					}
+			}
+			else if (*p == FAC_NATIONAL_FAIL_CALL) {
+				memcpy(&facilities->fail_call, p + 2, AX25_ADDR_LEN);
+			}
+			else if (*p == FAC_NATIONAL_FAIL_ADD) {
+				memcpy(&facilities->fail_addr, p + 3, ROSE_ADDR_LEN);
+			}
+			else if (*p == FAC_NATIONAL_DIGIS) {
+				fac_national_digis_received = 1;
+				facilities->source_ndigis = 0;
+				facilities->dest_ndigis   = 0;
+				for (pt = p + 2, lg = 0 ; lg < l ; pt += AX25_ADDR_LEN, lg += AX25_ADDR_LEN) {
+					if (pt[6] & AX25_HBIT)
+						memcpy(&facilities->dest_digis[facilities->dest_ndigis++], pt, AX25_ADDR_LEN);
+					else
+						memcpy(&facilities->source_digis[facilities->source_ndigis++], pt, AX25_ADDR_LEN);
 				}
-				p   += l + 2;
-				n   += l + 2;
-				len -= l + 2;
-				break;
+			}
+			p   += l + 2;
+			n   += l + 2;
+			len -= l + 2;
+			break;
 		}
 	} while (*p != 0x00 && len > 0);
 
@@ -321,49 +311,50 @@
 
 	do {
 		switch (*p & 0xC0) {
-			case 0x00:
-				p   += 2;
-				n   += 2;
-				len -= 2;
-				break;
+		case 0x00:
+			p   += 2;
+			n   += 2;
+			len -= 2;
+			break;
 
-			case 0x40:
-				p   += 3;
-				n   += 3;
-				len -= 3;
-				break;
+		case 0x40:
+			p   += 3;
+			n   += 3;
+			len -= 3;
+			break;
 
-			case 0x80:
-				p   += 4;
-				n   += 4;
-				len -= 4;
-				break;
+		case 0x80:
+			p   += 4;
+			n   += 4;
+			len -= 4;
+			break;
 
-			case 0xC0:
-				l = p[1];
-				if (*p == FAC_CCITT_DEST_NSAP) {
-					memcpy(&facilities->source_addr, p + 7, ROSE_ADDR_LEN);
-					memcpy(callsign, p + 12,   l - 10);
-					callsign[l - 10] = '\0';
-					facilities->source_call = *asc2ax(callsign);
-				}
-				if (*p == FAC_CCITT_SRC_NSAP) {
-					memcpy(&facilities->dest_addr, p + 7, ROSE_ADDR_LEN);
-					memcpy(callsign, p + 12, l - 10);
-					callsign[l - 10] = '\0';
-					facilities->dest_call = *asc2ax(callsign);
-				}
-				p   += l + 2;
-				n   += l + 2;
-				len -= l + 2;
-				break;
+		case 0xC0:
+			l = p[1];
+			if (*p == FAC_CCITT_DEST_NSAP) {
+				memcpy(&facilities->source_addr, p + 7, ROSE_ADDR_LEN);
+				memcpy(callsign, p + 12,   l - 10);
+				callsign[l - 10] = '\0';
+				facilities->source_call = *asc2ax(callsign);
+			}
+			if (*p == FAC_CCITT_SRC_NSAP) {
+				memcpy(&facilities->dest_addr, p + 7, ROSE_ADDR_LEN);
+				memcpy(callsign, p + 12, l - 10);
+				callsign[l - 10] = '\0';
+				facilities->dest_call = *asc2ax(callsign);
+			}
+			p   += l + 2;
+			n   += l + 2;
+			len -= l + 2;
+			break;
 		}
 	} while (*p != 0x00 && len > 0);
 
 	return n;
 }
 
-int rose_parse_facilities(unsigned char *p, struct rose_facilities_struct *facilities)
+int rose_parse_facilities(unsigned char *p,
+	struct rose_facilities_struct *facilities)
 {
 	int facilities_len, len;
 
@@ -378,26 +369,26 @@
 			p++;
 
 			switch (*p) {
-				case FAC_NATIONAL:		/* National */
-					len = rose_parse_national(p + 1, facilities, facilities_len - 1);
-					facilities_len -= len + 1;
-					p += len + 1;
-					break;
-
-				case FAC_CCITT:		/* CCITT */
-					len = rose_parse_ccitt(p + 1, facilities, facilities_len - 1);
-					facilities_len -= len + 1;
-					p += len + 1;
-					break;
-
-				default:
-					printk(KERN_DEBUG "ROSE: rose_parse_facilities - unknown facilities family %02X\n", *p);
-					facilities_len--;
-					p++;
-					break;
+			case FAC_NATIONAL:		/* National */
+				len = rose_parse_national(p + 1, facilities, facilities_len - 1);
+				facilities_len -= len + 1;
+				p += len + 1;
+				break;
+
+			case FAC_CCITT:		/* CCITT */
+				len = rose_parse_ccitt(p + 1, facilities, facilities_len - 1);
+				facilities_len -= len + 1;
+				p += len + 1;
+				break;
+
+			default:
+				printk(KERN_DEBUG "ROSE: rose_parse_facilities - unknown facilities family %02X\n", *p);
+				facilities_len--;
+				p++;
+				break;
 			}
-		}
-		else break;	/* Error in facilities format */
+		} else
+			break;	/* Error in facilities format */
 	}
 
 	return 1;
diff -Nru a/net/rose/rose_timer.c b/net/rose/rose_timer.c
--- a/net/rose/rose_timer.c	Fri Sep 20 08:20:47 2002
+++ b/net/rose/rose_timer.c	Fri Sep 20 08:20:47 2002
@@ -1,20 +1,12 @@
 /*
- *	ROSE release 003
+ * 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 code REQUIRES 2.1.15 or higher/ NET3.038
- *
- *	This module:
- *		This module 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.
- *
- *	History
- *	ROSE 001	Jonathan(G4KLX)	Cloned from nr_timer.c
- *	ROSE 003	Jonathan(G4KLX)	New timer architecture.
- *					Implemented idle timer.
+ * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
+ * Copyright (C) 2002 Ralf Baechle DO1GRB (ralf@gnu.org)
  */
-
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -139,34 +131,35 @@
 	struct sock *sk = (struct sock *)param;
 	rose_cb *rose = rose_sk(sk);
 
+	bh_lock_sock(sk);
 	switch (rose->state) {
-
-		case ROSE_STATE_0:
-			/* Magic here: If we listen() and a new link dies before it
-			   is accepted() it isn't 'dead' so doesn't get removed. */
-			if (sk->destroy || (sk->state == TCP_LISTEN && sk->dead)) {
-				rose_destroy_socket(sk);
-				return;
-			}
-			break;
-
-		case ROSE_STATE_3:
-			/*
-			 * Check for the state of the receive buffer.
-			 */
-			if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) &&
-			    (rose->condition & ROSE_COND_OWN_RX_BUSY)) {
-				rose->condition &= ~ROSE_COND_OWN_RX_BUSY;
-				rose->condition &= ~ROSE_COND_ACK_PENDING;
-				rose->vl         = rose->vr;
-				rose_write_internal(sk, ROSE_RR);
-				rose_stop_timer(sk);	/* HB */
-				break;
-			}
+	case ROSE_STATE_0:
+		/* Magic here: If we listen() and a new link dies before it
+		   is accepted() it isn't 'dead' so doesn't get removed. */
+		if (sk->destroy || (sk->state == TCP_LISTEN && sk->dead)) {
+			rose_destroy_socket(sk);
+			return;
+		}
+		break;
+
+	case ROSE_STATE_3:
+		/*
+		 * Check for the state of the receive buffer.
+		 */
+		if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) &&
+		    (rose->condition & ROSE_COND_OWN_RX_BUSY)) {
+			rose->condition &= ~ROSE_COND_OWN_RX_BUSY;
+			rose->condition &= ~ROSE_COND_ACK_PENDING;
+			rose->vl         = rose->vr;
+			rose_write_internal(sk, ROSE_RR);
+			rose_stop_timer(sk);	/* HB */
 			break;
+		}
+		break;
 	}
 
 	rose_start_heartbeat(sk);
+	bh_unlock_sock(sk);
 }
 
 static void rose_timer_expiry(unsigned long param)
@@ -174,33 +167,35 @@
 	struct sock *sk = (struct sock *)param;
 	rose_cb *rose = rose_sk(sk);
 
+	bh_lock_sock(sk);
 	switch (rose->state) {
-
-		case ROSE_STATE_1:	/* T1 */
-		case ROSE_STATE_4:	/* T2 */
-			rose_write_internal(sk, ROSE_CLEAR_REQUEST);
-			rose->state = ROSE_STATE_2;
-			rose_start_t3timer(sk);
-			break;
-
-		case ROSE_STATE_2:	/* T3 */
-			rose->neighbour->use--;
-			rose_disconnect(sk, ETIMEDOUT, -1, -1);
-			break;
-
-		case ROSE_STATE_3:	/* HB */
-			if (rose->condition & ROSE_COND_ACK_PENDING) {
-				rose->condition &= ~ROSE_COND_ACK_PENDING;
-				rose_enquiry_response(sk);
-			}
-			break;
+	case ROSE_STATE_1:	/* T1 */
+	case ROSE_STATE_4:	/* T2 */
+		rose_write_internal(sk, ROSE_CLEAR_REQUEST);
+		rose->state = ROSE_STATE_2;
+		rose_start_t3timer(sk);
+		break;
+
+	case ROSE_STATE_2:	/* T3 */
+		rose->neighbour->use--;
+		rose_disconnect(sk, ETIMEDOUT, -1, -1);
+		break;
+
+	case ROSE_STATE_3:	/* HB */
+		if (rose->condition & ROSE_COND_ACK_PENDING) {
+			rose->condition &= ~ROSE_COND_ACK_PENDING;
+			rose_enquiry_response(sk);
+		}
+		break;
 	}
+	bh_unlock_sock(sk);
 }
 
 static void rose_idletimer_expiry(unsigned long param)
 {
 	struct sock *sk = (struct sock *)param;
 
+	bh_lock_sock(sk);
 	rose_clear_queues(sk);
 
 	rose_write_internal(sk, ROSE_CLEAR_REQUEST);
@@ -210,10 +205,11 @@
 
 	sk->state     = TCP_CLOSE;
 	sk->err       = 0;
-	sk->shutdown |= SEND_SHUTDOWN;	
+	sk->shutdown |= SEND_SHUTDOWN;
 
 	if (!sk->dead)
 		sk->state_change(sk);
 
 	sk->dead = 1;
+	bh_unlock_sock(sk);
 }
diff -Nru a/net/rose/sysctl_net_rose.c b/net/rose/sysctl_net_rose.c
--- a/net/rose/sysctl_net_rose.c	Fri Sep 20 08:20:41 2002
+++ b/net/rose/sysctl_net_rose.c	Fri Sep 20 08:20:41 2002
@@ -1,10 +1,11 @@
-/* -*- linux-c -*-
- * sysctl_net_rose.c: sysctl interface to net ROSE subsystem.
+/*
+ * 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.
  *
- * Begun April 1, 1996, Mike Shaver.
- * Added /proc/sys/net/rose directory entry (empty =) ). [MS]
+ * Copyright (C) 1996 Mike Shaver (shaver@zeroknowledge.com)
  */
-
 #include <linux/mm.h>
 #include <linux/sysctl.h>
 #include <linux/init.h>
diff -Nru a/net/sunrpc/auth.c b/net/sunrpc/auth.c
--- a/net/sunrpc/auth.c	Fri Sep 20 08:20:41 2002
+++ b/net/sunrpc/auth.c	Fri Sep 20 08:20:41 2002
@@ -1,7 +1,7 @@
 /*
- * linux/fs/nfs/rpcauth.c
+ * linux/net/sunrpc/auth.c
  *
- * Generic RPC authentication API.
+ * Generic RPC client authentication API.
  *
  * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
  */
@@ -18,9 +18,7 @@
 # define RPCDBG_FACILITY	RPCDBG_AUTH
 #endif
 
-#define RPC_MAXFLAVOR	8
-
-static struct rpc_authops *	auth_flavors[RPC_MAXFLAVOR] = {
+static struct rpc_authops *	auth_flavors[RPC_AUTH_MAXFLAVOR] = {
 	&authnull_ops,		/* AUTH_NULL */
 	&authunix_ops,		/* AUTH_UNIX */
 	NULL,			/* others can be loadable modules */
@@ -29,9 +27,9 @@
 int
 rpcauth_register(struct rpc_authops *ops)
 {
-	unsigned int	flavor;
+	rpc_authflavor_t flavor;
 
-	if ((flavor = ops->au_flavor) >= RPC_MAXFLAVOR)
+	if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR)
 		return -EINVAL;
 	if (auth_flavors[flavor] != NULL)
 		return -EPERM;		/* what else? */
@@ -42,9 +40,9 @@
 int
 rpcauth_unregister(struct rpc_authops *ops)
 {
-	unsigned int	flavor;
+	rpc_authflavor_t flavor;
 
-	if ((flavor = ops->au_flavor) >= RPC_MAXFLAVOR)
+	if ((flavor = ops->au_flavor) >= RPC_AUTH_MAXFLAVOR)
 		return -EINVAL;
 	if (auth_flavors[flavor] != ops)
 		return -EPERM;		/* what else? */
@@ -53,11 +51,11 @@
 }
 
 struct rpc_auth *
-rpcauth_create(unsigned int flavor, struct rpc_clnt *clnt)
+rpcauth_create(rpc_authflavor_t flavor, struct rpc_clnt *clnt)
 {
 	struct rpc_authops	*ops;
 
-	if (flavor >= RPC_MAXFLAVOR || !(ops = auth_flavors[flavor]))
+	if (flavor >= RPC_AUTH_MAXFLAVOR || !(ops = auth_flavors[flavor]))
 		return NULL;
 	clnt->cl_auth = ops->create(clnt);
 	return clnt->cl_auth;
diff -Nru a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c
--- a/net/sunrpc/auth_null.c	Fri Sep 20 08:20:49 2002
+++ b/net/sunrpc/auth_null.c	Fri Sep 20 08:20:49 2002
@@ -1,5 +1,5 @@
 /*
- * linux/net/sunrpc/rpcauth_null.c
+ * linux/net/sunrpc/auth_null.c
  *
  * AUTH_NULL authentication. Really :-)
  *
@@ -106,14 +106,18 @@
 static u32 *
 nul_validate(struct rpc_task *task, u32 *p)
 {
-	u32		n = ntohl(*p++);
+	rpc_authflavor_t	flavor;
+	u32			size;
 
-	if (n != RPC_AUTH_NULL) {
-		printk("RPC: bad verf flavor: %ld\n", (unsigned long) n);
+	flavor = ntohl(*p++);
+	if (flavor != RPC_AUTH_NULL) {
+		printk("RPC: bad verf flavor: %u\n", flavor);
 		return NULL;
 	}
-	if ((n = ntohl(*p++)) != 0) {
-		printk("RPC: bad verf size: %ld\n", (unsigned long) n);
+
+	size = ntohl(*p++);
+	if (size != 0) {
+		printk("RPC: bad verf size: %u\n", size);
 		return NULL;
 	}
 
diff -Nru a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c
--- a/net/sunrpc/auth_unix.c	Fri Sep 20 08:20:41 2002
+++ b/net/sunrpc/auth_unix.c	Fri Sep 20 08:20:41 2002
@@ -1,5 +1,5 @@
 /*
- * linux/net/sunrpc/rpcauth_unix.c
+ * linux/net/sunrpc/auth_unix.c
  *
  * UNIX-style authentication; no AUTH_SHORT support
  *
@@ -216,18 +216,24 @@
 static u32 *
 unx_validate(struct rpc_task *task, u32 *p)
 {
-	u32		n = ntohl(*p++);
+	rpc_authflavor_t	flavor;
+	u32			size;
 
-	if (n != RPC_AUTH_NULL && n != RPC_AUTH_UNIX && n != RPC_AUTH_SHORT) {
-		printk("RPC: bad verf flavor: %ld\n", (unsigned long) n);
+	flavor = ntohl(*p++);
+	if (flavor != RPC_AUTH_NULL &&
+	    flavor != RPC_AUTH_UNIX &&
+	    flavor != RPC_AUTH_SHORT) {
+		printk("RPC: bad verf flavor: %u\n", flavor);
 		return NULL;
 	}
-	if ((n = ntohl(*p++)) > 400) {
-		printk("RPC: giant verf size: %ld\n", (unsigned long) n);
+
+	size = ntohl(*p++);
+	if (size > 400) {
+		printk("RPC: giant verf size: %u\n", size);
 		return NULL;
 	}
-	task->tk_auth->au_rslack = (n >> 2) + 2;
-	p += (n >> 2);
+	task->tk_auth->au_rslack = (size >> 2) + 2;
+	p += (size >> 2);
 
 	return p;
 }
diff -Nru a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
--- a/net/sunrpc/clnt.c	Fri Sep 20 08:20:44 2002
+++ b/net/sunrpc/clnt.c	Fri Sep 20 08:20:44 2002
@@ -7,7 +7,7 @@
  *
  *  -	RPC header generation and argument serialization.
  *  -	Credential refresh.
- *  -	TCP reconnect handling (when finished).
+ *  -	TCP connect handling.
  *  -	Retry of operation when it is suspected the operation failed because
  *	of uid squashing on the server, or when the credentials were stale
  *	and need to be refreshed, or when a packet was damaged in transit.
@@ -55,9 +55,9 @@
 static void	call_refresh(struct rpc_task *task);
 static void	call_refreshresult(struct rpc_task *task);
 static void	call_timeout(struct rpc_task *task);
-static void	call_reconnect(struct rpc_task *task);
-static void	child_reconnect(struct rpc_task *);
-static void	child_reconnect_status(struct rpc_task *);
+static void	call_connect(struct rpc_task *task);
+static void	child_connect(struct rpc_task *task);
+static void	child_connect_status(struct rpc_task *task);
 static u32 *	call_header(struct rpc_task *task);
 static u32 *	call_verify(struct rpc_task *task);
 
@@ -71,7 +71,8 @@
  */
 struct rpc_clnt *
 rpc_create_client(struct rpc_xprt *xprt, char *servname,
-		  struct rpc_program *program, u32 vers, int flavor)
+		  struct rpc_program *program, u32 vers,
+		  rpc_authflavor_t flavor)
 {
 	struct rpc_version	*version;
 	struct rpc_clnt		*clnt = NULL;
@@ -122,7 +123,7 @@
 	printk(KERN_INFO "RPC: out of memory in rpc_create_client\n");
 	goto out;
 out_no_auth:
-	printk(KERN_INFO "RPC: Couldn't create auth handle (flavor %d)\n",
+	printk(KERN_INFO "RPC: Couldn't create auth handle (flavor %u)\n",
 		flavor);
 	rpc_free(clnt);
 	clnt = NULL;
@@ -561,51 +562,54 @@
 	dprintk("RPC: %4d call_bind xprt %p %s connected\n", task->tk_pid,
 			xprt, (xprt_connected(xprt) ? "is" : "is not"));
 
-	task->tk_action = (xprt_connected(xprt)) ? call_transmit : call_reconnect;
+	task->tk_action = (xprt_connected(xprt)) ? call_transmit : call_connect;
 
 	if (!clnt->cl_port) {
-		task->tk_action = call_reconnect;
-		task->tk_timeout = clnt->cl_timeout.to_maxval;
+		task->tk_action = call_connect;
+		task->tk_timeout = RPC_CONNECT_TIMEOUT;
 		rpc_getport(task, clnt);
 	}
 }
 
 /*
- * 4a.	Reconnect to the RPC server (TCP case)
+ * 4a.	Connect to the RPC server (TCP case)
  */
 static void
-call_reconnect(struct rpc_task *task)
+call_connect(struct rpc_task *task)
 {
 	struct rpc_clnt *clnt = task->tk_client;
 	struct rpc_task *child;
 
-	dprintk("RPC: %4d call_reconnect status %d\n",
+	dprintk("RPC: %4d call_connect status %d\n",
 				task->tk_pid, task->tk_status);
 
 	task->tk_action = call_transmit;
 	if (task->tk_status < 0 || !clnt->cl_xprt->stream)
 		return;
 
-	/* Run as a child to ensure it runs as an rpciod task */
+	/* Run as a child to ensure it runs as an rpciod task.  Rpciod
+	 * guarantees we have the correct capabilities for socket bind
+	 * to succeed. */
 	child = rpc_new_child(clnt, task);
 	if (child) {
-		child->tk_action = child_reconnect;
+		child->tk_action = child_connect;
 		rpc_run_child(task, child, NULL);
 	}
 }
 
-static void child_reconnect(struct rpc_task *task)
+static void
+child_connect(struct rpc_task *task)
 {
-	task->tk_client->cl_stats->netreconn++;
 	task->tk_status = 0;
-	task->tk_action = child_reconnect_status;
-	xprt_reconnect(task);
+	task->tk_action = child_connect_status;
+	xprt_connect(task);
 }
 
-static void child_reconnect_status(struct rpc_task *task)
+static void
+child_connect_status(struct rpc_task *task)
 {
 	if (task->tk_status == -EAGAIN)
-		task->tk_action = child_reconnect;
+		task->tk_action = child_connect;
 	else
 		task->tk_action = NULL;
 }
@@ -638,7 +642,6 @@
 call_status(struct rpc_task *task)
 {
 	struct rpc_clnt	*clnt = task->tk_client;
-	struct rpc_xprt *xprt = clnt->cl_xprt;
 	struct rpc_rqst	*req = task->tk_rqstp;
 	int		status;
 
@@ -661,30 +664,23 @@
 		break;
 	case -ECONNREFUSED:
 	case -ENOTCONN:
-		req->rq_bytes_sent = 0;
-		if (clnt->cl_autobind || !clnt->cl_port) {
+		if (clnt->cl_autobind)
 			clnt->cl_port = 0;
-			task->tk_action = call_bind;
-			break;
-		}
-		if (xprt->stream) {
-			task->tk_action = call_reconnect;
-			break;
-		}
-		/*
-		 * Sleep and dream of an open connection
-		 */
-		task->tk_timeout = 5 * HZ;
-		rpc_sleep_on(&xprt->sending, task, NULL, NULL);
-	case -ENOMEM:
+		task->tk_action = call_bind;
+		break;
 	case -EAGAIN:
 		task->tk_action = call_transmit;
 		break;
+	case -EIO:
+		/* shutdown or soft timeout */
+		rpc_exit(task, status);
+		break;
 	default:
 		if (clnt->cl_chatty)
 			printk("%s: RPC call returned error %d\n",
 			       clnt->cl_protname, -status);
 		rpc_exit(task, status);
+		break;
 	}
 }
 
diff -Nru a/net/sunrpc/svc.c b/net/sunrpc/svc.c
--- a/net/sunrpc/svc.c	Fri Sep 20 08:20:47 2002
+++ b/net/sunrpc/svc.c	Fri Sep 20 08:20:47 2002
@@ -247,8 +247,8 @@
 	vers = ntohl(*bufp++);
 
 	/* First words of reply: */
-	svc_putlong(resp, xdr_one);		/* REPLY */
-	svc_putlong(resp, xdr_zero);		/* ACCEPT */
+	svc_putu32(resp, xdr_one);		/* REPLY */
+	svc_putu32(resp, xdr_zero);		/* ACCEPT */
 
 	if (dir != 0)		/* direction != CALL */
 		goto err_bad_dir;
@@ -300,7 +300,7 @@
 
 	/* Build the reply header. */
 	statp = resp->buf;
-	svc_putlong(resp, rpc_success);		/* RPC_SUCCESS */
+	svc_putu32(resp, rpc_success);		/* RPC_SUCCESS */
 
 	/* Bump per-procedure stats counter */
 	procp->pc_count++;
@@ -371,17 +371,17 @@
 err_bad_rpc:
 	serv->sv_stats->rpcbadfmt++;
 	resp->buf[-1] = xdr_one;	/* REJECT */
-	svc_putlong(resp, xdr_zero);	/* RPC_MISMATCH */
-	svc_putlong(resp, xdr_two);	/* Only RPCv2 supported */
-	svc_putlong(resp, xdr_two);
+	svc_putu32(resp, xdr_zero);	/* RPC_MISMATCH */
+	svc_putu32(resp, xdr_two);	/* Only RPCv2 supported */
+	svc_putu32(resp, xdr_two);
 	goto sendit;
 
 err_bad_auth:
 	dprintk("svc: authentication failed (%d)\n", ntohl(auth_stat));
 	serv->sv_stats->rpcbadauth++;
 	resp->buf[-1] = xdr_one;	/* REJECT */
-	svc_putlong(resp, xdr_one);	/* AUTH_ERROR */
-	svc_putlong(resp, auth_stat);	/* status */
+	svc_putu32(resp, xdr_one);	/* AUTH_ERROR */
+	svc_putu32(resp, auth_stat);	/* status */
 	goto sendit;
 
 err_bad_prog:
@@ -391,7 +391,7 @@
 	/* else it is just a Solaris client seeing if ACLs are supported */
 #endif
 	serv->sv_stats->rpcbadfmt++;
-	svc_putlong(resp, rpc_prog_unavail);
+	svc_putu32(resp, rpc_prog_unavail);
 	goto sendit;
 
 err_bad_vers:
@@ -399,9 +399,9 @@
 	printk("svc: unknown version (%d)\n", vers);
 #endif
 	serv->sv_stats->rpcbadfmt++;
-	svc_putlong(resp, rpc_prog_mismatch);
-	svc_putlong(resp, htonl(progp->pg_lovers));
-	svc_putlong(resp, htonl(progp->pg_hivers));
+	svc_putu32(resp, rpc_prog_mismatch);
+	svc_putu32(resp, htonl(progp->pg_lovers));
+	svc_putu32(resp, htonl(progp->pg_hivers));
 	goto sendit;
 
 err_bad_proc:
@@ -409,7 +409,7 @@
 	printk("svc: unknown procedure (%d)\n", proc);
 #endif
 	serv->sv_stats->rpcbadfmt++;
-	svc_putlong(resp, rpc_proc_unavail);
+	svc_putu32(resp, rpc_proc_unavail);
 	goto sendit;
 
 err_garbage:
@@ -417,6 +417,6 @@
 	printk("svc: failed to decode args\n");
 #endif
 	serv->sv_stats->rpcbadfmt++;
-	svc_putlong(resp, rpc_garbage_args);
+	svc_putu32(resp, rpc_garbage_args);
 	goto sendit;
 }
diff -Nru a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c
--- a/net/sunrpc/svcauth.c	Fri Sep 20 08:20:43 2002
+++ b/net/sunrpc/svcauth.c	Fri Sep 20 08:20:43 2002
@@ -31,14 +31,9 @@
 static void	svcauth_unix(struct svc_rqst *rqstp, u32 *statp, u32 *authp);
 
 /*
- * Max number of authentication flavors we support
- */
-#define RPC_SVCAUTH_MAX	8
-
-/*
  * Table of authenticators
  */
-static auth_fn_t	authtab[RPC_SVCAUTH_MAX] = {
+static auth_fn_t	authtab[RPC_AUTH_MAXFLAVOR] = {
 	svcauth_null,
 	svcauth_unix,
 	NULL,
@@ -47,17 +42,17 @@
 void
 svc_authenticate(struct svc_rqst *rqstp, u32 *statp, u32 *authp)
 {
-	u32		flavor;
-	auth_fn_t	func;
+	rpc_authflavor_t	flavor;
+	auth_fn_t		func;
 
 	*statp = rpc_success;
 	*authp = rpc_auth_ok;
 
-	svc_getlong(&rqstp->rq_argbuf, flavor);
+	svc_getu32(&rqstp->rq_argbuf, flavor);
 	flavor = ntohl(flavor);
 
 	dprintk("svc: svc_authenticate (%d)\n", flavor);
-	if (flavor >= RPC_SVCAUTH_MAX || !(func = authtab[flavor])) {
+	if (flavor >= RPC_AUTH_MAXFLAVOR || !(func = authtab[flavor])) {
 		*authp = rpc_autherr_badcred;
 		return;
 	}
@@ -67,18 +62,18 @@
 }
 
 int
-svc_auth_register(u32 flavor, auth_fn_t func)
+svc_auth_register(rpc_authflavor_t flavor, auth_fn_t func)
 {
-	if (flavor >= RPC_SVCAUTH_MAX || authtab[flavor])
+	if (flavor >= RPC_AUTH_MAXFLAVOR || authtab[flavor])
 		return -EINVAL;
 	authtab[flavor] = func;
 	return 0;
 }
 
 void
-svc_auth_unregister(u32 flavor)
+svc_auth_unregister(rpc_authflavor_t flavor)
 {
-	if (flavor < RPC_SVCAUTH_MAX)
+	if (flavor < RPC_AUTH_MAXFLAVOR)
 		authtab[flavor] = NULL;
 }
 
@@ -110,8 +105,8 @@
 
 	/* Put NULL verifier */
 	rqstp->rq_verfed = 1;
-	svc_putlong(resp, RPC_AUTH_NULL);
-	svc_putlong(resp, 0);
+	svc_putu32(resp, RPC_AUTH_NULL);
+	svc_putu32(resp, 0);
 }
 
 static void
@@ -157,8 +152,8 @@
 
 	/* Put NULL verifier */
 	rqstp->rq_verfed = 1;
-	svc_putlong(resp, RPC_AUTH_NULL);
-	svc_putlong(resp, 0);
+	svc_putu32(resp, RPC_AUTH_NULL);
+	svc_putu32(resp, 0);
 
 	return;
 
diff -Nru a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
--- a/net/sunrpc/svcsock.c	Fri Sep 20 08:20:41 2002
+++ b/net/sunrpc/svcsock.c	Fri Sep 20 08:20:41 2002
@@ -1091,8 +1091,8 @@
 	rqstp->rq_userset = 0;
 	rqstp->rq_verfed  = 0;
 
-	svc_getlong(&rqstp->rq_argbuf, rqstp->rq_xid);
-	svc_putlong(&rqstp->rq_resbuf, rqstp->rq_xid);
+	svc_getu32(&rqstp->rq_argbuf, rqstp->rq_xid);
+	svc_putu32(&rqstp->rq_resbuf, rqstp->rq_xid);
 
 	/* Assume that the reply consists of a single buffer. */
 	rqstp->rq_resbuf.nriov = 1;
diff -Nru a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
--- a/net/sunrpc/xprt.c	Fri Sep 20 08:20:47 2002
+++ b/net/sunrpc/xprt.c	Fri Sep 20 08:20:47 2002
@@ -86,9 +86,11 @@
 static void	do_xprt_transmit(struct rpc_task *);
 static inline void	do_xprt_reserve(struct rpc_task *);
 static void	xprt_disconnect(struct rpc_xprt *);
-static void	xprt_reconn_status(struct rpc_task *task);
+static void	xprt_conn_status(struct rpc_task *task);
+static struct rpc_xprt * xprt_setup(int proto, struct sockaddr_in *ap,
+						struct rpc_timeout *to);
 static struct socket *xprt_create_socket(int, struct rpc_timeout *);
-static int	xprt_bind_socket(struct rpc_xprt *, struct socket *);
+static void	xprt_bind_socket(struct rpc_xprt *, struct socket *);
 static int      __xprt_get_cong(struct rpc_xprt *, struct rpc_task *);
 
 #ifdef RPC_DEBUG_DATA
@@ -134,7 +136,7 @@
 /*
  * Serialize write access to sockets, in order to prevent different
  * requests from interfering with each other.
- * Also prevents TCP socket reconnections from colliding with writes.
+ * Also prevents TCP socket connects from colliding with writes.
  */
 static int
 __xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task)
@@ -407,106 +409,150 @@
 }
 
 /*
- * Reconnect a broken TCP connection.
+ * Attempt to connect a TCP socket.
  *
- * Note: This cannot collide with the TCP reads, as both run from rpciod
+ * NB: This never collides with TCP reads, as both run from rpciod
  */
 void
-xprt_reconnect(struct rpc_task *task)
+xprt_connect(struct rpc_task *task)
 {
 	struct rpc_xprt	*xprt = task->tk_xprt;
 	struct socket	*sock = xprt->sock;
 	struct sock	*inet;
 	int		status;
 
-	dprintk("RPC: %4d xprt_reconnect %p connected %d\n",
-				task->tk_pid, xprt, xprt_connected(xprt));
-	if (xprt->shutdown)
-		return;
+	dprintk("RPC: %4d xprt_connect xprt %p %s connected\n", task->tk_pid,
+			xprt, (xprt_connected(xprt) ? "is" : "is not"));
 
-	if (!xprt->stream)
+	if (xprt->shutdown) {
+		task->tk_status = -EIO;
 		return;
-
+	}
 	if (!xprt->addr.sin_port) {
 		task->tk_status = -EIO;
 		return;
 	}
-
 	if (!xprt_lock_write(xprt, task))
 		return;
 	if (xprt_connected(xprt))
 		goto out_write;
 
-	if (sock && sock->state != SS_UNCONNECTED)
-		xprt_close(xprt);
-	status = -ENOTCONN;
-	if (!(inet = xprt->inet)) {
-		/* Create an unconnected socket */
-		if (!(sock = xprt_create_socket(xprt->prot, &xprt->timeout)))
-			goto defer;
-		xprt_bind_socket(xprt, sock);
-		inet = sock->sk;
+	/*
+	 * We're here because the xprt was marked disconnected.
+	 * Start by resetting any existing state.
+	 */
+	xprt_close(xprt);
+	if (!(sock = xprt_create_socket(xprt->prot, &xprt->timeout))) {
+		/* couldn't create socket or bind to reserved port;
+		 * this is likely a permanent error, so cause an abort */
+		task->tk_status = -EIO;
+		goto out_write;
 	}
+	xprt_bind_socket(xprt, sock);
+	inet = sock->sk;
 
-	/* Now connect it asynchronously. */
-	dprintk("RPC: %4d connecting new socket\n", task->tk_pid);
+	/*
+	 * Tell the socket layer to start connecting...
+	 */
 	status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr,
 				sizeof(xprt->addr), O_NONBLOCK);
+	dprintk("RPC: %4d  connect status %d connected %d sock state %d\n",
+		task->tk_pid, -status, xprt_connected(xprt), inet->state);
 
-	if (status < 0) {
-		switch (status) {
-		case -EALREADY:
-		case -EINPROGRESS:
-			status = 0;
-			break;
-		case -EISCONN:
-		case -EPIPE:
-			status = 0;
-			xprt_close(xprt);
-			goto defer;
-		default:
-			printk("RPC: TCP connect error %d!\n", -status);
-			xprt_close(xprt);
-			goto defer;
-		}
-
+	switch (status) {
+	case -EINPROGRESS:
+	case -EALREADY:
 		/* Protect against TCP socket state changes */
 		lock_sock(inet);
-		dprintk("RPC: %4d connect status %d connected %d\n",
-				task->tk_pid, status, xprt_connected(xprt));
-
 		if (inet->state != TCP_ESTABLISHED) {
-			task->tk_timeout = xprt->timeout.to_maxval;
-			/* if the socket is already closing, delay 5 secs */
-			if ((1<<inet->state) & ~(TCPF_SYN_SENT|TCPF_SYN_RECV))
-				task->tk_timeout = 5*HZ;
-			rpc_sleep_on(&xprt->pending, task, xprt_reconn_status, NULL);
+			dprintk("RPC: %4d  waiting for connection\n",
+					task->tk_pid);
+			task->tk_timeout = RPC_CONNECT_TIMEOUT;
+			/* if the socket is already closing, delay briefly */
+			if ((1 << inet->state) & ~(TCPF_SYN_SENT|TCPF_SYN_RECV))
+				task->tk_timeout = RPC_REESTABLISH_TIMEOUT;
+			rpc_sleep_on(&xprt->pending, task, xprt_conn_status,
+									NULL);
 			release_sock(inet);
+			/* task status set when task wakes up again */
 			return;
 		}
 		release_sock(inet);
-	}
-defer:
-	if (status < 0) {
-		rpc_delay(task, 5*HZ);
+		task->tk_status = 0;
+		break;
+
+	case 0:
+	case -EISCONN:	/* not likely, but just in case */
+		/* Half closed state.  No race -- this socket is dead. */
+		if (inet->state != TCP_ESTABLISHED) {
+			xprt_close(xprt);
+			task->tk_status = -EAGAIN;
+			goto out_write;
+		}
+
+		/* Otherwise, the connection is already established. */
+		task->tk_status = 0;
+		break;
+
+	case -EPIPE:
+		xprt_close(xprt);
 		task->tk_status = -ENOTCONN;
+		goto out_write;
+
+	default:
+		/* Report myriad other possible returns.  If this file
+		 * system is soft mounted, just error out, like Solaris.  */
+		xprt_close(xprt);
+		if (task->tk_client->cl_softrtry) {
+			printk(KERN_WARNING
+			"RPC: error %d connecting to server %s, exiting\n",
+					-status, task->tk_client->cl_server);
+			task->tk_status = -EIO;
+		} else {
+			printk(KERN_WARNING
+			"RPC: error %d connecting to server %s\n",
+					-status, task->tk_client->cl_server);
+			rpc_delay(task, RPC_REESTABLISH_TIMEOUT);
+			task->tk_status = status;
+		}
+		break;
 	}
+
  out_write:
 	xprt_release_write(xprt, task);
 }
 
 /*
- * Reconnect timeout. We just mark the transport as not being in the
- * process of reconnecting, and leave the rest to the upper layers.
+ * We arrive here when awoken from waiting on connection establishment.
  */
 static void
-xprt_reconn_status(struct rpc_task *task)
+xprt_conn_status(struct rpc_task *task)
 {
 	struct rpc_xprt	*xprt = task->tk_xprt;
 
-	dprintk("RPC: %4d xprt_reconn_timeout %d\n",
-				task->tk_pid, task->tk_status);
+	switch (task->tk_status) {
+	case 0:
+		dprintk("RPC: %4d xprt_conn_status: connection established\n",
+				task->tk_pid);
+		goto out;
+	case -ETIMEDOUT:
+		dprintk("RPC: %4d xprt_conn_status: timed out\n",
+				task->tk_pid);
+		/* prevent TCP from continuing to retry SYNs */
+		xprt_close(xprt);
+		break;
+	default:
+		printk(KERN_ERR "RPC: error %d connecting to server %s\n",
+				-task->tk_status, task->tk_client->cl_server);
+		xprt_close(xprt);
+		rpc_delay(task, RPC_REESTABLISH_TIMEOUT);
+		break;
+	}
+	/* if soft mounted, cause this RPC to fail */
+	if (task->tk_client->cl_softrtry)
+		task->tk_status = -EIO;
 
+ out:
 	xprt_release_write(xprt, task);
 }
 
@@ -1154,8 +1200,12 @@
 		return;
 	case -ECONNREFUSED:
 	case -ENOTCONN:
-		if (!xprt->stream)
+		if (!xprt->stream) {
+			task->tk_timeout = RPC_REESTABLISH_TIMEOUT;
+			rpc_sleep_on(&xprt->sending, task, NULL, NULL);
 			return;
+		}
+		/* fall through */
 	default:
 		if (xprt->stream)
 			xprt_disconnect(xprt);
@@ -1305,8 +1355,7 @@
  * Initialize an RPC client
  */
 static struct rpc_xprt *
-xprt_setup(struct socket *sock, int proto,
-			struct sockaddr_in *ap, struct rpc_timeout *to)
+xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to)
 {
 	struct rpc_xprt	*xprt;
 	struct rpc_rqst	*req;
@@ -1353,7 +1402,6 @@
 
 	dprintk("RPC:      created transport %p\n", xprt);
 	
-	xprt_bind_socket(xprt, sock);
 	return xprt;
 }
 
@@ -1381,13 +1429,13 @@
 	return err;
 }
 
-static int 
+static void
 xprt_bind_socket(struct rpc_xprt *xprt, struct socket *sock)
 {
 	struct sock	*sk = sock->sk;
 
 	if (xprt->inet)
-		return -EBUSY;
+		return;
 
 	sk->user_data = xprt;
 	xprt->old_data_ready = sk->data_ready;
@@ -1413,7 +1461,7 @@
 	if(xprt->stream)
 		rpciod_up();
 
-	return 0;
+	return;
 }
 
 /*
@@ -1438,7 +1486,8 @@
 }
 
 /*
- * Create a client socket given the protocol and peer address.
+ * Datastream sockets are created here, but xprt_connect will create
+ * and connect stream sockets.
  */
 static struct socket *
 xprt_create_socket(int proto, struct rpc_timeout *to)
@@ -1457,8 +1506,10 @@
 	}
 
 	/* If the caller has the capability, bind to a reserved port */
-	if (capable(CAP_NET_BIND_SERVICE) && xprt_bindresvport(sock) < 0)
+	if (capable(CAP_NET_BIND_SERVICE) && xprt_bindresvport(sock) < 0) {
+		printk("RPC: can't bind to reserved port.\n");
 		goto failed;
+	}
 
 	return sock;
 
@@ -1473,17 +1524,32 @@
 struct rpc_xprt *
 xprt_create_proto(int proto, struct sockaddr_in *sap, struct rpc_timeout *to)
 {
-	struct socket	*sock;
 	struct rpc_xprt	*xprt;
 
-	dprintk("RPC:      xprt_create_proto called\n");
-
-	if (!(sock = xprt_create_socket(proto, to)))
-		return NULL;
+	xprt = xprt_setup(proto, sap, to);
+	if (!xprt)
+		goto out;
 
-	if (!(xprt = xprt_setup(sock, proto, sap, to)))
-		sock_release(sock);
+	if (!xprt->stream) {
+		struct socket *sock = xprt_create_socket(proto, to);
+		if (sock)
+			xprt_bind_socket(xprt, sock);
+		else {
+			rpc_free(xprt);
+			xprt = NULL;
+		}
+	} else
+		/*
+		 * Don't allow a TCP service user unless they have
+		 * enough capability to bind a reserved port.
+		 */
+		if (!capable(CAP_NET_BIND_SERVICE)) {
+			rpc_free(xprt);
+			xprt = NULL;
+		}
 
+ out:
+	dprintk("RPC:      xprt_create_proto created xprt %p\n", xprt);
 	return xprt;
 }
 
@@ -1522,7 +1588,7 @@
 	dprintk("RPC:      destroying transport %p\n", xprt);
 	xprt_shutdown(xprt);
 	xprt_close(xprt);
-	kfree(xprt);
+	rpc_free(xprt);
 
 	return 0;
 }
diff -Nru a/scripts/mkcompile_h b/scripts/mkcompile_h
--- a/scripts/mkcompile_h	Fri Sep 20 08:20:48 2002
+++ b/scripts/mkcompile_h	Fri Sep 20 08:20:49 2002
@@ -67,8 +67,8 @@
 # first line.
 
 if [ -r $TARGET ] && \
-      grep -v 'auto generated\|UTS_VERSION\|LINUX_COMPILE_TIME' $TARGET > .tmpver.1 && \
-      grep -v 'auto generated\|UTS_VERSION\|LINUX_COMPILE_TIME' .tmpcompile > .tmpver.2 && \
+      grep -v 'UTS_VERSION\|LINUX_COMPILE_TIME' $TARGET > .tmpver.1 && \
+      grep -v 'UTS_VERSION\|LINUX_COMPILE_TIME' .tmpcompile > .tmpver.2 && \
       cmp -s .tmpver.1 .tmpver.2; then
    echo ' (unchanged)'
    rm -f .tmpcompile
diff -Nru a/sound/Makefile b/sound/Makefile
--- a/sound/Makefile	Fri Sep 20 08:20:44 2002
+++ b/sound/Makefile	Fri Sep 20 08:20:44 2002
@@ -1,8 +1,6 @@
 # Makefile for the Linux sound card driver
 #
 
-O_TARGET := sound.o
-
 export-objs     := sound_core.o
 
 obj-$(CONFIG_SOUND) += soundcore.o
diff -Nru a/sound/oss/cs4281/cs4281m.c b/sound/oss/cs4281/cs4281m.c
--- a/sound/oss/cs4281/cs4281m.c	Fri Sep 20 08:20:48 2002
+++ b/sound/oss/cs4281/cs4281m.c	Fri Sep 20 08:20:48 2002
@@ -3205,7 +3205,7 @@
 			 "cs4281: cs4281_ioctl(): DSP_RESET\n"));
 		if (file->f_mode & FMODE_WRITE) {
 			stop_dac(s);
-			synchronize_irq();
+			synchronize_irq(s->irq);
 			s->dma_dac.swptr = s->dma_dac.hwptr =
 			    s->dma_dac.count = s->dma_dac.total_bytes =
 			    s->dma_dac.blocks = s->dma_dac.wakeup = 0;
@@ -3213,7 +3213,7 @@
 		}
 		if (file->f_mode & FMODE_READ) {
 			stop_adc(s);
-			synchronize_irq();
+			synchronize_irq(s->irq);
 			s->dma_adc.swptr = s->dma_adc.hwptr =
 			    s->dma_adc.count = s->dma_adc.total_bytes =
 			    s->dma_adc.blocks = s->dma_dac.wakeup = 0;
@@ -4452,7 +4452,7 @@
 {
 	struct cs4281_state *s = pci_get_drvdata(pci_dev);
 	// stop DMA controller 
-	synchronize_irq();
+	synchronize_irq(s->irq);
 	free_irq(s->irq, s);
 	unregister_sound_dsp(s->dev_audio);
 	unregister_sound_mixer(s->dev_mixer);
