---

 /dev/null                            |  131 --
 arch/ppc/Kconfig                     |  179 ---
 arch/ppc/configs/g5_defconfig        | 1383 ++++++++++++++++++++++++
 arch/ppc/configs/pmac_defconfig      |  645 ++++++-----
 arch/ppc/kernel/Makefile             |    3 
 arch/ppc/kernel/cpu_setup_6xx.S      |   44 
 arch/ppc/kernel/cpu_setup_power4.S   |  182 +++
 arch/ppc/kernel/head.S               |   79 -
 arch/ppc/kernel/idle_power4.S        |   34 
 arch/ppc/kernel/misc.S               |    4 
 arch/ppc/kernel/pci.c                |  103 -
 arch/ppc/kernel/ppc_ksyms.c          |   15 
 arch/ppc/kernel/setup.c              |   34 
 arch/ppc/kernel/smp-tbsync.c         |  181 +++
 arch/ppc/kernel/smp.c                |   52 
 arch/ppc/mm/hashtable.S              |   41 
 arch/ppc/mm/init.c                   |    2 
 arch/ppc/mm/pgtable.c                |   10 
 arch/ppc/mm/ppc_mmu.c                |    7 
 arch/ppc/mm/tlb.c                    |   20 
 arch/ppc/platforms/Makefile          |    3 
 arch/ppc/platforms/pmac_backlight.c  |   11 
 arch/ppc/platforms/pmac_cpufreq.c    |  186 ++-
 arch/ppc/platforms/pmac_feature.c    |  683 ++++++++++--
 arch/ppc/platforms/pmac_low_i2c.c    |  513 +++++++++
 arch/ppc/platforms/pmac_nvram.c      |  523 ++++++---
 arch/ppc/platforms/pmac_pci.c        |  630 +++++++++--
 arch/ppc/platforms/pmac_pic.c        |   61 -
 arch/ppc/platforms/pmac_setup.c      |   23 
 arch/ppc/platforms/pmac_smp.c        |   97 +
 arch/ppc/platforms/pmac_time.c       |    8 
 arch/ppc/syslib/Makefile             |    1 
 arch/ppc/syslib/of_device.c          |    3 
 arch/ppc/syslib/open_pic.c           |   17 
 arch/ppc/syslib/open_pic2.c          |  716 ++++++++++++
 arch/ppc/syslib/prom.c               |   36 
 arch/ppc/syslib/prom_init.c          |  162 +-
 drivers/Kconfig                      |    2 
 drivers/block/swim3.c                |  168 +--
 drivers/char/Makefile                |    4 
 drivers/char/generic_nvram.c         |  145 ++
 drivers/char/keyboard.c              |   10 
 drivers/i2c/busses/i2c-keywest.c     |  359 ++++--
 drivers/i2c/busses/i2c-keywest.h     |   10 
 drivers/ide/ppc/pmac.c               |  250 +++-
 drivers/macintosh/Kconfig            |  148 ++
 drivers/macintosh/Makefile           |    6 
 drivers/macintosh/adb.c              |    9 
 drivers/macintosh/adbhid.c           |   71 +
 drivers/macintosh/macio_asic.c       |  281 ++++-
 drivers/macintosh/mediabay.c         |   79 -
 drivers/macintosh/therm_pm72.c       | 1241 ++++++++++++++++++++++
 drivers/macintosh/therm_pm72.h       |  236 ++++
 drivers/macintosh/therm_windtunnel.c |  456 ++++++++
 drivers/macintosh/via-pmu.c          |   55 
 drivers/net/bmac.c                   |  388 +++---
 drivers/scsi/mac53c94.c              |  503 ++++----
 drivers/scsi/mesh.c                  | 1958 +++++++++++++++++------------------
 drivers/serial/pmac_zilog.c          |   89 -
 include/asm-ppc/delay.h              |    4 
 include/asm-ppc/keylargo.h           |   45 
 include/asm-ppc/machdep.h            |    3 
 include/asm-ppc/macio.h              |   71 +
 include/asm-ppc/nvram.h              |   25 
 include/asm-ppc/open_pic.h           |   27 
 include/asm-ppc/pgtable.h            |   14 
 include/asm-ppc/pmac_feature.h       |   17 
 include/asm-ppc/pmac_low_i2c.h       |   43 
 include/asm-ppc/reg.h                |    4 
 include/asm-ppc/uninorth.h           |   36 
 include/linux/pci_ids.h              |    6 
 71 files changed, 10329 insertions(+), 3256 deletions(-)

diff -puN /dev/null arch/ppc/configs/g5_defconfig
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/arch/ppc/configs/g5_defconfig	2004-01-28 23:09:16.000000000 -0800
@@ -0,0 +1,1383 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_MMU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_CLEAN_COMPILE is not set
+# CONFIG_STANDALONE is not set
+CONFIG_BROKEN=y
+CONFIG_BROKEN_ON_SMP=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=y
+
+#
+# Processor
+#
+# CONFIG_6xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+CONFIG_POWER4=y
+# CONFIG_8xx is not set
+CONFIG_ALTIVEC=y
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+CONFIG_PPC64BRIDGE=y
+CONFIG_PPC_STD_MMU=y
+
+#
+# Platform options
+#
+CONFIG_PPC_MULTIPLATFORM=y
+# CONFIG_APUS is not set
+# CONFIG_WILLOW is not set
+# CONFIG_PCORE is not set
+# CONFIG_POWERPMC250 is not set
+# CONFIG_EV64260 is not set
+# CONFIG_SPRUCE is not set
+# CONFIG_LOPEC is not set
+# CONFIG_MCPN765 is not set
+# CONFIG_MVME5100 is not set
+# CONFIG_PPLUS is not set
+# CONFIG_PRPMC750 is not set
+# CONFIG_PRPMC800 is not set
+# CONFIG_SANDPOINT is not set
+# CONFIG_ADIR is not set
+# CONFIG_K2 is not set
+# CONFIG_PAL4 is not set
+# CONFIG_GEMINI is not set
+# CONFIG_EST8260 is not set
+# CONFIG_SBS8260 is not set
+# CONFIG_RPX6 is not set
+# CONFIG_TQM8260 is not set
+CONFIG_PPC_CHRP=y
+CONFIG_PPC_PMAC=y
+CONFIG_PPC_PREP=y
+CONFIG_PPC_OF=y
+CONFIG_PPCBUG_NVRAM=y
+CONFIG_SMP=y
+CONFIG_IRQ_ALL_CPUS=y
+CONFIG_NR_CPUS=4
+CONFIG_HIGHMEM=y
+CONFIG_KERNEL_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_PPC_RTAS is not set
+# CONFIG_PREP_RESIDUAL is not set
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Bus options
+#
+# CONFIG_ISA is not set
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_LEGACY_PROC is not set
+CONFIG_PCI_NAMES=y
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=m
+CONFIG_YENTA=m
+CONFIG_CARDBUS=y
+# CONFIG_I82092 is not set
+# CONFIG_TCIC is not set
+
+#
+# Advanced setup
+#
+CONFIG_ADVANCED_OPTIONS=y
+# CONFIG_HIGHMEM_START_BOOL is not set
+CONFIG_HIGHMEM_START=0xfe000000
+# CONFIG_LOWMEM_SIZE_BOOL is not set
+CONFIG_LOWMEM_SIZE=0x30000000
+# CONFIG_KERNEL_START_BOOL is not set
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE_BOOL=y
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# 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
+#
+# CONFIG_PNP is not set
+
+#
+# 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=y
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_LBD is not set
+
+#
+# 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_IDECS is not set
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+CONFIG_BLK_DEV_IDEFLOPPY=y
+CONFIG_BLK_DEV_IDESCSI=y
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# 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_IDEDMA_PCI_WIP 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=y
+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 is not set
+# CONFIG_SCSI_REPORT_LUNS is not set
+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=y
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
+CONFIG_AIC7XXX_DEBUG_ENABLE=y
+CONFIG_AIC7XXX_DEBUG_MASK=0
+CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O 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_SIL 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_INITIO 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_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I 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_CONFIG=y
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# CONFIG_SCSI_QLA23XX 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
+# CONFIG_SCSI_MESH is not set
+# CONFIG_SCSI_MAC53C94 is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+CONFIG_IEEE1394=y
+
+#
+# Subsystem Options
+#
+# CONFIG_IEEE1394_VERBOSEDEBUG is not set
+CONFIG_IEEE1394_OUI_DB=y
+
+#
+# Device Drivers
+#
+# CONFIG_IEEE1394_PCILYNX is not set
+CONFIG_IEEE1394_OHCI1394=y
+
+#
+# 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
+#
+# CONFIG_I2O is not set
+
+#
+# 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=y
+CONFIG_MAC_EMUMOUSEBTN=y
+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=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+# CONFIG_IP_NF_NAT_LOCAL is not set
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_CLASSIFY=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IPV6_SCTP__=y
+CONFIG_IP_SCTP=y
+# CONFIG_SCTP_ADLER32 is not set
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+CONFIG_SCTP_HMAC_SHA1=y
+# CONFIG_SCTP_HMAC_MD5 is not set
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+CONFIG_ATM_CLIP_NO_ICMP=y
+# CONFIG_ATM_LANE is not set
+CONFIG_ATM_BR2684=m
+# CONFIG_ATM_BR2684_IPFILTER 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 is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# 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=y
+CONFIG_DE2104X=y
+CONFIG_TULIP=y
+# CONFIG_TULIP_MWI is not set
+CONFIG_TULIP_MMIO=y
+# CONFIG_DE4X5 is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_DM9102 is not set
+# CONFIG_PCMCIA_XIRCOM is not set
+# CONFIG_PCMCIA_XIRTULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# 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 is not set
+# 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_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 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=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+CONFIG_PPPOATM=m
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+# CONFIG_PCMCIA_WAVELAN is not set
+# CONFIG_PCMCIA_NETWAVE is not set
+
+#
+# Wireless 802.11 Frequency Hopping cards support
+#
+# CONFIG_PCMCIA_RAYCS is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+# CONFIG_AIRO is not set
+CONFIG_HERMES=m
+CONFIG_APPLE_AIRPORT=m
+CONFIG_PLX_HERMES=m
+CONFIG_TMD_HERMES=m
+CONFIG_PCI_HERMES=m
+
+#
+# Wireless 802.11b Pcmcia/Cardbus cards support
+#
+# CONFIG_PCMCIA_HERMES is not set
+CONFIG_AIRO_CS=m
+# CONFIG_PCMCIA_ATMEL is not set
+# CONFIG_PCMCIA_WL3501 is not set
+CONFIG_NET_WIRELESS=y
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# PCMCIA network device support
+#
+# CONFIG_NET_PCMCIA is not set
+
+#
+# ATM drivers
+#
+# CONFIG_ATM_TCP is not set
+# CONFIG_ATM_LANAI is not set
+# CONFIG_ATM_ENI is not set
+# CONFIG_ATM_FIRESTREAM is not set
+# CONFIG_ATM_ZATM is not set
+# CONFIG_ATM_NICSTAR is not set
+# CONFIG_ATM_IDT77252 is not set
+# CONFIG_ATM_AMBASSADOR is not set
+# CONFIG_ATM_HORIZON is not set
+# CONFIG_ATM_IA is not set
+# CONFIG_ATM_FORE200E_MAYBE is not set
+# CONFIG_ATM_HE is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# Bluetooth support
+#
+CONFIG_BT=m
+CONFIG_BT_L2CAP=m
+CONFIG_BT_SCO=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIUSB=m
+# CONFIG_BT_HCIUSB_SCO is not set
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_BCSP_TXCRC=y
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIDTL1 is not set
+# CONFIG_BT_HCIBT3C is not set
+# CONFIG_BT_HCIBLUECARD is not set
+CONFIG_BT_HCIBTUART=m
+# CONFIG_BT_HCIVHCI 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=y
+CONFIG_INPUT_EVBUG=m
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+# CONFIG_SERIO is not set
+# CONFIG_SERIO_I8042 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=y
+# CONFIG_JOYSTICK_IFORCE is not set
+# CONFIG_JOYSTICK_WARRIOR is not set
+# CONFIG_JOYSTICK_MAGELLAN is not set
+# CONFIG_JOYSTICK_SPACEORB is not set
+# CONFIG_JOYSTICK_SPACEBALL is not set
+# CONFIG_JOYSTICK_STINGER is not set
+# CONFIG_JOYSTICK_TWIDDLER is not set
+# CONFIG_INPUT_JOYDUMP is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_PCSPKR is not set
+CONFIG_INPUT_UINPUT=m
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=m
+CONFIG_SERIAL_8250_CS=m
+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=y
+CONFIG_SERIAL_PMACZILOG_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# Mice
+#
+CONFIG_BUSMOUSE=y
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_NVRAM=y
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X 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_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# 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_PIIX4 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_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_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# 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_PM3 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=m
+CONFIG_DMASOUND_PMAC=m
+CONFIG_DMASOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_OSSEMUL is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# PCI devices
+#
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_YMFPCI is not set
+# CONFIG_SND_ALS4000 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VX222 is not set
+
+#
+# ALSA PowerMac devices
+#
+CONFIG_SND_POWERMAC=m
+
+#
+# ALSA USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+
+#
+# PCMCIA devices
+#
+# CONFIG_SND_VXPOCKET is not set
+# CONFIG_SND_VXP440 is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME 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_AUDIO=m
+
+#
+# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem
+#
+CONFIG_USB_MIDI=m
+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=m
+# 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_SCANNER=m
+# 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 is not set
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+CONFIG_USB_SERIAL_VISOR=m
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+CONFIG_USB_SERIAL_KEYSPAN=m
+# CONFIG_USB_SERIAL_KEYSPAN_MPR is not set
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+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 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+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_SPEEDTOUCH is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# 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_XFS_FS=y
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_POSIX_ACL is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=y
+CONFIG_UDF_FS=m
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+# 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 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=m
+# 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 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V4 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_GSS is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT 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=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL 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=m
+# 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
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_SLAB=y
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_HIGHMEM=y
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_KGDB is not set
+CONFIG_XMON=y
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_DEBUG_INFO is not set
+CONFIG_BOOTX_TEXT=y
+
+#
+# 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=y
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_DES=y
+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=y
+# CONFIG_CRYPTO_TEST is not set
diff -puN arch/ppc/configs/pmac_defconfig~big-pmac-3 arch/ppc/configs/pmac_defconfig
--- 25/arch/ppc/configs/pmac_defconfig~big-pmac-3	2004-01-28 23:09:15.000000000 -0800
+++ 25-akpm/arch/ppc/configs/pmac_defconfig	2004-01-28 23:09:16.000000000 -0800
@@ -6,13 +6,15 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_HAVE_DEC_LOCK=y
 CONFIG_PPC=y
 CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
+# CONFIG_CLEAN_COMPILE is not set
 # CONFIG_STANDALONE is not set
+CONFIG_BROKEN=y
 CONFIG_BROKEN_ON_SMP=y
 
 #
@@ -23,8 +25,7 @@ CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 CONFIG_LOG_BUF_SHIFT=14
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
+# CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
 CONFIG_FUTEX=y
@@ -32,6 +33,7 @@ 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
@@ -53,16 +55,15 @@ CONFIG_6xx=y
 # CONFIG_POWER4 is not set
 # CONFIG_8xx is not set
 CONFIG_ALTIVEC=y
-CONFIG_TAU=y
-# CONFIG_TAU_INT is not set
-# CONFIG_TAU_AVERAGE is not set
+# CONFIG_TAU is not set
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_PROC_INTF=y
 CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
 # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
 CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
-# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
-# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_24_API=y
 CONFIG_CPU_FREQ_PMAC=y
 CONFIG_CPU_FREQ_TABLE=y
 CONFIG_PPC601_SYNC_FIX=y
@@ -101,7 +102,7 @@ CONFIG_PPC_OF=y
 CONFIG_PPCBUG_NVRAM=y
 # CONFIG_SMP is not set
 # CONFIG_PREEMPT is not set
-# CONFIG_HIGHMEM is not set
+CONFIG_HIGHMEM=y
 CONFIG_KERNEL_ELF=y
 CONFIG_BINFMT_ELF=y
 CONFIG_BINFMT_MISC=m
@@ -131,14 +132,10 @@ CONFIG_I82092=m
 CONFIG_TCIC=m
 
 #
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
 # Advanced setup
 #
 CONFIG_ADVANCED_OPTIONS=y
+# CONFIG_HIGHMEM_START_BOOL is not set
 CONFIG_HIGHMEM_START=0xfe000000
 # CONFIG_LOWMEM_SIZE_BOOL is not set
 CONFIG_LOWMEM_SIZE=0x30000000
@@ -149,6 +146,10 @@ CONFIG_TASK_SIZE=0xc0000000
 CONFIG_BOOT_LOAD=0x00800000
 
 #
+# Device Drivers
+#
+
+#
 # Generic Driver Options
 #
 # CONFIG_FW_LOADER is not set
@@ -159,6 +160,11 @@ CONFIG_BOOT_LOAD=0x00800000
 # CONFIG_MTD is not set
 
 #
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
 # Plug and Play support
 #
 # CONFIG_PNP is not set
@@ -166,6 +172,7 @@ CONFIG_BOOT_LOAD=0x00800000
 #
 # 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
@@ -179,11 +186,6 @@ CONFIG_BLK_DEV_INITRD=y
 CONFIG_LBD=y
 
 #
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
 # ATA/ATAPI/MFM/RLL support
 #
 CONFIG_IDE=y
@@ -213,7 +215,6 @@ CONFIG_BLK_DEV_GENERIC=y
 # CONFIG_BLK_DEV_OPTI621 is not set
 CONFIG_BLK_DEV_SL82C105=y
 CONFIG_BLK_DEV_IDEDMA_PCI=y
-# CONFIG_BLK_DEV_IDE_TCQ is not set
 # CONFIG_BLK_DEV_IDEDMA_FORCED is not set
 CONFIG_IDEDMA_PCI_AUTO=y
 # CONFIG_IDEDMA_ONLYDISK is not set
@@ -284,15 +285,16 @@ CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_AIC7XXX=m
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=253
 CONFIG_AIC7XXX_RESET_DELAY_MS=15000
-# CONFIG_AIC7XXX_PROBE_EISA_VL is not set
 # CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
 CONFIG_AIC7XXX_DEBUG_ENABLE=y
 CONFIG_AIC7XXX_DEBUG_MASK=0
 CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
 CONFIG_SCSI_AIC7XXX_OLD=m
 # CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
 CONFIG_SCSI_ADVANSYS=m
 # 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
@@ -301,16 +303,24 @@ CONFIG_SCSI_ADVANSYS=m
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO 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_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I 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_CONFIG=y
+# CONFIG_SCSI_QLA21XX is not set
+# CONFIG_SCSI_QLA22XX is not set
+# CONFIG_SCSI_QLA23XX 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
 CONFIG_SCSI_MESH=y
@@ -327,6 +337,11 @@ CONFIG_SCSI_MAC53C94=y
 # CONFIG_PCMCIA_QLOGIC is not set
 
 #
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
 # Fusion MPT device support
 #
 # CONFIG_FUSION is not set
@@ -340,15 +355,12 @@ CONFIG_IEEE1394=m
 # Subsystem Options
 #
 # CONFIG_IEEE1394_VERBOSEDEBUG is not set
-# CONFIG_IEEE1394_OUI_DB is not set
+CONFIG_IEEE1394_OUI_DB=y
 
 #
 # Device Drivers
 #
-
-#
-# Texas Instruments PCILynx requires I2C bit-banging
-#
+CONFIG_IEEE1394_PCILYNX=m
 CONFIG_IEEE1394_OHCI1394=m
 
 #
@@ -368,6 +380,23 @@ CONFIG_IEEE1394_RAWIO=m
 # CONFIG_I2O is not set
 
 #
+# Macintosh device drivers
+#
+CONFIG_ADB_CUDA=y
+CONFIG_ADB_PMU=y
+CONFIG_PMAC_PBOOK=y
+CONFIG_PMAC_APM_EMU=y
+CONFIG_PMAC_BACKLIGHT=y
+# CONFIG_MAC_FLOPPY is not set
+# CONFIG_MAC_SERIAL is not set
+CONFIG_ADB=y
+CONFIG_ADB_MACIO=y
+CONFIG_INPUT_ADBHID=y
+CONFIG_MAC_EMUMOUSEBTN=y
+# CONFIG_THERM_WINDTUNNEL is not set
+# CONFIG_ANSLCD is not set
+
+#
 # Networking support
 #
 CONFIG_NET=y
@@ -513,10 +542,11 @@ CONFIG_SUNGEM=y
 # CONFIG_NET_TULIP is not set
 # CONFIG_HP100 is not set
 CONFIG_NET_PCI=y
-CONFIG_PCNET32=y
+# CONFIG_PCNET32 is not set
 # 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 is not set
@@ -543,7 +573,7 @@ CONFIG_PCNET32=y
 # CONFIG_R8169 is not set
 # CONFIG_SIS190 is not set
 # CONFIG_SK98LIN is not set
-# CONFIG_TIGON3 is not set
+CONFIG_TIGON3=y
 
 #
 # Ethernet (10000 Mbit)
@@ -557,8 +587,8 @@ CONFIG_PPP_MULTILINK=y
 CONFIG_PPP_ASYNC=y
 CONFIG_PPP_SYNC_TTY=m
 CONFIG_PPP_DEFLATE=y
-CONFIG_PPP_BSDCOMP=m
-# CONFIG_PPPOE is not set
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPPOE=m
 # CONFIG_SLIP is not set
 
 #
@@ -689,58 +719,9 @@ CONFIG_IRTTY_SIR=m
 # CONFIG_ISDN_BOOL is not set
 
 #
-# Graphics support
+# Telephony Support
 #
-CONFIG_FB=y
-# CONFIG_FB_CYBER2000 is not set
-CONFIG_FB_OF=y
-CONFIG_FB_CONTROL=y
-CONFIG_FB_PLATINUM=y
-CONFIG_FB_VALKYRIE=y
-CONFIG_FB_CT65550=y
-CONFIG_FB_IMSTT=y
-# 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 is not set
-CONFIG_FB_MATROX_G100A=y
-CONFIG_FB_MATROX_G100=y
-# CONFIG_FB_MATROX_MULTIHEAD is not set
-CONFIG_FB_RADEON=y
-CONFIG_FB_ATY128=y
-CONFIG_FB_ATY=y
-CONFIG_FB_ATY_CT=y
-CONFIG_FB_ATY_GX=y
-# CONFIG_FB_ATY_XL_INIT is not set
-# CONFIG_FB_SIS is not set
-# CONFIG_FB_NEOMAGIC is not set
-CONFIG_FB_3DFX=y
-# 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
+# CONFIG_PHONE is not set
 
 #
 # Input device support
@@ -764,11 +745,8 @@ CONFIG_INPUT_EVDEV=y
 #
 # CONFIG_GAMEPORT is not set
 CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
+# CONFIG_SERIO is not set
 # 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
@@ -786,22 +764,6 @@ CONFIG_INPUT_MOUSE=y
 # CONFIG_INPUT_MISC is not set
 
 #
-# Macintosh device drivers
-#
-CONFIG_ADB_CUDA=y
-CONFIG_ADB_PMU=y
-CONFIG_PMAC_PBOOK=y
-CONFIG_PMAC_APM_EMU=y
-CONFIG_PMAC_BACKLIGHT=y
-# CONFIG_MAC_FLOPPY is not set
-CONFIG_MAC_SERIAL=y
-CONFIG_ADB=y
-CONFIG_ADB_MACIO=y
-CONFIG_INPUT_ADBHID=y
-CONFIG_MAC_EMUMOUSEBTN=y
-# CONFIG_ANSLCD is not set
-
-#
 # Character devices
 #
 CONFIG_VT=y
@@ -821,56 +783,16 @@ CONFIG_SERIAL_8250_NR_UARTS=4
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_SERIAL_PMACZILOG=y
-# CONFIG_SERIAL_PMACZILOG_CONSOLE is not set
+CONFIG_SERIAL_PMACZILOG_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
 
 #
-# I2C support
-#
-CONFIG_I2C=m
-CONFIG_I2C_CHARDEV=m
-
-#
-# I2C Algorithms
-#
-# CONFIG_I2C_ALGOBIT is not set
-# 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_I801 is not set
-CONFIG_I2C_KEYWEST=m
-# CONFIG_I2C_NFORCE2 is not set
-# CONFIG_I2C_PIIX4 is not set
-# CONFIG_I2C_SIS5595 is not set
-# CONFIG_I2C_SIS630 is not set
-# CONFIG_I2C_SIS96X is not set
-# CONFIG_I2C_VIAPRO is not set
-
-#
-# I2C Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-# CONFIG_SENSORS_ADM1021 is not set
-# CONFIG_SENSORS_EEPROM is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_LM75 is not set
-# CONFIG_SENSORS_LM78 is not set
-# CONFIG_SENSORS_LM85 is not set
-# CONFIG_SENSORS_VIA686A is not set
-# CONFIG_SENSORS_W83781D is not set
-
-#
 # Mice
 #
-CONFIG_BUSMOUSE=y
+# CONFIG_BUSMOUSE is not set
 # CONFIG_QIC02_TAPE is not set
 
 #
@@ -884,7 +806,7 @@ CONFIG_BUSMOUSE=y
 # CONFIG_WATCHDOG is not set
 CONFIG_NVRAM=y
 CONFIG_GEN_RTC=y
-# CONFIG_GEN_RTC_X is not set
+CONFIG_GEN_RTC_X=y
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -893,8 +815,15 @@ CONFIG_GEN_RTC=y
 # Ftape, the floppy tape device driver
 #
 # CONFIG_FTAPE is not set
-# CONFIG_AGP is not set
-# CONFIG_DRM is not set
+CONFIG_AGP=m
+CONFIG_AGP_UNINORTH=m
+CONFIG_DRM=y
+# CONFIG_DRM_TDFX is not set
+# CONFIG_DRM_GAMMA is not set
+CONFIG_DRM_R128=m
+CONFIG_DRM_RADEON=m
+# CONFIG_DRM_MGA is not set
+# CONFIG_DRM_SIS is not set
 
 #
 # PCMCIA character devices
@@ -903,167 +832,131 @@ CONFIG_GEN_RTC=y
 # CONFIG_RAW_DRIVER is not set
 
 #
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
+# I2C support
 #
-# CONFIG_DVB is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
 
 #
-# File systems
+# I2C Algorithms
 #
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# 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_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 is not set
-# CONFIG_AUTOFS4_FS is not set
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
 
 #
-# CD-ROM/DVD Filesystems
+# I2C Hardware Bus support
 #
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
-# CONFIG_UDF_FS is not set
+# 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=m
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PIIX4 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
 
 #
-# DOS/FAT/NT Filesystems
+# I2C Hardware Sensors Chip support
 #
-CONFIG_FAT_FS=m
-CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
-# CONFIG_NTFS_FS is not set
+# 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_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
 
 #
-# Pseudo filesystems
+# Multimedia devices
 #
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_DEVFS_FS=y
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
+# CONFIG_VIDEO_DEV is not set
 
 #
-# Miscellaneous filesystems
+# Digital Video Broadcasting Devices
 #
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-CONFIG_HFS_FS=m
-# 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
+# CONFIG_DVB is not set
 
 #
-# Network File Systems
+# Graphics support
 #
-CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-CONFIG_NFSD=y
-# CONFIG_NFSD_V3 is not set
-# CONFIG_NFSD_TCP is not set
-CONFIG_LOCKD=y
-CONFIG_EXPORTFS=y
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_GSS is not set
-CONFIG_SMB_FS=m
-# CONFIG_SMB_NLS_DEFAULT is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_INTERMEZZO_FS is not set
-# CONFIG_AFS_FS is not set
+CONFIG_FB=y
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+CONFIG_FB_OF=y
+CONFIG_FB_CONTROL=y
+CONFIG_FB_PLATINUM=y
+CONFIG_FB_VALKYRIE=y
+CONFIG_FB_CT65550=y
+CONFIG_FB_IMSTT=y
+# CONFIG_FB_S3TRIO is not set
+# CONFIG_FB_VGA16 is not set
+CONFIG_FB_RIVA=y
+CONFIG_FB_MATROX=y
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+# CONFIG_FB_MATROX_G450 is not set
+CONFIG_FB_MATROX_G100A=y
+CONFIG_FB_MATROX_G100=y
+# CONFIG_FB_MATROX_I2C is not set
+# CONFIG_FB_MATROX_MULTIHEAD is not set
+CONFIG_FB_RADEON=y
+CONFIG_FB_ATY128=y
+CONFIG_FB_ATY=y
+CONFIG_FB_ATY_CT=y
+CONFIG_FB_ATY_GX=y
+# CONFIG_FB_ATY_XL_INIT is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+CONFIG_FB_3DFX=y
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_VIRTUAL is not set
 
 #
-# Partition Types
+# Console display driver support
 #
-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=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_MINIX_SUBPARTITION is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_UNIXWARE_DISKLABEL 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
-CONFIG_SMB_NLS=y
-CONFIG_NLS=y
+# 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
 
 #
-# Native Language Support
+# Logo configuration
 #
-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=m
-# 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
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
 
 #
 # Sound
@@ -1164,7 +1057,7 @@ CONFIG_USB_DYNAMIC_MINORS=y
 #
 # CONFIG_USB_EHCI_HCD is not set
 CONFIG_USB_OHCI_HCD=y
-# CONFIG_USB_UHCI_HCD is not set
+CONFIG_USB_UHCI_HCD=y
 
 #
 # USB Device Class drivers
@@ -1234,8 +1127,20 @@ CONFIG_USB_SERIAL_VISOR=m
 # CONFIG_USB_SERIAL_IR is not set
 # CONFIG_USB_SERIAL_EDGEPORT is not set
 # CONFIG_USB_SERIAL_EDGEPORT_TI is not set
-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
-# CONFIG_USB_SERIAL_KEYSPAN is not set
+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 is not set
 # CONFIG_USB_SERIAL_KOBIL_SCT is not set
 # CONFIG_USB_SERIAL_MCT_U232 is not set
@@ -1244,19 +1149,176 @@ CONFIG_USB_SERIAL_VISOR=m
 # CONFIG_USB_SERIAL_CYBERJACK is not set
 # CONFIG_USB_SERIAL_XIRCOM is not set
 # CONFIG_USB_SERIAL_OMNINET is not set
+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
 # CONFIG_USB_GADGET is not set
 
 #
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# 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_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 is not set
+# 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 is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+# 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 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=y
+# 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 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=y
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_LOCKD=y
+CONFIG_EXPORTFS=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_GSS is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_CIFS is not set
+# 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=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL 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=m
+# 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
+
+#
 # Library routines
 #
 CONFIG_CRC32=y
@@ -1266,7 +1328,16 @@ CONFIG_ZLIB_DEFLATE=y
 #
 # Kernel hacking
 #
-# CONFIG_DEBUG_KERNEL is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_KGDB is not set
+# CONFIG_XMON is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_DEBUG_INFO is not set
 CONFIG_BOOTX_TEXT=y
 
 #
diff -puN arch/ppc/Kconfig~big-pmac-3 arch/ppc/Kconfig
--- 25/arch/ppc/Kconfig~big-pmac-3	2004-01-28 23:09:15.000000000 -0800
+++ 25-akpm/arch/ppc/Kconfig	2004-01-28 23:09:16.000000000 -0800
@@ -30,6 +30,10 @@ config PPC32
 	bool
 	default y
 
+# All PPCs use generic nvram driver through ppc_md
+config GENERIC_NVRAM
+	bool
+	default y
 
 source "init/Kconfig"
 
@@ -989,8 +993,6 @@ config HOTPLUG
 
 source "drivers/pcmcia/Kconfig"
 
-source "drivers/parport/Kconfig"
-
 endmenu
 
 menu "Advanced setup"
@@ -1088,179 +1090,10 @@ config PIN_TLB
 	depends on ADVANCED_OPTIONS && 8xx
 endmenu
 
-source "drivers/base/Kconfig"
-
-source "drivers/mtd/Kconfig"
-
-source "drivers/pnp/Kconfig"
-
-source "drivers/block/Kconfig"
-
-source "drivers/md/Kconfig"
-
-source "drivers/ide/Kconfig"
-
-source "drivers/scsi/Kconfig"
-
-source "drivers/message/fusion/Kconfig"
-
-source "drivers/ieee1394/Kconfig"
-
-source "drivers/message/i2o/Kconfig"
-
-source "net/Kconfig"
-
-source "drivers/isdn/Kconfig"
-
-source "drivers/video/Kconfig"
-
-source "drivers/cdrom/Kconfig"
-
-source "drivers/input/Kconfig"
-
-
-menu "Macintosh device drivers"
-
-# 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
-	help
-	  This provides support for CUDA based Power Macintosh systems.  This
-	  includes most OldWorld PowerMacs, the first generation iMacs, the
-	  Blue&White G3 and the "Yikes" G4 (PCI Graphics).  All later models
-	  should use CONFIG_ADB_PMU instead.  It is safe to say Y here even if
-	  your machine doesn't have a CUDA.
-
-	  If unsure say Y.
-
-config ADB_PMU
-	bool "Support for PMU  based PowerMacs"
-	depends on PPC_PMAC
-	help
-	  On PowerBooks, iBooks, and recent iMacs and Power Macintoshes, the
-	  PMU is an embedded microprocessor whose primary function is to
-	  control system power, and battery charging on the portable models.
-	  The PMU also controls the ADB (Apple Desktop Bus) which connects to
-	  the keyboard and mouse on some machines, as well as the non-volatile
-	  RAM and the RTC (real time clock) chip.  Say Y to enable support for
-	  this device; you should do so if your machine is one of those
-	  mentioned above.
-
-config PMAC_PBOOK
-	bool "Power management support for PowerBooks"
-	depends on ADB_PMU
-	---help---
-	  This provides support for putting a PowerBook to sleep; it also
-	  enables media bay support.  Power management works on the
-	  PB2400/3400/3500, Wallstreet, Lombard, and Bronze PowerBook G3 and
-	  the Titanium Powerbook G4, as well as the iBooks.  You should get
-	  the power management daemon, pmud, to make it work and you must have
-	  the /dev/pmu device (see the pmud README).
-
-	  Get pmud from <ftp://ftp.samba.org/pub/ppclinux/pmud/>.
-
-	  If you have a PowerBook, you should say Y here.
-
-	  You may also want to compile the dma sound driver as a module and
-	  have it autoloaded. The act of removing the module shuts down the
-	  sound hardware for more power savings.
-
-config PM
-	bool
-	depends on PPC_PMAC && ADB_PMU && PMAC_PBOOK
-	default y
-
-config PMAC_APM_EMU
-	tristate "APM emulation"
-	depends on PMAC_PBOOK
-
-# made a separate option since backlight may end up beeing used
-# on non-powerbook machines (but only on PMU based ones AFAIK)
-config PMAC_BACKLIGHT
-	bool "Backlight control for LCD screens"
-	depends on ADB_PMU
-	help
-	  Say Y here to build in code to manage the LCD backlight on a
-	  Macintosh PowerBook.  With this code, the backlight will be turned
-	  on and off appropriately on power-management and lid-open/lid-closed
-	  events; also, the PowerBook button device will be enabled so you can
-	  change the screen brightness.
-
-config MAC_FLOPPY
-	bool "Support for PowerMac floppy"
-	depends on PPC_PMAC
-	help
-	  If you have a SWIM-3 (Super Woz Integrated Machine 3; from Apple)
-	  floppy controller, say Y here. Most commonly found in PowerMacs.
-
-config MAC_SERIAL
-	tristate "Support for PowerMac serial ports (OBSOLETE DRIVER)"
-	depends on PPC_PMAC
-	help
-	  This driver is obsolete. Use CONFIG_SERIAL_PMACZILOG in
-	  "Character devices --> Serial drivers --> PowerMac z85c30" option.
-
-config ADB
-	bool "Apple Desktop Bus (ADB) support"
-	depends on PPC_PMAC
-	help
-	  Apple Desktop Bus (ADB) support is for support of devices which
-	  are connected to an ADB port.  ADB devices tend to have 4 pins.
-	  If you have an Apple Macintosh prior to the iMac, an iBook or
-	  PowerBook, or a "Blue and White G3", you probably want to say Y
-	  here.  Otherwise say N.
-
-config ADB_MACIO
-	bool "Include MacIO (CHRP) ADB driver"
-	depends on ADB
-	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
-	  also includes a MESH II SCSI controller, DBDMA controller, VIA chip,
-	  OpenPIC controller and two RS422/Geoports.)
-
-config INPUT_ADBHID
-	bool "Support for ADB input devices (keyboard, mice, ...)"
-	depends on ADB && INPUT=y
-	help
-	  Say Y here if you want to have ADB (Apple Desktop Bus) HID devices
-	  such as keyboards, mice, joysticks, trackpads  or graphic tablets
-	  handled by the input layer.  If you say Y here, make sure to say Y to
-	  the corresponding drivers "Keyboard support" (CONFIG_INPUT_KEYBDEV),
-	  "Mouse Support" (CONFIG_INPUT_MOUSEDEV) and "Event interface
-	  support" (CONFIG_INPUT_EVDEV) as well.
-
-	  If unsure, say Y.
-
-config MAC_EMUMOUSEBTN
-	bool "Support for mouse button 2+3 emulation"
-	depends on INPUT_ADBHID
-	help
-	  This provides generic support for emulating the 2nd and 3rd mouse
-	  button with keypresses.  If you say Y here, the emulation is still
-	  disabled by default.  The emulation is controlled by these sysctl
-	  entries:
-	  /proc/sys/dev/mac_hid/mouse_button_emulation
-	  /proc/sys/dev/mac_hid/mouse_button2_keycode
-	  /proc/sys/dev/mac_hid/mouse_button3_keycode
-
-	  If you have an Apple machine with a 1-button mouse, say Y here.
-
-config ANSLCD
-	bool "Support for ANS LCD display"
-	depends on ADB_CUDA
-
-endmenu
-
-source "drivers/char/Kconfig"
-
-source "drivers/media/Kconfig"
+source "drivers/Kconfig"
 
 source "fs/Kconfig"
 
-source "sound/Kconfig"
-
 source "arch/ppc/8xx_io/Kconfig"
 
 source "arch/ppc/8260_io/Kconfig"
@@ -1285,8 +1118,6 @@ config SERIAL_SICC_CONSOLE
 
 endmenu
 
-source "drivers/usb/Kconfig"
-
 source "lib/Kconfig"
 
 
diff -puN arch/ppc/kernel/cpu_setup_6xx.S~big-pmac-3 arch/ppc/kernel/cpu_setup_6xx.S
--- 25/arch/ppc/kernel/cpu_setup_6xx.S~big-pmac-3	2004-01-28 23:09:15.000000000 -0800
+++ 25-akpm/arch/ppc/kernel/cpu_setup_6xx.S	2004-01-28 23:09:16.000000000 -0800
@@ -142,7 +142,7 @@ setup_7410_workarounds:
 	sync
 	isync
 	blr
-	
+
 /* 740/750/7400/7410
  * Enable Store Gathering (SGE), Address Brodcast (ABE),
  * Branch History Table (BHTE), Branch Target ICache (BTIC)
@@ -213,7 +213,7 @@ setup_745x_specifics:
 	li	r7,CPU_FTR_CAN_NAP
 	andc	r6,r6,r7
 	stw	r6,CPU_SPEC_FEATURES(r5)
-1:	
+1:
 	mfspr	r11,HID0
 
 	/* All of the bits we have to set.....
@@ -248,20 +248,21 @@ END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM)
 /* Definitions for the table use to save CPU states */
 #define CS_HID0		0
 #define CS_HID1		4
-#define	CS_MSSCR0	8
-#define CS_MSSSR0	12
-#define CS_ICTRL	16
-#define CS_LDSTCR	20
-#define CS_LDSTDB	24
-#define CS_SIZE		28
+#define CS_HID2		8
+#define	CS_MSSCR0	12
+#define CS_MSSSR0	16
+#define CS_ICTRL	20
+#define CS_LDSTCR	24
+#define CS_LDSTDB	28
+#define CS_SIZE		32
 
 	.data
 	.balign	L1_CACHE_LINE_SIZE
-cpu_state_storage:	
+cpu_state_storage:
 	.space	CS_SIZE
 	.balign	L1_CACHE_LINE_SIZE,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
@@ -311,11 +312,18 @@ _GLOBAL(__save_cpu_setup)
 	stw	r4,CS_LDSTCR(r5)
 	mfspr	r4,SPRN_LDSTDB
 	stw	r4,CS_LDSTDB(r5)
-1:	
+1:
 	bne	cr5,1f
 	/* Backup 750FX specific registers */
 	mfspr	r4,SPRN_HID1
 	stw	r4,CS_HID1(r5)
+	/* If rev 2.x, backup HID2 */
+	mfspr	r3,PVR
+	andi.	r3,r3,0xff00
+	cmpi	cr0,r3,0x0200
+	bne	1f
+	mfspr	r4,SPRN_HID2
+	stw	r4,CS_HID2(r5)
 1:
 	mtcr	r7
 	blr
@@ -395,9 +403,19 @@ _GLOBAL(__restore_cpu_setup)
 	sync
 2:	bne	cr5,1f
 	/* Restore 750FX specific registers
-	 * that is restore PLL config & switch
-	 * to PLL 0
+	 * that is restore HID2 on rev 2.x and PLL config & switch
+	 * to PLL 0 on all
 	 */
+	/* If rev 2.x, restore HID2 with low voltage bit cleared */
+	mfspr	r3,PVR
+	andi.	r3,r3,0xff00
+	cmpi	cr0,r3,0x0200
+	bne	4f
+	lwz	r4,CS_HID2(r5)
+	rlwinm	r4,r4,0,19,17
+	mtspr	SPRN_HID2,r4
+	sync
+4:
 	lwz	r4,CS_HID1(r5)
 	rlwinm  r5,r4,0,16,14
 	mtspr	SPRN_HID1,r5
diff -puN /dev/null arch/ppc/kernel/cpu_setup_power4.S
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/arch/ppc/kernel/cpu_setup_power4.S	2004-01-28 23:09:16.000000000 -0800
@@ -0,0 +1,182 @@
+/*
+ * 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_LINE_SIZE
+cpu_state_storage:	
+	.space	CS_SIZE
+	.balign	L1_CACHE_LINE_SIZE,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 */
+	lis	r5,cpu_state_storage@h
+	ori	r5,r5,cpu_state_storage@l
+
+	/* 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)
+	/* Some CR fields are volatile, we back it up all */
+	mfcr	r7
+
+	/* Get storage ptr */
+	lis	r5,(cpu_state_storage-KERNELBASE)@h
+	ori	r5,r5,cpu_state_storage@l
+
+	/* 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:
+	mtcr	r7
+	blr
+
diff -puN arch/ppc/kernel/head.S~big-pmac-3 arch/ppc/kernel/head.S
--- 25/arch/ppc/kernel/head.S~big-pmac-3	2004-01-28 23:09:15.000000000 -0800
+++ 25-akpm/arch/ppc/kernel/head.S	2004-01-28 23:09:16.000000000 -0800
@@ -141,17 +141,6 @@ __start:
 	mr	r27,r7
 	li	r24,0			/* cpu # */
 
-#ifdef CONFIG_POWER4
-/*
- * 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
-	beql	ppc970_setup_hid
-#endif /* CONFIG_POWER4 */
-
 /*
  * early_init() does the early machine identification and does
  * the necessary low-level setup and clears the BSS
@@ -159,6 +148,14 @@ __start:
  */
 	bl	early_init
 
+/*
+ * On POWER4, we first need to tweak some CPU configuration registers
+ * like real mode cache inhibit or exception base
+ */
+#ifdef CONFIG_POWER4
+	bl	__power4_cpu_preinit
+#endif /* CONFIG_POWER4 */
+
 #ifdef CONFIG_APUS
 /* On APUS the __va/__pa constants need to be set to the correct
  * values before continuing.
@@ -1216,7 +1213,7 @@ __secondary_start_psurge99:
 __secondary_start:
 #ifdef CONFIG_PPC64BRIDGE
 	mfmsr	r0
-	clrldi	r0,r0,1		/* make sure it's in 32-bit mode */
+	clrldi	r0,r0,1			/* make sure it's in 32-bit mode */
 	SYNC
 	MTMSRD(r0)
 	isync
@@ -1278,26 +1275,15 @@ __secondary_start:
  */
 _GLOBAL(__setup_cpu_power3)
 	blr
-_GLOBAL(__setup_cpu_power4)
-	blr
-_GLOBAL(__setup_cpu_ppc970)
-	blr
 _GLOBAL(__setup_cpu_generic)
 	blr
 
-#ifndef CONFIG_6xx
+#if !defined(CONFIG_6xx) && !defined(CONFIG_POWER4)
 _GLOBAL(__save_cpu_setup)
 	blr
 _GLOBAL(__restore_cpu_setup)
-#ifdef CONFIG_POWER4
-	/* turn off real-mode cache inhibit on the PPC970 */
-	mfspr	r0,SPRN_PVR
-	srwi	r0,r0,16
-	cmpwi	r0,0x39
-	beq	ppc970_setup_hid
-#endif
 	blr
-#endif /* CONFIG_6xx */
+#endif /* !defined(CONFIG_6xx) && !defined(CONFIG_POWER4) */
 
 
 /*
@@ -1633,10 +1619,14 @@ initial_mm_power4:
 	lis	r4,0x2000		/* set pseudo-segment reg 12 */
 	ori	r5,r4,0x0ccc
 	mtsr	12,r5
+#if 0
 	ori	r5,r4,0x0888		/* set pseudo-segment reg 8 */
 	mtsr	8,r5			/* (for access to serial port) */
-	ori	r5,r4,0x0999		/* set pseudo-segment reg 8 */
+#endif
+#ifdef CONFIG_BOOTX_TEXT
+	ori	r5,r4,0x0999		/* set pseudo-segment reg 9 */
 	mtsr	9,r5			/* (for access to screen) */
+#endif
 	mfmsr	r0
 	clrldi	r0,r0,1
 	sync
@@ -1644,43 +1634,8 @@ initial_mm_power4:
 	isync
 	blr
 
-/*
- * On 970 (G5), we pre-set a few bits in HID0 & HID1
- */
-ppc970_setup_hid:
-	li	r0,0
-	sync
-	mtspr	0x3f4,r0
-	isync
-	sync
-	mtspr	0x3f6,r0
-	isync
-	mfspr	r0,SPRN_HID0
-	li	r11,1			/* clear DOZE, NAP and SLEEP */
-	rldimi	r0,r11,52,8		/* set 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
-	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	0x137,0
-	isync
-	blr
 #endif /* CONFIG_POWER4 */
-
+	
 #ifdef CONFIG_8260
 /* Jump into the system reset for the rom.
  * We first disable the MMU, and then jump to the ROM reset address.
diff -puN arch/ppc/kernel/idle_power4.S~big-pmac-3 arch/ppc/kernel/idle_power4.S
--- 25/arch/ppc/kernel/idle_power4.S~big-pmac-3	2004-01-28 23:09:15.000000000 -0800
+++ 25-akpm/arch/ppc/kernel/idle_power4.S	2004-01-28 23:09:16.000000000 -0800
@@ -28,17 +28,11 @@
 
 /*
  * Init idle, called at early CPU setup time from head.S for each CPU
- * Make sure no rest of NAP mode remains in HID0, save default
- * values for some CPU specific registers. Called with r24
- * containing CPU number and r3 reloc offset
+ * So nothing for now. Called with r24 containing CPU number and r3
+ * reloc offset
  */
  	.globl	init_idle_power4
 init_idle_power4:
-BEGIN_FTR_SECTION
-	mfspr	r4,SPRN_HID0
-	rlwinm	r4,r4,0,10,8	/* Clear NAP */
-	mtspr	SPRN_HID0, r4
-END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
 	blr
 
 /*
@@ -48,10 +42,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
  */
 	.globl	power4_idle
 power4_idle:
-	/* Check if we can nap or doze, put HID0 mask in r3
-	 */
-	lis	r3, 0
 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
 	 */
@@ -59,16 +52,11 @@ BEGIN_FTR_SECTION
 	lwz	r4,cur_cpu_spec@l(r4)
 	lwz	r4,CPU_SPEC_FEATURES(r4)
 	andi.	r0,r4,CPU_FTR_CAN_NAP
-	beq	1f
+	beqlr
 	/* Now check if user or arch enabled NAP mode */
 	lis	r4,powersave_nap@ha
 	lwz	r4,powersave_nap@l(r4)
 	cmpi	0,r4,0
-	beq	1f
-	lis	r3,HID0_NAP@h
-1:	
-END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
-	cmpi	0,r3,0
 	beqlr
 
 	/* Clear MSR:EE */
@@ -85,18 +73,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
 	blr
 1:	
 	/* Go to NAP now */	
-	mfspr	r4,SPRN_HID0
-	lis	r5,(HID0_NAP|HID0_SLEEP)@h
-	andc	r4,r4,r5
-	or	r4,r4,r3
-	oris	r4,r4,HID0_DPM@h	/* that should be done once for all  */
-	mtspr	SPRN_HID0,r4
-	mfspr	r0,SPRN_HID0
-	mfspr	r0,SPRN_HID0
-	mfspr	r0,SPRN_HID0
-	mfspr	r0,SPRN_HID0
-	mfspr	r0,SPRN_HID0
-	mfspr	r0,SPRN_HID0
 BEGIN_FTR_SECTION
 	DSSALL
 	sync
diff -puN arch/ppc/kernel/Makefile~big-pmac-3 arch/ppc/kernel/Makefile
--- 25/arch/ppc/kernel/Makefile~big-pmac-3	2004-01-28 23:09:15.000000000 -0800
+++ 25-akpm/arch/ppc/kernel/Makefile	2004-01-28 23:09:16.000000000 -0800
@@ -22,11 +22,12 @@ obj-y				:= entry.o traps.o irq.o idle.o
 					semaphore.o syscalls.o setup.o \
 					cputable.o ppc_htab.o
 obj-$(CONFIG_6xx)		+= l2cr.o cpu_setup_6xx.o
+obj-$(CONFIG_POWER4)		+= cpu_setup_power4.o
 obj-$(CONFIG_MODULES)		+= module.o ppc_ksyms.o
 obj-$(CONFIG_PCI)		+= pci.o
 obj-$(CONFIG_PCI)		+= pci-dma.o
 obj-$(CONFIG_KGDB)		+= ppc-stub.o
-obj-$(CONFIG_SMP)		+= smp.o
+obj-$(CONFIG_SMP)		+= smp.o smp-tbsync.o
 obj-$(CONFIG_TAU)		+= temp.o
 
 ifdef CONFIG_MATH_EMULATION
diff -puN arch/ppc/kernel/misc.S~big-pmac-3 arch/ppc/kernel/misc.S
--- 25/arch/ppc/kernel/misc.S~big-pmac-3	2004-01-28 23:09:15.000000000 -0800
+++ 25-akpm/arch/ppc/kernel/misc.S	2004-01-28 23:09:16.000000000 -0800
@@ -201,7 +201,7 @@ _GLOBAL(call_setup_cpu)
 	mr	r4,r24
 	bctr
 
-#ifdef CONFIG_CPU_FREQ_PMAC
+#if defined(CONFIG_CPU_FREQ_PMAC) && defined(CONFIG_6xx)
 
 /* This gets called by via-pmu.c to switch the PLL selection
  * on 750fx CPU. This function should really be moved to some
@@ -253,7 +253,7 @@ _GLOBAL(low_choose_750fx_pll)
 	mtmsr	r7
 	blr
 
-#endif /* CONFIG_CPU_FREQ_PMAC */
+#endif /* CONFIG_CPU_FREQ_PMAC && CONFIG_6xx */
 
 /* void local_save_flags_ptr(unsigned long *flags) */
 _GLOBAL(local_save_flags_ptr)
diff -puN arch/ppc/kernel/pci.c~big-pmac-3 arch/ppc/kernel/pci.c
--- 25/arch/ppc/kernel/pci.c~big-pmac-3	2004-01-28 23:09:15.000000000 -0800
+++ 25-akpm/arch/ppc/kernel/pci.c	2004-01-28 23:09:16.000000000 -0800
@@ -46,7 +46,9 @@ static int reparent_resources(struct res
 static void fixup_rev1_53c810(struct pci_dev* dev);
 static void fixup_cpc710_pci64(struct pci_dev* dev);
 #ifdef CONFIG_PPC_PMAC
-static void pcibios_fixup_cardbus(struct pci_dev* dev);
+extern void pmac_pci_fixup_cardbus(struct pci_dev* dev);
+extern void pmac_pci_fixup_pciata(struct pci_dev* dev);
+extern void pmac_pci_fixup_k2_sata(struct pci_dev* dev);
 #endif
 #ifdef CONFIG_PPC_OF
 static u8* pci_to_OF_bus_map;
@@ -69,7 +71,9 @@ struct pci_fixup pcibios_fixups[] = {
 	{ PCI_FIXUP_HEADER,	PCI_ANY_ID,		PCI_ANY_ID,			pcibios_fixup_resources },
 #ifdef CONFIG_PPC_PMAC
 	/* We should add per-machine fixup support in xxx_setup.c or xxx_pci.c */
-	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_TI,	PCI_ANY_ID,			pcibios_fixup_cardbus },
+	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_TI,	PCI_ANY_ID,			pmac_pci_fixup_cardbus },
+	{ PCI_FIXUP_FINAL,	PCI_ANY_ID,		PCI_ANY_ID,			pmac_pci_fixup_pciata },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SERVERWORKS, 0x0240,			pmac_pci_fixup_k2_sata },
 #endif /* CONFIG_PPC_PMAC */
  	{ 0 }
 };
@@ -155,42 +159,6 @@ pcibios_fixup_resources(struct pci_dev *
 		ppc_md.pcibios_fixup_resources(dev);
 }
 
-#ifdef CONFIG_PPC_PMAC
-static void
-pcibios_fixup_cardbus(struct pci_dev* dev)
-{
-	if (_machine != _MACH_Pmac)
-		return;
-	/*
-	 * Fix the interrupt routing on the various cardbus bridges
-	 * used on powerbooks
-	 */
-	if (dev->vendor != PCI_VENDOR_ID_TI)
-		return;
-	if (dev->device == PCI_DEVICE_ID_TI_1130 ||
-	    dev->device == PCI_DEVICE_ID_TI_1131) {
-		u8 val;
-	    	/* Enable PCI interrupt */
-		if (pci_read_config_byte(dev, 0x91, &val) == 0)
-			pci_write_config_byte(dev, 0x91, val | 0x30);
-		/* Disable ISA interrupt mode */
-		if (pci_read_config_byte(dev, 0x92, &val) == 0)
-			pci_write_config_byte(dev, 0x92, val & ~0x06);
-	}
-	if (dev->device == PCI_DEVICE_ID_TI_1210 ||
-	    dev->device == PCI_DEVICE_ID_TI_1211 ||
-	    dev->device == PCI_DEVICE_ID_TI_1410) {
-		u8 val;
-		/* 0x8c == TI122X_IRQMUX, 2 says to route the INTA
-		   signal out the MFUNC0 pin */
-		if (pci_read_config_byte(dev, 0x8c, &val) == 0)
-			pci_write_config_byte(dev, 0x8c, (val & ~0x0f) | 2);
-		/* Disable ISA interrupt mode */
-		if (pci_read_config_byte(dev, 0x92, &val) == 0)
-			pci_write_config_byte(dev, 0x92, val & ~0x06);
-	}
-}
-#endif /* CONFIG_PPC_PMAC */
 
 void
 pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
@@ -832,6 +800,17 @@ pci_busdev_to_OF_node(struct pci_bus *bu
 		return NULL;
 
 	/* Fixup bus number according to what OF think it is. */
+#ifdef CONFIG_PPC_PMAC
+	/* The G5 need a special case here. Basically, we don't remap all
+	 * busses on it so we don't create the pci-OF-map. However, we do
+	 * remap the AGP bus and so have to deal with it. A future better
+	 * fix has to be done by making the remapping per-host and always
+	 * filling the pci_to_OF map. --BenH
+	 */
+	if (_machine == _MACH_Pmac && busnr >= 0xf0)
+		busnr -= 0xf0;
+	else
+#endif
 	if (pci_to_OF_bus_map)
 		busnr = pci_to_OF_bus_map[busnr];
 	if (busnr == 0xff)
@@ -922,9 +901,10 @@ void __init
 pci_process_bridge_OF_ranges(struct pci_controller *hose,
 			   struct device_node *dev, int primary)
 {
-	unsigned int *ranges, *prev;
+	static unsigned int static_lc_ranges[1024] __initdata;
+	unsigned int *dt_ranges, *lc_ranges, *ranges, *prev;
 	unsigned int size;
-	int rlen = 0;
+	int rlen = 0, orig_rlen;
 	int memno = 0;
 	struct resource *res;
 	int np, na = prom_n_addr_cells(dev);
@@ -934,7 +914,22 @@ pci_process_bridge_OF_ranges(struct pci_
 	 * that can have more than 3 ranges, fortunately using contiguous
 	 * addresses -- BenH
 	 */
-	ranges = (unsigned int *) get_property(dev, "ranges", &rlen);
+	dt_ranges = (unsigned int *) get_property(dev, "ranges", &rlen);
+	if (!dt_ranges)
+		return;
+	/* Sanity check, though hopefully that never happens */
+	if (rlen > 1024) {
+		printk(KERN_WARNING "OF ranges property too large !\n");
+		rlen = 1024;
+	}
+	lc_ranges = static_lc_ranges;
+	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) {
@@ -959,10 +954,9 @@ pci_process_bridge_OF_ranges(struct pci_
 	 *			(size depending on dev->n_addr_cells)
 	 *   cells 4+5 or 5+6:	the size of the range
 	 */
-	rlen = 0;
-	hose->io_base_phys = 0;
-	ranges = (unsigned int *) get_property(dev, "ranges", &rlen);
-	while ((rlen -= np * sizeof(unsigned int)) >= 0) {
+	ranges = lc_ranges;
+	rlen = orig_rlen;
+	while (ranges && (rlen -= np * sizeof(unsigned int)) >= 0) {
 		res = NULL;
 		size = ranges[na+4];
 		switch (ranges[0] >> 24) {
@@ -1059,7 +1053,7 @@ do_update_p2p_io_resource(struct pci_bus
 
  	res = *(bus->resource[0]);
 
-	DBG("Remapping Bus %d, bridge: %s\n", bus->number, bridge->name);
+	DBG("Remapping Bus %d, bridge: %s\n", bus->number, bridge->slot_name);
 	res.start -= ((unsigned long) hose->io_base_virt - isa_io_base);
 	res.end -= ((unsigned long) hose->io_base_virt - isa_io_base);
 	DBG("  IO window: %08lx-%08lx\n", res.start, res.end);
@@ -1662,12 +1656,23 @@ pci_bus_to_phys(unsigned int ba, int bus
  * Note that the returned IO or memory base is a physical address
  */
 
-long
-sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
+long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
 {
-	struct pci_controller* hose = pci_bus_to_hose(bus);
+	struct pci_controller* hose;
 	long result = -EOPNOTSUPP;
 
+	/* 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 (_machine == _MACH_Pmac && machine_is_compatible("MacRISC4"))
+		if (bus == 0)
+			bus = 0xf0;
+#endif /* CONFIG_PPC_PMAC */
+
+	hose = pci_bus_to_hose(bus);
 	if (!hose)
 		return -ENODEV;
 
diff -puN arch/ppc/kernel/ppc_ksyms.c~big-pmac-3 arch/ppc/kernel/ppc_ksyms.c
--- 25/arch/ppc/kernel/ppc_ksyms.c~big-pmac-3	2004-01-28 23:09:15.000000000 -0800
+++ 25-akpm/arch/ppc/kernel/ppc_ksyms.c	2004-01-28 23:09:16.000000000 -0800
@@ -75,6 +75,7 @@ int abs(int);
 extern unsigned long mm_ptov (unsigned long paddr);
 
 EXPORT_SYMBOL(clear_page);
+EXPORT_SYMBOL(clear_user_page);
 EXPORT_SYMBOL(do_signal);
 EXPORT_SYMBOL(do_syscall_trace);
 EXPORT_SYMBOL(transfer_to_handler);
@@ -236,12 +237,6 @@ EXPORT_SYMBOL(adb_try_handler_change);
 EXPORT_SYMBOL(cuda_request);
 EXPORT_SYMBOL(cuda_poll);
 #endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_PMAC_BACKLIGHT
-EXPORT_SYMBOL(get_backlight_level);
-EXPORT_SYMBOL(set_backlight_level);
-EXPORT_SYMBOL(set_backlight_enable);
-EXPORT_SYMBOL(register_backlight_controller);
-#endif /* CONFIG_PMAC_BACKLIGHT */
 #ifdef CONFIG_PPC_MULTIPLATFORM
 EXPORT_SYMBOL(_machine);
 #endif
@@ -282,14 +277,6 @@ EXPORT_SYMBOL(note_scsi_host);
 #ifdef CONFIG_VT
 EXPORT_SYMBOL(kd_mksound);
 #endif
-#ifdef CONFIG_NVRAM
-EXPORT_SYMBOL(nvram_read_byte);
-EXPORT_SYMBOL(nvram_write_byte);
-#ifdef CONFIG_PPC_PMAC
-EXPORT_SYMBOL(pmac_xpram_read);
-EXPORT_SYMBOL(pmac_xpram_write);
-#endif
-#endif /* CONFIG_NVRAM */
 EXPORT_SYMBOL(to_tm);
 
 EXPORT_SYMBOL(pm_power_off);
diff -puN arch/ppc/kernel/setup.c~big-pmac-3 arch/ppc/kernel/setup.c
--- 25/arch/ppc/kernel/setup.c~big-pmac-3	2004-01-28 23:09:15.000000000 -0800
+++ 25-akpm/arch/ppc/kernel/setup.c	2004-01-28 23:09:16.000000000 -0800
@@ -35,6 +35,7 @@
 #include <asm/system.h>
 #include <asm/pmac_feature.h>
 #include <asm/sections.h>
+#include <asm/nvram.h>
 #include <asm/xmon.h>
 
 #if defined CONFIG_KGDB
@@ -116,6 +117,9 @@ struct screen_info screen_info = {
 
 void machine_restart(char *cmd)
 {
+#ifdef CONFIG_NVRAM
+	nvram_sync();
+#endif
 	ppc_md.restart(cmd);
 }
 
@@ -123,6 +127,9 @@ EXPORT_SYMBOL(machine_restart);
 
 void machine_power_off(void)
 {
+#ifdef CONFIG_NVRAM
+	nvram_sync();
+#endif
 	ppc_md.power_off();
 }
 
@@ -130,6 +137,9 @@ EXPORT_SYMBOL(machine_power_off);
 
 void machine_halt(void)
 {
+#ifdef CONFIG_NVRAM
+	nvram_sync();
+#endif
 	ppc_md.halt();
 }
 
@@ -563,24 +573,30 @@ int __init ppc_setup_l2cr(char *str)
 __setup("l2cr=", ppc_setup_l2cr);
 
 #ifdef CONFIG_NVRAM
-/* Generic nvram hooks we now look into ppc_md.nvram_read_val
- * on pmac too ;)
- * //XX Those 2 could be moved to headers
- */
-unsigned char
-nvram_read_byte(int addr)
+
+/* Generic nvram hooks used by drivers/char/gen_nvram.c */
+unsigned char nvram_read_byte(int addr)
 {
 	if (ppc_md.nvram_read_val)
 		return ppc_md.nvram_read_val(addr);
 	return 0xff;
 }
+EXPORT_SYMBOL(nvram_read_byte);
 
-void
-nvram_write_byte(unsigned char val, int addr)
+void nvram_write_byte(unsigned char val, int addr)
 {
 	if (ppc_md.nvram_write_val)
-		ppc_md.nvram_write_val(val, addr);
+		ppc_md.nvram_write_val(addr, val);
+}
+EXPORT_SYMBOL(nvram_write_byte);
+
+void nvram_sync(void)
+{
+	if (ppc_md.nvram_sync)
+		ppc_md.nvram_sync();
 }
+EXPORT_SYMBOL(nvram_sync);
+
 #endif /* CONFIG_NVRAM */
 
 static struct cpu cpu_devices[NR_CPUS];
diff -puN arch/ppc/kernel/smp.c~big-pmac-3 arch/ppc/kernel/smp.c
--- 25/arch/ppc/kernel/smp.c~big-pmac-3	2004-01-28 23:09:15.000000000 -0800
+++ 25-akpm/arch/ppc/kernel/smp.c	2004-01-28 23:09:16.000000000 -0800
@@ -61,10 +61,6 @@ static struct smp_ops_t *smp_ops;
 /* all cpu mappings are 1-1 -- Cort */
 volatile unsigned long cpu_callin_map[NR_CPUS];
 
-#define TB_SYNC_PASSES 4
-volatile unsigned long __initdata tb_sync_flag = 0;
-volatile unsigned long __initdata tb_offset = 0;
-
 int start_secondary(void *);
 extern int cpu_idle(void *unused);
 void smp_call_function_interrupt(void);
@@ -83,11 +79,14 @@ extern void __save_cpu_setup(void);
 #define PPC_MSG_INVALIDATE_TLB	2
 #define PPC_MSG_XMON_BREAK	3
 
-#define smp_message_pass(t,m,d,w) \
-    do { if (smp_ops) \
-	     atomic_inc(&ipi_sent); \
-	     smp_ops->message_pass((t),(m),(d),(w)); \
-       } while(0)
+static inline void
+smp_message_pass(int target, int msg, unsigned long data, int wait)
+{
+	if (smp_ops){
+		atomic_inc(&ipi_sent);
+		smp_ops->message_pass(target,msg,data,wait);
+	}
+}
 
 /*
  * Common functions
@@ -291,41 +290,6 @@ void smp_call_function_interrupt(void)
 		atomic_inc(&call_data->finished);
 }
 
-/* FIXME: Do this properly for all archs --RR */
-static spinlock_t timebase_lock = SPIN_LOCK_UNLOCKED;
-static unsigned int timebase_upper = 0, timebase_lower = 0;
-
-void __devinit
-smp_generic_give_timebase(void)
-{
-	spin_lock(&timebase_lock);
-	do {
-		timebase_upper = get_tbu();
-		timebase_lower = get_tbl();
-	} while (timebase_upper != get_tbu());
-	spin_unlock(&timebase_lock);
-
-	while (timebase_upper || timebase_lower)
-		rmb();
-}
-
-void __devinit
-smp_generic_take_timebase(void)
-{
-	int done = 0;
-
-	while (!done) {
-		spin_lock(&timebase_lock);
-		if (timebase_upper || timebase_lower) {
-			set_tb(timebase_upper, timebase_lower);
-			timebase_upper = 0;
-			timebase_lower = 0;
-			done = 1;
-		}
-		spin_unlock(&timebase_lock);
-	}
-}
-
 static void __devinit smp_store_cpu_info(int id)
 {
         struct cpuinfo_PPC *c = &cpu_data[id];
diff -puN /dev/null arch/ppc/kernel/smp-tbsync.c
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/arch/ppc/kernel/smp-tbsync.c	2004-01-28 23:09:16.000000000 -0800
@@ -0,0 +1,181 @@
+/*
+ * 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 int		tbu;
+	volatile int		tbl;
+	volatile int		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( int mark, int add )
+{
+	while( (int)(get_tbl() - mark) < 0 )
+		tbsync->race_result = add;
+}
+
+void __devinit
+smp_generic_take_timebase( void )
+{
+	int cmd, tbl, tbu;
+
+	local_irq_disable();
+	while( !running )
+		;
+	rmb();
+
+	for( ;; ) {
+		tbsync->ack = 1;
+		while( !tbsync->handshake )
+			;
+		rmb();
+
+		cmd = tbsync->cmd;
+		tbl = tbsync->tbl;
+		tbu = tbsync->tbu;
+		tbsync->ack = 0;
+		if( cmd == kExit )
+			return;
+
+		if( cmd == kSetAndTest ) {
+			while( tbsync->handshake )
+				;
+			asm volatile ("mttbl %0" :: "r" (tbl) );
+			asm volatile ("mttbu %0" :: "r" (tbu) );
+		} else {
+			while( tbsync->handshake )
+				;
+		}
+		enter_contest( tbsync->mark, -1 );
+	}
+	local_irq_enable();
+}
+
+static int __devinit
+start_contest( int cmd, int offset, int num )
+{
+	int i, tbu, tbl, mark, score=0;
+
+	tbsync->cmd = cmd;
+
+	local_irq_disable();
+	for( i=-3; i<num; ) {
+		tbl = get_tbl() + 400;
+		tbsync->tbu = tbu = get_tbu();
+		tbsync->tbl = tbl + offset;
+		tbsync->mark = mark = tbl + 400;
+
+		wmb();
+
+		tbsync->handshake = 1;
+		while( tbsync->ack )
+			;
+
+		while( (int)(get_tbl() - tbl) <= 0 )
+			;
+		tbsync->handshake = 0;
+		enter_contest( mark, 1 );
+
+		while( !tbsync->ack )
+			;
+
+		if( tbsync->tbu != get_tbu() || ((tbsync->tbl ^ get_tbl()) & 0x80000000) )
+			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 )
+		;
+
+	/* 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;
+
+	/* all done */
+	smp_tb_synchronized = 1;
+}
diff -puN arch/ppc/mm/hashtable.S~big-pmac-3 arch/ppc/mm/hashtable.S
--- 25/arch/ppc/mm/hashtable.S~big-pmac-3	2004-01-28 23:09:15.000000000 -0800
+++ 25-akpm/arch/ppc/mm/hashtable.S	2004-01-28 23:09:16.000000000 -0800
@@ -37,6 +37,32 @@
 #endif /* CONFIG_SMP */
 
 /*
+ * Sync CPUs with hash_page taking & releasing the hash
+ * table lock
+ */
+#ifdef CONFIG_SMP
+	.text
+_GLOBAL(hash_page_sync)
+	lis	r8,mmu_hash_lock@h
+	ori	r8,r8,mmu_hash_lock@l
+	lis	r0,0x0fff
+	b	10f
+11:	lwz	r6,0(r8)
+	cmpwi	0,r6,0
+	bne	11b
+10:	lwarx	r6,0,r8
+	cmpwi	0,r6,0
+	bne-	11b
+	stwcx.	r0,0,r8
+	bne-	10b
+	isync
+	eieio
+	li	r0,0
+	stw	r0,0(r8)
+	blr	
+#endif
+
+/*
  * Load a PTE into the hash table, if possible.
  * The address is in r4, and r3 contains an access flag:
  * _PAGE_RW (0x400) if a write.
@@ -417,21 +443,6 @@ _GLOBAL(hash_page_patch_C)
 	lwz	r6,next_slot@l(r4)
 	addi	r6,r6,PTE_SIZE
 	andi.	r6,r6,7*PTE_SIZE
-#ifdef CONFIG_POWER4
-	/*
-	 * Since we don't have BATs on POWER4, we rely on always having
-	 * PTEs in the hash table to map the hash table and the code
-	 * that manipulates it in virtual mode, namely flush_hash_page and
-	 * flush_hash_segments.  Otherwise we can get a DSI inside those
-	 * routines which leads to a deadlock on the hash_table_lock on
-	 * SMP machines.  We avoid this by never overwriting the first
-	 * PTE of each PTEG if it is already valid.
-	 *	-- paulus.
-	 */
-	bne	102f
-	li	r6,PTE_SIZE
-102:
-#endif /* CONFIG_POWER4 */
 	stw	r6,next_slot@l(r4)
 	add	r4,r3,r6
 
diff -puN arch/ppc/mm/init.c~big-pmac-3 arch/ppc/mm/init.c
--- 25/arch/ppc/mm/init.c~big-pmac-3	2004-01-28 23:09:15.000000000 -0800
+++ 25-akpm/arch/ppc/mm/init.c	2004-01-28 23:09:16.000000000 -0800
@@ -291,6 +291,8 @@ void __init MMU_init(void)
 		ppc_md.progress("MMU:exit", 0x211);
 
 #ifdef CONFIG_BOOTX_TEXT
+	/* By default, we are no longer mapped */
+       	boot_text_mapped = 0;
 	/* Must be done last, or ppc_md.progress will die. */
 	map_boot_text();
 #endif
diff -puN arch/ppc/mm/pgtable.c~big-pmac-3 arch/ppc/mm/pgtable.c
--- 25/arch/ppc/mm/pgtable.c~big-pmac-3	2004-01-28 23:09:15.000000000 -0800
+++ 25-akpm/arch/ppc/mm/pgtable.c	2004-01-28 23:09:16.000000000 -0800
@@ -44,6 +44,10 @@ int io_bat_index;
 
 extern char etext[], _stext[];
 
+#ifdef CONFIG_SMP
+extern void hash_page_sync(void);
+#endif
+
 #ifdef HAVE_BATS
 extern unsigned long v_mapped_by_bats(unsigned long va);
 extern unsigned long p_mapped_by_bats(unsigned long pa);
@@ -109,11 +113,17 @@ struct page *pte_alloc_one(struct mm_str
 
 void pte_free_kernel(pte_t *pte)
 {
+#ifdef CONFIG_SMP
+	hash_page_sync();
+#endif
 	free_page((unsigned long)pte);
 }
 
 void pte_free(struct page *pte)
 {
+#ifdef CONFIG_SMP
+	hash_page_sync();
+#endif
 	__free_page(pte);
 }
 
diff -puN arch/ppc/mm/ppc_mmu.c~big-pmac-3 arch/ppc/mm/ppc_mmu.c
--- 25/arch/ppc/mm/ppc_mmu.c~big-pmac-3	2004-01-28 23:09:15.000000000 -0800
+++ 25-akpm/arch/ppc/mm/ppc_mmu.c	2004-01-28 23:09:16.000000000 -0800
@@ -83,6 +83,9 @@ unsigned long p_mapped_by_bats(unsigned 
 
 unsigned long __init mmu_mapin_ram(void)
 {
+#ifdef CONFIG_POWER4
+	return 0;
+#else
 	unsigned long tot, bl, done;
 	unsigned long max_size = (256<<20);
 	unsigned long align;
@@ -119,6 +122,7 @@ unsigned long __init mmu_mapin_ram(void)
 	}
 
 	return done;
+#endif
 }
 
 /*
@@ -244,9 +248,10 @@ void __init MMU_init_hw(void)
 	Hash = mem_pieces_find(Hash_size, Hash_size);
 	cacheable_memzero(Hash, Hash_size);
 	_SDR1 = __pa(Hash) | SDR1_LOW_BITS;
-	Hash_end = (PTE *) ((unsigned long)Hash + Hash_size);
 #endif /* CONFIG_POWER4 */
 
+	Hash_end = (PTE *) ((unsigned long)Hash + Hash_size);
+
 	printk("Total memory = %ldMB; using %ldkB for hash table (at %p)\n",
 	       total_memory >> 20, Hash_size >> 10, Hash);
 
diff -puN arch/ppc/mm/tlb.c~big-pmac-3 arch/ppc/mm/tlb.c
--- 25/arch/ppc/mm/tlb.c~big-pmac-3	2004-01-28 23:09:15.000000000 -0800
+++ 25-akpm/arch/ppc/mm/tlb.c	2004-01-28 23:09:16.000000000 -0800
@@ -47,6 +47,26 @@ void flush_hash_entry(struct mm_struct *
 }
 
 /*
+ * Called by ptep_test_and_clear_young()
+ */
+void flush_hash_one_pte(pte_t *ptep)
+{
+	struct page *ptepage;
+	struct mm_struct *mm;
+	unsigned long ptephys;
+	unsigned long addr;
+
+	if (Hash == 0)
+		return;
+	
+	ptepage = virt_to_page(ptep);
+	mm = (struct mm_struct *) ptepage->mapping;
+	ptephys = __pa(ptep) & PAGE_MASK;
+	addr = ptepage->index + (((unsigned long)ptep & ~PAGE_MASK) << 9);
+	flush_hash_pages(mm->context, addr, ptephys, 1);
+}
+
+/*
  * Called at the end of a mmu_gather operation to make sure the
  * TLB flush is completely done.
  */
diff -puN arch/ppc/platforms/Makefile~big-pmac-3 arch/ppc/platforms/Makefile
--- 25/arch/ppc/platforms/Makefile~big-pmac-3	2004-01-28 23:09:15.000000000 -0800
+++ 25-akpm/arch/ppc/platforms/Makefile	2004-01-28 23:09:16.000000000 -0800
@@ -17,7 +17,8 @@ ifeq ($(CONFIG_APUS),y)
 obj-$(CONFIG_PCI)		+= apus_pci.o
 endif
 obj-$(CONFIG_PPC_PMAC)		+= pmac_pic.o pmac_setup.o pmac_time.o \
-					pmac_feature.o pmac_pci.o pmac_sleep.o
+					pmac_feature.o pmac_pci.o pmac_sleep.o \
+					pmac_low_i2c.o
 obj-$(CONFIG_PPC_CHRP)		+= chrp_setup.o chrp_time.o chrp_pci.o
 obj-$(CONFIG_PPC_PREP)		+= prep_pci.o prep_time.o prep_setup.o
 ifeq ($(CONFIG_PPC_PMAC),y)
diff -puN arch/ppc/platforms/pmac_backlight.c~big-pmac-3 arch/ppc/platforms/pmac_backlight.c
--- 25/arch/ppc/platforms/pmac_backlight.c~big-pmac-3	2004-01-28 23:09:15.000000000 -0800
+++ 25-akpm/arch/ppc/platforms/pmac_backlight.c	2004-01-28 23:09:16.000000000 -0800
@@ -8,6 +8,7 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/stddef.h>
 #include <linux/reboot.h>
 #include <linux/nvram.h>
@@ -37,6 +38,10 @@ register_backlight_controller(struct bac
 	char *prop;
 	int valid = 0;
 
+	/* There's already a matching controller, bail out */
+	if (backlighter != NULL)
+		return;
+
 	bk_node = find_devices("backlight");
 
 #ifdef CONFIG_ADB_PMU
@@ -84,6 +89,7 @@ register_backlight_controller(struct bac
 	printk(KERN_INFO "Registered \"%s\" backlight controller, level: %d/15\n",
 		type, backlight_level);
 }
+EXPORT_SYMBOL(register_backlight_controller);
 
 void __pmac
 unregister_backlight_controller(struct backlight_controller *ctrler, void *data)
@@ -92,6 +98,7 @@ unregister_backlight_controller(struct b
 	if (ctrler == backlighter && data == backlighter_data)
 		backlighter = NULL;
 }
+EXPORT_SYMBOL(unregister_backlight_controller);
 
 int __pmac
 set_backlight_enable(int enable)
@@ -105,6 +112,7 @@ set_backlight_enable(int enable)
 		backlight_enabled = enable;
 	return rc;
 }
+EXPORT_SYMBOL(set_backlight_enable);
 
 int __pmac
 get_backlight_enable(void)
@@ -113,6 +121,7 @@ get_backlight_enable(void)
 		return -ENODEV;
 	return backlight_enabled;
 }
+EXPORT_SYMBOL(get_backlight_enable);
 
 int __pmac
 set_backlight_level(int level)
@@ -137,6 +146,7 @@ set_backlight_level(int level)
 	}
 	return rc;
 }
+EXPORT_SYMBOL(set_backlight_level);
 
 int __pmac
 get_backlight_level(void)
@@ -145,3 +155,4 @@ get_backlight_level(void)
 		return -ENODEV;
 	return backlight_level;
 }
+EXPORT_SYMBOL(get_backlight_level);
diff -puN arch/ppc/platforms/pmac_cpufreq.c~big-pmac-3 arch/ppc/platforms/pmac_cpufreq.c
--- 25/arch/ppc/platforms/pmac_cpufreq.c~big-pmac-3	2004-01-28 23:09:15.000000000 -0800
+++ 25-akpm/arch/ppc/platforms/pmac_cpufreq.c	2004-01-28 23:09:16.000000000 -0800
@@ -22,6 +22,7 @@
 #include <linux/cpufreq.h>
 #include <linux/init.h>
 #include <linux/sysdev.h>
+#include <linux/i2c.h>
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/irq.h>
@@ -38,6 +39,14 @@
  */
 #undef DEBUG_FREQ
 
+/*
+ * There is a problem with the core cpufreq code on SMP kernels,
+ * it won't recalculate the Bogomips properly
+ */
+#ifdef CONFIG_SMP
+#warning "WARNING, CPUFREQ not recommended on SMP kernels"
+#endif
+
 extern void low_choose_750fx_pll(int pll);
 extern void low_sleep_handler(void);
 extern void openpic_suspend(struct sys_device *sysdev, u32 state);
@@ -48,7 +57,14 @@ extern void enable_kernel_fp(void);
 static unsigned int low_freq;
 static unsigned int hi_freq;
 static unsigned int cur_freq;
+
+/* Clean that up some day ... use a func ptr or at least an enum... */
 static int cpufreq_uses_pmu;
+static int cpufreq_uses_gpios;
+
+static u32 voltage_gpio;
+static u32 frequency_gpio;
+static u32 slew_done_gpio;
 
 #define PMAC_CPU_LOW_SPEED	1
 #define PMAC_CPU_HIGH_SPEED	0
@@ -65,8 +81,7 @@ static struct cpufreq_frequency_table pm
 	{0,			CPUFREQ_TABLE_END},
 };
 
-static inline void
-wakeup_decrementer(void)
+static inline void wakeup_decrementer(void)
 {
 	set_dec(tb_ticks_per_jiffy);
 	/* No currently-supported powerbook has a 601,
@@ -76,8 +91,7 @@ wakeup_decrementer(void)
 }
 
 #ifdef DEBUG_FREQ
-static inline void
-debug_calc_bogomips(void)
+static inline void debug_calc_bogomips(void)
 {
 	/* This will cause a recalc of bogomips and display the
 	 * result. We backup/restore the value to avoid affecting the
@@ -89,17 +103,18 @@ debug_calc_bogomips(void)
 	calibrate_delay();
 	loops_per_jiffy = save_lpj;
 }
-#endif
+#endif /* DEBUG_FREQ */
 
 /* Switch CPU speed under 750FX CPU control
  */
-static int __pmac
-cpu_750fx_cpu_speed(int low_speed)
+static int __pmac cpu_750fx_cpu_speed(int low_speed)
 {
 #ifdef DEBUG_FREQ
 	printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1));
 #endif
+#ifdef CONFIG_6xx
 	low_choose_750fx_pll(low_speed);
+#endif
 #ifdef DEBUG_FREQ
 	printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1));
 	debug_calc_bogomips();
@@ -108,15 +123,54 @@ cpu_750fx_cpu_speed(int low_speed)
 	return 0;
 }
 
+/* Switch CPU speed using slewing GPIOs
+ */
+static int __pmac gpios_set_cpu_speed(unsigned int low_speed)
+{
+	int gpio;
+
+	/* If ramping up, set voltage first */
+	if (low_speed == 0) {
+		pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x05);
+		/* Delay is way too big but it's ok, we schedule */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ/100);
+	}
+
+	/* Set frequency */
+	pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, frequency_gpio, low_speed ? 0x04 : 0x05);
+	udelay(200);
+	do {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+		gpio = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, slew_done_gpio, 0);
+	} while((gpio & 0x02) == 0);
+
+	/* If ramping down, set voltage last */
+	if (low_speed == 1) {
+		pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, voltage_gpio, 0x04);
+		/* Delay is way too big but it's ok, we schedule */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ/100);
+	}
+
+#ifdef DEBUG_FREQ
+	debug_calc_bogomips();
+#endif
+
+	return 0;
+}
+
 /* Switch CPU speed under PMU control
  */
-static int __pmac
-pmu_set_cpu_speed(unsigned int low_speed)
+static int __pmac pmu_set_cpu_speed(unsigned int low_speed)
 {
 	struct adb_request req;
 	unsigned long save_l2cr;
 	unsigned long save_l3cr;
 
+	preempt_disable();
+
 #ifdef DEBUG_FREQ
 	printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1));
 #endif
@@ -197,11 +251,12 @@ pmu_set_cpu_speed(unsigned int low_speed
 	debug_calc_bogomips();
 #endif
 
+	preempt_enable();
+
 	return 0;
 }
 
-static int __pmac
-do_set_cpu_speed(int speed_mode)
+static int __pmac do_set_cpu_speed(int speed_mode)
 {
 	struct cpufreq_freqs freqs;
 	int rc;
@@ -216,6 +271,8 @@ do_set_cpu_speed(int speed_mode)
 	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 	if (cpufreq_uses_pmu)
 		rc = pmu_set_cpu_speed(speed_mode);
+	else if (cpufreq_uses_gpios)
+		rc = gpios_set_cpu_speed(speed_mode);
 	else
 		rc = cpu_750fx_cpu_speed(speed_mode);
 	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
@@ -224,16 +281,14 @@ do_set_cpu_speed(int speed_mode)
 	return rc;
 }
 
-static int __pmac
-pmac_cpufreq_verify(struct cpufreq_policy *policy)
+static int __pmac pmac_cpufreq_verify(struct cpufreq_policy *policy)
 {
 	return cpufreq_frequency_table_verify(policy, pmac_cpu_freqs);
 }
 
-static int __pmac
-pmac_cpufreq_target(	struct cpufreq_policy *policy,
-			unsigned int target_freq,
-			unsigned int relation)
+static int __pmac pmac_cpufreq_target(	struct cpufreq_policy *policy,
+					unsigned int target_freq,
+					unsigned int relation)
 {
 	unsigned int    newstate = 0;
 
@@ -244,15 +299,13 @@ pmac_cpufreq_target(	struct cpufreq_poli
 	return do_set_cpu_speed(newstate);
 }
 
-unsigned int __pmac
-pmac_get_one_cpufreq(int i)
+unsigned int __pmac pmac_get_one_cpufreq(int i)
 {
 	/* Supports only one CPU for now */
 	return (i == 0) ? cur_freq : 0;
 }
 
-static int __pmac
-pmac_cpufreq_cpu_init(struct cpufreq_policy *policy)
+static int __pmac pmac_cpufreq_cpu_init(struct cpufreq_policy *policy)
 {
 	if (policy->cpu != 0)
 		return -ENODEV;
@@ -264,6 +317,18 @@ pmac_cpufreq_cpu_init(struct cpufreq_pol
 	return cpufreq_frequency_table_cpuinfo(policy, &pmac_cpu_freqs[0]);
 }
 
+static u32 __pmac read_gpio(struct device_node *np)
+{
+	u32 *reg = (u32 *)get_property(np, "reg", NULL);
+
+	if (reg == NULL)
+		return 0;
+	/* That works for all keylargos but shall be fixed properly
+	 * some day...
+	 */
+	return 0x50 + (*reg);
+}
+
 static struct cpufreq_driver pmac_cpufreq_driver = {
 	.verify 	= pmac_cpufreq_verify,
 	.target 	= pmac_cpufreq_target,
@@ -272,15 +337,17 @@ static struct cpufreq_driver pmac_cpufre
 	.owner		= THIS_MODULE,
 };
 
+
 /* Currently, we support the following machines:
  *
+ *  - Titanium PowerBook 1Ghz (PMU based, 667Mhz & 1Ghz)
  *  - Titanium PowerBook 800 (PMU based, 667Mhz & 800Mhz)
  *  - Titanium PowerBook 500 (PMU based, 300Mhz & 500Mhz)
  *  - iBook2 500 (PMU based, 400Mhz & 500Mhz)
  *  - iBook2 700 (CPU based, 400Mhz & 700Mhz, support low voltage)
+ *  - Recent MacRISC3 machines
  */
-static int __init
-pmac_cpufreq_setup(void)
+static int __init pmac_cpufreq_setup(void)
 {
 	struct device_node	*cpunode;
 	u32			*value;
@@ -304,6 +371,74 @@ pmac_cpufreq_setup(void)
 	if (machine_is_compatible("PowerBook3,4") ||
 	    machine_is_compatible("PowerBook3,5") ||
 	    machine_is_compatible("MacRISC3")) {
+		struct device_node *volt_gpio_np = of_find_node_by_name(NULL, "voltage-gpio");
+		struct device_node *freq_gpio_np = of_find_node_by_name(NULL, "frequency-gpio");
+		struct device_node *slew_done_gpio_np = of_find_node_by_name(NULL, "slewing-done");
+
+		/*
+		 * Check to see if it's GPIO driven or PMU only
+		 *
+		 * The way we extract the GPIO address is slightly hackish, but it
+		 * works well enough for now. We need to abstract the whole GPIO
+		 * stuff sooner or later anyway
+		 */
+
+		if (volt_gpio_np)
+			voltage_gpio = read_gpio(volt_gpio_np);
+		if (freq_gpio_np)
+			frequency_gpio = read_gpio(freq_gpio_np);
+		if (slew_done_gpio_np)
+			slew_done_gpio = read_gpio(slew_done_gpio_np);
+
+		/* If we use the frequency GPIOs, calculate the min/max speeds based
+		 * on the bus frequencies
+		 */
+		if (frequency_gpio && slew_done_gpio) {
+			int lenp, rc;
+			u32 *freqs, *ratio;
+
+			freqs = (u32 *)get_property(cpunode, "bus-frequencies", &lenp);
+			lenp /= sizeof(u32);
+			if (freqs == NULL || lenp != 2) {
+				printk(KERN_ERR "cpufreq: bus-frequencies incorrect or missing\n");
+				goto out;
+			}
+			ratio = (u32 *)get_property(cpunode, "processor-to-bus-ratio*2", NULL);
+			if (ratio == NULL) {
+				printk(KERN_ERR "cpufreq: processor-to-bus-ratio*2 missing\n");
+				goto out;
+			}
+
+			/* Get the min/max bus frequencies */
+			low_freq = min(freqs[0], freqs[1]);
+			hi_freq = max(freqs[0], freqs[1]);
+
+			/* Grrrr.. It _seems_ that the device-tree is lying on the low bus
+			 * frequency, it claims it to be around 84Mhz on some models while
+			 * it appears to be approx. 101Mhz on all. Let's hack around here...
+			 * fortunately, we don't need to be too precise
+			 */
+			if (low_freq < 98000000)
+				low_freq = 101000000;
+			
+			/* Convert those to CPU core clocks */
+			low_freq = (low_freq * (*ratio)) / 2000;
+			hi_freq = (hi_freq * (*ratio)) / 2000;
+
+			/* Now we get the frequencies, we read the GPIO to see what is out current
+			 * speed
+			 */
+			rc = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, frequency_gpio, 0);
+			cur_freq = (rc & 0x01) ? hi_freq : low_freq;
+
+			has_freq_ctl = 1;
+			cpufreq_uses_gpios = 1;
+			goto out;
+		}
+
+		/* If we use the PMU, look for the min & max frequencies in the
+		 * device-tree
+		 */
 		value = (u32 *)get_property(cpunode, "min-clock-frequency", NULL);
 		if (!value)
 			goto out;
@@ -359,6 +494,11 @@ out:
 	pmac_cpu_freqs[CPUFREQ_LOW].frequency = low_freq;
 	pmac_cpu_freqs[CPUFREQ_HIGH].frequency = hi_freq;
 
+	printk(KERN_INFO "Registering PowerMac CPU frequency driver\n");
+	printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Boot: %d Mhz, switch method: %s\n",
+	       low_freq/1000, hi_freq/1000, cur_freq/1000,
+	       cpufreq_uses_pmu ? "PMU" : (cpufreq_uses_gpios ? "GPIOs" : "CPU"));
+
 	return cpufreq_register_driver(&pmac_cpufreq_driver);
 }
 
diff -puN arch/ppc/platforms/pmac_feature.c~big-pmac-3 arch/ppc/platforms/pmac_feature.c
--- 25/arch/ppc/platforms/pmac_feature.c~big-pmac-3	2004-01-28 23:09:15.000000000 -0800
+++ 25-akpm/arch/ppc/platforms/pmac_feature.c	2004-01-28 23:09:16.000000000 -0800
@@ -41,6 +41,7 @@
 #include <asm/pmac_feature.h>
 #include <asm/dbdma.h>
 #include <asm/pci-bridge.h>
+#include <asm/pmac_low_i2c.h>
 
 #undef DEBUG_FEATURE
 
@@ -50,9 +51,13 @@
 #define DBG(fmt,...)
 #endif
 
-/* Exported from arch/ppc/kernel/idle.c */
+#ifdef CONFIG_6xx
 extern int powersave_lowspeed;
+#endif
+
 extern int powersave_nap;
+extern struct pci_dev *k2_skiplist[2];
+
 
 /*
  * We use a single global lock to protect accesses. Each driver has
@@ -95,7 +100,8 @@ static const char* macio_names[] __pmacd
 	"Paddington",
 	"Keylargo",
 	"Pangea",
-	"Intrepid"
+	"Intrepid",
+	"K2"
 };
 
 
@@ -113,14 +119,15 @@ static const char* macio_names[] __pmacd
 static struct device_node* uninorth_node __pmacdata;
 static u32* uninorth_base __pmacdata;
 static u32 uninorth_rev __pmacdata;
-
+static int uninorth_u3 __pmacdata;
+static void *u3_ht;
 
 /*
  * For each motherboard family, we have a table of functions pointers
  * that handle the various features.
  */
 
-typedef int (*feature_call)(struct device_node* node, int param, int value);
+typedef long (*feature_call)(struct device_node* node, long param, long value);
 
 struct feature_table_entry {
 	unsigned int	selector;
@@ -161,8 +168,10 @@ simple_feature_tweak(struct device_node*
 	return 0;
 }
 
-static int __pmac
-ohare_htw_scc_enable(struct device_node* node, int param, int value)
+#ifndef CONFIG_POWER4
+
+static long __pmac
+ohare_htw_scc_enable(struct device_node* node, long param, long value)
 {
 	struct macio_chip*	macio;
 	unsigned long		chan_mask;
@@ -254,22 +263,22 @@ ohare_htw_scc_enable(struct device_node*
 	return 0;
 }
 
-static int __pmac
-ohare_floppy_enable(struct device_node* node, int param, int value)
+static long __pmac
+ohare_floppy_enable(struct device_node* node, long param, long value)
 {
 	return simple_feature_tweak(node, macio_ohare,
 		OHARE_FCR, OH_FLOPPY_ENABLE, value);
 }
 
-static int __pmac
-ohare_mesh_enable(struct device_node* node, int param, int value)
+static long __pmac
+ohare_mesh_enable(struct device_node* node, long param, long value)
 {
 	return simple_feature_tweak(node, macio_ohare,
 		OHARE_FCR, OH_MESH_ENABLE, value);
 }
 
-static int __pmac
-ohare_ide_enable(struct device_node* node, int param, int value)
+static long __pmac
+ohare_ide_enable(struct device_node* node, long param, long value)
 {
 	switch(param) {
 	    case 0:
@@ -289,8 +298,8 @@ ohare_ide_enable(struct device_node* nod
 	}
 }
 
-static int __pmac
-ohare_ide_reset(struct device_node* node, int param, int value)
+static long __pmac
+ohare_ide_reset(struct device_node* node, long param, long value)
 {
 	switch(param) {
 	    case 0:
@@ -304,8 +313,8 @@ ohare_ide_reset(struct device_node* node
 	}
 }
 
-static int __pmac
-ohare_sleep_state(struct device_node* node, int param, int value)
+static long __pmac
+ohare_sleep_state(struct device_node* node, long param, long value)
 {
 	struct macio_chip*	macio = &macio_chips[0];
 
@@ -320,8 +329,8 @@ ohare_sleep_state(struct device_node* no
 	return 0;
 }
 
-static int __pmac
-heathrow_modem_enable(struct device_node* node, int param, int value)
+static long __pmac
+heathrow_modem_enable(struct device_node* node, long param, long value)
 {
 	struct macio_chip*	macio;
 	u8			gpio;
@@ -364,8 +373,8 @@ heathrow_modem_enable(struct device_node
 	return 0;
 }
 
-static int __pmac
-heathrow_floppy_enable(struct device_node* node, int param, int value)
+static long __pmac
+heathrow_floppy_enable(struct device_node* node, long param, long value)
 {
 	return simple_feature_tweak(node, macio_unknown,
 		HEATHROW_FCR,
@@ -373,8 +382,8 @@ heathrow_floppy_enable(struct device_nod
 		value);
 }
 
-static int __pmac
-heathrow_mesh_enable(struct device_node* node, int param, int value)
+static long __pmac
+heathrow_mesh_enable(struct device_node* node, long param, long value)
 {
 	struct macio_chip*	macio;
 	unsigned long		flags;
@@ -390,22 +399,11 @@ heathrow_mesh_enable(struct device_node*
 		MACIO_BIC(HEATHROW_FCR, HRW_MESH_ENABLE);
 	(void)MACIO_IN32(HEATHROW_FCR);
 	udelay(10);
-	/* Set/Clear termination power (todo: test ! the bit value
-	 * used by Darwin doesn't seem to match what we used so
-	 * far. If you experience problems, turn #if 1 into #if 0
-	 * and tell me about it --BenH.
-	 */
-#if 1
+	/* Set/Clear termination power */
 	if (value)
-		MACIO_BIC(HEATHROW_MBCR, 0x00000004);
+		MACIO_BIC(HEATHROW_MBCR, 0x04000000);
 	else
-		MACIO_BIS(HEATHROW_MBCR, 0x00000004);
-#else
-	if (value)
-		MACIO_BIC(HEATHROW_MBCR, 0x00040000);
-	else
-		MACIO_BIS(HEATHROW_MBCR, 0x00040000);
-#endif
+		MACIO_BIS(HEATHROW_MBCR, 0x04000000);
 	(void)MACIO_IN32(HEATHROW_MBCR);
 	udelay(10);
 	UNLOCK(flags);
@@ -413,8 +411,8 @@ heathrow_mesh_enable(struct device_node*
 	return 0;
 }
 
-static int __pmac
-heathrow_ide_enable(struct device_node* node, int param, int value)
+static long __pmac
+heathrow_ide_enable(struct device_node* node, long param, long value)
 {
 	switch(param) {
 	    case 0:
@@ -428,8 +426,8 @@ heathrow_ide_enable(struct device_node* 
 	}
 }
 
-static int __pmac
-heathrow_ide_reset(struct device_node* node, int param, int value)
+static long __pmac
+heathrow_ide_reset(struct device_node* node, long param, long value)
 {
 	switch(param) {
 	    case 0:
@@ -443,8 +441,8 @@ heathrow_ide_reset(struct device_node* n
 	}
 }
 
-static int __pmac
-heathrow_bmac_enable(struct device_node* node, int param, int value)
+static long __pmac
+heathrow_bmac_enable(struct device_node* node, long param, long value)
 {
 	struct macio_chip*	macio;
 	unsigned long		flags;
@@ -472,8 +470,8 @@ heathrow_bmac_enable(struct device_node*
 	return 0;
 }
 
-static int __pmac
-heathrow_sound_enable(struct device_node* node, int param, int value)
+static long __pmac
+heathrow_sound_enable(struct device_node* node, long param, long value)
 {
 	struct macio_chip*	macio;
 	unsigned long		flags;
@@ -608,8 +606,8 @@ heathrow_wakeup(struct macio_chip* macio
 	}
 }
 
-static int __pmac
-heathrow_sleep_state(struct device_node* node, int param, int value)
+static long __pmac
+heathrow_sleep_state(struct device_node* node, long param, long value)
 {
 	if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)
 		return -EPERM;
@@ -625,8 +623,8 @@ heathrow_sleep_state(struct device_node*
 	return 0;
 }
 
-static int __pmac
-core99_scc_enable(struct device_node* node, int param, int value)
+static long __pmac
+core99_scc_enable(struct device_node* node, long param, long value)
 {
 	struct macio_chip*	macio;
 	unsigned long		flags;
@@ -726,8 +724,8 @@ core99_scc_enable(struct device_node* no
 	return 0;
 }
 
-static int __pmac
-core99_modem_enable(struct device_node* node, int param, int value)
+static long __pmac
+core99_modem_enable(struct device_node* node, long param, long value)
 {
 	struct macio_chip*	macio;
 	u8			gpio;
@@ -778,8 +776,8 @@ core99_modem_enable(struct device_node* 
 	return 0;
 }
 
-static int __pmac
-pangea_modem_enable(struct device_node* node, int param, int value)
+static long __pmac
+pangea_modem_enable(struct device_node* node, long param, long value)
 {
 	struct macio_chip*	macio;
 	u8			gpio;
@@ -833,8 +831,8 @@ pangea_modem_enable(struct device_node* 
 	return 0;
 }
 
-static int __pmac
-core99_ata100_enable(struct device_node* node, int value)
+static long __pmac
+core99_ata100_enable(struct device_node* node, long value)
 {
 	unsigned long flags;
 	struct pci_dev *pdev = NULL;
@@ -863,8 +861,8 @@ core99_ata100_enable(struct device_node*
     	return 0;
 }
 
-static int __pmac
-core99_ide_enable(struct device_node* node, int param, int value)
+static long __pmac
+core99_ide_enable(struct device_node* node, long param, long value)
 {
 	/* Bus ID 0 to 2 are KeyLargo based IDE, busID 3 is U2
 	 * based ata-100
@@ -886,8 +884,8 @@ core99_ide_enable(struct device_node* no
 	}
 }
 
-static int __pmac
-core99_ide_reset(struct device_node* node, int param, int value)
+static long __pmac
+core99_ide_reset(struct device_node* node, long param, long value)
 {
 	switch(param) {
 	    case 0:
@@ -904,8 +902,8 @@ core99_ide_reset(struct device_node* nod
 	}
 }
 
-static int __pmac
-core99_gmac_enable(struct device_node* node, int param, int value)
+static long __pmac
+core99_gmac_enable(struct device_node* node, long param, long value)
 {
 	unsigned long flags;
 
@@ -921,8 +919,8 @@ core99_gmac_enable(struct device_node* n
 	return 0;
 }
 
-static int __pmac
-core99_gmac_phy_reset(struct device_node* node, int param, int value)
+static long __pmac
+core99_gmac_phy_reset(struct device_node* node, long param, long value)
 {
 	unsigned long flags;
 	struct macio_chip* macio;
@@ -938,16 +936,16 @@ core99_gmac_phy_reset(struct device_node
 	UNLOCK(flags);
 	mdelay(10);
 	LOCK(flags);
-	MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, KEYLARGO_GPIO_OUTPUT_ENABLE
-		| KEYLARGO_GPIO_OUTOUT_DATA);
+	MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, /*KEYLARGO_GPIO_OUTPUT_ENABLE | */
+		KEYLARGO_GPIO_OUTOUT_DATA);
 	UNLOCK(flags);
 	mdelay(10);
 
 	return 0;
 }
 
-static int __pmac
-core99_sound_chip_enable(struct device_node* node, int param, int value)
+static long __pmac
+core99_sound_chip_enable(struct device_node* node, long param, long value)
 {
 	struct macio_chip*	macio;
 	unsigned long		flags;
@@ -976,8 +974,8 @@ core99_sound_chip_enable(struct device_n
 	return 0;
 }
 
-static int __pmac
-core99_airport_enable(struct device_node* node, int param, int value)
+static long __pmac
+core99_airport_enable(struct device_node* node, long param, long value)
 {
 	struct macio_chip*	macio;
 	unsigned long		flags;
@@ -1063,8 +1061,8 @@ core99_airport_enable(struct device_node
 }
 
 #ifdef CONFIG_SMP
-static int __pmac
-core99_reset_cpu(struct device_node* node, int param, int value)
+static long __pmac
+core99_reset_cpu(struct device_node* node, long param, long value)
 {
 	unsigned int reset_io = 0;
 	unsigned long flags;
@@ -1099,7 +1097,7 @@ core99_reset_cpu(struct device_node* nod
 	MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);
 	(void)MACIO_IN8(reset_io);
 	udelay(1);
-	MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTOUT_DATA | KEYLARGO_GPIO_OUTPUT_ENABLE);
+	MACIO_OUT8(reset_io, 0);
 	(void)MACIO_IN8(reset_io);
 	UNLOCK(flags);
 
@@ -1107,8 +1105,8 @@ core99_reset_cpu(struct device_node* nod
 }
 #endif /* CONFIG_SMP */
 
-static int __pmac
-core99_usb_enable(struct device_node* node, int param, int value)
+static long __pmac
+core99_usb_enable(struct device_node* node, long param, long value)
 {
 	struct macio_chip* macio;
 	unsigned long flags;
@@ -1121,9 +1119,6 @@ core99_usb_enable(struct device_node* no
 	    macio->type != macio_intrepid)
 		return -ENODEV;
 
-	/* XXX Fix handling of 3rd USB controller in Intrepid, move the
-	 * port connect stuff (KL4_*) to the sleep code eventually
-	 */
 	prop = (char *)get_property(node, "AAPL,clock-id", NULL);
 	if (!prop)
 		return -ENODEV;
@@ -1131,6 +1126,8 @@ core99_usb_enable(struct device_node* no
 		number = 0;
 	else if (strncmp(prop, "usb1u148", 8) == 0)
 		number = 2;
+	else if (strncmp(prop, "usb2u248", 8) == 0)
+		number = 4;
 	else
 		return -ENODEV;
 
@@ -1147,44 +1144,79 @@ core99_usb_enable(struct device_node* no
 			mdelay(1);
 			LOCK(flags);
 			MACIO_BIS(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
-		} else {
+		} else if (number == 2) {
 			MACIO_BIC(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
 			UNLOCK(flags);
 			(void)MACIO_IN32(KEYLARGO_FCR0);
 			mdelay(1);
 			LOCK(flags);
 			MACIO_BIS(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
+		} else if (number == 4) {
+			MACIO_BIC(KEYLARGO_FCR1, (KL1_USB2_PAD_SUSPEND0 | KL1_USB2_PAD_SUSPEND1));
+			UNLOCK(flags);
+			(void)MACIO_IN32(KEYLARGO_FCR1);
+			mdelay(1);
+			LOCK(flags);
+			MACIO_BIS(KEYLARGO_FCR0, KL1_USB2_CELL_ENABLE);
+		}
+		if (number < 4) {
+			reg = MACIO_IN32(KEYLARGO_FCR4);
+			reg &=	~(KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |
+				KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number));
+			reg &=	~(KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |
+				KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1));
+			MACIO_OUT32(KEYLARGO_FCR4, reg);
+			(void)MACIO_IN32(KEYLARGO_FCR4);
+			udelay(10);
+		} else {
+			reg = MACIO_IN32(KEYLARGO_FCR3);
+			reg &=	~(KL3_IT_PORT_WAKEUP_ENABLE(0) | KL3_IT_PORT_RESUME_WAKE_EN(0) |
+				KL3_IT_PORT_CONNECT_WAKE_EN(0) | KL3_IT_PORT_DISCONNECT_WAKE_EN(0));
+			reg &=	~(KL3_IT_PORT_WAKEUP_ENABLE(1) | KL3_IT_PORT_RESUME_WAKE_EN(1) |
+				KL3_IT_PORT_CONNECT_WAKE_EN(1) | KL3_IT_PORT_DISCONNECT_WAKE_EN(1));
+			MACIO_OUT32(KEYLARGO_FCR3, reg);
+			(void)MACIO_IN32(KEYLARGO_FCR3);
+			udelay(10);
 		}
-		reg = MACIO_IN32(KEYLARGO_FCR4);
-		reg &=	~(KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |
-			KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number));
-		reg &=	~(KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |
-			KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1));
-		MACIO_OUT32(KEYLARGO_FCR4, reg);
-		(void)MACIO_IN32(KEYLARGO_FCR4);
-		udelay(10);
 	} else {
 		/* Turn OFF */
-		reg = MACIO_IN32(KEYLARGO_FCR4);
-		reg |=	KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |
-			KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number);
-		reg |=	KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |
-			KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1);
-		MACIO_OUT32(KEYLARGO_FCR4, reg);
-		(void)MACIO_IN32(KEYLARGO_FCR4);
-		udelay(1);
+		if (number < 4) {
+			reg = MACIO_IN32(KEYLARGO_FCR4);
+			reg |=	KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |
+				KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number);
+			reg |=	KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |
+				KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1);
+			MACIO_OUT32(KEYLARGO_FCR4, reg);
+			(void)MACIO_IN32(KEYLARGO_FCR4);
+			udelay(1);
+		} else {
+			reg = MACIO_IN32(KEYLARGO_FCR3);
+			reg |=	KL3_IT_PORT_WAKEUP_ENABLE(0) | KL3_IT_PORT_RESUME_WAKE_EN(0) |
+				KL3_IT_PORT_CONNECT_WAKE_EN(0) | KL3_IT_PORT_DISCONNECT_WAKE_EN(0);
+			reg |=	KL3_IT_PORT_WAKEUP_ENABLE(1) | KL3_IT_PORT_RESUME_WAKE_EN(1) |
+				KL3_IT_PORT_CONNECT_WAKE_EN(1) | KL3_IT_PORT_DISCONNECT_WAKE_EN(1);
+			MACIO_OUT32(KEYLARGO_FCR3, reg);
+			(void)MACIO_IN32(KEYLARGO_FCR3);
+			udelay(1);
+		}
 		if (number == 0) {
 			MACIO_BIC(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);
 			(void)MACIO_IN32(KEYLARGO_FCR0);
 			udelay(1);
 			MACIO_BIS(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));
 			(void)MACIO_IN32(KEYLARGO_FCR0);
-		} else {
+		} else if (number == 2) {
 			MACIO_BIC(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);
 			(void)MACIO_IN32(KEYLARGO_FCR0);
 			udelay(1);
 			MACIO_BIS(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));
 			(void)MACIO_IN32(KEYLARGO_FCR0);
+		} else if (number == 4) {
+			MACIO_BIC(KEYLARGO_FCR1, KL1_USB2_CELL_ENABLE);
+			(void)MACIO_IN32(KEYLARGO_FCR1);
+			udelay(1);
+			MACIO_BIS(KEYLARGO_FCR1, (KL1_USB2_PAD_SUSPEND0 | KL1_USB2_PAD_SUSPEND1));
+			(void)MACIO_IN32(KEYLARGO_FCR1);
 		}
 		udelay(1);
 	}
@@ -1193,8 +1225,8 @@ core99_usb_enable(struct device_node* no
 	return 0;
 }
 
-static int __pmac
-core99_firewire_enable(struct device_node* node, int param, int value)
+static long __pmac
+core99_firewire_enable(struct device_node* node, long param, long value)
 {
 	unsigned long flags;
 	struct macio_chip* macio;
@@ -1220,8 +1252,8 @@ core99_firewire_enable(struct device_nod
 	return 0;
 }
 
-static int __pmac
-core99_firewire_cable_power(struct device_node* node, int param, int value)
+static long __pmac
+core99_firewire_cable_power(struct device_node* node, long param, long value)
 {
 	unsigned long flags;
 	struct macio_chip* macio;
@@ -1251,8 +1283,10 @@ core99_firewire_cable_power(struct devic
 	return 0;
 }
 
-static int __pmac
-core99_read_gpio(struct device_node* node, int param, int value)
+#endif /* CONFIG_POWER4 */
+
+static long __pmac
+core99_read_gpio(struct device_node* node, long param, long value)
 {
 	struct macio_chip* macio = &macio_chips[0];
 
@@ -1260,8 +1294,8 @@ core99_read_gpio(struct device_node* nod
 }
 
 
-static int __pmac
-core99_write_gpio(struct device_node* node, int param, int value)
+static long __pmac
+core99_write_gpio(struct device_node* node, long param, long value)
 {
 	struct macio_chip* macio = &macio_chips[0];
 
@@ -1269,6 +1303,145 @@ core99_write_gpio(struct device_node* no
 	return 0;
 }
 
+#ifdef CONFIG_POWER4
+
+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;
+	u8 pbus, pid;
+
+	/* 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
+	 */
+	if (pci_device_from_OF_node(node, &pbus, &pid) == 0)
+		pdev = pci_find_slot(pbus, pid);
+
+	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;
+	u8 pbus, pid;
+
+	/* 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
+	 */
+	if (pci_device_from_OF_node(node, &pbus, &pid) == 0)
+		pdev = pci_find_slot(pbus, pid);
+
+	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);
+}
+
+#endif /* CONFIG_POWER4 */
+
+#ifndef CONFIG_POWER4
+
 static void __pmac
 keylargo_shutdown(struct macio_chip* macio, int sleep_mode)
 {
@@ -1541,8 +1714,8 @@ core99_wake_up(void)
 	return 0;
 }
 
-static int __pmac
-core99_sleep_state(struct device_node* node, int param, int value)
+static long __pmac
+core99_sleep_state(struct device_node* node, long param, long value)
 {
 	/* Param == 1 means to enter the "fake sleep" mode that is
 	 * used for CPU speed switch
@@ -1568,8 +1741,10 @@ core99_sleep_state(struct device_node* n
 	return 0;
 }
 
-static int __pmac
-generic_get_mb_info(struct device_node* node, int param, int value)
+#endif /* CONFIG_POWER4 */
+
+static long __pmac
+generic_get_mb_info(struct device_node* node, long param, long value)
 {
 	switch(param) {
 		case PMAC_MB_INFO_MODEL:
@@ -1579,9 +1754,9 @@ generic_get_mb_info(struct device_node* 
 		case PMAC_MB_INFO_NAME:
 			/* hack hack hack... but should work */
 			*((const char **)value) = pmac_mb.model_name;
-			break;
+			return 0;
 	}
-	return 0;
+	return -EINVAL;
 }
 
 
@@ -1596,6 +1771,8 @@ static struct feature_table_entry any_fe
 	{ 0, NULL }
 };
 
+#ifndef CONFIG_POWER4
+
 /* OHare based motherboards. Currently, we only use these on the
  * 2400,3400 and 3500 series powerbooks. Some older desktops seem
  * to have issues with turning on/off those asic cells
@@ -1741,10 +1918,29 @@ static struct feature_table_entry intrep
 	{ 0, NULL }
 };
 
+#else /* CONFIG_POWER4 */
+
+/* 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 },
+#ifdef CONFIG_SMP
+	{ PMAC_FTR_RESET_CPU,		g5_reset_cpu },
+#endif /* CONFIG_SMP */
+	{ PMAC_FTR_READ_GPIO,		core99_read_gpio },
+	{ PMAC_FTR_WRITE_GPIO,		core99_write_gpio },
+	{ 0, NULL }
+};
+
+#endif /* CONFIG_POWER4 */
+
 static struct pmac_mb_def pmac_mb_defs[] __pmacdata = {
 	/* Warning: ordering is important as some models may claim
 	 * beeing compatible with several types
 	 */
+#ifndef CONFIG_POWER4
 	{	"AAPL,8500",			"PowerMac 8500/8600",
 		PMAC_TYPE_PSURGE,		NULL,
 		0
@@ -1753,6 +1949,14 @@ static struct pmac_mb_def pmac_mb_defs[]
 		PMAC_TYPE_PSURGE,		NULL,
 		0
 	},
+	{	"AAPL,7200",			"PowerMac 7200",
+		PMAC_TYPE_PSURGE,		NULL,
+		0
+	},
+	{	"AAPL,7300",			"PowerMac 7200/7300",
+		PMAC_TYPE_PSURGE,		NULL,
+		0
+	},
 	{	"AAPL,7500",			"PowerMac 7500",
 		PMAC_TYPE_PSURGE,		NULL,
 		0
@@ -1905,20 +2109,43 @@ static struct pmac_mb_def pmac_mb_defs[]
 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
 		PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
 	},
+	{	"PowerBook5,2",			"PowerBook G4 15\"",
+		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
+		PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+	},
+	{	"PowerBook5,3",			"PowerBook G4 17\"",
+		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
+		PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+	},
 	{	"PowerBook6,1",			"PowerBook G4 12\"",
 		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
 		PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
 	},
+	{	"PowerBook6,2",			"PowerBook G4",
+		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
+		PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+	},
+	{	"PowerBook6,3",			"iBook G4",
+		PMAC_TYPE_UNKNOWN_INTREPID,	intrepid_features,
+		PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,
+	},
+#else /* CONFIG_POWER4 */
+	{	"PowerMac7,2",			"PowerMac G5",
+		PMAC_TYPE_POWERMAC_G5,		g5_features,
+		0,
+	},
+#endif /* CONFIG_POWER4 */
 };
 
 /*
  * The toplevel feature_call callback
  */
-int __pmac
+long __pmac
 pmac_do_feature_call(unsigned int selector, ...)
 {
 	struct device_node* node;
-	int param, value, i;
+	long param, value;
+	int i;
 	feature_call func = NULL;
 	va_list args;
 
@@ -1939,8 +2166,8 @@ pmac_do_feature_call(unsigned int select
 
 	va_start(args, selector);
 	node = (struct device_node*)va_arg(args, void*);
-	param = va_arg(args, int);
-	value = va_arg(args, int);
+	param = va_arg(args, long);
+	value = va_arg(args, long);
 	va_end(args);
 
 	return func(node, param, value);
@@ -1976,6 +2203,7 @@ probe_motherboard(void)
 
 	/* Fallback to selection depending on mac-io chip type */
 	switch(macio->type) {
+#ifndef CONFIG_POWER4
 	    case macio_grand_central:
 		pmac_mb.model_id = PMAC_TYPE_PSURGE;
 		pmac_mb.model_name = "Unknown PowerSurge";
@@ -2009,10 +2237,18 @@ probe_motherboard(void)
 		pmac_mb.model_name = "Unknown Intrepid-based";
 	    	pmac_mb.features = intrepid_features;
 	    	break;
+#else /* CONFIG_POWER4 */
+	    case macio_keylargo2:
+		pmac_mb.model_id = PMAC_TYPE_POWERMAC_G5;
+		pmac_mb.model_name = "Unknown G5";
+	    	pmac_mb.features = g5_features;
+	    	break;
+#endif /* CONFIG_POWER4 */
 	    default:
 	    	return -ENODEV;
 	}
 found:
+#ifndef CONFIG_POWER4
 	/* Fixup Hooper vs. Comet */
 	if (pmac_mb.model_id == PMAC_TYPE_HOOPER) {
 		u32* mach_id_ptr = (u32*)ioremap(0xf3000034, 4);
@@ -2026,6 +2262,7 @@ found:
 			pmac_mb.model_id = PMAC_TYPE_COMET;
 		iounmap(mach_id_ptr);
 	}
+#endif /* CONFIG_POWER4 */
 
 #ifdef CONFIG_6xx
 	/* Set default value of powersave_nap on machines that support it.
@@ -2057,7 +2294,9 @@ found:
 	 */
 	powersave_lowspeed = 1;
 #endif /* CONFIG_6xx */
-
+#ifdef CONFIG_POWER4
+	powersave_nap = 1;
+#endif
 	/* Check for "mobile" machine */
 	if (model && (strncmp(model, "PowerBook", 9) == 0
 		   || strncmp(model, "iBook", 5) == 0))
@@ -2076,18 +2315,26 @@ probe_uninorth(void)
 	unsigned long actrl;
 
 	/* Locate core99 Uni-N */
-	uninorth_node = find_devices("uni-n");
+	uninorth_node = of_find_node_by_name(NULL, "uni-n");
+	/* Locate G5 u3 */
+	if (uninorth_node == NULL) {
+		uninorth_node = of_find_node_by_name(NULL, "u3");
+		uninorth_u3 = 1;
+	}
 	if (uninorth_node && uninorth_node->n_addrs > 0) {
-		uninorth_base = ioremap(uninorth_node->addrs[0].address, 0x4000);
+		unsigned long address = uninorth_node->addrs[0].address;
+		uninorth_base = ioremap(address, 0x40000);
 		uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));
+		if (uninorth_u3)
+			u3_ht = ioremap(address + U3_HT_CONFIG_BASE, 0x1000);
 	} else
 		uninorth_node = NULL;
 
 	if (!uninorth_node)
 		return;
 
-	printk(KERN_INFO "Found Uninorth memory controller & host bridge, revision: %d\n",
-			uninorth_rev);
+	printk(KERN_INFO "Found %s memory controller & host bridge, revision: %d\n",
+	       uninorth_u3 ? "U3" : "UniNorth", uninorth_rev);
 	printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base);
 
 	/* Set the arbitrer QAck delay according to what Apple does
@@ -2172,6 +2419,7 @@ probe_macios(void)
 	probe_one_macio("mac-io", "paddington", macio_paddington);
 	probe_one_macio("mac-io", "gatwick", macio_gatwick);
 	probe_one_macio("mac-io", "heathrow", macio_heathrow);
+	probe_one_macio("mac-io", "K2-Keylargo", macio_keylargo2);
 
 	/* Make sure the "main" macio chip appear first */
 	if (macio_chips[0].type == macio_gatwick
@@ -2244,19 +2492,60 @@ set_initial_features(void)
 		MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);
 	}
 
+#ifdef CONFIG_POWER4
+	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");
+		}
+	}
+#else /* CONFIG_POWER4 */
+
 	if (macio_chips[0].type == macio_keylargo ||
 	    macio_chips[0].type == macio_pangea ||
 	    macio_chips[0].type == macio_intrepid) {
 		/* Enable GMAC for now for PCI probing. It will be disabled
 		 * later on after PCI probe
 		 */
-		np = find_devices("ethernet");
+		np = of_find_node_by_name(NULL, "ethernet");
 		while(np) {
 			if (np->parent
 			    && device_is_compatible(np->parent, "uni-north")
 			    && device_is_compatible(np, "gmac"))
 				core99_gmac_enable(np, 0, 1);
-			np = np->next;
+			np = of_find_node_by_name(np, "ethernet");
 		}
 
 		/* Enable FW before PCI probe. Will be disabled later on
@@ -2264,7 +2553,7 @@ set_initial_features(void)
 		 * dealing with uninorth internal cell and not a PCI cell
 		 * on the external PCI. The code below works though.
 		 */
-		np = find_devices("firewire");
+		np = of_find_node_by_name(NULL, "firewire");
 		while(np) {
 			if (np->parent
 			    && device_is_compatible(np->parent, "uni-north")
@@ -2274,18 +2563,18 @@ set_initial_features(void)
 				macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;
 				core99_firewire_enable(np, 0, 1);
 			}
-			np = np->next;
+			np = of_find_node_by_name(np, "firewire");
 		}
 
 		/* Enable ATA-100 before PCI probe. */
-		np = find_devices("ata-6");
+		np = of_find_node_by_name(NULL, "ata-6");
 		while(np) {
 			if (np->parent
 			    && device_is_compatible(np->parent, "uni-north")
 			    && device_is_compatible(np, "kauai-ata")) {
 				core99_ata100_enable(np, 1);
 			}
-			np = np->next;
+			np = of_find_node_by_name(np, "ata-6");
 		}
 
 		/* Switch airport off */
@@ -2313,6 +2602,99 @@ set_initial_features(void)
 		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);
 	}
 
+	/* Hack for bumping clock speed on the new PowerBooks and the
+	 * iBook G4. This implements the "platform-do-clockspreading" OF
+	 * property. For safety, we also check the product ID in the
+	 * device-tree to make reasonably sure we won't set wrong values
+	 * in the clock chip.
+	 *
+	 * Of course, ultimately, we have to implement a real parser for
+	 * the platform-do-* stuff...
+	 */
+	while (machine_is_compatible("PowerBook5,2") ||
+	       machine_is_compatible("PowerBook5,3") ||
+	       machine_is_compatible("PowerBook6,2") ||
+	       machine_is_compatible("PowerBook6,3")) {
+		struct device_node *ui2c = of_find_node_by_type(NULL, "i2c");
+		struct device_node *dt = of_find_node_by_name(NULL, "device-tree");
+		u8 buffer[9];
+		u32 *productID;
+		int i, rc, changed = 0;
+		
+		if (dt == NULL)
+			break;
+		productID = (u32 *)get_property(dt, "pid#", NULL);
+		if (productID == NULL)
+			break;
+		while(ui2c) {
+			struct device_node *p = of_get_parent(ui2c);
+			if (p && !strcmp(p->name, "uni-n"))
+				break;
+			ui2c = of_find_node_by_type(np, "i2c");
+		}
+		if (ui2c == NULL)
+			break;
+		DBG("Trying to bump clock speed for PID: %08x...\n", *productID);
+		rc = pmac_low_i2c_open(ui2c, 1);
+		if (rc != 0)
+			break;
+		pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
+		rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
+		DBG("read result: %d,", rc);
+		if (rc != 0) {
+			pmac_low_i2c_close(ui2c);
+			break;
+		}
+		for (i=0; i<9; i++)
+			DBG(" %02x", buffer[i]);
+		DBG("\n");
+		
+		switch(*productID) {
+		case 0x1182:	/* AlBook 12" rev 2 */
+		case 0x1183:	/* iBook G4 12" */
+			buffer[0] = (buffer[0] & 0x8f) | 0x70;
+			buffer[2] = (buffer[2] & 0x7f) | 0x00;
+			buffer[5] = (buffer[5] & 0x80) | 0x31;
+			buffer[6] = (buffer[6] & 0x40) | 0xb0;
+			buffer[7] = (buffer[7] & 0x00) | 0xc0;
+			buffer[8] = (buffer[8] & 0x00) | 0x30;
+			changed = 1;
+			break;
+		case 0x3142:	/* AlBook 15" (ATI M10) */
+		case 0x3143:	/* AlBook 17" (ATI M10) */
+			buffer[0] = (buffer[0] & 0xaf) | 0x50;
+			buffer[2] = (buffer[2] & 0x7f) | 0x00;
+			buffer[5] = (buffer[5] & 0x80) | 0x31;
+			buffer[6] = (buffer[6] & 0x40) | 0xb0;
+			buffer[7] = (buffer[7] & 0x00) | 0xd0;
+			buffer[8] = (buffer[8] & 0x00) | 0x30;
+			changed = 1;
+			break;
+		default:
+			DBG("i2c-hwclock: Machine model not handled\n");
+			break;
+		}
+		if (!changed) {
+			pmac_low_i2c_close(ui2c);
+			break;
+		}
+		pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_stdsub);
+		rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_write, 0x80, buffer, 9);
+		DBG("write result: %d,", rc);
+		pmac_low_i2c_setmode(ui2c, pmac_low_i2c_mode_combined);
+		rc = pmac_low_i2c_xfer(ui2c, 0xd2 | pmac_low_i2c_read, 0x80, buffer, 9);
+		DBG("read result: %d,", rc);
+		if (rc != 0) {
+			pmac_low_i2c_close(ui2c);
+			break;
+		}
+		for (i=0; i<9; i++)
+			DBG(" %02x", buffer[i]);
+		pmac_low_i2c_close(ui2c);
+		break;
+	}
+
+#endif /* CONFIG_POWER4 */
 
 	/* On all machines, switch modem & serial ports off */
 	np = find_devices("ch-a");
@@ -2339,6 +2721,9 @@ pmac_feature_init(void)
 		return;
 	}
 
+	/* Setup low-level i2c stuffs */
+	pmac_init_low_i2c();
+
 	/* Probe machine type */
 	if (probe_motherboard())
 		printk(KERN_WARNING "Unknown PowerMac !\n");
@@ -2367,3 +2752,55 @@ pmac_feature_late_init(void)
 }
 
 device_initcall(pmac_feature_late_init);
+
+#ifdef CONFIG_POWER4
+
+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)
+{
+	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;
+	}
+	if (pci_device_from_OF_node(pcix_node, &px_bus, &px_devfn) != 0) {
+		printk("PCI-X bridge found but not matched to pci\n");
+		return;
+	}
+	px_hose = pci_find_hose_for_OF_device(pcix_node);
+	if (px_hose == NULL) {
+		printk("PCI-X bridge found but not matched to host\n");
+		return;
+	}	
+	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 /* CONFIG_POWER4 */
diff -puN /dev/null arch/ppc/platforms/pmac_low_i2c.c
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/arch/ppc/platforms/pmac_low_i2c.c	2004-01-28 23:09:16.000000000 -0800
@@ -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 -puN arch/ppc/platforms/pmac_nvram.c~big-pmac-3 arch/ppc/platforms/pmac_nvram.c
--- 25/arch/ppc/platforms/pmac_nvram.c~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/arch/ppc/platforms/pmac_nvram.c	2004-01-28 23:09:16.000000000 -0800
@@ -8,8 +8,7 @@
  *  as published by the Free Software Foundation; either version
  *  2 of the License, or (at your option) any later version.
  *
- *  Todo: - cleanup some coding horrors in the flash code
- *        - add support for the OF persistent properties
+ *  Todo: - add support for the OF persistent properties
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -21,29 +20,40 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
+#include <linux/adb.h>
+#include <linux/pmu.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>
-#include <linux/adb.h>
-#include <linux/pmu.h>
 
-#undef DEBUG
+#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
 
-/* Core99 nvram is a flash */
-#define CORE99_FLASH_STATUS_DONE	0x80
-#define CORE99_FLASH_STATUS_ERR		0x38
-#define CORE99_FLASH_CMD_ERASE_CONFIRM	0xd0
-#define CORE99_FLASH_CMD_ERASE_SETUP	0x20
-#define CORE99_FLASH_CMD_RESET		0xff
-#define CORE99_FLASH_CMD_WRITE_SETUP	0x40
+/* 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 {
@@ -70,21 +80,110 @@ static volatile unsigned char *nvram_dat
 static int nvram_mult, is_core_99;
 static int core99_bank = 0;
 static int nvram_partitions[3];
-
-/* FIXME: kmalloc fails to allocate the image now that I had to move it
- *        before time_init(). For now, I allocate a static buffer here
- *        but it's a waste of space on all but core99 machines
- */
-#if 0
-static char* nvram_image;
-#else
-static char nvram_image[NVRAM_SIZE] __pmacdata;
-#endif
+static spinlock_t nv_lock = SPIN_LOCK_UNLOCKED;
 
 extern int pmac_newworld;
+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 unsigned char __pmac core99_nvram_read_byte(int addr)
+{
+	if (nvram_image == NULL)
+		return 0xff;
+	return nvram_image[addr];
+}
+
+static void __pmac core99_nvram_write_byte(int addr, unsigned char val)
+{
+	if (nvram_image == NULL)
+		return;
+	nvram_image[addr] = val;
+}
+
+
+static unsigned char __openfirmware direct_nvram_read_byte(int addr)
+{
+	return in_8(&nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult]);
+}
+
+static void __openfirmware direct_nvram_write_byte(int addr, unsigned char val)
+{
+	out_8(&nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult], val);
+}
+
+
+static unsigned char __pmac indirect_nvram_read_byte(int addr)
+{
+	unsigned char val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&nv_lock, flags);
+	out_8(nvram_addr, addr >> 5);
+	val = in_8(&nvram_data[(addr & 0x1f) << 4]);
+	spin_unlock_irqrestore(&nv_lock, flags);
+
+	return val;
+}
+
+static void __pmac indirect_nvram_write_byte(int addr, unsigned char val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&nv_lock, flags);
+	out_8(nvram_addr, addr >> 5);
+	out_8(&nvram_data[(addr & 0x1f) << 4], val);
+	spin_unlock_irqrestore(&nv_lock, flags);
+}
+
+
+#ifdef CONFIG_ADB_PMU
+
+static void __pmac pmu_nvram_complete(struct adb_request *req)
+{
+	if (req->arg)
+		complete((struct completion *)req->arg);
+}
 
-static u8 __pmac
-chrp_checksum(struct chrp_header* hdr)
+static unsigned char __pmac pmu_nvram_read_byte(int addr)
+{
+	struct adb_request req;
+	DECLARE_COMPLETION(req_complete); 
+	
+	req.arg = system_running ? &req_complete : NULL;
+	if (pmu_request(&req, pmu_nvram_complete, 3, PMU_READ_NVRAM,
+			(addr >> 8) & 0xff, addr & 0xff))
+		return 0xff;
+	if (system_running)
+		wait_for_completion(&req_complete);
+	while (!req.complete)
+		pmu_poll();
+	return req.reply[0];
+}
+
+static void __pmac pmu_nvram_write_byte(int addr, unsigned char val)
+{
+	struct adb_request req;
+	DECLARE_COMPLETION(req_complete); 
+	
+	req.arg = system_running ? &req_complete : NULL;
+	if (pmu_request(&req, pmu_nvram_complete, 4, PMU_WRITE_NVRAM,
+			(addr >> 8) & 0xff, addr & 0xff, val))
+		return;
+	if (system_running)
+		wait_for_completion(&req_complete);
+	while (!req.complete)
+		pmu_poll();
+}
+
+#endif /* CONFIG_ADB_PMU */
+
+
+static u8 __pmac chrp_checksum(struct chrp_header* hdr)
 {
 	u8 *ptr;
 	u16 sum = hdr->signature;
@@ -95,8 +194,7 @@ chrp_checksum(struct chrp_header* hdr)
 	return sum;
 }
 
-static u32 __pmac
-core99_calc_adler(u8 *buffer)
+static u32 __pmac core99_calc_adler(u8 *buffer)
 {
 	int cnt;
 	u32 low, high;
@@ -118,86 +216,186 @@ core99_calc_adler(u8 *buffer)
 	return (high << 16) | low;
 }
 
-static u32 __pmac
-core99_check(u8* datas)
+static u32 __pmac core99_check(u8* datas)
 {
 	struct core99_header* hdr99 = (struct core99_header*)datas;
 
 	if (hdr99->hdr.signature != CORE99_SIGNATURE) {
-#ifdef DEBUG
-		printk("Invalid signature\n");
-#endif
+		DBG("Invalid signature\n");
 		return 0;
 	}
 	if (hdr99->hdr.cksum != chrp_checksum(&hdr99->hdr)) {
-#ifdef DEBUG
-		printk("Invalid checksum\n");
-#endif
+		DBG("Invalid checksum\n");
 		return 0;
 	}
 	if (hdr99->adler != core99_calc_adler(datas)) {
-#ifdef DEBUG
-		printk("Invalid adler\n");
-#endif
+		DBG("Invalid adler\n");
 		return 0;
 	}
 	return hdr99->generation;
 }
 
-static int __pmac
-core99_erase_bank(int bank)
+static int __pmac sm_erase_bank(int bank)
 {
 	int stat, i;
+	unsigned long timeout;
 
 	u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE;
 
-	out_8(base, CORE99_FLASH_CMD_ERASE_SETUP);
-	out_8(base, CORE99_FLASH_CMD_ERASE_CONFIRM);
-	do { stat = in_8(base); }
-	while(!(stat & CORE99_FLASH_STATUS_DONE));
-	out_8(base, CORE99_FLASH_CMD_RESET);
-	if (stat & CORE99_FLASH_STATUS_ERR) {
-		printk("nvram: flash error 0x%02x on erase !\n", stat);
-		return -ENXIO;
-	}
+       	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("nvram: flash erase failed !\n");
+			printk(KERN_ERR "nvram: Sharp/Micron flash erase failed !\n");
 			return -ENXIO;
 		}
 	return 0;
 }
 
-static int __pmac
-core99_write_bank(int bank, u8* datas)
+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, CORE99_FLASH_CMD_WRITE_SETUP);
+		out_8(base+i, SM_FLASH_CMD_WRITE_SETUP);
+		udelay(1);
 		out_8(base+i, datas[i]);
-		do { stat = in_8(base); }
-		while(!(stat & CORE99_FLASH_STATUS_DONE));
-		if (stat & CORE99_FLASH_STATUS_ERR)
+		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, CORE99_FLASH_CMD_RESET);
-	if (stat & CORE99_FLASH_STATUS_ERR) {
-		printk("nvram: flash error 0x%02x on write !\n", stat);
-		return -ENXIO;
+	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("nvram: flash write failed !\n");
+			printk(KERN_ERR "nvram: AMD flash write failed !\n");
 			return -ENXIO;
 		}
 	return 0;
 }
 
-static void __init
-lookup_partitions(void)
+static void __init lookup_partitions(void)
 {
 	u8 buffer[17];
 	int i, offset;
@@ -227,15 +425,49 @@ lookup_partitions(void)
 		nvram_partitions[pmac_nvram_XPRAM] = 0x1300;
 		nvram_partitions[pmac_nvram_NR] = 0x1400;
 	}
+	DBG("nvram: OF partition at 0x%x\n", nvram_partitions[pmac_nvram_OF]);
+	DBG("nvram: XP partition at 0x%x\n", nvram_partitions[pmac_nvram_XPRAM]);
+	DBG("nvram: NR partition at 0x%x\n", nvram_partitions[pmac_nvram_NR]);
+}
+
+static void __pmac core99_nvram_sync(void)
+{
+	struct core99_header* hdr99;
+	unsigned long flags;
+
+	if (!is_core_99 || !nvram_data || !nvram_image)
+		return;
+
+	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);
+
 #ifdef DEBUG
-	printk("nvram: OF partition at 0x%x\n", nvram_partitions[pmac_nvram_OF]);
-	printk("nvram: XP partition at 0x%x\n", nvram_partitions[pmac_nvram_XPRAM]);
-	printk("nvram: NR partition at 0x%x\n", nvram_partitions[pmac_nvram_NR]);
+       	mdelay(2000);
 #endif
 }
 
-void __init
-pmac_nvram_init(void)
+void __init pmac_nvram_init(void)
 {
 	struct device_node *dp;
 
@@ -256,38 +488,65 @@ pmac_nvram_init(void)
 			printk(KERN_ERR "nvram: no address\n");
 			return;
 		}
-#if 0
-		nvram_image = kmalloc(NVRAM_SIZE, GFP_KERNEL);
-		if (!nvram_image) {
-			printk(KERN_ERR "nvram: can't allocate image\n");
+		nvram_image = alloc_bootmem(NVRAM_SIZE);
+		if (nvram_image == NULL) {
+			printk(KERN_ERR "nvram: can't allocate ram image\n");
 			return;
 		}
-#endif
 		nvram_data = ioremap(dp->addrs[0].address, NVRAM_SIZE*2);
-#ifdef DEBUG
-		printk("nvram: Checking bank 0...\n");
-#endif
+		nvram_naddrs = 1; /* Make sure we get the correct case */
+
+		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;
-#ifdef DEBUG
-		printk("nvram: gen0=%d, gen1=%d\n", gen_bank0, gen_bank1);
-		printk("nvram: Active bank is: %d\n", core99_bank);
-#endif
+
+		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_val	= core99_nvram_read_byte;
+		ppc_md.nvram_write_val	= core99_nvram_write_byte;
+		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;
+		}
 	} else if (_machine == _MACH_chrp && nvram_naddrs == 1) {
 		nvram_data = ioremap(dp->addrs[0].address + isa_mem_base,
 				     dp->addrs[0].size);
 		nvram_mult = 1;
+		ppc_md.nvram_read_val	= direct_nvram_read_byte;
+		ppc_md.nvram_write_val	= direct_nvram_write_byte;
 	} else if (nvram_naddrs == 1) {
 		nvram_data = ioremap(dp->addrs[0].address, dp->addrs[0].size);
 		nvram_mult = (dp->addrs[0].size + NVRAM_SIZE - 1) / NVRAM_SIZE;
+		ppc_md.nvram_read_val	= direct_nvram_read_byte;
+		ppc_md.nvram_write_val	= direct_nvram_write_byte;
 	} else if (nvram_naddrs == 2) {
 		nvram_addr = ioremap(dp->addrs[0].address, dp->addrs[0].size);
 		nvram_data = ioremap(dp->addrs[1].address, dp->addrs[1].size);
+		ppc_md.nvram_read_val	= indirect_nvram_read_byte;
+		ppc_md.nvram_write_val	= indirect_nvram_write_byte;
 	} else if (nvram_naddrs == 0 && sys_ctrler == SYS_CTRLER_PMU) {
+#ifdef CONFIG_ADB_PMU
 		nvram_naddrs = -1;
+		ppc_md.nvram_read_val	= pmu_nvram_read_byte;
+		ppc_md.nvram_write_val	= pmu_nvram_write_byte;
+#endif /* CONFIG_ADB_PMU */
 	} else {
 		printk(KERN_ERR "Don't know how to access NVRAM with %d addresses\n",
 		       nvram_naddrs);
@@ -295,117 +554,31 @@ pmac_nvram_init(void)
 	lookup_partitions();
 }
 
-void __pmac
-pmac_nvram_update(void)
-{
-	struct core99_header* hdr99;
-
-	if (!is_core_99 || !nvram_data || !nvram_image)
-		return;
-	if (!memcmp(nvram_image, (u8*)nvram_data + core99_bank*NVRAM_SIZE,
-		NVRAM_SIZE))
-		return;
-#ifdef DEBUG
-	printk("Updating nvram...\n");
-#endif
-	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(core99_bank)) {
-		printk("nvram: Error erasing bank %d\n", core99_bank);
-		return;
-	}
-	if (core99_write_bank(core99_bank, nvram_image))
-		printk("nvram: Error writing bank %d\n", core99_bank);
-}
-
-unsigned char __pmac
-pmac_nvram_read_byte(int addr)
-{
-	switch (nvram_naddrs) {
-#ifdef CONFIG_ADB_PMU
-	case -1: {
-		struct adb_request req;
-
-		if (pmu_request(&req, NULL, 3, PMU_READ_NVRAM,
-				(addr >> 8) & 0xff, addr & 0xff))
-			break;
-		while (!req.complete)
-			pmu_poll();
-		return req.reply[0];
-	}
-#endif
-	case 1:
-		if (is_core_99)
-			return nvram_image[addr];
-		return nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult];
-	case 2:
-		*nvram_addr = addr >> 5;
-		eieio();
-		return nvram_data[(addr & 0x1f) << 4];
-	}
-	return 0;
-}
-
-void __pmac
-pmac_nvram_write_byte(int addr, unsigned char val)
-{
-	switch (nvram_naddrs) {
-#ifdef CONFIG_ADB_PMU
-	case -1: {
-		struct adb_request req;
-
-		if (pmu_request(&req, NULL, 4, PMU_WRITE_NVRAM,
-				(addr >> 8) & 0xff, addr & 0xff, val))
-			break;
-		while (!req.complete)
-			pmu_poll();
-		break;
-	}
-#endif
-	case 1:
-		if (is_core_99) {
-			nvram_image[addr] = val;
-			break;
-		}
-		nvram_data[(addr & (NVRAM_SIZE - 1)) * nvram_mult] = val;
-		break;
-	case 2:
-		*nvram_addr = addr >> 5;
-		eieio();
-		nvram_data[(addr & 0x1f) << 4] = val;
-		break;
-	}
-	eieio();
-}
-
-int __pmac
-pmac_get_partition(int partition)
+int __pmac pmac_get_partition(int partition)
 {
 	return nvram_partitions[partition];
 }
 
-u8 __pmac
-pmac_xpram_read(int xpaddr)
+u8 __pmac pmac_xpram_read(int xpaddr)
 {
 	int offset = nvram_partitions[pmac_nvram_XPRAM];
 
 	if (offset < 0)
-		return 0;
+		return 0xff;
 
-	return pmac_nvram_read_byte(xpaddr + offset);
+	return ppc_md.nvram_read_val(xpaddr + offset);
 }
 
-void __pmac
-pmac_xpram_write(int xpaddr, u8 data)
+void __pmac pmac_xpram_write(int xpaddr, u8 data)
 {
 	int offset = nvram_partitions[pmac_nvram_XPRAM];
 
 	if (offset < 0)
 		return;
 
-	pmac_nvram_write_byte(data, xpaddr + offset);
+	ppc_md.nvram_write_val(xpaddr + offset, data);
 }
+
+EXPORT_SYMBOL(pmac_get_partition);
+EXPORT_SYMBOL(pmac_xpram_read);
+EXPORT_SYMBOL(pmac_xpram_write);
diff -puN arch/ppc/platforms/pmac_pci.c~big-pmac-3 arch/ppc/platforms/pmac_pci.c
--- 25/arch/ppc/platforms/pmac_pci.c~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/arch/ppc/platforms/pmac_pci.c	2004-01-28 23:09:16.000000000 -0800
@@ -1,13 +1,11 @@
 /*
  * Support for PCI bridges found on Power Macintoshes.
- *
- * This includes support for bandit, chaos, grackle (motorola
- * MPC106), and uninorth
+ * At present the "bandit" and "chaos" bridges are supported.
+ * Fortunately you access configuration space in the same
+ * way with either bridge.
  *
  * Copyright (C) 1997 Paul Mackerras (paulus@cs.anu.edu.au)
  *
- * 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
@@ -30,11 +28,30 @@
 
 #undef DEBUG
 
-static void add_bridges(struct device_node *dev);
+#ifdef DEBUG
+#ifdef CONFIG_XMON
+extern void xmon_printf(const char *fmt, ...);
+#define DBG(x...) xmon_printf(x)
+#else
+#define DBG(x...) printk(x)
+#endif
+#else
+#define DBG(x...)
+#endif
+
+static int add_bridge(struct device_node *dev);
+extern void pmac_check_ht_link(void);
 
 /* 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;
+#ifdef CONFIG_POWER4
+static struct pci_controller *u3_agp;
+#endif /* CONFIG_POWER4 */
+
+extern u8 pci_cache_line_size;
+
+struct pci_dev *k2_skiplist[2];
 
 /*
  * Magic constants for enabling cache coherency in the bandit/PSX bridge.
@@ -51,7 +68,7 @@ fixup_one_level_bus_range(struct device_
 {
 	for (; node != 0;node = node->sibling) {
 		int * bus_range;
-		unsigned int *class_code;		
+		unsigned int *class_code;
 		int len;
 
 		/* For PCI<->PCI bridges or CardBus bridges, we go down */
@@ -81,7 +98,7 @@ fixup_bus_range(struct device_node *brid
 	int * bus_range;
 	int len;
 
-	/* Lookup the "bus-range" property for the hose */	
+	/* 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",
@@ -92,7 +109,7 @@ fixup_bus_range(struct device_node *brid
 }
 
 /*
- * Apple MacRISC (UniNorth, Bandit, Chaos) PCI controllers.
+ * 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
@@ -106,6 +123,11 @@ fixup_bus_range(struct device_node *brid
  * 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)	\
@@ -211,12 +233,22 @@ static struct pci_ops macrisc_pci_ops =
 static int __pmac
 chaos_validate_dev(struct pci_bus *bus, int devfn, int offset)
 {
-	if (pci_busdev_to_OF_node(bus, devfn) == 0)
+	struct device_node *np;
+	u32 *vendor, *device;
+
+	np = pci_busdev_to_OF_node(bus, devfn);
+	if (np == NULL)
 		return PCIBIOS_DEVICE_NOT_FOUND;
-	if (/*(dev->vendor == 0x106b) && (dev->device == 3) &&*/ (offset >= 0x10)
-	    && (offset != 0x14) && (offset != 0x18) && (offset <= 0x24)) {
+
+	vendor = (u32 *)get_property(np, "vendor-id", NULL);
+	device = (u32 *)get_property(np, "device-id", NULL);
+	if (vendor == NULL || device == NULL)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	if ((*vendor == 0x106b) && (*device == 3) && (offset >= 0x10)
+	    && (offset != 0x14) && (offset != 0x18) && (offset <= 0x24))
 		return PCIBIOS_BAD_REGISTER_NUMBER;
-	}
+
 	return PCIBIOS_SUCCESSFUL;
 }
 
@@ -248,6 +280,128 @@ static struct pci_ops chaos_pci_ops =
 	chaos_write_config
 };
 
+#ifdef CONFIG_POWER4
+
+/*
+ * 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 = bus->sysdata;
+	unsigned int addr;
+	int i;
+
+	/*
+	 * 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 = 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 = bus->sysdata;
+	unsigned int addr;
+	int i;
+
+	/*
+	 * 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 = 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
+};
+
+#endif /* CONFIG_POWER4 */
 
 /*
  * For a bandit bridge, turn on cache coherency if necessary.
@@ -309,9 +463,7 @@ init_p2pbridge(void)
 	    || strcmp(p2pbridge->parent->name, "pci") != 0)
 		return;
 	if (pci_device_from_OF_node(p2pbridge, &bus, &devfn) < 0) {
-#ifdef DEBUG
-		printk("Can't find PCI infos for PCI<->PCI bridge\n");
-#endif	
+		DBG("Can't find PCI infos for PCI<->PCI bridge\n");
 		return;
 	}
 	/* Warning: At this point, we have not yet renumbered all busses.
@@ -319,9 +471,7 @@ init_p2pbridge(void)
 	 */
 	hose = pci_find_hose_for_OF_device(p2pbridge);
 	if (!hose) {
-#ifdef DEBUG
-		printk("Can't find hose for PCI<->PCI bridge\n");
-#endif	
+		DBG("Can't find hose for PCI<->PCI bridge\n");
 		return;
 	}
 	if (early_read_config_word(hose, bus, devfn,
@@ -333,13 +483,114 @@ init_p2pbridge(void)
 	early_write_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, val);
 }
 
+/*
+ * Some Apple desktop machines have a NEC PD720100A USB2 controller
+ * on the motherboard. Open Firmware, on these, will disable the
+ * EHCI part of it so it behaves like a pair of OHCI's. This fixup
+ * code re-enables it ;)
+ */
+static void __init
+fixup_nec_usb2(void)
+{
+	struct device_node *nec;
+
+	for (nec = NULL; (nec = of_find_node_by_name(nec, "usb")) != NULL;) {
+		struct pci_controller *hose;
+		u32 data, *prop;
+		u8 bus, devfn;
+		
+		prop = (u32 *)get_property(nec, "vendor-id", NULL);
+		if (prop == NULL)
+			continue;
+		if (0x1033 != *prop)
+			continue;
+		prop = (u32 *)get_property(nec, "device-id", NULL);
+		if (prop == NULL)
+			continue;
+		if (0x0035 != *prop)
+			continue;
+		prop = (u32 *)get_property(nec, "reg", 0);
+		if (prop == NULL)
+			continue;
+		devfn = (prop[0] >> 8) & 0xff;
+		bus = (prop[0] >> 16) & 0xff;
+		if (PCI_FUNC(devfn) != 0)
+			continue;
+		hose = pci_find_hose_for_OF_device(nec);
+		if (!hose)
+			continue;
+		early_read_config_dword(hose, bus, devfn, 0xe4, &data);
+		if (data & 1UL) {
+			printk("Found NEC PD720100A USB2 chip with disabled EHCI, fixing up...\n");
+			data &= ~1UL;
+			early_write_config_dword(hose, bus, devfn, 0xe4, data);
+			early_write_config_byte(hose, bus, devfn | 2, PCI_INTERRUPT_LINE,
+				nec->intrs[0].line);
+		}
+	}
+}
+
 void __init
 pmac_find_bridges(void)
 {
-	add_bridges(find_devices("bandit"));
-	add_bridges(find_devices("chaos"));
-	add_bridges(find_devices("pci"));
+	struct device_node *np, *root;
+	struct device_node *ht = NULL;
+
+	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, "bandit") == 0
+		    || strcmp(np->name, "chaos") == 0
+		    || 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);
+
+	/* Probe HT last as it relies on the agp resources to be already
+	 * setup
+	 */
+	if (ht && add_bridge(ht) != 0)
+		of_node_put(ht);
+
 	init_p2pbridge();
+	fixup_nec_usb2();
+#ifdef CONFIG_POWER4 
+	/* There is something wrong with DMA on U3/HT. I haven't figured out
+	 * the details yet, but if I set the cache line size to 128 bytes like
+	 * it should, I'm getting memory corruption caused by devices like
+	 * sungem (even without the MWI bit set, but maybe sungem doesn't
+	 * care). Right now, it appears that setting up a 64 bytes line size
+	 * works properly, 64 bytes beeing the max transfer size of HT, I
+	 * suppose this is related the way HT/PCI are hooked together. I still
+	 * need to dive into more specs though to be really sure of what's
+	 * going on. --BenH.
+	 *
+	 * Ok, apparently, it's just that HT can't do more than 64 bytes
+	 * transactions. MWI seem to be meaningless there as well, it may
+	 * be worth nop'ing out pci_set_mwi too though I haven't done that
+	 * yet.
+	 *
+	 * Note that it's a bit different for whatever is in the AGP slot.
+	 * For now, I don't care, but this can become a real issue, we
+	 * should probably hook pci_set_mwi anyway to make sure it sets
+	 * the real cache line size in there.
+	 */
+	if (machine_is_compatible("MacRISC4"))
+		pci_cache_line_size = 16; /* 64 bytes */
+
+	pmac_check_ht_link();
+#endif /* CONFIG_POWER4 */
 }
 
 #define GRACKLE_CFA(b, d, o)	(0x80 | ((b) << 8) | ((d) << 16) \
@@ -410,6 +661,118 @@ setup_chaos(struct pci_controller* hose,
 		ioremap(addr->address + 0xc00000, 0x1000);
 }
 
+#ifdef CONFIG_POWER4
+
+static void __init
+setup_u3_agp(struct pci_controller* hose, struct reg_property* addr)
+{
+	/* 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 reg_property *addr)
+{
+	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 = (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 to make 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;
+	}
+}
+
+#endif /* CONFIG_POWER4 */
+
 void __init
 setup_grackle(struct pci_controller *hose)
 {
@@ -426,69 +789,77 @@ setup_grackle(struct pci_controller *hos
  * "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 void __init
-add_bridges(struct device_node *dev)
+static int __init
+add_bridge(struct device_node *dev)
 {
 	int len;
 	struct pci_controller *hose;
 	struct reg_property *addr;
 	char* disp_name;
 	int *bus_range;
-	int first = 1, primary;
+	int primary = 1;
 
-	for (; dev != NULL; dev = dev->next) {
-		addr = (struct reg_property *) get_property(dev, "reg", &len);
-		if (addr == NULL || len < sizeof(*addr)) {
-			printk(KERN_WARNING "Can't use %s: no address\n",
-			       dev->full_name);
-			continue;
-		}
-		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 = pcibios_alloc_controller();
-		if (!hose)
-			continue;
-		hose->arch_data = dev;
-		hose->first_busno = bus_range ? bus_range[0] : 0;
-		hose->last_busno = bus_range ? bus_range[1] : 0xff;
-
-		disp_name = NULL;
-		primary = first;
-		if (device_is_compatible(dev, "uni-north")) {
-			primary = setup_uninorth(hose, addr);
-			disp_name = "UniNorth";
-		} else if (strcmp(dev->name, "pci") == 0) {
-			/* XXX assume this is a mpc106 (grackle) */
-			setup_grackle(hose);
-			disp_name = "Grackle (MPC106)";
-		} else if (strcmp(dev->name, "bandit") == 0) {
-			setup_bandit(hose, addr);
-			disp_name = "Bandit";
-		} else if (strcmp(dev->name, "chaos") == 0) {
-			setup_chaos(hose, addr);
-			disp_name = "Chaos";
-			primary = 0;
-		}
-		printk(KERN_INFO "Found %s PCI host bridge at 0x%08x. Firmware bus number: %d->%d\n",
-			disp_name, addr->address, hose->first_busno, hose->last_busno);
-#ifdef DEBUG
-		printk(" ->Hose at 0x%08lx, cfg_addr=0x%08lx,cfg_data=0x%08lx\n",
-			hose, hose->cfg_addr, hose->cfg_data);
-#endif	
-	
-		/* Interpret the "ranges" property */
-		/* This also maps the I/O region and sets isa_io/mem_base */
-		pci_process_bridge_OF_ranges(hose, dev, primary);
+	DBG("Adding PCI host bridge %s\n", dev->full_name);
 
-		/* Fixup "bus-range" OF property */
-		fixup_bus_range(dev);
+       	addr = (struct reg_property *) get_property(dev, "reg", &len);
+       	if (addr == NULL || len < sizeof(*addr)) {
+       		printk(KERN_WARNING "Can't use %s: no address\n",
+       		       dev->full_name);
+       		return -ENODEV;
+       	}
+       	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 = pcibios_alloc_controller();
+       	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;
+
+	disp_name = NULL;
+#ifdef CONFIG_POWER4
+       	if (device_is_compatible(dev, "u3-agp")) {
+       		setup_u3_agp(hose, addr);
+       		disp_name = "U3-AGP";
+       		primary = 0;
+       	} else if (device_is_compatible(dev, "u3-ht")) {
+       		setup_u3_ht(hose, addr);
+       		disp_name = "U3-HT";
+       		primary = 1;
+       	} else
+#endif /* CONFIG_POWER4 */
+	if (device_is_compatible(dev, "uni-north")) {
+       		primary = setup_uninorth(hose, addr);
+       		disp_name = "UniNorth";
+       	} else if (strcmp(dev->name, "pci") == 0) {
+       		/* XXX assume this is a mpc106 (grackle) */
+       		setup_grackle(hose);
+       		disp_name = "Grackle (MPC106)";
+       	} else if (strcmp(dev->name, "bandit") == 0) {
+       		setup_bandit(hose, addr);
+       		disp_name = "Bandit";
+       	} else if (strcmp(dev->name, "chaos") == 0) {
+       		setup_chaos(hose, addr);
+       		disp_name = "Chaos";
+       		primary = 0;
+       	}
+       	printk(KERN_INFO "Found %s PCI host bridge at 0x%08x. Firmware bus number: %d->%d\n",
+       		disp_name, addr->address, hose->first_busno, hose->last_busno);
+       	DBG(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
+       		hose, hose->cfg_addr, hose->cfg_data);
+
+       	/* Interpret the "ranges" property */
+       	/* This also maps the I/O region and sets isa_io/mem_base */
+       	pci_process_bridge_OF_ranges(hose, dev, primary);
 
-		first &= !primary;
-	}
+       	/* Fixup "bus-range" OF property */
+       	fixup_bus_range(dev);
+
+	return 0;
 }
 
 static void __init
@@ -575,7 +946,7 @@ pmac_pci_enable_device_hook(struct pci_d
 		cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
     		pci_write_config_word(dev, PCI_COMMAND, cmd);
     		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 16);
-    		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 8);
+    		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, pci_cache_line_size);
 	}
 
 	return 0;
@@ -628,3 +999,108 @@ pmac_pcibios_after_init(void)
 	}
 }
 
+void pmac_pci_fixup_cardbus(struct pci_dev* dev)
+{
+	if (_machine != _MACH_Pmac)
+		return;
+	/*
+	 * Fix the interrupt routing on the various cardbus bridges
+	 * used on powerbooks
+	 */
+	if (dev->vendor != PCI_VENDOR_ID_TI)
+		return;
+	if (dev->device == PCI_DEVICE_ID_TI_1130 ||
+	    dev->device == PCI_DEVICE_ID_TI_1131) {
+		u8 val;
+	    	/* Enable PCI interrupt */
+		if (pci_read_config_byte(dev, 0x91, &val) == 0)
+			pci_write_config_byte(dev, 0x91, val | 0x30);
+		/* Disable ISA interrupt mode */
+		if (pci_read_config_byte(dev, 0x92, &val) == 0)
+			pci_write_config_byte(dev, 0x92, val & ~0x06);
+	}
+	if (dev->device == PCI_DEVICE_ID_TI_1210 ||
+	    dev->device == PCI_DEVICE_ID_TI_1211 ||
+	    dev->device == PCI_DEVICE_ID_TI_1410 ||
+	    dev->device == PCI_DEVICE_ID_TI_1510) {
+		u8 val;
+		/* 0x8c == TI122X_IRQMUX, 2 says to route the INTA
+		   signal out the MFUNC0 pin */
+		if (pci_read_config_byte(dev, 0x8c, &val) == 0)
+			pci_write_config_byte(dev, 0x8c, (val & ~0x0f) | 2);
+		/* Disable ISA interrupt mode */
+		if (pci_read_config_byte(dev, 0x92, &val) == 0)
+			pci_write_config_byte(dev, 0x92, val & ~0x06);
+	}
+}
+
+void pmac_pci_fixup_pciata(struct pci_dev* dev)
+{
+       u8 progif = 0;
+
+       /*
+        * On PowerMacs, we try to switch any PCI ATA controller to
+	* fully native mode
+        */
+	if (_machine != _MACH_Pmac)
+		return;
+	/* Some controllers don't have the class IDE */
+	if (dev->vendor == PCI_VENDOR_ID_PROMISE)
+		switch(dev->device) {
+		case PCI_DEVICE_ID_PROMISE_20246:
+		case PCI_DEVICE_ID_PROMISE_20262:
+		case PCI_DEVICE_ID_PROMISE_20263:
+		case PCI_DEVICE_ID_PROMISE_20265:
+		case PCI_DEVICE_ID_PROMISE_20267:
+		case PCI_DEVICE_ID_PROMISE_20268:
+		case PCI_DEVICE_ID_PROMISE_20269:
+		case PCI_DEVICE_ID_PROMISE_20270:
+		case PCI_DEVICE_ID_PROMISE_20271:
+		case PCI_DEVICE_ID_PROMISE_20275:
+		case PCI_DEVICE_ID_PROMISE_20276:
+		case PCI_DEVICE_ID_PROMISE_20277:
+			goto good;
+		}
+	/* Others, check PCI class */
+	if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE)
+		return;
+ good:
+	pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
+	if ((progif & 5) != 5) {
+		printk(KERN_INFO "Forcing PCI IDE into native mode: %s\n", pci_name(dev));
+		(void) pci_write_config_byte(dev, PCI_CLASS_PROG, progif|5);
+		if (pci_read_config_byte(dev, PCI_CLASS_PROG, &progif) ||
+		    (progif & 5) != 5)
+			printk(KERN_ERR "Rewrite of PROGIF failed !\n");
+	}
+}
+
+/*
+ * Disable second function on K2-SATA, it's broken
+ * and disable IO BARs on first one
+ */
+void __pmac pmac_pci_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 -puN arch/ppc/platforms/pmac_pic.c~big-pmac-3 arch/ppc/platforms/pmac_pic.c
--- 25/arch/ppc/platforms/pmac_pic.c~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/arch/ppc/platforms/pmac_pic.c	2004-01-28 23:09:16.000000000 -0800
@@ -34,6 +34,7 @@
 #include <asm/time.h>
 #include <asm/open_pic.h>
 #include <asm/xmon.h>
+#include <asm/pmac_feature.h>
 
 #include "pmac_pic.h"
 
@@ -363,32 +364,76 @@ static int __init enable_second_ohare(vo
 	return irqctrler->intrs[0].line;
 }
 
-void __init
-pmac_pic_init(void)
+#ifdef CONFIG_POWER4
+static irqreturn_t k2u3_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+	int irq;
+
+	irq = openpic2_get_irq(regs);
+	if (irq != -1)
+		ppc_irq_dispatch_handler(regs, irq);
+	return IRQ_HANDLED;
+}
+#endif /* CONFIG_POWER4 */
+
+void __init pmac_pic_init(void)
 {
         int i;
-        struct device_node *irqctrler;
+        struct device_node *irqctrler  = NULL;
+        struct device_node *irqctrler2 = NULL;
+	struct device_node *np;
         unsigned long addr;
 	int irq_cascade = -1;
 
 	/* We first try to detect Apple's new Core99 chipset, since mac-io
 	 * is quite different on those machines and contains an IBM MPIC2.
 	 */
-	irqctrler = find_type_devices("open-pic");
+	np = find_type_devices("open-pic");
+	while(np) {
+		if (np->parent && !strcmp(np->parent->name, "u3"))
+			irqctrler2 = np;
+		else
+			irqctrler = np;
+		np = np->next;
+	}
 	if (irqctrler != NULL)
 	{
-		printk("PowerMac using OpenPIC irq controller\n");
 		if (irqctrler->n_addrs > 0)
 		{
-			unsigned char senses[NR_IRQS];
+			unsigned char senses[128];
+
+			printk(KERN_INFO "PowerMac using OpenPIC irq controller at 0x%08x\n",
+			       irqctrler->addrs[0].address);
 
-			prom_get_irq_senses(senses, 0, NR_IRQS);
+			prom_get_irq_senses(senses, 0, 128);
 			OpenPIC_InitSenses = senses;
-			OpenPIC_NumInitSenses = NR_IRQS;
+			OpenPIC_NumInitSenses = 128;
 			ppc_md.get_irq = openpic_get_irq;
+			pmac_call_feature(PMAC_FTR_ENABLE_MPIC, irqctrler, 0, 0);
 			OpenPIC_Addr = ioremap(irqctrler->addrs[0].address,
 					       irqctrler->addrs[0].size);
 			openpic_init(0);
+
+#ifdef CONFIG_POWER4
+			if (irqctrler2 != NULL && irqctrler2->n_intrs > 0 &&
+			    irqctrler2->n_addrs > 0) {
+				printk(KERN_INFO "Slave OpenPIC at 0x%08x hooked on IRQ %d\n",
+				       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, PMAC_OPENPIC2_OFFSET,
+						    PMAC_OPENPIC2_OFFSET+128);
+				OpenPIC_InitSenses = senses;
+				OpenPIC_NumInitSenses = 128;
+				openpic2_init(PMAC_OPENPIC2_OFFSET);
+				if (request_irq(irqctrler2->intrs[0].line, k2u3_action, 0,
+						"U3->K2 Cascade", NULL))
+					printk("Unable to get OpenPIC IRQ for cascade\n");
+			}
+#endif /* CONFIG_POWER4 */
+
 #ifdef CONFIG_XMON
 			{
 				struct device_node* pswitch;
diff -puN arch/ppc/platforms/pmac_setup.c~big-pmac-3 arch/ppc/platforms/pmac_setup.c
--- 25/arch/ppc/platforms/pmac_setup.c~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/arch/ppc/platforms/pmac_setup.c	2004-01-28 23:09:16.000000000 -0800
@@ -332,7 +332,7 @@ pmac_setup_arch(void)
 
 #ifdef CONFIG_SMP
 	/* Check for Core99 */
-	if (find_devices("uni-n"))
+	if (find_devices("uni-n") || find_devices("u3"))
 		ppc_md.smp_ops = &core99_smp_ops;
 	else
 		ppc_md.smp_ops = &psurge_smp_ops;
@@ -469,10 +469,6 @@ pmac_restart(char *cmd)
 	struct adb_request req;
 #endif /* CONFIG_ADB_CUDA */
 
-#ifdef CONFIG_NVRAM
-	pmac_nvram_update();
-#endif
-
 	switch (sys_ctrler) {
 #ifdef CONFIG_ADB_CUDA
 	case SYS_CTRLER_CUDA:
@@ -498,10 +494,6 @@ pmac_power_off(void)
 	struct adb_request req;
 #endif /* CONFIG_ADB_CUDA */
 
-#ifdef CONFIG_NVRAM
-	pmac_nvram_update();
-#endif
-
 	switch (sys_ctrler) {
 #ifdef CONFIG_ADB_CUDA
 	case SYS_CTRLER_CUDA:
@@ -637,11 +629,6 @@ pmac_init(unsigned long r3, unsigned lon
 	ppc_md.get_rtc_time   = pmac_get_rtc_time;
 	ppc_md.calibrate_decr = pmac_calibrate_decr;
 
-#ifdef CONFIG_NVRAM
-	ppc_md.nvram_read_val	= pmac_nvram_read_byte;
-	ppc_md.nvram_write_val	= pmac_nvram_write_byte;
-#endif
-
 	ppc_md.find_end_of_memory = pmac_find_end_of_memory;
 
 	ppc_md.feature_call   = pmac_do_feature_call;
@@ -685,6 +672,14 @@ pmac_declare_of_platform_devices(void)
 				break;
 			}
 	}
+	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;
+			}
+	}
 
 	np = find_devices("valkyrie");
 	if (np)
diff -puN arch/ppc/platforms/pmac_smp.c~big-pmac-3 arch/ppc/platforms/pmac_smp.c
--- 25/arch/ppc/platforms/pmac_smp.c~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/arch/ppc/platforms/pmac_smp.c	2004-01-28 23:09:16.000000000 -0800
@@ -119,8 +119,7 @@ static unsigned int core99_tb_gpio;
 /* Sync flag for HW tb sync */
 static volatile int sec_tb_reset = 0;
 
-static void __init
-core99_init_caches(int cpu)
+static void __init core99_init_caches(int cpu)
 {
 	if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR))
 		return;
@@ -188,8 +187,7 @@ static inline void psurge_clr_ipi(int cp
  */
 static unsigned long psurge_smp_message[NR_CPUS];
 
-void __pmac
-psurge_smp_message_recv(struct pt_regs *regs)
+void __pmac psurge_smp_message_recv(struct pt_regs *regs)
 {
 	int cpu = smp_processor_id();
 	int msg;
@@ -206,15 +204,14 @@ psurge_smp_message_recv(struct pt_regs *
 			smp_message_recv(msg, regs);
 }
 
-irqreturn_t __pmac
-psurge_primary_intr(int irq, void *d, struct pt_regs *regs)
+irqreturn_t __pmac psurge_primary_intr(int irq, void *d, struct pt_regs *regs)
 {
 	psurge_smp_message_recv(regs);
 	return IRQ_HANDLED;
 }
 
-static void __pmac
-smp_psurge_message_pass(int target, int msg, unsigned long data, int wait)
+static void __pmac smp_psurge_message_pass(int target, int msg, unsigned long data,
+					   int wait)
 {
 	int i;
 
@@ -410,8 +407,7 @@ static void __init psurge_dual_sync_tb(i
 	smp_tb_synchronized = 1;
 }
 
-static void __init
-smp_psurge_setup_cpu(int cpu_nr)
+static void __init smp_psurge_setup_cpu(int cpu_nr)
 {
 
 	if (cpu_nr == 0) {
@@ -435,41 +431,54 @@ smp_psurge_setup_cpu(int cpu_nr)
 		psurge_dual_sync_tb(cpu_nr);
 }
 
-void __init
-smp_psurge_take_timebase(void)
+void __init smp_psurge_take_timebase(void)
 {
 	/* Dummy implementation */
 }
 
-void __init
-smp_psurge_give_timebase(void)
+void __init smp_psurge_give_timebase(void)
 {
 	/* Dummy implementation */
 }
 
-static int __init
-smp_core99_probe(void)
+static int __init smp_core99_probe(void)
 {
+#ifdef CONFIG_6xx
 	extern int powersave_nap;
-	struct device_node *cpus;
-	int i, ncpus = 1;
+#endif
+	struct device_node *cpus, *firstcpu;
+	int i, ncpus = 0, boot_cpu = -1;
 	u32 *tbprop;
 
 	if (ppc_md.progress) ppc_md.progress("smp_core99_probe", 0x345);
-	cpus = find_type_devices("cpu");
-	if (cpus == NULL)
-		return 0;
-
-	tbprop = (u32 *)get_property(cpus, "timebase-enable", NULL);
-	if (tbprop)
-		core99_tb_gpio = *tbprop;
-	else
-		core99_tb_gpio = KL_GPIO_TB_ENABLE;
+	cpus = firstcpu = find_type_devices("cpu");
+	while(cpus != NULL) {
+		u32 *regprop = (u32 *)get_property(cpus, "reg", NULL);
+		char *stateprop = (char *)get_property(cpus, "state", NULL);
+		if (regprop != NULL && stateprop != NULL &&
+		    !strncmp(stateprop, "running", 7))
+			boot_cpu = *regprop;
+		++ncpus;
+		cpus = cpus->next;
+	}
+	if (boot_cpu == -1)
+		printk(KERN_WARNING "Couldn't detect boot CPU !\n");
+	if (boot_cpu != 0)
+		printk(KERN_WARNING "Boot CPU is %d, unsupported setup !\n", boot_cpu);
 
-       	while ((cpus = cpus->next) != NULL)
-	       	++ncpus;
+	if (machine_is_compatible("MacRISC4")) {
+		extern struct smp_ops_t core99_smp_ops;
 
-	printk("smp_core99_probe: found %d cpus\n", ncpus);
+		core99_smp_ops.take_timebase = smp_generic_take_timebase;
+		core99_smp_ops.give_timebase = smp_generic_give_timebase;
+	} else {
+		if (firstcpu != NULL)
+			tbprop = (u32 *)get_property(firstcpu, "timebase-enable", NULL);
+		if (tbprop)
+			core99_tb_gpio = *tbprop;
+		else
+			core99_tb_gpio = KL_GPIO_TB_ENABLE;
+	}
 
 	if (ncpus > 1) {
 		openpic_request_IPIs();
@@ -484,8 +493,7 @@ smp_core99_probe(void)
 	return ncpus;
 }
 
-static void __init
-smp_core99_kick_cpu(int nr)
+static void __init smp_core99_kick_cpu(int nr)
 {
 	unsigned long save_vector, new_vector;
 	unsigned long flags;
@@ -539,23 +547,31 @@ smp_core99_kick_cpu(int nr)
 	if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347);
 }
 
-static void __init
-smp_core99_setup_cpu(int cpu_nr)
+static void __init smp_core99_setup_cpu(int cpu_nr)
 {
-	/* Setup some registers */
+	/* Setup L2/L3 */
 	if (cpu_nr != 0)
 		core99_init_caches(cpu_nr);
 
 	/* Setup openpic */
 	do_openpic_setup_cpu();
 
-	/* Setup L2/L3 */
-	if (cpu_nr == 0)
+	if (cpu_nr == 0) {
+#ifdef CONFIG_POWER4
+		extern void g5_phy_disable_cpu1(void);
+
+		/* If we didn't start the second CPU, we must take
+		 * it off the bus
+		 */
+		if (machine_is_compatible("MacRISC4") &&
+		    num_online_cpus() < 2)		
+			g5_phy_disable_cpu1();
+#endif /* CONFIG_POWER4 */
 		if (ppc_md.progress) ppc_md.progress("core99_setup_cpu 0 done", 0x349);
+	}
 }
 
-void __init
-smp_core99_take_timebase(void)
+void __init smp_core99_take_timebase(void)
 {
 	/* Secondary processor "takes" the timebase by freezing
 	 * it, resetting its local TB and telling CPU 0 to go on
@@ -572,8 +588,7 @@ smp_core99_take_timebase(void)
        	sec_tb_reset = 1;
 }
 
-void __init
-smp_core99_give_timebase(void)
+void __init smp_core99_give_timebase(void)
 {
 	unsigned int t;
 
diff -puN arch/ppc/platforms/pmac_time.c~big-pmac-3 arch/ppc/platforms/pmac_time.c
--- 25/arch/ppc/platforms/pmac_time.c~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/arch/ppc/platforms/pmac_time.c	2004-01-28 23:09:16.000000000 -0800
@@ -266,6 +266,14 @@ pmac_calibrate_decr(void)
 		if (via_calibrate_decr())
 			return;
 
+	/* Special case: QuickSilver G4s seem to have a badly calibrated
+	 * timebase-frequency in OF, VIA is much better on these. We should
+	 * probably implement calibration based on the KL timer on these
+	 * machines anyway... -BenH
+	 */
+	if (machine_is_compatible("PowerMac3,5"))
+		if (via_calibrate_decr())
+			return;
 	/*
 	 * The cpu node should have a timebase-frequency property
 	 * to tell us the rate at which the decrementer counts.
diff -puN arch/ppc/syslib/Makefile~big-pmac-3 arch/ppc/syslib/Makefile
--- 25/arch/ppc/syslib/Makefile~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/arch/ppc/syslib/Makefile	2004-01-28 23:09:16.000000000 -0800
@@ -31,6 +31,7 @@ obj-$(CONFIG_PCI)		+= qspan_pci.o i8259.
 endif
 obj-$(CONFIG_PPC_OF)		+= prom_init.o prom.o of_device.o
 obj-$(CONFIG_PPC_PMAC)		+= open_pic.o indirect_pci.o
+obj-$(CONFIG_POWER4)		+= open_pic2.o
 obj-$(CONFIG_PPC_CHRP)		+= open_pic.o indirect_pci.o i8259.o
 obj-$(CONFIG_PPC_PREP)		+= open_pic.o indirect_pci.o i8259.o
 obj-$(CONFIG_ADIR)		+= i8259.o indirect_pci.o pci_auto.o \
diff -puN arch/ppc/syslib/of_device.c~big-pmac-3 arch/ppc/syslib/of_device.c
--- 25/arch/ppc/syslib/of_device.c~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/arch/ppc/syslib/of_device.c	2004-01-28 23:09:16.000000000 -0800
@@ -183,6 +183,7 @@ void of_release_dev(struct device *dev)
 	struct of_device *ofdev;
 
         ofdev = to_of_device(dev);
+	of_node_put(ofdev->node);
 	kfree(ofdev);
 }
 
@@ -242,7 +243,7 @@ struct of_device* of_platform_device_cre
 		return NULL;
 	memset(dev, 0, sizeof(*dev));
 
-	dev->node = np;
+	dev->node = of_node_get(np);
 	dev->dma_mask = 0xffffffffUL;
 	dev->dev.dma_mask = &dev->dma_mask;
 	dev->dev.parent = NULL;
diff -puN /dev/null arch/ppc/syslib/open_pic2.c
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/arch/ppc/syslib/open_pic2.c	2004-01-28 23:09:16.000000000 -0800
@@ -0,0 +1,716 @@
+/*
+ *  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.
+ *
+ *  This is a duplicate of open_pic.c that deals with U3s MPIC on
+ *  G5 PowerMacs. It's the same file except it's using big endian
+ *  register accesses
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/sysdev.h>
+#include <asm/ptrace.h>
+#include <asm/signal.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+#include <asm/sections.h>
+#include <asm/open_pic.h>
+#include <asm/i8259.h>
+#include <asm/hardirq.h>
+
+#include "open_pic_defs.h"
+
+void *OpenPIC2_Addr;
+static volatile struct OpenPIC *OpenPIC2 = NULL;
+/*
+ * We define OpenPIC_InitSenses table thusly:
+ * bit 0x1: sense, 0 for edge and 1 for level.
+ * bit 0x2: polarity, 0 for negative, 1 for positive.
+ */
+extern  u_int OpenPIC_NumInitSenses;
+extern u_char *OpenPIC_InitSenses;
+extern int use_of_interrupt_tree;
+
+static u_int NumProcessors;
+static u_int NumSources;
+static int open_pic2_irq_offset;
+static volatile OpenPIC_Source *ISR[NR_IRQS];
+
+/* Global Operations */
+static void openpic2_disable_8259_pass_through(void);
+static void openpic2_set_priority(u_int pri);
+static void openpic2_set_spurious(u_int vector);
+
+/* Timer Interrupts */
+static void openpic2_inittimer(u_int timer, u_int pri, u_int vector);
+static void openpic2_maptimer(u_int timer, u_int cpumask);
+
+/* Interrupt Sources */
+static void openpic2_enable_irq(u_int irq);
+static void openpic2_disable_irq(u_int irq);
+static void openpic2_initirq(u_int irq, u_int pri, u_int vector, int polarity,
+			    int is_level);
+static void openpic2_mapirq(u_int irq, u_int cpumask, u_int keepmask);
+
+/*
+ * These functions are not used but the code is kept here
+ * for completeness and future reference.
+ */
+static void openpic2_reset(void);
+#ifdef notused
+static void openpic2_enable_8259_pass_through(void);
+static u_int openpic2_get_priority(void);
+static u_int openpic2_get_spurious(void);
+static void openpic2_set_sense(u_int irq, int sense);
+#endif /* notused */
+
+/*
+ * Description of the openpic for the higher-level irq code
+ */
+static void openpic2_end_irq(unsigned int irq_nr);
+static void openpic2_ack_irq(unsigned int irq_nr);
+
+struct hw_interrupt_type open_pic2 = {
+	" OpenPIC2 ",
+	NULL,
+	NULL,
+	openpic2_enable_irq,
+	openpic2_disable_irq,
+	openpic2_ack_irq,
+	openpic2_end_irq,
+};
+
+/*
+ *  Accesses to the current processor's openpic registers
+ *  On cascaded controller, this is only CPU 0
+ */
+#define THIS_CPU		Processor[0]
+#define DECL_THIS_CPU
+#define CHECK_THIS_CPU
+
+#if 1
+#define check_arg_ipi(ipi) \
+    if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \
+	printk("open_pic.c:%d: illegal ipi %d\n", __LINE__, ipi);
+#define check_arg_timer(timer) \
+    if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \
+	printk("open_pic.c:%d: illegal timer %d\n", __LINE__, timer);
+#define check_arg_vec(vec) \
+    if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \
+	printk("open_pic.c:%d: illegal vector %d\n", __LINE__, vec);
+#define check_arg_pri(pri) \
+    if (pri < 0 || pri >= OPENPIC_NUM_PRI) \
+	printk("open_pic.c:%d: illegal priority %d\n", __LINE__, pri);
+/*
+ * Print out a backtrace if it's out of range, since if it's larger than NR_IRQ's
+ * data has probably been corrupted and we're going to panic or deadlock later
+ * anyway --Troy
+ */
+extern unsigned long* _get_SP(void);
+#define check_arg_irq(irq) \
+    if (irq < open_pic2_irq_offset || irq >= NumSources+open_pic2_irq_offset \
+	|| ISR[irq - open_pic2_irq_offset] == 0) { \
+      printk("open_pic.c:%d: illegal irq %d\n", __LINE__, irq); \
+      /*print_backtrace(_get_SP());*/ }
+#define check_arg_cpu(cpu) \
+    if (cpu < 0 || cpu >= NumProcessors){ \
+	printk("open_pic2.c:%d: illegal cpu %d\n", __LINE__, cpu); \
+	/*print_backtrace(_get_SP());*/ }
+#else
+#define check_arg_ipi(ipi)	do {} while (0)
+#define check_arg_timer(timer)	do {} while (0)
+#define check_arg_vec(vec)	do {} while (0)
+#define check_arg_pri(pri)	do {} while (0)
+#define check_arg_irq(irq)	do {} while (0)
+#define check_arg_cpu(cpu)	do {} while (0)
+#endif
+
+static 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;
+}
+
+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)
+{
+	openpic2_setfield(addr, OPENPIC_MASK);
+	while (openpic2_read(addr) & OPENPIC_ACTIVITY);
+	openpic2_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
+}
+
+static void openpic2_reset(void)
+{
+	openpic2_setfield(&OpenPIC2->Global.Global_Configuration0,
+			 OPENPIC_CONFIG_RESET);
+	while (openpic2_readfield(&OpenPIC2->Global.Global_Configuration0,
+				 OPENPIC_CONFIG_RESET))
+		mb();
+}
+
+void __init openpic2_set_sources(int first_irq, int num_irqs, void *first_ISR)
+{
+	volatile OpenPIC_Source *src = first_ISR;
+	int i, last_irq;
+
+	last_irq = first_irq + num_irqs;
+	if (last_irq > NumSources)
+		NumSources = last_irq;
+	if (src == 0)
+		src = &((struct OpenPIC *)OpenPIC2_Addr)->Source[first_irq];
+	for (i = first_irq; i < last_irq; ++i, ++src)
+		ISR[i] = src;
+}
+
+/*
+ * The `offset' parameter defines where the interrupts handled by the
+ * OpenPIC start in the space of interrupt numbers that the kernel knows
+ * about.  In other words, the OpenPIC's IRQ0 is numbered `offset' in the
+ * kernel's interrupt numbering scheme.
+ * We assume there is only one OpenPIC.
+ */
+void __init openpic2_init(int offset)
+{
+	u_int t, i;
+	u_int timerfreq;
+	const char *version;
+
+	if (!OpenPIC2_Addr) {
+		printk("No OpenPIC2 found !\n");
+		return;
+	}
+	OpenPIC2 = (volatile struct OpenPIC *)OpenPIC2_Addr;
+
+	if (ppc_md.progress) ppc_md.progress("openpic: enter", 0x122);
+
+	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;
+	}
+	NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
+			 OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1;
+	if (NumSources == 0)
+		openpic2_set_sources(0,
+				    ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
+				     OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1,
+				    NULL);
+	printk("OpenPIC (2) Version %s (%d CPUs and %d IRQ sources) at %p\n",
+	       version, NumProcessors, NumSources, OpenPIC2);
+	timerfreq = openpic2_read(&OpenPIC2->Global.Timer_Frequency);
+	if (timerfreq)
+		printk("OpenPIC timer frequency is %d.%06d MHz\n",
+		       timerfreq / 1000000, timerfreq % 1000000);
+
+	open_pic2_irq_offset = offset;
+
+	/* Initialize timer interrupts */
+	if ( ppc_md.progress ) ppc_md.progress("openpic2: timer",0x3ba);
+	for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
+		/* Disabled, Priority 0 */
+		openpic2_inittimer(i, 0, OPENPIC2_VEC_TIMER+i+offset);
+		/* No processor */
+		openpic2_maptimer(i, 0);
+	}
+
+	/* Initialize external interrupts */
+	if (ppc_md.progress) ppc_md.progress("openpic2: external",0x3bc);
+
+	openpic2_set_priority(0xf);
+
+	/* Init all external sources, including possibly the cascade. */
+	for (i = 0; i < NumSources; i++) {
+		int sense;
+
+		if (ISR[i] == 0)
+			continue;
+
+		/* the bootloader may have left it enabled (bad !) */
+		openpic2_disable_irq(i+offset);
+
+		sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: \
+				(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE);
+
+		if (sense & IRQ_SENSE_MASK)
+			irq_desc[i+offset].status = IRQ_LEVEL;
+
+		/* Enabled, Priority 8 */
+		openpic2_initirq(i, 8, i+offset, (sense & IRQ_POLARITY_MASK),
+				(sense & IRQ_SENSE_MASK));
+		/* Processor 0 */
+		openpic2_mapirq(i, 1<<0, 0);
+	}
+
+	/* Init descriptors */
+	for (i = offset; i < NumSources + offset; i++)
+		irq_desc[i].handler = &open_pic2;
+
+	/* Initialize the spurious interrupt */
+	if (ppc_md.progress) ppc_md.progress("openpic2: spurious",0x3bd);
+	openpic2_set_spurious(OPENPIC2_VEC_SPURIOUS+offset);
+
+	openpic2_disable_8259_pass_through();
+	openpic2_set_priority(0);
+
+	if (ppc_md.progress) ppc_md.progress("openpic2: exit",0x222);
+}
+
+#ifdef notused
+static void openpic2_enable_8259_pass_through(void)
+{
+	openpic2_clearfield(&OpenPIC2->Global.Global_Configuration0,
+			   OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
+}
+#endif /* notused */
+
+/* This can't be __init, it is used in openpic_sleep_restore_intrs */
+static void openpic2_disable_8259_pass_through(void)
+{
+	openpic2_setfield(&OpenPIC2->Global.Global_Configuration0,
+			 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
+}
+
+/*
+ *  Find out the current interrupt
+ */
+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;
+}
+
+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);
+}
+
+#ifdef notused
+static 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);
+}
+#endif /* notused */
+
+static void __init openpic2_set_priority(u_int pri)
+{
+	DECL_THIS_CPU;
+
+	CHECK_THIS_CPU;
+	check_arg_pri(pri);
+	openpic2_writefield(&OpenPIC2->THIS_CPU.Current_Task_Priority,
+			   OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri);
+}
+
+/*
+ *  Get/set the spurious vector
+ */
+#ifdef notused
+static u_int openpic2_get_spurious(void)
+{
+	return openpic2_readfield(&OpenPIC2->Global.Spurious_Vector,
+				 OPENPIC_VECTOR_MASK);
+}
+#endif /* notused */
+
+/* This can't be __init, it is used in openpic_sleep_restore_intrs */
+static void openpic2_set_spurious(u_int vec)
+{
+	check_arg_vec(vec);
+	openpic2_writefield(&OpenPIC2->Global.Spurious_Vector, OPENPIC_VECTOR_MASK,
+			   vec);
+}
+
+static spinlock_t openpic2_setup_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ *  Initialize a timer interrupt (and disable it)
+ *
+ *  timer: OpenPIC timer number
+ *  pri: interrupt source priority
+ *  vec: the vector it will produce
+ */
+static void __init openpic2_inittimer(u_int timer, u_int pri, u_int vec)
+{
+	check_arg_timer(timer);
+	check_arg_pri(pri);
+	check_arg_vec(vec);
+	openpic2_safe_writefield(&OpenPIC2->Global.Timer[timer].Vector_Priority,
+				OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
+				(pri << OPENPIC_PRIORITY_SHIFT) | vec);
+}
+
+/*
+ *  Map a timer interrupt to one or more CPUs
+ */
+static void __init openpic2_maptimer(u_int timer, u_int cpumask)
+{
+	check_arg_timer(timer);
+	openpic2_write(&OpenPIC2->Global.Timer[timer].Destination,
+		      cpumask);
+}
+
+/*
+ * Initalize the interrupt source which will generate an NMI.
+ * This raises the interrupt's priority from 8 to 9.
+ *
+ * irq: The logical IRQ which generates an NMI.
+ */
+void __init
+openpic2_init_nmi_irq(u_int irq)
+{
+	check_arg_irq(irq);
+	openpic2_safe_writefield(&ISR[irq - open_pic2_irq_offset]->Vector_Priority,
+				OPENPIC_PRIORITY_MASK,
+				9 << OPENPIC_PRIORITY_SHIFT);
+}
+
+/*
+ *
+ * All functions below take an offset'ed irq argument
+ *
+ */
+
+
+/*
+ *  Enable/disable an external interrupt source
+ *
+ *  Externally called, irq is an offseted system-wide interrupt number
+ */
+static void openpic2_enable_irq(u_int irq)
+{
+	volatile u_int *vpp;
+
+	check_arg_irq(irq);
+	vpp = &ISR[irq - open_pic2_irq_offset]->Vector_Priority;
+       	openpic2_clearfield(vpp, OPENPIC_MASK);
+	/* make sure mask gets to controller before we return to user */
+       	do {
+       		mb(); /* sync is probably useless here */
+       	} while (openpic2_readfield(vpp, OPENPIC_MASK));
+}
+
+static void openpic2_disable_irq(u_int irq)
+{
+	volatile u_int *vpp;
+	u32 vp;
+
+	check_arg_irq(irq);
+	vpp = &ISR[irq - open_pic2_irq_offset]->Vector_Priority;
+	openpic2_setfield(vpp, OPENPIC_MASK);
+	/* make sure mask gets to controller before we return to user */
+	do {
+		mb();  /* sync is probably useless here */
+		vp = openpic2_readfield(vpp, 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 __init
+openpic2_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
+{
+	openpic2_safe_writefield(&ISR[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, u_int keepmask)
+{
+	if (ISR[irq] == 0)
+		return;
+	if (keepmask != 0)
+		physmask |= openpic2_read(&ISR[irq]->Destination) & keepmask;
+	openpic2_write(&ISR[irq]->Destination, physmask);
+}
+
+#ifdef notused
+/*
+ *  Set the sense for an interrupt source (and disable it!)
+ *
+ *  sense: 1 for level, 0 for edge
+ */
+static void openpic2_set_sense(u_int irq, int sense)
+{
+	if (ISR[irq] != 0)
+		openpic2_safe_writefield(&ISR[irq]->Vector_Priority,
+					OPENPIC_SENSE_LEVEL,
+					(sense ? OPENPIC_SENSE_LEVEL : 0));
+}
+#endif /* notused */
+
+/* No spinlocks, should not be necessary with the OpenPIC
+ * (1 register = 1 interrupt and we have the desc lock).
+ */
+static void openpic2_ack_irq(unsigned int irq_nr)
+{
+	openpic2_disable_irq(irq_nr);
+	openpic2_eoi();
+}
+
+static void openpic2_end_irq(unsigned int irq_nr)
+{
+	if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+		openpic2_enable_irq(irq_nr);
+}
+
+int
+openpic2_get_irq(struct pt_regs *regs)
+{
+	int irq = openpic2_irq();
+
+	if (irq == (OPENPIC2_VEC_SPURIOUS + open_pic2_irq_offset))
+		irq = -1;
+	return irq;
+}
+
+#ifdef CONFIG_PM
+
+/*
+ * We implement the IRQ controller as a sysdev and put it
+ * to sleep at powerdown stage (the callback is named suspend,
+ * but it's old semantics, for the Device Model, it's really
+ * powerdown). The possible problem is that another sysdev that
+ * happens to be suspend after this one will have interrupts off,
+ * that may be an issue... For now, this isn't an issue on pmac
+ * though...
+ */
+
+static u32 save_ipi_vp[OPENPIC_NUM_IPI];
+static u32 save_irq_src_vp[OPENPIC_MAX_SOURCES];
+static u32 save_irq_src_dest[OPENPIC_MAX_SOURCES];
+static u32 save_cpu_task_pri[OPENPIC_MAX_PROCESSORS];
+static int openpic_suspend_count;
+
+static void openpic2_cached_enable_irq(u_int irq)
+{
+	check_arg_irq(irq);
+	save_irq_src_vp[irq - open_pic2_irq_offset] &= ~OPENPIC_MASK;
+}
+
+static void openpic2_cached_disable_irq(u_int irq)
+{
+	check_arg_irq(irq);
+	save_irq_src_vp[irq - open_pic2_irq_offset] |= OPENPIC_MASK;
+}
+
+/* WARNING: Can be called directly by the cpufreq code with NULL parameter,
+ * we need something better to deal with that... Maybe switch to S1 for
+ * cpufreq changes
+ */
+int openpic2_suspend(struct sys_device *sysdev, u32 state)
+{
+	int	i;
+	unsigned long flags;
+
+	spin_lock_irqsave(&openpic2_setup_lock, flags);
+
+	if (openpic_suspend_count++ > 0) {
+		spin_unlock_irqrestore(&openpic2_setup_lock, flags);
+		return 0;
+	}
+
+	open_pic2.enable = openpic2_cached_enable_irq;
+	open_pic2.disable = openpic2_cached_disable_irq;
+
+	for (i=0; i<NumProcessors; i++) {
+		save_cpu_task_pri[i] = openpic2_read(&OpenPIC2->Processor[i].Current_Task_Priority);
+		openpic2_writefield(&OpenPIC2->Processor[i].Current_Task_Priority,
+				   OPENPIC_CURRENT_TASK_PRIORITY_MASK, 0xf);
+	}
+
+	for (i=0; i<OPENPIC_NUM_IPI; i++)
+		save_ipi_vp[i] = openpic2_read(&OpenPIC2->Global.IPI_Vector_Priority(i));
+	for (i=0; i<NumSources; i++) {
+		if (ISR[i] == 0)
+			continue;
+		save_irq_src_vp[i] = openpic2_read(&ISR[i]->Vector_Priority) & ~OPENPIC_ACTIVITY;
+		save_irq_src_dest[i] = openpic2_read(&ISR[i]->Destination);
+	}
+
+	spin_unlock_irqrestore(&openpic2_setup_lock, flags);
+
+	return 0;
+}
+
+/* WARNING: Can be called directly by the cpufreq code with NULL parameter,
+ * we need something better to deal with that... Maybe switch to S1 for
+ * cpufreq changes
+ */
+int openpic2_resume(struct sys_device *sysdev)
+{
+	int		i;
+	unsigned long	flags;
+	u32		vppmask =	OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
+					OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK |
+					OPENPIC_MASK;
+
+	spin_lock_irqsave(&openpic2_setup_lock, flags);
+
+	if ((--openpic_suspend_count) > 0) {
+		spin_unlock_irqrestore(&openpic2_setup_lock, flags);
+		return 0;
+	}
+
+	openpic2_reset();
+
+	/* OpenPIC sometimes seem to need some time to be fully back up... */
+	do {
+		openpic2_set_spurious(OPENPIC2_VEC_SPURIOUS+open_pic2_irq_offset);
+	} while(openpic2_readfield(&OpenPIC2->Global.Spurious_Vector, OPENPIC_VECTOR_MASK)
+			!= (OPENPIC2_VEC_SPURIOUS + open_pic2_irq_offset));
+	
+	openpic2_disable_8259_pass_through();
+
+	for (i=0; i<OPENPIC_NUM_IPI; i++)
+		openpic2_write(&OpenPIC2->Global.IPI_Vector_Priority(i),
+			      save_ipi_vp[i]);
+	for (i=0; i<NumSources; i++) {
+		if (ISR[i] == 0)
+			continue;
+		openpic2_write(&ISR[i]->Destination, save_irq_src_dest[i]);
+		openpic2_write(&ISR[i]->Vector_Priority, save_irq_src_vp[i]);
+		/* make sure mask gets to controller before we return to user */
+		do {
+			openpic2_write(&ISR[i]->Vector_Priority, save_irq_src_vp[i]);
+		} while (openpic2_readfield(&ISR[i]->Vector_Priority, vppmask)
+			 != (save_irq_src_vp[i] & vppmask));
+	}
+	for (i=0; i<NumProcessors; i++)
+		openpic2_write(&OpenPIC2->Processor[i].Current_Task_Priority,
+			      save_cpu_task_pri[i]);
+
+	open_pic2.enable = openpic2_enable_irq;
+	open_pic2.disable = openpic2_disable_irq;
+
+	spin_unlock_irqrestore(&openpic2_setup_lock, flags);
+
+	return 0;
+}
+
+#endif /* CONFIG_PM */
+
+/* HACK ALERT */
+static struct sysdev_class openpic2_sysclass = {
+	set_kset_name("openpic2"),
+};
+
+static struct sys_device device_openpic2 = {
+	.id		= 0,
+	.cls		= &openpic2_sysclass,
+};
+
+static struct sysdev_driver driver_openpic2 = {
+#ifdef CONFIG_PM
+	.suspend	= &openpic2_suspend,
+	.resume		= &openpic2_resume,
+#endif /* CONFIG_PM */
+};
+
+static int __init init_openpic2_sysfs(void)
+{
+	int rc;
+
+	if (!OpenPIC2_Addr)
+		return -ENODEV;
+	printk(KERN_DEBUG "Registering openpic2 with sysfs...\n");
+	rc = sysdev_class_register(&openpic2_sysclass);
+	if (rc) {
+		printk(KERN_ERR "Failed registering openpic sys class\n");
+		return -ENODEV;
+	}
+	rc = sys_device_register(&device_openpic2);
+	if (rc) {
+		printk(KERN_ERR "Failed registering openpic sys device\n");
+		return -ENODEV;
+	}
+	rc = sysdev_driver_register(&openpic2_sysclass, &driver_openpic2);
+	if (rc) {
+		printk(KERN_ERR "Failed registering openpic sys driver\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+subsys_initcall(init_openpic2_sysfs);
+
diff -puN arch/ppc/syslib/open_pic.c~big-pmac-3 arch/ppc/syslib/open_pic.c
--- 25/arch/ppc/syslib/open_pic.c~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/arch/ppc/syslib/open_pic.c	2004-01-28 23:09:16.000000000 -0800
@@ -610,12 +610,15 @@ void openpic_request_IPIs(void)
 
 void __devinit do_openpic_setup_cpu(void)
 {
+#ifdef CONFIG_IRQ_ALL_CPUS
  	int i;
-	u32 msk = 1 << smp_hw_index[smp_processor_id()];
-
+	u32 msk;
+#endif
 	spin_lock(&openpic_setup_lock);
 
 #ifdef CONFIG_IRQ_ALL_CPUS
+	msk = 1 << smp_hw_index[smp_processor_id()];
+
  	/* let the openpic know we want intrs. default affinity
  	 * is 0xffffffff until changed via /proc
  	 * That's how it's done on x86. If we want it differently, then
@@ -788,15 +791,25 @@ static void openpic_set_sense(u_int irq,
  */
 static void openpic_ack_irq(unsigned int irq_nr)
 {
+#ifdef __SLOW_VERSION__
 	openpic_disable_irq(irq_nr);
 	openpic_eoi();
+#else
+	if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0)
+		openpic_eoi();
+#endif
 }
 
 static void openpic_end_irq(unsigned int irq_nr)
 {
+#ifdef __SLOW_VERSION__
 	if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
 	    && irq_desc[irq_nr].action)
 		openpic_enable_irq(irq_nr);
+#else
+	if ((irq_desc[irq_nr].status & IRQ_LEVEL) != 0)
+		openpic_eoi();
+#endif
 }
 
 static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask)
diff -puN arch/ppc/syslib/prom.c~big-pmac-3 arch/ppc/syslib/prom.c
--- 25/arch/ppc/syslib/prom.c~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/arch/ppc/syslib/prom.c	2004-01-28 23:09:16.000000000 -0800
@@ -160,7 +160,7 @@ finish_device_tree(void)
 			   match on /chosen.interrupt_controller */
 			if ((name != NULL
 			     && strcmp(name, "interrupt-controller") == 0)
-			    || (ic != NULL && iclen == 0)) {
+			    || (ic != NULL && iclen == 0 && strcmp(name, "AppleKiwi"))) {
 				if (n == 0)
 					dflt_interrupt_controller = np;
 				++n;
@@ -217,7 +217,7 @@ finish_node(struct device_node *np, unsi
 		ifunc = interpret_macio_props;
 	else if (!strcmp(np->type, "isa"))
 		ifunc = interpret_isa_props;
-	else if (!strcmp(np->name, "uni-n"))
+	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)
@@ -431,10 +431,21 @@ finish_node_interrupts(struct device_nod
 		 * This doesn't cope with the general case of multiple
 		 * cascaded interrupt controllers, but then neither will
 		 * irq.c at the moment either.  -- paulus
+		 * The G5 triggers that code, I add a machine test. On
+		 * those machines, we want to offset interrupts from the
+		 * second openpic by 128 -- BenH
 		 */
-		if (num_interrupt_controllers > 1 && ic != NULL
+		if (_machine != _MACH_Pmac && num_interrupt_controllers > 1
+		    && ic != NULL
 		    && get_property(ic, "interrupt-parent", NULL) == NULL)
 			offset = 16;
+		else if (_machine == _MACH_Pmac && num_interrupt_controllers > 1
+			 && ic != NULL && ic->parent != NULL) {
+			char *name = get_property(ic->parent, "name", NULL);
+			if (name && !strcmp(name, "u3"))
+				offset = 128;
+		}
+
 		np->intrs[i].line = irq[0] + offset;
 		if (n > 1)
 			np->intrs[i].sense = irq[1];
@@ -1212,8 +1223,6 @@ find_parent_pci_resource(struct pci_dev*
  * Request an OF device resource. Currently handles child of PCI devices,
  * or other nodes attached to the root node. Ultimately, put some
  * link to resources in the OF node.
- * WARNING: out_resource->name should be initialized before calling this
- * function.
  */
 struct resource* __openfirmware
 request_OF_resource(struct device_node* node, int index, const char* name_postfix)
@@ -1276,7 +1285,7 @@ release_OF_resource(struct device_node* 
 {
 	struct pci_dev* pcidev;
 	u8 pci_bus, pci_devfn;
-	unsigned long iomask;
+	unsigned long iomask, start, end;
 	struct device_node* nd;
 	struct resource* parent;
 	struct resource *res = NULL;
@@ -1305,18 +1314,23 @@ release_OF_resource(struct device_node* 
 	if (pcidev)
 		parent = find_parent_pci_resource(pcidev, &node->addrs[index]);
 	if (!parent) {
-		printk(KERN_WARNING "request_OF_resource(%s), parent not found\n",
+		printk(KERN_WARNING "release_OF_resource(%s), parent not found\n",
 			node->name);
 		return -ENODEV;
 	}
 
-	/* Find us in the parent */
+	/* Find us in the parent and its childs */
 	res = parent->child;
+	start = node->addrs[index].address;
+	end = start + node->addrs[index].size - 1;
 	while (res) {
-		if (res->start == node->addrs[index].address &&
-		    res->end == (res->start + node->addrs[index].size - 1))
+		if (res->start == start && res->end == end &&
+		    (res->flags & IORESOURCE_BUSY))
 		    	break;
-		res = res->sibling;
+		if (res->start <= start && res->end >= end)
+			res = res->child;
+		else
+			res = res->sibling;
 	}
 	if (!res)
 		return -ENODEV;
diff -puN arch/ppc/syslib/prom_init.c~big-pmac-3 arch/ppc/syslib/prom_init.c
--- 25/arch/ppc/syslib/prom_init.c~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/arch/ppc/syslib/prom_init.c	2004-01-28 23:09:16.000000000 -0800
@@ -260,6 +260,74 @@ prom_next_node(phandle *nodep)
 	}
 }
 
+#ifdef CONFIG_POWER4
+/*
+ * Set up a hash table with a set of entries in it to map the
+ * first 64MB of RAM.  This is used on 64-bit machines since
+ * some of them don't have BATs.
+ */
+
+static inline void make_pte(unsigned long htab, unsigned int hsize,
+			    unsigned int va, unsigned int pa, int mode)
+{
+	unsigned int *pteg;
+	unsigned int hash, i, vsid;
+
+	vsid = ((va >> 28) * 0x111) << 12;
+	hash = ((va ^ vsid) >> 5) & 0x7fff80;
+	pteg = (unsigned int *)(htab + (hash & (hsize - 1)));
+	for (i = 0; i < 8; ++i, pteg += 4) {
+		if ((pteg[1] & 1) == 0) {
+			pteg[1] = vsid | ((va >> 16) & 0xf80) | 1;
+			pteg[3] = pa | mode;
+			break;
+		}
+	}
+}
+
+extern unsigned long _SDR1;
+extern PTE *Hash;
+extern unsigned long Hash_size;
+
+static void __init
+prom_alloc_htab(void)
+{
+	unsigned int hsize;
+	unsigned long htab;
+	unsigned int addr;
+
+	/*
+	 * Because of OF bugs we can't use the "claim" client
+	 * interface to allocate memory for the hash table.
+	 * This code is only used on 64-bit PPCs, and the only
+	 * 64-bit PPCs at the moment are RS/6000s, and their
+	 * OF is based at 0xc00000 (the 12M point), so we just
+	 * arbitrarily use the 0x800000 - 0xc00000 region for the
+	 * hash table.
+	 *  -- paulus.
+	 */
+	hsize = 4 << 20;	/* POWER4 has no BATs */
+	htab = (8 << 20);
+	call_prom("claim", 3, 1, htab, hsize, 0);
+	Hash = (void *)(htab + KERNELBASE);
+	Hash_size = hsize;
+	_SDR1 = htab + __ilog2(hsize) - 18;
+
+	/*
+	 * Put in PTEs for the first 64MB of RAM
+	 */
+	memset((void *)htab, 0, hsize);
+	for (addr = 0; addr < 0x4000000; addr += 0x1000)
+		make_pte(htab, hsize, addr + KERNELBASE, addr,
+			 _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX);
+#if 0 /* DEBUG stuff mapping the SCC */
+	make_pte(htab, hsize, 0x80013000, 0x80013000,
+		 _PAGE_ACCESSED | _PAGE_NO_CACHE | _PAGE_GUARDED | PP_RWXX);
+#endif
+}
+#endif /* CONFIG_POWER4 */
+
+
 /*
  * If we have a display that we don't know how to drive,
  * we will want to try to execute OF's open method for it
@@ -434,13 +502,26 @@ setup_disp_fake_bi(ihandle dp)
 		address += 0x1000;
 
 #ifdef CONFIG_POWER4
-	extern int boot_text_mapped;
-	btext_setup_display(width, height, depth, pitch, address);
-	boot_text_mapped = 0;
-#else
+	{
+		extern boot_infos_t disp_bi;
+		unsigned long va, pa, i, offset;
+       		va = 0x90000000;
+		pa = address & 0xfffff000ul;
+		offset = address & 0x00000fff;
+
+		for (i=0; i<0x4000; i++) {  
+			make_pte((unsigned long)Hash - KERNELBASE, Hash_size, va, pa, 
+				 _PAGE_ACCESSED | _PAGE_NO_CACHE | _PAGE_GUARDED | PP_RWXX);
+			va += 0x1000;
+			pa += 0x1000;
+		}
+		btext_setup_display(width, height, depth, pitch, 0x90000000 | offset);
+		disp_bi.dispDeviceBase = (u8 *)address;
+	}
+#else /* CONFIG_POWER4 */
 	btext_setup_display(width, height, depth, pitch, address);
 	btext_prepare_BAT();
-#endif
+#endif /* CONFIG_POWER4 */
 #endif /* CONFIG_BOOTX_TEXT */
 }
 
@@ -648,72 +729,6 @@ prom_hold_cpus(unsigned long mem)
 	}
 }
 
-#ifdef CONFIG_POWER4
-/*
- * Set up a hash table with a set of entries in it to map the
- * first 64MB of RAM.  This is used on 64-bit machines since
- * some of them don't have BATs.
- * We assume the PTE will fit in the primary PTEG.
- */
-
-static inline void make_pte(unsigned long htab, unsigned int hsize,
-			    unsigned int va, unsigned int pa, int mode)
-{
-	unsigned int *pteg;
-	unsigned int hash, i, vsid;
-
-	vsid = ((va >> 28) * 0x111) << 12;
-	hash = ((va ^ vsid) >> 5) & 0x7fff80;
-	pteg = (unsigned int *)(htab + (hash & (hsize - 1)));
-	for (i = 0; i < 8; ++i, pteg += 4) {
-		if ((pteg[1] & 1) == 0) {
-			pteg[1] = vsid | ((va >> 16) & 0xf80) | 1;
-			pteg[3] = pa | mode;
-			break;
-		}
-	}
-}
-
-extern unsigned long _SDR1;
-extern PTE *Hash;
-extern unsigned long Hash_size;
-
-static void __init
-prom_alloc_htab(void)
-{
-	unsigned int hsize;
-	unsigned long htab;
-	unsigned int addr;
-
-	/*
-	 * Because of OF bugs we can't use the "claim" client
-	 * interface to allocate memory for the hash table.
-	 * This code is only used on 64-bit PPCs, and the only
-	 * 64-bit PPCs at the moment are RS/6000s, and their
-	 * OF is based at 0xc00000 (the 12M point), so we just
-	 * arbitrarily use the 0x800000 - 0xc00000 region for the
-	 * hash table.
-	 *  -- paulus.
-	 */
-	hsize = 4 << 20;	/* POWER4 has no BATs */
-	htab = (8 << 20);
-	call_prom("claim", 3, 1, htab, hsize, 0);
-	Hash = (void *)(htab + KERNELBASE);
-	Hash_size = hsize;
-	_SDR1 = htab + __ilog2(hsize) - 18;
-
-	/*
-	 * Put in PTEs for the first 64MB of RAM
-	 */
-	cacheable_memzero((void *)htab, hsize);
-	for (addr = 0; addr < 0x4000000; addr += 0x1000)
-		make_pte(htab, hsize, addr + KERNELBASE, addr,
-			 _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX);
-	make_pte(htab, hsize, 0x80013000, 0x80013000,
-		 _PAGE_ACCESSED | _PAGE_NO_CACHE | _PAGE_GUARDED | PP_RWXX);
-}
-#endif /* CONFIG_POWER4 */
-
 static void __init
 prom_instantiate_rtas(void)
 {
@@ -836,9 +851,10 @@ prom_init(int r3, int r4, prom_entry pp)
 	 * loaded by an OF bootloader which did set a BAT for us.
 	 * This breaks OF translate so we force phys to be 0.
 	 */
-	if (offset == 0)
+	if (offset == 0) {
+		prom_print("(already at 0xc0000000) phys=0\n");
 		phys = 0;
-	else if ((int) call_prom("getprop", 4, 1, prom_chosen, "mmu",
+	} else if ((int) call_prom("getprop", 4, 1, prom_chosen, "mmu",
 				 &prom_mmu, sizeof(prom_mmu)) <= 0) {
 		prom_print(" no MMU found\n");
 	} else if ((int)call_prom_ret("call-method", 4, 4, result, "translate",
diff -puN drivers/block/swim3.c~big-pmac-3 drivers/block/swim3.c
--- 25/drivers/block/swim3.c~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/drivers/block/swim3.c	2004-01-28 23:09:16.000000000 -0800
@@ -24,7 +24,10 @@
 #include <linux/delay.h>
 #include <linux/fd.h>
 #include <linux/ioctl.h>
+#include <linux/blkdev.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
 #include <asm/io.h>
 #include <asm/dbdma.h>
 #include <asm/prom.h>
@@ -144,7 +147,7 @@ struct swim3 {
 #define RELAX		3	/* also eject in progress */
 #define READ_DATA_0	4
 #define TWOMEG_DRIVE	5
-#define SINGLE_SIDED	6
+#define SINGLE_SIDED	6	/* drive or diskette is 4MB type? */
 #define DRIVE_PRESENT	7
 #define DISK_IN		8
 #define WRITE_PROT	9
@@ -184,6 +187,7 @@ struct floppy_state {
 	int	req_sector;	/* sector number ditto */
 	int	scount;		/* # sectors we're transferring at present */
 	int	retries;
+	int	settle_time;
 	int	secpercyl;	/* disk geometry information */
 	int	secpertrack;
 	int	total_secs;
@@ -232,8 +236,9 @@ static void setup_transfer(struct floppy
 static void act(struct floppy_state *fs);
 static void scan_timeout(unsigned long data);
 static void seek_timeout(unsigned long data);
+static void settle_timeout(unsigned long data);
 static void xfer_timeout(unsigned long data);
-static void swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 /*static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs);*/
 static int grab_drive(struct floppy_state *fs, enum swim_state state,
 		      int interruptible);
@@ -274,7 +279,6 @@ static void swim3_action(struct floppy_s
 	udelay(2);
 	out_8(&sw->select, sw->select & ~LSTRB);
 	udelay(1);
-	out_8(&sw->select, RELAX);
 }
 
 static int swim3_readbit(struct floppy_state *fs, int bit)
@@ -283,9 +287,8 @@ static int swim3_readbit(struct floppy_s
 	int stat;
 
 	swim3_select(fs, bit);
-	udelay(10);
+	udelay(1);
 	stat = in_8(&sw->status);
-	out_8(&sw->select, RELAX);
 	return (stat & DATA) == 0;
 }
 
@@ -374,13 +377,13 @@ static void set_timeout(struct floppy_st
 static inline void scan_track(struct floppy_state *fs)
 {
 	volatile struct swim3 *sw = fs->swim3;
-	int xx;
 
 	swim3_select(fs, READ_DATA_0);
-	xx = sw->intr;		/* clear SEEN_SECTOR bit */
+	in_8(&sw->intr);		/* clear SEEN_SECTOR bit */
+	in_8(&sw->error);
+	out_8(&sw->intr_enable, SEEN_SECTOR);
 	out_8(&sw->control_bis, DO_ACTION);
 	/* enable intr when track found */
-	out_8(&sw->intr_enable, ERROR_INTR | SEEN_SECTOR);
 	set_timeout(fs, HZ, scan_timeout);	/* enable timeout */
 }
 
@@ -395,12 +398,14 @@ static inline void seek_track(struct flo
 		swim3_action(fs, SEEK_NEGATIVE);
 		sw->nseek = -n;
 	}
-	fs->expect_cyl = (fs->cur_cyl > 0)? fs->cur_cyl + n: -1;
+	fs->expect_cyl = (fs->cur_cyl >= 0)? fs->cur_cyl + n: -1;
 	swim3_select(fs, STEP);
-	out_8(&sw->control_bis, DO_SEEK);
+	in_8(&sw->error);
 	/* enable intr when seek finished */
-	out_8(&sw->intr_enable, ERROR_INTR | SEEK_DONE);
-	set_timeout(fs, HZ/2, seek_timeout);	/* enable timeout */
+	out_8(&sw->intr_enable, SEEK_DONE);
+	out_8(&sw->control_bis, DO_SEEK);
+	set_timeout(fs, 3*HZ, seek_timeout);	/* enable timeout */
+	fs->settle_time = 0;
 }
 
 static inline void init_dma(struct dbdma_cmd *cp, int cmd,
@@ -448,18 +453,21 @@ static inline void setup_transfer(struct
 	}
 	++cp;
 	out_le16(&cp->command, DBDMA_STOP);
+	out_8(&sw->control_bic, DO_ACTION | WRITE_SECTORS);
+	in_8(&sw->error);
+	out_8(&sw->control_bic, DO_ACTION | WRITE_SECTORS);
+	if (rq_data_dir(fd_req) == WRITE)
+		out_8(&sw->control_bis, WRITE_SECTORS);
+	in_8(&sw->intr);
 	out_le32(&dr->control, (RUN << 16) | RUN);
-	out_8(&sw->control_bis,
-	      (rq_data_dir(fd_req) == WRITE? WRITE_SECTORS: 0) | DO_ACTION);
 	/* enable intr when transfer complete */
-	out_8(&sw->intr_enable, ERROR_INTR | TRANSFER_DONE);
+	out_8(&sw->intr_enable, TRANSFER_DONE);
+	out_8(&sw->control_bis, DO_ACTION);
 	set_timeout(fs, 2*HZ, xfer_timeout);	/* enable timeout */
 }
 
 static void act(struct floppy_state *fs)
 {
-	volatile struct swim3 *sw = fs->swim3;
-
 	for (;;) {
 		switch (fs->state) {
 		case idle:
@@ -492,20 +500,10 @@ static void act(struct floppy_state *fs)
 			return;
 
 		case settling:
-			/* wait for SEEK_COMPLETE to become true */
-			swim3_select(fs, SEEK_COMPLETE);
-			udelay(10);
-			out_8(&sw->intr_enable, ERROR_INTR | DATA_CHANGED);
-			in_8(&sw->intr);	/* clear DATA_CHANGED */
-			if (in_8(&sw->status) & DATA) {
-				/* seek_complete is not yet true */
-				set_timeout(fs, HZ/2, seek_timeout);
-				return;
-			}
-			out_8(&sw->intr_enable, 0);
-			in_8(&sw->intr);
-			fs->state = locating;
-			break;
+			/* check for SEEK_COMPLETE after 30ms */
+			fs->settle_time = (HZ + 32) / 33;
+			set_timeout(fs, fs->settle_time, settle_timeout);
+			return;
 
 		case do_transfer:
 			if (fs->cur_cyl != fs->req_cyl) {
@@ -537,7 +535,7 @@ static void scan_timeout(unsigned long d
 	volatile struct swim3 *sw = fs->swim3;
 
 	fs->timeout_pending = 0;
-	out_8(&sw->control_bic, DO_ACTION);
+	out_8(&sw->control_bic, DO_ACTION | WRITE_SECTORS);
 	out_8(&sw->select, RELAX);
 	out_8(&sw->intr_enable, 0);
 	fs->cur_cyl = -1;
@@ -557,20 +555,34 @@ static void seek_timeout(unsigned long d
 	volatile struct swim3 *sw = fs->swim3;
 
 	fs->timeout_pending = 0;
-	if (fs->state == settling) {
-		printk(KERN_ERR "swim3: MSI sel=%x ctrl=%x stat=%x intr=%x ie=%x\n",
-		       sw->select, sw->control, sw->status, sw->intr, sw->intr_enable);
-	}
 	out_8(&sw->control_bic, DO_SEEK);
 	out_8(&sw->select, RELAX);
 	out_8(&sw->intr_enable, 0);
-	if (fs->state == settling && swim3_readbit(fs, SEEK_COMPLETE)) {
-		/* printk(KERN_DEBUG "swim3: missed settling interrupt\n"); */
+	printk(KERN_ERR "swim3: seek timeout\n");
+	end_request(fd_req, 0);
+	fs->state = idle;
+	start_request(fs);
+}
+
+static void settle_timeout(unsigned long data)
+{
+	struct floppy_state *fs = (struct floppy_state *) data;
+	volatile struct swim3 *sw = fs->swim3;
+
+	fs->timeout_pending = 0;
+	if (swim3_readbit(fs, SEEK_COMPLETE)) {
+		out_8(&sw->select, RELAX);
 		fs->state = locating;
 		act(fs);
 		return;
 	}
-	printk(KERN_ERR "swim3: seek timeout\n");
+	out_8(&sw->select, RELAX);
+	if (fs->settle_time < 2*HZ) {
+		++fs->settle_time;
+		set_timeout(fs, 1, settle_timeout);
+		return;
+	}
+	printk(KERN_ERR "swim3: seek settle timeout\n");
 	end_request(fd_req, 0);
 	fs->state = idle;
 	start_request(fs);
@@ -583,9 +595,13 @@ static void xfer_timeout(unsigned long d
 	struct dbdma_regs *dr = fs->dma;
 	struct dbdma_cmd *cp = fs->dma_cmd;
 	unsigned long s;
+	int n;
 
 	fs->timeout_pending = 0;
 	st_le32(&dr->control, RUN << 16);
+	/* We must wait a bit for dbdma to stop */
+	for (n = 0; (in_le32(&dr->status) & ACTIVE) && n < 1000; n++)
+		udelay(1);
 	out_8(&sw->intr_enable, 0);
 	out_8(&sw->control_bic, WRITE_SECTORS | DO_ACTION);
 	out_8(&sw->select, RELAX);
@@ -604,7 +620,7 @@ static void xfer_timeout(unsigned long d
 	start_request(fs);
 }
 
-static void swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct floppy_state *fs = (struct floppy_state *) dev_id;
 	volatile struct swim3 *sw = fs->swim3;
@@ -613,18 +629,15 @@ static void swim3_interrupt(int irq, voi
 	struct dbdma_regs *dr;
 	struct dbdma_cmd *cp;
 
-	err = in_8(&sw->error);
 	intr = in_8(&sw->intr);
-#if 0
-	printk("swim3 intr state=%d intr=%x err=%x\n", fs->state, intr, err);
-#endif
+	err = (intr & ERROR_INTR)? in_8(&sw->error): 0;
 	if ((intr & ERROR_INTR) && fs->state != do_transfer)
 		printk(KERN_ERR "swim3_interrupt, state=%d, dir=%lx, intr=%x, err=%x\n",
 		       fs->state, rq_data_dir(fd_req), intr, err);
 	switch (fs->state) {
 	case locating:
 		if (intr & SEEN_SECTOR) {
-			out_8(&sw->control_bic, DO_ACTION);
+			out_8(&sw->control_bic, DO_ACTION | WRITE_SECTORS);
 			out_8(&sw->select, RELAX);
 			out_8(&sw->intr_enable, 0);
 			del_timer(&fs->timeout);
@@ -674,19 +687,33 @@ static void swim3_interrupt(int irq, voi
 	case do_transfer:
 		if ((intr & (ERROR_INTR | TRANSFER_DONE)) == 0)
 			break;
-		dr = fs->dma;
-		cp = fs->dma_cmd;
-		/* We must wait a bit for dbdma to complete */
-		for (n=0; (in_le32(&dr->status) & ACTIVE) && n < 1000; n++)
-			udelay(10);
-		DBDMA_DO_STOP(dr);
 		out_8(&sw->intr_enable, 0);
 		out_8(&sw->control_bic, WRITE_SECTORS | DO_ACTION);
 		out_8(&sw->select, RELAX);
 		del_timer(&fs->timeout);
 		fs->timeout_pending = 0;
+		dr = fs->dma;
+		cp = fs->dma_cmd;
 		if (rq_data_dir(fd_req) == WRITE)
 			++cp;
+		/*
+		 * Check that the main data transfer has finished.
+		 * On writing, the swim3 sometimes doesn't use
+		 * up all the bytes of the postamble, so we can still
+		 * see DMA active here.  That doesn't matter as long
+		 * as all the sector data has been transferred.
+		 */
+		if ((intr & ERROR_INTR) == 0 && cp->xfer_status == 0) {
+			/* wait a little while for DMA to complete */
+			for (n = 0; n < 100; ++n) {
+				if (cp->xfer_status != 0)
+					break;
+				udelay(1);
+				barrier();
+			}
+		}
+		/* turn off DMA */
+		out_le32(&dr->control, (RUN | PAUSE) << 16);
 		stat = ld_le16(&cp->xfer_status);
 		resid = ld_le16(&cp->res_count);
 		if (intr & ERROR_INTR) {
@@ -742,6 +769,7 @@ static void swim3_interrupt(int irq, voi
 	default:
 		printk(KERN_ERR "swim3: don't know what to do in state %d\n", fs->state);
 	}
+	return IRQ_HANDLED;
 }
 
 /*
@@ -793,16 +821,19 @@ static int fd_eject(struct floppy_state 
 	if (err)
 		return err;
 	swim3_action(fs, EJECT);
-	for (n = 2*HZ; n > 0; --n) {
-		if (swim3_readbit(fs, RELAX))
-			break;
+	for (n = 20; n > 0; --n) {
 		if (signal_pending(current)) {
 			err = -EINTR;
 			break;
 		}
+		swim3_select(fs, RELAX);
 		current->state = TASK_INTERRUPTIBLE;
 		schedule_timeout(1);
+		if (swim3_readbit(fs, DISK_IN) == 0)
+			break;
 	}
+	swim3_select(fs, RELAX);
+	udelay(150);
 	fs->ejected = 1;
 	release_drive(fs);
 	return err;
@@ -847,29 +878,31 @@ static int floppy_open(struct inode *ino
 	if (fs->ref_count == 0) {
 		if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
 			return -ENXIO;
-		out_8(&sw->mode, 0x95);
-		out_8(&sw->control_bic, 0xff);
 		out_8(&sw->setup, S_IBM_DRIVE | S_FCLK_DIV2);
+		out_8(&sw->control_bic, 0xff);
+		out_8(&sw->mode, 0x95);
 		udelay(10);
 		out_8(&sw->intr_enable, 0);
 		out_8(&sw->control_bis, DRIVE_ENABLE | INTR_ENABLE);
 		swim3_action(fs, MOTOR_ON);
 		fs->write_prot = -1;
 		fs->cur_cyl = -1;
-		for (n = HZ; n > 0; --n) {
-			if (swim3_readbit(fs, SEEK_COMPLETE))
+		for (n = 0; n < 2 * HZ; ++n) {
+			if (n >= HZ/30 && swim3_readbit(fs, SEEK_COMPLETE))
 				break;
 			if (signal_pending(current)) {
 				err = -EINTR;
 				break;
 			}
+			swim3_select(fs, RELAX);
 			current->state = TASK_INTERRUPTIBLE;
 			schedule_timeout(1);
 		}
 		if (err == 0 && (swim3_readbit(fs, SEEK_COMPLETE) == 0
 				 || swim3_readbit(fs, DISK_IN) == 0))
 			err = -ENXIO;
-		swim3_action(fs, 9);
+		swim3_action(fs, SETMFM);
+		swim3_select(fs, RELAX);
 
 	} else if (fs->ref_count == -1 || filp->f_flags & O_EXCL)
 		return -EBUSY;
@@ -892,6 +925,7 @@ static int floppy_open(struct inode *ino
 		if (fs->ref_count == 0) {
 			swim3_action(fs, MOTOR_OFF);
 			out_8(&sw->control_bic, DRIVE_ENABLE | INTR_ENABLE);
+			swim3_select(fs, RELAX);
 		}
 		return err;
 	}
@@ -911,6 +945,7 @@ static int floppy_release(struct inode *
 	if (fs->ref_count > 0 && --fs->ref_count == 0) {
 		swim3_action(fs, MOTOR_OFF);
 		out_8(&sw->control_bic, 0xff);
+		swim3_select(fs, RELAX);
 	}
 	return 0;
 }
@@ -933,15 +968,17 @@ static int floppy_revalidate(struct gend
 	sw = fs->swim3;
 	grab_drive(fs, revalidating, 0);
 	out_8(&sw->intr_enable, 0);
-	out_8(&sw->control_bis, DRIVE_ENABLE | INTR_ENABLE);
-	swim3_action(fs, MOTOR_ON);
+	out_8(&sw->control_bis, DRIVE_ENABLE);
+	swim3_action(fs, MOTOR_ON);	/* necessary? */
 	fs->write_prot = -1;
 	fs->cur_cyl = -1;
+	mdelay(1);
 	for (n = HZ; n > 0; --n) {
 		if (swim3_readbit(fs, SEEK_COMPLETE))
 			break;
 		if (signal_pending(current))
 			break;
+		swim3_select(fs, RELAX);
 		current->state = TASK_INTERRUPTIBLE;
 		schedule_timeout(1);
 	}
@@ -951,17 +988,14 @@ static int floppy_revalidate(struct gend
 		swim3_action(fs, MOTOR_OFF);
 	else {
 		fs->ejected = 0;
-		swim3_action(fs, 9);
+		swim3_action(fs, SETMFM);
 	}
+	swim3_select(fs, RELAX);
 
 	release_drive(fs);
 	return ret;
 }
 
-static void floppy_off(unsigned int nr)
-{
-}
-
 static struct block_device_operations floppy_fops = {
 	.open		= floppy_open,
 	.release	= floppy_release,
@@ -1104,3 +1138,5 @@ static int swim3_add_device(struct devic
 	
 	return 0;
 }
+
+module_init(swim3_init)
diff -puN /dev/null drivers/char/generic_nvram.c
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/char/generic_nvram.c	2004-01-28 23:09:16.000000000 -0800
@@ -0,0 +1,145 @@
+/*
+ * Generic /dev/nvram driver for architectures providing some
+ * "generic" hooks, that is :
+ *
+ * nvram_read_byte, nvram_write_byte, nvram_sync
+ *
+ * Note that an additional hook is supported for PowerMac only
+ * for getting the nvram "partition" informations
+ *
+ */
+
+#define NVRAM_VERSION "1.1"
+
+#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/init.h>
+#include <linux/smp_lock.h>
+#include <asm/uaccess.h>
+#include <asm/nvram.h>
+
+#define NVRAM_SIZE	8192
+
+static loff_t nvram_llseek(struct file *file, loff_t offset, int origin)
+{
+	lock_kernel();
+	switch (origin) {
+	case 1:
+		offset += file->f_pos;
+		break;
+	case 2:
+		offset += NVRAM_SIZE;
+		break;
+	}
+	if (offset < 0) {
+		unlock_kernel();
+		return -EINVAL;
+	}
+	file->f_pos = offset;
+	unlock_kernel();
+	return file->f_pos;
+}
+
+static ssize_t read_nvram(struct file *file, char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	unsigned int i;
+	char __user *p = buf;
+
+	if (verify_area(VERIFY_WRITE, buf, count))
+		return -EFAULT;
+	if (*ppos >= NVRAM_SIZE)
+		return 0;
+	for (i = *ppos; count > 0 && i < NVRAM_SIZE; ++i, ++p, --count)
+		if (__put_user(nvram_read_byte(i), p))
+			return -EFAULT;
+	*ppos = i;
+	return p - buf;
+}
+
+static ssize_t write_nvram(struct file *file, const char __user *buf,
+			   size_t count, loff_t *ppos)
+{
+	unsigned int i;
+	const char __user *p = buf;
+	char c;
+
+	if (verify_area(VERIFY_READ, buf, count))
+		return -EFAULT;
+	if (*ppos >= NVRAM_SIZE)
+		return 0;
+	for (i = *ppos; count > 0 && i < NVRAM_SIZE; ++i, ++p, --count) {
+		if (__get_user(c, p))
+			return -EFAULT;
+		nvram_write_byte(c, i);
+	}
+	*ppos = i;
+	return p - buf;
+}
+
+static int 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 (_machine != _MACH_Pmac)
+			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 (copy_to_user((void __user*)arg, &offset, sizeof(offset)) != 0)
+			return -EFAULT;
+		break;
+	}
+#endif /* CONFIG_PPC_PMAC */
+	case IOC_NVRAM_SYNC:
+		nvram_sync();
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+struct file_operations nvram_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= nvram_llseek,
+	.read		= read_nvram,
+	.write		= write_nvram,
+	.ioctl		= nvram_ioctl,
+};
+
+static struct miscdevice nvram_dev = {
+	NVRAM_MINOR,
+	"nvram",
+	&nvram_fops
+};
+
+int __init nvram_init(void)
+{
+	printk(KERN_INFO "Macintosh non-volatile memory driver v%s\n",
+		NVRAM_VERSION);
+	return misc_register(&nvram_dev);
+}
+
+void __exit nvram_cleanup(void)
+{
+        misc_deregister( &nvram_dev );
+}
+
+module_init(nvram_init);
+module_exit(nvram_cleanup);
+MODULE_LICENSE("GPL");
diff -puN drivers/char/keyboard.c~big-pmac-3 drivers/char/keyboard.c
--- 25/drivers/char/keyboard.c~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/drivers/char/keyboard.c	2004-01-28 23:09:16.000000000 -0800
@@ -972,11 +972,6 @@ extern void sun_do_break(void);
 static int emulate_raw(struct vc_data *vc, unsigned int keycode, 
 		       unsigned char up_flag)
 {
-#ifdef CONFIG_MAC_EMUMOUSEBTN
-	if (mac_hid_mouse_emulate_buttons(1, keycode, !up_flag))
-		return 0;
-#endif /* CONFIG_MAC_EMUMOUSEBTN */
-
 	if (keycode > 255 || !x86_keycodes[keycode])
 		return -1; 
 
@@ -1055,6 +1050,11 @@ void kbd_keycode(unsigned int keycode, i
 
 	rep = (down == 2);
 
+#ifdef CONFIG_MAC_EMUMOUSEBTN
+	if (mac_hid_mouse_emulate_buttons(1, keycode, down))
+		return;
+#endif /* CONFIG_MAC_EMUMOUSEBTN */
+
 	if ((raw_mode = (kbd->kbdmode == VC_RAW)))
 		if (emulate_raw(vc, keycode, !down << 7))
 			if (keycode < BTN_MISC)
diff -puN drivers/char/Makefile~big-pmac-3 drivers/char/Makefile
--- 25/drivers/char/Makefile~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/drivers/char/Makefile	2004-01-28 23:09:16.000000000 -0800
@@ -56,7 +56,9 @@ obj-$(CONFIG_SONYPI) += sonypi.o
 obj-$(CONFIG_RTC) += rtc.o
 obj-$(CONFIG_GEN_RTC) += genrtc.o
 obj-$(CONFIG_EFI_RTC) += efirtc.o
-ifeq ($(CONFIG_PPC),)
+ifeq ($(CONFIG_GENERIC_NVRAM),y)
+  obj-$(CONFIG_NVRAM) += generic_nvram.o
+else
   obj-$(CONFIG_NVRAM) += nvram.o
 endif
 obj-$(CONFIG_TOSHIBA) += toshiba.o
diff -puN drivers/i2c/busses/i2c-keywest.c~big-pmac-3 drivers/i2c/busses/i2c-keywest.c
--- 25/drivers/i2c/busses/i2c-keywest.c~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/drivers/i2c/busses/i2c-keywest.c	2004-01-28 23:09:16.000000000 -0800
@@ -26,6 +26,8 @@
     2001/12/13 BenH	New implementation
     2001/12/15 BenH	Add support for "byte" and "quick"
                         transfers. Add i2c_xfer routine.
+    2003/09/21 BenH	Rework state machine with Paulus help
+    2004/01/21 BenH	Merge in Greg KH changes, polled mode is back
 
     My understanding of the various modes supported by keywest are:
 
@@ -67,9 +69,35 @@
 #include <asm/prom.h>
 #include <asm/machdep.h>
 #include <asm/pmac_feature.h>
+#include <asm/pmac_low_i2c.h>
 
 #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 {\
+		pr_debug("KW: wrong state. Got %s, state: %s (isr: %02x)\n", \
+			 name, __kw_state_names[iface->state], isr);	\
+	} while(0)
+
+#ifdef DEBUG
+static const char *__kw_state_names[] = {
+	"state_idle",
+	"state_addr",
+	"state_read",
+	"state_write",
+	"state_stop",
+	"state_dead"
+};
+#endif /* DEBUG */
 
 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
 MODULE_DESCRIPTION("I2C driver for Apple's Keywest");
@@ -78,121 +106,154 @@ MODULE_PARM(probe, "i");
 
 static int probe = 0;
 
+#ifdef POLLED_MODE
+/* Don't schedule, the g5 fan controller is too
+ * timing sensitive
+ */
+static u8
+wait_interrupt(struct keywest_iface* iface)
+{
+	int i;
+	u8 isr;
+	
+	for (i = 0; i < 200000; i++) {
+		isr = read_reg(reg_isr) & KW_I2C_IRQ_MASK;
+		if (isr != 0)
+			return isr;
+		udelay(1);
+	}
+	return isr;
+}
+#endif /* POLLED_MODE */
+
 static void
 do_stop(struct keywest_iface* iface, int result)
 {
-	write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_STOP);
+	write_reg(reg_control, KW_I2C_CTL_STOP);
 	iface->state = state_stop;
 	iface->result = result;
 }
 
 /* Main state machine for standard & standard sub mode */
-static int
+static void
 handle_interrupt(struct keywest_iface *iface, u8 isr)
 {
 	int ack;
-	int rearm_timer = 1;
 	
-	pr_debug("handle_interrupt(), got: %x, status: %x, state: %d\n",
-		isr, read_reg(reg_status), iface->state);
-	if (isr == 0 && iface->state != state_stop) {
-		do_stop(iface, -1);
-		return rearm_timer;
-	}
-	if (isr & KW_I2C_IRQ_STOP && iface->state != state_stop) {
-		iface->result = -1;
-		iface->state = state_stop;
-	}
-	switch(iface->state) {
-	case state_addr:
-		if (!(isr & KW_I2C_IRQ_ADDR)) {
-			do_stop(iface, -1);
-			break;
+	if (isr == 0) {
+		if (iface->state != state_stop) {
+			pr_debug("KW: Timeout !\n");
+			do_stop(iface, -EIO);
 		}
-		ack = read_reg(reg_status);
-		pr_debug("ack on set address: %x\n", ack);
-		if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
-			do_stop(iface, -1);
-			break;
-		}
-		/* Handle rw "quick" mode */
-		if (iface->datalen == 0)
-			do_stop(iface, 0);
-		else if (iface->read_write == I2C_SMBUS_READ) {
-			iface->state = state_read;
-			if (iface->datalen > 1)
-				write_reg(reg_control, read_reg(reg_control)
-					| KW_I2C_CTL_AAK);
-		} else {
-			iface->state = state_write;
-			pr_debug("write byte: %x\n", *(iface->data));
-			write_reg(reg_data, *(iface->data++));
-			iface->datalen--;
-		}
-		
-		break;
-	case state_read:
-		if (!(isr & KW_I2C_IRQ_DATA)) {
-			do_stop(iface, -1);
-			break;
-		}
-		*(iface->data++) = read_reg(reg_data);
-		pr_debug("read byte: %x\n", *(iface->data-1));
-		iface->datalen--;
-		if (iface->datalen == 0)
-			iface->state = state_stop;
-		else
-			write_reg(reg_control, 0);
-		break;
-	case state_write:
-		if (!(isr & KW_I2C_IRQ_DATA)) {
-			do_stop(iface, -1);
-			break;
+		if (iface->state == state_stop) {
+			ack = read_reg(reg_status);
+			if (!(ack & KW_I2C_STAT_BUSY)) {
+				iface->state = state_idle;
+				write_reg(reg_ier, 0x00);
+#ifndef POLLED_MODE
+				complete(&iface->complete);
+#endif /* POLLED_MODE */
+			}
 		}
-		/* Check ack status */
+		return;
+	}
+
+	if (isr & KW_I2C_IRQ_ADDR) {
 		ack = read_reg(reg_status);
-		pr_debug("ack on data write: %x\n", ack);
+		if (iface->state != state_addr) {
+			write_reg(reg_isr, KW_I2C_IRQ_ADDR);
+			WRONG_STATE("KW_I2C_IRQ_ADDR"); 
+			do_stop(iface, -EIO);
+			return;
+		}
 		if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
-			do_stop(iface, -1);
-			break;
+			iface->state = state_stop;		     
+			iface->result = -ENODEV;
+			pr_debug("KW: NAK on address\n");
+		} else {
+			/* Handle rw "quick" mode */
+			if (iface->datalen == 0) {
+				do_stop(iface, 0);
+			} else if (iface->read_write == I2C_SMBUS_READ) {
+				iface->state = state_read;
+				if (iface->datalen > 1)
+					write_reg(reg_control, KW_I2C_CTL_AAK);
+			} else {
+				iface->state = state_write;
+				write_reg(reg_data, *(iface->data++));
+				iface->datalen--;
+			}
 		}
-		if (iface->datalen) {
-			pr_debug("write byte: %x\n", *(iface->data));
-			write_reg(reg_data, *(iface->data++));
+		write_reg(reg_isr, KW_I2C_IRQ_ADDR);
+	}
+
+	if (isr & KW_I2C_IRQ_DATA) {
+		if (iface->state == state_read) {
+			*(iface->data++) = read_reg(reg_data);
+			write_reg(reg_isr, KW_I2C_IRQ_DATA);
 			iface->datalen--;
-		} else
-			do_stop(iface, 0);
-		break;
-		
-	case state_stop:
-		if (!(isr & KW_I2C_IRQ_STOP) && (++iface->stopretry) < 10)
-			do_stop(iface, -1);
-		else {
-			rearm_timer = 0;
-			iface->state = state_idle;
-			write_reg(reg_control, 0x00);
-			write_reg(reg_ier, 0x00);
-			complete(&iface->complete);
+			if (iface->datalen == 0)
+				iface->state = state_stop;
+			else if (iface->datalen == 1)
+				write_reg(reg_control, 0);
+		} else if (iface->state == state_write) {
+			/* Check ack status */
+			ack = read_reg(reg_status);
+			if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
+				pr_debug("KW: nack on data write (%x): %x\n",
+				    iface->data[-1], ack);
+				do_stop(iface, -EIO);
+			} else if (iface->datalen) {
+				write_reg(reg_data, *(iface->data++));
+				iface->datalen--;
+			} else {
+				write_reg(reg_control, KW_I2C_CTL_STOP);
+				iface->state = state_stop;
+				iface->result = 0;
+			}
+			write_reg(reg_isr, KW_I2C_IRQ_DATA);
+		} else {
+			write_reg(reg_isr, KW_I2C_IRQ_DATA);
+			WRONG_STATE("KW_I2C_IRQ_DATA"); 
+			if (iface->state != state_stop)
+				do_stop(iface, -EIO);
 		}
-		break;
 	}
-	
-	write_reg(reg_isr, isr);
 
-	return rearm_timer;
+	if (isr & KW_I2C_IRQ_STOP) {
+		write_reg(reg_isr, KW_I2C_IRQ_STOP);
+		if (iface->state != state_stop) {
+			WRONG_STATE("KW_I2C_IRQ_STOP");
+			iface->result = -EIO;
+		}
+		iface->state = state_idle;
+		write_reg(reg_ier, 0x00);
+#ifndef POLLED_MODE
+		complete(&iface->complete);
+#endif /* POLLED_MODE */			
+	}
+
+	if (isr & KW_I2C_IRQ_START)
+		write_reg(reg_isr, KW_I2C_IRQ_START);
 }
 
+#ifndef POLLED_MODE
+
 /* Interrupt handler */
 static irqreturn_t
 keywest_irq(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct keywest_iface *iface = (struct keywest_iface *)dev_id;
+	unsigned long flags;
 
-	spin_lock(&iface->lock);
+	spin_lock_irqsave(&iface->lock, flags);
 	del_timer(&iface->timeout_timer);
-	if (handle_interrupt(iface, read_reg(reg_isr)))
-		mod_timer(&iface->timeout_timer, jiffies + POLL_TIMEOUT);
-	spin_unlock(&iface->lock);
+	handle_interrupt(iface, read_reg(reg_isr));
+	if (iface->state != state_idle) {
+		iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
+		add_timer(&iface->timeout_timer);
+	}
+	spin_unlock_irqrestore(&iface->lock, flags);
 	return IRQ_HANDLED;
 }
 
@@ -200,14 +261,20 @@ static void
 keywest_timeout(unsigned long data)
 {
 	struct keywest_iface *iface = (struct keywest_iface *)data;
+	unsigned long flags;
 
 	pr_debug("timeout !\n");
-	spin_lock_irq(&iface->lock);
-	if (handle_interrupt(iface, read_reg(reg_isr)))
-		mod_timer(&iface->timeout_timer, jiffies + POLL_TIMEOUT);
-	spin_unlock(&iface->lock);
+	spin_lock_irqsave(&iface->lock, flags);
+	handle_interrupt(iface, read_reg(reg_isr));
+	if (iface->state != state_idle) {
+		iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
+		add_timer(&iface->timeout_timer);
+	}
+	spin_unlock_irqrestore(&iface->lock, flags);
 }
 
+#endif /* POLLED_MODE */
+
 /*
  * SMBUS-type transfer entrypoint
  */
@@ -228,46 +295,54 @@ keywest_smbus_xfer(	struct i2c_adapter*	
 	int rc = 0;
 
 	if (iface->state == state_dead)
-		return -1;
+		return -ENXIO;
 		
 	/* Prepare datas & select mode */
 	iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK;
 	switch (size) {
-	    case I2C_SMBUS_QUICK:
+        case I2C_SMBUS_QUICK:
 	    	len = 0;
 	    	buffer = NULL;
 	    	iface->cur_mode |= KW_I2C_MODE_STANDARD;
 	    	break;
-	    case I2C_SMBUS_BYTE:
+        case I2C_SMBUS_BYTE:
 	    	len = 1;
 	    	buffer = &data->byte;
 	    	iface->cur_mode |= KW_I2C_MODE_STANDARD;
 	    	break;
-	    case I2C_SMBUS_BYTE_DATA:
+        case I2C_SMBUS_BYTE_DATA:
 	    	len = 1;
 	    	buffer = &data->byte;
 	    	iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
 	    	break;
-	    case I2C_SMBUS_WORD_DATA:
+        case I2C_SMBUS_WORD_DATA:
 	    	len = 2;
 	    	cur_word = cpu_to_le16(data->word);
 	    	buffer = (u8 *)&cur_word;
 	    	iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
 		break;
-	    case I2C_SMBUS_BLOCK_DATA:
+        case I2C_SMBUS_BLOCK_DATA:
 	    	len = data->block[0];
 	    	buffer = &data->block[1];
 	    	iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
 		break;
-	    default:
+        default:
 	    	return -1;
 	}
 
+	/* Turn a standardsub read into a combined mode access */
+ 	if (read_write == I2C_SMBUS_READ
+ 	    && (iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_STANDARDSUB) {
+ 		iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK;
+ 		iface->cur_mode |= KW_I2C_MODE_COMBINED;
+ 	}
+
 	/* Original driver had this limitation */
 	if (len > 32)
 		len = 32;
 
-	down(&iface->sem);
+	if (pmac_low_i2c_lock(iface->node))
+		return -ENXIO;
 
 	pr_debug("chan: %d, addr: 0x%x, transfer len: %d, read: %d\n",
 		chan->chan_no, addr, len, read_write == I2C_SMBUS_READ);
@@ -276,12 +351,11 @@ keywest_smbus_xfer(	struct i2c_adapter*	
 	iface->datalen = len;
 	iface->state = state_addr;
 	iface->result = 0;
-	iface->stopretry = 0;
 	iface->read_write = read_write;
 	
 	/* Setup channel & clear pending irqs */
-	write_reg(reg_mode, iface->cur_mode | (chan->chan_no << 4));
 	write_reg(reg_isr, read_reg(reg_isr));
+	write_reg(reg_mode, iface->cur_mode | (chan->chan_no << 4));
 	write_reg(reg_status, 0);
 
 	/* Set up address and r/w bit */
@@ -293,15 +367,31 @@ keywest_smbus_xfer(	struct i2c_adapter*	
 	    || (iface->cur_mode & KW_I2C_MODE_MODE_MASK) == KW_I2C_MODE_COMBINED)
 		write_reg(reg_subaddr, command);
 
+#ifndef POLLED_MODE
 	/* Arm timeout */
-	mod_timer(&iface->timeout_timer, jiffies + POLL_TIMEOUT);
+	iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
+	add_timer(&iface->timeout_timer);
+#endif
 
 	/* Start sending address & enable interrupt*/
-	write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_XADDR);
+	write_reg(reg_control, KW_I2C_CTL_XADDR);
 	write_reg(reg_ier, KW_I2C_IRQ_MASK);
 
-	/* Wait interrupt operations completion */
+#ifdef POLLED_MODE
+	pr_debug("using polled mode...\n");
+	/* State machine, to turn into an interrupt handler */
+	while(iface->state != state_idle) {
+		unsigned long flags;
+
+		u8 isr = wait_interrupt(iface);
+		spin_lock_irqsave(&iface->lock, flags);
+		handle_interrupt(iface, isr);
+		spin_unlock_irqrestore(&iface->lock, flags);
+	}
+#else /* POLLED_MODE */
+	pr_debug("using interrupt mode...\n");
 	wait_for_completion(&iface->complete);	
+#endif /* POLLED_MODE */	
 
 	rc = iface->result;	
 	pr_debug("transfer done, result: %d\n", rc);
@@ -310,7 +400,7 @@ keywest_smbus_xfer(	struct i2c_adapter*	
 	    	data->word = le16_to_cpu(cur_word);
 	
 	/* Release sem */
-	up(&iface->sem);
+	pmac_low_i2c_unlock(iface->node);
 	
 	return rc;
 }
@@ -329,7 +419,11 @@ keywest_xfer(	struct i2c_adapter *adap,
 	int i, completed;
 	int rc = 0;
 
-	down(&iface->sem);
+	if (iface->state == state_dead)
+		return -ENXIO;
+
+	if (pmac_low_i2c_lock(iface->node))
+		return -ENXIO;
 
 	/* Set adapter to standard mode */
 	iface->cur_mode &= ~KW_I2C_MODE_MODE_MASK;
@@ -360,7 +454,6 @@ keywest_xfer(	struct i2c_adapter *adap,
 		iface->datalen = pmsg->len;
 		iface->state = state_addr;
 		iface->result = 0;
-		iface->stopretry = 0;
 		if (pmsg->flags & I2C_M_RD)
 			iface->read_write = I2C_SMBUS_READ;
 		else
@@ -373,15 +466,27 @@ keywest_xfer(	struct i2c_adapter *adap,
 			(addr << 1) |
 			((iface->read_write == I2C_SMBUS_READ) ? 0x01 : 0x00));
 
+#ifndef POLLED_MODE
 		/* Arm timeout */
-		mod_timer(&iface->timeout_timer, jiffies + POLL_TIMEOUT);
+		iface->timeout_timer.expires = jiffies + POLL_TIMEOUT;
+		add_timer(&iface->timeout_timer);
+#endif
 
 		/* Start sending address & enable interrupt*/
-		write_reg(reg_control, read_reg(reg_control) | KW_I2C_CTL_XADDR);
 		write_reg(reg_ier, KW_I2C_IRQ_MASK);
+		write_reg(reg_control, KW_I2C_CTL_XADDR);
 
-		/* Wait interrupt operations completion */
+#ifdef POLLED_MODE
+		pr_debug("using polled mode...\n");
+		/* State machine, to turn into an interrupt handler */
+		while(iface->state != state_idle) {
+			u8 isr = wait_interrupt(iface);
+			handle_interrupt(iface, isr);
+		}
+#else /* POLLED_MODE */
+		pr_debug("using interrupt mode...\n");
 		wait_for_completion(&iface->complete);	
+#endif /* POLLED_MODE */	
 
 		rc = iface->result;
 		if (rc == 0)
@@ -390,7 +495,7 @@ keywest_xfer(	struct i2c_adapter *adap,
 	}
 
 	/* Release sem */
-	up(&iface->sem);
+	pmac_low_i2c_unlock(iface->node);
 
 	return completed;
 }
@@ -421,6 +526,9 @@ create_iface(struct device_node *np, str
 	struct keywest_iface* iface;
 	int rc;
 
+	if (pmac_low_i2c_lock(np))
+		return -ENODEV;
+
 	psteps = (unsigned long *)get_property(np, "AAPL,address-step", NULL);
 	steps = psteps ? (*psteps) : 0x10;
 
@@ -428,7 +536,7 @@ create_iface(struct device_node *np, str
 	for (bsteps = 0; (steps & 0x01) == 0; bsteps++)
 		steps >>= 1;
 
-	if (!strcmp(np->parent->name, "uni-n")) {
+	if (np->parent->name[0] == 'u') {
 		nchan = 2;
 		addroffset = 3;
 	} else {
@@ -441,12 +549,13 @@ create_iface(struct device_node *np, str
 	iface = (struct keywest_iface *) kmalloc(tsize, GFP_KERNEL);
 	if (iface == NULL) {
 		printk(KERN_ERR "i2c-keywest: can't allocate inteface !\n");
+		pmac_low_i2c_unlock(np);
 		return -ENOMEM;
 	}
 	memset(iface, 0, tsize);
-	init_MUTEX(&iface->sem);
 	spin_lock_init(&iface->lock);
 	init_completion(&iface->complete);
+	iface->node = of_node_get(np);
 	iface->bsteps = bsteps;
 	iface->chan_count = nchan;
 	iface->state = state_idle;
@@ -458,12 +567,15 @@ create_iface(struct device_node *np, str
 	if (iface->base == 0) {
 		printk(KERN_ERR "i2c-keywest: can't map inteface !\n");
 		kfree(iface);
+		pmac_low_i2c_unlock(np);
 		return -ENOMEM;
 	}
 
+#ifndef POLLED_MODE
 	init_timer(&iface->timeout_timer);
 	iface->timeout_timer.function = keywest_timeout;
 	iface->timeout_timer.data = (unsigned long)iface;
+#endif
 
 	/* Select interface rate */
 	iface->cur_mode = KW_I2C_MODE_100KHZ;
@@ -483,8 +595,8 @@ create_iface(struct device_node *np, str
 			*prate);
 	}
 	
-	/* Select standard sub mode */
-	iface->cur_mode |= KW_I2C_MODE_STANDARDSUB;
+	/* Select standard mode by default */
+	iface->cur_mode |= KW_I2C_MODE_STANDARD;
 	
 	/* Write mode */
 	write_reg(reg_mode, iface->cur_mode);
@@ -493,14 +605,17 @@ create_iface(struct device_node *np, str
 	write_reg(reg_ier, 0x00);
 	write_reg(reg_isr, KW_I2C_IRQ_MASK);
 
+#ifndef POLLED_MODE
 	/* Request chip interrupt */	
-	rc = request_irq(iface->irq, keywest_irq, 0, "keywest i2c", iface);
+	rc = request_irq(iface->irq, keywest_irq, SA_INTERRUPT, "keywest i2c", iface);
 	if (rc) {
 		printk(KERN_ERR "i2c-keywest: can't get IRQ %d !\n", iface->irq);
 		iounmap((void *)iface->base);
 		kfree(iface);
+		pmac_low_i2c_unlock(np);
 		return -ENODEV;
 	}
+#endif /* POLLED_MODE */
 
 	dev_set_drvdata(dev, iface);
 	
@@ -539,6 +654,7 @@ create_iface(struct device_node *np, str
 	printk(KERN_INFO "Found KeyWest i2c on \"%s\", %d channel%s, stepping: %d bits\n",
 		np->parent->name, nchan, nchan > 1 ? "s" : "", bsteps);
 		
+	pmac_low_i2c_unlock(np);
 	return 0;
 }
 
@@ -549,8 +665,10 @@ dispose_iface(struct device *dev)
 	int i, rc;
 	
 	/* Make sure we stop all activity */
-	down(&iface->sem);
+	if (pmac_low_i2c_lock(iface->node))
+		return -ENODEV;
 
+#ifndef POLLED_MODE
 	spin_lock_irq(&iface->lock);
 	while (iface->state != state_idle) {
 		spin_unlock_irq(&iface->lock);
@@ -558,10 +676,14 @@ dispose_iface(struct device *dev)
 		schedule_timeout(HZ/10);
 		spin_lock_irq(&iface->lock);
 	}
+#endif /* POLLED_MODE */
 	iface->state = state_dead;
+#ifndef POLLED_MODE
 	spin_unlock_irq(&iface->lock);
 	free_irq(iface->irq, iface);
-	up(&iface->sem);
+#endif /* POLLED_MODE */
+
+	pmac_low_i2c_unlock(iface->node);
 
 	/* Release all channels */
 	for (i=0; i<iface->chan_count; i++) {
@@ -576,6 +698,7 @@ dispose_iface(struct device *dev)
 	}
 	iounmap((void *)iface->base);
 	dev_set_drvdata(dev, NULL);
+	of_node_put(iface->node);
 	kfree(iface);
 
 	return 0;
@@ -634,8 +757,8 @@ static struct of_platform_driver i2c_key
 static int __init
 i2c_keywest_init(void)
 {
-	macio_register_driver(&i2c_keywest_macio_driver);
 	of_register_driver(&i2c_keywest_of_platform_driver);
+	macio_register_driver(&i2c_keywest_macio_driver);
 
 	return 0;
 }
@@ -643,8 +766,8 @@ i2c_keywest_init(void)
 static void __exit
 i2c_keywest_cleanup(void)
 {
-	macio_unregister_driver(&i2c_keywest_macio_driver);
 	of_unregister_driver(&i2c_keywest_of_platform_driver);
+	macio_unregister_driver(&i2c_keywest_macio_driver);
 }
 
 module_init(i2c_keywest_init);
diff -puN drivers/i2c/busses/i2c-keywest.h~big-pmac-3 drivers/i2c/busses/i2c-keywest.h
--- 25/drivers/i2c/busses/i2c-keywest.h~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/drivers/i2c/busses/i2c-keywest.h	2004-01-28 23:09:16.000000000 -0800
@@ -51,20 +51,19 @@ typedef enum {
 /* Physical interface */
 struct keywest_iface
 {
+	struct device_node	*node;
 	unsigned long		base;
 	unsigned		bsteps;
 	int			irq;
-	struct semaphore	sem;
 	spinlock_t		lock;
-	struct keywest_chan*	channels;
+	struct keywest_chan	*channels;
 	unsigned		chan_count;
 	u8			cur_mode;
 	char			read_write;
-	u8*			data;
+	u8			*data;
 	unsigned		datalen;
 	int			state;
 	int			result;
-	int			stopretry;
 	struct timer_list	timeout_timer;
 	struct completion	complete;
 };
@@ -98,8 +97,7 @@ static inline void __write_reg(struct ke
 {
 	out_8(((volatile u8 *)iface->base)
 		+ (((unsigned)reg) << iface->bsteps), val);
-	(void)__read_reg(iface, reg);
-	udelay(10);
+	(void)__read_reg(iface, reg_subaddr);
 }
 
 #define write_reg(reg, val)	__write_reg(iface, reg, val) 
diff -puN drivers/ide/ppc/pmac.c~big-pmac-3 drivers/ide/ppc/pmac.c
--- 25/drivers/ide/ppc/pmac.c~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/drivers/ide/ppc/pmac.c	2004-01-28 23:09:16.000000000 -0800
@@ -69,7 +69,7 @@ typedef struct pmac_ide_hwif {
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 	/* Those fields are duplicating what is in hwif. We currently
 	 * can't use the hwif ones because of some assumptions that are
-	 * being done by the generic code about the kind of dma controller
+	 * beeing done by the generic code about the kind of dma controller
 	 * and format of the dma table. This will have to be fixed though.
 	 */
 	volatile struct dbdma_regs*	dma_regs;
@@ -90,15 +90,17 @@ enum {
 	controller_heathrow,	/* Heathrow/Paddington */
 	controller_kl_ata3,	/* KeyLargo ATA-3 */
 	controller_kl_ata4,	/* KeyLargo ATA-4 */
-	controller_un_ata6	/* UniNorth2 ATA-6 */
+	controller_un_ata6,	/* UniNorth2 ATA-6 */
+	controller_k2_ata6	/* K2 ATA-6 */
 };
 
 static const char* model_name[] = {
 	"OHare ATA",		/* OHare based */
 	"Heathrow ATA",		/* Heathrow/Paddington */
-	"KeyLargo ATA-3",	/* KeyLargo ATA-3 */
-	"KeyLargo ATA-4",	/* KeyLargo ATA-4 */
-	"UniNorth ATA-6"	/* UniNorth2 ATA-6 */
+	"KeyLargo ATA-3",	/* KeyLargo ATA-3 (MDMA only) */
+	"KeyLargo ATA-4",	/* KeyLargo ATA-4 (UDMA/66) */
+	"UniNorth ATA-6",	/* UniNorth2 ATA-6 (UDMA/100) */
+	"K2 ATA-6",		/* K2 ATA-6 (UDMA/100) */
 };
 
 /*
@@ -336,16 +338,19 @@ kauai_lookup_timing(struct kauai_timing*
 /* allow up to 256 DBDMA commands per xfer */
 #define MAX_DCMDS		256
 
-/* Wait 2s for disk to answer on IDE bus after
- * enable operation.
- * NOTE: There is at least one case I know of a disk that needs about 10sec
- *       before anwering on the bus. I beleive we could add a kernel command
- *       line arg to override this delay for such cases.
- *       
- * NOTE2: This has to be fixed with a BSY wait loop. I'm working on adding
- *        that to the generic probe code.
+/* 
+ * Wait 1s for disk to answer on IDE bus after a hard reset
+ * of the device (via GPIO/FCR).
+ * 
+ * Some devices seem to "pollute" the bus even after dropping
+ * the BSY bit (typically some combo drives slave on the UDMA
+ * bus) after a hard reset. Since we hard reset all drives on
+ * KeyLargo ATA66, we have to keep that delay around. I may end
+ * up not hard resetting anymore on these and keep the delay only
+ * for older interfaces instead (we have to reset when coming
+ * from MacOS...) --BenH. 
  */
-#define IDE_WAKEUP_DELAY_MS	2000
+#define IDE_WAKEUP_DELAY	(1*HZ)
 
 static void pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif);
 static int pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq);
@@ -357,9 +362,16 @@ static int pmac_ide_dma_begin (ide_drive
 
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 
+/*
+ * Below is the code for blinking the laptop LED along with hard
+ * disk activity.
+ */
+
 #ifdef CONFIG_BLK_DEV_IDE_PMAC_BLINK
 
-/* Set to 50ms */
+/* Set to 50ms minimum led-on time (also used to limit frequency
+ * of requests sent to the PMU
+ */
 #define PMU_HD_BLINK_TIME	(HZ/50)
 
 static struct adb_request pmu_blink_on, pmu_blink_off;
@@ -402,6 +414,7 @@ pmu_hd_kick_blink(void *data, int rw)
 	pmu_blink_stoptime = jiffies + PMU_HD_BLINK_TIME;
 	wmb();
 	mod_timer(&pmu_blink_timer, pmu_blink_stoptime);
+	/* Fast path when LED is already ON */
 	if (pmu_blink_ledstate == 1)
 		return;
 	spin_lock_irqsave(&pmu_blink_lock, flags);
@@ -418,6 +431,11 @@ pmu_hd_blink_init(void)
 	struct device_node *dt;
 	const char *model;
 
+	/* Currently, I only enable this feature on KeyLargo based laptops,
+	 * older laptops may support it (at least heathrow/paddington) but
+	 * I don't feel like loading those venerable old machines with so
+	 * much additional interrupt & PMU activity...
+	 */
 	if (pmu_get_model() != PMU_KEYLARGO_BASED)
 		return 0;
 	
@@ -476,9 +494,11 @@ pmac_ide_init_hwif_ports(hw_regs_t *hw,
 		*irq = pmac_ide[ix].irq;
 }
 
-/* Setup timings for the selected drive (master/slave). I still need to verify if this
- * is enough, I beleive selectproc will be called whenever an IDE command is started,
- * but... */
+/*
+ * Apply the timings of the proper unit (master/slave) to the shared
+ * timing register when selecting that unit. This version is for
+ * ASICs with a single timing register
+ */
 static void __pmac
 pmac_ide_selectproc(ide_drive_t *drive)
 {
@@ -496,6 +516,11 @@ pmac_ide_selectproc(ide_drive_t *drive)
 	(void)readl((unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG));
 }
 
+/*
+ * Apply the timings of the proper unit (master/slave) to the shared
+ * timing register when selecting that unit. This version is for
+ * ASICs with a dual timing register (Kauai)
+ */
 static void __pmac
 pmac_ide_kauai_selectproc(ide_drive_t *drive)
 {
@@ -518,6 +543,9 @@ pmac_ide_kauai_selectproc(ide_drive_t *d
 	(void)readl((unsigned *)(IDE_DATA_REG + IDE_KAUAI_PIO_CONFIG));
 }
 
+/*
+ * Force an update of controller timing values for a given drive
+ */
 static void __pmac
 pmac_ide_do_update_timings(ide_drive_t *drive)
 {
@@ -526,12 +554,29 @@ pmac_ide_do_update_timings(ide_drive_t *
 	if (pmif == NULL)
 		return;
 
-	if (pmif->kind == controller_un_ata6)
+	if (pmif->kind == controller_un_ata6 || pmif->kind == controller_k2_ata6)
 		pmac_ide_kauai_selectproc(drive);
 	else
 		pmac_ide_selectproc(drive);
 }
 
+static void
+pmac_outbsync(ide_drive_t *drive, u8 value, unsigned long port)
+{
+	u32 tmp;
+	
+	writeb(value, port);	
+	tmp = readl((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG));
+}
+
+/*
+ * Send the SET_FEATURE IDE command to the drive and update drive->id with
+ * the new state. We currently don't use the generic routine as it used to
+ * cause various trouble, especially with older mediabays.
+ * This code is sometimes triggering a spurrious interrupt though, I need
+ * to sort that out sooner or later and see if I can finally get the
+ * common version to work properly in all cases
+ */
 static int __pmac
 pmac_ide_do_setfeature(ide_drive_t *drive, u8 command)
 {
@@ -606,7 +651,9 @@ out:
 	return result;
 }
 
-/* Calculate PIO timings */
+/*
+ * Old tuning functions (called on hdparm -p), sets up drive PIO timings
+ */
 static void __pmac
 pmac_ide_tuneproc(ide_drive_t *drive, u8 pio)
 {
@@ -625,7 +672,8 @@ pmac_ide_tuneproc(ide_drive_t *drive, u8
 	pio = ide_get_best_pio_mode(drive, pio, 4, &d);
 
 	switch (pmif->kind) {
-	case controller_un_ata6: {
+	case controller_un_ata6:
+	case controller_k2_ata6: {
 		/* 100Mhz cell */
 		u32 tr = kauai_lookup_timing(kauai_pio_timings, d.cycle_time);
 		if (tr == 0)
@@ -685,6 +733,10 @@ pmac_ide_tuneproc(ide_drive_t *drive, u8
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
+
+/*
+ * Calculate KeyLargo ATA/66 UDMA timings
+ */
 static int __pmac
 set_timings_udma_ata4(u32 *timings, u8 speed)
 {
@@ -710,6 +762,9 @@ set_timings_udma_ata4(u32 *timings, u8 s
 	return 0;
 }
 
+/*
+ * Calculate Kauai ATA/100 UDMA timings
+ */
 static int __pmac
 set_timings_udma_ata6(u32 *pio_timings, u32 *ultra_timings, u8 speed)
 {
@@ -727,6 +782,9 @@ set_timings_udma_ata6(u32 *pio_timings, 
 	return 0;
 }
 
+/*
+ * Calculate MDMA timings for all cells
+ */
 static int __pmac
 set_timings_mdma(ide_drive_t *drive, int intf_type, u32 *timings, u32 *timings2,
 			u8 speed, int drive_cycle_time)
@@ -753,6 +811,7 @@ set_timings_mdma(ide_drive_t *drive, int
 	/* Get the proper timing array for this controller */
 	switch(intf_type) {
 		case controller_un_ata6:
+		case controller_k2_ata6:
 			break;
 		case controller_kl_ata4:
 			tm = mdma_timings_66;
@@ -784,7 +843,8 @@ set_timings_mdma(ide_drive_t *drive, int
 #endif
 	}
 	switch(intf_type) {
-	case controller_un_ata6: {
+	case controller_un_ata6:
+	case controller_k2_ata6: {
 		/* 100Mhz cell */
 		u32 tr = kauai_lookup_timing(kauai_mdma_timings, cycleTime);
 		if (tr == 0)
@@ -854,8 +914,12 @@ set_timings_mdma(ide_drive_t *drive, int
 }
 #endif /* #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC */
 
-/* You may notice we don't use this function on normal operation,
- * our, normal mdma function is supposed to be more precise
+/* 
+ * Speedproc. This function is called by the core to set any of the standard
+ * timing (PIO, MDMA or UDMA) to both the drive and the controller.
+ * You may notice we don't use this function on normal "dma check" operation,
+ * our dedicated function is more precise as it uses the drive provided
+ * cycle time value. We should probably fix this one to deal with that too...
  */
 static int __pmac
 pmac_ide_tune_chipset (ide_drive_t *drive, byte speed)
@@ -874,7 +938,8 @@ pmac_ide_tune_chipset (ide_drive_t *driv
 	switch(speed) {
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 		case XFER_UDMA_5:
-			if (pmif->kind != controller_un_ata6)
+			if (pmif->kind != controller_un_ata6 &&
+			    pmif->kind != controller_k2_ata6)
 				return 1;
 		case XFER_UDMA_4:
 		case XFER_UDMA_3:
@@ -885,7 +950,8 @@ pmac_ide_tune_chipset (ide_drive_t *driv
 		case XFER_UDMA_0:
 			if (pmif->kind == controller_kl_ata4)
 				ret = set_timings_udma_ata4(timings, speed);
-			else if (pmif->kind == controller_un_ata6)
+			else if (pmif->kind == controller_un_ata6
+				 || pmif->kind == controller_k2_ata6)
 				ret = set_timings_udma_ata6(timings, timings2, speed);
 			else
 				ret = 1;		
@@ -923,6 +989,10 @@ pmac_ide_tune_chipset (ide_drive_t *driv
 	return 0;
 }
 
+/*
+ * Blast some well known "safe" values to the timing registers at init or
+ * wakeup from sleep time, before we do real calculation
+ */
 static void __pmac
 sanitize_timings(pmac_ide_hwif_t *pmif)
 {
@@ -930,6 +1000,7 @@ sanitize_timings(pmac_ide_hwif_t *pmif)
 	
 	switch(pmif->kind) {
 		case controller_un_ata6:
+		case controller_k2_ata6:
 			value = 0x08618a92;
 			value2 = 0x00002921;
 			break;
@@ -1052,9 +1123,11 @@ pmac_ide_do_resume(ide_hwif_t *hwif)
 	if (!pmif->mediabay) {
 		ppc_md.feature_call(PMAC_FTR_IDE_RESET, pmif->node, pmif->aapl_bus_id, 1);
 		ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, pmif->node, pmif->aapl_bus_id, 1);
-		mdelay(10);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ/100);
 		ppc_md.feature_call(PMAC_FTR_IDE_RESET, pmif->node, pmif->aapl_bus_id, 0);
-		mdelay(100);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(IDE_WAKEUP_DELAY);
 	}
 
 	/* Sanitize drive timings */
@@ -1063,6 +1136,13 @@ pmac_ide_do_resume(ide_hwif_t *hwif)
 	return 0;
 }
 
+/*
+ * Setup, register & probe an IDE channel driven by this driver, this is
+ * called by one of the 2 probe functions (macio or PCI). Note that a channel
+ * that ends up beeing free of any device is not kept around by this driver
+ * (it is kept in 2.4). This introduce an interface numbering change on some
+ * rare machines unfortunately, but it's better this way.
+ */
 static int
 pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
 {
@@ -1073,6 +1153,8 @@ pmac_ide_setup_device(pmac_ide_hwif_t *p
 	pmif->broken_dma = pmif->broken_dma_warn = 0;
 	if (device_is_compatible(np, "kauai-ata"))
 		pmif->kind = controller_un_ata6;
+	else if (device_is_compatible(np, "K2-UATA"))
+		pmif->kind = controller_k2_ata6;
 	else if (device_is_compatible(np, "keylargo-ata")) {
 		if (strcmp(np->name, "ata-4") == 0)
 			pmif->kind = controller_kl_ata4;
@@ -1089,7 +1171,8 @@ pmac_ide_setup_device(pmac_ide_hwif_t *p
 	pmif->aapl_bus_id =  bidp ? *bidp : 0;
 
 	/* Get cable type from device-tree */
-	if (pmif->kind == controller_kl_ata4 || pmif->kind == controller_un_ata6) {
+	if (pmif->kind == controller_kl_ata4 || pmif->kind == controller_un_ata6
+	    || pmif->kind == controller_k2_ata6) {
 		char* cable = get_property(np, "cable-type", NULL);
 		if (cable && !strncmp(cable, "80-", 3))
 			pmif->cable_80 = 1;
@@ -1119,13 +1202,16 @@ pmac_ide_setup_device(pmac_ide_hwif_t *p
  		/* 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);
-		mdelay(10);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ/100);
 		ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 0);
-		mdelay(100);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(IDE_WAKEUP_DELAY);		
 	}
 
 	/* Setup MMIO ops */
 	default_hwif_mmiops(hwif);
+       	hwif->OUTBSYNC = pmac_outbsync;
 
 	/* Tell common code _not_ to mess with resources */
 	hwif->mmio = 2;
@@ -1139,7 +1225,7 @@ pmac_ide_setup_device(pmac_ide_hwif_t *p
 	hwif->drives[0].unmask = 1;
 	hwif->drives[1].unmask = 1;
 	hwif->tuneproc = pmac_ide_tuneproc;
-	if (pmif->kind == controller_un_ata6)
+	if (pmif->kind == controller_un_ata6 || pmif->kind == controller_k2_ata6)
 		hwif->selectproc = pmac_ide_kauai_selectproc;
 	else
 		hwif->selectproc = pmac_ide_selectproc;
@@ -1187,6 +1273,9 @@ pmac_ide_setup_device(pmac_ide_hwif_t *p
 	return 0;
 }
 
+/*
+ * Attach to a macio probed interface
+ */
 static int __devinit
 pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_match *match)
 {
@@ -1215,17 +1304,8 @@ pmac_ide_macio_attach(struct macio_dev *
 		return -ENXIO;
 	}
 
-	/*
-	 * Some older OFs have bogus sizes, causing request_OF_resource
-	 * to fail. We fix them up here
-	 */
-	if (mdev->ofdev.node->addrs[0].size > 0x1000)
-		mdev->ofdev.node->addrs[0].size = 0x1000;
-	if (mdev->ofdev.node->n_addrs > 1 && mdev->ofdev.node->addrs[1].size > 0x100)
-		mdev->ofdev.node->addrs[1].size = 0x100;
-
 	/* Request memory resource for IO ports */
-	if (request_OF_resource(mdev->ofdev.node, 0, "  (mac-io ata ports)") == NULL) {
+	if (macio_request_resource(mdev, 0, "ide-pmac (ports)")) {
 		printk(KERN_ERR "ide%d: can't request mmio resource !\n", i);
 		return -EBUSY;
 	}
@@ -1235,14 +1315,14 @@ pmac_ide_macio_attach(struct macio_dev *
 	 * fixes in irq.c. That works well enough for the single case
 	 * where that happens though...
 	 */
-	if (mdev->ofdev.node->n_intrs == 0) {
+	if (macio_irq_count(mdev) == 0) {
 		printk(KERN_WARNING "ide%d: no intrs for device %s, using 13\n",
 			i, mdev->ofdev.node->full_name);
 		irq = 13;
 	} else
-		irq = mdev->ofdev.node->intrs[0].line;
+		irq = macio_irq(mdev, 0);
 
-	base =  (unsigned long) ioremap(mdev->ofdev.node->addrs[0].address, 0x400);
+	base =  (unsigned long)ioremap(macio_resource_start(mdev, 0), 0x400);
 	regbase = base;
 
 	hwif->pci_dev = mdev->bus->pdev;
@@ -1253,10 +1333,13 @@ pmac_ide_macio_attach(struct macio_dev *
 	pmif->regbase = regbase;
 	pmif->irq = irq;
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
-	if (mdev->ofdev.node->n_addrs >= 2)
-		pmif->dma_regs = (volatile struct dbdma_regs*)
-			ioremap(mdev->ofdev.node->addrs[1].address, 0x1000);
-	else
+	if (macio_resource_count(mdev) >= 2) {
+		if (macio_request_resource(mdev, 1, "ide-pmac (dma)"))
+			printk(KERN_WARNING "ide%d: can't request DMA resource !\n", i);
+		else
+			pmif->dma_regs = (volatile struct dbdma_regs*)
+				ioremap(macio_resource_start(mdev, 1), 0x1000);
+	} else
 		pmif->dma_regs = NULL;
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 	dev_set_drvdata(&mdev->ofdev.dev, hwif);
@@ -1269,7 +1352,9 @@ pmac_ide_macio_attach(struct macio_dev *
 		if (pmif->dma_regs)
 			iounmap((void *)pmif->dma_regs);
 		memset(pmif, 0, sizeof(*pmif));
-		release_OF_resource(mdev->ofdev.node, 0);
+		macio_release_resource(mdev, 0);
+		if (pmif->dma_regs)
+			macio_release_resource(mdev, 1);
 	}
 
 	return rc;
@@ -1305,6 +1390,9 @@ pmac_ide_macio_resume(struct macio_dev *
 	return rc;
 }
 
+/*
+ * Attach to a PCI probed interface
+ */
 static int __devinit
 pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
 {
@@ -1439,8 +1527,10 @@ static struct macio_driver pmac_ide_maci
 	.resume		= pmac_ide_macio_resume,
 };
 
-static struct pci_device_id pmac_ide_pci_match[] __devinitdata = {
-	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_KAUAI_ATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+static struct pci_device_id pmac_ide_pci_match[] = {
+	{ PCI_VENDOR_ID_APPLE, PCI_DEVIEC_ID_APPLE_UNI_N_ATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_IPID_ATA100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_K2_ATA100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 };
 
 static struct pci_driver pmac_ide_pci_driver = {
@@ -1468,6 +1558,11 @@ pmac_ide_probe(void)
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 
+/*
+ * This is very close to the generic ide-dma version of the function except
+ * that we don't use the fields in the hwif but our own copies for sg_table
+ * and friends. We build & map the sglist for a given request
+ */
 static int __pmac
 pmac_ide_build_sglist(ide_drive_t *drive, struct request *rq)
 {
@@ -1489,6 +1584,9 @@ pmac_ide_build_sglist(ide_drive_t *drive
 	return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
 }
 
+/*
+ * Same as above but for a "raw" taskfile request
+ */
 static int __pmac
 pmac_ide_raw_build_sglist(ide_drive_t *drive, struct request *rq)
 {
@@ -1630,7 +1728,9 @@ pmac_ide_destroy_dmatable (ide_drive_t *
 	}
 }
 
-/* Calculate MultiWord DMA timings */
+/*
+ * Pick up best MDMA timing for the drive and apply it
+ */
 static int __pmac
 pmac_ide_mdma_enable(ide_drive_t *drive, u16 mode)
 {
@@ -1685,7 +1785,9 @@ pmac_ide_mdma_enable(ide_drive_t *drive,
 	return 1;
 }
 
-/* Calculate Ultra DMA timings */
+/*
+ * Pick up best UDMA timing for the drive and apply it
+ */
 static int __pmac
 pmac_ide_udma_enable(ide_drive_t *drive, u16 mode)
 {
@@ -1704,7 +1806,7 @@ pmac_ide_udma_enable(ide_drive_t *drive,
 	timing_local[1] = *timings2;
 	
 	/* Calculate timings for interface */
-	if (pmif->kind == controller_un_ata6)
+	if (pmif->kind == controller_un_ata6 || pmif->kind == controller_k2_ata6)
 		ret = set_timings_udma_ata6(	&timing_local[0],
 						&timing_local[1],
 						mode);
@@ -1733,6 +1835,10 @@ pmac_ide_udma_enable(ide_drive_t *drive,
 	return 1;
 }
 
+/*
+ * Check what is the best DMA timing setting for the drive and
+ * call appropriate functions to apply it.
+ */
 static int __pmac
 pmac_ide_dma_check(ide_drive_t *drive)
 {
@@ -1754,11 +1860,13 @@ pmac_ide_dma_check(ide_drive_t *drive)
 		short mode;
 		
 		map = XFER_MWDMA;
-		if (pmif->kind == controller_kl_ata4 || pmif->kind == controller_un_ata6) {
+		if (pmif->kind == controller_kl_ata4 || pmif->kind == controller_un_ata6
+		    || pmif->kind == controller_k2_ata6) {
 			map |= XFER_UDMA;
 			if (pmif->cable_80) {
 				map |= XFER_UDMA_66;
-				if (pmif->kind == controller_un_ata6)
+				if (pmif->kind == controller_un_ata6 ||
+				    pmif->kind == controller_k2_ata6)
 					map |= XFER_UDMA_100;
 			}
 		}
@@ -1774,6 +1882,10 @@ pmac_ide_dma_check(ide_drive_t *drive)
 	return 0;
 }
 
+/*
+ * Prepare a DMA transfer. We build the DMA table, adjust the timings for
+ * a read on KeyLargo ATA/66 and mark us as waiting for DMA completion
+ */
 static int __pmac
 pmac_ide_dma_start(ide_drive_t *drive, int reading)
 {
@@ -1802,6 +1914,9 @@ pmac_ide_dma_start(ide_drive_t *drive, i
 	return 0;
 }
 
+/*
+ * Start a DMA READ command
+ */
 static int __pmac
 pmac_ide_dma_read(ide_drive_t *drive)
 {
@@ -1831,6 +1946,9 @@ pmac_ide_dma_read(ide_drive_t *drive)
 	return pmac_ide_dma_begin(drive);
 }
 
+/*
+ * Start a DMA WRITE command
+ */
 static int __pmac
 pmac_ide_dma_write (ide_drive_t *drive)
 {
@@ -1865,6 +1983,10 @@ pmac_ide_dma_count (ide_drive_t *drive)
 	return HWIF(drive)->ide_dma_begin(drive);
 }
 
+/*
+ * Kick the DMA controller into life after the DMA command has been issued
+ * to the drive.
+ */
 static int __pmac
 pmac_ide_dma_begin (ide_drive_t *drive)
 {
@@ -1881,6 +2003,9 @@ pmac_ide_dma_begin (ide_drive_t *drive)
 	return 0;
 }
 
+/*
+ * After a DMA transfer, make sure the controller is stopped
+ */
 static int __pmac
 pmac_ide_dma_end (ide_drive_t *drive)
 {
@@ -1900,6 +2025,12 @@ pmac_ide_dma_end (ide_drive_t *drive)
 	return (dstat & (RUN|DEAD|ACTIVE)) != RUN;
 }
 
+/*
+ * Check out that the interrupt we got was for us. We can't always know this
+ * for sure with those Apple interfaces (well, we could on the recent ones but
+ * that's not implemented yet), on the other hand, we don't have shared interrupts
+ * so it's not really a problem
+ */
 static int __pmac
 pmac_ide_dma_test_irq (ide_drive_t *drive)
 {
@@ -1982,6 +2113,10 @@ pmac_ide_dma_lostirq (ide_drive_t *drive
 	return 0;
 }
 
+/*
+ * Allocate the data structures needed for using DMA with an interface
+ * and fill the proper list of functions pointers
+ */
 static void __init 
 pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
 {
@@ -2049,6 +2184,7 @@ pmac_ide_setup_dma(pmac_ide_hwif_t *pmif
 	hwif->atapi_dma = 1;
 	switch(pmif->kind) {
 		case controller_un_ata6:
+		case controller_k2_ata6:
 			hwif->ultra_mask = pmif->cable_80 ? 0x3f : 0x07;
 			hwif->mwdma_mask = 0x07;
 			hwif->swdma_mask = 0x00;
diff -puN drivers/Kconfig~big-pmac-3 drivers/Kconfig
--- 25/drivers/Kconfig~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/drivers/Kconfig	2004-01-28 23:09:16.000000000 -0800
@@ -26,6 +26,8 @@ source "drivers/ieee1394/Kconfig"
 
 source "drivers/message/i2o/Kconfig"
 
+source "drivers/macintosh/Kconfig"
+
 source "net/Kconfig"
 
 source "drivers/isdn/Kconfig"
diff -puN drivers/macintosh/adb.c~big-pmac-3 drivers/macintosh/adb.c
--- 25/drivers/macintosh/adb.c~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/drivers/macintosh/adb.c	2004-01-28 23:09:16.000000000 -0800
@@ -83,6 +83,7 @@ static pid_t adb_probe_task_pid;
 static DECLARE_MUTEX(adb_probe_mutex);
 static struct completion adb_probe_task_comp;
 static int sleepy_trackpad;
+static int autopoll_devs;
 int __adb_probe_sync;
 
 #ifdef CONFIG_PMAC_PBOOK
@@ -379,7 +380,7 @@ adb_notify_sleep(struct pmu_sleep_notifi
 static int
 do_adb_reset_bus(void)
 {
-	int ret, nret, devs;
+	int ret, nret;
 	
 	if (adb_controller == NULL)
 		return -ENXIO;
@@ -390,7 +391,7 @@ do_adb_reset_bus(void)
 	nret = notifier_call_chain(&adb_client_list, ADB_MSG_PRE_RESET, NULL);
 	if (nret & NOTIFY_STOP_MASK) {
 		if (adb_controller->autopoll)
-			adb_controller->autopoll(devs);
+			adb_controller->autopoll(autopoll_devs);
 		return -EBUSY;
 	}
 
@@ -416,9 +417,9 @@ do_adb_reset_bus(void)
 	}
 
 	if (!ret) {
-		devs = adb_scan_bus();
+		autopoll_devs = adb_scan_bus();
 		if (adb_controller->autopoll)
-			adb_controller->autopoll(devs);
+			adb_controller->autopoll(autopoll_devs);
 	}
 	up(&adb_handler_sem);
 
diff -puN drivers/macintosh/adbhid.c~big-pmac-3 drivers/macintosh/adbhid.c
--- 25/drivers/macintosh/adbhid.c~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/drivers/macintosh/adbhid.c	2004-01-28 23:09:16.000000000 -0800
@@ -30,6 +30,8 @@
  * To do:
  *
  * Improve Kensington support.
+ * Split mouse/kbd
+ * Move to syfs
  */
 
 #include <linux/config.h>
@@ -63,6 +65,15 @@ static struct notifier_block adbhid_adb_
 	.notifier_call	= adb_message_handler,
 };
 
+/* Some special keys */
+#define ADB_KEY_DEL		0x33
+#define ADB_KEY_CMD		0x37
+#define ADB_KEY_CAPSLOCK	0x39
+#define ADB_KEY_FN		0x3f
+#define ADB_KEY_FWDEL		0x75
+#define ADB_KEY_POWER_OLD	0x7e
+#define ADB_KEY_POWER		0x7f
+
 unsigned char adb_to_linux_keycodes[128] = {
 	 30, 31, 32, 33, 35, 34, 44, 45, 46, 47, 86, 48, 16, 17, 18, 19,
 	 21, 20,  2,  3,  4,  5,  7,  6, 13, 10,  8, 12,  9, 11, 27, 24,
@@ -84,8 +95,13 @@ struct adbhid {
 	unsigned char *keycode;
 	char name[64];
 	char phys[32];
+	int flags;
 };
 
+#define FLAG_FN_KEY_PRESSED	0x00000001
+#define FLAG_POWER_FROM_FN	0x00000002
+#define FLAG_EMU_FWDEL_DOWN	0x00000004
+
 static struct adbhid *adbhid[16] = { 0 };
 
 static void adbhid_probe(void);
@@ -148,28 +164,64 @@ adbhid_keyboard_input(unsigned char *dat
 static void
 adbhid_input_keycode(int id, int keycode, int repeat, struct pt_regs *regs)
 {
+	struct adbhid *ahid = adbhid[id];
 	int up_flag;
 
 	up_flag = (keycode & 0x80);
 	keycode &= 0x7f;
 
 	switch (keycode) {
-	case 0x39: /* Generate down/up events for CapsLock everytime. */
-		input_regs(&adbhid[id]->input, regs);
-		input_report_key(&adbhid[id]->input, KEY_CAPSLOCK, 1);
-		input_report_key(&adbhid[id]->input, KEY_CAPSLOCK, 0);
-		input_sync(&adbhid[id]->input);
-		return;
-	case 0x3f: /* ignore Powerbook Fn key */
+	case ADB_KEY_CAPSLOCK: /* Generate down/up events for CapsLock everytime. */
+		input_regs(&ahid->input, regs);
+		input_report_key(&ahid->input, KEY_CAPSLOCK, 1);
+		input_report_key(&ahid->input, KEY_CAPSLOCK, 0);
+		input_sync(&ahid->input);
 		return;
 #ifdef CONFIG_PPC_PMAC
-	case 0x7e: /* Power key on PBook 3400 needs remapping */
+	case ADB_KEY_POWER_OLD: /* Power key on PBook 3400 needs remapping */
 		switch(pmac_call_feature(PMAC_FTR_GET_MB_INFO,
 			NULL, PMAC_MB_INFO_MODEL, 0)) {
 		case PMAC_TYPE_COMET:
 		case PMAC_TYPE_HOOPER:
 		case PMAC_TYPE_KANGA:
-			keycode = 0x7f;
+			keycode = ADB_KEY_POWER;
+		}
+		break;
+	case ADB_KEY_POWER: 
+		/* Fn + Command will produce a bogus "power" keycode */
+		if (ahid->flags & FLAG_FN_KEY_PRESSED) {
+			keycode = ADB_KEY_CMD;
+			if (up_flag)
+				ahid->flags &= ~FLAG_POWER_FROM_FN;
+			else
+				ahid->flags |= FLAG_POWER_FROM_FN;
+		} else if (ahid->flags & FLAG_POWER_FROM_FN) {
+			keycode = ADB_KEY_CMD;
+			ahid->flags &= ~FLAG_POWER_FROM_FN;
+		}
+		break;
+	case ADB_KEY_FN:
+		/* Keep track of the Fn key state */
+		if (up_flag) {
+			ahid->flags &= ~FLAG_FN_KEY_PRESSED;
+			/* Emulate Fn+delete = forward delete */
+			if (ahid->flags & FLAG_EMU_FWDEL_DOWN) {
+				ahid->flags &= ~FLAG_EMU_FWDEL_DOWN;
+				keycode = ADB_KEY_FWDEL;
+				break;
+			}
+		} else
+			ahid->flags |= FLAG_FN_KEY_PRESSED;
+		/* Swallow the key press */
+		return;
+	case ADB_KEY_DEL:
+		/* Emulate Fn+delete = forward delete */
+		if (ahid->flags & FLAG_FN_KEY_PRESSED) {
+			keycode = ADB_KEY_FWDEL;
+			if (up_flag)
+				ahid->flags &= ~FLAG_EMU_FWDEL_DOWN;
+			else
+				ahid->flags |= FLAG_EMU_FWDEL_DOWN;
 		}
 		break;
 #endif /* CONFIG_PPC_PMAC */
@@ -500,6 +552,7 @@ adbhid_input_register(int id, int defaul
 	adbhid[id]->original_handler_id = original_handler_id;
 	adbhid[id]->current_handler_id = current_handler_id;
 	adbhid[id]->mouse_kind = mouse_kind;
+	adbhid[id]->flags = 0;
 	adbhid[id]->input.private = adbhid[id];
 	adbhid[id]->input.name = adbhid[id]->name;
 	adbhid[id]->input.phys = adbhid[id]->phys;
diff -puN /dev/null drivers/macintosh/Kconfig
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/macintosh/Kconfig	2004-01-28 23:09:16.000000000 -0800
@@ -0,0 +1,148 @@
+
+menu "Macintosh device drivers"
+
+# 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
+	help
+	  This provides support for CUDA based Power Macintosh systems.  This
+	  includes most OldWorld PowerMacs, the first generation iMacs, the
+	  Blue&White G3 and the "Yikes" G4 (PCI Graphics).  All later models
+	  should use CONFIG_ADB_PMU instead.  It is safe to say Y here even if
+	  your machine doesn't have a CUDA.
+
+	  If unsure say Y.
+
+config ADB_PMU
+	bool "Support for PMU  based PowerMacs"
+	depends on PPC_PMAC
+	help
+	  On PowerBooks, iBooks, and recent iMacs and Power Macintoshes, the
+	  PMU is an embedded microprocessor whose primary function is to
+	  control system power, and battery charging on the portable models.
+	  The PMU also controls the ADB (Apple Desktop Bus) which connects to
+	  the keyboard and mouse on some machines, as well as the non-volatile
+	  RAM and the RTC (real time clock) chip.  Say Y to enable support for
+	  this device; you should do so if your machine is one of those
+	  mentioned above.
+
+config PMAC_PBOOK
+	bool "Power management support for PowerBooks"
+	depends on ADB_PMU
+	---help---
+	  This provides support for putting a PowerBook to sleep; it also
+	  enables media bay support.  Power management works on the
+	  PB2400/3400/3500, Wallstreet, Lombard, and Bronze PowerBook G3 and
+	  the Titanium Powerbook G4, as well as the iBooks.  You should get
+	  the power management daemon, pmud, to make it work and you must have
+	  the /dev/pmu device (see the pmud README).
+
+	  Get pmud from <ftp://ftp.samba.org/pub/ppclinux/pmud/>.
+
+	  If you have a PowerBook, you should say Y here.
+
+	  You may also want to compile the dma sound driver as a module and
+	  have it autoloaded. The act of removing the module shuts down the
+	  sound hardware for more power savings.
+
+config PM
+	bool
+	depends on PPC_PMAC && ADB_PMU && PMAC_PBOOK
+	default y
+
+config PMAC_APM_EMU
+	tristate "APM emulation"
+	depends on PMAC_PBOOK
+
+# made a separate option since backlight may end up beeing used
+# on non-powerbook machines (but only on PMU based ones AFAIK)
+config PMAC_BACKLIGHT
+	bool "Backlight control for LCD screens"
+	depends on ADB_PMU
+	help
+	  Say Y here to build in code to manage the LCD backlight on a
+	  Macintosh PowerBook.  With this code, the backlight will be turned
+	  on and off appropriately on power-management and lid-open/lid-closed
+	  events; also, the PowerBook button device will be enabled so you can
+	  change the screen brightness.
+
+config MAC_FLOPPY
+	bool "Support for PowerMac floppy"
+	depends on PPC_PMAC && !POWER4
+	help
+	  If you have a SWIM-3 (Super Woz Integrated Machine 3; from Apple)
+	  floppy controller, say Y here. Most commonly found in PowerMacs.
+
+config MAC_SERIAL
+	tristate "Support for PowerMac serial ports (OBSOLETE DRIVER)"
+	depends on PPC_PMAC
+	help
+	  This driver is obsolete. Use CONFIG_SERIAL_PMACZILOG in
+	  "Character devices --> Serial drivers --> PowerMac z85c30" option.
+
+config ADB
+	bool "Apple Desktop Bus (ADB) support"
+	depends on PPC_PMAC
+	help
+	  Apple Desktop Bus (ADB) support is for support of devices which
+	  are connected to an ADB port.  ADB devices tend to have 4 pins.
+	  If you have an Apple Macintosh prior to the iMac, an iBook or
+	  PowerBook, or a "Blue and White G3", you probably want to say Y
+	  here.  Otherwise say N.
+
+config ADB_MACIO
+	bool "Include MacIO (CHRP) ADB driver"
+	depends on ADB && !POWER4
+	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
+	  also includes a MESH II SCSI controller, DBDMA controller, VIA chip,
+	  OpenPIC controller and two RS422/Geoports.)
+
+config INPUT_ADBHID
+	bool "Support for ADB input devices (keyboard, mice, ...)"
+	depends on ADB && INPUT=y
+	help
+	  Say Y here if you want to have ADB (Apple Desktop Bus) HID devices
+	  such as keyboards, mice, joysticks, trackpads  or graphic tablets
+	  handled by the input layer.  If you say Y here, make sure to say Y to
+	  the corresponding drivers "Keyboard support" (CONFIG_INPUT_KEYBDEV),
+	  "Mouse Support" (CONFIG_INPUT_MOUSEDEV) and "Event interface
+	  support" (CONFIG_INPUT_EVDEV) as well.
+
+	  If unsure, say Y.
+
+config MAC_EMUMOUSEBTN
+	bool "Support for mouse button 2+3 emulation"
+	depends on INPUT_ADBHID
+	help
+	  This provides generic support for emulating the 2nd and 3rd mouse
+	  button with keypresses.  If you say Y here, the emulation is still
+	  disabled by default.  The emulation is controlled by these sysctl
+	  entries:
+	  /proc/sys/dev/mac_hid/mouse_button_emulation
+	  /proc/sys/dev/mac_hid/mouse_button2_keycode
+	  /proc/sys/dev/mac_hid/mouse_button3_keycode
+
+	  If you have an Apple machine with a 1-button mouse, say Y here.
+
+config THERM_WINDTUNNEL
+	tristate "Support for thermal management on Windtunnel G4s"
+	depends on I2C && I2C_KEYWEST && !POWER4
+	help
+	  This driver provides some thermostat and fan control for the desktop
+	  G4 "Windtunnel"
+
+config THERM_PM72
+	tristate "Support for thermal management on PowerMac G5"
+	depends on I2C && I2C_KEYWEST && POWER4
+	help
+	  This driver provides thermostat and fan control for the desktop
+	  G5 machines. 
+
+config ANSLCD
+	bool "Support for ANS LCD display"
+	depends on ADB_CUDA
+
+endmenu
diff -puN drivers/macintosh/macio_asic.c~big-pmac-3 drivers/macintosh/macio_asic.c
--- 25/drivers/macintosh/macio_asic.c~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/drivers/macintosh/macio_asic.c	2004-01-28 23:09:16.000000000 -0800
@@ -23,10 +23,13 @@
 #include <asm/prom.h>
 #include <asm/pci-bridge.h>
 
+#define DEBUG
+
+#define MAX_NODE_NAME_SIZE (BUS_ID_SIZE - 12)
+
 static struct macio_chip      *macio_on_hold;
 
-static int
-macio_bus_match(struct device *dev, struct device_driver *drv) 
+static int macio_bus_match(struct device *dev, struct device_driver *drv) 
 {
 	struct macio_dev * macio_dev = to_macio_device(dev);
 	struct macio_driver * macio_drv = to_macio_driver(drv);
@@ -85,41 +88,42 @@ static int macio_device_probe(struct dev
 static int macio_device_remove(struct device *dev)
 {
 	struct macio_dev * macio_dev = to_macio_device(dev);
-	struct macio_driver * drv = to_macio_driver(macio_dev->ofdev.dev.driver);
+	struct macio_driver * drv = to_macio_driver(dev->driver);
 
-	if (drv && drv->remove)
+	if (dev->driver && drv->remove)
 		drv->remove(macio_dev);
 	macio_dev_put(macio_dev);
 
 	return 0;
 }
 
+static void macio_device_shutdown(struct device *dev)
+{
+	struct macio_dev * macio_dev = to_macio_device(dev);
+	struct macio_driver * drv = to_macio_driver(dev->driver);
+
+	if (dev->driver && drv->shutdown)
+		drv->shutdown(macio_dev);
+}
+
 static int macio_device_suspend(struct device *dev, u32 state)
 {
 	struct macio_dev * macio_dev = to_macio_device(dev);
-	struct macio_driver * drv;
-	int error = 0;
+	struct macio_driver * drv = to_macio_driver(dev->driver);
 
-	if (macio_dev->ofdev.dev.driver == NULL)
-		return 0;
-	drv = to_macio_driver(macio_dev->ofdev.dev.driver);
-	if (drv->suspend)
-		error = drv->suspend(macio_dev, state);
-	return error;
+	if (dev->driver && drv->suspend)
+		return drv->suspend(macio_dev, state);
+	return 0;
 }
 
 static int macio_device_resume(struct device * dev)
 {
 	struct macio_dev * macio_dev = to_macio_device(dev);
-	struct macio_driver * drv;
-	int error = 0;
+	struct macio_driver * drv = to_macio_driver(dev->driver);
 
-	if (macio_dev->ofdev.dev.driver == NULL)
-		return 0;
-	drv = to_macio_driver(macio_dev->ofdev.dev.driver);
-	if (drv->resume)
-		error = drv->resume(macio_dev);
-	return error;
+	if (dev->driver && drv->resume)
+		return drv->resume(macio_dev);
+	return 0;
 }
 
 struct bus_type macio_bus_type = {
@@ -129,8 +133,7 @@ struct bus_type macio_bus_type = {
        .resume	= macio_device_resume,
 };
 
-static int __init
-macio_bus_driver_init(void)
+static int __init macio_bus_driver_init(void)
 {
 	return bus_register(&macio_bus_type);
 }
@@ -155,6 +158,58 @@ static void macio_release_dev(struct dev
 }
 
 /**
+ * macio_resource_quirks - tweak or skip some resources for a device
+ * @np: pointer to the device node
+ * @res: resulting resource
+ * @index: index of resource in node
+ *
+ * If this routine returns non-null, then the resource is completely
+ * skipped.
+ */
+static int macio_resource_quirks(struct device_node *np, struct resource *res, int index)
+{
+	if (res->flags & IORESOURCE_MEM) {
+		/* Grand Central has too large resource 0 on some machines */
+		if (index == 0 && !strcmp(np->name, "gc")) {
+			np->addrs[0].size = 0x20000;
+			res->end = res->start + 0x1ffff;
+		}
+		/* Airport has bogus resource 2 */
+		if (index >= 2 && !strcmp(np->name, "radio"))
+			return 1;
+		/* DBDMAs may have bogus sizes */
+		if ((res->start & 0x0001f000) == 0x00008000) {
+			np->addrs[index].size = 0x100;
+			res->end = res->start + 0xff;
+		}
+		/* ESCC parent eats child resources. We could have added a level of hierarchy,
+		 * but I don't really feel the need for it */
+		if (!strcmp(np->name, "escc"))
+			return 1;
+		/* ESCC has bogus resources >= 3 */
+		if (index >= 3 && !(strcmp(np->name, "ch-a") && strcmp(np->name, "ch-b")))
+			return 1;
+		/* Media bay has too many resources, keep only first one */
+		if (index > 0 && !strcmp(np->name, "media-bay"))
+			return 1;
+		/* Some older IDE resources have bogus sizes */
+		if (!(strcmp(np->name, "IDE") && strcmp(np->name, "ATA") &&
+		      strcmp(np->type, "ide") && strcmp(np->type, "ata"))) {
+			if (index == 0 && np->addrs[0].size > 0x1000) {
+				np->addrs[0].size = 0x1000;
+				res->end = res->start + 0xfff;
+			}
+			if (index == 1 && np->addrs[1].size > 0x100) {
+				np->addrs[1].size = 0x100;
+				res->end = res->start + 0xff;
+			}
+		}
+	}
+	return 0;
+}
+
+
+/**
  * macio_add_one_device - Add one device from OF node to the device tree
  * @chip: pointer to the macio_chip holding the device
  * @np: pointer to the device node in the OF tree
@@ -164,9 +219,11 @@ static void macio_release_dev(struct dev
  * be exposed to the bay driver some way...
  */
 static struct macio_dev * macio_add_one_device(struct macio_chip *chip, struct device *parent,
-		     struct device_node *np, struct macio_dev *in_bay)
+					       struct device_node *np, struct macio_dev *in_bay,
+					       struct resource *parent_res)
 {
 	struct macio_dev *dev;
+	int i, j;
 	u32 *reg;
 	
 	if (np == NULL)
@@ -186,22 +243,76 @@ static struct macio_dev * macio_add_one_
 	dev->ofdev.dev.bus = &macio_bus_type;
 	dev->ofdev.dev.release = macio_release_dev;
 
+#ifdef DEBUG
+	printk("preparing mdev @%p, ofdev @%p, dev @%p, kobj @%p\n",
+	       dev, &dev->ofdev, &dev->ofdev.dev, &dev->ofdev.dev.kobj);
+#endif
+
 	/* MacIO itself has a different reg, we use it's PCI base */
 	if (np == chip->of_node) {
-		sprintf(dev->ofdev.dev.bus_id, "%1d.%08lx:%.8s", chip->lbus.index,
+		sprintf(dev->ofdev.dev.bus_id, "%1d.%08lx:%.*s", chip->lbus.index,
 #ifdef CONFIG_PCI
 			pci_resource_start(chip->lbus.pdev, 0),
 #else
 			0, /* NuBus may want to do something better here */
 #endif
-			np->name);
+			MAX_NODE_NAME_SIZE, np->name);
 	} else {
 		reg = (u32 *)get_property(np, "reg", NULL);
-		sprintf(dev->ofdev.dev.bus_id, "%1d.%08x:%.8s", chip->lbus.index,
-			reg ? *reg : 0, np->name);
+		sprintf(dev->ofdev.dev.bus_id, "%1d.%08x:%.*s", chip->lbus.index,
+			reg ? *reg : 0, MAX_NODE_NAME_SIZE, np->name);
 	}
 
+	/* For now, we use pre-parsed entries in the device-tree for
+	 * interrupt routing and addresses, but we should change that
+	 * to dynamically parsed entries and so get rid of most of the
+	 * clutter in struct device_node
+	 */
+	for (i = j = 0; i < np->n_intrs; i++) {
+		struct resource *res = &dev->interrupt[j];
+
+		if (j >= MACIO_DEV_COUNT_IRQS)
+			break;
+		res->start = np->intrs[i].line;
+		res->flags = IORESOURCE_IO;
+		if (np->intrs[j].sense)
+			res->flags |= IORESOURCE_IRQ_LOWLEVEL;
+		else
+			res->flags |= IORESOURCE_IRQ_HIGHEDGE;
+		res->name = dev->ofdev.dev.bus_id;
+		if (macio_resource_quirks(np, res, i))
+			memset(res, 0, sizeof(struct resource));
+		else
+			j++;
+	}
+	dev->n_interrupts = j;
+	for (i = j = 0; i < np->n_addrs; i++) {
+		struct resource *res = &dev->resource[j];
+		
+		if (j >= MACIO_DEV_COUNT_RESOURCES)
+			break;
+		res->start = np->addrs[i].address;
+		res->end = np->addrs[i].address + np->addrs[i].size - 1;
+		res->flags = IORESOURCE_MEM;
+		res->name = dev->ofdev.dev.bus_id;
+		if (macio_resource_quirks(np, res, i))
+			memset(res, 0, sizeof(struct resource));
+		else {
+			j++;
+			/* Currently, we consider failure as harmless, this may
+			 * change in the future, once I've found all the device
+			 * tree bugs in older machines & worked around them
+			 */
+			if (insert_resource(parent_res, res))
+       				printk(KERN_WARNING "Can't request resource %d for MacIO"
+				       " device %s\n", i, dev->ofdev.dev.bus_id);
+		}
+	}
+	dev->n_resources = j;
+
 	if (of_device_register(&dev->ofdev) != 0) {
+		printk(KERN_DEBUG"macio: device registration error for %s!\n",
+		       dev->ofdev.dev.bus_id);
 		kfree(dev);
 		return NULL;
 	}
@@ -234,25 +345,30 @@ static void macio_pci_add_devices(struct
 	struct device_node *np, *pnode;
 	struct macio_dev *rdev, *mdev, *mbdev = NULL, *sdev = NULL;
 	struct device *parent = NULL;
+	struct resource *root_res = &iomem_resource;
 	
 	/* Add a node for the macio bus itself */
 #ifdef CONFIG_PCI
-	if (chip->lbus.pdev)
+	if (chip->lbus.pdev) {
 		parent = &chip->lbus.pdev->dev;
+		root_res = &chip->lbus.pdev->resource[0];
+	}
 #endif
 	pnode = of_node_get(chip->of_node);
 	if (pnode == NULL)
 		return;
 
-	rdev = macio_add_one_device(chip, parent, pnode, NULL);
+	/* Add macio itself to hierarchy */
+	rdev = macio_add_one_device(chip, parent, pnode, NULL, root_res);
 	if (rdev == NULL)
 		return;
+	root_res = &rdev->resource[0];
 
 	/* First scan 1st level */
 	for (np = NULL; (np = of_get_next_child(pnode, np)) != NULL;) {
 		if (!macio_skip_device(np)) {
 			of_node_get(np);
-			mdev = macio_add_one_device(chip, &rdev->ofdev.dev, np, NULL);
+			mdev = macio_add_one_device(chip, &rdev->ofdev.dev, np, NULL, root_res);
 			if (mdev == NULL)
 				of_node_put(np);
 			else if (strncmp(np->name, "media-bay", 9) == 0)
@@ -267,17 +383,20 @@ static void macio_pci_add_devices(struct
 		for (np = NULL; (np = of_get_next_child(mbdev->ofdev.node, np)) != NULL;)
 			if (!macio_skip_device(np)) {
 				of_node_get(np);
-				if (macio_add_one_device(chip, &mbdev->ofdev.dev, np, mbdev) == NULL)
+				if (macio_add_one_device(chip, &mbdev->ofdev.dev, np, mbdev,
+							 root_res) == NULL)
 					of_node_put(np);
 			}
 	/* Add serial ports if any */
-	if (sdev)
+	if (sdev) {
 		for (np = NULL; (np = of_get_next_child(sdev->ofdev.node, np)) != NULL;)
 			if (!macio_skip_device(np)) {
 				of_node_get(np);
-				if (macio_add_one_device(chip, &sdev->ofdev.dev, np, NULL) == NULL)
+				if (macio_add_one_device(chip, &sdev->ofdev.dev, np, NULL,
+							 root_res) == NULL)
 					of_node_put(np);
 			}
+	}
 }
 
 
@@ -294,6 +413,7 @@ int macio_register_driver(struct macio_d
 	drv->driver.bus = &macio_bus_type;
 	drv->driver.probe = macio_device_probe;
 	drv->driver.remove = macio_device_remove;
+	drv->driver.shutdown = macio_device_shutdown;
 
 	/* register with core */
 	count = driver_register(&drv->driver);
@@ -309,6 +429,97 @@ void macio_unregister_driver(struct maci
 	driver_unregister(&drv->driver);
 }
 
+/**
+ *	macio_request_resource - Request an MMIO resource
+ * 	@dev: pointer to the device holding the resource
+ *	@resource_no: resource number to request
+ *	@name: resource name
+ *
+ *	Mark  memory region number @resource_no associated with MacIO
+ *	device @dev as being reserved by owner @name.  Do not access
+ *	any address inside the memory regions unless this call returns
+ *	successfully.
+ *
+ *	Returns 0 on success, or %EBUSY on error.  A warning
+ *	message is also printed on failure.
+ */
+int macio_request_resource(struct macio_dev *dev, int resource_no, const char *name)
+{
+	if (macio_resource_len(dev, resource_no) == 0)
+		return 0;
+		
+	if (!request_mem_region(macio_resource_start(dev, resource_no),
+				macio_resource_len(dev, resource_no),
+				name))
+		goto err_out;
+	
+	return 0;
+
+err_out:
+	printk (KERN_WARNING "MacIO: Unable to reserve resource #%d:%lx@%lx"
+		" for device %s\n",
+		resource_no,
+		macio_resource_len(dev, resource_no),
+		macio_resource_start(dev, resource_no),
+		dev->ofdev.dev.bus_id);
+	return -EBUSY;
+}
+
+/**
+ * macio_release_resource - Release an MMIO resource
+ * @dev: pointer to the device holding the resource
+ * @resource_no: resource number to release
+ */
+void macio_release_resource(struct macio_dev *dev, int resource_no)
+{
+	if (macio_resource_len(dev, resource_no) == 0)
+		return;
+	release_mem_region(macio_resource_start(dev, resource_no),
+			   macio_resource_len(dev, resource_no));
+}
+
+/**
+ *	macio_request_resources - Reserve all memory resources
+ *	@dev: MacIO device whose resources are to be reserved
+ *	@name: Name to be associated with resource.
+ *
+ *	Mark all memory regions associated with MacIO device @dev as
+ *	being reserved by owner @name.  Do not access any address inside
+ *	the memory regions unless this call returns successfully.
+ *
+ *	Returns 0 on success, or %EBUSY on error.  A warning
+ *	message is also printed on failure.
+ */
+int macio_request_resources(struct macio_dev *dev, const char *name)
+{
+	int i;
+	
+	for (i = 0; i < dev->n_resources; i++)
+		if (macio_request_resource(dev, i, name))
+			goto err_out;
+	return 0;
+
+err_out:
+	while(--i >= 0)
+		macio_release_resource(dev, i);
+		
+	return -EBUSY;
+}
+
+/**
+ *	macio_release_resources - Release reserved memory resources
+ *	@dev: MacIO device whose resources were previously reserved
+ */
+
+void macio_release_resources(struct macio_dev *dev)
+{
+	int i;
+	
+	for (i = 0; i < dev->n_resources; i++)
+		macio_release_resource(dev, i);
+}
+
+
 #ifdef CONFIG_PCI
 
 static int __devinit macio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -416,3 +627,7 @@ EXPORT_SYMBOL(macio_register_driver);
 EXPORT_SYMBOL(macio_unregister_driver);
 EXPORT_SYMBOL(macio_dev_get);
 EXPORT_SYMBOL(macio_dev_put);
+EXPORT_SYMBOL(macio_request_resource);
+EXPORT_SYMBOL(macio_release_resource);
+EXPORT_SYMBOL(macio_request_resources);
+EXPORT_SYMBOL(macio_release_resources);
diff -puN drivers/macintosh/Makefile~big-pmac-3 drivers/macintosh/Makefile
--- 25/drivers/macintosh/Makefile~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/drivers/macintosh/Makefile	2004-01-28 23:09:16.000000000 -0800
@@ -8,9 +8,6 @@ obj-$(CONFIG_PPC_PMAC)		+= macio_asic.o
 
 obj-$(CONFIG_PMAC_PBOOK)	+= mediabay.o
 obj-$(CONFIG_MAC_SERIAL)	+= macserial.o
-ifneq ($(CONFIG_MAC),y)
-  obj-$(CONFIG_NVRAM)		+= nvram.o
-endif
 obj-$(CONFIG_MAC_EMUMOUSEBTN)	+= mac_hid.o
 obj-$(CONFIG_INPUT_ADBHID)	+= adbhid.o
 obj-$(CONFIG_ANSLCD)		+= ans-lcd.o
@@ -25,3 +22,6 @@ obj-$(CONFIG_ADB_MACIISI)	+= via-maciisi
 obj-$(CONFIG_ADB_IOP)		+= adb-iop.o
 obj-$(CONFIG_ADB_PMU68K)	+= via-pmu68k.o
 obj-$(CONFIG_ADB_MACIO)		+= macio-adb.o
+
+obj-$(CONFIG_THERM_PM72)	+= therm_pm72.o
+obj-$(CONFIG_THERM_WINDTUNNEL)	+= therm_windtunnel.o
diff -puN drivers/macintosh/mediabay.c~big-pmac-3 drivers/macintosh/mediabay.c
--- 25/drivers/macintosh/mediabay.c~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/drivers/macintosh/mediabay.c	2004-01-28 23:09:16.000000000 -0800
@@ -107,6 +107,11 @@ int media_bay_count = 0;
 #define MS_TO_HZ(ms)	((ms * HZ + 999) / 1000)
 
 /*
+ * Wait that number of ms between each step in normal polling mode
+ */
+#define MB_POLL_DELAY	25
+
+/*
  * Consider the media-bay ID value stable if it is the same for
  * this number of milliseconds
  */
@@ -121,7 +126,7 @@ int media_bay_count = 0;
  * Hold the media-bay reset signal true for this many ticks
  * after a device is inserted before releasing it.
  */
-#define MB_RESET_DELAY	40
+#define MB_RESET_DELAY	50
 
 /*
  * Wait this long after the reset signal is released and before doing
@@ -390,24 +395,28 @@ static void __pmac poll_media_bay(struct
 	int id = bay->ops->content(bay);
 
 	if (id == bay->last_value) {
-	    if (id != bay->content_id
-	        && ++bay->value_count >= MS_TO_HZ(MB_STABLE_DELAY)) {
-	        /* If the device type changes without going thru "MB_NO", we force
-	           a pass by "MB_NO" to make sure things are properly reset */
-	        if ((id != MB_NO) && (bay->content_id != MB_NO)) {
-	            id = MB_NO;
-		    MBDBG("mediabay%d: forcing MB_NO\n", bay->index);
-		}
-		MBDBG("mediabay%d: switching to %d\n", bay->index, id);
-		set_mb_power(bay, id != MB_NO);
-		bay->content_id = id;
-		if (id == MB_NO) {
+		if (id != bay->content_id) {
+			bay->value_count += MS_TO_HZ(MB_POLL_DELAY);
+			if (bay->value_count >= MS_TO_HZ(MB_STABLE_DELAY)) {
+				/* If the device type changes without going thru
+				 * "MB_NO", we force a pass by "MB_NO" to make sure
+				 * things are properly reset
+				 */
+				if ((id != MB_NO) && (bay->content_id != MB_NO)) {
+					id = MB_NO;
+					MBDBG("mediabay%d: forcing MB_NO\n", bay->index);
+				}
+				MBDBG("mediabay%d: switching to %d\n", bay->index, id);
+				set_mb_power(bay, id != MB_NO);
+				bay->content_id = id;
+				if (id == MB_NO) {
 #ifdef CONFIG_BLK_DEV_IDE
-		    bay->cd_retry = 0;
+					bay->cd_retry = 0;
 #endif
-		    printk(KERN_INFO "media bay %d is empty\n", bay->index);
+					printk(KERN_INFO "media bay %d is empty\n", bay->index);
+				}
+			}
 		}
- 	    }
 	} else {
 		bay->last_value = id;
 		bay->value_count = 0;
@@ -496,8 +505,12 @@ static void __pmac media_bay_step(int i)
 	    poll_media_bay(bay);
 
 	/* If timer expired or polling IDE busy, run state machine */
-	if ((bay->state != mb_ide_waiting) && (bay->timer != 0) && ((--bay->timer) != 0))
-	    return;
+	if ((bay->state != mb_ide_waiting) && (bay->timer != 0)) {
+		bay->timer -= MS_TO_HZ(MB_POLL_DELAY);
+		if (bay->timer > 0)
+			return;
+		bay->timer = 0;
+	}
 
 	switch(bay->state) {
 	case mb_powering_up:
@@ -572,12 +585,13 @@ static void __pmac media_bay_step(int i)
 			}
 			break;
 	    	} else if (bay->timer > 0)
-			bay->timer--;
-	    	if (bay->timer == 0) {
+			bay->timer -= MS_TO_HZ(MB_POLL_DELAY);
+	    	if (bay->timer <= 0) {
 			printk("\nIDE Timeout in bay %d !, IDE state is: 0x%02x\n",
 			       i, readb(bay->cd_base + 0x70));
 			MBDBG("mediabay%d: nIDE Timeout !\n", i);
 			set_mb_power(bay, 0);
+			bay->timer = 0;
 	    	}
 		break;
 #endif /* CONFIG_BLK_DEV_IDE */
@@ -630,7 +644,7 @@ static int __pmac media_bay_task(void *x
 		}
 
 		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(MS_TO_HZ(10));
+		schedule_timeout(MS_TO_HZ(MB_POLL_DELAY));
 		if (signal_pending(current))
 			return 0;
 	}
@@ -645,17 +659,16 @@ static int __devinit media_bay_attach(st
 
 	ofnode = mdev->ofdev.node;
 
-	if (!request_OF_resource(ofnode, 0, NULL))
-		return -ENXIO;
-
+	if (macio_resource_count(mdev) < 1)
+		return -ENODEV;
+	if (macio_request_resources(mdev, "media-bay"))
+		return -EBUSY;
 	/* Media bay registers are located at the beginning of the
          * mac-io chip, we get the parent address for now (hrm...)
          */
-	if (ofnode->parent->n_addrs == 0)
-		return -ENODEV;
 	regbase = (volatile u32 *)ioremap(ofnode->parent->addrs[0].address, 0x100);
 	if (regbase == NULL) {
-		release_OF_resource(ofnode, 0);
+		macio_release_resources(mdev);
 		return -ENOMEM;
 	}
 	
@@ -684,13 +697,13 @@ static int __devinit media_bay_attach(st
 	bay->state = mb_empty;
 	do {
 		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(MS_TO_HZ(10));
+		schedule_timeout(MS_TO_HZ(MB_POLL_DELAY));
 		media_bay_step(i);
 	} while((bay->state != mb_empty) &&
 		(bay->state != mb_up));
 
 	/* Mark us ready by filling our mdev data */
-	dev_set_drvdata(&mdev->ofdev.dev, bay);
+	macio_set_drvdata(mdev, bay);
 
 	/* Startup kernel thread */
 	if (i == 0)
@@ -702,7 +715,7 @@ static int __devinit media_bay_attach(st
 
 static int __pmac media_bay_suspend(struct macio_dev *mdev, u32 state)
 {
-	struct media_bay_info	*bay = dev_get_drvdata(&mdev->ofdev.dev);
+	struct media_bay_info	*bay = macio_get_drvdata(mdev);
 
 	if (state != mdev->ofdev.dev.power_state && state >= 2) {
 		down(&bay->lock);
@@ -710,7 +723,7 @@ static int __pmac media_bay_suspend(stru
 		set_mb_power(bay, 0);
 		up(&bay->lock);
 		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(MS_TO_HZ(10));
+		schedule_timeout(MS_TO_HZ(MB_POLL_DELAY));
 		mdev->ofdev.dev.power_state = state;
 	}
 	return 0;
@@ -718,7 +731,7 @@ static int __pmac media_bay_suspend(stru
 
 static int __pmac media_bay_resume(struct macio_dev *mdev)
 {
-	struct media_bay_info	*bay = dev_get_drvdata(&mdev->ofdev.dev);
+	struct media_bay_info	*bay = macio_get_drvdata(mdev);
 
 	if (mdev->ofdev.dev.power_state != 0) {
 		mdev->ofdev.dev.power_state = 0;
@@ -746,7 +759,7 @@ static int __pmac media_bay_resume(struc
 #endif
 	       	do {
 			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout(MS_TO_HZ(10));
+			schedule_timeout(MS_TO_HZ(MB_POLL_DELAY));
 	       		media_bay_step(bay->index);
 	       	} while((bay->state != mb_empty) &&
 	       		(bay->state != mb_up));
diff -puN -L drivers/macintosh/nvram.c drivers/macintosh/nvram.c~big-pmac-3 /dev/null
--- 25/drivers/macintosh/nvram.c
+++ /dev/null	2002-08-30 16:31:37.000000000 -0700
@@ -1,131 +0,0 @@
-/*
- * /dev/nvram driver for Power Macintosh.
- */
-
-#define NVRAM_VERSION "1.0"
-
-#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/smp_lock.h>
-#include <asm/uaccess.h>
-#include <asm/nvram.h>
-
-#define NVRAM_SIZE	8192
-
-static loff_t nvram_llseek(struct file *file, loff_t offset, int origin)
-{
-	lock_kernel();
-	switch (origin) {
-	case 1:
-		offset += file->f_pos;
-		break;
-	case 2:
-		offset += NVRAM_SIZE;
-		break;
-	}
-	if (offset < 0) {
-		unlock_kernel();
-		return -EINVAL;
-	}
-	file->f_pos = offset;
-	unlock_kernel();
-	return file->f_pos;
-}
-
-static ssize_t read_nvram(struct file *file, char __user *buf,
-			  size_t count, loff_t *ppos)
-{
-	unsigned int i;
-	char __user *p = buf;
-
-	if (verify_area(VERIFY_WRITE, buf, count))
-		return -EFAULT;
-	if (*ppos >= NVRAM_SIZE)
-		return 0;
-	for (i = *ppos; count > 0 && i < NVRAM_SIZE; ++i, ++p, --count)
-		if (__put_user(nvram_read_byte(i), p))
-			return -EFAULT;
-	*ppos = i;
-	return p - buf;
-}
-
-static ssize_t write_nvram(struct file *file, const char __user *buf,
-			   size_t count, loff_t *ppos)
-{
-	unsigned int i;
-	const char __user *p = buf;
-	char c;
-
-	if (verify_area(VERIFY_READ, buf, count))
-		return -EFAULT;
-	if (*ppos >= NVRAM_SIZE)
-		return 0;
-	for (i = *ppos; count > 0 && i < NVRAM_SIZE; ++i, ++p, --count) {
-		if (__get_user(c, p))
-			return -EFAULT;
-		nvram_write_byte(c, i);
-	}
-	*ppos = i;
-	return p - buf;
-}
-
-static int nvram_ioctl(struct inode *inode, struct file *file,
-	unsigned int cmd, unsigned long arg)
-{
-	switch(cmd) {
-		case PMAC_NVRAM_GET_OFFSET:
-		{
-			int part, offset;
-			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 (copy_to_user((void __user*)arg, &offset, sizeof(offset)) != 0)
-				return -EFAULT;
-			break;
-		}
-
-		default:
-			return -EINVAL;
-	}
-
-	return 0;
-}
-
-struct file_operations nvram_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= nvram_llseek,
-	.read		= read_nvram,
-	.write		= write_nvram,
-	.ioctl		= nvram_ioctl,
-};
-
-static struct miscdevice nvram_dev = {
-	NVRAM_MINOR,
-	"nvram",
-	&nvram_fops
-};
-
-int __init nvram_init(void)
-{
-	printk(KERN_INFO "Macintosh non-volatile memory driver v%s\n",
-		NVRAM_VERSION);
-	return misc_register(&nvram_dev);
-}
-
-void __exit nvram_cleanup(void)
-{
-        misc_deregister( &nvram_dev );
-}
-
-module_init(nvram_init);
-module_exit(nvram_cleanup);
-MODULE_LICENSE("GPL");
diff -puN /dev/null drivers/macintosh/therm_pm72.c
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/macintosh/therm_pm72.c	2004-01-28 23:09:16.000000000 -0800
@@ -0,0 +1,1241 @@
+/*
+ * Device driver for the thermostats & fan controller of  the
+ * Apple G5 "PowerMac7,2" desktop machines.
+ *
+ * (c) Copyright IBM Corp. 2003
+ *
+ * Maintained by: Benjamin Herrenschmidt
+ *                <benh@kernel.crashing.org>
+ * 
+ *
+ * The algorithm used is the PID control algorithm, used the same
+ * way the published Darwin code does, using the same values that
+ * are present in the Darwin 7.0 snapshot property lists.
+ *
+ * As far as the CPUs control loops are concerned, I use the
+ * calibration & PID constants provided by the EEPROM,
+ * I do _not_ embed any value from the property lists, as the ones
+ * provided by Darwin 7.0 seem to always have an older version that
+ * what I've seen on the actual computers.
+ * It would be interesting to verify that though. Darwin has a
+ * version code of 1.0.0d11 for all control loops it seems, while
+ * so far, the machines EEPROMs contain a dataset versioned 1.0.0f
+ *
+ * Darwin doesn't provide source to all parts, some missing
+ * bits like the AppleFCU driver or the actual scale of some
+ * of the values returned by sensors had to be "guessed" some
+ * way... or based on what Open Firmware does.
+ *
+ * I didn't yet figure out how to get the slots power consumption
+ * out of the FCU, so that part has not been implemented yet and
+ * the slots fan is set to a fixed 50% PWM, hoping this value is
+ * safe enough ...
+ *
+ * Note: I have observed strange oscillations of the CPU control
+ * loop on a dual G5 here. When idle, the CPU exhaust fan tend to
+ * oscillates slowly (over several minutes) between the minimum
+ * of 300RPMs and approx. 1000 RPMs. I don't know what is causing
+ * this, it could be some incorrect constant or an error in the
+ * way I ported the algorithm, or it could be just normal. I
+ * don't have full understanding on the way Apple tweaked the PID
+ * algorithm for the CPU control, it is definitely not a standard
+ * implementation...
+ *
+ * TODO:  - Check MPU structure version/signature
+ *        - Add things like /sbin/overtemp for non-critical
+ *          overtemp conditions so userland can take some policy
+ *          decisions, like slewing down CPUs
+ *	  - Deal with fan failures
+ *
+ * History:
+ *
+ *  Nov. 13, 2003 : 0.5
+ *	- First release
+ *
+ *  Nov. 14, 2003 : 0.6
+ *	- Read fan speed from FCU, low level fan routines now deal
+ *	  with errors & check fan status, though higher level don't
+ *	  do much.
+ *	- Move a bunch of definitions to .h file
+ *
+ *  Nov. 18, 2003 : 0.7
+ *	- Fix build on ppc64 kernel
+ *	- Move back statics definitions to .c file
+ *	- Avoid calling schedule_timeout with a negative number
+ *
+ *  Dev. 18, 2003 : 0.8
+ *	- Fix typo when reading back fan speed on 2 CPU machines
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/wait.h>
+#include <linux/reboot.h>
+#include <linux/kmod.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/sections.h>
+#include <asm/of_device.h>
+
+#include "therm_pm72.h"
+
+#define VERSION "0.8"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(args...)	printk(args)
+#else
+#define DBG(args...)
+#endif
+
+
+/*
+ * Driver statics
+ */
+
+static struct of_device *		of_dev;
+static struct i2c_adapter *		u3_0;
+static struct i2c_adapter *		u3_1;
+static struct i2c_client *		fcu;
+static struct cpu_pid_state		cpu_state[2];
+static struct backside_pid_state	backside_state;
+static struct drives_pid_state		drives_state;
+static int				state;
+static int				cpu_count;
+static pid_t				ctrl_task;
+static struct completion		ctrl_complete;
+static int				critical_state;
+static DECLARE_MUTEX(driver_lock);
+
+/*
+ * i2c_driver structure to attach to the host i2c controller
+ */
+
+static int therm_pm72_attach(struct i2c_adapter *adapter);
+static int therm_pm72_detach(struct i2c_adapter *adapter);
+
+static struct i2c_driver therm_pm72_driver =
+{
+	.name		= "therm_pm72",
+	.id		= 0xDEADBEEF,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= therm_pm72_attach,
+	.detach_adapter	= therm_pm72_detach,
+};
+
+
+static inline void wait_ms(unsigned int ms)
+{
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(1 + (ms * HZ + 999) / 1000);
+}
+
+/*
+ * Utility function to create an i2c_client structure and
+ * attach it to one of u3 adapters
+ */
+static struct i2c_client *attach_i2c_chip(int id, const char *name)
+{
+	struct i2c_client *clt;
+	struct i2c_adapter *adap;
+
+	if (id & 0x100)
+		adap = u3_1;
+	else
+		adap = u3_0;
+	if (adap == NULL)
+		return NULL;
+
+	clt = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+	if (clt == NULL)
+		return NULL;
+	memset(clt, 0, sizeof(struct i2c_client));
+
+	clt->addr = (id >> 1) & 0x7f;
+	clt->adapter = adap;
+	clt->driver = &therm_pm72_driver;
+	clt->id = 0xDEADBEEF;
+	strncpy(clt->name, name, I2C_NAME_SIZE-1);
+
+	if (i2c_attach_client(clt)) {
+		printk(KERN_ERR "therm_pm72: Failed to attach to i2c ID 0x%x\n", id);
+		kfree(clt);
+		return NULL;
+	}
+	return clt;
+}
+
+/*
+ * Utility function to get rid of the i2c_client structure
+ * (will also detach from the adapter hopepfully)
+ */
+static void detach_i2c_chip(struct i2c_client *clt)
+{
+	i2c_detach_client(clt);
+	kfree(clt);
+}
+
+/*
+ * Here are the i2c chip access wrappers
+ */
+static int read_smon_adc(struct i2c_client *chip, int chan)
+{
+	int ctrl;
+
+	ctrl = i2c_smbus_read_byte_data(chip, 1);
+	i2c_smbus_write_byte_data(chip, 1, (ctrl & 0x1f) | (chan << 5));
+	wait_ms(1);
+	return le16_to_cpu(i2c_smbus_read_word_data(chip, 4)) >> 6;
+}
+
+static int fan_read_reg(int reg, unsigned char *buf, int nb)
+{
+	int tries, nr, nw;
+
+	buf[0] = reg;
+	tries = 0;
+	for (;;) {
+		nw = i2c_master_send(fcu, buf, 1);
+		if (nw > 0 || (nw < 0 && nw != -EIO) || tries >= 100)
+			break;
+		wait_ms(10);
+		++tries;
+	}
+	if (nw < 0) {
+		printk(KERN_ERR "Failure writing address to FCU: %d", nw);
+		return -EIO;
+	}
+	tries = 0;
+	for (;;) {
+		nr = i2c_master_recv(fcu, buf, nb);
+		if (nr > 0 || (nr < 0 && nr != ENODEV) || tries >= 100)
+			break;
+		wait_ms(10);
+		++tries;
+	}
+	if (nr < 0)
+		printk(KERN_ERR "Failure reading data from FCU: %d", nw);
+	return nr;
+}
+
+static int fan_write_reg(int reg, const unsigned char *ptr, int nb)
+{
+	int tries, nw;
+	unsigned char buf[16];
+
+	buf[0] = reg;
+	memcpy(buf+1, ptr, nb);
+	++nb;
+	tries = 0;
+	for (;;) {
+		nw = i2c_master_send(fcu, buf, nb);
+		if (nw > 0 || (nw < 0 && nw != EIO) || tries >= 100)
+			break;
+		wait_ms(10);
+		++tries;
+	}
+	if (nw < 0)
+		printk(KERN_ERR "Failure writing to FCU: %d", nw);
+	return nw;
+}
+
+static int set_rpm_fan(int fan, int rpm)
+{
+	unsigned char buf[2];
+	int rc;
+
+	if (rpm < 300)
+		rpm = 300;
+	else if (rpm > 8191)
+		rpm = 8191;
+	buf[0] = rpm >> 5;
+	buf[1] = rpm << 3;
+	rc = fan_write_reg(0x10 + (fan * 2), buf, 2);
+	if (rc < 0)
+		return -EIO;
+	return 0;
+}
+
+static int get_rpm_fan(int fan, int programmed)
+{
+	unsigned char failure;
+	unsigned char active;
+	unsigned char buf[2];
+	int rc, reg_base;
+
+	rc = fan_read_reg(0xb, &failure, 1);
+	if (rc != 1)
+		return -EIO;
+	if ((failure & (1 << fan)) != 0)
+		return -EFAULT;
+	rc = fan_read_reg(0xd, &active, 1);
+	if (rc != 1)
+		return -EIO;
+	if ((active & (1 << fan)) == 0)
+		return -ENXIO;
+
+	/* Programmed value or real current speed */
+	reg_base = programmed ? 0x10 : 0x11;
+	rc = fan_read_reg(reg_base + (fan * 2), buf, 2);
+	if (rc != 2)
+		return -EIO;
+
+	return (buf[0] << 5) | buf[1] >> 3;
+}
+
+static int set_pwm_fan(int fan, int pwm)
+{
+	unsigned char buf[2];
+	int rc;
+
+	if (pwm < 10)
+		pwm = 10;
+	else if (pwm > 100)
+		pwm = 100;
+	pwm = (pwm * 2559) / 1000;
+	buf[0] = pwm;
+	rc = fan_write_reg(0x30 + (fan * 2), buf, 1);
+	if (rc < 0)
+		return rc;
+	return 0;
+}
+
+static int get_pwm_fan(int fan)
+{
+	unsigned char failure;
+	unsigned char active;
+	unsigned char buf[2];
+	int rc;
+
+	rc = fan_read_reg(0x2b, &failure, 1);
+	if (rc != 1)
+		return -EIO;
+	if ((failure & (1 << fan)) != 0)
+		return -EFAULT;
+	rc = fan_read_reg(0x2d, &active, 1);
+	if (rc != 1)
+		return -EIO;
+	if ((active & (1 << fan)) == 0)
+		return -ENXIO;
+
+	/* Programmed value or real current speed */
+	rc = fan_read_reg(0x30 + (fan * 2), buf, 1);
+	if (rc != 1)
+		return -EIO;
+
+	return (buf[0] * 1000) / 2559;
+}
+
+/*
+ * Utility routine to read the CPU calibration EEPROM data
+ * from the device-tree
+ */
+static int read_eeprom(int cpu, struct mpu_data *out)
+{
+	struct device_node *np;
+	char nodename[64];
+	u8 *data;
+	int len;
+
+	/* prom.c routine for finding a node by path is a bit brain dead
+	 * and requires exact @xxx unit numbers. This is a bit ugly but
+	 * will work for these machines
+	 */
+	sprintf(nodename, "/u3@0,f8000000/i2c@f8001000/cpuid@a%d", cpu ? 2 : 0);
+	np = of_find_node_by_path(nodename);
+	if (np == NULL) {
+		printk(KERN_ERR "therm_pm72: Failed to retreive cpuid node from device-tree\n");
+		return -ENODEV;
+	}
+	data = (u8 *)get_property(np, "cpuid", &len);
+	if (data == NULL) {
+		printk(KERN_ERR "therm_pm72: Failed to retreive cpuid property from device-tree\n");
+		of_node_put(np);
+		return -ENODEV;
+	}
+	memcpy(out, data, sizeof(struct mpu_data));
+	of_node_put(np);
+	
+	return 0;
+}
+
+/* 
+ * Now, unfortunately, sysfs doesn't give us a nice void * we could
+ * pass around to the attribute functions, so we don't really have
+ * choice but implement a bunch of them...
+ *
+ * That sucks a bit, we take the lock because FIX32TOPRINT evaluates
+ * the input twice... I accept patches :)
+ */
+#define BUILD_SHOW_FUNC_FIX(name, data)				\
+static ssize_t show_##name(struct device *dev, char *buf)	\
+{								\
+	ssize_t r;						\
+	down(&driver_lock);					\
+	r = sprintf(buf, "%d.%03d", FIX32TOPRINT(data));	\
+	up(&driver_lock);					\
+	return r;						\
+}
+#define BUILD_SHOW_FUNC_INT(name, data)				\
+static ssize_t show_##name(struct device *dev, char *buf)	\
+{								\
+	return sprintf(buf, "%d", data);			\
+}
+
+BUILD_SHOW_FUNC_FIX(cpu0_temperature, cpu_state[0].last_temp)
+BUILD_SHOW_FUNC_FIX(cpu0_voltage, cpu_state[0].voltage)
+BUILD_SHOW_FUNC_FIX(cpu0_current, cpu_state[0].current_a)
+BUILD_SHOW_FUNC_INT(cpu0_exhaust_fan_rpm, cpu_state[0].rpm)
+BUILD_SHOW_FUNC_INT(cpu0_intake_fan_rpm, cpu_state[0].intake_rpm)
+
+BUILD_SHOW_FUNC_FIX(cpu1_temperature, cpu_state[1].last_temp)
+BUILD_SHOW_FUNC_FIX(cpu1_voltage, cpu_state[1].voltage)
+BUILD_SHOW_FUNC_FIX(cpu1_current, cpu_state[1].current_a)
+BUILD_SHOW_FUNC_INT(cpu1_exhaust_fan_rpm, cpu_state[1].rpm)
+BUILD_SHOW_FUNC_INT(cpu1_intake_fan_rpm, cpu_state[1].intake_rpm)
+
+BUILD_SHOW_FUNC_FIX(backside_temperature, backside_state.last_temp)
+BUILD_SHOW_FUNC_INT(backside_fan_pwm, backside_state.pwm)
+
+BUILD_SHOW_FUNC_FIX(drives_temperature, drives_state.last_temp)
+BUILD_SHOW_FUNC_INT(drives_fan_rpm, drives_state.rpm)
+
+static DEVICE_ATTR(cpu0_temperature,S_IRUGO,show_cpu0_temperature,NULL);
+static DEVICE_ATTR(cpu0_voltage,S_IRUGO,show_cpu0_voltage,NULL);
+static DEVICE_ATTR(cpu0_current,S_IRUGO,show_cpu0_current,NULL);
+static DEVICE_ATTR(cpu0_exhaust_fan_rpm,S_IRUGO,show_cpu0_exhaust_fan_rpm,NULL);
+static DEVICE_ATTR(cpu0_intake_fan_rpm,S_IRUGO,show_cpu0_intake_fan_rpm,NULL);
+
+static DEVICE_ATTR(cpu1_temperature,S_IRUGO,show_cpu1_temperature,NULL);
+static DEVICE_ATTR(cpu1_voltage,S_IRUGO,show_cpu1_voltage,NULL);
+static DEVICE_ATTR(cpu1_current,S_IRUGO,show_cpu1_current,NULL);
+static DEVICE_ATTR(cpu1_exhaust_fan_rpm,S_IRUGO,show_cpu1_exhaust_fan_rpm,NULL);
+static DEVICE_ATTR(cpu1_intake_fan_rpm,S_IRUGO,show_cpu1_intake_fan_rpm,NULL);
+
+static DEVICE_ATTR(backside_temperature,S_IRUGO,show_backside_temperature,NULL);
+static DEVICE_ATTR(backside_fan_pwm,S_IRUGO,show_backside_fan_pwm,NULL);
+
+static DEVICE_ATTR(drives_temperature,S_IRUGO,show_drives_temperature,NULL);
+static DEVICE_ATTR(drives_fan_rpm,S_IRUGO,show_drives_fan_rpm,NULL);
+
+/*
+ * CPUs fans control loop
+ */
+static void do_monitor_cpu(struct cpu_pid_state *state)
+{
+	s32 temp, voltage, current_a, power, power_target;
+	s32 integral, derivative, proportional, adj_in_target, sval;
+	s64 integ_p, deriv_p, prop_p, sum; 
+	int i, intake, rc;
+
+	DBG("cpu %d:\n", state->index);
+
+	/* Read current fan status */
+	if (state->index == 0)
+		rc = get_rpm_fan(CPUA_EXHAUST_FAN_RPM_ID, !RPM_PID_USE_ACTUAL_SPEED);
+	else
+		rc = get_rpm_fan(CPUB_EXHAUST_FAN_RPM_ID, !RPM_PID_USE_ACTUAL_SPEED);
+	if (rc < 0) {
+		printk(KERN_WARNING "Error %d reading CPU %d exhaust fan !\n",
+		       rc, state->index);
+		/* XXX What do we do now ? */
+	} else
+		state->rpm = rc;
+	DBG("  current rpm: %d\n", state->rpm);
+
+	/* Get some sensor readings and scale it */
+	temp = read_smon_adc(state->monitor, 1);
+	voltage = read_smon_adc(state->monitor, 3);
+	current_a = read_smon_adc(state->monitor, 4);
+
+	/* Fixup temperature according to diode calibration
+	 */
+	DBG("  temp raw: %04x, m_diode: %04x, b_diode: %04x\n",
+	    temp, state->mpu.mdiode, state->mpu.bdiode);
+	temp = (temp * state->mpu.mdiode + (state->mpu.bdiode << 12)) >> 2;
+	state->last_temp = temp;
+	DBG("  temp: %d.%03d\n", FIX32TOPRINT(temp));
+
+	/* Check tmax, increment overtemp if we are there. At tmax+8, we go
+	 * full blown immediately and try to trigger a shutdown
+	 */
+	if (temp >= ((state->mpu.tmax + 8) << 16)) {
+		printk(KERN_WARNING "Warning ! CPU %d temperature way above maximum !\n",
+		       state->index);
+		state->overtemp = CPU_MAX_OVERTEMP;
+	} else if (temp > (state->mpu.tmax << 16))
+		state->overtemp++;
+	else
+		state->overtemp = 0;
+	if (state->overtemp >= CPU_MAX_OVERTEMP)
+		critical_state = 1;
+	if (state->overtemp > 0) {
+		state->rpm = state->mpu.rmaxn_exhaust_fan;
+		state->intake_rpm = intake = state->mpu.rmaxn_intake_fan;
+		goto do_set_fans;
+	}
+	
+	/* Scale other sensor values according to fixed scales
+	 * obtained in Darwin and calculate power from I and V
+	 */
+	state->voltage = voltage *= ADC_CPU_VOLTAGE_SCALE;
+	state->current_a = current_a *= ADC_CPU_CURRENT_SCALE;
+	power = (((u64)current_a) * ((u64)voltage)) >> 16;
+
+	/* Calculate power target value (could be done once for all)
+	 * and convert to a 16.16 fp number
+	 */
+	power_target = ((u32)(state->mpu.pmaxh - state->mpu.padjmax)) << 16;
+
+	DBG("  current: %d.%03d, voltage: %d.%03d\n",
+	    FIX32TOPRINT(current_a), FIX32TOPRINT(voltage));
+	DBG("  power: %d.%03d W, target: %d.%03d, error: %d.%03d\n", FIX32TOPRINT(power),
+	    FIX32TOPRINT(power_target), FIX32TOPRINT(power_target - power));
+
+	/* Store temperature and power in history array */
+	state->cur_temp = (state->cur_temp + 1) % CPU_TEMP_HISTORY_SIZE;
+	state->temp_history[state->cur_temp] = temp;
+	state->cur_power = (state->cur_power + 1) % state->count_power;
+	state->power_history[state->cur_power] = power;
+	state->error_history[state->cur_power] = power_target - power;
+	
+	/* If first loop, fill the history table */
+	if (state->first) {
+		for (i = 0; i < (state->count_power - 1); i++) {
+			state->cur_power = (state->cur_power + 1) % state->count_power;
+			state->power_history[state->cur_power] = power;
+			state->error_history[state->cur_power] = power_target - power;
+		}
+		for (i = 0; i < (CPU_TEMP_HISTORY_SIZE - 1); i++) {
+			state->cur_temp = (state->cur_temp + 1) % CPU_TEMP_HISTORY_SIZE;
+			state->temp_history[state->cur_temp] = temp;			
+		}
+		state->first = 0;
+	}
+
+	/* Calculate the integral term normally based on the "power" values */
+	sum = 0;
+	integral = 0;
+	for (i = 0; i < state->count_power; i++)
+		integral += state->error_history[i];
+	integral *= CPU_PID_INTERVAL;
+	DBG("  integral: %08x\n", integral);
+
+	/* Calculate the adjusted input (sense value).
+	 *   G_r is 12.20
+	 *   integ is 16.16
+	 *   so the result is 28.36
+	 *
+	 * input target is mpu.ttarget, input max is mpu.tmax
+	 */
+	integ_p = ((s64)state->mpu.pid_gr) * (s64)integral;
+	DBG("   integ_p: %d\n", (int)(deriv_p >> 36));
+	sval = (state->mpu.tmax << 16) - ((integ_p >> 20) & 0xffffffff);
+	adj_in_target = (state->mpu.ttarget << 16);
+	if (adj_in_target > sval)
+		adj_in_target = sval;
+	DBG("   adj_in_target: %d.%03d, ttarget: %d\n", FIX32TOPRINT(adj_in_target),
+	    state->mpu.ttarget);
+
+	/* Calculate the derivative term */
+	derivative = state->temp_history[state->cur_temp] -
+		state->temp_history[(state->cur_temp + CPU_TEMP_HISTORY_SIZE - 1)
+				    % CPU_TEMP_HISTORY_SIZE];
+	derivative /= CPU_PID_INTERVAL;
+	deriv_p = ((s64)state->mpu.pid_gd) * (s64)derivative;
+	DBG("   deriv_p: %d\n", (int)(deriv_p >> 36));
+	sum += deriv_p;
+
+	/* Calculate the proportional term */
+	proportional = temp - adj_in_target;
+	prop_p = ((s64)state->mpu.pid_gp) * (s64)proportional;
+	DBG("   prop_p: %d\n", (int)(prop_p >> 36));
+	sum += prop_p;
+
+	/* Scale sum */
+	sum >>= 36;
+
+	DBG("   sum: %d\n", (int)sum);
+	state->rpm += (s32)sum;
+
+	if (state->rpm < state->mpu.rminn_exhaust_fan)
+		state->rpm = state->mpu.rminn_exhaust_fan;
+	if (state->rpm > state->mpu.rmaxn_exhaust_fan)
+		state->rpm = state->mpu.rmaxn_exhaust_fan;
+
+	intake = (state->rpm * CPU_INTAKE_SCALE) >> 16;
+	if (intake < state->mpu.rminn_intake_fan)
+		intake = state->mpu.rminn_intake_fan;
+	if (intake > state->mpu.rmaxn_intake_fan)
+		intake = state->mpu.rmaxn_intake_fan;
+	state->intake_rpm = intake;
+
+ do_set_fans:
+	DBG("** CPU %d RPM: %d Ex, %d In, overtemp: %d\n",
+	    state->index, (int)state->rpm, intake, state->overtemp);
+
+	/* We should check for errors, shouldn't we ? But then, what
+	 * do we do once the error occurs ? For FCU notified fan
+	 * failures (-EFAULT) we probably want to notify userland
+	 * some way...
+	 */
+	if (state->index == 0) {
+		set_rpm_fan(CPUA_INTAKE_FAN_RPM_ID, intake);
+		set_rpm_fan(CPUA_EXHAUST_FAN_RPM_ID, state->rpm);
+	} else {
+		set_rpm_fan(CPUB_INTAKE_FAN_RPM_ID, intake);
+		set_rpm_fan(CPUB_EXHAUST_FAN_RPM_ID, state->rpm);
+	}
+}
+
+/*
+ * Initialize the state structure for one CPU control loop
+ */
+static int init_cpu_state(struct cpu_pid_state *state, int index)
+{
+	state->index = index;
+	state->first = 1;
+	state->rpm = 1000;
+	state->overtemp = 0;
+
+	if (index == 0)
+		state->monitor = attach_i2c_chip(SUPPLY_MONITOR_ID, "CPU0_monitor");
+	else if (index == 1)
+		state->monitor = attach_i2c_chip(SUPPLY_MONITORB_ID, "CPU1_monitor");
+	if (state->monitor == NULL)
+		goto fail;
+
+	if (read_eeprom(index, &state->mpu))
+		goto fail;
+
+	state->count_power = state->mpu.tguardband;
+	if (state->count_power > CPU_POWER_HISTORY_SIZE) {
+		printk(KERN_WARNING "Warning ! too many power history slots\n");
+		state->count_power = CPU_POWER_HISTORY_SIZE;
+	}
+	DBG("CPU %d Using %d power history entries\n", index, state->count_power);
+
+	if (index == 0) {
+		device_create_file(&of_dev->dev, &dev_attr_cpu0_temperature);
+		device_create_file(&of_dev->dev, &dev_attr_cpu0_voltage);
+		device_create_file(&of_dev->dev, &dev_attr_cpu0_current);
+		device_create_file(&of_dev->dev, &dev_attr_cpu0_exhaust_fan_rpm);
+		device_create_file(&of_dev->dev, &dev_attr_cpu0_intake_fan_rpm);
+	} else {
+		device_create_file(&of_dev->dev, &dev_attr_cpu1_temperature);
+		device_create_file(&of_dev->dev, &dev_attr_cpu1_voltage);
+		device_create_file(&of_dev->dev, &dev_attr_cpu1_current);
+		device_create_file(&of_dev->dev, &dev_attr_cpu1_exhaust_fan_rpm);
+		device_create_file(&of_dev->dev, &dev_attr_cpu1_intake_fan_rpm);
+	}
+
+	return 0;
+ fail:
+	if (state->monitor)
+		detach_i2c_chip(state->monitor);
+	state->monitor = NULL;
+	
+	return -ENODEV;
+}
+
+/*
+ * Dispose of the state data for one CPU control loop
+ */
+static void dispose_cpu_state(struct cpu_pid_state *state)
+{
+	if (state->monitor == NULL)
+		return;
+
+	if (state->index == 0) {
+		device_remove_file(&of_dev->dev, &dev_attr_cpu0_temperature);
+		device_remove_file(&of_dev->dev, &dev_attr_cpu0_voltage);
+		device_remove_file(&of_dev->dev, &dev_attr_cpu0_current);
+		device_remove_file(&of_dev->dev, &dev_attr_cpu0_exhaust_fan_rpm);
+		device_remove_file(&of_dev->dev, &dev_attr_cpu0_intake_fan_rpm);
+	} else {
+		device_remove_file(&of_dev->dev, &dev_attr_cpu1_temperature);
+		device_remove_file(&of_dev->dev, &dev_attr_cpu1_voltage);
+		device_remove_file(&of_dev->dev, &dev_attr_cpu1_current);
+		device_remove_file(&of_dev->dev, &dev_attr_cpu1_exhaust_fan_rpm);
+		device_remove_file(&of_dev->dev, &dev_attr_cpu1_intake_fan_rpm);
+	}
+
+	detach_i2c_chip(state->monitor);
+	state->monitor = NULL;
+}
+
+/*
+ * Motherboard backside & U3 heatsink fan control loop
+ */
+static void do_monitor_backside(struct backside_pid_state *state)
+{
+	s32 temp, integral, derivative;
+	s64 integ_p, deriv_p, prop_p, sum; 
+	int i, rc;
+
+	if (--state->ticks != 0)
+		return;
+	state->ticks = BACKSIDE_PID_INTERVAL;
+
+	DBG("backside:\n");
+
+	/* Check fan status */
+	rc = get_pwm_fan(BACKSIDE_FAN_PWM_ID);
+	if (rc < 0) {
+		printk(KERN_WARNING "Error %d reading backside fan !\n", rc);
+		/* XXX What do we do now ? */
+	} else
+		state->pwm = rc;
+	DBG("  current pwm: %d\n", state->pwm);
+
+	/* Get some sensor readings */
+	temp = i2c_smbus_read_byte_data(state->monitor, MAX6690_EXT_TEMP) << 16;
+	state->last_temp = temp;
+	DBG("  temp: %d.%03d, target: %d.%03d\n", FIX32TOPRINT(temp),
+	    FIX32TOPRINT(BACKSIDE_PID_INPUT_TARGET));
+
+	/* Store temperature and error in history array */
+	state->cur_sample = (state->cur_sample + 1) % BACKSIDE_PID_HISTORY_SIZE;
+	state->sample_history[state->cur_sample] = temp;
+	state->error_history[state->cur_sample] = temp - BACKSIDE_PID_INPUT_TARGET;
+	
+	/* If first loop, fill the history table */
+	if (state->first) {
+		for (i = 0; i < (BACKSIDE_PID_HISTORY_SIZE - 1); i++) {
+			state->cur_sample = (state->cur_sample + 1) %
+				BACKSIDE_PID_HISTORY_SIZE;
+			state->sample_history[state->cur_sample] = temp;
+			state->error_history[state->cur_sample] =
+				temp - BACKSIDE_PID_INPUT_TARGET;
+		}
+		state->first = 0;
+	}
+
+	/* Calculate the integral term */
+	sum = 0;
+	integral = 0;
+	for (i = 0; i < BACKSIDE_PID_HISTORY_SIZE; i++)
+		integral += state->error_history[i];
+	integral *= BACKSIDE_PID_INTERVAL;
+	DBG("  integral: %08x\n", integral);
+	integ_p = ((s64)BACKSIDE_PID_G_r) * (s64)integral;
+	DBG("   integ_p: %d\n", (int)(integ_p >> 36));
+	sum += integ_p;
+
+	/* Calculate the derivative term */
+	derivative = state->error_history[state->cur_sample] -
+		state->error_history[(state->cur_sample + BACKSIDE_PID_HISTORY_SIZE - 1)
+				    % BACKSIDE_PID_HISTORY_SIZE];
+	derivative /= BACKSIDE_PID_INTERVAL;
+	deriv_p = ((s64)BACKSIDE_PID_G_d) * (s64)derivative;
+	DBG("   deriv_p: %d\n", (int)(deriv_p >> 36));
+	sum += deriv_p;
+
+	/* Calculate the proportional term */
+	prop_p = ((s64)BACKSIDE_PID_G_p) * (s64)(state->error_history[state->cur_sample]);
+	DBG("   prop_p: %d\n", (int)(prop_p >> 36));
+	sum += prop_p;
+
+	/* Scale sum */
+	sum >>= 36;
+
+	DBG("   sum: %d\n", (int)sum);
+	state->pwm += (s32)sum;
+	if (state->pwm < BACKSIDE_PID_OUTPUT_MIN)
+		state->pwm = BACKSIDE_PID_OUTPUT_MIN;
+	if (state->pwm > BACKSIDE_PID_OUTPUT_MAX)
+		state->pwm = BACKSIDE_PID_OUTPUT_MAX;
+
+	DBG("** BACKSIDE PWM: %d\n", (int)state->pwm);
+	set_pwm_fan(BACKSIDE_FAN_PWM_ID, state->pwm);
+}
+
+/*
+ * Initialize the state structure for the backside fan control loop
+ */
+static int init_backside_state(struct backside_pid_state *state)
+{
+	state->ticks = 1;
+	state->first = 1;
+	state->pwm = 50;
+
+	state->monitor = attach_i2c_chip(BACKSIDE_MAX_ID, "backside_temp");
+	if (state->monitor == NULL)
+		return -ENODEV;
+
+	device_create_file(&of_dev->dev, &dev_attr_backside_temperature);
+	device_create_file(&of_dev->dev, &dev_attr_backside_fan_pwm);
+
+	return 0;
+}
+
+/*
+ * Dispose of the state data for the backside control loop
+ */
+static void dispose_backside_state(struct backside_pid_state *state)
+{
+	if (state->monitor == NULL)
+		return;
+
+	device_remove_file(&of_dev->dev, &dev_attr_backside_temperature);
+	device_remove_file(&of_dev->dev, &dev_attr_backside_fan_pwm);
+
+	detach_i2c_chip(state->monitor);
+	state->monitor = NULL;
+}
+ 
+/*
+ * Drives bay fan control loop
+ */
+static void do_monitor_drives(struct drives_pid_state *state)
+{
+	s32 temp, integral, derivative;
+	s64 integ_p, deriv_p, prop_p, sum; 
+	int i, rc;
+
+	if (--state->ticks != 0)
+		return;
+	state->ticks = DRIVES_PID_INTERVAL;
+
+	DBG("drives:\n");
+
+	/* Check fan status */
+	rc = get_rpm_fan(DRIVES_FAN_RPM_ID, !RPM_PID_USE_ACTUAL_SPEED);
+	if (rc < 0) {
+		printk(KERN_WARNING "Error %d reading drives fan !\n", rc);
+		/* XXX What do we do now ? */
+	} else
+		state->rpm = rc;
+	DBG("  current rpm: %d\n", state->rpm);
+
+	/* Get some sensor readings */
+	temp = le16_to_cpu(i2c_smbus_read_word_data(state->monitor, DS1775_TEMP)) << 8;
+	state->last_temp = temp;
+	DBG("  temp: %d.%03d, target: %d.%03d\n", FIX32TOPRINT(temp),
+	    FIX32TOPRINT(DRIVES_PID_INPUT_TARGET));
+
+	/* Store temperature and error in history array */
+	state->cur_sample = (state->cur_sample + 1) % DRIVES_PID_HISTORY_SIZE;
+	state->sample_history[state->cur_sample] = temp;
+	state->error_history[state->cur_sample] = temp - DRIVES_PID_INPUT_TARGET;
+	
+	/* If first loop, fill the history table */
+	if (state->first) {
+		for (i = 0; i < (DRIVES_PID_HISTORY_SIZE - 1); i++) {
+			state->cur_sample = (state->cur_sample + 1) %
+				DRIVES_PID_HISTORY_SIZE;
+			state->sample_history[state->cur_sample] = temp;
+			state->error_history[state->cur_sample] =
+				temp - DRIVES_PID_INPUT_TARGET;
+		}
+		state->first = 0;
+	}
+
+	/* Calculate the integral term */
+	sum = 0;
+	integral = 0;
+	for (i = 0; i < DRIVES_PID_HISTORY_SIZE; i++)
+		integral += state->error_history[i];
+	integral *= DRIVES_PID_INTERVAL;
+	DBG("  integral: %08x\n", integral);
+	integ_p = ((s64)DRIVES_PID_G_r) * (s64)integral;
+	DBG("   integ_p: %d\n", (int)(integ_p >> 36));
+	sum += integ_p;
+
+	/* Calculate the derivative term */
+	derivative = state->error_history[state->cur_sample] -
+		state->error_history[(state->cur_sample + DRIVES_PID_HISTORY_SIZE - 1)
+				    % DRIVES_PID_HISTORY_SIZE];
+	derivative /= DRIVES_PID_INTERVAL;
+	deriv_p = ((s64)DRIVES_PID_G_d) * (s64)derivative;
+	DBG("   deriv_p: %d\n", (int)(deriv_p >> 36));
+	sum += deriv_p;
+
+	/* Calculate the proportional term */
+	prop_p = ((s64)DRIVES_PID_G_p) * (s64)(state->error_history[state->cur_sample]);
+	DBG("   prop_p: %d\n", (int)(prop_p >> 36));
+	sum += prop_p;
+
+	/* Scale sum */
+	sum >>= 36;
+
+	DBG("   sum: %d\n", (int)sum);
+	state->rpm += (s32)sum;
+	if (state->rpm < DRIVES_PID_OUTPUT_MIN)
+		state->rpm = DRIVES_PID_OUTPUT_MIN;
+	if (state->rpm > DRIVES_PID_OUTPUT_MAX)
+		state->rpm = DRIVES_PID_OUTPUT_MAX;
+
+	DBG("** DRIVES RPM: %d\n", (int)state->rpm);
+	set_rpm_fan(DRIVES_FAN_RPM_ID, state->rpm);
+}
+
+/*
+ * Initialize the state structure for the drives bay fan control loop
+ */
+static int init_drives_state(struct drives_pid_state *state)
+{
+	state->ticks = 1;
+	state->first = 1;
+	state->rpm = 1000;
+
+	state->monitor = attach_i2c_chip(DRIVES_DALLAS_ID, "drives_temp");
+	if (state->monitor == NULL)
+		return -ENODEV;
+
+	device_create_file(&of_dev->dev, &dev_attr_drives_temperature);
+	device_create_file(&of_dev->dev, &dev_attr_drives_fan_rpm);
+
+	return 0;
+}
+
+/*
+ * Dispose of the state data for the drives control loop
+ */
+static void dispose_drives_state(struct drives_pid_state *state)
+{
+	if (state->monitor == NULL)
+		return;
+
+	device_remove_file(&of_dev->dev, &dev_attr_drives_temperature);
+	device_remove_file(&of_dev->dev, &dev_attr_drives_fan_rpm);
+
+	detach_i2c_chip(state->monitor);
+	state->monitor = NULL;
+}
+
+static int call_critical_overtemp(void)
+{
+	char *argv[] = { critical_overtemp_path, NULL };
+	static char *envp[] = { "HOME=/",
+				"TERM=linux",
+				"PATH=/sbin:/usr/sbin:/bin:/usr/bin",
+				NULL };
+
+	return call_usermodehelper(critical_overtemp_path, argv, envp, 0);
+}
+
+
+/*
+ * Here's the kernel thread that calls the various control loops
+ */
+static int main_control_loop(void *x)
+{
+	daemonize("kfand");
+
+	DBG("main_control_loop started\n");
+
+	/* Set the PCI fan once for now */
+	set_pwm_fan(SLOTS_FAN_PWM_ID, SLOTS_FAN_DEFAULT_PWM);
+
+	while (state == state_attached) {
+		unsigned long elapsed, start;
+
+		start = jiffies;
+
+		down(&driver_lock);
+		do_monitor_cpu(&cpu_state[0]);
+		if (cpu_state[1].monitor != NULL)
+			do_monitor_cpu(&cpu_state[1]);
+		do_monitor_backside(&backside_state);
+		do_monitor_drives(&drives_state);
+		up(&driver_lock);
+
+		if (critical_state == 1) {
+			printk(KERN_WARNING "Temperature control detected a critical condition\n");
+			printk(KERN_WARNING "Attempting to shut down...\n");
+			if (call_critical_overtemp()) {
+				printk(KERN_WARNING "Can't call %s, power off now!\n",
+				       critical_overtemp_path);
+				machine_power_off();
+			}
+		}
+		if (critical_state > 0)
+			critical_state++;
+		if (critical_state > MAX_CRITICAL_STATE) {
+			printk(KERN_WARNING "Shutdown timed out, power off now !\n");
+			machine_power_off();
+		}
+
+		// FIXME: Deal with signals
+		set_current_state(TASK_INTERRUPTIBLE);
+		elapsed = jiffies - start;
+		if (elapsed < HZ)
+			schedule_timeout(HZ - elapsed);
+	}
+
+	DBG("main_control_loop ended\n");
+
+	ctrl_task = 0;
+	complete_and_exit(&ctrl_complete, 0);
+}
+
+/*
+ * Dispose the control loops when tearing down
+ */
+static void dispose_control_loops(void)
+{
+	dispose_cpu_state(&cpu_state[0]);
+	dispose_cpu_state(&cpu_state[1]);
+
+	dispose_backside_state(&backside_state);
+	dispose_drives_state(&drives_state);
+}
+
+/*
+ * Create the control loops. U3-0 i2c bus is up, so we can now
+ * get to the various sensors
+ */
+static int create_control_loops(void)
+{
+	struct device_node *np;
+
+	/* Count CPUs from the device-tree, we don't care how many are
+	 * actually used by Linux
+	 */
+	cpu_count = 0;
+	for (np = NULL; NULL != (np = of_find_node_by_type(np, "cpu"));)
+		cpu_count++;
+
+	DBG("counted %d CPUs in the device-tree\n", cpu_count);
+
+	/* Create control loops for everything. If any fail, everything
+	 * fails
+	 */
+	if (init_cpu_state(&cpu_state[0], 0))
+		goto fail;
+	if (cpu_count > 1 && init_cpu_state(&cpu_state[1], 1))
+		goto fail;
+	if (init_backside_state(&backside_state))
+		goto fail;
+	if (init_drives_state(&drives_state))
+		goto fail;
+
+	DBG("all control loops up !\n");
+
+	return 0;
+	
+ fail:
+	DBG("failure creating control loops, disposing\n");
+
+	dispose_control_loops();
+
+	return -ENODEV;
+}
+
+/*
+ * Start the control loops after everything is up, that is create
+ * the thread that will make them run
+ */
+static void start_control_loops(void)
+{
+	init_completion(&ctrl_complete);
+
+	ctrl_task = kernel_thread(main_control_loop, NULL, SIGCHLD | CLONE_KERNEL);
+}
+
+/*
+ * Stop the control loops when tearing down
+ */
+static void stop_control_loops(void)
+{
+	if (ctrl_task != 0)
+		wait_for_completion(&ctrl_complete);
+}
+
+/*
+ * Attach to the i2c FCU after detecting U3-1 bus
+ */
+static int attach_fcu(void)
+{
+	fcu = attach_i2c_chip(FAN_CTRLER_ID, "fcu");
+	if (fcu == NULL)
+		return -ENODEV;
+
+	DBG("FCU attached\n");
+
+	return 0;
+}
+
+/*
+ * Detach from the i2c FCU when tearing down
+ */
+static void detach_fcu(void)
+{
+	if (fcu)
+		detach_i2c_chip(fcu);
+	fcu = NULL;
+}
+
+/*
+ * Attach to the i2c controller. We probe the various chips based
+ * on the device-tree nodes and build everything for the driver to
+ * run, we then kick the driver monitoring thread
+ */
+static int therm_pm72_attach(struct i2c_adapter *adapter)
+{
+	down(&driver_lock);
+
+	/* Check state */
+	if (state == state_detached)
+		state = state_attaching;
+	if (state != state_attaching) {
+		up(&driver_lock);
+		return 0;
+	}
+
+	/* Check if we are looking for one of these */
+	if (u3_0 == NULL && !strcmp(adapter->name, "u3 0")) {
+		u3_0 = adapter;
+		DBG("found U3-0, creating control loops\n");
+		if (create_control_loops())
+			u3_0 = NULL;
+	} else if (u3_1 == NULL && !strcmp(adapter->name, "u3 1")) {
+		u3_1 = adapter;
+		DBG("found U3-1, attaching FCU\n");
+		if (attach_fcu())
+			u3_1 = NULL;
+	}
+	/* We got all we need, start control loops */
+	if (u3_0 != NULL && u3_1 != NULL) {
+		DBG("everything up, starting control loops\n");
+		state = state_attached;
+		start_control_loops();
+	}
+	up(&driver_lock);
+
+	return 0;
+}
+
+/*
+ * Called on every adapter when the driver or the i2c controller
+ * is going away.
+ */
+static int therm_pm72_detach(struct i2c_adapter *adapter)
+{
+	down(&driver_lock);
+
+	if (state != state_detached)
+		state = state_detaching;
+
+	/* Stop control loops if any */
+	DBG("stopping control loops\n");
+	up(&driver_lock);
+	stop_control_loops();
+	down(&driver_lock);
+
+	if (u3_0 != NULL && !strcmp(adapter->name, "u3 0")) {
+		DBG("lost U3-0, disposing control loops\n");
+		dispose_control_loops();
+		u3_0 = NULL;
+	}
+	
+	if (u3_1 != NULL && !strcmp(adapter->name, "u3 1")) {
+		DBG("lost U3-1, detaching FCU\n");
+		detach_fcu();
+		u3_1 = NULL;
+	}
+	if (u3_0 == NULL && u3_1 == NULL)
+		state = state_detached;
+
+	up(&driver_lock);
+
+	return 0;
+}
+
+static int fcu_of_probe(struct of_device* dev, const struct of_match *match)
+{
+	int rc;
+
+	state = state_detached;
+
+	rc = i2c_add_driver(&therm_pm72_driver);
+	if (rc < 0)
+		return rc;
+	return 0;
+}
+
+static int fcu_of_remove(struct of_device* dev)
+{
+	i2c_del_driver(&therm_pm72_driver);
+
+	return 0;
+}
+
+static struct of_match fcu_of_match[] = 
+{
+	{
+	.name 		= OF_ANY_MATCH,
+	.type		= "fcu",
+	.compatible	= OF_ANY_MATCH
+	},
+	{},
+};
+
+static struct of_platform_driver fcu_of_platform_driver = 
+{
+	.name 		= "temperature",
+	.match_table	= fcu_of_match,
+	.probe		= fcu_of_probe,
+	.remove		= fcu_of_remove
+};
+
+/*
+ * Check machine type, attach to i2c controller
+ */
+static int __init therm_pm72_init(void)
+{
+	struct device_node *np;
+
+	if (!machine_is_compatible("PowerMac7,2"))
+	    	return -ENODEV;
+
+	printk(KERN_INFO "PowerMac G5 Thermal control driver %s\n", VERSION);
+
+	np = of_find_node_by_type(NULL, "fcu");
+	if (np == NULL) {
+		printk(KERN_ERR "Can't find FCU in device-tree !\n");
+		return -ENODEV;
+	}
+	of_dev = of_platform_device_create(np, "temperature");
+	if (of_dev == NULL) {
+		printk(KERN_ERR "Can't register FCU platform device !\n");
+		return -ENODEV;
+	}
+
+	of_register_driver(&fcu_of_platform_driver);
+	
+	return 0;
+}
+
+static void __exit therm_pm72_exit(void)
+{
+	of_unregister_driver(&fcu_of_platform_driver);
+
+	if (of_dev)
+		of_device_unregister(of_dev);
+}
+
+module_init(therm_pm72_init);
+module_exit(therm_pm72_exit);
+
+MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
+MODULE_DESCRIPTION("Driver for Apple's PowerMac7,2 G5 thermal control");
+MODULE_LICENSE("GPL");
+
diff -puN /dev/null drivers/macintosh/therm_pm72.h
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/macintosh/therm_pm72.h	2004-01-28 23:09:16.000000000 -0800
@@ -0,0 +1,236 @@
+#ifndef __THERM_PMAC_7_2_H__
+#define __THERM_PMAC_7_2_H__
+
+typedef unsigned short fu16;
+typedef int fs32;
+typedef short fs16;
+
+struct mpu_data
+{
+	u8	signature;		/* 0x00 - EEPROM sig. */
+	u8	bytes_used;		/* 0x01 - Bytes used in eeprom (160 ?) */
+	u8	size;			/* 0x02 - EEPROM size (256 ?) */
+	u8	version;		/* 0x03 - EEPROM version */
+	u32	data_revision;		/* 0x04 - Dataset revision */
+	u8	processor_bin_code[3];	/* 0x08 - Processor BIN code */
+	u8	bin_code_expansion;	/* 0x0b - ??? (padding ?) */
+	u8	processor_num;		/* 0x0c - Number of CPUs on this MPU */
+	u8	input_mul_bus_div;	/* 0x0d - Clock input multiplier/bus divider */
+	u8	reserved1[2];		/* 0x0e - */
+	u32	input_clk_freq_high;	/* 0x10 - Input clock frequency high */
+	u8	cpu_nb_target_cycles;	/* 0x14 - ??? */
+	u8	cpu_statlat;		/* 0x15 - ??? */
+	u8	cpu_snooplat;		/* 0x16 - ??? */
+	u8	cpu_snoopacc;		/* 0x17 - ??? */
+	u8	nb_paamwin;		/* 0x18 - ??? */
+	u8	nb_statlat;		/* 0x19 - ??? */
+	u8	nb_snooplat;		/* 0x1a - ??? */
+	u8	nb_snoopwin;		/* 0x1b - ??? */
+	u8	api_bus_mode;		/* 0x1c - ??? */
+	u8	reserved2[3];		/* 0x1d - */
+	u32	input_clk_freq_low;	/* 0x20 - Input clock frequency low */
+	u8	processor_card_slot;	/* 0x24 - Processor card slot number */
+	u8	reserved3[2];		/* 0x25 - */
+	u8	padjmax;       		/* 0x27 - Max power adjustment (Not in OF!) */
+	u8	ttarget;		/* 0x28 - Target temperature */
+	u8	tmax;			/* 0x29 - Max temperature */
+	u8	pmaxh;			/* 0x2a - Max power */
+	u8	tguardband;		/* 0x2b - Guardband temp ??? Hist. len in OSX */
+	fs32	pid_gp;			/* 0x2c - PID proportional gain */
+	fs32	pid_gr;			/* 0x30 - PID reset gain */
+	fs32	pid_gd;			/* 0x34 - PID derivative gain */
+	fu16	voph;			/* 0x38 - Vop High */
+	fu16	vopl;			/* 0x3a - Vop Low */
+	fs16	nactual_die;		/* 0x3c - nActual Die */
+	fs16	nactual_heatsink;	/* 0x3e - nActual Heatsink */
+	fs16	nactual_system;		/* 0x40 - nActual System */
+	u16	calibration_flags;	/* 0x42 - Calibration flags */
+	fu16	mdiode;			/* 0x44 - Diode M value (scaling factor) */
+	fs16	bdiode;			/* 0x46 - Diode B value (offset) */
+	fs32	theta_heat_sink;	/* 0x48 - Theta heat sink */
+	u16	rminn_intake_fan;	/* 0x4c - Intake fan min RPM */
+	u16	rmaxn_intake_fan;	/* 0x4e - Intake fan max RPM */
+	u16	rminn_exhaust_fan;	/* 0x50 - Exhaust fan min RPM */
+	u16	rmaxn_exhaust_fan;	/* 0x52 - Exhaust fan max RPM */
+	u8	processor_part_num[8];	/* 0x54 - Processor part number */
+	u32	processor_lot_num;	/* 0x5c - Processor lot number */
+	u8	orig_card_sernum[0x10];	/* 0x60 - Card original serial number */
+	u8	curr_card_sernum[0x10];	/* 0x70 - Card current serial number */
+	u8	mlb_sernum[0x18];	/* 0x80 - MLB serial number */
+	u32	checksum1;		/* 0x98 - */
+	u32	checksum2;		/* 0x9c - */	
+}; /* Total size = 0xa0 */
+
+/* Display a 16.16 fixed point value */
+#define FIX32TOPRINT(f)	((f) >> 16),((((f) & 0xffff) * 1000) >> 16)
+
+/*
+ * Maximum number of seconds to be in critical state (after a
+ * normal shutdown attempt). If the machine isn't down after
+ * this counter elapses, we force an immediate machine power
+ * off.
+ */
+#define MAX_CRITICAL_STATE			30
+static char * critical_overtemp_path = "/sbin/critical_overtemp";
+
+/*
+ * This option is "weird" :) Basically, if you define this to 1
+ * the control loop for the RPMs fans (not PWMs) will apply the
+ * correction factor obtained from the PID to the _actual_ RPM
+ * speed read from the FCU.
+ * If you define the below constant to 0, then it will be
+ * applied to the setpoint RPM speed, that is basically the
+ * speed we proviously "asked" for.
+ *
+ * I'm not sure which of these Apple's algorithm is supposed
+ * to use
+ */
+#define RPM_PID_USE_ACTUAL_SPEED		1
+
+/*
+ * i2c IDs. Currently, we hard code those and assume that
+ * the FCU is on U3 bus 1 while all sensors are on U3 bus
+ * 0. This appear to be safe enough for this first version
+ * of the driver, though I would accept any clean patch
+ * doing a better use of the device-tree without turning the
+ * while i2c registration mecanism into a racy mess
+ */
+#define FAN_CTRLER_ID		0x15e
+#define SUPPLY_MONITOR_ID      	0x58
+#define SUPPLY_MONITORB_ID     	0x5a
+#define DRIVES_DALLAS_ID	0x94
+#define BACKSIDE_MAX_ID		0x98
+
+/*
+ * Some MAX6690 & DS1775 register definitions
+ */
+#define MAX6690_INT_TEMP	0
+#define MAX6690_EXT_TEMP	1
+#define DS1775_TEMP		0
+
+/*
+ * Scaling factors for the AD7417 ADC converters (except
+ * for the CPU diode which is obtained from the EEPROM).
+ * Those values are obtained from the property list of
+ * the darwin driver
+ */
+#define ADC_12V_CURRENT_SCALE	0x0320	/* _AD2 */
+#define ADC_CPU_VOLTAGE_SCALE	0x00a0	/* _AD3 */
+#define ADC_CPU_CURRENT_SCALE	0x1f40	/* _AD4 */
+
+/*
+ * PID factors for the U3/Backside fan control loop
+ */
+#define BACKSIDE_FAN_PWM_ID		1
+#define BACKSIDE_PID_G_d		0x02800000
+#define BACKSIDE_PID_G_p		0x00500000
+#define BACKSIDE_PID_G_r		0x00000000
+#define BACKSIDE_PID_INPUT_TARGET	0x00410000
+#define BACKSIDE_PID_INTERVAL		5
+#define BACKSIDE_PID_OUTPUT_MAX		100
+#define BACKSIDE_PID_OUTPUT_MIN		20
+#define BACKSIDE_PID_HISTORY_SIZE	2
+
+struct backside_pid_state
+{
+	int			ticks;
+	struct i2c_client *	monitor;
+	s32		       	sample_history[BACKSIDE_PID_HISTORY_SIZE];
+	s32			error_history[BACKSIDE_PID_HISTORY_SIZE];
+	int			cur_sample;
+	s32			last_temp;
+	int			pwm;
+	int			first;
+};
+
+/*
+ * PID factors for the Drive Bay fan control loop
+ */
+#define DRIVES_FAN_RPM_ID      		2
+#define DRIVES_PID_G_d			0x01e00000
+#define DRIVES_PID_G_p			0x00500000
+#define DRIVES_PID_G_r			0x00000000
+#define DRIVES_PID_INPUT_TARGET		0x00280000
+#define DRIVES_PID_INTERVAL    		5
+#define DRIVES_PID_OUTPUT_MAX		4000
+#define DRIVES_PID_OUTPUT_MIN		300
+#define DRIVES_PID_HISTORY_SIZE		2
+
+struct drives_pid_state
+{
+	int			ticks;
+	struct i2c_client *	monitor;
+	s32	       		sample_history[BACKSIDE_PID_HISTORY_SIZE];
+	s32			error_history[BACKSIDE_PID_HISTORY_SIZE];
+	int			cur_sample;
+	s32			last_temp;
+	int			rpm;
+	int			first;
+};
+
+#define SLOTS_FAN_PWM_ID       		2
+#define	SLOTS_FAN_DEFAULT_PWM		50 /* Do better here ! */
+
+/*
+ * IDs in Darwin for the sensors & fans
+ *
+ * CPU A AD7417_TEMP	10	(CPU A ambient temperature)
+ * CPU A AD7417_AD1	11	(CPU A diode temperature)
+ * CPU A AD7417_AD2	12	(CPU A 12V current)
+ * CPU A AD7417_AD3	13	(CPU A voltage)
+ * CPU A AD7417_AD4	14	(CPU A current)
+ *
+ * CPU A FAKE POWER	48	(I_V_inputs: 13, 14)
+ *
+ * CPU B AD7417_TEMP	15	(CPU B ambient temperature)
+ * CPU B AD7417_AD1	16	(CPU B diode temperature)
+ * CPU B AD7417_AD2	17	(CPU B 12V current)
+ * CPU B AD7417_AD3	18	(CPU B voltage)
+ * CPU B AD7417_AD4	19	(CPU B current)
+ *
+ * CPU B FAKE POWER	49	(I_V_inputs: 18, 19)
+ */
+
+#define CPUA_INTAKE_FAN_RPM_ID		3
+#define CPUA_EXHAUST_FAN_RPM_ID		4
+#define CPUB_INTAKE_FAN_RPM_ID		5
+#define CPUB_EXHAUST_FAN_RPM_ID		6
+
+#define CPU_INTAKE_SCALE		0x0000f852
+#define CPU_TEMP_HISTORY_SIZE		2
+#define CPU_POWER_HISTORY_SIZE		10
+#define CPU_PID_INTERVAL		1
+#define CPU_MAX_OVERTEMP		30
+
+struct cpu_pid_state
+{
+	int			index;
+	struct i2c_client *	monitor;
+	struct mpu_data		mpu;
+	int			overtemp;
+	s32	       		temp_history[CPU_TEMP_HISTORY_SIZE];
+	int			cur_temp;
+	s32			power_history[CPU_POWER_HISTORY_SIZE];
+	s32			error_history[CPU_POWER_HISTORY_SIZE];
+	int			cur_power;
+	int			count_power;
+	int			rpm;
+	int			intake_rpm;
+	s32			voltage;
+	s32			current_a;
+	s32			last_temp;
+	int			first;
+};
+
+/*
+ * Driver state
+ */
+enum {
+	state_detached,
+	state_attaching,
+	state_attached,
+	state_detaching,
+};
+
+
+#endif /* __THERM_PMAC_7_2_H__ */
diff -puN /dev/null drivers/macintosh/therm_windtunnel.c
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/drivers/macintosh/therm_windtunnel.c	2004-01-28 23:09:16.000000000 -0800
@@ -0,0 +1,456 @@
+/* 
+ *   Creation Date: <2003/03/14 20:54:13 samuel>
+ *   Time-stamp: <2003/03/15 18:55:53 samuel>
+ *   
+ *	<therm_windtunnel.c>
+ *	
+ *	The G4 "windtunnel" has a single fan controlled by a
+ *	DS1775 fan controller and an ADM1030 thermostat.
+ *
+ *	The fan controller is equipped with a temperature sensor
+ *	which measures the case temperature. The ADM censor
+ *	measures the CPU temperature. This driver tunes the
+ *	behavior of the fan. It is based upon empirical observations
+ *	of the 'AppleFan' driver under OSX.
+ *
+ *	WARNING: This driver has only been testen on Apple's
+ *	1.25 MHz Dual G4 (March 03). Other machines might have
+ *	a different thermal design. It is tuned for a CPU
+ *	temperatur around 57 C.
+ *
+ *   Copyright (C) 2003 Samuel Rydh (samuel@ibrium.se)
+ *
+ *   Loosely based upon 'thermostat.c' written by Benjamin Herrenschmidt
+ *   
+ *   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
+ *   
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/workqueue.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/sections.h>
+
+MODULE_AUTHOR("Samuel Rydh <samuel@ibrium.se>");
+MODULE_DESCRIPTION("Apple G4 (windtunnel) fan driver");
+MODULE_LICENSE("GPL");
+
+#define LOG_TEMP		0			/* continously log temperature */
+
+/* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */
+static unsigned short normal_i2c[] = { 0x49, 0x2c, I2C_CLIENT_END };
+static unsigned short normal_i2c_range[] = { 0x48, 0x4f, 0x2c, 0x2f, I2C_CLIENT_END };
+static struct work_struct poll_work;
+
+I2C_CLIENT_INSMOD;
+
+#define I2C_DRIVERID_G4FAN	0x9001			/* fixme */
+
+#define THERMOSTAT_CLIENT_ID	1
+#define FAN_CLIENT_ID		2
+
+struct temp_range {
+	u8			high;			/* start the fan */
+	u8			low;			/* stop the fan */
+};
+struct apple_thermal_info {
+	u8			id;			/* implementation ID */
+	u8			fan_count;		/* number of fans */
+	u8			thermostat_count;	/* number of thermostats */
+	u8			unused[5];
+	struct temp_range	ranges[4];		/* temperature ranges (may be [])*/
+};
+
+static int do_detect( struct i2c_adapter *adapter, int addr, int kind);
+
+static struct {
+	struct i2c_client	*thermostat;
+	struct i2c_client	*fan;
+	int			error;
+	struct timer_list	timer;
+
+	int			overheat_temp;		/* 100% fan at this temp */
+	int			overheat_hyst;
+	int			temp;
+	int			casetemp;
+	int			fan_level;		/* active fan_table setting */
+
+	int			downind;
+	int			upind;
+
+	int			r0, r1, r20, r23, r25;	/* saved register */
+} x;
+
+static struct {
+	int			temp;
+	int			fan_setting;
+} fan_up_table[] = {
+	{ 0x0000, 11 },		/* min fan */
+	{ 0x3900, 8 },		/* 57.0 C */
+	{ 0x3a4a, 7 },		/* 58.3 C */
+	{ 0x3ad3, 6 },		/* 58.8 C */
+	{ 0x3b3c, 5 },		/* 59.2 C */
+	{ 0x3b94, 4 },		/* 59.6 C */
+	{ 0x3be3, 3 },		/* 58.9 C */
+	{ 0x3c29, 2 },		/* 59.2 C */
+	{ 0xffff, 1 }		/* on fire */
+};
+static struct {
+	int			temp;
+	int			fan_setting;
+} fan_down_table[] = {
+	{ 0x3700, 11 },		/* 55.0 C */
+	{ 0x374a, 6 },
+	{ 0x3800, 7 },		/* 56.0 C */
+	{ 0x3900, 8 },		/* 57.0 C */
+	{ 0x3a4a, 7 },		/* 58.3 C */
+	{ 0x3ad3, 6 },		/* 58.8 C */
+	{ 0x3b3c, 5 },		/* 59.2 C */
+	{ 0x3b94, 4 },		/* 58.9 C */
+	{ 0x3be3, 3 },		/* 58.9 C */
+	{ 0x3c29, 2 },		/* 59.2 C */
+	{ 0xffff, 1 }
+};
+
+static int
+write_reg( struct i2c_client *cl, int reg, int data, int len )
+{
+	u8 tmp[3];
+
+	if( len < 1 || len > 2 || data < 0 )
+		return -EINVAL;
+
+	tmp[0] = reg;
+	tmp[1] = (len == 1) ? data : (data >> 8);
+	tmp[2] = data;
+	len++;
+	
+	if( i2c_master_send(cl, tmp, len) != len )
+		return -ENODEV;
+	return 0;
+}
+
+static int
+read_reg( struct i2c_client *cl, int reg, int len )
+{
+	u8 buf[2];
+
+	if( len != 1 && len != 2 )
+		return -EINVAL;
+	buf[0] = reg;
+	if( i2c_master_send(cl, buf, 1) != 1 )
+		return -ENODEV;
+	if( i2c_master_recv(cl, buf, len) != len )
+		return -ENODEV;
+	return (len == 2)? ((unsigned int)buf[0] << 8) | buf[1] : buf[0];
+}
+
+
+static void
+print_temp( const char *s, int temp )
+{
+	printk("%s%d.%d C", s ? s : "", temp>>8, (temp & 255)*10/256 );
+}
+
+static void
+tune_fan( int fan_setting )
+{
+	int val = (fan_setting << 3) | 7;
+	x.fan_level = fan_setting;
+	
+	//write_reg( x.fan, 0x24, val, 1 );
+	write_reg( x.fan, 0x25, val, 1 );
+	write_reg( x.fan, 0x20, 0, 1 );
+	print_temp("CPU-temp: ", x.temp );
+	if( x.casetemp )
+		print_temp(", Case: ", x.casetemp );
+	printk("  Tuning fan: %d (%02x)\n", fan_setting, val );
+}
+
+static void
+poll_temp( void *param )
+{
+	int temp = read_reg( x.thermostat, 0, 2 );
+	int i, level, casetemp;
+
+	/* this actually occurs when the computer is loaded */
+	if( temp < 0 )
+		goto out;
+
+	casetemp = read_reg(x.fan, 0x0b, 1) << 8;
+	casetemp |= (read_reg(x.fan, 0x06, 1) & 0x7) << 5;
+
+	if( LOG_TEMP && x.temp != temp ) {
+		print_temp("CPU-temp: ", temp );
+		print_temp(", Case: ", casetemp );
+		printk(",  Fan: %d\n", x.fan_level );
+	}
+	x.temp = temp;
+	x.casetemp = casetemp;
+
+	level = -1;
+	for( i=0; (temp & 0xffff) > fan_down_table[i].temp ; i++ )
+		;
+	if( i < x.downind )
+		level = fan_down_table[i].fan_setting;
+	x.downind = i;
+
+	for( i=0; (temp & 0xfffe) >= fan_up_table[i+1].temp ; i++ )
+		;
+	if( x.upind < i )
+		level = fan_up_table[i].fan_setting;
+	x.upind = i;
+
+	if( level >= 0 )
+		tune_fan( level );
+ out:
+	x.timer.expires = jiffies + 8*HZ;
+	add_timer( &x.timer );
+}
+
+static void
+schedule_poll( unsigned long t )
+{
+	schedule_work(&poll_work);
+}
+
+/************************************************************************/
+/*	i2c probing and setup						*/
+/************************************************************************/
+
+static int
+do_attach( struct i2c_adapter *adapter )
+{
+	return i2c_probe( adapter, &addr_data, &do_detect );
+}
+
+static int
+do_detach( struct i2c_client *client )
+{
+	int err;
+
+	printk("do_detach: id %d\n", client->id );
+	if( (err=i2c_detach_client(client)) ) {
+		printk("failed to detach thermostat client\n");
+		return err;
+	}
+	kfree( client );
+	return 0;
+}
+
+static struct i2c_driver g4fan_driver = {  
+	.name		= "Apple G4 Thermostat/Fan",
+	.id		= I2C_DRIVERID_G4FAN,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter = &do_attach,
+	.detach_client	= &do_detach,
+	.command	= NULL,
+};
+
+static int
+detect_fan( struct i2c_client *cl )
+{
+	/* check that this is an ADM1030 */
+	if( read_reg(cl, 0x3d, 1) != 0x30 || read_reg(cl, 0x3e, 1) != 0x41 )
+		goto out;
+	printk("ADM1030 fan controller detected at %02x\n", cl->addr );
+
+	if( x.fan ) {
+		x.error |= 2;
+		goto out;
+	}
+	x.fan = cl;
+	cl->id = FAN_CLIENT_ID;
+	strncpy( cl->name, "ADM1030 fan controller", sizeof(cl->name) );
+
+	if( i2c_attach_client( cl ) )
+		goto out;
+	return 0;
+ out:
+	if( cl != x.fan )
+		kfree( cl );
+	return 0;
+}
+
+static int
+detect_thermostat( struct i2c_client *cl ) 
+{
+	int hyst_temp, os_temp, temp;
+
+	if( (temp=read_reg(cl, 0, 2)) < 0 )
+		goto out;
+	
+	/* temperature sanity check */
+	if( temp < 0x1600 || temp > 0x3c00 )
+		goto out;
+	hyst_temp = read_reg(cl, 2, 2);
+	os_temp = read_reg(cl, 3, 2);
+	if( hyst_temp < 0 || os_temp < 0 )
+		goto out;
+
+	printk("DS1775 digital thermometer detected at %02x\n", cl->addr );
+	print_temp("Temp: ", temp );
+	print_temp("  Hyst: ", hyst_temp );
+	print_temp("  OS: ", os_temp );
+	printk("\n");
+
+	if( x.thermostat ) {
+		x.error |= 1;
+		goto out;
+	}
+	x.temp = temp;
+	x.thermostat = cl;
+	x.overheat_temp = os_temp;
+	x.overheat_hyst = hyst_temp;
+	
+	cl->id = THERMOSTAT_CLIENT_ID;
+	strncpy( cl->name, "DS1775 thermostat", sizeof(cl->name) );
+
+	if( i2c_attach_client( cl ) )
+		goto out;
+	return 0;
+out:
+	kfree( cl );
+	return 0;
+}
+
+static int
+do_detect( struct i2c_adapter *adapter, int addr, int kind )
+{
+	struct i2c_client *cl;
+
+	if( strncmp(adapter->name, "uni-n", 5) )
+		return 0;
+	if( !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA
+				     | I2C_FUNC_SMBUS_WRITE_BYTE) )
+		return 0;
+
+	if( !(cl=kmalloc( sizeof(struct i2c_client), GFP_KERNEL )) )
+		return -ENOMEM;
+	memset( cl, 0, sizeof(struct i2c_client) );
+
+	cl->addr = addr;
+	cl->adapter = adapter;
+	cl->driver = &g4fan_driver;
+	cl->flags = 0;
+
+	if( addr < 0x48 )
+		return detect_fan( cl );
+	return detect_thermostat( cl );
+}
+
+#define PRINT_REG( r )	printk("reg %02x = %02x\n", r, read_reg(x.fan, r, 1) )
+
+static int __init
+g4fan_init( void )
+{
+	struct apple_thermal_info *info;
+	struct device_node *np;
+	int ret, val;
+	
+	np = of_find_node_by_name(NULL, "power-mgt");
+	if (np == NULL)
+		return -ENODEV;
+	info = (struct apple_thermal_info*)get_property(np, "thermal-info", NULL);
+	of_node_put(np);
+	if (info == NULL)
+		return -ENODEV;
+	
+	/* check for G4 "Windtunnel" SMP */
+	if( machine_is_compatible("PowerMac3,6") ) {
+		if( info->id != 3 ) {
+			printk(KERN_ERR "g4fan: design id %d unknown\n", info->id);
+			return -ENODEV;
+		}
+	} else {
+		printk(KERN_ERR "g4fan: unsupported machine type\n");
+		return -ENODEV;
+	}
+	if( (ret=i2c_add_driver(&g4fan_driver)) )
+		return ret;
+
+	if( !x.thermostat || !x.fan ) {
+		i2c_del_driver(&g4fan_driver );
+		return -ENODEV;
+	}
+
+	/* save registers (if we unload the module) */
+	x.r0 = read_reg( x.fan, 0x00, 1 );
+	x.r1 = read_reg( x.fan, 0x01, 1 );
+	x.r20 = read_reg( x.fan, 0x20, 1 );
+	x.r23 = read_reg( x.fan, 0x23, 1 );
+	x.r25 = read_reg( x.fan, 0x25, 1 );
+
+	/* improve measurement resolution (convergence time 1.5s) */
+	if( (val=read_reg( x.thermostat, 1, 1 )) >= 0 ) {
+		val |= 0x60;
+		if( write_reg( x.thermostat, 1, val, 1 ) )
+			printk("Failed writing config register\n");
+	}
+	/* disable interrupts and TAC input */
+	write_reg( x.fan, 0x01, 0x01, 1 );
+	/* enable filter */
+	write_reg( x.fan, 0x23, 0x91, 1 );
+	/* remote temp. controls fan */
+	write_reg( x.fan, 0x00, 0x95, 1 );
+
+	/* The thermostat (which besides measureing temperature controls
+	 * has a THERM output which puts the fan on 100%) is usually
+	 * set to kick in at 80 C (chip default). We reduce this a bit
+	 * to be on the safe side (OSX doesn't)...
+	 */
+	if( x.overheat_temp == (80 << 8) ) {
+		x.overheat_temp = 65 << 8;
+		x.overheat_hyst = 60 << 8;
+		write_reg( x.thermostat, 2, x.overheat_hyst, 2 );
+		write_reg( x.thermostat, 3, x.overheat_temp, 2 );
+
+		print_temp("Reducing overheating limit to ", x.overheat_temp );
+		print_temp(" (Hyst: ", x.overheat_hyst );
+		printk(")\n");
+	}
+
+	/* set an initial fan setting */
+	x.upind = x.downind = 1;
+	tune_fan( fan_up_table[x.upind].fan_setting );
+
+	INIT_WORK(&poll_work, poll_temp, NULL);
+
+	init_timer( &x.timer );
+	x.timer.expires = jiffies + 8*HZ;
+	x.timer.function = schedule_poll;
+	add_timer( &x.timer );
+	return 0;
+}
+
+static void __exit
+g4fan_exit( void )
+{
+	del_timer( &x.timer );
+
+	write_reg( x.fan, 0x01, x.r1, 1 );
+	write_reg( x.fan, 0x20, x.r20, 1 );
+	write_reg( x.fan, 0x23, x.r23, 1 );
+	write_reg( x.fan, 0x25, x.r25, 1 );
+	write_reg( x.fan, 0x00, x.r0, 1 );
+
+	i2c_del_driver( &g4fan_driver );
+}
+
+module_init(g4fan_init);
+module_exit(g4fan_exit);
+
diff -puN drivers/macintosh/via-pmu.c~big-pmac-3 drivers/macintosh/via-pmu.c
--- 25/drivers/macintosh/via-pmu.c~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/drivers/macintosh/via-pmu.c	2004-01-28 23:09:16.000000000 -0800
@@ -168,6 +168,7 @@ static struct proc_dir_entry *proc_pmu_r
 static struct proc_dir_entry *proc_pmu_info;
 static struct proc_dir_entry *proc_pmu_irqstats;
 static struct proc_dir_entry *proc_pmu_options;
+static int option_server_mode;
 
 #ifdef CONFIG_PMAC_PBOOK
 int pmu_battery_count;
@@ -334,7 +335,8 @@ find_via_pmu(void)
 		pmu_kind = PMU_PADDINGTON_BASED;
 	else if (device_is_compatible(vias->parent, "heathrow"))
 		pmu_kind = PMU_HEATHROW_BASED;
-	else if (device_is_compatible(vias->parent, "Keylargo")) {
+	else if (device_is_compatible(vias->parent, "Keylargo")
+		 || device_is_compatible(vias->parent, "K2-Keylargo")) {
 		struct device_node *gpio, *gpiop;
 
 		pmu_kind = PMU_KEYLARGO_BASED;
@@ -349,6 +351,8 @@ find_via_pmu(void)
 		if (gpiop && gpiop->n_addrs) {
 			gpio_reg = ioremap(gpiop->addrs->address, 0x10);
 			gpio = find_devices("extint-gpio1");
+			if (gpio == NULL)
+				gpio = find_devices("pmu-interrupt");
 			if (gpio && gpio->parent == gpiop && gpio->n_intrs)
 				gpio_irq = gpio->intrs[0].line;
 		}
@@ -564,7 +568,19 @@ init_pmu(void)
 	pmu_wait_complete(&req);
 	if (req.reply_len > 0)
 		pmu_version = req.reply[0];
-
+	
+	/* Read server mode setting */
+	if (pmu_kind == PMU_KEYLARGO_BASED) {
+		pmu_request(&req, NULL, 2, PMU_POWER_EVENTS,
+			    PMU_PWR_GET_POWERUP_EVENTS);
+		pmu_wait_complete(&req);
+		if (req.reply_len == 2) {
+			if (req.reply[1] & PMU_PWR_WAKEUP_AC_INSERT)
+				option_server_mode = 1;
+			printk(KERN_INFO "via-pmu: Server Mode is %s\n",
+			       option_server_mode ? "enabled" : "disabled");
+		}
+	}
 	return 1;
 }
 
@@ -583,6 +599,28 @@ static inline void wakeup_decrementer(vo
 	last_jiffy_stamp(0) = tb_last_stamp = get_tbl();
 }
 
+static void pmu_set_server_mode(int server_mode)
+{
+	struct adb_request req;
+
+	if (pmu_kind != PMU_KEYLARGO_BASED)
+		return;
+
+	option_server_mode = server_mode;
+	pmu_request(&req, NULL, 2, PMU_POWER_EVENTS, PMU_PWR_GET_POWERUP_EVENTS);
+	pmu_wait_complete(&req);
+	if (req.reply_len < 2)
+		return;
+	if (server_mode)
+		pmu_request(&req, NULL, 4, PMU_POWER_EVENTS,
+			    PMU_PWR_SET_POWERUP_EVENTS,
+			    req.reply[0], PMU_PWR_WAKEUP_AC_INSERT); 
+	else
+		pmu_request(&req, NULL, 4, PMU_POWER_EVENTS,
+			    PMU_PWR_CLR_POWERUP_EVENTS,
+			    req.reply[0], PMU_PWR_WAKEUP_AC_INSERT); 
+	pmu_wait_complete(&req);
+}
 
 #ifdef CONFIG_PMAC_PBOOK
 
@@ -845,6 +883,8 @@ proc_read_options(char *page, char **sta
 	if (pmu_kind == PMU_KEYLARGO_BASED && can_sleep)
 		p += sprintf(p, "lid_wakeup=%d\n", option_lid_wakeup);
 #endif /* CONFIG_PMAC_PBOOK */
+	if (pmu_kind == PMU_KEYLARGO_BASED)
+		p += sprintf(p, "server_mode=%d\n", option_server_mode);
 
 	return p - page;
 }
@@ -884,6 +924,12 @@ proc_write_options(struct file *file, co
 		if (!strcmp(label, "lid_wakeup"))
 			option_lid_wakeup = ((*val) == '1');
 #endif /* CONFIG_PMAC_PBOOK */
+	if (pmu_kind == PMU_KEYLARGO_BASED && !strcmp(label, "server_mode")) {
+		int new_value;
+		new_value = ((*val) == '1');
+		if (new_value != option_server_mode)
+			pmu_set_server_mode(new_value);
+	}
 	return fcount;
 }
 
@@ -1758,6 +1804,11 @@ pmu_shutdown(void)
 		pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB |
 						PMU_INT_TICK );
 		pmu_wait_complete(&req);
+	} else {
+		/* Disable server mode on shutdown or we'll just
+		 * wake up again
+		 */
+		pmu_set_server_mode(0);
 	}
 
 	pmu_request(&req, NULL, 5, PMU_SHUTDOWN,
diff -puN drivers/net/bmac.c~big-pmac-3 drivers/net/bmac.c
--- 25/drivers/net/bmac.c~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/drivers/net/bmac.c	2004-01-28 23:09:16.000000000 -0800
@@ -26,11 +26,9 @@
 #include <asm/pgtable.h>
 #include <asm/machdep.h>
 #include <asm/pmac_feature.h>
+#include <asm/macio.h>
 #include <asm/irq.h>
-#ifdef CONFIG_PMAC_PBOOK
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#endif
+
 #include "bmac.h"
 
 #define trunc_page(x)	((void *)(((unsigned long)(x)) & ~((unsigned long)(PAGE_SIZE - 1))))
@@ -67,7 +65,7 @@ struct bmac_data {
 	int rx_dma_intr;
 	volatile struct dbdma_cmd *tx_cmds;	/* xmit dma command list */
 	volatile struct dbdma_cmd *rx_cmds;	/* recv dma command list */
-	struct device_node *node;
+	struct macio_dev *mdev;
 	int is_bmac_plus;
 	struct sk_buff *rx_bufs[N_RX_RING];
 	int rx_fill;
@@ -84,9 +82,10 @@ struct bmac_data {
 	unsigned short hash_use_count[64];
 	unsigned short hash_table_mask[4];
 	spinlock_t lock;
-	struct net_device *next_bmac;
 };
 
+#if 0 /* Move that to ethtool */
+
 typedef struct bmac_reg_entry {
 	char *name;
 	unsigned short reg_offset;
@@ -128,16 +127,10 @@ static bmac_reg_entry_t reg_entries[N_RE
 	{"RXCV", RXCV}
 };
 
-static struct net_device *bmac_devs;
-static unsigned char *bmac_emergency_rxbuf;
-
-#ifdef CONFIG_PMAC_PBOOK
-static int bmac_sleep_notify(struct pmu_sleep_notifier *self, int when);
-static struct pmu_sleep_notifier bmac_sleep_notifier = {
-	bmac_sleep_notify, SLEEP_LEVEL_NET,
-};
 #endif
 
+static unsigned char *bmac_emergency_rxbuf;
+
 /*
  * Number of bytes of private data per BMAC: allow enough for
  * the rx and tx dma commands plus a branch dma command each,
@@ -149,7 +142,6 @@ static struct pmu_sleep_notifier bmac_sl
 	+ sizeof(struct sk_buff_head))
 
 static unsigned char bitrev(unsigned char b);
-static void bmac_probe1(struct device_node *bmac, int is_bmac_plus);
 static int bmac_open(struct net_device *dev);
 static int bmac_close(struct net_device *dev);
 static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev);
@@ -166,7 +158,6 @@ static irqreturn_t bmac_txdma_intr(int i
 static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs);
 static void bmac_set_timeout(struct net_device *dev);
 static void bmac_tx_timeout(unsigned long data);
-static int bmac_proc_info ( char *buffer, char **start, off_t offset, int length);
 static int bmac_output(struct sk_buff *skb, struct net_device *dev);
 static void bmac_start(struct net_device *dev);
 
@@ -244,7 +235,7 @@ bmac_enable_and_reset_chip(struct net_de
 	if (td)
 		dbdma_reset(td);
 
-	pmac_call_feature(PMAC_FTR_BMAC_ENABLE, bp->node, 0, 1);
+	pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 1);
 }
 
 #define MIFDELAY	udelay(10)
@@ -457,87 +448,80 @@ bmac_init_phy(struct net_device *dev)
 	}
 }
 
-static void
-bmac_init_chip(struct net_device *dev)
+static void bmac_init_chip(struct net_device *dev)
 {
 	bmac_init_phy(dev);
 	bmac_init_registers(dev);
 }
 
-#ifdef CONFIG_PMAC_PBOOK
-static int
-bmac_sleep_notify(struct pmu_sleep_notifier *self, int when)
+#ifdef CONFIG_PM
+static int bmac_suspend(struct macio_dev *mdev, u32 state)
 {
-	struct bmac_data *bp;
+	struct net_device* dev = macio_get_drvdata(mdev);	
+	struct bmac_data *bp = dev->priv;	
 	unsigned long flags;
 	unsigned short config;
-	struct net_device* dev = bmac_devs;
 	int i;
 	
-	if (bmac_devs == 0)
-		return PBOOK_SLEEP_OK;
-		
-	bp = (struct bmac_data *) dev->priv;
-	
-	switch (when) {
-	case PBOOK_SLEEP_REQUEST:
-		break;
-	case PBOOK_SLEEP_REJECT:
-		break;
-	case PBOOK_SLEEP_NOW:
-		netif_device_detach(dev);
-		/* prolly should wait for dma to finish & turn off the chip */
-		spin_lock_irqsave(&bp->lock, flags);
-		if (bp->timeout_active) {
-			del_timer(&bp->tx_timeout);
-			bp->timeout_active = 0;
-		}
-		disable_irq(dev->irq);
-		disable_irq(bp->tx_dma_intr);
-		disable_irq(bp->rx_dma_intr);
-		bp->sleeping = 1;
-		spin_unlock_irqrestore(&bp->lock, flags);
-		if (bp->opened) {
-			volatile struct dbdma_regs *rd = bp->rx_dma;
-			volatile struct dbdma_regs *td = bp->tx_dma;
+	netif_device_detach(dev);
+	/* prolly should wait for dma to finish & turn off the chip */
+	spin_lock_irqsave(&bp->lock, flags);
+	if (bp->timeout_active) {
+		del_timer(&bp->tx_timeout);
+		bp->timeout_active = 0;
+	}
+	disable_irq(dev->irq);
+	disable_irq(bp->tx_dma_intr);
+	disable_irq(bp->rx_dma_intr);
+	bp->sleeping = 1;
+	spin_unlock_irqrestore(&bp->lock, flags);
+	if (bp->opened) {
+		volatile struct dbdma_regs *rd = bp->rx_dma;
+		volatile struct dbdma_regs *td = bp->tx_dma;
 			
-			config = bmread(dev, RXCFG);
-			bmwrite(dev, RXCFG, (config & ~RxMACEnable));
-			config = bmread(dev, TXCFG);
-			bmwrite(dev, TXCFG, (config & ~TxMACEnable));
-			bmwrite(dev, INTDISABLE, DisableAll); /* disable all intrs */
-			/* disable rx and tx dma */
-			st_le32(&rd->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE));	/* clear run bit */
-			st_le32(&td->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE));	/* clear run bit */
-			/* free some skb's */
-			for (i=0; i<N_RX_RING; i++) {
-				if (bp->rx_bufs[i] != NULL) {
-					dev_kfree_skb(bp->rx_bufs[i]);
-					bp->rx_bufs[i] = NULL;
-				}
-			}
-			for (i = 0; i<N_TX_RING; i++) {
-				if (bp->tx_bufs[i] != NULL) {
-					dev_kfree_skb(bp->tx_bufs[i]);
-					bp->tx_bufs[i] = NULL;
-				}
-			}
+		config = bmread(dev, RXCFG);
+		bmwrite(dev, RXCFG, (config & ~RxMACEnable));
+		config = bmread(dev, TXCFG);
+       		bmwrite(dev, TXCFG, (config & ~TxMACEnable));
+		bmwrite(dev, INTDISABLE, DisableAll); /* disable all intrs */
+       		/* disable rx and tx dma */
+       		st_le32(&rd->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE));	/* clear run bit */
+       		st_le32(&td->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE));	/* clear run bit */
+       		/* free some skb's */
+       		for (i=0; i<N_RX_RING; i++) {
+       			if (bp->rx_bufs[i] != NULL) {
+       				dev_kfree_skb(bp->rx_bufs[i]);
+       				bp->rx_bufs[i] = NULL;
+       			}
+       		}
+       		for (i = 0; i<N_TX_RING; i++) {
+			if (bp->tx_bufs[i] != NULL) {
+		       		dev_kfree_skb(bp->tx_bufs[i]);
+	       			bp->tx_bufs[i] = NULL;
+		       	}
 		}
-		pmac_call_feature(PMAC_FTR_BMAC_ENABLE, bp->node, 0, 0);
-		break;
-	case PBOOK_WAKE:
-		/* see if this is enough */
-		if (bp->opened)
-			bmac_reset_and_enable(dev);
-		enable_irq(dev->irq);
-		enable_irq(bp->tx_dma_intr);
-		enable_irq(bp->rx_dma_intr);
-		netif_device_attach(dev);
-		break;
 	}
-	return PBOOK_SLEEP_OK;
+       	pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0);
+	return 0;
 }
-#endif
+
+static int bmac_resume(struct macio_dev *mdev)
+{
+	struct net_device* dev = macio_get_drvdata(mdev);	
+	struct bmac_data *bp = dev->priv;	
+
+	/* see if this is enough */
+	if (bp->opened)
+		bmac_reset_and_enable(dev);
+
+	enable_irq(dev->irq);
+       	enable_irq(bp->tx_dma_intr);
+       	enable_irq(bp->rx_dma_intr);
+       	netif_device_attach(dev);
+
+	return 0;
+}
+#endif /* CONFIG_PM */
 
 static int bmac_set_address(struct net_device *dev, void *addr)
 {
@@ -1277,103 +1261,61 @@ static void bmac_reset_and_enable(struct
 	spin_unlock_irqrestore(&bp->lock, flags);
 }
 
-static int __init bmac_probe(void)
-{
-	struct device_node *bmac;
-
-	MOD_INC_USE_COUNT;
-
-	for (bmac = find_devices("bmac"); bmac != 0; bmac = bmac->next)
-		bmac_probe1(bmac, 0);
-	for (bmac = find_compatible_devices("network", "bmac+"); bmac != 0;
-	     bmac = bmac->next)
-		bmac_probe1(bmac, 1);
-
-	if (bmac_devs != 0) {
-		proc_net_create ("bmac", 0, bmac_proc_info);
-#ifdef CONFIG_PMAC_PBOOK
-		pmu_register_sleep_notifier(&bmac_sleep_notifier);
-#endif
-	}
-
-	MOD_DEC_USE_COUNT;
-
-	return bmac_devs? 0: -ENODEV;
-}
-
-static void __init bmac_probe1(struct device_node *bmac, int is_bmac_plus)
+static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_match *match)
 {
 	int j, rev, ret;
 	struct bmac_data *bp;
 	unsigned char *addr;
 	struct net_device *dev;
+	int is_bmac_plus = ((int)match->data) != 0;
 
-	if (bmac->n_addrs != 3 || bmac->n_intrs != 3) {
-		printk(KERN_ERR "can't use BMAC %s: need 3 addrs and 3 intrs\n",
-		       bmac->full_name);
-		return;
+	if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) {
+		printk(KERN_ERR "BMAC: can't use, need 3 addrs and 3 intrs\n");
+		return -ENODEV;
 	}
-	addr = get_property(bmac, "mac-address", NULL);
+	addr = get_property(macio_get_of_node(mdev), "mac-address", NULL);
 	if (addr == NULL) {
-		addr = get_property(bmac, "local-mac-address", NULL);
+		addr = get_property(macio_get_of_node(mdev), "local-mac-address", NULL);
 		if (addr == NULL) {
-			printk(KERN_ERR "Can't get mac-address for BMAC %s\n",
-			       bmac->full_name);
-			return;
-		}
-	}
-
-	if (bmac_emergency_rxbuf == NULL) {
-		bmac_emergency_rxbuf = kmalloc(RX_BUFLEN, GFP_KERNEL);
-		if (bmac_emergency_rxbuf == NULL) {
-			printk(KERN_ERR "BMAC: can't allocate emergency RX buffer\n");
-			return;
+			printk(KERN_ERR "BMAC: Can't get mac-address\n");
+			return -ENODEV;
 		}
 	}
 
 	dev = alloc_etherdev(PRIV_BYTES);
 	if (!dev) {
-		printk(KERN_ERR "alloc_etherdev failed, out of memory for BMAC %s\n",
-		       bmac->full_name);
-		return;
+		printk(KERN_ERR "BMAC: alloc_etherdev failed, out of memory\n");
+		return -ENOMEM;
 	}
 		
 	bp = (struct bmac_data *) dev->priv;
 	SET_MODULE_OWNER(dev);
-	bp->node = bmac;
+	SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
+	macio_set_drvdata(mdev, dev);
+
+	bp->mdev = mdev;
 	spin_lock_init(&bp->lock);
 
-	if (!request_OF_resource(bmac, 0, " (bmac)")) {
+	if (macio_request_resources(mdev, "bmac")) {
 		printk(KERN_ERR "BMAC: can't request IO resource !\n");
-		goto out1;
-	}
-	if (!request_OF_resource(bmac, 1, " (bmac tx dma)")) {
-		printk(KERN_ERR "BMAC: can't request TX DMA resource !\n");
-		goto out2;
-	}
-	if (!request_OF_resource(bmac, 2, " (bmac rx dma)")) {
-		printk(KERN_ERR "BMAC: can't request RX DMA resource !\n");
-		goto out3;
+		goto out_free;
 	}
 
 	dev->base_addr = (unsigned long)
-		ioremap(bmac->addrs[0].address, bmac->addrs[0].size);
-	if (!dev->base_addr)
-		goto out4;
+		ioremap(macio_resource_start(mdev, 0), macio_resource_len(mdev, 0));
+	if (dev->base_addr == 0)
+		goto out_release;
 
-	dev->irq = bmac->intrs[0].line;
+	dev->irq = macio_irq(mdev, 0);
 
 	bmac_enable_and_reset_chip(dev);
 	bmwrite(dev, INTDISABLE, DisableAll);
 
-	printk(KERN_INFO "%s: BMAC%s at", dev->name, (is_bmac_plus? "+": ""));
 	rev = addr[0] == 0 && addr[1] == 0xA0;
 	for (j = 0; j < 6; ++j) {
 		dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j];
 		printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]);
 	}
-	XXDEBUG((", base_addr=%#0lx", dev->base_addr));
-	printk("\n");
 
 	/* Enable chip without interrupts for now */
 	bmac_enable_and_reset_chip(dev);
@@ -1392,15 +1334,15 @@ static void __init bmac_probe1(struct de
 
 	bp->is_bmac_plus = is_bmac_plus;
 	bp->tx_dma = (volatile struct dbdma_regs *)
-		ioremap(bmac->addrs[1].address, bmac->addrs[1].size);
+		ioremap(macio_resource_start(mdev, 1), macio_resource_len(mdev, 1));
 	if (!bp->tx_dma)
 		goto err_out_iounmap;
-	bp->tx_dma_intr = bmac->intrs[1].line;
+	bp->tx_dma_intr = macio_irq(mdev, 1);
 	bp->rx_dma = (volatile struct dbdma_regs *)
-		ioremap(bmac->addrs[2].address, bmac->addrs[2].size);
+		ioremap(macio_resource_start(mdev, 2), macio_resource_len(mdev, 2));
 	if (!bp->rx_dma)
 		goto err_out_iounmap_tx;
-	bp->rx_dma_intr = bmac->intrs[2].line;
+	bp->rx_dma_intr = macio_irq(mdev, 2);
 
 	bp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(bp + 1);
 	bp->rx_cmds = bp->tx_cmds + N_TX_RING + 1;
@@ -1415,14 +1357,14 @@ static void __init bmac_probe1(struct de
 		printk(KERN_ERR "BMAC: can't get irq %d\n", dev->irq);
 		goto err_out_iounmap_rx;
 	}
-	ret = request_irq(bmac->intrs[1].line, bmac_txdma_intr, 0, "BMAC-txdma", dev);
+	ret = request_irq(bp->tx_dma_intr, bmac_txdma_intr, 0, "BMAC-txdma", dev);
 	if (ret) {
-		printk(KERN_ERR "BMAC: can't get irq %d\n", bmac->intrs[1].line);
+		printk(KERN_ERR "BMAC: can't get irq %d\n", bp->tx_dma_intr);
 		goto err_out_irq0;
 	}
-	ret = request_irq(bmac->intrs[2].line, bmac_rxdma_intr, 0, "BMAC-rxdma", dev);
+	ret = request_irq(bp->rx_dma_intr, bmac_rxdma_intr, 0, "BMAC-rxdma", dev);
 	if (ret) {
-		printk(KERN_ERR "BMAC: can't get irq %d\n", bmac->intrs[2].line);
+		printk(KERN_ERR "BMAC: can't get irq %d\n", bp->rx_dma_intr);
 		goto err_out_irq1;
 	}
 
@@ -1430,22 +1372,23 @@ static void __init bmac_probe1(struct de
 	 * re-enabled on open()
 	 */
 	disable_irq(dev->irq);
-	pmac_call_feature(PMAC_FTR_BMAC_ENABLE, bp->node, 0, 0);
+	pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0);
 
 	if (register_netdev(dev) != 0) {
-		printk(KERN_ERR "registration failed for BMAC %s\n",
-		       bmac->full_name);
+		printk(KERN_ERR "BMAC: Ethernet registration failed\n");
 		goto err_out_irq2;
 	}
+
+	printk(KERN_INFO "%s: BMAC%s at", dev->name, (is_bmac_plus? "+": ""));
+	XXDEBUG((", base_addr=%#0lx", dev->base_addr));
+	printk("\n");
 	
-	bp->next_bmac = bmac_devs;
-	bmac_devs = dev;
-	return;
+	return 0;
 
 err_out_irq2:
-	free_irq(bmac->intrs[2].line, dev);
+	free_irq(bp->rx_dma_intr, dev);
 err_out_irq1:
-	free_irq(bmac->intrs[1].line, dev);
+	free_irq(bp->tx_dma_intr, dev);
 err_out_irq0:
 	free_irq(dev->irq, dev);
 err_out_iounmap_rx:
@@ -1454,15 +1397,13 @@ err_out_iounmap_tx:
 	iounmap((void *)bp->tx_dma);
 err_out_iounmap:
 	iounmap((void *)dev->base_addr);
-out4:
-	release_OF_resource(bp->node, 2);
-out3:
-	release_OF_resource(bp->node, 1);
-out2:
-	release_OF_resource(bp->node, 0);
-out1:
-	pmac_call_feature(PMAC_FTR_BMAC_ENABLE, bp->node, 0, 0);
+out_release:
+	macio_release_resources(mdev);
+out_free:
+	pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0);
 	free_netdev(dev);
+
+	return -ENODEV;
 }
 
 static int bmac_open(struct net_device *dev)
@@ -1520,7 +1461,7 @@ static int bmac_close(struct net_device 
 
 	bp->opened = 0;
 	disable_irq(dev->irq);
-	pmac_call_feature(PMAC_FTR_BMAC_ENABLE, bp->node, 0, 0);
+	pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0);
 
 	return 0;
 }
@@ -1649,6 +1590,7 @@ static void dump_dbdma(volatile struct d
 }
 #endif
 
+#if 0
 static int
 bmac_proc_info(char *buffer, char **start, off_t offset, int length)
 {
@@ -1683,46 +1625,86 @@ bmac_proc_info(char *buffer, char **star
 
 	return len;
 }
+#endif
 
+static int __devexit bmac_remove(struct macio_dev *mdev)
+{
+	struct net_device *dev = macio_get_drvdata(mdev);
+	struct bmac_data *bp = dev->priv;
 
-MODULE_AUTHOR("Randy Gobbel/Paul Mackerras");
-MODULE_DESCRIPTION("PowerMac BMAC ethernet driver.");
-MODULE_LICENSE("GPL");
+	unregister_netdev(dev);
 
-static void __exit bmac_cleanup (void)
-{
-	struct bmac_data *bp;
-	struct net_device *dev;
+       	free_irq(dev->irq, dev);
+	free_irq(bp->tx_dma_intr, dev);	
+	free_irq(bp->rx_dma_intr, dev);
 
-	if (bmac_emergency_rxbuf != NULL) {
-		kfree(bmac_emergency_rxbuf);
-		bmac_emergency_rxbuf = NULL;
-	}
+	iounmap((void *)dev->base_addr);
+	iounmap((void *)bp->tx_dma);
+	iounmap((void *)bp->rx_dma);
 
-	if (bmac_devs == 0)
-		return;
-#ifdef CONFIG_PMAC_PBOOK
-	pmu_unregister_sleep_notifier(&bmac_sleep_notifier);
+	macio_release_resources(mdev);
+
+	free_netdev(dev);
+
+	return 0;
+}
+
+static struct of_match bmac_match[] = 
+{
+	{
+	.name 		= "bmac",
+	.type		= OF_ANY_MATCH,
+	.compatible	= OF_ANY_MATCH,
+	.data		= (void *)0,
+	},
+	{
+	.name 		= OF_ANY_MATCH,
+	.type		= "network",
+	.compatible	= "bmac+",
+	.data		= (void *)1,
+	},
+	{},
+};
+
+static struct macio_driver bmac_driver = 
+{
+	.name 		= "bmac",
+	.match_table	= bmac_match,
+	.probe		= bmac_probe,
+	.remove		= bmac_remove,
+#ifdef CONFIG_PM
+	.suspend	= bmac_suspend,
+	.resume		= bmac_resume,
 #endif
-	proc_net_remove("bmac");
+};
 
-	do {
-		dev = bmac_devs;
-		bp = (struct bmac_data *) dev->priv;
-		bmac_devs = bp->next_bmac;
 
-		unregister_netdev(dev);
+static int __init bmac_init(void)
+{
+	if (bmac_emergency_rxbuf == NULL) {
+		bmac_emergency_rxbuf = kmalloc(RX_BUFLEN, GFP_KERNEL);
+		if (bmac_emergency_rxbuf == NULL) {
+			printk(KERN_ERR "BMAC: can't allocate emergency RX buffer\n");
+			return -ENOMEM;
+		}
+	}
 
-		release_OF_resource(bp->node, 0);
-		release_OF_resource(bp->node, 1);
-		release_OF_resource(bp->node, 2);
-		free_irq(dev->irq, dev);
-		free_irq(bp->tx_dma_intr, dev);
-		free_irq(bp->rx_dma_intr, dev);
+	return macio_register_driver(&bmac_driver);
+}
 
-		free_netdev(dev);
-	} while (bmac_devs != NULL);
+static void __exit bmac_exit(void)
+{
+	macio_unregister_driver(&bmac_driver);
+
+	if (bmac_emergency_rxbuf != NULL) {
+		kfree(bmac_emergency_rxbuf);
+		bmac_emergency_rxbuf = NULL;
+	}
 }
 
-module_init(bmac_probe);
-module_exit(bmac_cleanup);
+MODULE_AUTHOR("Randy Gobbel/Paul Mackerras");
+MODULE_DESCRIPTION("PowerMac BMAC ethernet driver.");
+MODULE_LICENSE("GPL");
+
+module_init(bmac_init);
+module_exit(bmac_exit);
diff -puN drivers/scsi/mac53c94.c~big-pmac-3 drivers/scsi/mac53c94.c
--- 25/drivers/scsi/mac53c94.c~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/drivers/scsi/mac53c94.c	2004-01-28 23:09:16.000000000 -0800
@@ -23,6 +23,7 @@
 #include <asm/prom.h>
 #include <asm/system.h>
 #include <asm/pci-bridge.h>
+#include <asm/macio.h>
 
 #include "scsi.h"
 #include "hosts.h"
@@ -37,13 +38,12 @@ enum fsc_phase {
 };
 
 struct fsc_state {
-	volatile struct	mac53c94_regs *regs;
+	struct	mac53c94_regs *regs;
 	int	intr;
-	volatile struct	dbdma_regs *dma;
+	struct	dbdma_regs *dma;
 	int	dmaintr;
 	int	clk_freq;
 	struct	Scsi_Host *host;
-	struct	fsc_state *next;
 	Scsi_Cmnd *request_q;
 	Scsi_Cmnd *request_qtail;
 	Scsi_Cmnd *current_req;		/* req we're currently working on */
@@ -52,151 +52,23 @@ struct fsc_state {
 	void	*dma_cmd_space;
 	struct	pci_dev *pdev;
 	dma_addr_t dma_addr;
+	struct macio_dev *mdev;
 };
 
-static struct fsc_state *all_53c94s;
-
 static void mac53c94_init(struct fsc_state *);
 static void mac53c94_start(struct fsc_state *);
 static void mac53c94_interrupt(int, void *, struct pt_regs *);
 static irqreturn_t do_mac53c94_interrupt(int, void *, struct pt_regs *);
 static void cmd_done(struct fsc_state *, int result);
 static void set_dma_cmds(struct fsc_state *, Scsi_Cmnd *);
-static int data_goes_out(Scsi_Cmnd *);
-
-int
-mac53c94_detect(Scsi_Host_Template *tp)
-{
-	struct device_node *node;
-	int nfscs;
-	struct fsc_state *state, **prev_statep;
-	struct Scsi_Host *host;
-	void *dma_cmd_space;
-	unsigned char *clkprop;
-	int proplen;
-	struct pci_dev *pdev;
-	u8 pbus, devfn;
-
-	nfscs = 0;
-	prev_statep = &all_53c94s;
-	for (node = find_devices("53c94"); node != 0; node = node->next) {
-		if (node->n_addrs != 2 || node->n_intrs != 2) {
-			printk(KERN_ERR "mac53c94: expected 2 addrs and intrs"
-			       " (got %d/%d) for node %s\n",
-			       node->n_addrs, node->n_intrs, node->full_name);
-			continue;
-		}
-
-		pdev = NULL;
-		if (node->parent != NULL
-		    && !pci_device_from_OF_node(node->parent, &pbus, &devfn))
-			pdev = pci_find_slot(pbus, devfn);
-		if (pdev == NULL) {
-			printk(KERN_ERR "mac53c94: can't find PCI device "
-			       "for %s\n", node->full_name);
-			continue;
-		}
-
-		host = scsi_register(tp, sizeof(struct fsc_state));
-		if (host == NULL)
-			break;
-		host->unique_id = nfscs;
-
-		state = (struct fsc_state *) host->hostdata;
-		if (state == 0) {
-			/* "can't happen" */
-			printk(KERN_ERR "mac53c94: no state for %s?!\n",
-			       node->full_name);
-			scsi_unregister(host);
-			break;
-		}
-		state->host = host;
-		state->pdev = pdev;
-
-		state->regs = (volatile struct mac53c94_regs *)
-			ioremap(node->addrs[0].address, 0x1000);
-		state->intr = node->intrs[0].line;
-		state->dma = (volatile struct dbdma_regs *)
-			ioremap(node->addrs[1].address, 0x1000);
-		state->dmaintr = node->intrs[1].line;
-		if (state->regs == NULL || state->dma == NULL) {
-			printk(KERN_ERR "mac53c94: ioremap failed for %s\n",
-			       node->full_name);
-			if (state->dma != NULL)
-				iounmap(state->dma);
-			if (state->regs != NULL)
-				iounmap(state->regs);
-			scsi_unregister(host);
-			break;
-		}
-
-		clkprop = get_property(node, "clock-frequency", &proplen);
-		if (clkprop == NULL || proplen != sizeof(int)) {
-			printk(KERN_ERR "%s: can't get clock frequency, "
-			       "assuming 25MHz\n", node->full_name);
-			state->clk_freq = 25000000;
-		} else
-			state->clk_freq = *(int *)clkprop;
-
-		/* Space for dma command list: +1 for stop command,
-		   +1 to allow for aligning. */
-		dma_cmd_space = kmalloc((host->sg_tablesize + 2) *
-					sizeof(struct dbdma_cmd), GFP_KERNEL);
-		if (dma_cmd_space == 0) {
-			printk(KERN_ERR "mac53c94: couldn't allocate dma "
-			       "command space for %s\n", node->full_name);
-			goto err_cleanup;
-		}
-		state->dma_cmds = (struct dbdma_cmd *)
-			DBDMA_ALIGN(dma_cmd_space);
-		memset(state->dma_cmds, 0, (host->sg_tablesize + 1)
-		       * sizeof(struct dbdma_cmd));
-		state->dma_cmd_space = dma_cmd_space;
-
-		*prev_statep = state;
-		prev_statep = &state->next;
-
-		if (request_irq(state->intr, do_mac53c94_interrupt, 0,
-				"53C94", state)) {
-			printk(KERN_ERR "mac53C94: can't get irq %d for %s\n",
-			       state->intr, node->full_name);
-		err_cleanup:
-			iounmap(state->dma);
-			iounmap(state->regs);
-			scsi_unregister(host);
-			break;
-		}
-
-		mac53c94_init(state);
-
-		++nfscs;
-	}
-	return nfscs;
-}
-
-int
-mac53c94_release(struct Scsi_Host *host)
-{
-	struct fsc_state *fp = (struct fsc_state *) host->hostdata;
 
-	if (fp == 0)
-		return 0;
-	if (fp->regs)
-		iounmap((void *) fp->regs);
-	if (fp->dma)
-		iounmap((void *) fp->dma);
-	kfree(fp->dma_cmd_space);
-	free_irq(fp->intr, fp);
-	return 0;
-}
 
-int
-mac53c94_queue(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+static int mac53c94_queue(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
 {
 	struct fsc_state *state;
 
 #if 0
-	if (data_goes_out(cmd)) {
+	if (cmd->sc_data_direction == SCSI_DATA_WRITE) {
 		int i;
 		printk(KERN_DEBUG "mac53c94_queue %p: command is", cmd);
 		for (i = 0; i < cmd->cmd_len; ++i)
@@ -223,60 +95,52 @@ mac53c94_queue(Scsi_Cmnd *cmd, void (*do
 	return 0;
 }
 
-int
-mac53c94_abort(Scsi_Cmnd *cmd)
+static int mac53c94_abort(Scsi_Cmnd *cmd)
 {
 	return SCSI_ABORT_SNOOZE;
 }
 
-int
-mac53c94_host_reset(Scsi_Cmnd *cmd)
+static int mac53c94_host_reset(Scsi_Cmnd *cmd)
 {
 	struct fsc_state *state = (struct fsc_state *) cmd->device->host->hostdata;
-	volatile struct mac53c94_regs *regs = state->regs;
-	volatile struct dbdma_regs *dma = state->dma;
+	struct mac53c94_regs *regs = state->regs;
+	struct dbdma_regs *dma = state->dma;
 
 	st_le32(&dma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
-	regs->command = CMD_SCSI_RESET;	/* assert RST */
-	eieio();
+	writeb(CMD_SCSI_RESET, &regs->command);	/* assert RST */
 	udelay(100);			/* leave it on for a while (>= 25us) */
-	regs->command = CMD_RESET;
-	eieio();
+	writeb(CMD_RESET, &regs->command);
 	udelay(20);
 	mac53c94_init(state);
-	regs->command = CMD_NOP;
-	eieio();
+	writeb(CMD_NOP, &regs->command);
 	return SUCCESS;
 }
 
-static void
-mac53c94_init(struct fsc_state *state)
+static void mac53c94_init(struct fsc_state *state)
 {
-	volatile struct mac53c94_regs *regs = state->regs;
-	volatile struct dbdma_regs *dma = state->dma;
+	struct mac53c94_regs *regs = state->regs;
+	struct dbdma_regs *dma = state->dma;
 	int x;
 
-	regs->config1 = state->host->this_id | CF1_PAR_ENABLE;
-	regs->sel_timeout = TIMO_VAL(250);	/* 250ms */
-	regs->clk_factor = CLKF_VAL(state->clk_freq);
-	regs->config2 = CF2_FEATURE_EN;
-	regs->config3 = 0;
-	regs->sync_period = 0;
-	regs->sync_offset = 0;
-	eieio();
-	x = regs->interrupt;
-	st_le32(&dma->control, (RUN|PAUSE|FLUSH|WAKE) << 16);
+	writeb(state->host->this_id | CF1_PAR_ENABLE, &regs->config1);
+	writeb(TIMO_VAL(250), &regs->sel_timeout);	/* 250ms */
+	writeb(CLKF_VAL(state->clk_freq), &regs->clk_factor);
+	writeb(CF2_FEATURE_EN, &regs->config2);
+	writeb(0, &regs->config3);
+	writeb(0, &regs->sync_period);
+	writeb(0, &regs->sync_offset);
+	x = readb(&regs->interrupt);
+	writel((RUN|PAUSE|FLUSH|WAKE) << 16, &dma->control);
 }
 
 /*
  * Start the next command for a 53C94.
  * Should be called with interrupts disabled.
  */
-static void
-mac53c94_start(struct fsc_state *state)
+static void mac53c94_start(struct fsc_state *state)
 {
 	Scsi_Cmnd *cmd;
-	volatile struct mac53c94_regs *regs = state->regs;
+	struct mac53c94_regs *regs = state->regs;
 	int i;
 
 	if (state->phase != idle || state->current_req != NULL)
@@ -287,37 +151,30 @@ mac53c94_start(struct fsc_state *state)
 	state->request_q = (Scsi_Cmnd *) cmd->host_scribble;
 
 	/* Off we go */
-	regs->count_lo = 0;
-	regs->count_mid = 0;
-	regs->count_hi = 0;
-	eieio();
-	regs->command = CMD_NOP + CMD_DMA_MODE;
+	writeb(0, &regs->count_lo);
+	writeb(0, &regs->count_mid);
+	writeb(0, &regs->count_hi);
+	writeb(CMD_NOP + CMD_DMA_MODE, &regs->command);
 	udelay(1);
-	eieio();
-	regs->command = CMD_FLUSH;
+	writeb(CMD_FLUSH, &regs->command);
 	udelay(1);
-	eieio();
-	regs->dest_id = cmd->device->id;
-	regs->sync_period = 0;
-	regs->sync_offset = 0;
-	eieio();
+	writeb(cmd->device->id, &regs->dest_id);
+	writeb(0, &regs->sync_period);
+	writeb(0, &regs->sync_offset);
 
 	/* load the command into the FIFO */
-	for (i = 0; i < cmd->cmd_len; ++i) {
-		regs->fifo = cmd->cmnd[i];
-		eieio();
-	}
+	for (i = 0; i < cmd->cmd_len; ++i)
+		writeb(cmd->cmnd[i], &regs->fifo);
 
 	/* do select without ATN XXX */
-	regs->command = CMD_SELECT;
+	writeb(CMD_SELECT, &regs->command);
 	state->phase = selecting;
 
 	if (cmd->use_sg > 0 || cmd->request_bufflen != 0)
 		set_dma_cmds(state, cmd);
 }
 
-static irqreturn_t
-do_mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+static irqreturn_t do_mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
 {
 	unsigned long flags;
 	struct Scsi_Host *dev = ((struct fsc_state *) dev_id)->current_req->device->host;
@@ -328,12 +185,11 @@ do_mac53c94_interrupt(int irq, void *dev
 	return IRQ_HANDLED;
 }
 
-static void
-mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+static void mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
 {
 	struct fsc_state *state = (struct fsc_state *) dev_id;
-	volatile struct mac53c94_regs *regs = state->regs;
-	volatile struct dbdma_regs *dma = state->dma;
+	struct mac53c94_regs *regs = state->regs;
+	struct dbdma_regs *dma = state->dma;
 	Scsi_Cmnd *cmd = state->current_req;
 	int nb, stat, seq, intr;
 	static int mac53c94_errors;
@@ -343,9 +199,9 @@ mac53c94_interrupt(int irq, void *dev_id
 	 * Apparently, reading the interrupt register unlatches
 	 * the status and sequence step registers.
 	 */
-	seq = regs->seqstep;
-	stat = regs->status;
-	intr = regs->interrupt;
+	seq = readb(&regs->seqstep);
+	stat = readb(&regs->status);
+	intr = readb(&regs->interrupt);
 
 #if 0
 	printk(KERN_DEBUG "mac53c94_intr, intr=%x stat=%x seq=%x phase=%d\n",
@@ -355,8 +211,8 @@ mac53c94_interrupt(int irq, void *dev_id
 	if (intr & INTR_RESET) {
 		/* SCSI bus was reset */
 		printk(KERN_INFO "external SCSI bus reset detected\n");
-		regs->command = CMD_NOP;
-		st_le32(&dma->control, RUN << 16);	/* stop dma */
+		writeb(CMD_NOP, &regs->command);
+		writel(RUN << 16, &dma->control);	/* stop dma */
 		cmd_done(state, DID_RESET << 16);
 		return;
 	}
@@ -373,8 +229,7 @@ mac53c94_interrupt(int irq, void *dev_id
 		       intr, stat, seq, state->phase);
 #endif
 		++mac53c94_errors;
-		regs->command = CMD_NOP + CMD_DMA_MODE;
-		eieio();
+		writeb(CMD_NOP + CMD_DMA_MODE, &regs->command);
 	}
 	if (cmd == 0) {
 		printk(KERN_DEBUG "53c94: interrupt with no command active?\n");
@@ -402,7 +257,7 @@ mac53c94_interrupt(int irq, void *dev_id
 			cmd_done(state, DID_ERROR << 16);
 			return;
 		}
-		regs->command = CMD_NOP;
+		writeb(CMD_NOP, &regs->command);
 		/* set DMA controller going if any data to transfer */
 		if ((stat & (STAT_MSG|STAT_CD)) == 0
 		    && (cmd->use_sg > 0 || cmd->request_bufflen != 0)) {
@@ -410,20 +265,17 @@ mac53c94_interrupt(int irq, void *dev_id
 			if (nb > 0xfff0)
 				nb = 0xfff0;
 			cmd->SCp.this_residual -= nb;
-			regs->count_lo = nb;
-			regs->count_mid = nb >> 8;
-			eieio();
-			regs->command = CMD_DMA_MODE + CMD_NOP;
-			eieio();
-			st_le32(&dma->cmdptr, virt_to_phys(state->dma_cmds));
-			st_le32(&dma->control, (RUN << 16) | RUN);
-			eieio();
-			regs->command = CMD_DMA_MODE + CMD_XFER_DATA;
+			writeb(nb, &regs->count_lo);
+			writeb(nb >> 8, &regs->count_mid);
+			writeb(CMD_DMA_MODE + CMD_NOP, &regs->command);
+			writel(virt_to_phys(state->dma_cmds), &dma->cmdptr);
+			writel((RUN << 16) | RUN, &dma->control);
+			writeb(CMD_DMA_MODE + CMD_XFER_DATA, &regs->command);
 			state->phase = dataing;
 			break;
 		} else if ((stat & STAT_PHASE) == STAT_CD + STAT_IO) {
 			/* up to status phase already */
-			regs->command = CMD_I_COMPLETE;
+			writeb(CMD_I_COMPLETE, &regs->command);
 			state->phase = completing;
 		} else {
 			printk(KERN_DEBUG "in unexpected phase %x after cmd\n",
@@ -446,18 +298,16 @@ mac53c94_interrupt(int irq, void *dev_id
 			if (nb > 0xfff0)
 				nb = 0xfff0;
 			cmd->SCp.this_residual -= nb;
-			regs->count_lo = nb;
-			regs->count_mid = nb >> 8;
-			eieio();
-			regs->command = CMD_DMA_MODE + CMD_NOP;
-			eieio();
-			regs->command = CMD_DMA_MODE + CMD_XFER_DATA;
+			writeb(nb, &regs->count_lo);
+			writeb(nb >> 8, &regs->count_mid);
+			writeb(CMD_DMA_MODE + CMD_NOP, &regs->command);
+			writeb(CMD_DMA_MODE + CMD_XFER_DATA, &regs->command);
 			break;
 		}
 		if ((stat & STAT_PHASE) != STAT_CD + STAT_IO) {
 			printk(KERN_DEBUG "intr %x before data xfer complete\n", intr);
 		}
-		out_le32(&dma->control, RUN << 16);	/* stop dma */
+		writel(RUN << 16, &dma->control);	/* stop dma */
 		dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
 		if (cmd->use_sg != 0) {
 			pci_unmap_sg(state->pdev,
@@ -468,7 +318,7 @@ mac53c94_interrupt(int irq, void *dev_id
 				cmd->request_bufflen, dma_dir);
 		}
 		/* should check dma status */
-		regs->command = CMD_I_COMPLETE;
+		writeb(CMD_I_COMPLETE, &regs->command);
 		state->phase = completing;
 		break;
 	case completing:
@@ -477,10 +327,10 @@ mac53c94_interrupt(int irq, void *dev_id
 			cmd_done(state, DID_ERROR << 16);
 			return;
 		}
-		cmd->SCp.Status = regs->fifo; eieio();
-		cmd->SCp.Message = regs->fifo; eieio();
-		cmd->result = 
-		regs->command = CMD_ACCEPT_MSG;
+		cmd->SCp.Status = readb(&regs->fifo);
+		cmd->SCp.Message = readb(&regs->fifo);
+		cmd->result = CMD_ACCEPT_MSG;
+		writeb(CMD_ACCEPT_MSG, &regs->command);
 		state->phase = busfreeing;
 		break;
 	case busfreeing:
@@ -495,8 +345,7 @@ mac53c94_interrupt(int irq, void *dev_id
 	}
 }
 
-static void
-cmd_done(struct fsc_state *state, int result)
+static void cmd_done(struct fsc_state *state, int result)
 {
 	Scsi_Cmnd *cmd;
 
@@ -513,8 +362,7 @@ cmd_done(struct fsc_state *state, int re
 /*
  * Set up DMA commands for transferring data.
  */
-static void
-set_dma_cmds(struct fsc_state *state, Scsi_Cmnd *cmd)
+static void set_dma_cmds(struct fsc_state *state, Scsi_Cmnd *cmd)
 {
 	int i, dma_cmd, total;
 	struct scatterlist *scl;
@@ -523,7 +371,8 @@ set_dma_cmds(struct fsc_state *state, Sc
 	u32 dma_len;
 	int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
 
-	dma_cmd = data_goes_out(cmd)? OUTPUT_MORE: INPUT_MORE;
+	dma_cmd = cmd->sc_data_direction == SCSI_DATA_WRITE? OUTPUT_MORE:
+		INPUT_MORE;
 	dcmds = state->dma_cmds;
 	if (cmd->use_sg > 0) {
 		int nseg;
@@ -562,63 +411,9 @@ set_dma_cmds(struct fsc_state *state, Sc
 	cmd->SCp.this_residual = total;
 }
 
-/*
- * Work out whether data will be going out from the host adaptor or into it.
- */
-static int
-data_goes_out(Scsi_Cmnd *cmd)
-{
-	switch (cmd->sc_data_direction) {
-	case SCSI_DATA_WRITE:
-		return 1;
-	case SCSI_DATA_READ:
-		return 0;
-	}
-
-	/* for SCSI_DATA_UNKNOWN or SCSI_DATA_NONE, fall back on the
-	   old method for now... */
-	switch (cmd->cmnd[0]) {
-	case CHANGE_DEFINITION: 
-	case COMPARE:	  
-	case COPY:
-	case COPY_VERIFY:	    
-	case FORMAT_UNIT:	 
-	case LOG_SELECT:
-	case MEDIUM_SCAN:	  
-	case MODE_SELECT:
-	case MODE_SELECT_10:
-	case REASSIGN_BLOCKS: 
-	case RESERVE:
-	case SEARCH_EQUAL:	  
-	case SEARCH_EQUAL_12: 
-	case SEARCH_HIGH:	 
-	case SEARCH_HIGH_12:  
-	case SEARCH_LOW:
-	case SEARCH_LOW_12:
-	case SEND_DIAGNOSTIC: 
-	case SEND_VOLUME_TAG:	     
-	case SET_WINDOW: 
-	case UPDATE_BLOCK:	
-	case WRITE_BUFFER:
- 	case WRITE_6:	
-	case WRITE_10:	
-	case WRITE_12:	  
-	case WRITE_LONG:	
-	case WRITE_LONG_2:      /* alternate code for WRITE_LONG */
-	case WRITE_SAME:	
-	case WRITE_VERIFY:
-	case WRITE_VERIFY_12:
-		return 1;
-	default:
-		return 0;
-	}
-}
-
-static Scsi_Host_Template driver_template = {
+static Scsi_Host_Template mac53c94_template = {
 	.proc_name	= "53c94",
 	.name		= "53C94",
-	.detect		= mac53c94_detect,
-	.release	= mac53c94_release,
 	.queuecommand	= mac53c94_queue,
 	.eh_abort_handler = mac53c94_abort,
 	.eh_host_reset_handler = mac53c94_host_reset,
@@ -629,4 +424,158 @@ static Scsi_Host_Template driver_templat
 	.use_clustering	= DISABLE_CLUSTERING,
 };
 
-#include "scsi_module.c"
+static int mac53c94_probe(struct macio_dev *mdev, const struct of_match *match)
+{
+	struct device_node *node = macio_get_of_node(mdev);
+	struct pci_dev *pdev = macio_get_pci_dev(mdev);
+	struct fsc_state *state;
+	struct Scsi_Host *host;
+	void *dma_cmd_space;
+	unsigned char *clkprop;
+	int proplen;
+
+	if (macio_resource_count(mdev) != 2 || macio_irq_count(mdev) != 2) {
+		printk(KERN_ERR "mac53c94: expected 2 addrs and intrs (got %d/%d)\n",
+		       node->n_addrs, node->n_intrs);
+		return -ENODEV;
+	}
+
+	if (macio_request_resources(mdev, "mac53c94") != 0) {
+       		printk(KERN_ERR "mac53c94: unable to request memory resources");
+		return -EBUSY;
+	}
+
+       	host = scsi_host_alloc(&mac53c94_template, sizeof(struct fsc_state));
+	if (host == NULL) {
+		printk(KERN_ERR "mac53c94: couldn't register host");
+		goto out_release;
+	}
+
+	state = (struct fsc_state *) host->hostdata;
+	macio_set_drvdata(mdev, state);
+	state->host = host;
+	state->pdev = pdev;
+	state->mdev = mdev;
+
+	state->regs = (struct mac53c94_regs *)
+		ioremap(macio_resource_start(mdev, 0), 0x1000);
+	state->intr = macio_irq(mdev, 0);
+	state->dma = (struct dbdma_regs *)
+		ioremap(macio_resource_start(mdev, 1), 0x1000);
+	state->dmaintr = macio_irq(mdev, 1);
+	if (state->regs == NULL || state->dma == NULL) {
+		printk(KERN_ERR "mac53c94: ioremap failed for %s\n",
+		       node->full_name);
+		goto out_free;
+	}
+
+       	clkprop = get_property(node, "clock-frequency", &proplen);
+       	if (clkprop == NULL || proplen != sizeof(int)) {
+       		printk(KERN_ERR "%s: can't get clock frequency, "
+       		       "assuming 25MHz\n", node->full_name);
+       		state->clk_freq = 25000000;
+       	} else
+       		state->clk_freq = *(int *)clkprop;
+
+       	/* Space for dma command list: +1 for stop command,
+       	 * +1 to allow for aligning.
+	 * XXX FIXME: Use DMA consistent routines
+	 */
+       	dma_cmd_space = kmalloc((host->sg_tablesize + 2) *
+       				sizeof(struct dbdma_cmd), GFP_KERNEL);
+       	if (dma_cmd_space == 0) {
+       		printk(KERN_ERR "mac53c94: couldn't allocate dma "
+       		       "command space for %s\n", node->full_name);
+       		goto out_free;
+       	}
+	state->dma_cmds = (struct dbdma_cmd *)DBDMA_ALIGN(dma_cmd_space);
+	memset(state->dma_cmds, 0, (host->sg_tablesize + 1)
+	       * sizeof(struct dbdma_cmd));
+	state->dma_cmd_space = dma_cmd_space;
+
+	mac53c94_init(state);
+
+	if (request_irq(state->intr, do_mac53c94_interrupt, 0, "53C94", state)) {
+		printk(KERN_ERR "mac53C94: can't get irq %d for %s\n",
+		       state->intr, node->full_name);
+		goto out_free_dma;
+	}
+
+	/* XXX FIXME: handle failure */
+	scsi_add_host(host, &mdev->ofdev.dev);
+	scsi_scan_host(host);
+
+	return 0;
+
+ out_free_dma:
+	kfree(state->dma_cmd_space);
+ out_free:
+	if (state->dma != NULL)
+		iounmap(state->dma);
+	if (state->regs != NULL)
+		iounmap(state->regs);
+	scsi_host_put(host);
+ out_release:
+	macio_release_resources(mdev);
+
+	return  -ENODEV;
+}
+
+static int mac53c94_remove(struct macio_dev *mdev)
+{
+	struct fsc_state *fp = (struct fsc_state *)macio_get_drvdata(mdev);
+	struct Scsi_Host *host = fp->host;
+
+	scsi_remove_host(host);
+
+	free_irq(fp->intr, fp);
+
+	if (fp->regs)
+		iounmap((void *) fp->regs);
+	if (fp->dma)
+		iounmap((void *) fp->dma);
+	kfree(fp->dma_cmd_space);
+
+	scsi_host_put(host);
+
+	macio_release_resources(mdev);
+
+	return 0;
+}
+
+
+static struct of_match mac53c94_match[] = 
+{
+	{
+	.name 		= "53c94",
+	.type		= OF_ANY_MATCH,
+	.compatible	= OF_ANY_MATCH
+	},
+	{},
+};
+
+static struct macio_driver mac53c94_driver = 
+{
+	.name 		= "mac53c94",
+	.match_table	= mac53c94_match,
+	.probe		= mac53c94_probe,
+	.remove		= mac53c94_remove,
+};
+
+
+static int __init init_mac53c94(void)
+{
+	return macio_register_driver(&mac53c94_driver);
+}
+
+static void __exit exit_mac53c94(void)
+{
+	return macio_unregister_driver(&mac53c94_driver);
+}
+
+module_init(init_mac53c94);
+module_exit(exit_mac53c94);
+
+MODULE_DESCRIPTION("PowerMac 53c94 SCSI driver");
+MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>");
+MODULE_LICENSE("GPL");
diff -puN drivers/scsi/mesh.c~big-pmac-3 drivers/scsi/mesh.c
--- 25/drivers/scsi/mesh.c~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/drivers/scsi/mesh.c	2004-01-28 23:09:16.000000000 -0800
@@ -10,9 +10,13 @@
  * Apr. 21 2002  - BenH		Rework bus reset code for new error handler
  *                              Add delay after initial bus reset
  *                              Add module parameters
+ *
+ * Sep. 27 2003  - BenH		Move to new driver model, fix some write posting
+ *				issues
  * To do:
  * - handle aborts correctly
  * - retry arbitration if lost (unless higher levels do this for us)
+ * - power down the chip when no device is detected
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -38,10 +42,7 @@
 #include <asm/machdep.h>
 #include <asm/pmac_feature.h>
 #include <asm/pci-bridge.h>
-#ifdef CONFIG_PMAC_PBOOK
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#endif
+#include <asm/macio.h>
 
 #include "scsi.h"
 #include "hosts.h"
@@ -164,10 +165,12 @@ struct mesh_state {
 	int	last_n_msgout;
 	u8	msgout[16];
 	struct dbdma_cmd *dma_cmds;	/* space for dbdma commands, aligned */
+	dma_addr_t dma_cmd_bus;
+	void	*dma_cmd_space;
+	int	dma_cmd_size;
 	int	clk_freq;
 	struct mesh_target tgts[8];
-	void	*dma_cmd_space;
-	struct device_node *ofnode;
+	struct macio_dev *mdev;
 	struct pci_dev* pdev;
 #ifdef MESH_DBG
 	int	log_ix;
@@ -176,324 +179,124 @@ struct mesh_state {
 #endif
 };
 
-#ifdef MESH_DBG
-
-static void dlog(struct mesh_state *ms, char *fmt, int a);
-static void dumplog(struct mesh_state *ms, int tgt);
-static void dumpslog(struct mesh_state *ms);
-
-#else
-static inline void dlog(struct mesh_state *ms, char *fmt, int a)
-{}
-static inline void dumplog(struct mesh_state *ms, int tgt)
-{}
-static inline void dumpslog(struct mesh_state *ms)
-{}
-
-#endif /* MESH_DBG */
-#define MKWORD(a, b, c, d)	(((a) << 24) + ((b) << 16) + ((c) << 8) + (d))
+/*
+ * Driver is too messy, we need a few prototypes...
+ */
+static void mesh_done(struct mesh_state *ms, int start_next);
+static void mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs);
+static void cmd_complete(struct mesh_state *ms);
+static void set_dma_cmds(struct mesh_state *ms, Scsi_Cmnd *cmd);
+static void halt_dma(struct mesh_state *ms);
+static void phase_mismatch(struct mesh_state *ms);
 
-static struct mesh_state *all_meshes;
 
-static void mesh_init(struct mesh_state *);
-static int mesh_notify_reboot(struct notifier_block *, unsigned long, void *);
-static void mesh_dump_regs(struct mesh_state *);
-static void mesh_start(struct mesh_state *);
-static void mesh_start_cmd(struct mesh_state *, Scsi_Cmnd *);
-static void add_sdtr_msg(struct mesh_state *);
-static void set_sdtr(struct mesh_state *, int, int);
-static void start_phase(struct mesh_state *);
-static void get_msgin(struct mesh_state *);
-static int msgin_length(struct mesh_state *);
-static void cmd_complete(struct mesh_state *);
-static void phase_mismatch(struct mesh_state *);
-static void reselected(struct mesh_state *);
-static void handle_reset(struct mesh_state *);
-static void handle_error(struct mesh_state *);
-static void handle_exception(struct mesh_state *);
-static void mesh_interrupt(int, void *, struct pt_regs *);
-static irqreturn_t do_mesh_interrupt(int, void *, struct pt_regs *);
-static void handle_msgin(struct mesh_state *);
-static void mesh_done(struct mesh_state *, int);
-static void mesh_completed(struct mesh_state *, Scsi_Cmnd *);
-static void set_dma_cmds(struct mesh_state *, Scsi_Cmnd *);
-static void halt_dma(struct mesh_state *);
-static int data_goes_out(Scsi_Cmnd *);
-static void do_abort(struct mesh_state *ms);
-static void set_mesh_power(struct mesh_state *ms, int state);
-
-#ifdef CONFIG_PMAC_PBOOK
-static int mesh_notify_sleep(struct pmu_sleep_notifier *self, int when);
-static struct pmu_sleep_notifier mesh_sleep_notifier = {
-	mesh_notify_sleep,
-	SLEEP_LEVEL_BLOCK,
-};
-#endif
+/*
+ * Some debugging & logging routines
+ */
 
-static struct notifier_block mesh_notifier = {
-	mesh_notify_reboot,
-	NULL,
-	0
-};
+#ifdef MESH_DBG
 
-int
-mesh_detect(Scsi_Host_Template *tp)
+static inline u32 readtb(void)
 {
-	struct device_node *mesh;
-	int nmeshes, tgt, *cfp, minper;
-	struct mesh_state *ms, **prev_statep;
-	struct Scsi_Host *mesh_host;
-	void *dma_cmd_space;
-
-	if (_machine == _MACH_Pmac) {
-	    use_active_neg = (find_devices("mac-io") ? 0 : SEQ_ACTIVE_NEG);
-	} else {
-	    /* CHRP mac-io */
-	    use_active_neg = SEQ_ACTIVE_NEG;
-	}
-
-	/* Calculate sync rate from module parameters */
-	if (sync_rate > 10)
-		sync_rate = 10;
-	if (sync_rate > 0) {
-		printk(KERN_INFO "mesh: configured for synchronous %d MB/s\n", sync_rate);
-		mesh_sync_period = 1000 / sync_rate;	/* ns */
-		mesh_sync_offset = 15;
-	} else
-		printk(KERN_INFO "mesh: configured for asynchronous\n");
-
-	nmeshes = 0;
-	prev_statep = &all_meshes;
-	/*
-	 * On powermacs, the MESH node has device_type "mesh".
-	 * On chrp machines, its device_type is "scsi" with
-	 * "chrp,mesh0" as its `compatible' property.
-	 */
-	mesh = find_devices("mesh");
-	if (mesh == 0)
-		mesh = find_compatible_devices("scsi", "chrp,mesh0");
-	for (; mesh != 0; mesh = mesh->next) {
-		u8 pci_bus, pci_devfn;
-		struct pci_dev* pdev = NULL;
-		
-		if (mesh->n_addrs != 2 || mesh->n_intrs != 2) {
-			printk(KERN_ERR "mesh: expected 2 addrs and 2 intrs"
-			       " (got %d,%d)\n", mesh->n_addrs, mesh->n_intrs);
-			continue;
-		}
-		if (mesh->parent != NULL
-		    && pci_device_from_OF_node(mesh->parent, &pci_bus,
-					       &pci_devfn) == 0)
-			pdev = pci_find_slot(pci_bus, pci_devfn);
-		if (pdev == NULL) {
-			printk(KERN_ERR "mesh: Can't locate PCI entry\n");
-			continue;
-		}
+	u32 tb;
 
-		mesh_host = scsi_register(tp, sizeof(struct mesh_state));
-		if (mesh_host == 0) {
-			printk(KERN_ERR "mesh: couldn't register host");
-			continue;
-		}
-		mesh_host->unique_id = nmeshes;
-#if !defined(MODULE)
-		note_scsi_host(mesh, mesh_host);
+#ifdef DBG_USE_TB
+	/* Beware: if you enable this, it will crash on 601s. */
+	asm ("mftb %0" : "=r" (tb) : );
+#else
+	tb = 0;
 #endif
-
-		ms = (struct mesh_state *) mesh_host->hostdata;
-		if (ms == 0)
-			panic("no mesh state");
-		memset(ms, 0, sizeof(*ms));
-		ms->host = mesh_host;
-		ms->ofnode = mesh;
-		ms->pdev = pdev;
-		ms->mesh = (volatile struct mesh_regs *)
-			ioremap(mesh->addrs[0].address, 0x1000);
-		ms->dma = (volatile struct dbdma_regs *)
-			ioremap(mesh->addrs[1].address, 0x1000);
-		ms->meshintr = mesh->intrs[0].line;
-		ms->dmaintr = mesh->intrs[1].line;
-
-		/* Space for dma command list: +1 for stop command,
-		   +1 to allow for aligning. */
-		dma_cmd_space = kmalloc((mesh_host->sg_tablesize + 2) *
-					sizeof(struct dbdma_cmd), GFP_KERNEL);
-		if (dma_cmd_space == 0)
-			panic("mesh: couldn't allocate dma command space");
-		ms->dma_cmds = (struct dbdma_cmd *) DBDMA_ALIGN(dma_cmd_space);
-		memset(ms->dma_cmds, 0, (mesh_host->sg_tablesize + 1)
-		       * sizeof(struct dbdma_cmd));
-		ms->dma_cmd_space = dma_cmd_space;
-
-		ms->current_req = 0;
-		for (tgt = 0; tgt < 8; ++tgt) {
-			ms->tgts[tgt].sdtr_state = do_sdtr;
-			ms->tgts[tgt].sync_params = ASYNC_PARAMS;
-			ms->tgts[tgt].current_req = 0;
-		}
-		*prev_statep = ms;
-		prev_statep = &ms->next;
-
-		if ((cfp = (int *) get_property(mesh, "clock-frequency",
-						NULL))) {
-			ms->clk_freq = *cfp;
-		} else {
-			printk(KERN_INFO "mesh: assuming 50MHz clock frequency\n");
-			ms->clk_freq = 50000000;
-		}
-		/* The maximum sync rate is clock / 5; increase
-		   mesh_sync_period if necessary. */
-		minper = 1000000000 / (ms->clk_freq / 5);	/* ns */
-		if (mesh_sync_period < minper)
-			mesh_sync_period = minper;
-
-		set_mesh_power(ms, 1);
-
-		mesh_init(ms);
-
-		if (request_irq(ms->meshintr, do_mesh_interrupt, 0, "MESH", ms)) {
-			printk(KERN_ERR "MESH: can't get irq %d\n", ms->meshintr);
-		}
-
-		++nmeshes;
-	}
-
-	if ((_machine == _MACH_Pmac) && (nmeshes > 0)) {
-#ifdef CONFIG_PMAC_PBOOK
-		pmu_register_sleep_notifier(&mesh_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
-		register_reboot_notifier(&mesh_notifier);
-	}
-
-	return nmeshes;
+	return tb;
 }
 
-int
-mesh_release(struct Scsi_Host *host)
+static void dlog(struct mesh_state *ms, char *fmt, int a)
 {
-	struct mesh_state *ms = (struct mesh_state *) host->hostdata;
+	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
+	struct dbglog *tlp, *slp;
 
-	if (ms == 0)
-		return 0;
-	if (ms->mesh)
-		iounmap((void *) ms->mesh);
-	if (ms->dma)
-		iounmap((void *) ms->dma);
-	kfree(ms->dma_cmd_space);
-	free_irq(ms->meshintr, ms);
-	pmac_call_feature(PMAC_FTR_MESH_ENABLE, ms->ofnode, 0, 0);
-	return 0;
+	tlp = &tp->log[tp->log_ix];
+	slp = &ms->log[ms->log_ix];
+	tlp->fmt = fmt;
+	tlp->tb = readtb();
+	tlp->phase = (ms->msgphase << 4) + ms->phase;
+	tlp->bs0 = ms->mesh->bus_status0;
+	tlp->bs1 = ms->mesh->bus_status1;
+	tlp->tgt = ms->conn_tgt;
+	tlp->d = a;
+	*slp = *tlp;
+	if (++tp->log_ix >= N_DBG_LOG)
+		tp->log_ix = 0;
+	if (tp->n_log < N_DBG_LOG)
+		++tp->n_log;
+	if (++ms->log_ix >= N_DBG_SLOG)
+		ms->log_ix = 0;
+	if (ms->n_log < N_DBG_SLOG)
+		++ms->n_log;
 }
 
-static void
-set_mesh_power(struct mesh_state *ms, int state)
+static void dumplog(struct mesh_state *ms, int t)
 {
-	if (_machine != _MACH_Pmac)
-		return;
-	if (state) {
-		pmac_call_feature(PMAC_FTR_MESH_ENABLE, ms->ofnode, 0, 1);
-		mdelay(200);
-	} else {
-		pmac_call_feature(PMAC_FTR_MESH_ENABLE, ms->ofnode, 0, 0);
-		mdelay(10);
-	}
-}			
+	struct mesh_target *tp = &ms->tgts[t];
+	struct dbglog *lp;
+	int i;
 
-#ifdef CONFIG_PMAC_PBOOK
-/*
- * notify clients before sleep and reset bus afterwards
- */
-int
-mesh_notify_sleep(struct pmu_sleep_notifier *self, int when)
-{
-	struct mesh_state *ms;
-	
-	switch (when) {
-	case PBOOK_SLEEP_REQUEST:
-		/* XXX We should wait for current transactions and queue
-		 * new ones that would be posted beyond this point 
-		 */ 
-		break;
-	case PBOOK_SLEEP_REJECT:
-		break;
-		
-	case PBOOK_SLEEP_NOW:
-		for (ms = all_meshes; ms != 0; ms = ms->next) {
-			unsigned long flags;
-
-			scsi_block_requests(ms->host);
-			spin_lock_irqsave(ms->host->host_lock, flags);
-			while(ms->phase != idle) {
-				spin_unlock_irqrestore(ms->host->host_lock, flags);
-				current->state = TASK_UNINTERRUPTIBLE;
-				schedule_timeout(1);
-				spin_lock_irqsave(ms->host->host_lock, flags);
-			}
-			ms->phase = sleeping;
-			spin_unlock_irqrestore(ms->host->host_lock, flags);
-			disable_irq(ms->meshintr);
-			set_mesh_power(ms, 0);
-		}
-		break;
-	case PBOOK_WAKE:
-		for (ms = all_meshes; ms != 0; ms = ms->next) {
-			unsigned long flags;
-			
-			set_mesh_power(ms, 1);
-			mesh_init(ms);
-			spin_lock_irqsave(ms->host->host_lock, flags);
-			mesh_start(ms);
-			spin_unlock_irqrestore(ms->host->host_lock, flags);
-			enable_irq(ms->meshintr);
-			scsi_unblock_requests(ms->host);
-		}
-		break;
-	}
-	return PBOOK_SLEEP_OK;
+	if (tp->n_log == 0)
+		return;
+	i = tp->log_ix - tp->n_log;
+	if (i < 0)
+		i += N_DBG_LOG;
+	tp->n_log = 0;
+	do {
+		lp = &tp->log[i];
+		printk(KERN_DEBUG "mesh log %d: bs=%.2x%.2x ph=%.2x ",
+		       t, lp->bs1, lp->bs0, lp->phase);
+#ifdef DBG_USE_TB
+		printk("tb=%10u ", lp->tb);
+#endif
+		printk(lp->fmt, lp->d);
+		printk("\n");
+		if (++i >= N_DBG_LOG)
+			i = 0;
+	} while (i != tp->log_ix);
 }
-#endif /* CONFIG_PMAC_PBOOK */
 
-/*
- * Called by midlayer with host locked to queue a new
- * request
- */
-int
-mesh_queue(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+static void dumpslog(struct mesh_state *ms)
 {
-	struct mesh_state *ms;
-
-	cmd->scsi_done = done;
-	cmd->host_scribble = NULL;
-
-	ms = (struct mesh_state *) cmd->device->host->hostdata;
+	struct dbglog *lp;
+	int i;
 
-	if (ms->request_q == NULL)
-		ms->request_q = cmd;
-	else
-		ms->request_qtail->host_scribble = (void *) cmd;
-	ms->request_qtail = cmd;
+	if (ms->n_log == 0)
+		return;
+	i = ms->log_ix - ms->n_log;
+	if (i < 0)
+		i += N_DBG_SLOG;
+	ms->n_log = 0;
+	do {
+		lp = &ms->log[i];
+		printk(KERN_DEBUG "mesh log: bs=%.2x%.2x ph=%.2x t%d ",
+		       lp->bs1, lp->bs0, lp->phase, lp->tgt);
+#ifdef DBG_USE_TB
+		printk("tb=%10u ", lp->tb);
+#endif
+		printk(lp->fmt, lp->d);
+		printk("\n");
+		if (++i >= N_DBG_SLOG)
+			i = 0;
+	} while (i != ms->log_ix);
+}
 
-	if (ms->phase == idle)
-		mesh_start(ms);
+#else
 
-	return 0;
-}
+static inline void dlog(struct mesh_state *ms, char *fmt, int a)
+{}
+static inline void dumplog(struct mesh_state *ms, int tgt)
+{}
+static inline void dumpslog(struct mesh_state *ms)
+{}
 
-/* Todo: here we can at least try to remove the command from the
- * queue if it isn't connected yet, and for pending command, assert
- * ATN until the bus gets freed.
- */
-int
-mesh_abort(Scsi_Cmnd *cmd)
-{
-	struct mesh_state *ms = (struct mesh_state *) cmd->device->host->hostdata;
+#endif /* MESH_DBG */
 
-	printk(KERN_DEBUG "mesh_abort(%p)\n", cmd);
-	mesh_dump_regs(ms);
-	dumplog(ms, cmd->device->id);
-	dumpslog(ms);
-	return SCSI_ABORT_SNOOZE;
-}
+#define MKWORD(a, b, c, d)	(((a) << 24) + ((b) << 16) + ((c) << 8) + (d))
 
 static void
 mesh_dump_regs(struct mesh_state *ms)
@@ -528,79 +331,35 @@ mesh_dump_regs(struct mesh_state *ms)
 	}
 }
 
+
 /*
- * Called by the midlayer with the lock held to reset the
- * SCSI host and bus.
- * The midlayer will wait for devices to come back, we don't need
- * to do that ourselves
+ * Flush write buffers on the bus path to the mesh
  */
-int
-mesh_host_reset(Scsi_Cmnd *cmd)
+static inline void mesh_flush_io(volatile struct mesh_regs *mr)
 {
-	struct mesh_state *ms = (struct mesh_state *) cmd->device->host->hostdata;
-	volatile struct mesh_regs *mr = ms->mesh;
-	volatile struct dbdma_regs *md = ms->dma;
-
-	printk(KERN_DEBUG "mesh_host_reset\n");
-
-	/* Reset the controller & dbdma channel */
-	out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16);	/* stop dma */
-	out_8(&mr->exception, 0xff);	/* clear all exception bits */
-	out_8(&mr->error, 0xff);	/* clear all error bits */
-	out_8(&mr->sequence, SEQ_RESETMESH);
-	udelay(1);
-	out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
-	out_8(&mr->source_id, ms->host->this_id);
-	out_8(&mr->sel_timeout, 25);	/* 250ms */
-	out_8(&mr->sync_params, ASYNC_PARAMS);
-
-	/* Reset the bus */
-	out_8(&mr->bus_status1, BS1_RST);	/* assert RST */
-	udelay(30);			/* leave it on for >= 25us */
-	out_8(&mr->bus_status1, 0);	/* negate RST */
-
-	/* Complete pending commands */
-	handle_reset(ms);
-	
-	return SUCCESS;
+	(void)in_8(&mr->mesh_id);
 }
 
+
 /*
- * If we leave drives set for synchronous transfers (especially
- * CDROMs), and reboot to MacOS, it gets confused, poor thing.
- * So, on reboot we reset the SCSI bus.
+ * Complete a SCSI command
  */
-static int
-mesh_notify_reboot(struct notifier_block *this, unsigned long code, void *x)
+static void mesh_completed(struct mesh_state *ms, Scsi_Cmnd *cmd)
 {
-	struct mesh_state *ms;
-	volatile struct mesh_regs *mr;
-
-	if (code == SYS_DOWN) {
-		printk(KERN_INFO "resetting MESH scsi bus(es)\n");
-		for (ms = all_meshes; ms != 0; ms = ms->next) {
-			mr = ms->mesh;
-			out_8(&mr->intr_mask, 0);
-			out_8(&mr->interrupt,
-			      INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
-			out_8(&mr->bus_status1, BS1_RST);
-			udelay(30);
-			out_8(&mr->bus_status1, 0);
-		}
-	}
-	return NOTIFY_DONE;
+	(*cmd->scsi_done)(cmd);
 }
 
+
 /* Called with  meshinterrupt disabled, initialize the chipset
  * and eventually do the initial bus reset. The lock must not be
  * held since we can schedule.
  */
-static void
-mesh_init(struct mesh_state *ms)
+static void mesh_init(struct mesh_state *ms)
 {
 	volatile struct mesh_regs *mr = ms->mesh;
 	volatile struct dbdma_regs *md = ms->dma;
 
+	mesh_flush_io(mr);
 	udelay(100);
 
 	/* Reset controller */
@@ -608,6 +367,7 @@ mesh_init(struct mesh_state *ms)
 	out_8(&mr->exception, 0xff);	/* clear all exception bits */
 	out_8(&mr->error, 0xff);	/* clear all error bits */
 	out_8(&mr->sequence, SEQ_RESETMESH);
+	mesh_flush_io(mr);
 	udelay(10);
 	out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
 	out_8(&mr->source_id, ms->host->this_id);
@@ -619,8 +379,10 @@ mesh_init(struct mesh_state *ms)
 		
 		/* Reset bus */
 		out_8(&mr->bus_status1, BS1_RST);	/* assert RST */
+		mesh_flush_io(mr);
 		udelay(30);			/* leave it on for >= 25us */
 		out_8(&mr->bus_status1, 0);	/* negate RST */
+		mesh_flush_io(mr);
 
 		/* Wait for bus to come back */
 		current->state = TASK_UNINTERRUPTIBLE;
@@ -630,6 +392,7 @@ mesh_init(struct mesh_state *ms)
 	/* Reconfigure controller */
 	out_8(&mr->interrupt, 0xff);	/* clear all interrupt bits */
 	out_8(&mr->sequence, SEQ_FLUSHFIFO);
+	mesh_flush_io(mr);
 	udelay(1);
 	out_8(&mr->sync_params, ASYNC_PARAMS);
 	out_8(&mr->sequence, SEQ_ENBRESEL);
@@ -638,51 +401,15 @@ mesh_init(struct mesh_state *ms)
 	ms->msgphase = msg_none;
 }
 
-/*
- * Start the next command for a MESH.
- * Should be called with interrupts disabled.
- */
-static void
-mesh_start(struct mesh_state *ms)
+
+static void mesh_start_cmd(struct mesh_state *ms, Scsi_Cmnd *cmd)
 {
-	Scsi_Cmnd *cmd, *prev, *next;
-
-	if (ms->phase != idle || ms->current_req != NULL) {
-		printk(KERN_ERR "inappropriate mesh_start (phase=%d, ms=%p)",
-		       ms->phase, ms);
-		return;
-	}
-
-	while (ms->phase == idle) {
-		prev = NULL;
-		for (cmd = ms->request_q; ; cmd = (Scsi_Cmnd *) cmd->host_scribble) {
-			if (cmd == NULL)
-				return;
-			if (ms->tgts[cmd->device->id].current_req == NULL)
-				break;
-			prev = cmd;
-		}
-		next = (Scsi_Cmnd *) cmd->host_scribble;
-		if (prev == NULL)
-			ms->request_q = next;
-		else
-			prev->host_scribble = (void *) next;
-		if (next == NULL)
-			ms->request_qtail = prev;
-
-		mesh_start_cmd(ms, cmd);
-	}
-}
-
-static void
-mesh_start_cmd(struct mesh_state *ms, Scsi_Cmnd *cmd)
-{
-	volatile struct mesh_regs *mr = ms->mesh;
-	int t, id;
+	volatile struct mesh_regs *mr = ms->mesh;
+	int t, id;
 
 	id = cmd->device->id;
 	ms->current_req = cmd;
-	ms->tgts[id].data_goes_out = data_goes_out(cmd);
+	ms->tgts[id].data_goes_out = cmd->sc_data_direction == SCSI_DATA_WRITE;
 	ms->tgts[id].current_req = cmd;
 
 #if 1
@@ -720,9 +447,10 @@ mesh_start_cmd(struct mesh_state *ms, Sc
 	     MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count));
 	out_8(&mr->interrupt, INT_CMDDONE);
 	out_8(&mr->sequence, SEQ_ENBRESEL);
+	mesh_flush_io(mr);
 	udelay(1);
 
-	if (mr->bus_status1 & (BS1_BSY | BS1_SEL)) {
+	if (in_8(&mr->bus_status1) & (BS1_BSY | BS1_SEL)) {
 		/*
 		 * Some other device has the bus or is arbitrating for it -
 		 * probably a target which is about to reselect us.
@@ -731,7 +459,7 @@ mesh_start_cmd(struct mesh_state *ms, Sc
 		     MKWORD(mr->interrupt, mr->exception,
 			    mr->error, mr->fifo_count));
 		for (t = 100; t > 0; --t) {
-			if ((mr->bus_status1 & (BS1_BSY | BS1_SEL)) == 0)
+			if ((in_8(&mr->bus_status1) & (BS1_BSY | BS1_SEL)) == 0)
 				break;
 			if (in_8(&mr->interrupt) != 0) {
 				dlog(ms, "intr b4 arb, intr/exc/err/fc=%.8x",
@@ -743,7 +471,7 @@ mesh_start_cmd(struct mesh_state *ms, Sc
 			}
 			udelay(1);
 		}
-		if (mr->bus_status1 & (BS1_BSY | BS1_SEL)) {
+		if (in_8(&mr->bus_status1) & (BS1_BSY | BS1_SEL)) {
 			/* XXX should try again in a little while */
 			ms->stat = DID_BUS_BUSY;
 			ms->phase = idle;
@@ -792,23 +520,25 @@ mesh_start_cmd(struct mesh_state *ms, Sc
 	}
 	dlog(ms, "after arb, intr/exc/err/fc=%.8x",
 	     MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count));
-	if (mr->interrupt == 0 && (mr->bus_status1 & BS1_SEL)
-	    && (mr->bus_status0 & BS0_IO)) {
+	if (in_8(&mr->interrupt) == 0 && (in_8(&mr->bus_status1) & BS1_SEL)
+	    && (in_8(&mr->bus_status0) & BS0_IO)) {
 		/* looks like a reselection - try resetting the mesh */
 		dlog(ms, "resel? after arb, intr/exc/err/fc=%.8x",
 		     MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count));
 		out_8(&mr->sequence, SEQ_RESETMESH);
+		mesh_flush_io(mr);
 		udelay(10);
 		out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
 		out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
 		out_8(&mr->sequence, SEQ_ENBRESEL);
-		for (t = 10; t > 0 && mr->interrupt == 0; --t)
+		mesh_flush_io(mr);
+		for (t = 10; t > 0 && in_8(&mr->interrupt) == 0; --t)
 			udelay(1);
 		dlog(ms, "tried reset after arb, intr/exc/err/fc=%.8x",
 		     MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count));
 #ifndef MESH_MULTIPLE_HOSTS
-		if (mr->interrupt == 0 && (mr->bus_status1 & BS1_SEL)
-		    && (mr->bus_status0 & BS0_IO)) {
+		if (in_8(&mr->interrupt) == 0 && (in_8(&mr->bus_status1) & BS1_SEL)
+		    && (in_8(&mr->bus_status0) & BS0_IO)) {
 			printk(KERN_ERR "mesh: controller not responding"
 			       " to reselection!\n");
 			/*
@@ -822,8 +552,76 @@ mesh_start_cmd(struct mesh_state *ms, Sc
 	}
 }
 
-static inline void
-add_sdtr_msg(struct mesh_state *ms)
+/*
+ * Start the next command for a MESH.
+ * Should be called with interrupts disabled.
+ */
+static void mesh_start(struct mesh_state *ms)
+{
+	Scsi_Cmnd *cmd, *prev, *next;
+
+	if (ms->phase != idle || ms->current_req != NULL) {
+		printk(KERN_ERR "inappropriate mesh_start (phase=%d, ms=%p)",
+		       ms->phase, ms);
+		return;
+	}
+
+	while (ms->phase == idle) {
+		prev = NULL;
+		for (cmd = ms->request_q; ; cmd = (Scsi_Cmnd *) cmd->host_scribble) {
+			if (cmd == NULL)
+				return;
+			if (ms->tgts[cmd->device->id].current_req == NULL)
+				break;
+			prev = cmd;
+		}
+		next = (Scsi_Cmnd *) cmd->host_scribble;
+		if (prev == NULL)
+			ms->request_q = next;
+		else
+			prev->host_scribble = (void *) next;
+		if (next == NULL)
+			ms->request_qtail = prev;
+
+		mesh_start_cmd(ms, cmd);
+	}
+}
+
+static void mesh_done(struct mesh_state *ms, int start_next)
+{
+	Scsi_Cmnd *cmd;
+	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
+
+	cmd = ms->current_req;
+	ms->current_req = 0;
+	tp->current_req = 0;
+	if (cmd) {
+		cmd->result = (ms->stat << 16) + cmd->SCp.Status;
+		if (ms->stat == DID_OK)
+			cmd->result += (cmd->SCp.Message << 8);
+		if (DEBUG_TARGET(cmd)) {
+			printk(KERN_DEBUG "mesh_done: result = %x, data_ptr=%d, buflen=%d\n",
+			       cmd->result, ms->data_ptr, cmd->request_bufflen);
+			if ((cmd->cmnd[0] == 0 || cmd->cmnd[0] == 0x12 || cmd->cmnd[0] == 3)
+			    && cmd->request_buffer != 0) {
+				unsigned char *b = cmd->request_buffer;
+				printk(KERN_DEBUG "buffer = %x %x %x %x %x %x %x %x\n",
+				       b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
+			}
+		}
+		cmd->SCp.this_residual -= ms->data_ptr;
+		mesh_completed(ms, cmd);
+	}
+	if (start_next) {
+		out_8(&ms->mesh->sequence, SEQ_ENBRESEL);
+		mesh_flush_io(ms->mesh);
+		udelay(1);
+		ms->phase = idle;
+		mesh_start(ms);
+	}
+}
+
+static inline void add_sdtr_msg(struct mesh_state *ms)
 {
 	int i = ms->n_msgout;
 
@@ -835,8 +633,7 @@ add_sdtr_msg(struct mesh_state *ms)
 	ms->n_msgout = i + 5;
 }
 
-static void
-set_sdtr(struct mesh_state *ms, int period, int offset)
+static void set_sdtr(struct mesh_state *ms, int period, int offset)
 {
 	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
 	volatile struct mesh_regs *mr = ms->mesh;
@@ -877,8 +674,7 @@ set_sdtr(struct mesh_state *ms, int peri
 	       ms->conn_tgt, tr/10, tr%10);
 }
 
-static void
-start_phase(struct mesh_state *ms)
+static void start_phase(struct mesh_state *ms)
 {
 	int i, seq, nb;
 	volatile struct mesh_regs *mr = ms->mesh;
@@ -925,14 +721,16 @@ start_phase(struct mesh_state *ms)
 						ms->msgout[1], ms->msgout[2]));
 		out_8(&mr->count_hi, 0);
 		out_8(&mr->sequence, SEQ_FLUSHFIFO);
+		mesh_flush_io(mr);
 		udelay(1);
 		/*
 		 * If ATN is not already asserted, we assert it, then
 		 * issue a SEQ_MSGOUT to get the mesh to drop ACK.
 		 */
-		if ((mr->bus_status0 & BS0_ATN) == 0) {
+		if ((in_8(&mr->bus_status0) & BS0_ATN) == 0) {
 			dlog(ms, "bus0 was %.2x explictly asserting ATN", mr->bus_status0);
 			out_8(&mr->bus_status0, BS0_ATN); /* explicit ATN */
+			mesh_flush_io(mr);
 			udelay(1);
 			out_8(&mr->count_lo, 1);
 			out_8(&mr->sequence, SEQ_MSGOUT + seq);
@@ -1006,6 +804,7 @@ start_phase(struct mesh_state *ms)
 	case busfreeing:
 	case disconnecting:
 		out_8(&mr->sequence, SEQ_ENBRESEL);
+		mesh_flush_io(mr);
 		udelay(1);
 		dlog(ms, "enbresel intr/exc/err/fc=%.8x",
 		     MKWORD(mr->interrupt, mr->exception, mr->error,
@@ -1020,8 +819,7 @@ start_phase(struct mesh_state *ms)
 
 }
 
-static inline void
-get_msgin(struct mesh_state *ms)
+static inline void get_msgin(struct mesh_state *ms)
 {
 	volatile struct mesh_regs *mr = ms->mesh;
 	int i, n;
@@ -1035,8 +833,7 @@ get_msgin(struct mesh_state *ms)
 	}
 }
 
-static inline int
-msgin_length(struct mesh_state *ms)
+static inline int msgin_length(struct mesh_state *ms)
 {
 	int b, n;
 
@@ -1054,349 +851,95 @@ msgin_length(struct mesh_state *ms)
 	return n;
 }
 
-static void
-cmd_complete(struct mesh_state *ms)
+static void reselected(struct mesh_state *ms)
 {
 	volatile struct mesh_regs *mr = ms->mesh;
-	Scsi_Cmnd *cmd = ms->current_req;
-	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
-	int seq, n, t;
-
-	dlog(ms, "cmd_complete fc=%x", mr->fifo_count);
-	seq = use_active_neg + (ms->n_msgout? SEQ_ATN: 0);
-	switch (ms->msgphase) {
-	case msg_out_xxx:
-		/* huh?  we expected a phase mismatch */
-		ms->n_msgin = 0;
-		ms->msgphase = msg_in;
-		/* fall through */
+	Scsi_Cmnd *cmd;
+	struct mesh_target *tp;
+	int b, t, prev;
 
-	case msg_in:
-		/* should have some message bytes in fifo */
-		get_msgin(ms);
-		n = msgin_length(ms);
-		if (ms->n_msgin < n) {
-			out_8(&mr->count_lo, n - ms->n_msgin);
-			out_8(&mr->sequence, SEQ_MSGIN + seq);
-		} else {
-			ms->msgphase = msg_none;
-			handle_msgin(ms);
-			start_phase(ms);
+	switch (ms->phase) {
+	case idle:
+		break;
+	case arbitrating:
+		if ((cmd = ms->current_req) != NULL) {
+			/* put the command back on the queue */
+			cmd->host_scribble = (void *) ms->request_q;
+			if (ms->request_q == NULL)
+				ms->request_qtail = cmd;
+			ms->request_q = cmd;
+			tp = &ms->tgts[cmd->device->id];
+			tp->current_req = NULL;
 		}
 		break;
+	case busfreeing:
+		ms->phase = reselecting;
+		mesh_done(ms, 0);
+		break;
+	case disconnecting:
+		break;
+	default:
+		printk(KERN_ERR "mesh: reselected in phase %d/%d tgt %d\n",
+		       ms->msgphase, ms->phase, ms->conn_tgt);
+		dumplog(ms, ms->conn_tgt);
+		dumpslog(ms);
+	}
 
-	case msg_in_bad:
-		out_8(&mr->sequence, SEQ_FLUSHFIFO);
+	if (ms->dma_started) {
+		printk(KERN_ERR "mesh: reselected with DMA started !\n");
+		halt_dma(ms);
+	}
+	ms->current_req = NULL;
+	ms->phase = dataing;
+	ms->msgphase = msg_in;
+	ms->n_msgout = 0;
+	ms->last_n_msgout = 0;
+	prev = ms->conn_tgt;
+
+	/*
+	 * We seem to get abortive reselections sometimes.
+	 */
+	while ((in_8(&mr->bus_status1) & BS1_BSY) == 0) {
+		static int mesh_aborted_resels;
+		mesh_aborted_resels++;
+		out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+		mesh_flush_io(mr);
 		udelay(1);
-		out_8(&mr->count_lo, 1);
-		out_8(&mr->sequence, SEQ_MSGIN + SEQ_ATN + use_active_neg);
-		break;
+		out_8(&mr->sequence, SEQ_ENBRESEL);
+		mesh_flush_io(mr);
+		udelay(5);
+		dlog(ms, "extra resel err/exc/fc = %.6x",
+		     MKWORD(0, mr->error, mr->exception, mr->fifo_count));
+	}
+	out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+       	mesh_flush_io(mr);
+	udelay(1);
+	out_8(&mr->sequence, SEQ_ENBRESEL);
+       	mesh_flush_io(mr);
+	udelay(1);
+	out_8(&mr->sync_params, ASYNC_PARAMS);
 
-	case msg_out:
-		/*
-		 * To get the right timing on ATN wrt ACK, we have
-		 * to get the MESH to drop ACK, wait until REQ gets
-		 * asserted, then drop ATN.  To do this we first
-		 * issue a SEQ_MSGOUT with ATN and wait for REQ,
-		 * then change the command to a SEQ_MSGOUT w/o ATN.
-		 * If we don't see REQ in a reasonable time, we
-		 * change the command to SEQ_MSGIN with ATN,
-		 * wait for the phase mismatch interrupt, then
-		 * issue the SEQ_MSGOUT without ATN.
-		 */
-		out_8(&mr->count_lo, 1);
-		out_8(&mr->sequence, SEQ_MSGOUT + use_active_neg + SEQ_ATN);
-		t = 30;		/* wait up to 30us */
-		while ((mr->bus_status0 & BS0_REQ) == 0 && --t >= 0)
-			udelay(1);
-		dlog(ms, "last_mbyte err/exc/fc/cl=%.8x",
-		     MKWORD(mr->error, mr->exception,
-			    mr->fifo_count, mr->count_lo));
-		if (in_8(&mr->interrupt) & (INT_ERROR | INT_EXCEPTION)) {
-			/* whoops, target didn't do what we expected */
-			ms->last_n_msgout = ms->n_msgout;
-			ms->n_msgout = 0;
-			if (in_8(&mr->interrupt) & INT_ERROR) {
-				printk(KERN_ERR "mesh: error %x in msg_out\n",
-				       in_8(&mr->error));
-				handle_error(ms);
-				return;
-			}
-			if (in_8(&mr->exception) != EXC_PHASEMM)
-				printk(KERN_ERR "mesh: exc %x in msg_out\n",
-				       in_8(&mr->exception));
-			else
-				printk(KERN_DEBUG "mesh: bs0=%x in msg_out\n",
-				       in_8(&mr->bus_status0));
-			handle_exception(ms);
-			return;
-		}
-		if (mr->bus_status0 & BS0_REQ) {
-			out_8(&mr->sequence, SEQ_MSGOUT + use_active_neg);
-			udelay(1);
-			out_8(&mr->fifo, ms->msgout[ms->n_msgout-1]);
-			ms->msgphase = msg_out_last;
-		} else {
-			out_8(&mr->sequence, SEQ_MSGIN + use_active_neg + SEQ_ATN);
-			ms->msgphase = msg_out_xxx;
-		}
-		break;
-
-	case msg_out_last:
-		ms->last_n_msgout = ms->n_msgout;
-		ms->n_msgout = 0;
-		ms->msgphase = ms->expect_reply? msg_in: msg_none;
-		start_phase(ms);
-		break;
-
-	case msg_none:
-		switch (ms->phase) {
-		case idle:
-			printk(KERN_ERR "mesh: interrupt in idle phase?\n");
-			dumpslog(ms);
-			return;
-		case selecting:
-			dlog(ms, "Selecting phase at command completion",0);
-			ms->msgout[0] = IDENTIFY(ALLOW_RESEL(ms->conn_tgt),
-						 (cmd? cmd->device->lun: 0));
-			ms->n_msgout = 1;
-			ms->expect_reply = 0;
-			if (ms->aborting) {
-				ms->msgout[0] = ABORT;
-				ms->n_msgout++;
-			} else if (tp->sdtr_state == do_sdtr) {
-				/* add SDTR message */
-				add_sdtr_msg(ms);
-				ms->expect_reply = 1;
-				tp->sdtr_state = sdtr_sent;
-			}
-			ms->msgphase = msg_out;
-			/*
-			 * We need to wait for REQ before dropping ATN.
-			 * We wait for at most 30us, then fall back to
-			 * a scheme where we issue a SEQ_COMMAND with ATN,
-			 * which will give us a phase mismatch interrupt
-			 * when REQ does come, and then we send the message.
-			 */
-			t = 230;		/* wait up to 230us */
-			while ((mr->bus_status0 & BS0_REQ) == 0) {
-				if (--t < 0) {
-					dlog(ms, "impatient for req", ms->n_msgout);
-					ms->msgphase = msg_none;
-					break;
-				}
-				udelay(1);
-			}
-			break;
-		case dataing:
-			if (ms->dma_count != 0) {
-				start_phase(ms);
-				return;
-			}
-			/*
-			 * We can get a phase mismatch here if the target
-			 * changes to the status phase, even though we have
-			 * had a command complete interrupt.  Then, if we
-			 * issue the SEQ_STATUS command, we'll get a sequence
-			 * error interrupt.  Which isn't so bad except that
-			 * occasionally the mesh actually executes the
-			 * SEQ_STATUS *as well as* giving us the sequence
-			 * error and phase mismatch exception.
-			 */
-			out_8(&mr->sequence, 0);
-			out_8(&mr->interrupt,
-			      INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
-			halt_dma(ms);
-			break;
-		case statusing:
-			if (cmd) {
-				cmd->SCp.Status = mr->fifo;
-				if (DEBUG_TARGET(cmd))
-					printk(KERN_DEBUG "mesh: status is %x\n",
-					       cmd->SCp.Status);
-			}
-			ms->msgphase = msg_in;
-			break;
-		case busfreeing:
-			mesh_done(ms, 1);
-			return;
-		case disconnecting:
-			ms->current_req = 0;
-			ms->phase = idle;
-			mesh_start(ms);
-			return;
-		default:
-			break;
-		}
-		++ms->phase;
-		start_phase(ms);
-		break;
-	}
-}
-
-static void phase_mismatch(struct mesh_state *ms)
-{
-	volatile struct mesh_regs *mr = ms->mesh;
-	int phase;
-
-	dlog(ms, "phasemm ch/cl/seq/fc=%.8x",
-	     MKWORD(mr->count_hi, mr->count_lo, mr->sequence, mr->fifo_count));
-	phase = mr->bus_status0 & BS0_PHASE;
-	if (ms->msgphase == msg_out_xxx && phase == BP_MSGOUT) {
-		/* output the last byte of the message, without ATN */
-		out_8(&mr->count_lo, 1);
-		out_8(&mr->sequence, SEQ_MSGOUT + use_active_neg);
-		udelay(1);
-		out_8(&mr->fifo, ms->msgout[ms->n_msgout-1]);
-		ms->msgphase = msg_out_last;
-		return;
-	}
-
-	if (ms->msgphase == msg_in) {
-		get_msgin(ms);
-		if (ms->n_msgin)
-			handle_msgin(ms);
-	}
-
-	if (ms->dma_started)
-		halt_dma(ms);
-	if (mr->fifo_count) {
-		out_8(&mr->sequence, SEQ_FLUSHFIFO);
-		udelay(1);
-	}
-
-	ms->msgphase = msg_none;
-	switch (phase) {
-	case BP_DATAIN:
-		ms->tgts[ms->conn_tgt].data_goes_out = 0;
-		ms->phase = dataing;
-		break;
-	case BP_DATAOUT:
-		ms->tgts[ms->conn_tgt].data_goes_out = 1;
-		ms->phase = dataing;
-		break;
-	case BP_COMMAND:
-		ms->phase = commanding;
-		break;
-	case BP_STATUS:
-		ms->phase = statusing;
-		break;
-	case BP_MSGIN:
-		ms->msgphase = msg_in;
-		ms->n_msgin = 0;
-		break;
-	case BP_MSGOUT:
-		ms->msgphase = msg_out;
-		if (ms->n_msgout == 0) {
-			if (ms->aborting) {
-				do_abort(ms);
-			} else {
-				if (ms->last_n_msgout == 0) {
-					printk(KERN_DEBUG
-					       "mesh: no msg to repeat\n");
-					ms->msgout[0] = NOP;
-					ms->last_n_msgout = 1;
-				}
-				ms->n_msgout = ms->last_n_msgout;
-			}
-		}
-		break;
-	default:
-		printk(KERN_DEBUG "mesh: unknown scsi phase %x\n", phase);
-		ms->stat = DID_ERROR;
-		mesh_done(ms, 1);
-		return;
-	}
-
-	start_phase(ms);
-}
-
-static void
-reselected(struct mesh_state *ms)
-{
-	volatile struct mesh_regs *mr = ms->mesh;
-	Scsi_Cmnd *cmd;
-	struct mesh_target *tp;
-	int b, t, prev;
-
-	switch (ms->phase) {
-	case idle:
-		break;
-	case arbitrating:
-		if ((cmd = ms->current_req) != NULL) {
-			/* put the command back on the queue */
-			cmd->host_scribble = (void *) ms->request_q;
-			if (ms->request_q == NULL)
-				ms->request_qtail = cmd;
-			ms->request_q = cmd;
-			tp = &ms->tgts[cmd->device->id];
-			tp->current_req = NULL;
-		}
-		break;
-	case busfreeing:
-		ms->phase = reselecting;
-		mesh_done(ms, 0);
-		break;
-	case disconnecting:
-		break;
-	default:
-		printk(KERN_ERR "mesh: reselected in phase %d/%d tgt %d\n",
-		       ms->msgphase, ms->phase, ms->conn_tgt);
-		dumplog(ms, ms->conn_tgt);
-		dumpslog(ms);
-	}
-
-	if (ms->dma_started) {
-		printk(KERN_ERR "mesh: reselected with DMA started !\n");
-		halt_dma(ms);
-	}
-	ms->current_req = NULL;
-	ms->phase = dataing;
-	ms->msgphase = msg_in;
-	ms->n_msgout = 0;
-	ms->last_n_msgout = 0;
-	prev = ms->conn_tgt;
-
-	/*
-	 * We seem to get abortive reselections sometimes.
-	 */
-	while ((mr->bus_status1 & BS1_BSY) == 0) {
-		static int mesh_aborted_resels;
-		mesh_aborted_resels++;
-		out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
-		udelay(1);
-		out_8(&mr->sequence, SEQ_ENBRESEL);
-		udelay(5);
-		dlog(ms, "extra resel err/exc/fc = %.6x",
-		     MKWORD(0, mr->error, mr->exception, mr->fifo_count));
-	}
-	out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
-	udelay(1);
-	out_8(&mr->sequence, SEQ_ENBRESEL);
-	udelay(1);
-	out_8(&mr->sync_params, ASYNC_PARAMS);
-
-	/*
-	 * Find out who reselected us.
-	 */
-	if (mr->fifo_count == 0) {
-		printk(KERN_ERR "mesh: reselection but nothing in fifo?\n");
-		ms->conn_tgt = ms->host->this_id;
-		goto bogus;
-	}
-	/* get the last byte in the fifo */
-	do {
-		b = in_8(&mr->fifo);
-		dlog(ms, "reseldata %x", b);
-	} while (in_8(&mr->fifo_count));
-	for (t = 0; t < 8; ++t)
-		if ((b & (1 << t)) != 0 && t != ms->host->this_id)
-			break;
-	if (b != (1 << t) + (1 << ms->host->this_id)) {
-		printk(KERN_ERR "mesh: bad reselection data %x\n", b);
-		ms->conn_tgt = ms->host->this_id;
-		goto bogus;
-	}
+	/*
+	 * Find out who reselected us.
+	 */
+	if (in_8(&mr->fifo_count) == 0) {
+		printk(KERN_ERR "mesh: reselection but nothing in fifo?\n");
+		ms->conn_tgt = ms->host->this_id;
+		goto bogus;
+	}
+	/* get the last byte in the fifo */
+	do {
+		b = in_8(&mr->fifo);
+		dlog(ms, "reseldata %x", b);
+	} while (in_8(&mr->fifo_count));
+	for (t = 0; t < 8; ++t)
+		if ((b & (1 << t)) != 0 && t != ms->host->this_id)
+			break;
+	if (b != (1 << t) + (1 << ms->host->this_id)) {
+		printk(KERN_ERR "mesh: bad reselection data %x\n", b);
+		ms->conn_tgt = ms->host->this_id;
+		goto bogus;
+	}
 
 
 	/*
@@ -1438,8 +981,7 @@ static void do_abort(struct mesh_state *
 	dlog(ms, "abort", 0);
 }
 
-static void
-handle_reset(struct mesh_state *ms)
+static void handle_reset(struct mesh_state *ms)
 {
 	int tgt;
 	struct mesh_target *tp;
@@ -1466,13 +1008,13 @@ handle_reset(struct mesh_state *ms)
 	ms->msgphase = msg_none;
 	out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
 	out_8(&mr->sequence, SEQ_FLUSHFIFO);
+       	mesh_flush_io(mr);
 	udelay(1);
 	out_8(&mr->sync_params, ASYNC_PARAMS);
 	out_8(&mr->sequence, SEQ_ENBRESEL);
 }
 
-static irqreturn_t
-do_mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+static irqreturn_t do_mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
 {
 	unsigned long flags;
 	struct Scsi_Host *dev = ((struct mesh_state *)dev_id)->host;
@@ -1497,7 +1039,7 @@ static void handle_error(struct mesh_sta
 		/* SCSI bus was reset */
 		printk(KERN_INFO "mesh: SCSI bus reset detected: "
 		       "waiting for end...");
-		while ((mr->bus_status1 & BS1_RST) != 0)
+		while ((in_8(&mr->bus_status1) & BS1_RST) != 0)
 			udelay(1);
 		printk("done\n");
 		handle_reset(ms);
@@ -1567,7 +1109,7 @@ static void handle_error(struct mesh_sta
 	}
 	mesh_dump_regs(ms);
 	dumplog(ms, ms->conn_tgt);
-	if (ms->phase > selecting && (mr->bus_status1 & BS1_BSY)) {
+	if (ms->phase > selecting && (in_8(&mr->bus_status1) & BS1_BSY)) {
 		/* try to do what the target wants */
 		do_abort(ms);
 		phase_mismatch(ms);
@@ -1609,40 +1151,11 @@ static void handle_exception(struct mesh
 	}
 }
 
-static void
-mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+static void handle_msgin(struct mesh_state *ms)
 {
-	struct mesh_state *ms = (struct mesh_state *) dev_id;
-	volatile struct mesh_regs *mr = ms->mesh;
-	int intr;
-
-#if 0
-	if (ALLOW_DEBUG(ms->conn_tgt))
-		printk(KERN_DEBUG "mesh_intr, bs0=%x int=%x exc=%x err=%x "
-		       "phase=%d msgphase=%d\n", mr->bus_status0,
-		       mr->interrupt, mr->exception, mr->error,
-		       ms->phase, ms->msgphase);
-#endif
-	while ((intr = in_8(&mr->interrupt)) != 0) {
-		dlog(ms, "interrupt intr/err/exc/seq=%.8x", 
-		     MKWORD(intr, mr->error, mr->exception, mr->sequence));
-		if (intr & INT_ERROR) {
-			handle_error(ms);
-		} else if (intr & INT_EXCEPTION) {
-			handle_exception(ms);
-		} else if (intr & INT_CMDDONE) {
-			out_8(&mr->interrupt, INT_CMDDONE);
-			cmd_complete(ms);
-		}
-	}
-}
-
-static void
-handle_msgin(struct mesh_state *ms)
-{
-	int i, code;
-	Scsi_Cmnd *cmd = ms->current_req;
-	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
+	int i, code;
+	Scsi_Cmnd *cmd = ms->current_req;
+	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
 
 	if (ms->n_msgin == 0)
 		return;
@@ -1736,51 +1249,10 @@ handle_msgin(struct mesh_state *ms)
 	ms->msgphase = msg_out;
 }
 
-static void
-mesh_done(struct mesh_state *ms, int start_next)
-{
-	Scsi_Cmnd *cmd;
-	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
-
-	cmd = ms->current_req;
-	ms->current_req = 0;
-	tp->current_req = 0;
-	if (cmd) {
-		cmd->result = (ms->stat << 16) + cmd->SCp.Status;
-		if (ms->stat == DID_OK)
-			cmd->result += (cmd->SCp.Message << 8);
-		if (DEBUG_TARGET(cmd)) {
-			printk(KERN_DEBUG "mesh_done: result = %x, data_ptr=%d, buflen=%d\n",
-			       cmd->result, ms->data_ptr, cmd->request_bufflen);
-			if ((cmd->cmnd[0] == 0 || cmd->cmnd[0] == 0x12 || cmd->cmnd[0] == 3)
-			    && cmd->request_buffer != 0) {
-				unsigned char *b = cmd->request_buffer;
-				printk(KERN_DEBUG "buffer = %x %x %x %x %x %x %x %x\n",
-				       b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
-			}
-		}
-		cmd->SCp.this_residual -= ms->data_ptr;
-		mesh_completed(ms, cmd);
-	}
-	if (start_next) {
-		out_8(&ms->mesh->sequence, SEQ_ENBRESEL);
-		udelay(1);
-		ms->phase = idle;
-		mesh_start(ms);
-	}
-}
-
-static void
-mesh_completed(struct mesh_state *ms, Scsi_Cmnd *cmd)
-{
-	(*cmd->scsi_done)(cmd);
-}
-
 /*
  * Set up DMA commands for transferring data.
  */
-static void
-set_dma_cmds(struct mesh_state *ms, Scsi_Cmnd *cmd)
+static void set_dma_cmds(struct mesh_state *ms, Scsi_Cmnd *cmd)
 {
 	int i, dma_cmd, total, off, dtot;
 	struct scatterlist *scl;
@@ -1848,8 +1320,7 @@ set_dma_cmds(struct mesh_state *ms, Scsi
 	ms->dma_count = dtot;
 }
 
-static void
-halt_dma(struct mesh_state *ms)
+static void halt_dma(struct mesh_state *ms)
 {
 	volatile struct dbdma_regs *md = ms->dma;
 	volatile struct mesh_regs *mr = ms->mesh;
@@ -1859,7 +1330,7 @@ halt_dma(struct mesh_state *ms)
 	if (!ms->tgts[ms->conn_tgt].data_goes_out) {
 		/* wait a little while until the fifo drains */
 		t = 50;
-		while (t > 0 && mr->fifo_count != 0
+		while (t > 0 && in_8(&mr->fifo_count) != 0
 		       && (in_le32(&md->status) & ACTIVE) != 0) {
 			--t;
 			udelay(1);
@@ -1899,162 +1370,697 @@ halt_dma(struct mesh_state *ms)
 	ms->dma_started = 0;
 }
 
-/*
- * Work out whether we expect data to go out from the host adaptor or into it.
- */
-static int
-data_goes_out(Scsi_Cmnd *cmd)
+static void phase_mismatch(struct mesh_state *ms)
 {
-	switch (cmd->sc_data_direction) {
-	case SCSI_DATA_WRITE:
-		return 1;
-	case SCSI_DATA_READ:
-		return 0;
-	}
+	volatile struct mesh_regs *mr = ms->mesh;
+	int phase;
 
-	/* for SCSI_DATA_UNKNOWN or SCSI_DATA_NONE, fall back on the
-	   old method for now... */
-	switch (cmd->cmnd[0]) {
-	case CHANGE_DEFINITION: 
-	case COMPARE:	  
-	case COPY:
-	case COPY_VERIFY:	    
-	case FORMAT_UNIT:	 
-	case LOG_SELECT:
-	case MEDIUM_SCAN:	  
-	case MODE_SELECT:
-	case MODE_SELECT_10:
-	case REASSIGN_BLOCKS: 
-	case RESERVE:
-	case SEARCH_EQUAL:	  
-	case SEARCH_EQUAL_12: 
-	case SEARCH_HIGH:	 
-	case SEARCH_HIGH_12:  
-	case SEARCH_LOW:
-	case SEARCH_LOW_12:
-	case SEND_DIAGNOSTIC: 
-	case SEND_VOLUME_TAG:	     
-	case SET_WINDOW: 
-	case UPDATE_BLOCK:	
-	case WRITE_BUFFER:
- 	case WRITE_6:	
-	case WRITE_10:	
-	case WRITE_12:	  
-	case WRITE_LONG:	
-	case WRITE_LONG_2:      /* alternate code for WRITE_LONG */
-	case WRITE_SAME:	
-	case WRITE_VERIFY:
-	case WRITE_VERIFY_12:
-		return 1;
-	default:
-		return 0;
+	dlog(ms, "phasemm ch/cl/seq/fc=%.8x",
+	     MKWORD(mr->count_hi, mr->count_lo, mr->sequence, mr->fifo_count));
+	phase = in_8(&mr->bus_status0) & BS0_PHASE;
+	if (ms->msgphase == msg_out_xxx && phase == BP_MSGOUT) {
+		/* output the last byte of the message, without ATN */
+		out_8(&mr->count_lo, 1);
+		out_8(&mr->sequence, SEQ_MSGOUT + use_active_neg);
+		mesh_flush_io(mr);
+		udelay(1);
+		out_8(&mr->fifo, ms->msgout[ms->n_msgout-1]);
+		ms->msgphase = msg_out_last;
+		return;
 	}
-}
 
-#ifdef MESH_DBG
-static inline u32 readtb(void)
-{
-	u32 tb;
+	if (ms->msgphase == msg_in) {
+		get_msgin(ms);
+		if (ms->n_msgin)
+			handle_msgin(ms);
+	}
 
-#ifdef DBG_USE_TB
-	/* Beware: if you enable this, it will crash on 601s. */
-	asm ("mftb %0" : "=r" (tb) : );
-#else
-	tb = 0;
-#endif
-	return tb;
-}
+	if (ms->dma_started)
+		halt_dma(ms);
+	if (mr->fifo_count) {
+		out_8(&mr->sequence, SEQ_FLUSHFIFO);
+		mesh_flush_io(mr);
+		udelay(1);
+	}
 
-static void dlog(struct mesh_state *ms, char *fmt, int a)
-{
-	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
-	struct dbglog *tlp, *slp;
+	ms->msgphase = msg_none;
+	switch (phase) {
+	case BP_DATAIN:
+		ms->tgts[ms->conn_tgt].data_goes_out = 0;
+		ms->phase = dataing;
+		break;
+	case BP_DATAOUT:
+		ms->tgts[ms->conn_tgt].data_goes_out = 1;
+		ms->phase = dataing;
+		break;
+	case BP_COMMAND:
+		ms->phase = commanding;
+		break;
+	case BP_STATUS:
+		ms->phase = statusing;
+		break;
+	case BP_MSGIN:
+		ms->msgphase = msg_in;
+		ms->n_msgin = 0;
+		break;
+	case BP_MSGOUT:
+		ms->msgphase = msg_out;
+		if (ms->n_msgout == 0) {
+			if (ms->aborting) {
+				do_abort(ms);
+			} else {
+				if (ms->last_n_msgout == 0) {
+					printk(KERN_DEBUG
+					       "mesh: no msg to repeat\n");
+					ms->msgout[0] = NOP;
+					ms->last_n_msgout = 1;
+				}
+				ms->n_msgout = ms->last_n_msgout;
+			}
+		}
+		break;
+	default:
+		printk(KERN_DEBUG "mesh: unknown scsi phase %x\n", phase);
+		ms->stat = DID_ERROR;
+		mesh_done(ms, 1);
+		return;
+	}
 
-	tlp = &tp->log[tp->log_ix];
-	slp = &ms->log[ms->log_ix];
-	tlp->fmt = fmt;
-	tlp->tb = readtb();
-	tlp->phase = (ms->msgphase << 4) + ms->phase;
-	tlp->bs0 = ms->mesh->bus_status0;
-	tlp->bs1 = ms->mesh->bus_status1;
-	tlp->tgt = ms->conn_tgt;
-	tlp->d = a;
-	*slp = *tlp;
-	if (++tp->log_ix >= N_DBG_LOG)
-		tp->log_ix = 0;
-	if (tp->n_log < N_DBG_LOG)
-		++tp->n_log;
-	if (++ms->log_ix >= N_DBG_SLOG)
-		ms->log_ix = 0;
-	if (ms->n_log < N_DBG_SLOG)
-		++ms->n_log;
+	start_phase(ms);
 }
 
-static void dumplog(struct mesh_state *ms, int t)
+static void cmd_complete(struct mesh_state *ms)
 {
-	struct mesh_target *tp = &ms->tgts[t];
-	struct dbglog *lp;
-	int i;
+	volatile struct mesh_regs *mr = ms->mesh;
+	Scsi_Cmnd *cmd = ms->current_req;
+	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
+	int seq, n, t;
 
-	if (tp->n_log == 0)
-		return;
-	i = tp->log_ix - tp->n_log;
-	if (i < 0)
-		i += N_DBG_LOG;
-	tp->n_log = 0;
-	do {
-		lp = &tp->log[i];
-		printk(KERN_DEBUG "mesh log %d: bs=%.2x%.2x ph=%.2x ",
-		       t, lp->bs1, lp->bs0, lp->phase);
-#ifdef DBG_USE_TB
-		printk("tb=%10u ", lp->tb);
-#endif
-		printk(lp->fmt, lp->d);
-		printk("\n");
-		if (++i >= N_DBG_LOG)
-			i = 0;
-	} while (i != tp->log_ix);
-}
+	dlog(ms, "cmd_complete fc=%x", mr->fifo_count);
+	seq = use_active_neg + (ms->n_msgout? SEQ_ATN: 0);
+	switch (ms->msgphase) {
+	case msg_out_xxx:
+		/* huh?  we expected a phase mismatch */
+		ms->n_msgin = 0;
+		ms->msgphase = msg_in;
+		/* fall through */
 
-static void dumpslog(struct mesh_state *ms)
-{
-	struct dbglog *lp;
-	int i;
+	case msg_in:
+		/* should have some message bytes in fifo */
+		get_msgin(ms);
+		n = msgin_length(ms);
+		if (ms->n_msgin < n) {
+			out_8(&mr->count_lo, n - ms->n_msgin);
+			out_8(&mr->sequence, SEQ_MSGIN + seq);
+		} else {
+			ms->msgphase = msg_none;
+			handle_msgin(ms);
+			start_phase(ms);
+		}
+		break;
 
-	if (ms->n_log == 0)
-		return;
-	i = ms->log_ix - ms->n_log;
-	if (i < 0)
-		i += N_DBG_SLOG;
-	ms->n_log = 0;
-	do {
-		lp = &ms->log[i];
-		printk(KERN_DEBUG "mesh log: bs=%.2x%.2x ph=%.2x t%d ",
-		       lp->bs1, lp->bs0, lp->phase, lp->tgt);
-#ifdef DBG_USE_TB
-		printk("tb=%10u ", lp->tb);
-#endif
-		printk(lp->fmt, lp->d);
-		printk("\n");
-		if (++i >= N_DBG_SLOG)
-			i = 0;
-	} while (i != ms->log_ix);
-}
-#endif /* MESH_DBG */
+	case msg_in_bad:
+		out_8(&mr->sequence, SEQ_FLUSHFIFO);
+		mesh_flush_io(mr);
+		udelay(1);
+		out_8(&mr->count_lo, 1);
+		out_8(&mr->sequence, SEQ_MSGIN + SEQ_ATN + use_active_neg);
+		break;
 
-static Scsi_Host_Template driver_template = {
-	.proc_name			= "mesh",
-	.name				= "MESH",
-	.detect				= mesh_detect,
-	.release			= mesh_release,
-	.queuecommand			= mesh_queue,
-	.eh_abort_handler		= mesh_abort,
-	.eh_host_reset_handler		= mesh_host_reset,
-	.can_queue			= 20,
-	.this_id			= 7,
-	.sg_tablesize			= SG_ALL,
+	case msg_out:
+		/*
+		 * To get the right timing on ATN wrt ACK, we have
+		 * to get the MESH to drop ACK, wait until REQ gets
+		 * asserted, then drop ATN.  To do this we first
+		 * issue a SEQ_MSGOUT with ATN and wait for REQ,
+		 * then change the command to a SEQ_MSGOUT w/o ATN.
+		 * If we don't see REQ in a reasonable time, we
+		 * change the command to SEQ_MSGIN with ATN,
+		 * wait for the phase mismatch interrupt, then
+		 * issue the SEQ_MSGOUT without ATN.
+		 */
+		out_8(&mr->count_lo, 1);
+		out_8(&mr->sequence, SEQ_MSGOUT + use_active_neg + SEQ_ATN);
+		t = 30;		/* wait up to 30us */
+		while ((in_8(&mr->bus_status0) & BS0_REQ) == 0 && --t >= 0)
+			udelay(1);
+		dlog(ms, "last_mbyte err/exc/fc/cl=%.8x",
+		     MKWORD(mr->error, mr->exception,
+			    mr->fifo_count, mr->count_lo));
+		if (in_8(&mr->interrupt) & (INT_ERROR | INT_EXCEPTION)) {
+			/* whoops, target didn't do what we expected */
+			ms->last_n_msgout = ms->n_msgout;
+			ms->n_msgout = 0;
+			if (in_8(&mr->interrupt) & INT_ERROR) {
+				printk(KERN_ERR "mesh: error %x in msg_out\n",
+				       in_8(&mr->error));
+				handle_error(ms);
+				return;
+			}
+			if (in_8(&mr->exception) != EXC_PHASEMM)
+				printk(KERN_ERR "mesh: exc %x in msg_out\n",
+				       in_8(&mr->exception));
+			else
+				printk(KERN_DEBUG "mesh: bs0=%x in msg_out\n",
+				       in_8(&mr->bus_status0));
+			handle_exception(ms);
+			return;
+		}
+		if (in_8(&mr->bus_status0) & BS0_REQ) {
+			out_8(&mr->sequence, SEQ_MSGOUT + use_active_neg);
+			mesh_flush_io(mr);
+			udelay(1);
+			out_8(&mr->fifo, ms->msgout[ms->n_msgout-1]);
+			ms->msgphase = msg_out_last;
+		} else {
+			out_8(&mr->sequence, SEQ_MSGIN + use_active_neg + SEQ_ATN);
+			ms->msgphase = msg_out_xxx;
+		}
+		break;
+
+	case msg_out_last:
+		ms->last_n_msgout = ms->n_msgout;
+		ms->n_msgout = 0;
+		ms->msgphase = ms->expect_reply? msg_in: msg_none;
+		start_phase(ms);
+		break;
+
+	case msg_none:
+		switch (ms->phase) {
+		case idle:
+			printk(KERN_ERR "mesh: interrupt in idle phase?\n");
+			dumpslog(ms);
+			return;
+		case selecting:
+			dlog(ms, "Selecting phase at command completion",0);
+			ms->msgout[0] = IDENTIFY(ALLOW_RESEL(ms->conn_tgt),
+						 (cmd? cmd->device->lun: 0));
+			ms->n_msgout = 1;
+			ms->expect_reply = 0;
+			if (ms->aborting) {
+				ms->msgout[0] = ABORT;
+				ms->n_msgout++;
+			} else if (tp->sdtr_state == do_sdtr) {
+				/* add SDTR message */
+				add_sdtr_msg(ms);
+				ms->expect_reply = 1;
+				tp->sdtr_state = sdtr_sent;
+			}
+			ms->msgphase = msg_out;
+			/*
+			 * We need to wait for REQ before dropping ATN.
+			 * We wait for at most 30us, then fall back to
+			 * a scheme where we issue a SEQ_COMMAND with ATN,
+			 * which will give us a phase mismatch interrupt
+			 * when REQ does come, and then we send the message.
+			 */
+			t = 230;		/* wait up to 230us */
+			while ((in_8(&mr->bus_status0) & BS0_REQ) == 0) {
+				if (--t < 0) {
+					dlog(ms, "impatient for req", ms->n_msgout);
+					ms->msgphase = msg_none;
+					break;
+				}
+				udelay(1);
+			}
+			break;
+		case dataing:
+			if (ms->dma_count != 0) {
+				start_phase(ms);
+				return;
+			}
+			/*
+			 * We can get a phase mismatch here if the target
+			 * changes to the status phase, even though we have
+			 * had a command complete interrupt.  Then, if we
+			 * issue the SEQ_STATUS command, we'll get a sequence
+			 * error interrupt.  Which isn't so bad except that
+			 * occasionally the mesh actually executes the
+			 * SEQ_STATUS *as well as* giving us the sequence
+			 * error and phase mismatch exception.
+			 */
+			out_8(&mr->sequence, 0);
+			out_8(&mr->interrupt,
+			      INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+			halt_dma(ms);
+			break;
+		case statusing:
+			if (cmd) {
+				cmd->SCp.Status = mr->fifo;
+				if (DEBUG_TARGET(cmd))
+					printk(KERN_DEBUG "mesh: status is %x\n",
+					       cmd->SCp.Status);
+			}
+			ms->msgphase = msg_in;
+			break;
+		case busfreeing:
+			mesh_done(ms, 1);
+			return;
+		case disconnecting:
+			ms->current_req = 0;
+			ms->phase = idle;
+			mesh_start(ms);
+			return;
+		default:
+			break;
+		}
+		++ms->phase;
+		start_phase(ms);
+		break;
+	}
+}
+
+
+/*
+ * Called by midlayer with host locked to queue a new
+ * request
+ */
+static int mesh_queue(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+{
+	struct mesh_state *ms;
+
+	cmd->scsi_done = done;
+	cmd->host_scribble = NULL;
+
+	ms = (struct mesh_state *) cmd->device->host->hostdata;
+
+	if (ms->request_q == NULL)
+		ms->request_q = cmd;
+	else
+		ms->request_qtail->host_scribble = (void *) cmd;
+	ms->request_qtail = cmd;
+
+	if (ms->phase == idle)
+		mesh_start(ms);
+
+	return 0;
+}
+
+/*
+ * Called to handle interrupts, either call by the interrupt
+ * handler (do_mesh_interrupt) or by other functions in
+ * exceptional circumstances
+ */
+static void mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+	struct mesh_state *ms = (struct mesh_state *) dev_id;
+	volatile struct mesh_regs *mr = ms->mesh;
+	int intr;
+
+#if 0
+	if (ALLOW_DEBUG(ms->conn_tgt))
+		printk(KERN_DEBUG "mesh_intr, bs0=%x int=%x exc=%x err=%x "
+		       "phase=%d msgphase=%d\n", mr->bus_status0,
+		       mr->interrupt, mr->exception, mr->error,
+		       ms->phase, ms->msgphase);
+#endif
+	while ((intr = in_8(&mr->interrupt)) != 0) {
+		dlog(ms, "interrupt intr/err/exc/seq=%.8x", 
+		     MKWORD(intr, mr->error, mr->exception, mr->sequence));
+		if (intr & INT_ERROR) {
+			handle_error(ms);
+		} else if (intr & INT_EXCEPTION) {
+			handle_exception(ms);
+		} else if (intr & INT_CMDDONE) {
+			out_8(&mr->interrupt, INT_CMDDONE);
+			cmd_complete(ms);
+		}
+	}
+}
+
+/* Todo: here we can at least try to remove the command from the
+ * queue if it isn't connected yet, and for pending command, assert
+ * ATN until the bus gets freed.
+ */
+static int mesh_abort(Scsi_Cmnd *cmd)
+{
+	struct mesh_state *ms = (struct mesh_state *) cmd->device->host->hostdata;
+
+	printk(KERN_DEBUG "mesh_abort(%p)\n", cmd);
+	mesh_dump_regs(ms);
+	dumplog(ms, cmd->device->id);
+	dumpslog(ms);
+	return SCSI_ABORT_SNOOZE;
+}
+
+/*
+ * Called by the midlayer with the lock held to reset the
+ * SCSI host and bus.
+ * The midlayer will wait for devices to come back, we don't need
+ * to do that ourselves
+ */
+static int mesh_host_reset(Scsi_Cmnd *cmd)
+{
+	struct mesh_state *ms = (struct mesh_state *) cmd->device->host->hostdata;
+	volatile struct mesh_regs *mr = ms->mesh;
+	volatile struct dbdma_regs *md = ms->dma;
+
+	printk(KERN_DEBUG "mesh_host_reset\n");
+
+	/* Reset the controller & dbdma channel */
+	out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16);	/* stop dma */
+	out_8(&mr->exception, 0xff);	/* clear all exception bits */
+	out_8(&mr->error, 0xff);	/* clear all error bits */
+	out_8(&mr->sequence, SEQ_RESETMESH);
+       	mesh_flush_io(mr);
+	udelay(1);
+	out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+	out_8(&mr->source_id, ms->host->this_id);
+	out_8(&mr->sel_timeout, 25);	/* 250ms */
+	out_8(&mr->sync_params, ASYNC_PARAMS);
+
+	/* Reset the bus */
+	out_8(&mr->bus_status1, BS1_RST);	/* assert RST */
+       	mesh_flush_io(mr);
+	udelay(30);			/* leave it on for >= 25us */
+	out_8(&mr->bus_status1, 0);	/* negate RST */
+
+	/* Complete pending commands */
+	handle_reset(ms);
+	
+	return SUCCESS;
+}
+
+static void set_mesh_power(struct mesh_state *ms, int state)
+{
+	if (_machine != _MACH_Pmac)
+		return;
+	if (state) {
+		pmac_call_feature(PMAC_FTR_MESH_ENABLE, macio_get_of_node(ms->mdev), 0, 1);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ/5);
+	} else {
+		pmac_call_feature(PMAC_FTR_MESH_ENABLE, macio_get_of_node(ms->mdev), 0, 0);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ/100);
+	}
+}			
+
+
+#ifdef CONFIG_PM
+static int mesh_suspend(struct macio_dev *mdev, u32 state)
+{
+	struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);
+	unsigned long flags;
+
+	if (state == mdev->ofdev.dev.power_state || state < 2)
+		return 0;
+
+	scsi_block_requests(ms->host);
+	spin_lock_irqsave(ms->host->host_lock, flags);
+	while(ms->phase != idle) {
+		spin_unlock_irqrestore(ms->host->host_lock, flags);
+		current->state = TASK_UNINTERRUPTIBLE;
+		schedule_timeout(HZ/100);
+		spin_lock_irqsave(ms->host->host_lock, flags);
+	}
+	ms->phase = sleeping;
+	spin_unlock_irqrestore(ms->host->host_lock, flags);
+	disable_irq(ms->meshintr);
+	set_mesh_power(ms, 0);
+
+	mdev->ofdev.dev.power_state = state;
+
+	return 0;
+}
+
+static int mesh_resume(struct macio_dev *mdev)
+{
+	struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);
+	unsigned long flags;
+
+	if (mdev->ofdev.dev.power_state == 0)
+		return 0;
+
+	set_mesh_power(ms, 1);
+	mesh_init(ms);
+	spin_lock_irqsave(ms->host->host_lock, flags);
+	mesh_start(ms);
+	spin_unlock_irqrestore(ms->host->host_lock, flags);
+	enable_irq(ms->meshintr);
+	scsi_unblock_requests(ms->host);
+
+	mdev->ofdev.dev.power_state = 0;
+
+	return 0;
+}
+
+#endif /* CONFIG_PM */
+
+/*
+ * If we leave drives set for synchronous transfers (especially
+ * CDROMs), and reboot to MacOS, it gets confused, poor thing.
+ * So, on reboot we reset the SCSI bus.
+ */
+static int mesh_shutdown(struct macio_dev *mdev)
+{
+	struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);
+	volatile struct mesh_regs *mr;
+	unsigned long flags;
+
+       	printk(KERN_INFO "resetting MESH scsi bus(es)\n");
+	spin_lock_irqsave(ms->host->host_lock, flags);
+       	mr = ms->mesh;
+	out_8(&mr->intr_mask, 0);
+	out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+	out_8(&mr->bus_status1, BS1_RST);
+	mesh_flush_io(mr);
+	udelay(30);
+	out_8(&mr->bus_status1, 0);
+	spin_unlock_irqrestore(ms->host->host_lock, flags);
+
+	return 0;
+}
+
+static Scsi_Host_Template mesh_template = {
+	.proc_name			= "mesh",
+	.name				= "MESH",
+	.queuecommand			= mesh_queue,
+	.eh_abort_handler		= mesh_abort,
+	.eh_host_reset_handler		= mesh_host_reset,
+	.can_queue			= 20,
+	.this_id			= 7,
+	.sg_tablesize			= SG_ALL,
 	.cmd_per_lun			= 2,
 	.use_clustering			= DISABLE_CLUSTERING,
 };
 
-#include "scsi_module.c"
+static int mesh_probe(struct macio_dev *mdev, const struct of_match *match)
+{
+	struct device_node *mesh = macio_get_of_node(mdev);
+	struct pci_dev* pdev = macio_get_pci_dev(mdev);
+	int tgt, *cfp, minper;
+	struct mesh_state *ms;
+	struct Scsi_Host *mesh_host;
+	void *dma_cmd_space;
+	dma_addr_t dma_cmd_bus;
+
+	switch (mdev->bus->chip->type) {
+	case macio_heathrow:
+	case macio_gatwick:
+	case macio_paddington:
+		use_active_neg = 0;
+		break;
+	default:
+		use_active_neg = SEQ_ACTIVE_NEG;
+	}
+
+	if (macio_resource_count(mdev) != 2 || macio_irq_count(mdev) != 2) {
+       		printk(KERN_ERR "mesh: expected 2 addrs and 2 intrs"
+	       	       " (got %d,%d)\n", mesh->n_addrs, mesh->n_intrs);
+		return -ENODEV;
+	}
+
+	if (macio_request_resources(mdev, "mesh") != 0) {
+       		printk(KERN_ERR "mesh: unable to request memory resources");
+		return -EBUSY;
+	}
+       	mesh_host = scsi_host_alloc(&mesh_template, sizeof(struct mesh_state));
+	if (mesh_host == NULL) {
+		printk(KERN_ERR "mesh: couldn't register host");
+		goto out_release;
+	}
+	
+	/* Old junk for root discovery, that will die ultimately */
+#if !defined(MODULE)
+       	note_scsi_host(mesh, mesh_host);
+#endif
+
+	mesh_host->base = macio_resource_start(mdev, 0);
+	mesh_host->irq = macio_irq(mdev, 0);
+       	ms = (struct mesh_state *) mesh_host->hostdata;
+	macio_set_drvdata(mdev, ms);
+	ms->host = mesh_host;
+	ms->mdev = mdev;
+	ms->pdev = pdev;
+	
+	ms->mesh = (volatile struct mesh_regs *)
+		ioremap(macio_resource_start(mdev, 0), 0x1000);
+	if (ms->mesh == NULL) {
+		printk(KERN_ERR "mesh: can't map registers\n");
+		goto out_free;
+	}		
+	ms->dma = (volatile struct dbdma_regs *)
+	       	ioremap(macio_resource_start(mdev, 1), 0x1000);
+	if (ms->dma == NULL) {
+		printk(KERN_ERR "mesh: can't map registers\n");
+		iounmap((void *)ms->mesh);
+		goto out_free;
+	}
+
+       	ms->meshintr = macio_irq(mdev, 0);
+       	ms->dmaintr = macio_irq(mdev, 1);
+
+       	/* Space for dma command list: +1 for stop command,
+       	 * +1 to allow for aligning.
+	 */
+	ms->dma_cmd_size = (mesh_host->sg_tablesize + 2) * sizeof(struct dbdma_cmd);
+
+	/* We use the PCI APIs for now until the generic one gets fixed
+	 * enough or until we get some macio-specific versions
+	 */
+	dma_cmd_space = pci_alloc_consistent(macio_get_pci_dev(mdev),
+					     ms->dma_cmd_size,
+					     &dma_cmd_bus);
+	if (dma_cmd_space == NULL) {
+		printk(KERN_ERR "mesh: can't allocate DMA table\n");
+		goto out_unmap;
+	}
+	memset(dma_cmd_space, 0, ms->dma_cmd_size);
+
+	ms->dma_cmds = (struct dbdma_cmd *) DBDMA_ALIGN(dma_cmd_space);
+       	ms->dma_cmd_space = dma_cmd_space;
+	ms->dma_cmd_bus = dma_cmd_bus + ((unsigned long)ms->dma_cmds)
+		- (unsigned long)dma_cmd_space;
+	ms->current_req = NULL;
+       	for (tgt = 0; tgt < 8; ++tgt) {
+	       	ms->tgts[tgt].sdtr_state = do_sdtr;
+	       	ms->tgts[tgt].sync_params = ASYNC_PARAMS;
+	       	ms->tgts[tgt].current_req = 0;
+       	}
+
+	if ((cfp = (int *) get_property(mesh, "clock-frequency", NULL)))
+       		ms->clk_freq = *cfp;
+	else {
+       		printk(KERN_INFO "mesh: assuming 50MHz clock frequency\n");
+	       	ms->clk_freq = 50000000;
+       	}
+
+       	/* The maximum sync rate is clock / 5; increase
+       	 * mesh_sync_period if necessary.
+	 */
+	minper = 1000000000 / (ms->clk_freq / 5); /* ns */
+	if (mesh_sync_period < minper)
+		mesh_sync_period = minper;
+
+	/* Power up the chip */
+	set_mesh_power(ms, 1);
+
+	/* Set it up */
+       	mesh_init(ms);
+
+	/* XXX FIXME: error should be fatal */
+       	if (request_irq(ms->meshintr, do_mesh_interrupt, 0, "MESH", ms))
+	       	printk(KERN_ERR "MESH: can't get irq %d\n", ms->meshintr);
+
+	/* XXX FIXME: handle failure */
+	scsi_add_host(mesh_host, &mdev->ofdev.dev);
+	scsi_scan_host(mesh_host);
+
+	return 0;
+
+out_unmap:
+	iounmap((void *)ms->dma);
+	iounmap((void *)ms->mesh);
+out_free:
+	scsi_host_put(mesh_host);
+out_release:
+	macio_release_resources(mdev);
+
+	return -ENODEV;
+}
+
+static int mesh_remove(struct macio_dev *mdev)
+{
+	struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);
+	struct Scsi_Host *mesh_host = ms->host;
+
+	scsi_remove_host(mesh_host);
+
+	free_irq(ms->meshintr, ms);
+
+	/* Reset scsi bus */
+	mesh_shutdown(mdev);
+
+	/* Shut down chip & termination */
+	set_mesh_power(ms, 0);
+
+	/* Unmap registers & dma controller */
+	iounmap((void *) ms->mesh);
+       	iounmap((void *) ms->dma);
+
+	/* Free DMA commands memory */
+	pci_free_consistent(macio_get_pci_dev(mdev), ms->dma_cmd_size,
+			  ms->dma_cmd_space, ms->dma_cmd_bus);
+
+	/* Release memory resources */
+	macio_release_resources(mdev);
+
+	scsi_host_put(mesh_host);
+
+	return 0;
+}
+
+
+static struct of_match mesh_match[] = 
+{
+	{
+	.name 		= "mesh",
+	.type		= OF_ANY_MATCH,
+	.compatible	= OF_ANY_MATCH
+	},
+	{
+	.name 		= OF_ANY_MATCH,
+	.type		= "scsi",
+	.compatible	= "chrp,mesh0"
+	},
+	{},
+};
+
+static struct macio_driver mesh_driver = 
+{
+	.name 		= "mesh",
+	.match_table	= mesh_match,
+	.probe		= mesh_probe,
+	.remove		= mesh_remove,
+	.shutdown	= mesh_shutdown,
+#ifdef CONFIG_PM
+	.suspend	= mesh_suspend,
+	.resume		= mesh_resume,
+#endif
+};
+
+
+static int __init init_mesh(void)
+{
+
+	/* Calculate sync rate from module parameters */
+	if (sync_rate > 10)
+		sync_rate = 10;
+	if (sync_rate > 0) {
+		printk(KERN_INFO "mesh: configured for synchronous %d MB/s\n", sync_rate);
+		mesh_sync_period = 1000 / sync_rate;	/* ns */
+		mesh_sync_offset = 15;
+	} else
+		printk(KERN_INFO "mesh: configured for asynchronous\n");
+
+	return macio_register_driver(&mesh_driver);
+}
+
+static void __exit exit_mesh(void)
+{
+	return macio_unregister_driver(&mesh_driver);
+}
+
+module_init(init_mesh);
+module_exit(exit_mesh);
diff -puN drivers/serial/pmac_zilog.c~big-pmac-3 drivers/serial/pmac_zilog.c
--- 25/drivers/serial/pmac_zilog.c~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/drivers/serial/pmac_zilog.c	2004-01-28 23:09:16.000000000 -0800
@@ -1120,7 +1120,7 @@ static struct uart_ops pmz_pops = {
  * 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, int early)
+static int __init pmz_setup_port(struct uart_pmac_port *up)
 {
 	struct device_node *np = up->node;
 	char *conn;
@@ -1133,11 +1133,6 @@ static int __init pmz_setup_port(struct 
 	/*
 	 * Request & map chip registers
 	 */
-	if (!early && request_OF_resource(np, 0, NULL) == NULL) {
-		printk("pmac_zilog: failed to request resources for %s\n",
-			np->full_name);
-		return -EBUSY;
-	}
 	up->port.mapbase = np->addrs[0].address;
 	up->port.membase = ioremap(up->port.mapbase, 0x1000);
       
@@ -1152,27 +1147,23 @@ static int __init pmz_setup_port(struct 
 		up->flags |= PMACZILOG_FLAG_HAS_DMA;
 #endif	
 	if (ZS_HAS_DMA(up)) {
-		if (!early && request_OF_resource(np, np->n_addrs - 2, " (tx dma)") == NULL) {
-			printk(KERN_ERR "pmac_zilog: can't request TX DMA resource !\n");
+		up->tx_dma_regs = (volatile struct dbdma_regs *)
+			ioremap(np->addrs[np->n_addrs - 2].address, 0x1000);
+		if (up->tx_dma_regs == NULL) {	
 			up->flags &= ~PMACZILOG_FLAG_HAS_DMA;
 			goto no_dma;
 		}
-		if (!early && request_OF_resource(np, np->n_addrs - 1, " (rx dma)") == NULL) {
-			release_OF_resource(np, np->n_addrs - 2);
-			printk(KERN_ERR "pmac_zilog: can't request RX DMA resource !\n");
+		up->rx_dma_regs = (volatile struct dbdma_regs *)
+			ioremap(np->addrs[np->n_addrs - 1].address, 0x1000);
+		if (up->rx_dma_regs == NULL) {	
+			iounmap((void *)up->tx_dma_regs);
 			up->flags &= ~PMACZILOG_FLAG_HAS_DMA;
 			goto no_dma;
 		}
-		up->tx_dma_regs = (volatile struct dbdma_regs *)
-			ioremap(np->addrs[np->n_addrs - 2].address, 0x1000);
-		up->rx_dma_regs = (volatile struct dbdma_regs *)
-			ioremap(np->addrs[np->n_addrs - 1].address, 0x1000);
 		up->tx_dma_irq = np->intrs[1].line;
 		up->rx_dma_irq = np->intrs[2].line;
 	}
 no_dma:
-	if (!early)
-		up->flags |= PMACZILOG_FLAG_RSRC_REQUESTED;
 
 	/*
 	 * Detect port type
@@ -1258,8 +1249,15 @@ static int pmz_attach(struct macio_dev *
 	 */
 	for (i = 0; i < MAX_ZS_PORTS; i++)
 		if (pmz_ports[i].node == mdev->ofdev.node) {
-			pmz_ports[i].dev = mdev;
-			dev_set_drvdata(&mdev->ofdev.dev, &pmz_ports[i]);
+			struct uart_pmac_port *up = &pmz_ports[i];
+
+			up->dev = mdev;
+			dev_set_drvdata(&mdev->ofdev.dev, up);
+			if (macio_request_resources(up->dev, "pmac_zilog"))
+				printk(KERN_WARNING "%s: Failed to request resource, port still active\n",
+				       up->node->name);
+			else
+				up->flags |= PMACZILOG_FLAG_RSRC_REQUESTED;				
 			return 0;
 		}
 	return -ENODEV;
@@ -1271,13 +1269,17 @@ static int pmz_attach(struct macio_dev *
  */
 static int pmz_detach(struct macio_dev *mdev)
 {
-	struct uart_pmac_port	*port = dev_get_drvdata(&mdev->ofdev.dev);
+	struct uart_pmac_port	*up = dev_get_drvdata(&mdev->ofdev.dev);
 	
-	if (!port)
+	if (!up)
 		return -ENODEV;
 
+	if (up->flags & PMACZILOG_FLAG_RSRC_REQUESTED) {
+		macio_release_resources(up->dev);
+		up->flags &= ~PMACZILOG_FLAG_RSRC_REQUESTED;
+	}
 	dev_set_drvdata(&mdev->ofdev.dev, NULL);
-	port->dev = NULL;
+	up->dev = NULL;
 	
 	return 0;
 }
@@ -1288,7 +1290,7 @@ static int pmz_detach(struct macio_dev *
  * used later to "attach" to the sysfs tree so we get power management
  * events
  */
-static int __init pmz_probe(int early)
+static int __init pmz_probe(void)
 {
 	struct device_node	*node_p, *node_a, *node_b, *np;
 	int			count = 0;
@@ -1333,9 +1335,9 @@ static int __init pmz_probe(int early)
 		/*
 		 * Setup the ports for real
 		 */
-		rc = pmz_setup_port(&pmz_ports[count], early);
+		rc = pmz_setup_port(&pmz_ports[count]);
 		if (rc == 0)
-			rc = pmz_setup_port(&pmz_ports[count+1], early);
+			rc = pmz_setup_port(&pmz_ports[count+1]);
 		if (rc != 0) {
 			of_node_put(node_a);
 			of_node_put(node_b);
@@ -1436,43 +1438,10 @@ static struct macio_driver pmz_driver = 
 //	.resume		= pmz_resume,  *** NYI
 };
 
-static void pmz_fixup_resources(void)
-{
-	int i;
-       	for (i=0; i<pmz_ports_count; i++) {
-       		struct uart_pmac_port *up = &pmz_ports[i];
-
-		if (up->node == NULL)
-			continue;
-       		if (up->flags & PMACZILOG_FLAG_RSRC_REQUESTED)
-			continue;
-		if (request_OF_resource(up->node, 0, NULL) == NULL)
-			printk(KERN_WARNING "%s: Failed to do late IO resource request, port still active\n",
-			       up->node->name);
-		up->flags |= PMACZILOG_FLAG_RSRC_REQUESTED;
-		if (!ZS_HAS_DMA(up))
-			continue;
-		if (request_OF_resource(up->node, up->node->n_addrs - 2, NULL) == NULL)
-			printk(KERN_WARNING "%s: Failed to do late DMA resource request, port still active\n",
-			       up->node->name);
-		if (request_OF_resource(up->node, up->node->n_addrs - 1, NULL) == NULL)
-			printk(KERN_WARNING "%s: Failed to do late DMA resource request, port still active\n",
-			       up->node->name);
-       	}
-
-}
-
 static int __init init_pmz(void)
 {
 	printk(KERN_DEBUG "%s\n", version);
 
-	/*
-	 * If we had serial console, then we didn't request
-	 * resources yet. We fix that up now
-	 */
-	if (pmz_ports_count > 0)
-		pmz_fixup_resources();
-
 	/* 
 	 * First, we need to do a direct OF-based probe pass. We
 	 * do that because we want serial console up before the
@@ -1481,7 +1450,7 @@ static int __init init_pmz(void)
 	 * uart_register_driver()
 	 */
 	if (pmz_ports_count == 0)
-		pmz_probe(0);
+		pmz_probe();
 
 	/*
 	 * Bail early if no port found
@@ -1610,7 +1579,7 @@ static int __init pmz_console_setup(stru
 static int __init pmz_console_init(void)
 {
 	/* Probe ports */
-	pmz_probe(1);
+	pmz_probe();
 
 	/* TODO: Autoprobe console based on OF */
 	/* pmz_console.index = i; */
diff -puN include/asm-ppc/delay.h~big-pmac-3 include/asm-ppc/delay.h
--- 25/include/asm-ppc/delay.h~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/include/asm-ppc/delay.h	2004-01-28 23:09:16.000000000 -0800
@@ -30,8 +30,8 @@ extern void __delay(unsigned int loops);
  * (which corresponds to ~3800 bogomips at HZ = 100).
  *  -- paulus
  */
-#define __MAX_UDELAY	(226050910/HZ)	/* maximum udelay argument */
-#define __MAX_NDELAY	(2147483647/HZ)	/* maximum ndelay argument */
+#define __MAX_UDELAY	(226050910UL/HZ)	/* maximum udelay argument */
+#define __MAX_NDELAY	(4294967295UL/HZ)	/* maximum ndelay argument */
 
 extern __inline__ void __udelay(unsigned int x)
 {
diff -puN include/asm-ppc/keylargo.h~big-pmac-3 include/asm-ppc/keylargo.h
--- 25/include/asm-ppc/keylargo.h~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/include/asm-ppc/keylargo.h	2004-01-28 23:09:16.000000000 -0800
@@ -18,6 +18,13 @@
 #define KEYLARGO_FCR4		0x48
 #define KEYLARGO_FCR5		0x4c	/* Pangea only */
 
+/* K2 aditional FCRs */
+#define K2_FCR6			0x34
+#define K2_FCR7			0x30
+#define K2_FCR8			0x2c
+#define K2_FCR9			0x28
+#define K2_FCR10		0x24
+
 /* GPIO registers */
 #define KEYLARGO_GPIO_LEVELS0		0x50
 #define KEYLARGO_GPIO_LEVELS1		0x54
@@ -30,6 +37,10 @@
 #define KEYLARGO_GPIO_OUTOUT_DATA	0x01
 #define KEYLARGO_GPIO_INPUT_DATA	0x02
 
+/* K2 does only extint GPIOs and does 51 of them */
+#define K2_GPIO_EXTINT_0		0x58
+#define K2_GPIO_EXTINT_CNT		51
+
 /* Specific GPIO regs */
 
 #define KL_GPIO_MODEM_RESET		(KEYLARGO_GPIO_0+0x03)
@@ -67,7 +78,8 @@
 #define KL_GPIO_AIRPORT_4		(KEYLARGO_GPIO_0+0x0f)
 
 /*
- * Bits in feature control register
+ * Bits in feature control register. Those bits different for K2 are
+ * listed separately
  */
 #define KL_MBCR_MB0_PCI_ENABLE		0x00000800	/* exist ? */
 #define KL_MBCR_MB0_IDE_ENABLE		0x00001000
@@ -202,9 +214,30 @@
 #define KL4_PORT_DISCONNECT_STAT(p)	(0x00000010 << ((p)<<3))
 
 /* Pangea and Intrepid only */
-#define KL5_VIA_USE_CLK31		0x000000001	/* Pangea Only */
-#define KL5_SCC_USE_CLK31		0x000000002	/* Pangea Only */
-#define KL5_PWM_CLK32_EN		0x000000004
-#define KL5_CLK3_68_EN			0x000000010
-#define KL5_CLK32_EN			0x000000020
+#define KL5_VIA_USE_CLK31		0000000001	/* Pangea Only */
+#define KL5_SCC_USE_CLK31		0x00000002	/* Pangea Only */
+#define KL5_PWM_CLK32_EN		0x00000004
+#define KL5_CLK3_68_EN			0x00000010
+#define KL5_CLK32_EN			0x00000020
+
+
+/* K2 definitions */
+#define K2_FCR0_USB0_SWRESET		0x00200000
+#define K2_FCR0_USB1_SWRESET		0x02000000
+#define K2_FCR0_RING_PME_DISABLE	0x08000000
+
+#define K2_FCR1_PCI1_BUS_RESET_N	0x00000010
+#define K2_FCR1_PCI1_SLEEP_RESET_EN	0x00000020
+#define K2_FCR1_PCI1_CLK_ENABLE		0x00004000
+#define K2_FCR1_FW_CLK_ENABLE		0x00008000
+#define K2_FCR1_FW_RESET_N		0x00010000
+#define K2_FCR1_GMAC_CLK_ENABLE		0x00400000
+#define K2_FCR1_GMAC_POWER_DOWN		0x00800000
+#define K2_FCR1_GMAC_RESET_N		0x01000000
+#define K2_FCR1_SATA_CLK_ENABLE		0x02000000
+#define K2_FCR1_SATA_POWER_DOWN		0x04000000
+#define K2_FCR1_SATA_RESET_N		0x08000000
+#define K2_FCR1_UATA_CLK_ENABLE		0x10000000
+#define K2_FCR1_UATA_RESET_N		0x40000000
+#define K2_FCR1_UATA_CHOOSE_CLK66	0x80000000
 
diff -puN include/asm-ppc/machdep.h~big-pmac-3 include/asm-ppc/machdep.h
--- 25/include/asm-ppc/machdep.h~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/include/asm-ppc/machdep.h	2004-01-28 23:09:16.000000000 -0800
@@ -56,6 +56,7 @@ struct machdep_calls {
 
 	unsigned char 	(*nvram_read_val)(int addr);
 	void		(*nvram_write_val)(int addr, unsigned char val);
+	void		(*nvram_sync)(void);
 
 	/*
 	 * optional PCI "hooks"
@@ -93,7 +94,7 @@ struct machdep_calls {
 	 * hook used to control some machine specific features (like reset
 	 * lines, chip power control, etc...).
 	 */
-	int (*feature_call)(unsigned int feature, ...);
+	long (*feature_call)(unsigned int feature, ...);
 
 #ifdef CONFIG_SMP
 	/* functions for dealing with other cpus */
diff -puN include/asm-ppc/macio.h~big-pmac-3 include/asm-ppc/macio.h
--- 25/include/asm-ppc/macio.h~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/include/asm-ppc/macio.h	2004-01-28 23:09:16.000000000 -0800
@@ -9,7 +9,7 @@ extern struct bus_type macio_bus_type;
 struct macio_driver;
 struct macio_chip;
 
-#define MACIO_DEV_COUNT_RESOURCE	8
+#define MACIO_DEV_COUNT_RESOURCES	8
 #define MACIO_DEV_COUNT_IRQS		8
 
 /*
@@ -38,6 +38,10 @@ struct macio_dev
 	struct macio_bus	*bus;		/* macio bus this device is on */
 	struct macio_dev	*media_bay;	/* Device is part of a media bay */
 	struct of_device	ofdev;
+	int			n_resources;
+	struct resource		resource[MACIO_DEV_COUNT_RESOURCES];
+	int			n_interrupts;
+	struct resource		interrupt[MACIO_DEV_COUNT_IRQS];
 };
 #define	to_macio_device(d) container_of(d, struct macio_dev, ofdev.dev)
 #define	of_to_macio_device(d) container_of(d, struct macio_dev, ofdev)
@@ -46,6 +50,71 @@ extern struct macio_dev *macio_dev_get(s
 extern void macio_dev_put(struct macio_dev *dev);
 
 /*
+ * Accessors to resources & interrupts and other device
+ * fields
+ */
+
+static inline int macio_resource_count(struct macio_dev *dev)
+{
+	return dev->n_resources;
+}
+
+static inline unsigned long macio_resource_start(struct macio_dev *dev, int resource_no)
+{
+	return dev->resource[resource_no].start;
+}
+
+static inline unsigned long macio_resource_end(struct macio_dev *dev, int resource_no)
+{
+	return dev->resource[resource_no].end;
+}
+
+static inline unsigned long macio_resource_len(struct macio_dev *dev, int resource_no)
+{
+	struct resource *res = &dev->resource[resource_no];
+	if (res->start == 0 || res->end == 0 || res->end < res->start)
+		return 0;
+	return res->end - res->start + 1;
+}
+
+extern int macio_request_resource(struct macio_dev *dev, int resource_no, const char *name);
+extern void macio_release_resource(struct macio_dev *dev, int resource_no);
+extern int macio_request_resources(struct macio_dev *dev, const char *name);
+extern void macio_release_resources(struct macio_dev *dev);
+
+static inline int macio_irq_count(struct macio_dev *dev)
+{
+	return dev->n_interrupts;
+}
+
+static inline int macio_irq(struct macio_dev *dev, int irq_no)
+{
+	return dev->interrupt[irq_no].start;
+}
+
+static inline void macio_set_drvdata(struct macio_dev *dev, void *data)
+{
+	dev_set_drvdata(&dev->ofdev.dev, data);
+}
+
+static inline void* macio_get_drvdata(struct macio_dev *dev)
+{
+	return dev_get_drvdata(&dev->ofdev.dev);
+}
+
+static inline struct device_node *macio_get_of_node(struct macio_dev *mdev)
+{
+	return mdev->ofdev.node;
+}
+
+#ifdef CONFIG_PCI
+static inline struct pci_dev *macio_get_pci_dev(struct macio_dev *mdev)
+{
+	return mdev->bus->pdev;
+}
+#endif
+
+/*
  * A driver for a mac-io chip based device
  */
 struct macio_driver
diff -puN include/asm-ppc/nvram.h~big-pmac-3 include/asm-ppc/nvram.h
--- 25/include/asm-ppc/nvram.h~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/include/asm-ppc/nvram.h	2004-01-28 23:09:16.000000000 -0800
@@ -34,23 +34,40 @@ enum {
 /* Return partition offset in nvram */
 extern int	pmac_get_partition(int partition);
 
-/* Direct access to XPRAM */
+/* 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 void	nvram_sync(void);
+
+/* Normal access to NVRAM */
+extern unsigned char nvram_read_byte(int i);
+extern void nvram_write_byte(unsigned char c, int i);
+
 /* Some offsets in XPRAM */
 #define PMAC_XPRAM_MACHINE_LOC	0xe4
 #define PMAC_XPRAM_SOUND_VOLUME	0x08
 
-/* Machine location structure in XPRAM */
+/* 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 */
-#define PMAC_NVRAM_GET_OFFSET	_IOWR('p', 0x40, int) /* Get NVRAM partition offset */
+/*
+ * /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 */
+#define IOC_NVRAM_SYNC		_IO('p', 0x43)		/* Sync NVRAM image */
 
 #endif
 #endif /* __KERNEL__ */
diff -puN include/asm-ppc/open_pic.h~big-pmac-3 include/asm-ppc/open_pic.h
--- 25/include/asm-ppc/open_pic.h~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/include/asm-ppc/open_pic.h	2004-01-28 23:09:16.000000000 -0800
@@ -21,8 +21,8 @@
  *  Non-offset'ed vector numbers
  */
 
-#define OPENPIC_VEC_TIMER	64	/* and up */
-#define OPENPIC_VEC_IPI		72	/* and up */
+#define OPENPIC_VEC_TIMER	110	/* and up */
+#define OPENPIC_VEC_IPI		118	/* and up */
 #define OPENPIC_VEC_SPURIOUS	127
 
 /* OpenPIC IRQ controller structure */
@@ -51,6 +51,7 @@ extern void openpic_setup_ISU(int isu_nu
 extern void openpic_cause_IPI(u_int ipi, u_int cpumask);
 extern void smp_openpic_message_pass(int target, int msg, unsigned long data,
 				     int wait);
+extern void openpic_set_k2_cascade(int irq);
 
 extern inline int openpic_to_irq(int irq)
 {
@@ -64,5 +65,25 @@ extern inline int openpic_to_irq(int irq
 		return 0;
 	}
 }
-/*extern int open_pic_irq_offset;*/
+/* Support for second openpic on G5 macs */
+
+// FIXME: To be replaced by sane cascaded controller management */
+
+#define PMAC_OPENPIC2_OFFSET	128
+
+#define OPENPIC2_VEC_TIMER	110	/* and up */
+#define OPENPIC2_VEC_IPI	118	/* and up */
+#define OPENPIC2_VEC_SPURIOUS	127
+
+
+extern void* OpenPIC2_Addr;
+
+/* Exported functions */
+extern void openpic2_set_sources(int first_irq, int num_irqs, void *isr);
+extern void openpic2_init(int linux_irq_offset);
+extern void openpic2_init_nmi_irq(u_int irq);
+extern u_int openpic2_irq(void);
+extern void openpic2_eoi(void);
+extern int openpic2_get_irq(struct pt_regs *regs);
+extern void openpic2_setup_ISU(int isu_num, unsigned long addr);
 #endif /* _PPC_KERNEL_OPEN_PIC_H */
diff -puN include/asm-ppc/pgtable.h~big-pmac-3 include/asm-ppc/pgtable.h
--- 25/include/asm-ppc/pgtable.h~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/include/asm-ppc/pgtable.h	2004-01-28 23:09:16.000000000 -0800
@@ -511,9 +511,21 @@ static inline void set_pte(pte_t *ptep, 
 #endif
 }
 
+extern void flush_hash_one_pte(pte_t *ptep);
+
+/*
+ * 2.6 calles this without flushing the TLB entry, this is wrong
+ * for our hash-based implementation, we fix that up here
+ */
 static inline int ptep_test_and_clear_young(pte_t *ptep)
 {
-	return (pte_update(ptep, _PAGE_ACCESSED, 0) & _PAGE_ACCESSED) != 0;
+	unsigned long old;
+	old = (pte_update(ptep, _PAGE_ACCESSED, 0) & _PAGE_ACCESSED);
+#if _PAGE_HASHPTE != 0
+	if (old & _PAGE_HASHPTE)
+		flush_hash_one_pte(ptep);
+#endif
+	return old != 0;
 }
 
 static inline int ptep_test_and_clear_dirty(pte_t *ptep)
diff -puN include/asm-ppc/pmac_feature.h~big-pmac-3 include/asm-ppc/pmac_feature.h
--- 25/include/asm-ppc/pmac_feature.h~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/include/asm-ppc/pmac_feature.h	2004-01-28 23:09:16.000000000 -0800
@@ -112,6 +112,10 @@
  */
 #define PMAC_TYPE_UNKNOWN_INTREPID	0x11f	/* Generic */
 
+/* MacRISC4 / G5 machines
+ */
+#define PMAC_TYPE_POWERMAC_G5		0x150	/* First tower */
+
 /*
  * Motherboard flags
  */
@@ -131,8 +135,8 @@
  */
 struct device_node;
 
-static inline int pmac_call_feature(int selector, struct device_node* node,
-					int param, int value)
+static inline long pmac_call_feature(int selector, struct device_node* node,
+					long param, long value)
 {
 	if (!ppc_md.feature_call)
 		return -ENODEV;
@@ -262,9 +266,15 @@ static inline int pmac_call_feature(int 
  */
 #define PMAC_FTR_WRITE_GPIO		PMAC_FTR_DEF(18)
 
+/* PMAC_FTR_ENABLE_MPIC
+ *
+ * Enable the MPIC cell
+ */
+#define PMAC_FTR_ENABLE_MPIC		PMAC_FTR_DEF(19)
+
 
 /* Don't use those directly, they are for the sake of pmac_setup.c */
-extern int pmac_do_feature_call(unsigned int selector, ...);
+extern long pmac_do_feature_call(unsigned int selector, ...);
 extern void pmac_feature_init(void);
 
 #define PMAC_FTR_DEF(x) ((_MACH_Pmac << 16) | (x))
@@ -289,6 +299,7 @@ enum {
 	macio_keylargo,
 	macio_pangea,
 	macio_intrepid,
+	macio_keylargo2,
 };
 
 struct macio_chip
diff -puN /dev/null include/asm-ppc/pmac_low_i2c.h
--- /dev/null	2002-08-30 16:31:37.000000000 -0700
+++ 25-akpm/include/asm-ppc/pmac_low_i2c.h	2004-01-28 23:09:16.000000000 -0800
@@ -0,0 +1,43 @@
+/* 
+ *  include/asm-ppc/pmac_low_i2c.h
+ *
+ *  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.
+ *
+ */
+#ifndef __PMAC_LOW_I2C_H__
+#define __PMAC_LOW_I2C_H__
+
+/* i2c mode (based on the platform functions format) */
+enum {
+	pmac_low_i2c_mode_dumb		= 1,
+	pmac_low_i2c_mode_std		= 2,
+	pmac_low_i2c_mode_stdsub	= 3,
+	pmac_low_i2c_mode_combined	= 4,
+};
+
+/* RW bit in address */
+enum {
+	pmac_low_i2c_read		= 0x01,
+	pmac_low_i2c_write		= 0x00
+};
+
+/* Init, called early during boot */
+extern void pmac_init_low_i2c(void);
+
+/* Locking functions exposed to i2c-keywest */
+int pmac_low_i2c_lock(struct device_node *np);
+int pmac_low_i2c_unlock(struct device_node *np);
+
+/* Access functions for platform code */
+int pmac_low_i2c_open(struct device_node *np, int channel);
+int pmac_low_i2c_close(struct device_node *np);
+int pmac_low_i2c_setmode(struct device_node *np, int mode);
+int pmac_low_i2c_xfer(struct device_node *np, u8 addrdir, u8 subaddr, u8 *data, int len);
+
+
+#endif /* __PMAC_LOW_I2C_H__ */
diff -puN include/asm-ppc/reg.h~big-pmac-3 include/asm-ppc/reg.h
--- 25/include/asm-ppc/reg.h~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/include/asm-ppc/reg.h	2004-01-28 23:09:16.000000000 -0800
@@ -91,6 +91,7 @@
 #define SPRN_TBRU	0x10D	/* Time Base Read Upper Register (user, R/O) */
 #define SPRN_TBWL	0x11C	/* Time Base Lower Register (super, R/W) */
 #define SPRN_TBWU	0x11D	/* Time Base Upper Register (super, R/W) */
+#define SPRN_HIOR	0x137	/* 970 Hypervisor interrupt offset */
 #define SPRN_DBAT0L	0x219	/* Data BAT 0 Lower Register */
 #define SPRN_DBAT0U	0x218	/* Data BAT 0 Upper Register */
 #define SPRN_DBAT1L	0x21B	/* Data BAT 1 Lower Register */
@@ -179,7 +180,10 @@
 #define HID1_PC3	(1<<13)		/* 7450 PLL_CFG[3] */
 #define HID1_SYNCBE	(1<<11)		/* 7450 ABE for sync, eieio */
 #define HID1_ABE	(1<<10)		/* 7450 Address Broadcast Enable */
+#define SPRN_HID2	0x3F8		/* Hardware Implementation Register 2 */
 #define SPRN_IABR	0x3F2	/* Instruction Address Breakpoint Register */
+#define SPRN_HID4	0x3F4		/* 970 HID4 */
+#define SPRN_HID5	0x3F6		/* 970 HID5 */
 #if !defined(SPRN_IAC1) && !defined(SPRN_IAC2)
 #define SPRN_IAC1	0x3F4		/* Instruction Address Compare 1 */
 #define SPRN_IAC2	0x3F5		/* Instruction Address Compare 2 */
diff -puN include/asm-ppc/uninorth.h~big-pmac-3 include/asm-ppc/uninorth.h
--- 25/include/asm-ppc/uninorth.h~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/include/asm-ppc/uninorth.h	2004-01-28 23:09:16.000000000 -0800
@@ -1,6 +1,8 @@
 /*
  * uninorth.h: definitions for using the "UniNorth" host bridge chip
  *             from Apple. This chip is used on "Core99" machines
+ *	       This also includes U2 used on more recent MacRISC2/3
+ *             machines and U3 (G5) 
  *
  */
 #ifdef __KERNEL__
@@ -8,23 +10,26 @@
 #define __ASM_UNINORTH_H__
 
 /*
- * Uni-N config space reg. definitions
+ * Uni-N and U3 config space reg. definitions
  *
  * (Little endian)
  */
 
 /* Address ranges selection. This one should work with Bandit too */
+/* Not U3 */
 #define UNI_N_ADDR_SELECT		0x48
 #define UNI_N_ADDR_COARSE_MASK		0xffff0000	/* 256Mb regions at *0000000 */
 #define UNI_N_ADDR_FINE_MASK		0x0000ffff	/*  16Mb regions at f*000000 */
 
 /* AGP registers */
+/* Not U3 */
 #define UNI_N_CFG_GART_BASE		0x8c
 #define UNI_N_CFG_AGP_BASE		0x90
 #define UNI_N_CFG_GART_CTRL		0x94
 #define UNI_N_CFG_INTERNAL_STATUS	0x98
 
 /* UNI_N_CFG_GART_CTRL bits definitions */
+/* Not U3 */
 #define UNI_N_CFG_GART_INVAL		0x00000001
 #define UNI_N_CFG_GART_ENABLE		0x00000100
 #define UNI_N_CFG_GART_2xRESET		0x00010000
@@ -90,6 +95,14 @@
 /* Version of the UniNorth chip */
 #define UNI_N_VERSION			0x0000		/* Known versions: 3,7 and 8 */
 
+#define UNI_N_VERSION_107		0x0003		/* 1.0.7 */
+#define UNI_N_VERSION_10A		0x0007		/* 1.0.10 */
+#define UNI_N_VERSION_150		0x0011		/* 1.5 */
+#define UNI_N_VERSION_200		0x0024		/* 2.0 */
+#define UNI_N_VERSION_PANGEA		0x00C0		/* Integrated U1 + K */
+#define UNI_N_VERSION_INTREPID		0x00D2		/* Integrated U2 + K */
+#define UNI_N_VERSION_300		0x0030		/* 3.0 (U3 on G5) */
+
 /* This register is used to enable/disable various clocks */
 #define UNI_N_CLOCK_CNTL		0x0020
 #define UNI_N_CLOCK_CNTL_PCI		0x00000001	/* PCI2 clock control */
@@ -131,5 +144,26 @@
 
 /* Uninorth 1.5 rev. has additional perf. monitor registers at 0xf00-0xf50 */
 
+
+/*
+ * U3 specific registers
+ */
+
+
+/* U3 Toggle */
+#define U3_TOGGLE_REG			0x00e0
+#define U3_PMC_START_STOP		0x0001
+#define U3_MPIC_RESET			0x0002
+#define U3_MPIC_OUTPUT_ENABLE		0x0004
+
+/* U3 API PHY Config 1 */
+#define U3_API_PHY_CONFIG_1		0x23030
+
+/* U3 HyperTransport registers */
+#define U3_HT_CONFIG_BASE      		0x70000
+#define U3_HT_LINK_COMMAND		0x100
+#define U3_HT_LINK_CONFIG		0x110
+#define U3_HT_LINK_FREQ			0x120
+
 #endif /* __ASM_UNINORTH_H__ */
 #endif /* __KERNEL__ */
diff -puN include/linux/pci_ids.h~big-pmac-3 include/linux/pci_ids.h
--- 25/include/linux/pci_ids.h~big-pmac-3	2004-01-28 23:09:16.000000000 -0800
+++ 25-akpm/include/linux/pci_ids.h	2004-01-28 23:09:16.000000000 -0800
@@ -711,6 +711,7 @@
 #define PCI_DEVICE_ID_TI_1410		0xac50
 #define PCI_DEVICE_ID_TI_1420		0xac51
 #define PCI_DEVICE_ID_TI_1520		0xac55
+#define PCI_DEVICE_ID_TI_1510		0xac56
 
 #define PCI_VENDOR_ID_SONY		0x104d
 #define PCI_DEVICE_ID_SONY_CXD3222	0x8039
@@ -806,9 +807,12 @@
 #define PCI_DEVICE_ID_APPLE_UNI_N_AGP15	0x002d
 #define PCI_DEVICE_ID_APPLE_UNI_N_FW2	0x0030
 #define PCI_DEVICE_ID_APPLE_UNI_N_GMAC2	0x0032
+#define PCI_DEVIEC_ID_APPLE_UNI_N_ATA	0x0033
 #define PCI_DEVICE_ID_APPLE_UNI_N_AGP2	0x0034
-#define PCI_DEVICE_ID_APPLE_KAUAI_ATA	0x003b
+#define PCI_DEVICE_ID_APPLE_IPID_ATA100	0x003b
 #define PCI_DEVICE_ID_APPLE_KEYLARGO_I	0x003e
+#define PCI_DEVICE_ID_APPLE_K2_ATA100	0x0043
+#define PCI_DEVICE_ID_APPLE_K2_GMAC	0x004c
 #define PCI_DEVICE_ID_APPLE_TIGON3	0x1645
 
 #define PCI_VENDOR_ID_YAMAHA		0x1073

_
