diff -u --recursive --new-file v2.4.9/linux/Documentation/00-INDEX linux/Documentation/00-INDEX
--- v2.4.9/linux/Documentation/00-INDEX	Thu Feb  8 16:32:44 2001
+++ linux/Documentation/00-INDEX	Mon Aug 27 07:44:15 2001
@@ -5,6 +5,11 @@
 Please try and keep the descriptions small enough to fit on one line.
 							 Thanks -- Paul G.
 
+Following translations are available on the WWW:
+
+   - Japanese, maintained by the JF Project (JF@linux.or.jp), at
+     http://www.linux.or.jp/JF/
+
 00-INDEX
 	- this file.
 BUG-HUNTING
diff -u --recursive --new-file v2.4.9/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.4.9/linux/Documentation/Configure.help	Mon Aug 27 12:41:37 2001
+++ linux/Documentation/Configure.help	Tue Aug 28 11:21:02 2001
@@ -1746,6 +1746,36 @@
   similar) CPU, R4xx0 might be a safe bet.
   If the resulting Kernel does not work try to recompile with R3000.
 
+CPU type
+CONFIG_CPU_VR41XX
+  The options selects support for the NEC VR41xx series of processors.
+  Only choose this option if you have one of these processors as a
+  kernel built with this option will not run on any other type of
+  processor or vice versa.
+
+CPU feature configuration
+CONFIG_CPU_ADVANCED
+  Saying yes here allows you to select support for various features your
+  CPU may or may not have.  Most people should say N here.
+
+ll and sc instructions
+CONFIG_CPU_HAS_LLSC
+  Say Y here if your CPU has the ll and sc instructions.  Say Y here for
+  better performance, N if you don't know.  You must say Y here for
+  multiprocessor machines.
+
+lld and scd instructions
+CONFIG_CPU_HAS_LLDSCD
+  Say Y here if your CPU has the lld and scd instructions, the 64-bit
+  equivalents of ll and sc.  Say Y here for better performance, N if
+  you don't know.  You must say Y here for multiprocessor machines.
+
+Support for writebuffer flushing
+CONFIG_CPU_HAS_WB
+  Say N here for slightly better performance.  You must say Y here for
+  machines which require flushing of write buffers in software.  Saying
+  Y is the safe option; N may result in kernel malfunction and crashes.
+
 Support for large 64-bit configurations
 CONFIG_MIPS_INSANE_LARGE
   MIPS R10000 does support a 44 bit / 16TB address space as opposed to
@@ -11478,6 +11508,45 @@
   The module will be called pegasus.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
+CONFIG_USB_KAWETH
+  Say Y here if you want to use one of the following 10Mbps only
+  USB Ethernet adapters based on the KLSI KL5KUSB101B chipset:
+       3Com 3C19250
+       ADS USB-10BT
+       ATEN USB Ethernet
+       ASANTE USB To Ethernet Adapter
+       AOX Endpoints USB Ethernet
+       Correga K.K.
+       D-Link DSB-650C and DU-E10
+       Entrega / Portgear E45
+       I-O DATA USB-ET/T
+       Jaton USB Ethernet Device Adapter
+       Kingston Technology USB Ethernet Adapter
+       Linksys USB10T
+       Mobility USB-Ethernet Adapter
+        NetGear EA-101
+       Peracom Enet and Enet2
+       Portsmith Express Ethernet Adapter
+       Shark Pocket Adapter
+       SMC 2202USB
+       Sony Vaio port extender
+
+  This driver is likely to work with most 10Mbps only USB Ethernet
+  adapters, including some "no brand" devices. It does NOT work on
+  SmartBridges smartNIC or on Belkin F5U111 devices - you should use
+  the CATC NetMate driver for those. If you are not sure which one
+  you need, select both, and the correct one should be selected for
+  you.
+
+  This driver makes the adapter appear as a normal Ethernet interface,
+  typically on eth0, if it is the only ethernet device, or perhaps on
+  eth1, if you have a PCI or ISA ethernet card installed.
+
+  This code is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called kaweth.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
 USB CATC NetMate-based Ethernet device support
 CONFIG_USB_CATC
   Say Y if you want to use one of the following 10Mbps USB Ethernet
@@ -11604,6 +11673,23 @@
   The module will be called dabusb.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
+Host-to-Host USB networking
+CONFIG_USB_USBNET
+  This driver supports network links over USB with USB "Network"
+  or "data transfer" cables, often used to network laptops to PCs.
+  Such cables have chips from suppliers such as NetChip and Prolific.
+  Intelligent USB devices could also use this approach to provide
+  Internet access, using standard USB cabling.
+
+  These links will have names like "usb0", "usb1", etc.  They act
+  like two-node Ethernets, so you can use 802.1d Ethernet Bridging
+  (CONFIG_BRIDGE) to simplify your network routing.
+
+  This code is also available as a kernel module (code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called usbnet.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
 PLUSB driver
 CONFIG_USB_PLUSB
   A driver for the Prolific PL-2302 USB-to-USB network device. This
@@ -15754,6 +15840,14 @@
   better 32 MB RAM to avoid excessive linking time. This is only
   useful for kernel hackers. If unsure, say N.
 
+Run uncached
+CONFIG_MIPS_UNCACHED
+  If you say Y here there kernel will disable all CPU caches.  This will
+  reduce the system's performance dramatically but can help finding
+  otherwise hard to track bugs.  It can also useful if you're doing
+  hardware debugging with a logic analyzer and need to see all traffic
+  on the bus.
+
 Magic System Request Key support
 CONFIG_MAGIC_SYSRQ
   If you say Y here, you will have some control over the system even
@@ -16983,11 +17077,75 @@
 CONFIG_ALL_PPC
   Linux currently supports several different kinds of PowerPC-based
   machines: Apple Power Macintoshes and clones (such as the Motorola
-  Starmax series), PReP (PowerPC Reference Platform) machines such as
-  the Motorola PowerStack, CHRP (Common Hardware Reference Platform), 
-  the embedded MBX boards from Motorola and many others. Currently, 
-  the default option is to build a kernel which works on the first 
-  three.  Support for other machines is currently incomplete.
+  Starmax series), PReP (PowerPC Reference Platform) machines (such
+  as the Motorola PowerStacks, Motorola cPCI/VME embedded systems,
+  and some IBM RS/6000 systems), CHRP (Common Hardware Reference
+  Platform), and several embedded PowerPC systems containing 4xx, 6xx,
+  7xx, 8xx, 74xx, and 82xx processors.  Currently, the default option
+  is to build a kernel which works on the first three. 
+
+AltiVec Kernel Support
+CONFIG_ALTIVEC
+  This option enables kernel support for the Altivec extensions to the
+  PowerPC processor. The kernel currently supports saving and restoring
+  altivec registers, and turning on the 'altivec enable' bit so user
+  processes can execute altivec instructions.
+
+  This option is only usefully if you have a processor that supports 
+  altivec (G4, otherwise known as 74xx series), but does not have
+  any affect on a non-altivec cpu (it does, however add code to the
+  kernel).
+
+  If in doubt, say Y here.
+
+Thermal Management Support
+CONFIG_TAU
+  G3 and G4 processors have an on-chip temperature sensor called the
+  'Thermal Assist Unit (TAU)', which, in theory, can measure the on-die
+  temperature within 2-4 degrees celcius. This option shows the current
+  on-die temperature in /proc/cpuinfo if the cpu supports it.
+
+  Unfortunately, on some chip revisions, this sensor is very inaccurate
+  and in some cases, does not work at all, so don't assume the cpu
+  temp is actually what /proc/cpuinfo says it is.
+
+Interrupt driven TAU driver
+CONFIG_TAU_INT
+  The TAU supports an interrupt driven mode which causes an interrupt
+  whenever the temperature goes out of range. This is the fastest way
+  to get notified the temp has exceeded a range. With this option off,
+  a timer is used to re-check the temperature periodically.
+
+  However, on some cpus it appears that the TAU interrupt hardware
+  is buggy and can cause a situation which would lead unexplained hard
+  lockups.
+
+  Unless you are extending the TAU driver, or enjoy kernel/hardware
+  debugging, leave this option off.
+
+Average high and low temp
+CONFIG_TAU_AVERAGE
+  The TAU hardware can compare the temperature to an upper and lower bound.
+  The default behavior is to show both the upper and lower bound in 
+  /proc/cpuinfo. If the range is large, the temperature is either changing
+  a lot, or the TAU hardware is broken (likely on some G4's). If the range
+  is small (around 4 degrees), the temperature is relatively stable.
+
+Support for CUDA based PowerMacs
+CONFIG_ADB_CUDA
+  This provides support for CUDA based Power Macintosh systems.  This
+  includes most OldWorld PowerMacs, the first generation iMacs, the
+  Blue&White G3 and the Yikes G4 (PCI Graphics).  All later models
+  should use CONFIG_ADB_PMU instead.
+
+  If unsure say Y.
+
+Support for PMU based PowerMacs
+CONFIG_ADB_PMU
+  This provides support for PMU based Power Macintosh systems.  This
+  includes all PowerBooks and all AGP-based machines.
+  
+  If unsure say Y.
 
 Power management support for PowerBooks
 CONFIG_PMAC_PBOOK
@@ -17004,13 +17162,6 @@
   You may also want to compile the dma sound driver as a module and
   have it autoloaded. The act of removing the module shuts down the
   sound hardware for more power savings.
-
-Mac-on-Linux support
-CONFIG_MOL
-  This option enables low-level support for Mac-on-Linux.
-  MOL lets you run MacOS and Linux simultaneously. Please
-  visit <http://www.maconlinux.org> for more information.
-  If unsure, say Y.
 
 ADB raw keycode support
 CONFIG_MAC_ADBKEYCODES
diff -u --recursive --new-file v2.4.9/linux/Documentation/filesystems/ntfs.txt linux/Documentation/filesystems/ntfs.txt
--- v2.4.9/linux/Documentation/filesystems/ntfs.txt	Mon Aug 27 12:41:37 2001
+++ linux/Documentation/filesystems/ntfs.txt	Tue Aug 28 06:57:18 2001
@@ -64,6 +64,26 @@
 			Be careful not to write anything to them or you could
 			crash the kernel and/or corrupt your file system!
 
+mft_zone_multiplier=	Set the MFT zone multiplier for the volume (this
+			setting is not persistent across mounts and can be
+			changed from mount to mount but cannot be changed on
+			remount). Values of 1 to 4 are allowed, 1 being the
+			default. The MFT zone multiplier determines how much
+			space is reserved for the MFT on the volume. If all
+			other space is used up, then the MFT zone will be
+			shrunk dynamically, so this has no impact on the
+			amount of free space. However, it can have an impact
+			on performance by affecting fragmentation of the MFT.
+			In general use the default. If you have a lot of small
+			files then use a higher value. The values have the
+			following meaning:
+			      Value	     MFT zone size (% of volume size)
+				1		12.5%
+				2		25%
+				3		37.5%
+				4		50%
+			NOTE: This is currently ignored! Work in progress.
+
 Known bugs and (mis-)features
 =============================
 
@@ -71,17 +91,45 @@
   use it, get the Linux-NTFS tools and use the ntfsfix utility after
   dismounting a partition you wrote to.
 
-- Use the show_sys_files mount option which should make things work generally
-  better. (It results in both the short and long file names being shown as well
-  as the sytem files.)
-
 - Writing of extension records is not supported properly.
 
+- $MFT extension is badly broken and really needs rewriting.
+
 Please send bug reports/comments/feed back/abuse to the Linux-NTFS development
 list at sourceforge: linux-ntfs-dev@lists.sourceforge.net
 
 ChangeLog
 =========
+
+NTFS 1.1.17:
+
+	- Fixed system file handling. No longer need to use show_sys_files
+	  option for driver to work fine. System files are now always treated
+	  the same, but without the option, they are made invisible to
+	  directory listings. As a result system files can once again be opened
+	  even without the show_sys_files option. This is important for the
+	  statfs system call to work properly, for example.
+	- Implemented MFT zone including mount parameter to tune it (just like
+	  in Windows via the registry, only we make it per mount rather than
+	  global for the whole driver, so we are better but we have no way of
+	  storing the value as we don't have a registry so either specify on
+	  each mount or put it in /etc/fstab). [Stage 1 of 3, mount parameter
+	  handling.]
+	- Fixed fixup functions to handle corruption cases and to return error
+	  codes to the caller.
+	- Made fixup functions apply hotfixes where sensible. [Stage 1 of 2+,
+	  in memory only.]
+	- Fixed ommission of "NTFS: " string in ntfs_error() output.
+	- Fixed stupid if statement bug in unistr.c. Thanks to Yann E. Morin
+	  for spotting it. 
+	- Get rid of all uses of max and min macros. This actually allowed for
+	  optimizing the code in several places so it was a Good Thing(TM).
+	- Make ntfs use generic_file_open to enforce the O_LARGEFILE flag.
+	- Detect encrypted files and refuse to access them (return EACCES
+	  error code to user space).
+	- Fix handling of encrypted & compressed files so that an encrypted
+	  file no longer is considered to be compressed (this was causing
+	  kernel segmentation faults).
 
 NTFS 1.1.16:
 
diff -u --recursive --new-file v2.4.9/linux/Documentation/mips/pci/pci.README linux/Documentation/mips/pci/pci.README
--- v2.4.9/linux/Documentation/mips/pci/pci.README	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/mips/pci/pci.README	Mon Aug 27 08:56:31 2001
@@ -0,0 +1,67 @@
+
+Pete Popov, ppopov@pacbell.net
+07/11/2001
+
+This README briefly explains how to use the pci and pci_auto
+code in arch/mips/kernel.  The code was ported from PowerPC and
+modified slightly. It has been tested pretty well on PPC on some
+rather complex systems with multiple bridges and devices behind
+each bridge. However, at the time this README was written, the
+mips port was tested only on boards with a single pci bus and
+no P2P bridges.  It's very possible that on boards with P2P
+bridges some modifications have to be made. The code will 
+evolve, no doubt, but currently every single mips board
+is doing its own pcibios thing and it has become a big
+mess.  This generic pci code is meant to clean up the mips
+pci mess and make it easier to add pci support to new boards.
+
+arch/mips/kernel/pci_auto.c has the pci bus enumeration code.
+This code scans the pci bus(es) and assigns all of the resources.
+Thus, you don't need the boot code to that, and many boot codes
+don't do it correctly anyway.  To enable the pci_auto code, add
+
+define_bool CONFIG_PCI_AUTO y 
+
+inside the define for your board in arch/mips/config.in. 
+For example, the Galileo EV96100 board  looks like this:
+
+if [ "$CONFIG_MIPS_EV96100" = "y" ]; then
+	define_bool CONFIG_PCI y
+	define_bool CONFIG_MIPS_GT96100 y
+	define_bool CONFIG_NEW_PCI y
+	define_bool CONFIG_PCI_AUTO y
+	define_bool CONFIG_SWAP_IO_SPACE y
+fi 
+
+
+Next, if you want to use the arch/mips/kernel/pci code, which has the
+pcibios_init() function, add
+
+define_bool CONFIG_NEW_PCI y
+ 
+inside the define for your board. Again, the EV96100 example above
+show NEW_PCI turned on.
+
+Note that you can enable CONFIG_NEW_PCI code without enabling 
+CONFIG_PCI_AUTO. But you can't do the opposite because the pci_auto
+routines are called from pcibios_init(), which is part of the 
+CONFIG_NEW_PCI code.
+
+
+Now you need to add your files to hook in your pci configuration
+cycles.  Usually you'll need only a couple of files named something
+like pci_fixups.c and pci_ops.c.  You can copy the templates
+provided and fill in the code.
+
+The file pci_ops.c should contain the pci configuration cycles routines.
+It also has the mips_pci_channels[] array which contains the descriptors
+of each pci controller.
+
+The file pci_fixups.c contains a few routines to do interrupt fixups,
+resources fixups, and, if needed, pci bios fixups.
+
+Usually you'll put your pci_fixups.c file in your board specific directory, 
+since the functions in that file are board specific.  The functions in
+pci_ops.c, on the other hand, are usually pci controller specific so that
+file could be shared among a few different boards using the same
+pci controller.
diff -u --recursive --new-file v2.4.9/linux/MAINTAINERS linux/MAINTAINERS
--- v2.4.9/linux/MAINTAINERS	Mon Aug 27 12:41:37 2001
+++ linux/MAINTAINERS	Mon Aug 27 08:56:31 2001
@@ -689,8 +689,8 @@
 S:	Orphan
 
 IEEE 1394 OHCI DRIVER
-P:	Sebastien Rougeaux
-M:	sebastien.rougeaux@anu.edu.au
+P:	Ben Collins
+M:	bcollins@debian.org
 L:	linux1394-devel@lists.sourceforge.net
 S:	Maintained
 
@@ -902,9 +902,9 @@
 
 MIPS
 P:	Ralf Baechle
-M:	ralf@gnu.ai.mit.edu
-W:	http://lena.fnet.fr/
-L:	linux-mips@fnet.fr
+M:	ralf@gnu.org
+W:	http://oss.sgi.com/mips/mips-howto.html
+L:	linux-mips@oss.sgi.com
 S:	Maintained
 
 MISCELLANEOUS MCA-SUPPORT
@@ -1452,6 +1452,13 @@
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
 S:	Maintained
+
+USB KAWASAKI LSI DRIVER
+P:      Brad Hards
+M:      bradh@frogmouth.net
+L:      linux-usb-users@lists.sourceforge.net
+L:      linux-usb-devel@lists.sourceforge.net
+S:      Maintained
 
 USB OHCI DRIVER
 P:	Roman Weissgaerber
diff -u --recursive --new-file v2.4.9/linux/Makefile linux/Makefile
--- v2.4.9/linux/Makefile	Mon Aug 27 12:41:37 2001
+++ linux/Makefile	Tue Aug 28 11:27:13 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
-SUBLEVEL = 9
-EXTRAVERSION =
+SUBLEVEL = 10
+EXTRAVERSION =-pre2
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -u --recursive --new-file v2.4.9/linux/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c
--- v2.4.9/linux/arch/alpha/kernel/alpha_ksyms.c	Mon Aug 27 12:41:37 2001
+++ linux/arch/alpha/kernel/alpha_ksyms.c	Mon Aug 27 07:56:48 2001
@@ -77,6 +77,14 @@
 EXPORT_SYMBOL(_writeb);
 EXPORT_SYMBOL(_writew);
 EXPORT_SYMBOL(_writel);
+EXPORT_SYMBOL(___raw_readb); 
+EXPORT_SYMBOL(___raw_readw); 
+EXPORT_SYMBOL(___raw_readl); 
+EXPORT_SYMBOL(___raw_readq); 
+EXPORT_SYMBOL(___raw_writeb); 
+EXPORT_SYMBOL(___raw_writew); 
+EXPORT_SYMBOL(___raw_writel); 
+EXPORT_SYMBOL(___raw_writeq); 
 EXPORT_SYMBOL(_memcpy_fromio);
 EXPORT_SYMBOL(_memcpy_toio);
 EXPORT_SYMBOL(_memset_c_io);
diff -u --recursive --new-file v2.4.9/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.4.9/linux/arch/i386/defconfig	Mon Aug 27 12:41:39 2001
+++ linux/arch/i386/defconfig	Mon Aug 27 09:16:06 2001
@@ -741,6 +741,7 @@
 # CONFIG_USB_PLUSB is not set
 # CONFIG_USB_PEGASUS is not set
 # CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
 # CONFIG_USB_NET1080 is not set
 
 #
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/Makefile linux/arch/ppc/Makefile
--- v2.4.9/linux/arch/ppc/Makefile	Wed Jul 25 17:10:18 2001
+++ linux/arch/ppc/Makefile	Tue Aug 28 06:58:33 2001
@@ -1,4 +1,4 @@
-# BK Id: SCCS/s.Makefile 1.18 07/07/01 13:37:26 paulus
+# BK Id: SCCS/s.Makefile 1.21 08/19/01 20:06:47 paulus
 #
 # 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
@@ -14,6 +14,7 @@
 # Rewritten by Cort Dougan and Paul Mackerras
 #
 
+# Be sure to change PAGE_OFFSET in include/asm-ppc/page.h to match
 KERNELLOAD	=0xc0000000
 
 ifeq ($(shell uname -m),ppc)
@@ -99,5 +100,5 @@
 
 archmrproper:
 
-archdep:
+archdep: scripts/mkdep
 	$(MAKEBOOT) fastdep
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/boot/Makefile linux/arch/ppc/boot/Makefile
--- v2.4.9/linux/arch/ppc/boot/Makefile	Wed Jul 25 17:10:18 2001
+++ linux/arch/ppc/boot/Makefile	Tue Aug 28 06:58:33 2001
@@ -12,8 +12,8 @@
 
 GZIP_FLAGS = -v9f
 
-CFLAGS	:= $(CPPFLAGS) -O2 -DSTDC_HEADERS -fno-builtin -D__BOOTER__ \
-		-I$(TOPDIR)/arch/$(ARCH)/boot/include
+CFLAGS	+= -fno-builtin -D__BOOTER__ -I$(TOPDIR)/arch/$(ARCH)/boot/include
+
 AFLAGS	+= -D__BOOTER__
 OBJCOPY_ARGS = -O elf32-powerpc
 
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/boot/chrp/Makefile linux/arch/ppc/boot/chrp/Makefile
--- v2.4.9/linux/arch/ppc/boot/chrp/Makefile	Wed Jul 25 17:10:18 2001
+++ linux/arch/ppc/boot/chrp/Makefile	Tue Aug 28 06:58:33 2001
@@ -1,4 +1,4 @@
-# BK Id: SCCS/s.Makefile 1.10 07/19/01 09:11:27 trini
+# BK Id: SCCS/s.Makefile 1.13 07/27/01 20:24:17 trini
 #
 # Makefile for making ELF bootable images for booting on CHRP
 # using Open Firmware.
@@ -14,8 +14,6 @@
 MSIZE=
 endif
 
-CFLAGS += -fno-builtin
-
 .c.o:
 	$(CC) $(CFLAGS) -DKERNELBASE=$(KERNELBASE) -c -o $*.o $<
 .S.o:
@@ -23,7 +21,8 @@
 
 LD_ARGS = -Ttext 0x00400000
 
-OBJS = ../common/crt0.o start.o main.o misc.o ../common/string.o image.o
+OBJS = ../common/crt0.o start.o main.o misc.o ../common/string.o image.o \
+	../common/ofcommon.o
 LIBS = $(TOPDIR)/lib/lib.a ../lib/zlib.a
 ADDNOTE = ../utils/addnote
 PIGGYBACK = ../utils/piggyback
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/boot/chrp/main.c linux/arch/ppc/boot/chrp/main.c
--- v2.4.9/linux/arch/ppc/boot/chrp/main.c	Tue Jul  3 17:08:18 2001
+++ linux/arch/ppc/boot/chrp/main.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.main.c 1.9 06/12/01 16:42:26 paulus
+ * BK Id: SCCS/s.main.c 1.13 07/27/01 20:24:17 trini
  */
 /*
  * Copyright (C) Paul Mackerras 1997.
@@ -10,14 +10,28 @@
  * 2 of the License, or (at your option) any later version.
  */
 #include "nonstdio.h"
-#include "zlib.h"
-#include <asm/bootinfo.h>
 #include <asm/processor.h>
-#include <asm/page.h>
 
-extern void *finddevice(const char *);
+extern char _end[];
+extern char initrd_data[];
+extern char image_data[];
+extern char sysmap_data[];
 extern int getprop(void *, const char *, void *, int);
-void gunzip(void *, int, unsigned char *, int *);
+extern int initrd_len;
+extern int image_len;
+extern int sysmap_len;
+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)
@@ -27,38 +41,28 @@
 
 #define RAM_FREE	((unsigned long)(_end+0x1000)&~0xFFF)
 #define PROG_START	0x00010000
+#define PROG_SIZE	0x00400000 /* 4MB */
 
-char *avail_ram;
-char *end_avail;
-
-extern char _end[];
-extern char image_data[];
-extern int image_len;
-extern char initrd_data[];
-extern int initrd_len;
-extern char sysmap_data[];
-extern int sysmap_len;
+#define SCRATCH_SIZE	(128 << 10)
 
-static char scratch[1024<<10];	/* 1MB of scratch space for gunzip */
+static char scratch[SCRATCH_SIZE];	/* 1MB of scratch space for gunzip */
 
+void
 chrpboot(int a1, int a2, void *prom)
 {
-    int ns, oh, i;
     unsigned sa, len;
     void *dst;
     unsigned char *im;
-    unsigned initrd_start, initrd_size;
+    unsigned initrd_start=0, initrd_size=0;
     extern char _start;
     
-    printf("chrpboot starting: loaded at 0x%x\n\r", &_start);
+    printf("chrpboot starting: loaded at 0x%p\n\r", &_start);
 
     if (initrd_len) {
 	initrd_size = initrd_len;
 	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%x (%x bytes)\n\r",
+	printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n\r",
 	       initrd_start, initrd_data, initrd_size);
 	memcpy((char *)initrd_start, initrd_data, initrd_size);
     }
@@ -66,133 +70,31 @@
     im = image_data;
     len = image_len;
     /* claim 4MB starting at PROG_START */
-    claim(PROG_START, (4<<20) - PROG_START, 0);
+    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%x <- 0x%x:0x%0x)...", dst, im, im+len);
+	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 = (unsigned long)PROG_START;
     printf("start address = 0x%x\n\r", sa);
 
-    {
-	    struct bi_record *rec;
-	    
-	    rec = (struct bi_record *)_ALIGN((unsigned long)dst+len+(1<<20)-1,(1<<20));
-
-	    rec->tag = BI_FIRST;
-	    rec->size = sizeof(struct bi_record);
-	    rec = (struct bi_record *)((unsigned long)rec + rec->size);
-	    
-	    rec->tag = BI_BOOTLOADER_ID;
-	    sprintf( (char *)rec->data, "chrpboot");
-	    rec->size = sizeof(struct bi_record) + strlen("chrpboot") + 1;
-	    rec = (struct bi_record *)((unsigned long)rec + rec->size);
-	    
-	    rec->tag = BI_MACHTYPE;
-	    rec->data[0] = _MACH_chrp;
-	    rec->data[1] = 1;
-	    rec->size = sizeof(struct bi_record) + 2 * sizeof(unsigned long);
-	    rec = (struct bi_record *)((unsigned long)rec + rec->size);
-#if 0
-	    rec->tag = BI_SYSMAP;
-	    rec->data[0] = (unsigned long)sysmap_data;
-	    rec->data[1] = sysmap_len;
-	    rec->size = sizeof(struct bi_record) + 2 * sizeof(unsigned long);
-	    rec = (struct bi_record *)((unsigned long)rec + rec->size);
-#endif
-	    rec->tag = BI_LAST;
-	    rec->size = sizeof(struct bi_record);
-	    rec = (struct bi_record *)((unsigned long)rec + rec->size);
-    }
-    (*(void (*)())sa)(a1, a2, prom);
+    (*(void (*)())sa)(a1, a2, prom, initrd_start, initrd_size);
 
     printf("returned?\n\r");
 
     pause();
-}
-
-void *zalloc(void *x, unsigned items, unsigned size)
-{
-    void *p = avail_ram;
-
-    size *= items;
-    size = (size + 7) & -8;
-    avail_ram += size;
-    if (avail_ram > end_avail) {
-	printf("oops... out of memory\n\r");
-	pause();
-    }
-    return p;
-}
-
-void zfree(void *x, void *addr, unsigned nb)
-{
-    nb = (nb + 7) & -8;
-    if (addr == (avail_ram - nb)) {
-	avail_ram -= nb;
-    }
-}
-
-#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);
 }
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/boot/chrp/start.c linux/arch/ppc/boot/chrp/start.c
--- v2.4.9/linux/arch/ppc/boot/chrp/start.c	Thu May 24 15:02:06 2001
+++ linux/arch/ppc/boot/chrp/start.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.start.c 1.6 05/18/01 15:16:59 cort
+ * BK Id: SCCS/s.start.c 1.8 07/25/01 18:13:07 trini
  */
 /*
  * Copyright (C) Paul Mackerras 1997.
@@ -24,6 +24,9 @@
 
 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)
 {
@@ -91,7 +94,7 @@
 }
 
 void
-exit()
+exit(void)
 {
     struct prom_args {
 	char *service;
@@ -104,7 +107,7 @@
 }
 
 void
-pause()
+pause(void)
 {
     struct prom_args {
 	char *service;
@@ -228,7 +231,7 @@
 static int lineleft;
 
 int
-getchar()
+getchar(void)
 {
     int c;
 
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/boot/common/crt0.S linux/arch/ppc/boot/common/crt0.S
--- v2.4.9/linux/arch/ppc/boot/common/crt0.S	Thu May 24 15:02:06 2001
+++ linux/arch/ppc/boot/common/crt0.S	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.crt0.S 1.10 05/21/01 00:49:49 cort
+ * BK Id: SCCS/s.crt0.S 1.12 08/09/01 17:09:10 paulus
  */
 /*    Copyright (c) 1997 Paul Mackerras <paulus@cs.anu.edu.au>
  *      Initial Power Macintosh COFF version.
@@ -34,7 +34,21 @@
 	.globl	__start
 __start:
 #endif
-#ifdef CONFIG_4xx
+
+	## Flush and invalidate the caches for the range in memory covering
+	## the .text section of the boot loader
+	
+	lis	r9,_start@h		# r9 = &_start
+	lis	r8,_etext@ha		# 
+	addi	r8,r8,_etext@l		# r8 = &_etext
+3:	dcbf	r0,r9			# Flush the data cache
+	icbi	r0,r9			# Invalidate the instruction cache
+	addi	r9,r9,0x10		# Increment by one cache line
+	cmplw	cr0,r9,r8		# Are we at the end yet?
+	blt	3b			# No, keep flushing and invalidating
+	sync				# sync ; isync after flushing the icache
+	isync
+
 	## Clear out the BSS as per ANSI C requirements
 
 	lis	r7,_end@ha
@@ -53,21 +67,7 @@
 	li	r0,0			# r0 = 0
 1:	stwu	r0,4(r8)		# Clear out a word
 	bdnz	1b			# If we are not done yet, keep clearing
-#endif
-
-	## Flush and invalidate the caches for the range in memory covering
-	## the .text section of the boot loader
-	
-2:	lis	r9,_start@h		# r9 = &_start
-	lis	r8,_etext@ha		# 
-	addi	r8,r8,_etext@l		# r8 = &_etext
-3:	dcbf	r0,r9			# Flush the data cache
-	icbi	r0,r9			# Invalidate the instruction cache
-	addi	r9,r9,0x10		# Increment by one cache line
-	cmplw	cr0,r9,r8		# Are we at the end yet?
-	blt	3b			# No, keep flushing and invalidating
-	sync				# sync ; isync after flushing the icache
-	isync
+2:
 
 #ifdef CONFIG_4xx
 	## Set up the stack
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/boot/common/misc-common.c linux/arch/ppc/boot/common/misc-common.c
--- v2.4.9/linux/arch/ppc/boot/common/misc-common.c	Wed Jul 25 17:10:18 2001
+++ linux/arch/ppc/boot/common/misc-common.c	Tue Aug 28 06:58:33 2001
@@ -31,9 +31,10 @@
  * 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <stdarg.h>	/* for va_ bits */
 #include <linux/config.h>
 #include "zlib.h"
-#include <linux/pci.h>
+#include "nonstdio.h"
 
 /* If we're on a ALL_PPC, assume we have a keyboard controller
  * Also note, if we're not ALL_PPC, we assume you are a serial
@@ -71,14 +72,15 @@
 void gunzip(void *, int, unsigned char *, int *);
 static int _cvt(unsigned long val, char *buf, long radix, char *digits);
 
-void _vprintk(void(*)(const char), const char *, va_list);
+void _vprintk(void(*putc)(const char), const char *fmt0, va_list ap);
+unsigned char *ISA_io = NULL;
 
 #if defined(CONFIG_SERIAL_CONSOLE)
 extern unsigned long com_port;
 
-extern int serial_tstc(volatile unsigned long com_port);
-extern unsigned char serial_getc(volatile unsigned long com_port);
-extern void serial_putc(volatile unsigned long com_port, unsigned char c);
+extern int serial_tstc(unsigned long com_port);
+extern unsigned char serial_getc(unsigned long com_port);
+extern void serial_putc(unsigned long com_port, unsigned char c);
 #endif
 
 void pause(void)
@@ -301,7 +303,6 @@
 
 #define FALSE 0
 #define TRUE  1
-#include <stdarg.h>
 
 void
 _printk(char const *fmt, ...)
@@ -528,6 +529,28 @@
 {
 	_printk("\n");
 	_dump_buf_with_offset(p, s, 0);
+}
+
+/* Very simple inb/outb routines.  We declare ISA_io to be 0 above, and
+ * then modify it on platforms which need to.  We do it like this
+ * because on some platforms we give inb/outb an exact location, and
+ * on others it's an offset from a given location. -- Tom
+ */
+
+void
+outb(int port, unsigned char val)
+{
+	/* Ensure I/O operations complete */
+	__asm__ volatile("eieio");
+	ISA_io[port] = val;
+}
+
+unsigned char
+inb(int port)
+{
+	/* Ensure I/O operations complete */
+	__asm__ volatile("eieio");
+	return (ISA_io[port]);
 }
 
 /*
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/boot/common/misc-simple.c linux/arch/ppc/boot/common/misc-simple.c
--- v2.4.9/linux/arch/ppc/boot/common/misc-simple.c	Thu May 24 15:02:06 2001
+++ linux/arch/ppc/boot/common/misc-simple.c	Tue Aug 28 06:58:33 2001
@@ -26,6 +26,7 @@
 #include <asm/processor.h>
 #include <asm/mmu.h>
 
+#include "nonstdio.h"
 #include "zlib.h"
 
 unsigned long com_port;
@@ -47,16 +48,8 @@
 char *zimage_start;
 int zimage_size;
 
-extern void puts(const char *);
-extern void putc(const char c);
-extern void puthex(unsigned long val);
-extern void *memcpy(void * __dest, __const void * __src,
-			    __kernel_size_t __n);
 extern void gunzip(void *, int, unsigned char *, int *);
-extern void udelay(long delay);
-extern int tstc(void);
-extern int getc(void);
-extern volatile unsigned long serial_init(int chan);
+extern unsigned long serial_init(int chan);
 
 void
 decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum)
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/boot/common/ns16550.c linux/arch/ppc/boot/common/ns16550.c
--- v2.4.9/linux/arch/ppc/boot/common/ns16550.c	Thu May 24 15:02:06 2001
+++ linux/arch/ppc/boot/common/ns16550.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.ns16550.c 1.7 05/18/01 06:20:29 patch
+ * BK Id: SCCS/s.ns16550.c 1.9 07/30/01 17:19:40 trini
  */
 /*
  * COM1 NS16550 support
@@ -10,12 +10,9 @@
 #include <linux/serial_reg.h>
 #include <asm/serial.h>
 
-/* Some machines, such as ones with a PReP memory map, initally have
- * their serial port at an offset of 0x80000000 from where they are
- * in <asm/serial.h>.  This tries to take that into account. */
-#ifndef IOOFFSET
-#define IOOFFSET 0
-#endif
+extern void outb(int port, unsigned char val);
+extern unsigned char inb(int port);
+extern unsigned long ISA_io;
 
 static struct serial_state rs_table[RS_TABLE_SIZE] = {
 	SERIAL_PORT_DFNS	/* Defined in <asm/serial.h> */
@@ -23,58 +20,67 @@
 
 static int shift;
 
-volatile unsigned long serial_init(int chan) {
+unsigned long serial_init(int chan) {
 	unsigned long com_port;
 
-	/* Get the base, and add any offset we need to deal with. */
-	com_port = rs_table[chan].port + IOOFFSET;
+	/* We need to find out which type io we're expecting.  If it's
+	 * 'SERIAL_IO_PORT', we get an offset from the isa_io_base.
+	 * If it's 'SERIAL_IO_MEM', we can the exact location.  -- Tom */
+	switch (rs_table[chan].io_type) {
+		case SERIAL_IO_PORT:
+			com_port = rs_table[chan].port;
+			break;
+		case SERIAL_IO_MEM:
+			com_port = (unsigned long)rs_table[chan].iomem_base;
+			break;
+		default:
+			/* We can't deal with it. */
+			return -1;
+	}
 
 	/* How far apart the registers are. */
 	shift = rs_table[chan].iomem_reg_shift;
 
 	/* See if port is present */
-	*((unsigned char *)com_port + (UART_LCR << shift)) = 0x00;
-	*((unsigned char *)com_port + (UART_IER << shift)) = 0x00;
+	outb(com_port + (UART_LCR << shift), 0x00);
+	outb(com_port + (UART_IER << shift), 0x00);
 	/* Access baud rate */
-	*((unsigned char *)com_port + (UART_LCR << shift)) = 0x00;
+	outb(com_port + (UART_LCR << shift), 0x80);
 #ifdef CONFIG_SERIAL_CONSOLE_NONSTD
 	/* Input clock. */
-	*((unsigned char *)com_port + (UART_DLL << shift)) = 
-			(BASE_BAUD / CONFIG_SERIAL_CONSOLE_BAUD);
-	*((unsigned char *)com_port + (UART_DLM << shift)) = 
-		(BASE_BAUD / CONFIG_SERIAL_CONSOLE_BAUD) >> 8;
+	outb(com_port + (UART_DLL << shift), 
+			(BASE_BAUD / CONFIG_SERIAL_CONSOLE_BAUD));
+	outb(com_port + (UART_DLM << shift), 
+		(BASE_BAUD / CONFIG_SERIAL_CONSOLE_BAUD) >> 8);
 #endif
 	 /* 8 data, 1 stop, no parity */
-	*((unsigned char *)com_port + (UART_LCR << shift)) = 0x03;
+	outb(com_port + (UART_LCR << shift), 0x03);
 	/* RTS/DTR */
-	*((unsigned char *)com_port + (UART_MCR << shift)) = 0x03;
+	outb(com_port + (UART_MCR << shift), 0x03);
 	/* Clear & enable FIFOs */
-	*((unsigned char *)com_port + (UART_FCR << shift)) = 0x07;
+	outb(com_port + (UART_FCR << shift), 0x07);
 
 	return (com_port);
 }
 
 void
-serial_putc(volatile unsigned long com_port, unsigned char c)
+serial_putc(unsigned long com_port, unsigned char c)
 {
-	while ((*((volatile unsigned char *)com_port + (UART_LSR << shift)) &
-				UART_LSR_THRE) == 0)
+	while ((inb(com_port + (UART_LSR << shift)) & UART_LSR_THRE) == 0)
 		;
-	*(volatile unsigned char *)com_port = c;
+	outb(com_port, c);
 }
 
 unsigned char
-serial_getc(volatile unsigned long com_port)
+serial_getc(unsigned long com_port)
 {
-	while ((*((volatile unsigned char *)com_port + (UART_LSR << shift))
-			& UART_LSR_DR) == 0)
+	while ((inb(com_port + (UART_LSR << shift)) & UART_LSR_DR) == 0)
 		;
-	return (*(volatile unsigned char *)com_port);
+	return inb(com_port);
 }
 
 int
-serial_tstc(volatile unsigned long com_port)
+serial_tstc(unsigned long com_port)
 {
-	return ((*((volatile unsigned char *)com_port + (UART_LSR << shift))
-				& UART_LSR_DR) != 0);
+	return ((inb(com_port + (UART_LSR << shift)) & UART_LSR_DR) != 0);
 }
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/boot/common/ofcommon.c linux/arch/ppc/boot/common/ofcommon.c
--- v2.4.9/linux/arch/ppc/boot/common/ofcommon.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/boot/common/ofcommon.c	Tue Aug 28 06:58:33 2001
@@ -0,0 +1,171 @@
+/*
+ * BK Id: SCCS/s.ofcommon.c 1.1 07/27/01 20:24:18 trini
+ *
+ * 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 <asm/bootinfo.h>
+#include <asm/page.h>
+
+extern int strcmp(const char *s1, const char *s2);
+extern char *avail_ram, *avail_high;
+extern char *end_avail;
+extern void claim(unsigned int virt, unsigned int size, unsigned int align);
+extern void pause(void);
+
+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)
+{
+	struct bi_record *rec;
+
+	/* 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);
+
+#ifdef SYSMAP_OFFSET
+	rec->tag = BI_SYSMAP;
+	rec->data[0] = SYSMAP_OFFSET;
+	rec->data[1] = SYSMAP_SIZE;
+	rec->size = sizeof(struct bi_record) + 2 * sizeof(unsigned long);
+	rec = (struct bi_record *)((unsigned long)rec + rec->size);
+#endif /* SYSMAP_OFFSET */
+	
+	rec->tag = BI_LAST;
+	rec->size = sizeof(struct bi_record);
+	rec = (struct bi_record *)((unsigned long)rec + rec->size);
+}
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/boot/include/nonstdio.h linux/arch/ppc/boot/include/nonstdio.h
--- v2.4.9/linux/arch/ppc/boot/include/nonstdio.h	Thu May 24 15:02:06 2001
+++ linux/arch/ppc/boot/include/nonstdio.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.nonstdio.h 1.7 05/18/01 15:17:23 cort
+ * BK Id: SCCS/s.nonstdio.h 1.9 07/25/01 18:13:07 trini
  */
 /*
  * Copyright (C) Paul Mackerras 1997.
@@ -8,14 +8,31 @@
  * 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 is sort of a catchall for I/O related functions.  Stuff that
+ * wouldn't be in 'stdio.h' normally is here, and it's 'nonstdio.h'
+ * for a reason.  -- Tom
  */
-typedef int	FILE;
+typedef int FILE;
 extern FILE *stdin, *stdout;
-#define NULL	((void *)0)
-#define EOF	(-1)
-#define fopen(n, m)	NULL
-#define fflush(f)	0
-#define fclose(f)	0
-extern char *fgets();
+#define NULL ((void *)0)
+#define EOF (-1)
+#define fopen(n, m) NULL
+#define fflush(f) 0
+#define fclose(f) 0
+#define perror(s) printf("%s: no files!\n", (s))
 
-#define perror(s)	printf("%s: no files!\n", (s))
+extern int getc(void);
+extern int printf(const char *format, ...);
+extern int strlen(const char *s);
+extern int sprintf(char *str, const char *format, ...);
+extern int tstc(void);
+extern void exit(void);
+extern void *memcpy(void *dest, const void *src, int n);
+extern void *memmove(void *dest, const void *src, int n);
+extern void outb(int port, unsigned char val);
+extern void putc(const char c);
+extern void puthex(unsigned long val);
+extern void puts(const char *);
+extern void udelay(long delay);
+extern unsigned char inb(int port);
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/boot/mbx/misc.c linux/arch/ppc/boot/mbx/misc.c
--- v2.4.9/linux/arch/ppc/boot/mbx/misc.c	Wed Jul 25 17:10:18 2001
+++ linux/arch/ppc/boot/mbx/misc.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.misc.c 1.11 07/18/01 15:46:50 trini
+ * BK Id: SCCS/s.misc.c 1.13 07/27/01 11:44:37 trini
  */
 /*
  * Adapted for PowerPC by Gary Thomas
@@ -23,6 +23,8 @@
 #include <asm/mpc8260.h>
 #endif
 
+#include "nonstdio.h"
+
 /*
  * The following references are needed to cause the linker to pull in the
  * gzimage.o and rdimage.o files.  These object files are special,
@@ -75,14 +77,7 @@
 char *zimage_start;
 int zimage_size;
 
-extern void puts(const char *);
-extern void putc(const char c);
-extern void udelay(long x);
-extern void puthex(unsigned long val);
-extern void * memcpy(void * __dest, __const void * __src, __kernel_size_t __n);
 extern void gunzip(void *, int, unsigned char *, int *);
-extern int tstc(void);
-extern int getc(void);
 
 unsigned long
 decompress_kernel(unsigned long load_addr, int num_words, unsigned long cksum, bd_t *bp)
@@ -267,33 +262,4 @@
 	puts("done.\n");
 	puts("Now booting the kernel\n");
 	return (unsigned long)hold_residual;
-}
-
-/*
- * PCI/ISA I/O support
- */
-
-volatile unsigned char *ISA_io  = (unsigned char *)0x80000000;
-volatile unsigned char *ISA_mem = (unsigned char *)0xC0000000;
-
-void
-outb(int port, char val)
-{
-	/* Ensure I/O operations complete */
-	__asm__ volatile("eieio");
-	ISA_io[port] = val;
-}
-
-unsigned char
-inb(int port)
-{
-	/* Ensure I/O operations complete */
-	__asm__ volatile("eieio");
-	return (ISA_io[port]);
-}
-
-unsigned long
-local_to_PCI(unsigned long addr)
-{
-	return ((addr & 0x7FFFFFFF) | 0x80000000);
 }
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/boot/pmac/Makefile linux/arch/ppc/boot/pmac/Makefile
--- v2.4.9/linux/arch/ppc/boot/pmac/Makefile	Wed Jul 25 17:10:18 2001
+++ linux/arch/ppc/boot/pmac/Makefile	Tue Aug 28 06:58:33 2001
@@ -1,4 +1,4 @@
-# BK Id: SCCS/s.Makefile 1.12 07/19/01 09:11:28 trini
+# BK Id: SCCS/s.Makefile 1.14 07/27/01 20:24:17 trini
 #
 # Makefile for making XCOFF bootable images for booting on PowerMacs
 # using Open Firmware.
@@ -12,12 +12,10 @@
 COFF_LD_ARGS = -e _start -T ld.script -Ttext 500000 -Tdata 510000 -Bstatic
 CHRP_LD_ARGS = -Ttext 0x01000000
 
-COMMONOBJS = start.o misc.o ../common/string.o image.o
+COMMONOBJS = start.o misc.o ../common/string.o image.o ../common/ofcommon.o
 COFFOBJS = ../common/coffcrt0.o $(COMMONOBJS) coffmain.o
 CHRPOBJS = ../common/crt0.o $(COMMONOBJS) chrpmain.o
 LIBS = $(TOPDIR)/lib/lib.a ../lib/zlib.a
-
-CFLAGS += -fno-builtin
 
 MKNOTE := ../utils/mknote
 SIZE := ../utils/size
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/boot/pmac/chrpmain.c linux/arch/ppc/boot/pmac/chrpmain.c
--- v2.4.9/linux/arch/ppc/boot/pmac/chrpmain.c	Tue Jul  3 17:08:18 2001
+++ linux/arch/ppc/boot/pmac/chrpmain.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.chrpmain.c 1.12 06/12/01 16:42:26 paulus
+ * BK Id: SCCS/s.chrpmain.c 1.16 07/27/01 20:24:18 trini
  */
 /*
  * Copyright (C) Paul Mackerras 1997.
@@ -11,21 +11,26 @@
  */
 #include "nonstdio.h"
 #include "zlib.h"
-#include <asm/bootinfo.h>
 #include <asm/processor.h>
-#include <asm/page.h>
 
-extern void *finddevice(const char *);
+extern char _end[];
+extern char image_data[], initrd_data[];
+extern int image_len, initrd_len;
 extern int getprop(void *, const char *, void *, int);
+extern unsigned int heap_max;
 extern void *claim(unsigned int, unsigned int, unsigned int);
+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);
-void make_bi_recs(unsigned long);
-void gunzip(void *, int, unsigned char *, int *);
-void stop_imac_ethernet(void);
-void stop_imac_usb(void);
 
-#define get_16be(x)	(*(unsigned short *)(x))
-#define get_32be(x)	(*(unsigned *)(x))
+char *avail_ram;
+char *begin_avail, *end_avail;
+char *avail_high;
+
 
 #define RAM_END		(16 << 20)
 
@@ -34,36 +39,22 @@
 
 #define SCRATCH_SIZE	(128 << 10)
 
-char *avail_ram;
-char *begin_avail, *end_avail;
-char *avail_high;
-unsigned int heap_use;
-unsigned int heap_max;
-
-extern char _end[];
-extern char image_data[];
-extern int image_len;
-extern char initrd_data[];
-extern int initrd_len;
-
-
-boot(int a1, int a2, void *prom)
+void boot(int a1, int a2, void *prom)
 {
-    int ns, oh, i;
     unsigned sa, len;
     void *dst;
     unsigned char *im;
     unsigned initrd_start, initrd_size;
     extern char _start;
     
-    printf("chrpboot starting: loaded at 0x%x\n", &_start);
+    printf("chrpboot starting: loaded at 0x%p\n", &_start);
     if (initrd_len) {
 	initrd_size = initrd_len;
 	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%x (%x bytes)\n", initrd_start,
+	printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n", initrd_start,
 	       initrd_data,initrd_size);
 	memcpy((char *)initrd_start, initrd_data, initrd_size);
     }
@@ -77,8 +68,8 @@
 	avail_ram = (char *) claim(0, SCRATCH_SIZE, 0x10);
 	begin_avail = avail_high = avail_ram;
 	end_avail = avail_ram + SCRATCH_SIZE;
-	printf("heap at 0x%x\n", avail_ram);
-	printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len);
+	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",
@@ -89,7 +80,8 @@
     }
 
     flush_cache(dst, len);
-    make_bi_recs((unsigned long) 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);
@@ -99,199 +91,4 @@
     printf("returned?\n");
 
     pause();
-}
-
-void make_bi_recs(unsigned long addr)
-{
-	struct bi_record *rec;
-
-	/* leave a 1MB gap then align to the next 1MB boundary */
-	addr = _ALIGN(addr+ (1<<20) - 1, (1<<20));
-	if (addr >= PROG_START + PROG_SIZE)
-		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, "coffboot");
-	rec->size = sizeof(struct bi_record) + strlen("coffboot") + 1;
-	rec = (struct bi_record *)((unsigned long)rec + rec->size);
-	    
-	rec->tag = BI_MACHTYPE;
-	rec->data[0] = _MACH_Pmac;
-	rec->data[1] = 1;
-	rec->size = sizeof(struct bi_record) + 2 * sizeof(unsigned long);
-	rec = (struct bi_record *)((unsigned long)rec + rec->size);
-
-#ifdef SYSMAP_OFFSET
-	rec->tag = BI_SYSMAP;
-	rec->data[0] = SYSMAP_OFFSET;
-	rec->data[1] = SYSMAP_SIZE;
-	rec->size = sizeof(struct bi_record) + 2 * sizeof(unsigned long);
-	rec = (struct bi_record *)((unsigned long)rec + rec->size);
-#endif /* SYSMAP_OFFSET */
-	
-	rec->tag = BI_LAST;
-	rec->size = sizeof(struct bi_record);
-	rec = (struct bi_record *)((unsigned long)rec + rec->size);
-}
-
-#if 0
-#define eieio()	asm volatile("eieio");
-
-void stop_imac_ethernet(void)
-{
-    void *macio, *enet;
-    unsigned int macio_addr[5], enet_reg[6];
-    int len;
-    volatile unsigned int *dbdma;
-
-    macio = finddevice("/pci/mac-io");
-    enet = finddevice("/pci/mac-io/ethernet");
-    if (macio == NULL || enet == NULL)
-	return;
-    len = getprop(macio, "assigned-addresses", macio_addr, sizeof(macio_addr));
-    if (len != sizeof(macio_addr))
-	return;
-    len = getprop(enet, "reg", enet_reg, sizeof(enet_reg));
-    if (len != sizeof(enet_reg))
-	return;
-    printf("macio base %x, dma at %x & %x\n",
-	   macio_addr[2], enet_reg[2], enet_reg[4]);
-
-    /* hope this is mapped... */
-    dbdma = (volatile unsigned int *) (macio_addr[2] + enet_reg[2]);
-    *dbdma = 0x80;	/* clear the RUN bit */
-    eieio();
-    dbdma = (volatile unsigned int *) (macio_addr[2] + enet_reg[4]);
-    *dbdma = 0x80;	/* clear the RUN bit */
-    eieio();
-}
-
-void stop_imac_usb(void)
-{
-    void *usb;
-    unsigned int usb_addr[5];
-    int len;
-    volatile unsigned int *usb_ctrl;
-
-    usb = finddevice("/pci/usb");
-    if (usb == NULL)
-	return;
-    len = getprop(usb, "assigned-addresses", usb_addr, sizeof(usb_addr));
-    if (len != sizeof(usb_addr))
-	return;
-    printf("usb base %x\n", usb_addr[2]);
-
-    usb_ctrl = (volatile unsigned int *) (usb_addr[2] + 8);
-    *usb_ctrl = 0x01000000;	/* cpu_to_le32(1) */
-    eieio();
-}
-#endif
-
-struct memchunk {
-    unsigned int size;
-    struct memchunk *next;
-};
-
-static struct memchunk *freechunks;
-
-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");
-	pause();
-    }
-    return p;
-}
-
-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");
-	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");
-	exit();
-    }
-
-    s.zalloc = zalloc;
-    s.zfree = zfree;
-    r = inflateInit2(&s, -MAX_WBITS);
-    if (r != Z_OK) {
-	printf("inflateInit2 returned %d\n", 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, s.msg);
-	exit();
-    }
-    *lenp = s.next_out - (unsigned char *) dst;
-    inflateEnd(&s);
 }
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/boot/pmac/coffmain.c linux/arch/ppc/boot/pmac/coffmain.c
--- v2.4.9/linux/arch/ppc/boot/pmac/coffmain.c	Tue Jul  3 17:08:18 2001
+++ linux/arch/ppc/boot/pmac/coffmain.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.coffmain.c 1.12 06/12/01 16:42:26 paulus
+ * BK Id: SCCS/s.coffmain.c 1.14 07/27/01 20:24:18 trini
  */
 /*
  * Copyright (C) Paul Mackerras 1997.
@@ -11,18 +11,25 @@
  */
 #include "nonstdio.h"
 #include "zlib.h"
-#include <asm/bootinfo.h>
 #include <asm/processor.h>
-#include <asm/page.h>
 
-extern void *finddevice(const char *);
-extern int getprop(void *, const char *, void *, int);
+extern char _start[], _end[];
 extern char *claim(unsigned, unsigned, unsigned);
-void make_bi_recs(unsigned long);
-void gunzip(void *, int, unsigned char *, int *);
+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);
 
-#define get_16be(x)	(*(unsigned short *)(x))
-#define get_32be(x)	(*(unsigned *)(x))
+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 */
@@ -32,29 +39,16 @@
 
 #define SCRATCH_SIZE	(128 << 10)
 
-char *avail_ram;
-char *begin_avail, *end_avail;
-char *avail_high;
-unsigned int heap_use;
-unsigned int heap_max;
-
-extern char _start[], _end[];
-extern char image_data[];
-extern int image_len;
-extern char initrd_data[];
-extern int initrd_len;
+static char heap[SCRATCH_SIZE];
 
-char heap[SCRATCH_SIZE];
-
-boot(int a1, int a2, void *prom)
+void boot(int a1, int a2, void *prom)
 {
-    int ns, oh, i;
     unsigned sa, len;
     void *dst;
     unsigned char *im;
     unsigned initrd_start, initrd_size;
     
-    printf("coffboot starting: loaded at 0x%x\n", _start);
+    printf("coffboot starting: loaded at 0x%p\n", &_start);
     setup_bats(RAM_START);
     if (initrd_len) {
 	initrd_size = initrd_len;
@@ -62,21 +56,21 @@
 	a1 = initrd_start;
 	a2 = initrd_size;
 	claim(initrd_start - RAM_START, RAM_END - initrd_start, 0);
-	printf("initial ramdisk moving 0x%x <- 0x%x (%x bytes)\n",
+	printf("initial ramdisk moving 0x%x <- 0x%p (%x bytes)\n",
 	       initrd_start, initrd_data, initrd_size);
 	memcpy((char *)initrd_start, initrd_data, initrd_size);
     }
     im = image_data;
     len = image_len;
-    /* claim 3MB starting at 0 */
+    /* 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%x\n", avail_ram);
-	printf("gunzipping (0x%x <- 0x%x:0x%0x)...", dst, im, im+len);
+	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",
@@ -86,8 +80,9 @@
     }
 
     flush_cache(dst, len);
-    make_bi_recs((unsigned long)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);
 
@@ -96,139 +91,4 @@
     printf("returned?\n");
 
     pause();
-}
-
-void make_bi_recs(unsigned long addr)
-{
-	struct bi_record *rec;
-
-	addr = _ALIGN(addr+ (1<<20) - 1, (1<<20));
-#if 0
-	if (addr >= PROG_START + PROG_SIZE)
-		claim(addr, 0x1000, 0);
-#endif
-
-	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, "coffboot");
-	rec->size = sizeof(struct bi_record) + strlen("coffboot") + 1;
-	rec = (struct bi_record *)((unsigned long)rec + rec->size);
-
-	rec->tag = BI_MACHTYPE;
-	rec->data[0] = _MACH_Pmac;
-	rec->data[1] = 1;
-	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);
-}
-
-struct memchunk {
-    unsigned int size;
-    struct memchunk *next;
-};
-
-static struct memchunk *freechunks;
-
-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");
-	pause();
-    }
-    return p;
-}
-
-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");
-	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");
-	exit();
-    }
-
-    s.zalloc = zalloc;
-    s.zfree = zfree;
-    r = inflateInit2(&s, -MAX_WBITS);
-    if (r != Z_OK) {
-	printf("inflateInit2 returned %d\n", 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, s.msg);
-	exit();
-    }
-    *lenp = s.next_out - (unsigned char *) dst;
-    inflateEnd(&s);
 }
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/boot/pmac/start.c linux/arch/ppc/boot/pmac/start.c
--- v2.4.9/linux/arch/ppc/boot/pmac/start.c	Thu May 24 15:02:07 2001
+++ linux/arch/ppc/boot/pmac/start.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.start.c 1.8 05/18/01 15:17:15 cort
+ * BK Id: SCCS/s.start.c 1.10 07/25/01 18:13:07 trini
  */
 /*
  * Copyright (C) Paul Mackerras 1997.
@@ -11,6 +11,9 @@
  */
 #include <stdarg.h>
 
+extern int strlen(const char *s);
+extern void boot(int a1, int a2, void *prom);
+
 int (*prom)();
 
 void *chosen_handle;
@@ -109,7 +112,7 @@
 }
 
 void
-exit()
+exit(void)
 {
     struct prom_args {
 	char *service;
@@ -122,7 +125,7 @@
 }
 
 void
-pause()
+pause(void)
 {
     struct prom_args {
 	char *service;
@@ -243,7 +246,7 @@
 }
 
 int
-readchar()
+readchar(void)
 {
     char ch;
 
@@ -263,7 +266,7 @@
 static int lineleft;
 
 int
-getchar()
+getchar(void)
 {
     int c;
 
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/boot/prep/Makefile linux/arch/ppc/boot/prep/Makefile
--- v2.4.9/linux/arch/ppc/boot/prep/Makefile	Wed Jul 25 17:10:18 2001
+++ linux/arch/ppc/boot/prep/Makefile	Tue Aug 28 06:58:33 2001
@@ -1,4 +1,4 @@
-# BK Id: SCCS/s.Makefile 1.19 07/19/01 09:11:28 trini
+# BK Id: SCCS/s.Makefile 1.24 08/01/01 13:25:40 trini
 #
 # arch/ppc/boot/Makefile
 #
@@ -17,8 +17,6 @@
 
 USE_STANDARD_AS_RULE		:= true
 
-CFLAGS				+= -fno-builtin
-
 ifeq ($(CONFIG_SMP),y)
 TFTPIMAGE			= /tftpboot/zImage.prep.smp
 else
@@ -32,7 +30,7 @@
 OBJCOPY_ARGS			= -O elf32-powerpc
 LIBS 				= ../lib/zlib.a
 
-obj-$(CONFIG_SERIAL_CONSOLE)	+= ns16550.o
+obj-$(CONFIG_SERIAL_CONSOLE)	+= ../common/ns16550.o
 obj-$(CONFIG_VGA_CONSOLE)	+= vreset.o kbd.o
 
 # Tools
@@ -45,9 +43,6 @@
 misc.o: misc.c
 	$(CC) $(CFLAGS) -DINITRD_OFFSET=0 -DINITRD_SIZE=0 -DZIMAGE_OFFSET=0 \
 		-DZIMAGE_SIZE=0 -c -o $@ $*.c
-
-ns16550.o: ../common/ns16550.c
-	$(CC) $(CFLAGS) -DIOOFFSET=0x80000000 -c -o $@ ../common/$*.c
 
 zvmlinux.initrd: zvmlinux ../images/vmlinux.gz
 	$(LD) $(ZLINKFLAGS) -o $@.tmp $(obj-y) $(LIBS)
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/boot/prep/head.S linux/arch/ppc/boot/prep/head.S
--- v2.4.9/linux/arch/ppc/boot/prep/head.S	Thu May 24 15:02:07 2001
+++ linux/arch/ppc/boot/prep/head.S	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.head.S 1.8 05/18/01 06:20:29 patch
+ * BK Id: SCCS/s.head.S 1.11 07/31/01 16:36:06 trini
  */
 #include "../../kernel/ppc_defs.h"
 #include "../../kernel/ppc_asm.tmpl"
@@ -95,6 +95,11 @@
 	subi	r1,r1,256
 	li	r2,0x000F		/* Mask pointer to 16-byte boundary */
 	andc	r1,r1,r2
+/* Setup ISA_io */
+	lis	r3,ISA_io@h
+	ori	r3,r3,ISA_io@l
+	lis	r4,0x8000
+	stw	r4,0(r3)
 /* Run loader */
 	mr	r3,r8			/* Load point */
 	mr	r4,r7			/* Program length */
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/boot/prep/misc.c linux/arch/ppc/boot/prep/misc.c
--- v2.4.9/linux/arch/ppc/boot/prep/misc.c	Tue Jul  3 17:08:18 2001
+++ linux/arch/ppc/boot/prep/misc.c	Tue Aug 28 06:58:33 2001
@@ -1,8 +1,7 @@
 /*
- * BK Id: SCCS/s.misc.c 1.14 06/16/01 20:43:20 trini
- */
-/*
- * misc.c
+ * BK Id: SCCS/s.misc.c 1.18 07/30/01 17:19:40 trini
+ *
+ * arch/ppc/boot/prep/misc.c
  *
  * Adapted for PowerPC by Gary Thomas
  *
@@ -11,7 +10,6 @@
  */
 
 #include <linux/types.h>
-#include "zlib.h"
 #include <asm/residual.h>
 #include <linux/config.h>
 #include <linux/threads.h>
@@ -22,9 +20,8 @@
 #include <asm/bootinfo.h>
 #include <asm/mmu.h>
 #include <asm/byteorder.h>
-#if defined(CONFIG_SERIAL_CONSOLE)
-unsigned long com_port;
-#endif /* CONFIG_SERIAL_CONSOLE */
+#include "nonstdio.h"
+#include "zlib.h"
 
 /*
  * Please send me load/board info and such data for hardware not
@@ -53,26 +50,28 @@
 char *zimage_start;
 int zimage_size;
 
+#if defined(CONFIG_SERIAL_CONSOLE)
+unsigned long com_port;
+#endif /* CONFIG_SERIAL_CONSOLE */
+#ifdef CONFIG_VGA_CONSOLE
 char *vidmem = (char *)0xC00B8000;
-int lines, cols;
-int orig_x, orig_y;
+int lines = 25, cols = 80;
+int orig_x, orig_y = 24;
+#endif /* CONFIG_VGA_CONSOLE */
 
-extern void puts(const char *);
-extern void putc(const char c);
-extern int tstc(void);
-extern int getc(void);
-extern void puthex(unsigned long val);
-extern void * memcpy(void * __dest, __const void * __src, __kernel_size_t __n);
 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 __kernel_size_t strlen(const char *s);
 extern int vga_init(unsigned char *ISA_mem);
-extern void udelay(long x);
-void gunzip(void *, int, unsigned char *, int *);
-unsigned char inb(int);
+extern void gunzip(void *, int, unsigned char *, int *);
+
+extern void _put_HID0(unsigned int val);
+extern void _put_MSR(unsigned int val);
+extern unsigned int _get_HID0(void);
+extern unsigned int _get_MSR(void);
+extern unsigned long serial_init(int chan);
 
 void
 writel(unsigned int val, unsigned int address)
@@ -105,7 +104,7 @@
 
 #ifdef CONFIG_VGA_CONSOLE
 void
-scroll()
+scroll(void)
 {
 	int i;
 
@@ -120,7 +119,7 @@
  * Motorola dual processor platforms.  
  */
 void
-park_cpus()
+park_cpus(void)
 {
 	volatile void (*go)(RESIDUAL *, int, int, char *, int);
 	unsigned int i;
@@ -154,11 +153,6 @@
 	unsigned char base_mod;
 	int start_multi = 0;
 	unsigned int pci_viddid, pci_did, tulip_pci_base, tulip_base;
-
-	lines = 25;
-	cols = 80;
-	orig_x = 0;
-	orig_y = 24;
 	
 	/*
 	 * IBM's have the MMU on, so we have to disable it or
@@ -438,28 +432,8 @@
 /*
  * PCI/ISA I/O support
  */
-
-volatile unsigned char *ISA_io  = (unsigned char *)0x80000000;
-volatile unsigned char *ISA_mem = (unsigned char *)0xC0000000;
-
-void
-outb(int port, char val)
-{
-	/* Ensure I/O operations complete */
-	__asm__ volatile("eieio");
-	ISA_io[port] = val;
-}
-
-unsigned char
-inb(int port)
-{
-	/* Ensure I/O operations complete */
-	__asm__ volatile("eieio");
-	return (ISA_io[port]);
-}
-
 unsigned long
 local_to_PCI(unsigned long addr)
 {
-	return ((addr & 0x7FFFFFFF) | 0x80000000);
+	return (addr | 0x80000000);
 }
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/boot/prep/vreset.c linux/arch/ppc/boot/prep/vreset.c
--- v2.4.9/linux/arch/ppc/boot/prep/vreset.c	Thu May 24 15:02:07 2001
+++ linux/arch/ppc/boot/prep/vreset.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.vreset.c 1.9 05/18/01 06:20:29 patch
+ * BK Id: SCCS/s.vreset.c 1.11 07/25/01 18:13:07 trini
  */
 /*
  * vreset.c
@@ -22,12 +22,10 @@
  */
 
 #include "iso_font.h"
+#include "nonstdio.h"
 
 extern char *vidmem;
 extern int lines, cols;
-extern void udelay(long x);
-extern void outb(int port, char val);
-extern unsigned char inb(int port);
 struct VaRegs;
 
 /*
@@ -43,7 +41,7 @@
 void unlockVideo(int slot);
 void setTextRegs(struct VgaRegs *svp);
 void setTextCLUT(int shift);
-void clearVideoMemory();
+void clearVideoMemory(void);
 void loadFont(unsigned char *ISA_mem);
 
 static void mdelay(int ms)
@@ -59,100 +57,100 @@
 #define NREGS 54
 #define ENDMK  0xFFFF  /* End marker */
 
-#define S3Vendor        0x5333
+#define S3Vendor	0x5333
 #define CirrusVendor    0x1013
 #define DiamondVendor   0x100E
 #define MatroxVendor    0x102B
 #define ParadiseVendor  0x101C
 
 struct VgaRegs GenVgaTextRegs[NREGS+1] = {
-/*      port    index   value  */
-  /* SR Regs */
-        0x3c4,  0x1,    0x0,
-        0x3c4,  0x2,    0x3,
-        0x3c4,  0x3,    0x0,
-        0x3c4,  0x4,    0x2,
-   /* CR Regs */
-        0x3d4,  0x0,    0x5f,
-        0x3d4,  0x1,    0x4f,
-        0x3d4,  0x2,    0x50,
-        0x3d4,  0x3,    0x82,
-        0x3d4,  0x4,    0x55,
-        0x3d4,  0x5,    0x81,
-        0x3d4,  0x6,    0xbf,
-        0x3d4,  0x7,    0x1f,
-        0x3d4,  0x8,    0x00,
-        0x3d4,  0x9,    0x4f,
-        0x3d4,  0xa,    0x0d,
-        0x3d4,  0xb,    0x0e,
-        0x3d4,  0xc,    0x00,
-        0x3d4,  0xd,    0x00,
-        0x3d4,  0xe,    0x00,
-        0x3d4,  0xf,    0x00,
-        0x3d4,  0x10,   0x9c,
-        0x3d4,  0x11,   0x8e,
-        0x3d4,  0x12,   0x8f,
-        0x3d4,  0x13,   0x28,
-        0x3d4,  0x14,   0x1f,
-        0x3d4,  0x15,   0x96,
-        0x3d4,  0x16,   0xb9,
-        0x3d4,  0x17,   0xa3,
-   /* GR Regs */
-        0x3ce,  0x0,    0x0,
-        0x3ce,  0x1,    0x0,
-        0x3ce,  0x2,    0x0,
-        0x3ce,  0x3,    0x0,
-        0x3ce,  0x4,    0x0,
-        0x3ce,  0x5,    0x10,
-        0x3ce,  0x6,    0xe,
-        0x3ce,  0x7,    0x0,
-        0x3ce,  0x8,    0xff,
-        ENDMK
+	/* port		index	value  */
+	/* SR Regs */
+	{ 0x3c4,	0x1,	0x0 },
+	{ 0x3c4,	0x2,	0x3 },
+	{ 0x3c4,	0x3,	0x0 },
+	{ 0x3c4,	0x4,	0x2 },
+	 /* CR Regs */
+	{ 0x3d4,	0x0,	0x5f },
+	{ 0x3d4,	0x1,	0x4f },
+	{ 0x3d4,	0x2,	0x50 },
+	{ 0x3d4,	0x3,	0x82 },
+	{ 0x3d4,	0x4,	0x55 },
+	{ 0x3d4,	0x5,	0x81 },
+	{ 0x3d4,	0x6,	0xbf },
+	{ 0x3d4,	0x7,	0x1f },
+	{ 0x3d4,	0x8,	0x00 },
+	{ 0x3d4,	0x9,	0x4f },
+	{ 0x3d4,	0xa,	0x0d },
+	{ 0x3d4,	0xb,	0x0e },
+	{ 0x3d4,	0xc,	0x00 },
+	{ 0x3d4,	0xd,	0x00 },
+	{ 0x3d4,	0xe,	0x00 },
+	{ 0x3d4,	0xf,	0x00 },
+	{ 0x3d4,	0x10,	0x9c },
+	{ 0x3d4,	0x11,	0x8e },
+	{ 0x3d4,	0x12,	0x8f },
+	{ 0x3d4,	0x13,	0x28 },
+	{ 0x3d4,	0x14,	0x1f },
+	{ 0x3d4,	0x15,	0x96 },
+	{ 0x3d4,	0x16,	0xb9 },
+	{ 0x3d4,	0x17,	0xa3 },
+	 /* GR Regs */
+	{ 0x3ce,	0x0,	0x0 },
+	{ 0x3ce,	0x1,	0x0 },
+	{ 0x3ce,	0x2,	0x0 },
+	{ 0x3ce,	0x3,	0x0 },
+	{ 0x3ce,	0x4,	0x0 },
+	{ 0x3ce,	0x5,	0x10 },
+	{ 0x3ce,	0x6,	0xe },
+	{ 0x3ce,	0x7,	0x0 },
+	{ 0x3ce,	0x8,	0xff },
+	{ ENDMK }
 };
 
 struct VgaRegs S3TextRegs[NREGS+1] = {
-/*	port	index	value  */
-  /* SR Regs */
-	0x3c4,	0x1,	0x0,
-	0x3c4,	0x2,	0x3,
-	0x3c4,	0x3,	0x0,
-	0x3c4,	0x4,	0x2,
-   /* CR Regs */
-	0x3d4,	0x0,	0x5f,
-	0x3d4,	0x1,	0x4f,
-	0x3d4,	0x2,	0x50,
-	0x3d4,	0x3,	0x82,
-	0x3d4,	0x4,	0x55,
-	0x3d4,	0x5,	0x81,
-	0x3d4,	0x6,	0xbf,
-	0x3d4,	0x7,	0x1f,
-	0x3d4,	0x8,	0x00,
-	0x3d4,	0x9,	0x4f,
-	0x3d4,	0xa,	0x0d,
-	0x3d4,	0xb,	0x0e,
-	0x3d4,	0xc,	0x00,
-	0x3d4,	0xd,	0x00,
-	0x3d4,	0xe,	0x00,
-	0x3d4,	0xf,	0x00,
-	0x3d4,	0x10,	0x9c,
-	0x3d4,	0x11,	0x8e,
-	0x3d4,	0x12,	0x8f,
-	0x3d4,	0x13,	0x28,
-	0x3d4,	0x14,	0x1f,
-	0x3d4,	0x15,	0x96,
-	0x3d4,	0x16,	0xb9,
-	0x3d4,	0x17,	0xa3,
-   /* GR Regs */
-	0x3ce,	0x0,	0x0,
-	0x3ce,	0x1,	0x0,
-	0x3ce,	0x2,	0x0,
-	0x3ce,	0x3,	0x0,
-	0x3ce,	0x4,	0x0,
-	0x3ce,	0x5,	0x10,
-	0x3ce,	0x6,	0xe,
-	0x3ce,	0x7,	0x0,
-	0x3ce,	0x8,	0xff,
-        ENDMK
+	/* port		index	value */
+	/* SR Regs */
+	{ 0x3c4,	0x1,	0x0 },
+	{ 0x3c4,	0x2,	0x3 },
+	{ 0x3c4,	0x3,	0x0 },
+	{ 0x3c4,	0x4,	0x2 },
+	/* CR Regs */
+	{ 0x3d4,	0x0,	0x5f },
+	{ 0x3d4,	0x1,	0x4f },
+	{ 0x3d4,	0x2,	0x50 },
+	{ 0x3d4,	0x3,	0x82 },
+	{ 0x3d4,	0x4,	0x55 },
+	{ 0x3d4,	0x5,	0x81 },
+	{ 0x3d4,	0x6,	0xbf },
+	{ 0x3d4,	0x7,	0x1f },
+	{ 0x3d4,	0x8,	0x00 },
+	{ 0x3d4,	0x9,	0x4f },
+	{ 0x3d4,	0xa,	0x0d },
+	{ 0x3d4,	0xb,	0x0e },
+	{ 0x3d4,	0xc,	0x00 },
+	{ 0x3d4,	0xd,	0x00 },
+	{ 0x3d4,	0xe,	0x00 },
+	{ 0x3d4,	0xf,	0x00 },
+	{ 0x3d4,	0x10,	0x9c },
+	{ 0x3d4,	0x11,	0x8e },
+	{ 0x3d4,	0x12,	0x8f },
+	{ 0x3d4,	0x13,	0x28 },
+	{ 0x3d4,	0x14,	0x1f },
+	{ 0x3d4,	0x15,	0x96 },
+	{ 0x3d4,	0x16,	0xb9 },
+	{ 0x3d4,	0x17,	0xa3 },
+	/* GR Regs */
+	{ 0x3ce,	0x0,	0x0 },
+	{ 0x3ce,	0x1,	0x0 },
+	{ 0x3ce,	0x2,	0x0 },
+	{ 0x3ce,	0x3,	0x0 },
+	{ 0x3ce,	0x4,	0x0 },
+	{ 0x3ce,	0x5,	0x10 },
+	{ 0x3ce,	0x6,	0xe },
+	{ 0x3ce,	0x7,	0x0 },
+	{ 0x3ce,	0x8,	0xff },
+	{ ENDMK }
 };
 
 struct RGBColors
@@ -167,262 +165,262 @@
  */
 struct RGBColors TextCLUT[256] = 
 {
-  /*	red	green	blue  */
-	0x0,	0x0,	0x0,
-	0x0,	0x0,	0x2a,
-	0x0,	0x2a,	0x0,
-	0x0,	0x2a,	0x2a,
-	0x2a,	0x0,	0x0,
-	0x2a,	0x0,	0x2a,
-	0x2a,	0x2a,	0x0,
-	0x2a,	0x2a,	0x2a,
-	0x0,	0x0,	0x15,
-	0x0,	0x0,	0x3f,
-	0x0,	0x2a,	0x15,
-	0x0,	0x2a,	0x3f,
-	0x2a,	0x0,	0x15,
-	0x2a,	0x0,	0x3f,
-	0x2a,	0x2a,	0x15,
-	0x2a,	0x2a,	0x3f,
-	0x0,	0x15,	0x0,
-	0x0,	0x15,	0x2a,
-	0x0,	0x3f,	0x0,
-	0x0,	0x3f,	0x2a,
-	0x2a,	0x15,	0x0,
-	0x2a,	0x15,	0x2a,
-	0x2a,	0x3f,	0x0,
-	0x2a,	0x3f,	0x2a,
-	0x0,	0x15,	0x15,
-	0x0,	0x15,	0x3f,
-	0x0,	0x3f,	0x15,
-	0x0,	0x3f,	0x3f,
-	0x2a,	0x15,	0x15,
-	0x2a,	0x15,	0x3f,
-	0x2a,	0x3f,	0x15,
-	0x2a,	0x3f,	0x3f,
-	0x15,	0x0,	0x0,
-	0x15,	0x0,	0x2a,
-	0x15,	0x2a,	0x0,
-	0x15,	0x2a,	0x2a,
-	0x3f,	0x0,	0x0,
-	0x3f,	0x0,	0x2a,
-	0x3f,	0x2a,	0x0,
-	0x3f,	0x2a,	0x2a,
-	0x15,	0x0,	0x15,
-	0x15,	0x0,	0x3f,
-	0x15,	0x2a,	0x15,
-	0x15,	0x2a,	0x3f,
-	0x3f,	0x0,	0x15,
-	0x3f,	0x0,	0x3f,
-	0x3f,	0x2a,	0x15,
-	0x3f,	0x2a,	0x3f,
-	0x15,	0x15,	0x0,
-	0x15,	0x15,	0x2a,
-	0x15,	0x3f,	0x0,
-	0x15,	0x3f,	0x2a,
-	0x3f,	0x15,	0x0,
-	0x3f,	0x15,	0x2a,
-	0x3f,	0x3f,	0x0,
-	0x3f,	0x3f,	0x2a,
-	0x15,	0x15,	0x15,
-	0x15,	0x15,	0x3f,
-	0x15,	0x3f,	0x15,
-	0x15,	0x3f,	0x3f,
-	0x3f,	0x15,	0x15,
-	0x3f,	0x15,	0x3f,
-	0x3f,	0x3f,	0x15,
-	0x3f,	0x3f,	0x3f,
-	0x39,	0xc,	0x5,
-	0x15,	0x2c,	0xf,
-	0x26,	0x10,	0x3d,
-	0x29,	0x29,	0x38,
-	0x4,	0x1a,	0xe,
-	0x2,	0x1e,	0x3a,
-	0x3c,	0x25,	0x33,
-	0x3c,	0xc,	0x2c,
-	0x3f,	0x3,	0x2b,
-	0x1c,	0x9,	0x13,
-	0x25,	0x2a,	0x35,
-	0x1e,	0xa,	0x38,
-	0x24,	0x8,	0x3,
-	0x3,	0xe,	0x36,
-	0xc,	0x6,	0x2a,
-	0x26,	0x3,	0x32,
-	0x5,	0x2f,	0x33,
-	0x3c,	0x35,	0x2f,
-	0x2d,	0x26,	0x3e,
-	0xd,	0xa,	0x10,
-	0x25,	0x3c,	0x11,
-	0xd,	0x4,	0x2e,
-	0x5,	0x19,	0x3e,
-	0xc,	0x13,	0x34,
-	0x2b,	0x6,	0x24,
-	0x4,	0x3,	0xd,
-	0x2f,	0x3c,	0xc,
-	0x2a,	0x37,	0x1f,
-	0xf,	0x12,	0x38,
-	0x38,	0xe,	0x2a,
-	0x12,	0x2f,	0x19,
-	0x29,	0x2e,	0x31,
-	0x25,	0x13,	0x3e,
-	0x33,	0x3e,	0x33,
-	0x1d,	0x2c,	0x25,
-	0x15,	0x15,	0x5,
-	0x32,	0x25,	0x39,
-	0x1a,	0x7,	0x1f,
-	0x13,	0xe,	0x1d,
-	0x36,	0x17,	0x34,
-	0xf,	0x15,	0x23,
-	0x2,	0x35,	0xd,
-	0x15,	0x3f,	0xc,
-	0x14,	0x2f,	0xf,
-	0x19,	0x21,	0x3e,
-	0x27,	0x11,	0x2f,
-	0x38,	0x3f,	0x3c,
-	0x36,	0x2d,	0x15,
-	0x16,	0x17,	0x2,
-	0x1,	0xa,	0x3d,
-	0x1b,	0x11,	0x3f,
-	0x21,	0x3c,	0xd,
-	0x1a,	0x39,	0x3d,
-	0x8,	0xe,	0xe,
-	0x22,	0x21,	0x23,
-	0x1e,	0x30,	0x5,
-	0x1f,	0x22,	0x3d,
-	0x1e,	0x2f,	0xa,
-	0x0,	0x1c,	0xe,
-	0x0,	0x1c,	0x15,
-	0x0,	0x1c,	0x1c,
-	0x0,	0x15,	0x1c,
-	0x0,	0xe,	0x1c,
-	0x0,	0x7,	0x1c,
-	0xe,	0xe,	0x1c,
-	0x11,	0xe,	0x1c,
-	0x15,	0xe,	0x1c,
-	0x18,	0xe,	0x1c,
-	0x1c,	0xe,	0x1c,
-	0x1c,	0xe,	0x18,
-	0x1c,	0xe,	0x15,
-	0x1c,	0xe,	0x11,
-	0x1c,	0xe,	0xe,
-	0x1c,	0x11,	0xe,
-	0x1c,	0x15,	0xe,
-	0x1c,	0x18,	0xe,
-	0x1c,	0x1c,	0xe,
-	0x18,	0x1c,	0xe,
-	0x15,	0x1c,	0xe,
-	0x11,	0x1c,	0xe,
-	0xe,	0x1c,	0xe,
-	0xe,	0x1c,	0x11,
-	0xe,	0x1c,	0x15,
-	0xe,	0x1c,	0x18,
-	0xe,	0x1c,	0x1c,
-	0xe,	0x18,	0x1c,
-	0xe,	0x15,	0x1c,
-	0xe,	0x11,	0x1c,
-	0x14,	0x14,	0x1c,
-	0x16,	0x14,	0x1c,
-	0x18,	0x14,	0x1c,
-	0x1a,	0x14,	0x1c,
-	0x1c,	0x14,	0x1c,
-	0x1c,	0x14,	0x1a,
-	0x1c,	0x14,	0x18,
-	0x1c,	0x14,	0x16,
-	0x1c,	0x14,	0x14,
-	0x1c,	0x16,	0x14,
-	0x1c,	0x18,	0x14,
-	0x1c,	0x1a,	0x14,
-	0x1c,	0x1c,	0x14,
-	0x1a,	0x1c,	0x14,
-	0x18,	0x1c,	0x14,
-	0x16,	0x1c,	0x14,
-	0x14,	0x1c,	0x14,
-	0x14,	0x1c,	0x16,
-	0x14,	0x1c,	0x18,
-	0x14,	0x1c,	0x1a,
-	0x14,	0x1c,	0x1c,
-	0x14,	0x1a,	0x1c,
-	0x14,	0x18,	0x1c,
-	0x14,	0x16,	0x1c,
-	0x0,	0x0,	0x10,
-	0x4,	0x0,	0x10,
-	0x8,	0x0,	0x10,
-	0xc,	0x0,	0x10,
-	0x10,	0x0,	0x10,
-	0x10,	0x0,	0xc,
-	0x10,	0x0,	0x8,
-	0x10,	0x0,	0x4,
-	0x10,	0x0,	0x0,
-	0x10,	0x4,	0x0,
-	0x10,	0x8,	0x0,
-	0x10,	0xc,	0x0,
-	0x10,	0x10,	0x0,
-	0xc,	0x10,	0x0,
-	0x8,	0x10,	0x0,
-	0x4,	0x10,	0x0,
-	0x0,	0x10,	0x0,
-	0x0,	0x10,	0x4,
-	0x0,	0x10,	0x8,
-	0x0,	0x10,	0xc,
-	0x0,	0x10,	0x10,
-	0x0,	0xc,	0x10,
-	0x0,	0x8,	0x10,
-	0x0,	0x4,	0x10,
-	0x8,	0x8,	0x10,
-	0xa,	0x8,	0x10,
-	0xc,	0x8,	0x10,
-	0xe,	0x8,	0x10,
-	0x10,	0x8,	0x10,
-	0x10,	0x8,	0xe,
-	0x10,	0x8,	0xc,
-	0x10,	0x8,	0xa,
-	0x10,	0x8,	0x8,
-	0x10,	0xa,	0x8,
-	0x10,	0xc,	0x8,
-	0x10,	0xe,	0x8,
-	0x10,	0x10,	0x8,
-	0xe,	0x10,	0x8,
-	0xc,	0x10,	0x8,
-	0xa,	0x10,	0x8,
-	0x8,	0x10,	0x8,
-	0x8,	0x10,	0xa,
-	0x8,	0x10,	0xc,
-	0x8,	0x10,	0xe,
-	0x8,	0x10,	0x10,
-	0x8,	0xe,	0x10,
-	0x8,	0xc,	0x10,
-	0x8,	0xa,	0x10,
-	0xb,	0xb,	0x10,
-	0xc,	0xb,	0x10,
-	0xd,	0xb,	0x10,
-	0xf,	0xb,	0x10,
-	0x10,	0xb,	0x10,
-	0x10,	0xb,	0xf,
-	0x10,	0xb,	0xd,
-	0x10,	0xb,	0xc,
-	0x10,	0xb,	0xb,
-	0x10,	0xc,	0xb,
-	0x10,	0xd,	0xb,
-	0x10,	0xf,	0xb,
-	0x10,	0x10,	0xb,
-	0xf,	0x10,	0xb,
-	0xd,	0x10,	0xb,
-	0xc,	0x10,	0xb,
-	0xb,	0x10,	0xb,
-	0xb,	0x10,	0xc,
-	0xb,	0x10,	0xd,
-	0xb,	0x10,	0xf,
-	0xb,	0x10,	0x10,
-	0xb,	0xf,	0x10,
-	0xb,	0xd,	0x10,
-	0xb,	0xc,	0x10,
-	0x0,	0x0,	0x0,
-	0x0,	0x0,	0x0,
-	0x0,	0x0,	0x0,
-	0x0,	0x0,	0x0,
-	0x0,	0x0,	0x0,
-	0x0,	0x0,	0x0,
-	0x0,	0x0,	0x0
+	/* red	green	blue  */
+	{ 0x0,	0x0,	0x0 },
+	{ 0x0,	0x0,	0x2a },
+	{ 0x0,	0x2a,	0x0 },
+	{ 0x0,	0x2a,	0x2a },
+	{ 0x2a,	0x0,	0x0 },
+	{ 0x2a,	0x0,	0x2a },
+	{ 0x2a,	0x2a,	0x0 },
+	{ 0x2a,	0x2a,	0x2a },
+	{ 0x0,	0x0,	0x15 },
+	{ 0x0,	0x0,	0x3f },
+	{ 0x0,	0x2a,	0x15 },
+	{ 0x0,	0x2a,	0x3f },
+	{ 0x2a,	0x0,	0x15 },
+	{ 0x2a,	0x0,	0x3f },
+	{ 0x2a,	0x2a,	0x15 },
+	{ 0x2a,	0x2a,	0x3f },
+	{ 0x0,	0x15,	0x0 },
+	{ 0x0,	0x15,	0x2a },
+	{ 0x0,	0x3f,	0x0 },
+	{ 0x0,	0x3f,	0x2a },
+	{ 0x2a,	0x15,	0x0 },
+	{ 0x2a,	0x15,	0x2a },
+	{ 0x2a,	0x3f,	0x0 },
+	{ 0x2a,	0x3f,	0x2a },
+	{ 0x0,	0x15,	0x15 },
+	{ 0x0,	0x15,	0x3f },
+	{ 0x0,	0x3f,	0x15 },
+	{ 0x0,	0x3f,	0x3f },
+	{ 0x2a,	0x15,	0x15 },
+	{ 0x2a,	0x15,	0x3f },
+	{ 0x2a,	0x3f,	0x15 },
+	{ 0x2a,	0x3f,	0x3f },
+	{ 0x15,	0x0,	0x0 },
+	{ 0x15,	0x0,	0x2a },
+	{ 0x15,	0x2a,	0x0 },
+	{ 0x15,	0x2a,	0x2a },
+	{ 0x3f,	0x0,	0x0 },
+	{ 0x3f,	0x0,	0x2a },
+	{ 0x3f,	0x2a,	0x0 },
+	{ 0x3f,	0x2a,	0x2a },
+	{ 0x15,	0x0,	0x15 },
+	{ 0x15,	0x0,	0x3f },
+	{ 0x15,	0x2a,	0x15 },
+	{ 0x15,	0x2a,	0x3f },
+	{ 0x3f,	0x0,	0x15 },
+	{ 0x3f,	0x0,	0x3f },
+	{ 0x3f,	0x2a,	0x15 },
+	{ 0x3f,	0x2a,	0x3f },
+	{ 0x15,	0x15,	0x0 },
+	{ 0x15,	0x15,	0x2a },
+	{ 0x15,	0x3f,	0x0 },
+	{ 0x15,	0x3f,	0x2a },
+	{ 0x3f,	0x15,	0x0 },
+	{ 0x3f,	0x15,	0x2a },
+	{ 0x3f,	0x3f,	0x0 },
+	{ 0x3f,	0x3f,	0x2a },
+	{ 0x15,	0x15,	0x15 },
+	{ 0x15,	0x15,	0x3f },
+	{ 0x15,	0x3f,	0x15 },
+	{ 0x15,	0x3f,	0x3f },
+	{ 0x3f,	0x15,	0x15 },
+	{ 0x3f,	0x15,	0x3f },
+	{ 0x3f,	0x3f,	0x15 },
+	{ 0x3f,	0x3f,	0x3f },
+	{ 0x39,	0xc,	0x5 },
+	{ 0x15,	0x2c,	0xf },
+	{ 0x26,	0x10,	0x3d },
+	{ 0x29,	0x29,	0x38 },
+	{ 0x4,	0x1a,	0xe },
+	{ 0x2,	0x1e,	0x3a },
+	{ 0x3c,	0x25,	0x33 },
+	{ 0x3c,	0xc,	0x2c },
+	{ 0x3f,	0x3,	0x2b },
+	{ 0x1c,	0x9,	0x13 },
+	{ 0x25,	0x2a,	0x35 },
+	{ 0x1e,	0xa,	0x38 },
+	{ 0x24,	0x8,	0x3 },
+	{ 0x3,	0xe,	0x36 },
+	{ 0xc,	0x6,	0x2a },
+	{ 0x26,	0x3,	0x32 },
+	{ 0x5,	0x2f,	0x33 },
+	{ 0x3c,	0x35,	0x2f },
+	{ 0x2d,	0x26,	0x3e },
+	{ 0xd,	0xa,	0x10 },
+	{ 0x25,	0x3c,	0x11 },
+	{ 0xd,	0x4,	0x2e },
+	{ 0x5,	0x19,	0x3e },
+	{ 0xc,	0x13,	0x34 },
+	{ 0x2b,	0x6,	0x24 },
+	{ 0x4,	0x3,	0xd },
+	{ 0x2f,	0x3c,	0xc },
+	{ 0x2a,	0x37,	0x1f },
+	{ 0xf,	0x12,	0x38 },
+	{ 0x38,	0xe,	0x2a },
+	{ 0x12,	0x2f,	0x19 },
+	{ 0x29,	0x2e,	0x31 },
+	{ 0x25,	0x13,	0x3e },
+	{ 0x33,	0x3e,	0x33 },
+	{ 0x1d,	0x2c,	0x25 },
+	{ 0x15,	0x15,	0x5 },
+	{ 0x32,	0x25,	0x39 },
+	{ 0x1a,	0x7,	0x1f },
+	{ 0x13,	0xe,	0x1d },
+	{ 0x36,	0x17,	0x34 },
+	{ 0xf,	0x15,	0x23 },
+	{ 0x2,	0x35,	0xd },
+	{ 0x15,	0x3f,	0xc },
+	{ 0x14,	0x2f,	0xf },
+	{ 0x19,	0x21,	0x3e },
+	{ 0x27,	0x11,	0x2f },
+	{ 0x38,	0x3f,	0x3c },
+	{ 0x36,	0x2d,	0x15 },
+	{ 0x16,	0x17,	0x2 },
+	{ 0x1,	0xa,	0x3d },
+	{ 0x1b,	0x11,	0x3f },
+	{ 0x21,	0x3c,	0xd },
+	{ 0x1a,	0x39,	0x3d },
+	{ 0x8,	0xe,	0xe },
+	{ 0x22,	0x21,	0x23 },
+	{ 0x1e,	0x30,	0x5 },
+	{ 0x1f,	0x22,	0x3d },
+	{ 0x1e,	0x2f,	0xa },
+	{ 0x0,	0x1c,	0xe },
+	{ 0x0,	0x1c,	0x15 },
+	{ 0x0,	0x1c,	0x1c },
+	{ 0x0,	0x15,	0x1c },
+	{ 0x0,	0xe,	0x1c },
+	{ 0x0,	0x7,	0x1c },
+	{ 0xe,	0xe,	0x1c },
+	{ 0x11,	0xe,	0x1c },
+	{ 0x15,	0xe,	0x1c },
+	{ 0x18,	0xe,	0x1c },
+	{ 0x1c,	0xe,	0x1c },
+	{ 0x1c,	0xe,	0x18 },
+	{ 0x1c,	0xe,	0x15 },
+	{ 0x1c,	0xe,	0x11 },
+	{ 0x1c,	0xe,	0xe },
+	{ 0x1c,	0x11,	0xe },
+	{ 0x1c,	0x15,	0xe },
+	{ 0x1c,	0x18,	0xe },
+	{ 0x1c,	0x1c,	0xe },
+	{ 0x18,	0x1c,	0xe },
+	{ 0x15,	0x1c,	0xe },
+	{ 0x11,	0x1c,	0xe },
+	{ 0xe,	0x1c,	0xe },
+	{ 0xe,	0x1c,	0x11 },
+	{ 0xe,	0x1c,	0x15 },
+	{ 0xe,	0x1c,	0x18 },
+	{ 0xe,	0x1c,	0x1c },
+	{ 0xe,	0x18,	0x1c },
+	{ 0xe,	0x15,	0x1c },
+	{ 0xe,	0x11,	0x1c },
+	{ 0x14,	0x14,	0x1c },
+	{ 0x16,	0x14,	0x1c },
+	{ 0x18,	0x14,	0x1c },
+	{ 0x1a,	0x14,	0x1c },
+	{ 0x1c,	0x14,	0x1c },
+	{ 0x1c,	0x14,	0x1a },
+	{ 0x1c,	0x14,	0x18 },
+	{ 0x1c,	0x14,	0x16 },
+	{ 0x1c,	0x14,	0x14 },
+	{ 0x1c,	0x16,	0x14 },
+	{ 0x1c,	0x18,	0x14 },
+	{ 0x1c,	0x1a,	0x14 },
+	{ 0x1c,	0x1c,	0x14 },
+	{ 0x1a,	0x1c,	0x14 },
+	{ 0x18,	0x1c,	0x14 },
+	{ 0x16,	0x1c,	0x14 },
+	{ 0x14,	0x1c,	0x14 },
+	{ 0x14,	0x1c,	0x16 },
+	{ 0x14,	0x1c,	0x18 },
+	{ 0x14,	0x1c,	0x1a },
+	{ 0x14,	0x1c,	0x1c },
+	{ 0x14,	0x1a,	0x1c },
+	{ 0x14,	0x18,	0x1c },
+	{ 0x14,	0x16,	0x1c },
+	{ 0x0,	0x0,	0x10 },
+	{ 0x4,	0x0,	0x10 },
+	{ 0x8,	0x0,	0x10 },
+	{ 0xc,	0x0,	0x10 },
+	{ 0x10,	0x0,	0x10 },
+	{ 0x10,	0x0,	0xc },
+	{ 0x10,	0x0,	0x8 },
+	{ 0x10,	0x0,	0x4 },
+	{ 0x10,	0x0,	0x0 },
+	{ 0x10,	0x4,	0x0 },
+	{ 0x10,	0x8,	0x0 },
+	{ 0x10,	0xc,	0x0 },
+	{ 0x10,	0x10,	0x0 },
+	{ 0xc,	0x10,	0x0 },
+	{ 0x8,	0x10,	0x0 },
+	{ 0x4,	0x10,	0x0 },
+	{ 0x0,	0x10,	0x0 },
+	{ 0x0,	0x10,	0x4 },
+	{ 0x0,	0x10,	0x8 },
+	{ 0x0,	0x10,	0xc },
+	{ 0x0,	0x10,	0x10 },
+	{ 0x0,	0xc,	0x10 },
+	{ 0x0,	0x8,	0x10 },
+	{ 0x0,	0x4,	0x10 },
+	{ 0x8,	0x8,	0x10 },
+	{ 0xa,	0x8,	0x10 },
+	{ 0xc,	0x8,	0x10 },
+	{ 0xe,	0x8,	0x10 },
+	{ 0x10,	0x8,	0x10 },
+	{ 0x10,	0x8,	0xe },
+	{ 0x10,	0x8,	0xc },
+	{ 0x10,	0x8,	0xa },
+	{ 0x10,	0x8,	0x8 },
+	{ 0x10,	0xa,	0x8 },
+	{ 0x10,	0xc,	0x8 },
+	{ 0x10,	0xe,	0x8 },
+	{ 0x10,	0x10,	0x8 },
+	{ 0xe,	0x10,	0x8 },
+	{ 0xc,	0x10,	0x8 },
+	{ 0xa,	0x10,	0x8 },
+	{ 0x8,	0x10,	0x8 },
+	{ 0x8,	0x10,	0xa },
+	{ 0x8,	0x10,	0xc },
+	{ 0x8,	0x10,	0xe },
+	{ 0x8,	0x10,	0x10 },
+	{ 0x8,	0xe,	0x10 },
+	{ 0x8,	0xc,	0x10 },
+	{ 0x8,	0xa,	0x10 },
+	{ 0xb,	0xb,	0x10 },
+	{ 0xc,	0xb,	0x10 },
+	{ 0xd,	0xb,	0x10 },
+	{ 0xf,	0xb,	0x10 },
+	{ 0x10,	0xb,	0x10 },
+	{ 0x10,	0xb,	0xf },
+	{ 0x10,	0xb,	0xd },
+	{ 0x10,	0xb,	0xc },
+	{ 0x10,	0xb,	0xb },
+	{ 0x10,	0xc,	0xb },
+	{ 0x10,	0xd,	0xb },
+	{ 0x10,	0xf,	0xb },
+	{ 0x10,	0x10,	0xb },
+	{ 0xf,	0x10,	0xb },
+	{ 0xd,	0x10,	0xb },
+	{ 0xc,	0x10,	0xb },
+	{ 0xb,	0x10,	0xb },
+	{ 0xb,	0x10,	0xc },
+	{ 0xb,	0x10,	0xd },
+	{ 0xb,	0x10,	0xf },
+	{ 0xb,	0x10,	0x10 },
+	{ 0xb,	0xf,	0x10 },
+	{ 0xb,	0xd,	0x10 },
+	{ 0xb,	0xc,	0x10 },
+	{ 0x0,	0x0,	0x0 },
+	{ 0x0,	0x0,	0x0 },
+	{ 0x0,	0x0,	0x0 },
+	{ 0x0,	0x0,	0x0 },
+	{ 0x0,	0x0,	0x0 },
+	{ 0x0,	0x0,	0x0 },
+	{ 0x0,	0x0,	0x0 }
 };
 
 unsigned char AC[21] = {
@@ -721,7 +719,7 @@
 }
 
 void
-clearVideoMemory()
+clearVideoMemory(void)
 {
 	int i, j;
 	for (i = 0;  i < lines;  i++) {
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/config.in linux/arch/ppc/config.in
--- v2.4.9/linux/arch/ppc/config.in	Wed Jul 25 17:10:18 2001
+++ linux/arch/ppc/config.in	Tue Aug 28 07:11:33 2001
@@ -1,4 +1,4 @@
-# BK Id: SCCS/s.config.in 1.34 07/08/01 11:39:11 trini
+# BK Id: SCCS/s.config.in 1.40 08/24/01 20:31:47 paulus
 #
 # For a description of the syntax of this configuration file,
 # see Documentation/kbuild/config-language.txt.
@@ -26,6 +26,7 @@
 mainmenu_option next_comment
 comment 'Platform support'
 define_bool CONFIG_PPC y
+define_bool CONFIG_PPC32 y
 choice 'Processor Type'	\
 	"6xx/7xx/74xx/8260	CONFIG_6xx	\
 	 4xx			CONFIG_4xx	\
@@ -42,6 +43,11 @@
   define_bool CONFIG_ALL_PPC y
 fi
 
+if [ "$CONFIG_6xx" = "y" -o "$CONFIG_POWER3" = "y" -o \
+     "$CONFIG_POWER4" = "y" ]; then
+  define_bool CONFIG_PPC_STD_MMU y
+fi
+
 if [ "$CONFIG_8260" = "y" ]; then
   define_bool CONFIG_SERIAL_CONSOLE y
   bool 'Support for EST8260' CONFIG_EST8260
@@ -93,7 +99,8 @@
   bool 'Workarounds for PPC601 bugs' CONFIG_PPC601_SYNC_FIX
 fi
 
-if [ "$CONFIG_8xx" = "y" -o "$CONFIG_8260" = "y" ]; then
+if [ "$CONFIG_POWER3" = "n" -a "$CONFIG_POWER4" = "n" -a \
+	"$CONFIG_6xx" = "n" ]; then
   define_bool CONFIG_ALL_PPC n
 fi
 
@@ -104,6 +111,11 @@
 
 if [ "$CONFIG_6xx" = "y" -a "$CONFIG_8260" = "n" ];then
   bool 'AltiVec Support' CONFIG_ALTIVEC
+  bool 'Thermal Management Support' CONFIG_TAU
+  if [ "$CONFIG_TAU" = "y" ]; then
+    bool '    Interrupt driven TAU driver (DANGEROUS)' CONFIG_TAU_INT
+    bool '    Average high and low temp' CONFIG_TAU_AVERAGE
+  fi
 fi
 
 if [ "$CONFIG_4xx" = "y" -o "$CONFIG_8xx" = "y" ]; then
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/configs/IVMS8_defconfig linux/arch/ppc/configs/IVMS8_defconfig
--- v2.4.9/linux/arch/ppc/configs/IVMS8_defconfig	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/configs/IVMS8_defconfig	Tue Aug 28 06:58:33 2001
@@ -21,6 +21,7 @@
 # Platform support
 #
 CONFIG_PPC=y
+CONFIG_PPC32=y
 # CONFIG_6xx is not set
 # CONFIG_4xx is not set
 # CONFIG_POWER3 is not set
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/configs/SM850_defconfig linux/arch/ppc/configs/SM850_defconfig
--- v2.4.9/linux/arch/ppc/configs/SM850_defconfig	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/configs/SM850_defconfig	Tue Aug 28 06:58:33 2001
@@ -21,6 +21,7 @@
 # Platform support
 #
 CONFIG_PPC=y
+CONFIG_PPC32=y
 # CONFIG_6xx is not set
 # CONFIG_4xx is not set
 # CONFIG_POWER3 is not set
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/configs/SPD823TS_defconfig linux/arch/ppc/configs/SPD823TS_defconfig
--- v2.4.9/linux/arch/ppc/configs/SPD823TS_defconfig	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/configs/SPD823TS_defconfig	Tue Aug 28 06:58:33 2001
@@ -21,6 +21,7 @@
 # Platform support
 #
 CONFIG_PPC=y
+CONFIG_PPC32=y
 # CONFIG_6xx is not set
 # CONFIG_4xx is not set
 # CONFIG_POWER3 is not set
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/configs/TQM823L_defconfig linux/arch/ppc/configs/TQM823L_defconfig
--- v2.4.9/linux/arch/ppc/configs/TQM823L_defconfig	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/configs/TQM823L_defconfig	Tue Aug 28 06:58:33 2001
@@ -21,6 +21,7 @@
 # Platform support
 #
 CONFIG_PPC=y
+CONFIG_PPC32=y
 # CONFIG_6xx is not set
 # CONFIG_4xx is not set
 # CONFIG_POWER3 is not set
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/configs/TQM850L_defconfig linux/arch/ppc/configs/TQM850L_defconfig
--- v2.4.9/linux/arch/ppc/configs/TQM850L_defconfig	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/configs/TQM850L_defconfig	Tue Aug 28 06:58:33 2001
@@ -21,6 +21,7 @@
 # Platform support
 #
 CONFIG_PPC=y
+CONFIG_PPC32=y
 # CONFIG_6xx is not set
 # CONFIG_4xx is not set
 # CONFIG_POWER3 is not set
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/configs/TQM860L_defconfig linux/arch/ppc/configs/TQM860L_defconfig
--- v2.4.9/linux/arch/ppc/configs/TQM860L_defconfig	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/configs/TQM860L_defconfig	Tue Aug 28 06:58:33 2001
@@ -21,6 +21,7 @@
 # Platform support
 #
 CONFIG_PPC=y
+CONFIG_PPC32=y
 # CONFIG_6xx is not set
 # CONFIG_4xx is not set
 # CONFIG_POWER3 is not set
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/configs/apus_defconfig linux/arch/ppc/configs/apus_defconfig
--- v2.4.9/linux/arch/ppc/configs/apus_defconfig	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/configs/apus_defconfig	Tue Aug 28 06:58:33 2001
@@ -21,18 +21,21 @@
 # Platform support
 #
 CONFIG_PPC=y
+CONFIG_PPC32=y
 CONFIG_6xx=y
 # CONFIG_4xx is not set
 # CONFIG_POWER3 is not set
 # CONFIG_POWER4 is not set
 # CONFIG_8xx is not set
 # CONFIG_8260 is not set
+CONFIG_PPC_STD_MMU=y
 # CONFIG_ALL_PPC is not set
 CONFIG_APUS=y
 # CONFIG_GEMINI is not set
 # CONFIG_PPC601_SYNC_FIX is not set
 # CONFIG_SMP is not set
 # CONFIG_ALTIVEC is not set
+# CONFIG_TAU is not set
 
 #
 # General setup
@@ -746,8 +749,10 @@
 CONFIG_SOUND=y
 CONFIG_DMASOUND_PAULA=m
 CONFIG_DMASOUND=m
+# CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
 # CONFIG_SOUND_FUSION is not set
 # CONFIG_SOUND_CS4281 is not set
 # CONFIG_SOUND_ES1370 is not set
@@ -756,6 +761,7 @@
 # CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_MAESTRO3 is not set
 # CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
 # CONFIG_SOUND_SONICVIBES is not set
 # CONFIG_SOUND_TRIDENT is not set
 # CONFIG_SOUND_MSNDCLAS is not set
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/configs/bseip_defconfig linux/arch/ppc/configs/bseip_defconfig
--- v2.4.9/linux/arch/ppc/configs/bseip_defconfig	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/configs/bseip_defconfig	Tue Aug 28 06:58:33 2001
@@ -19,6 +19,7 @@
 # Platform support
 #
 CONFIG_PPC=y
+CONFIG_PPC32=y
 # CONFIG_6xx is not set
 # CONFIG_4xx is not set
 # CONFIG_POWER3 is not set
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/configs/common_defconfig linux/arch/ppc/configs/common_defconfig
--- v2.4.9/linux/arch/ppc/configs/common_defconfig	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/configs/common_defconfig	Tue Aug 28 06:58:33 2001
@@ -21,18 +21,23 @@
 # Platform support
 #
 CONFIG_PPC=y
+CONFIG_PPC32=y
 CONFIG_6xx=y
 # CONFIG_4xx is not set
 # CONFIG_POWER3 is not set
 # CONFIG_POWER4 is not set
 # CONFIG_8xx is not set
 # CONFIG_8260 is not set
+CONFIG_PPC_STD_MMU=y
 CONFIG_ALL_PPC=y
 # CONFIG_APUS is not set
 # CONFIG_GEMINI is not set
 CONFIG_PPC601_SYNC_FIX=y
 # CONFIG_SMP is not set
 CONFIG_ALTIVEC=y
+CONFIG_TAU=y
+# CONFIG_TAU_INT is not set
+# CONFIG_TAU_AVERAGE is not set
 
 #
 # General setup
@@ -228,6 +233,7 @@
 CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
+CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
 CONFIG_IDEDMA_PCI_AUTO=y
 CONFIG_BLK_DEV_IDEDMA=y
@@ -237,8 +243,8 @@
 # CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_WDC_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD7409 is not set
-# CONFIG_AMD7409_OVERRIDE is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_AMD74XX_OVERRIDE is not set
 CONFIG_BLK_DEV_CMD64X=y
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
@@ -249,7 +255,8 @@
 # CONFIG_BLK_DEV_OPTI621 is not set
 # CONFIG_BLK_DEV_PDC202XX is not set
 # CONFIG_PDC202XX_BURST is not set
-# CONFIG_BLK_DEV_OSB4 is not set
+# CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_SVWKS is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
@@ -769,8 +776,10 @@
 CONFIG_SOUND=m
 CONFIG_DMASOUND_AWACS=m
 CONFIG_DMASOUND=m
+# CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
 # CONFIG_SOUND_FUSION is not set
 # CONFIG_SOUND_CS4281 is not set
 # CONFIG_SOUND_ES1370 is not set
@@ -779,6 +788,7 @@
 # CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_MAESTRO3 is not set
 # CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
 # CONFIG_SOUND_SONICVIBES is not set
 # CONFIG_SOUND_TRIDENT is not set
 # CONFIG_SOUND_MSNDCLAS is not set
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/configs/est8260_defconfig linux/arch/ppc/configs/est8260_defconfig
--- v2.4.9/linux/arch/ppc/configs/est8260_defconfig	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/configs/est8260_defconfig	Tue Aug 28 06:58:33 2001
@@ -19,16 +19,17 @@
 # Platform support
 #
 CONFIG_PPC=y
+CONFIG_PPC32=y
 CONFIG_6xx=y
 # CONFIG_4xx is not set
 # CONFIG_POWER3 is not set
 # CONFIG_POWER4 is not set
 # CONFIG_8xx is not set
 CONFIG_8260=y
+CONFIG_PPC_STD_MMU=y
 CONFIG_SERIAL_CONSOLE=y
 CONFIG_EST8260=y
 CONFIG_PPC601_SYNC_FIX=y
-# CONFIG_ALL_PPC is not set
 # CONFIG_SMP is not set
 
 #
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/configs/gemini_defconfig linux/arch/ppc/configs/gemini_defconfig
--- v2.4.9/linux/arch/ppc/configs/gemini_defconfig	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/configs/gemini_defconfig	Tue Aug 28 06:58:33 2001
@@ -21,18 +21,23 @@
 # Platform support
 #
 CONFIG_PPC=y
+CONFIG_PPC32=y
 CONFIG_6xx=y
 # CONFIG_4xx is not set
 # CONFIG_POWER3 is not set
 # CONFIG_POWER4 is not set
 # CONFIG_8xx is not set
 # CONFIG_8260 is not set
+CONFIG_PPC_STD_MMU=y
 # CONFIG_ALL_PPC is not set
 # CONFIG_APUS is not set
 CONFIG_GEMINI=y
 # CONFIG_PPC601_SYNC_FIX is not set
 # CONFIG_SMP is not set
 CONFIG_ALTIVEC=y
+CONFIG_TAU=y
+# CONFIG_TAU_INT is not set
+# CONFIG_TAU_AVERAGE is not set
 
 #
 # General setup
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/configs/ibmchrp_defconfig linux/arch/ppc/configs/ibmchrp_defconfig
--- v2.4.9/linux/arch/ppc/configs/ibmchrp_defconfig	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/configs/ibmchrp_defconfig	Tue Aug 28 06:58:33 2001
@@ -21,18 +21,21 @@
 # Platform support
 #
 CONFIG_PPC=y
+CONFIG_PPC32=y
 CONFIG_6xx=y
 # CONFIG_4xx is not set
 # CONFIG_POWER3 is not set
 # CONFIG_POWER4 is not set
 # CONFIG_8xx is not set
 # CONFIG_8260 is not set
+CONFIG_PPC_STD_MMU=y
 CONFIG_ALL_PPC=y
 # CONFIG_APUS is not set
 # CONFIG_GEMINI is not set
 # CONFIG_PPC601_SYNC_FIX is not set
 # CONFIG_SMP is not set
 # CONFIG_ALTIVEC is not set
+# CONFIG_TAU is not set
 
 #
 # General setup
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/configs/mbx_defconfig linux/arch/ppc/configs/mbx_defconfig
--- v2.4.9/linux/arch/ppc/configs/mbx_defconfig	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/configs/mbx_defconfig	Tue Aug 28 06:58:33 2001
@@ -19,6 +19,7 @@
 # Platform support
 #
 CONFIG_PPC=y
+CONFIG_PPC32=y
 # CONFIG_6xx is not set
 # CONFIG_4xx is not set
 # CONFIG_POWER3 is not set
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/configs/oak_defconfig linux/arch/ppc/configs/oak_defconfig
--- v2.4.9/linux/arch/ppc/configs/oak_defconfig	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/configs/oak_defconfig	Tue Aug 28 06:58:33 2001
@@ -21,6 +21,7 @@
 # Platform support
 #
 CONFIG_PPC=y
+CONFIG_PPC32=y
 # CONFIG_6xx is not set
 CONFIG_4xx=y
 # CONFIG_POWER3 is not set
@@ -29,6 +30,7 @@
 CONFIG_OAK=y
 # CONFIG_WALNUT is not set
 CONFIG_PPC601_SYNC_FIX=y
+# CONFIG_ALL_PPC is not set
 # CONFIG_SMP is not set
 # CONFIG_MATH_EMULATION is not set
 
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/configs/power3_defconfig linux/arch/ppc/configs/power3_defconfig
--- v2.4.9/linux/arch/ppc/configs/power3_defconfig	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/configs/power3_defconfig	Tue Aug 28 06:58:33 2001
@@ -21,6 +21,7 @@
 # Platform support
 #
 CONFIG_PPC=y
+CONFIG_PPC32=y
 # CONFIG_6xx is not set
 # CONFIG_4xx is not set
 CONFIG_POWER3=y
@@ -28,6 +29,7 @@
 # CONFIG_8xx is not set
 CONFIG_PPC64BRIDGE=y
 CONFIG_ALL_PPC=y
+CONFIG_PPC_STD_MMU=y
 CONFIG_SMP=y
 # CONFIG_IRQ_ALL_CPUS is not set
 
@@ -640,8 +642,10 @@
 #
 CONFIG_SOUND=y
 # CONFIG_DMASOUND_AWACS is not set
+# CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
 # CONFIG_SOUND_FUSION is not set
 # CONFIG_SOUND_CS4281 is not set
 # CONFIG_SOUND_ES1370 is not set
@@ -650,6 +654,7 @@
 # CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_MAESTRO3 is not set
 # CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
 # CONFIG_SOUND_SONICVIBES is not set
 # CONFIG_SOUND_TRIDENT is not set
 # CONFIG_SOUND_MSNDCLAS is not set
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/configs/rpxcllf_defconfig linux/arch/ppc/configs/rpxcllf_defconfig
--- v2.4.9/linux/arch/ppc/configs/rpxcllf_defconfig	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/configs/rpxcllf_defconfig	Tue Aug 28 06:58:33 2001
@@ -19,6 +19,7 @@
 # Platform support
 #
 CONFIG_PPC=y
+CONFIG_PPC32=y
 # CONFIG_6xx is not set
 # CONFIG_4xx is not set
 # CONFIG_POWER3 is not set
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/configs/rpxlite_defconfig linux/arch/ppc/configs/rpxlite_defconfig
--- v2.4.9/linux/arch/ppc/configs/rpxlite_defconfig	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/configs/rpxlite_defconfig	Tue Aug 28 06:58:33 2001
@@ -19,6 +19,7 @@
 # Platform support
 #
 CONFIG_PPC=y
+CONFIG_PPC32=y
 # CONFIG_6xx is not set
 # CONFIG_4xx is not set
 # CONFIG_POWER3 is not set
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/configs/walnut_defconfig linux/arch/ppc/configs/walnut_defconfig
--- v2.4.9/linux/arch/ppc/configs/walnut_defconfig	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/configs/walnut_defconfig	Tue Aug 28 06:58:33 2001
@@ -21,6 +21,7 @@
 # Platform support
 #
 CONFIG_PPC=y
+CONFIG_PPC32=y
 # CONFIG_6xx is not set
 CONFIG_4xx=y
 # CONFIG_POWER3 is not set
@@ -29,6 +30,7 @@
 # CONFIG_OAK is not set
 CONFIG_WALNUT=y
 CONFIG_PPC601_SYNC_FIX=y
+# CONFIG_ALL_PPC is not set
 # CONFIG_SMP is not set
 # CONFIG_MATH_EMULATION is not set
 
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/defconfig linux/arch/ppc/defconfig
--- v2.4.9/linux/arch/ppc/defconfig	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/defconfig	Tue Aug 28 06:58:33 2001
@@ -21,18 +21,23 @@
 # Platform support
 #
 CONFIG_PPC=y
+CONFIG_PPC32=y
 CONFIG_6xx=y
 # CONFIG_4xx is not set
 # CONFIG_POWER3 is not set
 # CONFIG_POWER4 is not set
 # CONFIG_8xx is not set
 # CONFIG_8260 is not set
+CONFIG_PPC_STD_MMU=y
 CONFIG_ALL_PPC=y
 # CONFIG_APUS is not set
 # CONFIG_GEMINI is not set
 CONFIG_PPC601_SYNC_FIX=y
 # CONFIG_SMP is not set
 CONFIG_ALTIVEC=y
+CONFIG_TAU=y
+# CONFIG_TAU_INT is not set
+# CONFIG_TAU_AVERAGE is not set
 
 #
 # General setup
@@ -228,6 +233,7 @@
 CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
+CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
 CONFIG_IDEDMA_PCI_AUTO=y
 CONFIG_BLK_DEV_IDEDMA=y
@@ -237,8 +243,8 @@
 # CONFIG_AEC62XX_TUNING is not set
 # CONFIG_BLK_DEV_ALI15X3 is not set
 # CONFIG_WDC_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD7409 is not set
-# CONFIG_AMD7409_OVERRIDE is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_AMD74XX_OVERRIDE is not set
 CONFIG_BLK_DEV_CMD64X=y
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
@@ -249,7 +255,8 @@
 # CONFIG_BLK_DEV_OPTI621 is not set
 # CONFIG_BLK_DEV_PDC202XX is not set
 # CONFIG_PDC202XX_BURST is not set
-# CONFIG_BLK_DEV_OSB4 is not set
+# CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_SVWKS is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
@@ -769,8 +776,10 @@
 CONFIG_SOUND=m
 CONFIG_DMASOUND_AWACS=m
 CONFIG_DMASOUND=m
+# CONFIG_SOUND_BT878 is not set
 # CONFIG_SOUND_CMPCI is not set
 # CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
 # CONFIG_SOUND_FUSION is not set
 # CONFIG_SOUND_CS4281 is not set
 # CONFIG_SOUND_ES1370 is not set
@@ -779,6 +788,7 @@
 # CONFIG_SOUND_MAESTRO is not set
 # CONFIG_SOUND_MAESTRO3 is not set
 # CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
 # CONFIG_SOUND_SONICVIBES is not set
 # CONFIG_SOUND_TRIDENT is not set
 # CONFIG_SOUND_MSNDCLAS is not set
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile
--- v2.4.9/linux/arch/ppc/kernel/Makefile	Wed Jul 25 17:10:18 2001
+++ linux/arch/ppc/kernel/Makefile	Tue Aug 28 06:58:33 2001
@@ -1,4 +1,4 @@
-# BK Id: SCCS/s.Makefile 1.24 07/10/01 12:12:22 trini
+# BK Id: SCCS/s.Makefile 1.32 08/24/01 20:07:37 paulus
 #
 #
 # Makefile for the linux kernel.
@@ -29,12 +29,13 @@
 
 O_TARGET := kernel.o
 
-export-objs			:= ppc_ksyms.o prep_setup.o 
+export-objs			:= ppc_ksyms.o prep_setup.o time.o
 
 obj-y				:= entry.o traps.o irq.o idle.o time.o misc.o \
 					process.o signal.o ptrace.o \
 					ppc_htab.o semaphore.o syscalls.o  \
-					align.o setup.o
+					align.o setup.o cputable.o
+obj-$(CONFIG_6xx)		+= l2cr.o
 obj-$(CONFIG_MODULES)		+= ppc_ksyms.o
 obj-$(CONFIG_POWER4)		+= xics.o
 obj-$(CONFIG_PCI)		+= pci.o pci-dma.o
@@ -43,6 +44,7 @@
 obj-$(CONFIG_4xx)		+= ppc4xx_pic.o
 obj-$(CONFIG_OAK)		+= oak_setup.o
 obj-$(CONFIG_WALNUT)		+= walnut_setup.o
+obj-$(CONFIG_TAU)		+= temp.o
 ifeq ($(CONFIG_WALNUT),y)
 obj-$(CONFIG_PCI)		+= galaxy_pci.o
 endif
@@ -71,12 +73,17 @@
 obj-$(CONFIG_GEMINI)		+= gemini_prom.o gemini_pci.o gemini_setup.o \
 					open_pic.o
 obj-$(CONFIG_8260)		+= m8260_setup.o ppc8260_pic.o
+obj-$(CONFIG_BOOTX_TEXT)	+= btext.o
 
+ifeq ($(CONFIG_SMP),y)
+obj-$(CONFIG_ALL_PPC)		+= pmac_smp.o chrp_smp.o
+endif
 
 include $(TOPDIR)/Rules.make
 
 entry.o: entry.S ppc_defs.h
 misc.o: misc.S ppc_defs.h
+l2cr.o: l2cr.S ppc_defs.h
 head.o: head.S ppc_defs.h
 head_4xx.o: head_4xx.S ppc_defs.h
 head_8xx.o: head_8xx.S ppc_defs.h
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/apus_setup.c linux/arch/ppc/kernel/apus_setup.c
--- v2.4.9/linux/arch/ppc/kernel/apus_setup.c	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/kernel/apus_setup.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.apus_setup.c 1.14 07/06/01 09:19:28 trini
+ * BK Id: SCCS/s.apus_setup.c 1.18 08/20/01 15:25:16 paulus
  */
 /*
  *  linux/arch/ppc/kernel/apus_setup.c
@@ -611,32 +611,8 @@
 /*
  * IDE stuff.
  */
-void ide_insw(ide_ioreg_t port, void *buf, int ns);
-void ide_outsw(ide_ioreg_t port, void *buf, int ns);
-void
-apus_ide_insw(ide_ioreg_t port, void *buf, int ns)
-{
-	ide_insw(port, buf, ns);
-}
-
-void
-apus_ide_outsw(ide_ioreg_t port, void *buf, int ns)
-{
-	ide_outsw(port, buf, ns);
-}
-
-int
-apus_ide_default_irq(ide_ioreg_t base)
-{
-        return 0;
-}
-
-ide_ioreg_t
-apus_ide_default_io_base(int index)
-{
-        return 0;
-}
 
+#if 0	/* no longer used  -- paulus */
 void
 apus_ide_fix_driveid(struct hd_driveid *id)
 {
@@ -682,6 +658,7 @@
       }
    }
 }
+#endif /* 0 */
 
 __init
 void apus_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, 
@@ -1039,6 +1016,15 @@
 	return total;
 }
 
+static void __init
+apus_map_io(void)
+{
+	/* Map PPC exception vectors. */
+	io_block_mapping(0xfff00000, 0xfff00000, 0x00020000, _PAGE_KERNEL);
+	/* Map chip and ZorroII memory */
+	io_block_mapping(zTwoBase,   0x00000000, 0x01000000, _PAGE_IO);
+}
+
 __init
 void apus_init_IRQ(void)
 {
@@ -1061,8 +1047,8 @@
 }
 
 __init
-void apus_init(unsigned long r3, unsigned long r4, unsigned long r5,
-	       unsigned long r6, unsigned long r7)
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+		   unsigned long r6, unsigned long r7)
 {
 	extern int parse_bootinfo(const struct bi_record *);
 	extern char _end[];
@@ -1113,6 +1099,7 @@
 	ppc_md.calibrate_decr = apus_calibrate_decr;
 
 	ppc_md.find_end_of_memory = apus_find_end_of_memory;
+	ppc_md.setup_io_mappings = apus_map_io;
 
 	ppc_md.nvram_read_val = NULL;
 	ppc_md.nvram_write_val = NULL;
@@ -1130,14 +1117,7 @@
 #endif
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-        ppc_ide_md.insw = apus_ide_insw;
-        ppc_ide_md.outsw = apus_ide_outsw;
-        ppc_ide_md.default_irq = apus_ide_default_irq;
-        ppc_ide_md.default_io_base = apus_ide_default_io_base;
-        ppc_ide_md.fix_driveid = apus_ide_fix_driveid;
         ppc_ide_md.ide_init_hwif = apus_ide_init_hwif_ports;
-
-        ppc_ide_md.io_base = _IO_BASE;
 #endif		
 }
 
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/btext.c linux/arch/ppc/kernel/btext.c
--- v2.4.9/linux/arch/ppc/kernel/btext.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/btext.c	Tue Aug 28 06:58:33 2001
@@ -0,0 +1,868 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * Procedures for drawing on the screen early on in the boot process.
+ *
+ * Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/version.h>
+
+#include <asm/init.h>
+#include <asm/bootx.h>
+#include <asm/btext.h>
+#include <asm/prom.h>
+#include <asm/page.h>
+#include <asm/mmu.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+
+#define NO_SCROLL
+
+#ifndef NO_SCROLL
+static void scrollscreen(void);
+#endif
+
+static void draw_byte(unsigned char c, long locX, long locY);
+static void draw_byte_32(unsigned char *bits, unsigned long *base, int rb);
+static void draw_byte_16(unsigned char *bits, unsigned long *base, int rb);
+static void draw_byte_8(unsigned char *bits, unsigned long *base, int rb);
+
+static int g_loc_X;
+static int g_loc_Y;
+static int g_max_loc_X;
+static int g_max_loc_Y;
+
+unsigned long disp_BAT[2] __initdata = {0, 0};
+
+#define cmapsz	(16*256)
+
+static unsigned char vga_font[cmapsz];
+
+int boot_text_mapped = 1;
+
+boot_infos_t *disp_bi;
+boot_infos_t fake_bi;
+
+extern char *klimit;
+
+/*
+ * Powermac can use btext_* after boot for xmon,
+ * chrp only uses it during early boot.
+ */
+#ifdef CONFIG_XMON
+#define BTEXT	__pmac
+#define BTDATA	__pmacdata
+#else
+#define BTEXT	__init
+#define BTDATA	__initdata
+#endif /* CONFIG_XMON */
+
+/*
+ * This is called only when we are booted via BootX.
+ */
+void __init
+btext_init(boot_infos_t *bi)
+{
+	unsigned long offset = reloc_offset();
+
+	RELOC(g_loc_X) = 0;
+	RELOC(g_loc_Y) = 0;
+	RELOC(g_max_loc_X) = (bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) / 8;
+	RELOC(g_max_loc_Y) = (bi->dispDeviceRect[3] - bi->dispDeviceRect[1]) / 16;
+	RELOC(disp_bi) = PTRUNRELOC(bi);
+}
+
+void __init
+btext_welcome(boot_infos_t* bi)
+{
+	unsigned long offset = reloc_offset();
+	unsigned long flags;
+	unsigned long pvr;
+	
+	btext_drawstring(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n"));
+	btext_drawstring(RELOC("\nlinked at        : 0x"));
+	btext_drawhex(KERNELBASE);
+	btext_drawstring(RELOC("\nframe buffer at  : 0x"));
+	btext_drawhex((unsigned long)bi->dispDeviceBase);
+	btext_drawstring(RELOC(" (phys), 0x"));
+	btext_drawhex((unsigned long)bi->logicalDisplayBase);
+	btext_drawstring(RELOC(" (log)"));
+	btext_drawstring(RELOC("\nklimit           : 0x"));
+	btext_drawhex((unsigned long)RELOC(klimit));
+	btext_drawstring(RELOC("\nMSR              : 0x"));
+	__asm__ __volatile__ ("mfmsr %0" : "=r" (flags));
+	btext_drawhex(flags);
+	__asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr));
+	pvr >>= 16;
+	if (pvr > 1) {
+	    btext_drawstring(RELOC("\nHID0             : 0x"));
+	    __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags));
+	    btext_drawhex(flags);
+	}
+	if (pvr == 8 || pvr == 12 || pvr == 0x800c) {
+	    btext_drawstring(RELOC("\nICTC             : 0x"));
+	    __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags));
+	    btext_drawhex(flags);
+	}
+	btext_drawstring(RELOC("\n\n"));
+}
+
+/* Calc BAT values for mapping the display and store them
+ * in disp_BAT.  Those values are then used from head.S to map
+ * the display during identify_machine() and MMU_Init()
+ * 
+ * The display is mapped to virtual address 0xD0000000, rather
+ * than 1:1, because some some CHRP machines put the frame buffer
+ * in the region starting at 0xC0000000 (KERNELBASE).
+ * This mapping is temporary and will disappear as soon as the
+ * setup done by MMU_Init() is applied.
+ * 
+ * For now, we align the BAT and then map 8Mb on 601 and 16Mb
+ * on other PPCs. This may cause trouble if the framebuffer
+ * is really badly aligned, but I didn't encounter this case
+ * yet.
+ */
+void __init
+btext_prepare_BAT(void)
+{
+	unsigned long offset = reloc_offset();
+	boot_infos_t* bi = PTRRELOC(RELOC(disp_bi));
+	unsigned long addr = (unsigned long)bi->dispDeviceBase;
+	unsigned long vaddr = KERNELBASE + 0x10000000;
+	unsigned long lowbits;
+
+	if (!RELOC(disp_bi)) {
+		RELOC(boot_text_mapped) = 0;
+		return;
+	}
+	if (PVR_VER(mfspr(PVR)) != 1) {
+		/* 603, 604, G3, G4, ... */
+		lowbits = addr & ~0xFF000000UL;
+		addr &= 0xFF000000UL;
+		RELOC(disp_BAT[0]) = vaddr | (BL_16M<<2) | 2;
+		RELOC(disp_BAT[1]) = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW);		
+	} else {
+		/* 601 */
+		lowbits = addr & ~0xFF800000UL;
+		addr &= 0xFF800000UL;
+		RELOC(disp_BAT[0]) = vaddr | (_PAGE_NO_CACHE | PP_RWXX) | 4;
+		RELOC(disp_BAT[1]) = addr | BL_8M | 0x40;
+	}
+	bi->logicalDisplayBase = (void *) (vaddr + lowbits);
+}
+
+/* This function will enable the early boot text when doing OF booting. This
+ * way, xmon output should work too
+ */
+void __init
+btext_setup_display(int width, int height, int depth, int pitch,
+		    unsigned long address)
+{
+	unsigned long offset = reloc_offset();
+	boot_infos_t* bi;
+
+	RELOC(disp_bi) = &fake_bi;
+	bi = PTRRELOC((&fake_bi));
+	RELOC(g_loc_X) = 0;
+	RELOC(g_loc_Y) = 0;
+	RELOC(g_max_loc_X) = width / 8;
+	RELOC(g_max_loc_Y) = height / 16;
+	bi->logicalDisplayBase = (unsigned char *)address;
+	bi->dispDeviceBase = (unsigned char *)address;
+	bi->dispDeviceRowBytes = pitch;
+	bi->dispDeviceDepth = depth;
+	bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0;
+	bi->dispDeviceRect[2] = width;
+	bi->dispDeviceRect[3] = height;
+}
+
+/* Here's a small text engine to use during early boot
+ * or for debugging purposes
+ * 
+ * todo:
+ * 
+ *  - build some kind of vgacon with it to enable early printk
+ *  - move to a separate file
+ *  - add a few video driver hooks to keep in sync with display
+ *    changes.
+ */
+
+void __openfirmware
+map_boot_text(void)
+{
+	unsigned long base, offset, size;
+	if (disp_bi == 0)
+		return;
+	base = ((unsigned long) disp_bi->dispDeviceBase) & 0xFFFFF000UL;
+	offset = ((unsigned long) disp_bi->dispDeviceBase) - base;
+	size = disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3] + offset
+		+ disp_bi->dispDeviceRect[0];
+	disp_bi->logicalDisplayBase = ioremap(base, size);
+	if (disp_bi->logicalDisplayBase == 0)
+		return;
+	disp_bi->logicalDisplayBase += offset;
+	boot_text_mapped = 1;
+}
+
+/* Calc the base address of a given point (x,y) */
+static unsigned char * BTEXT
+calc_base(boot_infos_t *bi, int x, int y)
+{
+	unsigned char *base;
+
+	base = bi->logicalDisplayBase;
+	if (base == 0)
+		base = bi->dispDeviceBase;
+	base += (x + bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3);
+	base += (y + bi->dispDeviceRect[1]) * bi->dispDeviceRowBytes;
+	return base;
+}
+
+/* Adjust the display to a new resolution */
+void
+btext_update_display(unsigned long phys, int width, int height,
+		     int depth, int pitch)
+{
+	if (disp_bi == 0)
+		return;
+	/* check it's the same frame buffer (within 64MB) */
+	if ((phys ^ (unsigned long)disp_bi->dispDeviceBase) & 0xfc000000) {
+		return;
+	}
+
+	disp_bi->dispDeviceBase = (__u8 *) phys;
+	disp_bi->dispDeviceRect[0] = 0;
+	disp_bi->dispDeviceRect[1] = 0;
+	disp_bi->dispDeviceRect[2] = width;
+	disp_bi->dispDeviceRect[3] = height;
+	disp_bi->dispDeviceDepth = depth;
+	disp_bi->dispDeviceRowBytes = pitch;
+	if (boot_text_mapped) {
+		iounmap(disp_bi->logicalDisplayBase);
+		boot_text_mapped = 0;
+	}
+	map_boot_text();
+	g_loc_X = 0;
+	g_loc_Y = 0;
+	g_max_loc_X = width / 8;
+	g_max_loc_Y = height / 16;
+}
+
+void BTEXT btext_clearscreen(void)
+{
+	unsigned long offset	= reloc_offset();
+	boot_infos_t* bi	= PTRRELOC(RELOC(disp_bi));
+	unsigned long *base	= (unsigned long *)calc_base(bi, 0, 0);
+	unsigned long width 	= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
+					(bi->dispDeviceDepth >> 3)) >> 2;
+	int i,j;
+	
+	for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++)
+	{
+		unsigned long *ptr = base;
+		for(j=width; j; --j)
+			*(ptr++) = 0;
+		base += (bi->dispDeviceRowBytes >> 2);
+	}
+}
+
+__inline__ void dcbst(const void* addr)
+{
+	__asm__ __volatile__ ("dcbst 0,%0" :: "r" (addr));
+}
+
+void BTEXT btext_flushscreen(void)
+{
+	unsigned long offset	= reloc_offset();
+	boot_infos_t* bi	= PTRRELOC(RELOC(disp_bi));
+	unsigned long *base	= (unsigned long *)calc_base(bi, 0, 0);
+	unsigned long width 	= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
+					(bi->dispDeviceDepth >> 3)) >> 2;
+	int i,j;
+	
+	for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++)
+	{
+		unsigned long *ptr = base;
+		for(j=width; j>0; j-=8) {
+			dcbst(ptr);
+			ptr += 8;
+		}
+		base += (bi->dispDeviceRowBytes >> 2);
+	}
+}
+
+#ifndef NO_SCROLL
+static BTEXT void
+scrollscreen(void)
+{
+	unsigned long offset		= reloc_offset();
+	boot_infos_t* bi		= PTRRELOC(RELOC(disp_bi));
+	unsigned long *src		= (unsigned long *)calc_base(bi,0,16);
+	unsigned long *dst		= (unsigned long *)calc_base(bi,0,0);
+	unsigned long width		= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
+						(bi->dispDeviceDepth >> 3)) >> 2;
+	int i,j;
+	
+#ifdef CONFIG_ADB_PMU
+	pmu_suspend();	/* PMU will not shut us down ! */
+#endif
+	for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1] - 16); i++)
+	{
+		unsigned long *src_ptr = src;
+		unsigned long *dst_ptr = dst;
+		for(j=width; j; --j)
+			*(dst_ptr++) = *(src_ptr++);
+		src += (bi->dispDeviceRowBytes >> 2);
+		dst += (bi->dispDeviceRowBytes >> 2);
+	}
+	for (i=0; i<16; i++)
+	{
+		unsigned long *dst_ptr = dst;
+		for(j=width; j; --j)
+			*(dst_ptr++) = 0;
+		dst += (bi->dispDeviceRowBytes >> 2);
+	}
+#ifdef CONFIG_ADB_PMU
+	pmu_resume();	/* PMU will not shut us down ! */
+#endif
+}
+#endif /* ndef NO_SCROLL */
+
+void BTEXT btext_drawchar(char c)
+{
+	unsigned long offset = reloc_offset();
+	int cline = 0, x;
+
+	if (!RELOC(boot_text_mapped))
+		return;
+
+	switch (c) {
+	case '\b':
+		if (RELOC(g_loc_X) > 0)
+			--RELOC(g_loc_X);
+		break;
+	case '\t':
+		RELOC(g_loc_X) = (RELOC(g_loc_X) & -8) + 8;
+		break;
+	case '\r':
+		RELOC(g_loc_X) = 0;
+		break;
+	case '\n':
+		RELOC(g_loc_X) = 0;
+		RELOC(g_loc_Y)++;
+		cline = 1;
+		break;
+	default:
+		draw_byte(c, RELOC(g_loc_X)++, RELOC(g_loc_Y));
+	}
+	if (RELOC(g_loc_X) >= RELOC(g_max_loc_X)) {
+		RELOC(g_loc_X) = 0;
+		RELOC(g_loc_Y)++;
+		cline = 1;
+	}
+#ifndef NO_SCROLL
+	while (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y)) {
+		scrollscreen();
+		RELOC(g_loc_Y)--;
+	}
+#else
+	/* wrap around from bottom to top of screen so we don't
+	   waste time scrolling each line.  -- paulus. */
+	if (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y))
+		RELOC(g_loc_Y) = 0;
+	if (cline) {
+		for (x = 0; x < RELOC(g_max_loc_X); ++x)
+			draw_byte(' ', x, RELOC(g_loc_Y));
+	}
+#endif
+}
+
+void BTEXT
+btext_drawstring(const char *c)
+{
+	unsigned long offset	= reloc_offset();
+
+	if (!RELOC(boot_text_mapped))
+		return;
+	while (*c)
+		btext_drawchar(*c++);
+}
+
+void BTEXT
+btext_drawhex(unsigned long v)
+{
+	static char hex_table[] = "0123456789abcdef";
+	unsigned long offset	= reloc_offset();
+	
+	if (!RELOC(boot_text_mapped))
+		return;
+	btext_drawchar(RELOC(hex_table)[(v >> 28) & 0x0000000FUL]);
+	btext_drawchar(RELOC(hex_table)[(v >> 24) & 0x0000000FUL]);
+	btext_drawchar(RELOC(hex_table)[(v >> 20) & 0x0000000FUL]);
+	btext_drawchar(RELOC(hex_table)[(v >> 16) & 0x0000000FUL]);
+	btext_drawchar(RELOC(hex_table)[(v >> 12) & 0x0000000FUL]);
+	btext_drawchar(RELOC(hex_table)[(v >>  8) & 0x0000000FUL]);
+	btext_drawchar(RELOC(hex_table)[(v >>  4) & 0x0000000FUL]);
+	btext_drawchar(RELOC(hex_table)[(v >>  0) & 0x0000000FUL]);
+	btext_drawchar(' ');
+}
+
+static void BTEXT
+draw_byte(unsigned char c, long locX, long locY)
+{
+	unsigned long offset	= reloc_offset();
+	boot_infos_t* bi	= PTRRELOC(RELOC(disp_bi));
+	unsigned char *base	= calc_base(bi, locX << 3, locY << 4);
+	unsigned char *font	= &RELOC(vga_font)[((unsigned long)c) * 16];
+	int rb			= bi->dispDeviceRowBytes;
+	
+	switch(bi->dispDeviceDepth) {
+	case 32:
+		draw_byte_32(font, (unsigned long *)base, rb);
+		break;
+	case 16:
+		draw_byte_16(font, (unsigned long *)base, rb);
+		break;
+	case 8:
+		draw_byte_8(font, (unsigned long *)base, rb);
+		break;
+	}
+}
+
+static unsigned long expand_bits_8[16] BTDATA = {
+	0x00000000,
+	0x000000ff,
+	0x0000ff00,
+	0x0000ffff,
+	0x00ff0000,
+	0x00ff00ff,
+	0x00ffff00,
+	0x00ffffff,
+	0xff000000,
+	0xff0000ff,
+	0xff00ff00,
+	0xff00ffff,
+	0xffff0000,
+	0xffff00ff,
+	0xffffff00,
+	0xffffffff
+};
+
+static unsigned long expand_bits_16[4] BTDATA = {
+	0x00000000,
+	0x0000ffff,
+	0xffff0000,
+	0xffffffff
+};
+
+
+static void BTEXT
+draw_byte_32(unsigned char *font, unsigned long *base, int rb)
+{
+	int l, bits;	
+	int fg = 0xFFFFFFFFUL;
+	int bg = 0x00000000UL;
+	
+	for (l = 0; l < 16; ++l)
+	{
+		bits = *font++;
+		base[0] = (-(bits >> 7) & fg) ^ bg;
+		base[1] = (-((bits >> 6) & 1) & fg) ^ bg;
+		base[2] = (-((bits >> 5) & 1) & fg) ^ bg;
+		base[3] = (-((bits >> 4) & 1) & fg) ^ bg;
+		base[4] = (-((bits >> 3) & 1) & fg) ^ bg;
+		base[5] = (-((bits >> 2) & 1) & fg) ^ bg;
+		base[6] = (-((bits >> 1) & 1) & fg) ^ bg;
+		base[7] = (-(bits & 1) & fg) ^ bg;
+		base = (unsigned long *) ((char *)base + rb);
+	}
+}
+
+static void BTEXT
+draw_byte_16(unsigned char *font, unsigned long *base, int rb)
+{
+	int l, bits;	
+	int fg = 0xFFFFFFFFUL;
+	int bg = 0x00000000UL;
+	unsigned long offset = reloc_offset();
+	unsigned long *eb = RELOC(expand_bits_16);
+
+	for (l = 0; l < 16; ++l)
+	{
+		bits = *font++;
+		base[0] = (eb[bits >> 6] & fg) ^ bg;
+		base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg;
+		base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg;
+		base[3] = (eb[bits & 3] & fg) ^ bg;
+		base = (unsigned long *) ((char *)base + rb);
+	}
+}
+
+static void BTEXT
+draw_byte_8(unsigned char *font, unsigned long *base, int rb)
+{
+	int l, bits;	
+	int fg = 0x0F0F0F0FUL;
+	int bg = 0x00000000UL;
+	unsigned long offset = reloc_offset();
+	unsigned long *eb = RELOC(expand_bits_8);
+
+	for (l = 0; l < 16; ++l)
+	{
+		bits = *font++;
+		base[0] = (eb[bits >> 4] & fg) ^ bg;
+		base[1] = (eb[bits & 0xf] & fg) ^ bg;
+		base = (unsigned long *) ((char *)base + rb);
+	}
+}
+
+static unsigned char vga_font[cmapsz] BTDATA = {
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 
+0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, 
+0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 
+0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 
+0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
+0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 
+0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 
+0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e, 
+0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 
+0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, 
+0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 
+0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e, 
+0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 
+0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb, 
+0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 
+0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
+0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 
+0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 
+0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 
+0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 
+0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 
+0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 
+0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 
+0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 
+0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
+0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
+0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 
+0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
+0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 
+0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
+0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 
+0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 
+0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 
+0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde, 
+0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 
+0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 
+0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c, 
+0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 
+0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
+0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c, 
+0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 
+0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7, 
+0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 
+0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 
+0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 
+0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
+0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
+0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 
+0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
+0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 
+0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
+0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 
+0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60, 
+0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60, 
+0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 
+0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60, 
+0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 
+0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 
+0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 
+0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 
+0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 
+0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, 
+0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 
+0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
+0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, 
+0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 
+0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 
+0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 
+0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 
+0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 
+0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
+0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, 
+0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 
+0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, 
+0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 
+0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c, 
+0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 
+0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
+0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, 
+0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
+0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 
+0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 
+0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 
+0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 
+0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
+0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
+0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
+0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 
+0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 
+0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 
+0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 
+0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44, 
+0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 
+0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 
+0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 
+0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 
+0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 
+0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
+0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 
+0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 
+0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 
+0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 
+0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 
+0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 
+0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 
+0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 
+0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 
+0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 
+0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
+0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 
+0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 
+};
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/chrp_setup.c linux/arch/ppc/kernel/chrp_setup.c
--- v2.4.9/linux/arch/ppc/kernel/chrp_setup.c	Wed Jul 25 17:10:18 2001
+++ linux/arch/ppc/kernel/chrp_setup.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.chrp_setup.c 1.22 07/18/01 22:56:39 paulus
+ * BK Id: SCCS/s.chrp_setup.c 1.32 08/20/01 22:58:32 paulus
  */
 /*
  *  linux/arch/ppc/kernel/setup.c
@@ -53,6 +53,7 @@
 #include <asm/keyboard.h>
 #include <asm/init.h>
 #include <asm/time.h>
+#include <asm/btext.h>
 
 #include "local_irq.h"
 #include "i8259.h"
@@ -68,7 +69,7 @@
 void chrp_event_scan(void);
 void rtas_display_progress(char *, unsigned short);
 void rtas_indicator_progress(char *, unsigned short);
-void bootx_text_progress(char *, unsigned short);
+void btext_progress(char *, unsigned short);
 
 extern unsigned long pmac_find_end_of_memory(void);
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
@@ -77,16 +78,10 @@
 			   char raw_mode);
 extern char pckbd_unexpected_up(unsigned char keycode);
 extern void pckbd_leds(unsigned char leds);
+extern int pckbd_rate(struct kbd_repeat *rep);
 extern void pckbd_init_hw(void);
 extern unsigned char pckbd_sysrq_xlate[128];
-extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int mackbd_getkeycode(unsigned int scancode);
-extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
-			    char raw_mode);
-extern char mackbd_unexpected_up(unsigned char keycode);
-extern void mackbd_leds(unsigned char leds);
-extern void mackbd_init_hw(void);
-extern unsigned char mackbd_sysrq_xlate[128];
+extern void select_adb_keyboard(void);
 
 extern kdev_t boot_dev;
 
@@ -94,9 +89,13 @@
 extern unsigned long Hash_size, Hash_mask;
 extern int probingmem;
 extern unsigned long loops_per_jiffy;
-extern int bootx_text_mapped;
 static int max_width;
 
+#ifdef CONFIG_SMP
+extern struct smp_ops_t chrp_smp_ops;
+extern struct smp_ops_t xics_smp_ops;
+#endif
+
 static const char *gg2_memtypes[4] = {
 	"FPM", "SDRAM", "EDO", "BEDO"
 };
@@ -248,9 +247,6 @@
 	chrp_find_bridges();
 
 #ifndef CONFIG_PPC64BRIDGE
-	/* PCI bridge config space access area -
-	 * appears to be not in devtree on longtrail. */
-	ioremap(GG2_PCI_CONFIG_BASE, 0x80000);
 	/*
 	 *  Temporary fixes for PCI devices.
 	 *  -- Geert
@@ -259,7 +255,6 @@
 
 #endif /* CONFIG_PPC64BRIDGE */
 
-#ifndef CONFIG_POWER4
 	/* Some IBM machines don't have the hydra -- Cort */
 	if (!OpenPIC_Addr) {
 		struct device_node *root;
@@ -276,7 +271,6 @@
 			OpenPIC_Addr = ioremap(opprop[n-1], 0x40000);
 		}
 	}
-#endif
 
 	/*
 	 *  Fix the Super I/O configuration
@@ -401,9 +395,6 @@
 void __init
 chrp_init2(void)
 {
-#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD)
-	struct device_node *kbd;
-#endif
 #ifdef CONFIG_NVRAM  
 	pmac_nvram_init();
 #endif
@@ -418,87 +409,35 @@
 	if (ppc_md.progress)
 		ppc_md.progress("  Have fun!    ", 0x7777);
 
-#if defined(CONFIG_VT) && defined(CONFIG_ADB_KEYBOARD)
+#if defined(CONFIG_VT) && (defined(CONFIG_ADB_KEYBOARD) || defined(CONFIG_INPUT))
 	/* see if there is a keyboard in the device tree
 	   with a parent of type "adb" */
-	for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next)
-		if (kbd->parent && kbd->parent->type
-		    && strcmp(kbd->parent->type, "adb") == 0)
-			break;
-	if (kbd) {
-		ppc_md.kbd_setkeycode    = mackbd_setkeycode;
-		ppc_md.kbd_getkeycode    = mackbd_getkeycode;
-		ppc_md.kbd_translate     = mackbd_translate;
-		ppc_md.kbd_unexpected_up = mackbd_unexpected_up;
-		ppc_md.kbd_leds          = mackbd_leds;
-		ppc_md.kbd_init_hw       = mackbd_init_hw;
-#ifdef CONFIG_MAGIC_SYSRQ
-		ppc_md.ppc_kbd_sysrq_xlate	 = mackbd_sysrq_xlate;
-		SYSRQ_KEY = 0x69;
-#endif /* CONFIG_MAGIC_SYSRQ */
+	{
+		struct device_node *kbd;
+
+		for (kbd = find_devices("keyboard"); kbd; kbd = kbd->next) {
+			if (kbd->parent && kbd->parent->type
+			    && strcmp(kbd->parent->type, "adb") == 0) {
+				select_adb_keyboard();
+				break;
+			}
+		}
 	}
-#endif /* CONFIG_VT && CONFIG_ADB_KEYBOARD */
+#endif /* CONFIG_VT && (CONFIG_ADB_KEYBOARD || CONFIG_INPUT) */
 }
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
 /*
  * IDE stuff.
  */
-unsigned int chrp_ide_irq = 0;
-int chrp_ide_ports_known = 0;
-ide_ioreg_t chrp_ide_regbase[MAX_HWIFS];
-ide_ioreg_t chrp_idedma_regbase;
-
-void __chrp
-chrp_ide_probe(void)
-{
-        struct pci_dev *pdev = pci_find_device(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, NULL);
-
-        chrp_ide_ports_known = 1;
-
-        if(pdev) {
-                chrp_ide_regbase[0]=pdev->resource[0].start;
-                chrp_ide_regbase[1]=pdev->resource[2].start;
-                chrp_idedma_regbase=pdev->resource[4].start;
-                chrp_ide_irq=pdev->irq;
-        }
-}
 
-void __chrp
-chrp_ide_insw(ide_ioreg_t port, void *buf, int ns)
-{
-	ide_insw(port+_IO_BASE, buf, ns);
-}
-
-void __chrp
-chrp_ide_outsw(ide_ioreg_t port, void *buf, int ns)
-{
-	ide_outsw(port+_IO_BASE, buf, ns);
-}
-
-int __chrp
-chrp_ide_default_irq(ide_ioreg_t base)
-{
-        if (chrp_ide_ports_known == 0)
-	        chrp_ide_probe();
-	return chrp_ide_irq;
-}
-
-ide_ioreg_t __chrp
-chrp_ide_default_io_base(int index)
-{
-        if (chrp_ide_ports_known == 0)
-	        chrp_ide_probe();
-	return chrp_ide_regbase[index];
-}
-
-int __chrp
+static int __chrp
 chrp_ide_check_region(ide_ioreg_t from, unsigned int extent)
 {
         return check_region(from, extent);
 }
 
-void __chrp
+static void __chrp
 chrp_ide_request_region(ide_ioreg_t from,
 			unsigned int extent,
 			const char *name)
@@ -506,14 +445,14 @@
         request_region(from, extent, name);
 }
 
-void __chrp
+static void __chrp
 chrp_ide_release_region(ide_ioreg_t from,
 			unsigned int extent)
 {
         release_region(from, extent);
 }
 
-void __chrp
+static void __chrp
 chrp_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
 {
 	ide_ioreg_t reg = data_port;
@@ -523,20 +462,42 @@
 		hw->io_ports[i] = reg;
 		reg += 1;
 	}
-	if (ctrl_port) {
-		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+	hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+}
+#endif
+
+/*
+ * One of the main thing these mappings are needed for is so that
+ * xmon can get to the serial port early on.  We probably should
+ * handle the machines with the mpc106 as well as the python (F50)
+ * and the GG2 (longtrail).  Actually we should look in the device
+ * tree and do the right thing.
+ */
+static void __init
+chrp_map_io(void)
+{
+	char *name;
+
+	/*
+	 * The code below tends to get removed, please don't take it out.
+	 * The F50 needs this mapping and it you take it out I'll track you
+	 * down and slap your hands.  If it causes problems please email me.
+	 *  -- Cort <cort@fsmlabs.com>
+	 */
+	name = get_property(find_path_device("/"), "name", NULL);
+	if (name && strncmp(name, "IBM-70", 6) == 0
+	    && strstr(name, "-F50")) {
+		io_block_mapping(0x80000000, 0x80000000, 0x10000000, _PAGE_IO);
+		io_block_mapping(0x90000000, 0x90000000, 0x10000000, _PAGE_IO);
+		return;
 	} else {
-		hw->io_ports[IDE_CONTROL_OFFSET] = 0;
+		io_block_mapping(0xf8000000, 0xf8000000, 0x04000000, _PAGE_IO);
 	}
-	if (irq != NULL)
-		hw->irq = chrp_ide_irq;
 }
 
-#endif
-
 void __init
-	   chrp_init(unsigned long r3, unsigned long r4, unsigned long r5,
-		     unsigned long r6, unsigned long r7)
+chrp_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	  unsigned long r6, unsigned long r7)
 {
 #ifdef CONFIG_BLK_DEV_INITRD
 	/* take care of initrd if we have one */
@@ -576,6 +537,7 @@
 	ppc_md.calibrate_decr = chrp_calibrate_decr;
 
 	ppc_md.find_end_of_memory = pmac_find_end_of_memory;
+	ppc_md.setup_io_mappings = chrp_map_io;
 
 #ifdef CONFIG_VT
 	/* these are adjusted in chrp_init2 if we have an ADB keyboard */
@@ -584,6 +546,7 @@
 	ppc_md.kbd_translate     = pckbd_translate;
 	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
 	ppc_md.kbd_leds          = pckbd_leds;
+	ppc_md.kbd_rate_fn	 = pckbd_rate;
 	ppc_md.kbd_init_hw       = pckbd_init_hw;
 #ifdef CONFIG_MAGIC_SYSRQ
 	ppc_md.ppc_kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
@@ -608,22 +571,23 @@
 		}
 	}
 #ifdef CONFIG_BOOTX_TEXT
-	if (ppc_md.progress == NULL && bootx_text_mapped)
-		ppc_md.progress = bootx_text_progress;
+	if (ppc_md.progress == NULL && boot_text_mapped)
+		ppc_md.progress = btext_progress;
 #endif
 
+#ifdef CONFIG_SMP
+#ifndef CONFIG_POWER4
+	ppc_md.smp_ops = &chrp_smp_ops;
+#else
+	ppc_md.smp_ops = &xics_smp_ops;
+#endif /* CONFIG_POWER4 */
+#endif /* CONFIG_SMP */
+
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-        ppc_ide_md.insw = chrp_ide_insw;
-        ppc_ide_md.outsw = chrp_ide_outsw;
-        ppc_ide_md.default_irq = chrp_ide_default_irq;
-        ppc_ide_md.default_io_base = chrp_ide_default_io_base;
         ppc_ide_md.ide_check_region = chrp_ide_check_region;
         ppc_ide_md.ide_request_region = chrp_ide_request_region;
         ppc_ide_md.ide_release_region = chrp_ide_release_region;
-        ppc_ide_md.fix_driveid = ppc_generic_ide_fix_driveid;
         ppc_ide_md.ide_init_hwif = chrp_ide_init_hwif_ports;
-
-        ppc_ide_md.io_base = _IO_BASE;
 #endif
 
 	/*
@@ -668,7 +632,7 @@
 
 #ifdef CONFIG_BOOTX_TEXT
 void
-bootx_text_progress(char *s, unsigned short hex)
+btext_progress(char *s, unsigned short hex)
 {
 	prom_print(s);
 	prom_print("\n");
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/chrp_smp.c linux/arch/ppc/kernel/chrp_smp.c
--- v2.4.9/linux/arch/ppc/kernel/chrp_smp.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/chrp_smp.c	Tue Aug 28 06:58:33 2001
@@ -0,0 +1,149 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * Smp support for CHRP machines.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great
+ * deal of code from the sparc and intel versions.
+ *
+ * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/delay.h>
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+
+#include <asm/ptrace.h>
+#include <asm/atomic.h>
+#include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/hardirq.h>
+#include <asm/softirq.h>
+#include <asm/init.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/smp.h>
+#include <asm/residual.h>
+#include <asm/feature.h>
+#include <asm/time.h>
+
+#include "open_pic.h"
+
+extern unsigned long smp_chrp_cpu_nr;
+
+static int
+smp_chrp_probe(void)
+{
+	if (smp_chrp_cpu_nr > 1)
+		openpic_request_IPIs();
+
+	return smp_chrp_cpu_nr;
+}
+
+static void
+smp_chrp_kick_cpu(int nr)
+{
+	*(unsigned long *)KERNELBASE = nr;
+	asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
+}
+
+static void
+smp_chrp_setup_cpu(int cpu_nr)
+{
+	static atomic_t ready = ATOMIC_INIT(1);
+	static volatile int frozen = 0;
+
+	if (cpu_nr == 0) {
+		/* wait for all the others */
+		while (atomic_read(&ready) < smp_num_cpus)
+			barrier();
+		atomic_set(&ready, 1);
+		/* freeze the timebase */
+		call_rtas("freeze-time-base", 0, 1, NULL);
+		mb();
+		frozen = 1;
+		/* XXX assumes this is not a 601 */
+		set_tb(0, 0);
+		last_jiffy_stamp(0) = 0;
+		while (atomic_read(&ready) < smp_num_cpus)
+			barrier();
+		/* thaw the timebase again */
+		call_rtas("thaw-time-base", 0, 1, NULL);
+		mb();
+		frozen = 0;
+		smp_tb_synchronized = 1;
+	} else {
+		atomic_inc(&ready);
+		while (!frozen)
+			barrier();
+		set_tb(0, 0);
+		last_jiffy_stamp(0) = 0;
+		mb();
+		atomic_inc(&ready);
+		while (frozen)
+			barrier();
+	}
+
+	if (OpenPIC_Addr)
+		do_openpic_setup_cpu();
+}
+
+#ifdef CONFIG_POWER4
+static void
+smp_xics_message_pass(int target, int msg, unsigned long data, int wait)
+{
+	/* for now, only do reschedule messages
+	   since we only have one IPI */
+	if (msg != PPC_MSG_RESCHEDULE)
+		return;
+	for (i = 0; i < smp_num_cpus; ++i) {
+		if (target == MSG_ALL || target == i
+		    || (target == MSG_ALL_BUT_SELF
+			&& i != smp_processor_id()))
+			xics_cause_IPI(i);
+	}
+}
+
+static int
+smp_xics_probe(void)
+{
+	return smp_chrp_cpu_nr;
+}
+
+static void
+smp_xics_setup_cpu(int cpu_nr)
+{
+	if (cpu_nr > 0)
+		xics_setup_cpu();
+}
+#endif /* CONFIG_POWER4 */
+
+/* CHRP with openpic */
+struct smp_ops_t chrp_smp_ops = {
+	smp_openpic_message_pass,
+	smp_chrp_probe,
+	smp_chrp_kick_cpu,
+	smp_chrp_setup_cpu,
+};
+
+#ifdef CONFIG_POWER4
+/* CHRP with new XICS interrupt controller */
+struct smp_ops_t xics_smp_ops = {
+	smp_xics_message_pass,
+	smp_xics_probe,
+	smp_chrp_kick_cpu,
+	smp_xics_setup_cpu,
+};
+#endif /* CONFIG_POWER4 */
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/cputable.c linux/arch/ppc/kernel/cputable.c
--- v2.4.9/linux/arch/ppc/kernel/cputable.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/cputable.c	Tue Aug 28 06:58:33 2001
@@ -0,0 +1,283 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ *  arch/ppc/kernel/cputable.c
+ *
+ *  Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/threads.h>
+#include <linux/init.h>
+#include <asm/cputable.h>
+
+struct cpu_spec* cur_cpu_spec[NR_CPUS];
+
+extern void __setup_cpu_601(int cpu_nr);
+extern void __setup_cpu_603(int cpu_nr);
+extern void __setup_cpu_604(int cpu_nr);
+extern void __setup_cpu_750(int cpu_nr);
+extern void __setup_cpu_7400(int cpu_nr);
+extern void __setup_cpu_7450(int cpu_nr);
+extern void __setup_cpu_power3(int cpu_nr);
+extern void __setup_cpu_power4(int cpu_nr);
+extern void __setup_cpu_8xx(int cpu_nr);
+extern void __setup_cpu_generic(int cpu_nr);
+
+#define CLASSIC_PPC (!defined(CONFIG_8xx) && 	 \
+		     !defined(CONFIG_4xx) && !defined(CONFIG_POWER3) &&  \
+		     !defined(CONFIG_POWER4) && !defined(CONFIG_PPC_ISERIES))
+
+/* This table only contains "desktop" CPUs, it need to be filled with embedded
+ * ones as well...
+ */
+#define COMMON_PPC	(PPC_FEATURE_32 | PPC_FEATURE_HAS_FPU | \
+			 PPC_FEATURE_HAS_MMU)
+
+/* We only set the altivec features if the kernel was compiled with altivec
+ * support
+ */
+#ifdef CONFIG_ALTIVEC
+#define CPU_FTR_ALTIVEC_COMP	CPU_FTR_ALTIVEC
+#else
+#define CPU_FTR_ALTIVEC_COMP	0
+#endif
+
+struct cpu_spec	cpu_specs[] = {
+#if CLASSIC_PPC
+    { 	/* 601 */
+	0xffff0000, 0x00010000, "601",
+	CPU_FTR_601 | CPU_FTR_HPTE_TABLE,
+	COMMON_PPC | PPC_FEATURE_601_INSTR | PPC_FEATURE_UNIFIED_CACHE,
+	32, 32,
+	__setup_cpu_601
+    },
+    {	/* 603 */
+    	0xffff0000, 0x00030000, "603",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB,
+	COMMON_PPC,
+    	32, 32,
+	__setup_cpu_603
+    },
+    {	/* 603e */
+    	0xffff0000, 0x00060000, "603e",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB,
+	COMMON_PPC,
+	32, 32,
+	__setup_cpu_603
+    },
+    {	/* 603ev */
+    	0xffff0000, 0x00070000, "603ev",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB,
+	COMMON_PPC,
+	32, 32,
+	__setup_cpu_603
+    },
+    {	/* 604 */
+    	0xffff0000, 0x00040000, "604",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_604_PERF_MON |
+	CPU_FTR_HPTE_TABLE,
+	COMMON_PPC,
+	32, 32,
+	__setup_cpu_604
+    },
+    {	/* 604e */
+    	0xfffff000, 0x00090000, "604e",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_604_PERF_MON |
+	CPU_FTR_HPTE_TABLE,
+	COMMON_PPC,
+	32, 32,
+	__setup_cpu_604
+    },
+    {	/* 604r */
+    	0xffff0000, 0x00090000, "604r",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_604_PERF_MON |
+	CPU_FTR_HPTE_TABLE,
+	COMMON_PPC,
+	32, 32,
+	__setup_cpu_604
+    },
+    {	/* 604ev */
+    	0xffff0000, 0x000a0000, "604ev",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_604_PERF_MON |
+	CPU_FTR_HPTE_TABLE,
+	COMMON_PPC,
+	32, 32,
+	__setup_cpu_604
+    },
+    {	/* 750 (0x4202, don't support TAU ?) */
+    	0xffffffff, 0x00084202, "750",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
+	CPU_FTR_L2CR | CPU_FTR_HPTE_TABLE,
+	COMMON_PPC,
+	32, 32,
+	__setup_cpu_750
+    },
+    {	/* 750CX */
+    	0xffffff00, 0x00082200, "750CX",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
+	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE,
+	COMMON_PPC,
+	32, 32,
+	__setup_cpu_750
+    },
+    {	/* 740/750 (L2CR bit need fixup for 740) */
+    	0xffff0000, 0x00080000, "740/750",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
+	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_HPTE_TABLE,
+	COMMON_PPC,
+	32, 32,
+	__setup_cpu_750
+    },
+    {	/* 7400 rev 1.1 ? (no TAU) */
+    	0xffffffff, 0x000c1101, "7400 (1.1)",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
+	CPU_FTR_L2CR | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE,
+	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
+	32, 32,
+	__setup_cpu_7400
+    },
+    {	/* 7400 */
+    	0xffff0000, 0x000c0000, "7400",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
+	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE,
+	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
+	32, 32,
+	__setup_cpu_7400
+    },
+    {	/* 7410 */
+    	0xffff0000, 0x800c0000, "7410",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
+	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP | CPU_FTR_HPTE_TABLE,
+	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
+	32, 32,
+	__setup_cpu_7400
+    },
+    {	/* 7450 */
+    	0xffff0000, 0x80000000, "7450",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB |
+	CPU_FTR_L2CR | CPU_FTR_TAU | CPU_FTR_ALTIVEC_COMP |
+	CPU_FTR_HPTE_TABLE | CPU_FTR_SPEC7450,
+	COMMON_PPC | PPC_FEATURE_HAS_ALTIVEC,
+	32, 32,
+	__setup_cpu_7450
+    },
+    {	/* 82xx (8240, 8245, 8260 are all 603e cores) */
+	0xffff0000, 0x00810000, "82xx",
+	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_CAN_DOZE | CPU_FTR_USE_TB,
+	COMMON_PPC,
+	32, 32,
+	__setup_cpu_603
+    },
+    {	/* default match, we assume split I/D cache & TB (non-601)... */
+    	0x00000000, 0x00000000, "(generic PPC)",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE,
+	COMMON_PPC,
+	32, 32,
+	__setup_cpu_generic
+    },
+#endif /* CLASSIC_PPC */    
+#ifdef CONFIG_PPC64BRIDGE
+    {	/* Power3 */
+    	0xffff0000, 0x00400000, "Power3 (630)",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE,
+    	COMMON_PPC | PPC_FEATURE_64,
+	128, 128,
+	__setup_cpu_power3
+    },
+    {	/* Power3+ */
+    	0xffff0000, 0x00410000, "Power3 (630+)",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE,
+    	COMMON_PPC | PPC_FEATURE_64,
+	128, 128,
+	__setup_cpu_power3
+    },
+	{	/* I-star */
+		0xffff0000, 0x00360000, "I-star",
+		CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE,
+		COMMON_PPC | PPC_FEATURE_64,
+		128, 128,
+		__setup_cpu_power3
+	},
+	{	/* S-star */
+		0xffff0000, 0x00370000, "S-star",
+		CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE,
+		COMMON_PPC | PPC_FEATURE_64,
+		128, 128,
+		__setup_cpu_power3
+	},
+#endif /* CONFIG_PPC64BRIDGE */    
+#ifdef CONFIG_POWER4
+    {	/* Power4 */
+    	0xffff0000, 0x00350000, "Power4",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE,
+    	COMMON_PPC | PPC_FEATURE_64,
+	128, 128,
+	__setup_cpu_power4
+    },
+#endif /* CONFIG_POWER4 */    
+#ifdef CONFIG_8xx
+    {	/* 8xx */
+    	0xffff0000, 0x00500000, "8xx",
+		/* CPU_FTR_CAN_DOZE is possible, if the 8xx code is there.... */
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB,
+    	PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+ 	16, 16,
+	0, __setup_cpu_8xx
+    },
+#endif /* CONFIG_8xx */
+#ifdef CONFIG_4xx
+    {	/* 403GC */
+    	0xffffff00, 0x00200200, "403GC",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB,
+    	PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+	16, 16,
+	0, /*__setup_cpu_403 */
+    },
+    {	/* 403GCX */
+    	0xffffff00, 0x00201400, "403GCX",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB,
+    	PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+	16, 16,
+	0, /*__setup_cpu_403 */
+    },
+    {	/* 403G ?? */
+    	0xffff0000, 0x00200000, "403G ??",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB,
+    	PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+	16, 16,
+	0, /*__setup_cpu_403 */
+    },
+    {	/* 405GP */
+    	0xffff0000, 0x40110000, "405GP",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB,
+    	PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+	32, 32,
+	0, /*__setup_cpu_405 */
+    },
+    {	/* STB 03xxx */
+    	0xffff0000, 0x40130000, "STB03xxx",
+    	CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB,
+    	PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_4xxMAC,
+	32, 32,
+	0, /*__setup_cpu_405 */
+    },
+#endif /* CONFIG_4xx */
+#if !CLASSIC_PPC
+    {	/* default match */
+    	0x00000000, 0x00000000, "(generic PPC)",
+    	0,
+    	PPC_FEATURE_32,
+	32, 32,
+	0,
+    }
+#endif /* !CLASSIC_PPC */
+};
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/entry.S linux/arch/ppc/kernel/entry.S
--- v2.4.9/linux/arch/ppc/kernel/entry.S	Wed Jul 25 17:10:18 2001
+++ linux/arch/ppc/kernel/entry.S	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.entry.S 1.20 07/19/01 23:02:48 paulus
+ * BK Id: SCCS/s.entry.S 1.22 08/15/01 22:43:06 paulus
  */
 /*
  *  PowerPC version 
@@ -23,12 +23,14 @@
  */
 
 #include "ppc_asm.h"
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sys.h>
+#include <linux/threads.h>
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/mmu.h>
-#include <linux/errno.h>
-#include <linux/sys.h>
-#include <linux/config.h>
+#include <asm/cputable.h>
 
 #undef SHOW_SYSCALLS
 #undef SHOW_SYSCALLS_TASK
@@ -217,7 +219,9 @@
 	mfmsr	r22
 	li	r0,MSR_FP	/* Disable floating-point */
 #ifdef CONFIG_ALTIVEC
-	oris	r0,r0,MSR_VEC@h
+BEGIN_FTR_SECTION
+	oris	r0,r0,MSR_VEC@h	/* Disable altivec */
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #endif /* CONFIG_ALTIVEC */
 	andc	r22,r22,r0
 	mtmsr	r22
@@ -238,21 +242,6 @@
 	tophys(r0,r4)
 	CLR_TOP32(r0)
 	mtspr	SPRG3,r0	/* Update current THREAD phys addr */
-#ifdef CONFIG_8xx
-	/* XXX it would be nice to find a SPRGx for this on 6xx,7xx too */
-	lwz	r9,PGDIR(r4)	/* cache the page table root */
-        tophys(r9,r9)		/* convert to phys addr */
-#ifdef CONFIG_8xx_CPU6
-	lis	r6, cpu6_errata_word@h
-	ori	r6, r6, cpu6_errata_word@l
-	li	r5, 0x3980
-	stw	r5, 8(r6)
-	lwz	r5, 8(r6)
-#endif
-        mtspr   M_TWB,r9	/* Update MMU base address */
-	tlbia
-	sync
-#endif /* CONFIG_8xx */
 	lwz	r1,KSP(r4)	/* Load new stack pointer */
 	/* save the old current 'last' for return value */
 	mr	r3,r2
@@ -328,19 +317,16 @@
 	andi.	r0,r0,MSR_PR
 	beq+	1f
 #ifdef CONFIG_ALTIVEC
-	mfpvr	r8			/* check if we are on a G4 */
-	srwi	r8,r8,16
-	cmpwi	r8,PVR_7400@h
-	bne	2f
+BEGIN_FTR_SECTION
 	lwz	r0,THREAD+THREAD_VRSAVE(r2)
-	mtspr	SPRN_VRSAVE,r0		/* if so, restore VRSAVE reg */
-2:
+	mtspr	SPRN_VRSAVE,r0		/* if G4, restore VRSAVE reg */
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #endif /* CONFIG_ALTIVEC */
 	addi	r0,r1,INT_FRAME_SIZE	/* size of frame */
 	stw	r0,THREAD+KSP(r2)	/* save kernel stack pointer */
 	tophys(r8,r1)
 	CLR_TOP32(r8)
-	mtspr	SPRG2,r8		/* phys exception stack pointer */	
+	mtspr	SPRG2,r8		/* phys exception stack pointer */
 1:
 	lwz	r3,_CTR(r1)
 	lwz	r0,_LINK(r1)
@@ -348,15 +334,32 @@
 	mtlr	r0
 	REST_4GPRS(3, r1)
 	REST_2GPRS(7, r1)
+
+	/* We have to "dummy" load from the context save area in case
+	 * these instructions cause an MMU fault.  If this happens
+	 * after we load SRR0/SRR1, our return context is hosed.  -- Dan
+	 */
+	lwz	r0,GPR0(r1)
+	lwz	r0,GPR2(r1)
+	lwz	r0,GPR1(r1)
+
+	/* We re-use r3,r4 here (the load above was to cause the MMU
+	 * fault if necessary).  Using r3,r4 removes the need to "dummy"
+	 * load the CCR and NIP.  Since we load them we may as well
+	 * use them.
+	 */
+	lwz	r3,_CCR(r1)
+	lwz	r4,_NIP(r1)
+
 	lwz	r0,_MSR(r1)
 	FIX_SRR1(r0,r2)
 	mtspr	SRR1,r0
-	lwz	r2,_CCR(r1)
-	mtcrf	0xFF,r2
-	lwz	r2,_NIP(r1)
-	mtspr	SRR0,r2
+	mtcrf	0xFF,r3
+	mtspr	SRR0,r4
 	lwz	r0,GPR0(r1)
 	lwz	r2,GPR2(r1)
+	lwz	r3,GPR3(r1)
+	lwz	r4,GPR4(r1)
 	lwz	r1,GPR1(r1)
 	SYNC
 	RFI
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/feature.c linux/arch/ppc/kernel/feature.c
--- v2.4.9/linux/arch/ppc/kernel/feature.c	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/kernel/feature.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.feature.c 1.16 07/06/01 14:42:47 trini
+ * BK Id: SCCS/s.feature.c 1.19 08/19/01 22:23:04 paulus
  */
 /*
  *  arch/ppc/kernel/feature.c
@@ -38,11 +38,15 @@
 #define FREG(c,r)			(&(((c)->reg)[(r)>>2]))
 
 /* Keylargo reg. access. */
-#define KL_FCR(r)	(keylargo_base + ((r) >> 2))
-#define KL_IN(r)	(in_le32(KL_FCR(r)))
-#define KL_OUT(r,v)	(out_le32(KL_FCR(r), (v)))
-#define KL_BIS(r,v)	(KL_OUT((r), KL_IN(r) | (v)))
-#define KL_BIC(r,v)	(KL_OUT((r), KL_IN(r) & ~(v)))
+#define KL_FCR(r)		(keylargo_base + ((r) >> 2))
+#define KL_IN(r)		(in_le32(KL_FCR(r)))
+#define KL_OUT(r,v)		(out_le32(KL_FCR(r), (v)))
+#define KL_BIS(r,v)		(KL_OUT((r), KL_IN(r) | (v)))
+#define KL_BIC(r,v)		(KL_OUT((r), KL_IN(r) & ~(v)))
+#define KL_GPIO_IN(r)		(in_8(((volatile u8 *)keylargo_base)+(r)))
+#define KL_GPIO_OUT(r,v)	(out_8(((volatile u8 *)keylargo_base)+(r), (v)))
+#define KL_LOCK()		spin_lock_irqsave(&keylargo->lock, flags)
+#define KL_UNLOCK()		spin_unlock_irqrestore(&keylargo->lock, flags)
 
 /* Uni-N reg. access. Note that Uni-N regs are big endian */
 #define UN_REG(r)	(uninorth_base + ((r) >> 2))
@@ -259,15 +263,29 @@
 static int				uninorth_rev;
 static int				keylargo_rev;
 static u32				board_features;
-static u8				airport_pwr_regs[5];
 static int				airport_pwr_state;
 static struct device_node*		airport_dev;
+static struct device_node*		uninorth_fw;
 
+/* Feature bits for Apple motherboards */
 #define FTR_NEED_OPENPIC_TWEAK		0x00000001
 #define FTR_CAN_NAP			0x00000002
 #define FTR_HAS_FW_POWER		0x00000004
 #define FTR_CAN_SLEEP			0x00000008
 
+/* This table currently lacks most oldworld machines, but
+ * they currently don't need it so...
+ * 
+ * Todo: The whole feature_xxx mecanism need to be redone
+ * some way to be able to handle the new kind of features
+ * exposed by core99. At this point, the main "tables" will
+ * probably be in this table, which will have to be filled with
+ * all known machines
+ */
+/* Warning: Don't change ordering of entries as some machines
+ * adverstise beeing compatible with several models. In those
+ * case, the "highest" has to be first
+ */
 static struct board_features_t {
 	char*	compatible;
 	u32	features;
@@ -283,17 +301,21 @@
   {	"PowerMac3,1",		FTR_NEED_OPENPIC_TWEAK		}, /* Sawtooth (G4) */
   {	"PowerMac3,2",		0				}, /* G4/Dual G4 */
   {	"PowerMac3,3",		FTR_NEED_OPENPIC_TWEAK		}, /* G4/Dual G4 */
-  {	"PowerMac5,1",		0				}, /* Cube */
+  {	"PowerMac3,4",		0				}, /* QuickSilver G4 */
+  {	"PowerMac3,5",		0				}, /* QuickSilver G4 */
+  {	"PowerMac5,1",		FTR_CAN_NAP			}, /* Cube */
   {	"AAPL,3400/2400",	FTR_CAN_SLEEP			}, /* 2400/3400 PowerBook */
   {	"AAPL,3500",		FTR_CAN_SLEEP			}, /* 3500 PowerBook (G3) */
   {	"AAPL,PowerBook1998",	FTR_CAN_SLEEP			}, /* Wallstreet PowerBook */
   {	"PowerBook1,1",		FTR_CAN_SLEEP			}, /* 101 (Lombard) PowerBook */
+  {	"PowerBook4,1",		FTR_CAN_NAP|FTR_CAN_SLEEP|	   /* New polycarbonate iBook */
+  				0/*FTR_HAS_FW_POWER*/		}, 
   {	"PowerBook2,1",		FTR_CAN_SLEEP 			}, /* iBook */
-  {	"PowerBook4,1",		FTR_CAN_NAP|FTR_CAN_SLEEP	}, /* iBook Dual USB */
   {	"PowerBook2,2",		FTR_CAN_SLEEP /*| FTR_CAN_NAP*/	}, /* iBook FireWire */
   {	"PowerBook3,1",		FTR_CAN_SLEEP|FTR_CAN_NAP|	   /* PowerBook 2000 (Pismo) */
   				FTR_HAS_FW_POWER		}, 
-  {	"PowerBook3,2",		FTR_CAN_NAP|FTR_CAN_SLEEP	}, /* PowerBook Titanium */
+  {	"PowerBook3,2",		FTR_CAN_NAP|FTR_CAN_SLEEP|	   /* PowerBook Titanium */
+  				0/*FTR_HAS_FW_POWER*/		},
   {	NULL, 0 }
 };
 
@@ -305,15 +327,25 @@
 	struct device_node *np;
 	u32 *rev;
 	int i;
-
+	char* model;
+	
 	if (_machine != _MACH_Pmac)
 		return;
 
-	/* Figure out motherboard type & options */
-	for(i=0;board_features_datas[i].compatible;i++) {
-		if (machine_is_compatible(board_features_datas[i].compatible)) {
-			board_features = board_features_datas[i].features;
-			break;
+	np = find_path_device("/");
+	if (!np) {
+		printk(KERN_ERR "feature.c: Can't find device-tree root !\n");
+		return;
+	}
+	model = (char*)get_property(np, "model", NULL);
+	if (model) {
+		printk("PowerMac model: %s\n", model);
+		/* Figure out motherboard type & options */
+		for(i=0;board_features_datas[i].compatible;i++) {
+			if (!strcmp(board_features_datas[i].compatible, model)) {
+				board_features = board_features_datas[i].features;
+				break;
+			}
 		}
 	}
 
@@ -382,8 +414,9 @@
 		printk("Uninorth at 0x%08x\n", np->addrs[0].address);
 	}
 	if (uninorth_base && keylargo_base)
-		printk("Uni-N revision: %d, KeyLargo revision: %d\n",
-			uninorth_rev, keylargo_rev);
+		printk("Uni-N revision: %d, KeyLargo revision: %d %s\n",
+			uninorth_rev, keylargo_rev,
+			(keylargo_rev & KL_PANGEA_REV) ? "(Pangea chipset)" : "");
 
 	if (uninorth_base)
 		uninorth_init();
@@ -402,6 +435,25 @@
 		feature_clear(controllers[0].device, FEATURE_Sound_CLK_enable);
 	}
 #endif
+
+#ifdef CONFIG_PMAC_PBOOK
+	/* On PowerBooks, we disable the serial ports by default, they
+	 * will be re-enabled by the driver
+	 */
+#ifndef CONFIG_XMON
+	if (controller_count && find_devices("via-pmu") != NULL) {
+		feature_set_modem_power(NULL, 0);
+		feature_clear(controllers[0].device, FEATURE_Serial_IO_A);
+		feature_clear(controllers[0].device, FEATURE_Serial_IO_B);
+		feature_clear(controllers[0].device, FEATURE_Serial_enable);
+		if (controller_count > 1) {
+			feature_clear(controllers[1].device, FEATURE_Serial_IO_A);
+			feature_clear(controllers[1].device, FEATURE_Serial_IO_B);
+			feature_clear(controllers[1].device, FEATURE_Serial_enable);
+		}
+	}
+#endif
+#endif
 }
 
 static struct feature_controller __init *
@@ -588,12 +640,16 @@
 	/* TODO: Handle save/restore of PCI config space here
 	 */
 
-	spin_lock_irqsave(&keylargo->lock, flags);
+	/* XXX We use the keylargo spinlock, but we never
+	 * have uninorth without keylargo, so...
+	 */
+	KL_LOCK();
 	if (power)
 		UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
 	else
 		UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);
-	spin_unlock_irqrestore(&keylargo->lock, flags);
+	(void)UN_IN(UNI_N_CLOCK_CNTL);
+	KL_UNLOCK();
 	udelay(20);
 }
 
@@ -605,17 +661,16 @@
 	if (!keylargo_base || !keylargo)
 		return;
 		
-	spin_lock_irqsave(&keylargo->lock, flags);
-	out_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET),
-		KEYLARGO_GPIO_OUTPUT_ENABLE);
-	(void)in_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET));
-	spin_unlock_irqrestore(&keylargo->lock, flags);
+	KL_LOCK();
+	KL_GPIO_OUT(KL_GPIO_ETH_PHY_RESET, KEYLARGO_GPIO_OUTPUT_ENABLE);
+	(void)KL_GPIO_IN(KL_GPIO_ETH_PHY_RESET);
+	KL_UNLOCK();
 	mdelay(10);
-	spin_lock_irqsave(&keylargo->lock, flags);
-	out_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET),
+	KL_LOCK();
+	KL_GPIO_OUT(KL_GPIO_ETH_PHY_RESET,
 		KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
-	(void)in_8((volatile u8 *)KL_FCR(KL_GPIO_ETH_PHY_RESET));
-	spin_unlock_irqrestore(&keylargo->lock, flags);
+	(void)KL_GPIO_IN(KL_GPIO_ETH_PHY_RESET);
+	KL_UNLOCK();
 	mdelay(10);
 }
 
@@ -642,17 +697,23 @@
 	else
 		return;
 
-	spin_lock_irqsave(&keylargo->lock, flags);
+	KL_LOCK();
 	if (power) {
 		/* Turn ON */
 			
 		if (number == 0) {
 			KL_BIC(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
+			(void)KL_IN(KEYLARGO_FCR0);
+			KL_UNLOCK();
 			mdelay(1);
+			KL_LOCK();
 			KL_BIS(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
 		} else {
 			KL_BIC(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
+			KL_UNLOCK();
+			(void)KL_IN(KEYLARGO_FCR0);
 			mdelay(1);
+			KL_LOCK();
 			KL_BIS(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
 		}
 		reg = KL_IN(KEYLARGO_FCR4);
@@ -689,7 +750,7 @@
 		}
 		udelay(1);
 	}
-	spin_unlock_irqrestore(&keylargo->lock, flags);
+	KL_UNLOCK();
 }
 
 void  __pmac
@@ -697,18 +758,25 @@
 {
 	unsigned long flags;
 
-	/* TODO: Handle save/restore of PCI config space here
+	/* TODO: should probably handle save/restore of PCI config space here
 	 */
 		
+	if (!uninorth_fw || (device && uninorth_fw != device))
+		return;
 	if (!uninorth_base)
 		return;
-	spin_lock_irqsave(&keylargo->lock, flags);
+
+	/* XXX We use the keylargo spinlock, but we never
+	 * have uninorth without keylargo, so...
+	 */
+	KL_LOCK();
 	if (power)
 		UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW);
 	else
 		UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW);
+	(void)UN_IN(UNI_N_CLOCK_CNTL);
+	KL_UNLOCK();
 	udelay(20);
-	spin_unlock_irqrestore(&keylargo->lock, flags);
 }
 
 /* Warning: will kill the PHY.. */
@@ -717,79 +785,159 @@
 {
 	unsigned long flags;
 	u8 gpioValue = power ? 0 : 4;
-	
+
+	if (!uninorth_fw || (device && uninorth_fw != device))
+		return;
 	if (!keylargo_base || !(board_features & FTR_HAS_FW_POWER))
 		return;
-	spin_lock_irqsave(&keylargo->lock, flags);
-	out_8((volatile u8 *)KL_FCR(KL_GPIO_FW_CABLE_POWER), gpioValue);
-	(void)in_8((volatile u8 *)KL_FCR(KL_GPIO_FW_CABLE_POWER));
-	spin_unlock_irqrestore(&keylargo->lock, flags);		
+	KL_LOCK();
+	KL_GPIO_OUT(KL_GPIO_FW_CABLE_POWER, gpioValue);
+	(void)KL_GPIO_IN(KL_GPIO_FW_CABLE_POWER);
+	KL_UNLOCK();		
+}
+
+void
+feature_set_modem_power(struct device_node* device, int power)
+{
+	unsigned long flags;
+
+	if (!device) {
+		device = find_devices("ch-a");
+		while(device && !device_is_compatible(device, "cobalt"))
+			device = device->next;
+		if (!device)
+			return;
+	}
+	if (keylargo && (keylargo_rev & KL_PANGEA_REV)) {
+		KL_LOCK();
+		if (power) {
+			/* Assert modem reset */
+			KL_GPIO_OUT(KL_GPIO_MODEM_RESET, KEYLARGO_GPIO_OUTPUT_ENABLE);
+			(void)KL_GPIO_IN(KL_GPIO_MODEM_RESET);
+			udelay(10);
+			/* Power up modem */
+			KL_GPIO_OUT(KL_GPIO_MODEM_POWER, KEYLARGO_GPIO_OUTPUT_ENABLE);
+			(void)KL_GPIO_IN(KL_GPIO_MODEM_POWER);
+			udelay(10);
+			/* Release modem reset */
+			KL_GPIO_OUT(KL_GPIO_MODEM_RESET,
+				KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
+			(void)KL_GPIO_IN(KL_GPIO_MODEM_RESET);
+		} else {
+			/* Power down modem */
+			KL_GPIO_OUT(KL_GPIO_MODEM_POWER,
+				KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
+			(void)KL_GPIO_IN(KL_GPIO_MODEM_POWER);
+		}
+		KL_UNLOCK();
+	} else {
+		if (power) {
+			mdelay(300);
+			feature_set(device, FEATURE_Modem_power);
+	   		mdelay(5);
+			feature_clear(device, FEATURE_Modem_power);
+	   		mdelay(10);
+			feature_set(device, FEATURE_Modem_power);
+		} else {
+			feature_clear(device, FEATURE_Modem_power);
+			mdelay(10);
+		}
+	}
 }
 
 #ifdef CONFIG_SMP
 void __pmac
 feature_core99_kick_cpu(int cpu_nr)
 {
-#if 1 /* New way */
 	const int reset_lines[] = {	KL_GPIO_RESET_CPU0,
 					KL_GPIO_RESET_CPU1,
 					KL_GPIO_RESET_CPU2,
 					KL_GPIO_RESET_CPU3 };
-	volatile u8* reset_io;
-
+	int reset_io;
+	unsigned long flags;
+	
 	if (!keylargo_base || cpu_nr > 3)
 		return;
-	reset_io = (volatile u8*)KL_FCR(reset_lines[cpu_nr]);
-	out_8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);
-	udelay(1);
-	out_8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
-#else
-	out_8((volatile u8 *)KL_FCR(KL_GPIO_EXTINT_CPU1), KL_GPIO_EXTINT_CPU1_ASSERT);
+	reset_io = reset_lines[cpu_nr];
+	
+	KL_LOCK();
+	KL_GPIO_OUT(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);
+	(void)KL_GPIO_IN(reset_io);
 	udelay(1);
-	out_8((volatile u8 *)KL_FCR(KL_GPIO_EXTINT_CPU1), KL_GPIO_EXTINT_CPU1_RELEASE);
-#endif	
+	KL_GPIO_OUT(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);
+	(void)KL_GPIO_IN(reset_io);
+	KL_UNLOCK();
 }
 #endif /* CONFIG_SMP */
 
 void __pmac
 feature_set_airport_power(struct device_node* device, int power)
 {
+	unsigned long flags;
+	
 	if (!keylargo_base || !airport_dev || airport_dev != device)
 		return;
 	if (airport_pwr_state == power)
-		return;
+		return;	
 	if (power) {
-		/* Some if this is from Darwin code, some is from tracing of
-		 * MacOS driver with Macsbug. Some real bit definitions would
-		 * really help here...
+		/* This code is a reproduction of OF enable-cardslot
+		 * and init-wireless methods, slightly hacked until
+		 * I got it working.
 		 */
-		out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_0), airport_pwr_regs[0]);
-		out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_1), airport_pwr_regs[1]);
-		out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_2), airport_pwr_regs[2]);
-		out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_3), airport_pwr_regs[3]);
-		out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_4), airport_pwr_regs[4]);
-		udelay(20);
-		out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_4), 5);
-		udelay(20);
-		out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_4), 4);
-		mdelay(20);
+		KL_LOCK();
+		KL_GPIO_OUT(KEYLARGO_GPIO_0+0xf, 5);
+		(void)KL_GPIO_IN(KEYLARGO_GPIO_0+0xf);
+		KL_UNLOCK();
+		mdelay(10);
+		KL_LOCK();
+		KL_GPIO_OUT(KEYLARGO_GPIO_0+0xf, 4);
+		(void)KL_GPIO_IN(KEYLARGO_GPIO_0+0xf);
+		KL_UNLOCK();
+
+		mdelay(10);
+
+		KL_LOCK();
 		KL_BIC(KEYLARGO_FCR2, KL2_AIRPORT_RESET_N);
+		(void)KL_IN(KEYLARGO_FCR2);
+		udelay(10);
+		KL_GPIO_OUT(KEYLARGO_GPIO_EXTINT_0+0xb, 0);
+		(void)KL_GPIO_IN(KEYLARGO_GPIO_EXTINT_0+0xb);
+		udelay(10);
+		KL_GPIO_OUT(KEYLARGO_GPIO_EXTINT_0+0xa, 0x28);
+		(void)KL_GPIO_IN(KEYLARGO_GPIO_EXTINT_0+0xa);
+		udelay(10);
+		KL_GPIO_OUT(KEYLARGO_GPIO_EXTINT_0+0xd, 0x28);
+		(void)KL_GPIO_IN(KEYLARGO_GPIO_EXTINT_0+0xd);
+		udelay(10);
+		KL_GPIO_OUT(KEYLARGO_GPIO_0+0xd, 0x28);
+		(void)KL_GPIO_IN(KEYLARGO_GPIO_0+0xd);
+		udelay(10);
+		KL_GPIO_OUT(KEYLARGO_GPIO_0+0xe, 0x28);
+		(void)KL_GPIO_IN(KEYLARGO_GPIO_0+0xe);
+		KL_UNLOCK();
 		udelay(10);
+		KL_OUT(0x1c000, 0);
+		
+		mdelay(1);
 		out_8((volatile u8*)KL_FCR(0x1a3e0), 0x41);
+		(void)in_8((volatile u8*)KL_FCR(0x1a3e0));
 		udelay(10);
+		KL_LOCK();
 		KL_BIS(KEYLARGO_FCR2, KL2_AIRPORT_RESET_N);
-		udelay(10);
+		(void)KL_IN(KEYLARGO_FCR2);
+		KL_UNLOCK();
+		mdelay(100);
 	} else {
-		airport_pwr_regs[0] = in_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_0));
-		airport_pwr_regs[1] = in_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_1));
-		airport_pwr_regs[2] = in_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_2));
-		airport_pwr_regs[3] = in_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_3));
-		airport_pwr_regs[4] = in_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_4));
-		out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_0), 0);
-		out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_1), 0);
-		out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_2), 0);
-		out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_3), 0);
-		out_8((volatile u8*)KL_FCR(KL_GPIO_AIRPORT_4), 0);
+		KL_LOCK();
+		KL_BIC(KEYLARGO_FCR2, KL2_AIRPORT_RESET_N);
+		(void)KL_IN(KEYLARGO_FCR2);
+		KL_GPIO_OUT(KL_GPIO_AIRPORT_0, 0);
+		KL_GPIO_OUT(KL_GPIO_AIRPORT_1, 0);
+		KL_GPIO_OUT(KL_GPIO_AIRPORT_2, 0);
+		KL_GPIO_OUT(KL_GPIO_AIRPORT_3, 0);
+		KL_GPIO_OUT(KL_GPIO_AIRPORT_4, 0);
+		(void)KL_GPIO_IN(KL_GPIO_AIRPORT_4);
+		KL_UNLOCK();
 	}
 	airport_pwr_state = power;	
 }
@@ -826,8 +974,11 @@
 	/* Enable FW before PCI probe. Will be disabled later on
 	 */
 	fw = find_devices("firewire");
-	if (fw && device_is_compatible(fw, "pci106b,18"))
+	if (fw && (device_is_compatible(fw, "pci106b,18") || 
+			device_is_compatible(fw, "pci106b,30"))) {
+		uninorth_fw = fw;
 		feature_set_firewire_power(fw, 1);
+	}
 }
 
 /* Initialize the Core99 KeyLargo ASIC. 
@@ -864,7 +1015,7 @@
 		device_is_compatible(ctrler->device, "gatwick"))
 		ctrler = &controllers[1];
 
-	if (ctrler->bits == feature_bits_heathrow ||
+	if (ctrler->bits == feature_bits_wallstreet ||
 		ctrler->bits == feature_bits_paddington) {
 		heathrow_prepare_for_sleep(ctrler);
 		return;
@@ -884,7 +1035,7 @@
 		device_is_compatible(ctrler->device, "gatwick"))
 		ctrler = &controllers[1];
 	
-	if (ctrler->bits == feature_bits_heathrow ||
+	if (ctrler->bits == feature_bits_wallstreet ||
 		ctrler->bits == feature_bits_paddington) {
 		heathrow_wakeup(ctrler);
 		return;
@@ -929,15 +1080,10 @@
 {
 	u32 temp;
 
-	/* For now, suspending the USB ref cause the machine to die on
-	 * wakeup -- BenH
-	 */
-#if 0
 	mdelay(1);
 	KL_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND);
 	(void)KL_IN(KEYLARGO_FCR0);
-	mdelay(1500);
-#endif
+	mdelay(100);
 
 	KL_BIC(KEYLARGO_FCR0,	KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |
 				KL0_SCC_CELL_ENABLE |
@@ -1014,7 +1160,7 @@
 core99_prepare_for_sleep(struct feature_controller* ctrler)
 {
 	int i;
-	u8* base8;
+	volatile u8* base8;
 	
 	/*
 	 * Save various bits of KeyLargo
@@ -1026,15 +1172,19 @@
 	feature_set_airport_power(airport_dev, 0);
 
 	/* We power off the FW cable. Should be done by the driver... */
+	feature_set_firewire_power(NULL, 0);
 	feature_set_firewire_cable_power(NULL, 0);
+
+	/* We make sure int. modem is off (in case driver lost it) */
+	feature_set_modem_power(NULL, 0);
 	 
 	/* Save the state of the various GPIOs */
 	save_gpio_levels[0] = KL_IN(KEYLARGO_GPIO_LEVELS0);
 	save_gpio_levels[1] = KL_IN(KEYLARGO_GPIO_LEVELS1);
-	base8 = (u8 *)KL_FCR(KEYLARGO_GPIO_EXTINT_0);
+	base8 = ((volatile u8 *)keylargo_base) + KEYLARGO_GPIO_EXTINT_0;
 	for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
 		save_gpio_extint[i] = in_8(base8+i);
-	base8 = (u8 *)KL_FCR(KEYLARGO_GPIO_0);
+	base8 = ((volatile u8 *)keylargo_base) + KEYLARGO_GPIO_0;
 	for (i=0; i<KEYLARGO_GPIO_CNT; i++)
 		save_gpio_normal[i] = in_8(base8+i);
 
@@ -1089,7 +1239,7 @@
 core99_wake_up(struct feature_controller* ctrler)
 {
 	int i;
-	u8* base8;
+	volatile u8* base8;
 
 	/*
 	 * Wakeup the host bridge
@@ -1131,10 +1281,10 @@
 
 	KL_OUT(KEYLARGO_GPIO_LEVELS0, save_gpio_levels[0]);
 	KL_OUT(KEYLARGO_GPIO_LEVELS1, save_gpio_levels[1]);
-	base8 = (u8 *)KL_FCR(KEYLARGO_GPIO_EXTINT_0);
+	base8 = ((volatile u8 *)keylargo_base) + KEYLARGO_GPIO_EXTINT_0;
 	for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)
 		out_8(base8+i, save_gpio_extint[i]);
-	base8 = (u8 *)KL_FCR(KEYLARGO_GPIO_0);
+	base8 = ((volatile u8 *)keylargo_base) + KEYLARGO_GPIO_0;
 	for (i=0; i<KEYLARGO_GPIO_CNT; i++)
 		out_8(base8+i, save_gpio_normal[i]);
 
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/gemini_setup.c linux/arch/ppc/kernel/gemini_setup.c
--- v2.4.9/linux/arch/ppc/kernel/gemini_setup.c	Mon May 21 17:04:47 2001
+++ linux/arch/ppc/kernel/gemini_setup.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.gemini_setup.c 1.7 05/17/01 18:14:21 cort
+ * BK Id: SCCS/s.gemini_setup.c 1.11 08/20/01 14:34:41 paulus
  */
 /*
  *  linux/arch/ppc/kernel/setup.c
@@ -54,17 +54,6 @@
 	0, 0, 14, 0, 0, 13, 5, 9, 6, 11, 8, 10, 0, 12, 7, 0
 };
 
-int chrp_get_irq(struct pt_regs *);
-void chrp_post_irq(struct pt_regs* regs, int);
-
-static inline unsigned long _get_HID1(void)
-{
-	unsigned long val;
-
-	__asm__ __volatile__("mfspr %0,1009" : "=r" (val));
-	return val;
-}
-
 /*
  * prom_init is the Gemini version of prom.c:prom_init.  We only need
  * the BSS clearing code, so I copied that out of prom.c.  This is a
@@ -208,10 +197,11 @@
 int
 gemini_get_clock_speed(void)
 {
-	unsigned long hid1, pvr = _get_PVR();
+	unsigned long hid1, pvr;
 	int clock;
 
-	hid1 = (_get_HID1() >> 28) & 0xf;
+	pvr = mfspr(PVR);
+	hid1 = (mfspr(HID1) >> 28) & 0xf;
 	if (PVR_VER(pvr) == 8 ||
 	    PVR_VER(pvr) == 12)
 		hid1 = cpu_7xx[hid1];
@@ -241,11 +231,12 @@
 {
         unsigned char reg, brev, fam, creg;
         unsigned long cache;
-        unsigned long pvr = _get_PVR();
+        unsigned long pvr;
 
         reg = readb(GEMINI_L2CFG);
         brev = readb(GEMINI_BREV);
         fam = readb(GEMINI_FEAT);
+        pvr = mfspr(PVR);
 
         switch(PVR_VER(pvr)) {
 
@@ -486,11 +477,60 @@
 	return total;
 }
 
-void __init gemini_init(unsigned long r3, unsigned long r4, unsigned long r5,
-			unsigned long r6, unsigned long r7)
+static void __init
+gemini_map_io(void)
+{
+	io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO);
+	io_block_mapping(0x80000000, 0x80000000, 0x10000000, _PAGE_IO);
+}
+
+#ifdef CONFIG_SMP
+static int
+smp_gemini_probe(void)
+{
+	int i, nr;
+
+        nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK) >> 2;
+	if (nr == 0)
+		nr = 4;
+
+	if (nr > 1) {
+		openpic_request_IPIs();
+		for (i = 1; i < nr; ++i)
+			smp_hw_index[i] = i;
+	}
+
+	return nr;
+}
+
+static void
+smp_gemini_kick_cpu(int nr)
+{
+	openpic_init_processor( 1<<nr );
+	openpic_init_processor( 0 );
+}
+
+static void
+smp_gemini_setup_cpu(int cpu_nr)
+{
+	if (OpenPIC_Addr)
+		do_openpic_setup_cpu();
+	if (cpu_nr > 0)
+		gemini_init_l2();
+}
+
+static struct smp_ops_t gemini_smp_ops = {
+	smp_openpic_message_pass,
+	smp_gemini_probe,
+	smp_gemini_kick_cpu,
+	smp_gemini_setup_cpu,
+};
+#endif /* CONFIG_SMP */
+
+void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+			  unsigned long r6, unsigned long r7)
 {
 	int i;
-	int chrp_get_irq( struct pt_regs * );
 
 	for(i = 0; i < GEMINI_LEDS; i++)
 		gemini_led_off(i);
@@ -525,6 +565,7 @@
 	ppc_md.calibrate_decr = gemini_calibrate_decr;
 
 	ppc_md.find_end_of_memory = gemini_find_end_of_memory;
+	ppc_md.setup_io_mappings = gemini_map_io;
 
 	/* no keyboard/mouse/video stuff yet.. */
 	ppc_md.kbd_setkeycode = NULL;
@@ -537,4 +578,8 @@
 	ppc_md.ppc_kbd_sysrq_xlate = NULL;
 #endif
 	ppc_md.pcibios_fixup_bus = gemini_pcibios_fixup;
+
+#ifdef CONFIG_SMP
+	ppc_md.smp_ops = &gemini_smp_ops;
+#endif /* CONFIG_SMP */
 }
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/head.S linux/arch/ppc/kernel/head.S
--- v2.4.9/linux/arch/ppc/kernel/head.S	Wed Jul 25 17:10:18 2001
+++ linux/arch/ppc/kernel/head.S	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.head.S 1.25 07/07/01 17:08:44 paulus
+ * BK Id: SCCS/s.head.S 1.29 08/19/01 22:43:23 paulus
  */
 /*
  *  PowerPC version 
@@ -31,6 +31,7 @@
 #include <asm/page.h>
 #include <asm/mmu.h>
 #include <asm/pgtable.h>
+#include <asm/cputable.h>
 
 #ifdef CONFIG_APUS
 #include <asm/amigappc.h>
@@ -153,7 +154,7 @@
 
 #ifndef CONFIG_GEMINI
 /* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains
- * the physical address we are running at, returned by prom_init()
+ * the physical address we are running at, returned by early_init()
  */
  	bl	mmu_off
 __after_mmu_off:
@@ -761,12 +762,10 @@
 	addi	r24,r1,STACK_FRAME_OVERHEAD
 	stw	r24,PT_REGS(r23)
 #ifdef CONFIG_ALTIVEC
-	mfpvr	r24			/* check if we are on a G4 */
-	srwi	r24,r24,16
-	cmpwi	r24,PVR_7400@h
-	bne	2f
-	mfspr	r22,SPRN_VRSAVE		/* if so, save vrsave register value */
+BEGIN_FTR_SECTION
+	mfspr	r22,SPRN_VRSAVE		/* if G4, save vrsave register value */
 	stw	r22,THREAD_VRSAVE(r23)
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #endif /* CONFIG_ALTIVEC */
 2:	addi	r2,r23,-THREAD		/* set r2 to current */
 	tovirt(r2,r2)
@@ -1280,10 +1279,13 @@
 	SYNC
 	MTMSRD(r0)
 	isync
-#else
-	bl	enable_caches
 #endif
 
+	lis	r3,-KERNELBASE@h
+	mr	r4,r24
+	bl	identify_cpu
+	bl	call_setup_cpu		/* Call setup_cpu for this CPU */
+
 	/* get current */
 	lis	r2,current_set@h
 	ori	r2,r2,current_set@l
@@ -1322,54 +1324,87 @@
 /*
  * Enable caches and 604-specific features if necessary.
  */
-enable_caches:
-	mfspr	r9,PVR
-	rlwinm	r9,r9,16,16,31
-	cmpi	0,r9,1
-	beq	6f			/* not needed for 601 */
+_GLOBAL(__setup_cpu_601)
+	blr
+_GLOBAL(__setup_cpu_603)
+	b	setup_common_caches
+_GLOBAL(__setup_cpu_604)
+	mflr	r4
+	bl	setup_common_caches
+	bl	setup_604_hid0
+	mtlr	r4
+	blr
+_GLOBAL(__setup_cpu_750)
+	mflr	r4
+	bl	setup_common_caches
+	bl	setup_750_7400_hid0
+	mtlr	r4
+	blr
+_GLOBAL(__setup_cpu_7400)
+	mflr	r4
+	bl	setup_common_caches
+	bl	setup_750_7400_hid0
+	mtlr	r4
+	blr
+_GLOBAL(__setup_cpu_7450)
+	blr
+_GLOBAL(__setup_cpu_power3)
+	blr
+_GLOBAL(__setup_cpu_power4)
+	blr
+_GLOBAL(__setup_cpu_generic)
+	blr
+
+/* Enable caches for 603's, 604, 750 & 7400 */
+setup_common_caches:
 	mfspr	r11,HID0
 	andi.	r0,r11,HID0_DCE
 	ori	r11,r11,HID0_ICE|HID0_DCE
 	ori	r8,r11,HID0_ICFI
-	bne	3f			/* don't invalidate the D-cache */
+	bne	1f			/* don't invalidate the D-cache */
 	ori	r8,r8,HID0_DCI		/* unless it wasn't enabled */
-3:
-	sync
+1:	sync
 	mtspr	HID0,r8			/* enable and invalidate caches */
 	sync
 	mtspr	HID0,r11		/* enable caches */
 	sync
 	isync
-	cmpi	0,r9,4			/* check for 604 */
-	cmpi	1,r9,9			/* or 604e */
-	cmpi	2,r9,10			/* or mach5 / 604r */
-	cmpi	3,r9,8			/* check for 750 (G3) */
-	cmpi	4,r9,12			/* or 7400 (G4) */
-	cror	2,2,6
-	cror	2,2,10
-	bne	4f
-	ori	r11,r11,HID0_SIED|HID0_BHTE /* for 604[e|r], enable */
-	bne	2,5f
-	ori	r11,r11,HID0_BTCD	/* superscalar exec & br history tbl */
-	b	5f
-4:
-	cror	14,14,18
-	bne	3,6f
-	/* for G3/G4:
-	 * enable Store Gathering (SGE), Address Brodcast (ABE),
-	 * Branch History Table (BHTE), Branch Target ICache (BTIC)
-	 */
+	blr
+
+/* 604, 604e, 604ev, ...
+ * Enable superscalar execution & branch history table
+ */
+setup_604_hid0:
+	mfspr	r11,HID0
+	ori	r11,r11,HID0_SIED|HID0_BHTE
+	ori	r8,r11,HID0_BTCD
+	sync
+	mtspr	HID0,r8		/* flush branch target address cache */
+	sync			/* on 604e/604r */
+	mtspr	HID0,r11
+	sync
+	isync
+	blr
+
+/* 740/750/7400/7410
+ * Enable Store Gathering (SGE), Address Brodcast (ABE),
+ * Branch History Table (BHTE), Branch Target ICache (BTIC)
+ * Dynamic Power Management (DPM), Speculative (SPD)
+ * Clear Instruction cache throttling (ICTC)
+ */
+setup_750_7400_hid0:
+	mfspr	r11,HID0
 	ori	r11,r11,HID0_SGE | HID0_ABE | HID0_BHTE | HID0_BTIC
 	oris	r11,r11,HID0_DPM@h	/* enable dynamic power mgmt */
 	li	r3,HID0_SPD
 	andc	r11,r11,r3		/* clear SPD: enable speculative */
  	li	r3,0
  	mtspr	ICTC,r3			/* Instruction Cache Throttling off */
-5:	isync
+	isync
 	mtspr	HID0,r11
 	sync
 	isync
-6:	blr
+	blr
 
 /*
  * Load stuff into the MMU.  Intended to be called with
@@ -1414,9 +1449,10 @@
  * This is where the main kernel code starts.
  */
 start_here:
-#ifndef CONFIG_PPC64BRIDGE
-	bl	enable_caches
-#endif
+	/* Call setup_cpu for CPU 0 */
+	li	r3,0		/* data offset */
+	li	r24,0		/* cpu# */
+	bl	call_setup_cpu
 
 	/* ptr to current */
 	lis	r2,init_task_union@h
@@ -1435,14 +1471,15 @@
 	li	r0,0
 	stwu	r0,-STACK_FRAME_OVERHEAD(r1)
 /*
- * Decide what sort of machine this is and initialize the MMU.
+ * Do early bootinfo parsing, platform-specific initialization,
+ * and set up the MMU.
  */
 	mr	r3,r31
 	mr	r4,r30
 	mr	r5,r29
 	mr	r6,r28
 	mr	r7,r27
-	bl	identify_machine
+	bl	machine_init
 	bl	MMU_init
 
 #ifdef CONFIG_APUS
@@ -1475,12 +1512,10 @@
 /* Load up the kernel context */
 2:
 	sync			/* Force all PTE updates to finish */
+	ISYNC_601
 	tlbia			/* Clear all TLB entries */
 	sync			/* wait for tlbia/tlbie to finish */
-#ifdef CONFIG_SMP
-	tlbsync			/* ... on all CPUs */
-	sync
-#endif
+	TLBSYNC			/* ... on all CPUs */
 
 	bl	load_up_mmu
 /* Now turn on the MMU for real! */
@@ -1500,7 +1535,7 @@
 	mulli	r3,r3,897	/* multiply context by skew factor */
 	rlwinm	r3,r3,4,8,27	/* VSID = (context & 0xfffff) << 4 */
 	addis	r3,r3,0x6000	/* Set Ks, Ku bits */
-	li	r0,12		/* TASK_SIZE / SEGMENT_SIZE */
+	li	r0,NUM_USER_SEGMENTS
 	mtctr	r0
 	li	r4,0
 3:
@@ -1512,7 +1547,8 @@
 	rlwinm	r3,r3,0,8,3	/* clear out any overflow from VSID field */
 	addis	r4,r4,0x1000	/* address of next segment */
 	bdnz	3b
-	SYNC
+	SYNC_601
+	isync
 	blr
 
 /* 
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/head_8xx.S linux/arch/ppc/kernel/head_8xx.S
--- v2.4.9/linux/arch/ppc/kernel/head_8xx.S	Tue Jul  3 17:08:18 2001
+++ linux/arch/ppc/kernel/head_8xx.S	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.head_8xx.S 1.14 06/28/01 15:50:16 paulus
+ * BK Id: SCCS/s.head_8xx.S 1.19 08/16/01 23:00:17 paulus
  */
 /*
  *  arch/ppc/kernel/except_8xx.S
@@ -31,6 +31,7 @@
 #include <asm/mmu.h>
 #include <asm/cache.h>
 #include <asm/pgtable.h>
+#include <asm/cputable.h>
 
 	.text
 	.globl	_stext
@@ -87,70 +88,10 @@
 	mr	r27,r7
 	li	r24,0			/* cpu # */
 
-	tlbia			/* Invalidate all TLB entries */
-	li	r8, 0
-	mtspr	MI_CTR, r8	/* Set instruction control to zero */
-	lis	r8, MD_RESETVAL@h
-#ifndef CONFIG_8xx_COPYBACK
-	oris	r8, r8, MD_WTDEF@h
-#endif
-	mtspr	MD_CTR, r8	/* Set data TLB control */
-
-	/* Now map the lower 8 Meg into the TLBs.  For this quick hack,
-	 * we can load the instruction and data TLB registers with the
-	 * same values.
-	 */
-	lis	r8, KERNELBASE@h	/* Create vaddr for TLB */
-	ori	r8, r8, MI_EVALID	/* Mark it valid */
-	mtspr	MI_EPN, r8
-	mtspr	MD_EPN, r8
-	li	r8, MI_PS8MEG		/* Set 8M byte page */
-	ori	r8, r8, MI_SVALID	/* Make it valid */
-	mtspr	MI_TWC, r8
-	mtspr	MD_TWC, r8
-	li	r8, MI_BOOTINIT		/* Create RPN for address 0 */
-	mtspr	MI_RPN, r8		/* Store TLB entry */
-	mtspr	MD_RPN, r8
-	lis	r8, MI_Kp@h		/* Set the protection mode */
-	mtspr	MI_AP, r8
-	mtspr	MD_AP, r8
-
-	/* Map another 8 MByte at the IMMR to get the processor
-	 * internal registers (among other things).
+	/* We have to turn on the MMU right away so we get cache modes
+	 * set correctly.
 	 */
-	mfspr	r9, 638			/* Get current IMMR */
-	andis.	r9, r9, 0xff80		/* Get 8Mbyte boundary */
-
-	mr	r8, r9			/* Create vaddr for TLB */
-	ori	r8, r8, MD_EVALID	/* Mark it valid */
-	mtspr	MD_EPN, r8
-	li	r8, MD_PS8MEG		/* Set 8M byte page */
-	ori	r8, r8, MD_SVALID	/* Make it valid */
-	mtspr	MD_TWC, r8
-	mr	r8, r9			/* Create paddr for TLB */
-	ori	r8, r8, MI_BOOTINIT|0x2 /* Inhibit cache -- Cort */
-	mtspr	MD_RPN, r8
-
-	/* Since the cache is enabled according to the information we
-	 * just loaded into the TLB, invalidate and enable the caches here.
-	 * We should probably check/set other modes....later.
-	 */
-	lis	r8, IDC_INVALL@h
-	mtspr	IC_CST, r8
-	mtspr	DC_CST, r8
-	lis	r8, IDC_ENABLE@h
-	mtspr	IC_CST, r8
-#ifdef CONFIG_8xx_COPYBACK
-	mtspr	DC_CST, r8
-#else
-	/* For a debug option, I left this here to easily enable
-	 * the write through cache mode
-	 */
-	lis	r8, DC_SFWT@h
-	mtspr	DC_CST, r8
-	lis	r8, IDC_ENABLE@h
-	mtspr	DC_CST, r8
-#endif
+	bl	initial_mmu
 
 /* We now have the lower 8 Meg mapped into TLB entries, and the caches
  * ready to work.
@@ -513,6 +454,7 @@
 #else
 	li	r21, 0x00f0
 	rlwimi	r20, r21, 0, 24, 28
+
 #endif
 #ifdef CONFIG_8xx_CPU6
 	li	r3, 0x3d80
@@ -721,131 +663,34 @@
 giveup_fpu:
 	blr
 
-/*
- * This code is jumped to from the startup code to copy
- * the kernel image to physical address 0.
- */
-relocate_kernel:
-	lis	r9,0x426f		/* if booted from BootX, don't */
-	addi	r9,r9,0x6f58		/* translate source addr */
-	cmpw	r31,r9			/* (we have to on chrp) */
-	beq	7f
-	rlwinm	r4,r4,0,8,31		/* translate source address */
-	add	r4,r4,r3		/* to region mapped with BATs */
-7:	addis	r9,r26,klimit@ha	/* fetch klimit */
-	lwz	r25,klimit@l(r9)
-	addis	r25,r25,-KERNELBASE@h
-	li	r6,0			/* Destination offset */
-	li	r5,0x4000		/* # bytes of memory to copy */
-	bl	copy_and_flush		/* copy the first 0x4000 bytes */
-	addi	r0,r3,4f@l		/* jump to the address of 4f */
-	mtctr	r0			/* in copy and do the rest. */
-	bctr				/* jump to the copy */
-4:	mr	r5,r25
-	bl	copy_and_flush		/* copy the rest */
-	b	turn_on_mmu
-
-/*
- * Copy routine used to copy the kernel to start at physical address 0
- * and flush and invalidate the caches as needed.
- * r3 = dest addr, r4 = source addr, r5 = copy limit, r6 = start offset
- * on exit, r3, r4, r5 are unchanged, r6 is updated to be >= r5.
- */
-copy_and_flush:
-	addi	r5,r5,-4
-	addi	r6,r6,-4
-4:	li	r0,CACHE_LINE_SIZE/4
-	mtctr	r0
-3:	addi	r6,r6,4			/* copy a cache line */
-	lwzx	r0,r6,r4
-	stwx	r0,r6,r3
-	bdnz	3b
-	dcbst	r6,r3			/* write it to memory */
-	sync
-	icbi	r6,r3			/* flush the icache line */
-	cmplw	0,r6,r5
-	blt	4b
-	isync
-	addi	r5,r5,4
-	addi	r6,r6,4
+/* Maybe someday.......
+*/
+_GLOBAL(__setup_cpu_8xx)
 	blr
 
-#ifdef CONFIG_SMP
-	.globl	__secondary_start_psurge
-__secondary_start_psurge:
-	li	r24,1			/* cpu # */
-	b	__secondary_start
-
-	.globl	__secondary_hold
-__secondary_hold:
-	/* tell the master we're here */
-	lis	r5,0x4@h
-	ori	r5,r5,0x4@l
-	stw	r3,0(r5)
-	dcbf	0,r5
-100:
-	lis	r5,0
-	dcbi	0,r5
-	lwz	r4,0(r5)
-	/* wait until we're told to start */
-	cmp	0,r4,r3
-	bne	100b
-	/* our cpu # was at addr 0 - go */
-	lis	r5,__secondary_start@h
-	ori	r5,r5,__secondary_start@l
-	tophys(r5,r5)
-	mtlr	r5
-	mr	r24,r3			/* cpu # */
-	blr
-#endif /* CONFIG_SMP */
-	
 /*
  * This is where the main kernel code starts.
  */
 start_here:
-#ifdef CONFIG_SMP
-	/* if we're the second cpu stack and r2 are different
-	* and we want to not clear the bss -- Cort */
-	lis	r5,first_cpu_booted@h
-	ori	r5,r5,first_cpu_booted@l
-	lwz	r5,0(r5)
-	cmpi	0,r5,0
-	beq	99f
-
-	/* get current */
-	lis	r2,current_set@h
-	ori	r2,r2,current_set@l
-	slwi	r24,r24,2			/* cpu # to current_set[cpu#] */
-	add	r2,r2,r24
-	lwz	r2,0(r2)
-	b	10f
-99:	
-#endif /* CONFIG_SMP */
+
 	/* ptr to current */
 	lis	r2,init_task_union@h
 	ori	r2,r2,init_task_union@l
-	/* Clear out the BSS */
-	lis	r11,_end@ha
-	addi	r11,r11,_end@l
-	lis	r8,__bss_start@ha
-	addi	r8,r8,__bss_start@l
-	subf	r11,r8,r11
-	addi	r11,r11,3
-	rlwinm.	r11,r11,30,2,31
-	beq	2f
-	addi	r8,r8,-4
-	mtctr	r11
-	li	r0,0
-3:	stwu	r0,4(r8)
-	bdnz	3b
-2:
-#ifdef CONFIG_SMP	
-10:
-#endif /* CONFIG_SMP */
+
+	/* ptr to phys current thread */
+	tophys(r4,r2)
+	addi	r4,r4,THREAD	/* init task's THREAD */
+	mtspr	SPRG3,r4
+	li	r3,0
+	mtspr	SPRG2,r3	/* 0 => r1 has kernel sp */
+
 	/* stack */
 	addi	r1,r2,TASK_UNION_SIZE
 	li	r0,0
 	stwu	r0,-STACK_FRAME_OVERHEAD(r1)
+
+	bl	early_init	/* We have to do this with MMU on */
+
 /*
  * Decide what sort of machine this is and initialize the MMU.
  */
@@ -854,12 +699,11 @@
 	mr	r5,r29
 	mr	r6,r28
 	mr	r7,r27
-	bl	identify_machine
+	bl	machine_init
 	bl	MMU_init
 
 /*
  * Go back to running unmapped so we can load up new values
- * for SDR1 (hash table pointer) and the segment registers
  * and change to using our exception vectors.
  * On the 8xx, all we have to do is invalidate the TLB to clear
  * the old 8M byte TLB mappings and load the page table base register.
@@ -869,8 +713,8 @@
 	 * easier......until someone changes init's static structures.
 	 */
 	lis	r6, swapper_pg_dir@h
-	tophys(r6,r6)
 	ori	r6, r6, swapper_pg_dir@l
+	tophys(r6,r6)
 #ifdef CONFIG_8xx_CPU6
 	lis	r4, cpu6_errata_word@h
 	ori	r4, r4, cpu6_errata_word@l
@@ -891,65 +735,117 @@
 	SYNC			/* Force all PTE updates to finish */
 	tlbia			/* Clear all TLB entries */
 	sync			/* wait for tlbia/tlbie to finish */
-#ifdef CONFIG_SMP
-	tlbsync			/* ... on all CPUs */
-	sync
-#endif
-/* Set up for using our exception vectors */
-	/* ptr to phys current thread */
-	tophys(r4,r2)
-	addi	r4,r4,THREAD	/* init task's THREAD */
-	mtspr	SPRG3,r4
-	li	r3,0
-	mtspr	SPRG2,r3	/* 0 => r1 has kernel sp */
+	TLBSYNC			/* ... on all CPUs */
+
+	/* set up the PTE pointers for the Abatron bdiGDB.
+	*/
+	tovirt(r6,r6)
+	lis	r5, abatron_pteptrs@h
+	ori	r5, r5, abatron_pteptrs@l
+	stw	r5, 0xf0(r0)	/* Must match your Abatron config file */
+	tophys(r5,r5)
+	stw	r6, 0(r5)
+
 /* Now turn on the MMU for real! */
 	li	r4,MSR_KERNEL
 	lis	r3,start_kernel@h
 	ori	r3,r3,start_kernel@l
-#ifdef CONFIG_SMP
-	/* the second time through here we go to
-	 * start_secondary(). -- Cort
-	 */
-	lis	r5,first_cpu_booted@h
-	ori	r5,r5,first_cpu_booted@l
-	tophys(r5,r5)
-	lwz	r5,0(r5)
-	cmpi	0,r5,0
-	beq	10f
-	lis	r3,start_secondary@h
-	ori	r3,r3,start_secondary@l
-10:	
-#endif /* CONFIG_SMP */
 	mtspr	SRR0,r3
 	mtspr	SRR1,r4
 	rfi			/* enable MMU and jump to start_kernel */
 
+/* Set up the initial MMU state so we can do the first level of
+ * kernel initialization.  This maps the first 8 MBytes of memory 1:1
+ * virtual to physical.  Also, set the cache mode since that is defined
+ * by TLB entries and perform any additional mapping (like of the IMMR).
+ */
+initial_mmu:
+	tlbia			/* Invalidate all TLB entries */
+	li	r8, 0
+	mtspr	MI_CTR, r8	/* Set instruction control to zero */
+	lis	r8, MD_RESETVAL@h
+#ifndef CONFIG_8xx_COPYBACK
+	oris	r8, r8, MD_WTDEF@h
+#endif
+	mtspr	MD_CTR, r8	/* Set data TLB control */
+
+	/* Now map the lower 8 Meg into the TLBs.  For this quick hack,
+	 * we can load the instruction and data TLB registers with the
+	 * same values.
+	 */
+	lis	r8, KERNELBASE@h	/* Create vaddr for TLB */
+	ori	r8, r8, MI_EVALID	/* Mark it valid */
+	mtspr	MI_EPN, r8
+	mtspr	MD_EPN, r8
+	li	r8, MI_PS8MEG		/* Set 8M byte page */
+	ori	r8, r8, MI_SVALID	/* Make it valid */
+	mtspr	MI_TWC, r8
+	mtspr	MD_TWC, r8
+	li	r8, MI_BOOTINIT		/* Create RPN for address 0 */
+	mtspr	MI_RPN, r8		/* Store TLB entry */
+	mtspr	MD_RPN, r8
+	lis	r8, MI_Kp@h		/* Set the protection mode */
+	mtspr	MI_AP, r8
+	mtspr	MD_AP, r8
+
+	/* Map another 8 MByte at the IMMR to get the processor
+	 * internal registers (among other things).
+	 */
+	mfspr	r9, 638			/* Get current IMMR */
+	andis.	r9, r9, 0xff80		/* Get 8Mbyte boundary */
+
+	mr	r8, r9			/* Create vaddr for TLB */
+	ori	r8, r8, MD_EVALID	/* Mark it valid */
+	mtspr	MD_EPN, r8
+	li	r8, MD_PS8MEG		/* Set 8M byte page */
+	ori	r8, r8, MD_SVALID	/* Make it valid */
+	mtspr	MD_TWC, r8
+	mr	r8, r9			/* Create paddr for TLB */
+	ori	r8, r8, MI_BOOTINIT|0x2 /* Inhibit cache -- Cort */
+	mtspr	MD_RPN, r8
+
+	/* Since the cache is enabled according to the information we
+	 * just loaded into the TLB, invalidate and enable the caches here.
+	 * We should probably check/set other modes....later.
+	 */
+	lis	r8, IDC_INVALL@h
+	mtspr	IC_CST, r8
+	mtspr	DC_CST, r8
+	lis	r8, IDC_ENABLE@h
+	mtspr	IC_CST, r8
+#ifdef CONFIG_8xx_COPYBACK
+	mtspr	DC_CST, r8
+#else
+	/* For a debug option, I left this here to easily enable
+	 * the write through cache mode
+	 */
+	lis	r8, DC_SFWT@h
+	mtspr	DC_CST, r8
+	lis	r8, IDC_ENABLE@h
+	mtspr	DC_CST, r8
+	blr
+#endif
+
+
 /*
  * Set up to use a given MMU context.
+ * r3 is context number, r4 is PGD pointer.
  *
- * The MPC8xx has something that currently happens "automagically."
- * Unshared user space address translations are subject to ASID (context)
- * match.  During each task switch, the ASID is incremented.  We can
- * guarantee (I hope :-) that no entries currently match this ASID
- * because every task will cause at least a TLB entry to be loaded for
- * the first instruction and data access, plus the kernel running will
- * have displaced several more TLBs.  The MMU contains 32 entries for
- * each TLB, and there are 16 contexts, so we just need to make sure
- * two pages get replaced for every context switch, which currently
- * happens.  There are other TLB management techniques that I will
- * eventually implement, but this is the easiest for now.  -- Dan
- *
- * On the MPC8xx, we place the physical address of the new task
- * page directory loaded into the MMU base register, and set the
- * ASID compare register with the new "context".
+ * We place the physical address of the new task page directory loaded
+ * into the MMU base register, and set the ASID compare register with
+ * the new "context."
  */
 _GLOBAL(set_context)
-	/* fetch the pgd from the context_mm array */
-	lis	r5, context_mm@ha
-	slwi	r6, r3, 2
-	add	r5, r5, r6
-	lwz	r5, context_mm@l(r5)	/* get the mm */
-	lwz	r4, MM_PGD(r5)		/* get the pgd from the mm */
+
+#ifdef CONFIG_BDI_SWITCH
+	/* Context switch the PTE pointer for the Abatron BDI2000.
+	 * The PGDIR is passed as second argument.
+	 */
+	lis	r5, KERNELBASE@h
+	lwz	r5, 0xf0(r5)
+	stw	r4, 0x4(r5)
+#endif
+
 #ifdef CONFIG_8xx_CPU6
 	lis	r6, cpu6_errata_word@h
 	ori	r6, r6, cpu6_errata_word@l
@@ -967,7 +863,6 @@
 	tophys	(r4, r4)
 	mtspr	M_TWB, r4		/* and pgd */
 #endif
-        tlbia
 	SYNC
 	blr
 
@@ -1012,6 +907,12 @@
 	.globl	cmd_line
 cmd_line:
 	.space	512
+
+/* Room for two PTE table poiners, usually the kernel and current user
+ * pointer to their respective root page table (pgdir).
+ */
+abatron_pteptrs:
+	.space	8
 
 #ifdef CONFIG_8xx_CPU6
 	.globl	cpu6_errata_word
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/idle.c linux/arch/ppc/kernel/idle.c
--- v2.4.9/linux/arch/ppc/kernel/idle.c	Mon May 21 17:04:47 2001
+++ linux/arch/ppc/kernel/idle.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.idle.c 1.11 05/17/01 18:14:21 cort
+ * BK Id: SCCS/s.idle.c 1.14 08/15/01 22:43:06 paulus
  */
 /*
  * Idle daemon for PowerPC.  Idle daemon will handle any action
@@ -31,12 +31,11 @@
 #include <asm/processor.h>
 #include <asm/mmu.h>
 #include <asm/cache.h>
+#include <asm/cputable.h>
 
 void zero_paged(void);
 void power_save(void);
-void inline htab_reclaim(void);
 
-unsigned long htab_reclaim_on = 0;
 unsigned long zero_paged_on = 0;
 unsigned long powersave_nap = 0;
 
@@ -50,27 +49,30 @@
 {
 	int do_power_save = 0;
 
-	/* only sleep on the 603-family/750 processors */
-	switch (_get_PVR() >> 16) {
-	case 3:			/* 603 */
-	case 6:			/* 603e */
-	case 7:			/* 603ev */
-	case 8:			/* 750 */
-	case 12:		/* 7400 */
-	case 0x800c:		/* 7410 */
+	if (cur_cpu_spec[smp_processor_id()]->cpu_features & CPU_FTR_CAN_DOZE)
 		do_power_save = 1;
-	}
 
 	/* endless loop with no priority at all */
 	current->nice = 20;
 	current->counter = -100;
-	init_idle();	
-	for (;;)
-	{
-		/*if ( !current->need_resched && zero_paged_on )
-			zero_paged();*/
-		if (!current->need_resched && htab_reclaim_on)
-			htab_reclaim();
+	init_idle();
+	for (;;) {
+#ifdef CONFIG_SMP
+		int oldval;
+
+		if (!do_power_save) {
+			/*
+			 * Deal with another CPU just having chosen a thread to
+			 * run here:
+			 */
+			oldval = xchg(&current->need_resched, -1);
+
+			if (!oldval) {
+				while(current->need_resched == -1)
+					; /* Do Nothing */
+			}
+		}
+#endif
 		if (do_power_save && !current->need_resched)
 			power_save();
 
@@ -92,68 +94,6 @@
 	return 0; 
 }
 
-/*
- * Mark 'zombie' pte's in the hash table as invalid.
- * This improves performance for the hash table reload code
- * a bit since we don't consider unused pages as valid.
- *  -- Cort
- */
-PTE *reclaim_ptr = 0;
-void inline htab_reclaim(void)
-{
-#ifndef CONFIG_8xx		
-#if 0	
-	PTE *ptr, *start;
-	static int dir = 1;
-#endif	
-	struct task_struct *p;
-	unsigned long valid = 0;
-	extern PTE *Hash, *Hash_end;
-	extern unsigned long Hash_size;
-
-	/* if we don't have a htab */
-	if ( Hash_size == 0 )
-		return;
-#if 0	
-	/* find a random place in the htab to start each time */
-	start = &Hash[jiffies%(Hash_size/sizeof(PTE))];
-	/* go a different direction each time */
-	dir *= -1;
-        for ( ptr = start;
-	      !current->need_resched && (ptr != Hash_end) && (ptr != Hash);
-	      ptr += dir)
-	{
-#else
-	if ( !reclaim_ptr ) reclaim_ptr = Hash;
-	while ( !current->need_resched )
-	{
-		reclaim_ptr++;
-		if ( reclaim_ptr == Hash_end ) reclaim_ptr = Hash;
-#endif	  
-		if (!reclaim_ptr->v)
-			continue;
-		valid = 0;
-		for_each_task(p)
-		{
-			if ( current->need_resched )
-				goto out;
-			/* if this vsid/context is in use */
-			if ( (reclaim_ptr->vsid >> 4) == p->mm->context )
-			{
-				valid = 1;
-				break;
-			}
-		}
-		if ( valid )
-			continue;
-		/* this pte isn't used */
-		reclaim_ptr->v = 0;
-	}
-out:
-	if ( current->need_resched ) printk("need_resched: %lx\n", current->need_resched);
-#endif /* CONFIG_8xx */
-}
-
 #if 0
 /*
  * Returns a pre-zero'd page from the list otherwise returns
@@ -287,7 +227,7 @@
 		atomic_inc((atomic_t *)&zero_cache_total);
 	}
 }
-#endif
+#endif /* 0 */
 
 void power_save(void)
 {
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/irq.c linux/arch/ppc/kernel/irq.c
--- v2.4.9/linux/arch/ppc/kernel/irq.c	Wed Jul 25 17:10:18 2001
+++ linux/arch/ppc/kernel/irq.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.irq.c 1.30 07/19/01 16:51:32 paulus
+ * BK Id: SCCS/s.irq.c 1.32 08/24/01 20:07:37 paulus
  */
 /*
  *  arch/ppc/kernel/irq.c
@@ -93,6 +93,11 @@
 static struct irqaction malloc_cache[IRQ_KMALLOC_ENTRIES];
 extern int mem_init_done;
 
+#if defined(CONFIG_TAU_INT)
+extern int tau_interrupts(unsigned long cpu);
+extern int tau_initialized;
+#endif
+
 void *irq_kmalloc(size_t size, int pri)
 {
 	unsigned int i;
@@ -402,12 +407,14 @@
 		}
 		len += sprintf(buf+len, "\n");
 	}
-#ifdef CONFIG_TAU
-	len += sprintf(buf+len, "TAU: ");
-	for (j = 0; j < smp_num_cpus; j++)
-		len += sprintf(buf+len, "%10u ",
-				tau_interrupts(j));
-	len += sprintf(buf+len, "\n");
+#ifdef CONFIG_TAU_INT
+	if (tau_initialized){
+		len += sprintf(buf+len, "TAU: ");
+		for (j = 0; j < smp_num_cpus; j++)
+			len += sprintf(buf+len, "%10u ",
+					tau_interrupts(j));
+		len += sprintf(buf+len, "  PowerPC             Thermal Assist (cpu temp)\n");
+	}
 #endif
 #ifdef CONFIG_SMP
 	/* should this be per processor send/receive? */
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/l2cr.S linux/arch/ppc/kernel/l2cr.S
--- v2.4.9/linux/arch/ppc/kernel/l2cr.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/l2cr.S	Tue Aug 28 06:58:33 2001
@@ -0,0 +1,201 @@
+/*
+	L2CR functions
+	Copyright © 1997-1998 by PowerLogix R & D, Inc.
+	
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+	
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+	
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the Free Software
+	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+/*
+	Thur, Dec. 12, 1998.
+	- First public release, contributed by PowerLogix.
+	***********
+	Sat, Aug. 7, 1999.
+	- Terry: Made sure code disabled interrupts before running. (Previously
+			it was assumed interrupts were already disabled).
+	- Terry: Updated for tentative G4 support.  4MB of memory is now flushed
+			instead of 2MB.  (Prob. only 3 is necessary).
+	- Terry: Updated for workaround to HID0[DPM] processor bug
+			during global invalidates.
+	***********
+	Thu, July 13, 2000.
+	- Terry: Added isync to correct for an errata.
+	
+	Author:	Terry Greeniaus (tgree@phys.ualberta.ca)
+	Please e-mail updates to this file to me, thanks!
+*/
+#include <asm/processor.h>
+#include <asm/cputable.h>
+#include "ppc_asm.h"
+
+/* Usage:
+	
+	When setting the L2CR register, you must do a few special
+	things.  If you are enabling the cache, you must perform a
+	global invalidate.  If you are disabling the cache, you must
+	flush the cache contents first.  This routine takes care of
+	doing these things.  When first enabling the cache, make sure
+	you pass in the L2CR you want, as well as passing in the
+	global invalidate bit set.  A global invalidate will only be
+	performed if the L2I bit is set in applyThis.  When enabling
+	the cache, you should also set the L2E bit in applyThis.  If
+	you want to modify the L2CR contents after the cache has been
+	enabled, the recommended procedure is to first call
+	__setL2CR(0) to disable the cache and then call it again with
+	the new values for L2CR.  Examples:
+
+	_setL2CR(0)		- disables the cache
+	_setL2CR(0xB3A04000)	- enables my G3 upgrade card:
+				- L2E set to turn on the cache
+				- L2SIZ set to 1MB
+				- L2CLK set to 1:1
+				- L2RAM set to pipelined synchronous late-write
+				- L2I set to perform a global invalidation
+				- L2OH set to 0.5 nS
+				- L2DF set because this upgrade card
+				  requires it
+
+	A similar call should work for your card.  You need to know
+	the correct setting for your card and then place them in the
+	fields I have outlined above.  Other fields support optional
+	features, such as L2DO which caches only data, or L2TS which
+	causes cache pushes from the L1 cache to go to the L2 cache
+	instead of to main memory.
+*/
+/*
+ * Summary: this procedure ignores the L2I bit in the value passed in,
+ * flushes the cache if it was already enabled, always invalidates the
+ * cache, then enables the cache if the L2E bit is set in the value
+ * passed in.
+ *   -- paulus.
+ */
+_GLOBAL(_set_L2CR)
+	/* Make sure this is a 750 or 7400 chip */
+BEGIN_FTR_SECTION
+	li	r3,-1
+	blr
+END_FTR_SECTION_IFCLR(CPU_FTR_L2CR)
+
+	/* Turn off interrupts and data relocation. */
+	mfmsr	r7		/* Save MSR in r7 */
+	rlwinm	r4,r7,0,17,15
+	rlwinm	r4,r4,0,28,26	/* Turn off DR bit */
+	sync
+	mtmsr	r4
+	isync
+
+	/* Get the current enable bit of the L2CR into r4 */
+	mfspr	r4,L2CR
+	
+	/* Tweak some bits */
+	rlwinm	r5,r3,0,0,0		/* r5 contains the new enable bit */
+	rlwinm	r3,r3,0,11,9		/* Turn off the invalidate bit */
+	rlwinm	r3,r3,0,1,31		/* Turn off the enable bit */
+
+	/* Check to see if we need to flush */
+	rlwinm.	r4,r4,0,0,0
+	beq	2f
+
+	/* Flush the cache. First, read the first 4MB of memory (physical) to
+	 * put new data in the cache.  (Actually we only need
+	 * the size of the L2 cache plus the size of the L1 cache, but 4MB will
+	 * cover everything just to be safe).
+	 */
+		
+	 /**** Might be a good idea to set L2DO here - to prevent instructions
+	       from getting into the cache.  But since we invalidate
+	       the next time we enable the cache it doesn't really matter.
+	  ****/
+
+	lis	r4,0x0002
+	mtctr	r4
+	li	r4,0
+1:
+	lwzx	r0,r0,r4
+	addi	r4,r4,32		/* Go to start of next cache line */
+	bdnz	1b
+	
+	/* Now, flush the first 4MB of memory */
+	lis	r4,0x0002
+	mtctr	r4
+	li	r4,0
+	sync
+1:
+	dcbf	r0,r4
+	addi	r4,r4,32		/* Go to start of next cache line */
+	bdnz	1b
+
+2:
+	/* Set up the L2CR configuration bits (and switch L2 off) */
+	sync
+	mtspr	L2CR,r3
+	sync
+
+	/* Before we perform the global invalidation, we must disable dynamic
+	 * power management via HID0[DPM] to work around a processor bug where
+	 * DPM can possibly interfere with the state machine in the processor
+	 * that invalidates the L2 cache tags.
+	 */
+	mfspr	r8,HID0			/* Save HID0 in r8 */
+	rlwinm	r4,r8,0,12,10		/* Turn off HID0[DPM] */
+	sync
+	mtspr	HID0,r4			/* Disable DPM */
+	sync
+
+	/* Perform a global invalidation */
+	oris	r3,r3,0x0020
+	sync
+	mtspr	L2CR,r3
+	sync
+	isync				/* For errata */
+
+	/* Wait for the invalidation to complete */
+3:	mfspr	r3,L2CR
+	rlwinm.	r4,r3,0,31,31
+	bne	3b
+	
+	rlwinm	r3,r3,0,11,9		/* Turn off the L2I bit */
+	sync
+	mtspr	L2CR,r3
+	sync
+	
+	/* Restore HID0[DPM] to whatever it was before */
+	sync
+	mtspr	1008,r8
+	sync
+
+	/* See if we need to enable the cache */
+	cmplwi	r5,0
+	beq	4f
+
+	/* Enable the cache */
+	oris	r3,r3,0x8000
+	mtspr	L2CR,r3
+	sync
+
+	/* Restore MSR (restores EE and DR bits to original state) */
+4:	SYNC
+	mtmsr	r7
+	isync
+	blr
+
+_GLOBAL(_get_L2CR)
+	/* Return the L2CR contents */
+	li	r3,0
+BEGIN_FTR_SECTION
+	mfspr	r3,L2CR
+END_FTR_SECTION_IFSET(CPU_FTR_L2CR)
+	blr
+
+/* --- End of PowerLogix code ---
+ */
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/m8260_setup.c linux/arch/ppc/kernel/m8260_setup.c
--- v2.4.9/linux/arch/ppc/kernel/m8260_setup.c	Wed Jul 25 17:10:18 2001
+++ linux/arch/ppc/kernel/m8260_setup.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.m8260_setup.c 1.20 07/18/01 22:56:39 paulus
+ * BK Id: SCCS/s.m8260_setup.c 1.24 08/20/01 15:25:16 paulus
  */
 /*
  *  linux/arch/ppc/kernel/setup.c
@@ -52,17 +52,6 @@
 unsigned long m8260_get_rtc_time(void);
 void m8260_calibrate_decr(void);
 
-#if 0
-extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
-extern int mackbd_getkeycode(unsigned int scancode);
-extern int mackbd_pretranslate(unsigned char scancode, char raw_mode);
-extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
-			   char raw_mode);
-extern char mackbd_unexpected_up(unsigned char keycode);
-extern void mackbd_leds(unsigned char leds);
-extern void mackbd_init_hw(void);
-#endif
-
 extern unsigned long loops_per_jiffy;
 
 unsigned char __res[sizeof(bd_t)];
@@ -72,10 +61,6 @@
 extern unsigned long find_available_memory(void);
 extern void m8260_cpm_reset(void);
 
-void __init adbdev_init(void)
-{
-}
-
 void __init
 m8260_setup_arch(void)
 {
@@ -102,7 +87,7 @@
 	bd_t	*binfo = (bd_t *)__res;
 	int freq, divisor;
 
-	freq = (binfo->bi_busfreq * 1000000);
+	freq = binfo->bi_busfreq;
         divisor = 4;
         tb_ticks_per_jiffy = freq / HZ / divisor;
 	tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000);
@@ -111,7 +96,8 @@
 /* The 8260 has an internal 1-second timer update register that
  * we should use for this purpose.
  */
-static uint	rtc_time;
+static uint rtc_time;
+
 static int
 m8260_set_rtc_time(unsigned long time)
 {
@@ -145,7 +131,7 @@
 			startaddr = simple_strtoul(&cmd[10], NULL, 0);
 	}
 
-	m8260_gorom((uint)__pa(__res), startaddr);
+	m8260_gorom((unsigned int)__pa(__res), startaddr);
 }
 
 void
@@ -171,9 +157,9 @@
 	len += sprintf(len+buffer,"core clock\t: %d MHz\n"
 		       "CPM  clock\t: %d MHz\n"
 		       "bus  clock\t: %d MHz\n",
-		       bp->bi_intfreq /*/ 1000000*/,
-		       bp->bi_cpmfreq /*/ 1000000*/,
-		       bp->bi_busfreq /*/ 1000000*/);
+		       bp->bi_intfreq / 1000000,
+		       bp->bi_cpmfreq / 1000000,
+		       bp->bi_busfreq / 1000000);
 
 	return len;
 }
@@ -219,9 +205,21 @@
 	return binfo->bi_memsize;
 }
 
+/* Map the IMMR, plus anything else we can cover
+ * in that upper space according to the memory controller
+ * chip select mapping.  Grab another bunch of space
+ * below that for stuff we can't cover in the upper.
+ */
+static void __init
+m8260_map_io(void)
+{
+	io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO);
+	io_block_mapping(0xe0000000, 0xe0000000, 0x10000000, _PAGE_IO);
+}
+
 void __init
-m8260_init(unsigned long r3, unsigned long r4, unsigned long r5,
-	 unsigned long r6, unsigned long r7)
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	      unsigned long r6, unsigned long r7)
 {
 
 	if ( r3 )
@@ -261,6 +259,7 @@
 	ppc_md.calibrate_decr = m8260_calibrate_decr;
 
 	ppc_md.find_end_of_memory = m8260_find_end_of_memory;
+	ppc_md.setup_io_mappings = m8260_map_io;
 
 	ppc_md.kbd_setkeycode    = NULL;
 	ppc_md.kbd_getkeycode    = NULL;
@@ -273,51 +272,11 @@
 #endif
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-        ppc_ide_md.insw = m8xx_ide_insw;
-        ppc_ide_md.outsw = m8xx_ide_outsw;
         ppc_ide_md.default_irq = m8xx_ide_default_irq;
         ppc_ide_md.default_io_base = m8xx_ide_default_io_base;
-        ppc_ide_md.fix_driveid = ppc_generic_ide_fix_driveid;
         ppc_ide_md.ide_init_hwif = m8xx_ide_init_hwif_ports;
         ppc_ide_md.ide_request_irq = m8xx_ide_request_irq;
-
-        ppc_ide_md.io_base = _IO_BASE;
 #endif		
-}
-
-/*
- * Copied from prom.c so I don't have include all of that crap.
- *				-- Dan
- *
- * prom_init() is called very early on, before the kernel text
- * and data have been mapped to KERNELBASE.  At this point the code
- * is running at whatever address it has been loaded at, so
- * references to extern and static variables must be relocated
- * explicitly.  The procedure reloc_offset() returns the address
- * we're currently running at minus the address we were linked at.
- * (Note that strings count as static variables.)
- */
-extern unsigned long reloc_offset(void);
-#define PTRRELOC(x)	((typeof(x))((unsigned long)(x) + offset))
-
-__init
-unsigned long
-prom_init(uint r3, uint r4, uint r5, uint r6)
-{
-	unsigned long offset = reloc_offset();
- 	unsigned long phys;
-	extern char __bss_start, _end;
-
-	/* First zero the BSS -- use memset, some arches don't have
-	 * caches on yet */
-	memset_io(PTRRELOC(&__bss_start),0 , &_end - &__bss_start);
-
- 	/* Default */
- 	phys = offset + KERNELBASE;
-
-	/* We are done.
-	*/
-	return phys;
 }
 
 /* Mainly for ksyms.
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/m8xx_setup.c linux/arch/ppc/kernel/m8xx_setup.c
--- v2.4.9/linux/arch/ppc/kernel/m8xx_setup.c	Wed Jul 25 17:10:18 2001
+++ linux/arch/ppc/kernel/m8xx_setup.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.m8xx_setup.c 1.23 07/18/01 22:56:39 paulus
+ * BK Id: SCCS/s.m8xx_setup.c 1.27 08/20/01 15:25:16 paulus
  */
 /*
  *  linux/arch/ppc/kernel/setup.c
@@ -358,26 +358,6 @@
 }
 #endif
 
-void
-m8xx_ide_insw(ide_ioreg_t port, void *buf, int ns)
-{
-#ifdef CONFIG_BLK_DEV_MPC8xx_IDE
-	ide_insw(port, buf, ns);
-#else
-	_insw_ns((unsigned short *)(port+_IO_BASE), buf, ns);
-#endif
-}
-
-void
-m8xx_ide_outsw(ide_ioreg_t port, void *buf, int ns)
-{
-#ifdef CONFIG_BLK_DEV_MPC8xx_IDE
-	ide_outsw(port, buf, ns);
-#else
-	_outsw_ns((unsigned short *)(port+_IO_BASE), buf, ns);
-#endif
-}
-
 int
 m8xx_ide_default_irq(ide_ioreg_t base)
 {
@@ -479,7 +459,7 @@
 # endif	/* CONFIG_SPD823TS, CONFIG_IVMS8 */
 
 	for (i = 0; i < IDE_NR_PORTS; ++i) {
-	 	*p++ = base + ioport_dsc[data_port].reg_off[i];
+		*p++ = base + ioport_dsc[data_port].reg_off[i] - _IO_BASE;
 	}
 
 	if (irq) {
@@ -595,9 +575,45 @@
 	return binfo->bi_memsize;
 }
 
+/*
+ * Now map in some of the I/O space that is generically needed
+ * or shared with multiple devices.
+ * All of this fits into the same 4Mbyte region, so it only
+ * requires one page table page.  (or at least it used to  -- paulus)
+ */
+void __init m8xx_map_io(void)
+{
+        io_block_mapping(IMAP_ADDR, IMAP_ADDR, IMAP_SIZE, _PAGE_IO);
+#ifdef CONFIG_MBX
+        io_block_mapping(NVRAM_ADDR, NVRAM_ADDR, NVRAM_SIZE, _PAGE_IO);
+        io_block_mapping(MBX_CSR_ADDR, MBX_CSR_ADDR, MBX_CSR_SIZE, _PAGE_IO);
+        io_block_mapping(PCI_CSR_ADDR, PCI_CSR_ADDR, PCI_CSR_SIZE, _PAGE_IO);
+
+	/* Map some of the PCI/ISA I/O space to get the IDE interface.
+	*/
+        io_block_mapping(PCI_ISA_IO_ADDR, PCI_ISA_IO_ADDR, 0x4000, _PAGE_IO);
+        io_block_mapping(PCI_IDE_ADDR, PCI_IDE_ADDR, 0x4000, _PAGE_IO);
+#endif
+#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC)
+	io_block_mapping(RPX_CSR_ADDR, RPX_CSR_ADDR, RPX_CSR_SIZE, _PAGE_IO);
+#if !defined(CONFIG_PCI)
+	io_block_mapping(_IO_BASE,_IO_BASE,_IO_BASE_SIZE, _PAGE_IO);
+#endif
+#endif
+#ifdef CONFIG_HTDMSOUND
+	io_block_mapping(HIOX_CSR_ADDR, HIOX_CSR_ADDR, HIOX_CSR_SIZE, _PAGE_IO);
+#endif
+#ifdef CONFIG_FADS
+	io_block_mapping(BCSR_ADDR, BCSR_ADDR, BCSR_SIZE, _PAGE_IO);
+#endif
+#ifdef CONFIG_PCI
+        io_block_mapping(PCI_CSR_ADDR, PCI_CSR_ADDR, PCI_CSR_SIZE, _PAGE_IO);
+#endif
+}
+
 void __init
-m8xx_init(unsigned long r3, unsigned long r4, unsigned long r5,
-	 unsigned long r6, unsigned long r7)
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	      unsigned long r6, unsigned long r7)
 {
 
 	if ( r3 )
@@ -641,6 +657,7 @@
 	ppc_md.calibrate_decr = m8xx_calibrate_decr;
 
 	ppc_md.find_end_of_memory = m8xx_find_end_of_memory;
+	ppc_md.setup_io_mappings = m8xx_map_io;
 
 	ppc_md.kbd_setkeycode    = NULL;
 	ppc_md.kbd_getkeycode    = NULL;
@@ -653,13 +670,8 @@
 #endif
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-        ppc_ide_md.insw = m8xx_ide_insw;
-        ppc_ide_md.outsw = m8xx_ide_outsw;
         ppc_ide_md.default_irq = m8xx_ide_default_irq;
         ppc_ide_md.default_io_base = m8xx_ide_default_io_base;
-        ppc_ide_md.fix_driveid = ppc_generic_ide_fix_driveid;
         ppc_ide_md.ide_init_hwif = m8xx_ide_init_hwif_ports;
-
-        ppc_ide_md.io_base = _IO_BASE;
 #endif		
 }
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S
--- v2.4.9/linux/arch/ppc/kernel/misc.S	Sun Aug 12 13:27:58 2001
+++ linux/arch/ppc/kernel/misc.S	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.misc.S 1.21 07/07/01 17:00:08 paulus
+ * BK Id: SCCS/s.misc.S 1.28 08/24/01 20:07:37 paulus
  */
 /*
  * This file contains miscellaneous low-level functions.
@@ -22,6 +22,7 @@
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/cache.h>
+#include <asm/cputable.h>
 #include "ppc_asm.h"
 
 	.text
@@ -49,6 +50,97 @@
 	mtlr	r0
 	blr
 
+/*
+ * identify_cpu,
+ * called with r3 = data offset and r4 = CPU number
+ * doesn't change r3
+ */
+_GLOBAL(identify_cpu)
+	addis	r8,r3,cpu_specs@ha
+	addi	r8,r8,cpu_specs@l
+	mfpvr	r7
+1:
+	lwz	r5,CPU_SPEC_PVR_MASK(r8)
+	and	r5,r5,r7
+	lwz	r6,CPU_SPEC_PVR_VALUE(r8)
+	cmplw	0,r6,r5
+	beq	1f
+	addi	r8,r8,CPU_SPEC_ENTRY_SIZE
+	b	1b
+1:
+	addis	r6,r3,cur_cpu_spec@ha
+	addi	r6,r6,cur_cpu_spec@l
+	slwi	r4,r4,2
+	sub	r8,r8,r3
+	stwx	r8,r4,r6
+	blr
+
+/*
+ * do_cpu_ftr_fixups - goes through the list of CPU feature fixups
+ * and writes nop's over sections of code that don't apply for this cpu.
+ * r3 = data offset (not changed)
+ */
+_GLOBAL(do_cpu_ftr_fixups)
+	/* Get CPU 0 features */
+	addis	r6,r3,cur_cpu_spec@ha
+	addi	r6,r6,cur_cpu_spec@l
+	lwz	r4,0(r6)
+	add	r4,r4,r3
+	lwz	r4,CPU_SPEC_FEATURES(r4)
+
+	/* Get the fixup table */
+	addis	r6,r3,__start___ftr_fixup@ha
+	addi	r6,r6,__start___ftr_fixup@l
+	addis	r7,r3,__stop___ftr_fixup@ha
+	addi	r7,r7,__stop___ftr_fixup@l
+
+	/* Do the fixup */
+1:	cmplw	0,r6,r7
+	bgelr
+	addi	r6,r6,16
+	lwz	r8,-16(r6)	/* mask */
+	and	r8,r8,r4
+	lwz	r9,-12(r6)	/* value */
+	cmplw	0,r8,r9
+	beq	1b
+	lwz	r8,-8(r6)	/* section begin */
+	lwz	r9,-4(r6)	/* section end */
+	subf.	r9,r8,r9
+	beq	1b
+	/* write nops over the section of code */
+	/* todo: if large section, add a branch at the start of it */
+	srwi	r9,r9,2
+	mtctr	r9
+	add	r8,r8,r3
+	lis	r0,0x60000000@h	/* nop */
+3:	stw	r0,0(r8)
+	andi.	r10,r4,CPU_FTR_SPLIT_ID_CACHE@l
+	beq	2f
+	dcbst	0,r8		/* suboptimal, but simpler */
+	sync
+	icbi	0,r8
+2:	addi	r8,r8,4
+	bdnz	3b
+	sync			/* additional sync needed on g4 */
+	isync
+	b	1b
+
+/*
+ * call_setup_cpu - call the setup_cpu function for this cpu
+ * r3 = data offset, r24 = cpu number
+ */
+_GLOBAL(call_setup_cpu)
+	addis	r5,r3,cur_cpu_spec@ha
+	addi	r5,r5,cur_cpu_spec@l
+	slwi	r4,r24,2
+	lwzx	r5,r4,r5
+	add	r5,r5,r3
+	lwz	r6,CPU_SPEC_SETUP(r5)
+	add	r6,r6,r3
+	mtctr	r6
+	mr	r3,r24
+	bctr
+
 /* void __save_flags_ptr(unsigned long *flags) */
 _GLOBAL(__save_flags_ptr)
 	mfmsr	r4
@@ -185,7 +277,7 @@
 _GLOBAL(_nmask_and_or_msr)
 	mfmsr	r0		/* Get current msr */
 	andc	r0,r0,r3	/* And off the bits set in r3 (first parm) */
-	or	r0,r0,r4		/* Or on the bits in r4 (second parm) */
+	or	r0,r0,r4	/* Or on the bits in r4 (second parm) */
 	SYNC			/* Some chip revs have problems here... */
 	mtmsr	r0		/* Update machine state */
 	isync
@@ -216,8 +308,7 @@
 	tlbia
 	sync
 #ifdef CONFIG_SMP
-	tlbsync
-	sync
+	TLBSYNC
 	li	r0,0
 	stw	r0,0(r9)		/* clear hash_table_lock */
 	mtmsr	r10
@@ -249,8 +340,7 @@
 	tlbie	r3
 	sync
 #ifdef CONFIG_SMP
-	tlbsync
-	sync
+	TLBSYNC
 	li	r0,0
 	stw	r0,0(r9)		/* clear hash_table_lock */
 	mtmsr	r10
@@ -314,26 +404,70 @@
 	sync				/* additional sync needed on g4 */
 	isync
 	blr
+/*
+ * Write any modified data cache blocks out to memory.
+ * Does not invalidate the corresponding cache lines (especially for
+ * any corresponding instruction cache).
+ *
+ * clean_dcache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(clean_dcache_range)
+	li	r5,CACHE_LINE_SIZE-1
+	andc	r3,r3,r5
+	subf	r4,r3,r4
+	add	r4,r4,r5
+	srwi.	r4,r4,LG_CACHE_LINE_SIZE
+	beqlr
+	mtctr	r4
+
+1:	dcbst	0,r3
+	addi	r3,r3,CACHE_LINE_SIZE
+	bdnz	1b
+	sync				/* wait for dcbst's to get to ram */
+	blr
 
 /*
- * Like above, but only do the D-cache.
+ * Write any modified data cache blocks out to memory
+ * and invalidate the corresponding instruction cache blocks.
  *
  * flush_dcache_range(unsigned long start, unsigned long stop)
  */
 _GLOBAL(flush_dcache_range)
-       li      r5,CACHE_LINE_SIZE-1
-       andc    r3,r3,r5
-       subf    r4,r3,r4
-       add     r4,r4,r5
-       srwi.   r4,r4,LG_CACHE_LINE_SIZE
-       beqlr
-       mtctr   r4
-
-1:     dcbst   0,r3
-       addi    r3,r3,CACHE_LINE_SIZE
-       bdnz    1b
-       sync                            /* wait for dcbst's to get to ram */
-       blr
+	li	r5,CACHE_LINE_SIZE-1
+	andc	r3,r3,r5
+	subf	r4,r3,r4
+	add	r4,r4,r5
+	srwi.	r4,r4,LG_CACHE_LINE_SIZE
+	beqlr
+	mtctr	r4
+
+1:	dcbf	0,r3
+	addi	r3,r3,CACHE_LINE_SIZE
+	bdnz	1b
+	sync				/* wait for dcbst's to get to ram */
+	blr
+
+/*
+ * Like above, but invalidate the D-cache.  This is used by the 8xx
+ * to invalidate the cache so the PPC core doesn't get stale data
+ * from the CPM (no cache snooping here :-).
+ *
+ * invalidate_dcache_range(unsigned long start, unsigned long stop)
+ */
+_GLOBAL(invalidate_dcache_range)
+	li	r5,CACHE_LINE_SIZE-1
+	andc	r3,r3,r5
+	subf	r4,r3,r4
+	add	r4,r4,r5
+	srwi.	r4,r4,LG_CACHE_LINE_SIZE
+	beqlr
+	mtctr	r4
+
+1:	dcbi	0,r3
+	addi	r3,r3,CACHE_LINE_SIZE
+	bdnz	1b
+	sync				/* wait for dcbi's to get to ram */
+	blr
 
 /*
  * Flush a particular page from the data cache to RAM.
@@ -481,94 +615,9 @@
 	blr
 
 /*
- * Try to acquire a spinlock.
- * Only does the stwcx. if the load returned 0 - the Programming
- * Environments Manual suggests not doing unnecessary stcwx.'s
- * since they may inhibit forward progress by other CPUs in getting
- * a lock.
- */
-_GLOBAL(__spin_trylock)
-	mr	r4,r3
-	eieio			/* prevent reordering of stores */
-	li	r5,-1
-	lwarx	r3,0,r4		/* fetch old value, establish reservation */
-	cmpwi	0,r3,0		/* is it 0? */
-	bnelr-			/* return failure if not */
-	stwcx.	r5,0,r4		/* try to update with new value */
-	bne-	1f		/* if we failed */
-	eieio			/* prevent reordering of stores */
-	blr
-1:	li	r3,1		/* return non-zero for failure */
-	blr
-
-/*
- * Atomic add/sub/inc/dec operations
- *
- * void atomic_add(int c, int *v)
- * void atomic_sub(int c, int *v)
- * void atomic_inc(int *v)
- * void atomic_dec(int *v)
- * int atomic_dec_and_test(int *v)
- * int atomic_inc_return(int *v)
- * int atomic_dec_return(int *v)
  * void atomic_clear_mask(atomic_t mask, atomic_t *addr)
  * void atomic_set_mask(atomic_t mask, atomic_t *addr);
  */
-#if 0 /* now inline - paulus */
-_GLOBAL(atomic_add)
-10:	lwarx	r5,0,r4		/* Fetch old value & reserve */
-	add	r5,r5,r3	/* Perform 'add' operation */
-	stwcx.	r5,0,r4		/* Update with new value */
-	bne-	10b		/* Retry if "reservation" (i.e. lock) lost */
-	blr
-_GLOBAL(atomic_add_return)
-10:	lwarx	r5,0,r4		/* Fetch old value & reserve */
-	add	r5,r5,r3	/* Perform 'add' operation */
-	stwcx.	r5,0,r4		/* Update with new value */
-	bne-	10b		/* Retry if "reservation" (i.e. lock) lost */
-	mr	r3,r5
-	blr
-_GLOBAL(atomic_sub)
-10:	lwarx	r5,0,r4		/* Fetch old value & reserve */
-	sub	r5,r5,r3	/* Perform 'add' operation */
-	stwcx.	r5,0,r4		/* Update with new value */
-	bne-	10b		/* Retry if "reservation" (i.e. lock) lost */
-	blr
-_GLOBAL(atomic_inc)
-10:	lwarx	r5,0,r3		/* Fetch old value & reserve */
-	addi	r5,r5,1		/* Perform 'add' operation */
-	stwcx.	r5,0,r3		/* Update with new value */
-	bne-	10b		/* Retry if "reservation" (i.e. lock) lost */
-	blr
-_GLOBAL(atomic_inc_return)
-10:	lwarx	r5,0,r3		/* Fetch old value & reserve */
-	addi	r5,r5,1		/* Perform 'add' operation */
-	stwcx.	r5,0,r3		/* Update with new value */
-	bne-	10b		/* Retry if "reservation" (i.e. lock) lost */
-	mr	r3,r5		/* Return new value */
-	blr
-_GLOBAL(atomic_dec)
-10:	lwarx	r5,0,r3		/* Fetch old value & reserve */
-	subi	r5,r5,1		/* Perform 'add' operation */
-	stwcx.	r5,0,r3		/* Update with new value */
-	bne-	10b		/* Retry if "reservation" (i.e. lock) lost */
-	blr
-_GLOBAL(atomic_dec_return)
-10:	lwarx	r5,0,r3		/* Fetch old value & reserve */
-	subi	r5,r5,1		/* Perform 'add' operation */
-	stwcx.	r5,0,r3		/* Update with new value */
-	bne-	10b		/* Retry if "reservation" (i.e. lock) lost */
-	mr	r3,r5		/* Return new value */
-	blr
-_GLOBAL(atomic_dec_and_test)
-10:	lwarx	r5,0,r3		/* Fetch old value & reserve */
-	subi	r5,r5,1		/* Perform 'add' operation */
-	stwcx.	r5,0,r3		/* Update with new value */
-	bne-	10b		/* Retry if "reservation" (i.e. lock) lost */
-	cntlzw	r3,r5
-	srwi	r3,r3,5
-	blr
-#endif /* 0 */
 _GLOBAL(atomic_clear_mask)
 10:	lwarx	r5,0,r4
 	andc	r5,r5,r3
@@ -768,281 +817,7 @@
 _GLOBAL(_get_SP)
 	mr	r3,r1		/* Close enough */
 	blr
-
-#if 0
-/* isn't it just easier to use the mtspr/mfspr inline macros?? --Troy */
-_GLOBAL(_get_THRM1)
-	mfspr	r3,THRM1
-	blr
-
-_GLOBAL(_get_THRM2)
-	mfspr	r3,THRM2
-	blr
-
-_GLOBAL(_get_THRM3)
-	mfspr	r3,THRM3
-	blr
-		
-_GLOBAL(_set_THRM1)
-	mtspr	THRM1,r3
-	blr
-
-_GLOBAL(_set_THRM2)
-	mtspr	THRM2,r3
-	blr
-
-_GLOBAL(_set_THRM3)
-	mtspr	THRM3,r3
-	blr
-#endif
-	
-_GLOBAL(_get_PVR)
-	mfspr	r3,PVR
-	blr
-
-#ifdef CONFIG_8xx
-_GLOBAL(_get_IMMR)
-	mfspr	r3, 638
-	blr
-#endif
 	
-_GLOBAL(_get_HID0)
-	mfspr	r3,HID0
-	blr
-
-_GLOBAL(_set_HID0)
-	sync
-	mtspr	HID0, r3
-	SYNC		/* Handle errata in some cases */
-	blr
-
-_GLOBAL(_get_ICTC)
-	mfspr	r3,ICTC
-	blr
-
-_GLOBAL(_set_ICTC)
-	mtspr	ICTC,r3
-	blr
-
-/*
-	L2CR functions
-	Copyright © 1997-1998 by PowerLogix R & D, Inc.
-	
-	This program is free software; you can redistribute it and/or modify
-	it under the terms of the GNU General Public License as published by
-	the Free Software Foundation; either version 2 of the License, or
-	(at your option) any later version.
-	
-	This program is distributed in the hope that it will be useful,
-	but WITHOUT ANY WARRANTY; without even the implied warranty of
-	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-	GNU General Public License for more details.
-	
-	You should have received a copy of the GNU General Public License
-	along with this program; if not, write to the Free Software
-	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-/*
-	Thur, Dec. 12, 1998.
-	- First public release, contributed by PowerLogix.
-	***********
-	Sat, Aug. 7, 1999.
-	- Terry: Made sure code disabled interrupts before running. (Previously
-			it was assumed interrupts were already disabled).
-	- Terry: Updated for tentative G4 support.  4MB of memory is now flushed
-			instead of 2MB.  (Prob. only 3 is necessary).
-	- Terry: Updated for workaround to HID0[DPM] processor bug
-			during global invalidates.
-	***********
-	Thu, July 13, 2000.
-	- Terry: Added isync to correct for an errata.
-	
-	Author:	Terry Greeniaus (tgree@phys.ualberta.ca)
-	Please e-mail updates to this file to me, thanks!
-*/
-/* Usage:
-	
-	When setting the L2CR register, you must do a few special
-	things.  If you are enabling the cache, you must perform a
-	global invalidate.  If you are disabling the cache, you must
-	flush the cache contents first.  This routine takes care of
-	doing these things.  When first enabling the cache, make sure
-	you pass in the L2CR you want, as well as passing in the
-	global invalidate bit set.  A global invalidate will only be
-	performed if the L2I bit is set in applyThis.  When enabling
-	the cache, you should also set the L2E bit in applyThis.  If
-	you want to modify the L2CR contents after the cache has been
-	enabled, the recommended procedure is to first call
-	__setL2CR(0) to disable the cache and then call it again with
-	the new values for L2CR.  Examples:
-
-	_setL2CR(0)		- disables the cache
-	_setL2CR(0xB3A04000)	- enables my G3 upgrade card:
-				- L2E set to turn on the cache
-				- L2SIZ set to 1MB
-				- L2CLK set to 1:1
-				- L2RAM set to pipelined synchronous late-write
-				- L2I set to perform a global invalidation
-				- L2OH set to 0.5 nS
-				- L2DF set because this upgrade card
-				  requires it
-
-	A similar call should work for your card.  You need to know
-	the correct setting for your card and then place them in the
-	fields I have outlined above.  Other fields support optional
-	features, such as L2DO which caches only data, or L2TS which
-	causes cache pushes from the L1 cache to go to the L2 cache
-	instead of to main memory.
-*/
-/*
- * Summary: this procedure ignores the L2I bit in the value passed in,
- * flushes the cache if it was already enabled, always invalidates the
- * cache, then enables the cache if the L2E bit is set in the value
- * passed in.
- *   -- paulus.
- */
-_GLOBAL(_set_L2CR)
-	/* Make sure this is a 750 or 7400 chip */
-	mfspr	r4,PVR
-	rlwinm	r4,r4,16,16,31
-	cmpwi	r4,0x0008
-	cmpwi	cr1,r4,0x000c
-	cror	2,2,4*cr1+2
-	bne	99f
-
-	/* Turn off interrupts and data relocation. */
-	mfmsr	r7		/* Save MSR in r7 */
-	rlwinm	r4,r7,0,17,15
-	rlwinm	r4,r4,0,28,26	/* Turn off DR bit */
-	sync
-	mtmsr	r4
-	isync
-
-	/* Get the current enable bit of the L2CR into r4 */
-	mfspr	r4,L2CR
-	
-	/* Tweak some bits */
-	rlwinm	r5,r3,0,0,0		/* r5 contains the new enable bit */
-	rlwinm	r3,r3,0,11,9		/* Turn off the invalidate bit */
-	rlwinm	r3,r3,0,1,31		/* Turn off the enable bit */
-
-	/* Check to see if we need to flush */
-	rlwinm.	r4,r4,0,0,0
-	beq	2f
-
-	/* Flush the cache. First, read the first 4MB of memory (physical) to
-	 * put new data in the cache.  (Actually we only need
-	 * the size of the L2 cache plus the size of the L1 cache, but 4MB will
-	 * cover everything just to be safe).
-	 */
-		
-	 /**** Might be a good idea to set L2DO here - to prevent instructions
-	       from getting into the cache.  But since we invalidate
-	       the next time we enable the cache it doesn't really matter.
-	  ****/
-
-	lis	r4,0x0002
-	mtctr	r4
-	li	r4,0
-1:
-	lwzx	r0,r0,r4
-	addi	r4,r4,32		/* Go to start of next cache line */
-	bdnz	1b
-	
-	/* Now, flush the first 4MB of memory */
-	lis	r4,0x0002
-	mtctr	r4
-	li	r4,0
-	sync
-1:
-	dcbf	r0,r4
-	addi	r4,r4,32		/* Go to start of next cache line */
-	bdnz	1b
-
-2:
-	/* Set up the L2CR configuration bits (and switch L2 off) */
-	sync
-	mtspr	L2CR,r3
-	sync
-
-	/* Before we perform the global invalidation, we must disable dynamic
-	 * power management via HID0[DPM] to work around a processor bug where
-	 * DPM can possibly interfere with the state machine in the processor
-	 * that invalidates the L2 cache tags.
-	 */
-	mfspr	r8,HID0			/* Save HID0 in r8 */
-	rlwinm	r4,r8,0,12,10		/* Turn off HID0[DPM] */
-	sync
-	mtspr	HID0,r4			/* Disable DPM */
-	sync
-
-	/* Perform a global invalidation */
-	oris	r3,r3,0x0020
-	sync
-	mtspr	L2CR,r3
-	sync
-	isync				/* For errata */
-
-	/* Wait for the invalidation to complete */
-3:	mfspr	r3,L2CR
-	rlwinm.	r4,r3,0,31,31
-	bne	3b
-	
-	rlwinm	r3,r3,0,11,9		/* Turn off the L2I bit */
-	sync
-	mtspr	L2CR,r3
-	sync
-	
-	/* Restore HID0[DPM] to whatever it was before */
-	sync
-	mtspr	1008,r8
-	sync
-
-	/* See if we need to enable the cache */
-	cmplwi	r5,0
-	beq	4f
-
-	/* Enable the cache */
-	oris	r3,r3,0x8000
-	mtspr	L2CR,r3
-	sync
-
-	/* Restore MSR (restores EE and DR bits to original state) */
-4:	SYNC
-	mtmsr	r7
-	isync
-	blr
-
-99:	li	r3,-1
-	blr
-
-_GLOBAL(_get_L2CR)
-	/* Make sure this is a 750 chip */
-	mfspr	r3,PVR
-	srwi	r3,r3,16
-	cmpwi	r3,0x0008
-	cmpwi	cr1,r3,0x000c
-	li	r3,0
-	cror	2,2,4*cr1+2
-	bnelr
-	/* Return the L2CR contents */
-	mfspr	r3,L2CR
-	blr
-
-/* --- End of PowerLogix code ---
- */
-
-/*
-_GLOBAL(_get_L2CR)
-	mfspr	r3,L2CR
-	blr
-
-_GLOBAL(_set_L2CR)
-	mtspr	L2CR,r3
-	blr
-		
-*/
-
 /*
  * These are used in the alignment trap handler when emulating
  * single-precision loads and stores.
@@ -1099,7 +874,7 @@
 	mr	r3,r4	        /* load arg and call fn */
 	blrl
 	li	r0,__NR_exit	/* exit after child exits */
-        li	r3,0
+	li	r3,0
 	sc
 
 /*
@@ -1279,7 +1054,7 @@
 	.long sys_setfsuid
 	.long sys_setfsgid
 	.long sys_llseek	/* 140 */
-        .long sys_getdents
+	.long sys_getdents
 	.long ppc_select
 	.long sys_flock
 	.long sys_msync
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/mk_defs.c linux/arch/ppc/kernel/mk_defs.c
--- v2.4.9/linux/arch/ppc/kernel/mk_defs.c	Tue Jul  3 17:08:18 2001
+++ linux/arch/ppc/kernel/mk_defs.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.mk_defs.c 1.8 06/28/01 15:50:16 paulus
+ * BK Id: SCCS/s.mk_defs.c 1.11 08/19/01 22:43:23 paulus
  */
 /*
  * This program is used to generate definitions needed by
@@ -26,6 +26,7 @@
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/processor.h>
+#include <asm/cputable.h>
 
 #define DEFINE(sym, val) \
 	asm volatile("\n#define\t" #sym "\t%0" : : "i" (val))
@@ -118,5 +119,14 @@
 	DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap));
 	DEFINE(CLONE_VM, CLONE_VM);
 	DEFINE(MM_PGD, offsetof(struct mm_struct, pgd));
+
+	/* About the CPU features table */
+	DEFINE(CPU_SPEC_ENTRY_SIZE, sizeof(struct cpu_spec));
+	DEFINE(CPU_SPEC_PVR_MASK, offsetof(struct cpu_spec, pvr_mask));
+	DEFINE(CPU_SPEC_PVR_VALUE, offsetof(struct cpu_spec, pvr_value));
+	DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features));
+	DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup));
+
+	DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28);
 	return 0;
 }
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/oak_setup.c linux/arch/ppc/kernel/oak_setup.c
--- v2.4.9/linux/arch/ppc/kernel/oak_setup.c	Mon May 21 17:04:47 2001
+++ linux/arch/ppc/kernel/oak_setup.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.oak_setup.c 1.5 05/17/01 18:14:21 cort
+ * BK Id: SCCS/s.oak_setup.c 1.8 08/15/01 21:48:38 paulus
  */
 /*
  *
@@ -74,8 +74,8 @@
  *
  */
 void __init
-oak_init(unsigned long r3, unsigned long r4, unsigned long r5, 
-	 unsigned long r6, unsigned long r7)
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5, 
+	      unsigned long r6, unsigned long r7)
 {
 	/*
 	 * If we were passed in a board information, copy it into the
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/open_pic.c linux/arch/ppc/kernel/open_pic.c
--- v2.4.9/linux/arch/ppc/kernel/open_pic.c	Mon May 21 17:04:47 2001
+++ linux/arch/ppc/kernel/open_pic.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.open_pic.c 1.20 05/17/01 18:14:21 cort
+ * BK Id: SCCS/s.open_pic.c 1.26 08/20/01 22:33:28 paulus
  */
 /*
  *  arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling
@@ -17,11 +17,13 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/irq.h>
+#include <linux/init.h>
 #include <asm/ptrace.h>
 #include <asm/signal.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/prom.h>
+#include <asm/init.h>
 
 #include "local_irq.h"
 #include "open_pic.h"
@@ -47,8 +49,6 @@
 
 /* Global Operations */
 static void openpic_disable_8259_pass_through(void);
-static u_int openpic_irq(void);
-static void openpic_eoi(void);
 static void openpic_set_priority(u_int pri);
 static void openpic_set_spurious(u_int vector);
 
@@ -73,8 +73,8 @@
  * These functions are not used but the code is kept here
  * for completeness and future reference.
  */
-#ifdef notused
 static void openpic_reset(void);
+#ifdef notused
 static void openpic_enable_8259_pass_through(void);
 static u_int openpic_get_priority(void);
 static u_int openpic_get_spurious(void);
@@ -412,13 +412,16 @@
 #endif
 }
 
-#ifdef notused
 static void openpic_reset(void)
 {
 	openpic_setfield(&OpenPIC->Global.Global_Configuration0,
 			 OPENPIC_CONFIG_RESET);
+	while (openpic_readfield(&OpenPIC->Global.Global_Configuration0,
+				 OPENPIC_CONFIG_RESET))
+		mb();
 }
 
+#ifdef notused
 static void openpic_enable_8259_pass_through(void)
 {
 	openpic_clearfield(&OpenPIC->Global.Global_Configuration0,
@@ -435,7 +438,7 @@
 /*
  *  Find out the current interrupt
  */
-static u_int openpic_irq(void)
+u_int openpic_irq(void)
 {
 	u_int vec;
 	DECL_THIS_CPU;
@@ -446,7 +449,7 @@
 	return vec;
 }
 
-static void openpic_eoi(void)
+void openpic_eoi(void)
 {
 	DECL_THIS_CPU;
 
@@ -518,6 +521,8 @@
 		      physmask(cpumask));
 }
 
+static spinlock_t openpic_setup_lock = SPIN_LOCK_UNLOCKED;
+
 #ifdef CONFIG_SMP
 /*
  *  Initialize an interprocessor interrupt (and disable it)
@@ -583,7 +588,6 @@
  * Get IPI's working and start taking interrupts.
  *   -- Cort
  */
-static spinlock_t openpic_setup_lock __initdata = SPIN_LOCK_UNLOCKED;
 
 void __init do_openpic_setup_cpu(void)
 {
@@ -802,11 +806,87 @@
 #endif
 		openpic_eoi();
         }
-	if (irq == OPENPIC_VEC_SPURIOUS + open_pic_irq_offset) {
+	if (irq == OPENPIC_VEC_SPURIOUS + open_pic_irq_offset)
 		irq = -1;
-		/* That's not SMP safe ... but who cares ? */
-		ppc_spurious_interrupts++;
-	}
 	return irq;
 }
 
+#ifdef CONFIG_SMP
+void
+smp_openpic_message_pass(int target, int msg, unsigned long data, int wait)
+{
+	/* make sure we're sending something that translates to an IPI */
+	if (msg > 0x3) {
+		printk("SMP %d: smp_message_pass: unknown msg %d\n",
+		       smp_processor_id(), msg);
+		return;
+	}
+	switch (target) {
+	case MSG_ALL:
+		openpic_cause_IPI(msg, 0xffffffff);
+		break;
+	case MSG_ALL_BUT_SELF:
+		openpic_cause_IPI(msg,
+				  0xffffffff & ~(1 << smp_processor_id()));
+		break;
+	default:
+		openpic_cause_IPI(msg, 1<<target);
+		break;
+	}
+}
+#endif /* CONFIG_SMP */
+
+#ifdef CONFIG_PMAC_PBOOK
+static u32 save_ipi_vp[OPENPIC_NUM_IPI];
+static u32 save_irq_src_vp[OPENPIC_MAX_SOURCES];
+static u32 save_irq_src_dest[OPENPIC_MAX_SOURCES];
+static u32 save_cpu_task_pri[OPENPIC_MAX_PROCESSORS];
+
+void __pmac
+openpic_sleep_save_intrs(void)
+{
+	int	i;
+	unsigned long flags;
+	
+	spin_lock_irqsave(&openpic_setup_lock, flags);
+
+	for (i=0; i<NumProcessors; i++) {
+		save_cpu_task_pri[i] = openpic_read(&OpenPIC->Processor[i].Current_Task_Priority);
+		openpic_writefield(&OpenPIC->Processor[i].Current_Task_Priority,
+				   OPENPIC_CURRENT_TASK_PRIORITY_MASK, 0xf);
+	}
+
+	for (i=0; i<OPENPIC_NUM_IPI; i++)
+		save_ipi_vp[i] = openpic_read(&OpenPIC->Global.IPI_Vector_Priority(i));
+	for (i=0; i<NumSources; i++) {
+		save_irq_src_vp[i] = openpic_read(&OpenPIC->Source[i].Vector_Priority)
+			& ~OPENPIC_ACTIVITY;
+		save_irq_src_dest[i] = openpic_read(&OpenPIC->Source[i].Destination);
+	}
+	spin_unlock_irqrestore(&openpic_setup_lock, flags);
+}
+
+void __pmac
+openpic_sleep_restore_intrs(void)
+{
+	int		i;
+	unsigned long	flags;
+
+	spin_lock_irqsave(&openpic_setup_lock, flags);
+	
+	openpic_reset();
+
+	for (i=0; i<OPENPIC_NUM_IPI; i++)
+		openpic_write(&OpenPIC->Global.IPI_Vector_Priority(i), save_ipi_vp[i]);
+	for (i=0; i<NumSources; i++) {
+		openpic_write(&OpenPIC->Source[i].Vector_Priority, save_irq_src_vp[i]);
+		openpic_write(&OpenPIC->Source[i].Destination, save_irq_src_dest[i]);
+	}
+	openpic_set_spurious(OPENPIC_VEC_SPURIOUS+open_pic_irq_offset);
+	openpic_disable_8259_pass_through();
+	for (i=0; i<NumProcessors; i++)
+		openpic_write(&OpenPIC->Processor[i].Current_Task_Priority, save_cpu_task_pri[i]);
+
+	spin_unlock_irqrestore(&openpic_setup_lock, flags);
+}
+#endif /* CONFIG_PMAC_PBOOK */
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/open_pic.h linux/arch/ppc/kernel/open_pic.h
--- v2.4.9/linux/arch/ppc/kernel/open_pic.h	Mon May 21 17:04:47 2001
+++ linux/arch/ppc/kernel/open_pic.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.open_pic.h 1.8 05/17/01 18:14:21 cort
+ * BK Id: SCCS/s.open_pic.h 1.12 08/20/01 22:33:28 paulus
  */
 /*
  *  arch/ppc/kernel/open_pic.h -- OpenPIC Interrupt Handling
@@ -19,6 +19,14 @@
 
 #define OPENPIC_SIZE	0x40000
 
+/*
+ *  Non-offset'ed vector numbers
+ */
+
+#define OPENPIC_VEC_TIMER	64	/* and up */
+#define OPENPIC_VEC_IPI		72	/* and up */
+#define OPENPIC_VEC_SPURIOUS	127
+
 /* OpenPIC IRQ controller structure */
 extern struct hw_interrupt_type open_pic;
 
@@ -33,16 +41,28 @@
 
 /* Exported functions */
 extern void openpic_init(int, int, unsigned char *, int);
+extern u_int openpic_irq(void);
+extern void openpic_eoi(void);
 extern void openpic_request_IPIs(void);
 extern void do_openpic_setup_cpu(void);
 extern int openpic_get_irq(struct pt_regs *regs);
 extern void openpic_init_processor(u_int cpumask);
 extern void openpic_setup_ISU(int isu_num, unsigned long addr);
 extern void openpic_cause_IPI(u_int ipi, u_int cpumask);
+extern void smp_openpic_message_pass(int target, int msg, unsigned long data,
+				     int wait);
 
 extern inline int openpic_to_irq(int irq)
 {
-	return irq += NUM_8259_INTERRUPTS;
+	/* IRQ 0 usually means 'disabled'.. don't mess with it 
+	 * exceptions to this (sandpoint maybe?) 
+	 * shouldn't use openpic_to_irq 
+	 */
+	if (irq != 0){
+		return irq += NUM_8259_INTERRUPTS;
+	} else {
+		return 0;
+	}
 }
 /*extern int open_pic_irq_offset;*/
 #endif /* _PPC_KERNEL_OPEN_PIC_H */
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/open_pic_defs.h linux/arch/ppc/kernel/open_pic_defs.h
--- v2.4.9/linux/arch/ppc/kernel/open_pic_defs.h	Mon May 21 17:04:47 2001
+++ linux/arch/ppc/kernel/open_pic_defs.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.open_pic_defs.h 1.7 05/17/01 18:14:21 cort
+ * BK Id: SCCS/s.open_pic_defs.h 1.8 08/20/01 22:33:28 paulus
  */
 /*
  *  linux/openpic.h -- OpenPIC definitions
@@ -44,14 +44,6 @@
 #define OPENPIC_NUM_PRI		16
 #define OPENPIC_NUM_VECTORS	256
 
-
-    /*
-     *  Non-offset'ed vector numbers
-     */
-
-#define OPENPIC_VEC_TIMER       64    /* and up */
-#define OPENPIC_VEC_IPI         72    /* and up */
-#define OPENPIC_VEC_SPURIOUS    127
 
 
     /*
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/pmac_nvram.c linux/arch/ppc/kernel/pmac_nvram.c
--- v2.4.9/linux/arch/ppc/kernel/pmac_nvram.c	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/kernel/pmac_nvram.c	Tue Aug 28 06:58:33 2001
@@ -1,10 +1,11 @@
 /*
- * BK Id: SCCS/s.pmac_nvram.c 1.10 08/08/01 16:23:35 paulus
+ * BK Id: SCCS/s.pmac_nvram.c 1.13 08/19/01 22:23:04 paulus
  */
 /*
  * Miscellaneous procedures for dealing with the PowerMac hardware.
  */
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/stddef.h>
 #include <linux/nvram.h>
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/pmac_pci.c linux/arch/ppc/kernel/pmac_pci.c
--- v2.4.9/linux/arch/ppc/kernel/pmac_pci.c	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/kernel/pmac_pci.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.pmac_pci.c 1.22 08/08/01 16:35:43 paulus
+ * BK Id: SCCS/s.pmac_pci.c 1.25 08/19/01 22:23:04 paulus
  */
 /*
  * Support for PCI bridges found on Power Macintoshes.
@@ -528,6 +528,7 @@
 pmac_pci_enable_device_hook(struct pci_dev *dev, int initial)
 {
 	struct device_node* node;
+	int updatecfg = 0;
 
 	node = pci_device_to_OF_node(dev);
 
@@ -538,14 +539,40 @@
 	    && dev->device == PCI_DEVICE_ID_APPLE_KL_USB && !node)
 		return -EINVAL;
 		
-	/* Firewire was disabled after PCI probe, the driver is claiming it,
-	 * so we must re-enable it now, at least until the driver can do it
-	 * itself.
+	/* Firewire & GMAC were disabled after PCI probe, the driver is
+	 * claiming them, we must re-enable them now.
 	 */
 	if (node && !strcmp(node->name, "firewire") && 
-	    device_is_compatible(node, "pci106b,18")) {
+	    (device_is_compatible(node, "pci106b,18") || 
+	     device_is_compatible(node, "pci106b,30"))) {
 		feature_set_firewire_cable_power(node, 1);
 		feature_set_firewire_power(node, 1);
+		updatecfg = 1;
+	}
+	if (node && !strcmp(node->name, "ethernet") && 
+	    device_is_compatible(node, "gmac")) {
+		feature_set_gmac_power(node, 1);
+		updatecfg = 1;
+	}
+
+	if (updatecfg) {
+		u16 cmd;
+		
+		/*
+		 * Make sure PCI is correctly configured
+		 *
+		 * We use old pci_bios versions of the function since, by
+		 * default, gmac is not powered up, and so will be absent
+		 * from the kernel initial PCI lookup. 
+		 * 
+		 * Should be replaced by 2.4 new PCI mecanisms and really
+		 * regiser the device.
+		 */
+		pci_read_config_word(dev, PCI_COMMAND, &cmd);
+		cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
+    		pci_write_config_word(dev, PCI_COMMAND, cmd);
+    		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 16);
+    		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 8);
 	}
 	
 	return 0;
@@ -580,7 +607,8 @@
 
 	nd = find_devices("firewire");
 	while (nd) {
-		if (nd->parent && device_is_compatible(nd, "pci106b,18")
+		if (nd->parent && (device_is_compatible(nd, "pci106b,18") ||
+					device_is_compatible(nd, "pci106b,30"))
 		    && device_is_compatible(nd->parent, "uni-north")) {
 			feature_set_firewire_power(nd, 0);
 			feature_set_firewire_cable_power(nd, 0);
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/pmac_pic.c linux/arch/ppc/kernel/pmac_pic.c
--- v2.4.9/linux/arch/ppc/kernel/pmac_pic.c	Mon May 21 17:04:47 2001
+++ linux/arch/ppc/kernel/pmac_pic.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.pmac_pic.c 1.14 05/17/01 18:14:21 cort
+ * BK Id: SCCS/s.pmac_pic.c 1.18 08/19/01 22:23:04 paulus
  */
 #include <linux/config.h>
 #include <linux/stddef.h>
@@ -35,7 +35,6 @@
 
 static int max_irqs;
 static int max_real_irqs;
-static int pmac_has_openpic;
 
 spinlock_t pmac_pic_lock = SPIN_LOCK_UNLOCKED;
 
@@ -291,17 +290,16 @@
  * controller.  If we find this second ohare, set it up and fix the
  * interrupt value in the device tree for the ethernet chip.
  */
-static void __init enable_second_ohare(void)
+static int __init enable_second_ohare(void)
 {
 	unsigned char bus, devfn;
 	unsigned short cmd;
         unsigned long addr;
-	int second_irq;
 	struct device_node *irqctrler = find_devices("pci106b,7");
 	struct device_node *ether;
 
 	if (irqctrler == NULL || irqctrler->n_addrs <= 0)
-		return;
+		return -1;
 	addr = (unsigned long) ioremap(irqctrler->addrs[0].address, 0x40);
 	pmac_irq_hw[1] = (volatile struct pmac_irq_hw *)(addr + 0x20);
 	max_irqs = 64;
@@ -317,11 +315,6 @@
 		}
 	}
 
-	second_irq = irqctrler->intrs[0].line;
-	printk(KERN_INFO "irq: secondary controller on irq %d\n", second_irq);
-	request_irq(second_irq, gatwick_action, SA_INTERRUPT,
-		    "interrupt cascade", 0 );
-
 	/* Fix interrupt for the modem/ethernet combo controller. The number
 	   in the device tree (27) is bogus (correct for the ethernet-only
 	   board but not the combo ethernet/modem board).
@@ -333,6 +326,9 @@
 		printk(KERN_INFO "irq: Fixed ethernet IRQ to %d\n",
 		       ether->intrs[0].line);
 	}
+
+	/* Return the interrupt number of the cascade */
+	return irqctrler->intrs[0].line;
 }
 
 void __init
@@ -341,8 +337,8 @@
         int i;
         struct device_node *irqctrler;
         unsigned long addr;
-	int second_irq = -999;
-
+	int irq_cascade = -1;
+	
 	/* We first try to detect Apple's new Core99 chipset, since mac-io
 	 * is quite different on those machines and contains an IBM MPIC2.
 	 */
@@ -368,7 +364,6 @@
 			OpenPIC_Addr = ioremap(irqctrler->addrs[0].address,
 					       irqctrler->addrs[0].size);
 			openpic_init(1, 0, 0, nmi_irq);
-			pmac_has_openpic = 1;
 #ifdef CONFIG_XMON
 			if (nmi_irq >= 0)
 				request_irq(nmi_irq, xmon_irq, 0,
@@ -418,6 +413,9 @@
 			for (i = 2; i < 4; ++i)
 				pmac_irq_hw[i] = (volatile struct pmac_irq_hw*)
 					(addr + (4 - i) * 0x10);
+			irq_cascade = irqctrler->intrs[0].line;
+			if (device_is_compatible(irqctrler, "gatwick"))
+				pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
 		}
 	} else {
 		/* older powermacs have a GC (grand central) or ohare at
@@ -430,23 +428,20 @@
 	   ohare chip, on the combo ethernet/modem card */
 	if (machine_is_compatible("AAPL,3400/2400")
 	     || machine_is_compatible("AAPL,3500"))
-		enable_second_ohare();
+		irq_cascade = enable_second_ohare();
 
 	/* disable all interrupts in all controllers */
 	for (i = 0; i * 32 < max_irqs; ++i)
 		out_le32(&pmac_irq_hw[i]->enable, 0);
 	
 	/* get interrupt line of secondary interrupt controller */
-	if (irqctrler) {
-		second_irq = irqctrler->intrs[0].line;
+	if (irq_cascade >= 0) {
 		printk(KERN_INFO "irq: secondary controller on irq %d\n",
-			(int)second_irq);
-		if (device_is_compatible(irqctrler, "gatwick"))
-			pmac_fix_gatwick_interrupts(irqctrler, max_real_irqs);
+			(int)irq_cascade);
 		for ( i = max_real_irqs ; i < max_irqs ; i++ )
 			irq_desc[i].handler = &gatwick_pic;
-		request_irq( second_irq, gatwick_action, SA_INTERRUPT,
-			     "gatwick cascade", 0 );
+		request_irq( irq_cascade, gatwick_action, SA_INTERRUPT,
+			     "cascade", 0 );
 	}
 	printk("System has %d possible interrupts\n", max_irqs);
 	if (max_irqs != max_real_irqs)
@@ -467,14 +462,15 @@
  */
 unsigned int sleep_save_mask[2];
 
-void
-sleep_save_intrs(int viaint)
+void __pmac
+pmac_sleep_save_intrs(int viaint)
 {
 	sleep_save_mask[0] = ppc_cached_irq_mask[0];
 	sleep_save_mask[1] = ppc_cached_irq_mask[1];
 	ppc_cached_irq_mask[0] = 0;
 	ppc_cached_irq_mask[1] = 0;
-	set_bit(viaint, ppc_cached_irq_mask);
+	if (viaint > 0)
+		set_bit(viaint, ppc_cached_irq_mask);
 	out_le32(&pmac_irq_hw[0]->enable, ppc_cached_irq_mask[0]);
 	if (max_real_irqs > 32)
 		out_le32(&pmac_irq_hw[1]->enable, ppc_cached_irq_mask[1]);
@@ -484,8 +480,8 @@
         (void)in_le32(&pmac_irq_hw[0]->enable);
 }
 
-void
-sleep_restore_intrs(void)
+void __pmac
+pmac_sleep_restore_intrs(void)
 {
 	int i;
 
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/pmac_pic.h linux/arch/ppc/kernel/pmac_pic.h
--- v2.4.9/linux/arch/ppc/kernel/pmac_pic.h	Mon May 21 17:04:47 2001
+++ linux/arch/ppc/kernel/pmac_pic.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.pmac_pic.h 1.5 05/17/01 18:14:21 cort
+ * BK Id: SCCS/s.pmac_pic.h 1.9 08/19/01 22:23:04 paulus
  */
 #ifndef _PPC_KERNEL_PMAC_PIC_H
 #define _PPC_KERNEL_PMAC_PIC_H
@@ -10,6 +10,5 @@
 
 void pmac_pic_init(void);
 int pmac_get_irq(struct pt_regs *regs);
-void pmac_post_irq(int);
 
 #endif /* _PPC_KERNEL_PMAC_PIC_H */
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/pmac_setup.c linux/arch/ppc/kernel/pmac_setup.c
--- v2.4.9/linux/arch/ppc/kernel/pmac_setup.c	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/kernel/pmac_setup.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.pmac_setup.c 1.24 07/06/01 14:49:51 trini
+ * BK Id: SCCS/s.pmac_setup.c 1.35 08/20/01 22:37:37 paulus
  */
 /*
  *  linux/arch/ppc/kernel/setup.c
@@ -65,6 +65,8 @@
 #include <asm/keyboard.h>
 #include <asm/dma.h>
 #include <asm/bootx.h>
+#include <asm/cputable.h>
+#include <asm/btext.h>
 
 #include <asm/time.h>
 #include "local_irq.h"
@@ -133,13 +135,16 @@
 sys_ctrler_t sys_ctrler = SYS_CTRLER_UNKNOWN;
 
 #ifdef CONFIG_SMP
+extern struct smp_ops_t psurge_smp_ops;
+extern struct smp_ops_t core99_smp_ops;
+
 volatile static long int core99_l2_cache;
-void __pmac
+void __init
 core99_init_l2(void)
 {
 	int cpu = smp_processor_id();
 
-	if ( (_get_PVR() >> 16) != 8 && (_get_PVR() >> 16) != 12 )
+	if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR))
 		return;
 
 	if (cpu == 0){
@@ -277,6 +282,9 @@
 {
 	struct device_node *cpu;
 	int *fp;
+	unsigned long pvr;
+	
+	pvr = PVR_VER(mfspr(PVR));
 
 	/* Set loops_per_jiffy to a half-way reasonable value,
 	   for use until calibrate_delay gets called. */
@@ -284,18 +292,12 @@
 	if (cpu != 0) {
 		fp = (int *) get_property(cpu, "clock-frequency", NULL);
 		if (fp != 0) {
-			switch (_get_PVR() >> 16) {
-			case 4:		/* 604 */
-			case 8:		/* G3 */
-			case 9:		/* 604e */
-			case 10:	/* mach V (604ev5) */
-			case 12:	/* G4 */
-			case 20:	/* 620 */
+			if (pvr == 4 || pvr >= 8)
+				/* 604, G3, G4 etc. */
 				loops_per_jiffy = *fp / HZ;
-				break;
-			default:	/* 601, 603, etc. */
+			else
+				/* 601, 603, etc. */
 				loops_per_jiffy = *fp / (2*HZ);
-			}
 		} else
 			loops_per_jiffy = 50000000 / HZ;
 	}
@@ -303,14 +305,13 @@
 	/* this area has the CPU identification register
 	   and some registers used by smp boards */
 	sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000);
-	__ioremap(0xffc00000, 0x400000, pgprot_val(PAGE_READONLY));
 	ohare_init();
 
 	/* Lookup PCI hosts */
 	pmac_find_bridges();
 	
 	/* Checks "l2cr-value" property in the registry */
-	if ( (_get_PVR() >> 16) == 8 || (_get_PVR() >> 16) == 12 ) {
+	if (cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR) {
 		struct device_node *np = find_devices("cpus");		
 		if (np == 0)
 			np = find_type_devices("cpu");		
@@ -342,9 +343,19 @@
 
 #ifdef CONFIG_ADB_CUDA
 	find_via_cuda();
+#else
+	if (find_devices("via-cuda")) {
+		printk("WARNING ! Your machine is Cuda based but your kernel\n");
+		printk("          wasn't compiled with CONFIG_ADB_CUDA option !\n");
+	}
 #endif	
 #ifdef CONFIG_ADB_PMU
 	find_via_pmu();
+#else
+	if (find_devices("via-pmu")) {
+		printk("WARNING ! Your machine is PMU based but your kernel\n");
+		printk("          wasn't compiled with CONFIG_ADB_PMU option !\n");
+	}
 #endif	
 #ifdef CONFIG_NVRAM
 	pmac_nvram_init();
@@ -361,6 +372,14 @@
 	else
 #endif
 		ROOT_DEV = to_kdev_t(DEFAULT_ROOT_DEVICE);
+
+#ifdef CONFIG_SMP
+	/* Check for Core99 */
+	if (find_devices("uni-n"))
+		ppc_md.smp_ops = &core99_smp_ops;
+	else
+		ppc_md.smp_ops = &psurge_smp_ops;
+#endif /* CONFIG_SMP */
 }
 
 static void __init ohare_init(void)
@@ -475,9 +494,11 @@
 	static int found_boot = 0;
 	char *p;
 
-	/* Do nothing if the root has been set already. */
+	/* Do nothing if the root has been mounted already. */
+	if (init_task.fs->rootmnt != NULL)
+		return;
 	if ((goodness <= current_root_goodness) &&
-		(ROOT_DEV != to_kdev_t(DEFAULT_ROOT_DEVICE)))
+	    (ROOT_DEV != to_kdev_t(DEFAULT_ROOT_DEVICE)))
 		return;
 	p = strstr(saved_command_line, "root=");
 	if (p != NULL && (p == saved_command_line || p[-1] == ' '))
@@ -563,41 +584,7 @@
 /*
  * IDE stuff.
  */
-void __pmac
-pmac_ide_insw(ide_ioreg_t port, void *buf, int ns)
-{
-	_insw_ns((unsigned short *)(port+_IO_BASE), buf, ns);
-}
-
-void __pmac
-pmac_ide_outsw(ide_ioreg_t port, void *buf, int ns)
-{
-	_outsw_ns((unsigned short *)(port+_IO_BASE), buf, ns);
-}
-
-int __pmac
-pmac_ide_default_irq(ide_ioreg_t base)
-{
-#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
-	extern int pmac_ide_get_irq(ide_ioreg_t base);
-        return pmac_ide_get_irq(base);
-#else
-	return 0;
-#endif
-}
-
-ide_ioreg_t __pmac
-pmac_ide_default_io_base(int index)
-{
-#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
-	extern ide_ioreg_t pmac_ide_get_base(int index);
-        return pmac_ide_get_base(index);
-#else
-	return 0;
-#endif
-}
-
-int __pmac
+static int __pmac
 pmac_ide_check_region(ide_ioreg_t from, unsigned int extent)
 {
 	/*
@@ -606,11 +593,11 @@
 	 * register, it should be OK.
 	 */
 	if (from < ~_IO_BASE)
-		return 0;
-	return check_region(from, extent);
+		return check_region(from, extent);
+	return 0;
 }
 
-void __pmac
+static void __pmac
 pmac_ide_request_region(ide_ioreg_t from,
 			unsigned int extent,
 			const char *name)
@@ -619,7 +606,7 @@
 		request_region(from, extent, name);
 }
 
-void __pmac
+static void __pmac
 pmac_ide_release_region(ide_ioreg_t from,
 			unsigned int extent)
 {
@@ -627,21 +614,24 @@
 		release_region(from, extent);
 }
 
-#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
-/* This is declared in drivers/block/ide-pmac.c */
-void __pmac
-pmac_ide_init_hwif_ports (hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq);
-#else
 /*
- * This registers the standard ports for this architecture with the IDE
- * driver.
+ * This is only used if we have a PCI IDE controller, not
+ * for the IDE controller in the ohare/paddington/heathrow/keylargo.
  */
-void __pmac
-pmac_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
+static void __pmac
+pmac_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port,
+		ide_ioreg_t ctrl_port, int *irq)
 {
+	ide_ioreg_t reg = data_port;
+	int i;
+
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+		hw->io_ports[i] = reg;
+		reg += 1;
+	}
+	hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
 }
 #endif
-#endif
 
 /*
  * Read in a property describing some pieces of memory.
@@ -728,39 +718,8 @@
 }
 
 void __init
-pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
-	  unsigned long r6, unsigned long r7)
+select_adb_keyboard(void)
 {
-	/* isa_io_base gets set in pmac_find_bridges */
-	isa_mem_base = PMAC_ISA_MEM_BASE;
-	pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
-	ISA_DMA_THRESHOLD = ~0L;
-	DMA_MODE_READ = 1;
-	DMA_MODE_WRITE = 2;
-
-	ppc_md.setup_arch     = pmac_setup_arch;
-	ppc_md.setup_residual = NULL;
-	ppc_md.get_cpuinfo    = pmac_get_cpuinfo;
-	ppc_md.irq_cannonicalize = NULL;
-	ppc_md.init_IRQ       = pmac_pic_init;
-	ppc_md.get_irq        = pmac_get_irq; /* Changed later on ... */
-	ppc_md.init           = pmac_init2;
-	
-	ppc_md.pcibios_fixup  = pmac_pcibios_fixup;
-	ppc_md.pcibios_enable_device_hook = pmac_pci_enable_device_hook;
-	ppc_md.pcibios_after_init = pmac_pcibios_after_init;
-
-	ppc_md.restart        = pmac_restart;
-	ppc_md.power_off      = pmac_power_off;
-	ppc_md.halt           = pmac_halt;
-
-	ppc_md.time_init      = pmac_time_init;
-	ppc_md.set_rtc_time   = pmac_set_rtc_time;
-	ppc_md.get_rtc_time   = pmac_get_rtc_time;
-	ppc_md.calibrate_decr = pmac_calibrate_decr;
-
-	ppc_md.find_end_of_memory = pmac_find_end_of_memory;
-
 #ifdef CONFIG_VT
 #ifdef CONFIG_INPUT
 	ppc_md.kbd_init_hw       = mac_hid_init_hw;
@@ -768,6 +727,8 @@
 	ppc_md.kbd_unexpected_up = mac_hid_kbd_unexpected_up;
 	ppc_md.kbd_setkeycode    = 0;
 	ppc_md.kbd_getkeycode    = 0;
+	ppc_md.kbd_leds		 = 0;
+	ppc_md.kbd_rate_fn	 = 0;
 #ifdef CONFIG_MAGIC_SYSRQ
 #ifdef CONFIG_MAC_ADBKEYCODES
 	if (!keyboard_sends_linux_keycodes) {
@@ -786,6 +747,7 @@
 	ppc_md.kbd_translate        = mackbd_translate;
 	ppc_md.kbd_unexpected_up    = mackbd_unexpected_up;
 	ppc_md.kbd_leds             = mackbd_leds;
+	ppc_md.kbd_rate_fn	    = NULL;
 	ppc_md.kbd_init_hw          = mackbd_init_hw;
 #ifdef CONFIG_MAGIC_SYSRQ
 	ppc_md.ppc_kbd_sysrq_xlate  = mackbd_sysrq_xlate;
@@ -793,21 +755,55 @@
 #endif /* CONFIG_MAGIC_SYSRQ */
 #endif /* CONFIG_INPUT_ADBHID/CONFIG_ADB_KEYBOARD */
 #endif /* CONFIG_VT */
+}
+
+void __init
+pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	  unsigned long r6, unsigned long r7)
+{
+	/* isa_io_base gets set in pmac_find_bridges */
+	isa_mem_base = PMAC_ISA_MEM_BASE;
+	pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
+	ISA_DMA_THRESHOLD = ~0L;
+	DMA_MODE_READ = 1;
+	DMA_MODE_WRITE = 2;
+
+	ppc_md.setup_arch     = pmac_setup_arch;
+	ppc_md.setup_residual = NULL;
+	ppc_md.get_cpuinfo    = pmac_get_cpuinfo;
+	ppc_md.irq_cannonicalize = NULL;
+	ppc_md.init_IRQ       = pmac_pic_init;
+	ppc_md.get_irq        = pmac_get_irq; /* Changed later on ... */
+	ppc_md.init           = pmac_init2;
+	
+	ppc_md.pcibios_fixup  = pmac_pcibios_fixup;
+	ppc_md.pcibios_enable_device_hook = pmac_pci_enable_device_hook;
+	ppc_md.pcibios_after_init = pmac_pcibios_after_init;
+
+	ppc_md.restart        = pmac_restart;
+	ppc_md.power_off      = pmac_power_off;
+	ppc_md.halt           = pmac_halt;
+
+	ppc_md.time_init      = pmac_time_init;
+	ppc_md.set_rtc_time   = pmac_set_rtc_time;
+	ppc_md.get_rtc_time   = pmac_get_rtc_time;
+	ppc_md.calibrate_decr = pmac_calibrate_decr;
+
+	ppc_md.find_end_of_memory = pmac_find_end_of_memory;
+
+	select_adb_keyboard();
 
 #if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
-        ppc_ide_md.insw			= pmac_ide_insw;
-        ppc_ide_md.outsw		= pmac_ide_outsw;
-        ppc_ide_md.default_irq		= pmac_ide_default_irq;
-        ppc_ide_md.default_io_base	= pmac_ide_default_io_base;
         ppc_ide_md.ide_check_region	= pmac_ide_check_region;
         ppc_ide_md.ide_request_region	= pmac_ide_request_region;
         ppc_ide_md.ide_release_region	= pmac_ide_release_region;
-        ppc_ide_md.fix_driveid		= ppc_generic_ide_fix_driveid;
         ppc_ide_md.ide_init_hwif	= pmac_ide_init_hwif_ports;
 #endif /* CONFIG_BLK_DEV_IDE && CONFIG_BLK_DEV_IDE_PMAC */
+
 #ifdef CONFIG_BOOTX_TEXT
 	ppc_md.progress = pmac_progress;
 #endif /* CONFIG_BOOTX_TEXT */
+
 	if (ppc_md.progress) ppc_md.progress("pmac_init(): exit", 0);
 	
 }
@@ -821,7 +817,7 @@
 {
 	if (disp_bi == 0)
 		return;
-	prom_drawstring(s);
-	prom_drawchar('\n');
+	btext_drawstring(s);
+	btext_drawchar('\n');
 }
 #endif /* CONFIG_BOOTX_TEXT */
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/pmac_smp.c linux/arch/ppc/kernel/pmac_smp.c
--- v2.4.9/linux/arch/ppc/kernel/pmac_smp.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/pmac_smp.c	Tue Aug 28 06:58:33 2001
@@ -0,0 +1,488 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * SMP support for power macintosh.
+ *
+ * We support both the old "powersurge" SMP architecture
+ * and the current Core99 (G4 PowerMac) machines.
+ *
+ * Support Macintosh G4 SMP by Troy Benjegerdes (hozer@drgw.net)
+ * and Ben Herrenschmidt <benh@kernel.crashing.org>.
+ *
+ * Support for DayStar quad CPU cards
+ * Copyright (C) XLR8, Inc. 1994-2000
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/delay.h>
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+
+#include <asm/ptrace.h>
+#include <asm/atomic.h>
+#include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/hardirq.h>
+#include <asm/softirq.h>
+#include <asm/init.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/smp.h>
+#include <asm/residual.h>
+#include <asm/feature.h>
+#include <asm/time.h>
+#include <asm/gemini.h>
+
+#include "open_pic.h"
+
+/*
+ * Powersurge (old powermac SMP) support.
+ */
+
+extern void __secondary_start_psurge(void);
+extern void __secondary_start_psurge2(void);	/* Temporary horrible hack */
+extern void __secondary_start_psurge3(void);	/* Temporary horrible hack */
+
+/* Addresses for powersurge registers */
+#define HAMMERHEAD_BASE		0xf8000000
+#define HHEAD_CONFIG		0x90
+#define HHEAD_SEC_INTR		0xc0
+
+/* register for interrupting the primary processor on the powersurge */
+/* N.B. this is actually the ethernet ROM! */
+#define PSURGE_PRI_INTR		0xf3019000
+
+/* register for storing the start address for the secondary processor */
+/* N.B. this is the PCI config space address register for the 1st bridge */
+#define PSURGE_START		0xf2800000
+
+/* Daystar/XLR8 4-CPU card */
+#define PSURGE_QUAD_REG_ADDR	0xf8800000
+
+#define PSURGE_QUAD_IRQ_SET	0
+#define PSURGE_QUAD_IRQ_CLR	1
+#define PSURGE_QUAD_IRQ_PRIMARY	2
+#define PSURGE_QUAD_CKSTOP_CTL	3
+#define PSURGE_QUAD_PRIMARY_ARB	4
+#define PSURGE_QUAD_BOARD_ID	6
+#define PSURGE_QUAD_WHICH_CPU	7
+#define PSURGE_QUAD_CKSTOP_RDBK	8
+#define PSURGE_QUAD_RESET_CTL	11
+
+#define PSURGE_QUAD_OUT(r, v)	(out_8(quad_base + ((r) << 4) + 4, (v)))
+#define PSURGE_QUAD_IN(r)	(in_8(quad_base + ((r) << 4) + 4) & 0x0f)
+#define PSURGE_QUAD_BIS(r, v)	(PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) | (v)))
+#define PSURGE_QUAD_BIC(r, v)	(PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) & ~(v)))
+
+/* virtual addresses for the above */
+static volatile u8 *hhead_base;
+static volatile u8 *quad_base;
+static volatile u32 *psurge_pri_intr;
+static volatile u8 *psurge_sec_intr;
+static volatile u32 *psurge_start;
+
+/* what sort of powersurge board we have */
+static int psurge_type;
+
+/* values for psurge_type */
+#define PSURGE_DUAL		0
+#define PSURGE_QUAD_OKEE	1
+#define PSURGE_QUAD_COTTON	2
+#define PSURGE_QUAD_ICEGRASS	3
+
+/* l2 cache stuff for dual G4 macs */
+extern void core99_init_l2(void);
+
+/*
+ * Set and clear IPIs for powersurge.
+ */
+static inline void psurge_set_ipi(int cpu)
+{
+	if (cpu == 0)
+		in_be32(psurge_pri_intr);
+	else if (psurge_type == PSURGE_DUAL)
+		out_8(psurge_sec_intr, 0);
+	else
+		PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_SET, 1 << cpu);
+}
+
+static inline void psurge_clr_ipi(int cpu)
+{
+	if (cpu > 0) {
+		if (psurge_type == PSURGE_DUAL)
+			out_8(psurge_sec_intr, ~0);
+		else
+			PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, 1 << cpu);
+	}
+}
+
+/*
+ * On powersurge (old SMP powermac architecture) we don't have
+ * separate IPIs for separate messages like openpic does.  Instead
+ * we have a bitmap for each processor, where a 1 bit means that
+ * the corresponding message is pending for that processor.
+ * Ideally each cpu's entry would be in a different cache line.
+ *  -- paulus.
+ */
+static unsigned long psurge_smp_message[NR_CPUS];
+
+void psurge_smp_message_recv(struct pt_regs *regs)
+{
+	int cpu = smp_processor_id();
+	int msg;
+
+	/* clear interrupt */
+	psurge_clr_ipi(cpu);
+
+	if (smp_num_cpus < 2)
+		return;
+
+	/* make sure there is a message there */
+	for (msg = 0; msg < 4; msg++)
+		if (test_and_clear_bit(msg, &psurge_smp_message[cpu]))
+			smp_message_recv(msg, regs);
+}
+
+void
+psurge_primary_intr(int irq, void *d, struct pt_regs *regs)
+{
+	psurge_smp_message_recv(regs);
+}
+
+static void
+smp_psurge_message_pass(int target, int msg, unsigned long data, int wait)
+{
+	int i;
+
+	if (smp_num_cpus < 2)
+		return;
+
+	for (i = 0; i < smp_num_cpus; i++) {
+		if (target == MSG_ALL
+		    || (target == MSG_ALL_BUT_SELF && i != smp_processor_id())
+		    || target == i) {
+			set_bit(msg, &psurge_smp_message[i]);
+			psurge_set_ipi(i);
+		}
+	}
+}
+
+/*
+ * Determine a quad card presence. We read the board ID register, we
+ * force the data bus to change to something else, and we read it again.
+ * It it's stable, then the register probably exist (ugh !)
+ */
+static int __init psurge_quad_probe(void)
+{
+	int type;
+	unsigned int i;
+
+	type = PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID);
+	if (type < PSURGE_QUAD_OKEE || type > PSURGE_QUAD_ICEGRASS
+	    || type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID))
+		return PSURGE_DUAL;
+
+	/* looks OK, try a slightly more rigorous test */
+	/* bogus is not necessarily cacheline-aligned,
+	   though I don't suppose that really matters.  -- paulus */
+	for (i = 0; i < 100; i++) {
+		volatile u32 bogus[8];
+		bogus[(0+i)%8] = 0x00000000;
+		bogus[(1+i)%8] = 0x55555555;
+		bogus[(2+i)%8] = 0xFFFFFFFF;
+		bogus[(3+i)%8] = 0xAAAAAAAA;
+		bogus[(4+i)%8] = 0x33333333;
+		bogus[(5+i)%8] = 0xCCCCCCCC;
+		bogus[(6+i)%8] = 0xCCCCCCCC;
+		bogus[(7+i)%8] = 0x33333333;
+		wmb();
+		asm volatile("dcbf 0,%0" : : "r" (bogus) : "memory");
+		mb();
+		if (type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID))
+			return PSURGE_DUAL;
+	}
+	return type;
+}
+
+static void __init psurge_quad_init(void)
+{
+	int procbits;
+
+	if (ppc_md.progress) ppc_md.progress("psurge_quad_init", 0x351);
+	procbits = ~PSURGE_QUAD_IN(PSURGE_QUAD_WHICH_CPU);
+	if (psurge_type == PSURGE_QUAD_ICEGRASS)
+		PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits);
+	else
+		PSURGE_QUAD_BIC(PSURGE_QUAD_CKSTOP_CTL, procbits);
+	mdelay(33);
+	out_8(psurge_sec_intr, ~0);
+	PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, procbits);
+	PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits);
+	if (psurge_type != PSURGE_QUAD_ICEGRASS)
+		PSURGE_QUAD_BIS(PSURGE_QUAD_CKSTOP_CTL, procbits);
+	PSURGE_QUAD_BIC(PSURGE_QUAD_PRIMARY_ARB, procbits);
+	mdelay(33);
+	PSURGE_QUAD_BIC(PSURGE_QUAD_RESET_CTL, procbits);
+	mdelay(33);
+	PSURGE_QUAD_BIS(PSURGE_QUAD_PRIMARY_ARB, procbits);
+	mdelay(33);
+}
+
+static int __init smp_psurge_probe(void)
+{
+	int i, ncpus;
+
+	/* We don't do SMP on the PPC601 -- paulus */
+	if (PVR_VER(mfspr(PVR)) == 1)
+		return 1;
+
+	/*
+	 * The powersurge cpu board can be used in the generation
+	 * of powermacs that have a socket for an upgradeable cpu card,
+	 * including the 7500, 8500, 9500, 9600.
+	 * The device tree doesn't tell you if you have 2 cpus because
+	 * OF doesn't know anything about the 2nd processor.
+	 * Instead we look for magic bits in magic registers,
+	 * in the hammerhead memory controller in the case of the
+	 * dual-cpu powersurge board.  -- paulus.
+	 */
+	if (find_devices("hammerhead") == NULL)
+		return 1;
+
+	hhead_base = ioremap(HAMMERHEAD_BASE, 0x800);
+	quad_base = ioremap(PSURGE_QUAD_REG_ADDR, 1024);
+	psurge_sec_intr = hhead_base + HHEAD_SEC_INTR;
+
+	psurge_type = psurge_quad_probe();
+	if (psurge_type != PSURGE_DUAL) {
+		psurge_quad_init();
+		/* All released cards using this HW design have 4 CPUs */
+		ncpus = 4;
+	} else {
+		iounmap((void *) quad_base);
+		if ((in_8(hhead_base + HHEAD_CONFIG) & 0x02) == 0) {
+			/* not a dual-cpu card */
+			iounmap((void *) hhead_base);
+			return 1;
+		}
+		ncpus = 2;
+	}
+
+	psurge_start = ioremap(PSURGE_START, 4);
+	psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4);
+
+	/* this is not actually strictly necessary -- paulus. */
+	for (i = 1; i < ncpus; ++i)
+		smp_hw_index[i] = i;
+
+	if (ppc_md.progress) ppc_md.progress("smp_psurge_probe - done", 0x352);
+
+	return ncpus;
+}
+
+static void __init smp_psurge_kick_cpu(int nr)
+{
+	void (*start)(void) = __secondary_start_psurge;
+	unsigned long a;
+
+	/* may need to flush here if secondary bats aren't setup */
+	for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)
+		asm volatile("dcbf 0,%0" : : "r" (a) : "memory");
+	asm volatile("sync");
+
+	if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu", 0x353);
+
+	/* setup entry point of secondary processor */
+	switch (nr) {
+	case 2:
+		start = __secondary_start_psurge2;
+		break;
+	case 3:
+		start = __secondary_start_psurge3;
+		break;
+	}
+
+	out_be32(psurge_start, __pa(start));
+	mb();
+
+	psurge_set_ipi(nr);
+	udelay(10);
+	psurge_clr_ipi(nr);
+
+	if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354);
+}
+
+/*
+ * With the dual-cpu powersurge board, the decrementers and timebases
+ * of both cpus are frozen after the secondary cpu is started up,
+ * until we give the secondary cpu another interrupt.  This routine
+ * uses this to get the timebases synchronized.
+ *  -- paulus.
+ */
+static void __init psurge_dual_sync_tb(int cpu_nr)
+{
+	static volatile int sec_tb_reset = 0;
+	int t;
+
+	set_dec(tb_ticks_per_jiffy);
+	set_tb(0, 0);
+	last_jiffy_stamp(cpu_nr) = 0;
+
+	if (cpu_nr > 0) {
+		mb();
+		sec_tb_reset = 1;
+		return;
+	}
+
+	/* wait for the secondary to have reset its TB before proceeding */
+	for (t = 10000000; t > 0 && !sec_tb_reset; --t)
+		;
+
+	/* now interrupt the secondary, starting both TBs */
+	psurge_set_ipi(1);
+
+	smp_tb_synchronized = 1;
+}
+
+static void __init
+smp_psurge_setup_cpu(int cpu_nr)
+{
+
+	if (cpu_nr == 0) {
+		if (smp_num_cpus < 2)
+			return;
+		/* reset the entry point so if we get another intr we won't
+		 * try to startup again */
+		out_be32(psurge_start, 0x100);
+		if (request_irq(30, psurge_primary_intr, 0, "primary IPI", 0))
+			printk(KERN_ERR "Couldn't get primary IPI interrupt");
+	}
+
+	if (psurge_type == PSURGE_DUAL)
+		psurge_dual_sync_tb(cpu_nr);
+}
+
+static int
+smp_core99_probe(void)
+{
+	struct device_node *cpus;
+	int i, ncpus = 1;
+
+	if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345);
+	cpus = find_type_devices("cpu");
+	if (cpus)
+		while ((cpus = cpus->next) != NULL)
+			++ncpus;
+	printk("smp_core99_probe: found %d cpus\n", ncpus);
+	if (ncpus > 1) {
+		openpic_request_IPIs();
+		for (i = 1; i < ncpus; ++i)
+			smp_hw_index[i] = i;
+	}
+
+	return ncpus;
+}
+
+static void
+smp_core99_kick_cpu(int nr)
+{
+	unsigned long save_vector, new_vector;
+	unsigned long flags;
+#if 1 /* New way... */
+	volatile unsigned long *vector
+		 = ((volatile unsigned long *)(KERNELBASE+0x100));
+	if (nr < 1 || nr > 3)
+		return;
+#else
+	volatile unsigned long *vector
+		 = ((volatile unsigned long *)(KERNELBASE+0x500));
+	if (nr != 1)
+		return;
+#endif
+	if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346);
+
+	local_irq_save(flags);
+	local_irq_disable();
+	
+	/* Save reset vector */
+	save_vector = *vector;
+	
+	/* Setup fake reset vector that does	  
+	 *   b __secondary_start_psurge - KERNELBASE
+	 */  
+	switch(nr) {
+		case 1:
+			new_vector = (unsigned long)__secondary_start_psurge;
+			break;
+		case 2:
+			new_vector = (unsigned long)__secondary_start_psurge2;
+			break;
+		case 3:
+			new_vector = (unsigned long)__secondary_start_psurge3;
+			break;
+	}
+	*vector = 0x48000002 + new_vector - KERNELBASE;
+	
+	/* flush data cache and inval instruction cache */
+	flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
+	
+	/* Put some life in our friend */
+	feature_core99_kick_cpu(nr);
+	
+	/* FIXME: We wait a bit for the CPU to take the exception, I should
+	 * instead wait for the entry code to set something for me. Well,
+	 * ideally, all that crap will be done in prom.c and the CPU left
+	 * in a RAM-based wait loop like CHRP.
+	 */
+	mdelay(1);
+	
+	/* Restore our exception vector */
+	*vector = save_vector;
+	flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
+	
+	local_irq_restore(flags);
+	if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347);
+}
+
+static void __init
+smp_core99_setup_cpu(int cpu_nr)
+{
+	/* Setup openpic */
+	do_openpic_setup_cpu();
+
+	/* Setup L2 */
+	if (cpu_nr != 0)
+		core99_init_l2();
+	else
+		if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349);
+}
+
+/* PowerSurge-style Macs */
+struct smp_ops_t psurge_smp_ops = {
+	smp_psurge_message_pass,
+	smp_psurge_probe,
+	smp_psurge_kick_cpu,
+	smp_psurge_setup_cpu,
+};
+
+/* Core99 Macs (dual G4s) */
+struct smp_ops_t core99_smp_ops = {
+	smp_openpic_message_pass,
+	smp_core99_probe,
+	smp_core99_kick_cpu,
+	smp_core99_setup_cpu,
+};
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/pmac_time.c linux/arch/ppc/kernel/pmac_time.c
--- v2.4.9/linux/arch/ppc/kernel/pmac_time.c	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/kernel/pmac_time.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.pmac_time.c 1.11 07/06/01 15:46:39 trini
+ * BK Id: SCCS/s.pmac_time.c 1.14 08/19/01 22:23:04 paulus
  */
 /*
  * Support for periodic interrupts (100 per second) and for getting
@@ -260,8 +260,13 @@
 	pmu_register_sleep_notifier(&time_sleep_notifier);
 #endif /* CONFIG_PMAC_PBOOK */
 
-	if (via_calibrate_decr())
-		return;
+	/* We assume MacRISC2 machines have correct device-tree
+	 * calibration. That's better since the VIA itself seems
+	 * to be slightly off. --BenH
+	 */
+	if (!machine_is_compatible("MacRISC2"))
+		if (via_calibrate_decr())
+			return;
 
 	/*
 	 * The cpu node should have a timebase-frequency property
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/ppc_asm.h linux/arch/ppc/kernel/ppc_asm.h
--- v2.4.9/linux/arch/ppc/kernel/ppc_asm.h	Wed Jul 25 17:10:18 2001
+++ linux/arch/ppc/kernel/ppc_asm.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.ppc_asm.h 1.14 07/02/01 22:08:05 paulus
+ * BK Id: SCCS/s.ppc_asm.h 1.16 08/15/01 22:43:06 paulus
  */
 /*
  * arch/ppc/kernel/ppc_asm.h
@@ -70,20 +70,35 @@
 #define REST_32VR(n,b,base)	REST_16VR(n,b,base); REST_16VR(n+16,b,base)
 
 #ifdef CONFIG_PPC601_SYNC_FIX
-#define SYNC \
-	sync; \
-	isync
+#define SYNC				\
+BEGIN_FTR_SECTION			\
+	sync;				\
+	isync;				\
+END_FTR_SECTION_IFSET(CPU_FTR_601)
+#define SYNC_601			\
+BEGIN_FTR_SECTION			\
+	sync;				\
+END_FTR_SECTION_IFSET(CPU_FTR_601)
+#define ISYNC_601			\
+BEGIN_FTR_SECTION			\
+	isync;				\
+END_FTR_SECTION_IFSET(CPU_FTR_601)
 #else
 #define	SYNC
+#define SYNC_601
+#define ISYNC_601
 #endif
 
 #ifndef CONFIG_SMP
 #define TLBSYNC
 #else /* CONFIG_SMP */
+/* tlbsync is not implemented on 601 */
 #define TLBSYNC				\
+BEGIN_FTR_SECTION			\
 	tlbsync;			\
-	sync
-#endif /* CONFIG_SMP */
+	sync;				\
+END_FTR_SECTION_IFCLR(CPU_FTR_601)
+#endif
 
 /*
  * This instruction is not implemented on the PPC 603 or 601; however, on
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/ppc_htab.c linux/arch/ppc/kernel/ppc_htab.c
--- v2.4.9/linux/arch/ppc/kernel/ppc_htab.c	Tue Jul  3 17:08:18 2001
+++ linux/arch/ppc/kernel/ppc_htab.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.ppc_htab.c 1.11 06/28/01 15:50:16 paulus
+ * BK Id: SCCS/s.ppc_htab.c 1.17 08/20/01 22:59:41 paulus
  */
 /*
  * PowerPC hash table management proc entry.  Will show information
@@ -20,6 +20,7 @@
 #include <linux/stat.h>
 #include <linux/sysctl.h>
 #include <linux/ctype.h>
+#include <linux/threads.h>
 
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
@@ -28,6 +29,8 @@
 #include <asm/residual.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
+#include <asm/cputable.h>
+#include <asm/system.h>
 
 static ssize_t ppc_htab_read(struct file * file, char * buf,
 			     size_t count, loff_t *ppos);
@@ -67,7 +70,7 @@
         write:          ppc_htab_write,
 };
 
-char *pmc1_lookup(unsigned long mmcr0)
+static char *pmc1_lookup(unsigned long mmcr0)
 {
 	switch ( mmcr0 & (0x7f<<7) )
 	{
@@ -84,7 +87,7 @@
 	}
 }	
 
-char *pmc2_lookup(unsigned long mmcr0)
+static char *pmc2_lookup(unsigned long mmcr0)
 {
 	switch ( mmcr0 & 0x3f )
 	{
@@ -121,11 +124,7 @@
 	if (count < 0)
 		return -EINVAL;
 
-	switch ( _get_PVR()>>16 )
-	{
-	case 4:  /* 604 */
-	case 9:  /* 604e */
-	case 10: /* 604ev5 */
+	if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
 		asm volatile ("mfspr %0,952 \n\t"
 		    "mfspr %1,953 \n\t"
 		    "mfspr %2,954 \n\t"
@@ -141,12 +140,9 @@
 			      "PMC2\t\t: %08lx (%s)\n",
 			      pmc1, pmc1_lookup(mmcr0),
 			      pmc2, pmc2_lookup(mmcr0));
-		break;
-	default:
-		break;
 	}
 
-	
+#ifdef CONFIG_PPC_STD_MMU
 	/* if we don't have a htab */
 	if ( Hash_size == 0 )
 	{
@@ -154,7 +150,6 @@
 		goto return_string;
 	}
 
-#if !defined(CONFIG_8xx) && !defined(CONFIG_4xx)
 	for ( ptr = Hash ; ptr < Hash_end ; ptr++)
 	{
 		unsigned int ctx, mctx, vsid;
@@ -211,7 +206,7 @@
 		      "Evicts\t\t: %lu\n",
 		      htab_reloads, htab_preloads, htab_hash_searches,
 		      primary_pteg_full, htab_evicts);
-#endif /* !8xx && !4xx */
+#endif /* CONFIG_PPC_STD_MMU */
 	
 return_string:
 	n += sprintf( buffer + n,
@@ -235,7 +230,7 @@
 static ssize_t ppc_htab_write(struct file * file, const char * buffer,
 			      size_t count, loff_t *ppos)
 {
-#ifndef CONFIG_8xx
+#ifdef CONFIG_PPC_STD_MMU
 	unsigned long tmp;
 	if ( current->uid != 0 )
 		return -EACCES;
@@ -246,37 +241,22 @@
 	/* turn off performance monitoring */
 	if ( !strncmp( buffer, "off", 3) )
 	{
-		switch ( _get_PVR()>>16 )
-		{
-		case 4:  /* 604 */
-		case 9:  /* 604e */
-		case 10: /* 604ev5 */
+		if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
 			asm volatile ("mtspr %0, %3 \n\t"
 			    "mtspr %1, %3 \n\t"
 			    "mtspr %2, %3 \n\t"			    
 			    :: "i" (MMCR0), "i" (PMC1), "i" (PMC2), "r" (0));
-			break;
-		default:
-			break;
 		}
-			
 	}
 
 	if ( !strncmp( buffer, "reset", 5) )
 	{
-		switch ( _get_PVR()>>16 )
-		{
-		case 4:  /* 604 */
-		case 9:  /* 604e */
-		case 10: /* 604ev5 */
+		if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
 			/* reset PMC1 and PMC2 */
 			asm volatile (
 				"mtspr 953, %0 \n\t"
 				"mtspr 954, %0 \n\t"
 				:: "r" (0));
-			break;
-		default:
-			break;
 		}
 		htab_reloads = 0;
 		htab_evicts = 0;
@@ -286,11 +266,7 @@
 
 	if ( !strncmp( buffer, "user", 4) )
 	{
-		switch ( _get_PVR()>>16 )
-		{
-		case 4:  /* 604 */
-		case 9:  /* 604e */
-		case 10: /* 604ev5 */
+		if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
 			/* setup mmcr0 and clear the correct pmc */
 			asm("mfspr %0,%1\n\t"  : "=r" (tmp) : "i" (MMCR0));
 			tmp &= ~(0x60000000);
@@ -301,19 +277,12 @@
 				"mtspr %5,%4 \n\t"    /* reset the pmc2 */
 				:: "r" (tmp), "i" (MMCR0), "i" (0),
 				"i" (PMC1),  "r" (0), "i"(PMC2) );
-			break;
-		default:
-			break;
 		}
 	}
 
 	if ( !strncmp( buffer, "kernel", 6) )
 	{
-		switch ( _get_PVR()>>16 )
-		{
-		case 4:  /* 604 */
-		case 9:  /* 604e */
-		case 10: /* 604ev5 */
+		if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
 			/* setup mmcr0 and clear the correct pmc */
 			asm("mfspr %0,%1\n\t"  : "=r" (tmp) : "i" (MMCR0));
 			tmp &= ~(0x60000000);
@@ -324,20 +293,13 @@
 				"mtspr %5,%4 \n\t"    /* reset the pmc2 */
 				:: "r" (tmp), "i" (MMCR0), "i" (0),
 				"i" (PMC1),  "r" (0), "i"(PMC2) );
-			break;
-		default:
-			break;
 		}
 	}
 	
 	/* PMC1 values */
 	if ( !strncmp( buffer, "dtlb", 4) )
 	{
-		switch ( _get_PVR()>>16 )
-		{
-		case 4:  /* 604 */
-		case 9:  /* 604e */
-		case 10: /* 604ev5 */
+		if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
 			/* setup mmcr0 and clear the correct pmc */
 			asm("mfspr %0,%1\n\t"  : "=r" (tmp) : "i" (MMCR0));
 			tmp &= ~(0x7f<<7);
@@ -352,11 +314,7 @@
 
 	if ( !strncmp( buffer, "ic miss", 7) )
 	{
-		switch ( _get_PVR()>>16 )
-		{
-		case 4:  /* 604 */
-		case 9:  /* 604e */
-		case 10: /* 604ev5 */
+		if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
 			/* setup mmcr0 and clear the correct pmc */
 			asm("mfspr %0,%1\n\t"  : "=r" (tmp) : "i" (MMCR0));
 			tmp &= ~(0x7f<<7);
@@ -372,11 +330,7 @@
 	/* PMC2 values */
 	if ( !strncmp( buffer, "load miss time", 14) )
 	{
-		switch ( _get_PVR()>>16 )
-		{
-		case 4:  /* 604 */
-		case 9:  /* 604e */
-		case 10: /* 604ev5 */
+		if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
 			/* setup mmcr0 and clear the correct pmc */
 		       asm volatile(
 			       "mfspr %0,%1\n\t"     /* get current mccr0 */
@@ -392,11 +346,7 @@
 	
 	if ( !strncmp( buffer, "itlb", 4) )
 	{
-		switch ( _get_PVR()>>16 )
-		{
-		case 4:  /* 604 */
-		case 9:  /* 604e */
-		case 10: /* 604ev5 */
+		if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
 			/* setup mmcr0 and clear the correct pmc */
 		       asm volatile(
 			       "mfspr %0,%1\n\t"     /* get current mccr0 */
@@ -412,11 +362,7 @@
 
 	if ( !strncmp( buffer, "dc miss", 7) )
 	{
-		switch ( _get_PVR()>>16 )
-		{
-		case 4:  /* 604 */
-		case 9:  /* 604e */
-		case 10: /* 604ev5 */
+		if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
 			/* setup mmcr0 and clear the correct pmc */
 		       asm volatile(
 			       "mfspr %0,%1\n\t"     /* get current mccr0 */
@@ -472,9 +418,9 @@
 	reset_SDR1();
 #endif	
 	return count;
-#else /* CONFIG_8xx */
+#else /* CONFIG_PPC_STD_MMU */
 	return 0;
-#endif /* CONFIG_8xx */
+#endif /* CONFIG_PPC_STD_MMU */
 }
 
 
@@ -516,7 +462,7 @@
 		"0.5", "1.0", "(reserved2)", "(reserved3)"
 	};
 
-	if ( ((_get_PVR() >> 16) != 8) && ((_get_PVR() >> 16) != 12))
+	if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR))
 		return -EFAULT;
 	
 	if ( /*!table->maxlen ||*/ (filp->f_pos && !write)) {
@@ -526,7 +472,7 @@
 	
 	vleft = table->maxlen / sizeof(int);
 	left = *lenp;
-	
+
 	for (; left /*&& vleft--*/; first=0) {
 		if (write) {
 			while (left) {
@@ -556,7 +502,6 @@
 			buffer += len;
 			left -= len;
 			_set_L2CR(val);
-			  
 		} else {
 			p = buf;
 			if (!first)
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/ppc_ksyms.c linux/arch/ppc/kernel/ppc_ksyms.c
--- v2.4.9/linux/arch/ppc/kernel/ppc_ksyms.c	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/kernel/ppc_ksyms.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.ppc_ksyms.c 1.38 07/23/01 15:35:53 trini
+ * BK Id: SCCS/s.ppc_ksyms.c 1.51 08/24/01 17:05:47 paulus
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -48,6 +48,8 @@
 #include <asm/smp.h>
 #endif /* CONFIG_SMP */
 #include <asm/time.h>
+#include <asm/cputable.h>
+#include <asm/btext.h>
 
 #ifdef  CONFIG_8xx
 #include "../8xx_io/commproc.h"
@@ -73,6 +75,8 @@
 int abs(int);
 extern unsigned long ret_to_user_hook;
 
+extern unsigned long mm_ptov (unsigned long paddr);
+
 EXPORT_SYMBOL(clear_page);
 EXPORT_SYMBOL(do_signal);
 EXPORT_SYMBOL(syscall_trace);
@@ -157,16 +161,10 @@
 EXPORT_SYMBOL(ioremap);
 EXPORT_SYMBOL(__ioremap);
 EXPORT_SYMBOL(iounmap);
+EXPORT_SYMBOL(iopa);
+EXPORT_SYMBOL(mm_ptov);
 
-EXPORT_SYMBOL(ide_insw);
-EXPORT_SYMBOL(ide_outsw);
 EXPORT_SYMBOL(ppc_ide_md);
-#ifdef CONFIG_BLK_DEV_IDE_MODULE
-EXPORT_SYMBOL(chrp_ide_irq);
-EXPORT_SYMBOL(chrp_ide_ports_known);
-EXPORT_SYMBOL(chrp_ide_regbase);
-EXPORT_SYMBOL(chrp_ide_probe);
-#endif
 
 #ifdef CONFIG_PCI
 EXPORT_SYMBOL_NOVERS(isa_io_base);
@@ -183,10 +181,10 @@
 /*EXPORT_SYMBOL(_disable_interrupts);
   EXPORT_SYMBOL(_enable_interrupts);*/
 EXPORT_SYMBOL(flush_instruction_cache);
-EXPORT_SYMBOL(_get_PVR);
 EXPORT_SYMBOL(giveup_fpu);
 EXPORT_SYMBOL(enable_kernel_fp);
 EXPORT_SYMBOL(flush_icache_range);
+EXPORT_SYMBOL(flush_dcache_range);
 EXPORT_SYMBOL(xchg_u32);
 #ifdef CONFIG_ALTIVEC
 EXPORT_SYMBOL(last_task_used_altivec);
@@ -200,6 +198,7 @@
 EXPORT_SYMBOL(__global_sti);
 EXPORT_SYMBOL(__global_save_flags);
 EXPORT_SYMBOL(__global_restore_flags);
+#ifdef SPINLOCK_DEBUG
 EXPORT_SYMBOL(_spin_lock);
 EXPORT_SYMBOL(_spin_unlock);
 EXPORT_SYMBOL(spin_trylock);
@@ -207,6 +206,7 @@
 EXPORT_SYMBOL(_read_unlock);
 EXPORT_SYMBOL(_write_lock);
 EXPORT_SYMBOL(_write_unlock);
+#endif
 EXPORT_SYMBOL(smp_call_function);
 EXPORT_SYMBOL(smp_hw_index);
 EXPORT_SYMBOL(smp_num_cpus);
@@ -226,17 +226,6 @@
 EXPORT_SYMBOL(cuda_request);
 EXPORT_SYMBOL(cuda_poll);
 #endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_ADB_PMU
-EXPORT_SYMBOL(pmu_request);
-EXPORT_SYMBOL(pmu_poll);
-EXPORT_SYMBOL(pmu_suspend);
-EXPORT_SYMBOL(pmu_resume);
-#endif /* CONFIG_ADB_PMU */
-#ifdef CONFIG_PMAC_PBOOK
-EXPORT_SYMBOL(pmu_register_sleep_notifier);
-EXPORT_SYMBOL(pmu_unregister_sleep_notifier);
-EXPORT_SYMBOL(pmu_enable_irled);
-#endif /* CONFIG_PMAC_PBOOK */
 #ifdef CONFIG_PMAC_BACKLIGHT
 EXPORT_SYMBOL(get_backlight_level);
 EXPORT_SYMBOL(set_backlight_level);
@@ -245,7 +234,6 @@
 #endif /* CONFIG_PMAC_BACKLIGHT */
 #if defined(CONFIG_ALL_PPC)
 EXPORT_SYMBOL(_machine);
-EXPORT_SYMBOL_NOVERS(have_of);
 EXPORT_SYMBOL_NOVERS(sys_ctrler);
 EXPORT_SYMBOL(find_devices);
 EXPORT_SYMBOL(find_type_devices);
@@ -273,10 +261,11 @@
 EXPORT_SYMBOL(feature_set_usb_power);
 EXPORT_SYMBOL(feature_set_firewire_power);
 EXPORT_SYMBOL(feature_set_firewire_cable_power);
+EXPORT_SYMBOL(feature_set_modem_power);
 EXPORT_SYMBOL(feature_set_airport_power);
 #endif /* defined(CONFIG_ALL_PPC) */
 #if defined(CONFIG_BOOTX_TEXT)
-EXPORT_SYMBOL(bootx_update_display);
+EXPORT_SYMBOL(btext_update_display);
 #endif
 #if defined(CONFIG_SCSI) && defined(CONFIG_ALL_PPC)
 EXPORT_SYMBOL(note_scsi_host);
@@ -303,7 +292,7 @@
 
 EXPORT_SYMBOL(abs);
 
-#ifdef CONFIG_VT
+#ifdef CONFIG_VGA_CONSOLE
 EXPORT_SYMBOL(screen_info);
 #endif
 
@@ -367,3 +356,4 @@
 #endif
 extern long *ret_from_intercept;
 EXPORT_SYMBOL(ret_from_intercept);
+EXPORT_SYMBOL(cur_cpu_spec);
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/prep_pci.c linux/arch/ppc/kernel/prep_pci.c
--- v2.4.9/linux/arch/ppc/kernel/prep_pci.c	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/kernel/prep_pci.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.prep_pci.c 1.22 08/05/01 16:18:54 trini
+ * BK Id: SCCS/s.prep_pci.c 1.24 08/20/01 15:06:15 paulus
  */
 /*
  * PReP pci functions.
@@ -172,7 +172,7 @@
 	0,	/* Slot 7  - unused */
 	0,	/* Slot 8  - unused */
 	0,	/* Slot 9  - unused */
-	0,	/* Slot 10 - unxued */
+	0,	/* Slot 10 - unused */
 	0,	/* Slot 11 - unused */
 	0,	/* Slot 12 - unused */
 	0,	/* Slot 13 - unused */
@@ -200,7 +200,7 @@
 	0,      /* Slot 7  - unused */
 	0,      /* Slot 8  - unused */
 	0,      /* Slot 9  - unused */
-	0,      /* Slot 10 - unxued */
+	0,      /* Slot 10 - unused */
 	0,      /* Slot 11 - unused */
 	0,      /* Slot 12 - unused */
 	0,      /* Slot 13 - unused */
@@ -322,8 +322,8 @@
 	3,	/* Slot 12 - unused */
 	0,	/* Slot 13 - unused */
 	2,	/* Slot 14 - SCSI */
-	0,	/* Slot 15 - graphics on 3600 */
-	9,	/* Slot 16 - PMC */
+	0,	/* Slot 15 - unused */
+	9,	/* Slot 16 - PMC 1 */
 	12,	/* Slot 17 - pci */
 	11,	/* Slot 18 - pci */
 	10,	/* Slot 19 - pci */
@@ -511,6 +511,44 @@
         13      /* Line 4 */
 };
 
+/*
+ * IBM RS/6000 43p/140  -- paulus
+ * XXX we should get all this from the residual data
+ */
+static char ibm43p_pci_IRQ_map[23] __prepdata = {
+        0, /* Slot 0  - unused */
+        0, /* Slot 1  - unused */
+        0, /* Slot 2  - unused */
+        0, /* Slot 3  - unused */
+        0, /* Slot 4  - unused */
+        0, /* Slot 5  - unused */
+        0, /* Slot 6  - unused */
+        0, /* Slot 7  - unused */
+        0, /* Slot 8  - unused */
+        0, /* Slot 9  - unused */
+        0, /* Slot 10 - unused */
+        0, /* Slot 11 - FireCoral ISA bridge */
+        6, /* Slot 12 - Ethernet  */
+        0, /* Slot 13 - openpic */
+        0, /* Slot 14 - unused */
+        0, /* Slot 15 - unused */
+        7, /* Slot 16 - NCR58C825a onboard scsi */
+        0, /* Slot 17 - unused */
+        2, /* Slot 18 - PCI Slot 2 PCIINTx# (See below) */
+        0, /* Slot 19 - unused */
+        0, /* Slot 20 - unused */
+        0, /* Slot 21 - unused */
+        1, /* Slot 22 - PCI slot 1 PCIINTx# (See below) */
+};
+
+static char ibm43p_pci_IRQ_routes[] __prepdata = {
+        0,      /* Line 0 - unused */
+        15,     /* Line 1 */
+        15,     /* Line 2 */
+        15,     /* Line 3 */
+        15,     /* Line 4 */
+};
+
 /* Motorola PowerPlus architecture PCI IRQ tables */
 /* Interrupt line values for INTA-D on primary/secondary MPIC inputs */
 
@@ -767,7 +805,52 @@
 	{0x000, 0x00, 0x00, "",					NULL,			NULL, NULL, NULL, 0x00}
 };
 
-unsigned long __init prep_route_pci_interrupts(void)
+void ibm_prep_init(void)
+{
+	u32 addr;
+#ifdef CONFIG_PREP_RESIDUAL
+	PPC_DEVICE *mpic;
+#endif
+
+	if (inb(0x0852) == 0xd5) {
+		/* This is for the 43p-140 */
+		early_read_config_dword(0, 0, PCI_DEVFN(13, 0),
+					PCI_BASE_ADDRESS_0, &addr);
+		if (addr != 0xffffffff
+		    && !(addr & PCI_BASE_ADDRESS_SPACE_IO)
+		    && (addr &= PCI_BASE_ADDRESS_MEM_MASK) != 0) {
+			addr += PREP_ISA_MEM_BASE;
+			OpenPIC_Addr = ioremap(addr, 0x40000);
+			ppc_md.get_irq = openpic_get_irq;
+		}
+	}
+
+#ifdef CONFIG_PREP_RESIDUAL
+	mpic = residual_find_device(-1, NULL, SystemPeripheral,
+				    ProgrammableInterruptController, MPIC, 0);
+	if (mpic != NULL) {
+		printk("mpic = %p\n", mpic);
+	}
+#endif
+}
+
+void
+ibm43p_pci_map_non0(struct pci_dev *dev)
+{
+	unsigned char intpin;
+	static unsigned char bridge_intrs[4] = { 3, 4, 5, 8 };
+
+	if (dev == NULL)
+		return;
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &intpin);
+	if (intpin < 1 || intpin > 4)
+		return;
+	intpin = (PCI_SLOT(dev->devfn) + intpin - 1) & 3;
+	dev->irq = openpic_to_irq(bridge_intrs[intpin]);
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+}
+
+void __init prep_route_pci_interrupts(void)
 {
 	unsigned char *ibc_pirq = (unsigned char *)0x80800860;
 	unsigned char *ibc_pcicon = (unsigned char *)0x80800840;
@@ -856,7 +939,13 @@
 			Motherboard_map_name = "IBM 6015";
 			Motherboard_map = ibm6015_pci_IRQ_map;
 			Motherboard_routes = ibm6015_pci_IRQ_routes;
-			break;			
+			break;
+		case 0xd5:
+			Motherboard_map_name = "IBM 43p/140";
+			Motherboard_map = ibm43p_pci_IRQ_map;
+			Motherboard_routes = ibm43p_pci_IRQ_routes;
+			Motherboard_non0 = ibm43p_pci_map_non0;
+			break;
 		default:
 			Motherboard_map_name = "IBM 8xx (Carolina)";
 			Motherboard_map = ibm8xx_pci_IRQ_map;
@@ -878,7 +967,7 @@
 	else
 	{
 		printk("No known machine pci routing!\n");
-		return -1;
+		return;
 	}
 	
 	/* Set up mapping from slots */
@@ -888,16 +977,15 @@
 	}
 	/* Enable PCI interrupts */
 	*ibc_pcicon |= 0x20;
-	return 0;
 }
 
 void __init
 prep_pib_init(void)
 {
-unsigned char   reg;
-unsigned short  short_reg;
+	unsigned char   reg;
+	unsigned short  short_reg;
 
-struct pci_dev *dev = NULL;
+	struct pci_dev *dev = NULL;
 
 	if (( _prep_type == _PREP_Motorola) && (OpenPIC_Addr)) {
 		/*
@@ -910,43 +998,47 @@
 			 * PPCBUG does not set the enable bits
 			 * for the IDE device. Force them on here.
 			 */
-			pcibios_read_config_byte(dev->bus->number, 
-					dev->devfn, 0x40, &reg);
+			pci_read_config_byte(dev, 0x40, &reg);
 
 			reg |= 0x03; /* IDE: Chip Enable Bits */
-			pcibios_write_config_byte(dev->bus->number, 
-					dev->devfn, 0x40, reg);
-
-			/* Force correct IDE function interrupt */
-			dev->irq = 14;
-			pcibios_write_config_byte(dev->bus->number,
-					dev->devfn,
+			pci_write_config_byte(dev, 0x40, reg);
+		}
+		if ((dev = pci_find_device(PCI_VENDOR_ID_VIA,
+						PCI_DEVICE_ID_VIA_82C586_2,
+						dev)) && (dev->devfn = 0x5a)) {
+			/* Force correct USB interrupt */
+			dev->irq = 11;
+			pci_write_config_byte(dev,
 					PCI_INTERRUPT_LINE,
 					dev->irq);
-
-		} else if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND, 
+		}
+		if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND,
 					PCI_DEVICE_ID_WINBOND_83C553, dev))) {
-			/*
-			 * Clear the PCI Interrupt Routing Control Register.
-			 */
+			 /* Clear PCI Interrupt Routing Control Register. */
 			short_reg = 0x0000;
 			pci_write_config_word(dev, 0x44, short_reg);
 			if (OpenPIC_Addr){
-				/*
-				 * Route both IDE interrupts to IRQ 14
-				 */
+				/* Route IDE interrupts to IRQ 14 */
 				reg = 0xEE;
-				pci_write_config_byte(dev, 0x44, reg);
+				pci_write_config_byte(dev, 0x43, reg);
 			}
 		}
 	}
+
 	if ((dev = pci_find_device(PCI_VENDOR_ID_WINBOND,
 				   PCI_DEVICE_ID_WINBOND_82C105, dev))){
 		if (OpenPIC_Addr){
-			/* Disable LEGIRQ mode so PCI INTs are routed to
-			   the 8259 */
-			printk("Set winbond IDE to native mode\n");
-			pci_write_config_dword(dev, 0x40, 0x10ff00a1);
+			/*
+			 * Disable LEGIRQ mode so PCI INTS are routed
+			 * directly to the 8259 and enable both channels
+			 */
+			pci_write_config_dword(dev, 0x40, 0x10ff0033);
+
+			/* Force correct IDE interrupt */
+			dev->irq = 14;
+			pci_write_config_byte(dev,
+					PCI_INTERRUPT_LINE,
+					dev->irq);
 		}else{
 			/* Enable LEGIRQ for PCI INT -> 8259 IRQ routing */
 			pci_write_config_dword(dev, 0x40, 0x10ff08a1);
@@ -1106,6 +1198,19 @@
 	}
 }
 
+static void __init
+prep_init_resource(struct resource *res, unsigned long start,
+		   unsigned long end, int flags)
+{
+	res->flags = flags;
+	res->start = start;
+	res->end = end;
+	res->name = "PCI host bridge";
+	res->parent = NULL;
+	res->sibling = NULL;
+	res->child = NULL;
+}
+
 void __init
 prep_find_bridges(void)
 {
@@ -1119,6 +1224,9 @@
 	hose->last_busno = 0xff;
 	hose->pci_mem_offset = PREP_ISA_MEM_BASE;
 	hose->io_base_virt = (void *)PREP_ISA_IO_BASE;
+	prep_init_resource(&hose->io_resource, 0, 0x0fffffff, IORESOURCE_IO);
+	prep_init_resource(&hose->mem_resources[0], 0xc0000000, 0xfeffffff,
+			   IORESOURCE_MEM);
 	
 	printk("PReP architecture\n");
 	{
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/prep_setup.c linux/arch/ppc/kernel/prep_setup.c
--- v2.4.9/linux/arch/ppc/kernel/prep_setup.c	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/kernel/prep_setup.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.prep_setup.c 1.26 08/05/01 16:18:54 trini
+ * BK Id: SCCS/s.prep_setup.c 1.32 08/20/01 15:06:15 paulus
  */
 /*
  *  linux/arch/ppc/kernel/setup.c
@@ -7,6 +7,9 @@
  *  Copyright (C) 1995  Linus Torvalds
  *  Adapted from 'alpha' version by Gary Thomas
  *  Modified by Cort Dougan (cort@cs.nmt.edu)
+ *
+ * Support for PReP (Motorola MTX/MVME)
+ * by Troy Benjegerdes (hozer@drgw.net)
  */
 
 /*
@@ -78,6 +81,7 @@
 extern unsigned char rs_nvram_read_val(int addr);
 extern void rs_nvram_write_val(int addr,
 				 unsigned char val);
+extern void ibm_prep_init(void);
 
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
@@ -85,6 +89,7 @@
 			   char raw_mode);
 extern char pckbd_unexpected_up(unsigned char keycode);
 extern void pckbd_leds(unsigned char leds);
+extern int pckbd_rate(struct kbd_repeat *rep);
 extern void pckbd_init_hw(void);
 extern unsigned char pckbd_sysrq_xlate[128];
 
@@ -329,13 +334,20 @@
 
 	/*print_residual_device_info();*/
 
-	raven_init();
+	switch (_prep_type) {
+	case _PREP_Motorola:
+		raven_init();
+		break;
+	case _PREP_IBM:
+		ibm_prep_init();
+		break;
+	}
 
 #ifdef CONFIG_VGA_CONSOLE
 	/* remap the VGA memory */
 	vgacon_remap_base = 0xf0000000;
 	/*vgacon_remap_base = ioremap(0xc0000000, 0xba000);*/
-        conswitchp = &vga_con;
+	conswitchp = &vga_con;
 #elif defined(CONFIG_DUMMY_CONSOLE)
 	conswitchp = &dummy_con;
 #endif
@@ -662,23 +674,6 @@
 	}
 }
 
-#if 0
-void __prep
-prep_do_IRQ(struct pt_regs *regs, int cpu)
-{
-        int irq;
-
-	if ( (irq = i8259_irq(0)) < 0 )
-	{
-		printk(KERN_DEBUG "Bogus interrupt from PC = %lx\n",
-		       regs->nip);
-		ppc_spurious_interrupts++;
-		return;
-	}
-        ppc_irq_dispatch_handler( regs, irq );
-}
-#endif
-
 int __prep
 prep_get_irq(struct pt_regs *regs)
 {
@@ -701,18 +696,6 @@
 /*
  * IDE stuff.
  */
-void __prep
-prep_ide_insw(ide_ioreg_t port, void *buf, int ns)
-{
-	_insw((unsigned short *)((port)+_IO_BASE), buf, ns);
-}
-
-void __prep
-prep_ide_outsw(ide_ioreg_t port, void *buf, int ns)
-{
-	_outsw((unsigned short *)((port)+_IO_BASE), buf, ns);
-}
-
 int __prep
 prep_ide_default_irq(ide_ioreg_t base)
 {
@@ -721,8 +704,9 @@
 		case 0x170: return 13;
 		case 0x1e8: return 11;
 		case 0x168: return 10;
-		default:
-                        return 0;
+		case 0xfff0: return 14;		/* MCP(N)750 ide0 */
+		case 0xffe0: return 15;		/* MCP(N)750 ide1 */
+		default: return 0;
 	}
 }
 
@@ -780,6 +764,45 @@
 }
 #endif
 
+#ifdef CONFIG_SMP
+/* PReP (MTX) support */
+static int
+smp_prep_probe(void)
+{
+	extern int mot_multi;
+
+	if (mot_multi) {
+		openpic_request_IPIs();
+		smp_hw_index[1] = 1;
+		return 2;
+	}
+
+	return 1;
+}
+
+static void
+smp_prep_kick_cpu(int nr)
+{
+	*(unsigned long *)KERNELBASE = nr;
+	asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
+	printk("CPU1 reset, waiting\n");
+}
+
+static void
+smp_prep_setup_cpu(int cpu_nr)
+{
+	if (OpenPIC_Addr)
+		do_openpic_setup_cpu();
+}
+
+static struct smp_ops_t prep_smp_ops = {
+	smp_openpic_message_pass,
+	smp_prep_probe,
+	smp_prep_kick_cpu,
+	smp_prep_setup_cpu,
+};
+#endif /* CONFIG_SMP */
+
 /*
  * This finds the amount of physical ram and does necessary
  * setup for prep.  This is pretty architecture specific so
@@ -788,29 +811,39 @@
  */
 unsigned long __init prep_find_end_of_memory(void)
 {
-	unsigned long total;
+	unsigned long total = 0;
+	extern unsigned int boot_mem_size;
+
 #ifdef CONFIG_PREP_RESIDUAL	
 	total = res->TotalMemory;
-#else
-	total = 0;
 #endif	
 
-	if (total == 0 )
-	{
+	if (total == 0 && boot_mem_size != 0)
+		total = boot_mem_size;
+
+	if (total == 0) {
 		/*
 		 * I need a way to probe the amount of memory if the residual
 		 * data doesn't contain it. -- Cort
 		 */
-		printk("Ramsize from residual data was 0 -- Probing for value\n");
 		total = 0x02000000;
-		printk("Ramsize default to be %ldM\n", total>>20);
+		printk(KERN_INFO "Ramsize from residual data was 0"
+		       " -- defaulting to %ldM\n", total>>20);
 	}
 
 	return (total);
 }
 
-unsigned long *MotSave_SmpIar;
-unsigned char *MotSave_CpusState[2];
+/*
+ * Setup the bat mappings we're going to load that cover
+ * the io areas.  RAM was mapped by mapin_ram().
+ * -- Cort
+ */
+void __init prep_map_io(void)
+{
+	io_block_mapping(0x80000000, 0x80000000, 0x10000000, _PAGE_IO);
+	io_block_mapping(0xf0000000, 0xc0000000, 0x08000000, _PAGE_IO);
+}
 
 void __init
 prep_init2(void)
@@ -838,13 +871,6 @@
 	{
 		memcpy((void *)res,(void *)(r3+KERNELBASE),
 		       sizeof(RESIDUAL));
-
-		/* These need to be saved for the Motorola Prep 
-		 * MVME4600 and Dual MTX boards.
-		 */
-		MotSave_SmpIar = &old_res->VitalProductData.SmpIar;
-		MotSave_CpusState[0] = &old_res->Cpus[0].CpuState;
-		MotSave_CpusState[1] = &old_res->Cpus[1].CpuState;
 	}
 #endif
 
@@ -912,19 +938,16 @@
 	}
 
 	ppc_md.find_end_of_memory = prep_find_end_of_memory;
+	ppc_md.setup_io_mappings = prep_map_io;
 
 #if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-        ppc_ide_md.insw = prep_ide_insw;
-        ppc_ide_md.outsw = prep_ide_outsw;
         ppc_ide_md.default_irq = prep_ide_default_irq;
         ppc_ide_md.default_io_base = prep_ide_default_io_base;
         ppc_ide_md.ide_check_region = prep_ide_check_region;
         ppc_ide_md.ide_request_region = prep_ide_request_region;
         ppc_ide_md.ide_release_region = prep_ide_release_region;
-        ppc_ide_md.fix_driveid = NULL;
         ppc_ide_md.ide_init_hwif = prep_ide_init_hwif_ports;
-#endif		
-        ppc_ide_md.io_base = _IO_BASE;
+#endif
 
 #ifdef CONFIG_VT
 	ppc_md.kbd_setkeycode    = pckbd_setkeycode;
@@ -932,10 +955,15 @@
 	ppc_md.kbd_translate     = pckbd_translate;
 	ppc_md.kbd_unexpected_up = pckbd_unexpected_up;
 	ppc_md.kbd_leds          = pckbd_leds;
+	ppc_md.kbd_rate_fn	 = pckbd_rate;
 	ppc_md.kbd_init_hw       = pckbd_init_hw;
 #ifdef CONFIG_MAGIC_SYSRQ
 	ppc_md.ppc_kbd_sysrq_xlate	 = pckbd_sysrq_xlate;
 	SYSRQ_KEY = 0x54;
 #endif
 #endif
+
+#ifdef CONFIG_SMP
+	ppc_md.smp_ops		 = &prep_smp_ops;
+#endif /* CONFIG_SMP */
 }
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/process.c linux/arch/ppc/kernel/process.c
--- v2.4.9/linux/arch/ppc/kernel/process.c	Wed Jul 25 17:10:18 2001
+++ linux/arch/ppc/kernel/process.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.process.c 1.23 07/19/01 23:02:48 paulus
+ * BK Id: SCCS/s.process.c 1.27 08/28/01 22:01:21 paulus
  */
 /*
  *  linux/arch/ppc/kernel/process.c
@@ -59,8 +59,6 @@
 };
 /* only used to get secondary processor up */
 struct task_struct *current_set[NR_CPUS] = {&init_task, };
-char *sysmap = NULL; 
-unsigned long sysmap_size = 0;
 
 #undef SHOW_TASK_SWITCHES
 #undef CHECK_STACK
@@ -324,7 +322,6 @@
 	    unsigned long unused,
 	    struct task_struct *p, struct pt_regs *regs)
 {
-	unsigned long msr;
 	struct pt_regs *childregs, *kregs;
 	extern void ret_from_fork(void);
 	unsigned long sp = (unsigned long)p + sizeof(union task_union);
@@ -362,11 +359,12 @@
 	 * copy fpu info - assume lazy fpu switch now always
 	 *  -- Cort
 	 */
-	if (regs->msr & MSR_FP)
+	if (regs->msr & MSR_FP) {
 		giveup_fpu(current);
+		childregs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1);
+	}
 	memcpy(&p->thread.fpr, &current->thread.fpr, sizeof(p->thread.fpr));
 	p->thread.fpscr = current->thread.fpscr;
-	childregs->msr &= ~MSR_FP;
 
 #ifdef CONFIG_ALTIVEC
 	/*
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/prom.c linux/arch/ppc/kernel/prom.c
--- v2.4.9/linux/arch/ppc/kernel/prom.c	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/kernel/prom.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.prom.c 1.35 07/25/01 14:11:37 trini
+ * BK Id: SCCS/s.prom.c 1.40 08/24/01 20:13:31 paulus
  */
 /*
  * Procedures for interfacing to the Open Firmware PROM on
@@ -33,6 +33,7 @@
 #include <asm/pgtable.h>
 #include <asm/bitops.h>
 #include <asm/bootinfo.h>
+#include <asm/btext.h>
 #include "open_pic.h"
 
 #ifdef CONFIG_FB
@@ -99,6 +100,7 @@
 #define FB_MAX	8
 #endif
 char *prom_display_paths[FB_MAX] __initdata = { 0, };
+phandle prom_display_nodes[FB_MAX] __initdata;
 unsigned int prom_num_displays __initdata = 0;
 char *of_stdout_device __initdata = 0;
 ihandle prom_disp_node __initdata = 0;
@@ -125,40 +127,6 @@
 
 static struct device_node *allnodes;
 
-#ifdef CONFIG_BOOTX_TEXT
-
-#define NO_SCROLL
-
-static void clearscreen(void);
-static void flushscreen(void);
-
-#ifndef NO_SCROLL
-static void scrollscreen(void);
-#endif
-
-static void prepare_disp_BAT(void);
-
-static void draw_byte(unsigned char c, long locX, long locY);
-static void draw_byte_32(unsigned char *bits, unsigned long *base, int rb);
-static void draw_byte_16(unsigned char *bits, unsigned long *base, int rb);
-static void draw_byte_8(unsigned char *bits, unsigned long *base, int rb);
-
-static int g_loc_X;
-static int g_loc_Y;
-static int g_max_loc_X;
-static int g_max_loc_Y;
-
-unsigned long disp_BAT[2] __initdata = {0, 0};
-
-#define cmapsz	(16*256)
-
-static unsigned char vga_font[cmapsz];
-
-int bootx_text_mapped = 1;
-
-#endif /* CONFIG_BOOTX_TEXT */
-
-
 static void *call_prom(const char *service, int nargs, int nret, ...);
 static void prom_exit(void);
 static unsigned long copy_device_tree(unsigned long, unsigned long);
@@ -174,7 +142,6 @@
 
 #ifdef CONFIG_BOOTX_TEXT
 static void setup_disp_fake_bi(ihandle dp);
-static void prom_welcome(boot_infos_t* bi, unsigned long phys);
 #endif
 
 extern void enter_rtas(void *);
@@ -182,10 +149,6 @@
 
 extern char cmd_line[512];	/* XXX */
 boot_infos_t *boot_infos;
-#ifdef CONFIG_BOOTX_TEXT
-boot_infos_t *disp_bi;
-boot_infos_t fake_bi;
-#endif
 unsigned long dev_tree_size;
 
 #define ALIGN(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long))
@@ -257,13 +220,7 @@
 	unsigned long offset = reloc_offset();
 
 	if (RELOC(prom_stdout) == 0)
-	{
-#ifdef CONFIG_BOOTX_TEXT
-		if (RELOC(disp_bi) != 0)
-			prom_drawstring(msg);
-#endif
 		return;
-	}
 
 	for (p = msg; *p != 0; p = q) {
 		for (q = p; *q != 0 && *q != '\n'; ++q)
@@ -399,26 +356,21 @@
 		bi->logicalDisplayBase = 0;
 
 #ifdef CONFIG_BOOTX_TEXT
-	RELOC(g_loc_X) = 0;
-	RELOC(g_loc_Y) = 0;
-	RELOC(g_max_loc_X) = (bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) / 8;
-	RELOC(g_max_loc_Y) = (bi->dispDeviceRect[3] - bi->dispDeviceRect[1]) / 16;
-	RELOC(disp_bi) = PTRUNRELOC(bi);
-		
-	clearscreen();
+	btext_init(bi);
 
-	/* Test if boot-info is compatible. Done only in config CONFIG_BOOTX_TEXT since
-	   there is nothing much we can do with an incompatible version, except display
-	   a message and eventually hang the processor...
-		   
-	   I'll try to keep enough of boot-info compatible in the future to always allow
-	   display of this message;
-	*/
-	if (!BOOT_INFO_IS_COMPATIBLE(bi))
-		prom_print(RELOC(" !!! WARNING - Incompatible version of BootX !!!\n\n\n"));
-		
-	prom_welcome(bi, phys);
-	flushscreen();
+	/*
+	 * Test if boot-info is compatible.  Done only in config
+	 * CONFIG_BOOTX_TEXT since there is nothing much we can do
+	 * with an incompatible version, except display a message
+	 * and eventually hang the processor...
+	 *
+	 * I'll try to keep enough of boot-info compatible in the
+	 * future to always allow display of this message;
+	 */
+	if (!BOOT_INFO_IS_COMPATIBLE(bi)) {
+		btext_drawstring(RELOC(" !!! WARNING - Incompatible version of BootX !!!\n\n\n"));
+		btext_flushscreen();
+	}
 #endif	/* CONFIG_BOOTX_TEXT */	
 		
 	/* New BootX enters kernel with MMU off, i/os are not allowed
@@ -461,10 +413,13 @@
 	}
 		
 #ifdef CONFIG_BOOTX_TEXT
-	prepare_disp_BAT();
-	prom_drawstring(RELOC("booting...\n"));
-	flushscreen();
-	RELOC(bootx_text_mapped) = 1;
+	/*
+	 * Note that after we call prepare_disp_BAT, we can't do
+	 * prom_draw*, flushscreen or clearscreen until we turn the MMU
+	 * on, since prepare_disp_BAT sets disp_bi->logicalDisplayBase
+	 * to a virtual address.
+	 */
+	btext_prepare_BAT();
 #endif
 }
 
@@ -591,13 +546,11 @@
 unsigned long __init
 prom_init(int r3, int r4, prom_entry pp)
 {
-	int chrp = 0;
 	unsigned long mem;
-	ihandle prom_mmu, prom_op;
+	ihandle prom_mmu;
 	unsigned long offset = reloc_offset();
 	int l;
 	char *p, *d;
-	int prom_version = 0;
  	unsigned long phys;
 
  	/* Default */
@@ -622,31 +575,6 @@
 	RELOC(of_stdout_device) = PTRUNRELOC(p);
 	mem += strlen(p) + 1;
 
-	/* Find the OF version */
-	prom_op = call_prom(RELOC("finddevice"), 1, 1, RELOC("/openprom"));
-	prom_version = 0;
-	if (prom_op != (void*)-1) {
-		char model[64];
-		int sz;
-		sz = (int)call_prom(RELOC("getprop"), 4, 1, prom_op,
-				    RELOC("model"), model, 64);
-		if (sz > 0) {
-			char *c;
-			/* hack to skip the ibm chrp firmware # */
-			if ( strncmp(model,RELOC("IBM"),3) ) {
-				for (c = model; *c; c++)
-					if (*c >= '0' && *c <= '9') {
-						prom_version = *c - '0';
-						break;
-					}
-			}
-			else
-				chrp = 1;
-		}
-	}
-	if (prom_version >= 3)
-		prom_print(RELOC("OF Version 3 detected.\n"));
-
 	/* Get the boot device and translate it to a full OF pathname. */
 	p = (char *) mem;
 	l = (int) call_prom(RELOC("getprop"), 4, 1, RELOC(prom_chosen),
@@ -725,22 +653,14 @@
 	call_prom(RELOC("quiesce"), 0, 0);
 
 #ifdef CONFIG_BOOTX_TEXT
-	if (!chrp && RELOC(disp_bi)) {
-		RELOC(prom_stdout) = 0; /* stop OF output */
-		clearscreen();
-		prepare_disp_BAT();
-		prom_welcome(PTRRELOC(RELOC(disp_bi)), phys);
-		prom_drawstring(RELOC("booting...\n"));
-		RELOC(bootx_text_mapped) = 1;
-	} else {
-		RELOC(bootx_text_mapped) = 0;
-	}
+	btext_prepare_BAT();
 #endif
 
 	prom_print(RELOC("returning "));
 	prom_print_hex(phys);
 	prom_print(RELOC(" from prom_init\n"));
 	RELOC(prom_stdout) = 0;
+
 	return phys;
 }
 
@@ -767,82 +687,6 @@
 	rtas(&u, RELOC(rtas_data));
 }
 
-#ifdef CONFIG_BOOTX_TEXT
-static void __init
-prom_welcome(boot_infos_t* bi, unsigned long phys)
-{
-	unsigned long offset = reloc_offset();
-	unsigned long flags;
-	unsigned long pvr;
-	
-	prom_drawstring(RELOC("Welcome to Linux, kernel " UTS_RELEASE "\n"));
-	prom_drawstring(RELOC("\nstarted at       : 0x"));
-	prom_drawhex(phys);
-	prom_drawstring(RELOC("\nlinked at        : 0x"));
-	prom_drawhex(KERNELBASE);
-	prom_drawstring(RELOC("\nframe buffer at  : 0x"));
-	prom_drawhex((unsigned long)bi->dispDeviceBase);
-	prom_drawstring(RELOC(" (phys), 0x"));
-	prom_drawhex((unsigned long)bi->logicalDisplayBase);
-	prom_drawstring(RELOC(" (log)"));
-	prom_drawstring(RELOC("\nklimit           : 0x"));
-	prom_drawhex((unsigned long)RELOC(klimit));
-	prom_drawstring(RELOC("\nMSR              : 0x"));
-	__asm__ __volatile__ ("mfmsr %0" : "=r" (flags));
-	prom_drawhex(flags);
-	__asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr));
-	pvr >>= 16;
-	if (pvr > 1) {
-	    prom_drawstring(RELOC("\nHID0             : 0x"));
-	    __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags));
-	    prom_drawhex(flags);
-	}
-	if (pvr == 8 || pvr == 12 || pvr == 0x800c) {
-	    prom_drawstring(RELOC("\nICTC             : 0x"));
-	    __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags));
-	    prom_drawhex(flags);
-	}
-	prom_drawstring(RELOC("\n\n"));
-}
-
-/* Calc BAT values for mapping the display and store them
- * in disp_BAT.  Those values are then used from head.S to map
- * the display during identify_machine() and MMU_Init()
- * 
- * For now, the display is mapped in place (1:1). This should
- * be changed if the display physical address overlaps
- * KERNELBASE, which is fortunately not the case on any machine
- * I know of. This mapping is temporary and will disappear as
- * soon as the setup done by MMU_Init() is applied
- * 
- * For now, we align the BAT and then map 8Mb on 601 and 16Mb
- * on other PPCs. This may cause trouble if the framebuffer
- * is really badly aligned, but I didn't encounter this case
- * yet.
- */
-static void __init
-prepare_disp_BAT(void)
-{
-	unsigned long offset = reloc_offset();
-	boot_infos_t* bi = PTRRELOC(RELOC(disp_bi));
-	unsigned long addr = (unsigned long)bi->dispDeviceBase;
-	
-	if ((_get_PVR() >> 16) != 1) {
-		/* 603, 604, G3, G4, ... */
-		addr &= 0xFF000000UL;
-		RELOC(disp_BAT[0]) = addr | (BL_16M<<2) | 2;
-		RELOC(disp_BAT[1]) = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW);		
-	} else {
-		/* 601 */
-		addr &= 0xFF800000UL;
-		RELOC(disp_BAT[0]) = addr | (_PAGE_NO_CACHE | PP_RWXX) | 4;
-		RELOC(disp_BAT[1]) = addr | BL_8M | 0x40;
-	}
-	bi->logicalDisplayBase = bi->dispDeviceBase;
-}
-
-#endif
-
 static int __init
 prom_set_color(ihandle ih, int i, int r, int g, int b)
 {
@@ -920,17 +764,22 @@
 		i = RELOC(prom_num_displays)++;
 		if (RELOC(of_stdout_device) != 0 && i > 0
 		    && strcmp(PTRRELOC(RELOC(of_stdout_device)), path) == 0) {
-			for (; i > 0; --i)
+			for (; i > 0; --i) {
 				RELOC(prom_display_paths[i])
 					= RELOC(prom_display_paths[i-1]);
+				RELOC(prom_display_nodes[i])
+					= RELOC(prom_display_nodes[i-1]);
+			}
 		}
 		RELOC(prom_display_paths[i]) = PTRUNRELOC(path);
+		RELOC(prom_display_nodes[i]) = node;
 		if (i == 0)
 			RELOC(prom_disp_node) = node;
 		if (RELOC(prom_num_displays) >= FB_MAX)
 			break;
 	}
 
+try_again:
 	/*
 	 * Open the first display and set its colormap.
 	 */
@@ -941,6 +790,15 @@
 		ih = call_prom(RELOC("open"), 1, 1, path);
 		if (ih == 0 || ih == (ihandle) -1) {
 			prom_print(RELOC("... failed\n"));
+			for (i=1; i<RELOC(prom_num_displays); i++) {
+				RELOC(prom_display_paths[i-1]) = RELOC(prom_display_paths[i]);
+				RELOC(prom_display_nodes[i-1]) = RELOC(prom_display_nodes[i]);
+			}	
+			if (--RELOC(prom_num_displays) > 0)
+				RELOC(prom_disp_node) = RELOC(prom_display_nodes[0]);
+			else
+				RELOC(prom_disp_node) = NULL;
+			goto try_again;
 		} else {
 			prom_print(RELOC("... ok\n"));
 			/*
@@ -977,7 +835,6 @@
 {
 	int width = 640, height = 480, depth = 8, pitch;
 	unsigned address;
-	boot_infos_t* bi;
 	unsigned long offset = reloc_offset();
 	struct pci_reg_property addrs[8];
 	int i, naddrs;
@@ -1025,20 +882,8 @@
 	/* kludge for valkyrie */
 	if (strcmp(name, RELOC("valkyrie")) == 0) 
 		address += 0x1000;
- 
-	RELOC(disp_bi) = &fake_bi;
-	bi = PTRRELOC((&fake_bi));
-	RELOC(g_loc_X) = 0;
-	RELOC(g_loc_Y) = 0;
-	RELOC(g_max_loc_X) = width / 8;
-	RELOC(g_max_loc_Y) = height / 16;
-	bi->logicalDisplayBase = (unsigned char *)address;
-	bi->dispDeviceBase = (unsigned char *)address;
-	bi->dispDeviceRowBytes = pitch;
-	bi->dispDeviceDepth = depth;
-	bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0;
-	bi->dispDeviceRect[2] = width;
-	bi->dispDeviceRect[3] = height;
+
+	btext_setup_display(width, height, depth, pitch, address);
 }
 #endif
 
@@ -1147,8 +992,7 @@
 		prev_propp = &pp->next;
 		namep = (char *) (pp + 1);
 		pp->name = PTRUNRELOC(namep);
-		/* Work around a GCC3 bug */
-		memcpy(namep, RELOC("linux,phandle"), sizeof("linux,phandle"));
+		strcpy(namep, RELOC("linux,phandle"));
 		mem_start = ALIGN((unsigned long)namep + strlen(namep) + 1);
 		pp->value = (unsigned char *) PTRUNRELOC(&np->node);
 		pp->length = sizeof(np->node);
@@ -1213,15 +1057,21 @@
 		 * np->name has not been set yet.  -- paulus
 		 */
 		int n = 0;
-		char *name;
+		char *name, *ic;
+		int iclen;
 
 		for (np = allnodes; np != NULL; np = np->allnext) {
-			if ((name = get_property(np, "name", NULL)) == NULL
-			    || strcmp(name, "interrupt-controller") != 0)
-				continue;
-			if (n == 0)
-				dflt_interrupt_controller = np;
-			++n;
+			ic = get_property(np, "interrupt-controller", &iclen);
+			name = get_property(np, "name", NULL);
+			/* checking iclen makes sure we don't get a false
+			   match on /chosen.interrupt_controller */
+			if ((name != NULL
+			     && strcmp(name, "interrupt-controller") == 0)
+			    || (ic != NULL && iclen == 0)) {
+				if (n == 0)
+					dflt_interrupt_controller = np;
+				++n;
+			}
 		}
 		num_interrupt_controllers = n;
 	}
@@ -1559,7 +1409,7 @@
 	}
 }
 
-int __init
+int
 prom_n_addr_cells(struct device_node* np)
 {
 	int* ip;
@@ -1574,7 +1424,7 @@
 	return 1;
 }
 
-int __init
+int
 prom_n_size_cells(struct device_node* np)
 {
 	int* ip;
@@ -1890,7 +1740,7 @@
 /*
  * Returns all nodes linked together
  */
-struct device_node __openfirmware *
+struct device_node * __openfirmware
 find_all_nodes(void)
 {
 	struct device_node *head, **prevp, *np;
@@ -1983,7 +1833,7 @@
 /*
  * Find the device_node with a given phandle.
  */
-static struct device_node __init *
+static struct device_node * __init
 find_phandle(phandle ph)
 {
 	struct device_node *np;
@@ -2111,6 +1961,12 @@
 		u.words[i+3] = va_arg(list, unsigned long);
 	va_end(list);
 
+	/* Shouldn't we enable kernel FP here ? enter_rtas will play
+	 * with MSR_FE0|MSR_FE1|MSR_FP so I assume rtas might use
+	 * floating points. If that's the case, then we need to make
+	 * sure any lazy FP context is backed up
+	 * --BenH
+	 */
 	spin_lock_irqsave(&rtas_lock, s);
 	enter_rtas((void *)__pa(&u));
 	spin_unlock_irqrestore(&rtas_lock, s);
@@ -2130,694 +1986,3 @@
 	for (;;)
 		prom_exit();
 }
-
-#ifdef CONFIG_BOOTX_TEXT
-
-/* Here's a small text engine to use during early boot or for debugging purposes
- * 
- * todo:
- * 
- *  - build some kind of vgacon with it to enable early printk
- *  - move to a separate file
- *  - add a few video driver hooks to keep in sync with display
- *    changes.
- */
-
-void
-map_bootx_text(void)
-{
-	unsigned long base, offset, size;
-	if (disp_bi == 0)
-		return;
-	base = ((unsigned long) disp_bi->dispDeviceBase) & 0xFFFFF000UL;
-	offset = ((unsigned long) disp_bi->dispDeviceBase) - base;
-	size = disp_bi->dispDeviceRowBytes * disp_bi->dispDeviceRect[3] + offset
-		+ disp_bi->dispDeviceRect[0];
-	disp_bi->logicalDisplayBase = ioremap(base, size);
-	if (disp_bi->logicalDisplayBase == 0)
-		return;
-	disp_bi->logicalDisplayBase += offset;
-	bootx_text_mapped = 1;
-}
-
-/* Calc the base address of a given point (x,y) */
-static unsigned char * __pmac
-calc_base(boot_infos_t *bi, int x, int y)
-{
-	unsigned char *base;
-
-	base = bi->logicalDisplayBase;
-	if (base == 0)
-		base = bi->dispDeviceBase;
-	base += (x + bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3);
-	base += (y + bi->dispDeviceRect[1]) * bi->dispDeviceRowBytes;
-	return base;
-}
-
-/* Adjust the display to a new resolution */
-void __openfirmware
-bootx_update_display(unsigned long phys, int width, int height,
-		     int depth, int pitch)
-{
-	if (disp_bi == 0)
-		return;
-	/* check it's the same frame buffer (within 64MB) */
-	if ((phys ^ (unsigned long)disp_bi->dispDeviceBase) & 0xfc000000) {
-		return;
-	}
-
-	disp_bi->dispDeviceBase = (__u8 *) phys;
-	disp_bi->dispDeviceRect[0] = 0;
-	disp_bi->dispDeviceRect[1] = 0;
-	disp_bi->dispDeviceRect[2] = width;
-	disp_bi->dispDeviceRect[3] = height;
-	disp_bi->dispDeviceDepth = depth;
-	disp_bi->dispDeviceRowBytes = pitch;
-	if (bootx_text_mapped) {
-		iounmap(disp_bi->logicalDisplayBase);
-		bootx_text_mapped = 0;
-	}
-	map_bootx_text();
-	g_loc_X = 0;
-	g_loc_Y = 0;
-	g_max_loc_X = width / 8;
-	g_max_loc_Y = height / 16;
-}
-
-static void __pmac
-clearscreen(void)
-{
-	unsigned long offset	= reloc_offset();
-	boot_infos_t* bi	= PTRRELOC(RELOC(disp_bi));
-	unsigned long *base	= (unsigned long *)calc_base(bi, 0, 0);
-	unsigned long width 	= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
-					(bi->dispDeviceDepth >> 3)) >> 2;
-	int i,j;
-	
-	for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++)
-	{
-		unsigned long *ptr = base;
-		for(j=width; j; --j)
-			*(ptr++) = 0;
-		base += (bi->dispDeviceRowBytes >> 2);
-	}
-}
-
-__inline__ void dcbst(const void* addr)
-{
-	__asm__ __volatile__ ("dcbst 0,%0" :: "r" (addr));
-}
-
-static void __pmac
-flushscreen(void)
-{
-	unsigned long offset	= reloc_offset();
-	boot_infos_t* bi	= PTRRELOC(RELOC(disp_bi));
-	unsigned long *base	= (unsigned long *)calc_base(bi, 0, 0);
-	unsigned long width 	= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
-					(bi->dispDeviceDepth >> 3)) >> 2;
-	int i,j;
-	
-	for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++)
-	{
-		unsigned long *ptr = base;
-		for(j=width; j>0; j-=8) {
-			dcbst(ptr);
-			ptr += 8;
-		}
-		base += (bi->dispDeviceRowBytes >> 2);
-	}
-}
-
-#ifndef NO_SCROLL
-static void __pmac
-scrollscreen(void)
-{
-	unsigned long offset		= reloc_offset();
-	boot_infos_t* bi		= PTRRELOC(RELOC(disp_bi));
-	unsigned long *src		= (unsigned long *)calc_base(bi,0,16);
-	unsigned long *dst		= (unsigned long *)calc_base(bi,0,0);
-	unsigned long width		= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
-						(bi->dispDeviceDepth >> 3)) >> 2;
-	int i,j;
-	
-#ifdef CONFIG_ADB_PMU
-	pmu_suspend();	/* PMU will not shut us down ! */
-#endif
-	for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1] - 16); i++)
-	{
-		unsigned long *src_ptr = src;
-		unsigned long *dst_ptr = dst;
-		for(j=width; j; --j)
-			*(dst_ptr++) = *(src_ptr++);
-		src += (bi->dispDeviceRowBytes >> 2);
-		dst += (bi->dispDeviceRowBytes >> 2);
-	}
-	for (i=0; i<16; i++)
-	{
-		unsigned long *dst_ptr = dst;
-		for(j=width; j; --j)
-			*(dst_ptr++) = 0;
-		dst += (bi->dispDeviceRowBytes >> 2);
-	}
-#ifdef CONFIG_ADB_PMU
-	pmu_resume();	/* PMU will not shut us down ! */
-#endif
-}
-#endif /* ndef NO_SCROLL */
-
-void __pmac
-prom_drawchar(char c)
-{
-	unsigned long offset = reloc_offset();
-	int cline = 0, x;
-
-	if (!RELOC(bootx_text_mapped))
-		return;
-
-	switch (c) {
-	case '\b':
-		if (RELOC(g_loc_X) > 0)
-			--RELOC(g_loc_X);
-		break;
-	case '\t':
-		RELOC(g_loc_X) = (RELOC(g_loc_X) & -8) + 8;
-		break;
-	case '\r':
-		RELOC(g_loc_X) = 0;
-		break;
-	case '\n':
-		RELOC(g_loc_X) = 0;
-		RELOC(g_loc_Y)++;
-		cline = 1;
-		break;
-	default:
-		draw_byte(c, RELOC(g_loc_X)++, RELOC(g_loc_Y));
-	}
-	if (RELOC(g_loc_X) >= RELOC(g_max_loc_X)) {
-		RELOC(g_loc_X) = 0;
-		RELOC(g_loc_Y)++;
-		cline = 1;
-	}
-#ifndef NO_SCROLL
-	while (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y)) {
-		scrollscreen();
-		RELOC(g_loc_Y)--;
-	}
-#else
-	/* wrap around from bottom to top of screen so we don't
-	   waste time scrolling each line.  -- paulus. */
-	if (RELOC(g_loc_Y) >= RELOC(g_max_loc_Y))
-		RELOC(g_loc_Y) = 0;
-	if (cline) {
-		for (x = 0; x < RELOC(g_max_loc_X); ++x)
-			draw_byte(' ', x, RELOC(g_loc_Y));
-	}
-#endif
-}
-
-void __pmac
-prom_drawstring(const char *c)
-{
-	unsigned long offset	= reloc_offset();
-
-	if (!RELOC(bootx_text_mapped))
-		return;
-	while (*c)
-		prom_drawchar(*c++);
-}
-
-void __pmac
-prom_drawhex(unsigned long v)
-{
-	static char hex_table[] = "0123456789abcdef";
-	unsigned long offset	= reloc_offset();
-	
-	if (!RELOC(bootx_text_mapped))
-		return;
-	prom_drawchar(RELOC(hex_table)[(v >> 28) & 0x0000000FUL]);
-	prom_drawchar(RELOC(hex_table)[(v >> 24) & 0x0000000FUL]);
-	prom_drawchar(RELOC(hex_table)[(v >> 20) & 0x0000000FUL]);
-	prom_drawchar(RELOC(hex_table)[(v >> 16) & 0x0000000FUL]);
-	prom_drawchar(RELOC(hex_table)[(v >> 12) & 0x0000000FUL]);
-	prom_drawchar(RELOC(hex_table)[(v >>  8) & 0x0000000FUL]);
-	prom_drawchar(RELOC(hex_table)[(v >>  4) & 0x0000000FUL]);
-	prom_drawchar(RELOC(hex_table)[(v >>  0) & 0x0000000FUL]);
-}
-
-static void __pmac
-draw_byte(unsigned char c, long locX, long locY)
-{
-	unsigned long offset	= reloc_offset();
-	boot_infos_t* bi	= PTRRELOC(RELOC(disp_bi));
-	unsigned char *base	= calc_base(bi, locX << 3, locY << 4);
-	unsigned char *font	= &RELOC(vga_font)[((unsigned long)c) * 16];
-	int rb			= bi->dispDeviceRowBytes;
-	
-	switch(bi->dispDeviceDepth) {
-		case 32:
-			draw_byte_32(font, (unsigned long *)base, rb);
-			break;
-		case 16:
-			draw_byte_16(font, (unsigned long *)base, rb);
-			break;
-		case 8:
-			draw_byte_8(font, (unsigned long *)base, rb);
-			break;
-		default:
-			break;
-	}
-}
-
-static unsigned long expand_bits_8[16] __pmacdata  = {
-	0x00000000,
-	0x000000ff,
-	0x0000ff00,
-	0x0000ffff,
-	0x00ff0000,
-	0x00ff00ff,
-	0x00ffff00,
-	0x00ffffff,
-	0xff000000,
-	0xff0000ff,
-	0xff00ff00,
-	0xff00ffff,
-	0xffff0000,
-	0xffff00ff,
-	0xffffff00,
-	0xffffffff
-};
-
-static unsigned long expand_bits_16[4] __pmacdata = {
-	0x00000000,
-	0x0000ffff,
-	0xffff0000,
-	0xffffffff
-};
-
-static void __pmac
-draw_byte_32(unsigned char *font, unsigned long *base, int rb)
-{
-	int l, bits;	
-	int fg = 0xFFFFFFFFUL;
-	int bg = 0x00000000UL;
-	
-	for (l = 0; l < 16; ++l)
-	{
-		bits = *font++;
-		base[0] = (-(bits >> 7) & fg) ^ bg;
-		base[1] = (-((bits >> 6) & 1) & fg) ^ bg;
-		base[2] = (-((bits >> 5) & 1) & fg) ^ bg;
-		base[3] = (-((bits >> 4) & 1) & fg) ^ bg;
-		base[4] = (-((bits >> 3) & 1) & fg) ^ bg;
-		base[5] = (-((bits >> 2) & 1) & fg) ^ bg;
-		base[6] = (-((bits >> 1) & 1) & fg) ^ bg;
-		base[7] = (-(bits & 1) & fg) ^ bg;
-		base = (unsigned long *) ((char *)base + rb);
-	}
-}
-
-static void __pmac
-draw_byte_16(unsigned char *font, unsigned long *base, int rb)
-{
-	int l, bits;	
-	int fg = 0xFFFFFFFFUL;
-	int bg = 0x00000000UL;
-	unsigned long offset = reloc_offset();
-	unsigned long *eb = RELOC(expand_bits_16);
-
-	for (l = 0; l < 16; ++l)
-	{
-		bits = *font++;
-		base[0] = (eb[bits >> 6] & fg) ^ bg;
-		base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg;
-		base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg;
-		base[3] = (eb[bits & 3] & fg) ^ bg;
-		base = (unsigned long *) ((char *)base + rb);
-	}
-}
-
-static void __pmac
-draw_byte_8(unsigned char *font, unsigned long *base, int rb)
-{
-	int l, bits;	
-	int fg = 0x0F0F0F0FUL;
-	int bg = 0x00000000UL;
-	unsigned long offset = reloc_offset();
-	unsigned long *eb = RELOC(expand_bits_8);
-
-	for (l = 0; l < 16; ++l)
-	{
-		bits = *font++;
-		base[0] = (eb[bits >> 4] & fg) ^ bg;
-		base[1] = (eb[bits & 0xf] & fg) ^ bg;
-		base = (unsigned long *) ((char *)base + rb);
-	}
-}
-
-static unsigned char vga_font[cmapsz] __pmacdata = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 
-0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, 
-0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 
-0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 
-0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
-0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 
-0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 
-0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e, 
-0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 
-0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, 
-0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 
-0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e, 
-0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 
-0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb, 
-0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 
-0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
-0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 
-0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 
-0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 
-0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
-0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 
-0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 
-0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 
-0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 
-0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 
-0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
-0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
-0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 
-0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
-0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 
-0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
-0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 
-0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 
-0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 
-0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde, 
-0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 
-0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 
-0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c, 
-0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 
-0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
-0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c, 
-0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 
-0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7, 
-0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 
-0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 
-0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 
-0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
-0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
-0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 
-0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
-0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 
-0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
-0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 
-0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60, 
-0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 
-0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60, 
-0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 
-0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60, 
-0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 
-0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 
-0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 
-0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 
-0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 
-0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, 
-0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 
-0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
-0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, 
-0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 
-0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 
-0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 
-0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 
-0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 
-0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
-0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, 
-0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 
-0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, 
-0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
-0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 
-0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c, 
-0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 
-0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
-0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, 
-0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
-0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 
-0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 
-0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 
-0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 
-0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
-0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
-0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
-0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 
-0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 
-0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 
-0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 
-0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44, 
-0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 
-0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 
-0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 
-0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 
-0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 
-0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
-0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 
-0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 
-0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 
-0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 
-0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 
-0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 
-0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 
-0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 
-0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 
-0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 
-0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
-0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 
-0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 
-};
-
-#endif /* CONFIG_BOOTX_TEXT */
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/setup.c linux/arch/ppc/kernel/setup.c
--- v2.4.9/linux/arch/ppc/kernel/setup.c	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/kernel/setup.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.setup.c 1.46 07/26/01 14:18:18 trini
+ * BK Id: SCCS/s.setup.c 1.55 08/24/01 20:07:37 paulus
  */
 /*
  * Common prep/pmac/chrp boot and setup code.
@@ -28,6 +28,7 @@
 #include <asm/amigappc.h>
 #include <asm/smp.h>
 #include <asm/elf.h>
+#include <asm/cputable.h>
 #ifdef CONFIG_8xx
 #include <asm/mpc8xx.h>
 #include <asm/8xx_immap.h>
@@ -40,55 +41,18 @@
 #include <asm/ppc4xx.h>
 #endif
 #include <asm/bootx.h>
+#include <asm/btext.h>
 #include <asm/machdep.h>
 #include <asm/feature.h>
 #include <asm/uaccess.h>
+#include <asm/system.h>
 
-
-extern void apus_init(unsigned long r3,
-                      unsigned long r4,
-                      unsigned long r5,
-                      unsigned long r6,
-                      unsigned long r7);
-
-extern void chrp_init(unsigned long r3,
-                      unsigned long r4,
-                      unsigned long r5,
-                      unsigned long r6,
-                      unsigned long r7);
-
-extern void gemini_init(unsigned long r3,
-                      unsigned long r4,
-                      unsigned long r5,
-                      unsigned long r6,
-                      unsigned long r7);
-
-extern void m8xx_init(unsigned long r3,
-		     unsigned long r4,
-		     unsigned long r5,
-		     unsigned long r6,
-		     unsigned long r7);
-
-extern void m8260_init(unsigned long r3,
-		     unsigned long r4,
-		     unsigned long r5,
-		     unsigned long r6,
-		     unsigned long r7);
-
-extern void pmac_init(unsigned long r3,
-                      unsigned long r4,
-                      unsigned long r5,
-                      unsigned long r6,
-                      unsigned long r7);
-
-extern void prep_init(unsigned long r3,
-                      unsigned long r4,
-                      unsigned long r5,
-                      unsigned long r6,
-                      unsigned long r7);
-
+extern void platform_init(unsigned long r3, unsigned long r4,
+		unsigned long r5, unsigned long r6, unsigned long r7);
 extern void bootx_init(unsigned long r4, unsigned long phys);
 extern unsigned long reloc_offset(void);
+extern void identify_cpu(unsigned long offset, unsigned long cpu);
+extern void do_cpu_ftr_fixups(unsigned long offset);
 
 #ifdef CONFIG_XMON
 extern void xmon_map_scc(void);
@@ -98,6 +62,13 @@
 char saved_command_line[256];
 unsigned char aux_device_present;
 struct ide_machdep_calls ppc_ide_md;
+char *sysmap;
+unsigned long sysmap_size;
+
+/* Used with the BI_MEMSIZE bootinfo parameter to store the memory
+   size value reported by the boot loader. */ 
+unsigned int boot_mem_size;
+
 int parse_bootinfo(void);
 
 unsigned long ISA_DMA_THRESHOLD;
@@ -105,7 +76,13 @@
 
 #ifdef CONFIG_ALL_PPC
 int _machine = 0;
-int have_of = 0;
+
+extern void prep_init(unsigned long r3, unsigned long r4,
+		unsigned long r5, unsigned long r6, unsigned long r7);
+extern void pmac_init(unsigned long r3, unsigned long r4,
+		unsigned long r5, unsigned long r6, unsigned long r7);
+extern void chrp_init(unsigned long r3, unsigned long r4,
+		unsigned long r5, unsigned long r6, unsigned long r7);
 #endif /* CONFIG_ALL_PPC */
 
 #ifdef CONFIG_MAGIC_SYSRQ
@@ -126,15 +103,7 @@
 int icache_bsize;
 int ucache_bsize;
 
-/*
- * Perhaps we can put the pmac screen_info[] here
- * on pmac as well so we don't need the ifdef's.
- * Until we get multiple-console support in here
- * that is.  -- Cort
- * Maybe tie it to serial consoles, since this is really what
- * these processors use on existing boards.  -- Dan
- */ 
-#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) && !defined(CONFIG_8260)
+#ifdef CONFIG_VGA_CONSOLE
 struct screen_info screen_info = {
 	0, 25,			/* orig-x, orig-y */
 	0,			/* unused */
@@ -146,35 +115,7 @@
 	1,			/* orig-video-isVGA */
 	16			/* orig-video-points */
 };
-
-/*
- * I really need to add multiple-console support... -- Cort
- */
-int __init pmac_display_supported(char *name)
-{
-	return 0;
-}
-void __init pmac_find_display(void)
-{
-}
-
-#else /* CONFIG_4xx || CONFIG_8xx */
-
-/* We need this to satisfy some external references until we can
- * strip the kernel down.
- */
-struct screen_info screen_info = {
-	0, 25,			/* orig-x, orig-y */
-	0,			/* unused */
-	0,			/* orig-video-page */
-	0,			/* orig-video-mode */
-	80,			/* orig-video-cols */
-	0,0,0,			/* ega_ax, ega_bx, ega_cx */
-	25,			/* orig-video-lines */
-	0,			/* orig-video-isVGA */
-	16			/* orig-video-points */
-};
-#endif /* !CONFIG_4xx && !CONFIG_8xx */
+#endif /* CONFIG_VGA_CONSOLE */
 
 void machine_restart(char *cmd)
 {
@@ -190,35 +131,11 @@
 {
 	ppc_md.halt();
 }
-  
-unsigned long cpu_temp(void)
-{
-	unsigned char thres = 0;
-	
-#if 0
-	/* disable thrm2 */
-	_set_THRM2( 0 );
-	/* threshold 0 C, tid: exceeding threshold, tie: don't generate interrupt */
-	_set_THRM1( THRM1_V );
-
-	/* we need 20us to do the compare - assume 300MHz processor clock */
-	_set_THRM3(0);
-	_set_THRM3(THRM3_E | (300*30)<<18 );
-
-	udelay(100);
-	/* wait for the compare to complete */
-	/*while ( !(_get_THRM1() & THRM1_TIV) ) ;*/
-	if ( !(_get_THRM1() & THRM1_TIV) )
-		printk("no tiv\n");
-	if ( _get_THRM1() & THRM1_TIN )
-		printk("crossed\n");
-	/* turn everything off */
-	_set_THRM3(0);
-	_set_THRM1(0);
-#endif
-		
-	return thres;
-}
+
+#ifdef CONFIG_TAU
+extern u32 cpu_temp(unsigned long cpu);
+extern u32 cpu_temp_both(unsigned long cpu);
+#endif /* CONFIG_TAU */
 
 int get_cpuinfo(char *buffer)
 {
@@ -227,7 +144,7 @@
 	unsigned long i;
 	unsigned int pvr;
 	unsigned short maj, min;
-	
+
 #ifdef CONFIG_SMP
 #define CPU_PRESENT(x) (cpu_callin_map[(x)])
 #define GET_PVR ((long int)(cpu_data[i].pvr))
@@ -235,7 +152,7 @@
 #else
 #define CPU_PRESENT(x) ((x)==0)
 #define smp_num_cpus 1
-#define GET_PVR ((long int)_get_PVR())
+#define GET_PVR (mfspr(PVR))
 #define CD(x) (x)
 #endif	
 
@@ -249,90 +166,31 @@
 		len += sprintf(len+buffer,"cpu\t\t: ");
 
 		pvr = GET_PVR;
-	
-		switch (PVR_VER(pvr))
-		{
-		case 0x0001:
-			len += sprintf(len+buffer, "601\n");
-			break;
-		case 0x0003:
-			len += sprintf(len+buffer, "603\n");
-			break;
-		case 0x0004:
-			len += sprintf(len+buffer, "604\n");
-			break;
-		case 0x0006:
-			len += sprintf(len+buffer, "603e\n");
-			break;
-		case 0x0007:
-			len += sprintf(len+buffer, "603");
-			if (((pvr >> 12) & 0xF) == 1) {
-				pvr ^= 0x00001000;	/* revision fix-up */
-				len += sprintf(len+buffer, "r\n");
-			} else {
-				len += sprintf(len+buffer, "ev\n");
-			}
-			break;
-		case 0x0008:		/* 740/750(P) */
-		case 0x1008:
-			len += sprintf(len+buffer, "750%s\n",
-				       PVR_VER(pvr) == 0x1008 ? "P" : "");
-			len += sprintf(len+buffer, "temperature \t: %lu C\n",
-				       cpu_temp());
-			break;
-		case 0x0009:		/* 604e/604r */
-		case 0x000A:
-			len += sprintf(len+buffer, "604");
-
-			if (PVR_VER(pvr) == 0x000A ||
-			    ((pvr >> 12) & 0xF) != 0) {
-				pvr &= ~0x00003000;	/* revision fix-up */
-				len += sprintf(len+buffer, "r\n");
-			} else {
-				len += sprintf(len+buffer, "e\n");
-			}
-			break;
-		case 0x000C:
-			len += sprintf(len+buffer, "7400 (G4");
+
+		if (cur_cpu_spec[i]->pvr_mask)
+			len += sprintf(len+buffer, "%s", cur_cpu_spec[i]->cpu_name);
+		else
+			len += sprintf(len+buffer, "unknown (%08x)", pvr);
 #ifdef CONFIG_ALTIVEC
+		if (cur_cpu_spec[i]->cpu_features & CPU_FTR_ALTIVEC)
 			len += sprintf(len+buffer, ", altivec supported");
-#endif /* CONFIG_ALTIVEC */
-			len += sprintf(len+buffer, ")\n");
-			break;
-		case 0x0020:
-			len += sprintf(len+buffer, "403G");
-			switch ((pvr >> 8) & 0xFF) {
-			case 0x02:
-				len += sprintf(len+buffer, "C\n");    
-				break;				      
-			case 0x14:
-				len += sprintf(len+buffer, "CX\n");
-				break;
-			}
-			break;
-		case 0x0035:
-			len += sprintf(len+buffer, "POWER4\n");
-			break;
-		case 0x0040:
-			len += sprintf(len+buffer, "POWER3 (630)\n");
-			break;
-		case 0x0041:
-			len += sprintf(len+buffer, "POWER3 (630+)\n");
-			break;
-		case 0x0050:
-			len += sprintf(len+buffer, "8xx\n");
-			break;
-		case 0x0081:
-			len += sprintf(len+buffer, "82xx\n");
-			break;
-		case 0x4011:
-			len += sprintf(len+buffer, "405GP\n");
-			break;
-		default:
-			len += sprintf(len+buffer, "unknown (%08x)\n", pvr);
-			break;
+#endif		
+		len += sprintf(len+buffer, "\n");
+#ifdef CONFIG_TAU
+		if (cur_cpu_spec[i]->cpu_features & CPU_FTR_TAU) {
+#ifdef CONFIG_TAU_AVERAGE	/* more straightforward, but potentially misleading */
+			len += sprintf(len+buffer, "temperature \t: %u C (uncalibrated)\n",
+				       cpu_temp(i));
+#else
+			/* show the actual temp sensor range */
+			u32 temp;
+			temp = cpu_temp_both(i);
+			len += sprintf(len+buffer, "temperature \t: %u-%u C (uncalibrated)\n",
+					temp & 0xff, temp >> 16);
+#endif
 		}
-		
+#endif
+
 		/*
 		 * Assume here that all clock rates are the same in a
 		 * smp system.  -- Cort
@@ -394,7 +252,7 @@
 	}
 
 #ifdef CONFIG_SMP
-	if ( i )
+	if ( i && smp_num_cpus > 1)
 		len += sprintf(buffer+len, "\n");
 	len += sprintf(buffer+len,"total bogomips\t: %lu.%02lu\n",
 		       bogosum/(500000/HZ),
@@ -423,31 +281,6 @@
 	return len;
 }
 
-#ifdef CONFIG_ALL_PPC
-void __init
-intuit_machine_type(void)
-{
-	char *model;
-	struct device_node *root;
-			
-	/* ask the OF info if we're a chrp or pmac */
-	root = find_path_device("/");
-	if (root != 0) {
-		/* assume pmac unless proven to be chrp -- Cort */
-		_machine = _MACH_Pmac;
-		model = get_property(root, "device_type", NULL);
-		if (model && !strncmp("chrp", model, 4))
-			_machine = _MACH_chrp;
-		else {
-			model = get_property(root, "model", NULL);
-			if (model && !strncmp(model, "IBM", 3))
-				_machine = _MACH_chrp;
-		}
-	}
-}
-#endif /* CONFIG_ALL_PPC */
-
-#if defined(CONFIG_6xx) || defined(CONFIG_PPC64BRIDGE)
 /*
  * We're called here very early in the boot.  We determine the machine
  * type and call the appropriate low-level setup functions.
@@ -472,6 +305,13 @@
 	 * caches on yet */
 	memset_io(PTRRELOC(&__bss_start), 0, &_end - &__bss_start);
 
+	/*
+	 * Identify the CPU type and fix up code sections
+	 * that depend on which cpu we have.
+	 */
+	identify_cpu(offset, 0);
+	do_cpu_ftr_fixups(offset);
+
 #if defined(CONFIG_ALL_PPC)
 	/* If we came here from BootX, clear the screen,
 	 * set up some pointers and return. */
@@ -493,78 +333,105 @@
 
 	return phys;
 }
-#endif /* CONFIG_6xx || CONFIG_PPC64BRIDGE */
+
+#ifdef CONFIG_ALL_PPC
+void __init
+intuit_machine_type(void)
+{
+	char *model;
+	struct device_node *root;
+			
+	/* ask the OF info if we're a chrp or pmac */
+	root = find_path_device("/");
+	if (root != 0) {
+		/* assume pmac unless proven to be chrp -- Cort */
+		_machine = _MACH_Pmac;
+		model = get_property(root, "device_type", NULL);
+		if (model && !strncmp("chrp", model, 4))
+			_machine = _MACH_chrp;
+		else {
+			model = get_property(root, "model", NULL);
+			if (model && !strncmp(model, "IBM", 3))
+				_machine = _MACH_chrp;
+		}
+	}
+}
 
 /*
- * Find out what kind of machine we're on and save any data we need
- * from the early boot process (devtree is copied on pmac by prom_init() )
+ * The ALL_PPC version of platform_init...
  */
-unsigned long __init
-identify_machine(unsigned long r3, unsigned long r4, unsigned long r5,
-		 unsigned long r6, unsigned long r7)
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	      unsigned long r6, unsigned long r7)
 {
-#ifdef CONFIG_CMDLINE
-	strcpy(cmd_line, CONFIG_CMDLINE);
-#endif /* CONFIG_CMDLINE */
+#ifdef CONFIG_BOOTX_TEXT
+	extern boot_infos_t *disp_bi;
 
-	parse_bootinfo();
+	if (disp_bi) {
+		btext_clearscreen();
+		btext_welcome(disp_bi);
+	}
+#endif	
 
-	if ( ppc_md.progress ) ppc_md.progress("id mach(): start", 0x100);
-	
-#ifdef CONFIG_ALL_PPC
 	/* if we didn't get any bootinfo telling us what we are... */
-	if ( _machine == 0 )
-	{
+	if (_machine == 0) {
 		/* prep boot loader tells us if we're prep or not */
 		if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) )
-		{
 			_machine = _MACH_prep;
-		} else
-			have_of = 1;
 	}
 
-	if ( have_of )
-	{
-		/* prom_init has already been called from __start */
-		if (boot_infos)
-			relocate_nodes();
-		/* we need to set _machine before calling finish_device_tree */
-		if (_machine == 0)
-			intuit_machine_type();
-		finish_device_tree();
-		/*
-		 * If we were booted via quik, r3 points to the physical
-		 * address of the command-line parameters.
-		 * If we were booted from an xcoff image (i.e. netbooted or
-		 * booted from floppy), we get the command line from the
-		 * bootargs property of the /chosen node.
-		 * If an initial ramdisk is present, r3 and r4
-		 * are used for initrd_start and initrd_size,
-		 * otherwise they contain 0xdeadbeef.  
-		 */
-		if (r3 >= 0x4000 && r3 < 0x800000 && r4 == 0) {
-			strncpy(cmd_line, (char *)r3 + KERNELBASE,
+	/* not much more to do here, if prep */
+	if (_machine == _MACH_prep) {
+		prep_init(r3, r4, r5, r6, r7);
+		return;
+	}
+
+	/* prom_init has already been called from __start */
+	if (boot_infos)
+		relocate_nodes();
+
+	/* If we aren't PReP, we can find out if we're Pmac
+	 * or CHRP with this. */
+	if (_machine == 0)
+		intuit_machine_type();
+
+	/* finish_device_tree may need _machine defined. */
+	finish_device_tree();
+
+	/*
+	 * If we were booted via quik, r3 points to the physical
+	 * address of the command-line parameters.
+	 * If we were booted from an xcoff image (i.e. netbooted or
+	 * booted from floppy), we get the command line from the
+	 * bootargs property of the /chosen node.
+	 * If an initial ramdisk is present, r3 and r4
+	 * are used for initrd_start and initrd_size,
+	 * otherwise they contain 0xdeadbeef.  
+	 */
+	if (r3 >= 0x4000 && r3 < 0x800000 && r4 == 0) {
+		cmd_line[0] = 0;
+		strncpy(cmd_line, (char *)r3 + KERNELBASE,
+			sizeof(cmd_line));
+	} else if (boot_infos != 0) {
+		/* booted by BootX - check for ramdisk */
+		if (boot_infos->kernelParamsOffset != 0)
+			strncpy(cmd_line, (char *) boot_infos
+				+ boot_infos->kernelParamsOffset,
 				sizeof(cmd_line));
-		} else if (boot_infos != 0) {
-			/* booted by BootX - check for ramdisk */
- 			if (boot_infos->kernelParamsOffset != 0)
-				strncpy(cmd_line, (char *) boot_infos
-					+ boot_infos->kernelParamsOffset,
-					sizeof(cmd_line));
 #ifdef CONFIG_BLK_DEV_INITRD
-			if (boot_infos->ramDisk) {
-				initrd_start = (unsigned long) boot_infos
-					+ boot_infos->ramDisk;
-				initrd_end = initrd_start + boot_infos->ramDiskSize;
-				initrd_below_start_ok = 1;
-			}
+		if (boot_infos->ramDisk) {
+			initrd_start = (unsigned long) boot_infos
+				+ boot_infos->ramDisk;
+			initrd_end = initrd_start + boot_infos->ramDiskSize;
+			initrd_below_start_ok = 1;
+		}
 #endif
-		} else {
-			struct device_node *chosen;
-			char *p;
+	} else {
+		struct device_node *chosen;
+		char *p;
 			
 #ifdef CONFIG_BLK_DEV_INITRD
-			if (r3 && r4 && r4 != 0xdeadbeef)
+		if (r3 && r4 && r4 != 0xdeadbeef)
 			{
 				if (r3 < KERNELBASE)
 					r3 += KERNELBASE;
@@ -574,92 +441,32 @@
 				initrd_below_start_ok = 1;
 			}
 #endif
-			chosen = find_devices("chosen");
-			if (chosen != NULL) {
-				p = get_property(chosen, "bootargs", NULL);
-				if (p && *p) {
-					cmd_line[0] = 0;
-					strncpy(cmd_line, p, sizeof(cmd_line));
-				}
+		chosen = find_devices("chosen");
+		if (chosen != NULL) {
+			p = get_property(chosen, "bootargs", NULL);
+			if (p && *p) {
+				cmd_line[0] = 0;
+				strncpy(cmd_line, p, sizeof(cmd_line));
 			}
 		}
-		cmd_line[sizeof(cmd_line) - 1] = 0;
 	}
-#endif /* CONFIG_ALL_PPC */
+	cmd_line[sizeof(cmd_line) - 1] = 0;
 
-#if defined(CONFIG_ALL_PPC)
-	switch (_machine)
-	{
+	switch (_machine) {
 	case _MACH_Pmac:
-                pmac_init(r3, r4, r5, r6, r7);
-		break;
-	case _MACH_prep:
-                prep_init(r3, r4, r5, r6, r7);
+		pmac_init(r3, r4, r5, r6, r7);
 		break;
 	case _MACH_chrp:
-                chrp_init(r3, r4, r5, r6, r7);
+		chrp_init(r3, r4, r5, r6, r7);
 		break;
-	default:
-		printk("Unknown machine type in identify_machine!\n");
-	}
-#elif defined(CONFIG_APUS)
-	apus_init(r3, r4, r5, r6, r7);
-#elif defined(CONFIG_GEMINI)
-	gemini_init(r3, r4, r5, r6, r7);
-#elif defined(CONFIG_4xx)
-	oak_init(r3, r4, r5, r6, r7);
-#elif defined(CONFIG_8xx)
-        m8xx_init(r3, r4, r5, r6, r7);
-#elif defined(CONFIG_8260)
-        m8260_init(r3, r4, r5, r6, r7);
-#else
-#error "No board type has been defined for identify_machine()!"
-#endif
-
-#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) && !defined(CONFIG_8260)
-	/* Check for nobats option (used in mapin_ram). */
-	if (strstr(cmd_line, "nobats")) {
-		extern int __map_without_bats;
-		__map_without_bats = 1;
-	}
-#endif /* !CONFIG_4xx && !CONFIG_8xx && !CONFIG_8260 */
-
-	/* Look for mem= option on command line */
-	if (strstr(cmd_line, "mem=")) {
-		char *p, *q;
-		unsigned long maxmem = 0;
-		extern unsigned long __max_memory;
-
-		for (q = cmd_line; (p = strstr(q, "mem=")) != 0; ) {
-			q = p + 4;
-			if (p > cmd_line && p[-1] != ' ')
-				continue;
-			maxmem = simple_strtoul(q, &q, 0);
-			if (*q == 'k' || *q == 'K') {
-				maxmem <<= 10;
-				++q;
-			} else if (*q == 'm' || *q == 'M') {
-				maxmem <<= 20;
-				++q;
-			}
-		}
-		__max_memory = maxmem;
 	}
-
-	/* this is for modules since _machine can be a define -- Cort */
-	ppc_md.ppc_machine = _machine;
-
-	if ( ppc_md.progress ) ppc_md.progress("id mach(): done", 0x200);
-
-	return 0;
 }
+#endif /* CONFIG_ALL_PPC */
 
 int parse_bootinfo(void)
 {
 	struct bi_record *rec;
 	extern char __bss_start[];
-	extern char *sysmap;
-	extern unsigned long sysmap_size;
 
 	rec = (struct bi_record *)_ALIGN((ulong)__bss_start+(1<<20)-1,(1<<20));
 	if ( rec->tag != BI_FIRST )
@@ -696,20 +503,43 @@
 #ifdef CONFIG_ALL_PPC
 		case BI_MACHTYPE:
 			_machine = data[0];
-			have_of = data[1];
 			break;
 #endif /* CONFIG_ALL_PPC */
+		case BI_MEMSIZE:
+			boot_mem_size = data[0];
+			break;
 		}
 	}
 
 	return 0;
 }
 
+/*
+ * Find out what kind of machine we're on and save any data we need
+ * from the early boot process (devtree is copied on pmac by prom_init()).
+ * This is called very early on the boot process, after a minimal
+ * MMU environment has been set up but before MMU_init is called.
+ */
+void __init
+machine_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	     unsigned long r6, unsigned long r7)
+{
+#ifdef CONFIG_CMDLINE
+	strcpy(cmd_line, CONFIG_CMDLINE);
+#endif /* CONFIG_CMDLINE */
+
+	parse_bootinfo();
+
+	platform_init(r3, r4, r5, r6, r7);
+
+	if (ppc_md.progress)
+		ppc_md.progress("id mach(): done", 0x200);
+}
+
 /* Checks "l2cr=xxxx" command-line option */
-int ppc_setup_l2cr(char *str)
+int __init ppc_setup_l2cr(char *str)
 {
-	if ( ((_get_PVR() >> 16) == 8) || ((_get_PVR() >> 16) == 12) )
-	{
+	if (cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR) {
 		unsigned long val = simple_strtoul(str, NULL, 0);
 		printk(KERN_INFO "l2cr set to %lx\n", val);
                 _set_L2CR(0);           /* force invalidate by disable cache */
@@ -761,18 +591,13 @@
 	 * Systems with OF can look in the properties on the cpu node(s)
 	 * for a possibly more accurate value.
 	 */
-	dcache_bsize = icache_bsize = 32;	/* most common value */
-	switch (_get_PVR() >> 16) {
-	case 1:		/* 601, with unified cache */
-		ucache_bsize = 32;
-		break;
-	/* XXX need definitions in here for 8xx etc. */
-	case 0x40:
-	case 0x41:
-	case 0x35:	/* 64-bit POWER3, POWER3+, POWER4 */
-		dcache_bsize = icache_bsize = 128;
-		break;
-	}
+	if (cur_cpu_spec[0]->cpu_features & CPU_FTR_SPLIT_ID_CACHE) {
+		dcache_bsize = cur_cpu_spec[0]->dcache_bsize;
+		icache_bsize = cur_cpu_spec[0]->icache_bsize;
+		ucache_bsize = 0;
+	} else
+		ucache_bsize = dcache_bsize = icache_bsize
+			= cur_cpu_spec[0]->dcache_bsize;
 
 	/* reboot on panic */
 	panic_timeout = 180;
@@ -813,6 +638,9 @@
 
 	paging_init();
 	sort_exception_table();
+
+	/* this is for modules since _machine can be a define -- Cort */
+	ppc_md.ppc_machine = _machine;
 }
 
 /* Convert the shorts/longs in hd_driveid from little to big endian;
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/sleep.S linux/arch/ppc/kernel/sleep.S
--- v2.4.9/linux/arch/ppc/kernel/sleep.S	Tue Jul  3 17:08:18 2001
+++ linux/arch/ppc/kernel/sleep.S	Tue Aug 28 06:58:33 2001
@@ -1,10 +1,10 @@
 /*
- * BK Id: SCCS/s.sleep.S 1.10 06/28/01 15:50:17 paulus
+ * BK Id: SCCS/s.sleep.S 1.13 08/19/01 22:23:04 paulus
  */
 /*
  * This file contains sleep low-level functions for PowerBook G3.
  *    Copyright (C) 1999 Benjamin Herrenschmidt (benh@kernel.crashing.org)
- *    and Paul Mackerras (paulus@cs.anu.edu.au).
+ *    and Paul Mackerras (paulus@samba.org).
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -45,7 +45,13 @@
 #define tovirt(rd,rs)	addis	rd,rs,KERNELBASE@h
 
 	.text
+	.align	5
 
+/* This gets called by via-pmu.c late during the sleep process.
+ * The PMU was already send the sleep command and will shut us down
+ * soon. We need to save all that is needed and setup the wakeup
+ * vector that will be called by the ROM on wakeup
+ */
 _GLOBAL(low_sleep_handler)
 	mflr	r0
 	stw	r0,4(r1)
@@ -53,13 +59,14 @@
 	stw	r2,SL_R2(r1)
 	stmw	r12,SL_R12(r1)
 
-	/* Save MSR, SDR1, TB  */
+	/* Save MSR & SDR1 */
 	mfmsr	r4
 	stw	r4,SL_MSR(r1)
 	mfsdr1	r4
 	stw	r4,SL_SDR1(r1)
-1:	
-	mftbu	r4
+
+	/* Get a stable timebase and save it */
+1:	mftbu	r4
 	stw	r4,SL_TB(r1)
 	mftb	r5
 	stw	r5,SL_TB+4(r1)
@@ -114,10 +121,19 @@
 	/* Save HID0 */
 	mfspr	r4,HID0
 	stw	r4,SL_HID0(r1)
-
-	/* Set up stuff at address 0 */
-	lis	r5,wake_up@ha
-	addi	r5,r5,wake_up@l
+	
+	/* The ROM can wake us up via 2 different vectors:
+	 *  - On wallstreet & lombard, we must write a magic
+	 *    value 'Lars' at address 4 and a pointer to a
+	 *    memory location containing the PC to resume from
+	 *    at address 0.
+	 *  - On Core99, we must store the wakeup vector at
+	 *    address 0x80 and eventually it's parameters
+	 *    at address 0x84. I've have some trouble with those
+	 *    parameters however and I no longer use them.
+	 */
+	lis	r5,grackle_wake_up@ha
+	addi	r5,r5,grackle_wake_up@l
 	tophys(r5,r5)
 	stw	r5,SL_PC(r1)
 	lis	r4,KERNELBASE@h
@@ -127,22 +143,35 @@
 	addi	r6,r6,MAGIC@l
 	stw	r5,0(r4)
 	stw	r6,4(r4)
+	/* Setup stuffs at 0x80-0x84 for Core99 */
+	lis	r3,core99_wake_up@ha
+	addi	r3,r3,core99_wake_up@l
+	tophys(r3,r3)
+	stw	r3,0x80(r4)
+	stw	r5,0x84(r4)
+	/* Store a pointer to our backup storage into
+	 * a kernel global
+	 */
+	lis r3,sleep_storage@ha
+	addi r3,r3,sleep_storage@l
+	stw r5,0(r3)
+
 
 /*
- * Flush the L1 data cache by reading the first 64kB of RAM
+ * Flush the L1 data cache by reading the first 128kB of RAM
  * and then flushing the same area with the dcbf instruction.
  * The L2 cache has already been disabled.
  */
-	li	r4,0x0800	/* 64kB / 32B */
+	li	r4,0x1000	/* 128kB / 32B */
 	mtctr	r4
 	lis	r4,KERNELBASE@h
 1:
 	lwz	r0,0(r4)
-	addi	r4,r4,0x0020		/* Go to start of next cache line */
+	addi	r4,r4,0x0020	/* Go to start of next cache line */
 	bdnz	1b
 	sync
 	
-	li	r4,0x0800	/* 64k */
+	li	r4,0x1000	/* 128kB / 32B */
 	mtctr	r4
 	lis	r4,KERNELBASE@h
 1:
@@ -160,7 +189,13 @@
 	sync
 	mtspr	HID0,r2
 	sync
-	
+
+/* This loop puts us back to sleep in case we have a spurrious
+ * wakeup so that the host bridge properly stays asleep. The
+ * CPU will be turned off, either after a known time (about 1
+ * second) on wallstreet & lombard, or as soon as the CPU enters
+ * SLEEP mode on core99
+ */
 	mfmsr	r2
 	oris	r2,r2,MSR_POW@h
 1:	sync
@@ -170,22 +205,66 @@
 
 /* 
  * Here is the resume code.
+ */
+
+
+/*
+ * Core99 machines resume here
+ * r4 has the physical address of SL_PC(sp) (unused)
+ */
+_GLOBAL(core99_wake_up)
+	/* Make sure HID0 no longer contains any sleep bit */
+	mfspr	r3,HID0
+	rlwinm	r3,r3,0,11,7		/* clear SLEEP, NAP, DOZE bits */
+	mtspr	HID0,r3
+	sync
+	isync
+
+	/* Won't that cause problems on CPU that doesn't support it ? */
+	lis	r3, 0
+	mtspr	SPRN_MMCR0, r3
+	
+	/* sanitize MSR */
+	mfmsr	r3
+	ori	r3,r3,MSR_EE|MSR_IP
+	xori	r3,r3,MSR_EE|MSR_IP
+	sync
+	isync
+	mtmsr	r3
+	sync
+	isync
+
+	/* Recover sleep storage */
+	lis	r3,sleep_storage@ha
+	addi	r3,r3,sleep_storage@l
+	tophys(r3,r3)
+	lwz	r1,0(r3)
+
+	/* Pass thru to older resume code ... */
+/* 
+ * Here is the resume code for older machines.
  * r1 has the physical address of SL_PC(sp).
  */
 	
-wake_up:
-	/* Flash inval the instruction cache */
+grackle_wake_up:
+	/* Enable and then Flash inval the instruction & data cache */
 	mfspr	r3,HID0
-	ori	r3,r3, HID0_ICFI
-	mtspr	HID0,r3
+	ori	r3,r3, HID0_ICE|HID0_ICFI|HID0_DCE|HID0_DCI
+	sync
 	isync
-	/* Restore the HID0 register.  This turns on the L1 caches. */
+	mtspr	HID0,r3
+	xori	r3,r3, HID0_ICFI|HID0_DCI
+	mtspr	HID0,r3
+	sync
+	
+	/* Restore the remaining bits of the HID0 register. */
 	subi	r1,r1,SL_PC
 	lwz	r3,SL_HID0(r1)
 	sync
 	isync
 	mtspr	HID0,r3
 	sync
+	isync
 
 	/* Restore the kernel's segment registers, the
 	   BATs, and SDR1.  Then we can turn on the MMU. */
@@ -242,6 +321,13 @@
 	lwz	r4,SL_IBAT3+4(r1)
 	mtibatl	3,r4
 
+	/* Flush all TLBs */
+	lis	r4,0x1000
+1:	addic.	r4,r4,-0x1000
+	tlbie	r4
+	blt	1b
+	sync
+
 	/* restore the MSR and turn on the MMU */
 	lwz	r3,SL_MSR(r1)
 	bl	turn_on_mmu	
@@ -250,6 +336,8 @@
 	tovirt(r1,r1)
 
 	/* Restore TB */
+	li	r3,0
+	mttbl	r3
 	lwz	r3,SL_TB(r1)
 	lwz	r4,SL_TB+4(r1)
 	mttbu	r3
@@ -269,4 +357,10 @@
 	mtsrr0	r4
 	mtsrr1	r3
 	sync
+	isync
 	rfi
+
+	.data
+	.globl sleep_storage
+sleep_storage:
+	.long 0
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/smp.c linux/arch/ppc/kernel/smp.c
--- v2.4.9/linux/arch/ppc/kernel/smp.c	Tue Jul  3 17:08:18 2001
+++ linux/arch/ppc/kernel/smp.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.smp.c 1.25 05/23/01 00:38:42 cort
+ * BK Id: SCCS/s.smp.c 1.29 08/20/01 21:35:14 paulus
  */
 /*
  * Smp support for ppc.
@@ -9,11 +9,6 @@
  *
  * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
  *
- * Support for PReP (Motorola MTX/MVME) and Macintosh G4 SMP 
- * by Troy Benjegerdes (hozer@drgw.net)
- *
- * Support for DayStar quad CPU cards
- * Copyright (C) XLR8, Inc. 1994-2000
  */
 
 #include <linux/config.h>
@@ -43,9 +38,9 @@
 #include <asm/residual.h>
 #include <asm/feature.h>
 #include <asm/time.h>
-#include <asm/gemini.h>
 
 #include "open_pic.h"
+
 int smp_threads_ready;
 volatile int smp_commenced;
 int smp_num_cpus = 1;
@@ -54,13 +49,14 @@
 struct klock_info_struct klock_info = { KLOCK_CLEAR, 0 };
 atomic_t ipi_recv;
 atomic_t ipi_sent;
-spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED;
+spinlock_t kernel_flag __cacheline_aligned = SPIN_LOCK_UNLOCKED;
 unsigned int prof_multiplier[NR_CPUS];
 unsigned int prof_counter[NR_CPUS];
 cycles_t cacheflush_time;
 static int max_cpus __initdata = NR_CPUS;
 unsigned long cpu_online_map;
 int smp_hw_index[NR_CPUS];
+static struct smp_ops_t *smp_ops;
 
 /* all cpu mappings are 1-1 -- Cort */
 volatile unsigned long cpu_callin_map[NR_CPUS];
@@ -74,60 +70,6 @@
 void smp_call_function_interrupt(void);
 void smp_message_pass(int target, int msg, unsigned long data, int wait);
 
-extern void __secondary_start_psurge(void);
-extern void __secondary_start_psurge2(void);	/* Temporary horrible hack */
-extern void __secondary_start_psurge3(void);	/* Temporary horrible hack */
-
-/* Addresses for powersurge registers */
-#define HAMMERHEAD_BASE		0xf8000000
-#define HHEAD_CONFIG		0x90
-#define HHEAD_SEC_INTR		0xc0
-
-/* register for interrupting the primary processor on the powersurge */
-/* N.B. this is actually the ethernet ROM! */
-#define PSURGE_PRI_INTR		0xf3019000
-
-/* register for storing the start address for the secondary processor */
-/* N.B. this is the PCI config space address register for the 1st bridge */
-#define PSURGE_START		0xf2800000
-
-/* Daystar/XLR8 4-CPU card */
-#define PSURGE_QUAD_REG_ADDR	0xf8800000
-
-#define PSURGE_QUAD_IRQ_SET	0
-#define PSURGE_QUAD_IRQ_CLR	1
-#define PSURGE_QUAD_IRQ_PRIMARY	2
-#define PSURGE_QUAD_CKSTOP_CTL	3
-#define PSURGE_QUAD_PRIMARY_ARB	4
-#define PSURGE_QUAD_BOARD_ID	6
-#define PSURGE_QUAD_WHICH_CPU	7
-#define PSURGE_QUAD_CKSTOP_RDBK	8
-#define PSURGE_QUAD_RESET_CTL	11
-
-#define PSURGE_QUAD_OUT(r, v)	(out_8(quad_base + ((r) << 4) + 4, (v)))
-#define PSURGE_QUAD_IN(r)	(in_8(quad_base + ((r) << 4) + 4) & 0x0f)
-#define PSURGE_QUAD_BIS(r, v)	(PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) | (v)))
-#define PSURGE_QUAD_BIC(r, v)	(PSURGE_QUAD_OUT((r), PSURGE_QUAD_IN(r) & ~(v)))
-
-/* virtual addresses for the above */
-static volatile u8 *hhead_base;
-static volatile u8 *quad_base;
-static volatile u32 *psurge_pri_intr;
-static volatile u8 *psurge_sec_intr;
-static volatile u32 *psurge_start;
-
-/* what sort of powersurge board we have */
-static int psurge_type;
-
-/* values for psurge_type */
-#define PSURGE_DUAL		0
-#define PSURGE_QUAD_OKEE	1
-#define PSURGE_QUAD_COTTON	2
-#define PSURGE_QUAD_ICEGRASS	3
-
-/* l2 cache stuff for dual G4 macs */
-extern void core99_init_l2(void);
-
 /* Since OpenPIC has only 4 IPIs, we use slightly different message numbers.
  * 
  * Make sure this matches openpic_request_IPIs in open_pic.c, or what shows up
@@ -137,621 +79,12 @@
 #define PPC_MSG_INVALIDATE_TLB	2
 #define PPC_MSG_XMON_BREAK	3
 
-static inline void set_tb(unsigned int upper, unsigned int lower)
-{
-	mtspr(SPRN_TBWL, 0);
-	mtspr(SPRN_TBWU, upper);
-	mtspr(SPRN_TBWL, lower);
-}
-
-/*
- * Set and clear IPIs for powersurge.
- */
-static inline void psurge_set_ipi(int cpu)
-{
-	if (cpu == 0)
-		in_be32(psurge_pri_intr);
-	else if (psurge_type == PSURGE_DUAL)
-		out_8(psurge_sec_intr, 0);
-	else
-		PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_SET, 1 << cpu);
-}
-
-static inline void psurge_clr_ipi(int cpu)
-{
-	if (cpu > 0) {
-		if (psurge_type == PSURGE_DUAL)
-			out_8(psurge_sec_intr, ~0);
-		else
-			PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, 1 << cpu);
-	}
-}
-
-/*
- * On powersurge (old SMP powermac architecture) we don't have
- * separate IPIs for separate messages like openpic does.  Instead
- * we have a bitmap for each processor, where a 1 bit means that
- * the corresponding message is pending for that processor.
- * Ideally each cpu's entry would be in a different cache line.
- *  -- paulus.
- */
-static unsigned long psurge_smp_message[NR_CPUS];
-
-void psurge_smp_message_recv(struct pt_regs *regs)
-{
-	int cpu = smp_processor_id();
-	int msg;
-
-	/* clear interrupt */
-	psurge_clr_ipi(cpu);
-
-	if (smp_num_cpus < 2)
-		return;
-
-	/* make sure there is a message there */
-	for (msg = 0; msg < 4; msg++)
-		if (test_and_clear_bit(msg, &psurge_smp_message[cpu]))
-			smp_message_recv(msg, regs);
-}
-
-void
-psurge_primary_intr(int irq, void *d, struct pt_regs *regs)
-{
-	psurge_smp_message_recv(regs);
-}
-
-static void
-smp_psurge_message_pass(int target, int msg, unsigned long data, int wait)
-{
-	int i;
-
-	if (smp_num_cpus < 2)
-		return;
-
-	for (i = 0; i < smp_num_cpus; i++) {
-		if (target == MSG_ALL
-		    || (target == MSG_ALL_BUT_SELF && i != smp_processor_id())
-		    || target == i) {
-			set_bit(msg, &psurge_smp_message[i]);
-			psurge_set_ipi(i);
-		}
-	}
-}
-
-/*
- * Determine a quad card presence. We read the board ID register, we
- * force the data bus to change to something else, and we read it again.
- * It it's stable, then the register probably exist (ugh !)
- */
-static int __init psurge_quad_probe(void)
-{
-	int type;
-	unsigned int i;
-
-	type = PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID);
-	if (type < PSURGE_QUAD_OKEE || type > PSURGE_QUAD_ICEGRASS
-	    || type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID))
-		return PSURGE_DUAL;
-
-	/* looks OK, try a slightly more rigorous test */
-	/* bogus is not necessarily cacheline-aligned,
-	   though I don't suppose that really matters.  -- paulus */
-	for (i = 0; i < 100; i++) {
-		volatile u32 bogus[8];
-		bogus[(0+i)%8] = 0x00000000;
-		bogus[(1+i)%8] = 0x55555555;
-		bogus[(2+i)%8] = 0xFFFFFFFF;
-		bogus[(3+i)%8] = 0xAAAAAAAA;
-		bogus[(4+i)%8] = 0x33333333;
-		bogus[(5+i)%8] = 0xCCCCCCCC;
-		bogus[(6+i)%8] = 0xCCCCCCCC;
-		bogus[(7+i)%8] = 0x33333333;
-		wmb();
-		asm volatile("dcbf 0,%0" : : "r" (bogus) : "memory");
-		mb();
-		if (type != PSURGE_QUAD_IN(PSURGE_QUAD_BOARD_ID))
-			return PSURGE_DUAL;
-	}
-	return type;
-}
-
-static void __init psurge_quad_init(void)
-{
-	int procbits;
-
-	if (ppc_md.progress) ppc_md.progress("psurge_quad_init", 0x351);
-	procbits = ~PSURGE_QUAD_IN(PSURGE_QUAD_WHICH_CPU);
-	if (psurge_type == PSURGE_QUAD_ICEGRASS)
-		PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits);
-	else
-		PSURGE_QUAD_BIC(PSURGE_QUAD_CKSTOP_CTL, procbits);
-	mdelay(33);
-	out_8(psurge_sec_intr, ~0);
-	PSURGE_QUAD_OUT(PSURGE_QUAD_IRQ_CLR, procbits);
-	PSURGE_QUAD_BIS(PSURGE_QUAD_RESET_CTL, procbits);
-	if (psurge_type != PSURGE_QUAD_ICEGRASS)
-		PSURGE_QUAD_BIS(PSURGE_QUAD_CKSTOP_CTL, procbits);
-	PSURGE_QUAD_BIC(PSURGE_QUAD_PRIMARY_ARB, procbits);
-	mdelay(33);
-	PSURGE_QUAD_BIC(PSURGE_QUAD_RESET_CTL, procbits);
-	mdelay(33);
-	PSURGE_QUAD_BIS(PSURGE_QUAD_PRIMARY_ARB, procbits);
-	mdelay(33);
-}
-
-static int __init smp_psurge_probe(void)
-{
-	int i, ncpus;
-
-	/* We don't do SMP on the PPC601 -- paulus */
-	if ((_get_PVR() >> 16) == 1)
-		return 1;
-
-	/*
-	 * The powersurge cpu board can be used in the generation
-	 * of powermacs that have a socket for an upgradeable cpu card,
-	 * including the 7500, 8500, 9500, 9600.
-	 * The device tree doesn't tell you if you have 2 cpus because
-	 * OF doesn't know anything about the 2nd processor.
-	 * Instead we look for magic bits in magic registers,
-	 * in the hammerhead memory controller in the case of the
-	 * dual-cpu powersurge board.  -- paulus.
-	 */
-	if (find_devices("hammerhead") == NULL)
-		return 1;
-
-	hhead_base = ioremap(HAMMERHEAD_BASE, 0x800);
-	quad_base = ioremap(PSURGE_QUAD_REG_ADDR, 1024);
-	psurge_sec_intr = hhead_base + HHEAD_SEC_INTR;
-
-	psurge_type = psurge_quad_probe();
-	if (psurge_type != PSURGE_DUAL) {
-		psurge_quad_init();
-		/* All released cards using this HW design have 4 CPUs */
-		ncpus = 4;
-	} else {
-		iounmap((void *) quad_base);
-		if ((in_8(hhead_base + HHEAD_CONFIG) & 0x02) == 0) {
-			/* not a dual-cpu card */
-			iounmap((void *) hhead_base);
-			return 1;
-		}
-		ncpus = 2;
-	}
-
-	psurge_start = ioremap(PSURGE_START, 4);
-	psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4);
-
-	/* this is not actually strictly necessary -- paulus. */
-	for (i = 1; i < ncpus; ++i)
-		smp_hw_index[i] = i;
-
-	if (ppc_md.progress) ppc_md.progress("smp_psurge_probe - done", 0x352);
-
-	return ncpus;
-}
-
-static void __init smp_psurge_kick_cpu(int nr)
-{
-	void (*start)(void) = __secondary_start_psurge;
-
-	if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu", 0x353);
-
-	/* setup entry point of secondary processor */
-	switch (nr) {
-	case 2:
-		start = __secondary_start_psurge2;
-		break;
-	case 3:
-		start = __secondary_start_psurge3;
-		break;
-	}
-
-	out_be32(psurge_start, __pa(start));
-	mb();
-
-	psurge_set_ipi(nr);
-	udelay(10);
-	psurge_clr_ipi(nr);
-
-	if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354);
-}
-
-/*
- * With the dual-cpu powersurge board, the decrementers and timebases
- * of both cpus are frozen after the secondary cpu is started up,
- * until we give the secondary cpu another interrupt.  This routine
- * uses this to get the timebases synchronized.
- *  -- paulus.
- */
-static void __init psurge_dual_sync_tb(int cpu_nr)
-{
-	static volatile int sec_tb_reset = 0;
-	int t;
-
-	set_dec(tb_ticks_per_jiffy);
-	set_tb(0, 0);
-	last_jiffy_stamp(cpu_nr) = 0;
-
-	if (cpu_nr > 0) {
-		mb();
-		sec_tb_reset = 1;
-		return;
-	}
-
-	/* wait for the secondary to have reset its TB before proceeding */
-	for (t = 10000000; t > 0 && !sec_tb_reset; --t)
-		;
-
-	/* now interrupt the secondary, starting both TBs */
-	psurge_set_ipi(1);
-
-	smp_tb_synchronized = 1;
-}
-
-static void
-smp_psurge_setup_cpu(int cpu_nr)
-{
-
-	if (cpu_nr == 0) {
-		if (smp_num_cpus < 2)
-			return;
-		/* reset the entry point so if we get another intr we won't
-		 * try to startup again */
-		out_be32(psurge_start, 0x100);
-		if (request_irq(30, psurge_primary_intr, 0, "primary IPI", 0))
-			printk(KERN_ERR "Couldn't get primary IPI interrupt");
-	}
-
-	if (psurge_type == PSURGE_DUAL)
-		psurge_dual_sync_tb(cpu_nr);
-}
-
-
-static void
-smp_openpic_message_pass(int target, int msg, unsigned long data, int wait)
-{
-	/* make sure we're sending something that translates to an IPI */
-	if ( msg > 0x3 ){
-		printk("SMP %d: smp_message_pass: unknown msg %d\n",
-		       smp_processor_id(), msg);
-		return;
-	}
-	switch ( target )
-	{
-	case MSG_ALL:
-		openpic_cause_IPI(msg, 0xffffffff);
-		break;
-	case MSG_ALL_BUT_SELF:
-		openpic_cause_IPI(msg,
-				  0xffffffff & ~(1 << smp_processor_id()));
-		break;
-	default:
-		openpic_cause_IPI(msg, 1<<target);
-		break;
-	}
-}
-
-static int
-smp_core99_probe(void)
-{
-	struct device_node *cpus;
-	int i, ncpus = 1;
-
-	if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345);
-	cpus = find_type_devices("cpu");
-	if (cpus)
-		while ((cpus = cpus->next) != NULL)
-			++ncpus;
-	printk("smp_core99_probe: found %d cpus\n", ncpus);
-	if (ncpus > 1) {
-		openpic_request_IPIs();
-		for (i = 1; i < ncpus; ++i)
-			smp_hw_index[i] = i;
-	}
-
-	return ncpus;
-}
-
-static void
-smp_core99_kick_cpu(int nr)
-{
-	unsigned long save_vector, new_vector;
-	unsigned long flags;
-#if 1 /* New way... */
-	volatile unsigned long *vector
-		 = ((volatile unsigned long *)(KERNELBASE+0x100));
-	if (nr < 1 || nr > 3)
-		return;
-#else
-	volatile unsigned long *vector
-		 = ((volatile unsigned long *)(KERNELBASE+0x500));
-	if (nr != 1)
-		return;
-#endif
-	if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu", 0x346);
-
-	local_irq_save(flags);
-	local_irq_disable();
-	
-	/* Save reset vector */
-	save_vector = *vector;
-	
-	/* Setup fake reset vector that does	  
-	 *   b __secondary_start_psurge - KERNELBASE
-	 */  
-	switch(nr) {
-		case 1:
-			new_vector = (unsigned long)__secondary_start_psurge;
-			break;
-		case 2:
-			new_vector = (unsigned long)__secondary_start_psurge2;
-			break;
-		case 3:
-			new_vector = (unsigned long)__secondary_start_psurge3;
-			break;
-	}
-	*vector = 0x48000002 + new_vector - KERNELBASE;
-	
-	/* flush data cache and inval instruction cache */
-	flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
-	
-	/* Put some life in our friend */
-	feature_core99_kick_cpu(nr);
-	
-	/* FIXME: We wait a bit for the CPU to take the exception, I should
-	 * instead wait for the entry code to set something for me. Well,
-	 * ideally, all that crap will be done in prom.c and the CPU left
-	 * in a RAM-based wait loop like CHRP.
-	 */
-	mdelay(1);
-	
-	/* Restore our exception vector */
-	*vector = save_vector;
-	flush_icache_range((unsigned long) vector, (unsigned long) vector + 4);
-	
-	local_irq_restore(flags);
-	if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347);
-}
-
-static void
-smp_core99_setup_cpu(int cpu_nr)
-{
-	/* Setup openpic */
-	do_openpic_setup_cpu();
-
-	/* Setup L2 */
-	if (cpu_nr != 0)
-		core99_init_l2();
-	else
-		if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349);
-}
-
-static int
-smp_chrp_probe(void)
-{
-	extern unsigned long smp_chrp_cpu_nr;
-
-	if (smp_chrp_cpu_nr > 1)
-		openpic_request_IPIs();
-
-	return smp_chrp_cpu_nr;
-}
-
-static void
-smp_chrp_kick_cpu(int nr)
-{
-	*(unsigned long *)KERNELBASE = nr;
-	asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
-}
-
-static void
-smp_chrp_setup_cpu(int cpu_nr)
-{
-	static atomic_t ready = ATOMIC_INIT(1);
-	static volatile int frozen = 0;
-
-	if (cpu_nr == 0) {
-		/* wait for all the others */
-		while (atomic_read(&ready) < smp_num_cpus)
-			barrier();
-		atomic_set(&ready, 1);
-		/* freeze the timebase */
-		call_rtas("freeze-time-base", 0, 1, NULL);
-		mb();
-		frozen = 1;
-		/* XXX assumes this is not a 601 */
-		set_tb(0, 0);
-		last_jiffy_stamp(0) = 0;
-		while (atomic_read(&ready) < smp_num_cpus)
-			barrier();
-		/* thaw the timebase again */
-		call_rtas("thaw-time-base", 0, 1, NULL);
-		mb();
-		frozen = 0;
-		smp_tb_synchronized = 1;
-	} else {
-		atomic_inc(&ready);
-		while (!frozen)
-			barrier();
-		set_tb(0, 0);
-		last_jiffy_stamp(0) = 0;
-		mb();
-		atomic_inc(&ready);
-		while (frozen)
-			barrier();
-	}
-
-	if (OpenPIC_Addr)
-		do_openpic_setup_cpu();
-}
-
-#ifdef CONFIG_POWER4
-static void
-smp_xics_message_pass(int target, int msg, unsigned long data, int wait)
-{
-	/* for now, only do reschedule messages
-	   since we only have one IPI */
-	if (msg != PPC_MSG_RESCHEDULE)
-		return;
-	for (i = 0; i < smp_num_cpus; ++i) {
-		if (target == MSG_ALL || target == i
-		    || (target == MSG_ALL_BUT_SELF
-			&& i != smp_processor_id()))
-			xics_cause_IPI(i);
-	}
-}
-
-static int
-smp_xics_probe(void)
-{
-	return smp_chrp_cpu_nr;
-}
-
-static void
-smp_xics_setup_cpu(int cpu_nr)
-{
-	if (cpu_nr > 0)
-		xics_setup_cpu();
-}
-#endif /* CONFIG_POWER4 */
-
-static int
-smp_prep_probe(void)
-{
-	extern int mot_multi;
-
-	if (mot_multi) {
-		openpic_request_IPIs();
-		smp_hw_index[1] = 1;
-		return 2;
-	}
-
-	return 1;
-}
-
-static void
-smp_prep_kick_cpu(int nr)
-{
-	extern unsigned long *MotSave_SmpIar;
-	extern unsigned char *MotSave_CpusState[2];
-
-	*MotSave_SmpIar = (unsigned long)__secondary_start_psurge - KERNELBASE;
-	*MotSave_CpusState[1] = CPU_GOOD;
-	printk("CPU1 reset, waiting\n");
-}
-
-static void
-smp_prep_setup_cpu(int cpu_nr)
-{
-	if (OpenPIC_Addr)
-		do_openpic_setup_cpu();
-}
-
-#ifdef CONFIG_GEMINI	
-static int
-smp_gemini_probe(void)
-{
-	int i, nr;
-
-        nr = (readb(GEMINI_CPUSTAT) & GEMINI_CPU_COUNT_MASK) >> 2;
-	if (nr == 0)
-		nr = 4;
-
-	if (nr > 1) {
-		openpic_request_IPIs();
-		for (i = 1; i < nr; ++i)
-			smp_hw_index[i] = i;
-	}
-
-	return nr;
-}
-
-static void
-smp_gemini_kick_cpu(int nr)
-{
-	openpic_init_processor( 1<<nr );
-	openpic_init_processor( 0 );
-}
-
-static void
-smp_gemini_setup_cpu(int cpu_nr)
-{
-	if (OpenPIC_Addr)
-		do_openpic_setup_cpu();
-	if (cpu_nr > 0)
-		gemini_init_l2();
-}
-#endif /* CONFIG_GEMINI */
-
-
-static struct smp_ops_t {
-	void  (*message_pass)(int target, int msg, unsigned long data, int wait);
-	int   (*probe)(void);
-	void  (*kick_cpu)(int nr);
-	void  (*setup_cpu)(int nr);
-
-} *smp_ops;
-
 #define smp_message_pass(t,m,d,w) \
     do { if (smp_ops) \
 	     atomic_inc(&ipi_sent); \
 	     smp_ops->message_pass((t),(m),(d),(w)); \
        } while(0)
 
-
-/* PowerSurge-style Macs */
-static struct smp_ops_t psurge_smp_ops = {
-	smp_psurge_message_pass,
-	smp_psurge_probe,
-	smp_psurge_kick_cpu,
-	smp_psurge_setup_cpu,
-};
-
-/* Core99 Macs (dual G4s) */
-static struct smp_ops_t core99_smp_ops = {
-	smp_openpic_message_pass,
-	smp_core99_probe,
-	smp_core99_kick_cpu,
-	smp_core99_setup_cpu,
-};
-
-/* CHRP with openpic */
-static struct smp_ops_t chrp_smp_ops = {
-	smp_openpic_message_pass,
-	smp_chrp_probe,
-	smp_chrp_kick_cpu,
-	smp_chrp_setup_cpu,
-};
-
-#ifdef CONFIG_POWER4
-/* CHRP with new XICS interrupt controller */
-static struct smp_ops_t xics_smp_ops = {
-	smp_xics_message_pass,
-	smp_xics_probe,
-	smp_chrp_kick_cpu,
-	smp_xics_setup_cpu,
-};
-#endif /* CONFIG_POWER4 */
-
-/* PReP (MTX) */
-static struct smp_ops_t prep_smp_ops = {
-	smp_openpic_message_pass,
-	smp_prep_probe,
-	smp_prep_kick_cpu,
-	smp_prep_setup_cpu,
-};
-
-#ifdef CONFIG_GEMINI	
-/* Gemini */
-static struct smp_ops_t gemini_smp_ops = {
-	smp_openpic_message_pass,
-	smp_gemini_probe,
-	smp_gemini_kick_cpu,
-	smp_gemini_setup_cpu,
-};
-#endif /* CONFIG_GEMINI	*/
-
 /* 
  * Common functions
  */
@@ -798,7 +131,7 @@
  */
 void smp_send_tlb_invalidate(int cpu)
 {
-	if ( (_get_PVR()>>16) == 8 )
+	if ( PVR_VER(mfspr(PVR)) == 8 )
 		smp_message_pass(MSG_ALL_BUT_SELF, PPC_MSG_INVALIDATE_TLB, 0, 0);
 }
 
@@ -947,7 +280,6 @@
 	extern struct task_struct *current_set[NR_CPUS];
 	int i, cpu_nr;
 	struct task_struct *p;
-	unsigned long a;
 
 	printk("Entering SMP Mode...\n");
 	smp_num_cpus = 1;
@@ -973,35 +305,12 @@
 	 */
 	cacheflush_time = 5 * 1024;
 
-	/* To be later replaced by some arch-specific routine */
-	switch(_machine) {
-	case _MACH_Pmac:
-		/* Check for Core99 */
-		if (find_devices("uni-n"))
-			smp_ops = &core99_smp_ops;
-		else
-			smp_ops = &psurge_smp_ops;
-		break;
-	case _MACH_chrp:
-#ifndef CONFIG_POWER4
-		smp_ops = &chrp_smp_ops;
-#else
-		smp_ops = &xics_smp_ops;
-#endif /* CONFIG_POWER4 */
-		break;
-	case _MACH_prep:
-		smp_ops = &prep_smp_ops;
-		break;
-#ifdef CONFIG_GEMINI		
-	case _MACH_gemini:
-		smp_ops = &gemini_smp_ops;
-		break;
-#endif /* CONFIG_GEMINI	*/
-	default:
+	smp_ops = ppc_md.smp_ops;
+	if (smp_ops == NULL) {
 		printk("SMP not supported on this machine.\n");
 		return;
 	}
-	
+
 	/* Probe arch for CPUs */
 	cpu_nr = smp_ops->probe();
 
@@ -1044,10 +353,12 @@
 		p->has_cpu = 1;
 		current_set[i] = p;
 
-		/* need to flush here since secondary bats aren't setup */
-		for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)
-			asm volatile("dcbf 0,%0" : : "r" (a) : "memory");
-		asm volatile("sync");
+		/*
+		 * There was a cache flush loop here to flush the cache
+		 * to memory for the first 8MB of RAM.  The cache flush
+		 * has been pushed into the kick_cpu function for those
+		 * platforms that need it.
+		 */
 
 		/* wake up cpus */
 		smp_ops->kick_cpu(i);
@@ -1155,7 +466,6 @@
 	/* so time.c doesn't get confused */
 	set_dec(tb_ticks_per_jiffy);
 	last_jiffy_stamp(cpu) = 0;
-	cpu_callin_map[cpu] = 1;
 }
 
 void __init smp_commence(void)
@@ -1247,7 +557,7 @@
 
 	/* assume bogomips are same for everything */
         c->loops_per_jiffy = loops_per_jiffy;
-        c->pvr = _get_PVR();
+        c->pvr = mfspr(PVR);
 }
 
 static int __init maxcpus(char *str)
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/temp.c linux/arch/ppc/kernel/temp.c
--- v2.4.9/linux/arch/ppc/kernel/temp.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/kernel/temp.c	Tue Aug 28 06:58:33 2001
@@ -0,0 +1,278 @@
+/*
+ * temp.c	Thermal management for cpu's with Thermal Assist Units
+ *
+ * Written by Troy Benjegerdes <hozer@drgw.net>
+ *
+ * TODO:
+ * dynamic power management to limit peak CPU temp (using ICTC)
+ * calibration???
+ * 
+ * Silly, crazy ideas: use cpu load (from scheduler) and ICTC to extend battery
+ * life in portables, and add a 'performance/watt' metric somewhere in /proc
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/nvram.h>
+#include <asm/cache.h>
+#include <asm/8xx_immap.h>
+#include <asm/machdep.h>
+
+static struct tau_temp
+{
+	int interrupts;
+	unsigned char low;
+	unsigned char high;
+	unsigned char grew;
+} tau[NR_CPUS];
+
+struct timer_list tau_timer;
+
+#undef DEBUG
+
+/* TODO: put these in a /proc interface, with some sanity checks, and maybe
+ * dynamic adjustment to minimize # of interrupts */
+/* configurable values for step size and how much to expand the window when
+ * we get an interrupt. These are based on the limit that was out of range */
+#define step_size		2	/* step size when temp goes out of range */
+#define window_expand		1	/* expand the window by this much */
+/* configurable values for shrinking the window */
+#define shrink_timer	2*HZ	/* period between shrinking the window */
+#define min_window	2	/* minimum window size, degrees C */
+
+void set_thresholds(unsigned long cpu)
+{
+#ifdef CONFIG_TAU_INT
+	/*
+	 * setup THRM1,
+	 * threshold, valid bit, enable interrupts, interrupt when below threshold
+	 */
+	mtspr(SPRN_THRM1, THRM1_THRES(tau[cpu].low) | THRM1_V | THRM1_TIE | THRM1_TID);
+
+	/* setup THRM2,
+	 * threshold, valid bit, enable interrupts, interrupt when above threshhold
+	 */
+	mtspr (SPRN_THRM2, THRM1_THRES(tau[cpu].high) | THRM1_V | THRM1_TIE);
+#else
+	/* same thing but don't enable interrupts */
+	mtspr(SPRN_THRM1, THRM1_THRES(tau[cpu].low) | THRM1_V | THRM1_TID);
+	mtspr(SPRN_THRM2, THRM1_THRES(tau[cpu].high) | THRM1_V);
+#endif
+}
+
+void TAUupdate(int cpu)
+{
+	unsigned thrm;
+
+#ifdef DEBUG
+	printk("TAUupdate ");
+#endif
+
+	/* if both thresholds are crossed, the step_sizes cancel out
+	 * and the window winds up getting expanded twice. */
+	if((thrm = mfspr(SPRN_THRM1)) & THRM1_TIV){ /* is valid? */
+		if(thrm & THRM1_TIN){ /* crossed low threshold */
+			if (tau[cpu].low >= step_size){
+				tau[cpu].low -= step_size;
+				tau[cpu].high -= (step_size - window_expand);
+			}
+			tau[cpu].grew = 1;
+#ifdef DEBUG
+			printk("low threshold crossed ");
+#endif
+		}
+	}
+	if((thrm = mfspr(SPRN_THRM2)) & THRM1_TIV){ /* is valid? */
+		if(thrm & THRM1_TIN){ /* crossed high threshold */
+			if (tau[cpu].high <= 127-step_size){
+				tau[cpu].low += (step_size - window_expand);
+				tau[cpu].high += step_size;
+			}
+			tau[cpu].grew = 1;
+#ifdef DEBUG
+			printk("high threshold crossed ");
+#endif
+		}
+	}
+
+#ifdef DEBUG
+	printk("grew = %d\n", tau[cpu].grew);
+#endif
+
+#ifndef CONFIG_TAU_INT /* tau_timeout will do this if not using interrupts */
+	set_thresholds(cpu);	
+#endif
+
+}
+
+#ifdef CONFIG_TAU_INT
+/*
+ * TAU interrupts - called when we have a thermal assist unit interrupt
+ * with interrupts disabled
+ */
+
+void TAUException(struct pt_regs * regs)
+{
+	unsigned long cpu = smp_processor_id();
+
+	hardirq_enter(cpu);
+	tau[cpu].interrupts++;
+	
+	TAUupdate(cpu);
+
+	hardirq_exit(cpu);
+	return;
+}
+#endif /* CONFIG_TAU_INT */
+
+static void tau_timeout(void * info)
+{
+	unsigned long cpu = smp_processor_id();
+	unsigned long flags;
+	int size;
+	int shrink;
+ 
+	/* disabling interrupts *should* be okay */
+	save_flags(flags); cli();
+
+#ifndef CONFIG_TAU_INT
+	TAUupdate(cpu);
+#endif
+	
+	size = tau[cpu].high - tau[cpu].low;
+	if (size > min_window && ! tau[cpu].grew) {
+		/* do an exponential shrink of half the amount currently over size */
+		shrink = (2 + size - min_window) / 4;
+		if (shrink) {
+			tau[cpu].low += shrink;
+			tau[cpu].high -= shrink;
+		} else { /* size must have been min_window + 1 */
+			tau[cpu].low += 1;
+#if 1 /* debug */
+			if ((tau[cpu].high - tau[cpu].low) != min_window){
+				printk(KERN_ERR "temp.c: line %d, logic error\n", __LINE__);
+			}
+#endif
+		}
+	}
+
+	tau[cpu].grew = 0;
+	
+	set_thresholds(cpu);
+
+	/*
+	 * Do the enable every time, since otherwise a bunch of (relatively)
+	 * complex sleep code needs to be added. One mtspr every time
+	 * tau_timeout is called is probably not a big deal.
+	 * 
+	 * Enable thermal sensor and set up sample interval timer
+	 * need 20 us to do the compare.. until a nice 'cpu_speed' function
+	 * call is implemented, just assume a 500 mhz clock. It doesn't really
+	 * matter if we take too long for a compare since it's all interrupt 
+	 * driven anyway. 
+	 *
+	 * use a extra long time.. (60 us @ 500 mhz)
+	 */
+	mtspr(SPRN_THRM3, THRM3_SITV(500*60) | THRM3_E);
+
+	restore_flags(flags);
+}
+
+static void tau_timeout_smp(unsigned long unused)
+{
+
+	/* schedule ourselves to be run again */
+	mod_timer(&tau_timer, jiffies + shrink_timer) ;
+#ifdef CONFIG_SMP
+	smp_call_function(tau_timeout, NULL, 1, 0);
+#endif
+	tau_timeout(NULL);
+}
+
+/*
+ * setup the TAU
+ * 
+ * Set things up to use THRM1 as a temperature lower bound, and THRM2 as an upper bound.
+ * Start off at zero
+ */
+
+int tau_initialized = 0;
+
+void __init TAU_init_smp(void * info)
+{
+	unsigned long cpu = smp_processor_id();
+	
+	/* set these to a reasonable value and let the timer shrink the
+	 * window */
+	tau[cpu].low = 5;
+	tau[cpu].high = 120;
+
+	set_thresholds(cpu);
+}
+
+int __init TAU_init(void)
+{
+	/* We assume in SMP that if one CPU has TAU support, they
+	 * all have it --BenH
+	 */
+	if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_TAU)) {
+		printk("Thermal assist unit not available\n");
+		tau_initialized = 0;
+		return 1;
+	}
+
+
+	/* first, set up the window shrinking timer */
+	init_timer(&tau_timer);
+	tau_timer.function = tau_timeout_smp;
+	tau_timer.expires = jiffies + shrink_timer;
+	add_timer(&tau_timer);
+	
+#ifdef CONFIG_SMP
+	smp_call_function(TAU_init_smp, NULL, 1, 0);
+#endif
+	TAU_init_smp(NULL);
+	
+	printk("Thermal assist unit ");
+#ifdef CONFIG_TAU_INT
+	printk("using interrupts, ");
+#else
+	printk("using timers, ");
+#endif
+	printk("shrink_timer: %d jiffies\n", shrink_timer); 
+	tau_initialized = 1;
+
+	return 0;
+}
+
+__initcall(TAU_init);
+
+/*
+ * return current temp
+ */
+
+u32 cpu_temp_both(unsigned long cpu)
+{
+	return ((tau[cpu].high << 16) | tau[cpu].low);
+}
+
+int cpu_temp(unsigned long cpu)
+{
+	return ((tau[cpu].high + tau[cpu].low) / 2);
+}
+
+int tau_interrupts(unsigned long cpu)
+{
+	return (tau[cpu].interrupts);
+}
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/time.c linux/arch/ppc/kernel/time.c
--- v2.4.9/linux/arch/ppc/kernel/time.c	Tue Jul  3 17:08:18 2001
+++ linux/arch/ppc/kernel/time.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.time.c 1.18 06/06/01 22:33:09 paulus
+ * BK Id: SCCS/s.time.c 1.21 08/20/01 22:08:08 paulus
  */
 /*
  * Common time routines among all ppc machines.
@@ -72,11 +72,6 @@
 
 unsigned long disarm_decr[NR_CPUS];
 
-#ifdef CONFIG_SMP
-extern void smp_local_timer_interrupt(struct pt_regs *);
-extern int smp_tb_synchronized;
-#endif /* CONFIG_SMP */
-
 extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz);
 
 /* keep track of when we need to update the rtc */
@@ -321,27 +316,30 @@
 	 * makes things more complex. Repeatedly read the RTC until the
 	 * next second boundary to try to achieve some precision...
 	 */
-	stamp = get_native_tbl();
-	sec = ppc_md.get_rtc_time();
-	elapsed = 0;
-	do {
-		old_stamp = stamp; 
-		old_sec = sec;
+	if (ppc_md.get_rtc_time) {
 		stamp = get_native_tbl();
-		if (__USE_RTC() && stamp < old_stamp) old_stamp -= 1000000000;
-		elapsed += stamp - old_stamp;
 		sec = ppc_md.get_rtc_time();
-	} while ( sec == old_sec && elapsed < 2*HZ*tb_ticks_per_jiffy);
-	if (sec==old_sec) {
-		printk("Warning: real time clock seems stuck!\n");
+		elapsed = 0;
+		do {
+			old_stamp = stamp; 
+			old_sec = sec;
+			stamp = get_native_tbl();
+			if (__USE_RTC() && stamp < old_stamp) old_stamp -= 1000000000;
+			elapsed += stamp - old_stamp;
+			sec = ppc_md.get_rtc_time();
+		} while ( sec == old_sec && elapsed < 2*HZ*tb_ticks_per_jiffy);
+		if (sec==old_sec) {
+			printk("Warning: real time clock seems stuck!\n");
+		}
+		write_lock_irqsave(&xtime_lock, flags);
+		xtime.tv_sec = sec;
+		last_jiffy_stamp(0) = tb_last_stamp = stamp;
+		xtime.tv_usec = 0;
+		/* No update now, we just read the time from the RTC ! */
+		last_rtc_update = xtime.tv_sec;
+		write_unlock_irqrestore(&xtime_lock, flags);
 	}
-	write_lock_irqsave(&xtime_lock, flags);
-	xtime.tv_sec = sec;
-	last_jiffy_stamp(0) = tb_last_stamp = stamp;
-	xtime.tv_usec = 0;
-	/* No update now, we just read the time from the RTC ! */
-	last_rtc_update = xtime.tv_sec;
-	write_unlock_irqrestore(&xtime_lock, flags);
+
 	/* Not exact, but the timer interrupt takes care of this */
 	set_dec(tb_ticks_per_jiffy);
 
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/kernel/traps.c linux/arch/ppc/kernel/traps.c
--- v2.4.9/linux/arch/ppc/kernel/traps.c	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/kernel/traps.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.traps.c 1.16 07/31/01 10:53:34 trini
+ * BK Id: SCCS/s.traps.c 1.19 08/24/01 20:07:37 paulus
  */
 /*
  *  linux/arch/ppc/kernel/traps.c
@@ -244,7 +244,7 @@
 	 */
 	if ((instword & INST_MFSPR_PVR_MASK) == INST_MFSPR_PVR) {
 		rd = (instword >> 21) & 0x1f;
-		regs->gpr[rd] = _get_PVR();
+		regs->gpr[rd] = mfspr(PVR);
 		retval = 0;
 	}
 	if (retval == 0)
@@ -372,12 +372,14 @@
 }
 #endif
 
+#if !defined(CONFIG_TAU_INT)
 void
 TAUException(struct pt_regs *regs)
 {
 	printk("TAU trap at PC: %lx, SR: %lx, vector=%lx\n",
 	       regs->nip, regs->msr, regs->trap);
 }
+#endif /* CONFIG_INT_TAU */
 
 void __init trap_init(void)
 {
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/lib/checksum.S linux/arch/ppc/lib/checksum.S
--- v2.4.9/linux/arch/ppc/lib/checksum.S	Mon May 21 17:04:47 2001
+++ linux/arch/ppc/lib/checksum.S	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.checksum.S 1.5 05/17/01 18:14:22 cort
+ * BK Id: SCCS/s.checksum.S 1.8 08/20/01 22:09:34 paulus
  */
 /*
  * This file contains assembly-language implementations
@@ -122,12 +122,30 @@
 	addc	r0,r0,r6
 	srwi.	r6,r5,2		/* # words to do */
 	beq	3f
-1:	mtctr	r6
-82:	lwzu	r6,4(r3)	/* the bdnz has zero overhead, so it should */
-92:	stwu	r6,4(r4)	/* be unnecessary to unroll this loop */
+1:	srwi.	r6,r5,4		/* # groups of 4 words to do */
+	beq	10f
+	mtctr	r6
+71:	lwz	r6,4(r3)
+72:	lwz	r9,8(r3)
+73:	lwz	r10,12(r3)
+74:	lwzu	r11,16(r3)
 	adde	r0,r0,r6
+75:	stw	r6,4(r4)
+	adde	r0,r0,r9
+76:	stw	r9,8(r4)
+	adde	r0,r0,r10
+77:	stw	r10,12(r4)
+	adde	r0,r0,r11
+78:	stwu	r11,16(r4)
+	bdnz	71b
+10:	rlwinm.	r6,r5,30,30,31	/* # words left to do */
+	beq	13f
+	mtctr	r6
+82:	lwzu	r9,4(r3)
+92:	stwu	r9,4(r4)
+	adde	r0,r0,r9
 	bdnz	82b
-	andi.	r5,r5,3
+13:	andi.	r5,r5,3
 3:	cmpi	0,r5,2
 	blt+	4f
 83:	lhz	r6,4(r3)
@@ -148,12 +166,16 @@
 /* These shouldn't go in the fixup section, since that would
    cause the ex_table addresses to get out of order. */
 
+src_error_4:
+	mfctr	r6		/* update # bytes remaining from ctr */
+	rlwimi	r5,r6,4,0,27
+	b	79f
 src_error_1:
 	li	r6,0
 	subi	r5,r5,2
 95:	sth	r6,4(r4)
 	addi	r4,r4,2
-	srwi.	r6,r5,2
+79:	srwi.	r6,r5,2
 	beq	3f
 	mtctr	r6
 src_error_2:
@@ -187,6 +209,14 @@
 .section __ex_table,"a"
 	.long	81b,src_error_1
 	.long	91b,dst_error
+	.long	71b,src_error_4
+	.long	72b,src_error_4
+	.long	73b,src_error_4
+	.long	74b,src_error_4
+	.long	75b,dst_error
+	.long	76b,dst_error
+	.long	77b,dst_error
+	.long	78b,dst_error
 	.long	82b,src_error_2
 	.long	92b,dst_error
 	.long	83b,src_error_3
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/lib/locks.c linux/arch/ppc/lib/locks.c
--- v2.4.9/linux/arch/ppc/lib/locks.c	Mon May 21 17:04:47 2001
+++ linux/arch/ppc/lib/locks.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.locks.c 1.8 05/17/01 18:14:22 cort
+ * BK Id: SCCS/s.locks.c 1.11 08/19/01 22:27:32 paulus
  */
 /*
  * Locks for smp ppc 
@@ -16,29 +16,53 @@
 #include <asm/system.h>
 #include <asm/io.h>
 
-#define DEBUG_LOCKS 1
+#ifdef SPINLOCK_DEBUG
 
 #undef INIT_STUCK
 #define INIT_STUCK 200000000 /*0xffffffff*/
 
+/*
+ * Try to acquire a spinlock.
+ * Only does the stwcx. if the load returned 0 - the Programming
+ * Environments Manual suggests not doing unnecessary stcwx.'s
+ * since they may inhibit forward progress by other CPUs in getting
+ * a lock.
+ */
+static unsigned long __spin_trylock(volatile unsigned long *lock)
+{
+	unsigned long ret;
+
+	__asm__ __volatile__ ("\n\
+1:	lwarx	%0,0,%1\n\
+	cmpwi	0,%0,0\n\
+	bne	2f\n\
+	stwcx.	%2,0,%1\n\
+	bne-	1b\n\
+	isync\n\
+2:"
+	: "=&r"(ret)
+	: "r"(lock), "r"(1)
+	: "cr0", "memory");
+
+	return ret;
+}
+
 void _spin_lock(spinlock_t *lock)
 {
 	int cpu = smp_processor_id();
-#ifdef DEBUG_LOCKS
 	unsigned int stuck = INIT_STUCK;
-#endif /* DEBUG_LOCKS */
 	while (__spin_trylock(&lock->lock)) {
-#ifdef DEBUG_LOCKS
-		if(!--stuck) {
-			printk("_spin_lock(%p) CPU#%d NIP %p"
-			       " holder: cpu %ld pc %08lX\n",
-			       lock, cpu, __builtin_return_address(0),
-			       lock->owner_cpu,lock->owner_pc);
-			stuck = INIT_STUCK;
-			/* steal the lock */
-			/*xchg_u32((void *)&lock->lock,0);*/
+		while ((unsigned volatile long)lock->lock != 0) {
+			if (!--stuck) {
+				printk("_spin_lock(%p) CPU#%d NIP %p"
+				       " holder: cpu %ld pc %08lX\n",
+				       lock, cpu, __builtin_return_address(0),
+				       lock->owner_cpu,lock->owner_pc);
+				stuck = INIT_STUCK;
+				/* steal the lock */
+				/*xchg_u32((void *)&lock->lock,0);*/
+			}
 		}
-#endif /* DEBUG_LOCKS */
 	}
 	lock->owner_pc = (unsigned long)__builtin_return_address(0);
 	lock->owner_cpu = cpu;
@@ -53,11 +77,8 @@
 	return 1;
 }
 
-
-
 void _spin_unlock(spinlock_t *lp)
 {
-#ifdef DEBUG_LOCKS
   	if ( !lp->lock )
 		printk("_spin_unlock(%p): no lock cpu %d curr PC %p %s/%d\n",
 		       lp, smp_processor_id(), __builtin_return_address(0),
@@ -66,13 +87,12 @@
 		printk("_spin_unlock(%p): cpu %d trying clear of cpu %d pc %lx val %lx\n",
 		      lp, smp_processor_id(), (int)lp->owner_cpu,
 		      lp->owner_pc,lp->lock);
-#endif /* DEBUG_LOCKS */
 	lp->owner_pc = lp->owner_cpu = 0;
 	wmb();
 	lp->lock = 0;
-	wmb();
 }
 
+
 /*
  * Just like x86, implement read-write locks as a 32-bit counter
  * with the high bit (sign) being the "write" bit.
@@ -80,14 +100,11 @@
  */
 void _read_lock(rwlock_t *rw)
 {
-#ifdef DEBUG_LOCKS
 	unsigned long stuck = INIT_STUCK;
 	int cpu = smp_processor_id();
-#endif /* DEBUG_LOCKS */		  
 
 again:	
 	/* get our read lock in there */
-	wmb();
 	atomic_inc((atomic_t *) &(rw)->lock);
 	if ( (signed long)((rw)->lock) < 0) /* someone has a write lock */
 	{
@@ -96,13 +113,11 @@
 		/* wait for the write lock to go away */
 		while ((signed long)((rw)->lock) < 0)
 		{
-#ifdef DEBUG_LOCKS
 			if(!--stuck)
 			{
 				printk("_read_lock(%p) CPU#%d\n", rw, cpu);
 				stuck = INIT_STUCK;
 			}
-#endif /* DEBUG_LOCKS */
 		}
 		/* try to get the read lock again */
 		goto again;
@@ -112,38 +127,30 @@
 
 void _read_unlock(rwlock_t *rw)
 {
-#ifdef DEBUG_LOCKS
 	if ( rw->lock == 0 )
 		printk("_read_unlock(): %s/%d (nip %08lX) lock %lx\n",
 		       current->comm,current->pid,current->thread.regs->nip,
 		      rw->lock);
-#endif /* DEBUG_LOCKS */
 	wmb();
 	atomic_dec((atomic_t *) &(rw)->lock);
-	wmb();
 }
 
 void _write_lock(rwlock_t *rw)
 {
-#ifdef DEBUG_LOCKS
 	unsigned long stuck = INIT_STUCK;
 	int cpu = smp_processor_id();
-#endif /* DEBUG_LOCKS */		  
 
 again:
-	wmb();
 	if ( test_and_set_bit(31,&(rw)->lock) ) /* someone has a write lock */
 	{
 		while ( (rw)->lock & (1<<31) ) /* wait for write lock */
 		{
-#ifdef DEBUG_LOCKS
 			if(!--stuck)
 			{
 				printk("write_lock(%p) CPU#%d lock %lx)\n",
 				       rw, cpu,rw->lock);
 				stuck = INIT_STUCK;
 			}
-#endif /* DEBUG_LOCKS */		  
 			barrier();
 		}
 		goto again;
@@ -155,14 +162,12 @@
 		clear_bit(31,&(rw)->lock);
 		while ( (rw)->lock & ~(1<<31) )
 		{
-#ifdef DEBUG_LOCKS
 			if(!--stuck)
 			{
 				printk("write_lock(%p) 2 CPU#%d lock %lx)\n",
 				       rw, cpu,rw->lock);
 				stuck = INIT_STUCK;
 			}
-#endif /* DEBUG_LOCKS */
 			barrier();
 		}
 		goto again;
@@ -172,79 +177,12 @@
 
 void _write_unlock(rwlock_t *rw)
 {
-#ifdef DEBUG_LOCKS
 	if ( !(rw->lock & (1<<31)) )
 		printk("_write_lock(): %s/%d (nip %08lX) lock %lx\n",
 		      current->comm,current->pid,current->thread.regs->nip,
 		      rw->lock);
-#endif /* DEBUG_LOCKS */
 	wmb();
 	clear_bit(31,&(rw)->lock);
-	wmb();
-}
-
-void __lock_kernel(struct task_struct *task)
-{
-#ifdef DEBUG_LOCKS
-	unsigned long stuck = INIT_STUCK;
-	
-	if ( (signed long)(task->lock_depth) < 0 )
-	{
-		printk("__lock_kernel(): %s/%d (nip %08lX) lock depth %x\n",
-		      task->comm,task->pid,task->thread.regs->nip,
-		      task->lock_depth);
-	}
-#endif /* DEBUG_LOCKS */
-
-	if (atomic_inc_return((atomic_t *) &task->lock_depth) != 1)
-		return;
-	/* mine! */
-	while (__spin_trylock(&klock_info.kernel_flag)) {
-#ifdef DEBUG_LOCKS
-		if(!--stuck) {
-			printk("_lock_kernel() CPU#%d NIP %p\n",
-			       smp_processor_id(),
-			       __builtin_return_address(0));
-			stuck = INIT_STUCK;
-		}
-#endif /* DEBUG_LOCKS */
-	}
-	
-	klock_info.akp = smp_processor_id();
-	/* my kernel mode! mine!!! */
 }
 
-void __unlock_kernel(struct task_struct *task)
-{
-#ifdef DEBUG_LOCKS
- 	if ((task->lock_depth == 0) || (klock_info.kernel_flag != KLOCK_HELD))
-	{
-		printk("__unlock_kernel(): %s/%d (nip %08lX) "
-		       "lock depth %x flags %lx\n",
-		       task->comm,task->pid,task->thread.regs->nip,
-		       task->lock_depth, klock_info.kernel_flag);
-		klock_info.akp = NO_PROC_ID;		
-		klock_info.kernel_flag = 0;
-		return;
-	}
-#endif /* DEBUG_LOCKS */
-	if (atomic_dec_and_test((atomic_t *) &task->lock_depth))
-	{
-		wmb();
-		klock_info.akp = NO_PROC_ID;
-		wmb();
-		klock_info.kernel_flag = KLOCK_CLEAR;
-		wmb();
-	}
-}	
-
-void reacquire_kernel_lock(struct task_struct *task, int cpu,int depth)
-{
-	if (depth)
-	{
-		__cli();
-		__lock_kernel(task);
-		task->lock_depth = depth;
-		__sti();
-	}
-}
+#endif
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/mm/4xx_mmu.c linux/arch/ppc/mm/4xx_mmu.c
--- v2.4.9/linux/arch/ppc/mm/4xx_mmu.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/mm/4xx_mmu.c	Tue Aug 28 06:58:33 2001
@@ -0,0 +1,98 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * This file contains the routines for initializing the MMU
+ * on the 4xx series of chips.
+ *  -- paulus
+ * 
+ *  Derived from arch/ppc/mm/init.c:
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
+ *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ *    Copyright (C) 1996 Paul Mackerras
+ *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/stddef.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/bootmem.h>
+#include <linux/highmem.h>
+
+#include <asm/pgalloc.h>
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/mmu_context.h>
+#include <asm/pgtable.h>
+#include <asm/mmu.h>
+#include <asm/uaccess.h>
+#include <asm/smp.h>
+#include <asm/bootx.h>
+#include <asm/machdep.h>
+#include <asm/setup.h>
+
+/* Used by the 4xx TLB replacement exception handler.
+ * Just needed it declared someplace (and initialized to zero).
+ */
+unsigned int tlb_4xx_index;
+
+/*
+ * MMU_init_hw does the chip-specific initialization of the MMU hardware.
+ */
+void __init MMU_init_hw(void)
+{
+	/*
+	 * The Zone Protection Register (ZPR) defines how protection will
+	 * be applied to every page which is a member of a given zone. At
+	 * present, we utilize only two of the 4xx's zones.
+	 * The zone index bits (of ZSEL) in the PTE are used for software
+	 * indicators, except the LSB.  For user access, zone 15 is used,
+	 * for kernel access, zone 14 is used.  We set all but zone 15
+	 * to zero, allowing only kernel access as indicated in the PTE.
+	 * For zone 15, we set a 01 binary (a value of 10 will not work)
+	 * to allow user access as indicated in the PTE.  This also allows
+	 * kernel access as indicated in the PTE.
+	 */
+
+        mtspr(SPRN_ZPR, 0x00000001);
+
+	flush_instruction_cache();
+
+	/*
+	 * Set up the real-mode cache parameters for the exception vector
+	 * handlers (which are run in real-mode).
+	 */
+
+        mtspr(SPRN_DCWR, 0x00000000);	/* All caching is write-back */
+
+        /*
+	 * Cache instruction and data space where the exception
+	 * vectors and the kernel live in real-mode.
+	 */
+
+        mtspr(SPRN_DCCR, 0x80000000);	/* 128 MB of data space at 0x0. */
+        mtspr(SPRN_ICCR, 0x80000000);	/* 128 MB of instr. space at 0x0. */
+}
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/mm/Makefile linux/arch/ppc/mm/Makefile
--- v2.4.9/linux/arch/ppc/mm/Makefile	Tue Jul  3 17:08:18 2001
+++ linux/arch/ppc/mm/Makefile	Tue Aug 28 06:58:33 2001
@@ -1,4 +1,4 @@
-# BK Id: SCCS/s.Makefile 1.6 06/28/01 15:50:17 paulus
+# BK Id: SCCS/s.Makefile 1.8 08/16/01 17:25:47 paulus
 #
 #
 # Makefile for the linux ppc-specific parts of the memory manager.
@@ -15,15 +15,13 @@
 EXTRA_AFLAGS		:= -Wa,-mppc64bridge
 endif
 
-O_TARGET		:= mm.o
-obj-y			:= fault.o init.o mem_pieces.o extable.o
+O_TARGET			:= mm.o
+obj-y				:= fault.o init.o mem_pieces.o extable.o \
+					mmu_context.o pgtable.o
 
-ifneq ($(CONFIG_8xx),y)
-ifneq ($(CONFIG_4xx),y)
-obj-y			+= hashtable.o
-endif
-endif
-
-obj-$(CONFIG_4xx)	+= 4xx_tlb.o
+obj-$(CONFIG_PPC_STD_MMU)	+= hashtable.o ppc_mmu.o tlb.o
+obj-$(CONFIG_PPC_ISERIES)	+= iSeries_hashtable.o iSeries_mmu.o tlb.o
+obj-$(CONFIG_4xx)		+= cachemap.o 4xx_mmu.o
+obj-$(CONFIG_8xx)		+= cachemap.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/mm/cachemap.c linux/arch/ppc/mm/cachemap.c
--- v2.4.9/linux/arch/ppc/mm/cachemap.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/mm/cachemap.c	Tue Aug 28 06:58:33 2001
@@ -0,0 +1,163 @@
+/*
+ * 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
+ *
+ *  Copyright (C) 2000 Russell King
+ *
+ * Consistent memory allocators.  Used for DMA devices that want to
+ * share uncached memory with the processor core.  The function return
+ * is the virtual address and 'dma_handle' is the physical address.
+ * Mostly stolen from the ARM port, with some changes for PowerPC.
+ *						-- Dan
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/module.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/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/stddef.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/bootmem.h>
+#include <linux/highmem.h>
+#include <linux/pci.h>
+
+#include <asm/pgalloc.h>
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/hardirq.h>
+#include <asm/mmu_context.h>
+#include <asm/pgtable.h>
+#include <asm/mmu.h>
+#include <asm/uaccess.h>
+#include <asm/smp.h>
+#include <asm/machdep.h>
+
+void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle)
+{
+	int order, rsize;
+	unsigned long page;
+	void *ret;
+	pte_t	*pte;
+
+	if (in_interrupt())
+		BUG();
+
+	/* Only allocate page size areas.
+	*/
+	size = PAGE_ALIGN(size);
+	order = get_order(size);
+
+	page = __get_free_pages(gfp, order);
+	if (!page) {
+		BUG();
+		return NULL;
+	}
+
+	/*
+	 * we need to ensure that there are no cachelines in use,
+	 * or worse dirty in this area.
+	 */
+	invalidate_dcache_range(page, page + size);
+
+	ret = (void *)page;
+	*dma_handle = virt_to_bus(ret);
+
+	/* Chase down all of the PTEs and mark them uncached.
+	*/
+	rsize = (int)size;
+	while (rsize > 0) {
+		if (get_pteptr(&init_mm, page, &pte)) {
+			pte_val(*pte) |= _PAGE_NO_CACHE | _PAGE_GUARDED;
+			flush_tlb_page(find_vma(&init_mm,page),page);
+		}
+		else {
+			BUG();
+			return NULL;
+		}
+		page += PAGE_SIZE;
+		rsize -= PAGE_SIZE;
+	}
+
+	return ret;
+}
+
+/*
+ * free page(s) as defined by the above mapping.
+ * The caller has to tell us the size so we can free the proper number
+ * of pages.  We can't vmalloc() a new space for these pages and simply
+ * call vfree() like some other architectures because we could end up
+ * with aliased cache lines (or at least a cache line with the wrong
+ * attributes).  This can happen when the PowerPC speculative loads
+ * across page boundaries.
+ */
+void consistent_free(void *vaddr, size_t size)
+{
+	int order, rsize;
+	unsigned long addr;
+	pte_t	*pte;
+
+	if (in_interrupt())
+		BUG();
+
+	size = PAGE_ALIGN(size);
+	order = get_order(size);
+
+	/* Chase down all of the PTEs and mark them cached again.
+	*/
+	addr = (unsigned long)vaddr;
+	rsize = (int)size;
+	while (rsize > 0) {
+		if (get_pteptr(&init_mm, addr, &pte)) {
+			pte_val(*pte) &= ~(_PAGE_NO_CACHE | _PAGE_GUARDED);
+			flush_tlb_page(find_vma(&init_mm,addr),addr);
+		}
+		else {
+			BUG();
+			return;
+		}
+		addr += PAGE_SIZE;
+		rsize -= PAGE_SIZE;
+	}
+	free_pages((unsigned long)vaddr, order);
+}
+
+/*
+ * make an area consistent.
+ */
+void consistent_sync(void *vaddr, size_t size, int direction)
+{
+	unsigned long start = (unsigned long)vaddr;
+	unsigned long end   = start + size;
+
+	switch (direction) {
+	case PCI_DMA_NONE:
+		BUG();
+	case PCI_DMA_FROMDEVICE:	/* invalidate only */
+		invalidate_dcache_range(start, end);
+		break;
+	case PCI_DMA_TODEVICE:		/* writeback only */
+		clean_dcache_range(start, end);
+		break;
+	case PCI_DMA_BIDIRECTIONAL:	/* writeback and invalidate */
+		flush_dcache_range(start, end);
+		break;
+	}
+}
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/mm/hashtable.S linux/arch/ppc/mm/hashtable.S
--- v2.4.9/linux/arch/ppc/mm/hashtable.S	Tue Jul  3 17:08:18 2001
+++ linux/arch/ppc/mm/hashtable.S	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.hashtable.S 1.16 06/29/01 08:51:52 paulus
+ * BK Id: SCCS/s.hashtable.S 1.18 08/15/01 22:43:07 paulus
  */
 /*
  *  arch/ppc/kernel/hashtable.S
@@ -31,6 +31,7 @@
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/cputable.h>
 
 #ifdef CONFIG_SMP
 	.comm	hash_table_lock,4
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/mm/init.c linux/arch/ppc/mm/init.c
--- v2.4.9/linux/arch/ppc/mm/init.c	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/mm/init.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.init.c 1.30 07/06/01 09:19:29 trini
+ * BK Id: SCCS/s.init.c 1.34 08/20/01 22:12:43 paulus
  */
 /*
  *  PowerPC version 
@@ -21,20 +21,14 @@
  */
 
 #include <linux/config.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/ptrace.h>
-#include <linux/mman.h>
 #include <linux/mm.h>
-#include <linux/swap.h>
 #include <linux/stddef.h>
-#include <linux/vmalloc.h>
 #include <linux/init.h>
-#include <linux/delay.h>
 #include <linux/bootmem.h>
 #include <linux/highmem.h>
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -47,138 +41,49 @@
 #include <asm/mmu_context.h>
 #include <asm/pgtable.h>
 #include <asm/mmu.h>
-#include <asm/uaccess.h>
-#ifdef CONFIG_8xx
-#include <asm/8xx_immap.h>
-#include <asm/mpc8xx.h>
-#endif
-#ifdef CONFIG_8260
-#include <asm/immap_8260.h>
-#include <asm/mpc8260.h>
-#endif
 #include <asm/smp.h>
-#include <asm/bootx.h>
 #include <asm/machdep.h>
-#include <asm/setup.h>
-#include <asm/amigahw.h>
-#include <asm/gemini.h>
+#include <asm/btext.h>
 
 #include "mem_pieces.h"
+#include "mmu_decl.h"
 
-#if defined(CONFIG_4xx)
-#include "4xx_tlb.h"
-#endif
-
-#define MAX_LOW_MEM	(512 << 20)
+#define MAX_LOW_MEM	(0xF0000000UL - KERNELBASE)
 
-#define	PGTOKB(pages)	(((pages) * PAGE_SIZE) >> 10)
-
-mm_context_t next_mmu_context;
-unsigned long context_map[(LAST_CONTEXT+1) / (8*sizeof(unsigned long))];
-#ifdef FEW_CONTEXTS
-atomic_t nr_free_contexts;
-struct mm_struct *context_mm[LAST_CONTEXT+1];
-void steal_context(void);
-#endif /* FEW_CONTEXTS */
-
-int prom_trashed;
-unsigned long *end_of_DRAM;
+void *end_of_DRAM;
 unsigned long total_memory;
 unsigned long total_lowmem;
-unsigned long ram_phys_base;
+
 int mem_init_done;
 int init_bootmem_done;
 int boot_mapsize;
 unsigned long totalram_pages;
 unsigned long totalhigh_pages;
-extern pgd_t swapper_pg_dir[];
-extern char _start[], _end[];
+
+extern char _end[];
 extern char etext[], _stext[];
 extern char __init_begin, __init_end;
 extern char __prep_begin, __prep_end;
 extern char __chrp_begin, __chrp_end;
 extern char __pmac_begin, __pmac_end;
 extern char __openfirmware_begin, __openfirmware_end;
-unsigned long ioremap_base;
-unsigned long ioremap_bot;
-unsigned long avail_start;
-extern int num_memory;
-extern struct mem_info memory[];
-extern boot_infos_t *boot_infos;
-extern unsigned int rtas_data, rtas_size;
-#ifndef CONFIG_SMP
-struct pgtable_cache_struct quicklists;
-#endif
+
 #ifdef CONFIG_HIGHMEM
 pte_t *kmap_pte;
 pgprot_t kmap_prot;
 #endif
 
 void MMU_init(void);
-void *early_get_page(void);
-static void mapin_ram(void);
-int map_page(unsigned long va, unsigned long pa, int flags);
 void set_phys_avail(unsigned long total_ram);
-extern void die_if_kernel(char *,struct pt_regs *,long);
 
-extern char _start[], _end[];
-extern char _stext[], etext[];
+/* XXX should be in current.h  -- paulus */
 extern struct task_struct *current_set[NR_CPUS];
 
 char *klimit = _end;
 struct mem_pieces phys_avail;
 
-PTE *Hash, *Hash_end;
-unsigned long Hash_size, Hash_mask;
-#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)
-unsigned long _SDR1;
-static void hash_init(void);
-
-union ubat {			/* BAT register values to be loaded */
-	BAT	bat;
-#ifdef CONFIG_PPC64BRIDGE
-	u64	word[2];
-#else
-	u32	word[2];
-#endif	
-} BATS[4][2];			/* 4 pairs of IBAT, DBAT */
-
-struct batrange {		/* stores address ranges mapped by BATs */
-	unsigned long start;
-	unsigned long limit;
-	unsigned long phys;
-} bat_addrs[4];
-
-/*
- * Return PA for this VA if it is mapped by a BAT, or 0
- */
-static inline unsigned long v_mapped_by_bats(unsigned long va)
-{
-	int b;
-	for (b = 0; b < 4; ++b)
-		if (va >= bat_addrs[b].start && va < bat_addrs[b].limit)
-			return bat_addrs[b].phys + (va - bat_addrs[b].start);
-	return 0;
-}
-
-/*
- * Return VA for a given PA or 0 if not mapped
- */
-static inline unsigned long p_mapped_by_bats(unsigned long pa)
-{
-	int b;
-	for (b = 0; b < 4; ++b)
-		if (pa >= bat_addrs[b].phys
-	    	    && pa < (bat_addrs[b].limit-bat_addrs[b].start)
-		              +bat_addrs[b].phys)
-			return bat_addrs[b].start+(pa-bat_addrs[b].phys);
-	return 0;
-}
-
-#else /* CONFIG_4xx || CONFIG_8xx */
-#define v_mapped_by_bats(x)	(0UL)
-#define p_mapped_by_bats(x)	(0UL)
-#endif /* !CONFIG_4xx && !CONFIG_8xx */
+extern char *sysmap; 
+extern unsigned long sysmap_size;
 
 /*
  * this tells the system to map all of ram with the segregs
@@ -298,421 +203,7 @@
 	val->mem_unit = PAGE_SIZE;
 }
 
-void *
-ioremap(unsigned long addr, unsigned long size)
-{
-	return __ioremap(addr, size, _PAGE_NO_CACHE);
-}
-
-void *
-__ioremap(unsigned long addr, unsigned long size, unsigned long flags)
-{
-	unsigned long p, v, i;
-	int err;
-
-	/*
-	 * Choose an address to map it to.
-	 * Once the vmalloc system is running, we use it.
-	 * Before then, we map addresses >= ioremap_base
-	 * virt == phys; for addresses below this we use
-	 * space going down from ioremap_base (ioremap_bot
-	 * records where we're up to).
-	 */
-	p = addr & PAGE_MASK;
-	size = PAGE_ALIGN(addr + size) - p;
-
-	/*
-	 * If the address lies within the first 16 MB, assume it's in ISA
-	 * memory space
-	 */
-	if ( p < 16*1024*1024 )
-		p += _ISA_MEM_BASE;
-
-	/*
-	 * Don't allow anybody to remap normal RAM that we're using.
-	 * mem_init() sets high_memory so only do the check after that.
-	 */
-	if ( mem_init_done && (p < virt_to_phys(high_memory)) )
-	{
-		printk("__ioremap(): phys addr %0lx is RAM lr %p\n", p,
-		       __builtin_return_address(0));
-		return NULL;
-	}
-
-	if (size == 0)
-		return NULL;
-
-	/*
-	 * Is it already mapped?  Perhaps overlapped by a previous
-	 * BAT mapping.  If the whole area is mapped then we're done,
-	 * otherwise remap it since we want to keep the virt addrs for
-	 * each request contiguous.
-	 *
-	 * We make the assumption here that if the bottom and top
-	 * of the range we want are mapped then it's mapped to the
-	 * same virt address (and this is contiguous).
-	 *  -- Cort
-	 */
-	if ((v = p_mapped_by_bats(p)) /*&& p_mapped_by_bats(p+size-1)*/ )
-		goto out;
-	
-	if (mem_init_done) {
-		struct vm_struct *area;
-		area = get_vm_area(size, VM_IOREMAP);
-		if (area == 0)
-			return NULL;
-		v = VMALLOC_VMADDR(area->addr);
-	} else {
-#ifndef CONFIG_HIGHMEM
-		if (p >= ioremap_base)
-#else
-		if (p >= ioremap_base && p < PKMAP_BASE)
-#endif /* CONFIG_HIGHMEM */
-			v = p;
-		else
-			v = (ioremap_bot -= size);
-	}
-
-	if ((flags & _PAGE_PRESENT) == 0)
-		flags |= pgprot_val(PAGE_KERNEL);
-	if (flags & (_PAGE_NO_CACHE | _PAGE_WRITETHRU))
-		flags |= _PAGE_GUARDED;
-
-	/*
-	 * Should check if it is a candidate for a BAT mapping
-	 */
-
-	err = 0;
-	for (i = 0; i < size && err == 0; i += PAGE_SIZE)
-		err = map_page(v+i, p+i, flags);
-	if (err) {
-		if (mem_init_done)
-			vfree((void *)v);
-		return NULL;
-	}
-
-out:
-	return (void *) (v + (addr & ~PAGE_MASK));
-}
-
-void iounmap(void *addr)
-{
-	if (addr > high_memory && (unsigned long) addr < ioremap_bot)
-		vfree((void *) (PAGE_MASK & (unsigned long) addr));
-}
-
-unsigned long iopa(unsigned long addr)
-{
-	unsigned long pa;
-	pmd_t *pd;
-	pte_t *pg;
-
-	/* Check the BATs */
-	pa = v_mapped_by_bats(addr);
-	if (pa)
-		return pa;
-
-	/* Do we have a page table? */
-	if (init_mm.pgd == NULL)
-		return 0;
-
-	/* Use upper 10 bits of addr to index the first level map */
-	pd = (pmd_t *) (init_mm.pgd + (addr >> PGDIR_SHIFT));
-	if (pmd_none(*pd))
-		return 0;
-
-	/* Use middle 10 bits of addr to index the second-level map */
-	pg = pte_offset(pd, addr);
-	return (pte_val(*pg) & PAGE_MASK) | (addr & ~PAGE_MASK);
-}
-
-int
-map_page(unsigned long va, unsigned long pa, int flags)
-{
-	pmd_t *pd;
-	pte_t *pg;
-	int err = -ENOMEM;
-
-	spin_lock(&init_mm.page_table_lock);
-	/* Use upper 10 bits of VA to index the first level map */
-	pd = pmd_offset(pgd_offset_k(va), va);
-	/* Use middle 10 bits of VA to index the second-level map */
-	pg = pte_alloc(&init_mm, pd, va);
-	if (pg != 0) {
-		err = 0;
-		set_pte(pg, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags)));
-#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)
-		if (mem_init_done && Hash != 0)
-			flush_hash_page(0, va, pg);
-#endif /* !4xx && !8xx */
-	}
-	spin_unlock(&init_mm.page_table_lock);
-	return err;
-}
-
-#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)
-/*
- * TLB flushing:
- *
- *  - flush_tlb_all() flushes all processes TLBs
- *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
- *  - flush_tlb_page(vma, vmaddr) flushes one page
- *  - flush_tlb_range(mm, start, end) flushes a range of pages
- *
- * since the hardware hash table functions as an extension of the
- * tlb as far as the linux tables are concerned, flush it too.
- *    -- Cort
- */
-
-/*
- * Flush all tlb/hash table entries (except perhaps for those
- * mapping RAM starting at PAGE_OFFSET, since they never change).
- */
-void
-local_flush_tlb_all(void)
-{
-	/* aargh!!! */
-	/* just flush the kernel part of the address space, that's
-	   all that the current callers of this require.  -- paulus. */
-	local_flush_tlb_range(&init_mm, TASK_SIZE, ~0UL);
-
-#ifdef CONFIG_SMP
-	smp_send_tlb_invalidate(0);
-#endif /* CONFIG_SMP */
-}
-
-/*
- * Flush all the (user) entries for the address space described
- * by mm.  We can't rely on mm->mmap describing all the entries
- * that might be in the hash table.
- */
-void
-local_flush_tlb_mm(struct mm_struct *mm)
-{
-	if (Hash == 0) {
-		_tlbia();
-		return;
-	}
-
-	if (mm->map_count) {
-		struct vm_area_struct *mp;
-		for (mp = mm->mmap; mp != NULL; mp = mp->vm_next)
-			local_flush_tlb_range(mm, mp->vm_start, mp->vm_end);
-	} else
-		local_flush_tlb_range(mm, 0, TASK_SIZE);
-
-#ifdef CONFIG_SMP
-	smp_send_tlb_invalidate(0);
-#endif	
-}
-
-void
-local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
-{
-	struct mm_struct *mm;
-	pmd_t *pmd;
-	pte_t *pte;
-
-	if (Hash == 0) {
-		_tlbie(vmaddr);
-		return;
-	}
-	mm = (vmaddr < TASK_SIZE)? vma->vm_mm: &init_mm;
-	pmd = pmd_offset(pgd_offset(mm, vmaddr), vmaddr);
-	if (!pmd_none(*pmd)) {
-		pte = pte_offset(pmd, vmaddr);
-		if (pte_val(*pte) & _PAGE_HASHPTE)
-			flush_hash_page(mm->context, vmaddr, pte);
-	}
-#ifdef CONFIG_SMP
-	smp_send_tlb_invalidate(0);
-#endif	
-}
-
-
-/*
- * For each address in the range, find the pte for the address
- * and check _PAGE_HASHPTE bit; if it is set, find and destroy
- * the corresponding HPTE.
- */
-void
-local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
-{
-	pmd_t *pmd;
-	pte_t *pte;
-	unsigned long pmd_end;
-	unsigned int ctx = mm->context;
-
-	if (Hash == 0) {
-		_tlbia();
-		return;
-	}
-	start &= PAGE_MASK;
-	if (start >= end)
-		return;
-	pmd = pmd_offset(pgd_offset(mm, start), start);
-	do {
-		pmd_end = (start + PGDIR_SIZE) & PGDIR_MASK;
-		if (!pmd_none(*pmd)) {
-			if (!pmd_end || pmd_end > end)
-				pmd_end = end;
-			pte = pte_offset(pmd, start);
-			do {
-				if ((pte_val(*pte) & _PAGE_HASHPTE) != 0)
-					flush_hash_page(ctx, start, pte);
-				start += PAGE_SIZE;
-				++pte;
-			} while (start && start < pmd_end);
-		} else {
-			start = pmd_end;
-		}
-		++pmd;
-	} while (start && start < end);
-
-#ifdef CONFIG_SMP
-	smp_send_tlb_invalidate(0);
-#endif	
-}
-
-/*
- * Set up one of the I/D BAT (block address translation) register pairs.
- * The parameters are not checked; in particular size must be a power
- * of 2 between 128k and 256M.
- */
-void __init setbat(int index, unsigned long virt, unsigned long phys,
-       unsigned int size, int flags)
-{
-	unsigned int bl;
-	int wimgxpp;
-	union ubat *bat = BATS[index];
-
-	bl = (size >> 17) - 1;
-	if ((_get_PVR() >> 16) != 1) {
-		/* 603, 604, etc. */
-		/* Do DBAT first */
-		wimgxpp = flags & (_PAGE_WRITETHRU | _PAGE_NO_CACHE
-				   | _PAGE_COHERENT | _PAGE_GUARDED);
-		wimgxpp |= (flags & _PAGE_RW)? BPP_RW: BPP_RX;
-		bat[1].word[0] = virt | (bl << 2) | 2; /* Vs=1, Vp=0 */
-		bat[1].word[1] = phys | wimgxpp;
-#ifndef CONFIG_KGDB /* want user access for breakpoints */
-		if (flags & _PAGE_USER)
-#endif
-			bat[1].bat.batu.vp = 1;
-		if (flags & _PAGE_GUARDED) {
-			/* G bit must be zero in IBATs */
-			bat[0].word[0] = bat[0].word[1] = 0;
-		} else {
-			/* make IBAT same as DBAT */
-			bat[0] = bat[1];
-		}
-	} else {
-		/* 601 cpu */
-		if (bl > BL_8M)
-			bl = BL_8M;
-		wimgxpp = flags & (_PAGE_WRITETHRU | _PAGE_NO_CACHE
-				   | _PAGE_COHERENT);
-		wimgxpp |= (flags & _PAGE_RW)?
-			((flags & _PAGE_USER)? PP_RWRW: PP_RWXX): PP_RXRX;
-		bat->word[0] = virt | wimgxpp | 4;	/* Ks=0, Ku=1 */
-		bat->word[1] = phys | bl | 0x40;	/* V=1 */
-	}
-
-	bat_addrs[index].start = virt;
-	bat_addrs[index].limit = virt + ((bl + 1) << 17) - 1;
-	bat_addrs[index].phys = phys;
-}
-
-#define IO_PAGE	(_PAGE_NO_CACHE | _PAGE_GUARDED | _PAGE_RW)
-#ifdef CONFIG_SMP
-#define RAM_PAGE (_PAGE_RW|_PAGE_COHERENT)
-#else
-#define RAM_PAGE (_PAGE_RW)
-#endif
-#endif /* CONFIG_8xx */
-
-/*
- * Map in all of physical memory starting at KERNELBASE.
- */
-static void __init mapin_ram(void)
-{
-	unsigned long v, p, s, f;
-
-#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx) && !defined(CONFIG_POWER4)
-	if (!__map_without_bats) {
-		unsigned long tot, bl, done;
-		unsigned long max_size = (256<<20);
-		unsigned long align;
-
-		/* Set up BAT2 and if necessary BAT3 to cover RAM. */
-
-		/* Make sure we don't map a block larger than the
-		   smallest alignment of the physical address. */
-		/* alignment of ram_phys_base */
-		align = ~(ram_phys_base-1) & ram_phys_base;
-		/* set BAT block size to MIN(max_size, align) */
-		if (align && align < max_size)
-			max_size = align;
-
-		tot = total_lowmem;
-		for (bl = 128<<10; bl < max_size; bl <<= 1) {
-			if (bl * 2 > tot)
-				break;
-		}
-
-		setbat(2, KERNELBASE, ram_phys_base, bl, RAM_PAGE);
-		done = (unsigned long)bat_addrs[2].limit - KERNELBASE + 1;
-		if ((done < tot) && !bat_addrs[3].limit) {
-			/* use BAT3 to cover a bit more */
-			tot -= done;
-			for (bl = 128<<10; bl < max_size; bl <<= 1)
-				if (bl * 2 > tot)
-					break;
-			setbat(3, KERNELBASE+done, ram_phys_base+done, bl, 
-			       RAM_PAGE);
-		}
-	}
-#endif /* !CONFIG_4xx && !CONFIG_8xx && !CONFIG_POWER4 */
-
-	v = KERNELBASE;
-	p = ram_phys_base;
-	for (s = 0; s < total_lowmem; s += PAGE_SIZE) {
-		/* On the MPC8xx, we want the page shared so we
-		 * don't get ASID compares on kernel space.
-		 */
-		f = _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_SHARED;
-#if defined(CONFIG_KGDB) || defined(CONFIG_XMON)
-		/* Allows stub to set breakpoints everywhere */
-		f |= _PAGE_RW | _PAGE_DIRTY;
-#else
-		if ((char *) v < _stext || (char *) v >= etext)
-			f |= _PAGE_RW | _PAGE_DIRTY;
-#ifndef CONFIG_8xx
-		else
-			/* On the powerpc (not 8xx), no user access
-			   forces R/W kernel access */
-			f |= _PAGE_USER;
-#endif /* CONFIG_8xx */
-#endif /* CONFIG_KGDB */
-		map_page(v, p, f);
-		v += PAGE_SIZE;
-		p += PAGE_SIZE;
-	}
-}
-
-/* This is only called until mem_init is done. */
-void __init *early_get_page(void)
-{
-	void *p;
-
-	if (init_bootmem_done) {
-		p = alloc_bootmem_pages(PAGE_SIZE);
-	} else {
-		p = mem_pieces_find(PAGE_SIZE, PAGE_SIZE);
-	}
-	return p;
-}
-
+/* Free up now-unused memory */
 static void free_sec(unsigned long start, unsigned long end, const char *name)
 {
 	unsigned long cnt = 0;
@@ -725,7 +216,7 @@
 		start += PAGE_SIZE;
  	}
 	if (cnt) {
-		printk(" %ldk %s", PGTOKB(cnt), name);
+		printk(" %ldk %s", cnt << (PAGE_SHIFT - 10), name);
 		totalram_pages += cnt;
 	}
 }
@@ -766,110 +257,54 @@
 #endif
 
 /*
- * Initialize the context management stuff.
+ * Check for command-line options that affect what MMU_init will do.
  */
-static void mmu_context_init(void)
+void MMU_setup(void)
 {
-	context_map[0] = 1;	/* init_mm uses context 0 */
-	next_mmu_context = 1;
-#ifdef FEW_CONTEXTS
-	atomic_set(&nr_free_contexts, LAST_CONTEXT);
-	context_mm[0] = &init_mm;
-#endif /* FEW_CONTEXTS */
-}
-
-#ifdef FEW_CONTEXTS
-/*
- * Steal a context from a task that has one at the moment.
- * This is only used on 8xx and 4xx and we presently assume that
- * they don't do SMP.  If they do then this will have to check
- * whether the MM we steal is in use.
- * We also assume that this is only used on systems that don't
- * use an MMU hash table - this is true for 8xx and 4xx.
- * This isn't an LRU system, it just frees up each context in
- * turn (sort-of pseudo-random replacement :).  This would be the
- * place to implement an LRU scheme if anyone was motivated to do it.
- *  -- paulus
- */
-void steal_context(void)
-{
-	struct mm_struct *mm;
-
-	/* free up context `next_mmu_context' */
-	/* if we shouldn't free context 0, don't... */
-#ifdef CONFIG_4xx
-	if (next_mmu_context == 0)
-		next_mmu_context = 1;
-#endif /* CONFIG_4xx */
-	mm = context_mm[next_mmu_context];
-	flush_tlb_mm(mm);
-	destroy_context(mm);
+	/* Check for nobats option (used in mapin_ram). */
+	if (strstr(cmd_line, "nobats")) {
+		__map_without_bats = 1;
+	}
+
+	/* Look for mem= option on command line */
+	if (strstr(cmd_line, "mem=")) {
+		char *p, *q;
+		unsigned long maxmem = 0;
+
+		for (q = cmd_line; (p = strstr(q, "mem=")) != 0; ) {
+			q = p + 4;
+			if (p > cmd_line && p[-1] != ' ')
+				continue;
+			maxmem = simple_strtoul(q, &q, 0);
+			if (*q == 'k' || *q == 'K') {
+				maxmem <<= 10;
+				++q;
+			} else if (*q == 'm' || *q == 'M') {
+				maxmem <<= 20;
+				++q;
+			}
+		}
+		__max_memory = maxmem;
+	}
 }
-#endif /* FEW_CONTEXTS */
-
-extern boot_infos_t *disp_bi;
 
 /*
- * Do very early mm setup such as finding the size of memory
- * and setting up the hash table.
- * A lot of this is prep/pmac specific but a lot of it could
- * still be merged.
- * -- Cort
+ * MMU_init sets up the basic memory mappings for the kernel,
+ * including both RAM and possibly some I/O regions,
+ * and sets up the page tables and the MMU hardware ready to go.
  */
-#if defined(CONFIG_4xx)
-void __init
-MMU_init(void)
+void __init MMU_init(void)
 {
-	/*
-	 * The Zone Protection Register (ZPR) defines how protection will
-	 * be applied to every page which is a member of a given zone. At
-	 * present, we utilize only two of the 4xx's zones.
-	 * The zone index bits (of ZSEL) in the PTE are used for software
-	 * indicators, except the LSB.  For user access, zone 15 is used,
-	 * for kernel access, zone 14 is used.  We set all but zone 15
-	 * to zero, allowing only kernel access as indicated in the PTE.
-	 * For zone 15, we set a 10 binary (I guess a 01 would work too)
-	 * to allow user access as indicated in the PTE.  This also allows
-	 * kernel access as indicated in the PTE.
-	 */
+	if (ppc_md.progress)
+		ppc_md.progress("MMU:enter", 0x111);
 
-        mtspr(SPRN_ZPR, 0x00000002);
-
-	flush_instruction_cache();
+	/* parse args from command line */
+	MMU_setup();
 
 	/*
-	 * Find the top of physical memory and map all of it in starting
-	 * at KERNELBASE.
+	 * Figure out how much memory we have, how much
+	 * is lowmem, and how much is highmem.
 	 */
-
-        total_memory = total_lowmem = ppc_md.find_end_of_memory();
-	end_of_DRAM = __va(total_lowmem);
-	set_phys_avail(total_lowmem);
-        mapin_ram();
-
-	/*
-	 * Set up the real-mode cache parameters for the exception vector
-	 * handlers (which are run in real-mode).
-	 */
-
-        mtspr(SPRN_DCWR, 0x00000000);	/* All caching is write-back */
-
-        /*
-	 * Cache instruction and data space where the exception
-	 * vectors and the kernel live in real-mode.
-	 */
-
-        mtspr(SPRN_DCCR, 0x80000000);	/* 128 MB of data space at 0x0. */
-        mtspr(SPRN_ICCR, 0x80000000);	/* 128 MB of instr. space at 0x0. */
-
-	mmu_context_init();
-}
-
-#else /* !CONFIG_4xx */
-void __init MMU_init(void)
-{
-	if ( ppc_md.progress ) ppc_md.progress("MMU:enter", 0x111);
-
 	total_memory = ppc_md.find_end_of_memory();
 
 	if (__max_memory && total_memory > __max_memory)
@@ -884,114 +319,54 @@
 	end_of_DRAM = __va(total_lowmem);
 	set_phys_avail(total_lowmem);
 
-#if !defined(CONFIG_8xx)
-	if ( ppc_md.progress ) ppc_md.progress("MMU:hash init", 0x300);
-        hash_init();
-#ifndef CONFIG_PPC64BRIDGE
-        _SDR1 = __pa(Hash) | (Hash_mask >> 10);
-#endif
-	
-	ioremap_base = 0xf8000000;
-#endif /* CONFIG_8xx */
+	/* Initialize the MMU hardware */
+	if (ppc_md.progress)
+		ppc_md.progress("MMU:hw init", 0x300);
+	MMU_init_hw();
 
-	if ( ppc_md.progress ) ppc_md.progress("MMU:mapin", 0x301);
 	/* Map in all of RAM starting at KERNELBASE */
+	if (ppc_md.progress)
+		ppc_md.progress("MMU:mapin", 0x301);
 	mapin_ram();
 
-#if defined(CONFIG_8xx)
-        /* Now map in some of the I/O space that is generically needed
-         * or shared with multiple devices.
-         * All of this fits into the same 4Mbyte region, so it only
-         * requires one page table page.
-         */
-        ioremap(IMAP_ADDR, IMAP_SIZE);
-#ifdef CONFIG_MBX
-        ioremap(NVRAM_ADDR, NVRAM_SIZE);
-        ioremap(MBX_CSR_ADDR, MBX_CSR_SIZE);
-        ioremap(PCI_CSR_ADDR, PCI_CSR_SIZE);
-
-	/* Map some of the PCI/ISA I/O space to get the IDE interface.
-	*/
-        ioremap(PCI_ISA_IO_ADDR, 0x4000);
-        ioremap(PCI_IDE_ADDR, 0x4000);
-#endif
-#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC)
-	ioremap(RPX_CSR_ADDR, RPX_CSR_SIZE);
-#if !defined(CONFIG_PCI)
-	ioremap(_IO_BASE,_IO_BASE_SIZE);
-#endif
-#endif
-#ifdef CONFIG_HTDMSOUND
-	ioremap(HIOX_CSR_ADDR, HIOX_CSR_SIZE);
-#endif
-#ifdef CONFIG_FADS
-	ioremap(BCSR_ADDR, BCSR_SIZE);
-#endif
-#ifdef CONFIG_PCI
-        ioremap(PCI_CSR_ADDR, PCI_CSR_SIZE);
-#endif
-#else /* !CONFIG_8xx */
-	/*
-	 * Setup the bat mappings we're going to load that cover
-	 * the io areas.  RAM was mapped by mapin_ram().
-	 * -- Cort
-	 */
-	if ( ppc_md.progress ) ppc_md.progress("MMU:setbat", 0x302);
-	switch (_machine) {
-	case _MACH_prep:
-		setbat(0, 0x80000000, 0x80000000, 0x10000000, IO_PAGE);
-		setbat(1, 0xf0000000, 0xc0000000, 0x08000000, IO_PAGE);
-		ioremap_base = 0xf0000000;
-		break;
-	case _MACH_chrp:
-		/*
-		 * The code below tends to get removed, please don't take it out.
-		 * The F50 needs this mapping and it you take it out I'll track you
-		 * down and slap your hands.  If it causes problems please email me.
-		 *  -- Cort <cort@fsmlabs.com>
-		 */
-#ifndef CONFIG_POWER3
-		setbat(0, 0x80000000, 0x80000000, 0x10000000, IO_PAGE);
-		setbat(1, 0x90000000, 0x90000000, 0x10000000, IO_PAGE);
-#endif
-		break;
-	case _MACH_Pmac:
-		ioremap_base = 0xfe000000;
-		break;
-	case _MACH_apus:
-		/* Map PPC exception vectors. */
-		setbat(0, 0xfff00000, 0xfff00000, 0x00020000, RAM_PAGE);
-		/* Map chip and ZorroII memory */
-		setbat(1, zTwoBase,   0x00000000, 0x01000000, IO_PAGE);
-		break;
-	case _MACH_gemini:
-		setbat(0, 0xf0000000, 0xf0000000, 0x10000000, IO_PAGE);
-		setbat(1, 0x80000000, 0x80000000, 0x10000000, IO_PAGE);
-		break;
-	case _MACH_8260:
-		/* Map the IMMR, plus anything else we can cover
-		 * in that upper space according to the memory controller
-		 * chip select mapping.  Grab another bunch of space
-		 * below that for stuff we can't cover in the upper.
-		 */
-		setbat(0, 0xf0000000, 0xf0000000, 0x10000000, IO_PAGE);
-		setbat(1, 0xe0000000, 0xe0000000, 0x10000000, IO_PAGE);
-		ioremap_base = 0xe0000000;
-		break;
-	}
+#ifdef CONFIG_HIGHMEM
+	ioremap_base = PKMAP_BASE;
+#else
+	ioremap_base = 0xfe000000UL;	/* for now, could be 0xfffff000 */
+#endif /* CONFIG_HIGHMEM */
 	ioremap_bot = ioremap_base;
-#endif /* CONFIG_8xx */
 
-	if ( ppc_md.progress ) ppc_md.progress("MMU:exit", 0x211);
+	/* Map in I/O resources */
+	if (ppc_md.progress)
+		ppc_md.progress("MMU:setio", 0x302);
+	if (ppc_md.setup_io_mappings)
+		ppc_md.setup_io_mappings();
+
+	/* Initialize the context management stuff */
+	mmu_context_init();
+
+	if (ppc_md.progress)
+		ppc_md.progress("MMU:exit", 0x211);
+
 #ifdef CONFIG_BOOTX_TEXT
 	/* Must be done last, or ppc_md.progress will die */
-	if (_machine == _MACH_Pmac || _machine == _MACH_chrp)
-		map_bootx_text();
+	if (have_of)
+		map_boot_text();
 #endif
+}
 
-	mmu_context_init();
+/* This is only called until mem_init is done. */
+void __init *early_get_page(void)
+{
+	void *p;
+
+	if (init_bootmem_done) {
+		p = alloc_bootmem_pages(PAGE_SIZE);
+	} else {
+		p = mem_pieces_find(PAGE_SIZE, PAGE_SIZE);
+	}
+	return p;
 }
-#endif /* CONFIG_4xx */
 
 /*
  * Initialize the bootmem system and give it all the memory we
@@ -1068,8 +443,6 @@
 
 void __init mem_init(void)
 {
-	extern char *sysmap; 
-	extern unsigned long sysmap_size;
 	unsigned long addr;
 	int codepages = 0;
 	int datapages = 0;
@@ -1094,7 +467,7 @@
 	   make sure the ramdisk pages aren't reserved. */
 	if (initrd_start) {
 		for (addr = initrd_start; addr < initrd_end; addr += PAGE_SIZE)
-			clear_bit(PG_reserved, &virt_to_page(addr)->flags);
+			ClearPageReserved(virt_to_page(addr));
 	}
 #endif /* CONFIG_BLK_DEV_INITRD */
 
@@ -1106,7 +479,7 @@
 		     addr += PAGE_SIZE)
 			SetPageReserved(virt_to_page(addr));
 #endif /* defined(CONFIG_ALL_PPC) */
-	if ( sysmap_size )
+	if ( sysmap )
 		for (addr = (unsigned long)sysmap;
 		     addr < PAGE_ALIGN((unsigned long)sysmap+sysmap_size) ;
 		     addr += PAGE_SIZE)
@@ -1147,133 +520,12 @@
 	       codepages<< (PAGE_SHIFT-10), datapages<< (PAGE_SHIFT-10),
 	       initpages<< (PAGE_SHIFT-10),
 	       (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10)));
+	if (sysmap)
+		printk("System.map loaded at 0x%08x for debugger, size: %ld bytes\n",
+			(unsigned int)sysmap, sysmap_size);
 	mem_init_done = 1;
 }
 
-#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)
-/*
- * Initialize the hash table and patch the instructions in hashtable.S.
- */
-static void __init hash_init(void)
-{
-	int Hash_bits, mb, mb2;
-	unsigned int hmask, h;
-
-	extern unsigned int hash_page_patch_A[];
-	extern unsigned int hash_page_patch_B[], hash_page_patch_C[];
-	extern unsigned int hash_page[];
-	extern unsigned int flush_hash_patch_A[], flush_hash_patch_B[];
-
-#ifdef CONFIG_PPC64BRIDGE
-	/* The hash table has already been allocated and initialized
-	   in prom.c */
-	Hash_mask = (Hash_size >> 7) - 1;
-	hmask = Hash_mask >> 9;
-	Hash_bits = __ilog2(Hash_size) - 7;
-	mb = 25 - Hash_bits;
-	if (Hash_bits > 16)
-		Hash_bits = 16;
-	mb2 = 25 - Hash_bits;
-
-#else /* CONFIG_PPC64BRIDGE */
-
-	if ( ppc_md.progress ) ppc_md.progress("hash:enter", 0x105);
-	/*
-	 * Allow 64k of hash table for every 16MB of memory,
-	 * up to a maximum of 2MB.
-	 */
-	for (h = 64<<10; h < total_memory / 256 && h < (2<<20); h *= 2)
-		;
-	Hash_size = h;
-	Hash_mask = (h >> 6) - 1;
-	hmask = Hash_mask >> 10;
-	Hash_bits = __ilog2(h) - 6;
-	mb = 26 - Hash_bits;
-	if (Hash_bits > 16)
-		Hash_bits = 16;
-	mb2 = 26 - Hash_bits;
-
-	/* shrink the htab since we don't use it on 603's -- Cort */
-	switch (_get_PVR()>>16) {
-	case 3: /* 603 */
-	case 6: /* 603e */
-	case 7: /* 603ev */
-	case 0x0081: /* 82xx */
-		Hash_size = 0;
-		Hash_mask = 0;
-		break;
-	default:
-	        /* on 601/4 let things be */
-		break;
- 	}
-	
-	if ( ppc_md.progress ) ppc_md.progress("hash:find piece", 0x322);
-	/* Find some memory for the hash table. */
-	if ( Hash_size ) {
-		Hash = mem_pieces_find(Hash_size, Hash_size);
-		cacheable_memzero(Hash, Hash_size);
-		_SDR1 = __pa(Hash) | (Hash_mask >> 10);
-	} else
-		Hash = 0;
-#endif /* CONFIG_PPC64BRIDGE */
-
-	printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
-	       total_memory >> 20, Hash_size >> 10, Hash);
-	if ( Hash_size )
-	{
-		if ( ppc_md.progress ) ppc_md.progress("hash:patch", 0x345);
-		Hash_end = (PTE *) ((unsigned long)Hash + Hash_size);
-
-		/*
-		 * Patch up the instructions in hashtable.S:create_hpte
-		 */
-		hash_page_patch_A[0] = (hash_page_patch_A[0] & ~0xffff)
-			| ((unsigned int)(Hash) >> 16);
-		hash_page_patch_A[1] = (hash_page_patch_A[1] & ~0x7c0)
-			| (mb << 6);
-		hash_page_patch_A[2] = (hash_page_patch_A[2] & ~0x7c0)
-			| (mb2 << 6);
-		hash_page_patch_B[0] = (hash_page_patch_B[0] & ~0xffff)
-			| hmask;
-		hash_page_patch_C[0] = (hash_page_patch_C[0] & ~0xffff)
-			| hmask;
-		/*
-		 * Ensure that the locations we've patched have been written
-		 * out from the data cache and invalidated in the instruction
-		 * cache, on those machines with split caches.
-		 */
-		flush_icache_range((unsigned long) &hash_page_patch_A[0],
-				   (unsigned long) &hash_page_patch_C[1]);
-		/*
-		 * Patch up the instructions in hashtable.S:flush_hash_page
-		 */
-		flush_hash_patch_A[0] = (flush_hash_patch_A[0] & ~0xffff)
-			| ((unsigned int)(Hash) >> 16);
-		flush_hash_patch_A[1] = (flush_hash_patch_A[1] & ~0x7c0)
-			| (mb << 6);
-		flush_hash_patch_A[2] = (flush_hash_patch_A[2] & ~0x7c0)
-			| (mb2 << 6);
-		flush_hash_patch_B[0] = (flush_hash_patch_B[0] & ~0xffff)
-			| hmask;
-		flush_icache_range((unsigned long) &flush_hash_patch_A[0],
-				   (unsigned long) &flush_hash_patch_B[1]);
-	}
-	else {
-		Hash_end = 0;
-		/*
-		 * Put a blr (procedure return) instruction at the
-		 * start of hash_page, since we can still get DSI
-		 * exceptions on a 603.
-		 */
-		hash_page[0] = 0x4e800020;
-		flush_icache_range((unsigned long) &hash_page[0],
-				   (unsigned long) &hash_page[1]);
-	}
-
-	if ( ppc_md.progress ) ppc_md.progress("hash:done", 0x205);
-}
-#endif /* !CONFIG_4xx && !CONFIG_8xx */
-
 /*
  * Set phys_avail to the amount of physical memory,
  * less the kernel text/data/bss.
@@ -1314,12 +566,16 @@
 	/* remove the RTAS pages from the available memory */
 	if (rtas_data)
 		mem_pieces_remove(&phys_avail, rtas_data, rtas_size, 1);
+	/* remove the sysmap pages from the available memory */
+	if (sysmap)
+		mem_pieces_remove(&phys_avail, __pa(sysmap), sysmap_size, 1);
 #endif /* CONFIG_ALL_PPC */
-#ifdef CONFIG_PPC64BRIDGE
-	/* Remove the hash table from the available memory */
-	if (Hash)
-		mem_pieces_remove(&phys_avail, __pa(Hash), Hash_size, 1);
-#endif /* CONFIG_PPC64BRIDGE */
+}
+
+/* Mark some memory as reserved by removing it from phys_avail. */
+void __init reserve_phys_mem(unsigned long start, unsigned long size)
+{
+	mem_pieces_remove(&phys_avail, start, size, 1);
 }
 
 void flush_page_to_ram(struct page *page)
@@ -1328,32 +584,6 @@
 	__flush_page_to_ram(vaddr);
 	kunmap(page);
 }
-
-#if !defined(CONFIG_4xx) && !defined(CONFIG_8xx)
-/*
- * This is called at the end of handling a user page fault, when the
- * fault has been handled by updating a PTE in the linux page tables.
- * We use it to preload an HPTE into the hash table corresponding to
- * the updated linux PTE.
- */
-void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
-		      pte_t pte)
-{
-	struct mm_struct *mm;
-	pmd_t *pmd;
-	pte_t *ptep;
-	static int nopreload;
-
-	if (Hash == 0 || nopreload)
-		return;
-	mm = (address < TASK_SIZE)? vma->vm_mm: &init_mm;
-	pmd = pmd_offset(pgd_offset(mm, address), address);
-	if (!pmd_none(*pmd)) {
-		ptep = pte_offset(pmd, address);
-		add_hash_page(mm->context, address, ptep);
-	}
-}
-#endif /* !4xx && !8xx */
 
 /*
  * set_pte stores a linux PTE into the linux page table.
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/mm/mmu_context.c linux/arch/ppc/mm/mmu_context.c
--- v2.4.9/linux/arch/ppc/mm/mmu_context.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/mm/mmu_context.c	Tue Aug 28 06:58:33 2001
@@ -0,0 +1,89 @@
+/*
+ * 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,
+ * 8260, and POWER3 implementations but excludes the 8xx and 4xx.
+ * Although the iSeries hardware does comply with the architecture
+ * specification, the need to work through the hypervisor makes
+ * things sufficiently different that it is handled elsewhere.
+ *  -- paulus
+ * 
+ *  Derived from arch/ppc/mm/init.c:
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
+ *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ *    Copyright (C) 1996 Paul Mackerras
+ *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+
+#include <asm/mmu_context.h>
+
+mm_context_t next_mmu_context;
+unsigned long context_map[(LAST_CONTEXT+1) / (8*sizeof(unsigned long))];
+#ifdef FEW_CONTEXTS
+atomic_t nr_free_contexts;
+struct mm_struct *context_mm[LAST_CONTEXT+1];
+void steal_context(void);
+#endif /* FEW_CONTEXTS */
+
+/*
+ * Initialize the context management stuff.
+ */
+void __init mmu_context_init(void)
+{
+	/*
+	 * Some processors have too few contexts to reserve one for
+	 * init_mm, and require using context 0 for a normal task.
+	 * Other processors reserve the use of context zero for the kernel.
+	 * This code assumes FIRST_CONTEXT < 32.
+	 */
+	context_map[0] = (1 << FIRST_CONTEXT) - 1;
+	next_mmu_context = FIRST_CONTEXT;
+#ifdef FEW_CONTEXTS
+	atomic_set(&nr_free_contexts, LAST_CONTEXT);
+#endif /* FEW_CONTEXTS */
+}
+
+#ifdef FEW_CONTEXTS
+/*
+ * Steal a context from a task that has one at the moment.
+ * This is only used on 8xx and 4xx and we presently assume that
+ * they don't do SMP.  If they do then this will have to check
+ * whether the MM we steal is in use.
+ * We also assume that this is only used on systems that don't
+ * use an MMU hash table - this is true for 8xx and 4xx.
+ * This isn't an LRU system, it just frees up each context in
+ * turn (sort-of pseudo-random replacement :).  This would be the
+ * place to implement an LRU scheme if anyone was motivated to do it.
+ *  -- paulus
+ */
+void steal_context(void)
+{
+	struct mm_struct *mm;
+
+	/* free up context `next_mmu_context' */
+	/* if we shouldn't free context 0, don't... */
+	if (next_mmu_context < FIRST_CONTEXT)
+		next_mmu_context = FIRST_CONTEXT;
+	mm = context_mm[next_mmu_context];
+	flush_tlb_mm(mm);
+	destroy_context(mm);
+}
+#endif /* FEW_CONTEXTS */
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/mm/mmu_decl.h linux/arch/ppc/mm/mmu_decl.h
--- v2.4.9/linux/arch/ppc/mm/mmu_decl.h	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/mm/mmu_decl.h	Tue Aug 28 06:58:33 2001
@@ -0,0 +1,73 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * Declarations of procedures and variables shared between files
+ * in arch/ppc/mm/.
+ * 
+ *  Derived from arch/ppc/mm/init.c:
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
+ *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ *    Copyright (C) 1996 Paul Mackerras
+ *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  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.
+ *
+ */
+
+extern void mapin_ram(void);
+extern void bat_mapin_ram(void);
+extern int map_page(unsigned long va, unsigned long pa, int flags);
+extern void setbat(int index, unsigned long virt, unsigned long phys,
+		   unsigned int size, int flags);
+extern void reserve_phys_mem(unsigned long start, unsigned long size);
+
+extern int __map_without_bats;
+extern void *end_of_DRAM;
+extern unsigned long ioremap_base;
+extern unsigned long ioremap_bot;
+extern unsigned int rtas_data, rtas_size;
+
+extern unsigned long total_memory;
+extern unsigned long total_lowmem;
+extern unsigned long ram_phys_base;
+extern int mem_init_done;
+
+extern PTE *Hash, *Hash_end;
+extern unsigned long Hash_size, Hash_mask;
+
+/* ...and now those things that may be slightly different between processor
+ * architectures.  -- Dan
+ */
+#if defined(CONFIG_8xx)
+#define flush_HPTE(X, va, pg)	_tlbie(va)
+#define MMU_init_hw()		do { } while(0)
+
+#elif defined(CONFIG_4xx)
+#define flush_HPTE(X, va, pg)	_tlbie(va)
+
+#else
+/* anything except 4xx or 8xx */
+extern void MMU_init_hw(void);
+
+/* Be careful....this needs to be updated if we ever encounter 603 SMPs,
+ * which includes all new 82xx processors.  We need tlbie/tlbsync here
+ * in that case (I think). -- Dan.
+ */
+static inline void flush_HPTE(unsigned context, unsigned long va, pte_t *pg)
+{
+	if ((Hash != 0) &&
+	    (cur_cpu_spec[0]->cpu_features & CPU_FTR_HPTE_TABLE))
+		flush_hash_page(0, va, pg);
+	else
+		_tlbie(va);
+}
+#endif
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/mm/pgtable.c linux/arch/ppc/mm/pgtable.c
--- v2.4.9/linux/arch/ppc/mm/pgtable.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/mm/pgtable.c	Tue Aug 28 06:58:33 2001
@@ -0,0 +1,360 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * This file contains the routines setting up the linux page tables.
+ *  -- paulus
+ * 
+ *  Derived from arch/ppc/mm/init.c:
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
+ *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ *    Copyright (C) 1996 Paul Mackerras
+ *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/io.h>
+
+#include "mmu_decl.h"
+
+unsigned long ram_phys_base;
+
+unsigned long ioremap_base;
+unsigned long ioremap_bot;
+int io_bat_index;
+
+#ifndef CONFIG_SMP
+struct pgtable_cache_struct quicklists;
+#endif
+
+#if defined(CONFIG_6xx) || defined(CONFIG_POWER3)
+#define HAVE_BATS	1
+#endif
+
+extern char etext[], _stext[];
+
+#ifdef HAVE_BATS
+extern unsigned long v_mapped_by_bats(unsigned long va);
+extern unsigned long p_mapped_by_bats(unsigned long pa);
+void setbat(int index, unsigned long virt, unsigned long phys,
+	    unsigned int size, int flags);
+
+#else /* !HAVE_BATS */
+#define v_mapped_by_bats(x)	(0UL)
+#define p_mapped_by_bats(x)	(0UL)
+#endif /* HAVE_BATS */
+
+#ifndef CONFIG_PPC_ISERIES
+void *
+ioremap(unsigned long addr, unsigned long size)
+{
+	return __ioremap(addr, size, _PAGE_NO_CACHE);
+}
+
+void *
+__ioremap(unsigned long addr, unsigned long size, unsigned long flags)
+{
+	unsigned long p, v, i;
+	int err;
+
+	/*
+	 * Choose an address to map it to.
+	 * Once the vmalloc system is running, we use it.
+	 * Before then, we use space going down from ioremap_base
+	 * (ioremap_bot records where we're up to).
+	 */
+	p = addr & PAGE_MASK;
+	size = PAGE_ALIGN(addr + size) - p;
+
+	/*
+	 * If the address lies within the first 16 MB, assume it's in ISA
+	 * memory space
+	 */
+	if (p < 16*1024*1024)
+		p += _ISA_MEM_BASE;
+
+	/*
+	 * Don't allow anybody to remap normal RAM that we're using.
+	 * mem_init() sets high_memory so only do the check after that.
+	 */
+	if ( mem_init_done && (p < virt_to_phys(high_memory)) )
+	{
+		printk("__ioremap(): phys addr %0lx is RAM lr %p\n", p,
+		       __builtin_return_address(0));
+		return NULL;
+	}
+
+	if (size == 0)
+		return NULL;
+
+	/*
+	 * Is it already mapped?  Perhaps overlapped by a previous
+	 * BAT mapping.  If the whole area is mapped then we're done,
+	 * otherwise remap it since we want to keep the virt addrs for
+	 * each request contiguous.
+	 *
+	 * We make the assumption here that if the bottom and top
+	 * of the range we want are mapped then it's mapped to the
+	 * same virt address (and this is contiguous).
+	 *  -- Cort
+	 */
+	if ((v = p_mapped_by_bats(p)) /*&& p_mapped_by_bats(p+size-1)*/ )
+		goto out;
+	
+	if (mem_init_done) {
+		struct vm_struct *area;
+		area = get_vm_area(size, VM_IOREMAP);
+		if (area == 0)
+			return NULL;
+		v = VMALLOC_VMADDR(area->addr);
+	} else {
+		v = (ioremap_bot -= size);
+	}
+
+	if ((flags & _PAGE_PRESENT) == 0)
+		flags |= _PAGE_KERNEL;
+	if (flags & _PAGE_NO_CACHE)
+		flags |= _PAGE_GUARDED;
+
+	/*
+	 * Should check if it is a candidate for a BAT mapping
+	 */
+
+	err = 0;
+	for (i = 0; i < size && err == 0; i += PAGE_SIZE)
+		err = map_page(v+i, p+i, flags);
+	if (err) {
+		if (mem_init_done)
+			vfree((void *)v);
+		return NULL;
+	}
+
+out:
+	return (void *) (v + (addr & ~PAGE_MASK));
+}
+
+void iounmap(void *addr)
+{
+	/*
+	 * If mapped by BATs then there is nothing to do.
+	 * Calling vfree() generates a benign warning.
+	 */
+	if (v_mapped_by_bats((unsigned long)addr)) return;
+
+	if (addr > high_memory && (unsigned long) addr < ioremap_bot)
+		vfree((void *) (PAGE_MASK & (unsigned long) addr));
+}
+#endif /* CONFIG_PPC_ISERIES */
+
+int
+map_page(unsigned long va, unsigned long pa, int flags)
+{
+	pmd_t *pd;
+	pte_t *pg;
+	int err = -ENOMEM;
+
+	spin_lock(&init_mm.page_table_lock);
+	/* Use upper 10 bits of VA to index the first level map */
+	pd = pmd_offset(pgd_offset_k(va), va);
+	/* Use middle 10 bits of VA to index the second-level map */
+	pg = pte_alloc(&init_mm, pd, va);
+	if (pg != 0) {
+		err = 0;
+		set_pte(pg, mk_pte_phys(pa & PAGE_MASK, __pgprot(flags)));
+		if (mem_init_done)
+			flush_HPTE(0, va, pg);
+	}
+	spin_unlock(&init_mm.page_table_lock);
+	return err;
+}
+
+/*
+ * Map in all of physical memory starting at KERNELBASE.
+ */
+void __init mapin_ram(void)
+{
+	unsigned long v, p, s, f;
+
+#ifdef HAVE_BATS
+	if (!__map_without_bats)
+		bat_mapin_ram();
+#endif /* HAVE_BATS */
+
+	v = KERNELBASE;
+	p = ram_phys_base;
+	for (s = 0; s < total_lowmem; s += PAGE_SIZE) {
+		/* On the MPC8xx, we want the page shared so we
+		 * don't get ASID compares on kernel space.
+		 */
+		f = _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_SHARED;
+#if defined(CONFIG_KGDB) || defined(CONFIG_XMON)
+		/* Allows stub to set breakpoints everywhere */
+		f |= _PAGE_RW | _PAGE_DIRTY;
+#else
+		if ((char *) v < _stext || (char *) v >= etext)
+			f |= _PAGE_RW | _PAGE_DIRTY;
+#ifndef CONFIG_8xx
+		else
+			/* On the powerpc (not 8xx), no user access
+			   forces R/W kernel access */
+			f |= _PAGE_USER;
+#endif /* CONFIG_8xx */
+#endif /* CONFIG_KGDB */
+		map_page(v, p, f);
+		v += PAGE_SIZE;
+		p += PAGE_SIZE;
+	}
+}
+
+/* is x a power of 2? */
+#define is_power_of_2(x)	((x) != 0 && (((x) & ((x) - 1)) == 0))
+
+/*
+ * Set up a mapping for a block of I/O.
+ * virt, phys, size must all be page-aligned.
+ * This should only be called before ioremap is called.
+ */
+void __init io_block_mapping(unsigned long virt, unsigned long phys,
+			     unsigned int size, int flags)
+{
+	int i;
+
+	if (virt > KERNELBASE && virt < ioremap_bot)
+		ioremap_bot = ioremap_base = virt;
+
+#ifdef HAVE_BATS
+	/*
+	 * Use a BAT for this if possible...
+	 */
+	if (io_bat_index < 2 && is_power_of_2(size)
+	    && (virt & (size - 1)) == 0 && (phys & (size - 1)) == 0) {
+		setbat(io_bat_index, virt, phys, size, flags);
+		++io_bat_index;
+		return;
+	}
+#endif /* HAVE_BATS */
+
+	/* No BATs available, put it in the page tables. */
+	for (i = 0; i < size; i += PAGE_SIZE)
+		map_page(virt + i, phys + i, flags);
+}
+
+/* Scan the real Linux page tables and return a PTE pointer for
+ * a virtual address in a context.
+ * Returns true (1) if PTE was found, zero otherwise.  The pointer to
+ * the PTE pointer is unmodified if PTE is not found.
+ */
+int
+get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep)
+{
+        pgd_t	*pgd;
+        pmd_t	*pmd;
+        pte_t	*pte;
+        int     retval = 0;
+
+        pgd = pgd_offset(mm, addr & PAGE_MASK);
+        if (pgd) {
+                pmd = pmd_offset(pgd, addr & PAGE_MASK);
+                if (pmd_present(*pmd)) {
+                        pte = pte_offset(pmd, addr & PAGE_MASK);
+                        if (pte) {
+				retval = 1;
+				*ptep = pte;
+                        }
+                }
+        }
+        return(retval);
+}
+
+/* Find physical address for this virtual address.  Normally used by
+ * I/O functions, but anyone can call it.
+ */
+unsigned long iopa(unsigned long addr)
+{
+	unsigned long pa;
+
+	/* I don't know why this won't work on PMacs or CHRP.  It
+	 * appears there is some bug, or there is some implicit
+	 * mapping done not properly represented by BATs or in page
+	 * tables.......I am actively working on resolving this, but
+	 * can't hold up other stuff.  -- Dan
+	 */
+	pte_t *pte;
+	struct mm_struct *mm;
+
+	/* Check the BATs */
+	pa = v_mapped_by_bats(addr);
+	if (pa)
+		return pa;
+
+	/* Allow mapping of user addresses (within the thread)
+	 * for DMA if necessary.
+	 */
+	if (addr < TASK_SIZE)
+		mm = current->mm;
+	else
+		mm = &init_mm;
+	
+	pa = 0;
+	if (get_pteptr(mm, addr, &pte))
+		pa = (pte_val(*pte) & PAGE_MASK) | (addr & ~PAGE_MASK);
+
+	return(pa);
+}
+
+/* This is will find the virtual address for a physical one....
+ * Swiped from APUS, could be dangerous :-).
+ * This is only a placeholder until I really find a way to make this
+ * work.  -- Dan
+ */
+unsigned long
+mm_ptov (unsigned long paddr)
+{
+	unsigned long ret;
+#if 0
+	if (paddr < 16*1024*1024)
+		ret = ZTWO_VADDR(paddr);
+	else {
+		int i;
+
+		for (i = 0; i < kmap_chunk_count;){
+			unsigned long phys = kmap_chunks[i++];
+			unsigned long size = kmap_chunks[i++];
+			unsigned long virt = kmap_chunks[i++];
+			if (paddr >= phys
+			    && paddr < (phys + size)){
+				ret = virt + paddr - phys;
+				goto exit;
+			}
+		}
+		
+		ret = (unsigned long) __va(paddr);
+	}
+exit:
+#ifdef DEBUGPV
+	printk ("PTOV(%lx)=%lx\n", paddr, ret);
+#endif
+#else
+	ret = (unsigned long)paddr + KERNELBASE;
+#endif
+	return ret;
+}
+
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/mm/ppc_mmu.c linux/arch/ppc/mm/ppc_mmu.c
--- v2.4.9/linux/arch/ppc/mm/ppc_mmu.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/mm/ppc_mmu.c	Tue Aug 28 06:58:33 2001
@@ -0,0 +1,313 @@
+/*
+ * 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,
+ * 8260, and POWER3 implementations but excludes the 8xx and 4xx.
+ * Although the iSeries hardware does comply with the architecture
+ * specification, the need to work through the hypervisor makes
+ * things sufficiently different that it is handled elsewhere.
+ *  -- paulus
+ * 
+ *  Derived from arch/ppc/mm/init.c:
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
+ *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ *    Copyright (C) 1996 Paul Mackerras
+ *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+
+#include <asm/prom.h>
+#include <asm/mmu.h>
+#include <asm/machdep.h>
+
+#include "mmu_decl.h"
+#include "mem_pieces.h"
+
+PTE *Hash, *Hash_end;
+unsigned long Hash_size, Hash_mask;
+unsigned long _SDR1;
+
+union ubat {			/* BAT register values to be loaded */
+	BAT	bat;
+#ifdef CONFIG_PPC64BRIDGE
+	u64	word[2];
+#else
+	u32	word[2];
+#endif	
+} BATS[4][2];			/* 4 pairs of IBAT, DBAT */
+
+struct batrange {		/* stores address ranges mapped by BATs */
+	unsigned long start;
+	unsigned long limit;
+	unsigned long phys;
+} bat_addrs[4];
+
+/*
+ * Return PA for this VA if it is mapped by a BAT, or 0
+ */
+unsigned long v_mapped_by_bats(unsigned long va)
+{
+	int b;
+	for (b = 0; b < 4; ++b)
+		if (va >= bat_addrs[b].start && va < bat_addrs[b].limit)
+			return bat_addrs[b].phys + (va - bat_addrs[b].start);
+	return 0;
+}
+
+/*
+ * Return VA for a given PA or 0 if not mapped
+ */
+unsigned long p_mapped_by_bats(unsigned long pa)
+{
+	int b;
+	for (b = 0; b < 4; ++b)
+		if (pa >= bat_addrs[b].phys
+	    	    && pa < (bat_addrs[b].limit-bat_addrs[b].start)
+		              +bat_addrs[b].phys)
+			return bat_addrs[b].start+(pa-bat_addrs[b].phys);
+	return 0;
+}
+
+void __init bat_mapin_ram(void)
+{
+	unsigned long tot, bl, done;
+	unsigned long max_size = (256<<20);
+	unsigned long align;
+
+	/* Set up BAT2 and if necessary BAT3 to cover RAM. */
+
+	/* Make sure we don't map a block larger than the
+	   smallest alignment of the physical address. */
+	/* alignment of ram_phys_base */
+	align = ~(ram_phys_base-1) & ram_phys_base;
+	/* set BAT block size to MIN(max_size, align) */
+	if (align && align < max_size)
+		max_size = align;
+
+	tot = total_lowmem;
+	for (bl = 128<<10; bl < max_size; bl <<= 1) {
+		if (bl * 2 > tot)
+			break;
+	}
+
+	setbat(2, KERNELBASE, ram_phys_base, bl, _PAGE_KERNEL);
+	done = (unsigned long)bat_addrs[2].limit - KERNELBASE + 1;
+	if ((done < tot) && !bat_addrs[3].limit) {
+		/* use BAT3 to cover a bit more */
+		tot -= done;
+		for (bl = 128<<10; bl < max_size; bl <<= 1)
+			if (bl * 2 > tot)
+				break;
+		setbat(3, KERNELBASE+done, ram_phys_base+done, bl, 
+		       _PAGE_KERNEL);
+	}
+}
+
+/*
+ * Set up one of the I/D BAT (block address translation) register pairs.
+ * The parameters are not checked; in particular size must be a power
+ * of 2 between 128k and 256M.
+ */
+void __init setbat(int index, unsigned long virt, unsigned long phys,
+		   unsigned int size, int flags)
+{
+	unsigned int bl;
+	int wimgxpp;
+	union ubat *bat = BATS[index];
+
+#ifdef CONFIG_SMP
+	if ((flags & _PAGE_NO_CACHE) == 0)
+		flags |= _PAGE_COHERENT;
+#endif
+	bl = (size >> 17) - 1;
+	if (PVR_VER(mfspr(PVR)) != 1) {
+		/* 603, 604, etc. */
+		/* Do DBAT first */
+		wimgxpp = flags & (_PAGE_WRITETHRU | _PAGE_NO_CACHE
+				   | _PAGE_COHERENT | _PAGE_GUARDED);
+		wimgxpp |= (flags & _PAGE_RW)? BPP_RW: BPP_RX;
+		bat[1].word[0] = virt | (bl << 2) | 2; /* Vs=1, Vp=0 */
+		bat[1].word[1] = phys | wimgxpp;
+#ifndef CONFIG_KGDB /* want user access for breakpoints */
+		if (flags & _PAGE_USER)
+#endif
+			bat[1].bat.batu.vp = 1;
+		if (flags & _PAGE_GUARDED) {
+			/* G bit must be zero in IBATs */
+			bat[0].word[0] = bat[0].word[1] = 0;
+		} else {
+			/* make IBAT same as DBAT */
+			bat[0] = bat[1];
+		}
+	} else {
+		/* 601 cpu */
+		if (bl > BL_8M)
+			bl = BL_8M;
+		wimgxpp = flags & (_PAGE_WRITETHRU | _PAGE_NO_CACHE
+				   | _PAGE_COHERENT);
+		wimgxpp |= (flags & _PAGE_RW)?
+			((flags & _PAGE_USER)? PP_RWRW: PP_RWXX): PP_RXRX;
+		bat->word[0] = virt | wimgxpp | 4;	/* Ks=0, Ku=1 */
+		bat->word[1] = phys | bl | 0x40;	/* V=1 */
+	}
+
+	bat_addrs[index].start = virt;
+	bat_addrs[index].limit = virt + ((bl + 1) << 17) - 1;
+	bat_addrs[index].phys = phys;
+}
+
+/*
+ * Initialize the hash table and patch the instructions in hashtable.S.
+ */
+void __init MMU_init_hw(void)
+{
+	int Hash_bits, mb, mb2;
+	unsigned int hmask;
+
+	extern unsigned int hash_page_patch_A[];
+	extern unsigned int hash_page_patch_B[], hash_page_patch_C[];
+	extern unsigned int hash_page[];
+	extern unsigned int flush_hash_patch_A[], flush_hash_patch_B[];
+
+#ifdef CONFIG_PPC64BRIDGE
+	/* The hash table has already been allocated and initialized
+	   in prom.c */
+	Hash_mask = (Hash_size >> 7) - 1;
+	hmask = Hash_mask >> 9;
+	Hash_bits = __ilog2(Hash_size) - 7;
+	mb = 25 - Hash_bits;
+	if (Hash_bits > 16)
+		Hash_bits = 16;
+	mb2 = 25 - Hash_bits;
+
+	/* Remove the hash table from the available memory */
+	if (Hash)
+		reserve_phys_mem(__pa(Hash), Hash_size);
+
+#else /* CONFIG_PPC64BRIDGE */
+	unsigned int h;
+
+	if ((cur_cpu_spec[0]->cpu_features & CPU_FTR_HPTE_TABLE) == 0)
+		return;
+	if ( ppc_md.progress ) ppc_md.progress("hash:enter", 0x105);
+	/*
+	 * Allow 64k of hash table for every 16MB of memory,
+	 * up to a maximum of 2MB.
+	 */
+	for (h = 64<<10; h < total_memory / 256 && h < (2<<20); h *= 2)
+		;
+	Hash_size = h;
+	Hash_mask = (h >> 6) - 1;
+	hmask = Hash_mask >> 10;
+	Hash_bits = __ilog2(h) - 6;
+	mb = 26 - Hash_bits;
+	if (Hash_bits > 16)
+		Hash_bits = 16;
+	mb2 = 26 - Hash_bits;
+
+	if ( ppc_md.progress ) ppc_md.progress("hash:find piece", 0x322);
+	/* Find some memory for the hash table. */
+	if ( Hash_size ) {
+		Hash = mem_pieces_find(Hash_size, Hash_size);
+		cacheable_memzero(Hash, Hash_size);
+		_SDR1 = __pa(Hash) | (Hash_mask >> 10);
+	} else
+		Hash = 0;
+#endif /* CONFIG_PPC64BRIDGE */
+
+	printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
+	       total_memory >> 20, Hash_size >> 10, Hash);
+	if (Hash_size) {
+		if ( ppc_md.progress ) ppc_md.progress("hash:patch", 0x345);
+		Hash_end = (PTE *) ((unsigned long)Hash + Hash_size);
+
+		/*
+		 * Patch up the instructions in hashtable.S:create_hpte
+		 */
+		hash_page_patch_A[0] = (hash_page_patch_A[0] & ~0xffff)
+			| ((unsigned int)(Hash) >> 16);
+		hash_page_patch_A[1] = (hash_page_patch_A[1] & ~0x7c0)
+			| (mb << 6);
+		hash_page_patch_A[2] = (hash_page_patch_A[2] & ~0x7c0)
+			| (mb2 << 6);
+		hash_page_patch_B[0] = (hash_page_patch_B[0] & ~0xffff)
+			| hmask;
+		hash_page_patch_C[0] = (hash_page_patch_C[0] & ~0xffff)
+			| hmask;
+		/*
+		 * Ensure that the locations we've patched have been written
+		 * out from the data cache and invalidated in the instruction
+		 * cache, on those machines with split caches.
+		 */
+		flush_icache_range((unsigned long) &hash_page_patch_A[0],
+				   (unsigned long) &hash_page_patch_C[1]);
+		/*
+		 * Patch up the instructions in hashtable.S:flush_hash_page
+		 */
+		flush_hash_patch_A[0] = (flush_hash_patch_A[0] & ~0xffff)
+			| ((unsigned int)(Hash) >> 16);
+		flush_hash_patch_A[1] = (flush_hash_patch_A[1] & ~0x7c0)
+			| (mb << 6);
+		flush_hash_patch_A[2] = (flush_hash_patch_A[2] & ~0x7c0)
+			| (mb2 << 6);
+		flush_hash_patch_B[0] = (flush_hash_patch_B[0] & ~0xffff)
+			| hmask;
+		flush_icache_range((unsigned long) &flush_hash_patch_A[0],
+				   (unsigned long) &flush_hash_patch_B[1]);
+	}
+	else {
+		Hash_end = 0;
+		/*
+		 * Put a blr (procedure return) instruction at the
+		 * start of hash_page, since we can still get DSI
+		 * exceptions on a 603.
+		 */
+		hash_page[0] = 0x4e800020;
+		flush_icache_range((unsigned long) &hash_page[0],
+				   (unsigned long) &hash_page[1]);
+	}
+
+	if ( ppc_md.progress ) ppc_md.progress("hash:done", 0x205);
+}
+
+/*
+ * This is called at the end of handling a user page fault, when the
+ * fault has been handled by updating a PTE in the linux page tables.
+ * We use it to preload an HPTE into the hash table corresponding to
+ * the updated linux PTE.
+ */
+void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
+		      pte_t pte)
+{
+	struct mm_struct *mm;
+	pmd_t *pmd;
+	pte_t *ptep;
+	static int nopreload;
+
+	if (Hash == 0 || nopreload)
+		return;
+	mm = (address < TASK_SIZE)? vma->vm_mm: &init_mm;
+	pmd = pmd_offset(pgd_offset(mm, address), address);
+	if (!pmd_none(*pmd)) {
+		ptep = pte_offset(pmd, address);
+		add_hash_page(mm->context, address, ptep);
+	}
+}
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/mm/tlb.c linux/arch/ppc/mm/tlb.c
--- v2.4.9/linux/arch/ppc/mm/tlb.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/ppc/mm/tlb.c	Tue Aug 28 06:58:33 2001
@@ -0,0 +1,162 @@
+/*
+ * 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 the
+ * hash table also.
+ *  -- paulus
+ * 
+ *  Derived from arch/ppc/mm/init.c:
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
+ *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
+ *    Copyright (C) 1996 Paul Mackerras
+ *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
+ *
+ *  Derived from "arch/i386/mm/init.c"
+ *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+
+#include "mmu_decl.h"
+
+/*
+ * TLB flushing:
+ *
+ *  - flush_tlb_all() flushes all processes TLBs
+ *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
+ *  - flush_tlb_page(vma, vmaddr) flushes one page
+ *  - flush_tlb_range(mm, start, end) flushes a range of pages
+ *
+ * since the hardware hash table functions as an extension of the
+ * tlb as far as the linux tables are concerned, flush it too.
+ *    -- Cort
+ */
+
+/*
+ * Flush all tlb/hash table entries (except perhaps for those
+ * mapping RAM starting at PAGE_OFFSET, since they never change).
+ */
+void
+local_flush_tlb_all(void)
+{
+	/* aargh!!! */
+	/*
+	 * Just flush the kernel part of the address space, that's
+	 * all that the current callers of this require.
+	 * Eventually I hope to persuade the powers that be that
+	 * we can and should dispense with flush_tlb_all().
+	 *  -- paulus.
+	 */
+	local_flush_tlb_range(&init_mm, TASK_SIZE, ~0UL);
+
+#ifdef CONFIG_SMP
+	smp_send_tlb_invalidate(0);
+#endif /* CONFIG_SMP */
+}
+
+/*
+ * Flush all the (user) entries for the address space described
+ * by mm.  We can't rely on mm->mmap describing all the entries
+ * that might be in the hash table.
+ */
+void
+local_flush_tlb_mm(struct mm_struct *mm)
+{
+	if (Hash == 0) {
+		_tlbia();
+		return;
+	}
+
+	if (mm->map_count) {
+		struct vm_area_struct *mp;
+		for (mp = mm->mmap; mp != NULL; mp = mp->vm_next)
+			local_flush_tlb_range(mm, mp->vm_start, mp->vm_end);
+	} else
+		local_flush_tlb_range(mm, 0, TASK_SIZE);
+
+#ifdef CONFIG_SMP
+	smp_send_tlb_invalidate(0);
+#endif	
+}
+
+void
+local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
+{
+	struct mm_struct *mm;
+	pmd_t *pmd;
+	pte_t *pte;
+
+	if (Hash == 0) {
+		_tlbie(vmaddr);
+		return;
+	}
+	mm = (vmaddr < TASK_SIZE)? vma->vm_mm: &init_mm;
+	pmd = pmd_offset(pgd_offset(mm, vmaddr), vmaddr);
+	if (!pmd_none(*pmd)) {
+		pte = pte_offset(pmd, vmaddr);
+		if (pte_val(*pte) & _PAGE_HASHPTE)
+			flush_hash_page(mm->context, vmaddr, pte);
+	}
+#ifdef CONFIG_SMP
+	smp_send_tlb_invalidate(0);
+#endif	
+}
+
+
+/*
+ * For each address in the range, find the pte for the address
+ * and check _PAGE_HASHPTE bit; if it is set, find and destroy
+ * the corresponding HPTE.
+ */
+void
+local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
+{
+	pmd_t *pmd;
+	pte_t *pte;
+	unsigned long pmd_end;
+	unsigned int ctx = mm->context;
+
+	if (Hash == 0) {
+		_tlbia();
+		return;
+	}
+	start &= PAGE_MASK;
+	if (start >= end)
+		return;
+	pmd = pmd_offset(pgd_offset(mm, start), start);
+	do {
+		pmd_end = (start + PGDIR_SIZE) & PGDIR_MASK;
+		if (!pmd_none(*pmd)) {
+			if (!pmd_end || pmd_end > end)
+				pmd_end = end;
+			pte = pte_offset(pmd, start);
+			do {
+				if ((pte_val(*pte) & _PAGE_HASHPTE) != 0)
+					flush_hash_page(ctx, start, pte);
+				start += PAGE_SIZE;
+				++pte;
+			} while (start && start < pmd_end);
+		} else {
+			start = pmd_end;
+		}
+		++pmd;
+	} while (start && start < end);
+
+#ifdef CONFIG_SMP
+	smp_send_tlb_invalidate(0);
+#endif	
+}
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/vmlinux.lds linux/arch/ppc/vmlinux.lds
--- v2.4.9/linux/arch/ppc/vmlinux.lds	Mon Aug 27 12:41:39 2001
+++ linux/arch/ppc/vmlinux.lds	Tue Aug 28 06:58:33 2001
@@ -70,6 +70,10 @@
   __ksymtab : { *(__ksymtab) }
   __stop___ksymtab = .;
 
+  __start___ftr_fixup = .;
+  __ftr_fixup : { *(__ftr_fixup) }
+  __stop___ftr_fixup = .;
+
   . = ALIGN(32);
   .data.cacheline_aligned : { *(.data.cacheline_aligned) }
 
diff -u --recursive --new-file v2.4.9/linux/arch/ppc/xmon/start.c linux/arch/ppc/xmon/start.c
--- v2.4.9/linux/arch/ppc/xmon/start.c	Mon May 21 17:04:47 2001
+++ linux/arch/ppc/xmon/start.c	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.start.c 1.12 05/21/01 21:39:13 paulus
+ * BK Id: SCCS/s.start.c 1.16 08/20/01 22:17:58 paulus
  */
 /*
  * Copyright (C) 1996 Paul Mackerras.
@@ -18,6 +18,7 @@
 #include <asm/feature.h>
 #include <asm/processor.h>
 #include <asm/delay.h>
+#include <asm/btext.h>
 #ifdef CONFIG_SMP
 #include <asm/bitops.h>
 #endif
@@ -25,8 +26,6 @@
 static volatile unsigned char *sccc, *sccd;
 unsigned long TXRDY, RXRDY;
 extern void xmon_printf(const char *fmt, ...);
-extern void prom_drawchar(char);
-extern void prom_drawstring(const char *str);
 static int xmon_expect(const char *str, unsigned int timeout);
 
 static int console;
@@ -56,6 +55,7 @@
 void
 xmon_map_scc(void)
 {
+#ifdef CONFIG_ALL_PPC
 	volatile unsigned char *base;
 
 	use_screen = 0;
@@ -85,14 +85,34 @@
 				use_screen = 1;
 #endif
 		}
-		prom_drawstring("xmon uses ");
+		if (!use_screen && (np = find_devices("escc")) != NULL) {
+			/*
+			 * look for the device node for the serial port
+			 * we're using and see if it says it has a modem
+			 */
+			char *name = xmon_use_sccb? "ch-b": "ch-a";
+			char *slots;
+			int l;
+
+			np = np->child;
+			while (np != NULL && strcmp(np->name, name) != 0)
+				np = np->sibling;
+			if (np != NULL) {
+				/* XXX should parse this properly */
+				slots = get_property(np, "slot-names", &l);
+				if (slots != NULL && l >= 10
+				    && strcmp(slots+4, "Modem") == 0)
+					via_modem = 1;
+			}
+		}
+		btext_drawstring("xmon uses ");
 		if (use_screen)
-			prom_drawstring("screen and keyboard\n");
+			btext_drawstring("screen and keyboard\n");
 		else {
 			if (via_modem)
-				prom_drawstring("modem on ");
-			prom_drawstring(xmon_use_sccb? "printer": "modem");
-			prom_drawstring(" port\n");
+				btext_drawstring("modem on ");
+			btext_drawstring(xmon_use_sccb? "printer": "modem");
+			btext_drawstring(" port\n");
 		}
 
 #endif /* CONFIG_BOOTX_TEXT */
@@ -114,15 +134,6 @@
 		sccc = base + (addr & ~PAGE_MASK);
 		sccd = sccc + 0x10;
 	}
-	else if ( _machine & _MACH_gemini )
-	{
-		/* should already be mapped by the kernel boot */
-		sccc = (volatile unsigned char *) 0xffeffb0d;
-		sccd = (volatile unsigned char *) 0xffeffb08;
-		TXRDY = 0x20;
-		RXRDY = 1;
-		console = 1;
-	}
 	else
 	{
 		/* should already be mapped by the kernel boot */
@@ -135,6 +146,14 @@
 		TXRDY = 0x20;
 		RXRDY = 1;
 	}
+#elif defined(CONFIG_GEMINI)
+	/* should already be mapped by the kernel boot */
+	sccc = (volatile unsigned char *) 0xffeffb0d;
+	sccd = (volatile unsigned char *) 0xffeffb08;
+	TXRDY = 0x20;
+	RXRDY = 1;
+	console = 1;
+#endif /* platform */
 }
 
 static int scc_initialized = 0;
@@ -175,7 +194,7 @@
 	if (use_screen) {
 		/* write it on the screen */
 		for (i = 0; i < nb; ++i)
-			prom_drawchar(*p++);
+			btext_drawchar(*p++);
 		goto out;
 	}
 #endif
@@ -216,7 +235,7 @@
 
 static unsigned char xmon_keytab[128] =
 	"asdfhgzxcv\000bqwer"				/* 0x00 - 0x0f */
-	"yt123465=97-80o]"				/* 0x10 - 0x1f */
+	"yt123465=97-80]o"				/* 0x10 - 0x1f */
 	"u[ip\rlj'k;\\,/nm."				/* 0x20 - 0x2f */
 	"\t `\177\0\033\0\0\0\0\0\0\0\0\0\0"		/* 0x30 - 0x3f */
 	"\0.\0*\0+\0\0\0\0\0/\r\0-\0"			/* 0x40 - 0x4f */
@@ -224,7 +243,7 @@
 
 static unsigned char xmon_shift_keytab[128] =
 	"ASDFHGZXCV\000BQWER"				/* 0x00 - 0x0f */
-	"YT!@#$^%+(&=*)}O"				/* 0x10 - 0x1f */
+	"YT!@#$^%+(&_*)}O"				/* 0x10 - 0x1f */
 	"U{IP\rLJ\"K:|<?NM>"				/* 0x20 - 0x2f */
 	"\t ~\177\0\033\0\0\0\0\0\0\0\0\0\0"		/* 0x30 - 0x3f */
 	"\0.\0*\0+\0\0\0\0\0/\r\0-\0"			/* 0x40 - 0x4f */
@@ -243,15 +262,15 @@
 		do {
 			if (--t < 0) {
 				on = 1 - on;
-				prom_drawchar(on? 0xdb: 0x20);
-				prom_drawchar('\b');
+				btext_drawchar(on? 0xdb: 0x20);
+				btext_drawchar('\b');
 				t = 200000;
 			}
 			do_poll_adb();
 		} while (xmon_adb_keycode == -1);
 		k = xmon_adb_keycode;
 		if (on)
-			prom_drawstring(" \b");
+			btext_drawstring(" \b");
 
 		/* test for shift keys */
 		if ((k & 0x7f) == 0x38 || (k & 0x7f) == 0x7b) {
@@ -544,7 +563,9 @@
 xmon_enter(void)
 {
 #ifdef CONFIG_ADB_PMU
-	pmu_suspend();
+	if (_machine == _MACH_Pmac) {
+		pmu_suspend();
+	}
 #endif
 }
 
@@ -552,6 +573,8 @@
 xmon_leave(void)
 {
 #ifdef CONFIG_ADB_PMU
-	pmu_resume();
+	if (_machine == _MACH_Pmac) {
+		pmu_resume();
+	}
 #endif
 }
diff -u --recursive --new-file v2.4.9/linux/arch/sparc/boot/btfixupprep.c linux/arch/sparc/boot/btfixupprep.c
--- v2.4.9/linux/arch/sparc/boot/btfixupprep.c	Sun Oct  4 10:22:42 1998
+++ linux/arch/sparc/boot/btfixupprep.c	Tue Aug 28 07:09:44 2001
@@ -1,4 +1,4 @@
-/* $Id: btfixupprep.c,v 1.5 1998/09/16 12:24:55 jj Exp $
+/* $Id: btfixupprep.c,v 1.6 2001/08/22 15:27:47 davem Exp $
    Simple utility to prepare vmlinux image for sparc.
    Resolves all BTFIXUP uses and settings and creates
    a special .s object to link to the image.
@@ -88,6 +88,16 @@
 	return array + last - 1;
 }
 
+void set_mode (char *buffer)
+{
+  	for (mode = 0;; mode++)
+		if (buffer[mode] < '0' || buffer[mode] > '9')
+			break;
+	if (mode != 8 && mode != 16)
+		fatal();
+}
+
+
 int main(int argc,char **argv)
 {
 	char *p, *q;
@@ -106,14 +116,6 @@
 			goto main0;
 	fatal();
 main0:
-	if (fgets (buffer, 1024, stdin) == NULL || buffer[0] < '0' || buffer[0] > '9')
-		fatal();
-	for (mode = 0;; mode++)
-		if (buffer[mode] < '0' || buffer[mode] > '9')
-			break;
-	if (mode != 8 && mode != 16)
-		fatal();
-	
 	rellen = strlen(relrec);
 	while (fgets (buffer, 1024, stdin) != NULL)
 		if (!strncmp (buffer, relrec, rellen))
@@ -132,6 +134,8 @@
 		int nbase;
 		if (!strncmp (buffer, relrec, rellen))
 			goto main1;
+		if (mode == 0)
+			set_mode (buffer);
 		p = strchr (buffer, '\n');
 		if (p) *p = 0;
 		if (strlen (buffer) < 22+mode)
diff -u --recursive --new-file v2.4.9/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig
--- v2.4.9/linux/arch/sparc64/defconfig	Mon Aug 27 12:41:40 2001
+++ linux/arch/sparc64/defconfig	Tue Aug 28 07:09:44 2001
@@ -255,6 +255,7 @@
 CONFIG_BLK_DEV_IDEPCI=y
 # CONFIG_IDEPCI_SHARE_IRQ is not set
 CONFIG_BLK_DEV_IDEDMA_PCI=y
+CONFIG_BLK_DEV_ADMA=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
 CONFIG_IDEDMA_PCI_AUTO=y
 CONFIG_BLK_DEV_IDEDMA=y
@@ -264,8 +265,8 @@
 # CONFIG_AEC62XX_TUNING is not set
 CONFIG_BLK_DEV_ALI15X3=y
 # CONFIG_WDC_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD7409 is not set
-# CONFIG_AMD7409_OVERRIDE is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_AMD74XX_OVERRIDE is not set
 CONFIG_BLK_DEV_CMD64X=y
 # CONFIG_BLK_DEV_CY82C693 is not set
 # CONFIG_BLK_DEV_CS5530 is not set
@@ -276,7 +277,8 @@
 # CONFIG_BLK_DEV_OPTI621 is not set
 # CONFIG_BLK_DEV_PDC202XX is not set
 # CONFIG_PDC202XX_BURST is not set
-# CONFIG_BLK_DEV_OSB4 is not set
+# CONFIG_PDC202XX_FORCE is not set
+# CONFIG_BLK_DEV_SVWKS is not set
 # CONFIG_BLK_DEV_SIS5513 is not set
 # CONFIG_BLK_DEV_SLC90E66 is not set
 # CONFIG_BLK_DEV_TRM290 is not set
diff -u --recursive --new-file v2.4.9/linux/arch/sparc64/kernel/dtlb_backend.S linux/arch/sparc64/kernel/dtlb_backend.S
--- v2.4.9/linux/arch/sparc64/kernel/dtlb_backend.S	Mon Aug 27 12:41:40 2001
+++ linux/arch/sparc64/kernel/dtlb_backend.S	Tue Aug 28 07:09:44 2001
@@ -1,4 +1,4 @@
-/* $Id: dtlb_backend.S,v 1.12 2001/08/13 20:41:54 kanoj Exp $
+/* $Id: dtlb_backend.S,v 1.13 2001/08/17 04:55:09 kanoj Exp $
  * dtlb_backend.S: Back end to DTLB miss replacement strategy.
  *                 This is included directly into the trap table.
  *
@@ -6,11 +6,27 @@
  * Copyright (C) 1997,1998 Jakub Jelinek   (jj@ultra.linux.cz)
  */
 
-#define TAG_CONTEXT_BITS	0x3ff
+#include <asm/pgtable.h>
+
+#if PAGE_SHIFT == 13
+#define FILL_VALID_SZ_BITS1(r1) \
+	 sllx		%g2, 62, r1
+#define FILL_VALID_SZ_BITS2(r1)
+#define FILL_VALID_SZ_BITS_NOP nop
+#else /* PAGE_SHIFT */
+#define FILL_VALID_SZ_BITS1(r1) \
+	or		%g0, 5, r1
+#define FILL_VALID_SZ_BITS2(r1) \
+	sllx		r1, 61, r1
+#define FILL_VALID_SZ_BITS_NOP
+#endif /* PAGE_SHIFT */
+
+#define VPTE_BITS		(_PAGE_CP | _PAGE_CV | _PAGE_P )
 #define VPTE_SHIFT		(PAGE_SHIFT - 3)
-#define PMD_SHIFT		(23 - PAGE_SHIFT + 3)
-#define PGD_SHIFT		(34 - PAGE_SHIFT + 3)
-#define VPTE_BITS		(_PAGE_CP | _PAGE_CV | _PAGE_P)
+#define TLB_PMD_SHIFT		(PAGE_SHIFT - 3 + 3)
+#define TLB_PGD_SHIFT		(PAGE_SHIFT - 2 + PAGE_SHIFT - 3 + 3)
+#define TLB_PMD_MASK		(((1 << PMD_BITS) - 1) << 1)
+#define TLB_PGD_MASK		(((1 << (VA_BITS - PAGE_SHIFT - (PAGE_SHIFT - 3) - PMD_BITS)) - 1) << 2)
 
 /* Ways we can get here:
  *
@@ -31,13 +47,13 @@
 
 /* TLB1 ** ICACHE line 2: Quick VPTE miss	  	*/
 	ldxa		[%g1] ASI_DMMU, %g5		! Doing PGD caching?
-	srlx		%g6, (PMD_SHIFT - 1), %g1	! Position PMD offset
+	srlx		%g6, (TLB_PMD_SHIFT - 1), %g1	! Position PMD offset
 	be,pn		%xcc, sparc64_vpte_nucleus	! Is it from Nucleus?
-	 and		%g1, 0xffe, %g1			! Mask PMD offset bits
+	 and		%g1, TLB_PMD_MASK, %g1		! Mask PMD offset bits
 	brnz,pt		%g5, sparc64_vpte_continue	! Yep, go like smoke
 	 add		%g1, %g1, %g1			! Position PMD offset some more
-	srlx		%g6, (PGD_SHIFT - 2), %g5	! Position PGD offset
-	and		%g5, 0xffc, %g5			! Mask PGD offset
+	srlx		%g6, (TLB_PGD_SHIFT - 2), %g5	! Position PGD offset
+	and		%g5, TLB_PGD_MASK, %g5		! Mask PGD offset
 
 /* TLB1 ** ICACHE line 3: Quick VPTE miss	  	*/
 	lduwa		[%g7 + %g5] ASI_PHYS_USE_EC, %g5! Load PGD
@@ -48,7 +64,8 @@
 	lduwa		[%g5 + %g1] ASI_PHYS_USE_EC, %g5! Load PMD
 	sllx		%g5, 11, %g5			! Shift into place
 	brz,pn		%g5, vpte_noent			! Valid?
-	 sllx		%g2, 62, %g1			! Put _PAGE_VALID into %g1
+	 FILL_VALID_SZ_BITS1(%g1)			! Put _PAGE_VALID into %g1
+	FILL_VALID_SZ_BITS2(%g1)			! Put _PAGE_VALID into %g1
 	or		%g5, VPTE_BITS, %g5		! Prepare VPTE data
 
 /* TLB1 ** ICACHE line 4: Quick VPTE miss	  	*/
@@ -59,10 +76,15 @@
 	retry						! Load PTE once again
 	nop
 	nop
-	nop
+	FILL_VALID_SZ_BITS_NOP
 
-#undef TAG_CONTEXT_BITS
 #undef VPTE_SHIFT
-#undef PMD_SHIFT
-#undef PGD_SHIFT
+#undef TLB_PMD_SHIFT
+#undef TLB_PGD_SHIFT
 #undef VPTE_BITS
+#undef TLB_PMD_MASK
+#undef TLB_PGD_MASK
+#undef FILL_VALID_SZ_BITS1
+#undef FILL_VALID_SZ_BITS2
+#undef FILL_VALID_SZ_BITS_NOP
+
diff -u --recursive --new-file v2.4.9/linux/arch/sparc64/kernel/dtlb_base.S linux/arch/sparc64/kernel/dtlb_base.S
--- v2.4.9/linux/arch/sparc64/kernel/dtlb_base.S	Mon Aug 27 12:41:40 2001
+++ linux/arch/sparc64/kernel/dtlb_base.S	Tue Aug 28 07:09:44 2001
@@ -1,4 +1,4 @@
-/* $Id: dtlb_base.S,v 1.10 2001/08/13 20:41:54 kanoj Exp $
+/* $Id: dtlb_base.S,v 1.12 2001/08/17 04:55:09 kanoj Exp $
  * dtlb_base.S:	Front end to DTLB miss replacement strategy.
  *              This is included directly into the trap table.
  *
@@ -6,11 +6,6 @@
  * Copyright (C) 1997,1998 Jakub Jelinek   (jj@ultra.linux.cz)
  */
 
-#define TAG_CONTEXT_BITS	0x3ff
-#define VPTE_SHIFT		(PAGE_SHIFT - 3)
-#define KERN_HIGHBITS		((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000)
-#define KERN_LOWBITS		(_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W)
-
 /* %g1	TLB_SFSR	(%g1 + %g1 == TLB_TAG_ACCESS)
  * %g2	(KERN_HIGHBITS | KERN_LOWBITS)
  * %g3  VPTE base	(0xfffffffe00000000)	Spitfire/Blackbird (44-bit VA space)
@@ -48,26 +43,47 @@
  * 4) User space accesses by nucleus at tl0
  */
 
+#if PAGE_SHIFT == 13
+/*
+ * To compute vpte offset, we need to do ((addr >> 13) << 3),
+ * which can be optimized to (addr >> 10) if bits 10/11/12 can
+ * be guaranteed to be 0 ... mmu_context.h does guarantee this
+ * by only using 10 bits in the hwcontext value.
+ */
+#define CREATE_VPTE_OFFSET1(r1, r2)
+#define CREATE_VPTE_OFFSET2(r1, r2) \
+				srax	r1, 10, r2
+#define CREATE_VPTE_NOP		nop
+#else
+#define CREATE_VPTE_OFFSET1(r1, r2) \
+				srax	r1, PAGE_SHIFT, r2
+#define CREATE_VPTE_OFFSET2(r1, r2) \
+				sllx	r2, 3, r2
+#define CREATE_VPTE_NOP
+#endif
+
 /* DTLB ** ICACHE line 1: Quick user TLB misses		*/
 	ldxa		[%g1 + %g1] ASI_DMMU, %g4	! Get TAG_ACCESS
 	andcc		%g4, TAG_CONTEXT_BITS, %g0	! From Nucleus?
 from_tl1_trap:
+	CREATE_VPTE_OFFSET1(%g4, %g6)			! Create VPTE offset
 	be,pn		%xcc, 3f			! Yep, special processing
-	 srax		%g4, VPTE_SHIFT, %g6		! Create VPTE offset
+	 CREATE_VPTE_OFFSET2(%g4, %g6)			! Create VPTE offset
 	ldxa		[%g3 + %g6] ASI_S, %g5		! Load VPTE
 1:	brlz,pt		%g5, 9f				! Valid, load into TLB
 	 nop						! Delay-slot
-	ba,a,pt		%xcc, 4f			! Invalid, branch out
+	ba,a,pt		%xcc, longpath			! Invalid, branch out
 
 /* DTLB ** ICACHE line 2: Quick kernel TLB misses	*/
 3:	brlz,pt		%g4, 9f				! Kernel virtual map?
 	 xor		%g2, %g4, %g5			! Finish bit twiddles
-	ldxa		[%g3 + %g6] ASI_N, %g5		! Yep, load k-vpte
-	ba,pt		%xcc, 1b			! Continue tlb reload
+	ba,pt		%xcc, kvmap			! Yep, go check for obp/vmalloc
 	 nop
+	nop
 9:	stxa		%g5, [%g0] ASI_DTLB_DATA_IN	! Reload TLB
 	retry						! Trap return
-4:	rdpr		%pstate, %g5			! Move into alternate globals
+longpath:
+	rdpr		%pstate, %g5			! Move into alternate globals
 
 /* DTLB ** ICACHE line 3: winfixups+real_faults		*/
 	wrpr		%g5, PSTATE_AG|PSTATE_MG, %pstate
@@ -87,9 +103,8 @@
 	nop
 	nop
 	nop
-	nop
+	CREATE_VPTE_NOP
 
-#undef TAG_CONTEXT_BITS
-#undef VPTE_SHIFT
-#undef KERN_HIGHBITS
-#undef KERN_LOWBITS
+#undef CREATE_VPTE_OFFSET1
+#undef CREATE_VPTE_OFFSET2
+#undef CREATE_VPTE_NOP
diff -u --recursive --new-file v2.4.9/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S
--- v2.4.9/linux/arch/sparc64/kernel/entry.S	Mon Aug 27 12:41:40 2001
+++ linux/arch/sparc64/kernel/entry.S	Tue Aug 28 07:09:44 2001
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.129 2001/08/13 20:41:54 kanoj Exp $
+/* $Id: entry.S,v 1.134 2001/08/27 18:42:07 kanoj Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -21,7 +21,7 @@
 #include <asm/visasm.h>
 #include <asm/estate.h>
 
-/* #define SYSCALL_TRACING */
+/* #define SYSCALL_TRACING	1 */
 
 #define curptr      g6
 
@@ -32,7 +32,25 @@
 
 	.globl		sparc64_vpte_patchme1
 	.globl		sparc64_vpte_patchme2
+/*
+ * On a second level vpte miss, check whether the original fault is to the OBP 
+ * range (note that this is only possible for instruction miss, data misses to
+ * obp range do not use vpte). If so, go back directly to the faulting address.
+ * This is because we want to read the tpc, otherwise we have no way of knowing
+ * the 8k aligned faulting address if we are using >8k kernel pagesize. This also
+ * ensures no vpte range addresses are dropped into tlb while obp is executing
+ * (see inherit_locked_prom_mappings() rant).
+ */
 sparc64_vpte_nucleus:
+	mov		0xf, %g5
+	sllx		%g5, 28, %g5			! Load 0xf0000000
+	cmp		%g4, %g5			! Is addr >= LOW_OBP_ADDRESS?
+	blu,pn		%xcc, sparc64_vpte_patchme1
+	 mov		0x1, %g5
+	sllx		%g5, 32, %g5			! Load 0x100000000
+	cmp		%g4, %g5			! Is addr < HI_OBP_ADDRESS?
+	blu,pn		%xcc, obp_iaddr_patch
+	 nop
 sparc64_vpte_patchme1:
 	sethi		%hi(0), %g5			! This has to be patched
 sparc64_vpte_patchme2:
@@ -45,6 +63,74 @@
 	stxa		%g4, [%g1 + %g1] ASI_DMMU	! Restore previous TAG_ACCESS
 	done						! Slick trick
 
+	.globl		obp_iaddr_patch
+	.globl		obp_daddr_patch
+
+obp_iaddr_patch:
+	sethi		%hi(0), %g5			! This and following is patched
+	or		%g5, %lo(0), %g5		! g5 now holds obp pmd base physaddr
+	wrpr		%g0, 1, %tl			! Behave as if we are at TL0
+	rdpr		%tpc, %g4			! Find original faulting iaddr
+	srlx		%g4, 13, %g4			! Throw out context bits
+	sllx		%g4, 13, %g4			! g4 has vpn + ctx0 now
+	mov		TLB_SFSR, %g1			! Restore %g1 value
+	stxa		%g4, [%g1 + %g1] ASI_IMMU	! Restore previous TAG_ACCESS
+	srlx		%g4, 23, %g6			! Find pmd number
+	and		%g6, 0x7ff, %g6			! Find pmd number
+	sllx		%g6, 2, %g6			! Find pmd offset
+	lduwa		[%g5 + %g6] ASI_PHYS_USE_EC, %g5! Load pmd, ie pagetable physaddr
+	brz,pn		%g5, longpath			! Kill the PROM ? :-)
+	 sllx		%g5, 11, %g5			! Shift into place
+	srlx		%g4, 13, %g6			! find pte number in pagetable
+	and		%g6, 0x3ff, %g6			! find pte number in pagetable
+	sllx		%g6, 3, %g6			! find pte offset in pagetable
+	ldxa		[%g5 + %g6] ASI_PHYS_USE_EC, %g5! Load pte
+	brgez,pn	%g5, longpath			! Kill the PROM ? :-)
+	 nop
+	stxa		%g5, [%g0] ASI_ITLB_DATA_IN	! put into tlb
+	retry						! go back to original fault
+
+obp_daddr_patch:
+	sethi		%hi(0), %g5			! This and following is patched
+	or		%g5, %lo(0), %g5		! g5 now holds obp pmd base physaddr
+	srlx		%g4, 23, %g6			! Find pmd number
+	and		%g6, 0x7ff, %g6			! Find pmd number
+	sllx		%g6, 2, %g6			! Find pmd offset
+	lduwa		[%g5 + %g6] ASI_PHYS_USE_EC, %g5! Load pmd, ie pagetable physaddr
+	brz,pn		%g5, longpath
+	 sllx		%g5, 11, %g5			! Shift into place
+	srlx		%g4, 13, %g6			! find pte number in pagetable
+	and		%g6, 0x3ff, %g6			! find pte number in pagetable
+	sllx		%g6, 3, %g6			! find pte offset in pagetable
+	ldxa		[%g5 + %g6] ASI_PHYS_USE_EC, %g5! Load pte
+	brgez,pn	%g5, longpath
+	 nop
+	stxa		%g5, [%g0] ASI_DTLB_DATA_IN	! put into tlb
+	retry
+
+/*
+ * On a first level data miss, check whether this is to the OBP range (note that
+ * such accesses can be made by prom, as well as by kernel using prom_getproperty
+ * on "address"), and if so, do not use vpte access ... rather, use information
+ * saved during inherit_prom_mappings() using 8k pagesize.
+ */
+kvmap:
+	mov		0xf, %g5
+	sllx		%g5, 28, %g5			! Load 0xf0000000
+	cmp		%g4, %g5			! Is addr >= LOW_OBP_ADDRESS?
+	blu,pn		%xcc, vmalloc_addr
+	 mov		0x1, %g5
+	sllx		%g5, 32, %g5			! Load 0x100000000
+	cmp		%g4, %g5			! Is addr < HI_OBP_ADDRESS?
+	blu,pn		%xcc, obp_daddr_patch
+	 nop
+vmalloc_addr:						! vmalloc addr accessed
+	ldxa		[%g3 + %g6] ASI_N, %g5		! Yep, load k-vpte
+	brgez,pn	%g5, longpath			! Valid, load into TLB
+	 nop
+	stxa		%g5, [%g0] ASI_DTLB_DATA_IN	! Reload TLB
+	retry
+
 	/* This is trivial with the new code... */
 	.globl		do_fpdis
 do_fpdis:
@@ -1413,9 +1499,8 @@
 	 srl		%i0, 0, %o0				! IEU0
 	sll		%g1, 2, %l4				! IEU0	Group
 #ifdef SYSCALL_TRACING
-	add		%sp, STACK_BIAS + REGWIN_SZ, %o1
 	call		syscall_trace_entry
-	 mov		%g1, %o0
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
 	srl		%i0, 0, %o0
 #endif
 	mov		%i4, %o4				! IEU1
@@ -1442,9 +1527,8 @@
 	 mov		%i0, %o0				! IEU0
 	sll		%g1, 2, %l4				! IEU0	Group
 #ifdef SYSCALL_TRACING
-	add		%sp, STACK_BIAS + REGWIN_SZ, %o1
 	call		syscall_trace_entry
-	 mov		%g1, %o0
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
 	mov		%i0, %o0
 #endif
 	mov		%i1, %o1				! IEU1
@@ -1464,8 +1548,10 @@
 3:	stx		%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
 ret_sys_call:
 #ifdef SYSCALL_TRACING
+	mov		%o0, %o1
 	call		syscall_trace_exit
-	 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	mov		%o1, %o0
 #endif
 	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %g3
 	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 ! pc = npc
diff -u --recursive --new-file v2.4.9/linux/arch/sparc64/kernel/iommu_common.c linux/arch/sparc64/kernel/iommu_common.c
--- v2.4.9/linux/arch/sparc64/kernel/iommu_common.c	Mon Jun 19 17:59:38 2000
+++ linux/arch/sparc64/kernel/iommu_common.c	Tue Aug 28 07:09:44 2001
@@ -1,4 +1,4 @@
-/* $Id: iommu_common.c,v 1.4 2000/06/04 21:50:23 anton Exp $
+/* $Id: iommu_common.c,v 1.5 2001/08/24 17:57:51 kanoj Exp $
  * iommu_common.c: UltraSparc SBUS/PCI common iommu code.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -36,12 +36,12 @@
 		unsigned long start, end;
 
 		start = sg[i].dvma_address;
-		start = start & PAGE_MASK;
+		start = start & IO_PAGE_MASK;
 
 		end = sg[i].dvma_address + sg[i].dvma_length;
-		end = (end + (PAGE_SIZE - 1)) & PAGE_MASK;
+		end = (end + (IO_PAGE_SIZE - 1)) & IO_PAGE_MASK;
 
-		pgcount += ((end - start) >> PAGE_SHIFT);
+		pgcount += ((end - start) >> IO_PAGE_SHIFT);
 	}
 
 	if (pgcount != npages) {
@@ -70,7 +70,7 @@
 		unsigned long paddr;
 
 		/* SG and DMA_SG must begin at the same sub-page boundary. */
-		if ((sgaddr & ~PAGE_MASK) != (daddr & ~PAGE_MASK)) {
+		if ((sgaddr & ~IO_PAGE_MASK) != (daddr & ~IO_PAGE_MASK)) {
 			printk("verify_one_map: Wrong start offset "
 			       "sg[%08lx] dma[%08x]\n",
 			       sgaddr, daddr);
@@ -80,10 +80,10 @@
 
 		/* Verify the IOPTE points to the right page. */
 		paddr = iopte_val(*iopte) & IOPTE_PAGE;
-		if ((paddr + PAGE_OFFSET) != (sgaddr & PAGE_MASK)) {
+		if ((paddr + PAGE_OFFSET) != (sgaddr & IO_PAGE_MASK)) {
 			printk("verify_one_map: IOPTE[%08lx] maps the "
 			       "wrong page, should be [%08lx]\n",
-			       iopte_val(*iopte), (sgaddr & PAGE_MASK) - PAGE_OFFSET);
+			       iopte_val(*iopte), (sgaddr & IO_PAGE_MASK) - PAGE_OFFSET);
 			nents = -1;
 			goto out;
 		}
@@ -91,10 +91,10 @@
 		/* If this SG crosses a page, adjust to that next page
 		 * boundary and loop.
 		 */
-		if ((sgaddr & PAGE_MASK) ^ ((sgaddr + sglen - 1) & PAGE_MASK)) {
+		if ((sgaddr & IO_PAGE_MASK) ^ ((sgaddr + sglen - 1) & IO_PAGE_MASK)) {
 			unsigned long next_page, diff;
 
-			next_page = (sgaddr + PAGE_SIZE) & PAGE_MASK;
+			next_page = (sgaddr + IO_PAGE_SIZE) & IO_PAGE_MASK;
 			diff = next_page - sgaddr;
 			sgaddr += diff;
 			daddr += diff;
@@ -109,7 +109,7 @@
 		daddr += sglen;
 		dlen -= sglen;
 
-		if (dlen > 0 && ((daddr & ~PAGE_MASK) == 0))
+		if (dlen > 0 && ((daddr & ~IO_PAGE_MASK) == 0))
 			iopte++;
 
 		sg++;
@@ -175,7 +175,7 @@
 		int i;
 
 		printk("verify_sglist: Crap, messed up mappings, dumping, iodma at %08x.\n",
-		       (u32) (sg->dvma_address & PAGE_MASK));
+		       (u32) (sg->dvma_address & IO_PAGE_MASK));
 		for (i = 0; i < nents; i++) {
 			printk("sg(%d): address(%p) length(%x) "
 			       "dma_address[%08x] dma_length[%08x]\n",
@@ -189,13 +189,6 @@
 }
 #endif
 
-/* Two addresses are "virtually contiguous" if and only if:
- * 1) They are equal, or...
- * 2) They are both on a page boundry
- */
-#define VCONTIG(__X, __Y)	(((__X) == (__Y)) || \
-				 (((__X) | (__Y)) << (64UL - PAGE_SHIFT)) == 0UL)
-
 unsigned long prepare_sg(struct scatterlist *sg, int nents)
 {
 	struct scatterlist *dma_sg = sg;
@@ -204,7 +197,7 @@
 
 	prev  = (unsigned long) sg->address;
 	prev += (unsigned long) (dent_len = sg->length);
-	dent_addr = (u32) ((unsigned long)sg->address & (PAGE_SIZE - 1UL));
+	dent_addr = (u32) ((unsigned long)sg->address & (IO_PAGE_SIZE - 1UL));
 	while (--nents) {
 		unsigned long addr;
 
@@ -217,9 +210,9 @@
 
 			dent_addr = ((dent_addr +
 				      dent_len +
-				      (PAGE_SIZE - 1UL)) >> PAGE_SHIFT);
-			dent_addr <<= PAGE_SHIFT;
-			dent_addr += addr & (PAGE_SIZE - 1UL);
+				      (IO_PAGE_SIZE - 1UL)) >> IO_PAGE_SHIFT);
+			dent_addr <<= IO_PAGE_SHIFT;
+			dent_addr += addr & (IO_PAGE_SIZE - 1UL);
 			dent_len = 0;
 		}
 		dent_len += sg->length;
@@ -230,5 +223,5 @@
 
 	return ((unsigned long) dent_addr +
 		(unsigned long) dent_len +
-		(PAGE_SIZE - 1UL)) >> PAGE_SHIFT;
+		(IO_PAGE_SIZE - 1UL)) >> IO_PAGE_SHIFT;
 }
diff -u --recursive --new-file v2.4.9/linux/arch/sparc64/kernel/iommu_common.h linux/arch/sparc64/kernel/iommu_common.h
--- v2.4.9/linux/arch/sparc64/kernel/iommu_common.h	Mon Dec 20 22:05:52 1999
+++ linux/arch/sparc64/kernel/iommu_common.h	Tue Aug 28 07:09:44 2001
@@ -1,4 +1,4 @@
-/* $Id: iommu_common.h,v 1.1 1999/12/17 12:31:54 jj Exp $
+/* $Id: iommu_common.h,v 1.3 2001/08/24 19:36:58 kanoj Exp $
  * iommu_common.h: UltraSparc SBUS/PCI common iommu declarations.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -10,6 +10,22 @@
 #include <asm/page.h>
 #include <asm/iommu.h>
 #include <asm/scatterlist.h>
+
+/*
+ * These give mapping size of each iommu pte/tlb.
+ */
+#define IO_PAGE_SHIFT			13
+#define IO_PAGE_SIZE			(1UL << IO_PAGE_SHIFT)
+#define IO_PAGE_MASK			(~(IO_PAGE_SIZE-1))
+#define IO_PAGE_ALIGN(addr)		(((addr)+IO_PAGE_SIZE-1)&IO_PAGE_MASK)
+
+#define IO_TSB_ENTRIES			(128*1024)
+#define IO_TSB_SIZE			(IO_TSB_ENTRIES * 8)
+
+/*
+ * This is the hardwired shift in the iotlb tag/data parts.
+ */
+#define IOMMU_PAGE_SHIFT		13
 
 /* You are _strongly_ advised to enable the following debugging code
  * any time you make changes to the sg code below, run it for a while
diff -u --recursive --new-file v2.4.9/linux/arch/sparc64/kernel/itlb_base.S linux/arch/sparc64/kernel/itlb_base.S
--- v2.4.9/linux/arch/sparc64/kernel/itlb_base.S	Sun Nov 12 20:37:16 2000
+++ linux/arch/sparc64/kernel/itlb_base.S	Tue Aug 28 07:09:44 2001
@@ -1,4 +1,4 @@
-/* $Id: itlb_base.S,v 1.10 2000/11/10 08:28:45 davem Exp $
+/* $Id: itlb_base.S,v 1.11 2001/08/17 04:55:09 kanoj Exp $
  * itlb_base.S:	Front end to ITLB miss replacement strategy.
  *              This is included directly into the trap table.
  *
@@ -6,8 +6,25 @@
  * Copyright (C) 1997,1998 Jakub Jelinek   (jj@ultra.linux.cz)
  */
 
-#define TAG_CONTEXT_BITS	0x3ff
-#define VPTE_SHIFT		(PAGE_SHIFT - 3)
+#if PAGE_SHIFT == 13
+/*
+ * To compute vpte offset, we need to do ((addr >> 13) << 3),
+ * which can be optimized to (addr >> 10) if bits 10/11/12 can
+ * be guaranteed to be 0 ... mmu_context.h does guarantee this
+ * by only using 10 bits in the hwcontext value.
+ */
+#define CREATE_VPTE_OFFSET1(r1, r2) \
+				srax	r1, 10, r2
+#define CREATE_VPTE_OFFSET2(r1, r2)
+#define CREATE_VPTE_NOP		nop
+#else /* PAGE_SHIFT */
+#define CREATE_VPTE_OFFSET1(r1, r2) \
+				srax	r1, PAGE_SHIFT, r2
+#define CREATE_VPTE_OFFSET2(r1, r2) \
+				sllx	r2, 3, r2
+#define CREATE_VPTE_NOP
+#endif /* PAGE_SHIFT */
+
 
 /* Ways we can get here:
  *
@@ -20,7 +37,8 @@
 
 /* ITLB ** ICACHE line 1: Quick user TLB misses		*/
 	ldxa		[%g1 + %g1] ASI_IMMU, %g4	! Get TAG_ACCESS
-	srax		%g4, VPTE_SHIFT, %g6		! Create VPTE offset
+	CREATE_VPTE_OFFSET1(%g4, %g6)			! Create VPTE offset
+	CREATE_VPTE_OFFSET2(%g4, %g6)			! Create VPTE offset
 	ldxa		[%g3 + %g6] ASI_P, %g5		! Load VPTE
 1:	brgez,pn	%g5, 3f				! Not valid, branch out
 	 nop						! Delay-slot
@@ -58,7 +76,8 @@
 	nop
 	nop
 	nop
-	nop
+	CREATE_VPTE_NOP
 
-#undef TAG_CONTEXT_BITS
-#undef VPTE_SHIFT
+#undef CREATE_VPTE_OFFSET1
+#undef CREATE_VPTE_OFFSET2
+#undef CREATE_VPTE_NOP
diff -u --recursive --new-file v2.4.9/linux/arch/sparc64/kernel/pci_iommu.c linux/arch/sparc64/kernel/pci_iommu.c
--- v2.4.9/linux/arch/sparc64/kernel/pci_iommu.c	Thu May 24 15:00:58 2001
+++ linux/arch/sparc64/kernel/pci_iommu.c	Tue Aug 28 07:09:44 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_iommu.c,v 1.14 2001/05/23 03:06:51 davem Exp $
+/* $Id: pci_iommu.c,v 1.15 2001/08/24 19:36:58 kanoj Exp $
  * pci_iommu.c: UltraSparc PCI controller IOM/STC support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -121,7 +121,7 @@
 	while ((1UL << cnum) < npages)
 		cnum++;
 
-	ent = (base << (32 - PAGE_SHIFT + PBM_LOGCLUSTERS - iommu->page_table_sz_bits))
+	ent = (base << (32 - IO_PAGE_SHIFT + PBM_LOGCLUSTERS - iommu->page_table_sz_bits))
 		>> (32 + PBM_LOGCLUSTERS + cnum - iommu->page_table_sz_bits);
 
 	/* If the global flush might not have caught this entry,
@@ -184,7 +184,7 @@
 	void *ret;
 	int npages;
 
-	size = PAGE_ALIGN(size);
+	size = IO_PAGE_ALIGN(size);
 	order = get_order(size);
 	if (order >= 10)
 		return NULL;
@@ -198,7 +198,7 @@
 	iommu = pcp->pbm->iommu;
 
 	spin_lock_irqsave(&iommu->lock, flags);
-	iopte = alloc_consistent_cluster(iommu, size >> PAGE_SHIFT);
+	iopte = alloc_consistent_cluster(iommu, size >> IO_PAGE_SHIFT);
 	if (iopte == NULL) {
 		spin_unlock_irqrestore(&iommu->lock, flags);
 		free_pages(first_page, order);
@@ -206,9 +206,9 @@
 	}
 
 	*dma_addrp = (iommu->page_table_map_base +
-		      ((iopte - iommu->page_table) << PAGE_SHIFT));
+		      ((iopte - iommu->page_table) << IO_PAGE_SHIFT));
 	ret = (void *) first_page;
-	npages = size >> PAGE_SHIFT;
+	npages = size >> IO_PAGE_SHIFT;
 	ctx = 0;
 	if (iommu->iommu_ctxflush)
 		ctx = iommu->iommu_cur_ctx++;
@@ -218,17 +218,17 @@
 				     IOPTE_WRITE |
 				     (first_page & IOPTE_PAGE));
 		iopte++;
-		first_page += PAGE_SIZE;
+		first_page += IO_PAGE_SIZE;
 	}
 
 	{
 		int i;
 		u32 daddr = *dma_addrp;
 
-		npages = size >> PAGE_SHIFT;
+		npages = size >> IO_PAGE_SHIFT;
 		for (i = 0; i < npages; i++) {
 			pci_iommu_write(iommu->iommu_flush, daddr);
-			daddr += PAGE_SIZE;
+			daddr += IO_PAGE_SIZE;
 		}
 	}
 
@@ -245,11 +245,11 @@
 	iopte_t *iopte;
 	unsigned long flags, order, npages, i, ctx;
 
-	npages = PAGE_ALIGN(size) >> PAGE_SHIFT;
+	npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT;
 	pcp = pdev->sysdata;
 	iommu = pcp->pbm->iommu;
 	iopte = iommu->page_table +
-		((dvma - iommu->page_table_map_base) >> PAGE_SHIFT);
+		((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
 
 	spin_lock_irqsave(&iommu->lock, flags);
 
@@ -286,7 +286,7 @@
 		pci_iommu_write(iommu->iommu_ctxflush, ctx);
 	} else {
 		for (i = 0; i < npages; i++) {
-			u32 daddr = dvma + (i << PAGE_SHIFT);
+			u32 daddr = dvma + (i << IO_PAGE_SHIFT);
 
 			pci_iommu_write(iommu->iommu_flush, daddr);
 		}
@@ -321,8 +321,8 @@
 		BUG();
 
 	oaddr = (unsigned long)ptr;
-	npages = PAGE_ALIGN(oaddr + sz) - (oaddr & PAGE_MASK);
-	npages >>= PAGE_SHIFT;
+	npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK);
+	npages >>= IO_PAGE_SHIFT;
 
 	spin_lock_irqsave(&iommu->lock, flags);
 
@@ -330,9 +330,9 @@
 	if (base == NULL)
 		goto bad;
 	bus_addr = (iommu->page_table_map_base +
-		    ((base - iommu->page_table) << PAGE_SHIFT));
-	ret = bus_addr | (oaddr & ~PAGE_MASK);
-	base_paddr = __pa(oaddr & PAGE_MASK);
+		    ((base - iommu->page_table) << IO_PAGE_SHIFT));
+	ret = bus_addr | (oaddr & ~IO_PAGE_MASK);
+	base_paddr = __pa(oaddr & IO_PAGE_MASK);
 	ctx = 0;
 	if (iommu->iommu_ctxflush)
 		ctx = iommu->iommu_cur_ctx++;
@@ -343,7 +343,7 @@
 	if (direction != PCI_DMA_TODEVICE)
 		iopte_protection |= IOPTE_WRITE;
 
-	for (i = 0; i < npages; i++, base++, base_paddr += PAGE_SIZE)
+	for (i = 0; i < npages; i++, base++, base_paddr += IO_PAGE_SIZE)
 		iopte_val(*base) = iopte_protection | base_paddr;
 
 	spin_unlock_irqrestore(&iommu->lock, flags);
@@ -372,15 +372,15 @@
 	iommu = pcp->pbm->iommu;
 	strbuf = &pcp->pbm->stc;
 
-	npages = PAGE_ALIGN(bus_addr + sz) - (bus_addr & PAGE_MASK);
-	npages >>= PAGE_SHIFT;
+	npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK);
+	npages >>= IO_PAGE_SHIFT;
 	base = iommu->page_table +
-		((bus_addr - iommu->page_table_map_base) >> PAGE_SHIFT);
+		((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
 #ifdef DEBUG_PCI_IOMMU
 	if (iopte_val(*base) == IOPTE_INVALID)
 		printk("pci_unmap_single called on non-mapped region %08x,%08x from %016lx\n", bus_addr, sz, __builtin_return_address(0));
 #endif
-	bus_addr &= PAGE_MASK;
+	bus_addr &= IO_PAGE_MASK;
 
 	spin_lock_irqsave(&iommu->lock, flags);
 
@@ -404,7 +404,7 @@
 				pci_iommu_write(flushreg, ctx);
 			} while(((long)pci_iommu_read(matchreg)) < 0L);
 		} else {
-			for (i = 0; i < npages; i++, vaddr += PAGE_SIZE)
+			for (i = 0; i < npages; i++, vaddr += IO_PAGE_SIZE)
 				pci_iommu_write(strbuf->strbuf_pflush, vaddr);
 		}
 
@@ -432,9 +432,9 @@
 		unsigned long pteval = ~0UL;
 		u32 dma_npages;
 
-		dma_npages = ((dma_sg->dvma_address & (PAGE_SIZE - 1UL)) +
+		dma_npages = ((dma_sg->dvma_address & (IO_PAGE_SIZE - 1UL)) +
 			      dma_sg->dvma_length +
-			      ((u32)(PAGE_SIZE - 1UL))) >> PAGE_SHIFT;
+			      ((u32)(IO_PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT;
 		do {
 			unsigned long offset;
 			signed int len;
@@ -449,15 +449,15 @@
 
 				tmp = (unsigned long) __pa(sg->address);
 				len = sg->length;
-				if (((tmp ^ pteval) >> PAGE_SHIFT) != 0UL) {
-					pteval = tmp & PAGE_MASK;
-					offset = tmp & (PAGE_SIZE - 1UL);
+				if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) {
+					pteval = tmp & IO_PAGE_MASK;
+					offset = tmp & (IO_PAGE_SIZE - 1UL);
 					break;
 				}
-				if (((tmp ^ (tmp + len - 1UL)) >> PAGE_SHIFT) != 0UL) {
-					pteval = (tmp + PAGE_SIZE) & PAGE_MASK;
+				if (((tmp ^ (tmp + len - 1UL)) >> IO_PAGE_SHIFT) != 0UL) {
+					pteval = (tmp + IO_PAGE_SIZE) & IO_PAGE_MASK;
 					offset = 0UL;
-					len -= (PAGE_SIZE - (tmp & (PAGE_SIZE - 1UL)));
+					len -= (IO_PAGE_SIZE - (tmp & (IO_PAGE_SIZE - 1UL)));
 					break;
 				}
 				sg++;
@@ -466,8 +466,8 @@
 			pteval = iopte_protection | (pteval & IOPTE_PAGE);
 			while (len > 0) {
 				*iopte++ = __iopte(pteval);
-				pteval += PAGE_SIZE;
-				len -= (PAGE_SIZE - offset);
+				pteval += IO_PAGE_SIZE;
+				len -= (IO_PAGE_SIZE - offset);
 				offset = 0;
 				dma_npages--;
 			}
@@ -479,14 +479,14 @@
 			 * adjusting pteval along the way.  Stop when we
 			 * detect a page crossing event.
 			 */
-			while ((pteval << (64 - PAGE_SHIFT)) != 0UL &&
+			while ((pteval << (64 - IO_PAGE_SHIFT)) != 0UL &&
 			       pteval == __pa(sg->address) &&
 			       ((pteval ^
-				 (__pa(sg->address) + sg->length - 1UL)) >> PAGE_SHIFT) == 0UL) {
+				 (__pa(sg->address) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) {
 				pteval += sg->length;
 				sg++;
 			}
-			if ((pteval << (64 - PAGE_SHIFT)) == 0UL)
+			if ((pteval << (64 - IO_PAGE_SHIFT)) == 0UL)
 				pteval = ~0UL;
 		} while (dma_npages != 0);
 		dma_sg++;
@@ -534,7 +534,7 @@
 	base = alloc_streaming_cluster(iommu, npages);
 	if (base == NULL)
 		goto bad;
-	dma_base = iommu->page_table_map_base + ((base - iommu->page_table) << PAGE_SHIFT);
+	dma_base = iommu->page_table_map_base + ((base - iommu->page_table) << IO_PAGE_SHIFT);
 
 	/* Step 3: Normalize DMA addresses. */
 	used = nelems;
@@ -591,16 +591,16 @@
 	iommu = pcp->pbm->iommu;
 	strbuf = &pcp->pbm->stc;
 	
-	bus_addr = sglist->dvma_address & PAGE_MASK;
+	bus_addr = sglist->dvma_address & IO_PAGE_MASK;
 
 	for (i = 1; i < nelems; i++)
 		if (sglist[i].dvma_length == 0)
 			break;
 	i--;
-	npages = (PAGE_ALIGN(sglist[i].dvma_address + sglist[i].dvma_length) - bus_addr) >> PAGE_SHIFT;
+	npages = (IO_PAGE_ALIGN(sglist[i].dvma_address + sglist[i].dvma_length) - bus_addr) >> IO_PAGE_SHIFT;
 
 	base = iommu->page_table +
-		((bus_addr - iommu->page_table_map_base) >> PAGE_SHIFT);
+		((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
 
 #ifdef DEBUG_PCI_IOMMU
 	if (iopte_val(*base) == IOPTE_INVALID)
@@ -629,7 +629,7 @@
 				pci_iommu_write(flushreg, ctx);
 			} while(((long)pci_iommu_read(matchreg)) < 0L);
 		} else {
-			for (i = 0; i < npages; i++, vaddr += PAGE_SIZE)
+			for (i = 0; i < npages; i++, vaddr += IO_PAGE_SIZE)
 				pci_iommu_write(strbuf->strbuf_pflush, vaddr);
 		}
 
@@ -667,9 +667,9 @@
 
 	spin_lock_irqsave(&iommu->lock, flags);
 
-	npages = PAGE_ALIGN(bus_addr + sz) - (bus_addr & PAGE_MASK);
-	npages >>= PAGE_SHIFT;
-	bus_addr &= PAGE_MASK;
+	npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK);
+	npages >>= IO_PAGE_SHIFT;
+	bus_addr &= IO_PAGE_MASK;
 
 	/* Step 1: Record the context, if any. */
 	ctx = 0;
@@ -678,7 +678,7 @@
 		iopte_t *iopte;
 
 		iopte = iommu->page_table +
-			((bus_addr - iommu->page_table_map_base)>>PAGE_SHIFT);
+			((bus_addr - iommu->page_table_map_base)>>IO_PAGE_SHIFT);
 		ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL;
 	}
 
@@ -696,7 +696,7 @@
 	} else {
 		unsigned long i;
 
-		for (i = 0; i < npages; i++, bus_addr += PAGE_SIZE)
+		for (i = 0; i < npages; i++, bus_addr += IO_PAGE_SIZE)
 			pci_iommu_write(strbuf->strbuf_pflush, bus_addr);
 	}
 
@@ -735,7 +735,7 @@
 		iopte_t *iopte;
 
 		iopte = iommu->page_table +
-			((sglist[0].dvma_address - iommu->page_table_map_base) >> PAGE_SHIFT);
+			((sglist[0].dvma_address - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
 		ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL;
 	}
 
@@ -754,14 +754,14 @@
 		unsigned long i, npages;
 		u32 bus_addr;
 
-		bus_addr = sglist[0].dvma_address & PAGE_MASK;
+		bus_addr = sglist[0].dvma_address & IO_PAGE_MASK;
 
 		for(i = 1; i < nelems; i++)
 			if (!sglist[i].dvma_length)
 				break;
 		i--;
-		npages = (PAGE_ALIGN(sglist[i].dvma_address + sglist[i].dvma_length) - bus_addr) >> PAGE_SHIFT;
-		for (i = 0; i < npages; i++, bus_addr += PAGE_SIZE)
+		npages = (IO_PAGE_ALIGN(sglist[i].dvma_address + sglist[i].dvma_length) - bus_addr) >> IO_PAGE_SHIFT;
+		for (i = 0; i < npages; i++, bus_addr += IO_PAGE_SIZE)
 			pci_iommu_write(strbuf->strbuf_pflush, bus_addr);
 	}
 
diff -u --recursive --new-file v2.4.9/linux/arch/sparc64/kernel/pci_psycho.c linux/arch/sparc64/kernel/pci_psycho.c
--- v2.4.9/linux/arch/sparc64/kernel/pci_psycho.c	Mon Aug 27 12:41:40 2001
+++ linux/arch/sparc64/kernel/pci_psycho.c	Tue Aug 28 07:09:44 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_psycho.c,v 1.27 2001/08/12 13:18:23 davem Exp $
+/* $Id: pci_psycho.c,v 1.28 2001/08/24 19:36:58 kanoj Exp $
  * pci_psycho.c: PSYCHO/U2P specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -18,6 +18,7 @@
 #include <asm/starfire.h>
 
 #include "pci_impl.h"
+#include "iommu_common.h"
 
 /* All PSYCHO registers are 64-bits.  The following accessor
  * routines are how they are accessed.  The REG parameter
@@ -715,12 +716,12 @@
 			       ((tag & PSYCHO_IOMMU_TAG_WRITE) ? 1 : 0),
 			       ((tag & PSYCHO_IOMMU_TAG_STREAM) ? 1 : 0),
 			       ((tag & PSYCHO_IOMMU_TAG_SIZE) ? 64 : 8),
-			       (tag & PSYCHO_IOMMU_TAG_VPAGE) << PAGE_SHIFT);
+			       (tag & PSYCHO_IOMMU_TAG_VPAGE) << IOMMU_PAGE_SHIFT);
 			printk("PSYCHO%d: IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n",
 			       p->index, i,
 			       ((data & PSYCHO_IOMMU_DATA_VALID) ? 1 : 0),
 			       ((data & PSYCHO_IOMMU_DATA_CACHE) ? 1 : 0),
-			       (data & PSYCHO_IOMMU_DATA_PPAGE) << PAGE_SHIFT);
+			       (data & PSYCHO_IOMMU_DATA_PPAGE) << IOMMU_PAGE_SHIFT);
 		}
 	}
 	__psycho_check_stc_error(p, afsr, afar, type);
@@ -1322,7 +1323,7 @@
 	 * table (128K ioptes * 8 bytes per iopte).  This is
 	 * page order 7 on UltraSparc.
 	 */
-	tsbbase = __get_free_pages(GFP_KERNEL, 7);
+	tsbbase = __get_free_pages(GFP_KERNEL, get_order(IO_TSB_SIZE));
 	if (!tsbbase) {
 		prom_printf("PSYCHO_IOMMU: Error, gfp(tsb) failed.\n");
 		prom_halt();
@@ -1331,7 +1332,7 @@
 	iommu->page_table_sz_bits = 17;
 	iommu->page_table_map_base = 0xc0000000;
 	iommu->dma_addr_mask = 0xffffffff;
-	memset((char *)tsbbase, 0, PAGE_SIZE << 7);
+	memset((char *)tsbbase, 0, IO_TSB_SIZE);
 
 	/* We start with no consistent mappings. */
 	iommu->lowest_consistent_map =
diff -u --recursive --new-file v2.4.9/linux/arch/sparc64/kernel/pci_sabre.c linux/arch/sparc64/kernel/pci_sabre.c
--- v2.4.9/linux/arch/sparc64/kernel/pci_sabre.c	Mon Aug 27 12:41:40 2001
+++ linux/arch/sparc64/kernel/pci_sabre.c	Tue Aug 28 07:09:44 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_sabre.c,v 1.38 2001/08/12 13:18:23 davem Exp $
+/* $Id: pci_sabre.c,v 1.39 2001/08/24 19:36:58 kanoj Exp $
  * pci_sabre.c: Sabre specific PCI controller support.
  *
  * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu)
@@ -19,6 +19,7 @@
 #include <asm/smp.h>
 
 #include "pci_impl.h"
+#include "iommu_common.h"
 
 /* All SABRE registers are 64-bits.  The following accessor
  * routines are how they are accessed.  The REG parameter
@@ -759,13 +760,13 @@
 			       p->index, i, tag, type_string,
 			       ((tag & SABRE_IOMMUTAG_WRITE) ? 1 : 0),
 			       ((tag & SABRE_IOMMUTAG_SIZE) ? 64 : 8),
-			       ((tag & SABRE_IOMMUTAG_VPN) << PAGE_SHIFT));
+			       ((tag & SABRE_IOMMUTAG_VPN) << IOMMU_PAGE_SHIFT));
 			printk("SABRE%d: IOMMU DATA(%d)[RAW(%016lx)valid(%d)used(%d)cache(%d)ppg(%016lx)\n",
 			       p->index, i, data,
 			       ((data & SABRE_IOMMUDATA_VALID) ? 1 : 0),
 			       ((data & SABRE_IOMMUDATA_USED) ? 1 : 0),
 			       ((data & SABRE_IOMMUDATA_CACHE) ? 1 : 0),
-			       ((data & SABRE_IOMMUDATA_PPN) << PAGE_SHIFT));
+			       ((data & SABRE_IOMMUDATA_PPN) << IOMMU_PAGE_SHIFT));
 		}
 	}
 	spin_unlock_irqrestore(&iommu->lock, flags);
diff -u --recursive --new-file v2.4.9/linux/arch/sparc64/kernel/pci_schizo.c linux/arch/sparc64/kernel/pci_schizo.c
--- v2.4.9/linux/arch/sparc64/kernel/pci_schizo.c	Mon Aug 27 12:41:40 2001
+++ linux/arch/sparc64/kernel/pci_schizo.c	Tue Aug 28 07:09:44 2001
@@ -1,4 +1,4 @@
-/* $Id: pci_schizo.c,v 1.20 2001/08/12 13:18:23 davem Exp $
+/* $Id: pci_schizo.c,v 1.21 2001/08/24 19:36:58 kanoj Exp $
  * pci_schizo.c: SCHIZO specific PCI controller support.
  *
  * Copyright (C) 2001 David S. Miller (davem@redhat.com)
@@ -16,6 +16,7 @@
 #include <asm/upa.h>
 
 #include "pci_impl.h"
+#include "iommu_common.h"
 
 /* All SCHIZO registers are 64-bits.  The following accessor
  * routines are how they are accessed.  The REG parameter
@@ -659,12 +660,12 @@
 			       ((tag & SCHIZO_IOMMU_TAG_WRITE) ? 1 : 0),
 			       ((tag & SCHIZO_IOMMU_TAG_STREAM) ? 1 : 0),
 			       ((tag & SCHIZO_IOMMU_TAG_SIZE) ? 64 : 8),
-			       (tag & SCHIZO_IOMMU_TAG_VPAGE) << PAGE_SHIFT);
+			       (tag & SCHIZO_IOMMU_TAG_VPAGE) << IOMMU_PAGE_SHIFT);
 			printk("SCHIZO%d: PBM-%c IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n",
 			       p->index, pbm_name, i,
 			       ((data & SCHIZO_IOMMU_DATA_VALID) ? 1 : 0),
 			       ((data & SCHIZO_IOMMU_DATA_CACHE) ? 1 : 0),
-			       (data & SCHIZO_IOMMU_DATA_PPAGE) << PAGE_SHIFT);
+			       (data & SCHIZO_IOMMU_DATA_PPAGE) << IOMMU_PAGE_SHIFT);
 		}
 	}
 	__schizo_check_stc_error_pbm(pbm, type);
@@ -1639,7 +1640,7 @@
 	 * table (128K ioptes * 8 bytes per iopte).  This is
 	 * page order 7 on UltraSparc.
 	 */
-	tsbbase = __get_free_pages(GFP_KERNEL, 7);
+	tsbbase = __get_free_pages(GFP_KERNEL, get_order(IO_TSB_SIZE));
 	if (!tsbbase) {
 		prom_printf("SCHIZO_IOMMU: Error, gfp(tsb) failed.\n");
 		prom_halt();
@@ -1648,7 +1649,7 @@
 	iommu->page_table_sz_bits = 17;
 	iommu->page_table_map_base = 0xc0000000;
 	iommu->dma_addr_mask = 0xffffffff;
-	memset((char *)tsbbase, 0, PAGE_SIZE << 7);
+	memset((char *)tsbbase, 0, IO_TSB_SIZE);
 
 	/* We start with no consistent mappings. */
 	iommu->lowest_consistent_map =
diff -u --recursive --new-file v2.4.9/linux/arch/sparc64/kernel/sbus.c linux/arch/sparc64/kernel/sbus.c
--- v2.4.9/linux/arch/sparc64/kernel/sbus.c	Thu May 24 15:00:58 2001
+++ linux/arch/sparc64/kernel/sbus.c	Tue Aug 28 07:09:44 2001
@@ -1,4 +1,4 @@
-/* $Id: sbus.c,v 1.14 2001/05/23 03:06:51 davem Exp $
+/* $Id: sbus.c,v 1.16 2001/08/24 19:36:58 kanoj Exp $
  * sbus.c: UltraSparc SBUS controller support.
  *
  * Copyright (C) 1999 David S. Miller (davem@redhat.com)
@@ -37,7 +37,7 @@
 #define ONE_GIG		(1UL * 1024UL * 1024UL * 1024UL)
 #define CLUSTER_SIZE	(ONE_GIG / NCLUSTERS)
 #define CLUSTER_MASK	(CLUSTER_SIZE - 1)
-#define CLUSTER_NPAGES	(CLUSTER_SIZE >> PAGE_SHIFT)
+#define CLUSTER_NPAGES	(CLUSTER_SIZE >> IO_PAGE_SHIFT)
 #define MAP_BASE	((u32)0xc0000000)
 
 struct sbus_iommu {
@@ -99,7 +99,7 @@
 static void iommu_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages)
 {
 	while (npages--)
-		upa_writeq(base + (npages << PAGE_SHIFT),
+		upa_writeq(base + (npages << IO_PAGE_SHIFT),
 			   iommu->iommu_regs + IOMMU_FLUSH);
 	upa_readq(iommu->sbus_control_reg);
 }
@@ -120,7 +120,7 @@
 {
 	iommu->strbuf_flushflag = 0UL;
 	while (npages--)
-		upa_writeq(base + (npages << PAGE_SHIFT),
+		upa_writeq(base + (npages << IO_PAGE_SHIFT),
 			   iommu->strbuf_regs + STRBUF_PFLUSH);
 
 	/* Whoopee cushion! */
@@ -191,8 +191,8 @@
 	cnum = 0;
 	while ((1UL << cnum) < npages)
 		cnum++;
-	ent = (base & CLUSTER_MASK) >> (PAGE_SHIFT + cnum);
-	iopte = iommu->page_table + ((base - MAP_BASE) >> PAGE_SHIFT);
+	ent = (base & CLUSTER_MASK) >> (IO_PAGE_SHIFT + cnum);
+	iopte = iommu->page_table + ((base - MAP_BASE) >> IO_PAGE_SHIFT);
 	iopte_val(*iopte) = 0UL;
 
 	/* If the global flush might not have caught this entry,
@@ -235,7 +235,7 @@
 
 static void free_consistent_cluster(struct sbus_iommu *iommu, u32 base, unsigned long npages)
 {
-	iopte_t *iopte = iommu->page_table + ((base - MAP_BASE) >> PAGE_SHIFT);
+	iopte_t *iopte = iommu->page_table + ((base - MAP_BASE) >> IO_PAGE_SHIFT);
 
 	if ((iopte - iommu->page_table) == iommu->lowest_consistent_map) {
 		iopte_t *walk = iopte + npages;
@@ -266,7 +266,7 @@
 	if (size <= 0 || sdev == NULL || dvma_addr == NULL)
 		return NULL;
 
-	size = PAGE_ALIGN(size);
+	size = IO_PAGE_ALIGN(size);
 	order = get_order(size);
 	if (order >= 10)
 		return NULL;
@@ -278,7 +278,7 @@
 	iommu = sdev->bus->iommu;
 
 	spin_lock_irqsave(&iommu->lock, flags);
-	iopte = alloc_consistent_cluster(iommu, size >> PAGE_SHIFT);
+	iopte = alloc_consistent_cluster(iommu, size >> IO_PAGE_SHIFT);
 	if (iopte == NULL) {
 		spin_unlock_irqrestore(&iommu->lock, flags);
 		free_pages(first_page, order);
@@ -286,15 +286,15 @@
 	}
 
 	/* Ok, we're committed at this point. */
-	*dvma_addr = MAP_BASE +	((iopte - iommu->page_table) << PAGE_SHIFT);
+	*dvma_addr = MAP_BASE +	((iopte - iommu->page_table) << IO_PAGE_SHIFT);
 	ret = (void *) first_page;
-	npages = size >> PAGE_SHIFT;
+	npages = size >> IO_PAGE_SHIFT;
 	while (npages--) {
 		*iopte++ = __iopte(IOPTE_VALID | IOPTE_CACHE | IOPTE_WRITE |
 				   (__pa(first_page) & IOPTE_PAGE));
-		first_page += PAGE_SIZE;
+		first_page += IO_PAGE_SIZE;
 	}
-	iommu_flush(iommu, *dvma_addr, size >> PAGE_SHIFT);
+	iommu_flush(iommu, *dvma_addr, size >> IO_PAGE_SHIFT);
 	spin_unlock_irqrestore(&iommu->lock, flags);
 
 	return ret;
@@ -308,7 +308,7 @@
 	if (size <= 0 || sdev == NULL || cpu == NULL)
 		return;
 
-	npages = PAGE_ALIGN(size) >> PAGE_SHIFT;
+	npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT;
 	iommu = sdev->bus->iommu;
 
 	spin_lock_irq(&iommu->lock);
@@ -333,25 +333,25 @@
 		BUG();
 
 	pbase = (unsigned long) ptr;
-	offset = (u32) (pbase & ~PAGE_MASK);
-	size = (PAGE_ALIGN(pbase + size) - (pbase & PAGE_MASK));
-	pbase = (unsigned long) __pa(pbase & PAGE_MASK);
+	offset = (u32) (pbase & ~IO_PAGE_MASK);
+	size = (IO_PAGE_ALIGN(pbase + size) - (pbase & IO_PAGE_MASK));
+	pbase = (unsigned long) __pa(pbase & IO_PAGE_MASK);
 
 	spin_lock_irqsave(&iommu->lock, flags);
-	npages = size >> PAGE_SHIFT;
+	npages = size >> IO_PAGE_SHIFT;
 	iopte = alloc_streaming_cluster(iommu, npages);
 	if (iopte == NULL)
 		goto bad;
-	dma_base = MAP_BASE + ((iopte - iommu->page_table) << PAGE_SHIFT);
-	npages = size >> PAGE_SHIFT;
+	dma_base = MAP_BASE + ((iopte - iommu->page_table) << IO_PAGE_SHIFT);
+	npages = size >> IO_PAGE_SHIFT;
 	iopte_bits = IOPTE_VALID | IOPTE_STBUF | IOPTE_CACHE;
 	if (dir != SBUS_DMA_TODEVICE)
 		iopte_bits |= IOPTE_WRITE;
 	while (npages--) {
 		*iopte++ = __iopte(iopte_bits | (pbase & IOPTE_PAGE));
-		pbase += PAGE_SIZE;
+		pbase += IO_PAGE_SIZE;
 	}
-	npages = size >> PAGE_SHIFT;
+	npages = size >> IO_PAGE_SHIFT;
 	spin_unlock_irqrestore(&iommu->lock, flags);
 
 	return (dma_base | offset);
@@ -365,14 +365,14 @@
 void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t dma_addr, size_t size, int direction)
 {
 	struct sbus_iommu *iommu = sdev->bus->iommu;
-	u32 dma_base = dma_addr & PAGE_MASK;
+	u32 dma_base = dma_addr & IO_PAGE_MASK;
 	unsigned long flags;
 
-	size = (PAGE_ALIGN(dma_addr + size) - dma_base);
+	size = (IO_PAGE_ALIGN(dma_addr + size) - dma_base);
 
 	spin_lock_irqsave(&iommu->lock, flags);
-	free_streaming_cluster(iommu, dma_base, size >> PAGE_SHIFT);
-	strbuf_flush(iommu, dma_base, size >> PAGE_SHIFT);
+	free_streaming_cluster(iommu, dma_base, size >> IO_PAGE_SHIFT);
+	strbuf_flush(iommu, dma_base, size >> IO_PAGE_SHIFT);
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
@@ -385,9 +385,9 @@
 		unsigned long pteval = ~0UL;
 		u32 dma_npages;
 
-		dma_npages = ((dma_sg->dvma_address & (PAGE_SIZE - 1UL)) +
+		dma_npages = ((dma_sg->dvma_address & (IO_PAGE_SIZE - 1UL)) +
 			      dma_sg->dvma_length +
-			      ((u32)(PAGE_SIZE - 1UL))) >> PAGE_SHIFT;
+			      ((u32)(IO_PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT;
 		do {
 			unsigned long offset;
 			signed int len;
@@ -402,15 +402,15 @@
 
 				tmp = (unsigned long) __pa(sg->address);
 				len = sg->length;
-				if (((tmp ^ pteval) >> PAGE_SHIFT) != 0UL) {
-					pteval = tmp & PAGE_MASK;
-					offset = tmp & (PAGE_SIZE - 1UL);
+				if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) {
+					pteval = tmp & IO_PAGE_MASK;
+					offset = tmp & (IO_PAGE_SIZE - 1UL);
 					break;
 				}
-				if (((tmp ^ (tmp + len - 1UL)) >> PAGE_SHIFT) != 0UL) {
-					pteval = (tmp + PAGE_SIZE) & PAGE_MASK;
+				if (((tmp ^ (tmp + len - 1UL)) >> IO_PAGE_SHIFT) != 0UL) {
+					pteval = (tmp + IO_PAGE_SIZE) & IO_PAGE_MASK;
 					offset = 0UL;
-					len -= (PAGE_SIZE - (tmp & (PAGE_SIZE - 1UL)));
+					len -= (IO_PAGE_SIZE - (tmp & (IO_PAGE_SIZE - 1UL)));
 					break;
 				}
 				sg++;
@@ -419,8 +419,8 @@
 			pteval = ((pteval & IOPTE_PAGE) | iopte_bits);
 			while (len > 0) {
 				*iopte++ = __iopte(pteval);
-				pteval += PAGE_SIZE;
-				len -= (PAGE_SIZE - offset);
+				pteval += IO_PAGE_SIZE;
+				len -= (IO_PAGE_SIZE - offset);
 				offset = 0;
 				dma_npages--;
 			}
@@ -432,14 +432,14 @@
 			 * adjusting pteval along the way.  Stop when we
 			 * detect a page crossing event.
 			 */
-			while ((pteval << (64 - PAGE_SHIFT)) != 0UL &&
+			while ((pteval << (64 - IO_PAGE_SHIFT)) != 0UL &&
 			       pteval == __pa(sg->address) &&
 			       ((pteval ^
-				 (__pa(sg->address) + sg->length - 1UL)) >> PAGE_SHIFT) == 0UL) {
+				 (__pa(sg->address) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) {
 				pteval += sg->length;
 				sg++;
 			}
-			if ((pteval << (64 - PAGE_SHIFT)) == 0UL)
+			if ((pteval << (64 - IO_PAGE_SHIFT)) == 0UL)
 				pteval = ~0UL;
 		} while (dma_npages != 0);
 		dma_sg++;
@@ -472,7 +472,7 @@
 	iopte = alloc_streaming_cluster(iommu, npages);
 	if (iopte == NULL)
 		goto bad;
-	dma_base = MAP_BASE + ((iopte - iommu->page_table) << PAGE_SHIFT);
+	dma_base = MAP_BASE + ((iopte - iommu->page_table) << IO_PAGE_SHIFT);
 
 	/* Normalize DVMA addresses. */
 	sgtmp = sg;
@@ -516,18 +516,18 @@
 		return;
 	}
 
-	dvma_base = sg[0].dvma_address & PAGE_MASK;
+	dvma_base = sg[0].dvma_address & IO_PAGE_MASK;
 	for (i = 0; i < nents; i++) {
 		if (sg[i].dvma_length == 0)
 			break;
 	}
 	i--;
-	size = PAGE_ALIGN(sg[i].dvma_address + sg[i].dvma_length) - dvma_base;
+	size = IO_PAGE_ALIGN(sg[i].dvma_address + sg[i].dvma_length) - dvma_base;
 
 	iommu = sdev->bus->iommu;
 	spin_lock_irqsave(&iommu->lock, flags);
-	free_streaming_cluster(iommu, dvma_base, size >> PAGE_SHIFT);
-	strbuf_flush(iommu, dvma_base, size >> PAGE_SHIFT);
+	free_streaming_cluster(iommu, dvma_base, size >> IO_PAGE_SHIFT);
+	strbuf_flush(iommu, dvma_base, size >> IO_PAGE_SHIFT);
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
@@ -536,10 +536,10 @@
 	struct sbus_iommu *iommu = sdev->bus->iommu;
 	unsigned long flags;
 
-	size = (PAGE_ALIGN(base + size) - (base & PAGE_MASK));
+	size = (IO_PAGE_ALIGN(base + size) - (base & IO_PAGE_MASK));
 
 	spin_lock_irqsave(&iommu->lock, flags);
-	strbuf_flush(iommu, base & PAGE_MASK, size >> PAGE_SHIFT);
+	strbuf_flush(iommu, base & IO_PAGE_MASK, size >> IO_PAGE_SHIFT);
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
@@ -550,16 +550,16 @@
 	u32 base;
 	int i;
 
-	base = sg[0].dvma_address & PAGE_MASK;
+	base = sg[0].dvma_address & IO_PAGE_MASK;
 	for (i = 0; i < nents; i++) {
 		if (sg[i].dvma_length == 0)
 			break;
 	}
 	i--;
-	size = PAGE_ALIGN(sg[i].dvma_address + sg[i].dvma_length) - base;
+	size = IO_PAGE_ALIGN(sg[i].dvma_address + sg[i].dvma_length) - base;
 
 	spin_lock_irqsave(&iommu->lock, flags);
-	strbuf_flush(iommu, base, size >> PAGE_SHIFT);
+	strbuf_flush(iommu, base, size >> IO_PAGE_SHIFT);
 	spin_unlock_irqrestore(&iommu->lock, flags);
 }
 
@@ -1123,14 +1123,14 @@
 	 * table (128K ioptes * 8 bytes per iopte).  This is
 	 * page order 7 on UltraSparc.
 	 */
-	tsb_base = __get_free_pages(GFP_ATOMIC, 7);
+	tsb_base = __get_free_pages(GFP_ATOMIC, get_order(IO_TSB_SIZE));
 	if (tsb_base == 0UL) {
 		prom_printf("sbus_iommu_init: Fatal error, cannot alloc TSB table.\n");
 		prom_halt();
 	}
 
 	iommu->page_table = (iopte_t *) tsb_base;
-	memset(iommu->page_table, 0, (PAGE_SIZE << 7));
+	memset(iommu->page_table, 0, IO_TSB_SIZE);
 
 	upa_writeq(control, iommu->iommu_regs + IOMMU_CONTROL);
 
diff -u --recursive --new-file v2.4.9/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c
--- v2.4.9/linux/arch/sparc64/kernel/smp.c	Mon Aug 27 12:41:40 2001
+++ linux/arch/sparc64/kernel/smp.c	Tue Aug 28 07:09:44 2001
@@ -702,7 +702,7 @@
 		int cpu = smp_processor_id();
 
 		start &= PAGE_MASK;
-		end   &= PAGE_MASK;
+		end    = PAGE_ALIGN(end);
 
 		if (mm == current->active_mm && atomic_read(&mm->mm_users) == 1) {
 			mm->cpu_vm_mask = (1UL << cpu);
diff -u --recursive --new-file v2.4.9/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c
--- v2.4.9/linux/arch/sparc64/kernel/sparc64_ksyms.c	Mon Aug 27 12:41:40 2001
+++ linux/arch/sparc64/kernel/sparc64_ksyms.c	Tue Aug 28 07:09:44 2001
@@ -1,4 +1,4 @@
-/* $Id: sparc64_ksyms.c,v 1.108 2001/06/05 03:39:50 davem Exp $
+/* $Id: sparc64_ksyms.c,v 1.110 2001/08/18 08:08:13 davem Exp $
  * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -163,7 +163,9 @@
 /* Atomic counter implementation. */
 EXPORT_SYMBOL(__atomic_add);
 EXPORT_SYMBOL(__atomic_sub);
+#ifdef CONFIG_SMP
 EXPORT_SYMBOL(atomic_dec_and_lock);
+#endif
 
 /* Atomic bit operations. */
 EXPORT_SYMBOL(___test_and_set_bit);
diff -u --recursive --new-file v2.4.9/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c
--- v2.4.9/linux/arch/sparc64/mm/fault.c	Mon Aug 27 12:41:40 2001
+++ linux/arch/sparc64/mm/fault.c	Tue Aug 28 07:09:44 2001
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.55 2001/08/09 20:18:43 davem Exp $
+/* $Id: fault.c,v 1.56 2001/08/27 18:42:07 kanoj Exp $
  * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -26,6 +26,16 @@
 #define ELEMENTS(arr) (sizeof (arr)/sizeof (arr[0]))
 
 extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
+
+void syscall_trace_entry(struct pt_regs *regs)
+{
+	printk("scall entry: %s[%d]/cpu%d: %d\n", current->comm, current->pid, smp_processor_id(), (int) regs->u_regs[UREG_G1]);
+}
+
+void syscall_trace_exit(struct pt_regs *regs)
+{
+	printk("scall exit: %s[%d]/cpu%d: %d\n", current->comm, current->pid, smp_processor_id(), (int) regs->u_regs[UREG_G1]);
+}
 
 /* Nice, simple, prom library does all the sweating for us. ;) */
 unsigned long __init prom_probe_memory (void)
diff -u --recursive --new-file v2.4.9/linux/arch/sparc64/mm/init.c linux/arch/sparc64/mm/init.c
--- v2.4.9/linux/arch/sparc64/mm/init.c	Mon Aug 27 12:41:40 2001
+++ linux/arch/sparc64/mm/init.c	Tue Aug 28 07:09:44 2001
@@ -1,4 +1,4 @@
-/*  $Id: init.c,v 1.179 2001/08/08 07:52:00 davem Exp $
+/*  $Id: init.c,v 1.186 2001/08/23 05:14:57 kanoj Exp $
  *  arch/sparc64/mm/init.c
  *
  *  Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu)
@@ -27,7 +27,6 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
-#include <asm/vaddrs.h>
 #include <asm/dma.h>
 #include <asm/starfire.h>
 
@@ -202,10 +201,10 @@
 	struct linux_prom_translation *trans;
 	unsigned long phys_page, tte_vaddr, tte_data;
 	void (*remap_func)(unsigned long, unsigned long, int);
-	pgd_t *pgdp;
-	pmd_t *pmdp;
+	pmd_t *pmdp, *pmd;
 	pte_t *ptep;
 	int node, n, i, tsz;
+	extern unsigned int obp_iaddr_patch[2], obp_daddr_patch[2];
 
 	node = prom_finddevice("/virtual-memory");
 	n = prom_getproplen(node, "translations");
@@ -229,36 +228,39 @@
 	}
 	n = n / sizeof(*trans);
 
+	/*
+	 * The obp translations are saved based on 8k pagesize, since obp can use
+	 * a mixture of pagesizes. Misses to the 0xf0000000 - 0x100000000, ie obp 
+	 * range, are handled in entry.S and do not use the vpte scheme (see rant
+	 * in inherit_locked_prom_mappings()).
+	 */
+#define OBP_PMD_SIZE 2048
+#define BASE_PAGE_SIZE 8192
+	pmd = __alloc_bootmem(OBP_PMD_SIZE, OBP_PMD_SIZE, 0UL);
+	if (pmd == NULL)
+		early_pgtable_allocfail("pmd");
+	memset(pmd, 0, OBP_PMD_SIZE);
 	for (i = 0; i < n; i++) {
 		unsigned long vaddr;
 
 		if (trans[i].virt >= 0xf0000000 && trans[i].virt < 0x100000000) {
 			for (vaddr = trans[i].virt;
 			     vaddr < trans[i].virt + trans[i].size;
-			     vaddr += PAGE_SIZE) {
+			     vaddr += BASE_PAGE_SIZE) {
 				unsigned long val;
 
-				pgdp = pgd_offset(&init_mm, vaddr);
-				if (pgd_none(*pgdp)) {
-					pmdp = __alloc_bootmem(PMD_TABLE_SIZE,
-							       PMD_TABLE_SIZE,
-							       0UL);
-					if (pmdp == NULL)
-						early_pgtable_allocfail("pmd");
-					memset(pmdp, 0, PMD_TABLE_SIZE);
-					pgd_set(pgdp, pmdp);
-				}
-				pmdp = pmd_offset(pgdp, vaddr);
+				pmdp = pmd + ((vaddr >> 23) & 0x7ff);
 				if (pmd_none(*pmdp)) {
-					ptep = __alloc_bootmem(PTE_TABLE_SIZE,
-							       PTE_TABLE_SIZE,
+					ptep = __alloc_bootmem(BASE_PAGE_SIZE,
+							       BASE_PAGE_SIZE,
 							       0UL);
 					if (ptep == NULL)
 						early_pgtable_allocfail("pte");
-					memset(ptep, 0, PTE_TABLE_SIZE);
+					memset(ptep, 0, BASE_PAGE_SIZE);
 					pmd_set(pmdp, ptep);
 				}
-				ptep = pte_offset(pmdp, vaddr);
+				ptep = (pte_t *)pmd_page(*pmdp) +
+						((vaddr >> 13) & 0x3ff);
 
 				val = trans[i].data;
 
@@ -267,10 +269,17 @@
 					val &= ~0x0003fe0000000000UL;
 
 				set_pte (ptep, __pte(val | _PAGE_MODIFIED));
-				trans[i].data += PAGE_SIZE;
+				trans[i].data += BASE_PAGE_SIZE;
 			}
 		}
 	}
+	phys_page = __pa(pmd);
+	obp_iaddr_patch[0] |= (phys_page >> 10);
+	obp_iaddr_patch[1] |= (phys_page & 0x3ff);
+	flushi((long)&obp_iaddr_patch[0]);
+	obp_daddr_patch[0] |= (phys_page >> 10);
+	obp_daddr_patch[1] |= (phys_page & 0x3ff);
+	flushi((long)&obp_daddr_patch[0]);
 
 	/* Now fixup OBP's idea about where we really are mapped. */
 	prom_printf("Remapping the kernel... ");
diff -u --recursive --new-file v2.4.9/linux/arch/sparc64/mm/modutil.c linux/arch/sparc64/mm/modutil.c
--- v2.4.9/linux/arch/sparc64/mm/modutil.c	Thu Apr 12 12:10:25 2001
+++ linux/arch/sparc64/mm/modutil.c	Tue Aug 28 07:09:44 2001
@@ -1,4 +1,4 @@
-/*  $Id: modutil.c,v 1.8 2001/04/04 00:49:39 davem Exp $
+/*  $Id: modutil.c,v 1.9 2001/08/14 22:10:56 davem Exp $
  *  arch/sparc64/mm/modutil.c
  *
  *  Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -10,7 +10,10 @@
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
-#include <asm/vaddrs.h>
+
+#define  MODULES_VADDR	0x0000000001000000ULL  /* Where to map modules */
+#define  MODULES_LEN	0x000000007f000000ULL
+#define  MODULES_END	0x0000000080000000ULL
 
 static struct vm_struct * modvmlist = NULL;
 
diff -u --recursive --new-file v2.4.9/linux/drivers/atm/Makefile linux/drivers/atm/Makefile
--- v2.4.9/linux/drivers/atm/Makefile	Mon Mar 26 15:36:30 2001
+++ linux/drivers/atm/Makefile	Mon Aug 27 09:01:33 2001
@@ -25,6 +25,7 @@
 obj-$(CONFIG_ATM_AMBASSADOR) += ambassador.o
 obj-$(CONFIG_ATM_TCP) += atmtcp.o
 obj-$(CONFIG_ATM_IA) += iphase.o suni.o
+obj-$(CONFIG_ATM_FIRESTREAM) += firestream.o
 
 ifeq ($(CONFIG_ATM_FORE200E_PCA),y)
   FORE200E_FW_OBJS += fore200e_pca_fw.o
diff -u --recursive --new-file v2.4.9/linux/drivers/atm/firestream.c linux/drivers/atm/firestream.c
--- v2.4.9/linux/drivers/atm/firestream.c	Wed Apr 11 19:02:30 2001
+++ linux/drivers/atm/firestream.c	Mon Aug 27 09:01:33 2001
@@ -295,6 +295,7 @@
 
 
 static int fs_keystream = 0;
+static int fs_maxphy = 1;
 
 #ifdef DEBUG
 /* I didn't forget to set this to zero before shipping. Hit me with a stick 
@@ -308,6 +309,7 @@
 #ifdef DEBUG 
 MODULE_PARM(fs_debug, "i");
 #endif
+MODULE_PARM(fs_maxphy, "i");
 MODULE_PARM(loopback, "i");
 MODULE_PARM(num, "i");
 MODULE_PARM(fs_keystream, "i");
@@ -866,6 +868,7 @@
 	int bfp;
 	int to;
 	unsigned short tmc0;
+	int uaddr;
 
 	func_enter ();
 
@@ -908,6 +911,9 @@
 	txtp = &atm_vcc->qos.txtp;
 	rxtp = &atm_vcc->qos.rxtp;
 
+	/* XXX Use VPI? How many bits? Which bits? */
+	uaddr = atm_vcc->dev->number - dev->start_number;
+
 	if (!test_bit(ATM_VF_PARTIAL, &atm_vcc->flags)) {
 		if (IS_FS50(dev)) {
 			/* Increment the channel numer: take a free one next time.  */
@@ -1012,7 +1018,7 @@
 		tc->TMC[2] = 0; /* Unused */
 		tc->TMC[3] = 0; /* Unused */
     
-		tc->spec = 0;    /* UTOPIA address, UDF, HEC: Unused -> 0 */
+		tc->spec = uaddr << 16;  /* UTOPIA address, UDF, HEC: Unused -> 0 */
 		tc->rtag[0] = 0; /* What should I do with routing tags??? 
 				    -- Not used -- AS -- Thanks -- REW*/
 		tc->rtag[1] = 0;
@@ -1081,7 +1087,7 @@
 			submit_command (dev, &dev->hp_txq, 
 					QE_CMD_REG_WR | QE_CMD_IMM_INQ,
 					0x80 + vcc->channo,
-					(vpi << 16) | vci, 0 ); /* XXX -- Use defines. */
+					(uaddr << 28) | (vpi << 16) | vci, 0 ); /* XXX -- Use defines. */
 		}
 		submit_command (dev, &dev->hp_txq, 
 				QE_CMD_RX_EN | QE_CMD_IMM_INQ | vcc->channo,
@@ -1772,8 +1778,10 @@
 
 	if (IS_FS50 (dev)) {
 		write_fs (dev, RAS0, RAS0_DCD_XHLT);
-		dev->atm_dev->ci_range.vpi_bits = 12;
-		dev->atm_dev->ci_range.vci_bits = 16;
+		for (i=0;i<fs_maxphy;i++) {
+			dev->atm_dev[i]->ci_range.vpi_bits = 12;
+			dev->atm_dev[i]->ci_range.vci_bits = 16;
+		}
 		dev->nchannels = FS50_NR_CHANNELS;
 	} else {
 		write_fs (dev, RAS0, RAS0_DCD_XHLT 
@@ -1781,8 +1789,10 @@
 			  | (((1 << FS155_VCI_BITS) - 1) * RAS0_VCSEL));
 		/* We can chose the split arbitarily. We might be able to 
 		   support more. Whatever. This should do for now. */
-		dev->atm_dev->ci_range.vpi_bits = FS155_VPI_BITS;
-		dev->atm_dev->ci_range.vci_bits = FS155_VCI_BITS;
+		for (i=0;i<fs_maxphy;i++) {
+			dev->atm_dev[i]->ci_range.vpi_bits = FS155_VPI_BITS;
+			dev->atm_dev[i]->ci_range.vci_bits = FS155_VCI_BITS;
+		}
     
 		/* Address bits we can't use should be compared to 0. */
 		write_fs (dev, RAC, 0);
@@ -1817,9 +1827,14 @@
 	}
 	memset (dev->tx_inuse, 0, dev->nchannels / 8);
 
-	/* -- RAS1 : FS155 and 50 differ. Default (0) should be OK for both */
-	/* -- RAS2 : FS50 only: Default is OK. */
+	if (IS_FS50 (dev)) {
+		/* -- RAS1 : FS155 and 50 differ. Default (0) should be OK for FS155, FS50/multiphy needs the maxPHY set... */
+		write_fs (dev, RAS1, (fs_maxphy - 1) * RAS1_UTREG);
 
+		/* -- RAS2 : FS50 only: Default is OK. */
+		/* Enable selecting for Utopia address for multiphy configs. */
+		write_fs (dev, RAS2, RAS2_USEL);
+	}
 	/* DMAMODE, default should be OK. -- REW */
 	write_fs (dev, DMAMR, DMAMR_TX_MODE_FULL);
 
@@ -1888,7 +1903,8 @@
 	add_timer (&dev->timer);
 #endif
 
-	dev->atm_dev->dev_data = dev;
+	for (i=0;i<fs_maxphy;i++)
+		dev->atm_dev[i]->dev_data = dev;
   
 	func_exit ();
 	return 0;
@@ -1897,9 +1913,9 @@
 static int __init firestream_init_one (struct pci_dev *pci_dev,
 				       const struct pci_device_id *ent) 
 {
-	struct atm_dev *atm_dev;
 	struct fs_dev *fs_dev;
-	
+	int i;
+
 	if (pci_enable_device(pci_dev)) 
 		goto err_out;
 
@@ -1910,13 +1926,17 @@
 		goto err_out;
 
 	memset (fs_dev, 0, sizeof (struct fs_dev));
-  
-	atm_dev = atm_dev_register("fs", &ops, -1, NULL);
-	if (!atm_dev)
-		goto err_out_free_fs_dev;
-  
+
+	for (i=0;i<fs_maxphy;i++) {
+		fs_dev->atm_dev[i] = atm_dev_register("fs", &ops, -1, NULL);
+		if (!fs_dev->atm_dev[i])
+			goto err_out_free_atm_dev;
+	}
+	/* XXX if another device is registering atm devices at the same time
+	   we get confusion.  */
+	fs_dev->start_number = fs_dev->atm_dev[0]->number;
+
 	fs_dev->pci_dev = pci_dev;
-	fs_dev->atm_dev = atm_dev;
 	fs_dev->flags = ent->driver_data;
 
 	if (fs_init(fs_dev))
@@ -1927,7 +1947,8 @@
 	return 0;
 
  err_out_free_atm_dev:
-	atm_dev_deregister(atm_dev);
+	for (i--;i >= 0;i--)
+		atm_dev_deregister(fs_dev->atm_dev[i]);
  err_out_free_fs_dev:
 	kfree(fs_dev);
  err_out:
@@ -2002,7 +2023,9 @@
 		free_irq (dev->irq, dev);
 		del_timer (&dev->timer);
 
-		atm_dev_deregister(dev->atm_dev);
+		for (i=0;i<fs_maxphy;i++)
+			atm_dev_deregister(dev->atm_dev[i]);
+
 		free_queue (dev, &dev->hp_txq);
 		free_queue (dev, &dev->lp_txq);
 		free_queue (dev, &dev->tx_relq);
diff -u --recursive --new-file v2.4.9/linux/drivers/atm/firestream.h linux/drivers/atm/firestream.h
--- v2.4.9/linux/drivers/atm/firestream.h	Wed Apr 11 19:02:30 2001
+++ linux/drivers/atm/firestream.h	Mon Aug 27 09:01:33 2001
@@ -345,13 +345,15 @@
 #define CELLOSCONF_COST   (0x1 <<  0)
 /* Bits? */
 
-
 #define RAS0 0x1bc
 #define RAS0_DCD_XHLT (0x1 << 31)
 
 #define RAS0_VPSEL    (0x1 << 16)
 #define RAS0_VCSEL    (0x1 <<  0)
 
+#define RAS1 0x1c0
+#define RAS1_UTREG    (0x1 << 5)
+
 
 #define DMAMR 0x1cc
 #define DMAMR_TX_MODE_FULL (0x0 << 0)
@@ -360,6 +362,14 @@
 
 
 
+#define RAS2 0x280
+
+#define RAS2_NNI  (0x1 << 0)
+#define RAS2_USEL (0x1 << 1)
+#define RAS2_UBS  (0x1 << 2)
+
+
+
 struct fs_transmit_config {
 	u32 flags;
 	u32 atm_hdr;
@@ -456,6 +466,7 @@
 	int n;
 };
 
+#define MAX_PHY 0x20
 
 struct fs_dev {
 	struct fs_dev *next;		/* other FS devices */
@@ -463,8 +474,9 @@
 
 	unsigned char irq;		/* IRQ */
 	struct pci_dev *pci_dev;	/* PCI stuff */
-	struct atm_dev *atm_dev;
+	struct atm_dev *atm_dev[MAX_PHY];
 	struct timer_list timer;
+	int start_number; 
 
 	unsigned long hw_base;		/* mem base address */
 	unsigned long base;             /* Mapping of base address */
diff -u --recursive --new-file v2.4.9/linux/drivers/char/agp/agp.h linux/drivers/char/agp/agp.h
--- v2.4.9/linux/drivers/char/agp/agp.h	Mon Aug 27 12:41:40 2001
+++ linux/drivers/char/agp/agp.h	Mon Aug 27 07:40:33 2001
@@ -101,6 +101,7 @@
 	int num_aperture_sizes;
 	int num_of_masks;
 	int capndx;
+	int cant_use_aperture;
 
 	/* Links to driver specific functions */
 
diff -u --recursive --new-file v2.4.9/linux/drivers/char/agp/agpgart_be.c linux/drivers/char/agp/agpgart_be.c
--- v2.4.9/linux/drivers/char/agp/agpgart_be.c	Mon Aug 27 12:41:40 2001
+++ linux/drivers/char/agp/agpgart_be.c	Mon Aug 27 07:40:33 2001
@@ -305,6 +305,9 @@
 
 void agp_copy_info(agp_kern_info * info)
 {
+	unsigned long page_mask = 0;
+	int i;
+
 	memset(info, 0, sizeof(agp_kern_info));
 	if (agp_bridge.type == NOT_SUPPORTED) {
 		info->chipset = agp_bridge.type;
@@ -319,6 +322,12 @@
 	info->aper_size = agp_return_size();
 	info->max_memory = agp_bridge.max_memory_agp;
 	info->current_memory = atomic_read(&agp_bridge.current_memory_agp);
+	info->cant_use_aperture = agp_bridge.cant_use_aperture;
+
+	for(i = 0; i < agp_bridge.num_of_masks; i++)
+		page_mask |= agp_bridge.mask_memory(page_mask, i);
+
+	info->page_mask = ~page_mask;
 }
 
 /* End - Routine to copy over information structure */
@@ -1083,6 +1092,7 @@
 	agp_bridge.free_by_type = intel_i810_free_by_type;
 	agp_bridge.agp_alloc_page = agp_generic_alloc_page;
 	agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+	agp_bridge.cant_use_aperture = 0;
 
 	return 0;
 }
@@ -1275,6 +1285,7 @@
 	agp_bridge.free_by_type = agp_generic_free_by_type;
 	agp_bridge.agp_alloc_page = agp_generic_alloc_page;
 	agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+	agp_bridge.cant_use_aperture = 0;
 
 	return 0;
 	
@@ -1305,6 +1316,7 @@
 	agp_bridge.free_by_type = agp_generic_free_by_type;
 	agp_bridge.agp_alloc_page = agp_generic_alloc_page;
 	agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+	agp_bridge.cant_use_aperture = 0;
 
 	return 0;
 	
@@ -1335,6 +1347,7 @@
 	agp_bridge.free_by_type = agp_generic_free_by_type;
 	agp_bridge.agp_alloc_page = agp_generic_alloc_page;
 	agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+	agp_bridge.cant_use_aperture = 0;
 
 	return 0;
 	
@@ -1452,6 +1465,7 @@
 	agp_bridge.free_by_type = agp_generic_free_by_type;
 	agp_bridge.agp_alloc_page = agp_generic_alloc_page;
 	agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+	agp_bridge.cant_use_aperture = 0;
 
 	return 0;
 	
@@ -1563,6 +1577,7 @@
 	agp_bridge.free_by_type = agp_generic_free_by_type;
 	agp_bridge.agp_alloc_page = agp_generic_alloc_page;
 	agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+	agp_bridge.cant_use_aperture = 0;
 
 	return 0;
 }
@@ -1938,6 +1953,7 @@
 	agp_bridge.free_by_type = agp_generic_free_by_type;
 	agp_bridge.agp_alloc_page = agp_generic_alloc_page;
 	agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+	agp_bridge.cant_use_aperture = 0;
 
 	return 0;
 	
@@ -2181,6 +2197,7 @@
 	agp_bridge.free_by_type = agp_generic_free_by_type;
 	agp_bridge.agp_alloc_page = ali_alloc_page;
 	agp_bridge.agp_destroy_page = ali_destroy_page;
+	agp_bridge.cant_use_aperture = 0;
 
 	return 0;
 	
@@ -2766,6 +2783,7 @@
 	agp_bridge.free_by_type = agp_generic_free_by_type;
 	agp_bridge.agp_alloc_page = agp_generic_alloc_page;
 	agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+	agp_bridge.cant_use_aperture = 0;
 
 	pci_read_config_dword(agp_bridge.dev,
 			      SVWRKS_APSIZE,
diff -u --recursive --new-file v2.4.9/linux/drivers/char/drm/ati_pcigart.h linux/drivers/char/drm/ati_pcigart.h
--- v2.4.9/linux/drivers/char/drm/ati_pcigart.h	Mon Aug 27 12:41:40 2001
+++ linux/drivers/char/drm/ati_pcigart.h	Mon Aug 27 13:22:50 2001
@@ -72,8 +72,6 @@
 	int i;
 	DRM_DEBUG( "%s\n", __FUNCTION__ );
 
-	if ( !address ) return;
-
 	page = virt_to_page( address );
 
 	for ( i = 0 ; i <= ATI_PCIGART_TABLE_PAGES ; i++, page++ ) {
@@ -84,23 +82,40 @@
 	free_pages( address, ATI_PCIGART_TABLE_ORDER );
 }
 
-unsigned long DRM(ati_pcigart_init)( drm_device_t *dev )
+int DRM(ati_pcigart_init)( drm_device_t *dev,
+			   unsigned long *addr,
+			   dma_addr_t *bus_addr)
 {
 	drm_sg_mem_t *entry = dev->sg;
-	unsigned long address;
+	unsigned long address = 0;
 	unsigned long pages;
-	u32 *pci_gart, page_base;
-	int i, j;
+	u32 *pci_gart, page_base, bus_address = 0;
+	int i, j, ret = 0;
 
 	if ( !entry ) {
 		DRM_ERROR( "no scatter/gather memory!\n" );
-		return 0;
+		goto done;
 	}
 
 	address = DRM(ati_alloc_pcigart_table)();
 	if ( !address ) {
 		DRM_ERROR( "cannot allocate PCI GART page!\n" );
-		return 0;
+		goto done;
+	}
+
+	if ( !dev->pdev ) {
+		DRM_ERROR( "PCI device unknown!\n" );
+		goto done;
+	}
+
+	bus_address = pci_map_single(dev->pdev, (void *)address,
+				  ATI_PCIGART_TABLE_PAGES * PAGE_SIZE,
+				  PCI_DMA_TODEVICE);
+	if (bus_address == 0) {
+		DRM_ERROR( "unable to map PCIGART pages!\n" );
+		DRM(ati_free_pcigart_table)( address );
+		address = 0;
+		goto done;
 	}
 
 	pci_gart = (u32 *)address;
@@ -111,28 +126,72 @@
 	memset( pci_gart, 0, ATI_MAX_PCIGART_PAGES * sizeof(u32) );
 
 	for ( i = 0 ; i < pages ; i++ ) {
-		page_base = page_to_bus( entry->pagelist[i] );
+		/* we need to support large memory configurations */
+		entry->busaddr[i] = pci_map_single(dev->pdev,
+					   page_address( entry->pagelist[i] ),
+					   PAGE_SIZE,
+					   PCI_DMA_TODEVICE);
+		if (entry->busaddr[i] == 0) {
+			DRM_ERROR( "unable to map PCIGART pages!\n" );
+			DRM(ati_pcigart_cleanup)( dev, address, bus_address );
+			address = 0;
+			bus_address = 0;
+			goto done;
+		}
+		page_base = (u32) entry->busaddr[i];
+
 		for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
 			*pci_gart++ = cpu_to_le32( page_base );
 			page_base += ATI_PCIGART_PAGE_SIZE;
 		}
 	}
 
+	ret = 1;
+
 #if __i386__
 	asm volatile ( "wbinvd" ::: "memory" );
 #else
 	mb();
 #endif
 
-	return address;
+done:
+	*addr = address;
+	*bus_addr = bus_address;
+	return ret;
 }
 
-int DRM(ati_pcigart_cleanup)( unsigned long address )
+int DRM(ati_pcigart_cleanup)( drm_device_t *dev,
+			      unsigned long addr,
+			      dma_addr_t bus_addr)
 {
+	drm_sg_mem_t *entry = dev->sg;
+	unsigned long pages;
+	int i;
 
-	if ( address ) {
-		DRM(ati_free_pcigart_table)( address );
+	/* we need to support large memory configurations */
+	if ( !entry ) {
+		DRM_ERROR( "no scatter/gather memory!\n" );
+		return 0;
+	}
+
+	if ( bus_addr ) {
+		pci_unmap_single(dev->pdev, bus_addr,
+				 ATI_PCIGART_TABLE_PAGES * PAGE_SIZE,
+				 PCI_DMA_TODEVICE);
+
+		pages = ( entry->pages <= ATI_MAX_PCIGART_PAGES )
+		        ? entry->pages : ATI_MAX_PCIGART_PAGES;
+
+		for ( i = 0 ; i < pages ; i++ ) {
+			if ( !entry->busaddr[i] ) break;
+			pci_unmap_single(dev->pdev, entry->busaddr[i],
+					 PAGE_SIZE, PCI_DMA_TODEVICE);
+		}
+	}
+
+	if ( addr ) {
+		DRM(ati_free_pcigart_table)( addr );
 	}
 
-	return 0;
+	return 1;
 }
diff -u --recursive --new-file v2.4.9/linux/drivers/char/drm/drmP.h linux/drivers/char/drm/drmP.h
--- v2.4.9/linux/drivers/char/drm/drmP.h	Sun Aug 12 13:27:59 2001
+++ linux/drivers/char/drm/drmP.h	Mon Aug 27 13:22:50 2001
@@ -76,6 +76,17 @@
 #include <asm/pgalloc.h>
 #include "drm.h"
 
+/* page_to_bus for earlier kernels, not optimal in all cases */
+#ifndef page_to_bus
+#define page_to_bus(page)	((unsigned int)(virt_to_bus(page_address(page))))
+#endif
+
+/* We just use virt_to_bus for pci_map_single on older kernels */
+#if LINUX_VERSION_CODE < 0x020400
+#define pci_map_single(hwdev, ptr, size, direction)	virt_to_bus(ptr)
+#define pci_unmap_single(hwdev, dma_addr, size, direction)
+#endif
+
 /* DRM template customization defaults
  */
 #ifndef __HAVE_AGP
@@ -616,6 +627,8 @@
 	int                acquired;
 	unsigned long      base;
    	int 		   agp_mtrr;
+	int		   cant_use_aperture;
+	unsigned long	   page_mask;
 } drm_agp_head_t;
 #endif
 
@@ -624,6 +637,7 @@
 	void            *virtual;
 	int             pages;
 	struct page     **pagelist;
+	dma_addr_t	*busaddr;
 } drm_sg_mem_t;
 
 typedef struct drm_sigdata {
@@ -714,6 +728,7 @@
 #if __REALLY_HAVE_AGP
 	drm_agp_head_t    *agp;
 #endif
+	struct pci_dev *pdev;
 #ifdef __alpha__
 #if LINUX_VERSION_CODE < 0x020403
 	struct pci_controler *hose;
@@ -1018,8 +1033,12 @@
 #endif
 
                                /* ATI PCIGART support (ati_pcigart.h) */
-extern unsigned long  DRM(ati_pcigart_init)(drm_device_t *dev);
-extern int            DRM(ati_pcigart_cleanup)(unsigned long address);
+extern int            DRM(ati_pcigart_init)(drm_device_t *dev,
+					    unsigned long *addr,
+					    dma_addr_t *bus_addr);
+extern int            DRM(ati_pcigart_cleanup)(drm_device_t *dev,
+					       unsigned long addr,
+					       dma_addr_t bus_addr);
 
 #endif /* __KERNEL__ */
 #endif
diff -u --recursive --new-file v2.4.9/linux/drivers/char/drm/drm_agpsupport.h linux/drivers/char/drm/drm_agpsupport.h
--- v2.4.9/linux/drivers/char/drm/drm_agpsupport.h	Sun Aug 12 13:27:59 2001
+++ linux/drivers/char/drm/drm_agpsupport.h	Mon Aug 27 13:22:50 2001
@@ -316,6 +316,14 @@
 
 		default:		head->chipset = "Unknown";       break;
 		}
+#if LINUX_VERSION_CODE <= 0x020408
+		head->cant_use_aperture = 0;
+		head->page_mask = ~(0xfff);
+#else
+		head->cant_use_aperture = head->agp_info.cant_use_aperture;
+		head->page_mask = head->agp_info.page_mask;
+#endif
+
 		DRM_INFO("AGP %d.%d on %s @ 0x%08lx %ZuMB\n",
 			 head->agp_info.version.major,
 			 head->agp_info.version.minor,
diff -u --recursive --new-file v2.4.9/linux/drivers/char/drm/drm_ioctl.h linux/drivers/char/drm/drm_ioctl.h
--- v2.4.9/linux/drivers/char/drm/drm_ioctl.h	Sun Aug 12 13:27:59 2001
+++ linux/drivers/char/drm/drm_ioctl.h	Mon Aug 27 13:22:50 2001
@@ -98,7 +98,6 @@
 	}
 	sprintf(dev->devname, "%s@%s", dev->name, dev->unique);
 
-#ifdef __alpha__
 	do {
 		struct pci_dev *pci_dev;
                 int b, d, f;
@@ -114,10 +113,13 @@
                 if (*p) break;
  
                 pci_dev = pci_find_slot(b, PCI_DEVFN(d,f));
-                if (pci_dev)
-                        dev->hose = pci_dev->sysdata;
-        } while(0);
+                if (pci_dev) {
+			dev->pdev = pci_dev;
+#ifdef __alpha__
+			dev->hose = pci_dev->sysdata;
 #endif
+		}
+        } while(0);
 
 	return 0;
 }
diff -u --recursive --new-file v2.4.9/linux/drivers/char/drm/drm_scatter.h linux/drivers/char/drm/drm_scatter.h
--- v2.4.9/linux/drivers/char/drm/drm_scatter.h	Mon Aug 27 12:41:40 2001
+++ linux/drivers/char/drm/drm_scatter.h	Mon Aug 27 13:22:50 2001
@@ -47,12 +47,15 @@
 
 	vfree( entry->virtual );
 
+	DRM(free)( entry->busaddr,
+		   entry->pages * sizeof(*entry->busaddr),
+		   DRM_MEM_PAGES );
 	DRM(free)( entry->pagelist,
-		  entry->pages * sizeof(*entry->pagelist),
-		  DRM_MEM_PAGES );
+		   entry->pages * sizeof(*entry->pagelist),
+		   DRM_MEM_PAGES );
 	DRM(free)( entry,
-		  sizeof(*entry),
-		  DRM_MEM_SGLISTS );
+		   sizeof(*entry),
+		   DRM_MEM_SGLISTS );
 }
 
 int DRM(sg_alloc)( struct inode *inode, struct file *filp,
@@ -93,16 +96,31 @@
 		DRM(free)( entry, sizeof(*entry), DRM_MEM_SGLISTS );
 		return -ENOMEM;
 	}
-	memset(entry->pagelist, 0, pages * sizeof(*entry->pagelist));
+
+	entry->busaddr = DRM(alloc)( pages * sizeof(*entry->busaddr),
+				     DRM_MEM_PAGES );
+	if ( !entry->busaddr ) {
+		DRM(free)( entry->pagelist,
+			   entry->pages * sizeof(*entry->pagelist),
+			   DRM_MEM_PAGES );
+		DRM(free)( entry,
+			   sizeof(*entry),
+			   DRM_MEM_SGLISTS );
+		return -ENOMEM;
+	}
+	memset( (void *)entry->busaddr, 0, pages * sizeof(*entry->busaddr) );
 
 	entry->virtual = vmalloc_32( pages << PAGE_SHIFT );
 	if ( !entry->virtual ) {
+		DRM(free)( entry->busaddr,
+			   entry->pages * sizeof(*entry->busaddr),
+			   DRM_MEM_PAGES );
 		DRM(free)( entry->pagelist,
-			  entry->pages * sizeof(*entry->pagelist),
-			  DRM_MEM_PAGES );
+			   entry->pages * sizeof(*entry->pagelist),
+			   DRM_MEM_PAGES );
 		DRM(free)( entry,
-			  sizeof(*entry),
-			  DRM_MEM_SGLISTS );
+			   sizeof(*entry),
+			   DRM_MEM_SGLISTS );
 		return -ENOMEM;
 	}
 
diff -u --recursive --new-file v2.4.9/linux/drivers/char/drm/drm_vm.h linux/drivers/char/drm/drm_vm.h
--- v2.4.9/linux/drivers/char/drm/drm_vm.h	Mon Aug 27 12:41:40 2001
+++ linux/drivers/char/drm/drm_vm.h	Mon Aug 27 13:22:50 2001
@@ -67,6 +67,70 @@
 			    int write_access)
 #endif
 {
+#if __REALLY_HAVE_AGP
+	drm_file_t *priv  = vma->vm_file->private_data;
+	drm_device_t *dev = priv->dev;
+	drm_map_t *map    = NULL;
+	drm_map_list_t  *r_list;
+	struct list_head *list;
+
+	/*
+         * Find the right map
+         */
+
+	if(!dev->agp->cant_use_aperture) goto vm_nopage_error;
+
+	list_for_each(list, &dev->maplist->head) {
+		r_list = (drm_map_list_t *)list;
+		map = r_list->map;
+		if (!map) continue;
+		if (map->offset == VM_OFFSET(vma)) break;
+	}
+
+	if (map && map->type == _DRM_AGP) {
+		unsigned long offset = address - vma->vm_start;
+		unsigned long baddr = VM_OFFSET(vma) + offset;
+		struct drm_agp_mem *agpmem;
+		struct page *page;
+
+#if __alpha__
+		/*
+                 * Adjust to a bus-relative address
+                 */
+		baddr -= dev->hose->mem_space->start;
+#endif
+
+		/*
+                 * It's AGP memory - find the real physical page to map
+                 */
+		for(agpmem = dev->agp->memory; agpmem; agpmem = agpmem->next) {
+			if (agpmem->bound <= baddr &&
+			    agpmem->bound + agpmem->pages * PAGE_SIZE > baddr) 
+				break;
+		}
+
+		if (!agpmem) goto vm_nopage_error;
+
+		/*
+                 * Get the page, inc the use count, and return it
+                 */
+		offset = (baddr - agpmem->bound) >> PAGE_SHIFT;
+		agpmem->memory->memory[offset] &= dev->agp->page_mask;
+		page = virt_to_page(__va(agpmem->memory->memory[offset]));
+		get_page(page);
+
+		DRM_DEBUG("baddr = 0x%lx page = 0x%p, offset = 0x%lx\n",
+			  baddr, __va(agpmem->memory->memory[offset]), offset);
+
+#if LINUX_VERSION_CODE < 0x020317
+		return page_address(page);
+#else
+		return page;
+#endif
+        }
+vm_nopage_error:
+#endif /* __REALLY_HAVE_AGP */
+
 	return NOPAGE_SIGBUS;		/* Disallow mremap */
 }
 
@@ -220,24 +284,27 @@
 	drm_file_t	 *priv	 = vma->vm_file->private_data;
 	drm_device_t	 *dev	 = priv->dev;
 	drm_device_dma_t *dma	 = dev->dma;
-	unsigned long	 physical;
 	unsigned long	 offset;
-	unsigned long	 page;
+	unsigned long	 page_nr;
+	struct page	 *page;
 
 	if (!dma)		   return NOPAGE_SIGBUS; /* Error */
 	if (address > vma->vm_end) return NOPAGE_SIGBUS; /* Disallow mremap */
 	if (!dma->pagelist)	   return NOPAGE_OOM ; /* Nothing allocated */
 
 	offset	 = address - vma->vm_start; /* vm_[pg]off[set] should be 0 */
-	page	 = offset >> PAGE_SHIFT;
-	physical = dma->pagelist[page] + (offset & (~PAGE_MASK));
-	atomic_inc(&virt_to_page(physical)->count); /* Dec. by kernel */
+	page_nr  = offset >> PAGE_SHIFT;
+	page = virt_to_page((dma->pagelist[page_nr] + 
+			     (offset & (~PAGE_MASK))));
 
-	DRM_DEBUG("0x%08lx (page %lu) => 0x%08lx\n", address, page, physical);
+	get_page(page);
+
+	DRM_DEBUG("0x%08lx (page %lu) => 0x%08x\n", address, page_nr, 
+		  page_to_bus(page));
 #if LINUX_VERSION_CODE < 0x020317
-	return physical;
+	return page_address(page);
 #else
-	return virt_to_page(physical);
+	return page;
 #endif
 }
 
@@ -274,10 +341,10 @@
 	map_offset = map->offset - dev->sg->handle;
 	page_offset = (offset >> PAGE_SHIFT) + (map_offset >> PAGE_SHIFT);
 	page = entry->pagelist[page_offset];
-	atomic_inc(&page->count);                       /* Dec. by kernel */
+	get_page(page);
 
 #if LINUX_VERSION_CODE < 0x020317
-	return (unsigned long)virt_to_phys(page->virtual);
+	return page_address(page);
 #else
 	return page;
 #endif
@@ -435,9 +502,20 @@
 	}
 
 	switch (map->type) {
+        case _DRM_AGP:
+#if defined(__alpha__)
+                /*
+                 * On Alpha we can't talk to bus dma address from the
+                 * CPU, so for memory of type DRM_AGP, we'll deal with
+                 * sorting out the real physical pages and mappings
+                 * in nopage()
+                 */
+                vma->vm_ops = &DRM(vm_ops);
+                break;
+#endif
+                /* fall through to _DRM_FRAME_BUFFER... */        
 	case _DRM_FRAME_BUFFER:
 	case _DRM_REGISTERS:
-	case _DRM_AGP:
 		if (VM_OFFSET(vma) >= __pa(high_memory)) {
 #if defined(__i386__)
 			if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) {
diff -u --recursive --new-file v2.4.9/linux/drivers/char/drm/mga_drv.h linux/drivers/char/drm/mga_drv.h
--- v2.4.9/linux/drivers/char/drm/mga_drv.h	Sun Aug 12 13:27:59 2001
+++ linux/drivers/char/drm/mga_drv.h	Mon Aug 27 07:40:33 2001
@@ -145,14 +145,28 @@
 #define mga_flush_write_combine()	mb()
 
 
-#define MGA_BASE( reg )		((u32)(dev_priv->mmio->handle))
+#define MGA_BASE( reg )		((unsigned long)(dev_priv->mmio->handle))
 #define MGA_ADDR( reg )		(MGA_BASE(reg) + reg)
 
 #define MGA_DEREF( reg )	*(volatile u32 *)MGA_ADDR( reg )
+#define MGA_DEREF8( reg )	*(volatile u8 *)MGA_ADDR( reg )
+
+#ifdef __alpha__
+#define MGA_READ( reg )		(_MGA_READ((u32 *)MGA_ADDR(reg)))
+#define MGA_WRITE( reg, val )	do { wmb(); MGA_DEREF( reg ) = val; } while (0)
+#define MGA_WRITE8( reg, val )  do { wmb(); MGA_DEREF8( reg ) = val; } while (0)
+
+static inline u32 _MGA_READ(u32 *addr)
+{
+	mb();
+	return *(volatile u32 *)addr;
+}
+
+#else
 #define MGA_READ( reg )		MGA_DEREF( reg )
 #define MGA_WRITE( reg, val )	do { MGA_DEREF( reg ) = val; } while (0)
-#define MGA_DEREF8( reg )	*(volatile u8 *)MGA_ADDR( reg )
 #define MGA_WRITE8( reg, val )  do { MGA_DEREF8( reg ) = val; } while (0)
+#endif
 
 #define DWGREG0 	0x1c00
 #define DWGREG0_END 	0x1dff
diff -u --recursive --new-file v2.4.9/linux/drivers/char/drm/r128_cce.c linux/drivers/char/drm/r128_cce.c
--- v2.4.9/linux/drivers/char/drm/r128_cce.c	Mon Aug 27 12:41:40 2001
+++ linux/drivers/char/drm/r128_cce.c	Mon Aug 27 07:40:33 2001
@@ -351,11 +351,10 @@
 		page_ofs = tmp_ofs >> PAGE_SHIFT;
 
 		R128_WRITE( R128_PM4_BUFFER_DL_RPTR_ADDR,
-			    page_to_bus(entry->pagelist[page_ofs]));
-
-		DRM_DEBUG( "ring rptr: offset=0x%08lx handle=0x%08lx\n",
-			   page_to_bus(entry->pagelist[page_ofs]),
-			   entry->handle + tmp_ofs );
+     			    entry->busaddr[page_ofs]);
+		DRM_DEBUG( "ring rptr: offset=0x%08x handle=0x%08lx\n",
+			   entry->busaddr[page_ofs],
+     			   entry->handle + tmp_ofs );
 	}
 
 	/* Set watermark control */
@@ -599,15 +598,14 @@
 		    dev_priv->sarea_priv->last_dispatch );
 
 	if ( dev_priv->is_pci ) {
-		dev_priv->phys_pci_gart = DRM(ati_pcigart_init)( dev );
-		if ( !dev_priv->phys_pci_gart ) {
+		if (!DRM(ati_pcigart_init)( dev, &dev_priv->phys_pci_gart,
+     					    &dev_priv->bus_pci_gart) ) {
 			DRM_ERROR( "failed to init PCI GART!\n" );
 			dev->dev_private = (void *)dev_priv;
 			r128_do_cleanup_cce( dev );
 			return -ENOMEM;
 		}
-		R128_WRITE( R128_PCI_GART_PAGE,
-			    virt_to_bus( (void *)dev_priv->phys_pci_gart ) );
+		R128_WRITE( R128_PCI_GART_PAGE, dev_priv->bus_pci_gart );
 	}
 
 	r128_cce_init_ring_buffer( dev, dev_priv );
@@ -629,6 +627,11 @@
 			DRM_IOREMAPFREE( dev_priv->cce_ring );
 			DRM_IOREMAPFREE( dev_priv->ring_rptr );
 			DRM_IOREMAPFREE( dev_priv->buffers );
+		} else {
+			if (!DRM(ati_pcigart_cleanup)( dev,
+						dev_priv->phys_pci_gart,
+						dev_priv->bus_pci_gart ))
+				DRM_ERROR( "failed to cleanup PCI GART!\n" );
 		}
 
 		DRM(free)( dev->dev_private, sizeof(drm_r128_private_t),
diff -u --recursive --new-file v2.4.9/linux/drivers/char/drm/r128_drv.h linux/drivers/char/drm/r128_drv.h
--- v2.4.9/linux/drivers/char/drm/r128_drv.h	Sun Aug 12 13:27:59 2001
+++ linux/drivers/char/drm/r128_drv.h	Mon Aug 27 07:40:33 2001
@@ -72,6 +72,7 @@
 	int usec_timeout;
 	int is_pci;
 	unsigned long phys_pci_gart;
+	dma_addr_t bus_pci_gart;
 	unsigned long cce_buffers_offset;
 
 	atomic_t idle_count;
diff -u --recursive --new-file v2.4.9/linux/drivers/char/drm/radeon_cp.c linux/drivers/char/drm/radeon_cp.c
--- v2.4.9/linux/drivers/char/drm/radeon_cp.c	Mon Aug 27 12:41:40 2001
+++ linux/drivers/char/drm/radeon_cp.c	Mon Aug 27 07:40:33 2001
@@ -624,10 +624,9 @@
 		page_ofs = tmp_ofs >> PAGE_SHIFT;
 
 		RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR,
-			      page_to_bus(entry->pagelist[page_ofs]));
-
+			     entry->busaddr[page_ofs]);
 		DRM_DEBUG( "ring rptr: offset=0x%08x handle=0x%08lx\n",
-			   page_to_bus(entry->pagelist[page_ofs]),
+			   entry->busaddr[page_ofs],
 			   entry->handle + tmp_ofs );
 	}
 
@@ -929,8 +928,8 @@
 		      dev_priv->sarea_priv->last_clear );
 
 	if ( dev_priv->is_pci ) {
-		dev_priv->phys_pci_gart = DRM(ati_pcigart_init)( dev );
-		if ( !dev_priv->phys_pci_gart ) {
+		if (!DRM(ati_pcigart_init)( dev, &dev_priv->phys_pci_gart,
+					    &dev_priv->bus_pci_gart)) {
 			DRM_ERROR( "failed to init PCI GART!\n" );
 			dev->dev_private = (void *)dev_priv;
 			radeon_do_cleanup_cp(dev);
@@ -944,8 +943,7 @@
 
 		/* set PCI GART page-table base address
 		 */
-		RADEON_WRITE( RADEON_AIC_PT_BASE,
-			      virt_to_bus( (void *)dev_priv->phys_pci_gart ) );
+		RADEON_WRITE( RADEON_AIC_PT_BASE, dev_priv->bus_pci_gart );
 
 		/* set address range for PCI address translate
 		 */
@@ -990,6 +988,11 @@
 			DRM_IOREMAPFREE( dev_priv->cp_ring );
 			DRM_IOREMAPFREE( dev_priv->ring_rptr );
 			DRM_IOREMAPFREE( dev_priv->buffers );
+		} else {
+			if (!DRM(ati_pcigart_cleanup)( dev,
+						dev_priv->phys_pci_gart,
+						dev_priv->bus_pci_gart ))
+				DRM_ERROR( "failed to cleanup PCI GART!\n" );
 		}
 
 		DRM(free)( dev->dev_private, sizeof(drm_radeon_private_t),
diff -u --recursive --new-file v2.4.9/linux/drivers/char/drm/radeon_drv.h linux/drivers/char/drm/radeon_drv.h
--- v2.4.9/linux/drivers/char/drm/radeon_drv.h	Sun Aug 12 13:27:59 2001
+++ linux/drivers/char/drm/radeon_drv.h	Mon Aug 27 07:40:33 2001
@@ -84,6 +84,7 @@
 	int usec_timeout;
 	int is_pci;
 	unsigned long phys_pci_gart;
+	dma_addr_t bus_pci_gart;
 
 	atomic_t idle_count;
 
diff -u --recursive --new-file v2.4.9/linux/drivers/char/drm/tdfx_drv.c linux/drivers/char/drm/tdfx_drv.c
--- v2.4.9/linux/drivers/char/drm/tdfx_drv.c	Sun Aug 12 13:27:59 2001
+++ linux/drivers/char/drm/tdfx_drv.c	Mon Aug 27 07:40:33 2001
@@ -44,13 +44,30 @@
 #define DRIVER_MINOR		0
 #define DRIVER_PATCHLEVEL	0
 
+#ifndef PCI_VENDOR_ID_3DFX
+#define PCI_VENDOR_ID_3DFX 0x121A
+#endif
 #ifndef PCI_DEVICE_ID_3DFX_VOODOO5
 #define PCI_DEVICE_ID_3DFX_VOODOO5 0x0009
 #endif
+#ifndef PCI_DEVICE_ID_3DFX_VOODOO4
+#define PCI_DEVICE_ID_3DFX_VOODOO4 0x0007
+#endif
+#ifndef PCI_DEVICE_ID_3DFX_VOODOO3_3000 /* Voodoo3 3000 */
+#define PCI_DEVICE_ID_3DFX_VOODOO3_3000 0x0005
+#endif
+#ifndef PCI_DEVICE_ID_3DFX_VOODOO3_2000 /* Voodoo3 3000 */
+#define PCI_DEVICE_ID_3DFX_VOODOO3_2000 0x0004
+#endif
+#ifndef PCI_DEVICE_ID_3DFX_BANSHEE
+#define PCI_DEVICE_ID_3DFX_BANSHEE 0x0003
+#endif
 
 static drm_pci_list_t DRM(idlist)[] = {
 	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE },
-	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3 },
+	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3_2000 },
+	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3_3000 },
+	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO4 },
 	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO5 },
 	{ 0, 0 }
 };
diff -u --recursive --new-file v2.4.9/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c
--- v2.4.9/linux/drivers/char/pc_keyb.c	Mon Aug 27 12:41:41 2001
+++ linux/drivers/char/pc_keyb.c	Tue Aug 28 07:09:44 2001
@@ -31,6 +31,7 @@
 #include <linux/miscdevice.h>
 #include <linux/slab.h>
 #include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
 #include <linux/smp_lock.h>
 
 #include <asm/keyboard.h>
@@ -602,7 +603,7 @@
 		return 1;
 }
 
-int pckbd_rate(struct kbd_repeat *rep)
+static int pckbd_rate(struct kbd_repeat *rep)
 {
 	if (rep == NULL)
 		return -EINVAL;
@@ -834,6 +835,8 @@
 #if defined CONFIG_PSMOUSE
 	psaux_init();
 #endif
+
+	kbd_rate = pckbd_rate;
 
 	/* Ok, finally allocate the IRQ, and off we go.. */
 	kbd_request_irq(keyboard_interrupt);
diff -u --recursive --new-file v2.4.9/linux/drivers/char/vt.c linux/drivers/char/vt.c
--- v2.4.9/linux/drivers/char/vt.c	Mon Aug 27 12:41:41 2001
+++ linux/drivers/char/vt.c	Tue Aug 28 07:09:44 2001
@@ -28,7 +28,6 @@
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
-#include <asm/keyboard.h>
 
 #include <linux/kbd_kern.h>
 #include <linux/vt_kern.h>
@@ -145,8 +144,13 @@
 
 #endif
 
-void (*kd_mksound)(unsigned int hz, unsigned int ticks) = _kd_mksound;
+int _kbd_rate(struct kbd_repeat *rep)
+{
+	return -EINVAL;
+}
 
+void (*kd_mksound)(unsigned int hz, unsigned int ticks) = _kd_mksound;
+int (*kbd_rate)(struct kbd_repeat *rep) = _kbd_rate;
 
 #define i (tmp.kb_index)
 #define s (tmp.kb_table)
@@ -504,7 +508,6 @@
 	{
 		struct kbd_repeat kbrep;
 		
-		if (!kbd_rate) return( -EINVAL );
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
 
diff -u --recursive --new-file v2.4.9/linux/drivers/i2o/i2o_block.c linux/drivers/i2o/i2o_block.c
--- v2.4.9/linux/drivers/i2o/i2o_block.c	Mon Aug 27 12:41:41 2001
+++ linux/drivers/i2o/i2o_block.c	Mon Aug 27 14:20:21 2001
@@ -1195,9 +1195,6 @@
 	if(!dev->i2odev)
 		return 0;
 
-	/* Sync the device so we don't get errors */
-	fsync_dev(inode->i_rdev);
-
 	if (dev->refcnt <= 0)
 		printk(KERN_ALERT "i2ob_release: refcount(%d) <= 0\n", dev->refcnt);
 	dev->refcnt--;
diff -u --recursive --new-file v2.4.9/linux/drivers/ide/via82cxxx.c linux/drivers/ide/via82cxxx.c
--- v2.4.9/linux/drivers/ide/via82cxxx.c	Mon Aug 27 12:41:41 2001
+++ linux/drivers/ide/via82cxxx.c	Mon Aug 27 07:48:29 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: via82cxxx.c,v 3.23 2001/03/09 09:30:00 vojtech Exp $
+ * $Id: via82cxxx.c,v 3.26 2001/08/17 12:03:00 vojtech Exp $
  *
  *  Copyright (c) 2000-2001 Vojtech Pavlik
  *
@@ -88,7 +88,6 @@
 #define VIA_BAD_CLK66		0x020	/* 66 MHz clock doesn't work correctly */
 #define VIA_SET_FIFO		0x040	/* Needs to have FIFO split set */
 #define VIA_SET_THRESH		0x080	/* Needs to have FIFO thresholds set */
-#define VIA_BAD_PIO		0x100	/* Always uses 26 PCICLK/xfer regardles of PIO mode */
 
 /*
  * VIA SouthBridge chips.
@@ -101,11 +100,9 @@
 	unsigned char rev_max;
 	unsigned short flags;
 } via_isa_bridges[] = {
-#ifdef VIA_NEW_BRIDGES_TESTED
 	{ "vt8233",	PCI_DEVICE_ID_VIA_8233_0,   0x00, 0x2f, VIA_UDMA_100 },
-	{ "vt8231",	PCI_DEVICE_ID_VIA_8231,     0x00, 0x2f, VIA_UDMA_66 },
-#endif
-	{ "vt82c686b",	PCI_DEVICE_ID_VIA_82C686,   0x40, 0x4f, VIA_UDMA_100 | VIA_BAD_PIO },
+	{ "vt8231",	PCI_DEVICE_ID_VIA_8231,     0x00, 0x2f, VIA_UDMA_100 },
+	{ "vt82c686b",	PCI_DEVICE_ID_VIA_82C686,   0x40, 0x4f, VIA_UDMA_100 },
 	{ "vt82c686a",	PCI_DEVICE_ID_VIA_82C686,   0x10, 0x2f, VIA_UDMA_66 },
 	{ "vt82c686",	PCI_DEVICE_ID_VIA_82C686,   0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
 	{ "vt82c596b",	PCI_DEVICE_ID_VIA_82C596,   0x10, 0x2f, VIA_UDMA_66 },
@@ -154,7 +151,7 @@
 
 	via_print("----------VIA BusMastering IDE Configuration----------------");
 
-	via_print("Driver Version:                     3.23");
+	via_print("Driver Version:                     3.26");
 	via_print("South Bridge:                       VIA %s", via_config->name);
 
 	pci_read_config_byte(isa_dev, PCI_REVISION_ID, &t);
@@ -220,8 +217,8 @@
 		switch (via_config->flags & VIA_UDMA) {
 			
 			case VIA_UDMA_100:
-				speed[i] = 2000 / udma[i];
-				cycle[i] = 10 * udma[i];
+				speed[i] = 60 * via_clock / udma[i];
+				cycle[i] = 333 / via_clock * udma[i];
 				break;
 
 			case VIA_UDMA_66:
@@ -301,7 +298,7 @@
 	switch (via_config->flags & VIA_UDMA) {
 		case VIA_UDMA_33:   UT = T;   break;
 		case VIA_UDMA_66:   UT = T/2; break;
-		case VIA_UDMA_100:  UT = 10;  break;
+		case VIA_UDMA_100:  UT = T/3; break;
 		default:	    UT = T;   break;
 	}
 
diff -u --recursive --new-file v2.4.9/linux/drivers/md/lvm.c linux/drivers/md/lvm.c
--- v2.4.9/linux/drivers/md/lvm.c	Wed Jul 25 17:10:20 2001
+++ linux/drivers/md/lvm.c	Mon Aug 27 14:20:21 2001
@@ -1059,7 +1059,6 @@
 	       lvm_name, minor, VG_BLK(minor), LV_BLK(minor));
 #endif
 
-	sync_dev(inode->i_rdev);
 	if (lv_ptr->lv_open == 1) vg_ptr->lv_open--;
 	lv_ptr->lv_open--;
 
diff -u --recursive --new-file v2.4.9/linux/drivers/media/video/videodev.c linux/drivers/media/video/videodev.c
--- v2.4.9/linux/drivers/media/video/videodev.c	Mon Aug 27 12:41:42 2001
+++ linux/drivers/media/video/videodev.c	Tue Aug 28 07:00:58 2001
@@ -164,7 +164,6 @@
 	
 	if(vfl->owner)
 		__MOD_INC_USE_COUNT(vfl->owner);
-	unlock_kernel();
 	
 	if(vfl->open)
 	{
@@ -175,9 +174,11 @@
 			if(vfl->owner)
 				__MOD_DEC_USE_COUNT(vfl->owner);
 			
+			unlock_kernel();
 			return err;
 		}
 	}
+	unlock_kernel();
 	return 0;
 error_out:
 	unlock_kernel();
diff -u --recursive --new-file v2.4.9/linux/drivers/net/wireless/airport.c linux/drivers/net/wireless/airport.c
--- v2.4.9/linux/drivers/net/wireless/airport.c	Mon Aug 27 12:41:43 2001
+++ linux/drivers/net/wireless/airport.c	Mon Aug 27 09:00:37 2001
@@ -5,6 +5,10 @@
  *
  * Copyright notice & release notes in file orinoco.c
  * 
+ * Note specific to airport stub:
+ * 
+ *  0.05 : first version of the new split driver
+ *  0.06 : fix possible hang on powerup, add sleep support
  */
 
 #include <linux/module.h>
@@ -25,9 +29,12 @@
 #include <linux/etherdevice.h>
 #include <linux/wireless.h>
 #include <linux/list.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
 
 #include <asm/prom.h>
 #include <asm/feature.h>
+#include <asm/irq.h>
 
 #include "hermes.h"
 #include "orinoco.h"
@@ -40,10 +47,18 @@
 	struct device_node* node;
 	int irq_requested;
 	int ndev_registered;
+	int open;
 	/* Common structure (fully included), see orinoco.h */
 	struct dldwd_priv priv;
 } dldwd_card_t;
 
+#ifdef CONFIG_PMAC_PBOOK
+static int airport_sleep_notify(struct pmu_sleep_notifier *self, int when);
+static struct pmu_sleep_notifier airport_sleep_notifier = {
+	airport_sleep_notify, SLEEP_LEVEL_NET,
+};
+#endif
+
 /*
  * Function prototypes
  */
@@ -69,24 +84,15 @@
 static int airport_init(struct net_device *dev)
 {
 	dldwd_priv_t *priv = dev->priv;
-	dldwd_card_t* card = (dldwd_card_t *)priv->card;
 	int rc;
 	
 	TRACE_ENTER(priv->ndev.name);
 
 	MOD_INC_USE_COUNT;
 
-	feature_set_airport_power(card->node, 1);
-	current->state = TASK_UNINTERRUPTIBLE;
-	schedule_timeout(HZ);
-
 	rc = dldwd_init(dev);
-	if (rc) {	
-		feature_set_airport_power(card->node, 0);
-		current->state = TASK_UNINTERRUPTIBLE;
-		schedule_timeout(HZ);
-	}
-	priv->hw_ready = 1;
+	if (!rc)
+		priv->hw_ready = 1;
 
 	MOD_DEC_USE_COUNT;
 
@@ -97,18 +103,20 @@
 airport_open(struct net_device *dev)
 {
 	dldwd_priv_t *priv = dev->priv;
+	dldwd_card_t* card = (dldwd_card_t *)priv->card;
 	int rc;
 
 	TRACE_ENTER(priv->ndev.name);
 
-	netif_device_attach(dev);
 	rc = dldwd_reset(priv);
 	if (rc)
 		airport_stop(dev);
-	else
-		netif_start_queue(dev);
+	else {
+		card->open = 1;
+		netif_device_attach(dev);
+	}
 
-	TRACE_EXIT(priv->ndev.name);
+//	TRACE_EXIT(priv->ndev.name);
 
 	return rc;
 }
@@ -117,18 +125,66 @@
 airport_stop(struct net_device *dev)
 {
 	dldwd_priv_t *priv = dev->priv;
+	dldwd_card_t* card = (dldwd_card_t *)priv->card;
 
 	TRACE_ENTER(priv->ndev.name);
 
 	netif_stop_queue(dev);
-
 	dldwd_shutdown(priv);
+	card->open = 0;
 
 	TRACE_EXIT(priv->ndev.name);
 
 	return 0;
 }
 
+#ifdef CONFIG_PMAC_PBOOK
+static int
+airport_sleep_notify(struct pmu_sleep_notifier *self, int when)
+{
+	dldwd_priv_t *priv;
+	struct net_device *ndev;
+	dldwd_card_t* card;
+	int rc;
+	
+	if (!airport_dev)
+		return PBOOK_SLEEP_OK;
+	priv = airport_dev;
+	ndev = &priv->ndev;
+	card = (dldwd_card_t *)priv->card;
+
+	switch (when) {
+	case PBOOK_SLEEP_REQUEST:
+		break;
+	case PBOOK_SLEEP_REJECT:
+		break;
+	case PBOOK_SLEEP_NOW:
+		printk(KERN_INFO "%s: Airport entering sleep mode\n", ndev->name);
+		netif_device_detach(ndev);
+		if (card->open)
+			dldwd_shutdown(priv);
+		disable_irq(ndev->irq);
+		feature_set_airport_power(card->node, 0);
+		priv->hw_ready = 0;
+		break;
+	case PBOOK_WAKE:
+		printk(KERN_INFO "%s: Airport waking up\n", ndev->name);
+		feature_set_airport_power(card->node, 1);
+		mdelay(200);
+		hermes_reset(&priv->hw);
+		priv->hw_ready = 1;		
+		rc = dldwd_reset(priv);
+		if (rc)
+			printk(KERN_ERR "airport: Error %d re-initing card !\n", rc);
+		else if (card->open)
+			netif_device_attach(ndev);
+		enable_irq(ndev->irq);
+		break;
+	}
+	return PBOOK_SLEEP_OK;
+}
+#endif /* CONFIG_PMAC_PBOOK */
+
 static dldwd_priv_t*
 airport_attach(struct device_node* of_node)
 {
@@ -175,6 +231,14 @@
 
 	hermes_struct_init(hw, ndev->base_addr);
 		
+	/* Power up card */
+	feature_set_airport_power(card->node, 1);
+	current->state = TASK_UNINTERRUPTIBLE;
+	schedule_timeout(HZ);
+
+	/* Reset it before we get the interrupt */
+	hermes_reset(hw);
+
 	if (request_irq(ndev->irq, dldwd_interrupt, 0, "Airport", (void *)priv)) {
 		printk(KERN_ERR "airport: Couldn't get IRQ %d\n", ndev->irq);
 		goto failed;
@@ -198,6 +262,9 @@
 		printk(KERN_ERR "airport: Failed to create /proc node for %s\n",
 		       ndev->name);
 
+#ifdef CONFIG_PMAC_PBOOK
+	pmu_register_sleep_notifier(&airport_sleep_notifier);
+#endif
 	return priv;
 	
 failed:
@@ -219,6 +286,9 @@
 	/* Unregister proc entry */
 	dldwd_proc_dev_cleanup(priv);
 
+#ifdef CONFIG_PMAC_PBOOK
+	pmu_unregister_sleep_notifier(&airport_sleep_notifier);
+#endif
 	if (card->ndev_registered)
 		unregister_netdev(&priv->ndev);
 	card->ndev_registered = 0;
@@ -265,8 +335,6 @@
 		airport_detach(airport_dev);
 	airport_dev = NULL;
 }
-
-MODULE_DESCRIPTION("Apple Airport driver");
 
 module_init(init_airport);
 module_exit(exit_airport);
diff -u --recursive --new-file v2.4.9/linux/drivers/pci/names.c linux/drivers/pci/names.c
--- v2.4.9/linux/drivers/pci/names.c	Mon Oct  2 12:00:16 2000
+++ linux/drivers/pci/names.c	Mon Aug 27 08:47:07 2001
@@ -32,9 +32,9 @@
  * real memory.. Parse the same file multiple times
  * to get all the info.
  */
-#define VENDOR( vendor, name )		static const char __vendorstr_##vendor[] __initdata = name;
+#define VENDOR( vendor, name )		static char __vendorstr_##vendor[] __initdata = name;
 #define ENDVENDOR()
-#define DEVICE( vendor, device, name ) 	static const char __devicestr_##vendor##device[] __initdata = name;
+#define DEVICE( vendor, device, name ) 	static char __devicestr_##vendor##device[] __initdata = name;
 #include "devlist.h"
 
 
@@ -43,7 +43,7 @@
 #define DEVICE( vendor, device, name )	{ 0x##device, 0, __devicestr_##vendor##device },
 #include "devlist.h"
 
-static const struct pci_vendor_info __initdata pci_vendor_list[] = {
+static struct pci_vendor_info __initdata pci_vendor_list[] = {
 #define VENDOR( vendor, name )		{ 0x##vendor, sizeof(__devices_##vendor) / sizeof(struct pci_device_info), __vendorstr_##vendor, __devices_##vendor },
 #define ENDVENDOR()
 #define DEVICE( vendor, device, name )
diff -u --recursive --new-file v2.4.9/linux/drivers/pcmcia/yenta.c linux/drivers/pcmcia/yenta.c
--- v2.4.9/linux/drivers/pcmcia/yenta.c	Wed Jul 25 17:10:22 2001
+++ linux/drivers/pcmcia/yenta.c	Mon Aug 27 08:05:50 2001
@@ -729,7 +729,7 @@
 	if (type & IORESOURCE_IO) {
 		align = 1024;
 		size = 256;
-		min = PCIBIOS_MIN_IO;
+		min = 0x4000;
 		max = 0xffff;
 	}
 		
diff -u --recursive --new-file v2.4.9/linux/drivers/s390/block/dasd.c linux/drivers/s390/block/dasd.c
--- v2.4.9/linux/drivers/s390/block/dasd.c	Sun Aug 12 13:27:59 2001
+++ linux/drivers/s390/block/dasd.c	Mon Aug 27 14:20:21 2001
@@ -2140,13 +2140,7 @@
 	}
 	for (i = (1 << DASD_PARTN_BITS) - 1; i >= 0; i--) {
                 int major = device->major_info->gendisk.major;
-		int minor = start + i;
-		kdev_t devi = MKDEV (major, minor);
-		struct super_block *sb = get_super (devi);
-		sync_dev (devi);
-		if (sb)
-			invalidate_inodes (sb);
-		invalidate_buffers (devi);
+		invalidate_device(MKDEV (major, start+i), 1);
 	}
         dasd_destroy_partitions(device);
         dasd_setup_partitions(device);
@@ -2517,7 +2511,6 @@
 		rc = -ENODEV;
                 goto out;
 	}
-	fsync_dev (inp->i_rdev);	/* sync the device */
         count = atomic_dec_return (&device->open_count);
         if ( count == 0) {
                 invalidate_buffers (inp->i_rdev);
diff -u --recursive --new-file v2.4.9/linux/drivers/s390/block/xpram.c linux/drivers/s390/block/xpram.c
--- v2.4.9/linux/drivers/s390/block/xpram.c	Sun Aug 12 13:28:00 2001
+++ linux/drivers/s390/block/xpram.c	Mon Aug 27 14:20:21 2001
@@ -625,8 +625,7 @@
 	 */
 	if (!atomic_dec_return(&(dev->usage))) {
 		/* but flush it right now */
-		fsync_dev(inode->i_rdev);
-		invalidate_buffers(inode->i_rdev);
+		/* Everything is already flushed by caller -- AV */
 	}
 	MOD_DEC_USE_COUNT;
 	return(0);
diff -u --recursive --new-file v2.4.9/linux/drivers/sbus/char/pcikbd.c linux/drivers/sbus/char/pcikbd.c
--- v2.4.9/linux/drivers/sbus/char/pcikbd.c	Mon Aug 27 12:41:44 2001
+++ linux/drivers/sbus/char/pcikbd.c	Tue Aug 28 07:09:44 2001
@@ -1,4 +1,4 @@
-/* $Id: pcikbd.c,v 1.59 2001/08/13 14:40:08 davem Exp $
+/* $Id: pcikbd.c,v 1.61 2001/08/18 09:40:46 davem Exp $
  * pcikbd.c: Ultra/AX PC keyboard support.
  *
  * Copyright (C) 1997  Eddie C. Dost  (ecd@skynet.be)
@@ -22,6 +22,7 @@
 #include <linux/miscdevice.h>
 #include <linux/kbd_ll.h>
 #include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/smp_lock.h>
@@ -224,6 +225,17 @@
 	"\r\000/";					/* 0x60 - 0x6f */
 #endif
 
+#define DEFAULT_KEYB_REP_DELAY	250
+#define DEFAULT_KEYB_REP_RATE	30	/* cps */
+
+static struct kbd_repeat kbdrate = {
+	DEFAULT_KEYB_REP_DELAY,
+	DEFAULT_KEYB_REP_RATE
+};
+
+static unsigned char parse_kbd_rate(struct kbd_repeat *r);
+static int write_kbd_rate(unsigned char r);
+
 int pcikbd_setkeycode(unsigned int scancode, unsigned int keycode)
 {
 	if(scancode < SC_LIM || scancode > 255 || keycode > 127)
@@ -335,12 +347,7 @@
 		printk("Prom Leave: Enable Keyboard: no ACK\n");
 
 	/* Reset keyboard rate */
-	pcikbd_write(KBD_DATA_REG, KBD_CMD_SET_RATE);
-	if(pcikbd_wait_for_input() != KBD_REPLY_ACK)
-		printk("Prom Leave: Set rate: no ACK\n");
-	pcikbd_write(KBD_DATA_REG, 0x00);
-	if(pcikbd_wait_for_input() != KBD_REPLY_ACK)
-		printk("Prom Leave: Set rate: no ACK\n");
+	write_kbd_rate(parse_kbd_rate(&kbdrate));
 }
 
 int pcikbd_translate(unsigned char scancode, unsigned char *keycode,
@@ -478,8 +485,81 @@
 		send_data(KBD_CMD_ENABLE);
 }
 
-int pcikbd_rate(struct kbd_repeat *rep)
+static unsigned char parse_kbd_rate(struct kbd_repeat *r)
+{
+	static struct r2v {
+		int rate;
+		unsigned char val;
+	} kbd_rates[]={	{ 5,  0x14 },
+			{ 7,  0x10 },
+			{ 10, 0x0c },
+			{ 15, 0x08 },
+			{ 20, 0x04 },
+			{ 25, 0x02 },
+			{ 30, 0x00 } };
+	static struct d2v {
+		int delay;
+		unsigned char val;
+	} kbd_delays[]={ { 250,  0 },
+			 { 500,  1 },
+			 { 750,  2 },
+			 { 1000, 3 } };
+	int rate = 0, delay = 0;
+
+	if (r != NULL) {
+		int i, new_rate = 30, new_delay = 250;
+		if (r->rate <= 0)
+			r->rate = kbdrate.rate;
+		if (r->delay <= 0)
+			r->delay = kbdrate.delay;
+
+		for (i = 0; i < sizeof(kbd_rates) / sizeof(struct r2v); i++) {
+			if (kbd_rates[i].rate == r->rate) {
+				new_rate = kbd_rates[i].rate;
+				rate = kbd_rates[i].val;
+				break;
+			}
+		}
+		for (i=0; i < sizeof(kbd_delays) / sizeof(struct d2v); i++) {
+			if (kbd_delays[i].delay == r->delay) {
+				new_delay = kbd_delays[i].delay;
+				delay = kbd_delays[i].val;
+				break;
+			}
+		}
+		r->rate = new_rate;
+		r->delay = new_delay;
+	}
+	return (delay << 5) | rate;
+}
+
+static int write_kbd_rate(unsigned char r)
+{
+	if (!send_data(KBD_CMD_SET_RATE) || !send_data(r)) {
+		/* re-enable kbd if any errors */
+		send_data(KBD_CMD_ENABLE);
+		return 0;
+	}
+
+	return 1;
+}
+
+static int pcikbd_rate(struct kbd_repeat *rep)
 {
+	unsigned char r;
+	struct kbd_repeat old_rep;
+
+	if (rep == NULL)
+		return -EINVAL;
+
+	r = parse_kbd_rate(rep);
+	memcpy(&old_rep, &kbdrate, sizeof(struct kbd_repeat));
+	if (write_kbd_rate(r)) {
+		memcpy(&kbdrate,rep,sizeof(struct kbd_repeat));
+		memcpy(rep,&old_rep,sizeof(struct kbd_repeat));
+		return 0;
+	}
+
 	return -EIO;
 }
 
@@ -641,12 +721,7 @@
 	if(pcikbd_wait_for_input() != KBD_REPLY_ACK)
 		return "Enable keyboard: no ACK";
 
-	pcikbd_write(KBD_DATA_REG, KBD_CMD_SET_RATE);
-	if(pcikbd_wait_for_input() != KBD_REPLY_ACK)
-		return "Set rate: no ACK";
-	pcikbd_write(KBD_DATA_REG, 0x00);
-	if(pcikbd_wait_for_input() != KBD_REPLY_ACK)
-		return "Set rate: no ACK";
+	write_kbd_rate(parse_kbd_rate(&kbdrate));
 
 	return NULL; /* success */
 }
@@ -744,6 +819,7 @@
 	}
 
 	kd_mksound = nop_kd_mksound;
+	kbd_rate = pcikbd_rate;
 
 #ifdef __sparc_v9__
 	edev = 0;
diff -u --recursive --new-file v2.4.9/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c
--- v2.4.9/linux/drivers/scsi/sr.c	Wed Jul 25 17:10:23 2001
+++ linux/drivers/scsi/sr.c	Mon Aug 27 14:20:21 2001
@@ -101,7 +101,6 @@
 {
 	if (scsi_CDs[MINOR(cdi->dev)].device->sector_size > 2048)
 		sr_set_blocklength(MINOR(cdi->dev), 2048);
-	sync_dev(cdi->dev);
 	scsi_CDs[MINOR(cdi->dev)].device->access_count--;
 	if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module)
 		__MOD_DEC_USE_COUNT(scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module);
diff -u --recursive --new-file v2.4.9/linux/drivers/sgi/char/ds1286.c linux/drivers/sgi/char/ds1286.c
--- v2.4.9/linux/drivers/sgi/char/ds1286.c	Mon Aug 27 12:41:45 2001
+++ linux/drivers/sgi/char/ds1286.c	Mon Aug 27 08:56:31 2001
@@ -1,32 +1,30 @@
-/* $Id: ds1286.c,v 1.6 1999/10/09 00:01:31 ralf Exp $
- *
- *	Real Time Clock interface for Linux	
+/*
+ * DS1286 Real Time Clock interface for Linux	
  *
- *	Copyright (C) 1998, 1999 Ralf Baechle
+ * Copyright (C) 1998, 1999, 2000 Ralf Baechle
  *	
- *	Based on code written by Paul Gortmaker.
+ * Based on code written by Paul Gortmaker.
  *
- *	This driver allows use of the real time clock (built into
- *	nearly all computers) from user space. It exports the /dev/rtc
- *	interface supporting various ioctl() and also the /proc/rtc
- *	pseudo-file for status information.
+ * This driver allows use of the real time clock (built into nearly all
+ * computers) from user space. It exports the /dev/rtc interface supporting
+ * various ioctl() and also the /proc/rtc pseudo-file for status
+ * information.
  *
- *	The ioctls can be used to set the interrupt behaviour and
- *	generation rate from the RTC via IRQ 8. Then the /dev/rtc
- *	interface can be used to make use of these timer interrupts,
- *	be they interval or alarm based.
+ * The ioctls can be used to set the interrupt behaviour and generation rate
+ * from the RTC via IRQ 8. Then the /dev/rtc interface can be used to make
+ * use of these timer interrupts, be they interval or alarm based.
  *
- *	The /dev/rtc interface will block on reads until an interrupt
- *	has been received. If a RTC interrupt has already happened,
- *	it will output an unsigned long and then block. The output value
- *	contains the interrupt status in the low byte and the number of
- *	interrupts since the last read in the remaining high bytes. The 
- *	/dev/rtc interface can also be used with the select(2) call.
+ * The /dev/rtc interface will block on reads until an interrupt has been
+ * received. If a RTC interrupt has already happened, it will output an
+ * unsigned long and then block. The output value contains the interrupt
+ * status in the low byte and the number of interrupts since the last read
+ * in the remaining high bytes. The /dev/rtc interface can also be used with
+ * the select(2) call.
  *
- *	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 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/types.h>
 #include <linux/errno.h>
@@ -38,7 +36,6 @@
 #include <linux/poll.h>
 #include <linux/rtc.h>
 #include <linux/spinlock.h>
-#include <linux/smp_lock.h>
 
 #include <asm/ds1286.h>
 #include <asm/io.h>
@@ -81,58 +78,20 @@
 #define RTC_IS_OPEN		0x01	/* means /dev/rtc is in use	*/
 #define RTC_TIMER_ON		0x02	/* missed irq timer active	*/
 
-unsigned char ds1286_status = 0;	/* bitmapped status byte.	*/
-unsigned long ds1286_freq = 0;		/* Current periodic IRQ rate	*/
-unsigned long ds1286_irq_data = 0;	/* our output to the world	*/
+unsigned char ds1286_status;		/* bitmapped status byte.	*/
+unsigned long ds1286_freq;		/* Current periodic IRQ rate	*/
 
 unsigned char days_in_mo[] = 
 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
 
 /*
- *	A very tiny interrupt handler. It runs with SA_INTERRUPT set,
- *	so that there is no possibility of conflicting with the
- *	set_rtc_mmss() call that happens during some timer interrupts.
- *	(See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.)
- */
-
-/*
  *	Now all the various file operations that we export.
  */
 
 static ssize_t ds1286_read(struct file *file, char *buf,
                            size_t count, loff_t *ppos)
 {
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned long data;
-	ssize_t retval;
-	
-	if (count < sizeof(unsigned long))
-		return -EINVAL;
-
-	add_wait_queue(&ds1286_wait, &wait);
-
-	current->state = TASK_INTERRUPTIBLE;
-		
-	while ((data = xchg(&ds1286_irq_data, 0)) == 0) {
-		if (file->f_flags & O_NONBLOCK) {
-			retval = -EAGAIN;
-			goto out;
-		}
-		if (signal_pending(current)) {
-			retval = -ERESTARTSYS;
-			goto out;
-		}
-		schedule();
-	}
-
-	retval = put_user(data, (unsigned long *)buf); 
-	if (!retval)
-		retval = sizeof(unsigned long); 
- out:
-	current->state = TASK_RUNNING;
-	remove_wait_queue(&ds1286_wait, &wait);
-
-	return retval;
+	return -EIO;
 }
 
 static int ds1286_ioctl(struct inode *inode, struct file *file,
@@ -338,27 +297,32 @@
 
 static int ds1286_open(struct inode *inode, struct file *file)
 {
-	if(ds1286_status & RTC_IS_OPEN)
-		return -EBUSY;
+	spin_lock_irq(&ds1286_lock);
+
+	if (ds1286_status & RTC_IS_OPEN)
+		goto out_busy;
 
 	ds1286_status |= RTC_IS_OPEN;
-	ds1286_irq_data = 0;
+
+	spin_lock_irq(&ds1286_lock);
 	return 0;
+
+out_busy:
+	spin_lock_irq(&ds1286_lock);
+	return -EBUSY;
 }
 
 static int ds1286_release(struct inode *inode, struct file *file)
 {
-	lock_kernel();
 	ds1286_status &= ~RTC_IS_OPEN;
-	unlock_kernel();
+
 	return 0;
 }
 
 static unsigned int ds1286_poll(struct file *file, poll_table *wait)
 {
 	poll_wait(file, &ds1286_wait, wait);
-	if (ds1286_irq_data != 0)
-		return POLLIN | POLLRDNORM;
+
 	return 0;
 }
 
@@ -407,7 +371,7 @@
 
 	get_rtc_time(&tm);
 	hundredth = CMOS_READ(RTC_HUNDREDTH_SECOND);
-	hundredth = BCD_TO_BIN(hundredth);
+	BCD_TO_BIN(hundredth);
 
 	p += sprintf(p,
 	             "rtc_time\t: %02d:%02d:%02d.%02d\n"
diff -u --recursive --new-file v2.4.9/linux/drivers/sgi/char/graphics.c linux/drivers/sgi/char/graphics.c
--- v2.4.9/linux/drivers/sgi/char/graphics.c	Mon Mar 19 12:35:09 2001
+++ linux/drivers/sgi/char/graphics.c	Mon Aug 27 08:56:31 2001
@@ -1,5 +1,4 @@
-/* $Id: graphics.c,v 1.22 2000/02/18 00:24:43 ralf Exp $
- *
+/*
  * gfx.c: support for SGI's /dev/graphics, /dev/opengl
  *
  * Author: Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -214,8 +213,7 @@
 /* 
  * This is the core of the direct rendering engine.
  */
-
-unsigned long
+struct page *
 sgi_graphics_nopage (struct vm_area_struct *vma, unsigned long address, int
 		     no_share)
 {
@@ -250,7 +248,6 @@
 	pgd = pgd_offset(current->mm, address);
 	pmd = pmd_offset(pgd, address);
 	pte = pte_offset(pmd, address);
-	printk("page: %08lx\n", pte_page(*pte));
 	return pte_page(*pte);
 }
 
diff -u --recursive --new-file v2.4.9/linux/drivers/sgi/char/graphics_syms.c linux/drivers/sgi/char/graphics_syms.c
--- v2.4.9/linux/drivers/sgi/char/graphics_syms.c	Mon Feb 28 07:18:20 2000
+++ linux/drivers/sgi/char/graphics_syms.c	Wed Dec 31 16:00:00 1969
@@ -1,35 +0,0 @@
-/*
- * graphics_syms.c: interfaces for SGI Indy newport graphics
- *
- * Copyright (C) 1999 Alex deVries <puffin@redhat.com>
- *
- * We should not even be trying to compile this if we are not doing
- * a module.
- */
-
-#define __NO_VERSION__
-#include <linux/module.h>
-
-/* extern int rrm_command (unsigned int cmd, void *arg);
-extern int rrm_close (struct inode *inode, struct file *file);
-EXPORT_SYMBOL(rrm_command);
-EXPORT_SYMBOL(rrm_close);
-
-
-*/
-extern void shmiq_init (void);
-extern void usema_init(void);
-
-EXPORT_SYMBOL(shmiq_init);
-EXPORT_SYMBOL(usema_init);
-
-extern void disable_gconsole(void);
-extern void enable_gconsole(void);
-extern void remove_mapping (struct task_struct *task, unsigned long start,
-      unsigned long end);
-
-EXPORT_SYMBOL(disable_gconsole);
-EXPORT_SYMBOL(enable_gconsole);
-EXPORT_SYMBOL(remove_mapping);
-
-EXPORT_SYMBOL(npregs);
diff -u --recursive --new-file v2.4.9/linux/drivers/sgi/char/newport.c linux/drivers/sgi/char/newport.c
--- v2.4.9/linux/drivers/sgi/char/newport.c	Mon Feb 28 07:18:20 2000
+++ linux/drivers/sgi/char/newport.c	Mon Aug 27 08:56:31 2001
@@ -16,6 +16,8 @@
 
 struct newport_regs *npregs;
 
+EXPORT_SYMBOL(npregs);
+
 /* Kernel routines for supporting graphics context switching */
 
 void newport_save (void *y)
diff -u --recursive --new-file v2.4.9/linux/drivers/sgi/char/rrm.c linux/drivers/sgi/char/rrm.c
--- v2.4.9/linux/drivers/sgi/char/rrm.c	Tue Aug 29 14:09:15 2000
+++ linux/drivers/sgi/char/rrm.c	Mon Aug 27 08:56:31 2001
@@ -9,12 +9,11 @@
  *
  * Fixes:
  */
+#include <linux/module.h>
+
 #include <asm/uaccess.h>
 #include <asm/rrm.h>
 
-#ifdef MODULE
-#include <linux/module.h>
-#endif
 
 int
 rrm_open_rn (int rnid, void *arg)
@@ -71,3 +70,6 @@
 	/* This routine is invoked when the device is closed */
 	return 0;
 }
+
+EXPORT_SYMBOL(rrm_command);
+EXPORT_SYMBOL(rrm_close);
diff -u --recursive --new-file v2.4.9/linux/drivers/sgi/char/sgicons.c linux/drivers/sgi/char/sgicons.c
--- v2.4.9/linux/drivers/sgi/char/sgicons.c	Sun Jul  9 22:32:58 2000
+++ linux/drivers/sgi/char/sgicons.c	Mon Aug 27 08:56:31 2001
@@ -1,5 +1,4 @@
-/* $Id: sgicons.c,v 1.10 1998/08/25 09:18:58 ralf Exp $
- *
+/*
  * sgicons.c: Setting up and registering console I/O on the SGI.
  *
  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -10,12 +9,10 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
+#include <linux/module.h>
 #include <asm/uaccess.h>
 #include "gconsole.h"
 
-/* To make psaux code cleaner */
-unsigned char aux_device_present = 0xaa;
-
 /* This is the system graphics console (the first adapter found) */
 struct console_ops *gconsole = 0;
 struct console_ops *real_gconsole = 0;
@@ -35,6 +32,9 @@
 		gconsole = 0;
 	}
 }
+
+EXPORT_SYMBOL(disable_gconsole);
+EXPORT_SYMBOL(enable_gconsole);
 
 void
 register_gconsole (struct console_ops *gc)
diff -u --recursive --new-file v2.4.9/linux/drivers/sgi/char/sgiserial.c linux/drivers/sgi/char/sgiserial.c
--- v2.4.9/linux/drivers/sgi/char/sgiserial.c	Thu Oct 12 14:20:47 2000
+++ linux/drivers/sgi/char/sgiserial.c	Mon Aug 27 08:56:31 2001
@@ -13,6 +13,9 @@
  * thorough pass to merge in the rest of the updates.
  * Better still, someone really ought to make it a common
  * code module for both platforms.   kevink@mips.com
+ *
+ * 20010616 - Klaus Naumann <spock@mgnet.de> : Make serial console work with
+ *                                             any speed - not only 9600
  */
 
 #include <linux/config.h> /* for CONFIG_REMOTE_DEBUG */
@@ -58,9 +61,9 @@
 static int zilog_irq = SGI_SERIAL_IRQ;
 
 /* Console hooks... */
-static int zs_cons_chanout = 0;
-static int zs_cons_chanin = 0;
-struct sgi_serial *zs_consinfo = 0;
+static int zs_cons_chanout;
+static int zs_cons_chanin;
+struct sgi_serial *zs_consinfo;
 
 static unsigned char kgdb_regs[16] = {
 	0, 0, 0,                     /* write 0, 1, 2 */
@@ -97,6 +100,7 @@
 DECLARE_TASK_QUEUE(tq_serial);
 
 struct tty_driver serial_driver, callout_driver;
+struct console *sgisercon;
 static int serial_refcount;
 
 /* serial subtype definitions */
@@ -144,10 +148,10 @@
 					dev_t device, const char *routine)
 {
 #ifdef SERIAL_PARANOIA_CHECK
-	static const char *badmagic =
+	static const char *badmagic = KERN_WARNING
 		"Warning: bad magic number for serial struct (%d, %d) in %s\n";
-	static const char *badinfo =
-		"Warning: null sun_serial for (%d, %d) in %s\n";
+	static const char *badinfo = KERN_WARNING
+		"Warning: null sgi_serial for (%d, %d) in %s\n";
 
 	if (!info) {
 		printk(badinfo, MAJOR(device), MINOR(device), routine);
@@ -178,7 +182,8 @@
  * interrupts are enabled. Therefore we have to check ioc_iocontrol before we
  * access it.
  */
-static inline unsigned char read_zsreg(struct sgi_zschannel *channel, unsigned char reg)
+static inline unsigned char read_zsreg(struct sgi_zschannel *channel,
+                                       unsigned char reg)
 {
 	unsigned char retval;
 	volatile unsigned char junk;
@@ -192,7 +197,8 @@
 	return retval;
 }
 
-static inline void write_zsreg(struct sgi_zschannel *channel, unsigned char reg, unsigned char value)
+static inline void write_zsreg(struct sgi_zschannel *channel,
+                               unsigned char reg, unsigned char value)
 {
 	volatile unsigned char junk;
 
@@ -323,7 +329,7 @@
  */
 static void batten_down_hatches(void)
 {
-	prom_imode();
+	ArcEnterInteractiveMode();
 #if 0
 	/* If we are doing kadb, we call the debugger
 	 * else we just drop into the boot monitor.
@@ -682,7 +688,7 @@
 	save_flags(flags); cli();
 
 #ifdef SERIAL_DEBUG_OPEN
-	printk("starting up ttys%d (irq %d)...", info->line, info->irq);
+	printk("starting up ttys%d (irq %d)...\n", info->line, info->irq);
 #endif
 
 	/*
@@ -1302,6 +1308,59 @@
 	junk = ioc_icontrol->istat0;
 	sti();
 	return put_user(status,value);
+} 
+
+static int get_modem_info(struct sgi_serial * info, unsigned int *value)
+{
+	unsigned char status;
+	unsigned int result;
+
+	cli();
+	status = info->zs_channel->control;
+	udelay(2);
+	sti();
+	result =  ((info->curregs[5] & RTS) ? TIOCM_RTS : 0)
+		| ((info->curregs[5] & DTR) ? TIOCM_DTR : 0)
+		| ((status  & DCD) ? TIOCM_CAR : 0)
+		| ((status  & SYNC) ? TIOCM_DSR : 0)
+		| ((status  & CTS) ? TIOCM_CTS : 0);
+	if (put_user(result, value))
+		return -EFAULT;
+	return 0;
+}
+
+static int set_modem_info(struct sgi_serial * info, unsigned int cmd,
+			  unsigned int *value)
+{
+	unsigned int arg;
+
+	if (get_user(arg, value))
+		return -EFAULT;
+	switch (cmd) {
+	case TIOCMBIS: 
+		if (arg & TIOCM_RTS)
+			info->curregs[5] |= RTS;
+		if (arg & TIOCM_DTR)
+			info->curregs[5] |= DTR;
+		break;
+	case TIOCMBIC:
+		if (arg & TIOCM_RTS)
+			info->curregs[5] &= ~RTS;
+		if (arg & TIOCM_DTR)
+			info->curregs[5] &= ~DTR;
+		break;
+	case TIOCMSET:
+		info->curregs[5] = ((info->curregs[5] & ~(RTS | DTR))
+			     | ((arg & TIOCM_RTS) ? RTS : 0)
+			     | ((arg & TIOCM_DTR) ? DTR : 0));
+		break;
+	default:
+		return -EINVAL;
+	}
+	cli();
+	write_zsreg(info->zs_channel, 5, info->curregs[5]);
+	sti();
+	return 0;
 }
 
 /*
@@ -1322,11 +1381,10 @@
 static int rs_ioctl(struct tty_struct *tty, struct file * file,
 		    unsigned int cmd, unsigned long arg)
 {
-	int error;
-	struct sgi_serial * info = (struct sgi_serial *)tty->driver_data;
+	struct sgi_serial * info = (struct sgi_serial *) tty->driver_data;
 	int retval;
 
-	if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
+	if (serial_paranoia_check(info, tty->device, "zs_ioctl"))
 		return -ENODEV;
 
 	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
@@ -1353,45 +1411,36 @@
 			send_break(info, arg ? arg*(HZ/10) : HZ/4);
 			return 0;
 		case TIOCGSOFTCAR:
-			error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
-			if (error)
-				return error;
-			put_user(C_CLOCAL(tty) ? 1 : 0,
-			         (unsigned long *) arg);
+			if (put_user(C_CLOCAL(tty) ? 1 : 0,
+				     (unsigned long *) arg))
+				return -EFAULT;
 			return 0;
 		case TIOCSSOFTCAR:
-			error = get_user(arg, (unsigned long *)arg);
-			if (error)
-				return error;
+			if (get_user(arg, (unsigned long *) arg))
+				return -EFAULT;
 			tty->termios->c_cflag =
 				((tty->termios->c_cflag & ~CLOCAL) |
 				 (arg ? CLOCAL : 0));
 			return 0;
+		case TIOCMGET:
+			return get_modem_info(info, (unsigned int *) arg);
+		case TIOCMBIS:
+		case TIOCMBIC:
+		case TIOCMSET:
+			return set_modem_info(info, cmd, (unsigned int *) arg);
 		case TIOCGSERIAL:
-			error = verify_area(VERIFY_WRITE, (void *) arg,
-						sizeof(struct serial_struct));
-			if (error)
-				return error;
 			return get_serial_info(info,
 					       (struct serial_struct *) arg);
 		case TIOCSSERIAL:
 			return set_serial_info(info,
 					       (struct serial_struct *) arg);
 		case TIOCSERGETLSR: /* Get line status register */
-			error = verify_area(VERIFY_WRITE, (void *) arg,
-				sizeof(unsigned int));
-			if (error)
-				return error;
-			else
-			    return get_lsr_info(info, (unsigned int *) arg);
+			return get_lsr_info(info, (unsigned int *) arg);
 
 		case TIOCSERGSTRUCT:
-			error = verify_area(VERIFY_WRITE, (void *) arg,
-						sizeof(struct sgi_serial));
-			if (error)
-				return error;
-			copy_to_user((struct sun_serial *) arg,
-				    info, sizeof(struct sgi_serial));
+			if (copy_to_user((struct sgi_serial *) arg,
+				    info, sizeof(struct sgi_serial)))
+				return -EFAULT;
 			return 0;
 			
 		default:
@@ -1727,11 +1776,19 @@
 		change_speed(info);
 	}
 
+	/* If this is the serial console change the speed to 
+	 * the right value
+	 */
+	if (info->is_cons) {
+		info->tty->termios->c_cflag = sgisercon->cflag;
+		change_speed(info);		
+	}
+
 	info->session = current->session;
 	info->pgrp = current->pgrp;
 
 #ifdef SERIAL_DEBUG_OPEN
-	printk("rs_open ttys%d successful...", info->line);
+	printk("rs_open ttys%d successful...\n", info->line);
 #endif
 	return 0;
 }
@@ -1748,13 +1805,10 @@
 {
 	extern struct hpc3_miscregs *hpc3mregs;
 
-	if(chip > 0) {
-		prom_printf("Wheee, bogus zs chip number requested.\n");
-		prom_getchar();
-		romvec->imode();
-	}
-	return (struct sgi_zslayout *) (&hpc3mregs->ser1cmd);
+	if (chip > 0)
+		panic("Wheee, bogus zs chip number requested.");
 
+	return (struct sgi_zslayout *) (&hpc3mregs->ser1cmd);
 }
 
 
@@ -1784,13 +1838,6 @@
 	}
 	if(o && i)
 		io = 1;
-	if(ss->zs_baud != 9562) { /* Don't ask... */
-		prom_printf("BAD console baud rate %d\n", ss->zs_baud);
-		prom_getchar();
-		prom_imode();
-		panic("Console baud rate weirdness");
-	}
-
 
 	/* Set flag variable for this port so that it cannot be
 	 * opened for other uses by accident.
@@ -1798,7 +1845,7 @@
 	ss->is_cons = 1;
 
 	if(io) {
-		if(!msg_printed) {
+		if (!msg_printed) {
 			printk("zs%d: console I/O\n", ((channel>>1)&1));
 			msg_printed = 1;
 		}
@@ -1806,7 +1853,6 @@
 	} else {
 		printk("zs%d: console %s\n", ((channel>>1)&1),
 		       (i==1 ? "input" : (o==1 ? "output" : "WEIRD")));
-
 	}
 }
 
@@ -2002,7 +2048,6 @@
 rs_cons_hook(int chip, int out, int line)
 {
 	int channel;
-
 	
 	if(chip)
 		panic("rs_cons_hook called with chip not zero");
@@ -2087,11 +2132,11 @@
 static int __init zs_console_setup(struct console *con, char *options)
 {
 	struct sgi_serial *info;
-	int	baud = 9600;
+	int	baud;
 	int	bits = 8;
 	int	parity = 'n';
 	int	cflag = CREAD | HUPCL | CLOCAL;
-	char	*s;
+	char	*s, *dbaud;
 	int     i, brg;
     
 	if (options) {
@@ -2102,6 +2147,21 @@
 		if (*s) parity = *s++;
 		if (*s) bits   = *s - '0';
 	}
+	else {
+		/* If the user doesn't set console=... try to read the
+		 * PROM variable - if this fails use 9600 baud and
+		 * inform the user about the problem
+		 */
+		dbaud = ArcGetEnvironmentVariable("dbaud");
+		if(dbaud) baud = simple_strtoul(dbaud, NULL, 10);
+		else {
+			/* Use prom_printf() to make sure that the user
+			 * is getting anything ...
+			 */
+			prom_printf("No dbaud set in PROM ?!? Using 9600.\n");
+			baud = 9600;
+		}
+	}
 
 	/*
 	 *	Now construct a cflag setting.
@@ -2156,7 +2216,8 @@
 	info = zs_soft + con->index;
 	info->is_cons = 1;
     
-	printk("Console: ttyS%d (Zilog8530)\n", info->line);
+	printk("Console: ttyS%d (Zilog8530), %d baud\n", 
+						info->line, baud);
 
 	i = con->cflag & CBAUD;
 	if (con->cflag & CBAUDEX) {
@@ -2195,6 +2256,8 @@
 		zscons_regs[4] |= SB2;
 	else
 		zscons_regs[4] |= SB1;
+	
+	sgisercon = con;
 
 	brg = BPS_TO_BRG(baud, ZS_CLOCK / info->clk_divisor);
 	zscons_regs[12] = brg & 0xff;
diff -u --recursive --new-file v2.4.9/linux/drivers/sgi/char/sgiserial.h linux/drivers/sgi/char/sgiserial.h
--- v2.4.9/linux/drivers/sgi/char/sgiserial.h	Fri Jun 25 17:39:34 1999
+++ linux/drivers/sgi/char/sgiserial.h	Mon Aug 27 08:56:31 2001
@@ -359,7 +359,7 @@
 #define	ZCOUNT		0x2	/* Zero count */
 #define	Tx_BUF_EMP	0x4	/* Tx Buffer empty */
 #define	DCD		0x8	/* DCD */
-#define	SYNC_HUNT	0x10	/* Sync/hunt */
+#define	SYNC		0x10	/* Sync/hunt */
 #define	CTS		0x20	/* CTS */
 #define	TxEOM		0x40	/* Tx underrun */
 #define	BRK_ABRT	0x80	/* Break/Abort */
diff -u --recursive --new-file v2.4.9/linux/drivers/sgi/char/shmiq.c linux/drivers/sgi/char/shmiq.c
--- v2.4.9/linux/drivers/sgi/char/shmiq.c	Mon Mar 19 12:35:09 2001
+++ linux/drivers/sgi/char/shmiq.c	Mon Aug 27 08:56:31 2001
@@ -1,5 +1,4 @@
-/* $Id: shmiq.c,v 1.19 2000/02/23 00:41:21 ralf Exp $
- *
+/*
  * shmiq.c: shared memory input queue driver
  * written 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
  *
@@ -42,7 +41,6 @@
  * Until then, I just allow for 1 qcntl device.
  *
  */
-
 #include <linux/fs.h>
 #include <linux/miscdevice.h>
 #include <linux/sched.h>
@@ -52,6 +50,7 @@
 #include <linux/vmalloc.h>
 #include <linux/wait.h>
 #include <linux/major.h>
+#include <linux/module.h>
 #include <linux/smp_lock.h>
 #include <linux/devfs_fs_kernel.h>
 
@@ -470,3 +469,5 @@
 			       S_IFCHR | S_IRUSR | S_IWUSR,
 			       &shmiq_fops, NULL);
 }
+
+EXPORT_SYMBOL(shmiq_init);
diff -u --recursive --new-file v2.4.9/linux/drivers/sgi/char/usema.c linux/drivers/sgi/char/usema.c
--- v2.4.9/linux/drivers/sgi/char/usema.c	Wed Jul 12 21:58:43 2000
+++ linux/drivers/sgi/char/usema.c	Mon Aug 27 08:56:31 2001
@@ -20,8 +20,7 @@
  * usema(7m), usinit(3p), usnewsema(3p)
  * /usr/include/sys/usioctl.h 
  *
-*/
-
+ */
 #include <linux/fs.h>
 #include <linux/miscdevice.h>
 #include <linux/sched.h>
@@ -31,6 +30,7 @@
 #include <linux/string.h>
 #include <linux/dcache.h>
 #include <linux/mm.h>
+#include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/smp_lock.h>
 #include "usema.h"
@@ -180,3 +180,5 @@
 	       SGI_USEMACLONE);
 	misc_register(&dev_usemaclone);
 }
+
+EXPORT_SYMBOL(usema_init);
diff -u --recursive --new-file v2.4.9/linux/drivers/sound/awe_wave.c linux/drivers/sound/awe_wave.c
--- v2.4.9/linux/drivers/sound/awe_wave.c	Fri Mar  2 11:12:11 2001
+++ linux/drivers/sound/awe_wave.c	Mon Aug 27 08:11:43 2001
@@ -4873,7 +4873,7 @@
 /* any three numbers you like */
 #define UNIQUE_ID1	0x1234
 #define UNIQUE_ID2	0x4321
-#define UNIQUE_ID3	0xFFFF
+#define UNIQUE_ID3	0xABCD
 
 static void __init
 awe_check_dram(void)
diff -u --recursive --new-file v2.4.9/linux/drivers/tc/lk201-map.map linux/drivers/tc/lk201-map.map
--- v2.4.9/linux/drivers/tc/lk201-map.map	Wed Dec 31 16:00:00 1969
+++ linux/drivers/tc/lk201-map.map	Mon Aug 27 08:56:31 2001
@@ -0,0 +1,356 @@
+# Default kernel keymap. This uses 7 modifier combinations.
+keymaps 0-2,4-5,8,12
+# Change the above line into
+#	keymaps 0-2,4-6,8,12
+# in case you want the entries
+#	altgr   control keycode  83 = Boot            
+#	altgr   control keycode 111 = Boot            
+# below.
+#
+# In fact AltGr is used very little, and one more keymap can
+# be saved by mapping AltGr to Alt (and adapting a few entries):
+# keycode 100 = Alt
+#
+keycode   0x15 = grave		tilde
+	alt     keycode   0x15 = Escape
+	control keycode   0x15 = Meta_Escape
+keycode   0x16 = one              exclam
+	alt     keycode   0x16 = Meta_one
+keycode   0x17 = two              at               at
+	control	keycode   0x17 = nul
+	shift	control	keycode   0x17 = nul
+	alt	keycode   0x17 = Meta_two
+keycode   0x18 = three            numbersign
+	control keycode   0x18 = Escape
+	alt     keycode   0x18 = Meta_three
+keycode   0x19 = four             dollar           dollar
+	control keycode   0x19 = Control_backslash
+	alt     keycode   0x19 = Meta_four
+keycode   0x1a = five             percent
+	control keycode   0x1a = Control_bracketright
+	alt     keycode   0x1a = Meta_five
+keycode   0x1b = six              asciicircum
+	control keycode   0x1b = Control_asciicircum
+	alt     keycode   0x1b = Meta_six
+keycode   0x1c = seven            ampersand        braceleft
+	control keycode   0x1c = Control_underscore
+	alt     keycode   0x1c = Meta_seven
+keycode   0x1d = eight            asterisk         bracketleft
+	control keycode   0x1d = Delete
+	alt     keycode   0x1d = Meta_eight
+keycode  0x1e = nine             parenleft        bracketright
+	alt     keycode  0x1e = Meta_nine
+keycode  0x1f = zero             parenright       braceright
+	alt     keycode  0x1f = Meta_zero
+keycode  0x20 = minus            underscore       backslash
+	control	keycode  0x20 = Control_underscore
+	shift	control	keycode  0x20 = Control_underscore
+	alt	keycode  0x20 = Meta_minus
+keycode  0x21 = equal            plus
+	alt     keycode  0x21 = Meta_equal
+keycode  0x22 = Delete           Delete
+	control keycode  0x22 = BackSpace
+	alt     keycode  0x22 = Meta_Delete
+keycode  0x2a = Tab              Tab
+	alt     keycode  0x2a = Meta_Tab
+keycode  0x2b = q
+keycode  0x2c = w
+keycode  0x2d = e
+	altgr   keycode  0x2d = Hex_E
+keycode  0x2e = r
+keycode  0x2f = t
+keycode  0x30 = y
+keycode  0x31 = u
+keycode  0x32 = i
+keycode  0x33 = o
+keycode  0x34 = p
+keycode  0x35 = bracketleft      braceleft
+	control keycode  0x35 = Escape
+	alt     keycode  0x35 = Meta_bracketleft
+keycode  0x36 = bracketright     braceright       asciitilde
+	control keycode  0x36 = Control_bracketright
+	alt     keycode  0x36 = Meta_bracketright
+keycode  0x37 = Return
+	alt     keycode  0x37 = Meta_Control_m
+keycode  0x3f = Control
+keycode  0x41 = a
+	altgr   keycode  0x41 = Hex_A
+keycode  0x42 = s
+keycode  0x43 = d
+	altgr   keycode  0x43 = Hex_D
+keycode  0x44 = f
+	altgr   keycode  0x44 = Hex_F
+keycode  0x45 = g
+keycode  0x46 = h
+keycode  0x47 = j
+keycode  0x48 = k
+keycode  0x49 = l
+keycode  0x4a = semicolon        colon
+	alt     keycode  0x4a = Meta_semicolon
+keycode  0x4b = apostrophe       quotedbl
+	control keycode  0x4b = Control_g
+	alt     keycode  0x4b = Meta_apostrophe
+# keycode  41 = grave            asciitilde
+#	control keycode  41 = nul
+#	alt     keycode  41 = Meta_grave
+keycode  0x52 = Shift
+keycode  0x4c = backslash        bar
+	control keycode  0x4c = Control_backslash
+	alt     keycode  0x4c = Meta_backslash
+keycode  0x53 = greater	less
+keycode  0x54 = z
+keycode  0x55 = x
+keycode  0x56 = c
+	altgr   keycode  0x56 = Hex_C
+keycode  0x57 = v
+keycode  0x58 = b
+	altgr   keycode  0x58 = Hex_B
+keycode  0x59 = n
+keycode  0x5a = m
+keycode  0x5b = comma            less
+	alt     keycode  0x5b = Meta_comma
+keycode  0x5c = period           greater
+	control keycode  0x5c = Compose
+	alt     keycode  0x5c = Meta_period
+keycode  0x5d = slash            question
+	control keycode  0x5d = Delete
+	alt     keycode  0x5d = Meta_slash
+
+keycode  0x67 = Alt
+keycode  0x68 = space            space
+	control keycode  0x68 = nul
+	alt     keycode  0x68 = Meta_space
+keycode  0x40 = Caps_Lock
+keycode  0x01 = F1
+	control keycode  0x01 = F1
+	alt     keycode  0x01 = Console_1
+	control alt     keycode  0x01 = Console_1
+keycode  0x02 = F2
+	control keycode  0x02 = F2
+	alt     keycode  0x02 = Console_2
+	control alt     keycode  0x02 = Console_2
+keycode  0x03 = F3
+	control keycode  0x03 = F3
+	alt     keycode  0x03 = Console_3
+	control alt     keycode  0x03 = Console_3
+keycode  0x04 = F4
+	control keycode  0x04 = F4
+	alt     keycode  0x04 = Console_4
+	control alt     keycode  0x04 = Console_4
+keycode  0x05 = F5
+	control keycode  0x05 = F5
+	alt     keycode  0x05 = Console_5
+	control alt     keycode  0x05 = Console_5
+keycode  0x06 = F6
+	control keycode  0x06 = F6
+	alt     keycode  0x06 = Console_6
+	control alt     keycode  0x06 = Console_6
+keycode  0x07 = F7
+	control keycode  0x07 = F7
+	alt     keycode  0x07 = Console_7
+	control alt     keycode  0x07 = Console_7
+keycode  0x08 = F8
+	control keycode  0x08 = F8
+	alt     keycode  0x08 = Console_8
+	control alt     keycode  0x08 = Console_8
+keycode  0x09 = F9
+	control keycode  0x09 = F9
+	alt     keycode  0x09 = Console_9
+	control alt     keycode  0x09 = Console_9
+keycode  0x0a = F10
+	control keycode  0x0a = F10
+	alt     keycode  0x0a = Console_10
+	control alt     keycode  0x0a = Console_10
+keycode  0x0b = F11
+	control keycode  0x0b = F11
+	alt     keycode  0x0b = Console_11
+	control alt     keycode  0x0b = Console_11
+keycode  0x0c = F12
+	control keycode  0x0c = F12
+	alt     keycode  0x0c = Console_12
+	control alt     keycode  0x0c = Console_12
+keycode  0x0d = F13
+	control keycode  0x0d = F13
+	alt     keycode  0x0d = Console_13
+	control alt     keycode  0x0d = Console_13
+keycode  0x0e = F14
+	control keycode  0x0e = F14
+	alt     keycode  0x0e = Console_14
+	control alt     keycode  0x0e = Console_14
+
+keycode  0x11 = F17
+	control keycode  0x11 = F17
+	alt     keycode  0x11 = Console_17
+	control alt     keycode  0x11 = Console_17
+keycode  0x12 = F18
+	control keycode  0x12 = F18
+	alt     keycode  0x12 = Console_18
+	control alt     keycode  0x12 = Console_18
+keycode  0x13 = F19
+	control keycode  0x13 = F19
+	alt     keycode  0x13 = Console_19
+	control alt     keycode  0x13 = Console_19
+keycode  0x14 = F20
+	control keycode  0x14 = F20
+	alt     keycode  0x14 = Console_20
+	control alt     keycode  0x14 = Console_20
+
+
+keycode  0x3b = KP_7
+	alt     keycode  0x3b = Ascii_7
+	altgr   keycode  0x3b = Hex_7
+keycode  0x3c = KP_8
+	alt     keycode  0x3c = Ascii_8
+	altgr   keycode  0x3c = Hex_8
+keycode  0x3d = KP_9
+	alt     keycode  0x3d = Ascii_9
+	altgr   keycode  0x3d = Hex_9
+keycode  0x3e = KP_Subtract
+keycode  0x4e = KP_4
+	alt     keycode  0x4e = Ascii_4
+	altgr   keycode  0x4e = Hex_4
+keycode  0x4f = KP_5
+	alt     keycode  0x4f = Ascii_5
+	altgr   keycode  0x4f = Hex_5
+keycode  0x50 = KP_6
+	alt     keycode  0x50 = Ascii_6
+	altgr   keycode  0x50 = Hex_6
+keycode  0x62 = KP_1
+	alt     keycode  0x62 = Ascii_1
+	altgr   keycode  0x62 = Hex_1
+keycode  0x63 = KP_2
+	alt     keycode  0x63 = Ascii_2
+	altgr   keycode  0x63 = Hex_2
+keycode  0x64 = KP_3
+	alt     keycode  0x64 = Ascii_3
+	altgr   keycode  0x64 = Hex_3
+keycode  0x6b = KP_0
+	alt     keycode  0x6b = Ascii_0
+	altgr   keycode  0x6b = Hex_0
+keycode  0x6c = KP_Period
+#	altgr   control keycode  0x6c = Boot
+	control alt     keycode  0x6c = Boot
+keycode  0x65 = KP_Enter
+
+keycode  0x3f = Control
+
+# keycode 100 = AltGr
+
+keycode 0x23 = Find
+keycode 0x4d = Up
+keycode 0x39 = Prior
+	shift   keycode 0x39 = Scroll_Backward
+keycode 0x5f = Left
+	alt     keycode 0x5f = Decr_Console
+keycode 0x61 = Right
+	alt     keycode 0x61 = Incr_Console
+keycode 0x38 = Select
+keycode 0x60 = Down
+keycode 0x3a = Next
+	shift   keycode 0x3a = Scroll_Forward
+keycode 0x24 = Insert
+keycode 0x25 = Remove
+#	altgr   control keycode 0x25 = Boot
+	control alt     keycode 0x25 = Boot
+
+keycode 0x0f = Help      Show_Memory      Show_Registers
+	control keycode  0x0f = Show_State
+
+keycode 0x10 = Do
+
+string F1 = "\033[[A"
+string F2 = "\033[[B"
+string F3 = "\033[[C"
+string F4 = "\033[[D"
+string F5 = "\033[[E"
+string F6 = "\033[17~"
+string F7 = "\033[18~"
+string F8 = "\033[19~"
+string F9 = "\033[20~"
+string F10 = "\033[21~"
+string F11 = "\033[23~"
+string F12 = "\033[24~"
+string F13 = "\033[25~"
+string F14 = "\033[26~"
+string F15 = "\033[28~"
+string F16 = "\033[29~"
+string F17 = "\033[31~"
+string F18 = "\033[32~"
+string F19 = "\033[33~"
+string F20 = "\033[34~"
+string Find = "\033[1~"
+string Insert = "\033[2~"
+string Remove = "\033[3~"
+string Select = "\033[4~"
+string Prior = "\033[5~"
+string Next = "\033[6~"
+string Macro = "\033[M"
+string Pause = "\033[P"
+compose '`' 'A' to 'À'
+compose '`' 'a' to 'à'
+compose '\'' 'A' to 'Á'
+compose '\'' 'a' to 'á'
+compose '^' 'A' to 'Â'
+compose '^' 'a' to 'â'
+compose '~' 'A' to 'Ã'
+compose '~' 'a' to 'ã'
+compose '"' 'A' to 'Ä'
+compose '"' 'a' to 'ä'
+compose 'O' 'A' to 'Å'
+compose 'o' 'a' to 'å'
+compose '0' 'A' to 'Å'
+compose '0' 'a' to 'å'
+compose 'A' 'A' to 'Å'
+compose 'a' 'a' to 'å'
+compose 'A' 'E' to 'Æ'
+compose 'a' 'e' to 'æ'
+compose ',' 'C' to 'Ç'
+compose ',' 'c' to 'ç'
+compose '`' 'E' to 'È'
+compose '`' 'e' to 'è'
+compose '\'' 'E' to 'É'
+compose '\'' 'e' to 'é'
+compose '^' 'E' to 'Ê'
+compose '^' 'e' to 'ê'
+compose '"' 'E' to 'Ë'
+compose '"' 'e' to 'ë'
+compose '`' 'I' to 'Ì'
+compose '`' 'i' to 'ì'
+compose '\'' 'I' to 'Í'
+compose '\'' 'i' to 'í'
+compose '^' 'I' to 'Î'
+compose '^' 'i' to 'î'
+compose '"' 'I' to 'Ï'
+compose '"' 'i' to 'ï'
+compose '-' 'D' to 'Ð'
+compose '-' 'd' to 'ð'
+compose '~' 'N' to 'Ñ'
+compose '~' 'n' to 'ñ'
+compose '`' 'O' to 'Ò'
+compose '`' 'o' to 'ò'
+compose '\'' 'O' to 'Ó'
+compose '\'' 'o' to 'ó'
+compose '^' 'O' to 'Ô'
+compose '^' 'o' to 'ô'
+compose '~' 'O' to 'Õ'
+compose '~' 'o' to 'õ'
+compose '"' 'O' to 'Ö'
+compose '"' 'o' to 'ö'
+compose '/' 'O' to 'Ø'
+compose '/' 'o' to 'ø'
+compose '`' 'U' to 'Ù'
+compose '`' 'u' to 'ù'
+compose '\'' 'U' to 'Ú'
+compose '\'' 'u' to 'ú'
+compose '^' 'U' to 'Û'
+compose '^' 'u' to 'û'
+compose '"' 'U' to 'Ü'
+compose '"' 'u' to 'ü'
+compose '\'' 'Y' to 'Ý'
+compose '\'' 'y' to 'ý'
+compose 'T' 'H' to 'Þ'
+compose 't' 'h' to 'þ'
+compose 's' 's' to 'ß'
+compose '"' 'y' to 'ÿ'
+compose 's' 'z' to 'ß'
+compose 'i' 'j' to 'ÿ'
diff -u --recursive --new-file v2.4.9/linux/drivers/tc/lk201-remap.c linux/drivers/tc/lk201-remap.c
--- v2.4.9/linux/drivers/tc/lk201-remap.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/tc/lk201-remap.c	Mon Aug 27 08:56:31 2001
@@ -0,0 +1,172 @@
+/*
+ * Keyboard mappings for DEC LK201/401/501 keyboards
+ * 
+ * 17.05.99 Michael Engel (engel@unix-ag.org)
+ *
+ * DEC US keyboards generate keycodes in the range 0x55 - 0xfb
+ *
+ * This conflicts with Linux scancode conventions which define 
+ * 0x00-0x7f as "normal" and 0x80-0xff as "shifted" scancodes, so we
+ * have to remap the keycodes to 0x00-0x7f with the scancodeRemap
+ * array. The generated scancode is simply the number of the key counted
+ * from the left upper to the right lower corner of the keyboard ...
+ *
+ * These scancodes are then being remapped (I hope ;-)) with the 
+ * lk501*map[] arrays which define scancode -> Linux code mapping
+ *
+ * Oh man is this horrible ;-)
+ *
+ * Scancodes with dual labels exist for keyboards as follows:
+ *
+ * code:  left label          / right label
+ *
+ * 0x73:  LKx01, LK421        / LK443, LK444
+ * 0x74:  LKx01, LK421        / LK443, LK444
+ * 0x7c:  LKx01, LK421        / LK443, LK444
+ * 0x8a:  LKx01, LK421        / LK443, LK444
+ * 0x8b:  LKx01, LK421        / LK443, LK444
+ * 0x8c:  LKx01, LK421        / LK443, LK444
+ * 0x8d:  LKx01, LK421        / LK443, LK444
+ * 0x8e:  LKx01, LK421        / LK443, LK444
+ * 0x8f:  LKx01, LK421        / LK443, LK444
+ * 0x9c:  LKx01, LK421        / LK443, LK444
+ * 0xa1:  LKx01, LK421        / LK443, LK444
+ * 0xa2:  LKx01, LK421        / LK443, LK444
+ * 0xa3:  LKx01, LK421        / LK443, LK444
+ * 0xa4:  LKx01, LK421        / LK443, LK444
+ * 0xad:         LK421        / LK443, LK444
+ * 0xc9:  LKx01, LK421, LK443 /        LK444
+ * 0xf7:  LKx01,        LK443 /        LK444
+ */
+
+unsigned char scancodeRemap[256] = {
+/* ----- 								*/
+/*  0 */ 0,		0,		0,		0,
+/* ----- 								*/
+/*  4 */ 0,		0,		0,		0,
+/* ----- 								*/
+/*  8 */ 0,		0,		0,		0,
+/* ----- 								*/
+/*  c */ 0,		0,		0,		0,
+/* ----- 								*/
+/* 10 */ 0,		0,		0,		0,
+/* ----- 								*/
+/* 14 */ 0,		0,		0,		0,
+/* ----- 								*/
+/* 18 */ 0,		0,		0,		0,
+/* ----- 								*/
+/* 1c */ 0,		0,		0,		0,
+/* ----- 								*/
+/* 20 */ 0,		0,		0,		0,
+/* ----- 								*/
+/* 24 */ 0,		0,		0,		0,
+/* ----- 								*/
+/* 28 */ 0,		0,		0,		0,
+/* ----- 								*/
+/* 2c */ 0,		0,		0,		0,
+/* ----- 								*/
+/* 30 */ 0,		0,		0,		0,
+/* ----- 								*/
+/* 34 */ 0,		0,		0,		0,
+/* ----- 								*/
+/* 38 */ 0,		0,		0,		0,
+/* ----- 								*/
+/* 3c */ 0,		0,		0,		0,
+/* ----- 								*/
+/* 40 */ 0,		0,		0,		0,
+/* ----- 								*/
+/* 44 */ 0,		0,		0,		0,
+/* ----- 								*/
+/* 48 */ 0,		0,		0,		0,
+/* ----- 								*/
+/* 4c */ 0,		0,		0,		0,
+/* ----- 								*/
+/* 50 */ 0,		0,		0,		0,
+/* ----- 	 	ESC		F1		F2 		*/
+/* 54 */ 0,		0,		0x01,  		0x02,
+/* ----- F3		F4		F5				*/
+/* 58 */ 0x03,  	0x04,		0x05,		0,
+/* ----- 								*/
+/* 5c */ 0,		0,		0,		0,
+/* ----- 								*/
+/* 60 */ 0,		0,		0,		0,
+/* ----- F6		F7		F8		F9		*/
+/* 64 */ 0x06,		0x07,		0x08,		0x09, 
+/* ----- F10								*/
+/* 68 */ 0x0a,		0,		0,		0,
+/* ----- 								*/
+/* 6c */ 0,		0,		0,		0,
+/* ----- 		F11   		F12		F13/PRNT SCRN	*/
+/* 70 */ 0,		0x0b,  		0x0c,		0x0d,
+/* ----- F14/SCRL LCK							*/
+/* 74 */ 0x0e,		0,		0,		0,
+/* ----- 								*/
+/* 78 */ 0,		0,		0,		0,
+/* ----- HELP/PAUSE	DO						*/
+/* 7c */ 0x0f,		0x10,		0,		0,
+/* ----- F17		F18		F19		F20		*/
+/* 80 */ 0x11,		0x12,		0x13,		0x14,
+/* ----- 								*/
+/* 84 */ 0,		0,		0,		0,
+/* ----- 				FIND/INSERT	INSERT/HOME	*/
+/* 88 */ 0,		0,		0x23,		0x24,
+/* ----- REMOVE/PG UP	SELECT/DELETE	PREVIOUS/END	NEXT/PG DN	*/
+/* 8c */ 0x25,		0x38,		0x39,		0x3a,
+/* ----- 				KP 0				*/
+/* 90 */ 0,		0,		0x6b,		0,
+/* ----- KP .		KP ENTER	KP 1		KP 2		*/
+/* 94 */ 0x6c,		0x65,		0x62,		0x63,
+/* ----- KP 3		KP 4		KP 5		KP 6		*/
+/* 98 */ 0x64,		0x4e,		0x4f,		0x50,
+/* ----- KP ,/KP +	KP 7		KP 8		KP 9		*/
+/* 9c */ 0x51,		0x3b,		0x3c,		0x3d,
+/* ----- KP -		KP F1/NUM LCK	KP F2/KP /	KP F3/KP *	*/
+/* a0 */ 0x3e,		0x26,		0x27,		0x28,
+/* ----- KP F4/KP -					LEFT		*/
+/* a4 */ 0x29,		0,		0,		0x5f,
+/* ----- RIGHT		DOWN		UP		SHIFT Rt	*/
+/* a8 */ 0x61,		0x60, 		0x4d,		0x5e,
+/* ----- ALT		COMP Rt/CTRL Rt	SHIFT		CONTROL		*/
+/* ac */ 0,		0,		0x52,		0x3f,
+/* ----- CAPS		COMPOSE		ALT Rt				*/
+/* b0 */ 0x40,		0x67,		0,		0,
+/* ----- 								*/
+/* b4 */ 0,		0,		0,		0,
+/* ----- 								*/
+/* b8 */ 0,		0,		0,		0,
+/* ----- BKSP		RET		TAB		`		*/
+/* bc */ 0x22,		0x37,		0x2a,		0x15,
+/* ----- 1		q		a		z		*/
+/* c0 */ 0x16,		0x2b,		0x41,		0x54,
+/* ----- 		2		w		s		*/
+/* c4 */ 0,		0x17,		0x2c,		0x42,
+/* ----- x		</\\				3		*/
+/* c8 */ 0x55,		0x53,		0,		0x18,
+/* ----- e		d		c				*/
+/* cc */ 0x2d,		0x43,		0x56,		0,
+/* ----- 4		r		f		v		*/
+/* d0 */ 0x19,		0x2e,		0x44,		0x57,
+/* ----- SPACE				5		t		*/
+/* d4 */ 0x68,		0,		0x1a,		0x2f,
+/* ----- g		b				6		*/
+/* d8 */ 0x45,		0x58,		0,		0x1b,
+/* ----- y		h		n				*/
+/* dc */ 0x30,		0x46,		0x59,		0,
+/* ----- 7		u		j		m		*/
+/* e0 */ 0x1c,		0x31,		0x47,		0x5a,
+/* ----- 		8		i		k		*/
+/* e4 */ 0,		0x1d,		0x32,		0x48,
+/* ----- ,				9		o		*/
+/* e8 */ 0x5b,		0,		0x1e,		0x33,
+/* ----- l		.				0		*/
+/* ec */ 0x49,		0x5c,		0,		0x1f,
+/* ----- p				;		/		*/
+/* f0 */ 0x34,		0,		0x4a,		0x5d,
+/* ----- 		=		]		\\/\'		*/
+/* f4 */ 0,		0x21,		0x36,		0x4c,
+/* ----- 		-		[		\'		*/
+/* f8 */ 0,		0x20,		0x35,		0x4b,
+/* ----- 								*/
+/* fc */ 0,		0,		0,		0,
+};
+
diff -u --recursive --new-file v2.4.9/linux/drivers/tc/lk201.c linux/drivers/tc/lk201.c
--- v2.4.9/linux/drivers/tc/lk201.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/tc/lk201.c	Mon Aug 27 08:56:31 2001
@@ -0,0 +1,237 @@
+/*
+ *
+ * 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
+ * for more details.
+ *
+ */
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/kbd_ll.h>
+#include <asm/wbflush.h>
+#include <asm/dec/tc.h>
+#include <asm/dec/machtype.h>
+
+#include "zs.h"
+#include "lk201.h"
+
+/* Simple translation table for the SysRq keys */
+
+#ifdef CONFIG_MAGIC_SYSRQ
+/*
+ * Actually no translation at all, at least until we figure out
+ * how to define SysRq for LK201 and friends. --macro
+ */
+unsigned char lk201_sysrq_xlate[128];
+unsigned char *kbd_sysrq_xlate = lk201_sysrq_xlate;
+#endif
+
+#define KEYB_LINE	3
+
+static int __init lk201_init(struct dec_serial *);
+static void __init lk201_info(struct dec_serial *);
+static void lk201_kbd_rx_char(unsigned char, unsigned char);
+
+struct zs_hook lk201_kbdhook = {
+	init_channel:   lk201_init,
+	init_info:      lk201_info,
+	rx_char:        NULL,
+	poll_rx_char:   NULL,
+	poll_tx_char:   NULL,
+	cflags:         B4800 | CS8 | CSTOPB | CLOCAL
+};
+
+/*
+ * This is used during keyboard initialisation
+ */
+static unsigned char lk201_reset_string[] = {
+	LK_CMD_LEDS_ON, LK_PARAM_LED_MASK(0xf),	/* show we are resetting */
+	LK_CMD_SET_DEFAULTS,
+	LK_CMD_MODE(LK_MODE_RPT_DOWN, 1),
+	LK_CMD_MODE(LK_MODE_RPT_DOWN, 2),
+	LK_CMD_MODE(LK_MODE_RPT_DOWN, 3),
+	LK_CMD_MODE(LK_MODE_RPT_DOWN, 4),
+	LK_CMD_MODE(LK_MODE_DOWN_UP, 5),
+	LK_CMD_MODE(LK_MODE_DOWN_UP, 6),
+	LK_CMD_MODE(LK_MODE_RPT_DOWN, 7),
+	LK_CMD_MODE(LK_MODE_RPT_DOWN, 8),
+	LK_CMD_MODE(LK_MODE_RPT_DOWN, 9),
+	LK_CMD_MODE(LK_MODE_RPT_DOWN, 10),
+	LK_CMD_MODE(LK_MODE_RPT_DOWN, 11),
+	LK_CMD_MODE(LK_MODE_RPT_DOWN, 12),
+	LK_CMD_MODE(LK_MODE_DOWN, 13),
+	LK_CMD_MODE(LK_MODE_RPT_DOWN, 14),
+	LK_CMD_ENB_RPT,
+	LK_CMD_DIS_KEYCLK,
+	LK_CMD_RESUME,
+	LK_CMD_ENB_BELL, LK_PARAM_VOLUME(4),
+	LK_CMD_LEDS_OFF, LK_PARAM_LED_MASK(0xf)
+};
+
+static int __init lk201_reset(struct dec_serial *info)
+{
+	int i;
+
+	for (i = 0; i < sizeof(lk201_reset_string); i++)
+		if (info->hook->poll_tx_char(info, lk201_reset_string[i])) {
+			printk(__FUNCTION__" transmit timeout\n");
+			return -EIO;
+		}
+	return 0;
+}
+
+void kbd_leds(unsigned char leds)
+{
+	return;
+}
+
+int kbd_setkeycode(unsigned int scancode, unsigned int keycode)
+{
+	return -EINVAL;
+}
+
+int kbd_getkeycode(unsigned int scancode)
+{
+	return -EINVAL;
+}
+
+int kbd_translate(unsigned char scancode, unsigned char *keycode,
+		  char raw_mode)
+{
+	*keycode = scancode;
+	return 1;
+}
+
+char kbd_unexpected_up(unsigned char keycode)
+{
+	return 0x80;
+}
+
+static void lk201_kbd_rx_char(unsigned char ch, unsigned char stat)
+{
+	static int shift_state = 0;
+	static int prev_scancode;
+	unsigned char c = scancodeRemap[ch];
+
+	if (!stat || stat == 4) {
+		switch (ch) {
+		case LK_KEY_ACK:
+			break;
+		case LK_KEY_LOCK:
+			shift_state ^= LK_LOCK;
+			handle_scancode(c, shift_state && LK_LOCK ? 1 : 0);
+			break;
+		case LK_KEY_SHIFT:
+			shift_state ^= LK_SHIFT;
+			handle_scancode(c, shift_state && LK_SHIFT ? 1 : 0);
+			break;
+		case LK_KEY_CTRL:
+			shift_state ^= LK_CTRL;
+			handle_scancode(c, shift_state && LK_CTRL ? 1 : 0);
+			break;
+		case LK_KEY_COMP:
+			shift_state ^= LK_COMP;
+			handle_scancode(c, shift_state && LK_COMP ? 1 : 0);
+			break;
+		case LK_KEY_RELEASE:
+			if (shift_state & LK_SHIFT)
+				handle_scancode(scancodeRemap[LK_KEY_SHIFT], 0);
+			if (shift_state & LK_CTRL)
+				handle_scancode(scancodeRemap[LK_KEY_CTRL], 0);
+			if (shift_state & LK_COMP)
+				handle_scancode(scancodeRemap[LK_KEY_COMP], 0);
+			if (shift_state & LK_LOCK)
+				handle_scancode(scancodeRemap[LK_KEY_LOCK], 0);
+			shift_state = 0;
+			break;
+		case LK_KEY_REPEAT:
+			handle_scancode(prev_scancode, 1);
+			break;
+		default:
+			prev_scancode = c;
+			handle_scancode(c, 1);
+			break;
+		}
+	} else
+		printk("Error reading LKx01 keyboard: 0x%02x\n", stat);
+}
+
+static void __init lk201_info(struct dec_serial *info)
+{
+}
+
+static int __init lk201_init(struct dec_serial *info)
+{
+	unsigned int ch, id = 0;
+	int result;
+
+	printk("DECstation LK keyboard driver v0.04... ");
+
+	result = lk201_reset(info);
+	if (result)
+		return result;
+	mdelay(10);
+
+	/*
+	 * Detect whether there is an LK201 or an LK401
+	 * The LK401 has ALT keys...
+	 */
+	info->hook->poll_tx_char(info, LK_CMD_REQ_ID);
+	while ((ch = info->hook->poll_rx_char(info)) > 0)
+		id = ch;
+
+	switch (id) {
+	case 1:
+		printk("LK201 detected\n");
+		break;
+	case 2:
+		printk("LK401 detected\n");
+		break;
+	default:
+		printk("unknown keyboard, ID %d,\n", id);
+		printk("... please report to <linux-mips@oss.sgi.com>\n");
+	}
+
+	/*
+	 * now we're ready
+	 */
+	info->hook->rx_char = lk201_kbd_rx_char;
+
+	return 0;
+}
+
+void __init kbd_init_hw(void)
+{
+	extern int register_zs_hook(unsigned int, struct zs_hook *);
+	extern int unregister_zs_hook(unsigned int);
+
+	if (TURBOCHANNEL) {
+		if (mips_machtype != MACH_DS5000_XX) {
+			/*
+			 * This is not a MAXINE, so:
+			 *
+			 * kbd_init_hw() is being called before
+			 * rs_init() so just register the kbd hook
+			 * and let zs_init do the rest :-)
+			 */
+			if (mips_machtype == MACH_DS5000_200)
+				printk("LK201 Support for DS5000/200 not yet ready ...\n");
+			else
+				if(!register_zs_hook(KEYB_LINE, &lk201_kbdhook))
+					unregister_zs_hook(KEYB_LINE);
+		}
+	} else {
+		/*
+		 * TODO: modify dz.c to allow similar hooks
+		 * for LK201 handling on DS2100, DS3100, and DS5000/200
+		 */
+		printk("LK201 Support for DS3100 not yet ready ...\n");
+	}
+}
+
+
+
+
diff -u --recursive --new-file v2.4.9/linux/drivers/tc/lk201.h linux/drivers/tc/lk201.h
--- v2.4.9/linux/drivers/tc/lk201.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/tc/lk201.h	Mon Aug 27 08:56:31 2001
@@ -0,0 +1,53 @@
+/*
+ *	Commands to the keyboard processor
+ */
+
+#define	LK_PARAM		0x80	/* start/end parameter list */
+
+#define	LK_CMD_RESUME		0x8b
+#define	LK_CMD_INHIBIT		0xb9
+#define	LK_CMD_LEDS_ON		0x13	/* 1 param: led bitmask */
+#define	LK_CMD_LEDS_OFF		0x11	/* 1 param: led bitmask */
+#define	LK_CMD_DIS_KEYCLK	0x99
+#define	LK_CMD_ENB_KEYCLK	0x1b	/* 1 param: volume */
+#define	LK_CMD_DIS_CTLCLK	0xb9
+#define	LK_CMD_ENB_CTLCLK	0xbb
+#define	LK_CMD_SOUND_CLK	0x9f
+#define	LK_CMD_DIS_BELL		0xa1
+#define	LK_CMD_ENB_BELL		0x23	/* 1 param: volume */
+#define	LK_CMD_BELL		0xa7
+#define	LK_CMD_TMP_NORPT	0xc1
+#define	LK_CMD_ENB_RPT		0xe3
+#define	LK_CMD_DIS_RPT		0xe1
+#define	LK_CMD_RPT_TO_DOWN	0xd9
+#define	LK_CMD_REQ_ID		0xab
+#define	LK_CMD_POWER_UP		0xfd
+#define	LK_CMD_TEST_MODE	0xcb
+#define	LK_CMD_SET_DEFAULTS	0xd3
+
+/* there are 4 leds, represent them in the low 4 bits of a byte */
+#define	LK_PARAM_LED_MASK(ledbmap)	(LK_PARAM|(ledbmap))
+
+/* max volume is 0, lowest is 0x7 */
+#define	LK_PARAM_VOLUME(v)		(LK_PARAM|((v)&0x7))
+
+/* mode set command(s) details */
+#define	LK_MODE_DOWN		0x0
+#define	LK_MODE_RPT_DOWN	0x2
+#define	LK_MODE_DOWN_UP		0x6
+#define	LK_CMD_MODE(m,div)	(LK_PARAM|(div<<3)|m)
+
+#define LK_SHIFT 1<<0
+#define LK_CTRL 1<<1
+#define LK_LOCK 1<<2
+#define LK_COMP 1<<3
+
+#define LK_KEY_SHIFT 174
+#define LK_KEY_CTRL 175
+#define LK_KEY_LOCK 176
+#define LK_KEY_COMP 177
+#define LK_KEY_RELEASE 179
+#define LK_KEY_REPEAT 180
+#define LK_KEY_ACK 186
+
+extern unsigned char scancodeRemap[256];
\ No newline at end of file
diff -u --recursive --new-file v2.4.9/linux/drivers/tc/tc.c linux/drivers/tc/tc.c
--- v2.4.9/linux/drivers/tc/tc.c	Sat May 13 08:31:25 2000
+++ linux/drivers/tc/tc.c	Mon Aug 27 08:56:31 2001
@@ -1,4 +1,4 @@
-/* $Id: tc.c,v 1.3 1999/10/09 00:01:32 ralf Exp $
+/*
  * tc-init: We assume the TURBOchannel to be up and running so
  * just probe for Modules and fill in the global data structure
  * tc_bus.
@@ -8,9 +8,7 @@
  * for more details.
  *
  * Copyright (c) Harald Koerfgen, 1998
- *
  */
-
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
@@ -23,14 +21,15 @@
 
 #include <asm/ptrace.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 
 #define TC_DEBUG
 
 slot_info tc_bus[MAX_SLOT];
-static int max_tcslot = 0;
-static tcinfo *info = (tcinfo *)0;
+static int max_tcslot;
+static tcinfo *info;
 
-unsigned long system_base = 0;
+unsigned long system_base;
 
 extern void (*dbe_board_handler)(struct pt_regs *regs);
 extern unsigned long *(*rex_slot_address)(int);
@@ -112,19 +111,19 @@
 	for (slot = 0; slot <= max_slot; slot++) {
 		module = (char *)(startaddr + slot * size);
 		offset = -1;
-		if (module[OLDCARD + PATTERN0] == 0x55 && module[OLDCARD + PATTERN1] == 0x00
-		  && module[OLDCARD + PATTERN2] == 0xaa && module[OLDCARD + PATTERN3] == 0xff)
+		if (module[OLDCARD + TC_PATTERN0] == 0x55 && module[OLDCARD + TC_PATTERN1] == 0x00
+		  && module[OLDCARD + TC_PATTERN2] == 0xaa && module[OLDCARD + TC_PATTERN3] == 0xff)
 			offset = OLDCARD;
-		if (module[PATTERN0] == 0x55 && module[PATTERN1] == 0x00
-		  && module[PATTERN2] == 0xaa && module[PATTERN3] == 0xff)
+		if (module[TC_PATTERN0] == 0x55 && module[TC_PATTERN1] == 0x00
+		  && module[TC_PATTERN2] == 0xaa && module[TC_PATTERN3] == 0xff)
 			offset = 0;
 
 		if (offset != -1) {
 			tc_bus[slot].base_addr = (unsigned long)module;
 			for(i = 0; i < 8; i++) {
-				tc_bus[slot].firmware[i] = module[FIRM_VER + offset + 4 * i];
-				tc_bus[slot].vendor[i] = module[VENDOR + offset + 4 * i];
-				tc_bus[slot].name[i] = module[MODULE + offset + 4 * i];
+				tc_bus[slot].firmware[i] = module[TC_FIRM_VER + offset + 4 * i];
+				tc_bus[slot].vendor[i] = module[TC_VENDOR + offset + 4 * i];
+				tc_bus[slot].name[i] = module[TC_MODULE + offset + 4 * i];
 			}
 			tc_bus[slot].firmware[8] = 0;
 			tc_bus[slot].vendor[8] = 0;
@@ -206,7 +205,7 @@
 	if (TURBOCHANNEL && info->slot_size && slot0addr) {
 		printk("TURBOchannel rev. %1d at %2d.%1d MHz ", info->revision,
 			tc_clock / 10, tc_clock % 10);
-		printk("(%sparity)\n", info->parity ? "" : "no ");
+		printk("(with%s parity)\n", info->parity ? "" : "out");
 
 		slot_size = info->slot_size << 20;
 
@@ -235,3 +234,11 @@
 		ioport_resource.end = KSEG2 - 1;
 	}
 }
+
+EXPORT_SYMBOL(search_tc_card);
+EXPORT_SYMBOL(claim_tc_card);
+EXPORT_SYMBOL(release_tc_card);
+EXPORT_SYMBOL(get_tc_base_addr);
+EXPORT_SYMBOL(get_tc_irq_nr);
+EXPORT_SYMBOL(get_tc_speed);
+
diff -u --recursive --new-file v2.4.9/linux/drivers/tc/tcsyms.c linux/drivers/tc/tcsyms.c
--- v2.4.9/linux/drivers/tc/tcsyms.c	Sat May 13 08:31:25 2000
+++ linux/drivers/tc/tcsyms.c	Wed Dec 31 16:00:00 1969
@@ -1,14 +0,0 @@
-/*
- *	TURBOchannel Services -- Exported Symbols
- *
- */
-
-#include <linux/module.h>
-#include <asm/dec/tc.h>
-
-EXPORT_SYMBOL(search_tc_card);
-EXPORT_SYMBOL(claim_tc_card);
-EXPORT_SYMBOL(release_tc_card);
-EXPORT_SYMBOL(get_tc_base_addr);
-EXPORT_SYMBOL(get_tc_irq_nr);
-EXPORT_SYMBOL(get_tc_speed);
diff -u --recursive --new-file v2.4.9/linux/drivers/tc/zs.c linux/drivers/tc/zs.c
--- v2.4.9/linux/drivers/tc/zs.c	Thu Oct 12 14:20:47 2000
+++ linux/drivers/tc/zs.c	Mon Aug 27 08:56:31 2001
@@ -1,22 +1,46 @@
 /*
- * decserial.c: Serial port driver for IOASIC DECsatations.
+ * decserial.c: Serial port driver for IOASIC DECstations.
  *
- * Derived from drivers/macintosh/macserial.c by Harald Koerfgen.
  * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
+ * Derived from drivers/macintosh/macserial.c by Harald Koerfgen.
  *
  * DECstation changes
- * Copyright (C) 1998 Harald Koerfgen (Harald.Koerfgen@home.ivm.de)
+ * Copyright (C) 1998-2000 Harald Koerfgen
+ * Copyright (C) 2000,2001 Maciej W. Rozycki <macro@ds2.pg.gda.pl>
  *
  * For the rest of the code the original Copyright applies:
  * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
  *
- * Keyboard and mouse are not supported right now. If you want to change this,
- * you might want to have a look at drivers/sbus/char/sunserial.c to see
- * how this might be done. HK
+ *
+ * Note: for IOASIC systems the wiring is as follows:
+ *
+ * mouse/keyboard:
+ * DIN-7 MJ-4  signal        SCC
+ * 2     1     TxD       <-  A.TxD
+ * 3     4     RxD       ->  A.RxD
+ *
+ * EIA-232/EIA-423:
+ * DB-25 MMJ-6 signal        SCC
+ * 2     2     TxD       <-  B.TxD
+ * 3     5     RxD       ->  B.RxD
+ * 4           RTS       <- ~A.RTS
+ * 5           CTS       -> ~B.CTS
+ * 6     6     DSR       -> ~A.SYNC
+ * 8           CD        -> ~B.DCD
+ * 12          DSRS(DCE) -> ~A.CTS  (*)
+ * 15          TxC       ->  B.TxC
+ * 17          RxC       ->  B.RxC
+ * 20    1     DTR       <- ~A.DTR
+ * 22          RI        -> ~A.DCD
+ * 23          DSRS(DTE) <- ~B.RTS
+ *
+ * (*) EIA-232 defines the signal at this pin to be SCD, while DSRS(DCE)
+ *     is shared with DSRS(DTE) at pin 23.
  */
 
 #include <linux/config.h>
+#include <linux/version.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
@@ -31,6 +55,7 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/ioport.h>
 #ifdef CONFIG_SERIAL_CONSOLE
 #include <linux/console.h>
 #endif
@@ -43,17 +68,26 @@
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
 #include <asm/wbflush.h>
+#include <asm/bootinfo.h>
+#ifdef CONFIG_DECSTATION
 #include <asm/dec/interrupts.h>
 #include <asm/dec/machtype.h>
 #include <asm/dec/tc.h>
 #include <asm/dec/ioasic_addrs.h>
+#endif
+#ifdef CONFIG_BAGET_MIPS
+#include <asm/baget/baget.h>
+unsigned long system_base;
+#endif
 #ifdef CONFIG_KGDB
 #include <asm/kgdb.h>
 #endif
+#ifdef CONFIG_MAGIC_SYSRQ
+#include <linux/sysrq.h>
+#endif
 
 #include "zs.h"
 
-
 /*
  * It would be nice to dynamically allocate everything that
  * depends on NUM_SERIAL, so we could support any number of
@@ -61,11 +95,60 @@
  */
 #define NUM_SERIAL	2		/* Max number of ZS chips supported */
 #define NUM_CHANNELS	(NUM_SERIAL * 2)	/* 2 channels per chip */
+#define CHANNEL_A_NR  (zs_parms->channel_a_offset > zs_parms->channel_b_offset)
+                                        /* Number of channel A in the chip */ 
+#define ZS_CHAN_IO_SIZE 8
+#define ZS_CLOCK        7372800 	/* Z8530 RTxC input clock rate */
 
 #define RECOVERY_DELAY  udelay(2)
 
-struct dec_zschannel zs_channels[NUM_CHANNELS];
+struct zs_parms {
+	unsigned long scc0;
+	unsigned long scc1;
+	int channel_a_offset;
+	int channel_b_offset;
+	int irq;
+	int clock;
+};
 
+static struct zs_parms *zs_parms;
+
+#ifdef CONFIG_DECSTATION
+static struct zs_parms ds_parms = {
+	scc0 : SCC0,
+	scc1 : SCC1,
+	channel_a_offset : 1,
+	channel_b_offset : 9,
+	irq : SERIAL,
+	clock : ZS_CLOCK
+};
+#endif
+#ifdef CONFIG_BAGET_MIPS
+static struct zs_parms baget_parms = {
+	scc0 : UNI_SCC0,
+	scc1 : UNI_SCC1,
+	channel_a_offset : 9,
+	channel_b_offset : 1,
+	irq : BAGET_SCC_IRQ,
+	clock : 14745000
+};
+#endif
+
+#ifdef CONFIG_DECSTATION
+#define DS_BUS_PRESENT (IOASIC)
+#else
+#define DS_BUS_PRESENT 0
+#endif
+
+#ifdef CONFIG_BAGET_MIPS
+#define BAGET_BUS_PRESENT (mips_machtype == MACH_BAGET202)
+#else
+#define BAGET_BUS_PRESENT 0
+#endif
+
+#define BUS_PRESENT (DS_BUS_PRESENT || BAGET_BUS_PRESENT)
+
+struct dec_zschannel zs_channels[NUM_CHANNELS];
 struct dec_serial zs_soft[NUM_CHANNELS];
 int zs_channels_found;
 struct dec_serial *zs_chain;	/* list of all channels */
@@ -75,19 +158,9 @@
 #ifdef CONFIG_SERIAL_CONSOLE
 static struct console sercons;
 #endif
-
-#ifdef CONFIG_KGDB
-struct dec_zschannel *zs_kgdbchan;
-static unsigned char scc_inittab[] = {
-	9,  0x80,	/* reset A side (CHRA) */
-	13, 0,		/* set baud rate divisor */
-	12, 1,
-	14, 1,		/* baud rate gen enable, src=rtxc (BRENABL) */
-	11, 0x50,	/* clocks = br gen (RCBR | TCBR) */
-	5,  0x6a,	/* tx 8 bits, assert RTS (Tx8 | TxENAB | RTS) */
-	4,  0x44,	/* x16 clock, 1 stop (SB1 | X16CLK)*/
-	3,  0xc1,	/* rx enable, 8 bits (RxENABLE | Rx8)*/
-};
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) \
+    && !defined(MODULE)
+static unsigned long break_pressed; /* break, really ... */
 #endif
 
 static unsigned char zs_init_regs[16] __initdata = {
@@ -106,8 +179,6 @@
 	0 			     /* write 15 */
 };
 
-#define ZS_CLOCK         7372800 	/* Z8530 RTxC input clock rate */
-
 DECLARE_TASK_QUEUE(tq_zs_serial);
 
 struct tty_driver serial_driver, callout_driver;
@@ -129,6 +200,12 @@
 #undef SERIAL_DEBUG_THROTTLE
 #undef SERIAL_PARANOIA_CHECK
 
+#undef ZS_DEBUG_REGS
+
+#ifdef SERIAL_DEBUG_THROTTLE
+#define _tty_name(tty,buf) tty_name(tty,buf)
+#endif
+
 #define RS_STROBE_TIME 10
 #define RS_ISR_PASS_LIMIT 256
 
@@ -184,7 +261,7 @@
  */
 static int baud_table[] = {
 	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-	9600, 19200, 38400, 57600, 0, 0 };
+	9600, 19200, 38400, 57600, 115200, 0 };
 
 /* 
  * Reading and writing Z8530 registers.
@@ -256,16 +333,21 @@
 }
 
 /* Sets or clears DTR/RTS on the requested line */
-static inline void zs_rtsdtr(struct dec_serial *ss, int set)
+static inline void zs_rtsdtr(struct dec_serial *info, int which, int set)
 {
-	if (ss->zs_channel != ss->zs_chan_a) {
-		if (set)
-			ss->zs_chan_a->curregs[5] |= (RTS | DTR);
-		else
-			ss->zs_chan_a->curregs[5] &= ~(RTS | DTR);
-		write_zsreg(ss->zs_chan_a, 5, ss->zs_chan_a->curregs[5]);
+        unsigned long flags;
+
+
+	save_flags(flags); cli();
+	if (info->zs_channel != info->zs_chan_a) {
+		if (set) {
+			info->zs_chan_a->curregs[5] |= (which & (RTS | DTR));
+		} else {
+			info->zs_chan_a->curregs[5] &= ~(which & (RTS | DTR));
+		}
+		write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
 	}
-	return;
+	restore_flags(flags);
 }
 
 /* Utility routines for the Zilog */
@@ -281,7 +363,7 @@
 	 */
 	brg = (read_zsreg(channel, 13) << 8);
 	brg |= read_zsreg(channel, 12);
-	return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->clk_divisor)));
+	return BRG_TO_BPS(brg, (zs_parms->clock/(ss->clk_divisor)));
 }
 
 /* On receive, this clears errors and the receiver interrupts */
@@ -302,6 +384,8 @@
  * -----------------------------------------------------------------------
  */
 
+static int tty_break;	/* Set whenever BREAK condition is detected.  */
+
 /*
  * This routine is used by the interrupt handler to schedule
  * processing in the software interrupt portion of the driver.
@@ -320,23 +404,59 @@
 	struct tty_struct *tty = info->tty;
 	unsigned char ch, stat, flag;
 
-	while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) != 0) {
+	while ((read_zsreg(info->zs_channel, R0) & Rx_CH_AV) != 0) {
 
 		stat = read_zsreg(info->zs_channel, R1);
 		ch = read_zsdata(info->zs_channel);
 
-#ifdef CONFIG_KGDB
-		if (info->kgdb_channel) {
-			if (ch == 0x03 || ch == '$')
-				breakpoint();
-			if (stat & (Rx_OVR|FRM_ERR|PAR_ERR))
-				write_zsreg(info->zs_channel, 0, ERR_RES);
-			return;
+		if (!tty && !info->hook && !info->hook->rx_char)
+			continue;
+
+		if (tty_break) {
+			tty_break = 0;
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE)
+			if (info->line == sercons.index) {
+				if (!break_pressed) {
+					break_pressed = jiffies;
+					goto ignore_char;
+				}
+				break_pressed = 0;
+			}
+#endif
+			flag = TTY_BREAK;
+			if (info->flags & ZILOG_SAK)
+				do_SAK(tty);
+		} else {
+			if (stat & Rx_OVR) {
+				flag = TTY_OVERRUN;
+			} else if (stat & FRM_ERR) {
+				flag = TTY_FRAME;
+			} else if (stat & PAR_ERR) {
+				flag = TTY_PARITY;
+			} else
+				flag = 0;
+			if (flag)
+				/* reset the error indication */
+				write_zsreg(info->zs_channel, R0, ERR_RES);
+		}
+
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE)
+		if (break_pressed && info->line == sercons.index) {
+			if (ch != 0 &&
+			    time_before(jiffies, break_pressed + HZ*5)) {
+				handle_sysrq(ch, regs, NULL, NULL);
+				break_pressed = 0;
+				goto ignore_char;
+			}
+			break_pressed = 0;
 		}
 #endif
-		if (!tty)
-			continue;
 
+		if (info->hook && info->hook->rx_char) {
+			(*info->hook->rx_char)(ch, flag);
+			return;
+  		}
+		
 		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
 			static int flip_buf_ovf;
 			++flip_buf_ovf;
@@ -348,26 +468,18 @@
 			if (flip_max_cnt < tty->flip.count)
 				flip_max_cnt = tty->flip.count;
 		}
-		if (stat & Rx_OVR) {
-			flag = TTY_OVERRUN;
-		} else if (stat & FRM_ERR) {
-			flag = TTY_FRAME;
-		} else if (stat & PAR_ERR) {
-			flag = TTY_PARITY;
-		} else
-			flag = 0;
-		if (flag)
-			/* reset the error indication */
-			write_zsreg(info->zs_channel, 0, ERR_RES);
+
 		*tty->flip.flag_buf_ptr++ = flag;
 		*tty->flip.char_buf_ptr++ = ch;
+	ignore_char:
 	}
-	tty_flip_buffer_push(tty);
+	if (tty)
+		tty_flip_buffer_push(tty);
 }
 
 static void transmit_chars(struct dec_serial *info)
 {
-	if ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0)
+	if ((read_zsreg(info->zs_channel, R0) & Tx_BUF_EMP) == 0)
 		return;
 	info->tx_active = 0;
 
@@ -379,8 +491,9 @@
 		return;
 	}
 
-	if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tx_stopped) {
-		write_zsreg(info->zs_channel, 0, RES_Tx_P);
+	if ((info->xmit_cnt <= 0) || (info->tty && info->tty->stopped)
+	    || info->tx_stopped) {
+		write_zsreg(info->zs_channel, R0, RES_Tx_P);
 		return;
 	}
 	/* Send char */
@@ -395,45 +508,48 @@
 
 static _INLINE_ void status_handle(struct dec_serial *info)
 {
-	unsigned char status;
+	unsigned char stat;
 
 	/* Get status from Read Register 0 */
-	status = read_zsreg(info->zs_channel, 0);
+	stat = read_zsreg(info->zs_channel, R0);
+
+	if (stat & BRK_ABRT) {
+#ifdef SERIAL_DEBUG_INTR
+		printk("handling break....");
+#endif
+		tty_break = 1;
+	}
 
-	/* FIXEM: Check for DCD transitions */
-	if (((status ^ info->read_reg_zero) & DCD) != 0
-	    && info->tty && !C_CLOCAL(info->tty)) {
-		if (status & DCD) {
-			wake_up_interruptible(&info->open_wait);
-		} else if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) {
-			if (info->tty)
+	if (info->zs_channel != info->zs_chan_a) {
+
+		/* FIXEM: Check for DCD transitions */
+		if (((stat ^ info->read_reg_zero) & DCD) != 0
+		    && info->tty && !C_CLOCAL(info->tty)) {
+			if (stat & DCD) {
+				wake_up_interruptible(&info->open_wait);
+			} else if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) {
 				tty_hangup(info->tty);
+			}
 		}
-	}
 
-	/* Check for CTS transitions */
-	if (info->tty && C_CRTSCTS(info->tty)) {
-		/*
-		 * For some reason, on the Power Macintosh,
-		 * it seems that the CTS bit is 1 when CTS is
-		 * *negated* and 0 when it is asserted.
-		 * The DCD bit doesn't seem to be inverted
-		 * like this.
-		 */
-		if ((status & CTS) != 0) {
-			if (info->tx_stopped) {
-				info->tx_stopped = 0;
-				if (!info->tx_active)
-					transmit_chars(info);
+		/* Check for CTS transitions */
+		if (info->tty && C_CRTSCTS(info->tty)) {
+			if ((stat & CTS) != 0) {
+				if (info->tx_stopped) {
+					info->tx_stopped = 0;
+					if (!info->tx_active)
+						transmit_chars(info);
+				}
+			} else {
+				info->tx_stopped = 1;
 			}
-		} else {
-			info->tx_stopped = 1;
 		}
+
 	}
 
 	/* Clear status condition... */
-	write_zsreg(info->zs_channel, 0, RES_EXT_INT);
-	info->read_reg_zero = status;
+	write_zsreg(info->zs_channel, R0, RES_EXT_INT);
+	info->read_reg_zero = stat;
 }
 
 /*
@@ -459,7 +575,7 @@
 		shift = 0;	/* Channel B */
 
 	for (;;) {
-		zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift; 
+		zs_intreg = read_zsreg(info->zs_chan_a, R3) >> shift; 
 		if ((zs_intreg & CHAN_IRQMASK) == 0)
 			break;
 
@@ -473,8 +589,31 @@
 			status_handle(info);
 		}
 	}
+	
+	/* Why do we need this ? */
+	write_zsreg(info->zs_channel, 0, RES_H_IUS);
 }
 
+#ifdef ZS_DEBUG_REGS
+void zs_dump (void) {
+	int i, j;
+	for (i = 0; i < zs_channels_found; i++) {
+		struct dec_zschannel *ch = &zs_channels[i]; 
+		if ((long)ch->control == UNI_IO_BASE+UNI_SCC1A_CTRL) {
+			for (j = 0; j < 15; j++) {
+				printk("W%d = 0x%x\t", 
+				       j, (int)ch->curregs[j]);
+			}
+			for (j = 0; j < 15; j++) {
+				printk("R%d = 0x%x\t", 
+				       j, (int)read_zsreg(ch,j));
+			}
+			printk("\n\n");
+		}
+	}
+}
+#endif
+
 /*
  * -------------------------------------------------------------------
  * Here ends the serial interrupt routines.
@@ -559,7 +698,7 @@
 	}
 }
 
-static int startup(struct dec_serial * info)
+int zs_startup(struct dec_serial * info)
 {
 	unsigned long flags;
 
@@ -575,7 +714,7 @@
 	save_flags(flags); cli();
 
 #ifdef SERIAL_DEBUG_OPEN
-	printk("starting up ttyS%d (irq %d)...", info->line, info->irq);
+	printk("starting up ttyS%02d (irq %d)...", info->line, info->irq);
 #endif
 
 	/*
@@ -593,7 +732,7 @@
 	/*
 	 * Turn on RTS and DTR.
 	 */
-	zs_rtsdtr(info, 1);
+	zs_rtsdtr(info, RTS | DTR, 1);
 
 	/*
 	 * Finally, enable sequencing and interrupts
@@ -664,8 +803,7 @@
 	info->zs_channel->curregs[5] &= ~TxENAB;
 	write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
 	if (!info->tty || C_HUPCL(info->tty)) {
-		info->zs_chan_a->curregs[5] &= ~(DTR | RTS);
-		write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
+		zs_rtsdtr(info, RTS | DTR, 0);
 	}
 
 	if (info->tty)
@@ -681,29 +819,45 @@
  */
 static void change_speed(struct dec_serial *info)
 {
-	unsigned short port;
 	unsigned cflag;
 	int	i;
-	int	brg;
+	int	brg, bits;
 	unsigned long flags;
 
-	if (!info->tty || !info->tty->termios)
-		return;
-	cflag = info->tty->termios->c_cflag;
-	if (!(port = info->port))
-		return;
+	if (!info->hook) {
+		if (!info->tty || !info->tty->termios)
+			return;
+		cflag = info->tty->termios->c_cflag;
+		if (!info->port)
+			return;
+	} else {
+		cflag = info->hook->cflags;
+	}
+
 	i = cflag & CBAUD;
+	if (i & CBAUDEX) {
+		i &= ~CBAUDEX;
+		if (i < 1 || i > 2) {
+			if (!info->hook)
+				info->tty->termios->c_cflag &= ~CBAUDEX;
+			else
+				info->hook->cflags &= ~CBAUDEX;
+		} else
+			i += 15;
+	}
 
 	save_flags(flags); cli();
 	info->zs_baud = baud_table[i];
 	info->clk_divisor = 16;
-
-	switch (info->zs_baud) {
-	default:
+	if (info->zs_baud) {
 		info->zs_channel->curregs[4] = X16CLK;
-		brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor);
+		brg = BPS_TO_BRG(info->zs_baud, zs_parms->clock/info->clk_divisor);
 		info->zs_channel->curregs[12] = (brg & 255);
 		info->zs_channel->curregs[13] = ((brg >> 8) & 255);
+		zs_rtsdtr(info, DTR, 1); 
+	} else {
+		zs_rtsdtr(info, RTS | DTR, 0);
+		return;
 	}
 
 	/* byte size and parity */
@@ -711,24 +865,31 @@
 	info->zs_channel->curregs[5] &= ~TxNBITS_MASK;
 	switch (cflag & CSIZE) {
 	case CS5:
+		bits = 7;
 		info->zs_channel->curregs[3] |= Rx5;
 		info->zs_channel->curregs[5] |= Tx5;
 		break;
 	case CS6:
+		bits = 8;
 		info->zs_channel->curregs[3] |= Rx6;
 		info->zs_channel->curregs[5] |= Tx6;
 		break;
 	case CS7:
+		bits = 9;
 		info->zs_channel->curregs[3] |= Rx7;
 		info->zs_channel->curregs[5] |= Tx7;
 		break;
 	case CS8:
 	default: /* defaults to 8 bits */
+		bits = 10;
 		info->zs_channel->curregs[3] |= Rx8;
 		info->zs_channel->curregs[5] |= Tx8;
 		break;
 	}
 
+	info->timeout = ((info->xmit_fifo_size*HZ*bits) / info->zs_baud);
+        info->timeout += HZ/50;         /* Add .02 seconds of slop */
+
 	info->zs_channel->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
 	if (cflag & CSTOPB) {
 		info->zs_channel->curregs[4] |= SB2;
@@ -750,7 +911,7 @@
 		info->zs_channel->curregs[15] &= ~DCDIE;
 	if (cflag & CRTSCTS) {
 		info->zs_channel->curregs[15] |= CTSIE;
-		if ((read_zsreg(info->zs_channel, 0) & CTS) != 0)
+		if ((read_zsreg(info->zs_channel, 0) & CTS) == 0)
 			info->tx_stopped = 1;
 	} else {
 		info->zs_channel->curregs[15] &= ~CTSIE;
@@ -895,17 +1056,7 @@
 	}
 
 	if (C_CRTSCTS(tty)) {
-		/*
-		 * Here we want to turn off the RTS line.  On Macintoshes,
-		 * we only get the DTR line, which goes to both DTR and
-		 * RTS on the modem.  RTS doesn't go out to the serial
-		 * port socket.  So you should make sure your modem is
-		 * set to ignore DTR if you're using CRTSCTS.
-		 */
-		save_flags(flags); cli();
-		info->zs_chan_a->curregs[5] &= ~(DTR | RTS);
-		write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
-		restore_flags(flags);
+		zs_rtsdtr(info, RTS, 0);
 	}
 }
 
@@ -937,11 +1088,7 @@
 	}
 
 	if (C_CRTSCTS(tty)) {
-		/* Assert RTS and DTR lines */
-		save_flags(flags); cli();
-		info->zs_chan_a->curregs[5] |= DTR | RTS;
-		write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
-		restore_flags(flags);
+		zs_rtsdtr(info, RTS, 1);
 	}
 }
 
@@ -983,7 +1130,7 @@
 	copy_from_user(&new_serial,new_info,sizeof(new_serial));
 	old_info = *info;
 
-	if (!suser()) {
+	if (!capable(CAP_SYS_ADMIN)) {
 		if ((new_serial.baud_base != info->baud_base) ||
 		    (new_serial.type != info->type) ||
 		    (new_serial.close_delay != info->close_delay) ||
@@ -1012,7 +1159,7 @@
 	info->closing_wait = new_serial.closing_wait;
 
 check_and_exit:
-	retval = startup(info);
+	retval = zs_startup(info);
 	return retval;
 }
 
@@ -1039,18 +1186,25 @@
 
 static int get_modem_info(struct dec_serial *info, unsigned int *value)
 {
-	unsigned char control, status;
+	unsigned char control, status_a, status_b;
 	unsigned int result;
 
-	cli();
-	control = info->zs_chan_a->curregs[5];
-	status = read_zsreg(info->zs_channel, 0);
-	sti();
-	result =  ((control & RTS) ? TIOCM_RTS: 0)
-		| ((control & DTR) ? TIOCM_DTR: 0)
-		| ((status  & DCD) ? TIOCM_CAR: 0)
-		| ((status  & CTS) ? 0: TIOCM_CTS);
-	put_user(result,value);
+	if (info->zs_channel == info->zs_chan_a)
+		result = 0;
+	else {
+		cli();
+		control = info->zs_chan_a->curregs[5];
+		status_a = read_zsreg(info->zs_chan_a, 0);
+		status_b = read_zsreg(info->zs_channel, 0);
+		sti();
+		result =  ((control  & RTS) ? TIOCM_RTS: 0)
+			| ((control  & DTR) ? TIOCM_DTR: 0)
+			| ((status_b & DCD) ? TIOCM_CAR: 0)
+			| ((status_a & DCD) ? TIOCM_RNG: 0)
+			| ((status_a & SYNC_HUNT) ? TIOCM_DSR: 0)
+			| ((status_b & CTS) ? TIOCM_CTS: 0);
+	}
+	put_user(result, value);
 	return 0;
 }
 
@@ -1063,6 +1217,10 @@
 	error = verify_area(VERIFY_READ, value, sizeof(int));
 	if (error)
 		return error;
+
+	if (info->zs_channel == info->zs_chan_a)
+		return 0;
+
 	get_user(arg, value);
 	bits = (arg & TIOCM_RTS? RTS: 0) + (arg & TIOCM_DTR? DTR: 0);
 	cli();
@@ -1074,7 +1232,8 @@
 		info->zs_chan_a->curregs[5] &= ~bits;
 		break;
 	case TIOCMSET:
-		info->zs_chan_a->curregs[5] = (info->zs_chan_a->curregs[5] & ~(DTR | RTS)) | bits;
+		info->zs_chan_a->curregs[5] = 
+			(info->zs_chan_a->curregs[5] & ~(DTR | RTS)) | bits;
 		break;
 	default:
 		sti();
@@ -1113,10 +1272,9 @@
 	int error;
 	struct dec_serial * info = (struct dec_serial *)tty->driver_data;
 
-#ifdef CONFIG_KGDB
-	if (info->kgdb_channel)
+	if (info->hook)
 		return -ENODEV;
-#endif
+
 	if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
 		return -ENODEV;
 
@@ -1210,7 +1368,7 @@
 	}
 	
 #ifdef SERIAL_DEBUG_OPEN
-	printk("rs_close ttys%d, count = %d\n", info->line, info->count);
+	printk("rs_close ttyS%02d, count = %d\n", info->line, info->count);
 #endif
 	if ((tty->count == 1) && (info->count != 1)) {
 		/*
@@ -1225,7 +1383,7 @@
 		info->count = 1;
 	}
 	if (--info->count < 0) {
-		printk("rs_close: bad serial port count for ttys%d: %d\n",
+		printk("rs_close: bad serial port count for ttyS%02d: %d\n",
 		       info->line, info->count);
 		info->count = 0;
 	}
@@ -1415,7 +1573,7 @@
 	retval = 0;
 	add_wait_queue(&info->open_wait, &wait);
 #ifdef SERIAL_DEBUG_OPEN
-	printk("block_til_ready before block: ttys%d, count = %d\n",
+	printk("block_til_ready before block: ttyS%02d, count = %d\n",
 	       info->line, info->count);
 #endif
 	cli();
@@ -1427,7 +1585,7 @@
 		cli();
 		if (!(info->flags & ZILOG_CALLOUT_ACTIVE) &&
 		    (tty->termios->c_cflag & CBAUD))
-			zs_rtsdtr(info, 1);
+			zs_rtsdtr(info, RTS | DTR, 1);
 		sti();
 		set_current_state(TASK_INTERRUPTIBLE);
 		if (tty_hung_up_p(filp) ||
@@ -1451,7 +1609,7 @@
 			break;
 		}
 #ifdef SERIAL_DEBUG_OPEN
-		printk("block_til_ready blocking: ttys%d, count = %d\n",
+		printk("block_til_ready blocking: ttyS%02d, count = %d\n",
 		       info->line, info->count);
 #endif
 		schedule();
@@ -1462,7 +1620,7 @@
 		info->count++;
 	info->blocked_open--;
 #ifdef SERIAL_DEBUG_OPEN
-	printk("block_til_ready after blocking: ttys%d, count = %d\n",
+	printk("block_til_ready after blocking: ttyS%02d, count = %d\n",
 	       info->line, info->count);
 #endif
 	if (retval)
@@ -1487,10 +1645,9 @@
 		return -ENODEV;
 	info = zs_soft + line;
 
-#ifdef CONFIG_KGDB
-	if (info->kgdb_channel)
+	if (info->hook)
 		return -ENODEV;
-#endif
+
 	if (serial_paranoia_check(info, tty->device, "rs_open"))
 		return -ENODEV;
 #ifdef SERIAL_DEBUG_OPEN
@@ -1520,7 +1677,7 @@
 	/*
 	 * Start up serial port
 	 */
-	retval = startup(info);
+	retval = zs_startup(info);
 	if (retval)
 		return retval;
 
@@ -1552,7 +1709,7 @@
 	info->pgrp = current->pgrp;
 
 #ifdef SERIAL_DEBUG_OPEN
-	printk("rs_open ttys%d successful...", info->line);
+	printk("rs_open ttyS%02d successful...", info->line);
 #endif
 /* tty->low_latency = 1; */
 	return 0;
@@ -1562,7 +1719,7 @@
 
 static void __init show_serial_version(void)
 {
-	printk("DECstation Z8530 serial driver version 0.03\n");
+	printk("DECstation Z8530 serial driver version 0.05\n");
 }
 
 /*  Initialize Z8530s zs_channels
@@ -1576,7 +1733,7 @@
 	/*
 	 * did we get here by accident?
 	 */
-	if(!IOASIC) {
+	if(!BUS_PRESENT) {
 		printk("Not on JUNKIO machine, skipping probe_sccs\n");
 		return;
 	}
@@ -1587,19 +1744,36 @@
 	 * system_base for this case :-(. HK
 	 */
 	switch(mips_machtype) {
+#ifdef CONFIG_DECSTATION
 	case MACH_DS5000_2X0:
 		system_base = 0xbf800000;
 		n_chips = 2;
+		zs_parms = &ds_parms;
 		break;
 	case MACH_DS5000_1XX:
 		system_base = 0xbc000000;
 		n_chips = 2;
+		zs_parms = &ds_parms;
 		break;
 	case MACH_DS5000_XX:
 		system_base = 0xbc000000;
 		n_chips = 1;
+		zs_parms = &ds_parms;
+		break;
+#endif
+#ifdef CONFIG_BAGET_MIPS
+	case MACH_BAGET202:
+		system_base = UNI_IO_BASE;
+		n_chips = 2;
+		zs_parms = &baget_parms;
+		zs_init_regs[2] = 0x8;
 		break;
+#endif
+	default:
+		panic("zs: unsupported bus");
 	}
+	if (!zs_parms)
+		panic("zs: uninitialized parms");
 
 	pp = &zs_chain;
 
@@ -1610,16 +1784,44 @@
 			/*
 			 * The sccs reside on the high byte of the 16 bit IOBUS
 			 */
-			zs_channels[n_channels].control = (volatile unsigned char *)
-				system_base + (0 == chip ? SCC0 : SCC1) + (0 == channel ? 1 : 9);
-			zs_channels[n_channels].data = zs_channels[n_channels].control + 4;
+			zs_channels[n_channels].control = 
+				(volatile unsigned char *)system_base + 
+			  (0 == chip ? zs_parms->scc0 : zs_parms->scc1) + 
+			  (0 == channel ? zs_parms->channel_a_offset : 
+			                  zs_parms->channel_b_offset);
+			zs_channels[n_channels].data = 
+				zs_channels[n_channels].control + 4;
+
+#ifndef CONFIG_SERIAL_CONSOLE
+			/*
+			 * We're called early and memory managment isn't up, yet.
+			 * Thus check_region would fail.
+			 */
+			if (check_region((unsigned long)
+					 zs_channels[n_channels].control,
+					 ZS_CHAN_IO_SIZE) < 0) {
+				panic("SCC I/O region is not free");
+			}
+			request_region((unsigned long)
+				       zs_channels[n_channels].control,
+				       ZS_CHAN_IO_SIZE, "SCC");
+#endif
 			zs_soft[n_channels].zs_channel = &zs_channels[n_channels];
-			zs_soft[n_channels].irq = SERIAL;
+			zs_soft[n_channels].irq = zs_parms->irq;
 
-			if (0 == channel)
-				zs_soft[n_channels].zs_chan_a = &zs_channels[n_channels+1];
+			/* 
+			 *  Identification of channel A. Location of channel A
+                         *  inside chip depends on mapping of internal address
+			 *  the chip decodes channels by.
+			 *  CHANNEL_A_NR returns either 0 (in case of 
+			 *  DECstations) or 1 (in case of Baget).
+			 */
+			if (CHANNEL_A_NR == channel)
+				zs_soft[n_channels].zs_chan_a = 
+				    &zs_channels[n_channels+1-2*CHANNEL_A_NR];
 			else
-				zs_soft[n_channels].zs_chan_a = &zs_channels[n_channels];
+				zs_soft[n_channels].zs_chan_a = 
+				    &zs_channels[n_channels];
 
 			*pp = &zs_soft[n_channels];
 			pp = &zs_soft[n_channels].zs_next;
@@ -1639,9 +1841,9 @@
 /*	save_and_cli(flags);
 	for (n = 0; n < zs_channels_found; n++) {
 		if (((int)zs_channels[n].control & 0xf) == 1) {
-			write_zsreg(zs_soft[channel].zs_chan_a, R9, FHWRES);
-			udelay(10000);
-			write_zsreg(zs_soft[channel].zs_chan_a, R9, 0);
+			write_zsreg(zs_soft[n].zs_chan_a, R9, FHWRES);
+			mdelay(10);
+			write_zsreg(zs_soft[n].zs_chan_a, R9, 0);
 		}
 		load_zsregs(zs_soft[n].zs_channel, zs_soft[n].zs_channel->curregs);
 	} 
@@ -1655,7 +1857,7 @@
 	unsigned long flags;
 	struct dec_serial *info;
 
-	if(!IOASIC)
+	if(!BUS_PRESENT)
 		return -ENODEV;
 
 	/* Setup base handler, and timer table. */
@@ -1672,7 +1874,11 @@
 
 	memset(&serial_driver, 0, sizeof(struct tty_driver));
 	serial_driver.magic = TTY_DRIVER_MAGIC;
+#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
+	serial_driver.name = "tts/%d";
+#else
 	serial_driver.name = "ttyS";
+#endif
 	serial_driver.major = TTY_MAJOR;
 	serial_driver.minor_start = 64;
 	serial_driver.num = zs_channels_found;
@@ -1682,7 +1888,7 @@
 
 	serial_driver.init_termios.c_cflag =
 		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-	serial_driver.flags = TTY_DRIVER_REAL_RAW;
+	serial_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
 	serial_driver.refcount = &serial_refcount;
 	serial_driver.table = serial_table;
 	serial_driver.termios = serial_termios;
@@ -1710,7 +1916,11 @@
 	 * major number and the subtype code.
 	 */
 	callout_driver = serial_driver;
+#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
+	callout_driver.name = "cua/%d";
+#else
 	callout_driver.name = "cua";
+#endif
 	callout_driver.major = TTYAUX_MAJOR;
 	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
 
@@ -1722,36 +1932,26 @@
 	save_flags(flags); cli();
 
 	for (channel = 0; channel < zs_channels_found; ++channel) {
-#ifdef CONFIG_KGDB
-		if (zs_soft[channel].kgdb_channel) {
-			continue;
-		}
-#endif
+		if (zs_soft[channel].hook &&
+		    zs_soft[channel].hook->init_channel)
+			(*zs_soft[channel].hook->init_channel)
+				(&zs_soft[channel]);
+
 		zs_soft[channel].clk_divisor = 16;
 		zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
 
-		if (request_irq(SERIAL, rs_interrupt, SA_SHIRQ,
+		if (request_irq(zs_parms->irq, rs_interrupt, SA_SHIRQ,
 				"SCC", &zs_soft[channel]))
 			printk(KERN_ERR "decserial: can't get irq %d\n",
-			       SERIAL);
-
-		/* If console serial line, then enable interrupts. */
-/*		if (zs_soft[channel].is_cons) {
-			write_zsreg(zs_soft[channel].zs_channel, R1,
-				    (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB));
-			write_zsreg(zs_soft[channel].zs_channel, R9,
-				    (VIS | MIE));
-		}
-*/
+			       zs_parms->irq);
 	}
 
 	for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
 	{
-#ifdef CONFIG_KGDB
-		if (info->kgdb_channel) {
+		if (info->hook && info->hook->init_info) {
+			(*info->hook->init_info)(info);
 			continue;
 		}
-#endif
 		info->magic = SERIAL_MAGIC;
 		info->port = (int) info->zs_channel->control;
 		info->line = i;
@@ -1765,13 +1965,18 @@
 		info->blocked_open = 0;
 		info->tqueue.routine = do_softint;
 		info->tqueue.data = info;
-		info->callout_termios =callout_driver.init_termios;
+		info->callout_termios = callout_driver.init_termios;
 		info->normal_termios = serial_driver.init_termios;
 		init_waitqueue_head(&info->open_wait);
 		init_waitqueue_head(&info->close_wait);
-		printk("tty%02d at 0x%08x (irq = %d)", info->line, 
+		printk("ttyS%02d at 0x%08x (irq = %d)", info->line, 
 		       info->port, info->irq);
 		printk(" is a Z85C30 SCC\n");
+		tty_register_devfs(&serial_driver, 0,
+				   serial_driver.minor_start + info->line);
+		tty_register_devfs(&callout_driver, 0,
+				   callout_driver.minor_start + info->line);
+
 	}
 
 	restore_flags(flags);
@@ -1795,38 +2000,116 @@
 }
 
 /*
- * ------------------------------------------------------------
- * Serial console driver
- * ------------------------------------------------------------
+ * polling I/O routines
  */
-#ifdef CONFIG_SERIAL_CONSOLE
+static int
+zs_poll_tx_char(struct dec_serial *info, unsigned char ch)
+{
+	struct dec_zschannel *chan = info->zs_channel;
+	int    ret;
 
+	if(chan) {
+		int loops = 10000;
+//		int nine = read_zsreg(chan, R9);
 
-/*
- *	Print a string to the serial port trying not to disturb
- *	any possible real use of the port...
- */
+		RECOVERY_DELAY;
+//        	write_zsreg(chan, R9, nine & ~MIE);
+               	wbflush();
+		RECOVERY_DELAY;
+
+        	while (!(*(chan->control) & Tx_BUF_EMP) && --loops)
+	        	RECOVERY_DELAY;
+
+                if (loops) {
+                        ret = 0;
+        	        *(chan->data) = ch;
+                	wbflush();
+			RECOVERY_DELAY;
+                } else
+                        ret = -EAGAIN;
+
+//        	write_zsreg(chan, R9, nine);
+               	wbflush();
+		RECOVERY_DELAY;
+
+                return ret;
+        }
 
-/* This is for console output */
-static void
-zs_console_putchar(struct dec_serial *info, char ch)
+	return -ENODEV;
+}
+
+static int
+zs_poll_rx_char(struct dec_serial *info)
 {
-	int loops = 10000;
-	unsigned long flags;
+        struct dec_zschannel *chan = info->zs_channel;
+        int    ret;
 
-	if(!info->zs_channel)
-		return;
+	if(chan) {
+                int loops = 10000;
 
-	save_flags(flags); cli();
+                while((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
+		        loops--;
 
-	while (!(*(info->zs_channel->control) & Tx_BUF_EMP) && --loops)
-		RECOVERY_DELAY;
-	*(info->zs_channel->data) = ch;
-	wbflush(); RECOVERY_DELAY;
+                if (loops)
+                        ret = read_zsdata(chan);
+                else
+                        ret = -EAGAIN;
 
-	restore_flags(flags);
+                return ret;
+        } else
+                return -ENODEV;
+}
+
+unsigned int register_zs_hook(unsigned int channel, struct zs_hook *hook)
+{
+	struct dec_serial *info = &zs_soft[channel];
+
+	if (info->hook) {
+		printk(__FUNCTION__": line %d has already a hook registered\n", channel);
+
+		return 0;
+	} else {
+		info->hook = hook;
+
+		if (zs_chain == 0)
+			probe_sccs();
+
+		if (!(info->flags & ZILOG_INITIALIZED))
+			zs_startup(info);
+
+		hook->poll_rx_char = zs_poll_rx_char;
+		hook->poll_tx_char = zs_poll_tx_char;
+
+		return 1;
+	}
+}
+
+unsigned int unregister_zs_hook(unsigned int channel)
+{
+	struct dec_serial *info = &zs_soft[channel];
+
+        if (info->hook) {
+                info->hook = NULL;
+                return 1;
+        } else {
+                printk(__FUNCTION__": trying to unregister hook on line %d,"
+                       " but none is registered\n", channel);
+                return 0;
+        }
 }
 
+/*
+ * ------------------------------------------------------------
+ * Serial console driver
+ * ------------------------------------------------------------
+ */
+#ifdef CONFIG_SERIAL_CONSOLE
+
+
+/*
+ *	Print a string to the serial port trying not to disturb
+ *	any possible real use of the port...
+ */
 static void serial_console_write(struct console *co, const char *s,
 				 unsigned count)
 {
@@ -1835,28 +2118,11 @@
 
 	info = zs_soft + co->index;
 
-#if 0
-	/*
-	 * disable master interrupt if necessary
-	 */
-	nine = info->zs_channel->curregs[9];
-	if(nine & MIE)
-		write_zsreg(info->zs_channel, R9, nine & ~MIE);
-#endif
-	/*
-	 * do it
-	 */
 	for (i = 0; i < count; i++, s++) {
 		if(*s == '\n')
-			zs_console_putchar(info, '\r');
-		zs_console_putchar(info, *s);
+			zs_poll_tx_char(info, '\r');
+		zs_poll_tx_char(info, *s);
 	}
-	/*
-	 * restore master interrupt enable
-	 */
-#if 0
-	write_zsreg(info->zs_channel, R9, nine);
-#endif
 }
 
 /*
@@ -1864,7 +2130,11 @@
  */
 static int serial_console_wait_key(struct console *co)
 {
-	return 0;
+	struct dec_serial *info;
+
+        info = zs_soft + co->index;
+
+        return zs_poll_rx_char(info);
 }
 
 static kdev_t serial_console_device(struct console *c)
@@ -1888,7 +2158,7 @@
 	char	*s;
 	unsigned long flags;
 
-	if(!IOASIC)
+	if(!BUS_PRESENT)
 		return -ENODEV;
 
 	info = zs_soft + co->index;
@@ -1963,7 +2233,7 @@
 	/*
 	 * Turn on RTS and DTR.
 	 */
-	zs_rtsdtr(info, 1);
+	zs_rtsdtr(info, RTS | DTR, 1);
 
 	/*
 	 * Finally, enable sequencing
@@ -2017,6 +2287,18 @@
 #endif /* ifdef CONFIG_SERIAL_CONSOLE */
 
 #ifdef CONFIG_KGDB
+struct dec_zschannel *zs_kgdbchan;
+static unsigned char scc_inittab[] = {
+	9,  0x80,	/* reset A side (CHRA) */
+	13, 0,		/* set baud rate divisor */
+	12, 1,
+	14, 1,		/* baud rate gen enable, src=rtxc (BRENABL) */
+	11, 0x50,	/* clocks = br gen (RCBR | TCBR) */
+	5,  0x6a,	/* tx 8 bits, assert RTS (Tx8 | TxENAB | RTS) */
+	4,  0x44,	/* x16 clock, 1 stop (SB1 | X16CLK)*/
+	3,  0xc1,	/* rx enable, 8 bits (RxENABLE | Rx8)*/
+};
+
 /* These are for receiving and sending characters under the kgdb
  * source level kernel debugger.
  */
@@ -2051,6 +2333,25 @@
 	write_zsreg(chan, 1, one);
 	write_zsreg(chan, 9, nine);
 }
+
+static int kgdbhook_init_channel(struct dec_serial* info) 
+{
+	return 0;
+}
+
+static void kgdbhook_init_info(struct dec_serial* info)
+{
+}
+
+static void kgdbhook_rx_char(struct dec_serial* info, 
+			     unsigned char ch, unsigned char stat)
+{
+	if (ch == 0x03 || ch == '$')
+		breakpoint();
+	if (stat & (Rx_OVR|FRM_ERR|PAR_ERR))
+		write_zsreg(info->zs_channel, 0, ERR_RES);
+}
+
 /* This sets up the serial port we're using, and turns on
  * interrupts for that channel, so kgdb is usable once we're done.
  */
@@ -2059,7 +2360,7 @@
 	int brg;
 	int i, x;
 	volatile char *sccc = ms->control;
-	brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
+	brg = BPS_TO_BRG(bps, zs_parms->clock/16);
 	printk("setting bps on kgdb line to %d [brg=%x]\n", bps, brg);
 	for (i = 20000; i != 0; --i) {
 		x = *sccc; eieio();
@@ -2074,6 +2375,13 @@
  * for /dev/ttyb which is determined in setup_arch() from the
  * boot command line flags.
  */
+struct zs_hook zs_kgdbhook = {
+	init_channel : kgdbhook_init_channel,
+	init_info    : kgdbhook_init_info,
+	cflags       : B38400|CS8|CLOCAL,
+	rx_char      : kgdbhook_rx_char,
+}
+
 void __init zs_kgdb_hook(int tty_num)
 {
 	/* Find out how many Z8530 SCCs we have */
@@ -2084,11 +2392,12 @@
 	zs_soft[tty_num].change_needed = 0;
 	zs_soft[tty_num].clk_divisor = 16;
 	zs_soft[tty_num].zs_baud = 38400;
-	zs_soft[tty_num].kgdb_channel = 1;     /* This runs kgdb */
-	zs_soft[tty_num ^ 1].kgdb_channel = 0; /* This does not */
+ 	zs_soft[tty_num].hook = &zs_kgdbhook; /* This runs kgdb */
 	/* Turn on transmitter/receiver at 8-bits/char */
         kgdb_chaninit(zs_soft[tty_num].zs_channel, 1, 38400);
 	printk("KGDB: on channel %d initialized\n", tty_num);
 	set_debug_traps(); /* init stub */
 }
 #endif /* ifdef CONFIG_KGDB */
+
+
diff -u --recursive --new-file v2.4.9/linux/drivers/tc/zs.h linux/drivers/tc/zs.h
--- v2.4.9/linux/drivers/tc/zs.h	Sat May 13 08:31:25 2000
+++ linux/drivers/tc/zs.h	Mon Aug 27 08:56:31 2001
@@ -89,6 +89,18 @@
 	unsigned char curregs[NUM_ZSREGS];
 };
 
+struct dec_serial;
+
+struct zs_hook {
+	int (*init_channel)(struct dec_serial* info);
+	void (*init_info)(struct dec_serial* info);
+	void (*rx_char)(unsigned char ch, unsigned char stat);
+	int  (*poll_rx_char)(struct dec_serial* info);
+	int  (*poll_tx_char)(struct dec_serial* info,
+			     unsigned char ch);
+	unsigned cflags;
+};
+
 struct dec_serial {
 	struct dec_serial *zs_next;	/* For IRQ servicing chain */
 	struct dec_zschannel *zs_channel; /* Channel registers */
@@ -97,7 +109,7 @@
 
 	char soft_carrier;  /* Use soft carrier on this channel */
 	char break_abort;   /* Is serial console in, so process brk/abrt */
-	char kgdb_channel;  /* Kgdb is running on this channel */
+	struct zs_hook *hook;  /* Hook on this channel */
 	char is_cons;       /* Is this our console. */
 	unsigned char tx_active; /* character is being xmitted */
 	unsigned char tx_stopped; /* output is suspended */
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/Config.in linux/drivers/usb/Config.in
--- v2.4.9/linux/drivers/usb/Config.in	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/Config.in	Tue Aug 28 11:21:02 2001
@@ -67,7 +67,8 @@
    dep_tristate '  PLUSB Prolific USB-Network driver (EXPERIMENTAL)' CONFIG_USB_PLUSB $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
    dep_tristate '  USB ADMtek Pegasus-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
    dep_tristate '  USB CATC NetMate-based Ethernet driver (EXPERIMENTAL)' CONFIG_USB_CATC $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
-   dep_tristate '  NetChip 1080-based USB Host-to-Host Link (EXPERIMENTAL)' CONFIG_USB_NET1080 $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
+   dep_tristate '  USB KLSI KL5USB101-based ethernet device support (EXPERIMENTAL)' CONFIG_USB_KAWETH $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
+   dep_tristate '  USB-to-USB Networking (NetChip, Prolific, ...) (EXPERIMENTAL)' CONFIG_USB_USBNET $CONFIG_USB $CONFIG_NET $CONFIG_EXPERIMENTAL
 
    comment 'USB port drivers'
    dep_tristate '  USS720 parport driver' CONFIG_USB_USS720 $CONFIG_USB $CONFIG_PARPORT
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/Makefile linux/drivers/usb/Makefile
--- v2.4.9/linux/drivers/usb/Makefile	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/Makefile	Tue Aug 28 11:21:02 2001
@@ -65,11 +65,12 @@
 obj-$(CONFIG_USB_SE401)		+= se401.o
 obj-$(CONFIG_USB_PEGASUS)	+= pegasus.o
 obj-$(CONFIG_USB_CATC)		+= catc.o
+obj-$(CONFIG_USB_KAWETH)        += kaweth.o
 obj-$(CONFIG_USB_RIO500)	+= rio500.o
 obj-$(CONFIG_USB_DSBR)		+= dsbr100.o
 obj-$(CONFIG_USB_MICROTEK)	+= microtek.o
 obj-$(CONFIG_USB_BLUETOOTH)	+= bluetooth.o
-obj-$(CONFIG_USB_NET1080)	+= net1080.o
+obj-$(CONFIG_USB_USBNET)	+= usbnet.o
 
 # Object files in subdirectories
 
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/bluetooth.c linux/drivers/usb/bluetooth.c
--- v2.4.9/linux/drivers/usb/bluetooth.c	Wed Jul 25 17:10:23 2001
+++ linux/drivers/usb/bluetooth.c	Tue Aug 28 11:21:02 2001
@@ -159,7 +159,6 @@
 #define RELEVANT_IFLAG(iflag)	(iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
 
 #define CHAR2INT16(c1,c0)	(((u32)((c1) & 0xff) << 8) + (u32)((c0) & 0xff))
-#define MIN(a,b)		(((a)<(b))?(a):(b))
 
 #define NUM_BULK_URBS		24
 #define NUM_CONTROL_URBS	16
@@ -518,7 +517,7 @@
 				}
 				
 
-				buffer_size = MIN (count, bluetooth->bulk_out_buffer_size);
+				buffer_size = min (int, count, bluetooth->bulk_out_buffer_size);
 				memcpy (urb->transfer_buffer, current_position, buffer_size);
 
 				/* build up our urb */
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/dc2xx.c linux/drivers/usb/dc2xx.c
--- v2.4.9/linux/drivers/usb/dc2xx.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/dc2xx.c	Tue Aug 28 11:21:02 2001
@@ -63,6 +63,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/devfs_fs_kernel.h>
 
 #ifdef CONFIG_USB_DEBUG
 	#define DEBUG
@@ -72,6 +73,9 @@
 #include <linux/usb.h>
 
 
+/* /dev/usb dir. */
+extern devfs_handle_t usb_devfs_handle;			
+
 /*
  * Version Information
  */
@@ -137,11 +141,12 @@
 	/* this is non-null iff the device is open */
 	char			*buf;		/* buffer for I/O */
 
+	devfs_handle_t		devfs;		/* devfs device */
+
 	/* always valid */
 	wait_queue_head_t	wait;		/* for timed waits */
 };
 
-
 /* Support multiple cameras, possibly of different types.  */
 static struct camera_state *minor_data [MAX_CAMERAS];
 
@@ -368,8 +373,10 @@
 	struct usb_interface_descriptor	*interface;
 	struct usb_endpoint_descriptor	*endpoint;
 	int				direction, ep;
+	char name[8];
 	struct camera_state		*camera = NULL;
 
+
 	/* these have one config, one interface */
 	if (dev->descriptor.bNumConfigurations != 1
 			|| dev->config[0].bNumInterfaces != 1) {
@@ -446,6 +453,15 @@
 
 	camera->dev = dev;
 	usb_inc_dev_use (dev);
+
+	/* If we have devfs, register the device */
+	sprintf(name, "dc2xx%d", camera->subminor);
+	camera->devfs = devfs_register(usb_devfs_handle, name,
+				       DEVFS_FL_DEFAULT, USB_MAJOR,
+				       USB_CAMERA_MINOR_BASE + camera->subminor,
+				       S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
+				       S_IWGRP, &usb_camera_fops, NULL);
+
 	goto bye;
 
 error:
@@ -464,6 +480,8 @@
 
 	down (&state_table_mutex);
 	down (&camera->sem);
+
+	devfs_unregister(camera->devfs); 
 
 	/* If camera's not opened, we can clean up right away.
 	 * Else apps see a disconnect on next I/O; the release cleans.
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/inode.c linux/drivers/usb/inode.c
--- v2.4.9/linux/drivers/usb/inode.c	Wed Jul 25 17:10:23 2001
+++ linux/drivers/usb/inode.c	Tue Aug 28 10:56:06 2001
@@ -751,7 +751,6 @@
 		usb_deregister(&usbdevfs_driver);
 		return ret;
 	}
-	kern_mount(&usbdevice_fs_type);
 #ifdef CONFIG_PROC_FS		
 	/* create mount point for usbdevfs */
 	usbdir = proc_mkdir("usb", proc_bus);
@@ -763,7 +762,6 @@
 {
 	usb_deregister(&usbdevfs_driver);
 	unregister_filesystem(&usbdevice_fs_type);
-	kern_umount(usbdevice_fs_type.kern_mnt);
 #ifdef CONFIG_PROC_FS	
         if (usbdir)
                 remove_proc_entry("usb", proc_bus);
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/kaweth.c linux/drivers/usb/kaweth.c
--- v2.4.9/linux/drivers/usb/kaweth.c	Mon Aug 27 12:41:45 2001
+++ linux/drivers/usb/kaweth.c	Tue Aug 28 11:21:02 2001
@@ -248,9 +248,9 @@
 	
 	dr->requesttype = requesttype;
 	dr->request = request;
-	dr->value = value;
-	dr->index = index;
-	dr->length = size;
+	dr->value = cpu_to_le16p(&value);
+	dr->index = cpu_to_le16p(&index);
+	dr->length = cpu_to_le16p(&size);
 
 	return kaweth_internal_control_msg(kaweth->dev,
 					pipe,
@@ -370,6 +370,9 @@
 	kaweth->firmware_buf[4] = type;
 	kaweth->firmware_buf[5] = interrupt;
 
+	kaweth_dbg("High: %i, Low:%i", kaweth->firmware_buf[3],
+		   kaweth->firmware_buf[2]);
+
 	kaweth_dbg("Downloading firmware at %x to kaweth device at %x", 
 	    (int)data, 
 	    (int)kaweth);
@@ -476,7 +479,7 @@
 	int count = urb->actual_length;
 	int count2 = urb->transfer_buffer_length;
 			
-	__u16 pkt_len = *(__u16 *)kaweth->rx_buf;
+	__u16 pkt_len = le16_to_cpup(kaweth->rx_buf);
 
 	struct sk_buff *skb;
 
@@ -608,7 +611,7 @@
 	kaweth_async_set_rx_mode(kaweth);
 	netif_stop_queue(net);
 
-	*((__u16 *)kaweth->tx_buf) = skb->len;
+	*((__u16 *)kaweth->tx_buf) = cpu_to_le16(skb->len);
 
 	memcpy(kaweth->tx_buf + 2, skb->data, skb->len);
 
@@ -719,8 +722,6 @@
 	net->trans_start = jiffies;
 
 	usb_unlink_urb(kaweth->tx_urb);
-
-	netif_wake_queue(net);
 }
 
 /****************************************************************
@@ -836,7 +837,7 @@
 
 	kaweth_info("Statistics collection: %x", kaweth->configuration.statistics_mask);
 	kaweth_info("Multicast filter limit: %x", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1));
-	kaweth_info("MTU: %d", kaweth->configuration.segment_size);
+	kaweth_info("MTU: %d", le16_to_cpu(kaweth->configuration.segment_size));
 	kaweth_info("Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
 		 (int)kaweth->configuration.hw_addr[0],
 		 (int)kaweth->configuration.hw_addr[1],
@@ -879,6 +880,10 @@
 	kaweth->rx_urb = usb_alloc_urb(0);
 
 	kaweth->net = init_etherdev(0, 0);
+	if (!kaweth->net) {
+		kaweth_err("Error calling init_etherdev.");
+		return kaweth;
+	}
 
 	memcpy(kaweth->net->broadcast, &bcast_addr, sizeof(bcast_addr));
 	memcpy(kaweth->net->dev_addr, 
@@ -896,7 +901,7 @@
 	kaweth->net->hard_start_xmit = kaweth_start_xmit;
 	kaweth->net->set_multicast_list = kaweth_set_rx_mode;
 	kaweth->net->get_stats = kaweth_netdev_stats;
-	kaweth->net->mtu = kaweth->configuration.segment_size;
+	kaweth->net->mtu = le16_to_cpu(kaweth->configuration.segment_size);
 
 	memset(&kaweth->stats, 0, sizeof(kaweth->stats));
 
@@ -1051,4 +1056,11 @@
 
 module_init(kaweth_init);
 module_exit(kaweth_exit);
+
+
+
+
+
+
+
 
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/mdc800.c linux/drivers/usb/mdc800.c
--- v2.4.9/linux/drivers/usb/mdc800.c	Wed Jul 25 17:10:23 2001
+++ linux/drivers/usb/mdc800.c	Tue Aug 28 11:21:02 2001
@@ -610,16 +610,18 @@
 	spin_lock (&mdc800->io_lock);
 	if (mdc800->open && (mdc800->state != NOT_CONNECTED))
 	{
-		mdc800->open=0;
+		spin_unlock(&mdc800->io_lock);
 		usb_unlink_urb (mdc800->irq_urb);
 		usb_unlink_urb (mdc800->write_urb);
 		usb_unlink_urb (mdc800->download_urb);
+		mdc800->open=0;
 	}
 	else
 	{
+		spin_unlock (&mdc800->io_lock);
 		retval=-EIO;
 	}
-	spin_unlock (&mdc800->io_lock);
+
 
 	return retval;
 }
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/net1080.c linux/drivers/usb/net1080.c
--- v2.4.9/linux/drivers/usb/net1080.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/net1080.c	Wed Dec 31 16:00:00 1969
@@ -1,1128 +0,0 @@
-/*
- * NetChip 1080 Driver (USB Host-to-Host Link)
- * Copyright (C) 2000 by David Brownell <dbrownell@users.sourceforge.net>
- */
-
-/*
- * This talks to the NetChip 1080, which can appear in "network cables"
- * and other designs.  This driver interoperates with the Win32 network
- * drivers from NetChip, using the NetChip reference design.
- *
- * The IP-over-USB protocol here may be of interest.  Embedded devices
- * could implement it at the cost of two bulk endpoints, and whatever
- * other system resources the desired IP-based applications need.
- * Some Linux palmtops could support that today.  (Devices that don't
- * support the TTL-driven data mangling of the net1080 chip won't need
- * the header/trailer support though.)
- * 
- * STATUS:
- *
- * 13-sept-2000		experimental, new
- *
- * This doesn't yet do any network hotplugging, and there's no matching
- * ifup policy script ... it should arrange bridging with "brctl", and
- * should handle static and dynamic ("pump") setups.
- *
- * RX/TX queue sizes currently fixed at one due to URB unlink problems.
- *
- * 10-oct-2000
- * usb_device_id table created. 
- *
- * 28-oct-2000
- * misc fixes; mostly, discard more TTL-mangled rx packets.
- *
- * 01-nov-2000
- * usb_device_id table support added by Adam J. Richter <adam@yggdrasil.com>.
- * 
- * 08-apr-2001 gb
- * Identify version on module load.
- * 
- *-------------------------------------------------------------------------*/
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kmod.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/random.h>
-#include <asm/unaligned.h>
-
-#define DEBUG				// error path messages
-// #define VERBOSE			// more; success messages
-#define USE_TTL				// timeout our reads
-
-#if !defined (DEBUG) && defined (CONFIG_USB_DEBUG)
-#   define DEBUG
-#endif
-#include <linux/usb.h>
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.0.0"
-#define DRIVER_AUTHOR "David Brownell <dbrownell@users.sourceforge.net>"
-#define DRIVER_DESC "NetChip 1080 Driver (USB Host-to-Host Link)"
-
-
-static const struct usb_device_id	products [] = {
-	// reference design
-	{ USB_DEVICE(0x1080, 0x525), 
-	  driver_info: (unsigned long) "NetChip TurboCONNECT" },
-	// Belkin, ...
-	{ },		// END
-};
-
-MODULE_DEVICE_TABLE (usb, products);
-
-static u8	node_id [ETH_ALEN];
-
-
-/*-------------------------------------------------------------------------
- *
- * NetChip protocol:  ethernet framing, and only use bulk endpoints (01/81;
- * not mailboxes 02/82 or status interrupt 83).  Expects Ethernet bridging.
- * Odd USB length == always short read.
- *	- nc_header
- *	- payload, in Ethernet framing (14 byte header etc)
- *	- (optional padding byte, if needed so length is odd)
- *	- nc_trailer
- */
-
-struct nc_header {
-	u16	hdr_len;		// sizeof nc_header (LE, all)
-	u16	packet_len;		// packet size
-	u16	packet_id;		// detects dropped packets
-#define NC_MIN_HEADER	6
-
-	// all else is optional, and must start with:
-	// u16	vendorId;		// from usb-if
-	// u16	productId;
-};
-
-#define	NC_PAD_BYTE	((unsigned char)0xAC)
-
-struct nc_trailer {
-	u16	packet_id;
-};
-
-// packetsize == f(mtu setting), with upper limit
-#define NC_MAX_PACKET(mtu) (sizeof (struct nc_header) \
-				+ (mtu) \
-				+ 1 \
-				+ sizeof (struct nc_trailer))
-#define MAX_PACKET	8191
-
-// zero means no timeout; else, how long a 64 byte bulk
-// read may be queued before HW flushes it.
-#define	NC_READ_TTL	((u8)255)	// ms
-
-
-/*-------------------------------------------------------------------------*/
-
-// list of all devices we manage
-static DECLARE_MUTEX (net1080_mutex);
-static LIST_HEAD (net1080_list);
-
-
-// Nineteen USB 1.1 max size bulk transactions per frame, max.
-#if 0
-#define	RX_QLEN		4
-#define	TX_QLEN		4
-
-#else
-// unlink_urbs() has probs on OHCI without test8-pre patches.
-#define	RX_QLEN		1
-#define	TX_QLEN		1
-#endif
-
-enum skb_state {
-	illegal = 0,
-	tx_start, tx_done,
-	rx_start, rx_done, rx_cleanup
-};
-
-struct skb_data {	// skb->cb is one of these
-	struct urb		*urb;
-	struct net1080		*dev;
-	enum skb_state		state;
-	size_t			length;
-};
-
-
-struct net1080 {
-	// housekeeping
-	struct usb_device	*udev;
-	const struct usb_device_id	*prod_info;
-	struct semaphore	mutex;
-	struct list_head	dev_list;
-	wait_queue_head_t	*wait;
-
-	// protocol/interface state
-	struct net_device	net;
-	struct net_device_stats	stats;
-	u16			packet_id;
-
-	// various kinds of pending driver work
-	struct sk_buff_head	rxq;
-	struct sk_buff_head	txq;
-	struct sk_buff_head	done;
-	struct tasklet_struct	bh;
-};
-
-#define	mutex_lock(x)	down(x)
-#define	mutex_unlock(x)	up(x)
-
-static void defer_bh (struct net1080 *dev, struct sk_buff *skb)
-{
-	unsigned long	flags;
-
-	skb_unlink (skb);
-	spin_lock_irqsave (&dev->done.lock, flags);
-	__skb_queue_tail (&dev->done, skb);
-	if (dev->done.qlen == 1)
-		tasklet_schedule (&dev->bh);
-	spin_unlock_irqrestore (&dev->done.lock, flags);
-}
-
-/*-------------------------------------------------------------------------
- *
- * We ignore most registers and EEPROM contents.
- */
-
-#define	REG_USBCTL	((u8)0x04)
-#define REG_TTL		((u8)0x10)
-#define REG_STATUS	((u8)0x11)
-
-/*
- * Vendor specific requests to read/write data
- */
-
-#define	REQUEST_REGISTER	((u8)0x10)
-#define	REQUEST_EEPROM		((u8)0x11)
-
-#define	CONTROL_TIMEOUT		(500)			/* msec */
-
-static int
-vendor_read (struct net1080 *dev, u8 req, u8 regnum, u16 *retval_ptr)
-{
-	int status = usb_control_msg (dev->udev,
-		usb_rcvctrlpipe (dev->udev, 0),
-		req,
-		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-		0, regnum,
-		retval_ptr, sizeof *retval_ptr,
-		CONTROL_TIMEOUT);
-	if (status > 0)
-		status = 0;
-	if (!status)
-		le16_to_cpus (retval_ptr);
-	return status;
-}
-
-static inline int
-register_read (struct net1080 *dev, u8 regnum, u16 *retval_ptr)
-{
-	return vendor_read (dev, REQUEST_REGISTER, regnum, retval_ptr);
-}
-
-// without retval, this can become fully async (usable in_interrupt)
-static void
-vendor_write (struct net1080 *dev, u8 req, u8 regnum, u16 value)
-{
-	usb_control_msg (dev->udev,
-		usb_sndctrlpipe (dev->udev, 0),
-		req,
-		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-		value, regnum,
-		0, 0,			// data is in setup packet
-		CONTROL_TIMEOUT);
-}
-
-static inline void
-register_write (struct net1080 *dev, u8 regnum, u16 value)
-{
-	vendor_write (dev, REQUEST_REGISTER, regnum, value);
-}
-
-
-#if 0
-static void dump_registers (struct net1080 *dev)
-{
-	u8	reg;
-	u16	value;
-
-	dbg ("%s registers:", dev->net.name);
-	for (reg = 0; reg < 0x20; reg++) {
-		int retval;
-
-		// reading some registers is trouble
-		if (reg >= 0x08 && reg <= 0xf)
-			continue;
-		if (reg >= 0x12 && reg <= 0x1e)
-			continue;
-
-		retval = register_read (dev, reg, &value);
-		if (retval < 0)
-			dbg ("%s reg [0x%x] ==> error %d",
-				dev->net.name, reg, retval);
-		else
-			dbg ("%s reg [0x%x] = 0x%x",
-				dev->net.name, reg, value);
-	}
-}
-#endif
-
-
-/*-------------------------------------------------------------------------
- *
- * Control register
- */
-
-#define	USBCTL_WRITABLE_MASK	0x1f0f
-// bits 15-13 reserved, r/o
-#define	USBCTL_ENABLE_LANG	(1 << 12)
-#define	USBCTL_ENABLE_MFGR	(1 << 11)
-#define	USBCTL_ENABLE_PROD	(1 << 10)
-#define	USBCTL_ENABLE_SERIAL	(1 << 9)
-#define	USBCTL_ENABLE_DEFAULTS	(1 << 8)
-// bits 7-4 reserved, r/o
-#define	USBCTL_FLUSH_OTHER	(1 << 3)
-#define	USBCTL_FLUSH_THIS	(1 << 2)
-#define	USBCTL_DISCONN_OTHER	(1 << 1)
-#define	USBCTL_DISCONN_THIS	(1 << 0)
-
-#ifdef DEBUG
-static void dump_usbctl (struct net1080 *dev, u16 usbctl)
-{
-	dbg ("%s: USB %d dev %d usbctl 0x%x:%s%s%s%s%s;"
-			" this%s%s;"
-			" other%s%s; r/o 0x%x",
-		dev->net.name,
-		dev->udev->bus->busnum, dev->udev->devnum,
-		usbctl,
-		(usbctl & USBCTL_ENABLE_LANG) ? " lang" : "",
-		(usbctl & USBCTL_ENABLE_MFGR) ? " mfgr" : "",
-		(usbctl & USBCTL_ENABLE_PROD) ? " prod" : "",
-		(usbctl & USBCTL_ENABLE_SERIAL) ? " serial" : "",
-		(usbctl & USBCTL_ENABLE_DEFAULTS) ? " defaults" : "",
-
-		(usbctl & USBCTL_FLUSH_OTHER) ? " FLUSH" : "",
-		(usbctl & USBCTL_DISCONN_OTHER) ? " DIS" : "",
-		(usbctl & USBCTL_FLUSH_THIS) ? " FLUSH" : "",
-		(usbctl & USBCTL_DISCONN_THIS) ? " DIS" : "",
-		usbctl & ~USBCTL_WRITABLE_MASK
-		);
-}
-#else
-static inline void dump_usbctl (struct net1080 *dev, u16 usbctl) {}
-#endif
-
-/*-------------------------------------------------------------------------
- *
- * Status register
- */
-
-#define	STATUS_PORT_A		(1 << 15)
-
-#define	STATUS_CONN_OTHER	(1 << 14)
-#define	STATUS_SUSPEND_OTHER	(1 << 13)
-#define	STATUS_MAILBOX_OTHER	(1 << 12)
-#define	STATUS_PACKETS_OTHER(n)	(((n) >> 8) && 0x03)
-
-#define	STATUS_CONN_THIS	(1 << 6)
-#define	STATUS_SUSPEND_THIS	(1 << 5)
-#define	STATUS_MAILBOX_THIS	(1 << 4)
-#define	STATUS_PACKETS_THIS(n)	(((n) >> 0) && 0x03)
-
-#define	STATUS_UNSPEC_MASK	0x0c8c
-#define	STATUS_NOISE_MASK 	((u16)~(0x0303|STATUS_UNSPEC_MASK))
-
-
-#ifdef DEBUG
-static void dump_status (struct net1080 *dev, u16 status)
-{
-	dbg ("%s: USB %d dev %d status 0x%x:"
-			" this (%c) PKT=%d%s%s%s;"
-			" other PKT=%d%s%s%s; unspec 0x%x",
-		dev->net.name,
-		dev->udev->bus->busnum, dev->udev->devnum,
-		status,
-
-		// XXX the packet counts don't seem right
-		// (1 at reset, not 0); maybe UNSPEC too
-
-		(status & STATUS_PORT_A) ? 'A' : 'B',
-		STATUS_PACKETS_THIS (status),
-		(status & STATUS_CONN_THIS) ? " CON" : "",
-		(status & STATUS_SUSPEND_THIS) ? " SUS" : "",
-		(status & STATUS_MAILBOX_THIS) ? " MBOX" : "",
-
-		STATUS_PACKETS_OTHER (status),
-		(status & STATUS_CONN_OTHER) ? " CON" : "",
-		(status & STATUS_SUSPEND_OTHER) ? " SUS" : "",
-		(status & STATUS_MAILBOX_OTHER) ? " MBOX" : "",
-
-		status & STATUS_UNSPEC_MASK
-		);
-}
-#else
-static inline void dump_status (struct net1080 *dev, u16 status) {}
-#endif
-
-/*-------------------------------------------------------------------------
- *
- * TTL register
- */
-
-#define	TTL_THIS(ttl)	(0x00ff & ttl)
-#define	TTL_OTHER(ttl)	(0x00ff & (ttl >> 8))
-#define MK_TTL(this,other)	((u16)(((other)<<8)|(0x00ff&(this))))
-
-#ifdef DEBUG
-static void dump_ttl (struct net1080 *dev, u16 ttl)
-{
-	dbg ("%s: USB %d dev %d ttl 0x%x this = %d, other = %d",
-		dev->net.name,
-		dev->udev->bus->busnum, dev->udev->devnum,
-		ttl,
-
-		TTL_THIS (ttl),
-		TTL_OTHER (ttl)
-		);
-}
-#else
-static inline void dump_ttl (struct net1080 *dev, u16 ttl) {}
-#endif
-
-#define	RUN_CONTEXT (in_irq () ? "in_irq" \
-			: (in_interrupt () ? "in_interrupt" : "can sleep"))
-
-/*-------------------------------------------------------------------------*/
-
-// ensure that the device is in a known state before using it.
-
-// preconditions:
-//	caller owns the device mutex
-//	caller has a process context
-
-static int net1080_reset (struct net1080 *dev)
-{
-	u16		usbctl, status, ttl;
-	int		retval;
-
-	if ((retval = register_read (dev, REG_STATUS, &status)) < 0) {
-		dbg ("can't read dev %d status: %d", dev->udev->devnum, retval);
-		goto done;
-	}
-	dump_status (dev, status);
-
-	if ((retval = register_read (dev, REG_USBCTL, &usbctl)) < 0) {
-		dbg ("can't read USBCTL, %d", retval);
-		goto done;
-	}
-	dump_usbctl (dev, usbctl);
-
-	register_write (dev, REG_USBCTL,
-			USBCTL_FLUSH_THIS | USBCTL_FLUSH_OTHER);
-
-	if ((retval = register_read (dev, REG_TTL, &ttl)) < 0) {
-		dbg ("can't read TTL, %d", retval);
-		goto done;
-	}
-	dump_ttl (dev, ttl);
-
-#ifdef	USE_TTL
-	// Have the chip flush reads that seem to be starving for read
-	// bandwidth ... or we're otherwise reading.  Note, Win32 drivers
-	// may change our read TTL for us.
-
-	register_write (dev, REG_TTL,
-			MK_TTL (NC_READ_TTL, TTL_OTHER (ttl)) );
-	dbg ("%s: assigned TTL, %d ms", dev->net.name, NC_READ_TTL);
-#endif
-
-	info ("%s: %s, port %c on USB %d dev %d, peer %sconnected",
-		dev->net.name, (char *) dev->prod_info->driver_info,
-		(status & STATUS_PORT_A) ? 'A' : 'B',
-		dev->udev->bus->busnum,
-		dev->udev->devnum,
-		(status & STATUS_CONN_OTHER) ? "" : "dis"
-		);
-	retval = 0;
-
-done:
-	return retval;
-}
-
-
-/*-------------------------------------------------------------------------
- *
- * Network Device Driver support (peer link to USB Host)
- *
- --------------------------------------------------------------------------*/
-
-static int net1080_change_mtu (struct net_device *net, int new_mtu)
-{
-	if ((new_mtu < 0) || NC_MAX_PACKET (new_mtu) > MAX_PACKET)
-		return -EINVAL;
-	net->mtu = new_mtu;
-	return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static struct net_device_stats *net1080_get_stats (struct net_device *net)
-{
-	return &((struct net1080 *) net->priv)->stats;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static void rx_complete (struct urb *urb);
-
-static void rx_submit (struct net1080 *dev, struct urb *urb, int flags)
-{
-	struct sk_buff		*skb;
-	struct skb_data		*entry;
-	int			retval = 0;
-	unsigned long		lockflags;
-
-	if ((skb = alloc_skb (NC_MAX_PACKET (dev->net.mtu), flags)) == 0) {
-		err ("no rx skb");
-		tasklet_schedule (&dev->bh);
-		usb_free_urb (urb);
-		return;
-	}
-
-	entry = (struct skb_data *) skb->cb;
-	entry->urb = urb;
-	entry->dev = dev;
-	entry->state = rx_start;
-	entry->length = 0;
-
-	FILL_BULK_URB (urb, dev->udev, usb_rcvbulkpipe (dev->udev, 1),
-			skb->data, skb->truesize, rx_complete, skb);
-	urb->transfer_flags |= USB_QUEUE_BULK;
-
-	spin_lock_irqsave (&dev->rxq.lock, lockflags);
-	if (!netif_queue_stopped (&dev->net)) {
-		if ((retval = usb_submit_urb (urb)) != 0) {
-			err ("%s rx submit, %d", dev->net.name, retval);
-			tasklet_schedule (&dev->bh);
-		} else {
-			__skb_queue_tail (&dev->rxq, skb);
-		}
-	} else {
-		dbg ("rx: stopped");
-		retval = -ENOLINK;
-	}
-	spin_unlock_irqrestore (&dev->rxq.lock, lockflags);
-	if (retval) {
-		dev_kfree_skb_any (skb);
-		usb_free_urb (urb);
-	}
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-static void rx_complete (struct urb *urb)
-{
-	struct sk_buff		*skb = (struct sk_buff *) urb->context;
-	struct skb_data		*entry = (struct skb_data *) skb->cb;
-	struct net1080		*dev = entry->dev;
-	int			urb_status = urb->status;
-
-	urb->dev = 0;
-	skb->len = urb->actual_length;
-	entry->state = rx_done;
-	entry->urb = 0;
-
-	if ((urb->transfer_flags & USB_ASYNC_UNLINK) != 0) {
-		dbg ("rx ... shutting down");
-		usb_free_urb (urb);
-		urb = 0;
-	}
-
-	switch (urb_status) {
-	    // success
-	    case 0:
-		if (!(skb->len & 0x01)) {
-			entry->state = rx_cleanup;
-			dev->stats.rx_errors++;
-			dev->stats.rx_length_errors++;
-			dbg ("even rx len %d", skb->len);
-		} else if (skb->len > MAX_PACKET) {
-			entry->state = rx_cleanup;
-			dev->stats.rx_errors++;
-			dev->stats.rx_frame_errors++;
-			dbg ("rx too big, %d", skb->len);
-		}
-		break;
-
-	    // hardware-reported interface shutdown ... which we
-	    // typically see before khubd calls disconnect()
-	    case -ETIMEDOUT:		// usb-ohci
-	    case -EILSEQ:		// *uhci ... "crc"/timeout error
-		// netif_device_detach (&dev->net);
-		// FALLTHROUGH
-			
-	    // software-driven interface shutdown
-	    case -ECONNRESET:
-		entry->state = rx_cleanup;
-		usb_free_urb (urb);
-		urb = 0;
-		dbg ("%s ... shutdown rx (%d)", dev->net.name, urb_status);
-		break;
-
-	    // data overrun ... flush fifo?
-	    case -EOVERFLOW:
-		dev->stats.rx_over_errors++;
-		// FALLTHROUGH
-	    
-	    default:
-		entry->state = rx_cleanup;
-		dev->stats.rx_errors++;
-		err ("%s rx: status %d", dev->net.name, urb_status);
-		break;
-	}
-	defer_bh (dev, skb);
-
-	if (urb) {
-		if (!netif_queue_stopped (&dev->net)) {
-			rx_submit (dev, urb, GFP_ATOMIC);
-			return;
-		} else
-			usb_free_urb (urb);
-	}
-#ifdef	VERBOSE
-	dbg ("no read resubmitted");
-#endif	/* VERBOSE */
-}
-
-/*-------------------------------------------------------------------------*/
-
-// unlink pending rx/tx; completion handlers do all other cleanup
-
-static int unlink_urbs (struct sk_buff_head *q)
-{
-	unsigned long		flags;
-	struct sk_buff		*skb;
-	struct skb_data		*entry;
-	int			retval;
-	int			count = 0;
-
-	spin_lock_irqsave (&q->lock, flags);
-	for (skb = q->next; skb != (struct sk_buff *) q; skb = skb->next) {
-		entry = (struct skb_data *) skb->cb;
-		entry->urb->transfer_flags |= USB_ASYNC_UNLINK;
-		retval = usb_unlink_urb (entry->urb);
-		if (retval < 0)
-			dbg ("unlink urb err, %d", retval);
-		else
-			count++;
-	}
-	spin_unlock_irqrestore (&q->lock, flags);
-	return count;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-// precondition: never called in_interrupt
-
-static int net1080_stop (struct net_device *net)
-{
-	struct net1080		*dev = (struct net1080 *) net->priv;
-	int			temp;
-	DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup); 
-	DECLARE_WAITQUEUE (wait, current);
-
-	mutex_lock (&dev->mutex);
-	
-	dbg ("%s stop stats: rx/tx %ld/%ld, errs %ld/%ld", net->name,
-		dev->stats.rx_packets, dev->stats.tx_packets, 
-		dev->stats.rx_errors, dev->stats.tx_errors
-		);
-
-	netif_stop_queue(net);
-
-	// ensure there are no more active urbs
-	add_wait_queue (&unlink_wakeup, &wait);
-	dev->wait = &unlink_wakeup;
-	temp = unlink_urbs (&dev->txq) + unlink_urbs (&dev->rxq);
-
-	// maybe wait for deletions to finish.
-	if (temp) {
-		current->state = TASK_UNINTERRUPTIBLE;
-		schedule ();
-		dbg ("waited for %d urb completions", temp);
-	}
-	dev->wait = 0;
-	current->state = TASK_RUNNING;
-	remove_wait_queue (&unlink_wakeup, &wait); 
-
-	mutex_unlock (&dev->mutex);
-	MOD_DEC_USE_COUNT;
-	return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-// posts a read, and enables write queing
-
-// precondition: never called in_interrupt
-
-static int net1080_open (struct net_device *net)
-{
-	struct net1080		*dev = (struct net1080 *) net->priv;
-	int			retval;
-	u16			status;
-	int			i;
-
-	MOD_INC_USE_COUNT;
-	mutex_lock (&dev->mutex);
-
-	// insist peer be connected -- is this the best place?
-	if ((retval = register_read (dev, REG_STATUS, &status)) != 0) {
-		dbg ("%s open: status read failed - %d", net->name, retval);
-		goto done;
-	}
-	if ((status & STATUS_CONN_OTHER) != STATUS_CONN_OTHER)  {
-		retval = -ENOLINK;
-		dbg ("%s open: peer not connected", net->name);
-		goto done;
-	}
-
-	MOD_INC_USE_COUNT;
-	netif_start_queue (net);
-	for (i = 0; i < RX_QLEN; i++)
-		rx_submit (dev, usb_alloc_urb (0), GFP_KERNEL);
-
-	dbg ("%s open: started queueing (rx %d, tx %d)",
-		net->name, RX_QLEN, TX_QLEN);
-done:
-	mutex_unlock (&dev->mutex);
-	MOD_DEC_USE_COUNT;
-	return retval;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static void tx_complete (struct urb *urb)
-{
-	struct sk_buff		*skb = (struct sk_buff *) urb->context;
-	struct skb_data		*entry = (struct skb_data *) skb->cb;
-	struct net1080		*dev = entry->dev;
-
-	urb->dev = 0;
-	entry->state = tx_done;
-	defer_bh (dev, skb);
-	netif_wake_queue (&dev->net);
-}
-
-/*-------------------------------------------------------------------------*/
-
-static struct sk_buff *fixup_skb (struct sk_buff *skb)
-{
-	int			padlen;
-	struct sk_buff		*skb2;
-
-	padlen = ((skb->len + sizeof (struct nc_header)
-			+ sizeof (struct nc_trailer)) & 0x01) ? 0 : 1;
-	if (!skb_cloned (skb)) {
-		int	headroom = skb_headroom (skb);
-		int	tailroom = skb_tailroom (skb);
-
-		if ((padlen + sizeof (struct nc_trailer)) <= tailroom
-			    && sizeof (struct nc_header) <= headroom)
-			return skb;
-
-		if ((sizeof (struct nc_header) + padlen
-					+ sizeof (struct nc_trailer)) <
-				(headroom + tailroom)) {
-			skb->data = memmove (skb->head
-						+ sizeof (struct nc_header),
-					    skb->data, skb->len);
-			skb->tail = skb->data + skb->len;
-			return skb;
-		}
-	}
-	skb2 = skb_copy_expand (skb,
-				sizeof (struct nc_header),
-				sizeof (struct nc_trailer) + padlen,
-				in_interrupt () ? GFP_ATOMIC : GFP_KERNEL);
-	dev_kfree_skb_any (skb);
-	return skb2;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static int net1080_start_xmit (struct sk_buff *skb, struct net_device *net)
-{
-	struct net1080		*dev = (struct net1080 *) net->priv;
-	int			length = skb->len;
-	int			retval = 0;
-	struct urb		*urb = 0;
-	struct skb_data		*entry;
-	struct nc_header	*header;
-	struct nc_trailer	*trailer;
-	unsigned long		flags;
-
-	if ((skb = fixup_skb (skb)) == 0) {
-		dbg ("can't fixup skb");
-		goto drop;
-	}
-	if ((urb = usb_alloc_urb (0)) == 0) {
-		dbg ("no urb");
-		goto drop;
-	}
-
-	entry = (struct skb_data *) skb->cb;
-	entry->urb = urb;
-	entry->dev = dev;
-	entry->state = tx_start;
-	entry->length = length;
-
-	header = (struct nc_header *) skb_push (skb, sizeof *header);
-	header->hdr_len = cpu_to_le16 (sizeof (*header));
-	header->packet_len = cpu_to_le16 (length);
-	if (!((skb->len + sizeof *trailer) & 0x01))
-		*skb_put (skb, 1) = NC_PAD_BYTE;
-	trailer = (struct nc_trailer *) skb_put (skb, sizeof *trailer);
-
-	FILL_BULK_URB (urb, dev->udev,
-			usb_sndbulkpipe (dev->udev, 1),
-			skb->data, skb->len, tx_complete, skb);
-	urb->transfer_flags |= USB_QUEUE_BULK;
-	// FIXME urb->timeout = ...;
-
-	spin_lock_irqsave (&dev->txq.lock, flags);
-	if (!netif_queue_stopped (&dev->net)) {
-		header->packet_id = cpu_to_le16 (dev->packet_id++);
-		put_unaligned (header->packet_id, &trailer->packet_id);
-
-		netif_stop_queue (net);
-		if ((retval = usb_submit_urb (urb)) != 0) {
-			netif_start_queue (net);
-			dbg ("%s tx: submit urb err %d", net->name, retval);
-		} else {
-			net->trans_start = jiffies;
-			__skb_queue_tail (&dev->txq, skb);
-			if (dev->txq.qlen < TX_QLEN)
-				netif_start_queue (net);
-		}
-	} else
-		retval = -ENOLINK;
-	spin_unlock_irqrestore (&dev->txq.lock, flags);
-
-	if (retval) {
-		dbg ("drop");
-drop:
-		dev->stats.tx_dropped++;
-		dev_kfree_skb_any (skb);
-		usb_free_urb (urb);
-#ifdef	VERBOSE
-	} else {
-		dbg ("%s: tx %p len %d", net->name, skb, length);
-#endif
-	}
-	return retval;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-static void rx_process (struct net1080 *dev, struct sk_buff *skb)
-{
-	struct nc_header	*header;
-	struct nc_trailer	*trailer;
-
-	header = (struct nc_header *) skb->data;
-	le16_to_cpus (&header->hdr_len);
-	le16_to_cpus (&header->packet_len);
-	if (header->packet_len > MAX_PACKET) {
-		dev->stats.rx_frame_errors++;
-		dbg ("packet too big, %d", header->packet_len);
-		goto error;
-	} else if (header->hdr_len < NC_MIN_HEADER) {
-		dev->stats.rx_frame_errors++;
-		dbg ("header too short, %d", header->hdr_len);
-		goto error;
-	} else if (header->hdr_len > header->packet_len) {
-		dev->stats.rx_frame_errors++;
-		dbg ("header too big, %d packet %d", header->hdr_len, header->packet_len);
-		goto error;
-	} else if (header->hdr_len != sizeof *header) {
-		// out of band data for us?
-		dbg ("header OOB, %d bytes", header->hdr_len - NC_MIN_HEADER);
-		// switch (vendor/product ids) { ... }
-	}
-	skb_pull (skb, header->hdr_len);
-
-	trailer = (struct nc_trailer *)
-		(skb->data + skb->len - sizeof *trailer);
-	skb_trim (skb, skb->len - sizeof *trailer);
-
-	if ((header->packet_len & 0x01) == 0) {
-		if (skb->data [header->packet_len] != NC_PAD_BYTE) {
-			dev->stats.rx_frame_errors++;
-			dbg ("bad pad");
-			goto error;
-		}
-		skb_trim (skb, skb->len - 1);
-	}
-	if (skb->len != header->packet_len) {
-		dev->stats.rx_length_errors++;
-		dbg ("bad packet len %d (expected %d)",
-			skb->len, header->packet_len);
-		goto error;
-	}
-	if (header->packet_id != get_unaligned (&trailer->packet_id)) {
-		dev->stats.rx_fifo_errors++;
-		dbg ("(2+ dropped) rx packet_id mismatch 0x%x 0x%x",
-			header->packet_id, trailer->packet_id);
-		goto error;
-	}
-
-	if (skb->len) {
-		skb->dev = &dev->net;
-		skb->protocol = eth_type_trans (skb, &dev->net);
-		dev->stats.rx_packets++;
-		dev->stats.rx_bytes += skb->len;
-
-#ifdef	VERBOSE
-		dbg ("%s: rx %p len %d, type 0x%x, id 0x%x",
-			dev->net.name, skb, skb->len, skb->protocol,
-			le16_to_cpu (header->packet_id));
-#endif
-		netif_rx (skb);
-	} else {
-		dbg ("drop");
-error:
-		dev->stats.rx_errors++;
-		dev_kfree_skb (skb);
-	}
-}
-
-/*-------------------------------------------------------------------------*/
-
-// tasklet
-
-// We can have a state machine in this tasklet monitor the link state,
-// using async control messaging and calling attach/detach routines.
-
-// But then some listener ought to respond to the changes; do those
-// network attach/detach notifications get to userland somehow, such
-// as by calling "ifup usb0" and "ifdown usb0"?
-
-static void net1080_bh (unsigned long param)
-{
-	struct net1080		*dev = (struct net1080 *) param;
-	struct sk_buff		*skb;
-	struct skb_data		*entry;
-
-	while ((skb = skb_dequeue (&dev->done))) {
-		entry = (struct skb_data *) skb->cb;
-		switch (entry->state) {
-		    case rx_done:
-			rx_process (dev, skb);
-			continue;
-		    case tx_done:
-			if (entry->urb->status) {
-				// can this statistic become more specific?
-				dev->stats.tx_errors++;
-				dbg ("%s tx: err %d", dev->net.name,
-					entry->urb->status);
-			} else {
-				dev->stats.tx_packets++;
-				dev->stats.tx_bytes += entry->length;
-			}
-			// FALLTHROUGH:
-		    case rx_cleanup:
-			usb_free_urb (entry->urb);
-			dev_kfree_skb (skb);
-			continue;
-		    default:
-			dbg ("%s: bogus skb state %d",
-				dev->net.name, entry->state);
-		}
-	}
-
-	// waiting for all pending urbs to complete?
-	if (dev->wait) {
-		if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) {
-			wake_up (dev->wait);
-		}
-
-	// or are we maybe short a few urbs?
-	} else if (!netif_queue_stopped (&dev->net)) {
-		if (dev->rxq.qlen < TX_QLEN) {
-			struct urb	*urb;
-			int		i;
-			for (i = 0; i < 3 && dev->rxq.qlen < TX_QLEN; i++) {
-				if ((urb = usb_alloc_urb (0)) != 0)
-					rx_submit (dev, urb, GFP_ATOMIC);
-			}
-			dbg ("%s: rxqlen now %d",
-				dev->net.name, dev->rxq.qlen);
-		}
-	}
-}
-
-/*-------------------------------------------------------------------------
- *
- * USB Device Driver support
- *
- --------------------------------------------------------------------------*/
- 
-// precondition: never called in_interrupt
-
-static void net1080_disconnect (struct usb_device *udev, void *ptr)
-{
-	struct net1080	*dev = (struct net1080 *) ptr;
-
-	info ("%s: USB %d dev %d, %s, disconnected",
-		dev->net.name,
-		udev->bus->busnum, udev->devnum,
-		(char *) dev->prod_info->driver_info);
-	
-	unregister_netdev (&dev->net);
-
-	mutex_lock (&net1080_mutex);
-	mutex_lock (&dev->mutex);
-	list_del (&dev->dev_list);
-	mutex_unlock (&net1080_mutex);
-
-#ifdef DEBUG
-	memset (dev, 0x55, sizeof *dev);
-#endif
-	kfree (dev);
-	usb_dec_dev_use (udev);
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-// precondition: never called in_interrupt
-
-static void *
-net1080_probe (struct usb_device *udev, unsigned ifnum, const struct usb_device_id *prod)
-{
-	struct net1080		*dev;
-	struct net_device 	*net;
-	struct usb_interface_descriptor	*interface;
-	int			retval;
-
-	// sanity check; expect dedicated interface/devices for now.
-	interface = &udev->actconfig->interface [ifnum].altsetting[0];
-	if (udev->descriptor.bNumConfigurations != 1
-			|| udev->config[0].bNumInterfaces != 1
-			|| udev->config[0].bNumInterfaces != 1
-			|| interface->bInterfaceClass != USB_CLASS_VENDOR_SPEC
-			|| interface->bNumEndpoints != 5
-			) {
-		dbg ("Bogus config info");
-		return 0;
-	}
-
-	// set up our own records
-	if (!(dev = kmalloc (sizeof *dev, GFP_KERNEL))) {
-		dbg ("can't kmalloc dev");
-		return 0;
-	}
-	memset (dev, 0, sizeof *dev);
-
-	init_MUTEX_LOCKED (&dev->mutex);
-	usb_inc_dev_use (udev);
-	dev->udev = udev;
-	dev->prod_info = prod;
-	INIT_LIST_HEAD (&dev->dev_list);
-	skb_queue_head_init (&dev->rxq);
-	skb_queue_head_init (&dev->txq);
-	skb_queue_head_init (&dev->done);
-	dev->bh.func = net1080_bh;
-	dev->bh.data = (unsigned long) dev;
-
-	// set up network interface records
-	net = &dev->net;
-	net->priv = dev;
-	strcpy (net->name, "usb%d");
-	memcpy (net->dev_addr, node_id, sizeof node_id);
-
-	ether_setup (net);
-	// net->flags |= IFF_POINTOPOINT;
-
-	net->change_mtu = net1080_change_mtu;
-	net->get_stats = net1080_get_stats;
-	net->hard_start_xmit = net1080_start_xmit;
-	net->open = net1080_open;
-	net->stop = net1080_stop;
-
-	register_netdev (&dev->net);
-
-	// ... talk to the device
-	// dump_registers (dev);
-
-	if ((retval = net1080_reset (dev)) < 0) {
-		err ("%s: init reset fail on USB %d dev %d - %d",
-			dev->net.name, udev->bus->busnum, udev->devnum, retval);
-		mutex_unlock (&dev->mutex);
-		net1080_disconnect (udev, dev);
-		return 0;
-	}
-
-	// ok, it's ready to go.
-	mutex_lock (&net1080_mutex);
-	list_add (&dev->dev_list, &net1080_list);
-	mutex_unlock (&dev->mutex);
-
-	// start as if the link is up
-	netif_device_attach (&dev->net);
-
-	mutex_unlock (&net1080_mutex);
-
-	return dev;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-static struct usb_driver net1080_driver = {
-	name:		"net1080",
-	id_table:	products,
-	probe:		net1080_probe,
-	disconnect:	net1080_disconnect,
-};
-
-/*-------------------------------------------------------------------------*/
-
-static int __init net1080_init (void)
-{
-	// compiler should optimize this out
-	if (sizeof (((struct sk_buff *)0)->cb) < sizeof (struct skb_data))
-		BUG ();
-
- 	if (usb_register (&net1080_driver) < 0)
- 		return -1;
-
-	get_random_bytes (node_id, sizeof node_id);
-	node_id [0] &= 0x7f;
-
-	info(DRIVER_VERSION ":" DRIVER_DESC);
-
-	return 0;
-}
-module_init (net1080_init);
-
-static void __exit net1080_exit (void)
-{
- 	usb_deregister (&net1080_driver);
-}
-module_exit (net1080_exit);
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/pegasus.c linux/drivers/usb/pegasus.c
--- v2.4.9/linux/drivers/usb/pegasus.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/pegasus.c	Tue Aug 28 07:09:44 2001
@@ -1,7 +1,7 @@
 /*
 **	Pegasus: USB 10/100Mbps/HomePNA (1Mbps) Controller
 **
-**	Copyright (c) 1999,2000 Petko Manolov - Petkan (petkan@dce.bg)
+**	Copyright (c) 1999-2001 Petko Manolov (pmanolov@lnxw.com)
 **	
 **
 **	ChangeLog:
@@ -53,9 +53,9 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.4.19 2001/06/07 (C) 1999-2001"
+#define DRIVER_VERSION "v0.4.21 (2001/08/27)"
 #define DRIVER_AUTHOR "Petko Manolov <pmanolov@lnxw.com>"
-#define DRIVER_DESC "ADMtek AN986 Pegasus USB Ethernet driver"
+#define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
 
 #define	PEGASUS_USE_INTR
 #define	PEGASUS_WRITE_EEPROM
@@ -117,9 +117,7 @@
 			warn( __FUNCTION__ " status %d", urb->status);
 	}
 	pegasus->flags &= ~ETH_REGS_CHANGED;
-	if ( waitqueue_active(&pegasus->ctrl_wait) ) {
-		wake_up_interruptible( &pegasus->ctrl_wait );
-	}
+	wake_up(&pegasus->ctrl_wait );
 }
 
 
@@ -135,9 +133,13 @@
 		return 0;
 	}
 	memcpy(buffer,data,size);
-	
+
+	add_wait_queue(&pegasus->ctrl_wait, &wait);
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	while ( pegasus->flags & ETH_REGS_CHANGED )
-		interruptible_sleep_on( &pegasus->ctrl_wait );
+		schedule();
+	remove_wait_queue(&pegasus->ctrl_wait, &wait);
+	set_current_state(TASK_RUNNING);
 
 	pegasus->dr.requesttype = PEGASUS_REQT_READ;
 	pegasus->dr.request = PEGASUS_REQ_GET_REGS;
@@ -152,7 +154,7 @@
 			  buffer, size, ctrl_callback, pegasus );
 
 	add_wait_queue( &pegasus->ctrl_wait, &wait );
-	set_current_state( TASK_INTERRUPTIBLE );
+	set_current_state( TASK_UNINTERRUPTIBLE );
 
 	if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
 		err( __FUNCTION__ " BAD CTRLs %d", ret);
@@ -182,8 +184,12 @@
 	}
 	memcpy(buffer, data, size);
 
+	add_wait_queue(&pegasus->ctrl_wait, &wait);
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	while ( pegasus->flags & ETH_REGS_CHANGED )
-		interruptible_sleep_on( &pegasus->ctrl_wait );
+		schedule();
+	remove_wait_queue(&pegasus->ctrl_wait, &wait);
+	set_current_state(TASK_RUNNING);
 
 	pegasus->dr.requesttype = PEGASUS_REQT_WRITE;
 	pegasus->dr.request = PEGASUS_REQ_SET_REGS;
@@ -198,7 +204,7 @@
 			  buffer, size, ctrl_callback, pegasus );
 			  
 	add_wait_queue( &pegasus->ctrl_wait, &wait );
-	set_current_state( TASK_INTERRUPTIBLE );
+	set_current_state( TASK_UNINTERRUPTIBLE );
 
 	if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
 		err( __FUNCTION__ " BAD CTRL %d", ret);
@@ -228,8 +234,12 @@
 	}
 	memcpy(buffer, &data, 1);
 
+	add_wait_queue(&pegasus->ctrl_wait, &wait);
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	while ( pegasus->flags & ETH_REGS_CHANGED )
-		interruptible_sleep_on( &pegasus->ctrl_wait );
+		schedule();
+	remove_wait_queue(&pegasus->ctrl_wait, &wait);
+	set_current_state(TASK_RUNNING);
 
 	pegasus->dr.requesttype = PEGASUS_REQT_WRITE;
 	pegasus->dr.request = PEGASUS_REQ_SET_REG;
@@ -244,7 +254,7 @@
 			  buffer, 1, ctrl_callback, pegasus );
 
 	add_wait_queue( &pegasus->ctrl_wait, &wait );
-	set_current_state( TASK_INTERRUPTIBLE );
+	set_current_state( TASK_UNINTERRUPTIBLE );
 
 	if ( (ret = usb_submit_urb( &pegasus->ctrl_urb )) ) {
 		err( __FUNCTION__ " BAD CTRL %d", ret);
@@ -620,7 +630,6 @@
 }
 #endif
 
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,48)
 static void pegasus_tx_timeout( struct net_device *net )
 {
 	pegasus_t *pegasus = net->priv;
@@ -633,7 +642,6 @@
 	usb_unlink_urb( &pegasus->tx_urb );
 	pegasus->stats.tx_errors++;
 }
-#endif
 
 
 static int pegasus_start_xmit( struct sk_buff *skb, struct net_device *net )
@@ -861,10 +869,8 @@
 	net->priv = pegasus;
 	net->open = pegasus_open;
 	net->stop = pegasus_close;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,48)
 	net->watchdog_timeo = PEGASUS_TX_TIMEOUT;
 	net->tx_timeout = pegasus_tx_timeout;
-#endif
 	net->do_ioctl = pegasus_ioctl;
 	net->hard_start_xmit = pegasus_start_xmit;
 	net->set_multicast_list = pegasus_set_multicast;
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/printer.c linux/drivers/usb/printer.c
--- v2.4.9/linux/drivers/usb/printer.c	Wed Jul 25 17:10:24 2001
+++ linux/drivers/usb/printer.c	Tue Aug 28 11:21:02 2001
@@ -230,7 +230,7 @@
 		goto out;
 	}
 #else
-	retval = 0;	
+	retval = 0;
 #endif
 
 	usblp->used = 1;
@@ -242,7 +242,11 @@
 	if (usblp->bidir) {
 		usblp->readcount = 0;
 		usblp->readurb.dev = usblp->dev;
-		usb_submit_urb(&usblp->readurb);
+		if (usb_submit_urb(&usblp->readurb) < 0) {
+			retval = -EIO;
+			usblp->used = 0;
+			file->private_data = NULL;
+		}
 	}
 out:
 	unlock_kernel();
@@ -299,7 +303,7 @@
 	}
 
 	if (_IOC_TYPE(cmd) == 'P')	/* new-style ioctl number */
-	
+
 		switch (_IOC_NR(cmd)) {
 
 			case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */
@@ -658,7 +662,7 @@
 #endif
 
 	sprintf(name, "lp%d", minor);
-	
+
 	/* if we have devfs, create with perms=660 */
 	usblp->devfs = devfs_register(usb_devfs_handle, name,
 				      DEVFS_FL_DEFAULT, USB_MAJOR,
@@ -681,8 +685,11 @@
 		BUG ();
 	}
 
+
 	down (&usblp->sem);
+	lock_kernel();
 	usblp->dev = NULL;
+	unlock_kernel();
 
 	usb_unlink_urb(&usblp->writeurb);
 	if (usblp->bidir)
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/rio500.c linux/drivers/usb/rio500.c
--- v2.4.9/linux/drivers/usb/rio500.c	Sun Aug 12 13:28:00 2001
+++ linux/drivers/usb/rio500.c	Tue Aug 28 11:21:02 2001
@@ -120,13 +120,17 @@
 	unsigned char *buffer;
 	int result, requesttype;
 	int retries;
-	int retval;
+	int retval=0;
 
+	down(&(rio->lock));
         /* Sanity check to make sure rio is connected, powered, etc */
         if ( rio == NULL ||
              rio->present == 0 ||
              rio->rio_dev == NULL )
-          return -1;
+	{
+		retval = -ENODEV;
+		goto err_out;
+	}
 
 	switch (cmd) {
 	case RIO_RECV_COMMAND:
@@ -142,8 +146,10 @@
 			goto err_out;
 		}
 		buffer = (unsigned char *) __get_free_page(GFP_KERNEL);
-		if (buffer == NULL)
-			return -ENOMEM;
+		if (buffer == NULL) {
+			retval = -ENOMEM;
+			goto err_out;
+		}
 		if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length)) {
 			retval = -EFAULT;
 			free_page((unsigned long) buffer);
@@ -158,7 +164,6 @@
 		     rio_cmd.index, rio_cmd.length);
 		/* Send rio control message */
 		retries = 3;
-		down(&(rio->lock));
 		while (retries) {
 			result = usb_control_msg(rio->rio_dev,
 						 usb_rcvctrlpipe(rio-> rio_dev, 0),
@@ -180,7 +185,6 @@
 				     le32_to_cpu(*((long *) buffer)));
 				if (copy_to_user(rio_cmd.buffer, buffer,
 						 rio_cmd.length)) {
-					up(&(rio->lock));
 					free_page((unsigned long) buffer);
 					retval = -EFAULT;
 					goto err_out;
@@ -196,7 +200,6 @@
 			   be swapped at the app level */
 
 		}
-		up(&(rio->lock));
 		free_page((unsigned long) buffer);
 		break;
 
@@ -204,16 +207,23 @@
 		data = (void *) arg;
 		if (data == NULL)
 			break;
-		if (copy_from_user(&rio_cmd, data, sizeof(struct RioCommand)))
-			return -EFAULT;
-		if (rio_cmd.length > PAGE_SIZE)
-			return -EINVAL;
+		if (copy_from_user(&rio_cmd, data, sizeof(struct RioCommand))) {
+			retval = -EFAULT;
+			goto err_out;
+		}
+		if (rio_cmd.length > PAGE_SIZE) {
+			retval = -EINVAL;
+			goto err_out;
+		}
 		buffer = (unsigned char *) __get_free_page(GFP_KERNEL);
-		if (buffer == NULL)
-			return -ENOMEM;
+		if (buffer == NULL) {
+			retval = -ENOMEM;
+			goto err_out;
+		}
 		if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length)) {
 			free_page((unsigned long)buffer);
-			return -EFAULT;
+			retval = -EFAULT;
+			goto err_out;
 		}
 
 		requesttype = rio_cmd.requesttype | USB_DIR_OUT |
@@ -223,7 +233,6 @@
 		     rio_cmd.index, rio_cmd.length);
 		/* Send rio control message */
 		retries = 3;
-		down(&(rio->lock));
 		while (retries) {
 			result = usb_control_msg(rio->rio_dev,
 						 usb_sndctrlpipe(rio-> rio_dev, 0),
@@ -247,16 +256,14 @@
 			}
 
 		}
-		up(&(rio->lock));
 		free_page((unsigned long) buffer);
 		break;
 
 	default:
-		return -ENOIOCTLCMD;
+		retval = -ENOTTY;
 		break;
 	}
 
-	return 0;
 
 err_out:
 	up(&(rio->lock));
@@ -277,13 +284,17 @@
 	int maxretry;
 	int errn = 0;
 
+	down(&(rio->lock));
         /* Sanity check to make sure rio is connected, powered, etc */
         if ( rio == NULL ||
              rio->present == 0 ||
              rio->rio_dev == NULL )
-          return -1;
+	{
+		up(&(rio->lock));
+		return -ENODEV;
+	}
+
 
-	down(&(rio->lock));
 
 	do {
 		unsigned long thistime;
@@ -356,17 +367,20 @@
 	int maxretry = 10;
 	char *ibuf;
 
-        /* Sanity check to make sure rio is connected, powered, etc */
+	down(&(rio->lock));
+	/* Sanity check to make sure rio is connected, powered, etc */
         if ( rio == NULL ||
              rio->present == 0 ||
              rio->rio_dev == NULL )
-          return -1;
+	{
+		up(&(rio->lock));
+		return -ENODEV;
+	}
 
 	ibuf = rio->ibuf;
 
 	read_count = 0;
 
-	down(&(rio->lock));
 
 	while (count > 0) {
 		if (signal_pending(current)) {
@@ -461,7 +475,7 @@
 				    S_IWGRP, &usb_rio_fops, NULL);
 	if (rio->devfs == NULL)
 		dbg("probe_rio: device node registration failed");
-	
+
 	init_MUTEX(&(rio->lock));
 
 	return rio;
@@ -473,10 +487,12 @@
 
 	devfs_unregister(rio->devfs);
 
+	down(&(rio->lock));
 	if (rio->isopen) {
 		rio->isopen = 0;
 		/* better let it finish - the release will do whats needed */
 		rio->rio_dev = NULL;
+		up(&(rio->lock));
 		return;
 	}
 	kfree(rio->ibuf);
@@ -485,6 +501,7 @@
 	info("USB Rio disconnected.");
 
 	rio->present = 0;
+	up(&(rio->lock));
 }
 
 static struct usb_device_id rio_table [] = {
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/serial/Config.in linux/drivers/usb/serial/Config.in
--- v2.4.9/linux/drivers/usb/serial/Config.in	Wed Jul 25 17:10:24 2001
+++ linux/drivers/usb/serial/Config.in	Tue Aug 28 11:21:02 2001
@@ -15,7 +15,7 @@
   dep_tristate '  USB Digi International AccelePort USB Serial Driver' CONFIG_USB_SERIAL_DIGI_ACCELEPORT $CONFIG_USB_SERIAL
   dep_tristate '  USB Empeg empeg-car Mark I/II Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EMPEG $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
   dep_tristate '  USB FTDI Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_FTDI_SIO $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
-  dep_tristate '  USB Handspring Visor Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL
+  dep_tristate '  USB Handspring Visor / Palm m50x / Sony Clie Driver' CONFIG_USB_SERIAL_VISOR $CONFIG_USB_SERIAL
   dep_tristate '  USB Inside Out Edgeport Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_EDGEPORT $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
   dep_tristate '  USB Keyspan PDA Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN_PDA $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
   dep_tristate '  USB Keyspan USA-xxx Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_KEYSPAN $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/serial/belkin_sa.c linux/drivers/usb/serial/belkin_sa.c
--- v2.4.9/linux/drivers/usb/serial/belkin_sa.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/serial/belkin_sa.c	Tue Aug 28 11:21:02 2001
@@ -551,7 +551,8 @@
 	case TIOCMSET: /* Turns on and off the lines as specified by the mask */
 	case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
 	case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
-		if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+		if (get_user(mask, (unsigned long *) arg))
+			return -EFAULT;
 
 		if ((cmd == TIOCMSET) || (mask & TIOCM_RTS)) {
 			/* RTS needs set */
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/serial/cyberjack.c linux/drivers/usb/serial/cyberjack.c
--- v2.4.9/linux/drivers/usb/serial/cyberjack.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/serial/cyberjack.c	Tue Aug 28 11:21:02 2001
@@ -241,7 +241,8 @@
 
 	/* Copy data */
 	if (from_user) {
-		copy_from_user(priv->wrbuf+priv->wrfilled, buf, count);
+		if (copy_from_user(priv->wrbuf+priv->wrfilled, buf, count))
+			return -EFAULT;
 	} else {
 		memcpy (priv->wrbuf+priv->wrfilled, buf, count);
 	}  
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/serial/digi_acceleport.c linux/drivers/usb/serial/digi_acceleport.c
--- v2.4.9/linux/drivers/usb/serial/digi_acceleport.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/serial/digi_acceleport.c	Tue Aug 28 11:21:02 2001
@@ -409,11 +409,6 @@
 #define DIGI_READ_INPUT_SIGNALS_DCD		128
 
 
-/* macros */
-#define MAX(a,b)	(((a)>(b))?(a):(b))
-#define MIN(a,b)	(((a)<(b))?(a):(b))
-
-
 /* Structures */
 
 typedef struct digi_serial {
@@ -675,7 +670,7 @@
 		}
 
 		/* len must be a multiple of 4, so commands are not split */
-		len = MIN( count, oob_port->bulk_out_size );
+		len = min(int, count, oob_port->bulk_out_size );
 		if( len > 4 )
 			len &= ~3;
 
@@ -752,7 +747,7 @@
 		/* len must be a multiple of 4 and small enough to */
 		/* guarantee the write will send buffered data first, */
 		/* so commands are in order with data and not split */
-		len = MIN( count, port->bulk_out_size-2-priv->dp_out_buf_len );
+		len = min(int, count, port->bulk_out_size-2-priv->dp_out_buf_len );
 		if( len > 4 )
 			len &= ~3;
 
@@ -956,7 +951,7 @@
 	spin_lock_irqsave( &priv->dp_port_lock, flags );
 
 	/* send any buffered chars from throttle time on to tty subsystem */
-	len = MIN( priv->dp_in_buf_len, TTY_FLIPBUF_SIZE - tty->flip.count );
+	len = min(int, priv->dp_in_buf_len, TTY_FLIPBUF_SIZE - tty->flip.count );
 	if( len > 0 ) {
 		memcpy( tty->flip.char_buf_ptr, priv->dp_in_buf, len );
 		memcpy( tty->flip.flag_buf_ptr, priv->dp_in_flag_buf, len );
@@ -1277,7 +1272,7 @@
 priv->dp_port_num, count, from_user, in_interrupt() );
 
 	/* copy user data (which can sleep) before getting spin lock */
-	count = MIN( 64, MIN( count, port->bulk_out_size-2 ) );
+	count = min(int, 64, min(int, count, port->bulk_out_size-2 ) );
 	if( from_user && copy_from_user( user_buf, buf, count ) ) {
 		return( -EFAULT );
 	}
@@ -1308,7 +1303,7 @@
 
 	/* allow space for any buffered data and for new data, up to */
 	/* transfer buffer size - 2 (for command and length bytes) */
-	new_len = MIN( count, port->bulk_out_size-2-priv->dp_out_buf_len );
+	new_len = min(int, count, port->bulk_out_size-2-priv->dp_out_buf_len );
 	data_len = new_len + priv->dp_out_buf_len;
 
 	if( data_len == 0 ) {
@@ -1934,7 +1929,7 @@
 
 		if( throttled ) {
 
-			len = MIN( len,
+			len = min( int, len,
 				DIGI_IN_BUF_SIZE - priv->dp_in_buf_len );
 
 			if( len > 0 ) {
@@ -1947,7 +1942,7 @@
 
 		} else {
 
-			len = MIN( len, TTY_FLIPBUF_SIZE - tty->flip.count );
+			len = min( int, len, TTY_FLIPBUF_SIZE - tty->flip.count );
 
 			if( len > 0 ) {
 				memcpy( tty->flip.char_buf_ptr, data, len );
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/serial/empeg.c linux/drivers/usb/serial/empeg.c
--- v2.4.9/linux/drivers/usb/serial/empeg.c	Sun Aug 12 13:28:00 2001
+++ linux/drivers/usb/serial/empeg.c	Tue Aug 28 11:21:02 2001
@@ -85,8 +85,6 @@
 #define EMPEG_VENDOR_ID			0x084f
 #define EMPEG_PRODUCT_ID		0x0001
 
-#define MIN(a,b)		(((a)<(b))?(a):(b))
-
 /* function prototypes for an empeg-car player */
 static int  empeg_open			(struct usb_serial_port *port, struct file *filp);
 static void empeg_close			(struct usb_serial_port *port, struct file *filp);
@@ -278,10 +276,13 @@
 			}
 		}
 
-		transfer_size = MIN (count, URB_TRANSFER_BUFFER_SIZE);
+		transfer_size = min (int, count, URB_TRANSFER_BUFFER_SIZE);
 
 		if (from_user) {
-			copy_from_user (urb->transfer_buffer, current_position, transfer_size);
+			if (copy_from_user (urb->transfer_buffer, current_position, transfer_size)) {
+				bytes_sent = -EFAULT;
+				break;
+			}
 		} else {
 			memcpy (urb->transfer_buffer, current_position, transfer_size);
 		}
@@ -301,8 +302,11 @@
 
 		/* send it down the pipe */
 		status = usb_submit_urb(urb);
-		if (status)
-			dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status);
+		if (status) {
+			err(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status);
+			bytes_sent = status;
+			break;
+		}
 
 		current_position += transfer_size;
 		bytes_sent += transfer_size;
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/serial/ftdi_sio.c linux/drivers/usb/serial/ftdi_sio.c
--- v2.4.9/linux/drivers/usb/serial/ftdi_sio.c	Wed Jul 25 17:10:24 2001
+++ linux/drivers/usb/serial/ftdi_sio.c	Tue Aug 28 11:21:02 2001
@@ -470,8 +470,9 @@
 
 		/* Copy in the data to send */
 		if (from_user) {
-			copy_from_user(port->write_urb->transfer_buffer + data_offset , 
-				       buf, count - data_offset );
+			if (copy_from_user(port->write_urb->transfer_buffer + data_offset,
+					   buf, count - data_offset ))
+				return -EFAULT;
 		}
 		else {
 			memcpy(port->write_urb->transfer_buffer + data_offset,
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/serial/io_edgeport.c linux/drivers/usb/serial/io_edgeport.c
--- v2.4.9/linux/drivers/usb/serial/io_edgeport.c	Wed Jul 25 17:10:24 2001
+++ linux/drivers/usb/serial/io_edgeport.c	Tue Aug 28 11:21:02 2001
@@ -236,7 +236,7 @@
 #include <linux/errno.h>
 #include <linux/poll.h>
 #include <linux/init.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/fcntl.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
@@ -1311,7 +1311,7 @@
 	fifo = &edge_port->txfifo;
 
 	// calculate number of bytes to put in fifo
-	copySize = MIN(count, (edge_port->txCredits - fifo->count));
+	copySize = min (int, count, (edge_port->txCredits - fifo->count));
 
 	dbg(__FUNCTION__"(%d) of %d byte(s) Fifo room  %d -- will copy %d bytes", 
 	    port->number, count, edge_port->txCredits - fifo->count, copySize);
@@ -1329,12 +1329,13 @@
 	// then copy the reset from the start of the buffer 
 
 	bytesleft = fifo->size - fifo->head;
-	firsthalf = MIN(bytesleft,copySize);
+	firsthalf = min (int, bytesleft, copySize);
 	dbg (__FUNCTION__" - copy %d bytes of %d into fifo ", firsthalf, bytesleft);
 
 	/* now copy our data */
 	if (from_user) {
-		copy_from_user(&fifo->fifo[fifo->head], data, firsthalf);
+		if (copy_from_user(&fifo->fifo[fifo->head], data, firsthalf))
+			return -EFAULT;
 	} else {
 		memcpy(&fifo->fifo[fifo->head], data, firsthalf);
 	}  
@@ -1353,7 +1354,8 @@
 	if (secondhalf) {
 		dbg (__FUNCTION__" - copy rest of data %d", secondhalf);
 		if (from_user) {
-			copy_from_user(&fifo->fifo[fifo->head], &data[firsthalf], secondhalf);
+			if (copy_from_user(&fifo->fifo[fifo->head], &data[firsthalf], secondhalf))
+				return -EFAULT;
 		} else {
 			memcpy(&fifo->fifo[fifo->head], &data[firsthalf], secondhalf);
 		}
@@ -1452,7 +1454,7 @@
 
 	/* now copy our data */
 	bytesleft =  fifo->size - fifo->tail;
-	firsthalf = MIN(bytesleft,count);
+	firsthalf = min (int, bytesleft, count);
 	memcpy(&buffer[2], &fifo->fifo[fifo->tail], firsthalf);
 	fifo->tail  += firsthalf;
 	fifo->count -= firsthalf;
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/serial/io_edgeport.h linux/drivers/usb/serial/io_edgeport.h
--- v2.4.9/linux/drivers/usb/serial/io_edgeport.h	Mon Mar 19 17:21:54 2001
+++ linux/drivers/usb/serial/io_edgeport.h	Tue Aug 28 11:21:02 2001
@@ -25,16 +25,6 @@
 #ifndef FALSE
 	#define FALSE		(0)
 #endif
-#ifndef MIN
-	#define MIN(a,b)	(((a)<(b))?(a):(b))
-#endif
-#ifndef MAX
-	#define MAX(a,b)	(((a)>(b))?(a):(b))
-#endif
-#ifndef max
-	#define max		MAX
-#endif
-
 #ifndef LOW8
 	#define LOW8(a)		((unsigned char)(a & 0xff))
 #endif
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/serial/keyspan.c linux/drivers/usb/serial/keyspan.c
--- v2.4.9/linux/drivers/usb/serial/keyspan.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/serial/keyspan.c	Tue Aug 28 11:21:02 2001
@@ -349,7 +349,8 @@
 		((char *)this_urb->transfer_buffer)[0] = 0;
 
 		if (from_user) {
-			copy_from_user(this_urb->transfer_buffer + 1, buf, todo);
+			if (copy_from_user(this_urb->transfer_buffer + 1, buf, todo))
+				return -EFAULT;
 		} else {
 			memcpy (this_urb->transfer_buffer + 1, buf, todo);
 		}
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/serial/mct_u232.c linux/drivers/usb/serial/mct_u232.c
--- v2.4.9/linux/drivers/usb/serial/mct_u232.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/serial/mct_u232.c	Tue Aug 28 11:21:02 2001
@@ -94,7 +94,7 @@
  */
 #undef FIX_WRITE_RETURN_CODE_PROBLEM
 #ifdef FIX_WRITE_RETURN_CODE_PROBLEM
-static int write_blocking = 0; /* disabled by default */
+static int write_blocking; /* disabled by default */
 #endif
 
 /*
@@ -524,7 +524,10 @@
 		usb_serial_debug_data (__FILE__, __FUNCTION__, size, buf);
 		
 		if (from_user) {
-			copy_from_user(port->write_urb->transfer_buffer, buf, size);
+			if (copy_from_user(port->write_urb->transfer_buffer, buf, size)) {
+				up (&port->sem);
+				return -EFAULT;
+			}
 		}
 		else {
 			memcpy (port->write_urb->transfer_buffer, buf, size);
@@ -815,7 +818,7 @@
 {
 	struct usb_serial *serial = port->serial;
 	struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
-	int ret, mask;
+	int mask;
 	
 	dbg (__FUNCTION__ "cmd=0x%x", cmd);
 
@@ -828,7 +831,8 @@
 	case TIOCMSET: /* Turns on and off the lines as specified by the mask */
 	case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
 	case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
-		if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+		if (get_user(mask, (unsigned long *) arg))
+			return -EFAULT;
 
 		if ((cmd == TIOCMSET) || (mask & TIOCM_RTS)) {
 			/* RTS needs set */
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/serial/usbserial.c linux/drivers/usb/serial/usbserial.c
--- v2.4.9/linux/drivers/usb/serial/usbserial.c	Wed Jul 25 17:10:24 2001
+++ linux/drivers/usb/serial/usbserial.c	Tue Aug 28 11:21:02 2001
@@ -307,8 +307,6 @@
 #define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux-usb/"
 #define DRIVER_DESC "USB Serial Driver core"
 
-#define MAX(a,b)	(((a)>(b))?(a):(b))
-
 /* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) */
 /* need to always compile these in, as some of the other devices use these functions as their own. */
 /* if a driver does not provide a function pointer, the generic function will be called. */
@@ -852,7 +850,8 @@
 		count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
 
 		if (from_user) {
-			copy_from_user(port->write_urb->transfer_buffer, buf, count);
+			if (copy_from_user(port->write_urb->transfer_buffer, buf, count))
+				return -EFAULT;
 		}
 		else {
 			memcpy (port->write_urb->transfer_buffer, buf, count);
@@ -1260,9 +1259,9 @@
 
 	/* initialize some parts of the port structures */
 	/* we don't use num_ports here cauz some devices have more endpoint pairs than ports */
-	max_endpoints = MAX(num_bulk_in, num_bulk_out);
-	max_endpoints = MAX(max_endpoints, num_interrupt_in);
-	max_endpoints = MAX(max_endpoints, serial->num_ports);
+	max_endpoints = max(int, num_bulk_in, num_bulk_out);
+	max_endpoints = max(int, max_endpoints, num_interrupt_in);
+	max_endpoints = max(int, max_endpoints, serial->num_ports);
 	dbg (__FUNCTION__ " - setting up %d port structures for this device", max_endpoints);
 	for (i = 0; i < max_endpoints; ++i) {
 		port = &serial->port[i];
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/serial/visor.c linux/drivers/usb/serial/visor.c
--- v2.4.9/linux/drivers/usb/serial/visor.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/serial/visor.c	Tue Aug 28 11:21:02 2001
@@ -11,6 +11,9 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (08/23/2001) gkh
+ *	fixed a few potential bugs pointed out by Oliver Neukum.
+ *
  * (05/30/2001) gkh
  *	switched from using spinlock to a semaphore, which fixes lots of problems.
  *
@@ -115,12 +118,10 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.2"
+#define DRIVER_VERSION "v1.3"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
 #define DRIVER_DESC "USB HandSpring Visor driver"
 
-#define MIN(a,b)                (((a)<(b))?(a):(b))
-
 /* function prototypes for a handspring visor */
 static int  visor_open		(struct usb_serial_port *port, struct file *filp);
 static void visor_close		(struct usb_serial_port *port, struct file *filp);
@@ -152,11 +153,16 @@
 	{ }					/* Terminating entry */
 };
 
+static __devinitdata struct usb_device_id clie_id_table [] = {
+	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_ID) },
+	{ }					/* Terminating entry */
+};
 
 static __devinitdata struct usb_device_id id_table [] = {
 	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M500_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M505_ID) },
+	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_ID) },
 	{ }					/* Terminating entry */
 };
 
@@ -242,6 +248,31 @@
 	read_bulk_callback:	visor_read_bulk_callback,
 };
 
+/* device info for the Sony Clie */
+static struct usb_serial_device_type clie_device = {
+	name:			"Sony Clie",
+	id_table:		clie_id_table,
+	needs_interrupt_in:	MUST_HAVE_NOT,		/* this device must not have an interrupt in endpoint */
+	needs_bulk_in:		MUST_HAVE,		/* this device must have a bulk in endpoint */
+	needs_bulk_out:		MUST_HAVE,		/* this device must have a bulk out endpoint */
+	num_interrupt_in:	0,
+	num_bulk_in:		1,
+	num_bulk_out:		1,
+	num_ports:		1,
+	open:			visor_open,
+	close:			visor_close,
+	throttle:		visor_throttle,
+	unthrottle:		visor_unthrottle,
+	shutdown:		visor_shutdown,
+	ioctl:			visor_ioctl,
+	set_termios:		visor_set_termios,
+	write:			visor_write,
+	write_room:		visor_write_room,
+	chars_in_buffer:	visor_chars_in_buffer,
+	write_bulk_callback:	visor_write_bulk_callback,
+	read_bulk_callback:	visor_read_bulk_callback,
+};
+
 #define NUM_URBS			24
 #define URB_TRANSFER_BUFFER_SIZE	768
 static struct urb	*write_urb_pool[NUM_URBS];
@@ -351,8 +382,6 @@
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
-	usb_serial_debug_data (__FILE__, __FUNCTION__, count, buf);
-	
 	while (count > 0) {
 		/* try to find a free urb in our list of them */
 		urb = NULL;
@@ -376,12 +405,18 @@
 			}
 		}
 		
-		transfer_size = MIN (count, URB_TRANSFER_BUFFER_SIZE);
-		if (from_user)
-			copy_from_user (urb->transfer_buffer, current_position, transfer_size);
-		else
+		transfer_size = min (int, count, URB_TRANSFER_BUFFER_SIZE);
+		if (from_user) {
+			if (copy_from_user (urb->transfer_buffer, current_position, transfer_size)) {
+				bytes_sent = -EFAULT;
+				break;
+			}
+		} else {
 			memcpy (urb->transfer_buffer, current_position, transfer_size);
-		
+		}
+
+		usb_serial_debug_data (__FILE__, __FUNCTION__, transfer_size, urb->transfer_buffer);
+
 		/* build up our urb */
 		FILL_BULK_URB (urb, serial->dev, usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), 
 				urb->transfer_buffer, transfer_size, visor_write_bulk_callback, port);
@@ -389,8 +424,11 @@
 
 		/* send it down the pipe */
 		status = usb_submit_urb(urb);
-		if (status)
-			dbg(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status);
+		if (status) {
+			err(__FUNCTION__ " - usb_submit_urb(write bulk) failed with status = %d", status);
+			bytes_sent = status;
+			break;
+		}
 
 		current_position += transfer_size;
 		bytes_sent += transfer_size;
@@ -674,10 +712,16 @@
 /* This function is all nice and good, but we don't change anything based on it :) */
 static void visor_set_termios (struct usb_serial_port *port, struct termios *old_termios)
 {
-	unsigned int cflag = port->tty->termios->c_cflag;
+	unsigned int cflag;
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
+	if ((!port->tty) || (!port->tty->termios)) {
+		dbg(__FUNCTION__" - no tty structures");
+		return;
+	}
+
+	cflag = port->tty->termios->c_cflag;
 	/* check that they really want us to change something */
 	if (old_termios) {
 		if ((cflag == old_termios->c_cflag) &&
@@ -687,11 +731,6 @@
 		}
 	}
 
-	if ((!port->tty) || (!port->tty->termios)) {
-		dbg(__FUNCTION__" - no tty structures");
-		return;
-	}
-
 	/* get the byte size */
 	switch (cflag & CSIZE) {
 		case CS5:	dbg(__FUNCTION__ " - data bits = 5");   break;
@@ -744,6 +783,7 @@
 	usb_serial_register (&handspring_device);
 	usb_serial_register (&palm_m500_device);
 	usb_serial_register (&palm_m505_device);
+	usb_serial_register (&clie_device);
 	
 	/* create our write urb pool and transfer buffers */ 
 	spin_lock_init (&write_urb_pool_lock);
@@ -763,7 +803,7 @@
 		}
 	}
 
-	info(DRIVER_VERSION ":" DRIVER_DESC);
+	info(DRIVER_DESC " " DRIVER_VERSION);
 
 	return 0;
 }
@@ -777,6 +817,7 @@
 	usb_serial_deregister (&handspring_device);
 	usb_serial_deregister (&palm_m500_device);
 	usb_serial_deregister (&palm_m505_device);
+	usb_serial_deregister (&clie_device);
 
 	spin_lock_irqsave (&write_urb_pool_lock, flags);
 
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/serial/visor.h linux/drivers/usb/serial/visor.h
--- v2.4.9/linux/drivers/usb/serial/visor.h	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/serial/visor.h	Tue Aug 28 11:21:02 2001
@@ -24,6 +24,10 @@
 #define PALM_M500_ID			0x0001
 #define PALM_M505_ID			0x0002
 
+#define SONY_VENDOR_ID			0x054C
+#define SONY_CLIE_ID			0x0038
+#define SONY_CLIE_320_ID		0x0066
+
 /****************************************************************************
  * Handspring Visor Vendor specific request codes (bRequest values)
  * A big thank you to Handspring for providing the following information.
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/serial/whiteheat.c linux/drivers/usb/serial/whiteheat.c
--- v2.4.9/linux/drivers/usb/serial/whiteheat.c	Tue Jul  3 17:08:21 2001
+++ linux/drivers/usb/serial/whiteheat.c	Tue Aug 28 11:21:02 2001
@@ -412,12 +412,19 @@
 
 static void whiteheat_set_termios (struct usb_serial_port *port, struct termios *old_termios)
 {
-	unsigned int cflag = port->tty->termios->c_cflag;
+	unsigned int cflag;
 	struct whiteheat_port_settings port_settings;
 
 	dbg(__FUNCTION__ " -port %d", port->number);
 
 	down (&port->sem);
+
+	if ((!port->tty) || (!port->tty->termios)) {
+		dbg(__FUNCTION__" - no tty structures");
+		goto exit;
+	}
+	
+	cflag = port->tty->termios->c_cflag;
 	/* check that they really want us to change something */
 	if (old_termios) {
 		if ((cflag == old_termios->c_cflag) &&
@@ -427,11 +434,6 @@
 		}
 	}
 
-	if ((!port->tty) || (!port->tty->termios)) {
-		dbg(__FUNCTION__" - no tty structures");
-		goto exit;
-	}
-	
 	/* set the port number */
 	/* firmware uses 1 based port numbering */
 	port_settings.port = port->number + 1;
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/usb-skeleton.c linux/drivers/usb/usb-skeleton.c
--- v2.4.9/linux/drivers/usb/usb-skeleton.c	Wed Jul 25 17:10:24 2001
+++ linux/drivers/usb/usb-skeleton.c	Tue Aug 28 11:21:02 2001
@@ -1,5 +1,5 @@
 /*
- * USB Skeleton driver
+ * USB Skeleton driver - 0.4
  *
  * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
  *
@@ -22,6 +22,7 @@
  *
  * History:
  *
+ * 2001_08_21 - 0.4 - more small bug fixes.
  * 2001_05_29 - 0.3 - more bug fixes based on review from linux-usb-devel
  * 2001_05_24 - 0.2 - bug fixes based on review from linux-usb-devel people
  * 2001_05_01 - 0.1 - first version
@@ -56,7 +57,7 @@
 
 
 /* Version Information */
-#define DRIVER_VERSION "v0.3"
+#define DRIVER_VERSION "v0.4"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com"
 #define DRIVER_DESC "USB Skeleton Driver"
 
@@ -179,6 +180,22 @@
 
 
 /**
+ *	skel_delete
+ */
+static inline void skel_delete (struct usb_skel *dev)
+{
+	minor_table[dev->minor] = NULL;
+	if (dev->bulk_in_buffer != NULL)
+		kfree (dev->bulk_in_buffer);
+	if (dev->bulk_out_buffer != NULL)
+		kfree (dev->bulk_out_buffer);
+	if (dev->write_urb != NULL)
+		usb_free_urb (dev->write_urb);
+	kfree (dev);
+}
+
+
+/**
  *	skel_open
  */
 static int skel_open (struct inode *inode, struct file *file)
@@ -256,27 +273,21 @@
 
 	if (dev->udev == NULL) {
 		/* the device was unplugged before the file was released */
-		minor_table[dev->minor] = NULL;
-		if (dev->bulk_in_buffer != NULL)
-			kfree (dev->bulk_in_buffer);
-		if (dev->bulk_out_buffer != NULL)
-			kfree (dev->bulk_out_buffer);
-		if (dev->write_urb != NULL)
-			usb_free_urb (dev->write_urb);
-		kfree (dev);
-		goto exit;
+		up (&dev->sem);
+		skel_delete (dev);
+		MOD_DEC_USE_COUNT;
+		up (&minor_table_mutex);
+		return 0;
 	}
 
 	/* decrement our usage count for the device */
 	--dev->open_count;
 	if (dev->open_count <= 0) {
 		/* shutdown any bulk writes that might be going on */
-		dev->write_urb->transfer_flags |= USB_ASYNC_UNLINK;
 		usb_unlink_urb (dev->write_urb);
 		dev->open_count = 0;
 	}
 
-exit:
 	/* decrement our usage count for the module */
 	MOD_DEC_USE_COUNT;
 
@@ -453,9 +464,12 @@
 }
 
 
-
-
-
+/**
+ *	skel_probe
+ *
+ *	Called by the usb core when a new device is connected that it thinks
+ *	this driver might be interested in.
+ */
 static void * skel_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
 {
 	struct usb_skel *dev = NULL;
@@ -476,7 +490,7 @@
 
 	/* select a "subminor" number (part of a minor number) */
 	down (&minor_table_mutex);
-	for (minor = 0; minor < MAX_DEVICES; i++) {
+	for (minor = 0; minor < MAX_DEVICES; ++minor) {
 		if (minor_table[minor] == NULL)
 			break;
 	}
@@ -558,14 +572,7 @@
 	goto exit;
 	
 error:
-	minor_table [dev->minor] = NULL;
-	if (dev->bulk_in_buffer != NULL)
-		kfree (dev->bulk_in_buffer);
-	if (dev->bulk_out_buffer != NULL)
-		kfree (dev->bulk_out_buffer);
-	if (dev->write_urb != NULL)
-		usb_free_urb (dev->write_urb);
-	kfree (dev);
+	skel_delete (dev);
 	dev = NULL;
 
 exit:
@@ -576,6 +583,8 @@
 
 /**
  *	skel_disconnect
+ *
+ *	Called by the usb core when the device is removed from the system.
  */
 static void skel_disconnect(struct usb_device *udev, void *ptr)
 {
@@ -591,14 +600,7 @@
 
 	/* if the device is not opened, then we clean up right now */
 	if (!dev->open_count) {
-		minor_table[dev->minor] = NULL;
-		if (dev->bulk_in_buffer != NULL)
-			kfree (dev->bulk_in_buffer);
-		if (dev->bulk_out_buffer != NULL)
-			kfree (dev->bulk_out_buffer);
-		if (dev->write_urb != NULL)
-			usb_free_urb (dev->write_urb);
-		kfree (dev);
+		skel_delete (dev);
 	} else {
 		dev->udev = NULL;
 		up (&dev->sem);
@@ -628,8 +630,7 @@
 		return -1;
 	}
 
-	info(DRIVER_VERSION " " DRIVER_AUTHOR);
-	info(DRIVER_DESC);
+	info(DRIVER_DESC " " DRIVER_VERSION);
 	return 0;
 }
 
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/usb-uhci.c linux/drivers/usb/usb-uhci.c
--- v2.4.9/linux/drivers/usb/usb-uhci.c	Mon Aug 27 12:41:45 2001
+++ linux/drivers/usb/usb-uhci.c	Tue Aug 28 11:21:02 2001
@@ -1,7 +1,7 @@
 /* 
  * Universal Host Controller Interface driver for USB (take II).
  *
- * (c) 1999-2000 Georg Acher, acher@in.tum.de (executive slave) (base guitar)
+ * (c) 1999-2001 Georg Acher, acher@in.tum.de (executive slave) (base guitar)
  *               Deti Fliegl, deti@fliegl.de (executive slave) (lead voice)
  *               Thomas Sailer, sailer@ife.ee.ethz.ch (chief consultant) (cheer leader)
  *               Roman Weissgaerber, weissg@vienna.at (virt root hub) (studio porter)
@@ -16,7 +16,7 @@
  * (C) Copyright 1999 Randy Dunlap
  * (C) Copyright 1999 Gregory P. Smith
  *
- * $Id: usb-uhci.c,v 1.259 2001/03/30 14:51:59 acher Exp $
+ * $Id: usb-uhci.c,v 1.267 2001/08/28 16:45:00 acher Exp $
  */
 
 #include <linux/config.h>
@@ -52,7 +52,7 @@
 /* This enables an extra UHCI slab for memory debugging */
 #define DEBUG_SLAB
 
-#define VERSTR "$Revision: 1.259 $ time " __TIME__ " " __DATE__
+#define VERSTR "$Revision: 1.267 $ time " __TIME__ " " __DATE__
 
 #include <linux/usb.h>
 #include "usb-uhci.h"
@@ -61,7 +61,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.251"
+#define DRIVER_VERSION "v1.267"
 #define DRIVER_AUTHOR "Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber"
 #define DRIVER_DESC "USB Universal Host Controller Interface driver"
 
@@ -88,13 +88,34 @@
 #define SLAB_FLAG     (in_interrupt ()? SLAB_ATOMIC : SLAB_KERNEL)
 #define KMALLOC_FLAG  (in_interrupt ()? GFP_ATOMIC : GFP_KERNEL)
 
+/* CONFIG_USB_UHCI_HIGH_BANDWITH turns on Full Speed Bandwidth
+ * Reclamation: feature that puts loop on descriptor loop when
+ * there's some transfer going on. With FSBR, USB performance
+ * is optimal, but PCI can be slowed down up-to 5 times, slowing down
+ * system performance (eg. framebuffer devices).
+ */
 #define CONFIG_USB_UHCI_HIGH_BANDWIDTH 
+
+/* *_DEPTH_FIRST puts descriptor in depth-first mode. This has
+ * somehow similar effect to FSBR (higher speed), but does not
+ * slow PCI down. OTOH USB performace is slightly slower than
+ * in FSBR case and single device could hog whole USB, starving
+ * other devices.
+ */
 #define USE_CTRL_DEPTH_FIRST 0  // 0: Breadth first, 1: Depth first
 #define USE_BULK_DEPTH_FIRST 0  // 0: Breadth first, 1: Depth first
 
+/* Turning off both CONFIG_USB_UHCI_HIGH_BANDWITH and *_DEPTH_FIRST
+ * will lead to <64KB/sec performance over USB for bulk transfers targeting
+ * one device's endpoint. You probably do not want to do that.
+ */
+
 // stop bandwidth reclamation after (roughly) 50ms
 #define IDLE_TIMEOUT  (HZ/20)
 
+// Suppress HC interrupt error messages for 5s
+#define ERROR_SUPPRESSION_TIME (HZ*5)
+
 _static int rh_submit_urb (urb_t *urb);
 _static int rh_unlink_urb (urb_t *urb);
 _static int delete_qh (uhci_t *s, uhci_desc_t *qh);
@@ -133,20 +154,15 @@
 _static void uhci_switch_timer_int(uhci_t *s)
 {
 
-	if (!list_empty(&s->urb_unlinked)) {
-		s->td1ms->hw.td.status |= cpu_to_le32(TD_CTRL_IOC);
-	}
-	else {
-		s->td1ms->hw.td.status &= cpu_to_le32(~TD_CTRL_IOC);
-	}
-
-	if (s->timeout_urbs) {
-		s->td32ms->hw.td.status |= cpu_to_le32(TD_CTRL_IOC);
-	}
-	else {
-		s->td32ms->hw.td.status &= cpu_to_le32(~TD_CTRL_IOC);
-	}
+	if (!list_empty(&s->urb_unlinked))
+		set_td_ioc(s->td1ms);
+	else
+		clr_td_ioc(s->td1ms);
 
+	if (s->timeout_urbs)
+		set_td_ioc(s->td32ms);
+	else
+		clr_td_ioc(s->td32ms);
 	wmb();
 }
 /*-------------------------------------------------------------------*/
@@ -199,6 +215,7 @@
 			enable_desc_loop(s, urb);
 	}
 #endif
+	urb->status = -EINPROGRESS;
 	((urb_priv_t*)urb->hcpriv)->started=jiffies;
 	list_add (p, &s->urb_list);
 	if (urb->timeout)
@@ -241,7 +258,7 @@
 		return -ENOMEM;
 	memset (*new, 0, sizeof (uhci_desc_t));
 	(*new)->dma_addr = dma_handle;
-	(*new)->hw.td.link = cpu_to_le32(UHCI_PTR_TERM | (flags & UHCI_PTR_BITS));	// last by default
+	set_td_link((*new), UHCI_PTR_TERM | (flags & UHCI_PTR_BITS));	// last by default
 	(*new)->type = TD_TYPE;
 	mb();
 	INIT_LIST_HEAD (&(*new)->vertical);
@@ -257,7 +274,7 @@
 	
 	spin_lock_irqsave (&s->td_lock, xxx);
 
-	td->hw.td.link = cpu_to_le32(qh->dma_addr | (flags & UHCI_PTR_DEPTH) | UHCI_PTR_QH);
+	set_td_link(td, qh->dma_addr | (flags & UHCI_PTR_DEPTH) | UHCI_PTR_QH);
        
 	mb();
 	spin_unlock_irqrestore (&s->td_lock, xxx);
@@ -277,11 +294,11 @@
 
 	if (qh == prev ) {
 		// virgin qh without any tds
-		qh->hw.qh.element = cpu_to_le32(new->dma_addr | UHCI_PTR_TERM);
+		set_qh_element(qh, new->dma_addr | UHCI_PTR_TERM);
 	}
 	else {
 		// already tds inserted, implicitely remove TERM bit of prev
-		prev->hw.td.link = cpu_to_le32(new->dma_addr | (flags & UHCI_PTR_DEPTH));
+		set_td_link(prev, new->dma_addr | (flags & UHCI_PTR_DEPTH));
 	}
 	mb();
 	spin_unlock_irqrestore (&s->td_lock, xxx);
@@ -300,7 +317,7 @@
 	next = list_entry (td->horizontal.next, uhci_desc_t, horizontal);
 	list_add (&new->horizontal, &td->horizontal);
 	new->hw.td.link = td->hw.td.link;
-	td->hw.td.link = cpu_to_le32(new->dma_addr);
+	set_td_link(td, new->dma_addr);
 	mb();
 	spin_unlock_irqrestore (&s->td_lock, flags);	
 	
@@ -361,8 +378,8 @@
 		return -ENOMEM;
 	memset (*new, 0, sizeof (uhci_desc_t));
 	(*new)->dma_addr = dma_handle;
-	(*new)->hw.qh.head = cpu_to_le32(UHCI_PTR_TERM);
-	(*new)->hw.qh.element = cpu_to_le32(UHCI_PTR_TERM);
+	set_qh_head(*new, UHCI_PTR_TERM);
+	set_qh_element(*new, UHCI_PTR_TERM);
 	(*new)->type = QH_TYPE;
 	
 	mb();
@@ -387,16 +404,16 @@
 		// (OLD) (POS) -> (OLD) (NEW) (POS)
 		old = list_entry (pos->horizontal.prev, uhci_desc_t, horizontal);
 		list_add_tail (&new->horizontal, &pos->horizontal);
-		new->hw.qh.head = cpu_to_le32(MAKE_QH_ADDR (pos)) ;
+		set_qh_head(new, MAKE_QH_ADDR (pos)) ;
 		if (!(old->hw.qh.head & cpu_to_le32(UHCI_PTR_TERM)))
-			old->hw.qh.head = cpu_to_le32(MAKE_QH_ADDR (new)) ;
+			set_qh_head(old, MAKE_QH_ADDR (new)) ;
 	}
 	else {
 		// (POS) (OLD) -> (POS) (NEW) (OLD)
 		old = list_entry (pos->horizontal.next, uhci_desc_t, horizontal);
 		list_add (&new->horizontal, &pos->horizontal);
-		new->hw.qh.head = cpu_to_le32(MAKE_QH_ADDR (old));
-		pos->hw.qh.head = cpu_to_le32(MAKE_QH_ADDR (new)) ;
+		set_qh_head(new, MAKE_QH_ADDR (old));
+		set_qh_head(pos, MAKE_QH_ADDR (new)) ;
 	}
 
 	mb ();
@@ -522,7 +539,7 @@
 		if (s->ls_control_chain)
 			delete_desc (s, s->ls_control_chain);
 		if (s->control_chain)
-			 delete_desc(s, s->control_chain);
+			delete_desc (s, s->control_chain);
 		if (s->bulk_chain)
 			delete_desc (s, s->bulk_chain);
 		if (s->chain_end)
@@ -576,24 +593,20 @@
 	dbg("allocating iso descs");
 	for (n = 0; n < 1024; n++) {
 	 	// allocate skeleton iso/irq-tds
-		ret = alloc_td (s, &td, 0);
-		if (ret)
+		if (alloc_td (s, &td, 0))
 			goto init_skel_cleanup;
+
 		s->iso_td[n] = td;
 		s->framelist[n] = cpu_to_le32((__u32) td->dma_addr);
 	}
 
 	dbg("allocating qh: chain_end");
-	ret = alloc_qh (s, &qh);
-	
-	if (ret)
+	if (alloc_qh (s, &qh))	
 		goto init_skel_cleanup;
 				
 	s->chain_end = qh;
 
-	ret = alloc_td (s, &td, 0);
-
-	if (ret)
+	if (alloc_td (s, &td, 0))
 		goto init_skel_cleanup;
 	
 	fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 1ms interrupt (enabled on demand)
@@ -602,8 +615,7 @@
 	s->td1ms=td;
 
 	dbg("allocating qh: bulk_chain");
-	ret = alloc_qh (s, &qh);
-	if (ret)
+	if (alloc_qh (s, &qh))
 		goto init_skel_cleanup;
 	
 	insert_qh (s, s->chain_end, qh, 0);
@@ -619,12 +631,11 @@
 
 #ifdef	CONFIG_USB_UHCI_HIGH_BANDWIDTH
 	// disabled reclamation loop
-	s->chain_end->hw.qh.head = cpu_to_le32(s->control_chain->dma_addr | UHCI_PTR_QH | UHCI_PTR_TERM);
+	set_qh_head(s->chain_end, s->control_chain->dma_addr | UHCI_PTR_QH | UHCI_PTR_TERM);
 #endif
 
 	dbg("allocating qh: ls_control_chain");
-	ret = alloc_qh (s, &qh);
-	if (ret)
+	if (alloc_qh (s, &qh))
 		goto init_skel_cleanup;
 	
 	insert_qh (s, s->control_chain, qh, 0);
@@ -638,15 +649,15 @@
 	for (n = 0; n < 8; n++) {
 		uhci_desc_t *td;
 
-		alloc_td (s, &td, 0);
-		if (!td)
+		if (alloc_td (s, &td, 0))
 			goto init_skel_cleanup;
+
 		s->int_chain[n] = td;
 		if (n == 0) {
-			s->int_chain[0]->hw.td.link = cpu_to_le32(s->ls_control_chain->dma_addr | UHCI_PTR_QH);
+			set_td_link(s->int_chain[0], s->ls_control_chain->dma_addr | UHCI_PTR_QH);
 		}
 		else {
-			s->int_chain[n]->hw.td.link = cpu_to_le32(s->int_chain[0]->dma_addr);
+			set_td_link(s->int_chain[n], s->int_chain[0]->dma_addr);
 		}
 	}
 
@@ -661,16 +672,13 @@
 		else 
 			for (o = 1, m = 2; m <= 128; o++, m += m)
 				if ((n & (m - 1)) == ((m - 1) / 2))
-					((uhci_desc_t*) s->iso_td[n])->hw.td.link =
-						cpu_to_le32(s->int_chain[o]->dma_addr);
+					set_td_link(((uhci_desc_t*) s->iso_td[n]), s->int_chain[o]->dma_addr);
 	}
 
-	ret = alloc_td (s, &td, 0);
-
-	if (ret)
+	if (alloc_td (s, &td, 0))
 		goto init_skel_cleanup;
 	
-	fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 32ms interrupt
+	fill_td (td, 0 * TD_CTRL_IOC, 0, 0); // generate 32ms interrupt (activated later)
 	s->td32ms=td;
 
 	insert_td_horizontal (s, s->int_chain[5], td);
@@ -700,20 +708,12 @@
 	char *data;
 	int depth_first=USE_CTRL_DEPTH_FIRST;  // UHCI descriptor chasing method
 
-	if (!maxsze) {
-		err("uhci_submit_control_urb: pipesize for pipe %x is zero", urb->pipe);
-		return -EINVAL;
-	}
-
 	dbg("uhci_submit_control start");
-	alloc_qh (s, &qh);		// alloc qh for this request
-
-	if (!qh)
+	if (alloc_qh (s, &qh))		// alloc qh for this request
 		return -ENOMEM;
 
-	alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first);		// get td for setup stage
-
-	if (!td) {
+	if (alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first))		// get td for setup stage
+	{
 		delete_qh (s, qh);
 		return -ENOMEM;
 	}
@@ -749,8 +749,7 @@
 	while (len > 0) {
 		int pktsze = len;
 
-		alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first);
-		if (!td)
+		if (alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first))
 			goto fail_unmap_enomem;
 
 		if (pktsze > maxsze)
@@ -768,7 +767,7 @@
 		len -= pktsze;
 	}
 
-	/*  Build the final TD for control status */
+	/* Build the final TD for control status */
 	/* It's only IN if the pipe is out AND we aren't expecting data */
 
 	destination &= ~UHCI_PID;
@@ -780,9 +779,7 @@
 
 	destination |= 1 << TD_TOKEN_TOGGLE;	/* End in Data1 */
 
-	alloc_td (s, &td, UHCI_PTR_DEPTH);
-	
-	if (!td)
+	if (alloc_td (s, &td, UHCI_PTR_DEPTH))
 		goto fail_unmap_enomem;
 
 	status &=~TD_CTRL_SPD;
@@ -795,7 +792,6 @@
 
 	list_add (&qh->desc_list, &urb_priv->desc_list);
 
-	urb->status = -EINPROGRESS;
 	queue_urb (s, urb);	// queue before inserting in desc chain
 
 	qh->hw.qh.element &= cpu_to_le32(~UHCI_PTR_TERM);
@@ -821,7 +817,7 @@
 _static int uhci_submit_bulk_urb (urb_t *urb, urb_t *bulk_urb)
 {
 	uhci_t *s = (uhci_t*) urb->dev->bus->hcpriv;
-	urb_priv_t *urb_priv = urb->hcpriv;
+	urb_priv_t *urb_priv = urb->hcpriv, *upriv, *bpriv=NULL;
 	uhci_desc_t *qh, *td, *nqh=NULL, *bqh=NULL, *first_td=NULL;
 	unsigned long destination, status;
 	char *data;
@@ -829,33 +825,22 @@
 	int maxsze = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
 	int info, len, last;
 	int depth_first=USE_BULK_DEPTH_FIRST;  // UHCI descriptor chasing method
-	urb_priv_t *upriv, *bpriv=NULL;
 
 	if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)))
 		return -EPIPE;
 
-	if (urb->transfer_buffer_length < 0) {
-		err("Negative transfer length in submit_bulk");
-		return -EINVAL;
-	}
-	
-	if (!maxsze)
-		return -EMSGSIZE;
-	
 	queue_dbg("uhci_submit_bulk_urb: urb %p, old %p, pipe %08x, len %i",
 		  urb,bulk_urb,urb->pipe,urb->transfer_buffer_length);
 
 	upriv = (urb_priv_t*)urb->hcpriv;
 
 	if (!bulk_urb) {
-		alloc_qh (s, &qh);		// get qh for this request
-		
-		if (!qh)
+		if (alloc_qh (s, &qh))		// get qh for this request
 			return -ENOMEM;
 
 		if (urb->transfer_flags & USB_QUEUE_BULK) {
-			alloc_qh(s, &nqh); // placeholder for clean unlink
-			if (!nqh) {
+			if (alloc_qh(s, &nqh)) // placeholder for clean unlink
+			{
 				delete_desc (s, qh);
 				return -ENOMEM;
 			}
@@ -872,17 +857,16 @@
 	}
 
 	if (urb->transfer_flags & USB_QUEUE_BULK) {
-		alloc_qh (s, &bqh); // "bottom" QH,
-		
-		if (!bqh) {
+		if (alloc_qh (s, &bqh))  // "bottom" QH
+		{
 			if (!bulk_urb) { 
 				delete_desc(s, qh);
 				delete_desc(s, nqh);
 			}
 			return -ENOMEM;
 		}
-		bqh->hw.qh.element = cpu_to_le32(UHCI_PTR_TERM);
-		bqh->hw.qh.head = cpu_to_le32(nqh->dma_addr | UHCI_PTR_QH); // element
+		set_qh_element(bqh, UHCI_PTR_TERM);
+		set_qh_head(bqh, nqh->dma_addr | UHCI_PTR_QH); // element
 		upriv->bottom_qh = bqh;
 	}
 	queue_dbg("uhci_submit_bulk: qh %p bqh %p nqh %p",qh, bqh, nqh);
@@ -901,9 +885,8 @@
 	do {					// TBD: Really allow zero-length packets?
 		int pktsze = len;
 
-		alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first);
-
-		if (!td) {
+		if (alloc_td (s, &td, UHCI_PTR_DEPTH * depth_first))
+		{
 			delete_qh (s, qh);
 			return -ENOMEM;
 		}
@@ -924,7 +907,7 @@
 		last = (len == 0 && (usb_pipein(pipe) || pktsze < maxsze || !(urb->transfer_flags & USB_ZERO_PACKET)));
 
 		if (last)
-			td->hw.td.status |= cpu_to_le32(TD_CTRL_IOC);	// last one generates INT
+			set_td_ioc(td);	// last one generates INT
 
 		insert_td (s, qh, td, UHCI_PTR_DEPTH * depth_first);
 		if (!first_td)
@@ -941,11 +924,10 @@
 	if (urb->transfer_flags & USB_QUEUE_BULK)
 		append_qh(s, td, bqh, UHCI_PTR_DEPTH * depth_first);
 
-	urb->status = -EINPROGRESS;
 	queue_urb_unlocked (s, urb);
 	
 	if (urb->transfer_flags & USB_QUEUE_BULK)
-		qh->hw.qh.element = cpu_to_le32(first_td->dma_addr);
+		set_qh_element(qh, first_td->dma_addr);
 	else
 		qh->hw.qh.element &= cpu_to_le32(~UHCI_PTR_TERM);    // arm QH
 
@@ -988,10 +970,11 @@
 	}
 }
 /*-------------------------------------------------------------------*/
-// mode: 0: unlink but no deletion mark (step 1 of async_unlink)
-//       1: regular (unlink/delete-mark)
-//       2: deletion mark for QH (step 2 of async_unlink)
-// looks a bit complicated because of all the bulk queueing goodies
+/* mode: CLEAN_TRANSFER_NO_DELETION: unlink but no deletion mark (step 1 of async_unlink)
+         CLEAN_TRANSFER_REGULAR: regular (unlink/delete-mark)
+         CLEAN_TRANSFER_DELETION_MARK: deletion mark for QH (step 2 of async_unlink)
+ looks a bit complicated because of all the bulk queueing goodies
+*/
 
 _static void uhci_clean_transfer (uhci_t *s, urb_t *urb, uhci_desc_t *qh, int mode)
 {
@@ -1005,18 +988,16 @@
 	
 	if (!priv->next_queued_urb)  { // no more appended bulk queues
 
-		queue_dbg("uhci_clean_transfer: No more bulks for urb %p, qh %p, bqh %p, nqh %p",urb, qh, bqh, priv->next_qh);	
+		queue_dbg("uhci_clean_transfer: No more bulks for urb %p, qh %p, bqh %p, nqh %p", urb, qh, bqh, priv->next_qh);	
 	
-		if (priv->prev_queued_urb) {  // qh not top of the queue
-			urb_priv_t* ppriv=(urb_priv_t*)priv->prev_queued_urb->hcpriv;
+		if (priv->prev_queued_urb && mode != CLEAN_TRANSFER_DELETION_MARK) {  // qh not top of the queue
+				unsigned long flags; 
+				urb_priv_t* ppriv=(urb_priv_t*)priv->prev_queued_urb->hcpriv;
 
-			if (mode != 2) {
-				unsigned long flags;
-				
 				spin_lock_irqsave (&s->qh_lock, flags);
 				prevqh = list_entry (ppriv->desc_list.next, uhci_desc_t, desc_list);
 				prevtd = list_entry (prevqh->vertical.prev, uhci_desc_t, vertical);
-				prevtd->hw.td.link = cpu_to_le32(priv->bottom_qh->dma_addr | UHCI_PTR_QH); // skip current qh
+				set_td_link(prevtd, priv->bottom_qh->dma_addr | UHCI_PTR_QH); // skip current qh
 				mb();
 				queue_dbg("uhci_clean_transfer: relink pqh %p, ptd %p",prevqh, prevtd);
 				spin_unlock_irqrestore (&s->qh_lock, flags);
@@ -1024,19 +1005,18 @@
 				ppriv->bottom_qh = priv->bottom_qh;
 				ppriv->next_queued_urb = NULL;
 			}
-		}
 		else {   // queue is dead, qh is top of the queue
 			
-			if (mode!=2)
+			if (mode != CLEAN_TRANSFER_DELETION_MARK) 				
 				unlink_qh(s, qh); // remove qh from horizontal chain
 
 			if (bqh) {  // remove remainings of bulk queue
 				nqh=priv->next_qh;
 
-				if (mode != 2) 
+				if (mode != CLEAN_TRANSFER_DELETION_MARK) 
 					unlink_qh(s, nqh);  // remove nqh from horizontal chain
 				
-				if (mode) {
+				if (mode != CLEAN_TRANSFER_NO_DELETION) {  // add helper QHs to free desc list
 					nqh->last_used = bqh->last_used = now;
 					list_add_tail (&nqh->horizontal, &s->free_desc);
 					list_add_tail (&bqh->horizontal, &s->free_desc);
@@ -1049,7 +1029,7 @@
 	  queue_dbg("uhci_clean_transfer: urb %p, prevurb %p, nexturb %p, qh %p, bqh %p, nqh %p",
 		       urb, priv->prev_queued_urb,  priv->next_queued_urb, qh, bqh, priv->next_qh);	
        	
-		if (mode !=2) {	// no work for cleanup at unlink-completion
+		if (mode != CLEAN_TRANSFER_DELETION_MARK) {	// no work for cleanup at unlink-completion
 			urb_t *nurb;
 			unsigned long flags;
 
@@ -1059,7 +1039,7 @@
 			if (!priv->prev_queued_urb) { // top QH
 				
 				prevqh = list_entry (qh->horizontal.prev, uhci_desc_t, horizontal);
-				prevqh->hw.qh.head = cpu_to_le32(bqh->dma_addr | UHCI_PTR_QH);
+				set_qh_head(prevqh, bqh->dma_addr | UHCI_PTR_QH);
 				list_del (&qh->horizontal);  // remove this qh form horizontal chain
 				list_add (&bqh->horizontal, &prevqh->horizontal); // insert next bqh in horizontal chain
 			}
@@ -1072,18 +1052,18 @@
 				ppriv->bottom_qh = bnqh;
 				ppriv->next_queued_urb = nurb;				
 				prevqh = list_entry (ppriv->desc_list.next, uhci_desc_t, desc_list);
-				prevqh->hw.qh.head = cpu_to_le32(bqh->dma_addr | UHCI_PTR_QH);
+				set_qh_head(prevqh, bqh->dma_addr | UHCI_PTR_QH);
 			}
 
 			mb();
-			spin_unlock_irqrestore (&s->qh_lock, flags);
 			((urb_priv_t*)nurb->hcpriv)->prev_queued_urb=priv->prev_queued_urb;
+			spin_unlock_irqrestore (&s->qh_lock, flags);
 		}		
 	}
 
-	if (mode) {
+	if (mode != CLEAN_TRANSFER_NO_DELETION) {
 		qh->last_used = now;	
-		list_add_tail (&qh->horizontal, &s->free_desc); // mark for later deletion/kfree
+		list_add_tail (&qh->horizontal, &s->free_desc); // mark qh for later deletion/kfree
 	}
 }
 /*-------------------------------------------------------------------*/
@@ -1134,9 +1114,56 @@
 		urb_priv->transfer_buffer_dma = 0;
 	}
 }
+/*-------------------------------------------------------------------*/
+/* needs urb_list_lock!
+   mode: UNLINK_ASYNC_STORE_URB: unlink and move URB into unlinked list
+         UNLINK_ASYNC_DONT_STORE: unlink, don't move URB into unlinked list
+*/
+_static int uhci_unlink_urb_async (uhci_t *s,urb_t *urb, int mode)
+{
+	uhci_desc_t *qh;
+	urb_priv_t *urb_priv;
+	
+	async_dbg("unlink_urb_async called %p",urb);
+
+	if ((urb->status == -EINPROGRESS) ||
+	    ((usb_pipetype (urb->pipe) ==  PIPE_INTERRUPT) && ((urb_priv_t*)urb->hcpriv)->flags))
+	{
+		((urb_priv_t*)urb->hcpriv)->started = ~0;  // mark
+		dequeue_urb (s, urb);
+
+		if (mode==UNLINK_ASYNC_STORE_URB)
+			list_add_tail (&urb->urb_list, &s->urb_unlinked); // store urb
+
+		uhci_switch_timer_int(s);
+       		s->unlink_urb_done = 1;
+		uhci_release_bandwidth(urb);
+
+		urb->status = -ECONNABORTED;	// mark urb as "waiting to be killed"	
+		urb_priv = (urb_priv_t*)urb->hcpriv;
+
+		switch (usb_pipetype (urb->pipe)) {
+		case PIPE_INTERRUPT:
+			usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
+
+		case PIPE_ISOCHRONOUS:
+			uhci_clean_iso_step1 (s, urb_priv);
+			break;
 
+		case PIPE_BULK:
+		case PIPE_CONTROL:
+			qh = list_entry (urb_priv->desc_list.next, uhci_desc_t, desc_list);
+			uhci_clean_transfer (s, urb, qh, CLEAN_TRANSFER_NO_DELETION);
+			break;
+		}
+		((urb_priv_t*)urb->hcpriv)->started = UHCI_GET_CURRENT_FRAME(s);
+		return -EINPROGRESS;  // completion will follow
+	}		
+
+	return 0;    // URB already dead
+}
 /*-------------------------------------------------------------------*/
-// unlinks an urb by dequeuing its qh, waits some frames and forgets it
+// kills an urb by unlinking descriptors and waiting for at least one frame
 _static int uhci_unlink_urb_sync (uhci_t *s, urb_t *urb)
 {
 	uhci_desc_t *qh;
@@ -1150,43 +1177,36 @@
 		spin_lock(&urb->lock); 
 	
 	if (urb->status == -EINPROGRESS) {
-		// URB probably still in work
-		dequeue_urb (s, urb);
-		uhci_switch_timer_int(s);
-		s->unlink_urb_done=1;
 
-		uhci_release_bandwidth(urb);
-		urb->status = -ENOENT;	// mark urb as killed		
+		// move descriptors out the the running chains, dequeue urb
+		uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_DONT_STORE);
 
 		if (!in_interrupt())	
 			spin_unlock(&urb->lock); 
-
-		spin_unlock_irqrestore (&s->urb_list_lock, flags);		
 		
 		urb_priv = urb->hcpriv;
 
+		// cleanup the rest
 		switch (usb_pipetype (urb->pipe)) {
 
-		case PIPE_INTERRUPT:
-			usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));
-
 		case PIPE_ISOCHRONOUS:
-			uhci_clean_iso_step1(s, urb_priv);
 			uhci_wait_ms(1);
 			uhci_clean_iso_step2(s, urb_priv);
 			break;
 
 		case PIPE_BULK:
 		case PIPE_CONTROL:
-			spin_lock_irqsave (&s->urb_list_lock, flags);
 			qh = list_entry (urb_priv->desc_list.next, uhci_desc_t, desc_list);
-			uhci_clean_transfer(s, urb, qh, 1);
-			spin_unlock_irqrestore (&s->urb_list_lock, flags);
+			uhci_clean_transfer(s, urb, qh, CLEAN_TRANSFER_DELETION_MARK);
 			uhci_wait_ms(1);
 		}
-		
+
+		spin_unlock_irqrestore (&s->urb_list_lock, flags);
+				
 		uhci_urb_dma_unmap(s, urb, urb->hcpriv);
 
+		urb->status = -ENOENT;	// mark urb as killed		
+
 #ifdef DEBUG_SLAB
 		kmem_cache_free (urb_priv_kmem, urb->hcpriv);
 #else
@@ -1219,7 +1239,7 @@
 	struct list_head *q;
 	urb_t *urb;
 	struct usb_device *dev;
-	int pipe,now;
+	int now, type;
 	urb_priv_t *urb_priv;
 
 	q=s->urb_unlinked.next;
@@ -1235,21 +1255,22 @@
 		if (!urb_priv) // avoid crash when URB is corrupted
 			break;
 			
-		if (force ||
- 		    ((urb_priv->started != 0xffffffff) && (urb_priv->started != now))) {
+		if (force || ((urb_priv->started != ~0) && (urb_priv->started != now))) {
 			async_dbg("async cleanup %p",urb);
-			switch (usb_pipetype (urb->pipe)) { // process descriptors
+			type=usb_pipetype (urb->pipe);
+
+			switch (type) { // process descriptors
 			case PIPE_CONTROL:
-				process_transfer (s, urb, 2);  // 2: don't unlink (already done)
+				process_transfer (s, urb, CLEAN_TRANSFER_DELETION_MARK);  // don't unlink (already done)
 				break;
 			case PIPE_BULK:
 				if (!s->avoid_bulk.counter)
-					process_transfer (s, urb, 2); // don't unlink (already done)
+					process_transfer (s, urb, CLEAN_TRANSFER_DELETION_MARK); // don't unlink (already done)
 				else
 					continue;
 				break;
 			case PIPE_ISOCHRONOUS:
-				process_iso (s, urb, 1); // force, don't unlink
+				process_iso (s, urb, PROCESS_ISO_FORCE); // force, don't unlink
 				break;
 			case PIPE_INTERRUPT:
 				process_interrupt (s, urb);
@@ -1259,8 +1280,7 @@
 			if (!(urb->transfer_flags & USB_TIMEOUT_KILLED))
 		  		urb->status = -ECONNRESET; // mark as asynchronously killed
 
-			pipe = urb->pipe;		// completion may destroy all...
-			dev = urb->dev;
+			dev = urb->dev;	// completion may destroy all...
 			urb_priv = urb->hcpriv;
 			list_del (&urb->urb_list);
 			
@@ -1274,7 +1294,8 @@
 
 			if (!(urb->transfer_flags & USB_TIMEOUT_KILLED))
 				urb->status = -ENOENT;  // now the urb is really dead
-			switch (usb_pipetype (pipe)) {
+
+			switch (type) {
 			case PIPE_ISOCHRONOUS:
 			case PIPE_INTERRUPT:
 				uhci_clean_iso_step2(s, urb_priv);
@@ -1293,50 +1314,7 @@
 		}
 	}
 }
-
-/*-------------------------------------------------------------------*/
-// needs urb_list_lock!
-_static int uhci_unlink_urb_async (uhci_t *s,urb_t *urb)
-{
-	uhci_desc_t *qh;
-	urb_priv_t *urb_priv;
-	
-	async_dbg("unlink_urb_async called %p",urb);
-
-	if ((urb->status == -EINPROGRESS) ||
-	    ((usb_pipetype (urb->pipe) ==  PIPE_INTERRUPT) && ((urb_priv_t*)urb->hcpriv)->flags))
-	{
-		((urb_priv_t*)urb->hcpriv)->started = ~0;
-
-		dequeue_urb (s, urb);
-		list_add_tail (&urb->urb_list, &s->urb_unlinked); // store urb
-		uhci_switch_timer_int(s);
-			
-		s->unlink_urb_done = 1;
-		
-		urb->status = -ECONNABORTED;	// mark urb as "waiting to be killed"	
-		urb_priv = (urb_priv_t*)urb->hcpriv;
-
-		switch (usb_pipetype (urb->pipe)) {
-		case PIPE_INTERRUPT:
-			usb_dotoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe));		
-
-		case PIPE_ISOCHRONOUS:
-			uhci_clean_iso_step1 (s, urb_priv);
-			break;
-
-		case PIPE_BULK:
-		case PIPE_CONTROL:
-			qh = list_entry (urb_priv->desc_list.next, uhci_desc_t, desc_list);
-			uhci_clean_transfer (s, urb, qh, 0);
-			break;
-		}
-		((urb_priv_t*)urb->hcpriv)->started = UHCI_GET_CURRENT_FRAME(s);
-		return -EINPROGRESS;  // completion will follow
-	}		
-
-	return 0;    // URB already dead
-}
+ 
 /*-------------------------------------------------------------------*/
 _static int uhci_unlink_urb (urb_t *urb)
 {
@@ -1365,7 +1343,7 @@
 			spin_lock(&urb->lock);
 
 		uhci_release_bandwidth(urb);
-		ret = uhci_unlink_urb_async(s, urb);
+		ret = uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
 
 		if (!in_interrupt())
 			spin_unlock(&urb->lock);
@@ -1509,9 +1487,7 @@
 	if (urb->transfer_buffer_length > usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe)))
 		return -EINVAL;
 
-	ret = alloc_td (s, &td, UHCI_PTR_DEPTH);
-
-	if (ret)
+	if (alloc_td (s, &td, UHCI_PTR_DEPTH))
 		return -ENOMEM;
 
 	status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC |
@@ -1526,7 +1502,6 @@
 	fill_td (td, status, info, urb_priv->transfer_buffer_dma);
 	list_add_tail (&td->desc_list, &urb_priv->desc_list);
 
-	urb->status = -EINPROGRESS;
 	queue_urb (s, urb);
 
 	insert_td_horizontal (s, s->int_chain[nint], td);	// store in INT-TDs
@@ -1563,27 +1538,27 @@
 		goto err;
 	}
 
-	// First try to get all TDs
+	memset(tdm, 0, urb->number_of_packets * sizeof (uhci_desc_t*));
+
+	// First try to get all TDs. Cause: Removing already inserted TDs can only be done 
+	// racefree in three steps: unlink TDs, wait one frame, delete TDs. 
+	// So, this solutions seems simpler...
+
 	for (n = 0; n < urb->number_of_packets; n++) {
 		dbg("n:%d urb->iso_frame_desc[n].length:%d", n, urb->iso_frame_desc[n].length);
-		if (!urb->iso_frame_desc[n].length) {
-			// allows ISO striping by setting length to zero in iso_descriptor
-			tdm[n] = 0;
-			continue;
-		}
+		if (!urb->iso_frame_desc[n].length)
+			continue;  // allows ISO striping by setting length to zero in iso_descriptor
+
 
 #ifdef ISO_SANITY_CHECK
 		if(urb->iso_frame_desc[n].length > maxsze) {
 
 			err("submit_iso: urb->iso_frame_desc[%d].length(%d)>%d",n , urb->iso_frame_desc[n].length, maxsze);
-			tdm[n] = 0;
 			ret=-EINVAL;		
 		}
 		else
 #endif
-		ret = alloc_td (s, &td, UHCI_PTR_DEPTH);
-
-		if (ret) {
+		if (alloc_td (s, &td, UHCI_PTR_DEPTH)) {
 			int i;	// Cleanup allocated TDs
 
 			for (i = 0; i < n; n++)
@@ -1596,31 +1571,26 @@
 		tdm[n] = td;
 	}
 
-	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;	//| (urb->transfer_flags&USB_DISABLE_SPD?0:TD_CTRL_SPD);
+	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
 
 	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid (urb->pipe);
 
-	
 	// Queue all allocated TDs
 	for (n = 0; n < urb->number_of_packets; n++) {
 		td = tdm[n];
 		if (!td)
 			continue;
 			
-		if (n  == last)
+		if (n  == last) {
 			status |= TD_CTRL_IOC;
+			queue_urb (s, urb);
+		}
 
 		fill_td (td, status, destination | (((urb->iso_frame_desc[n].length - 1) & 0x7ff) << 21),
 			 urb_priv->transfer_buffer_dma + urb->iso_frame_desc[n].offset);
 		list_add_tail (&td->desc_list, &urb_priv->desc_list);
 	
-		if (n == last) {
-			urb->status = -EINPROGRESS;
-			queue_urb (s, urb);
-		}
 		insert_td_horizontal (s, s->iso_td[(urb->start_frame + n) & 1023], td);	// store in iso-tds
-		//uhci_show_td(td);
-
 	}
 
 	kfree (tdm);
@@ -1630,7 +1600,6 @@
       err:
 	__restore_flags(flags);
 	return ret;
-
 }
 /*-------------------------------------------------------------------*/
 // returns: 0 (no transfer queued), urb* (this urb already queued)
@@ -1663,7 +1632,7 @@
 {
 	uhci_t *s;
 	urb_priv_t *urb_priv;
-	int ret = 0;
+	int ret = 0, type;
 	unsigned long flags;
 	urb_t *queued_urb=NULL;
 	int bustime;
@@ -1676,10 +1645,23 @@
 	
 	if (!s->running)
 		return -ENODEV;
-		
+	
+	type = usb_pipetype (urb->pipe);
+
 	if (usb_pipedevice (urb->pipe) == s->rh.devnum)
 		return rh_submit_urb (urb);	/* virtual root hub */
 
+	// Sanity checks
+	if (usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe)) <= 0) {		
+		err("uhci_submit_urb: pipesize for pipe %x is zero", urb->pipe);
+		return -EMSGSIZE;
+	}
+
+	if (urb->transfer_buffer_length < 0 && type != PIPE_ISOCHRONOUS) {
+		err("uhci_submit_urb: Negative transfer length for urb %p", urb);
+		return -EINVAL;
+	}
+
 	usb_inc_dev_use (urb->dev);
 
 	spin_lock_irqsave (&s->urb_list_lock, flags);
@@ -1690,8 +1672,8 @@
 
 		queue_dbg("found bulk urb %p\n", queued_urb);
 
-		if ((usb_pipetype (urb->pipe) != PIPE_BULK) ||
-		    ((usb_pipetype (urb->pipe) == PIPE_BULK) &&
+		if (( type != PIPE_BULK) ||
+		    ((type == PIPE_BULK) &&
 		     (!(urb->transfer_flags & USB_QUEUE_BULK) || !(queued_urb->transfer_flags & USB_QUEUE_BULK)))) {
 			spin_unlock_irqrestore (&s->urb_list_lock, flags);
 			usb_dec_dev_use (urb->dev);
@@ -1711,20 +1693,15 @@
 		return -ENOMEM;
 	}
 
+	memset(urb_priv, 0, sizeof(urb_priv_t));
 	urb->hcpriv = urb_priv;
 	INIT_LIST_HEAD (&urb_priv->desc_list);
-	urb_priv->flags = 0;
+
 	dbg("submit_urb: scheduling %p", urb);
-	urb_priv->next_queued_urb = NULL;
-	urb_priv->prev_queued_urb = NULL;
-	urb_priv->bottom_qh = NULL;
-	urb_priv->next_qh = NULL;
 	
-	if (usb_pipetype (urb->pipe) == PIPE_CONTROL)
+	if (type == PIPE_CONTROL)
 		urb_priv->setup_packet_dma = pci_map_single(s->uhci_pci, urb->setup_packet,
 							    sizeof(devrequest), PCI_DMA_TODEVICE);
-	else
-		urb_priv->setup_packet_dma = 0;
 
 	if (urb->transfer_buffer_length)
 		urb_priv->transfer_buffer_dma = pci_map_single(s->uhci_pci,
@@ -1733,10 +1710,8 @@
 							       usb_pipein(urb->pipe) ?
 							       PCI_DMA_FROMDEVICE :
 							       PCI_DMA_TODEVICE);
-	else
-		urb_priv->transfer_buffer_dma = 0;
 
-	if (usb_pipetype (urb->pipe) == PIPE_BULK) {
+	if (type == PIPE_BULK) {
 	
 		if (queued_urb) {
 			while (((urb_priv_t*)queued_urb->hcpriv)->next_queued_urb)  // find last queued bulk
@@ -1751,7 +1726,7 @@
 	}
 	else {
 		spin_unlock_irqrestore (&s->urb_list_lock, flags);
-		switch (usb_pipetype (urb->pipe)) {
+		switch (type) {
 		case PIPE_ISOCHRONOUS:			
 			if (urb->bandwidth == 0) {      /* not yet checked/allocated */
 				if (urb->number_of_packets <= 0) {
@@ -1760,14 +1735,13 @@
 				}
 
 				bustime = usb_check_bandwidth (urb->dev, urb);
-				if (bustime < 0) {
+				if (bustime < 0) 
 					ret = bustime;
-					break;
+				else {
+					ret = uhci_submit_iso_urb(urb);
+					if (ret == 0)
+						usb_claim_bandwidth (urb->dev, urb, bustime, 1);
 				}
-
-				ret = uhci_submit_iso_urb(urb);
-				if (ret == 0)
-					usb_claim_bandwidth (urb->dev, urb, bustime, 1);
 			} else {        /* bandwidth is already set */
 				ret = uhci_submit_iso_urb(urb);
 			}
@@ -1810,8 +1784,7 @@
 	return 0;
 }
 
-// Checks for URB timeout and removes bandwidth reclamation 
-// if URB idles too long
+// Checks for URB timeout and removes bandwidth reclamation if URB idles too long
 _static void uhci_check_timeouts(uhci_t *s)
 {
 	struct list_head *p,*p2;
@@ -1834,7 +1807,7 @@
 			((hcpriv->started + urb->timeout) < jiffies)) {
 			urb->transfer_flags |= USB_TIMEOUT_KILLED | USB_ASYNC_UNLINK;
 			async_dbg("uhci_check_timeout: timeout for %p",urb);
-			uhci_unlink_urb_async(s, urb);
+			uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
 		}
 #ifdef CONFIG_USB_UHCI_HIGH_BANDWIDTH
 		else if (((type == PIPE_BULK) || (type == PIPE_CONTROL)) &&  
@@ -1973,7 +1946,6 @@
 
 /*-------------------------------------------------------------------------*/
 /* Root Hub INTs are polled by this timer, polling interval 20ms */
-/* This time is also used for URB-timeout checking */
 
 _static int rh_init_int_timer (urb_t *urb)
 {
@@ -2284,7 +2256,7 @@
 			spin_unlock_irqrestore (&s->urb_list_lock, flags);
 			warn("forced removing of queued URB %p due to disconnect",urb);
 			uhci_unlink_urb(urb);
-			urb->dev = NULL; // avoid further processing of this UR
+			urb->dev = NULL; // avoid further processing of this URB
 			spin_lock_irqsave (&s->urb_list_lock, flags);
 			p = s->urb_list.prev;	
 		}
@@ -2325,13 +2297,34 @@
 	uhci_unlink_urb
 };
 
+_static void correct_data_toggles(urb_t *urb)
+{
+	usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe), 
+		       !usb_gettoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe)));
+
+	while(urb) {
+		urb_priv_t *priv=urb->hcpriv;		
+		uhci_desc_t *qh = list_entry (priv->desc_list.next, uhci_desc_t, desc_list);
+		struct list_head *p = qh->vertical.next;
+		uhci_desc_t *td;
+		dbg("URB to correct %p\n", urb);
+	
+		for (; p != &qh->vertical; p = p->next) {
+			td = list_entry (p, uhci_desc_t, vertical);
+			td->hw.td.info^=cpu_to_le32(1<<TD_TOKEN_TOGGLE);
+		}
+		urb=priv->next_queued_urb;
+	}
+}
+
 /* 
  * For IN-control transfers, process_transfer gets a bit more complicated,
  * since there are devices that return less data (eg. strings) than they
  * have announced. This leads to a queue abort due to the short packet,
  * the status stage is not executed. If this happens, the status stage
  * is manually re-executed.
- * mode: 1: regular (unlink QH), 2: QHs already unlinked (for async unlink_urb)
+ * mode: PROCESS_TRANSFER_REGULAR: regular (unlink QH)
+ *       PROCESS_TRANSFER_DONT_UNLINK: QHs already unlinked (for async unlink_urb)
  */
 
 _static int process_transfer (uhci_t *s, urb_t *urb, int mode)
@@ -2356,7 +2349,7 @@
 	 */
 
 	if (urb_priv->flags && 
-		((qh->hw.qh.element == cpu_to_le32(UHCI_PTR_TERM)) ||(!(last_desc->hw.td.status & cpu_to_le32(TD_CTRL_ACTIVE))))) 
+	    ((qh->hw.qh.element == cpu_to_le32(UHCI_PTR_TERM)) || !is_td_active(desc)))
 		goto transfer_finished;
 
 	urb->actual_length=0;
@@ -2364,13 +2357,13 @@
 	for (; p != &qh->vertical; p = p->next) {
 		desc = list_entry (p, uhci_desc_t, vertical);
 
-		if (desc->hw.td.status & cpu_to_le32(TD_CTRL_ACTIVE)) {	// do not process active TDs
-			if (mode==2) // if called from async_unlink
-				uhci_clean_transfer(s, urb, qh, mode);
+		if (is_td_active(desc)) {	// do not process active TDs
+			if (mode == CLEAN_TRANSFER_DELETION_MARK) // if called from async_unlink
+				uhci_clean_transfer(s, urb, qh, CLEAN_TRANSFER_DELETION_MARK);
 			return ret;
 		}
 	
-		actual_length = (le32_to_cpu(desc->hw.td.status) + 1) & 0x7ff;		// extract transfer parameters from TD
+		actual_length = uhci_actual_length(le32_to_cpu(desc->hw.td.status));		// extract transfer parameters from TD
 		maxlength = (((le32_to_cpu(desc->hw.td.info) >> 21) & 0x7ff) + 1) & 0x7ff;
 		status = uhci_map_status (uhci_status_bits (le32_to_cpu(desc->hw.td.status)), usb_pipeout (urb->pipe));
 
@@ -2401,10 +2394,8 @@
 			if ((usb_pipetype (urb->pipe) == PIPE_CONTROL)) {
 				if (uhci_packetid(le32_to_cpu(last_desc->hw.td.info)) == USB_PID_OUT) {
 			
-					qh->hw.qh.element = cpu_to_le32(last_desc->dma_addr);  // re-trigger status stage
+					set_qh_element(qh, last_desc->dma_addr);  // re-trigger status stage
 					dbg("short packet during control transfer, retrigger status stage @ %p",last_desc);
-					//uhci_show_td (desc);
-					//uhci_show_td (last_desc);
 					urb_priv->flags = 1; // mark as short control packet
 					return 0;
 				}
@@ -2421,7 +2412,24 @@
 
 	}
 
-	usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe), !data_toggle);
+	if (usb_pipetype (urb->pipe) == PIPE_BULK ) {  /* toggle correction for short bulk transfers (nonqueued/queued) */
+
+		urb_priv_t *priv=(urb_priv_t*)urb->hcpriv;
+		urb_t *next_queued_urb=priv->next_queued_urb;
+
+		if (next_queued_urb) {
+			urb_priv_t *next_priv=(urb_priv_t*)next_queued_urb->hcpriv;
+			uhci_desc_t *qh = list_entry (next_priv->desc_list.next, uhci_desc_t, desc_list);
+			uhci_desc_t *first_td=list_entry (qh->vertical.next, uhci_desc_t, vertical);
+
+			if (data_toggle == uhci_toggle (le32_to_cpu(first_td->hw.td.info))) {
+				err("process_transfer: fixed toggle");
+				correct_data_toggles(next_queued_urb);
+			}						
+		}
+		else
+			usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), usb_pipeout (urb->pipe), !data_toggle);		
+	}
 
  transfer_finished:
 	
@@ -2454,7 +2462,7 @@
 	{
 		desc = list_entry (p, uhci_desc_t, desc_list);
 
-		if (desc->hw.td.status & cpu_to_le32(TD_CTRL_ACTIVE)) {
+		if (is_td_active(desc)) {
 			// do not process active TDs
 			//dbg("TD ACT Status @%p %08x",desc,le32_to_cpu(desc->hw.td.status));
 			break;
@@ -2466,7 +2474,7 @@
 		}
 		// extract transfer parameters from TD
 
-		actual_length = (le32_to_cpu(desc->hw.td.status) + 1) & 0x7ff;
+		actual_length = uhci_actual_length(le32_to_cpu(desc->hw.td.status));
 		status = uhci_map_status (uhci_status_bits (le32_to_cpu(desc->hw.td.status)), usb_pipeout (urb->pipe));
 
 		// see if EP is stalled
@@ -2523,8 +2531,8 @@
 				mb();
 			}
 			else {
-				uhci_unlink_urb_async(s, urb);
-				desc->hw.td.status &= cpu_to_le32(~TD_CTRL_IOC); // inactivate TD
+				uhci_unlink_urb_async(s, urb, UNLINK_ASYNC_STORE_URB);
+				clr_td_ioc(desc); // inactivate TD
 			}
 		}
 	}
@@ -2532,7 +2540,9 @@
 	return ret;
 }
 
-// mode: 1: force processing, don't unlink tds (already unlinked)
+// mode: PROCESS_ISO_REGULAR: processing only for done TDs, unlink TDs
+// mode: PROCESS_ISO_FORCE: force processing, don't unlink TDs (already unlinked)
+
 _static int process_iso (uhci_t *s, urb_t *urb, int mode)
 {
 	int i;
@@ -2542,7 +2552,7 @@
 	uhci_desc_t *desc = list_entry (urb_priv->desc_list.prev, uhci_desc_t, desc_list);
 
 	dbg("urb contains iso request");
-	if ((desc->hw.td.status & cpu_to_le32(TD_CTRL_ACTIVE)) && !mode)
+	if (is_td_active(desc) && mode==PROCESS_ISO_REGULAR)
 		return -EXDEV;	// last TD not finished
 
 	urb->error_count = 0;
@@ -2555,7 +2565,7 @@
 		desc = list_entry (p, uhci_desc_t, desc_list);
 		
 		//uhci_show_td(desc);
-		if (desc->hw.td.status & cpu_to_le32(TD_CTRL_ACTIVE)) {
+		if (is_td_active(desc)) {
 			// means we have completed the last TD, but not the TDs before
 			desc->hw.td.status &= cpu_to_le32(~TD_CTRL_ACTIVE);
 			dbg("TD still active (%x)- grrr. paranoia!", le32_to_cpu(desc->hw.td.status));
@@ -2566,7 +2576,7 @@
 			goto err;
 		}
 
-		if (!mode)
+		if (mode == PROCESS_ISO_REGULAR)
 			unlink_td (s, desc, 1);
 
 		if (urb->number_of_packets <= i) {
@@ -2575,7 +2585,7 @@
 			goto err;
 		}
 
-		urb->iso_frame_desc[i].actual_length = (le32_to_cpu(desc->hw.td.status) + 1) & 0x7ff;
+		urb->iso_frame_desc[i].actual_length = uhci_actual_length(le32_to_cpu(desc->hw.td.status));
 		urb->iso_frame_desc[i].status = uhci_map_status (uhci_status_bits (le32_to_cpu(desc->hw.td.status)), usb_pipeout (urb->pipe));
 		urb->actual_length += urb->iso_frame_desc[i].actual_length;
 
@@ -2608,16 +2618,16 @@
 
 	switch (usb_pipetype (urb->pipe)) {
 	case PIPE_CONTROL:
-		ret = process_transfer (s, urb, 1);
+		ret = process_transfer (s, urb, CLEAN_TRANSFER_REGULAR);
 		break;
 	case PIPE_BULK:
 		if (!s->avoid_bulk.counter)
-			ret = process_transfer (s, urb, 1);
+			ret = process_transfer (s, urb, CLEAN_TRANSFER_REGULAR);
 		else
 			return 0;
 		break;
 	case PIPE_ISOCHRONOUS:
-		ret = process_iso (s, urb, 0);
+		ret = process_iso (s, urb, PROCESS_ISO_REGULAR);
 		break;
 	case PIPE_INTERRUPT:
 		ret = process_interrupt (s, urb);
@@ -2712,19 +2722,20 @@
 				int was_unlinked = (urb->status == -ENOENT);
 				urb->dev = NULL;
 				spin_unlock(&s->urb_list_lock);
+
 				urb->complete ((struct urb *) urb);
+
 				// Re-submit the URB if ring-linked
 				if (is_ring && !was_unlinked && !contains_killed) {
 					urb->dev=usb_dev;
 					uhci_submit_urb (urb);
-				} else
-					urb = 0;
+
+				}
+				spin_unlock(&urb->lock);		
 				spin_lock(&s->urb_list_lock);
 			}
 			
 			usb_dec_dev_use (usb_dev);
-			if (urb)
-				spin_unlock(&urb->lock);		
 		}
 	}
 
@@ -2752,11 +2763,16 @@
 	dbg("interrupt");
 
 	if (status != 1) {
-		warn("interrupt, status %x, frame# %i", status, 
-		     UHCI_GET_CURRENT_FRAME(s));
-
+		// Avoid too much error messages at a time
+		if ((jiffies - s->last_error_time > ERROR_SUPPRESSION_TIME)) {
+			warn("interrupt, status %x, frame# %i", status, 
+			     UHCI_GET_CURRENT_FRAME(s));
+			s->last_error_time = jiffies;
+		}
+		
 		// remove host controller halted state
 		if ((status&0x20) && (s->running)) {
+			err("Host controller halted, trying to restart.");
 			outw (USBCMD_RS | inw(io_addr + USBCMD), io_addr + USBCMD);
 		}
 		//uhci_show_status (s);
@@ -2799,8 +2815,8 @@
 	if ((jiffies - s->timeout_check) > (HZ/30)) 
 		uhci_check_timeouts(s);
 
-	clean_descs(s,0);
-	uhci_cleanup_unlink(s, 0);
+	clean_descs(s, CLEAN_NOT_FORCED);
+	uhci_cleanup_unlink(s, CLEAN_NOT_FORCED);
 	uhci_switch_timer_int(s);
 							
 	spin_unlock (&s->urb_list_lock);
@@ -2869,8 +2885,8 @@
 	reset_hc (s);
 	wait_ms (1);
 
-	uhci_unlink_urbs (s, 0, 1);  // Forced unlink of remaining URBs
-	uhci_cleanup_unlink (s, 1);  // force cleanup of async killed URBs
+	uhci_unlink_urbs (s, 0, CLEAN_FORCED);  // Forced unlink of remaining URBs
+	uhci_cleanup_unlink (s, CLEAN_FORCED);  // force cleanup of async killed URBs
 	
 	usb_deregister_bus (s->bus);
 
@@ -2943,11 +2959,9 @@
 	spin_lock_init (&s->qh_lock);
 	spin_lock_init (&s->td_lock);
 	atomic_set(&s->avoid_bulk, 0);
-	s->timeout_urbs = 0;	
 	s->irq = -1;
 	s->io_addr = io_addr;
 	s->io_size = io_size;
-	s->timeout_check = 0;
 	s->uhci_pci=dev;
 
 	bus = usb_alloc_bus (&uhci_device_operations);
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/usb-uhci.h linux/drivers/usb/usb-uhci.h
--- v2.4.9/linux/drivers/usb/usb-uhci.h	Mon Aug 27 12:41:45 2001
+++ linux/drivers/usb/usb-uhci.h	Tue Aug 28 11:21:02 2001
@@ -2,7 +2,7 @@
 #define __LINUX_UHCI_H
 
 /*
-   $Id: usb-uhci.h,v 1.55 2000/05/13 12:50:30 acher Exp $
+   $Id: usb-uhci.h,v 1.58 2001/08/28 16:45:00 acher Exp $
  */
 #define MODNAME "usb-uhci"
 #define UHCI_LATENCY_TIMER 0
@@ -218,12 +218,35 @@
 	int timeout_urbs;
 	struct pci_dev *uhci_pci;
 	struct pci_pool *desc_pool;
+	long last_error_time;          // last error output in uhci_interrupt()
 } uhci_t, *puhci_t;
 
 
 #define MAKE_TD_ADDR(a) ((a)->dma_addr&~UHCI_PTR_QH)
 #define MAKE_QH_ADDR(a) ((a)->dma_addr|UHCI_PTR_QH)
 #define UHCI_GET_CURRENT_FRAME(uhci) (inw ((uhci)->io_addr + USBFRNUM))
+
+#define CLEAN_TRANSFER_NO_DELETION 0
+#define CLEAN_TRANSFER_REGULAR 1
+#define CLEAN_TRANSFER_DELETION_MARK 2
+
+#define CLEAN_NOT_FORCED 0
+#define CLEAN_FORCED 1
+
+#define PROCESS_ISO_REGULAR 0
+#define PROCESS_ISO_FORCE 1
+
+#define UNLINK_ASYNC_STORE_URB 0
+#define UNLINK_ASYNC_DONT_STORE 1
+
+#define is_td_active(desc) (desc->hw.td.status & cpu_to_le32(TD_CTRL_ACTIVE))
+
+#define set_qh_head(desc,val) (desc)->hw.qh.head=cpu_to_le32(val)
+#define set_qh_element(desc,val) (desc)->hw.qh.element=cpu_to_le32(val)
+#define set_td_link(desc,val) (desc)->hw.td.link=cpu_to_le32(val)
+#define set_td_ioc(desc) (desc)->hw.td.status |= cpu_to_le32(TD_CTRL_IOC)
+#define clr_td_ioc(desc) (desc)->hw.td.status &= cpu_to_le32(~TD_CTRL_IOC)
+
 
 /* ------------------------------------------------------------------------------------ 
    Virtual Root HUB 
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
--- v2.4.9/linux/drivers/usb/usb.c	Sun Aug 12 13:28:00 2001
+++ linux/drivers/usb/usb.c	Tue Aug 28 11:22:21 2001
@@ -459,7 +459,7 @@
 	list_del(&bus->bus_list);
 	write_unlock_irq (&usb_bus_list_lock);
 
-       usbdevfs_remove_bus(bus);
+	usbdevfs_remove_bus(bus);
 
 	clear_bit(bus->busnum, busmap.busmap);
 
@@ -707,7 +707,6 @@
 
 	private = NULL;
 	for (tmp = usb_driver_list.next; tmp != &usb_driver_list;) {
-
 		driver = list_entry(tmp, struct usb_driver, driver_list);
 		tmp = tmp->next;
 
@@ -725,17 +724,19 @@
 						break;
 				}
 			}
+
 			/* if driver not bound, leave defaults unchanged */
 			if (private == NULL)
 				interface->act_altsetting = 0;
-		}
-		else /* "old style" driver */
-		{
+		} else { /* "old style" driver */
 			down(&driver->serialize);
 			private = driver->probe(dev, ifnum, NULL);
 			up(&driver->serialize);
 		}
 
+		/* probe() may have changed the config on us */
+		interface = dev->actconfig->interface + ifnum;
+
 		if (private) {
 			usb_driver_claim_interface(driver, interface, private);
 			up(&dev->serialize);
@@ -1178,7 +1179,7 @@
  *	@pipe: endpoint "pipe" to send the message to
  *	@data: pointer to the data to send
  *	@len: length in bytes of the data to send
- *	@actual_length: pointer to a location to put the actual length transfered in bytes
+ *	@actual_length: pointer to a location to put the actual length transferred in bytes
  *	@timeout: time to wait for the message to complete before timing out (if 0 the wait is forever)
  *
  *	This function sends a simple bulk message to a specified endpoint
@@ -1222,7 +1223,7 @@
 }
 /*-------------------------------------------------------------------*/
 
-static int usb_parse_endpoint(struct usb_device *dev, struct usb_endpoint_descriptor *endpoint, unsigned char *buffer, int size)
+static int usb_parse_endpoint(struct usb_endpoint_descriptor *endpoint, unsigned char *buffer, int size)
 {
 	struct usb_descriptor_header *header;
 	unsigned char *begin;
@@ -1266,8 +1267,7 @@
 			return -1;
 		}
 
-		/* If we find another descriptor which is at or below us */
-		/*  in the descriptor heirarchy then we're done  */
+		/* If we find another "proper" descriptor then we're done  */
 		if ((header->bDescriptorType == USB_DT_ENDPOINT) ||
 		    (header->bDescriptorType == USB_DT_INTERFACE) ||
 		    (header->bDescriptorType == USB_DT_CONFIG) ||
@@ -1308,7 +1308,7 @@
 	return parsed;
 }
 
-static int usb_parse_interface(struct usb_device *dev, struct usb_interface *interface, unsigned char *buffer, int size)
+static int usb_parse_interface(struct usb_interface *interface, unsigned char *buffer, int size)
 {
 	int i, len, numskipped, retval, parsed = 0;
 	struct usb_descriptor_header *header;
@@ -1373,8 +1373,7 @@
 				return -1;
 			}
 
-			/* If we find another descriptor which is at or below */
-			/*  us in the descriptor heirarchy then return */
+			/* If we find another "proper" descriptor then we're done  */
 			if ((header->bDescriptorType == USB_DT_INTERFACE) ||
 			    (header->bDescriptorType == USB_DT_ENDPOINT) ||
 			    (header->bDescriptorType == USB_DT_CONFIG) ||
@@ -1440,7 +1439,7 @@
 				return -1;
 			}
 		
-			retval = usb_parse_endpoint(dev, ifp->endpoint + i, buffer, size);
+			retval = usb_parse_endpoint(ifp->endpoint + i, buffer, size);
 			if (retval < 0)
 				return retval;
 
@@ -1460,7 +1459,7 @@
 	return parsed;
 }
 
-int usb_parse_configuration(struct usb_device *dev, struct usb_config_descriptor *config, char *buffer)
+int usb_parse_configuration(struct usb_config_descriptor *config, char *buffer)
 {
 	int i, retval, size;
 	struct usb_descriptor_header *header;
@@ -1489,6 +1488,9 @@
 	buffer += config->bLength;
 	size -= config->bLength;
 	
+	config->extra = NULL;
+	config->extralen = 0;
+
 	for (i = 0; i < config->bNumInterfaces; i++) {
 		int numskipped, len;
 		char *begin;
@@ -1505,8 +1507,7 @@
 				return -1;
 			}
 
-			/* If we find another descriptor which is at or below */
-			/*  us in the descriptor heirarchy then we're done  */
+			/* If we find another "proper" descriptor then we're done  */
 			if ((header->bDescriptorType == USB_DT_ENDPOINT) ||
 			    (header->bDescriptorType == USB_DT_INTERFACE) ||
 			    (header->bDescriptorType == USB_DT_CONFIG) ||
@@ -1525,22 +1526,23 @@
 		/* Copy any unknown descriptors into a storage area for */
 		/*  drivers to later parse */
 		len = (int)(buffer - begin);
-		if (!len) {
-			config->extra = NULL;
-			config->extralen = 0;
-		} else {
-			config->extra = kmalloc(len, GFP_KERNEL);
-			if (!config->extra) {
-				err("couldn't allocate memory for config extra descriptors");
-				config->extralen = 0;
-				return -1;
-			}
+		if (len) {
+			if (config->extralen) {
+				warn("extra config descriptor");
+			} else {
+				config->extra = kmalloc(len, GFP_KERNEL);
+				if (!config->extra) {
+					err("couldn't allocate memory for config extra descriptors");
+					config->extralen = 0;
+					return -1;
+				}
 
-			memcpy(config->extra, begin, len);
-			config->extralen = len;
+				memcpy(config->extra, begin, len);
+				config->extralen = len;
+			}
 		}
 
-		retval = usb_parse_interface(dev, config->interface + i, buffer, size);
+		retval = usb_parse_interface(config->interface + i, buffer, size);
 		if (retval < 0)
 			return retval;
 
@@ -2081,7 +2083,7 @@
 
 		dev->rawdescriptors[cfgno] = bigbuffer;
 
-		result = usb_parse_configuration(dev, &dev->config[cfgno], bigbuffer);
+		result = usb_parse_configuration(&dev->config[cfgno], bigbuffer);
 		if (result > 0)
 			dbg("descriptor data left");
 		else if (result < 0) {
diff -u --recursive --new-file v2.4.9/linux/drivers/usb/usbnet.c linux/drivers/usb/usbnet.c
--- v2.4.9/linux/drivers/usb/usbnet.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/usbnet.c	Tue Aug 28 11:21:02 2001
@@ -0,0 +1,1567 @@
+/*
+ * USB Host-to-Host Links
+ * Copyright (C) 2000-2001 by David Brownell <dbrownell@users.sourceforge.net>
+ */
+
+/*
+ * This is used for "USB networking", connecting USB hosts as peers.
+ *
+ * It can be used with USB "network cables", for IP-over-USB communications;
+ * Ethernet speeds without the Ethernet.  USB devices (including some PDAs)
+ * can support such links directly, replacing device-specific protocols
+ * with Internet standard ones.
+ *
+ * The links can be bridged using the Ethernet bridging (net/bridge)
+ * support as appropriate.  Devices currently supported include:
+ *
+ *	- AnchorChip 2720
+ *	- Belkin F5U104 (custom)
+ *	- "Linux Devices" (like iPaq and similar SA-1100 based PDAs)
+ *	- NetChip 1080 (interoperates with NetChip Win32 drivers)
+ *	- Prolific PL-2301/2302 (replaces "plusb" driver)
+ *
+ * USB devices can implement their side of this protocol at the cost
+ * of two bulk endpoints; it's not restricted to "cable" applications.
+ * See the LINUXDEV support.
+ *
+ * 
+ * TODO:
+ *
+ * This needs to be retested for bulk queuing problems ... earlier versions
+ * seemed to find different types of problems in each HCD.  Once they're fixed,
+ * re-enable queues to get higher bandwidth utilization (without needing
+ * to tweak MTU for larger packets).
+ *
+ * Add support for more "network cable" chips; interop with their Win32
+ * drivers may be a good thing.  Test the AnchorChip 2720 support..
+ * Figure out the initialization protocol used by the Prolific chips,
+ * for better robustness ... there's some powerup/reset handshake that's
+ * needed when only one end reboots.
+ *
+ * Use interrupt on PL230x to detect peer connect/disconnect, and call
+ * netif_carrier_{on,off} (?) appropriately.  For Net1080, detect peer
+ * connect/disconnect with async control messages.
+ *
+ * Find some way to report "peer connected" network hotplug events; it'll
+ * likely mean updating the networking layer.  (This has been discussed
+ * on the netdev list...)
+ *
+ * Craft smarter hotplug policy scripts ... ones that know how to arrange
+ * bridging with "brctl", and can handle static and dynamic ("pump") setups.
+ * Use those "peer connected" events.
+ *
+ *
+ * CHANGELOG:
+ *
+ * 13-sep-2000	experimental, new
+ * 10-oct-2000	usb_device_id table created. 
+ * 28-oct-2000	misc fixes; mostly, discard more TTL-mangled rx packets.
+ * 01-nov-2000	usb_device_id table and probing api update by
+ *		Adam J. Richter <adam@yggdrasil.com>.
+ * 18-dec-2000	(db) tx watchdog, "net1080" renaming to "usbnet", device_info
+ *		and prolific support, isolate net1080-specific bits, cleanup.
+ *		fix unlink_urbs oops in D3 PM resume code path.
+ * 02-feb-2001	(db) fix tx skb sharing, packet length, match_flags, ...
+ * 08-feb-2001	stubbed in "linuxdev", maybe the SA-1100 folk can use it;
+ *		AnchorChips 2720 support (from spec) for testing;
+ *		fix bit-ordering problem with ethernet multicast addr
+ * 19-feb-2001  Support for clearing halt conditions. SA1100 UDC support
+ *		updates. Oleg Drokin (green@iXcelerator.com)
+ * 25-mar-2001	More SA-1100 updates, including workaround for ip problem
+ *		expecting cleared skb->cb and framing change to match latest
+ *		handhelds.org version (Oleg).  Enable device IDs from the
+ *		Win32 Belkin driver; other cleanups (db).
+ * 16-jul-2001	Bugfixes for uhci oops-on-unplug, Belkin support, various
+ *		cleanups for problems not yet seen in the field. (db)
+ *
+ *-------------------------------------------------------------------------*/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/random.h>
+#include <asm/unaligned.h>
+
+// #define	DEBUG			// error path messages, extra info
+// #define	VERBOSE			// more; success messages
+// #define	REALLY_QUEUE
+
+#if !defined (DEBUG) && defined (CONFIG_USB_DEBUG)
+#   define DEBUG
+#endif
+#include <linux/usb.h>
+
+
+#define	CONFIG_USB_AN2720
+#define	CONFIG_USB_BELKIN_F5U104
+#define	CONFIG_USB_LINUXDEV
+#define	CONFIG_USB_NET1080
+#define	CONFIG_USB_PL2301
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Nineteen USB 1.1 max size bulk transactions per frame (ms), max.
+ * Several dozen bytes of IPv4 data can fit in two such transactions.
+ * One maximum size Ethernet packet takes twenty four of them.
+ */
+#ifdef REALLY_QUEUE
+#define	RX_QLEN		4
+#define	TX_QLEN		4
+#else
+#define	RX_QLEN		1
+#define	TX_QLEN		1
+#endif
+
+// packets are always ethernet inside
+// ... except they can be bigger (up to 64K with this framing)
+#define MIN_PACKET	sizeof(struct ethhdr)
+#define MAX_PACKET	32768
+
+// reawaken network queue this soon after stopping; else watchdog barks
+#define TX_TIMEOUT_JIFFIES	(5*HZ)
+
+// for vendor-specific control operations
+#define	CONTROL_TIMEOUT_MS	(500)			/* msec */
+#define CONTROL_TIMEOUT_JIFFIES ((CONTROL_TIMEOUT_MS * HZ)/1000)
+
+// between wakeups
+#define UNLINK_TIMEOUT_JIFFIES ((3  /*ms*/ * HZ)/1000)
+
+/*-------------------------------------------------------------------------*/
+
+// list of all devices we manage
+static DECLARE_MUTEX (usbnet_mutex);
+static LIST_HEAD (usbnet_list);
+
+// randomly generated ethernet address
+static u8	node_id [ETH_ALEN];
+
+// state we keep for each device we handle
+struct usbnet {
+	// housekeeping
+	struct usb_device	*udev;
+	struct driver_info	*driver_info;
+	struct semaphore	mutex;
+	struct list_head	dev_list;
+	wait_queue_head_t	*wait;
+
+	// protocol/interface state
+	struct net_device	net;
+	struct net_device_stats	stats;
+	u16			packet_id;
+
+	// various kinds of pending driver work
+	struct sk_buff_head	rxq;
+	struct sk_buff_head	txq;
+	struct sk_buff_head	done;
+	struct tasklet_struct	bh;
+	struct tq_struct ctrl_task;
+};
+
+// device-specific info used by the driver
+struct driver_info {
+	char		*description;
+
+	int		flags;
+#define FLAG_FRAMING	0x0001		/* guard against device dropouts */ 
+
+	/* reset device ... can sleep */
+	int	(*reset)(struct usbnet *);
+
+	/* see if peer is connected ... can sleep */
+	int	(*check_connect)(struct usbnet *);
+
+	// FIXME -- also an interrupt mechanism
+
+	/* framework currently "knows" bulk EPs talk packets */
+	int		in;		/* rx endpoint */
+	int		out;		/* tx endpoint */
+	int		epsize;
+};
+
+#define EP_SIZE(usbnet)	((usbnet)->driver_info->epsize)
+
+// we record the state for each of our queued skbs
+enum skb_state {
+	illegal = 0,
+	tx_start, tx_done,
+	rx_start, rx_done, rx_cleanup
+};
+
+struct skb_data {	// skb->cb is one of these
+	struct urb		*urb;
+	struct usbnet		*dev;
+	enum skb_state		state;
+	size_t			length;
+};
+
+
+#define	mutex_lock(x)	down(x)
+#define	mutex_unlock(x)	up(x)
+
+#define	RUN_CONTEXT (in_irq () ? "in_irq" \
+			: (in_interrupt () ? "in_interrupt" : "can sleep"))
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+#define devdbg(usbnet, fmt, arg...) \
+	printk(KERN_DEBUG "%s: " fmt "\n" , (usbnet)->net.name, ## arg)
+#else
+#define devdbg(usbnet, fmt, arg...) do {} while(0)
+#endif
+
+#define devinfo(usbnet, fmt, arg...) \
+	printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net.name, ## arg)
+
+/*-------------------------------------------------------------------------
+ *
+ * NetChip framing of ethernet packets, supporting additional error
+ * checks for links that may drop bulk packets from inside messages.
+ * Odd USB length == always short read for last usb packet.
+ *	- nc_header
+ *	- Ethernet header (14 bytes)
+ *	- payload
+ *	- (optional padding byte, if needed so length becomes odd)
+ *	- nc_trailer
+ *
+ * This framing is to be avoided for non-NetChip devices.
+ */
+
+struct nc_header {		// packed:
+	u16	hdr_len;		// sizeof nc_header (LE, all)
+	u16	packet_len;		// payload size (including ethhdr)
+	u16	packet_id;		// detects dropped packets
+#define MIN_HEADER	6
+
+	// all else is optional, and must start with:
+	// u16	vendorId;		// from usb-if
+	// u16	productId;
+} __attribute__((__packed__));
+
+#define	PAD_BYTE	((unsigned char)0xAC)
+
+struct nc_trailer {
+	u16	packet_id;
+} __attribute__((__packed__));
+
+// packets may use FLAG_FRAMING and optional pad
+#define FRAMED_SIZE(mtu) (sizeof (struct nc_header) \
+				+ sizeof (struct ethhdr) \
+				+ (mtu) \
+				+ 1 \
+				+ sizeof (struct nc_trailer))
+
+#define MIN_FRAMED	FRAMED_SIZE(0)
+
+
+
+#ifdef	CONFIG_USB_AN2720
+
+/*-------------------------------------------------------------------------
+ *
+ * AnchorChips 2720 driver ... http://www.cypress.com
+ *
+ * This doesn't seem to have a way to detect whether the peer is
+ * connected, or need any reset handshaking.  It's got pretty big
+ * internal buffers (handles most of a frame's worth of data).
+ * Chip data sheets don't describe any vendor control messages.
+ *
+ *-------------------------------------------------------------------------*/
+
+static const struct driver_info	an2720_info = {
+	description:	"AnchorChips/Cypress 2720",
+	// no reset available!
+	// no check_connect available!
+
+	in: 2, out: 2,		// direction distinguishes these
+	epsize:	64,
+};
+
+#endif	/* CONFIG_USB_AN2720 */
+
+
+
+#ifdef	CONFIG_USB_BELKIN_F5U104
+
+/*-------------------------------------------------------------------------
+ *
+ * Belkin F5U104 ... two NetChip 2280 devices + Atmel microcontroller
+ *
+ *-------------------------------------------------------------------------*/
+
+static const struct driver_info	belkin_info = {
+	description:	"Belkin USB Direct Connect (F5U104)",
+
+	in: 1, out: 1,		// direction distinguishes these
+	epsize:	64,
+};
+
+#endif	/* CONFIG_USB_BELKIN_F5U104 */
+
+
+
+#ifdef	CONFIG_USB_LINUXDEV
+
+/*-------------------------------------------------------------------------
+ *
+ * This could talk to a device that uses Linux, such as a PDA or
+ * an embedded system, or in fact to any "smart" device using this
+ * particular mapping of USB and Ethernet.
+ *
+ * Such a Linux host would need a "USB Device Controller" hardware
+ * (not "USB Host Controller"), and a network driver talking to that
+ * hardware.
+ *
+ * One example is Intel's SA-1100 chip, which integrates basic USB
+ * support (arch/arm/sa1100/usb-eth.c); it's used in the iPaq PDA.
+ *
+ *-------------------------------------------------------------------------*/
+
+
+static const struct driver_info	linuxdev_info = {
+	description:	"Linux Device",
+	// no reset defined (yet?)
+	// no check_connect needed!
+	in: 2, out: 1,
+	epsize:	64,
+};
+
+#endif	/* CONFIG_USB_LINUXDEV */
+
+
+
+#ifdef	CONFIG_USB_NET1080
+
+/*-------------------------------------------------------------------------
+ *
+ * Netchip 1080 driver ... http://www.netchip.com
+ *
+ *-------------------------------------------------------------------------*/
+
+/*
+ * Zero means no timeout; else, how long a 64 byte bulk packet may be queued
+ * before the hardware drops it.  If that's done, the driver will need to
+ * frame network packets to guard against the dropped USB packets.  The win32
+ * driver sets this for both sides of the link.
+ */
+#define	NC_READ_TTL_MS	((u8)255)	// ms
+
+/*
+ * We ignore most registers and EEPROM contents.
+ */
+#define	REG_USBCTL	((u8)0x04)
+#define REG_TTL		((u8)0x10)
+#define REG_STATUS	((u8)0x11)
+
+/*
+ * Vendor specific requests to read/write data
+ */
+#define	REQUEST_REGISTER	((u8)0x10)
+#define	REQUEST_EEPROM		((u8)0x11)
+
+static int
+nc_vendor_read (struct usbnet *dev, u8 req, u8 regnum, u16 *retval_ptr)
+{
+	int status = usb_control_msg (dev->udev,
+		usb_rcvctrlpipe (dev->udev, 0),
+		req,
+		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		0, regnum,
+		retval_ptr, sizeof *retval_ptr,
+		CONTROL_TIMEOUT_JIFFIES);
+	if (status > 0)
+		status = 0;
+	if (!status)
+		le16_to_cpus (retval_ptr);
+	return status;
+}
+
+static inline int
+nc_register_read (struct usbnet *dev, u8 regnum, u16 *retval_ptr)
+{
+	return nc_vendor_read (dev, REQUEST_REGISTER, regnum, retval_ptr);
+}
+
+// no retval ... can become async, usable in_interrupt()
+static void
+nc_vendor_write (struct usbnet *dev, u8 req, u8 regnum, u16 value)
+{
+	usb_control_msg (dev->udev,
+		usb_sndctrlpipe (dev->udev, 0),
+		req,
+		USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		value, regnum,
+		0, 0,			// data is in setup packet
+		CONTROL_TIMEOUT_JIFFIES);
+}
+
+static inline void
+nc_register_write (struct usbnet *dev, u8 regnum, u16 value)
+{
+	nc_vendor_write (dev, REQUEST_REGISTER, regnum, value);
+}
+
+
+#if 0
+static void nc_dump_registers (struct usbnet *dev)
+{
+	u8	reg;
+	u16	*vp = kmalloc (sizeof (u16));
+
+	if (!vp) {
+		dbg ("no memory?");
+		return;
+	}
+
+	dbg ("%s registers:", dev->net.name);
+	for (reg = 0; reg < 0x20; reg++) {
+		int retval;
+
+		// reading some registers is trouble
+		if (reg >= 0x08 && reg <= 0xf)
+			continue;
+		if (reg >= 0x12 && reg <= 0x1e)
+			continue;
+
+		retval = nc_register_read (dev, reg, vp);
+		if (retval < 0)
+			dbg ("%s reg [0x%x] ==> error %d",
+				dev->net.name, reg, retval);
+		else
+			dbg ("%s reg [0x%x] = 0x%x",
+				dev->net.name, reg, *vp);
+	}
+	kfree (vp);
+}
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Control register
+ */
+
+#define	USBCTL_WRITABLE_MASK	0x1f0f
+// bits 15-13 reserved, r/o
+#define	USBCTL_ENABLE_LANG	(1 << 12)
+#define	USBCTL_ENABLE_MFGR	(1 << 11)
+#define	USBCTL_ENABLE_PROD	(1 << 10)
+#define	USBCTL_ENABLE_SERIAL	(1 << 9)
+#define	USBCTL_ENABLE_DEFAULTS	(1 << 8)
+// bits 7-4 reserved, r/o
+#define	USBCTL_FLUSH_OTHER	(1 << 3)
+#define	USBCTL_FLUSH_THIS	(1 << 2)
+#define	USBCTL_DISCONN_OTHER	(1 << 1)
+#define	USBCTL_DISCONN_THIS	(1 << 0)
+
+static inline void nc_dump_usbctl (struct usbnet *dev, u16 usbctl)
+{
+#ifdef DEBUG
+	devdbg (dev, "net1080 %03d/%03d usbctl 0x%x:%s%s%s%s%s;"
+			" this%s%s;"
+			" other%s%s; r/o 0x%x",
+		dev->udev->bus->busnum, dev->udev->devnum,
+		usbctl,
+		(usbctl & USBCTL_ENABLE_LANG) ? " lang" : "",
+		(usbctl & USBCTL_ENABLE_MFGR) ? " mfgr" : "",
+		(usbctl & USBCTL_ENABLE_PROD) ? " prod" : "",
+		(usbctl & USBCTL_ENABLE_SERIAL) ? " serial" : "",
+		(usbctl & USBCTL_ENABLE_DEFAULTS) ? " defaults" : "",
+
+		(usbctl & USBCTL_FLUSH_OTHER) ? " FLUSH" : "",
+		(usbctl & USBCTL_DISCONN_OTHER) ? " DIS" : "",
+		(usbctl & USBCTL_FLUSH_THIS) ? " FLUSH" : "",
+		(usbctl & USBCTL_DISCONN_THIS) ? " DIS" : "",
+		usbctl & ~USBCTL_WRITABLE_MASK
+		);
+#endif
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Status register
+ */
+
+#define	STATUS_PORT_A		(1 << 15)
+
+#define	STATUS_CONN_OTHER	(1 << 14)
+#define	STATUS_SUSPEND_OTHER	(1 << 13)
+#define	STATUS_MAILBOX_OTHER	(1 << 12)
+#define	STATUS_PACKETS_OTHER(n)	(((n) >> 8) && 0x03)
+
+#define	STATUS_CONN_THIS	(1 << 6)
+#define	STATUS_SUSPEND_THIS	(1 << 5)
+#define	STATUS_MAILBOX_THIS	(1 << 4)
+#define	STATUS_PACKETS_THIS(n)	(((n) >> 0) && 0x03)
+
+#define	STATUS_UNSPEC_MASK	0x0c8c
+#define	STATUS_NOISE_MASK 	((u16)~(0x0303|STATUS_UNSPEC_MASK))
+
+
+static inline void nc_dump_status (struct usbnet *dev, u16 status)
+{
+#ifdef DEBUG
+	devdbg (dev, "net1080 %03d/%03d status 0x%x:"
+			" this (%c) PKT=%d%s%s%s;"
+			" other PKT=%d%s%s%s; unspec 0x%x",
+		dev->udev->bus->busnum, dev->udev->devnum,
+		status,
+
+		// XXX the packet counts don't seem right
+		// (1 at reset, not 0); maybe UNSPEC too
+
+		(status & STATUS_PORT_A) ? 'A' : 'B',
+		STATUS_PACKETS_THIS (status),
+		(status & STATUS_CONN_THIS) ? " CON" : "",
+		(status & STATUS_SUSPEND_THIS) ? " SUS" : "",
+		(status & STATUS_MAILBOX_THIS) ? " MBOX" : "",
+
+		STATUS_PACKETS_OTHER (status),
+		(status & STATUS_CONN_OTHER) ? " CON" : "",
+		(status & STATUS_SUSPEND_OTHER) ? " SUS" : "",
+		(status & STATUS_MAILBOX_OTHER) ? " MBOX" : "",
+
+		status & STATUS_UNSPEC_MASK
+		);
+#endif
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * TTL register
+ */
+
+#define	TTL_THIS(ttl)	(0x00ff & ttl)
+#define	TTL_OTHER(ttl)	(0x00ff & (ttl >> 8))
+#define MK_TTL(this,other)	((u16)(((other)<<8)|(0x00ff&(this))))
+
+static inline void nc_dump_ttl (struct usbnet *dev, u16 ttl)
+{
+#ifdef DEBUG
+	devdbg (dev, "net1080 %03d/%03d ttl 0x%x this = %d, other = %d",
+		dev->udev->bus->busnum, dev->udev->devnum,
+		ttl,
+
+		TTL_THIS (ttl),
+		TTL_OTHER (ttl)
+		);
+#endif
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int net1080_reset (struct usbnet *dev)
+{
+	u16		usbctl, status, ttl;
+	u16		*vp = kmalloc (sizeof (u16), GFP_KERNEL);
+	int		retval;
+
+	if (!vp)
+		return -ENOMEM;
+
+	// nc_dump_registers (dev);
+
+	if ((retval = nc_register_read (dev, REG_STATUS, vp)) < 0) {
+		dbg ("can't read dev %d status: %d", dev->udev->devnum, retval);
+		goto done;
+	}
+	status = *vp;
+	// nc_dump_status (dev, status);
+
+	if ((retval = nc_register_read (dev, REG_USBCTL, vp)) < 0) {
+		dbg ("can't read USBCTL, %d", retval);
+		goto done;
+	}
+	usbctl = *vp;
+	// nc_dump_usbctl (dev, usbctl);
+
+	nc_register_write (dev, REG_USBCTL,
+			USBCTL_FLUSH_THIS | USBCTL_FLUSH_OTHER);
+
+	if ((retval = nc_register_read (dev, REG_TTL, vp)) < 0) {
+		dbg ("can't read TTL, %d", retval);
+		goto done;
+	}
+	ttl = *vp;
+	// nc_dump_ttl (dev, ttl);
+
+	nc_register_write (dev, REG_TTL,
+			MK_TTL (NC_READ_TTL_MS, TTL_OTHER (ttl)) );
+	dbg ("%s: assigned TTL, %d ms", dev->net.name, NC_READ_TTL_MS);
+
+	devdbg (dev, "port %c, peer %sconnected",
+		(status & STATUS_PORT_A) ? 'A' : 'B',
+		(status & STATUS_CONN_OTHER) ? "" : "dis"
+		);
+	retval = 0;
+
+done:
+	kfree (vp);
+	return retval;
+}
+
+static int net1080_check_connect (struct usbnet *dev)
+{
+	int			retval;
+	u16			status;
+	u16			*vp = kmalloc (sizeof (u16), GFP_KERNEL);
+
+	if (!vp)
+		return -ENOMEM;
+	retval = nc_register_read (dev, REG_STATUS, vp);
+	status = *vp;
+	kfree (vp);
+	if (retval != 0) {
+		dbg ("%s net1080_check_conn read - %d", dev->net.name, retval);
+		return retval;
+	}
+	if ((status & STATUS_CONN_OTHER) != STATUS_CONN_OTHER)
+		return -ENOLINK;
+	return 0;
+}
+
+static const struct driver_info	net1080_info = {
+	description:	"NetChip TurboCONNECT",
+	flags:		FLAG_FRAMING,
+	reset:		net1080_reset,
+	check_connect:	net1080_check_connect,
+
+	in: 1, out: 1,		// direction distinguishes these
+	epsize:	64,
+};
+
+#endif /* CONFIG_USB_NET1080 */
+
+
+
+#ifdef CONFIG_USB_PL2301
+
+/*-------------------------------------------------------------------------
+ *
+ * Prolific PL-2301/PL-2302 driver ... http://www.prolifictech.com
+ *
+ *-------------------------------------------------------------------------*/
+
+/*
+ * Bits 0-4 can be used for software handshaking; they're set from
+ * one end, cleared from the other, "read" with the interrupt byte.
+ */
+#define	PL_S_EN		(1<<7)		/* (feature only) suspend enable */
+/* reserved bit -- rx ready (6) ? */
+#define	PL_TX_READY	(1<<5)		/* (interrupt only) transmit ready */
+#define	PL_RESET_OUT	(1<<4)		/* reset output pipe */
+#define	PL_RESET_IN	(1<<3)		/* reset input pipe */
+#define	PL_TX_C		(1<<2)		/* transmission complete */
+#define	PL_TX_REQ	(1<<1)		/* transmission received */
+#define	PL_PEER_E	(1<<0)		/* peer exists */
+
+static inline int
+pl_vendor_req (struct usbnet *dev, u8 req, u8 val, u8 index)
+{
+	return usb_control_msg (dev->udev,
+		usb_rcvctrlpipe (dev->udev, 0),
+		req,
+		USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+		val, index,
+		0, 0,
+		CONTROL_TIMEOUT_JIFFIES);
+}
+
+static inline int
+pl_clear_QuickLink_features (struct usbnet *dev, int val)
+{
+	return pl_vendor_req (dev, 1, (u8) val, 0);
+}
+
+static inline int
+pl_set_QuickLink_features (struct usbnet *dev, int val)
+{
+	return pl_vendor_req (dev, 3, (u8) val, 0);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int pl_reset (struct usbnet *dev)
+{
+	return pl_set_QuickLink_features (dev,
+		PL_S_EN|PL_RESET_OUT|PL_RESET_IN|PL_PEER_E);
+}
+
+static int pl_check_connect (struct usbnet *dev)
+{
+	// FIXME test interrupt data PL_PEER_E bit
+	// plus, there's some handshake done by
+	// the prolific win32 driver... 
+	dbg ("%s: assuming peer is connected", dev->net.name);
+	return 0;
+}
+
+static const struct driver_info	prolific_info = {
+	description:	"Prolific PL-2301/PL-2302",
+	reset:		pl_reset,
+	check_connect:	pl_check_connect,
+
+	in: 3, out: 2,
+	epsize:	64,
+};
+
+#endif /* CONFIG_USB_PL2301 */
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * Network Device Driver (peer link to "Host Device", from USB host)
+ *
+ *-------------------------------------------------------------------------*/
+
+static int usbnet_change_mtu (struct net_device *net, int new_mtu)
+{
+	struct usbnet	*dev = (struct usbnet *) net->priv;
+
+	if (new_mtu <= sizeof (struct ethhdr) || new_mtu > MAX_PACKET)
+		return -EINVAL;
+	if (((dev->driver_info->flags) & FLAG_FRAMING)) {
+		if (FRAMED_SIZE (new_mtu) > MAX_PACKET)
+			return -EINVAL;
+	// no second zero-length packet read wanted after mtu-sized packets
+	} else if (((new_mtu + sizeof (struct ethhdr)) % EP_SIZE (dev)) == 0)
+		return -EDOM;
+	net->mtu = new_mtu;
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct net_device_stats *usbnet_get_stats (struct net_device *net)
+{
+	return &((struct usbnet *) net->priv)->stats;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* urb completions are currently in_irq; avoid doing real work then. */
+
+static void defer_bh (struct usbnet *dev, struct sk_buff *skb)
+{
+	struct sk_buff_head	*list = skb->list;
+	unsigned long		flags;
+
+	spin_lock_irqsave (&list->lock, flags);
+	__skb_unlink (skb, list);
+	spin_unlock (&list->lock);
+	spin_lock (&dev->done.lock);
+	__skb_queue_tail (&dev->done, skb);
+	if (dev->done.qlen == 1)
+		tasklet_schedule (&dev->bh);
+	spin_unlock_irqrestore (&dev->done.lock, flags);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void rx_complete (struct urb *urb);
+
+static void rx_submit (struct usbnet *dev, struct urb *urb, int flags)
+{
+	struct sk_buff		*skb;
+	struct skb_data		*entry;
+	int			retval = 0;
+	unsigned long		lockflags;
+	size_t			size;
+
+	size = (dev->driver_info->flags & FLAG_FRAMING)
+			? FRAMED_SIZE (dev->net.mtu)
+			: (sizeof (struct ethhdr) + dev->net.mtu);
+	if ((skb = alloc_skb (size, flags)) == 0) {
+		dbg ("no rx skb");
+		tasklet_schedule (&dev->bh);
+		usb_free_urb (urb);
+		return;
+	}
+
+	entry = (struct skb_data *) skb->cb;
+	entry->urb = urb;
+	entry->dev = dev;
+	entry->state = rx_start;
+	entry->length = 0;
+
+	FILL_BULK_URB (urb, dev->udev,
+		usb_rcvbulkpipe (dev->udev, dev->driver_info->in),
+		skb->data, size, rx_complete, skb);
+#ifdef	REALLY_QUEUE
+	urb->transfer_flags |= USB_QUEUE_BULK;
+#endif
+
+	spin_lock_irqsave (&dev->rxq.lock, lockflags);
+
+	if (netif_running (&dev->net)) {
+		if ((retval = usb_submit_urb (urb)) != 0) {
+			dbg ("%s rx submit, %d", dev->net.name, retval);
+			tasklet_schedule (&dev->bh);
+		} else {
+			__skb_queue_tail (&dev->rxq, skb);
+		}
+	} else {
+		dbg ("rx: stopped");
+		retval = -ENOLINK;
+	}
+	spin_unlock_irqrestore (&dev->rxq.lock, lockflags);
+	if (retval) {
+		dev_kfree_skb_any (skb);
+		usb_free_urb (urb);
+	}
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
+{
+	if (dev->driver_info->flags & FLAG_FRAMING) {
+		struct nc_header	*header;
+		struct nc_trailer	*trailer;
+
+		if (!(skb->len & 0x01)
+				|| MIN_FRAMED > skb->len
+				|| skb->len > FRAMED_SIZE (dev->net.mtu)) {
+			dev->stats.rx_frame_errors++;
+			dbg ("rx framesize %d range %d..%d mtu %d", skb->len,
+				MIN_FRAMED, FRAMED_SIZE (dev->net.mtu),
+				dev->net.mtu
+				);
+			goto error;
+		}
+
+		header = (struct nc_header *) skb->data;
+		le16_to_cpus (&header->hdr_len);
+		le16_to_cpus (&header->packet_len);
+		if (FRAMED_SIZE (header->packet_len) > MAX_PACKET) {
+			dev->stats.rx_frame_errors++;
+			dbg ("packet too big, %d", header->packet_len);
+			goto error;
+		} else if (header->hdr_len < MIN_HEADER) {
+			dev->stats.rx_frame_errors++;
+			dbg ("header too short, %d", header->hdr_len);
+			goto error;
+		} else if (header->hdr_len > MIN_HEADER) {
+			// out of band data for us?
+			dbg ("header OOB, %d bytes",
+				header->hdr_len - MIN_HEADER);
+			// switch (vendor/product ids) { ... }
+		}
+		skb_pull (skb, header->hdr_len);
+
+		trailer = (struct nc_trailer *)
+			(skb->data + skb->len - sizeof *trailer);
+		skb_trim (skb, skb->len - sizeof *trailer);
+
+		if ((header->packet_len & 0x01) == 0) {
+			if (skb->data [header->packet_len] != PAD_BYTE) {
+				dev->stats.rx_frame_errors++;
+				dbg ("bad pad");
+				goto error;
+			}
+			skb_trim (skb, skb->len - 1);
+		}
+		if (skb->len != header->packet_len) {
+			dev->stats.rx_frame_errors++;
+			dbg ("bad packet len %d (expected %d)",
+				skb->len, header->packet_len);
+			goto error;
+		}
+		if (header->packet_id != get_unaligned (&trailer->packet_id)) {
+			dev->stats.rx_fifo_errors++;
+			dbg ("(2+ dropped) rx packet_id mismatch 0x%x 0x%x",
+				header->packet_id, trailer->packet_id);
+			goto error;
+		}
+#if 0
+		devdbg (dev, "frame <rx h %d p %d id %d", header->hdr_len,
+			header->packet_len, header->packet_id);
+#endif
+	} else {
+		// we trust the network stack to remove
+		// the extra byte we may have appended
+	}
+
+	if (skb->len) {
+		int	status;
+
+// FIXME: eth_copy_and_csum "small" packets to new SKB (small < ~200 bytes) ?
+
+		skb->dev = &dev->net;
+		skb->protocol = eth_type_trans (skb, &dev->net);
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes += skb->len;
+
+#ifdef	VERBOSE
+		devdbg (dev, "< rx, len %d, type 0x%x",
+			skb->len + sizeof (struct ethhdr), skb->protocol);
+#endif
+		memset (skb->cb,0,sizeof(struct skb_data));
+		status = netif_rx (skb);
+		if (status != NET_RX_SUCCESS)
+			devdbg (dev, "netif_rx status %d", status);
+	} else {
+		dbg ("drop");
+error:
+		dev->stats.rx_errors++;
+		skb_queue_tail (&dev->done, skb);
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void rx_complete (struct urb *urb)
+{
+	struct sk_buff		*skb = (struct sk_buff *) urb->context;
+	struct skb_data		*entry = (struct skb_data *) skb->cb;
+	struct usbnet		*dev = entry->dev;
+	int			urb_status = urb->status;
+
+	skb_put (skb, urb->actual_length);
+	entry->state = rx_done;
+	entry->urb = 0;
+
+	switch (urb_status) {
+	    // success
+	    case 0:
+		if (MIN_PACKET > skb->len || skb->len > MAX_PACKET) {
+			entry->state = rx_cleanup;
+			dev->stats.rx_errors++;
+			dev->stats.rx_length_errors++;
+			dbg ("rx length %d", skb->len);
+		}
+		break;
+
+	    // software-driven interface shutdown
+	    case -ECONNRESET:		// usb-ohci, usb-uhci
+	    case -ECONNABORTED:		// uhci ... for usb-uhci, INTR
+		dbg ("%s shutdown, code %d", dev->net.name, urb_status);
+		entry->state = rx_cleanup;
+		// do urb frees only in the tasklet
+		entry->urb = urb;
+		urb = 0;
+		break;
+
+	    // data overrun ... flush fifo?
+	    case -EOVERFLOW:
+		dev->stats.rx_over_errors++;
+		// FALLTHROUGH
+	    
+	    default:
+		// on unplug we'll get a burst of ETIMEDOUT/EILSEQ
+		// till the khubd gets and handles its interrupt.
+		entry->state = rx_cleanup;
+		dev->stats.rx_errors++;
+		dbg ("%s rx: status %d", dev->net.name, urb_status);
+		break;
+	}
+
+	defer_bh (dev, skb);
+
+	if (urb) {
+		if (netif_running (&dev->net)) {
+			rx_submit (dev, urb, GFP_ATOMIC);
+			return;
+		}
+	}
+#ifdef	VERBOSE
+	dbg ("no read resubmitted");
+#endif /* VERBOSE */
+}
+
+/*-------------------------------------------------------------------------*/
+
+// unlink pending rx/tx; completion handlers do all other cleanup
+
+static int unlink_urbs (struct sk_buff_head *q)
+{
+	unsigned long		flags;
+	struct sk_buff		*skb, *skbnext;
+	int			count = 0;
+
+	spin_lock_irqsave (&q->lock, flags);
+	for (skb = q->next; skb != (struct sk_buff *) q; skb = skbnext) {
+		struct skb_data		*entry;
+		struct urb		*urb;
+		int			retval;
+
+		entry = (struct skb_data *) skb->cb;
+		urb = entry->urb;
+		skbnext = skb->next;
+
+		// during some PM-driven resume scenarios,
+		// these (async) unlinks complete immediately
+		retval = usb_unlink_urb (urb);
+		if (retval < 0)
+			dbg ("unlink urb err, %d", retval);
+		else
+			count++;
+	}
+	spin_unlock_irqrestore (&q->lock, flags);
+	return count;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+// precondition: never called in_interrupt
+
+static int usbnet_stop (struct net_device *net)
+{
+	struct usbnet		*dev = (struct usbnet *) net->priv;
+	int			temp;
+	DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup); 
+	DECLARE_WAITQUEUE (wait, current);
+
+	mutex_lock (&dev->mutex);
+	netif_stop_queue(net);
+
+	devdbg (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld",
+		dev->stats.rx_packets, dev->stats.tx_packets, 
+		dev->stats.rx_errors, dev->stats.tx_errors
+		);
+
+	// ensure there are no more active urbs
+	add_wait_queue (&unlink_wakeup, &wait);
+	dev->wait = &unlink_wakeup;
+	temp = unlink_urbs (&dev->txq) + unlink_urbs (&dev->rxq);
+
+	// maybe wait for deletions to finish.
+	while (skb_queue_len (&dev->rxq)
+			&& skb_queue_len (&dev->txq)
+			&& skb_queue_len (&dev->done)) {
+		current->state = TASK_UNINTERRUPTIBLE;
+		schedule_timeout (UNLINK_TIMEOUT_JIFFIES);
+		dbg ("waited for %d urb completions", temp);
+	}
+	dev->wait = 0;
+	remove_wait_queue (&unlink_wakeup, &wait); 
+
+	mutex_unlock (&dev->mutex);
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+// posts reads, and enables write queing
+
+// precondition: never called in_interrupt
+
+static int usbnet_open (struct net_device *net)
+{
+	struct usbnet		*dev = (struct usbnet *) net->priv;
+	int			retval = 0;
+	struct driver_info	*info = dev->driver_info;
+
+	mutex_lock (&dev->mutex);
+
+	// put into "known safe" state
+	if (info->reset && (retval = info->reset (dev)) < 0) {
+		devinfo (dev, "open reset fail (%d) usbnet %03d/%03d, %s",
+			retval,
+			dev->udev->bus->busnum, dev->udev->devnum,
+			info->description);
+		goto done;
+	}
+
+	// insist peer be connected
+	if (info->check_connect && (retval = info->check_connect (dev)) < 0) {
+		devdbg (dev, "can't open; %d", retval);
+		goto done;
+	}
+
+	netif_start_queue (net);
+	devdbg (dev, "open: enable queueing (rx %d, tx %d) mtu %d %sframed",
+		RX_QLEN, TX_QLEN, dev->net.mtu,
+		(info->flags & FLAG_FRAMING) ? "" : "un"
+		);
+
+	// delay posting reads until we're fully open
+	tasklet_schedule (&dev->bh);
+done:
+	mutex_unlock (&dev->mutex);
+	return retval;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* usb_clear_halt cannot be called in interrupt context */
+
+static void
+tx_clear_halt(void *data)
+{
+	struct usbnet		*dev = data;
+
+	usb_clear_halt (dev->udev,
+		usb_sndbulkpipe (dev->udev, dev->driver_info->out));
+	netif_wake_queue (&dev->net);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void tx_complete (struct urb *urb)
+{
+	struct sk_buff		*skb = (struct sk_buff *) urb->context;
+	struct skb_data		*entry = (struct skb_data *) skb->cb;
+	struct usbnet		*dev = entry->dev;
+
+	if (urb->status == USB_ST_STALL) {
+		if (dev->ctrl_task.sync == 0) {
+			dev->ctrl_task.routine = tx_clear_halt;
+			dev->ctrl_task.data = dev;
+			schedule_task(&dev->ctrl_task);
+		} else {
+			dbg ("Cannot clear TX stall");
+		}
+	}
+	urb->dev = 0;
+	entry->state = tx_done;
+	defer_bh (dev, skb);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void usbnet_tx_timeout (struct net_device *net)
+{
+	struct usbnet		*dev = (struct usbnet *) net->priv;
+
+	unlink_urbs (&dev->txq);
+	tasklet_schedule (&dev->bh);
+
+	// FIXME: device recovery -- reset?
+}
+
+/*-------------------------------------------------------------------------*/
+
+static inline struct sk_buff *fixup_skb (struct sk_buff *skb, int flags)
+{
+	int			padlen;
+	struct sk_buff		*skb2;
+
+	padlen = ((skb->len + sizeof (struct nc_header)
+			+ sizeof (struct nc_trailer)) & 0x01) ? 0 : 1;
+	if (!skb_cloned (skb)) {
+		int	headroom = skb_headroom (skb);
+		int	tailroom = skb_tailroom (skb);
+
+		if ((padlen + sizeof (struct nc_trailer)) <= tailroom
+			    && sizeof (struct nc_header) <= headroom)
+			return skb;
+
+		if ((sizeof (struct nc_header) + padlen
+					+ sizeof (struct nc_trailer)) <
+				(headroom + tailroom)) {
+			skb->data = memmove (skb->head
+						+ sizeof (struct nc_header),
+					    skb->data, skb->len);
+			skb->tail = skb->data + skb->len;
+			return skb;
+		}
+	}
+	skb2 = skb_copy_expand (skb,
+				sizeof (struct nc_header),
+				sizeof (struct nc_trailer) + padlen,
+				flags);
+	dev_kfree_skb_any (skb);
+	return skb2;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
+{
+	struct usbnet		*dev = (struct usbnet *) net->priv;
+	int			length = skb->len;
+	int			retval = NET_XMIT_SUCCESS;
+	struct urb		*urb = 0;
+	struct skb_data		*entry;
+	struct nc_header	*header = 0;
+	struct nc_trailer	*trailer = 0;
+	struct driver_info	*info = dev->driver_info;
+	int			flags;
+
+	flags = in_interrupt () ? GFP_ATOMIC : GFP_KERNEL;
+
+	if (info->flags & FLAG_FRAMING) {
+		struct sk_buff	*skb2;
+		skb2 = fixup_skb (skb, flags);
+		if (!skb2) {
+			dbg ("can't fixup skb");
+			goto drop;
+		}
+		skb = skb2;
+	}
+
+	if (!(urb = usb_alloc_urb (0))) {
+		dbg ("no urb");
+		goto drop;
+	}
+
+	entry = (struct skb_data *) skb->cb;
+	entry->urb = urb;
+	entry->dev = dev;
+	entry->state = tx_start;
+	entry->length = length;
+
+	if (info->flags & FLAG_FRAMING) {
+		header = (struct nc_header *) skb_push (skb, sizeof *header);
+		header->hdr_len = cpu_to_le16 (sizeof (*header));
+		header->packet_len = cpu_to_le16 (length);
+		if (!((skb->len + sizeof *trailer) & 0x01))
+			*skb_put (skb, 1) = PAD_BYTE;
+		trailer = (struct nc_trailer *) skb_put (skb, sizeof *trailer);
+	} else if ((length % EP_SIZE (dev)) == 0) {
+			if (skb_shared (skb)) {
+				struct sk_buff *skb2;
+				skb2 = skb_unshare (skb, flags);
+				if (!skb2) {
+					dbg ("can't unshare skb");
+					goto drop;
+				}
+				skb = skb2;
+			}
+			skb->len++;
+		}
+
+	FILL_BULK_URB (urb, dev->udev,
+			usb_sndbulkpipe (dev->udev, info->out),
+			skb->data, skb->len, tx_complete, skb);
+	// Idle-but-posted reads with UHCI really chew up
+	// PCI bandwidth unless FSBR is disabled
+	urb->transfer_flags |= USB_ASYNC_UNLINK | USB_NO_FSBR;
+#ifdef	REALLY_QUEUE
+	urb->transfer_flags |= USB_QUEUE_BULK;
+#endif
+	// FIXME urb->timeout = ... jiffies ... ;
+
+	spin_lock_irqsave (&dev->txq.lock, flags);
+	if (info->flags & FLAG_FRAMING) {
+		header->packet_id = cpu_to_le16 (dev->packet_id++);
+		put_unaligned (header->packet_id, &trailer->packet_id);
+#if 0
+		devdbg (dev, "frame >tx h %d p %d id %d",
+			header->hdr_len, header->packet_len,
+			header->packet_id);
+#endif
+	}
+
+	netif_stop_queue (net);
+	if ((retval = usb_submit_urb (urb)) != 0) {
+		netif_start_queue (net);
+		dbg ("%s tx: submit urb err %d", net->name, retval);
+	} else {
+		net->trans_start = jiffies;
+		__skb_queue_tail (&dev->txq, skb);
+		if (dev->txq.qlen < TX_QLEN)
+			netif_start_queue (net);
+	}
+	spin_unlock_irqrestore (&dev->txq.lock, flags);
+
+	if (retval) {
+		devdbg (dev, "drop, code %d", retval);
+drop:
+		retval = NET_XMIT_DROP;
+		dev->stats.tx_dropped++;
+		dev_kfree_skb_any (skb);
+		usb_free_urb (urb);
+#ifdef	VERBOSE
+	} else {
+		devdbg (dev, "> tx, len %d, type 0x%x",
+			length, skb->protocol);
+#endif
+	}
+	return retval;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+// tasklet ... work that avoided running in_irq()
+
+static void usbnet_bh (unsigned long param)
+{
+	struct usbnet		*dev = (struct usbnet *) param;
+	struct sk_buff		*skb;
+	struct skb_data		*entry;
+
+	while ((skb = skb_dequeue (&dev->done))) {
+		entry = (struct skb_data *) skb->cb;
+		switch (entry->state) {
+		    case rx_done:
+			entry->state = rx_cleanup;
+			rx_process (dev, skb);
+			continue;
+		    case tx_done:
+			if (entry->urb->status) {
+				// can this statistic become more specific?
+				dev->stats.tx_errors++;
+				dbg ("%s tx: err %d", dev->net.name,
+					entry->urb->status);
+			} else {
+				dev->stats.tx_packets++;
+				dev->stats.tx_bytes += entry->length;
+			}
+			// FALLTHROUGH:
+		    case rx_cleanup:
+			usb_free_urb (entry->urb);
+			dev_kfree_skb (skb);
+			continue;
+		    default:
+			dbg ("%s: bogus skb state %d",
+				dev->net.name, entry->state);
+		}
+	}
+
+	// waiting for all pending urbs to complete?
+	if (dev->wait) {
+		if ((dev->txq.qlen + dev->rxq.qlen + dev->done.qlen) == 0) {
+			wake_up (dev->wait);
+		}
+
+	// or are we maybe short a few urbs?
+	} else if (netif_running (&dev->net)) {
+		int	temp = dev->rxq.qlen;
+
+		if (temp < RX_QLEN) {
+			struct urb	*urb;
+			int		i;
+			for (i = 0; i < 3 && dev->rxq.qlen < RX_QLEN; i++) {
+				if ((urb = usb_alloc_urb (0)) != 0)
+					rx_submit (dev, urb, GFP_ATOMIC);
+			}
+			if (temp != dev->rxq.qlen)
+				devdbg (dev, "rxqlen %d --> %d",
+						temp, dev->rxq.qlen);
+			if (dev->rxq.qlen < RX_QLEN)
+				tasklet_schedule (&dev->bh);
+		}
+		if (dev->txq.qlen < TX_QLEN)
+			netif_wake_queue (&dev->net);
+	}
+}
+
+
+
+/*-------------------------------------------------------------------------
+ *
+ * USB Device Driver support
+ *
+ *-------------------------------------------------------------------------*/
+ 
+// precondition: never called in_interrupt
+
+static void usbnet_disconnect (struct usb_device *udev, void *ptr)
+{
+	struct usbnet	*dev = (struct usbnet *) ptr;
+
+	devinfo (dev, "unregister usbnet %03d/%03d, %s",
+		udev->bus->busnum, udev->devnum,
+		dev->driver_info->description);
+	
+	unregister_netdev (&dev->net);
+
+	mutex_lock (&usbnet_mutex);
+	mutex_lock (&dev->mutex);
+	list_del (&dev->dev_list);
+	mutex_unlock (&usbnet_mutex);
+
+	kfree (dev);
+	usb_dec_dev_use (udev);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+// precondition: never called in_interrupt
+
+static void *
+usbnet_probe (struct usb_device *udev, unsigned ifnum,
+			const struct usb_device_id *prod)
+{
+	struct usbnet			*dev;
+	struct net_device 		*net;
+	struct usb_interface_descriptor	*interface;
+	struct driver_info		*info;
+	int				altnum = 0;
+
+	info = (struct driver_info *) prod->driver_info;
+
+	// sanity check; expect dedicated interface/devices for now.
+	interface = &udev->actconfig->interface [ifnum].altsetting [altnum];
+	if (udev->descriptor.bNumConfigurations != 1
+			|| udev->config[0].bNumInterfaces != 1
+//			|| interface->bInterfaceClass != USB_CLASS_VENDOR_SPEC
+			) {
+		dbg ("Bogus config info");
+		return 0;
+	}
+
+	if (usb_set_interface (udev, ifnum, altnum) < 0) {
+		err ("set_interface failed");
+		return 0;
+	}
+
+	// set up our own records
+	if (!(dev = kmalloc (sizeof *dev, GFP_KERNEL))) {
+		dbg ("can't kmalloc dev");
+		return 0;
+	}
+	memset (dev, 0, sizeof *dev);
+
+	init_MUTEX_LOCKED (&dev->mutex);
+	usb_inc_dev_use (udev);
+	dev->udev = udev;
+	dev->driver_info = info;
+	INIT_LIST_HEAD (&dev->dev_list);
+	skb_queue_head_init (&dev->rxq);
+	skb_queue_head_init (&dev->txq);
+	skb_queue_head_init (&dev->done);
+	dev->bh.func = usbnet_bh;
+	dev->bh.data = (unsigned long) dev;
+
+	// set up network interface records
+	net = &dev->net;
+	SET_MODULE_OWNER (net);
+	net->priv = dev;
+	strcpy (net->name, "usb%d");
+	memcpy (net->dev_addr, node_id, sizeof node_id);
+
+	// point-to-point link ... we always use Ethernet headers 
+	// supports win32 interop and the bridge driver.
+	ether_setup (net);
+
+	net->change_mtu = usbnet_change_mtu;
+	net->get_stats = usbnet_get_stats;
+	net->hard_start_xmit = usbnet_start_xmit;
+	net->open = usbnet_open;
+	net->stop = usbnet_stop;
+	net->watchdog_timeo = TX_TIMEOUT_JIFFIES;
+	net->tx_timeout = usbnet_tx_timeout;
+
+	register_netdev (&dev->net);
+	devinfo (dev, "register usbnet %03d/%03d, %s",
+		udev->bus->busnum, udev->devnum,
+		dev->driver_info->description);
+
+	// ok, it's ready to go.
+	mutex_lock (&usbnet_mutex);
+	list_add (&dev->dev_list, &usbnet_list);
+	mutex_unlock (&dev->mutex);
+
+	// start as if the link is up
+	netif_device_attach (&dev->net);
+
+	mutex_unlock (&usbnet_mutex);
+	return dev;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * chip vendor names won't normally be on the cables, and
+ * may not be on the device.
+ */
+
+static const struct usb_device_id	products [] = {
+
+#ifdef	CONFIG_USB_AN2720
+{
+	USB_DEVICE (0x0547, 0x2720),	// AnchorChips defaults
+	driver_info:	(unsigned long) &an2720_info,
+},
+#endif
+
+
+// GeneSys GL620USB (www.genesyslogic.com.tw)
+// (patch exists against an older driver version)
+
+
+#ifdef	CONFIG_USB_LINUXDEV
+/*
+ * for example, this can be a host side talk-to-PDA driver.
+ * this driver is NOT what runs _inside_ a Linux device !!
+ */
+{
+	// 1183 = 0x049F, both used as hex values?
+	USB_DEVICE (0x049F, 0x505A),	// Compaq "Itsy"
+	driver_info:	(unsigned long) &linuxdev_info,
+},
+#endif
+
+#ifdef	CONFIG_USB_NET1080
+{
+	USB_DEVICE (0x0525, 0x1080),	// NetChip ref design
+	driver_info:	(unsigned long) &net1080_info,
+},
+#endif
+
+#ifdef	CONFIG_USB_BELKIN_F5U104
+{
+	USB_DEVICE (0x050d, 0x0004),	// Belkin
+	driver_info:	(unsigned long) &belkin_info,
+}, {
+	USB_DEVICE (0x056c, 0x8100),	// eTEK
+	driver_info:	(unsigned long) &belkin_info,
+},
+#endif
+
+#ifdef CONFIG_USB_PL2301
+{
+	USB_DEVICE (0x067b, 0x0000),	// PL-2301
+	driver_info:	(unsigned long) &prolific_info,
+}, {
+	USB_DEVICE (0x067b, 0x0001),	// PL-2302
+	driver_info:	(unsigned long) &prolific_info,
+},
+#endif
+
+	{ },		// END
+};
+MODULE_DEVICE_TABLE (usb, products);
+
+static struct usb_driver usbnet_driver = {
+	name:		"usbnet",
+	id_table:	products,
+	probe:		usbnet_probe,
+	disconnect:	usbnet_disconnect,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init usbnet_init (void)
+{
+	// compiler should optimize this out
+	if (sizeof (((struct sk_buff *)0)->cb) < sizeof (struct skb_data))
+		BUG ();
+
+	get_random_bytes (node_id, sizeof node_id);
+	node_id [0] &= 0xfe;	// clear multicast bit
+
+ 	if (usb_register (&usbnet_driver) < 0)
+ 		return -1;
+
+	return 0;
+}
+module_init (usbnet_init);
+
+static void __exit usbnet_exit (void)
+{
+ 	usb_deregister (&usbnet_driver);
+}
+module_exit (usbnet_exit);
+
+MODULE_AUTHOR ("David Brownell <dbrownell@users.sourceforge.net>");
+MODULE_DESCRIPTION ("USB Host-to-Host Link Drivers (Belkin, Linux, NetChip, Prolific, ...)");
diff -u --recursive --new-file v2.4.9/linux/fs/affs/Changes linux/fs/affs/Changes
--- v2.4.9/linux/fs/affs/Changes	Wed Jul 25 17:10:24 2001
+++ linux/fs/affs/Changes	Tue Aug 28 07:11:20 2001
@@ -28,6 +28,14 @@
 
 Please direct bug reports to: zippel@linux-m68k.org
 
+Version 3.17
+------------
+
+- locking fixes
+- wrong sign in __affs_hash_dentry
+- remove unnecessary check in affs_new_inode
+- enable international mode for dircache fs
+
 Version 3.16
 ------------
 
diff -u --recursive --new-file v2.4.9/linux/fs/affs/amigaffs.c linux/fs/affs/amigaffs.c
--- v2.4.9/linux/fs/affs/amigaffs.c	Wed Jul 25 17:10:24 2001
+++ linux/fs/affs/amigaffs.c	Tue Aug 28 07:11:20 2001
@@ -311,7 +311,7 @@
 		goto done_unlock;
 	mark_buffer_dirty_inode(bh, inode);
 
-	affs_lock_dir(dir);
+	affs_unlock_dir(dir);
 
 	if (inode->i_nlink > 1)
 		retval = affs_remove_link(dentry);
diff -u --recursive --new-file v2.4.9/linux/fs/affs/inode.c linux/fs/affs/inode.c
--- v2.4.9/linux/fs/affs/inode.c	Wed Jul 25 17:10:24 2001
+++ linux/fs/affs/inode.c	Tue Aug 28 07:11:20 2001
@@ -300,7 +300,7 @@
 	u32			 block;
 	struct buffer_head	*bh;
 
-	if (!dir || !(inode = get_empty_inode()))
+	if (!(inode = get_empty_inode()))
 		goto err_inode;
 
 	if (!(block = affs_alloc_block(dir, dir->i_ino)))
diff -u --recursive --new-file v2.4.9/linux/fs/affs/namei.c linux/fs/affs/namei.c
--- v2.4.9/linux/fs/affs/namei.c	Wed Jul 25 17:10:24 2001
+++ linux/fs/affs/namei.c	Tue Aug 28 07:11:20 2001
@@ -72,7 +72,7 @@
 static inline int
 __affs_hash_dentry(struct dentry *dentry, struct qstr *qstr, toupper_t toupper)
 {
-	const char *name = qstr->name;
+	const u8 *name = qstr->name;
 	unsigned long hash;
 	int i;
 
@@ -448,25 +448,20 @@
 	if (!bh)
 		goto done;
 
-	affs_lock_dir(old_dir);
-	if (old_dir != new_dir)
-		affs_lock_dir(new_dir);
-
 	/* Remove header from its parent directory. */
+	affs_lock_dir(old_dir);
 	retval = affs_remove_hash(old_dir, bh);
+	affs_unlock_dir(old_dir);
 	if (retval)
-		goto done_unlock;
+		goto done;
 
 	/* And insert it into the new directory with the new name. */
 	affs_copy_name(AFFS_TAIL(sb, bh)->name, new_dentry);
 	affs_fix_checksum(sb, bh);
+	affs_lock_dir(new_dir);
 	retval = affs_insert_hash(new_dir, bh);
-	/* TODO: move it back to old_dir? */
-
-done_unlock:
-	affs_unlock_dir(old_dir);
-	if (old_dir != new_dir)
-		affs_unlock_dir(new_dir);
+	affs_unlock_dir(new_dir);
+	/* TODO: move it back to old_dir, if error? */
 
 done:
 	mark_buffer_dirty_inode(bh, retval ? old_dir : new_dir);
diff -u --recursive --new-file v2.4.9/linux/fs/affs/super.c linux/fs/affs/super.c
--- v2.4.9/linux/fs/affs/super.c	Thu Apr 19 22:57:06 2001
+++ linux/fs/affs/super.c	Tue Aug 28 07:11:20 2001
@@ -355,16 +355,16 @@
 	switch (chksum) {
 		case MUFS_FS:
 		case MUFS_INTLFFS:
+		case MUFS_DCFFS:
 			AFFS_SB->s_flags |= SF_MUFS;
 			/* fall thru */
 		case FS_INTLFFS:
+		case FS_DCFFS:
 			AFFS_SB->s_flags |= SF_INTL;
 			break;
-		case MUFS_DCFFS:
 		case MUFS_FFS:
 			AFFS_SB->s_flags |= SF_MUFS;
 			break;
-		case FS_DCFFS:
 		case FS_FFS:
 			break;
 		case MUFS_OFS:
diff -u --recursive --new-file v2.4.9/linux/fs/block_dev.c linux/fs/block_dev.c
--- v2.4.9/linux/fs/block_dev.c	Sun Aug 12 13:28:00 2001
+++ linux/fs/block_dev.c	Tue Aug 28 11:00:41 2001
@@ -153,7 +153,7 @@
 			}
 			buffercount=0;
 		}
-		balance_dirty(dev);
+		balance_dirty();
 		if (write_error)
 			break;
 	}
diff -u --recursive --new-file v2.4.9/linux/fs/buffer.c linux/fs/buffer.c
--- v2.4.9/linux/fs/buffer.c	Mon Aug 27 12:41:46 2001
+++ linux/fs/buffer.c	Tue Aug 28 11:02:25 2001
@@ -796,7 +796,7 @@
 
 static void free_more_memory(void)
 {
-	balance_dirty(NODEV);
+	balance_dirty();
 	page_launder(GFP_NOFS, 0);		
 	wakeup_bdflush();
 	wakeup_kswapd();
@@ -1086,7 +1086,7 @@
 /* -1 -> no need to flush
     0 -> async flush
     1 -> sync flush (wait for I/O completion) */
-int balance_dirty_state(kdev_t dev)
+static int balance_dirty_state(void)
 {
 	unsigned long dirty, tot, hard_dirty_limit, soft_dirty_limit;
 
@@ -1114,16 +1114,16 @@
  * pressures on different devices - thus the (currently unused)
  * 'dev' parameter.
  */
-void balance_dirty(kdev_t dev)
+void balance_dirty(void)
 {
-	int state = balance_dirty_state(dev);
+	int state = balance_dirty_state();
 
 	if (state < 0)
 		return;
 
 	/* If we're getting into imbalance, start write-out */
 	spin_lock(&lru_list_lock);
-	write_some_buffers(dev);
+	write_some_buffers(NODEV);
 
 	/*
 	 * And if we're _really_ out of balance, wait for
@@ -1132,7 +1132,7 @@
 	 * This will throttle heavy writers.
 	 */
 	if (state > 0) {
-		wait_for_some_buffers(dev);
+		wait_for_some_buffers(NODEV);
 		wakeup_bdflush();
 	}
 }
@@ -1155,7 +1155,7 @@
 {
 	if (!atomic_set_buffer_dirty(bh)) {
 		__mark_dirty(bh);
-		balance_dirty(bh->b_dev);
+		balance_dirty();
 	}
 }
 
@@ -1712,7 +1712,7 @@
 	}
 
 	if (need_balance_dirty)
-		balance_dirty(bh->b_dev);
+		balance_dirty();
 	/*
 	 * is this a partial write that happened to make all buffers
 	 * uptodate then we can optimize away a bogus readpage() for
@@ -2448,6 +2448,8 @@
 	write_unlock(&hash_table_lock);
 	spin_unlock(&lru_list_lock);
 	if (gfp_mask & __GFP_IO) {
+		if (!(gfp_mask & __GFP_HIGHIO) && PageHighMem(page))
+			return 0;
 		sync_page_buffers(bh, gfp_mask);
 		/* We waited synchronously, so we can free the buffers. */
 		if (gfp_mask & __GFP_WAIT) {
@@ -2706,7 +2708,7 @@
 		CHECK_EMERGENCY_SYNC
 
 		spin_lock(&lru_list_lock);
-		if (!write_some_buffers(NODEV) || balance_dirty_state(NODEV) < 0) {
+		if (!write_some_buffers(NODEV) || balance_dirty_state() < 0) {
 			wait_for_some_buffers(NODEV);
 			interruptible_sleep_on(&bdflush_wait);
 		}
diff -u --recursive --new-file v2.4.9/linux/fs/cramfs/inode.c linux/fs/cramfs/inode.c
--- v2.4.9/linux/fs/cramfs/inode.c	Wed Jul 25 17:10:24 2001
+++ linux/fs/cramfs/inode.c	Mon Aug 27 07:53:49 2001
@@ -374,6 +374,7 @@
 {
 	struct inode *inode = page->mapping->host;
 	u32 maxblock, bytes_filled;
+	void *pgdata;
 
 	maxblock = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
 	bytes_filled = 0;
@@ -387,15 +388,18 @@
 			start_offset = *(u32 *) cramfs_read(sb, blkptr_offset-4, 4);
 		compr_len = (*(u32 *) cramfs_read(sb, blkptr_offset, 4)
 			     - start_offset);
+		pgdata = kmap(page);
 		if (compr_len == 0)
 			; /* hole */
 		else
-			bytes_filled = cramfs_uncompress_block(page_address(page),
+			bytes_filled = cramfs_uncompress_block(pgdata,
 				 PAGE_CACHE_SIZE,
 				 cramfs_read(sb, start_offset, compr_len),
 				 compr_len);
-	}
-	memset(page_address(page) + bytes_filled, 0, PAGE_CACHE_SIZE - bytes_filled);
+	} else
+		pgdata = kmap(page);
+	memset(pgdata + bytes_filled, 0, PAGE_CACHE_SIZE - bytes_filled);
+	kunmap(page);
 	flush_dcache_page(page);
 	SetPageUptodate(page);
 	UnlockPage(page);
diff -u --recursive --new-file v2.4.9/linux/fs/dquot.c linux/fs/dquot.c
--- v2.4.9/linux/fs/dquot.c	Sun Aug 12 13:28:00 2001
+++ linux/fs/dquot.c	Tue Aug 28 10:56:06 2001
@@ -325,7 +325,7 @@
         memset(&dquot->dq_dqb, 0, sizeof(struct dqblk));
 }
 
-static void invalidate_dquots(kdev_t dev, short type)
+static void invalidate_dquots(struct super_block *sb, short type)
 {
 	struct dquot *dquot, *next;
 	int need_restart;
@@ -335,12 +335,10 @@
 	need_restart = 0;
 	while ((dquot = next) != NULL) {
 		next = dquot->dq_next;
-		if (dquot->dq_dev != dev)
+		if (dquot->dq_sb != sb)
 			continue;
 		if (dquot->dq_type != type)
 			continue;
-		if (!dquot->dq_sb)	/* Already invalidated entry? */
-			continue;
 		if (dquot->dq_flags & DQ_LOCKED) {
 			__wait_on_dquot(dquot);
 
@@ -349,12 +347,10 @@
 			/*
 			 * Make sure it's still the same dquot.
 			 */
-			if (dquot->dq_dev != dev)
+			if (dquot->dq_sb != sb)
 				continue;
 			if (dquot->dq_type != type)
 				continue;
-			if (!dquot->dq_sb)
-				continue;
 		}
 		/*
 		 *  Because inodes needn't to be the only holders of dquot
@@ -1409,7 +1405,7 @@
 
 		/* Note: these are blocking operations */
 		remove_dquot_ref(sb, cnt);
-		invalidate_dquots(sb->s_dev, cnt);
+		invalidate_dquots(sb, cnt);
 
 		/* Wait for any pending IO - remove me as soon as invalidate is more polite */
 		down(&dqopt->dqio_sem);
diff -u --recursive --new-file v2.4.9/linux/fs/inode.c linux/fs/inode.c
--- v2.4.9/linux/fs/inode.c	Sun Aug 12 13:28:00 2001
+++ linux/fs/inode.c	Mon Aug 27 08:22:28 2001
@@ -1049,6 +1049,7 @@
 
 			if (op && op->delete_inode) {
 				void (*delete)(struct inode *) = op->delete_inode;
+				DQUOT_INIT(inode);
 				/* s_op->delete_inode internally recalls clear_inode() */
 				delete(inode);
 			} else
diff -u --recursive --new-file v2.4.9/linux/fs/msdos/namei.c linux/fs/msdos/namei.c
--- v2.4.9/linux/fs/msdos/namei.c	Mon Aug 27 12:41:46 2001
+++ linux/fs/msdos/namei.c	Tue Aug 28 10:54:43 2001
@@ -17,6 +17,8 @@
 
 #include <asm/uaccess.h>
 
+#include "../fat/msbuffer.h"
+
 #define MSDOS_DEBUG 0
 #define PRINTK(x)
 
diff -u --recursive --new-file v2.4.9/linux/fs/ntfs/Makefile linux/fs/ntfs/Makefile
--- v2.4.9/linux/fs/ntfs/Makefile	Mon Aug 27 12:41:46 2001
+++ linux/fs/ntfs/Makefile	Tue Aug 28 06:57:18 2001
@@ -5,7 +5,7 @@
 obj-y   := fs.o sysctl.o support.o util.o inode.o dir.o super.o attr.o unistr.o
 obj-m   := $(O_TARGET)
 # New version format started 3 February 2001.
-EXTRA_CFLAGS = -DNTFS_VERSION=\"1.1.16\" #-DDEBUG
+EXTRA_CFLAGS = -DNTFS_VERSION=\"1.1.17\" #-DDEBUG
 
 include $(TOPDIR)/Rules.make
 
diff -u --recursive --new-file v2.4.9/linux/fs/ntfs/attr.c linux/fs/ntfs/attr.c
--- v2.4.9/linux/fs/ntfs/attr.c	Mon Aug 27 12:41:46 2001
+++ linux/fs/ntfs/attr.c	Tue Aug 28 06:57:18 2001
@@ -13,6 +13,7 @@
 #include "attr.h"
 
 #include <linux/errno.h>
+#include <linux/ntfs_fs.h>
 #include "macros.h"
 #include "support.h"
 #include "util.h"
@@ -148,7 +149,10 @@
 					"attribute non-resident. Bug!\n");
 				return -EINVAL;
 			}
-			m = memcmp(value, a->d.data, min(int, value_len, a->size));
+			m = value_len;
+			if (m > a->size)
+				m = a->size;
+			m = memcmp(value, a->d.data, m);
 			if (m > 0)
 				continue;
 			if (m < 0) {
@@ -234,7 +238,7 @@
 		}
 		if (attr->d.r.runlist) {
 			ntfs_memcpy(new, attr->d.r.runlist, attr->d.r.len
-							* sizeof(ntfs_runlist));
+					* sizeof(ntfs_runlist));
 			ntfs_vfree(attr->d.r.runlist);
 		}
 		attr->d.r.runlist = new;
@@ -250,7 +254,7 @@
 }
 
 /* Extends an attribute. Another run will be added if necessary, but we try to
- * extend the last run in the runlist first.
+ * extend the last run in the run list first.
  * FIXME: what if there isn't enough contiguous space, we don't create
  * multiple runs?
  *
@@ -264,7 +268,8 @@
 	ntfs_cluster_t cluster;
 	int clen;
 
-	if (attr->compressed || ino->record_count > 1)
+	if ((attr->flags & (ATTR_IS_COMPRESSED | ATTR_IS_ENCRYPTED)) ||
+			ino->record_count > 1)
 		return -EOPNOTSUPP;
 	if (attr->resident) {
 		error = ntfs_make_attr_nonresident(ino, attr);
@@ -272,7 +277,7 @@
 			return error;
 	}
 	if (*len <= attr->allocated)
-		return 0;	/* Truely stupid things do sometimes happen. */
+		return 0;	/* Truly stupid things do sometimes happen. */
 	rl = attr->d.r.runlist;
 	rlen = attr->d.r.len - 1;
 	if (rlen >= 0)
@@ -357,7 +362,7 @@
 	if (newsize == oldsize)
 		return 0;
 	/* FIXME: Modifying compressed attributes not supported yet. */
-	if (attr->compressed)
+	if (attr->flags & (ATTR_IS_COMPRESSED | ATTR_IS_ENCRYPTED))
 		/* FIXME: Extending is easy: just insert sparse runs. */
 		return -EOPNOTSUPP;
 	if (attr->resident) {
@@ -370,16 +375,18 @@
 		}
 		v = attr->d.data;
 		if (newsize) {
+			__s64 minsize = newsize;
 			attr->d.data = ntfs_malloc(newsize);
 			if (!attr->d.data) {
 				ntfs_free(v);
 				return -ENOMEM;
 			}
-			if (newsize > oldsize)
+			if (newsize > oldsize) {
+				minsize = oldsize;
 				ntfs_bzero((char*)attr->d.data + oldsize,
 					   newsize - oldsize);
-			ntfs_memcpy((char*)attr->d.data, v,
-				    min(s64, newsize, oldsize));
+			}
+			ntfs_memcpy((char*)attr->d.data, v, minsize);
 		} else
 			attr->d.data = 0;
 		ntfs_free(v);
@@ -389,6 +396,12 @@
 	/* Non-resident attribute. */
 	rl = attr->d.r.runlist;
 	if (newsize < oldsize) {
+		/*
+		 * FIXME: We might be going awfully wrong for newsize = 0,
+		 * possibly even leaking memory really badly. But considering
+		 * in that case there is more breakage due to -ENOTSUP stuff
+		 * further down the code path, who cares for the moment... (AIA)
+		 */
 		for (i = 0, count = 0; i < attr->d.r.len; i++) {
 			if ((__s64)(count + rl[i].len) << clustersizebits >
 									newsize)
@@ -441,7 +454,7 @@
 }
 
 int ntfs_create_attr(ntfs_inode *ino, int anum, char *aname, void *data,
-		     int dsize, ntfs_attribute **rattr)
+		int dsize, ntfs_attribute **rattr)
 {
 	void *name;
 	int namelen;
@@ -463,7 +476,7 @@
 		namelen = 0;
 	}
 	error = ntfs_new_attr(ino, anum, name, namelen, data, dsize, &i,
-									&found);
+			&found);
 	if (error || found) {
 		ntfs_free(name);
 		return error ? error : -EEXIST;
@@ -481,7 +494,8 @@
 				"+ 0x28) (%i)\n", attr->attrno,
 				NTFS_GETU16(ino->attr + 0x28));
 	attr->resident = 1;
-	attr->compressed = attr->cengine = 0;
+	attr->flags = 0;
+	attr->cengine = 0;
 	attr->size = attr->allocated = attr->initialized = dsize;
 
 	/* FIXME: INDEXED information should come from $AttrDef
@@ -498,7 +512,8 @@
 	return 0;
 }
 
-/* Non-resident attributes are stored in runs (intervals of clusters).
+/*
+ * Non-resident attributes are stored in runs (intervals of clusters).
  *
  * This function stores in the inode readable information about a non-resident
  * attribute.
@@ -630,7 +645,7 @@
 	}
 	attr = ino->attrs + i;
 	attr->resident = NTFS_GETU8(attrdata + 8) == 0;
-	attr->compressed = NTFS_GETU16(attrdata + 0xC);
+	attr->flags = *(__u16*)(attrdata + 0xC);
 	attr->attrno = NTFS_GETU16(attrdata + 0xE);
   
 	if (attr->resident) {
@@ -640,13 +655,13 @@
 		if (!attr->d.data)
 			return -ENOMEM;
 		ntfs_memcpy(attr->d.data, data, attr->size);
-		attr->indexed = NTFS_GETU16(attrdata + 0x16);
+		attr->indexed = NTFS_GETU8(attrdata + 0x16);
 	} else {
 		attr->allocated = NTFS_GETS64(attrdata + 0x28);
 		attr->size = NTFS_GETS64(attrdata + 0x30);
 		attr->initialized = NTFS_GETS64(attrdata + 0x38);
 		attr->cengine = NTFS_GETU16(attrdata + 0x22);
-		if (attr->compressed)
+		if (attr->flags & ATTR_IS_COMPRESSED)
 			attr->compsize = NTFS_GETS64(attrdata + 0x40);
 		ntfs_debug(DEBUG_FILE3, "ntfs_insert_attribute: "
 			"attr->allocated = 0x%Lx, attr->size = 0x%Lx, "
@@ -664,11 +679,14 @@
 
 int ntfs_read_zero(ntfs_io *dest, int size)
 {
+	int i;
 	char *sparse = ntfs_calloc(512);
 	if (!sparse)
 		return -ENOMEM;
+	i = 512;
 	while (size) {
-		int i = min(int, size, 512);
+		if (i > size)
+			i = size;
 		dest->fn_put(dest, sparse, i);
 		size -= i;
 	}
@@ -683,7 +701,7 @@
 	int error = 0;
 	int clustersizebits;
 	int s_vcn, rnum, vcn, got, l1;
-	__s64 copied, len, chunk, offs1, l;
+	__s64 copied, len, chunk, offs1, l, chunk2;
 	ntfs_cluster_t cluster, cl1;
 	char *comp = 0, *comp1;
 	char *decomp = 0;
@@ -720,12 +738,15 @@
 		chunk = 0;
 		if (cluster == (ntfs_cluster_t)-1) {
 			/* Sparse cluster. */
-			__s64 l1;
+			__s64 ll;
+
 			if ((len - (s_vcn - vcn)) & 15)
 				ntfs_error("Unexpected sparse chunk size.");
-			l1 = chunk = min(s64, ((__s64)(vcn + len) << clustersizebits)
-								- offset, l);
-			error = ntfs_read_zero(dest, l1);
+			ll = ((__s64)(vcn + len) << clustersizebits) - offset;
+			if (ll > l)
+				ll = l;
+			chunk = ll;
+			error = ntfs_read_zero(dest, ll);
 			if (error)
 				goto out;
 		} else if (dest->do_read) {
@@ -741,14 +762,21 @@
 			cl1 = cluster + s_vcn - vcn;
 			comp1 = comp;
 			do {
+				int delta;
+
 				io.param = comp1;
-				l1 = min(int, len - max(int, s_vcn - vcn, 0), 16 - got);
+				delta = s_vcn - vcn;
+				if (delta < 0)
+					delta = 0;
+				l1 = len - delta;
+				if (l1 > 16 - got)
+					l1 = 16 - got;
 				io.size = (__s64)l1 << clustersizebits;
 				error = ntfs_getput_clusters(ino->vol, cl1, 0,
 					       		     &io);
 				if (error)
 					goto out;
-				if (l1 + max(int, s_vcn - vcn, 0) == len) {
+				if (l1 + delta == len) {
 					rnum++;
 					rl++;
 					vcn += len;
@@ -779,8 +807,11 @@
 				comp1 = decomp;
 			}
 			offs1 = offset - ((__s64)s_vcn << clustersizebits);
-			chunk = min(s64, (16 << clustersizebits) - offs1, chunk);
-			chunk = min(s64, l, chunk);
+			chunk2 = (16 << clustersizebits) - offs1;
+			if (chunk2 > l)
+				chunk2 = l;
+			if (chunk > chunk2)
+				chunk = chunk2;
 			dest->fn_put(dest, comp1 + offs1, chunk);
 		}
 		l -= chunk;
@@ -795,7 +826,7 @@
 			len = rl->len;
 		}
 	}
- out:
+out:
 	if (comp)
 		ntfs_free(comp);
 	if (decomp)
@@ -805,7 +836,7 @@
 }
 
 int ntfs_write_compressed(ntfs_inode *ino, ntfs_attribute *attr, __s64 offset,
-			  ntfs_io *dest)
+		ntfs_io *dest)
 {
 	return -EOPNOTSUPP;
 }
diff -u --recursive --new-file v2.4.9/linux/fs/ntfs/dir.c linux/fs/ntfs/dir.c
--- v2.4.9/linux/fs/ntfs/dir.c	Mon Aug 27 12:41:46 2001
+++ linux/fs/ntfs/dir.c	Tue Aug 28 06:57:18 2001
@@ -27,8 +27,7 @@
  * be restored. */
 int ntfs_check_index_record(ntfs_inode *ino, char *record)
 {
-	return ntfs_fixup_record(ino->vol, record, "INDX",
-				 ino->u.index.recordsize);
+	return ntfs_fixup_record(record, "INDX", ino->u.index.recordsize);
 }
 
 static inline int ntfs_is_top(ntfs_u64 stack)
@@ -268,12 +267,21 @@
 		ntfs_resize_attr(walk->dir, a, used);
 	} else {
 		NTFS_PUTU16(buf + 0x1C, used - 0x18);
-		ntfs_insert_fixups(buf, vol->sector_size);
 		io.size = walk->dir->u.index.recordsize;
+		error = ntfs_insert_fixups(buf, io.size);
+		if (error) {
+			printk(KERN_ALERT "NTFS: ntfs_index_writeback() caught "
+					"corrupt index record ntfs record "
+					"header. Refusing to write corrupt "
+					"data to disk. Unmount and run chkdsk "
+					"immediately!\n");
+			return -EIO;
+		}
 		error = ntfs_write_attr(walk->dir, vol->at_index_allocation,
-			I30, (__s64)block << vol->cluster_size_bits, &io);
+				I30, (__s64)block << vol->cluster_size_bits,
+				&io);
 		if (error || (io.size != walk->dir->u.index.recordsize &&
-							(error = -EIO, 1)))
+				(error = -EIO, 1)))
 			return error;
 	}
 	return 0;
@@ -467,7 +475,7 @@
 	NTFS_PUTU32(index + 0x24, NTFS_GETU32(root + 0x1C));
 	error = ntfs_index_writeback(&walk, index, walk.newblock, 
 				     isize + NTFS_GETU16(index + 0x18) + 0x18);
-	if(error)
+	if (error)
 		goto out;
 	/* Mark root as split. */
 	NTFS_PUTU32(root + 0x1C, 1);
diff -u --recursive --new-file v2.4.9/linux/fs/ntfs/fs.c linux/fs/ntfs/fs.c
--- v2.4.9/linux/fs/ntfs/fs.c	Mon Aug 27 12:41:46 2001
+++ linux/fs/ntfs/fs.c	Tue Aug 28 06:57:18 2001
@@ -11,7 +11,7 @@
  */
 
 #include <linux/config.h>
-
+#include <linux/errno.h>
 #include "ntfstypes.h"
 #include "struct.h"
 #include "util.h"
@@ -27,10 +27,8 @@
 #include <linux/init.h>
 #include <linux/smp_lock.h>
 #include <asm/page.h>
-
-#ifndef NLS_MAX_CHARSET_SIZE
 #include <linux/nls.h>
-#endif
+#include <linux/ntfs_fs.h>
 
 /* Forward declarations. */
 static struct inode_operations ntfs_dir_inode_operations;
@@ -67,6 +65,7 @@
 {
 	int error;
 	ntfs_io io;
+	ntfs_attribute *attr;
 	ntfs_inode *ino = NTFS_LINO2NINO(filp->f_dentry->d_inode);
 
 	/* Inode is not properly initialized. */
@@ -75,11 +74,14 @@
 	ntfs_debug(DEBUG_OTHER, "ntfs_read %x, %Lx, %x ->",
 		   (unsigned)ino->i_number, (unsigned long long)*off,
 		   (unsigned)count);
+	attr = ntfs_find_attr(ino, ino->vol->at_data, NULL);
 	/* Inode has no unnamed data attribute. */
-	if(!ntfs_find_attr(ino, ino->vol->at_data, NULL)) {
+	if (!attr) {
 		ntfs_debug(DEBUG_OTHER, "ntfs_read: $DATA not found!\n");
 		return -EINVAL;
 	}
+	if (attr->flags & ATTR_IS_ENCRYPTED)
+		return -EACCES;
 	/* Read the data. */
 	io.fn_put = ntfs_putuser;
 	io.fn_get = 0;
@@ -285,8 +287,21 @@
 	return 1;
 }
 
+/*
+ * This needs to be outside parse_options() otherwise a remount will reset
+ * these unintentionally.
+ */
+static void init_ntfs_super_block(ntfs_volume* vol)
+{
+	vol->uid = vol->gid = 0;
+	vol->umask = 0077;
+	vol->ngt = ngt_nt;
+	vol->nls_map = (void*)-1;
+	vol->mft_zone_multiplier = -1;
+}
+
 /* Parse the (re)mount options. */
-static int parse_options(ntfs_volume *vol, char *opt, int remount)
+static int parse_options(ntfs_volume *vol, char *opt)
 {
 	char *value;		/* Defaults if not specified and !remount. */
 	ntfs_uid_t uid = -1;	/* 0, root user only */
@@ -296,6 +311,8 @@
 	void *nls_map = NULL;	/* Try to load the default NLS. */
 	int use_utf8 = -1;	/* If no NLS specified and loading the default
 				   NLS failed use utf8. */
+	int mft_zone_mul = -1;	/* 1 */
+
 	if (!opt)
 		goto done;
 	for (opt = strtok(opt, ","); opt; opt = strtok(NULL, ",")) {
@@ -326,6 +343,24 @@
 						"argument\n");
 				return 0;
 			}
+		} else if (strcmp(opt, "mft_zone_multiplier") == 0) {
+			unsigned long ul;
+
+			if (!value || !*value)
+				goto needs_arg;
+			ul = simple_strtoul(value, &value, 0);
+			if (*value) {
+				printk(KERN_ERR "NTFS: mft_zone_multiplier "
+						"invalid argument\n");
+				return 0;
+			}
+			if (ul >= 1 && ul <= 4)
+				mft_zone_mul = ul;
+			else {
+				mft_zone_mul = 1;
+				printk(KERN_WARNING "NTFS: mft_zone_multiplier "
+					      "out of range. Setting to 1.\n");
+			}
 		} else if (strcmp(opt, "posix") == 0) {
 			int val;
 			if (!value || !*value)
@@ -361,40 +396,69 @@
 		}
 	}
 done:
-	if (use_utf8 != -1 && use_utf8) {
-		if (nls_map) {
+	if (use_utf8 == -1) {
+		/* utf8 was not specified at all. */
+		if (!nls_map) {
+			/*
+			 * No NLS was specified. If first mount, load the
+			 * default NLS, otherwise don't change the NLS setting.
+			 */
+			if (vol->nls_map == (void*)-1)
+				vol->nls_map = load_nls_default();
+		} else {
+			/* If an NLS was already loaded, unload it first. */
+			if (vol->nls_map && vol->nls_map != (void*)-1)
+				unload_nls(vol->nls_map);
+			/* Use the specified NLS. */
+			vol->nls_map = nls_map;
+		}
+	} else {
+		/* utf8 was specified. */
+		if (use_utf8 && nls_map) {
 			unload_nls(nls_map);
 			printk(KERN_ERR "NTFS: utf8 cannot be combined with "
 					"iocharset.\n");
 			return 0;
 		}
-		if (remount && vol->nls_map)
+		/* If an NLS was already loaded, unload it first. */
+		if (vol->nls_map && vol->nls_map != (void*)-1)
 			unload_nls(vol->nls_map);
-		vol->nls_map = NULL;
-	} else {
-		if (nls_map) {
-			if (remount && vol->nls_map)
-				unload_nls(vol->nls_map);
-			vol->nls_map = nls_map;
-		} else if (!remount || (remount && !use_utf8 && !vol->nls_map))
-			vol->nls_map = load_nls_default();
+		if (!use_utf8) {
+			/* utf8 was specified as false. */
+			if (!nls_map)
+				/* No NLS was specified, load the default. */
+				vol->nls_map = load_nls_default();
+			else
+				/* Use the specified NLS. */
+				vol->nls_map = nls_map;
+		} else
+			/* utf8 was specified as true. */
+			vol->nls_map = NULL;
 	}
 	if (uid != -1)
 		vol->uid = uid;
-	else if (!remount)
-		vol->uid = 0;
 	if (gid != -1)
 		vol->gid = gid;
-	else if (!remount)
-		vol->gid = 0;
 	if (umask != -1)
 		vol->umask = (ntmode_t)umask;
-	else if (!remount)
-		vol->umask = 0077;
 	if (ngt != -1)
 		vol->ngt = ngt;
-	else if (!remount)
-		vol->ngt = ngt_nt;
+	if (mft_zone_mul != -1) {
+		/* mft_zone_multiplier was specified. */
+		if (vol->mft_zone_multiplier != -1) {
+			/* This is a remount, ignore a change and warn user. */
+			if (vol->mft_zone_multiplier != mft_zone_mul)
+				printk(KERN_WARNING "NTFS: Ignoring changes in "
+						"mft_zone_multiplier on "
+						"remount. If you want to "
+						"change this you need to "
+						"umount and mount again.\n");
+		} else
+			/* Use the specified multiplier. */
+			vol->mft_zone_multiplier = mft_zone_mul;
+	} else if (vol->mft_zone_multiplier == -1)
+		/* No multiplier specified and first mount, so set default. */
+		vol->mft_zone_multiplier = 1;
 	return 1;
 needs_arg:
 	printk(KERN_ERR "NTFS: %s needs an argument", opt);
@@ -436,10 +500,12 @@
 }
 
 static struct file_operations ntfs_file_operations_nommap = {
+	llseek:		generic_file_llseek,
 	read:		ntfs_read,
 #ifdef CONFIG_NTFS_RW
 	write:		ntfs_write,
 #endif
+	open:		generic_file_open,
 };
 
 static struct inode_operations ntfs_inode_operations_nobmap;
@@ -556,18 +622,8 @@
 }
 #endif
 
-#if 0
-static int ntfs_bmap(struct inode *ino, int block)
-{
-	int ret = ntfs_vcn_to_lcn(NTFS_LINO2NINO(ino), block);
-	ntfs_debug(DEBUG_OTHER, "bmap of %lx, block %x is %x\n", ino->i_ino,
-		   block, ret);
-	return (ret == -1) ? 0 : ret;
-}
-#endif
-
 /* It's fscking broken. */
-/* FIXME: [bm]map code is disabled until ntfs_get_block() gets sorted! */
+/* FIXME: mmap code is disabled until ntfs_get_block() gets sorted! */
 /*
 static int ntfs_get_block(struct inode *inode, long block, struct buffer_head *bh, int create)
 {
@@ -576,11 +632,13 @@
 }
 
 static struct file_operations ntfs_file_operations = {
+	llseek:		generic_file_llseek,
 	read:		ntfs_read,
 	mmap:		generic_file_mmap,
 #ifdef CONFIG_NTFS_RW
 	write:		ntfs_write,
 #endif
+	open:		generic_file_open,
 };
 
 static struct inode_operations ntfs_inode_operations;
@@ -646,19 +704,10 @@
 
 	vol = NTFS_INO2VOL(inode);
 	inode->i_mode = 0;
-	ntfs_debug(DEBUG_OTHER, "ntfs_read_inode 0x%x\n", (unsigned)inode->i_ino);
-	/*
-	 * This kills all accesses to system files (except $Extend directory).
-	 * The driver can bypass this by calling ntfs_init_inode() directly.
-	 * Only if ngt is ngt_full do we allow access to the system files.
-	 */
+	ntfs_debug(DEBUG_OTHER, "ntfs_read_inode 0x%lx\n", inode->i_ino);
 	switch (inode->i_ino) {
 		/* Those are loaded special files. */
 	case FILE_$Mft:
-		if (vol->ngt != ngt_full) {
-			ntfs_error("Trying to open $MFT!\n");
-			return;
-		}
 		if (!vol->mft_ino || ((vol->ino_flags & 1) == 0))
 			goto sys_file_error;
 		ntfs_memcpy(&inode->u.ntfs_i, vol->mft_ino, sizeof(ntfs_inode));
@@ -670,10 +719,6 @@
 		ntfs_debug(DEBUG_OTHER, "Opening $MFT!\n");
 		break;
 	case FILE_$MftMirr:
-		if (vol->ngt != ngt_full) {
-			ntfs_error("Trying to open $MFTMirr!\n");
-			return;
-		}
 		if (!vol->mftmirr || ((vol->ino_flags & 2) == 0))
 			goto sys_file_error;
 		ntfs_memcpy(&inode->u.ntfs_i, vol->mftmirr, sizeof(ntfs_inode));
@@ -685,10 +730,6 @@
 		ntfs_debug(DEBUG_OTHER, "Opening $MFTMirr!\n");
 		break;
 	case FILE_$BitMap:
-		if (vol->ngt != ngt_full) {
-			ntfs_error("Trying to open $Bitmap!\n");
-			return;
-		}
 		if (!vol->bitmap || ((vol->ino_flags & 4) == 0))
 			goto sys_file_error;
 		ntfs_memcpy(&inode->u.ntfs_i, vol->bitmap, sizeof(ntfs_inode));
@@ -700,14 +741,10 @@
 		ntfs_debug(DEBUG_OTHER, "Opening $Bitmap!\n");
 		break;
 	case FILE_$LogFile ... FILE_$AttrDef:
-	/* We need to allow reading the root directory. */
+	/* No need to log root directory accesses. */
 	case FILE_$Boot ... FILE_$UpCase:
-		if (vol->ngt != ngt_full) {
-			ntfs_error("Trying to open system file %i!\n",
-								inode->i_ino);
-	 		return;
-		} /* Do the default for ngt_full. */
-		ntfs_debug(DEBUG_OTHER, "Opening system file %i!\n", inode->i_ino);
+		ntfs_debug(DEBUG_OTHER, "Opening system file %i!\n",
+				inode->i_ino);
 	default:
 		ino = &inode->u.ntfs_i;
 		if (!ino || ntfs_init_inode(ino, NTFS_INO2VOL(inode),
@@ -731,7 +768,8 @@
 		inode->i_size = data->size;
 		/* FIXME: once ntfs_get_block is implemented, uncomment the
 		 * next line and remove the "can_mmap = 0;". (AIA) */
-		/* can_mmap = !data->resident && !data->compressed; */
+		/* can_mmap = !data->resident && !(data->flags &
+		 * 		(ATTR_IS_COMPRESSED | ATTR_IS_ENCRYPTED)); */
 		can_mmap = 0;
 	}
 	/* Get the file modification times from the standard information. */
@@ -768,7 +806,7 @@
 		inode->i_mode = S_IFREG | S_IRUGO;
 	}
 #ifdef CONFIG_NTFS_RW
-	if (!data || !data->compressed)
+	if (!data || !(data->flags & (ATTR_IS_COMPRESSED | ATTR_IS_ENCRYPTED)))
 		inode->i_mode |= S_IWUGO;
 #endif
 	inode->i_mode &= ~vol->umask;
@@ -798,13 +836,10 @@
 	ntfs_debug(DEBUG_OTHER, "_ntfs_clear_inode 0x%x\n", inode->i_ino);
 	vol = NTFS_INO2VOL(inode);
 	if (!vol)
-		ntfs_error("_ntfs_clear_inode: vol = NTFS_INO2VOL(inode) is NULL.\n");
+		ntfs_error("_ntfs_clear_inode: vol = NTFS_INO2VOL(inode) is "
+				"NULL.\n");
 	switch (inode->i_ino) {
 	case FILE_$Mft:
-		if (vol->ngt != ngt_full) {
-			ntfs_error("Trying to _clear_inode of $MFT!\n");
-			goto unl_out;
-		}
 		if (vol->mft_ino && ((vol->ino_flags & 1) == 0)) {
 			ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode));
 			ntfs_memcpy(ino, &inode->u.ntfs_i, sizeof(ntfs_inode));
@@ -814,10 +849,6 @@
 		}
 		break;
 	case FILE_$MftMirr:
-		if (vol->ngt != ngt_full) {
-			ntfs_error("Trying to _clear_inode of $MFTMirr!\n");
-			goto unl_out;
-		}
 		if (vol->mftmirr && ((vol->ino_flags & 2) == 0)) {
 			ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode));
 			ntfs_memcpy(ino, &inode->u.ntfs_i, sizeof(ntfs_inode));
@@ -827,10 +858,6 @@
 		}
 		break;
 	case FILE_$BitMap:
-		if (vol->ngt != ngt_full) {
-			ntfs_error("Trying to _clear_inode of $Bitmap!\n");
-			goto unl_out;
-		}
 		if (vol->bitmap && ((vol->ino_flags & 4) == 0)) {
 			ino = (ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode));
 			ntfs_memcpy(ino, &inode->u.ntfs_i, sizeof(ntfs_inode));
@@ -839,13 +866,6 @@
 			goto unl_out;
 		}
 		break;
-	case FILE_$LogFile ... FILE_$AttrDef:
-	case FILE_$Boot ... FILE_$UpCase:
-		if (vol->ngt != ngt_full) {
-			ntfs_error("Trying to _clear_inode of system file %i! "
-					"Shouldn't happen.\n", inode->i_ino);
-			goto unl_out;
-		} /* Do the default for ngt_full. */
 	default:
 		/* Nothing. Just clear the inode and exit. */
 	}
@@ -905,7 +925,7 @@
 /* Called when remounting a filesystem by do_remount_sb() in fs/super.c. */
 static int ntfs_remount_fs(struct super_block *sb, int *flags, char *options)
 {
-	if (!parse_options(NTFS_SB2VOL(sb), options, 1))
+	if (!parse_options(NTFS_SB2VOL(sb), options))
 		return -EINVAL;
 	return 0;
 }
@@ -1006,11 +1026,12 @@
 {
 	ntfs_volume *vol;
 	struct buffer_head *bh;
-	int i;
+	int i, to_read;
 
 	ntfs_debug(DEBUG_OTHER, "ntfs_read_super\n");
 	vol = NTFS_SB2VOL(sb);
-	if (!parse_options(vol, (char*)options, 0))
+	init_ntfs_super_block(vol);
+	if (!parse_options(vol, (char*)options))
 		goto ntfs_read_super_vol;
 	/* Assume a 512 bytes block device for now. */
 	set_blocksize(sb->s_dev, 512);
@@ -1048,12 +1069,17 @@
 	set_blocksize(sb->s_dev, sb->s_blocksize);
 	ntfs_debug(DEBUG_OTHER, "set_blocksize\n");
 	/* Allocate an MFT record (MFT record can be smaller than a cluster). */
-	if (!(vol->mft = ntfs_malloc(max(int, vol->mft_record_size,
-					 vol->cluster_size))))
+	i = vol->cluster_size;
+	if (i < vol->mft_record_size)
+		i = vol->mft_record_size;
+	if (!(vol->mft = ntfs_malloc(i)))
 		goto ntfs_read_super_unl;
 
 	/* Read at least the MFT record for $Mft. */
-	for (i = 0; i < max(int, vol->mft_clusters_per_record, 1); i++) {
+	to_read = vol->mft_clusters_per_record;
+	if (to_read < 1)
+		to_read = 1;
+	for (i = 0; i < to_read; i++) {
 		if (!(bh = bread(sb->s_dev, vol->mft_lcn + i,
 							  vol->cluster_size))) {
 			ntfs_error("Could not read $Mft record 0\n");
diff -u --recursive --new-file v2.4.9/linux/fs/ntfs/inode.c linux/fs/ntfs/inode.c
--- v2.4.9/linux/fs/ntfs/inode.c	Mon Aug 27 12:41:46 2001
+++ linux/fs/ntfs/inode.c	Tue Aug 28 06:57:18 2001
@@ -20,6 +20,7 @@
 #include "dir.h"
 #include "support.h"
 #include "util.h"
+#include <linux/ntfs_fs.h>
 #include <linux/smp_lock.h>
 
 typedef struct {
@@ -88,7 +89,7 @@
 	/* Try to allocate at least 0.1% of the remaining disk space for
 	 * inodes. If the disk is almost full, make sure at least one inode is
 	 * requested. */
-	int rcount, error, block, blockbits;
+	int rcount, error, mft_rec_size;
 	__s64 size;
 	ntfs_attribute *mdata, *bmp;
 	ntfs_u8 *buf;
@@ -97,35 +98,34 @@
 	mdata = ntfs_find_attr(vol->mft_ino, vol->at_data, 0);
 	if (!mdata)
 		return -EINVAL;
+	mft_rec_size = vol->mft_record_size;
 	/* First check whether there is uninitialized space. */
-	if (mdata->allocated < mdata->size + vol->mft_record_size) {
+	if (mdata->allocated < mdata->size + mft_rec_size) {
 		size = (__s64)ntfs_get_free_cluster_count(vol->bitmap) <<
-							vol->cluster_size_bits;
+				vol->cluster_size_bits >> 10;
 		/* On error, size will be negative. We can ignore this as we
 		 * will fall back to the minimal size allocation below. (AIA) */
-		block = vol->mft_record_size;
-		blockbits = vol->mft_record_size_bits;
-		size = max(s64, size >> 10, mdata->size + vol->mft_record_size);
-		size = (__s64)((size + block - 1) >> blockbits) << blockbits;
-		/* Require this to be a single chunk. */
+		if (size < mdata->size + mft_rec_size)
+			size = mdata->size + mft_rec_size;
+		size += mft_rec_size - 1;
+		size &= ~(__s64)(mft_rec_size - 1);
 		error = ntfs_extend_attr(vol->mft_ino, mdata, &size,
-							   ALLOC_REQUIRE_SIZE);
+				ALLOC_REQUIRE_SIZE);
 		/* Try again, now we have the largest available fragment. */
 		if (error == -ENOSPC) {
 			/* Round down to multiple of mft record size. */
-			size = (__s64)(size >> vol->mft_record_size_bits) <<
-						vol->mft_record_size_bits;
+			size &= ~(__s64)(mft_rec_size - 1);
 			if (!size)
 				return -ENOSPC;
 			error = ntfs_extend_attr(vol->mft_ino, mdata, &size,
-							   ALLOC_REQUIRE_SIZE);
+					ALLOC_REQUIRE_SIZE);
 		}
 		if (error)
 			return error;
 	}
 	/* Even though we might have allocated more than needed, we initialize
 	 * only one record. */
-	mdata->size += vol->mft_record_size;
+	mdata->size += mft_rec_size;
 	/* Now extend the bitmap if necessary. */
 	rcount = mdata->size >> vol->mft_record_size_bits;
 	bmp = ntfs_find_attr(vol->mft_ino, vol->at_bitmap, 0);
@@ -144,27 +144,34 @@
 		io.param = buf;
 		io.size = 1;
 		error = ntfs_write_attr(vol->mft_ino, vol->at_bitmap, 0,
-					bmp->size - 1, &io);
+				bmp->size - 1, &io);
 		if (error)
 			return error;
 		if (io.size != 1)
 			return -EIO;
 	}
 	/* Now fill in the MFT header for the new block. */
-	buf = ntfs_calloc(vol->mft_record_size);
+	buf = ntfs_calloc(mft_rec_size);
 	if (!buf)
 		return -ENOMEM;
-	ntfs_fill_mft_header(buf, vol->mft_record_size, vol->sector_size, 0);
-	ntfs_insert_fixups(buf, vol->sector_size);
+	ntfs_fill_mft_header(buf, mft_rec_size, vol->sector_size, 0);
+	error = ntfs_insert_fixups(buf, mft_rec_size);
+	if (error) {
+		printk(KERN_ALERT "NTFS: ntfs_extend_mft() caught corrupt "
+				"mtf record ntfs record header. Refusing to "
+				"write corrupt data to disk. Unmount and run "
+				"chkdsk immediately!\n");
+		return -EIO;
+	}
 	io.param = buf;
-	io.size = vol->mft_record_size;
+	io.size = mft_rec_size;
 	io.fn_put = ntfs_put;
 	io.fn_get = ntfs_get;
 	error = ntfs_write_attr(vol->mft_ino, vol->at_data, 0,
 			(__s64)(rcount - 1) << vol->mft_record_size_bits, &io);
 	if (error)
 		return error;
-	if (io.size != vol->mft_record_size)
+	if (io.size != mft_rec_size)
 		return -EIO;
 	error = ntfs_update_inode(vol->mft_ino);
 	if (error)
@@ -394,11 +401,14 @@
 		io.fn_put = ntfs_put;
 		io.fn_get = 0;
 		io.param = buf + delta;
-		io.size = len = min(int, datasize, 1024 - delta);
+		len = 1024 - delta;
+		if (len > datasize)
+			len = datasize;
 		ntfs_debug(DEBUG_FILE2, "load_attributes %x: len = %i\n",
 						ino->i_number, len);
 		ntfs_debug(DEBUG_FILE2, "load_attributes %x: delta = %i\n",
 						ino->i_number, delta);
+		io.size = len;
 		if (ntfs_read_attr(ino, vol->at_attribute_list, 0, offset,
 				   &io))
 			ntfs_error("error in load_attributes\n");
@@ -472,7 +482,7 @@
 /* Check and fixup a MFT record. */
 int ntfs_check_mft_record(ntfs_volume *vol, char *record)
 {
-	return ntfs_fixup_record(vol, record, "FILE", vol->mft_record_size);
+	return ntfs_fixup_record(record, "FILE", vol->mft_record_size);
 }
 
 /* Return (in result) the value indicating the next available attribute 
@@ -540,8 +550,7 @@
 	ntfs_attribute *attr = ntfs_find_attr(ino, type, name);
 	if (!attr)
 		return 0;
-	return
-		attr->resident;
+	return attr->resident;
 }
 	
 /*
@@ -702,10 +711,10 @@
 				return error;
 			return ntfs_read_zero(dest, l - chunk);
 		}
-		if (attr->compressed)
+		if (attr->flags & ATTR_IS_COMPRESSED)
 			return ntfs_read_compressed(ino, attr, offset, dest);
 	} else {
-		if (attr->compressed)
+		if (attr->flags & ATTR_IS_COMPRESSED)
 			return ntfs_write_compressed(ino, attr, offset, dest);
 	}
 	vcn = 0;
@@ -720,7 +729,7 @@
 			"inode = 0x%x, rnum = %i, offset = 0x%Lx, vcn = , 0x%x"
 			"s_vcn = 0x%x\n", ino->i_number, rnum, offset, vcn,
 			s_vcn);
-		/*FIXME: Should extend runlist. */
+		/*FIXME: Should extend run list. */
 		return -EOPNOTSUPP;
 	}
 	copied = 0;
@@ -729,8 +738,9 @@
 		cluster = attr->d.r.runlist[rnum].cluster;
 		len = attr->d.r.runlist[rnum].len;
 		s_cluster = cluster + s_vcn - vcn;
-		chunk = min(s64, ((__s64)(vcn + len) << clustersizebits) - offset,
-									l);
+		chunk = ((__s64)(vcn + len) << clustersizebits) - offset;
+		if (chunk > l)
+			chunk = l;
 		dest->size = chunk;
 		error = ntfs_getput_clusters(ino->vol, s_cluster, offset -
 				((__s64)s_vcn << clustersizebits), dest);
@@ -787,7 +797,8 @@
 	
 	data = ntfs_find_attr(ino, ino->vol->at_data, 0);
 	/* It's hard to give an error code. */
-	if (!data || data->resident || data->compressed)
+	if (!data || data->resident || data->flags & (ATTR_IS_COMPRESSED |
+			ATTR_IS_ENCRYPTED))
 		return -1;
 	if (data->size <= (__s64)vcn << ino->vol->cluster_size_bits)
 		return -1;
@@ -845,15 +856,15 @@
 }
 
 /**
- * layout_runs - compress runlist into mapping pairs array
- * @attr:	attribute containing the runlist to compress
+ * layout_runs - compress run list into mapping pairs array
+ * @attr:	attribute containing the run list to compress
  * @rec:	destination buffer to hold the mapping pairs array
  * @offs:	current position in @rec (in/out variable)
  * @size:	size of the buffer @rec
  *
- * layout_runs walks the runlist in @attr, compresses it and writes it out the
+ * layout_runs walks the run list in @attr, compresses it and writes it out the
  * resulting mapping pairs array into @rec (up to a maximum of @size bytes are
- * written). On entry @offs is the offset in @rec at which to begin writting the
+ * written). On entry @offs is the offset in @rec at which to begin writing the
  * mapping pairs array. On exit, it contains the offset in @rec of the first
  * byte after the end of the mapping pairs array.
  */
@@ -997,14 +1008,14 @@
 		if (size < asize)
 			return -E2BIG;
 		NTFS_PUTU32(buf + 0x10, attr->size);
-		NTFS_PUTU16(buf + 0x16, attr->indexed);
+		NTFS_PUTU8(buf + 0x16, attr->indexed);
 		NTFS_PUTU16(buf + 0x14, hdrsize);
 		if (attr->size)
 			ntfs_memcpy(buf + hdrsize, attr->d.data, attr->size);
 	} else {
 		int error;
 
- 		if (attr->compressed)
+ 		if (attr->flags & ATTR_IS_COMPRESSED)
  			nameoff = 0x48;
  		else
  			nameoff = 0x40;
@@ -1029,7 +1040,7 @@
 		NTFS_PUTS64(buf + 0x28, attr->allocated);
 		NTFS_PUTS64(buf + 0x30, attr->size);
 		NTFS_PUTS64(buf + 0x38, attr->initialized);
-		if (attr->compressed)
+		if (attr->flags & ATTR_IS_COMPRESSED)
 			NTFS_PUTS64(buf + 0x40, attr->compsize);
 	}
 	NTFS_PUTU32(buf, attr->type);
@@ -1037,7 +1048,7 @@
 	NTFS_PUTU8(buf + 8, attr->resident ? 0 : 1);
 	NTFS_PUTU8(buf + 9, attr->namelen);
 	NTFS_PUTU16(buf + 0xa, nameoff);
-	NTFS_PUTU16(buf + 0xc, attr->compressed);
+	NTFS_PUTU16(buf + 0xc, attr->flags);
 	NTFS_PUTU16(buf + 0xe, attr->attrno);
 	if (attr->namelen)
 		ntfs_memcpy(buf + nameoff, attr->name, 2 * attr->namelen);
@@ -1151,14 +1162,24 @@
 	io.fn_get = ntfs_get;
 	io.fn_put = 0;
 	for (i = 0; i < store.count; i++) {
-		ntfs_insert_fixups(store.records[i].record,
-						ino->vol->sector_size);
+		error = ntfs_insert_fixups(store.records[i].record,
+				ino->vol->mft_record_size);
+		if (error) {
+			printk(KERN_ALERT "NTFS: ntfs_update_inode() caught "
+					"corrupt %s mtf record ntfs record "
+					"header. Refusing to write corrupt "
+					"data to disk. Unmount and run chkdsk "
+					"immediately!\n", i ? "extension":
+					"base");
+			deallocate_store(&store);
+			return -EIO;
+		}
 		io.param = store.records[i].record;
 		io.size = ino->vol->mft_record_size;
 		/* FIXME: Is this the right way? */
 		error = ntfs_write_attr(ino->vol->mft_ino, ino->vol->at_data,
-					0, (__s64)store.records[i].recno <<
-					ino->vol->mft_record_size_bits, &io);
+				0, (__s64)store.records[i].recno <<
+				ino->vol->mft_record_size_bits, &io);
 		if (error || io.size != ino->vol->mft_record_size) {
 			/* Big trouble, partially written file. */
 			ntfs_error("Please unmount: Write error in inode "
diff -u --recursive --new-file v2.4.9/linux/fs/ntfs/struct.h linux/fs/ntfs/struct.h
--- v2.4.9/linux/fs/ntfs/struct.h	Wed Jul 25 17:10:24 2001
+++ linux/fs/ntfs/struct.h	Tue Aug 28 06:57:18 2001
@@ -4,6 +4,7 @@
  * Copyright (C) 1997 Régis Duchesne
  * Copyright (C) 2000-2001 Anton Altaparmakov (AIA)
  */
+#include <linux/ntfs_fs.h>
 
 /* Necessary forward definition. */
 struct ntfs_inode;
@@ -28,7 +29,8 @@
 	int namelen;
 	int attrno;
 	__s64 size, allocated, initialized, compsize;
-	int compressed, resident, indexed;
+	ATTR_FLAGS flags;
+	__u8 resident, indexed;
 	int cengine;
 	union {
 		void *data;             /* if resident */
diff -u --recursive --new-file v2.4.9/linux/fs/ntfs/super.c linux/fs/ntfs/super.c
--- v2.4.9/linux/fs/ntfs/super.c	Wed Jul 25 17:10:24 2001
+++ linux/fs/ntfs/super.c	Tue Aug 28 06:57:18 2001
@@ -7,16 +7,18 @@
  * Copyright (C) 2000-2001 Anton Altparmakov (AIA)
  */
 
+#include <linux/ntfs_fs.h>
+#include <linux/errno.h>
+#include <linux/bitops.h>
+#include <linux/module.h>
 #include "ntfstypes.h"
 #include "struct.h"
 #include "super.h"
-
-#include <linux/errno.h>
-#include <linux/bitops.h>
 #include "macros.h"
 #include "inode.h"
 #include "support.h"
 #include "util.h"
+#include <linux/smp_lock.h>
 
 /* All important structures in NTFS use 2 consistency checks:
  * . a magic structure identifier (FILE, INDX, RSTR, RCRD...)
@@ -24,14 +26,18 @@
  *   structure's record should end with the word at offset <n> of the first
  *   sector, and if it is the case, must be replaced with the words following
  *   <n>. The value of <n> and the number of fixups is taken from the fields
- *   at the offsets 4 and 6.
+ *   at the offsets 4 and 6. Note that the sector size is defined as
+ *   NTFS_SECTOR_SIZE and not as the hardware sector size (this is concordant
+ *   with what the Windows NTFS driver does).
  *
- * This function perform these 2 checks, and _fails_ if :
+ * This function perform these 2 checks, and _fails_ if:
+ * . the input size is invalid
+ * . the fixup header is invalid
+ * . the size does not match the number of sectors
  * . the magic identifier is wrong
- * . the size is given and does not match the number of sectors
  * . a fixup is invalid
  */
-int ntfs_fixup_record(ntfs_volume *vol, char *record, char *magic, int size)
+int ntfs_fixup_record(char *record, char *magic, int size)
 {
 	int start, count, offset;
 	ntfs_u16 fixup;
@@ -39,19 +45,24 @@
 	if (!IS_MAGIC(record, magic))
 		return 0;
 	start = NTFS_GETU16(record + 4);
-	count = NTFS_GETU16(record + 6);
-	count--;
-	if(size && vol->sector_size * count != size)
+	count = NTFS_GETU16(record + 6) - 1;
+	if (size & (NTFS_SECTOR_SIZE - 1) || start & 1 ||
+			start + count * 2 > size || size >> 9 != count) {
+		if (size <= 0)
+			printk(KERN_ERR "NTFS: BUG: ntfs_fixup_record() got "
+					"zero size! Please report this to "
+					"linux-ntfs-dev@lists.sf.net\n");
 		return 0;
+	}
 	fixup = NTFS_GETU16(record + start);
 	start += 2;
-	offset = vol->sector_size - 2;
-	while (count--){
+	offset = NTFS_SECTOR_SIZE - 2;
+	while (count--) {
 		if (NTFS_GETU16(record + offset) != fixup)
 			return 0;
 		NTFS_PUTU16(record + offset, NTFS_GETU16(record + start));
 		start += 2;
-		offset += vol->sector_size;
+		offset += NTFS_SECTOR_SIZE;
 	}
 	return 1;
 }
@@ -63,8 +74,9 @@
 int ntfs_init_volume(ntfs_volume *vol, char *boot)
 {
 	int sectors_per_cluster_bits;
+	__s64 ll;
 
-	/* Historical default values, in case we don't load $AttrDef. */
+	/* System defined default values, in case we don't load $AttrDef. */
 	vol->at_standard_information = 0x10;
 	vol->at_attribute_list = 0x20;
 	vol->at_file_name = 0x30;
@@ -77,7 +89,7 @@
 	vol->at_index_allocation = 0xA0;
 	vol->at_bitmap = 0xB0;
 	vol->at_symlink = 0xC0;
-	/* Sector size */
+	/* Sector size. */
 	vol->sector_size = NTFS_GETU16(boot + 0xB);
 	ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->sector_size = 0x%x\n",
 				vol->sector_size);
@@ -127,22 +139,49 @@
 		vol->index_record_size = 1 << -vol->index_clusters_per_record;
 	vol->index_record_size_bits = ffs(vol->index_record_size) - 1;
 	ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->index_record_size = "
-				"0x%x\n", vol->index_record_size); 
+				"0x%x\n", vol->index_record_size);
 	ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->index_record_size_bits "
-				"= 0x%x\n", vol->index_record_size_bits); 
+				"= 0x%x\n", vol->index_record_size_bits);
 	/*
-	 * Check mft and mftmirr locations for 64-bit-ness. NOTE: This is a
-	 * crude check only as many other things could be out of bounds later
-	 * on, but it will catch at least some of the cases, since the mftmirr
-	 * is located in the middle of the volume so if the volume is very
-	 * large the mftmirr probably will be out of 32-bit bounds.
+	 * Get the size of the volume in clusters (ofs 0x28 is nr_sectors) and
+	 * check for 64-bit-ness. Windows currently only uses 32 bits to save
+	 * the clusters so we do the same as it is much faster on 32-bit CPUs.
 	 */
-	vol->mft_lcn = NTFS_GETS64(boot + 0x30);
-	if (vol->mft_lcn >= (__s64)1 << 31 ||
-	    NTFS_GETS64(boot + 0x38) >= (__s64)1 << 31) {
-		ntfs_error("Cannot handle 64-bit clusters yet.\n");
+	ll = NTFS_GETS64(boot + 0x28) >> sectors_per_cluster_bits;
+	if (ll >= (__s64)1 << 31) {
+		ntfs_error("Cannot handle 64-bit clusters. Please inform "
+				"linux-ntfs-dev@lists.sf.net that you got this "
+				"error.\n");
 		return -1;
 	}
+	vol->nr_clusters = (ntfs_cluster_t)ll;
+	ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->nr_clusters = 0x%x\n",
+			vol->nr_clusters);
+	/*
+	 * Determine MFT zone size. FIXME: Need to take into consideration
+	 * where the mft zone starts (at vol->mft_lcn) as vol->mft_zone_end
+	 * needs to be relative to that.
+	 */
+	vol->mft_zone_end = vol->nr_clusters;
+	switch (vol->mft_zone_multiplier) {  /* % of volume size in clusters */
+	case 4:
+		vol->mft_zone_end = vol->mft_zone_end >> 1;	/* 50%   */
+		break;
+	case 3:
+		vol->mft_zone_end = vol->mft_zone_end * 3 >> 3;	/* 37.5% */
+		break;
+	case 2:
+		vol->mft_zone_end = vol->mft_zone_end >> 2;	/* 25%   */
+		break;
+	/* case 1: */
+	default:
+		vol->mft_zone_end = vol->mft_zone_end >> 3;	/* 12.5% */
+		break;
+	}
+	ntfs_debug(DEBUG_FILE3, "ntfs_init_volume: vol->mft_zone_end = %x\n",
+			vol->mft_zone_end);
+	vol->mft_lcn = (ntfs_cluster_t)NTFS_GETS64(boot + 0x30);
+	vol->mft_mirr_lcn = (ntfs_cluster_t)NTFS_GETS64(boot + 0x38);
 	/* This will be initialized later. */
 	vol->upcase = 0;
 	vol->upcase_length = 0;
@@ -304,8 +343,7 @@
 	error = -ENOMEM;
 	ntfs_debug(DEBUG_BSD, "Going to load MFT\n");
 	if (!vol->mft_ino || (error = ntfs_init_inode(vol->mft_ino, vol,
-						      FILE_$Mft)))
-	{
+			FILE_$Mft))) {
 		ntfs_error("Problem loading MFT\n");
 		return error;
 	}
@@ -443,26 +481,48 @@
 	return clusters;
 }
 
-/* Insert the fixups for the record. The number and location of the fixes
- * is obtained from the record header */
-void ntfs_insert_fixups(unsigned char *rec, int secsize)
+/*
+ * Insert the fixups for the record. The number and location of the fixes
+ * is obtained from the record header but we double check with @rec_size and
+ * use that as the upper boundary, if necessary overwriting the count value in
+ * the record header.
+ *
+ * We return 0 on success or -1 if fixup header indicated the beginning of the
+ * update sequence array to be beyond the valid limit.
+ */
+int ntfs_insert_fixups(unsigned char *rec, int rec_size)
 {
-	int first = NTFS_GETU16(rec + 4);
-	int count = NTFS_GETU16(rec + 6);
+	int first;
+	int count;
 	int offset = -2;
-	ntfs_u16 fix = NTFS_GETU16(rec + first);
+	ntfs_u16 fix;
 	
-	fix++;
+	first = NTFS_GETU16(rec + 4);
+	count = (rec_size >> NTFS_SECTOR_BITS) + 1;
+	if (first + count * 2 > NTFS_SECTOR_SIZE - 2) {
+		printk(KERN_CRIT "NTFS: ntfs_insert_fixups() detected corrupt "
+				"NTFS record update sequence array position. - "
+				"Cannot hotfix.\n");
+		return -1;
+	}
+	if (count != NTFS_GETU16(rec + 6)) {
+		printk(KERN_ERR "NTFS: ntfs_insert_fixups() detected corrupt "
+				"NTFS record update sequence array size. - "
+				"Applying hotfix.\n");
+		NTFS_PUTU16(rec + 6, count);
+	}
+	fix = (NTFS_GETU16(rec + first) + 1) & 0xffff;
 	if (fix == 0xffff || !fix)
 		fix = 1;
 	NTFS_PUTU16(rec + first, fix);
 	count--;
 	while (count--) {
 		first += 2;
-		offset += secsize;
+		offset += NTFS_SECTOR_SIZE;
 		NTFS_PUTU16(rec + first, NTFS_GETU16(rec + offset));
 		NTFS_PUTU16(rec + offset, fix);
-	};
+	}
+	return 0;
 }
 
 /* Search the bitmap bits of l bytes for *cnt zero bits. Return the bit number
@@ -475,7 +535,7 @@
 	int bc = 0;
 	int bstart = 0, bstop = 0, found = 0;
 	int start, stop = 0, in = 0;
-	/* special case searching for a single block */
+	/* Special case searching for a single block. */
 	if (*cnt == 1) {
 		while (l && *bits == 0xFF) {
 			bits++;
@@ -501,7 +561,7 @@
 		if (in) {
 			if ((c & 1) == 0)
 				stop++;
-			else { /* end of sequence of zeroes */
+			else { /* End of sequence of zeroes. */
 				in = 0;
 				if (!found || bstop-bstart < stop-start) {
 					bstop = stop; bstart = start;
@@ -514,7 +574,7 @@
 		} else {
 			if (c & 1)
 				start++;
-			else { /*start of sequence*/
+			else { /* Start of sequence. */
 				in = 1;
 				stop = start + 1;
 			}
@@ -523,7 +583,9 @@
 		c >>= 1;
 	}
 	if (in && (!found || bstop - bstart < stop - start)) {
-		bstop = stop; bstart = start; found = 1;
+		bstop = stop;
+		bstart = start;
+		found = 1;
 	}
 	if (!found)
 		return -ENOSPC;
@@ -541,21 +603,21 @@
 
 	io.fn_put = ntfs_put;
 	io.fn_get = ntfs_get;
-	bsize = (cnt + (loc & 7) + 7) >> 3; /* round up to multiple of 8*/
+	bsize = (cnt + (loc & 7) + 7) >> 3; /* Round up to multiple of 8. */
 	bits = ntfs_malloc(bsize);
 	if (!bits)
 		return -ENOMEM;
 	io.param = bits;
 	io.size = bsize;
 	error = ntfs_read_attr(bitmap, bitmap->vol->at_data, 0, loc >> 3, &io);
-	if (error || io.size != bsize){
+	if (error || io.size != bsize) {
 		ntfs_free(bits);
 		return error ? error : -EIO;
 	}
 	/* Now set the bits. */
 	it = bits;
 	locit = loc;
-	while (locit % 8 && cnt) { /* process first byte */
+	while (locit % 8 && cnt) { /* Process first byte. */
 		if (bit)
 			*it |= 1 << (locit % 8);
 		else
@@ -565,13 +627,13 @@
 		if (locit % 8 == 0)
 			it++;
 	}
-	while (cnt > 8) { /*process full bytes */
+	while (cnt > 8) { /* Process full bytes. */
 		*it = bit ? 0xFF : 0;
 		cnt -= 8;
 		locit += 8;
 		it++;
 	}
-	while (cnt) { /*process last byte */
+	while (cnt) { /* Process last byte. */
 		if (bit)
 			*it |= 1 << (locit % 8);
 		else
@@ -579,7 +641,7 @@
 		cnt--;
 		locit++;
 	}
-	/* reset to start */
+	/* Reset to start. */
 	io.param = bits;
 	io.size = bsize;
 	error = ntfs_write_attr(bitmap, bitmap->vol->at_data, 0, loc >> 3, &io);
diff -u --recursive --new-file v2.4.9/linux/fs/ntfs/super.h linux/fs/ntfs/super.h
--- v2.4.9/linux/fs/ntfs/super.h	Wed Jul 25 17:10:24 2001
+++ linux/fs/ntfs/super.h	Tue Aug 28 06:57:18 2001
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 1995-1997 Martin von Löwis
  * Copyright (C) 1996-1997 Régis Duchesne
+ * Copyright (c) 2001 Anton Altaparmakov
  */
 
 #define ALLOC_REQUIRE_LOCATION 1
@@ -18,13 +19,13 @@
 
 int ntfs_release_volume(ntfs_volume *vol);
 
-void ntfs_insert_fixups(unsigned char *rec, int secsize);
+int ntfs_insert_fixups(unsigned char *rec, int rec_size);
 
-int ntfs_fixup_record(ntfs_volume *vol, char *record, char *magic, int size);
+int ntfs_fixup_record(char *record, char *magic, int size);
 
 int ntfs_allocate_clusters(ntfs_volume *vol, ntfs_cluster_t *location,
-			   int *count, int flags);
+		int *count, int flags);
 
 int ntfs_deallocate_clusters(ntfs_volume *vol, ntfs_cluster_t location,
-			     int count);
+		int count);
 
diff -u --recursive --new-file v2.4.9/linux/fs/ntfs/support.c linux/fs/ntfs/support.c
--- v2.4.9/linux/fs/ntfs/support.c	Mon Aug 27 12:41:46 2001
+++ linux/fs/ntfs/support.c	Tue Aug 28 06:57:18 2001
@@ -17,10 +17,7 @@
 #include "util.h"
 #include "inode.h"
 #include "macros.h"
-
-#ifndef NLS_MAX_CHARSET_SIZE
 #include <linux/nls.h>
-#endif
 
 static char print_buf[1024];
 
@@ -108,8 +105,8 @@
         va_list ap;
 
         va_start(ap, fmt);
-        strcpy(print_buf, KERN_ERR);
-        vsprintf(print_buf + 3, fmt, ap);
+        strcpy(print_buf, KERN_ERR "NTFS: ");
+        vsprintf(print_buf + 9, fmt, ap);
         printk(print_buf);
         va_end(ap);
 }
@@ -162,8 +159,8 @@
 	return 0;
 }
 
-int ntfs_getput_clusters(ntfs_volume *vol, int cluster,	ntfs_size_t start_offs,
-			 ntfs_io *buf)
+int ntfs_getput_clusters(ntfs_volume *vol, int cluster, ntfs_size_t start_offs,
+		ntfs_io *buf)
 {
 	struct super_block *sb = NTFS_SB(vol);
 	struct buffer_head *bh;
@@ -173,6 +170,7 @@
 
 	ntfs_debug(DEBUG_OTHER, "%s_clusters %d %d %d\n", 
 		   buf->do_read ? "get" : "put", cluster, start_offs, length);
+	to_copy = vol->cluster_size - start_offs;
 	while (length) {
 		if (!(bh = bread(sb->s_dev, cluster, vol->cluster_size))) {
 			ntfs_debug(DEBUG_OTHER, "%s failed\n",
@@ -180,7 +178,8 @@
 			error = -EIO;
 			goto error_ret;
 		}
-		to_copy = min(unsigned int, vol->cluster_size - start_offs, length);
+		if (to_copy > length)
+			to_copy = length;
 		lock_buffer(bh);
 		if (buf->do_read) {
 			buf->fn_put(buf, bh->b_data + start_offs, to_copy);
@@ -211,10 +210,11 @@
 				}
 			}
 		}
+		brelse(bh);
 		length -= to_copy;
 		start_offs = 0;
+		to_copy = vol->cluster_size;
 		cluster++;
-		brelse(bh);
 	}
 error_ret:
 	return error;
diff -u --recursive --new-file v2.4.9/linux/fs/ntfs/unistr.c linux/fs/ntfs/unistr.c
--- v2.4.9/linux/fs/ntfs/unistr.c	Mon Aug 27 12:41:46 2001
+++ linux/fs/ntfs/unistr.c	Tue Aug 28 06:57:18 2001
@@ -1,6 +1,4 @@
 /*
- * $Id: unistr.c,v 1.4 2001/04/08 03:02:55 antona Exp $
- *
  * unistr.c - Unicode string handling. Part of the Linux-NTFS project.
  *
  * Copyright (c) 2000,2001 Anton Altaparmakov.
@@ -93,11 +91,13 @@
 		       wchar_t *name2, __u32 name2_len,
 		       int ic, int err_val)
 {
-	__u32 cnt;
+	__u32 cnt, min_len;
 	wchar_t c1, c2;
 
-	for (cnt = 0; cnt < min(unsigned int, name1_len, name2_len); ++cnt)
-	{
+	min_len = name1_len;
+	if (min_len > name2_len)
+		min_len = name2_len;
+	for (cnt = 0; cnt < min_len; ++cnt) {
 		c1 = le16_to_cpu(*name1++);
 		c2 = le16_to_cpu(*name2++);
 		if (ic) {
@@ -106,7 +106,7 @@
 			if (c2 < upcase_len)
 				c2 = le16_to_cpu(upcase[c2]);
 		}
-		if (c1 < 64 && legal_ansi_char_array[c1] & 8);
+		if (c1 < 64 && legal_ansi_char_array[c1] & 8)
 			return err_val;
 		if (c1 < c2)
 			return -1;
diff -u --recursive --new-file v2.4.9/linux/fs/ntfs/unistr.h linux/fs/ntfs/unistr.h
--- v2.4.9/linux/fs/ntfs/unistr.h	Wed Jul 25 17:10:24 2001
+++ linux/fs/ntfs/unistr.h	Tue Aug 28 06:57:18 2001
@@ -1,6 +1,4 @@
 /*
- * $Id: unistr.h,v 1.5 2001/04/11 11:49:16 antona Exp $
- *
  * unistr.h - Exports for unicode string handling. Part of the Linux-NTFS
  *	      project.
  *
diff -u --recursive --new-file v2.4.9/linux/fs/partitions/ibm.c linux/fs/partitions/ibm.c
--- v2.4.9/linux/fs/partitions/ibm.c	Sun Aug 12 13:28:00 2001
+++ linux/fs/partitions/ibm.c	Mon Aug 27 14:20:21 2001
@@ -45,67 +45,22 @@
 static int
 get_drive_geometry(int kdev,struct hd_geometry *geo) 
 {
-	int rc = 0;
-	mm_segment_t old_fs;
-	struct file *filp;
-	struct inode *inode;
-        /* find out offset of volume label (partn table) */
-        filp = (struct file *)kmalloc (sizeof(struct file),GFP_KERNEL);
-        if ( filp == NULL ) {
-                printk (KERN_WARNING __FILE__ " ibm_partition: kmalloc failed fo
-r filp\n");
-                return -ENOMEM;
-        }
-        memset(filp,0,sizeof(struct file));
-        filp ->f_mode = 1; /* read only */
-        inode = get_empty_inode();
-	if ( inode == NULL )
-		return -ENOMEM;
-        inode -> i_rdev = kdev;
-	inode -> i_bdev = bdget(kdev_t_to_nr(kdev));
-	rc = blkdev_open(inode,filp);
-        if ( rc == 0 ) {
-		old_fs=get_fs();
-		set_fs(KERNEL_DS);
-		rc = inode-> i_bdev -> bd_op->ioctl (inode, filp, HDIO_GETGEO, 
-						     (unsigned long)(geo))
-			;
-		set_fs(old_fs);
-	}
-	blkdev_put(inode->i_bdev,BDEV_FILE);
+	struct block_device *bdev = bdget(kdev_t_to_nr(kdev));
+	int rc = blkdev_get(bdev, 0, 1, BDEV_FILE);
+        if ( rc == 0 )
+		rc = ioctl_by_bdev(bdev, HDIO_GETGEO, (unsigned long)geo);
+	blkdev_put(bdev,BDEV_FILE);
 	return rc;
 }
 
 static int
 get_drive_info(int kdev,dasd_information_t *info) 
 {
-	int rc = 0;
-	mm_segment_t old_fs;
-	struct file *filp;
-	struct inode *inode;
-        /* find out offset of volume label (partn table) */
-        filp = (struct file *)kmalloc (sizeof(struct file),GFP_KERNEL);
-        if ( filp == NULL ) {
-                printk (KERN_WARNING __FILE__ " ibm_partition: kmalloc failed fo
-r filp\n");
-                return -ENOMEM;
-        }
-        memset(filp,0,sizeof(struct file));
-        filp ->f_mode = 1; /* read only */
-        inode = get_empty_inode();
-	if ( inode == NULL )
-		return -ENOMEM;
-        inode -> i_rdev = kdev;
-	inode -> i_bdev = bdget(kdev_t_to_nr(kdev));
-        rc = blkdev_open(inode,filp);
-        if ( rc == 0 ) {
-		old_fs=get_fs();
-		set_fs(KERNEL_DS);
-		rc = inode-> i_bdev -> bd_op->ioctl (inode, filp, BIODASDINFO, 
-						     (unsigned long)(info));
-		set_fs(old_fs);
-	}
-	blkdev_put(inode->i_bdev,BDEV_FILE);
+	struct block_device *bdev = bdget(kdev_t_to_nr(kdev));
+	int rc = blkdev_get(bdev, 0, 1, BDEV_FILE);
+        if ( rc == 0 )
+		rc = ioctl_by_bdev(bdev, BIODASDINFO, (unsigned long)(info));
+	blkdev_put(bdev,BDEV_FILE);
 	return rc;
 }
 
diff -u --recursive --new-file v2.4.9/linux/fs/pipe.c linux/fs/pipe.c
--- v2.4.9/linux/fs/pipe.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/pipe.c	Tue Aug 28 10:56:06 2001
@@ -630,8 +630,7 @@
 	return sb;
 }
 
-static DECLARE_FSTYPE(pipe_fs_type, "pipefs", pipefs_read_super,
-	FS_NOMOUNT|FS_SINGLE);
+static DECLARE_FSTYPE(pipe_fs_type, "pipefs", pipefs_read_super, FS_NOMOUNT);
 
 static int __init init_pipe_fs(void)
 {
@@ -650,7 +649,7 @@
 static void __exit exit_pipe_fs(void)
 {
 	unregister_filesystem(&pipe_fs_type);
-	kern_umount(pipe_mnt);
+	mntput(pipe_mnt);
 }
 
 module_init(init_pipe_fs)
diff -u --recursive --new-file v2.4.9/linux/fs/proc/proc_misc.c linux/fs/proc/proc_misc.c
--- v2.4.9/linux/fs/proc/proc_misc.c	Wed Jul 25 17:10:24 2001
+++ linux/fs/proc/proc_misc.c	Tue Aug 28 07:11:33 2001
@@ -573,7 +573,7 @@
 			entry->size = (1+prof_len) * sizeof(unsigned int);
 		}
 	}
-#ifdef __powerpc__
+#ifdef CONFIG_PPC32
 	{
 		extern struct file_operations ppc_htab_operations;
 		entry = create_proc_entry("ppc_htab", S_IRUGO|S_IWUSR, NULL);
diff -u --recursive --new-file v2.4.9/linux/fs/super.c linux/fs/super.c
--- v2.4.9/linux/fs/super.c	Sun Aug 12 13:28:00 2001
+++ linux/fs/super.c	Tue Aug 28 10:56:06 2001
@@ -122,6 +122,7 @@
 		return -EINVAL;
 	if (fs->next)
 		return -EBUSY;
+	INIT_LIST_HEAD(&fs->fs_supers);
 	write_lock(&file_systems_lock);
 	p = find_filesystem(fs->name);
 	if (*p)
@@ -387,8 +388,6 @@
 	spin_lock(&dcache_lock);
 	list_add(&mnt->mnt_list, vfsmntlist.prev);
 	spin_unlock(&dcache_lock);
-	if (sb->s_type->fs_flags & FS_SINGLE)
-		get_filesystem(sb->s_type);
 out:
 	return mnt;
 }
@@ -435,8 +434,6 @@
 	list_add(&mnt->mnt_list, vfsmntlist.prev);
 	spin_unlock(&dcache_lock);
 	up(&nd->dentry->d_inode->i_zombie);
-	if (mnt->mnt_sb->s_type->fs_flags & FS_SINGLE)
-		get_filesystem(mnt->mnt_sb->s_type);
 	mntget(mnt);
 	return 0;
 fail:
@@ -669,6 +666,7 @@
 
 static void put_super(struct super_block *sb)
 {
+	atomic_dec(&sb->s_active);
 	up_write(&sb->s_umount);
 	__put_super(sb);
 }
@@ -735,10 +733,6 @@
 	s = find_super(dev);
 	if (s) {
 		spin_unlock(&sb_lock);
-		/* Yes, it sucks. As soon as we get refcounting... */
-		/* Almost there - next two lines will go away RSN */
-		lock_super(s);
-		unlock_super(s);
 		down_read(&s->s_umount);
 		if (s->s_root)
 			return s;
@@ -792,6 +786,7 @@
 		INIT_LIST_HEAD(&s->s_dirty);
 		INIT_LIST_HEAD(&s->s_locked_inodes);
 		INIT_LIST_HEAD(&s->s_files);
+		INIT_LIST_HEAD(&s->s_instances);
 		init_rwsem(&s->s_umount);
 		sema_init(&s->s_lock, 1);
 		s->s_count = 1;
@@ -819,7 +814,10 @@
 	s->s_type = type;
 	spin_lock(&sb_lock);
 	list_add (&s->s_list, super_blocks.prev);
+	list_add (&s->s_instances, &type->fs_supers);
+	s->s_count += S_BIAS;
 	spin_unlock(&sb_lock);
+	down_write(&s->s_umount);
 	lock_super(s);
 	if (!type->read_super(s, data, silent))
 		goto out_fail;
@@ -835,11 +833,12 @@
 	s->s_bdev = 0;
 	s->s_type = NULL;
 	unlock_super(s);
-	atomic_dec(&s->s_active);
 	spin_lock(&sb_lock);
 	list_del(&s->s_list);
+	list_del(&s->s_instances);
+	s->s_count -= S_BIAS;
 	spin_unlock(&sb_lock);
-	__put_super(s);
+	put_super(s);
 	return NULL;
 }
 
@@ -871,16 +870,38 @@
 			kdevname(dev));
 }
 
+static int grab_super(struct super_block *sb)
+{
+	sb->s_count++;
+	atomic_inc(&sb->s_active);
+	spin_unlock(&sb_lock);
+	down_write(&sb->s_umount);
+	if (sb->s_root) {
+		spin_lock(&sb_lock);
+		if (sb->s_count > S_BIAS) {
+			sb->s_count--;
+			spin_unlock(&sb_lock);
+			return 1;
+		}
+		spin_unlock(&sb_lock);
+	}
+	put_super(sb);
+	return 0;
+}
+
 static struct super_block *get_sb_bdev(struct file_system_type *fs_type,
 	char *dev_name, int flags, void * data)
 {
 	struct inode *inode;
 	struct block_device *bdev;
 	struct block_device_operations *bdops;
-	struct super_block * sb;
+	struct super_block * s;
 	struct nameidata nd;
+	struct list_head *p;
 	kdev_t dev;
 	int error = 0;
+	mode_t mode = FMODE_READ; /* we always need it ;-) */
+
 	/* What device it is? */
 	if (!dev_name || !*dev_name)
 		return ERR_PTR(-EINVAL);
@@ -901,50 +922,77 @@
 	/* Done with lookups, semaphore down */
 	down(&mount_sem);
 	dev = to_kdev_t(bdev->bd_dev);
-	sb = get_super(dev);
-	if (sb) {
-		if (fs_type == sb->s_type &&
-		    ((flags ^ sb->s_flags) & MS_RDONLY) == 0) {
-/*
- * We are heavily relying on mount_sem here. We _will_ get rid of that
- * ugliness RSN (and then atomicity of ->s_active will play), but first
- * we need to get rid of "reuse" branch of get_empty_super() and that
- * requires reference counters. Chicken and egg problem, but fortunately
- * we can use the fact that right now all accesses to ->s_active are
- * under mount_sem.
- */
-			if (atomic_read(&sb->s_active)) {
-				spin_lock(&sb_lock);
-				sb->s_count--;
-				spin_unlock(&sb_lock);
-			}
-			atomic_inc(&sb->s_active);
-			up_read(&sb->s_umount);
-			path_release(&nd);
-			return sb;
-		}
-		drop_super(sb);
-	} else {
-		mode_t mode = FMODE_READ; /* we always need it ;-) */
-		if (!(flags & MS_RDONLY))
-			mode |= FMODE_WRITE;
-		error = blkdev_get(bdev, mode, 0, BDEV_FS);
-		if (error)
-			goto out;
-		check_disk_change(dev);
-		error = -EACCES;
-		if (!(flags & MS_RDONLY) && is_read_only(dev))
+	if (!(flags & MS_RDONLY))
+		mode |= FMODE_WRITE;
+	error = blkdev_get(bdev, mode, 0, BDEV_FS);
+	if (error)
+		goto out;
+	check_disk_change(dev);
+	error = -EACCES;
+	if (!(flags & MS_RDONLY) && is_read_only(dev))
+		goto out1;
+
+	error = -ENOMEM;
+	s = alloc_super();
+	if (!s)
+		goto out1;
+	down_write(&s->s_umount);
+
+	error = -EBUSY;
+restart:
+	spin_lock(&sb_lock);
+
+	list_for_each(p, &super_blocks) {
+		struct super_block *old = sb_entry(p);
+		if (old->s_dev != dev)
+			continue;
+		if (old->s_type != fs_type ||
+		    ((flags ^ old->s_flags) & MS_RDONLY)) {
+			spin_unlock(&sb_lock);
+			put_super(s);
 			goto out1;
-		error = -EINVAL;
-		sb = read_super(dev, bdev, fs_type, flags, data, 0);
-		if (sb) {
-			get_filesystem(fs_type);
-			path_release(&nd);
-			return sb;
 		}
-out1:
+		if (!grab_super(old))
+			goto restart;
+		put_super(s);
 		blkdev_put(bdev, BDEV_FS);
+		path_release(&nd);
+		return old;
 	}
+	s->s_dev = dev;
+	s->s_bdev = bdev;
+	s->s_flags = flags;
+	s->s_type = fs_type;
+	list_add (&s->s_list, super_blocks.prev);
+	list_add (&s->s_instances, &fs_type->fs_supers);
+	s->s_count += S_BIAS;
+
+	spin_unlock(&sb_lock);
+
+	error = -EINVAL;
+	lock_super(s);
+	if (!fs_type->read_super(s, data, 0))
+		goto out_fail;
+	unlock_super(s);
+	/* tell bdcache that we are going to keep this one */
+	atomic_inc(&bdev->bd_count);
+	get_filesystem(fs_type);
+	path_release(&nd);
+	return s;
+
+out_fail:
+	s->s_dev = 0;
+	s->s_bdev = 0;
+	s->s_type = NULL;
+	unlock_super(s);
+	spin_lock(&sb_lock);
+	list_del(&s->s_list);
+	list_del(&s->s_instances);
+	s->s_count -= S_BIAS;
+	spin_unlock(&sb_lock);
+	put_super(s);
+out1:
+	blkdev_put(bdev, BDEV_FS);
 out:
 	path_release(&nd);
 	up(&mount_sem);
@@ -975,18 +1023,62 @@
 static struct super_block *get_sb_single(struct file_system_type *fs_type,
 	int flags, void *data)
 {
-	struct super_block * sb;
+	struct super_block * s = alloc_super();
+	if (!s)
+		return ERR_PTR(-ENOMEM);
+	down_write(&s->s_umount);
 	/*
 	 * Get the superblock of kernel-wide instance, but
 	 * keep the reference to fs_type.
 	 */
 	down(&mount_sem);
-	sb = fs_type->kern_mnt->mnt_sb;
-	if (!sb)
-		BUG();
-	atomic_inc(&sb->s_active);
-	do_remount_sb(sb, flags, data);
-	return sb;
+retry:
+	spin_lock(&sb_lock);
+	if (!list_empty(&fs_type->fs_supers)) {
+		struct super_block *old;
+		old = list_entry(fs_type->fs_supers.next, struct super_block,
+				s_instances);
+		if (!grab_super(old))
+			goto retry;
+		put_super(s);
+		do_remount_sb(old, flags, data);
+		return old;
+	} else {
+		kdev_t dev = get_unnamed_dev();
+		if (!dev) {
+			put_super(s);
+			up(&mount_sem);
+			return ERR_PTR(-EMFILE);
+		}
+		s->s_dev = dev;
+		s->s_flags = flags;
+		s->s_type = fs_type;
+		list_add (&s->s_list, super_blocks.prev);
+		list_add (&s->s_instances, &fs_type->fs_supers);
+		s->s_count += S_BIAS;
+		spin_unlock(&sb_lock);
+		lock_super(s);
+		if (!fs_type->read_super(s, data, 0))
+			goto out_fail;
+		unlock_super(s);
+		get_filesystem(fs_type);
+		return s;
+
+	out_fail:
+		s->s_dev = 0;
+		s->s_bdev = 0;
+		s->s_type = NULL;
+		unlock_super(s);
+		spin_lock(&sb_lock);
+		list_del(&s->s_list);
+		list_del(&s->s_instances);
+		s->s_count -= S_BIAS;
+		spin_unlock(&sb_lock);
+		put_super(s);
+		put_unnamed_dev(dev);
+		up(&mount_sem);
+		return ERR_PTR(-EINVAL);
+	}
 }
 
 static void kill_super(struct super_block *sb)
@@ -997,8 +1089,12 @@
 	struct file_system_type *fs = sb->s_type;
 	struct super_operations *sop = sb->s_op;
 
-	if (!atomic_dec_and_test(&sb->s_active))
+	if (!atomic_dec_and_lock(&sb->s_active, &sb_lock))
 		return;
+
+	sb->s_count -= S_BIAS;
+	spin_unlock(&sb_lock);
+
 	down_write(&sb->s_umount);
 	lock_kernel();
 	sb->s_root = NULL;
@@ -1037,7 +1133,9 @@
 		put_unnamed_dev(dev);
 	spin_lock(&sb_lock);
 	list_del(&sb->s_list);
+	list_del(&sb->s_instances);
 	spin_unlock(&sb_lock);
+	atomic_inc(&sb->s_active);
 	put_super(sb);
 }
 
@@ -1056,7 +1154,7 @@
 	if (flags & MS_RDONLY)
 		acct_auto_close(sb->s_dev);
 	shrink_dcache_sb(sb);
-	fsync_dev(sb->s_dev);
+	fsync_super(sb);
 	/* If we are remounting RDONLY, make sure there are no rw files open */
 	if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY))
 		if (!fs_may_remount_ro(sb))
@@ -1083,27 +1181,24 @@
 {
 	struct super_block *sb;
 	struct vfsmount *mnt = alloc_vfsmnt();
-	kdev_t dev;
 
 	if (!mnt)
 		return ERR_PTR(-ENOMEM);
 
-	dev = get_unnamed_dev();
-	if (!dev) {
-		kmem_cache_free(mnt_cache, mnt);
-		return ERR_PTR(-EMFILE);
-	}
-	sb = read_super(dev, NULL, type, 0, NULL, 0);
-	if (!sb) {
-		put_unnamed_dev(dev);
+	if (type->fs_flags & FS_SINGLE)
+		sb = get_sb_single(type, 0, NULL);
+	else
+		sb = get_sb_nodev(type, 0, NULL);
+	if (IS_ERR(sb)) {
 		kmem_cache_free(mnt_cache, mnt);
-		return ERR_PTR(-EINVAL);
+		return (struct vfsmount *)sb;
 	}
 	mnt->mnt_sb = sb;
 	mnt->mnt_root = dget(sb->s_root);
 	mnt->mnt_mountpoint = mnt->mnt_root;
 	mnt->mnt_parent = mnt;
-	type->kern_mnt = mnt;
+	up_write(&sb->s_umount);
+	up(&mount_sem);
 	return mnt;
 }
 
@@ -1140,8 +1235,11 @@
 		 * Special case for "unmounting" root ...
 		 * we just try to remount it readonly.
 		 */
-		if (!(sb->s_flags & MS_RDONLY))
+		if (!(sb->s_flags & MS_RDONLY)) {
+			down_write(&sb->s_umount);
 			retval = do_remount_sb(sb, MS_RDONLY, 0);
+			up_write(&sb->s_umount);
+		}
 		return retval;
 	}
 
@@ -1152,8 +1250,6 @@
 			spin_unlock(&dcache_lock);
 			return -EBUSY;
 		}
-		if (sb->s_type->fs_flags & FS_SINGLE)
-			put_filesystem(sb->s_type);
 		detach_mnt(mnt, &parent_nd);
 		list_del(&mnt->mnt_list);
 		spin_unlock(&dcache_lock);
@@ -1317,13 +1413,19 @@
 
 static int do_remount(struct nameidata *nd, int flags, char *data)
 {
+	int err;
+	struct super_block * sb = nd->mnt->mnt_sb;
+
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
 
 	if (nd->dentry != nd->mnt->mnt_root)
 		return -EINVAL;
 
-	return do_remount_sb(nd->mnt->mnt_sb, flags, data);
+	down_write(&sb->s_umount);
+	err = do_remount_sb(sb, flags, data);
+	up_write(&sb->s_umount);
+	return err;
 }
 
 static int do_add_mount(struct nameidata *nd, char *type, int flags,
@@ -1379,6 +1481,7 @@
 	mnt->mnt_root = dget(sb->s_root);
 	mnt->mnt_mountpoint = mnt->mnt_root;
 	mnt->mnt_parent = mnt;
+	up_write(&sb->s_umount);
 
 	/* Something was mounted here while we slept */
 	while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry))
@@ -1639,6 +1742,7 @@
 		fs_type = sb->s_type;
 		atomic_inc(&sb->s_active);
 		up_read(&sb->s_umount);
+		down_write(&sb->s_umount);
 		goto mount_it;
 	}
 
@@ -1659,6 +1763,8 @@
 	panic("VFS: Unable to mount root fs on %s", kdevname(ROOT_DEV));
 
 mount_it:
+	/* FIXME */
+	up_write(&sb->s_umount);
 	printk ("VFS: Mounted root (%s filesystem)%s.\n",
 		fs_type->name,
 		(sb->s_flags & MS_RDONLY) ? " readonly" : "");
diff -u --recursive --new-file v2.4.9/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c
--- v2.4.9/linux/fs/umsdos/dir.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/umsdos/dir.c	Tue Aug 28 08:16:07 2001
@@ -67,7 +67,7 @@
 static int umsdos_dir_once (	void *buf,
 				const char *name,
 				int len,
-				off_t offset,
+				loff_t offset,
 				ino_t ino,
 				unsigned type)
 {
diff -u --recursive --new-file v2.4.9/linux/fs/umsdos/emd.c linux/fs/umsdos/emd.c
--- v2.4.9/linux/fs/umsdos/emd.c	Tue Mar  6 19:44:37 2001
+++ linux/fs/umsdos/emd.c	Mon Aug 27 08:13:05 2001
@@ -259,10 +259,10 @@
 		p->ctime = cpu_to_le32(entry->ctime);
 		p->rdev = cpu_to_le16(entry->rdev);
 		p->mode = cpu_to_le16(entry->mode);
-		memcpy(p->name,entry->name,
+		memcpy(p->spare,entry->spare,
 			(char *)(page_address(page) + PAGE_CACHE_SIZE) - p->spare);
 		memcpy(page_address(page2),
-				entry->spare+PAGE_CACHE_SIZE-offs,
+				((char*)entry)+PAGE_CACHE_SIZE-offs,
 				offs+info->recsize-PAGE_CACHE_SIZE);
 		ret = mapping->a_ops->commit_write(NULL,page2,0,
 					offs+info->recsize-PAGE_CACHE_SIZE);
diff -u --recursive --new-file v2.4.9/linux/fs/umsdos/ioctl.c linux/fs/umsdos/ioctl.c
--- v2.4.9/linux/fs/umsdos/ioctl.c	Wed Apr 18 11:49:13 2001
+++ linux/fs/umsdos/ioctl.c	Tue Aug 28 08:16:07 2001
@@ -28,7 +28,7 @@
 				     void *buf,
 				     const char *name,
 				     int name_len,
-				     off_t offset,
+				     loff_t offset,
 				     ino_t ino,
 				     unsigned type)
 {
diff -u --recursive --new-file v2.4.9/linux/fs/umsdos/rdir.c linux/fs/umsdos/rdir.c
--- v2.4.9/linux/fs/umsdos/rdir.c	Fri Feb  9 11:29:44 2001
+++ linux/fs/umsdos/rdir.c	Tue Aug 28 08:16:07 2001
@@ -32,7 +32,7 @@
 static int rdir_filldir (	void *buf,
 				const char *name,
 				int name_len,
-				off_t offset,
+				loff_t offset,
 				ino_t ino,
 				unsigned int d_type)
 {
diff -u --recursive --new-file v2.4.9/linux/include/asm-alpha/keyboard.h linux/include/asm-alpha/keyboard.h
--- v2.4.9/linux/include/asm-alpha/keyboard.h	Mon Aug 27 12:41:47 2001
+++ linux/include/asm-alpha/keyboard.h	Tue Aug 28 07:09:44 2001
@@ -22,7 +22,6 @@
 			   char raw_mode);
 extern char pckbd_unexpected_up(unsigned char keycode);
 extern void pckbd_leds(unsigned char leds);
-extern int pckbd_rate(struct kbd_repeat *rep);
 extern void pckbd_init_hw(void);
 extern unsigned char pckbd_sysrq_xlate[128];
 
@@ -31,7 +30,6 @@
 #define kbd_translate		pckbd_translate
 #define kbd_unexpected_up	pckbd_unexpected_up
 #define kbd_leds		pckbd_leds
-#define kbd_rate               pckbd_rate
 #define kbd_init_hw		pckbd_init_hw
 #define kbd_sysrq_xlate		pckbd_sysrq_xlate
 
diff -u --recursive --new-file v2.4.9/linux/include/asm-i386/keyboard.h linux/include/asm-i386/keyboard.h
--- v2.4.9/linux/include/asm-i386/keyboard.h	Mon Aug 27 12:41:48 2001
+++ linux/include/asm-i386/keyboard.h	Tue Aug 28 07:09:44 2001
@@ -27,7 +27,6 @@
 			   char raw_mode);
 extern char pckbd_unexpected_up(unsigned char keycode);
 extern void pckbd_leds(unsigned char leds);
-extern int pckbd_rate(struct kbd_repeat *rep);
 extern void pckbd_init_hw(void);
 extern void pckbd_pm_resume(void);
 extern unsigned char pckbd_sysrq_xlate[128];
@@ -37,7 +36,6 @@
 #define kbd_translate		pckbd_translate
 #define kbd_unexpected_up	pckbd_unexpected_up
 #define kbd_leds		pckbd_leds
-#define kbd_rate		pckbd_rate
 #define kbd_init_hw		pckbd_init_hw
 #define kbd_sysrq_xlate		pckbd_sysrq_xlate
 
diff -u --recursive --new-file v2.4.9/linux/include/asm-i386/kmap_types.h linux/include/asm-i386/kmap_types.h
--- v2.4.9/linux/include/asm-i386/kmap_types.h	Thu Apr 12 12:11:39 2001
+++ linux/include/asm-i386/kmap_types.h	Mon Aug 27 07:43:02 2001
@@ -6,6 +6,8 @@
 	KM_BOUNCE_WRITE,
 	KM_SKB_DATA,
 	KM_SKB_DATA_SOFTIRQ,
+	KM_USER0,
+	KM_USER1,
 	KM_TYPE_NR
 };
 
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/atomic.h linux/include/asm-ppc/atomic.h
--- v2.4.9/linux/include/asm-ppc/atomic.h	Wed Jul 25 17:10:25 2001
+++ linux/include/asm-ppc/atomic.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.atomic.h 1.8 05/17/01 18:14:24 cort
+ * BK Id: SCCS/s.atomic.h 1.13 08/21/01 16:07:48 trini
  */
 /*
  * PowerPC atomic operations
@@ -7,6 +7,7 @@
 
 #ifndef _ASM_PPC_ATOMIC_H_ 
 #define _ASM_PPC_ATOMIC_H_
+#ifdef __KERNEL__
 
 typedef struct { volatile int counter; } atomic_t;
 
@@ -18,75 +19,137 @@
 extern void atomic_clear_mask(unsigned long mask, unsigned long *addr);
 extern void atomic_set_mask(unsigned long mask, unsigned long *addr);
 
-static __inline__ int atomic_add_return(int a, atomic_t *v)
+#ifdef CONFIG_SMP
+#define SMP_ISYNC	"\n\tisync"
+#else
+#define SMP_ISYNC
+#endif
+
+static __inline__ void atomic_add(int a, atomic_t *v)
 {
 	int t;
 
-	__asm__ __volatile__("\n\
-1:	lwarx	%0,0,%3\n\
+	__asm__ __volatile__(
+"1:	lwarx	%0,0,%3		# atomic_add\n\
 	add	%0,%2,%0\n\
 	stwcx.	%0,0,%3\n\
 	bne-	1b"
 	: "=&r" (t), "=m" (v->counter)
-	: "r" (a), "r" (v), "m" (v->counter)
+	: "r" (a), "r" (&v->counter), "m" (v->counter)
 	: "cc");
+}
+
+static __inline__ int atomic_add_return(int a, atomic_t *v)
+{
+	int t;
+
+	__asm__ __volatile__(
+"1:	lwarx	%0,0,%2		# atomic_add_return\n\
+	add	%0,%1,%0\n\
+	stwcx.	%0,0,%2\n\
+	bne-	1b"
+	SMP_ISYNC
+	: "=&r" (t)
+	: "r" (a), "r" (&v->counter)
+	: "cc", "memory");
 
 	return t;
 }
 
-static __inline__ int atomic_sub_return(int a, atomic_t *v)
+static __inline__ void atomic_sub(int a, atomic_t *v)
 {
 	int t;
 
-	__asm__ __volatile__("\n\
-1:	lwarx	%0,0,%3\n\
+	__asm__ __volatile__(
+"1:	lwarx	%0,0,%3		# atomic_sub\n\
 	subf	%0,%2,%0\n\
 	stwcx.	%0,0,%3\n\
 	bne-	1b"
 	: "=&r" (t), "=m" (v->counter)
-	: "r" (a), "r" (v), "m" (v->counter)
+	: "r" (a), "r" (&v->counter), "m" (v->counter)
 	: "cc");
+}
+
+static __inline__ int atomic_sub_return(int a, atomic_t *v)
+{
+	int t;
+
+	__asm__ __volatile__(
+"1:	lwarx	%0,0,%2		# atomic_sub_return\n\
+	subf	%0,%1,%0\n\
+	stwcx.	%0,0,%2\n\
+	bne-	1b"
+	SMP_ISYNC
+	: "=&r" (t)
+	: "r" (a), "r" (&v->counter)
+	: "cc", "memory");
 
 	return t;
 }
 
-static __inline__ int atomic_inc_return(atomic_t *v)
+static __inline__ void atomic_inc(atomic_t *v)
 {
 	int t;
 
-	__asm__ __volatile__("\n\
-1:	lwarx	%0,0,%2\n\
+	__asm__ __volatile__(
+"1:	lwarx	%0,0,%2		# atomic_inc\n\
 	addic	%0,%0,1\n\
 	stwcx.	%0,0,%2\n\
 	bne-	1b"
 	: "=&r" (t), "=m" (v->counter)
-	: "r" (v), "m" (v->counter)
+	: "r" (&v->counter), "m" (v->counter)
 	: "cc");
+}
+
+static __inline__ int atomic_inc_return(atomic_t *v)
+{
+	int t;
+
+	__asm__ __volatile__(
+"1:	lwarx	%0,0,%1		# atomic_inc_return\n\
+	addic	%0,%0,1\n\
+	stwcx.	%0,0,%1\n\
+	bne-	1b"
+	SMP_ISYNC
+	: "=&r" (t)
+	: "r" (&v->counter)
+	: "cc", "memory");
 
 	return t;
 }
 
-static __inline__ int atomic_dec_return(atomic_t *v)
+static __inline__ void atomic_dec(atomic_t *v)
 {
 	int t;
 
-	__asm__ __volatile__("\n\
-1:	lwarx	%0,0,%2\n\
+	__asm__ __volatile__(
+"1:	lwarx	%0,0,%2		# atomic_dec\n\
 	addic	%0,%0,-1\n\
 	stwcx.	%0,0,%2\n\
-	bne	1b"
+	bne-	1b"
 	: "=&r" (t), "=m" (v->counter)
-	: "r" (v), "m" (v->counter)
+	: "r" (&v->counter), "m" (v->counter)
 	: "cc");
+}
+
+static __inline__ int atomic_dec_return(atomic_t *v)
+{
+	int t;
+
+	__asm__ __volatile__(
+"1:	lwarx	%0,0,%1		# atomic_dec_return\n\
+	addic	%0,%0,-1\n\
+	stwcx.	%0,0,%1\n\
+	bne-	1b"
+	SMP_ISYNC
+	: "=&r" (t)
+	: "r" (&v->counter)
+	: "cc", "memory");
 
 	return t;
 }
 
-#define atomic_add(a, v)		((void) atomic_add_return((a), (v)))
-#define atomic_sub(a, v)		((void) atomic_sub_return((a), (v)))
 #define atomic_sub_and_test(a, v)	(atomic_sub_return((a), (v)) == 0)
-#define atomic_inc(v)			((void) atomic_inc_return((v)))
-#define atomic_dec(v)			((void) atomic_dec_return((v)))
 #define atomic_dec_and_test(v)		(atomic_dec_return((v)) == 0)
 
 /*
@@ -97,16 +160,17 @@
 {
 	int t;
 
-	__asm__ __volatile__("\n"
-"1:	lwarx	%0,0,%2\n"
-"	addic.	%0,%0,-1\n"
-"	blt	2f\n"
-"	stwcx.	%0,0,%2\n"
-"	bne	1b\n"
-"2:"
-	: "=&r" (t), "=m" (v->counter)
-	: "r" (&v->counter), "m" (v->counter)
-	: "cc");
+	__asm__ __volatile__(
+"1:	lwarx	%0,0,%1		# atomic_dec_if_positive\n\
+	addic.	%0,%0,-1\n\
+	blt-	2f\n\
+	stwcx.	%0,0,%1\n\
+	bne-	1b"
+	SMP_ISYNC
+	"\n\
+2:"	: "=&r" (t)
+	: "r" (&v->counter)
+	: "cc", "memory");
 
 	return t;
 }
@@ -116,4 +180,5 @@
 #define smp_mb__before_atomic_inc()	smp_mb()
 #define smp_mb__after_atomic_inc()	smp_mb()
 
+#endif /* __KERNEL__ */
 #endif /* _ASM_PPC_ATOMIC_H_ */
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/bootinfo.h linux/include/asm-ppc/bootinfo.h
--- v2.4.9/linux/include/asm-ppc/bootinfo.h	Tue Jul  3 17:08:21 2001
+++ linux/include/asm-ppc/bootinfo.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.bootinfo.h 1.9 06/13/01 15:28:43 paulus
+ * BK Id: SCCS/s.bootinfo.h 1.11 08/17/01 15:23:17 paulus
  */
 /*
  * Non-machine dependent bootinfo structure.  Basic idea
@@ -31,6 +31,7 @@
 #define BI_INITRD		0x1014
 #define BI_SYSMAP		0x1015
 #define BI_MACHTYPE		0x1016
+#define BI_MEMSIZE		0x1017
 
 #endif /* CONFIG_APUS */
 
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/bseip.h linux/include/asm-ppc/bseip.h
--- v2.4.9/linux/include/asm-ppc/bseip.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/bseip.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.bseip.h 1.7 05/17/01 18:14:24 cort
+ * BK Id: SCCS/s.bseip.h 1.10 08/17/01 15:23:17 paulus
  */
 
 /*
@@ -38,9 +38,5 @@
 /* We don't use the 8259.
 */
 #define NR_8259_INTS	0
-
-/* Machine type
-*/
-#define _MACH_8xx (_MACH_bseip)
 
 #endif
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/btext.h linux/include/asm-ppc/btext.h
--- v2.4.9/linux/include/asm-ppc/btext.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/btext.h	Tue Aug 28 06:58:33 2001
@@ -0,0 +1,37 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * Definitions for using the procedures in btext.c.
+ *
+ * Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ */
+#ifndef __PPC_BTEXT_H
+#define __PPC_BTEXT_H
+#ifdef __KERNEL__
+
+#include <asm/bootx.h>
+
+extern void btext_clearscreen(void);
+extern void btext_flushscreen(void);
+
+extern unsigned long disp_BAT[2];
+
+extern boot_infos_t *disp_bi;
+extern int boot_text_mapped;
+
+void btext_init(boot_infos_t *bi);
+void btext_welcome(boot_infos_t* bi);
+void btext_prepare_BAT(void);
+void btext_setup_display(int width, int height, int depth, int pitch,
+			 unsigned long address);
+void map_boot_text(void);
+void btext_update_display(unsigned long phys, int width, int height,
+			  int depth, int pitch);
+
+void btext_drawchar(char c);
+void btext_drawstring(const char *str);
+void btext_drawhex(unsigned long v);
+
+#endif /* __KERNEL__ */
+#endif /* __PPC_BTEXT_H */
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/cputable.h linux/include/asm-ppc/cputable.h
--- v2.4.9/linux/include/asm-ppc/cputable.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-ppc/cputable.h	Tue Aug 28 06:58:33 2001
@@ -0,0 +1,92 @@
+/*
+ * 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)
+ *
+ *  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 __ASM_PPC_CPUTABLE_H
+#define __ASM_PPC_CPUTABLE_H
+
+/* Exposed to userland CPU features */
+#define PPC_FEATURE_32			0x80000000
+#define PPC_FEATURE_64			0x40000000
+#define PPC_FEATURE_601_INSTR		0x20000000
+#define PPC_FEATURE_HAS_ALTIVEC		0x10000000
+#define PPC_FEATURE_HAS_FPU		0x08000000
+#define PPC_FEATURE_HAS_MMU		0x04000000
+#define PPC_FEATURE_HAS_4xxMAC		0x02000000
+#define PPC_FEATURE_UNIFIED_CACHE	0x01000000
+
+#ifdef __KERNEL__
+
+#ifndef __ASSEMBLY__
+
+/* This structure can grow, it's real size is used by head.S code
+ * via the mkdefs mecanism.
+ */
+struct cpu_spec {
+	/* CPU is matched via (PVR & pvr_mask) == pvr_value */
+	unsigned int	pvr_mask;
+	unsigned int	pvr_value;
+
+	char		*cpu_name;
+	unsigned int	cpu_features;		/* Kernel features */
+	unsigned int	cpu_user_features;	/* Userland features */
+
+	/* cache line sizes */
+	unsigned int	icache_bsize;
+	unsigned int	dcache_bsize;
+
+	/* this is called to initialize various CPU bits like L1 cache,
+	 * BHT, SPD, etc... from head.S before branching to identify_machine
+	 */
+	void		(*cpu_setup)(int cpu_nr);
+};
+
+extern struct cpu_spec		cpu_specs[];
+extern struct cpu_spec		*cur_cpu_spec[];
+
+#endif /* __ASSEMBLY__ */
+
+/* CPU kernel features */
+#define CPU_FTR_SPLIT_ID_CACHE		0x00000001
+#define CPU_FTR_L2CR			0x00000002
+#define CPU_FTR_SPEC7450		0x00000004
+#define CPU_FTR_ALTIVEC			0x00000008
+#define CPU_FTR_TAU			0x00000010
+#define CPU_FTR_CAN_DOZE		0x00000020
+#define CPU_FTR_USE_TB			0x00000040
+#define CPU_FTR_604_PERF_MON		0x00000080
+#define CPU_FTR_601			0x00000100
+#define CPU_FTR_HPTE_TABLE		0x00000200
+
+#ifdef __ASSEMBLY__
+
+#define BEGIN_FTR_SECTION		98:
+
+#define END_FTR_SECTION(msk, val)		\
+99:						\
+	.section __ftr_fixup,"a";		\
+	.align 2;				\
+	.long msk;				\
+	.long val;				\
+	.long 98b;				\
+	.long 99b;				\
+	.previous
+
+#define END_FTR_SECTION_IFSET(msk)	END_FTR_SECTION((msk), (msk))
+#define END_FTR_SECTION_IFCLR(msk)	END_FTR_SECTION((msk), 0)
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_PPC_CPUTABLE_H */
+#endif /* __KERNEL__ */
+
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/elf.h linux/include/asm-ppc/elf.h
--- v2.4.9/linux/include/asm-ppc/elf.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/elf.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.elf.h 1.10 05/17/01 18:14:24 cort
+ * BK Id: SCCS/s.elf.h 1.14 08/21/01 16:07:48 trini
  */
 #ifndef __PPC_ELF_H
 #define __PPC_ELF_H
@@ -7,7 +7,9 @@
 /*
  * ELF register definitions..
  */
+#include <asm/types.h>
 #include <asm/ptrace.h>
+#include <asm/cputable.h>
 
 #define ELF_NGREG	48	/* includes nip, msr, lr, etc. */
 #define ELF_NFPREG	33	/* includes fpscr */
@@ -60,7 +62,7 @@
    instruction set this cpu supports.  This could be done in userspace,
    but it's not easy, and we've already done it here.  */
 
-#define ELF_HWCAP	(0)
+#define ELF_HWCAP	(cur_cpu_spec[0]->cpu_user_features)
 
 /* This yields a string that ld.so will use to load implementation
    specific libraries for optimization.  This is more specific in
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/fads.h linux/include/asm-ppc/fads.h
--- v2.4.9/linux/include/asm-ppc/fads.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/fads.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.fads.h 1.8 05/17/01 18:14:24 cort
+ * BK Id: SCCS/s.fads.h 1.11 08/17/01 15:23:17 paulus
  */
 
 /*
@@ -66,8 +66,4 @@
  */
 #define NR_8259_INTS	0
  
-/* Machine type
- */
-#define _MACH_8xx (_MACH_fads)
-
 #endif
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/feature.h linux/include/asm-ppc/feature.h
--- v2.4.9/linux/include/asm-ppc/feature.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/feature.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.feature.h 1.9 05/17/01 18:14:24 cort
+ * BK Id: SCCS/s.feature.h 1.13 08/19/01 22:23:04 paulus
  */
 /*
  * Definitions for accessing the Feature Control Register (FCR)
@@ -91,6 +91,8 @@
 
 extern void 	feature_set_firewire_power(struct device_node* device, int power);
 extern void 	feature_set_firewire_cable_power(struct device_node* device, int power);
+
+extern void	feature_set_modem_power(struct device_node* device, int power);
 
 extern void	feature_set_airport_power(struct device_node* device, int power);
 
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/ide.h linux/include/asm-ppc/ide.h
--- v2.4.9/linux/include/asm-ppc/ide.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/ide.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.ide.h 1.10 05/17/01 18:14:24 cort
+ * BK Id: SCCS/s.ide.h 1.13 08/20/01 15:25:16 paulus
  */
 /*
  *  linux/include/asm-ppc/ide.h
@@ -29,22 +29,9 @@
 #include <linux/ioport.h>
 #include <asm/io.h>
 
-extern int pmac_ide_ports_known;
-extern ide_ioreg_t pmac_ide_regbase[MAX_HWIFS];
-extern int pmac_ide_irq[MAX_HWIFS];
-extern void pmac_ide_probe(void);
-
-extern int chrp_ide_ports_known;
-extern ide_ioreg_t chrp_ide_regbase[MAX_HWIFS];
-extern ide_ioreg_t chrp_idedma_regbase; /* one for both channels */
-extern unsigned int chrp_ide_irq;
-extern void chrp_ide_probe(void);
-
 extern void ppc_generic_ide_fix_driveid(struct hd_driveid *id);
 
 struct ide_machdep_calls {
-        void        (*insw)(ide_ioreg_t port, void *buf, int ns);
-        void        (*outsw)(ide_ioreg_t port, void *buf, int ns);
         int         (*default_irq)(ide_ioreg_t base);
         ide_ioreg_t (*default_io_base)(int index);
         int         (*ide_check_region)(ide_ioreg_t from, unsigned int extent);
@@ -53,30 +40,16 @@
                                       const char *name);
         void        (*ide_release_region)(ide_ioreg_t from,
                                       unsigned int extent);
-        void        (*fix_driveid)(struct hd_driveid *id);
         void        (*ide_init_hwif)(hw_regs_t *hw,
                                      ide_ioreg_t data_port,
                                      ide_ioreg_t ctrl_port,
                                      int *irq);
-
-        int io_base;
 };
 
 extern struct ide_machdep_calls ppc_ide_md;
 
-void ide_insw(ide_ioreg_t port, void *buf, int ns);
-void ide_outsw(ide_ioreg_t port, void *buf, int ns);
 void ppc_generic_ide_fix_driveid(struct hd_driveid *id);
-
-#undef insw
-#define insw(port, buf, ns) 	do {				\
-	ppc_ide_md.insw((port), (buf), (ns));			\
-} while (0)
-     
-#undef outsw
-#define outsw(port, buf, ns) 	do {				\
-	ppc_ide_md.outsw((port), (buf), (ns));			\
-} while (0)
+#define ide_fix_driveid(id)	ppc_generic_ide_fix_driveid((id))
 
 #undef	SUPPORT_SLOW_DATA_PORTS
 #define	SUPPORT_SLOW_DATA_PORTS	0
@@ -87,10 +60,9 @@
 
 static __inline__ int ide_default_irq(ide_ioreg_t base)
 {
-	if ( ppc_ide_md.default_irq )
+	if (ppc_ide_md.default_irq)
 		return ppc_ide_md.default_irq(base);
-	else
-		return -1;
+	return 0;
 }
 
 static __inline__ ide_ioreg_t ide_default_io_base(int index)
@@ -100,7 +72,7 @@
 	return 0;
 }
 
-static __inline__ void  ide_init_hwif_ports(hw_regs_t *hw,
+static __inline__ void ide_init_hwif_ports(hw_regs_t *hw,
 					   ide_ioreg_t data_port,
 					   ide_ioreg_t ctrl_port, int *irq)
 {
@@ -135,20 +107,14 @@
 
 static __inline__ void ide_request_region (ide_ioreg_t from, unsigned int extent, const char *name)
 {
-	if ( ppc_ide_md.ide_request_region )
+	if (ppc_ide_md.ide_request_region)
 		ppc_ide_md.ide_request_region(from, extent, name);
 }
 
 static __inline__ void ide_release_region (ide_ioreg_t from, unsigned int extent)
 {
-	if ( ppc_ide_md.ide_release_region )
+	if (ppc_ide_md.ide_release_region)
 		ppc_ide_md.ide_release_region(from, extent);
-}
-
-static __inline__ void ide_fix_driveid (struct hd_driveid *id)
-{
-        if ( ppc_ide_md.fix_driveid )
-		ppc_ide_md.fix_driveid(id);
 }
 
 typedef union {
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/io.h linux/include/asm-ppc/io.h
--- v2.4.9/linux/include/asm-ppc/io.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/io.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.io.h 1.7 05/17/01 18:14:24 cort
+ * BK Id: SCCS/s.io.h 1.11 08/28/01 15:48:26 paulus
  */
 #ifdef __KERNEL__
 #ifndef _PPC_IO_H
@@ -24,7 +24,7 @@
 #define PREP_PCI_DRAM_OFFSET 	0x80000000
 
 #if defined(CONFIG_4xx)
-#include <asm/board.h>
+#include <asm/ppc4xx.h>
 #elif defined(CONFIG_8xx)
 #include <asm/mpc8xx.h>
 #elif defined(CONFIG_8260)
@@ -185,15 +185,13 @@
  */
 extern void *__ioremap(unsigned long address, unsigned long size,
 		       unsigned long flags);
-extern void *__ioremap_at(unsigned long phys, unsigned long size,
-			  unsigned long flags);
 extern void *ioremap(unsigned long address, unsigned long size);
 #define ioremap_nocache(addr, size)	ioremap((addr), (size))
 extern void iounmap(void *addr);
 extern unsigned long iopa(unsigned long addr);
-#ifdef CONFIG_APUS
 extern unsigned long mm_ptov(unsigned long addr) __attribute__ ((const));
-#endif
+extern void io_block_mapping(unsigned long virt, unsigned long phys,
+			     unsigned int size, int flags);
 
 /*
  * The PCI bus is inherently Little-Endian.  The PowerPC is being
@@ -245,6 +243,12 @@
 	return (void*) mm_ptov (address);
 #endif
 }
+
+/*
+ * Change "struct page" to physical address.
+ */
+#define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
+#define page_to_bus(page)	(page_to_phys(page) + PCI_DRAM_OFFSET)
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/ivms8.h linux/include/asm-ppc/ivms8.h
--- v2.4.9/linux/include/asm-ppc/ivms8.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/ivms8.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.ivms8.h 1.5 05/17/01 18:14:24 cort
+ * BK Id: SCCS/s.ivms8.h 1.6 08/17/01 15:23:17 paulus
  */
 /*
  * A collection of structures, addresses, and values associated with
@@ -87,9 +87,4 @@
 */
 #define NR_8259_INTS	0
 
-/* Generic 8xx type
-*/
-#define _MACH_8xx (_MACH_ivms8)
-
 #endif	/* __MACH_IVMS8_DEFS */
-
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/keyboard.h linux/include/asm-ppc/keyboard.h
--- v2.4.9/linux/include/asm-ppc/keyboard.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/keyboard.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.keyboard.h 1.5 05/17/01 18:14:24 cort
+ * BK Id: %F% %I% %G% %U% %#%
  */
 /*
  *  linux/include/asm-ppc/keyboard.h
@@ -23,6 +23,7 @@
 
 #include <linux/kernel.h>
 #include <linux/ioport.h>
+#include <linux/kd.h>
 #include <asm/io.h>
 
 #define KEYBOARD_IRQ			1
@@ -67,13 +68,14 @@
 	if ( ppc_md.kbd_leds )
 		ppc_md.kbd_leds(leds);
 }
-  
+
 static inline void kbd_init_hw(void)
 {
 	if ( ppc_md.kbd_init_hw )
 		ppc_md.kbd_init_hw();
 }
 
+#define kbd_rate	(ppc_md.kbd_rate_fn)
 #define kbd_sysrq_xlate	(ppc_md.ppc_kbd_sysrq_xlate)
 
 extern unsigned long SYSRQ_KEY;
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/keylargo.h linux/include/asm-ppc/keylargo.h
--- v2.4.9/linux/include/asm-ppc/keylargo.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/keylargo.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.keylargo.h 1.9 05/17/01 18:14:24 cort
+ * BK Id: SCCS/s.keylargo.h 1.13 08/19/01 22:23:04 paulus
  */
 /*
  * keylargo.h: definitions for using the "KeyLargo" I/O controller chip.
@@ -35,7 +35,12 @@
 #define KL_GPIO_MODEM_RESET		(KEYLARGO_GPIO_0+0x03) /* Pangea */
 #define KL_GPIO_MODEM_POWER		(KEYLARGO_GPIO_0+0x02) /* Pangea */
 
+/* Hrm... this one is only to be used on Pismo. It seeem to also
+ * control the timebase enable on other machines. Still to be
+ * experimented... --BenH.
+ */
 #define KL_GPIO_FW_CABLE_POWER		(KEYLARGO_GPIO_0+0x09)
+#define KL_GPIO_TB_ENABLE		(KEYLARGO_GPIO_0+0x09)
 
 #define KL_GPIO_ETH_PHY_RESET		(KEYLARGO_GPIO_0+0x10)
 
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/machdep.h linux/include/asm-ppc/machdep.h
--- v2.4.9/linux/include/asm-ppc/machdep.h	Tue Jul  3 17:08:21 2001
+++ linux/include/asm-ppc/machdep.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.machdep.h 1.14 06/28/01 16:13:50 paulus
+ * BK Id: SCCS/s.machdep.h 1.19 08/18/01 18:16:33 paulus
  */
 #ifdef __KERNEL__
 #ifndef _PPC_MACHDEP_H
@@ -14,6 +14,7 @@
 struct pt_regs;
 struct pci_bus;	
 struct pci_dev;
+struct kbd_repeat;
 
 struct machdep_calls {
 	void		(*setup_arch)(void);
@@ -44,6 +45,8 @@
 	unsigned long	heartbeat_count;
 
 	unsigned long	(*find_end_of_memory)(void);
+	void		(*setup_io_mappings)(void);
+
   	void		(*progress)(char *, unsigned short);
 
 	unsigned char 	(*nvram_read_val)(int addr);
@@ -58,6 +61,7 @@
 				char raw_mode);
 	char		(*kbd_unexpected_up)(unsigned char keycode);
 	void		(*kbd_leds)(unsigned char leds);
+	int		(*kbd_rate_fn)(struct kbd_repeat *rep);
 	void		(*kbd_init_hw)(void);
 #ifdef CONFIG_MAGIC_SYSRQ
 	unsigned char 	*ppc_kbd_sysrq_xlate;
@@ -83,6 +87,11 @@
 
 	/* 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;
+#endif /* CONFIG_SMP */
 };
 
 extern struct machdep_calls ppc_md;
@@ -101,6 +110,15 @@
 } sys_ctrler_t;
 
 extern sys_ctrler_t sys_ctrler;
+
+#ifdef CONFIG_SMP
+struct smp_ops_t {
+	void  (*message_pass)(int target, int msg, unsigned long data, int wait);
+	int   (*probe)(void);
+	void  (*kick_cpu)(int nr);
+	void  (*setup_cpu)(int nr);
+};
+#endif /* CONFIG_SMP */
 
 #endif /* _PPC_MACHDEP_H */
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/mbx.h linux/include/asm-ppc/mbx.h
--- v2.4.9/linux/include/asm-ppc/mbx.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/mbx.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.mbx.h 1.8 05/17/01 18:14:25 cort
+ * BK Id: SCCS/s.mbx.h 1.11 08/17/01 15:23:17 paulus
  */
 /*
  * A collection of structures, addresses, and values associated with
@@ -94,8 +94,5 @@
 */
 #define NR_8259_INTS	16
 
-/* Generic 8xx type
-*/
-#define _MACH_8xx (_MACH_mbx)
 #endif
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/mmu_context.h linux/include/asm-ppc/mmu_context.h
--- v2.4.9/linux/include/asm-ppc/mmu_context.h	Tue Jul  3 17:08:21 2001
+++ linux/include/asm-ppc/mmu_context.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.mmu_context.h 1.12 06/28/01 15:50:17 paulus
+ * BK Id: SCCS/s.mmu_context.h 1.15 08/16/01 23:00:17 paulus
  */
 #ifdef __KERNEL__
 #ifndef __PPC_MMU_CONTEXT_H
@@ -58,16 +58,19 @@
 #ifdef CONFIG_8xx
 #define NO_CONTEXT      	16
 #define LAST_CONTEXT    	15
+#define FIRST_CONTEXT    	0
 
 #elif CONFIG_4xx
 #define NO_CONTEXT      	256
 #define LAST_CONTEXT    	255
+#define FIRST_CONTEXT    	1
 
 #else
 
 /* PPC 6xx, 7xx CPUs */
 #define NO_CONTEXT      	((mm_context_t) -1)
 #define LAST_CONTEXT    	32767
+#define FIRST_CONTEXT    	1
 #endif
 
 /*
@@ -75,11 +78,12 @@
  * On 32-bit PowerPCs (other than the 8xx embedded chips), this is done by
  * loading up the segment registers for the user part of the address space.
  *
- * On the 8xx parts, the context currently includes the page directory,
- * and once I implement a real TLB context manager this will disappear.
- * The PGD is ignored on other processors. - Dan
+ * Since the PGD is immediately available, it is much faster to simply
+ * pass this along as a second parameter, which is required for 8xx and
+ * can be used for debugging on all processors (if you happen to have
+ * an Abatron).
  */
-extern void set_context(mm_context_t context);
+extern void set_context(mm_context_t context, pgd_t *pgd);
 
 /*
  * Bitmap of contexts in use.
@@ -156,7 +160,7 @@
 {
 	tsk->thread.pgdir = next->pgd;
 	get_mmu_context(next);
-	set_context(next->context);
+	set_context(next->context, next->pgd);
 }
 
 /*
@@ -167,8 +171,10 @@
 {
 	current->thread.pgdir = mm->pgd;
 	get_mmu_context(mm);
-	set_context(mm->context);
+	set_context(mm->context, mm->pgd);
 }
+
+extern void mmu_context_init(void);
 
 #endif /* __PPC_MMU_CONTEXT_H */
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/page.h linux/include/asm-ppc/page.h
--- v2.4.9/linux/include/asm-ppc/page.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/page.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.page.h 1.5 05/17/01 18:14:25 cort
+ * BK Id: SCCS/s.page.h 1.8 08/19/01 20:06:47 paulus
  */
 #ifndef _PPC_PAGE_H
 #define _PPC_PAGE_H
@@ -12,6 +12,7 @@
 #ifdef __KERNEL__
 #include <linux/config.h>
 
+/* Be sure to change arch/ppc/Makefile to match */
 #define PAGE_OFFSET	0xc0000000
 #define KERNELBASE	PAGE_OFFSET
 
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/param.h linux/include/asm-ppc/param.h
--- v2.4.9/linux/include/asm-ppc/param.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/param.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.param.h 1.5 05/17/01 18:14:25 cort
+ * BK Id: SCCS/s.param.h 1.8 08/20/01 22:50:29 paulus
  */
 #ifndef _ASM_PPC_PARAM_H
 #define _ASM_PPC_PARAM_H
@@ -21,7 +21,7 @@
 #define MAXHOSTNAMELEN	64	/* max length of hostname */
 
 #ifdef __KERNEL__
-# define CLOCKS_PER_SEC	100	/* frequency at which times() counts */
+# define CLOCKS_PER_SEC	HZ	/* frequency at which times() counts */
 #endif
 
 #endif
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/processor.h linux/include/asm-ppc/processor.h
--- v2.4.9/linux/include/asm-ppc/processor.h	Sun Aug 12 13:28:00 2001
+++ linux/include/asm-ppc/processor.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.processor.h 1.24 06/15/01 13:56:56 paulus
+ * BK Id: SCCS/s.processor.h 1.28 08/17/01 15:23:17 paulus
  */
 #ifdef __KERNEL__
 #ifndef __ASM_PPC_PROCESSOR_H
@@ -475,33 +475,13 @@
 #define	PVR_8240	0x00810100
 #define	PVR_8260	PVR_8240
 
-
-/* I am just adding a single entry for 8260 boards.  I think we may be
- * able to combine mbx, fads, rpxlite, bseip, and classic into a single
- * generic 8xx as well.  The boards containing these processors are either
- * identical at the processor level (due to the high integration) or so
- * wildly different that testing _machine at run time is best replaced by
- * conditional compilation by board type (found in their respective .h file).
- *	-- Dan
+/* We only need to define a new _MACH_xxx for machines which are part of
+ * a configuration which supports more than one type of different machine.
+ * This is currently limited to CONFIG_ALL_PPC and CHRP/PReP/PMac. -- Tom
  */
 #define _MACH_prep	0x00000001
 #define _MACH_Pmac	0x00000002	/* pmac or pmac clone (non-chrp) */
 #define _MACH_chrp	0x00000004	/* chrp machine */
-#define _MACH_mbx	0x00000008	/* Motorola MBX board */
-#define _MACH_apus	0x00000010	/* amiga with phase5 powerup */
-#define _MACH_fads	0x00000020	/* Motorola FADS board */
-#define _MACH_rpxlite	0x00000040	/* RPCG RPX-Lite 8xx board */
-#define _MACH_bseip	0x00000080	/* Bright Star Engineering ip-Engine */
-#define _MACH_unused0	0x00000100	/* Now free to be used */
-#define _MACH_gemini	0x00000200      /* Synergy Microsystems gemini board */
-#define _MACH_classic	0x00000400	/* RPCG RPX-Classic 8xx board */
-#define _MACH_oak	0x00000800	/* IBM "Oak" 403 eval. board */
-#define _MACH_walnut	0x00001000	/* IBM "Walnut" 405GP eval. board */
-#define _MACH_8260	0x00002000	/* Generic 8260 */
-#define _MACH_tqm860	0x00004000	/* TQM860/L */
-#define _MACH_tqm8xxL	0x00008000	/* TQM8xxL */
-#define _MACH_spd8xx	0x00010000	/* SPD8xx */
-#define _MACH_ivms8	0x00020000	/* IVMS8 */
 
 /* see residual.h for these */
 #define _PREP_Motorola 0x01  /* motorola prep */
@@ -558,11 +538,10 @@
 #ifndef __ASSEMBLY__
 #if defined(CONFIG_ALL_PPC)
 extern int _machine;
-extern int have_of;
-#endif /* CONFIG_ALL_PPC */
 
 /* what kind of prep workstation we are */
 extern int _prep_type;
+
 /*
  * This is used to identify the board type from a given PReP board
  * vendor. Board revision is also made available.
@@ -570,6 +549,9 @@
 extern unsigned char ucSystemType;
 extern unsigned char ucBoardRev;
 extern unsigned char ucBoardRevMaj, ucBoardRevMin;
+#else
+#define _machine 0
+#endif /* CONFIG_ALL_PPC */
 
 struct task_struct;
 void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp);
@@ -681,26 +663,9 @@
 /* In misc.c */
 void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val);
 
-#endif /* ndef ASSEMBLY*/
+#endif /* !__ASSEMBLY__ */
 
-#ifndef CONFIG_ALL_PPC
-#if defined(CONFIG_APUS)
-#define _machine _MACH_apus
-#elif defined(CONFIG_GEMINI)
-#define _machine _MACH_gemini
-#elif defined(CONFIG_OAK)
-#define _machine _MACH_oak
-#elif defined(CONFIG_WALNUT)
-#define _machine _MACH_walnut
-#elif defined(CONFIG_8xx)
-#define _machine _MACH_8xx
-#elif defined(CONFIG_8260)
-#define _machine _MACH_8260
-#else
-#error "Machine not defined correctly"
-#endif
-#define have_of 0
-#endif /* !CONFIG_ALL_PPC */
+#define have_of (_machine == _MACH_chrp || _machine == _MACH_Pmac)
 
 #endif /* __ASM_PPC_PROCESSOR_H */
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/prom.h linux/include/asm-ppc/prom.h
--- v2.4.9/linux/include/asm-ppc/prom.h	Mon Aug 27 12:41:48 2001
+++ linux/include/asm-ppc/prom.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.prom.h 1.16 07/25/01 14:11:37 trini
+ * BK Id: SCCS/s.prom.h 1.19 08/17/01 15:23:17 paulus
  */
 /*
  * Definitions for talking to the Open Firmware PROM on
@@ -18,9 +18,6 @@
 
 extern char *prom_display_paths[];
 extern unsigned int prom_num_displays;
-#ifdef CONFIG_ALL_PPC
-extern int have_of;
-#endif
 
 struct address_range {
 	unsigned int space;
@@ -92,13 +89,6 @@
 extern void print_properties(struct device_node *node);
 extern int call_rtas(const char *service, int nargs, int nret,
 		     unsigned long *outputs, ...);
-extern void prom_drawstring(const char *c);
-extern void prom_drawhex(unsigned long v);
-extern void prom_drawchar(char c);
-
-extern void map_bootx_text(void);
-extern void bootx_update_display(unsigned long phys, int width, int height,
-				 int depth, int pitch);
 
 /*
  * When we call back to the Open Firmware client interface, we usually
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/residual.h linux/include/asm-ppc/residual.h
--- v2.4.9/linux/include/asm-ppc/residual.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/residual.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.residual.h 1.5 05/17/01 18:14:25 cort
+ * BK Id: SCCS/s.residual.h 1.8 08/09/01 09:11:24 trini
  */
 /* 7/18/95                                                                    */
 /*----------------------------------------------------------------------------*/
@@ -29,7 +29,7 @@
 /*               Public structures...                                         */
 /*----------------------------------------------------------------------------*/
 
-#include "pnp.h"
+#include <asm/pnp.h>
 
 typedef enum _L1CACHE_TYPE {
   NoneCAC = 0,
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/rpxclassic.h linux/include/asm-ppc/rpxclassic.h
--- v2.4.9/linux/include/asm-ppc/rpxclassic.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/rpxclassic.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.rpxclassic.h 1.8 05/17/01 18:14:25 cort
+ * BK Id: SCCS/s.rpxclassic.h 1.11 08/17/01 15:23:17 paulus
  */
 
 /*
@@ -99,10 +99,6 @@
 /* We don't use the 8259.
 */
 #define NR_8259_INTS	0
-
-/* Machine type
-*/
-#define _MACH_8xx (_MACH_classic)
 
 #endif
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/rpxlite.h linux/include/asm-ppc/rpxlite.h
--- v2.4.9/linux/include/asm-ppc/rpxlite.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/rpxlite.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.rpxlite.h 1.8 05/17/01 18:14:25 cort
+ * BK Id: SCCS/s.rpxlite.h 1.11 08/17/01 15:23:17 paulus
  */
 
 /*
@@ -79,10 +79,6 @@
 /* We don't use the 8259.
 */
 #define NR_8259_INTS	0
-
-/* Machine type
-*/
-#define _MACH_8xx (_MACH_rpxlite)
 
 #endif
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/smp.h linux/include/asm-ppc/smp.h
--- v2.4.9/linux/include/asm-ppc/smp.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/smp.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.smp.h 1.9 05/17/01 18:14:25 cort
+ * BK Id: SCCS/s.smp.h 1.12 08/16/01 07:49:31 paulus
  */
 /* smp.h: PPC specific SMP stuff.
  *
@@ -32,12 +32,14 @@
 extern unsigned long cpu_online_map;
 extern unsigned long smp_proc_in_lock[NR_CPUS];
 extern volatile unsigned long cpu_callin_map[NR_CPUS];
+extern int smp_tb_synchronized;
 
 extern void smp_store_cpu_info(int id);
 extern void smp_send_tlb_invalidate(int);
 extern void smp_send_xmon_break(int cpu);
 struct pt_regs;
 extern void smp_message_recv(int, struct pt_regs *);
+extern void smp_local_timer_interrupt(struct pt_regs *);
 
 #define NO_PROC_ID		0xFF            /* No processor magic marker */
 #define PROC_CHANGE_PENALTY	20
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/spinlock.h linux/include/asm-ppc/spinlock.h
--- v2.4.9/linux/include/asm-ppc/spinlock.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/spinlock.h	Tue Aug 28 06:58:33 2001
@@ -1,33 +1,79 @@
 /*
- * BK Id: SCCS/s.spinlock.h 1.5 05/17/01 18:14:25 cort
+ * BK Id: SCCS/s.spinlock.h 1.9 08/21/01 16:07:48 trini
  */
-#ifdef __KERNEL__
 #ifndef __ASM_SPINLOCK_H
 #define __ASM_SPINLOCK_H
 
+#include <asm/system.h>
+
+#undef SPINLOCK_DEBUG
+
 /*
  * Simple spin lock operations.
  */
 
 typedef struct {
 	volatile unsigned long lock;
+#ifdef SPINLOCK_DEBUG
 	volatile unsigned long owner_pc;
 	volatile unsigned long owner_cpu;
+#endif
 } spinlock_t;
 
-#define SPIN_LOCK_UNLOCKED	(spinlock_t) { 0, 0, 0 }
-#define spin_lock_init(lp) 	do { (lp)->lock = 0; } while(0)
-#define spin_unlock_wait(lp)	do { barrier(); } while((lp)->lock)
+#ifdef __KERNEL__
+#if SPINLOCK_DEBUG
+#define SPINLOCK_DEBUG_INIT     , 0, 0
+#else
+#define SPINLOCK_DEBUG_INIT     /* */
+#endif
+
+#define SPIN_LOCK_UNLOCKED	(spinlock_t) { 0 SPINLOCK_DEBUG_INIT }
+
+#define spin_lock_init(x) 	do { *(x) = SPIN_LOCK_UNLOCKED; } while(0)
 #define spin_is_locked(x)	((x)->lock != 0)
+#define spin_unlock_wait(x)	do { barrier(); } while(spin_is_locked(x))
+
+#ifndef SPINLOCK_DEBUG
+
+static inline void spin_lock(spinlock_t *lock)
+{
+	unsigned long tmp;
+
+	__asm__ __volatile__(
+	"b	1f			# spin_lock\n\
+2:	lwzx	%0,0,%1\n\
+	cmpwi	0,%0,0\n\
+	bne+	2b\n\
+1:	lwarx	%0,0,%1\n\
+	cmpwi	0,%0,0\n\
+	bne-	2b\n\
+	stwcx.	%2,0,%1\n\
+	bne-	2b\n\
+	isync"
+	: "=&r"(tmp)
+	: "r"(&lock->lock), "r"(1)
+	: "cr0", "memory");
+}
+
+static inline void spin_unlock(spinlock_t *lock)
+{
+	__asm__ __volatile__("eieio		# spin_unlock": : :"memory");
+	lock->lock = 0;
+}
+
+#define spin_trylock(lock) (!test_and_set_bit(0,(lock)))
+
+#else
 
 extern void _spin_lock(spinlock_t *lock);
 extern void _spin_unlock(spinlock_t *lock);
 extern int spin_trylock(spinlock_t *lock);
+extern unsigned long __spin_trylock(volatile unsigned long *lock);
 
 #define spin_lock(lp)			_spin_lock(lp)
 #define spin_unlock(lp)			_spin_unlock(lp)
 
-extern unsigned long __spin_trylock(volatile unsigned long *lock);
+#endif
 
 /*
  * Read-write spinlocks, allowing multiple readers
@@ -41,12 +87,85 @@
  */
 typedef struct {
 	volatile unsigned long lock;
+#ifdef SPINLOCK_DEBUG
 	volatile unsigned long owner_pc;
+#endif
 } rwlock_t;
 
-#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
+#if SPINLOCK_DEBUG
+#define RWLOCK_DEBUG_INIT     , 0
+#else
+#define RWLOCK_DEBUG_INIT     /* */
+#endif
+
+#define RW_LOCK_UNLOCKED (rwlock_t) { 0 RWLOCK_DEBUG_INIT }
 #define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0)
 
+#ifndef SPINLOCK_DEBUG
+
+static __inline__ void read_lock(rwlock_t *rw)
+{
+	unsigned int tmp;
+
+	__asm__ __volatile__(
+	"b		2f		# read_lock\n\
+1:	lwzx		%0,0,%1\n\
+	cmpwi		0,%0,0\n\
+	blt+		1b\n\
+2:	lwarx		%0,0,%1\n\
+	addic.		%0,%0,1\n\
+	ble-		1b\n\
+	stwcx.		%0,0,%1\n\
+	bne-		2b\n\
+	isync"
+	: "=&r"(tmp)
+	: "r"(&rw->lock)
+	: "cr0", "memory");
+}
+
+static __inline__ void read_unlock(rwlock_t *rw)
+{
+	unsigned int tmp;
+
+	__asm__ __volatile__(
+	"eieio				# read_unlock\n\
+1:	lwarx		%0,0,%1\n\
+	addic		%0,%0,-1\n\
+	stwcx.		%0,0,%1\n\
+	bne-		1b"
+	: "=&r"(tmp)
+	: "r"(&rw->lock)
+	: "cr0", "memory");
+}
+
+static __inline__ void write_lock(rwlock_t *rw)
+{
+	unsigned int tmp;
+
+	__asm__ __volatile__(
+	"b		2f		# write_lock\n\
+1:	lwzx		%0,0,%1\n\
+	cmpwi		0,%0,0\n\
+	bne+		1b\n\
+2:	lwarx		%0,0,%1\n\
+	cmpwi		0,%0,0\n\
+	bne-		1b\n\
+	stwcx.		%2,0,%1\n\
+	bne-		2b\n\
+	isync"
+	: "=&r"(tmp)
+	: "r"(&rw->lock), "r"(-1)
+	: "cr0", "memory");
+}
+
+static __inline__ void write_unlock(rwlock_t *rw)
+{
+	__asm__ __volatile__("eieio		# write_unlock": : :"memory");
+	rw->lock = 0;
+}
+
+#else
+
 extern void _read_lock(rwlock_t *rw);
 extern void _read_unlock(rwlock_t *rw);
 extern void _write_lock(rwlock_t *rw);
@@ -56,6 +175,8 @@
 #define write_lock(rw)		_write_lock(rw)
 #define write_unlock(rw)	_write_unlock(rw)
 #define read_unlock(rw)		_read_unlock(rw)
+
+#endif
 
 #endif /* __ASM_SPINLOCK_H */
 #endif /* __KERNEL__ */
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/system.h linux/include/asm-ppc/system.h
--- v2.4.9/linux/include/asm-ppc/system.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/system.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.system.h 1.10 05/17/01 18:14:26 cort
+ * BK Id: SCCS/s.system.h 1.14 08/20/01 14:34:41 paulus
  */
 /*
  * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
@@ -55,9 +55,13 @@
 extern void flush_instruction_cache(void);
 extern void hard_reset_now(void);
 extern void poweroff_now(void);
-extern int _get_PVR(void);
+#ifdef CONFIG_6xx
 extern long _get_L2CR(void);
 extern void _set_L2CR(unsigned long);
+#else
+#define _get_L2CR()	0
+#define _set_L2CR(val)	do { } while(0)
+#endif
 extern void via_cuda_init(void);
 extern void pmac_nvram_init(void);
 extern void read_rtc_time(void);
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/time.h linux/include/asm-ppc/time.h
--- v2.4.9/linux/include/asm-ppc/time.h	Tue Jul  3 17:08:21 2001
+++ linux/include/asm-ppc/time.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.time.h 1.13 06/27/01 14:49:58 trini
+ * BK Id: SCCS/s.time.h 1.15 08/16/01 07:49:31 paulus
  */
 /*
  * Common time prototypes and such for all ppc machines.
@@ -74,6 +74,13 @@
 	unsigned long tbl;
 	asm volatile("mftbu %0" : "=r" (tbl));
 	return tbl;
+}
+
+extern __inline__ void set_tb(unsigned int upper, unsigned int lower)
+{
+	mtspr(SPRN_TBWL, 0);
+	mtspr(SPRN_TBWU, upper);
+	mtspr(SPRN_TBWL, lower);
 }
 
 extern __inline__ unsigned long get_rtcl(void) {
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/timex.h linux/include/asm-ppc/timex.h
--- v2.4.9/linux/include/asm-ppc/timex.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/timex.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.timex.h 1.5 05/17/01 18:14:26 cort
+ * BK Id: SCCS/s.timex.h 1.8 08/15/01 22:43:07 paulus
  */
 /*
  * linux/include/asm-ppc/timex.h
@@ -11,6 +11,7 @@
 #define _ASMppc_TIMEX_H
 
 #include <linux/config.h>
+#include <asm/cputable.h>
 
 #define CLOCK_TICK_RATE	1193180 /* Underlying HZ */
 #define CLOCK_TICK_FACTOR	20	/* Factor of both 1000000 and CLOCK_TICK_RATE */
@@ -23,23 +24,25 @@
 /*
  * For the "cycle" counter we use the timebase lower half.
  * Currently only used on SMP.
- *
- * Since SMP kernels won't run on the PPC601 CPU (which doesn't have
- * the timebase register) anyway, we don't bother checking the CPU version.
  */
 
 extern cycles_t cacheflush_time;
 
 static inline cycles_t get_cycles(void)
 {
-#ifdef CONFIG_SMP
-	cycles_t ret;
+	cycles_t ret = 0;
 
-	__asm__("mftb %0" : "=r" (ret) : );
+	__asm__ __volatile__(
+		"98:	mftb %0\n"
+		"99:\n"
+		".section __ftr_fixup,\"a\"\n"
+		"	.long %1\n"
+		"	.long 0\n"
+		"	.long 98b\n"
+		"	.long 99b\n"
+		".previous"
+		: "=r" (ret) : "i" (CPU_FTR_601));
 	return ret;
-#else
-	return 0;
-#endif
 }
 
 #endif
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/tqm8xx.h linux/include/asm-ppc/tqm8xx.h
--- v2.4.9/linux/include/asm-ppc/tqm8xx.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/tqm8xx.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.tqm8xx.h 1.6 05/17/01 18:14:26 cort
+ * BK Id: SCCS/s.tqm8xx.h 1.7 08/17/01 15:23:17 paulus
  */
 /*
  * A collection of structures, addresses, and values associated with
@@ -68,14 +68,5 @@
 /* We don't use the 8259.
 */
 #define NR_8259_INTS	0
-
-/* Generic 8xx type
-*/
-#if defined(CONFIG_TQM8xxL)
-#define _MACH_8xx (_MACH_tqm8xxL)
-#endif
-#if defined(CONFIG_TQM860)
-#define _MACH_8xx (_MACH_tqm860)
-#endif
 
 #endif	/* __MACH_TQM8xx_DEFS */
diff -u --recursive --new-file v2.4.9/linux/include/asm-ppc/uninorth.h linux/include/asm-ppc/uninorth.h
--- v2.4.9/linux/include/asm-ppc/uninorth.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/uninorth.h	Tue Aug 28 06:58:33 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.uninorth.h 1.7 05/17/01 18:14:26 cort
+ * BK Id: SCCS/s.uninorth.h 1.11 08/19/01 22:23:04 paulus
  */
 /*
  * uninorth.h: definitions for using the "UniNorth" host bridge chip
@@ -31,6 +31,52 @@
 #define UNI_N_CFG_GART_ENABLE		0x00000100
 #define UNI_N_CFG_GART_2xRESET		0x00010000
 
+/* My understanding of UniNorth AGP as of UniNorth rev 1.0x,
+ * revision 1.5 (x4 AGP) may need further changes.
+ * 
+ * AGP_BASE register contains the base address of the AGP aperture on
+ * the AGP bus. It doesn't seem to be visible to the CPU as of UniNorth 1.x,
+ * even if decoding of this address range is enabled in the address select
+ * register. Apparently, the only supported bases are 256Mb multiples
+ * (high 4 bits of that register).
+ * 
+ * GART_BASE register appear to contain the physical address of the GART
+ * in system memory in the high address bits (page aligned), and the
+ * GART size in the low order bits (number of GART pages)
+ *
+ * The GART format itself is one 32bits word per physical memory page.
+ * This word contains, in little-endian format (!!!), the physical address
+ * of the page in the high bits, and what appears to be an "enable" bit
+ * in the LSB bit (0) that must be set to 1 when the entry is valid.
+ * 
+ * Obviously, the GART is not cache coherent and so any change to it
+ * must be flushed to memory (or maybe just make the GART space non
+ * cachable). AGP memory itself doens't seem to be cache coherent neither.
+ * 
+ * In order to invalidate the GART (which is probably necessary to inval
+ * the bridge internal TLBs), the following sequence has to be written,
+ * in order, to the GART_CTRL register:
+ * 
+ *   UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_INVAL
+ *   UNI_N_CFG_GART_ENABLE
+ *   UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_2xRESET
+ *   UNI_N_CFG_GART_ENABLE
+ *   
+ * As far as AGP "features" are concerned, it looks like fast write may
+ * not be supported but this has to be confirmed.
+ * 
+ * Turning on AGP seem to require a double invalidate operation, one before
+ * setting the AGP command register, on after.
+ * 
+ * Turning off AGP seems to require the following sequence: first wait
+ * for the AGP to be idle by reading the internal status register, then
+ * write in that order to the GART_CTRL register:
+ * 
+ *   UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_INVAL
+ *   0
+ *   UNI_N_CFG_GART_2xRESET
+ *   0
+ */
 
 /* 
  * Uni-N memory mapped reg. definitions
diff -u --recursive --new-file v2.4.9/linux/include/asm-sparc/keyboard.h linux/include/asm-sparc/keyboard.h
--- v2.4.9/linux/include/asm-sparc/keyboard.h	Mon Dec 20 22:05:52 1999
+++ linux/include/asm-sparc/keyboard.h	Tue Aug 28 07:09:44 2001
@@ -1,4 +1,4 @@
-/* $Id: keyboard.h,v 1.3 1999/11/23 08:56:44 davem Exp $
+/* $Id: keyboard.h,v 1.7 2001/08/18 09:40:46 davem Exp $
  * linux/include/asm-sparc/keyboard.h
  *
  * sparc64 Created Aug 29 1997 by Eddie C. Dost (ecd@skynet.be)
@@ -13,7 +13,9 @@
 
 #ifdef __KERNEL__
 
+#include <linux/config.h>
 #include <linux/ioport.h>
+#include <linux/kd.h>
 #include <asm/io.h>
 
 #define KEYBOARD_IRQ			13
diff -u --recursive --new-file v2.4.9/linux/include/asm-sparc64/floppy.h linux/include/asm-sparc64/floppy.h
--- v2.4.9/linux/include/asm-sparc64/floppy.h	Wed May 16 10:31:27 2001
+++ linux/include/asm-sparc64/floppy.h	Tue Aug 28 07:09:44 2001
@@ -1,4 +1,4 @@
-/* $Id: floppy.h,v 1.30 2001/05/11 07:05:38 davem Exp $
+/* $Id: floppy.h,v 1.31 2001/08/22 17:46:31 davem Exp $
  * asm-sparc64/floppy.h: Sparc specific parts of the Floppy driver.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -268,8 +268,15 @@
 static struct linux_ebus_dma *sun_pci_fd_ebus_dma;
 static struct pci_dev *sun_pci_ebus_dev;
 static int sun_pci_broken_drive = -1;
-static unsigned int sun_pci_dma_addr = -1U;
-static int sun_pci_dma_len, sun_pci_dma_direction;
+
+struct sun_pci_dma_op {
+	unsigned int 	addr;
+	int		len;
+	int		direction;
+	char		*buf;
+};
+static struct sun_pci_dma_op sun_pci_dma_current = { -1U, 0, 0, NULL};
+static struct sun_pci_dma_op sun_pci_dma_pending = { -1U, 0, 0, NULL};
 
 extern void floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 
@@ -339,6 +346,29 @@
 {
 	unsigned int dcsr;
 
+	if((NULL == sun_pci_dma_pending.buf) 	||
+	   (0	== sun_pci_dma_pending.len) 	||
+	   (0	== sun_pci_dma_pending.direction)) {
+		goto enable; /* TODO: BUG() */
+	}
+
+	sun_pci_dma_current.buf = sun_pci_dma_pending.buf;
+	sun_pci_dma_current.len = sun_pci_dma_pending.len;
+	sun_pci_dma_current.direction = sun_pci_dma_pending.direction;
+
+	sun_pci_dma_pending.buf  = NULL;
+	sun_pci_dma_pending.len  = 0;
+	sun_pci_dma_pending.direction = 0;
+	sun_pci_dma_pending.addr = -1U;
+
+	sun_pci_dma_current.addr = 
+		pci_map_single(	sun_pci_ebus_dev,
+				sun_pci_dma_current.buf,
+				sun_pci_dma_current.len,
+				sun_pci_dma_current.direction);
+	writel(sun_pci_dma_current.addr, &sun_pci_fd_ebus_dma->dacr);
+
+enable:
 	dcsr = readl(&sun_pci_fd_ebus_dma->dcsr);
 	dcsr |= EBUS_DCSR_EN_DMA;
 	writel(dcsr, &sun_pci_fd_ebus_dma->dcsr);
@@ -362,12 +392,12 @@
 			writel(dcsr, &sun_pci_fd_ebus_dma->dcsr);
 		}
 	}
-	if (sun_pci_dma_addr != -1U)
+	if (sun_pci_dma_current.addr != -1U)
 		pci_unmap_single(sun_pci_ebus_dev,
-				 sun_pci_dma_addr,
-				 sun_pci_dma_len,
-				 sun_pci_dma_direction);
-	sun_pci_dma_addr = -1U;
+				 sun_pci_dma_current.addr,
+				 sun_pci_dma_current.len,
+				 sun_pci_dma_current.direction);
+	sun_pci_dma_current.addr = -1U;
 }
 
 static void sun_pci_fd_set_dma_mode(int mode)
@@ -387,29 +417,23 @@
 	 */
 	if (mode == DMA_MODE_WRITE) {
 		dcsr &= ~(EBUS_DCSR_WRITE);
-		sun_pci_dma_direction = PCI_DMA_TODEVICE;
+		sun_pci_dma_pending.direction = PCI_DMA_TODEVICE;
 	} else {
 		dcsr |= EBUS_DCSR_WRITE;
-		sun_pci_dma_direction = PCI_DMA_FROMDEVICE;
+		sun_pci_dma_pending.direction = PCI_DMA_FROMDEVICE;
 	}
 	writel(dcsr, &sun_pci_fd_ebus_dma->dcsr);
 }
 
 static void sun_pci_fd_set_dma_count(int length)
 {
-	sun_pci_dma_len = length;
+	sun_pci_dma_pending.len = length;
 	writel(length, &sun_pci_fd_ebus_dma->dbcr);
 }
 
 static void sun_pci_fd_set_dma_addr(char *buffer)
 {
-	unsigned int addr;
-
-	addr = sun_pci_dma_addr = pci_map_single(sun_pci_ebus_dev,
-						 buffer,
-						 sun_pci_dma_len,
-						 sun_pci_dma_direction);
-	writel(addr, &sun_pci_fd_ebus_dma->dacr);
+	sun_pci_dma_pending.buf = buffer;
 }
 
 static unsigned int sun_pci_get_dma_residue(void)
@@ -719,7 +743,7 @@
 		sun_fdops.fd_inb = sun_pci_fd_inb;
 		sun_fdops.fd_outb = sun_pci_fd_outb;
 
-		use_virtual_dma = 0;
+		can_use_virtual_dma = use_virtual_dma = 0;
 		sun_fdops.fd_enable_dma = sun_pci_fd_enable_dma;
 		sun_fdops.fd_disable_dma = sun_pci_fd_disable_dma;
 		sun_fdops.fd_set_dma_mode = sun_pci_fd_set_dma_mode;
@@ -796,9 +820,9 @@
 			ns87303_modify(config, ASC, ASC_DRV2_SEL, 0);
 			ns87303_modify(config, FCR, 0, FCR_LDE);
 
-			cfg = sun_floppy_types[0];
+			config = sun_floppy_types[0];
 			sun_floppy_types[0] = sun_floppy_types[1];
-			sun_floppy_types[1] = cfg;
+			sun_floppy_types[1] = config;
 
 			if (sun_pci_broken_drive != -1) {
 				sun_pci_broken_drive = 1 - sun_pci_broken_drive;
diff -u --recursive --new-file v2.4.9/linux/include/asm-sparc64/keyboard.h linux/include/asm-sparc64/keyboard.h
--- v2.4.9/linux/include/asm-sparc64/keyboard.h	Mon Aug 27 12:41:48 2001
+++ linux/include/asm-sparc64/keyboard.h	Tue Aug 28 07:09:44 2001
@@ -1,4 +1,4 @@
-/* $Id: keyboard.h,v 1.4 2001/08/13 14:40:07 davem Exp $
+/* $Id: keyboard.h,v 1.5 2001/08/18 09:40:46 davem Exp $
  * linux/include/asm-sparc64/keyboard.h
  *
  * Created Aug 29 1997 by Eddie C. Dost (ecd@skynet.be)
@@ -25,7 +25,6 @@
 			    char raw_mode);
 extern char pcikbd_unexpected_up(unsigned char keycode);
 extern void pcikbd_leds(unsigned char leds);
-extern int pcikbd_rate(struct kbd_repeat *rep);
 extern void pcikbd_init_hw(void);
 extern unsigned char pcikbd_sysrq_xlate[128];
 
@@ -34,7 +33,6 @@
 #define kbd_translate			pcikbd_translate
 #define kbd_unexpected_up		pcikbd_unexpected_up
 #define kbd_leds			pcikbd_leds
-#define kbd_rate			pcikbd_rate
 #define kbd_init_hw			pcikbd_init_hw
 #define kbd_sysrq_xlate			pcikbd_sysrq_xlate
 #define kbd_init			pcikbd_init
diff -u --recursive --new-file v2.4.9/linux/include/asm-sparc64/mmu_context.h linux/include/asm-sparc64/mmu_context.h
--- v2.4.9/linux/include/asm-sparc64/mmu_context.h	Mon Aug 27 12:41:48 2001
+++ linux/include/asm-sparc64/mmu_context.h	Tue Aug 28 07:09:44 2001
@@ -1,24 +1,11 @@
-/* $Id: mmu_context.h,v 1.50 2001/08/13 20:24:34 kanoj Exp $ */
+/* $Id: mmu_context.h,v 1.51 2001/08/17 04:55:09 kanoj Exp $ */
 #ifndef __SPARC64_MMU_CONTEXT_H
 #define __SPARC64_MMU_CONTEXT_H
 
 /* Derived heavily from Linus's Alpha/AXP ASN code... */
 
-#ifndef __ASSEMBLY__
-
-#include <linux/spinlock.h>
-#include <asm/system.h>
-#include <asm/spitfire.h>
 #include <asm/page.h>
 
-static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
-{
-}
-
-extern spinlock_t ctx_alloc_lock;
-extern unsigned long tlb_context_cache;
-extern unsigned long mmu_context_bmap[];
-
 /*
  * For the 8k pagesize kernel, use only 10 hw context bits to optimize some shifts in
  * the fast tlbmiss handlers, instead of all 13 bits (specifically for vpte offset
@@ -28,9 +15,25 @@
  */
 #if PAGE_SHIFT == 13
 #define CTX_VERSION_SHIFT	10
+#define TAG_CONTEXT_BITS	0x3ff
 #else
 #define CTX_VERSION_SHIFT	12
+#define TAG_CONTEXT_BITS	0xfff
 #endif
+
+#ifndef __ASSEMBLY__
+
+#include <linux/spinlock.h>
+#include <asm/system.h>
+#include <asm/spitfire.h>
+
+static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu)
+{
+}
+
+extern spinlock_t ctx_alloc_lock;
+extern unsigned long tlb_context_cache;
+extern unsigned long mmu_context_bmap[];
 
 #define CTX_VERSION_MASK	((~0UL) << CTX_VERSION_SHIFT)
 #define CTX_FIRST_VERSION	((1UL << CTX_VERSION_SHIFT) + 1UL)
diff -u --recursive --new-file v2.4.9/linux/include/asm-sparc64/pgalloc.h linux/include/asm-sparc64/pgalloc.h
--- v2.4.9/linux/include/asm-sparc64/pgalloc.h	Thu Apr 26 22:17:26 2001
+++ linux/include/asm-sparc64/pgalloc.h	Tue Aug 28 07:09:44 2001
@@ -1,4 +1,4 @@
-/* $Id: pgalloc.h,v 1.20 2001/04/26 02:36:36 davem Exp $ */
+/* $Id: pgalloc.h,v 1.21 2001/08/22 22:16:56 kanoj Exp $ */
 #ifndef _SPARC64_PGALLOC_H
 #define _SPARC64_PGALLOC_H
 
@@ -64,7 +64,7 @@
 #define flush_tlb_range(__mm, start, end) \
 do { if(CTX_VALID((__mm)->context)) { \
 	unsigned long __start = (start)&PAGE_MASK; \
-	unsigned long __end = (end)&PAGE_MASK; \
+	unsigned long __end = PAGE_ALIGN(end); \
 	__flush_tlb_range(CTX_HWBITS((__mm)->context), __start, \
 			  SECONDARY_CONTEXT, __end, PAGE_SIZE, \
 			  (__end - __start)); \
diff -u --recursive --new-file v2.4.9/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h
--- v2.4.9/linux/include/asm-sparc64/pgtable.h	Mon Aug 27 12:41:48 2001
+++ linux/include/asm-sparc64/pgtable.h	Tue Aug 28 07:09:44 2001
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.141 2001/08/13 20:24:34 kanoj Exp $
+/* $Id: pgtable.h,v 1.143 2001/08/22 22:16:56 kanoj Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -18,16 +18,6 @@
 #include <asm/system.h>
 #include <asm/page.h>
 
-#ifndef __ASSEMBLY__
-
-#define PG_dcache_dirty		PG_arch_1
-
-/* Certain architectures need to do special things when pte's
- * within a page table are directly modified.  Thus, the following
- * hook is made available.
- */
-#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
-
 /* XXX All of this needs to be rethought so we can take advantage
  * XXX cheetah's full 64-bit virtual address space, ie. no more hole
  * XXX in the middle like on spitfire. -DaveM
@@ -55,6 +45,16 @@
 #define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
 #define PGDIR_MASK	(~(PGDIR_SIZE-1))
 
+#ifndef __ASSEMBLY__
+
+#define PG_dcache_dirty		PG_arch_1
+
+/* Certain architectures need to do special things when pte's
+ * within a page table are directly modified.  Thus, the following
+ * hook is made available.
+ */
+#define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval))
+
 /* Entries per page directory level. */
 #define PTRS_PER_PTE		(1UL << (PAGE_SHIFT-3))
 
@@ -72,9 +72,6 @@
 #define USER_PTRS_PER_PGD	((const int)((current->thread.flags & SPARC_FLAG_32BIT) ? \
 				 (1) : (PTRS_PER_PGD)))
 #define FIRST_USER_PGD_NR	0
-
-#define PTE_TABLE_SIZE	0x2000	/* 1024 entries 8 bytes each */
-#define PMD_TABLE_SIZE	0x2000	/* 2048 entries 4 bytes each */
 
 /* NOTE: TLB miss handlers depend heavily upon where this is. */
 #define VMALLOC_START		0x0000000140000000UL
diff -u --recursive --new-file v2.4.9/linux/include/asm-sparc64/vaddrs.h linux/include/asm-sparc64/vaddrs.h
--- v2.4.9/linux/include/asm-sparc64/vaddrs.h	Tue Aug  4 16:03:35 1998
+++ linux/include/asm-sparc64/vaddrs.h	Wed Dec 31 16:00:00 1969
@@ -1,22 +0,0 @@
-/* $Id: vaddrs.h,v 1.10 1998/05/14 13:36:01 jj Exp $ */
-#ifndef _SPARC64_VADDRS_H
-#define _SPARC64_VADDRS_H
-
-/* asm-sparc64/vaddrs.h:  Here will be define the virtual addresses at
- *                      which important I/O addresses will be mapped.
- *                      For instance the timer register virtual address
- *                      is defined here.
- *
- * Copyright (C) 1995,1998 David S. Miller (davem@caip.rutgers.edu)
- */
-
-/* Everything here must be in the first kernel PGD. */
-#define  DVMA_VADDR     0x0000000100000000ULL  /* Base area of the DVMA on suns */
-#define  DVMA_LEN       0x0000000040000000ULL  /* Size of the DVMA address space */
-#define  DVMA_END       0x0000000140000000ULL
-#define  MODULES_VADDR	0x0000000001000000ULL  /* Where to map modules */
-#define  MODULES_LEN	0x000000007f000000ULL
-#define  MODULES_END	0x0000000080000000ULL
-
-#endif /* !(_SPARC_VADDRS_H) */
-
diff -u --recursive --new-file v2.4.9/linux/include/linux/agp_backend.h linux/include/linux/agp_backend.h
--- v2.4.9/linux/include/linux/agp_backend.h	Tue Jul  3 17:08:21 2001
+++ linux/include/linux/agp_backend.h	Mon Aug 27 07:40:33 2001
@@ -85,6 +85,8 @@
 	size_t aper_size;
 	int max_memory;		/* In pages */
 	int current_memory;
+	int cant_use_aperture;
+	unsigned long page_mask;
 } agp_kern_info;
 
 /* 
diff -u --recursive --new-file v2.4.9/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.4.9/linux/include/linux/fs.h	Mon Aug 27 12:41:48 2001
+++ linux/include/linux/fs.h	Tue Aug 28 11:01:01 2001
@@ -89,12 +89,7 @@
 #define FS_NO_PRELIM	4 /* prevent preloading of dentries, even if
 			   * FS_NO_DCACHE is not set.
 			   */
-#define FS_SINGLE	8 /*
-			   * Filesystem that can have only one superblock;
-			   * kernel-wide vfsmnt is placed in ->kern_mnt by
-			   * kern_mount() which must be called _after_
-			   * register_filesystem().
-			   */
+#define FS_SINGLE	8 /* Filesystem that can have only one superblock */
 #define FS_NOMOUNT	16 /* Never mount from userland */
 #define FS_LITTER	32 /* Keeps the tree in dcache */
 #define FS_ODD_RENAME	32768	/* Temporary stuff; will go away as soon
@@ -665,6 +660,7 @@
 extern spinlock_t sb_lock;
 
 #define sb_entry(list)	list_entry((list), struct super_block, s_list)
+#define S_BIAS (1<<30)
 struct super_block {
 	struct list_head	s_list;		/* Keep this first */
 	kdev_t			s_dev;
@@ -688,6 +684,7 @@
 	struct list_head	s_files;
 
 	struct block_device	*s_bdev;
+	struct list_head	s_instances;
 	struct quota_mount_options s_dquot;	/* Diskquota specific options */
 
 	union {
@@ -913,8 +910,8 @@
 	int fs_flags;
 	struct super_block *(*read_super) (struct super_block *, void *, int);
 	struct module *owner;
-	struct vfsmount *kern_mnt; /* For kernel mount, if it's FS_SINGLE fs */
 	struct file_system_type * next;
+	struct list_head fs_supers;
 };
 
 #define DECLARE_FSTYPE(var,type,read,flags) \
@@ -1147,7 +1144,7 @@
 	buffer_insert_inode_queue(bh, inode);
 }
 
-extern void balance_dirty(kdev_t);
+extern void balance_dirty(void);
 extern int check_disk_change(kdev_t);
 extern int invalidate_inodes(struct super_block *);
 extern int invalidate_device(kdev_t, int);
diff -u --recursive --new-file v2.4.9/linux/include/linux/highmem.h linux/include/linux/highmem.h
--- v2.4.9/linux/include/linux/highmem.h	Tue Aug  7 12:48:43 2001
+++ linux/include/linux/highmem.h	Mon Aug 27 13:21:43 2001
@@ -45,8 +45,9 @@
 /* when CONFIG_HIGHMEM is not set these will be plain clear/copy_page */
 static inline void clear_user_highpage(struct page *page, unsigned long vaddr)
 {
-	clear_user_page(kmap(page), vaddr);
-	kunmap(page);
+	void *addr = kmap_atomic(page, KM_USER0);
+	clear_user_page(addr, vaddr);
+	kunmap_atomic(addr, KM_USER0);
 }
 
 static inline void clear_highpage(struct page *page)
@@ -85,11 +86,11 @@
 {
 	char *vfrom, *vto;
 
-	vfrom = kmap(from);
-	vto = kmap(to);
+	vfrom = kmap_atomic(from, KM_USER0);
+	vto = kmap_atomic(to, KM_USER1);
 	copy_user_page(vto, vfrom, vaddr);
-	kunmap(from);
-	kunmap(to);
+	kunmap_atomic(vfrom, KM_USER0);
+	kunmap_atomic(vto, KM_USER1);
 }
 
 static inline void copy_highpage(struct page *to, struct page *from)
diff -u --recursive --new-file v2.4.9/linux/include/linux/kernel.h linux/include/linux/kernel.h
--- v2.4.9/linux/include/linux/kernel.h	Mon Aug 27 12:41:48 2001
+++ linux/include/linux/kernel.h	Mon Aug 27 21:15:58 2001
@@ -10,6 +10,7 @@
 #include <stdarg.h>
 #include <linux/linkage.h>
 #include <linux/stddef.h>
+#include <linux/types.h>
 
 /* Optimization barrier */
 /* The "volatile" is due to gcc bugs */
@@ -61,6 +62,8 @@
 extern long long simple_strtoll(const char *,char **,unsigned int);
 extern int sprintf(char * buf, const char * fmt, ...);
 extern int vsprintf(char *buf, const char *, va_list);
+extern int snprintf(char * buf, size_t size, const char *fmt, ...);
+extern int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
 extern int get_option(char **str, int *pint);
 extern char *get_options(char *str, int nints, int *ints);
 extern unsigned long long memparse(char *ptr, char **retptr);
@@ -113,9 +116,9 @@
 	((unsigned char *)&addr)[0]
 
 #define min(type,x,y) \
-	({ type __x = (x), __y = (y); __x < __y ? __x: __y; })
+	({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
 #define max(type,x,y) \
-	({ type __x = (x), __y = (y); __x > __y ? __x: __y; })
+	({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.4.9/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.4.9/linux/include/linux/mm.h	Tue Aug  7 12:48:43 2001
+++ linux/include/linux/mm.h	Mon Aug 27 21:03:37 2001
@@ -536,17 +536,20 @@
 /* Action modifiers - doesn't change the zoning */
 #define __GFP_WAIT	0x10	/* Can wait and reschedule? */
 #define __GFP_HIGH	0x20	/* Should access emergency pools? */
-#define __GFP_IO	0x40	/* Can start physical IO? */
-#define __GFP_FS	0x80	/* Can call down to low-level FS? */
+#define __GFP_IO	0x40	/* Can start low memory physical IO? */
+#define __GFP_HIGHIO	0x80	/* Can start high mem physical IO? */
+#define __GFP_FS	0x100	/* Can call down to low-level FS? */
 
+#define GFP_NOHIGHIO	(__GFP_HIGH | __GFP_WAIT | __GFP_IO)
 #define GFP_NOIO	(__GFP_HIGH | __GFP_WAIT)
-#define GFP_NOFS	(__GFP_HIGH | __GFP_WAIT | __GFP_IO)
+#define GFP_NOFS	(__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO)
 #define GFP_ATOMIC	(__GFP_HIGH)
-#define GFP_USER	(             __GFP_WAIT | __GFP_IO | __GFP_FS)
-#define GFP_HIGHUSER	(             __GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HIGHMEM)
-#define GFP_KERNEL	(__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_FS)
-#define GFP_NFS		(__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_FS)
-#define GFP_KSWAPD	(                          __GFP_IO | __GFP_FS)
+#define GFP_USER	(             __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
+#define GFP_HIGHUSER	(             __GFP_WAIT | __GFP_IO | __GFP_HIGHIO \
+	       	| __GFP_FS | __GFP_HIGHMEM)
+#define GFP_KERNEL	(__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
+#define GFP_NFS	(__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS)
+#define GFP_KSWAPD	(                          __GFP_IO | __GFP_HIGHIO | __GFP_FS)
 
 /* Flag - indicates that the buffer will be suitable for DMA.  Ignored on some
    platforms, used as appropriate on others */
diff -u --recursive --new-file v2.4.9/linux/include/linux/ntfs_fs.h linux/include/linux/ntfs_fs.h
--- v2.4.9/linux/include/linux/ntfs_fs.h	Mon Mar 13 12:35:39 2000
+++ linux/include/linux/ntfs_fs.h	Tue Aug 28 06:57:18 2001
@@ -1,3 +1,21 @@
 #ifndef _LINUX_NTFS_FS_H
 #define _LINUX_NTFS_FS_H
+
+#include <asm/byteorder.h>
+
+#define NTFS_SECTOR_BITS 9
+#define NTFS_SECTOR_SIZE 512
+
+/*
+ * Attribute flags (16-bit).
+ */
+typedef enum {
+	ATTR_IS_COMPRESSED      = cpu_to_le16(0x0001),
+	ATTR_COMPRESSION_MASK   = cpu_to_le16(0x00ff),  /* Compression method
+							 * mask. Also, first
+							 * illegal value. */
+	ATTR_IS_ENCRYPTED       = cpu_to_le16(0x4000),
+	ATTR_IS_SPARSE          = cpu_to_le16(0x8000),
+} __attribute__ ((__packed__)) ATTR_FLAGS;
+
 #endif
diff -u --recursive --new-file v2.4.9/linux/include/linux/ntfs_fs_i.h linux/include/linux/ntfs_fs_i.h
--- v2.4.9/linux/include/linux/ntfs_fs_i.h	Wed Jul 25 17:10:26 2001
+++ linux/include/linux/ntfs_fs_i.h	Tue Aug 28 06:57:18 2001
@@ -1,6 +1,8 @@
 #ifndef _LINUX_NTFS_FS_I_H
 #define _LINUX_NTFS_FS_I_H
 
+#include <linux/types.h>
+
 /* Forward declarations, to keep number of mutual includes low */
 struct ntfs_attribute;
 struct ntfs_sb_info;
diff -u --recursive --new-file v2.4.9/linux/include/linux/ntfs_fs_sb.h linux/include/linux/ntfs_fs_sb.h
--- v2.4.9/linux/include/linux/ntfs_fs_sb.h	Mon Aug 27 12:41:48 2001
+++ linux/include/linux/ntfs_fs_sb.h	Tue Aug 28 06:57:18 2001
@@ -1,7 +1,7 @@
 #ifndef _LINUX_NTFS_FS_SB_H
 #define _LINUX_NTFS_FS_SB_H
 
-typedef __s64 LCN;
+#include <linux/ntfs_fs_i.h>
 
 struct ntfs_sb_info{
 	/* Configuration provided by user at mount time. */
@@ -10,6 +10,8 @@
 	ntmode_t umask;
 	void *nls_map;
 	unsigned int ngt;
+	char mft_zone_multiplier;
+	ntfs_cluster_t mft_zone_end;
 	/* Configuration provided by user with the ntfstools.
 	 * FIXME: This is no longer possible. What is this good for? (AIA) */
 	ntfs_size_t partition_bias;	/* For access to underlying device. */
@@ -36,7 +38,9 @@
 	int index_clusters_per_record;
 	int index_record_size;
 	int index_record_size_bits;
-	LCN mft_lcn;
+	ntfs_cluster_t nr_clusters;
+	ntfs_cluster_t mft_lcn;
+	ntfs_cluster_t mft_mirr_lcn;
 	/* Data read from special files. */
 	unsigned char *mft;
 	unsigned short *upcase;
diff -u --recursive --new-file v2.4.9/linux/include/linux/pci_ids.h linux/include/linux/pci_ids.h
--- v2.4.9/linux/include/linux/pci_ids.h	Mon Aug 27 12:41:48 2001
+++ linux/include/linux/pci_ids.h	Mon Aug 27 08:56:31 2001
@@ -985,6 +985,7 @@
 #define PCI_VENDOR_ID_PHILIPS		0x1131
 #define PCI_DEVICE_ID_PHILIPS_SAA7145	0x7145
 #define PCI_DEVICE_ID_PHILIPS_SAA7146	0x7146
+#define PCI_DEVICE_ID_PHILIPS_SAA9730	0x9730
 
 #define PCI_VENDOR_ID_EICON		0x1133
 #define PCI_DEVICE_ID_EICON_DIVA20PRO	0xe001
@@ -1098,6 +1099,9 @@
 
 #define PCI_VENDOR_ID_GALILEO		0x11ab
 #define PCI_DEVICE_ID_GALILEO_GT64011	0x4146
+#define PCI_DEVICE_ID_GALILEO_GT64111	0x4146
+#define PCI_DEVICE_ID_GALILEO_GT96100	0x9652
+#define PCI_DEVICE_ID_GALILEO_GT96100A	0x9653
 
 #define PCI_VENDOR_ID_LITEON		0x11ad
 #define PCI_DEVICE_ID_LITEON_LNE100TX	0x0002
@@ -1227,6 +1231,10 @@
 #define PCI_DEVICE_ID_ENSONIQ_ES1371	0x1371
 
 #define PCI_VENDOR_ID_ROCKWELL		0x127A
+
+#define PCI_VENDOR_ID_ITE		0x1283
+#define PCI_DEVICE_ID_ITE_IT8172G	0x8172
+#define PCI_DEVICE_ID_ITE_IT8172G_AUDIO 0x0801
 
 #define PCI_VENDOR_ID_ITE		0x1283
 #define PCI_DEVICE_ID_ITE_IT8172G	0x8172
diff -u --recursive --new-file v2.4.9/linux/include/linux/slab.h linux/include/linux/slab.h
--- v2.4.9/linux/include/linux/slab.h	Tue Aug  7 12:48:43 2001
+++ linux/include/linux/slab.h	Mon Aug 27 21:03:37 2001
@@ -17,13 +17,14 @@
 /* flags for kmem_cache_alloc() */
 #define	SLAB_NOFS		GFP_NOFS
 #define	SLAB_NOIO		GFP_NOIO
+#define SLAB_NOHIGHIO		GFP_NOHIGHIO
 #define	SLAB_ATOMIC		GFP_ATOMIC
 #define	SLAB_USER		GFP_USER
 #define	SLAB_KERNEL		GFP_KERNEL
 #define	SLAB_NFS		GFP_NFS
 #define	SLAB_DMA		GFP_DMA
 
-#define SLAB_LEVEL_MASK		(__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_FS)
+#define SLAB_LEVEL_MASK		(__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_HIGHIO|__GFP_FS)
 #define	SLAB_NO_GROW		0x00001000UL	/* don't grow a cache */
 
 /* flags to pass to kmem_cache_create().
diff -u --recursive --new-file v2.4.9/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.4.9/linux/include/linux/sysctl.h	Tue Aug  7 12:48:42 2001
+++ linux/include/linux/sysctl.h	Tue Aug 28 07:09:44 2001
@@ -281,6 +281,8 @@
 	NET_TCP_APP_WIN=86,
 	NET_TCP_ADV_WIN_SCALE=87,
 	NET_IPV4_NONLOCAL_BIND=88,
+	NET_IPV4_ICMP_RATELIMIT=89,
+	NET_IPV4_ICMP_RATEMASK=90
 };
 
 enum {
diff -u --recursive --new-file v2.4.9/linux/include/linux/vt_kern.h linux/include/linux/vt_kern.h
--- v2.4.9/linux/include/linux/vt_kern.h	Tue Aug  7 12:51:23 2001
+++ linux/include/linux/vt_kern.h	Tue Aug 28 07:09:44 2001
@@ -8,6 +8,7 @@
 
 #include <linux/config.h>
 #include <linux/vt.h>
+#include <linux/kd.h>
 
 /*
  * Presently, a lot of graphics programs do not restore the contents of
@@ -31,6 +32,7 @@
 } *vt_cons[MAX_NR_CONSOLES];
 
 extern void (*kd_mksound)(unsigned int hz, unsigned int ticks);
+extern int (*kbd_rate)(struct kbd_repeat *rep);
 
 /* console.c */
 
diff -u --recursive --new-file v2.4.9/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.4.9/linux/kernel/ksyms.c	Mon Aug 27 12:41:49 2001
+++ linux/kernel/ksyms.c	Mon Aug 27 21:15:58 2001
@@ -434,6 +434,7 @@
 /* process management */
 EXPORT_SYMBOL(complete_and_exit);
 EXPORT_SYMBOL(__wake_up);
+EXPORT_SYMBOL(__wake_up_sync);
 EXPORT_SYMBOL(wake_up_process);
 EXPORT_SYMBOL(sleep_on);
 EXPORT_SYMBOL(sleep_on_timeout);
@@ -457,7 +458,9 @@
 EXPORT_SYMBOL(panic);
 EXPORT_SYMBOL(printk);
 EXPORT_SYMBOL(sprintf);
+EXPORT_SYMBOL(snprintf);
 EXPORT_SYMBOL(vsprintf);
+EXPORT_SYMBOL(vsnprintf);
 EXPORT_SYMBOL(kdevname);
 EXPORT_SYMBOL(bdevname);
 EXPORT_SYMBOL(cdevname);
diff -u --recursive --new-file v2.4.9/linux/kernel/signal.c linux/kernel/signal.c
--- v2.4.9/linux/kernel/signal.c	Wed Jan  3 20:45:26 2001
+++ linux/kernel/signal.c	Mon Aug 27 08:58:52 2001
@@ -242,16 +242,16 @@
 #endif
 
 	sig = next_signal(current, mask);
-	if (current->notifier) {
-		if (sigismember(current->notifier_mask, sig)) {
-			if (!(current->notifier)(current->notifier_data)) {
-				current->sigpending = 0;
-				return 0;
+	if (sig) {
+		if (current->notifier) {
+			if (sigismember(current->notifier_mask, sig)) {
+				if (!(current->notifier)(current->notifier_data)) {
+					current->sigpending = 0;
+					return 0;
+				}
 			}
 		}
-	}
 
-	if (sig) {
 		if (!collect_signal(sig, &current->pending, info))
 			sig = 0;
 				
diff -u --recursive --new-file v2.4.9/linux/kernel/sysctl.c linux/kernel/sysctl.c
--- v2.4.9/linux/kernel/sysctl.c	Sun Aug 12 13:28:01 2001
+++ linux/kernel/sysctl.c	Tue Aug 28 07:11:33 2001
@@ -83,8 +83,8 @@
 extern int sysctl_userprocess_debug;
 #endif
 
-#ifdef __powerpc__
-extern unsigned long htab_reclaim_on, zero_paged_on, powersave_nap;
+#ifdef CONFIG_PPC32
+extern unsigned long zero_paged_on, powersave_nap;
 int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
 		  void *buffer, size_t *lenp);
 #endif
@@ -178,9 +178,7 @@
 	{KERN_SPARC_STOP_A, "stop-a", &stop_a_enabled, sizeof (int),
 	 0644, NULL, &proc_dointvec},
 #endif
-#ifdef __powerpc__
-	{KERN_PPC_HTABRECLAIM, "htab-reclaim", &htab_reclaim_on, sizeof(int),
-	 0644, NULL, &proc_dointvec},
+#ifdef CONFIG_PPC32
 	{KERN_PPC_ZEROPAGED, "zero-paged", &zero_paged_on, sizeof(int),
 	 0644, NULL, &proc_dointvec},
 	{KERN_PPC_POWERSAVE_NAP, "powersave-nap", &powersave_nap, sizeof(int),
diff -u --recursive --new-file v2.4.9/linux/lib/Makefile linux/lib/Makefile
--- v2.4.9/linux/lib/Makefile	Wed Apr 25 13:31:03 2001
+++ linux/lib/Makefile	Tue Aug 28 07:11:33 2001
@@ -8,7 +8,7 @@
 
 L_TARGET := lib.a
 
-export-objs := cmdline.o rwsem-spinlock.o rwsem.o
+export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o
 
 obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o
 
diff -u --recursive --new-file v2.4.9/linux/lib/dec_and_lock.c linux/lib/dec_and_lock.c
--- v2.4.9/linux/lib/dec_and_lock.c	Fri Jul  7 16:22:48 2000
+++ linux/lib/dec_and_lock.c	Tue Aug 28 07:11:33 2001
@@ -1,3 +1,4 @@
+#include <linux/module.h>
 #include <linux/spinlock.h>
 #include <asm/atomic.h>
 
@@ -34,4 +35,6 @@
 	spin_unlock(lock);
 	return 0;
 }
+
+EXPORT_SYMBOL(atomic_dec_and_lock);
 #endif
diff -u --recursive --new-file v2.4.9/linux/mm/filemap.c linux/mm/filemap.c
--- v2.4.9/linux/mm/filemap.c	Mon Aug 27 12:41:49 2001
+++ linux/mm/filemap.c	Tue Aug 28 11:09:19 2001
@@ -2541,6 +2541,7 @@
 
 	while (count) {
 		unsigned long index, offset;
+		long page_fault;
 		char *kaddr;
 
 		/*
@@ -2574,15 +2575,15 @@
 			PAGE_BUG(page);
 		}
 
+		kaddr = kmap(page);
 		status = mapping->a_ops->prepare_write(file, page, offset, offset+bytes);
 		if (status)
 			goto unlock;
-		kaddr = page_address(page);
-		status = __copy_from_user(kaddr+offset, buf, bytes);
+		page_fault = __copy_from_user(kaddr+offset, buf, bytes);
 		flush_dcache_page(page);
-		if (status)
-			goto fail_write;
 		status = mapping->a_ops->commit_write(file, page, offset, offset+bytes);
+		if (page_fault)
+			goto fail_write;
 		if (!status)
 			status = bytes;
 
@@ -2593,6 +2594,7 @@
 			buf += status;
 		}
 unlock:
+		kunmap(page);
 		/* Mark it unlocked again and drop the page.. */
 		UnlockPage(page);
 		check_used_once(page);
@@ -2618,8 +2620,6 @@
 	return err;
 fail_write:
 	status = -EFAULT;
-	ClearPageUptodate(page);
-	kunmap(page);
 	goto unlock;
 }
 
diff -u --recursive --new-file v2.4.9/linux/mm/highmem.c linux/mm/highmem.c
--- v2.4.9/linux/mm/highmem.c	Mon Aug 27 12:41:49 2001
+++ linux/mm/highmem.c	Mon Aug 27 21:03:37 2001
@@ -321,7 +321,7 @@
 	struct page *page;
 
 repeat_alloc:
-	page = alloc_page(GFP_NOIO);
+	page = alloc_page(GFP_NOHIGHIO);
 	if (page)
 		return page;
 	/*
@@ -359,7 +359,7 @@
 	struct buffer_head *bh;
 
 repeat_alloc:
-	bh = kmem_cache_alloc(bh_cachep, SLAB_NOIO);
+	bh = kmem_cache_alloc(bh_cachep, SLAB_NOHIGHIO);
 	if (bh)
 		return bh;
 	/*
diff -u --recursive --new-file v2.4.9/linux/mm/memory.c linux/mm/memory.c
--- v2.4.9/linux/mm/memory.c	Mon Aug 27 12:41:49 2001
+++ linux/mm/memory.c	Sun Aug 26 20:32:18 2001
@@ -1119,6 +1119,7 @@
 			 */
 			return pte_same(*page_table, orig_pte) ? -1 : 1;
 		}
+		SetPageReferenced(page);
 	}
 
 	/*
diff -u --recursive --new-file v2.4.9/linux/mm/page_alloc.c linux/mm/page_alloc.c
--- v2.4.9/linux/mm/page_alloc.c	Mon Aug 27 12:41:49 2001
+++ linux/mm/page_alloc.c	Tue Aug 28 07:09:44 2001
@@ -502,7 +502,8 @@
 	}
 
 	/* No luck.. */
-	printk(KERN_ERR "__alloc_pages: %lu-order allocation failed.\n", order);
+	printk(KERN_ERR "__alloc_pages: %lu-order allocation failed (gfp=0x%x/%i).\n",
+		order, gfp_mask, !!(current->flags & PF_MEMALLOC));
 	return NULL;
 }
 
diff -u --recursive --new-file v2.4.9/linux/mm/shmem.c linux/mm/shmem.c
--- v2.4.9/linux/mm/shmem.c	Sun Aug 12 13:28:01 2001
+++ linux/mm/shmem.c	Tue Aug 28 10:56:06 2001
@@ -1158,6 +1158,7 @@
 #else
 static DECLARE_FSTYPE(tmpfs_fs_type, "tmpfs", shmem_read_super, FS_LITTER|FS_NOMOUNT);
 #endif
+static struct vfsmount *shm_mnt;
 
 static int __init init_shmem_fs(void)
 {
@@ -1181,6 +1182,7 @@
 		unregister_filesystem(&tmpfs_fs_type);
 		return PTR_ERR(res);
 	}
+	shm_mnt = res;
 
 	/* The internal instance should not do size checking */
 	if ((error = shmem_set_size(&res->mnt_sb->u.shmem_sb, ULONG_MAX, ULONG_MAX)))
@@ -1195,6 +1197,7 @@
 	unregister_filesystem(&shmem_fs_type);
 #endif
 	unregister_filesystem(&tmpfs_fs_type);
+	mntput(shm_mnt);
 }
 
 module_init(init_shmem_fs)
@@ -1292,7 +1295,7 @@
 	this.name = name;
 	this.len = strlen(name);
 	this.hash = 0; /* will go */
-	root = tmpfs_fs_type.kern_mnt->mnt_root;
+	root = shm_mnt->mnt_root;
 	dentry = d_alloc(root, &this);
 	if (!dentry)
 		return ERR_PTR(-ENOMEM);
@@ -1310,7 +1313,7 @@
 	d_instantiate(dentry, inode);
 	dentry->d_inode->i_size = size;
 	shmem_truncate(inode);
-	file->f_vfsmnt = mntget(tmpfs_fs_type.kern_mnt);
+	file->f_vfsmnt = mntget(shm_mnt);
 	file->f_dentry = dentry;
 	file->f_op = &shmem_file_operations;
 	file->f_mode = FMODE_WRITE | FMODE_READ;
diff -u --recursive --new-file v2.4.9/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- v2.4.9/linux/net/appletalk/ddp.c	Mon Aug 27 12:41:49 2001
+++ linux/net/appletalk/ddp.c	Tue Aug 28 07:09:44 2001
@@ -752,7 +752,7 @@
 
 /* ioctl calls. Shouldn't even need touching */
 /* Device configuration ioctl calls */
-int atif_ioctl(int cmd, void *arg)
+static int atif_ioctl(int cmd, void *arg)
 {
 	static char aarp_mcast[6] = {0x09, 0x00, 0x00, 0xFF, 0xFF, 0xFF};
 	struct ifreq atreq;
@@ -1855,7 +1855,15 @@
 		case SIOCDIFADDR:
 		case SIOCSARP:	/* proxy AARP */
 		case SIOCDARP:	/* proxy AARP */
-			return atif_ioctl(cmd, (void *)arg);
+		{
+			int ret;
+
+			rtnl_lock();
+			ret = atif_ioctl(cmd, (void *)arg);
+			rtnl_unlock();
+
+			return ret;
+		}
 		/* Physical layer ioctl calls */
 		case SIOCSIFLINK:
 		case SIOCGIFHWADDR:
diff -u --recursive --new-file v2.4.9/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- v2.4.9/linux/net/ipv4/icmp.c	Sun Aug 12 13:28:01 2001
+++ linux/net/ipv4/icmp.c	Tue Aug 28 07:09:44 2001
@@ -3,7 +3,7 @@
  *	
  *		Alan Cox, <alan@redhat.com>
  *
- *	Version: $Id: icmp.c,v 1.79 2001/08/03 22:20:39 davem Exp $
+ *	Version: $Id: icmp.c,v 1.80 2001/08/22 20:38:41 davem Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License
@@ -16,6 +16,9 @@
  *	Other than that this module is a complete rewrite.
  *
  *	Fixes:
+ *	Clemens Fruhwirth	:	introduce global icmp rate limiting
+ *					with icmp type masking ability instead
+ *					of broken per type icmp timeouts.
  *		Mike Shaver	:	RFC1122 checks.
  *		Alan Cox	:	Multicast ping reply as self.
  *		Alan Cox	:	Fix atomicity lockup in ip_build_xmit 
@@ -143,6 +146,21 @@
 /* Control parameter - ignore bogus broadcast responses? */
 int sysctl_icmp_ignore_bogus_error_responses;
 
+/* 
+ * 	Configurable global rate limit.
+ *
+ *	ratelimit defines tokens/packet consumed for dst->rate_token bucket
+ *	ratemask defines which icmp types are ratelimited by setting
+ * 	it's bit position.
+ *
+ *	default: 
+ *	dest unreachable (0x03), source quench (0x04),
+ *	time exceeded (0x11), parameter problem (0x12)
+ */
+
+int sysctl_icmp_ratelimit = 1*HZ;
+int sysctl_icmp_ratemask = 0x1818;
+
 /*
  *	ICMP control array. This specifies what to do with each ICMP.
  */
@@ -153,7 +171,6 @@
 	unsigned long *input;		/* Address to increment on input */
 	void (*handler)(struct sk_buff *skb);
 	short	error;		/* This ICMP is classed as an error message */
-	int *timeout; /* Rate limit */
 };
 
 static struct icmp_control icmp_pointers[NR_ICMP_TYPES+1];
@@ -221,11 +238,6 @@
  *	Note that the same dst_entry fields are modified by functions in 
  *	route.c too, but these work for packet destinations while xrlim_allow
  *	works for icmp destinations. This means the rate limiting information
- *	for one "ip object" is shared.
- *
- *	Note that the same dst_entry fields are modified by functions in 
- *	route.c too, but these work for packet destinations while xrlim_allow
- *	works for icmp destinations. This means the rate limiting information
  *	for one "ip object" is shared - and these ICMPs are twice limited:
  *	by source and by destination.
  *
@@ -238,15 +250,12 @@
 int xrlim_allow(struct dst_entry *dst, int timeout)
 {
 	unsigned long now;
-	static int burst = HZ;
 
 	now = jiffies;
 	dst->rate_tokens += now - dst->rate_last;
 	dst->rate_last = now;
-	if (burst < XRLIM_BURST_FACTOR*timeout)
-		burst = XRLIM_BURST_FACTOR*timeout;
-	if (dst->rate_tokens > burst)
-		dst->rate_tokens = burst;
+	if (dst->rate_tokens > XRLIM_BURST_FACTOR*timeout)
+        	dst->rate_tokens = XRLIM_BURST_FACTOR*timeout;
 	if (dst->rate_tokens >= timeout) {
 		dst->rate_tokens -= timeout;
 		return 1;
@@ -258,22 +267,22 @@
 {
 	struct dst_entry *dst = &rt->u.dst; 
 
-	if (type > NR_ICMP_TYPES || !icmp_pointers[type].timeout)
+	if (type > NR_ICMP_TYPES)
 		return 1;
 
 	/* Don't limit PMTU discovery. */
 	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
 		return 1;
 
-	/* Redirect has its own rate limit mechanism */
-	if (type == ICMP_REDIRECT)
-		return 1;
-
 	/* No rate limit on loopback */
 	if (dst->dev && (dst->dev->flags&IFF_LOOPBACK))
  		return 1;
 
-	return xrlim_allow(dst, *(icmp_pointers[type].timeout));
+	/* Limit if icmp type is enabled in ratemask. */
+	if((1 << type) & sysctl_icmp_ratemask)
+		return xrlim_allow(dst, sysctl_icmp_ratelimit);
+	else
+		return 1;
 }
 
 /*
@@ -929,57 +938,43 @@
 	goto drop;
 }
 
-
-/* 
- * 	Configurable rate limits.
- *	Someone should check if these default values are correct.
- *	Note that these values interact with the routing cache GC timeout.
- *	If you chose them too high they won't take effect, because the
- *	dst_entry gets expired too early. The same should happen when
- *	the cache grows too big.
- */
-int sysctl_icmp_destunreach_time = 1*HZ;
-int sysctl_icmp_timeexceed_time = 1*HZ;
-int sysctl_icmp_paramprob_time = 1*HZ;
-int sysctl_icmp_echoreply_time; /* don't limit it per default. */
-
 /*
  *	This table is the definition of how we handle ICMP.
  */
  
 static struct icmp_control icmp_pointers[NR_ICMP_TYPES+1] = {
 /* ECHO REPLY (0) */
- { &icmp_statistics[0].IcmpOutEchoReps, &icmp_statistics[0].IcmpInEchoReps, icmp_discard, 0, &sysctl_icmp_echoreply_time},
- { &icmp_statistics[0].dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1, },
- { &icmp_statistics[0].dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1, },
+ { &icmp_statistics[0].IcmpOutEchoReps, &icmp_statistics[0].IcmpInEchoReps, icmp_discard, 0 },
+ { &icmp_statistics[0].dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1 },
+ { &icmp_statistics[0].dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1 },
 /* DEST UNREACH (3) */
- { &icmp_statistics[0].IcmpOutDestUnreachs, &icmp_statistics[0].IcmpInDestUnreachs, icmp_unreach, 1, &sysctl_icmp_destunreach_time },
+ { &icmp_statistics[0].IcmpOutDestUnreachs, &icmp_statistics[0].IcmpInDestUnreachs, icmp_unreach, 1 },
 /* SOURCE QUENCH (4) */
- { &icmp_statistics[0].IcmpOutSrcQuenchs, &icmp_statistics[0].IcmpInSrcQuenchs, icmp_unreach, 1, },
+ { &icmp_statistics[0].IcmpOutSrcQuenchs, &icmp_statistics[0].IcmpInSrcQuenchs, icmp_unreach, 1 },
 /* REDIRECT (5) */
- { &icmp_statistics[0].IcmpOutRedirects, &icmp_statistics[0].IcmpInRedirects, icmp_redirect, 1, },
- { &icmp_statistics[0].dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1, },
- { &icmp_statistics[0].dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1, },
+ { &icmp_statistics[0].IcmpOutRedirects, &icmp_statistics[0].IcmpInRedirects, icmp_redirect, 1 },
+ { &icmp_statistics[0].dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1 },
+ { &icmp_statistics[0].dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1 },
 /* ECHO (8) */
- { &icmp_statistics[0].IcmpOutEchos, &icmp_statistics[0].IcmpInEchos, icmp_echo, 0, },
- { &icmp_statistics[0].dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1, },
- { &icmp_statistics[0].dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1, },
+ { &icmp_statistics[0].IcmpOutEchos, &icmp_statistics[0].IcmpInEchos, icmp_echo, 0 },
+ { &icmp_statistics[0].dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1 },
+ { &icmp_statistics[0].dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1 },
 /* TIME EXCEEDED (11) */
- { &icmp_statistics[0].IcmpOutTimeExcds, &icmp_statistics[0].IcmpInTimeExcds, icmp_unreach, 1, &sysctl_icmp_timeexceed_time },
+ { &icmp_statistics[0].IcmpOutTimeExcds, &icmp_statistics[0].IcmpInTimeExcds, icmp_unreach, 1 },
 /* PARAMETER PROBLEM (12) */
- { &icmp_statistics[0].IcmpOutParmProbs, &icmp_statistics[0].IcmpInParmProbs, icmp_unreach, 1, &sysctl_icmp_paramprob_time },
+ { &icmp_statistics[0].IcmpOutParmProbs, &icmp_statistics[0].IcmpInParmProbs, icmp_unreach, 1 },
 /* TIMESTAMP (13) */
- { &icmp_statistics[0].IcmpOutTimestamps, &icmp_statistics[0].IcmpInTimestamps, icmp_timestamp, 0,  },
+ { &icmp_statistics[0].IcmpOutTimestamps, &icmp_statistics[0].IcmpInTimestamps, icmp_timestamp, 0  },
 /* TIMESTAMP REPLY (14) */
- { &icmp_statistics[0].IcmpOutTimestampReps, &icmp_statistics[0].IcmpInTimestampReps, icmp_discard, 0, },
+ { &icmp_statistics[0].IcmpOutTimestampReps, &icmp_statistics[0].IcmpInTimestampReps, icmp_discard, 0 },
 /* INFO (15) */
- { &icmp_statistics[0].dummy, &icmp_statistics[0].dummy, icmp_discard, 0, },
+ { &icmp_statistics[0].dummy, &icmp_statistics[0].dummy, icmp_discard, 0 },
 /* INFO REPLY (16) */
- { &icmp_statistics[0].dummy, &icmp_statistics[0].dummy, icmp_discard, 0, },
+ { &icmp_statistics[0].dummy, &icmp_statistics[0].dummy, icmp_discard, 0 },
 /* ADDR MASK (17) */
- { &icmp_statistics[0].IcmpOutAddrMasks, &icmp_statistics[0].IcmpInAddrMasks, icmp_address, 0,  },
+ { &icmp_statistics[0].IcmpOutAddrMasks, &icmp_statistics[0].IcmpInAddrMasks, icmp_address, 0  },
 /* ADDR MASK REPLY (18) */
- { &icmp_statistics[0].IcmpOutAddrMaskReps, &icmp_statistics[0].IcmpInAddrMaskReps, icmp_address_reply, 0, }
+ { &icmp_statistics[0].IcmpOutAddrMaskReps, &icmp_statistics[0].IcmpInAddrMaskReps, icmp_address_reply, 0 }
 };
 
 void __init icmp_init(struct net_proto_family *ops)
diff -u --recursive --new-file v2.4.9/linux/net/ipv4/netfilter/ip_nat_helper.c linux/net/ipv4/netfilter/ip_nat_helper.c
--- v2.4.9/linux/net/ipv4/netfilter/ip_nat_helper.c	Fri Apr 27 14:15:01 2001
+++ linux/net/ipv4/netfilter/ip_nat_helper.c	Tue Aug 28 07:09:44 2001
@@ -267,8 +267,8 @@
 		/* Replace with NOPs. */
 		tcph->check
 			= ip_nat_cheat_check(*((u_int16_t *)(opt + i))^0xFFFF,
-					     0, tcph->check);
-		opt[i] = opt[i+1] = 0;
+					     (TCPOPT_NOP<<8)|TCPOPT_NOP, tcph->check);
+		opt[i] = opt[i+1] = TCPOPT_NOP;
 	}
 	else DEBUGP("Something wrong with SACK_PERM.\n");
 }
diff -u --recursive --new-file v2.4.9/linux/net/ipv4/sysctl_net_ipv4.c linux/net/ipv4/sysctl_net_ipv4.c
--- v2.4.9/linux/net/ipv4/sysctl_net_ipv4.c	Sun Mar 25 18:14:25 2001
+++ linux/net/ipv4/sysctl_net_ipv4.c	Tue Aug 28 07:09:44 2001
@@ -1,7 +1,7 @@
 /*
  * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem.
  *
- * $Id: sysctl_net_ipv4.c,v 1.48 2001/02/23 01:39:05 davem Exp $
+ * $Id: sysctl_net_ipv4.c,v 1.49 2001/08/22 20:38:41 davem Exp $
  *
  * Begun April 1, 1996, Mike Shaver.
  * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS]
@@ -32,10 +32,8 @@
 extern int sysctl_ip_dynaddr;
 
 /* From icmp.c */
-extern int sysctl_icmp_destunreach_time;
-extern int sysctl_icmp_timeexceed_time;
-extern int sysctl_icmp_paramprob_time;
-extern int sysctl_icmp_echoreply_time;
+extern int sysctl_icmp_ratelimit;
+extern int sysctl_icmp_ratemask;
 
 /* From igmp.c */
 extern int sysctl_igmp_max_memberships;
@@ -178,14 +176,6 @@
 	{NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES, "icmp_ignore_bogus_error_responses",
 	 &sysctl_icmp_ignore_bogus_error_responses, sizeof(int), 0644, NULL,
 	 &proc_dointvec},
-	{NET_IPV4_ICMP_DESTUNREACH_RATE, "icmp_destunreach_rate",
-	 &sysctl_icmp_destunreach_time, sizeof(int), 0644, NULL, &proc_dointvec},
-	{NET_IPV4_ICMP_TIMEEXCEED_RATE, "icmp_timeexceed_rate",
-	 &sysctl_icmp_timeexceed_time, sizeof(int), 0644, NULL, &proc_dointvec},
-	{NET_IPV4_ICMP_PARAMPROB_RATE, "icmp_paramprob_rate",
-	 &sysctl_icmp_paramprob_time, sizeof(int), 0644, NULL, &proc_dointvec},
-	{NET_IPV4_ICMP_ECHOREPLY_RATE, "icmp_echoreply_rate",
-	 &sysctl_icmp_echoreply_time, sizeof(int), 0644, NULL, &proc_dointvec},
 	{NET_IPV4_ROUTE, "route", NULL, 0, 0555, ipv4_route_table},
 #ifdef CONFIG_IP_MULTICAST
 	{NET_IPV4_IGMP_MAX_MEMBERSHIPS, "igmp_max_memberships",
@@ -227,6 +217,10 @@
 	 &sysctl_tcp_app_win, sizeof(int), 0644, NULL, &proc_dointvec},
 	{NET_TCP_ADV_WIN_SCALE, "tcp_adv_win_scale",
 	 &sysctl_tcp_adv_win_scale, sizeof(int), 0644, NULL, &proc_dointvec},
+	{NET_IPV4_ICMP_RATELIMIT, "icmp_ratelimit",
+	 &sysctl_icmp_ratelimit, sizeof(int), 0644, NULL, &proc_dointvec},
+	{NET_IPV4_ICMP_RATEMASK, "icmp_ratemask",
+	 &sysctl_icmp_ratemask, sizeof(int), 0644, NULL, &proc_dointvec},
 	{0}
 };
 
diff -u --recursive --new-file v2.4.9/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.4.9/linux/net/ipv4/tcp.c	Mon Aug 27 12:41:49 2001
+++ linux/net/ipv4/tcp.c	Tue Aug 28 07:11:33 2001
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.208 2001/08/13 18:56:12 davem Exp $
+ * Version:	$Id: tcp.c,v 1.209 2001/08/28 00:31:04 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -2361,7 +2361,7 @@
 			val = (val ? : sysctl_tcp_fin_timeout)/HZ;
 		break;
 	case TCP_DEFER_ACCEPT:
-		val = tp->defer_accept == 0 ? 0 : (TCP_TIMEOUT_INIT<<(tp->defer_accept-1));
+		val = tp->defer_accept == 0 ? 0 : ((TCP_TIMEOUT_INIT/HZ)<<(tp->defer_accept-1));
 		break;
 	case TCP_WINDOW_CLAMP:
 		val = tp->window_clamp;
diff -u --recursive --new-file v2.4.9/linux/net/socket.c linux/net/socket.c
--- v2.4.9/linux/net/socket.c	Wed Jul 25 17:10:27 2001
+++ linux/net/socket.c	Tue Aug 28 10:56:06 2001
@@ -303,8 +303,7 @@
 }
 
 static struct vfsmount *sock_mnt;
-static DECLARE_FSTYPE(sock_fs_type, "sockfs", sockfs_read_super,
-	FS_NOMOUNT|FS_SINGLE);
+static DECLARE_FSTYPE(sock_fs_type, "sockfs", sockfs_read_super, FS_NOMOUNT);
 static int sockfs_delete_dentry(struct dentry *dentry)
 {
 	return 1;
@@ -1205,13 +1204,14 @@
 	msg.msg_iovlen=1;
 	msg.msg_control=NULL;
 	msg.msg_controllen=0;
-	msg.msg_namelen=addr_len;
+	msg.msg_namelen=0;
 	if(addr)
 	{
 		err = move_addr_to_kernel(addr, addr_len, address);
 		if (err < 0)
 			goto out_put;
 		msg.msg_name=address;
+		msg.msg_namelen=addr_len;
 	}
 	if (sock->file->f_flags & O_NONBLOCK)
 		flags |= MSG_DONTWAIT;
