--- /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-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/configs/pmac_defconfig 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/Kconfig 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/kernel/cpu_setup_6xx.S 2004-02-04 00:29:23.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-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/kernel/head.S 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/kernel/idle_power4.S 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/kernel/Makefile 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/kernel/misc.S 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/kernel/pci.c 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/kernel/ppc_ksyms.c 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/kernel/setup.c 2004-02-04 00:29:23.000000000 -0800 @@ -35,6 +35,7 @@ #include #include #include +#include #include #if defined CONFIG_KGDB @@ -111,6 +112,9 @@ struct screen_info screen_info = { void machine_restart(char *cmd) { +#ifdef CONFIG_NVRAM + nvram_sync(); +#endif ppc_md.restart(cmd); } @@ -118,6 +122,9 @@ EXPORT_SYMBOL(machine_restart); void machine_power_off(void) { +#ifdef CONFIG_NVRAM + nvram_sync(); +#endif ppc_md.power_off(); } @@ -125,6 +132,9 @@ EXPORT_SYMBOL(machine_power_off); void machine_halt(void) { +#ifdef CONFIG_NVRAM + nvram_sync(); +#endif ppc_md.halt(); } @@ -558,24 +568,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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/kernel/smp.c 2004-02-04 00:29:23.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-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/mm/hashtable.S 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/mm/init.c 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/mm/pgtable.c 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/mm/ppc_mmu.c 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/mm/tlb.c 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/platforms/Makefile 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/platforms/pmac_backlight.c 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/platforms/pmac_cpufreq.c 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/platforms/pmac_feature.c 2004-02-04 00:29:23.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-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/platforms/pmac_nvram.c 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/platforms/pmac_pci.c 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/platforms/pmac_pic.c 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/platforms/pmac_setup.c 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/platforms/pmac_smp.c 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/platforms/pmac_time.c 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/syslib/Makefile 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/syslib/of_device.c 2004-02-04 00:29:23.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-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/syslib/open_pic.c 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/syslib/prom.c 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/arch/ppc/syslib/prom_init.c 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/drivers/block/swim3.c 2004-02-04 00:29:23.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-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/drivers/char/keyboard.c 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/drivers/char/Makefile 2004-02-04 00:29:23.000000000 -0800 @@ -56,7 +56,9 @@ obj-$(CONFIG_SONYPI) += sonypi.o obj-$(CONFIG_RTC) += rtc.o obj-$(CONFIG_GEN_RTC) += genrtc.o obj-$(CONFIG_EFI_RTC) += efirtc.o -ifeq ($(CONFIG_PPC),) +ifeq ($(CONFIG_GENERIC_NVRAM),y) + obj-$(CONFIG_NVRAM) += generic_nvram.o +else obj-$(CONFIG_NVRAM) += nvram.o endif obj-$(CONFIG_TOSHIBA) += toshiba.o diff -puN drivers/i2c/busses/i2c-keywest.c~big-pmac-3 drivers/i2c/busses/i2c-keywest.c --- 25/drivers/i2c/busses/i2c-keywest.c~big-pmac-3 2004-02-04 00:29:23.000000000 -0800 +++ 25-akpm/drivers/i2c/busses/i2c-keywest.c 2004-02-04 00:29:23.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/drivers/i2c/busses/i2c-keywest.h 2004-02-04 00:29:24.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/drivers/ide/ppc/pmac.c 2004-02-04 00:29:24.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/drivers/Kconfig 2004-02-04 00:29:24.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/drivers/macintosh/adb.c 2004-02-04 00:29:24.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/drivers/macintosh/adbhid.c 2004-02-04 00:29:24.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-02-04 00:29:24.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/drivers/macintosh/macio_asic.c 2004-02-04 00:29:24.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/drivers/macintosh/Makefile 2004-02-04 00:29:24.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/drivers/macintosh/mediabay.c 2004-02-04 00:29:24.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-02-04 00:29:24.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-02-04 00:29:24.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-02-04 00:29:24.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/drivers/macintosh/via-pmu.c 2004-02-04 00:29:24.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/drivers/net/bmac.c 2004-02-04 00:29:24.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/drivers/scsi/mac53c94.c 2004-02-04 00:29:24.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/drivers/scsi/mesh.c 2004-02-04 00:29:24.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/drivers/serial/pmac_zilog.c 2004-02-04 00:29:24.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/include/asm-ppc/delay.h 2004-02-04 00:29:24.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/include/asm-ppc/keylargo.h 2004-02-04 00:29:24.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/include/asm-ppc/machdep.h 2004-02-04 00:29:24.000000000 -0800 @@ -57,6 +57,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" @@ -94,7 +95,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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/include/asm-ppc/macio.h 2004-02-04 00:29:24.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/include/asm-ppc/nvram.h 2004-02-04 00:29:24.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/include/asm-ppc/open_pic.h 2004-02-04 00:29:24.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/include/asm-ppc/pgtable.h 2004-02-04 00:29:24.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/include/asm-ppc/pmac_feature.h 2004-02-04 00:29:24.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-02-04 00:29:24.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/include/asm-ppc/reg.h 2004-02-04 00:29:24.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/include/asm-ppc/uninorth.h 2004-02-04 00:29:24.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-02-04 00:29:23.000000000 -0800 +++ 25-akpm/include/linux/pci_ids.h 2004-02-04 00:29:24.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 _