# This is a BitKeeper generated diff -Nru style patch.
#
# drivers/video/riva/fbdev.c
#   2004/02/12 08:39:59-08:00 benh@kernel.crashing.org +4 -0
#   fix rivafb build on ppc64
# 
# ChangeSet
#   2004/02/11 21:53:47-08:00 benh@kernel.crashing.org 
#   [PATCH] fix rivafb build on ppc64
#   
#   rivafb is part of the g5 defconfig, but will cause a build error
#   on ppc64 due to a missing #include, here is the fix.
# 
# ChangeSet
#   2004/02/12 16:21:43+11:00 benh@kernel.crashing.org 
#   ppc64: Add defconfigs for pSeries and PowerMac G5
# 
# arch/ppc64/configs/g5_defconfig
#   2004/02/12 16:21:02+11:00 benh@kernel.crashing.org +1078 -0
# 
# arch/ppc64/configs/g5_defconfig
#   2004/02/12 16:21:02+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/arch/ppc64/configs/g5_defconfig
# 
# arch/ppc64/configs/pSeries_defconfig
#   2004/02/12 16:17:38+11:00 benh@kernel.crashing.org +783 -0
# 
# arch/ppc64/configs/pSeries_defconfig
#   2004/02/12 16:17:38+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/arch/ppc64/configs/pSeries_defconfig
# 
# ChangeSet
#   2004/02/12 15:52:47+11:00 benh@kernel.crashing.org 
#   ppc64: Don't build offb's code that relies on the BootX bootloader on ppc64
# 
# drivers/video/offb.c
#   2004/02/12 15:52:37+11:00 benh@kernel.crashing.org +2 -2
#   ppc64: Don't build offb's code that relies on the BootX bootloader on ppc64
# 
# ChangeSet
#   2004/02/12 15:51:57+11:00 benh@kernel.crashing.org 
#   ppc64: Add missing #include, warned on ppc32 and broke build on ppc64
# 
# drivers/video/fbmon.c
#   2004/02/12 15:51:44+11:00 benh@kernel.crashing.org +1 -0
#   ppc64: Add missing #include, warned on ppc32 and broke build on ppc64
# 
# ChangeSet
#   2004/02/12 15:50:52+11:00 benh@kernel.crashing.org 
#   ppc64: Fix break handling in pmac_zilog driver, fixes for 64 bits kernel
# 
# drivers/serial/pmac_zilog.c
#   2004/02/12 15:50:41+11:00 benh@kernel.crashing.org +34 -37
#   ppc64: Fix break handling in pmac_zilog driver, fixes for 64 bits kernel
# 
# ChangeSet
#   2004/02/12 15:49:46+11:00 benh@kernel.crashing.org 
#   ppc64: Fix build of via-pmu driver on 64 bits kernel.
# 
# drivers/macintosh/via-pmu.c
#   2004/02/12 15:49:35+11:00 benh@kernel.crashing.org +8 -2
#   ppc64: Fix build of via-pmu driver on 64 bits kernel.
# 
# ChangeSet
#   2004/02/12 15:47:20+11:00 benh@kernel.crashing.org 
#   ppc64: Fix a refounting issue in macio_asic
# 
# drivers/macintosh/macio_asic.c
#   2004/02/12 15:47:10+11:00 benh@kernel.crashing.org +3 -0
#   ppc64: Fix a refounting issue in macio_asic
# 
# ChangeSet
#   2004/02/12 15:46:41+11:00 benh@kernel.crashing.org 
#   ppc64: fix build of ADB driver
# 
# drivers/macintosh/adb.c
#   2004/02/12 15:46:29+11:00 benh@kernel.crashing.org +2 -2
#   ppc64: fix build of ADB driver
# 
# ChangeSet
#   2004/02/12 15:45:59+11:00 benh@kernel.crashing.org 
#   ppc64: fix build of pmac "mac-io" IDE driver on 64 bits kernel
# 
# drivers/ide/ppc/pmac.c
#   2004/02/12 15:45:47+11:00 benh@kernel.crashing.org +17 -6
#   ppc64: fix build of pmac "mac-io" IDE driver on 64 bits kernel
# 
# ChangeSet
#   2004/02/12 15:45:12+11:00 benh@kernel.crashing.org 
#   ppc64: Switch off use of polled mode in i2c driver
#   
#   The secondary MPIC is now supported on ppc64, so the driver can
#   use interrupts all the time now
# 
# drivers/i2c/busses/i2c-keywest.c
#   2004/02/12 15:44:59+11:00 benh@kernel.crashing.org +0 -7
#   ppc64: Switch off use of polled mode in i2c driver
#   
#   The secondary MPIC is now supported on ppc64, so the driver can
#   use interrupts all the time now
# 
# ChangeSet
#   2004/02/12 15:43:20+11:00 benh@kernel.crashing.org 
#   ppc64: Add SMP support for PowerMac G5
# 
# include/asm-ppc64/machdep.h
#   2004/02/12 15:43:05+11:00 benh@kernel.crashing.org +0 -4
#   ppc64: Add SMP support for PowerMac G5
# 
# arch/ppc64/kernel/smp.c
#   2004/02/12 15:43:05+11:00 benh@kernel.crashing.org +37 -24
#   ppc64: Add SMP support for PowerMac G5
# 
# ChangeSet
#   2004/02/12 15:41:38+11:00 benh@kernel.crashing.org 
#   ppc64: Add pciconfig_iobase syscall for 32 bits apps only
#   
#   This syscall is used by XFree to retreive the IO base of the
#   bus where the video card is plugged. This is only implemented
#   for compatibility with existing XFree86, I don't plan to do
#   a 64 bits version, XFree shall be fixed to use proper PCI access
#   methods
# 
# arch/ppc64/kernel/sys_ppc32.c
#   2004/02/12 15:41:27+11:00 benh@kernel.crashing.org +61 -1
#   ppc64: Add pciconfig_iobase syscall for 32 bits apps only
#   
#   This syscall is used by XFree to retreive the IO base of the
#   bus where the video card is plugged. This is only implemented
#   for compatibility with existing XFree86, I don't plan to do
#   a 64 bits version, XFree shall be fixed to use proper PCI access
#   methods
# 
# arch/ppc64/kernel/misc.S
#   2004/02/12 15:41:27+11:00 benh@kernel.crashing.org +2 -2
#   ppc64: Add pciconfig_iobase syscall for 32 bits apps only
#   
#   This syscall is used by XFree to retreive the IO base of the
#   bus where the video card is plugged. This is only implemented
#   for compatibility with existing XFree86, I don't plan to do
#   a 64 bits version, XFree shall be fixed to use proper PCI access
#   methods
# 
# ChangeSet
#   2004/02/12 15:39:34+11:00 benh@kernel.crashing.org 
#   ppc64: Add CPU NAP mode in idle loop on PowerMac G5
# 
# arch/ppc64/kernel/setup.c
#   2004/02/12 15:39:21+11:00 benh@kernel.crashing.org +2 -0
#   ppc64: Add CPU NAP mode in idle loop on PowerMac G5
# 
# arch/ppc64/kernel/idle.c
#   2004/02/12 15:39:21+11:00 benh@kernel.crashing.org +15 -0
#   ppc64: Add CPU NAP mode in idle loop on PowerMac G5
# 
# ChangeSet
#   2004/02/12 15:37:52+11:00 benh@kernel.crashing.org 
#   ppc64: Call the PowerMac G5 init routines
# 
# arch/ppc64/kernel/setup.c
#   2004/02/12 15:37:40+11:00 benh@kernel.crashing.org +37 -4
#   ppc64: Call the PowerMac G5 init routines
# 
# ChangeSet
#   2004/02/12 15:36:26+11:00 benh@kernel.crashing.org 
#   ppc64: Add support for z85c30 SCCs for low level console (PowerMac G5)
#   
#   This is only used with the "sccdbg" kernel command line option, as
#   you need a special adapter (www.geethree.com) to get access to the
#   serial port on those machines.
# 
# arch/ppc64/kernel/udbg.c
#   2004/02/12 15:36:15+11:00 benh@kernel.crashing.org +87 -0
#   ppc64: Add support for z85c30 SCCs for low level console (PowerMac G5)
#   
#   This is only used with the "sccdbg" kernel command line option, as
#   you need a special adapter (www.geethree.com) to get access to the
#   serial port on those machines.
# 
# ChangeSet
#   2004/02/12 15:33:50+11:00 benh@kernel.crashing.org 
#   ppc64: xmon breakpoints are support on PowerMac G5 too
# 
# arch/ppc64/xmon/xmon.c
#   2004/02/12 15:33:39+11:00 benh@kernel.crashing.org +2 -1
#   ppc64: xmon breakpoints are support on PowerMac G5 too
# 
# ChangeSet
#   2004/02/12 15:33:06+11:00 benh@kernel.crashing.org 
#   ppc64: Add a missing isync in __hash_page, alloc hash table on PowerMac G5
# 
# arch/ppc64/mm/hash_utils.c
#   2004/02/12 15:32:56+11:00 benh@kernel.crashing.org +2 -1
#   ppc64: Add a missing isync in __hash_page, alloc hash table on PowerMac G5
# 
# arch/ppc64/mm/hash_low.S
#   2004/02/12 15:32:56+11:00 benh@kernel.crashing.org +1 -1
#   ppc64: Add a missing isync in __hash_page, alloc hash table on PowerMac G5
# 
# ChangeSet
#   2004/02/12 15:31:59+11:00 benh@kernel.crashing.org 
#   ppc64: Remove duplicate (& incorrect) definition of kern_add_valid()
# 
# include/asm-ppc64/mmzone.h
#   2004/02/12 15:31:48+11:00 benh@kernel.crashing.org +0 -3
#   ppc64: Remove duplicate (& incorrect) definition of kern_add_valid()
# 
# ChangeSet
#   2004/02/12 15:31:14+11:00 benh@kernel.crashing.org 
#   ppc64: Add the feature_call function pointer to machdep
# 
# include/asm-ppc64/machdep.h
#   2004/02/12 15:31:04+11:00 benh@kernel.crashing.org +5 -0
#   ppc64: Add the feature_call function pointer to machdep
# 
# ChangeSet
#   2004/02/12 15:30:27+11:00 benh@kernel.crashing.org 
#   ppc64: Add support for PowerMac G5 interrupts
# 
# arch/ppc64/kernel/open_pic_defs.h
#   2004/02/12 15:30:16+11:00 benh@kernel.crashing.org +0 -34
#   ppc64: Add support for PowerMac G5 interrupts
# 
# arch/ppc64/kernel/open_pic.h
#   2004/02/12 15:30:16+11:00 benh@kernel.crashing.org +2 -0
#   ppc64: Add support for PowerMac G5 interrupts
# 
# arch/ppc64/kernel/open_pic.c
#   2004/02/12 15:30:16+11:00 benh@kernel.crashing.org +69 -12
#   ppc64: Add support for PowerMac G5 interrupts
# 
# arch/ppc64/kernel/chrp_setup.c
#   2004/02/12 15:30:16+11:00 benh@kernel.crashing.org +2 -2
#   ppc64: Add support for PowerMac G5 interrupts
# 
# ChangeSet
#   2004/02/12 15:28:02+11:00 benh@kernel.crashing.org 
#   ppc64: Add the G5 (IBM 970) CPU to the cputable
# 
# arch/ppc64/kernel/cputable.c
#   2004/02/12 15:27:51+11:00 benh@kernel.crashing.org +3 -2
#   ppc64: Add the G5 (IBM 970) CPU to the cputable
# 
# ChangeSet
#   2004/02/12 15:24:50+11:00 benh@kernel.crashing.org 
#   ppc64: Add the PowerMac PCI support
#   
#   This involves moving the final fixup to a function pointer in machdep,
#   turning all the PCI DMA routines into function pointers in a separate
#   structure and a bit of renaming work. The PowerMac currently use
#   "direct" PCI DMA bypassing the iommu. The driver for the IOMMU will
#   come later, allowing us to lift the limitation to 2Gb of RAM
# 
# include/asm-ppc64/pci_dma.h
#   2004/02/12 15:24:38+11:00 benh@kernel.crashing.org +4 -2
#   ppc64: Add PowerMac G5 PCI support
# 
# include/asm-ppc64/pci.h
#   2004/02/12 15:24:38+11:00 benh@kernel.crashing.org +56 -13
#   ppc64: Add PowerMac G5 PCI support
# 
# include/asm-ppc64/pci-bridge.h
#   2004/02/12 15:24:38+11:00 benh@kernel.crashing.org +4 -1
#   ppc64: Add PowerMac G5 PCI support
# 
# include/asm-ppc64/machdep.h
#   2004/02/12 15:24:38+11:00 benh@kernel.crashing.org +3 -0
#   ppc64: Add PowerMac G5 PCI support
# 
# arch/ppc64/kernel/pci_dn.c
#   2004/02/12 15:24:38+11:00 benh@kernel.crashing.org +1 -0
#   ppc64: Add PowerMac G5 PCI support
# 
# arch/ppc64/kernel/pci_dma.c
#   2004/02/12 15:24:38+11:00 benh@kernel.crashing.org +23 -8
#   ppc64: Add PowerMac G5 PCI support
# 
# arch/ppc64/kernel/pci.c
#   2004/02/12 15:24:38+11:00 benh@kernel.crashing.org +21 -5
#   ppc64: Add PowerMac G5 PCI support
# 
# arch/ppc64/kernel/pSeries_pci.c
#   2004/02/12 15:24:38+11:00 benh@kernel.crashing.org +1 -1
#   ppc64: Add PowerMac G5 PCI support
# 
# arch/ppc64/kernel/iSeries_setup.c
#   2004/02/12 15:24:38+11:00 benh@kernel.crashing.org +6 -3
#   ppc64: Add PowerMac G5 PCI support
# 
# arch/ppc64/kernel/iSeries_pci.c
#   2004/02/12 15:24:38+11:00 benh@kernel.crashing.org +2 -2
#   ppc64: Add PowerMac G5 PCI support
# 
# arch/ppc64/kernel/chrp_setup.c
#   2004/02/12 15:24:38+11:00 benh@kernel.crashing.org +3 -0
#   ppc64: Add PowerMac G5 PCI support
# 
# ChangeSet
#   2004/02/12 15:14:11+11:00 benh@kernel.crashing.org 
#   ppc64: Update the nvram driver to deal with PowerMac G5
#   
#   This involves making the actual read/write routines be indirect
#   through ppc_md, and adding the various nvram partition types
#   used on a PowerMac.
# 
# include/asm-ppc64/nvram.h
#   2004/02/12 15:14:00+11:00 benh@kernel.crashing.org +51 -6
#   ppc64: Update the nvram driver to deal with PowerMac G5
# 
# include/asm-ppc64/machdep.h
#   2004/02/12 15:14:00+11:00 benh@kernel.crashing.org +3 -0
#   ppc64: Update the nvram driver to deal with PowerMac G5
# 
# arch/ppc64/kernel/setup.c
#   2004/02/12 15:14:00+11:00 benh@kernel.crashing.org +7 -0
#   ppc64: Update the nvram driver to deal with PowerMac G5
# 
# arch/ppc64/kernel/nvram.c
#   2004/02/12 15:14:00+11:00 benh@kernel.crashing.org +263 -272
#   ppc64: Update the nvram driver to deal with PowerMac G5
# 
# arch/ppc64/kernel/chrp_setup.c
#   2004/02/12 15:14:00+11:00 benh@kernel.crashing.org +4 -3
#   ppc64: Update the nvram driver to deal with PowerMac G5
# 
# ChangeSet
#   2004/02/12 15:10:38+11:00 benh@kernel.crashing.org 
#   ppc32: Separate definitions for known vs unknown PowerMac G5 models
# 
# include/asm-ppc/pmac_feature.h
#   2004/02/12 15:10:27+11:00 benh@kernel.crashing.org +1 -0
#   ppc32: Separate definitions for known vs unknown PowerMac G5 models
# 
# arch/ppc/platforms/pmac_feature.c
#   2004/02/12 15:10:27+11:00 benh@kernel.crashing.org +1 -1
#   ppc32: Separate definitions for known vs unknown PowerMac G5 models
# 
# ChangeSet
#   2004/02/12 15:08:25+11:00 benh@kernel.crashing.org 
#   ppc64: Add support for PowerMacs in the OF client interface code (prom.c)
#   
#   Also move some of the init cruft into separate function to make
#   things slightly more readable. We sill need to significantly
#   cleanup that file, but that will come later...
#   
#   Properly export the OF device-tree accessors to modules
# 
# include/asm-ppc64/prom.h
#   2004/02/12 15:08:14+11:00 benh@kernel.crashing.org +7 -0
#   ppc64: Add support for PowerMacs in the OF client interface code (prom.c)
#   
#   Also move some of the init cruft into separate function to make
#   things slightly more readable. We sill need to significantly
#   cleanup that file, but that will come later...
#   
#   Properly export the OF device-tree accessors to modules
# 
# include/asm-ppc64/lmb.h
#   2004/02/12 15:08:14+11:00 benh@kernel.crashing.org +3 -2
#   ppc64: Add support for PowerMacs in the OF client interface code (prom.c)
#   
#   Also move some of the init cruft into separate function to make
#   things slightly more readable. We sill need to significantly
#   cleanup that file, but that will come later...
#   
#   Properly export the OF device-tree accessors to modules
# 
# arch/ppc64/kernel/prom.c
#   2004/02/12 15:08:14+11:00 benh@kernel.crashing.org +376 -78
#   ppc64: Add support for PowerMacs in the OF client interface code (prom.c)
#   
#   Also move some of the init cruft into separate function to make
#   things slightly more readable. We sill need to significantly
#   cleanup that file, but that will come later...
#   
#   Properly export the OF device-tree accessors to modules
# 
# ChangeSet
#   2004/02/12 15:03:58+11:00 benh@kernel.crashing.org 
#   ppc64: Add the head.S changes to boot a PowerMac G5.
#   
#   Apple's OF boots us with translation enabled. Also move the
#   copy_and_flush of the CPU holding loop to prom.c as it mustn't
#   be called on platforms that don't boot in real mode (that space
#   isn't always mapped)
# 
# arch/ppc64/kernel/prom.c
#   2004/02/12 15:03:45+11:00 benh@kernel.crashing.org +5 -0
#   ppc64: Add the head.S changes to boot a PowerMac G5.
#   
#   Apple's OF boots us with translation enabled. Also move the
#   copy_and_flush of the CPU holding loop to prom.c as it mustn't
#   be called on platforms that don't boot in real mode (that space
#   isn't always mapped)
# 
# arch/ppc64/kernel/head.S
#   2004/02/12 15:03:45+11:00 benh@kernel.crashing.org +87 -30
#   ppc64: Add the head.S changes to boot a PowerMac G5.
#   
#   Apple's OF boots us with translation enabled. Also move the
#   copy_and_flush of the CPU holding loop to prom.c as it mustn't
#   be called on platforms that don't boot in real mode (that space
#   isn't always mapped)
# 
# ChangeSet
#   2004/02/12 14:57:25+11:00 benh@kernel.crashing.org 
#   ppc64: Add some definitions relative to the G5 CPU and POWERMAC platform
# 
# include/asm-ppc64/systemcfg.h
#   2004/02/12 14:57:14+11:00 benh@kernel.crashing.org +6 -0
#   Add definitions for G5 CPU and POWERMAC platform
# 
# include/asm-ppc64/sections.h
#   2004/02/12 14:57:14+11:00 benh@kernel.crashing.org +12 -0
#   Add some empty includes used by some PowerMac code for ppc32 sections
# 
# include/asm-ppc64/processor.h
#   2004/02/12 14:57:14+11:00 benh@kernel.crashing.org +19 -1
#   Add some G5 specific definitions
# 
# arch/ppc64/kernel/smp.c
#   2004/02/12 14:57:14+11:00 benh@kernel.crashing.org +0 -7
#   Move set_tb to include asm/processor.h
# 
# ChangeSet
#   2004/02/12 14:53:14+11:00 benh@kernel.crashing.org 
#   ppc64: Add the Kconfig & Makefile changes related to the PowerMac G5 merge
# 
# drivers/macintosh/Kconfig
#   2004/02/12 14:53:03+11:00 benh@kernel.crashing.org +6 -6
#   ppc64: Add the Kconfig & Makefile changes related to the PowerMac G5 merge
# 
# arch/ppc64/kernel/Makefile
#   2004/02/12 14:53:03+11:00 benh@kernel.crashing.org +14 -4
#   ppc64: Add the Kconfig & Makefile changes related to the PowerMac G5 merge
# 
# arch/ppc64/Kconfig
#   2004/02/12 14:53:03+11:00 benh@kernel.crashing.org +22 -1
#   ppc64: Add the Kconfig & Makefile changes related to the PowerMac G5 merge
# 
# ChangeSet
#   2004/02/12 14:50:52+11:00 benh@kernel.crashing.org 
#   ppc64: Start of PowerMac G5 merge, add all arch and include files
# 
# include/asm-ppc64/xmon.h
#   2004/02/12 14:49:47+11:00 benh@kernel.crashing.org +17 -0
# 
# include/asm-ppc64/xmon.h
#   2004/02/12 14:49:47+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/include/asm-ppc64/xmon.h
# 
# include/asm-ppc64/uninorth.h
#   2004/02/12 14:49:46+11:00 benh@kernel.crashing.org +2 -0
# 
# include/asm-ppc64/uninorth.h
#   2004/02/12 14:49:46+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/include/asm-ppc64/uninorth.h
# 
# include/asm-ppc64/pmac_low_i2c.h
#   2004/02/12 14:49:45+11:00 benh@kernel.crashing.org +2 -0
# 
# include/asm-ppc64/pmac_low_i2c.h
#   2004/02/12 14:49:45+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/include/asm-ppc64/pmac_low_i2c.h
# 
# include/asm-ppc64/pmac_feature.h
#   2004/02/12 14:49:44+11:00 benh@kernel.crashing.org +2 -0
# 
# include/asm-ppc64/pmac_feature.h
#   2004/02/12 14:49:44+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/include/asm-ppc64/pmac_feature.h
# 
# include/asm-ppc64/offsets.h
#   2004/02/12 14:49:43+11:00 benh@kernel.crashing.org +110 -0
# 
# include/asm-ppc64/of_device.h
#   2004/02/12 14:49:43+11:00 benh@kernel.crashing.org +2 -0
# 
# include/asm-ppc64/offsets.h
#   2004/02/12 14:49:43+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/include/asm-ppc64/offsets.h
# 
# include/asm-ppc64/of_device.h
#   2004/02/12 14:49:43+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/include/asm-ppc64/of_device.h
# 
# include/asm-ppc64/macio.h
#   2004/02/12 14:49:42+11:00 benh@kernel.crashing.org +2 -0
# 
# include/asm-ppc64/macio.h
#   2004/02/12 14:49:42+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/include/asm-ppc64/macio.h
# 
# include/asm-ppc64/keylargo.h
#   2004/02/12 14:49:41+11:00 benh@kernel.crashing.org +2 -0
# 
# include/asm-ppc64/keylargo.h
#   2004/02/12 14:49:41+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/include/asm-ppc64/keylargo.h
# 
# include/asm-ppc64/dbdma.h
#   2004/02/12 14:49:40+11:00 benh@kernel.crashing.org +2 -0
# 
# include/asm-ppc64/dbdma.h
#   2004/02/12 14:49:40+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/include/asm-ppc64/dbdma.h
# 
# include/asm-ppc64/btext.h
#   2004/02/12 14:49:39+11:00 benh@kernel.crashing.org +29 -0
# 
# include/asm-ppc64/btext.h
#   2004/02/12 14:49:39+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/include/asm-ppc64/btext.h
# 
# include/asm-ppc64/bootx.h
#   2004/02/12 14:49:38+11:00 benh@kernel.crashing.org +135 -0
# 
# include/asm-ppc64/bootx.h
#   2004/02/12 14:49:38+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/include/asm-ppc64/bootx.h
# 
# arch/ppc64/kernel/smp-tbsync.c
#   2004/02/12 14:48:01+11:00 benh@kernel.crashing.org +179 -0
# 
# arch/ppc64/kernel/smp-tbsync.c
#   2004/02/12 14:48:01+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/arch/ppc64/kernel/smp-tbsync.c
# 
# arch/ppc64/kernel/pmac_time.c
#   2004/02/12 14:48:00+11:00 benh@kernel.crashing.org +157 -0
# 
# arch/ppc64/kernel/pmac_time.c
#   2004/02/12 14:48:00+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/arch/ppc64/kernel/pmac_time.c
# 
# arch/ppc64/kernel/pmac_smp.c
#   2004/02/12 14:47:59+11:00 benh@kernel.crashing.org +174 -0
# 
# arch/ppc64/kernel/pmac_smp.c
#   2004/02/12 14:47:59+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/arch/ppc64/kernel/pmac_smp.c
# 
# arch/ppc64/kernel/pmac_setup.c
#   2004/02/12 14:47:59+11:00 benh@kernel.crashing.org +504 -0
# 
# arch/ppc64/kernel/pmac_pci.c
#   2004/02/12 14:47:58+11:00 benh@kernel.crashing.org +755 -0
# 
# arch/ppc64/kernel/pmac_setup.c
#   2004/02/12 14:47:58+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/arch/ppc64/kernel/pmac_setup.c
# 
# arch/ppc64/kernel/pmac_pci.c
#   2004/02/12 14:47:58+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/arch/ppc64/kernel/pmac_pci.c
# 
# arch/ppc64/kernel/pmac_nvram.c
#   2004/02/12 14:47:57+11:00 benh@kernel.crashing.org +495 -0
# 
# arch/ppc64/kernel/pmac_nvram.c
#   2004/02/12 14:47:57+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/arch/ppc64/kernel/pmac_nvram.c
# 
# arch/ppc64/kernel/pmac_low_i2c.c
#   2004/02/12 14:47:56+11:00 benh@kernel.crashing.org +513 -0
# 
# arch/ppc64/kernel/pmac_low_i2c.c
#   2004/02/12 14:47:56+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/arch/ppc64/kernel/pmac_low_i2c.c
# 
# arch/ppc64/kernel/pmac_feature.c
#   2004/02/12 14:47:55+11:00 benh@kernel.crashing.org +654 -0
# 
# arch/ppc64/kernel/pmac_feature.c
#   2004/02/12 14:47:55+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/arch/ppc64/kernel/pmac_feature.c
# 
# arch/ppc64/kernel/pmac.h
#   2004/02/12 14:47:54+11:00 benh@kernel.crashing.org +32 -0
# 
# arch/ppc64/kernel/pci_dma_direct.c
#   2004/02/12 14:47:54+11:00 benh@kernel.crashing.org +88 -0
# 
# arch/ppc64/kernel/pmac.h
#   2004/02/12 14:47:54+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/arch/ppc64/kernel/pmac.h
# 
# arch/ppc64/kernel/pci_dma_direct.c
#   2004/02/12 14:47:54+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/arch/ppc64/kernel/pci_dma_direct.c
# 
# arch/ppc64/kernel/pSeries_nvram.c
#   2004/02/12 14:47:53+11:00 benh@kernel.crashing.org +150 -0
# 
# arch/ppc64/kernel/pSeries_nvram.c
#   2004/02/12 14:47:53+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/arch/ppc64/kernel/pSeries_nvram.c
# 
# arch/ppc64/kernel/open_pic_u3.c
#   2004/02/12 14:47:52+11:00 benh@kernel.crashing.org +348 -0
# 
# arch/ppc64/kernel/open_pic_u3.c
#   2004/02/12 14:47:52+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/arch/ppc64/kernel/open_pic_u3.c
# 
# arch/ppc64/kernel/of_device.c
#   2004/02/12 14:47:51+11:00 benh@kernel.crashing.org +272 -0
# 
# arch/ppc64/kernel/of_device.c
#   2004/02/12 14:47:51+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/arch/ppc64/kernel/of_device.c
# 
# arch/ppc64/kernel/idle_power4.S
#   2004/02/12 14:47:50+11:00 benh@kernel.crashing.org +79 -0
# 
# arch/ppc64/kernel/idle_power4.S
#   2004/02/12 14:47:50+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/arch/ppc64/kernel/idle_power4.S
# 
# arch/ppc64/kernel/cpu_setup_power4.S
#   2004/02/12 14:47:49+11:00 benh@kernel.crashing.org +179 -0
# 
# arch/ppc64/kernel/cpu_setup_power4.S
#   2004/02/12 14:47:49+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/arch/ppc64/kernel/cpu_setup_power4.S
# 
# arch/ppc64/kernel/btext.c
#   2004/02/12 14:47:48+11:00 benh@kernel.crashing.org +748 -0
# 
# arch/ppc64/kernel/btext.c
#   2004/02/12 14:47:48+11:00 benh@kernel.crashing.org +0 -0
#   BitKeeper file /home/benh/kernels/linux-2.5-merge/arch/ppc64/kernel/btext.c
# 
# ChangeSet
#   2004/02/12 14:45:05+11:00 benh@kernel.crashing.org 
#   ppc32: Add CONFIG_PPC_PMAC64 when building for G5
# 
# ChangeSet
#   2004/02/11 19:41:32-08:00 rusty@rustcorp.com.au 
#   [PATCH] Shut up about the damn modules already...
#   
#   In almost all distributions, the kernel asks for modules which don't
#   exist, such as "net-pf-10" or whatever.  Changing "modprobe -q" to
#   "succeed" in this case is hacky and breaks some setups, and also we
#   want to know if it failed for the fallback code for old aliases in
#   fs/char_dev.c, for example.
#   
#   Just remove the debugging message which fill people's logs: the
#   correct way of debugging module problems is something like this:
#   
#   	echo '#! /bin/sh' > /tmp/modprobe
#   	echo 'echo "$@" >> /tmp/modprobe.log' >> /tmp/modprobe
#   	echo 'exec /sbin/modprobe "$@"' >> /tmp/modprobe
#   	chmod a+x /tmp/modprobe
#   	echo /tmp/modprobe > /proc/sys/kernel/modprobe
# 
# kernel/kmod.c
#   2004/02/11 19:07:33-08:00 rusty@rustcorp.com.au +0 -10
#   Shut up about the damn modules already...
# 
# arch/ppc/Kconfig
#   2004/02/12 14:40:58+11:00 benh@kernel.crashing.org +5 -0
#   ppc32: Add CONFIG_PPC_PMAC64 when building for G5
# 
# ChangeSet
#   2004/02/11 22:28:16+01:00 wim@iguana.be 
#   [WATCHDOG] v2.6.2 arch-[m68k/sparc/sparc64]-Kconfig-patch
#   
#   Source WATCHDOG config info from drivers/char/watchdog/Kconfig
#   for m68k, sparc and sparc64 architectures
# 
# arch/sparc64/Kconfig
#   2004/02/11 22:27:17+01:00 wim@iguana.be +1 -14
#   Source WATCHDOG config info from drivers/char/watchdog/Kconfig
# 
# arch/sparc/Kconfig
#   2004/02/11 22:27:17+01:00 wim@iguana.be +1 -14
#   Source WATCHDOG config info from drivers/char/watchdog/Kconfig
# 
# arch/m68k/Kconfig
#   2004/02/11 22:27:17+01:00 wim@iguana.be +1 -44
#   Source WATCHDOG config info from drivers/char/watchdog/Kconfig
# 
# ChangeSet
#   2004/02/11 21:37:02+01:00 marcel@holtmann.org 
#   [Bluetooth] Fix non-blocking socket race conditions
#   
#   A poll on a non-blocking listen socket signals readable too early. The
#   first time the socket should be readable is if a child is in connected
#   state. And don't signal writeable if the socket is in config state.
#   
#   Noticed by Jean Tourrilhes <jt@hpl.hp.com>
# 
# net/bluetooth/af_bluetooth.c
#   2004/02/11 21:36:07+01:00 marcel@holtmann.org +22 -5
#   Fix non-blocking socket race conditions
# 
# ChangeSet
#   2004/02/11 21:35:42+01:00 marcel@holtmann.org 
#   [Bluetooth] Fix several copy_to_user() and reference counting glitches
#   
#   This patch corrects the error handling of copy_to_user() and adds more
#   error checks. It also fixes two reference counting bugs.
#   
#   Noticed by Andi Kleen <ak@suse.de>
# 
# net/bluetooth/rfcomm/tty.c
#   2004/02/11 21:35:07+01:00 marcel@holtmann.org +11 -8
#   Fix several copy_to_user() and reference counting glitches
# 
# net/bluetooth/hci_conn.c
#   2004/02/11 21:35:06+01:00 marcel@holtmann.org +16 -16
#   Fix several copy_to_user() and reference counting glitches
# 
# net/bluetooth/hci_core.c
#   2004/02/11 21:34:49+01:00 marcel@holtmann.org +7 -9
#   Fix several copy_to_user() and reference counting glitches
# 
# ChangeSet
#   2004/02/11 21:29:21+01:00 wim@iguana.be 
#   [WATCHDOG] v2.6.2 pcwd_pci-watchdog
#   
#   Add the Berkshire Products PCI-PC Watchdog driver
# 
# drivers/char/watchdog/pcwd_pci.c
#   2004/02/11 21:28:17+01:00 wim@iguana.be +681 -0
#   Add the Berkshire Products PCI-PC Watchdog driver
# 
# drivers/char/watchdog/pcwd_pci.c
#   2004/02/11 21:28:17+01:00 wim@iguana.be +0 -0
#   BitKeeper file /home/wim/BitKeeper/projects/linux-2.6-watchdog/drivers/char/watchdog/pcwd_pci.c
# 
# drivers/char/watchdog/Makefile
#   2004/02/11 21:28:17+01:00 wim@iguana.be +1 -0
#   Add the Berkshire Products PCI-PC Watchdog driver
# 
# drivers/char/watchdog/Kconfig
#   2004/02/11 21:28:17+01:00 wim@iguana.be +15 -0
#   Add the Berkshire Products PCI-PC Watchdog driver
# 
# ChangeSet
#   2004/02/11 21:24:04+01:00 wim@iguana.be 
#   [WATCHDOG] v2.6.2 indydog-Kconfig+Makefile-patch
#   
#   Apparently we ported the indydog code to the 2.5/2.6 kernel series,
#   but we forgot to put it in the kernel configuration file + the Makefile
# 
# drivers/char/watchdog/Makefile
#   2004/02/11 21:23:06+01:00 wim@iguana.be +1 -0
#   Apparently we ported the indydog code to the 2.5/2.6 kernel series,
#   but we forgot to put it in the kernel configuration file + the Makefile
# 
# drivers/char/watchdog/Kconfig
#   2004/02/11 21:23:06+01:00 wim@iguana.be +11 -0
#   Apparently we ported the indydog code to the 2.5/2.6 kernel series,
#   but we forgot to put it in the kernel configuration file + the Makefile
# 
# ChangeSet
#   2004/02/11 21:19:08+01:00 wim@iguana.be 
#   [WATCHDOG] v2.6.2 watchdog-Kconfig-patch
#   
#   Cleanup/Restructuring of drivers/char/watchdog/Kconfig
# 
# drivers/char/watchdog/Kconfig
#   2004/02/11 21:18:09+01:00 wim@iguana.be +215 -186
#   Cleanup/Restructuring of drivers/char/watchdog/Kconfig
# 
# ChangeSet
#   2004/02/11 21:14:18+01:00 wim@iguana.be 
#   [WATCHDOG] v2.6.2 i8xx_tco-v0.06_update
#   
#   Version 0.06 of the intel i8xx TCO driver:
#   * change i810_margin to heartbeat (in seconds)
#   * use module_param
#   * added notify system support
#   * renamed module to i8xx_tco
# 
# drivers/char/watchdog/i8xx_tco.h
#   2004/02/11 21:13:19+01:00 wim@iguana.be +3 -3
#   Version 0.06 of the intel i8xx TCO driver:
#   * change i810_margin to heartbeat (in seconds)
#   * use module_param
#   * added notify system support
#   * renamed module to i8xx_tco
# 
# drivers/char/watchdog/i8xx_tco.c
#   2004/02/11 21:13:19+01:00 wim@iguana.be +200 -127
#   Version 0.06 of the intel i8xx TCO driver:
#   * change i810_margin to heartbeat (in seconds)
#   * use module_param
#   * added notify system support
#   * renamed module to i8xx_tco
# 
# drivers/char/watchdog/Makefile
#   2004/02/11 21:13:18+01:00 wim@iguana.be +1 -1
#   Version 0.06 of the intel i8xx TCO driver:
#   * change i810_margin to heartbeat (in seconds)
#   * use module_param
#   * added notify system support
#   * renamed module to i8xx_tco
# 
# drivers/char/watchdog/Kconfig
#   2004/02/11 21:13:18+01:00 wim@iguana.be +9 -11
#   Version 0.06 of the intel i8xx TCO driver:
#   * change i810_margin to heartbeat (in seconds)
#   * use module_param
#   * added notify system support
#   * renamed module to i8xx_tco
# 
# drivers/char/watchdog/i8xx_tco.h
#   2004/02/11 21:07:40+01:00 wim@iguana.be +0 -0
#   Rename: drivers/char/watchdog/i810-tco.h -> drivers/char/watchdog/i8xx_tco.h
# 
# drivers/char/watchdog/i8xx_tco.c
#   2004/02/11 21:07:35+01:00 wim@iguana.be +0 -0
#   Rename: drivers/char/watchdog/i810-tco.c -> drivers/char/watchdog/i8xx_tco.c
# 
# ChangeSet
#   2004/02/11 21:01:53+01:00 wim@iguana.be 
#   [WATCHDOG] v2.6.2 indydog-v0.3_update
#   
#   Added notifier support
#   Moved start and stop code to their own subroutines
#   Extended ioctl support
#   Add MODULE_* info
# 
# drivers/char/watchdog/indydog.c
#   2004/02/11 21:00:54+01:00 wim@iguana.be +91 -20
#   Added notifier support
#   Moved start and stop code to their own subroutines
#   Extended ioctl support
#   Add MODULE_* info
# 
# ChangeSet
#   2004/02/11 20:54:48+01:00 wim@iguana.be 
#   [WATCHDOG] v2.6.2 acquirewdt-cleanup
#   
#   small cleanup
# 
# drivers/char/watchdog/acquirewdt.c
#   2004/02/11 20:53:50+01:00 wim@iguana.be +42 -17
#   small cleanup
# 
# ChangeSet
#   2004/02/11 20:45:49+01:00 wim@iguana.be 
#   [WATCHDOG] v2.6.2 watchdog-module_*-update
#   
#   Update MODULE_* information
# 
# drivers/char/watchdog/wafer5823wdt.c
#   2004/02/11 20:44:48+01:00 wim@iguana.be +1 -0
#   Update MODULE_* information
# 
# drivers/char/watchdog/softdog.c
#   2004/02/11 20:44:48+01:00 wim@iguana.be +5 -0
#   Update MODULE_* information
# 
# drivers/char/watchdog/scx200_wdt.c
#   2004/02/11 20:44:48+01:00 wim@iguana.be +1 -0
#   Update MODULE_* information
# 
# drivers/char/watchdog/sc520_wdt.c
#   2004/02/11 20:44:48+01:00 wim@iguana.be +1 -0
#   Update MODULE_* information
# 
# drivers/char/watchdog/sbc60xxwdt.c
#   2004/02/11 20:44:48+01:00 wim@iguana.be +1 -0
#   Update MODULE_* information
# 
# drivers/char/watchdog/amd7xx_tco.c
#   2004/02/11 20:44:48+01:00 wim@iguana.be +1 -1
#   Update MODULE_* information
# 
# drivers/char/watchdog/alim7101_wdt.c
#   2004/02/11 20:44:48+01:00 wim@iguana.be +1 -0
#   Update MODULE_* information
# 
# drivers/char/watchdog/alim1535_wdt.c
#   2004/02/11 20:44:47+01:00 wim@iguana.be +1 -0
#   Update MODULE_* information
# 
# drivers/char/watchdog/advantechwdt.c
#   2004/02/11 20:44:47+01:00 wim@iguana.be +1 -1
#   Update MODULE_* information
# 
# ChangeSet
#   2004/02/11 20:35:36+01:00 wim@iguana.be 
#   [WATCHDOG] v2.6.2 shwdt-cleanup
#   
#   Make heartbeat a module parameter and some general clean-up.
# 
# drivers/char/watchdog/shwdt.c
#   2004/02/11 20:34:35+01:00 wim@iguana.be +90 -41
#   Make heartbeat a module parameter and some general clean-up.
# 
# ChangeSet
#   2004/02/11 20:28:51+01:00 willy@debian.org 
#   [WATCHDOG] v2.6.2 watchdog-architecture-cleanup
#   
#   In order to make the watchdog menu useful for some architectures, we need
#   to only be able to select the watchdogs that can compile.  This patch also
#   moves the SuperH watchdog from its own Kconfig file to the normal one.
# 
# drivers/char/watchdog/Kconfig
#   2004/02/11 20:19:33+01:00 willy@debian.org +38 -21
#   In order to make the watchdog menu useful for some architectures, we need
#   to only be able to select the watchdogs that can compile.  This patch also
#   moves the SuperH watchdog from its own Kconfig file to the normal one.
# 
# arch/sh/Kconfig
#   2004/02/11 20:19:33+01:00 willy@debian.org +1 -55
#   In order to make the watchdog menu useful for some architectures, we need
#   to only be able to select the watchdogs that can compile.  This patch also
#   moves the SuperH watchdog from its own Kconfig file to the normal one.
# 
# ChangeSet
#   2004/02/11 07:58:16-08:00 torvalds@home.osdl.org 
#   This reverts the mmap address hint usage for now.
#   
#   It broke some existing setups, so let's drop it until we have
#   a better notion of how to do this.
# 
# mm/mmap.c
#   2004/02/11 07:58:12-08:00 torvalds@home.osdl.org +2 -3
#   This reverts the mmap address hint usage for now.
#   
#   It broke some existing setups, so let's drop it until we have
#   a better notion of how to do this.
# 
# arch/x86_64/kernel/sys_x86_64.c
#   2004/02/11 07:58:12-08:00 torvalds@home.osdl.org +2 -2
#   This reverts the mmap address hint usage for now.
#   
#   It broke some existing setups, so let's drop it until we have
#   a better notion of how to do this.
# 
# ChangeSet
#   2004/02/11 07:54:06-08:00 mingo@elte.hu 
#   [PATCH] open writecount scalability cleanup
#   
#   This is an obvious scalability improvement for write()s.  We used a
#   global lock to protect the inode writecount (updated on every open for
#   writing) - this just makes it use the existing inode->i_lock instead.
#   
#   Compiles & boots fine on x86 SMP.
# 
# fs/namei.c
#   2004/02/10 16:00:00-08:00 mingo@elte.hu +15 -11
#   open writecount scalability cleanup
# 
# ChangeSet
#   2004/02/11 15:09:40+00:00 davej@redhat.com 
#   [CPUFREQ] Remove bogus scaling from longhaul driver freqency tables.
#   This is nonsense. We only use the lower 8 bits, so putting the useful
#   info in the upper 8 makes no sense at all.
# 
# arch/i386/kernel/cpu/cpufreq/longhaul.c
#   2004/02/11 15:09:34+00:00 davej@redhat.com +1 -1
#   [CPUFREQ] Remove bogus scaling from longhaul driver freqency tables.
#   This is nonsense. We only use the lower 8 bits, so putting the useful
#   info in the upper 8 makes no sense at all.
# 
# ChangeSet
#   2004/02/11 12:01:13+00:00 davej@redhat.com 
#   [CPUFREQ] Fix off-by-1000 error in longhaul.
#   Cpufreq core expects units in khz not mhz. Oops.
# 
# arch/i386/kernel/cpu/cpufreq/longhaul.c
#   2004/02/11 12:01:08+00:00 davej@redhat.com +6 -5
#   [CPUFREQ] Fix off-by-1000 error in longhaul.
#   Cpufreq core expects units in khz not mhz. Oops.
# 
# ChangeSet
#   2004/02/10 21:38:40-08:00 davem@nuts.davemloft.net 
#   [SPARC64]: Fix exception remaining length calcs in VIS copy routines.
# 
# arch/sparc64/lib/VIScopy.S
#   2004/02/10 21:34:37-08:00 davem@nuts.davemloft.net +11 -14
#   [SPARC64]: Fix exception remaining length calcs in VIS copy routines.
# 
# ChangeSet
#   2004/02/10 21:13:54-08:00 davidm@tiger.hpl.hp.com 
#   ia64: Correct init_task.rbs_bot value (not that it matters).
# 
# include/asm-ia64/processor.h
#   2004/02/10 21:13:48-08:00 davidm@tiger.hpl.hp.com +13 -13
#   (INIT_THREAD): Correct initial value of .rbs_bot member (not that it matters).
# 
# ChangeSet
#   2004/02/10 21:08:10-08:00 davidm@tiger.hpl.hp.com 
#   ia64: Update defconfig
# 
# arch/ia64/defconfig
#   2004/02/10 21:08:04-08:00 davidm@tiger.hpl.hp.com +29 -31
#   Update
# 
# ChangeSet
#   2004/02/10 18:59:35-08:00 davidm@tiger.hpl.hp.com 
#   ia64: Fix some more warnings caused by casts used as l-values.
# 
# include/asm-ia64/percpu.h
#   2004/02/10 18:59:28-08:00 davidm@tiger.hpl.hp.com +1 -1
#   (per_cpu): Define the UP-version also in a manner such that it can be
#   	used as an l-value without solicitying a warning from GCC v3.4.
# 
# arch/ia64/lib/io.c
#   2004/02/10 18:59:28-08:00 davidm@tiger.hpl.hp.com +8 -8
#   (__ia64_memcpy_fromio): Get rid of ugly casts used as l-values (gcc 3.4
#   	warns about them).
#   (__ia64_memcpy_toio): Likewise.
# 
# ChangeSet
#   2004/02/10 18:51:34-08:00 davidm@tiger.hpl.hp.com 
#   ia64: Based on patch by Stephane Eranian: Make fpswa version info available
#   	via /proc/efi/fpswa, rather than printing it at boot time.
# 
# include/asm-ia64/fpswa.h
#   2004/02/10 18:51:27-08:00 davidm@tiger.hpl.hp.com +2 -0
#   (fpswa_interface): Declare.
#   
# 
# arch/ia64/kernel/traps.c
#   2004/02/10 18:51:27-08:00 davidm@tiger.hpl.hp.com +2 -9
#   (fpswa_interface): Make it global.
#   (trap_init): Don't print version info at boot-time.
# 
# arch/ia64/kernel/efivars.c
#   2004/02/10 18:51:27-08:00 davidm@tiger.hpl.hp.com +42 -1
#   (efi_fpswa_read): New function.
#   (efivars_init): If fpswa_interface is non-NULL, register "fpswa" entry
#   	under /proc/efi.
# 
# ChangeSet
#   2004/02/11 12:17:29+11:00 hch@sgi.com 
#   [XFS] make sure i_size_write is called under i_sem
#   
#   SGI Modid: xfs-linux:xfs-kern:166504a
# 
# fs/xfs/linux/xfs_vnode.c
#   2004/02/11 12:12:33+11:00 hch@sgi.com +0 -1
#   [XFS] make sure i_size_write is called under i_sem
# 
# fs/xfs/linux/xfs_iops.c
#   2004/02/11 12:12:33+11:00 hch@sgi.com +9 -3
#   [XFS] make sure i_size_write is called under i_sem
# 
# ChangeSet
#   2004/02/10 15:37:14-08:00 kaos@ocs.com.au 
#   [PATCH] ia64: Periodically forward MCA or INIT records to user-level
#   
#   Periodically check for outstanding MCA or INIT records and pass them to
#   user space salinfo.
# 
# arch/ia64/kernel/salinfo.c
#   2004/02/09 21:24:46-08:00 kaos@ocs.com.au +40 -0
#   ia64: Periodically forward outstanding MCA or INIT records to user-level
# 
# ChangeSet
#   2004/02/10 15:32:28-08:00 kaos@ocs.com.au 
#   [PATCH] ia64: mca.c - Fix the "did we recover from MCA test" and move it up
#   
#   Correct the "did we recover from MCA test" and move it up a level to
#   simplify interaction with debuggers.
# 
# arch/ia64/kernel/mca.c
#   2004/02/09 21:15:07-08:00 kaos@ocs.com.au +9 -12
#   ia64: mca.c - Correct the "did we recover from MCA test" and move it up a level
# 
# ChangeSet
#   2004/02/10 15:20:28-08:00 kenneth.w.chen@intel.com 
#   [PATCH] ia64: remove unused cpucount variable
#   
# 
# arch/ia64/kernel/smpboot.c
#   2004/02/05 16:00:00-08:00 kenneth.w.chen@intel.com +0 -1
#   ia64: remove unused cpucount variable
# 
# ChangeSet
#   2004/02/10 15:17:40-08:00 jun.nakajima@intel.com 
#   [PATCH] Remove the assumption that the number of the sibling is 2
#   
#   Thanks to Nick's domain patch, the kernel worked fine with
#   smp_num_siblings = 4 (in simulation).
# 
# arch/i386/kernel/cpu/intel.c
#   2004/02/10 15:00:54-08:00 jun.nakajima@intel.com +2 -6
#   Remove the assumption that the number of the sibling is 2
# 
# ChangeSet
#   2004/02/10 14:54:01-08:00 kaos@sgi.com 
#   [PATCH] ia64: mca.c - pass irq_safe around
#   
#   Patches from Ben Woodward to calculate irq_safe once and pass it around.
# 
# arch/ia64/kernel/salinfo.c
#   2004/02/05 22:29:43-08:00 kaos@sgi.com +2 -2
#   ia64: mca.c - pass irq_safe around
# 
# arch/ia64/kernel/mca.c
#   2004/02/05 22:29:43-08:00 kaos@sgi.com +5 -5
#   ia64: mca.c - pass irq_safe around
# 
# ChangeSet
#   2004/02/10 14:14:47-08:00 kaos@sgi.com 
#   [PATCH] ia64: mca.c cleanup - Bjorn's printk cleanup
#   
# 
# include/asm-ia64/mca.h
#   2004/02/04 18:12:39-08:00 kaos@sgi.com +0 -5
#   ia64: mca.c cleanup - Bjorn's printk cleanup
# 
# arch/ia64/kernel/mca.c
#   2004/02/04 18:12:39-08:00 kaos@sgi.com +42 -36
#   ia64: mca.c cleanup - Bjorn's printk cleanup
# 
# ChangeSet
#   2004/02/10 14:14:04-08:00 kaos@sgi.com 
#   [PATCH] ia64: mca.c cleanup - Reorder to remove the need for forward declarations and to consolidate related code
#   
# 
# arch/ia64/kernel/mca.c
#   2004/02/04 17:56:08-08:00 kaos@sgi.com +334 -346
#   ia64: mca.c cleanup - Reorder to remove the need for forward declarations and to consolidate related code
# 
# ChangeSet
#   2004/02/10 14:13:21-08:00 kaos@sgi.com 
#   [PATCH] ia64: mca.c cleanup - Delete dead variables and functions
#   
# 
# include/asm-ia64/mca.h
#   2004/02/04 17:01:04-08:00 kaos@sgi.com +0 -33
#   ia64: mca.c cleanup - Delete dead variables and functions
# 
# arch/ia64/kernel/mca.c
#   2004/02/04 17:01:04-08:00 kaos@sgi.com +15 -45
#   ia64: mca.c cleanup - Delete dead variables and functions
# 
# ChangeSet
#   2004/02/10 14:12:30-08:00 kaos@sgi.com 
#   [PATCH] ia64: mca.c cleanup - Mark variables and functions static where possible
#   
# 
# include/asm-ia64/mca.h
#   2004/02/04 16:53:36-08:00 kaos@sgi.com +1 -7
#   ia64: mca.c cleanup - Mark variables and functions static where possible
# 
# arch/ia64/kernel/mca.c
#   2004/02/04 16:53:36-08:00 kaos@sgi.com +24 -17
#   ia64: mca.c cleanup - Mark variables and functions static where possible
# 
# ChangeSet
#   2004/02/10 14:11:58-08:00 kaos@sgi.com 
#   [PATCH] ia64: mca.c cleanup - Delete all record printing code, moved to salinfo_decode in user space
#   
# 
# include/asm-ia64/mca.h
#   2004/02/04 16:48:21-08:00 kaos@sgi.com +0 -12
#   ia64: mca.c cleanup - Delete all record printing code, moved to salinfo_decode in user space
# 
# arch/ia64/sn/kernel/mca.c
#   2004/02/04 16:48:21-08:00 kaos@sgi.com +0 -14
#   ia64: mca.c cleanup - Delete all record printing code, moved to salinfo_decode in user space
# 
# arch/ia64/kernel/mca.c
#   2004/02/04 16:48:21-08:00 kaos@sgi.com +2 -1063
#   ia64: mca.c cleanup - Delete all record printing code, moved to salinfo_decode in user space
# 
# ChangeSet
#   2004/02/10 14:11:17-08:00 kaos@sgi.com 
#   [PATCH] ia64: Avoid deadlock when using printk() for MCA and INIT records
#   
#   Port the ia64 mca.c clean up patches from 2.4.25-pre8 to 2.6.2-rc2.
#   
#   The following 6 patches do :-
#   
#   1 Avoid deadlock when using printk() for MCA and INIT records.
#   2 Delete all record printing code, moved to salinfo_decode in user space.
#   3 Mark variables and functions static where possible.
#   4 Delete dead variables and functions.
#   5 Reorder to remove the need for forward declarations and to consolidate
#     related code.
#   6 Bjorn's printk cleanup.
#   
#   Altogether they shrink mca.c from 2432 to 1339 lines and make it much
#   more readable.
#   
#   The only functional change is the removal of any attempt to print the
#   CMC/CPE/MCA/INIT record contents in the kernel plus the addition of an
#   info printk to ia64_mca_check_errors(), to match 2.4.  Now we just get
#   one line to say that a record has been detected, except for MCA which
#   prints nothing at all.
# 
# arch/ia64/kernel/mca.c
#   2004/02/04 16:41:17-08:00 kaos@sgi.com +25 -28
#   ia64: Avoid deadlock when using printk() for MCA and INIT records
# 
# ChangeSet
#   2004/02/10 13:45:36-08:00 alex.williamson@hp.com 
#   [PATCH] ia64: sba_iommu perf tunning and new functionality
#   
#      I've been doing some performance tuning and adding some functionality
#   to sba_iommu for zx1/sx1000 chipsets.  This adds:
#   
#         * Long overdue consistent_dma_mask support
#         * Long overdue ability to do large mappings in the iommu
#         * Tightened spinlock usage for better performance/scalability
#         * Added branch prediction hints for some of the performance paths
#         * Added explicit data prefetching to some performance paths -
#           perfmon shows roughly a 20% decrease in L3 misses in the bitmap
#           search code
#         * Increased delayed resource freeing depth and added a separate
#           lock per ioc to avoid contention
#         * Added code to free up queued pdir entries should we be unable to
#           find space for new ones (not that I've ever seen the pdir
#           anywhere close to full)
#         * Finished cleaning out the hint support code, Grant is
#           maintaining this separately for now
#         * Added option to control bypass of sg mappings separately from
#           single/coherent mappings
#   
#   Much like the swiotlb, sba_iommu allows devices capable of 64bit
#   addressing to bypass the iommu and DMA directly to/from memory.  Using a
#   worst case scenario test (64bit bypass disabled, all DMA mapped through
#   the iommu), I saw a 60% increase in sequential block input throughput
#   using bonnie++ on a large RAID0 MD array.  In fact, this patch provides
#   the best bonnie++ performance with bypass disabled.  This is likely due
#   to benefits seen from coalescing the scatterlist, allowing better disk
#   streaming.  I assume that network performance will likely be limited by
#   mapping latency, so I added the last bullet item to allow sg mappings to
#   get the benefit of coalescing while keeping a low latency path for
#   single and coherent mappings.  If anyone is setup for network
#   benchmarks, I'd be interested in a before and after with this patch.
# 
# arch/ia64/hp/common/sba_iommu.c
#   2004/02/02 07:58:46-08:00 alex.williamson@hp.com +231 -114
#   ia64: sba_iommu perf tunning and new functionality
# 
# ChangeSet
#   2004/02/10 15:32:27-06:00 shaggy@kleikamp.dyn.webahead.ibm.com 
#   JFS: Threads should exit with complete_and_exit
# 
# fs/jfs/jfs_txnmgr.c
#   2004/02/10 15:32:21-06:00 shaggy@kleikamp.dyn.webahead.ibm.com +2 -4
#   Use complete_and_exit to avoid race
# 
# fs/jfs/jfs_logmgr.c
#   2004/02/10 15:32:21-06:00 shaggy@kleikamp.dyn.webahead.ibm.com +1 -2
#   Use complete_and_exit to avoid race
# 
# ChangeSet
#   2004/02/10 12:55:53-08:00 kenneth.w.chen@intel.com 
#   [PATCH] ia64: fix ld.a emulation
#   
#   This patch fixes a corner-case of ld.a emulation.  ld.a should be
#   emulated such that it always loads a misaligned value and clears the
#   corresponding ALAT entry.  The old emulation was correct for the case
#   where ld.a was followed by ld.c/chk.a (since ALAT entry was cleared),
#   but wrong for the case where it _wasn't_ followed by ld.c/chk.a.  In
#   that case, the misaligned value wasn't read from memory, as it should
#   have been.
# 
# arch/ia64/kernel/unaligned.c
#   2004/02/05 13:31:57-08:00 kenneth.w.chen@intel.com +17 -27
#   ia64: fix ld.a emulation
# 
# ChangeSet
#   2004/02/10 12:16:10-08:00 steiner@sgi.com 
#   [PATCH] ia64: Enable cpu_vm_mask maintenance and improve SN2 TLB flushing
# 
# include/asm-ia64/mmu_context.h
#   2004/02/01 04:38:13-08:00 steiner@sgi.com +3 -0
#   ia64: Improve SN2 TLB flushing algorithm
# 
# arch/ia64/sn/kernel/sn2/sn2_smp.c
#   2004/02/02 00:09:31-08:00 steiner@sgi.com +52 -8
#   ia64: Improve SN2 TLB flushing algorithm
# 
# ChangeSet
#   2004/02/10 11:19:39-08:00 torvalds@home.osdl.org 
#   Fix bogus mode bit testing by smbfs.
#   
#   The S_IFxxxx macros aren't bits to be tested, they
#   are values of the S_IFMT field.
# 
# fs/smbfs/proc.c
#   2004/02/10 11:19:34-08:00 torvalds@home.osdl.org +7 -7
#   Fix bogus mode bit testing by smbfs.
#   
#   The S_IFxxxx macros aren't bits to be tested, they
#   are values of the S_IFMT field.
# 
# ChangeSet
#   2004/02/10 18:03:26+00:00 davej@redhat.com 
#   [CPUFREQ] Fix deadlock in userspace governor.
#   Another fix from Dominik.
# 
# drivers/cpufreq/cpufreq_userspace.c
#   2004/02/10 18:03:20+00:00 davej@redhat.com +9 -2
#   [CPUFREQ] Fix deadlock in userspace governor.
#   Another fix from Dominik.
# 
# ChangeSet
#   2004/02/10 17:57:45+00:00 davej@redhat.com 
#   [CPUFREQ] Pentium-4-M detection fix for speedstep-lib
#   From Dominik..
#   The different P-4-M steppings have different "ebx" values. Analyze it
#   correctly to sort out Pentium-4-based Celerons.
# 
# arch/i386/kernel/cpu/cpufreq/speedstep-lib.c
#   2004/02/10 17:57:40+00:00 davej@redhat.com +46 -8
#   [CPUFREQ] Pentium-4-M detection fix for speedstep-lib
#   From Dominik..
#   The different P-4-M steppings have different "ebx" values. Analyze it
#   correctly to sort out Pentium-4-based Celerons.
# 
# ChangeSet
#   2004/02/10 17:54:34+00:00 davej@redhat.com 
#   [CPUFREQ] powernow-k8 printk cleanups from Pavel.
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k8.c
#   2004/02/10 17:54:29+00:00 davej@redhat.com +38 -50
#   [CPUFREQ] powernow-k8 printk cleanups from Pavel.
# 
# ChangeSet
#   2004/02/10 17:45:49+00:00 davej@redhat.com 
#   [CPUFREQ] convert powernow-k8 to use frequency tables [5/5]
#   Move the table verification to an extra function.
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k8.c
#   2004/02/10 17:45:44+00:00 davej@redhat.com +44 -38
#   [CPUFREQ] convert powernow-k8 to use frequency tables [5/5]
#   Move the table verification to an extra function.
# 
# ChangeSet
#   2004/02/10 17:44:31+00:00 davej@redhat.com 
#   [CPUFREQ] convert powernow-k8 to use frequency tables [4/5]
#   Remove the *ppst table, and remove an unneccessary forward-declaration
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k8.h
#   2004/02/10 17:44:26+00:00 davej@redhat.com +0 -4
#   [CPUFREQ] convert powernow-k8 to use frequency tables [4/5]
#   Remove the *ppst table, and remove an unneccessary forward-declaration
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k8.c
#   2004/02/10 17:44:26+00:00 davej@redhat.com +63 -105
#   [CPUFREQ] convert powernow-k8 to use frequency tables [4/5]
#   Remove the *ppst table, and remove an unneccessary forward-declaration
# 
# ChangeSet
#   2004/02/10 17:43:28+00:00 davej@redhat.com 
#   [CPUFREQ] convert powernow-k8 to use frequency tables [3/5]
#   Keep *ppst local to the only function which needs it any longer.
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k8.c
#   2004/02/10 17:43:22+00:00 davej@redhat.com +5 -7
#   [CPUFREQ] convert powernow-k8 to use frequency tables [3/5]
#   Keep *ppst local to the only function which needs it any longer.
# 
# ChangeSet
#   2004/02/10 17:42:30+00:00 davej@redhat.com 
#   [CPUFREQ] convert powernow-k8 to use frequency tables [2/5]
#   
#   Use the frequency_table for calculating the correct ->target state
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k8.c
#   2004/02/10 17:42:25+00:00 davej@redhat.com +13 -116
#   [CPUFREQ] convert powernow-k8 to use frequency tables [2/5]
#   
#   Use the frequency_table for calculating the correct ->target state
# 
# ChangeSet
#   2004/02/10 17:41:20+00:00 davej@redhat.com 
#   [CPUFREQ] convert powernow-k8 to use frequency tables [1/5]
#   Add a struct cpufreq_frequency_table, fill it with content, and use it for
#   ->verify.
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k8.c
#   2004/02/10 17:41:15+00:00 davej@redhat.com +27 -29
#   [CPUFREQ] convert powernow-k8 to use frequency tables [1/5]
#   Add a struct cpufreq_frequency_table, fill it with content, and use it for
#   ->verify.
# 
# ChangeSet
#   2004/02/10 09:38:45-08:00 jsimmons@infradead.org 
#   [PATCH] framebuffer GPM corruption fix.
#   
#   This patch fixes the GPM cursor corruption people where seeing.
# 
# drivers/video/console/fbcon.c
#   2004/02/09 16:41:17-08:00 jsimmons@infradead.org +8 -4
#   framebuffer GPM corruption fix.
# 
# ChangeSet
#   2004/02/10 09:24:56-08:00 thornber@redhat.com 
#   [PATCH] dm: block size bug with 64 bit devs
#   
#   With 32 bit sector_t the block device size _in bytes_ is also cut to
#   32 bit in __set_size when the block device is mount (a filesystem
#   mounted). The argument should be cast to loff_t before expanding the
#   sector count to a byte count and calling i_size_write.
#   
#   [Christophe Saout]
# 
# drivers/md/dm.c
#   2004/02/10 08:11:50-08:00 thornber@redhat.com +1 -1
#   dm: block size bug with 64 bit devs
# 
# ChangeSet
#   2004/02/10 17:17:19+00:00 davej@redhat.com 
#   [CPUFREQ] Fix an oops unloading p4-clockmod.
#   Reverting frequency changes on unloading is uncommon for cpufreq drivers
#   so let's remove this speciality.
# 
# arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
#   2004/02/10 17:17:14+00:00 davej@redhat.com +1 -1
#   [CPUFREQ] Fix an oops unloading p4-clockmod.
#   Reverting frequency changes on unloading is uncommon for cpufreq drivers
#   so let's remove this speciality.
# 
# ChangeSet
#   2004/02/10 09:10:33-08:00 torvalds@home.osdl.org 
#   Make <linux/compiler.h> a bit more palatable to
#   user program inclusion.
#   
#   It's still wrong to include kernel headers from
#   user programs. Oh, well.
# 
# include/linux/compiler.h
#   2004/02/10 09:10:28-08:00 torvalds@home.osdl.org +4 -0
#   Make <linux/compiler.h> a bit more palatable to
#   user program inclusion.
#   
#   It's still wrong to include kernel headers from
#   user programs. Oh, well.
# 
# ChangeSet
#   2004/02/10 09:00:29-08:00 B.Zolnierkiewicz@elka.pw.edu.pl 
#   [PATCH] fix build for CONFIG_BLK_DEV_IDEDMA=n
#   
#   Ths "fix duplication of DMA {black,white}list in icside.c" patch broke it.
#   
#   Noticed by Geert Uytterhoeven <geert@linux-m68k.org>.
# 
# include/linux/ide.h
#   2004/02/10 07:35:39-08:00 B.Zolnierkiewicz@elka.pw.edu.pl +3 -3
#   fix build for CONFIG_BLK_DEV_IDEDMA=n
# 
# ChangeSet
#   2004/02/10 16:54:06+00:00 davej@redhat.com 
#   [CPUFREQ] Geode register fixes.
#   
#   From: Hiroshi Miura <miura at da-cha.org>
#                                                                                                           
#   I mistook a Geode chipset's register meanings. (-.-;
#   ON is not 'CPU is ON' but 'cpu modulation is ON' that is stops cpu.
#                                                                                                                  
#   this causes a bad freq setting.
#                                                                                                                  
#   This patch fixes this and minor bug that is,
#                                                                                                                  
#           if (new_khz == stock_freq) {  /* if new khz == 100% of CPU speed, it is special case */
#                   local_irq_save(flags);
#                   cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
#                                                                                                                  
#   cpufreq_notify_transition() called after local_irq_save();
#   this makes not update cpu_khz.
# 
# arch/i386/kernel/cpu/cpufreq/gx-suspmod.c
#   2004/02/10 16:54:00+00:00 davej@redhat.com +43 -44
#   [CPUFREQ] Geode register fixes.
#   
#   From: Hiroshi Miura <miura at da-cha.org>
#                                                                                                           
#   I mistook a Geode chipset's register meanings. (-.-;
#   ON is not 'CPU is ON' but 'cpu modulation is ON' that is stops cpu.
#                                                                                                                  
#   this causes a bad freq setting.
#                                                                                                                  
#   This patch fixes this and minor bug that is,
#                                                                                                                  
#           if (new_khz == stock_freq) {  /* if new khz == 100% of CPU speed, it is special case */
#                   local_irq_save(flags);
#                   cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
#                                                                                                                  
#   cpufreq_notify_transition() called after local_irq_save();
#   this makes not update cpu_khz.
# 
# ChangeSet
#   2004/02/10 08:45:59-08:00 axboe@suse.de 
#   [PATCH] DVD-R capability flag set incorrectly, /proc formatting fix
#   
#   From John McKell <mckellj@iomega.com>:
#   
#     This patch for scsi/sr.c and cdrom/cdrom.c persuades
#     /proc/sys/dev/cdrom/info to report that connecting a drive via USB
#     rather than ATAPI in fact does not make it able to write DVD-R.
#   
#     Without this patch, when sr0 and hdd are the same type of device
#     connected via USB and ATAPI respectively, I see:
#   
#   	$ cat /proc/sys/dev/cdrom/info:
#   	drive name:             sr1     sr0     hdd
#   	...
#   	Can write CD-R:         1       0       0
#   	Can write CD-RW:        1       0       0
#   	Can read DVD:           0       0       0
#   	Can write DVD-R:        1       1       0
#   	Can write DVD-RAM:      0       0       0
#   	Can read MRW:           0               0               0
#   	Can write MRW:          0               0               0
#   
#     With this patch applied, instead I see:
#   
#   	$ cat /proc/sys/dev/cdrom/info:
#   	drive name:             sr1     sr0     hdd
#   	...
#   	Can write CD-R:         1       0       0
#   	Can write CD-RW:        1       0       0
#   	Can read DVD:           0       0       0
#   	Can write DVD-R:        0       0       0
#   	Can write DVD-RAM:      0       0       0
#   	Can read MRW:           0       0       0
#   	Can write MRW:          0       0       0
#   
#     The sr1 device in particular is an ordinary CD-RW that in fact cannot
#     write DVD-R.
#   
#     While messing with this code, I also thought to tweak the /proc
#     formatting to align the tabbed columns.
# 
# drivers/scsi/sr.c
#   2004/02/09 12:59:10-08:00 axboe@suse.de +1 -2
#   DVD-R capability flag set incorrectly, /proc formatting fix
# 
# drivers/cdrom/cdrom.c
#   2004/02/09 12:58:21-08:00 axboe@suse.de +4 -4
#   DVD-R capability flag set incorrectly, /proc formatting fix
# 
# ChangeSet
#   2004/02/10 08:11:44-08:00 benh@kernel.crashing.org 
#   [PATCH] Export OF device path for PCI devices
#   
#   Here's a new version of the patch according to our discussion.
#   
#   This allows the platform to add its own platform files to the
#   sysfs PCI device node through a "pcibios_add_platform_entries()"
#   call.
#   
#   I added an empty pcibios_add_platform_entries() inline to all
#   archs that apparently have PCI and implemented the OF stuff for
#   ppc and ppc64. The name is still "devspec" for now, I doubt
#   it will conflict and that's consistent with our use of the
#   "devspec" name in other places.
# 
# include/asm-x86_64/pci.h
#   2004/02/09 21:07:57-08:00 benh@kernel.crashing.org +4 -0
#   Export OF device path for PCI devices
# 
# include/asm-v850/pci.h
#   2004/02/09 21:07:45-08:00 benh@kernel.crashing.org +4 -0
#   Export OF device path for PCI devices
# 
# include/asm-sparc64/pci.h
#   2004/02/09 21:07:02-08:00 benh@kernel.crashing.org +4 -0
#   Export OF device path for PCI devices
# 
# include/asm-sparc/pci.h
#   2004/02/09 21:05:18-08:00 benh@kernel.crashing.org +4 -0
#   Export OF device path for PCI devices
# 
# include/asm-sh/pci.h
#   2004/02/09 21:05:05-08:00 benh@kernel.crashing.org +4 -0
#   Export OF device path for PCI devices
# 
# include/asm-ppc64/pci.h
#   2004/02/09 21:04:41-08:00 benh@kernel.crashing.org +2 -0
#   Export OF device path for PCI devices
# 
# include/asm-ppc/pci.h
#   2004/02/09 21:04:02-08:00 benh@kernel.crashing.org +2 -0
#   Export OF device path for PCI devices
# 
# include/asm-parisc/pci.h
#   2004/02/09 21:03:35-08:00 benh@kernel.crashing.org +4 -0
#   Export OF device path for PCI devices
# 
# include/asm-mips/pci.h
#   2004/02/09 21:03:19-08:00 benh@kernel.crashing.org +4 -0
#   Export OF device path for PCI devices
# 
# include/asm-m68knommu/pci.h
#   2004/02/09 21:01:42-08:00 benh@kernel.crashing.org +4 -0
#   Export OF device path for PCI devices
# 
# include/asm-m68k/pci.h
#   2004/02/09 21:01:20-08:00 benh@kernel.crashing.org +4 -0
#   Export OF device path for PCI devices
# 
# include/asm-ia64/pci.h
#   2004/02/09 21:01:02-08:00 benh@kernel.crashing.org +4 -0
#   Export OF device path for PCI devices
# 
# include/asm-i386/pci.h
#   2004/02/09 20:58:40-08:00 benh@kernel.crashing.org +5 -0
#   Export OF device path for PCI devices
# 
# include/asm-h8300/pci.h
#   2004/02/09 21:00:24-08:00 benh@kernel.crashing.org +4 -0
#   Export OF device path for PCI devices
# 
# include/asm-arm/pci.h
#   2004/02/09 20:59:21-08:00 benh@kernel.crashing.org +4 -0
#   Export OF device path for PCI devices
# 
# include/asm-alpha/pci.h
#   2004/02/09 20:58:44-08:00 benh@kernel.crashing.org +4 -0
#   Export OF device path for PCI devices
# 
# drivers/pci/pci-sysfs.c
#   2004/02/09 20:55:42-08:00 benh@kernel.crashing.org +3 -0
#   Export OF device path for PCI devices
# 
# arch/ppc64/kernel/pci.c
#   2004/02/09 22:21:01-08:00 benh@kernel.crashing.org +22 -0
#   Export OF device path for PCI devices
# 
# arch/ppc/kernel/pci.c
#   2004/02/09 22:20:41-08:00 benh@kernel.crashing.org +23 -0
#   Export OF device path for PCI devices
# 
# ChangeSet
#   2004/02/09 11:03:07-06:00 shaggy@kleikamp.dyn.webahead.ibm.com 
#   JFS: rename should update mtime on source and target directories
# 
# fs/jfs/namei.c
#   2004/02/09 11:03:01-06:00 shaggy@kleikamp.dyn.webahead.ibm.com +2 -2
#   rename should update i_mtime on affected directories
# 
# ChangeSet
#   2004/02/07 00:20:48+01:00 marcel@holtmann.org 
#   [Bluetooth] Fix error handling for not connected socket
#   
#   This patch adds the missing fput() call for the BNEP and CMTP protocol
#   layers in case the user submits a not connected socket.
#   
#   Noticed by Andi Kleen <ak@suse.de>
# 
# net/bluetooth/cmtp/sock.c
#   2004/02/07 00:18:03+01:00 marcel@holtmann.org +3 -1
#   Fix error handling for not connected socket
# 
# net/bluetooth/bnep/sock.c
#   2004/02/07 00:17:24+01:00 marcel@holtmann.org +3 -1
#   Fix error handling for not connected socket
# 
# ChangeSet
#   2004/02/05 14:14:04+01:00 marcel@holtmann.org 
#   [Bluetooth] Fix race for incoming connections
#   
#   This patch fixes a racing condition in accepting incoming RFCOMM
#   connections. If a SABM command frame occurs in data packet right
#   after L2CAP configuration request packet and there is no active
#   session yet then the kernel RFCOMM thread wakes up only once and
#   creates a new session. But it does not process SABM frame from
#   second data packet waiting in the queue. Connection setup hangs
#   and the other side is waiting for UA frame response, but the
#   kernel thread keeps sleeping. A possible solution is to force
#   additional thread wakeup right after successful creation of the
#   new session.
#   
#   Patch from Dmitri Khokhlov <dkhokhlov@hotmail.com>
# 
# net/bluetooth/rfcomm/core.c
#   2004/02/05 14:12:42+01:00 marcel@holtmann.org +3 -2
#   Fix race for incoming connections
# 
# ChangeSet
#   2004/02/05 13:11:48+01:00 marcel@holtmann.org 
#   [Bluetooth] Support for tracking the voice setting
#   
#   This patch makes sure that the Bluetooth core layer always knows the
#   current voice setting. It will be read on device initialization and
#   then stored in the hci_dev structure.
# 
# net/bluetooth/hci_event.c
#   2004/02/05 13:07:38+01:00 marcel@holtmann.org +37 -1
#   Support for tracking the voice setting
# 
# net/bluetooth/hci_core.c
#   2004/02/05 13:07:36+01:00 marcel@holtmann.org +3 -0
#   Support for tracking the voice setting
# 
# include/net/bluetooth/hci_core.h
#   2004/02/05 13:07:34+01:00 marcel@holtmann.org +4 -3
#   Support for tracking the voice setting
# 
# include/net/bluetooth/hci.h
#   2004/02/05 13:06:23+01:00 marcel@holtmann.org +11 -0
#   Support for tracking the voice setting
# 
# ChangeSet
#   2004/02/03 18:55:16+00:00 davej@delerium.codemonkey.org.uk 
#   Merge delerium.codemonkey.org.uk:/mnt/nfs/sepia/bar/src/kernel/2.6/trees/bk-linus
#   into delerium.codemonkey.org.uk:/mnt/nfs/sepia/bar/src/kernel/2.6/trees/cpufreq
# 
# arch/i386/kernel/cpu/cpufreq/speedstep-lib.h
#   2004/02/03 18:55:04+00:00 davej@delerium.codemonkey.org.uk +0 -6
#   Auto merged
# 
# arch/i386/kernel/cpu/cpufreq/speedstep-lib.c
#   2004/02/03 18:55:04+00:00 davej@delerium.codemonkey.org.uk +0 -23
#   Auto merged
# 
# arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
#   2004/02/03 18:55:04+00:00 davej@delerium.codemonkey.org.uk +0 -18
#   Auto merged
# 
# arch/i386/kernel/cpu/cpufreq/Kconfig
#   2004/02/03 18:55:03+00:00 davej@delerium.codemonkey.org.uk +0 -5
#   Auto merged
# 
# ChangeSet
#   2004/01/13 23:14:59+00:00 davej@redhat.com 
#   [CPUFREQ] fix up CPU detection in p4-clockmod
#   <Dominik Brodowski>
#   
#   Too many users use the p4-clockmod cpufreq driver instead of the more
#   advanced speedstep-centrino, speedstep-ich or even acpi drivers. All of the
#   latter (usually) provide voltage scaling, while the p4-clockmod driver only
#   offers a variant of frequency scaling. So, warn users if they try out this
#   driver instead.
#                                                                                                  
#   Also, instead of using a local copy, use the speedstep_lib infrastructure
#   for detecting the processor speed. Adding the Pentium-M get_frequency
#   function to that module only costs about 200 bytes in object size.
# 
# arch/i386/kernel/cpu/cpufreq/speedstep-lib.h
#   2004/01/13 23:14:53+00:00 davej@redhat.com +6 -0
#   [CPUFREQ] fix up CPU detection in p4-clockmod
#   <Dominik Brodowski>
#   
#   Too many users use the p4-clockmod cpufreq driver instead of the more
#   advanced speedstep-centrino, speedstep-ich or even acpi drivers. All of the
#   latter (usually) provide voltage scaling, while the p4-clockmod driver only
#   offers a variant of frequency scaling. So, warn users if they try out this
#   driver instead.
#                                                                                                  
#   Also, instead of using a local copy, use the speedstep_lib infrastructure
#   for detecting the processor speed. Adding the Pentium-M get_frequency
#   function to that module only costs about 200 bytes in object size.
# 
# arch/i386/kernel/cpu/cpufreq/speedstep-lib.c
#   2004/01/13 23:14:53+00:00 davej@redhat.com +23 -0
#   [CPUFREQ] fix up CPU detection in p4-clockmod
#   <Dominik Brodowski>
#   
#   Too many users use the p4-clockmod cpufreq driver instead of the more
#   advanced speedstep-centrino, speedstep-ich or even acpi drivers. All of the
#   latter (usually) provide voltage scaling, while the p4-clockmod driver only
#   offers a variant of frequency scaling. So, warn users if they try out this
#   driver instead.
#                                                                                                  
#   Also, instead of using a local copy, use the speedstep_lib infrastructure
#   for detecting the processor speed. Adding the Pentium-M get_frequency
#   function to that module only costs about 200 bytes in object size.
# 
# arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
#   2004/01/13 23:14:53+00:00 davej@redhat.com +18 -37
#   [CPUFREQ] fix up CPU detection in p4-clockmod
#   <Dominik Brodowski>
#   
#   Too many users use the p4-clockmod cpufreq driver instead of the more
#   advanced speedstep-centrino, speedstep-ich or even acpi drivers. All of the
#   latter (usually) provide voltage scaling, while the p4-clockmod driver only
#   offers a variant of frequency scaling. So, warn users if they try out this
#   driver instead.
#                                                                                                  
#   Also, instead of using a local copy, use the speedstep_lib infrastructure
#   for detecting the processor speed. Adding the Pentium-M get_frequency
#   function to that module only costs about 200 bytes in object size.
# 
# arch/i386/kernel/cpu/cpufreq/Kconfig
#   2004/01/13 23:14:53+00:00 davej@redhat.com +5 -5
#   [CPUFREQ] fix up CPU detection in p4-clockmod
#   <Dominik Brodowski>
#   
#   Too many users use the p4-clockmod cpufreq driver instead of the more
#   advanced speedstep-centrino, speedstep-ich or even acpi drivers. All of the
#   latter (usually) provide voltage scaling, while the p4-clockmod driver only
#   offers a variant of frequency scaling. So, warn users if they try out this
#   driver instead.
#                                                                                                  
#   Also, instead of using a local copy, use the speedstep_lib infrastructure
#   for detecting the processor speed. Adding the Pentium-M get_frequency
#   function to that module only costs about 200 bytes in object size.
# 
# ChangeSet
#   2004/01/13 21:56:44+00:00 davej@redhat.com 
#   [CPUFREQ] Silence powernow-k7 when built as a module.
#   (Pavel Machek)
# 
# arch/i386/kernel/cpu/cpufreq/powernow-k7.c
#   2004/01/13 21:56:38+00:00 davej@redhat.com +3 -8
#   [CPUFREQ] Silence powernow-k7 when built as a module.
#   (Pavel Machek)
# 
diff -Nru a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c
--- a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c	Wed Feb 11 22:14:31 2004
+++ b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c	Wed Feb 11 22:14:31 2004
@@ -28,30 +28,34 @@
  *	with 'Suspend Modulation OFF Count Register'
  *	and 'Suspend Modulation ON Count Register'.
  *	These registers are 8bit counters that represent the number of 
- *	32us intervals which the SUSP# pin is asserted/de-asserted to the 
- *	processor.
+ *	32us intervals which the SUSP# pin is asserted(ON)/de-asserted(OFF)
+ *	to the processor.
  *
  *	These counters define a ratio which is the effective frequency 
  * 	of operation of the system.
  *
- *			       On Count
+ *			       OFF Count
  *	F_eff = Fgx * ----------------------
- *	                On Count + Off Count
+ *	                OFF Count + ON Count
  *
  *	0 <= On Count, Off Count <= 255
  *
  *	From these limits, we can get register values 
  *
- *	on_duration + off_duration <= MAX_DURATION
- *	off_duration = on_duration * (stock_freq - freq) / freq
+ *	off_duration + on_duration <= MAX_DURATION
+ *	on_duration = off_duration * (stock_freq - freq) / freq
  *
- *      on_duration  =  (freq * DURATION) / stock_freq 
- *      off_duration = DURATION - on_duration 
+ *      off_duration  =  (freq * DURATION) / stock_freq 
+ *      on_duration = DURATION - off_duration 
  *
  *
  *---------------------------------------------------------------------------
  *
  * ChangeLog:
+ *  	Dec. 12, 2003	Hiroshi Miura <miura@da-cha.org>
+ *  		- fix on/off register mistake
+ *  		- fix cpu_khz calc when it stops cpu modulation.
+ *
  *	Dec. 11, 2002 	Hiroshi Miura <miura@da-cha.org>
  *		- rewrite for Cyrix MediaGX Cx5510/5520 and 
  *		  NatSemi Geode Cs5530(A).
@@ -233,13 +237,13 @@
 	int old_tmp_freq = stock_freq;
 	int tmp_freq;
 
-	*on_duration=1;
-	*off_duration=0;
+	*off_duration=1;
+	*on_duration=0;
 
 	for (i=max_duration; i>0; i--) {
-		tmp_on = ((khz * i) / stock_freq) & 0xff; 
-		tmp_off = i - tmp_on;
-		tmp_freq = (stock_freq * tmp_on) / i;
+		tmp_off = ((khz * i) / stock_freq) & 0xff; 
+		tmp_on = i - tmp_off;
+		tmp_freq = (stock_freq * tmp_off) / i;
 		/* if this relation is closer to khz, use this. If it's equal,
 		 * prefer it, too - lower latency */
 		if (abs(tmp_freq - khz) <= abs(old_tmp_freq - khz)) {
@@ -273,42 +277,37 @@
 
 	freqs.new = new_khz;
 
-	if (new_khz == stock_freq) {  /* if new khz == 100% of CPU speed, it is special case */
-		local_irq_save(flags);
-		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-		pci_write_config_byte(gx_params->cs55x0, PCI_SUSCFG, (gx_params->pci_suscfg & ~(SUSMOD)));
-		pci_read_config_byte(gx_params->cs55x0, PCI_SUSCFG, &(gx_params->pci_suscfg));
-		local_irq_restore(flags);
-		dprintk("suspend modulation disabled: cpu runs 100 percent speed.\n");
-		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-		return;
-	}
-
 	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-
 	local_irq_save(flags);
-	switch (gx_params->cs55x0->device) {
-	case PCI_DEVICE_ID_CYRIX_5530_LEGACY:
-		pmer1 = gx_params->pci_pmer1 | IRQ_SPDUP | VID_SPDUP;
-		/* FIXME: need to test other values -- Zwane,Miura */
-		pci_write_config_byte(gx_params->cs55x0, PCI_IRQTC, 4); /* typical 2 to 4ms */
-		pci_write_config_byte(gx_params->cs55x0, PCI_VIDTC, 100);/* typical 50 to 100ms */
-		pci_write_config_byte(gx_params->cs55x0, PCI_PMER1, pmer1);
 
-		if (gx_params->pci_rev < 0x10) {   /* CS5530(rev 1.2, 1.3) */
+	if (new_khz != stock_freq) {  /* if new khz == 100% of CPU speed, it is special case */
+		switch (gx_params->cs55x0->device) {
+		case PCI_DEVICE_ID_CYRIX_5530_LEGACY:
+			pmer1 = gx_params->pci_pmer1 | IRQ_SPDUP | VID_SPDUP;
+			/* FIXME: need to test other values -- Zwane,Miura */
+			pci_write_config_byte(gx_params->cs55x0, PCI_IRQTC, 4); /* typical 2 to 4ms */
+			pci_write_config_byte(gx_params->cs55x0, PCI_VIDTC, 100);/* typical 50 to 100ms */
+			pci_write_config_byte(gx_params->cs55x0, PCI_PMER1, pmer1);
+
+			if (gx_params->pci_rev < 0x10) {   /* CS5530(rev 1.2, 1.3) */
+				suscfg = gx_params->pci_suscfg | SUSMOD;
+			} else {                           /* CS5530A,B.. */
+				suscfg = gx_params->pci_suscfg | SUSMOD | PWRSVE;
+			}
+			break;
+		case PCI_DEVICE_ID_CYRIX_5520:
+		case PCI_DEVICE_ID_CYRIX_5510:
 			suscfg = gx_params->pci_suscfg | SUSMOD;
-		} else {                           /* CS5530A,B.. */
-			suscfg = gx_params->pci_suscfg | SUSMOD | PWRSVE;
+		default:
+			local_irq_restore(flags);
+			dprintk("fatal: try to set unknown chipset.\n");
+			return;
 		}
-		break;
-	case PCI_DEVICE_ID_CYRIX_5520:
-	case PCI_DEVICE_ID_CYRIX_5510:
-		suscfg = gx_params->pci_suscfg | SUSMOD;
-		break;
-	default:
-		local_irq_restore(flags);
-		dprintk("fatal: try to set unknown chipset.\n");
-		return;
+	} else {
+		suscfg = gx_params->pci_suscfg & ~(SUSMOD);
+		gx_params->off_duration = 0;
+		gx_params->on_duration = 0;
+		dprintk("suspend modulation disabled: cpu runs 100 percent speed.\n");
 	}
 
 	pci_write_config_byte(gx_params->cs55x0, PCI_MODOFF, gx_params->off_duration);
diff -Nru a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c
--- a/arch/i386/kernel/cpu/cpufreq/longhaul.c	Wed Feb 11 22:14:30 2004
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c	Wed Feb 11 22:14:30 2004
@@ -63,11 +63,12 @@
 
 static unsigned int calc_speed (int mult, int fsb)
 {
-	int mhz;
-	mhz = (mult/10)*fsb;
+	int khz;
+	khz = (mult/10)*fsb;
 	if (mult%10)
-		mhz += fsb/2;
-	return mhz;
+		khz += fsb/2;
+	khz *= 1000;
+	return khz;
 }
 
 
@@ -253,7 +254,7 @@
 	highest_speed = calc_speed (maxmult, fsb);
 	lowest_speed = calc_speed (minmult,fsb);
 	dprintk (KERN_INFO PFX "FSB: %dMHz Lowestspeed=%dMHz Highestspeed=%dMHz\n",
-		 fsb, lowest_speed, highest_speed);
+		 fsb, lowest_speed/1000, highest_speed/1000);
 
 	longhaul_table = kmalloc((numscales + 1) * sizeof(struct cpufreq_frequency_table), GFP_KERNEL);
 	if(!longhaul_table)
@@ -267,7 +268,7 @@
 		if (ratio > maxmult || ratio < minmult)
 			continue;
 		longhaul_table[k].frequency = calc_speed (ratio, fsb);
-		longhaul_table[k].index	= (j << 8);
+		longhaul_table[k].index	= j;
 		k++;
 	}
 
diff -Nru a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
--- a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c	Wed Feb 11 22:14:31 2004
+++ b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c	Wed Feb 11 22:14:31 2004
@@ -246,7 +246,7 @@
 static int cpufreq_p4_cpu_exit(struct cpufreq_policy *policy)
 {
 	cpufreq_frequency_table_put_attr(policy->cpu);    
-	return cpufreq_p4_setdc(policy->cpu, DC_DISABLE);
+	return 0;
 }
 
 static struct freq_attr* p4clockmod_attr[] = {
diff -Nru a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c	Wed Feb 11 22:14:30 2004
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c	Wed Feb 11 22:14:30 2004
@@ -91,17 +91,12 @@
 	struct cpuinfo_x86 *c = cpu_data;
 	unsigned int maxei, eax, ebx, ecx, edx;
 
-	if (c->x86_vendor != X86_VENDOR_AMD) {
-		printk (KERN_INFO PFX "AMD processor not detected.\n");
-		return 0;
-	}
-
-	if (c->x86 !=6) {
+	if ((c->x86_vendor != X86_VENDOR_AMD) || (c->x86 !=6)) {
+#ifdef MODULE
 		printk (KERN_INFO PFX "This module only works with AMD K7 CPUs\n");
+#endif
 		return 0;
 	}
-
-	printk (KERN_INFO PFX "AMD K7 CPU detected.\n");
 
 	if ((c->x86_model == 6) && (c->x86_mask == 0)) {
 		printk (KERN_INFO PFX "K7 660[A0] core detected, enabling errata workarounds\n");
diff -Nru a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c	Wed Feb 11 22:14:31 2004
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c	Wed Feb 11 22:14:31 2004
@@ -31,7 +31,7 @@
 
 #define PFX "powernow-k8: "
 #define BFX PFX "BIOS error: "
-#define VERSION "version 1.00.08 - September 26, 2003"
+#define VERSION "version 1.00.08a"
 #include "powernow-k8.h"
 
 #ifdef CONFIG_PREEMPT
@@ -44,10 +44,11 @@
 static u32 rvo;		/* ramp voltage offset, from PSB */
 static u32 irt;		/* isochronous relief time, from PSB */
 static u32 vidmvs;	/* usable value calculated from mvs, from PSB */
-struct pst_s *ppst;	/* array of p states, valid for this part */
 static u32 currvid;	/* keep track of the current fid / vid */
 static u32 currfid;
 
+static struct cpufreq_frequency_table *powernow_table;
+
 /*
 The PSB table supplied by BIOS allows for the definition of the number of
 p-states that can be used when running on a/c, and the number of p-states
@@ -71,30 +72,12 @@
 static u32 batps;	/* limit on the number of p states when on battery */
 			/* - set by BIOS in the PSB/PST                    */
 
-static struct cpufreq_driver cpufreq_amd64_driver = {
-	.verify = powernowk8_verify,
-	.target = powernowk8_target,
-	.init = powernowk8_cpu_init,
-	.name = "cpufreq-amd64",
-	.owner = THIS_MODULE,
-};
-
-#define SEARCH_UP     1
-#define SEARCH_DOWN   0
-
-/* Return a frequency in MHz, given an input fid */
-u32
-find_freq_from_fid(u32 fid)
+ /* Return a frequency in MHz, given an input fid */
+static u32 find_freq_from_fid(u32 fid)
 {
-	return 800 + (fid * 100);
+ 	return 800 + (fid * 100);
 }
 
-/* Return a fid matching an input frequency in MHz */
-static u32
-find_fid_from_freq(u32 freq)
-{
-	return (freq - 800) / 100;
-}
 
 /* Return the vco fid for an input fid */
 static u32
@@ -107,56 +90,27 @@
 	}
 }
 
-/* Sort the fid/vid frequency table into ascending order by fid. The spec */
-/* implies that it will be sorted by BIOS, but, it only implies it, and I */
-/* prefer not to trust when I can check.                                  */
-/* Yes, it is a simple bubble sort, but the PST is really small, so the   */
-/* choice of algorithm is pretty irrelevant.                              */
-static inline void
-sort_pst(struct pst_s *ppst, u32 numpstates)
-{
-	u32 i;
-	u8 tempfid;
-	u8 tempvid;
-	int swaps = 1;
-
-	while (swaps) {
-		swaps = 0;
-		for (i = 0; i < (numpstates - 1); i++) {
-			if (ppst[i].fid > ppst[i + 1].fid) {
-				swaps = 1;
-				tempfid = ppst[i].fid;
-				tempvid = ppst[i].vid;
-				ppst[i].fid = ppst[i + 1].fid;
-				ppst[i].vid = ppst[i + 1].vid;
-				ppst[i + 1].fid = tempfid;
-				ppst[i + 1].vid = tempvid;
-			}
-		}
-	}
-
-	return;
-}
-
-/* Return 1 if the pending bit is set. Unless we are actually just told the */
-/* processor to transition a state, seeing this bit set is really bad news. */
+/*
+ * Return 1 if the pending bit is set. Unless we are actually just told the
+ * processor to transition a state, seeing this bit set is really bad news.
+ */
 static inline int
 pending_bit_stuck(void)
 {
-	u32 lo;
-	u32 hi;
+	u32 lo, hi;
 
 	rdmsr(MSR_FIDVID_STATUS, lo, hi);
 	return lo & MSR_S_LO_CHANGE_PENDING ? 1 : 0;
 }
 
-/* Update the global current fid / vid values from the status msr. Returns 1 */
-/* on error.                                                                 */
+/*
+ * Update the global current fid / vid values from the status msr. Returns 1
+ * on error.
+ */
 static int
 query_current_values_with_pending_wait(void)
 {
-	u32 lo;
-	u32 hi;
+	u32 lo, hi;
 	u32 i = 0;
 
 	lo = MSR_S_LO_CHANGE_PENDING;
@@ -271,9 +225,11 @@
 	return 0;
 }
 
-/* Reduce the vid by the max of step or reqvid.                   */
-/* Decreasing vid codes represent increasing voltages :           */
-/* vid of 0 is 1.550V, vid of 0x1e is 0.800V, vid of 0x1f is off. */
+/*
+ * Reduce the vid by the max of step or reqvid.
+ * Decreasing vid codes represent increasing voltages:
+ * vid of 0 is 1.550V, vid of 0x1e is 0.800V, vid of 0x1f is off.
+ */
 static int
 decrease_vid_code_by_step(u32 reqvid, u32 step)
 {
@@ -316,8 +272,10 @@
 	return 0;
 }
 
-/* Phase 1 - core voltage transition ... setup appropriate voltage for the */
-/* fid transition.                                                         */
+/*
+ * Phase 1 - core voltage transition ... setup appropriate voltage for the
+ * fid transition.
+ */
 static inline int
 core_voltage_pre_transition(u32 reqvid)
 {
@@ -500,7 +458,9 @@
 	}
 
 	if (c->x86_vendor != X86_VENDOR_AMD) {
+#ifdef MODULE
 		printk(KERN_INFO PFX "Not an AMD processor\n");
+#endif
 		return 0;
 	}
 
@@ -533,20 +493,59 @@
 		return 0;
 	}
 
-	printk(KERN_INFO PFX "Found AMD Athlon 64 / Opteron processor "
-	       "supporting p-state transitions\n");
-
+	printk(KERN_INFO PFX "Found AMD64 processor supporting PowerNow (" VERSION ")\n");
 	return 1;
 }
 
+static int check_pst_table(struct pst_s *pst, u8 maxvid)
+{
+	unsigned int j;
+	u8 lastfid = 0xFF;
+
+	for (j = 0; j < numps; j++) {
+		if (pst[j].vid > LEAST_VID) {
+			printk(KERN_ERR PFX "vid %d invalid : 0x%x\n", j, pst[j].vid);
+			return -EINVAL;
+		}
+		if (pst[j].vid < rvo) {	/* vid + rvo >= 0 */
+			printk(KERN_ERR PFX
+			       "BIOS error - 0 vid exceeded with pstate %d\n",
+			       j);
+			return -ENODEV;
+		}
+		if (pst[j].vid < maxvid + rvo) {	/* vid + rvo >= maxvid */
+			printk(KERN_ERR PFX
+			       "BIOS error - maxvid exceeded with pstate %d\n",
+			       j);
+			return -ENODEV;
+		}
+		if ((pst[j].fid > MAX_FID)
+		    || (pst[j].fid & 1)
+		    || (pst[j].fid < HI_FID_TABLE_BOTTOM)){
+			printk(KERN_ERR PFX "fid %d invalid : 0x%x\n", j, pst[j].fid);
+			return -EINVAL;
+		}
+		if (pst[j].fid < lastfid)
+			lastfid = pst[j].fid;
+	}
+	if (lastfid & 1) {
+		printk(KERN_ERR PFX "lastfid invalid\n");
+		return -EINVAL;
+	}
+	if (lastfid > LO_FID_TABLE_TOP) {
+		printk(KERN_INFO PFX  "first fid not from lo freq table\n");
+	}
+
+	return 0;
+}
+
 /* Find and validate the PSB/PST table in BIOS. */
 static inline int
 find_psb_table(void)
 {
 	struct psb_s *psb;
 	struct pst_s *pst;
-	unsigned i, j;
-	u32 lastfid;
+	unsigned int i, j;
 	u32 mvs;
 	u8 maxvid;
 
@@ -573,33 +572,19 @@
 		}
 
 		vstable = psb->voltagestabilizationtime;
-		printk(KERN_INFO PFX "voltage stable time: %d (units 20us)\n",
-		       vstable);
-
 		dprintk(KERN_DEBUG PFX "flags2: 0x%x\n", psb->flags2);
 		rvo = psb->flags2 & 3;
 		irt = ((psb->flags2) >> 2) & 3;
 		mvs = ((psb->flags2) >> 4) & 3;
 		vidmvs = 1 << mvs;
 		batps = ((psb->flags2) >> 6) & 3;
-		printk(KERN_INFO PFX "p states on battery: %d ", batps);
-		switch (batps) {
-		case 0:
-			printk("- all available\n");
-			break;
-		case 1:
-			printk("- only the minimum\n");
-			break;
-		case 2:
-			printk("- only the 2 lowest\n");
-			break;
-		case 3:
-			printk("- only the 3 lowest\n");
-			break;
-		}
-		printk(KERN_INFO PFX "ramp voltage offset: %d\n", rvo);
-		printk(KERN_INFO PFX "isochronous relief time: %d\n", irt);
-		printk(KERN_INFO PFX "maximum voltage step: %d\n", mvs);
+
+		printk(KERN_INFO PFX "voltage stable in %d usec", vstable * 20);
+		if (batps)
+			printk(", only %d lowest states on battery", batps);
+		printk(", ramp voltage offset: %d", rvo);
+		printk(", isochronous relief time: %d", irt);
+		printk(", maximum voltage step: %d\n", mvs);
 
 		dprintk(KERN_DEBUG PFX "numpst: 0x%x\n", psb->numpst);
 		if (psb->numpst != 1) {
@@ -610,14 +595,13 @@
 		dprintk(KERN_DEBUG PFX "cpuid: 0x%x\n", psb->cpuid);
 
 		plllock = psb->plllocktime;
-		printk(KERN_INFO PFX "pll lock time: 0x%x\n", plllock);
+		printk(KERN_INFO PFX "pll lock time: 0x%x, ", plllock);
 
 		maxvid = psb->maxvid;
-		printk(KERN_INFO PFX "maxfid: 0x%x\n", psb->maxfid);
-		printk(KERN_INFO PFX "maxvid: 0x%x\n", maxvid);
+		printk("maxfid 0x%x (%d MHz), maxvid 0x%x\n", 
+		       psb->maxfid, find_freq_from_fid(psb->maxfid), maxvid);
 
 		numps = psb->numpstates;
-		printk(KERN_INFO PFX "numpstates: 0x%x\n", numps);
 		if (numps < 2) {
 			printk(KERN_ERR BFX "no p states to transition\n");
 			return -ENODEV;
@@ -636,78 +620,41 @@
 			       "%d p-states\n", numps);
 		}
 
-		if ((numps <= 1) || (batps <= 1)) {
+		if (numps <= 1) {
 			printk(KERN_ERR PFX "only 1 p-state to transition\n");
 			return -ENODEV;
 		}
 
-		ppst = kmalloc(sizeof (struct pst_s) * numps, GFP_KERNEL);
-		if (!ppst) {
-			printk(KERN_ERR PFX "ppst memory alloc failure\n");
-			return -ENOMEM;
-		}
-
 		pst = (struct pst_s *) (psb + 1);
-		for (j = 0; j < numps; j++) {
-			ppst[j].fid = pst[j].fid;
-			ppst[j].vid = pst[j].vid;
-			printk(KERN_INFO PFX
-			       "   %d : fid 0x%x, vid 0x%x\n", j,
-			       ppst[j].fid, ppst[j].vid);
-		}
-		sort_pst(ppst, numps);
-
-		lastfid = ppst[0].fid;
-		if (lastfid > LO_FID_TABLE_TOP)
-			printk(KERN_INFO BFX "first fid not in lo freq tbl\n");
-
-		if ((lastfid > MAX_FID) || (lastfid & 1) || (ppst[0].vid > LEAST_VID)) {
-			printk(KERN_ERR BFX "first fid/vid bad (0x%x - 0x%x)\n",
-			       lastfid, ppst[0].vid);
-			kfree(ppst);
-			return -ENODEV;
-		}
+		if (check_pst_table(pst, maxvid))
+			return -EINVAL;
 
-		for (j = 1; j < numps; j++) {
-			if ((lastfid >= ppst[j].fid)
-			    || (ppst[j].fid & 1)
-			    || (ppst[j].fid < HI_FID_TABLE_BOTTOM)
-			    || (ppst[j].fid > MAX_FID)
-			    || (ppst[j].vid > LEAST_VID)) {
-				printk(KERN_ERR BFX
-				       "invalid fid/vid in pst(%x %x)\n",
-				       ppst[j].fid, ppst[j].vid);
-				kfree(ppst);
-				return -ENODEV;
-			}
-			lastfid = ppst[j].fid;
+		powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table) * (numps + 1)), GFP_KERNEL);
+		if (!powernow_table) {
+			printk(KERN_ERR PFX "powernow_table memory alloc failure\n");
+			return -ENOMEM;
 		}
 
 		for (j = 0; j < numps; j++) {
-			if (ppst[j].vid < rvo) {	/* vid+rvo >= 0 */
-				printk(KERN_ERR BFX
-				       "0 vid exceeded with pstate %d\n", j);
-				kfree(ppst);
-				return -ENODEV;
-			}
-			if (ppst[j].vid < maxvid+rvo) { /* vid+rvo >= maxvid */
-				printk(KERN_ERR BFX
-				       "maxvid exceeded with pstate %d\n", j);
-				kfree(ppst);
-				return -ENODEV;
-			}
+			printk(KERN_INFO PFX "   %d : fid 0x%x (%d MHz), vid 0x%x\n", j,
+			       pst[j].fid, find_freq_from_fid(pst[j].fid), pst[j].vid);
+			powernow_table[j].index = pst[j].fid; /* lower 8 bits */
+			powernow_table[j].index |= (pst[j].vid << 8); /* upper 8 bits */
+			powernow_table[j].frequency = find_freq_from_fid(pst[j].fid);
 		}
+		powernow_table[numps].frequency = CPUFREQ_TABLE_END;
+		powernow_table[numps].index = 0;
 
 		if (query_current_values_with_pending_wait()) {
-			kfree(ppst);
+			kfree(powernow_table);
 			return -EIO;
 		}
 
-		printk(KERN_INFO PFX "currfid 0x%x, currvid 0x%x\n",
-		       currfid, currvid);
+		printk(KERN_INFO PFX "currfid 0x%x (%d MHz), currvid 0x%x\n",
+		       currfid, find_freq_from_fid(currfid), currvid);
 
 		for (j = 0; j < numps; j++)
-			if ((ppst[j].fid==currfid) && (ppst[j].vid==currvid))
+			if ((pst[j].fid==currfid) && (pst[j].vid==currvid))
 				return 0;
 
 		printk(KERN_ERR BFX "currfid/vid do not match PST, ignoring\n");
@@ -718,112 +665,22 @@
 	return -ENODEV;
 }
 
-/* Converts a frequency (that might not necessarily be a multiple of 200) */
-/* to a fid.                                                              */
-static u32
-find_closest_fid(u32 freq, int searchup)
-{
-	if (searchup == SEARCH_UP)
-		freq += MIN_FREQ_RESOLUTION - 1;
-
-	freq = (freq / MIN_FREQ_RESOLUTION) * MIN_FREQ_RESOLUTION;
-
-	if (freq < MIN_FREQ)
-		freq = MIN_FREQ;
-	else if (freq > MAX_FREQ)
-		freq = MAX_FREQ;
-
-	return find_fid_from_freq(freq);
-}
-
-static int
-find_match(u32 * ptargfreq, u32 * pmin, u32 * pmax, int searchup, u32 * pfid,
-	   u32 * pvid)
-{
-	u32 availpstates = batps;
-	u32 targfid = find_closest_fid(*ptargfreq, searchup);
-	u32 minfid = find_closest_fid(*pmin, SEARCH_DOWN);
-	u32 maxfid = find_closest_fid(*pmax, SEARCH_UP);
-	u32 minidx = 0;
-	u32 maxidx = availpstates - 1;
-	u32 targidx = 0xffffffff;
-	int i;
-
-	dprintk(KERN_DEBUG PFX "find match: freq %d MHz, min %d, max %d\n",
-		*ptargfreq, *pmin, *pmax);
-
-	/* Restrict values to the frequency choices in the PST */
-	if (minfid < ppst[0].fid)
-		minfid = ppst[0].fid;
-	if (maxfid > ppst[maxidx].fid)
-		maxfid = ppst[maxidx].fid;
-
-	/* Find appropriate PST index for the minimim fid */
-	for (i = 0; i < (int) availpstates; i++) {
-		if (minfid >= ppst[i].fid)
-			minidx = i;
-	}
-
-	/* Find appropriate PST index for the maximum fid */
-	for (i = availpstates - 1; i >= 0; i--) {
-		if (maxfid <= ppst[i].fid)
-			maxidx = i;
-	}
-
-	if (minidx > maxidx)
-		maxidx = minidx;
-
-	/* Frequency ids are now constrained by limits matching PST entries */
-	minfid = ppst[minidx].fid;
-	maxfid = ppst[maxidx].fid;
-
-	/* Limit the target frequency to these limits */
-	if (targfid < minfid)
-		targfid = minfid;
-	else if (targfid > maxfid)
-		targfid = maxfid;
-
-	/* Find the best target index into the PST, contrained by the range */
-	if (searchup == SEARCH_UP) {
-		for (i = maxidx; i >= (int) minidx; i--) {
-			if (targfid <= ppst[i].fid)
-				targidx = i;
-		}
-	} else {
-		for (i = minidx; i <= (int) maxidx; i++) {
-			if (targfid >= ppst[i].fid)
-				targidx = i;
-		}
-	}
-
-	if (targidx == 0xffffffff) {
-		printk(KERN_ERR PFX "could not find target\n");
-		return 1;
-	}
-
-	*pmin = find_freq_from_fid(minfid);
-	*pmax = find_freq_from_fid(maxfid);
-	*ptargfreq = find_freq_from_fid(ppst[targidx].fid);
-
-	if (pfid)
-		*pfid = ppst[targidx].fid;
-	if (pvid)
-		*pvid = ppst[targidx].vid;
-
-	return 0;
-}
-
 /* Take a frequency, and issue the fid/vid transition command */
 static inline int
-transition_frequency(u32 * preq, u32 * pmin, u32 * pmax, u32 searchup)
+transition_frequency(unsigned int index)
 {
 	u32 fid;
 	u32 vid;
 	int res;
 	struct cpufreq_freqs freqs;
 
-	if (find_match(preq, pmin, pmax, searchup, &fid, &vid))
-		return 1;
+	/* fid are the lower 8 bits of the index we stored into
+	 * the cpufreq frequency table in find_psb_table, vid are 
+	 * the upper 8 bits.
+	 */
+
+	fid = powernow_table[index].index & 0xFF;
+	vid = (powernow_table[index].index & 0xFF00) >> 8;
 
 	dprintk(KERN_DEBUG PFX "table matched fid 0x%x, giving vid 0x%x\n",
 		fid, vid);
@@ -867,14 +724,7 @@
 {
 	u32 checkfid = currfid;
 	u32 checkvid = currvid;
-	u32 reqfreq = targfreq / 1000;
-	u32 minfreq = pol->min / 1000;
-	u32 maxfreq = pol->max / 1000;
-
-	if (ppst == 0) {
-		printk(KERN_ERR PFX "targ: ppst 0\n");
-		return -ENODEV;
-	}
+	unsigned int newstate;
 
 	if (pending_bit_stuck()) {
 		printk(KERN_ERR PFX "drv targ fail: change pending bit set\n");
@@ -896,9 +746,10 @@
 		       checkfid, currfid, checkvid, currvid);
 	}
 
-	if (transition_frequency(&reqfreq, &minfreq, &maxfreq,
-				 relation ==
-				 CPUFREQ_RELATION_H ? SEARCH_UP : SEARCH_DOWN))
+	if (cpufreq_frequency_table_target(pol, powernow_table, targfreq, relation, &newstate))
+		return -EINVAL;
+	
+	if (transition_frequency(newstate))
 	{
 		printk(KERN_ERR PFX "transition frequency failed\n");
 		return 1;
@@ -913,36 +764,12 @@
 static int
 powernowk8_verify(struct cpufreq_policy *pol)
 {
-	u32 min = pol->min / 1000;
-	u32 max = pol->max / 1000;
-	u32 targ = min;
-	int res;
-
-	if (ppst == 0) {
-		printk(KERN_ERR PFX "verify - ppst 0\n");
-		return -ENODEV;
-	}
-
 	if (pending_bit_stuck()) {
 		printk(KERN_ERR PFX "failing verify, change pending bit set\n");
 		return -EIO;
 	}
 
-	dprintk(KERN_DEBUG PFX
-		"ver: cpu%d, min %d, max %d, cur %d, pol %d\n", pol->cpu,
-		pol->min, pol->max, pol->cur, pol->policy);
-
-	if (pol->cpu != 0) {
-		printk(KERN_ERR PFX "verify - cpu not 0\n");
-		return -ENODEV;
-	}
-
-	res = find_match(&targ, &min, &max, SEARCH_DOWN, 0, 0);
-	if (!res) {
-		pol->min = min * 1000;
-		pol->max = max * 1000;
-	}
-	return res;
+	return cpufreq_frequency_table_verify(pol, powernow_table);
 }
 
 /* per CPU init entry point to the driver */
@@ -968,10 +795,11 @@
 	dprintk(KERN_DEBUG PFX "policy current frequency %d kHz\n", pol->cur);
 
 	/* min/max the cpu is capable of */
-	pol->cpuinfo.min_freq = 1000 * find_freq_from_fid(ppst[0].fid);
-	pol->cpuinfo.max_freq = 1000 * find_freq_from_fid(ppst[numps-1].fid);
-	pol->min = 1000 * find_freq_from_fid(ppst[0].fid);
-	pol->max = 1000 * find_freq_from_fid(ppst[batps - 1].fid);
+	if (cpufreq_frequency_table_cpuinfo(pol, powernow_table)) {
+		printk(KERN_ERR PFX "invalid powernow_table\n");
+		kfree(powernow_table);
+		return -EINVAL;
+	}
 
 	printk(KERN_INFO PFX "cpu_init done, current fid 0x%x, vid 0x%x\n",
 	       currfid, currvid);
@@ -979,14 +807,33 @@
 	return 0;
 }
 
+static int __exit powernowk8_cpu_exit (struct cpufreq_policy *pol)
+{
+	if (pol->cpu != 0)
+		return -EINVAL;
+
+	if (powernow_table)
+		kfree(powernow_table);
+
+	return 0;
+}
+
+static struct cpufreq_driver cpufreq_amd64_driver = {
+	.verify = powernowk8_verify,
+	.target = powernowk8_target,
+	.init = powernowk8_cpu_init,
+	.exit = powernowk8_cpu_exit,
+	.name = "powernow-k8",
+	.owner = THIS_MODULE,
+};
+
+
 /* driver entry point for init */
 static int __init
 powernowk8_init(void)
 {
 	int rc;
 
-	printk(KERN_INFO PFX VERSION "\n");
-
 	if (check_supported_cpu() == 0)
 		return -ENODEV;
 
@@ -996,7 +843,6 @@
 
 	if (pending_bit_stuck()) {
 		printk(KERN_ERR PFX "powernowk8_init fail, change pending bit set\n");
-		kfree(ppst);
 		return -EIO;
 	}
 
@@ -1010,7 +856,6 @@
 	dprintk(KERN_INFO PFX "powernowk8_exit\n");
 
 	cpufreq_unregister_driver(&cpufreq_amd64_driver);
-	kfree(ppst);
 }
 
 MODULE_AUTHOR("Paul Devriendt <paul.devriendt@amd.com>");
diff -Nru a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h	Wed Feb 11 22:14:31 2004
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h	Wed Feb 11 22:14:31 2004
@@ -120,7 +120,3 @@
 static inline int core_voltage_pre_transition(u32 reqvid);
 static inline int core_voltage_post_transition(u32 reqvid);
 static inline int core_frequency_transition(u32 reqfid);
-static int powernowk8_verify(struct cpufreq_policy *pol);
-static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq,
-		      unsigned relation);
-static int __init powernowk8_cpu_init(struct cpufreq_policy *pol);
diff -Nru a/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c b/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c	Wed Feb 11 22:14:31 2004
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c	Wed Feb 11 22:14:31 2004
@@ -207,17 +207,55 @@
 		if (c->x86_model != 2)
 			return 0;
 
-		if ((c->x86_mask != 4) && /* B-stepping [M-P4-M] */
-			(c->x86_mask != 7) && /* C-stepping [M-P4-M] */
-			(c->x86_mask != 9))   /* D-stepping [M-P4-M or M-P4/533] */
-			return 0;
-
 		ebx = cpuid_ebx(0x00000001);
 		ebx &= 0x000000FF;
-		if ((ebx != 0x0e) && (ebx != 0x0f))
-			return 0;
 
-		return SPEEDSTEP_PROCESSOR_P4M;
+		dprintk(KERN_INFO "ebx value is %x, x86_mask is %x\n", ebx, c->86_mask);
+
+		switch (c->x86_mask) {
+		case 4: 
+			/*
+			 * B-stepping [M-P4-M] 
+			 * sample has ebx = 0x0f, production has 0x0e.
+			 */
+			if ((ebx == 0x0e) || (ebx == 0x0f))
+				return SPEEDSTEP_PROCESSOR_P4M;
+			break;
+		case 7: 
+			/*
+			 * C-stepping [M-P4-M]
+			 * needs to have ebx=0x0e, else it's a celeron:
+			 * cf. 25130917.pdf / page 7, footnote 5 even
+			 * though 25072120.pdf / page 7 doesn't say
+			 * samples are only of B-stepping...
+			 */
+			if (ebx == 0x0e)
+				return SPEEDSTEP_PROCESSOR_P4M;
+			break;
+		case 9:
+			/*
+			 * D-stepping [M-P4-M or M-P4/533]
+			 *
+			 * this is totally strange: CPUID 0x0F29 is
+			 * used by M-P4-M, M-P4/533 and(!) Celeron CPUs.
+			 * The latter need to be sorted out as they don't
+			 * support speedstep.
+			 * Celerons with CPUID 0x0F29 may have either
+			 * ebx=0x8 or 0xf -- 25130917.pdf doesn't say anything
+			 * specific.
+			 * M-P4-Ms may have either ebx=0xe or 0xf [see above]
+			 * M-P4/533 have either ebx=0xe or 0xf. [25317607.pdf]
+			 * So, how to distinguish all those processors with
+			 * ebx=0xf? I don't know. Sort them out, and wait
+			 * for someone to complain.
+			 */
+			if (ebx == 0x0e)
+				return SPEEDSTEP_PROCESSOR_P4M;
+			break;
+		default:
+			break;
+		}
+		return 0;
 	}
 
 	switch (c->x86_model) {
diff -Nru a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c
--- a/arch/i386/kernel/cpu/intel.c	Wed Feb 11 22:14:30 2004
+++ b/arch/i386/kernel/cpu/intel.c	Wed Feb 11 22:14:30 2004
@@ -296,12 +296,8 @@
 		} else if (smp_num_siblings > 1 ) {
 			index_lsb = 0;
 			index_msb = 31;
-			/*
-			 * At this point we only support two siblings per
-			 * processor package.
-			 */
-#define NR_SIBLINGS	2
-			if (smp_num_siblings != NR_SIBLINGS) {
+
+			if (smp_num_siblings > NR_CPUS) {
 				printk(KERN_WARNING "CPU: Unsupported number of the siblings %d", smp_num_siblings);
 				smp_num_siblings = 1;
 				goto too_many_siblings;
diff -Nru a/arch/ia64/defconfig b/arch/ia64/defconfig
--- a/arch/ia64/defconfig	Wed Feb 11 22:14:30 2004
+++ b/arch/ia64/defconfig	Wed Feb 11 22:14:30 2004
@@ -48,13 +48,14 @@
 CONFIG_MMU=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_TIME_INTERPOLATION=y
+CONFIG_EFI=y
 # CONFIG_ITANIUM is not set
 CONFIG_MCKINLEY=y
 # CONFIG_IA64_GENERIC is not set
 # CONFIG_IA64_DIG is not set
-# CONFIG_IA64_HP_SIM is not set
 CONFIG_IA64_HP_ZX1=y
 # CONFIG_IA64_SGI_SN2 is not set
+# CONFIG_IA64_HP_SIM is not set
 # CONFIG_IA64_PAGE_SIZE_4KB is not set
 # CONFIG_IA64_PAGE_SIZE_8KB is not set
 CONFIG_IA64_PAGE_SIZE_16KB=y
@@ -80,15 +81,14 @@
 # CONFIG_HUGETLB_PAGE_SIZE_256KB is not set
 # CONFIG_IA64_PAL_IDLE is not set
 CONFIG_SMP=y
+CONFIG_NR_CPUS=16
 # CONFIG_PREEMPT is not set
+CONFIG_HAVE_DEC_LOCK=y
 CONFIG_IA32_SUPPORT=y
 CONFIG_COMPAT=y
-CONFIG_HAVE_DEC_LOCK=y
 CONFIG_PERFMON=y
 CONFIG_IA64_PALINFO=y
-CONFIG_EFI=y
 CONFIG_EFI_VARS=y
-CONFIG_NR_CPUS=16
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=y
 
@@ -140,7 +140,6 @@
 #
 # Plug and Play support
 #
-# CONFIG_PNP is not set
 
 #
 # Block devices
@@ -179,6 +178,7 @@
 #
 # IDE chipset support/bugfixes
 #
+# CONFIG_IDE_GENERIC is not set
 CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_IDEPCI_SHARE_IRQ=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
@@ -223,7 +223,6 @@
 #
 # I2O device support
 #
-# CONFIG_I2O is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -234,6 +233,7 @@
 CONFIG_MD_RAID0=m
 CONFIG_MD_RAID1=m
 CONFIG_MD_RAID5=m
+# CONFIG_MD_RAID6 is not set
 CONFIG_MD_MULTIPATH=m
 CONFIG_BLK_DEV_DM=m
 CONFIG_DM_IOCTL_V4=y
@@ -303,9 +303,15 @@
 # CONFIG_SCSI_QLOGIC_ISP is not set
 # CONFIG_SCSI_QLOGIC_FC is not set
 CONFIG_SCSI_QLOGIC_1280=y
+CONFIG_SCSI_QLA2XXX=y
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# CONFIG_SCSI_QLA2300 is not set
+# CONFIG_SCSI_QLA2322 is not set
+# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_QLA6322 is not set
 # CONFIG_SCSI_DC395x is not set
 # CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 
 #
@@ -414,6 +420,7 @@
 # CONFIG_AMD8111_ETH is not set
 # CONFIG_ADAPTEC_STARFIRE is not set
 # CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
 # CONFIG_DGRS is not set
 CONFIG_EEPRO100=y
 # CONFIG_EEPRO100_PIO is not set
@@ -539,8 +546,8 @@
 #
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_ACPI=y
 CONFIG_SERIAL_8250_HCDP=y
+CONFIG_SERIAL_8250_ACPI=y
 CONFIG_SERIAL_8250_NR_UARTS=4
 # CONFIG_SERIAL_8250_EXTENDED is not set
 
@@ -553,24 +560,6 @@
 CONFIG_UNIX98_PTY_COUNT=256
 
 #
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# I2C Algorithms
-#
-
-#
-# I2C Hardware Bus support
-#
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-
-#
 # Mice
 #
 # CONFIG_BUSMOUSE is not set
@@ -610,6 +599,11 @@
 # CONFIG_RAW_DRIVER is not set
 
 #
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
 # Multimedia devices
 #
 # CONFIG_VIDEO_DEV is not set
@@ -789,6 +783,7 @@
 # CONFIG_FB_ATY is not set
 # CONFIG_FB_SIS is not set
 # CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
 # CONFIG_FB_TRIDENT is not set
@@ -844,6 +839,7 @@
 #
 # CONFIG_SND_ALI5451 is not set
 # CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
 # CONFIG_SND_CS46XX is not set
 # CONFIG_SND_CS4281 is not set
 # CONFIG_SND_EMU10K1 is not set
@@ -927,7 +923,6 @@
 # USB Imaging devices
 #
 # CONFIG_USB_MDC800 is not set
-# CONFIG_USB_SCANNER is not set
 # CONFIG_USB_MICROTEK is not set
 # CONFIG_USB_HPUSBSCSI is not set
 
@@ -961,12 +956,19 @@
 #
 # USB Miscellaneous drivers
 #
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
 # CONFIG_USB_TIGL is not set
 # CONFIG_USB_AUERSWALD is not set
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_BRLVGER is not set
 # CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+
+#
+# USB Gadget Support
+#
 # CONFIG_USB_GADGET is not set
 
 #
@@ -988,10 +990,6 @@
 CONFIG_IA64_PRINT_HAZARDS=y
 # CONFIG_DISABLE_VHPT is not set
 CONFIG_MAGIC_SYSRQ=y
-CONFIG_IA64_EARLY_PRINTK=y
-CONFIG_IA64_EARLY_PRINTK_UART=y
-CONFIG_IA64_EARLY_PRINTK_UART_BASE=0xff5e0000
-CONFIG_IA64_EARLY_PRINTK_VGA=y
 # CONFIG_DEBUG_SLAB is not set
 # CONFIG_DEBUG_SPINLOCK is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
diff -Nru a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c
--- a/arch/ia64/hp/common/sba_iommu.c	Wed Feb 11 22:14:30 2004
+++ b/arch/ia64/hp/common/sba_iommu.c	Wed Feb 11 22:14:30 2004
@@ -57,11 +57,21 @@
 ** There's potentially a conflict in the bio merge code with us
 ** advertising an iommu, but then bypassing it.  Since I/O MMU bypassing
 ** appears to give more performance than bio-level virtual merging, we'll
-** do the former for now.
+** do the former for now.  NOTE: BYPASS_SG also needs to be undef'd to
+** completely restrict DMA to the IOMMU.
 */
 #define ALLOW_IOV_BYPASS
 
 /*
+** This option specifically allows/disallows bypassing scatterlists with
+** multiple entries.  Coalescing these entries can allow better DMA streaming
+** and in some cases shows better performance than entirely bypassing the
+** IOMMU.  Performance increase on the order of 1-2% sequential output/input
+** using bonnie++ on a RAID0 MD device (sym2 & mpt).
+*/
+#undef ALLOW_IOV_BYPASS_SG
+
+/*
 ** If a device prefetches beyond the end of a valid pdir entry, it will cause
 ** a hard failure, ie. MCA.  Version 3.0 and later of the zx1 LBA should
 ** disconnect on 4k boundaries and prevent such issues.  If the device is
@@ -75,7 +85,10 @@
 #define ENABLE_MARK_CLEAN
 
 /*
-** The number of debug flags is a clue - this code is fragile.
+** The number of debug flags is a clue - this code is fragile.  NOTE: since
+** tightening the use of res_lock the resource bitmap and actual pdir are no
+** longer guaranteed to stay in sync.  The sanity checking code isn't going to
+** like that.
 */
 #undef DEBUG_SBA_INIT
 #undef DEBUG_SBA_RUN
@@ -140,9 +153,7 @@
 ** allocated and free'd/purged at a time might make this
 ** less interesting).
 */
-#define DELAYED_RESOURCE_CNT	16
-
-#define DEFAULT_DMA_HINT_REG	0
+#define DELAYED_RESOURCE_CNT	64
 
 #define ZX1_IOC_ID	((PCI_DEVICE_ID_HP_ZX1_IOC << 16) | PCI_VENDOR_ID_HP)
 #define REO_IOC_ID	((PCI_DEVICE_ID_HP_REO_IOC << 16) | PCI_VENDOR_ID_HP)
@@ -187,14 +198,15 @@
 	unsigned long	imask;		/* pdir IOV Space mask */
 
 	unsigned long	*res_hint;	/* next avail IOVP - circular search */
-	spinlock_t	res_lock;
-	unsigned long	hint_mask_pdir;	/* bits used for DMA hints */
+	unsigned long	dma_mask;
+	spinlock_t	res_lock;	/* protects the resource bitmap, but must be held when */
+					/* clearing pdir to prevent races with allocations. */
 	unsigned int	res_bitshift;	/* from the RIGHT! */
 	unsigned int	res_size;	/* size of resource map in bytes */
-	unsigned int	hint_shift_pdir;
-	unsigned long	dma_mask;
 #if DELAYED_RESOURCE_CNT > 0
-	int saved_cnt;
+	spinlock_t	saved_lock;	/* may want to try to get this on a separate cacheline */
+					/* than res_lock for bigger systems. */
+	int		saved_cnt;
 	struct sba_dma_pair {
 		dma_addr_t	iova;
 		size_t		size;
@@ -221,6 +233,9 @@
 static struct ioc *ioc_list;
 static int reserve_sba_gart = 1;
 
+static SBA_INLINE void sba_mark_invalid(struct ioc *, dma_addr_t, size_t);
+static SBA_INLINE void sba_free_range(struct ioc *, dma_addr_t, size_t);
+
 #define sba_sg_address(sg)	(page_address((sg)->page) + (sg)->offset)
 
 #ifdef FULL_VALID_PDIR
@@ -405,7 +420,7 @@
 #define PAGES_PER_RANGE 1	/* could increase this to 4 or 8 if needed */
 
 /* Convert from IOVP to IOVA and vice versa. */
-#define SBA_IOVA(ioc,iovp,offset,hint_reg) ((ioc->ibase) | (iovp) | (offset))
+#define SBA_IOVA(ioc,iovp,offset) ((ioc->ibase) | (iovp) | (offset))
 #define SBA_IOVP(ioc,iova) ((iova) & ~(ioc->ibase))
 
 #define PDIR_ENTRY_SIZE	sizeof(u64)
@@ -453,20 +468,25 @@
 
 	ASSERT(((unsigned long) ioc->res_hint & (sizeof(unsigned long) - 1UL)) == 0);
 	ASSERT(res_ptr < res_end);
-	if (bits_wanted > (BITS_PER_LONG/2)) {
-		/* Search word at a time - no mask needed */
-		for(; res_ptr < res_end; ++res_ptr) {
-			if (*res_ptr == 0) {
-				*res_ptr = RESMAP_MASK(bits_wanted);
+
+	if (likely(bits_wanted == 1)) {
+		unsigned int bitshiftcnt;
+		for(; res_ptr < res_end ; res_ptr++) {
+			if (likely(*res_ptr != ~0UL)) {
+				bitshiftcnt = ffz(*res_ptr);
+				*res_ptr |= (1UL << bitshiftcnt);
 				pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map);
 				pide <<= 3;	/* convert to bit address */
-				break;
+				pide += bitshiftcnt;
+				ioc->res_bitshift = bitshiftcnt + bits_wanted;
+				goto found_it;
 			}
 		}
-		/* point to the next word on next pass */
-		res_ptr++;
-		ioc->res_bitshift = 0;
-	} else {
+		goto not_found;
+
+	}
+	
+	if (likely(bits_wanted <= BITS_PER_LONG/2)) {
 		/*
 		** Search the resource bit map on well-aligned values.
 		** "o" is the alignment.
@@ -475,45 +495,72 @@
 		*/
 		unsigned long o = 1 << get_iovp_order(bits_wanted << iovp_shift);
 		uint bitshiftcnt = ROUNDUP(ioc->res_bitshift, o);
-		unsigned long mask;
+		unsigned long mask, base_mask;
 
-		if (bitshiftcnt >= BITS_PER_LONG) {
-			bitshiftcnt = 0;
-			res_ptr++;
-		}
-		mask = RESMAP_MASK(bits_wanted) << bitshiftcnt;
+		base_mask = RESMAP_MASK(bits_wanted);
+		mask = base_mask << bitshiftcnt;
 
 		DBG_RES("%s() o %ld %p", __FUNCTION__, o, res_ptr);
-		while(res_ptr < res_end)
+		for(; res_ptr < res_end ; res_ptr++)
 		{ 
 			DBG_RES("    %p %lx %lx\n", res_ptr, mask, *res_ptr);
 			ASSERT(0 != mask);
-			if(0 == ((*res_ptr) & mask)) {
-				*res_ptr |= mask;     /* mark resources busy! */
-				pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map);
-				pide <<= 3;	/* convert to bit address */
-				pide += bitshiftcnt;
-				break;
-			}
-			mask <<= o;
-			bitshiftcnt += o;
-			if (0 == mask) {
-				mask = RESMAP_MASK(bits_wanted);
-				bitshiftcnt=0;
-				res_ptr++;
+			for (; mask ; mask <<= o, bitshiftcnt += o) {
+				if(0 == ((*res_ptr) & mask)) {
+					*res_ptr |= mask;     /* mark resources busy! */
+					pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map);
+					pide <<= 3;	/* convert to bit address */
+					pide += bitshiftcnt;
+					ioc->res_bitshift = bitshiftcnt + bits_wanted;
+					goto found_it;
+				}
 			}
+
+			bitshiftcnt = 0;
+			mask = base_mask;
+
 		}
-		/* look in the same word on the next pass */
-		ioc->res_bitshift = bitshiftcnt + bits_wanted;
-	}
 
-	/* wrapped ? */
-	if (res_end <= res_ptr) {
-		ioc->res_hint = (unsigned long *) ioc->res_map;
-		ioc->res_bitshift = 0;
 	} else {
-		ioc->res_hint = res_ptr;
+		int qwords, bits, i;
+		unsigned long *end;
+
+		qwords = bits_wanted >> 6; /* /64 */
+		bits = bits_wanted - (qwords * BITS_PER_LONG);
+
+		end = res_end - qwords;
+
+		for (; res_ptr < end; res_ptr++) {
+			for (i = 0 ; i < qwords ; i++) {
+				if (res_ptr[i] != 0)
+					goto next_ptr;
+			}
+			if (bits && res_ptr[i] && (__ffs(res_ptr[i]) < bits))
+				continue;
+
+			/* Found it, mark it */
+			for (i = 0 ; i < qwords ; i++)
+				res_ptr[i] = ~0UL;
+			res_ptr[i] |= RESMAP_MASK(bits);
+
+			pide = ((unsigned long)res_ptr - (unsigned long)ioc->res_map);
+			pide <<= 3;	/* convert to bit address */
+			res_ptr += qwords;
+			ioc->res_bitshift = bits;
+			goto found_it;
+next_ptr:
+			;
+		}
 	}
+
+not_found:
+	prefetch(ioc->res_map);
+	ioc->res_hint = (unsigned long *) ioc->res_map;
+	ioc->res_bitshift = 0;
+	return (pide);
+
+found_it:
+	ioc->res_hint = res_ptr;
 	return (pide);
 }
 
@@ -531,26 +578,67 @@
 {
 	unsigned int pages_needed = size >> iovp_shift;
 #ifdef PDIR_SEARCH_TIMING
-	unsigned long itc_start = ia64_get_itc();
+	unsigned long itc_start;
 #endif
 	unsigned long pide;
+	unsigned long flags;
 
 	ASSERT(pages_needed);
-	ASSERT(pages_needed <= BITS_PER_LONG);
 	ASSERT(0 == (size & ~iovp_mask));
 
+	spin_lock_irqsave(&ioc->res_lock, flags);
+
+#ifdef PDIR_SEARCH_TIMING
+	itc_start = ia64_get_itc();
+#endif
 	/*
 	** "seek and ye shall find"...praying never hurts either...
 	*/
-
 	pide = sba_search_bitmap(ioc, pages_needed);
-	if (pide >= (ioc->res_size << 3)) {
+	if (unlikely(pide >= (ioc->res_size << 3))) {
 		pide = sba_search_bitmap(ioc, pages_needed);
-		if (pide >= (ioc->res_size << 3))
+		if (unlikely(pide >= (ioc->res_size << 3))) {
+#if DELAYED_RESOURCE_CNT > 0
+			/*
+			** With delayed resource freeing, we can give this one more shot.  We're
+			** getting close to being in trouble here, so do what we can to make this
+			** one count.
+			*/
+			spin_lock(&ioc->saved_lock);
+			if (ioc->saved_cnt > 0) {
+				struct sba_dma_pair *d;
+				int cnt = ioc->saved_cnt;
+
+				d = &(ioc->saved[ioc->saved_cnt]);
+
+				while (cnt--) {
+					sba_mark_invalid(ioc, d->iova, d->size);
+					sba_free_range(ioc, d->iova, d->size);
+					d--;
+				}
+				ioc->saved_cnt = 0;
+				READ_REG(ioc->ioc_hpa+IOC_PCOM);	/* flush purges */
+			}
+			spin_unlock(&ioc->saved_lock);
+
+			pide = sba_search_bitmap(ioc, pages_needed);
+			if (unlikely(pide >= (ioc->res_size << 3)))
+				panic(__FILE__ ": I/O MMU @ %p is out of mapping resources\n",
+				      ioc->ioc_hpa);
+#else
 			panic(__FILE__ ": I/O MMU @ %p is out of mapping resources\n",
 			      ioc->ioc_hpa);
+#endif
+		}
 	}
 
+#ifdef PDIR_SEARCH_TIMING
+	ioc->avg_search[ioc->avg_idx++] = (ia64_get_itc() - itc_start) / pages_needed;
+	ioc->avg_idx &= SBA_SEARCH_SAMPLE - 1;
+#endif
+
+	prefetchw(&(ioc->pdir_base[pide]));
+
 #ifdef ASSERT_PDIR_SANITY
 	/* verify the first enable bit is clear */
 	if(0x00 != ((u8 *) ioc->pdir_base)[pide*PDIR_ENTRY_SIZE + 7]) {
@@ -563,10 +651,7 @@
 		(uint) ((unsigned long) ioc->res_hint - (unsigned long) ioc->res_map),
 		ioc->res_bitshift );
 
-#ifdef PDIR_SEARCH_TIMING
-	ioc->avg_search[ioc->avg_idx++] = ia64_get_itc() - itc_start;
-	ioc->avg_idx &= SBA_SEARCH_SAMPLE - 1;
-#endif
+	spin_unlock_irqrestore(&ioc->res_lock, flags);
 
 	return (pide);
 }
@@ -587,22 +672,33 @@
 	unsigned int pide = PDIR_INDEX(iovp);
 	unsigned int ridx = pide >> 3;	/* convert bit to byte address */
 	unsigned long *res_ptr = (unsigned long *) &((ioc)->res_map[ridx & ~RESMAP_IDX_MASK]);
-
 	int bits_not_wanted = size >> iovp_shift;
+	unsigned long m;
 
-	/* 3-bits "bit" address plus 2 (or 3) bits for "byte" == bit in word */
-	unsigned long m = RESMAP_MASK(bits_not_wanted) << (pide & (BITS_PER_LONG - 1));
+	for (; bits_not_wanted > 0 ; res_ptr++) {
+		
+		if (unlikely(bits_not_wanted > BITS_PER_LONG)) {
+
+			/* these mappings start 64bit aligned */
+			*res_ptr = 0UL;
+			bits_not_wanted -= BITS_PER_LONG;
+			pide += BITS_PER_LONG;
 
-	DBG_RES("%s( ,%x,%x) %x/%lx %x %p %lx\n",
-		__FUNCTION__, (uint) iova, size,
-		bits_not_wanted, m, pide, res_ptr, *res_ptr);
-
-	ASSERT(m != 0);
-	ASSERT(bits_not_wanted);
-	ASSERT((bits_not_wanted * iovp_size) <= DMA_CHUNK_SIZE);
-	ASSERT(bits_not_wanted <= BITS_PER_LONG);
-	ASSERT((*res_ptr & m) == m); /* verify same bits are set */
-	*res_ptr &= ~m;
+		} else {
+
+			/* 3-bits "bit" address plus 2 (or 3) bits for "byte" == bit in word */
+			m = RESMAP_MASK(bits_not_wanted) << (pide & (BITS_PER_LONG - 1));
+			bits_not_wanted = 0;
+
+			DBG_RES("%s( ,%x,%x) %x/%lx %x %p %lx\n", __FUNCTION__, (uint) iova, size,
+		        	bits_not_wanted, m, pide, res_ptr, *res_ptr);
+
+			ASSERT(m != 0);
+			ASSERT(bits_not_wanted);
+			ASSERT((*res_ptr & m) == m); /* verify same bits are set */
+			*res_ptr &= ~m;
+		}
+	}
 }
 
 
@@ -612,9 +708,6 @@
 *
 ***************************************************************/
 
-#define SBA_DMA_HINT(ioc, val) ((val) << (ioc)->hint_shift_pdir)
-
-
 /**
  * sba_io_pdir_entry - fill in one IO PDIR entry
  * @pdir_ptr:  pointer to IO PDIR entry
@@ -764,32 +857,36 @@
 sba_map_single(struct device *dev, void *addr, size_t size, int dir)
 {
 	struct ioc *ioc;
-	unsigned long flags;
 	dma_addr_t iovp;
 	dma_addr_t offset;
 	u64 *pdir_start;
 	int pide;
+#ifdef ASSERT_PDIR_SANITY
+	unsigned long flags;
+#endif
 #ifdef ALLOW_IOV_BYPASS
 	unsigned long pci_addr = virt_to_phys(addr);
 #endif
 
-	ioc = GET_IOC(dev);
-	ASSERT(ioc);
-
 #ifdef ALLOW_IOV_BYPASS
+	ASSERT(to_pci_dev(dev)->dma_mask);
 	/*
  	** Check if the PCI device can DMA to ptr... if so, just return ptr
  	*/
-	if (dev && dev->dma_mask && (pci_addr & ~*dev->dma_mask) == 0) {
+	if (likely((pci_addr & ~to_pci_dev(dev)->dma_mask) == 0)) {
 		/*
  		** Device is bit capable of DMA'ing to the buffer...
 		** just return the PCI address of ptr
  		*/
 		DBG_BYPASS("sba_map_single() bypass mask/addr: 0x%lx/0x%lx\n",
-		           *dev->dma_mask, pci_addr);
+		           to_pci_dev(dev)->dma_mask, pci_addr);
 		return pci_addr;
 	}
 #endif
+	ioc = GET_IOC(dev);
+	ASSERT(ioc);
+
+	prefetch(ioc->res_hint);
 
 	ASSERT(size > 0);
 	ASSERT(size <= DMA_CHUNK_SIZE);
@@ -800,13 +897,15 @@
 	/* round up to nearest iovp_size */
 	size = (size + offset + ~iovp_mask) & iovp_mask;
 
-	spin_lock_irqsave(&ioc->res_lock, flags);
 #ifdef ASSERT_PDIR_SANITY
+	spin_lock_irqsave(&ioc->res_lock, flags);
 	if (sba_check_pdir(ioc,"Check before sba_map_single()"))
 		panic("Sanity check failed");
+	spin_unlock_irqrestore(&ioc->res_lock, flags);
 #endif
 
 	pide = sba_alloc_range(ioc, size);
+
 	iovp = (dma_addr_t) pide << iovp_shift;
 
 	DBG_RUN("%s() 0x%p -> 0x%lx\n",
@@ -829,10 +928,11 @@
 
 	/* form complete address */
 #ifdef ASSERT_PDIR_SANITY
+	spin_lock_irqsave(&ioc->res_lock, flags);
 	sba_check_pdir(ioc,"Check after sba_map_single()");
-#endif
 	spin_unlock_irqrestore(&ioc->res_lock, flags);
-	return SBA_IOVA(ioc, iovp, offset, DEFAULT_DMA_HINT_REG);
+#endif
+	return SBA_IOVA(ioc, iovp, offset);
 }
 
 /**
@@ -857,7 +957,7 @@
 	ASSERT(ioc);
 
 #ifdef ALLOW_IOV_BYPASS
-	if ((iova & ioc->imask) != ioc->ibase) {
+	if (likely((iova & ioc->imask) != ioc->ibase)) {
 		/*
 		** Address does not fall w/in IOVA, must be bypassing
 		*/
@@ -880,14 +980,15 @@
 	size += offset;
 	size = ROUNDUP(size, iovp_size);
 
-	spin_lock_irqsave(&ioc->res_lock, flags);
 
 #if DELAYED_RESOURCE_CNT > 0
+	spin_lock_irqsave(&ioc->saved_lock, flags);
 	d = &(ioc->saved[ioc->saved_cnt]);
 	d->iova = iova;
 	d->size = size;
-	if (++(ioc->saved_cnt) >= DELAYED_RESOURCE_CNT) {
+	if (unlikely(++(ioc->saved_cnt) >= DELAYED_RESOURCE_CNT)) {
 		int cnt = ioc->saved_cnt;
+		spin_lock(&ioc->res_lock);
 		while (cnt--) {
 			sba_mark_invalid(ioc, d->iova, d->size);
 			sba_free_range(ioc, d->iova, d->size);
@@ -895,11 +996,15 @@
 		}
 		ioc->saved_cnt = 0;
 		READ_REG(ioc->ioc_hpa+IOC_PCOM);	/* flush purges */
+		spin_unlock(&ioc->res_lock);
 	}
+	spin_unlock_irqrestore(&ioc->saved_lock, flags);
 #else /* DELAYED_RESOURCE_CNT == 0 */
+	spin_lock_irqsave(&ioc->res_lock, flags);
 	sba_mark_invalid(ioc, iova, size);
 	sba_free_range(ioc, iova, size);
 	READ_REG(ioc->ioc_hpa+IOC_PCOM);	/* flush purges */
+	spin_unlock_irqrestore(&ioc->res_lock, flags);
 #endif /* DELAYED_RESOURCE_CNT == 0 */
 #ifdef ENABLE_MARK_CLEAN
 	if (dir == DMA_FROM_DEVICE) {
@@ -925,16 +1030,6 @@
 		}
 	}
 #endif
-	spin_unlock_irqrestore(&ioc->res_lock, flags);
-
-	/* XXX REVISIT for 2.5 Linux - need syncdma for zero-copy support.
-	** For Astro based systems this isn't a big deal WRT performance.
-	** As long as 2.4 kernels copyin/copyout data from/to userspace,
-	** we don't need the syncdma. The issue here is I/O MMU cachelines
-	** are *not* coherent in all cases.  May be hwrev dependent.
-	** Need to investigate more.
-	asm volatile("syncdma");
-	*/
 }
 
 
@@ -953,18 +1048,33 @@
 	void *addr;
 
 	addr = (void *) __get_free_pages(flags, get_order(size));
-	if (!addr)
+	if (unlikely(!addr))
 		return NULL;
 
+	memset(addr, 0, size);
+	*dma_handle = virt_to_phys(addr);
+
+#ifdef ALLOW_IOV_BYPASS
+	ASSERT(to_pci_dev(dev)->consistent_dma_mask);
 	/*
-	 * REVISIT: if sba_map_single starts needing more than dma_mask from the
-	 * device, this needs to be updated.
+ 	** Check if the PCI device can DMA to ptr... if so, just return ptr
+ 	*/
+	if (likely((*dma_handle & ~to_pci_dev(dev)->consistent_dma_mask) == 0)) {
+		DBG_BYPASS("sba_alloc_coherent() bypass mask/addr: 0x%lx/0x%lx\n",
+		           to_pci_dev(dev)->consistent_dma_mask, *dma_handle);
+
+		return addr;
+	}
+#endif
+
+	/*
+	 * If device can't bypass or bypass is disabled, pass the 32bit fake
+	 * device to map single to get an iova mapping.
 	 */
 	ioc = GET_IOC(dev);
 	ASSERT(ioc);
 	*dma_handle = sba_map_single(&ioc->sac_only_dev->dev, addr, size, 0);
 
-	memset(addr, 0, size);
 	return addr;
 }
 
@@ -1232,8 +1342,10 @@
 {
 	struct ioc *ioc;
 	int coalesced, filled = 0;
+#ifdef ASSERT_PDIR_SANITY
 	unsigned long flags;
-#ifdef ALLOW_IOV_BYPASS
+#endif
+#ifdef ALLOW_IOV_BYPASS_SG
 	struct scatterlist *sg;
 #endif
 
@@ -1241,8 +1353,9 @@
 	ioc = GET_IOC(dev);
 	ASSERT(ioc);
 
-#ifdef ALLOW_IOV_BYPASS
-	if (dev && dev->dma_mask && (ioc->dma_mask & ~*dev->dma_mask) == 0) {
+#ifdef ALLOW_IOV_BYPASS_SG
+	ASSERT(to_pci_dev(dev)->dma_mask);
+	if (likely((ioc->dma_mask & ~to_pci_dev(dev)->dma_mask) == 0)) {
 		for (sg = sglist ; filled < nents ; filled++, sg++){
 			sg->dma_length = sg->length;
 			sg->dma_address = virt_to_phys(sba_sg_address(sg));
@@ -1253,21 +1366,22 @@
 	/* Fast path single entry scatterlists. */
 	if (nents == 1) {
 		sglist->dma_length = sglist->length;
-		sglist->dma_address = sba_map_single(dev, sba_sg_address(sglist), sglist->length,
-		                                     dir);
+		sglist->dma_address = sba_map_single(dev, sba_sg_address(sglist), sglist->length, dir);
 		return 1;
 	}
 
-	spin_lock_irqsave(&ioc->res_lock, flags);
-
 #ifdef ASSERT_PDIR_SANITY
+	spin_lock_irqsave(&ioc->res_lock, flags);
 	if (sba_check_pdir(ioc,"Check before sba_map_sg()"))
 	{
 		sba_dump_sg(ioc, sglist, nents);
 		panic("Check before sba_map_sg()");
 	}
+	spin_unlock_irqrestore(&ioc->res_lock, flags);
 #endif
 
+	prefetch(ioc->res_hint);
+
 	/*
 	** First coalesce the chunks and allocate I/O pdir space
 	**
@@ -1289,14 +1403,14 @@
 	filled = sba_fill_pdir(ioc, sglist, nents);
 
 #ifdef ASSERT_PDIR_SANITY
+	spin_lock_irqsave(&ioc->res_lock, flags);
 	if (sba_check_pdir(ioc,"Check after sba_map_sg()"))
 	{
 		sba_dump_sg(ioc, sglist, nents);
 		panic("Check after sba_map_sg()\n");
 	}
-#endif
-
 	spin_unlock_irqrestore(&ioc->res_lock, flags);
+#endif
 
 	ASSERT(coalesced == filled);
 	DBG_RUN_SG("%s() DONE %d mappings\n", __FUNCTION__, filled);
@@ -1316,18 +1430,18 @@
  */
 void sba_unmap_sg (struct device *dev, struct scatterlist *sglist, int nents, int dir)
 {
-	struct ioc *ioc;
 #ifdef ASSERT_PDIR_SANITY
+	struct ioc *ioc;
 	unsigned long flags;
 #endif
 
 	DBG_RUN_SG("%s() START %d entries,  %p,%x\n",
 		__FUNCTION__, nents, sba_sg_address(sglist), sglist->length);
 
+#ifdef ASSERT_PDIR_SANITY
 	ioc = GET_IOC(dev);
 	ASSERT(ioc);
 
-#ifdef ASSERT_PDIR_SANITY
 	spin_lock_irqsave(&ioc->res_lock, flags);
 	sba_check_pdir(ioc,"Check before sba_unmap_sg()");
 	spin_unlock_irqrestore(&ioc->res_lock, flags);
@@ -1478,6 +1592,9 @@
 ioc_resource_init(struct ioc *ioc)
 {
 	spin_lock_init(&ioc->res_lock);
+#if DELAYED_RESOURCE_CNT > 0
+	spin_lock_init(&ioc->saved_lock);
+#endif
 
 	/* resource map size dictated by pdir_size */
 	ioc->res_size = ioc->pdir_size / PDIR_ENTRY_SIZE; /* entries */
@@ -1689,13 +1806,13 @@
 
 	seq_printf(s, "Hewlett Packard %s IOC rev %d.%d\n",
 		ioc->name, ((ioc->rev >> 4) & 0xF), (ioc->rev & 0xF));
-	seq_printf(s, "IOVA size       : %d MB\n", ioc->iov_size/(1024*1024));
+	seq_printf(s, "IOVA size       : %ld MB\n", ((ioc->pdir_size >> 3) * iovp_size)/(1024*1024));
 	seq_printf(s, "IOVA page size  : %ld kb\n", iovp_size/1024);
 
 	for (i = 0; i < (ioc->res_size / sizeof(unsigned long)); ++i, ++res_ptr)
 		used += hweight64(*res_ptr);
 
-	seq_printf(s, "PDIR size       : %d entries\n", ioc->res_size << 3);
+	seq_printf(s, "PDIR size       : %d entries\n", ioc->pdir_size >> 3);
 	seq_printf(s, "PDIR used       : %d entries\n", used);
 
 #ifdef PDIR_SEARCH_TIMING
@@ -1708,7 +1825,7 @@
 			if (ioc->avg_search[i] < min) min = ioc->avg_search[i];
 		}
 		avg /= SBA_SEARCH_SAMPLE;
-		seq_printf(s, "Bitmap search   : %ld/%ld/%ld (min/avg/max CPU Cycles)\n",
+		seq_printf(s, "Bitmap search   : %ld/%ld/%ld (min/avg/max CPU Cycles/IOVA page)\n",
 		           min, avg, max);
 	}
 #endif
diff -Nru a/arch/ia64/kernel/efivars.c b/arch/ia64/kernel/efivars.c
--- a/arch/ia64/kernel/efivars.c	Wed Feb 11 22:14:31 2004
+++ b/arch/ia64/kernel/efivars.c	Wed Feb 11 22:14:31 2004
@@ -29,9 +29,12 @@
  *
  * Changelog:
  *
+ *  10 Feb 2004 - Stephane Eranian <eranian@hpl.hp.com>
+ *   Provide FPSWA version number via /proc/efi/fpswa
+ *
  *  10 Dec 2002 - Matt Domsch <Matt_Domsch@dell.com>
  *   fix locking per Peter Chubb's findings
- * 
+ *
  *  25 Mar 2002 - Matt Domsch <Matt_Domsch@dell.com>
  *   move uuid_unparse() to include/asm-ia64/efi.h:efi_guid_unparse()
  *
@@ -70,6 +73,7 @@
 #include <linux/smp.h>
 #include <linux/efi.h>
 
+#include <asm/fpswa.h>
 #include <asm/uaccess.h>
 
 MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
@@ -407,6 +411,37 @@
 	.read = efi_systab_read,
 };
 
+static ssize_t
+efi_fpswa_read (struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+	ssize_t size, length;
+	char str[32];
+	void *data;
+
+	snprintf(str, sizeof(str), "revision=%u.%u\n",
+                 fpswa_interface->revision >> 16, fpswa_interface->revision & 0xffff);
+
+	length = strlen(str);
+
+	if (*ppos >= length)
+                return 0;
+
+	data = str + file->f_pos;
+	size = length - file->f_pos;
+	if (size > count)
+		size = count;
+	if (copy_to_user(buffer, data, size))
+		return -EFAULT;
+
+	*ppos += size;
+	return size;
+}
+
+static struct proc_dir_entry *efi_fpswa_entry;
+static struct file_operations efi_fpswa_fops = {
+	.read = efi_fpswa_read,
+};
+
 static int __init
 efivars_init(void)
 {
@@ -428,6 +463,12 @@
 	efi_systab_entry = create_proc_entry("systab", S_IRUSR | S_IRGRP, efi_dir);
 	if (efi_systab_entry)
 		efi_systab_entry->proc_fops = &efi_systab_fops;
+
+        if (fpswa_interface) {
+                efi_fpswa_entry = create_proc_entry("fpswa", S_IRUGO, efi_dir);
+                if (efi_fpswa_entry)
+                        efi_fpswa_entry->proc_fops = &efi_fpswa_fops;
+        }
 
 	efi_vars_dir = proc_mkdir("vars", efi_dir);
 
diff -Nru a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
--- a/arch/ia64/kernel/mca.c	Wed Feb 11 22:14:31 2004
+++ b/arch/ia64/kernel/mca.c	Wed Feb 11 22:14:31 2004
@@ -18,7 +18,7 @@
  * Copyright (C) 2000 Intel
  * Copyright (C) Chuck Fleckenstein (cfleck@co.intel.com)
  *
- * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) 1999, 2004 Silicon Graphics, Inc.
  * Copyright (C) Vijay Chander(vijay@engr.sgi.com)
  *
  * 03/04/15 D. Mosberger Added INIT backtrace support.
@@ -40,6 +40,14 @@
  * 2003-12-08 Keith Owens <kaos@sgi.com>
  *            smp_call_function() must not be called from interrupt context (can
  *            deadlock on tasklist_lock).  Use keventd to call smp_call_function().
+ *
+ * 2004-02-01 Keith Owens <kaos@sgi.com>
+ *            Avoid deadlock when using printk() for MCA and INIT records.
+ *            Delete all record printing code, moved to salinfo_decode in user space.
+ *            Mark variables and functions static where possible.
+ *            Delete dead variables and functions.
+ *            Reorder to remove the need for forward declarations and to consolidate
+ *            related code.
  */
 #include <linux/config.h>
 #include <linux/types.h>
@@ -68,14 +76,18 @@
 #include <asm/irq.h>
 #include <asm/hw_irq.h>
 
-#undef MCA_PRT_XTRA_DATA
+#if defined(IA64_MCA_DEBUG_INFO)
+# define IA64_MCA_DEBUG(fmt...)	printk(fmt)
+#else
+# define IA64_MCA_DEBUG(fmt...)
+#endif
 
 typedef struct ia64_fptr {
 	unsigned long fp;
 	unsigned long gp;
 } ia64_fptr_t;
 
-ia64_mc_info_t			ia64_mc_info;
+/* Used by mca_asm.S */
 ia64_mca_sal_to_os_state_t	ia64_sal_to_os_handoff_state;
 ia64_mca_os_to_sal_state_t	ia64_os_to_sal_handoff_state;
 u64				ia64_mca_proc_state_dump[512];
@@ -83,56 +95,17 @@
 u64				ia64_mca_stackframe[32];
 u64				ia64_mca_bspstore[1024];
 u64				ia64_init_stack[KERNEL_STACK_SIZE/8] __attribute__((aligned(16)));
-u64				ia64_os_mca_recovery_successful;
 u64				ia64_mca_serialize;
-static void			ia64_mca_wakeup_ipi_wait(void);
-static void			ia64_mca_wakeup(int cpu);
-static void			ia64_mca_wakeup_all(void);
-static void			ia64_log_init(int);
+
+/* In mca_asm.S */
 extern void			ia64_monarch_init_handler (void);
 extern void			ia64_slave_init_handler (void);
-static u64			ia64_log_get(int sal_info_type, u8 **buffer);
-extern struct hw_interrupt_type	irq_type_iosapic_level;
-
-struct ia64_mca_tlb_info ia64_mca_tlb_list[NR_CPUS];
-
-static struct irqaction cmci_irqaction = {
-	.handler =	ia64_mca_cmc_int_handler,
-	.flags =	SA_INTERRUPT,
-	.name =		"cmc_hndlr"
-};
-
-static struct irqaction cmcp_irqaction = {
-	.handler =	ia64_mca_cmc_int_caller,
-	.flags =	SA_INTERRUPT,
-	.name =		"cmc_poll"
-};
-
-static struct irqaction mca_rdzv_irqaction = {
-	.handler =	ia64_mca_rendez_int_handler,
-	.flags =	SA_INTERRUPT,
-	.name =		"mca_rdzv"
-};
 
-static struct irqaction mca_wkup_irqaction = {
-	.handler =	ia64_mca_wakeup_int_handler,
-	.flags =	SA_INTERRUPT,
-	.name =		"mca_wkup"
-};
+static ia64_mc_info_t		ia64_mc_info;
 
-#ifdef CONFIG_ACPI
-static struct irqaction mca_cpe_irqaction = {
-	.handler =	ia64_mca_cpe_int_handler,
-	.flags =	SA_INTERRUPT,
-	.name =		"cpe_hndlr"
-};
+extern struct hw_interrupt_type	irq_type_iosapic_level;
 
-static struct irqaction mca_cpep_irqaction = {
-	.handler =	ia64_mca_cpe_int_caller,
-	.flags =	SA_INTERRUPT,
-	.name =		"cpe_poll"
-};
-#endif /* CONFIG_ACPI */
+struct ia64_mca_tlb_info ia64_mca_tlb_list[NR_CPUS];
 
 #define MAX_CPE_POLL_INTERVAL (15*60*HZ) /* 15 minutes */
 #define MIN_CPE_POLL_INTERVAL (2*60*HZ)  /* 2 minutes */
@@ -156,59 +129,152 @@
  */
 static int cpe_poll_enabled = 1;
 
-extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size);
+extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe);
+
+/*
+ * IA64_MCA log support
+ */
+#define IA64_MAX_LOGS		2	/* Double-buffering for nested MCAs */
+#define IA64_MAX_LOG_TYPES      4   /* MCA, INIT, CMC, CPE */
+
+typedef struct ia64_state_log_s
+{
+	spinlock_t	isl_lock;
+	int		isl_index;
+	unsigned long	isl_count;
+	ia64_err_rec_t  *isl_log[IA64_MAX_LOGS]; /* need space to store header + error log */
+} ia64_state_log_t;
+
+static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES];
+
+#define IA64_LOG_ALLOCATE(it, size) \
+	{ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)] = \
+		(ia64_err_rec_t *)alloc_bootmem(size); \
+	ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)] = \
+		(ia64_err_rec_t *)alloc_bootmem(size);}
+#define IA64_LOG_LOCK_INIT(it) spin_lock_init(&ia64_state_log[it].isl_lock)
+#define IA64_LOG_LOCK(it)      spin_lock_irqsave(&ia64_state_log[it].isl_lock, s)
+#define IA64_LOG_UNLOCK(it)    spin_unlock_irqrestore(&ia64_state_log[it].isl_lock,s)
+#define IA64_LOG_NEXT_INDEX(it)    ia64_state_log[it].isl_index
+#define IA64_LOG_CURR_INDEX(it)    1 - ia64_state_log[it].isl_index
+#define IA64_LOG_INDEX_INC(it) \
+    {ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index; \
+    ia64_state_log[it].isl_count++;}
+#define IA64_LOG_INDEX_DEC(it) \
+    ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index
+#define IA64_LOG_NEXT_BUFFER(it)   (void *)((ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)]))
+#define IA64_LOG_CURR_BUFFER(it)   (void *)((ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)]))
+#define IA64_LOG_COUNT(it)         ia64_state_log[it].isl_count
+
+/*
+ * ia64_log_init
+ *	Reset the OS ia64 log buffer
+ * Inputs   :   info_type   (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE})
+ * Outputs	:	None
+ */
+static void
+ia64_log_init(int sal_info_type)
+{
+	u64	max_size = 0;
+
+	IA64_LOG_NEXT_INDEX(sal_info_type) = 0;
+	IA64_LOG_LOCK_INIT(sal_info_type);
+
+	// SAL will tell us the maximum size of any error record of this type
+	max_size = ia64_sal_get_state_info_size(sal_info_type);
+	if (!max_size)
+		/* alloc_bootmem() doesn't like zero-sized allocations! */
+		return;
+
+	// set up OS data structures to hold error info
+	IA64_LOG_ALLOCATE(sal_info_type, max_size);
+	memset(IA64_LOG_CURR_BUFFER(sal_info_type), 0, max_size);
+	memset(IA64_LOG_NEXT_BUFFER(sal_info_type), 0, max_size);
+}
+
+/*
+ * ia64_log_get
+ *
+ *	Get the current MCA log from SAL and copy it into the OS log buffer.
+ *
+ *  Inputs  :   info_type   (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE})
+ *              irq_safe    whether you can use printk at this point
+ *  Outputs :   size        (total record length)
+ *              *buffer     (ptr to error record)
+ *
+ */
+static u64
+ia64_log_get(int sal_info_type, u8 **buffer, int irq_safe)
+{
+	sal_log_record_header_t     *log_buffer;
+	u64                         total_len = 0;
+	int                         s;
+
+	IA64_LOG_LOCK(sal_info_type);
+
+	/* Get the process state information */
+	log_buffer = IA64_LOG_NEXT_BUFFER(sal_info_type);
+
+	total_len = ia64_sal_get_state_info(sal_info_type, (u64 *)log_buffer);
+
+	if (total_len) {
+		IA64_LOG_INDEX_INC(sal_info_type);
+		IA64_LOG_UNLOCK(sal_info_type);
+		if (irq_safe) {
+			IA64_MCA_DEBUG("%s: SAL error record type %d retrieved. "
+				       "Record length = %ld\n", __FUNCTION__, sal_info_type, total_len);
+		}
+		*buffer = (u8 *) log_buffer;
+		return total_len;
+	} else {
+		IA64_LOG_UNLOCK(sal_info_type);
+		return 0;
+	}
+}
 
 /*
  *  ia64_mca_log_sal_error_record
  *
- *  This function retrieves a specified error record type from SAL,
- *  wakes up any processes waiting for error records, and sends it to
- *  the system log.
+ *  This function retrieves a specified error record type from SAL
+ *  and wakes up any processes waiting for error records.
  *
  *  Inputs  :   sal_info_type   (Type of error record MCA/CMC/CPE/INIT)
- *  Outputs :   platform error status
+ *  		called_from_init (1 for boot processing)
  */
-int
+static void
 ia64_mca_log_sal_error_record(int sal_info_type, int called_from_init)
 {
 	u8 *buffer;
 	u64 size;
-	int platform_err;
+	int irq_safe = sal_info_type != SAL_INFO_TYPE_MCA && sal_info_type != SAL_INFO_TYPE_INIT;
+	static const char * const rec_name[] = { "MCA", "INIT", "CMC", "CPE" };
 
-	size = ia64_log_get(sal_info_type, &buffer);
+	size = ia64_log_get(sal_info_type, &buffer, irq_safe);
 	if (!size)
-		return 0;
+		return;
 
-	/* TODO:
-	 * 1. analyze error logs to determine recoverability
-	 * 2. perform error recovery procedures, if applicable
-	 * 3. set ia64_os_mca_recovery_successful flag, if applicable
-	 */
+	salinfo_log_wakeup(sal_info_type, buffer, size, irq_safe);
+
+	if (irq_safe || called_from_init)
+		printk(KERN_INFO "CPU %d: SAL log contains %s error record\n",
+			smp_processor_id(),
+			sal_info_type < ARRAY_SIZE(rec_name) ? rec_name[sal_info_type] : "UNKNOWN");
 
-	salinfo_log_wakeup(sal_info_type, buffer, size);
-	platform_err = ia64_log_print(sal_info_type, (prfunc_t)printk);
 	/* Clear logs from corrected errors in case there's no user-level logger */
 	if (sal_info_type == SAL_INFO_TYPE_CPE || sal_info_type == SAL_INFO_TYPE_CMC)
 		ia64_sal_clear_state_info(sal_info_type);
-
-	return platform_err;
 }
 
 /*
  * platform dependent error handling
  */
 #ifndef PLATFORM_MCA_HANDLERS
-void
-mca_handler_platform (void)
-{
-
-}
 
-irqreturn_t
+static irqreturn_t
 ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs)
 {
-	IA64_MCA_DEBUG("ia64_mca_cpe_int_handler: received interrupt. CPU:%d vector = %#x\n",
-		       smp_processor_id(), cpe_irq);
+	IA64_MCA_DEBUG("%s: received interrupt. CPU:%d vector = %#x\n",
+		       __FUNCTION__, smp_processor_id(), cpe_irq);
 
 	/* SAL spec states this should run w/ interrupts enabled */
 	local_irq_enable();
@@ -356,7 +422,7 @@
 	PUT_NAT_BIT(sw->caller_unat, &pt->r30);	PUT_NAT_BIT(sw->caller_unat, &pt->r31);
 }
 
-void
+static void
 init_handler_platform (pal_min_state_area_t *ms,
 		       struct pt_regs *pt, struct switch_stack *sw)
 {
@@ -404,23 +470,6 @@
 }
 
 /*
- * ia64_mca_init_platform
- *
- *  External entry for platform specific MCA initialization.
- *
- *  Inputs
- *      None
- *
- *  Outputs
- *      None
- */
-void
-ia64_mca_init_platform (void)
-{
-
-}
-
-/*
  *  ia64_mca_check_errors
  *
  *  External entry to check for error records which may have been posted by SAL
@@ -438,6 +487,7 @@
 	/*
 	 *  If there is an MCA error record pending, get it and log it.
 	 */
+	printk(KERN_INFO "CPU %d: checking for saved MCA error records\n", smp_processor_id());
 	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA, 1);
 
 	return 0;
@@ -465,13 +515,13 @@
 
 	isrv = ia64_sal_mc_set_params(SAL_MC_PARAM_CPE_INT, SAL_MC_PARAM_MECHANISM_INT, cpev, 0, 0);
 	if (isrv.status) {
-		printk(KERN_ERR "ia64_mca_platform_init: failed to register Corrected "
-		       "Platform Error interrupt vector with SAL.\n");
+		printk(KERN_ERR "Failed to register Corrected Platform "
+		       "Error interrupt vector with SAL (status %ld)\n", isrv.status);
 		return;
 	}
 
-	IA64_MCA_DEBUG("ia64_mca_platform_init: corrected platform error "
-		       "vector %#x setup and enabled\n", cpev);
+	IA64_MCA_DEBUG("%s: corrected platform error "
+		       "vector %#x setup and enabled\n", __FUNCTION__, cpev);
 }
 #endif /* CONFIG_ACPI */
 
@@ -499,12 +549,12 @@
 	cmcv.cmcv_vector	= IA64_CMC_VECTOR;
 	ia64_setreg(_IA64_REG_CR_CMCV, cmcv.cmcv_regval);
 
-	IA64_MCA_DEBUG("ia64_mca_platform_init: CPU %d corrected "
+	IA64_MCA_DEBUG("%s: CPU %d corrected "
 		       "machine check vector %#x setup and enabled.\n",
-		       smp_processor_id(), IA64_CMC_VECTOR);
+		       __FUNCTION__, smp_processor_id(), IA64_CMC_VECTOR);
 
-	IA64_MCA_DEBUG("ia64_mca_platform_init: CPU %d CMCV = %#016lx\n",
-		       smp_processor_id(), ia64_getreg(_IA64_REG_CR_CMCV));
+	IA64_MCA_DEBUG("%s: CPU %d CMCV = %#016lx\n",
+		       __FUNCTION__, smp_processor_id(), ia64_getreg(_IA64_REG_CR_CMCV));
 }
 
 /*
@@ -519,7 +569,7 @@
  * Outputs
  *	None
  */
-void
+static void
 ia64_mca_cmc_vector_disable (void *dummy)
 {
 	cmcv_reg_t	cmcv;
@@ -529,9 +579,9 @@
 	cmcv.cmcv_mask = 1; /* Mask/disable interrupt */
 	ia64_setreg(_IA64_REG_CR_CMCV, cmcv.cmcv_regval)
 
-	IA64_MCA_DEBUG("ia64_mca_cmc_vector_disable: CPU %d corrected "
+	IA64_MCA_DEBUG("%s: CPU %d corrected "
 		       "machine check vector %#x disabled.\n",
-		       smp_processor_id(), cmcv.cmcv_vector);
+		       __FUNCTION__, smp_processor_id(), cmcv.cmcv_vector);
 }
 
 /*
@@ -546,7 +596,7 @@
  * Outputs
  *	None
  */
-void
+static void
 ia64_mca_cmc_vector_enable (void *dummy)
 {
 	cmcv_reg_t	cmcv;
@@ -556,63 +606,9 @@
 	cmcv.cmcv_mask = 0; /* Unmask/enable interrupt */
 	ia64_setreg(_IA64_REG_CR_CMCV, cmcv.cmcv_regval)
 
-	IA64_MCA_DEBUG("ia64_mca_cmc_vector_enable: CPU %d corrected "
+	IA64_MCA_DEBUG("%s: CPU %d corrected "
 		       "machine check vector %#x enabled.\n",
-		       smp_processor_id(), cmcv.cmcv_vector);
-}
-
-
-#if defined(MCA_TEST)
-
-sal_log_processor_info_t	slpi_buf;
-
-void
-mca_test(void)
-{
-	slpi_buf.valid.psi_static_struct = 1;
-	slpi_buf.valid.num_cache_check = 1;
-	slpi_buf.valid.num_tlb_check = 1;
-	slpi_buf.valid.num_bus_check = 1;
-	slpi_buf.valid.processor_static_info.minstate = 1;
-	slpi_buf.valid.processor_static_info.br = 1;
-	slpi_buf.valid.processor_static_info.cr = 1;
-	slpi_buf.valid.processor_static_info.ar = 1;
-	slpi_buf.valid.processor_static_info.rr = 1;
-	slpi_buf.valid.processor_static_info.fr = 1;
-
-	ia64_os_mca_dispatch();
-}
-
-#endif /* #if defined(MCA_TEST) */
-
-
-/*
- *  verify_guid
- *
- *  Compares a test guid to a target guid and returns result.
- *
- *  Inputs
- *      test_guid *     (ptr to guid to be verified)
- *      target_guid *   (ptr to standard guid to be verified against)
- *
- *  Outputs
- *      0               (test verifies against target)
- *      non-zero        (test guid does not verify)
- */
-static int
-verify_guid (efi_guid_t *test, efi_guid_t *target)
-{
-	int     rc;
-#ifdef IA64_MCA_DEBUG_INFO
-	char out[40];
-#endif
-
-	if ((rc = efi_guidcmp(*test, *target))) {
-		IA64_MCA_DEBUG(KERN_DEBUG
-			       "verify_guid: invalid GUID = %s\n",
-			       efi_guid_unparse(test, out));
-	}
-	return rc;
+		       __FUNCTION__, smp_processor_id(), cmcv.cmcv_vector);
 }
 
 /*
@@ -640,191 +636,6 @@
 }
 
 /*
- * ia64_mca_init
- *
- *  Do all the system level mca specific initialization.
- *
- *	1. Register spinloop and wakeup request interrupt vectors
- *
- *	2. Register OS_MCA handler entry point
- *
- *	3. Register OS_INIT handler entry point
- *
- *  4. Initialize MCA/CMC/INIT related log buffers maintained by the OS.
- *
- *  Note that this initialization is done very early before some kernel
- *  services are available.
- *
- *  Inputs  :   None
- *
- *  Outputs :   None
- */
-void __init
-ia64_mca_init(void)
-{
-	ia64_fptr_t *mon_init_ptr = (ia64_fptr_t *)ia64_monarch_init_handler;
-	ia64_fptr_t *slave_init_ptr = (ia64_fptr_t *)ia64_slave_init_handler;
-	ia64_fptr_t *mca_hldlr_ptr = (ia64_fptr_t *)ia64_os_mca_dispatch;
-	int i;
-	s64 rc;
-	struct ia64_sal_retval isrv;
-	u64 timeout = IA64_MCA_RENDEZ_TIMEOUT;	/* platform specific */
-
-	IA64_MCA_DEBUG("ia64_mca_init: begin\n");
-
-	/* initialize recovery success indicator */
-	ia64_os_mca_recovery_successful = 0;
-
-	/* Clear the Rendez checkin flag for all cpus */
-	for(i = 0 ; i < NR_CPUS; i++)
-		ia64_mc_info.imi_rendez_checkin[i] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
-
-	/*
-	 * Register the rendezvous spinloop and wakeup mechanism with SAL
-	 */
-
-	/* Register the rendezvous interrupt vector with SAL */
-	while (1) {
-		isrv = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_INT,
-					      SAL_MC_PARAM_MECHANISM_INT,
-					      IA64_MCA_RENDEZ_VECTOR,
-					      timeout,
-					      SAL_MC_PARAM_RZ_ALWAYS);
-		rc = isrv.status;
-		if (rc == 0)
-			break;
-		if (rc == -2) {
-			printk(KERN_INFO "ia64_mca_init: increasing MCA rendezvous timeout from "
-				"%ld to %ld\n", timeout, isrv.v0);
-			timeout = isrv.v0;
-			continue;
-		}
-		printk(KERN_ERR "ia64_mca_init: Failed to register rendezvous interrupt "
-		       "with SAL.  rc = %ld\n", rc);
-		return;
-	}
-
-	/* Register the wakeup interrupt vector with SAL */
-	isrv = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_WAKEUP,
-				      SAL_MC_PARAM_MECHANISM_INT,
-				      IA64_MCA_WAKEUP_VECTOR,
-				      0, 0);
-	rc = isrv.status;
-	if (rc) {
-		printk(KERN_ERR "ia64_mca_init: Failed to register wakeup interrupt with SAL.  "
-		       "rc = %ld\n", rc);
-		return;
-	}
-
-	IA64_MCA_DEBUG("ia64_mca_init: registered mca rendezvous spinloop and wakeup mech.\n");
-
-	ia64_mc_info.imi_mca_handler        = ia64_tpa(mca_hldlr_ptr->fp);
-	/*
-	 * XXX - disable SAL checksum by setting size to 0; should be
-	 *	ia64_tpa(ia64_os_mca_dispatch_end) - ia64_tpa(ia64_os_mca_dispatch);
-	 */
-	ia64_mc_info.imi_mca_handler_size	= 0;
-
-	/* Register the os mca handler with SAL */
-	if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_MCA,
-				       ia64_mc_info.imi_mca_handler,
-				       ia64_tpa(mca_hldlr_ptr->gp),
-				       ia64_mc_info.imi_mca_handler_size,
-				       0, 0, 0)))
-	{
-		printk(KERN_ERR "ia64_mca_init: Failed to register os mca handler with SAL.  "
-		       "rc = %ld\n", rc);
-		return;
-	}
-
-	IA64_MCA_DEBUG("ia64_mca_init: registered os mca handler with SAL at 0x%lx, gp = 0x%lx\n",
-		       ia64_mc_info.imi_mca_handler, ia64_tpa(mca_hldlr_ptr->gp));
-
-	/*
-	 * XXX - disable SAL checksum by setting size to 0, should be
-	 * IA64_INIT_HANDLER_SIZE
-	 */
-	ia64_mc_info.imi_monarch_init_handler		= ia64_tpa(mon_init_ptr->fp);
-	ia64_mc_info.imi_monarch_init_handler_size	= 0;
-	ia64_mc_info.imi_slave_init_handler		= ia64_tpa(slave_init_ptr->fp);
-	ia64_mc_info.imi_slave_init_handler_size	= 0;
-
-	IA64_MCA_DEBUG("ia64_mca_init: os init handler at %lx\n",
-		       ia64_mc_info.imi_monarch_init_handler);
-
-	/* Register the os init handler with SAL */
-	if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_INIT,
-				       ia64_mc_info.imi_monarch_init_handler,
-				       ia64_tpa(ia64_getreg(_IA64_REG_GP)),
-				       ia64_mc_info.imi_monarch_init_handler_size,
-				       ia64_mc_info.imi_slave_init_handler,
-				       ia64_tpa(ia64_getreg(_IA64_REG_GP)),
-				       ia64_mc_info.imi_slave_init_handler_size)))
-	{
-		printk(KERN_ERR "ia64_mca_init: Failed to register m/s init handlers with SAL. "
-		       "rc = %ld\n", rc);
-		return;
-	}
-
-	IA64_MCA_DEBUG("ia64_mca_init: registered os init handler with SAL\n");
-
-	/*
-	 *  Configure the CMCI/P vector and handler. Interrupts for CMC are
-	 *  per-processor, so AP CMC interrupts are setup in smp_callin() (smpboot.c).
-	 */
-	register_percpu_irq(IA64_CMC_VECTOR, &cmci_irqaction);
-	register_percpu_irq(IA64_CMCP_VECTOR, &cmcp_irqaction);
-	ia64_mca_cmc_vector_setup();       /* Setup vector on BSP & enable */
-
-	/* Setup the MCA rendezvous interrupt vector */
-	register_percpu_irq(IA64_MCA_RENDEZ_VECTOR, &mca_rdzv_irqaction);
-
-	/* Setup the MCA wakeup interrupt vector */
-	register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, &mca_wkup_irqaction);
-
-#ifdef CONFIG_ACPI
-	/* Setup the CPE interrupt vector */
-	{
-		irq_desc_t *desc;
-		unsigned int irq;
-		int cpev = acpi_request_vector(ACPI_INTERRUPT_CPEI);
-
-		if (cpev >= 0) {
-			for (irq = 0; irq < NR_IRQS; ++irq)
-				if (irq_to_vector(irq) == cpev) {
-					desc = irq_descp(irq);
-					desc->status |= IRQ_PER_CPU;
-					desc->handler = &irq_type_iosapic_level;
-					setup_irq(irq, &mca_cpe_irqaction);
-				}
-			ia64_mca_register_cpev(cpev);
-		}
-	}
-#endif
-
-	/* Initialize the areas set aside by the OS to buffer the
-	 * platform/processor error states for MCA/INIT/CMC
-	 * handling.
-	 */
-	ia64_log_init(SAL_INFO_TYPE_MCA);
-	ia64_log_init(SAL_INFO_TYPE_INIT);
-	ia64_log_init(SAL_INFO_TYPE_CMC);
-	ia64_log_init(SAL_INFO_TYPE_CPE);
-
-#if defined(MCA_TEST)
-	mca_test();
-#endif /* #if defined(MCA_TEST) */
-
-	printk(KERN_INFO "Mca related initialization done\n");
-
-	/* commented out because this is done elsewhere */
-#if 0
-	/* Do post-failure MCA error logging */
-	ia64_mca_check_errors();
-#endif
-}
-
-/*
  * ia64_mca_wakeup_ipi_wait
  *
  *	Wait for the inter-cpu interrupt to be sent by the
@@ -834,7 +645,7 @@
  *  Inputs  :   None
  *  Outputs :   None
  */
-void
+static void
 ia64_mca_wakeup_ipi_wait(void)
 {
 	int	irr_num = (IA64_MCA_WAKEUP_VECTOR >> 6);
@@ -868,7 +679,7 @@
  *  Inputs  :   cpuid
  *  Outputs :   None
  */
-void
+static void
 ia64_mca_wakeup(int cpu)
 {
 	platform_send_ipi(cpu, IA64_MCA_WAKEUP_VECTOR, IA64_IPI_DM_INT, 0);
@@ -884,7 +695,7 @@
  *  Inputs  :   None
  *  Outputs :   None
  */
-void
+static void
 ia64_mca_wakeup_all(void)
 {
 	int cpu;
@@ -909,7 +720,7 @@
  *  Inputs  :   None
  *  Outputs :   None
  */
-irqreturn_t
+static irqreturn_t
 ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs)
 {
 	unsigned long flags;
@@ -935,7 +746,6 @@
 	return IRQ_HANDLED;
 }
 
-
 /*
  * ia64_mca_wakeup_int_handler
  *
@@ -951,7 +761,7 @@
  *  Outputs :   None
  *
  */
-irqreturn_t
+static irqreturn_t
 ia64_mca_wakeup_int_handler(int wakeup_irq, void *arg, struct pt_regs *ptregs)
 {
 	return IRQ_HANDLED;
@@ -971,11 +781,9 @@
  *  Outputs :   None
  */
 
-void
-ia64_return_to_sal_check(void)
+static void
+ia64_return_to_sal_check(int recover)
 {
-	pal_processor_state_info_t *psp = (pal_processor_state_info_t *)
-		&ia64_sal_to_os_handoff_state.proc_state_param;
 
 	/* Copy over some relevant stuff from the sal_to_os_mca_handoff
 	 * so that it can be used at the time of os_mca_to_sal_handoff
@@ -986,15 +794,10 @@
 	ia64_os_to_sal_handoff_state.imots_sal_check_ra =
 		ia64_sal_to_os_handoff_state.imsto_sal_check_ra;
 
-	/*
-	 * Did we correct the error? At the moment the only error that
-	 * we fix is a TLB error, if any other kind of error occurred
-	 * we must reboot.
-	 */
-	if (psp->cc == 1 && psp->bc == 1 && psp->rc == 1 && psp->uc == 1)
-		ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_COLD_BOOT;
-	else
+	if (recover)
 		ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_CORRECTED;
+	else
+		ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_COLD_BOOT;
 
 	/* Default = tell SAL to return to same context */
 	ia64_os_to_sal_handoff_state.imots_context = IA64_MCA_SAME_CONTEXT;
@@ -1023,16 +826,12 @@
 void
 ia64_mca_ucmc_handler(void)
 {
-	int platform_err = 0;
+	pal_processor_state_info_t *psp = (pal_processor_state_info_t *)
+		&ia64_sal_to_os_handoff_state.proc_state_param;
+	int recover = psp->tc && !(psp->cc || psp->bc || psp->rc || psp->uc);
 
 	/* Get the MCA error record and log it */
-	platform_err = ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA, 0);
-
-	/*
-	 *  Do Platform-specific mca error handling if required.
-	 */
-	if (platform_err)
-		mca_handler_platform();
+	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA, 0);
 
 	/*
 	 *  Wakeup all the processors which are spinning in the rendezvous
@@ -1041,7 +840,7 @@
 	ia64_mca_wakeup_all();
 
 	/* Return to SAL */
-	ia64_return_to_sal_check();
+	ia64_return_to_sal_check(recover);
 }
 
 static DECLARE_WORK(cmc_disable_work, ia64_mca_cmc_vector_disable_keventd, NULL);
@@ -1062,15 +861,15 @@
  * Outputs
  *	None
  */
-irqreturn_t
+static irqreturn_t
 ia64_mca_cmc_int_handler(int cmc_irq, void *arg, struct pt_regs *ptregs)
 {
 	static unsigned long	cmc_history[CMC_HISTORY_LENGTH];
 	static int		index;
 	static spinlock_t	cmc_history_lock = SPIN_LOCK_UNLOCKED;
 
-	IA64_MCA_DEBUG("ia64_mca_cmc_int_handler: received interrupt vector = %#x on CPU %d\n",
-		       cmc_irq, smp_processor_id());
+	IA64_MCA_DEBUG("%s: received interrupt vector = %#x on CPU %d\n",
+		       __FUNCTION__, cmc_irq, smp_processor_id());
 
 	/* SAL spec states this should run w/ interrupts enabled */
 	local_irq_enable();
@@ -1100,7 +899,7 @@
 			 * make sure there's a log somewhere that indicates
 			 * something is generating more than we can handle.
 			 */
-			printk(KERN_WARNING "%s: WARNING: Switching to polling CMC handler, error records may be lost\n", __FUNCTION__);
+			printk(KERN_WARNING "WARNING: Switching to polling CMC handler; error records may be lost\n");
 
 			mod_timer(&cmc_poll_timer, jiffies + CMC_POLL_INTERVAL);
 
@@ -1117,41 +916,6 @@
 }
 
 /*
- * IA64_MCA log support
- */
-#define IA64_MAX_LOGS		2	/* Double-buffering for nested MCAs */
-#define IA64_MAX_LOG_TYPES      4   /* MCA, INIT, CMC, CPE */
-
-typedef struct ia64_state_log_s
-{
-	spinlock_t	isl_lock;
-	int		isl_index;
-	unsigned long	isl_count;
-	ia64_err_rec_t  *isl_log[IA64_MAX_LOGS]; /* need space to store header + error log */
-} ia64_state_log_t;
-
-static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES];
-
-#define IA64_LOG_ALLOCATE(it, size) \
-	{ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)] = \
-		(ia64_err_rec_t *)alloc_bootmem(size); \
-	ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)] = \
-		(ia64_err_rec_t *)alloc_bootmem(size);}
-#define IA64_LOG_LOCK_INIT(it) spin_lock_init(&ia64_state_log[it].isl_lock)
-#define IA64_LOG_LOCK(it)      spin_lock_irqsave(&ia64_state_log[it].isl_lock, s)
-#define IA64_LOG_UNLOCK(it)    spin_unlock_irqrestore(&ia64_state_log[it].isl_lock,s)
-#define IA64_LOG_NEXT_INDEX(it)    ia64_state_log[it].isl_index
-#define IA64_LOG_CURR_INDEX(it)    1 - ia64_state_log[it].isl_index
-#define IA64_LOG_INDEX_INC(it) \
-    {ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index; \
-    ia64_state_log[it].isl_count++;}
-#define IA64_LOG_INDEX_DEC(it) \
-    ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index
-#define IA64_LOG_NEXT_BUFFER(it)   (void *)((ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)]))
-#define IA64_LOG_CURR_BUFFER(it)   (void *)((ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)]))
-#define IA64_LOG_COUNT(it)         ia64_state_log[it].isl_count
-
-/*
  *  ia64_mca_cmc_int_caller
  *
  * 	Triggered by sw interrupt from CMC polling routine.  Calls
@@ -1165,7 +929,7 @@
  * Outputs
  * 	handled
  */
-irqreturn_t
+static irqreturn_t
 ia64_mca_cmc_int_caller(int cpe_irq, void *arg, struct pt_regs *ptregs)
 {
 	static int start_count = -1;
@@ -1184,10 +948,10 @@
 	if (cpuid < NR_CPUS) {
 		platform_send_ipi(cpuid, IA64_CMCP_VECTOR, IA64_IPI_DM_INT, 0);
 	} else {
-		/* If no log recored, switch out of polling mode */
+		/* If no log record, switch out of polling mode */
 		if (start_count == IA64_LOG_COUNT(SAL_INFO_TYPE_CMC)) {
 
-			printk(KERN_WARNING "%s: Returning to interrupt driven CMC handler\n", __FUNCTION__);
+			printk(KERN_WARNING "Returning to interrupt driven CMC handler\n");
 			schedule_work(&cmc_enable_work);
 			cmc_polling_enabled = 0;
 
@@ -1232,7 +996,7 @@
  * Outputs
  * 	handled
  */
-irqreturn_t
+static irqreturn_t
 ia64_mca_cpe_int_caller(int cpe_irq, void *arg, struct pt_regs *ptregs)
 {
 	static int start_count = -1;
@@ -1286,41 +1050,6 @@
 }
 
 /*
- * ia64_mca_late_init
- *
- *	Opportunity to setup things that require initialization later
- *	than ia64_mca_init.  Setup a timer to poll for CPEs if the
- *	platform doesn't support an interrupt driven mechanism.
- *
- *  Inputs  :   None
- *  Outputs :   Status
- */
-static int __init
-ia64_mca_late_init(void)
-{
-	init_timer(&cmc_poll_timer);
-	cmc_poll_timer.function = ia64_mca_cmc_poll;
-
-	/* Reset to the correct state */
-	cmc_polling_enabled = 0;
-
-	init_timer(&cpe_poll_timer);
-	cpe_poll_timer.function = ia64_mca_cpe_poll;
-
-#ifdef CONFIG_ACPI
-	/* If platform doesn't support CPEI, get the timer going. */
-	if (acpi_request_vector(ACPI_INTERRUPT_CPEI) < 0 && cpe_poll_enabled) {
-		register_percpu_irq(IA64_CPEP_VECTOR, &mca_cpep_irqaction);
-		ia64_mca_cpe_poll(0UL);
-	}
-#endif
-
-	return 0;
-}
-
-device_initcall(ia64_mca_late_init);
-
-/*
  * C portion of the OS INIT handler
  *
  * Called from ia64_monarch_init_handler
@@ -1337,6 +1066,8 @@
 {
 	pal_min_state_area_t *ms;
 
+	oops_in_progress = 1;	/* avoid deadlock in printk, but it makes recovery dodgy */
+
 	printk(KERN_INFO "Entered OS INIT handler. PSP=%lx\n",
 		ia64_sal_to_os_handoff_state.proc_state_param);
 
@@ -1350,1083 +1081,256 @@
 	init_handler_platform(ms, pt, sw);	/* call platform specific routines */
 }
 
-/*
- *  ia64_log_prt_guid
- *
- *  Print a formatted GUID.
- *
- * Inputs   :   p_guid      (ptr to the GUID)
- *              prfunc      (print function)
- * Outputs  :   None
- *
- */
-void
-ia64_log_prt_guid (efi_guid_t *p_guid, prfunc_t prfunc)
-{
-	char out[40];
-	printk(KERN_DEBUG "GUID = %s\n", efi_guid_unparse(p_guid, out));
-}
-
-static void
-ia64_log_hexdump(unsigned char *p, unsigned long n_ch, prfunc_t prfunc)
+static int __init
+ia64_mca_disable_cpe_polling(char *str)
 {
-	unsigned long i;
-	int j;
-
-	if (!p)
-		return;
-
-	for (i = 0; i < n_ch;) {
-		prfunc("%p ", (void *)p);
-		for (j = 0; (j < 16) && (i < n_ch); i++, j++, p++) {
-			prfunc("%02x ", *p);
-		}
-		prfunc("\n");
-	}
+	cpe_poll_enabled = 0;
+	return 1;
 }
 
-#ifdef MCA_PRT_XTRA_DATA    // for test only @FVL
+__setup("disable_cpe_poll", ia64_mca_disable_cpe_polling);
 
-static void
-ia64_log_prt_record_header (sal_log_record_header_t *rh, prfunc_t prfunc)
-{
-	prfunc("SAL RECORD HEADER:  Record buffer = %p,  header size = %ld\n",
-	       (void *)rh, sizeof(sal_log_record_header_t));
-	ia64_log_hexdump((unsigned char *)rh, sizeof(sal_log_record_header_t),
-			 (prfunc_t)prfunc);
-	prfunc("Total record length = %d\n", rh->len);
-	ia64_log_prt_guid(&rh->platform_guid, prfunc);
-	prfunc("End of SAL RECORD HEADER\n");
-}
+static struct irqaction cmci_irqaction = {
+	.handler =	ia64_mca_cmc_int_handler,
+	.flags =	SA_INTERRUPT,
+	.name =		"cmc_hndlr"
+};
 
-static void
-ia64_log_prt_section_header (sal_log_section_hdr_t *sh, prfunc_t prfunc)
-{
-	prfunc("SAL SECTION HEADER:  Record buffer = %p,  header size = %ld\n",
-	       (void *)sh, sizeof(sal_log_section_hdr_t));
-	ia64_log_hexdump((unsigned char *)sh, sizeof(sal_log_section_hdr_t),
-			 (prfunc_t)prfunc);
-	prfunc("Length of section & header = %d\n", sh->len);
-	ia64_log_prt_guid(&sh->guid, prfunc);
-	prfunc("End of SAL SECTION HEADER\n");
-}
-#endif  // MCA_PRT_XTRA_DATA for test only @FVL
+static struct irqaction cmcp_irqaction = {
+	.handler =	ia64_mca_cmc_int_caller,
+	.flags =	SA_INTERRUPT,
+	.name =		"cmc_poll"
+};
 
-/*
- * ia64_log_init
- *	Reset the OS ia64 log buffer
- * Inputs   :   info_type   (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE})
- * Outputs	:	None
- */
-void
-ia64_log_init(int sal_info_type)
-{
-	u64	max_size = 0;
+static struct irqaction mca_rdzv_irqaction = {
+	.handler =	ia64_mca_rendez_int_handler,
+	.flags =	SA_INTERRUPT,
+	.name =		"mca_rdzv"
+};
 
-	IA64_LOG_NEXT_INDEX(sal_info_type) = 0;
-	IA64_LOG_LOCK_INIT(sal_info_type);
+static struct irqaction mca_wkup_irqaction = {
+	.handler =	ia64_mca_wakeup_int_handler,
+	.flags =	SA_INTERRUPT,
+	.name =		"mca_wkup"
+};
 
-	// SAL will tell us the maximum size of any error record of this type
-	max_size = ia64_sal_get_state_info_size(sal_info_type);
-	if (!max_size)
-		/* alloc_bootmem() doesn't like zero-sized allocations! */
-		return;
+#ifdef CONFIG_ACPI
+static struct irqaction mca_cpe_irqaction = {
+	.handler =	ia64_mca_cpe_int_handler,
+	.flags =	SA_INTERRUPT,
+	.name =		"cpe_hndlr"
+};
 
-	// set up OS data structures to hold error info
-	IA64_LOG_ALLOCATE(sal_info_type, max_size);
-	memset(IA64_LOG_CURR_BUFFER(sal_info_type), 0, max_size);
-	memset(IA64_LOG_NEXT_BUFFER(sal_info_type), 0, max_size);
-}
+static struct irqaction mca_cpep_irqaction = {
+	.handler =	ia64_mca_cpe_int_caller,
+	.flags =	SA_INTERRUPT,
+	.name =		"cpe_poll"
+};
+#endif /* CONFIG_ACPI */
 
 /*
- * ia64_log_get
+ * ia64_mca_init
  *
- *	Get the current MCA log from SAL and copy it into the OS log buffer.
+ *  Do all the system level mca specific initialization.
  *
- *  Inputs  :   info_type   (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE})
- *  Outputs :   size        (total record length)
- *              *buffer     (ptr to error record)
+ *	1. Register spinloop and wakeup request interrupt vectors
  *
- */
-static u64
-ia64_log_get(int sal_info_type, u8 **buffer)
-{
-	sal_log_record_header_t     *log_buffer;
-	u64                         total_len = 0;
-	int                         s;
-
-	IA64_LOG_LOCK(sal_info_type);
-
-	/* Get the process state information */
-	log_buffer = IA64_LOG_NEXT_BUFFER(sal_info_type);
-
-	total_len = ia64_sal_get_state_info(sal_info_type, (u64 *)log_buffer);
-
-	if (total_len) {
-		IA64_LOG_INDEX_INC(sal_info_type);
-		IA64_LOG_UNLOCK(sal_info_type);
-		IA64_MCA_DEBUG("ia64_log_get: SAL error record type %d retrieved. "
-			       "Record length = %ld\n", sal_info_type, total_len);
-		*buffer = (u8 *) log_buffer;
-		return total_len;
-	} else {
-		IA64_LOG_UNLOCK(sal_info_type);
-		return 0;
-	}
-}
-
-/*
- *  ia64_log_prt_oem_data
+ *	2. Register OS_MCA handler entry point
  *
- *  Print OEM specific data if included.
+ *	3. Register OS_INIT handler entry point
  *
- * Inputs   :   header_len  (length passed in section header)
- *              sect_len    (default length of section type)
- *              p_data      (ptr to data)
- *			prfunc		(print function)
- * Outputs	:	None
+ *  4. Initialize MCA/CMC/INIT related log buffers maintained by the OS.
  *
- */
-void
-ia64_log_prt_oem_data (int header_len, int sect_len, u8 *p_data, prfunc_t prfunc)
-{
-	int oem_data_len, i;
-
-	if ((oem_data_len = header_len - sect_len) > 0) {
-		prfunc(" OEM Specific Data:");
-		for (i = 0; i < oem_data_len; i++, p_data++)
-			prfunc(" %02x", *p_data);
-	}
-	prfunc("\n");
-}
-
-/*
- *  ia64_log_rec_header_print
+ *  Note that this initialization is done very early before some kernel
+ *  services are available.
  *
- *  Log info from the SAL error record header.
+ *  Inputs  :   None
  *
- *  Inputs  :   lh *    (ptr to SAL log error record header)
- *              prfunc  (fn ptr of log output function to use)
  *  Outputs :   None
  */
-void
-ia64_log_rec_header_print (sal_log_record_header_t *lh, prfunc_t prfunc)
-{
-	prfunc("+Err Record ID: %ld    SAL Rev: %2x.%02x\n", lh->id,
-			lh->revision.major, lh->revision.minor);
-	prfunc("+Time: %02x/%02x/%02x%02x %02x:%02x:%02x    Severity %d\n",
-			lh->timestamp.slh_month, lh->timestamp.slh_day,
-			lh->timestamp.slh_century, lh->timestamp.slh_year,
-			lh->timestamp.slh_hour, lh->timestamp.slh_minute,
-			lh->timestamp.slh_second, lh->severity);
-}
-
-/*
- * ia64_log_processor_regs_print
- *	Print the contents of the saved processor register(s) in the format
- *		<reg_prefix>[<index>] <value>
- *
- * Inputs	:	regs		(Register save buffer)
- *			reg_num	(# of registers)
- *			reg_class	(application/banked/control/bank1_general)
- *			reg_prefix	(ar/br/cr/b1_gr)
- * Outputs	:	None
- *
- */
-void
-ia64_log_processor_regs_print(u64	*regs,
-			      int	reg_num,
-			      char	*reg_class,
-			      char	*reg_prefix,
-			      prfunc_t	prfunc)
-{
-	int i;
-
-	prfunc("+%s Registers\n", reg_class);
-	for (i = 0; i < reg_num; i++)
-		prfunc("+ %s[%d] 0x%lx\n", reg_prefix, i, regs[i]);
-}
-
-/*
- * ia64_log_processor_fp_regs_print
- *  Print the contents of the saved floating page register(s) in the format
- *      <reg_prefix>[<index>] <value>
- *
- * Inputs:  ia64_fpreg  (Register save buffer)
- *          reg_num     (# of registers)
- *          reg_class   (application/banked/control/bank1_general)
- *          reg_prefix  (ar/br/cr/b1_gr)
- * Outputs: None
- *
- */
-void
-ia64_log_processor_fp_regs_print (struct ia64_fpreg *regs,
-                                  int               reg_num,
-                                  char              *reg_class,
-                                  char              *reg_prefix,
-                                  prfunc_t          prfunc)
+void __init
+ia64_mca_init(void)
 {
+	ia64_fptr_t *mon_init_ptr = (ia64_fptr_t *)ia64_monarch_init_handler;
+	ia64_fptr_t *slave_init_ptr = (ia64_fptr_t *)ia64_slave_init_handler;
+	ia64_fptr_t *mca_hldlr_ptr = (ia64_fptr_t *)ia64_os_mca_dispatch;
 	int i;
+	s64 rc;
+	struct ia64_sal_retval isrv;
+	u64 timeout = IA64_MCA_RENDEZ_TIMEOUT;	/* platform specific */
 
-	prfunc("+%s Registers\n", reg_class);
-	for (i = 0; i < reg_num; i++)
-		prfunc("+ %s[%d] 0x%lx%016lx\n", reg_prefix, i, regs[i].u.bits[1],
-		       regs[i].u.bits[0]);
-}
-
-static char *pal_mesi_state[] = {
-	"Invalid",
-	"Shared",
-	"Exclusive",
-	"Modified",
-	"Reserved1",
-	"Reserved2",
-	"Reserved3",
-	"Reserved4"
-};
-
-static char *pal_cache_op[] = {
-	"Unknown",
-	"Move in",
-	"Cast out",
-	"Coherency check",
-	"Internal",
-	"Instruction fetch",
-	"Implicit Writeback",
-	"Reserved"
-};
-
-/*
- * ia64_log_cache_check_info_print
- *	Display the machine check information related to cache error(s).
- * Inputs:  i           (Multiple errors are logged, i - index of logged error)
- *          cc_info *   (Ptr to cache check info logged by the PAL and later
- *					 captured by the SAL)
- *          prfunc      (fn ptr of print function to be used for output)
- * Outputs: None
- */
-void
-ia64_log_cache_check_info_print (int                      i,
-                                 sal_log_mod_error_info_t *cache_check_info,
-				 prfunc_t		prfunc)
-{
-	pal_cache_check_info_t  *info;
-	u64                     target_addr;
-
-	if (!cache_check_info->valid.check_info) {
-		IA64_MCA_DEBUG("ia64_mca_log_print: invalid cache_check_info[%d]\n",i);
-		return;                 /* If check info data not valid, skip it */
-	}
-
-	info        = (pal_cache_check_info_t *)&cache_check_info->check_info;
-	target_addr = cache_check_info->target_identifier;
-
-	prfunc("+ Cache check info[%d]\n+", i);
-	prfunc("  Level: L%d,",info->level);
-	if (info->mv)
-		prfunc(" Mesi: %s,",pal_mesi_state[info->mesi]);
-	prfunc(" Index: %d,", info->index);
-	if (info->ic)
-		prfunc(" Cache: Instruction,");
-	if (info->dc)
-		prfunc(" Cache: Data,");
-	if (info->tl)
-		prfunc(" Line: Tag,");
-	if (info->dl)
-		prfunc(" Line: Data,");
-	prfunc(" Operation: %s,", pal_cache_op[info->op]);
-	if (info->wiv)
-		prfunc(" Way: %d,", info->way);
-	if (cache_check_info->valid.target_identifier)
-		/* Hope target address is saved in target_identifier */
-		if (info->tv)
-			prfunc(" Target Addr: 0x%lx,", target_addr);
-	if (info->mcc)
-		prfunc(" MC: Corrected");
-	prfunc("\n");
-}
-
-/*
- * ia64_log_tlb_check_info_print
- *	Display the machine check information related to tlb error(s).
- * Inputs:  i           (Multiple errors are logged, i - index of logged error)
- *          tlb_info *  (Ptr to machine check info logged by the PAL and later
- *					 captured by the SAL)
- *          prfunc      (fn ptr of print function to be used for output)
- * Outputs: None
- */
-void
-ia64_log_tlb_check_info_print (int                      i,
-                               sal_log_mod_error_info_t *tlb_check_info,
-                               prfunc_t                 prfunc)
-
-{
-	pal_tlb_check_info_t    *info;
-
-	if (!tlb_check_info->valid.check_info) {
-		IA64_MCA_DEBUG("ia64_mca_log_print: invalid tlb_check_info[%d]\n", i);
-		return;                 /* If check info data not valid, skip it */
-	}
-
-	info = (pal_tlb_check_info_t *)&tlb_check_info->check_info;
-
-	prfunc("+ TLB Check Info [%d]\n+", i);
-	if (info->itc)
-		prfunc("  Failure: Instruction Translation Cache");
-	if (info->dtc)
-		prfunc("  Failure: Data Translation Cache");
-	if (info->itr) {
-		prfunc("  Failure: Instruction Translation Register");
-		prfunc(" ,Slot: %ld", info->tr_slot);
-	}
-	if (info->dtr) {
-		prfunc("  Failure: Data Translation Register");
-		prfunc(" ,Slot: %ld", info->tr_slot);
-	}
-	if (info->mcc)
-		prfunc(" ,MC: Corrected");
-	prfunc("\n");
-}
-
-/*
- * ia64_log_bus_check_info_print
- *	Display the machine check information related to bus error(s).
- * Inputs:  i           (Multiple errors are logged, i - index of logged error)
- *          bus_info *  (Ptr to machine check info logged by the PAL and later
- *					 captured by the SAL)
- *          prfunc      (fn ptr of print function to be used for output)
- * Outputs: None
- */
-void
-ia64_log_bus_check_info_print (int                      i,
-                               sal_log_mod_error_info_t *bus_check_info,
-                               prfunc_t                 prfunc)
-{
-	pal_bus_check_info_t *info;
-	u64         req_addr;   /* Address of the requestor of the transaction */
-	u64         resp_addr;  /* Address of the responder of the transaction */
-	u64         targ_addr;  /* Address where the data was to be delivered to */
-	/* or obtained from */
-
-	if (!bus_check_info->valid.check_info) {
-		IA64_MCA_DEBUG("ia64_mca_log_print: invalid bus_check_info[%d]\n", i);
-		return;                 /* If check info data not valid, skip it */
-	}
-
-	info      = (pal_bus_check_info_t *)&bus_check_info->check_info;
-	req_addr  = bus_check_info->requestor_identifier;
-	resp_addr = bus_check_info->responder_identifier;
-	targ_addr = bus_check_info->target_identifier;
-
-	prfunc("+ BUS Check Info [%d]\n+", i);
-	prfunc(" Status Info: %d", info->bsi);
-	prfunc(" ,Severity: %d", info->sev);
-	prfunc(" ,Transaction Type: %d", info->type);
-	prfunc(" ,Transaction Size: %d", info->size);
-	if (info->cc)
-		prfunc(" ,Cache-cache-transfer");
-	if (info->ib)
-		prfunc(" ,Error: Internal");
-	if (info->eb)
-		prfunc(" ,Error: External");
-	if (info->mcc)
-		prfunc(" ,MC: Corrected");
-	if (info->tv)
-		prfunc(" ,Target Address: 0x%lx", targ_addr);
-	if (info->rq)
-		prfunc(" ,Requestor Address: 0x%lx", req_addr);
-	if (info->tv)
-		prfunc(" ,Responder Address: 0x%lx", resp_addr);
-	prfunc("\n");
-}
-
-/*
- *  ia64_log_mem_dev_err_info_print
- *
- *  Format and log the platform memory device error record section data.
- *
- *  Inputs:  mem_dev_err_info * (Ptr to memory device error record section
- *                               returned by SAL)
- *           prfunc             (fn ptr of print function to be used for output)
- *  Outputs: None
- */
-void
-ia64_log_mem_dev_err_info_print (sal_log_mem_dev_err_info_t *mdei,
-                                 prfunc_t                   prfunc)
-{
-	prfunc("+ Mem Error Detail: ");
-
-	if (mdei->valid.error_status)
-		prfunc(" Error Status: %#lx,", mdei->error_status);
-	if (mdei->valid.physical_addr)
-		prfunc(" Physical Address: %#lx,", mdei->physical_addr);
-	if (mdei->valid.addr_mask)
-		prfunc(" Address Mask: %#lx,", mdei->addr_mask);
-	if (mdei->valid.node)
-		prfunc(" Node: %d,", mdei->node);
-	if (mdei->valid.card)
-		prfunc(" Card: %d,", mdei->card);
-	if (mdei->valid.module)
-		prfunc(" Module: %d,", mdei->module);
-	if (mdei->valid.bank)
-		prfunc(" Bank: %d,", mdei->bank);
-	if (mdei->valid.device)
-		prfunc(" Device: %d,", mdei->device);
-	if (mdei->valid.row)
-		prfunc(" Row: %d,", mdei->row);
-	if (mdei->valid.column)
-		prfunc(" Column: %d,", mdei->column);
-	if (mdei->valid.bit_position)
-		prfunc(" Bit Position: %d,", mdei->bit_position);
-	if (mdei->valid.target_id)
-		prfunc(" ,Target Address: %#lx,", mdei->target_id);
-	if (mdei->valid.requestor_id)
-		prfunc(" ,Requestor Address: %#lx,", mdei->requestor_id);
-	if (mdei->valid.responder_id)
-		prfunc(" ,Responder Address: %#lx,", mdei->responder_id);
-	if (mdei->valid.bus_spec_data)
-		prfunc(" Bus Specific Data: %#lx,", mdei->bus_spec_data);
-	prfunc("\n");
-
-	if (mdei->valid.oem_id) {
-		u8  *p_data = &(mdei->oem_id[0]);
-		int i;
-
-		prfunc(" OEM Memory Controller ID:");
-		for (i = 0; i < 16; i++, p_data++)
-			prfunc(" %02x", *p_data);
-		prfunc("\n");
-	}
-
-	if (mdei->valid.oem_data) {
-		platform_mem_dev_err_print((int)mdei->header.len,
-				      (int)sizeof(sal_log_mem_dev_err_info_t) - 1,
-				      &(mdei->oem_data[0]), prfunc);
-	}
-}
-
-/*
- *  ia64_log_sel_dev_err_info_print
- *
- *  Format and log the platform SEL device error record section data.
- *
- *  Inputs:  sel_dev_err_info * (Ptr to the SEL device error record section
- *                               returned by SAL)
- *           prfunc             (fn ptr of print function to be used for output)
- *  Outputs: None
- */
-void
-ia64_log_sel_dev_err_info_print (sal_log_sel_dev_err_info_t *sdei,
-                                 prfunc_t                   prfunc)
-{
-	int     i;
-
-	prfunc("+ SEL Device Error Detail: ");
-
-	if (sdei->valid.record_id)
-		prfunc(" Record ID: %#x", sdei->record_id);
-	if (sdei->valid.record_type)
-		prfunc(" Record Type: %#x", sdei->record_type);
-	prfunc(" Time Stamp: ");
-	for (i = 0; i < 4; i++)
-		prfunc("%1d", sdei->timestamp[i]);
-	if (sdei->valid.generator_id)
-		prfunc(" Generator ID: %#x", sdei->generator_id);
-	if (sdei->valid.evm_rev)
-		prfunc(" Message Format Version: %#x", sdei->evm_rev);
-	if (sdei->valid.sensor_type)
-		prfunc(" Sensor Type: %#x", sdei->sensor_type);
-	if (sdei->valid.sensor_num)
-		prfunc(" Sensor Number: %#x", sdei->sensor_num);
-	if (sdei->valid.event_dir)
-		prfunc(" Event Direction Type: %#x", sdei->event_dir);
-	if (sdei->valid.event_data1)
-		prfunc(" Data1: %#x", sdei->event_data1);
-	if (sdei->valid.event_data2)
-		prfunc(" Data2: %#x", sdei->event_data2);
-	if (sdei->valid.event_data3)
-		prfunc(" Data3: %#x", sdei->event_data3);
-	prfunc("\n");
-
-}
-
-/*
- *  ia64_log_pci_bus_err_info_print
- *
- *  Format and log the platform PCI bus error record section data.
- *
- *  Inputs:  pci_bus_err_info * (Ptr to the PCI bus error record section
- *                               returned by SAL)
- *           prfunc             (fn ptr of print function to be used for output)
- *  Outputs: None
- */
-void
-ia64_log_pci_bus_err_info_print (sal_log_pci_bus_err_info_t *pbei,
-                                 prfunc_t                   prfunc)
-{
-	prfunc("+ PCI Bus Error Detail: ");
-
-	if (pbei->valid.err_status)
-		prfunc(" Error Status: %#lx", pbei->err_status);
-	if (pbei->valid.err_type)
-		prfunc(" Error Type: %#x", pbei->err_type);
-	if (pbei->valid.bus_id)
-		prfunc(" Bus ID: %#x", pbei->bus_id);
-	if (pbei->valid.bus_address)
-		prfunc(" Bus Address: %#lx", pbei->bus_address);
-	if (pbei->valid.bus_data)
-		prfunc(" Bus Data: %#lx", pbei->bus_data);
-	if (pbei->valid.bus_cmd)
-		prfunc(" Bus Command: %#lx", pbei->bus_cmd);
-	if (pbei->valid.requestor_id)
-		prfunc(" Requestor ID: %#lx", pbei->requestor_id);
-	if (pbei->valid.responder_id)
-		prfunc(" Responder ID: %#lx", pbei->responder_id);
-	if (pbei->valid.target_id)
-		prfunc(" Target ID: %#lx", pbei->target_id);
-	if (pbei->valid.oem_data)
-		prfunc("\n");
-
-	if (pbei->valid.oem_data) {
-		platform_pci_bus_err_print((int)pbei->header.len,
-				      (int)sizeof(sal_log_pci_bus_err_info_t) - 1,
-				      &(pbei->oem_data[0]), prfunc);
-	}
-}
-
-/*
- *  ia64_log_smbios_dev_err_info_print
- *
- *  Format and log the platform SMBIOS device error record section data.
- *
- *  Inputs:  smbios_dev_err_info * (Ptr to the SMBIOS device error record
- *                                  section returned by SAL)
- *           prfunc             (fn ptr of print function to be used for output)
- *  Outputs: None
- */
-void
-ia64_log_smbios_dev_err_info_print (sal_log_smbios_dev_err_info_t *sdei,
-                                    prfunc_t                      prfunc)
-{
-	u8      i;
-
-	prfunc("+ SMBIOS Device Error Detail: ");
+	IA64_MCA_DEBUG("%s: begin\n", __FUNCTION__);
 
-	if (sdei->valid.event_type)
-		prfunc(" Event Type: %#x", sdei->event_type);
-	if (sdei->valid.time_stamp) {
-		prfunc(" Time Stamp: ");
-		for (i = 0; i < 6; i++)
-			prfunc("%d", sdei->time_stamp[i]);
-	}
-	if ((sdei->valid.data) && (sdei->valid.length)) {
-		prfunc(" Data: ");
-		for (i = 0; i < sdei->length; i++)
-			prfunc(" %02x", sdei->data[i]);
-	}
-	prfunc("\n");
-}
+	/* Clear the Rendez checkin flag for all cpus */
+	for(i = 0 ; i < NR_CPUS; i++)
+		ia64_mc_info.imi_rendez_checkin[i] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
 
-/*
- *  ia64_log_pci_comp_err_info_print
- *
- *  Format and log the platform PCI component error record section data.
- *
- *  Inputs:  pci_comp_err_info * (Ptr to the PCI component error record section
- *                                returned by SAL)
- *           prfunc             (fn ptr of print function to be used for output)
- *  Outputs: None
- */
-void
-ia64_log_pci_comp_err_info_print(sal_log_pci_comp_err_info_t *pcei,
-				 prfunc_t                     prfunc)
-{
-	u32     n_mem_regs, n_io_regs;
-	u64     i, n_pci_data;
-	u64     *p_reg_data;
-	u8      *p_oem_data;
-
-	prfunc("+ PCI Component Error Detail: ");
-
-	if (pcei->valid.err_status)
-		prfunc(" Error Status: %#lx\n", pcei->err_status);
-	if (pcei->valid.comp_info)
-		prfunc(" Component Info: Vendor Id = %#x, Device Id = %#x,"
-		       " Class Code = %#x, Seg/Bus/Dev/Func = %d/%d/%d/%d\n",
-		       pcei->comp_info.vendor_id, pcei->comp_info.device_id,
-		       pcei->comp_info.class_code, pcei->comp_info.seg_num,
-		       pcei->comp_info.bus_num, pcei->comp_info.dev_num,
-		       pcei->comp_info.func_num);
-
-	n_mem_regs = (pcei->valid.num_mem_regs) ? pcei->num_mem_regs : 0;
-	n_io_regs =  (pcei->valid.num_io_regs)  ? pcei->num_io_regs  : 0;
-	p_reg_data = &(pcei->reg_data_pairs[0]);
-	p_oem_data = (u8 *)p_reg_data +
-		(n_mem_regs + n_io_regs) * 2 * sizeof(u64);
-	n_pci_data = p_oem_data - (u8 *)pcei;
-
-	if (n_pci_data > pcei->header.len) {
-		prfunc(" Invalid PCI Component Error Record format: length = %ld, "
-		       " Size PCI Data = %d, Num Mem-Map/IO-Map Regs = %ld/%ld\n",
-		       pcei->header.len, n_pci_data, n_mem_regs, n_io_regs);
-		return;
-	}
+	/*
+	 * Register the rendezvous spinloop and wakeup mechanism with SAL
+	 */
 
-	if (n_mem_regs) {
-		prfunc(" Memory Mapped Registers\n Address \tValue\n");
-		for (i = 0; i < pcei->num_mem_regs; i++) {
-			prfunc(" %#lx %#lx\n", p_reg_data[0], p_reg_data[1]);
-			p_reg_data += 2;
-		}
-	}
-	if (n_io_regs) {
-		prfunc(" I/O Mapped Registers\n Address \tValue\n");
-		for (i = 0; i < pcei->num_io_regs; i++) {
-			prfunc(" %#lx %#lx\n", p_reg_data[0], p_reg_data[1]);
-			p_reg_data += 2;
+	/* Register the rendezvous interrupt vector with SAL */
+	while (1) {
+		isrv = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_INT,
+					      SAL_MC_PARAM_MECHANISM_INT,
+					      IA64_MCA_RENDEZ_VECTOR,
+					      timeout,
+					      SAL_MC_PARAM_RZ_ALWAYS);
+		rc = isrv.status;
+		if (rc == 0)
+			break;
+		if (rc == -2) {
+			printk(KERN_INFO "Increasing MCA rendezvous timeout from "
+				"%ld to %ld milliseconds\n", timeout, isrv.v0);
+			timeout = isrv.v0;
+			continue;
 		}
+		printk(KERN_ERR "Failed to register rendezvous interrupt "
+		       "with SAL (status %ld)\n", rc);
+		return;
 	}
-	if (pcei->valid.oem_data) {
-		platform_pci_comp_err_print((int)pcei->header.len, n_pci_data,
-				      p_oem_data, prfunc);
-		prfunc("\n");
-	}
-}
-
-/*
- *  ia64_log_plat_specific_err_info_print
- *
- *  Format and log the platform specifie error record section data.
- *
- *  Inputs:  sel_dev_err_info * (Ptr to the platform specific error record
- *                               section returned by SAL)
- *           prfunc             (fn ptr of print function to be used for output)
- *  Outputs: None
- */
-void
-ia64_log_plat_specific_err_info_print (sal_log_plat_specific_err_info_t *psei,
-                                       prfunc_t                         prfunc)
-{
-	prfunc("+ Platform Specific Error Detail: ");
-
-	if (psei->valid.err_status)
-		prfunc(" Error Status: %#lx", psei->err_status);
-	if (psei->valid.guid) {
-		prfunc(" GUID: ");
-		ia64_log_prt_guid(&psei->guid, prfunc);
-	}
-	if (psei->valid.oem_data) {
-		platform_plat_specific_err_print((int) psei->header.len,
-				      (char *) psei->oem_data - (char *) psei,
-				      &psei->oem_data[0], prfunc);
-	}
-	prfunc("\n");
-}
-
-/*
- *  ia64_log_host_ctlr_err_info_print
- *
- *  Format and log the platform host controller error record section data.
- *
- *  Inputs:  host_ctlr_err_info * (Ptr to the host controller error record
- *                                 section returned by SAL)
- *           prfunc             (fn ptr of print function to be used for output)
- *  Outputs: None
- */
-void
-ia64_log_host_ctlr_err_info_print (sal_log_host_ctlr_err_info_t *hcei,
-                                   prfunc_t                     prfunc)
-{
-	prfunc("+ Host Controller Error Detail: ");
-
-	if (hcei->valid.err_status)
-		prfunc(" Error Status: %#lx", hcei->err_status);
-	if (hcei->valid.requestor_id)
-		prfunc(" Requestor ID: %#lx", hcei->requestor_id);
-	if (hcei->valid.responder_id)
-		prfunc(" Responder ID: %#lx", hcei->responder_id);
-	if (hcei->valid.target_id)
-		prfunc(" Target ID: %#lx", hcei->target_id);
-	if (hcei->valid.bus_spec_data)
-		prfunc(" Bus Specific Data: %#lx", hcei->bus_spec_data);
-	if (hcei->valid.oem_data) {
-		platform_host_ctlr_err_print((int)hcei->header.len,
-				      (int)sizeof(sal_log_host_ctlr_err_info_t) - 1,
-				      &(hcei->oem_data[0]), prfunc);
-	}
-	prfunc("\n");
-}
-
-/*
- *  ia64_log_plat_bus_err_info_print
- *
- *  Format and log the platform bus error record section data.
- *
- *  Inputs:  plat_bus_err_info * (Ptr to the platform bus error record section
- *                                returned by SAL)
- *           prfunc             (fn ptr of print function to be used for output)
- *  Outputs: None
- */
-void
-ia64_log_plat_bus_err_info_print (sal_log_plat_bus_err_info_t *pbei,
-                                  prfunc_t                    prfunc)
-{
-	prfunc("+ Platform Bus Error Detail: ");
 
-	if (pbei->valid.err_status)
-		prfunc(" Error Status: %#lx", pbei->err_status);
-	if (pbei->valid.requestor_id)
-		prfunc(" Requestor ID: %#lx", pbei->requestor_id);
-	if (pbei->valid.responder_id)
-		prfunc(" Responder ID: %#lx", pbei->responder_id);
-	if (pbei->valid.target_id)
-		prfunc(" Target ID: %#lx", pbei->target_id);
-	if (pbei->valid.bus_spec_data)
-		prfunc(" Bus Specific Data: %#lx", pbei->bus_spec_data);
-	if (pbei->valid.oem_data) {
-		platform_plat_bus_err_print((int)pbei->header.len,
-				      (int)sizeof(sal_log_plat_bus_err_info_t) - 1,
-				      &(pbei->oem_data[0]), prfunc);
+	/* Register the wakeup interrupt vector with SAL */
+	isrv = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_WAKEUP,
+				      SAL_MC_PARAM_MECHANISM_INT,
+				      IA64_MCA_WAKEUP_VECTOR,
+				      0, 0);
+	rc = isrv.status;
+	if (rc) {
+		printk(KERN_ERR "Failed to register wakeup interrupt with SAL "
+		       "(status %ld)\n", rc);
+		return;
 	}
-	prfunc("\n");
-}
 
-/*
- *  ia64_log_proc_dev_err_info_print
- *
- *  Display the processor device error record.
- *
- *  Inputs:  sal_log_processor_info_t * (Ptr to processor device error record
- *                                       section body).
- *           prfunc                     (fn ptr of print function to be used
- *                                       for output).
- *  Outputs: None
- */
-void
-ia64_log_proc_dev_err_info_print (sal_log_processor_info_t  *slpi,
-                                  prfunc_t                  prfunc)
-{
-#ifdef MCA_PRT_XTRA_DATA
-	size_t  d_len = slpi->header.len - sizeof(sal_log_section_hdr_t);
-#endif
-	sal_processor_static_info_t *spsi;
-	int                         i;
-	sal_log_mod_error_info_t    *p_data;
+	IA64_MCA_DEBUG("%s: registered MCA rendezvous spinloop and wakeup mech.\n", __FUNCTION__);
 
-	prfunc("+Processor Device Error Info Section\n");
+	ia64_mc_info.imi_mca_handler        = ia64_tpa(mca_hldlr_ptr->fp);
+	/*
+	 * XXX - disable SAL checksum by setting size to 0; should be
+	 *	ia64_tpa(ia64_os_mca_dispatch_end) - ia64_tpa(ia64_os_mca_dispatch);
+	 */
+	ia64_mc_info.imi_mca_handler_size	= 0;
 
-#ifdef MCA_PRT_XTRA_DATA    // for test only @FVL
+	/* Register the os mca handler with SAL */
+	if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_MCA,
+				       ia64_mc_info.imi_mca_handler,
+				       ia64_tpa(mca_hldlr_ptr->gp),
+				       ia64_mc_info.imi_mca_handler_size,
+				       0, 0, 0)))
 	{
-		char    *p_data = (char *)&slpi->valid;
-
-		prfunc("SAL_PROC_DEV_ERR SECTION DATA:  Data buffer = %p, "
-		       "Data size = %ld\n", (void *)p_data, d_len);
-		ia64_log_hexdump(p_data, d_len, prfunc);
-		prfunc("End of SAL_PROC_DEV_ERR SECTION DATA\n");
+		printk(KERN_ERR "Failed to register OS MCA handler with SAL "
+		       "(status %ld)\n", rc);
+		return;
 	}
-#endif  // MCA_PRT_XTRA_DATA for test only @FVL
 
-	if (slpi->valid.proc_error_map)
-		prfunc(" Processor Error Map: %#lx\n", slpi->proc_error_map);
-
-	if (slpi->valid.proc_state_param)
-		prfunc(" Processor State Param: %#lx\n", slpi->proc_state_parameter);
-
-	if (slpi->valid.proc_cr_lid)
-		prfunc(" Processor LID: %#lx\n", slpi->proc_cr_lid);
+	IA64_MCA_DEBUG("%s: registered OS MCA handler with SAL at 0x%lx, gp = 0x%lx\n", __FUNCTION__,
+		       ia64_mc_info.imi_mca_handler, ia64_tpa(mca_hldlr_ptr->gp));
 
 	/*
-	 *  Note: March 2001 SAL spec states that if the number of elements in any
-	 *  of  the MOD_ERROR_INFO_STRUCT arrays is zero, the entire array is
-	 *  absent. Also, current implementations only allocate space for number of
-	 *  elements used.  So we walk the data pointer from here on.
+	 * XXX - disable SAL checksum by setting size to 0, should be
+	 * size of the actual init handler in mca_asm.S.
 	 */
-	p_data = &slpi->info[0];
-
-	/* Print the cache check information if any*/
-	for (i = 0 ; i < slpi->valid.num_cache_check; i++, p_data++)
-		ia64_log_cache_check_info_print(i, p_data, prfunc);
-
-	/* Print the tlb check information if any*/
-	for (i = 0 ; i < slpi->valid.num_tlb_check; i++, p_data++)
-		ia64_log_tlb_check_info_print(i, p_data, prfunc);
-
-	/* Print the bus check information if any*/
-	for (i = 0 ; i < slpi->valid.num_bus_check; i++, p_data++)
-		ia64_log_bus_check_info_print(i, p_data, prfunc);
-
-	/* Print the reg file check information if any*/
-	for (i = 0 ; i < slpi->valid.num_reg_file_check; i++, p_data++)
-		ia64_log_hexdump((u8 *)p_data, sizeof(sal_log_mod_error_info_t),
-				 prfunc);    /* Just hex dump for now */
-
-	/* Print the ms check information if any*/
-	for (i = 0 ; i < slpi->valid.num_ms_check; i++, p_data++)
-		ia64_log_hexdump((u8 *)p_data, sizeof(sal_log_mod_error_info_t),
-				 prfunc);    /* Just hex dump for now */
-
-	/* Print CPUID registers if any*/
-	if (slpi->valid.cpuid_info) {
-		u64     *p = (u64 *)p_data;
+	ia64_mc_info.imi_monarch_init_handler		= ia64_tpa(mon_init_ptr->fp);
+	ia64_mc_info.imi_monarch_init_handler_size	= 0;
+	ia64_mc_info.imi_slave_init_handler		= ia64_tpa(slave_init_ptr->fp);
+	ia64_mc_info.imi_slave_init_handler_size	= 0;
 
-		prfunc(" CPUID Regs: %#lx %#lx %#lx %#lx\n", p[0], p[1], p[2], p[3]);
-		p_data++;
-	}
+	IA64_MCA_DEBUG("%s: OS INIT handler at %lx\n", __FUNCTION__,
+		       ia64_mc_info.imi_monarch_init_handler);
 
-	/* Print processor static info if any */
-	if (slpi->valid.psi_static_struct) {
-		spsi = (sal_processor_static_info_t *)p_data;
-
-		/* Print branch register contents if valid */
-		if (spsi->valid.br)
-			ia64_log_processor_regs_print(spsi->br, 8, "Branch", "br",
-						      prfunc);
-
-		/* Print control register contents if valid */
-		if (spsi->valid.cr)
-			ia64_log_processor_regs_print(spsi->cr, 128, "Control", "cr",
-						      prfunc);
-
-		/* Print application register contents if valid */
-		if (spsi->valid.ar)
-			ia64_log_processor_regs_print(spsi->ar, 128, "Application",
-						      "ar", prfunc);
-
-		/* Print region register contents if valid */
-		if (spsi->valid.rr)
-			ia64_log_processor_regs_print(spsi->rr, 8, "Region", "rr",
-						      prfunc);
-
-		/* Print floating-point register contents if valid */
-		if (spsi->valid.fr)
-			ia64_log_processor_fp_regs_print(spsi->fr, 128, "Floating-point", "fr",
-							 prfunc);
+	/* Register the os init handler with SAL */
+	if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_INIT,
+				       ia64_mc_info.imi_monarch_init_handler,
+				       ia64_tpa(ia64_getreg(_IA64_REG_GP)),
+				       ia64_mc_info.imi_monarch_init_handler_size,
+				       ia64_mc_info.imi_slave_init_handler,
+				       ia64_tpa(ia64_getreg(_IA64_REG_GP)),
+				       ia64_mc_info.imi_slave_init_handler_size)))
+	{
+		printk(KERN_ERR "Failed to register m/s INIT handlers with SAL "
+		       "(status %ld)\n", rc);
+		return;
 	}
-}
 
-/*
- * ia64_log_processor_info_print
- *
- *	Display the processor-specific information logged by PAL as a part
- *	of MCA or INIT or CMC.
- *
- *  Inputs   :  lh      (Pointer of the sal log header which specifies the
- *                       format of SAL state info as specified by the SAL spec).
- *              prfunc  (fn ptr of print function to be used for output).
- * Outputs	:	None
- */
-void
-ia64_log_processor_info_print(sal_log_record_header_t *lh, prfunc_t prfunc)
-{
-	sal_log_section_hdr_t       *slsh;
-	int                         n_sects;
-	u32                         ercd_pos;
+	IA64_MCA_DEBUG("%s: registered OS INIT handler with SAL\n", __FUNCTION__);
 
-	if (!lh)
-		return;
+	/*
+	 *  Configure the CMCI/P vector and handler. Interrupts for CMC are
+	 *  per-processor, so AP CMC interrupts are setup in smp_callin() (smpboot.c).
+	 */
+	register_percpu_irq(IA64_CMC_VECTOR, &cmci_irqaction);
+	register_percpu_irq(IA64_CMCP_VECTOR, &cmcp_irqaction);
+	ia64_mca_cmc_vector_setup();       /* Setup vector on BSP & enable */
 
-#ifdef MCA_PRT_XTRA_DATA    // for test only @FVL
-	ia64_log_prt_record_header(lh, prfunc);
-#endif  // MCA_PRT_XTRA_DATA for test only @FVL
-
-	if ((ercd_pos = sizeof(sal_log_record_header_t)) >= lh->len) {
-		IA64_MCA_DEBUG("ia64_mca_log_print: "
-			       "truncated SAL CMC error record. len = %d\n",
-			       lh->len);
-		return;
-	}
+	/* Setup the MCA rendezvous interrupt vector */
+	register_percpu_irq(IA64_MCA_RENDEZ_VECTOR, &mca_rdzv_irqaction);
 
-	/* Print record header info */
-	ia64_log_rec_header_print(lh, prfunc);
+	/* Setup the MCA wakeup interrupt vector */
+	register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, &mca_wkup_irqaction);
 
-	for (n_sects = 0; (ercd_pos < lh->len); n_sects++, ercd_pos += slsh->len) {
-		/* point to next section header */
-		slsh = (sal_log_section_hdr_t *)((char *)lh + ercd_pos);
-
-#ifdef MCA_PRT_XTRA_DATA    // for test only @FVL
-		ia64_log_prt_section_header(slsh, prfunc);
-#endif  // MCA_PRT_XTRA_DATA for test only @FVL
+#ifdef CONFIG_ACPI
+	/* Setup the CPE interrupt vector */
+	{
+		irq_desc_t *desc;
+		unsigned int irq;
+		int cpev = acpi_request_vector(ACPI_INTERRUPT_CPEI);
 
-		if (verify_guid(&slsh->guid, &(SAL_PROC_DEV_ERR_SECT_GUID))) {
-			IA64_MCA_DEBUG("ia64_mca_log_print: unsupported record section\n");
-			continue;
+		if (cpev >= 0) {
+			for (irq = 0; irq < NR_IRQS; ++irq)
+				if (irq_to_vector(irq) == cpev) {
+					desc = irq_descp(irq);
+					desc->status |= IRQ_PER_CPU;
+					desc->handler = &irq_type_iosapic_level;
+					setup_irq(irq, &mca_cpe_irqaction);
+				}
+			ia64_mca_register_cpev(cpev);
 		}
-
-		/*
-		 *  Now process processor device error record section
-		 */
-		ia64_log_proc_dev_err_info_print((sal_log_processor_info_t *)slsh, printk);
 	}
+#endif
 
-	IA64_MCA_DEBUG("ia64_mca_log_print: "
-		       "found %d sections in SAL CMC error record. len = %d\n",
-		       n_sects, lh->len);
-	if (!n_sects) {
-		prfunc("No Processor Device Error Info Section found\n");
-		return;
-	}
+	/* Initialize the areas set aside by the OS to buffer the
+	 * platform/processor error states for MCA/INIT/CMC
+	 * handling.
+	 */
+	ia64_log_init(SAL_INFO_TYPE_MCA);
+	ia64_log_init(SAL_INFO_TYPE_INIT);
+	ia64_log_init(SAL_INFO_TYPE_CMC);
+	ia64_log_init(SAL_INFO_TYPE_CPE);
+
+	printk(KERN_INFO "MCA related initialization done\n");
 }
 
 /*
- *  ia64_log_platform_info_print
+ * ia64_mca_late_init
  *
- *  Format and Log the SAL Platform Error Record.
+ *	Opportunity to setup things that require initialization later
+ *	than ia64_mca_init.  Setup a timer to poll for CPEs if the
+ *	platform doesn't support an interrupt driven mechanism.
  *
- *  Inputs  :   lh      (Pointer to the sal error record header with format
- *                       specified by the SAL spec).
- *              prfunc  (fn ptr of log output function to use)
- *  Outputs :	platform error status
+ *  Inputs  :   None
+ *  Outputs :   Status
  */
-int
-ia64_log_platform_info_print (sal_log_record_header_t *lh, prfunc_t prfunc)
+static int __init
+ia64_mca_late_init(void)
 {
-	sal_log_section_hdr_t	*slsh;
-	int			n_sects;
-	u32			ercd_pos;
-	int			platform_err = 0;
-
-	if (!lh)
-		return platform_err;
-
-#ifdef MCA_PRT_XTRA_DATA    // for test only @FVL
-	ia64_log_prt_record_header(lh, prfunc);
-#endif  // MCA_PRT_XTRA_DATA for test only @FVL
-
-	if ((ercd_pos = sizeof(sal_log_record_header_t)) >= lh->len) {
-		IA64_MCA_DEBUG("ia64_mca_log_print: "
-			       "truncated SAL error record. len = %d\n",
-			       lh->len);
-		return platform_err;
-	}
-
-	/* Print record header info */
-	ia64_log_rec_header_print(lh, prfunc);
-
-	for (n_sects = 0; (ercd_pos < lh->len); n_sects++, ercd_pos += slsh->len) {
-		/* point to next section header */
-		slsh = (sal_log_section_hdr_t *)((char *)lh + ercd_pos);
-
-#ifdef MCA_PRT_XTRA_DATA    // for test only @FVL
-		ia64_log_prt_section_header(slsh, prfunc);
-
-		if (efi_guidcmp(slsh->guid, SAL_PROC_DEV_ERR_SECT_GUID) != 0) {
-			size_t  d_len = slsh->len - sizeof(sal_log_section_hdr_t);
-			char    *p_data = (char *)&((sal_log_mem_dev_err_info_t *)slsh)->valid;
-
-			prfunc("Start of Platform Err Data Section:  Data buffer = %p, "
-			       "Data size = %ld\n", (void *)p_data, d_len);
-			ia64_log_hexdump(p_data, d_len, prfunc);
-			prfunc("End of Platform Err Data Section\n");
-		}
-#endif  // MCA_PRT_XTRA_DATA for test only @FVL
-
-		/*
-		 *  Now process CPE error record section
-		 */
-		if (efi_guidcmp(slsh->guid, SAL_PROC_DEV_ERR_SECT_GUID) == 0) {
-			ia64_log_proc_dev_err_info_print((sal_log_processor_info_t *)slsh,
-							 prfunc);
-		} else if (efi_guidcmp(slsh->guid, SAL_PLAT_MEM_DEV_ERR_SECT_GUID) == 0) {
-			platform_err = 1;
-			prfunc("+Platform Memory Device Error Info Section\n");
-			ia64_log_mem_dev_err_info_print((sal_log_mem_dev_err_info_t *)slsh,
-							prfunc);
-		} else if (efi_guidcmp(slsh->guid, SAL_PLAT_SEL_DEV_ERR_SECT_GUID) == 0) {
-			platform_err = 1;
-			prfunc("+Platform SEL Device Error Info Section\n");
-			ia64_log_sel_dev_err_info_print((sal_log_sel_dev_err_info_t *)slsh,
-							prfunc);
-		} else if (efi_guidcmp(slsh->guid, SAL_PLAT_PCI_BUS_ERR_SECT_GUID) == 0) {
-			platform_err = 1;
-			prfunc("+Platform PCI Bus Error Info Section\n");
-			ia64_log_pci_bus_err_info_print((sal_log_pci_bus_err_info_t *)slsh,
-							prfunc);
-		} else if (efi_guidcmp(slsh->guid, SAL_PLAT_SMBIOS_DEV_ERR_SECT_GUID) == 0) {
-			platform_err = 1;
-			prfunc("+Platform SMBIOS Device Error Info Section\n");
-			ia64_log_smbios_dev_err_info_print((sal_log_smbios_dev_err_info_t *)slsh,
-							   prfunc);
-		} else if (efi_guidcmp(slsh->guid, SAL_PLAT_PCI_COMP_ERR_SECT_GUID) == 0) {
-			platform_err = 1;
-			prfunc("+Platform PCI Component Error Info Section\n");
-			ia64_log_pci_comp_err_info_print((sal_log_pci_comp_err_info_t *)slsh,
-							 prfunc);
-		} else if (efi_guidcmp(slsh->guid, SAL_PLAT_SPECIFIC_ERR_SECT_GUID) == 0) {
-			platform_err = 1;
-			prfunc("+Platform Specific Error Info Section\n");
-			ia64_log_plat_specific_err_info_print((sal_log_plat_specific_err_info_t *)
-							      slsh,
-							      prfunc);
-		} else if (efi_guidcmp(slsh->guid, SAL_PLAT_HOST_CTLR_ERR_SECT_GUID) == 0) {
-			platform_err = 1;
-			prfunc("+Platform Host Controller Error Info Section\n");
-			ia64_log_host_ctlr_err_info_print((sal_log_host_ctlr_err_info_t *)slsh,
-							  prfunc);
-		} else if (efi_guidcmp(slsh->guid, SAL_PLAT_BUS_ERR_SECT_GUID) == 0) {
-			platform_err = 1;
-			prfunc("+Platform Bus Error Info Section\n");
-			ia64_log_plat_bus_err_info_print((sal_log_plat_bus_err_info_t *)slsh,
-							 prfunc);
-		} else {
-			IA64_MCA_DEBUG("ia64_mca_log_print: unsupported record section\n");
-			continue;
-		}
-	}
+	init_timer(&cmc_poll_timer);
+	cmc_poll_timer.function = ia64_mca_cmc_poll;
 
-	IA64_MCA_DEBUG("ia64_mca_log_print: found %d sections in SAL error record. len = %d\n",
-		       n_sects, lh->len);
-	if (!n_sects) {
-		prfunc("No Platform Error Info Sections found\n");
-		return platform_err;
-	}
-	return platform_err;
-}
+	/* Reset to the correct state */
+	cmc_polling_enabled = 0;
 
-/*
- * ia64_log_print
- *
- *  Displays the contents of the OS error log information
- *
- *  Inputs   :  info_type   (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE})
- *              prfunc      (fn ptr of log output function to use)
- * Outputs	:	platform error status
- */
-int
-ia64_log_print(int sal_info_type, prfunc_t prfunc)
-{
-	int platform_err = 0;
+	init_timer(&cpe_poll_timer);
+	cpe_poll_timer.function = ia64_mca_cpe_poll;
 
-	switch(sal_info_type) {
-	      case SAL_INFO_TYPE_MCA:
-		prfunc("+CPU %d: SAL log contains MCA error record\n", smp_processor_id());
-		ia64_log_rec_header_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc);
-		break;
-	      case SAL_INFO_TYPE_INIT:
-		prfunc("+CPU %d: SAL log contains INIT error record\n", smp_processor_id());
-		ia64_log_rec_header_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc);
-		break;
-	      case SAL_INFO_TYPE_CMC:
-		prfunc("+BEGIN HARDWARE ERROR STATE AT CMC\n");
-		ia64_log_processor_info_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc);
-		prfunc("+END HARDWARE ERROR STATE AT CMC\n");
-		break;
-	      case SAL_INFO_TYPE_CPE:
-		prfunc("+BEGIN HARDWARE ERROR STATE AT CPE\n");
-		ia64_log_platform_info_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc);
-		prfunc("+END HARDWARE ERROR STATE AT CPE\n");
-		break;
-	      default:
-		prfunc("+MCA UNKNOWN ERROR LOG (UNIMPLEMENTED)\n");
-		break;
+#ifdef CONFIG_ACPI
+	/* If platform doesn't support CPEI, get the timer going. */
+	if (acpi_request_vector(ACPI_INTERRUPT_CPEI) < 0 && cpe_poll_enabled) {
+		register_percpu_irq(IA64_CPEP_VECTOR, &mca_cpep_irqaction);
+		ia64_mca_cpe_poll(0UL);
 	}
-	return platform_err;
-}
+#endif
 
-static int __init
-ia64_mca_disable_cpe_polling(char *str)
-{
-	cpe_poll_enabled = 0;
-	return 1;
+	return 0;
 }
 
-__setup("disable_cpe_poll", ia64_mca_disable_cpe_polling);
+device_initcall(ia64_mca_late_init);
diff -Nru a/arch/ia64/kernel/salinfo.c b/arch/ia64/kernel/salinfo.c
--- a/arch/ia64/kernel/salinfo.c	Wed Feb 11 22:14:31 2004
+++ b/arch/ia64/kernel/salinfo.c	Wed Feb 11 22:14:31 2004
@@ -16,6 +16,9 @@
  *   Cache the record across multi-block reads from user space.
  *   Support > 64 cpus.
  *   Delete module_exit and MOD_INC/DEC_COUNT, salinfo cannot be a module.
+ *
+ * Jan 28 2004	kaos@sgi.com
+ *   Periodically check for outstanding MCA or INIT records.
  */
 
 #include <linux/types.h>
@@ -23,6 +26,7 @@
 #include <linux/module.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/timer.h>
 #include <linux/vmalloc.h>
 
 #include <asm/semaphore.h>
@@ -179,6 +183,8 @@
 /* This routine is invoked in interrupt context.  Note: mca.c enables
  * interrupts before calling this code for CMC/CPE.  MCA and INIT events are
  * not irq safe, do not call any routines that use spinlocks, they may deadlock.
+ * MCA and INIT records are recorded, a timer event will look for any
+ * outstanding events and wake up the user space code.
  *
  * The buffer passed from mca.c points to the output from ia64_log_get. This is
  * a persistent buffer but its contents can change between the interrupt and
@@ -186,12 +192,12 @@
  * changes.
  */
 void
-salinfo_log_wakeup(int type, u8 *buffer, u64 size)
+salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe)
 {
 	struct salinfo_data *data = salinfo_data + type;
 	struct salinfo_data_saved *data_saved;
 	unsigned long flags = 0;
-	int i, irqsafe = type != SAL_INFO_TYPE_MCA && type != SAL_INFO_TYPE_INIT;
+	int i;
 	int saved_size = ARRAY_SIZE(data->data_saved);
 
 	BUG_ON(type >= ARRAY_SIZE(salinfo_log_name));
@@ -224,6 +230,35 @@
 	}
 }
 
+/* Check for outstanding MCA/INIT records every 5 minutes (arbitrary) */
+#define SALINFO_TIMER_DELAY (5*60*HZ)
+static struct timer_list salinfo_timer;
+
+static void
+salinfo_timeout_check(struct salinfo_data *data)
+{
+	int i;
+	if (!data->open)
+		return;
+	for (i = 0; i < NR_CPUS; ++i) {
+		if (test_bit(i, &data->cpu_event)) {
+			/* double up() is not a problem, user space will see no
+			 * records for the additional "events".
+			 */
+			up(&data->sem);
+		}
+	}
+}
+
+static void 
+salinfo_timeout (unsigned long arg)
+{
+	salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_MCA);
+	salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_INIT);
+	salinfo_timer.expires = jiffies + SALINFO_TIMER_DELAY;
+	add_timer(&salinfo_timer);
+}
+
 static int
 salinfo_event_open(struct inode *inode, struct file *file)
 {
@@ -562,6 +597,11 @@
 	}
 
 	*sdir++ = salinfo_dir;
+
+	init_timer(&salinfo_timer);
+	salinfo_timer.expires = jiffies + SALINFO_TIMER_DELAY;
+	salinfo_timer.function = &salinfo_timeout;
+	add_timer(&salinfo_timer);
 
 	return 0;
 }
diff -Nru a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
--- a/arch/ia64/kernel/smpboot.c	Wed Feb 11 22:14:30 2004
+++ b/arch/ia64/kernel/smpboot.c	Wed Feb 11 22:14:30 2004
@@ -77,7 +77,6 @@
 extern void start_ap (void);
 extern unsigned long ia64_iobase;
 
-int cpucount;
 task_t *task_for_booting_cpu;
 
 /* Bitmask of currently online CPUs */
diff -Nru a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
--- a/arch/ia64/kernel/traps.c	Wed Feb 11 22:14:31 2004
+++ b/arch/ia64/kernel/traps.c	Wed Feb 11 22:14:31 2004
@@ -46,21 +46,14 @@
 
 extern spinlock_t timerlist_lock;
 
-static fpswa_interface_t *fpswa_interface;
+fpswa_interface_t *fpswa_interface;
 
 void __init
 trap_init (void)
 {
-	int major = 0, minor = 0;
-
-	if (ia64_boot_param->fpswa) {
+	if (ia64_boot_param->fpswa)
 		/* FPSWA fixup: make the interface pointer a kernel virtual address: */
 		fpswa_interface = __va(ia64_boot_param->fpswa);
-		major = fpswa_interface->revision >> 16;
-		minor = fpswa_interface->revision & 0xffff;
-	}
-	printk(KERN_INFO "fpswa interface at %lx (rev %d.%d)\n",
-	       ia64_boot_param->fpswa, major, minor);
 }
 
 /*
diff -Nru a/arch/ia64/kernel/unaligned.c b/arch/ia64/kernel/unaligned.c
--- a/arch/ia64/kernel/unaligned.c	Wed Feb 11 22:14:31 2004
+++ b/arch/ia64/kernel/unaligned.c	Wed Feb 11 22:14:31 2004
@@ -740,6 +740,7 @@
 emulate_load_int (unsigned long ifa, load_store_t ld, struct pt_regs *regs)
 {
 	unsigned int len = 1 << ld.x6_sz;
+	unsigned long val = 0;
 
 	/*
 	 * r0, as target, doesn't need to be checked because Illegal Instruction
@@ -750,21 +751,18 @@
 	 */
 
 	/*
-	 * ldX.a we don't try to emulate anything but we must invalidate the ALAT entry.
+	 * ldX.a we will emulate load and also invalidate the ALAT entry.
 	 * See comment below for explanation on how we handle ldX.a
 	 */
-	if (ld.x6_op != 0x2) {
-		unsigned long val = 0;
 
-		if (len != 2 && len != 4 && len != 8) {
-			DPRINT("unknown size: x6=%d\n", ld.x6_sz);
-			return -1;
-		}
-		/* this assumes little-endian byte-order: */
-		if (copy_from_user(&val, (void *) ifa, len))
-		    return -1;
-		setreg(ld.r1, val, 0, regs);
+	if (len != 2 && len != 4 && len != 8) {
+		DPRINT("unknown size: x6=%d\n", ld.x6_sz);
+		return -1;
 	}
+	/* this assumes little-endian byte-order: */
+	if (copy_from_user(&val, (void *) ifa, len))
+		return -1;
+	setreg(ld.r1, val, 0, regs);
 
 	/*
 	 * check for updates on any kind of loads
@@ -817,7 +815,7 @@
 	 *		store & shift to temporary;
 	 *		r1=temporary
 	 *
-	 *	  So int this case, you would get the right value is r1 but the wrong info in
+	 *	  So in this case, you would get the right value is r1 but the wrong info in
 	 *	  the ALAT.  Notice that you could do it in reverse to finish with address 3
 	 *	  but you would still get the size wrong.  To get the size right, one needs to
 	 *	  execute exactly the same kind of load. You could do it from a aligned
@@ -826,9 +824,12 @@
 	 *	  So no matter what, it is not possible to emulate an advanced load
 	 *	  correctly. But is that really critical ?
 	 *
+	 *	  We will always convert ld.a into a normal load with ALAT invalidated.  This
+	 *	  will enable compiler to do optimization where certain code path after ld.a
+	 *	  is not required to have ld.c/chk.a, e.g., code path with no intervening stores.
 	 *
-	 *	  Now one has to look at how ld.a is used, one must either do a ld.c.* or
-	 *	  chck.a.* to reuse the value stored in the ALAT. Both can "fail" (meaning no
+	 *	  If there is a store after the advanced load, one must either do a ld.c.* or
+	 *	  chk.a.* to reuse the value stored in the ALAT. Both can "fail" (meaning no
 	 *	  entry found in ALAT), and that's perfectly ok because:
 	 *
 	 *		- ld.c.*, if the entry is not present a  normal load is executed
@@ -836,19 +837,8 @@
 	 *
 	 *	  In either case, the load can be potentially retried in another form.
 	 *
-	 *	  So it's okay NOT to do any actual load on an unaligned ld.a. However the ALAT
-	 *	  must be invalidated for the register (so that's chck.a.*,ld.c.* don't pick up
-	 *	  a stale entry later) The register base update MUST also be performed.
-	 *
-	 *	  Now what is the content of the register and its NaT bit in the case we don't
-	 *	  do the load ?  EAS2.4, says (in case an actual load is needed)
-	 *
-	 *		- r1 = [r3], Nat = 0 if succeeds
-	 *		- r1 = 0 Nat = 0 if trying to access non-speculative memory
-	 *
-	 *	  For us, there is nothing to do, because both ld.c.* and chk.a.* are going to
-	 *	  retry and thus eventually reload the register thereby changing Nat and
-	 *	  register content.
+	 *	  ALAT must be invalidated for the register (so that chk.a or ld.c don't pick
+	 *	  up a stale entry later). The register base update MUST also be performed.
 	 */
 
 	/*
diff -Nru a/arch/ia64/lib/io.c b/arch/ia64/lib/io.c
--- a/arch/ia64/lib/io.c	Wed Feb 11 22:14:30 2004
+++ b/arch/ia64/lib/io.c	Wed Feb 11 22:14:30 2004
@@ -9,13 +9,13 @@
  * This needs to be optimized.
  */
 void
-__ia64_memcpy_fromio (void * to, unsigned long from, long count)
+__ia64_memcpy_fromio (void *to, unsigned long from, long count)
 {
+	char *dst = to;
+
 	while (count) {
 		count--;
-		*(char *) to = readb(from);
-		((char *) to)++;
-		from++;
+		*dst++ = readb(from++);
 	}
 }
 EXPORT_SYMBOL(__ia64_memcpy_fromio);
@@ -25,13 +25,13 @@
  * This needs to be optimized.
  */
 void
-__ia64_memcpy_toio (unsigned long to, void * from, long count)
+__ia64_memcpy_toio (unsigned long to, void *from, long count)
 {
+	char *src = from;
+
 	while (count) {
 		count--;
-		writeb(*(char *) from, to);
-		((char *) from)++;
-		to++;
+		writeb(*src++, to++);
 	}
 }
 EXPORT_SYMBOL(__ia64_memcpy_toio);
diff -Nru a/arch/ia64/sn/kernel/mca.c b/arch/ia64/sn/kernel/mca.c
--- a/arch/ia64/sn/kernel/mca.c	Wed Feb 11 22:14:30 2004
+++ b/arch/ia64/sn/kernel/mca.c	Wed Feb 11 22:14:30 2004
@@ -68,20 +68,6 @@
 }
 
 
-
-/*
- * ia64_sn2_platform_plat_specific_err_print
- *
- * Called by the MCA handler to log platform-specific errors.
- */
-void
-ia64_sn2_platform_plat_specific_err_print(int header_len, int sect_len, u8 *p_data, prfunc_t prfunc)
-{
-	ia64_sn_plat_specific_err_print(print_hook, p_data - sect_len);
-}
-
-
-
 static void
 sn_cpei_handler(int irq, void *devid, struct pt_regs *regs)
 {
diff -Nru a/arch/ia64/sn/kernel/sn2/sn2_smp.c b/arch/ia64/sn/kernel/sn2/sn2_smp.c
--- a/arch/ia64/sn/kernel/sn2/sn2_smp.c	Wed Feb 11 22:14:31 2004
+++ b/arch/ia64/sn/kernel/sn2/sn2_smp.c	Wed Feb 11 22:14:31 2004
@@ -5,7 +5,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved.
  */
 
 #include <linux/init.h>
@@ -27,6 +27,8 @@
 #include <asm/delay.h>
 #include <asm/io.h>
 #include <asm/smp.h>
+#include <asm/numa.h>
+#include <asm/bitops.h>
 #include <asm/hw_irq.h>
 #include <asm/current.h>
 #include <asm/sn/sn_cpuid.h>
@@ -67,14 +69,56 @@
  *
  * Purges the translation caches of all processors of the given virtual address
  * range.
+ *
+ * Note:
+ * 	- cpu_vm_mask is a bit mask that indicates which cpus have loaded the context.
+ * 	- cpu_vm_mask is converted into a nodemask of the nodes containing the
+ * 	  cpus in cpu_vm_mask.
+ *	- if only one bit is set in cpu_vm_mask & it is the current cpu,
+ *	  then only the local TLB needs to be flushed. This flushing can be done
+ *	  using ptc.l. This is the common case & avoids the global spinlock.
+ *	- if multiple cpus have loaded the context, then flushing has to be
+ *	  done with ptc.g/MMRs under protection of the global ptc_lock.
  */
 
 void
 sn2_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbits)
 {
-	int			cnode, mycnode, nasid, flushed=0;
+	int			i, cnode, mynasid, cpu, lcpu=0, nasid, flushed=0;
 	volatile unsigned	long	*ptc0, *ptc1;
 	unsigned long		flags=0, data0, data1;
+	struct mm_struct	*mm=current->active_mm;
+	short			nasids[NR_NODES], nix;
+	DECLARE_BITMAP(nodes_flushed, NR_NODES);
+
+	CLEAR_BITMAP(nodes_flushed, NR_NODES);
+
+	i = 0;
+
+	for_each_cpu_mask(cpu, mm->cpu_vm_mask) {
+		cnode = cpu_to_node(cpu);
+		__set_bit(cnode, nodes_flushed);
+		lcpu = cpu;
+		i++;
+	}
+
+	preempt_disable();
+
+	if (likely(i == 1 && lcpu == smp_processor_id())) {
+		do {
+			ia64_ptcl(start, nbits<<2);
+			start += (1UL << nbits);
+		} while (start < end);
+		ia64_srlz_i();
+		preempt_enable();
+		return;
+	}
+
+	nix = 0;
+	for (cnode=find_first_bit(&nodes_flushed, NR_NODES); cnode < NR_NODES; 
+			cnode=find_next_bit(&nodes_flushed, NR_NODES, ++cnode))
+		nasids[nix++] = cnodeid_to_nasid(cnode);
+
 
 	data0 = (1UL<<SH_PTC_0_A_SHFT) |
 		(nbits<<SH_PTC_0_PS_SHFT) |
@@ -84,20 +128,19 @@
 	ptc0 = (long*)GLOBAL_MMR_PHYS_ADDR(0, SH_PTC_0);
 	ptc1 = (long*)GLOBAL_MMR_PHYS_ADDR(0, SH_PTC_1);
 
-	mycnode = numa_node_id();
+
+	mynasid = smp_physical_node_id();
 
 	spin_lock_irqsave(&sn2_global_ptc_lock, flags);
 
 	do {
 		data1 = start | (1UL<<SH_PTC_1_START_SHFT);
-		for (cnode = 0; cnode < numnodes; cnode++) {
-			if (is_headless_node(cnode))
-				continue;
-			if (cnode == mycnode) {
+		for (i=0; i<nix; i++) {
+			nasid = nasids[i];
+			if (likely(nasid == mynasid)) {
 				ia64_ptcga(start, nbits<<2);
 				ia64_srlz_i();
 			} else {
-				nasid = cnodeid_to_nasid(cnode);
 				ptc0 = CHANGE_NASID(nasid, ptc0);
 				ptc1 = CHANGE_NASID(nasid, ptc1);
 				pio_atomic_phys_write_mmrs(ptc0, data0, ptc1, data1);
@@ -115,6 +158,7 @@
 
 	spin_unlock_irqrestore(&sn2_global_ptc_lock, flags);
 
+	preempt_enable();
 }
 
 /*
diff -Nru a/arch/m68k/Kconfig b/arch/m68k/Kconfig
--- a/arch/m68k/Kconfig	Wed Feb 11 22:14:31 2004
+++ b/arch/m68k/Kconfig	Wed Feb 11 22:14:31 2004
@@ -1012,50 +1012,7 @@
 config USERIAL
 	bool "Support for user serial device modules"
 
-config WATCHDOG
-	bool "Watchdog Timer Support"
-	---help---
-	  If you say Y here (and to one of the following options) and create a
-	  character special file /dev/watchdog with major number 10 and minor
-	  number 130 using mknod ("man mknod"), you will get a watchdog, i.e.:
-	  subsequently opening the file and then failing to write to it for
-	  longer than 1 minute will result in rebooting the machine. This
-	  could be useful for a networked machine that needs to come back
-	  online as fast as possible after a lock-up. There's both a watchdog
-	  implementation entirely in software (which can sometimes fail to
-	  reboot the machine) and a driver for hardware watchdog boards, which
-	  are more robust and can also keep track of the temperature inside
-	  your computer. For details, read <file:Documentation/watchdog/watchdog.txt>
-	  in the kernel source.
-
-	  The watchdog is usually used together with the watchdog daemon
-	  which is available from
-	  <ftp://ibiblio.org/pub/Linux/system/daemons/watchdog/>. This daemon can
-	  also monitor NFS connections and can reboot the machine when the process
-	  table is full.
-
-	  If unsure, say N.
-
-config WATCHDOG_NOWAYOUT
-	bool "Disable watchdog shutdown on close"
-	depends on WATCHDOG
-	help
-	  The default watchdog behaviour (which you get if you say N here) is
-	  to stop the timer if the process managing it closes the file
-	  /dev/watchdog. It's always remotely possible that this process might
-	  get killed. If you say Y here, the watchdog cannot be stopped once
-	  it has been started.
-
-config SOFT_WATCHDOG
-	bool "Software watchdog"
-	depends on WATCHDOG
-	help
-	  A software monitoring watchdog. This will fail to reboot your system
-	  from some situations that the hardware watchdog will recover
-	  from. Equally it's a lot cheaper to install.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called softdog.
+source "drivers/char/watchdog/Kconfig"
 
 config GEN_RTC
 	tristate "Generic /dev/rtc emulation" if !SUN3
diff -Nru a/arch/ppc/Kconfig b/arch/ppc/Kconfig
--- a/arch/ppc/Kconfig	Wed Feb 11 22:14:31 2004
+++ b/arch/ppc/Kconfig	Wed Feb 11 22:14:31 2004
@@ -592,6 +592,11 @@
 	depends on PPC_MULTIPLATFORM
 	default y
 
+config PPC_PMAC64
+	bool
+	depends on PPC_PMAC && POWER4
+	default y
+
 config PPC_PREP
 	bool
 	depends on PPC_MULTIPLATFORM
diff -Nru a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
--- a/arch/ppc/kernel/pci.c	Wed Feb 11 22:14:31 2004
+++ b/arch/ppc/kernel/pci.c	Wed Feb 11 22:14:31 2004
@@ -1022,7 +1022,30 @@
 		prom_add_property(find_path_device("/"), of_prop);
 	}
 }
+
+static ssize_t pci_show_devspec(struct device *dev, char *buf)
+{
+	struct pci_dev *pdev;
+	struct device_node *np;
+
+	pdev = to_pci_dev (dev);
+	np = pci_device_to_OF_node(pdev);
+	if (np == NULL || np->full_name == NULL)
+		return 0;
+	return sprintf(buf, "%s", np->full_name);
+}
+static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL);
+
 #endif /* CONFIG_PPC_OF */
+
+/* Add sysfs properties */
+void pcibios_add_platform_entries(struct pci_dev *dev)
+{
+#ifdef CONFIG_PPC_OF
+	device_create_file(&pdev->dev, &dev_attr_devspec);
+#endif /* CONFIG_PPC_OF */
+}
+
 
 #ifdef CONFIG_PPC_PMAC
 /*
diff -Nru a/arch/ppc/platforms/pmac_feature.c b/arch/ppc/platforms/pmac_feature.c
--- a/arch/ppc/platforms/pmac_feature.c	Wed Feb 11 22:14:31 2004
+++ b/arch/ppc/platforms/pmac_feature.c	Wed Feb 11 22:14:31 2004
@@ -2239,7 +2239,7 @@
 	    	break;
 #else /* CONFIG_POWER4 */
 	    case macio_keylargo2:
-		pmac_mb.model_id = PMAC_TYPE_POWERMAC_G5;
+		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_K2;
 		pmac_mb.model_name = "Unknown G5";
 	    	pmac_mb.features = g5_features;
 	    	break;
diff -Nru a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig
--- a/arch/ppc64/Kconfig	Wed Feb 11 22:14:31 2004
+++ b/arch/ppc64/Kconfig	Wed Feb 11 22:14:31 2004
@@ -60,7 +60,7 @@
 	bool "iSeries"
 
 config PPC_PSERIES
-	bool "pSeries"
+	bool "pSeries / PowerMac G5"
 
 endchoice
 
@@ -72,12 +72,33 @@
 	bool
 	default y
 
+config PPC_OF
+	depends on PPC_PSERIES
+	bool
+	default y
+
 # VMX is pSeries only for now until somebody writes the iSeries
 # exception vectors for it
 config ALTIVEC
 	bool "Support for VMX (Altivec) vector unit"
 	depends on PPC_PSERIES
 	default y
+
+config PPC_PMAC
+	depends on PPC_PSERIES
+	bool "Apple PowerMac G5 support"
+
+config PPC_PMAC64
+	bool
+	depends on PPC_PMAC
+	default y
+
+config BOOTX_TEXT
+	bool "Support for early boot text console"
+	depends PPC_OF
+	help
+	  Say Y here to see progress messages from the boot firmware in text
+	  mode. Requires an Open Firmware compatible video card.
 
 config POWER4_ONLY
 	bool "Optimize for POWER4"
diff -Nru a/arch/ppc64/configs/g5_defconfig b/arch/ppc64/configs/g5_defconfig
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc64/configs/g5_defconfig	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,1078 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_64BIT=y
+CONFIG_MMU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_COMPAT=y
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCE_MAX_ZONEORDER=13
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# Platform support
+#
+# CONFIG_PPC_ISERIES is not set
+CONFIG_PPC_PSERIES=y
+CONFIG_PPC=y
+CONFIG_PPC64=y
+CONFIG_PPC_OF=y
+CONFIG_ALTIVEC=y
+CONFIG_PPC_PMAC=y
+CONFIG_PPC_PMAC64=y
+CONFIG_BOOTX_TEXT=y
+CONFIG_POWER4_ONLY=y
+CONFIG_SMP=y
+CONFIG_IRQ_ALL_CPUS=y
+CONFIG_NR_CPUS=2
+# CONFIG_HMT is not set
+CONFIG_DISCONTIGMEM=y
+# CONFIG_NUMA is not set
+# CONFIG_PPC_RTAS is not set
+# CONFIG_LPARCFG is not set
+
+#
+# General setup
+#
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+# CONFIG_PCMCIA is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_FW_LOADER=y
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_IDETAPE=y
+CONFIG_BLK_DEV_IDEFLOPPY=y
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_GENERIC is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_SL82C105 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+CONFIG_BLK_DEV_ADMA=y
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+CONFIG_BLK_DEV_IDE_PMAC=y
+CONFIG_BLK_DEV_IDE_PMAC_ATA100FIRST=y
+CONFIG_BLK_DEV_IDEDMA_PMAC=y
+# CONFIG_BLK_DEV_IDE_PMAC_BLINK is not set
+CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO=y
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_REPORT_LUNS=y
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_MEGARAID is not set
+CONFIG_SCSI_SATA=y
+CONFIG_SCSI_SATA_SVW=y
+# CONFIG_SCSI_ATA_PIIX is not set
+# CONFIG_SCSI_SATA_PROMISE is not set
+# CONFIG_SCSI_SATA_VIA is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CPQFCTS is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INIA100 is not set
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+CONFIG_SCSI_QLA2XXX=y
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# CONFIG_SCSI_QLA2300 is not set
+# CONFIG_SCSI_QLA2322 is not set
+# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_QLA6322 is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_MESH is not set
+# CONFIG_SCSI_MAC53C94 is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_LINEAR=y
+CONFIG_MD_RAID0=y
+CONFIG_MD_RAID1=y
+CONFIG_MD_RAID5=y
+# CONFIG_MD_RAID6 is not set
+# CONFIG_MD_MULTIPATH is not set
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_IOCTL_V4=y
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+CONFIG_IEEE1394=m
+
+#
+# Subsystem Options
+#
+# CONFIG_IEEE1394_VERBOSEDEBUG is not set
+CONFIG_IEEE1394_OUI_DB=y
+
+#
+# Device Drivers
+#
+# CONFIG_IEEE1394_PCILYNX is not set
+CONFIG_IEEE1394_OHCI1394=m
+
+#
+# Protocol Drivers
+#
+CONFIG_IEEE1394_VIDEO1394=m
+CONFIG_IEEE1394_SBP2=m
+# CONFIG_IEEE1394_SBP2_PHYS_DMA is not set
+CONFIG_IEEE1394_ETH1394=m
+CONFIG_IEEE1394_DV1394=m
+CONFIG_IEEE1394_RAWIO=m
+# CONFIG_IEEE1394_CMP is not set
+
+#
+# I2O device support
+#
+
+#
+# Macintosh device drivers
+#
+CONFIG_ADB_PMU=y
+# CONFIG_PMAC_PBOOK is not set
+# CONFIG_PMAC_BACKLIGHT is not set
+# CONFIG_MAC_SERIAL is not set
+CONFIG_ADB=y
+# CONFIG_INPUT_ADBHID is not set
+CONFIG_THERM_PM72=y
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=y
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_INET_ECN=y
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+# CONFIG_IPV6 is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NETFILTER is not set
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IPV6_SCTP__=y
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+CONFIG_LLC=y
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_MACE is not set
+# CONFIG_BMAC is not set
+# CONFIG_OAKNET is not set
+# CONFIG_HAPPYMEAL is not set
+CONFIG_SUNGEM=y
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_PCI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+CONFIG_ACENIC=y
+CONFIG_ACENIC_OMIT_TIGON_I=y
+# CONFIG_DL2K is not set
+CONFIG_E1000=y
+# CONFIG_E1000_NAPI is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SK98LIN is not set
+CONFIG_TIGON3=m
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_IXGB is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+CONFIG_TR=y
+CONFIG_IBMOL=y
+# CONFIG_IBMLS is not set
+# CONFIG_3C359 is not set
+# CONFIG_TMS380TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BT is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN_BOOL is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=m
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PCIPS2 is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_PMACZILOG=y
+CONFIG_SERIAL_PMACZILOG_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_HVC_CONSOLE=y
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+CONFIG_RAW_DRIVER=y
+CONFIG_MAX_RAW_DEVS=256
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_ELV is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_ISA is not set
+CONFIG_I2C_KEYWEST=y
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VELLEMAN is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# I2C Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CYBER2000 is not set
+CONFIG_FB_OF=y
+# CONFIG_FB_CONTROL is not set
+# CONFIG_FB_PLATINUM is not set
+# CONFIG_FB_VALKYRIE is not set
+# CONFIG_FB_CT65550 is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_S3TRIO is not set
+# CONFIG_FB_VGA16 is not set
+CONFIG_FB_RIVA=y
+# CONFIG_FB_MATROX is not set
+CONFIG_FB_RADEON=y
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_PCI_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_UHCI_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_BLUETOOTH_TTY is not set
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_STORAGE=m
+CONFIG_USB_STORAGE_DEBUG=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_DPCM=y
+CONFIG_USB_STORAGE_HP8200e=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+CONFIG_HID_FF=y
+CONFIG_HID_PID=y
+CONFIG_LOGITECH_FF=y
+CONFIG_THRUSTMASTER_FF=y
+CONFIG_USB_HIDDEV=y
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_XPAD is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+
+#
+# Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_USBNET=m
+
+#
+# USB Host-to-Host Cables
+#
+CONFIG_USB_AN2720=y
+CONFIG_USB_BELKIN=y
+CONFIG_USB_GENESYS=y
+CONFIG_USB_NET1080=y
+CONFIG_USB_PL2301=y
+
+#
+# Intelligent USB Devices/Gadgets
+#
+CONFIG_USB_ARMLINUX=y
+CONFIG_USB_EPSON2888=y
+CONFIG_USB_ZAURUS=y
+CONFIG_USB_CDCETHER=y
+
+#
+# USB Network Adapters
+#
+CONFIG_USB_AX8817X=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_SAFE=m
+CONFIG_USB_SERIAL_SAFE_PADDED=y
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_EZUSB=y
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_TIGL is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_BRLVGER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+# CONFIG_EXT2_FS_SECURITY is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=m
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=m
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+# CONFIG_DEVFS_FS is not set
+CONFIG_DEVPTS_FS=y
+CONFIG_DEVPTS_FS_XATTR=y
+# CONFIG_DEVPTS_FS_SECURITY is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_SMB_FS is not set
+CONFIG_CIFS=m
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_NEC98_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_XMON is not set
+# CONFIG_PPCDBG is not set
+# CONFIG_DEBUG_INFO is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
+CONFIG_ZLIB_INFLATE=m
+CONFIG_ZLIB_DEFLATE=m
diff -Nru a/arch/ppc64/configs/pSeries_defconfig b/arch/ppc64/configs/pSeries_defconfig
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc64/configs/pSeries_defconfig	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,783 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_64BIT=y
+CONFIG_MMU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_COMPAT=y
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCE_MAX_ZONEORDER=13
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# Platform support
+#
+# CONFIG_PPC_ISERIES is not set
+CONFIG_PPC_PSERIES=y
+CONFIG_PPC=y
+CONFIG_PPC64=y
+CONFIG_PPC_OF=y
+CONFIG_ALTIVEC=y
+# CONFIG_PPC_PMAC is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_POWER4_ONLY is not set
+CONFIG_SMP=y
+CONFIG_IRQ_ALL_CPUS=y
+CONFIG_NR_CPUS=32
+# CONFIG_HMT is not set
+# CONFIG_DISCONTIGMEM is not set
+CONFIG_PPC_RTAS=y
+CONFIG_RTAS_FLASH=m
+CONFIG_SCANLOG=m
+CONFIG_LPARCFG=y
+
+#
+# General setup
+#
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_PCI_LEGACY_PROC=y
+CONFIG_PCI_NAMES=y
+# CONFIG_HOTPLUG is not set
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+CONFIG_BLK_DEV_FD=y
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_REPORT_LUNS=y
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CPQFCTS is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INIA100 is not set
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+CONFIG_SCSI_QLA2XXX=y
+CONFIG_SCSI_QLA21XX=y
+CONFIG_SCSI_QLA22XX=y
+# CONFIG_SCSI_QLA2300 is not set
+# CONFIG_SCSI_QLA2322 is not set
+# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_QLA6322 is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_LINEAR=y
+CONFIG_MD_RAID0=y
+CONFIG_MD_RAID1=y
+CONFIG_MD_RAID5=y
+# CONFIG_MD_RAID6 is not set
+# CONFIG_MD_MULTIPATH is not set
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_IOCTL_V4=y
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+
+#
+# Macintosh device drivers
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=y
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_INET_ECN=y
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+# CONFIG_IPV6 is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NETFILTER is not set
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IPV6_SCTP__=y
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_OAKNET is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_VORTEX=y
+# CONFIG_TYPHOON is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=y
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+CONFIG_E100=y
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_VIA_RHINE is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+CONFIG_ACENIC=y
+CONFIG_ACENIC_OMIT_TIGON_I=y
+# CONFIG_DL2K is not set
+CONFIG_E1000=y
+# CONFIG_E1000_NAPI is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_IXGB is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BT is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN_BOOL is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PCIPS2 is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_PCSPKR=y
+# CONFIG_INPUT_UINPUT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_PMACZILOG is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_HVC_CONSOLE=y
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+CONFIG_RAW_DRIVER=y
+CONFIG_MAX_RAW_DEVS=256
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CYBER2000 is not set
+CONFIG_FB_OF=y
+# CONFIG_FB_CT65550 is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_S3TRIO is not set
+# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_RIVA is not set
+CONFIG_FB_MATROX=y
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G450=y
+CONFIG_FB_MATROX_G100=y
+CONFIG_FB_MATROX_MULTIHEAD=y
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_PCI_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+# CONFIG_EXT2_FS_SECURITY is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=y
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_JFS_FS=y
+CONFIG_JFS_POSIX_ACL=y
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+CONFIG_XFS_POSIX_ACL=y
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=m
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=m
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+# CONFIG_DEVFS_FS is not set
+CONFIG_DEVPTS_FS=y
+CONFIG_DEVPTS_FS_XATTR=y
+# CONFIG_DEVPTS_FS_SECURITY is not set
+CONFIG_TMPFS=y
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_SMB_FS is not set
+CONFIG_CIFS=m
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_XMON=y
+CONFIG_XMON_DEFAULT=y
+# CONFIG_PPCDBG is not set
+# CONFIG_DEBUG_INFO is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
diff -Nru a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile
--- a/arch/ppc64/kernel/Makefile	Wed Feb 11 22:14:31 2004
+++ b/arch/ppc64/kernel/Makefile	Wed Feb 11 22:14:31 2004
@@ -10,9 +10,11 @@
 			align.o semaphore.o bitops.o stab.o pacaData.o \
 			udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \
 			ptrace32.o signal32.o pmc.o rtc.o init_task.o \
-			lmb.o cputable.o
+			lmb.o cputable.o cpu_setup_power4.o idle_power4.o
 
-obj-$(CONFIG_PCI)	+= pci.o pci_dn.o pci_dma.o
+obj-$(CONFIG_PPC_OF) +=	of_device.o
+
+obj-$(CONFIG_PCI)	+= pci.o pci_dn.o pci_dma.o pci_dma_direct.o
 
 ifdef CONFIG_PPC_ISERIES
 obj-$(CONFIG_PCI)	+= iSeries_pci.o iSeries_pci_reset.o \
@@ -27,7 +29,7 @@
 			     proc_pmc.o
 
 obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \
-			     eeh.o nvram.o rtasd.o ras.o \
+			     eeh.o nvram.o pSeries_nvram.o rtasd.o ras.o \
 			     open_pic.o xics.o pSeries_htab.o rtas.o \
 			     chrp_setup.o i8259.o prom.o vio.o
 
@@ -39,6 +41,14 @@
 obj-$(CONFIG_SCANLOG)		+= scanlog.o
 obj-$(CONFIG_VIOPATH)		+= viopath.o
 obj-$(CONFIG_LPARCFG)		+= lparcfg.o
-obj-$(CONFIG_HVC_CONSOLE)   += hvconsole.o
+obj-$(CONFIG_HVC_CONSOLE)	+= hvconsole.o
+obj-$(CONFIG_BOOTX_TEXT)	+= btext.o
+
+obj-$(CONFIG_PPC_PMAC)		+= pmac_setup.o pmac_feature.o pmac_pci.o \
+				   pmac_time.o pmac_nvram.o pmac_low_i2c.o \
+				   open_pic_u3.o
+ifdef CONFIG_SMP
+obj-$(CONFIG_PPC_PMAC)		+= pmac_smp.o smp-tbsync.o
+endif
 
 CFLAGS_ioctl32.o += -Ifs/
diff -Nru a/arch/ppc64/kernel/btext.c b/arch/ppc64/kernel/btext.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc64/kernel/btext.c	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,748 @@
+/*
+ * 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/sections.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/lmb.h>
+#include <asm/processor.h>
+
+#undef 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 int *base, int rb);
+static void draw_byte_16(unsigned char *bits, unsigned int *base, int rb);
+static void draw_byte_8(unsigned char *bits, unsigned int *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;
+int force_printk_to_btext = 0;
+
+boot_infos_t disp_bi;
+
+extern char *klimit;
+
+/* 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 = PTRRELOC(&disp_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;
+	RELOC(boot_text_mapped) = 1;
+}
+
+/* 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_boot_text(void)
+{
+	unsigned long base, offset, size;
+	boot_infos_t *bi = &disp_bi;
+	unsigned char *vbase;
+
+	/* By default, we are no longer mapped */
+	boot_text_mapped = 0;
+	if (bi->dispDeviceBase == 0)
+		return;
+	base = ((unsigned long) bi->dispDeviceBase) & 0xFFFFF000UL;
+	offset = ((unsigned long) bi->dispDeviceBase) - base;
+	size = bi->dispDeviceRowBytes * bi->dispDeviceRect[3] + offset
+		+ bi->dispDeviceRect[0];
+	vbase = __ioremap(base, size, _PAGE_NO_CACHE);
+	if (vbase == 0)
+		return;
+	bi->logicalDisplayBase = vbase + offset;
+	boot_text_mapped = 1;
+}
+
+/* Calc the base address of a given point (x,y) */
+static unsigned char * 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)
+{
+	boot_infos_t *bi = &disp_bi;
+
+	if (bi->dispDeviceBase == 0)
+		return;
+
+	/* check it's the same frame buffer (within 256MB) */
+	if ((phys ^ (unsigned long)bi->dispDeviceBase) & 0xf0000000)
+		return;
+
+	bi->dispDeviceBase = (__u8 *) phys;
+	bi->dispDeviceRect[0] = 0;
+	bi->dispDeviceRect[1] = 0;
+	bi->dispDeviceRect[2] = width;
+	bi->dispDeviceRect[3] = height;
+	bi->dispDeviceDepth = depth;
+	bi->dispDeviceRowBytes = pitch;
+	if (boot_text_mapped) {
+		iounmap(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_clearscreen(void)
+{
+	unsigned long offset = reloc_offset();
+	boot_infos_t* bi	= PTRRELOC(&disp_bi);
+	unsigned long *base	= (unsigned long *)calc_base(bi, 0, 0);
+	unsigned long width 	= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
+					(bi->dispDeviceDepth >> 3)) >> 3;
+	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 >> 3);
+	}
+}
+
+#ifndef NO_SCROLL
+static void scrollscreen(void)
+{
+	unsigned long offset   	= reloc_offset();
+	boot_infos_t* bi       	= PTRRELOC(&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)) >> 3;
+	int i,j;
+
+	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 >> 3);
+		dst += (bi->dispDeviceRowBytes >> 3);
+	}
+	for (i=0; i<16; i++)
+	{
+		unsigned long *dst_ptr = dst;
+		for(j=width; j; --j)
+			*(dst_ptr++) = 0;
+		dst += (bi->dispDeviceRowBytes >> 3);
+	}
+}
+#endif /* ndef NO_SCROLL */
+
+void btext_drawchar(char c)
+{
+	unsigned long offset = reloc_offset();
+	int cline = 0;
+#ifdef NO_SCROLL
+	int x;
+#endif
+	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_drawstring(const char *c)
+{
+	unsigned long offset = reloc_offset();
+
+	if (!RELOC(boot_text_mapped))
+		return;
+	while (*c)
+		btext_drawchar(*c++);
+}
+
+void btext_drawhex(unsigned long v)
+{
+	unsigned long offset = reloc_offset();
+	char *hex_table = RELOC("0123456789abcdef");
+
+	if (!RELOC(boot_text_mapped))
+		return;
+	btext_drawchar(hex_table[(v >> 60) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >> 56) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >> 52) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >> 48) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >> 44) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >> 40) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >> 36) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >> 32) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >> 28) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >> 24) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >> 20) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >> 16) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >> 12) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >>  8) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >>  4) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >>  0) & 0x0000000FUL]);
+	btext_drawchar(' ');
+}
+
+static void draw_byte(unsigned char c, long locX, long locY)
+{
+	unsigned long offset	= reloc_offset();
+	boot_infos_t* bi       	= PTRRELOC(&disp_bi);
+	unsigned char *base	= calc_base(bi, locX << 3, locY << 4);
+	unsigned char *font	= PTRRELOC(&vga_font[((unsigned int)c) * 16]);
+	int rb			= bi->dispDeviceRowBytes;
+
+#if 0
+	switch(bi->dispDeviceDepth) {
+	case 24:
+	case 32:
+		draw_byte_32(font, (unsigned int *)base, rb);
+		break;
+	case 15:
+	case 16:
+		draw_byte_16(font, (unsigned int *)base, rb);
+		break;
+	case 8:
+		draw_byte_8(font, (unsigned int *)base, rb);
+		break;
+	}
+#else
+	if(bi->dispDeviceDepth == 24 ||
+	   bi->dispDeviceDepth == 32) {
+		draw_byte_32(font, (unsigned int *)base, rb);
+	} else if(bi->dispDeviceDepth == 15 ||
+	   bi->dispDeviceDepth == 16) {
+		draw_byte_16(font, (unsigned int *)base, rb);
+	} else if(bi->dispDeviceDepth == 8) {
+		draw_byte_8(font, (unsigned int *)base, rb);
+	} 
+#endif
+}
+
+static unsigned int expand_bits_8[16] = {
+	0x00000000,
+	0x000000ff,
+	0x0000ff00,
+	0x0000ffff,
+	0x00ff0000,
+	0x00ff00ff,
+	0x00ffff00,
+	0x00ffffff,
+	0xff000000,
+	0xff0000ff,
+	0xff00ff00,
+	0xff00ffff,
+	0xffff0000,
+	0xffff00ff,
+	0xffffff00,
+	0xffffffff
+};
+
+static unsigned int expand_bits_16[4] = {
+	0x00000000,
+	0x0000ffff,
+	0xffff0000,
+	0xffffffff
+};
+
+
+static void draw_byte_32(unsigned char *font, unsigned int *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 int *) ((char *)base + rb);
+	}
+}
+
+static void draw_byte_16(unsigned char *font, unsigned int *base, int rb)
+{
+	int l, bits;
+	int fg = 0xFFFFFFFFUL;
+	int bg = 0x00000000UL;
+	unsigned long offset = reloc_offset();
+	unsigned int *eb = PTRRELOC((int *)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 int *) ((char *)base + rb);
+	}
+}
+
+static void draw_byte_8(unsigned char *font, unsigned int *base, int rb)
+{
+	int l, bits;
+	int fg = 0x0F0F0F0FUL;
+	int bg = 0x00000000UL;
+	unsigned long offset = reloc_offset();
+	unsigned int *eb = PTRRELOC((int *)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 int *) ((char *)base + rb);
+	}
+}
+
+static unsigned char vga_font[cmapsz] = {
+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 -Nru a/arch/ppc64/kernel/chrp_setup.c b/arch/ppc64/kernel/chrp_setup.c
--- a/arch/ppc64/kernel/chrp_setup.c	Wed Feb 11 22:14:30 2004
+++ b/arch/ppc64/kernel/chrp_setup.c	Wed Feb 11 22:14:30 2004
@@ -67,9 +67,10 @@
 
 void chrp_progress(char *, unsigned short);
 
-extern void openpic_init_IRQ(void);
+extern void pSeries_init_openpic(void);
 
 extern void find_and_init_phbs(void);
+extern void pSeries_final_fixup(void);
 
 extern void pSeries_get_boot_time(struct rtc_time *rtc_time);
 extern void pSeries_get_rtc_time(struct rtc_time *rtc_time);
@@ -178,6 +179,10 @@
 #ifdef CONFIG_DUMMY_CONSOLE
 	conswitchp = &dummy_con;
 #endif
+
+#ifdef CONFIG_PPC_PSERIES
+	pSeries_nvram_init();
+#endif
 }
 
 void __init
@@ -252,7 +257,7 @@
 	ppc_md.setup_residual = NULL;
 	ppc_md.get_cpuinfo    = chrp_get_cpuinfo;
 	if(naca->interrupt_controller == IC_OPEN_PIC) {
-		ppc_md.init_IRQ       = openpic_init_IRQ; 
+		ppc_md.init_IRQ       = pSeries_init_openpic; 
 		ppc_md.get_irq        = openpic_get_irq;
 	} else {
 		ppc_md.init_IRQ       = xics_init_IRQ;
@@ -261,6 +266,8 @@
 
 	ppc_md.init           = chrp_init2;
 
+	ppc_md.pcibios_fixup  = pSeries_final_fixup;
+
 	ppc_md.restart        = rtas_restart;
 	ppc_md.power_off      = rtas_power_off;
 	ppc_md.halt           = rtas_halt;
@@ -271,9 +278,6 @@
 	ppc_md.calibrate_decr = pSeries_calibrate_decr;
 
 	ppc_md.progress       = chrp_progress;
-
-	ppc_md.nvram_read     = pSeries_nvram_read;
-	ppc_md.nvram_write    = pSeries_nvram_write;
 
         /* Build up the firmware_features bitmask field
          * using contents of device-tree/ibm,hypertas-functions.
diff -Nru a/arch/ppc64/kernel/cpu_setup_power4.S b/arch/ppc64/kernel/cpu_setup_power4.S
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc64/kernel/cpu_setup_power4.S	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,179 @@
+/*
+ * This file contains low level CPU setup functions.
+ *    Copyright (C) 2003 Benjamin 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 <asm/processor.h>
+#include <asm/page.h>
+#include <asm/ppc_asm.h>
+#include <asm/cputable.h>
+#include <asm/ppc_asm.h>
+#include <asm/offsets.h>
+#include <asm/cache.h>
+
+_GLOBAL(__power4_cpu_preinit)
+	/*
+	 * On the PPC970, we have to turn off real-mode cache inhibit
+	 * early, before we first turn the MMU off.
+	 */
+	mfspr	r0,SPRN_PVR
+	srwi	r0,r0,16
+	cmpwi	r0,0x39
+	bnelr
+
+	li	r0,0
+	sync
+	mtspr	SPRN_HID4,r0
+	isync
+	sync
+	mtspr	SPRN_HID5,r0
+	isync
+
+	mfspr	r0,SPRN_HID1
+	li	r11,0x1200		/* enable i-fetch cacheability */
+	sldi	r11,r11,44		/* and prefetch */
+	or	r0,r0,r11
+	mtspr	SPRN_HID1,r0
+	mtspr	SPRN_HID1,r0
+	isync
+	li	r0,0
+	sync
+	mtspr	SPRN_HIOR,0		/* Clear interrupt prefix */
+	isync
+	blr
+
+_GLOBAL(__setup_cpu_power4)
+	blr
+	
+_GLOBAL(__setup_cpu_ppc970)
+	mfspr	r0,SPRN_HID0
+	li	r11,5			/* clear DOZE and SLEEP */
+	rldimi	r0,r11,52,8		/* set NAP and DPM */
+	mtspr	SPRN_HID0,r0
+	mfspr	r0,SPRN_HID0
+	mfspr	r0,SPRN_HID0
+	mfspr	r0,SPRN_HID0
+	mfspr	r0,SPRN_HID0
+	mfspr	r0,SPRN_HID0
+	mfspr	r0,SPRN_HID0
+	sync
+	isync
+	blr
+
+/* Definitions for the table use to save CPU states */
+#define CS_HID0		0
+#define CS_HID1		8
+#define	CS_HID4		16
+#define CS_HID5		24
+#define CS_SIZE		32
+
+	.data
+	.balign	L1_CACHE_BYTES,0
+cpu_state_storage:	
+	.space	CS_SIZE
+	.balign	L1_CACHE_BYTES,0
+	.text
+	
+/* Called in normal context to backup CPU 0 state. This
+ * does not include cache settings. This function is also
+ * called for machine sleep. This does not include the MMU
+ * setup, BATs, etc... but rather the "special" registers
+ * like HID0, HID1, HID4, etc...
+ */
+_GLOBAL(__save_cpu_setup)
+	/* Some CR fields are volatile, we back it up all */
+	mfcr	r7
+
+	/* Get storage ptr */
+	LOADADDR(r5,cpu_state_storage)
+
+	/* We only deal with 970 for now */
+	mfspr	r0,SPRN_PVR
+	srwi	r0,r0,16
+	cmpwi	r0,0x39
+	bne	1f
+
+	/* Save HID0,1,4 and 5 */
+	mfspr	r3,SPRN_HID0
+	std	r3,CS_HID0(r5)
+	mfspr	r3,SPRN_HID1
+	std	r3,CS_HID1(r5)
+	mfspr	r3,SPRN_HID4
+	std	r3,CS_HID4(r5)
+	mfspr	r3,SPRN_HID5
+	std	r3,CS_HID5(r5)
+	
+1:
+	mtcr	r7
+	blr
+
+/* Called with no MMU context (typically MSR:IR/DR off) to
+ * restore CPU state as backed up by the previous
+ * function. This does not include cache setting
+ */
+_GLOBAL(__restore_cpu_setup)
+	/* Get storage ptr (FIXME when using anton reloc as we
+	 * are running with translation disabled here
+	 */
+	LOADADDR(r5,cpu_state_storage)
+
+	/* We only deal with 970 for now */
+	mfspr	r0,SPRN_PVR
+	srwi	r0,r0,16
+	cmpwi	r0,0x39
+	bne	1f
+
+	/* Clear interrupt prefix */
+	li	r0,0
+	sync
+	mtspr	SPRN_HIOR,0
+	isync
+
+	/* Restore HID0 */
+	ld	r3,CS_HID0(r5)
+	sync
+	isync
+	mtspr	SPRN_HID0,r3
+	mfspr	r3,SPRN_HID0
+	mfspr	r3,SPRN_HID0
+	mfspr	r3,SPRN_HID0
+	mfspr	r3,SPRN_HID0
+	mfspr	r3,SPRN_HID0
+	mfspr	r3,SPRN_HID0
+	sync
+	isync
+
+	/* Restore HID1 */
+	ld	r3,CS_HID1(r5)
+	sync
+	isync
+	mtspr	SPRN_HID1,r3
+	mtspr	SPRN_HID1,r3
+	sync
+	isync
+	
+	/* Restore HID4 */
+	ld	r3,CS_HID4(r5)
+	sync
+	isync
+	mtspr	SPRN_HID4,r3
+	sync
+	isync
+
+	/* Restore HID5 */
+	ld	r3,CS_HID5(r5)
+	sync
+	isync
+	mtspr	SPRN_HID5,r3
+	sync
+	isync
+1:
+	blr
+
diff -Nru a/arch/ppc64/kernel/cputable.c b/arch/ppc64/kernel/cputable.c
--- a/arch/ppc64/kernel/cputable.c	Wed Feb 11 22:14:30 2004
+++ b/arch/ppc64/kernel/cputable.c	Wed Feb 11 22:14:30 2004
@@ -30,6 +30,7 @@
  */
 extern void __setup_cpu_power3(unsigned long offset, struct cpu_spec* spec);
 extern void __setup_cpu_power4(unsigned long offset, struct cpu_spec* spec);
+extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec);
 
 
 /* We only set the altivec features if the kernel was compiled with altivec
@@ -119,10 +120,10 @@
     {	/* PPC970 */
 	    0xffff0000, 0x00390000, "PPC970",
 	    CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
-	    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP,
+	    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP | CPU_FTR_CAN_NAP,
 	    COMMON_USER_PPC64 | PPC_FEATURE_HAS_ALTIVEC_COMP,
 	    128, 128,
-	    __setup_cpu_power4,
+	    __setup_cpu_ppc970,
 	    COMMON_PPC64_FW
     },
     {	/* Power5 */
diff -Nru a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S
--- a/arch/ppc64/kernel/head.S	Wed Feb 11 22:14:31 2004
+++ b/arch/ppc64/kernel/head.S	Wed Feb 11 22:14:31 2004
@@ -1320,6 +1320,16 @@
 #endif
 
 #ifdef CONFIG_PPC_PSERIES
+
+_STATIC(mmu_off)
+	mfmsr	r3
+	andi.	r0,r3,MSR_IR|MSR_DR
+	beqlr
+	andc	r3,r3,r0
+	mtspr	SRR0,r4
+	mtspr	SRR1,r3
+	sync
+	rfid
 _GLOBAL(__start_initialization_pSeries)
 	mr	r31,r3			/* save parameters */
 	mr	r30,r4
@@ -1339,33 +1349,27 @@
 	/* Relocate the TOC from a virt addr to a real addr */
 	sub	r2,r2,r3
 
-	/* DRENG / PPPBBB Fix the following comment!!! -Peter */
-	/* The following copies the first 0x100 bytes of code from the    */
-	/* load addr to physical addr 0x0.  This code causes secondary    */
-	/* processors to spin until a flag in the PACA is set.  This      */
-	/* is done at this time rather than with the entire kernel        */
-	/* relocation which is done below because we need to cause the    */
-	/* processors to spin on code that is not going to move while OF  */
-	/* is still alive. Although the spin code is not actually run on  */
-	/* a uniprocessor, we always do this copy.                        */
-	SET_REG_TO_CONST(r4, KERNELBASE)/* Src addr                       */
-	sub	r4,r4,r3  		/* current address of __start     */
-			                /*        the source addr         */
-	li	r3,0                    /* Dest addr                      */
-	li	r5,0x100 		/* # bytes of memory to copy      */
-	li	r6,0			/* Destination offset             */
-	bl	.copy_and_flush		/* copy the first 0x100 bytes     */
-
+	/* Save parameters */
 	mr	r3,r31
 	mr	r4,r30
 	mr	r5,r29
 	mr	r6,r28
 	mr	r7,r27
 
+	/* Do all of the interaction with OF client interface */
 	bl	.prom_init
+	mr	r23,r3			/* Save phys address we are running at */
+
+	/* Setup some critical 970 SPRs before switching MMU off */
+	bl	.__power4_cpu_preinit
 
 	li	r24,0			/* cpu # */
 
+	/* Switch off MMU if not already */
+	LOADADDR(r4, .__after_prom_start - KERNELBASE)
+	add	r4,r4,r23
+	bl	.mmu_off	
+
 /*
  * At this point, r3 contains the physical address we are running at,
  * returned by prom_init()
@@ -1390,6 +1394,7 @@
 
 	li	r3,0                    /* target addr */
 
+	// XXX FIXME: Use phys returned by OF (r23)
 	sub	r4,r27,r26 		/* source addr */
 					/* current address of _start   */
 			                /*   i.e. where we are running */
@@ -1425,7 +1430,7 @@
  *
  * Note: this routine *only* clobbers r0, r6 and lr
  */
-_STATIC(copy_and_flush)
+_GLOBAL(copy_and_flush)
 	addi	r5,r5,-8
 	addi	r6,r6,-8
 4:	li	r0,16                   /* Use the least common      */
@@ -1675,6 +1680,58 @@
 #endif /* CONFIG_ALTIVEC */
 
 #ifdef CONFIG_SMP
+#ifdef CONFIG_PPC_PMAC
+/*
+ * On PowerMac, secondary processors starts from the reset vector, which
+ * is temporarily turned into a call to one of the functions below.
+ */
+	.section ".text";
+	.align 2 ;
+
+	.globl	pmac_secondary_start_1	
+pmac_secondary_start_1:	
+	li	r24, 1
+	b	.pmac_secondary_start
+	
+	.globl pmac_secondary_start_2
+pmac_secondary_start_2:	
+	li	r24, 2
+	b	.pmac_secondary_start
+	
+	.globl pmac_secondary_start_3
+pmac_secondary_start_3:
+	li	r24, 3
+	b	.pmac_secondary_start
+	
+_GLOBAL(pmac_secondary_start)
+	/* turn on 64-bit mode */
+	bl	.enable_64b_mode
+	isync
+
+	/* Copy some CPU settings from CPU 0 */
+	bl	.__restore_cpu_setup
+
+	/* pSeries do that early though I don't think we really need it */
+	mfmsr	r3
+	ori	r3,r3,MSR_RI
+	mtmsrd	r3			/* RI on */
+
+	/* Set up a paca value for this processor. */
+	LOADADDR(r4, paca) 		 /* Get base vaddr of paca array  */
+	mulli	r13,r24,PACA_SIZE	 /* Calculate vaddr of right paca */
+	add	r13,r13,r4               /* for this processor.           */
+	mtspr	SPRG3,r13		 /* Save vaddr of paca in SPRG3   */
+
+        /* Create a temp kernel stack for use before relocation is on.    */
+        mr      r1,r13
+        addi    r1,r1,PACAGUARD
+        addi    r1,r1,0x1000
+        subi    r1,r1,STACK_FRAME_OVERHEAD
+
+	b	.__secondary_start
+
+#endif /* CONFIG_PPC_PMAC */
+
 /*
  * This function is called after the master CPU has released the
  * secondary processors.  The execution environment is relocation off.
@@ -1870,6 +1927,12 @@
 	li	r0,0
 	stdu	r0,-STACK_FRAME_OVERHEAD(r1)
 
+		/* set up the TOC (physical address) */
+	LOADADDR(r2,__toc_start)
+	addi    r2,r2,0x4000
+	addi    r2,r2,0x4000
+	sub	r2,r2,r26
+
 	LOADADDR(r3,cpu_specs)
 	sub	r3,r3,r26
 	LOADADDR(r4,cur_cpu_spec)
@@ -1877,12 +1940,6 @@
 	mr	r5,r26
 	bl	.identify_cpu
 
-	/* set up the TOC (physical address) */
-	LOADADDR(r2,__toc_start)
-	addi    r2,r2,0x4000
-	addi    r2,r2,0x4000
-	sub	r2,r2,r26
-
 	/* Get the pointer to the segment table which is used by           */
 	/* stab_initialize                                                 */
 	LOADADDR(r27, boot_cpuid)
@@ -1926,7 +1983,8 @@
 
 	li	r3,SYSTEMCFG_PHYS_ADDR	/* r3 = ptr to systemcfg */
 	lwz	r3,PLATFORM(r3)		/* r3 = platform flags */
-	cmpldi r3,PLATFORM_PSERIES
+	/* Test if bit 0 is set (LPAR bit) */
+	andi.	r3,r3,0x1
 	bne    98f
 	LOADADDR(r6,_SDR1)		/* Only if NOT LPAR */
 	sub	r6,r6,r26
@@ -1938,11 +1996,12 @@
 	mtspr	SRR0,r3
 	mtspr	SRR1,r4
 	rfid
-#endif	/* CONFIG_PPC_PSERIES */
-
+#endif /* CONFIG_PPC_PSERIES */
+	
 	/* This is where all platforms converge execution */
 _STATIC(start_here_common)
-	
+	/* relocation is on at this point */
+
 	/* The following code sets up the SP and TOC now that we are */
 	/* running with translation enabled. */
 
@@ -2012,8 +2071,6 @@
 	bl .start_kernel
 
 _GLOBAL(__setup_cpu_power3)
-	blr
-_GLOBAL(__setup_cpu_power4)
 	blr
 
 _GLOBAL(hmt_init)
diff -Nru a/arch/ppc64/kernel/iSeries_pci.c b/arch/ppc64/kernel/iSeries_pci.c
--- a/arch/ppc64/kernel/iSeries_pci.c	Wed Feb 11 22:14:31 2004
+++ b/arch/ppc64/kernel/iSeries_pci.c	Wed Feb 11 22:14:31 2004
@@ -241,9 +241,9 @@
 }
 
 /*
- * pcibios_final_fixup(void)  
+ * iSeries_pci_final_fixup(void)  
  */
-void __init pcibios_final_fixup(void)
+void __init iSeries_pci_final_fixup(void)
 {
 	struct pci_dev *pdev = NULL;
 	struct iSeries_Device_Node *node;
diff -Nru a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c
--- a/arch/ppc64/kernel/iSeries_setup.c	Wed Feb 11 22:14:31 2004
+++ b/arch/ppc64/kernel/iSeries_setup.c	Wed Feb 11 22:14:31 2004
@@ -63,10 +63,11 @@
 static void build_iSeries_Memory_Map(void);
 static void setup_iSeries_cache_sizes(void);
 static void iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr);
-void build_valid_hpte(unsigned long vsid, unsigned long ea, unsigned long pa,
-		pte_t *ptep, unsigned hpteflags, unsigned bolted);
+extern void build_valid_hpte(unsigned long vsid, unsigned long ea, unsigned long pa,
+			     pte_t *ptep, unsigned hpteflags, unsigned bolted);
 static void iSeries_setup_dprofile(void);
-void iSeries_setup_arch(void);
+extern void iSeries_setup_arch(void);
+extern void iSeries_pci_final_fixup(void);
 
 /* Global Variables */
 static unsigned long procFreqHz;
@@ -317,6 +318,8 @@
 	ppc_md.init_irq_desc = iSeries_init_irq_desc;
 	ppc_md.get_irq = iSeries_get_irq;
 	ppc_md.init = NULL;
+
+	ppc_md.pcibios_fixup  = iSeries_pci_final_fixup;
 
 	ppc_md.restart = iSeries_restart;
 	ppc_md.power_off = iSeries_power_off;
diff -Nru a/arch/ppc64/kernel/idle.c b/arch/ppc64/kernel/idle.c
--- a/arch/ppc64/kernel/idle.c	Wed Feb 11 22:14:31 2004
+++ b/arch/ppc64/kernel/idle.c	Wed Feb 11 22:14:31 2004
@@ -42,6 +42,7 @@
 
 extern long cede_processor(void);
 extern long poll_pending(void);
+extern void power4_idle(void);
 
 int (*idle_loop)(void);
 
@@ -279,6 +280,17 @@
 	return 0; 
 }
 
+int native_idle(void)
+{
+	while(1) {
+		if (!need_resched())
+			power4_idle();
+		if (need_resched())
+			schedule();
+	}
+	return 0;
+}
+
 int idle_setup(void)
 {
 #ifdef CONFIG_PPC_ISERIES
@@ -297,6 +309,9 @@
 			printk("idle = default_idle\n");
 			idle_loop = default_idle;
 		}
+	} else if (systemcfg->platform == PLATFORM_POWERMAC) {
+		printk("idle = native_idle\n");
+		idle_loop = native_idle;
 	} else {
 		printk("idle_setup: unknown platform, use default_idle\n");
 		idle_loop = default_idle;
diff -Nru a/arch/ppc64/kernel/idle_power4.S b/arch/ppc64/kernel/idle_power4.S
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc64/kernel/idle_power4.S	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,79 @@
+/*
+ *  This file contains the power_save function for 6xx & 7xxx CPUs
+ *  rewritten in assembler
+ *
+ *  Warning ! This code assumes that if your machine has a 750fx
+ *  it will have PLL 1 set to low speed mode (used during NAP/DOZE).
+ *  if this is not the case some additional changes will have to
+ *  be done to check a runtime var (a bit like powersave-nap)
+ *
+ *  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/threads.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/cputable.h>
+#include <asm/thread_info.h>
+#include <asm/ppc_asm.h>
+#include <asm/offsets.h>
+
+#undef DEBUG
+
+	.text
+
+/*
+ * Here is the power_save_6xx function. This could eventually be
+ * split into several functions & changing the function pointer
+ * depending on the various features.
+ */
+_GLOBAL(power4_idle)
+BEGIN_FTR_SECTION
+	blr
+END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP)
+	/* We must dynamically check for the NAP feature as it
+	 * can be cleared by CPU init after the fixups are done
+	 */
+	LOADBASE(r3,cur_cpu_spec)
+	ld	r4,cur_cpu_spec@l(r3)
+	ld	r4,CPU_SPEC_FEATURES(r4)
+	andi.	r0,r4,CPU_FTR_CAN_NAP
+	beqlr
+	/* Now check if user or arch enabled NAP mode */
+	LOADBASE(r3,powersave_nap)
+	lwz	r4,powersave_nap@l(r3)
+	cmpi	0,r4,0
+	beqlr
+
+	/* Clear MSR:EE */
+	mfmsr	r7
+	li	r4,0
+	ori	r4,r4,MSR_EE
+	andc	r0,r7,r4
+	mtmsrd	r0
+
+	/* Check current_thread_info()->flags */
+	clrrdi	r4,r1,THREAD_SHIFT
+	ld	r4,TI_FLAGS(r4)
+	andi.	r0,r4,_TIF_NEED_RESCHED
+	beq	1f
+	mtmsrd	r7	/* out of line this ? */
+	blr
+1:	
+	/* Go to NAP now */	
+BEGIN_FTR_SECTION
+	DSSALL
+	sync
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
+	oris	r7,r7,MSR_POW@h
+	sync
+	isync
+	mtmsrd	r7
+	isync
+	sync
+	blr
+	
diff -Nru a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S
--- a/arch/ppc64/kernel/misc.S	Wed Feb 11 22:14:31 2004
+++ b/arch/ppc64/kernel/misc.S	Wed Feb 11 22:14:31 2004
@@ -763,7 +763,7 @@
 	.llong .sys_fstat64
 	.llong .sys32_pciconfig_read
 	.llong .sys32_pciconfig_write
-	.llong .sys_ni_syscall		/* 200 - old pciconfig_iobase */
+	.llong .sys32_pciconfig_iobase	/* 200 - pciconfig_iobase */
 	.llong .sys_ni_syscall		/* reserved for MacOnLinux */
 	.llong .sys_getdents64
 	.llong .sys_pivot_root
@@ -1022,7 +1022,7 @@
 	.llong .sys_ni_syscall		/* 32bit only fstat64 */
 	.llong .sys_ni_syscall		/* 32bit only pciconfig_read */
 	.llong .sys_ni_syscall		/* 32bit only pciconfig_write */
-	.llong .sys_ni_syscall		/* 200 - old pciconfig_iobase */
+	.llong .sys_ni_syscall		/* 32bit only pciconfig_iobase */
 	.llong .sys_ni_syscall		/* reserved for MacOnLinux */
 	.llong .sys_getdents64
 	.llong .sys_pivot_root
diff -Nru a/arch/ppc64/kernel/nvram.c b/arch/ppc64/kernel/nvram.c
--- a/arch/ppc64/kernel/nvram.c	Wed Feb 11 22:14:30 2004
+++ b/arch/ppc64/kernel/nvram.c	Wed Feb 11 22:14:30 2004
@@ -9,6 +9,10 @@
  * /dev/nvram driver for PPC64
  *
  * This perhaps should live in drivers/char
+ *
+ * TODO: Split the /dev/nvram part (that one can use
+ *       drivers/char/generic_nvram.c) from the arch & partition
+ *       parsing code.
  */
 
 #include <linux/module.h>
@@ -34,16 +38,10 @@
 static int nvram_setup_partition(void);
 static int nvram_create_os_partition(void);
 static int nvram_remove_os_partition(void);
-static unsigned char nvram_checksum(struct nvram_header *p);
-static int nvram_write_header(struct nvram_partition * part);
 
-static unsigned int nvram_size;
-static unsigned int nvram_fetch, nvram_store;
-static char nvram_buf[NVRW_CNT];	/* assume this is in the first 4GB */
 static struct nvram_partition * nvram_part;
 static long nvram_error_log_index = -1;
 static long nvram_error_log_size = 0;
-static spinlock_t nvram_lock = SPIN_LOCK_UNLOCKED;
 
 volatile int no_more_logging = 1; /* Until we initialize everything,
 				   * make sure we don't try logging
@@ -58,12 +56,18 @@
 
 static loff_t dev_nvram_llseek(struct file *file, loff_t offset, int origin)
 {
+	int size;
+
+	if (ppc_md.nvram_size == NULL)
+		return -ENODEV;
+	size = ppc_md.nvram_size();
+
 	switch (origin) {
 	case 1:
 		offset += file->f_pos;
 		break;
 	case 2:
-		offset += nvram_size;
+		offset += size;
 		break;
 	}
 	if (offset < 0)
@@ -78,13 +82,18 @@
 {
 	ssize_t len;
 	char *tmp_buffer;
+	int size;
+
+	if (ppc_md.nvram_size == NULL)
+		return -ENODEV;
+	size = ppc_md.nvram_size();
 
 	if (verify_area(VERIFY_WRITE, buf, count))
 		return -EFAULT;
-	if (*ppos >= nvram_size)
+	if (*ppos >= size)
 		return 0;
-	if (count > nvram_size) 
-		count = nvram_size;
+	if (count > size) 
+		count = size;
 
 	tmp_buffer = (char *) kmalloc(count, GFP_KERNEL);
 	if (!tmp_buffer) {
@@ -113,13 +122,18 @@
 {
 	ssize_t len;
 	char * tmp_buffer;
+	int size;
+
+	if (ppc_md.nvram_size == NULL)
+		return -ENODEV;
+	size = ppc_md.nvram_size();
 
 	if (verify_area(VERIFY_READ, buf, count))
 		return -EFAULT;
-	if (*ppos >= nvram_size)
+	if (*ppos >= size)
 		return 0;
-	if (count > nvram_size)
-		count = nvram_size;
+	if (count > size)
+		count = size;
 
 	tmp_buffer = (char *) kmalloc(count, GFP_KERNEL);
 	if (!tmp_buffer) {
@@ -145,6 +159,28 @@
 static int dev_nvram_ioctl(struct inode *inode, struct file *file,
 	unsigned int cmd, unsigned long arg)
 {
+	switch(cmd) {
+#ifdef CONFIG_PPC_PMAC
+	case OBSOLETE_PMAC_NVRAM_GET_OFFSET:
+		printk(KERN_WARNING "nvram: Using obsolete PMAC_NVRAM_GET_OFFSET ioctl\n");
+	case IOC_NVRAM_GET_OFFSET: {
+		int part, offset;
+
+		if (systemcfg->platform != PLATFORM_POWERMAC)
+			return -EINVAL;
+		if (copy_from_user(&part, (void __user*)arg, sizeof(part)) != 0)
+			return -EFAULT;
+		if (part < pmac_nvram_OF || part > pmac_nvram_NR)
+			return -EINVAL;
+		offset = pmac_get_partition(part);
+		if (offset < 0)
+			return offset;
+		if (copy_to_user((void __user*)arg, &offset, sizeof(offset)) != 0)
+			return -EFAULT;
+		return 0;
+	}
+#endif /* CONFIG_PPC_PMAC */
+	}
 	return -EINVAL;
 }
 
@@ -162,259 +198,75 @@
 	&nvram_fops
 };
 
-ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index)
-{
-	unsigned int i;
-	unsigned long len, done;
-	unsigned long flags;
-	char *p = buf;
-
-	if (*index >= nvram_size)
-		return 0;
-
-	i = *index;
-	if (i + count > nvram_size)
-		count = nvram_size - i;
-
-	spin_lock_irqsave(&nvram_lock, flags);
-
-	for (; count != 0; count -= len) {
-		len = count;
-		if (len > NVRW_CNT)
-			len = NVRW_CNT;
-		
-		if ((rtas_call(nvram_fetch, 3, 2, &done, i, __pa(nvram_buf),
-			       len) != 0) || len != done) {
-			spin_unlock_irqrestore(&nvram_lock, flags);
-			return -EIO;
-		}
-		
-		memcpy(p, nvram_buf, len);
 
-		p += len;
-		i += len;
-	}
 
-	spin_unlock_irqrestore(&nvram_lock, flags);
+static void nvram_print_partitions(char * label)
+{
+	struct list_head * p;
+	struct nvram_partition * tmp_part;
 	
-	*index = i;
-	return p - buf;
+	printk(KERN_WARNING "--------%s---------\n", label);
+	printk(KERN_WARNING "indx\t\tsig\tchks\tlen\tname\n");
+	list_for_each(p, &nvram_part->partition) {
+		tmp_part = list_entry(p, struct nvram_partition, partition);
+		printk(KERN_WARNING "%d    \t%02x\t%02x\t%d\t%s\n",
+		       tmp_part->index, tmp_part->header.signature,
+		       tmp_part->header.checksum, tmp_part->header.length,
+		       tmp_part->header.name);
+	}
 }
 
-ssize_t pSeries_nvram_write(char *buf, size_t count, loff_t *index)
-{
-	unsigned int i;
-	unsigned long len, done;
-	unsigned long flags;
-	const char *p = buf;
-
-	if (*index >= nvram_size)
-		return 0;
 
-	i = *index;
-	if (i + count > nvram_size)
-		count = nvram_size - i;
-
-	spin_lock_irqsave(&nvram_lock, flags);
-
-	for (; count != 0; count -= len) {
-		len = count;
-		if (len > NVRW_CNT)
-			len = NVRW_CNT;
-
-		memcpy(nvram_buf, p, len);
-
-		if ((rtas_call(nvram_store, 3, 2, &done, i, __pa(nvram_buf),
-			       len) != 0) || len != done) {
-			spin_unlock_irqrestore(&nvram_lock, flags);
-			return -EIO;
-		}
-		
-		p += len;
-		i += len;
-	}
-	spin_unlock_irqrestore(&nvram_lock, flags);
-	
-	*index = i;
-	return p - buf;
-}
- 
-int __init nvram_init(void)
+static int nvram_write_header(struct nvram_partition * part)
 {
-	struct device_node *nvram;
-	unsigned int *nbytes_p, proplen;
-	int error;
+	loff_t tmp_index;
 	int rc;
 	
-	if ((nvram = of_find_node_by_type(NULL, "nvram")) != NULL) {
-		nbytes_p = (unsigned int *)get_property(nvram, "#bytes", &proplen);
-		if (nbytes_p && proplen == sizeof(unsigned int)) {
-			nvram_size = *nbytes_p;
-		} else {
-			return -EIO;
-		}
-	}
-	nvram_fetch = rtas_token("nvram-fetch");
-	nvram_store = rtas_token("nvram-store");
-	printk(KERN_INFO "PPC64 nvram contains %d bytes\n", nvram_size);
-	of_node_put(nvram);
-
-  	rc = misc_register(&nvram_dev);
-  
-  	/* If we don't know how big NVRAM is then we shouldn't touch
-  	   the nvram partitions */
-  	if (nvram == NULL) {
-  		return rc;
-  	}
-  	
-  	/* initialize our anchor for the nvram partition list */
-  	nvram_part = (struct nvram_partition *) kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
-  	if (!nvram_part) {
-  		printk(KERN_ERR "nvram_init: Failed kmalloc\n");
-  		return -ENOMEM;
-  	}
-  	INIT_LIST_HEAD(&nvram_part->partition);
-  
-  	/* Get all the NVRAM partitions */
-  	error = nvram_scan_partitions();
-  	if (error) {
-  		printk(KERN_ERR "nvram_init: Failed nvram_scan_partitions\n");
-  		return error;
-  	}
-  		
-  	if(nvram_setup_partition()) 
-  		printk(KERN_WARNING "nvram_init: Could not find nvram partition"
-  		       " for nvram buffered error logging.\n");
-  
-#ifdef DEBUG_NVRAM
-	nvram_print_partitions("NVRAM Partitions");
-#endif
+	tmp_index = part->index;
+	rc = ppc_md.nvram_write((char *)&part->header, NVRAM_HEADER_LEN, &tmp_index); 
 
-  	return rc;
+	return rc;
 }
 
-void __exit nvram_cleanup(void)
-{
-        misc_deregister( &nvram_dev );
-}
 
-static int nvram_scan_partitions(void)
+static unsigned char nvram_checksum(struct nvram_header *p)
 {
-	loff_t cur_index = 0;
-	struct nvram_header phead;
-	struct nvram_partition * tmp_part;
-	unsigned char c_sum;
-	char * header;
-	long size;
-	
-	header = (char *) kmalloc(NVRAM_HEADER_LEN, GFP_KERNEL);
-	if (!header) {
-		printk(KERN_ERR "nvram_scan_partitions: Failed kmalloc\n");
-		return -ENOMEM;
-	}
-
-	while (cur_index < nvram_size) {
-
-		size = ppc_md.nvram_read(header, NVRAM_HEADER_LEN, &cur_index);
-		if (size != NVRAM_HEADER_LEN) {
-			printk(KERN_ERR "nvram_scan_partitions: Error parsing "
-			       "nvram partitions\n");
-			kfree(header);
-			return size;
-		}
-
-		cur_index -= NVRAM_HEADER_LEN; /* nvram_read will advance us */
-
-		memcpy(&phead, header, NVRAM_HEADER_LEN);
-
-		c_sum = nvram_checksum(&phead);
-		if (c_sum != phead.checksum)
-			printk(KERN_WARNING "WARNING: nvram partition checksum "
-			       "was %02x, should be %02x!\n", phead.checksum, c_sum);
-		
-		tmp_part = (struct nvram_partition *)
-			kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
-		if (!tmp_part) {
-			printk(KERN_ERR "nvram_scan_partitions: kmalloc failed\n");
-			kfree(header);
-			return -ENOMEM;
-		}
-		
-		memcpy(&tmp_part->header, &phead, NVRAM_HEADER_LEN);
-		tmp_part->index = cur_index;
-		list_add_tail(&tmp_part->partition, &nvram_part->partition);
-		
-		cur_index += phead.length * NVRAM_BLOCK_LEN;
-	}
+	unsigned int c_sum, c_sum2;
+	unsigned short *sp = (unsigned short *)p->name; /* assume 6 shorts */
+	c_sum = p->signature + p->length + sp[0] + sp[1] + sp[2] + sp[3] + sp[4] + sp[5];
 
-	kfree(header);
-	return 0;
+	/* The sum may have spilled into the 3rd byte.  Fold it back. */
+	c_sum = ((c_sum & 0xffff) + (c_sum >> 16)) & 0xffff;
+	/* The sum cannot exceed 2 bytes.  Fold it into a checksum */
+	c_sum2 = (c_sum >> 8) + (c_sum << 8);
+	c_sum = ((c_sum + c_sum2) >> 8) & 0xff;
+	return c_sum;
 }
 
-/* nvram_setup_partition
- *
- * This will setup the partition we need for buffering the
- * error logs and cleanup partitions if needed.
- *
- * The general strategy is the following:
- * 1.) If there is ppc64,linux partition large enough then use it.
- * 2.) If there is not a ppc64,linux partition large enough, search
- * for a free partition that is large enough.
- * 3.) If there is not a free partition large enough remove 
- * _all_ OS partitions and consolidate the space.
- * 4.) Will first try getting a chunk that will satisfy the maximum
- * error log size (NVRAM_MAX_REQ).
- * 5.) If the max chunk cannot be allocated then try finding a chunk
- * that will satisfy the minum needed (NVRAM_MIN_REQ).
+
+/*
+ * Find an nvram partition, sig can be 0 for any
+ * partition or name can be NULL for any name, else
+ * tries to match both
  */
-static int nvram_setup_partition(void)
+struct nvram_partition *nvram_find_partition(int sig, const char *name)
 {
-	struct list_head * p;
 	struct nvram_partition * part;
-	int rc;
+	struct list_head * p;
 
-	/* see if we have an OS partition that meets our needs.
-	   will try getting the max we need.  If not we'll delete
-	   partitions and try again. */
 	list_for_each(p, &nvram_part->partition) {
 		part = list_entry(p, struct nvram_partition, partition);
-		if (part->header.signature != NVRAM_SIG_OS)
-			continue;
 
-		if (strcmp(part->header.name, "ppc64,linux"))
+		if (sig && part->header.signature != sig)
 			continue;
-
-		if (part->header.length >= NVRAM_MIN_REQ) {
-			/* found our partition */
-			nvram_error_log_index = part->index + NVRAM_HEADER_LEN;
-			nvram_error_log_size = ((part->header.length - 1) *
-						NVRAM_BLOCK_LEN) - sizeof(struct err_log_info);
-			return 0;
-		}
-	}
-	
-	/* try creating a partition with the free space we have */
-	rc = nvram_create_os_partition();
-	if (!rc) {
-		return 0;
-	}
-		
-	/* need to free up some space */
-	rc = nvram_remove_os_partition();
-	if (rc) {
-		return rc;
-	}
-	
-	/* create a partition in this new space */
-	rc = nvram_create_os_partition();
-	if (rc) {
-		printk(KERN_ERR "nvram_create_os_partition: Could not find a "
-		       "NVRAM partition large enough\n");
-		return rc;
+		if (name && 0 != strncmp(name, part->header.name, 12))
+			continue;
+		return part; 
 	}
-	
-	return 0;
+	return NULL;
 }
+EXPORT_SYMBOL(nvram_find_partition);
+
 
 static int nvram_remove_os_partition(void)
 {
@@ -572,22 +424,185 @@
 }
 
 
-void nvram_print_partitions(char * label)
+/* nvram_setup_partition
+ *
+ * This will setup the partition we need for buffering the
+ * error logs and cleanup partitions if needed.
+ *
+ * The general strategy is the following:
+ * 1.) If there is ppc64,linux partition large enough then use it.
+ * 2.) If there is not a ppc64,linux partition large enough, search
+ * for a free partition that is large enough.
+ * 3.) If there is not a free partition large enough remove 
+ * _all_ OS partitions and consolidate the space.
+ * 4.) Will first try getting a chunk that will satisfy the maximum
+ * error log size (NVRAM_MAX_REQ).
+ * 5.) If the max chunk cannot be allocated then try finding a chunk
+ * that will satisfy the minum needed (NVRAM_MIN_REQ).
+ */
+static int nvram_setup_partition(void)
 {
 	struct list_head * p;
+	struct nvram_partition * part;
+	int rc;
+
+	/* For now, we don't do any of this on pmac, until I
+	 * have figured out if it's worth killing some unused stuffs
+	 * in our nvram, as Apple defined partitions use pretty much
+	 * all of the space
+	 */
+	if (systemcfg->platform == PLATFORM_POWERMAC)
+		return -ENOSPC;
+
+	/* see if we have an OS partition that meets our needs.
+	   will try getting the max we need.  If not we'll delete
+	   partitions and try again. */
+	list_for_each(p, &nvram_part->partition) {
+		part = list_entry(p, struct nvram_partition, partition);
+		if (part->header.signature != NVRAM_SIG_OS)
+			continue;
+
+		if (strcmp(part->header.name, "ppc64,linux"))
+			continue;
+
+		if (part->header.length >= NVRAM_MIN_REQ) {
+			/* found our partition */
+			nvram_error_log_index = part->index + NVRAM_HEADER_LEN;
+			nvram_error_log_size = ((part->header.length - 1) *
+						NVRAM_BLOCK_LEN) - sizeof(struct err_log_info);
+			return 0;
+		}
+	}
+	
+	/* try creating a partition with the free space we have */
+	rc = nvram_create_os_partition();
+	if (!rc) {
+		return 0;
+	}
+		
+	/* need to free up some space */
+	rc = nvram_remove_os_partition();
+	if (rc) {
+		return rc;
+	}
+	
+	/* create a partition in this new space */
+	rc = nvram_create_os_partition();
+	if (rc) {
+		printk(KERN_ERR "nvram_create_os_partition: Could not find a "
+		       "NVRAM partition large enough\n");
+		return rc;
+	}
+	
+	return 0;
+}
+
+
+static int nvram_scan_partitions(void)
+{
+	loff_t cur_index = 0;
+	struct nvram_header phead;
 	struct nvram_partition * tmp_part;
+	unsigned char c_sum;
+	char * header;
+	long size;
+	int total_size;
+
+	if (ppc_md.nvram_size == NULL)
+		return -ENODEV;
+	total_size = ppc_md.nvram_size();
 	
-	printk(KERN_WARNING "--------%s---------\n", label);
-	printk(KERN_WARNING "indx\t\tsig\tchks\tlen\tname\n");
-	list_for_each(p, &nvram_part->partition) {
-		tmp_part = list_entry(p, struct nvram_partition, partition);
-		printk(KERN_WARNING "%d    \t%02x\t%02x\t%d\t%s\n",
-		       tmp_part->index, tmp_part->header.signature,
-		       tmp_part->header.checksum, tmp_part->header.length,
-		       tmp_part->header.name);
+	header = (char *) kmalloc(NVRAM_HEADER_LEN, GFP_KERNEL);
+	if (!header) {
+		printk(KERN_ERR "nvram_scan_partitions: Failed kmalloc\n");
+		return -ENOMEM;
+	}
+
+	while (cur_index < total_size) {
+
+		size = ppc_md.nvram_read(header, NVRAM_HEADER_LEN, &cur_index);
+		if (size != NVRAM_HEADER_LEN) {
+			printk(KERN_ERR "nvram_scan_partitions: Error parsing "
+			       "nvram partitions\n");
+			kfree(header);
+			return size;
+		}
+
+		cur_index -= NVRAM_HEADER_LEN; /* nvram_read will advance us */
+
+		memcpy(&phead, header, NVRAM_HEADER_LEN);
+
+		c_sum = nvram_checksum(&phead);
+		if (c_sum != phead.checksum)
+			printk(KERN_WARNING "WARNING: nvram partition checksum "
+			       "was %02x, should be %02x!\n", phead.checksum, c_sum);
+		
+		tmp_part = (struct nvram_partition *)
+			kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
+		if (!tmp_part) {
+			printk(KERN_ERR "nvram_scan_partitions: kmalloc failed\n");
+			kfree(header);
+			return -ENOMEM;
+		}
+		
+		memcpy(&tmp_part->header, &phead, NVRAM_HEADER_LEN);
+		tmp_part->index = cur_index;
+		list_add_tail(&tmp_part->partition, &nvram_part->partition);
+		
+		cur_index += phead.length * NVRAM_BLOCK_LEN;
 	}
+
+	kfree(header);
+	return 0;
 }
 
+static int __init nvram_init(void)
+{
+	int error;
+	int rc;
+	
+	if (ppc_md.nvram_size == NULL || ppc_md.nvram_size() <= 0)
+		return  -ENODEV;
+
+  	rc = misc_register(&nvram_dev);
+	if (rc != 0) {
+		printk(KERN_ERR "nvram_init: failed to register device\n");
+		return rc;
+	}
+  	
+  	/* initialize our anchor for the nvram partition list */
+  	nvram_part = (struct nvram_partition *) kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
+  	if (!nvram_part) {
+  		printk(KERN_ERR "nvram_init: Failed kmalloc\n");
+  		return -ENOMEM;
+  	}
+  	INIT_LIST_HEAD(&nvram_part->partition);
+  
+  	/* Get all the NVRAM partitions */
+  	error = nvram_scan_partitions();
+  	if (error) {
+  		printk(KERN_ERR "nvram_init: Failed nvram_scan_partitions\n");
+  		return error;
+  	}
+  		
+  	if(nvram_setup_partition()) 
+  		printk(KERN_WARNING "nvram_init: Could not find nvram partition"
+  		       " for nvram buffered error logging.\n");
+  
+#ifdef DEBUG_NVRAM
+	nvram_print_partitions("NVRAM Partitions");
+#endif
+
+  	return rc;
+}
+
+void __exit nvram_cleanup(void)
+{
+        misc_deregister( &nvram_dev );
+}
+
+
+
 /* nvram_write_error_log
  *
  * We need to buffer the error logs into nvram to ensure that we have
@@ -711,30 +726,6 @@
 	return 0;
 }
 
-static int nvram_write_header(struct nvram_partition * part)
-{
-	loff_t tmp_index;
-	int rc;
-	
-	tmp_index = part->index;
-	rc = ppc_md.nvram_write((char *)&part->header, NVRAM_HEADER_LEN, &tmp_index); 
-
-	return rc;
-}
-
-static unsigned char nvram_checksum(struct nvram_header *p)
-{
-	unsigned int c_sum, c_sum2;
-	unsigned short *sp = (unsigned short *)p->name; /* assume 6 shorts */
-	c_sum = p->signature + p->length + sp[0] + sp[1] + sp[2] + sp[3] + sp[4] + sp[5];
-
-	/* The sum may have spilled into the 3rd byte.  Fold it back. */
-	c_sum = ((c_sum & 0xffff) + (c_sum >> 16)) & 0xffff;
-	/* The sum cannot exceed 2 bytes.  Fold it into a checksum */
-	c_sum2 = (c_sum >> 8) + (c_sum << 8);
-	c_sum = ((c_sum + c_sum2) >> 8) & 0xff;
-	return c_sum;
-}
 
 module_init(nvram_init);
 module_exit(nvram_cleanup);
diff -Nru a/arch/ppc64/kernel/of_device.c b/arch/ppc64/kernel/of_device.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc64/kernel/of_device.c	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,272 @@
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <asm/errno.h>
+#include <asm/of_device.h>
+
+/**
+ * of_match_device - Tell if an of_device structure has a matching
+ * of_match structure
+ * @ids: array of of device match structures to search in
+ * @dev: the of device structure to match against
+ *
+ * Used by a driver to check whether an of_device present in the
+ * system is in its list of supported devices.
+ */
+const struct of_match * of_match_device(const struct of_match *matches,
+					const struct of_device *dev)
+{
+	if (!dev->node)
+		return NULL;
+	while (matches->name || matches->type || matches->compatible) {
+		int match = 1;
+		if (matches->name && matches->name != OF_ANY_MATCH)
+			match &= dev->node->name
+				&& !strcmp(matches->name, dev->node->name);
+		if (matches->type && matches->type != OF_ANY_MATCH)
+			match &= dev->node->type
+				&& !strcmp(matches->type, dev->node->type);
+		if (matches->compatible && matches->compatible != OF_ANY_MATCH)
+			match &= device_is_compatible(dev->node,
+				matches->compatible);
+		if (match)
+			return matches;
+		matches++;
+	}
+	return NULL;
+}
+
+static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct of_device * of_dev = to_of_device(dev);
+	struct of_platform_driver * of_drv = to_of_platform_driver(drv);
+	const struct of_match * matches = of_drv->match_table;
+
+	if (!matches)
+		return 0;
+
+	return of_match_device(matches, of_dev) != NULL;
+}
+
+struct of_device *of_dev_get(struct of_device *dev)
+{
+	struct device *tmp;
+
+	if (!dev)
+		return NULL;
+	tmp = get_device(&dev->dev);
+	if (tmp)
+		return to_of_device(tmp);
+	else
+		return NULL;
+}
+
+void of_dev_put(struct of_device *dev)
+{
+	if (dev)
+		put_device(&dev->dev);
+}
+
+
+static int of_device_probe(struct device *dev)
+{
+	int error = -ENODEV;
+	struct of_platform_driver *drv;
+	struct of_device *of_dev;
+	const struct of_match *match;
+
+	drv = to_of_platform_driver(dev->driver);
+	of_dev = to_of_device(dev);
+
+	if (!drv->probe)
+		return error;
+
+	of_dev_get(of_dev);
+
+	match = of_match_device(drv->match_table, of_dev);
+	if (match)
+		error = drv->probe(of_dev, match);
+	if (error)
+		of_dev_put(of_dev);
+
+	return error;
+}
+
+static int of_device_remove(struct device *dev)
+{
+	struct of_device * of_dev = to_of_device(dev);
+	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
+
+	if (dev->driver && drv->remove)
+		drv->remove(of_dev);
+	return 0;
+}
+
+static int of_device_suspend(struct device *dev, u32 state)
+{
+	struct of_device * of_dev = to_of_device(dev);
+	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
+	int error = 0;
+
+	if (dev->driver && drv->suspend)
+		error = drv->suspend(of_dev, state);
+	return error;
+}
+
+static int of_device_resume(struct device * dev)
+{
+	struct of_device * of_dev = to_of_device(dev);
+	struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
+	int error = 0;
+
+	if (dev->driver && drv->resume)
+		error = drv->resume(of_dev);
+	return error;
+}
+
+struct bus_type of_platform_bus_type = {
+       .name	= "of_platform",
+       .match	= of_platform_bus_match,
+       .suspend	= of_device_suspend,
+       .resume	= of_device_resume,
+};
+
+static int __init of_bus_driver_init(void)
+{
+	return bus_register(&of_platform_bus_type);
+}
+
+postcore_initcall(of_bus_driver_init);
+
+int of_register_driver(struct of_platform_driver *drv)
+{
+	int count = 0;
+
+	/* initialize common driver fields */
+	drv->driver.name = drv->name;
+	drv->driver.bus = &of_platform_bus_type;
+	drv->driver.probe = of_device_probe;
+	drv->driver.remove = of_device_remove;
+
+	/* register with core */
+	count = driver_register(&drv->driver);
+	return count ? count : 1;
+}
+
+void of_unregister_driver(struct of_platform_driver *drv)
+{
+	driver_unregister(&drv->driver);
+}
+
+
+static ssize_t dev_show_devspec(struct device *dev, char *buf)
+{
+	struct of_device *ofdev;
+
+	ofdev = to_of_device(dev);
+	return sprintf(buf, "%s", ofdev->node->full_name);
+}
+
+static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
+
+/**
+ * of_release_dev - free an of device structure when all users of it are finished.
+ * @dev: device that's been disconnected
+ *
+ * Will be called only by the device core when all users of this of device are
+ * done.
+ */
+void of_release_dev(struct device *dev)
+{
+	struct of_device *ofdev;
+
+        ofdev = to_of_device(dev);
+	kfree(ofdev);
+}
+
+int of_device_register(struct of_device *ofdev)
+{
+	int rc;
+	struct of_device **odprop;
+
+	BUG_ON(ofdev->node == NULL);
+
+	odprop = (struct of_device **)get_property(ofdev->node, "linux,device", NULL);
+	if (!odprop) {
+		struct property *new_prop;
+	
+		new_prop = kmalloc(sizeof(struct property) + sizeof(struct of_device *),
+			GFP_KERNEL);
+		if (new_prop == NULL)
+			return -ENOMEM;
+		new_prop->name = "linux,device";
+		new_prop->length = sizeof(sizeof(struct of_device *));
+		new_prop->value = (unsigned char *)&new_prop[1];
+		odprop = (struct of_device **)new_prop->value;
+		*odprop = NULL;
+		prom_add_property(ofdev->node, new_prop);
+	}
+	*odprop = ofdev;
+
+	rc = device_register(&ofdev->dev);
+	if (rc)
+		return rc;
+
+	device_create_file(&ofdev->dev, &dev_attr_devspec);
+
+	return 0;
+}
+
+void of_device_unregister(struct of_device *ofdev)
+{
+	struct of_device **odprop;
+
+	device_remove_file(&ofdev->dev, &dev_attr_devspec);
+
+	odprop = (struct of_device **)get_property(ofdev->node, "linux,device", NULL);
+	if (odprop)
+		*odprop = NULL;
+
+	device_unregister(&ofdev->dev);
+}
+
+struct of_device* of_platform_device_create(struct device_node *np, const char *bus_id)
+{
+	struct of_device *dev;
+	u32 *reg;
+
+	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return NULL;
+	memset(dev, 0, sizeof(*dev));
+
+	dev->node = np;
+	dev->dma_mask = 0xffffffffUL;
+	dev->dev.dma_mask = &dev->dma_mask;
+	dev->dev.parent = NULL;
+	dev->dev.bus = &of_platform_bus_type;
+	dev->dev.release = of_release_dev;
+
+	reg = (u32 *)get_property(np, "reg", NULL);
+	strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);
+
+	if (of_device_register(dev) != 0) {
+		kfree(dev);
+		return NULL;
+	}
+
+	return dev;
+}
+
+EXPORT_SYMBOL(of_match_device);
+EXPORT_SYMBOL(of_platform_bus_type);
+EXPORT_SYMBOL(of_register_driver);
+EXPORT_SYMBOL(of_unregister_driver);
+EXPORT_SYMBOL(of_device_register);
+EXPORT_SYMBOL(of_device_unregister);
+EXPORT_SYMBOL(of_dev_get);
+EXPORT_SYMBOL(of_dev_put);
+EXPORT_SYMBOL(of_platform_device_create);
+EXPORT_SYMBOL(of_release_dev);
diff -Nru a/arch/ppc64/kernel/open_pic.c b/arch/ppc64/kernel/open_pic.c
--- a/arch/ppc64/kernel/open_pic.c	Wed Feb 11 22:14:31 2004
+++ b/arch/ppc64/kernel/open_pic.c	Wed Feb 11 22:14:31 2004
@@ -34,7 +34,42 @@
 u_int OpenPIC_NumInitSenses __initdata = 0;
 u_char *OpenPIC_InitSenses __initdata = NULL;
 
-void find_ISUs(void);
+/*
+ *  Local (static) OpenPIC Operations
+ */
+
+
+/* Global Operations */
+static void openpic_reset(void);
+static void openpic_enable_8259_pass_through(void);
+static void openpic_disable_8259_pass_through(void);
+static u_int openpic_irq(void);
+static void openpic_eoi(void);
+static u_int openpic_get_priority(void);
+static void openpic_set_priority(u_int pri);
+static u_int openpic_get_spurious(void);
+static void openpic_set_spurious(u_int vector);
+
+#ifdef CONFIG_SMP
+/* Interprocessor Interrupts */
+static void openpic_initipi(u_int ipi, u_int pri, u_int vector);
+static irqreturn_t openpic_ipi_action(int cpl, void *dev_id,
+					struct pt_regs *regs);
+#endif
+
+/* Timer Interrupts */
+static void openpic_inittimer(u_int timer, u_int pri, u_int vector);
+static void openpic_maptimer(u_int timer, u_int cpumask);
+
+/* Interrupt Sources */
+static void openpic_enable_irq(u_int irq);
+static void openpic_disable_irq(u_int irq);
+static void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity,
+			    int is_level);
+static void openpic_mapirq(u_int irq, u_int cpumask);
+static void openpic_set_sense(u_int irq, int sense);
+
+static void find_ISUs(void);
 
 static u_int NumProcessors;
 static u_int NumSources;
@@ -130,7 +165,7 @@
 
 #define GET_ISU(source)	ISU[(source) >> 4][(source) & 0xf]
 
-void __init openpic_init_IRQ(void)
+void __init pSeries_init_openpic(void)
 {
         struct device_node *np;
         int i;
@@ -359,9 +394,12 @@
 	}
 
 	/* Init all external sources */
-	for (i = 1; i < NumSources; i++) {
+	for (i = 0; i < NumSources; i++) {
 		int pri, sense;
 
+		/* skip cascade if any */
+		if (offset && i == 0)
+			continue;
 		/* the bootloader may have left it enabled (bad !) */
 		openpic_disable_irq(i+offset);
 
@@ -396,6 +434,9 @@
  */
 static int __init openpic_setup_i8259(void)
 {
+	if (systemcfg->platform == PLATFORM_POWERMAC)
+		return 0;
+
 	if (naca->interrupt_controller == IC_OPEN_PIC) {
 		/* Initialize the cascade */
 		if (request_irq(NUM_8259_INTERRUPTS, no_action, SA_INTERRUPT,
@@ -419,6 +460,14 @@
 
 void find_ISUs(void)
 {
+	/* For PowerMac, setup ISUs on base openpic */
+	if (systemcfg->platform == PLATFORM_POWERMAC) {
+		int i;
+		for (i=0; i<128; i+=0x10) {
+			ISU[i>>4] = &((struct OpenPIC *)OpenPIC_Addr)->Source[i];
+			NumISUs++;
+		}
+	}
         /* Use /interrupt-controller/reg and
          * /interrupt-controller/interrupt-ranges from OF device tree
 	 * the ISU array is setup in chrp_pci.c in ibm_add_bridges
@@ -429,11 +478,22 @@
 	/* basically each ISU is a bus, and this assumes that
 	 * open_pic_isu_count interrupts per bus are possible 
 	 * ISU == Interrupt Source
+	 *
+	 * On G5, we keep the original NumSources provided by the controller,
+	 * it's below 128, so we have room to stuff the IPIs and timers like darwin
+	 * does. We put the spurrious vector up at 0xff though.
 	 */
-	NumSources = NumISUs * 0x10;
-	openpic_vec_ipi = NumSources + open_pic_irq_offset;
-	openpic_vec_timer = openpic_vec_ipi + OPENPIC_NUM_IPI; 
-	openpic_vec_spurious = openpic_vec_timer + OPENPIC_NUM_TIMERS;
+	if (systemcfg->platform == PLATFORM_POWERMAC) {
+		openpic_vec_ipi = NumSources;
+		openpic_vec_timer = openpic_vec_ipi + 4; 
+		openpic_vec_spurious = 0xff;
+	} else {
+		NumSources = NumISUs * 0x10;
+
+		openpic_vec_ipi = NumSources + open_pic_irq_offset;
+		openpic_vec_timer = openpic_vec_ipi + OPENPIC_NUM_IPI; 
+		openpic_vec_spurious = openpic_vec_timer + OPENPIC_NUM_TIMERS;
+	}
 }
 
 static inline void openpic_reset(void)
@@ -767,8 +827,7 @@
 
 static void openpic_end_irq(unsigned int irq_nr)
 {
-	if ((irq_desc[irq_nr].status & IRQ_LEVEL) != 0)
-		openpic_eoi();
+	openpic_eoi();
 }
 
 static void openpic_set_affinity(unsigned int irq_nr, cpumask_t cpumask)
@@ -807,9 +866,7 @@
 
 	int irq = openpic_irq();
 
-	/* Management of the cascade should be moved out of here */
-        if (open_pic_irq_offset && irq == open_pic_irq_offset)
-        {
+        if (open_pic_irq_offset && irq == open_pic_irq_offset) {
                 /*
                  * This magic address generates a PCI IACK cycle.
                  */
diff -Nru a/arch/ppc64/kernel/open_pic.h b/arch/ppc64/kernel/open_pic.h
--- a/arch/ppc64/kernel/open_pic.h	Wed Feb 11 22:14:30 2004
+++ b/arch/ppc64/kernel/open_pic.h	Wed Feb 11 22:14:30 2004
@@ -40,6 +40,8 @@
 
 extern inline int openpic_to_irq(int irq)
 {
+	if (systemcfg->platform == PLATFORM_POWERMAC)
+		return irq;
 	return irq += NUM_8259_INTERRUPTS;
 }
 /*extern int open_pic_irq_offset;*/
diff -Nru a/arch/ppc64/kernel/open_pic_defs.h b/arch/ppc64/kernel/open_pic_defs.h
--- a/arch/ppc64/kernel/open_pic_defs.h	Wed Feb 11 22:14:31 2004
+++ b/arch/ppc64/kernel/open_pic_defs.h	Wed Feb 11 22:14:31 2004
@@ -279,40 +279,6 @@
 #define Vector_Priority			_Vector_Priority.Reg
 #define Destination			_Destination.Reg
 
-/*
- *  Local (static) OpenPIC Operations
- */
-
-
-/* Global Operations */
-static void openpic_reset(void);
-static void openpic_enable_8259_pass_through(void);
-static void openpic_disable_8259_pass_through(void);
-static u_int openpic_irq(void);
-static void openpic_eoi(void);
-static u_int openpic_get_priority(void);
-static void openpic_set_priority(u_int pri);
-static u_int openpic_get_spurious(void);
-static void openpic_set_spurious(u_int vector);
-
-#ifdef CONFIG_SMP
-/* Interprocessor Interrupts */
-static void openpic_initipi(u_int ipi, u_int pri, u_int vector);
-static irqreturn_t openpic_ipi_action(int cpl, void *dev_id,
-					struct pt_regs *regs);
-#endif
-
-/* Timer Interrupts */
-static void openpic_inittimer(u_int timer, u_int pri, u_int vector);
-static void openpic_maptimer(u_int timer, u_int cpumask);
-
-/* Interrupt Sources */
-static void openpic_enable_irq(u_int irq);
-static void openpic_disable_irq(u_int irq);
-static void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity,
-			    int is_level);
-static void openpic_mapirq(u_int irq, u_int cpumask);
-static void openpic_set_sense(u_int irq, int sense);
 
 #endif /* __KERNEL__ */
 
diff -Nru a/arch/ppc64/kernel/open_pic_u3.c b/arch/ppc64/kernel/open_pic_u3.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc64/kernel/open_pic_u3.c	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,348 @@
+/*
+ *  arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling
+ *
+ *  Copyright (C) 1997 Geert Uytterhoeven
+ *
+ *  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/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <asm/ptrace.h>
+#include <asm/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+
+#include <asm/machdep.h>
+
+#include "open_pic.h"
+#include "open_pic_defs.h"
+
+void* OpenPIC2_Addr;
+static volatile struct OpenPIC *OpenPIC2 = NULL;
+
+extern u_int OpenPIC_NumInitSenses;
+extern u_char *OpenPIC_InitSenses;
+
+static u_int NumSources;
+static int NumISUs;
+static int open_pic2_irq_offset;
+
+static OpenPIC_SourcePtr ISU2[OPENPIC_MAX_ISU];
+
+unsigned int openpic2_vec_spurious;
+
+/*
+ *  Accesses to the current processor's openpic registers
+ *  U3 secondary openpic has only one output
+ */
+#define THIS_CPU		Processor[0]
+#define DECL_THIS_CPU
+#define CHECK_THIS_CPU
+
+#define GET_ISU(source)	ISU2[(source) >> 4][(source) & 0xf]
+
+static inline u_int openpic2_read(volatile u_int *addr)
+{
+	u_int val;
+
+	val = in_be32(addr);
+	return val;
+}
+
+static inline void openpic2_write(volatile u_int *addr, u_int val)
+{
+	out_be32(addr, val);
+}
+
+static inline u_int openpic2_readfield(volatile u_int *addr, u_int mask)
+{
+	u_int val = openpic2_read(addr);
+	return val & mask;
+}
+
+static inline void openpic2_writefield(volatile u_int *addr, u_int mask,
+			       u_int field)
+{
+	u_int val = openpic2_read(addr);
+	openpic2_write(addr, (val & ~mask) | (field & mask));
+}
+
+static inline void openpic2_clearfield(volatile u_int *addr, u_int mask)
+{
+	openpic2_writefield(addr, mask, 0);
+}
+
+static inline void openpic2_setfield(volatile u_int *addr, u_int mask)
+{
+	openpic2_writefield(addr, mask, mask);
+}
+
+static void openpic2_safe_writefield(volatile u_int *addr, u_int mask,
+				    u_int field)
+{
+	unsigned int loops = 100000;
+
+	openpic2_setfield(addr, OPENPIC_MASK);
+	while (openpic2_read(addr) & OPENPIC_ACTIVITY) {
+		if (!loops--) {
+			printk(KERN_ERR "openpic2_safe_writefield timeout\n");
+			break;
+		}
+	}
+	openpic2_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
+}
+
+
+static inline void openpic2_reset(void)
+{
+	openpic2_setfield(&OpenPIC2->Global.Global_Configuration0,
+			 OPENPIC_CONFIG_RESET);
+}
+
+static void openpic2_disable_8259_pass_through(void)
+{
+	openpic2_setfield(&OpenPIC2->Global.Global_Configuration0,
+			 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
+}
+
+/*
+ *  Find out the current interrupt
+ */
+static u_int openpic2_irq(void)
+{
+	u_int vec;
+	DECL_THIS_CPU;
+	CHECK_THIS_CPU;
+	vec = openpic2_readfield(&OpenPIC2->THIS_CPU.Interrupt_Acknowledge,
+				 OPENPIC_VECTOR_MASK);
+	return vec;
+}
+
+static void openpic2_eoi(void)
+{
+	DECL_THIS_CPU;
+	CHECK_THIS_CPU;
+	openpic2_write(&OpenPIC2->THIS_CPU.EOI, 0);
+	/* Handle PCI write posting */
+	(void)openpic2_read(&OpenPIC2->THIS_CPU.EOI);
+}
+
+
+static inline u_int openpic2_get_priority(void)
+{
+	DECL_THIS_CPU;
+	CHECK_THIS_CPU;
+	return openpic2_readfield(&OpenPIC2->THIS_CPU.Current_Task_Priority,
+				  OPENPIC_CURRENT_TASK_PRIORITY_MASK);
+}
+
+static void openpic2_set_priority(u_int pri)
+{
+	DECL_THIS_CPU;
+	CHECK_THIS_CPU;
+	openpic2_writefield(&OpenPIC2->THIS_CPU.Current_Task_Priority,
+			    OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri);
+}
+
+/*
+ *  Get/set the spurious vector
+ */
+static inline u_int openpic2_get_spurious(void)
+{
+	return openpic2_readfield(&OpenPIC2->Global.Spurious_Vector,
+				  OPENPIC_VECTOR_MASK);
+}
+
+static void openpic2_set_spurious(u_int vec)
+{
+	openpic2_writefield(&OpenPIC2->Global.Spurious_Vector, OPENPIC_VECTOR_MASK,
+			    vec);
+}
+
+/*
+ *  Enable/disable an external interrupt source
+ *
+ *  Externally called, irq is an offseted system-wide interrupt number
+ */
+static void openpic2_enable_irq(u_int irq)
+{
+	unsigned int loops = 100000;
+
+	openpic2_clearfield(&GET_ISU(irq - open_pic2_irq_offset).Vector_Priority, OPENPIC_MASK);
+	/* make sure mask gets to controller before we return to user */
+	do {
+		if (!loops--) {
+			printk(KERN_ERR "openpic_enable_irq timeout\n");
+			break;
+		}
+
+		mb(); /* sync is probably useless here */
+	} while(openpic2_readfield(&GET_ISU(irq - open_pic2_irq_offset).Vector_Priority,
+			OPENPIC_MASK));
+}
+
+static void openpic2_disable_irq(u_int irq)
+{
+	u32 vp;
+	unsigned int loops = 100000;
+	
+	openpic2_setfield(&GET_ISU(irq - open_pic2_irq_offset).Vector_Priority,
+			  OPENPIC_MASK);
+	/* make sure mask gets to controller before we return to user */
+	do {
+		if (!loops--) {
+			printk(KERN_ERR "openpic_disable_irq timeout\n");
+			break;
+		}
+
+		mb();  /* sync is probably useless here */
+		vp = openpic2_readfield(&GET_ISU(irq - open_pic2_irq_offset).Vector_Priority,
+    			OPENPIC_MASK | OPENPIC_ACTIVITY);
+	} while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK));
+}
+
+/*
+ *  Initialize an interrupt source (and disable it!)
+ *
+ *  irq: OpenPIC interrupt number
+ *  pri: interrupt source priority
+ *  vec: the vector it will produce
+ *  pol: polarity (1 for positive, 0 for negative)
+ *  sense: 1 for level, 0 for edge
+ */
+static void openpic2_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
+{
+	openpic2_safe_writefield(&GET_ISU(irq).Vector_Priority,
+				 OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
+				 OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK,
+				 (pri << OPENPIC_PRIORITY_SHIFT) | vec |
+				 (pol ? OPENPIC_POLARITY_POSITIVE :
+				  OPENPIC_POLARITY_NEGATIVE) |
+				 (sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE));
+}
+
+/*
+ *  Map an interrupt source to one or more CPUs
+ */
+static void openpic2_mapirq(u_int irq, u_int physmask)
+{
+	openpic2_write(&GET_ISU(irq).Destination, physmask);
+}
+
+/*
+ *  Set the sense for an interrupt source (and disable it!)
+ *
+ *  sense: 1 for level, 0 for edge
+ */
+static inline void openpic2_set_sense(u_int irq, int sense)
+{
+	openpic2_safe_writefield(&GET_ISU(irq).Vector_Priority,
+				 OPENPIC_SENSE_LEVEL,
+				 (sense ? OPENPIC_SENSE_LEVEL : 0));
+}
+
+static void openpic2_end_irq(unsigned int irq_nr)
+{
+	openpic2_eoi();
+}
+
+int openpic2_get_irq(struct pt_regs *regs)
+{
+	int irq = openpic2_irq();
+
+	if (irq == openpic2_vec_spurious)
+		return -1;
+	return irq + open_pic2_irq_offset;
+}
+
+struct hw_interrupt_type open_pic2 = {
+	" OpenPIC2 ",
+	NULL,
+	NULL,
+	openpic2_enable_irq,
+	openpic2_disable_irq,
+	NULL,
+	openpic2_end_irq,
+};
+
+void __init openpic2_init(int offset)
+{
+	u_int t, i;
+	const char *version;
+
+	if (!OpenPIC2_Addr) {
+		printk(KERN_INFO "No OpenPIC2 found !\n");
+		return;
+	}
+	OpenPIC2 = (volatile struct OpenPIC *)OpenPIC2_Addr;
+
+	ppc64_boot_msg(0x20, "OpenPic U3 Init");
+
+	t = openpic2_read(&OpenPIC2->Global.Feature_Reporting0);
+	switch (t & OPENPIC_FEATURE_VERSION_MASK) {
+	case 1:
+		version = "1.0";
+		break;
+	case 2:
+		version = "1.2";
+		break;
+	case 3:
+		version = "1.3";
+		break;
+	default:
+		version = "?";
+		break;
+	}
+	printk(KERN_INFO "OpenPIC (U3) Version %s\n", version);
+
+	open_pic2_irq_offset = offset;
+
+	for (i=0; i<128; i+=0x10) {
+		ISU2[i>>4] = &((struct OpenPIC *)OpenPIC2_Addr)->Source[i];
+		NumISUs++;
+	}
+	NumSources = NumISUs * 0x10;
+	openpic2_vec_spurious = NumSources;
+
+	openpic2_set_priority(0xf);
+
+	/* Init all external sources */
+	for (i = 0; i < NumSources; i++) {
+		int pri, sense;
+
+		/* the bootloader may have left it enabled (bad !) */
+		openpic2_disable_irq(i+offset);
+
+		pri = 8;
+		sense = (i < OpenPIC_NumInitSenses) ? OpenPIC_InitSenses[i]: 1;
+		if (sense)
+			irq_desc[i+offset].status = IRQ_LEVEL;
+
+		/* Enabled, Priority 8 or 9 */
+		openpic2_initirq(i, pri, i, !sense, sense);
+		/* Processor 0 */
+		openpic2_mapirq(i, 0x1);
+	}
+
+	/* Init descriptors */
+	for (i = offset; i < NumSources + offset; i++)
+		irq_desc[i].handler = &open_pic2;
+
+	/* Initialize the spurious interrupt */
+	openpic2_set_spurious(openpic2_vec_spurious);
+
+	openpic2_set_priority(0);
+	openpic2_disable_8259_pass_through();
+
+	ppc64_boot_msg(0x25, "OpenPic2 Done");
+}
diff -Nru a/arch/ppc64/kernel/pSeries_nvram.c b/arch/ppc64/kernel/pSeries_nvram.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc64/kernel/pSeries_nvram.c	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,150 @@
+/*
+ *  c 2001 PPC 64 Team, IBM Corp
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ *
+ * /dev/nvram driver for PPC64
+ *
+ * This perhaps should live in drivers/char
+ */
+
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/fcntl.h>
+#include <linux/nvram.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <asm/uaccess.h>
+#include <asm/nvram.h>
+#include <asm/rtas.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+
+static unsigned int nvram_size;
+static unsigned int nvram_fetch, nvram_store;
+static char nvram_buf[NVRW_CNT];	/* assume this is in the first 4GB */
+static spinlock_t nvram_lock = SPIN_LOCK_UNLOCKED;
+
+
+static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index)
+{
+	unsigned int i;
+	unsigned long len, done;
+	unsigned long flags;
+	char *p = buf;
+
+	if (nvram_size == 0 || nvram_fetch)
+		return -ENODEV;
+
+	if (*index >= nvram_size)
+		return 0;
+
+	i = *index;
+	if (i + count > nvram_size)
+		count = nvram_size - i;
+
+	spin_lock_irqsave(&nvram_lock, flags);
+
+	for (; count != 0; count -= len) {
+		len = count;
+		if (len > NVRW_CNT)
+			len = NVRW_CNT;
+		
+		if ((rtas_call(nvram_fetch, 3, 2, &done, i, __pa(nvram_buf),
+			       len) != 0) || len != done) {
+			spin_unlock_irqrestore(&nvram_lock, flags);
+			return -EIO;
+		}
+		
+		memcpy(p, nvram_buf, len);
+
+		p += len;
+		i += len;
+	}
+
+	spin_unlock_irqrestore(&nvram_lock, flags);
+	
+	*index = i;
+	return p - buf;
+}
+
+static ssize_t pSeries_nvram_write(char *buf, size_t count, loff_t *index)
+{
+	unsigned int i;
+	unsigned long len, done;
+	unsigned long flags;
+	const char *p = buf;
+
+	if (nvram_size == 0 || nvram_store)
+		return -ENODEV;
+
+	if (*index >= nvram_size)
+		return 0;
+
+	i = *index;
+	if (i + count > nvram_size)
+		count = nvram_size - i;
+
+	spin_lock_irqsave(&nvram_lock, flags);
+
+	for (; count != 0; count -= len) {
+		len = count;
+		if (len > NVRW_CNT)
+			len = NVRW_CNT;
+
+		memcpy(nvram_buf, p, len);
+
+		if ((rtas_call(nvram_store, 3, 2, &done, i, __pa(nvram_buf),
+			       len) != 0) || len != done) {
+			spin_unlock_irqrestore(&nvram_lock, flags);
+			return -EIO;
+		}
+		
+		p += len;
+		i += len;
+	}
+	spin_unlock_irqrestore(&nvram_lock, flags);
+	
+	*index = i;
+	return p - buf;
+}
+
+static ssize_t pSeries_nvram_get_size(void)
+{
+	return nvram_size ? nvram_size : -ENODEV;
+}
+
+int __init pSeries_nvram_init(void)
+{
+	struct device_node *nvram;
+	unsigned int *nbytes_p, proplen;
+
+	nvram = of_find_node_by_type(NULL, "nvram");
+	if (nvram == NULL)
+		return -ENODEV;
+
+	nbytes_p = (unsigned int *)get_property(nvram, "#bytes", &proplen);
+	if (nbytes_p == NULL || proplen != sizeof(unsigned int))
+		return -EIO;
+
+	nvram_size = *nbytes_p;
+
+	nvram_fetch = rtas_token("nvram-fetch");
+	nvram_store = rtas_token("nvram-store");
+	printk(KERN_INFO "PPC64 nvram contains %d bytes\n", nvram_size);
+	of_node_put(nvram);
+
+	ppc_md.nvram_read	= pSeries_nvram_read;
+	ppc_md.nvram_write	= pSeries_nvram_write;
+	ppc_md.nvram_size	= pSeries_nvram_get_size;
+
+	return 0;
+}
diff -Nru a/arch/ppc64/kernel/pSeries_pci.c b/arch/ppc64/kernel/pSeries_pci.c
--- a/arch/ppc64/kernel/pSeries_pci.c	Wed Feb 11 22:14:31 2004
+++ b/arch/ppc64/kernel/pSeries_pci.c	Wed Feb 11 22:14:31 2004
@@ -687,7 +687,7 @@
 
 extern void chrp_request_regions(void);
 
-void __init pcibios_final_fixup(void)
+void __init pSeries_final_fixup(void)
 {
 	struct pci_dev *dev = NULL;
 
diff -Nru a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c
--- a/arch/ppc64/kernel/pci.c	Wed Feb 11 22:14:31 2004
+++ b/arch/ppc64/kernel/pci.c	Wed Feb 11 22:14:31 2004
@@ -34,6 +34,7 @@
 #include <asm/ppcdebug.h>
 #include <asm/naca.h>
 #include <asm/pci_dma.h>
+#include <asm/machdep.h>
 
 #include "pci.h"
 
@@ -58,21 +59,32 @@
 void pcibios_final_fixup(void);
 static void fixup_broken_pcnet32(struct pci_dev* dev);
 static void fixup_windbond_82c105(struct pci_dev* dev);
+extern void fixup_k2_sata(struct pci_dev* dev);
 
 void iSeries_pcibios_init(void);
 
 struct pci_controller *hose_head;
 struct pci_controller **hose_tail = &hose_head;
 
+struct pci_dma_ops pci_dma_ops;
+EXPORT_SYMBOL(pci_dma_ops);
+
 int global_phb_number;		/* Global phb counter */
 
 /* Cached ISA bridge dev. */
 struct pci_dev *ppc64_isabridge_dev = NULL;
 
 struct pci_fixup pcibios_fixups[] = {
-	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_TRIDENT,	PCI_ANY_ID, fixup_broken_pcnet32 },
-	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_WINBOND,	PCI_DEVICE_ID_WINBOND_82C105, fixup_windbond_82c105 },
-	{ PCI_FIXUP_HEADER, PCI_ANY_ID,	PCI_ANY_ID, pcibios_name_device },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_TRIDENT,		PCI_ANY_ID,
+	  fixup_broken_pcnet32 },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_WINBOND,		PCI_DEVICE_ID_WINBOND_82C105,
+	  fixup_windbond_82c105 },
+	{ PCI_FIXUP_HEADER,	PCI_ANY_ID,    			PCI_ANY_ID,
+	  pcibios_name_device },
+#ifdef CONFIG_PPC_PMAC
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SERVERWORKS,	0x0240,
+	  fixup_k2_sata },
+#endif
 	{ 0 }
 };
 
@@ -250,6 +262,9 @@
 	case phb_type_winnipeg:
 		model = "PHB WP";
 		break;
+	case phb_type_apple:
+		model = "PHB APPLE";
+		break;
 	default:
 		model = "PHB UK";
 		break;
@@ -332,8 +347,9 @@
 		pci_assign_unassigned_resources();
 #endif
 
-	/* Call machine dependent fixup */
-	pcibios_final_fixup();
+	/* Call machine dependent final fixup */
+	if (ppc_md.pcibios_fixup)
+		ppc_md.pcibios_fixup();
 
 	/* Cache the location of the ISA bridge (if we have one) */
 	ppc64_isabridge_dev = pci_find_class(PCI_CLASS_BRIDGE_ISA << 8, NULL);
@@ -539,4 +555,26 @@
 			       vma->vm_end - vma->vm_start, vma->vm_page_prot);
 
 	return ret;
+}
+
+#ifdef CONFIG_PPC_PSERIES
+static ssize_t pci_show_devspec(struct device *dev, char *buf)
+{
+	struct pci_dev *pdev;
+	struct device_node *np;
+
+	pdev = to_pci_dev (dev);
+	np = pci_device_to_OF_node(pdev);
+	if (np == NULL || np->full_name == NULL)
+		return 0;
+	return sprintf(buf, "%s", np->full_name);
+}
+static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL);
+#endif /* CONFIG_PPC_PSERIES */
+
+void pcibios_add_platform_entries(struct pci_dev *pdev)
+{
+#ifdef CONFIG_PPC_PSERIES
+	device_create_file(&pdev->dev, &dev_attr_devspec);
+#endif /* CONFIG_PPC_PSERIES */
 }
diff -Nru a/arch/ppc64/kernel/pci_dma.c b/arch/ppc64/kernel/pci_dma.c
--- a/arch/ppc64/kernel/pci_dma.c	Wed Feb 11 22:14:31 2004
+++ b/arch/ppc64/kernel/pci_dma.c	Wed Feb 11 22:14:31 2004
@@ -1002,7 +1002,7 @@
  * Returns the virtual address of the buffer and sets dma_handle
  * to the dma address (tce) of the first page.
  */
-void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+static void *tce_alloc_consistent(struct pci_dev *hwdev, size_t size,
 			   dma_addr_t *dma_handle)
 {
 	struct TceTable * tbl;
@@ -1055,7 +1055,7 @@
 	return ret;
 }
 
-void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+static void tce_free_consistent(struct pci_dev *hwdev, size_t size,
 			 void *vaddr, dma_addr_t dma_handle)
 {
 	struct TceTable * tbl;
@@ -1089,7 +1089,7 @@
  * need not be page aligned, the dma_addr_t returned will point to the same
  * byte within the page as vaddr.
  */
-dma_addr_t pci_map_single(struct pci_dev *hwdev, void *vaddr, 
+static dma_addr_t tce_map_single(struct pci_dev *hwdev, void *vaddr, 
 			  size_t size, int direction )
 {
 	struct TceTable * tbl;
@@ -1124,7 +1124,7 @@
 	return dma_handle;
 }
 
-void pci_unmap_single( struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction )
+static void tce_unmap_single( struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction )
 {
 	struct TceTable * tbl;
 	unsigned order, nPages;
@@ -1354,7 +1354,7 @@
 	return dmaAddr;
 }
 
-int pci_map_sg( struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction )
+static int tce_map_sg( struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction )
 {
 	struct TceTable * tbl;
 	unsigned numTces;
@@ -1389,7 +1389,7 @@
 	return num_dma;
 }
 
-void pci_unmap_sg( struct pci_dev *hwdev, struct scatterlist *sg, int nelms, int direction )
+static void tce_unmap_sg( struct pci_dev *hwdev, struct scatterlist *sg, int nelms, int direction )
 {
 	struct TceTable * tbl;
 	unsigned order, numTces, i;
@@ -1430,7 +1430,7 @@
 
 }
 #else
-int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems,
+static int tce_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems,
 	       int direction)
 {
 	int i;
@@ -1448,7 +1448,7 @@
 	return nelems;
 }
 
-void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems,
+static void tce_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems,
 		  int direction)
 {
 	while (nelems--) {
@@ -1465,7 +1465,15 @@
 {
 	ppc_md.tce_build = tce_build_pSeries;
 	ppc_md.tce_free_one = tce_free_one_pSeries;
+
+	pci_dma_ops.pci_alloc_consistent = tce_alloc_consistent;
+	pci_dma_ops.pci_free_consistent = tce_free_consistent;
+	pci_dma_ops.pci_map_single = tce_map_single;
+	pci_dma_ops.pci_unmap_single = tce_unmap_single;
+	pci_dma_ops.pci_map_sg = tce_map_sg;
+	pci_dma_ops.pci_unmap_sg = tce_unmap_sg;
 }
+
 #endif
 
 #ifdef CONFIG_PPC_ISERIES
@@ -1473,5 +1481,12 @@
 {
 	ppc_md.tce_build = tce_build_iSeries;
 	ppc_md.tce_free_one = tce_free_one_iSeries;
+
+	pci_dma_ops.pci_alloc_consistent = tce_alloc_consistent;
+	pci_dma_ops.pci_free_consistent = tce_free_consistent;
+	pci_dma_ops.pci_map_single = tce_map_single;
+	pci_dma_ops.pci_unmap_single = tce_unmap_single;
+	pci_dma_ops.pci_map_sg = tce_map_sg;
+	pci_dma_ops.pci_unmap_sg = tce_unmap_sg;
 }
 #endif
diff -Nru a/arch/ppc64/kernel/pci_dma_direct.c b/arch/ppc64/kernel/pci_dma_direct.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc64/kernel/pci_dma_direct.c	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,88 @@
+/*
+ * Support for DMA from PCI devices to main memory on
+ * machines without an iommu or with directly addressable
+ * RAM (typically a pmac with 2Gb of RAM or less)
+ *
+ * Copyright (C) 2003 Benjamin 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/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/mm.h>
+
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/abs_addr.h>
+
+#include "pci.h"
+
+static void *pci_direct_alloc_consistent(struct pci_dev *hwdev, size_t size,
+				   dma_addr_t *dma_handle)
+{
+	void *ret;
+
+	ret = (void *)__get_free_pages(GFP_ATOMIC, get_order(size));
+	if (ret != NULL) {
+		memset(ret, 0, size);
+		*dma_handle = virt_to_absolute((unsigned long)ret);
+	}
+	return ret;
+}
+
+static void pci_direct_free_consistent(struct pci_dev *hwdev, size_t size,
+				 void *vaddr, dma_addr_t dma_handle)
+{
+	free_pages((unsigned long)vaddr, get_order(size));
+}
+
+static dma_addr_t pci_direct_map_single(struct pci_dev *hwdev, void *ptr,
+				  size_t size, int direction)
+{
+	return virt_to_absolute((unsigned long)ptr);
+}
+
+static void pci_direct_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
+			      size_t size, int direction)
+{
+}
+
+static int pci_direct_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+		       int nents, int direction)
+{
+	int i;
+
+	for (i = 0; i < nents; i++, sg++) {
+		sg->dma_address = page_to_phys(sg->page) + sg->offset;
+		sg->dma_length = sg->length;
+	}
+
+	return nents;
+}
+
+static void pci_direct_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+			  int nents, int direction)
+{
+}
+
+void __init pci_dma_init_direct(void)
+{
+	pci_dma_ops.pci_alloc_consistent = pci_direct_alloc_consistent;
+	pci_dma_ops.pci_free_consistent = pci_direct_free_consistent;
+	pci_dma_ops.pci_map_single = pci_direct_map_single;
+	pci_dma_ops.pci_unmap_single = pci_direct_unmap_single;
+	pci_dma_ops.pci_map_sg = pci_direct_map_sg;
+	pci_dma_ops.pci_unmap_sg = pci_direct_unmap_sg;
+}
diff -Nru a/arch/ppc64/kernel/pci_dn.c b/arch/ppc64/kernel/pci_dn.c
--- a/arch/ppc64/kernel/pci_dn.c	Wed Feb 11 22:14:31 2004
+++ b/arch/ppc64/kernel/pci_dn.c	Wed Feb 11 22:14:31 2004
@@ -181,6 +181,7 @@
 	}
 	return dn;
 }
+EXPORT_SYMBOL(fetch_dev_dn);
 
 
 /******************************************************************
diff -Nru a/arch/ppc64/kernel/pmac.h b/arch/ppc64/kernel/pmac.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc64/kernel/pmac.h	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,32 @@
+#ifndef __PMAC_H__
+#define __PMAC_H__
+
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+/*
+ * Declaration for the various functions exported by the
+ * pmac_* files. Mostly for use by pmac_setup
+ */
+
+extern void pmac_get_boot_time(struct rtc_time *tm);
+extern void pmac_get_rtc_time(struct rtc_time *tm);
+extern int  pmac_set_rtc_time(struct rtc_time *tm);
+extern void pmac_read_rtc_time(void);
+extern void pmac_calibrate_decr(void);
+
+extern void pmac_pcibios_fixup(void);
+extern void pmac_pci_init(void);
+extern void pmac_setup_pci_dma(void);
+extern void fixup_k2_sata(struct pci_dev* dev);
+extern void pmac_check_ht_link(void);
+
+extern void pmac_setup_smp(void);
+
+extern unsigned long pmac_ide_get_base(int index);
+extern void pmac_ide_init_hwif_ports(hw_regs_t *hw,
+	unsigned long data_port, unsigned long ctrl_port, int *irq);
+
+extern void pmac_nvram_init(void);
+
+#endif /* __PMAC_H__ */
diff -Nru a/arch/ppc64/kernel/pmac_feature.c b/arch/ppc64/kernel/pmac_feature.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc64/kernel/pmac_feature.c	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,654 @@
+/*
+ *  arch/ppc/platforms/pmac_feature.c
+ *
+ *  Copyright (C) 1996-2001 Paul Mackerras (paulus@cs.anu.edu.au)
+ *                          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.
+ *
+ *  TODO:
+ *
+ *   - Replace mdelay with some schedule loop if possible
+ *   - Shorten some obfuscated delays on some routines (like modem
+ *     power)
+ *   - Refcount some clocks (see darwin)
+ *   - Split split split...
+ *
+ */
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <asm/sections.h>
+#include <asm/errno.h>
+#include <asm/keylargo.h>
+#include <asm/uninorth.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/dbdma.h>
+#include <asm/pci-bridge.h>
+#include <asm/pmac_low_i2c.h>
+
+#undef DEBUG_FEATURE
+
+#ifdef DEBUG_FEATURE
+#define DBG(fmt,...) printk(KERN_DEBUG fmt)
+#else
+#define DBG(fmt,...)
+#endif
+
+/*
+ * We use a single global lock to protect accesses. Each driver has
+ * to take care of its own locking
+ */
+static spinlock_t feature_lock  __pmacdata = SPIN_LOCK_UNLOCKED;
+
+#define LOCK(flags)	spin_lock_irqsave(&feature_lock, flags);
+#define UNLOCK(flags)	spin_unlock_irqrestore(&feature_lock, flags);
+
+
+/*
+ * Instance of some macio stuffs
+ */
+struct macio_chip macio_chips[MAX_MACIO_CHIPS]  __pmacdata;
+
+struct macio_chip* __pmac
+macio_find(struct device_node* child, int type)
+{
+	while(child) {
+		int	i;
+
+		for (i=0; i < MAX_MACIO_CHIPS && macio_chips[i].of_node; i++)
+			if (child == macio_chips[i].of_node &&
+			    (!type || macio_chips[i].type == type))
+				return &macio_chips[i];
+		child = child->parent;
+	}
+	return NULL;
+}
+
+static const char* macio_names[] __pmacdata =
+{
+	"Unknown",
+	"Grand Central",
+	"OHare",
+	"OHareII",
+	"Heathrow",
+	"Gatwick",
+	"Paddington",
+	"Keylargo",
+	"Pangea",
+	"Intrepid",
+	"K2"
+};
+
+
+
+/*
+ * Uninorth reg. access. Note that Uni-N regs are big endian
+ */
+
+#define UN_REG(r)	(uninorth_base + ((r) >> 2))
+#define UN_IN(r)	(in_be32(UN_REG(r)))
+#define UN_OUT(r,v)	(out_be32(UN_REG(r), (v)))
+#define UN_BIS(r,v)	(UN_OUT((r), UN_IN(r) | (v)))
+#define UN_BIC(r,v)	(UN_OUT((r), UN_IN(r) & ~(v)))
+
+static struct device_node* uninorth_node __pmacdata;
+static u32* uninorth_base __pmacdata;
+static u32 uninorth_rev __pmacdata;
+static void *u3_ht;
+
+extern struct pci_dev *k2_skiplist[2];
+
+/*
+ * For each motherboard family, we have a table of functions pointers
+ * that handle the various features.
+ */
+
+typedef long (*feature_call)(struct device_node* node, long param, long value);
+
+struct feature_table_entry {
+	unsigned int	selector;
+	feature_call	function;
+};
+
+struct pmac_mb_def
+{
+	const char*			model_string;
+	const char*			model_name;
+	int				model_id;
+	struct feature_table_entry* 	features;
+	unsigned long			board_flags;
+};
+static struct pmac_mb_def pmac_mb __pmacdata;
+
+/*
+ * Here are the chip specific feature functions
+ */
+
+
+static long __pmac g5_read_gpio(struct device_node* node, long param, long value)
+{
+	struct macio_chip* macio = &macio_chips[0];
+
+	return MACIO_IN8(param);
+}
+
+
+static long __pmac g5_write_gpio(struct device_node* node, long param, long value)
+{
+	struct macio_chip* macio = &macio_chips[0];
+
+	MACIO_OUT8(param, (u8)(value & 0xff));
+	return 0;
+}
+
+static long __pmac g5_gmac_enable(struct device_node* node, long param, long value)
+{
+	struct macio_chip* macio = &macio_chips[0];
+	unsigned long flags;
+	struct pci_dev *pdev = NULL;
+
+	if (node == NULL)
+		return -ENODEV;
+
+	/* XXX FIXME: We should fix pci_device_from_OF_node here, and
+	 * get to a real pci_dev or we'll get into trouble with PCI
+	 * domains the day we get overlapping numbers (like if we ever
+	 * decide to show the HT root.
+	 * Note that we only get the slot when value is 0. This is called
+	 * early during boot with value 1 to enable all devices, at which
+	 * point, we don't yet have probed pci_find_slot, so it would fail
+	 * to look for the slot at this point.
+	 */
+	if (!value)
+		pdev = pci_find_slot(node->busno, node->devfn);
+
+	LOCK(flags);
+	if (value) {
+		MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE);
+		mb();
+		k2_skiplist[0] = NULL;
+	} else {
+		k2_skiplist[0] = pdev;
+		mb();
+		MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE);
+	}
+	
+	UNLOCK(flags);
+	mdelay(1);
+
+	return 0;
+}
+
+static long __pmac g5_fw_enable(struct device_node* node, long param, long value)
+{
+	struct macio_chip* macio = &macio_chips[0];
+	unsigned long flags;
+	struct pci_dev *pdev = NULL;
+
+	/* XXX FIXME: We should fix pci_device_from_OF_node here, and
+	 * get to a real pci_dev or we'll get into trouble with PCI
+	 * domains the day we get overlapping numbers (like if we ever
+	 * decide to show the HT root
+	 * Note that we only get the slot when value is 0. This is called
+	 * early during boot with value 1 to enable all devices, at which
+	 * point, we don't yet have probed pci_find_slot, so it would fail
+	 * to look for the slot at this point.
+	 */
+	if (node == NULL)
+		return -ENODEV;
+
+	if (!value)
+		pdev = pci_find_slot(node->busno, node->devfn);
+
+	LOCK(flags);
+	if (value) {
+		MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE);
+		mb();
+		k2_skiplist[1] = NULL;
+	} else {
+		k2_skiplist[0] = pdev;
+		mb();
+		MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE);
+	}
+	
+	UNLOCK(flags);
+	mdelay(1);
+
+	return 0;
+}
+
+static long __pmac g5_mpic_enable(struct device_node* node, long param, long value)
+{
+	unsigned long flags;
+
+	if (node->parent == NULL || strcmp(node->parent->name, "u3"))
+		return 0;
+
+	LOCK(flags);
+	UN_BIS(U3_TOGGLE_REG, U3_MPIC_RESET | U3_MPIC_OUTPUT_ENABLE);
+	UNLOCK(flags);
+
+	return 0;
+}
+
+#ifdef CONFIG_SMP
+static long __pmac g5_reset_cpu(struct device_node* node, long param, long value)
+{
+	unsigned int reset_io = 0;
+	unsigned long flags;
+	struct macio_chip* macio;
+	struct device_node* np;
+
+	macio = &macio_chips[0];
+	if (macio->type != macio_keylargo2)
+		return -ENODEV;
+
+	np = find_path_device("/cpus");
+	if (np == NULL)
+		return -ENODEV;
+	for (np = np->child; np != NULL; np = np->sibling) {
+		u32* num = (u32 *)get_property(np, "reg", NULL);
+		u32* rst = (u32 *)get_property(np, "soft-reset", NULL);
+		if (num == NULL || rst == NULL)
+			continue;
+		if (param == *num) {
+			reset_io = *rst;
+			break;
+		}
+	}
+	if (np == NULL || reset_io == 0)
+		return -ENODEV;
+
+	LOCK(flags);
+	MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);
+	(void)MACIO_IN8(reset_io);
+	udelay(1);
+	MACIO_OUT8(reset_io, 0);
+	(void)MACIO_IN8(reset_io);
+	UNLOCK(flags);
+
+	return 0;
+}
+#endif /* CONFIG_SMP */
+
+/*
+ * This can be called from pmac_smp so isn't static
+ *
+ * This takes the second CPU off the bus on dual CPU machines
+ * running UP
+ */
+void __pmac g5_phy_disable_cpu1(void)
+{
+	UN_OUT(U3_API_PHY_CONFIG_1, 0);
+}
+
+static long __pmac generic_get_mb_info(struct device_node* node, long param, long value)
+{
+	switch(param) {
+		case PMAC_MB_INFO_MODEL:
+			return pmac_mb.model_id;
+		case PMAC_MB_INFO_FLAGS:
+			return pmac_mb.board_flags;
+		case PMAC_MB_INFO_NAME:			
+			/* hack hack hack... but should work */
+			*((const char **)value) = pmac_mb.model_name;
+			return 0;
+	}
+	return -EINVAL;
+}
+
+
+/*
+ * Table definitions
+ */
+
+/* Used on any machine
+ */
+static struct feature_table_entry any_features[]  __pmacdata = {
+	{ PMAC_FTR_GET_MB_INFO,		generic_get_mb_info },
+	{ 0, NULL }
+};
+
+/* G5 features
+ */
+static struct feature_table_entry g5_features[]  __pmacdata = {
+	{ PMAC_FTR_GMAC_ENABLE,		g5_gmac_enable },
+	{ PMAC_FTR_1394_ENABLE,		g5_fw_enable },
+	{ PMAC_FTR_ENABLE_MPIC,		g5_mpic_enable },
+	{ PMAC_FTR_READ_GPIO,		g5_read_gpio },
+	{ PMAC_FTR_WRITE_GPIO,		g5_write_gpio },
+#ifdef CONFIG_SMP
+	{ PMAC_FTR_RESET_CPU,		g5_reset_cpu },
+#endif /* CONFIG_SMP */
+	{ 0, NULL }
+};
+
+static struct pmac_mb_def pmac_mb_defs[] __pmacdata = {
+	{	"PowerMac7,2",			"PowerMac G5",
+		PMAC_TYPE_POWERMAC_G5,		g5_features,
+		0,
+	},
+};
+
+/*
+ * The toplevel feature_call callback
+ */
+long __pmac pmac_do_feature_call(unsigned int selector, ...)
+{
+	struct device_node* node;
+	long param, value;
+	int i;
+	feature_call func = NULL;
+	va_list args;
+
+	if (pmac_mb.features)
+		for (i=0; pmac_mb.features[i].function; i++)
+			if (pmac_mb.features[i].selector == selector) {
+				func = pmac_mb.features[i].function;
+				break;
+			}
+	if (!func)
+		for (i=0; any_features[i].function; i++)
+			if (any_features[i].selector == selector) {
+				func = any_features[i].function;
+				break;
+			}
+	if (!func)
+		return -ENODEV;
+
+	va_start(args, selector);
+	node = (struct device_node*)va_arg(args, void*);
+	param = va_arg(args, long);
+	value = va_arg(args, long);
+	va_end(args);
+
+	return func(node, param, value);
+}
+
+static int __init probe_motherboard(void)
+{
+	int i;
+	struct macio_chip* macio = &macio_chips[0];
+	const char* model = NULL;
+	struct device_node *dt;
+
+	/* Lookup known motherboard type in device-tree. First try an
+	 * exact match on the "model" property, then try a "compatible"
+	 * match is none is found.
+	 */
+	dt = find_devices("device-tree");
+	if (dt != NULL)
+		model = (const char *) get_property(dt, "model", NULL);
+	for(i=0; model && i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) {
+	    if (strcmp(model, pmac_mb_defs[i].model_string) == 0) {
+		pmac_mb = pmac_mb_defs[i];
+		goto found;
+	    }
+	}
+	for(i=0; i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) {
+	    if (machine_is_compatible(pmac_mb_defs[i].model_string)) {
+		pmac_mb = pmac_mb_defs[i];
+		goto found;
+	    }
+	}
+
+	/* Fallback to selection depending on mac-io chip type */
+	switch(macio->type) {
+	case macio_keylargo2:
+		pmac_mb.model_id = PMAC_TYPE_UNKNOWN_K2;
+		pmac_mb.model_name = "Unknown K2-based";
+	    	pmac_mb.features = g5_features;
+		
+	default:
+	    	return -ENODEV;
+	}
+found:
+	/* Check for "mobile" machine */
+	if (model && (strncmp(model, "PowerBook", 9) == 0
+		   || strncmp(model, "iBook", 5) == 0))
+		pmac_mb.board_flags |= PMAC_MB_MOBILE;
+
+
+	printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name);
+	return 0;
+}
+
+/* Initialize the Core99 UniNorth host bridge and memory controller
+ */
+static void __init probe_uninorth(void)
+{
+	uninorth_node = of_find_node_by_name(NULL, "u3");
+	if (uninorth_node && uninorth_node->n_addrs > 0) {
+		/* Small hack until I figure out if parsing in prom.c is correct. I should
+		 * get rid of those pre-parsed junk anyway
+		 */
+		unsigned long address = uninorth_node->addrs[0].address;
+		uninorth_base = ioremap(address, 0x40000);
+		uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
+		u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000);
+	} else
+		uninorth_node = NULL;
+
+	if (!uninorth_node)
+		return;
+
+	printk(KERN_INFO "Found U3 memory controller & host bridge, revision: %d\n",
+	       uninorth_rev);
+	printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base);
+
+}
+
+static void __init probe_one_macio(const char* name, const char* compat, int type)
+{
+	struct device_node*	node;
+	int			i;
+	volatile u32*		base;
+	u32*			revp;
+
+	node = find_devices(name);
+	if (!node || !node->n_addrs)
+		return;
+	if (compat)
+		do {
+			if (device_is_compatible(node, compat))
+				break;
+			node = node->next;
+		} while (node);
+	if (!node)
+		return;
+	for(i=0; i<MAX_MACIO_CHIPS; i++) {
+		if (!macio_chips[i].of_node)
+			break;
+		if (macio_chips[i].of_node == node)
+			return;
+	}
+	if (i >= MAX_MACIO_CHIPS) {
+		printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n");
+		printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name);
+		return;
+	}
+	base = (volatile u32*)ioremap(node->addrs[0].address, node->addrs[0].size);
+	if (!base) {
+		printk(KERN_ERR "pmac_feature: Can't map mac-io chip !\n");
+		return;
+	}
+	if (type == macio_keylargo) {
+		u32* did = (u32 *)get_property(node, "device-id", NULL);
+		if (*did == 0x00000025)
+			type = macio_pangea;
+		if (*did == 0x0000003e)
+			type = macio_intrepid;
+	}
+	macio_chips[i].of_node	= node;
+	macio_chips[i].type	= type;
+	macio_chips[i].base	= base;
+	macio_chips[i].flags	= MACIO_FLAG_SCCB_ON | MACIO_FLAG_SCCB_ON;
+	macio_chips[i].name 	= macio_names[type];
+	revp = (u32 *)get_property(node, "revision-id", NULL);
+	if (revp)
+		macio_chips[i].rev = *revp;
+	printk(KERN_INFO "Found a %s mac-io controller, rev: %d, mapped at 0x%p\n",
+		macio_names[type], macio_chips[i].rev, macio_chips[i].base);
+}
+
+static int __init
+probe_macios(void)
+{
+	probe_one_macio("mac-io", "K2-Keylargo", macio_keylargo2);
+
+	macio_chips[0].lbus.index = 0;
+	macio_chips[1].lbus.index = 1;
+
+	return (macio_chips[0].of_node == NULL) ? -ENODEV : 0;
+}
+
+static void __init
+set_initial_features(void)
+{
+	struct device_node *np;
+
+	if (macio_chips[0].type == macio_keylargo2) {
+#ifndef CONFIG_SMP
+		/* On SMP machines running UP, we have the second CPU eating
+		 * bus cycles. We need to take it off the bus. This is done
+		 * from pmac_smp for SMP kernels running on one CPU
+		 */
+		np = of_find_node_by_type(NULL, "cpu");
+		if (np != NULL)
+			np = of_find_node_by_type(np, "cpu");
+		if (np != NULL) {
+			g5_phy_disable_cpu1();
+			of_node_put(np);
+		}
+#endif /* CONFIG_SMP */
+		/* Enable GMAC for now for PCI probing. It will be disabled
+		 * later on after PCI probe
+		 */
+		np = of_find_node_by_name(NULL, "ethernet");
+		while(np) {
+			if (device_is_compatible(np, "K2-GMAC"))
+				g5_gmac_enable(np, 0, 1);
+			np = of_find_node_by_name(np, "ethernet");
+		}
+
+		/* Enable FW before PCI probe. Will be disabled later on
+		 * Note: We should have a batter way to check that we are
+		 * dealing with uninorth internal cell and not a PCI cell
+		 * on the external PCI. The code below works though.
+		 */
+		np = of_find_node_by_name(NULL, "firewire");
+		while(np) {
+			if (device_is_compatible(np, "pci106b,5811")) {
+				macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
+				g5_fw_enable(np, 0, 1);
+			}
+			np = of_find_node_by_name(np, "firewire");
+		}
+	}
+}
+
+void __init
+pmac_feature_init(void)
+{
+	/* Detect the UniNorth memory controller */
+	probe_uninorth();
+
+	/* Probe mac-io controllers */
+	if (probe_macios()) {
+		printk(KERN_WARNING "No mac-io chip found\n");
+		return;
+	}
+
+	/* Setup low-level i2c stuffs */
+	pmac_init_low_i2c();
+
+	/* Probe machine type */
+	if (probe_motherboard())
+		printk(KERN_WARNING "Unknown PowerMac !\n");
+
+	/* Set some initial features (turn off some chips that will
+	 * be later turned on)
+	 */
+	set_initial_features();
+}
+
+int __init pmac_feature_late_init(void)
+{
+#if 0
+	struct device_node* np;
+
+	/* Request some resources late */
+	if (uninorth_node)
+		request_OF_resource(uninorth_node, 0, NULL);
+	np = find_devices("hammerhead");
+	if (np)
+		request_OF_resource(np, 0, NULL);
+	np = find_devices("interrupt-controller");
+	if (np)
+		request_OF_resource(np, 0, NULL);
+#endif
+	return 0;
+}
+
+device_initcall(pmac_feature_late_init);
+
+
+static void dump_HT_speeds(char *name, u32 cfg, u32 frq)
+{
+	int	freqs[16] = { 200,300,400,500,600,800,1000,0,0,0,0,0,0,0,0,0 };
+	int	bits[8] = { 8,16,0,32,2,4,0,0 };
+	int	freq = (frq >> 8) & 0xf;
+
+	if (freqs[freq] == 0)
+		printk("%s: Unknown HT link frequency %x\n", name, freq);
+	else
+		printk("%s: %d MHz on main link, (%d in / %d out) bits width\n",
+		       name, freqs[freq],
+		       bits[(cfg >> 28) & 0x7], bits[(cfg >> 24) & 0x7]);
+}
+
+void __init pmac_check_ht_link(void)
+{
+#if 0 /* Disabled for now */
+	u32	ufreq, freq, ucfg, cfg;
+	struct device_node *pcix_node;
+	u8  	px_bus, px_devfn;
+	struct pci_controller *px_hose;
+
+	(void)in_be32(u3_ht + U3_HT_LINK_COMMAND);
+	ucfg = cfg = in_be32(u3_ht + U3_HT_LINK_CONFIG);
+	ufreq = freq = in_be32(u3_ht + U3_HT_LINK_FREQ);
+	dump_HT_speeds("U3 HyperTransport", cfg, freq);
+
+	pcix_node = of_find_compatible_node(NULL, "pci", "pci-x");
+	if (pcix_node == NULL) {
+		printk("No PCI-X bridge found\n");
+		return;
+	}
+	px_hose = pcix_node->phb;
+	px_bus = pcix_node->busno;
+	px_devfn = pcix_node->devfn;
+	
+	early_read_config_dword(px_hose, px_bus, px_devfn, 0xc4, &cfg);
+	early_read_config_dword(px_hose, px_bus, px_devfn, 0xcc, &freq);
+	dump_HT_speeds("PCI-X HT Uplink", cfg, freq);
+	early_read_config_dword(px_hose, px_bus, px_devfn, 0xc8, &cfg);
+	early_read_config_dword(px_hose, px_bus, px_devfn, 0xd0, &freq);
+	dump_HT_speeds("PCI-X HT Downlink", cfg, freq);
+#endif
+}
diff -Nru a/arch/ppc64/kernel/pmac_low_i2c.c b/arch/ppc64/kernel/pmac_low_i2c.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc64/kernel/pmac_low_i2c.c	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,513 @@
+/*
+ *  arch/ppc/platforms/pmac_low_i2c.c
+ *
+ *  Copyright (C) 2003 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.
+ *
+ *  This file contains some low-level i2c access routines that
+ *  need to be used by various bits of the PowerMac platform code
+ *  at times where the real asynchronous & interrupt driven driver
+ *  cannot be used. The API borrows some semantics from the darwin
+ *  driver in order to ease the implementation of the platform
+ *  properties parser
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <asm/keylargo.h>
+#include <asm/uninorth.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/pmac_low_i2c.h>
+
+#define MAX_LOW_I2C_HOST	4
+
+#if 1
+#define DBG(x...) do {\
+		printk(KERN_DEBUG "KW:" x);	\
+	} while(0)
+#else
+#define DBGG(x...)
+#endif
+
+struct low_i2c_host;
+
+typedef int (*low_i2c_func_t)(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len);
+
+struct low_i2c_host
+{
+	struct device_node	*np;		/* OF device node */
+	struct semaphore	mutex;		/* Access mutex for use by i2c-keywest */
+	low_i2c_func_t		func;		/* Access function */
+	int			is_open : 1;	/* Poor man's access control */
+	int			mode;		/* Current mode */
+	int			channel;	/* Current channel */
+	int			num_channels;	/* Number of channels */
+	unsigned long		base;		/* For keywest-i2c, base address */
+	int			bsteps;		/* And register stepping */
+	int			speed;		/* And speed */
+};
+
+static struct low_i2c_host	low_i2c_hosts[MAX_LOW_I2C_HOST];
+
+/* No locking is necessary on allocation, we are running way before
+ * anything can race with us
+ */
+static struct low_i2c_host *find_low_i2c_host(struct device_node *np)
+{
+	int i;
+
+	for (i = 0; i < MAX_LOW_I2C_HOST; i++)
+		if (low_i2c_hosts[i].np == np)
+			return &low_i2c_hosts[i];
+	return NULL;
+}
+
+/*
+ *
+ * i2c-keywest implementation (UniNorth, U2, U3, Keylargo's)
+ *
+ */
+
+/*
+ * Keywest i2c definitions borrowed from drivers/i2c/i2c-keywest.h,
+ * should be moved somewhere in include/asm-ppc/
+ */
+/* Register indices */
+typedef enum {
+	reg_mode = 0,
+	reg_control,
+	reg_status,
+	reg_isr,
+	reg_ier,
+	reg_addr,
+	reg_subaddr,
+	reg_data
+} reg_t;
+
+
+/* Mode register */
+#define KW_I2C_MODE_100KHZ	0x00
+#define KW_I2C_MODE_50KHZ	0x01
+#define KW_I2C_MODE_25KHZ	0x02
+#define KW_I2C_MODE_DUMB	0x00
+#define KW_I2C_MODE_STANDARD	0x04
+#define KW_I2C_MODE_STANDARDSUB	0x08
+#define KW_I2C_MODE_COMBINED	0x0C
+#define KW_I2C_MODE_MODE_MASK	0x0C
+#define KW_I2C_MODE_CHAN_MASK	0xF0
+
+/* Control register */
+#define KW_I2C_CTL_AAK		0x01
+#define KW_I2C_CTL_XADDR	0x02
+#define KW_I2C_CTL_STOP		0x04
+#define KW_I2C_CTL_START	0x08
+
+/* Status register */
+#define KW_I2C_STAT_BUSY	0x01
+#define KW_I2C_STAT_LAST_AAK	0x02
+#define KW_I2C_STAT_LAST_RW	0x04
+#define KW_I2C_STAT_SDA		0x08
+#define KW_I2C_STAT_SCL		0x10
+
+/* IER & ISR registers */
+#define KW_I2C_IRQ_DATA		0x01
+#define KW_I2C_IRQ_ADDR		0x02
+#define KW_I2C_IRQ_STOP		0x04
+#define KW_I2C_IRQ_START	0x08
+#define KW_I2C_IRQ_MASK		0x0F
+
+/* State machine states */
+enum {
+	state_idle,
+	state_addr,
+	state_read,
+	state_write,
+	state_stop,
+	state_dead
+};
+
+#define WRONG_STATE(name) do {\
+		printk(KERN_DEBUG "KW: wrong state. Got %s, state: %s (isr: %02x)\n", \
+		       name, __kw_state_names[state], isr); \
+	} while(0)
+
+static const char *__kw_state_names[] = {
+	"state_idle",
+	"state_addr",
+	"state_read",
+	"state_write",
+	"state_stop",
+	"state_dead"
+};
+
+static inline u8 __kw_read_reg(struct low_i2c_host *host, reg_t reg)
+{
+	return in_8(((volatile u8 *)host->base)
+		+ (((unsigned)reg) << host->bsteps));
+}
+
+static inline void __kw_write_reg(struct low_i2c_host *host, reg_t reg, u8 val)
+{
+	out_8(((volatile u8 *)host->base)
+		+ (((unsigned)reg) << host->bsteps), val);
+	(void)__kw_read_reg(host, reg_subaddr);
+}
+
+#define kw_write_reg(reg, val)	__kw_write_reg(host, reg, val) 
+#define kw_read_reg(reg)	__kw_read_reg(host, reg) 
+
+
+/* Don't schedule, the g5 fan controller is too
+ * timing sensitive
+ */
+static u8 kw_wait_interrupt(struct low_i2c_host* host)
+{
+	int i;
+	u8 isr;
+	
+	for (i = 0; i < 200000; i++) {
+		isr = kw_read_reg(reg_isr) & KW_I2C_IRQ_MASK;
+		if (isr != 0)
+			return isr;
+		udelay(1);
+	}
+	return isr;
+}
+
+static int kw_handle_interrupt(struct low_i2c_host *host, int state, int rw, int *rc, u8 **data, int *len, u8 isr)
+{
+	u8 ack;
+
+	if (isr == 0) {
+		if (state != state_stop) {
+			DBG("KW: Timeout !\n");
+			*rc = -EIO;
+			goto stop;
+		}
+		if (state == state_stop) {
+			ack = kw_read_reg(reg_status);
+			if (!(ack & KW_I2C_STAT_BUSY)) {
+				state = state_idle;
+				kw_write_reg(reg_ier, 0x00);
+			}
+		}
+		return state;
+	}
+
+	if (isr & KW_I2C_IRQ_ADDR) {
+		ack = kw_read_reg(reg_status);
+		if (state != state_addr) {
+			kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
+			WRONG_STATE("KW_I2C_IRQ_ADDR"); 
+			*rc = -EIO;
+			goto stop;
+		}
+		if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {			
+			*rc = -ENODEV;
+			DBG("KW: NAK on address\n");
+			return state_stop;		     
+		} else {
+			if (rw) {
+				state = state_read;
+				if (*len > 1)
+					kw_write_reg(reg_control, KW_I2C_CTL_AAK);
+			} else {
+				state = state_write;
+				kw_write_reg(reg_data, **data);
+				(*data)++; (*len)--;
+			}
+		}
+		kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
+	}
+
+	if (isr & KW_I2C_IRQ_DATA) {
+		if (state == state_read) {
+			**data = kw_read_reg(reg_data);
+			(*data)++; (*len)--;
+			kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
+			if ((*len) == 0)
+				state = state_stop;
+			else if ((*len) == 1)
+				kw_write_reg(reg_control, 0);
+		} else if (state == state_write) {
+			ack = kw_read_reg(reg_status);
+			if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
+				DBG("KW: nack on data write\n");
+				*rc = -EIO;
+				goto stop;
+			} else if (*len) {
+				kw_write_reg(reg_data, **data);
+				(*data)++; (*len)--;
+			} else {
+				kw_write_reg(reg_control, KW_I2C_CTL_STOP);
+				state = state_stop;
+				*rc = 0;
+			}
+			kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
+		} else {
+			kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
+			WRONG_STATE("KW_I2C_IRQ_DATA"); 
+			if (state != state_stop) {
+				*rc = -EIO;
+				goto stop;
+			}
+		}
+	}
+
+	if (isr & KW_I2C_IRQ_STOP) {
+		kw_write_reg(reg_isr, KW_I2C_IRQ_STOP);
+		if (state != state_stop) {
+			WRONG_STATE("KW_I2C_IRQ_STOP");
+			*rc = -EIO;
+		}
+		return state_idle;
+	}
+
+	if (isr & KW_I2C_IRQ_START)
+		kw_write_reg(reg_isr, KW_I2C_IRQ_START);
+
+	return state;
+
+ stop:
+	kw_write_reg(reg_control, KW_I2C_CTL_STOP);	
+	return state_stop;
+}
+
+static int keywest_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 subaddr, u8 *data, int len)
+{
+	u8 mode_reg = host->speed;
+	int state = state_addr;
+	int rc = 0;
+
+	/* Setup mode & subaddress if any */
+	switch(host->mode) {
+	case pmac_low_i2c_mode_dumb:
+		printk(KERN_ERR "low_i2c: Dumb mode not supported !\n");
+		return -EINVAL;
+	case pmac_low_i2c_mode_std:
+		mode_reg |= KW_I2C_MODE_STANDARD;
+		break;
+	case pmac_low_i2c_mode_stdsub:
+		mode_reg |= KW_I2C_MODE_STANDARDSUB;
+		kw_write_reg(reg_subaddr, subaddr);
+		break;
+	case pmac_low_i2c_mode_combined:
+		mode_reg |= KW_I2C_MODE_COMBINED;
+		kw_write_reg(reg_subaddr, subaddr);
+		break;
+	}
+
+	/* Setup channel & clear pending irqs */
+	kw_write_reg(reg_isr, kw_read_reg(reg_isr));
+	kw_write_reg(reg_mode, mode_reg | (host->channel << 4));
+	kw_write_reg(reg_status, 0);
+
+	/* Set up address and r/w bit */
+	kw_write_reg(reg_addr, addr);
+
+	/* Start sending address & disable interrupt*/
+	kw_write_reg(reg_ier, 0 /*KW_I2C_IRQ_MASK*/);
+	kw_write_reg(reg_control, KW_I2C_CTL_XADDR);
+
+	/* State machine, to turn into an interrupt handler */
+	while(state != state_idle) {
+		u8 isr = kw_wait_interrupt(host);
+		state = kw_handle_interrupt(host, state, addr & 1, &rc, &data, &len, isr);
+	}
+
+	return rc;
+}
+
+static void keywest_low_i2c_add(struct device_node *np)
+{
+	struct low_i2c_host	*host = find_low_i2c_host(NULL);
+	unsigned long		*psteps, *prate, steps, aoffset = 0;
+	struct device_node	*parent;
+
+	if (host == NULL) {
+		printk(KERN_ERR "low_i2c: Can't allocate host for %s\n",
+		       np->full_name);
+		return;
+	}
+	memset(host, 0, sizeof(*host));
+
+	init_MUTEX(&host->mutex);
+	host->np = of_node_get(np);	
+	psteps = (unsigned long *)get_property(np, "AAPL,address-step", NULL);
+	steps = psteps ? (*psteps) : 0x10;
+	for (host->bsteps = 0; (steps & 0x01) == 0; host->bsteps++)
+		steps >>= 1;
+	parent = of_get_parent(np);
+	host->num_channels = 1;
+	if (parent && parent->name[0] == 'u') {
+		host->num_channels = 2;
+		aoffset = 3;
+	}
+	/* Select interface rate */
+	host->speed = KW_I2C_MODE_100KHZ;
+	prate = (unsigned long *)get_property(np, "AAPL,i2c-rate", NULL);
+	if (prate) switch(*prate) {
+	case 100:
+		host->speed = KW_I2C_MODE_100KHZ;
+		break;
+	case 50:
+		host->speed = KW_I2C_MODE_50KHZ;
+		break;
+	case 25:
+		host->speed = KW_I2C_MODE_25KHZ;
+		break;
+	}	
+	host->mode = pmac_low_i2c_mode_std;
+	host->base = (unsigned long)ioremap(np->addrs[0].address + aoffset,
+						np->addrs[0].size);
+	host->func = keywest_low_i2c_func;
+}
+
+/*
+ *
+ * PMU implementation
+ *
+ */
+
+
+#ifdef CONFIG_ADB_PMU
+
+static int pmu_low_i2c_func(struct low_i2c_host *host, u8 addr, u8 sub, u8 *data, int len)
+{
+	// TODO
+	return -ENODEV;
+}
+
+static void pmu_low_i2c_add(struct device_node *np)
+{
+	struct low_i2c_host	*host = find_low_i2c_host(NULL);
+
+	if (host == NULL) {
+		printk(KERN_ERR "low_i2c: Can't allocate host for %s\n",
+		       np->full_name);
+		return;
+	}
+	memset(host, 0, sizeof(*host));
+
+	init_MUTEX(&host->mutex);
+	host->np = of_node_get(np);	
+	host->num_channels = 3;
+	host->mode = pmac_low_i2c_mode_std;
+	host->func = pmu_low_i2c_func;
+}
+
+#endif /* CONFIG_ADB_PMU */
+
+void __init pmac_init_low_i2c(void)
+{
+	struct device_node *np;
+
+	/* Probe keywest-i2c busses */
+	np = of_find_compatible_node(NULL, "i2c", "keywest-i2c");
+	while(np) {
+		keywest_low_i2c_add(np);
+		np = of_find_compatible_node(np, "i2c", "keywest-i2c");
+	}
+
+#ifdef CONFIG_ADB_PMU
+	/* Probe PMU busses */
+	np = of_find_node_by_name(NULL, "via-pmu");
+	if (np)
+		pmu_low_i2c_add(np);
+#endif /* CONFIG_ADB_PMU */
+
+	/* TODO: Add CUDA support as well */
+}
+
+int pmac_low_i2c_lock(struct device_node *np)
+{
+	struct low_i2c_host *host = find_low_i2c_host(np);
+
+	if (!host)
+		return -ENODEV;
+	down(&host->mutex);
+	return 0;
+}
+EXPORT_SYMBOL(pmac_low_i2c_lock);
+
+int pmac_low_i2c_unlock(struct device_node *np)
+{
+	struct low_i2c_host *host = find_low_i2c_host(np);
+
+	if (!host)
+		return -ENODEV;
+	up(&host->mutex);
+	return 0;
+}
+EXPORT_SYMBOL(pmac_low_i2c_unlock);
+
+
+int pmac_low_i2c_open(struct device_node *np, int channel)
+{
+	struct low_i2c_host *host = find_low_i2c_host(np);
+
+	if (!host)
+		return -ENODEV;
+
+	if (channel >= host->num_channels)
+		return -EINVAL;
+
+	down(&host->mutex);
+	host->is_open = 1;
+	host->channel = channel;
+
+	return 0;
+}
+EXPORT_SYMBOL(pmac_low_i2c_open);
+
+int pmac_low_i2c_close(struct device_node *np)
+{
+	struct low_i2c_host *host = find_low_i2c_host(np);
+
+	if (!host)
+		return -ENODEV;
+
+	host->is_open = 0;
+	up(&host->mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(pmac_low_i2c_close);
+
+int pmac_low_i2c_setmode(struct device_node *np, int mode)
+{
+	struct low_i2c_host *host = find_low_i2c_host(np);
+
+	if (!host)
+		return -ENODEV;
+	WARN_ON(!host->is_open);
+	host->mode = mode;
+
+	return 0;
+}
+EXPORT_SYMBOL(pmac_low_i2c_setmode);
+
+int pmac_low_i2c_xfer(struct device_node *np, u8 addrdir, u8 subaddr, u8 *data, int len)
+{
+	struct low_i2c_host *host = find_low_i2c_host(np);
+
+	if (!host)
+		return -ENODEV;
+	WARN_ON(!host->is_open);
+
+	return host->func(host, addrdir, subaddr, data, len);
+}
+EXPORT_SYMBOL(pmac_low_i2c_xfer);
+
diff -Nru a/arch/ppc64/kernel/pmac_nvram.c b/arch/ppc64/kernel/pmac_nvram.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc64/kernel/pmac_nvram.c	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,495 @@
+/*
+ *  arch/ppc/platforms/pmac_nvram.c
+ *
+ *  Copyright (C) 2002 Benjamin 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.
+ *
+ *  Todo: - add support for the OF persistent properties
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/bootmem.h>
+#include <linux/completion.h>
+#include <linux/spinlock.h>
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/nvram.h>
+
+#define DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+#define NVRAM_SIZE		0x2000	/* 8kB of non-volatile RAM */
+
+#define CORE99_SIGNATURE	0x5a
+#define CORE99_ADLER_START	0x14
+
+/* On Core99, nvram is either a sharp, a micron or an AMD flash */
+#define SM_FLASH_STATUS_DONE	0x80
+#define SM_FLASH_STATUS_ERR	0x38
+
+#define SM_FLASH_CMD_ERASE_CONFIRM	0xd0
+#define SM_FLASH_CMD_ERASE_SETUP	0x20
+#define SM_FLASH_CMD_RESET		0xff
+#define SM_FLASH_CMD_WRITE_SETUP	0x40
+#define SM_FLASH_CMD_CLEAR_STATUS	0x50
+#define SM_FLASH_CMD_READ_STATUS	0x70
+
+/* CHRP NVRAM header */
+struct chrp_header {
+  u8		signature;
+  u8		cksum;
+  u16		len;
+  char          name[12];
+  u8		data[0];
+};
+
+struct core99_header {
+  struct chrp_header	hdr;
+  u32			adler;
+  u32			generation;
+  u32			reserved[2];
+};
+
+/*
+ * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
+ */
+static volatile unsigned char *nvram_data;
+static int core99_bank = 0;
+// XXX Turn that into a sem
+static spinlock_t nv_lock = SPIN_LOCK_UNLOCKED;
+
+extern int system_running;
+
+static int (*core99_write_bank)(int bank, u8* datas);
+static int (*core99_erase_bank)(int bank);
+
+static char *nvram_image __pmacdata;
+
+
+static ssize_t __pmac core99_nvram_read(char *buf, size_t count, loff_t *index)
+{
+	int i;
+
+	if (nvram_image == NULL)
+		return -ENODEV;
+	if (*index > NVRAM_SIZE)
+		return 0;
+
+	i = *index;
+	if (i + count > NVRAM_SIZE)
+		count = NVRAM_SIZE - i;
+
+	memcpy(buf, &nvram_image[i], count);
+	*index = i + count;
+	return count;
+}
+
+static ssize_t __pmac core99_nvram_write(char *buf, size_t count, loff_t *index)
+{
+	int i;
+
+	if (nvram_image == NULL)
+		return -ENODEV;
+	if (*index > NVRAM_SIZE)
+		return 0;
+
+	i = *index;
+	if (i + count > NVRAM_SIZE)
+		count = NVRAM_SIZE - i;
+
+	memcpy(&nvram_image[i], buf, count);
+	*index = i + count;
+	return count;
+}
+
+static ssize_t __pmac core99_nvram_size(void)
+{
+	if (nvram_image == NULL)
+		return -ENODEV;
+	return NVRAM_SIZE;
+}
+
+static u8 __pmac chrp_checksum(struct chrp_header* hdr)
+{
+	u8 *ptr;
+	u16 sum = hdr->signature;
+	for (ptr = (u8 *)&hdr->len; ptr < hdr->data; ptr++)
+		sum += *ptr;
+	while (sum > 0xFF)
+		sum = (sum & 0xFF) + (sum>>8);
+	return sum;
+}
+
+static u32 __pmac core99_calc_adler(u8 *buffer)
+{
+	int cnt;
+	u32 low, high;
+
+   	buffer += CORE99_ADLER_START;
+	low = 1;
+	high = 0;
+	for (cnt=0; cnt<(NVRAM_SIZE-CORE99_ADLER_START); cnt++) {
+		if ((cnt % 5000) == 0) {
+			high  %= 65521UL;
+			high %= 65521UL;
+		}
+		low += buffer[cnt];
+		high += low;
+	}
+	low  %= 65521UL;
+	high %= 65521UL;
+
+	return (high << 16) | low;
+}
+
+static u32 __pmac core99_check(u8* datas)
+{
+	struct core99_header* hdr99 = (struct core99_header*)datas;
+
+	if (hdr99->hdr.signature != CORE99_SIGNATURE) {
+		DBG("Invalid signature\n");
+		return 0;
+	}
+	if (hdr99->hdr.cksum != chrp_checksum(&hdr99->hdr)) {
+		DBG("Invalid checksum\n");
+		return 0;
+	}
+	if (hdr99->adler != core99_calc_adler(datas)) {
+		DBG("Invalid adler\n");
+		return 0;
+	}
+	return hdr99->generation;
+}
+
+static int __pmac sm_erase_bank(int bank)
+{
+	int stat, i;
+	unsigned long timeout;
+
+	u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+
+       	DBG("nvram: Sharp/Micron Erasing bank %d...\n", bank);
+
+	out_8(base, SM_FLASH_CMD_ERASE_SETUP);
+	out_8(base, SM_FLASH_CMD_ERASE_CONFIRM);
+	timeout = 0;
+	do {
+		if (++timeout > 1000000) {
+			printk(KERN_ERR "nvram: Sharp/Miron flash erase timeout !\n");
+			break;
+		}
+		out_8(base, SM_FLASH_CMD_READ_STATUS);
+		stat = in_8(base);
+	} while (!(stat & SM_FLASH_STATUS_DONE));
+
+	out_8(base, SM_FLASH_CMD_CLEAR_STATUS);
+	out_8(base, SM_FLASH_CMD_RESET);
+
+	for (i=0; i<NVRAM_SIZE; i++)
+		if (base[i] != 0xff) {
+			printk(KERN_ERR "nvram: Sharp/Micron flash erase failed !\n");
+			return -ENXIO;
+		}
+	return 0;
+}
+
+static int __pmac sm_write_bank(int bank, u8* datas)
+{
+	int i, stat = 0;
+	unsigned long timeout;
+
+	u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+
+       	DBG("nvram: Sharp/Micron Writing bank %d...\n", bank);
+
+	for (i=0; i<NVRAM_SIZE; i++) {
+		out_8(base+i, SM_FLASH_CMD_WRITE_SETUP);
+		udelay(1);
+		out_8(base+i, datas[i]);
+		timeout = 0;
+		do {
+			if (++timeout > 1000000) {
+				printk(KERN_ERR "nvram: Sharp/Micron flash write timeout !\n");
+				break;
+			}
+			out_8(base, SM_FLASH_CMD_READ_STATUS);
+			stat = in_8(base);
+		} while (!(stat & SM_FLASH_STATUS_DONE));
+		if (!(stat & SM_FLASH_STATUS_DONE))
+			break;
+	}
+	out_8(base, SM_FLASH_CMD_CLEAR_STATUS);
+	out_8(base, SM_FLASH_CMD_RESET);
+	for (i=0; i<NVRAM_SIZE; i++)
+		if (base[i] != datas[i]) {
+			printk(KERN_ERR "nvram: Sharp/Micron flash write failed !\n");
+			return -ENXIO;
+		}
+	return 0;
+}
+
+static int __pmac amd_erase_bank(int bank)
+{
+	int i, stat = 0;
+	unsigned long timeout;
+
+	u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+
+       	DBG("nvram: AMD Erasing bank %d...\n", bank);
+
+	/* Unlock 1 */
+	out_8(base+0x555, 0xaa);
+	udelay(1);
+	/* Unlock 2 */
+	out_8(base+0x2aa, 0x55);
+	udelay(1);
+
+	/* Sector-Erase */
+	out_8(base+0x555, 0x80);
+	udelay(1);
+	out_8(base+0x555, 0xaa);
+	udelay(1);
+	out_8(base+0x2aa, 0x55);
+	udelay(1);
+	out_8(base, 0x30);
+	udelay(1);
+
+	timeout = 0;
+	do {
+		if (++timeout > 1000000) {
+			printk(KERN_ERR "nvram: AMD flash erase timeout !\n");
+			break;
+		}
+		stat = in_8(base) ^ in_8(base);
+	} while (stat != 0);
+	
+	/* Reset */
+	out_8(base, 0xf0);
+	udelay(1);
+	
+	for (i=0; i<NVRAM_SIZE; i++)
+		if (base[i] != 0xff) {
+			printk(KERN_ERR "nvram: AMD flash erase failed !\n");
+			return -ENXIO;
+		}
+	return 0;
+}
+
+static int __pmac amd_write_bank(int bank, u8* datas)
+{
+	int i, stat = 0;
+	unsigned long timeout;
+
+	u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
+
+       	DBG("nvram: AMD Writing bank %d...\n", bank);
+
+	for (i=0; i<NVRAM_SIZE; i++) {
+		/* Unlock 1 */
+		out_8(base+0x555, 0xaa);
+		udelay(1);
+		/* Unlock 2 */
+		out_8(base+0x2aa, 0x55);
+		udelay(1);
+
+		/* Write single word */
+		out_8(base+0x555, 0xa0);
+		udelay(1);
+		out_8(base+i, datas[i]);
+		
+		timeout = 0;
+		do {
+			if (++timeout > 1000000) {
+				printk(KERN_ERR "nvram: AMD flash write timeout !\n");
+				break;
+			}
+			stat = in_8(base) ^ in_8(base);
+		} while (stat != 0);
+		if (stat != 0)
+			break;
+	}
+
+	/* Reset */
+	out_8(base, 0xf0);
+	udelay(1);
+
+	for (i=0; i<NVRAM_SIZE; i++)
+		if (base[i] != datas[i]) {
+			printk(KERN_ERR "nvram: AMD flash write failed !\n");
+			return -ENXIO;
+		}
+	return 0;
+}
+
+
+static int __pmac core99_nvram_sync(void)
+{
+	struct core99_header* hdr99;
+	unsigned long flags;
+
+	spin_lock_irqsave(&nv_lock, flags);
+	if (!memcmp(nvram_image, (u8*)nvram_data + core99_bank*NVRAM_SIZE,
+		NVRAM_SIZE))
+		goto bail;
+
+	DBG("Updating nvram...\n");
+
+	hdr99 = (struct core99_header*)nvram_image;
+	hdr99->generation++;
+	hdr99->hdr.signature = CORE99_SIGNATURE;
+	hdr99->hdr.cksum = chrp_checksum(&hdr99->hdr);
+	hdr99->adler = core99_calc_adler(nvram_image);
+	core99_bank = core99_bank ? 0 : 1;
+	if (core99_erase_bank)
+		if (core99_erase_bank(core99_bank)) {
+			printk("nvram: Error erasing bank %d\n", core99_bank);
+			goto bail;
+		}
+	if (core99_write_bank)
+		if (core99_write_bank(core99_bank, nvram_image))
+			printk("nvram: Error writing bank %d\n", core99_bank);
+ bail:
+	spin_unlock_irqrestore(&nv_lock, flags);
+
+	return 0;
+}
+
+int __init pmac_nvram_init(void)
+{
+	struct device_node *dp;
+	u32 gen_bank0, gen_bank1;
+	int i;
+
+	dp = find_devices("nvram");
+	if (dp == NULL) {
+		printk(KERN_ERR "Can't find NVRAM device\n");
+		return -ENODEV;
+	}
+	if (!device_is_compatible(dp, "nvram,flash")) {
+		printk(KERN_ERR "Incompatible type of NVRAM\n");
+		return -ENXIO;
+	}
+
+	nvram_image = alloc_bootmem(NVRAM_SIZE);
+	if (nvram_image == NULL) {
+		printk(KERN_ERR "nvram: can't allocate ram image\n");
+		return -ENOMEM;
+	}
+	nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2);
+	
+	DBG("nvram: Checking bank 0...\n");
+
+	gen_bank0 = core99_check((u8 *)nvram_data);
+	gen_bank1 = core99_check((u8 *)nvram_data + NVRAM_SIZE);
+	core99_bank = (gen_bank0 < gen_bank1) ? 1 : 0;
+
+	DBG("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1);
+	DBG("nvram: Active bank is: %d\n", core99_bank);
+
+	for (i=0; i<NVRAM_SIZE; i++)
+		nvram_image[i] = nvram_data[i + core99_bank*NVRAM_SIZE];
+
+	ppc_md.nvram_read	= core99_nvram_read;
+	ppc_md.nvram_write	= core99_nvram_write;
+	ppc_md.nvram_size	= core99_nvram_size;
+	ppc_md.nvram_sync	= core99_nvram_sync;
+	
+	/* 
+	 * Maybe we could be smarter here though making an exclusive list
+	 * of known flash chips is a bit nasty as older OF didn't provide us
+	 * with a useful "compatible" entry. A solution would be to really
+	 * identify the chip using flash id commands and base ourselves on
+	 * a list of known chips IDs
+	 */
+	if (device_is_compatible(dp, "amd-0137")) {
+		core99_erase_bank = amd_erase_bank;
+		core99_write_bank = amd_write_bank;
+	} else {
+		core99_erase_bank = sm_erase_bank;
+		core99_write_bank = sm_write_bank;
+	}
+
+	return 0;
+}
+
+int __pmac pmac_get_partition(int partition)
+{
+	struct nvram_partition *part;
+	const char *name;
+	int sig;
+
+	switch(partition) {
+	case pmac_nvram_OF:
+		name = "common";
+		sig = NVRAM_SIG_SYS;
+		break;
+	case pmac_nvram_XPRAM:
+		name = "APL,MacOS75";
+		sig = NVRAM_SIG_OS;
+		break;
+	case pmac_nvram_NR:
+	default:
+		/* Oldworld stuff */
+		return -ENODEV;
+	}
+
+	part = nvram_find_partition(sig, name);
+	if (part == NULL)
+		return 0;
+
+	return part->index;
+}
+
+u8 __pmac pmac_xpram_read(int xpaddr)
+{
+	int offset = pmac_get_partition(pmac_nvram_XPRAM);
+	loff_t index;
+	u8 buf;
+	ssize_t count;
+
+	if (offset < 0 || xpaddr < 0 || xpaddr > 0x100)
+		return 0xff;
+	index = offset + xpaddr;
+
+	count = ppc_md.nvram_read(&buf, 1, &index);
+	if (count != 1)
+		return 0xff;
+	return buf;
+}
+
+void __pmac pmac_xpram_write(int xpaddr, u8 data)
+{
+	int offset = pmac_get_partition(pmac_nvram_XPRAM);
+	loff_t index;
+	u8 buf;
+
+	if (offset < 0 || xpaddr < 0 || xpaddr > 0x100)
+		return;
+	index = offset + xpaddr;
+	buf = data;
+
+	ppc_md.nvram_write(&buf, 1, &index);
+}
+
+EXPORT_SYMBOL(pmac_get_partition);
+EXPORT_SYMBOL(pmac_xpram_read);
+EXPORT_SYMBOL(pmac_xpram_write);
diff -Nru a/arch/ppc64/kernel/pmac_pci.c b/arch/ppc64/kernel/pmac_pci.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc64/kernel/pmac_pci.c	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,755 @@
+/*
+ * Support for PCI bridges found on Power Macintoshes.
+ * At present the "bandit" and "chaos" bridges are supported.
+ * Fortunately you access configuration space in the same
+ * way with either bridge.
+ *
+ * Copyright (C) 2003 Benjamin Herrenschmuidt (benh@kernel.crashing.org)
+ * Copyright (C) 1997 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
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+
+#include <asm/sections.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+
+#include "pci.h"
+#include "pmac.h"
+
+#define DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+extern int pci_probe_only;
+extern int pci_read_irq_line(struct pci_dev *pci_dev);
+
+/* XXX Could be per-controller, but I don't think we risk anything by
+ * assuming we won't have both UniNorth and Bandit */
+static int has_uninorth;
+static struct pci_controller *u3_agp;
+u8 pci_cache_line_size;
+struct pci_dev *k2_skiplist[2];
+
+static int __init fixup_one_level_bus_range(struct device_node *node, int higher)
+{
+	for (; node != 0;node = node->sibling) {
+		int * bus_range;
+		unsigned int *class_code;
+		int len;
+
+		/* For PCI<->PCI bridges or CardBus bridges, we go down */
+		class_code = (unsigned int *) get_property(node, "class-code", 0);
+		if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI &&
+			(*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS))
+			continue;
+		bus_range = (int *) get_property(node, "bus-range", &len);
+		if (bus_range != NULL && len > 2 * sizeof(int)) {
+			if (bus_range[1] > higher)
+				higher = bus_range[1];
+		}
+		higher = fixup_one_level_bus_range(node->child, higher);
+	}
+	return higher;
+}
+
+/* This routine fixes the "bus-range" property of all bridges in the
+ * system since they tend to have their "last" member wrong on macs
+ *
+ * Note that the bus numbers manipulated here are OF bus numbers, they
+ * are not Linux bus numbers.
+ */
+static void __init fixup_bus_range(struct device_node *bridge)
+{
+	int * bus_range;
+	int len;
+
+	/* Lookup the "bus-range" property for the hose */
+	bus_range = (int *) get_property(bridge, "bus-range", &len);
+	if (bus_range == NULL || len < 2 * sizeof(int)) {
+		printk(KERN_WARNING "Can't get bus-range for %s\n",
+			       bridge->full_name);
+		return;
+	}
+	bus_range[1] = fixup_one_level_bus_range(bridge->child, bus_range[1]);
+}
+
+/*
+ * Apple MacRISC (U3, UniNorth, Bandit, Chaos) PCI controllers.
+ *
+ * The "Bandit" version is present in all early PCI PowerMacs,
+ * and up to the first ones using Grackle. Some machines may
+ * have 2 bandit controllers (2 PCI busses).
+ *
+ * "Chaos" is used in some "Bandit"-type machines as a bridge
+ * for the separate display bus. It is accessed the same
+ * way as bandit, but cannot be probed for devices. It therefore
+ * has its own config access functions.
+ *
+ * The "UniNorth" version is present in all Core99 machines
+ * (iBook, G4, new IMacs, and all the recent Apple machines).
+ * It contains 3 controllers in one ASIC.
+ *
+ * The U3 is the bridge used on G5 machines. It contains on
+ * AGP bus which is dealt with the old UniNorth access routines
+ * and an HyperTransport bus which uses its own set of access
+ * functions.
+ */
+
+#define MACRISC_CFA0(devfn, off)	\
+	((1 << (unsigned long)PCI_SLOT(dev_fn)) \
+	| (((unsigned long)PCI_FUNC(dev_fn)) << 8) \
+	| (((unsigned long)(off)) & 0xFCUL))
+
+#define MACRISC_CFA1(bus, devfn, off)	\
+	((((unsigned long)(bus)) << 16) \
+	|(((unsigned long)(devfn)) << 8) \
+	|(((unsigned long)(off)) & 0xFCUL) \
+	|1UL)
+
+static unsigned long __pmac macrisc_cfg_access(struct pci_controller* hose,
+					       u8 bus, u8 dev_fn, u8 offset)
+{
+	unsigned int caddr;
+
+	if (bus == hose->first_busno) {
+		if (dev_fn < (11 << 3))
+			return 0;
+		caddr = MACRISC_CFA0(dev_fn, offset);
+	} else
+		caddr = MACRISC_CFA1(bus, dev_fn, offset);
+
+	/* Uninorth will return garbage if we don't read back the value ! */
+	do {
+		out_le32(hose->cfg_addr, caddr);
+	} while (in_le32(hose->cfg_addr) != caddr);
+
+	offset &= has_uninorth ? 0x07 : 0x03;
+	return ((unsigned long)hose->cfg_data) + offset;
+}
+
+static int __pmac macrisc_read_config(struct pci_bus *bus, unsigned int devfn,
+				      int offset, int len, u32 *val)
+{
+	struct pci_controller *hose;
+	struct device_node *busdn;
+	unsigned long addr;
+	int i;
+
+	if (bus->self)
+		busdn = pci_device_to_OF_node(bus->self);
+	else
+		busdn = bus->sysdata;	/* must be a phb */
+	if (busdn == NULL)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	hose = busdn->phb;
+	if (hose == NULL)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	/*
+	 * When a device in K2 is powered down, we die on config
+	 * cycle accesses. Fix that here.
+	 */
+	for (i=0; i<2; i++)
+		if (k2_skiplist[i] && k2_skiplist[i]->bus == bus &&
+		    k2_skiplist[i]->devfn == devfn) {
+			switch (len) {
+			case 1:
+				*val = 0xff; break;
+			case 2:
+				*val = 0xffff; break;
+			default:
+				*val = 0xfffffffful; break;
+			}
+			return PCIBIOS_SUCCESSFUL;
+		}
+	    
+	addr = macrisc_cfg_access(hose, bus->number, devfn, offset);
+	if (!addr)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	/*
+	 * Note: the caller has already checked that offset is
+	 * suitably aligned and that len is 1, 2 or 4.
+	 */
+	switch (len) {
+	case 1:
+		*val = in_8((u8 *)addr);
+		break;
+	case 2:
+		*val = in_le16((u16 *)addr);
+		break;
+	default:
+		*val = in_le32((u32 *)addr);
+		break;
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int __pmac macrisc_write_config(struct pci_bus *bus, unsigned int devfn,
+				       int offset, int len, u32 val)
+{
+	struct pci_controller *hose;
+	struct device_node *busdn;
+	unsigned long addr;
+	int i;
+
+	if (bus->self)
+		busdn = pci_device_to_OF_node(bus->self);
+	else
+		busdn = bus->sysdata;	/* must be a phb */
+	if (busdn == NULL)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	hose = busdn->phb;
+	if (hose == NULL)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	/*
+	 * When a device in K2 is powered down, we die on config
+	 * cycle accesses. Fix that here.
+	 */
+	for (i=0; i<2; i++)
+		if (k2_skiplist[i] && k2_skiplist[i]->bus == bus &&
+		    k2_skiplist[i]->devfn == devfn)
+			return PCIBIOS_SUCCESSFUL;
+
+	addr = macrisc_cfg_access(hose, bus->number, devfn, offset);
+	if (!addr)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	/*
+	 * Note: the caller has already checked that offset is
+	 * suitably aligned and that len is 1, 2 or 4.
+	 */
+	switch (len) {
+	case 1:
+		out_8((u8 *)addr, val);
+		(void) in_8((u8 *)addr);
+		break;
+	case 2:
+		out_le16((u16 *)addr, val);
+		(void) in_le16((u16 *)addr);
+		break;
+	default:
+		out_le32((u32 *)addr, val);
+		(void) in_le32((u32 *)addr);
+		break;
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops macrisc_pci_ops =
+{
+	macrisc_read_config,
+	macrisc_write_config
+};
+
+/*
+ * These versions of U3 HyperTransport config space access ops do not
+ * implement self-view of the HT host yet
+ */
+
+#define U3_HT_CFA0(devfn, off)		\
+		((((unsigned long)devfn) << 8) | offset)
+#define U3_HT_CFA1(bus, devfn, off)	\
+		(U3_HT_CFA0(devfn, off) \
+		+ (((unsigned long)bus) << 16) \
+		+ 0x01000000UL)
+
+static unsigned long __pmac u3_ht_cfg_access(struct pci_controller* hose,
+					     u8 bus, u8 devfn, u8 offset)
+{
+	if (bus == hose->first_busno) {
+		/* For now, we don't self probe U3 HT bridge */
+		if (PCI_FUNC(devfn) != 0 || PCI_SLOT(devfn) > 7 ||
+		    PCI_SLOT(devfn) < 1)
+			return 0;
+		return ((unsigned long)hose->cfg_data) + U3_HT_CFA0(devfn, offset);
+	} else
+		return ((unsigned long)hose->cfg_data) + U3_HT_CFA1(bus, devfn, offset);
+}
+
+static int __pmac u3_ht_read_config(struct pci_bus *bus, unsigned int devfn,
+				    int offset, int len, u32 *val)
+{
+	struct pci_controller *hose;
+	struct device_node *busdn;
+	unsigned long addr;
+
+	if (bus->self)
+		busdn = pci_device_to_OF_node(bus->self);
+	else
+		busdn = bus->sysdata;	/* must be a phb */
+	if (busdn == NULL)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	hose = busdn->phb;
+	if (hose == NULL)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
+	if (!addr)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	/*
+	 * Note: the caller has already checked that offset is
+	 * suitably aligned and that len is 1, 2 or 4.
+	 */
+	switch (len) {
+	case 1:
+		*val = in_8((u8 *)addr);
+		break;
+	case 2:
+		*val = in_le16((u16 *)addr);
+		break;
+	default:
+		*val = in_le32((u32 *)addr);
+		break;
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int __pmac u3_ht_write_config(struct pci_bus *bus, unsigned int devfn,
+				     int offset, int len, u32 val)
+{
+	struct pci_controller *hose;
+	struct device_node *busdn;
+	unsigned long addr;
+
+	if (bus->self)
+		busdn = pci_device_to_OF_node(bus->self);
+	else
+		busdn = bus->sysdata;	/* must be a phb */
+	if (busdn == NULL)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	hose = busdn->phb;
+	if (hose == NULL)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	addr = u3_ht_cfg_access(hose, bus->number, devfn, offset);
+	if (!addr)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	/*
+	 * Note: the caller has already checked that offset is
+	 * suitably aligned and that len is 1, 2 or 4.
+	 */
+	switch (len) {
+	case 1:
+		out_8((u8 *)addr, val);
+		(void) in_8((u8 *)addr);
+		break;
+	case 2:
+		out_le16((u16 *)addr, val);
+		(void) in_le16((u16 *)addr);
+		break;
+	default:
+		out_le32((u32 *)addr, val);
+		(void) in_le32((u32 *)addr);
+		break;
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops u3_ht_pci_ops =
+{
+	u3_ht_read_config,
+	u3_ht_write_config
+};
+
+static void __init setup_u3_agp(struct pci_controller* hose)
+{
+	/* On G5, we move AGP up to high bus number so we don't need
+	 * to reassign bus numbers for HT. If we ever have P2P bridges
+	 * on AGP, we'll have to move pci_assign_all_busses to the
+	 * pci_controller structure so we enable it for AGP and not for
+	 * HT childs.
+	 * We hard code the address because of the different size of
+	 * the reg address cell, we shall fix that by killing struct
+	 * reg_property and using some accessor functions instead
+	 */
+       	hose->first_busno = 0xf0;
+	hose->last_busno = 0xff;
+	has_uninorth = 1;
+	hose->ops = &macrisc_pci_ops;
+	hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000);
+	hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000);
+
+	u3_agp = hose;
+}
+
+static void __init setup_u3_ht(struct pci_controller* hose)
+{
+	struct device_node *np = (struct device_node *)hose->arch_data;
+	int i, cur;
+
+	hose->ops = &u3_ht_pci_ops;
+
+	/* We hard code the address because of the different size of
+	 * the reg address cell, we shall fix that by killing struct
+	 * reg_property and using some accessor functions instead
+	 */
+	hose->cfg_data = (volatile unsigned char *)ioremap(0xf2000000, 0x02000000);
+
+	/*
+	 * /ht node doesn't expose a "ranges" property, so we "remove" regions that
+	 * have been allocated to AGP. So far, this version of the code doesn't assign
+	 * any of the 0xfxxxxxxx "fine" memory regions to /ht.
+	 * We need to fix that sooner or later by either parsing all child "ranges"
+	 * properties or figuring out the U3 address space decoding logic and
+	 * then read it's configuration register (if any).
+	 */
+	hose->io_base_phys = 0xf4000000 + 0x00400000;
+	hose->io_base_virt = ioremap(hose->io_base_phys, 0x00400000);
+	isa_io_base = pci_io_base = (unsigned long) hose->io_base_virt;
+	hose->io_resource.name = np->full_name;
+	hose->io_resource.start = 0;
+	hose->io_resource.end = 0x003fffff;
+	hose->io_resource.flags = IORESOURCE_IO;
+	hose->pci_mem_offset = 0;
+	hose->first_busno = 0;
+	hose->last_busno = 0xef;
+	hose->mem_resources[0].name = np->full_name;
+	hose->mem_resources[0].start = 0x80000000;
+	hose->mem_resources[0].end = 0xefffffff;
+	hose->mem_resources[0].flags = IORESOURCE_MEM;
+
+	if (u3_agp == NULL) {
+		DBG("U3 has no AGP, using full resource range\n");
+		return;
+	}
+
+	/* We "remove" the AGP resources from the resources allocated to HT, that
+	 * is we create "holes". However, that code does assumptions that so far
+	 * happen to be true (cross fingers...), typically that resources in the
+	 * AGP node are properly ordered
+	 */
+	cur = 0;
+	for (i=0; i<3; i++) {
+		struct resource *res = &u3_agp->mem_resources[i];
+		if (res->flags != IORESOURCE_MEM)
+			continue;
+		/* We don't care about "fine" resources */
+		if (res->start >= 0xf0000000)
+			continue;
+		/* Check if it's just a matter of "shrinking" us in one direction */
+		if (hose->mem_resources[cur].start == res->start) {
+			DBG("U3/HT: shrink start of %d, %08lx -> %08lx\n",
+			    cur, hose->mem_resources[cur].start, res->end + 1);
+			hose->mem_resources[cur].start = res->end + 1;
+			continue;
+		}
+		if (hose->mem_resources[cur].end == res->end) {
+			DBG("U3/HT: shrink end of %d, %08lx -> %08lx\n",
+			    cur, hose->mem_resources[cur].end, res->start - 1);
+			hose->mem_resources[cur].end = res->start - 1;
+			continue;
+		}
+		/* No, it's not the case, we need a hole */
+		if (cur == 2) {
+			/* not enough resources for a hole, we drop part of the range */
+			printk(KERN_WARNING "Running out of resources for /ht host !\n");
+			hose->mem_resources[cur].end = res->start - 1;
+			continue;
+		}		
+		cur++;
+       		DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n",
+		    cur-1, res->start - 1, cur, res->end + 1);
+		hose->mem_resources[cur].name = np->full_name;
+		hose->mem_resources[cur].flags = IORESOURCE_MEM;
+		hose->mem_resources[cur].start = res->end + 1;
+		hose->mem_resources[cur].end = hose->mem_resources[cur-1].end;
+		hose->mem_resources[cur-1].end = res->start - 1;
+	}
+}
+
+static void __init pmac_process_bridge_OF_ranges(struct pci_controller *hose,
+			   struct device_node *dev, int primary)
+{
+	static unsigned int static_lc_ranges[2024];
+	unsigned int *dt_ranges, *lc_ranges, *ranges, *prev;
+	unsigned int size;
+	int rlen = 0, orig_rlen;
+	int memno = 0;
+	struct resource *res;
+	int np, na = prom_n_addr_cells(dev);
+
+	np = na + 5;
+
+	/* First we try to merge ranges to fix a problem with some pmacs
+	 * that can have more than 3 ranges, fortunately using contiguous
+	 * addresses -- BenH
+	 */
+	dt_ranges = (unsigned int *) get_property(dev, "ranges", &rlen);
+	if (!dt_ranges)
+		return;
+	/*	lc_ranges = (unsigned int *) alloc_bootmem(rlen);*/
+	lc_ranges = static_lc_ranges;
+	if (!lc_ranges)
+		return; /* what can we do here ? */
+	memcpy(lc_ranges, dt_ranges, rlen);
+	orig_rlen = rlen;
+
+	/* Let's work on a copy of the "ranges" property instead of damaging
+	 * the device-tree image in memory
+	 */
+	ranges = lc_ranges;
+	prev = NULL;
+	while ((rlen -= np * sizeof(unsigned int)) >= 0) {
+		if (prev) {
+			if (prev[0] == ranges[0] && prev[1] == ranges[1] &&
+				(prev[2] + prev[na+4]) == ranges[2] &&
+				(prev[na+2] + prev[na+4]) == ranges[na+2]) {
+				prev[na+4] += ranges[na+4];
+				ranges[0] = 0;
+				ranges += np;
+				continue;
+			}
+		}
+		prev = ranges;
+		ranges += np;
+	}
+
+	/*
+	 * The ranges property is laid out as an array of elements,
+	 * each of which comprises:
+	 *   cells 0 - 2:	a PCI address
+	 *   cells 3 or 3+4:	a CPU physical address
+	 *			(size depending on dev->n_addr_cells)
+	 *   cells 4+5 or 5+6:	the size of the range
+	 */
+	ranges = lc_ranges;
+	rlen = orig_rlen;
+	while (ranges && (rlen -= np * sizeof(unsigned int)) >= 0) {
+		res = NULL;
+		size = ranges[na+4];
+		switch (ranges[0] >> 24) {
+		case 1:		/* I/O space */
+			if (ranges[2] != 0)
+				break;
+			hose->io_base_phys = ranges[na+2];
+			/* limit I/O space to 16MB */
+			if (size > 0x01000000)
+				size = 0x01000000;
+			hose->io_base_virt = ioremap(ranges[na+2], size);
+			if (primary)
+				isa_io_base = (unsigned long) hose->io_base_virt;
+			res = &hose->io_resource;
+			res->flags = IORESOURCE_IO;
+			res->start = ranges[2];
+			break;
+		case 2:		/* memory space */
+			memno = 0;
+			if (ranges[1] == 0 && ranges[2] == 0
+			    && ranges[na+4] <= (16 << 20)) {
+				/* 1st 16MB, i.e. ISA memory area */
+#if 0
+				if (primary)
+					isa_mem_base = ranges[na+2];
+#endif
+				memno = 1;
+			}
+			while (memno < 3 && hose->mem_resources[memno].flags)
+				++memno;
+			if (memno == 0)
+				hose->pci_mem_offset = ranges[na+2] - ranges[2];
+			if (memno < 3) {
+				res = &hose->mem_resources[memno];
+				res->flags = IORESOURCE_MEM;
+				res->start = ranges[na+2];
+			}
+			break;
+		}
+		if (res != NULL) {
+			res->name = dev->full_name;
+			res->end = res->start + size - 1;
+			res->parent = NULL;
+			res->sibling = NULL;
+			res->child = NULL;
+		}
+		ranges += np;
+	}
+}
+
+/*
+ * We assume that if we have a G3 powermac, we have one bridge called
+ * "pci" (a MPC106) and no bandit or chaos bridges, and contrariwise,
+ * if we have one or more bandit or chaos bridges, we don't have a MPC106.
+ */
+static int __init add_bridge(struct device_node *dev)
+{
+	int len;
+	struct pci_controller *hose;
+	char* disp_name;
+	int *bus_range;
+	int primary = 1;
+ 	struct property *of_prop;
+
+	DBG("Adding PCI host bridge %s\n", dev->full_name);
+
+       	bus_range = (int *) get_property(dev, "bus-range", &len);
+       	if (bus_range == NULL || len < 2 * sizeof(int)) {
+       		printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n",
+       			       dev->full_name);
+       	}
+
+       	hose = pci_alloc_pci_controller(phb_type_apple);
+       	if (!hose)
+       		return -ENOMEM;
+       	hose->arch_data = dev;
+       	hose->first_busno = bus_range ? bus_range[0] : 0;
+       	hose->last_busno = bus_range ? bus_range[1] : 0xff;
+
+	of_prop = (struct property *)alloc_bootmem(sizeof(struct property) +
+			sizeof(hose->global_number));        
+	if (of_prop) {
+		memset(of_prop, 0, sizeof(struct property));
+		of_prop->name = "linux,pci-domain";
+		of_prop->length = sizeof(hose->global_number);
+		of_prop->value = (unsigned char *)&of_prop[1];
+		memcpy(of_prop->value, &hose->global_number, sizeof(hose->global_number));
+		prom_add_property(dev, of_prop);
+	}
+
+	disp_name = NULL;
+       	if (device_is_compatible(dev, "u3-agp")) {
+       		setup_u3_agp(hose);
+       		disp_name = "U3-AGP";
+       		primary = 0;
+       	} else if (device_is_compatible(dev, "u3-ht")) {
+       		setup_u3_ht(hose);
+       		disp_name = "U3-HT";
+       		primary = 1;
+       	}
+       	printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n",
+       		disp_name, hose->first_busno, hose->last_busno);
+
+       	/* Interpret the "ranges" property */
+       	/* This also maps the I/O region and sets isa_io/mem_base */
+       	pmac_process_bridge_OF_ranges(hose, dev, primary);
+
+       	/* Fixup "bus-range" OF property */
+       	fixup_bus_range(dev);
+
+	return 0;
+}
+
+
+void __init pmac_pcibios_fixup(void)
+{
+	struct pci_dev *dev = NULL;
+
+	while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
+		pci_read_irq_line(dev);
+
+	pci_fix_bus_sysdata();
+}
+
+static void __init pmac_fixup_phb_resources(void)
+{
+	struct pci_controller *hose;
+	
+	for (hose = hose_head; hose; hose = hose->next) {
+		unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base;
+		hose->io_resource.start += offset;
+		hose->io_resource.end += offset;
+		printk(KERN_INFO "PCI Host %d, io start: %lx; io end: %lx\n",
+		       hose->global_number,
+		       hose->io_resource.start, hose->io_resource.end);
+	}
+}
+
+void __init pmac_pci_init(void)
+{
+	struct device_node *np, *root;
+	struct device_node *ht = NULL;
+
+	/* Probe root PCI hosts, that is on U3 the AGP host and the
+	 * HyperTransport host. That one is actually "kept" around
+	 * and actually added last as it's resource management relies
+	 * on the AGP resources to have been setup first
+	 */
+	root = of_find_node_by_path("/");
+	if (root == NULL) {
+		printk(KERN_CRIT "pmac_find_bridges: can't find root of device tree\n");
+		return;
+	}
+	for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) {
+		if (np->name == NULL)
+			continue;
+		if (strcmp(np->name, "pci") == 0) {
+			if (add_bridge(np) == 0)
+				of_node_get(np);
+		}
+		if (strcmp(np->name, "ht") == 0) {
+			of_node_get(np);
+			ht = np;
+		}
+	}
+	of_node_put(root);
+
+	/* Now setup the HyperTransport host if we found any
+	 */
+	if (ht && add_bridge(ht) != 0)
+		of_node_put(ht);
+
+	/* Fixup the IO resources on our host bridges as the common code
+	 * does it only for childs of the host bridges
+	 */
+	pmac_fixup_phb_resources();
+
+	/* Setup the linkage between OF nodes and PHBs */ 
+	pci_devs_phb_init();
+
+	pmac_check_ht_link();
+
+	/* Tell pci.c to use the common resource allocation mecanism */
+	pci_probe_only = 0;
+	
+	/* HT don't do more than 64 bytes transfers. FIXME: Deal with
+	 * the exception of U3/AGP (hook into pci_set_mwi)
+	 */
+	pci_cache_line_size = 16; /* 64 bytes */
+}
+
+/*
+ * Disable second function on K2-SATA, it's broken
+ * and disable IO BARs on first one
+ */
+void fixup_k2_sata(struct pci_dev* dev)
+{
+	int i;
+	u16 cmd;
+
+	if (PCI_FUNC(dev->devfn) > 0) {
+		pci_read_config_word(dev, PCI_COMMAND, &cmd);
+		cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+		for (i = 0; i < 6; i++) {
+			dev->resource[i].start = dev->resource[i].end = 0;
+			dev->resource[i].flags = 0;
+			pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0);
+		}
+	} else {
+		pci_read_config_word(dev, PCI_COMMAND, &cmd);
+		cmd &= ~PCI_COMMAND_IO;
+		pci_write_config_word(dev, PCI_COMMAND, cmd);
+		for (i = 0; i < 5; i++) {
+			dev->resource[i].start = dev->resource[i].end = 0;
+			dev->resource[i].flags = 0;
+			pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0);
+		}
+	}
+}
diff -Nru a/arch/ppc64/kernel/pmac_setup.c b/arch/ppc64/kernel/pmac_setup.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc64/kernel/pmac_setup.c	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,504 @@
+/*
+ *  arch/ppc/platforms/setup.c
+ *
+ *  PowerPC version
+ *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ *  Adapted for Power Macintosh by Paul Mackerras
+ *    Copyright (C) 1996 Paul Mackerras (paulus@cs.anu.edu.au)
+ *
+ *  Derived from "arch/alpha/kernel/setup.c"
+ *    Copyright (C) 1995 Linus Torvalds
+ *
+ *  Maintained by Benjamin 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.
+ *
+ */
+
+/*
+ * bootup setup stuff..
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/tty.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/major.h>
+#include <linux/initrd.h>
+#include <linux/vt_kern.h>
+#include <linux/console.h>
+#include <linux/ide.h>
+#include <linux/pci.h>
+#include <linux/adb.h>
+#include <linux/cuda.h>
+#include <linux/pmu.h>
+#include <linux/irq.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+
+#include <asm/processor.h>
+#include <asm/sections.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/pci-bridge.h>
+#include <asm/pci_dma.h>
+#include <asm/machdep.h>
+#include <asm/dma.h>
+#include <asm/bootx.h>
+#include <asm/btext.h>
+#include <asm/cputable.h>
+#include <asm/pmac_feature.h>
+#include <asm/time.h>
+#include <asm/of_device.h>
+#include <asm/lmb.h>
+
+#include "pmac.h"
+
+extern char saved_command_line[];
+static int current_root_goodness = -1;
+#define DEFAULT_ROOT_DEVICE Root_SDA1	/* sda1 - slightly silly choice */
+
+extern  int powersave_nap;
+int sccdbg;
+
+extern void udbg_init_scc(struct device_node *np);
+
+#ifdef CONFIG_BOOTX_TEXT
+void pmac_progress(char *s, unsigned short hex);
+#endif
+
+void __pmac pmac_show_cpuinfo(struct seq_file *m)
+{
+	struct device_node *np;
+	char *pp;
+	int plen;
+	char* mbname;
+	int mbmodel = pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL,
+					PMAC_MB_INFO_MODEL, 0);
+	unsigned int mbflags = pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL,
+						 PMAC_MB_INFO_FLAGS, 0);
+
+	if (pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_NAME,
+			      (long)&mbname) != 0)
+		mbname = "Unknown";
+	
+	/* find motherboard type */
+	seq_printf(m, "machine\t\t: ");
+	np = find_devices("device-tree");
+	if (np != NULL) {
+		pp = (char *) get_property(np, "model", NULL);
+		if (pp != NULL)
+			seq_printf(m, "%s\n", pp);
+		else
+			seq_printf(m, "PowerMac\n");
+		pp = (char *) get_property(np, "compatible", &plen);
+		if (pp != NULL) {
+			seq_printf(m, "motherboard\t:");
+			while (plen > 0) {
+				int l = strlen(pp) + 1;
+				seq_printf(m, " %s", pp);
+				plen -= l;
+				pp += l;
+			}
+			seq_printf(m, "\n");
+		}
+	} else
+		seq_printf(m, "PowerMac\n");
+
+	/* print parsed model */
+	seq_printf(m, "detected as\t: %d (%s)\n", mbmodel, mbname);
+	seq_printf(m, "pmac flags\t: %08x\n", mbflags);
+	seq_printf(m, "memory\t\t: %luMB\n", lmb_phys_mem_size() >> 20);
+
+	/* Checks "l2cr-value" property in the registry */
+	np = find_devices("cpus");	
+	if (np == 0)
+		np = find_type_devices("cpu");	
+	if (np != 0) {
+		unsigned int *l2cr = (unsigned int *)
+			get_property(np, "l2cr-value", NULL);
+		if (l2cr != 0) {
+			seq_printf(m, "l2cr override\t: 0x%x\n", *l2cr);
+		}
+	}
+
+	/* Indicate newworld */
+	seq_printf(m, "pmac-generation\t: NewWorld\n");
+}
+
+
+void __init pmac_setup_arch(void)
+{
+	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. */
+	cpu = find_type_devices("cpu");
+	if (cpu != 0) {
+		fp = (int *) get_property(cpu, "clock-frequency", NULL);
+		if (fp != 0) {
+			if (pvr == 4 || pvr >= 8)
+				/* 604, G3, G4 etc. */
+				loops_per_jiffy = *fp / HZ;
+			else
+				/* 601, 603, etc. */
+				loops_per_jiffy = *fp / (2*HZ);
+		} else
+			loops_per_jiffy = 50000000 / HZ;
+	}
+	
+	/* We can NAP */
+	powersave_nap = 1;
+
+	/* Initialize the PMU */
+	find_via_pmu();
+
+	/* Init NVRAM access */
+	pmac_nvram_init();
+
+	/* Setup SMP callback */
+#ifdef CONFIG_SMP
+	pmac_setup_smp();
+#endif
+	/* Setup the PCI DMA to "direct" for now, until we have proper
+	 * DART support and can deal with more than 2Gb of RAM
+	 */
+	pci_dma_init_direct();
+
+	/* Lookup PCI hosts */
+       	pmac_pci_init();
+
+#ifdef CONFIG_DUMMY_CONSOLE
+	conswitchp = &dummy_con;
+#endif
+}
+
+extern char *bootpath;
+extern char *bootdevice;
+void *boot_host;
+int boot_target;
+int boot_part;
+extern dev_t boot_dev;
+
+#ifdef CONFIG_SCSI
+void __init note_scsi_host(struct device_node *node, void *host)
+{
+	int l;
+	char *p;
+
+	l = strlen(node->full_name);
+	if (bootpath != NULL && bootdevice != NULL
+	    && strncmp(node->full_name, bootdevice, l) == 0
+	    && (bootdevice[l] == '/' || bootdevice[l] == 0)) {
+		boot_host = host;
+		/*
+		 * There's a bug in OF 1.0.5.  (Why am I not surprised.)
+		 * If you pass a path like scsi/sd@1:0 to canon, it returns
+		 * something like /bandit@F2000000/gc@10/53c94@10000/sd@0,0
+		 * That is, the scsi target number doesn't get preserved.
+		 * So we pick the target number out of bootpath and use that.
+		 */
+		p = strstr(bootpath, "/sd@");
+		if (p != NULL) {
+			p += 4;
+			boot_target = simple_strtoul(p, NULL, 10);
+			p = strchr(p, ':');
+			if (p != NULL)
+				boot_part = simple_strtoul(p + 1, NULL, 10);
+		}
+	}
+}
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
+static dev_t __init find_ide_boot(void)
+{
+	char *p;
+	int n;
+	dev_t __init pmac_find_ide_boot(char *bootdevice, int n);
+
+	if (bootdevice == NULL)
+		return 0;
+	p = strrchr(bootdevice, '/');
+	if (p == NULL)
+		return 0;
+	n = p - bootdevice;
+
+	return pmac_find_ide_boot(bootdevice, n);
+}
+#endif /* CONFIG_BLK_DEV_IDE && CONFIG_BLK_DEV_IDE_PMAC */
+
+void __init find_boot_device(void)
+{
+#if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
+	boot_dev = find_ide_boot();
+#endif
+}
+
+static int initializing = 1;
+
+static int pmac_late_init(void)
+{
+	initializing = 0;
+	return 0;
+}
+
+late_initcall(pmac_late_init);
+
+/* can't be __init - can be called whenever a disk is first accessed */
+void __pmac note_bootable_part(dev_t dev, int part, int goodness)
+{
+	static int found_boot = 0;
+	char *p;
+
+	if (!initializing)
+		return;
+	if ((goodness <= current_root_goodness) &&
+	    ROOT_DEV != DEFAULT_ROOT_DEVICE)
+		return;
+	p = strstr(saved_command_line, "root=");
+	if (p != NULL && (p == saved_command_line || p[-1] == ' '))
+		return;
+
+	if (!found_boot) {
+		find_boot_device();
+		found_boot = 1;
+	}
+	if (!boot_dev || dev == boot_dev) {
+		ROOT_DEV = dev + part;
+		boot_dev = 0;
+		current_root_goodness = goodness;
+	}
+}
+
+void __pmac pmac_restart(char *cmd)
+{
+	pmu_restart();
+}
+
+void __pmac pmac_power_off(void)
+{
+	pmu_shutdown();
+}
+
+void __pmac pmac_halt(void)
+{
+	pmac_power_off();
+}
+
+#ifdef CONFIG_BOOTX_TEXT
+static int dummy_getc_poll(void)
+{
+	return -1;
+}
+
+static unsigned char dummy_getc(void)
+{
+	return 0;
+}
+
+static void btext_putc(unsigned char c)
+{
+	btext_drawchar(c);
+}
+#endif /* CONFIG_BOOTX_TEXT */
+
+/* 
+ * Early initialization.
+ * Relocation is on but do not reference unbolted pages
+ * Also, device-tree hasn't been "finished", so don't muck with
+ * it too much
+ */
+void __init pmac_init_early(void)
+{
+	hpte_init_pSeries();
+
+#ifdef CONFIG_BOOTX_TEXT
+	ppc_md.udbg_putc = btext_putc;
+	ppc_md.udbg_getc = dummy_getc;
+	ppc_md.udbg_getc_poll = dummy_getc_poll;
+#endif /* CONFIG_BOOTX_TEXT */
+}
+
+extern void* OpenPIC_Addr;
+extern void* OpenPIC2_Addr;
+extern u_int OpenPIC_NumInitSenses;
+extern u_char *OpenPIC_InitSenses;
+extern void openpic_init(int main_pic, int offset, unsigned char* chrp_ack,
+			 int programmer_switch_irq);
+extern void openpic2_init(int offset);
+extern int openpic_get_irq(struct pt_regs *regs);
+extern int openpic2_get_irq(struct pt_regs *regs);
+
+static int pmac_cascade_irq = -1;
+
+static irqreturn_t pmac_u3_do_cascade(int cpl, void *dev_id, struct pt_regs *regs)
+{
+	int irq;
+
+	for (;;) {
+		irq = openpic2_get_irq(regs);
+		if (irq == -1)
+			break;
+		ppc_irq_dispatch_handler(regs, irq);
+	}
+	return IRQ_HANDLED;
+}
+
+static __init void pmac_init_IRQ(void)
+{
+        struct device_node *irqctrler  = NULL;
+        struct device_node *irqctrler2 = NULL;
+	struct device_node *np = NULL;
+
+	/* We first try to detect Apple's new Core99 chipset, since mac-io
+	 * is quite different on those machines and contains an IBM MPIC2.
+	 */
+	while ((np = of_find_node_by_type(np, "open-pic")) != NULL) {
+		struct device_node *parent = of_get_parent(np);
+		if (parent && !strcmp(parent->name, "u3"))
+			irqctrler2 = of_node_get(np);
+		else
+			irqctrler = of_node_get(np);
+		of_node_put(parent);
+	}
+	if (irqctrler != NULL && irqctrler->n_addrs > 0) {
+		unsigned char senses[128];
+
+		printk(KERN_INFO "PowerMac using OpenPIC irq controller at 0x%08x\n",
+		       (unsigned int)irqctrler->addrs[0].address);
+
+		prom_get_irq_senses(senses, 0, 128);
+		OpenPIC_InitSenses = senses;
+		OpenPIC_NumInitSenses = 128;
+		OpenPIC_Addr = ioremap(irqctrler->addrs[0].address,
+				       irqctrler->addrs[0].size);
+		openpic_init(1, 0, NULL, -1);
+
+		if (irqctrler2 != NULL && irqctrler2->n_intrs > 0 &&
+		    irqctrler2->n_addrs > 0) {
+			printk(KERN_INFO "Slave OpenPIC at 0x%08x hooked on IRQ %d\n",
+			       (u32)irqctrler2->addrs[0].address,
+			       irqctrler2->intrs[0].line);
+			pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler2, 0, 0);
+			OpenPIC2_Addr = ioremap(irqctrler2->addrs[0].address,
+						irqctrler2->addrs[0].size);
+			prom_get_irq_senses(senses, 128, 128 + 128);
+			OpenPIC_InitSenses = senses;
+			OpenPIC_NumInitSenses = 128;
+			openpic2_init(128);
+			pmac_cascade_irq = irqctrler2->intrs[0].line;
+		}
+	}
+	of_node_put(irqctrler);
+	of_node_put(irqctrler2);
+}
+
+/* We cannot do request_irq too early ... Right now, we get the
+ * cascade as a core_initcall, which should be fine for our needs
+ */
+static int __init pmac_irq_cascade_init(void)
+{
+	if (request_irq(pmac_cascade_irq, pmac_u3_do_cascade, 0,
+			"U3->K2 Cascade", NULL))
+		printk(KERN_ERR "Unable to get OpenPIC IRQ for cascade\n");
+	return 0;
+}
+
+core_initcall(pmac_irq_cascade_init);
+
+void __init pmac_init(unsigned long r3, unsigned long r4, unsigned long r5,
+		      unsigned long r6, unsigned long r7)
+{
+	/* Probe motherboard chipset */
+	pmac_feature_init();
+
+	/* Init SCC */
+	if (strstr(cmd_line, "sccdbg")) {
+		sccdbg = 1;
+		udbg_init_scc(NULL);
+	}
+
+	/* Fill up the machine description */
+	ppc_md.setup_arch     = pmac_setup_arch;
+       	ppc_md.get_cpuinfo    = pmac_show_cpuinfo;
+
+	ppc_md.init_IRQ       = pmac_init_IRQ;
+	ppc_md.get_irq        = openpic_get_irq;
+
+	ppc_md.pcibios_fixup  = pmac_pcibios_fixup;
+
+	ppc_md.restart        = pmac_restart;
+	ppc_md.power_off      = pmac_power_off;
+	ppc_md.halt           = pmac_halt;
+
+       	ppc_md.get_boot_time  = pmac_get_boot_time;
+       	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.feature_call   = pmac_do_feature_call;
+
+
+#ifdef CONFIG_BOOTX_TEXT
+	ppc_md.progress       = pmac_progress;
+#endif /* CONFIG_BOOTX_TEXT */
+
+	if (ppc_md.progress) ppc_md.progress("pmac_init(): exit", 0);
+
+}
+
+#ifdef CONFIG_BOOTX_TEXT
+void __init pmac_progress(char *s, unsigned short hex)
+{
+	if (sccdbg) {
+		udbg_puts(s);
+		udbg_putc('\n');
+	}
+	else if (boot_text_mapped) {
+		btext_drawstring(s);
+		btext_drawchar('\n');
+	}
+}
+#endif /* CONFIG_BOOTX_TEXT */
+
+static int __init pmac_declare_of_platform_devices(void)
+{
+	struct device_node *np;
+
+	np = find_devices("u3");
+	if (np) {
+		for (np = np->child; np != NULL; np = np->sibling)
+			if (strncmp(np->name, "i2c", 3) == 0) {
+				of_platform_device_create(np, "u3-i2c");
+				break;
+			}
+	}
+
+	return 0;
+}
+
+device_initcall(pmac_declare_of_platform_devices);
diff -Nru a/arch/ppc64/kernel/pmac_smp.c b/arch/ppc64/kernel/pmac_smp.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc64/kernel/pmac_smp.c	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,174 @@
+/*
+ * SMP support for power macintosh.
+ *
+ * We support both the old "powersurge" SMP architecture
+ * and the current Core99 (G4 PowerMac) machines.
+ *
+ * Note that we don't support the very first rev. of
+ * Apple/DayStar 2 CPUs board, the one with the funky
+ * watchdog. Hopefully, none of these should be there except
+ * maybe internally to Apple. I should probably still add some
+ * code to detect this card though and disable SMP. --BenH.
+ *
+ * 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 <linux/errno.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/sections.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/smp.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/time.h>
+#include <asm/cacheflush.h>
+#include <asm/keylargo.h>
+
+#include "open_pic.h"
+
+extern void pmac_secondary_start_1(void);
+extern void pmac_secondary_start_2(void);
+extern void pmac_secondary_start_3(void);
+
+extern void smp_openpic_message_pass(int target, int msg, unsigned long data, int wait);
+
+extern struct smp_ops_t *smp_ops;
+
+static int __init smp_core99_probe(void)
+{
+	struct device_node *cpus;
+	int ncpus = 1;
+
+	/* Maybe use systemconfiguration here ? */
+	if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345);
+	cpus = find_type_devices("cpu");
+	if (cpus == NULL)
+		return 0;
+
+       	while ((cpus = cpus->next) != NULL)
+	       	++ncpus;
+
+	printk(KERN_INFO "PowerMac SMP probe found %d cpus\n", ncpus);
+
+	if (ncpus > 1)
+		openpic_request_IPIs();
+
+	return ncpus;
+}
+
+static void __init smp_core99_kick_cpu(int nr)
+{
+	int save_vector;
+	unsigned long new_vector;
+	unsigned long flags;
+	volatile unsigned int *vector
+		 = ((volatile unsigned int *)(KERNELBASE+0x100));
+
+	if (nr < 1 || nr > 3)
+		return;
+	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 .pmac_secondary_start - KERNELBASE
+	 */
+	switch(nr) {
+		case 1:
+			new_vector = (unsigned long)pmac_secondary_start_1;
+			break;
+		case 2:
+			new_vector = (unsigned long)pmac_secondary_start_2;
+			break;
+		case 3:
+			new_vector = (unsigned long)pmac_secondary_start_3;
+			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 */
+	pmac_call_feature(PMAC_FTR_RESET_CPU, NULL, nr, 0);
+	paca[nr].xProcStart = 1;
+
+	/* 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();
+
+	if (cpu_nr == 0) {
+		extern void g5_phy_disable_cpu1(void);
+
+		/* If we didn't start the second CPU, we must take
+		 * it off the bus
+		 */
+		if (num_online_cpus() < 2)		
+			g5_phy_disable_cpu1();
+		if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349);
+	}
+}
+
+extern void smp_generic_give_timebase(void);
+extern void smp_generic_take_timebase(void);
+
+struct smp_ops_t core99_smp_ops __pmacdata = {
+	.message_pass	= smp_openpic_message_pass,
+	.probe		= smp_core99_probe,
+	.kick_cpu	= smp_core99_kick_cpu,
+	.setup_cpu	= smp_core99_setup_cpu,
+	.give_timebase	= smp_generic_give_timebase,
+	.take_timebase	= smp_generic_take_timebase,
+};
+
+void __init pmac_setup_smp(void)
+{
+	smp_ops = &core99_smp_ops;
+}
diff -Nru a/arch/ppc64/kernel/pmac_time.c b/arch/ppc64/kernel/pmac_time.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc64/kernel/pmac_time.c	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,157 @@
+/*
+ * Support for periodic interrupts (100 per second) and for getting
+ * the current time from the RTC on Power Macintoshes.
+ *
+ * We use the decrementer register for our periodic interrupts.
+ *
+ * Paul Mackerras	August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#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/init.h>
+#include <linux/time.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+
+#include <asm/sections.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/machdep.h>
+#include <asm/hardirq.h>
+#include <asm/time.h>
+#include <asm/nvram.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+extern void setup_default_decr(void);
+
+/* Apparently the RTC stores seconds since 1 Jan 1904 */
+#define RTC_OFFSET	2082844800
+
+/*
+ * Calibrate the decrementer frequency with the VIA timer 1.
+ */
+#define VIA_TIMER_FREQ_6	4700000	/* time 1 frequency * 6 */
+
+extern struct timezone sys_tz;
+extern void to_tm(int tim, struct rtc_time * tm);
+
+void __pmac pmac_get_rtc_time(struct rtc_time *tm)
+{
+	struct adb_request req;
+	unsigned int now;
+
+	/* Get the time from the RTC */
+	if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
+		return;
+	while (!req.complete)
+		pmu_poll();
+	if (req.reply_len != 4)
+		printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n",
+		       req.reply_len);
+	now = (req.reply[0] << 24) + (req.reply[1] << 16)
+		+ (req.reply[2] << 8) + req.reply[3];
+	DBG("get: %u -> %u\n", (int)now, (int)(now - RTC_OFFSET));
+	now -= RTC_OFFSET;
+
+	to_tm(now, tm);
+	tm->tm_year -= 1900;
+	tm->tm_mon -= 1;
+	
+	DBG("-> tm_mday: %d, tm_mon: %d, tm_year: %d, %d:%02d:%02d\n",
+	       tm->tm_mday, tm->tm_mon, tm->tm_year,
+	       tm->tm_hour, tm->tm_min, tm->tm_sec);
+}
+
+int __pmac pmac_set_rtc_time(struct rtc_time *tm)
+{
+	struct adb_request req;
+	unsigned int nowtime;
+
+	DBG("set: tm_mday: %d, tm_mon: %d, tm_year: %d, %d:%02d:%02d\n",
+	       tm->tm_mday, tm->tm_mon, tm->tm_year,
+	       tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+	nowtime = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+			 tm->tm_hour, tm->tm_min, tm->tm_sec);
+	DBG("-> %u -> %u\n", (int)nowtime, (int)(nowtime + RTC_OFFSET));
+	nowtime += RTC_OFFSET;
+
+	if (pmu_request(&req, NULL, 5, PMU_SET_RTC,
+			nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0)
+		return 0;
+	while (!req.complete)
+		pmu_poll();
+	if (req.reply_len != 0)
+		printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n",
+		       req.reply_len);
+	return 1;
+}
+
+void __init pmac_get_boot_time(struct rtc_time *tm)
+{
+	pmac_get_rtc_time(tm);
+
+#ifdef disabled__CONFIG_NVRAM
+	s32 delta = 0;
+	int dst;
+	
+	delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16;
+	delta |= ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xa)) << 8;
+	delta |= pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0xb);
+	if (delta & 0x00800000UL)
+		delta |= 0xFF000000UL;
+	dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0);
+	printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60,
+		dst ? "on" : "off");
+#endif
+}
+
+/*
+ * Query the OF and get the decr frequency.
+ * This was taken from the pmac time_init() when merging the prep/pmac
+ * time functions.
+ */
+void __init pmac_calibrate_decr(void)
+{
+	struct device_node *cpu;
+	unsigned int freq, *fp;
+	struct div_result divres;
+
+	/*
+	 * The cpu node should have a timebase-frequency property
+	 * to tell us the rate at which the decrementer counts.
+	 */
+	cpu = find_type_devices("cpu");
+	if (cpu == 0)
+		panic("can't find cpu node in time_init");
+	fp = (unsigned int *) get_property(cpu, "timebase-frequency", NULL);
+	if (fp == 0)
+		panic("can't get cpu timebase frequency");
+	freq = *fp;
+	printk("time_init: decrementer frequency = %u.%.6u MHz\n",
+	       freq/1000000, freq%1000000);
+	tb_ticks_per_jiffy = freq / HZ;
+	tb_ticks_per_sec = tb_ticks_per_jiffy * HZ;
+	tb_ticks_per_usec = freq / 1000000;
+	tb_to_us = mulhwu_scale_factor(freq, 1000000);
+	div128_by_32( 1024*1024, 0, tb_ticks_per_sec, &divres );
+	tb_to_xs = divres.result_low;
+
+	setup_default_decr();
+}
+
diff -Nru a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c
--- a/arch/ppc64/kernel/prom.c	Wed Feb 11 22:14:31 2004
+++ b/arch/ppc64/kernel/prom.c	Wed Feb 11 22:14:31 2004
@@ -30,6 +30,7 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
+#include <linux/delay.h>
 #include <asm/prom.h>
 #include <asm/rtas.h>
 #include <asm/lmb.h>
@@ -48,6 +49,7 @@
 #include <asm/pci_dma.h>
 #include <asm/bootinfo.h>
 #include <asm/ppcdebug.h>
+#include <asm/btext.h>
 #include <asm/sections.h>
 #include "open_pic.h"
 
@@ -115,24 +117,15 @@
 static interpret_func interpret_pci_props;
 static interpret_func interpret_isa_props;
 static interpret_func interpret_root_props;
+static interpret_func interpret_dbdma_props;
+static interpret_func interpret_macio_props;
 
 #ifndef FB_MAX			/* avoid pulling in all of the fb stuff */
 #define FB_MAX	8
 #endif
 
-
-struct prom_t prom = {
-	0,			/* entry */
-	0,			/* chosen */
-	0,			/* cpu */
-	0,			/* stdout */
-	0,			/* disp_node */
-	{0,0,0,{0},NULL},	/* args */
-	0,			/* version */
-	32,			/* encode_phys_size */
-	0			/* bi_rec pointer */
-};
-
+/* prom structure */
+struct prom_t prom;
 
 char *prom_display_paths[FB_MAX] __initdata = { 0, };
 unsigned int prom_num_displays = 0;
@@ -140,7 +133,6 @@
 
 extern struct rtas_t rtas;
 extern unsigned long klimit;
-extern unsigned long embedded_sysmap_end;
 extern struct lmb lmb;
 
 #define MAX_PHB 16 * 3  // 16 Towers * 3 PHBs/tower
@@ -189,6 +181,8 @@
 extern unsigned long reloc_offset(void);
 
 extern void enter_prom(void *dummy,...);
+extern void copy_and_flush(unsigned long dest, unsigned long src,
+			   unsigned long size, unsigned long offset);
 
 extern char cmd_line[512];	/* XXX */
 unsigned long dev_tree_size;
@@ -341,9 +335,14 @@
 					  RELOC("d-cache-size"),
 					  &size, sizeof(size));
 
-				call_prom(RELOC("getprop"), 4, 1, node,
-					  RELOC("d-cache-line-size"),
-					  &lsize, sizeof(lsize));
+				if (_systemcfg->platform == PLATFORM_POWERMAC)
+					call_prom(RELOC("getprop"), 4, 1, node,
+						  RELOC("d-cache-block-size"),
+						  &lsize, sizeof(lsize));
+				else
+					call_prom(RELOC("getprop"), 4, 1, node,
+						  RELOC("d-cache-line-size"),
+						  &lsize, sizeof(lsize));
 
 				_systemcfg->dCacheL1Size = size;
 				_systemcfg->dCacheL1LineSize = lsize;
@@ -354,9 +353,14 @@
 					  RELOC("i-cache-size"),
 					  &size, sizeof(size));
 
-				call_prom(RELOC("getprop"), 4, 1, node,
-					  RELOC("i-cache-line-size"),
-					  &lsize, sizeof(lsize));
+				if (_systemcfg->platform == PLATFORM_POWERMAC)
+					call_prom(RELOC("getprop"), 4, 1, node,
+						  RELOC("i-cache-block-size"),
+						  &lsize, sizeof(lsize));
+				else
+					call_prom(RELOC("getprop"), 4, 1, node,
+						  RELOC("i-cache-line-size"),
+						  &lsize, sizeof(lsize));
 
 				_systemcfg->iCacheL1Size = size;
 				_systemcfg->iCacheL1LineSize = lsize;
@@ -377,6 +381,8 @@
 			struct isa_reg_property reg;
 			union pci_range ranges;
 
+			if (_systemcfg->platform == PLATFORM_POWERMAC)
+				continue;
 			type[0] = 0;
 			call_prom(RELOC("getprop"), 4, 1, node,
 				  RELOC("ibm,aix-loc"), type, sizeof(type));
@@ -407,24 +413,27 @@
                 }
 	}
 
-	_naca->interrupt_controller = IC_INVALID;
-        for (node = 0; prom_next_node(&node); ) {
-                type[0] = 0;
-                call_prom(RELOC("getprop"), 4, 1, node, RELOC("name"),
-                          type, sizeof(type));
-                if (strcmp(type, RELOC("interrupt-controller"))) {
-			continue;
-		}
-                call_prom(RELOC("getprop"), 4, 1, node, RELOC("compatible"),
-                          type, sizeof(type));
-                if (strstr(type, RELOC("open-pic"))) {
-			_naca->interrupt_controller = IC_OPEN_PIC;
-		} else if (strstr(type, RELOC("ppc-xicp"))) {
-			_naca->interrupt_controller = IC_PPC_XIC;
-		} else {
-			prom_print(RELOC("prom: failed to recognize interrupt-controller\n"));
+	if (_systemcfg->platform == PLATFORM_POWERMAC)
+		_naca->interrupt_controller = IC_OPEN_PIC;
+	else {
+		_naca->interrupt_controller = IC_INVALID;
+		for (node = 0; prom_next_node(&node); ) {
+			type[0] = 0;
+			call_prom(RELOC("getprop"), 4, 1, node, RELOC("name"),
+				  type, sizeof(type));
+			if (strcmp(type, RELOC("interrupt-controller")))
+				continue;
+			call_prom(RELOC("getprop"), 4, 1, node, RELOC("compatible"),
+				  type, sizeof(type));
+			if (strstr(type, RELOC("open-pic")))
+				_naca->interrupt_controller = IC_OPEN_PIC;
+			else if (strstr(type, RELOC("ppc-xicp")))
+				_naca->interrupt_controller = IC_PPC_XIC;
+			else
+				prom_print(RELOC("prom: failed to recognize"
+						 " interrupt-controller\n"));
+			break;
 		}
-		break;
 	}
 
 	if (_naca->interrupt_controller == IC_INVALID) {
@@ -438,7 +447,8 @@
 
 	_systemcfg->physicalMemorySize = lmb_phys_mem_size();
 
-	if (_systemcfg->platform == PLATFORM_PSERIES) {
+	if (_systemcfg->platform == PLATFORM_PSERIES ||
+	    _systemcfg->platform == PLATFORM_POWERMAC) {
 		unsigned long rnd_mem_size, pteg_count;
 
 		/* round mem_size up to next power of 2 */
@@ -517,12 +527,19 @@
 	char type[64];
         unsigned long i, offset = reloc_offset();
 	struct prom_t *_prom = PTRRELOC(&prom);
+        struct systemcfg *_systemcfg = RELOC(systemcfg);
 	union lmb_reg_property reg;
 	unsigned long lmb_base, lmb_size;
 	unsigned long num_regs, bytes_per_reg = (_prom->encode_phys_size*2)/8;
 
 	lmb_init();
 
+	/* XXX Quick HACK. Proper fix is to drop those structures and properly use
+	 * #address-cells. PowerMac has #size-cell set to 1 and #address-cells to 2
+	 */
+	if (_systemcfg->platform == PLATFORM_POWERMAC)
+		bytes_per_reg = 12;
+
         for (node = 0; prom_next_node(&node); ) {
                 type[0] = 0;
                 call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),
@@ -535,7 +552,15 @@
 			&reg, sizeof(reg)) / bytes_per_reg;
 
 		for (i=0; i < num_regs ;i++) {
-			if (_prom->encode_phys_size == 32) {
+			if (_systemcfg->platform == PLATFORM_POWERMAC) {
+				lmb_base = ((unsigned long)reg.addrPM[i].address_hi) << 32;
+				lmb_base |= (unsigned long)reg.addrPM[i].address_lo;
+				lmb_size = reg.addrPM[i].size;
+				if (lmb_base > 0x80000000ull) {
+					prom_print(RELOC("Skipping memory above 2Gb for now, not yet supported\n"));
+					continue;
+				}
+			} else if (_prom->encode_phys_size == 32) {
 				lmb_base = reg.addr32[i].address;
 				lmb_size = reg.addr32[i].size;
 			} else {
@@ -920,19 +945,47 @@
 	struct paca_struct *_xPaca = PTRRELOC(&paca[0]);
 	struct prom_t *_prom = PTRRELOC(&prom);
 
+	/* On pmac, we just fill out the various global bitmasks and
+	 * arrays indicating our CPUs are here, they are actually started
+	 * later on from pmac_smp
+	 */
+	if (_systemcfg->platform == PLATFORM_POWERMAC) {
+		for (node = 0; prom_next_node(&node); ) {
+			type[0] = 0;
+			call_prom(RELOC("getprop"), 4, 1, node, RELOC("device_type"),
+				  type, sizeof(type));
+			if (strcmp(type, RELOC("cpu")) != 0)
+				continue;
+			reg = -1;
+			call_prom(RELOC("getprop"), 4, 1, node, RELOC("reg"),
+				  &reg, sizeof(reg));
+			_xPaca[cpuid].xHwProcNum = reg;
+
+#ifdef CONFIG_SMP
+			cpu_set(cpuid, RELOC(cpu_available_map));
+			cpu_set(cpuid, RELOC(cpu_possible_map));
+			cpu_set(cpuid, RELOC(cpu_present_at_boot));
+			if (reg == 0)
+				cpu_set(cpuid, RELOC(cpu_online_map));
+#endif /* CONFIG_SMP */
+			cpuid++;
+		}
+		return;
+	}
+
 	/* Initially, we must have one active CPU. */
 	_systemcfg->processorCount = 1;
 
 #ifdef DEBUG_PROM
 	prom_print(RELOC("prom_hold_cpus: start...\n"));
 	prom_print(RELOC("    1) spinloop       = 0x"));
-	prom_print_hex(spinloop);
+	prom_print_hex((unsigned long)spinloop);
 	prom_print_nl();
 	prom_print(RELOC("    1) *spinloop      = 0x"));
 	prom_print_hex(*spinloop);
 	prom_print_nl();
 	prom_print(RELOC("    1) acknowledge    = 0x"));
-	prom_print_hex(acknowledge);
+	prom_print_hex((unsigned long)acknowledge);
 	prom_print_nl();
 	prom_print(RELOC("    1) *acknowledge   = 0x"));
 	prom_print_hex(*acknowledge);
@@ -1210,6 +1263,144 @@
 	_naca->smt_state = my_smt_enabled;
 }
 
+
+#ifdef CONFIG_BOOTX_TEXT
+
+/* This function will enable the early boot text when doing OF booting. This
+ * way, xmon output should work too
+ */
+static void __init setup_disp_fake_bi(ihandle dp)
+{
+	int width = 640, height = 480, depth = 8, pitch;
+	unsigned address;
+	struct pci_reg_property addrs[8];
+	int i, naddrs;
+	char name[64];
+	unsigned long offset = reloc_offset();
+	char *getprop = RELOC("getprop");
+
+	prom_print(RELOC("Initializing fake screen: "));
+
+	memset(name, 0, sizeof(name));
+	call_prom(getprop, 4, 1, dp, RELOC("name"), name, sizeof(name));
+	name[sizeof(name)-1] = 0;
+	prom_print(name);
+	prom_print(RELOC("\n"));
+	call_prom(getprop, 4, 1, dp, RELOC("width"), &width, sizeof(width));
+	call_prom(getprop, 4, 1, dp, RELOC("height"), &height, sizeof(height));
+	call_prom(getprop, 4, 1, dp, RELOC("depth"), &depth, sizeof(depth));
+	pitch = width * ((depth + 7) / 8);
+	call_prom(getprop, 4, 1, dp, RELOC("linebytes"),
+		  &pitch, sizeof(pitch));
+	if (pitch == 1)
+		pitch = 0x1000;		/* for strange IBM display */
+	address = 0;
+
+	prom_print(RELOC("width "));
+	prom_print_hex(width);
+	prom_print(RELOC(" height "));
+	prom_print_hex(height);
+	prom_print(RELOC(" depth "));
+	prom_print_hex(depth);
+	prom_print(RELOC(" linebytes "));
+	prom_print_hex(pitch);
+	prom_print(RELOC("\n"));
+
+
+	call_prom(getprop, 4, 1, dp, RELOC("address"),
+		  &address, sizeof(address));
+	if (address == 0) {
+		/* look for an assigned address with a size of >= 1MB */
+		naddrs = (int) call_prom(getprop, 4, 1, dp,
+				RELOC("assigned-addresses"),
+				addrs, sizeof(addrs));
+		naddrs /= sizeof(struct pci_reg_property);
+		for (i = 0; i < naddrs; ++i) {
+			if (addrs[i].size_lo >= (1 << 20)) {
+				address = addrs[i].addr.a_lo;
+				/* use the BE aperture if possible */
+				if (addrs[i].size_lo >= (16 << 20))
+					address += (8 << 20);
+				break;
+			}
+		}
+		if (address == 0) {
+			prom_print(RELOC("Failed to get address of frame buffer\n"));
+			return;
+		}
+	}
+	btext_setup_display(width, height, depth, pitch, address);
+	prom_print(RELOC("Addr of fb: "));
+	prom_print_hex(address);
+	prom_print_nl();
+	RELOC(boot_text_mapped) = 0;
+}
+#endif /* CONFIG_BOOTX_TEXT */
+
+static void __init prom_init_client_services(unsigned long pp)
+{
+	unsigned long offset = reloc_offset();
+	struct prom_t *_prom = PTRRELOC(&prom);
+
+	/* Get a handle to the prom entry point before anything else */
+	_prom->entry = pp;
+
+	/* Init default value for phys size */
+	_prom->encode_phys_size = 32;
+
+	/* get a handle for the stdout device */
+	_prom->chosen = (ihandle)call_prom(RELOC("finddevice"), 1, 1,
+				       RELOC("/chosen"));
+	if ((long)_prom->chosen <= 0)
+		prom_panic(RELOC("cannot find chosen")); /* msg won't be printed :( */
+
+	/* get device tree root */
+	_prom->root = (ihandle)call_prom(RELOC("finddevice"), 1, 1, RELOC("/"));
+	if ((long)_prom->root <= 0)
+		prom_panic(RELOC("cannot find device tree root")); /* msg won't be printed :( */
+}
+
+static void __init prom_init_stdout(void)
+{
+	unsigned long offset = reloc_offset();
+	struct prom_t *_prom = PTRRELOC(&prom);
+	u32 val;
+
+        if ((long)call_prom(RELOC("getprop"), 4, 1, _prom->chosen,
+			    RELOC("stdout"), &val,
+			    sizeof(val)) <= 0)
+                prom_panic(RELOC("cannot find stdout"));
+
+        _prom->stdout = (ihandle)(unsigned long)val;
+}
+
+static int __init prom_find_machine_type(void)
+{
+	unsigned long offset = reloc_offset();
+	struct prom_t *_prom = PTRRELOC(&prom);
+	char compat[256];
+	int len, i = 0;
+
+	len = (int)(long)call_prom(RELOC("getprop"), 4, 1, _prom->root,
+				   RELOC("compatible"),
+				   compat, sizeof(compat)-1);
+	if (len > 0) {
+		compat[len] = 0;
+		while (i < len) {
+			char *p = &compat[i];
+			int sl = strlen(p);
+			if (sl == 0)
+				break;
+			if (strstr(p, RELOC("Power Macintosh")) ||
+			    strstr(p, RELOC("MacRISC4")))
+				return PLATFORM_POWERMAC;
+			i += sl + 1;
+		}
+	}
+	/* Default to pSeries */
+	return PLATFORM_PSERIES;
+}
+
 /*
  * We enter here early on, when the Open Firmware prom is still
  * handling exceptions and the MMU hash table for us.
@@ -1220,7 +1411,7 @@
 	  unsigned long r6, unsigned long r7)
 {
 	unsigned long mem;
-	ihandle prom_root, prom_cpu;
+	ihandle prom_cpu;
 	phandle cpu_pkg;
 	unsigned long offset = reloc_offset();
 	long l;
@@ -1239,36 +1430,27 @@
 	RELOC(systemcfg) = _systemcfg = (struct systemcfg *)(SYSTEMCFG_VIRT_ADDR - offset);
 	RELOC(naca) = (struct naca_struct *)(NACA_VIRT_ADDR - offset);
 
-	/* Default machine type. */
-	_systemcfg->platform = PLATFORM_PSERIES;
+	/* Init interface to Open Firmware and pickup bi-recs */
+	prom_init_client_services(pp);
 
-#if 0
-	/* Reset klimit to take into account the embedded system map */
-	if (RELOC(embedded_sysmap_end))
-		RELOC(klimit) = __va(PAGE_ALIGN(RELOC(embedded_sysmap_end)));
-#endif
+	/* Init prom stdout device */
+	prom_init_stdout();
 
-	/* Get a handle to the prom entry point before anything else */
-	_prom->entry = pp;
+	/* check out if we have bi_recs */
 	_prom->bi_recs = prom_bi_rec_verify((struct bi_record *)r6);
-	if ( _prom->bi_recs != NULL ) {
-		RELOC(klimit) = PTRUNRELOC((unsigned long)_prom->bi_recs + _prom->bi_recs->data[1]);
-	}
-
-	/* First get a handle for the stdout device */
-	_prom->chosen = (ihandle)call_prom(RELOC("finddevice"), 1, 1,
-				       RELOC("/chosen"));
+	if ( _prom->bi_recs != NULL )
+		RELOC(klimit) = PTRUNRELOC((unsigned long)_prom->bi_recs +
+					   _prom->bi_recs->data[1]);
 
-	if ((long)_prom->chosen <= 0)
-		prom_panic(RELOC("cannot find chosen")); /* msg won't be printed :( */
+	/* Default machine type. */
+	_systemcfg->platform = prom_find_machine_type();
 
-        if ((long)call_prom(RELOC("getprop"), 4, 1, _prom->chosen,
-			    RELOC("stdout"), &getprop_rval,
-			    sizeof(getprop_rval)) <= 0)
-                prom_panic(RELOC("cannot find stdout"));
 
-        _prom->stdout = (ihandle)(unsigned long)getprop_rval;
+	/* On pSeries, copy the CPU hold code */
+	if (_systemcfg->platform == PLATFORM_PSERIES)
+		copy_and_flush(0, KERNELBASE - offset, 0x100, 0);
 
+	/* Start storing things at klimit */
 	mem = RELOC(klimit) - offset; 
 
 	/* Get the full OF pathname of the stdout device */
@@ -1279,13 +1461,10 @@
 	mem += strlen(p) + 1;
 
 	getprop_rval = 1;
-	prom_root = (ihandle)call_prom(RELOC("finddevice"), 1, 1, RELOC("/"));
-	if (prom_root != (ihandle)-1) {
-                call_prom(RELOC("getprop"), 4, 1,
-                    prom_root, RELOC("#size-cells"),
-		    &getprop_rval, sizeof(getprop_rval));
-	}
-	_prom->encode_phys_size = (getprop_rval==1) ? 32 : 64;
+	call_prom(RELOC("getprop"), 4, 1,
+		  _prom->root, RELOC("#size-cells"),
+		  &getprop_rval, sizeof(getprop_rval));
+	_prom->encode_phys_size = (getprop_rval == 1) ? 32 : 64;
 
 	/* Determine which cpu is actually running right _now_ */
         if ((long)call_prom(RELOC("getprop"), 4, 1, _prom->chosen,
@@ -1324,13 +1503,24 @@
 		mem = DOUBLEWORD_ALIGN(mem + strlen(d) + 1);
 	}
 
+	RELOC(cmd_line[0]) = 0;
+	if ((long)_prom->chosen > 0) {
+		call_prom(RELOC("getprop"), 4, 1, _prom->chosen, 
+			  RELOC("bootargs"), p, sizeof(cmd_line));
+		if (p != NULL && p[0] != 0)
+			strncpy(RELOC(cmd_line), p, sizeof(cmd_line));
+	}
+	RELOC(cmd_line[sizeof(cmd_line) - 1]) = 0;
+
+
 	mem = prom_initialize_lmb(mem);
 
 	mem = prom_bi_rec_reserve(mem);
 
 	mem = check_display(mem);
 
-	prom_instantiate_rtas();
+	if (_systemcfg->platform != PLATFORM_POWERMAC)
+		prom_instantiate_rtas();
         
         /* Initialize some system info into the Naca early... */
         mem = prom_initialize_naca(mem);
@@ -1341,7 +1531,7 @@
          * following, regardless of whether we have an SMP
          * kernel or not.
          */
-	        prom_hold_cpus(mem);
+	prom_hold_cpus(mem);
 
 #ifdef DEBUG_PROM
 	prom_print(RELOC("copying OF device tree...\n"));
@@ -1355,6 +1545,13 @@
 	if (_systemcfg->platform == PLATFORM_PSERIES)
 		prom_initialize_tce_table();
 
+#ifdef CONFIG_BOOTX_TEXT
+	if(_prom->disp_node) {
+		prom_print(RELOC("Setting up bi display...\n"));
+		setup_disp_fake_bi(_prom->disp_node);
+	}
+#endif /* CONFIG_BOOTX_TEXT */
+
 	prom_print(RELOC("Calling quiesce ...\n"));
 	call_prom(RELOC("quiesce"), 0, 0);
 	phys = KERNELBASE - offset;
@@ -1471,6 +1668,10 @@
 		RELOC(prom_display_paths[i]) = PTRUNRELOC(path);
 		if (RELOC(prom_num_displays) >= FB_MAX)
 			break;
+		/* XXX Temporary workaround: only open the first display so we don't
+		 * lose debug output
+		 */
+		break;
 	}
 	return DOUBLEWORD_ALIGN(mem);
 }
@@ -1684,9 +1885,9 @@
 	np->type = get_property(np, "device_type", 0);
 
 	/* get the device addresses and interrupts */
-	if (ifunc != NULL) {
-	  mem_start = ifunc(np, mem_start, naddrc, nsizec);
-	}
+	if (ifunc != NULL)
+		mem_start = ifunc(np, mem_start, naddrc, nsizec);
+
 	mem_start = finish_node_interrupts(np, mem_start);
 
 	/* Look for #address-cells and #size-cells properties. */
@@ -1700,7 +1901,6 @@
 	/* the f50 sets the name to 'display' and 'compatible' to what we
 	 * expect for the name -- Cort
 	 */
-	ifunc = NULL;
 	if (!strcmp(np->name, "display"))
 		np->name = get_property(np, "compatible", 0);
 
@@ -1710,8 +1910,19 @@
 		ifunc = NULL;
 	else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci"))
 		ifunc = interpret_pci_props;
+	else if (!strcmp(np->type, "dbdma"))
+		ifunc = interpret_dbdma_props;
+	else if (!strcmp(np->type, "mac-io") || ifunc == interpret_macio_props)
+		ifunc = interpret_macio_props;
 	else if (!strcmp(np->type, "isa"))
 		ifunc = interpret_isa_props;
+	else if (!strcmp(np->name, "uni-n") || !strcmp(np->name, "u3"))
+		ifunc = interpret_root_props;
+	else if (!((ifunc == interpret_dbdma_props
+		    || ifunc == interpret_macio_props)
+		   && (!strcmp(np->type, "escc")
+		       || !strcmp(np->type, "media-bay"))))
+		ifunc = NULL;
 
 	for (child = np->child; child != NULL; child = child->sibling)
 		mem_start = finish_node(child, mem_start, ifunc,
@@ -1888,6 +2099,12 @@
 		if (n <= 0)
 			continue;
 		np->intrs[i].line = openpic_to_irq(virt_irq_create_mapping(irq[0]));
+		/* We offset irq numbers for the u3 MPIC by 128 in PowerMac */
+		if (systemcfg->platform == PLATFORM_POWERMAC && ic && ic->parent) {
+			char *name = get_property(ic->parent, "name", NULL);
+			if (name && !strcmp(name, "u3"))
+				np->intrs[i].line += 128;
+		}
 		if (n > 1)
 			np->intrs[i].sense = irq[1];
 		if (n > 2) {
@@ -1960,6 +2177,78 @@
 }
 
 static unsigned long __init
+interpret_dbdma_props(struct device_node *np, unsigned long mem_start,
+		      int naddrc, int nsizec)
+{
+	struct reg_property32 *rp;
+	struct address_range *adr;
+	unsigned long base_address;
+	int i, l;
+	struct device_node *db;
+
+	base_address = 0;
+	for (db = np->parent; db != NULL; db = db->parent) {
+		if (!strcmp(db->type, "dbdma") && db->n_addrs != 0) {
+			base_address = db->addrs[0].address;
+			break;
+		}
+	}
+
+	rp = (struct reg_property32 *) get_property(np, "reg", &l);
+	if (rp != 0 && l >= sizeof(struct reg_property32)) {
+		i = 0;
+		adr = (struct address_range *) mem_start;
+		while ((l -= sizeof(struct reg_property32)) >= 0) {
+			adr[i].space = 2;
+			adr[i].address = rp[i].address + base_address;
+			adr[i].size = rp[i].size;
+			++i;
+		}
+		np->addrs = adr;
+		np->n_addrs = i;
+		mem_start += i * sizeof(struct address_range);
+	}
+
+	return mem_start;
+}
+
+static unsigned long __init
+interpret_macio_props(struct device_node *np, unsigned long mem_start,
+		      int naddrc, int nsizec)
+{
+	struct reg_property32 *rp;
+	struct address_range *adr;
+	unsigned long base_address;
+	int i, l;
+	struct device_node *db;
+
+	base_address = 0;
+	for (db = np->parent; db != NULL; db = db->parent) {
+		if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) {
+			base_address = db->addrs[0].address;
+			break;
+		}
+	}
+
+	rp = (struct reg_property32 *) get_property(np, "reg", &l);
+	if (rp != 0 && l >= sizeof(struct reg_property32)) {
+		i = 0;
+		adr = (struct address_range *) mem_start;
+		while ((l -= sizeof(struct reg_property32)) >= 0) {
+			adr[i].space = 2;
+			adr[i].address = rp[i].address + base_address;
+			adr[i].size = rp[i].size;
+			++i;
+		}
+		np->addrs = adr;
+		np->n_addrs = i;
+		mem_start += i * sizeof(struct address_range);
+	}
+
+	return mem_start;
+}
+
+static unsigned long __init
 interpret_isa_props(struct device_node *np, unsigned long mem_start,
 		    int naddrc, int nsizec)
 {
@@ -2207,6 +2496,7 @@
 	read_unlock(&devtree_lock);
 	return np;
 }
+EXPORT_SYMBOL(of_find_node_by_name);
 
 /**
  *	of_find_node_by_type - Find a node by its "device_type" property
@@ -2270,6 +2560,7 @@
 	read_unlock(&devtree_lock);
 	return np;
 }
+EXPORT_SYMBOL(of_find_compatible_node);
 
 /**
  *	of_find_node_by_path - Find a node matching a full OF path
@@ -2290,6 +2581,7 @@
 	read_unlock(&devtree_lock);
 	return np;
 }
+EXPORT_SYMBOL(of_find_node_by_path);
 
 /**
  *	of_find_all_nodes - Get next node in global list
@@ -2313,6 +2605,7 @@
 	read_unlock(&devtree_lock);
 	return np;
 }
+EXPORT_SYMBOL(of_find_all_nodes);
 
 /**
  *	of_get_parent - Get a node's parent if any
@@ -2333,6 +2626,7 @@
 	read_unlock(&devtree_lock);
 	return np;
 }
+EXPORT_SYMBOL(of_get_parent);
 
 /**
  *	of_get_next_child - Iterate a node childs
@@ -2357,6 +2651,7 @@
 	read_unlock(&devtree_lock);
 	return next;
 }
+EXPORT_SYMBOL(of_get_next_child);
 
 /**
  *	of_node_get - Increment refcount of a node
@@ -2373,6 +2668,7 @@
 	}
 	return NULL;
 }
+EXPORT_SYMBOL(of_node_get);
 
 /**
  *	of_node_put - Decrement refcount of a node
@@ -2396,6 +2692,7 @@
 	else
 		atomic_dec(&node->_users);
 }
+EXPORT_SYMBOL(of_node_put);
 
 /**
  *	of_node_cleanup - release a dynamically allocated node
@@ -2652,6 +2949,12 @@
 		err = -ENODEV;
 		goto out;
 	}
+
+	/* We don't support that function on PowerMac, at least
+	 * not yet
+	 */
+	if (systemcfg->platform == PLATFORM_POWERMAC)
+		return -ENODEV;
 
 	/* do the work of interpret_pci_props */
 	if (parent->type && !strcmp(parent->type, "pci")) {
diff -Nru a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c
--- a/arch/ppc64/kernel/setup.c	Wed Feb 11 22:14:31 2004
+++ b/arch/ppc64/kernel/setup.c	Wed Feb 11 22:14:31 2004
@@ -40,6 +40,8 @@
 #include <asm/time.h>
 #include <asm/cputable.h>
 #include <asm/sections.h>
+#include <asm/btext.h>
+#include <asm/nvram.h>
 
 extern unsigned long klimit;
 /* extern void *stab; */
@@ -54,10 +56,17 @@
 		       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 iSeries_init( void );
 extern void iSeries_init_early( void );
 extern void pSeries_init_early( void );
 extern void pSeriesLP_init_early(void);
+extern void pmac_init_early(void);
 extern void mm_init_ppc64( void ); 
 extern void pseries_secondary_smp_init(unsigned long); 
 extern int  idle_setup(void);
@@ -68,6 +77,8 @@
 unsigned long decr_overclock_set = 0;
 unsigned long decr_overclock_proc0_set = 0;
 
+int powersave_nap;
+
 #ifdef CONFIG_XMON
 extern void xmon_map_scc(void);
 #endif
@@ -188,9 +199,25 @@
 #endif
 		parse_bootinfo();
 		break;
+#endif /* CONFIG_PPC_PSERIES */
+#ifdef CONFIG_PPC_PMAC
+	case PLATFORM_POWERMAC:
+		pmac_init_early();
+#ifdef CONFIG_BLK_DEV_INITRD
+		initrd_start = initrd_end = 0;
 #endif
+		parse_bootinfo();
+#endif /* CONFIG_PPC_PMAC */
 	}
 
+#ifdef CONFIG_BOOTX_TEXT
+	map_boot_text();
+	if (systemcfg->platform == PLATFORM_POWERMAC) {
+		early_console_initialized = 1;
+		register_console(&udbg_console);
+	}
+#endif /* CONFIG_BOOTX_TEXT */
+
 #ifdef CONFIG_PPC_PSERIES
 	if (systemcfg->platform & PLATFORM_PSERIES) {
 		early_console_initialized = 1;
@@ -206,14 +233,23 @@
 				rtas_call(rtas_token("start-cpu"), 3, 1, 
 					  (void *)&ret,
 					  get_hard_smp_processor_id(i), 
-					  *((unsigned long *)pseries_secondary_smp_init), i);
+					  *((unsigned long *)pseries_secondary_smp_init),
+					  i);
 				cpu_set(i, cpu_possible_map);
 				systemcfg->processorCount++;
 			}
 		}
-#endif
 	}
-#endif
+#endif /* CONFIG_SMP */
+#endif /* CONFIG_PPC_PSERIES */
+
+#ifdef CONFIG_PPC_PMAC
+	if (systemcfg->platform == PLATFORM_POWERMAC) {
+		finish_device_tree();
+		pmac_init(r3, r4, r5, r6, r7);
+	}
+#endif /* CONFIG_PPC_PMAC */
+
 	/* Finish initializing the hash table (do the dynamic
 	 * patching for the fast-path hashtable.S code)
 	 */
@@ -226,7 +262,7 @@
 	printk("naca->pftSize                 = 0x%lx\n", naca->pftSize);
 	printk("naca->debug_switch            = 0x%lx\n", naca->debug_switch);
 	printk("naca->interrupt_controller    = 0x%ld\n", naca->interrupt_controller);
-	printk("systemcfg                      = 0x%p\n", systemcfg);
+	printk("systemcfg                     = 0x%p\n", systemcfg);
 	printk("systemcfg->processorCount     = 0x%lx\n", systemcfg->processorCount);
 	printk("systemcfg->physicalMemorySize = 0x%lx\n", systemcfg->physicalMemorySize);
 	printk("systemcfg->dCacheL1LineSize   = 0x%x\n", systemcfg->dCacheL1LineSize);
@@ -261,6 +297,8 @@
 
 void machine_restart(char *cmd)
 {
+	if (ppc_md.nvram_sync)
+		ppc_md.nvram_sync();
 	ppc_md.restart(cmd);
 }
 
@@ -268,6 +306,8 @@
   
 void machine_power_off(void)
 {
+	if (ppc_md.nvram_sync)
+		ppc_md.nvram_sync();
 	ppc_md.power_off();
 }
 
@@ -275,6 +315,8 @@
   
 void machine_halt(void)
 {
+	if (ppc_md.nvram_sync)
+		ppc_md.nvram_sync();
 	ppc_md.halt();
 }
 
diff -Nru a/arch/ppc64/kernel/smp-tbsync.c b/arch/ppc64/kernel/smp-tbsync.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc64/kernel/smp-tbsync.c	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,179 @@
+/*
+ * Smp timebase synchronization for ppc.
+ *
+ * Copyright (C) 2003 Samuel Rydh (samuel@ibrium.se)
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/unistd.h>
+#include <linux/init.h>
+#include <asm/atomic.h>
+#include <asm/smp.h>
+#include <asm/time.h>
+
+#define NUM_ITER		300
+
+enum {
+	kExit=0, kSetAndTest, kTest
+};
+
+static struct {
+	volatile long		tb;
+	volatile long		mark;
+	volatile int		cmd;
+	volatile int		handshake;
+	int			filler[3];
+
+	volatile int		ack;
+	int			filler2[7];
+
+	volatile int		race_result;
+} *tbsync;
+
+static volatile int		running;
+
+static void __devinit
+enter_contest( long mark, long add )
+{
+	while( (long)(mftb() - mark) < 0 )
+		tbsync->race_result = add;
+}
+
+void __devinit
+smp_generic_take_timebase( void )
+{
+	int cmd;
+	long tb;
+
+	local_irq_disable();
+	while( !running )
+		;
+	rmb();
+
+	for( ;; ) {
+		tbsync->ack = 1;
+		while( !tbsync->handshake )
+			;
+		rmb();
+
+		cmd = tbsync->cmd;
+		tb = tbsync->tb;
+		tbsync->ack = 0;
+		if( cmd == kExit )
+			return;
+
+		if( cmd == kSetAndTest ) {
+			while( tbsync->handshake )
+				;
+			asm volatile ("mttbl %0" :: "r" (tb & 0xfffffffful) );
+			asm volatile ("mttbu %0" :: "r" (tb >> 32) );
+		} else {
+			while( tbsync->handshake )
+				;
+		}
+		enter_contest( tbsync->mark, -1 );
+	}
+	local_irq_enable();
+}
+
+static int __devinit
+start_contest( int cmd, long offset, long num )
+{
+	int i, score=0;
+	long tb, mark;
+
+	tbsync->cmd = cmd;
+
+	local_irq_disable();
+	for( i=-3; i<num; ) {
+		tb = (long)mftb() + 400;
+		tbsync->tb = tb + offset;
+		tbsync->mark = mark = tb + 400;
+
+		wmb();
+
+		tbsync->handshake = 1;
+		while( tbsync->ack )
+			;
+
+		while( (long)(mftb() - tb) <= 0 )
+			;
+		tbsync->handshake = 0;
+		enter_contest( mark, 1 );
+
+		while( !tbsync->ack )
+			;
+
+	       	if ((tbsync->tb ^ (long)mftb()) & 0x8000000000000000ul)
+			continue;
+		if( i++ > 0 )
+			score += tbsync->race_result;
+	}
+	local_irq_enable();
+	return score;
+}
+
+void __devinit
+smp_generic_give_timebase( void )
+{
+	int i, score, score2, old, min=0, max=5000, offset=1000;
+
+	printk("Synchronizing timebase\n");
+
+	/* if this fails then this kernel won't work anyway... */
+	tbsync = kmalloc( sizeof(*tbsync), GFP_KERNEL );
+	memset( tbsync, 0, sizeof(*tbsync) );
+	mb();
+	running = 1;
+
+	while( !tbsync->ack )
+		;
+
+	printk("Got ack\n");
+
+	/* binary search */
+	for( old=-1 ; old != offset ; offset=(min+max)/2 ) {
+		score = start_contest( kSetAndTest, offset, NUM_ITER );
+
+		printk("score %d, offset %d\n", score, offset );
+
+		if( score > 0 )
+			max = offset;
+		else
+			min = offset;
+		old = offset;
+	}
+	score = start_contest( kSetAndTest, min, NUM_ITER );
+	score2 = start_contest( kSetAndTest, max, NUM_ITER );
+
+	printk( "Min %d (score %d), Max %d (score %d)\n", min, score, max, score2 );
+	score = abs( score );
+	score2 = abs( score2 );
+	offset = (score < score2) ? min : max;
+
+	/* guard against inaccurate mttb */
+	for( i=0; i<10; i++ ) {
+		start_contest( kSetAndTest, offset, NUM_ITER/10 );
+
+		if( (score2=start_contest(kTest, offset, NUM_ITER)) < 0 )
+			score2 = -score2;
+		if( score2 <= score || score2 < 20 )
+			break;
+	}
+	printk("Final offset: %d (%d/%d)\n", offset, score2, NUM_ITER );
+
+	/* exiting */
+	tbsync->cmd = kExit;
+	wmb();
+	tbsync->handshake = 1;
+	while( tbsync->ack )
+		;
+	tbsync->handshake = 0;
+	kfree( tbsync );
+	tbsync = NULL;
+	running = 0;
+}
diff -Nru a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c
--- a/arch/ppc64/kernel/smp.c	Wed Feb 11 22:14:31 2004
+++ b/arch/ppc64/kernel/smp.c	Wed Feb 11 22:14:31 2004
@@ -62,7 +62,7 @@
 EXPORT_SYMBOL(cpu_online_map);
 EXPORT_SYMBOL(cpu_possible_map);
 
-static struct smp_ops_t *smp_ops;
+struct smp_ops_t *smp_ops;
 
 static volatile unsigned int cpu_callin_map[NR_CPUS];
 
@@ -76,13 +76,8 @@
 
 #define smp_message_pass(t,m,d,w) smp_ops->message_pass((t),(m),(d),(w))
 
-static inline void set_tb(unsigned int upper, unsigned int lower)
-{
-	mttbl(0);
-	mttbu(upper);
-	mttbl(lower);
-}
-
+/* Low level assembly function used to backup CPU 0 state */
+extern void __save_cpu_setup(void);
 #ifdef CONFIG_PPC_ISERIES
 static unsigned long iSeries_smp_message[NR_CPUS];
 
@@ -182,21 +177,23 @@
 {
 }
 
+static struct smp_ops_t iSeries_smp_ops = {
+	.message_pass = smp_iSeries_message_pass,
+	.probe        = smp_iSeries_probe,
+	.kick_cpu     = smp_iSeries_kick_cpu,
+	.setup_cpu    = smp_iSeries_setup_cpu,
+};
+
 /* This is called very early. */
 void __init smp_init_iSeries(void)
 {
-	smp_ops = &ppc_md.smp_ops;
-	smp_ops->message_pass = smp_iSeries_message_pass;
-	smp_ops->probe        = smp_iSeries_probe;
-	smp_ops->kick_cpu     = smp_iSeries_kick_cpu;
-	smp_ops->setup_cpu    = smp_iSeries_setup_cpu;
+	smp_ops = &iSeries_smp_ops;
 	systemcfg->processorCount	= smp_iSeries_numProcs();
 }
 #endif
 
 #ifdef CONFIG_PPC_PSERIES
-static void
-smp_openpic_message_pass(int target, int msg, unsigned long data, int wait)
+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 ){
@@ -240,8 +237,7 @@
 	do_openpic_setup_cpu();
 }
 
-static void
-smp_kick_cpu(int nr)
+static void smp_pSeries_kick_cpu(int nr)
 {
 	/* Verify we have a Paca for processor nr */
 	if ( ( nr <= 0 ) ||
@@ -290,8 +286,7 @@
 	register_vpa(flags, cpu, __pa((unsigned long)&(paca[cpu].xLpPaca))); 
 }
 
-static void
-smp_xics_message_pass(int target, int msg, unsigned long data, int wait)
+static void smp_xics_message_pass(int target, int msg, unsigned long data, int wait)
 {
 	int i;
 
@@ -358,27 +353,34 @@
 	spin_unlock(&timebase_lock);
 }
 
+static struct smp_ops_t pSeries_openpic_smp_ops = {
+	.message_pass	= smp_openpic_message_pass,
+	.probe		= smp_openpic_probe,
+	.kick_cpu	= smp_pSeries_kick_cpu,
+	.setup_cpu	= smp_openpic_setup_cpu,
+};
+
+static struct smp_ops_t pSeries_xics_smp_ops = {
+	.message_pass	= smp_xics_message_pass,
+	.probe		= smp_xics_probe,
+	.kick_cpu	= smp_pSeries_kick_cpu,
+	.setup_cpu	= smp_xics_setup_cpu,
+};
+
 /* This is called very early */
 void __init smp_init_pSeries(void)
 {
-	smp_ops = &ppc_md.smp_ops;
 
-	if (naca->interrupt_controller == IC_OPEN_PIC) {
-		smp_ops->message_pass	= smp_openpic_message_pass;
-		smp_ops->probe		= smp_openpic_probe;
-		smp_ops->setup_cpu	= smp_openpic_setup_cpu;
-	} else {
-		smp_ops->message_pass	= smp_xics_message_pass;
-		smp_ops->probe		= smp_xics_probe;
-		smp_ops->setup_cpu	= smp_xics_setup_cpu;
-	}
+	if (naca->interrupt_controller == IC_OPEN_PIC)
+		smp_ops = &pSeries_openpic_smp_ops;
+	else
+		smp_ops = &pSeries_xics_smp_ops;
 
+	/* Non-lpar has additional take/give timebase */
 	if (systemcfg->platform == PLATFORM_PSERIES) {
 		smp_ops->give_timebase = pSeries_give_timebase;
 		smp_ops->take_timebase = pSeries_take_timebase;
 	}
-
-	smp_ops->kick_cpu = smp_kick_cpu;
 }
 #endif
 
@@ -613,6 +615,10 @@
 #endif
 
 	max_cpus = smp_ops->probe();
+ 
+	/* Backup CPU 0 state if necessary */
+	__save_cpu_setup();
+
 	smp_space_timers(max_cpus);
 }
 
diff -Nru a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c
--- a/arch/ppc64/kernel/sys_ppc32.c	Wed Feb 11 22:14:31 2004
+++ b/arch/ppc64/kernel/sys_ppc32.c	Wed Feb 11 22:14:31 2004
@@ -76,6 +76,8 @@
 #include <asm/ppc32.h>
 #include <asm/mmu_context.h>
 
+#include "pci.h"
+
 typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
 typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
 
@@ -2210,7 +2212,7 @@
 
 
 extern asmlinkage int sys_pciconfig_write(unsigned long bus, unsigned long dfn, unsigned long off,
-					                                unsigned long len, unsigned char *buf);
+					  unsigned long len, unsigned char *buf);
 
 asmlinkage int sys32_pciconfig_write(u32 bus, u32 dfn, u32 off, u32 len, u32 ubuf)
 {
@@ -2220,6 +2222,64 @@
 				   (unsigned long) len,
 				   (unsigned char *)AA(ubuf));
 }
+
+#define IOBASE_BRIDGE_NUMBER	0
+#define IOBASE_MEMORY		1
+#define IOBASE_IO		2
+#define IOBASE_ISA_IO		3
+#define IOBASE_ISA_MEM		4
+
+asmlinkage int sys32_pciconfig_iobase(u32 which, u32 in_bus, u32 in_devfn)
+{
+	struct pci_controller* hose;
+	struct list_head *ln;
+	struct pci_bus *bus = NULL;
+	struct device_node *hose_node;
+
+	/* Argh ! Please forgive me for that hack, but that's the
+	 * simplest way to get existing XFree to not lockup on some
+	 * G5 machines... So when something asks for bus 0 io base
+	 * (bus 0 is HT root), we return the AGP one instead.
+	 */
+#ifdef CONFIG_PPC_PMAC
+	if (systemcfg->platform == PLATFORM_POWERMAC &&
+	    machine_is_compatible("MacRISC4"))
+		if (in_bus == 0)
+			in_bus = 0xf0;
+#endif /* CONFIG_PPC_PMAC */
+
+	/* That syscall isn't quite compatible with PCI domains, but it's
+	 * used on pre-domains setup. We return the first match
+	 */
+
+	for (ln = pci_root_buses.next; ln != &pci_root_buses; ln = ln->next) {
+		bus = pci_bus_b(ln);
+		if (in_bus >= bus->number && in_bus < (bus->number + bus->subordinate))
+			break;
+		bus = NULL;
+	}
+	if (bus == NULL || bus->sysdata == NULL)
+		return -ENODEV;
+
+	hose_node = (struct device_node *)bus->sysdata;
+	hose = hose_node->phb;
+
+	switch (which) {
+	case IOBASE_BRIDGE_NUMBER:
+		return (long)hose->first_busno;
+	case IOBASE_MEMORY:
+		return (long)hose->pci_mem_offset;
+	case IOBASE_IO:
+		return (long)hose->io_base_phys;
+	case IOBASE_ISA_IO:
+		return (long)isa_io_base;
+	case IOBASE_ISA_MEM:
+		return -EINVAL;
+	}
+
+	return -EOPNOTSUPP;
+}
+
 
 extern asmlinkage int sys_newuname(struct new_utsname * name);
 
diff -Nru a/arch/ppc64/kernel/udbg.c b/arch/ppc64/kernel/udbg.c
--- a/arch/ppc64/kernel/udbg.c	Wed Feb 11 22:14:30 2004
+++ b/arch/ppc64/kernel/udbg.c	Wed Feb 11 22:14:30 2004
@@ -22,6 +22,9 @@
 #include <asm/naca.h>
 #include <asm/uaccess.h>
 #include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pmac_feature.h>
 
 struct NS16550 {
 	/* this struct must be packed */
@@ -69,6 +72,61 @@
 	}
 }
 
+#ifdef CONFIG_PPC_PMAC
+
+#define	SCC_TXRDY	4
+#define SCC_RXRDY	1
+
+static volatile u8 *sccc, *sccd;
+
+static unsigned char scc_inittab[] = {
+    13, 0,		/* set baud rate divisor */
+    12, 0,
+    14, 1,		/* baud rate gen enable, src=rtxc */
+    11, 0x50,		/* clocks = br gen */
+    5,  0xea,		/* tx 8 bits, assert DTR & RTS */
+    4,  0x46,		/* x16 clock, 1 stop */
+    3,  0xc1,		/* rx enable, 8 bits */
+};
+
+void
+udbg_init_scc(struct device_node *np)
+{
+	unsigned long addr;
+	int i, x;
+
+	if (np == NULL)
+		np = of_find_node_by_name(NULL, "escc");
+	if (np == NULL)
+		return;
+	
+	/* Lock-enable the SCC channel */
+	pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1);
+
+	/* Setup for 57600 8N1 */
+	addr = np->addrs[0].address + 0x20;
+	sccc = (volatile u8 *) ioremap(addr & PAGE_MASK, PAGE_SIZE) ;
+	sccc += addr & ~PAGE_MASK;
+	sccd = sccc + 0x10;
+
+	for (i = 20000; i != 0; --i)
+		x = *sccc; eieio();
+	*sccc = 9; eieio();		/* reset A or B side */
+	*sccc = 0xc0; eieio();
+	for (i = 0; i < sizeof(scc_inittab); ++i) {
+		*sccc = scc_inittab[i];
+		eieio();
+	}
+
+	ppc_md.udbg_putc = udbg_putc;
+	ppc_md.udbg_getc = udbg_getc;
+	ppc_md.udbg_getc_poll = udbg_getc_poll;
+
+	udbg_puts("Hello World !\n");
+}
+
+#endif /* CONFIG_PPC_PMAC */
+
 void
 udbg_putc(unsigned char c)
 {
@@ -83,6 +141,16 @@
 			udbg_comport->thr = '\r'; eieio();
 		}
 	}
+#ifdef CONFIG_PPC_PMAC
+	else if (sccc) {
+		while ((*sccc & SCC_TXRDY) == 0)
+			eieio();
+		*sccd = c;		
+		eieio();
+		if (c == '\n')
+			udbg_putc('\r');
+	}
+#endif /* CONFIG_PPC_PMAC */
 }
 
 int udbg_getc_poll(void)
@@ -93,6 +161,15 @@
 		else
 			return -1;
 	}
+#ifdef CONFIG_PPC_PMAC
+	else if (sccc) {
+		eieio();
+		if ((*sccc & SCC_RXRDY) != 0)
+			return *sccd;
+		else
+			return -1;
+	}
+#endif /* CONFIG_PPC_PMAC */
 	return -1;
 }
 
@@ -104,6 +181,14 @@
 			/* wait for char */;
 		return udbg_comport->rbr;
 	}
+#ifdef CONFIG_PPC_PMAC
+	else if (sccc) {
+		eieio();
+		while ((*sccc & SCC_RXRDY) == 0)
+			eieio();
+		return *sccd;
+	}
+#endif /* CONFIG_PPC_PMAC */
 	return 0;
 }
 
@@ -149,6 +234,8 @@
 		do {
 			c = ppc_md.udbg_getc();
 		} while (c == 0x11 || c == 0x13);
+		if (c == 0)
+			break;
 		*p++ = c;
 	}
 	return i;
diff -Nru a/arch/ppc64/mm/hash_low.S b/arch/ppc64/mm/hash_low.S
--- a/arch/ppc64/mm/hash_low.S	Wed Feb 11 22:14:31 2004
+++ b/arch/ppc64/mm/hash_low.S	Wed Feb 11 22:14:31 2004
@@ -95,7 +95,7 @@
 	/* Write the linux PTE atomically (setting busy) */
 	stdcx.	r30,0,r6
 	bne-	1b
-	
+	isync
 
 	/* Step 2:
 	 *
diff -Nru a/arch/ppc64/mm/hash_utils.c b/arch/ppc64/mm/hash_utils.c
--- a/arch/ppc64/mm/hash_utils.c	Wed Feb 11 22:14:31 2004
+++ b/arch/ppc64/mm/hash_utils.c	Wed Feb 11 22:14:31 2004
@@ -140,7 +140,8 @@
 	htab_data.htab_num_ptegs = pteg_count;
 	htab_data.htab_hash_mask = pteg_count - 1;
 
-	if (systemcfg->platform == PLATFORM_PSERIES) {
+	if (systemcfg->platform == PLATFORM_PSERIES ||
+	    systemcfg->platform == PLATFORM_POWERMAC) {
 		/* Find storage for the HPT.  Must be contiguous in
 		 * the absolute address space.
 		 */
diff -Nru a/arch/ppc64/xmon/xmon.c b/arch/ppc64/xmon/xmon.c
--- a/arch/ppc64/xmon/xmon.c	Wed Feb 11 22:14:31 2004
+++ b/arch/ppc64/xmon/xmon.c	Wed Feb 11 22:14:31 2004
@@ -847,7 +847,8 @@
 			break;
 		}
 		
-		if (!(systemcfg->platform & PLATFORM_PSERIES)) {
+		if (systemcfg->platform != PLATFORM_POWERMAC &&
+		   !(systemcfg->platform & PLATFORM_PSERIES)) {
 			printf("Not supported for this platform\n");
 			break;
 		}
diff -Nru a/arch/sh/Kconfig b/arch/sh/Kconfig
--- a/arch/sh/Kconfig	Wed Feb 11 22:14:31 2004
+++ b/arch/sh/Kconfig	Wed Feb 11 22:14:31 2004
@@ -940,61 +940,7 @@
 	  <ftp://gnu.systemy.it/pub/gpm/>) solves this problem, or you can get
 	  the "mconv2" utility from <ftp://ibiblio.org/pub/Linux/system/mouse/>.
 
-
-menu "Watchdog Cards"
-
-config WATCHDOG
-	bool "Watchdog Timer Support"
-	---help---
-	  If you say Y here (and to one of the following options) and create a
-	  character special file /dev/watchdog with major number 10 and minor
-	  number 130 using mknod ("man mknod"), you will get a watchdog, i.e.:
-	  subsequently opening the file and then failing to write to it for
-	  longer than 1 minute will result in rebooting the machine. This
-	  could be useful for a networked machine that needs to come back
-	  online as fast as possible after a lock-up. There's both a watchdog
-	  implementation entirely in software (which can sometimes fail to
-	  reboot the machine) and a driver for hardware watchdog boards, which
-	  are more robust and can also keep track of the temperature inside
-	  your computer. For details, read <file:Documentation/watchdog/watchdog.txt>
-	  in the kernel source.
-
-	  The watchdog is usually used together with the watchdog daemon
-	  which is available from
-	  <ftp://ibiblio.org/pub/Linux/system/daemons/watchdog/>. This daemon can
-	  also monitor NFS connections and can reboot the machine when the process
-	  table is full.
-
-	  If unsure, say N.
-
-config WATCHDOG_NOWAYOUT
-	bool "Disable watchdog shutdown on close"
-	depends on WATCHDOG
-	help
-	  The default watchdog behaviour (which you get if you say N here) is
-	  to stop the timer if the process managing it closes the file
-	  /dev/watchdog. It's always remotely possible that this process might
-	  get killed. If you say Y here, the watchdog cannot be stopped once
-	  it has been started.
-
-config SH_WDT
-	tristate "SuperH Watchdog"
-	depends on WATCHDOG
-	help
-	  This driver adds watchdog support for the integrated watchdog in the
-	  SuperH processors. If you have one of these processors and wish
-	  to have watchdog support enabled, say Y, otherwise say N.
-
-	  As a side note, saying Y here will automatically boost HZ to 1000
-	  so that the timer has a chance to clear the overflow counter. On
-	  slower systems (such as the SH-2 and SH-3) this will likely yield
-	  some performance issues. As such, the WDT should be avoided here
-	  unless it is absolutely necessary.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called shwdt.
-
-endmenu
+source "drivers/char/watchdog/Kconfig"
 
 config RTC
 	tristate "Enhanced Real Time Clock Support"
diff -Nru a/arch/sparc/Kconfig b/arch/sparc/Kconfig
--- a/arch/sparc/Kconfig	Wed Feb 11 22:14:30 2004
+++ b/arch/sparc/Kconfig	Wed Feb 11 22:14:30 2004
@@ -376,20 +376,7 @@
 
 source "drivers/usb/Kconfig"
 
-menu "Watchdog"
-
-config SOFT_WATCHDOG
-	tristate "Software watchdog"
-	help
-	  A software monitoring watchdog. This will fail to reboot your system
-	  from some situations that the hardware watchdog will recover
-	  from. Equally it's a lot cheaper to install.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called softdog.
-
-endmenu
-
+source "drivers/char/watchdog/Kconfig"
 
 menu "Kernel hacking"
 
diff -Nru a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
--- a/arch/sparc64/Kconfig	Wed Feb 11 22:14:31 2004
+++ b/arch/sparc64/Kconfig	Wed Feb 11 22:14:31 2004
@@ -639,20 +639,7 @@
 
 source "drivers/usb/Kconfig"
 
-
-menu "Watchdog"
-
-config SOFT_WATCHDOG
-	tristate "Software watchdog"
-	help
-	  A software monitoring watchdog. This will fail to reboot your system
-	  from some situations that the hardware watchdog will recover
-	  from. Equally it's a lot cheaper to install.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called softdog.
-
-endmenu
+source "drivers/char/watchdog/Kconfig"
 
 source "arch/sparc64/oprofile/Kconfig"
 
diff -Nru a/arch/sparc64/lib/VIScopy.S b/arch/sparc64/lib/VIScopy.S
--- a/arch/sparc64/lib/VIScopy.S	Wed Feb 11 22:14:30 2004
+++ b/arch/sparc64/lib/VIScopy.S	Wed Feb 11 22:14:30 2004
@@ -120,7 +120,6 @@
 #define EXVIS2(x,y) EXVISN(x,y,2)
 #define EXVIS3(x,y) EXVISN(x,y,3)
 #define EXVIS4(x,y) EXVISN(x,y,4)
-#define EXVIS5(x,y) EXVISN(x,y,5)
 
 #define FREG_FROB(f1, f2, f3, f4, f5, f6, f7, f8, f9)		\
 	faligndata		%f1, %f2, %f48;			\
@@ -135,7 +134,7 @@
 #define MAIN_LOOP_CHUNK(src, dest, fdest, fsrc, len, jmptgt)	\
 	EXVIS(LDBLK		[%src] ASIBLK, %fdest);		\
 	ASI_SETDST_BLK						\
-	EXVIS2(STBLK		%fsrc, [%dest] ASIBLK);		\
+	EXVIS(STBLK		%fsrc, [%dest] ASIBLK);		\
 	add			%src, 0x40, %src;		\
 	subcc			%len, 0x40, %len;		\
 	be,pn			%xcc, jmptgt;			\
@@ -156,14 +155,14 @@
 #ifdef __KERNEL__
 #define STORE_JUMP(dest, fsrc, target)				\
 	srl			asi_dest, 3, %g5;		\
-	EXVIS3(STBLK		%fsrc, [%dest] ASIBLK);		\
+	EXVIS2(STBLK		%fsrc, [%dest] ASIBLK);		\
 	xor		       asi_dest, ASI_BLK_XOR1, asi_dest;\
 	add			%dest, 0x40, %dest;		\
 	xor			asi_dest, %g5, asi_dest;	\
 	ba,pt			%xcc, target;
 #else
 #define STORE_JUMP(dest, fsrc, target)				\
-	EXVIS3(STBLK		%fsrc, [%dest] ASIBLK);		\
+	EXVIS2(STBLK		%fsrc, [%dest] ASIBLK);		\
 	add			%dest, 0x40, %dest;		\
 	ba,pt			%xcc, target;
 #endif
@@ -182,7 +181,7 @@
 	subcc			%left, 8, %left;		\
 	bl,pn			%xcc, vis_out;			\
 	 faligndata		%f0, %f1, %f48;			\
-	EXVIS4(STDF		%f48, [%dest] ASINORMAL);	\
+	EXVIS3(STDF		%f48, [%dest] ASINORMAL);	\
 	add			%dest, 8, %dest;
 
 #define UNEVEN_VISCHUNK_LAST(dest, f0, f1, left)		\
@@ -675,21 +674,21 @@
 	xor		asi_src, %g5, asi_src			! IEU0	Group
 #endif
 vis_slk:ASI_SETSRC_NOBLK					! LSU	Group
-	EXVIS4(LDDF	[%o1] ASINORMAL, %f2)			! Load	Group
+	EXVIS3(LDDF	[%o1] ASINORMAL, %f2)			! Load	Group
 	add		%o1, 8, %o1				! IEU0
 	subcc		%g3, 8, %g3				! IEU1
 	ASI_SETDST_NOBLK					! LSU	Group
 	faligndata	%f0, %f2, %f8				! GRU	Group
-	EXVIS5(STDF	%f8, [%o0] ASINORMAL)			! Store
+	EXVIS4(STDF	%f8, [%o0] ASINORMAL)			! Store
 	bl,pn		%xcc, vis_out_slp			! CTI
 	 add		%o0, 8, %o0				! IEU0	Group
 	ASI_SETSRC_NOBLK					! LSU	Group
-	EXVIS4(LDDF	[%o1] ASINORMAL, %f0)			! Load	Group
+	EXVIS3(LDDF	[%o1] ASINORMAL, %f0)			! Load	Group
 	add		%o1, 8, %o1				! IEU0
 	subcc		%g3, 8, %g3				! IEU1
 	ASI_SETDST_NOBLK					! LSU	Group
 	faligndata	%f2, %f0, %f8				! GRU	Group
-	EXVIS5(STDF	%f8, [%o0] ASINORMAL)			! Store
+	EXVIS4(STDF	%f8, [%o0] ASINORMAL)			! Store
 	bge,pt		%xcc, vis_slk				! CTI
 	 add		%o0, 8, %o0				! IEU0	Group
 vis_out_slp:
@@ -1138,19 +1137,17 @@
 		sub		%g7, %g2, %g7
 		ba,pt		%xcc, VIScopyfixup_ret
 		 add		%g7, %o2, %o1
-VIScopyfixup_vis3:
-		sub		%o2, 0x80, %o2
 VIScopyfixup_vis2:
-		add		%o2, 0x40, %o2
+		sub		%o2, 0x40, %o2
 VIScopyfixup_vis0:
 		add		%o2, 0x80, %o2
 VIScopyfixup_vis1:
 		add		%g7, %g3, %g7
 		ba,pt		%xcc, VIScopyfixup_ret
 		 add		%o2, %g7, %o1
-VIScopyfixup_vis5:
-		add		%g3, 8, %g3
 VIScopyfixup_vis4:
+		add		%g3, 8, %g3
+VIScopyfixup_vis3:
 		add		%g3, 8, %g3
 		ba,pt		%xcc, VIScopyfixup_ret
 		 add		%o2, %g3, %o1
diff -Nru a/arch/x86_64/kernel/sys_x86_64.c b/arch/x86_64/kernel/sys_x86_64.c
--- a/arch/x86_64/kernel/sys_x86_64.c	Wed Feb 11 22:14:31 2004
+++ b/arch/x86_64/kernel/sys_x86_64.c	Wed Feb 11 22:14:31 2004
@@ -110,8 +110,8 @@
 		if (end - len >= addr &&
 		    (!vma || addr + len <= vma->vm_start))
 			return addr;
-	} else
-		addr = mm->free_area_cache;
+	}
+	addr = mm->free_area_cache;
 	if (addr < begin) 
 		addr = begin; 
 	start_addr = addr;
diff -Nru a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
--- a/drivers/cdrom/cdrom.c	Wed Feb 11 22:14:30 2004
+++ b/drivers/cdrom/cdrom.c	Wed Feb 11 22:14:30 2004
@@ -2766,13 +2766,13 @@
 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
 	    pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD_RAM) != 0);
 
-	pos += sprintf(info+pos, "\nCan read MRW:");
+	pos += sprintf(info+pos, "\nCan read MRW:\t");
 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-	    pos += sprintf(info+pos, "\t\t%d", CDROM_CAN(CDC_MRW) != 0);
+	    pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MRW) != 0);
 
-	pos += sprintf(info+pos, "\nCan write MRW:");
+	pos += sprintf(info+pos, "\nCan write MRW:\t");
 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
-	    pos += sprintf(info+pos, "\t\t%d", CDROM_CAN(CDC_MRW_W) != 0);
+	    pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MRW_W) != 0);
 
 	strcpy(info+pos,"\n\n");
 		
diff -Nru a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
--- a/drivers/char/watchdog/Kconfig	Wed Feb 11 22:14:31 2004
+++ b/drivers/char/watchdog/Kconfig	Wed Feb 11 22:14:31 2004
@@ -38,6 +38,15 @@
 	  get killed. If you say Y here, the watchdog cannot be stopped once
 	  it has been started.
 
+#
+# General Watchdog drivers
+#
+
+comment "Watchdog Device Drivers"
+	depends on WATCHDOG
+
+# Architecture Independant
+
 config SOFT_WATCHDOG
 	tristate "Software watchdog"
 	depends on WATCHDOG
@@ -49,88 +58,53 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called softdog.
 
-config WDT
-	tristate "WDT Watchdog timer"
-	depends on WATCHDOG
-	---help---
-	  If you have a WDT500P or WDT501P watchdog board, say Y here,
-	  otherwise N. It is not possible to probe for this board, which means
-	  that you have to inform the kernel about the IO port and IRQ using
-	  the "wdt=" kernel option (try "man bootparam" or see the
-	  documentation of your boot loader (lilo or loadlin) about how to
-	  pass options to the kernel at boot time).
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called wdt.
-
-config WDT_501
-	bool "WDT501 features"
-	depends on WDT
-	help
-	  Saying Y here and creating a character special file /dev/temperature
-	  with major number 10 and minor number 131 ("man mknod") will give
-	  you a thermometer inside your computer: reading from
-	  /dev/temperature yields one byte, the temperature in degrees
-	  Fahrenheit. This works only if you have a WDT501P watchdog board
-	  installed.
+# ARM Architecture
 
-config WDT_501_FAN
-	bool "Fan Tachometer"
-	depends on WDT_501
+config 21285_WATCHDOG
+	tristate "DC21285 watchdog"
+	depends on WATCHDOG && FOOTBRIDGE
 	help
-	  Enable the Fan Tachometer on the WDT501. Only do this if you have a
-	  fan tachometer actually set up.
+	  The Intel Footbridge chip contains a builtin watchdog circuit. Say Y
+	  here if you wish to use this. Alternatively say M to compile the
+	  driver as a module, which will be called wdt285.
 
-config WDTPCI
-	tristate "WDT PCI Watchdog timer"
-	depends on WATCHDOG
-	---help---
-	  If you have a PCI WDT500/501 watchdog board, say Y here, otherwise
-	  N.  It is not possible to probe for this board, which means that you
-	  have to inform the kernel about the IO port and IRQ using the "wdt="
-	  kernel option (try "man bootparam" or see the documentation of your
-	  boot loader (lilo or loadlin) about how to pass options to the
-	  kernel at boot time).
+	  This driver does not work on all machines. In particular, early CATS
+	  boards have hardware problems that will cause the machine to simply
+	  lock up if the watchdog fires.
 
-	  To compile this driver as a module, choose M here: the
-	  module will be called wdt_pci.
+	  "If in doubt, leave it out" - say N.
 
-config WDT_501_PCI
-	bool "WDT501-PCI features"
-	depends on WDTPCI
+config 977_WATCHDOG
+	tristate "NetWinder WB83C977 watchdog"
+	depends on WATCHDOG && FOOTBRIDGE && ARCH_NETWINDER
 	help
-	  Saying Y here and creating a character special file /dev/temperature
-	  with major number 10 and minor number 131 ("man mknod") will give
-	  you a thermometer inside your computer: reading from
-	  /dev/temperature yields one byte, the temperature in degrees
-	  Fahrenheit. This works only if you have a WDT501P watchdog board
-	  installed.
+	  Say Y here to include support for the WB977 watchdog included in
+	  NetWinder machines. Alternatively say M to compile the driver as
+	  a module, which will be called wdt977.
 
-config PCWATCHDOG
-	tristate "Berkshire Products PC Watchdog"
-	depends on WATCHDOG
-	---help---
-	  This is the driver for the Berkshire Products PC Watchdog card.
-	  This card simply watches your kernel to make sure it doesn't freeze,
-	  and if it does, it reboots your computer after a certain amount of
-	  time. This driver is like the WDT501 driver but for different
-	  hardware. Please read <file:Documentation/watchdog/pcwd-watchdog.txt>. The PC
-	  watchdog cards can be ordered from <http://www.berkprod.com/>.
+	  Not sure? It's safe to say N.
+
+config SA1100_WATCHDOG
+	tristate "SA1100 watchdog"
+	depends on WATCHDOG && ARCH_SA1100
+	help
+	  Watchdog timer embedded into SA11x0 chips. This will reboot your
+	  system when timeout is reached.
+	  NOTE, that once enabled, this timer cannot be disabled.
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called pcwd.
+	  module will be called sa1100_wdt.
 
-	  Most people will say N.
+# X86 (i386 + ia64 + x86_64) Architecture
 
 config ACQUIRE_WDT
 	tristate "Acquire SBC Watchdog Timer"
-	depends on WATCHDOG
+	depends on WATCHDOG && X86
 	---help---
-	  This is the driver for the hardware watchdog on the PSC-6x86 Single
-	  Board Computer produced by Acquire Inc (and others).  This watchdog
+	  This is the driver for the hardware watchdog on Single Board
+	  Computers produced by Acquire Inc (and others). This watchdog
 	  simply watches your kernel to make sure it doesn't freeze, and if
 	  it does, it reboots your computer after a certain amount of time.
-	  This driver is like the WDT501 driver but for different hardware.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called acquirewdt.
@@ -139,50 +113,65 @@
 
 config ADVANTECH_WDT
 	tristate "Advantech SBC Watchdog Timer"
-	depends on WATCHDOG
+	depends on WATCHDOG && X86
 	help
 	  If you are configuring a Linux kernel for the Advantech single-board
 	  computer, say `Y' here to support its built-in watchdog timer
-	  feature.  See the help for CONFIG_WATCHDOG for discussion.
+	  feature. More information can be found at
+	  <http://www.advantech.com.tw/products/>
 
-config 21285_WATCHDOG
-	tristate "DC21285 watchdog"
-	depends on WATCHDOG && FOOTBRIDGE
+config ALIM1535_WDT
+	tristate "ALi M1535 PMU Watchdog Timer"
+	depends on WATCHDOG && X86 && PCI
+	---help---
+	  This is the driver for the hardware watchdog on the ALi M1535 PMU.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called alim1535_wdt.
+
+	  Most people will say N.
+
+config ALIM7101_WDT
+	tristate "ALi M7101 PMU Computer Watchdog"
+	depends on WATCHDOG && X86 && PCI
 	help
-	  The Intel Footbridge chip contains a builtin watchdog circuit. Say Y
-	  here if you wish to use this. Alternatively say M to compile the
-	  driver as a module, which will be called wdt285.
+	  This is the driver for the hardware watchdog on the ALi M7101 PMU
+	  as used in the x86 Cobalt servers.
 
-	  This driver does not work on all machines. In particular, early CATS
-	  boards have hardware problems that will cause the machine to simply
-	  lock up if the watchdog fires.
+	  To compile this driver as a module, choose M here: the
+	  module will be called alim7101_wdt.
 
-	  "If in doubt, leave it out" - say N.
+	  Most people will say N.
 
-config 977_WATCHDOG
-	tristate "NetWinder WB83C977 watchdog"
-	depends on WATCHDOG && FOOTBRIDGE && ARCH_NETWINDER
+config AMD7XX_TCO
+	tristate "AMD 766/768 TCO Timer/Watchdog"
+	depends on WATCHDOG && X86 && PCI
 	help
-	  Say Y here to include support for the WB977 watchdog included in
-	  NetWinder machines. Alternatively say M to compile the driver as
-	  a module, which will be called wdt977.
+	  This is the driver for the hardware watchdog built in to the
+	  AMD 766/768 chipsets.
+	  This watchdog simply watches your kernel to make sure it doesn't
+	  freeze, and if it does, it reboots your computer after a certain
+	  amount of time.
 
-	  Not sure? It's safe to say N.
+	  You can compile this driver directly into the kernel, or use
+	  it as a module.  The module will be called amd7xx_tco.
 
-config SA1100_WATCHDOG
-	tristate "SA1100 watchdog"
-	depends on WATCHDOG && ARCH_SA1100
+config SC520_WDT
+	tristate "AMD Elan SC520 processor Watchdog"
+	depends on WATCHDOG && X86
 	help
-	  Watchdog timer embedded into SA11x0 chips. This will reboot your
-	  system when timeout is reached.
-	  NOTE, that once enabled, this timer cannot be disabled.
+	  This is the driver for the hardware watchdog built in to the
+	  AMD "Elan" SC520 microcomputer commonly used in embedded systems.
+	  This watchdog simply watches your kernel to make sure it doesn't
+	  freeze, and if it does, it reboots your computer after a certain
+	  amount of time.
 
-	  To compile this driver as a module, choose M here: the
-	  module will be called sa1100_wdt.
+	  You can compile this driver directly into the kernel, or use
+	  it as a module.  The module will be called sc520_wdt.
 
 config EUROTECH_WDT
 	tristate "Eurotech CPU-1220/1410 Watchdog Timer"
-	depends on WATCHDOG
+	depends on WATCHDOG && X86
 	help
 	  Enable support for the watchdog timer on the Eurotech CPU-1220 and
 	  CPU-1410 cards.  These are PC/104 SBCs. Spec sheets and product
@@ -190,7 +179,7 @@
 
 config IB700_WDT
 	tristate "IB700 SBC Watchdog Timer"
-	depends on WATCHDOG
+	depends on WATCHDOG && X86
 	---help---
 	  This is the driver for the hardware watchdog on the IB700 Single
 	  Board Computer produced by TMC Technology (www.tmc-uk.com). This watchdog
@@ -204,52 +193,60 @@
 
 	  Most people will say N.
 
-config I810_TCO
-	tristate "Intel i8xx TCO timer / Watchdog"
-	depends on WATCHDOG
-	---help---
-	  Hardware driver for the TCO timer built into the Intel i8xx
-	  chipset family.  The TCO (Total Cost of Ownership) timer is a
-	  watchdog timer that will reboot the machine after its second
-	  expiration. The expiration time can be configured by commandline
-	  argument "i810_margin=<n>" where <n> is the counter initial value.
-	  It is decremented every 0.6 secs, the default is 50 which gives a
-	  timeout of 30 seconds and one minute until reset.
+config WAFER_WDT
+	tristate "ICP Wafer 5823 Single Board Computer Watchdog"
+	depends on WATCHDOG && X86
+	help
+	  This is a driver for the hardware watchdog on the ICP Wafer 5823
+	  Single Board Computer (and probably other similar models).
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called wafer5823wdt.
+
+config I8XX_TCO
+	tristate "Intel i8xx TCO Timer/Watchdog"
+	depends on WATCHDOG && (X86 || IA64) && PCI
+	---help---
+	  Hardware driver for the TCO timer built into the Intel 82801
+	  I/O Controller Hub family.  The TCO (Total Cost of Ownership)
+	  timer is a watchdog timer that will reboot the machine after
+	  its second expiration. The expiration time can be configured
+	  with the "heartbeat" parameter.
 
 	  On some motherboards the driver may fail to reset the chipset's
 	  NO_REBOOT flag which prevents the watchdog from rebooting the
 	  machine. If this is the case you will get a kernel message like
-	  "i810tco init: failed to reset NO_REBOOT flag".
+	  "failed to reset NO_REBOOT flag, reboot disabled by hardware".
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called i810-tco.
+	  module will be called i8xx_tco.
 
-config MIXCOMWD
-	tristate "Mixcom Watchdog"
-	depends on WATCHDOG
-	---help---
-	  This is a driver for the Mixcom hardware watchdog cards.  This
-	  watchdog simply watches your kernel to make sure it doesn't freeze,
-	  and if it does, it reboots your computer after a certain amount of
-	  time.
+config SC1200_WDT
+	tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog"
+	depends on WATCHDOG && X86
+	help
+	  This is a driver for National Semiconductor PC87307/PC97307 hardware
+	  watchdog cards as found on the SC1200. This watchdog is mainly used
+	  for power management purposes and can be used to power down the device
+	  during inactivity periods (includes interrupt activity monitoring).
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called mixcomwd.
+	  module will be called sc1200wdt.
 
 	  Most people will say N.
 
 config SCx200_WDT
-	tristate "NatSemi SCx200 Watchdog"
-	depends on WATCHDOG
+	tristate "National Semiconductor SCx200 Watchdog"
+	depends on WATCHDOG && X86 && PCI
 	help
-	  Enable the built-in watchdog timer support on the National 
+	  Enable the built-in watchdog timer support on the National
 	  Semiconductor SCx200 processors.
 
 	  If compiled as a module, it will be called scx200_watchdog.
 
 config 60XX_WDT
 	tristate "SBC-60XX Watchdog Timer"
-	depends on WATCHDOG
+	depends on WATCHDOG && X86
 	help
 	  This driver can be used with the watchdog timer found on some
 	  single board computers, namely the 6010 PII based computer.
@@ -261,24 +258,17 @@
 	  You can compile this driver directly into the kernel, or use
 	  it as a module.  The module will be called sbc60xxwdt.
 
-config W83877F_WDT
-	tristate "W83877F (EMACS) Watchdog Timer"
-	depends on WATCHDOG
+config CPU5_WDT
+	tristate "SMA CPU5 Watchdog"
+	depends on WATCHDOG && X86
 	---help---
-	  This is the driver for the hardware watchdog on the W83877F chipset
-	  as used in EMACS PC-104 motherboards (and likely others).  This
-	  watchdog simply watches your kernel to make sure it doesn't freeze,
-	  and if it does, it reboots your computer after a certain amount of
-	  time.
-
+	  TBD.
 	  To compile this driver as a module, choose M here: the
-	  module will be called w83877f_wdt.
-
-	  Most people will say N.
+	  module will be called cpu5wdt.
 
 config W83627HF_WDT
 	tristate "W83627HF Watchdog Timer"
-	depends on WATCHDOG
+	depends on WATCHDOG && X86
 	---help---
 	  This is the driver for the hardware watchdog on the W83627HF chipset
 	  as used in Advantech PC-9578 and Tyan S2721-533 motherboards
@@ -291,9 +281,24 @@
 
 	  Most people will say N.
 
+config W83877F_WDT
+	tristate "W83877F (EMACS) Watchdog Timer"
+	depends on WATCHDOG && X86
+	---help---
+	  This is the driver for the hardware watchdog on the W83877F chipset
+	  as used in EMACS PC-104 motherboards (and likely others).  This
+	  watchdog simply watches your kernel to make sure it doesn't freeze,
+	  and if it does, it reboots your computer after a certain amount of
+	  time.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called w83877f_wdt.
+
+	  Most people will say N.
+
 config MACHZ_WDT
 	tristate "ZF MachZ Watchdog"
-	depends on WATCHDOG
+	depends on WATCHDOG && X86
 	---help---
 	  If you are using a ZF Micro MachZ processor, say Y here, otherwise
 	  N.  This is the driver for the watchdog timer builtin on that
@@ -304,85 +309,150 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called machzwd.
 
-config SC520_WDT
-	tristate "AMD Elan SC520 processor Watchdog"
-	depends on WATCHDOG
-	help
-	  This is the driver for the hardware watchdog built in to the
-	  AMD "Elan" SC520 microcomputer commonly used in embedded systems.
-	  This watchdog simply watches your kernel to make sure it doesn't
-	  freeze, and if it does, it reboots your computer after a certain
-	  amount of time.
-	
-	  You can compile this driver directly into the kernel, or use
-	  it as a module.  The module will be called sc520_wdt.
+# MIPS Architecture
 
-config AMD7XX_TCO
-	tristate "AMD 766/768 TCO Timer/Watchdog"
-	depends on WATCHDOG
+config INDYDOG
+	tristate "Indy/I2 Hardware Watchdog"
+	depends on WATCHDOG && SGI_IP22
 	help
-	  This is the driver for the hardware watchdog built in to the
-	  AMD 766/768 chipsets.
-	  This watchdog simply watches your kernel to make sure it doesn't
-	  freeze, and if it does, it reboots your computer after a certain
-	  amount of time.
-	
-	  You can compile this driver directly into the kernel, or use
-	  it as a module.  The module will be called amd7xx_tco.
+	  Hardwaredriver for the Indy's/I2's watchdog. This is a
+	  watchdog timer that will reboot the machine after a 60 second
+	  timer expired and no process has written to /dev/watchdog during
+	  that time.
 
-config ALIM7101_WDT
-	tristate "ALi M7101 PMU Computer Watchdog"
-	depends on WATCHDOG
+# SUPERH Architecture
+
+config SH_WDT
+	tristate "SuperH Watchdog"
+	depends on WATCHDOG && SUPERH
 	help
-	  This is the driver for the hardware watchdog on the ALi M7101 PMU
-	  as used in the x86 Cobalt servers.
+	  This driver adds watchdog support for the integrated watchdog in the
+	  SuperH processors. If you have one of these processors and wish
+	  to have watchdog support enabled, say Y, otherwise say N.
+
+	  As a side note, saying Y here will automatically boost HZ to 1000
+	  so that the timer has a chance to clear the overflow counter. On
+	  slower systems (such as the SH-2 and SH-3) this will likely yield
+	  some performance issues. As such, the WDT should be avoided here
+	  unless it is absolutely necessary.
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called alim7101_wdt.
+	  module will be called shwdt.
 
-	  Most people will say N.
+#
+# ISA-based Watchdog Cards
+#
 
-config ALIM1535_WDT
-	tristate "ALi M1535 PMU Watchdog Timer"
-	depends on WATCHDOG
+comment "ISA-based Watchdog Cards"
+	depends on WATCHDOG && ISA
+
+config PCWATCHDOG
+	tristate "Berkshire Products ISA-PC Watchdog"
+	depends on WATCHDOG && ISA
 	---help---
-	  This is the driver for the hardware watchdog on the ALi M1535 PMU.
+	  This is the driver for the Berkshire Products PC Watchdog card.
+	  This card simply watches your kernel to make sure it doesn't freeze,
+	  and if it does, it reboots your computer after a certain amount of
+	  time. This driver is like the WDT501 driver but for different
+	  hardware. Please read <file:Documentation/watchdog/pcwd-watchdog.txt>. The PC
+	  watchdog cards can be ordered from <http://www.berkprod.com/>.
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called alim1535_wdt.
+	  module will be called pcwd.
 
 	  Most people will say N.
 
-config SC1200_WDT
-	tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog"
-	depends on WATCHDOG
-	help
-	  This is a driver for National Semiconductor PC87307/PC97307 hardware
-	  watchdog cards as found on the SC1200. This watchdog is mainly used
-	  for power management purposes and can be used to power down the device
-	  during inactivity periods (includes interrupt activity monitoring).
+config MIXCOMWD
+	tristate "Mixcom Watchdog"
+	depends on WATCHDOG && ISA
+	---help---
+	  This is a driver for the Mixcom hardware watchdog cards.  This
+	  watchdog simply watches your kernel to make sure it doesn't freeze,
+	  and if it does, it reboots your computer after a certain amount of
+	  time.
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called sc1200wdt.
+	  module will be called mixcomwd.
 
 	  Most people will say N.
 
-config WAFER_WDT
-	tristate "ICP Wafer 5823 Single Board Computer Watchdog"
-	depends on WATCHDOG
+config WDT
+	tristate "WDT Watchdog timer"
+	depends on WATCHDOG && ISA
+	---help---
+	  If you have a WDT500P or WDT501P watchdog board, say Y here,
+	  otherwise N. It is not possible to probe for this board, which means
+	  that you have to inform the kernel about the IO port and IRQ using
+	  the "wdt=" kernel option (try "man bootparam" or see the
+	  documentation of your boot loader (lilo or loadlin) about how to
+	  pass options to the kernel at boot time).
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called wdt.
+
+config WDT_501
+	bool "WDT501 features"
+	depends on WDT
 	help
-	  This is a driver for the hardware watchdog on the ICP Wafer 5823
-	  Single Board Computer (and probably other similar models).
+	  Saying Y here and creating a character special file /dev/temperature
+	  with major number 10 and minor number 131 ("man mknod") will give
+	  you a thermometer inside your computer: reading from
+	  /dev/temperature yields one byte, the temperature in degrees
+	  Fahrenheit. This works only if you have a WDT501P watchdog board
+	  installed.
+
+config WDT_501_FAN
+	bool "Fan Tachometer"
+	depends on WDT_501
+	help
+	  Enable the Fan Tachometer on the WDT501. Only do this if you have a
+	  fan tachometer actually set up.
+
+#
+# PCI-based Watchdog Cards
+#
+
+comment "PCI-based Watchdog Cards"
+	depends on WATCHDOG && PCI
+
+config PCIPCWATCHDOG
+	tristate "Berkshire Products PCI-PC Watchdog"
+	depends on WATCHDOG && PCI
+	---help---
+	  This is the driver for the Berkshire Products PCI-PC Watchdog card.
+	  This card simply watches your kernel to make sure it doesn't freeze,
+	  and if it does, it reboots your computer after a certain amount of
+	  time. The card can also monitor the internal temperature of the PC.
+	  More info is available at <http://www.berkprod.com/pci_pc_watchdog.htm>.
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called wafer5823wdt.
+	  module will be called pcwd_pci.
 
-config CPU5_WDT
-	tristate "SMA CPU5 Watchdog"
-	depends on WATCHDOG
+	  Most people will say N.
+
+config WDTPCI
+	tristate "WDT PCI Watchdog timer"
+	depends on WATCHDOG && PCI
 	---help---
-	  TBD.
+	  If you have a PCI WDT500/501 watchdog board, say Y here, otherwise
+	  N.  It is not possible to probe for this board, which means that you
+	  have to inform the kernel about the IO port and IRQ using the "wdt="
+	  kernel option (try "man bootparam" or see the documentation of your
+	  boot loader (lilo or loadlin) about how to pass options to the
+	  kernel at boot time).
+
 	  To compile this driver as a module, choose M here: the
-	  module will be called cpu5wdt.
+	  module will be called wdt_pci.
+
+config WDT_501_PCI
+	bool "WDT501-PCI features"
+	depends on WDTPCI
+	help
+	  Saying Y here and creating a character special file /dev/temperature
+	  with major number 10 and minor number 131 ("man mknod") will give
+	  you a thermometer inside your computer: reading from
+	  /dev/temperature yields one byte, the temperature in degrees
+	  Fahrenheit. This works only if you have a WDT501P watchdog board
+	  installed.
 
 endmenu
diff -Nru a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile
--- a/drivers/char/watchdog/Makefile	Wed Feb 11 22:14:31 2004
+++ b/drivers/char/watchdog/Makefile	Wed Feb 11 22:14:31 2004
@@ -18,7 +18,7 @@
 obj-$(CONFIG_WDTPCI) += wdt_pci.o
 obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
 obj-$(CONFIG_977_WATCHDOG) += wdt977.o
-obj-$(CONFIG_I810_TCO) += i810-tco.o
+obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o
 obj-$(CONFIG_MACHZ_WDT) += machzwd.o
 obj-$(CONFIG_SH_WDT) += shwdt.o
 obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
@@ -33,3 +33,5 @@
 obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
 obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o
 obj-$(CONFIG_AMD7XX_TCO) += amd7xx_tco.o
+obj-$(CONFIG_INDYDOG) += indydog.o
+obj-$(CONFIG_PCIPCWATCHDOG) += pcwd_pci.o
diff -Nru a/drivers/char/watchdog/acquirewdt.c b/drivers/char/watchdog/acquirewdt.c
--- a/drivers/char/watchdog/acquirewdt.c	Wed Feb 11 22:14:31 2004
+++ b/drivers/char/watchdog/acquirewdt.c	Wed Feb 11 22:14:31 2004
@@ -22,6 +22,32 @@
  *          Can't add timeout - driver doesn't allow changing value
  */
 
+/*
+ *	Theory of Operation:
+ *		The Watch-Dog Timer is provided to ensure that standalone
+ *		Systems can always recover from catastrophic conditions that
+ *		caused the CPU to crash. This condition may have occured by
+ *		external EMI or a software bug. When the CPU stops working
+ *		correctly, hardware on the board will either perform a hardware
+ *		reset (cold boot) or a non-maskable interrupt (NMI) to bring the
+ *		system back to a known state.
+ *
+ *		The Watch-Dog Timer is controlled by two I/O Ports.
+ *		  443 hex	- Read	- Enable or refresh the Watch-Dog Timer
+ *		  043 hex	- Read	- Disable the Watch-Dog Timer
+ *
+ *		To enable the Watch-Dog Timer, a read from I/O port 443h must
+ *		be performed. This will enable and activate the countdown timer
+ *		which will eventually time out and either reset the CPU or cause
+ *		an NMI depending on the setting of a jumper. To ensure that this
+ *		reset condition does not occur, the Watch-Dog Timer must be
+ *		periodically refreshed by reading the same I/O port 443h.
+ *		The Watch-Dog Timer is disabled by reading I/O port 043h.
+ *
+ *		The Watch-Dog Timer Time-Out Period is set via jumpers.
+ *		It can be 1, 2, 10, 20, 110 or 220 seconds.
+ */
+
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -39,7 +65,7 @@
 
 #define WATCHDOG_NAME "Acquire WDT"
 #define PFX WATCHDOG_NAME ": "
-#define WATCHDOG_TIMEOUT 0	/* ??? Is the timeout hardcoded to 1 minute ??? */
+#define WATCHDOG_HEARTBEAT 0	/* There is no way to see what the correct time-out period is */
 
 static unsigned long acq_is_open;
 static char expect_close;
@@ -69,7 +95,7 @@
  *	Kernel methods.
  */
 
-static void acq_ping(void)
+static void acq_keepalive(void)
 {
 	/* Write a watchdog value */
 	inb_p(wdt_start);
@@ -111,7 +137,7 @@
 		}
 
 		/* Well, anyhow someone wrote to us, we should return that favour */
-		acq_ping();
+		acq_keepalive();
 	}
 	return count;
 }
@@ -119,6 +145,7 @@
 static int acq_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 	unsigned long arg)
 {
+	int options, retval = -EINVAL;
 	static struct watchdog_info ident =
 	{
 		.options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
@@ -136,16 +163,14 @@
 	  return put_user(0, (int *)arg);
 
 	case WDIOC_KEEPALIVE:
-	  acq_ping();
+	  acq_keepalive();
 	  return 0;
 
 	case WDIOC_GETTIMEOUT:
-	  return put_user(WATCHDOG_TIMEOUT, (int *)arg);
+	  return put_user(WATCHDOG_HEARTBEAT, (int *)arg);
 
 	case WDIOC_SETOPTIONS:
 	{
-	    int options, retval = -EINVAL;
-
 	    if (get_user(options, (int *)arg))
 	      return -EFAULT;
 
@@ -157,7 +182,7 @@
 
 	    if (options & WDIOS_ENABLECARD)
 	    {
-	      acq_ping();
+	      acq_keepalive();
 	      retval = 0;
 	    }
 
@@ -178,7 +203,7 @@
 		__module_get(THIS_MODULE);
 
 	/* Activate */
-	acq_ping();
+	acq_keepalive();
 	return 0;
 }
 
@@ -188,7 +213,7 @@
 		acq_stop();
 	} else {
 		printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
-		acq_ping();
+		acq_keepalive();
 	}
 	clear_bit(0, &acq_is_open);
 	expect_close = 0;
@@ -237,8 +262,6 @@
 static struct notifier_block acq_notifier =
 {
 	.notifier_call = acq_notify_sys,
-	.next = NULL,
-	.priority = 0,
 };
 
 static int __init acq_init(void)
@@ -280,8 +303,8 @@
 	printk (KERN_INFO PFX "initialized. (nowayout=%d)\n",
 		nowayout);
 
-out:
-	return ret;
+	return 0;
+
 unreg_reboot:
 	unregister_reboot_notifier(&acq_notifier);
 unreg_regions:
@@ -289,7 +312,8 @@
 unreg_stop:
 	if (wdt_stop != wdt_start)
 		release_region(wdt_stop, 1);
-	goto out;
+out:
+	return ret;
 }
 
 static void __exit acq_exit(void)
@@ -304,6 +328,7 @@
 module_init(acq_init);
 module_exit(acq_exit);
 
+MODULE_AUTHOR("David Woodhouse");
+MODULE_DESCRIPTION("Acquire Inc. Single Board Computer Watchdog Timer driver");
 MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Unkown");
-MODULE_DESCRIPTION("Acquire Single Board Computer Watchdog Timer driver");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff -Nru a/drivers/char/watchdog/advantechwdt.c b/drivers/char/watchdog/advantechwdt.c
--- a/drivers/char/watchdog/advantechwdt.c	Wed Feb 11 22:14:31 2004
+++ b/drivers/char/watchdog/advantechwdt.c	Wed Feb 11 22:14:31 2004
@@ -334,4 +334,4 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Marek Michalkiewicz <marekm@linux.org.pl>");
 MODULE_DESCRIPTION("Advantech Single Board Computer WDT driver");
-
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff -Nru a/drivers/char/watchdog/alim1535_wdt.c b/drivers/char/watchdog/alim1535_wdt.c
--- a/drivers/char/watchdog/alim1535_wdt.c	Wed Feb 11 22:14:30 2004
+++ b/drivers/char/watchdog/alim1535_wdt.c	Wed Feb 11 22:14:30 2004
@@ -463,3 +463,4 @@
 MODULE_AUTHOR("Alan Cox");
 MODULE_DESCRIPTION("ALi M1535 PMU Watchdog Timer driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff -Nru a/drivers/char/watchdog/alim7101_wdt.c b/drivers/char/watchdog/alim7101_wdt.c
--- a/drivers/char/watchdog/alim7101_wdt.c	Wed Feb 11 22:14:31 2004
+++ b/drivers/char/watchdog/alim7101_wdt.c	Wed Feb 11 22:14:31 2004
@@ -383,3 +383,4 @@
 MODULE_AUTHOR("Steve Hill");
 MODULE_DESCRIPTION("ALi M7101 PMU Computer Watchdog Timer driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff -Nru a/drivers/char/watchdog/amd7xx_tco.c b/drivers/char/watchdog/amd7xx_tco.c
--- a/drivers/char/watchdog/amd7xx_tco.c	Wed Feb 11 22:14:30 2004
+++ b/drivers/char/watchdog/amd7xx_tco.c	Wed Feb 11 22:14:30 2004
@@ -390,4 +390,4 @@
 MODULE_AUTHOR("Zwane Mwaikambo <zwane@holomorphy.com>");
 MODULE_DESCRIPTION("AMD 766/768 TCO Timer Driver");
 MODULE_LICENSE("GPL");
-
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff -Nru a/drivers/char/watchdog/i810-tco.c b/drivers/char/watchdog/i810-tco.c
--- a/drivers/char/watchdog/i810-tco.c	Wed Feb 11 22:14:30 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,437 +0,0 @@
-/*
- *	i810-tco 0.05:	TCO timer driver for i8xx chipsets
- *
- *	(c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved.
- *				http://www.kernelconcepts.de
- *
- *	This program is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU General Public License
- *	as published by the Free Software Foundation; either version
- *	2 of the License, or (at your option) any later version.
- *
- *	Neither kernel concepts nor Nils Faerber admit liability nor provide
- *	warranty for any of this software. This material is provided
- *	"AS-IS" and at no charge.
- *
- *	(c) Copyright 2000	kernel concepts <nils@kernelconcepts.de>
- *				developed for
- *                              Jentro AG, Haar/Munich (Germany)
- *
- *	TCO timer driver for i8xx chipsets
- *	based on softdog.c by Alan Cox <alan@redhat.com>
- *
- *	The TCO timer is implemented in the following I/O controller hubs:
- *	(See the intel documentation on http://developer.intel.com.)
- *	82801AA & 82801AB  chip : document number 290655-003, 290677-004,
- *	82801BA & 82801BAM chip : document number 290687-002, 298242-005,
- *	82801CA & 82801CAM chip : document number 290716-001, 290718-001,
- *	82801DB & 82801E   chip : document number 290744-001, 273599-001,
- *	82801EB & 82801ER  chip : document number 252516-001
- *
- *  20000710 Nils Faerber
- *	Initial Version 0.01
- *  20000728 Nils Faerber
- *	0.02 Fix for SMI_EN->TCO_EN bit, some cleanups
- *  20011214 Matt Domsch <Matt_Domsch@dell.com>
- *	0.03 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
- *	     Didn't add timeout option as i810_margin already exists.
- *  20020224 Joel Becker, Wim Van Sebroeck
- *	0.04 Support for 82801CA(M) chipset, timer margin needs to be > 3,
- *	     add support for WDIOC_SETTIMEOUT and WDIOC_GETTIMEOUT.
- *  20020412 Rob Radez <rob@osinvestor.com>, Wim Van Sebroeck
- *	0.05 Fix possible timer_alive race, add expect close support,
- *	     clean up ioctls (WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS and
- *	     WDIOC_SETOPTIONS), made i810tco_getdevice __init,
- *	     removed boot_status, removed tco_timer_read,
- *	     added support for 82801DB and 82801E chipset,
- *	     added support for 82801EB and 8280ER chipset,
- *	     general cleanup.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include "i810-tco.h"
-
-
-/* Module and version information */
-#define TCO_VERSION "0.05"
-#define TCO_MODULE_NAME "i810 TCO timer"
-#define TCO_DRIVER_NAME   TCO_MODULE_NAME ", v" TCO_VERSION
-
-/* Default expire timeout */
-#define TIMER_MARGIN	50	/* steps of 0.6sec, 3<n<64. Default is 30 seconds */
-
-static unsigned int ACPIBASE;
-static spinlock_t tco_lock;	/* Guards the hardware */
-
-static int i810_margin = TIMER_MARGIN;	/* steps of 0.6sec */
-
-MODULE_PARM(i810_margin, "i");
-MODULE_PARM_DESC(i810_margin, "i810-tco timeout in steps of 0.6sec, 3<n<64. Default = 50 (30 seconds)");
-
-#ifdef CONFIG_WATCHDOG_NOWAYOUT
-static int nowayout = 1;
-#else
-static int nowayout = 0;
-#endif
-
-MODULE_PARM(nowayout,"i");
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
-
-
-/*
- *	Timer active flag
- */
-
-static unsigned long timer_alive;
-static char tco_expect_close;
-
-/*
- * Some TCO specific functions
- */
-
-
-/*
- * Start the timer countdown
- */
-static int tco_timer_start (void)
-{
-	unsigned char val;
-
-	spin_lock(&tco_lock);
-	val = inb (TCO1_CNT + 1);
-	val &= 0xf7;
-	outb (val, TCO1_CNT + 1);
-	val = inb (TCO1_CNT + 1);
-	spin_unlock(&tco_lock);
-
-	if (val & 0x08)
-		return -1;
-	return 0;
-}
-
-/*
- * Stop the timer countdown
- */
-static int tco_timer_stop (void)
-{
-	unsigned char val;
-
-	spin_lock(&tco_lock);
-	val = inb (TCO1_CNT + 1);
-	val |= 0x08;
-	outb (val, TCO1_CNT + 1);
-	val = inb (TCO1_CNT + 1);
-	spin_unlock(&tco_lock);
-
-	if ((val & 0x08) == 0)
-		return -1;
-	return 0;
-}
-
-/*
- * Set the timer reload value
- */
-static int tco_timer_settimer (unsigned char tmrval)
-{
-	unsigned char val;
-
-	/* from the specs: */
-	/* "Values of 0h-3h are ignored and should not be attempted" */
-	if (tmrval > 0x3f || tmrval < 0x04)
-		return -1;
-
-	spin_lock(&tco_lock);
-	val = inb (TCO1_TMR);
-	val &= 0xc0;
-	val |= tmrval;
-	outb (val, TCO1_TMR);
-	val = inb (TCO1_TMR);
-	spin_unlock(&tco_lock);
-
-	if ((val & 0x3f) != tmrval)
-		return -1;
-
-	return 0;
-}
-
-/*
- * Reload (trigger) the timer. Lock is needed so we don't reload it during
- * a reprogramming event
- */
-
-static void tco_timer_reload (void)
-{
-	spin_lock(&tco_lock);
-	outb (0x01, TCO1_RLD);
-	spin_unlock(&tco_lock);
-}
-
-/*
- *	Allow only one person to hold it open
- */
-
-static int i810tco_open (struct inode *inode, struct file *file)
-{
-	if (test_and_set_bit(0, &timer_alive))
-		return -EBUSY;
-
-	/*
-	 *      Reload and activate timer
-	 */
-	tco_timer_reload ();
-	tco_timer_start ();
-	return 0;
-}
-
-static int i810tco_release (struct inode *inode, struct file *file)
-{
-	/*
-	 *      Shut off the timer.
-	 */
-	if (tco_expect_close == 42) {
-		tco_timer_stop ();
-	} else {
-		tco_timer_reload ();
-		printk(KERN_CRIT TCO_MODULE_NAME ": Unexpected close, not stopping watchdog!\n");
-	}
-	clear_bit(0, &timer_alive);
-	tco_expect_close = 0;
-	return 0;
-}
-
-static ssize_t i810tco_write (struct file *file, const char *data,
-			      size_t len, loff_t * ppos)
-{
-	/*  Can't seek (pwrite) on this device  */
-	if (ppos != &file->f_pos)
-		return -ESPIPE;
-
-	/* See if we got the magic character 'V' and reload the timer */
-	if (len) {
-		if (!nowayout) {
-			size_t i;
-
-			/* note: just in case someone wrote the magic character
-			 * five months ago... */
-			tco_expect_close = 0;
-
-			/* scan to see whether or not we got the magic character */
-			for (i = 0; i != len; i++) {
-				u8 c;
-				if(get_user(c, data+i))
-					return -EFAULT;
-				if (c == 'V')
-					tco_expect_close = 42;
-			}
-		}
-
-		/* someone wrote to us, we should reload the timer */
-		tco_timer_reload ();
-	}
-	return len;
-}
-
-static int i810tco_ioctl (struct inode *inode, struct file *file,
-			  unsigned int cmd, unsigned long arg)
-{
-	int new_margin, u_margin;
-	int options, retval = -EINVAL;
-
-	static struct watchdog_info ident = {
-		.options =		WDIOF_SETTIMEOUT |
-					WDIOF_KEEPALIVEPING |
-					WDIOF_MAGICCLOSE,
-		.firmware_version =	0,
-		.identity =		"i810 TCO timer",
-	};
-	switch (cmd) {
-		default:
-			return -ENOIOCTLCMD;
-		case WDIOC_GETSUPPORT:
-			if (copy_to_user
-			    ((struct watchdog_info *) arg, &ident, sizeof (ident)))
-				return -EFAULT;
-			return 0;
-		case WDIOC_GETSTATUS:
-		case WDIOC_GETBOOTSTATUS:
-			return put_user (0, (int *) arg);
-		case WDIOC_SETOPTIONS:
-			if (get_user (options, (int *) arg))
-				return -EFAULT;
-			if (options & WDIOS_DISABLECARD) {
-				tco_timer_stop ();
-				retval = 0;
-			}
-			if (options & WDIOS_ENABLECARD) {
-				tco_timer_reload ();
-				tco_timer_start ();
-				retval = 0;
-			}
-			return retval;
-		case WDIOC_KEEPALIVE:
-			tco_timer_reload ();
-			return 0;
-		case WDIOC_SETTIMEOUT:
-			if (get_user (u_margin, (int *) arg))
-				return -EFAULT;
-			new_margin = (u_margin * 10 + 5) / 6;
-			if ((new_margin < 4) || (new_margin > 63))
-				return -EINVAL;
-			if (tco_timer_settimer ((unsigned char) new_margin))
-			    return -EINVAL;
-			i810_margin = new_margin;
-			tco_timer_reload ();
-			/* Fall */
-		case WDIOC_GETTIMEOUT:
-			return put_user ((int)(i810_margin * 6 / 10), (int *) arg);
-	}
-}
-
-/*
- * Data for PCI driver interface
- *
- * This data only exists for exporting the supported
- * PCI ids via MODULE_DEVICE_TABLE.  We do not actually
- * register a pci_driver, because someone else might one day
- * want to register another driver on the same PCI id.
- */
-static struct pci_device_id i810tco_pci_tbl[] = {
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0,	PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0,	PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0,	PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10,	PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0,	PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12,	PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0,	PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0,	PCI_ANY_ID, PCI_ANY_ID, },
-	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0,	PCI_ANY_ID, PCI_ANY_ID, },
-	{ 0, },
-};
-MODULE_DEVICE_TABLE (pci, i810tco_pci_tbl);
-
-static struct pci_dev *i810tco_pci;
-
-static unsigned char __init i810tco_getdevice (void)
-{
-	struct pci_dev *dev = NULL;
-	u8 val1, val2;
-	u16 badr;
-	/*
-	 *      Find the PCI device
-	 */
-
-	while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
-		if (pci_match_device(i810tco_pci_tbl, dev)) {
-			i810tco_pci = dev;
-			break;
-		}
-	}
-
-	if (i810tco_pci) {
-		/*
-		 *      Find the ACPI base I/O address which is the base
-		 *      for the TCO registers (TCOBASE=ACPIBASE + 0x60)
-		 *      ACPIBASE is bits [15:7] from 0x40-0x43
-		 */
-		pci_read_config_byte (i810tco_pci, 0x40, &val1);
-		pci_read_config_byte (i810tco_pci, 0x41, &val2);
-		badr = ((val2 << 1) | (val1 >> 7)) << 7;
-		ACPIBASE = badr;
-		/* Something's wrong here, ACPIBASE has to be set */
-		if (badr == 0x0001 || badr == 0x0000) {
-			printk (KERN_ERR TCO_MODULE_NAME " init: failed to get TCOBASE address\n");
-			return 0;
-		}
-		/*
-		 * Check chipset's NO_REBOOT bit
-		 */
-		pci_read_config_byte (i810tco_pci, 0xd4, &val1);
-		if (val1 & 0x02) {
-			val1 &= 0xfd;
-			pci_write_config_byte (i810tco_pci, 0xd4, val1);
-			pci_read_config_byte (i810tco_pci, 0xd4, &val1);
-			if (val1 & 0x02) {
-				printk (KERN_ERR TCO_MODULE_NAME " init: failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
-				return 0;	/* Cannot reset NO_REBOOT bit */
-			}
-		}
-		/* Set the TCO_EN bit in SMI_EN register */
-		val1 = inb (SMI_EN + 1);
-		val1 &= 0xdf;
-		outb (val1, SMI_EN + 1);
-		/* Clear out the (probably old) status */
-		outb (0, TCO1_STS);
-		outb (3, TCO2_STS);
-		return 1;
-	}
-	return 0;
-}
-
-static struct file_operations i810tco_fops = {
-	.owner =	THIS_MODULE,
-	.write =	i810tco_write,
-	.ioctl =	i810tco_ioctl,
-	.open =		i810tco_open,
-	.release =	i810tco_release,
-};
-
-static struct miscdevice i810tco_miscdev = {
-	.minor =	WATCHDOG_MINOR,
-	.name =		"watchdog",
-	.fops =		&i810tco_fops,
-};
-
-static int __init watchdog_init (void)
-{
-	spin_lock_init(&tco_lock);
-	if (!i810tco_getdevice () || i810tco_pci == NULL)
-		return -ENODEV;
-	if (!request_region (TCOBASE, 0x10, "i810 TCO")) {
-		printk (KERN_ERR TCO_MODULE_NAME
-			": I/O address 0x%04x already in use\n",
-			TCOBASE);
-		return -EIO;
-	}
-	if (misc_register (&i810tco_miscdev) != 0) {
-		release_region (TCOBASE, 0x10);
-		printk (KERN_ERR TCO_MODULE_NAME ": cannot register miscdev\n");
-		return -EIO;
-	}
-	tco_timer_settimer ((unsigned char) i810_margin);
-	tco_timer_reload ();
-
-	printk (KERN_INFO TCO_DRIVER_NAME
-		": timer margin: %d sec (0x%04x) (nowayout=%d)\n",
-		(int) (i810_margin * 6 / 10), TCOBASE, nowayout);
-	return 0;
-}
-
-static void __exit watchdog_cleanup (void)
-{
-	u8 val;
-
-	/* Reset the timer before we leave */
-	tco_timer_reload ();
-	/* Set the NO_REBOOT bit to prevent later reboots, just for sure */
-	pci_read_config_byte (i810tco_pci, 0xd4, &val);
-	val |= 0x02;
-	pci_write_config_byte (i810tco_pci, 0xd4, val);
-	release_region (TCOBASE, 0x10);
-	misc_deregister (&i810tco_miscdev);
-}
-
-module_init(watchdog_init);
-module_exit(watchdog_cleanup);
-
-MODULE_AUTHOR("Nils Faerber");
-MODULE_DESCRIPTION("TCO timer driver for i8xx chipsets");
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/char/watchdog/i810-tco.h b/drivers/char/watchdog/i810-tco.h
--- a/drivers/char/watchdog/i810-tco.h	Wed Feb 11 22:14:31 2004
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,42 +0,0 @@
-/*
- *	i810-tco:	TCO timer driver for i8xx chipsets
- *
- *	(c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved.
- *				http://www.kernelconcepts.de
- *
- *	This program is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU General Public License
- *	as published by the Free Software Foundation; either version
- *	2 of the License, or (at your option) any later version.
- *
- *	Neither kernel concepts nor Nils Faerber admit liability nor provide
- *	warranty for any of this software. This material is provided
- *	"AS-IS" and at no charge.
- *
- *	(c) Copyright 2000	kernel concepts <nils@kernelconcepts.de>
- *				developed for
- *                              Jentro AG, Haar/Munich (Germany)
- *
- *	TCO timer driver for i8xx chipsets
- *	based on softdog.c by Alan Cox <alan@redhat.com>
- *
- *	For history and the complete list of supported I/O Controller Hub's
- *	see i810-tco.c
- */
-
-
-/*
- * Some address definitions for the i810 TCO
- */
-
-#define	TCOBASE		ACPIBASE + 0x60	/* TCO base address		*/
-#define TCO1_RLD	TCOBASE + 0x00	/* TCO Timer Reload and Current Value */
-#define TCO1_TMR	TCOBASE + 0x01	/* TCO Timer Initial Value	*/
-#define	TCO1_DAT_IN	TCOBASE + 0x02	/* TCO Data In Register		*/
-#define	TCO1_DAT_OUT	TCOBASE + 0x03	/* TCO Data Out Register	*/
-#define	TCO1_STS	TCOBASE + 0x04	/* TCO1 Status Register		*/
-#define	TCO2_STS	TCOBASE + 0x06	/* TCO2 Status Register		*/
-#define TCO1_CNT	TCOBASE + 0x08	/* TCO1 Control Register	*/
-#define TCO2_CNT	TCOBASE + 0x0a	/* TCO2 Control Register	*/
-
-#define	SMI_EN		ACPIBASE + 0x30	/* SMI Control and Enable Register */
diff -Nru a/drivers/char/watchdog/i8xx_tco.c b/drivers/char/watchdog/i8xx_tco.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/char/watchdog/i8xx_tco.c	Wed Feb 11 22:14:30 2004
@@ -0,0 +1,510 @@
+/*
+ *	i8xx_tco 0.06:	TCO timer driver for i8xx chipsets
+ *
+ *	(c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved.
+ *				http://www.kernelconcepts.de
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *
+ *	Neither kernel concepts nor Nils Faerber admit liability nor provide
+ *	warranty for any of this software. This material is provided
+ *	"AS-IS" and at no charge.
+ *
+ *	(c) Copyright 2000	kernel concepts <nils@kernelconcepts.de>
+ *				developed for
+ *                              Jentro AG, Haar/Munich (Germany)
+ *
+ *	TCO timer driver for i8xx chipsets
+ *	based on softdog.c by Alan Cox <alan@redhat.com>
+ *
+ *	The TCO timer is implemented in the following I/O controller hubs:
+ *	(See the intel documentation on http://developer.intel.com.)
+ *	82801AA & 82801AB  chip : document number 290655-003, 290677-004,
+ *	82801BA & 82801BAM chip : document number 290687-002, 298242-005,
+ *	82801CA & 82801CAM chip : document number 290716-001, 290718-001,
+ *	82801DB & 82801E   chip : document number 290744-001, 273599-001,
+ *	82801EB & 82801ER  chip : document number 252516-001
+ *
+ *  20000710 Nils Faerber
+ *	Initial Version 0.01
+ *  20000728 Nils Faerber
+ *	0.02 Fix for SMI_EN->TCO_EN bit, some cleanups
+ *  20011214 Matt Domsch <Matt_Domsch@dell.com>
+ *	0.03 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
+ *	     Didn't add timeout option as i810_margin already exists.
+ *  20020224 Joel Becker, Wim Van Sebroeck
+ *	0.04 Support for 82801CA(M) chipset, timer margin needs to be > 3,
+ *	     add support for WDIOC_SETTIMEOUT and WDIOC_GETTIMEOUT.
+ *  20020412 Rob Radez <rob@osinvestor.com>, Wim Van Sebroeck
+ *	0.05 Fix possible timer_alive race, add expect close support,
+ *	     clean up ioctls (WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS and
+ *	     WDIOC_SETOPTIONS), made i810tco_getdevice __init,
+ *	     removed boot_status, removed tco_timer_read,
+ *	     added support for 82801DB and 82801E chipset,
+ *	     added support for 82801EB and 8280ER chipset,
+ *	     general cleanup.
+ *  20030921 Wim Van Sebroeck <wim@iguana.be>
+ *	0.06 change i810_margin to heartbeat, use module_param,
+ *	     added notify system support, renamed module to i8xx_tco.
+ */
+
+/*
+ *	Includes, defines, variables, module parameters, ...
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#include "i8xx_tco.h"
+
+/* Module and version information */
+#define TCO_VERSION "0.06"
+#define TCO_MODULE_NAME "i8xx TCO timer"
+#define TCO_DRIVER_NAME   TCO_MODULE_NAME ", v" TCO_VERSION
+#define PFX TCO_MODULE_NAME ": "
+
+/* internal variables */
+static unsigned int ACPIBASE;
+static spinlock_t tco_lock;	/* Guards the hardware */
+static unsigned long timer_alive;
+static char tco_expect_close;
+static struct pci_dev *i8xx_tco_pci;
+
+/* module parameters */
+#define WATCHDOG_HEARTBEAT 30	/* 30 sec default heartbeat (2<heartbeat<39) */
+static int heartbeat = WATCHDOG_HEARTBEAT;  /* in seconds */
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+/*
+ * Some TCO specific functions
+ */
+
+static inline unsigned char seconds_to_ticks(int seconds)
+{
+	/* the internal timer is stored as ticks which decrement
+	 * every 0.6 seconds */
+	return (seconds * 10) / 6;
+}
+
+static int tco_timer_start (void)
+{
+	unsigned char val;
+
+	spin_lock(&tco_lock);
+	val = inb (TCO1_CNT + 1);
+	val &= 0xf7;
+	outb (val, TCO1_CNT + 1);
+	val = inb (TCO1_CNT + 1);
+	spin_unlock(&tco_lock);
+
+	if (val & 0x08)
+		return -1;
+	return 0;
+}
+
+static int tco_timer_stop (void)
+{
+	unsigned char val;
+
+	spin_lock(&tco_lock);
+	val = inb (TCO1_CNT + 1);
+	val |= 0x08;
+	outb (val, TCO1_CNT + 1);
+	val = inb (TCO1_CNT + 1);
+	spin_unlock(&tco_lock);
+
+	if ((val & 0x08) == 0)
+		return -1;
+	return 0;
+}
+
+static int tco_timer_keepalive (void)
+{
+	spin_lock(&tco_lock);
+	outb (0x01, TCO1_RLD);
+	spin_unlock(&tco_lock);
+	return 0;
+}
+
+static int tco_timer_set_heartbeat (int t)
+{
+	unsigned char val;
+	unsigned char tmrval;
+
+	tmrval = seconds_to_ticks(t);
+	/* from the specs: */
+	/* "Values of 0h-3h are ignored and should not be attempted" */
+	if (tmrval > 0x3f || tmrval < 0x04)
+		return -EINVAL;
+
+	/* Write new heartbeat to watchdog */
+	spin_lock(&tco_lock);
+	val = inb (TCO1_TMR);
+	val &= 0xc0;
+	val |= tmrval;
+	outb (val, TCO1_TMR);
+	val = inb (TCO1_TMR);
+	spin_unlock(&tco_lock);
+
+	if ((val & 0x3f) != tmrval)
+		return -EINVAL;
+
+	heartbeat = t;
+	return 0;
+}
+
+/*
+ *	/dev/watchdog handling
+ */
+
+static int i8xx_tco_open (struct inode *inode, struct file *file)
+{
+	/* /dev/watchdog can only be opened once */
+	if (test_and_set_bit(0, &timer_alive))
+		return -EBUSY;
+
+	/*
+	 *      Reload and activate timer
+	 */
+	tco_timer_keepalive ();
+	tco_timer_start ();
+	return 0;
+}
+
+static int i8xx_tco_release (struct inode *inode, struct file *file)
+{
+	/*
+	 *      Shut off the timer.
+	 */
+	if (tco_expect_close == 42) {
+		tco_timer_stop ();
+	} else {
+		printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+		tco_timer_keepalive ();
+	}
+	clear_bit(0, &timer_alive);
+	tco_expect_close = 0;
+	return 0;
+}
+
+static ssize_t i8xx_tco_write (struct file *file, const char *data,
+			      size_t len, loff_t * ppos)
+{
+	/*  Can't seek (pwrite) on this device  */
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	/* See if we got the magic character 'V' and reload the timer */
+	if (len) {
+		if (!nowayout) {
+			size_t i;
+
+			/* note: just in case someone wrote the magic character
+			 * five months ago... */
+			tco_expect_close = 0;
+
+			/* scan to see whether or not we got the magic character */
+			for (i = 0; i != len; i++) {
+				char c;
+				if(get_user(c, data+i))
+					return -EFAULT;
+				if (c == 'V')
+					tco_expect_close = 42;
+			}
+		}
+
+		/* someone wrote to us, we should reload the timer */
+		tco_timer_keepalive ();
+	}
+	return len;
+}
+
+static int i8xx_tco_ioctl (struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg)
+{
+	int new_options, retval = -EINVAL;
+	int new_heartbeat;
+	static struct watchdog_info ident = {
+		.options =		WDIOF_SETTIMEOUT |
+					WDIOF_KEEPALIVEPING |
+					WDIOF_MAGICCLOSE,
+		.firmware_version =	0,
+		.identity =		TCO_MODULE_NAME,
+	};
+
+	switch (cmd) {
+		case WDIOC_GETSUPPORT:
+			return copy_to_user((struct watchdog_info *) arg, &ident,
+				sizeof (ident)) ? -EFAULT : 0;
+
+		case WDIOC_GETSTATUS:
+		case WDIOC_GETBOOTSTATUS:
+			return put_user (0, (int *) arg);
+
+		case WDIOC_KEEPALIVE:
+			tco_timer_keepalive ();
+			return 0;
+
+		case WDIOC_SETOPTIONS:
+		{
+			if (get_user (new_options, (int *) arg))
+				return -EFAULT;
+
+			if (new_options & WDIOS_DISABLECARD) {
+				tco_timer_stop ();
+				retval = 0;
+			}
+
+			if (new_options & WDIOS_ENABLECARD) {
+				tco_timer_keepalive ();
+				tco_timer_start ();
+				retval = 0;
+			}
+
+			return retval;
+		}
+
+		case WDIOC_SETTIMEOUT:
+		{
+			if (get_user(new_heartbeat, (int *) arg))
+				return -EFAULT;
+
+			if (tco_timer_set_heartbeat(new_heartbeat))
+			    return -EINVAL;
+
+			tco_timer_keepalive ();
+			/* Fall */
+		}
+
+		case WDIOC_GETTIMEOUT:
+			return put_user(heartbeat, (int *)arg);
+
+		default:
+			return -ENOIOCTLCMD;
+	}
+}
+
+/*
+ *	Notify system
+ */
+
+static int i8xx_tco_notify_sys (struct notifier_block *this, unsigned long code, void *unused)
+{
+	if (code==SYS_DOWN || code==SYS_HALT) {
+		/* Turn the WDT off */
+		tco_timer_stop ();
+	}
+
+	return NOTIFY_DONE;
+}
+
+/*
+ *	Kernel Interfaces
+ */
+
+static struct file_operations i8xx_tco_fops = {
+	.owner =	THIS_MODULE,
+	.llseek =	no_llseek,
+	.write =	i8xx_tco_write,
+	.ioctl =	i8xx_tco_ioctl,
+	.open =		i8xx_tco_open,
+	.release =	i8xx_tco_release,
+};
+
+static struct miscdevice i8xx_tco_miscdev = {
+	.minor =	WATCHDOG_MINOR,
+	.name =		"watchdog",
+	.fops =		&i8xx_tco_fops,
+};
+
+static struct notifier_block i8xx_tco_notifier = {
+	.notifier_call =	i8xx_tco_notify_sys,
+};
+
+/*
+ * Data for PCI driver interface
+ *
+ * This data only exists for exporting the supported
+ * PCI ids via MODULE_DEVICE_TABLE.  We do not actually
+ * register a pci_driver, because someone else might one day
+ * want to register another driver on the same PCI id.
+ */
+static struct pci_device_id i8xx_tco_pci_tbl[] = {
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0,	PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0, },			/* End of list */
+};
+MODULE_DEVICE_TABLE (pci, i8xx_tco_pci_tbl);
+
+/*
+ *	Init & exit routines
+ */
+
+static unsigned char __init i8xx_tco_getdevice (void)
+{
+	struct pci_dev *dev = NULL;
+	u8 val1, val2;
+	u16 badr;
+	/*
+	 *      Find the PCI device
+	 */
+
+	while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+		if (pci_match_device(i8xx_tco_pci_tbl, dev)) {
+			i8xx_tco_pci = dev;
+			break;
+		}
+	}
+
+	if (i8xx_tco_pci) {
+		/*
+		 *      Find the ACPI base I/O address which is the base
+		 *      for the TCO registers (TCOBASE=ACPIBASE + 0x60)
+		 *      ACPIBASE is bits [15:7] from 0x40-0x43
+		 */
+		pci_read_config_byte (i8xx_tco_pci, 0x40, &val1);
+		pci_read_config_byte (i8xx_tco_pci, 0x41, &val2);
+		badr = ((val2 << 1) | (val1 >> 7)) << 7;
+		ACPIBASE = badr;
+		/* Something's wrong here, ACPIBASE has to be set */
+		if (badr == 0x0001 || badr == 0x0000) {
+			printk (KERN_ERR PFX "failed to get TCOBASE address\n");
+			return 0;
+		}
+		/*
+		 * Check chipset's NO_REBOOT bit
+		 */
+		pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1);
+		if (val1 & 0x02) {
+			val1 &= 0xfd;
+			pci_write_config_byte (i8xx_tco_pci, 0xd4, val1);
+			pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1);
+			if (val1 & 0x02) {
+				printk (KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
+				return 0;	/* Cannot reset NO_REBOOT bit */
+			}
+		}
+		/* Set the TCO_EN bit in SMI_EN register */
+		val1 = inb (SMI_EN + 1);
+		val1 &= 0xdf;
+		outb (val1, SMI_EN + 1);
+		/* Clear out the (probably old) status */
+		outb (0, TCO1_STS);
+		outb (3, TCO2_STS);
+		return 1;
+	}
+	return 0;
+}
+
+static int __init watchdog_init (void)
+{
+	int ret;
+
+	spin_lock_init(&tco_lock);
+
+	/* Check whether or not the hardware watchdog is there */
+	if (!i8xx_tco_getdevice () || i8xx_tco_pci == NULL)
+		return -ENODEV;
+
+	if (!request_region (TCOBASE, 0x10, "i8xx TCO")) {
+		printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
+			TCOBASE);
+		ret = -EIO;
+		goto out;
+	}
+
+	/* Check that the heartbeat value is within it's range ; if not reset to the default */
+	if (tco_timer_set_heartbeat (heartbeat)) {
+		heartbeat = WATCHDOG_HEARTBEAT;
+		tco_timer_set_heartbeat (heartbeat);
+		printk(KERN_INFO PFX "heartbeat value must be 2<heartbeat<39, using %d\n",
+			heartbeat);
+	}
+
+	ret = register_reboot_notifier(&i8xx_tco_notifier);
+	if (ret != 0) {
+		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			ret);
+		goto unreg_region;
+	}
+
+	ret = misc_register(&i8xx_tco_miscdev);
+	if (ret != 0) {
+		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, ret);
+		goto unreg_notifier;
+	}
+
+	tco_timer_keepalive ();
+
+	printk (KERN_INFO PFX "initialized (0x%04x). heartbeat=%d sec (nowayout=%d)\n",
+		TCOBASE, heartbeat, nowayout);
+
+	return 0;
+
+unreg_notifier:
+	unregister_reboot_notifier(&i8xx_tco_notifier);
+unreg_region:
+	release_region (TCOBASE, 0x10);
+out:
+	return ret;
+}
+
+static void __exit watchdog_cleanup (void)
+{
+	u8 val;
+
+	/* Stop the timer before we leave */
+	if (!nowayout)
+		tco_timer_stop ();
+
+	/* Set the NO_REBOOT bit to prevent later reboots, just for sure */
+	pci_read_config_byte (i8xx_tco_pci, 0xd4, &val);
+	val |= 0x02;
+	pci_write_config_byte (i8xx_tco_pci, 0xd4, val);
+
+	/* Deregister */
+	misc_deregister (&i8xx_tco_miscdev);
+	unregister_reboot_notifier(&i8xx_tco_notifier);
+	release_region (TCOBASE, 0x10);
+}
+
+module_init(watchdog_init);
+module_exit(watchdog_cleanup);
+
+MODULE_AUTHOR("Nils Faerber");
+MODULE_DESCRIPTION("TCO timer driver for i8xx chipsets");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff -Nru a/drivers/char/watchdog/i8xx_tco.h b/drivers/char/watchdog/i8xx_tco.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/char/watchdog/i8xx_tco.h	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,42 @@
+/*
+ *	i8xx_tco:	TCO timer driver for i8xx chipsets
+ *
+ *	(c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved.
+ *				http://www.kernelconcepts.de
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *
+ *	Neither kernel concepts nor Nils Faerber admit liability nor provide
+ *	warranty for any of this software. This material is provided
+ *	"AS-IS" and at no charge.
+ *
+ *	(c) Copyright 2000	kernel concepts <nils@kernelconcepts.de>
+ *				developed for
+ *                              Jentro AG, Haar/Munich (Germany)
+ *
+ *	TCO timer driver for i8xx chipsets
+ *	based on softdog.c by Alan Cox <alan@redhat.com>
+ *
+ *	For history and the complete list of supported I/O Controller Hub's
+ *	see i8xx_tco.c
+ */
+
+
+/*
+ * Some address definitions for the TCO
+ */
+
+#define	TCOBASE		ACPIBASE + 0x60	/* TCO base address		*/
+#define TCO1_RLD	TCOBASE + 0x00	/* TCO Timer Reload and Current Value */
+#define TCO1_TMR	TCOBASE + 0x01	/* TCO Timer Initial Value	*/
+#define	TCO1_DAT_IN	TCOBASE + 0x02	/* TCO Data In Register		*/
+#define	TCO1_DAT_OUT	TCOBASE + 0x03	/* TCO Data Out Register	*/
+#define	TCO1_STS	TCOBASE + 0x04	/* TCO1 Status Register		*/
+#define	TCO2_STS	TCOBASE + 0x06	/* TCO2 Status Register		*/
+#define TCO1_CNT	TCOBASE + 0x08	/* TCO1 Control Register	*/
+#define TCO2_CNT	TCOBASE + 0x0a	/* TCO2 Control Register	*/
+
+#define	SMI_EN		ACPIBASE + 0x30	/* SMI Control and Enable Register */
diff -Nru a/drivers/char/watchdog/indydog.c b/drivers/char/watchdog/indydog.c
--- a/drivers/char/watchdog/indydog.c	Wed Feb 11 22:14:31 2004
+++ b/drivers/char/watchdog/indydog.c	Wed Feb 11 22:14:31 2004
@@ -1,5 +1,5 @@
 /*
- *	IndyDog	0.2	A Hardware Watchdog Device for SGI IP22
+ *	IndyDog	0.3	A Hardware Watchdog Device for SGI IP22
  *
  *	(c) Copyright 2002 Guido Guenther <agx@sigxcpu.org>, All Rights Reserved.
  *
@@ -19,11 +19,16 @@
 #include <linux/mm.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/moduleparam.h>
 #include <asm/uaccess.h>
 #include <asm/sgi/sgimc.h>
 
+#define PFX "indydog: "
+#define WATCHDOG_HEARTBEAT 60
+
 static unsigned long indydog_alive;
 static struct sgimc_misc_ctrl *mcmisc_regs;
 static char expect_close;
@@ -37,11 +42,30 @@
 module_param(nowayout, int, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
 
-static void indydog_ping()
+static void indydog_start(void)
 {
-	mcmisc_regs->watchdogt = 0;
+	u32 mc_ctrl0 = mcmisc_regs->cpuctrl0;
+
+	mc_ctrl0 |= SGIMC_CCTRL0_WDOG;
+	mcmisc_regs->cpuctrl0 = mc_ctrl0;
+
+	printk(KERN_INFO PFX "Started watchdog timer.\n");
 }
 
+static void indydog_stop(void)
+{
+	u32 mc_ctrl0 = mcmisc_regs->cpuctrl0;
+
+	mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG;
+	mcmisc_regs->cpuctrl0 = mc_ctrl0;
+
+	printk(KERN_INFO PFX "Stopped watchdog timer.\n");
+}
+
+static void indydog_ping(void)
+{
+	mcmisc_regs->watchdogt = 0;
+}
 
 /*
  *	Allow only one person to hold it open
@@ -49,8 +73,6 @@
 
 static int indydog_open(struct inode *inode, struct file *file)
 {
-	u32 mc_ctrl0;
-
 	if( test_and_set_bit(0,&indydog_alive) )
 		return -EBUSY;
 
@@ -60,13 +82,9 @@
 	/*
 	 *	Activate timer
 	 */
-	mcmisc_regs = (struct sgimc_misc_ctrl *)(KSEG1+0x1fa00000);
-
-	mc_ctrl0 = mcmisc_regs->cpuctrl0 | SGIMC_CCTRL0_WDOG;
-	mcmisc_regs->cpuctrl0 = mc_ctrl0;
+	indydog_start();
 	indydog_ping();
 
-	printk("Started watchdog timer.\n");
 	return 0;
 }
 
@@ -78,12 +96,10 @@
 	 */
 
 	if (expect_close == 42) {
-		u32 mc_ctrl0 = mcmisc_regs->cpuctrl0;
-		mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG;
-		mcmisc_regs->cpuctrl0 = mc_ctrl0;
-		printk("Stopped watchdog timer.\n");
+		indydog_stop();
 	} else {
-		printk(KERN_CRIT "WDT device closed unexpectedly.  WDT will not stop!\n");
+		printk(KERN_CRIT PFX "WDT device closed unexpectedly.  WDT will not stop!\n");
+		indydog_ping();
 	}
 	clear_bit(0,&indydog_alive);
 	expect_close = 0;
@@ -121,9 +137,12 @@
 static int indydog_ioctl(struct inode *inode, struct file *file,
 	unsigned int cmd, unsigned long arg)
 {
+	int options, retval = -EINVAL;
 	static struct watchdog_info ident = {
-		.options = WDIOF_MAGICCLOSE,
-		.identity = "Hardware Watchdog for SGI IP22",
+		.options =		WDIOF_KEEPALIVEPING |
+					WDIOF_MAGICCLOSE,
+		.firmware_version =	0,
+		.identity =		"Hardware Watchdog for SGI IP22",
 	};
 
 	switch (cmd) {
@@ -139,9 +158,40 @@
 		case WDIOC_KEEPALIVE:
 			indydog_ping();
 			return 0;
+		case WDIOC_GETTIMEOUT:
+			return put_user(WATCHDOG_TIMEOUT,(int *)arg);
+		case WDIOC_SETOPTIONS:
+		{
+			if (get_user(options, (int *)arg))
+				return -EFAULT;
+
+			if (options & WDIOS_DISABLECARD)
+			{
+				indydog_stop();
+				retval = 0;
+			}
+
+			if (options & WDIOS_ENABLECARD)
+			{
+				indydog_start();
+				retval = 0;
+			}
+
+			return retval;
+		}
 	}
 }
 
+static int indydog_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
+{
+	if (code==SYS_DOWN || code==SYS_HALT) {
+		/* Turn the WDT off */
+		indydog_stop();
+	}
+
+	return NOTIFY_DONE;
+}
+
 static struct file_operations indydog_fops = {
 	.owner	= THIS_MODULE,
 	.write	= indydog_write,
@@ -156,16 +206,32 @@
 	.fops	= &indydog_fops,
 };
 
-static char banner[] __initdata = KERN_INFO "Hardware Watchdog Timer for SGI IP22: 0.2\n";
+static struct notifier_block indydog_notifier = {
+	.notifier_call = indydog_notify_sys,
+};
+
+static char banner[] __initdata = KERN_INFO PFX "Hardware Watchdog Timer for SGI IP22: 0.3\n";
 
 static int __init watchdog_init(void)
 {
 	int ret;
 
-	ret = misc_register(&indydog_miscdev);
+	mcmisc_regs = (struct sgimc_misc_ctrl *)(KSEG1+0x1fa00000);
+
+	ret = register_reboot_notifier(&indydog_notifier);
+	if (ret) {
+		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			ret);
+		return ret;
+	}
 
-	if (ret)
+	ret = misc_register(&indydog_miscdev);
+	if (ret) {
+		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, ret);
+		unregister_reboot_notifier(&indydog_notifier);
 		return ret;
+	}
 
 	printk(banner);
 
@@ -175,8 +241,13 @@
 static void __exit watchdog_exit(void)
 {
 	misc_deregister(&indydog_miscdev);
+	unregister_reboot_notifier(&indydog_notifier);
 }
 
 module_init(watchdog_init);
 module_exit(watchdog_exit);
+
+MODULE_AUTHOR("Guido Guenther <agx@sigxcpu.org>");
+MODULE_DESCRIPTION("Hardware Watchdog Device for SGI IP22");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff -Nru a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/char/watchdog/pcwd_pci.c	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,681 @@
+/*
+ *	Berkshire PCI-PC Watchdog Card Driver
+ *
+ *	(c) Copyright 2003 Wim Van Sebroeck <wim@iguana.be>.
+ *
+ *	Based on source code of the following authors:
+ *	  Ken Hollis <kenji@bitgate.com>,
+ *	  Lindsay Harris <lindsay@bluegum.com>,
+ *	  Alan Cox <alan@redhat.com>,
+ *	  Matt Domsch <Matt_Domsch@dell.com>,
+ *	  Rob Radez <rob@osinvestor.com>
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *
+ *	Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
+ *	provide warranty for any of this software. This material is
+ *	provided "AS-IS" and at no charge.
+ */
+
+/*
+ *	A bells and whistles driver is available from http://www.pcwd.de/
+ *	More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/
+ */
+
+/*
+ *	Includes, defines, variables, module parameters, ...
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/spinlock.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+/* Module and version information */
+#define WATCHDOG_VERSION "1.00"
+#define WATCHDOG_DATE "09/02/2004"
+#define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog"
+#define WATCHDOG_NAME "pcwd_pci"
+#define PFX WATCHDOG_NAME ": "
+#define DRIVER_VERSION WATCHDOG_DRIVER_NAME " driver, v" WATCHDOG_VERSION " (" WATCHDOG_DATE ")\n"
+
+/* Stuff for the PCI ID's  */
+#ifndef PCI_VENDOR_ID_QUICKLOGIC
+#define PCI_VENDOR_ID_QUICKLOGIC    0x11e3
+#endif
+
+#ifndef PCI_DEVICE_ID_WATCHDOG_PCIPCWD
+#define PCI_DEVICE_ID_WATCHDOG_PCIPCWD 0x5030
+#endif
+
+/*
+ * These are the defines that describe the control status bits for the
+ * PCI-PC Watchdog card.
+ */
+#define WD_PCI_WTRP             0x01	/* Watchdog Trip status */
+#define WD_PCI_HRBT             0x02	/* Watchdog Heartbeat */
+#define WD_PCI_TTRP             0x04	/* Temperature Trip status */
+
+/* according to documentation max. time to process a command for the pci
+   watchdog card is 100 ms, so we give it 150 ms to do it's job */
+#define PCI_COMMAND_TIMEOUT	150
+
+/* Watchdog's internal commands */
+#define CMD_GET_STATUS			0x04
+#define CMD_GET_FIRMWARE_VERSION	0x08
+#define CMD_READ_WATCHDOG_TIMEOUT	0x18
+#define CMD_WRITE_WATCHDOG_TIMEOUT	0x19
+
+/* internal variables */
+static int temp_panic;
+static unsigned long is_active;
+static char expect_release;
+static struct {
+	int supports_temp;	/* Wether or not the card has a temperature device */
+	int boot_status;	/* The card's boot status */
+	unsigned long io_addr;	/* The cards I/O address */
+	spinlock_t io_lock;
+	struct pci_dev *pdev;
+} pcipcwd_private;
+
+/* module parameters */
+#define WATCHDOG_HEARTBEAT 2	/* 2 sec default heartbeat */
+static int heartbeat = WATCHDOG_HEARTBEAT;
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
+
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+static int nowayout = 1;
+#else
+static int nowayout = 0;
+#endif
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+/*
+ *	Internal functions
+ */
+
+static int send_command(int cmd, int *msb, int *lsb)
+{
+	int got_response, count;
+
+	spin_lock(&pcipcwd_private.io_lock);
+	/* If a command requires data it should be written first.
+	 * Data for commands with 8 bits of data should be written to port 4.
+	 * Commands with 16 bits of data, should be written as LSB to port 4
+	 * and MSB to port 5.
+	 * After the required data has been written then write the command to
+	 * port 6. */
+	outb_p(*lsb, pcipcwd_private.io_addr + 4);
+	outb_p(*msb, pcipcwd_private.io_addr + 5);
+	outb_p(cmd, pcipcwd_private.io_addr + 6);
+
+	/* wait till the pci card processed the command, signaled by
+	 * the WRSP bit in port 2 and give it a max. timeout of
+	 * PCI_COMMAND_TIMEOUT to process */
+	got_response = inb_p(pcipcwd_private.io_addr + 2) & 0x40;
+	for (count = 0; (count < PCI_COMMAND_TIMEOUT) && (!got_response); count++) {
+		mdelay(1);
+		got_response = inb_p(pcipcwd_private.io_addr + 2) & 0x40;
+	}
+
+	if (got_response) {
+		/* read back response */
+		*lsb = inb_p(pcipcwd_private.io_addr + 4);
+		*msb = inb_p(pcipcwd_private.io_addr + 5);
+
+		/* clear WRSP bit */
+		inb_p(pcipcwd_private.io_addr + 6);
+	}
+	spin_unlock(&pcipcwd_private.io_lock);
+
+	return got_response;
+}
+
+static int pcipcwd_start(void)
+{
+	int stat_reg;
+
+	spin_lock(&pcipcwd_private.io_lock);
+	outb_p(0x00, pcipcwd_private.io_addr + 3);
+	udelay(1000);
+
+	stat_reg = inb_p(pcipcwd_private.io_addr + 2);
+	spin_unlock(&pcipcwd_private.io_lock);
+
+	if (stat_reg & 0x10) {
+		printk(KERN_ERR PFX "Card timer not enabled\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int pcipcwd_stop(void)
+{
+	int stat_reg;
+
+	spin_lock(&pcipcwd_private.io_lock);
+	outb_p(0xA5, pcipcwd_private.io_addr + 3);
+	udelay(1000);
+
+	outb_p(0xA5, pcipcwd_private.io_addr + 3);
+	udelay(1000);
+
+	stat_reg = inb_p(pcipcwd_private.io_addr + 2);
+	spin_unlock(&pcipcwd_private.io_lock);
+
+	if (!(stat_reg & 0x10)) {
+		printk(KERN_ERR PFX "Card did not acknowledge disable attempt\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int pcipcwd_keepalive(void)
+{
+	/* Re-trigger watchdog by writing to port 0 */
+	outb_p(0x42, pcipcwd_private.io_addr);
+	return 0;
+}
+
+static int pcipcwd_set_heartbeat(int t)
+{
+	int t_msb = t / 256;
+	int t_lsb = t % 256;
+
+	if ((t < 0x0001) || (t > 0xFFFF))
+		return -EINVAL;
+
+	/* Write new heartbeat to watchdog */
+	send_command(CMD_WRITE_WATCHDOG_TIMEOUT, &t_msb, &t_lsb);
+
+	heartbeat = t;
+	return 0;
+}
+
+static int pcipcwd_get_status(int *status)
+{
+	int new_status;
+
+	*status=0;
+	new_status = inb_p(pcipcwd_private.io_addr + 1);
+	if (new_status & WD_PCI_WTRP)
+		*status |= WDIOF_CARDRESET;
+	if (new_status & WD_PCI_TTRP) {
+		*status |= WDIOF_OVERHEAT;
+		if (temp_panic)
+			panic(PFX "Temperature overheat trip!\n");
+	}
+
+	return 0;
+}
+
+static int pcipcwd_clear_status(void)
+{
+	outb_p(0x01, pcipcwd_private.io_addr + 1);
+	return 0;
+}
+
+static int pcipcwd_get_temperature(int *temperature)
+{
+	*temperature = 0;
+	if (!pcipcwd_private.supports_temp)
+		return -ENODEV;
+
+	/*
+	 * Convert celsius to fahrenheit, since this was
+	 * the decided 'standard' for this return value.
+	 */
+	*temperature = ((inb_p(pcipcwd_private.io_addr)) * 9 / 5) + 32;
+
+	return 0;
+}
+
+/*
+ *	/dev/watchdog handling
+ */
+
+static ssize_t pcipcwd_write(struct file *file, const char *data,
+			      size_t len, loff_t *ppos)
+{
+	/* Can't seek (pwrite) on this device  */
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	/* See if we got the magic character 'V' and reload the timer */
+	if (len) {
+		if (!nowayout) {
+			size_t i;
+
+			/* note: just in case someone wrote the magic character
+			 * five months ago... */
+			expect_release = 0;
+
+			/* scan to see whether or not we got the magic character */
+			for (i = 0; i != len; i++) {
+				char c;
+				if(get_user(c, data+i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_release = 42;
+			}
+		}
+
+		/* someone wrote to us, we should reload the timer */
+		pcipcwd_keepalive();
+	}
+	return len;
+}
+
+static int pcipcwd_ioctl(struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg)
+{
+	static struct watchdog_info ident = {
+		.options =		WDIOF_OVERHEAT |
+					WDIOF_CARDRESET |
+					WDIOF_KEEPALIVEPING |
+					WDIOF_SETTIMEOUT |
+					WDIOF_MAGICCLOSE,
+		.firmware_version =	1,
+		.identity =		WATCHDOG_DRIVER_NAME,
+	};
+
+	switch (cmd) {
+		case WDIOC_GETSUPPORT:
+			return copy_to_user((struct watchdog_info *) arg, &ident,
+				sizeof (ident)) ? -EFAULT : 0;
+
+		case WDIOC_GETSTATUS:
+		{
+			int status;
+
+			pcipcwd_get_status(&status);
+
+			return put_user(status, (int *) arg);
+		}
+
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(pcipcwd_private.boot_status, (int *) arg);
+
+		case WDIOC_GETTEMP:
+		{
+			int temperature;
+
+			if (pcipcwd_get_temperature(&temperature))
+				return -EFAULT;
+
+			return put_user(temperature, (int *) arg);
+		}
+
+		case WDIOC_KEEPALIVE:
+			pcipcwd_keepalive();
+			return 0;
+
+		case WDIOC_SETOPTIONS:
+		{
+			int new_options, retval = -EINVAL;
+
+			if (get_user (new_options, (int *) arg))
+				return -EFAULT;
+
+			if (new_options & WDIOS_DISABLECARD) {
+				pcipcwd_stop();
+				retval = 0;
+			}
+
+			if (new_options & WDIOS_ENABLECARD) {
+				pcipcwd_start();
+				retval = 0;
+			}
+
+			if (new_options & WDIOS_TEMPPANIC) {
+				temp_panic = 1;
+				retval = 0;
+			}
+
+			return retval;
+		}
+
+		case WDIOC_SETTIMEOUT:
+		{
+			int new_heartbeat;
+
+			if (get_user(new_heartbeat, (int *) arg))
+				return -EFAULT;
+
+			if (pcipcwd_set_heartbeat(new_heartbeat))
+			    return -EINVAL;
+
+			pcipcwd_keepalive();
+			/* Fall */
+		}
+
+		case WDIOC_GETTIMEOUT:
+			return put_user(heartbeat, (int *)arg);
+
+		default:
+			return -ENOIOCTLCMD;
+	}
+}
+
+static int pcipcwd_open(struct inode *inode, struct file *file)
+{
+	/* /dev/watchdog can only be opened once */
+	if (test_and_set_bit(0, &is_active))
+		return -EBUSY;
+
+	/* Activate */
+	pcipcwd_start();
+	pcipcwd_keepalive();
+	return 0;
+}
+
+static int pcipcwd_release(struct inode *inode, struct file *file)
+{
+	/*
+	 *      Shut off the timer.
+	 */
+	if (expect_release == 42) {
+		pcipcwd_stop();
+	} else {
+		printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+		pcipcwd_keepalive();
+	}
+	clear_bit(0, &is_active);
+	expect_release = 0;
+	return 0;
+}
+
+/*
+ *	/dev/temperature handling
+ */
+
+static ssize_t pcipcwd_temp_read(struct file *file, char *data,
+				size_t len, loff_t *ppos)
+{
+	int temperature;
+
+	/* Can't seek (pwrite) on this device  */
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
+
+	if (pcipcwd_get_temperature(&temperature))
+		return -EFAULT;
+
+	if (copy_to_user (data, &temperature, 1))
+		return -EFAULT;
+
+	return 1;
+}
+
+static int pcipcwd_temp_open(struct inode *inode, struct file *file)
+{
+	if (!pcipcwd_private.supports_temp)
+		return -ENODEV;
+
+	return 0;
+}
+
+static int pcipcwd_temp_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+/*
+ *	Notify system
+ */
+
+static int pcipcwd_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
+{
+	if (code==SYS_DOWN || code==SYS_HALT) {
+		/* Turn the WDT off */
+		pcipcwd_stop();
+	}
+
+	return NOTIFY_DONE;
+}
+
+/*
+ *	Kernel Interfaces
+ */
+
+static struct file_operations pcipcwd_fops = {
+	.owner =	THIS_MODULE,
+	.llseek =	no_llseek,
+	.write =	pcipcwd_write,
+	.ioctl =	pcipcwd_ioctl,
+	.open =		pcipcwd_open,
+	.release =	pcipcwd_release,
+};
+
+static struct miscdevice pcipcwd_miscdev = {
+	.minor =	WATCHDOG_MINOR,
+	.name =		"watchdog",
+	.fops =		&pcipcwd_fops,
+};
+
+static struct file_operations pcipcwd_temp_fops = {
+	.owner =	THIS_MODULE,
+	.llseek =	no_llseek,
+	.read =		pcipcwd_temp_read,
+	.open =		pcipcwd_temp_open,
+	.release =	pcipcwd_temp_release,
+};
+
+static struct miscdevice pcipcwd_temp_miscdev = {
+	.minor =	TEMP_MINOR,
+	.name =		"temperature",
+	.fops =		&pcipcwd_temp_fops,
+};
+
+static struct notifier_block pcipcwd_notifier = {
+	.notifier_call =	pcipcwd_notify_sys,
+};
+
+/*
+ *	Init & exit routines
+ */
+
+static inline void check_temperature_support(void)
+{
+	if (inb_p(pcipcwd_private.io_addr) != 0xF0)
+		pcipcwd_private.supports_temp = 1;
+}
+
+static int __devinit pcipcwd_card_init(struct pci_dev *pdev,
+		const struct pci_device_id *ent)
+{
+	static int cards_found;
+	int ret = -EIO;
+	int got_fw_rev, fw_rev_major, fw_rev_minor;
+	char fw_ver_str[20];
+	char option_switches;
+
+	cards_found++;
+	if (cards_found == 1)
+		printk(KERN_INFO PFX DRIVER_VERSION);
+
+	if (cards_found > 1) {
+		printk(KERN_ERR PFX "This driver only supports 1 device\n");
+		return -ENODEV;
+	}
+
+	if (pci_enable_device(pdev)) {
+		printk(KERN_ERR PFX "Not possible to enable PCI Device\n");
+		return -ENODEV;
+	}
+
+	if (pci_resource_start(pdev, 0) == 0x0000) {
+		printk(KERN_ERR PFX "No I/O-Address for card detected\n");
+		return -ENODEV;
+	}
+
+	pcipcwd_private.pdev = pdev;
+	pcipcwd_private.io_addr = pci_resource_start(pdev, 0);
+
+	if (pci_request_regions(pdev, WATCHDOG_NAME)) {
+		printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
+			(int) pcipcwd_private.io_addr);
+		ret = -EIO;
+		goto err_out_disable_device;
+	}
+
+	/* get the boot_status */
+	pcipcwd_get_status(&pcipcwd_private.boot_status);
+
+	/* clear the "card caused reboot" flag */
+	pcipcwd_clear_status();
+
+	/* disable card */
+	pcipcwd_stop();
+
+	/* Check whether or not the card supports the temperature device */
+	check_temperature_support();
+
+	/* Get the Firmware Version */
+	got_fw_rev = send_command(CMD_GET_FIRMWARE_VERSION, &fw_rev_major, &fw_rev_minor);
+	if (got_fw_rev) {
+		sprintf(fw_ver_str, "%u.%02u", fw_rev_major, fw_rev_minor);
+	} else {
+		sprintf(fw_ver_str, "<card no answer>");
+	}
+
+	/* Get switch settings */
+	option_switches = inb_p(pcipcwd_private.io_addr + 3);
+
+	printk(KERN_INFO PFX "Found card at port 0x%04x (Firmware: %s) %s temp option\n",
+		(int) pcipcwd_private.io_addr, fw_ver_str,
+		(pcipcwd_private.supports_temp ? "with" : "without"));
+
+	printk(KERN_INFO PFX "Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
+		option_switches,
+		((option_switches & 0x10) ? "ON" : "OFF"),
+		((option_switches & 0x08) ? "ON" : "OFF"));
+
+	if (pcipcwd_private.boot_status & WDIOF_CARDRESET)
+		printk(KERN_INFO PFX "Previous reset was caused by the Watchdog card\n");
+
+	if (pcipcwd_private.boot_status & WDIOF_OVERHEAT)
+		printk(KERN_INFO PFX "Card sensed a CPU Overheat\n");
+
+	if (pcipcwd_private.boot_status == 0)
+		printk(KERN_INFO PFX "No previous trip detected - Cold boot or reset\n");
+
+	/* Check that the heartbeat value is within it's range ; if not reset to the default */
+	if (heartbeat < 1 || heartbeat > 0xFFFF) {
+		heartbeat = WATCHDOG_HEARTBEAT;
+		printk(KERN_INFO PFX "heartbeat value must be 0<heartbeat<65536, using %d\n",
+			heartbeat);
+	}
+
+	/* Calculate the watchdog's heartbeat */
+	pcipcwd_set_heartbeat(heartbeat);
+
+	ret = register_reboot_notifier(&pcipcwd_notifier);
+	if (ret != 0) {
+		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
+			ret);
+		goto err_out_release_region;
+	}
+
+	ret = misc_register(&pcipcwd_miscdev);
+	if (ret != 0) {
+		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, ret);
+		goto err_out_unregister_reboot;
+	}
+
+	if (pcipcwd_private.supports_temp) {
+		ret = misc_register(&pcipcwd_temp_miscdev);
+		if (ret != 0) {
+			printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+				TEMP_MINOR, ret);
+			goto err_out_misc_deregister;
+		}
+	}
+
+	printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
+		heartbeat, nowayout);
+
+	return 0;
+
+err_out_misc_deregister:
+	misc_deregister(&pcipcwd_miscdev);
+err_out_unregister_reboot:
+	unregister_reboot_notifier(&pcipcwd_notifier);
+err_out_release_region:
+	pci_release_regions(pdev);
+err_out_disable_device:
+	pci_disable_device(pdev);
+	return ret;
+}
+
+static void __devexit pcipcwd_card_exit(struct pci_dev *pdev)
+{
+	/* Stop the timer before we leave */
+	if (!nowayout)
+		pcipcwd_stop();
+
+	/* Deregister */
+	if (pcipcwd_private.supports_temp)
+		misc_deregister(&pcipcwd_temp_miscdev);
+	misc_deregister(&pcipcwd_miscdev);
+	unregister_reboot_notifier(&pcipcwd_notifier);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+}
+
+static struct pci_device_id pcipcwd_pci_tbl[] = {
+	{ PCI_VENDOR_ID_QUICKLOGIC, PCI_DEVICE_ID_WATCHDOG_PCIPCWD,
+		PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0 },			/* End of list */
+};
+MODULE_DEVICE_TABLE(pci, pcipcwd_pci_tbl);
+
+static struct pci_driver pcipcwd_driver = {
+	.name		= WATCHDOG_NAME,
+	.id_table	= pcipcwd_pci_tbl,
+	.probe		= pcipcwd_card_init,
+	.remove		= __devexit_p(pcipcwd_card_exit),
+};
+
+static int __init pcipcwd_init_module(void)
+{
+	spin_lock_init (&pcipcwd_private.io_lock);
+
+	return pci_module_init(&pcipcwd_driver);
+}
+
+static void __exit pcipcwd_cleanup_module(void)
+{
+	pci_unregister_driver(&pcipcwd_driver);
+}
+
+module_init(pcipcwd_init_module);
+module_exit(pcipcwd_cleanup_module);
+
+MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>");
+MODULE_DESCRIPTION("Berkshire PCI-PC Watchdog driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_ALIAS_MISCDEV(TEMP_MINOR);
diff -Nru a/drivers/char/watchdog/sbc60xxwdt.c b/drivers/char/watchdog/sbc60xxwdt.c
--- a/drivers/char/watchdog/sbc60xxwdt.c	Wed Feb 11 22:14:31 2004
+++ b/drivers/char/watchdog/sbc60xxwdt.c	Wed Feb 11 22:14:31 2004
@@ -412,3 +412,4 @@
 MODULE_AUTHOR("Jakob Oestergaard <jakob@unthought.net>");
 MODULE_DESCRIPTION("60xx Single Board Computer Watchdog Timer driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff -Nru a/drivers/char/watchdog/sc520_wdt.c b/drivers/char/watchdog/sc520_wdt.c
--- a/drivers/char/watchdog/sc520_wdt.c	Wed Feb 11 22:14:31 2004
+++ b/drivers/char/watchdog/sc520_wdt.c	Wed Feb 11 22:14:31 2004
@@ -447,3 +447,4 @@
 MODULE_AUTHOR("Scott and Bill Jennings");
 MODULE_DESCRIPTION("Driver for watchdog timer in AMD \"Elan\" SC520 uProcessor");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff -Nru a/drivers/char/watchdog/scx200_wdt.c b/drivers/char/watchdog/scx200_wdt.c
--- a/drivers/char/watchdog/scx200_wdt.c	Wed Feb 11 22:14:31 2004
+++ b/drivers/char/watchdog/scx200_wdt.c	Wed Feb 11 22:14:31 2004
@@ -36,6 +36,7 @@
 MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
 MODULE_DESCRIPTION("NatSemi SCx200 Watchdog Driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
 
 #ifndef CONFIG_WATCHDOG_NOWAYOUT
 #define CONFIG_WATCHDOG_NOWAYOUT 0
diff -Nru a/drivers/char/watchdog/shwdt.c b/drivers/char/watchdog/shwdt.c
--- a/drivers/char/watchdog/shwdt.c	Wed Feb 11 22:14:30 2004
+++ b/drivers/char/watchdog/shwdt.c	Wed Feb 11 22:14:30 2004
@@ -33,6 +33,8 @@
 #include <asm/uaccess.h>
 #include <asm/watchdog.h>
 
+#define PFX "shwdt: "
+
 /*
  * Default clock division ratio is 5.25 msecs. For an additional table of
  * values, consult the asm-sh/watchdog.h. Overload this at module load
@@ -70,7 +72,9 @@
 static char shwdt_expect_close;
 static struct timer_list timer;
 static unsigned long next_heartbeat;
-static int heartbeat = 30;
+
+#define WATCHDOG_HEARTBEAT 30			/* 30 sec default heartbeat */
+static int heartbeat = WATCHDOG_HEARTBEAT;	/* in seconds */
 
 #ifdef CONFIG_WATCHDOG_NOWAYOUT
 static int nowayout = 1;
@@ -87,8 +91,8 @@
 {
 	__u8 csr;
 
-	mod_timer(&timer, next_ping_period(clock_division_ratio));
 	next_heartbeat = jiffies + (heartbeat * HZ);
+	mod_timer(&timer, next_ping_period(clock_division_ratio));
 
 	csr = sh_wdt_read_csr();
 	csr |= WTCSR_WT | clock_division_ratio;
@@ -142,6 +146,30 @@
 }
 
 /**
+ * 	sh_wdt_keepalive - Keep the Userspace Watchdog Alive
+ *
+ * 	The Userspace watchdog got a KeepAlive: schedule the next heartbeat.
+ */
+static void sh_wdt_keepalive(void)
+{
+	next_heartbeat = jiffies + (heartbeat * HZ);
+}
+
+/**
+ * 	sh_wdt_set_heartbeat - Set the Userspace Watchdog heartbeat
+ *
+ * 	Set the Userspace Watchdog heartbeat
+ */
+static int sh_wdt_set_heartbeat(int t)
+{
+	if ((t < 1) || (t > 3600)) /* arbitrary upper limit */
+		return -EINVAL;
+
+	heartbeat = t;
+	return 0;
+}
+
+/**
  * 	sh_wdt_ping - Ping the Watchdog
  *
  *	@data: Unused
@@ -160,6 +188,8 @@
 		sh_wdt_write_cnt(0);
 
 		mod_timer(&timer, next_ping_period(clock_division_ratio));
+	} else {
+		printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
 	}
 }
 
@@ -193,11 +223,11 @@
  */
 static int sh_wdt_close(struct inode *inode, struct file *file)
 {
-	if (!nowayout && shwdt_expect_close == 42) {
+	if (shwdt_expect_close == 42) {
 		sh_wdt_stop();
 	} else {
-		printk(KERN_CRIT "shwdt: Unexpected close, not stopping watchdog!\n");
-		next_heartbeat = jiffies + (heartbeat * HZ);
+		printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+		sh_wdt_keepalive();
 	}
 
 	clear_bit(0, &shwdt_is_open);
@@ -224,18 +254,20 @@
 		return -ESPIPE;
 
 	if (count) {
-		size_t i;
+		if (!nowayout) {
+			size_t i;
 
-		shwdt_expect_close = 0;
+			shwdt_expect_close = 0;
 
-		for (i = 0; i != count; i++) {
-			char c;
-			if (get_user(c, buf + i))
-				return -EFAULT;
-			if (c == 'V')
-				shwdt_expect_close = 42;
+			for (i = 0; i != count; i++) {
+				char c;
+				if (get_user(c, buf + i))
+					return -EFAULT;
+				if (c == 'V')
+					shwdt_expect_close = 42;
+			}
 		}
-		next_heartbeat = jiffies + (heartbeat * HZ);
+		sh_wdt_keepalive();
 	}
 
 	return count;
@@ -255,38 +287,32 @@
 static int sh_wdt_ioctl(struct inode *inode, struct file *file,
 			unsigned int cmd, unsigned long arg)
 {
-	int new_timeout;
+	int new_heartbeat;
+	int options, retval = -EINVAL;
 
 	switch (cmd) {
 		case WDIOC_GETSUPPORT:
-			if (copy_to_user((struct watchdog_info *)arg,
+			return copy_to_user((struct watchdog_info *)arg,
 					  &sh_wdt_info,
-					  sizeof(sh_wdt_info))) {
-				return -EFAULT;
-			}
-
-			break;
+					  sizeof(sh_wdt_info)) ? -EFAULT : 0;
 		case WDIOC_GETSTATUS:
 		case WDIOC_GETBOOTSTATUS:
 			return put_user(0, (int *)arg);
 		case WDIOC_KEEPALIVE:
-			next_heartbeat = jiffies + (heartbeat * HZ);
-
-			break;
+			sh_wdt_keepalive();
+			return 0;
 		case WDIOC_SETTIMEOUT:
-			if (get_user(new_timeout, (int *)arg))
+			if (get_user(new_heartbeat, (int *)arg))
 				return -EFAULT;
-			if (new_timeout < 1 || new_timeout > 3600) /* arbitrary upper limit */
+
+			if (sh_wdt_set_heartbeat(new_heartbeat))
 				return -EINVAL;
-			heartbeat = new_timeout;
-			next_heartbeat = jiffies + (heartbeat * HZ);
+
+			sh_wdt_keepalive();
 			/* Fall */
 		case WDIOC_GETTIMEOUT:
 			return put_user(heartbeat, (int *)arg);
 		case WDIOC_SETOPTIONS:
-		{
-			int options, retval = -EINVAL;
-
 			if (get_user(options, (int *)arg))
 				return -EFAULT;
 
@@ -301,7 +327,6 @@
 			}
 
 			return retval;
-		}
 		default:
 			return -ENOIOCTLCMD;
 	}
@@ -346,7 +371,6 @@
 
 static struct notifier_block sh_wdt_notifier = {
 	.notifier_call		= sh_wdt_notify_sys,
-	.priority		= 0,
 };
 
 static struct miscdevice sh_wdt_miscdev = {
@@ -363,21 +387,42 @@
  */
 static int __init sh_wdt_init(void)
 {
-	if (misc_register(&sh_wdt_miscdev)) {
-		printk(KERN_ERR "shwdt: Can't register misc device\n");
-		return -EINVAL;
+	int rc;
+
+	if ((clock_division_ratio < 0x5) || (clock_division_ratio > 0x7)) {
+		clock_division_ratio = WTCSR_CKS_4096;
+		printk(KERN_INFO PFX "clock_division_ratio value must be 0x5<=x<=0x7, using %d\n",
+			clock_division_ratio);
 	}
 
-	if (register_reboot_notifier(&sh_wdt_notifier)) {
-		printk(KERN_ERR "shwdt: Can't register reboot notifier\n");
-		misc_deregister(&sh_wdt_miscdev);
-		return -EINVAL;
+	if (sh_wdt_set_heartbeat(heartbeat))
+	{
+		heartbeat = WATCHDOG_HEARTBEAT;
+		printk(KERN_INFO PFX "heartbeat value must be 1<=x<=3600, using %d\n",
+			heartbeat);
 	}
 
 	init_timer(&timer);
 	timer.function = sh_wdt_ping;
 	timer.data = 0;
 
+	rc = register_reboot_notifier(&sh_wdt_notifier);
+	if (rc) {
+		printk(KERN_ERR PFX "Can't register reboot notifier (err=%d)\n", rc);
+		return rc;
+	}
+
+	rc = misc_register(&sh_wdt_miscdev)
+	if (rc) {
+		printk(KERN_ERR PFX "Can't register miscdev on minor=%d (err=%d)\n",
+			sh_wdt_miscdev.minor, rc);
+		unregister_reboot_notifier(&sh_wdt_notifier);
+		return rc;
+	}
+
+	printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
+		heartbeat, nowayout);
+
 	return 0;
 }
 
@@ -389,16 +434,20 @@
  */
 static void __exit sh_wdt_exit(void)
 {
-	unregister_reboot_notifier(&sh_wdt_notifier);
 	misc_deregister(&sh_wdt_miscdev);
+	unregister_reboot_notifier(&sh_wdt_notifier);
 }
 
 MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
 MODULE_DESCRIPTION("SuperH watchdog driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
 
 module_param(clock_division_ratio, int, 0);
 MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). Defaults to 0x7.");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<=heartbeat<=3600, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
 
 module_param(nowayout, int, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
diff -Nru a/drivers/char/watchdog/softdog.c b/drivers/char/watchdog/softdog.c
--- a/drivers/char/watchdog/softdog.c	Wed Feb 11 22:14:31 2004
+++ b/drivers/char/watchdog/softdog.c	Wed Feb 11 22:14:31 2004
@@ -231,3 +231,8 @@
 
 module_init(watchdog_init);
 module_exit(watchdog_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("Software Watchdog Device Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff -Nru a/drivers/char/watchdog/wafer5823wdt.c b/drivers/char/watchdog/wafer5823wdt.c
--- a/drivers/char/watchdog/wafer5823wdt.c	Wed Feb 11 22:14:31 2004
+++ b/drivers/char/watchdog/wafer5823wdt.c	Wed Feb 11 22:14:31 2004
@@ -330,5 +330,6 @@
 MODULE_AUTHOR("Justin Cormack");
 MODULE_DESCRIPTION("ICP Wafer 5823 Single Board Computer WDT driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
 
 /* end of wafer5823wdt.c */
diff -Nru a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c
--- a/drivers/cpufreq/cpufreq_userspace.c	Wed Feb 11 22:14:30 2004
+++ b/drivers/cpufreq/cpufreq_userspace.c	Wed Feb 11 22:14:30 2004
@@ -2,7 +2,7 @@
  *  linux/drivers/cpufreq/cpufreq_userspace.c
  *
  *  Copyright (C)  2001 Russell King
- *            (C)  2002 - 2003 Dominik Brodowski <linux@brodo.de>
+ *            (C)  2002 - 2004 Dominik Brodowski <linux@brodo.de>
  *
  * 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
@@ -112,7 +112,14 @@
 	if (freq > cpu_max_freq[cpu])
 		freq = cpu_max_freq[cpu];
 
-	ret = cpufreq_driver_target(&current_policy[cpu], freq, 
+	/*
+	 * We're safe from concurrent calls to ->target() here
+	 * as we hold the userspace_sem lock. If we were calling
+	 * cpufreq_driver_target, a deadlock situation might occur:
+	 * A: cpufreq_set (lock userspace_sem) -> cpufreq_driver_target(lock policy->lock)
+	 * B: cpufreq_set_policy(lock policy->lock) -> __cpufreq_governor -> cpufreq_governor_userspace (lock userspace_sem)
+	 */
+	ret = __cpufreq_driver_target(&current_policy[cpu], freq, 
 	      CPUFREQ_RELATION_L);
 
  err:
diff -Nru a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c
--- a/drivers/i2c/busses/i2c-keywest.c	Wed Feb 11 22:14:31 2004
+++ b/drivers/i2c/busses/i2c-keywest.c	Wed Feb 11 22:14:31 2004
@@ -74,14 +74,7 @@
 
 #include "i2c-keywest.h"
 
-/* Currently, we don't deal with the weird interrupt cascade of the G5
- * machines with the ppc64 kernel, so use Polled mode on these
- */
-#ifdef CONFIG_PPC64
-#define POLLED_MODE
-#else
 #undef POLLED_MODE
-#endif
 
 /* Some debug macros */
 #define WRONG_STATE(name) do {\
diff -Nru a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
--- a/drivers/ide/ppc/pmac.c	Wed Feb 11 22:14:30 2004
+++ b/drivers/ide/ppc/pmac.c	Wed Feb 11 22:14:30 2004
@@ -39,13 +39,16 @@
 #include <asm/io.h>
 #include <asm/dbdma.h>
 #include <asm/ide.h>
-#include <asm/mediabay.h>
 #include <asm/pci-bridge.h>
 #include <asm/machdep.h>
 #include <asm/pmac_feature.h>
 #include <asm/sections.h>
 #include <asm/irq.h>
 
+#ifndef CONFIG_PPC64
+#include <asm/mediabay.h>
+#endif
+
 #include "ide-timing.h"
 
 extern void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq);
@@ -1183,6 +1186,7 @@
 	/* Make sure we have sane timings */
 	sanitize_timings(pmif);
 
+#ifndef CONFIG_PPC64
 	/* XXX FIXME: Media bay stuff need re-organizing */
 	if (np->parent && np->parent->name
 	    && strcasecmp(np->parent->name, "media-bay") == 0) {
@@ -1198,7 +1202,9 @@
 		 * units, I keep the old way
 		 */
 		ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, 0, 1);
-	} else {
+	} else
+#endif
+	{
  		/* This is necessary to enable IDE when net-booting */
 		ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 1);
 		ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 1);
@@ -1238,9 +1244,9 @@
 		hwif->led_act = pmu_hd_kick_blink;
 #endif
 
-	printk(KERN_INFO "ide%d: Found Apple %s controller, bus ID %d%s\n",
-			hwif->index, model_name[pmif->kind], pmif->aapl_bus_id,
-			pmif->mediabay ? " (mediabay)" : "");
+	printk(KERN_INFO "ide%d: Found Apple %s controller, bus ID %d%s, irq %d\n",
+	       hwif->index, model_name[pmif->kind], pmif->aapl_bus_id,
+	       pmif->mediabay ? " (mediabay)" : "", hwif->irq);
 			
 #ifdef CONFIG_PMAC_PBOOK
 	if (pmif->mediabay && check_media_bay_by_base(pmif->regbase, MB_CD) == 0)
@@ -1447,7 +1453,12 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 	pmif->dma_regs = (volatile struct dbdma_regs*)(base + 0x1000);
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */	
-	pmif->irq = pdev->irq;
+
+	/* We use the OF node irq mapping */
+	if (np->n_intrs == 0)
+		pmif->irq = pdev->irq;
+	else
+		pmif->irq = np->intrs[0].line;
 
 	pci_set_drvdata(pdev, hwif);
 
diff -Nru a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
--- a/drivers/macintosh/Kconfig	Wed Feb 11 22:14:31 2004
+++ b/drivers/macintosh/Kconfig	Wed Feb 11 22:14:31 2004
@@ -4,7 +4,7 @@
 # we want to change this to something like CONFIG_SYSCTRL_CUDA/PMU
 config ADB_CUDA
 	bool "Support for CUDA based PowerMacs"
-	depends on PPC_PMAC && !POWER4
+	depends on PPC_PMAC && !PPC_PMAC64
 	help
 	  This provides support for CUDA based Power Macintosh systems.  This
 	  includes most OldWorld PowerMacs, the first generation iMacs, the
@@ -69,7 +69,7 @@
 
 config MAC_FLOPPY
 	bool "Support for PowerMac floppy"
-	depends on PPC_PMAC && !POWER4
+	depends on PPC_PMAC && !PPC_PMAC64
 	help
 	  If you have a SWIM-3 (Super Woz Integrated Machine 3; from Apple)
 	  floppy controller, say Y here. Most commonly found in PowerMacs.
@@ -93,7 +93,7 @@
 
 config ADB_MACIO
 	bool "Include MacIO (CHRP) ADB driver"
-	depends on ADB && !POWER4
+	depends on ADB && PPC_PMAC && !PPC_PMAC64
 	help
 	  Say Y here to include direct support for the ADB controller in the
 	  Hydra chip used on PowerPC Macintoshes of the CHRP type.  (The Hydra
@@ -129,14 +129,14 @@
 
 config THERM_WINDTUNNEL
 	tristate "Support for thermal management on Windtunnel G4s"
-	depends on I2C && I2C_KEYWEST && !POWER4
+	depends on I2C && I2C_KEYWEST && PPC_PMAC && !PPC_PMAC64
 	help
 	  This driver provides some thermostat and fan control for the desktop
 	  G4 "Windtunnel"
 
 config THERM_ADT7467
 	tristate "Support for thermal mgmnt on laptops with ADT 7467 chipset"
-	depends on I2C && I2C_KEYWEST && !POWER4
+	depends on I2C && I2C_KEYWEST && PPC_PMAC && !PPC_PMAC64
 	help
 	  This driver provides some thermostat and fan control for the
           iBook G4, and the ATI based aluminium PowerBooks, allowing slighlty
@@ -144,7 +144,7 @@
 
 config THERM_PM72
 	tristate "Support for thermal management on PowerMac G5"
-	depends on I2C && I2C_KEYWEST && POWER4
+	depends on I2C && I2C_KEYWEST && PPC_PMAC64
 	help
 	  This driver provides thermostat and fan control for the desktop
 	  G5 machines. 
diff -Nru a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
--- a/drivers/macintosh/adb.c	Wed Feb 11 22:14:31 2004
+++ b/drivers/macintosh/adb.c	Wed Feb 11 22:14:31 2004
@@ -40,9 +40,9 @@
 #include <asm/semaphore.h>
 #ifdef CONFIG_PPC
 #include <asm/prom.h>
-#include <asm/hydra.h>
 #endif
 
+
 EXPORT_SYMBOL(adb_controller);
 EXPORT_SYMBOL(adb_client_list);
 
@@ -290,7 +290,7 @@
 	struct adb_driver *driver;
 	int i;
 
-#ifdef CONFIG_PPC
+#ifdef CONFIG_PPC32
 	if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
 		return 0;
 #endif
diff -Nru a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c
--- a/drivers/macintosh/macio_asic.c	Wed Feb 11 22:14:30 2004
+++ b/drivers/macintosh/macio_asic.c	Wed Feb 11 22:14:30 2004
@@ -539,6 +539,9 @@
 	if (np == NULL)
 		return -ENODEV;
 
+	/* This assumption is wrong, fix that here for now until I fix the arch */
+	of_node_get(np);
+
 	/* We also assume that pmac_feature will have done a get() on nodes stored
 	 * in the macio chips array
 	 */
diff -Nru a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
--- a/drivers/macintosh/via-pmu.c	Wed Feb 11 22:14:31 2004
+++ b/drivers/macintosh/via-pmu.c	Wed Feb 11 22:14:31 2004
@@ -374,7 +374,9 @@
 	printk(KERN_INFO "PMU driver %d initialized for %s, firmware: %02x\n",
 	       PMU_DRIVER_VERSION, pbook_type[pmu_kind], pmu_version);
 	       
+#ifndef CONFIG_PPC64
 	sys_ctrler = SYS_CTRLER_PMU;
+#endif
 	
 	return 1;
 }
@@ -459,7 +461,9 @@
 	if (vias == NULL)
 		return -ENODEV;
 
+#ifndef CONFIG_PPC64
 	request_OF_resource(vias, 0, NULL);
+#endif
 #ifdef CONFIG_PMAC_BACKLIGHT
 	/* Enable backlight */
 	register_backlight_controller(&pmu_backlight_controller, NULL, "pmu");
@@ -590,6 +594,7 @@
 	return pmu_kind;
 }
 
+#ifndef CONFIG_PPC64
 static inline void wakeup_decrementer(void)
 {
 	set_dec(tb_ticks_per_jiffy);
@@ -598,6 +603,7 @@
 	 */
 	last_jiffy_stamp(0) = tb_last_stamp = get_tbl();
 }
+#endif
 
 static void pmu_set_server_mode(int server_mode)
 {
@@ -1389,7 +1395,7 @@
 			}
 			pmu_done(req);
 		} else {
-#ifdef CONFIG_XMON
+#if defined(CONFIG_XMON) && !defined(CONFIG_PPC64)
 			if (len == 4 && data[1] == 0x2c) {
 				extern int xmon_wants_key, xmon_adb_keycode;
 				if (xmon_wants_key) {
@@ -1397,7 +1403,7 @@
 					return;
 				}
 			}
-#endif /* CONFIG_XMON */
+#endif /* defined(CONFIG_XMON) && !defined(CONFIG_PPC64) */
 #ifdef CONFIG_ADB
 			/*
 			 * XXX On the [23]400 the PMU gives us an up
diff -Nru a/drivers/md/dm.c b/drivers/md/dm.c
--- a/drivers/md/dm.c	Wed Feb 11 22:14:31 2004
+++ b/drivers/md/dm.c	Wed Feb 11 22:14:31 2004
@@ -674,7 +674,7 @@
 	bdev = bdget_disk(disk, 0);
 	if (bdev) {
 		down(&bdev->bd_inode->i_sem);
-		i_size_write(bdev->bd_inode, size << SECTOR_SHIFT);
+		i_size_write(bdev->bd_inode, (loff_t)size << SECTOR_SHIFT);
 		up(&bdev->bd_inode->i_sem);
 		bdput(bdev);
 	}
diff -Nru a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
--- a/drivers/pci/pci-sysfs.c	Wed Feb 11 22:14:31 2004
+++ b/drivers/pci/pci-sysfs.c	Wed Feb 11 22:14:31 2004
@@ -180,4 +180,7 @@
 	device_create_file (dev, &dev_attr_irq);
 	device_create_file (dev, &dev_attr_resource);
 	sysfs_create_bin_file(&dev->kobj, &pci_config_attr);
+
+	/* add platform-specific attributes */
+	pcibios_add_platform_entries(pdev);
 }
diff -Nru a/drivers/scsi/sr.c b/drivers/scsi/sr.c
--- a/drivers/scsi/sr.c	Wed Feb 11 22:14:30 2004
+++ b/drivers/scsi/sr.c	Wed Feb 11 22:14:30 2004
@@ -798,10 +798,9 @@
 	if ((buffer[n + 2] & 0x8) == 0)
 		/* not a DVD drive */
 		cd->cdi.mask |= CDC_DVD;
-	if ((buffer[n + 3] & 0x20) == 0) {
+	if ((buffer[n + 3] & 0x20) == 0) 
 		/* can't write DVD-RAM media */
 		cd->cdi.mask |= CDC_DVD_RAM;
-	} else
 	if ((buffer[n + 3] & 0x10) == 0)
 		/* can't write DVD-R media */
 		cd->cdi.mask |= CDC_DVD_R;
diff -Nru a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
--- a/drivers/serial/pmac_zilog.c	Wed Feb 11 22:14:30 2004
+++ b/drivers/serial/pmac_zilog.c	Wed Feb 11 22:14:30 2004
@@ -68,6 +68,10 @@
 
 #include "pmac_zilog.h"
 
+#if defined(CONFIG_SERIAL_PMACZILOG_CONSOLE) && defined(CONFIG_PPC64)
+#define HAS_SCCDBG
+extern int sccdbg;
+#endif
 
 /* Not yet implemented */
 #undef HAS_DBDMA
@@ -170,7 +174,6 @@
  */
 static void pmz_maybe_update_regs(struct uart_pmac_port *up)
 {
-#if 1
        	if (!ZS_REGS_HELD(up)) {
 		if (ZS_TX_ACTIVE(up)) {
 			up->flags |= PMACZILOG_FLAG_REGS_HELD;
@@ -179,10 +182,6 @@
 			pmz_load_zsregs(up, up->curregs);
 		}
 	}
-#else
-       	pr_debug("pmz: maybe_update_regs: updating\n");
-	 pmz_load_zsregs(up, up->curregs);
-#endif
 }
 
 static void pmz_receive_chars(struct uart_pmac_port *up, struct pt_regs *regs)
@@ -205,22 +204,18 @@
 			zssync(up);
 		}
 
-		ch = read_zsreg(up, R0);
-
-		/* This funny hack depends upon BRK_ABRT not interfering
-		 * with the other bits we care about in R1.
-		 */
-		if (ch & BRK_ABRT)
-			r1 |= BRK_ABRT;
-
 		ch = read_zsdata(up);
 		ch &= up->parity_mask;
+		if (ch == 0 && up->prev_status & BRK_ABRT) {
+			r1 |= BRK_ABRT;
+			printk("rx break\n");
+		}
 
 		/* A real serial line, record the character and status.  */
 		*tty->flip.char_buf_ptr = ch;
 		*tty->flip.flag_buf_ptr = TTY_NORMAL;
 		up->port.icount.rx++;
-		if (r1 & (BRK_ABRT | PAR_ERR | Rx_OVR | CRC_ERR)) {
+		if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR | BRK_ABRT)) {
 			if (r1 & BRK_ABRT) {
 				r1 &= ~(PAR_ERR | CRC_ERR);
 				up->port.icount.brk++;
@@ -274,6 +269,15 @@
 	write_zsreg(up, R0, RES_EXT_INT);
 	zssync(up);
 
+#ifdef HAS_SCCDBG
+	if (sccdbg && (status & BRK_ABRT) && !(up->prev_status & BRK_ABRT)) {
+#ifdef CONFIG_XMON
+		extern void xmon(struct pt_regs *);
+		xmon(regs);
+#endif
+	}
+#endif /* HAS_SCCDBG */
+
 	if (ZS_WANTS_MODEM_STATUS(up)) {
 		if (status & SYNC_HUNT)
 			up->port.icount.dsr++;
@@ -383,10 +387,10 @@
 		write_zsreg(up_a, R0, RES_H_IUS);
 		zssync(up_a);		
 		pr_debug("pmz: irq channel A: %x\n", r3);
-		if (r3 & CHARxIP)
-			pmz_receive_chars(up_a, regs);
        		if (r3 & CHAEXT)
        			pmz_status_handle(up_a, regs);
+		if (r3 & CHARxIP)
+			pmz_receive_chars(up_a, regs);
        		if (r3 & CHATxIP)
        			pmz_transmit_chars(up_a);
 	        rc = IRQ_HANDLED;
@@ -398,10 +402,10 @@
 		write_zsreg(up_b, R0, RES_H_IUS);
 		zssync(up_b);
 		pr_debug("pmz: irq channel B: %x\n", r3);
-       	       	if (r3 & CHBRxIP)
-       			pmz_receive_chars(up_b, regs);
        		if (r3 & CHBEXT)
        			pmz_status_handle(up_b, regs);
+       	       	if (r3 & CHBRxIP)
+       			pmz_receive_chars(up_b, regs);
        		if (r3 & CHBTxIP)
        			pmz_transmit_chars(up_b);
 	       	rc = IRQ_HANDLED;
@@ -575,15 +579,12 @@
 
 /* 
  * Enable modem status change interrupts
- * The port lock is not held.
+ * The port lock is held.
  */
 static void pmz_enable_ms(struct uart_port *port)
 {
 	struct uart_pmac_port *up = to_pmz(port);
 	unsigned char new_reg;
-	unsigned long flags;
-
-	spin_lock_irqsave(&port->lock, flags);
 
 	new_reg = up->curregs[R15] | (DCDIE | SYNCIE | CTSIE);
 	if (new_reg != up->curregs[R15]) {
@@ -592,8 +593,6 @@
 		/* NOTE: Not subject to 'transmitter active' rule.  */ 
 		write_zsreg(up, R15, up->curregs[R15]);
 	}
-
-	spin_unlock_irqrestore(&port->lock, flags);
 }
 
 /* 
@@ -765,7 +764,7 @@
 	up->curregs[R9] |= NV | MIE;
 
 	up->curregs[R1] |= EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
-	//	pmz_maybe_update_regs(up);
+       	pmz_maybe_update_regs(up);
 
 	return pwr_delay;
 }
@@ -1051,10 +1050,13 @@
 
 	pmz_convert_to_zs(up, termios->c_cflag, termios->c_iflag, baud);
 
-	if (UART_ENABLE_MS(&up->port, termios->c_cflag))
+	if (UART_ENABLE_MS(&up->port, termios->c_cflag)) {
+		up->curregs[R15] |= DCDIE | SYNCIE | CTSIE;
 		up->flags |= PMACZILOG_FLAG_MODEM_STATUS;
-	else
+	} else {
+		up->curregs[R15] &= ~(DCDIE | SYNCIE | CTSIE);
 		up->flags &= ~PMACZILOG_FLAG_MODEM_STATUS;
+	}
 
 	/* set the irda codec to the right rate */
 	if (ZS_IS_IRDA(up))
@@ -1120,7 +1122,7 @@
  * Unlike sunzilog, we don't need to pre-init the spinlock as we don't
  * register our console before uart_add_one_port() is called
  */
-static int __init pmz_setup_port(struct uart_pmac_port *up)
+static int __init pmz_init_port(struct uart_pmac_port *up)
 {
 	struct device_node *np = up->node;
 	char *conn;
@@ -1225,13 +1227,6 @@
 {
 	struct device_node *np;
 
-	if (up->flags & PMACZILOG_FLAG_RSRC_REQUESTED) {
-		release_OF_resource(up->node, 0);
-		if (ZS_HAS_DMA(up)) {
-			release_OF_resource(up->node, up->node->n_addrs - 2);
-			release_OF_resource(up->node, up->node->n_addrs - 1);
-		}
-	}
 	iounmap((void *)up->control_reg);
 	np = up->node;
 	up->node = NULL;
@@ -1335,9 +1330,9 @@
 		/*
 		 * Setup the ports for real
 		 */
-		rc = pmz_setup_port(&pmz_ports[count]);
+		rc = pmz_init_port(&pmz_ports[count]);
 		if (rc == 0)
-			rc = pmz_setup_port(&pmz_ports[count+1]);
+			rc = pmz_init_port(&pmz_ports[count+1]);
 		if (rc != 0) {
 			of_node_put(node_a);
 			of_node_put(node_b);
@@ -1581,6 +1576,8 @@
 	/* Probe ports */
 	pmz_probe();
 
+#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
+#endif
 	/* TODO: Autoprobe console based on OF */
 	/* pmz_console.index = i; */
 	register_console(&pmz_console);
diff -Nru a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
--- a/drivers/video/console/fbcon.c	Wed Feb 11 22:14:31 2004
+++ b/drivers/video/console/fbcon.c	Wed Feb 11 22:14:31 2004
@@ -1826,9 +1826,11 @@
 	vc->vc_font.height = h;
 	if (vc->vc_hi_font_mask && cnt == 256) {
 		vc->vc_hi_font_mask = 0;
-		if (vc->vc_can_do_color)
+		if (vc->vc_can_do_color) {
 			vc->vc_complement_mask >>= 1;
-
+			vc->vc_s_complement_mask >>= 1;
+		}
+			
 		/* ++Edmund: reorder the attribute bits */
 		if (vc->vc_can_do_color) {
 			unsigned short *cp =
@@ -1847,9 +1849,11 @@
 		}
 	} else if (!vc->vc_hi_font_mask && cnt == 512) {
 		vc->vc_hi_font_mask = 0x100;
-		if (vc->vc_can_do_color)
+		if (vc->vc_can_do_color) {
 			vc->vc_complement_mask <<= 1;
-
+			vc->vc_s_complement_mask <<= 1;
+		}
+			
 		/* ++Edmund: reorder the attribute bits */
 		{
 			unsigned short *cp =
diff -Nru a/drivers/video/fbmon.c b/drivers/video/fbmon.c
--- a/drivers/video/fbmon.c	Wed Feb 11 22:14:31 2004
+++ b/drivers/video/fbmon.c	Wed Feb 11 22:14:31 2004
@@ -32,6 +32,7 @@
 #ifdef CONFIG_PPC_OF
 #include <linux/pci.h>
 #include <asm/prom.h>
+#include <asm/pci-bridge.h>
 #endif
 #include <video/edid.h>
 #include "edid.h"
diff -Nru a/drivers/video/offb.c b/drivers/video/offb.c
--- a/drivers/video/offb.c	Wed Feb 11 22:14:31 2004
+++ b/drivers/video/offb.c	Wed Feb 11 22:14:31 2004
@@ -247,7 +247,7 @@
 {
 	struct device_node *dp;
 	unsigned int dpy;
-#ifdef CONFIG_BOOTX_TEXT
+#if defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32)
 	struct device_node *displays = find_type_devices("display");
 	struct device_node *macos_display = NULL;
 
@@ -323,7 +323,7 @@
 			     boot_infos->dispDeviceDepth,
 			     boot_infos->dispDeviceRowBytes, addr, NULL);
 	}
-#endif
+#endif /* defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32) */
 
 	for (dpy = 0; dpy < prom_num_displays; dpy++) {
 		if ((dp = find_path_device(prom_display_paths[dpy])))
diff -Nru a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
--- a/drivers/video/riva/fbdev.c	Wed Feb 11 22:14:31 2004
+++ b/drivers/video/riva/fbdev.c	Wed Feb 11 22:14:31 2004
@@ -44,6 +44,10 @@
 #ifdef CONFIG_MTRR
 #include <asm/mtrr.h>
 #endif
+#ifdef CONFIG_PPC_OF
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#endif
 
 #include "rivafb.h"
 #include "nvreg.h"
diff -Nru a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
--- a/fs/jfs/jfs_logmgr.c	Wed Feb 11 22:14:31 2004
+++ b/fs/jfs/jfs_logmgr.c	Wed Feb 11 22:14:31 2004
@@ -2230,8 +2230,7 @@
 	} while (!jfs_stop_threads);
 
 	jfs_info("jfsIOWait being killed!");
-	complete(&jfsIOwait);
-	return 0;
+	complete_and_exit(&jfsIOwait, 0);
 }
 
 /*
diff -Nru a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
--- a/fs/jfs/jfs_txnmgr.c	Wed Feb 11 22:14:31 2004
+++ b/fs/jfs/jfs_txnmgr.c	Wed Feb 11 22:14:31 2004
@@ -2842,8 +2842,7 @@
 		jfs_err("jfs_lazycommit being killed w/pending transactions!");
 	else
 		jfs_info("jfs_lazycommit being killed\n");
-	complete(&jfsIOwait);
-	return 0;
+	complete_and_exit(&jfsIOwait, 0);
 }
 
 void txLazyUnlock(struct tblock * tblk)
@@ -3044,8 +3043,7 @@
 	} while (!jfs_stop_threads);
 
 	jfs_info("jfs_sync being killed");
-	complete(&jfsIOwait);
-	return 0;
+	complete_and_exit(&jfsIOwait, 0);
 }
 
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_JFS_DEBUG)
diff -Nru a/fs/jfs/namei.c b/fs/jfs/namei.c
--- a/fs/jfs/namei.c	Wed Feb 11 22:14:31 2004
+++ b/fs/jfs/namei.c	Wed Feb 11 22:14:31 2004
@@ -1232,7 +1232,7 @@
 	old_ip->i_ctime = CURRENT_TIME;
 	mark_inode_dirty(old_ip);
 
-	new_dir->i_ctime = CURRENT_TIME;
+	new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
 	mark_inode_dirty(new_dir);
 
 	/* Build list of inodes modified by this transaction */
@@ -1244,7 +1244,7 @@
 
 	if (old_dir != new_dir) {
 		iplist[ipcount++] = new_dir;
-		old_dir->i_ctime = CURRENT_TIME;
+		old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
 		mark_inode_dirty(old_dir);
 	}
 
diff -Nru a/fs/namei.c b/fs/namei.c
--- a/fs/namei.c	Wed Feb 11 22:14:30 2004
+++ b/fs/namei.c	Wed Feb 11 22:14:30 2004
@@ -237,30 +237,34 @@
  * except for the cases where we don't hold i_writecount yet. Then we need to
  * use {get,deny}_write_access() - these functions check the sign and refuse
  * to do the change if sign is wrong. Exclusion between them is provided by
- * spinlock (arbitration_lock) and I'll rip the second arsehole to the first
- * who will try to move it in struct inode - just leave it here.
+ * the inode->i_lock spinlock.
  */
-static spinlock_t arbitration_lock = SPIN_LOCK_UNLOCKED;
+
 int get_write_access(struct inode * inode)
 {
-	spin_lock(&arbitration_lock);
+	spin_lock(&inode->i_lock);
 	if (atomic_read(&inode->i_writecount) < 0) {
-		spin_unlock(&arbitration_lock);
+		spin_unlock(&inode->i_lock);
 		return -ETXTBSY;
 	}
 	atomic_inc(&inode->i_writecount);
-	spin_unlock(&arbitration_lock);
+	spin_unlock(&inode->i_lock);
+
 	return 0;
 }
+
 int deny_write_access(struct file * file)
 {
-	spin_lock(&arbitration_lock);
-	if (atomic_read(&file->f_dentry->d_inode->i_writecount) > 0) {
-		spin_unlock(&arbitration_lock);
+	struct inode *inode = file->f_dentry->d_inode;
+
+	spin_lock(&inode->i_lock);
+	if (atomic_read(&inode->i_writecount) > 0) {
+		spin_unlock(&inode->i_lock);
 		return -ETXTBSY;
 	}
-	atomic_dec(&file->f_dentry->d_inode->i_writecount);
-	spin_unlock(&arbitration_lock);
+	atomic_dec(&inode->i_writecount);
+	spin_unlock(&inode->i_lock);
+
 	return 0;
 }
 
diff -Nru a/fs/smbfs/proc.c b/fs/smbfs/proc.c
--- a/fs/smbfs/proc.c	Wed Feb 11 22:14:30 2004
+++ b/fs/smbfs/proc.c	Wed Feb 11 22:14:30 2004
@@ -560,19 +560,19 @@
 
 static u32 smb_filetype_from_mode(int mode)
 {
-	if (mode & S_IFREG)
+	if (S_ISREG(mode))
 		return UNIX_TYPE_FILE;
-	if (mode & S_IFDIR)
+	if (S_ISDIR(mode))
 		return UNIX_TYPE_DIR;
-	if (mode & S_IFLNK)
+	if (S_ISLNK(mode))
 		return UNIX_TYPE_SYMLINK;
-	if (mode & S_IFCHR)
+	if (S_ISCHR(mode))
 		return UNIX_TYPE_CHARDEV;
-	if (mode & S_IFBLK)
+	if (S_ISBLK(mode))
 		return UNIX_TYPE_BLKDEV;
-	if (mode & S_IFIFO)
+	if (S_ISFIFO(mode))
 		return UNIX_TYPE_FIFO;
-	if (mode & S_IFSOCK)
+	if (S_ISSOCK(mode))
 		return UNIX_TYPE_SOCKET;
 	return UNIX_TYPE_UNKNOWN;
 }
diff -Nru a/fs/xfs/linux/xfs_iops.c b/fs/xfs/linux/xfs_iops.c
--- a/fs/xfs/linux/xfs_iops.c	Wed Feb 11 22:14:30 2004
+++ b/fs/xfs/linux/xfs_iops.c	Wed Feb 11 22:14:30 2004
@@ -82,9 +82,14 @@
 
 	va.va_mask = XFS_AT_NLINK|XFS_AT_SIZE|XFS_AT_NBLOCKS;
 	VOP_GETATTR(vp, &va, ATTR_LAZY, NULL, error);
-	ip->i_nlink = va.va_nlink;
-	ip->i_size = va.va_size;
-	ip->i_blocks = va.va_nblocks;
+	if (likely(!error)) {
+		ip->i_nlink = va.va_nlink;
+		ip->i_blocks = va.va_nblocks;
+
+		/* we're under i_sem so i_size can't change under us */
+		if (i_size_read(ip) != va.va_size)
+			i_size_write(ip, va.va_size);
+	}
 }
 
 /*
@@ -536,6 +541,7 @@
 	if (error)
 		return(-error);	/* Positive error up from XFS */
 	if (ia_valid & ATTR_SIZE) {
+		i_size_write(inode, vattr.va_size);
 		error = vmtruncate(inode, attr->ia_size);
 	}
 
diff -Nru a/fs/xfs/linux/xfs_vnode.c b/fs/xfs/linux/xfs_vnode.c
--- a/fs/xfs/linux/xfs_vnode.c	Wed Feb 11 22:14:30 2004
+++ b/fs/xfs/linux/xfs_vnode.c	Wed Feb 11 22:14:30 2004
@@ -213,7 +213,6 @@
 		inode->i_mtime	    = va.va_mtime;
 		inode->i_ctime	    = va.va_ctime;
 		inode->i_atime	    = va.va_atime;
-		i_size_write(inode, va.va_size);
 		if (va.va_xflags & XFS_XFLAG_IMMUTABLE)
 			inode->i_flags |= S_IMMUTABLE;
 		else
diff -Nru a/include/asm-alpha/pci.h b/include/asm-alpha/pci.h
--- a/include/asm-alpha/pci.h	Wed Feb 11 22:14:30 2004
+++ b/include/asm-alpha/pci.h	Wed Feb 11 22:14:30 2004
@@ -208,6 +208,10 @@
 	return 0;
 }
 
+static inline void pcibios_add_platform_entries(struct pci_dev *dev)
+{
+}
+
 #endif /* __KERNEL__ */
 
 /* Values for the `which' argument to sys_pciconfig_iobase.  */
diff -Nru a/include/asm-arm/pci.h b/include/asm-arm/pci.h
--- a/include/asm-arm/pci.h	Wed Feb 11 22:14:30 2004
+++ b/include/asm-arm/pci.h	Wed Feb 11 22:14:30 2004
@@ -186,6 +186,10 @@
 pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
 			 struct resource *res);
 
+static inline void pcibios_add_platform_entries(struct pci_dev *dev)
+{
+}
+
 #endif /* __KERNEL__ */
  
 #endif
diff -Nru a/include/asm-h8300/pci.h b/include/asm-h8300/pci.h
--- a/include/asm-h8300/pci.h	Wed Feb 11 22:14:31 2004
+++ b/include/asm-h8300/pci.h	Wed Feb 11 22:14:31 2004
@@ -22,4 +22,8 @@
 
 #define PCI_DMA_BUS_IS_PHYS	(1)
 
+static inline void pcibios_add_platform_entries(struct pci_dev *dev)
+{
+}
+
 #endif /* _ASM_H8300_PCI_H */
diff -Nru a/include/asm-i386/pci.h b/include/asm-i386/pci.h
--- a/include/asm-i386/pci.h	Wed Feb 11 22:14:31 2004
+++ b/include/asm-i386/pci.h	Wed Feb 11 22:14:31 2004
@@ -89,6 +89,11 @@
 extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
 			       enum pci_mmap_state mmap_state, int write_combine);
 
+
+static inline void pcibios_add_platform_entries(struct pci_dev *dev)
+{
+}
+
 #endif /* __KERNEL__ */
 
 /* implement the pci_ DMA API in terms of the generic device dma_ one */
diff -Nru a/include/asm-ia64/fpswa.h b/include/asm-ia64/fpswa.h
--- a/include/asm-ia64/fpswa.h	Wed Feb 11 22:14:31 2004
+++ b/include/asm-ia64/fpswa.h	Wed Feb 11 22:14:31 2004
@@ -68,4 +68,6 @@
 	efi_fpswa_t	 fpswa;
 } fpswa_interface_t;
 
+extern fpswa_interface_t *fpswa_interface;
+
 #endif /* _ASM_IA64_FPSWA_H */
diff -Nru a/include/asm-ia64/mca.h b/include/asm-ia64/mca.h
--- a/include/asm-ia64/mca.h	Wed Feb 11 22:14:30 2004
+++ b/include/asm-ia64/mca.h	Wed Feb 11 22:14:30 2004
@@ -2,7 +2,7 @@
  * File:	mca.h
  * Purpose:	Machine check handling specific defines
  *
- * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) 1999, 2004 Silicon Graphics, Inc.
  * Copyright (C) Vijay Chander (vijay@engr.sgi.com)
  * Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
  */
@@ -20,23 +20,8 @@
 #include <asm/processor.h>
 #include <asm/mca_asm.h>
 
-/* These are the return codes from all the IA64_MCA specific interfaces */
-typedef	int ia64_mca_return_code_t;
-
-enum {
-	IA64_MCA_SUCCESS	=	0,
-	IA64_MCA_FAILURE	=	1
-};
-
 #define IA64_MCA_RENDEZ_TIMEOUT		(20 * 1000)	/* value in milliseconds - 20 seconds */
 
-#define IA64_CMC_INT_DISABLE		0
-#define IA64_CMC_INT_ENABLE		1
-
-
-typedef u32 int_vector_t;
-typedef u64 millisec_t;
-
 typedef union cmcv_reg_u {
 	u64	cmcv_regval;
 	struct	{
@@ -53,10 +38,6 @@
 #define cmcv_mask		cmcv_reg_s.cmcr_mask
 #define cmcv_vector		cmcv_reg_s.cmcr_vector
 
-
-#define IA64_MCA_UCMC_HANDLER_SIZE	0x10
-#define IA64_INIT_HANDLER_SIZE		0x10
-
 enum {
 	IA64_MCA_RENDEZ_CHECKIN_NOTDONE	=	0x0,
 	IA64_MCA_RENDEZ_CHECKIN_DONE	=	0x1
@@ -85,16 +66,6 @@
 
 } ia64_mc_info_t;
 
-/* Possible rendez states passed from SAL to OS during MCA
- * handoff
- */
-enum {
-	IA64_MCA_RENDEZ_NOT_RQD		=	0x0,
-	IA64_MCA_RENDEZ_DONE_WITHOUT_INIT	=	0x1,
-	IA64_MCA_RENDEZ_DONE_WITH_INIT		=	0x2,
-	IA64_MCA_RENDEZ_FAILURE			=	-1
-};
-
 typedef struct ia64_mca_sal_to_os_state_s {
 	u64		imsto_os_gp;		/* GP of the os registered with the SAL */
 	u64		imsto_pal_proc;		/* PAL_PROC entry point - physical addr */
@@ -136,41 +107,14 @@
 						 */
 } ia64_mca_os_to_sal_state_t;
 
-typedef int (*prfunc_t)(const char * fmt, ...);
-
 extern void ia64_mca_init(void);
 extern void ia64_os_mca_dispatch(void);
 extern void ia64_os_mca_dispatch_end(void);
 extern void ia64_mca_ucmc_handler(void);
 extern void ia64_monarch_init_handler(void);
 extern void ia64_slave_init_handler(void);
-extern irqreturn_t ia64_mca_rendez_int_handler(int,void *,struct pt_regs *);
-extern irqreturn_t ia64_mca_wakeup_int_handler(int,void *,struct pt_regs *);
-extern irqreturn_t ia64_mca_cmc_int_handler(int,void *,struct pt_regs *);
-extern irqreturn_t ia64_mca_cmc_int_caller(int,void *,struct pt_regs *);
-extern irqreturn_t ia64_mca_cpe_int_handler(int,void *,struct pt_regs *);
-extern irqreturn_t ia64_mca_cpe_int_caller(int,void *,struct pt_regs *);
-extern int  ia64_log_print(int,prfunc_t);
 extern void ia64_mca_cmc_vector_setup(void);
 extern int  ia64_mca_check_errors(void);
 
-#define PLATFORM_CALL(fn, args)	printk("Platform call TBD\n")
-
-#define platform_mem_dev_err_print ia64_log_prt_oem_data
-#define platform_pci_bus_err_print ia64_log_prt_oem_data
-#define platform_pci_comp_err_print ia64_log_prt_oem_data
-#define platform_plat_specific_err_print ia64_log_prt_oem_data
-#define platform_host_ctlr_err_print ia64_log_prt_oem_data
-#define platform_plat_bus_err_print ia64_log_prt_oem_data
-
-#undef	MCA_TEST
-
-#undef IA64_MCA_DEBUG_INFO
-
-#if defined(IA64_MCA_DEBUG_INFO)
-# define IA64_MCA_DEBUG(fmt...)	printk(fmt)
-#else
-# define IA64_MCA_DEBUG(fmt...)
-#endif
 #endif /* !__ASSEMBLY__ */
 #endif /* _ASM_IA64_MCA_H */
diff -Nru a/include/asm-ia64/mmu_context.h b/include/asm-ia64/mmu_context.h
--- a/include/asm-ia64/mmu_context.h	Wed Feb 11 22:14:30 2004
+++ b/include/asm-ia64/mmu_context.h	Wed Feb 11 22:14:30 2004
@@ -106,6 +106,7 @@
 		/* re-check, now that we've got the lock: */
 		context = mm->context;
 		if (context == 0) {
+			cpus_clear(mm->cpu_vm_mask);
 			if (ia64_ctx.next >= ia64_ctx.limit)
 				wrap_mmu_context(mm);
 			mm->context = context = ia64_ctx.next++;
@@ -170,6 +171,8 @@
 	do {
 		context = get_mmu_context(mm);
 		MMU_TRACE('A', smp_processor_id(), mm, context);
+		if (!cpu_isset(smp_processor_id(), mm->cpu_vm_mask))
+			cpu_set(smp_processor_id(), mm->cpu_vm_mask);
 		reload_context(context);
 		MMU_TRACE('a', smp_processor_id(), mm, context);
 		/* in the unlikely event of a TLB-flush by another thread, redo the load: */
diff -Nru a/include/asm-ia64/pci.h b/include/asm-ia64/pci.h
--- a/include/asm-ia64/pci.h	Wed Feb 11 22:14:31 2004
+++ b/include/asm-ia64/pci.h	Wed Feb 11 22:14:31 2004
@@ -112,6 +112,10 @@
 	return 0;
 }
 
+static inline void pcibios_add_platform_entries(struct pci_dev *dev)
+{
+}
+
 /* generic pci stuff */
 #include <asm-generic/pci.h>
 
diff -Nru a/include/asm-ia64/percpu.h b/include/asm-ia64/percpu.h
--- a/include/asm-ia64/percpu.h	Wed Feb 11 22:14:31 2004
+++ b/include/asm-ia64/percpu.h	Wed Feb 11 22:14:31 2004
@@ -50,7 +50,7 @@
 
 #else /* ! SMP */
 
-#define per_cpu(var, cpu)			((void)cpu, per_cpu__##var)
+#define per_cpu(var, cpu)			(*((void)cpu, &per_cpu__##var))
 #define __get_cpu_var(var)			per_cpu__##var
 #define per_cpu_init()				(__phys_per_cpu_start)
 
diff -Nru a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h
--- a/include/asm-ia64/processor.h	Wed Feb 11 22:14:30 2004
+++ b/include/asm-ia64/processor.h	Wed Feb 11 22:14:30 2004
@@ -289,19 +289,19 @@
 	struct ia64_fpreg fph[96];	/* saved/loaded on demand */
 };
 
-#define INIT_THREAD {				\
-	.flags =	0,			\
-	.on_ustack =	0,			\
-	.ksp =		0,			\
-	.map_base =	DEFAULT_MAP_BASE,	\
-	.rbs_bot =	DEFAULT_USER_STACK_SIZE,	\
-	.task_size =	DEFAULT_TASK_SIZE,	\
-	.last_fph_cpu =  -1,			\
-	INIT_THREAD_IA32			\
-	INIT_THREAD_PM				\
-	.dbr =		{0, },			\
-	.ibr =		{0, },			\
-	.fph =		{{{{0}}}, }		\
+#define INIT_THREAD {						\
+	.flags =	0,					\
+	.on_ustack =	0,					\
+	.ksp =		0,					\
+	.map_base =	DEFAULT_MAP_BASE,			\
+	.rbs_bot =	STACK_TOP - DEFAULT_USER_STACK_SIZE,	\
+	.task_size =	DEFAULT_TASK_SIZE,			\
+	.last_fph_cpu =  -1,					\
+	INIT_THREAD_IA32					\
+	INIT_THREAD_PM						\
+	.dbr =		{0, },					\
+	.ibr =		{0, },					\
+	.fph =		{{{{0}}}, }				\
 }
 
 #define start_thread(regs,new_ip,new_sp) do {							\
diff -Nru a/include/asm-m68k/pci.h b/include/asm-m68k/pci.h
--- a/include/asm-m68k/pci.h	Wed Feb 11 22:14:31 2004
+++ b/include/asm-m68k/pci.h	Wed Feb 11 22:14:31 2004
@@ -54,4 +54,8 @@
  */
 #define PCI_DMA_BUS_IS_PHYS	(1)
 
+static inline void pcibios_add_platform_entries(struct pci_dev *dev)
+{
+}
+
 #endif /* _ASM_M68K_PCI_H */
diff -Nru a/include/asm-m68knommu/pci.h b/include/asm-m68knommu/pci.h
--- a/include/asm-m68knommu/pci.h	Wed Feb 11 22:14:31 2004
+++ b/include/asm-m68knommu/pci.h	Wed Feb 11 22:14:31 2004
@@ -30,6 +30,10 @@
  */
 #define pci_dac_dma_supported(pci_dev, mask) (0)
 
+static inline void pcibios_add_platform_entries(struct pci_dev *dev)
+{
+}
+
 #endif /* CONFIG_COMEMPCI */
 
 #endif /* M68KNOMMU_PCI_H */
diff -Nru a/include/asm-mips/pci.h b/include/asm-mips/pci.h
--- a/include/asm-mips/pci.h	Wed Feb 11 22:14:31 2004
+++ b/include/asm-mips/pci.h	Wed Feb 11 22:14:31 2004
@@ -120,6 +120,10 @@
 	dma_cache_wback_inv(addr, len);
 }
 
+static inline void pcibios_add_platform_entries(struct pci_dev *dev)
+{
+}
+
 #endif /* __KERNEL__ */
 
 /* implement the pci_ DMA API in terms of the generic device dma_ one */
diff -Nru a/include/asm-parisc/pci.h b/include/asm-parisc/pci.h
--- a/include/asm-parisc/pci.h	Wed Feb 11 22:14:31 2004
+++ b/include/asm-parisc/pci.h	Wed Feb 11 22:14:31 2004
@@ -196,4 +196,8 @@
 pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
 			 struct resource *res);
 
+static inline void pcibios_add_platform_entries(struct pci_dev *dev)
+{
+}
+
 #endif /* __ASM_PARISC_PCI_H */
diff -Nru a/include/asm-ppc/pci.h b/include/asm-ppc/pci.h
--- a/include/asm-ppc/pci.h	Wed Feb 11 22:14:31 2004
+++ b/include/asm-ppc/pci.h	Wed Feb 11 22:14:31 2004
@@ -282,6 +282,8 @@
 pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
 			struct resource *res);
 
+extern void pcibios_add_platform_entries(struct pci_dev *dev);
+
 #endif	/* __KERNEL__ */
 
 #endif /* __PPC_PCI_H */
diff -Nru a/include/asm-ppc/pmac_feature.h b/include/asm-ppc/pmac_feature.h
--- a/include/asm-ppc/pmac_feature.h	Wed Feb 11 22:14:30 2004
+++ b/include/asm-ppc/pmac_feature.h	Wed Feb 11 22:14:30 2004
@@ -115,6 +115,7 @@
 /* MacRISC4 / G5 machines
  */
 #define PMAC_TYPE_POWERMAC_G5		0x150	/* First tower */
+#define PMAC_TYPE_UNKNOWN_K2		0x19f	/* Any other K2 based */
 
 /*
  * Motherboard flags
diff -Nru a/include/asm-ppc64/bootx.h b/include/asm-ppc64/bootx.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc64/bootx.h	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,135 @@
+/*
+ * This file describes the structure passed from the BootX application
+ * (for MacOS) when it is used to boot Linux.
+ *
+ * Written by Benjamin Herrenschmidt.
+ */
+
+
+#ifndef __ASM_BOOTX_H__
+#define __ASM_BOOTX_H__
+
+#ifdef macintosh
+#include <Types.h>
+#include "linux_type_defs.h"
+#endif
+
+#ifdef macintosh
+/* All this requires PowerPC alignment */
+#pragma options align=power
+#endif
+
+/* On kernel entry:
+ *
+ * r3 = 0x426f6f58    ('BooX')
+ * r4 = pointer to boot_infos
+ * r5 = NULL
+ *
+ * Data and instruction translation disabled, interrupts
+ * disabled, kernel loaded at physical 0x00000000 on PCI
+ * machines (will be different on NuBus).
+ */
+
+#define BOOT_INFO_VERSION               5
+#define BOOT_INFO_COMPATIBLE_VERSION    1
+
+/* Bit in the architecture flag mask. More to be defined in
+   future versions. Note that either BOOT_ARCH_PCI or
+   BOOT_ARCH_NUBUS is set. The other BOOT_ARCH_NUBUS_xxx are
+   set additionally when BOOT_ARCH_NUBUS is set.
+ */
+#define BOOT_ARCH_PCI                   0x00000001UL
+#define BOOT_ARCH_NUBUS                 0x00000002UL
+#define BOOT_ARCH_NUBUS_PDM             0x00000010UL
+#define BOOT_ARCH_NUBUS_PERFORMA        0x00000020UL
+#define BOOT_ARCH_NUBUS_POWERBOOK       0x00000040UL
+
+/*  Maximum number of ranges in phys memory map */
+#define MAX_MEM_MAP_SIZE				26
+
+/* This is the format of an element in the physical memory map. Note that
+   the map is optional and current BootX will only build it for pre-PCI
+   machines */
+typedef struct boot_info_map_entry
+{
+    __u32       physAddr;                /* Physical starting address */
+    __u32       size;                    /* Size in bytes */
+} boot_info_map_entry_t;
+
+
+/* Here are the boot informations that are passed to the bootstrap
+ * Note that the kernel arguments and the device tree are appended
+ * at the end of this structure. */
+typedef struct boot_infos
+{
+    /* Version of this structure */
+    __u32       version;
+    /* backward compatible down to version: */
+    __u32       compatible_version;
+
+    /* NEW (vers. 2) this holds the current _logical_ base addr of
+       the frame buffer (for use by early boot message) */
+    __u8*       logicalDisplayBase;
+
+    /* NEW (vers. 4) Apple's machine identification */
+    __u32       machineID;
+
+    /* NEW (vers. 4) Detected hw architecture */
+    __u32       architecture;
+
+    /* The device tree (internal addresses relative to the beginning of the tree,
+     * device tree offset relative to the beginning of this structure).
+     * On pre-PCI macintosh (BOOT_ARCH_PCI bit set to 0 in architecture), this
+     * field is 0.
+     */
+    __u32       deviceTreeOffset;        /* Device tree offset */
+    __u32       deviceTreeSize;          /* Size of the device tree */
+
+    /* Some infos about the current MacOS display */
+    __u32       dispDeviceRect[4];       /* left,top,right,bottom */
+    __u32       dispDeviceDepth;         /* (8, 16 or 32) */
+    __u8*       dispDeviceBase;          /* base address (physical) */
+    __u32       dispDeviceRowBytes;      /* rowbytes (in bytes) */
+    __u32       dispDeviceColorsOffset;  /* Colormap (8 bits only) or 0 (*) */
+    /* Optional offset in the registry to the current
+     * MacOS display. (Can be 0 when not detected) */
+     __u32      dispDeviceRegEntryOffset;
+
+    /* Optional pointer to boot ramdisk (offset from this structure) */
+    __u32       ramDisk;
+    __u32       ramDiskSize;             /* size of ramdisk image */
+
+    /* Kernel command line arguments (offset from this structure) */
+    __u32       kernelParamsOffset;
+
+    /* ALL BELOW NEW (vers. 4) */
+
+    /* This defines the physical memory. Valid with BOOT_ARCH_NUBUS flag
+       (non-PCI) only. On PCI, memory is contiguous and it's size is in the
+       device-tree. */
+    boot_info_map_entry_t
+    	        physMemoryMap[MAX_MEM_MAP_SIZE]; /* Where the phys memory is */
+    __u32       physMemoryMapSize;               /* How many entries in map */
+
+
+    /* The framebuffer size (optional, currently 0) */
+    __u32       frameBufferSize;         /* Represents a max size, can be 0. */
+
+    /* NEW (vers. 5) */
+
+    /* Total params size (args + colormap + device tree + ramdisk) */
+    __u32       totalParamsSize;
+
+} boot_infos_t;
+
+/* (*) The format of the colormap is 256 * 3 * 2 bytes. Each color index is represented
+ * by 3 short words containing a 16 bits (unsigned) color component.
+ * Later versions may contain the gamma table for direct-color devices here.
+ */
+#define BOOTX_COLORTABLE_SIZE    (256UL*3UL*2UL)
+
+#ifdef macintosh
+#pragma options align=reset
+#endif
+
+#endif
diff -Nru a/include/asm-ppc64/btext.h b/include/asm-ppc64/btext.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc64/btext.h	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,29 @@
+/*
+ * 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 boot_infos_t disp_bi;
+extern int boot_text_mapped;
+
+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 -Nru a/include/asm-ppc64/dbdma.h b/include/asm-ppc64/dbdma.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc64/dbdma.h	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,2 @@
+#include <asm-ppc/dbdma.h>
+
diff -Nru a/include/asm-ppc64/keylargo.h b/include/asm-ppc64/keylargo.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc64/keylargo.h	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,2 @@
+#include <asm-ppc/keylargo.h>
+
diff -Nru a/include/asm-ppc64/lmb.h b/include/asm-ppc64/lmb.h
--- a/include/asm-ppc64/lmb.h	Wed Feb 11 22:14:31 2004
+++ b/include/asm-ppc64/lmb.h	Wed Feb 11 22:14:31 2004
@@ -21,8 +21,9 @@
 #define MAX_LMB_REGIONS 64
 
 union lmb_reg_property { 
-	struct reg_property32 addr32[MAX_LMB_REGIONS];
-	struct reg_property64 addr64[MAX_LMB_REGIONS];
+	struct reg_property32	 addr32[MAX_LMB_REGIONS];
+	struct reg_property64	 addr64[MAX_LMB_REGIONS];
+	struct reg_property_pmac addrPM[MAX_LMB_REGIONS];
 };
 
 #define LMB_MEMORY_AREA	1
diff -Nru a/include/asm-ppc64/machdep.h b/include/asm-ppc64/machdep.h
--- a/include/asm-ppc64/machdep.h	Wed Feb 11 22:14:30 2004
+++ b/include/asm-ppc64/machdep.h	Wed Feb 11 22:14:30 2004
@@ -69,6 +69,9 @@
 	void		(*init_IRQ)(void);
 	int		(*get_irq)(struct pt_regs *);
 
+	/* PCI stuff */
+	void		(*pcibios_fixup)(void);
+
 	/* Optional, may be NULL. */
 	void		(*init)(void);
 
@@ -94,11 +97,15 @@
 
 	ssize_t		(*nvram_write)(char *buf, size_t count, loff_t *index);
 	ssize_t		(*nvram_read)(char *buf, size_t count, loff_t *index);	
+	ssize_t		(*nvram_size)(void);		
+	int		(*nvram_sync)(void);
+
+	/* Motherboard/chipset features. This is a kind of general purpose
+	 * hook used to control some machine specific features (like reset
+	 * lines, chip power control, etc...).
+	 */
+	long	 	(*feature_call)(unsigned int feature, ...);
 
-#ifdef CONFIG_SMP
-	/* functions for dealing with other cpus */
-	struct smp_ops_t smp_ops;
-#endif /* CONFIG_SMP */
 };
 
 extern struct machdep_calls ppc_md;
diff -Nru a/include/asm-ppc64/macio.h b/include/asm-ppc64/macio.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc64/macio.h	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,2 @@
+#include <asm-ppc/macio.h>
+
diff -Nru a/include/asm-ppc64/mmzone.h b/include/asm-ppc64/mmzone.h
--- a/include/asm-ppc64/mmzone.h	Wed Feb 11 22:14:31 2004
+++ b/include/asm-ppc64/mmzone.h	Wed Feb 11 22:14:31 2004
@@ -72,9 +72,6 @@
 #define local_mapnr(kvaddr) \
 	( (__pa(kvaddr) >> PAGE_SHIFT) - node_start_pfn(kvaddr_to_nid(kvaddr)) 
 
-/* XXX fix - Anton - and wli */
-#define kern_addr_valid(kaddr)	(0)
-
 /* Written this way to avoid evaluating arguments twice */
 #define discontigmem_pfn_to_page(pfn) \
 ({ \
diff -Nru a/include/asm-ppc64/nvram.h b/include/asm-ppc64/nvram.h
--- a/include/asm-ppc64/nvram.h	Wed Feb 11 22:14:31 2004
+++ b/include/asm-ppc64/nvram.h	Wed Feb 11 22:14:31 2004
@@ -38,12 +38,15 @@
 #define NVRAM_SIG_OF	0x50	/* open firmware config */
 #define NVRAM_SIG_FW	0x51	/* general firmware */
 #define NVRAM_SIG_HW	0x52	/* hardware (VPD) */
+#define NVRAM_SIG_FLIP	0x5a	/* Apple flip/flop header */
+#define NVRAM_SIG_APPL	0x5f	/* Apple "system" (???) */
 #define NVRAM_SIG_SYS	0x70	/* system env vars */
 #define NVRAM_SIG_CFG	0x71	/* config data */
 #define NVRAM_SIG_ELOG	0x72	/* error log */
 #define NVRAM_SIG_VEND	0x7e	/* vendor defined */
 #define NVRAM_SIG_FREE	0x7f	/* Free space */
 #define NVRAM_SIG_OS	0xa0	/* OS defined */
+#define NVRAM_SIG_PANIC	0xa1	/* Apple OSX "panic" */
 
 /* If change this size, then change the size of NVNAME_LEN */
 struct nvram_header {
@@ -60,11 +63,53 @@
 };
 
 
-ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index);
-ssize_t pSeries_nvram_write(char *buf, size_t count, loff_t *index);
-int nvram_write_error_log(char * buff, int length, unsigned int err_type);
-int nvram_read_error_log(char * buff, int length, unsigned int * err_type);
-int nvram_clear_error_log(void);
-void nvram_print_partitions(char * label);
+extern int nvram_write_error_log(char * buff, int length, unsigned int err_type);
+extern int nvram_read_error_log(char * buff, int length, unsigned int * err_type);
+extern int nvram_clear_error_log(void);
+extern struct nvram_partition *nvram_find_partition(int sig, const char *name);
+
+extern int pSeries_nvram_init(void);
+extern int pmac_nvram_init(void);
+
+/* PowerMac specific nvram stuffs */
+
+enum {
+	pmac_nvram_OF,		/* Open Firmware partition */
+	pmac_nvram_XPRAM,	/* MacOS XPRAM partition */
+	pmac_nvram_NR		/* MacOS Name Registry partition */
+};
+
+/* Return partition offset in nvram */
+extern int	pmac_get_partition(int partition);
+
+/* Direct access to XPRAM on PowerMacs */
+extern u8	pmac_xpram_read(int xpaddr);
+extern void	pmac_xpram_write(int xpaddr, u8 data);
+
+/* Synchronize NVRAM */
+extern int	nvram_sync(void);
+
+/* Some offsets in XPRAM */
+#define PMAC_XPRAM_MACHINE_LOC	0xe4
+#define PMAC_XPRAM_SOUND_VOLUME	0x08
+
+/* Machine location structure in PowerMac XPRAM */
+struct pmac_machine_location {
+	unsigned int	latitude;	/* 2+30 bit Fractional number */
+	unsigned int	longitude;	/* 2+30 bit Fractional number */
+	unsigned int	delta;		/* mix of GMT delta and DLS */
+};
+
+/*
+ * /dev/nvram ioctls
+ *
+ * Note that PMAC_NVRAM_GET_OFFSET is still supported, but is
+ * definitely obsolete. Do not use it if you can avoid it
+ */
+
+#define OBSOLETE_PMAC_NVRAM_GET_OFFSET \
+				_IOWR('p', 0x40, int)
+
+#define IOC_NVRAM_GET_OFFSET	_IOWR('p', 0x42, int)	/* Get NVRAM partition offset */
 
 #endif /* _PPC64_NVRAM_H */
diff -Nru a/include/asm-ppc64/of_device.h b/include/asm-ppc64/of_device.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc64/of_device.h	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,2 @@
+#include <asm-ppc/of_device.h>
+
diff -Nru a/include/asm-ppc64/offsets.h b/include/asm-ppc64/offsets.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc64/offsets.h	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,110 @@
+#ifndef __ASM_OFFSETS_H__
+#define __ASM_OFFSETS_H__
+/*
+ * DO NOT MODIFY.
+ *
+ * This file was generated by arch/ppc64/Makefile
+ *
+ */
+
+#define THREAD_SHIFT 14 /* THREAD_SHIFT */
+#define THREAD_SIZE 16384 /* THREAD_SIZE */
+#define TI_FLAGS 16 /* offsetof(struct thread_info, flags) */
+#define THREAD 1328 /* offsetof(struct task_struct, thread) */
+#define PT_REGS 8 /* offsetof(struct thread_struct, regs) */
+#define THREAD_FPEXC_MODE 288 /* offsetof(struct thread_struct, fpexc_mode) */
+#define THREAD_FPR0 24 /* offsetof(struct thread_struct, fpr[0]) */
+#define THREAD_FPSCR 280 /* offsetof(struct thread_struct, fpscr) */
+#define KSP 0 /* offsetof(struct thread_struct, ksp) */
+#define THREAD_VR0 320 /* offsetof(struct thread_struct, vr[0]) */
+#define THREAD_VRSAVE 848 /* offsetof(struct thread_struct, vrsave) */
+#define THREAD_VSCR 832 /* offsetof(struct thread_struct, vscr) */
+#define THREAD_USED_VR 856 /* offsetof(struct thread_struct, used_vr) */
+#define MM 184 /* offsetof(struct task_struct, mm) */
+#define PACA 24 /* offsetof(struct naca_struct, paca) */
+#define DCACHEL1LINESIZE 100 /* offsetof(struct systemcfg, dCacheL1LineSize) */
+#define DCACHEL1LOGLINESIZE 96 /* offsetof(struct naca_struct, dCacheL1LogLineSize) */
+#define DCACHEL1LINESPERPAGE 100 /* offsetof(struct naca_struct, dCacheL1LinesPerPage) */
+#define ICACHEL1LINESIZE 108 /* offsetof(struct systemcfg, iCacheL1LineSize) */
+#define ICACHEL1LOGLINESIZE 104 /* offsetof(struct naca_struct, iCacheL1LogLineSize) */
+#define ICACHEL1LINESPERPAGE 108 /* offsetof(struct naca_struct, iCacheL1LinesPerPage) */
+#define SLBSIZE 72 /* offsetof(struct naca_struct, slb_size) */
+#define PLATFORM 24 /* offsetof(struct systemcfg, platform) */
+#define PACA_SIZE 8192 /* sizeof(struct paca_struct) */
+#define PACAPACAINDEX 24 /* offsetof(struct paca_struct, xPacaIndex) */
+#define PACAPROCSTART 256 /* offsetof(struct paca_struct, xProcStart) */
+#define PACAKSAVE 32 /* offsetof(struct paca_struct, xKsave) */
+#define PACACURRENT 16 /* offsetof(struct paca_struct, xCurrent) */
+#define PACASAVEDMSR 2144 /* offsetof(struct paca_struct, xSavedMsr) */
+#define PACASTABREAL 56 /* offsetof(struct paca_struct, xStab_data.real) */
+#define PACASTABVIRT 64 /* offsetof(struct paca_struct, xStab_data.virt) */
+#define PACASTABRR 72 /* offsetof(struct paca_struct, xStab_data.next_round_robin) */
+#define PACAR1 2136 /* offsetof(struct paca_struct, xR1) */
+#define PACALPQUEUE 40 /* offsetof(struct paca_struct, lpQueuePtr) */
+#define PACATOC 48 /* offsetof(struct paca_struct, xTOC) */
+#define PACAEXCSP 80 /* offsetof(struct paca_struct, exception_sp) */
+#define PACAPROCENABLED 88 /* offsetof(struct paca_struct, xProcEnabled) */
+#define PACADEFAULTDECR 28 /* offsetof(struct paca_struct, default_decr) */
+#define PACAPROFENABLED 89 /* offsetof(struct paca_struct, prof_enabled) */
+#define PACAPROFLEN 200 /* offsetof(struct paca_struct, prof_len) */
+#define PACAPROFSHIFT 180 /* offsetof(struct paca_struct, prof_shift) */
+#define PACAPROFBUFFER 184 /* offsetof(struct paca_struct, prof_buffer) */
+#define PACAPROFSTEXT 192 /* offsetof(struct paca_struct, prof_stext) */
+#define PACALPPACA 384 /* offsetof(struct paca_struct, xLpPaca) */
+#define LPPACA 384 /* offsetof(struct paca_struct, xLpPaca) */
+#define PACAREGSAV 1024 /* offsetof(struct paca_struct, xRegSav) */
+#define PACAEXC 3840 /* offsetof(struct paca_struct, exception_stack) */
+#define PACAGUARD 4096 /* offsetof(struct paca_struct, guard) */
+#define LPPACASRR0 144 /* offsetof(struct ItLpPaca, xSavedSrr0) */
+#define LPPACASRR1 152 /* offsetof(struct ItLpPaca, xSavedSrr1) */
+#define LPPACAANYINT 128 /* offsetof(struct ItLpPaca, xIntDword.xAnyInt) */
+#define LPPACADECRINT 132 /* offsetof(struct ItLpPaca, xIntDword.xFields.xDecrInt) */
+#define LPQCUREVENTPTR 16 /* offsetof(struct ItLpQueue, xSlicCurEventPtr) */
+#define LPQOVERFLOW 0 /* offsetof(struct ItLpQueue, xPlicOverflowIntPending) */
+#define LPEVENTFLAGS 0 /* offsetof(struct HvLpEvent, xFlags) */
+#define PROMENTRY 0 /* offsetof(struct prom_t, entry) */
+#define RTASBASE 8 /* offsetof(struct rtas_t, base) */
+#define RTASENTRY 0 /* offsetof(struct rtas_t, entry) */
+#define RTASSIZE 16 /* offsetof(struct rtas_t, size) */
+#define STACK_FRAME_OVERHEAD 112 /* STACK_FRAME_OVERHEAD */
+#define SWITCH_FRAME_SIZE 464 /* STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) */
+#define INT_FRAME_SIZE 752 /* STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 288 */
+#define PROM_FRAME_SIZE 480 /* STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16 */
+#define RTAS_FRAME_SIZE 480 /* STACK_FRAME_OVERHEAD + sizeof(struct pt_regs) + 16 */
+#define GPR0 112 /* STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0]) */
+#define GPR1 120 /* STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1]) */
+#define GPR2 128 /* STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2]) */
+#define GPR3 136 /* STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[3]) */
+#define GPR4 144 /* STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[4]) */
+#define GPR5 152 /* STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[5]) */
+#define GPR6 160 /* STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[6]) */
+#define GPR7 168 /* STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[7]) */
+#define GPR8 176 /* STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[8]) */
+#define GPR9 184 /* STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[9]) */
+#define GPR20 272 /* STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[20]) */
+#define GPR21 280 /* STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[21]) */
+#define GPR22 288 /* STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[22]) */
+#define GPR23 296 /* STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[23]) */
+#define _NIP 368 /* STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, nip) */
+#define _MSR 376 /* STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, msr) */
+#define _CTR 392 /* STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ctr) */
+#define _LINK 400 /* STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, link) */
+#define _CCR 416 /* STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ccr) */
+#define _XER 408 /* STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer) */
+#define _DAR 440 /* STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar) */
+#define _DSISR 448 /* STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr) */
+#define ORIG_GPR3 384 /* STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3) */
+#define RESULT 456 /* STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result) */
+#define TRAP 432 /* STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap) */
+#define SOFTE 424 /* STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, softe) */
+#define _SRR0 464 /* STACK_FRAME_OVERHEAD+sizeof(struct pt_regs) */
+#define _SRR1 472 /* STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)+8 */
+#define CLONE_VM 256 /* CLONE_VM */
+#define CLONE_UNTRACED 8388608 /* CLONE_UNTRACED */
+#define CPU_SPEC_ENTRY_SIZE 56 /* sizeof(struct cpu_spec) */
+#define CPU_SPEC_PVR_MASK 0 /* offsetof(struct cpu_spec, pvr_mask) */
+#define CPU_SPEC_PVR_VALUE 4 /* offsetof(struct cpu_spec, pvr_value) */
+#define CPU_SPEC_FEATURES 16 /* offsetof(struct cpu_spec, cpu_features) */
+#define CPU_SPEC_SETUP 40 /* offsetof(struct cpu_spec, cpu_setup) */
+
+#endif
diff -Nru a/include/asm-ppc64/pci-bridge.h b/include/asm-ppc64/pci-bridge.h
--- a/include/asm-ppc64/pci-bridge.h	Wed Feb 11 22:14:30 2004
+++ b/include/asm-ppc64/pci-bridge.h	Wed Feb 11 22:14:30 2004
@@ -21,7 +21,8 @@
 	phb_type_hypervisor = 0x1,
 	phb_type_python     = 0x10,
 	phb_type_speedwagon = 0x11,
-	phb_type_winnipeg   = 0x12
+	phb_type_winnipeg   = 0x12,
+	phb_type_apple      = 0xff
 };
 
 /*
@@ -47,6 +48,8 @@
 	unsigned long pci_io_offset;
 
 	struct pci_ops *ops;
+	volatile unsigned int *cfg_addr;
+	volatile unsigned char *cfg_data;
 
 	/* Currently, we limit ourselves to 1 IO range and 3 mem
 	 * ranges since the common pci_bus structure can't handle more
diff -Nru a/include/asm-ppc64/pci.h b/include/asm-ppc64/pci.h
--- a/include/asm-ppc64/pci.h	Wed Feb 11 22:14:31 2004
+++ b/include/asm-ppc64/pci.h	Wed Feb 11 22:14:31 2004
@@ -55,19 +55,62 @@
 
 extern unsigned int pcibios_assign_all_busses(void);
 
-extern void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
-				  dma_addr_t *dma_handle);
-extern void pci_free_consistent(struct pci_dev *hwdev, size_t size,
-				void *vaddr, dma_addr_t dma_handle);
-
-extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
-				 size_t size, int direction);
-extern void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
-                             size_t size, int direction);
-extern int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-                      int nents, int direction);
-extern void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
-                         int nents, int direction);
+/*
+ * PCI DMA operations are abstracted for G5 vs. i/pSeries
+ */
+struct pci_dma_ops {
+	void *		(*pci_alloc_consistent)(struct pci_dev *hwdev, size_t size,
+					dma_addr_t *dma_handle);
+	void		(*pci_free_consistent)(struct pci_dev *hwdev, size_t size,
+				       void *vaddr, dma_addr_t dma_handle);
+
+	dma_addr_t	(*pci_map_single)(struct pci_dev *hwdev, void *ptr,
+					  size_t size, int direction);
+	void		(*pci_unmap_single)(struct pci_dev *hwdev, dma_addr_t dma_addr,
+					    size_t size, int direction);
+	int		(*pci_map_sg)(struct pci_dev *hwdev, struct scatterlist *sg,
+				      int nents, int direction);
+	void		(*pci_unmap_sg)(struct pci_dev *hwdev, struct scatterlist *sg,
+					int nents, int direction);
+};
+
+extern struct pci_dma_ops pci_dma_ops;
+
+static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
+					 dma_addr_t *dma_handle)
+{
+	return pci_dma_ops.pci_alloc_consistent(hwdev, size, dma_handle);
+}
+
+static inline void pci_free_consistent(struct pci_dev *hwdev, size_t size,
+				       void *vaddr, dma_addr_t dma_handle)
+{
+	pci_dma_ops.pci_free_consistent(hwdev, size, vaddr, dma_handle);
+}
+
+static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
+					size_t size, int direction)
+{
+	return pci_dma_ops.pci_map_single(hwdev, ptr, size, direction); 
+}
+
+static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
+				    size_t size, int direction)
+{
+	pci_dma_ops.pci_unmap_single(hwdev, dma_addr, size, direction);
+}
+
+static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+			     int nents, int direction)
+{
+	return pci_dma_ops.pci_map_sg(hwdev, sg, nents, direction);
+}
+
+static inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+				int nents, int direction)
+{
+	pci_dma_ops.pci_unmap_sg(hwdev, sg, nents, direction);
+}
 
 static inline void pci_dma_sync_single(struct pci_dev *hwdev,
 				       dma_addr_t dma_handle,
@@ -151,6 +194,8 @@
 pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus);
 
 extern int pci_read_irq_line(struct pci_dev *dev);
+
+extern void pcibios_add_platform_entries(struct pci_dev *dev);
 
 #endif	/* __KERNEL__ */
 
diff -Nru a/include/asm-ppc64/pci_dma.h b/include/asm-ppc64/pci_dma.h
--- a/include/asm-ppc64/pci_dma.h	Wed Feb 11 22:14:30 2004
+++ b/include/asm-ppc64/pci_dma.h	Wed Feb 11 22:14:30 2004
@@ -94,7 +94,9 @@
 extern void create_tce_tables(void);
 extern void create_pci_bus_tce_table(unsigned long);
 
-void tce_init_pSeries(void);
-void tce_init_iSeries(void);
+extern void tce_init_pSeries(void);
+extern void tce_init_iSeries(void);
+
+extern void pci_dma_init_direct(void);
 
 #endif
diff -Nru a/include/asm-ppc64/pmac_feature.h b/include/asm-ppc64/pmac_feature.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc64/pmac_feature.h	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,2 @@
+#include <asm-ppc/pmac_feature.h>
+
diff -Nru a/include/asm-ppc64/pmac_low_i2c.h b/include/asm-ppc64/pmac_low_i2c.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc64/pmac_low_i2c.h	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,2 @@
+#include <asm-ppc/pmac_low_i2c.h>
+
diff -Nru a/include/asm-ppc64/processor.h b/include/asm-ppc64/processor.h
--- a/include/asm-ppc64/processor.h	Wed Feb 11 22:14:30 2004
+++ b/include/asm-ppc64/processor.h	Wed Feb 11 22:14:30 2004
@@ -216,8 +216,11 @@
 #define	  HID0_BHTE	(1<<2)		/* Branch History Table Enable */
 #define	  HID0_BTCD	(1<<1)		/* Branch target cache disable */
 #define	SPRN_MSRDORM	0x3F1	/* Hardware Implementation Register 1 */
+#define SPRN_HID1	0x3F1	/* Hardware Implementation Register 1 */
 #define	SPRN_IABR	0x3F2	/* Instruction Address Breakpoint Register */
 #define	SPRN_NIADORM	0x3F3	/* Hardware Implementation Register 2 */
+#define SPRN_HID4	0x3F4	/* 970 HID4 */
+#define SPRN_HID5	0x3F6	/* 970 HID5 */
 #define	SPRN_TSC 	0x3FD	/* Thread switch control */
 #define	SPRN_TST 	0x3FC	/* Thread switch timeout */
 #define	SPRN_IAC1	0x3F4	/* Instruction Address Compare 1 */
@@ -263,6 +266,7 @@
 #define	SPRN_TBRU	0x10D	/* Time Base Read Upper Register (user, R/O) */
 #define	SPRN_TBWL	0x11C	/* Time Base Lower Register (super, W/O) */
 #define	SPRN_TBWU	0x11D	/* Time Base Write Upper Register (super, W/O) */
+#define SPRN_HIOR	0x137	/* 970 Hypervisor interrupt offset */
 #define	SPRN_TCR	0x3DA	/* Timer Control Register */
 #define	  TCR_WP(x)		(((x)&0x3)<<30)	/* WDT Period */
 #define	    WP_2_17		0		/* 2^17 clocks */
@@ -373,6 +377,7 @@
 #define	PV_ICESTAR	0x0036
 #define	PV_SSTAR	0x0037
 #define	PV_POWER4p	0x0038
+#define PV_GPUL		0x0039
 #define	PV_POWER5	0x003A
 #define	PV_630        	0x0040
 #define	PV_630p	        0x0041
@@ -382,7 +387,12 @@
 #define PLATFORM_PSERIES_LPAR 0x0101
 #define PLATFORM_ISERIES_LPAR 0x0201
 #define PLATFORM_LPAR         0x0001
-	
+#define PLATFORM_POWERMAC     0x0400
+
+/* Compatibility with drivers coming from PPC32 world */
+#define _machine	(systemcfg->platform)
+#define _MACH_Pmac	PLATFORM_POWERMAC
+
 /*
  * List of interrupt controllers.
  */
@@ -457,6 +467,14 @@
 			asm volatile("mfasr %0" : "=r" (rval)); rval;})
 
 #ifndef __ASSEMBLY__
+
+static inline void set_tb(unsigned int upper, unsigned int lower)
+{
+	mttbl(0);
+	mttbu(upper);
+	mttbl(lower);
+}
+
 extern unsigned long *_get_SP(void);
 
 extern int have_of;
diff -Nru a/include/asm-ppc64/prom.h b/include/asm-ppc64/prom.h
--- a/include/asm-ppc64/prom.h	Wed Feb 11 22:14:31 2004
+++ b/include/asm-ppc64/prom.h	Wed Feb 11 22:14:31 2004
@@ -108,6 +108,12 @@
 	unsigned long size;
 };
 
+struct reg_property_pmac {
+	unsigned int address_hi;
+	unsigned int address_lo;
+	unsigned int size;
+};
+
 struct translation_property {
 	unsigned long virt;
 	unsigned long size;
@@ -207,6 +213,7 @@
 
 struct prom_t {
 	unsigned long entry;
+	ihandle root;
 	ihandle chosen;
 	int cpu;
 	ihandle stdout;
diff -Nru a/include/asm-ppc64/sections.h b/include/asm-ppc64/sections.h
--- a/include/asm-ppc64/sections.h	Wed Feb 11 22:14:31 2004
+++ b/include/asm-ppc64/sections.h	Wed Feb 11 22:14:31 2004
@@ -5,4 +5,16 @@
 
 #include <asm-generic/sections.h>
 
+#define __pmac
+#define __pmacdata
+
+#define __prep
+#define __prepdata
+
+#define __chrp
+#define __chrpdata
+
+#define __openfirmware
+#define __openfirmwaredata
+
 #endif
diff -Nru a/include/asm-ppc64/systemcfg.h b/include/asm-ppc64/systemcfg.h
--- a/include/asm-ppc64/systemcfg.h	Wed Feb 11 22:14:31 2004
+++ b/include/asm-ppc64/systemcfg.h	Wed Feb 11 22:14:31 2004
@@ -72,6 +72,7 @@
 #define PV_ICESTAR      0x0036
 #define PV_SSTAR        0x0037
 #define PV_POWER4p      0x0038
+#define PV_GPUL		0x0039
 #define PV_630          0x0040
 #define PV_630p         0x0041
 
@@ -79,6 +80,11 @@
 #define PLATFORM_PSERIES      0x0100
 #define PLATFORM_PSERIES_LPAR 0x0101
 #define PLATFORM_ISERIES_LPAR 0x0201
+#define PLATFORM_POWERMAC     0x0400
+
+/* Compatibility with drivers coming from PPC32 world */
+#define _machine	(systemcfg->platform)
+#define _MACH_Pmac	PLATFORM_POWERMAC
 
 
 static inline volatile struct systemcfg *systemcfg_init(void)
diff -Nru a/include/asm-ppc64/uninorth.h b/include/asm-ppc64/uninorth.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc64/uninorth.h	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,2 @@
+#include <asm-ppc/uninorth.h>
+
diff -Nru a/include/asm-ppc64/xmon.h b/include/asm-ppc64/xmon.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc64/xmon.h	Wed Feb 11 22:14:31 2004
@@ -0,0 +1,17 @@
+#ifndef __PPC_XMON_H
+#define __PPC_XMON_H
+#ifdef __KERNEL__
+
+struct pt_regs;
+
+extern void xmon(struct pt_regs *excp);
+extern void xmon_printf(const char *fmt, ...);
+extern void xmon_map_scc(void);
+extern int xmon_bpt(struct pt_regs *regs);
+extern int xmon_sstep(struct pt_regs *regs);
+extern int xmon_iabr_match(struct pt_regs *regs);
+extern int xmon_dabr_match(struct pt_regs *regs);
+extern void (*xmon_fault_handler)(struct pt_regs *regs);
+
+#endif
+#endif
diff -Nru a/include/asm-sh/pci.h b/include/asm-sh/pci.h
--- a/include/asm-sh/pci.h	Wed Feb 11 22:14:31 2004
+++ b/include/asm-sh/pci.h	Wed Feb 11 22:14:31 2004
@@ -256,6 +256,10 @@
 extern int pciauto_assign_resources(int busno, struct pci_channel *hose);
 #endif
 
+static inline void pcibios_add_platform_entries(struct pci_dev *dev)
+{
+}
+
 #endif /* __KERNEL__ */
 
 /* generic pci stuff */
diff -Nru a/include/asm-sparc/pci.h b/include/asm-sparc/pci.h
--- a/include/asm-sparc/pci.h	Wed Feb 11 22:14:31 2004
+++ b/include/asm-sparc/pci.h	Wed Feb 11 22:14:31 2004
@@ -141,6 +141,10 @@
 
 #define pci_dac_dma_supported(dev, mask)	(0)
 
+static inline void pcibios_add_platform_entries(struct pci_dev *dev)
+{
+}
+
 #endif /* __KERNEL__ */
 
 /* generic pci stuff */
diff -Nru a/include/asm-sparc64/pci.h b/include/asm-sparc64/pci.h
--- a/include/asm-sparc64/pci.h	Wed Feb 11 22:14:30 2004
+++ b/include/asm-sparc64/pci.h	Wed Feb 11 22:14:30 2004
@@ -215,6 +215,10 @@
 pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
 			struct pci_bus_region *region);
 
+static inline void pcibios_add_platform_entries(struct pci_dev *dev)
+{
+}
+
 #endif /* __KERNEL__ */
 
 #endif /* __SPARC64_PCI_H */
diff -Nru a/include/asm-v850/pci.h b/include/asm-v850/pci.h
--- a/include/asm-v850/pci.h	Wed Feb 11 22:14:30 2004
+++ b/include/asm-v850/pci.h	Wed Feb 11 22:14:30 2004
@@ -76,4 +76,8 @@
 pci_free_consistent (struct pci_dev *pdev, size_t size, void *cpu_addr,
 		     dma_addr_t dma_addr);
 
+static inline void pcibios_add_platform_entries(struct pci_dev *dev)
+{
+}
+
 #endif /* __V850_PCI_H__ */
diff -Nru a/include/asm-x86_64/pci.h b/include/asm-x86_64/pci.h
--- a/include/asm-x86_64/pci.h	Wed Feb 11 22:14:31 2004
+++ b/include/asm-x86_64/pci.h	Wed Feb 11 22:14:31 2004
@@ -263,6 +263,10 @@
 extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
 			       enum pci_mmap_state mmap_state, int write_combine);
 
+static inline void pcibios_add_platform_entries(struct pci_dev *dev)
+{
+}
+
 #endif /* __KERNEL__ */
 
 /* generic pci stuff */
diff -Nru a/include/linux/compiler.h b/include/linux/compiler.h
--- a/include/linux/compiler.h	Wed Feb 11 22:14:31 2004
+++ b/include/linux/compiler.h	Wed Feb 11 22:14:31 2004
@@ -9,6 +9,8 @@
 # define __kernel
 #endif
 
+#ifdef __KERNEL__
+
 #ifndef __ASSEMBLY__
 #if __GNUC__ > 3
 # include <linux/compiler-gcc+.h>	/* catch-all for GCC 4, 5, etc. */
@@ -105,5 +107,7 @@
      __ptr = (unsigned long) (ptr);				\
     (typeof(ptr)) (__ptr + (off)); })
 #endif
+
+#endif /* __KERNEL__ */
 
 #endif /* __LINUX_COMPILER_H */
diff -Nru a/include/linux/ide.h b/include/linux/ide.h
--- a/include/linux/ide.h	Wed Feb 11 22:14:31 2004
+++ b/include/linux/ide.h	Wed Feb 11 22:14:31 2004
@@ -1626,6 +1626,7 @@
 extern int __ide_dma_verbose(ide_drive_t *);
 extern int __ide_dma_lostirq(ide_drive_t *);
 extern int __ide_dma_timeout(ide_drive_t *);
+#endif /* CONFIG_BLK_DEV_IDEDMA_PCI */
 
 #ifdef CONFIG_BLK_DEV_IDE_TCQ
 extern int __ide_dma_queued_on(ide_drive_t *drive);
@@ -1634,12 +1635,11 @@
 extern ide_startstop_t __ide_dma_queued_write(ide_drive_t *drive);
 extern ide_startstop_t __ide_dma_queued_start(ide_drive_t *drive);
 #endif
+#endif /* CONFIG_BLK_DEV_IDEDMA */
 
-#else
+#ifndef CONFIG_BLK_DEV_IDEDMA_PCI
 static inline void ide_release_dma(ide_hwif_t *drive) {;}
 #endif
-
-#endif /* CONFIG_BLK_DEV_IDEDMA */
 
 extern int ide_hwif_request_regions(ide_hwif_t *hwif);
 extern void ide_hwif_release_regions(ide_hwif_t* hwif);
diff -Nru a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
--- a/include/net/bluetooth/hci.h	Wed Feb 11 22:14:31 2004
+++ b/include/net/bluetooth/hci.h	Wed Feb 11 22:14:31 2004
@@ -253,6 +253,17 @@
 	__u8     dev_class[3];
 } __attribute__ ((packed));
 
+#define OCF_READ_VOICE_SETTING	0x0025
+struct hci_rp_read_voice_setting {
+	__u8	status;
+	__u16	voice_setting;
+} __attribute__ ((packed));
+
+#define OCF_WRITE_VOICE_SETTING	0x0026
+struct hci_cp_write_voice_setting {
+	__u16	voice_setting;
+} __attribute__ ((packed));
+
 #define OCF_HOST_BUFFER_SIZE	0x0033
 struct hci_cp_host_buffer_size {
 	__u16    acl_mtu;
diff -Nru a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
--- a/include/net/bluetooth/hci_core.h	Wed Feb 11 22:14:31 2004
+++ b/include/net/bluetooth/hci_core.h	Wed Feb 11 22:14:31 2004
@@ -71,11 +71,12 @@
 	__u8	 	type;
 	bdaddr_t	bdaddr;
 	__u8		features[8];
+	__u16		voice_setting;
 
 	__u16		pkt_type;
 	__u16		link_policy;
 	__u16		link_mode;
-	
+
 	atomic_t 	cmd_cnt;
 	unsigned int 	acl_cnt;
 	unsigned int 	sco_cnt;
@@ -88,7 +89,7 @@
 	unsigned long   cmd_last_tx;
 	unsigned long   acl_last_tx;
 	unsigned long   sco_last_tx;
-	
+
 	struct tasklet_struct 	cmd_task;
 	struct tasklet_struct	rx_task;
 	struct tasklet_struct 	tx_task;
@@ -119,7 +120,7 @@
 #endif
 
 	struct module           *owner;
-	
+
 	int (*open)(struct hci_dev *hdev);
 	int (*close)(struct hci_dev *hdev);
 	int (*flush)(struct hci_dev *hdev);
diff -Nru a/kernel/kmod.c b/kernel/kmod.c
--- a/kernel/kmod.c	Wed Feb 11 22:14:30 2004
+++ b/kernel/kmod.c	Wed Feb 11 22:14:30 2004
@@ -105,16 +105,6 @@
 	}
 
 	ret = call_usermodehelper(modprobe_path, argv, envp, 1);
-	if (ret != 0) {
-		static unsigned long last;
-		unsigned long now = jiffies;
-		if (now - last > HZ) {
-			last = now;
-			printk(KERN_DEBUG
-			       "request_module: failed %s -- %s. error = %d\n",
-			       modprobe_path, module_name, ret);
-		}
-	}
 	atomic_dec(&kmod_concurrent);
 	return ret;
 }
diff -Nru a/mm/mmap.c b/mm/mmap.c
--- a/mm/mmap.c	Wed Feb 11 22:14:31 2004
+++ b/mm/mmap.c	Wed Feb 11 22:14:31 2004
@@ -743,9 +743,8 @@
 		if (TASK_SIZE - len >= addr &&
 		    (!vma || addr + len <= vma->vm_start))
 			return addr;
-	} else
-		addr = mm->free_area_cache;
-	start_addr = addr;
+	}
+	start_addr = addr = mm->free_area_cache;
 
 full_search:
 	for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
diff -Nru a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
--- a/net/bluetooth/af_bluetooth.c	Wed Feb 11 22:14:30 2004
+++ b/net/bluetooth/af_bluetooth.c	Wed Feb 11 22:14:30 2004
@@ -236,15 +236,31 @@
 	return err ? : copied;
 }
 
+static inline unsigned int bt_accept_poll(struct sock *parent)
+{
+	struct list_head *p, *n;
+	struct sock *sk;
+
+	list_for_each_safe(p, n, &bt_sk(parent)->accept_q) {
+		sk = (struct sock *) list_entry(p, struct bt_sock, accept_q);
+		if (sk->sk_state == BT_CONNECTED)
+			return POLLIN | POLLRDNORM;
+	}
+
+	return 0;
+}
+
 unsigned int bt_sock_poll(struct file * file, struct socket *sock, poll_table *wait)
 {
 	struct sock *sk = sock->sk;
-	unsigned int mask;
+	unsigned int mask = 0;
 
 	BT_DBG("sock %p, sk %p", sock, sk);
 
 	poll_wait(file, sk->sk_sleep, wait);
-	mask = 0;
+
+	if (sk->sk_state == BT_LISTEN)
+		return bt_accept_poll(sk);
 
 	if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
 		mask |= POLLERR;
@@ -253,16 +269,17 @@
 		mask |= POLLHUP;
 
 	if (!skb_queue_empty(&sk->sk_receive_queue) || 
-			!list_empty(&bt_sk(sk)->accept_q) ||
 			(sk->sk_shutdown & RCV_SHUTDOWN))
 		mask |= POLLIN | POLLRDNORM;
 
 	if (sk->sk_state == BT_CLOSED)
 		mask |= POLLHUP;
 
-	if (sk->sk_state == BT_CONNECT || sk->sk_state == BT_CONNECT2)
+	if (sk->sk_state == BT_CONNECT ||
+			sk->sk_state == BT_CONNECT2 ||
+			sk->sk_state == BT_CONFIG)
 		return mask;
-	
+
 	if (sock_writeable(sk))
 		mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
 	else
diff -Nru a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c
--- a/net/bluetooth/bnep/sock.c	Wed Feb 11 22:14:31 2004
+++ b/net/bluetooth/bnep/sock.c	Wed Feb 11 22:14:31 2004
@@ -93,8 +93,10 @@
 		if (!nsock)
 			return err;
 
-		if (nsock->sk->sk_state != BT_CONNECTED)
+		if (nsock->sk->sk_state != BT_CONNECTED) {
+			fput(nsock->file);
 			return -EBADFD;
+		}
 
 		err = bnep_add_connection(&ca, nsock);
 		if (!err) {
diff -Nru a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c
--- a/net/bluetooth/cmtp/sock.c	Wed Feb 11 22:14:31 2004
+++ b/net/bluetooth/cmtp/sock.c	Wed Feb 11 22:14:31 2004
@@ -87,8 +87,10 @@
 		if (!nsock)
 			return err;
 
-		if (nsock->sk->sk_state != BT_CONNECTED)
+		if (nsock->sk->sk_state != BT_CONNECTED) {
+			fput(nsock->file);
 			return -EBADFD;
+		}
 
 		err = cmtp_add_connection(&ca, nsock);
 		if (!err) {
diff -Nru a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
--- a/net/bluetooth/hci_conn.c	Wed Feb 11 22:14:31 2004
+++ b/net/bluetooth/hci_conn.c	Wed Feb 11 22:14:31 2004
@@ -353,21 +353,24 @@
 	struct hci_conn_info *ci;
 	struct hci_dev *hdev;
 	struct list_head *p;
-	int n = 0, size;
+	int n = 0, size, err;
 
 	if (copy_from_user(&req, (void *) arg, sizeof(req)))
 		return -EFAULT;
 
-	if (!(hdev = hci_dev_get(req.dev_id)))
-		return -ENODEV;
-
-	size = req.conn_num * sizeof(struct hci_conn_info) + sizeof(req);
+	if (!req.conn_num || req.conn_num > (PAGE_SIZE * 2) / sizeof(*ci))
+		return -EINVAL;
 
-	if (verify_area(VERIFY_WRITE, (void *)arg, size))
-		return -EFAULT;
+	size = sizeof(req) + req.conn_num * sizeof(*ci);
 
 	if (!(cl = (void *) kmalloc(size, GFP_KERNEL)))
 		return -ENOMEM;
+
+	if (!(hdev = hci_dev_get(req.dev_id))) {
+		kfree(cl);
+		return -ENODEV;
+	}
+
 	ci = cl->conn_info;
 
 	hci_dev_lock_bh(hdev);
@@ -381,20 +384,21 @@
 		(ci + n)->out   = c->out;
 		(ci + n)->state = c->state;
 		(ci + n)->link_mode = c->link_mode;
-		n++;
+		if (++n >= req.conn_num)
+			break;
 	}
 	hci_dev_unlock_bh(hdev);
 
 	cl->dev_id = hdev->id;
 	cl->conn_num = n;
-	size = n * sizeof(struct hci_conn_info) + sizeof(req);
+	size = sizeof(req) + n * sizeof(*ci);
 
 	hci_dev_put(hdev);
 
-	copy_to_user((void *) arg, cl, size);
+	err = copy_to_user((void *) arg, cl, size);
 	kfree(cl);
 
-	return 0;
+	return err ? -EFAULT : 0;
 }
 
 int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg)
@@ -407,9 +411,6 @@
 	if (copy_from_user(&req, (void *) arg, sizeof(req)))
 		return -EFAULT;
 
-	if (verify_area(VERIFY_WRITE, ptr, sizeof(ci)))
-		return -EFAULT;
-
 	hci_dev_lock_bh(hdev);
 	conn = hci_conn_hash_lookup_ba(hdev, req.type, &req.bdaddr);
 	if (conn) {
@@ -425,6 +426,5 @@
 	if (!conn)
 		return -ENOENT;
 
-	copy_to_user(ptr, &ci, sizeof(ci));
-	return 0;
+	return copy_to_user(ptr, &ci, sizeof(ci)) ? -EFAULT : 0;
 }
diff -Nru a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
--- a/net/bluetooth/hci_core.c	Wed Feb 11 22:14:30 2004
+++ b/net/bluetooth/hci_core.c	Wed Feb 11 22:14:30 2004
@@ -237,6 +237,9 @@
 	/* Read BD Address */
 	hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BD_ADDR, 0, NULL);
 
+	/* Read Voice Setting */
+	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_READ_VOICE_SETTING, 0, NULL);
+
 	/* Optional initialization */
 
 	/* Clear Event Filters */
@@ -713,22 +716,20 @@
 	struct hci_dev_list_req *dl;
 	struct hci_dev_req *dr;
 	struct list_head *p;
-	int n = 0, size;
+	int n = 0, size, err;
 	__u16 dev_num;
 
 	if (get_user(dev_num, (__u16 *) arg))
 		return -EFAULT;
 
-	if (!dev_num)
+	if (!dev_num || dev_num > (PAGE_SIZE * 2) / sizeof(*dr))
 		return -EINVAL;
-	
-	size = dev_num * sizeof(*dr) + sizeof(*dl);
 
-	if (verify_area(VERIFY_WRITE, (void *) arg, size))
-		return -EFAULT;
+	size = sizeof(*dl) + dev_num * sizeof(*dr);
 
 	if (!(dl = kmalloc(size, GFP_KERNEL)))
 		return -ENOMEM;
+
 	dr = dl->dev_req;
 
 	read_lock_bh(&hci_dev_list_lock);
@@ -743,12 +744,12 @@
 	read_unlock_bh(&hci_dev_list_lock);
 
 	dl->dev_num = n;
-	size = n * sizeof(*dr) + sizeof(*dl);
+	size = sizeof(*dl) + n * sizeof(*dr);
 
-	copy_to_user((void *) arg, dl, size);
+	err = copy_to_user((void *) arg, dl, size);
 	kfree(dl);
 
-	return 0;
+	return err ? -EFAULT : 0;
 }
 
 int hci_get_dev_info(unsigned long arg)
diff -Nru a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
--- a/net/bluetooth/hci_event.c	Wed Feb 11 22:14:30 2004
+++ b/net/bluetooth/hci_event.c	Wed Feb 11 22:14:30 2004
@@ -123,6 +123,8 @@
 static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
 {
 	__u8 status, param;
+	__u16 setting;
+	struct hci_rp_read_voice_setting *vs;
 	void *sent;
 
 	BT_DBG("%s ocf 0x%x", hdev->name, ocf);
@@ -198,6 +200,7 @@
 		sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE);
 		if (!sent)
 			break;
+
 		status = *((__u8 *) skb->data);
 		param  = *((__u8 *) sent);
 
@@ -215,6 +218,39 @@
 		hci_req_complete(hdev, status);
 		break;
 
+	case OCF_READ_VOICE_SETTING:
+		vs = (struct hci_rp_read_voice_setting *) skb->data;
+
+		if (vs->status) {
+			BT_DBG("%s READ_VOICE_SETTING failed %d", hdev->name, vc->status);
+			break;
+		}
+
+		setting = __le16_to_cpu(vs->voice_setting);
+
+		if (hdev->voice_setting != setting ) {
+			hdev->voice_setting = setting;
+
+			BT_DBG("%s: voice setting 0x%04x", hdev->name, setting);
+		}
+		break;
+
+	case OCF_WRITE_VOICE_SETTING:
+		sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_VOICE_SETTING);
+		if (!sent)
+			break;
+
+		status = *((__u8 *) skb->data);
+		setting = __le16_to_cpu(get_unaligned((__u16 *) sent));
+
+		if (!status && hdev->voice_setting != setting) {
+			hdev->voice_setting = setting;
+
+			BT_DBG("%s: voice setting 0x%04x", hdev->name, setting);
+		}
+		hci_req_complete(hdev, status);
+		break;
+
 	case OCF_HOST_BUFFER_SIZE:
 		status = *((__u8 *) skb->data);
 		if (status) {
@@ -282,7 +318,7 @@
 		hdev->sco_pkts = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt);
 
 		BT_DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name,
-		    hdev->acl_mtu, hdev->sco_mtu, hdev->acl_pkts, hdev->sco_pkts);
+			    hdev->acl_mtu, hdev->sco_mtu, hdev->acl_pkts, hdev->sco_pkts);
 		break;
 
 	case OCF_READ_BD_ADDR:
diff -Nru a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
--- a/net/bluetooth/rfcomm/core.c	Wed Feb 11 22:14:30 2004
+++ b/net/bluetooth/rfcomm/core.c	Wed Feb 11 22:14:30 2004
@@ -1663,9 +1663,10 @@
 	nsock->sk->sk_state_change = rfcomm_l2state_change;
 
 	s = rfcomm_session_add(nsock, BT_OPEN);
-	if (s)
+	if (s) {
 		rfcomm_session_hold(s);
-	else
+		rfcomm_schedule(RFCOMM_SCHED_RX);
+	} else
 		sock_release(nsock);
 }
 
diff -Nru a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
--- a/net/bluetooth/rfcomm/tty.c	Wed Feb 11 22:14:31 2004
+++ b/net/bluetooth/rfcomm/tty.c	Wed Feb 11 22:14:31 2004
@@ -349,7 +349,7 @@
 	struct rfcomm_dev_list_req *dl;
 	struct rfcomm_dev_info *di;
 	struct list_head *p;
-	int n = 0, size;
+	int n = 0, size, err;
 	u16 dev_num;
 
 	BT_DBG("");
@@ -357,14 +357,11 @@
 	if (get_user(dev_num, (u16 *) arg))
 		return -EFAULT;
 
-	if (!dev_num)
+	if (!dev_num || dev_num > (PAGE_SIZE * 4) / sizeof(*di))
 		return -EINVAL;
 
 	size = sizeof(*dl) + dev_num * sizeof(*di);
 
-	if (verify_area(VERIFY_WRITE, (void *)arg, size))
-		return -EFAULT;
-
 	if (!(dl = kmalloc(size, GFP_KERNEL)))
 		return -ENOMEM;
 
@@ -389,9 +386,10 @@
 	dl->dev_num = n;
 	size = sizeof(*dl) + n * sizeof(*di);
 
-	copy_to_user((void *) arg, dl, size);
+	err = copy_to_user((void *) arg, dl, size);
 	kfree(dl);
-	return 0;
+
+	return err ? -EFAULT : 0;
 }
 
 static int rfcomm_get_dev_info(unsigned long arg)
@@ -563,8 +561,10 @@
 	set_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
 
 	err = rfcomm_dlc_open(dlc, &dev->src, &dev->dst, dev->channel);
-	if (err < 0)
+	if (err < 0) {
+		rfcomm_dev_put(dev);
 		return err;
+	}
 
 	/* Wait for DLC to connect */
 	add_wait_queue(&dev->wait, &wait);
@@ -588,6 +588,9 @@
 	}
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&dev->wait, &wait);
+
+	if (err < 0)
+		rfcomm_dev_put(dev);
 
 	return err;
 }