---
/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-25 23:39:04.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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/configs/pmac_defconfig 2004-01-25 23:39:04.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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/Kconfig 2004-01-25 23:39:04.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 .
-
- 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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/kernel/cpu_setup_6xx.S 2004-01-25 23:39:04.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-25 23:39:04.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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+_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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/kernel/head.S 2004-01-25 23:39:04.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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/kernel/idle_power4.S 2004-01-25 23:39:04.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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/kernel/Makefile 2004-01-25 23:39:04.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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/kernel/misc.S 2004-01-25 23:39:04.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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/kernel/pci.c 2004-01-25 23:39:04.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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/kernel/ppc_ksyms.c 2004-01-25 23:39:04.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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/kernel/setup.c 2004-01-25 23:39:04.000000000 -0800
@@ -35,6 +35,7 @@
#include
#include
#include
+#include
#include
#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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/kernel/smp.c 2004-01-25 23:39:04.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-25 23:39:04.000000000 -0800
@@ -0,0 +1,181 @@
+/*
+ * Smp timebase synchronization for ppc.
+ *
+ * Copyright (C) 2003 Samuel Rydh (samuel@ibrium.se)
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#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; itbu = 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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/mm/hashtable.S 2004-01-25 23:39:04.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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/mm/init.c 2004-01-25 23:39:04.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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/mm/pgtable.c 2004-01-25 23:39:04.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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/mm/ppc_mmu.c 2004-01-25 23:39:04.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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/mm/tlb.c 2004-01-25 23:39:04.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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/platforms/Makefile 2004-01-25 23:39:04.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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/platforms/pmac_backlight.c 2004-01-25 23:39:04.000000000 -0800
@@ -8,6 +8,7 @@
#include
#include
+#include
#include
#include
#include
@@ -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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/platforms/pmac_cpufreq.c 2004-01-25 23:39:04.000000000 -0800
@@ -22,6 +22,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/platforms/pmac_feature.c 2004-01-25 23:39:04.000000000 -0800
@@ -41,6 +41,7 @@
#include
#include
#include
+#include
#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-25 23:39:04.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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/platforms/pmac_nvram.c 2004-01-25 23:39:04.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
#include
@@ -21,29 +20,40 @@
#include
#include
#include
+#include
+#include
+#include
+#include
+#include
#include
#include
#include
#include
#include
#include
-#include
-#include
-#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 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 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 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; igeneration++;
+ 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; iaddrs[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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/platforms/pmac_pci.c 2004-01-25 23:39:04.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 = ¯isc_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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/platforms/pmac_pic.c 2004-01-25 23:39:04.000000000 -0800
@@ -34,6 +34,7 @@
#include
#include
#include
+#include
#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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/platforms/pmac_setup.c 2004-01-25 23:39:04.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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/platforms/pmac_smp.c 2004-01-25 23:39:04.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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/platforms/pmac_time.c 2004-01-25 23:39:04.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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/syslib/Makefile 2004-01-25 23:39:04.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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/syslib/of_device.c 2004-01-25 23:39:04.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-25 23:39:05.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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#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; iProcessor[i].Current_Task_Priority);
+ openpic2_writefield(&OpenPIC2->Processor[i].Current_Task_Priority,
+ OPENPIC_CURRENT_TASK_PRIORITY_MASK, 0xf);
+ }
+
+ for (i=0; iGlobal.IPI_Vector_Priority(i));
+ for (i=0; iVector_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; iGlobal.IPI_Vector_Priority(i),
+ save_ipi_vp[i]);
+ for (i=0; iDestination, 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; iProcessor[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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/syslib/open_pic.c 2004-01-25 23:39:04.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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/syslib/prom.c 2004-01-25 23:39:05.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-25 23:39:04.000000000 -0800
+++ 25-akpm/arch/ppc/syslib/prom_init.c 2004-01-25 23:39:05.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-25 23:39:04.000000000 -0800
+++ 25-akpm/drivers/block/swim3.c 2004-01-25 23:39:05.000000000 -0800
@@ -24,7 +24,10 @@
#include
#include
#include
+#include
#include
+#include
+#include
#include
#include
#include
@@ -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-25 23:39:05.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
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#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-25 23:39:04.000000000 -0800
+++ 25-akpm/drivers/char/keyboard.c 2004-01-25 23:39:05.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-25 23:39:04.000000000 -0800
+++ 25-akpm/drivers/char/Makefile 2004-01-25 23:39:05.000000000 -0800
@@ -57,7 +57,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-25 23:39:04.000000000 -0800
+++ 25-akpm/drivers/i2c/busses/i2c-keywest.c 2004-01-25 23:39:05.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
#include
#include
+#include
#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 ");
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; ichan_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-25 23:39:04.000000000 -0800
+++ 25-akpm/drivers/i2c/busses/i2c-keywest.h 2004-01-25 23:39:05.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-25 23:39:04.000000000 -0800
+++ 25-akpm/drivers/ide/ppc/pmac.c 2004-01-25 23:39:05.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-25 23:39:04.000000000 -0800
+++ 25-akpm/drivers/Kconfig 2004-01-25 23:39:05.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-25 23:39:04.000000000 -0800
+++ 25-akpm/drivers/macintosh/adb.c 2004-01-25 23:39:05.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-25 23:39:04.000000000 -0800
+++ 25-akpm/drivers/macintosh/adbhid.c 2004-01-25 23:39:05.000000000 -0800
@@ -30,6 +30,8 @@
* To do:
*
* Improve Kensington support.
+ * Split mouse/kbd
+ * Move to syfs
*/
#include
@@ -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-25 23:39:05.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 .
+
+ 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-25 23:39:04.000000000 -0800
+++ 25-akpm/drivers/macintosh/macio_asic.c 2004-01-25 23:39:05.000000000 -0800
@@ -23,10 +23,13 @@
#include
#include
+#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-25 23:39:04.000000000 -0800
+++ 25-akpm/drivers/macintosh/Makefile 2004-01-25 23:39:05.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-25 23:39:04.000000000 -0800
+++ 25-akpm/drivers/macintosh/mediabay.c 2004-01-25 23:39:05.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
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#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-25 23:39:05.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
+ *
+ *
+ *
+ * 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#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 ");
+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-25 23:39:05.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-25 23:39:05.000000000 -0800
@@ -0,0 +1,456 @@
+/*
+ * Creation Date: <2003/03/14 20:54:13 samuel>
+ * Time-stamp: <2003/03/15 18:55:53 samuel>
+ *
+ *
+ *
+ * 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+MODULE_AUTHOR("Samuel Rydh ");
+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-25 23:39:04.000000000 -0800
+++ 25-akpm/drivers/macintosh/via-pmu.c 2004-01-25 23:39:05.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-25 23:39:04.000000000 -0800
+++ 25-akpm/drivers/net/bmac.c 2004-01-25 23:39:05.000000000 -0800
@@ -26,11 +26,9 @@
#include
#include
#include
+#include
#include
-#ifdef CONFIG_PMAC_PBOOK
-#include
-#include
-#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; irx_bufs[i] != NULL) {
- dev_kfree_skb(bp->rx_bufs[i]);
- bp->rx_bufs[i] = NULL;
- }
- }
- for (i = 0; itx_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; irx_bufs[i] != NULL) {
+ dev_kfree_skb(bp->rx_bufs[i]);
+ bp->rx_bufs[i] = NULL;
+ }
+ }
+ for (i = 0; itx_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-25 23:39:04.000000000 -0800
+++ 25-akpm/drivers/scsi/mac53c94.c 2004-01-25 23:39:05.000000000 -0800
@@ -23,6 +23,7 @@
#include
#include
#include
+#include
#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, ®s->command); /* assert RST */
udelay(100); /* leave it on for a while (>= 25us) */
- regs->command = CMD_RESET;
- eieio();
+ writeb(CMD_RESET, ®s->command);
udelay(20);
mac53c94_init(state);
- regs->command = CMD_NOP;
- eieio();
+ writeb(CMD_NOP, ®s->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, ®s->config1);
+ writeb(TIMO_VAL(250), ®s->sel_timeout); /* 250ms */
+ writeb(CLKF_VAL(state->clk_freq), ®s->clk_factor);
+ writeb(CF2_FEATURE_EN, ®s->config2);
+ writeb(0, ®s->config3);
+ writeb(0, ®s->sync_period);
+ writeb(0, ®s->sync_offset);
+ x = readb(®s->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, ®s->count_lo);
+ writeb(0, ®s->count_mid);
+ writeb(0, ®s->count_hi);
+ writeb(CMD_NOP + CMD_DMA_MODE, ®s->command);
udelay(1);
- eieio();
- regs->command = CMD_FLUSH;
+ writeb(CMD_FLUSH, ®s->command);
udelay(1);
- eieio();
- regs->dest_id = cmd->device->id;
- regs->sync_period = 0;
- regs->sync_offset = 0;
- eieio();
+ writeb(cmd->device->id, ®s->dest_id);
+ writeb(0, ®s->sync_period);
+ writeb(0, ®s->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], ®s->fifo);
/* do select without ATN XXX */
- regs->command = CMD_SELECT;
+ writeb(CMD_SELECT, ®s->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(®s->seqstep);
+ stat = readb(®s->status);
+ intr = readb(®s->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, ®s->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, ®s->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, ®s->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, ®s->count_lo);
+ writeb(nb >> 8, ®s->count_mid);
+ writeb(CMD_DMA_MODE + CMD_NOP, ®s->command);
+ writel(virt_to_phys(state->dma_cmds), &dma->cmdptr);
+ writel((RUN << 16) | RUN, &dma->control);
+ writeb(CMD_DMA_MODE + CMD_XFER_DATA, ®s->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, ®s->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, ®s->count_lo);
+ writeb(nb >> 8, ®s->count_mid);
+ writeb(CMD_DMA_MODE + CMD_NOP, ®s->command);
+ writeb(CMD_DMA_MODE + CMD_XFER_DATA, ®s->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, ®s->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(®s->fifo);
+ cmd->SCp.Message = readb(®s->fifo);
+ cmd->result = CMD_ACCEPT_MSG;
+ writeb(CMD_ACCEPT_MSG, ®s->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 ");
+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-25 23:39:04.000000000 -0800
+++ 25-akpm/drivers/scsi/mesh.c 2004-01-25 23:39:05.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
#include
@@ -38,10 +42,7 @@
#include
#include
#include
-#ifdef CONFIG_PMAC_PBOOK
-#include
-#include
-#endif
+#include
#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-25 23:39:04.000000000 -0800
+++ 25-akpm/drivers/serial/pmac_zilog.c 2004-01-25 23:39:05.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; inode == 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-25 23:39:04.000000000 -0800
+++ 25-akpm/include/asm-ppc/delay.h 2004-01-25 23:39:05.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-25 23:39:04.000000000 -0800
+++ 25-akpm/include/asm-ppc/keylargo.h 2004-01-25 23:39:05.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-25 23:39:04.000000000 -0800
+++ 25-akpm/include/asm-ppc/machdep.h 2004-01-25 23:39:05.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-25 23:39:04.000000000 -0800
+++ 25-akpm/include/asm-ppc/macio.h 2004-01-25 23:39:05.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-25 23:39:04.000000000 -0800
+++ 25-akpm/include/asm-ppc/nvram.h 2004-01-25 23:39:05.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-25 23:39:04.000000000 -0800
+++ 25-akpm/include/asm-ppc/open_pic.h 2004-01-25 23:39:05.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-25 23:39:04.000000000 -0800
+++ 25-akpm/include/asm-ppc/pgtable.h 2004-01-25 23:39:05.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-25 23:39:04.000000000 -0800
+++ 25-akpm/include/asm-ppc/pmac_feature.h 2004-01-25 23:39:05.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-25 23:39:05.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-25 23:39:04.000000000 -0800
+++ 25-akpm/include/asm-ppc/reg.h 2004-01-25 23:39:05.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-25 23:39:04.000000000 -0800
+++ 25-akpm/include/asm-ppc/uninorth.h 2004-01-25 23:39:05.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-25 23:39:04.000000000 -0800
+++ 25-akpm/include/linux/pci_ids.h 2004-01-25 23:39:05.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
_