# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet v2.5.66 -> 1.1011 # drivers/video/fbmem.c 1.64 -> 1.65 # fs/xfs/linux/xfs_lrw.c 1.17 -> 1.18 # include/acpi/acglobal.h 1.21 -> 1.22 # drivers/media/video/saa7110.c 1.9 -> 1.10 # drivers/video/vfb.c 1.25 -> 1.26 # arch/sparc64/kernel/pci.c 1.27 -> 1.29 # fs/nfs/read.c 1.30 -> 1.32 # drivers/char/drm/drm_agpsupport.h 1.15 -> 1.16 # drivers/char/ipmi/ipmi_kcs_intf.c 1.3 -> 1.4 # drivers/net/znet.c 1.10 -> 1.11 # include/pcmcia/ds.h 1.6 -> 1.8 # arch/sparc64/kernel/smp.c 1.52 -> 1.53 # arch/ppc64/kernel/pci.h 1.7 -> 1.8 # include/acpi/acpixf.h 1.20 -> 1.22 # drivers/pcmcia/cs_internal.h 1.5 -> 1.10 # drivers/i2c/chips/Makefile 1.2 -> 1.4 # include/pcmcia/cs.h 1.2 -> 1.3 # drivers/i2c/chips/lm75.c 1.7 -> 1.13 # Documentation/swsusp.txt 1.5 -> 1.7 # fs/xfs/xfs_mount.h 1.9 -> 1.11 # include/asm-x86_64/hdreg.h 1.2 -> 1.3 # include/asm-ppc64/ioctls.h 1.1 -> 1.2 # drivers/media/video/tda9887.c 1.3 -> 1.4 # include/asm-v850/softirq.h 1.1 -> (deleted) # arch/sparc64/boot/Makefile 1.6 -> 1.7 # fs/xfs/linux/xfs_linux.h 1.16 -> 1.17 # fs/xfs/support/mutex.h 1.1 -> 1.2 # include/asm-ppc/pmac_feature.h 1.8 -> 1.9 # drivers/media/video/bt856.c 1.7 -> 1.8 # drivers/ide/ide-taskfile.c 1.13 -> 1.14 # crypto/digest.c 1.14 -> 1.15 # arch/x86_64/kernel/traps.c 1.17 -> 1.18 # fs/befs/btree.c 1.4 -> 1.5 # fs/libfs.c 1.14 -> 1.15 # arch/arm/mach-sa1100/assabet.c 1.18 -> 1.19 # arch/x86_64/mm/fault.c 1.10 -> 1.11 # include/asm-x86_64/numa.h 1.1 -> 1.2 # arch/alpha/kernel/module.c 1.3 -> 1.4 # Documentation/filesystems/sysv-fs.txt 1.1 -> 1.2 # kernel/ksyms.c 1.186 -> 1.187 # arch/arm/kernel/entry-common.S 1.13 -> 1.14 # drivers/pcmcia/sa1100_graphicsclient.c 1.6 -> 1.7 # include/asm-ppc64/softirq.h 1.5 -> (deleted) # fs/xfs/linux/xfs_vfs.h 1.4 -> 1.7 # arch/sparc64/kernel/us3_cpufreq.c 1.5 -> 1.6 # crypto/internal.h 1.16 -> 1.18 # arch/arm/mach-sa1100/cpu-sa1110.c 1.19 -> 1.20 # drivers/pcmcia/sa1100_freebird.c 1.9 -> 1.10 # include/acpi/acpiosxf.h 1.24 -> 1.26 # arch/x86_64/ia32/fpu32.c 1.5 -> 1.6 # Documentation/IPMI.txt 1.1 -> 1.2 # mm/fremap.c 1.7 -> 1.8 # drivers/i2c/chips/adm1021.c 1.7 -> 1.13 # drivers/i2c/Makefile 1.8 -> 1.9 # include/net/irda/irlmp.h 1.13 -> 1.14 # arch/sparc/kernel/setup.c 1.17 -> 1.18 # drivers/acpi/hardware/hwgpe.c 1.17 -> 1.18 # drivers/net/tulip/de4x5.c 1.23 -> 1.24 # net/ipv4/xfrm_input.c 1.8 -> 1.9 net/xfrm/xfrm_input.c (moved) # include/linux/aio.h 1.7 -> 1.8 # include/asm-s390/bitops.h 1.9 -> 1.10 # fs/xfs/support/atomic.h 1.1 -> 1.2 # include/linux/swap.h 1.73 -> 1.76 # include/linux/buffer_head.h 1.39 -> 1.40 # drivers/scsi/scsi_pc98.c 1.1 -> 1.2 # fs/xfs/support/mrlock.c 1.2 -> 1.3 # drivers/i2c/i2c-elektor.c 1.14 -> 1.15 # include/asm-sparc/softirq.h 1.6 -> (deleted) # fs/cramfs/inode.c 1.26 -> 1.27 # drivers/net/3c509.c 1.34 -> 1.35 # drivers/usb/net/cdc-ether.c 1.27 -> 1.28 # fs/xfs/pagebuf/page_buf.c 1.45 -> 1.47 # fs/xfs/xfs_qm.c 1.9 -> 1.11 fs/xfs/quota/xfs_qm.c (moved) # drivers/media/video/saa7185.c 1.9 -> 1.10 # net/irda/irnet/irnet_irda.c 1.14 -> 1.16 # fs/sysfs/file.c 1.3 -> 1.4 # arch/sparc/kernel/irq.c 1.21 -> 1.22 # arch/x86_64/kernel/setup.c 1.10 -> 1.11 # include/asm-ppc64/termios.h 1.1 -> 1.2 # drivers/scsi/aha152x.c 1.25 -> 1.27 # include/linux/raid/md_k.h 1.56 -> 1.57 # drivers/pcmcia/sa1100_pangolin.c 1.9 -> 1.10 # arch/i386/kernel/apm.c 1.47 -> 1.48 # net/Kconfig 1.7 -> 1.9 # net/ipv6/ip6_output.c 1.14 -> 1.15 # drivers/acpi/fan.c 1.11 -> 1.12 # arch/sparc64/lib/Makefile 1.9 -> 1.10 # mm/page_alloc.c 1.149 -> 1.150 # arch/alpha/kernel/pci.c 1.28 -> 1.29 # include/asm-ppc64/pci-bridge.h 1.5 -> 1.6 # arch/alpha/kernel/alpha_ksyms.c 1.32 -> 1.33 # include/linux/idr.h 1.2 -> 1.3 # drivers/acpi/utilities/utmisc.c 1.22 -> 1.23 # include/asm-arm/proc-armv/pgtable.h 1.11 -> 1.12 # drivers/char/drm/i830_dma.c 1.12 -> 1.13 # drivers/usb/host/ohci-hcd.c 1.39 -> 1.40 # arch/sparc/kernel/sparc_ksyms.c 1.14 -> 1.15 # include/asm-i386/ide.h 1.11 -> 1.12 # drivers/usb/serial/generic.c 1.5 -> 1.6 # arch/i386/boot98/setup.S 1.1 -> 1.2 # drivers/char/drm/drm_proc.h 1.8 -> 1.9 # arch/ppc/platforms/sleep.S 1.8 -> 1.10 arch/ppc/platforms/pmac_sleep.S (moved) # fs/xfs/support/debug.c 1.12 -> 1.13 # arch/i386/kernel/vm86.c 1.21 -> 1.23 # include/asm-i386/ioctls.h 1.3 -> 1.4 # include/asm-m68k/ioctls.h 1.2 -> 1.3 # drivers/pcmcia/i82092aa.h 1.2 -> 1.3 # fs/ChangeLog 1.1 -> (deleted) # drivers/media/video/bttv-if.c 1.10 -> 1.11 # drivers/video/Makefile 1.83 -> 1.84 # drivers/acpi/utilities/utglobal.c 1.25 -> 1.26 # drivers/i2c/i2c-philips-par.c 1.10 -> 1.11 # arch/ppc/platforms/spruce_setup.c 1.9 -> 1.10 # drivers/media/video/bt819.c 1.6 -> 1.7 # include/asm-parisc/ioctls.h 1.3 -> 1.4 # arch/sparc/kernel/sun4d_smp.c 1.11 -> 1.12 # include/asm-sparc64/timer.h 1.2 -> 1.3 # include/acpi/acobject.h 1.17 -> 1.18 # arch/ppc64/kernel/chrp_setup.c 1.20 -> 1.21 # include/asm-arm/system.h 1.15 -> 1.16 # drivers/oprofile/event_buffer.h 1.3 -> 1.4 # drivers/char/ipmi/ipmi_kcs_sm.c 1.1 -> 1.2 # net/irda/irnet/irnet_irda.h 1.5 -> 1.7 # include/asm-um/softirq.h 1.1 -> (deleted) # include/asm-ia64/ioctls.h 1.3 -> 1.4 # mm/vmscan.c 1.149 -> 1.151 # arch/ppc64/Makefile 1.25 -> 1.26 # drivers/s390/char/sclp_tty.c 1.5 -> 1.6 # include/asm-x86_64/kdebug.h 1.2 -> 1.3 # arch/sparc64/kernel/pci_iommu.c 1.7 -> 1.8 # arch/sparc/Makefile 1.21 -> 1.22 # drivers/i2c/i2c-core.c 1.24 -> 1.31 # arch/x86_64/kernel/apic.c 1.14 -> 1.15 # fs/xfs/xfs_dquot_item.c 1.2 -> 1.4 fs/xfs/quota/xfs_dquot_item.c (moved) # include/asm-i386/uaccess.h 1.20 -> 1.22 # drivers/char/drm/r128_cce.c 1.9 -> 1.10 # drivers/media/video/saa7134/saa7134-i2c.c 1.6 -> 1.7 # drivers/base/node.c 1.8 -> 1.9 # drivers/char/drm/r128_state.c 1.10 -> 1.11 # include/asm-i386/page.h 1.23 -> 1.24 # fs/jfs/jfs_imap.c 1.20 -> 1.21 # net/ipv4/udp.c 1.32 -> 1.33 # include/asm-sparc64/pci.h 1.10 -> 1.12 # net/ipx/af_ipx.c 1.25 -> 1.26 # include/asm-m68k/softirq.h 1.3 -> (deleted) # init/main.c 1.95 -> 1.96 # arch/mips/kernel/smp.c 1.10 -> 1.11 # include/linux/i2c.h 1.16 -> 1.21 # drivers/pcmcia/sa1100_badge4.c 1.8 -> 1.9 # fs/xfs/xfs_trans_dquot.c 1.3 -> 1.5 fs/xfs/quota/xfs_trans_dquot.c (moved) # include/asm-s390x/softirq.h 1.6 -> (deleted) # arch/ia64/sn/kernel/sv.c 1.4 -> 1.5 # arch/sparc64/kernel/Makefile 1.23 -> 1.24 # drivers/char/drm/radeon_cp.c 1.15 -> 1.16 # Documentation/filesystems/cifs.txt 1.1 -> 1.2 # fs/xfs/xfs_vfsops.c 1.25 -> 1.27 # drivers/scsi/scsi_sysfs.c 1.8 -> 1.9 # drivers/md/raid5.c 1.63 -> 1.65 # drivers/pcmcia/pci_socket.h 1.4 -> 1.5 # include/net/ah.h 1.1 -> 1.2 # fs/xfs/xfs.h 1.3 -> 1.4 # arch/mips/kernel/mips_ksyms.c 1.7 -> 1.8 # drivers/video/cyber2000fb.c 1.25 -> 1.26 # drivers/i2c/Kconfig 1.6 -> 1.7 # include/linux/xfrm.h 1.4 -> 1.6 # include/asm-ppc/pgtable.h 1.20 -> 1.21 # drivers/char/drm/drm_bufs.h 1.9 -> 1.10 # net/ipv4/netfilter/Makefile 1.17 -> 1.19 # arch/um/kernel/smp.c 1.6 -> 1.7 # fs/jbd/checkpoint.c 1.7 -> 1.8 # drivers/scsi/wd33c93.h 1.4 -> 1.5 # include/asm-i386/floppy.h 1.4 -> 1.5 # drivers/char/drm/drm_ioctl.h 1.8 -> 1.9 # net/ipv4/devinet.c 1.12 -> 1.13 # include/asm-ppc64/compat.h 1.10 -> 1.11 # include/net/compat.h 1.1 -> 1.3 # drivers/usb/core/message.c 1.23 -> 1.24 # net/ipv4/Makefile 1.15 -> 1.16 # drivers/cdrom/optcd.c 1.26 -> 1.27 # kernel/softirq.c 1.34 -> 1.36 # arch/um/drivers/stdio_console.c 1.8 -> 1.9 # net/irda/discovery.c 1.3 -> 1.4 # include/asm-cris/softirq.h 1.4 -> (deleted) # arch/x86_64/kernel/smp.c 1.13 -> 1.14 # net/irda/irlap_frame.c 1.10 -> 1.11 # drivers/scsi/scsi.h 1.68 -> 1.69 # fs/xfs/xfs_bmap.h 1.1 -> 1.2 # include/linux/fs.h 1.222 -> 1.224 # drivers/pcmcia/cs.c 1.16.1.1 -> 1.23 # drivers/usb/storage/usb.c 1.57 -> 1.58 # include/asm-i386/timer.h 1.5 -> 1.6 # arch/sparc64/kernel/devices.c 1.8 -> 1.9 # drivers/pcmcia/cardbus.c 1.24 -> 1.25 # Documentation/networking/bonding.txt 1.8 -> 1.9 # arch/x86_64/kernel/i387.c 1.5 -> 1.6 # drivers/oprofile/buffer_sync.c 1.10 -> 1.11 # fs/xfs/linux/xfs_super.h 1.10 -> 1.14 # arch/mips/mm/fault.c 1.4 -> 1.5 # include/net/sctp/sctp.h 1.25 -> 1.26 # arch/i386/kernel/cpu/intel.c 1.17 -> 1.18 # net/ipv4/tcp.c 1.36 -> 1.37 # include/linux/crypto.h 1.27 -> 1.28 # drivers/net/pcnet32.c 1.31 -> 1.32 # crypto/proc.c 1.1 -> 1.2 # drivers/pcmcia/sa1111_generic.c 1.11 -> 1.13 # fs/xfs/linux/xfs_stats.h 1.2 -> 1.3 # drivers/net/mace.c 1.12 -> 1.13 # arch/sparc/kernel/smp.c 1.7 -> 1.8 # arch/x86_64/ia32/ptrace32.c 1.5 -> 1.6 # arch/x86_64/kernel/setup64.c 1.11 -> 1.12 # arch/alpha/kernel/smp.c 1.32 -> 1.34 # drivers/acpi/events/evxfevnt.c 1.15 -> 1.17 # arch/ppc/platforms/pmac_time.c 1.11 -> 1.12 # drivers/ide/ide.c 1.56 -> 1.57 # drivers/md/md.c 1.158 -> 1.160 # include/asm-alpha/pgtable.h 1.17 -> 1.18 # Documentation/driver-model/overview.txt 1.7 -> 1.8 # fs/xfs/xfs_qm.h 1.1 -> 1.4 fs/xfs/quota/xfs_qm.h (moved) # drivers/i2c/busses/i2c-piix4.c 1.7 -> 1.8 # net/sunrpc/rpc_pipe.c 1.6 -> 1.7 # drivers/char/drm/i830.h 1.5 -> 1.6 # arch/x86_64/kernel/ptrace.c 1.11 -> 1.12 # drivers/pcmcia/cistpl.c 1.8.1.1 -> 1.12 # arch/arm/kernel/entry-armv.S 1.27 -> 1.28 # drivers/isdn/hisax/sedlbauer_cs.c 1.6 -> 1.7 # drivers/char/pty.c 1.9 -> 1.10 # net/irda/af_irda.c 1.37 -> 1.38 # drivers/base/cpu.c 1.7 -> 1.9 # drivers/usb/media/ov511.c 1.40 -> 1.41 # fs/xfs/xfs_macros.c 1.3 -> 1.4 # include/asm-ppc64/machdep.h 1.13 -> 1.14 # drivers/usb/misc/emi26.c 1.6 -> 1.7 # include/asm-i386/nmi.h 1.1 -> 1.2 # include/asm-alpha/softirq.h 1.5 -> (deleted) # drivers/media/video/tvaudio.c 1.15 -> 1.16 # kernel/extable.c 1.4 -> 1.6 # include/asm-s390x/ioctls.h 1.1 -> 1.2 # fs/char_dev.c 1.10 -> 1.13 # drivers/char/drm/i810.h 1.5 -> 1.6 # net/core/filter.c 1.3 -> 1.4 # arch/sparc64/defconfig 1.77 -> 1.78 # fs/xfs/linux/xfs_vnode.c 1.11 -> 1.13 # drivers/char/drm/i810_dma.c 1.20 -> 1.21 # arch/sparc64/kernel/setup.c 1.36 -> 1.37 # drivers/acpi/acpi_ksyms.c 1.22 -> 1.23 # drivers/ide/ide-iops.c 1.14 -> 1.15 # fs/xfs/xfs_mount.c 1.20 -> 1.23 # drivers/char/pcmcia/synclink_cs.c 1.9 -> 1.10 # arch/arm/kernel/armksyms.c 1.20 -> 1.21 # net/socket.c 1.45 -> 1.48 # arch/x86_64/kernel/entry.S 1.10 -> 1.11 # drivers/ieee1394/pcilynx.c 1.25 -> 1.26 # drivers/pcmcia/ti113x.h 1.4 -> 1.5 # arch/ppc/platforms/chrp_smp.c 1.8 -> 1.9 # net/ipv4/xfrm_algo.c 1.6 -> 1.8 net/xfrm/xfrm_algo.c (moved) # drivers/char/hw_random.c 1.7 -> 1.8 # drivers/s390/net/ctcmain.c 1.17 -> 1.18 # drivers/base/base.h 1.22 -> 1.23 # drivers/pcmcia/sa1100_pfs168.c 1.7 -> 1.8 # drivers/ide/ide-timing.h 1.2 -> 1.3 # include/asm-v850/ioctls.h 1.1 -> 1.2 # include/asm-arm/softirq.h 1.7 -> (deleted) # fs/exec.c 1.73 -> 1.74 # fs/xfs/linux/xfs_globals.h 1.2 -> 1.4 # include/asm-ppc64/pci.h 1.4 -> 1.5 # net/sunrpc/clnt.c 1.33 -> 1.34 # drivers/usb/storage/transport.c 1.64 -> 1.66 # arch/alpha/kernel/sys_nautilus.c 1.11 -> 1.12 # drivers/char/drm/i830_drm.h 1.5 -> 1.6 # drivers/pcmcia/sa1100_xp860.c 1.7 -> 1.8 # drivers/char/drm/mga_state.c 1.12 -> 1.13 # arch/mips64/kernel/mips64_ksyms.c 1.7 -> 1.8 # net/ipv6/raw.c 1.19 -> 1.20 # arch/x86_64/kernel/head64.c 1.6 -> 1.7 # lib/idr.c 1.2 -> 1.3 # net/netsyms.c 1.56 -> 1.59 # include/linux/pci_ids.h 1.87 -> 1.88 # drivers/ide/ide-disk.c 1.35 -> 1.36 # drivers/media/video/saa7111.c 1.7 -> 1.9 # drivers/char/drm/gamma_drv.h 1.5 -> 1.6 # include/net/protocol.h 1.7 -> 1.8 # drivers/md/linear.c 1.26 -> 1.29 # include/asm-x86_64/pci.h 1.5 -> 1.6 # arch/x86_64/boot/compressed/misc.c 1.5 -> 1.6 # mm/shmem.c 1.107 -> 1.109 # net/Makefile 1.21 -> 1.22 # drivers/media/video/tuner-3036.c 1.6 -> 1.7 # drivers/pcmcia/sa1100_jornada720.c 1.8 -> 1.9 # arch/x86_64/ia32/sys_ia32.c 1.25 -> 1.27 # fs/befs/linuxvfs.c 1.7 -> 1.8 # arch/x86_64/kernel/pci-gart.c 1.7 -> 1.8 # drivers/media/video/tda9875.c 1.10 -> 1.11 # arch/ppc64/kernel/irq.c 1.22 -> 1.23 # drivers/net/hamradio/dmascc.c 1.8 -> 1.9 # Documentation/filesystems/befs.txt 1.1 -> 1.2 # mm/swap_state.c 1.57 -> 1.58 # drivers/media/radio/radio-cadet.c 1.11 -> 1.12 # arch/x86_64/ia32/ipc32.c 1.6 -> 1.7 # crypto/crypto_null.c 1.1 -> 1.2 # drivers/md/multipath.c 1.45 -> 1.47 # fs/xfs/xfs_dquot.c 1.5 -> 1.7 fs/xfs/quota/xfs_dquot.c (moved) # include/asm-sparc/ioctls.h 1.3 -> 1.4 # include/asm-arm/div64.h 1.1 -> 1.2 # fs/aio.c 1.29 -> 1.30 # arch/x86_64/kernel/nmi.c 1.9 -> 1.10 # fs/xfs/xfs_trans.c 1.5 -> 1.6 # include/asm-arm/ioctls.h 1.2 -> 1.3 # drivers/usb/usb-skeleton.c 1.29 -> 1.31 # net/sunrpc/auth_gss/auth_gss.c 1.4 -> 1.5 # drivers/pcmcia/ricoh.h 1.4 -> 1.5 # include/asm-m68knommu/softirq.h 1.1 -> (deleted) # drivers/usb/core/hub.c 1.59 -> 1.61 # drivers/video/matrox/i2c-matroxfb.c 1.6 -> 1.7 # arch/sparc64/kernel/rtrap.S 1.13 -> 1.14 # scripts/file2alias.c 1.3 -> 1.4 # Documentation/pci.txt 1.7 -> 1.8 # arch/arm/tools/mach-types 1.25 -> 1.26 # drivers/isdn/hisax/elsa_cs.c 1.3 -> 1.4 # arch/i386/kernel/smpboot.c 1.54 -> 1.55 # drivers/acpi/utilities/utdelete.c 1.17 -> 1.18 # drivers/i2c/scx200_acb.c 1.3 -> 1.6 # arch/x86_64/kernel/suspend.c 1.2 -> 1.3 # drivers/serial/Makefile 1.13 -> 1.14 # fs/jfs/jfs_xtree.c 1.8 -> 1.9 # fs/xfs/xfs_rename.c 1.7 -> 1.8 # drivers/pcmcia/sa1100_flexanet.c 1.9 -> 1.10 # include/asm-s390x/compat.h 1.9 -> 1.10 # drivers/i2c/busses/i2c-i801.c 1.7 -> 1.8 # drivers/usb/storage/isd200.c 1.28 -> 1.29 # drivers/serial/8250_cs.c 1.9 -> 1.10 # arch/sparc64/kernel/time.c 1.35 -> 1.36 # drivers/scsi/scsi_lib.c 1.75 -> 1.77 # fs/sysfs/bin.c 1.3 -> 1.4 # drivers/usb/storage/scsiglue.c 1.37 -> 1.40 # drivers/pnp/Kconfig 1.4 -> 1.5 # include/asm-i386/dma.h 1.1 -> 1.2 # fs/ncpfs/inode.c 1.39 -> 1.40 # net/ipv4/xfrm_policy.c 1.21 -> 1.22 net/xfrm/xfrm_policy.c (moved) # drivers/net/irda/irda-usb.c 1.35 -> 1.36 # include/asm-x86_64/i387.h 1.7 -> 1.8 # arch/ppc/platforms/pmac_smp.c 1.9 -> 1.11 # drivers/i2c/busses/i2c-ali15x3.c 1.6 -> 1.7 # drivers/usb/core/usb.c 1.116 -> 1.117 # drivers/char/drm/radeon_drv.h 1.17 -> 1.18 # include/asm-mips64/softirq.h 1.2 -> (deleted) # kernel/posix-timers.c 1.9 -> 1.10 # drivers/net/r8169.c 1.7 -> 1.8 # drivers/i2c/i2c-proc.c 1.18 -> 1.23 drivers/i2c/i2c-sensor.c (moved) # drivers/pcmcia/sa1100_stork.c 1.10 -> 1.11 # fs/xfs/linux/xfs_iomap.c 1.6 -> 1.7 # drivers/s390/char/tubio.h 1.8 -> 1.9 # include/asm-sparc64/ioctls.h 1.3 -> 1.4 # drivers/i2c/i2c-algo-bit.c 1.13 -> 1.14 # arch/x86_64/ia32/ia32_ioctl.c 1.16 -> 1.17 # fs/xfs/linux/xfs_file.c 1.10 -> 1.11 # drivers/scsi/pcmcia/qlogic_stub.c 1.12 -> 1.13 # drivers/acpi/events/evgpeblk.c 1.1 -> 1.4 # arch/i386/kernel/timers/timer_none.c 1.2 -> 1.3 # crypto/compress.c 1.6 -> 1.7 # include/asm-x86_64/suspend.h 1.3 -> 1.4 # include/linux/interrupt.h 1.18 -> 1.20 # arch/i386/mm/highmem.c 1.2 -> 1.3 # fs/xfs/xfs_bmap_btree.c 1.7 -> 1.8 # fs/jfs/jfs_extent.c 1.7 -> 1.8 # drivers/md/raid1.c 1.57 -> 1.59 # fs/xfs/xfs_log_recover.c 1.14 -> 1.15 # drivers/usb/image/mdc800.c 1.27 -> 1.28 # net/sunrpc/sched.c 1.23 -> 1.24 # arch/i386/kernel/nmi.c 1.16 -> 1.17 # net/irda/irlan/irlan_client.c 1.5 -> 1.6 # net/irda/timer.c 1.3 -> 1.4 # drivers/md/raid0.c 1.23 -> 1.25 # drivers/acpi/ec.c 1.21 -> 1.23 # include/asm-mips/softirq.h 1.2 -> (deleted) # drivers/char/drm/drm_fops.h 1.8 -> 1.9 # arch/ppc/kernel/head.S 1.29 -> 1.30 # drivers/i2c/chips/Kconfig 1.4 -> 1.8 # include/pcmcia/driver_ops.h 1.2 -> 1.3 # include/asm-s390/ioctls.h 1.2 -> 1.3 # drivers/i2c/busses/i2c-isa.c 1.1 -> 1.2 # arch/x86_64/kernel/process.c 1.15 -> 1.16 # scripts/Makefile.modpost 1.3 -> 1.4 # arch/i386/boot/setup.S 1.19 -> 1.20 # net/ipv6/af_inet6.c 1.23 -> 1.24 # net/ipv6/tcp_ipv6.c 1.43 -> 1.44 # drivers/pcmcia/tcic.c 1.16.1.1 -> 1.19 # drivers/s390/net/netiucv.c 1.17 -> 1.18 # net/ipv4/xfrm_user.c 1.15 -> 1.17 net/xfrm/xfrm_user.c (moved) # drivers/pcmcia/hd64465_ss.c 1.11 -> 1.13 # arch/v850/kernel/v850_ksyms.c 1.2 -> 1.3 # net/sched/sch_csz.c 1.5 -> 1.6 # arch/mips64/mm/fault.c 1.7 -> 1.8 # fs/buffer.c 1.191 -> 1.192 # fs/xfs/linux/xfs_behavior.h 1.2 -> 1.3 # drivers/pcmcia/sa1100.h 1.9 -> 1.10 # net/ipv4/esp.c 1.19 -> 1.20 # fs/nfsd/export.c 1.74 -> 1.76 # drivers/pcmcia/sa1100_trizeps.c 1.9 -> 1.10 # drivers/acpi/events/evxface.c 1.19 -> 1.20 # include/linux/i2c-proc.h 1.5 -> 1.9 include/linux/i2c-sensor.h (moved) # drivers/acpi/utilities/utinit.c 1.15 -> 1.16 # drivers/usb/core/hcd.c 1.54 -> 1.55 # include/pcmcia/bus_ops.h 1.2 -> 1.3 # include/acpi/acevents.h 1.15 -> 1.17 # drivers/acpi/events/evmisc.c 1.20 -> 1.22 # include/acpi/actypes.h 1.22 -> 1.24 # lib/Kconfig 1.2 -> 1.3 # Documentation/ia64/efirtc.txt 1.2 -> 1.3 # include/linux/skbuff.h 1.21 -> 1.22 # fs/xfs/pagebuf/page_buf.h 1.25 -> 1.26 # fs/xfs/xfs_attr.c 1.4 -> 1.5 # drivers/acpi/events/evgpe.c 1.9 -> 1.11 # drivers/char/tty_io.c 1.67 -> 1.71 # arch/x86_64/pci/irq.c 1.6 -> 1.7 # drivers/scsi/pcmcia/fdomain_stub.c 1.13 -> 1.14 # include/asm-ppc/keylargo.h 1.7 -> 1.8 # fs/jfs/jfs_txnmgr.c 1.40 -> 1.42 # drivers/pcmcia/sa1100_generic.h 1.8 -> 1.9 # include/acpi/achware.h 1.13 -> 1.14 # arch/ppc64/kernel/process.c 1.29 -> 1.30 # include/asm-arm/hardirq.h 1.7 -> 1.8 # drivers/s390/char/tubfs.c 1.14 -> 1.15 # net/sctp/ipv6.c 1.26 -> 1.27 # MAINTAINERS 1.131 -> 1.132 # net/sctp/protocol.c 1.37 -> 1.38 # drivers/pcmcia/rsrc_mgr.c 1.9.1.1 -> 1.13 # drivers/s390/cio/qdio.c 1.3 -> 1.4 # drivers/pcmcia/yenta.c 1.19 -> 1.21 # include/asm-alpha/fcntl.h 1.2 -> 1.3 # net/compat.c 1.5 -> 1.7 # drivers/scsi/scsi_debug.c 1.30 -> 1.31 # drivers/char/rio/rio_linux.c 1.15 -> 1.16 # drivers/pcmcia/sa1100_generic.c 1.26 -> 1.30 # net/irda/irlap_event.c 1.16 -> 1.18 # drivers/media/video/msp3400.c 1.15 -> 1.16 # include/acpi/aclocal.h 1.26 -> 1.28 # mm/mmap.c 1.75 -> 1.77 # fs/proc/base.c 1.39 -> 1.40 # arch/s390/kernel/s390_ksyms.c 1.9 -> 1.10 # include/asm-sparc64/compat.h 1.11 -> 1.12 # mm/highmem.c 1.42 -> 1.43 # fs/xfs/linux/xfs_globals.c 1.8 -> 1.10 # drivers/net/irda/sir_dev.c 1.4 -> 1.5 # include/asm-cris/ioctls.h 1.2 -> 1.3 # net/ipv6/esp6.c 1.5 -> 1.8 # drivers/char/drm/drm_dma.h 1.10 -> 1.11 # fs/xfs/support/mrlock.h 1.1 -> 1.2 # drivers/usb/class/cdc-acm.c 1.35 -> 1.36 # drivers/scsi/aha152x.h 1.9 -> 1.11 # include/asm-sh/ioctls.h 1.2 -> 1.3 # fs/xfs/xfs_qm_syscalls.c 1.4 -> 1.7 fs/xfs/quota/xfs_qm_syscalls.c (moved) # drivers/char/drm/radeon_drm.h 1.11 -> 1.12 # drivers/char/drm/drm_lock.h 1.6 -> 1.7 # fs/xfs/xfs_dquot_item.h 1.1 -> 1.3 fs/xfs/quota/xfs_dquot_item.h (moved) # arch/ppc/platforms/pmac_setup.c 1.25 -> 1.26 # arch/x86_64/kernel/head.S 1.9 -> 1.10 # arch/arm/lib/Makefile 1.14 -> 1.15 # drivers/acpi/events/evsci.c 1.13 -> 1.15 # fs/xfs/xfs_clnt.h 1.3 -> 1.4 # include/net/irda/discovery.h 1.4 -> 1.5 # drivers/char/drm/sis_mm.c 1.4 -> 1.5 # drivers/scsi/sym53c8xx.c 1.30 -> 1.31 # include/net/esp.h 1.1 -> 1.2 # net/packet/af_packet.c 1.20 -> 1.21 # drivers/char/drm/i830_drv.h 1.6 -> 1.7 # arch/i386/kernel/timers/timer_tsc.c 1.14 -> 1.15 # drivers/usb/media/stv680.c 1.23 -> 1.24 # include/linux/ftape.h 1.2 -> 1.3 # drivers/scsi/wd33c93.c 1.12 -> 1.13 # include/asm-x86_64/unistd.h 1.13 -> 1.14 # net/sunrpc/xprt.c 1.51 -> 1.52 # net/ipv6/ah6.c 1.5 -> 1.8 # drivers/acpi/processor.c 1.35.1.1 -> 1.37 # arch/i386/kernel/timers/timer_cyclone.c 1.4 -> 1.5 # net/irda/irnet/irnet.h 1.15 -> 1.16 # include/asm-x86_64/debugreg.h 1.1 -> 1.2 # drivers/s390/char/con3215.c 1.13 -> 1.14 # drivers/acpi/resources/rsxface.c 1.13 -> 1.14 # arch/x86_64/kernel/signal.c 1.15 -> 1.16 # include/asm-sparc64/rwsem.h 1.9 -> 1.10 # include/asm-x86_64/thread_info.h 1.8 -> 1.9 # fs/xfs/xfs_rtalloc.h 1.1 -> 1.2 # fs/xfs/Makefile 1.9 -> 1.11 # include/asm-sh/softirq.h 1.4 -> (deleted) # CREDITS 1.79 -> 1.80 # fs/jfs/jfs_dtree.c 1.20 -> 1.21 # drivers/media/video/tda7432.c 1.8 -> 1.9 # drivers/pcmcia/sa1100_h3600.c 1.9 -> 1.10 # drivers/char/ipmi/Kconfig 1.1 -> 1.2 # include/asm-ppc/softirq.h 1.11 -> (deleted) # include/asm-x86_64/compat.h 1.9 -> 1.10 # arch/mips64/kernel/smp.c 1.7 -> 1.8 # drivers/pcmcia/sa1100_graphicsmaster.c 1.5 -> 1.6 # drivers/char/sonypi.c 1.14 -> 1.15 # net/ipv6/ipv6_syms.c 1.10 -> 1.11 # arch/ppc64/kernel/prom.c 1.21 -> 1.22 # drivers/usb/host/ohci-pci.c 1.10 -> 1.11 # net/ipv4/xfrm_state.c 1.15 -> 1.17 net/xfrm/xfrm_state.c (moved) # include/asm-x86_64/pgtable.h 1.16 -> 1.17 # net/core/skbuff.c 1.21 -> 1.23 # kernel/module.c 1.68 -> 1.74 # drivers/scsi/qlogicfc.c 1.29 -> 1.30 # include/net/sock.h 1.33 -> 1.34 # fs/xfs/xfs_inode.h 1.11 -> 1.12 # net/irda/irnet/irnet_ppp.h 1.4 -> 1.5 # arch/ppc64/kernel/iSeries_setup.c 1.9 -> 1.10 # include/asm-alpha/ioctls.h 1.3 -> 1.4 # net/core/sock.c 1.19 -> 1.21 # fs/quota_v1.c 1.7 -> 1.8 # drivers/video/logo/Makefile 1.1 -> 1.2 # net/ipv4/sysctl_net_ipv4.c 1.8 -> 1.9 # include/asm-i386/hardirq.h 1.17 -> 1.18 # arch/ppc64/kernel/smp.c 1.31 -> 1.32 # drivers/char/drm/drmP.h 1.17 -> 1.18 # net/irda/irnet/irnet_ppp.c 1.10 -> 1.11 # net/ipv6/ip6_input.c 1.8 -> 1.9 # arch/x86_64/kernel/Makefile 1.18 -> 1.19 # fs/xfs/xfs_trans.h 1.4 -> 1.5 # arch/x86_64/kernel/aperture.c 1.2 -> 1.3 # drivers/serial/21285.c 1.15 -> 1.16 # net/ipv4/tcp_input.c 1.34 -> 1.35 # include/acpi/acconfig.h 1.33 -> 1.35 # drivers/acpi/tables/tbgetall.c 1.9 -> 1.10 # drivers/media/video/saa5249.c 1.12 -> 1.13 # drivers/pcmcia/Kconfig 1.2 -> 1.4 # fs/nfs/nfs4proc.c 1.12 -> 1.13 # include/asm-s390/softirq.h 1.7 -> (deleted) # drivers/mtd/maps/epxa10db-flash.c 1.2 -> 1.3 # include/linux/highmem.h 1.23 -> 1.24 # include/asm-mips64/ioctls.h 1.4 -> 1.5 # net/ipv4/tcp_minisocks.c 1.24 -> 1.25 # arch/i386/mm/init.c 1.45 -> 1.46 # drivers/acpi/battery.c 1.15 -> 1.16 # Documentation/i2c/proc-interface 1.1 -> (deleted) # drivers/pcmcia/ds.c 1.19 -> 1.25 # drivers/pcmcia/sa1100_yopy.c 1.9 -> 1.10 # fs/xfs/xfs_iocore.c 1.2 -> 1.4 # include/asm-x86_64/softirq.h 1.4 -> (deleted) # fs/xfs/linux/xfs_ioctl.c 1.11 -> 1.12 # drivers/net/gt96100eth.c 1.7 -> 1.8 # net/ipv4/Kconfig 1.4 -> 1.5 # arch/ppc64/kernel/stab.c 1.8 -> 1.10 # drivers/i2c/i2c-dev.c 1.23.1.1 -> 1.26 # drivers/i2c/i2c-algo-pcf.c 1.10 -> 1.11 # include/linux/module.h 1.53 -> 1.59 # mm/slab.c 1.71 -> 1.73 # fs/xfs/xfsidbg.c 1.20 -> 1.22 # net/ipv4/netfilter/ip_nat_standalone.c 1.18 -> 1.19 # drivers/pcmcia/Makefile 1.21 -> 1.23 # drivers/scsi/scsi_scan.c 1.66 -> 1.67 # arch/x86_64/Kconfig 1.16 -> 1.17 # include/net/irda/irlan_client.h 1.2 -> 1.3 # kernel/sched.c 1.174 -> 1.175 # drivers/pcmcia/sa1100_assabet.c 1.12 -> 1.13 # crypto/tcrypt.c 1.21 -> 1.22 # include/asm-ia64/softirq.h 1.8 -> (deleted) # fs/quota_v2.c 1.11 -> 1.12 # drivers/scsi/Makefile 1.39 -> 1.40 # include/asm-ppc/ioctls.h 1.4 -> 1.5 # drivers/acpi/osl.c 1.28 -> 1.30 # drivers/i2c/i2c-elv.c 1.10 -> 1.12 # drivers/s390/char/tubtty.c 1.8 -> 1.9 # include/linux/if_bonding.h 1.6 -> 1.7 # drivers/s390/char/tuball.c 1.9 -> 1.10 # drivers/i2c/i2c-velleman.c 1.8 -> 1.9 # Documentation/power/pci.txt 1.2 -> 1.3 # drivers/char/drm/drm_drv.h 1.13 -> 1.15 # net/ipv6/udp.c 1.20 -> 1.23 # drivers/i2c/busses/i2c-amd8111.c 1.6 -> 1.7 # arch/x86_64/mm/numa.c 1.1 -> 1.2 # net/ipv4/netfilter/Kconfig 1.2 -> 1.4 # arch/s390x/kernel/s390_ksyms.c 1.8 -> 1.9 # arch/sparc64/kernel/sparc64_ksyms.c 1.42 -> 1.44 # drivers/char/drm/drm_lists.h 1.6 -> 1.7 # net/ipv4/netfilter/ipt_REJECT.c 1.12 -> 1.13 # include/asm-x86_64/system.h 1.12 -> 1.13 # include/linux/kdev_t.h 1.7 -> 1.8 # include/net/xfrm.h 1.22 -> 1.24 # fs/nfsd/nfs4xdr.c 1.10 -> 1.13 # arch/x86_64/kernel/reboot.c 1.2 -> 1.3 # fs/xfs/xfs_dqblk.h 1.1 -> (deleted) # drivers/media/video/tuner.c 1.15 -> 1.16 # fs/sysfs/inode.c 1.84 -> 1.85 # drivers/acpi/events/evevent.c 1.24 -> 1.25 # drivers/char/drm/radeon_state.c 1.18 -> 1.19 # drivers/char/ipmi/ipmi_devintf.c 1.4 -> 1.5 # drivers/acpi/hardware/hwregs.c 1.20 -> 1.21 # arch/i386/kernel/timers/timer_pit.c 1.8 -> 1.9 # include/linux/mtd/compatmac.h 1.3 -> 1.4 # arch/m68k/kernel/m68k_ksyms.c 1.10 -> 1.11 # drivers/i2c/busses/i2c-amd756.c 1.5 -> 1.6 # drivers/char/vt.c 1.37 -> 1.38 # include/asm-ppc/uninorth.h 1.7 -> 1.8 # drivers/parisc/eisa_eeprom.c 1.3 -> 1.4 # drivers/net/Kconfig 1.21 -> 1.22 # drivers/i2c/busses/Kconfig 1.8 -> 1.9 # arch/ppc64/kernel/pci.c 1.27 -> 1.29 # arch/ppc64/boot/Makefile 1.12 -> 1.13 # arch/sparc64/kernel/binfmt_elf32.c 1.8 -> 1.9 # arch/sparc/kernel/sun4m_smp.c 1.10 -> 1.11 # drivers/char/drm/Kconfig 1.2 -> 1.3 # drivers/char/drm/radeon_mem.c 1.5 -> 1.6 # drivers/usb/serial/kobil_sct.c 1.5 -> 1.6 # arch/i386/kernel/acpi/boot.c 1.23 -> 1.24 # drivers/base/driver.c 1.19 -> 1.20 # include/asm-mips/ioctls.h 1.3 -> 1.4 # net/ipv4/netfilter/iptable_mangle.c 1.10 -> 1.11 # arch/sparc64/Kconfig 1.16 -> 1.17 # drivers/acpi/thermal.c 1.22 -> 1.23 # drivers/char/drm/mga_dma.c 1.10 -> 1.11 # net/ipv4/ah.c 1.16 -> 1.17 # include/asm-x86_64/proto.h 1.8 -> 1.9 # arch/x86_64/Makefile 1.24 -> 1.25 # include/asm-x86_64/apic.h 1.4 -> 1.5 # include/net/irda/af_irda.h 1.2 -> 1.3 # arch/i386/kernel/cpu/proc.c 1.9 -> 1.10 # drivers/pcmcia/i82365.c 1.24.1.1 -> 1.27 # arch/x86_64/kernel/bluesmoke.c 1.8 -> 1.9 # drivers/net/tulip/dmfe.c 1.26 -> 1.28 # arch/m68knommu/kernel/m68k_ksyms.c 1.2 -> 1.3 # drivers/char/drm/mga_drv.h 1.11 -> 1.12 # arch/ppc/kernel/Makefile 1.35 -> 1.36 # drivers/media/video/tvmixer.c 1.12 -> 1.13 # drivers/scsi/pcmcia/aha152x_stub.c 1.12 -> 1.13 # drivers/char/drm/radeon.h 1.9 -> 1.10 # fs/ext3/super.c 1.56 -> 1.57 # fs/xfs/linux/xfs_aops.c 1.27 -> 1.28 # drivers/scsi/Kconfig 1.17 -> 1.18 # include/linux/device.h 1.85 -> 1.86 # net/irda/ircomm/ircomm_tty_attach.c 1.8 -> 1.9 # drivers/pci/Makefile 1.24 -> 1.25 # net/irda/irlmp.c 1.21 -> 1.22 # drivers/char/drm/drm_os_linux.h 1.7 -> 1.8 # arch/ppc/platforms/pmac_feature.c 1.15 -> 1.16 # arch/ppc/kernel/misc.S 1.41 -> 1.42 # arch/alpha/kernel/err_titan.c 1.2 -> 1.3 # crypto/tcrypt.h 1.12 -> 1.13 # drivers/media/video/adv7175.c 1.8 -> 1.10 # fs/xfs/linux/xfs_super.c 1.30 -> 1.33 # drivers/serial/Kconfig 1.6 -> 1.7 # arch/sparc/boot/Makefile 1.13 -> 1.14 # drivers/pcmcia/sa1100_shannon.c 1.8 -> 1.9 # drivers/char/drm/gamma_dma.c 1.8 -> 1.9 # drivers/pcmcia/sa1100_cerf.c 1.10 -> 1.11 # drivers/pcmcia/sa1100_neponset.c 1.9 -> 1.10 # fs/xfs/linux/xfs_stats.c 1.2 -> 1.3 # mm/rmap.c 1.22 -> 1.23 # include/net/dst.h 1.12 -> 1.13 # fs/xfs/xfs_bmap.c 1.8 -> 1.9 # arch/sparc64/kernel/irq.c 1.26 -> 1.28 # drivers/net/bonding.c 1.18 -> 1.19 # include/linux/netfilter_ipv4/ip_conntrack.h 1.10 -> 1.11 # include/linux/irq_cpustat.h 1.6 -> 1.7 # net/ipv6/addrconf.c 1.33 -> 1.34 # drivers/scsi/3w-xxxx.c 1.27 -> 1.28 # crypto/Kconfig 1.11 -> 1.12 # drivers/char/drm/radeon_irq.c 1.7 -> 1.8 # drivers/char/watchdog/indydog.c 1.5 -> 1.6 # arch/i386/oprofile/nmi_int.c 1.9 -> 1.10 # net/core/Makefile 1.12 -> 1.13 # arch/x86_64/mm/ioremap.c 1.8 -> 1.9 # drivers/char/drm/i810_drv.h 1.7 -> 1.8 # include/linux/netdevice.h 1.31 -> 1.32 # arch/ppc/kernel/smp.c 1.29 -> 1.31 # drivers/macintosh/apm_emu.c 1.4 -> 1.5 # drivers/usb/Makefile 1.39 -> 1.40 # include/asm-ppc64/pgtable.h 1.17.1.1 -> 1.21 # arch/arm/kernel/apm.c 1.1 -> 1.2 # drivers/pcmcia/sa1111_generic.h 1.5 -> 1.6 # include/pcmcia/ss.h 1.7 -> 1.10 # crypto/api.c 1.29 -> 1.30 # drivers/atm/iphase.c 1.14 -> 1.16 # drivers/usb/misc/usbtest.c 1.12 -> 1.14 # fs/xfs/xfs_dmapi.h 1.3 -> 1.7 # drivers/char/drm/Makefile 1.15 -> 1.16 # arch/i386/kernel/timers/timer.c 1.5 -> 1.6 # fs/xfs/linux/xfs_behavior.c 1.2 -> 1.3 # drivers/acpi/namespace/nsaccess.c 1.19 -> 1.20 # drivers/scsi/scsi_ioctl.c 1.15 -> 1.16 # crypto/Makefile 1.16 -> 1.17 # include/linux/bitops.h 1.2 -> 1.3 # fs/xfs/xfs_buf.h 1.10 -> 1.11 # fs/quota.c 1.12 -> 1.13 # fs/xfs/xfs_inode.c 1.15 -> 1.17 # fs/xfs/xfs_iget.c 1.9 -> 1.11 # arch/x86_64/boot/setup.S 1.4 -> 1.5 # drivers/usb/core/usb-debug.c 1.8 -> 1.9 # drivers/usb/core/buffer.c 1.4 -> 1.5 # include/asm-i386/softirq.h 1.13 -> (deleted) # arch/x86_64/ia32/ia32_signal.c 1.11 -> 1.12 # drivers/char/drm/sis.h 1.4 -> 1.5 # include/asm-x86_64/processor.h 1.13 -> 1.14 # drivers/pcmcia/sa1100_simpad.c 1.10 -> 1.11 # drivers/usb/class/audio.c 1.32 -> 1.33 # fs/ext3/fsync.c 1.5 -> 1.6 # arch/x86_64/mm/k8topology.c 1.1 -> 1.2 # fs/xfs/xfs_quota.h 1.1 -> 1.3 # drivers/scsi/pcmcia/nsp_cs.c 1.17.1.1 -> 1.19 # arch/sparc64/kernel/traps.c 1.24 -> 1.25 # arch/ppc/Kconfig 1.18 -> 1.19 # arch/ppc/syslib/prom_init.c 1.6 -> 1.7 # include/asm-x86_64/ioctls.h 1.2 -> 1.3 # arch/sparc64/Makefile 1.25 -> 1.26 # arch/ppc64/kernel/iSeries_pci.c 1.9 -> 1.10 # fs/inode.c 1.89 -> 1.90 # drivers/pcmcia/pci_socket.c 1.13 -> 1.15 # include/asm-i386/apic.h 1.10 -> 1.11 # fs/xfs/xfs_dquot.h 1.1 -> 1.3 fs/xfs/quota/xfs_dquot.h (moved) # include/asm-parisc/softirq.h 1.2 -> (deleted) # arch/i386/kernel/i386_ksyms.c 1.49 -> 1.50 # drivers/pcmcia/sa1100_system3.c 1.7 -> 1.8 # drivers/macintosh/macio-adb.c 1.2 -> 1.3 # fs/xfs/xfs_quota_priv.h 1.2 -> 1.4 fs/xfs/quota/xfs_quota_priv.h (moved) # fs/xfs/support/time.h 1.6 -> 1.7 # drivers/block/scsi_ioctl.c 1.21 -> 1.22 # drivers/base/memblk.c 1.4 -> 1.5 # fs/xfs/xfs_utils.c 1.7 -> 1.8 # drivers/acpi/Kconfig 1.7 -> 1.9 # include/asm-i386/string.h 1.7 -> 1.8 # include/asm-sparc64/softirq.h 1.10 -> (deleted) # arch/ppc64/kernel/pSeries_lpar.c 1.19 -> 1.20 # drivers/acpi/namespace/nswalk.c 1.12 -> 1.13 # include/asm-ppc/termios.h 1.7 -> 1.8 # drivers/usb/misc/speedtch.c 1.70 -> 1.74 # fs/xfs/linux/xfs_vnode.h 1.14 -> 1.15 # arch/i386/kernel/apic.c 1.34 -> 1.35 # net/ipv6/xfrm6_input.c 1.2 -> 1.3 # arch/ppc/platforms/Makefile 1.15 -> 1.17 # drivers/macintosh/adb.c 1.17 -> 1.18 # drivers/acorn/char/i2c.c 1.6 -> 1.7 # drivers/pcmcia/sa1100_adsbitsy.c 1.7 -> 1.8 # arch/x86_64/kernel/smpboot.c 1.15 -> 1.16 # drivers/pcmcia/i82092.c 1.13 -> 1.15 # drivers/char/drm/r128_drv.h 1.12 -> 1.13 # arch/arm/mach-footbridge/dc21285.c 1.6 -> 1.7 # fs/xfs/xfs_vnodeops.c 1.22 -> 1.23 # fs/block_dev.c 1.125 -> 1.126 # Documentation/kernel-parameters.txt 1.17 -> 1.19 # include/asm-x86_64/desc.h 1.8 -> 1.9 # arch/ppc64/kernel/pSeries_pci.c 1.22 -> 1.23 # arch/i386/mm/boot_ioremap.c 1.1 -> 1.2 # include/asm-parisc/compat.h 1.7 -> 1.8 # (new) -> 1.2 drivers/i2c/chips/w83781d.c # (new) -> 1.1 arch/sparc64/lib/rwsem.c # (new) -> 1.3 fs/xfs/linux/xfs_vfs.c # (new) -> 1.1 fs/xfs/quota/xfs_qm_bhv.c # (new) -> 1.2 include/linux/i2c-vid.h # (new) -> 1.1 drivers/scsi/pc980155.c # (new) -> 1.1 fs/xfs/quota/xfs_qm_stats.c # (new) -> 1.1 include/linux/netfilter_ipv4/ip_conntrack_amanda.h # (new) -> 1.3 drivers/i2c/chips/via686a.c # (new) -> 1.1 drivers/scsi/pc980155.h # (new) -> 1.1 Documentation/i2c/sysfs-interface # (new) -> 1.1 include/asm-ppc/macio_asic.h # (new) -> 1.1 drivers/pcmcia/sa11xx_core.c # (new) -> 1.1 arch/ppc/kernel/cpu_setup_6xx.S # (new) -> 1.1 net/ipv4/netfilter/ip_nat_amanda.c # (new) -> 1.1 include/linux/netfilter_ipv4/ip_conntrack_tftp.h # (new) -> 1.1 net/ipv4/netfilter/ip_nat_tftp.c # (new) -> 1.1 net/ipv4/netfilter/ip_conntrack_tftp.c # (new) -> 1.3 fs/xfs/xfs_qmops.c # (new) -> 1.1 net/xfrm/Kconfig # (new) -> 1.2 arch/ppc/platforms/pmac_cpufreq.c # (new) -> 1.1 net/ipv4/netfilter/ip_conntrack_amanda.c # (new) -> 1.1 drivers/pcmcia/sa11xx_core.h # (new) -> 1.1 arch/sparc64/kernel/us2e_cpufreq.c # (new) -> 1.1 drivers/char/drm/i830_irq.c # (new) -> 1.1 include/linux/kmalloc_sizes.h # (new) -> 1.2 fs/xfs/xfs_dmops.c # (new) -> 1.1 fs/xfs/quota/xfs_qm_stats.h # (new) -> 1.1 crypto/deflate.c # (new) -> 1.1 arch/arm/lib/div64.S # (new) -> 1.1 net/xfrm/Makefile # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 03/03/24 torvalds@penguin.transmeta.com 1.977.12.4 # Linux 2.5.66 # -------------------------------------------- # 03/03/25 anton@samba.org 1.977.1.12 # Merge samba.org:/scratch/anton/linux-2.5 # into samba.org:/scratch/anton/tmp3 # -------------------------------------------- # 03/03/25 anton@samba.org 1.977.1.13 # Merge samba.org:/scratch/anton/linux-2.5 # into samba.org:/scratch/anton/tmp3 # -------------------------------------------- # 03/03/24 greg@kroah.com 1.977.3.4 # [PATCH] i2c: set up a "generic" i2c driver to prevent oopses when devices are registering. # # This is needed as we are still not using the driver core model for # matching up devices to drivers, but doing it by hand. Once that is # changed, this will not be needed. # -------------------------------------------- # 03/03/24 greg@kroah.com 1.977.12.5 # Merge kroah.com:/home/greg/linux/BK/bleed-2.5 # into kroah.com:/home/greg/linux/BK/i2c-2.5 # -------------------------------------------- # 03/03/25 anton@samba.org 1.977.1.14 # ppc64: Rework pci probe to be like alpha. # -------------------------------------------- # 03/03/24 agrover@groveronline.com 1.977.2.90 # Merge groveronline.com:/root/bk/linux-2.5 # into groveronline.com:/root/bk/linux-acpi # -------------------------------------------- # 03/03/24 greg@kroah.com 1.977.13.1 # Merge kroah.com:/home/greg/linux/BK/bleed-2.5 # into kroah.com:/home/greg/linux/BK/gregkh-2.5 # -------------------------------------------- # 03/03/24 davem@nuts.ninka.net 1.977.14.1 # Merge nuts.ninka.net:/home/davem/src/BK/network-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/03/25 paulus@samba.org 1.977.1.15 # ppc64: Add missing RELOCs # -------------------------------------------- # 03/03/24 hch@lst.de 1.977.14.2 # [NET]: Kill dev_init_buffers, was scheduled to die in 2.5.x # -------------------------------------------- # 03/03/24 toml@us.ibm.com 1.977.14.3 # [IPSEC]: Fix IPV6 UDP policy checking. # -------------------------------------------- # 03/03/25 anton@samba.org 1.977.1.16 # ppc64: fix pci probe on large bus systems # -------------------------------------------- # 03/03/25 anton@samba.org 1.977.15.1 # Merge samba.org:/scratch/anton/linux-2.5 # into samba.org:/scratch/anton/linux-2.5_ppc64 # -------------------------------------------- # 03/03/25 anton@samba.org 1.977.1.17 # Merge samba.org:/scratch/anton/export # into samba.org:/scratch/anton/linux-2.5_ppc64 # -------------------------------------------- # 03/03/25 anton@samba.org 1.977.16.1 # ppc64: Disable 32bit SLB invalidation optimisation for the moment # -------------------------------------------- # 03/03/25 anton@samba.org 1.977.17.1 # Merge samba.org:/scratch/anton/export into samba.org:/scratch/anton/tmp3 # -------------------------------------------- # 03/03/25 anton@samba.org 1.977.17.2 # ppc64: Fix problem with casting out the segment for our kernel stack # -------------------------------------------- # 03/03/25 anton@samba.org 1.977.1.18 # Merge samba.org:/scratch/anton/export # into samba.org:/scratch/anton/linux-2.5_ppc64 # -------------------------------------------- # 03/03/24 rth@are.twiddle.net 1.977.18.1 # Merge are.twiddle.net:/home/rth/BK/linus-2.5 # into are.twiddle.net:/home/rth/BK/axp-2.5 # -------------------------------------------- # 03/03/24 ink@jurassic.park.msu.ru 1.977.18.2 # [PATCH] alpha: file offset in pte # # It's possible to squeeze more bits out of lower half of pte, # but 32 seem to be a plenty... # # Ivan. # -------------------------------------------- # 03/03/24 ink@jurassic.park.msu.ru 1.977.18.3 # [PATCH] alpha: handle unaligned REFQUADs produced by BUG() macro # # -------------------------------------------- # 03/03/24 ink@jurassic.park.msu.ru 1.977.18.4 # [PATCH] alpha: pci update # # - Check for parent PCI bus instead of bridge device to break the # look in common_swizzle(). Functionally it's the same, but it's # cleaner for PC-style host bridges (nautiluses). # - Generic PCI setup changes finally went in (thanks to rmk), so that # FIXME in common_init_pci() can go. # # Ivan. # -------------------------------------------- # 03/03/24 ink@jurassic.park.msu.ru 1.977.18.5 # [PATCH] alpha: nautilus_init_pci() cleanup # # -------------------------------------------- # 03/03/24 ink@jurassic.park.msu.ru 1.977.18.6 # [PATCH] alpha: fix jiffies compile warning in smp.c # # Fix more annoying compile problems due to wrong types # for comparing jiffies. This patch applies to alpha arch. # # From Thomas Weyergraf. # # Ivan. # -------------------------------------------- # 03/03/24 torvalds@home.transmeta.com 1.977.12.6 # Merge bk://are.twiddle.net/axp-2.5/ # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/03/24 davem@nuts.ninka.net 1.977.14.4 # [TCP]: Forward port of 2.4.x bugfix, noticed as missing by davej@codemonkey.org.uk. # # In tcp_sendmsg, make sure we jump to the out label # when seglen is decremented to zero and no more iovecs remain. # This matches the do_tcp_sendpages logic and makes sure that # PSH is set correctly at the end of a write even if the write length # equals the current mss. # -------------------------------------------- # 03/03/24 sfr@canb.auug.org.au 1.977.14.5 # [SCTP]: Fix IRQ flags warnings. # -------------------------------------------- # 03/03/24 yoshfuji@linux-ipv6.org 1.977.14.6 # [IPSEC]: Move xfrm_*.c into net/xfrm/ # -------------------------------------------- # 03/03/24 davem@kernel.bkbits.net 1.977.12.7 # Merge davem@nuts.ninka.net:/home/davem/src/BK/net-2.5 # into kernel.bkbits.net:/home/davem/net-2.5 # -------------------------------------------- # 03/03/24 davem@nuts.ninka.net 1.977.19.1 # [DRM]: Fix warnings and build errors introduced by previous changes to drm_drv.h # -------------------------------------------- # 03/03/24 davem@kernel.bkbits.net 1.977.20.1 # Merge davem@nuts.ninka.net:/home/davem/src/BK/sparc-2.5 # into kernel.bkbits.net:/home/davem/sparc-2.5 # -------------------------------------------- # 03/03/25 rmk@flint.arm.linux.org.uk 1.977.21.1 # [ARM] Add pte_file() and friends to pgtable.h # -------------------------------------------- # 03/03/25 davem@nuts.ninka.net 1.977.14.7 # [IPSEC]: Kill skb_ah_walk, not needed. # -------------------------------------------- # 03/03/25 davem@nuts.ninka.net 1.977.14.8 # [NET]: Make SKB layout/initialization/copy more cache friendly. # -------------------------------------------- # 03/03/25 zaitcev@redhat.com 1.977.19.2 # [SPARC]: Handle make w/o arg sanely, by Sam Ravnborg. # -------------------------------------------- # 03/03/25 zaitcev@redhat.com 1.977.19.3 # [SPARC64]: Kill ELF_FLAGS_INIT. # -------------------------------------------- # 03/03/25 davem@nuts.ninka.net 1.977.19.4 # [SPARC64]: Uninline rwsem assembler. # -------------------------------------------- # 03/03/25 shaggy@shaggy.austin.ibm.com 1.977.22.1 # Merge jfs@jfs.bkbits.net:linux-2.5 # into shaggy.austin.ibm.com:/shaggy/bk/jfs-2.5 # -------------------------------------------- # 03/03/25 hch@lst.de 1.977.23.1 # [PATCH] fix rescan warning # # The prototype for scsi_rescan_device was missing and once added it's # caller doesn't compile anymore because it expects a return value.. # -------------------------------------------- # 03/03/25 willy@debian.org 1.977.23.2 # [PATCH] C3000 support in sym53c8xx # # This patch adds support for the HP firmware call pdc_get_initiator(). # This is necessary to support the narrow SCSI port on machines such as # the C3000 which use one channel of the 896 in narrow mode and one in # wide mode. The only way to figure this out is to ask firmware how it's # configured. # -------------------------------------------- # 03/03/25 hch@lst.de 1.889.390.1 # [PATCH] aha152x tidbits # # (1) fix the jiffies warnings # (2) remove the #undef MODULE braindamange for pcmcia # (3) make all methods static and move the template away from the header # -------------------------------------------- # 03/03/25 jejb@raven.il.steeleye.com 1.977.23.3 # Merge raven.il.steeleye.com:/home/jejb/BK/scsi-aha152x-2.5 # into raven.il.steeleye.com:/home/jejb/BK/scsi-misc-2.5 # -------------------------------------------- # 03/03/25 dougg@torque.net 1.977.23.4 # [PATCH] minor scsi_lib.c cleanup for 2.5.64 # # The following patch made the trail in /var/log/messages # a little easier to follow (for me). Just a cosmetic change. # -------------------------------------------- # 03/03/25 torvalds@home.transmeta.com 1.977.20.2 # Merge bk://kernel.bkbits.net/davem/sparc-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/03/25 torvalds@home.transmeta.com 1.977.12.8 # Merge bk://kernel.bkbits.net/davem/net-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/03/25 torvalds@home.transmeta.com 1.977.1.19 # Merge http://ppc.bkbits.net/for-linus-ppc64 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/03/25 ak@suse.de 1.977.1.20 # [PATCH] aio compat patches # # The new aio emulation in x86-64 needs a few aio symbols exported. # Export them. # -------------------------------------------- # 03/03/25 ak@suse.de 1.977.1.21 # [PATCH] ACPI NUMA option fix for x86-64 # # The ACPI NUMA support doesn't work on x86-64 currently (no SRAT # parsing yet). Disable for now. # -------------------------------------------- # 03/03/25 baldrick@wanadoo.fr 1.977.13.2 # [PATCH] USB speedtouch: code reorganization # # Remove dead code from sarlib, reorganize live sarlib code (trivial transformations). # -------------------------------------------- # 03/03/25 baldrick@wanadoo.fr 1.977.13.3 # [PATCH] USB speedtouch: trivial cleanups # -------------------------------------------- # 03/03/25 baldrick@wanadoo.fr 1.977.13.4 # [PATCH] USB speedtouch: per vcc data cleanups # # Use struct list_head rather than a singly linked list in udsl_vcc_data. Reject # attempts to open multiple vccs with the same vpi/vci pair. Some cleanups too. # -------------------------------------------- # 03/03/25 baldrick@wanadoo.fr 1.977.13.5 # [PATCH] USB speedtouch: eliminate ATM open/close races # # The list of open vccs is modified by open/close, and traversed by the # receive tasklet. This is the last race I know of in this driver. # -------------------------------------------- # 03/03/25 ink@jurassic.park.msu.ru 1.977.13.6 # [PATCH] USB: missing include # # at least Alpha needs mm.h for "page_address". # -------------------------------------------- # 03/03/25 david-b@pacbell.net 1.977.13.7 # [PATCH] USB: usb-skeleton, usbtest use "real" device ids # # I'll be switching "gadget zero" to use real product IDs # (donated by NetChip), and these are the two drivers that # will need to recognize them. # -------------------------------------------- # 03/03/25 joe@perches.com 1.977.13.8 # [PATCH] USB: usb_skeleton.c trivial fix # # Remove redundant __FILE__. # -------------------------------------------- # 03/03/25 ak@suse.de 1.977.1.22 # [PATCH] x86-64 updates # # Lots of x86-64 updates. Merge with 2.4 and NUMA works now. Also reenabled # the preemptive kernel. And some other bug fixes. # IOMMU disabled by default now because it has problems. # # - Add more CONFIG options for device driver debugging and iommu # force/debug. (don't enable iommu force currently) # - Some S3/ACPI fixes/cleanups from Pavel. # - Set MSG_COMPAT_* in msg_flags for networking 32bit emulation. # This unfortunately still doesn't fix the fd passing problems. # - Sync PCI IOMMU code with 2.4 (minor fixes, flush less often) # - Really fix UP compilation (Pavel) # - Reenable preempt # - Fix CONFIG_DISCONTIGMEM bootup and enable. Still needs more tuning. # - Fix some bugs in topology discovery and clean code up. # - Don't put unwind tables into object files # - Some kernel debugging hooks # - Move CPU detection into early real mode code to better interact with # vesafb consoles # - Initialize mode in real mode character output # - New 32bit FPU signal save/restore # - Various fixes in FPU handling in ptrace # - Fix security holes in ptrace (32bit and 64bit) # - Fix serial ioctl (including security hole) # - Add bluetooth ioctls to 32bit emu (from sparc64) # - Correctly enable si_val in queued signals in 32bit emulation # - Rework SEM_STAT emulation. LTP still fails unfortunately. # - Fix error case in msg* emulation # - Fix debug register access from ptrace (Michal Ludvig, me) # - Fix handling of NULL arguments in 32bit execve # - Fix some error cases for 32bit readv/writev (LTP still complains) # - Remove rate control from unimplemented syscall warnings # - Fix error message for missing aperture # - Turn some APIC printks into Dprintk to make the bootup more quiet # - Some fixes for no APIC (probably still broken), add disableapic # option (untested) # - Sync K8 MCE handler with 2.4. Should work a lot better now. # - Remove never used KDB hooks # - Fix buffer overflow in command line copying # - Merge from i386: use separate status word for lazy FPU state # - Don't force the IOMMU for dma masks < 4GB. # - Print backtrace in Sysrq-T (from Andrea) # - Merge from i386: fix FPU race in fork. # - Disable NX mode by default for now # - Rewrite dump_pagetable # - Fix off by one bug in ioremap (i386 merge) # - Merge from i386: handle VIA pci bridge bugs # - Disable NUMA ACPI support (no SRAT support yet) # - Fix aio 32bit emulation # - Increase 32bit address space to nearly 4GB # - Add exit_group syscall # - Fix TLS setting in clone (Ulrich Drepper) # -------------------------------------------- # 03/03/25 oliver.spang@siemens.com 1.977.13.9 # [PATCH] USB: Compiler error in cdc-acm when DEBUG defined # -------------------------------------------- # 03/03/25 randy.dunlap@verizon.net 1.977.13.10 # [PATCH] USB: usb/misc/emi26.c stack reduction # # Reduces stack usage in emi26_load_firmware(). # -------------------------------------------- # 03/03/25 greg@kroah.com 1.977.13.11 # [PATCH] USB: fix Makefile to allow usb midi driver to be built if it's the only class driver selected. # -------------------------------------------- # 03/03/25 mochel@osdl.org 1.977.24.1 # driver model: don't define DEBUG in base.h # -------------------------------------------- # 03/03/25 mochel@osdl.org 1.977.24.2 # driver model: Make sure we initialize drivers' class_list. # -------------------------------------------- # 03/03/25 mochel@osdl.org 1.977.24.3 # driver model: Fix error handling in sysfs registration # # From Matt Dobson: # # The cpu, memblk, and node driver/device registration should be a little # more clean in the way it handles registration failures. Or at least # *consistent* amongst the topology elements. Right now, failures are # either silent, obscure, or leave things in an inconsistent state. # -------------------------------------------- # 03/03/25 oliver@neukum.name 1.977.13.12 # [PATCH] USB: Another memory allocation in block IO error handling path # # - memory allocation in block io error code path with GFP_KERNEL # -------------------------------------------- # 03/03/25 oliver@neukum.name 1.977.13.13 # [PATCH] USB: storage device reset cleanup # # > In the absence of far-reaching changes to the API, my suggestion is to # > have the emulated SCSI bus reset code in usb-storage do nothing but log an # > error message and return an error code. For the time being, considering # > how infrequently these resets occur, we can simply rely on the user # > unplugging the USB cable and putting it back in or cycling the power to # > the drive. (Yes, there are situations where these resets crop up # > regularly -- but they are the result of some other incompatibility that a # > device reset won't fix anyway.) # # OK, as the consensus seems to be that in the short run changing things # for a full reset implementation is not worth it, here's an implementation # that does the best we can do without. # It issues a reset only if we can be sure that there are no other users # of the device in question. # As the version currently in the storage driver is broken anyway, # this is a definite improvement. And it addresses the need of exporting # the probe/remove functions for storage's sake. # -------------------------------------------- # 03/03/25 oliver@neukum.name 1.977.13.14 # [PATCH] USB: storage: add logging to reset # # - add logging to reset # -------------------------------------------- # 03/03/25 agrover@groveronline.com 1.977.1.23 # Merge groveronline.com:/root/bk/linux-2.5 # into groveronline.com:/root/bk/linux-acpi # -------------------------------------------- # 03/03/25 nathans@sgi.com 1.977.25.1 # [XFS] Next step in bhv code cleanup - this is a start on moving quota and dmapi # into behavior layers, purging several points where these sit slap bang in # the middle of XFS code (esp. read_super). Also removes numerous #ifdef's # and a bunch of unused #define's from all over the place. More to come. # # SGI Modid: 2.5.x-xfs:slinx:141499a # -------------------------------------------- # 03/03/25 nathans@sgi.com 1.977.25.2 # [XFS] In showargs, report the usrquota/grpquota option variant, which is common. # # SGI Modid: 2.5.x-xfs:slinx:141511a # -------------------------------------------- # 03/03/25 mdharm-usb@one-eyed-alien.net 1.977.13.15 # [PATCH] usb-storage: LUN and isd200 # # This patch (developed with assistance from Jan Harkes # ) makes the LUN field of a bulk-only transport come # from a known-good source, rather than the likely-good command-byte. It # also updates the ISD200 driver to work with this change. # -------------------------------------------- # 03/03/25 mdharm-usb@one-eyed-alien.net 1.977.13.16 # [PATCH] usb-storage: initialize urb status # # This patch initializes the URB status before it's used. While not # technically required, it's good programming practice (and a similar bug # just bit us on 2.4 with UHCI). # -------------------------------------------- # 03/03/25 mdharm-usb@one-eyed-alien.net 1.977.13.17 # [PATCH] usb-storage: cleanup # # This patch changes some debugging output to be a bit more clear, and # removes some un-needed code -- it's no longer possible for us to have # active URBs in the disconnect path. # -------------------------------------------- # 03/03/25 mochel@osdl.org 1.977.26.1 # driver model: increase BUS_ID_SIZE to 20 # # From Ben Collins, for the sake of ieee1394, so the 64-bit (16 char) GUID # can be used for the bus_id. # -------------------------------------------- # 03/03/25 nathans@sgi.com 1.977.25.3 # [XFS] whitespace and code formatting changes # -------------------------------------------- # 03/03/25 greg@kroah.com 1.977.13.18 # [PATCH] USB: fix compiler warning in usb-storage # -------------------------------------------- # 03/03/25 bhards@bigpond.net.au 1.977.13.19 # [PATCH] USB: CDC Ethernet zero packet fix # -------------------------------------------- # 03/03/25 bhards@bigpond.net.au 1.977.13.20 # [PATCH] USB: CDC Ethernet maintainer transfer # -------------------------------------------- # 03/03/25 greg@kroah.com 1.977.13.21 # USB: remove unneeded #include # -------------------------------------------- # 03/03/25 greg@kroah.com 1.977.27.1 # Merge kroah.com:/home/greg/linux/BK/bleed-2.5 # into kroah.com:/home/greg/linux/BK/gregkh-2.5 # -------------------------------------------- # 03/03/25 mochel@osdl.org 1.977.28.1 # Merge bk://linux.bkbits.net/linux-2.5 # into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-virgin # -------------------------------------------- # 03/03/25 mochel@osdl.org 1.977.28.2 # Merge osdl.org:/home/mochel/src/kernel/devel/linux-2.5-virgin # into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-core # -------------------------------------------- # 03/03/26 rmk@flint.arm.linux.org.uk 1.977.21.2 # [ARM] Fix ARM do_div() implementation # # The ARM do_div() implementation was rather lax in that it only # performed a 32-bit divide. This cset fixes this oversight by # providing a 64-bit by 32-bit division in asm. # # This is necessary for posix-timers to function correctly. # -------------------------------------------- # 03/03/25 j.dittmer@portrix.net 1.977.29.1 # [PATCH] i2c: fix compile bugs in tvmixer.c # # Additionally I need the following patch to tvmixer.c to compile properly # with CONFIG_SOUND_TVMIXER=m. Just a /client->name/client->dev.name/g. # -------------------------------------------- # 03/03/25 j.dittmer@portrix.net 1.977.29.2 # [PATCH] i2c: add i2c-via686a driver # -------------------------------------------- # 03/03/25 mochel@osdl.org 1.977.28.3 # driver model: fix warning in cpu init. # -------------------------------------------- # 03/03/25 davem@nuts.ninka.net 1.977.30.1 # Merge nuts.ninka.net:/home/davem/src/BK/network-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/03/25 davem@nuts.ninka.net 1.977.31.1 # Merge nuts.ninka.net:/home/davem/src/BK/sparcwork-2.5 # into nuts.ninka.net:/home/davem/src/BK/sparc-2.5 # -------------------------------------------- # 03/03/25 jgrimm2@us.ibm.com 1.977.30.2 # [IPV6]: Export some icmpv6 symbols for SCTP. # -------------------------------------------- # 03/03/25 yoshfuji@linux-ipv6.org 1.977.30.3 # [IPSEC]: Remove duplicate / obsolete entry in include/linux/dst.h # -------------------------------------------- # 03/03/25 randy.dunlap@verizon.net 1.977.30.4 # [NET]: typo and comment fixes # -------------------------------------------- # 03/03/25 chas@locutus.cmf.nrl.navy.mil 1.977.30.5 # [ATM]: Fix total_len calculation in IPHASE driver. # -------------------------------------------- # 03/03/25 kuznet@ms2.inr.ac.ru 1.977.30.6 # [IPV4]: Make sure rtcache flush happens after sysctl updates. # -------------------------------------------- # 03/03/26 davem@nuts.ninka.net 1.977.31.2 # [SPARC64]: cpufreq cleanup, move notifier into common area. # -------------------------------------------- # 03/03/26 davem@nuts.ninka.net 1.977.31.3 # [SPARC64]: Initial cut at Ultra-IIe cpufreq driver. # -------------------------------------------- # 03/03/26 davem@nuts.ninka.net 1.977.31.4 # [SPARC64]: Make boot targets get cleaned up properly. # -------------------------------------------- # 03/03/26 davem@nuts.ninka.net 1.977.30.7 # [IPSEC]: Remove unused field 'owner' from selector. # -------------------------------------------- # 03/03/26 rmk@flint.arm.linux.org.uk 1.977.21.3 # [ARM] Remove EXPORT_NO_SYMBOLS # -------------------------------------------- # 03/03/26 rmk@flint.arm.linux.org.uk 1.977.21.4 # [ARM] Update mach-types # -------------------------------------------- # 03/03/26 rmk@flint.arm.linux.org.uk 1.977.21.5 # [ARM] Pass prev task_struct through __switch_to # -------------------------------------------- # 03/03/26 davem@nuts.ninka.net 1.977.30.8 # [IPSEC]: linux/xfrm.h u32 --> __u32. # -------------------------------------------- # 03/03/26 rmk@flint.arm.linux.org.uk 1.977.21.6 # [ARM] console init functions return type int # -------------------------------------------- # 03/03/26 rmk@flint.arm.linux.org.uk 1.977.21.7 # [ARM] Update Cyber2000fb driver for new fbcon API # # This cset updates cyber2000fb (used on NetWinders) to the new # fbcon API, and adds cfbfillrect, cfbcopyarea and cfbimgblt # objects when building cyber2000fb. # -------------------------------------------- # 03/03/26 rmk@flint.arm.linux.org.uk 1.977.21.8 # [ARM] Support write combining on framebuffers # -------------------------------------------- # 03/03/26 rmk@flint.arm.linux.org.uk 1.977.21.9 # [ARM] Fix potential oops in epxa10db-flash.c # # Fix potential oops if kmalloc returns NULL. # Really return an error when out of memory. # -------------------------------------------- # 03/03/26 rmk@flint.arm.linux.org.uk 1.977.21.10 # [ARM] Quieten dc21285 host bridge driver during bus probing. # # - don't report PCI aborts during config cycles as errors. # - don't scan the pci buses if we receive a master abort. # - setup error handlers earlier. # -------------------------------------------- # 03/03/26 rmk@flint.arm.linux.org.uk 1.977.21.11 # [ARM] Kill compiler warning about uninitialised ppcr in cpu-sa1110.c. # -------------------------------------------- # 03/03/26 rmk@flint.arm.linux.org.uk 1.977.21.12 # [ARM] Ensure transmit lines are held in mark state. # -------------------------------------------- # 03/03/26 rmk@flint.arm.linux.org.uk 1.977.32.1 # Merge flint.arm.linux.org.uk:/usr/src/linux-bk-2.5/linux-2.5-pci # into flint.arm.linux.org.uk:/usr/src/linux-bk-2.5/linux-2.5-pcmcia # -------------------------------------------- # 03/03/26 torvalds@home.transmeta.com 1.977.30.9 # Merge bk://kernel.bkbits.net/davem/net-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/03/26 torvalds@home.transmeta.com 1.977.30.10 # Merge bk://bk.arm.linux.org.uk/linux-2.5-rmk # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/03/26 hch@sgi.com 1.977.25.4 # [XFS] Separate the quota source into its own subdirectory ala dmapi. # Push a bunch of quota- and dmapi-specific code down into these # subdirs which previously was compiled into the core XFS code, # and don't descend into these subdirs if options config'd off. # # SGI Modid: 2.5.x-xfs:slinx:141850a # -------------------------------------------- # 03/03/26 nathans@sgi.com 1.977.25.5 # [XFS] Cleanup/remove a bunch of macros, comments and code. # # SGI Modid: 2.5.x-xfs:slinx:141925a # -------------------------------------------- # 03/03/26 nathans@sgi.com 1.977.25.6 # [XFS] Header shuffling to try and keep several source trees aligned - move the # realtime inode detection macro somewhere more appropriate. # # SGI Modid: 2.5.x-xfs:slinx:141951a # -------------------------------------------- # 03/03/26 nathans@sgi.com 1.977.25.7 # [XFS] Cut and paste stuff up on my part in the DMAPI headers. # # SGI Modid: 2.5.x-xfs:slinx:142163a # -------------------------------------------- # 03/03/26 nathans@sgi.com 1.977.25.8 # [XFS] Cut and paste stuff up on my part in the DMAPI headers. # # SGI Modid: 2.5.x-xfs:slinx:142170a # -------------------------------------------- # 03/03/26 nathans@sgi.com 1.977.25.9 # [XFS] Add back the pagebuf flag for scheduling on the data daemon. Moving # this into just a pagebuf_iodone parameter was broken as we don't have # sufficient state in all the places we need it to make the decision. # # SGI Modid: 2.5.x-xfs:slinx:141626a # -------------------------------------------- # 03/03/26 lord@sgi.com 1.977.25.10 # [XFS] optimize timestamp updates, use new hires timestamps more directly, # also fix a bug where the mtime field was not correctly updated. # # SGI Modid: 2.5.x-xfs:slinx:142296a # -------------------------------------------- # 03/03/26 sandeen@sgi.com 1.977.25.11 # [XFS] Use mod_timer in place of del/modify/add (can race) # Also use del_timer_sync when we're done. # # SGI Modid: 2.5.x-xfs:slinx:142197a # -------------------------------------------- # 03/03/26 roehrich@sgi.com 1.977.25.12 # [XFS] fix initialization of dmapi code # # SGI Modid: 2.5.x-xfs:slinx:142389a # -------------------------------------------- # 03/03/26 hch@sgi.com 1.977.25.13 # [XFS] remove fs/xfs/xfs_dqblk.h # # This one should have gone away a few checkings ago. I blame it on # BitKeeper.. :) # -------------------------------------------- # 03/03/26 torvalds@home.transmeta.com 1.977.27.2 # Merge bk://linuxusb.bkbits.net/linus-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/03/26 hch@hera.kernel.org 1.977.27.3 # Merge # -------------------------------------------- # 03/03/26 torvalds@home.transmeta.com 1.977.33.1 # Merge bk://bk.arm.linux.org.uk/linux-2.5-pcmcia # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/03/26 torvalds@home.transmeta.com 1.977.27.4 # Merge ssh://master.kernel.org//home/hch/BK/xfs/linux-2.5/ # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/03/26 linux@de.rmk.(none) 1.977.32.2 # [PCMCIA] "driver services" socket add/remove abstraction # # Previously, "Driver Services" could only be called when the socket # drivers were initialized earlier. This caused an awful lot of # problems, especially when modprobe tried to load ds.ko and a pcmcia # card driver at once. # # As all socket devices are registered with the driver model core as # being of "class_type pcmcia_socket_class", we can take use of that and # register them with "Driver Services" upon detection or upon # module loading of ds.c. # # Also, the "I-need-two-initcalls-in-a-module"-tweak can go away. # # Unfortunately, this patch reportedly breaks some RedHat pcmcia init # scritps - they relied on the failed loading of ds.c to detect that no # socket driver was loaded previously. To properly detect this, you # should take a look at the /sys/class/pcmcia_socket/devices directory. # -------------------------------------------- # 03/03/26 linux@de.rmk.(none) 1.977.32.3 # [PCMCIA] remove "init_status" from struct pcmcia_driver # # As we don't have a late_initcall in ds.c any more, we can't easily # distinguish between in-kernel drivers and those built as modules. This # information was used by cardmgr to detect whether "rmmod" makes # sense. As unloading of modules seems to be deprecated behaviour anyway # in 2.5., and the current driver unloading process is IMO broken # anyway, I don't shed any tears on this lost functionality. # -------------------------------------------- # 03/03/27 linux@de.rmk.(none) 1.977.32.4 # [PATCH] convert ds.c's socekt_info_t to struct pcmcia_bus_socket # # Rename socket_info_t (which is used many, many times differently # within pcmcia) to "struct pcmcia_bus_socket". # # Also, a couple of functions in ds.c can be converted to use the "struct # pcmcia_bus_socket" as argument instead of the socket number. # -------------------------------------------- # 03/03/27 linux@de.rmk.(none) 1.977.32.5 # [PCMCIA] remove unused include/pcmcia/driver_ops.h # # Except for dev_node_t, the contents of include/pcmcia/driver_ops.h # aren't used anywhere within the kernel. It's a left-over file from the # days when cardbus 32-bit cards weren't handled as pci devices, and # their drivers as pci drivers. So, move the dev_node_t to # include/pcmcia/ds.h, remove the lone in-kernel reference to # driver_ops.h, and remove the contents of driver_ops.h. # -------------------------------------------- # 03/03/27 paulus@samba.org 1.983 # Merge samba.org:/home/paulus/kernel/linux-2.5 # into samba.org:/home/paulus/kernel/for-linus-ppc # -------------------------------------------- # 03/03/27 benh@kernel.crashing.org 1.984 # PPC32: Factor out common code for reading/setting various SPRs. # -------------------------------------------- # 03/03/27 benh@kernel.crashing.org 1.985 # PPC32: Add support for CPU frequency scaling on some PowerMacs # -------------------------------------------- # 03/03/26 torvalds@home.transmeta.com 1.977.27.5 # Merge bk://bk.arm.linux.org.uk/linux-2.5-pcmcia # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/03/27 benh@kernel.crashing.org 1.986 # PPC32: Add function for choosing which PLL to use on 750FX cpus. # -------------------------------------------- # 03/03/27 benh@kernel.crashing.org 1.987 # PPC32: Forward-port support for new powermacs from 2.4 tree. # -------------------------------------------- # 03/03/27 paulus@samba.org 1.988 # PPC32: Fix compilation of powermac cpufreq stuff # -------------------------------------------- # 03/03/27 benh@kernel.crashing.org 1.989 # PPC32: Unmap the VIA (versatile interface adaptor) chip after we are done with it. # -------------------------------------------- # 03/03/27 trini@kernel.crashing.org 1.990 # PPC32: Update the banner printed for the Spruce board # -------------------------------------------- # 03/03/27 benh@kernel.crashing.org 1.991 # PPC32: Get Open Firmware to initialize all the displays, not just one. # -------------------------------------------- # 03/03/27 mochel@osdl.org 1.977.27.6 # Merge bk://linux.bkbits.net/linux-2.5 # into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-virgin # -------------------------------------------- # 03/03/27 mochel@osdl.org 1.977.27.7 # Merge osdl.org:/home/mochel/src/kernel/devel/linux-2.5-virgin # into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-core # -------------------------------------------- # 03/03/27 hch@lst.de 1.977.23.5 # [PATCH] update qlogic and fdomain drivers to use pcmcia_register_driver # -------------------------------------------- # 03/03/27 hch@lst.de 1.977.23.6 # [PATCH] some more entries for the largelun list # -------------------------------------------- # 03/03/27 tomita@cinet.co.jp 1.977.23.7 # [PATCH] Complete support for PC-9800 sub-arch (9/9) SCSI # # This is the patch to support NEC PC-9800 subarchitecture # against 2.5.65-ac4. (9/9) # # SCSI host adapter support. # - BIOS parameter change for PC98. # - Add pc980155 driver for old PC98. # - wd33c93.c update error handler for eh_*. # - wd33c93.h register to int for PIO mode. # # Regards, # Osamu Tomita # -------------------------------------------- # 03/03/27 dougg@torque.net 1.977.23.8 # [PATCH] scsi_ioctl.c for SEND_DIAGNOSTIC # # This is a multi-part message in MIME format. # -------------------------------------------- # 03/03/27 dougg@torque.net 1.977.23.9 # [PATCH] block scsi_ioctl.c lk 2.5.66 # # This is a multi-part message in MIME format. # -------------------------------------------- # 03/03/27 jmorris@intercode.com.au 1.977.30.11 # [NET]: Warn only once about SO_BSDCOMPAT. # -------------------------------------------- # 03/03/27 jejb@raven.il.steeleye.com 1.889.391.1 # fix scsi/qlogicfc.c stack problems # # Revert Randy's stack fix and apply the one from the -dj tree # instead. # -------------------------------------------- # 03/03/27 trond.myklebust@fys.uio.no 1.977.34.1 # Fix xprt.c so that it resends RPC requests immediately after a timeout. # Doing this ensures that we keep probing the connection to the server # rather than just waiting for the entire congestion window to time out. # The latter can be very expensive due to the exponential backoff rule. # -------------------------------------------- # 03/03/27 jejb@raven.il.steeleye.com 1.977.23.10 # Merge raven.il.steeleye.com:/home/jejb/BK/scsi-qlogicfc-2.5 # into raven.il.steeleye.com:/home/jejb/BK/scsi-misc-2.5 # -------------------------------------------- # 03/03/27 trond.myklebust@fys.uio.no 1.977.34.2 # Micro-optimization: rename rpc_lookup_path() as rpc_lookup_parent() # and drop the 'flags' argument (it was always set too LOOKUP_PARENT). # # If the user supplies and empty path, return -ENOENT. # -------------------------------------------- # 03/03/27 trond.myklebust@fys.uio.no 1.977.34.3 # Fix the RPC debugging code so that it doesn't Oops if a task has # a null 'p_proc' procedure pointer. # -------------------------------------------- # 03/03/27 trond.myklebust@fys.uio.no 1.977.34.4 # [PATCH] Fix misleading EIO on NFS client # # The following patch by Joe Korty removes an over-zealous check in the NFS # read code that causes pages to be incorrectly marked with PG_error and # hence causes an EIO to be returned to userland. # # The test is incorrect as it ignores the fact that we may be caching a # write that will extend the file on the server (and hence will create a # hole in the region concerned.). # -------------------------------------------- # 03/03/27 trond.myklebust@fys.uio.no 1.977.34.5 # Fix a typo in auth_gss.c. Clean out an unused variable. # -------------------------------------------- # 03/03/27 alan@lxorguk.ukuu.org.uk 1.977.35.1 # [PATCH] Avoid unknown IDE commands # # One from Jens - fix up the problems with older Samsung disks that don't # abort unknown commands sometimes # -------------------------------------------- # 03/03/27 alan@lxorguk.ukuu.org.uk 1.977.35.2 # [PATCH] Add a comment that the irq_nosync stuff needs revisiting # -------------------------------------------- # 03/03/27 alan@lxorguk.ukuu.org.uk 1.977.35.3 # [PATCH] Ensure hdparm errors to the user when the request isnt allowed # -------------------------------------------- # 03/03/27 alan@lxorguk.ukuu.org.uk 1.977.35.4 # [PATCH] Remove obsolete IDE timing hack # # Vojtech Pavlik # # The ide fixes for the VIA8235 obsolete this hack # -------------------------------------------- # 03/03/27 trond.myklebust@fys.uio.no 1.977.34.6 # Fix a memory corruption bug in NFSv4 client. # -------------------------------------------- # 03/03/27 alan@lxorguk.ukuu.org.uk 1.977.35.5 # [PATCH] fix radio_cadet driver locking # # Forward port the replacement to the horribly broken locking in 2.5 # radio_cadet driver. # -------------------------------------------- # 03/03/27 alan@lxorguk.ukuu.org.uk 1.977.35.6 # [PATCH] Fix up 3w-xxxx driver # # Fix up 3w-xxxx. I didnt test SMP and it shows # -------------------------------------------- # 03/03/27 alan@lxorguk.ukuu.org.uk 1.977.35.7 # [PATCH] Merge the serial config entries for PC9800 # # From Osamu Tomita # -------------------------------------------- # 03/03/27 alan@lxorguk.ukuu.org.uk 1.977.35.8 # [PATCH] Make cramfs compile again # -------------------------------------------- # 03/03/27 alan@lxorguk.ukuu.org.uk 1.977.35.9 # [PATCH] fs/exec.c does not need __NO_VERSION__ # # From Christoph Hellwig I think # -------------------------------------------- # 03/03/27 alan@lxorguk.ukuu.org.uk 1.977.35.10 # [PATCH] Quota should not reference user addresses directly # # (Stanford Checker, Chris Wright) # -------------------------------------------- # 03/03/27 alan@lxorguk.ukuu.org.uk 1.977.35.11 # [PATCH] PC9800 uses different IDE i/o bases for legacy mode devices # # From Osamu Tomita # -------------------------------------------- # 03/03/27 alan@lxorguk.ukuu.org.uk 1.977.35.12 # [PATCH] Wrong kind of NUL fix for asm headers # -------------------------------------------- # 03/03/27 alan@lxorguk.ukuu.org.uk 1.977.35.13 # [PATCH] S/390 typo fixes # # From Steven Cole # -------------------------------------------- # 03/03/27 trond.myklebust@fys.uio.no 1.977.34.7 # Fix clnt.c to skip re-encoding an RPC call in the case when # we're writing over TCP and have done a partial send. # -------------------------------------------- # 03/03/27 neilb@cse.unsw.edu.au 1.977.35.14 # [PATCH] kNFSd: READ_BUF macro update # # Fix some misleading comments, and correct the test for requesting more # than one page. # -------------------------------------------- # 03/03/27 neilb@cse.unsw.edu.au 1.977.35.15 # [PATCH] kNFSd: fix WRITE decoding # # NFSv4 operations after WRITE are decoded into wr_vec[] pages, thus the # argp->pagelen can be non-zero at the end of decoding the WRITE # operation. # # This patch correctly sets argp->pagelen, and correctly advances argp->p # after the WRITE operation # -------------------------------------------- # 03/03/27 neilb@cse.unsw.edu.au 1.977.35.16 # [PATCH] kNFSd:fix read encoding # # encode_read: change 'len' variable from unsigned long to a long for # '(len > 0)' comparison. don't set up a tail iovec for zero length # reads. # -------------------------------------------- # 03/03/27 neilb@cse.unsw.edu.au 1.977.35.17 # [PATCH] kNFSd: Be more careful with readlock in exp_parent # # We currently hold a read_lock of dparent_lock # while calling exp_get_by_name on several ancestors # of a given dentry. However exp_get_by_name can # malloc(GFP_KERNEL), so that isn't a good idea. # # Now we only claim the lock while actually # stepping up the parent chain. # # This addresses bug 29 @ bugme.osdl.org # -------------------------------------------- # 03/03/27 neilb@cse.unsw.edu.au 1.977.35.18 # [PATCH] md: md/linear oops fix # # From: Daniel McNeil # # This fixes an oops caused by incorrect usage of sector_div() # in which_dev() in md/linear.c. It was dereferencing an non-existent # hash table entry. # -------------------------------------------- # 03/03/27 neilb@cse.unsw.edu.au 1.977.35.19 # [PATCH] md: Cleanup #define TEXT text ... printk(TEXT) # # Also reformat some printks so lines don't exceed 80chars. # # Thanks to Angus Sawyer # -------------------------------------------- # 03/03/27 neilb@cse.unsw.edu.au 1.977.35.20 # [PATCH] md: Convert md personalities to new module interface # # Thanks to Angus Sawyer and # Daniel McNeil # -------------------------------------------- # 03/03/27 torvalds@penguin.transmeta.com 1.977.34.8 # Merge http://nfsclient.bkbits.net/linux-2.5 # into penguin.transmeta.com:/home/penguin/torvalds/repositories/kernel/linux # -------------------------------------------- # 03/03/27 davem@nuts.ninka.net 1.977.36.1 # [USB]: In ohci-pci.c, use size_t printf format. # -------------------------------------------- # 03/03/27 davem@nuts.ninka.net 1.977.36.2 # [SPARC64]: Fix pcibios_resource_to_bus and the build for this platform. # -------------------------------------------- # 03/03/27 torvalds@penguin.transmeta.com 1.992 # Merge bk://ppc.bkbits.net/for-linus-ppc # into penguin.transmeta.com:/home/penguin/torvalds/repositories/kernel/linux # -------------------------------------------- # 03/03/27 davem@nuts.ninka.net 1.977.36.3 # [SPARC64]: Implement dump stack and handle dumping currents stack properly. # -------------------------------------------- # 03/03/27 davem@nuts.ninka.net 1.977.36.4 # [SPARC64]: Use GFP_ATOMIC in request_irq. # -------------------------------------------- # 03/03/27 mochel@osdl.org 1.977.27.8 # sysfs: Fix file removal # # Turns out we do need to do d_delete() on individual files (and symlinks) # when removing them the tree, to make sure they actually get removed from # the hierarchy. # -------------------------------------------- # 03/03/27 mochel@osdl.org 1.977.37.1 # Merge bk://linux.bkbits.net/linux-2.5 # into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-virgin # -------------------------------------------- # 03/03/27 mochel@osdl.org 1.977.27.9 # Merge osdl.org:/home/mochel/src/kernel/devel/linux-2.5-virgin # into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-core # -------------------------------------------- # 03/03/27 cminyard@mvista.com 1.977.34.9 # [PATCH] fix ipmi_devintf.c compilation # # This fixes ipmi compilation (with some documentation updates and another # minor fix, too). # # It also fixes a problem with the state machine getting stuck in a # certain error condition. # -------------------------------------------- # 03/03/27 ldm.adm@hostme.bitkeeper.com 1.977.38.1 # Merge hostme.bitkeeper.com:/ua/repos/l/ldm/linux-2.5 # into hostme.bitkeeper.com:/ua/repos/l/ldm/linux-2.5-core # -------------------------------------------- # 03/03/27 mochel@osdl.org 1.977.27.10 # Merge bk://ldm@bkbits.net/linux-2.5-core # into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-core # -------------------------------------------- # 03/03/28 linux@de.rmk.(none) 1.977.32.6 # [PCMCIA] fix pcmcia_bind_driver # # Don't allow "bind_request" to be called before "register_pccard_driver". # -------------------------------------------- # 03/03/28 linux@de.rmk.(none) 1.977.32.7 # [PCMCIA] fix compilation with PCMCIA_DEBUG on # -------------------------------------------- # 03/03/27 torvalds@home.transmeta.com 1.993 # Merge penguin:v2.5/linux # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/03/27 torvalds@home.transmeta.com 1.994 # Merge bk://bk.arm.linux.org.uk/linux-2.5-pcmcia # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/03/28 hch@lst.de 1.977.23.11 # [PATCH] aha152x pcmcia updates # # (1) use new pcmcia_register_driver() & co API # (2) use scsi_add_host & co. This needed some restructuring in aha152x.c # (3) add a bunch of missing statics to aha152x.c # (4) move prototypes for functions used by aha152x_stub.c to aha152x.h # -------------------------------------------- # 03/03/28 agrover@groveronline.com 1.995 # Merge groveronline.com:/root/bk/linux-2.5 # into groveronline.com:/root/bk/linux-acpi # -------------------------------------------- # 03/03/28 agrover@groveronline.com 1.996 # ACPI: Interpreter update to 20030328 # - Add APIs to add and remove GPE Block devices # - Clean up problems with semaphore acquisition from the ISR # -------------------------------------------- # 03/03/28 linux@de.rmk.(none) 1.994.1.1 # [PCMCIA] generic suspend/resume capability # # The socket drivers already offer suspend and resume # capability. Integrate this with the driver model, based on a # suggestion by Russell King. # # Also, remove two never-used functions from the socket drivers (to_ns). # # drivers/pcmcia/cs.c | 70 ++++++++++++++++++++-------------------- # drivers/pcmcia/cs_internal.h | 1 # drivers/pcmcia/hd64465_ss.c | 2 + # drivers/pcmcia/i82092.c | 17 ++++++--- # drivers/pcmcia/i82365.c | 2 + # drivers/pcmcia/pci_socket.c | 15 +------- # drivers/pcmcia/sa1100_generic.c | 2 + # drivers/pcmcia/sa1111_generic.c | 14 +------- # drivers/pcmcia/tcic.c | 7 +--- # include/pcmcia/ss.h | 5 ++ # 10 files changed, 64 insertions(+), 71 deletions(-) # -------------------------------------------- # 03/03/28 linux@de.rmk.(none) 1.994.1.2 # [PCMCIA] don't inform "driver services" of cardbus-related events # -------------------------------------------- # 03/03/29 hch@de.rmk.(none) 1.994.1.3 # [SERIAL] switch over 8250_cs to pcmcia_register_driver # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.1 # [PATCH] initcall debug code # # The patch is designed to help locate where the kernel is dying during the # startup sequence. # # - Boot parameter "initcall_debug" causes the kernel to print out the # address of each initcall before calling it. # # The kallsyms tables do not cover __init sections, so printing the # symbolic version of these symbols doesn't work. They need to be looked up # in System.map. # # - Detect whether an initcall returns with interrupts disabled or with a # locking imbalance. If it does, complain and then try to fix it up. # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.2 # [PATCH] POSIX timers interface long/int cleanup # # From: Eric Piel # # Fixes some long/int confusion on 64-bit machines which was causing failures # on ia64 - we end up trying to set bits in the 32-63 range on an int and the # kernel locks up. # # Also cleans up idr.h. # # George has acked this change. # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.3 # [PATCH] slab: fix off-by-one in size calculation # # From: Manfred Spraul # # Brian spotted a stupid bug in the slab initialization: # # If multiple objects fit into one cacheline, then the allocator ignores # SLAB_HWCACHE_ALIGN and squeezes the objects into the same cacheline. The # implementation contains an off by one error and thus doesn't work correctly: # For Athlon optimized kernels, the 32-byte slab uses 64 byte of memory. # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.4 # [PATCH] add flush_cache_page() to install_page() # # install_page() needs to run flush_cache_page() prior to overwriting an # already-established pte. # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.5 # [PATCH] posix timers: fix double-reporting of timer expiration # # From: george anzinger # # Timer expirations are being reported twice. # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.6 # [PATCH] remove SWAP_ERROR # # From: Hugh Dickins # # Delete unused SWAP_ERROR and non-existent page_over_rsslimit(). # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.7 # [PATCH] permit page unmapping if !CONFIG_SWAP # # From: Hugh Dickins # # Raised #endif CONFIG_SWAP in shrink_list, it was excluding # try_to_unmap of file pages. Suspect !CONFIG_MMU relied on # that to suppress try_to_unmap, added SWAP_FAIL stub for it. # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.8 # [PATCH] make add_to_swap_cache() static # # From: Hugh Dickins # # Make add_to_swap_cache static, it's only used by read_swap_cache_async; # and since that has just done a GFP_HIGHUSER allocation, surely it's # better for add_to_swap_cache to use GFP_KERNEL than GFP_ATOMIC. # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.9 # [PATCH] tmpfs truncation fix # # From: Hugh Dickins # # Recent testing has shown that swapoff can sneak a page back into the # tmpfs page cache after truncate_inode_pages has cleaned it, before # shmem_truncate resets next_index to stop that: BUG_ON(inode->i_blocks) # in shmem_delete_inode. So call truncate_inode_pages again to be safe. # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.10 # [PATCH] handle oom in tmpfs # # From: Hugh Dickins # # move_from_swap_cache and add_to_page_cache_lru are using GFP_ATOMIC, # which can easily fail in an intermittent way. Rude if shmem_getpage # then fails with -ENOMEM: use blk_congestion_wait() to let kswapd in, # and repeat. # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.11 # [PATCH] remove vm_enough_memory double counting # # From: Hugh Dickins # # Stop vm_enough_memory double counting total_swapcache_pages: it dates # from the days when we didn't free swap when freeing swapcache page. # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.12 # [PATCH] ext3: fix max file size # # ext3 is only permitting files of up to 32G. It should be allowing files to # be up to 2TB. # # This is because it is running ext3_max_size(1024) before the filesystem's # blocksize has been determined. # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.13 # [PATCH] wait_on_buffer refcounting checks # # It is generally illegal to wait on an unpinned buffer - another CPU could # free it up even before __wait_on_buffer() has taken a ref against the buffer. # # Maybe external locking rules will prevent this in specific cases, but that is # really subtle and fragile as locking rules are evolved. # # The patch detects people calling wait_on_buffer() against an unpinned buffer # and issues a diagnostic. # # Also remove the get_bh() from __wait_on_buffer(). It is too late. # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.14 # [PATCH] x86 clock override boot option # # From: john stultz # # This patch allows one to manually specify the i386 gettimeofday time-source # by passing clock=[pit|tsc|cyclone|...] as a boot argument. The argument will # override the default probled selection, and in case the selected time-source # not be avalible the code defaults to using the PIT (printing a warning saying # so). # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.15 # [PATCH] fix to support discontigmem for 16way x440 # # From: Patricia Gaughen # # The boot-time ioermap code needs to invalidate the tlb entries after setting # up the new pte. # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.16 # [PATCH] tty_io cleanup # # From: Andries.Brouwer@cwi.nl # # Adding the unregister_chrdev_region call that is the counterpart to # register_chrdev_region, we get a nice cleanup of tty_io.c. # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.17 # [PATCH] speed up ext3_sync_file() # # There is never a need to write out b_assoc_buffers() in ext3_sync_file(). # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.18 # [PATCH] add a might_sleep() check to kmap() # # kmap() can sleep, but rarely does. Add a check for kmap() being called from # inappropriate contexts. # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.19 # [PATCH] ext3: remove dead code and variables # # Spotted by Oleg Drokin: remove a couple of local variables which aren't being # used for anything. # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.20 # [PATCH] use page_to_pfn() in __blk_queue_bounce() # # From: William Lee Irwin III # # __blk_queue_bounce() contains an open-coded page_to_pfn() for the # discontig, non-MAP_NR_DENSE() case (wherever MAP_NR_DENSE() went). # This converts it to use the standard page_to_pfn() abstraction. # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.21 # [PATCH] init_inode_once() wants sizeof(struct hlist_head) # # From: William Lee Irwin III # # inode_init() wants to deal with things in in units of the size of # struct hlist_head, not struct list_head. # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.22 # [PATCH] honour VM_DONTEXPAND in vma merging # # From: Gerd Knorr # # 2.5.x kernels don't look at the VM_DONTEXPAND flag when merging multiple vmas # into one. # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.23 # [PATCH] Fix 64bit warnings in mm/page_alloc.c # # From: Andi Kleen # # Fix a warning on x86_64 (and presumably ia64) which arises from casting an # int to a pointer. # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.24 # [PATCH] make cdevname() callable from interrupts # # We just made bdevname() irq-safe. This patch makes cdevname() callable from # interrupts as well. # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.25 # [PATCH] register_chrdev_region() leak and race fix # # - If two CPUs run register_chrdev_region(major == 0) at the same time they # can get the same major. # # Fix that by extending the lock coverage. # # - local variable `cd' was leaky on an error path. # # - Add some API commentary. # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.26 # [PATCH] slab: cache sizes cleanup # # From: Brian Gerst # # - Reduce code duplication by putting the kmalloc cache sizes into a header # file. # # - Tidy up kmem_cache_sizes_init(). # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.27 # [PATCH] sync blockdevs on the final close only # # From: davej@codemonkey.org.uk # # We currently run sync_blockdev() on every close of a blockdev. This patch # arranges for the sync to happen only on the final close. # -------------------------------------------- # 03/03/28 akpm@digeo.com 1.994.2.28 # [PATCH] Remove unused variable in nfs_readpage_result() # # Remove unused local `fattr' in nfs_readpage_result(). # -------------------------------------------- # 03/03/28 bwindle@fint.org 1.994.2.29 # [tulip] remove unnecessary linux/version.h includes # -------------------------------------------- # 03/03/29 davej@codemonkey.org.uk 1.994.2.30 # [tulip dmfe] add pci id # -------------------------------------------- # 03/03/29 fubar@us.ibm.com 1.994.2.31 # [bonding] bug fixes, and a few minor feature additions # # Mainly sync w/ 2.4.x version. # -------------------------------------------- # 03/03/29 bunk@fs.tum.de 1.994.2.32 # [PATCH] fix .text.exit error in drivers/net/r8169.c # # In drivers/net/r8169.c the function rtl8169_remove_one is __devexit but # the pointer to it didn't use __devexit_p resulting in a.text.exit # compile error when !CONFIG_HOTPLUG. # # The fix is simple: # -------------------------------------------- # 03/03/29 davej@codemonkey.org.uk 1.994.2.33 # [PATCH] finish init_etherdev conversion for gt96100eth # # - No need to alloc dev->priv (due to init_etherdev usage) # - No need to kfree dev->priv (kfree'd with (dev) already) # -------------------------------------------- # 03/03/29 paulus@samba.org 1.994.2.34 # [PATCH] MACE ethernet driver update # # This patch updates the MACE ethernet driver, used on older powermacs, # to remove the uses of save_flags/restore_flags/cli/sti and use a # spinlock instead. # # Jeff, please send this on to Linus. # # Paul. # -------------------------------------------- # 03/03/29 mbligh@aracnet.com 1.994.2.35 # [PATCH] remove warning for 3c509.c # # Get this compile warning: # drivers/net/3c509.c:207: warning: `el3_device_remove' declared `static' but never defined # because the function definition is under # "#if defined(CONFIG_EISA) || defined(CONFIG_MCA)". # # This patch puts the declaration under the same conditions. # I'd be shocked if it wasn't correct ;-) # # M. # -------------------------------------------- # 03/03/28 davem@nuts.ninka.net 1.977.36.5 # [SPARC64]: Fix interrupt enabling on trap return. # -------------------------------------------- # 03/03/29 davem@nuts.ninka.net 1.994.3.1 # Merge nuts.ninka.net:/home/davem/src/BK/sparcwork-2.5 # into nuts.ninka.net:/home/davem/src/BK/sparc-2.5 # -------------------------------------------- # 03/03/29 davem@nuts.ninka.net 1.994.3.2 # [SPARC64]: Update defconfig. # -------------------------------------------- # 03/03/29 jmorris@intercode.com.au 1.977.30.12 # [CRYPTO]: Add Deflate algorithm to crypto API. # -------------------------------------------- # 03/03/29 davem@nuts.ninka.net 1.994.3.3 # [SPARC64]: Implement pcibios_bus_to_resource. # -------------------------------------------- # 03/03/29 toml@us.ibm.com 1.977.30.13 # [IPSEC]: Missing ipv6 policy checks. # -------------------------------------------- # 03/03/29 toml@us.ibm.com 1.977.30.14 # [IPSEC]: IPV6 AH/ESP fixes. # -------------------------------------------- # 03/03/29 jt@bougret.hpl.hp.com 1.994.4.1 # [PATCH] : Discovery locking fixes # # o [CRITICA] Fix remaining locking problem with discovery log # o [CRITICA] Don't call expiry callback under spinlock # o [FEATURE] Simplify/cleanup/optimise discovery/expiry code # -------------------------------------------- # 03/03/29 jt@bougret.hpl.hp.com 1.994.4.2 # [PATCH] : IrLAP dynamic window code fix # # o [FEATURE] Fix the dynamic window code to properly send the pf bit. # Increase perf by 40% for large packets at SIR. # -------------------------------------------- # 03/03/29 jt@bougret.hpl.hp.com 1.994.4.3 # [PATCH] : irda-usb Rx path cleanup + no clear_halt # # o [CORRECT] Don't do usb_clear_halt() on USB control pipe # o [FEATURE] Cleanup and simplify the USB Rx path # -------------------------------------------- # 03/03/29 jt@bougret.hpl.hp.com 1.994.4.4 # [PATCH] : irtty-sir ZeroCopy Rx # # o [FEATURE] Enable ZeroCopy Rx in irtty-sir/sir-dev # (provided by the new SIR wrapper in 2.5.61). # -------------------------------------------- # 03/03/29 jt@bougret.hpl.hp.com 1.994.4.5 # [PATCH] : IrDA timer fix # # o [FEATURE] Make IrDA timers use mod_timer instead of # add+del_timer # -------------------------------------------- # 03/03/29 jt@bougret.hpl.hp.com 1.994.4.6 # [PATCH] : IrNET module fix # # o [CORRECT] Fix module refcounting (MOD_INC/DEC => .owner) # o [FEATURE] Add hints to discovery (control channel) # -------------------------------------------- # 03/03/29 jgarzik@redhat.com 1.994.5.1 # [hw_random] add AMD pci id # # Contributed by Andi Kleen # -------------------------------------------- # 03/03/29 torvalds@home.transmeta.com 1.994.2.36 # Merge bk://kernel.bkbits.net/jgarzik/irda-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/03/29 torvalds@home.transmeta.com 1.994.2.37 # Merge bk://kernel.bkbits.net/jgarzik/misc-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/03/29 torvalds@home.transmeta.com 1.994.2.38 # Merge bk://ldm.bkbits.net/linux-2.5-core # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/03/30 linux@de.rmk.(none) 1.994.1.4 # [PCMCIA] Fix "Removing wireless card triggers might_sleep warnings." # # Bug 516. # # Use schedule_delayed_work instead of a timer should fix this. Thanks # to Andrew Morton and Russell King. # # (Added flush_scheduled_work() to ensure our delayed work completes # before we free the pcmcia_bus_socket structure. --rmk) # -------------------------------------------- # 03/03/29 torvalds@home.transmeta.com 1.994.2.39 # Update direct-rendering to current DRI CVS tree. # # This adds support for i830 interrupt handling, and new improved # lock context keying. See per-file comments for more detail, as this # commit sadly mixes up a few different things (that's what you get # for not tracking the changes at a fine enough granularity). # -------------------------------------------- # 03/03/30 rmk@flint.arm.linux.org.uk 1.994.1.5 # [PCMCIA] Reorganise SA11xx PCMCIA support. # # The SA1100 PCMCIA structure didn't lend itself well to the device # model. With this reorganisation, we end up with a reasonable # structure which fits better with the driver model. It is now # obvious that SA11x0-based socket drivers are separate from # SA1111-based socket drivers, and are treated as two separate drivers # by the driver model. # -------------------------------------------- # 03/03/30 davem@nuts.ninka.net 1.977.30.15 # [NET]: Nuke CONFIG_FILTER. # -------------------------------------------- # 03/03/30 Andries.Brouwer@cwi.nl 1.994.2.40 # [PATCH] readlink in /proc w/ overlong path # # Trying to read the overlong target of a /proc/*/fd/N file descriptor # leads to a SIGSEGV inside the kernel, because the code doesn't check # for an error pointer return from d_path. # -------------------------------------------- # 03/03/30 torvalds@home.transmeta.com 1.994.1.6 # Merge bk://bk.arm.linux.org.uk/linux-2.5-pcmcia # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/03/31 davem@nuts.ninka.net 1.994.1.7 # Merge nuts.ninka.net:/home/davem/src/BK/network-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/03/31 randolph@tausq.org 1.994.1.8 # [COMPAT]: Fix sock_fprog handling. # -------------------------------------------- # 03/03/31 randolph@tausq.org 1.994.1.9 # [COMPAT]: Fix MSG_CMSG_COMPAT flag passing, kill cmsg_compat_recvmsg_fixup. # -------------------------------------------- # 03/03/31 hch@lst.de 1.994.1.10 # [IPV6]: Fix warning with modular ipv6. # -------------------------------------------- # 03/03/31 davem@nuts.ninka.net 1.994.6.1 # Merge nuts.ninka.net:/home/davem/src/BK/sparcwork-2.5 # into nuts.ninka.net:/home/davem/src/BK/sparc-2.5 # -------------------------------------------- # 03/03/31 davem@nuts.ninka.net 1.994.6.2 # [SPARC64]: Get ALI trident sound working again. # -------------------------------------------- # 03/03/31 davem@nuts.ninka.net 1.994.1.11 # [NET]: Use might_sleep in alloc_skb. # -------------------------------------------- # 03/03/31 laforge@netfilter.org 1.994.1.12 # [NETFILTER]: iptables iptable_mangle LOCAL_IN bugfix. # -------------------------------------------- # 03/03/31 laforge@netfilter.org 1.994.1.13 # [NETFILTER]: ipt_REJECT bugfix for TCP RST packets + asymm. routing. # -------------------------------------------- # 03/03/31 paulm@routefree.com 1.994.1.14 # [NETFILTER]: ip_conntrack bugfix for LOCAL_NAT and PPTP. # -------------------------------------------- # 03/03/31 acme@conectiva.com.br 1.994.7.1 # o af_ipx: code reformatting # # This just reformats the goto labels to a more accepted style. Now to # do some more reformatting after ages and then make it aware of the # new modules infrastructure, i.e. kill MOD_{INC,DEC}_USE_COUNT, then # rinse and repeat it with LLC, Appletalk, etc. # -------------------------------------------- # 03/03/31 torvalds@home.transmeta.com 1.994.1.15 # Merge bk://kernel.bkbits.net/davem/net-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/03/31 davem@redhat.com 1.994.1.16 # [PATCH] Check for disabled local interrupts in "might_sleep()" # # Self explanatory, as per the discussion last week. # -------------------------------------------- # 03/03/31 axboe@suse.de 1.994.1.17 # [PATCH] scsi queueing weirdness # # The queueing logic in scsi_lib looks really odd right now. # # - Defers calling elv_next_request() until we actually think we can queue # something. Always want to do that, request will have been marked # REQ_STARTED after this, so block layer cannot touch it or merge to it. # # - Kill the queue empty check. If elv_next_request() returned a req, # there's one to queue. # -------------------------------------------- # 03/03/31 davem@nuts.ninka.net 1.994.8.1 # Merge bk://kernel.bkbits.net/acme/net-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/03/31 toml@us.ibm.com 1.994.8.2 # [IPSEC]: Use "sizeof" for header sizes. # -------------------------------------------- # 03/03/31 davem@nuts.ninka.net 1.994.1.18 # Merge nuts.ninka.net:/home/davem/src/BK/network-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/03/31 yoshfuji@linux-ipv6.org 1.994.1.19 # [IPV6]: Don't allow multiple instances of the same IPv6 address on an interface. # -------------------------------------------- # 03/03/31 dougg@torque.net 1.977.23.12 # scsi_debug version 1.69 for lk 2.5.66 # # As people are using scsi_debug to simulate a large # number of disks to play with the dev_t expansion, # some problems have come to light. # # Changelog: # - change num_devs to num_tgts # so now the user can independently modify the # number of hosts (add_host), the number of targets # per host (num_tgts) and the number of luns per # target (max_luns) # - num_tgts sets scsi_host::max_id after allowance is # made for the initiator's target id # - max_luns default changed to 1 and it is sysfs # writeable # - REPORT LUN response cleaned up. Could now possibly # generate a response indicatimg there were up to # 16,384 logical units available # - clean up sense buffer generation # # Updated http://www.torque.net/sg/sdebug25.html # -------------------------------------------- # 03/03/31 bunk@fs.tum.de 1.994.1.20 # [ATM]: Fix IPHASE driver build. # -------------------------------------------- # 03/03/31 torvalds@penguin.transmeta.com 1.994.9.1 # Did you know that C integer constant promotions are different # depending on whether the constant is a hexadecimal one as # opposed to a decimal one? # # Let's make it all explicit. There are probably more lurking # around, these were found during development of my C checker tool. # -------------------------------------------- # 03/03/31 torvalds@penguin.transmeta.com 1.994.9.2 # Fix SMP/preemption race condition in vm86 entry mode. # -------------------------------------------- # 03/03/31 jejb@raven.il.steeleye.com 1.994.10.1 # Merge raven.il.steeleye.com:/home/jejb/BK/scsi-misc-2.5 # into raven.il.steeleye.com:/home/jejb/BK/scsi-for-linus-2.5 # -------------------------------------------- # 03/03/31 davem@nuts.ninka.net 1.994.11.1 # [SOFTIRQ]: Move softirq implementation to common area, add debug check. # 1) Every arch implemented local_bh_foo identically, move to # linux/interrupt.h # 2) Kill all asm/softirq.h references # 3) Kill asm/softirq.h itself # 4) Move local_bh_disable() out of line to kernel/softirq.c # 5) Add BUG check on irqs_disabled() to local_bh_disable() # -------------------------------------------- # 03/03/31 davem@nuts.ninka.net 1.994.11.2 # [SOFTIRQ]: interrupt.h needs preempt.h # -------------------------------------------- # 03/03/31 davem@nuts.ninka.net 1.994.11.3 # [SOFTIRQ]: Define local_softirq_pending, use it in softirq.c # # Platforms, such as IA64, have a per-cpu mapping for local cpu # data. When we killed off asm/softirq.h, we removed the usage # of local_softirq_pending IA64 was using. By defining a generic # version we can put the optimization back. # -------------------------------------------- # 03/03/31 greg@kroah.com 1.977.29.3 # [PATCH] i2c: fix memleak caused by my last patch fo the adv7175.c driver # -------------------------------------------- # 03/03/31 mb@ozaba.mine.nu 1.994.1.21 # [NETFILTER]: Add tftp conntrack + NAT support. # -------------------------------------------- # 03/03/31 netfilter@interlinx.bc.ca 1.994.1.22 # [NETFILTER]: Add amanda conntrack + NAT support. # -------------------------------------------- # 03/03/31 davem@kernel.bkbits.net 1.994.1.23 # Merge davem@nuts.ninka.net:/home/davem/src/BK/net-2.5 # into kernel.bkbits.net:/home/davem/net-2.5 # -------------------------------------------- # 03/03/31 torvalds@home.transmeta.com 1.994.9.3 # Merge http://linux-scsi.bkbits.net/scsi-for-linus-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/04/01 greg@kroah.com 1.977.29.4 # [PATCH] i2c: change the way i2c creates the bus ids to actually be unique now. # # It also is much like the old naming scheme, to keep things consistent. # -------------------------------------------- # 03/04/01 torvalds@penguin.transmeta.com 1.994.12.1 # Fix another non-preempt-safe CPU# access in vm86.c # -------------------------------------------- # 03/04/01 torvalds@home.transmeta.com 1.994.9.4 # Merge penguin:v2.5/linux # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.5 # [PATCH] remove outdated fs/ChangeLog # # From: Adrian Bunk # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.6 # [PATCH] include/asm-i386/dma.h: wrong lowest DMA channel # # From: Uros Bizjak # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.7 # [PATCH] fix linewrap in Documentation/filesystems/befs.txt # # From: ookhoi@humilis.net # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.8 # [PATCH] [PATCH 2.5.63] pty tty_driver add .owner field remove MOD_INC_DEC_USE_COUNT # # From: Hanna Linder # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.9 # [PATCH] rio_linux.c misc_register patch # # From: Chris Wilson # # This function did check misc_register's return code, but made no effort to # clean up if it failed, leaving a large amount of potential crud lying # around. I moved the registration to the start of the function, so that the # cleanup is trivial, and made sure the device gets unregistered in the # cases where it would not have been registered at all before. # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.10 # [PATCH] fix wrong module documentation # # From: Jochen Hein # # This cannot be a module. Remove module-related help # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.11 # [PATCH] Fix use of const with __initdata in znet.c # # From: Pablo Menichini # # initdata can't be const # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.12 # [PATCH] Kill unnecessary bootup messages # # From: Pavel Machek # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.13 # [PATCH] Fix use of const with __initdata in vfb.c # # From: Pablo Menichini # # Unused piece of fluff. Remove it. # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.14 # [PATCH] fix linewrap in Documentation_swsusp.txt # # From: sander@humilis.net # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.15 # [PATCH] remove KERNEL_VER from ftape.h # # From: Adrian Bunk # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.16 # [PATCH] fix linewrap in Documentation/filesystems/sysv-fs.txt # # From: ookhoi@humilis.net # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.17 # [PATCH] fix linewrap in Documentation/pci.txt # # From: ookhoi@humilis.net # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.18 # [PATCH] fix linewrap in Documentation/ia64/efirtc.txt # # From: ookhoi@humilis.net # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.19 # [PATCH] fix linewrap in Documentation/filesystems/cifs.txt # # From: ookhoi@humilis.net # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.20 # [PATCH] tty_driver add .owner field remove MOD_INC_DEC_USE_COUNT # # From: Hanna Linder # # Here are the changes for s390 to set .owner for tty_drivers # and remove MOD_INC/DEC_USE_COUNT. Martin has already approved # this. # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.21 # [PATCH] fix linewrap in Documentation/power/pci.txt # # From: ookhoi@humilis.net # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.22 # [PATCH] Explanation of sleep levels for swsusp # # From: Pavel Machek # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.23 # [PATCH] Change "char *version" to "char version[]" # # From: Pablo Menichini # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.24 # [PATCH] [PATCH 2.5.59] Change __initdata to __initdata_or_module # # From: Pablo Menichini # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.25 # [PATCH] remove unreachable code (and comments) in fs/befs/linuxvfs.c # # From: Will Dyson # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.26 # [PATCH] vt tty_driver add .owner field # # From: Hanna Linder # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.27 # [PATCH] eisa_eeprom.c misc_register patch # # From: Chris Wilson # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.28 # [PATCH] tty_io tty_driver add .owner field # # From: Hanna Linder # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.29 # [PATCH] Trivial documentation fix. # # From: Ryan Bradetich # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.30 # [PATCH] drivers_media_video_saa7111.c cleanup # # From: Frank Davis # # This patch makes us of a new predefined macro, instead of having the code # directly in the driver. # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.31 # [PATCH] net_pcnet32.c remove check_region # # From: Marcus Alanen # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.32 # [PATCH] fix the static compilation of mxser.c # # From: Adrian Bunk # # initcall was renamed and made module_init() # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.33 # [PATCH] 2.5.60 i386_mm_init.c comment cleanup # # From: Paul Gortmaker # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.34 # [PATCH] Remove compile warning from fs/ncpfs/inode.c # # From: Bob Miller # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.9.35 # [PATCH] Fix use of const with __initdata # # From: Pablo Menichini # # initdata can't be const # -------------------------------------------- # 03/04/01 torvalds@home.transmeta.com 1.994.9.36 # Merge bk://kernel.bkbits.net/davem/softirq-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/04/01 torvalds@home.transmeta.com 1.994.1.24 # Merge bk://kernel.bkbits.net/davem/net-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.1.25 # [PATCH] module_text_address returns the module pointer # # By making module_text_address return the module it found, we # simplify symbol_put_addr significantly. # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.1.26 # [PATCH] Symbol list removal # # This removes the symbol list, and the concept of kernel symbol groups, # in favour of just iterating through the modules. Now all iteration is # within kernel/module.c, this is a fairly trivial cleanup. # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.1.27 # [PATCH] Extable list removal # # This removes the extable list, and the struct exception_table, in # favour of just iterating through the modules. Now all iteration is # within kernel/module.c, this is a fairly trivial cleanup. # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.1.28 # [PATCH] Subdivide PCI class for aliases # # The previous handling of PCI class masks was too primitive: the # class field is not "all or nothing" but has base class, subclass # and interface fields. This patch changes the alias form from: # pci:vNdNsvNsdNcN to pci:vNdNsvNsdNbcNscNiN. # -------------------------------------------- # 03/04/01 Andries.Brouwer@cwi.nl 1.994.1.29 # [PATCH] kill TIOCTTYGSTRUCT # # Only used for (dubious) debugging purposes, and exposes # internal kernel state. # -------------------------------------------- # 03/04/01 sfr@canb.auug.org.au 1.994.1.30 # [PATCH] stop even more macros for comverting compat pointers # # Just want to nip this in the bud :-) # -------------------------------------------- # 03/04/01 rusty@rustcorp.com.au 1.994.1.31 # [PATCH] Fix floppy.h # # CROSS_64KB won't work as advertised due to missing parenthesis. # # Pointed out by Joern Engel. # -------------------------------------------- # 03/04/01 jack@suse.cz 1.994.1.32 # [PATCH] Quota module licences # -------------------------------------------- # 03/04/01 paulus@samba.org 1.994.1.33 # [PATCH] update adb driver # # This updates the ADB (Apple desktop bus) driver used on macs and # powermacs. The main change, from Ben Herrenschmidt, is that handlers # are called without a lock held now. It also adds a way for userland to # obtain some information about individual ADB devices from the driver. # -------------------------------------------- # 03/04/01 paulus@samba.org 1.994.1.34 # [PATCH] update apm emulation for mac # # This updates the battery charge calculations for powerbooks. This is # Ben Herrenschmidt's work. # -------------------------------------------- # 03/04/01 paulus@samba.org 1.994.1.35 # [PATCH] add some more Apple PCI ids # # This adds the PCI ids for some of the newer Apple chips. # -------------------------------------------- # 03/04/01 neilb@cse.unsw.edu.au 1.994.1.36 # [PATCH] kNFSd: Verify exportability when updating export cache. # # The systemcall interface for adding exports checked that # the filesystem was exportable. The new interface doesn't... # # This patch splits this functionality into a separate function # which is called from both sites. # -------------------------------------------- # 03/04/01 randy.dunlap@verizon.net 1.994.1.37 # [PATCH] reduce stack usage in cdrom/optcd.c # # This changes/fixes the optcd.c stack reduction patch from last week. # # Alan and Jens objected to the kmalloc() in cdromread(), suggesting that # the read buffer should be allocated one time and held onto, so this # patch does that. # -------------------------------------------- # 03/04/01 torvalds@home.transmeta.com 1.997 # Merge http://linux-acpi.bkbits.net/linux-acpi # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/04/01 hch@lst.de 1.998 # [PATCH] remove kdevname() before someone starts using it again # -------------------------------------------- # 03/04/01 marijnk@gmx.co.uk 1.999 # [PATCH] fix for drivers/video/logo/Makefile # # The fb-logo *.c files are not deleted on a make clean; this patch fixes # this. # -------------------------------------------- # 03/04/01 davej@codemonkey.org.uk 1.1000 # [PATCH] Add new cache descriptors, as found on P4-M (Centrino) # -------------------------------------------- # 03/04/01 davej@codemonkey.org.uk 1.1001 # [PATCH] fix up newer x86 cpuinfo flags. # # According to Intel document 24161823.pdf[*] page 18, 'tm2' is misdefined. # Its bit 7 not, bit 8. Also add the missing 'EST' (Enhanced Speedstep Technology) # bit, and use the correct Intel terminology for the context ID bit. # # [*] http://www.intel.com/design/xeon/applnots/241618.htm # -------------------------------------------- # 03/04/01 levon@movementarian.org 1.1002 # [PATCH] module load notification # # This implements a simple notifier so oprofile can notice removed and # added modules properly # -------------------------------------------- # 03/04/01 stelian@popies.net 1.1003 # [PATCH] fix ec_read using wrong #define's in sonypi driver. # # Damn, a copy and paste error and nobody noticed until now. # # From Daniel K. # -------------------------------------------- # 03/04/01 sfr@canb.auug.org.au 1.1004 # [PATCH] more compat types # -------------------------------------------- # 03/04/01 torvalds@home.transmeta.com 1.1005 # Add missing header includes # -------------------------------------------- # 03/04/02 levon@movementarian.org 1.1006 # [PATCH] Convert APIC to driver model # # This is Mikael's version of Pavel's patch, fixed to let CONFIG_PM=n # compile. It works for me on my 2-way using oprofile. # -------------------------------------------- # 03/04/02 torvalds@home.transmeta.com 1.1007 # Fix naming confusion: number of symbol kallsyms is "num_kallsyms", # while number of symbols is "num_syms". It used to be "num_syms" and # "num_ksyms" respectively (ie the "k" was the wrong way around). # # The previous naming was not just confusing, it had caused one actual # bug (ie the normal symbol code had used "num_syms", which was wrong # in the old confusing naming scheme). # -------------------------------------------- # 03/04/02 greg@kroah.com 1.977.29.5 # i2c: convert lm75 chip driver to use sysfs files. # -------------------------------------------- # 03/04/02 greg@kroah.com 1.977.29.6 # i2c: convert adm1021 chip driver to use sysfs files. # # Note, some data is not converted and will not be displayed. # Someone with this hardware is going to have to finish the rest of # this conversion. # -------------------------------------------- # 03/04/02 greg@kroah.com 1.977.29.7 # i2c: remove sysctl and proc functions from via686a.c driver # # This still needs to be converted to use sysfs files, but due to # lack of hardware, I can not do this. This change is necessary as # the sysctl and proc interface is about to go away. # -------------------------------------------- # 03/04/02 greg@kroah.com 1.977.29.8 # i2c: remove proc and sysctl code from i2c-proc as it is no longer used. # -------------------------------------------- # 03/04/02 greg@kroah.com 1.977.29.9 # i2c: remove unused paramater in found_proc callback function. # # (the users of this function have already been changed in previous patches) # -------------------------------------------- # 03/04/02 greg@kroah.com 1.977.29.10 # i2c: move i2c-proc to i2c-sensor and clean up all usages of it. # -------------------------------------------- # 03/04/02 kai@tp1.ruhr-uni-bochum.de 1.1005.1.1 # USB: Add missing #include # -------------------------------------------- # 03/04/02 kai@tp1.ruhr-uni-bochum.de 1.1005.1.2 # modules: Fix exporting symbols from modules # # This patch fixes two issues: # o The CONFIG_MODVERSIONING=y case broke at compile time since some # functions were not updated with the latest module changes # o Exporting symbols from modules stopped working due to confusion of # mod->num_syms and mod->num_ksyms. Rename mod->num_ksyms to mod->num_syms, # which is more logical since the associated array is called ->syms, and # for the kallsyms member use "num_symtab", since the associated array is # ->symtab. # -------------------------------------------- # 03/04/02 kai@tp1.ruhr-uni-bochum.de 1.1005.1.3 # kbuild: Fix dependencies for generated .mod.o files # # For some reason which I cannot remember, we didn't use the automatic # dependency generation for the generated .mod.[co] files. However, we do # of course need dependency information for those, too, they need to be updated # when e.g. the kernel version number changes. # -------------------------------------------- # 03/04/02 greg@kroah.com 1.977.29.11 # i2c: remove all proc code from the i2c core, as it's no longer needed. # -------------------------------------------- # 03/04/02 azarah@gentoo.org 1.977.29.12 # [PATCH] i2c: w83781d i2c driver updated for 2.5.66-bk4 (with sysfs support, empty tree) # # This should have a working w83781d driver updated for 2.5.66-bk4. # Currently sysfs support is working, and are according to the spec # (sensors-sysfs) in the 'lm sensors sysfs file structure' thread. # Thus I used 'temp_input[1-3]', as there was not final decision # on having them temp_input[0-2] as well, for example. # -------------------------------------------- # 03/04/02 greg@kroah.com 1.977.29.13 # i2c: clean up previous w83781d patch due to changes I made to i2c core and build. # -------------------------------------------- # 03/04/02 greg@kroah.com 1.1008 # Merge kroah.com:/home/greg/linux/BK/bleed-2.5 # into kroah.com:/home/greg/linux/BK/i2c-2.5 # -------------------------------------------- # 03/04/02 greg@kroah.com 1.1009 # i2c: fix up broken drivers/i2c/busses build due to I2C_PROC now being gone. # -------------------------------------------- # 03/04/02 greg@kroah.com 1.1010 # i2c: remove old proc documentation and add sysfs file documentation # -------------------------------------------- # 03/04/02 kai@tp1.ruhr-uni-bochum.de 1.1007.1.1 # Hand merge # -------------------------------------------- # 03/04/02 torvalds@home.transmeta.com 1.1011 # Merge bk://kernel.bkbits.net/gregkh/linux/i2c-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # diff -Nru a/CREDITS b/CREDITS --- a/CREDITS Wed Apr 2 22:24:06 2003 +++ b/CREDITS Wed Apr 2 22:24:06 2003 @@ -1210,6 +1210,10 @@ S: Atlanta, Georgia 30332 S: USA +N: Brad Hards +E: bradh@frogmouth.net +D: Various USB bits, other minor patches + N: Angelo Haritsis E: ah@computer.org D: kernel patches (serial, watchdog) diff -Nru a/Documentation/IPMI.txt b/Documentation/IPMI.txt --- a/Documentation/IPMI.txt Wed Apr 2 22:24:04 2003 +++ b/Documentation/IPMI.txt Wed Apr 2 22:24:04 2003 @@ -5,6 +5,18 @@ +The Intelligent Platform Management Interface, or IPMI, is a +standard for controlling intelligent devices that monitor a system. +It provides for dynamic discovery of sensors in the system and the +ability to monitor the sensors and be informed when the sensor's +values change or go outside certain boundaries. It also has a +standardized database for field-replacable units (FRUs) and a watchdog +timer. + +To use this, you need an interface to an IPMI controller in your +system (called a Baseboard Management Controller, or BMC) and +management software that can use the IPMI system. + This document describes how to use the IPMI driver for Linux. If you are not familiar with IPMI itself, see the web site at http://www.intel.com/design/servers/ipmi/index.htm. IPMI is a big diff -Nru a/Documentation/driver-model/overview.txt b/Documentation/driver-model/overview.txt --- a/Documentation/driver-model/overview.txt Wed Apr 2 22:24:05 2003 +++ b/Documentation/driver-model/overview.txt Wed Apr 2 22:24:05 2003 @@ -90,7 +90,7 @@ Or by hand on the command line: -# mount -t sysfs sysfs /devices +# mount -t sysfs sysfs /sys Whenever a device is inserted into the tree, a directory is created for it. This directory may be populated at each layer of discovery - the global layer, diff -Nru a/Documentation/filesystems/befs.txt b/Documentation/filesystems/befs.txt --- a/Documentation/filesystems/befs.txt Wed Apr 2 22:24:05 2003 +++ b/Documentation/filesystems/befs.txt Wed Apr 2 22:24:05 2003 @@ -18,32 +18,35 @@ AUTHOR ===== Current maintainer: Will Dyson -Has been working on the code since Aug 13, 2001. See the changelog for details. +Has been working on the code since Aug 13, 2001. See the changelog for +details. Original Author: Makoto Kato -His orriginal code can still be found at: -Does anyone know of a more current email address for Makoto? He doesn't respond -to the address given above... +His orriginal code can still be found at: + +Does anyone know of a more current email address for Makoto? He doesn't +respond to the address given above... WHAT IS THIS DRIVER? ================== This module implements the native filesystem of BeOS -for the linux 2.4.1 and later kernels. Currently it is a read-only implementation. +for the linux 2.4.1 and later kernels. Currently it is a read-only +implementation. Which is it, BFS or BEFS? ================ Be, Inc said, "BeOS Filesystem is officially called BFS, not BeFS". -But Unixware Boot Filesystem is called bfs, too. And they are already in the -kernel. -Because of this nameing conflict, on Linux the BeOS filesystem is called befs. +But Unixware Boot Filesystem is called bfs, too. And they are already in +the kernel. Because of this nameing conflict, on Linux the BeOS +filesystem is called befs. HOW TO INSTALL ============== step 1. Install the BeFS patch into the source code tree of linux. Apply the patchfile to your kernel source tree. -Assuming that your kernel source is in /foo/bar/linux and the patchfile is called -patch-befs-xxx, you would do the following: +Assuming that your kernel source is in /foo/bar/linux and the patchfile +is called patch-befs-xxx, you would do the following: cd /foo/bar/linux patch -p1 < /path/to/patch-befs-xxx @@ -66,8 +69,9 @@ The BeFS module is not a standard part of the linux kernel, so you must first enable support for experimental code under the "Code maturity level" menu. -Then, under the "Filesystems" menu will be an option called "BeFS filesystem (experimental)", -or something like that. Enable that option (it is fine to make it a module). +Then, under the "Filesystems" menu will be an option called "BeFS +filesystem (experimental)", or something like that. Enable that option +(it is fine to make it a module). Save your kernel configuration and then build your kernel. diff -Nru a/Documentation/filesystems/cifs.txt b/Documentation/filesystems/cifs.txt --- a/Documentation/filesystems/cifs.txt Wed Apr 2 22:24:04 2003 +++ b/Documentation/filesystems/cifs.txt Wed Apr 2 22:24:04 2003 @@ -1,26 +1,33 @@ -This module, cifs, is a filesystem that implements the SMB/CIFS protocol, which is the -protocol used by Windows based operating systems (including Windows 2000 and its successors) -as well as Samba, OS/2 and many others operating systems and network file server appliances. -The Cifs VFS filesystem module is designed to work well with servers that implement the newer versions -(dialects) of the SMB/CIFS protocol such as Samba, the program written by Andrew Tridgell -that turns any Unix host into a file server for DOS or Windows clients, as well as Windows NT, -Windows 2000 and its successors. It is not designed to handle older smb servers well, those that -implement older versions of the dialect (such as OS/2 or Windows 95), for this purpose use smbfs. +This module, cifs, is a filesystem that implements the SMB/CIFS +protocol, which is the protocol used by Windows based operating systems +(including Windows 2000 and its successors) as well as Samba, OS/2 and +many others operating systems and network file server appliances. The +Cifs VFS filesystem module is designed to work well with servers that +implement the newer versions (dialects) of the SMB/CIFS protocol such as +Samba, the program written by Andrew Tridgell that turns any Unix host +into a file server for DOS or Windows clients, as well as Windows NT, +Windows 2000 and its successors. It is not designed to handle older smb +servers well, those that implement older versions of the dialect (such +as OS/2 or Windows 95), for this purpose use smbfs. -This module can support mounting without a mount helper program. The mount syntax is: - mount //server_ip_address/share_name /mnt -o user=username,password=your_password -where "username", "your_password" and "server_ip_address" and "share_name" should be replaced -with specific values (supplied by the user) e.g. - mount //9.53.216.16/public /mnt -o user=jsmith,password=openup +This module can support mounting without a mount helper program. The +mount syntax is: + mount //server_ip/share_name /mnt -o user=username,password=your_password -This cifs implementation is designed to handle network caching (safely) as well as to implement locking, -large file (64 bit access), distributed file system ("dfs") and other advanced protocol features. It -also implements the SNIA standard for Unix extensions to CIFS (when communicating with servers such as -Samba 2.2.3 or later which support it). +where "username", "your_password" and "server_ip" and "share_name" +should be replaced with specific values (supplied by the user) e.g. + mount //9.53.216.16/public /mnt -o user=jsmith,password=openup + +This cifs implementation is designed to handle network caching (safely) +as well as to implement locking, large file (64 bit access), distributed +file system ("dfs") and other advanced protocol features. It also +implements the SNIA standard for Unix extensions to CIFS (when +communicating with servers such as Samba 2.2.3 or later which support it). For more information contact sfrench@us.ibm.com -Cifs is an SMB client (or gateway). For more info on the SMB/CIFS protocol and Samba, including -documentation, please go to http://www.samba.org/ and then on to your nearest mirror. For more +Cifs is an SMB client (or gateway). For more info on the SMB/CIFS +protocol and Samba, including documentation, please go to +http://www.samba.org/ and then on to your nearest mirror. For more information about the cifs vfs, go to the project page at: http://us1.samba.org/samba/Linux_CIFS_client.html diff -Nru a/Documentation/filesystems/sysv-fs.txt b/Documentation/filesystems/sysv-fs.txt --- a/Documentation/filesystems/sysv-fs.txt Wed Apr 2 22:24:04 2003 +++ b/Documentation/filesystems/sysv-fs.txt Wed Apr 2 22:24:04 2003 @@ -23,8 +23,9 @@ - Only file systems with no filesystem name and no pack name are recognized. (See Coherent "man mkfs" for a description of these features.) - SystemV Release 2 FS: - The superblock is only searched in the blocks 9, 15, 18, which corresponds to the - beginning of track 1 on floppy disks. No support for this FS on hard disk yet. + The superblock is only searched in the blocks 9, 15, 18, which + corresponds to the beginning of track 1 on floppy disks. No support + for this FS on hard disk yet. Please report any bugs and suggestions to diff -Nru a/Documentation/i2c/proc-interface b/Documentation/i2c/proc-interface --- a/Documentation/i2c/proc-interface Wed Apr 2 22:24:06 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,53 +0,0 @@ -i2c-core is the core i2c module (surprise!) which offers general routines on -which other modules build. You will find that all i2c-related modules depend -on this module, so it will (need to) be loaded whenever another i2c-related -module is loaded. Seen from the outside, the most interesting is the /proc -interface. Note that there is no corresponding sysctl interface! - -/proc/bus/i2c -============= - -Whenever i2c-core is loaded, you will find a file /proc/bus/i2c, which lists -all currently registered I2C adapters. Each line contains exactly one -I2C adapter. Each line has the following format: "i2c-%d\t%9s\t%-32s't%-32s\n", -which works out to four columns separated by tabs. Note that the file -will be empty, if no adapters are registered at all. - -Adapters are numbered from 0 upwards. The first column contains the number -of the adapter, for example "i2c-4" for adapter 4. The name listed is also -the name of the /proc file which lists all devices attached to it, and -of the /dev file which corresponds to this adapter. - -The second column documents what kind of adapter this is. Some adapters -understand the full I2C protocol, others only a subset called SMBus, -and yet others are some kind of pseudo-adapters that do not understand -i2c at all. Possible values in here are "i2c", "smbus", "i2c/smbus" -and "dummy". Because the SMBus protocol can be fully emulated by i2c -adapters, if you see "i2c" here, SMBus is supported too. There may -be some future adapters which support both specific SMBus commands and -general I2C, and they will display "i2c/smbus". - -The third and fourth column are respectively the algorithm and adapter -name of this adapter. Each adapter is associated with an algorithm, -and several adapters can share the same algorithm. The combination of -algorithm name and adapter name should be unique for an adapter, but -you can't really count on that yet. - - -/proc/bus/i2c-* -=============== - -Each registered adapter gets its own file in /proc/bus/, which lists -the devices registered to the adapter. Each line in such a file contains -one registered device. Each line has the following format: -"%02x\t%-32s\t%-32s\n", which works out to three columns separated by -tabs. Note that this file can be empty, if no devices are found on -the adapter. - -The first column contains the (hexadecimal) address of the client. As -only 7-bit addresses are supported at this moment, two digits are -enough. - -The second and third column are respectively the client name and the -driver name of this client. Each client is associated with a driver, -and several clients can share the same driver. diff -Nru a/Documentation/i2c/sysfs-interface b/Documentation/i2c/sysfs-interface --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/i2c/sysfs-interface Wed Apr 2 22:24:08 2003 @@ -0,0 +1,177 @@ +Naming and data format standards for sysfs files +------------------------------------------------ + +The libsensors library offers an interface to the raw sensors data +through the sysfs interface. See libsensors documentation and source for +more further information. + +An alternative method that some programs use is to access the sysfs +files directly. This document briefly describes the standards that the +drivers follow, so that an application program can scan for entries and +access this data in a simple and consistent way. + +If you are developing a userspace application please send us feedback on +this standard. + +Note that motherboards vary widely in the connections to sensor chips. +There is no standard that ensures, for example, that the second +temperature sensor is connected to the CPU, or that the second fan is on +the CPU. Therefore, programs must provide a facility for the user to +label or bind /proc entries for display. Sensor chips often have unused +inputs that should be ignored by user programs. + +Each chip gets its own directory in the sysfs /sys/devices tree. To +find all sensor chips, it is easier to follow the symlinks from +/sys/i2c/devices/ + +All sysfs values are fixed point numbers. To get the true value of some +of the values, you should divide by the specified value. + +There is only one value per file, unlike the older /proc specification. + +Alarms are direct indications read from the chips. The drivers do NOT +make comparisons of readings to thresholds. This allows violations +between readings to be caught and alarmed. The exact definition of an +alarm (for example, whether a threshold must be met or must be exceeded +to cause an alarm) is chip-dependent. + + +------------------------------------------------------------------------- + +sysfs entries are as follows: + + +Entry Function +----- -------- +alarms Alarm bitmask. + Read only. + Integer representation of one to four bytes. + A '1' bit means an alarm. + Chips should be programmed for 'comparator' mode so that + the alarm will 'come back' after you read the register + if it is still valid. + Generally a direct representation of a chip's internal + alarm registers; there is no standard for the position + of individual bits. + Bits are defined in kernel/include/sensors.h. + +beep_enable Beep/interrupt enable + 0 to disable. + 1 to enable. + Read/Write + +beep_mask Bitmask for beep. + Same format as 'alarms' with the same bit locations. + Read only. + +curr_max[1-n] Current max value + Fixed point XXXXX, divide by 1000 to get Amps. + Read/Write. + +curr_min[1-n] Current min or hysteresis value. + Preferably a hysteresis value, reported as a absolute + current, NOT a delta from the max value. + Fixed point XXXXX, divide by 1000 to get Amps. + Read/Write. + +curr_input[1-n] Current input value + Fixed point XXXXX, divide by 1000 to get Amps. + Read only. + +fan_min[1-3] Fan minimum value + Integer value indicating RPM + Read/Write. + +fan_input[1-3] Fan input value. + Integer value indicating RPM + Read only. + +fan_div[1-3] Fan divisor. + Integers in powers of two (1,2,4,8,16,32,64,128). + Some chips only support values 1,2,4,8. + See doc/fan-divisors for details. + +in_min[0-8] Voltage min value. + Fixed point value in form XXXX. Divide by 1000 to get + Volts. + Read/Write + +in_max[0-8] Voltage max value. + Fixed point value in form XXXX. Divide by 1000 to get + Volts. + Read/Write + +in_input[0-8] Voltage input value. + Fixed point value in form XXXX. Divide by 1000 to get + Volts. + Read only + Actual voltage depends on the scaling resistors on the + motherboard, as recommended in the chip datasheet. + This varies by chip and by motherboard. + Because of this variation, values are generally NOT scaled + by the chip driver, and must be done by the application. + However, some drivers (notably lm87 and via686a) + do scale, with various degrees of success. + These drivers will output the actual voltage. + First two values are read/write and third is read only. + Typical usage: + in_*0 CPU #1 voltage (not scaled) + in_*1 CPU #1 voltage (not scaled) + in_*2 3.3V nominal (not scaled) + in_*3 5.0V nominal (scaled) + in_*4 12.0V nominal (scaled) + in_*5 -12.0V nominal (scaled) + in_*6 -5.0V nominal (scaled) + in_*7 varies + in_*8 varies + +pwm[1-3] Pulse width modulation fan control. + Integer 0 - 255 + Read/Write + 255 is max or 100%. + Corresponds to the fans 1-3. + +pwm_enable[1-3] pwm enable + not always present even if pwm* is. + 0 to turn off + 1 to turn on + Read/Write + +sensor[1-3] Sensor type selection. + Integers 1,2,3, or thermistor Beta value (3435) + Read/Write. + +temp_max[1-3] Temperature max value. + Fixed point value in form XXXXX and should be divided by + 1000 to get degrees Celsius. + Read/Write value. + +temp_min[1-3] Temperature min or hysteresis value. + Fixed point value in form XXXXX and should be divided by + 1000 to get degrees Celsius. This is preferably a + hysteresis value, reported as a absolute temperature, + NOT a delta from the max value. + Read/Write value. + +temp_input[1-3] Temperature input value. + Read only value. + + If there are multiple temperature sensors, temp_*1 is + generally the sensor inside the chip itself, generally + reported as "motherboard temperature". temp_*2 and + temp_*3 are generally sensors external to the chip + itself, for example the thermal diode inside the CPU or + a thermistor nearby. + +vid CPU core voltage. + Read only. + Fixed point value in form XXXX corresponding to CPU core + voltage as told to the sensor chip. Divide by 1000 to + get Volts. Not always correct. + +vrm Voltage Regulator Module version number. + Read only. + Two digit number (XX), first is major version, second is + minor version. + Affects the way the driver calculates the core voltage from + the vid pins. See doc/vid for details. diff -Nru a/Documentation/ia64/efirtc.txt b/Documentation/ia64/efirtc.txt --- a/Documentation/ia64/efirtc.txt Wed Apr 2 22:24:06 2003 +++ b/Documentation/ia64/efirtc.txt Wed Apr 2 22:24:06 2003 @@ -12,13 +12,13 @@ to get access to the Time Service offered by EFI version 0.92. EFI provides 4 calls one can make once the OS is booted: GetTime(), -SetTime(), GetWakeupTime(), SetWakeupTime() which are all supported by this driver. -We describe those calls as well the design of the driver in the following -sections. +SetTime(), GetWakeupTime(), SetWakeupTime() which are all supported by this +driver. We describe those calls as well the design of the driver in the +following sections. II/ Design Decisions -The original ideas was to provide a very simple driver to get access to, +The original ideas was to provide a very simple driver to get access to, at first, the time of day service. This is required in order to access, in a portable way, the CMOS clock. A program like /sbin/hwclock uses such a clock to initialize the system view of the time during boot. @@ -39,8 +39,8 @@ without necessarily impacting any of the user applications. The decoupling enables flexibility and permits writing wrapper code is ncase things change. -The driver exposes two interfaces, one via the device file and a set of ioctl()s. -The other is read-only via the /proc filesystem. +The driver exposes two interfaces, one via the device file and a set of +ioctl()s. The other is read-only via the /proc filesystem. As of today we don't offer a /proc/sys interface. diff -Nru a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt --- a/Documentation/kernel-parameters.txt Wed Apr 2 22:24:08 2003 +++ b/Documentation/kernel-parameters.txt Wed Apr 2 22:24:08 2003 @@ -207,6 +207,12 @@ chandev= [HW,NET] Generic channel device initialisation + clock= [BUGS=IA-32, HW] gettimeofday timesource override. + Forces specified timesource (if avaliable) to be used + when calculating gettimeofday(). If specicified timesource + is not avalible, it defaults to PIT. + Format: { pit | tsc | cyclone | ... } + cm206= [HW,CD] Format: { auto | [,][] } @@ -389,6 +395,10 @@ Format: Run specified binary instead of /sbin/init as init process. + + initcall_debug [KNL] Trace initcalls as they are executed. Useful + for working out where the kernel is dying during + startup. initrd= [BOOT] Specify the location of the initial ramdisk diff -Nru a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt --- a/Documentation/networking/bonding.txt Wed Apr 2 22:24:04 2003 +++ b/Documentation/networking/bonding.txt Wed Apr 2 22:24:04 2003 @@ -7,6 +7,7 @@ - Constantine Gavrilov - Chad N. Tindel - Janice Girouard + - Jay Vosburgh Note : ------ @@ -199,28 +200,42 @@ parameters be specified, otherwise serious network degradation will occur during link failures. +max_bonds + + Specifies the number of bonding devices to create for this + instance of the bonding driver. E.g., if max_bonds is 3, and + the bonding driver is not already loaded, then bond0, bond1 + and bond2 will be created. The default value is 1. + mode - Specifies one of four bonding policies. The default is round-robin. - Possible values are: - - 0 Round-robin policy: Transmit in a sequential order from the - first available slave through the last. This mode provides - load balancing and fault tolerance. - - 1 Active-backup policy: Only one slave in the bond is active. A - different slave becomes active if, and only if, the active slave - fails. The bond's MAC address is externally visible on only - one port (network adapter) to avoid confusing the switch. - This mode provides fault tolerance. - - - 2 XOR policy: Transmit based on [(source MAC address XOR'd with - destination MAC address) modula slave count]. This selects the - same slave for each destination MAC address. This mode provides - load balancing and fault tolerance. - 3 Broadcast policy: transmits everything on all slave interfaces. - This mode provides fault tolerance. + Specifies one of four bonding policies. The default is +round-robin (balance-rr). Possible values are (you can use either the +text or numeric option): + + balance-rr or 0 + Round-robin policy: Transmit in a sequential order + from the first available slave through the last. This + mode provides load balancing and fault tolerance. + + active-backup or 1 + Active-backup policy: Only one slave in the bond is + active. A different slave becomes active if, and only + if, the active slave fails. The bond's MAC address is + externally visible on only one port (network adapter) + to avoid confusing the switch. This mode provides + fault tolerance. + + balance-xor or 2 + XOR policy: Transmit based on [(source MAC address + XOR'd with destination MAC address) modula slave + count]. This selects the same slave for each + destination MAC address. This mode provides load + balancing and fault tolerance. + + broadcast or 3 + Broadcast policy: transmits everything on all slave + interfaces. This mode provides fault tolerance. miimon @@ -229,6 +244,27 @@ 100 is a good starting point. See High Availability section for additional information. The default value is 0. +use_carrier + + Specifies whether or not miimon should use MII or ETHTOOL + ioctls vs. netif_carrier_ok() to determine the link status. + The MII or ETHTOOL ioctls are less efficient and utilize a + deprecated calling sequence within the kernel. The + netif_carrier_ok() relies on the device driver to maintain its + state with netif_carrier_on/off; at this writing, most, but + not all, device drivers support this facility. + + If bonding insists that the link is up when it should not be, + it may be that your network device driver does not support + netif_carrier_on/off. This is because the default state for + netif_carrier is "carrier on." In this case, disabling + use_carrier will cause bonding to revert to the MII / ETHTOOL + ioctl method to determine the link state. + + A value of 1 enables the use of netif_carrier_ok(), a value of + 0 will use the deprecated MII / ETHTOOL ioctls. The default + value is 1. + downdelay Specifies the delay time in milli-seconds to disable a link after a @@ -277,14 +313,17 @@ multicast - Integer value for the mode of operation for multicast support. + Option specifying the mode of operation for multicast support. Possible values are: - 0 Disabled (no multicast support) + disabled or 0 + Disabled (no multicast support) - 1 Enabled on active slave only, useful in active-backup mode + active or 1 + Enabled on active slave only, useful in active-backup mode - 2 Enabled on all slaves, this is the default + all or 2 + Enabled on all slaves, this is the default Configuring Multiple Bonds @@ -321,7 +360,52 @@ alias bond0 bonding options bond0 arp_interval=60 arp_ip_target=192.168.0.100 +Potential Problems When Using ARP Monitor +========================================= + +1. Driver support +The ARP monitor relies on the network device driver to maintain two +statistics: the last receive time (dev->last_rx), and the last +transmit time (dev->trans_start). If the network device driver does +not update one or both of these, then the typical result will be that, +upon startup, all links in the bond will immediately be declared down, +and remain that way. A network monitoring tool (tcpdump, e.g.) will +show ARP requests and replies being sent and received on the bonding +device. + +The possible resolutions for this are to (a) fix the device driver, or +(b) discontinue the ARP monitor (using miimon as an alternative, for +example). + +2. Adventures in Routing + +When bonding is set up with the ARP monitor, it is important that the +slave devices not have routes that supercede routes of the master (or, +generally, not have routes at all). For example, suppose the bonding +device bond0 has two slaves, eth0 and eth1, and the routing table is +as follows: + +Kernel IP routing table +Destination Gateway Genmask Flags MSS Window irtt Iface +10.0.0.0 0.0.0.0 255.255.0.0 U 40 0 0 eth0 +10.0.0.0 0.0.0.0 255.255.0.0 U 40 0 0 eth1 +10.0.0.0 0.0.0.0 255.255.0.0 U 40 0 0 bond0 +127.0.0.0 0.0.0.0 255.0.0.0 U 40 0 0 lo + +In this case, the ARP monitor (and ARP itself) may become confused, +because ARP requests will be sent on one interface (bond0), but the +corresponding reply will arrive on a different interface (eth0). This +reply looks to ARP as an unsolicited ARP reply (because ARP matches +replies on an interface basis), and is discarded. This will likely +still update the receive/transmit times in the driver, but will lose +packets. + +The resolution here is simply to insure that slaves do not have routes +of their own, and if for some reason they must, those routes do not +supercede routes of their master. This should generally be the case, +but unusual configurations or errant manual or automatic static route +additions may cause trouble. Switch Configuration ==================== @@ -462,7 +546,7 @@ If not explicitly configured with ifconfig, the MAC address of the bonding device is taken from its first slave device. This MAC address is then passed to all following slaves and remains persistent (even if - the first slave is removed) until the bonding device is brought + the the first slave is removed) until the bonding device is brought down or reconfigured. If you wish to change the MAC address, you can set it with ifconfig: @@ -606,12 +690,16 @@ To use this mode, pass "mode=1" to the module at load time : + # modprobe bonding miimon=100 mode=active-backup + + or: + # modprobe bonding miimon=100 mode=1 Or, put in your /etc/modules.conf : alias bond0 bonding - options bond0 miimon=100 mode=1 + options bond0 miimon=100 mode=active-backup Example 1: Using multiple host and multiple switches to build a "no single point of failure" solution. @@ -698,7 +786,7 @@ Examples : # modprobe bonding miimon=100 mode=1 downdelay=2000 updelay=5000 - # modprobe bonding miimon=100 mode=0 downdelay=0 updelay=5000 + # modprobe bonding miimon=100 mode=balance-rr downdelay=0 updelay=5000 Promiscuous Sniffing notes diff -Nru a/Documentation/pci.txt b/Documentation/pci.txt --- a/Documentation/pci.txt Wed Apr 2 22:24:05 2003 +++ b/Documentation/pci.txt Wed Apr 2 22:24:05 2003 @@ -51,21 +51,24 @@ execution of pci_register_driver for already existing devices or later if a new device gets inserted) for all PCI devices which match the ID table and are not handled - by the other drivers yet. This function gets passed a pointer - to the pci_dev structure representing the device and also - which entry in the ID table did the device match. It returns - zero when the driver has accepted the device or an error - code (negative number) otherwise. This function always gets - called from process context, so it can sleep. - remove Pointer to a function which gets called whenever a device - being handled by this driver is removed (either during - deregistration of the driver or when it's manually pulled - out of a hot-pluggable slot). This function always gets - called from process context, so it can sleep. + by the other drivers yet. This function gets passed a + pointer to the pci_dev structure representing the device + and also which entry in the ID table did the device + match. It returns zero when the driver has accepted the + device or an error code (negative number) otherwise. + This function always gets called from process context, + so it can sleep. + remove Pointer to a function which gets called whenever a + device being handled by this driver is removed (either + during deregistration of the driver or when it's + manually pulled out of a hot-pluggable slot). This + function always gets called from process context, so it + can sleep. save_state Save a device's state before it's suspend. suspend Put device into low power state. resume Wake device from low power state. - enable_wake Enable device to generate wake events from a low power state. + enable_wake Enable device to generate wake events from a low power + state. (Please see Documentation/power/pci.txt for descriptions of PCI Power Management and the related functions) @@ -186,8 +189,9 @@ See Documentation/IO-mapping.txt for how to access device memory. - You still need to call request_region() for I/O regions and request_mem_region() -for memory regions to make sure nobody else is using the same device. + You still need to call request_region() for I/O regions and +request_mem_region() for memory regions to make sure nobody else is using the +same device. All interrupt handlers should be registered with SA_SHIRQ and use the devid to map IRQs to devices (remember that all PCI interrupts are shared). diff -Nru a/Documentation/power/pci.txt b/Documentation/power/pci.txt --- a/Documentation/power/pci.txt Wed Apr 2 22:24:07 2003 +++ b/Documentation/power/pci.txt Wed Apr 2 22:24:07 2003 @@ -22,7 +22,7 @@ power management operations. Implementation of the PCI PM Spec is optional, as are several sub-components of -it. If a device supports the PCI PM Spec, the device will have an 8 byte +it. If a device supports the PCI PM Spec, the device will have an 8 byte capability field in its PCI configuration space. This field is used to describe and control the standard PCI power management features. @@ -50,33 +50,35 @@ | D1, D2, D3 | D0 | +---------------------------+ -Note that when the system is entering a global suspend state, all devices will be -placed into D3 and when resuming, all devices will be placed into D0. However, -when the system is running, other state transitions are possible. +Note that when the system is entering a global suspend state, all devices will +be placed into D3 and when resuming, all devices will be placed into D0. +However, when the system is running, other state transitions are possible. 2. How The PCI Subsystem Handles Power Management ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The PCI suspend/resume functionality is accessed indirectly via the Power Management -subsystem. At boot, the PCI driver registers a power management callback with that layer. -Upon entering a suspend state, the PM layer iterates through all of its registered -callbacks. This currently takes place only during APM state transitions. - -Upon going to sleep, the PCI subsystem walks its device tree twice. Both times, it does -a depth first walk of the device tree. The first walk saves each of the device's state -and checks for devices that will prevent the system from entering a global power state. -The next walk then places the devices in a low power state. - -The first walk allows a graceful recovery in the event of a failure, since none of the -devices have actually been powered down. - -In both walks, in particular the second, all children of a bridge are touched before the -actual bridge itself. This allows the bridge to retain power while its children are being -accessed. - -Upon resuming from sleep, just the opposite must be true: all bridges must be powered on -and restored before their children are powered on. This is easily accomplished with a -breadth-first walk of the PCI device tree. +The PCI suspend/resume functionality is accessed indirectly via the Power +Management subsystem. At boot, the PCI driver registers a power management +callback with that layer. Upon entering a suspend state, the PM layer iterates +through all of its registered callbacks. This currently takes place only during +APM state transitions. + +Upon going to sleep, the PCI subsystem walks its device tree twice. Both times, +it does a depth first walk of the device tree. The first walk saves each of the +device's state and checks for devices that will prevent the system from entering +a global power state. The next walk then places the devices in a low power +state. + +The first walk allows a graceful recovery in the event of a failure, since none +of the devices have actually been powered down. + +In both walks, in particular the second, all children of a bridge are touched +before the actual bridge itself. This allows the bridge to retain power while +its children are being accessed. + +Upon resuming from sleep, just the opposite must be true: all bridges must be +powered on and restored before their children are powered on. This is easily +accomplished with a breadth-first walk of the PCI device tree. 3. PCI Utility Functions @@ -86,8 +88,8 @@ Assuming that a device behaves as advertised, these should be applicable in most cases. However, results may vary. -Note that these functions are never implicitly called for the driver. The driver is always -responsible for deciding when and if to call these. +Note that these functions are never implicitly called for the driver. The driver +is always responsible for deciding when and if to call these. pci_save_state @@ -97,7 +99,8 @@ pci_save_state(dev, buffer); Description: - Save first 64 bytes of PCI config space. Buffer must be allocated by caller. + Save first 64 bytes of PCI config space. Buffer must be allocated by + caller. pci_restore_state @@ -109,8 +112,8 @@ Description: Restore previously saved config space. (First 64 bytes only); - If buffer is NULL, then restore what information we know about the device - from bootup: BARs and interrupt line. + If buffer is NULL, then restore what information we know about the + device from bootup: BARs and interrupt line. pci_set_power_state @@ -120,7 +123,8 @@ pci_set_power_state(dev, state); Description: - Transition device to low power state using PCI PM Capabilities registers. + Transition device to low power state using PCI PM Capabilities + registers. Will fail under one of the following conditions: - If state is less than current state, but not D0 (illegal transition) @@ -138,14 +142,15 @@ Enable device to generate PME# during low power state using PCI PM Capabilities. - Checks whether if device supports generating PME# from requested state and fail - if it does not, unless enable == 0 (request is to disable wake events, which - is implicit if it doesn't even support it in the first place). - - Note that the PMC Register in the device's PM Capabilties has a bitmask of - the states it supports generating PME# from. D3hot is bit 3 and D3cold is bit - 4. So, while a value of 4 as the state may not seem semantically correct, it - is. + Checks whether if device supports generating PME# from requested state + and fail if it does not, unless enable == 0 (request is to disable wake + events, which is implicit if it doesn't even support it in the first + place). + + Note that the PMC Register in the device's PM Capabilties has a bitmask + of the states it supports generating PME# from. D3hot is bit 3 and + D3cold is bit 4. So, while a value of 4 as the state may not seem + semantically correct, it is. 4. PCI Device Drivers @@ -168,25 +173,26 @@ if (dev->driver && dev->driver->save_state) dev->driver->save_state(dev,state); -The driver should use this callback to save device state. It should take into -account the current state of the device and the requested state in order to avoid -any unnecessary operations. - -For example, a video card that supports all 4 states (D0-D3), all controller context -is preserved when entering D1, but the screen is placed into a low power state -(blanked). - -The driver can also interpret this function as a notification that it may be entering -a sleep state in the near future. If it knows that the device cannot enter the -requested state, either because of lack of support for it, or because the device is -middle of some critical operation, then it should fail. - -This function should not be used to set any state in the device or the driver because -the device may not actually enter the sleep state (e.g. another driver later causes -causes a global state transition to fail). - -Note that in intermediate low power states, a device's I/O and memory spaces may be -disabled and may not be available in subsequent transitions to lower power states. +The driver should use this callback to save device state. It should take into +account the current state of the device and the requested state in order to +avoid any unnecessary operations. + +For example, a video card that supports all 4 states (D0-D3), all controller +context is preserved when entering D1, but the screen is placed into a low power +state (blanked). + +The driver can also interpret this function as a notification that it may be +entering a sleep state in the near future. If it knows that the device cannot +enter the requested state, either because of lack of support for it, or because +the device is middle of some critical operation, then it should fail. + +This function should not be used to set any state in the device or the driver +because the device may not actually enter the sleep state (e.g. another driver +later causes causes a global state transition to fail). + +Note that in intermediate low power states, a device's I/O and memory spaces may +be disabled and may not be available in subsequent transitions to lower power +states. suspend @@ -197,27 +203,27 @@ if (dev->driver && dev->driver->suspend) dev->driver->suspend(dev,state); -A driver uses this function to actually transition the device into a low power -state. This may include disabling I/O, memory and bus-mastering, as well as physically -transitioning the device to a lower power state. +A driver uses this function to actually transition the device into a low power +state. This may include disabling I/O, memory and bus-mastering, as well as +physically transitioning the device to a lower power state. Bus mastering may be disabled by doing: pci_disable_device(dev); -For devices that support the PCI PM Spec, this may be used to set the device's power -state: +For devices that support the PCI PM Spec, this may be used to set the device's +power state: pci_set_power_state(dev,state); The driver is also responsible for disabling any other device-specific features (e.g blanking screen, turning off on-card memory, etc). -The driver should be sure to track the current state of the device, as it may obviate -the need for some operations. +The driver should be sure to track the current state of the device, as it may +obviate the need for some operations. -The driver should update the current_state field in its pci_dev structure in this -function. +The driver should update the current_state field in its pci_dev structure in +this function. resume ------ @@ -227,36 +233,37 @@ if (dev->driver && dev->driver->suspend) dev->driver->resume(dev) -The resume callback may be called from any power state, and is always meant to +The resume callback may be called from any power state, and is always meant to transition the device to the D0 state. -The driver is responsible for reenabling any features of the device that had -been disabled during previous suspend calls and restoring all state that was saved -in previous save_state calls. - -If the device is currently in D3, it must be completely reinitialized, as it must be -assumed that the device has lost all of its context (even that of its PCI config -space). For almost all current drivers, this means that the initialization code that -the driver does at boot must be separated out and called again from the resume -callback. Note that some values for the device may not have to be probed for this -time around if they are saved before entering the low power state. +The driver is responsible for reenabling any features of the device that had +been disabled during previous suspend calls and restoring all state that was +saved in previous save_state calls. + +If the device is currently in D3, it must be completely reinitialized, as it +must be assumed that the device has lost all of its context (even that of its +PCI config space). For almost all current drivers, this means that the +initialization code that the driver does at boot must be separated out and +called again from the resume callback. Note that some values for the device may +not have to be probed for this time around if they are saved before entering the +low power state. -If the device supports the PCI PM Spec, it can use this to physically transition the -device to D0: +If the device supports the PCI PM Spec, it can use this to physically transition +the device to D0: pci_set_power_state(dev,0); -Note that if the entire system is transitioning out of a global sleep state, all -devices will be placed in the D0 state, so this is not necessary. However, in the -event that the device is placed in the D3 state during normal operation, this call -is necessary. It is impossible to determine which of the two events is taking place -in the driver, so it is always a good idea to make that call. +Note that if the entire system is transitioning out of a global sleep state, all +devices will be placed in the D0 state, so this is not necessary. However, in +the event that the device is placed in the D3 state during normal operation, +this call is necessary. It is impossible to determine which of the two events is +taking place in the driver, so it is always a good idea to make that call. -The driver should take note of the state that it is resuming from in order to ensure -correct (and speedy) operation. +The driver should take note of the state that it is resuming from in order to +ensure correct (and speedy) operation. -The driver should update the current_state field in its pci_dev structure in this -function. +The driver should update the current_state field in its pci_dev structure in +this function. enable_wake diff -Nru a/Documentation/swsusp.txt b/Documentation/swsusp.txt --- a/Documentation/swsusp.txt Wed Apr 2 22:24:04 2003 +++ b/Documentation/swsusp.txt Wed Apr 2 22:24:04 2003 @@ -62,14 +62,14 @@ echo 4 > /proc/acpi/sleep. Either way it saves the state of the machine into active swaps and then -reboots. You must explicitly specify the swap partition to resume from with ``resume='' -kernel option. If signature is found it loads and restores saved state. If the -option ``noresume'' is specified as a boot parameter, it skips the resuming. -Warning! Look at section ``Things to implement'' to see what isn't yet -implemented. Also I strongly suggest you to list all active swaps in -/etc/fstab. Firstly because you don't have to specify anything to resume and -secondly if you have more than one swap area you can't decide which one has the -'root' signature. +reboots. You must explicitly specify the swap partition to resume from with +``resume='' kernel option. If signature is found it loads and restores saved +state. If the option ``noresume'' is specified as a boot parameter, it skips +the resuming. Warning! Look at section ``Things to implement'' to see what +isn't yet implemented. Also I strongly suggest you to list all active swaps +in /etc/fstab. Firstly because you don't have to specify anything to resume +and secondly if you have more than one swap area you can't decide which one +has the 'root' signature. In the meantime while the system is suspended you should not touch any of the hardware! @@ -110,10 +110,10 @@ pleasure. Check out my patch at the same location for the sysvinit patch. WARNINGS! -- It does not like pcmcia cards. And this is logical: pcmcia cards need cardmgr to be - initialized. they are not initialized during singleuser boot, but "resumed" kernel does - expect them to be initialized. That leads to armagedon. You should eject any pcmcia cards - before suspending. +- It does not like pcmcia cards. And this is logical: pcmcia cards need + cardmgr to be initialized. they are not initialized during singleuser boot, + but "resumed" kernel does expect them to be initialized. That leads to + armagedon. You should eject any pcmcia cards before suspending. Things to implement - SMP support. I've done an SMP support but since I don't have access to a kind @@ -155,6 +155,20 @@ - pc_keyb -- perhaps we can wait for vojtech's input patches - do IDE cdroms need some kind of support? - IDE CD-RW -- how to deal with that? + +Sleep states summary (thanx, Ducrot) +==================================== + +In a really perfect world: +echo 1 > /proc/acpi/sleep # for standby +echo 2 > /proc/acpi/sleep # for suspend to ram +echo 3 > /proc/acpi/sleep # for suspend to ram, but with more power conservative +echo 4 > /proc/acpi/sleep # for suspend to disk +echo 5 > /proc/acpi/sleep # for shutdown unfriendly the system + +and perhaps +echo 4b > /proc/acpi/sleep # for suspend to disk via s4bios + FAQ: diff -Nru a/MAINTAINERS b/MAINTAINERS --- a/MAINTAINERS Wed Apr 2 22:24:06 2003 +++ b/MAINTAINERS Wed Apr 2 22:24:06 2003 @@ -1869,11 +1869,12 @@ W: http://www.kroah.com/linux-usb/ USB CDC ETHERNET DRIVER -P: Brad Hards -M: bradh@frogmouth.net +P: Greg Kroah-Hartman +M: greg@kroah.com L: linux-usb-users@lists.sourceforge.net L: linux-usb-devel@lists.sourceforge.net S: Maintained +W: http://www.kroah.com/linux-usb/ USB EHCI DRIVER P: David Brownell diff -Nru a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c --- a/arch/alpha/kernel/alpha_ksyms.c Wed Apr 2 22:24:04 2003 +++ b/arch/alpha/kernel/alpha_ksyms.c Wed Apr 2 22:24:04 2003 @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff -Nru a/arch/alpha/kernel/err_titan.c b/arch/alpha/kernel/err_titan.c --- a/arch/alpha/kernel/err_titan.c Wed Apr 2 22:24:07 2003 +++ b/arch/alpha/kernel/err_titan.c Wed Apr 2 22:24:07 2003 @@ -22,8 +22,10 @@ static int titan_parse_c_misc(u64 c_misc, int print) { +#ifdef CONFIG_VERBOSE_MCHECK char *src; int nxs = 0; +#endif int status = MCHK_DISPOSITION_REPORT; #define TITAN__CCHIP_MISC__NXM (1UL << 28) @@ -263,11 +265,11 @@ static int titan_parse_p_agperror(int which, u64 agperror, int print) { + int status = MCHK_DISPOSITION_REPORT; +#ifdef CONFIG_VERBOSE_MCHECK int cmd, len; unsigned long addr; - int status = MCHK_DISPOSITION_REPORT; -#ifdef CONFIG_VERBOSE_MCHECK char *agperror_cmd[] = { "Read (low-priority)", "Read (high-priority)", "Write (low-priority)", "Write (high-priority)", @@ -575,14 +577,14 @@ static int privateer_process_680_frame(struct el_common *mchk_header, int print) { + int status = MCHK_DISPOSITION_UNKNOWN_ERROR; +#ifdef CONFIG_VERBOSE_MCHECK struct el_PRIVATEER_envdata_mcheck *emchk = (struct el_PRIVATEER_envdata_mcheck *) ((unsigned long)mchk_header + mchk_header->sys_offset); - int status = MCHK_DISPOSITION_UNKNOWN_ERROR; /* TODO - catagorize errors, for now, no error */ -#ifdef CONFIG_VERBOSE_MCHECK if (!print) return status; diff -Nru a/arch/alpha/kernel/module.c b/arch/alpha/kernel/module.c --- a/arch/alpha/kernel/module.c Wed Apr 2 22:24:04 2003 +++ b/arch/alpha/kernel/module.c Wed Apr 2 22:24:04 2003 @@ -199,7 +199,9 @@ case R_ALPHA_NONE: break; case R_ALPHA_REFQUAD: - *(u64 *)location = value; + /* BUG() can produce misaligned relocations. */ + ((u32 *)location)[0] = value; + ((u32 *)location)[1] = value >> 32; break; case R_ALPHA_GPREL32: value -= gp; diff -Nru a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c --- a/arch/alpha/kernel/pci.c Wed Apr 2 22:24:04 2003 +++ b/arch/alpha/kernel/pci.c Wed Apr 2 22:24:04 2003 @@ -285,7 +285,7 @@ pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); /* Move up the chain of bridges. */ dev = dev->bus->self; - } while (dev->bus->self); + } while (dev->bus->parent); *pinp = pin; /* The slot is the slot of the last bridge. */ @@ -410,10 +410,8 @@ if (pci_probe_only) pcibios_claim_console_setup(); - else /* FIXME: `else' will be removed when - pci_assign_unassigned_resources() is able to work - correctly with [partially] allocated PCI tree. */ - pci_assign_unassigned_resources(); + + pci_assign_unassigned_resources(); pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq); } diff -Nru a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c --- a/arch/alpha/kernel/smp.c Wed Apr 2 22:24:04 2003 +++ b/arch/alpha/kernel/smp.c Wed Apr 2 22:24:04 2003 @@ -35,7 +35,6 @@ #include #include #include -#include #include #include @@ -112,7 +111,7 @@ static void __init wait_boot_cpu_to_stop(int cpuid) { - long stop = jiffies + 10*HZ; + unsigned long stop = jiffies + 10*HZ; while (time_before(jiffies, stop)) { if (!smp_secondary_alive) @@ -349,7 +348,7 @@ { struct percpu_struct *cpu; struct pcb_struct *hwpcb, *ipcb; - long timeout; + unsigned long timeout; cpu = (struct percpu_struct *) ((char*)hwrpb @@ -428,7 +427,7 @@ smp_boot_one_cpu(int cpuid) { struct task_struct *idle; - long timeout; + unsigned long timeout; /* Cook up an idler for this guy. Note that the address we give to kernel_thread is irrelevant -- it's going to start @@ -816,7 +815,7 @@ int wait, unsigned long to_whom) { struct smp_call_struct data; - long timeout; + unsigned long timeout; int num_cpus_to_call; data.func = func; diff -Nru a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c --- a/arch/alpha/kernel/sys_nautilus.c Wed Apr 2 22:24:05 2003 +++ b/arch/alpha/kernel/sys_nautilus.c Wed Apr 2 22:24:05 2003 @@ -183,14 +183,17 @@ extern void free_reserved_mem(void *, void *); +static struct resource irongate_mem = { + .name = "Irongate PCI MEM", + .flags = IORESOURCE_MEM, +}; + void __init nautilus_init_pci(void) { struct pci_controller *hose = hose_head; struct pci_bus *bus; struct pci_dev *irongate; - unsigned long saved_io_start, saved_io_end; - unsigned long saved_mem_start, saved_mem_end; unsigned long bus_align, bus_size, pci_mem; unsigned long memtop = max_low_pfn << PAGE_SHIFT; @@ -199,50 +202,41 @@ hose->bus = bus; hose->last_busno = bus->subordinate; - /* We're going to size the root bus, so we must - - have a non-NULL PCI device associated with the bus - - preserve hose resources. */ irongate = pci_find_slot(0, 0); bus->self = irongate; - saved_io_start = bus->resource[0]->start; - saved_io_end = bus->resource[0]->end; - saved_mem_start = bus->resource[1]->start; - saved_mem_end = bus->resource[1]->end; + bus->resource[1] = &irongate_mem; pci_bus_size_bridges(bus); - /* Don't care about IO. */ - bus->resource[0]->start = saved_io_start; - bus->resource[0]->end = saved_io_end; + /* IO port range. */ + bus->resource[0]->start = 0; + bus->resource[0]->end = 0xffff; + /* Set up PCI memory range - limit is hardwired to 0xffffffff, + base must be at aligned to 16Mb. */ bus_align = bus->resource[1]->start; bus_size = bus->resource[1]->end + 1 - bus_align; - /* Align to 16Mb. */ if (bus_align < 0x1000000UL) bus_align = 0x1000000UL; - /* Restore hose MEM resource. */ - bus->resource[1]->start = saved_mem_start; - bus->resource[1]->end = saved_mem_end; - pci_mem = (0x100000000UL - bus_size) & -bus_align; + bus->resource[1]->start = pci_mem; + bus->resource[1]->end = 0xffffffffUL; + if (request_resource(&iomem_resource, bus->resource[1]) < 0) + printk(KERN_ERR "Failed to request MEM on hose 0\n"); + if (pci_mem < memtop && pci_mem > alpha_mv.min_mem_address) { free_reserved_mem(__va(alpha_mv.min_mem_address), __va(pci_mem)); - printk("nautilus_init_arch: %ldk freed\n", + printk("nautilus_init_pci: %ldk freed\n", (pci_mem - alpha_mv.min_mem_address) >> 10); } - alpha_mv.min_mem_address = pci_mem; if ((IRONGATE0->dev_vendor >> 16) > 0x7006) /* Albacore? */ IRONGATE0->pci_mem = pci_mem; pci_bus_assign_resources(bus); - - /* To break the loop in common_swizzle() */ - bus->self = NULL; - pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq); } diff -Nru a/arch/arm/kernel/apm.c b/arch/arm/kernel/apm.c --- a/arch/arm/kernel/apm.c Wed Apr 2 22:24:07 2003 +++ b/arch/arm/kernel/apm.c Wed Apr 2 22:24:07 2003 @@ -552,8 +552,6 @@ MODULE_DESCRIPTION("Advanced Power Management"); MODULE_LICENSE("GPL"); -EXPORT_NO_SYMBOLS; - #ifndef MODULE static int __init apm_setup(char *str) { diff -Nru a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c --- a/arch/arm/kernel/armksyms.c Wed Apr 2 22:24:05 2003 +++ b/arch/arm/kernel/armksyms.c Wed Apr 2 22:24:05 2003 @@ -69,6 +69,7 @@ extern void __udivsi3(void); extern void __umodsi3(void); extern void abort(void); +extern void do_div64(void); extern void ret_from_exception(void); extern void fpundefinstr(void); @@ -234,6 +235,7 @@ EXPORT_SYMBOL_NOVERS(__udivmoddi4); EXPORT_SYMBOL_NOVERS(__udivsi3); EXPORT_SYMBOL_NOVERS(__umodsi3); +EXPORT_SYMBOL_NOVERS(do_div64); /* bitops */ EXPORT_SYMBOL(_set_bit_le); diff -Nru a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S --- a/arch/arm/kernel/entry-armv.S Wed Apr 2 22:24:05 2003 +++ b/arch/arm/kernel/entry-armv.S Wed Apr 2 22:24:05 2003 @@ -997,11 +997,11 @@ * previous and next are guaranteed not to be the same. */ ENTRY(__switch_to) - add ip, r0, #TI_CPU_SAVE - ldr r2, [r1, #TI_CPU_DOMAIN]! + add ip, r1, #TI_CPU_SAVE + ldr r3, [r2, #TI_CPU_DOMAIN]! stmia ip, {r4 - sl, fp, sp, lr} @ Store most regs on stack - mcr p15, 0, r2, c3, c0 @ Set domain register - ldmib r1, {r4 - sl, fp, sp, pc} @ Load all regs saved previously + mcr p15, 0, r3, c3, c0, 0 @ Set domain register + ldmib r2, {r4 - sl, fp, sp, pc} @ Load all regs saved previously __INIT /* diff -Nru a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S --- a/arch/arm/kernel/entry-common.S Wed Apr 2 22:24:04 2003 +++ b/arch/arm/kernel/entry-common.S Wed Apr 2 22:24:04 2003 @@ -75,7 +75,6 @@ * This is how we return from a fork. */ ENTRY(ret_from_fork) - ldr r0, [r0, #TI_TASK] bl schedule_tail get_thread_info tsk ldr r1, [tsk, #TI_FLAGS] @ check for syscall tracing diff -Nru a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile --- a/arch/arm/lib/Makefile Wed Apr 2 22:24:06 2003 +++ b/arch/arm/lib/Makefile Wed Apr 2 22:24:06 2003 @@ -13,7 +13,7 @@ strnlen_user.o strchr.o strrchr.o testchangebit.o \ testclearbit.o testsetbit.o uaccess.o getuser.o \ putuser.o ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \ - ucmpdi2.o udivdi3.o lib1funcs.o + ucmpdi2.o udivdi3.o lib1funcs.o div64.o obj-m := obj-n := diff -Nru a/arch/arm/lib/div64.S b/arch/arm/lib/div64.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/lib/div64.S Wed Apr 2 22:24:08 2003 @@ -0,0 +1,42 @@ +#include + +ql .req r0 @ quotient low +qh .req r1 @ quotient high +dl .req r3 @ divisor low +dh .req r2 @ divisor high +nl .req r4 @ dividend low +nh .req r5 @ dividend high + +ENTRY(do_div64) + stmfd sp!, {r4, r5, lr} + mov nl, r0 + movs nh, r1 @ if high bits are zero + movne lr, #33 + moveq lr, #1 @ only divide low bits + moveq nh, r0 + +1: cmp nh, dh + bls 2f + add lr, lr, #1 + movs dh, dh, lsl #1 @ left justify divisor + bpl 1b + +2: movs nh, r1 + moveq dl, dh + moveq dh, #0 + movne dl, #0 + mov ql, #0 + mov qh, #0 +3: subs ip, nl, dl @ trial subtraction + sbcs ip, nh, dh + movcs nh, ip @ only update if successful + subcs nl, nl, dl @ (repeat the subtraction) + adcs ql, ql, ql @ C=1 if successful, shift into + adc qh, qh, qh @ quotient + movs dh, dh, lsr #1 @ shift base high part right + mov dl, dl, rrx @ shift base low part right + subs lr, lr, #1 + bne 3b + + mov r2, nl + ldmfd sp!, {r4, r5, pc} diff -Nru a/arch/arm/mach-footbridge/dc21285.c b/arch/arm/mach-footbridge/dc21285.c --- a/arch/arm/mach-footbridge/dc21285.c Wed Apr 2 22:24:08 2003 +++ b/arch/arm/mach-footbridge/dc21285.c Wed Apr 2 22:24:08 2003 @@ -25,10 +25,13 @@ #define MAX_SLOTS 21 -#define PCICMD_ERROR_BITS ((PCI_STATUS_DETECTED_PARITY | \ - PCI_STATUS_REC_MASTER_ABORT | \ - PCI_STATUS_REC_TARGET_ABORT | \ - PCI_STATUS_PARITY) << 16) +#define PCICMD_ABORT ((PCI_STATUS_REC_MASTER_ABORT| \ + PCI_STATUS_REC_TARGET_ABORT)<<16) + +#define PCICMD_ERROR_BITS ((PCI_STATUS_DETECTED_PARITY | \ + PCI_STATUS_REC_MASTER_ABORT | \ + PCI_STATUS_REC_TARGET_ABORT | \ + PCI_STATUS_PARITY) << 16) extern int setup_arm_irq(int, struct irqaction *); extern void pcibios_report_status(u_int status_mask, int warn); @@ -84,6 +87,12 @@ *value = v; + v = *CSR_PCICMD; + if (v & PCICMD_ABORT) { + *CSR_PCICMD = v & (0xffff|PCICMD_ABORT); + return -1; + } + return PCIBIOS_SUCCESSFUL; } @@ -92,6 +101,7 @@ int size, u32 value) { unsigned long addr = dc21285_base_address(bus, devfn); + u32 v; if (addr) switch (size) { @@ -109,6 +119,12 @@ break; } + v = *CSR_PCICMD; + if (v & PCICMD_ABORT) { + *CSR_PCICMD = v & (0xffff|PCICMD_ABORT); + return -1; + } + return PCIBIOS_SUCCESSFUL; } @@ -148,16 +164,16 @@ cmd = cmd & 0xffff; if (status & PCI_STATUS_REC_MASTER_ABORT) { - printk(KERN_DEBUG "PCI: master abort: "); - pcibios_report_status(PCI_STATUS_REC_MASTER_ABORT, 1); - printk("\n"); - + printk(KERN_DEBUG "PCI: master abort, pc=0x%08lx\n", + instruction_pointer(regs)); cmd |= PCI_STATUS_REC_MASTER_ABORT << 16; } if (status & PCI_STATUS_REC_TARGET_ABORT) { printk(KERN_DEBUG "PCI: target abort: "); - pcibios_report_status(PCI_STATUS_SIG_TARGET_ABORT, 1); + pcibios_report_status(PCI_STATUS_REC_MASTER_ABORT | + PCI_STATUS_SIG_TARGET_ABORT | + PCI_STATUS_REC_TARGET_ABORT, 1); printk("\n"); cmd |= PCI_STATUS_REC_TARGET_ABORT << 16; @@ -289,6 +305,38 @@ "%s mode\n", *CSR_CLASSREV & 0xff, cfn_mode ? "central function" : "addin"); + if (footbridge_cfn_mode()) { + /* + * Clear any existing errors - we aren't + * interested in historical data... + */ + *CSR_SA110_CNTL = (*CSR_SA110_CNTL & 0xffffde07) | + SA110_CNTL_RXSERR; + *CSR_PCICMD = (*CSR_PCICMD & 0xffff) | PCICMD_ERROR_BITS; + } + + init_timer(&serr_timer); + init_timer(&perr_timer); + + serr_timer.data = IRQ_PCI_SERR; + serr_timer.function = dc21285_enable_error; + perr_timer.data = IRQ_PCI_PERR; + perr_timer.function = dc21285_enable_error; + + /* + * We don't care if these fail. + */ + request_irq(IRQ_PCI_SERR, dc21285_serr_irq, SA_INTERRUPT, + "PCI system error", &serr_timer); + request_irq(IRQ_PCI_PERR, dc21285_parity_irq, SA_INTERRUPT, + "PCI parity error", &perr_timer); + request_irq(IRQ_PCI_ABORT, dc21285_abort_irq, SA_INTERRUPT, + "PCI abort", NULL); + request_irq(IRQ_DISCARD_TIMER, dc21285_discard_irq, SA_INTERRUPT, + "Discard timer", NULL); + request_irq(IRQ_PCI_DPERR, dc21285_dparity_irq, SA_INTERRUPT, + "PCI data parity", NULL); + if (cfn_mode) { static struct resource csrio; @@ -324,35 +372,5 @@ void __init dc21285_postinit(void) { - if (footbridge_cfn_mode()) { - /* - * Clear any existing errors - we aren't - * interested in historical data... - */ - *CSR_SA110_CNTL = (*CSR_SA110_CNTL & 0xffffde07) | - SA110_CNTL_RXSERR; - *CSR_PCICMD = (*CSR_PCICMD & 0xffff) | PCICMD_ERROR_BITS; - } - - /* - * Initialise PCI error IRQ after we've finished probing - */ - request_irq(IRQ_PCI_ABORT, dc21285_abort_irq, SA_INTERRUPT, "PCI abort", NULL); - request_irq(IRQ_DISCARD_TIMER, dc21285_discard_irq, SA_INTERRUPT, "Discard timer", NULL); - request_irq(IRQ_PCI_DPERR, dc21285_dparity_irq, SA_INTERRUPT, "PCI data parity", NULL); - - init_timer(&serr_timer); - init_timer(&perr_timer); - - serr_timer.data = IRQ_PCI_SERR; - serr_timer.function = dc21285_enable_error; - perr_timer.data = IRQ_PCI_PERR; - perr_timer.function = dc21285_enable_error; - - request_irq(IRQ_PCI_SERR, dc21285_serr_irq, SA_INTERRUPT, - "PCI system error", &serr_timer); - request_irq(IRQ_PCI_PERR, dc21285_parity_irq, SA_INTERRUPT, - "PCI parity error", &perr_timer); - register_isa_ports(DC21285_PCI_MEM, DC21285_PCI_IO, 0); } diff -Nru a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c --- a/arch/arm/mach-sa1100/assabet.c Wed Apr 2 22:24:04 2003 +++ b/arch/arm/mach-sa1100/assabet.c Wed Apr 2 22:24:04 2003 @@ -117,6 +117,8 @@ PGSR = 0; PCFR = 0; PSDR = 0; + PPDR |= PPC_TXD3 | PPC_TXD1; + PPSR |= PPC_TXD3 | PPC_TXD1; sa1100fb_lcd_power = assabet_lcd_power; sa1100fb_backlight_power = assabet_backlight_power; diff -Nru a/arch/arm/mach-sa1100/cpu-sa1110.c b/arch/arm/mach-sa1100/cpu-sa1110.c --- a/arch/arm/mach-sa1100/cpu-sa1110.c Wed Apr 2 22:24:04 2003 +++ b/arch/arm/mach-sa1100/cpu-sa1110.c Wed Apr 2 22:24:04 2003 @@ -234,6 +234,8 @@ (sa11x0_ppcr_to_freq(ppcr-1) >= policy->min)) ppcr--; break; + default: + return -EINVAL; } freqs.old = sa11x0_getspeed(); diff -Nru a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types --- a/arch/arm/tools/mach-types Wed Apr 2 22:24:05 2003 +++ b/arch/arm/tools/mach-types Wed Apr 2 22:24:05 2003 @@ -6,7 +6,7 @@ # To add an entry into this database, please see Documentation/arm/README, # or contact rmk@arm.linux.org.uk # -# Last update: Wed Mar 5 22:11:59 2003 +# Last update: Tue Mar 25 16:34:29 2003 # # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # @@ -305,3 +305,11 @@ pxa_whitechapel ARCH_PXA_WHITECHAPEL PXA_WHITECHAPEL 294 nwsc ARCH_NWSC NWSC 295 nwlarm ARCH_NWLARM NWLARM 296 +ixp425_mguard ARCH_IXP425_MGUARD IXP425_MGUARD 297 +pxa_netdcu4 ARCH_PXA_NETDCU4 PXA_NETDCU4 298 +ixdp2401 ARCH_IXDP2401 IXDP2401 299 +ixdp2801 ARCH_IXDP2801 IXDP2801 300 +zodiac ARCH_ZODIAC ZODIAC 301 +armmodul ARCH_ARMMODUL ARMMODUL 302 +ketop SA1100_KETOP KETOP 303 +av7200 ARCH_AV7200 AV7200 304 diff -Nru a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S --- a/arch/i386/boot/setup.S Wed Apr 2 22:24:05 2003 +++ b/arch/i386/boot/setup.S Wed Apr 2 22:24:05 2003 @@ -162,7 +162,7 @@ # can be located anywhere in # low memory 0x10000 or higher. -ramdisk_max: .long __MAXMEM-1 # (Header version 0x0203 or later) +ramdisk_max: .long MAXMEM-1 # (Header version 0x0203 or later) # The highest safe address for # the contents of an initrd diff -Nru a/arch/i386/boot98/setup.S b/arch/i386/boot98/setup.S --- a/arch/i386/boot98/setup.S Wed Apr 2 22:24:04 2003 +++ b/arch/i386/boot98/setup.S Wed Apr 2 22:24:04 2003 @@ -169,7 +169,7 @@ # can be located anywhere in # low memory 0x10000 or higher. -ramdisk_max: .long __MAXMEM-1 # (Header version 0x0203 or later) +ramdisk_max: .long MAXMEM-1 # (Header version 0x0203 or later) # The highest safe address for # the contents of an initrd diff -Nru a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c --- a/arch/i386/kernel/acpi/boot.c Wed Apr 2 22:24:07 2003 +++ b/arch/i386/kernel/acpi/boot.c Wed Apr 2 22:24:07 2003 @@ -28,6 +28,7 @@ #include #include #include +#include #include #if defined (CONFIG_X86_LOCAL_APIC) diff -Nru a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c --- a/arch/i386/kernel/apic.c Wed Apr 2 22:24:07 2003 +++ b/arch/i386/kernel/apic.c Wed Apr 2 22:24:08 2003 @@ -10,6 +10,8 @@ * for testing these extensively. * Maciej W. Rozycki : Various updates and fixes. * Mikael Pettersson : Power Management for UP-APIC. + * Pavel Machek and + * Mikael Pettersson : PM converted to driver model. */ #include @@ -451,17 +453,14 @@ #ifdef CONFIG_PM -#include -#include +#include +#include static struct { /* 'active' is true if the local APIC was enabled by us and not the BIOS; this signifies that we are also responsible for disabling it before entering apm/acpi suspend */ int active; - /* 'perfctr_pmdev' is here because the current (2.4.1) PM - callback system doesn't handle hierarchical dependencies */ - struct pm_dev *perfctr_pmdev; /* r/w apic fields */ unsigned int apic_id; unsigned int apic_taskpri; @@ -478,13 +477,16 @@ unsigned int apic_thmr; } apic_pm_state; -static void apic_pm_suspend(void *data) +static int lapic_suspend(struct device *dev, u32 state, u32 level) { unsigned int l, h; unsigned long flags; - if (apic_pm_state.perfctr_pmdev) - pm_send(apic_pm_state.perfctr_pmdev, PM_SUSPEND, data); + if (level != SUSPEND_POWER_DOWN) + return 0; + if (!apic_pm_state.active) + return 0; + apic_pm_state.apic_id = apic_read(APIC_ID); apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI); apic_pm_state.apic_ldr = apic_read(APIC_LDR); @@ -505,13 +507,22 @@ l &= ~MSR_IA32_APICBASE_ENABLE; wrmsr(MSR_IA32_APICBASE, l, h); local_irq_restore(flags); + return 0; } -static void apic_pm_resume(void *data) +static int lapic_resume(struct device *dev, u32 level) { unsigned int l, h; unsigned long flags; + if (level != RESUME_POWER_ON) + return 0; + if (!apic_pm_state.active) + return 0; + + /* XXX: Pavel needs this for S3 resume, but can't explain why */ + set_fixmap_nocache(FIX_APIC_BASE, APIC_DEFAULT_PHYS_BASE); + local_irq_save(flags); rdmsr(MSR_IA32_APICBASE, l, h); l &= ~MSR_IA32_APICBASE_BASE; @@ -536,73 +547,45 @@ apic_write(APIC_ESR, 0); apic_read(APIC_ESR); local_irq_restore(flags); - if (apic_pm_state.perfctr_pmdev) - pm_send(apic_pm_state.perfctr_pmdev, PM_RESUME, data); -} - -static int apic_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) -{ - switch (rqst) { - case PM_SUSPEND: - apic_pm_suspend(data); - break; - case PM_RESUME: - apic_pm_resume(data); - break; - } return 0; } -/* perfctr driver should call this instead of pm_register() */ -struct pm_dev *apic_pm_register(pm_dev_t type, - unsigned long id, - pm_callback callback) -{ - struct pm_dev *dev; - - if (!apic_pm_state.active) - return pm_register(type, id, callback); - if (apic_pm_state.perfctr_pmdev) - return NULL; /* we're busy */ - dev = kmalloc(sizeof(struct pm_dev), GFP_KERNEL); - if (dev) { - memset(dev, 0, sizeof(*dev)); - dev->type = type; - dev->id = id; - dev->callback = callback; - apic_pm_state.perfctr_pmdev = dev; - } - return dev; -} - -/* perfctr driver should call this instead of pm_unregister() */ -void apic_pm_unregister(struct pm_dev *dev) -{ - if (!apic_pm_state.active) { - pm_unregister(dev); - } else if (dev == apic_pm_state.perfctr_pmdev) { - apic_pm_state.perfctr_pmdev = NULL; - kfree(dev); - } -} +static struct device_driver lapic_driver = { + .name = "lapic", + .bus = &system_bus_type, + .resume = lapic_resume, + .suspend = lapic_suspend, +}; + +/* not static, needed by child devices */ +struct sys_device device_lapic = { + .name = "lapic", + .id = 0, + .dev = { + .name = "lapic", + .driver = &lapic_driver, + }, +}; +EXPORT_SYMBOL(device_lapic); -static void __init apic_pm_init1(void) +static void __init apic_pm_activate(void) { - /* can't pm_register() at this early stage in the boot process - (causes an immediate reboot), so just set the flag */ apic_pm_state.active = 1; } -static void __init apic_pm_init2(void) +static int __init init_lapic_devicefs(void) { - if (apic_pm_state.active) - pm_register(PM_SYS_DEV, 0, apic_pm_callback); + if (!cpu_has_apic) + return 0; + /* XXX: remove suspend/resume procs if !apic_pm_state.active? */ + driver_register(&lapic_driver); + return sys_device_register(&device_lapic); } +device_initcall(init_lapic_devicefs); #else /* CONFIG_PM */ -static inline void apic_pm_init1(void) { } -static inline void apic_pm_init2(void) { } +static inline void apic_pm_activate(void) { } #endif /* CONFIG_PM */ @@ -670,7 +653,7 @@ printk("Found and enabled local APIC!\n"); - apic_pm_init1(); + apic_pm_activate(); return 0; @@ -1154,8 +1137,6 @@ connect_bsp_APIC(); phys_cpu_present_map = 1 << boot_cpu_physical_apicid; - - apic_pm_init2(); setup_local_APIC(); diff -Nru a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c --- a/arch/i386/kernel/apm.c Wed Apr 2 22:24:04 2003 +++ b/arch/i386/kernel/apm.c Wed Apr 2 22:24:04 2003 @@ -218,6 +218,7 @@ #include #include #include +#include #include #include #include @@ -1237,6 +1238,9 @@ } printk(KERN_CRIT "apm: suspend was vetoed, but suspending anyway.\n"); } + + device_suspend(3, SUSPEND_POWER_DOWN); + /* serialize with the timer interrupt */ write_seqlock_irq(&xtime_lock); @@ -1257,6 +1261,7 @@ if (err != APM_SUCCESS) apm_error("suspend", err); err = (err == APM_SUCCESS) ? 0 : -EIO; + device_resume(RESUME_POWER_ON); pm_send_all(PM_RESUME, (void *)0); queue_event(APM_NORMAL_RESUME, NULL); out: @@ -1370,6 +1375,7 @@ write_seqlock_irq(&xtime_lock); set_time(); write_sequnlock_irq(&xtime_lock); + device_resume(RESUME_POWER_ON); pm_send_all(PM_RESUME, (void *)0); queue_event(event, NULL); } diff -Nru a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c --- a/arch/i386/kernel/cpu/intel.c Wed Apr 2 22:24:04 2003 +++ b/arch/i386/kernel/cpu/intel.c Wed Apr 2 22:24:04 2003 @@ -93,15 +93,17 @@ { { 0x06, LVL_1_INST, 8 }, { 0x08, LVL_1_INST, 16 }, - { 0x0A, LVL_1_DATA, 8 }, - { 0x0C, LVL_1_DATA, 16 }, + { 0x0a, LVL_1_DATA, 8 }, + { 0x0c, LVL_1_DATA, 16 }, { 0x22, LVL_3, 512 }, { 0x23, LVL_3, 1024 }, { 0x25, LVL_3, 2048 }, { 0x29, LVL_3, 4096 }, + { 0x2c, LVL_1_DATA, 32 }, + { 0x30, LVL_1_INST, 32 }, { 0x39, LVL_2, 128 }, { 0x3b, LVL_2, 128 }, - { 0x3C, LVL_2, 256 }, + { 0x3c, LVL_2, 256 }, { 0x41, LVL_2, 128 }, { 0x42, LVL_2, 256 }, { 0x43, LVL_2, 512 }, @@ -114,13 +116,15 @@ { 0x71, LVL_TRACE, 16 }, { 0x72, LVL_TRACE, 32 }, { 0x79, LVL_2, 128 }, - { 0x7A, LVL_2, 256 }, - { 0x7B, LVL_2, 512 }, - { 0x7C, LVL_2, 1024 }, + { 0x7a, LVL_2, 256 }, + { 0x7b, LVL_2, 512 }, + { 0x7c, LVL_2, 1024 }, { 0x82, LVL_2, 256 }, { 0x83, LVL_2, 512 }, { 0x84, LVL_2, 1024 }, { 0x85, LVL_2, 2048 }, + { 0x86, LVL_2, 512 }, + { 0x87, LVL_2, 1024 }, { 0x00, 0, 0} }; diff -Nru a/arch/i386/kernel/cpu/proc.c b/arch/i386/kernel/cpu/proc.c --- a/arch/i386/kernel/cpu/proc.c Wed Apr 2 22:24:07 2003 +++ b/arch/i386/kernel/cpu/proc.c Wed Apr 2 22:24:07 2003 @@ -44,8 +44,8 @@ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* Intel-defined (#2) */ - "pni", NULL, NULL, "monitor", "ds_cpl", NULL, NULL, NULL, - "tm2", NULL, "cnxt_id", NULL, NULL, NULL, NULL, NULL, + "pni", NULL, NULL, "monitor", "ds_cpl", NULL, NULL, "tm2", + "est", NULL, "cid", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, diff -Nru a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c --- a/arch/i386/kernel/i386_ksyms.c Wed Apr 2 22:24:07 2003 +++ b/arch/i386/kernel/i386_ksyms.c Wed Apr 2 22:24:07 2003 @@ -163,10 +163,6 @@ EXPORT_SYMBOL(flush_tlb_page); #endif -#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_PM) -EXPORT_SYMBOL_GPL(set_nmi_pm_callback); -EXPORT_SYMBOL_GPL(unset_nmi_pm_callback); -#endif #ifdef CONFIG_X86_IO_APIC EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector); #endif diff -Nru a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c --- a/arch/i386/kernel/nmi.c Wed Apr 2 22:24:05 2003 +++ b/arch/i386/kernel/nmi.c Wed Apr 2 22:24:05 2003 @@ -9,6 +9,8 @@ * Mikael Pettersson : AMD K7 support for local APIC NMI watchdog. * Mikael Pettersson : Power Management for local APIC NMI watchdog. * Mikael Pettersson : Pentium 4 support for local APIC NMI watchdog. + * Pavel Machek and + * Mikael Pettersson : PM converted to driver model. Disable/enable API. */ #include @@ -20,6 +22,7 @@ #include #include #include +#include #include #include @@ -134,14 +137,18 @@ __setup("nmi_watchdog=", setup_nmi_watchdog); -#ifdef CONFIG_PM - -#include - -struct pm_dev *nmi_pmdev; +/* nmi_active: + * +1: the lapic NMI watchdog is active, but can be disabled + * 0: the lapic NMI watchdog has not been set up, and cannot + * be enabled + * -1: the lapic NMI watchdog is disabled, but can be enabled + */ +static int nmi_active; -static void disable_apic_nmi_watchdog(void) +void disable_lapic_nmi_watchdog(void) { + if (nmi_active <= 0) + return; switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: wrmsr(MSR_K7_EVNTSEL0, 0, 0); @@ -158,46 +165,65 @@ } break; } + nmi_active = -1; + /* tell do_nmi() and others that we're not active any more */ + nmi_watchdog = 0; } -static int nmi_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) +void enable_lapic_nmi_watchdog(void) { - switch (rqst) { - case PM_SUSPEND: - disable_apic_nmi_watchdog(); - break; - case PM_RESUME: + if (nmi_active < 0) { + nmi_watchdog = NMI_LOCAL_APIC; setup_apic_nmi_watchdog(); - break; } - return 0; } -struct pm_dev * set_nmi_pm_callback(pm_callback callback) -{ - apic_pm_unregister(nmi_pmdev); - return apic_pm_register(PM_SYS_DEV, 0, callback); -} +#ifdef CONFIG_PM + +#include -void unset_nmi_pm_callback(struct pm_dev * dev) +static int lapic_nmi_suspend(struct device *dev, u32 state, u32 level) { - apic_pm_unregister(dev); - nmi_pmdev = apic_pm_register(PM_SYS_DEV, 0, nmi_pm_callback); + if (level != SUSPEND_POWER_DOWN) + return 0; + disable_lapic_nmi_watchdog(); + return 0; } - -static void nmi_pm_init(void) + +static int lapic_nmi_resume(struct device *dev, u32 level) { - if (!nmi_pmdev) - nmi_pmdev = apic_pm_register(PM_SYS_DEV, 0, nmi_pm_callback); + if (level != RESUME_POWER_ON) + return 0; + enable_lapic_nmi_watchdog(); + return 0; } -#define __pminit /*empty*/ - -#else /* CONFIG_PM */ +static struct device_driver lapic_nmi_driver = { + .name = "lapic_nmi", + .bus = &system_bus_type, + .resume = lapic_nmi_resume, + .suspend = lapic_nmi_suspend, +}; + +static struct sys_device device_lapic_nmi = { + .name = "lapic_nmi", + .id = 0, + .dev = { + .name = "lapic_nmi", + .driver = &lapic_nmi_driver, + .parent = &device_lapic.dev, + }, +}; -static inline void nmi_pm_init(void) { } - -#define __pminit __init +static int __init init_lapic_nmi_devicefs(void) +{ + if (nmi_active == 0) + return 0; + driver_register(&lapic_nmi_driver); + return sys_device_register(&device_lapic_nmi); +} +/* must come after the local APIC's device_initcall() */ +late_initcall(init_lapic_nmi_devicefs); #endif /* CONFIG_PM */ @@ -206,7 +232,7 @@ * Original code written by Keith Owens. */ -static void __pminit clear_msr_range(unsigned int base, unsigned int n) +static void clear_msr_range(unsigned int base, unsigned int n) { unsigned int i; @@ -214,7 +240,7 @@ wrmsr(base+i, 0, 0); } -static void __pminit setup_k7_watchdog(void) +static void setup_k7_watchdog(void) { unsigned int evntsel; @@ -236,7 +262,7 @@ wrmsr(MSR_K7_EVNTSEL0, evntsel, 0); } -static void __pminit setup_p6_watchdog(void) +static void setup_p6_watchdog(void) { unsigned int evntsel; @@ -258,7 +284,7 @@ wrmsr(MSR_P6_EVNTSEL0, evntsel, 0); } -static int __pminit setup_p4_watchdog(void) +static int setup_p4_watchdog(void) { unsigned int misc_enable, dummy; @@ -288,7 +314,7 @@ return 1; } -void __pminit setup_apic_nmi_watchdog (void) +void setup_apic_nmi_watchdog (void) { switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: @@ -312,7 +338,7 @@ default: return; } - nmi_pm_init(); + nmi_active = 1; } static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED; @@ -400,3 +426,7 @@ wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1); } } + +EXPORT_SYMBOL(nmi_watchdog); +EXPORT_SYMBOL(disable_lapic_nmi_watchdog); +EXPORT_SYMBOL(enable_lapic_nmi_watchdog); diff -Nru a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c --- a/arch/i386/kernel/smpboot.c Wed Apr 2 22:24:05 2003 +++ b/arch/i386/kernel/smpboot.c Wed Apr 2 22:24:05 2003 @@ -422,7 +422,7 @@ /* * Synchronize the TSC with the BP */ - if (cpu_has_tsc) + if (cpu_has_tsc && cpu_khz) synchronize_tsc_ap(); } @@ -1114,7 +1114,7 @@ /* * Synchronize the TSC with the AP */ - if (cpu_has_tsc && cpucount) + if (cpu_has_tsc && cpucount && cpu_khz) synchronize_tsc_bp(); } diff -Nru a/arch/i386/kernel/timers/timer.c b/arch/i386/kernel/timers/timer.c --- a/arch/i386/kernel/timers/timer.c Wed Apr 2 22:24:07 2003 +++ b/arch/i386/kernel/timers/timer.c Wed Apr 2 22:24:07 2003 @@ -1,4 +1,6 @@ +#include #include +#include #include /* list of externed timers */ @@ -17,6 +19,17 @@ NULL, }; +static char clock_override[10] __initdata; + +static int __init clock_setup(char* str) +{ + if (str) { + strncpy(clock_override, str,10); + clock_override[9] = '\0'; + } + return 1; +} +__setup("clock=", clock_setup); /* iterates through the list of timers, returning the first * one that initializes successfully. @@ -28,7 +41,7 @@ /* find most preferred working timer */ while (timers[i]) { if (timers[i]->init) - if (timers[i]->init() == 0) + if (timers[i]->init(clock_override) == 0) return timers[i]; ++i; } diff -Nru a/arch/i386/kernel/timers/timer_cyclone.c b/arch/i386/kernel/timers/timer_cyclone.c --- a/arch/i386/kernel/timers/timer_cyclone.c Wed Apr 2 22:24:06 2003 +++ b/arch/i386/kernel/timers/timer_cyclone.c Wed Apr 2 22:24:06 2003 @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -73,7 +74,7 @@ return delay_at_last_interrupt + offset; } -static int init_cyclone(void) +static int __init init_cyclone(char* override) { u32* reg; u32 base; /* saved cyclone base address */ @@ -81,8 +82,11 @@ u32 offset; /* offset from pageaddr to cyclone_timer register */ int i; + /* check clock override */ + if (override[0] && strncmp(override,"cyclone",7)) + return -ENODEV; + /*make sure we're on a summit box*/ - /*XXX need to use proper summit hooks! such as xapic -john*/ if(!use_cyclone) return -ENODEV; printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n"); diff -Nru a/arch/i386/kernel/timers/timer_none.c b/arch/i386/kernel/timers/timer_none.c --- a/arch/i386/kernel/timers/timer_none.c Wed Apr 2 22:24:05 2003 +++ b/arch/i386/kernel/timers/timer_none.c Wed Apr 2 22:24:05 2003 @@ -1,6 +1,7 @@ +#include #include -static int init_none(void) +static int __init init_none(char* override) { return 0; } diff -Nru a/arch/i386/kernel/timers/timer_pit.c b/arch/i386/kernel/timers/timer_pit.c --- a/arch/i386/kernel/timers/timer_pit.c Wed Apr 2 22:24:07 2003 +++ b/arch/i386/kernel/timers/timer_pit.c Wed Apr 2 22:24:07 2003 @@ -17,8 +17,12 @@ extern spinlock_t i8253_lock; #include "do_timer.h" -static int init_pit(void) +static int __init init_pit(char* override) { + /* check clock override */ + if (override[0] && strncmp(override,"pit",3)) + printk(KERN_ERR "Warning: clock= override failed. Defaulting to PIT\n"); + return 0; } diff -Nru a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c --- a/arch/i386/kernel/timers/timer_tsc.c Wed Apr 2 22:24:06 2003 +++ b/arch/i386/kernel/timers/timer_tsc.c Wed Apr 2 22:24:06 2003 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -244,8 +245,13 @@ #endif -static int init_tsc(void) +static int __init init_tsc(char* override) { + + /* check clock override */ + if (override[0] && strncmp(override,"tsc",3)) + return -ENODEV; + /* * If we have APM enabled or the CPU clock speed is variable * (CPU stops clock on HLT or slows clock to save power) diff -Nru a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c --- a/arch/i386/kernel/vm86.c Wed Apr 2 22:24:04 2003 +++ b/arch/i386/kernel/vm86.c Wed Apr 2 22:24:04 2003 @@ -113,10 +113,13 @@ printk("vm86: could not access userspace vm86_info\n"); do_exit(SIGSEGV); } - tss = init_tss + smp_processor_id(); + + tss = init_tss + get_cpu(); current->thread.esp0 = current->thread.saved_esp0; load_esp0(tss, current->thread.esp0); current->thread.saved_esp0 = 0; + put_cpu(); + loadsegment(fs, current->thread.saved_fs); loadsegment(gs, current->thread.saved_gs); ret = KVM86->regs32; @@ -289,9 +292,10 @@ asm volatile("movl %%fs,%0":"=m" (tsk->thread.saved_fs)); asm volatile("movl %%gs,%0":"=m" (tsk->thread.saved_gs)); - tss = init_tss + smp_processor_id(); + tss = init_tss + get_cpu(); tss->esp0 = tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0; disable_sysenter(tss); + put_cpu(); tsk->thread.screen_bitmap = info->screen_bitmap; if (info->flags & VM86_SCREEN_BITMAP) diff -Nru a/arch/i386/mm/boot_ioremap.c b/arch/i386/mm/boot_ioremap.c --- a/arch/i386/mm/boot_ioremap.c Wed Apr 2 22:24:08 2003 +++ b/arch/i386/mm/boot_ioremap.c Wed Apr 2 22:24:08 2003 @@ -19,6 +19,7 @@ #undef CONFIG_X86_PAE #include #include +#include #include #include @@ -48,10 +49,12 @@ { boot_pte_t* pte; int i; + char *vaddr = virtual_source; pte = boot_vaddr_to_pte(virtual_source); for (i=0; i < nrpages; i++, phys_addr += PAGE_SIZE, pte++) { set_pte(pte, pfn_pte(phys_addr>>PAGE_SHIFT, PAGE_KERNEL)); + __flush_tlb_one(&vaddr[i*PAGE_SIZE]); } } diff -Nru a/arch/i386/mm/highmem.c b/arch/i386/mm/highmem.c --- a/arch/i386/mm/highmem.c Wed Apr 2 22:24:05 2003 +++ b/arch/i386/mm/highmem.c Wed Apr 2 22:24:05 2003 @@ -2,8 +2,7 @@ void *kmap(struct page *page) { - if (in_interrupt()) - BUG(); + might_sleep(); if (page < highmem_start_page) return page_address(page); return kmap_high(page); diff -Nru a/arch/i386/mm/init.c b/arch/i386/mm/init.c --- a/arch/i386/mm/init.c Wed Apr 2 22:24:06 2003 +++ b/arch/i386/mm/init.c Wed Apr 2 22:24:06 2003 @@ -44,6 +44,8 @@ struct mmu_gather mmu_gathers[NR_CPUS]; unsigned long highstart_pfn, highend_pfn; +static int do_test_wp_bit(void); + /* * Creates a middle page table and puts a pointer to it in the * given global directory entry. This only returns the gd entry @@ -377,15 +379,10 @@ /* * Test if the WP bit works in supervisor mode. It isn't supported on 386's - * and also on some strange 486's (NexGen etc.). All 586+'s are OK. The jumps - * before and after the test are here to work-around some nasty CPU bugs. - */ - -/* - * This function cannot be __init, since exceptions don't work in that - * section. + * and also on some strange 486's (NexGen etc.). All 586+'s are OK. This + * used to involve black magic jumps to work around some nasty CPU bugs, + * but fortunately the switch to using exceptions got rid of all that. */ -static int do_test_wp_bit(void); void __init test_wp_bit(void) { @@ -539,7 +536,10 @@ panic("pgtable_cache_init(): Cannot create pgd cache"); } -/* Put this after the callers, so that it cannot be inlined */ +/* + * This function cannot be __init, since exceptions don't work in that + * section. Put this after the callers, so that it cannot be inlined. + */ static int do_test_wp_bit(void) { char tmp_reg; diff -Nru a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c --- a/arch/i386/oprofile/nmi_int.c Wed Apr 2 22:24:07 2003 +++ b/arch/i386/oprofile/nmi_int.c Wed Apr 2 22:24:07 2003 @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -25,27 +26,59 @@ static int nmi_start(void); static void nmi_stop(void); -static struct pm_dev * oprofile_pmdev; - -/* We're at risk of causing big trouble unless we - * make sure to not cause any NMI interrupts when - * suspended. - */ -static int oprofile_pm_callback(struct pm_dev * dev, - pm_request_t rqst, void * data) -{ - switch (rqst) { - case PM_SUSPEND: - nmi_stop(); - break; - case PM_RESUME: - nmi_start(); - break; - } +/* 0 == registered but off, 1 == registered and on */ +static int nmi_enabled = 0; + +#ifdef CONFIG_PM + +static int nmi_suspend(struct device *dev, u32 state, u32 level) +{ + if (level != SUSPEND_POWER_DOWN) + return 0; + if (nmi_enabled == 1) + nmi_stop(); return 0; } - - + + +static int nmi_resume(struct device *dev, u32 level) +{ + if (level != RESUME_POWER_ON) + return 0; + if (nmi_enabled == 1) + nmi_start(); + return 0; +} + + +static struct device_driver nmi_driver = { + .name = "oprofile", + .bus = &system_bus_type, + .resume = nmi_resume, + .suspend = nmi_suspend, +}; + + +static struct device device_nmi = { + .name = "oprofile", + .bus_id = "oprofile", + .driver = &nmi_driver, + .parent = &device_lapic.dev, +}; + + +static int __init init_nmi_driverfs(void) +{ + driver_register(&nmi_driver); + return device_register(&device_nmi); +} + + +late_initcall(init_nmi_driverfs); + +#endif /* CONFIG_PM */ + + static int nmi_callback(struct pt_regs * regs, int cpu) { return model->check_ctrs(cpu, &cpu_msrs[cpu], regs); @@ -86,7 +119,7 @@ saved_lvtpc[cpu] = apic_read(APIC_LVTPC); apic_write(APIC_LVTPC, APIC_DM_NMI); } - + static int nmi_setup(void) { @@ -95,9 +128,10 @@ * without actually triggering any NMIs as this will * break the core code horrifically. */ + disable_lapic_nmi_watchdog(); on_each_cpu(nmi_cpu_setup, NULL, 0, 1); set_nmi_callback(nmi_callback); - oprofile_pmdev = set_nmi_pm_callback(oprofile_pm_callback); + nmi_enabled = 1; return 0; } @@ -145,9 +179,10 @@ static void nmi_shutdown(void) { - unset_nmi_pm_callback(oprofile_pmdev); + nmi_enabled = 0; unset_nmi_callback(); on_each_cpu(nmi_cpu_shutdown, NULL, 0, 1); + enable_lapic_nmi_watchdog(); } diff -Nru a/arch/ia64/sn/kernel/sv.c b/arch/ia64/sn/kernel/sv.c --- a/arch/ia64/sn/kernel/sv.c Wed Apr 2 22:24:04 2003 +++ b/arch/ia64/sn/kernel/sv.c Wed Apr 2 22:24:04 2003 @@ -18,7 +18,6 @@ #include #include -#include #include #include diff -Nru a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c --- a/arch/m68k/kernel/m68k_ksyms.c Wed Apr 2 22:24:07 2003 +++ b/arch/m68k/kernel/m68k_ksyms.c Wed Apr 2 22:24:07 2003 @@ -17,7 +17,6 @@ #include #include #include -#include asmlinkage long long __ashldi3 (long long, int); asmlinkage long long __ashrdi3 (long long, int); diff -Nru a/arch/m68knommu/kernel/m68k_ksyms.c b/arch/m68knommu/kernel/m68k_ksyms.c --- a/arch/m68knommu/kernel/m68k_ksyms.c Wed Apr 2 22:24:07 2003 +++ b/arch/m68knommu/kernel/m68k_ksyms.c Wed Apr 2 22:24:07 2003 @@ -17,7 +17,6 @@ #include #include #include -#include #include extern void dump_thread(struct pt_regs *, struct user *); diff -Nru a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c --- a/arch/mips/kernel/mips_ksyms.c Wed Apr 2 22:24:04 2003 +++ b/arch/mips/kernel/mips_ksyms.c Wed Apr 2 22:24:04 2003 @@ -25,7 +25,6 @@ #include #include #include -#include #include #ifdef CONFIG_BLK_DEV_FD #include diff -Nru a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c --- a/arch/mips/kernel/smp.c Wed Apr 2 22:24:04 2003 +++ b/arch/mips/kernel/smp.c Wed Apr 2 22:24:04 2003 @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include diff -Nru a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c --- a/arch/mips/mm/fault.c Wed Apr 2 22:24:04 2003 +++ b/arch/mips/mm/fault.c Wed Apr 2 22:24:04 2003 @@ -22,7 +22,6 @@ #include #include #include -#include #include #include diff -Nru a/arch/mips64/kernel/mips64_ksyms.c b/arch/mips64/kernel/mips64_ksyms.c --- a/arch/mips64/kernel/mips64_ksyms.c Wed Apr 2 22:24:05 2003 +++ b/arch/mips64/kernel/mips64_ksyms.c Wed Apr 2 22:24:05 2003 @@ -24,7 +24,6 @@ #include #include #include -#include #include #include diff -Nru a/arch/mips64/kernel/smp.c b/arch/mips64/kernel/smp.c --- a/arch/mips64/kernel/smp.c Wed Apr 2 22:24:06 2003 +++ b/arch/mips64/kernel/smp.c Wed Apr 2 22:24:06 2003 @@ -6,12 +6,12 @@ #include #include #include +#include #include #include #include #include -#include #include #include diff -Nru a/arch/mips64/mm/fault.c b/arch/mips64/mm/fault.c --- a/arch/mips64/mm/fault.c Wed Apr 2 22:24:06 2003 +++ b/arch/mips64/mm/fault.c Wed Apr 2 22:24:06 2003 @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff -Nru a/arch/ppc/Kconfig b/arch/ppc/Kconfig --- a/arch/ppc/Kconfig Wed Apr 2 22:24:07 2003 +++ b/arch/ppc/Kconfig Wed Apr 2 22:24:07 2003 @@ -666,6 +666,52 @@ here. Saying Y here will not hurt performance (on any machine) but will increase the size of the kernel. +config CPU_FREQ + bool "CPU Frequency scaling" + help + Clock scaling allows you to change the clock speed of CPUs on the + fly. This is a nice method to save battery power on notebooks, + because the lower the clock speed, the less power the CPU consumes. + + For more information, take a look at linux/Documentation/cpufreq or + at + + If in doubt, say N. + +config CPU_FREQ_PROC_INTF + bool "/proc/cpufreq interface (DEPRECATED)" + depends on CPU_FREQ && PROC_FS + help + This enables the /proc/cpufreq interface for controlling + CPUFreq. Please note that it is recommended to use the sysfs + interface instead (which is built automatically). + + For details, take a look at linux/Documentation/cpufreq. + + If in doubt, say N. + +config CPU_FREQ_24_API + bool "/proc/sys/cpu/ interface (2.4. / OLD)" + depends on CPU_FREQ + help + This enables the /proc/sys/cpu/ sysctl interface for controlling + CPUFreq, as known from the 2.4.-kernel patches for CPUFreq. 2.5 + uses a sysfs interface instead. Please note that some drivers do + not work well with the 2.4. /proc/sys/cpu sysctl interface, + so if in doubt, say N here. + + For details, take a look at linux/Documentation/cpufreq. + + If in doubt, say N. + +config CPU_FREQ_PMAC + bool "Support for Apple PowerBooks" + depends on CPU_FREQ && ADB_PMU + help + This adds support for frequency switching on Apple PowerBooks, + this currently includes some models of iBook & Titanium + PowerBook. + endmenu menu "General setup" diff -Nru a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile --- a/arch/ppc/kernel/Makefile Wed Apr 2 22:24:07 2003 +++ b/arch/ppc/kernel/Makefile Wed Apr 2 22:24:07 2003 @@ -21,7 +21,7 @@ process.o signal.o ptrace.o align.o \ semaphore.o syscalls.o setup.o \ cputable.o ppc_htab.o -obj-$(CONFIG_6xx) += l2cr.o +obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o obj-$(CONFIG_MODULES) += module.o ppc_ksyms.o obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_PCI) += pci-dma.o diff -Nru a/arch/ppc/kernel/cpu_setup_6xx.S b/arch/ppc/kernel/cpu_setup_6xx.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/kernel/cpu_setup_6xx.S Wed Apr 2 22:24:08 2003 @@ -0,0 +1,415 @@ +/* + * 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 + +_GLOBAL(__setup_cpu_601) + blr +_GLOBAL(__setup_cpu_603) + b setup_common_caches +_GLOBAL(__setup_cpu_604) + mflr r4 + bl setup_common_caches + bl setup_604_hid0 + mtlr r4 + blr +_GLOBAL(__setup_cpu_750) + mflr r4 + bl setup_common_caches + bl setup_750_7400_hid0 + mtlr r4 + blr +_GLOBAL(__setup_cpu_750cx) + mflr r4 + bl setup_common_caches + bl setup_750_7400_hid0 + bl setup_750cx + mtlr r4 + blr +_GLOBAL(__setup_cpu_750fx) + mflr r4 + bl setup_common_caches + bl setup_750_7400_hid0 + bl setup_750fx + mtlr r4 + blr +_GLOBAL(__setup_cpu_7400) + mflr r4 + bl setup_7400_workarounds + bl setup_common_caches + bl setup_750_7400_hid0 + mtlr r4 + blr +_GLOBAL(__setup_cpu_7410) + mflr r4 + bl setup_7410_workarounds + bl setup_common_caches + bl setup_750_7400_hid0 + li r3,0 + mtspr SPRN_L2CR2,r3 + mtlr r4 + blr +_GLOBAL(__setup_cpu_7450) + mflr r4 + bl setup_common_caches + bl setup_745x_specifics + mtlr r4 + blr +_GLOBAL(__setup_cpu_7455) + mflr r4 + bl setup_common_caches + bl setup_745x_specifics + mtlr r4 + blr + +/* Enable caches for 603's, 604, 750 & 7400 */ +setup_common_caches: + mfspr r11,HID0 + andi. r0,r11,HID0_DCE +#ifdef CONFIG_DCACHE_DISABLE + ori r11,r11,HID0_ICE +#else + ori r11,r11,HID0_ICE|HID0_DCE +#endif + ori r8,r11,HID0_ICFI + bne 1f /* don't invalidate the D-cache */ + ori r8,r8,HID0_DCI /* unless it wasn't enabled */ +1: sync + mtspr HID0,r8 /* enable and invalidate caches */ + sync + mtspr HID0,r11 /* enable caches */ + sync + isync + blr + +/* 604, 604e, 604ev, ... + * Enable superscalar execution & branch history table + */ +setup_604_hid0: + mfspr r11,HID0 + ori r11,r11,HID0_SIED|HID0_BHTE + ori r8,r11,HID0_BTCD + sync + mtspr HID0,r8 /* flush branch target address cache */ + sync /* on 604e/604r */ + mtspr HID0,r11 + sync + isync + blr + +/* 7400 <= rev 2.7 and 7410 rev = 1.0 suffer from some + * erratas we work around here. + * Moto MPC710CE.pdf describes them, those are errata + * #3, #4 and #5 + * Note that we assume the firmware didn't choose to + * apply other workarounds (there are other ones documented + * in the .pdf). It appear that Apple firmware only works + * around #3 and with the same fix we use. We may want to + * check if the CPU is using 60x bus mode in which case + * the workaround for errata #4 is useless. Also, we may + * want to explicitely clear HID0_NOPDST as this is not + * needed once we have applied workaround #5 (though it's + * not set by Apple's firmware at least). + */ +setup_7400_workarounds: + mfpvr r3 + rlwinm r3,r3,0,20,31 + cmpwi 0,r3,0x0207 + ble 1f + blr +setup_7410_workarounds: + mfpvr r3 + rlwinm r3,r3,0,20,31 + cmpwi 0,r3,0x0100 + bnelr +1: + mfspr r11,SPRN_MSSSR0 + /* Errata #3: Set L1OPQ_SIZE to 0x10 */ + rlwinm r11,r11,0,9,6 + oris r11,r11,0x0100 + /* Errata #4: Set L2MQ_SIZE to 1 (check for MPX mode first ?) */ + oris r11,r11,0x0002 + /* Errata #5: Set DRLT_SIZE to 0x01 */ + rlwinm r11,r11,0,5,2 + oris r11,r11,0x0800 + sync + mtspr SPRN_MSSSR0,r11 + sync + isync + blr + +/* 740/750/7400/7410 + * Enable Store Gathering (SGE), Address Brodcast (ABE), + * Branch History Table (BHTE), Branch Target ICache (BTIC) + * Dynamic Power Management (DPM), Speculative (SPD) + * Clear Instruction cache throttling (ICTC) + */ +setup_750_7400_hid0: + mfspr r11,HID0 + ori r11,r11,HID0_SGE | HID0_ABE | HID0_BHTE | HID0_BTIC +BEGIN_FTR_SECTION + oris r11,r11,HID0_DPM@h /* enable dynamic power mgmt */ +END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM) + li r3,HID0_SPD + andc r11,r11,r3 /* clear SPD: enable speculative */ + li r3,0 + mtspr ICTC,r3 /* Instruction Cache Throttling off */ + isync + mtspr HID0,r11 + sync + isync + blr + +/* 750cx specific + * Looks like we have to disable NAP feature for some PLL settings... + * (waiting for confirmation) + */ +setup_750cx: + mfspr r10, SPRN_HID1 + rlwinm r10,r10,4,28,31 + cmpi cr0,r10,7 + cmpi cr1,r10,9 + cmpi cr2,r10,11 + cror 4*cr0+eq,4*cr0+eq,4*cr1+eq + cror 4*cr0+eq,4*cr0+eq,4*cr2+eq + bnelr + lwz r6,CPU_SPEC_FEATURES(r5) + li r7,CPU_FTR_CAN_NAP + andc r6,r6,r7 + stw r6,CPU_SPEC_FEATURES(r5) + blr + +/* 750fx specific + */ +setup_750fx: + blr + +/* MPC 745x + * Enable Store Gathering (SGE), Branch Folding (FOLD) + * Branch History Table (BHTE), Branch Target ICache (BTIC) + * Dynamic Power Management (DPM), Speculative (SPD) + * Ensure our data cache instructions really operate. + * Timebase has to be running or we wouldn't have made it here, + * just ensure we don't disable it. + * Clear Instruction cache throttling (ICTC) + * Enable L2 HW prefetch + */ +setup_745x_specifics: + /* We check for the presence of an L3 cache setup by + * the firmware. If any, we disable NAP capability as + * it's known to be bogus on rev 2.1 and earlier + */ + mfspr r11,SPRN_L3CR + andis. r11,r11,L3CR_L3E@h + beq 1f + lwz r6,CPU_SPEC_FEATURES(r5) + andi. r0,r6,CPU_FTR_L3_DISABLE_NAP + beq 1f + li r7,CPU_FTR_CAN_NAP + andc r6,r6,r7 + stw r6,CPU_SPEC_FEATURES(r5) +1: + mfspr r11,HID0 + + /* All of the bits we have to set..... + */ + ori r11,r11,HID0_SGE | HID0_FOLD | HID0_BHTE | HID0_BTIC | HID0_LRSTK +BEGIN_FTR_SECTION + oris r11,r11,HID0_DPM@h /* enable dynamic power mgmt */ +END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM) + + /* All of the bits we have to clear.... + */ + li r3,HID0_SPD | HID0_NOPDST | HID0_NOPTI + andc r11,r11,r3 /* clear SPD: enable speculative */ + li r3,0 + + mtspr ICTC,r3 /* Instruction Cache Throttling off */ + isync + mtspr HID0,r11 + sync + isync + + /* Enable L2 HW prefetch + */ + mfspr r3,SPRN_MSSCR0 + ori r3,r3,3 + sync + mtspr SPRN_MSSCR0,r3 + sync + isync + blr + +/* 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 + + .data + .balign 4 +cpu_state_storage: + .space CS_SIZE + .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, MSSCR0, etc... + */ +_GLOBAL(__save_cpu_setup) + /* Get storage ptr */ + lis r5,cpu_state_storage@h + ori r5,r5,cpu_state_storage@l + + /* Save HID0 (common to all CONFIG_6xx cpus) */ + mfspr r3,SPRN_HID0 + stw r3,CS_HID0(r5) + + /* Now deal with CPU type dependent registers */ + mfspr r3,PVR + srwi r3,r3,16 + cmpli cr0,r3,0x8000 /* 7450 */ + cmpli cr1,r3,0x000c /* 7400 */ + cmpli cr2,r3,0x800c /* 7410 */ + cmpli cr3,r3,0x8001 /* 7455 */ + cmpli cr4,r3,0x8002 /* 7457 */ + cmpli cr5,r3,0x7000 /* 750FX */ + /* cr1 is 7400 || 7410 */ + cror 4*cr1+eq,4*cr1+eq,4*cr2+eq + /* cr0 is 74xx */ + cror 4*cr0+eq,4*cr0+eq,4*cr3+eq + cror 4*cr0+eq,4*cr0+eq,4*cr4+eq + cror 4*cr0+eq,4*cr0+eq,4*cr1+eq + bne 1f + /* Backup 74xx specific regs */ + mfspr r4,SPRN_MSSCR0 + stw r4,CS_MSSCR0(r5) + mfspr r4,SPRN_MSSSR0 + stw r4,CS_MSSSR0(r5) + beq cr1,1f + /* Backup 745x specific registers */ + mfspr r4,SPRN_HID1 + stw r4,CS_HID1(r5) + mfspr r4,SPRN_ICTRL + stw r4,CS_ICTRL(r5) + mfspr r4,SPRN_LDSTCR + stw r4,CS_LDSTCR(r5) + mfspr r4,SPRN_LDSTDB + stw r4,CS_LDSTDB(r5) +1: + bne cr5,1f + /* Backup 750FX specific registers */ + mfspr r4,SPRN_HID1 + stw r4,CS_HID1(r5) +1: + blr + +/* Called with no MMU context (typically MSR:IR/DR off) to + * restore CPU state as backed up by the previous + * function. This does not include cache setting + */ +_GLOBAL(__restore_cpu_setup) + /* Get storage ptr */ + lis r5,(cpu_state_storage-KERNELBASE)@h + ori r5,r5,cpu_state_storage@l + + /* Restore HID0 */ + lwz r3,CS_HID0(r5) + sync + isync + mtspr SPRN_HID0,r3 + sync + isync + + /* Now deal with CPU type dependent registers */ + mfspr r3,PVR + srwi r3,r3,16 + cmpli cr0,r3,0x8000 /* 7450 */ + cmpli cr1,r3,0x000c /* 7400 */ + cmpli cr2,r3,0x800c /* 7410 */ + cmpli cr3,r3,0x8001 /* 7455 */ + cmpli cr4,r3,0x8002 /* 7457 */ + cmpli cr5,r3,0x7000 /* 750FX */ + /* cr1 is 7400 || 7410 */ + cror 4*cr1+eq,4*cr1+eq,4*cr2+eq + /* cr0 is 74xx */ + cror 4*cr0+eq,4*cr0+eq,4*cr3+eq + cror 4*cr0+eq,4*cr0+eq,4*cr4+eq + cror 4*cr0+eq,4*cr0+eq,4*cr1+eq + bne 2f + /* Restore 74xx specific regs */ + lwz r4,CS_MSSCR0(r5) + sync + mtspr SPRN_MSSCR0,r4 + sync + isync + lwz r4,CS_MSSSR0(r5) + sync + mtspr SPRN_MSSSR0,r4 + sync + isync + bne cr2,1f + /* Clear 7410 L2CR2 */ + li r4,0 + mtspr SPRN_L2CR2,r4 +1: beq cr1,2f + /* Restore 745x specific registers */ + lwz r4,CS_HID1(r5) + sync + mtspr SPRN_HID1,r4 + isync + sync + lwz r4,CS_ICTRL(r5) + sync + mtspr SPRN_ICTRL,r4 + isync + sync + lwz r4,CS_LDSTCR(r5) + sync + mtspr SPRN_LDSTCR,r4 + isync + sync + lwz r4,CS_LDSTDB(r5) + sync + mtspr SPRN_LDSTDB,r4 + isync + sync +2: bne cr5,1f + /* Restore 750FX specific registers + * that is restore PLL config & switch + * to PLL 0 + */ + lwz r4,CS_HID1(r5) + rlwinm r5,r4,0,16,14 + mtspr SPRN_HID1,r5 + /* Wait for PLL to stabilize */ + mftbl r5 +3: mftbl r6 + sub r6,r6,r5 + cmpli cr0,r6,10000 + ble 3b + /* Setup final PLL */ + mtspr SPRN_HID1,r4 +1: + blr + diff -Nru a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S --- a/arch/ppc/kernel/head.S Wed Apr 2 22:24:05 2003 +++ b/arch/ppc/kernel/head.S Wed Apr 2 22:24:05 2003 @@ -890,7 +890,7 @@ */ mfmsr r5 oris r5,r5,MSR_VEC@h - mtmsr r5 /* enable use of AltiVec now */ + MTMSRD(r5) /* enable use of AltiVec now */ isync /* * For SMP, we don't do lazy AltiVec switching because it just gets too @@ -962,7 +962,7 @@ mfmsr r5 oris r5,r5,MSR_VEC@h SYNC - mtmsr r5 /* enable use of AltiVec now */ + MTMSRD(r5) /* enable use of AltiVec now */ isync cmpi 0,r3,0 beqlr- /* if no previous owner, done */ @@ -999,7 +999,7 @@ ori r5,r5,MSR_FP SYNC_601 ISYNC_601 - mtmsr r5 /* enable use of fpu now */ + MTMSRD(r5) /* enable use of fpu now */ SYNC_601 isync cmpi 0,r3,0 @@ -1191,6 +1191,8 @@ MTMSRD(r0) isync #endif + /* Copy some CPU settings from CPU 0 */ + bl __restore_cpu_setup lis r3,-KERNELBASE@h mr r4,r24 @@ -1236,248 +1238,21 @@ #endif /* CONFIG_SMP */ /* - * Enable caches and 604-specific features if necessary. + * Those generic dummy functions are kept for CPUs not + * included in CONFIG_6xx */ -_GLOBAL(__setup_cpu_601) - blr -_GLOBAL(__setup_cpu_603) - b setup_common_caches -_GLOBAL(__setup_cpu_604) - mflr r4 - bl setup_common_caches - bl setup_604_hid0 - mtlr r4 - blr -_GLOBAL(__setup_cpu_750) - mflr r4 - bl setup_common_caches - bl setup_750_7400_hid0 - mtlr r4 - blr -_GLOBAL(__setup_cpu_750cx) - mflr r4 - bl setup_common_caches - bl setup_750_7400_hid0 - bl setup_750cx - mtlr r4 - blr -_GLOBAL(__setup_cpu_750fx) - mflr r4 - bl setup_common_caches - bl setup_750_7400_hid0 - bl setup_750fx - mtlr r4 - blr -_GLOBAL(__setup_cpu_7400) - mflr r4 - bl setup_7400_workarounds - bl setup_common_caches - bl setup_750_7400_hid0 - mtlr r4 - blr -_GLOBAL(__setup_cpu_7410) - mflr r4 - bl setup_7410_workarounds - bl setup_common_caches - bl setup_750_7400_hid0 - li r3,0 - mtspr SPRN_L2CR2,r3 - mtlr r4 - blr -_GLOBAL(__setup_cpu_7450) - mflr r4 - bl setup_common_caches - bl setup_745x_specifics - mtlr r4 - blr -_GLOBAL(__setup_cpu_7455) - mflr r4 - bl setup_common_caches - bl setup_745x_specifics - mtlr r4 - blr _GLOBAL(__setup_cpu_power3) blr _GLOBAL(__setup_cpu_generic) blr -/* Enable caches for 603's, 604, 750 & 7400 */ -setup_common_caches: - mfspr r11,HID0 - andi. r0,r11,HID0_DCE -#ifdef CONFIG_DCACHE_DISABLE - ori r11,r11,HID0_ICE -#else - ori r11,r11,HID0_ICE|HID0_DCE -#endif - ori r8,r11,HID0_ICFI - bne 1f /* don't invalidate the D-cache */ - ori r8,r8,HID0_DCI /* unless it wasn't enabled */ -1: sync - mtspr HID0,r8 /* enable and invalidate caches */ - sync - mtspr HID0,r11 /* enable caches */ - sync - isync - blr - -/* 604, 604e, 604ev, ... - * Enable superscalar execution & branch history table - */ -setup_604_hid0: - mfspr r11,HID0 - ori r11,r11,HID0_SIED|HID0_BHTE - ori r8,r11,HID0_BTCD - sync - mtspr HID0,r8 /* flush branch target address cache */ - sync /* on 604e/604r */ - mtspr HID0,r11 - sync - isync - blr - -/* 7400 <= rev 2.7 and 7410 rev = 1.0 suffer from some - * errata we work around here. - * Moto MPC710CE.pdf describes them, those are errata - * #3, #4 and #5 - * Note that we assume the firmware didn't choose to - * apply other workarounds (there are other ones documented - * in the .pdf). It appear that Apple firmware only works - * around #3 and with the same fix we use. We may want to - * check if the CPU is using 60x bus mode in which case - * the workaround for errata #4 is useless. Also, we may - * want to explicitely clear HID0_NOPDST as this is not - * needed once we have applied workaround #5 (though it's - * not set by Apple's firmware at least). - */ -setup_7400_workarounds: - mfpvr r3 - rlwinm r3,r3,0,20,31 - cmpwi 0,r3,0x0207 - ble 1f - blr -setup_7410_workarounds: - mfpvr r3 - rlwinm r3,r3,0,20,31 - cmpwi 0,r3,0x0100 - bnelr -1: - mfspr r11,SPRN_MSSSR0 - /* Errata #3: Set L1OPQ_SIZE to 0x10 */ - rlwinm r11,r11,0,9,6 - oris r11,r11,0x0100 - /* Errata #4: Set L2MQ_SIZE to 1 (check for MPX mode first ?) */ - oris r11,r11,0x0002 - /* Errata #5: Set DRLT_SIZE to 0x01 */ - rlwinm r11,r11,0,5,2 - oris r11,r11,0x0800 - sync - mtspr SPRN_MSSSR0,r11 - sync - isync - blr - -/* 740/750/7400/7410 - * Enable Store Gathering (SGE), Address Brodcast (ABE), - * Branch History Table (BHTE), Branch Target ICache (BTIC) - * Dynamic Power Management (DPM), Speculative (SPD) - * Clear Instruction cache throttling (ICTC) - */ -setup_750_7400_hid0: - mfspr r11,HID0 - ori r11,r11,HID0_SGE | HID0_ABE | HID0_BHTE | HID0_BTIC -BEGIN_FTR_SECTION - oris r11,r11,HID0_DPM@h /* enable dynamic power mgmt */ -END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM) - li r3,HID0_SPD - andc r11,r11,r3 /* clear SPD: enable speculative */ - li r3,0 - mtspr ICTC,r3 /* Instruction Cache Throttling off */ - isync - mtspr HID0,r11 - sync - isync - blr - -/* 750cx specific - * Looks like we have to disable NAP feature for some PLL settings... - * (waiting for confirmation) - */ -setup_750cx: - mfspr r10, SPRN_HID1 - rlwinm r10,r10,4,28,31 - cmpi cr0,r10,7 - cmpi cr1,r10,9 - cmpi cr2,r10,11 - cror 4*cr0+eq,4*cr0+eq,4*cr1+eq - cror 4*cr0+eq,4*cr0+eq,4*cr2+eq - bnelr - lwz r6,CPU_SPEC_FEATURES(r5) - li r7,CPU_FTR_CAN_NAP - andc r6,r6,r7 - stw r6,CPU_SPEC_FEATURES(r5) +#ifndef CONFIG_6xx +_GLOBAL(__save_cpu_setup) blr - -/* 750fx specific - */ -setup_750fx: +_GLOBAL(__restore_cpu_setup) blr +#endif /* CONFIG_6xx */ -/* MPC 745x - * Enable Store Gathering (SGE), Branch Folding (FOLD) - * Branch History Table (BHTE), Branch Target ICache (BTIC) - * Dynamic Power Management (DPM), Speculative (SPD) - * Ensure our data cache instructions really operate. - * Timebase has to be running or we wouldn't have made it here, - * just ensure we don't disable it. - * Clear Instruction cache throttling (ICTC) - * Enable L2 HW prefetch - */ -setup_745x_specifics: - /* We check for the presence of an L3 cache setup by - * the firmware. If any, we disable NAP capability as - * it's known to be bogus on rev 2.1 and earlier - */ - mfspr r11,SPRN_L3CR - andis. r11,r11,L3CR_L3E@h - beq 1f - lwz r6,CPU_SPEC_FEATURES(r5) - andi. r0,r6,CPU_FTR_L3_DISABLE_NAP - beq 1f - li r7,CPU_FTR_CAN_NAP - andc r6,r6,r7 - stw r6,CPU_SPEC_FEATURES(r5) -1: - mfspr r11,HID0 - - /* All of the bits we have to set..... - */ - ori r11,r11,HID0_SGE | HID0_FOLD | HID0_BHTE | HID0_BTIC | HID0_LRSTK -BEGIN_FTR_SECTION - oris r11,r11,HID0_DPM@h /* enable dynamic power mgmt */ -END_FTR_SECTION_IFCLR(CPU_FTR_NO_DPM) - - /* All of the bits we have to clear.... - */ - li r3,HID0_SPD | HID0_NOPDST | HID0_NOPTI - andc r11,r11,r3 /* clear SPD: enable speculative */ - li r3,0 - - mtspr ICTC,r3 /* Instruction Cache Throttling off */ - isync - mtspr HID0,r11 - sync - isync - - /* Enable L2 HW prefetch - */ - mfspr r3,SPRN_MSSCR0 - ori r3,r3,3 - sync - mtspr SPRN_MSSCR0,r3 - sync - isync - blr /* * Load stuff into the MMU. Intended to be called with diff -Nru a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S --- a/arch/ppc/kernel/misc.S Wed Apr 2 22:24:07 2003 +++ b/arch/ppc/kernel/misc.S Wed Apr 2 22:24:07 2003 @@ -201,6 +201,60 @@ mr r4,r24 bctr +#ifdef CONFIG_CPU_FREQ_PMAC + +/* This gets called by via-pmu.c to switch the PLL selection + * on 750fx CPU. This function should really be moved to some + * other place (as most of the cpufreq code in via-pmu + */ +_GLOBAL(low_choose_750fx_pll) + /* Clear MSR:EE */ + mfmsr r7 + rlwinm r0,r7,0,17,15 + mtmsr r0 + + /* If switching to PLL1, disable HID0:BTIC */ + cmpli cr0,r3,0 + beq 1f + mfspr r5,HID0 + rlwinm r5,r5,0,27,25 + sync + mtspr HID0,r5 + isync + sync + +1: + /* Calc new HID1 value */ + mfspr r4,SPRN_HID1 /* Build a HID1:PS bit from parameter */ + rlwinm r5,r3,16,15,15 /* Clear out HID1:PS from value read */ + rlwinm r4,r4,0,16,14 /* Could have I used rlwimi here ? */ + or r4,r4,r5 + mtspr SPRN_HID1,r4 + + /* Store new HID1 image */ + rlwinm r6,r1,0,0,18 + lwz r6,TI_CPU(r6) + slwi r6,r6,2 + addis r6,r6,nap_save_hid1@ha + stw r4,nap_save_hid1@l(r6) + + /* If switching to PLL0, enable HID0:BTIC */ + cmpli cr0,r3,0 + bne 1f + mfspr r5,HID0 + ori r5,r5,HID0_BTIC + sync + mtspr HID0,r5 + isync + sync + +1: + /* Return */ + mtmsr r7 + blr + +#endif /* CONFIG_CPU_FREQ_PMAC */ + /* void local_save_flags_ptr(unsigned long *flags) */ _GLOBAL(local_save_flags_ptr) mfmsr r4 @@ -351,7 +405,16 @@ sync /* Flush to memory before changing mapping */ tlbia isync /* Flush shadow TLB */ -#else /* ! defined(CONFIG_40x) */ +#elif defined(CONFIG_440) + lis r3,0 + sync +1: + tlbwe r3,r3,PPC440_TLB_PAGEID + addi r3,r3,1 + cmpwi 0,r3,61 + ble 1b + isync +#else /* !(CONFIG_40x || CONFIG_440) */ #if defined(CONFIG_SMP) rlwinm r8,r1,0,0,18 lwz r8,TI_CPU(r8) @@ -392,7 +455,7 @@ * Flush MMU TLB for a particular address */ _GLOBAL(_tlbie) -#ifdef CONFIG_40x +#if defined(CONFIG_40x) tlbsx. r3, 0, r3 bne 10f sync @@ -402,7 +465,31 @@ tlbwe r3, r3, TLB_TAG isync 10: -#else /* ! CONFIG_40x */ +#elif defined(CONFIG_440) + mfspr r4,SPRN_MMUCR /* Get MMUCR */ + lis r5,PPC440_MMUCR_STS@h + ori r5,r5,PPC440_MMUCR_TID@l /* Create mask */ + andc r4,r4,r5 /* Clear out TID/STS bits */ + mfspr r5,SPRN_PID /* Get PID */ + or r4,r4,r5 /* Set TID bits */ + mfmsr r6 /* Get MSR */ + andi. r6,r6,MSR_IS@l /* TS=1? */ + beq 11f /* If not, leave STS=0 */ + oris r4,r4,PPC440_MMUCR_STS@h /* Set STS=1 */ +11: mtspr SPRN_MMUCR, r4 /* Put MMUCR */ + + tlbsx. r3, 0, r3 + bne 10f + sync + /* There are only 64 TLB entries, so r3 < 64, + * which means bit 22, is clear. Since 22 is + * the V bit in the TLB_PAGEID, loading this + * value will invalidate the TLB entry. + */ + tlbwe r3, r3, PPC440_TLB_PAGEID + isync +10: +#else /* !(CONFIG_40x || CONFIG_440) */ #if defined(CONFIG_SMP) rlwinm r8,r1,0,0,18 lwz r8,TI_CPU(r8) @@ -569,22 +656,18 @@ blr #ifdef CONFIG_NOT_COHERENT_CACHE -/* This is a bad one....It is used by 'consistent_sync' functions when - * there isn't any handle on the virtual address needed by the usual - * cache flush instructions. On the MPC8xx, we can use the cache line - * flush command, on others all we can do is read enough data to completely - * reload the cache, flushing old data out. - */ - -/* Cache organization. The 4xx has a 8K (128 line) cache, and the 8xx - * has 1, 2, 4, 8K variants. For now, cover worst case. When we can - * deteremine actual size, we will use that later. +/* + * 40x cores have 8K or 16K dcache and 32 byte line size. + * 440 has a 32K dcache and 32 byte line size. + * 8xx has 1, 2, 4, 8K variants. + * For now, cover the worst case of the 440. + * Must be called with external interrupts disabled. */ -#define CACHE_NWAYS 2 -#define CACHE_NLINES 128 +#define CACHE_NWAYS 64 +#define CACHE_NLINES 16 _GLOBAL(flush_dcache_all) - li r4, (CACHE_NWAYS * CACHE_NLINES) + li r4, (2 * CACHE_NWAYS * CACHE_NLINES) mtctr r4 lis r5, KERNELBASE@h 1: lwz r3, 0(r5) /* Load one word from every line */ diff -Nru a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c --- a/arch/ppc/kernel/smp.c Wed Apr 2 22:24:07 2003 +++ b/arch/ppc/kernel/smp.c Wed Apr 2 22:24:07 2003 @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -68,6 +67,9 @@ static int __smp_call_function(void (*func) (void *info), void *info, int wait, int target); +/* Low level assembly function used to backup CPU 0 state */ +extern void __save_cpu_setup(void); + /* Since OpenPIC has only 4 IPIs, we use slightly different message numbers. * * Make sure this matches openpic_request_IPIs in open_pic.c, or what shows up @@ -348,6 +350,9 @@ /* Probe platform for CPUs: always linear. */ num_cpus = smp_ops->probe(); cpu_possible_map = (1 << num_cpus)-1; + + /* Backup CPU 0 state */ + __save_cpu_setup(); if (smp_ops->space_timers) smp_ops->space_timers(num_cpus); diff -Nru a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile --- a/arch/ppc/platforms/Makefile Wed Apr 2 22:24:08 2003 +++ b/arch/ppc/platforms/Makefile Wed Apr 2 22:24:08 2003 @@ -19,12 +19,14 @@ obj-$(CONFIG_ALL_PPC) += pmac_pic.o pmac_setup.o pmac_time.o \ pmac_feature.o pmac_pci.o chrp_setup.o\ chrp_time.o chrp_pci.o prep_pci.o \ - prep_time.o prep_setup.o + prep_time.o prep_setup.o pmac_sleep.o ifeq ($(CONFIG_ALL_PPC),y) obj-$(CONFIG_NVRAM) += pmac_nvram.o endif obj-$(CONFIG_PMAC_BACKLIGHT) += pmac_backlight.o -obj-$(CONFIG_PMAC_PBOOK) += sleep.o +ifeq ($(CONFIG_ALL_PPC),y) +obj-$(CONFIG_CPU_FREQ_PMAC) += pmac_cpufreq.o +endif obj-$(CONFIG_PPC_RTAS) += error_log.o proc_rtas.o obj-$(CONFIG_PREP_RESIDUAL) += residual.o obj-$(CONFIG_ADIR) += adir_setup.o adir_pic.o adir_pci.o diff -Nru a/arch/ppc/platforms/chrp_smp.c b/arch/ppc/platforms/chrp_smp.c --- a/arch/ppc/platforms/chrp_smp.c Wed Apr 2 22:24:05 2003 +++ b/arch/ppc/platforms/chrp_smp.c Wed Apr 2 22:24:05 2003 @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include diff -Nru a/arch/ppc/platforms/pmac_cpufreq.c b/arch/ppc/platforms/pmac_cpufreq.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/platforms/pmac_cpufreq.c Wed Apr 2 22:24:08 2003 @@ -0,0 +1,345 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG_FREQ + +extern void low_choose_750fx_pll(int pll); +extern void low_sleep_handler(void); +extern void openpic_sleep_save_intrs(void); +extern void openpic_sleep_restore_intrs(void); +extern void enable_kernel_altivec(void); +extern void enable_kernel_fp(void); + +static unsigned int low_freq; +static unsigned int hi_freq; +static unsigned int cur_freq; +static int cpufreq_uses_pmu; + +#define PMAC_CPU_LOW_SPEED 1 +#define PMAC_CPU_HIGH_SPEED 0 + +static inline void +wakeup_decrementer(void) +{ + set_dec(tb_ticks_per_jiffy); + /* No currently-supported powerbook has a 601, + * so use get_tbl, not native + */ + last_jiffy_stamp(0) = tb_last_stamp = get_tbl(); +} + +#ifdef DEBUG_FREQ +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 + * core cpufreq framework's own calculation. + */ + extern void calibrate_delay(void); + + unsigned long save_lpj = loops_per_jiffy; + calibrate_delay(); + loops_per_jiffy = save_lpj; +} +#endif + +/* Switch CPU speed under 750FX CPU control + */ +static int __pmac +cpu_750fx_cpu_speed(int low_speed) +{ +#ifdef DEBUG_FREQ + printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1)); +#endif + low_choose_750fx_pll(low_speed); +#ifdef DEBUG_FREQ + printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1)); + debug_calc_bogomips(); +#endif + + return 0; +} + +/* Switch CPU speed under PMU control + */ +static int __pmac +pmu_set_cpu_speed(unsigned int low_speed) +{ + struct adb_request req; + unsigned long save_l2cr; + unsigned long save_l3cr; + +#ifdef DEBUG_FREQ + printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1)); +#endif + /* Disable all interrupt sources on openpic */ + openpic_sleep_save_intrs(); + + /* Make sure the PMU is idle */ + pmu_suspend(); + + /* Make sure the decrementer won't interrupt us */ + asm volatile("mtdec %0" : : "r" (0x7fffffff)); + /* Make sure any pending DEC interrupt occuring while we did + * the above didn't re-enable the DEC */ + mb(); + asm volatile("mtdec %0" : : "r" (0x7fffffff)); + + /* We can now disable MSR_EE */ + local_irq_disable(); + + /* Giveup the FPU & vec */ + enable_kernel_fp(); + +#ifdef CONFIG_ALTIVEC + if (cur_cpu_spec[0]->cpu_features & CPU_FTR_ALTIVEC) + enable_kernel_altivec(); +#endif /* CONFIG_ALTIVEC */ + + /* Save & disable L2 and L3 caches */ + save_l3cr = _get_L3CR(); /* (returns -1 if not available) */ + save_l2cr = _get_L2CR(); /* (returns -1 if not available) */ + if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0) + _set_L3CR(save_l3cr & 0x7fffffff); + if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0) + _set_L2CR(save_l2cr & 0x7fffffff); + + /* Send the new speed command. My assumption is that this command + * will cause PLL_CFG[0..3] to be changed next time CPU goes to sleep + */ + pmu_request(&req, NULL, 6, PMU_CPU_SPEED, 'W', 'O', 'O', 'F', low_speed); + while (!req.complete) + pmu_poll(); + + pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,1,1); + + low_sleep_handler(); + + pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,1,0); + + /* Restore L2 cache */ + if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0) + _set_L2CR(save_l2cr); + /* Restore L3 cache */ + if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0) + _set_L3CR(save_l3cr); + + /* Restore userland MMU context */ + set_context(current->active_mm->context, current->active_mm->pgd); + +#ifdef DEBUG_FREQ + printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1)); +#endif + + /* Restore decrementer */ + wakeup_decrementer(); + + /* Restore interrupts */ + openpic_sleep_restore_intrs(); + + pmu_resume(); + + /* Let interrupts flow again ... */ + local_irq_enable(); + +#ifdef DEBUG_FREQ + debug_calc_bogomips(); +#endif + + return 0; +} + +static int __pmac +do_set_cpu_speed(int speed_mode) +{ + struct cpufreq_freqs freqs; + int rc; + + freqs.old = cur_freq; + freqs.new = (speed_mode == PMAC_CPU_HIGH_SPEED) ? hi_freq : low_freq; + freqs.cpu = CPUFREQ_ALL_CPUS; + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + if (cpufreq_uses_pmu) + rc = pmu_set_cpu_speed(speed_mode); + else + rc = cpu_750fx_cpu_speed(speed_mode); + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + cur_freq = (speed_mode == PMAC_CPU_HIGH_SPEED) ? hi_freq : low_freq; + + return rc; +} + +static int __pmac +pmac_cpufreq_verify(struct cpufreq_policy *policy) +{ + if (!policy) + return -EINVAL; + + policy->cpu = 0; /* UP only */ + + cpufreq_verify_within_limits(policy, low_freq, hi_freq); + + if ((policy->min > low_freq) && + (policy->max < hi_freq)) + policy->max = hi_freq; + + return 0; +} + +static int __pmac +pmac_cpufreq_setpolicy(struct cpufreq_policy *policy) +{ + int rc; + + if (!policy) + return -EINVAL; + if (policy->min > low_freq) + rc = do_set_cpu_speed(PMAC_CPU_HIGH_SPEED); + else if (policy->max < hi_freq) + rc = do_set_cpu_speed(PMAC_CPU_LOW_SPEED); + else if (policy->policy == CPUFREQ_POLICY_POWERSAVE) + rc = do_set_cpu_speed(PMAC_CPU_LOW_SPEED); + else + rc = do_set_cpu_speed(PMAC_CPU_HIGH_SPEED); + + return rc; +} + +unsigned int __pmac +pmac_get_one_cpufreq(int i) +{ + /* Supports only one CPU for now */ + return (i == 0) ? cur_freq : 0; +} + + +/* Currently, we support the following machines: + * + * - 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) + */ +static int __init +pmac_cpufreq_setup(void) +{ + struct device_node *cpunode; + struct cpufreq_driver *driver; + u32 *value; + int has_freq_ctl = 0; + int rc; + + memset(&driver, 0, sizeof(driver)); + + /* Assume only one CPU */ + cpunode = find_type_devices("cpu"); + if (!cpunode) + goto out; + + /* Get current cpu clock freq */ + value = (u32 *)get_property(cpunode, "clock-frequency", NULL); + if (!value) + goto out; + cur_freq = (*value) / 1000; + + /* Check for tibook 800Mhz or 1Ghz */ + if (machine_is_compatible("PowerBook3,4") || machine_is_compatible("PowerBook3,5")) { + value = (u32 *)get_property(cpunode, "min-clock-frequency", NULL); + if (!value) + goto out; + low_freq = (*value) / 1000; + + value = (u32 *)get_property(cpunode, "max-clock-frequency", NULL); + if (!value) + goto out; + hi_freq = (*value) / 1000; + has_freq_ctl = 1; + cpufreq_uses_pmu = 1; + } + /* Else check for iBook2 500 */ + else if (machine_is_compatible("PowerBook4,1")) { + /* We only know about 500Mhz model */ + if (cur_freq < 450000 || cur_freq > 550000) + goto out; + hi_freq = cur_freq; + low_freq = 400000; + has_freq_ctl = 1; + cpufreq_uses_pmu = 1; + } + /* Else check for TiPb 500 */ + else if (machine_is_compatible("PowerBook3,2")) { + /* We only know about 500Mhz model */ + if (cur_freq < 450000 || cur_freq > 550000) + goto out; + hi_freq = cur_freq; + low_freq = 300000; + has_freq_ctl = 1; + cpufreq_uses_pmu = 1; + } + /* Else check for 750FX */ + else if (PVR_VER(mfspr(PVR)) == 0x7000) { + if (get_property(cpunode, "dynamic-power-step", NULL) == NULL) + goto out; + hi_freq = cur_freq; + value = (u32 *)get_property(cpunode, "reduced-clock-frequency", NULL); + if (!value) + goto out; + low_freq = (*value) / 1000; + cpufreq_uses_pmu = 0; + has_freq_ctl = 1; + } +out: + if (!has_freq_ctl) + return -ENODEV; + + /* initialization of main "cpufreq" code*/ + driver = kmalloc(sizeof(struct cpufreq_driver) + + NR_CPUS * sizeof(struct cpufreq_policy), GFP_KERNEL); + if (!driver) + return -ENOMEM; + + driver->policy = (struct cpufreq_policy *) (driver + 1); + + driver->verify = &pmac_cpufreq_verify; + driver->setpolicy = &pmac_cpufreq_setpolicy; + driver->init = NULL; + driver->exit = NULL; + strncpy(driver->name, "powermac", CPUFREQ_NAME_LEN); + + driver->policy[0].cpu = 0; + driver->policy[0].cpuinfo.transition_latency = CPUFREQ_ETERNAL; + driver->policy[0].cpuinfo.min_freq = low_freq; + driver->policy[0].min = low_freq; + driver->policy[0].max = cur_freq; + driver->policy[0].cpuinfo.max_freq = cur_freq; + driver->policy[0].policy = (cur_freq == low_freq) ? + CPUFREQ_POLICY_POWERSAVE : CPUFREQ_POLICY_PERFORMANCE; + + rc = cpufreq_register_driver(driver); + if (rc) + kfree(driver); + return rc; +} + +__initcall(pmac_cpufreq_setup); + diff -Nru a/arch/ppc/platforms/pmac_feature.c b/arch/ppc/platforms/pmac_feature.c --- a/arch/ppc/platforms/pmac_feature.c Wed Apr 2 22:24:07 2003 +++ b/arch/ppc/platforms/pmac_feature.c Wed Apr 2 22:24:07 2003 @@ -14,6 +14,8 @@ * - Replace mdelay with some schedule loop if possible * - Shorten some obfuscated delays on some routines (like modem * power) + * - Refcount some clocks (see darwin) + * - Split split split... * */ #include @@ -25,6 +27,8 @@ #include #include #include +#include +#include #include #include #include @@ -34,8 +38,10 @@ #include #include #include +#include #include #include +#include #undef DEBUG_FEATURE @@ -46,7 +52,8 @@ #endif /* Exported from arch/ppc/kernel/idle.c */ -extern unsigned long powersave_nap; +extern int powersave_nap; +extern int powersave_lowspeed; /* * We use a single global lock to protect accesses. Each driver has @@ -57,53 +64,13 @@ #define LOCK(flags) spin_lock_irqsave(&feature_lock, flags); #define UNLOCK(flags) spin_unlock_irqrestore(&feature_lock, flags); + /* - * Helper functions regarding the various flavors of mac-io + * Instance of some macio stuffs */ - -#define MAX_MACIO_CHIPS 2 +struct macio_chip macio_chips[MAX_MACIO_CHIPS] __pmacdata; -enum { - macio_unknown = 0, - macio_grand_central, - macio_ohare, - macio_ohareII, - macio_heathrow, - macio_gatwick, - macio_paddington, - macio_keylargo, - macio_pangea -}; - -static const char* macio_names[] __pmacdata = -{ - "Unknown", - "Grand Central", - "OHare", - "OHareII", - "Heathrow", - "Gatwick", - "Paddington", - "Keylargo", - "Pangea" -}; - -static struct macio_chip -{ - struct device_node* of_node; - int type; - int rev; - volatile u32* base; - unsigned long flags; -} macio_chips[MAX_MACIO_CHIPS] __pmacdata; - -#define MACIO_FLAG_SCCA_ON 0x00000001 -#define MACIO_FLAG_SCCB_ON 0x00000002 -#define MACIO_FLAG_SCC_LOCKED 0x00000004 -#define MACIO_FLAG_AIRPORT_ON 0x00000010 -#define MACIO_FLAG_FW_SUPPORTED 0x00000020 - -static struct macio_chip* __pmac +struct macio_chip* __pmac macio_find(struct device_node* child, int type) { while(child) { @@ -118,15 +85,21 @@ return NULL; } -#define MACIO_FCR32(macio, r) ((macio)->base + ((r) >> 2)) -#define MACIO_FCR8(macio, r) (((volatile u8*)((macio)->base)) + (r)) +static const char* macio_names[] __pmacdata = +{ + "Unknown", + "Grand Central", + "OHare", + "OHareII", + "Heathrow", + "Gatwick", + "Paddington", + "Keylargo", + "Pangea", + "Intrepid" +}; + -#define MACIO_IN32(r) (in_le32(MACIO_FCR32(macio,r))) -#define MACIO_OUT32(r,v) (out_le32(MACIO_FCR32(macio,r), (v))) -#define MACIO_BIS(r,v) (MACIO_OUT32((r), MACIO_IN32(r) | (v))) -#define MACIO_BIC(r,v) (MACIO_OUT32((r), MACIO_IN32(r) & ~(v))) -#define MACIO_IN8(r) (in_8(MACIO_FCR8(macio,r))) -#define MACIO_OUT8(r,v) (out_8(MACIO_FCR8(macio,r), (v))) /* * Uninorth reg. access. Note that Uni-N regs are big endian @@ -196,7 +169,7 @@ unsigned long chan_mask; unsigned long fcr; unsigned long flags; - int htw; + int htw, trans; unsigned long rmask; macio = macio_find(node, 0); @@ -211,6 +184,9 @@ htw = (macio->type == macio_heathrow || macio->type == macio_paddington || macio->type == macio_gatwick); + /* On these machines, the HRW_SCC_TRANS_EN_N bit mustn't be touched */ + trans = (pmac_mb.model_id != PMAC_TYPE_YOSEMITE && + pmac_mb.model_id != PMAC_TYPE_YIKES); if (value) { #ifdef CONFIG_ADB_PMU if ((param & 0xfff) == PMAC_SCC_IRDA) @@ -222,7 +198,13 @@ if (!(fcr & OH_SCC_ENABLE)) { fcr |= OH_SCC_ENABLE; if (htw) { - fcr &= ~HRW_SCC_TRANS_EN_N; + /* Side effect: this will also power up the + * modem, but it's too messy to figure out on which + * ports this controls the tranceiver and on which + * it controls the modem + */ + if (trans) + fcr &= ~HRW_SCC_TRANS_EN_N; MACIO_OUT32(OHARE_FCR, fcr); fcr |= (rmask = HRW_RESET_SCC); MACIO_OUT32(OHARE_FCR, fcr); @@ -258,7 +240,7 @@ MACIO_OUT32(OHARE_FCR, fcr); if ((fcr & (OH_SCCA_IO | OH_SCCB_IO)) == 0) { fcr &= ~OH_SCC_ENABLE; - if (htw) + if (htw && trans) fcr |= HRW_SCC_TRANS_EN_N; MACIO_OUT32(OHARE_FCR, fcr); } @@ -330,9 +312,9 @@ if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0) return -EPERM; - if (value) { + if (value == 1) { MACIO_BIC(OHARE_FCR, OH_IOBUS_ENABLE); - } else { + } else if (value == 0) { MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE); } @@ -522,7 +504,7 @@ return 0; } -static u32 save_fcr[5] __pmacdata; +static u32 save_fcr[6] __pmacdata; static u32 save_mbcr __pmacdata; static u32 save_gpio_levels[2] __pmacdata; static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT] __pmacdata; @@ -586,6 +568,7 @@ /* This seems to be necessary as well or the fan * keeps coming up and battery drains fast */ MACIO_BIC(HEATHROW_FCR, HRW_IOBUS_ENABLE); + MACIO_BIC(HEATHROW_FCR, HRW_IDE0_RESET_N); /* Make sure eth is down even if module or sleep * won't work properly */ MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE | HRW_BMAC_RESET); @@ -750,7 +733,13 @@ struct macio_chip* macio; u8 gpio; unsigned long flags; - + + /* Hack for internal USB modem */ + if (node == NULL) { + if (macio_chips[0].type != macio_keylargo) + return -ENODEV; + node = macio_chips[0].of_node; + } macio = macio_find(node, 0); if (!macio) return -ENODEV; @@ -791,8 +780,96 @@ } static int __pmac +pangea_modem_enable(struct device_node* node, int param, int value) +{ + struct macio_chip* macio; + u8 gpio; + unsigned long flags; + + /* Hack for internal USB modem */ + if (node == NULL) { + if (macio_chips[0].type != macio_pangea && + macio_chips[0].type != macio_intrepid) + return -ENODEV; + node = macio_chips[0].of_node; + } + macio = macio_find(node, 0); + if (!macio) + return -ENODEV; + gpio = MACIO_IN8(KL_GPIO_MODEM_RESET); + gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE; + gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA; + + if (!value) { + LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio); + UNLOCK(flags); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + mdelay(250); + } + LOCK(flags); + if (value) { + MACIO_OUT8(KL_GPIO_MODEM_POWER, + KEYLARGO_GPIO_OUTPUT_ENABLE); + UNLOCK(flags); + (void)MACIO_IN32(KEYLARGO_FCR2); + mdelay(250); + } else { + MACIO_OUT8(KL_GPIO_MODEM_POWER, + KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA); + UNLOCK(flags); + } + if (value) { + LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); LOCK(flags); + MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA); + (void)MACIO_IN8(KL_GPIO_MODEM_RESET); + UNLOCK(flags); mdelay(250); + } + return 0; +} + +static int __pmac +core99_ata100_enable(struct device_node* node, int value) +{ + unsigned long flags; + struct pci_dev *pdev = NULL; + u8 pbus, pid; + + if (uninorth_rev < 0x24) + return -ENODEV; + + LOCK(flags); + if (value) + UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_ATA100); + else + UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_ATA100); + (void)UN_IN(UNI_N_CLOCK_CNTL); + UNLOCK(flags); + udelay(20); + + if (value) { + if (pci_device_from_OF_node(node, &pbus, &pid) == 0) + pdev = pci_find_slot(pbus, pid); + if (pdev == NULL) + return 0; + pci_enable_device(pdev); + pci_set_master(pdev); + } + return 0; +} + +static int __pmac core99_ide_enable(struct device_node* node, int param, int value) { + /* Bus ID 0 to 2 are KeyLargo based IDE, busID 3 is U2 + * based ata-100 + */ switch(param) { case 0: return simple_feature_tweak(node, macio_unknown, @@ -803,6 +880,8 @@ case 2: return simple_feature_tweak(node, macio_unknown, KEYLARGO_FCR1, KL1_UIDE_ENABLE, value); + case 3: + return core99_ata100_enable(node, value); default: return -ENODEV; } @@ -850,7 +929,8 @@ struct macio_chip* macio; macio = &macio_chips[0]; - if (macio->type != macio_keylargo && macio->type != macio_pangea) + if (macio->type != macio_keylargo && macio->type != macio_pangea && + macio->type != macio_intrepid) return -ENODEV; LOCK(flags); @@ -987,27 +1067,40 @@ static int __pmac core99_reset_cpu(struct device_node* node, int param, int value) { - const int reset_lines[] = { KL_GPIO_RESET_CPU0, - KL_GPIO_RESET_CPU1, - KL_GPIO_RESET_CPU2, - KL_GPIO_RESET_CPU3 }; - int reset_io; + unsigned int reset_io = 0; unsigned long flags; struct macio_chip* macio; + struct device_node* np; + const int dflt_reset_lines[] = { KL_GPIO_RESET_CPU0, + KL_GPIO_RESET_CPU1, + KL_GPIO_RESET_CPU2, + KL_GPIO_RESET_CPU3 }; macio = &macio_chips[0]; - if (macio->type != macio_keylargo && macio->type != macio_pangea) + if (macio->type != macio_keylargo) return -ENODEV; - if (param > 3 || param < 0) + + np = find_path_device("/cpus"); + if (np == NULL) return -ENODEV; - - reset_io = reset_lines[param]; + 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) + reset_io = dflt_reset_lines[param]; LOCK(flags); MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE); (void)MACIO_IN8(reset_io); udelay(1); - MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA); + MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTOUT_DATA | KEYLARGO_GPIO_OUTPUT_ENABLE); (void)MACIO_IN8(reset_io); UNLOCK(flags); @@ -1025,15 +1118,19 @@ u32 reg; macio = &macio_chips[0]; - if (macio->type != macio_keylargo && macio->type != macio_pangea) + if (macio->type != macio_keylargo && macio->type != macio_pangea && + 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; - if (strncmp(prop, "usb0u048", strlen("usb0u048")) == 0) + if (strncmp(prop, "usb0u048", 8) == 0) number = 0; - else if (strncmp(prop, "usb1u148", strlen("usb1u148")) == 0) + else if (strncmp(prop, "usb1u148", 8) == 0) number = 2; else return -ENODEV; @@ -1104,7 +1201,8 @@ struct macio_chip* macio; macio = &macio_chips[0]; - if (macio->type != macio_keylargo && macio->type != macio_pangea) + if (macio->type != macio_keylargo && macio->type != macio_pangea && + macio->type != macio_intrepid) return -ENODEV; if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED)) return -ENODEV; @@ -1133,7 +1231,8 @@ if ((pmac_mb.board_flags & PMAC_MB_HAS_FW_POWER) == 0) return -ENODEV; macio = &macio_chips[0]; - if (macio->type != macio_keylargo && macio->type != macio_pangea) + if (macio->type != macio_keylargo && macio->type != macio_pangea && + macio->type != macio_intrepid) return -ENODEV; if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED)) return -ENODEV; @@ -1172,23 +1271,24 @@ } static void __pmac -keylargo_shutdown(struct macio_chip* macio, int restart) +keylargo_shutdown(struct macio_chip* macio, int sleep_mode) { u32 temp; - mdelay(1); - MACIO_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND); - (void)MACIO_IN32(KEYLARGO_FCR0); - mdelay(100); + if (sleep_mode) { + mdelay(1); + MACIO_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND); + (void)MACIO_IN32(KEYLARGO_FCR0); + mdelay(1); + } MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE | KL0_SCC_CELL_ENABLE | KL0_IRDA_ENABLE | KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE); - - (void)MACIO_IN32(KEYLARGO_FCR0); udelay(10); + MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK); - (void)MACIO_IN32(KEYLARGO_MBCR); udelay(10); + MACIO_BIS(KEYLARGO_MBCR, KL_MBCR_MB0_IDE_ENABLE); MACIO_BIC(KEYLARGO_FCR1, KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT | @@ -1199,27 +1299,33 @@ KL1_EIDE0_ENABLE | KL1_EIDE0_RESET_N | KL1_EIDE1_ENABLE | KL1_EIDE1_RESET_N | KL1_UIDE_ENABLE); - (void)MACIO_IN32(KEYLARGO_FCR1); udelay(10); MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT); - udelay(10); MACIO_BIC(KEYLARGO_FCR2, KL2_IOBUS_ENABLE); - udelay(10); + temp = MACIO_IN32(KEYLARGO_FCR3); - if (macio->rev >= 2) - temp |= (KL3_SHUTDOWN_PLL2X | KL3_SHUTDOWN_PLL_TOTAL); - + if (macio->rev >= 2) { + temp |= KL3_SHUTDOWN_PLL2X; + if (sleep_mode) + temp |= KL3_SHUTDOWN_PLL_TOTAL; + } + temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 | - KL3_SHUTDOWN_PLLKW35 | KL3_SHUTDOWN_PLLKW12; + KL3_SHUTDOWN_PLLKW35; + if (sleep_mode) + temp |= KL3_SHUTDOWN_PLLKW12; temp &= ~(KL3_CLK66_ENABLE | KL3_CLK49_ENABLE | KL3_CLK45_ENABLE - | KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE - | KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE); + | KL3_CLK31_ENABLE | KL3_I2S1_CLK18_ENABLE | KL3_I2S0_CLK18_ENABLE); + if (sleep_mode) + temp &= ~(KL3_TIMER_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE); MACIO_OUT32(KEYLARGO_FCR3, temp); - (void)MACIO_IN32(KEYLARGO_FCR3); udelay(10); + + /* Flush posted writes & wait a bit */ + (void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1); } static void __pmac -pangea_shutdown(struct macio_chip* macio, int restart) +pangea_shutdown(struct macio_chip* macio, int sleep_mode) { u32 temp; @@ -1227,10 +1333,6 @@ KL0_SCC_CELL_ENABLE | KL0_USB0_CELL_ENABLE | KL0_USB1_CELL_ENABLE); - (void)MACIO_IN32(KEYLARGO_FCR0); udelay(10); - MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK); - (void)MACIO_IN32(KEYLARGO_MBCR); udelay(10); - MACIO_BIC(KEYLARGO_FCR1, KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT | KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE | @@ -1238,18 +1340,54 @@ KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE | KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE | KL1_UIDE_ENABLE); - (void)MACIO_IN32(KEYLARGO_FCR1); udelay(10); + if (pmac_mb.board_flags & PMAC_MB_MOBILE) + MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N); MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT); - udelay(10); + temp = MACIO_IN32(KEYLARGO_FCR3); temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 | KL3_SHUTDOWN_PLLKW35; - temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE - | KL3_CLK31_ENABLE | KL3_TIMER_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE - | KL3_I2S0_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE); + temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE | KL3_CLK31_ENABLE + | KL3_I2S0_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE); + if (sleep_mode) + temp &= ~(KL3_VIA_CLK16_ENABLE | KL3_TIMER_CLK18_ENABLE); MACIO_OUT32(KEYLARGO_FCR3, temp); - (void)MACIO_IN32(KEYLARGO_FCR3); udelay(10); + + /* Flush posted writes & wait a bit */ + (void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1); +} + +static void __pmac +intrepid_shutdown(struct macio_chip* macio, int sleep_mode) +{ + u32 temp; + + MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE | + KL0_SCC_CELL_ENABLE | + KL0_USB0_CELL_ENABLE | KL0_USB1_CELL_ENABLE); + + MACIO_BIC(KEYLARGO_FCR1, + KL1_USB2_CELL_ENABLE | + KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT | + KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE | + KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE); + if (pmac_mb.board_flags & PMAC_MB_MOBILE) + MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N); + + MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT); + + temp = MACIO_IN32(KEYLARGO_FCR3); + temp |= KL3_IT_SHUTDOWN_PLL1 | KL3_IT_SHUTDOWN_PLL2 | + KL3_IT_SHUTDOWN_PLL3; + temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE | + KL3_I2S1_CLK18_ENABLE | KL3_I2S0_CLK18_ENABLE); + if (sleep_mode) + temp &= ~(KL3_TIMER_CLK18_ENABLE | KL3_IT_VIA_CLK32_ENABLE); + MACIO_OUT32(KEYLARGO_FCR3, temp); + + /* Flush posted writes & wait a bit */ + (void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1); } static int __pmac @@ -1259,7 +1397,8 @@ int i; macio = &macio_chips[0]; - if (macio->type != macio_keylargo && macio->type != macio_pangea) + if (macio->type != macio_keylargo && macio->type != macio_pangea && + macio->type != macio_intrepid) return -ENODEV; /* We power off the wireless slot in case it was not done @@ -1275,7 +1414,11 @@ } /* We make sure int. modem is off (in case driver lost it) */ - core99_modem_enable(macio->of_node, 0, 0); + if (macio->type == macio_keylargo) + core99_modem_enable(macio->of_node, 0, 0); + else + pangea_modem_enable(macio->of_node, 0, 0); + /* We make sure the sound is off as well */ core99_sound_chip_enable(macio->of_node, 0, 0); @@ -1292,12 +1435,15 @@ save_gpio_normal[i] = MACIO_IN8(KEYLARGO_GPIO_0+i); /* Save the FCRs */ - save_mbcr = MACIO_IN32(KEYLARGO_MBCR); + if (macio->type == macio_keylargo) + save_mbcr = MACIO_IN32(KEYLARGO_MBCR); save_fcr[0] = MACIO_IN32(KEYLARGO_FCR0); save_fcr[1] = MACIO_IN32(KEYLARGO_FCR1); save_fcr[2] = MACIO_IN32(KEYLARGO_FCR2); save_fcr[3] = MACIO_IN32(KEYLARGO_FCR3); save_fcr[4] = MACIO_IN32(KEYLARGO_FCR4); + if (macio->type == macio_pangea || macio->type == macio_intrepid) + save_fcr[5] = MACIO_IN32(KEYLARGO_FCR5); /* Save state & config of DBDMA channels */ dbdma_save(macio, save_dbdma); @@ -1306,9 +1452,11 @@ * Turn off as much as we can */ if (macio->type == macio_pangea) - pangea_shutdown(macio, 0); + pangea_shutdown(macio, 1); + else if (macio->type == macio_intrepid) + intrepid_shutdown(macio, 1); else if (macio->type == macio_keylargo) - keylargo_shutdown(macio, 0); + keylargo_shutdown(macio, 1); /* * Put the host bridge to sleep @@ -1338,7 +1486,8 @@ int i; macio = &macio_chips[0]; - if (macio->type != macio_keylargo && macio->type != macio_pangea) + if (macio->type != macio_keylargo && macio->type != macio_pangea && + macio->type != macio_intrepid) return -ENODEV; /* @@ -1352,9 +1501,11 @@ /* * Restore KeyLargo */ - - MACIO_OUT32(KEYLARGO_MBCR, save_mbcr); - (void)MACIO_IN32(KEYLARGO_MBCR); udelay(10); + + if (macio->type == macio_keylargo) { + MACIO_OUT32(KEYLARGO_MBCR, save_mbcr); + (void)MACIO_IN32(KEYLARGO_MBCR); udelay(10); + } MACIO_OUT32(KEYLARGO_FCR0, save_fcr[0]); (void)MACIO_IN32(KEYLARGO_FCR0); udelay(10); MACIO_OUT32(KEYLARGO_FCR1, save_fcr[1]); @@ -1365,6 +1516,10 @@ (void)MACIO_IN32(KEYLARGO_FCR3); udelay(10); MACIO_OUT32(KEYLARGO_FCR4, save_fcr[4]); (void)MACIO_IN32(KEYLARGO_FCR4); udelay(10); + if (macio->type == macio_pangea || macio->type == macio_intrepid) { + MACIO_OUT32(KEYLARGO_FCR5, save_fcr[5]); + (void)MACIO_IN32(KEYLARGO_FCR5); udelay(10); + } dbdma_restore(macio, save_dbdma); @@ -1390,6 +1545,21 @@ static int __pmac core99_sleep_state(struct device_node* node, int param, int value) { + /* Param == 1 means to enter the "fake sleep" mode that is + * used for CPU speed switch + */ + if (param == 1) { + if (value == 1) { + UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING); + UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_IDLE2); + } else { + UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL); + udelay(10); + UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING); + udelay(10); + } + return 0; + } if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0) return -EPERM; if (value == 1) @@ -1400,55 +1570,6 @@ } static int __pmac -pangea_modem_enable(struct device_node* node, int param, int value) -{ - struct macio_chip* macio; - u8 gpio; - unsigned long flags; - - macio = macio_find(node, 0); - if (!macio) - return -ENODEV; - gpio = MACIO_IN8(KL_GPIO_MODEM_RESET); - gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE; - gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA; - - if (!value) { - LOCK(flags); - MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio); - UNLOCK(flags); - (void)MACIO_IN8(KL_GPIO_MODEM_RESET); - mdelay(250); - } - LOCK(flags); - if (value) { - MACIO_OUT8(KL_GPIO_MODEM_POWER, - KEYLARGO_GPIO_OUTPUT_ENABLE); - UNLOCK(flags); - (void)MACIO_IN32(KEYLARGO_FCR2); - mdelay(250); - } else { - MACIO_OUT8(KL_GPIO_MODEM_POWER, - KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA); - UNLOCK(flags); - } - if (value) { - LOCK(flags); - MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA); - (void)MACIO_IN8(KL_GPIO_MODEM_RESET); - UNLOCK(flags); mdelay(250); LOCK(flags); - MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio); - (void)MACIO_IN8(KL_GPIO_MODEM_RESET); - UNLOCK(flags); mdelay(250); LOCK(flags); - MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA); - (void)MACIO_IN8(KL_GPIO_MODEM_RESET); - UNLOCK(flags); mdelay(250); - } - return 0; -} - - -static int __pmac generic_get_mb_info(struct device_node* node, int param, int value) { switch(param) { @@ -1561,6 +1682,26 @@ { 0, NULL } }; +/* RackMac + */ +static struct feature_table_entry rackmac_features[] __pmacdata = { + { PMAC_FTR_SCC_ENABLE, core99_scc_enable }, + { PMAC_FTR_IDE_ENABLE, core99_ide_enable }, + { PMAC_FTR_IDE_RESET, core99_ide_reset }, + { PMAC_FTR_GMAC_ENABLE, core99_gmac_enable }, + { PMAC_FTR_GMAC_PHY_RESET, core99_gmac_phy_reset }, + { PMAC_FTR_USB_ENABLE, core99_usb_enable }, + { PMAC_FTR_1394_ENABLE, core99_firewire_enable }, + { PMAC_FTR_1394_CABLE_POWER, core99_firewire_cable_power }, + { PMAC_FTR_SLEEP_STATE, core99_sleep_state }, +#ifdef CONFIG_SMP + { PMAC_FTR_RESET_CPU, core99_reset_cpu }, +#endif /* CONFIG_SMP */ + { PMAC_FTR_READ_GPIO, core99_read_gpio }, + { PMAC_FTR_WRITE_GPIO, core99_write_gpio }, + { 0, NULL } +}; + /* Pangea features */ static struct feature_table_entry pangea_features[] __pmacdata = { @@ -1580,6 +1721,26 @@ { PMAC_FTR_WRITE_GPIO, core99_write_gpio }, { 0, NULL } }; + +/* Intrepid features + */ +static struct feature_table_entry intrepid_features[] __pmacdata = { + { PMAC_FTR_SCC_ENABLE, core99_scc_enable }, + { PMAC_FTR_MODEM_ENABLE, pangea_modem_enable }, + { PMAC_FTR_IDE_ENABLE, core99_ide_enable }, + { PMAC_FTR_IDE_RESET, core99_ide_reset }, + { PMAC_FTR_GMAC_ENABLE, core99_gmac_enable }, + { PMAC_FTR_GMAC_PHY_RESET, core99_gmac_phy_reset }, + { PMAC_FTR_SOUND_CHIP_ENABLE, core99_sound_chip_enable }, + { PMAC_FTR_AIRPORT_ENABLE, core99_airport_enable }, + { PMAC_FTR_USB_ENABLE, core99_usb_enable }, + { PMAC_FTR_1394_ENABLE, core99_firewire_enable }, + { PMAC_FTR_1394_CABLE_POWER, core99_firewire_cable_power }, + { PMAC_FTR_SLEEP_STATE, core99_sleep_state }, + { PMAC_FTR_READ_GPIO, core99_read_gpio }, + { PMAC_FTR_WRITE_GPIO, core99_write_gpio }, + { 0, NULL } +}; static struct pmac_mb_def pmac_mb_defs[] __pmacdata = { /* Warning: ordering is important as some models may claim @@ -1611,11 +1772,11 @@ }, { "AAPL,3400/2400", "PowerBook 3400", PMAC_TYPE_HOOPER, ohare_features, - PMAC_MB_CAN_SLEEP + PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE }, { "AAPL,3500", "PowerBook 3500", PMAC_TYPE_KANGA, ohare_features, - PMAC_MB_CAN_SLEEP + PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE }, { "AAPL,Gossamer", "PowerMac G3 (Gossamer)", PMAC_TYPE_GOSSAMER, heathrow_desktop_features, @@ -1627,11 +1788,11 @@ }, { "AAPL,PowerBook1998", "PowerBook Wallstreet", PMAC_TYPE_WALLSTREET, heathrow_laptop_features, - PMAC_MB_CAN_SLEEP + PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE }, - { "AAPL,PowerBook1,1", "PowerBook 101 (Lombard)", + { "PowerBook1,1", "PowerBook 101 (Lombard)", PMAC_TYPE_101_PBOOK, paddington_features, - PMAC_MB_CAN_SLEEP + PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE }, { "iMac,1", "iMac (first generation)", PMAC_TYPE_ORIG_IMAC, paddington_features, @@ -1641,13 +1802,21 @@ PMAC_TYPE_PANGEA_IMAC, pangea_features, PMAC_MB_CAN_SLEEP }, - { "PowerBook4,2", "iBook 2 with 14\" LCD", + { "PowerBook4,3", "iBook 2 rev. 2", PMAC_TYPE_IBOOK2, pangea_features, - PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER + PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE + }, + { "PowerBook4,2", "iBook 2", + PMAC_TYPE_IBOOK2, pangea_features, + PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE }, { "PowerBook4,1", "iBook 2", PMAC_TYPE_IBOOK2, pangea_features, - PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER + PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE + }, + { "PowerMac4,4", "eMac", + PMAC_TYPE_EMAC, core99_features, + PMAC_MB_CAN_SLEEP }, { "PowerMac4,2", "Flat panel iMac", PMAC_TYPE_FLAT_PANEL_IMAC, pangea_features, @@ -1663,34 +1832,35 @@ }, { "PowerBook2,1", "iBook (first generation)", PMAC_TYPE_ORIG_IBOOK, core99_features, - PMAC_MB_CAN_SLEEP + PMAC_MB_CAN_SLEEP | PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE }, { "PowerMac3,1", "PowerMac G4 AGP Graphics", PMAC_TYPE_SAWTOOTH, core99_features, - 0 + PMAC_MB_OLD_CORE99 }, { "PowerMac3,2", "PowerMac G4 AGP Graphics", PMAC_TYPE_SAWTOOTH, core99_features, - 0 + PMAC_MB_OLD_CORE99 }, { "PowerMac3,3", "PowerMac G4 AGP Graphics", PMAC_TYPE_SAWTOOTH, core99_features, - 0 + PMAC_MB_OLD_CORE99 }, { "PowerMac2,1", "iMac FireWire", PMAC_TYPE_FW_IMAC, core99_features, - PMAC_MB_CAN_SLEEP + PMAC_MB_CAN_SLEEP | PMAC_MB_OLD_CORE99 }, { "PowerMac2,2", "iMac FireWire", PMAC_TYPE_FW_IMAC, core99_features, - PMAC_MB_CAN_SLEEP + PMAC_MB_CAN_SLEEP | PMAC_MB_OLD_CORE99 }, { "PowerBook2,2", "iBook FireWire", PMAC_TYPE_FW_IBOOK, core99_features, - PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER + PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE }, { "PowerMac5,1", "PowerMac G4 Cube", PMAC_TYPE_CUBE, core99_features, + PMAC_MB_OLD_CORE99 }, { "PowerMac3,4", "PowerMac G4 Silver", PMAC_TYPE_QUICKSILVER, core99_features, @@ -1702,19 +1872,31 @@ }, { "PowerBook3,1", "PowerBook Pismo", PMAC_TYPE_PISMO, core99_features, - PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER + PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE }, { "PowerBook3,2", "PowerBook Titanium", PMAC_TYPE_TITANIUM, core99_features, - PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER + PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE }, { "PowerBook3,3", "PowerBook Titanium II", PMAC_TYPE_TITANIUM2, core99_features, - PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER + PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE }, { "PowerBook3,4", "PowerBook Titanium III", PMAC_TYPE_TITANIUM3, core99_features, - PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER + PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE + }, + { "PowerBook3,5", "PowerBook Titanium IV", + PMAC_TYPE_TITANIUM4, core99_features, + PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE + }, + { "RackMac1,1", "XServe", + PMAC_TYPE_RACKMAC, rackmac_features, + 0, + }, + { "PowerMac3,6", "PowerMac G4 Windtunnel", + PMAC_TYPE_WINDTUNNEL, rackmac_features, + 0, }, }; @@ -1758,8 +1940,22 @@ { int i; struct macio_chip* macio = &macio_chips[0]; - - /* Lookup known motherboard type in device-tree */ + const char* model = NULL; + struct device_node *dt; + + /* Lookup known motherboard type in device-tree. First try an + * exact match on the "model" property, then try a "compatible" + * match is none is found. + */ + dt = find_devices("device-tree"); + if (dt != NULL) + model = (const char *) get_property(dt, "model", NULL); + for(i=0; model && i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) { + if (strcmp(model, pmac_mb_defs[i].model_string) == 0) { + pmac_mb = pmac_mb_defs[i]; + goto found; + } + } for(i=0; i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) { if (machine_is_compatible(pmac_mb_defs[i].model_string)) { pmac_mb = pmac_mb_defs[i]; @@ -1797,6 +1993,11 @@ pmac_mb.model_name = "Unknown Pangea-based"; pmac_mb.features = pangea_features; break; + case macio_intrepid: + pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PANGEA; + pmac_mb.model_name = "Unknown Pangea-based"; + pmac_mb.features = intrepid_features; + break; default: return -ENODEV; } @@ -1815,6 +2016,7 @@ iounmap(mach_id_ptr); } +#ifdef CONFIG_6xx /* Set default value of powersave_nap on machines that support it. * It appears that uninorth rev 3 has a problem with it, we don't * enable it on those. In theory, the flush-on-lock property is @@ -1823,7 +2025,6 @@ */ while (uninorth_base && uninorth_rev > 3) { struct device_node* np = find_path_device("/cpus"); - u32 pvr = mfspr(PVR); if (!np || !np->child) { printk(KERN_WARNING "Can't find CPU(s) in device tree !\n"); break; @@ -1835,14 +2036,23 @@ /* Nap mode not supported if flush-on-lock property is present */ if (get_property(np, "flush-on-lock", NULL)) break; - /* Some 7450 may have problem with NAP mode too ... */ - if (((pvr >> 16) == 0x8000) && ((pvr & 0xffff) < 0x0201)) - break; powersave_nap = 1; printk(KERN_INFO "Processor NAP mode on idle enabled.\n"); break; } + /* On CPUs that support it (750FX), lowspeed by default during + * NAP mode + */ + powersave_lowspeed = 1; +#endif /* CONFIG_6xx */ + + /* Check for "mobile" machine */ + if (model && (strncmp(model, "PowerBook", 9) == 0 + || strncmp(model, "iBook", 5) == 0)) + pmac_mb.board_flags |= PMAC_MB_MOBILE; + + printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name); return 0; } @@ -1857,7 +2067,7 @@ /* Locate core99 Uni-N */ uninorth_node = find_devices("uni-n"); if (uninorth_node && uninorth_node->n_addrs > 0) { - uninorth_base = ioremap(uninorth_node->addrs[0].address, 0x1000); + uninorth_base = ioremap(uninorth_node->addrs[0].address, 0x4000); uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); } else uninorth_node = NULL; @@ -1867,15 +2077,23 @@ printk(KERN_INFO "Found Uninorth memory controller & host bridge, revision: %d\n", uninorth_rev); + printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base); /* Set the arbitrer QAck delay according to what Apple does */ - if (uninorth_rev < 0x10) { + if (uninorth_rev < 0x11) { actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK; actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 : UNI_N_ARB_CTRL_QACK_DELAY) << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT; UN_OUT(UNI_N_ARB_CTRL, actrl); } + + /* Some more magic as done by them in recent MacOS X on UniNorth + * revs 1.5 to 2.O and Pangea. Seem to toggle the UniN Maxbus/PCI + * memory timeout + */ + if ((uninorth_rev >= 0x11 && uninorth_rev <= 0x24) || uninorth_rev == 0xc0) + UN_OUT(0x2160, UN_IN(0x2160) & 0x00ffffff); } static void __init @@ -1917,11 +2135,14 @@ u32* did = (u32 *)get_property(node, "device-id", NULL); if (*did == 0x00000025) type = macio_pangea; + if (*did == 0x0000003e) + type = macio_intrepid; } macio_chips[i].of_node = node; macio_chips[i].type = type; macio_chips[i].base = base; macio_chips[i].flags = MACIO_FLAG_SCCB_ON | MACIO_FLAG_SCCB_ON; + macio_chips[i].name = macio_names[type]; revp = (u32 *)get_property(node, "revision-id", NULL); if (revp) macio_chips[i].rev = *revp; @@ -2011,7 +2232,8 @@ } if (macio_chips[0].type == macio_keylargo || - macio_chips[0].type == macio_pangea) { + 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 */ @@ -2042,6 +2264,17 @@ np = np->next; } + /* Enable ATA-100 before PCI probe. */ + np = find_devices("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; + } + /* Switch airport off */ np = find_devices("radio"); while(np) { @@ -2079,9 +2312,6 @@ initial_serial_shutdown(np); np = np->next; } - - /* Let hardware settle down */ - mdelay(10); } void __init diff -Nru a/arch/ppc/platforms/pmac_setup.c b/arch/ppc/platforms/pmac_setup.c --- a/arch/ppc/platforms/pmac_setup.c Wed Apr 2 22:24:06 2003 +++ b/arch/ppc/platforms/pmac_setup.c Wed Apr 2 22:24:06 2003 @@ -225,6 +225,20 @@ return 0; } +int __openfirmware +pmac_show_percpuinfo(struct seq_file *m, int i) +{ +#ifdef CONFIG_CPU_FREQ_PMAC + extern unsigned int pmac_get_one_cpufreq(int i); + unsigned int freq = pmac_get_one_cpufreq(i); + if (freq != 0) { + seq_printf(m, "clock\t\t: %dMHz\n", freq/1000); + return 0; + } +#endif /* CONFIG_CPU_FREQ_PMAC */ + return of_show_percpuinfo(m, i); +} + static volatile u32 *sysctrl_regs; void __init @@ -604,7 +618,7 @@ ppc_md.setup_arch = pmac_setup_arch; ppc_md.show_cpuinfo = pmac_show_cpuinfo; - ppc_md.show_percpuinfo = of_show_percpuinfo; + ppc_md.show_percpuinfo = pmac_show_percpuinfo; ppc_md.irq_cannonicalize = NULL; ppc_md.init_IRQ = pmac_pic_init; ppc_md.get_irq = pmac_get_irq; /* Changed later on ... */ diff -Nru a/arch/ppc/platforms/pmac_sleep.S b/arch/ppc/platforms/pmac_sleep.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ppc/platforms/pmac_sleep.S Wed Apr 2 22:24:04 2003 @@ -0,0 +1,375 @@ +/* + * This file contains sleep low-level functions for PowerBook G3. + * Copyright (C) 1999 Benjamin Herrenschmidt (benh@kernel.crashing.org) + * and Paul Mackerras (paulus@samba.org). + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * 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 + +#define MAGIC 0x4c617273 /* 'Lars' */ + +/* + * Structure for storing CPU registers on the stack. + */ +#define SL_SP 0 +#define SL_PC 4 +#define SL_MSR 8 +#define SL_SDR1 0xc +#define SL_SPRG0 0x10 /* 4 sprg's */ +#define SL_DBAT0 0x20 +#define SL_IBAT0 0x28 +#define SL_DBAT1 0x30 +#define SL_IBAT1 0x38 +#define SL_DBAT2 0x40 +#define SL_IBAT2 0x48 +#define SL_DBAT3 0x50 +#define SL_IBAT3 0x58 +#define SL_TB 0x60 +#define SL_R2 0x68 +#define SL_CR 0x6c +#define SL_R12 0x70 /* r12 to r31 */ +#define SL_SIZE (SL_R12 + 80) + + .section .text + .align 5 + +#if defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_CPU_FREQ_PMAC) + +/* This gets called by via-pmu.c late during the sleep process. + * The PMU was already send the sleep command and will shut us down + * soon. We need to save all that is needed and setup the wakeup + * vector that will be called by the ROM on wakeup + */ +_GLOBAL(low_sleep_handler) + mflr r0 + stw r0,4(r1) + stwu r1,-SL_SIZE(r1) + mfcr r0 + stw r0,SL_CR(r1) + stw r2,SL_R2(r1) + stmw r12,SL_R12(r1) + + /* Save MSR & SDR1 */ + mfmsr r4 + stw r4,SL_MSR(r1) + mfsdr1 r4 + stw r4,SL_SDR1(r1) + + /* Get a stable timebase and save it */ +1: mftbu r4 + stw r4,SL_TB(r1) + mftb r5 + stw r5,SL_TB+4(r1) + mftbu r3 + cmpw r3,r4 + bne 1b + + /* Save SPRGs */ + mfsprg r4,0 + stw r4,SL_SPRG0(r1) + mfsprg r4,1 + stw r4,SL_SPRG0+4(r1) + mfsprg r4,2 + stw r4,SL_SPRG0+8(r1) + mfsprg r4,3 + stw r4,SL_SPRG0+12(r1) + + /* Save BATs */ + mfdbatu r4,0 + stw r4,SL_DBAT0(r1) + mfdbatl r4,0 + stw r4,SL_DBAT0+4(r1) + mfdbatu r4,1 + stw r4,SL_DBAT1(r1) + mfdbatl r4,1 + stw r4,SL_DBAT1+4(r1) + mfdbatu r4,2 + stw r4,SL_DBAT2(r1) + mfdbatl r4,2 + stw r4,SL_DBAT2+4(r1) + mfdbatu r4,3 + stw r4,SL_DBAT3(r1) + mfdbatl r4,3 + stw r4,SL_DBAT3+4(r1) + mfibatu r4,0 + stw r4,SL_IBAT0(r1) + mfibatl r4,0 + stw r4,SL_IBAT0+4(r1) + mfibatu r4,1 + stw r4,SL_IBAT1(r1) + mfibatl r4,1 + stw r4,SL_IBAT1+4(r1) + mfibatu r4,2 + stw r4,SL_IBAT2(r1) + mfibatl r4,2 + stw r4,SL_IBAT2+4(r1) + mfibatu r4,3 + stw r4,SL_IBAT3(r1) + mfibatl r4,3 + stw r4,SL_IBAT3+4(r1) + + /* Backup various CPU config stuffs */ + bl __save_cpu_setup + + /* The ROM can wake us up via 2 different vectors: + * - On wallstreet & lombard, we must write a magic + * value 'Lars' at address 4 and a pointer to a + * memory location containing the PC to resume from + * at address 0. + * - On Core99, we must store the wakeup vector at + * address 0x80 and eventually it's parameters + * at address 0x84. I've have some trouble with those + * parameters however and I no longer use them. + */ + lis r5,grackle_wake_up@ha + addi r5,r5,grackle_wake_up@l + tophys(r5,r5) + stw r5,SL_PC(r1) + lis r4,KERNELBASE@h + tophys(r5,r1) + addi r5,r5,SL_PC + lis r6,MAGIC@ha + addi r6,r6,MAGIC@l + stw r5,0(r4) + stw r6,4(r4) + /* Setup stuffs at 0x80-0x84 for Core99 */ + lis r3,core99_wake_up@ha + addi r3,r3,core99_wake_up@l + tophys(r3,r3) + stw r3,0x80(r4) + stw r5,0x84(r4) + /* Store a pointer to our backup storage into + * a kernel global + */ + lis r3,sleep_storage@ha + addi r3,r3,sleep_storage@l + stw r5,0(r3) + +BEGIN_FTR_SECTION + DSSALL + sync +END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) + +/* + * Flush the L1 data cache by reading the first 128kB of RAM + * and then flushing the same area with the dcbf instruction. + * The L2 cache has already been disabled. + */ + li r4,0x1000 /* 128kB / 32B */ + mtctr r4 + lis r4,KERNELBASE@h +1: + lwz r0,0(r4) + addi r4,r4,0x0020 /* Go to start of next cache line */ + bdnz 1b + sync + + li r4,0x1000 /* 128kB / 32B */ + mtctr r4 + lis r4,KERNELBASE@h +1: + dcbf r0,r4 + addi r4,r4,0x0020 /* Go to start of next cache line */ + bdnz 1b + sync + +/* + * Set the HID0 and MSR for sleep. + */ + mfspr r2,HID0 + rlwinm r2,r2,0,10,7 /* clear doze, nap */ + oris r2,r2,HID0_SLEEP@h + sync + mtspr HID0,r2 + sync + +/* This loop puts us back to sleep in case we have a spurrious + * wakeup so that the host bridge properly stays asleep. The + * CPU will be turned off, either after a known time (about 1 + * second) on wallstreet & lombard, or as soon as the CPU enters + * SLEEP mode on core99 + */ + mfmsr r2 + oris r2,r2,MSR_POW@h +1: sync + mtmsr r2 + isync + b 1b + +/* + * Here is the resume code. + */ + + +/* + * Core99 machines resume here + * r4 has the physical address of SL_PC(sp) (unused) + */ +_GLOBAL(core99_wake_up) + /* Make sure HID0 no longer contains any sleep bit */ + mfspr r3,HID0 + rlwinm r3,r3,0,11,7 /* clear SLEEP, NAP, DOZE bits */ + mtspr HID0,r3 + sync + isync + + /* Won't that cause problems on CPU that doesn't support it ? */ + lis r3, 0 + mtspr SPRN_MMCR0, r3 + + /* sanitize MSR */ + mfmsr r3 + ori r3,r3,MSR_EE|MSR_IP + xori r3,r3,MSR_EE|MSR_IP + sync + isync + mtmsr r3 + sync + isync + + /* Recover sleep storage */ + lis r3,sleep_storage@ha + addi r3,r3,sleep_storage@l + tophys(r3,r3) + lwz r1,0(r3) + + /* Pass thru to older resume code ... */ +/* + * Here is the resume code for older machines. + * r1 has the physical address of SL_PC(sp). + */ + +grackle_wake_up: + /* Enable and then Flash inval the instruction & data cache */ + mfspr r3,HID0 + ori r3,r3, HID0_ICE|HID0_ICFI|HID0_DCE|HID0_DCI + sync + isync + mtspr HID0,r3 + xori r3,r3, HID0_ICFI|HID0_DCI + mtspr HID0,r3 + sync + + /* Restore the kernel's segment registers before + * we do any r1 memory access as we are not sure they + * are in a sane state above the first 256Mb region + */ + li r0,16 /* load up segment register values */ + mtctr r0 /* for context 0 */ + lis r3,0x2000 /* Ku = 1, VSID = 0 */ + li r4,0 +3: mtsrin r3,r4 + addi r3,r3,0x111 /* increment VSID */ + addis r4,r4,0x1000 /* address of next segment */ + bdnz 3b + + subi r1,r1,SL_PC + + /* Restore various CPU config stuffs */ + bl __restore_cpu_setup + + /* Restore the BATs, and SDR1. Then we can turn on the MMU. */ + lwz r4,SL_SDR1(r1) + mtsdr1 r4 + lwz r4,SL_SPRG0(r1) + mtsprg 0,r4 + lwz r4,SL_SPRG0+4(r1) + mtsprg 1,r4 + lwz r4,SL_SPRG0+8(r1) + mtsprg 2,r4 + lwz r4,SL_SPRG0+12(r1) + mtsprg 3,r4 + + lwz r4,SL_DBAT0(r1) + mtdbatu 0,r4 + lwz r4,SL_DBAT0+4(r1) + mtdbatl 0,r4 + lwz r4,SL_DBAT1(r1) + mtdbatu 1,r4 + lwz r4,SL_DBAT1+4(r1) + mtdbatl 1,r4 + lwz r4,SL_DBAT2(r1) + mtdbatu 2,r4 + lwz r4,SL_DBAT2+4(r1) + mtdbatl 2,r4 + lwz r4,SL_DBAT3(r1) + mtdbatu 3,r4 + lwz r4,SL_DBAT3+4(r1) + mtdbatl 3,r4 + lwz r4,SL_IBAT0(r1) + mtibatu 0,r4 + lwz r4,SL_IBAT0+4(r1) + mtibatl 0,r4 + lwz r4,SL_IBAT1(r1) + mtibatu 1,r4 + lwz r4,SL_IBAT1+4(r1) + mtibatl 1,r4 + lwz r4,SL_IBAT2(r1) + mtibatu 2,r4 + lwz r4,SL_IBAT2+4(r1) + mtibatl 2,r4 + lwz r4,SL_IBAT3(r1) + mtibatu 3,r4 + lwz r4,SL_IBAT3+4(r1) + mtibatl 3,r4 + + /* Flush all TLBs */ + lis r4,0x1000 +1: addic. r4,r4,-0x1000 + tlbie r4 + blt 1b + sync + + /* restore the MSR and turn on the MMU */ + lwz r3,SL_MSR(r1) + bl turn_on_mmu + + /* get back the stack pointer */ + tovirt(r1,r1) + + /* Restore TB */ + li r3,0 + mttbl r3 + lwz r3,SL_TB(r1) + lwz r4,SL_TB+4(r1) + mttbu r3 + mttbl r4 + + /* Restore the callee-saved registers and return */ + lwz r0,SL_CR(r1) + mtcr r0 + lwz r2,SL_R2(r1) + lmw r12,SL_R12(r1) + addi r1,r1,SL_SIZE + lwz r0,4(r1) + mtlr r0 + blr + +turn_on_mmu: + mflr r4 + tovirt(r4,r4) + mtsrr0 r4 + mtsrr1 r3 + sync + isync + rfi + +#endif /* defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_CPU_FREQ) */ + + + .data + .globl sleep_storage +sleep_storage: + .long 0 diff -Nru a/arch/ppc/platforms/pmac_smp.c b/arch/ppc/platforms/pmac_smp.c --- a/arch/ppc/platforms/pmac_smp.c Wed Apr 2 22:24:05 2003 +++ b/arch/ppc/platforms/pmac_smp.c Wed Apr 2 22:24:05 2003 @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -106,14 +105,16 @@ volatile static long int core99_l3_cache; static void __init -core99_init_caches(void) +core99_init_caches(int cpu) { - int cpu = smp_processor_id(); - + /* Check cache presence on cpu 0, we assume all CPUs have + * same features here. We also assume that if we don't have + * L2CR, we don't have L3CR neither + */ if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR)) return; - if (cpu == 0){ + if (cpu == 0) { core99_l2_cache = _get_L2CR(); printk("CPU0: L2CR is %lx\n", core99_l2_cache); } else { @@ -137,106 +138,6 @@ } } -/* Some CPU registers have to be saved from the first CPU and - * applied to others. Note that we override what is setup by - * the cputable intentionally. - */ - -#define reg_hid0 0 -#define reg_hid1 1 -#define reg_msscr0 2 -#define reg_msssr0 3 -#define reg_ictrl 4 -#define reg_ldstcr 5 -#define reg_ldstdb 6 -#define reg_count 7 - -static unsigned long cpu_regs[reg_count]; - -static void __pmac -cpu_setup_grab(void) -{ - unsigned int pvers = mfspr(SPRN_PVR)>>16; - - /* Read cache setting of CPU 0 */ - core99_init_caches(); - - /* 7400/7410/7450 */ - if (pvers == 0x8000 || pvers == 0x000c || pvers == 0x800c) { - cpu_regs[reg_hid0] = mfspr(SPRN_HID0); - cpu_regs[reg_msscr0] = mfspr(SPRN_MSSCR0); - cpu_regs[reg_msssr0] = mfspr(SPRN_MSSSR0); - } - /* 7450 only */ - if (pvers == 0x8000) { - cpu_regs[reg_hid1] = mfspr(SPRN_HID1); - cpu_regs[reg_ictrl] = mfspr(SPRN_ICTRL); - cpu_regs[reg_ldstcr] = mfspr(SPRN_LDSTCR); - cpu_regs[reg_ldstdb] = mfspr(SPRN_LDSTDB); - } - flush_dcache_range((unsigned long)cpu_regs, (unsigned long)&cpu_regs[reg_count]); -} - -static void __pmac -cpu_setup_apply(int cpu_nr) -{ - unsigned int pvers = mfspr(SPRN_PVR)>>16; - - /* Apply cache setting from CPU 0 */ - core99_init_caches(); - - /* 7400/7410/7450 */ - if (pvers == 0x8000 || pvers == 0x000c || pvers == 0x800c) { - unsigned long tmp; - __asm__ __volatile__ ( - "lwz %0,4*"stringify(reg_hid0)"(%1)\n" - "sync\n" - "mtspr "stringify(SPRN_HID0)", %0\n" - "isync;sync\n" - "lwz %0, 4*"stringify(reg_msscr0)"(%1)\n" - "sync\n" - "mtspr "stringify(SPRN_MSSCR0)", %0\n" - "isync;sync\n" -// "lwz %0, "stringify(reg_msssr0)"(%1)\n" -// "sync\n" -// "mtspr "stringify(SPRN_MSSSR0)", %0\n" -// "isync;sync\n" - : "=&r" (tmp) : "r" (cpu_regs)); - } - /* 7410 only */ - if (pvers == 0x800c) { - unsigned long tmp; - __asm__ __volatile__ ( - "li %0, 0\n" - "sync\n" - "mtspr "stringify(SPRN_L2CR2)", %0\n" - "isync;sync\n" - : "=&r" (tmp)); - } - /* 7450 only */ - if (pvers == 0x8000) { - unsigned long tmp; - __asm__ __volatile__ ( - "lwz %0, 4*"stringify(reg_hid1)"(%1)\n" - "sync\n" - "mtspr "stringify(SPRN_HID1)", %0\n" - "isync;sync\n" - "lwz %0, 4*"stringify(reg_ictrl)"(%1)\n" - "sync\n" - "mtspr "stringify(SPRN_ICTRL)", %0\n" - "isync;sync\n" - "lwz %0, 4*"stringify(reg_ldstcr)"(%1)\n" - "sync\n" - "mtspr "stringify(SPRN_LDSTCR)", %0\n" - "isync;sync\n" - "lwz %0, 4*"stringify(reg_ldstdb)"(%1)\n" - "sync\n" - "mtspr "stringify(SPRN_LDSTDB)", %0\n" - "isync;sync\n" - : "=&r" (tmp) : "r" (cpu_regs)); - } -} - /* * Set and clear IPIs for powersurge. */ @@ -501,7 +402,7 @@ /* reset the entry point so if we get another intr we won't * try to startup again */ out_be32(psurge_start, 0x100); - if (request_irq(30, psurge_primary_intr, 0, "primary IPI", 0)) + if (request_irq(30, psurge_primary_intr, SA_INTERRUPT, "primary IPI", 0)) printk(KERN_ERR "Couldn't get primary IPI interrupt"); } @@ -526,8 +427,10 @@ openpic_request_IPIs(); for (i = 1; i < ncpus; ++i) smp_hw_index[i] = i; +#ifdef CONFIG_6xx powersave_nap = 0; - cpu_setup_grab(); +#endif + core99_init_caches(0); } return ncpus; @@ -593,7 +496,7 @@ { /* Setup some registers */ if (cpu_nr != 0) - cpu_setup_apply(cpu_nr); + core99_init_caches(cpu_nr); /* Setup openpic */ do_openpic_setup_cpu(); @@ -605,20 +508,20 @@ /* PowerSurge-style Macs */ struct smp_ops_t psurge_smp_ops __pmacdata = { - smp_psurge_message_pass, - smp_psurge_probe, - smp_psurge_kick_cpu, - smp_psurge_setup_cpu, - .give_timebase = smp_generic_give_timebase, - .take_timebase = smp_generic_take_timebase, + .message_pass = smp_psurge_message_pass, + .probe = smp_psurge_probe, + .kick_cpu = smp_psurge_kick_cpu, + .setup_cpu = smp_psurge_setup_cpu, + .give_timebase = smp_generic_give_timebase, + .take_timebase = smp_generic_take_timebase, }; /* Core99 Macs (dual G4s) */ struct smp_ops_t core99_smp_ops __pmacdata = { - smp_openpic_message_pass, - smp_core99_probe, - smp_core99_kick_cpu, - smp_core99_setup_cpu, - .give_timebase = smp_generic_give_timebase, - .take_timebase = smp_generic_take_timebase, + .message_pass = smp_openpic_message_pass, + .probe = smp_core99_probe, + .kick_cpu = smp_core99_kick_cpu, + .setup_cpu = smp_core99_setup_cpu, + .give_timebase = smp_generic_give_timebase, + .take_timebase = smp_generic_take_timebase, }; diff -Nru a/arch/ppc/platforms/pmac_time.c b/arch/ppc/platforms/pmac_time.c --- a/arch/ppc/platforms/pmac_time.c Wed Apr 2 22:24:04 2003 +++ b/arch/ppc/platforms/pmac_time.c Wed Apr 2 22:24:04 2003 @@ -202,6 +202,8 @@ printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %u (%u ticks)\n", tb_ticks_per_jiffy, dstart - dend); + iounmap((void*)via); + return 1; } diff -Nru a/arch/ppc/platforms/sleep.S b/arch/ppc/platforms/sleep.S --- a/arch/ppc/platforms/sleep.S Wed Apr 2 22:24:04 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,444 +0,0 @@ -/* - * This file contains sleep low-level functions for PowerBook G3. - * Copyright (C) 1999 Benjamin Herrenschmidt (benh@kernel.crashing.org) - * and Paul Mackerras (paulus@samba.org). - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include -#include -#include -#include - -#define MAGIC 0x4c617273 /* 'Lars' */ - -/* - * Structure for storing CPU registers on the stack. - */ -#define SL_SP 0 -#define SL_PC 4 -#define SL_MSR 8 -#define SL_SDR1 0xc -#define SL_SPRG0 0x10 /* 4 sprg's */ -#define SL_DBAT0 0x20 -#define SL_IBAT0 0x28 -#define SL_DBAT1 0x30 -#define SL_IBAT1 0x38 -#define SL_DBAT2 0x40 -#define SL_IBAT2 0x48 -#define SL_DBAT3 0x50 -#define SL_IBAT3 0x58 -#define SL_TB 0x60 -#define SL_HID0 0x68 -#define SL_HID1 0x6c -#define SL_MSSCR0 0x70 -#define SL_MSSSR0 0x74 -#define SL_ICTRL 0x78 -#define SL_LDSTCR 0x7c -#define SL_LDSTDB 0x80 -#define SL_R2 0x84 -#define SL_CR 0x88 -#define SL_R12 0x8c /* r12 to r31 */ -#define SL_SIZE (SL_R12 + 80) - - .text - .align 5 - -/* This gets called by via-pmu.c late during the sleep process. - * The PMU was already send the sleep command and will shut us down - * soon. We need to save all that is needed and setup the wakeup - * vector that will be called by the ROM on wakeup - */ -_GLOBAL(low_sleep_handler) - mflr r0 - stw r0,4(r1) - stwu r1,-SL_SIZE(r1) - mfcr r0 - stw r0,SL_CR(r1) - stw r2,SL_R2(r1) - stmw r12,SL_R12(r1) - - /* Save MSR & SDR1 */ - mfmsr r4 - stw r4,SL_MSR(r1) - mfsdr1 r4 - stw r4,SL_SDR1(r1) - - /* Get a stable timebase and save it */ -1: mftbu r4 - stw r4,SL_TB(r1) - mftb r5 - stw r5,SL_TB+4(r1) - mftbu r3 - cmpw r3,r4 - bne 1b - - /* Save SPRGs */ - mfsprg r4,0 - stw r4,SL_SPRG0(r1) - mfsprg r4,1 - stw r4,SL_SPRG0+4(r1) - mfsprg r4,2 - stw r4,SL_SPRG0+8(r1) - mfsprg r4,3 - stw r4,SL_SPRG0+12(r1) - - /* Save BATs */ - mfdbatu r4,0 - stw r4,SL_DBAT0(r1) - mfdbatl r4,0 - stw r4,SL_DBAT0+4(r1) - mfdbatu r4,1 - stw r4,SL_DBAT1(r1) - mfdbatl r4,1 - stw r4,SL_DBAT1+4(r1) - mfdbatu r4,2 - stw r4,SL_DBAT2(r1) - mfdbatl r4,2 - stw r4,SL_DBAT2+4(r1) - mfdbatu r4,3 - stw r4,SL_DBAT3(r1) - mfdbatl r4,3 - stw r4,SL_DBAT3+4(r1) - mfibatu r4,0 - stw r4,SL_IBAT0(r1) - mfibatl r4,0 - stw r4,SL_IBAT0+4(r1) - mfibatu r4,1 - stw r4,SL_IBAT1(r1) - mfibatl r4,1 - stw r4,SL_IBAT1+4(r1) - mfibatu r4,2 - stw r4,SL_IBAT2(r1) - mfibatl r4,2 - stw r4,SL_IBAT2+4(r1) - mfibatu r4,3 - stw r4,SL_IBAT3(r1) - mfibatl r4,3 - stw r4,SL_IBAT3+4(r1) - - /* Save HID0 */ - mfspr r4,HID0 - stw r4,SL_HID0(r1) - - /* Save 7400/7410/7450 specific registers */ - mfspr r3,PVR - srwi r3,r3,16 - cmpli cr0,r3,0x8000 - cmpli cr1,r3,0x000c - cmpli cr2,r3,0x800c - cror 4*cr1+eq,4*cr1+eq,4*cr2+eq - cror 4*cr0+eq,4*cr0+eq,4*cr1+eq - bne 1f - mfspr r4,SPRN_MSSCR0 - stw r4,SL_MSSCR0(r1) - mfspr r4,SPRN_MSSSR0 - stw r4,SL_MSSSR0(r1) - /* Save 7450 specific registers */ - beq cr1,1f - mfspr r4,HID1 - stw r4,SL_HID1(r1) - mfspr r4,SPRN_ICTRL - stw r4,SL_ICTRL(r1) - mfspr r4,SPRN_LDSTCR - stw r4,SL_LDSTCR(r1) - mfspr r4,SPRN_LDSTDB - stw r4,SL_LDSTDB(r1) -1: - /* The ROM can wake us up via 2 different vectors: - * - On wallstreet & lombard, we must write a magic - * value 'Lars' at address 4 and a pointer to a - * memory location containing the PC to resume from - * at address 0. - * - On Core99, we must store the wakeup vector at - * address 0x80 and eventually it's parameters - * at address 0x84. I've have some trouble with those - * parameters however and I no longer use them. - */ - lis r5,grackle_wake_up@ha - addi r5,r5,grackle_wake_up@l - tophys(r5,r5) - stw r5,SL_PC(r1) - lis r4,KERNELBASE@h - tophys(r5,r1) - addi r5,r5,SL_PC - lis r6,MAGIC@ha - addi r6,r6,MAGIC@l - stw r5,0(r4) - stw r6,4(r4) - /* Setup stuffs at 0x80-0x84 for Core99 */ - lis r3,core99_wake_up@ha - addi r3,r3,core99_wake_up@l - tophys(r3,r3) - stw r3,0x80(r4) - stw r5,0x84(r4) - /* Store a pointer to our backup storage into - * a kernel global - */ - lis r3,sleep_storage@ha - addi r3,r3,sleep_storage@l - stw r5,0(r3) - - -/* - * Flush the L1 data cache by reading the first 128kB of RAM - * and then flushing the same area with the dcbf instruction. - * The L2 cache has already been disabled. - */ - li r4,0x1000 /* 128kB / 32B */ - mtctr r4 - lis r4,KERNELBASE@h -1: - lwz r0,0(r4) - addi r4,r4,0x0020 /* Go to start of next cache line */ - bdnz 1b - sync - - li r4,0x1000 /* 128kB / 32B */ - mtctr r4 - lis r4,KERNELBASE@h -1: - dcbf r0,r4 - addi r4,r4,0x0020 /* Go to start of next cache line */ - bdnz 1b - sync - -/* - * Set the HID0 and MSR for sleep. - */ - mfspr r2,HID0 - rlwinm r2,r2,0,10,7 /* clear doze, nap */ - oris r2,r2,HID0_SLEEP@h - sync - mtspr HID0,r2 - sync - -/* This loop puts us back to sleep in case we have a spurrious - * wakeup so that the host bridge properly stays asleep. The - * CPU will be turned off, either after a known time (about 1 - * second) on wallstreet & lombard, or as soon as the CPU enters - * SLEEP mode on core99 - */ - mfmsr r2 - oris r2,r2,MSR_POW@h -1: sync - mtmsr r2 - isync - b 1b - -/* - * Here is the resume code. - */ - - -/* - * Core99 machines resume here - * r4 has the physical address of SL_PC(sp) (unused) - */ -_GLOBAL(core99_wake_up) - /* Make sure HID0 no longer contains any sleep bit */ - mfspr r3,HID0 - rlwinm r3,r3,0,11,7 /* clear SLEEP, NAP, DOZE bits */ - mtspr HID0,r3 - sync - isync - - /* Won't that cause problems on CPU that doesn't support it ? */ - lis r3, 0 - mtspr SPRN_MMCR0, r3 - - /* sanitize MSR */ - mfmsr r3 - ori r3,r3,MSR_EE|MSR_IP - xori r3,r3,MSR_EE|MSR_IP - sync - isync - mtmsr r3 - sync - isync - - /* Recover sleep storage */ - lis r3,sleep_storage@ha - addi r3,r3,sleep_storage@l - tophys(r3,r3) - lwz r1,0(r3) - - /* Pass thru to older resume code ... */ -/* - * Here is the resume code for older machines. - * r1 has the physical address of SL_PC(sp). - */ - -grackle_wake_up: - /* Enable and then Flash inval the instruction & data cache */ - mfspr r3,HID0 - ori r3,r3, HID0_ICE|HID0_ICFI|HID0_DCE|HID0_DCI - sync - isync - mtspr HID0,r3 - xori r3,r3, HID0_ICFI|HID0_DCI - mtspr HID0,r3 - sync - - /* Restore the kernel's segment registers before - * we do any r1 memory access as we are not sure they - * are in a sane state above the first 256Mb region - */ - li r0,16 /* load up segment register values */ - mtctr r0 /* for context 0 */ - lis r3,0x2000 /* Ku = 1, VSID = 0 */ - li r4,0 -3: mtsrin r3,r4 - addi r3,r3,0x111 /* increment VSID */ - addis r4,r4,0x1000 /* address of next segment */ - bdnz 3b - - /* Restore the remaining bits of the HID0 register. */ - subi r1,r1,SL_PC - lwz r3,SL_HID0(r1) - sync - isync - mtspr HID0,r3 - sync - isync - - /* Restore 7400/7410/7450 specific registers */ - mfspr r3,PVR - srwi r3,r3,16 - cmpli cr0,r3,0x8000 - cmpli cr1,r3,0x000c - cmpli cr2,r3,0x800c - cror 4*cr1+eq,4*cr1+eq,4*cr2+eq - cror 4*cr0+eq,4*cr0+eq,4*cr1+eq - bne 1f - lwz r4,SL_MSSCR0(r1) - sync - mtspr SPRN_MSSCR0,r4 - sync - isync - lwz r4,SL_MSSSR0(r1) - sync - mtspr SPRN_MSSSR0,r4 - sync - isync - bne cr2,1f - li r4,0 - mtspr SPRN_L2CR2,r4 - /* Restore 7450 specific registers */ - beq cr1,1f - lwz r4,SL_HID1(r1) - sync - mtspr HID1,r4 - isync - sync - lwz r4,SPRN_ICTRL(r1) - sync - mtspr SPRN_ICTRL,r4 - isync - sync - lwz r4,SPRN_LDSTCR(r1) - sync - mtspr SPRN_LDSTCR,r4 - isync - sync - lwz r4,SL_LDSTDB(r1) - sync - mtspr SPRN_LDSTDB,r4 - isync - sync -1: - /* Restore the BATs, and SDR1. Then we can turn on the MMU. */ - lwz r4,SL_SDR1(r1) - mtsdr1 r4 - lwz r4,SL_SPRG0(r1) - mtsprg 0,r4 - lwz r4,SL_SPRG0+4(r1) - mtsprg 1,r4 - lwz r4,SL_SPRG0+8(r1) - mtsprg 2,r4 - lwz r4,SL_SPRG0+12(r1) - mtsprg 3,r4 - - lwz r4,SL_DBAT0(r1) - mtdbatu 0,r4 - lwz r4,SL_DBAT0+4(r1) - mtdbatl 0,r4 - lwz r4,SL_DBAT1(r1) - mtdbatu 1,r4 - lwz r4,SL_DBAT1+4(r1) - mtdbatl 1,r4 - lwz r4,SL_DBAT2(r1) - mtdbatu 2,r4 - lwz r4,SL_DBAT2+4(r1) - mtdbatl 2,r4 - lwz r4,SL_DBAT3(r1) - mtdbatu 3,r4 - lwz r4,SL_DBAT3+4(r1) - mtdbatl 3,r4 - lwz r4,SL_IBAT0(r1) - mtibatu 0,r4 - lwz r4,SL_IBAT0+4(r1) - mtibatl 0,r4 - lwz r4,SL_IBAT1(r1) - mtibatu 1,r4 - lwz r4,SL_IBAT1+4(r1) - mtibatl 1,r4 - lwz r4,SL_IBAT2(r1) - mtibatu 2,r4 - lwz r4,SL_IBAT2+4(r1) - mtibatl 2,r4 - lwz r4,SL_IBAT3(r1) - mtibatu 3,r4 - lwz r4,SL_IBAT3+4(r1) - mtibatl 3,r4 - - /* Flush all TLBs */ - lis r4,0x1000 -1: addic. r4,r4,-0x1000 - tlbie r4 - blt 1b - sync - - /* restore the MSR and turn on the MMU */ - lwz r3,SL_MSR(r1) - bl turn_on_mmu - - /* get back the stack pointer */ - tovirt(r1,r1) - - /* Restore TB */ - li r3,0 - mttbl r3 - lwz r3,SL_TB(r1) - lwz r4,SL_TB+4(r1) - mttbu r3 - mttbl r4 - - /* Restore the callee-saved registers and return */ - lwz r0,SL_CR(r1) - mtcr r0 - lwz r2,SL_R2(r1) - lmw r12,SL_R12(r1) - addi r1,r1,SL_SIZE - lwz r0,4(r1) - mtlr r0 - blr - -turn_on_mmu: - mflr r4 - tovirt(r4,r4) - mtsrr0 r4 - mtsrr1 r3 - sync - isync - rfi - - .data - .globl sleep_storage -sleep_storage: - .long 0 diff -Nru a/arch/ppc/platforms/spruce_setup.c b/arch/ppc/platforms/spruce_setup.c --- a/arch/ppc/platforms/spruce_setup.c Wed Apr 2 22:24:04 2003 +++ b/arch/ppc/platforms/spruce_setup.c Wed Apr 2 22:24:04 2003 @@ -133,8 +133,8 @@ #endif /* Identify the system */ - printk("System Identification: IBM Spruce\n"); - printk("IBM Spruce port (C) 2001 MontaVista Software, Inc. (source@mvista.com)\n"); + printk(KERN_INFO "System Identification: IBM Spruce\n"); + printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n"); } static void diff -Nru a/arch/ppc/syslib/prom_init.c b/arch/ppc/syslib/prom_init.c --- a/arch/ppc/syslib/prom_init.c Wed Apr 2 22:24:07 2003 +++ b/arch/ppc/syslib/prom_init.c Wed Apr 2 22:24:07 2003 @@ -275,7 +275,7 @@ { phandle node; ihandle ih; - int i; + int i, j; char type[16], *path; static unsigned char default_colors[] = { 0x00, 0x00, 0x00, @@ -335,26 +335,23 @@ break; } -try_again: - /* - * Open the first display and set its colormap. - */ - if (prom_num_displays > 0) { - path = prom_display_paths[0]; + for (j=0; j 0) - prom_disp_node = prom_display_nodes[0]; - else + if (--prom_num_displays > 0) { + prom_disp_node = prom_display_nodes[j]; + j--; + } else prom_disp_node = NULL; - goto try_again; + continue; } else { prom_print("... ok\n"); /* @@ -369,7 +366,7 @@ break; #ifdef CONFIG_LOGO_LINUX_CLUT224 - clut = logo_linux_clut224.clut; + clut = PTRRELOC(logo_linux_clut224.clut); for (i = 0; i < logo_linux_clut224.clutsize; i++, clut += 3) if (prom_set_color(ih, i + 32, clut[0], diff -Nru a/arch/ppc64/Makefile b/arch/ppc64/Makefile --- a/arch/ppc64/Makefile Wed Apr 2 22:24:04 2003 +++ b/arch/ppc64/Makefile Wed Apr 2 22:24:04 2003 @@ -13,10 +13,10 @@ # Adjusted for PPC64 by Tom Gall # -KERNELLOAD = 0xc000000000000000 +KERNELLOAD := 0xc000000000000000 LDFLAGS := -m elf64ppc -LDFLAGS_vmlinux = -Bstatic -e $(KERNELLOAD) -Ttext $(KERNELLOAD) +LDFLAGS_vmlinux := -Bstatic -e $(KERNELLOAD) -Ttext $(KERNELLOAD) LDFLAGS_BLOB := --format binary --oformat elf64-powerpc CFLAGS += -msoft-float -pipe -Wno-uninitialized -mminimal-toc \ -mtraceback=full -mcpu=power4 @@ -29,21 +29,19 @@ core-$(CONFIG_XMON) += arch/ppc64/xmon/ drivers-$(CONFIG_OPROFILE) += arch/ppc64/oprofile/ -makeboot =$(Q)$(MAKE) -f scripts/Makefile.build obj=arch/ppc64/boot $(1) +boot := arch/ppc64/boot boottarget-$(CONFIG_PPC_PSERIES) := zImage zImage.initrd boottarget-$(CONFIG_PPC_ISERIES) := vmlinux.sminitrd vmlinux.initrd vmlinux.sm $(boottarget-y): vmlinux - $(call makeboot,arch/ppc64/boot/$@) + $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ %_config: arch/ppc64/configs/%_defconfig rm -f .config arch/ppc64/defconfig cp -f arch/ppc64/configs/$(@:config=defconfig) arch/ppc64/defconfig archclean: - $(Q)$(MAKE) -f scripts/Makefile.clean obj=arch/ppc64/boot - -archmrproper: + $(Q)$(MAKE) $(clean)=$(boot) prepare: include/asm-ppc64/offsets.h diff -Nru a/arch/ppc64/boot/Makefile b/arch/ppc64/boot/Makefile --- a/arch/ppc64/boot/Makefile Wed Apr 2 22:24:07 2003 +++ b/arch/ppc64/boot/Makefile Wed Apr 2 22:24:07 2003 @@ -79,7 +79,7 @@ $(obj)/vmlinux.sminitrd: $(obj)/vmlinux.sm $(obj)/addRamDisk $(obj)/ramdisk.image.gz FORCE $(call if_changed,ramdisk) -$(obj)/sysmap.o: System.map $(obj)/piggyback +$(obj)/sysmap.o: System.map $(obj)/piggyback FORCE $(call if_changed,piggy) addsection = $(BOOTOBJCOPY) $(1) \ @@ -92,7 +92,7 @@ quiet_cmd_piggy = PIGGY $@ cmd_piggy = $(obj)/piggyback $(@:.o=) < $< | $(BOOTAS) -o $@ -$(call gz-sec, $(required)): $(obj)/kernel-%.gz: % +$(call gz-sec, $(required)): $(obj)/kernel-%.gz: % FORCE $(call if_changed,gzip) $(obj)/kernel-initrd.gz: $(obj)/ramdisk.image.gz @@ -101,7 +101,7 @@ $(call src-sec, $(required) $(initrd)): $(obj)/kernel-%.c: $(obj)/kernel-%.gz touch $@ -$(call obj-sec, $(required) $(initrd)): $(obj)/kernel-%.o: $(obj)/kernel-%.c +$(call obj-sec, $(required) $(initrd)): $(obj)/kernel-%.o: $(obj)/kernel-%.c FORCE $(call if_changed_dep,bootcc) $(call addsection, $@) diff -Nru a/arch/ppc64/kernel/chrp_setup.c b/arch/ppc64/kernel/chrp_setup.c --- a/arch/ppc64/kernel/chrp_setup.c Wed Apr 2 22:24:04 2003 +++ b/arch/ppc64/kernel/chrp_setup.c Wed Apr 2 22:24:04 2003 @@ -71,9 +71,6 @@ extern void init_ras_IRQ(void); extern void find_and_init_phbs(void); -extern void pSeries_pcibios_fixup(void); -extern void pSeries_pcibios_fixup_bus(struct pci_bus *bus); -extern void iSeries_pcibios_fixup(void); extern void pSeries_get_rtc_time(struct rtc_time *rtc_time); extern int pSeries_set_rtc_time(struct rtc_time *rtc_time); @@ -201,7 +198,6 @@ hpte_init_pSeries(); tce_init_pSeries(); - pSeries_pcibios_init_early(); #ifdef CONFIG_SMP smp_init_pSeries(); @@ -243,15 +239,6 @@ ppc_md.get_irq = xics_get_irq; } ppc_md.init_ras_IRQ = init_ras_IRQ; - - #ifndef CONFIG_PPC_ISERIES - ppc_md.pcibios_fixup = pSeries_pcibios_fixup; - ppc_md.pcibios_fixup_bus = pSeries_pcibios_fixup_bus; - #else - ppc_md.pcibios_fixup = NULL; - // ppc_md.pcibios_fixup = iSeries_pcibios_fixup; - #endif - ppc_md.init = chrp_init2; diff -Nru a/arch/ppc64/kernel/iSeries_pci.c b/arch/ppc64/kernel/iSeries_pci.c --- a/arch/ppc64/kernel/iSeries_pci.c Wed Apr 2 22:24:07 2003 +++ b/arch/ppc64/kernel/iSeries_pci.c Wed Apr 2 22:24:07 2003 @@ -84,8 +84,6 @@ struct iSeries_Device_Node* get_Device_Node(struct pci_dev* PciDev); unsigned long find_and_init_phbs(void); -void fixup_resources(struct pci_dev *dev); -void iSeries_pcibios_fixup(void); struct pci_controller* alloc_phb(struct device_node *dev, char *model, unsigned int addr_size_words) ; void iSeries_Scan_PHBs_Slots(struct pci_controller* Phb); @@ -275,7 +273,7 @@ return 0; } /*********************************************************************** - * ppc64_pcibios_init + * iSeries_pcibios_init * * Chance to initialize and structures or variable before PCI Bus walk. * @@ -302,9 +300,9 @@ PPCDBG(PPCDBG_BUSWALK,"iSeries_pcibios_init Exit.\n"); } /*********************************************************************** - * iSeries_pcibios_fixup(void) + * pcibios_final_fixup(void) ***********************************************************************/ -void __init iSeries_pcibios_fixup(void) +void __init pcibios_final_fixup(void) { struct pci_dev* PciDev; struct iSeries_Device_Node* DeviceNode; @@ -328,8 +326,6 @@ iSeries_allocateDeviceBars(PciDev); - PPCDBGCALL(PPCDBG_BUSWALK,dumpPci_Dev(PciDev) ); - iSeries_Device_Information(PciDev,Buffer, sizeof(Buffer) ); printk("%d. %s\n",DeviceCount,Buffer); @@ -345,11 +341,7 @@ mf_displaySrc(0xC9000200); } -/*********************************************************************** - * iSeries_pcibios_fixup_bus(int Bus) - * - ***********************************************************************/ -void iSeries_pcibios_fixup_bus(struct pci_bus* PciBus) +void pcibios_fixup_bus(struct pci_bus* PciBus) { PPCDBG(PPCDBG_BUSWALK,"iSeries_pcibios_fixup_bus(0x%04X) Entry.\n",PciBus->number); @@ -357,12 +349,12 @@ /*********************************************************************** - * fixup_resources(struct pci_dev *dev) + * pcibios_fixup_resources(struct pci_dev *dev) * ***********************************************************************/ -void fixup_resources(struct pci_dev *PciDev) +void pcibios_fixup_resources(struct pci_dev *PciDev) { - PPCDBG(PPCDBG_BUSWALK,"fixup_resources PciDev %p\n",PciDev); + PPCDBG(PPCDBG_BUSWALK,"pcibios_fixup_resources PciDev %p\n",PciDev); } @@ -910,18 +902,3 @@ } while (CheckReturnCode("WWL",DevNode, Return.rc) != 0); if(Pci_Trace_Flag == 1) PCIFR("WWL: IoAddress 0x%p = 0x%08X",IoAddress, Data); } -/* - * This is called very early before the page table is setup. - * There are warnings here because of type mismatches.. Okay for now. AHT - */ -void -iSeries_pcibios_init_early(void) -{ - //ppc_md.pcibios_read_config_byte = iSeries_Node_read_config_byte; - //ppc_md.pcibios_read_config_word = iSeries_Node_read_config_word; - //ppc_md.pcibios_read_config_dword = iSeries_Node_read_config_dword; - //ppc_md.pcibios_write_config_byte = iSeries_Node_write_config_byte; - //ppc_md.pcibios_write_config_word = iSeries_Node_write_config_word; - //ppc_md.pcibios_write_config_dword = iSeries_Node_write_config_dword; -} - diff -Nru a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c --- a/arch/ppc64/kernel/iSeries_setup.c Wed Apr 2 22:24:06 2003 +++ b/arch/ppc64/kernel/iSeries_setup.c Wed Apr 2 22:24:06 2003 @@ -62,8 +62,6 @@ pte_t * ptep, unsigned hpteflags, unsigned bolted ); extern void ppcdbg_initialize(void); extern void iSeries_pcibios_init(void); -extern void iSeries_pcibios_fixup(void); -extern void iSeries_pcibios_fixup_bus(int); static void iSeries_setup_dprofile(void); /* Global Variables */ @@ -316,9 +314,6 @@ ppc_md.init_ras_IRQ = NULL; ppc_md.get_irq = iSeries_get_irq; ppc_md.init = NULL; - - ppc_md.pcibios_fixup = iSeries_pcibios_fixup; - ppc_md.pcibios_fixup_bus = iSeries_pcibios_fixup_bus; ppc_md.restart = iSeries_restart; ppc_md.power_off = iSeries_power_off; diff -Nru a/arch/ppc64/kernel/pSeries_lpar.c b/arch/ppc64/kernel/pSeries_lpar.c --- a/arch/ppc64/kernel/pSeries_lpar.c Wed Apr 2 22:24:07 2003 +++ b/arch/ppc64/kernel/pSeries_lpar.c Wed Apr 2 22:24:07 2003 @@ -320,7 +320,6 @@ #ifdef CONFIG_SMP smp_init_pSeries(); #endif - pSeries_pcibios_init_early(); /* The keyboard is not useful in the LPAR environment. * Leave all the interfaces NULL. diff -Nru a/arch/ppc64/kernel/pSeries_pci.c b/arch/ppc64/kernel/pSeries_pci.c --- a/arch/ppc64/kernel/pSeries_pci.c Wed Apr 2 22:24:08 2003 +++ b/arch/ppc64/kernel/pSeries_pci.c Wed Apr 2 22:24:08 2003 @@ -2,6 +2,7 @@ * pSeries_pci.c * * Copyright (C) 2001 Dave Engebretsen, IBM Corporation + * Copyright (C) 2003 Anton Blanchard , IBM * * pSeries specific routines for PCI. * @@ -51,6 +52,8 @@ static int s7a_workaround; +extern unsigned long pci_probe_only; + static int rtas_read_config(struct device_node *dn, int where, int size, u32 *val) { unsigned long returnval = ~0L; @@ -371,9 +374,6 @@ phb->last_busno += (phb->global_number << 8); } - /* Dump PHB information for Debug */ - PPCDBGCALL(PPCDBG_PHBINIT, dumpPci_Controller(phb)); - return phb; } @@ -423,129 +423,96 @@ return 0; } -void -fixup_resources(struct pci_dev *dev) +void pcibios_name_device(struct pci_dev *dev) { - int i; - struct pci_controller *phb = PCI_GET_PHB_PTR(dev); struct device_node *dn; - /* Add IBM loc code (slot) as a prefix to the device names for service */ + /* + * Add IBM loc code (slot) as a prefix to the device names for service + */ dn = pci_device_to_OF_node(dev); if (dn) { char *loc_code = get_property(dn, "ibm,loc-code", 0); if (loc_code) { int loc_len = strlen(loc_code); if (loc_len < sizeof(dev->dev.name)) { - memmove(dev->dev.name+loc_len+1, dev->dev.name, sizeof(dev->dev.name)-loc_len-1); + memmove(dev->dev.name+loc_len+1, dev->dev.name, + sizeof(dev->dev.name)-loc_len-1); memcpy(dev->dev.name, loc_code, loc_len); dev->dev.name[loc_len] = ' '; dev->dev.name[sizeof(dev->dev.name)-1] = '\0'; } } } +} - PPCDBG(PPCDBG_PHBINIT, "fixup_resources:\n"); - PPCDBG(PPCDBG_PHBINIT, "\tphb = 0x%016LX\n", phb); - PPCDBG(PPCDBG_PHBINIT, "\tphb->pci_io_offset = 0x%016LX\n", phb->pci_io_offset); - PPCDBG(PPCDBG_PHBINIT, "\tphb->pci_mem_offset = 0x%016LX\n", phb->pci_mem_offset); - - PPCDBG(PPCDBG_PHBINIT, "\tdev->dev.name = %s\n", dev->dev.name); - PPCDBG(PPCDBG_PHBINIT, "\tdev->vendor:device = 0x%04X : 0x%04X\n", dev->vendor, dev->device); - - if (phb == NULL) - return; - - for (i = 0; i < DEVICE_COUNT_RESOURCE; ++i) { - PPCDBG(PPCDBG_PHBINIT, "\tdevice %x.%x[%d] (flags %x) [%lx..%lx]\n", - dev->bus->number, dev->devfn, i, - dev->resource[i].flags, - dev->resource[i].start, - dev->resource[i].end); - - if ((dev->resource[i].start == 0) && (dev->resource[i].end == 0)) { - continue; - } - if (dev->resource[i].start > dev->resource[i].end) { - /* Bogus resource. Just clear it out. */ - dev->resource[i].start = dev->resource[i].end = 0; - continue; - } +void __init pcibios_fixup_device_resources(struct pci_dev *dev, + struct pci_bus *bus) +{ + /* Update device resources. */ + struct pci_controller *hose = PCI_GET_PHB_PTR(bus); + int i; + for (i = 0; i < PCI_NUM_RESOURCES; i++) { if (dev->resource[i].flags & IORESOURCE_IO) { - unsigned long offset = (unsigned long)phb->io_base_virt - pci_io_base; + unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base; dev->resource[i].start += offset; dev->resource[i].end += offset; - PPCDBG(PPCDBG_PHBINIT, "\t\t-> now [%lx .. %lx]\n", - dev->resource[i].start, dev->resource[i].end); - } else if (dev->resource[i].flags & IORESOURCE_MEM) { - if (dev->resource[i].start == 0) { - /* Bogus. Probably an unused bridge. */ - dev->resource[i].end = 0; - } else { - dev->resource[i].start += phb->pci_mem_offset; - dev->resource[i].end += phb->pci_mem_offset; - } - PPCDBG(PPCDBG_PHBINIT, "\t\t-> now [%lx..%lx]\n", - dev->resource[i].start, dev->resource[i].end); - - } else { - continue; } + else if (dev->resource[i].flags & IORESOURCE_MEM) { + dev->resource[i].start += hose->pci_mem_offset; + dev->resource[i].end += hose->pci_mem_offset; + } + } +} - /* zap the 2nd function of the winbond chip */ - if (dev->resource[i].flags & IORESOURCE_IO - && dev->bus->number == 0 && dev->devfn == 0x81) - dev->resource[i].flags &= ~IORESOURCE_IO; - } -} - -void __init pSeries_pcibios_fixup_bus(struct pci_bus *bus) +void __init pcibios_fixup_bus(struct pci_bus *bus) { - struct pci_controller *phb = PCI_GET_PHB_PTR(bus); + struct pci_controller *hose = PCI_GET_PHB_PTR(bus); + struct list_head *ln; + + /* XXX or bus->parent? */ + struct pci_dev *dev = bus->self; struct resource *res; int i; - if (bus->parent == NULL) { - /* This is a host bridge - fill in its resources */ - phb->bus = bus; - bus->resource[0] = res = &phb->io_resource; + if (!dev) { + /* Root bus. */ + + hose->bus = bus; + bus->resource[0] = res = &hose->io_resource; if (!res->flags) BUG(); /* No I/O resource for this PHB? */ + if (request_resource(&ioport_resource, res)) + printk(KERN_ERR "Failed to request IO" + "on hose %d\n", 0 /* FIXME */); + for (i = 0; i < 3; ++i) { - res = &phb->mem_resources[i]; - if (!res->flags) { - if (i == 0) - BUG(); /* No memory resource for this PHB? */ - } + res = &hose->mem_resources[i]; + if (!res->flags && i == 0) + BUG(); /* No memory resource for this PHB? */ bus->resource[i+1] = res; + if (res->flags && request_resource(&iomem_resource, res)) + printk(KERN_ERR "Failed to request MEM" + "on hose %d\n", 0 /* FIXME */); } - } else { + } else if (pci_probe_only && + (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { /* This is a subordinate bridge */ + pci_read_bridge_bases(bus); + pcibios_fixup_device_resources(dev, bus); + } - for (i = 0; i < 4; ++i) { - if ((res = bus->resource[i]) == NULL) - continue; - if (!res->flags) - continue; - if (res == pci_find_parent_resource(bus->self, res)) { - /* Transparent resource -- don't try to "fix" it. */ - continue; - } - if (res->flags & IORESOURCE_IO) { - unsigned long offset = (unsigned long)phb->io_base_virt - pci_io_base; - res->start += offset; - res->end += offset; - } else if (phb->pci_mem_offset - && (res->flags & IORESOURCE_MEM)) { - if (res->start < phb->pci_mem_offset) { - res->start += phb->pci_mem_offset; - res->end += phb->pci_mem_offset; - } - } - } + /* XXX Need to check why Alpha doesnt do this - Anton */ + if (!pci_probe_only) + return; + + for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) { + struct pci_dev *dev = pci_dev_b(ln); + if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI) + pcibios_fixup_device_resources(dev, bus); } } @@ -562,19 +529,20 @@ } } -void __init -pSeries_pcibios_fixup(void) +extern void chrp_request_regions(void); + +void __init pcibios_final_fixup(void) { struct pci_dev *dev; - PPCDBG(PPCDBG_PHBINIT, "pSeries_pcibios_fixup: start\n"); - check_s7a(); - - pci_for_each_dev(dev) { + + pci_for_each_dev(dev) pci_read_irq_line(dev); - PPCDBGCALL(PPCDBG_PHBINIT, dumpPci_Dev(dev) ); - } + + chrp_request_regions(); + pci_fix_bus_sysdata(); + create_tce_tables(); } /*********************************************************************** @@ -595,14 +563,4 @@ node=node->parent; } return NULL; -} - -/* - * This is called very early before the page table is setup. - */ -void -pSeries_pcibios_init_early(void) -{ - ppc_md.pcibios_read_config = rtas_read_config; - ppc_md.pcibios_write_config = rtas_write_config; } diff -Nru a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c --- a/arch/ppc64/kernel/pci.c Wed Apr 2 22:24:07 2003 +++ b/arch/ppc64/kernel/pci.c Wed Apr 2 22:24:07 2003 @@ -2,6 +2,9 @@ * Port for PPC64 David Engebretsen, IBM Corp. * Contains common pci routines for ppc64 platform, pSeries and iSeries brands. * + * Copyright (C) 2003 Anton Blanchard , IBM + * Rework, based on alpha PCI code. + * * 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,31 +33,37 @@ #include #include #include -#include #include "pci.h" +unsigned long pci_probe_only = 1; +unsigned long pci_assign_all_buses = 0; + +unsigned int pcibios_assign_all_busses(void) +{ + return pci_assign_all_buses; +} + /* pci_io_base -- the base address from which io bars are offsets. * This is the lowest I/O base address (so bar values are always positive), * and it *must* be the start of ISA space if an ISA bus exists because * ISA drivers use hard coded offsets. If no ISA bus exists a dummy * page is mapped and isa_io_limit prevents access to it. */ -unsigned long isa_io_base = 0; /* NULL if no ISA bus */ -unsigned long pci_io_base = 0; +unsigned long isa_io_base; /* NULL if no ISA bus */ +unsigned long pci_io_base; -static void pcibios_fixup_resources(struct pci_dev* dev); +void pcibios_name_device(struct pci_dev* dev); +void pcibios_final_fixup(void); static void fixup_broken_pcnet32(struct pci_dev* dev); static void fixup_windbond_82c105(struct pci_dev* dev); -void fixup_resources(struct pci_dev* dev); -void iSeries_pcibios_init(void); +void iSeries_pcibios_init(void); -struct pci_controller* hose_head; -struct pci_controller** hose_tail = &hose_head; +struct pci_controller *hose_head; +struct pci_controller **hose_tail = &hose_head; -int global_phb_number = 0; /* Global phb counter */ -struct pci_controller *phbtab[PCI_MAX_PHB]; +int global_phb_number; /* Global phb counter */ /* Cached ISA bridge dev. */ struct pci_dev *ppc64_isabridge_dev = NULL; @@ -62,8 +71,8 @@ struct pci_fixup pcibios_fixups[] = { { PCI_FIXUP_HEADER, PCI_VENDOR_ID_TRIDENT, PCI_ANY_ID, fixup_broken_pcnet32 }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, fixup_windbond_82c105 }, - { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources }, - { 0 } + { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pcibios_name_device }, + { 0 } }; static void fixup_broken_pcnet32(struct pci_dev* dev) @@ -81,14 +90,21 @@ * p610. We should probably be more careful in case * someone tries to plug in a similar adapter. */ + int i; unsigned int reg; printk("Using INTC for W82c105 IDE controller.\n"); pci_read_config_dword(dev, 0x40, ®); /* Enable LEGIRQ to use INTC instead of ISA interrupts */ pci_write_config_dword(dev, 0x40, reg | (1<<11)); -} + for (i = 0; i < DEVICE_COUNT_RESOURCE; ++i) { + /* zap the 2nd function of the winbond chip */ + if (dev->resource[i].flags & IORESOURCE_IO + && dev->bus->number == 0 && dev->devfn == 0x81) + dev->resource[i].flags &= ~IORESOURCE_IO; + } +} /* Given an mmio phys address, find a pci device that implements * this address. This is of course expensive, but only used @@ -127,12 +143,30 @@ return NULL; } -static void -pcibios_fixup_resources(struct pci_dev* dev) +void __devinit +pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, + struct resource *res) { - fixup_resources(dev); + unsigned long offset = 0; + struct pci_controller *hose = PCI_GET_PHB_PTR(dev); + + if (!hose) + return; + + if (res->flags & IORESOURCE_IO) + offset = (unsigned long)hose->io_base_virt - pci_io_base; + + if (res->flags & IORESOURCE_MEM) + offset = hose->pci_mem_offset; + + region->start = res->start - offset; + region->end = res->end - offset; } +#ifdef CONFIG_HOTPLUG +EXPORT_SYMBOL(pcibios_resource_to_bus); +#endif + /* * We need to avoid collisions with `mirrored' VGA ports * and other strange ISA hardware, so we always want the @@ -146,180 +180,38 @@ * but we want to try to avoid allocating at 0x2900-0x2bff * which might have be mirrored at 0x0100-0x03ff.. */ -void -pcibios_align_resource(void *data, struct resource *res, - unsigned long size, unsigned long align) +void pcibios_align_resource(void *data, struct resource *res, + unsigned long size, unsigned long align) { struct pci_dev *dev = data; + struct pci_controller *hose = PCI_GET_PHB_PTR(dev); + unsigned long start = res->start; + unsigned long alignto; if (res->flags & IORESOURCE_IO) { - unsigned long start = res->start; - - if (size > 0x100) { - printk(KERN_ERR "PCI: Can not align I/O Region %s %s because size %ld is too large.\n", - dev->slot_name, res->name, size); - } - - if (start & 0x300) { + unsigned long offset = (unsigned long)hose->io_base_virt - + pci_io_base; + /* Make sure we start at our min on all hoses */ + if (start - offset < PCIBIOS_MIN_IO) + start = PCIBIOS_MIN_IO + offset; + + /* + * Put everything into 0x00-0xff region modulo 0x400 + */ + if (start & 0x300) start = (start + 0x3ff) & ~0x3ff; - res->start = start; - } - } -} -/* - * Handle resources of PCI devices. If the world were perfect, we could - * just allocate all the resource regions and do nothing more. It isn't. - * On the other hand, we cannot just re-allocate all devices, as it would - * require us to know lots of host bridge internals. So we attempt to - * keep as much of the original configuration as possible, but tweak it - * when it's found to be wrong. - * - * Known BIOS problems we have to work around: - * - I/O or memory regions not configured - * - regions configured, but not enabled in the command register - * - bogus I/O addresses above 64K used - * - expansion ROMs left enabled (this may sound harmless, but given - * the fact the PCI specs explicitly allow address decoders to be - * shared between expansion ROMs and other resource regions, it's - * at least dangerous) - * - * Our solution: - * (1) Allocate resources for all buses behind PCI-to-PCI bridges. - * This gives us fixed barriers on where we can allocate. - * (2) Allocate resources for all enabled devices. If there is - * a collision, just mark the resource as unallocated. Also - * disable expansion ROMs during this step. - * (3) Try to allocate resources for disabled devices. If the - * resources were assigned correctly, everything goes well, - * if they weren't, they won't disturb allocation of other - * resources. - * (4) Assign new addresses to resources which were either - * not configured at all or misconfigured. If explicitly - * requested by the user, configure expansion ROM address - * as well. - */ + } else if (res->flags & IORESOURCE_MEM) { + /* Make sure we start at our min on all hoses */ + if (start - hose->pci_mem_offset < PCIBIOS_MIN_MEM) + start = PCIBIOS_MIN_MEM + hose->pci_mem_offset; -static void __init -pcibios_allocate_bus_resources(struct list_head *bus_list) -{ - struct list_head *ln; - struct pci_bus *bus; - int i; - struct resource *res, *pr; - - /* Depth-First Search on bus tree */ - for (ln=bus_list->next; ln != bus_list; ln=ln->next) { - bus = pci_bus_b(ln); - for (i = 0; i < 4; ++i) { - if ((res = bus->resource[i]) == NULL || !res->flags) - continue; - if (bus->parent == NULL) - pr = (res->flags & IORESOURCE_IO)? - &ioport_resource: &iomem_resource; - else - pr = pci_find_parent_resource(bus->self, res); - - if (pr == res) - continue; /* transparent bus or undefined */ - if (pr && request_resource(pr, res) == 0) - continue; - printk(KERN_ERR "PCI: Cannot allocate resource region " - "%d of PCI bridge %x\n", i, bus->number); - printk(KERN_ERR "PCI: resource is %lx..%lx (%lx), parent %p\n", - res->start, res->end, res->flags, pr); - } - pcibios_allocate_bus_resources(&bus->children); + /* Align to multiple of size of minimum base. */ + alignto = max(0x1000UL, align); + start = ALIGN(start, alignto); } -} - -static void __init -pcibios_allocate_resources(int pass) -{ - struct pci_dev *dev; - int idx, disabled; - u16 command; - struct resource *r, *pr; - pci_for_each_dev(dev) { - pci_read_config_word(dev, PCI_COMMAND, &command); - for(idx = 0; idx < 6; idx++) { - r = &dev->resource[idx]; - if (r->parent) /* Already allocated */ - continue; - if (!r->start) /* Address not assigned at all */ - continue; - - if (r->flags & IORESOURCE_IO) - disabled = !(command & PCI_COMMAND_IO); - else - disabled = !(command & PCI_COMMAND_MEMORY); - if (pass == disabled) { - PPCDBG(PPCDBG_PHBINIT, - "PCI: Resource %08lx-%08lx (f=%lx, d=%d, p=%d)\n", - r->start, r->end, r->flags, disabled, pass); - pr = pci_find_parent_resource(dev, r); - if (!pr || request_resource(pr, r) < 0) { - PPCDBG(PPCDBG_PHBINIT, - "PCI: Cannot allocate resource region %d of device %s, pr = 0x%lx\n", idx, dev->slot_name, pr); - if(pr) { - PPCDBG(PPCDBG_PHBINIT, - "PCI: Cannot allocate resource 0x%lx\n", request_resource(pr,r)); - } - /* We'll assign a new address later */ - r->end -= r->start; - r->start = 0; - } - } - } - if (!pass) { - r = &dev->resource[PCI_ROM_RESOURCE]; - if (r->flags & PCI_ROM_ADDRESS_ENABLE) { - /* Turn the ROM off, leave the resource region, but keep it unregistered. */ - u32 reg; - r->flags &= ~PCI_ROM_ADDRESS_ENABLE; - pci_read_config_dword(dev, dev->rom_base_reg, ®); - pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE); - } - } - } -} - -static void __init -pcibios_assign_resources(void) -{ - struct pci_dev *dev; - int idx; - struct resource *r; - - pci_for_each_dev(dev) { - int class = dev->class >> 8; - - /* Don't touch classless devices and host bridges */ - if (!class || class == PCI_CLASS_BRIDGE_HOST) - continue; - - for (idx = 0; idx < 6; idx++) { - r = &dev->resource[idx]; - - /* - * We shall assign a new address to this resource, - * either because the BIOS (sic) forgot to do so - * or because we have decided the old address was - * unusable for some reason. - */ - if (!r->start && r->end) - pci_assign_resource(dev, idx); - } - -#if 0 /* don't assign ROMs */ - r = &dev->resource[PCI_ROM_RESOURCE]; - r->end -= r->start; - r->start = 0; - if (r->end) - pci_assign_resource(dev, PCI_ROM_RESOURCE); -#endif - } + res->start = start; } /* @@ -358,20 +250,49 @@ else memcpy(hose->what,model,7); hose->type = controller_type; - hose->global_number = global_phb_number; - phbtab[global_phb_number++] = hose; + hose->global_number = global_phb_number++; *hose_tail = hose; hose_tail = &hose->next; return hose; } -static int __init -pcibios_init(void) +static void __init pcibios_claim_one_bus(struct pci_bus *b) +{ + struct list_head *ld; + struct pci_bus *child_bus; + + for (ld = b->devices.next; ld != &b->devices; ld = ld->next) { + struct pci_dev *dev = pci_dev_b(ld); + int i; + + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + struct resource *r = &dev->resource[i]; + + if (r->parent || !r->start || !r->flags) + continue; + pci_claim_resource(dev, i); + } + } + + list_for_each_entry(child_bus, &b->children, node) + pcibios_claim_one_bus(child_bus); +} + +static void __init pcibios_claim_of_setup(void) +{ + struct list_head *lb; + + for (lb = pci_root_buses.next; lb != &pci_root_buses; lb = lb->next) { + struct pci_bus *b = pci_bus_b(lb); + pcibios_claim_one_bus(b); + } +} + +static int __init pcibios_init(void) { struct pci_controller *hose; struct pci_bus *bus; - int next_busno; #ifdef CONFIG_PPC_ISERIES iSeries_pcibios_init(); @@ -379,38 +300,26 @@ //ppc64_boot_msg(0x40, "PCI Probe"); printk("PCI: Probing PCI hardware\n"); - PPCDBG(PPCDBG_BUSWALK,"PCI: Probing PCI hardware\n"); /* Scan all of the recorded PCI controllers. */ - for (next_busno = 0, hose = hose_head; hose; hose = hose->next) { + for (hose = hose_head; hose; hose = hose->next) { hose->last_busno = 0xff; - bus = pci_scan_bus(hose->first_busno, hose->ops, hose->arch_data); + bus = pci_scan_bus(hose->first_busno, hose->ops, + hose->arch_data); hose->bus = bus; hose->last_busno = bus->subordinate; - if (next_busno <= hose->last_busno) - next_busno = hose->last_busno+1; } - /* Call machine dependent fixup */ - if (ppc_md.pcibios_fixup) { - ppc_md.pcibios_fixup(); - } - - /* Allocate and assign resources */ - pcibios_allocate_bus_resources(&pci_root_buses); - pcibios_allocate_resources(0); - pcibios_allocate_resources(1); - pcibios_assign_resources(); - -#ifndef CONFIG_PPC_ISERIES - void chrp_request_regions(void); - chrp_request_regions(); + if (pci_probe_only) + pcibios_claim_of_setup(); + else + /* FIXME: `else' will be removed when + pci_assign_unassigned_resources() is able to work + correctly with [partially] allocated PCI tree. */ + pci_assign_unassigned_resources(); - pci_fix_bus_sysdata(); - - create_tce_tables(); - PPCDBG(PPCDBG_BUSWALK,"pSeries create_tce_tables()\n"); -#endif + /* Call machine dependent fixup */ + pcibios_final_fixup(); /* Cache the location of the ISA bridge (if we have one) */ ppc64_isabridge_dev = pci_find_class(PCI_CLASS_BRIDGE_ISA << 8, NULL); @@ -418,7 +327,6 @@ printk("ISA bridge at %s\n", ppc64_isabridge_dev->slot_name); printk("PCI: Probing PCI hardware done\n"); - PPCDBG(PPCDBG_BUSWALK,"PCI: Probing PCI hardware done.\n"); //ppc64_boot_msg(0x41, "PCI Done"); return 0; @@ -426,12 +334,6 @@ subsys_initcall(pcibios_init); -void __init pcibios_fixup_bus(struct pci_bus *bus) -{ - if (ppc_md.pcibios_fixup_bus) - ppc_md.pcibios_fixup_bus(bus); -} - char __init *pcibios_setup(char *str) { return str; @@ -439,35 +341,29 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) { - u16 cmd, old_cmd; - int idx; - struct resource *r; - - PPCDBG(PPCDBG_BUSWALK,"PCI: %s for device %s \n", __FUNCTION__, - dev->slot_name); + u16 cmd, oldcmd; + int i; pci_read_config_word(dev, PCI_COMMAND, &cmd); - old_cmd = cmd; - for (idx = 0; idx < 6; idx++) { + oldcmd = cmd; + + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + struct resource *res = &dev->resource[i]; + /* Only set up the requested stuff */ - if (!(mask & (1<resource[idx]; - if (!r->start && r->end) { - printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", dev->slot_name); - return -EINVAL; - } - if (r->flags & IORESOURCE_IO) + if (res->flags & IORESOURCE_IO) cmd |= PCI_COMMAND_IO; - if (r->flags & IORESOURCE_MEM) + if (res->flags & IORESOURCE_MEM) cmd |= PCI_COMMAND_MEMORY; } - if (cmd != old_cmd) { - printk("PCI: Enabling device %s (%04x -> %04x)\n", - dev->slot_name, old_cmd, cmd); - PPCDBG(PPCDBG_BUSWALK,"PCI: Enabling device %s \n", - dev->slot_name); + + if (cmd != oldcmd) { + printk(KERN_DEBUG "PCI: Enabling device: (%s), cmd %x\n", + dev->slot_name, cmd); + /* Enable the appropriate bits in the PCI command register. */ pci_write_config_word(dev, PCI_COMMAND, cmd); } return 0; @@ -608,113 +504,4 @@ vma->vm_end - vma->vm_start, vma->vm_page_prot); return ret; -} - -/***************************************************** - * Dump Resource information - *****************************************************/ -void dumpResources(struct resource* Resource) -{ - if(Resource != NULL) { - int Flags = 0x00000F00 & Resource->flags; - if(Resource->start == 0 && Resource->end == 0) return; - else if(Resource->start == Resource->end ) return; - else { - if (Flags == IORESOURCE_IO) udbg_printf("IO.:"); - else if(Flags == IORESOURCE_MEM) udbg_printf("MEM:"); - else if(Flags == IORESOURCE_IRQ) udbg_printf("IRQ:"); - else udbg_printf("0x%02X:",Resource->flags); - - } - udbg_printf("0x%016LX / 0x%016LX (0x%08X)\n", - Resource->start, Resource->end, Resource->end - Resource->start); - } -} - -int resourceSize(struct resource* Resource) -{ - if(Resource->start == 0 && Resource->end == 0) return 0; - else if(Resource->start == Resource->end ) return 0; - else return (Resource->end-1)-Resource->start; -} - - -/***************************************************** - * Dump PHB information for Debug - *****************************************************/ -void dumpPci_Controller(struct pci_controller* phb) -{ - udbg_printf("\tpci_controller= 0x%016LX\n", phb); - if (phb != NULL) { - udbg_printf("\twhat & type = %s 0x%02X\n ",phb->what,phb->type); - udbg_printf("\tbus = "); - if (phb->bus != NULL) udbg_printf("0x%02X\n", phb->bus->number); - else udbg_printf("\n"); - udbg_printf("\tarch_data = 0x%016LX\n", phb->arch_data); - udbg_printf("\tfirst_busno = 0x%02X\n", phb->first_busno); - udbg_printf("\tlast_busno = 0x%02X\n", phb->last_busno); - udbg_printf("\tio_base_virt* = 0x%016LX\n", phb->io_base_virt); - udbg_printf("\tio_base_phys = 0x%016LX\n", phb->io_base_phys); - udbg_printf("\tpci_mem_offset= 0x%016LX\n", phb->pci_mem_offset); - udbg_printf("\tpci_io_offset = 0x%016LX\n", phb->pci_io_offset); - - udbg_printf("\tResources\n"); - dumpResources(&phb->io_resource); - if (phb->mem_resource_count > 0) dumpResources(&phb->mem_resources[0]); - if (phb->mem_resource_count > 1) dumpResources(&phb->mem_resources[1]); - if (phb->mem_resource_count > 2) dumpResources(&phb->mem_resources[2]); - - udbg_printf("\tglobal_num = 0x%02X\n", phb->global_number); - udbg_printf("\tlocal_num = 0x%02X\n", phb->local_number); - } -} - -/***************************************************** - * Dump PHB information for Debug - *****************************************************/ -void dumpPci_Bus(struct pci_bus* Pci_Bus) -{ - int i; - udbg_printf("\tpci_bus = 0x%016LX \n",Pci_Bus); - if (Pci_Bus != NULL) { - - udbg_printf("\tnumber = 0x%02X \n",Pci_Bus->number); - udbg_printf("\tprimary = 0x%02X \n",Pci_Bus->primary); - udbg_printf("\tsecondary = 0x%02X \n",Pci_Bus->secondary); - udbg_printf("\tsubordinate = 0x%02X \n",Pci_Bus->subordinate); - - for (i=0;i<4;++i) { - if(Pci_Bus->resource[i] == NULL) continue; - if(Pci_Bus->resource[i]->start == 0 && Pci_Bus->resource[i]->end == 0) break; - udbg_printf("\tResources[%d]",i); - dumpResources(Pci_Bus->resource[i]); - } - } -} - -/***************************************************** - * Dump Device information for Debug - *****************************************************/ -void dumpPci_Dev(struct pci_dev* Pci_Dev) -{ - int i; - udbg_printf("\tpci_dev* = 0x%p\n",Pci_Dev); - if ( Pci_Dev == NULL ) return; - udbg_printf("\tname = %s \n",Pci_Dev->dev.name); - udbg_printf("\tbus* = 0x%p\n",Pci_Dev->bus); - udbg_printf("\tsysdata* = 0x%p\n",Pci_Dev->sysdata); - udbg_printf("\tDevice = 0x%4X%02X:%02X.%02X 0x%04X:%04X\n", - PCI_GET_PHB_NUMBER(Pci_Dev), - PCI_GET_BUS_NUMBER(Pci_Dev), - PCI_SLOT(Pci_Dev->devfn), - PCI_FUNC(Pci_Dev->devfn), - Pci_Dev->vendor, - Pci_Dev->device); - udbg_printf("\tHdr/Irq = 0x%02X/0x%02X \n",Pci_Dev->hdr_type,Pci_Dev->irq); - for (i=0;iresource[i].start == 0 && Pci_Dev->resource[i].end == 0) continue; - udbg_printf("\tResources[%d] ",i); - dumpResources(&Pci_Dev->resource[i]); - } - dumpResources(&Pci_Dev->resource[i]); } diff -Nru a/arch/ppc64/kernel/pci.h b/arch/ppc64/kernel/pci.h --- a/arch/ppc64/kernel/pci.h Wed Apr 2 22:24:04 2003 +++ b/arch/ppc64/kernel/pci.h Wed Apr 2 22:24:04 2003 @@ -19,18 +19,14 @@ extern struct pci_controller* hose_head; extern struct pci_controller** hose_tail; -/* PHB's are also in a table. */ -#define PCI_MAX_PHB 64 -extern int global_phb_number; -extern struct pci_controller *phbtab[]; + +extern int global_phb_number; /******************************************************************* * Platform functions that are brand specific implementation. *******************************************************************/ extern unsigned long find_and_init_phbs(void); -extern void ppc64_pcibios_init(void); - extern struct pci_dev *ppc64_isabridge_dev; /* may be NULL if no ISA bus */ /******************************************************************* @@ -46,10 +42,6 @@ void pci_fix_bus_sysdata(void); struct device_node *fetch_dev_dn(struct pci_dev *dev); -void iSeries_pcibios_init_early(void); -void pSeries_pcibios_init_early(void); -void pSeries_pcibios_init(void); - /******************************************************************* * Helper macros for extracting data from pci structures. * PCI_GET_PHB_PTR(struct pci_dev*) returns the Phb pointer. @@ -59,13 +51,5 @@ #define PCI_GET_PHB_PTR(dev) (((struct device_node *)(dev)->sysdata)->phb) #define PCI_GET_PHB_NUMBER(dev) (((dev)->bus->number&0x00FFFF00)>>8) #define PCI_GET_BUS_NUMBER(dev) ((dev)->bus->number&0x0000FF) - -/******************************************************************* - * Debugging Routines. - *******************************************************************/ -extern void dumpResources(struct resource* Resource); -extern void dumpPci_Controller(struct pci_controller* phb); -extern void dumpPci_Bus(struct pci_bus* Pci_Bus); -extern void dumpPci_Dev(struct pci_dev* Pci_Dev); #endif /* __PPC_KERNEL_PCI_H__ */ diff -Nru a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c --- a/arch/ppc64/kernel/process.c Wed Apr 2 22:24:06 2003 +++ b/arch/ppc64/kernel/process.c Wed Apr 2 22:24:06 2003 @@ -208,6 +208,12 @@ } else { childregs->gpr[1] = usp; p->thread.regs = childregs; + if (clone_flags & CLONE_SETTLS) { + if (test_thread_flag(TIF_32BIT)) + childregs->gpr[2] = childregs->gpr[6]; + else + childregs->gpr[13] = childregs->gpr[6]; + } } childregs->gpr[3] = 0; /* Result from fork() */ sp -= STACK_FRAME_OVERHEAD; @@ -304,7 +310,7 @@ if (clone_flags & (CLONE_PARENT_SETTID | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) { parent_tidptr = p3; - child_tidptr = p4; + child_tidptr = p5; if (test_thread_flag(TIF_32BIT)) { parent_tidptr &= 0xffffffff; child_tidptr &= 0xffffffff; diff -Nru a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c --- a/arch/ppc64/kernel/prom.c Wed Apr 2 22:24:06 2003 +++ b/arch/ppc64/kernel/prom.c Wed Apr 2 22:24:06 2003 @@ -1270,8 +1270,8 @@ break; #ifdef CONFIG_LOGO_LINUX_CLUT224 - clut = RELOC(RELOC(&logo_linux_clut224)->clut); - for (i = 0; i < logo_linux_clut224.clutsize; i++, clut += 3) + clut = PTRRELOC(RELOC(logo_linux_clut224.clut)); + for (i = 0; i < RELOC(logo_linux_clut224.clutsize); i++, clut += 3) if (prom_set_color(ih, i + 32, clut[0], clut[1], clut[2]) != 0) break; diff -Nru a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c --- a/arch/ppc64/kernel/smp.c Wed Apr 2 22:24:06 2003 +++ b/arch/ppc64/kernel/smp.c Wed Apr 2 22:24:06 2003 @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include diff -Nru a/arch/ppc64/kernel/stab.c b/arch/ppc64/kernel/stab.c --- a/arch/ppc64/kernel/stab.c Wed Apr 2 22:24:07 2003 +++ b/arch/ppc64/kernel/stab.c Wed Apr 2 22:24:07 2003 @@ -197,11 +197,23 @@ PMC_SW_PROCESSOR(stab_capacity_castouts); + /* + * Never cast out the segment for our kernel stack. Since we + * dont invalidate the ERAT we could have a valid translation + * for the kernel stack during the first part of exception exit + * which gets invalidated due to a tlbie from another cpu at a + * non recoverable point (after setting srr0/1) - Anton + */ castout_entry = get_paca()->xStab_data.next_round_robin; - entry = castout_entry; - castout_entry++; - if (castout_entry >= naca->slb_size) - castout_entry = 1; + do { + entry = castout_entry; + castout_entry++; + if (castout_entry >= naca->slb_size) + castout_entry = 1; + asm volatile("slbmfee %0,%1" : "=r" (esid_data) : "r" (entry)); + } while (esid_data.data.esid == GET_ESID((unsigned long)_get_SP()) && + esid_data.data.v); + get_paca()->xStab_data.next_round_robin = castout_entry; /* slbie not needed as the previous mapping is still valid. */ @@ -346,7 +358,12 @@ void flush_stab(struct task_struct *tsk, struct mm_struct *mm) { if (cpu_has_slb()) { - if (!STAB_PRESSURE && test_thread_flag(TIF_32BIT)) { + /* + * XXX disable 32bit slb invalidate optimisation until we fix + * the issue where a 32bit app execed out of a 64bit app can + * cause segments above 4GB not to be flushed - Anton + */ + if (0 && !STAB_PRESSURE && test_thread_flag(TIF_32BIT)) { union { unsigned long word0; slb_dword0 data; diff -Nru a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c --- a/arch/s390/kernel/s390_ksyms.c Wed Apr 2 22:24:06 2003 +++ b/arch/s390/kernel/s390_ksyms.c Wed Apr 2 22:24:06 2003 @@ -6,10 +6,10 @@ #include #include #include +#include #include #include #include -#include #if CONFIG_IP_MULTICAST #include #endif diff -Nru a/arch/s390x/kernel/s390_ksyms.c b/arch/s390x/kernel/s390_ksyms.c --- a/arch/s390x/kernel/s390_ksyms.c Wed Apr 2 22:24:07 2003 +++ b/arch/s390x/kernel/s390_ksyms.c Wed Apr 2 22:24:07 2003 @@ -8,11 +8,11 @@ #include #include #include +#include #include #include #include #include -#include #if CONFIG_IP_MULTICAST #include #endif diff -Nru a/arch/sparc/Makefile b/arch/sparc/Makefile --- a/arch/sparc/Makefile Wed Apr 2 22:24:04 2003 +++ b/arch/sparc/Makefile Wed Apr 2 22:24:04 2003 @@ -54,13 +54,16 @@ LIBS_Y := $(patsubst %/, %/lib.a, $(libs-y)) export INIT_Y CORE_Y DRIVERS_Y NET_Y LIBS_Y HEAD_Y -makeboot =$(Q)$(MAKE) -f scripts/Makefile.build obj=arch/$(ARCH)/boot $(1) +# Default target +all: image + +boot := arch/sparc/boot image tftpboot.img: vmlinux - $(call makeboot,arch/sparc/boot/$@) + $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ archclean: - $(Q)$(MAKE) -f scripts/Makefile.clean obj=arch/$(ARCH)/boot + $(Q)$(MAKE) $(clean)=$(boot) prepare: include/asm-$(ARCH)/asm_offsets.h @@ -72,3 +75,9 @@ CLEAN_FILES += include/asm-$(ARCH)/asm_offsets.h \ arch/$(ARCH)/kernel/asm-offsets.s + +# Don't use tabs in echo arguments. +define archhelp + echo '* image - kernel image ($(boot)/image)' + echo ' tftpboot.img - image prepared for tftp' +endef diff -Nru a/arch/sparc/boot/Makefile b/arch/sparc/boot/Makefile --- a/arch/sparc/boot/Makefile Wed Apr 2 22:24:07 2003 +++ b/arch/sparc/boot/Makefile Wed Apr 2 22:24:07 2003 @@ -32,7 +32,3 @@ $(obj)/btfix.s: $(obj)/btfixupprep vmlinux FORCE $(call if_changed,btfix) - -archhelp: - @echo '* image - kernel image ($(obj)/image)' - @echo ' tftpboot.img - image prepared for tftp' diff -Nru a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c --- a/arch/sparc/kernel/irq.c Wed Apr 2 22:24:04 2003 +++ b/arch/sparc/kernel/irq.c Wed Apr 2 22:24:04 2003 @@ -45,7 +45,6 @@ #include #include #include -#include #include #include diff -Nru a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c --- a/arch/sparc/kernel/setup.c Wed Apr 2 22:24:04 2003 +++ b/arch/sparc/kernel/setup.c Wed Apr 2 22:24:04 2003 @@ -43,7 +43,6 @@ #include #include #include -#include #include #include diff -Nru a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c --- a/arch/sparc/kernel/smp.c Wed Apr 2 22:24:04 2003 +++ b/arch/sparc/kernel/smp.c Wed Apr 2 22:24:04 2003 @@ -30,7 +30,6 @@ #include #include #include -#include #define __KERNEL_SYSCALLS__ #include diff -Nru a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c --- a/arch/sparc/kernel/sparc_ksyms.c Wed Apr 2 22:24:04 2003 +++ b/arch/sparc/kernel/sparc_ksyms.c Wed Apr 2 22:24:04 2003 @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include diff -Nru a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c --- a/arch/sparc/kernel/sun4d_smp.c Wed Apr 2 22:24:04 2003 +++ b/arch/sparc/kernel/sun4d_smp.c Wed Apr 2 22:24:04 2003 @@ -29,7 +29,6 @@ #include #include #include -#include #include #include diff -Nru a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c --- a/arch/sparc/kernel/sun4m_smp.c Wed Apr 2 22:24:07 2003 +++ b/arch/sparc/kernel/sun4m_smp.c Wed Apr 2 22:24:07 2003 @@ -26,7 +26,6 @@ #include #include #include -#include #define __KERNEL_SYSCALLS__ #include diff -Nru a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig --- a/arch/sparc64/Kconfig Wed Apr 2 22:24:07 2003 +++ b/arch/sparc64/Kconfig Wed Apr 2 22:24:07 2003 @@ -139,8 +139,8 @@ bool "CPU Frequency scaling" help Clock scaling allows you to change the clock speed of CPUs on the - fly. Currently there is only a sparc64 driver for UltraSPARC-III - processors. + fly. Currently there are only sparc64 drivers for UltraSPARC-III + and UltraSPARC-IIe processors. For details, take a look at linux/Documentation/cpufreq. @@ -161,6 +161,16 @@ depends on CPU_FREQ_TABLE help This adds the CPUFreq driver for UltraSPARC-III processors. + + For details, take a look at linux/Documentation/cpufreq. + + If in doubt, say N. + +config US2E_FREQ + tristate "UltraSPARC-IIe CPU Frequency driver" + depends on CPU_FREQ_TABLE + help + This adds the CPUFreq driver for UltraSPARC-IIe processors. For details, take a look at linux/Documentation/cpufreq. diff -Nru a/arch/sparc64/Makefile b/arch/sparc64/Makefile --- a/arch/sparc64/Makefile Wed Apr 2 22:24:07 2003 +++ b/arch/sparc64/Makefile Wed Apr 2 22:24:07 2003 @@ -71,10 +71,13 @@ # FIXME: is drivers- right? drivers-$(CONFIG_OPROFILE) += arch/sparc64/oprofile/ -makeboot = $(Q)$(MAKE) -f scripts/Makefile.build obj=arch/$(ARCH)/boot $(1) +boot := arch/sparc64/boot image tftpboot.img vmlinux.aout: vmlinux - $(call makeboot,arch/sparc64/boot/$@) + $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ + +archclean: + $(Q)$(MAKE) $(clean)=$(boot) define archhelp echo '* vmlinux - Standard sparc64 kernel' diff -Nru a/arch/sparc64/boot/Makefile b/arch/sparc64/boot/Makefile --- a/arch/sparc64/boot/Makefile Wed Apr 2 22:24:04 2003 +++ b/arch/sparc64/boot/Makefile Wed Apr 2 22:24:04 2003 @@ -8,7 +8,7 @@ ELFTOAOUT := elftoaout host-progs := piggyback -targets := tftpboot.img vmlinux.aout +targets := image tftpboot.img vmlinux.aout quiet_cmd_elftoaout = ELT2AOUT $@ cmd_elftoaout = $(ELFTOAOUT) vmlinux -o $@ diff -Nru a/arch/sparc64/defconfig b/arch/sparc64/defconfig --- a/arch/sparc64/defconfig Wed Apr 2 22:24:05 2003 +++ b/arch/sparc64/defconfig Wed Apr 2 22:24:05 2003 @@ -41,6 +41,7 @@ CONFIG_CPU_FREQ=y CONFIG_CPU_FREQ_TABLE=y CONFIG_US3_FREQ=m +CONFIG_US2E_FREQ=m CONFIG_CPU_FREQ_PROC_INTF=y CONFIG_CPU_FREQ_GOV_USERSPACE=m # CONFIG_CPU_FREQ_24_API is not set @@ -361,11 +362,11 @@ # CONFIG_SYN_COOKIES is not set CONFIG_INET_AH=y CONFIG_INET_ESP=y -CONFIG_XFRM_USER=m CONFIG_IPV6=m CONFIG_IPV6_PRIVACY=y CONFIG_INET6_AH=m CONFIG_INET6_ESP=m +CONFIG_XFRM_USER=m # # SCTP Configuration (EXPERIMENTAL) diff -Nru a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile --- a/arch/sparc64/kernel/Makefile Wed Apr 2 22:24:04 2003 +++ b/arch/sparc64/kernel/Makefile Wed Apr 2 22:24:04 2003 @@ -21,6 +21,7 @@ obj-$(CONFIG_BINFMT_AOUT32) += binfmt_aout32.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_US3_FREQ) += us3_cpufreq.o +obj-$(CONFIG_US2E_FREQ) += us2e_cpufreq.o ifdef CONFIG_SUNOS_EMUL obj-y += sys_sunos32.o sunos_ioctl32.o diff -Nru a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c --- a/arch/sparc64/kernel/binfmt_elf32.c Wed Apr 2 22:24:07 2003 +++ b/arch/sparc64/kernel/binfmt_elf32.c Wed Apr 2 22:24:07 2003 @@ -152,7 +152,6 @@ #ifdef CONFIG_BINFMT_ELF32_MODULE #define CONFIG_BINFMT_ELF_MODULE CONFIG_BINFMT_ELF32_MODULE #endif -#define ELF_FLAGS_INIT set_thread_flag(TIF_32BIT) MODULE_DESCRIPTION("Binary format loader for compatibility with 32bit SparcLinux binaries on the Ultra"); MODULE_AUTHOR("Eric Youngdale, David S. Miller, Jakub Jelinek"); diff -Nru a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c --- a/arch/sparc64/kernel/devices.c Wed Apr 2 22:24:04 2003 +++ b/arch/sparc64/kernel/devices.c Wed Apr 2 22:24:04 2003 @@ -17,6 +17,7 @@ #include #include #include +#include /* Used to synchronize acceses to NatSemi SUPER I/O chip configure * operations in asm/ns87303.h @@ -88,7 +89,6 @@ #ifndef CONFIG_SMP { - extern unsigned long up_clock_tick; up_clock_tick = prom_getintdefault(prom_node_cpu, "clock-frequency", 0); diff -Nru a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c --- a/arch/sparc64/kernel/irq.c Wed Apr 2 22:24:07 2003 +++ b/arch/sparc64/kernel/irq.c Wed Apr 2 22:24:07 2003 @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -356,7 +355,7 @@ } if (action == NULL) action = (struct irqaction *)kmalloc(sizeof(struct irqaction), - GFP_KERNEL); + GFP_ATOMIC); if (!action) { spin_unlock_irqrestore(&irq_action_lock, flags); @@ -376,7 +375,7 @@ goto free_and_ebusy; } if ((bucket->flags & IBF_MULTI) == 0) { - vector = kmalloc(sizeof(void *) * 4, GFP_KERNEL); + vector = kmalloc(sizeof(void *) * 4, GFP_ATOMIC); if (vector == NULL) goto free_and_enomem; @@ -900,7 +899,7 @@ } if (action == NULL) action = (struct irqaction *)kmalloc(sizeof(struct irqaction), - GFP_KERNEL); + GFP_ATOMIC); if (!action) { spin_unlock_irqrestore(&irq_action_lock, flags); return -ENOMEM; diff -Nru a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c --- a/arch/sparc64/kernel/pci.c Wed Apr 2 22:24:04 2003 +++ b/arch/sparc64/kernel/pci.c Wed Apr 2 22:24:04 2003 @@ -470,6 +470,54 @@ return err; } +/* Sort resources by alignment */ +void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) +{ + int i; + + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + struct resource *r; + struct resource_list *list, *tmp; + unsigned long r_align; + + r = &dev->resource[i]; + r_align = r->end - r->start; + + if (!(r->flags) || r->parent) + continue; + if (!r_align) { + printk(KERN_WARNING "PCI: Ignore bogus resource %d " + "[%lx:%lx] of %s\n", + i, r->start, r->end, dev->dev.name); + continue; + } + r_align = (i < PCI_BRIDGE_RESOURCES) ? r_align + 1 : r->start; + for (list = head; ; list = list->next) { + unsigned long align = 0; + struct resource_list *ln = list->next; + int idx; + + if (ln) { + idx = ln->res - &ln->dev->resource[0]; + align = (idx < PCI_BRIDGE_RESOURCES) ? + ln->res->end - ln->res->start + 1 : + ln->res->start; + } + if (r_align > align) { + tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); + if (!tmp) + panic("pdev_sort_resources(): " + "kmalloc() failed!\n"); + tmp->next = ln; + tmp->res = r; + tmp->dev = dev; + list->next = tmp; + break; + } + } + } +} + void pcibios_update_irq(struct pci_dev *pdev, int irq) { } @@ -482,6 +530,44 @@ int pcibios_enable_device(struct pci_dev *pdev, int mask) { return 0; +} + +void pcibios_resource_to_bus(struct pci_dev *pdev, struct pci_bus_region *region, + struct resource *res) +{ + struct pci_pbm_info *pbm = pci_bus2pbm[pdev->bus->number]; + struct resource zero_res, *root; + + zero_res.start = 0; + zero_res.end = 0; + zero_res.flags = res->flags; + + if (res->flags & IORESOURCE_IO) + root = &pbm->io_space; + else + root = &pbm->mem_space; + + pbm->parent->resource_adjust(pdev, &zero_res, root); + + region->start = res->start - zero_res.start; + region->end = res->end - zero_res.start; +} + +void pcibios_bus_to_resource(struct pci_dev *pdev, struct resource *res, + struct pci_bus_region *region) +{ + struct pci_pbm_info *pbm = pci_bus2pbm[pdev->bus->number]; + struct resource *root; + + res->start = region->start; + res->end = region->end; + + if (res->flags & IORESOURCE_IO) + root = &pbm->io_space; + else + root = &pbm->mem_space; + + pbm->parent->resource_adjust(pdev, res, root); } char * __init pcibios_setup(char *str) diff -Nru a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c --- a/arch/sparc64/kernel/pci_iommu.c Wed Apr 2 22:24:04 2003 +++ b/arch/sparc64/kernel/pci_iommu.c Wed Apr 2 22:24:04 2003 @@ -784,6 +784,26 @@ spin_unlock_irqrestore(&iommu->lock, flags); } +static void ali_sound_dma_hack(struct pci_dev *pdev, int set_bit) +{ + struct pci_dev *ali_isa_bridge; + u8 val; + + /* ALI sound chips generate 31-bits of DMA, a special register + * determines what bit 31 is emitted as. + */ + ali_isa_bridge = pci_find_device(PCI_VENDOR_ID_AL, + PCI_DEVICE_ID_AL_M1533, + NULL); + + pci_read_config_byte(ali_isa_bridge, 0x7e, &val); + if (set_bit) + val |= 0x01; + else + val &= ~0x01; + pci_write_config_byte(ali_isa_bridge, 0x7e, val); +} + int pci_dma_supported(struct pci_dev *pdev, u64 device_mask) { struct pcidev_cookie *pcp = pdev->sysdata; @@ -795,6 +815,14 @@ struct pci_iommu *iommu = pcp->pbm->iommu; dma_addr_mask = iommu->dma_addr_mask; + + if (pdev->vendor == PCI_VENDOR_ID_AL && + pdev->device == PCI_DEVICE_ID_AL_M5451 && + device_mask == 0x7fffffff) { + ali_sound_dma_hack(pdev, + (dma_addr_mask & 0x80000000) != 0); + return 1; + } } return (device_mask & dma_addr_mask) == dma_addr_mask; diff -Nru a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S --- a/arch/sparc64/kernel/rtrap.S Wed Apr 2 22:24:05 2003 +++ b/arch/sparc64/kernel/rtrap.S Wed Apr 2 22:24:05 2003 @@ -185,6 +185,7 @@ * sched+signal checks with IRQs disabled. */ to_user: wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate + wrpr 0, %pil __handle_preemption_continue: ldx [%g6 + TI_FLAGS], %l0 sethi %hi(_TIF_USER_WORK_MASK), %o0 @@ -271,6 +272,7 @@ brnz %l5, kern_fpucheck sethi %hi(PREEMPT_ACTIVE), %l6 stw %l6, [%g6 + TI_PRE_COUNT] + wrpr 0, %pil call schedule nop ba,pt %xcc, rtrap diff -Nru a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c --- a/arch/sparc64/kernel/setup.c Wed Apr 2 22:24:05 2003 +++ b/arch/sparc64/kernel/setup.c Wed Apr 2 22:24:05 2003 @@ -44,6 +44,7 @@ #include #include #include +#include #ifdef CONFIG_IP_PNP #include diff -Nru a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c --- a/arch/sparc64/kernel/smp.c Wed Apr 2 22:24:04 2003 +++ b/arch/sparc64/kernel/smp.c Wed Apr 2 22:24:04 2003 @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include diff -Nru a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c --- a/arch/sparc64/kernel/sparc64_ksyms.c Wed Apr 2 22:24:07 2003 +++ b/arch/sparc64/kernel/sparc64_ksyms.c Wed Apr 2 22:24:07 2003 @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -55,6 +54,7 @@ #endif #include #include +#include struct poll { int fd; @@ -159,11 +159,7 @@ EXPORT_SYMBOL(smp_call_function); #endif /* CONFIG_SMP */ -/* Uniprocessor clock frequency */ -#ifndef CONFIG_SMP -extern unsigned long up_clock_tick; -EXPORT_SYMBOL(up_clock_tick); -#endif +EXPORT_SYMBOL(sparc64_get_clock_tick); /* semaphores */ EXPORT_SYMBOL(down); diff -Nru a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c --- a/arch/sparc64/kernel/time.c Wed Apr 2 22:24:05 2003 +++ b/arch/sparc64/kernel/time.c Wed Apr 2 22:24:05 2003 @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include @@ -988,6 +990,73 @@ return clock; } +struct freq_table { + unsigned long udelay_val_ref; + unsigned long clock_tick_ref; + unsigned int ref_freq; +}; +static DEFINE_PER_CPU(struct freq_table, sparc64_freq_table) = { 0, 0, 0 }; + +unsigned long sparc64_get_clock_tick(unsigned int cpu) +{ + struct freq_table *ft = &per_cpu(sparc64_freq_table, cpu); + + if (ft->clock_tick_ref) + return ft->clock_tick_ref; +#ifdef CONFIG_SMP + return cpu_data[cpu].clock_tick; +#else + return up_clock_tick; +#endif +} + +#ifdef CONFIG_CPU_FREQ + +static int sparc64_cpufreq_notifier(struct notifier_block *nb, unsigned long val, + void *data) +{ + struct cpufreq_freqs *freq = data; + unsigned int cpu = freq->cpu; + struct freq_table *ft = &per_cpu(sparc64_freq_table, cpu); + +#ifdef CONFIG_SMP + if (!ft->ref_freq) { + ft->ref_freq = freq->old; + ft->udelay_val_ref = cpu_data[cpu].udelay_val; + ft->clock_tick_ref = cpu_data[cpu].clock_tick; + } + if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || + (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) { + cpu_data[cpu].udelay_val = + cpufreq_scale(ft->udelay_val_ref, + ft->ref_freq, + freq->new); + cpu_data[cpu].clock_tick = + cpufreq_scale(ft->clock_tick_ref, + ft->ref_freq, + freq->new); + } +#else + /* In the non-SMP case, kernel/cpufreq.c takes care of adjusting + * loops_per_jiffy. + */ + if (!ft->ref_freq) { + ft->ref_freq = freq->old; + ft->clock_tick_ref = up_clock_tick; + } + if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || + (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) + up_clock_tick = cpufreq_scale(ft->clock_tick_ref, ft->ref_freq, freq->new); +#endif + + return 0; +} + +static struct notifier_block sparc64_cpufreq_notifier_block = { + .notifier_call = sparc64_cpufreq_notifier +}; +#endif + /* The quotient formula is taken from the IA64 port. */ void __init time_init(void) { @@ -996,6 +1065,11 @@ timer_ticks_per_usec_quotient = (((1000000UL << 30) + (clock / 2)) / clock); + +#ifdef CONFIG_CPU_FREQ + cpufreq_register_notifier(&sparc64_cpufreq_notifier_block, + CPUFREQ_TRANSITION_NOTIFIER); +#endif } static __inline__ unsigned long do_gettimeoffset(void) diff -Nru a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c --- a/arch/sparc64/kernel/traps.c Wed Apr 2 22:24:07 2003 +++ b/arch/sparc64/kernel/traps.c Wed Apr 2 22:24:07 2003 @@ -1575,6 +1575,9 @@ struct reg_window *rw; int count = 0; + if (tp == current_thread_info()) + flushw_all(); + fp = ksp + STACK_BIAS; thread_base = (unsigned long) tp; do { @@ -1595,6 +1598,15 @@ if (tsk) show_trace_raw(tsk->thread_info, tsk->thread_info->ksp); +} + +void dump_stack(void) +{ + unsigned long ksp; + + __asm__ __volatile__("mov %%fp, %0" + : "=r" (ksp)); + show_trace_raw(current_thread_info(), ksp); } void die_if_kernel(char *str, struct pt_regs *regs) diff -Nru a/arch/sparc64/kernel/us2e_cpufreq.c b/arch/sparc64/kernel/us2e_cpufreq.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/sparc64/kernel/us2e_cpufreq.c Wed Apr 2 22:24:08 2003 @@ -0,0 +1,398 @@ +/* us2e_cpufreq.c: UltraSPARC-IIe cpu frequency support + * + * Copyright (C) 2003 David S. Miller (davem@redhat.com) + * + * Many thanks to Dominik Brodowski for fixing up the cpufreq + * infrastructure in order to make this driver easier to implement. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static struct cpufreq_driver *cpufreq_us2e_driver; + +struct us2e_freq_percpu_info { + struct cpufreq_frequency_table table[6]; +}; + +/* Indexed by cpu number. */ +static struct us2e_freq_percpu_info *us2e_freq_table; + +#define HBIRD_MEM_CNTL0_ADDR 0x1fe0000f010UL +#define HBIRD_ESTAR_MODE_ADDR 0x1fe0000f080UL + +/* UltraSPARC-IIe has five dividers: 1, 2, 4, 6, and 8. These are controlled + * in the ESTAR mode control register. + */ +#define ESTAR_MODE_DIV_1 0x0000000000000000UL +#define ESTAR_MODE_DIV_2 0x0000000000000001UL +#define ESTAR_MODE_DIV_4 0x0000000000000003UL +#define ESTAR_MODE_DIV_6 0x0000000000000002UL +#define ESTAR_MODE_DIV_8 0x0000000000000004UL +#define ESTAR_MODE_DIV_MASK 0x0000000000000007UL + +#define MCTRL0_SREFRESH_ENAB 0x0000000000010000UL +#define MCTRL0_REFR_COUNT_MASK 0x0000000000007f00UL +#define MCTRL0_REFR_COUNT_SHIFT 8 +#define MCTRL0_REFR_INTERVAL 7800 +#define MCTRL0_REFR_CLKS_P_CNT 64 + +static unsigned long read_hbreg(unsigned long addr) +{ + unsigned long ret; + + __asm__ __volatile__("ldxa [%1] %2, %0" + : "=&r" (ret) + : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E)); + return ret; +} + +static void write_hbreg(unsigned long addr, unsigned long val) +{ + __asm__ __volatile__("stxa %0, [%1] %2\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E) + : "memory"); + if (addr == HBIRD_ESTAR_MODE_ADDR) { + /* Need to wait 16 clock cycles for the PLL to lock. */ + udelay(1); + } +} + +static void self_refresh_ctl(int enable) +{ + unsigned long mctrl = read_hbreg(HBIRD_MEM_CNTL0_ADDR); + + if (enable) + mctrl |= MCTRL0_SREFRESH_ENAB; + else + mctrl &= ~MCTRL0_SREFRESH_ENAB; + write_hbreg(HBIRD_MEM_CNTL0_ADDR, mctrl); + (void) read_hbreg(HBIRD_MEM_CNTL0_ADDR); +} + +static void frob_mem_refresh(int cpu_slowing_down, + unsigned long clock_tick, + unsigned long old_divisor, unsigned long divisor) +{ + unsigned long old_refr_count, refr_count, mctrl; + + + refr_count = (clock_tick * MCTRL0_REFR_INTERVAL); + refr_count /= (MCTRL0_REFR_CLKS_P_CNT * divisor * 1000000000UL); + + mctrl = read_hbreg(HBIRD_MEM_CNTL0_ADDR); + old_refr_count = (mctrl & MCTRL0_REFR_COUNT_MASK) + >> MCTRL0_REFR_COUNT_SHIFT; + + mctrl &= ~MCTRL0_REFR_COUNT_MASK; + mctrl |= refr_count << MCTRL0_REFR_COUNT_SHIFT; + write_hbreg(HBIRD_MEM_CNTL0_ADDR, mctrl); + mctrl = read_hbreg(HBIRD_MEM_CNTL0_ADDR); + + if (cpu_slowing_down && !(mctrl & MCTRL0_SREFRESH_ENAB)) { + unsigned long usecs; + + /* We have to wait for both refresh counts (old + * and new) to go to zero. + */ + usecs = (MCTRL0_REFR_CLKS_P_CNT * + (refr_count + old_refr_count) * + 1000000UL * + old_divisor) / clock_tick; + udelay(usecs + 1UL); + } +} + +static void us2e_transition(unsigned long estar, unsigned long new_bits, + unsigned long clock_tick, + unsigned long old_divisor, unsigned long divisor) +{ + unsigned long flags; + + local_irq_save(flags); + + estar &= ~ESTAR_MODE_DIV_MASK; + + /* This is based upon the state transition diagram in the IIe manual. */ + if (old_divisor == 2 && divisor == 1) { + self_refresh_ctl(0); + write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits); + frob_mem_refresh(0, clock_tick, old_divisor, divisor); + } else if (old_divisor == 1 && divisor == 2) { + frob_mem_refresh(1, clock_tick, old_divisor, divisor); + write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits); + self_refresh_ctl(1); + } else if (old_divisor == 1 && divisor > 2) { + us2e_transition(estar, ESTAR_MODE_DIV_2, clock_tick, + 1, 2); + us2e_transition(estar, new_bits, clock_tick, + 2, divisor); + } else if (old_divisor > 2 && divisor == 1) { + us2e_transition(estar, ESTAR_MODE_DIV_2, clock_tick, + old_divisor, 2); + us2e_transition(estar, new_bits, clock_tick, + 2, divisor); + } else if (old_divisor < divisor) { + frob_mem_refresh(0, clock_tick, old_divisor, divisor); + write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits); + } else if (old_divisor > divisor) { + write_hbreg(HBIRD_ESTAR_MODE_ADDR, estar | new_bits); + frob_mem_refresh(1, clock_tick, old_divisor, divisor); + } else { + BUG(); + } + + local_irq_restore(flags); +} + +static unsigned long index_to_estar_mode(unsigned int index) +{ + switch (index) { + case 0: + return ESTAR_MODE_DIV_1; + + case 1: + return ESTAR_MODE_DIV_2; + + case 2: + return ESTAR_MODE_DIV_4; + + case 3: + return ESTAR_MODE_DIV_6; + + case 4: + return ESTAR_MODE_DIV_8; + + default: + BUG(); + }; +} + +static unsigned long index_to_divisor(unsigned int index) +{ + switch (index) { + case 0: + return 1; + + case 1: + return 2; + + case 2: + return 4; + + case 3: + return 6; + + case 4: + return 8; + + default: + BUG(); + }; +} + +static unsigned long estar_to_divisor(unsigned long estar) +{ + unsigned long ret; + + switch (estar & ESTAR_MODE_DIV_MASK) { + case ESTAR_MODE_DIV_1: + ret = 1; + break; + case ESTAR_MODE_DIV_2: + ret = 2; + break; + case ESTAR_MODE_DIV_4: + ret = 4; + break; + case ESTAR_MODE_DIV_6: + ret = 6; + break; + case ESTAR_MODE_DIV_8: + ret = 8; + break; + default: + BUG(); + }; + + return ret; +} + +static void us2e_set_cpu_divider_index(unsigned int cpu, unsigned int index) +{ + unsigned long new_bits, new_freq, cpus_allowed; + unsigned long clock_tick, divisor, old_divisor, estar; + struct cpufreq_freqs freqs; + + if (!cpu_online(cpu)) + return; + + cpus_allowed = current->cpus_allowed; + set_cpus_allowed(current, (1UL << cpu)); + + new_freq = clock_tick = sparc64_get_clock_tick(cpu); + new_bits = index_to_estar_mode(index); + divisor = index_to_divisor(index); + new_freq /= divisor; + + estar = read_hbreg(HBIRD_ESTAR_MODE_ADDR); + + old_divisor = estar_to_divisor(estar); + + freqs.old = clock_tick / old_divisor; + freqs.new = new_freq; + freqs.cpu = cpu; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + us2e_transition(estar, new_bits, clock_tick, old_divisor, divisor); + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + set_cpus_allowed(current, cpus_allowed); +} + +static int us2e_freq_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int new_index = 0; + + if (cpufreq_frequency_table_target(policy, + &us2e_freq_table[policy->cpu].table[0], + target_freq, + relation, + &new_index)) + return -EINVAL; + + us2e_set_cpu_divider_index(policy->cpu, new_index); + + return 0; +} + +static int us2e_freq_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, + &us2e_freq_table[policy->cpu].table[0]); +} + +static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy) +{ + unsigned int cpu = policy->cpu; + unsigned long clock_tick = sparc64_get_clock_tick(cpu); + struct cpufreq_frequency_table *table = + &us2e_freq_table[cpu].table[0]; + + table[0].index = 0; + table[0].frequency = clock_tick / 1; + table[1].index = 1; + table[1].frequency = clock_tick / 2; + table[2].index = 2; + table[2].frequency = clock_tick / 4; + table[2].index = 3; + table[2].frequency = clock_tick / 6; + table[2].index = 4; + table[2].frequency = clock_tick / 8; + table[2].index = 5; + table[3].frequency = CPUFREQ_TABLE_END; + + policy->policy = CPUFREQ_POLICY_PERFORMANCE; + policy->cpuinfo.transition_latency = 0; + policy->cur = clock_tick; + + return cpufreq_frequency_table_cpuinfo(policy, table); +} + +static int __exit us2e_freq_cpu_exit(struct cpufreq_policy *policy) +{ + if (cpufreq_us2e_driver) + us2e_set_cpu_divider_index(policy->cpu, 0); + + return 0; +} + +static int __init us2e_freq_init(void) +{ + unsigned long manuf, impl, ver; + int ret; + + __asm__("rdpr %%ver, %0" : "=r" (ver)); + manuf = ((ver >> 48) & 0xffff); + impl = ((ver >> 32) & 0xffff); + + if (manuf == 0x17 && impl == 0x13) { + struct cpufreq_driver *driver; + + ret = -ENOMEM; + driver = kmalloc(sizeof(struct cpufreq_driver), GFP_KERNEL); + if (!driver) + goto err_out; + memset(driver, 0, sizeof(*driver)); + + us2e_freq_table = kmalloc( + (NR_CPUS * sizeof(struct us2e_freq_percpu_info)), + GFP_KERNEL); + if (!us2e_freq_table) + goto err_out; + + memset(us2e_freq_table, 0, + (NR_CPUS * sizeof(struct us2e_freq_percpu_info))); + + driver->verify = us2e_freq_verify; + driver->target = us2e_freq_target; + driver->init = us2e_freq_cpu_init; + driver->exit = us2e_freq_cpu_exit; + driver->owner = THIS_MODULE, + strcpy(driver->name, "UltraSPARC-IIe"); + + cpufreq_us2e_driver = driver; + ret = cpufreq_register_driver(driver); + if (ret) + goto err_out; + + return 0; + +err_out: + if (driver) { + kfree(driver); + cpufreq_us2e_driver = NULL; + } + if (us2e_freq_table) { + kfree(us2e_freq_table); + us2e_freq_table = NULL; + } + return ret; + } + + return -ENODEV; +} + +static void __exit us2e_freq_exit(void) +{ + if (cpufreq_us2e_driver) { + cpufreq_unregister_driver(cpufreq_us2e_driver); + + kfree(cpufreq_us2e_driver); + cpufreq_us2e_driver = NULL; + kfree(us2e_freq_table); + us2e_freq_table = NULL; + } +} + +MODULE_AUTHOR("David S. Miller "); +MODULE_DESCRIPTION("cpufreq driver for UltraSPARC-IIe"); +MODULE_LICENSE("GPL"); + +module_init(us2e_freq_init); +module_exit(us2e_freq_exit); diff -Nru a/arch/sparc64/kernel/us3_cpufreq.c b/arch/sparc64/kernel/us3_cpufreq.c --- a/arch/sparc64/kernel/us3_cpufreq.c Wed Apr 2 22:24:04 2003 +++ b/arch/sparc64/kernel/us3_cpufreq.c Wed Apr 2 22:24:04 2003 @@ -16,14 +16,12 @@ #include #include +#include static struct cpufreq_driver *cpufreq_us3_driver; struct us3_freq_percpu_info { struct cpufreq_frequency_table table[4]; - unsigned long udelay_val_ref; - unsigned long clock_tick_ref; - unsigned int ref_freq; }; /* Indexed by cpu number. */ @@ -56,71 +54,9 @@ : "memory"); } -#ifndef CONFIG_SMP -extern unsigned long up_clock_tick; -unsigned long clock_tick_ref; -unsigned int ref_freq; -#endif - -static __inline__ unsigned long get_clock_tick(unsigned int cpu) -{ -#ifdef CONFIG_SMP - if (us3_freq_table[cpu].clock_tick_ref) - return us3_freq_table[cpu].clock_tick_ref; - return cpu_data[cpu].clock_tick; -#else - if (clock_tick_ref) - return clock_tick_ref; - return up_clock_tick; -#endif -} - -static int us3_cpufreq_notifier(struct notifier_block *nb, unsigned long val, - void *data) -{ - struct cpufreq_freqs *freq = data; -#ifdef CONFIG_SMP - unsigned int cpu = freq->cpu; - - if (!us3_freq_table[cpu].ref_freq) { - us3_freq_table[cpu].ref_freq = freq->old; - us3_freq_table[cpu].udelay_val_ref = cpu_data[cpu].udelay_val; - us3_freq_table[cpu].clock_tick_ref = cpu_data[cpu].clock_tick; - } - if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || - (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) { - cpu_data[cpu].udelay_val = - cpufreq_scale(us3_freq_table[cpu].udelay_val_ref, - us3_freq_table[cpu].ref_freq, - freq->new); - cpu_data[cpu].clock_tick = - cpufreq_scale(us3_freq_table[cpu].clock_tick_ref, - us3_freq_table[cpu].ref_freq, - freq->new); - } -#else - /* In the non-SMP case, kernel/cpufreq.c takes care of adjusting - * loops_per_jiffy. - */ - if (!ref_freq) { - ref_freq = freq->old; - clock_tick_ref = up_clock_tick; - } - if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || - (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) - up_clock_tick = cpufreq_scale(clock_tick_ref, ref_freq, freq->new); -#endif - - return 0; -} - -static struct notifier_block us3_cpufreq_notifier_block = { - .notifier_call = us3_cpufreq_notifier -}; - static unsigned long get_current_freq(unsigned int cpu, unsigned long safari_cfg) { - unsigned long clock_tick = get_clock_tick(cpu); + unsigned long clock_tick = sparc64_get_clock_tick(cpu); unsigned long ret; switch (safari_cfg & SAFARI_CFG_DIV_MASK) { @@ -151,7 +87,7 @@ cpus_allowed = current->cpus_allowed; set_cpus_allowed(current, (1UL << cpu)); - new_freq = get_clock_tick(cpu); + new_freq = sparc64_get_clock_tick(cpu); switch (index) { case 0: new_bits = SAFARI_CFG_DIV_1; @@ -186,17 +122,17 @@ set_cpus_allowed(current, cpus_allowed); } -static int us3freq_target(struct cpufreq_policy *policy, +static int us3_freq_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) { unsigned int new_index = 0; if (cpufreq_frequency_table_target(policy, - &us3_freq_table[policy->cpu].table[0], - target_freq, - relation, - &new_index)) + &us3_freq_table[policy->cpu].table[0], + target_freq, + relation, + &new_index)) return -EINVAL; us3_set_cpu_divider_index(policy->cpu, new_index); @@ -204,16 +140,16 @@ return 0; } -static int us3freq_verify(struct cpufreq_policy *policy) +static int us3_freq_verify(struct cpufreq_policy *policy) { return cpufreq_frequency_table_verify(policy, &us3_freq_table[policy->cpu].table[0]); } -static int __init us3freq_cpu_init(struct cpufreq_policy *policy) +static int __init us3_freq_cpu_init(struct cpufreq_policy *policy) { unsigned int cpu = policy->cpu; - unsigned long clock_tick = get_clock_tick(cpu); + unsigned long clock_tick = sparc64_get_clock_tick(cpu); struct cpufreq_frequency_table *table = &us3_freq_table[cpu].table[0]; @@ -233,7 +169,7 @@ return cpufreq_frequency_table_cpuinfo(policy, table); } -static int __exit us3freq_cpu_exit(struct cpufreq_policy *policy) +static int __exit us3_freq_cpu_exit(struct cpufreq_policy *policy) { if (cpufreq_us3_driver) us3_set_cpu_divider_index(policy->cpu, 0); @@ -241,7 +177,7 @@ return 0; } -static int __init us3freq_init(void) +static int __init us3_freq_init(void) { unsigned long manuf, impl, ver; int ret; @@ -254,9 +190,6 @@ (impl == CHEETAH_IMPL || impl == CHEETAH_PLUS_IMPL)) { struct cpufreq_driver *driver; - cpufreq_register_notifier(&us3_cpufreq_notifier_block, - CPUFREQ_TRANSITION_NOTIFIER); - ret = -ENOMEM; driver = kmalloc(sizeof(struct cpufreq_driver), GFP_KERNEL); if (!driver) @@ -272,10 +205,10 @@ memset(us3_freq_table, 0, (NR_CPUS * sizeof(struct us3_freq_percpu_info))); - driver->verify = us3freq_verify; - driver->target = us3freq_target; - driver->init = us3freq_cpu_init; - driver->exit = us3freq_cpu_exit; + driver->verify = us3_freq_verify; + driver->target = us3_freq_target; + driver->init = us3_freq_cpu_init; + driver->exit = us3_freq_cpu_exit; driver->owner = THIS_MODULE, strcpy(driver->name, "UltraSPARC-III"); @@ -295,20 +228,16 @@ kfree(us3_freq_table); us3_freq_table = NULL; } - cpufreq_unregister_notifier(&us3_cpufreq_notifier_block, - CPUFREQ_TRANSITION_NOTIFIER); return ret; } return -ENODEV; } -static void __exit us3freq_exit(void) +static void __exit us3_freq_exit(void) { if (cpufreq_us3_driver) { cpufreq_unregister_driver(cpufreq_us3_driver); - cpufreq_unregister_notifier(&us3_cpufreq_notifier_block, - CPUFREQ_TRANSITION_NOTIFIER); kfree(cpufreq_us3_driver); cpufreq_us3_driver = NULL; @@ -321,5 +250,5 @@ MODULE_DESCRIPTION("cpufreq driver for UltraSPARC-III"); MODULE_LICENSE("GPL"); -module_init(us3freq_init); -module_exit(us3freq_exit); +module_init(us3_freq_init); +module_exit(us3_freq_exit); diff -Nru a/arch/sparc64/lib/Makefile b/arch/sparc64/lib/Makefile --- a/arch/sparc64/lib/Makefile Wed Apr 2 22:24:04 2003 +++ b/arch/sparc64/lib/Makefile Wed Apr 2 22:24:04 2003 @@ -11,4 +11,4 @@ VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o \ VIScsumcopyusr.o VISsave.o atomic.o rwlock.o bitops.o \ dec_and_lock.o U3memcpy.o U3copy_from_user.o U3copy_to_user.o \ - U3copy_in_user.o mcount.o ipcsum.o + U3copy_in_user.o mcount.o ipcsum.o rwsem.o diff -Nru a/arch/sparc64/lib/rwsem.c b/arch/sparc64/lib/rwsem.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/sparc64/lib/rwsem.c Wed Apr 2 22:24:08 2003 @@ -0,0 +1,238 @@ +/* rwsem.c: Don't inline expand these suckers all over the place. + * + * Written by David S. Miller (davem@redhat.com), 2001. + * Derived from asm-i386/rwsem.h + */ + +#include +#include +#include + +extern struct rw_semaphore *FASTCALL(rwsem_down_read_failed(struct rw_semaphore *sem)); +extern struct rw_semaphore *FASTCALL(rwsem_down_write_failed(struct rw_semaphore *sem)); +extern struct rw_semaphore *FASTCALL(rwsem_wake(struct rw_semaphore *)); +extern struct rw_semaphore *FASTCALL(rwsem_downgrade_wake(struct rw_semaphore *)); + +void __down_read(struct rw_semaphore *sem) +{ + __asm__ __volatile__( + "! beginning __down_read\n" + "1:\tlduw [%0], %%g5\n\t" + "add %%g5, 1, %%g7\n\t" + "cas [%0], %%g5, %%g7\n\t" + "cmp %%g5, %%g7\n\t" + "bne,pn %%icc, 1b\n\t" + " add %%g7, 1, %%g7\n\t" + "cmp %%g7, 0\n\t" + "bl,pn %%icc, 3f\n\t" + " membar #StoreLoad | #StoreStore\n" + "2:\n\t" + ".subsection 2\n" + "3:\tmov %0, %%g5\n\t" + "save %%sp, -160, %%sp\n\t" + "mov %%g1, %%l1\n\t" + "mov %%g2, %%l2\n\t" + "mov %%g3, %%l3\n\t" + "call %1\n\t" + " mov %%g5, %%o0\n\t" + "mov %%l1, %%g1\n\t" + "mov %%l2, %%g2\n\t" + "ba,pt %%xcc, 2b\n\t" + " restore %%l3, %%g0, %%g3\n\t" + ".previous\n\t" + "! ending __down_read" + : : "r" (sem), "i" (rwsem_down_read_failed) + : "g5", "g7", "memory", "cc"); +} +EXPORT_SYMBOL(__down_read); + +int __down_read_trylock(struct rw_semaphore *sem) +{ + int result; + + __asm__ __volatile__( + "! beginning __down_read_trylock\n" + "1:\tlduw [%1], %%g5\n\t" + "add %%g5, 1, %%g7\n\t" + "cmp %%g7, 0\n\t" + "bl,pn %%icc, 2f\n\t" + " mov 0, %0\n\t" + "cas [%1], %%g5, %%g7\n\t" + "cmp %%g5, %%g7\n\t" + "bne,pn %%icc, 1b\n\t" + " mov 1, %0\n\t" + "membar #StoreLoad | #StoreStore\n" + "2:\n\t" + "! ending __down_read_trylock" + : "=&r" (result) + : "r" (sem) + : "g5", "g7", "memory", "cc"); + + return result; +} +EXPORT_SYMBOL(__down_read_trylock); + +void __down_write(struct rw_semaphore *sem) +{ + __asm__ __volatile__( + "! beginning __down_write\n\t" + "sethi %%hi(%2), %%g1\n\t" + "or %%g1, %%lo(%2), %%g1\n" + "1:\tlduw [%0], %%g5\n\t" + "add %%g5, %%g1, %%g7\n\t" + "cas [%0], %%g5, %%g7\n\t" + "cmp %%g5, %%g7\n\t" + "bne,pn %%icc, 1b\n\t" + " cmp %%g7, 0\n\t" + "bne,pn %%icc, 3f\n\t" + " membar #StoreLoad | #StoreStore\n" + "2:\n\t" + ".subsection 2\n" + "3:\tmov %0, %%g5\n\t" + "save %%sp, -160, %%sp\n\t" + "mov %%g2, %%l2\n\t" + "mov %%g3, %%l3\n\t" + "call %1\n\t" + " mov %%g5, %%o0\n\t" + "mov %%l2, %%g2\n\t" + "ba,pt %%xcc, 2b\n\t" + " restore %%l3, %%g0, %%g3\n\t" + ".previous\n\t" + "! ending __down_write" + : : "r" (sem), "i" (rwsem_down_write_failed), + "i" (RWSEM_ACTIVE_WRITE_BIAS) + : "g1", "g5", "g7", "memory", "cc"); +} +EXPORT_SYMBOL(__down_write); + +int __down_write_trylock(struct rw_semaphore *sem) +{ + int result; + + __asm__ __volatile__( + "! beginning __down_write_trylock\n\t" + "sethi %%hi(%2), %%g1\n\t" + "or %%g1, %%lo(%2), %%g1\n" + "1:\tlduw [%1], %%g5\n\t" + "cmp %%g5, 0\n\t" + "bne,pn %%icc, 2f\n\t" + " mov 0, %0\n\t" + "add %%g5, %%g1, %%g7\n\t" + "cas [%1], %%g5, %%g7\n\t" + "cmp %%g5, %%g7\n\t" + "bne,pn %%icc, 1b\n\t" + " mov 1, %0\n\t" + "membar #StoreLoad | #StoreStore\n" + "2:\n\t" + "! ending __down_write_trylock" + : "=&r" (result) + : "r" (sem), "i" (RWSEM_ACTIVE_WRITE_BIAS) + : "g1", "g5", "g7", "memory", "cc"); + + return result; +} +EXPORT_SYMBOL(__down_write_trylock); + +void __up_read(struct rw_semaphore *sem) +{ + __asm__ __volatile__( + "! beginning __up_read\n\t" + "1:\tlduw [%0], %%g5\n\t" + "sub %%g5, 1, %%g7\n\t" + "cas [%0], %%g5, %%g7\n\t" + "cmp %%g5, %%g7\n\t" + "bne,pn %%icc, 1b\n\t" + " cmp %%g7, 0\n\t" + "bl,pn %%icc, 3f\n\t" + " membar #StoreLoad | #StoreStore\n" + "2:\n\t" + ".subsection 2\n" + "3:\tsethi %%hi(%2), %%g1\n\t" + "sub %%g7, 1, %%g7\n\t" + "or %%g1, %%lo(%2), %%g1\n\t" + "andcc %%g7, %%g1, %%g0\n\t" + "bne,pn %%icc, 2b\n\t" + " mov %0, %%g5\n\t" + "save %%sp, -160, %%sp\n\t" + "mov %%g2, %%l2\n\t" + "mov %%g3, %%l3\n\t" + "call %1\n\t" + " mov %%g5, %%o0\n\t" + "mov %%l2, %%g2\n\t" + "ba,pt %%xcc, 2b\n\t" + " restore %%l3, %%g0, %%g3\n\t" + ".previous\n\t" + "! ending __up_read" + : : "r" (sem), "i" (rwsem_wake), + "i" (RWSEM_ACTIVE_MASK) + : "g1", "g5", "g7", "memory", "cc"); +} +EXPORT_SYMBOL(__up_read); + +void __up_write(struct rw_semaphore *sem) +{ + __asm__ __volatile__( + "! beginning __up_write\n\t" + "sethi %%hi(%2), %%g1\n\t" + "or %%g1, %%lo(%2), %%g1\n" + "1:\tlduw [%0], %%g5\n\t" + "sub %%g5, %%g1, %%g7\n\t" + "cas [%0], %%g5, %%g7\n\t" + "cmp %%g5, %%g7\n\t" + "bne,pn %%icc, 1b\n\t" + " sub %%g7, %%g1, %%g7\n\t" + "cmp %%g7, 0\n\t" + "bl,pn %%icc, 3f\n\t" + " membar #StoreLoad | #StoreStore\n" + "2:\n\t" + ".subsection 2\n" + "3:\tmov %0, %%g5\n\t" + "save %%sp, -160, %%sp\n\t" + "mov %%g2, %%l2\n\t" + "mov %%g3, %%l3\n\t" + "call %1\n\t" + " mov %%g5, %%o0\n\t" + "mov %%l2, %%g2\n\t" + "ba,pt %%xcc, 2b\n\t" + " restore %%l3, %%g0, %%g3\n\t" + ".previous\n\t" + "! ending __up_write" + : : "r" (sem), "i" (rwsem_wake), + "i" (RWSEM_ACTIVE_WRITE_BIAS) + : "g1", "g5", "g7", "memory", "cc"); +} +EXPORT_SYMBOL(__up_write); + +void __downgrade_write(struct rw_semaphore *sem) +{ + __asm__ __volatile__( + "! beginning __downgrade_write\n\t" + "sethi %%hi(%2), %%g1\n\t" + "or %%g1, %%lo(%2), %%g1\n" + "1:\tlduw [%0], %%g5\n\t" + "sub %%g5, %%g1, %%g7\n\t" + "cas [%0], %%g5, %%g7\n\t" + "cmp %%g5, %%g7\n\t" + "bne,pn %%icc, 1b\n\t" + " sub %%g7, %%g1, %%g7\n\t" + "cmp %%g7, 0\n\t" + "bl,pn %%icc, 3f\n\t" + " membar #StoreLoad | #StoreStore\n" + "2:\n\t" + ".subsection 2\n" + "3:\tmov %0, %%g5\n\t" + "save %%sp, -160, %%sp\n\t" + "mov %%g2, %%l2\n\t" + "mov %%g3, %%l3\n\t" + "call %1\n\t" + " mov %%g5, %%o0\n\t" + "mov %%l2, %%g2\n\t" + "ba,pt %%xcc, 2b\n\t" + " restore %%l3, %%g0, %%g3\n\t" + ".previous\n\t" + "! ending __up_write" + : : "r" (sem), "i" (rwsem_downgrade_wake), + "i" (RWSEM_WAITING_BIAS) + : "g1", "g5", "g7", "memory", "cc"); +} +EXPORT_SYMBOL(__downgrade_write); diff -Nru a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c --- a/arch/um/drivers/stdio_console.c Wed Apr 2 22:24:04 2003 +++ b/arch/um/drivers/stdio_console.c Wed Apr 2 22:24:04 2003 @@ -18,7 +18,6 @@ #include "linux/interrupt.h" #include "linux/slab.h" #include "asm/current.h" -#include "asm/softirq.h" #include "asm/hardirq.h" #include "asm/irq.h" #include "stdio_console.h" diff -Nru a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c --- a/arch/um/kernel/smp.c Wed Apr 2 22:24:04 2003 +++ b/arch/um/kernel/smp.c Wed Apr 2 22:24:04 2003 @@ -17,7 +17,6 @@ #include "asm/smp.h" #include "asm/processor.h" #include "asm/spinlock.h" -#include "asm/softirq.h" #include "asm/hardirq.h" #include "user_util.h" #include "kern_util.h" diff -Nru a/arch/v850/kernel/v850_ksyms.c b/arch/v850/kernel/v850_ksyms.c --- a/arch/v850/kernel/v850_ksyms.c Wed Apr 2 22:24:06 2003 +++ b/arch/v850/kernel/v850_ksyms.c Wed Apr 2 22:24:06 2003 @@ -16,7 +16,6 @@ #include #include #include -#include #include diff -Nru a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig --- a/arch/x86_64/Kconfig Wed Apr 2 22:24:07 2003 +++ b/arch/x86_64/Kconfig Wed Apr 2 22:24:07 2003 @@ -179,9 +179,7 @@ If you don't know what to do here, say N. -# broken currently config PREEMPT - depends on NOT_WORKING bool "Preemptible Kernel" ---help--- This option reduces the latency of the kernel when reacting to @@ -200,7 +198,7 @@ # someone write a better help text please. config K8_NUMA bool "K8 NUMA support" - depends on SMP && NOT_WORKING + depends on SMP help Enable NUMA (Non Unified Memory Architecture) support for AMD Opteron Multiprocessor systems. The kernel will try to allocate @@ -590,10 +588,8 @@ allocation as well as poisoning memory on free to catch use of freed memory. -# bool ' Memory mapped I/O debugging' CONFIG_DEBUG_IOVIRT config MAGIC_SYSRQ bool "Magic SysRq key" - depends on DEBUG_KERNEL help If you say Y here, you will have some control over the system even if the system crashes for example during kernel debugging (e.g., you @@ -639,13 +635,36 @@ config FRAME_POINTER bool "Compile the kernel with frame pointers" - depends on DEBUG_KERNEL help Compile the kernel with frame pointers. This may help for some debugging with external debuggers. Note the standard oops backtracer - doesn't make use of it and the x86-64 kernel doesn't ensure an consistent + doesn't make use of this and the x86-64 kernel doesn't ensure an consistent frame pointer through inline assembly (semaphores etc.) Normally you should say N. + +config IOMMU_DEBUG + bool "Force IOMMU to on" + help + Force the IOMMU to on even when you have less than 4GB of memory and add + debugging code. + Can be disabled at boot time with iommu=noforce. + +config IOMMU_LEAK + bool "IOMMU leak tracing" + depends on DEBUG_KERNEL + help + Add a simple leak tracer to the IOMMU code. This is useful when you + are debugging a buggy device driver that leaks IOMMU mappings. + +config MCE_DEBUG + bool "K8 Machine check debugging mode" + default y + help + Turn on all Machine Check debugging for device driver problems. + This can cause panics, but is useful to find device driver problems. + +#config X86_REMOTE_DEBUG +# bool "kgdb debugging stub" endmenu diff -Nru a/arch/x86_64/Makefile b/arch/x86_64/Makefile --- a/arch/x86_64/Makefile Wed Apr 2 22:24:07 2003 +++ b/arch/x86_64/Makefile Wed Apr 2 22:24:07 2003 @@ -47,6 +47,10 @@ # should lower this a lot and see how much .text is saves CFLAGS += -finline-limit=2000 #CFLAGS += -g +# don't enable this when you use kgdb: +ifneq ($(CONFIG_X86_REMOTE_DEBUG),y) +CFLAGS += -fno-asynchronous-unwind-tables +endif head-y := arch/x86_64/kernel/head.o arch/x86_64/kernel/head64.o arch/x86_64/kernel/init_task.o diff -Nru a/arch/x86_64/boot/compressed/misc.c b/arch/x86_64/boot/compressed/misc.c --- a/arch/x86_64/boot/compressed/misc.c Wed Apr 2 22:24:05 2003 +++ b/arch/x86_64/boot/compressed/misc.c Wed Apr 2 22:24:05 2003 @@ -274,7 +274,7 @@ puts(x); puts("\n\n -- System halted"); - while(1); /* Halt */ + while(1); } void setup_normal_output_buffer(void) @@ -429,8 +429,6 @@ else setup_output_buffer_if_we_run_high(mv); makecrc(); - puts("Checking CPU type..."); - check_cpu(); puts(".\nDecompressing Linux..."); gunzip(); puts("done.\nBooting the kernel.\n"); diff -Nru a/arch/x86_64/boot/setup.S b/arch/x86_64/boot/setup.S --- a/arch/x86_64/boot/setup.S Wed Apr 2 22:24:07 2003 +++ b/arch/x86_64/boot/setup.S Wed Apr 2 22:24:07 2003 @@ -42,6 +42,7 @@ * if CX/DX have been changed in the e801 call and if so use AX/BX . * Michael Miller, April 2001 * + * Added long mode checking and SSE force. March 2003, Andi Kleen. */ #include @@ -200,10 +201,10 @@ prtsp2: call prtspc # Print double space prtspc: movb $0x20, %al # Print single space (note: fall-thru) -# Part of above routine, this one just prints ascii al -prtchr: pushw %ax +prtchr: + pushw %ax pushw %cx - xorb %bh, %bh + movw $0007,%bx movw $0x01, %cx movb $0x0e, %ah int $0x10 @@ -280,6 +281,75 @@ loader_panic_mess: .string "Wrong loader, giving up..." loader_ok: + /* check for long mode. */ + /* we have to do this before the VESA setup, otherwise the user + can't see the error message. */ + + pushw %ds + movw %cs,%ax + movw %ax,%ds + + /* minimum CPUID flags for x86-64 */ + /* see http://www.x86-64.org/lists/discuss/msg02971.html */ +#define SSE_MASK ((1<<25)|(1<<26)) +#define REQUIRED_MASK1 ((1<<0)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<8)|(1<<11)| \ + (1<<13)|(1<<15)|(1<<24)|(1<<29)) + + pushfl /* standard way to check for cpuid */ + popl %eax + movl %eax,%ebx + xorl $0x200000,%eax + pushl %eax + popfl + pushfl + popl %eax + cmpl %eax,%ebx + jz no_longmode /* cpu has no cpuid */ + movl $0x80000000,%eax + cpuid + cmpl $0x80000001,%eax + jb no_longmode /* no extended cpuid */ + xor %di,%di + cmpl $0x68747541,%ebx /* AuthenticAMD */ + jnz noamd + cmpl $0x69746e65,%edx + jnz noamd + cmpl $0x444d4163,%ecx + jnz noamd + mov $1,%di /* cpu is from AMD */ +noamd: + movl $0x80000001,%eax + cpuid + andl $REQUIRED_MASK1,%edx + xorl $REQUIRED_MASK1,%edx + jnz no_longmode +sse_test: + movl $1,%eax + cpuid + andl $SSE_MASK,%edx + cmpl $SSE_MASK,%edx + je sse_ok + test %di,%di + jz no_longmode /* only try to force SSE on AMD */ + movl $0xc0010015,%ecx /* HWCR */ + rdmsr + btr $15,%eax /* enable SSE */ + wrmsr + xor %di,%di /* don't loop */ + jmp sse_test /* try again */ +no_longmode: + call beep + lea long_mode_panic,%si + call prtstr +no_longmode_loop: + jmp no_longmode_loop +long_mode_panic: + .string "Your CPU does not support long mode. Use a 32bit distribution." + .byte 0 + +sse_ok: + popw %ds + # Get memory size (extended mem, kB) xorl %eax, %eax diff -Nru a/arch/x86_64/ia32/fpu32.c b/arch/x86_64/ia32/fpu32.c --- a/arch/x86_64/ia32/fpu32.c Wed Apr 2 22:24:04 2003 +++ b/arch/x86_64/ia32/fpu32.c Wed Apr 2 22:24:04 2003 @@ -77,17 +77,20 @@ struct _fpxreg *to; struct _fpreg *from; int i; - int err; - __u32 v; + u32 v; + int err = 0; - err = __get_user(fxsave->cwd, &buf->cw); - err |= __get_user(fxsave->swd, &buf->sw); - err |= __get_user(fxsave->twd, &buf->tag); +#define G(num,val) err |= __get_user(val, num + (u32 *)buf) + G(0, fxsave->cwd); + G(1, fxsave->swd); + G(2, fxsave->twd); fxsave->twd = twd_i387_to_fxsr(fxsave->twd); - err |= __get_user(fxsave->rip, &buf->ipoff); - err |= __get_user(fxsave->rdp, &buf->dataoff); - err |= __get_user(v, &buf->cssel); - fxsave->fop = v >> 16; + G(3, fxsave->rip); + G(4, v); + fxsave->fop = v>>16; /* cs ignored */ + G(5, fxsave->rdp); + /* 6: ds ignored */ +#undef G if (err) return -1; @@ -109,21 +112,29 @@ struct _fpreg *to; struct _fpxreg *from; int i; - u32 ds; - int err; + u16 cs,ds; + int err = 0; - err = __put_user((unsigned long)fxsave->cwd | 0xffff0000, &buf->cw); - err |= __put_user((unsigned long)fxsave->swd | 0xffff0000, &buf->sw); - err |= __put_user((u32)fxsave->rip, &buf->ipoff); - err |= __put_user((u32)(regs->cs | ((u32)fxsave->fop << 16)), - &buf->cssel); - err |= __put_user((u32)twd_fxsr_to_i387(fxsave), &buf->tag); - err |= __put_user((u32)fxsave->rdp, &buf->dataoff); - if (tsk == current) - asm("movl %%ds,%0 " : "=r" (ds)); - else /* ptrace. task has stopped. */ + if (tsk == current) { + /* should be actually ds/cs at fpu exception time, + but that information is not available in 64bit mode. */ + asm("movw %%ds,%0 " : "=r" (ds)); + asm("movw %%cs,%0 " : "=r" (cs)); + } else { /* ptrace. task has stopped. */ ds = tsk->thread.ds; - err |= __put_user(ds, &buf->datasel); + cs = regs->cs; + } + +#define P(num,val) err |= __put_user(val, num + (u32 *)buf) + P(0, (u32)fxsave->cwd | 0xffff0000); + P(1, (u32)fxsave->swd | 0xffff0000); + P(2, twd_fxsr_to_i387(fxsave)); + P(3, (u32)fxsave->rip); + P(4, cs | ((u32)fxsave->fop) << 16); + P(5, fxsave->rdp); + P(6, 0xffff0000 | ds); +#undef P + if (err) return -1; @@ -144,9 +155,9 @@ &buf->_fxsr_env[0], sizeof(struct i387_fxsave_struct))) return -1; - } tsk->thread.i387.fxsave.mxcsr &= 0xffbf; - current->used_math = 1; + tsk->used_math = 1; + } return convert_fxsr_from_user(&tsk->thread.i387.fxsave, buf); } @@ -157,12 +168,11 @@ { int err = 0; - if (!tsk->used_math) - return 0; - tsk->used_math = 0; - unlazy_fpu(tsk); + init_fpu(tsk); if (convert_fxsr_to_user(buf, &tsk->thread.i387.fxsave, regs, tsk)) return -1; + if (fsave) + return 0; err |= __put_user(tsk->thread.i387.fxsave.swd, &buf->status); if (fsave) return err ? -1 : 1; diff -Nru a/arch/x86_64/ia32/ia32_ioctl.c b/arch/x86_64/ia32/ia32_ioctl.c --- a/arch/x86_64/ia32/ia32_ioctl.c Wed Apr 2 22:24:05 2003 +++ b/arch/x86_64/ia32/ia32_ioctl.c Wed Apr 2 22:24:05 2003 @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -60,6 +61,8 @@ #include #include #include +#include +#include #if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE) /* Ugh. This header really is not clean */ #define min min @@ -2906,35 +2909,28 @@ { typedef struct serial_struct SS; struct serial_struct32 *ss32 = ptr; - int err = 0; + int err; struct serial_struct ss; mm_segment_t oldseg = get_fs(); - set_fs(KERNEL_DS); if (cmd == TIOCSSERIAL) { - err = -EFAULT; if (copy_from_user(&ss, ss32, sizeof(struct serial_struct32))) - goto out; + return -EFAULT; memmove(&ss.iomem_reg_shift, ((char*)&ss.iomem_base)+4, sizeof(SS)-offsetof(SS,iomem_reg_shift)); ss.iomem_base = (void *)((unsigned long)ss.iomem_base & 0xffffffff); } - if (!err) + set_fs(KERNEL_DS); err = sys_ioctl(fd,cmd,(unsigned long)(&ss)); + set_fs(oldseg); if (cmd == TIOCGSERIAL && err >= 0) { - __u32 base; if (__copy_to_user(ss32,&ss,offsetof(SS,iomem_base)) || - __copy_to_user(&ss32->iomem_reg_shift, - &ss.iomem_reg_shift, - sizeof(SS) - offsetof(SS, iomem_reg_shift))) - err = -EFAULT; - if (ss.iomem_base > (unsigned char *)0xffffffff) - base = -1; - else - base = (unsigned long)ss.iomem_base; - err |= __put_user(base, &ss32->iomem_base); + __put_user((unsigned long)ss.iomem_base >> 32 ? + 0xffffffff : (unsigned)(unsigned long)ss.iomem_base, + &ss32->iomem_base) || + __put_user(ss.iomem_reg_shift, &ss32->iomem_reg_shift) || + __put_user(ss.port_high, &ss32->port_high)) + return -EFAULT; } - out: - set_fs(oldseg); return err; } @@ -3045,7 +3041,14 @@ return sys_ioctl(fd, BLKGETSIZE64, arg); } +/* Bluetooth ioctls */ +#define HCIUARTSETPROTO _IOW('U', 200, int) +#define HCIUARTGETPROTO _IOR('U', 201, int) +#define BNEPCONNADD _IOW('B', 200, int) +#define BNEPCONNDEL _IOW('B', 201, int) +#define BNEPGETCONNLIST _IOR('B', 210, int) +#define BNEPGETCONNINFO _IOR('B', 211, int) struct usbdevfs_ctrltransfer32 { __u8 bRequestType; @@ -4093,6 +4096,7 @@ COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC) COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER) COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE) +COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE_MULTI) /* DEVFS */ COMPATIBLE_IOCTL(DEVFSDIOC_GET_PROTO_REV) COMPATIBLE_IOCTL(DEVFSDIOC_SET_EVENT_MASK) @@ -4200,6 +4204,17 @@ COMPATIBLE_IOCTL(HCISETACLMTU) COMPATIBLE_IOCTL(HCISETSCOMTU) COMPATIBLE_IOCTL(HCIINQUIRY) +COMPATIBLE_IOCTL(HCIUARTSETPROTO) +COMPATIBLE_IOCTL(HCIUARTGETPROTO) +COMPATIBLE_IOCTL(RFCOMMCREATEDEV) +COMPATIBLE_IOCTL(RFCOMMRELEASEDEV) +COMPATIBLE_IOCTL(RFCOMMGETDEVLIST) +COMPATIBLE_IOCTL(RFCOMMGETDEVINFO) +COMPATIBLE_IOCTL(RFCOMMSTEALDLC) +COMPATIBLE_IOCTL(BNEPCONNADD) +COMPATIBLE_IOCTL(BNEPCONNDEL) +COMPATIBLE_IOCTL(BNEPGETCONNLIST) +COMPATIBLE_IOCTL(BNEPGETCONNINFO) /* Misc. */ COMPATIBLE_IOCTL(0x41545900) /* ATYIO_CLKR */ COMPATIBLE_IOCTL(0x41545901) /* ATYIO_CLKW */ diff -Nru a/arch/x86_64/ia32/ia32_signal.c b/arch/x86_64/ia32/ia32_signal.c --- a/arch/x86_64/ia32/ia32_signal.c Wed Apr 2 22:24:07 2003 +++ b/arch/x86_64/ia32/ia32_signal.c Wed Apr 2 22:24:07 2003 @@ -47,9 +47,16 @@ { if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) return -EFAULT; - if (from->si_code < 0) - return __copy_to_user(to, from, sizeof(siginfo_t)); - else { + if (from->si_code < 0) { + /* the only field that's different is the alignment + of the pointer in sigval_t. Move that 4 bytes down including + padding. */ + memmove(&((siginfo_t32 *)&from)->si_int, + &from->si_int, + sizeof(siginfo_t) - offsetof(siginfo_t, si_int)); + /* last 4 bytes stay the same */ + return __copy_to_user(to, from, sizeof(siginfo_t32)); + } else { int err; /* If you change siginfo_t structure, please be sure @@ -59,7 +66,7 @@ 3 ints plus the relevant union member. */ err = __put_user(from->si_signo, &to->si_signo); err |= __put_user(from->si_errno, &to->si_errno); - err |= __put_user((short)from->si_code, &to->si_code); + err |= __put_user(from->si_code, &to->si_code); /* First 32bits of unions are always present. */ err |= __put_user(from->si_pid, &to->si_pid); switch (from->si_code >> 16) { @@ -108,6 +115,7 @@ mm_segment_t seg; if (uss_ptr) { u32 ptr; + memset(&uss,0,sizeof(stack_t)); if (!access_ok(VERIFY_READ,uss_ptr,sizeof(stack_ia32_t)) || __get_user(ptr, &uss_ptr->ss_sp) || __get_user(uss.ss_flags, &uss_ptr->ss_flags) || @@ -340,8 +348,11 @@ tmp = save_i387_ia32(current, fpstate, regs, 0); if (tmp < 0) err = -EFAULT; - else + else { + current->used_math = 0; + stts(); err |= __put_user((u32)(u64)(tmp ? fpstate : NULL), &sc->fpstate); + } /* non-iBCS2 extensions.. */ err |= __put_user(mask, &sc->oldmask); diff -Nru a/arch/x86_64/ia32/ipc32.c b/arch/x86_64/ia32/ipc32.c --- a/arch/x86_64/ia32/ipc32.c Wed Apr 2 22:24:05 2003 +++ b/arch/x86_64/ia32/ipc32.c Wed Apr 2 22:24:05 2003 @@ -187,12 +187,58 @@ } } +static int put_semid(void *user_semid, struct semid64_ds *s, int version) +{ + int err2; + switch (version) { + case IPC_64: { + struct semid64_ds32 *usp64 = (struct semid64_ds32 *) user_semid; + + if (!access_ok(VERIFY_WRITE, usp64, sizeof(*usp64))) { + err2 = -EFAULT; + break; + } + err2 = __put_user(s->sem_perm.key, &usp64->sem_perm.key); + err2 |= __put_user(s->sem_perm.uid, &usp64->sem_perm.uid); + err2 |= __put_user(s->sem_perm.gid, &usp64->sem_perm.gid); + err2 |= __put_user(s->sem_perm.cuid, &usp64->sem_perm.cuid); + err2 |= __put_user(s->sem_perm.cgid, &usp64->sem_perm.cgid); + err2 |= __put_user(s->sem_perm.mode, &usp64->sem_perm.mode); + err2 |= __put_user(s->sem_perm.seq, &usp64->sem_perm.seq); + err2 |= __put_user(s->sem_otime, &usp64->sem_otime); + err2 |= __put_user(s->sem_ctime, &usp64->sem_ctime); + err2 |= __put_user(s->sem_nsems, &usp64->sem_nsems); + break; + } + default: { + struct semid_ds32 *usp32 = (struct semid_ds32 *) user_semid; + + if (!access_ok(VERIFY_WRITE, usp32, sizeof(*usp32))) { + err2 = -EFAULT; + break; + } + err2 = __put_user(s->sem_perm.key, &usp32->sem_perm.key); + err2 |= __put_user(s->sem_perm.uid, &usp32->sem_perm.uid); + err2 |= __put_user(s->sem_perm.gid, &usp32->sem_perm.gid); + err2 |= __put_user(s->sem_perm.cuid, &usp32->sem_perm.cuid); + err2 |= __put_user(s->sem_perm.cgid, &usp32->sem_perm.cgid); + err2 |= __put_user(s->sem_perm.mode, &usp32->sem_perm.mode); + err2 |= __put_user(s->sem_perm.seq, &usp32->sem_perm.seq); + err2 |= __put_user(s->sem_otime, &usp32->sem_otime); + err2 |= __put_user(s->sem_ctime, &usp32->sem_ctime); + err2 |= __put_user(s->sem_nsems, &usp32->sem_nsems); + break; + } + } + return err2; +} + static int semctl32 (int first, int second, int third, void *uptr) { union semun fourth; u32 pad; - int err = 0, err2; + int err; struct semid64_ds s; mm_segment_t old_fs; int version = ipc_parse_version32(&third); @@ -225,46 +271,10 @@ fourth.__pad = &s; old_fs = get_fs(); set_fs(KERNEL_DS); - err = sys_semctl(first, second|IPC_64, third, fourth); + err = sys_semctl(first, second, third|IPC_64, fourth); set_fs(old_fs); - - if (version == IPC_64) { - struct semid64_ds32 *usp64 = (struct semid64_ds32 *) A(pad); - - if (!access_ok(VERIFY_WRITE, usp64, sizeof(*usp64))) { - err = -EFAULT; - break; - } - err2 = __put_user(s.sem_perm.key, &usp64->sem_perm.key); - err2 |= __put_user(s.sem_perm.uid, &usp64->sem_perm.uid); - err2 |= __put_user(s.sem_perm.gid, &usp64->sem_perm.gid); - err2 |= __put_user(s.sem_perm.cuid, &usp64->sem_perm.cuid); - err2 |= __put_user(s.sem_perm.cgid, &usp64->sem_perm.cgid); - err2 |= __put_user(s.sem_perm.mode, &usp64->sem_perm.mode); - err2 |= __put_user(s.sem_perm.seq, &usp64->sem_perm.seq); - err2 |= __put_user(s.sem_otime, &usp64->sem_otime); - err2 |= __put_user(s.sem_ctime, &usp64->sem_ctime); - err2 |= __put_user(s.sem_nsems, &usp64->sem_nsems); - } else { - struct semid_ds32 *usp32 = (struct semid_ds32 *) A(pad); - - if (!access_ok(VERIFY_WRITE, usp32, sizeof(*usp32))) { - err = -EFAULT; - break; - } - err2 = __put_user(s.sem_perm.key, &usp32->sem_perm.key); - err2 |= __put_user(s.sem_perm.uid, &usp32->sem_perm.uid); - err2 |= __put_user(s.sem_perm.gid, &usp32->sem_perm.gid); - err2 |= __put_user(s.sem_perm.cuid, &usp32->sem_perm.cuid); - err2 |= __put_user(s.sem_perm.cgid, &usp32->sem_perm.cgid); - err2 |= __put_user(s.sem_perm.mode, &usp32->sem_perm.mode); - err2 |= __put_user(s.sem_perm.seq, &usp32->sem_perm.seq); - err2 |= __put_user(s.sem_otime, &usp32->sem_otime); - err2 |= __put_user(s.sem_ctime, &usp32->sem_ctime); - err2 |= __put_user(s.sem_nsems, &usp32->sem_nsems); - } - if (err2) - err = -EFAULT; + if (!err) + err = put_semid((void *)A(pad), &s, version); break; default: err = -EINVAL; @@ -343,6 +353,7 @@ return err; } + static int msgctl32 (int first, int second, void *uptr) { @@ -387,7 +398,6 @@ set_fs(KERNEL_DS); err = sys_msgctl(first, second|IPC_64, (void *) &m64); set_fs(old_fs); - if (version == IPC_64) { if (!access_ok(VERIFY_WRITE, up64, sizeof(*up64))) { err = -EFAULT; @@ -608,7 +618,9 @@ if (err2) err = -EFAULT; break; - + default: + err = -EINVAL; + break; } return err; } diff -Nru a/arch/x86_64/ia32/ptrace32.c b/arch/x86_64/ia32/ptrace32.c --- a/arch/x86_64/ia32/ptrace32.c Wed Apr 2 22:24:04 2003 +++ b/arch/x86_64/ia32/ptrace32.c Wed Apr 2 22:24:04 2003 @@ -8,7 +8,7 @@ * This allows to access 64bit processes too; but there is no way to see the extended * register contents. * - * $Id: ptrace32.c,v 1.12 2002/03/24 13:02:02 ak Exp $ + * $Id: ptrace32.c,v 1.16 2003/03/14 16:06:35 ak Exp $ */ #include @@ -22,11 +22,9 @@ #include #include #include -#include -#include #include -#include #include +#include #define R32(l,q) \ case offsetof(struct user32, regs.l): stack[offsetof(struct pt_regs, q)/8] = val; break @@ -39,29 +37,26 @@ switch (regno) { case offsetof(struct user32, regs.fs): if (val && (val & 3) != 3) return -EIO; - child->thread.fs = val; + child->thread.fs = val & 0xffff; break; case offsetof(struct user32, regs.gs): if (val && (val & 3) != 3) return -EIO; - child->thread.gs = val; + child->thread.gs = val & 0xffff; break; case offsetof(struct user32, regs.ds): if (val && (val & 3) != 3) return -EIO; - child->thread.ds = val; + child->thread.ds = val & 0xffff; break; case offsetof(struct user32, regs.es): - if (val && (val & 3) != 3) return -EIO; - child->thread.es = val; + child->thread.es = val & 0xffff; break; - case offsetof(struct user32, regs.ss): if ((val & 3) != 3) return -EIO; - stack[offsetof(struct pt_regs, ss)/8] = val; + stack[offsetof(struct pt_regs, ss)/8] = val & 0xffff; break; - case offsetof(struct user32, regs.cs): if ((val & 3) != 3) return -EIO; - stack[offsetof(struct pt_regs, cs)/8] = val; + stack[offsetof(struct pt_regs, cs)/8] = val & 0xffff; break; R32(ebx, rbx); @@ -79,8 +74,16 @@ stack[offsetof(struct pt_regs, eflags)/8] = val & 0x44dd5; break; - case offsetof(struct user32, u_debugreg[0]) ... offsetof(struct user32, u_debugreg[6]): - child->thread.debugreg[(regno-offsetof(struct user32, u_debugreg[0]))/4] = val; + case offsetof(struct user32, u_debugreg[4]): + case offsetof(struct user32, u_debugreg[5]): + return -EIO; + + case offsetof(struct user32, u_debugreg[0]) ... + offsetof(struct user32, u_debugreg[3]): + case offsetof(struct user32, u_debugreg[6]): + child->thread.debugreg + [(regno-offsetof(struct user32, u_debugreg[0]))/4] + = val; break; case offsetof(struct user32, u_debugreg[7]): @@ -170,11 +173,19 @@ if (child) get_task_struct(child); read_unlock(&tasklist_lock); - *err = ptrace_check_attach(child,0); - if (*err == 0) + if (child) { + *err = -EPERM; + if (child->pid == 1) + goto out; + *err = ptrace_check_attach(child, request == PTRACE_KILL); + if (*err < 0) + goto out; return child; + } + out: put_task_struct(child); return NULL; + } extern asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, unsigned long data); @@ -187,6 +198,9 @@ __u32 val; switch (request) { + default: + return sys_ptrace(request, pid, addr, data); + case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: case PTRACE_POKEDATA: @@ -201,9 +215,6 @@ case PTRACE_GETFPXREGS: break; - default: - ret = sys_ptrace(request, pid, addr, data); - return ret; } child = find_target(request, pid, &ret); @@ -261,7 +272,6 @@ ret = -EIO; break; } - empty_fpu(child); ret = 0; for ( i = 0; i <= 16*4; i += sizeof(u32) ) { ret |= __get_user(tmp, (u32 *) (unsigned long) data); @@ -271,33 +281,47 @@ break; } - case PTRACE_SETFPREGS: - empty_fpu(child); + case PTRACE_GETFPREGS: + ret = -EIO; + if (!access_ok(VERIFY_READ, (void *)(u64)data, + sizeof(struct user_i387_struct))) + break; save_i387_ia32(child, (void *)(u64)data, childregs, 1); ret = 0; break; - case PTRACE_GETFPREGS: - empty_fpu(child); - restore_i387_ia32(child, (void *)(u64)data, 1); + case PTRACE_SETFPREGS: + ret = -EIO; + if (!access_ok(VERIFY_WRITE, (void *)(u64)data, + sizeof(struct user_i387_struct))) + break; ret = 0; + /* don't check EFAULT to be bug-to-bug compatible to i386 */ + restore_i387_ia32(child, (void *)(u64)data, 1); break; case PTRACE_GETFPXREGS: { struct user32_fxsr_struct *u = (void *)(u64)data; - empty_fpu(child); - ret = copy_to_user(u, &child->thread.i387.fxsave, sizeof(*u)); - ret |= __put_user(childregs->cs, &u->fcs); - ret |= __put_user(child->thread.ds, &u->fos); - if (ret) + init_fpu(child); + ret = -EIO; + if (!access_ok(VERIFY_WRITE, u, sizeof(*u))) + break; ret = -EFAULT; + if (__copy_to_user(u, &child->thread.i387.fxsave, sizeof(*u))) + break; + ret = __put_user(childregs->cs, &u->fcs); + ret |= __put_user(child->thread.ds, &u->fos); break; } case PTRACE_SETFPXREGS: { struct user32_fxsr_struct *u = (void *)(u64)data; - empty_fpu(child); - /* no error checking to be bug to bug compatible with i386 */ - copy_from_user(&child->thread.i387.fxsave, u, sizeof(*u)); + unlazy_fpu(child); + ret = -EIO; + if (!access_ok(VERIFY_READ, u, sizeof(*u))) + break; + /* no checking to be bug-to-bug compatible with i386 */ + __copy_from_user(&child->thread.i387.fxsave, u, sizeof(*u)); + child->used_math = 1; child->thread.i387.fxsave.mxcsr &= 0xffbf; ret = 0; break; diff -Nru a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c --- a/arch/x86_64/ia32/sys_ia32.c Wed Apr 2 22:24:05 2003 +++ b/arch/x86_64/ia32/sys_ia32.c Wed Apr 2 22:24:05 2003 @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include @@ -738,7 +739,7 @@ asmlinkage ssize_t sys_writev(unsigned long,const struct iovec *,unsigned long); static struct iovec * -get_compat_iovec(struct compat_iovec *iov32, struct iovec *iov_buf, u32 count, int type, int *errp) +get_compat_iovec(struct compat_iovec *iov32, struct iovec *iov_buf, u32 *count, int type, int *errp) { int i; u32 buf, len; @@ -747,15 +748,18 @@ /* Get the "struct iovec" from user memory */ - if (!count) + *errp = 0; + if (!*count) return 0; - if (count > UIO_MAXIOV) + *errp = -EINVAL; + if (*count > UIO_MAXIOV) return(struct iovec *)0; - if(verify_area(VERIFY_READ, iov32, sizeof(struct compat_iovec)*count)) + *errp = -EFAULT; + if(verify_area(VERIFY_READ, iov32, sizeof(struct compat_iovec)*(*count))) return(struct iovec *)0; - if (count > UIO_FASTIOV) { + if (*count > UIO_FASTIOV) { *errp = -ENOMEM; - iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL); + iov = kmalloc(*count*sizeof(struct iovec), GFP_KERNEL); if (!iov) return((struct iovec *)0); } else @@ -763,14 +767,19 @@ ivp = iov; totlen = 0; - for (i = 0; i < count; i++) { + for (i = 0; i < *count; i++) { *errp = __get_user(len, &iov32->iov_len) | __get_user(buf, &iov32->iov_base); if (*errp) goto error; *errp = verify_area(type, (void *)A(buf), len); - if (*errp) + if (*errp) { + if (i > 0) { + *count = i; + break; + } goto error; + } /* SuS checks: */ *errp = -EINVAL; if ((int)len < 0) @@ -799,7 +808,7 @@ int ret; mm_segment_t old_fs = get_fs(); - if ((iov = get_compat_iovec(vector, iovstack, count, VERIFY_WRITE, &ret)) == NULL) + if ((iov = get_compat_iovec(vector, iovstack, &count, VERIFY_WRITE, &ret)) == NULL) return ret; set_fs(KERNEL_DS); ret = sys_readv(fd, iov, count); @@ -817,7 +826,7 @@ int ret; mm_segment_t old_fs = get_fs(); - if ((iov = get_compat_iovec(vector, iovstack, count, VERIFY_READ, &ret)) == NULL) + if ((iov = get_compat_iovec(vector, iovstack, &count, VERIFY_READ, &ret)) == NULL) return ret; set_fs(KERNEL_DS); ret = sys_writev(fd, iov, count); @@ -1672,21 +1681,26 @@ return cnt; } -long sys32_execve(char *name, u32 argv, u32 envp, struct pt_regs regs) +asmlinkage long sys32_execve(char *name, u32 argv, u32 envp, struct pt_regs regs) { mm_segment_t oldseg; - char **buf; - int na,ne; + char **buf = NULL; + int na = 0,ne = 0; int ret; - unsigned sz; + unsigned sz = 0; + if (argv) { na = nargs(argv, NULL); if (na < 0) return -EFAULT; + } + if (envp) { ne = nargs(envp, NULL); if (ne < 0) return -EFAULT; + } + if (argv || envp) { sz = (na+ne)*sizeof(void *); if (sz > PAGE_SIZE) buf = vmalloc(sz); @@ -1694,14 +1708,19 @@ buf = kmalloc(sz, GFP_KERNEL); if (!buf) return -ENOMEM; + } + if (argv) { ret = nargs(argv, buf); if (ret < 0) goto free; + } + if (envp) { ret = nargs(envp, buf + na); if (ret < 0) goto free; + } name = getname(name); ret = PTR_ERR(name); @@ -1710,7 +1729,7 @@ oldseg = get_fs(); set_fs(KERNEL_DS); - ret = do_execve(name, buf, buf+na, ®s); + ret = do_execve(name, argv ? buf : NULL, envp ? buf+na : NULL, ®s); set_fs(oldseg); if (ret == 0) @@ -1719,10 +1738,12 @@ putname(name); free: + if (argv || envp) { if (sz > PAGE_SIZE) vfree(buf); else kfree(buf); + } return ret; } @@ -2012,12 +2033,8 @@ long sys32_module_warning(void) { - static long warn_time = -(60*HZ); - if (time_before(warn_time + 60*HZ,jiffies) && strcmp(current->comm,"klogd")) { printk(KERN_INFO "%s: 32bit 2.4.x modutils not supported on 64bit kernel\n", current->comm); - warn_time = jiffies; - } return -ENOSYS ; } @@ -2055,6 +2072,7 @@ return err; } + extern long sys_io_setup(unsigned nr_reqs, aio_context_t *ctx); long sys32_io_setup(unsigned nr_reqs, u32 *ctx32p) @@ -2071,48 +2089,47 @@ return ret; } -extern asmlinkage long sys_io_submit(aio_context_t ctx_id, long nr, - struct iocb **iocbpp); - -long sys32_io_submit(aio_context_t ctx_id, unsigned long nr, - u32 *iocbpp) +asmlinkage long sys32_io_submit(aio_context_t ctx_id, int nr, + compat_uptr_t *iocbpp) { - mm_segment_t oldfs = get_fs(); - int k, err = 0; - struct iocb **iocb64; - if (nr > 128) + struct kioctx *ctx; + long ret = 0; + int i; + + if (unlikely(nr < 0)) + return -EINVAL; + + if (unlikely(!access_ok(VERIFY_READ, iocbpp, (nr*sizeof(*iocbpp))))) + return -EFAULT; + + ctx = lookup_ioctx(ctx_id); + if (unlikely(!ctx)) { + pr_debug("EINVAL: io_submit: invalid context id\n"); return -EINVAL; - iocb64 = kmalloc(sizeof(struct iocb *) * nr, GFP_KERNEL); - if (!iocb64) - return -ENOMEM; - for (k = 0; k < nr && !err; k++) { - u64 val1, val2; - u32 iocb32; - struct iocb *iocb; - err = get_user(iocb32, (u32 *)(u64)iocbpp[k]); - iocb64[k] = iocb = (void *)(u64)iocb32; - - if (get_user(val1, &iocb->aio_buf) || - get_user(val2, &iocb->aio_nbytes)) - err = -EFAULT; - else if (!val1) /* should check cmd */ - ; - else if (verify_area(VERIFY_WRITE, (void*)val1, val2)) - err = -EFAULT; - - /* paranoia check - remove it when you are sure they - are not pointers */ - if (get_user(val1, &iocb->aio_reserved2) || val1 || - get_user(val2, &iocb->aio_reserved2) || val2) - err = -EFAULT; - } - if (!err) { - set_fs(KERNEL_DS); - err = sys_io_submit(ctx_id, nr, iocb64); - set_fs(oldfs); } - kfree(iocb64); - return err; + + for (i=0; icomm); - warn_time = jiffies; - } return -ENOSYS ; } diff -Nru a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile --- a/arch/x86_64/kernel/Makefile Wed Apr 2 22:24:06 2003 +++ b/arch/x86_64/kernel/Makefile Wed Apr 2 22:24:06 2003 @@ -10,14 +10,13 @@ setup64.o bluesmoke.o bootflag.o e820.o reboot.o obj-$(CONFIG_MTRR) += mtrr/ +obj-$(CONFIG_ACPI) += acpi/ obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_CPUID) += cpuid.o obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o obj-$(CONFIG_X86_IO_APIC) += io_apic.o mpparse.o obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o suspend_asm.o -obj-$(CONFIG_ACPI) += acpi.o -obj-$(CONFIG_ACPI_SLEEP) += wakeup.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_GART_IOMMU) += pci-gart.o aperture.o obj-$(CONFIG_DUMMY_IOMMU) += pci-nommu.o diff -Nru a/arch/x86_64/kernel/aperture.c b/arch/x86_64/kernel/aperture.c --- a/arch/x86_64/kernel/aperture.c Wed Apr 2 22:24:06 2003 +++ b/arch/x86_64/kernel/aperture.c Wed Apr 2 22:24:06 2003 @@ -105,7 +105,8 @@ if (!fix && !fallback_aper_force) return; - printk("Your BIOS is broken and doesn't leave a aperture memory hole\n"); + printk("Your BIOS doesn't leave a aperture memory hole\n"); + printk("Please enable the IOMMU option in the BIOS setup\n"); aper_alloc = allocate_aperture(); if (!aper_alloc) return; diff -Nru a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c --- a/arch/x86_64/kernel/apic.c Wed Apr 2 22:24:04 2003 +++ b/arch/x86_64/kernel/apic.c Wed Apr 2 22:24:04 2003 @@ -408,7 +408,7 @@ if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ apic_write(APIC_ESR, 0); value = apic_read(APIC_ESR); - printk("ESR value before enabling vector: %08x\n", value); + Dprintk("ESR value before enabling vector: %08x\n", value); value = ERROR_APIC_VECTOR; // enables sending errors apic_write_around(APIC_LVTERR, value); @@ -418,7 +418,7 @@ if (maxlvt > 3) apic_write(APIC_ESR, 0); value = apic_read(APIC_ESR); - printk("ESR value after enabling vector: %08x\n", value); + Dprintk("ESR value after enabling vector: %08x\n", value); } else { if (esr_disable) /* @@ -1080,9 +1080,10 @@ if (nmi_watchdog == NMI_LOCAL_APIC) check_nmi_watchdog(); #ifdef CONFIG_X86_IO_APIC - if (smp_found_config) - if (!skip_ioapic_setup && nr_ioapics) + if (smp_found_config && !skip_ioapic_setup && nr_ioapics) setup_IO_APIC(); + else + nr_ioapics = 0; #endif setup_boot_APIC_clock(); diff -Nru a/arch/x86_64/kernel/bluesmoke.c b/arch/x86_64/kernel/bluesmoke.c --- a/arch/x86_64/kernel/bluesmoke.c Wed Apr 2 22:24:07 2003 +++ b/arch/x86_64/kernel/bluesmoke.c Wed Apr 2 22:24:07 2003 @@ -1,65 +1,87 @@ /* - * arch/x86_64/kernel/bluesmoke.c - x86-64 Machine Check Exception Reporting - * - -RED-PEN: need to add power management to restore after S3 wakeup. - + * Machine check handler. + * K8 parts Copyright 2002,2003 Andi Kleen, SuSE Labs. + * Rest from unknown author(s). */ - +#include #include #include #include -#include -#include -#include -#include +#include +#include +#include #include -#include #include -#include -#include -#include +#include +#include +#include -#ifdef CONFIG_X86_MCE +static int mce_disabled __initdata; +static unsigned long mce_cpus; -static int mce_disabled __initdata = 0; +/* + * Machine Check Handler For PII/PIII/K7 + */ static int banks; +static unsigned long ignored_banks, disabled_banks; +/* Machine Check on everything dubious. This is a good setting + for device driver testing. */ +#define K8_DRIVER_DEBUG ((1<<13)-1) +/* Report RAM errors and Hyper Transport Problems, but ignore Device + aborts and GART errors. */ +#define K8_NORMAL_OP 0xff -/* - * Machine Check Handler For Hammer - */ +#ifdef CONFIG_MCE_DEBUG +static u32 k8_nb_flags __initdata = K8_DRIVER_DEBUG; +#else +static u32 k8_nb_flags __initdata = K8_NORMAL_OP; +#endif -static void hammer_machine_check(struct pt_regs * regs, long error_code) +static void generic_machine_check(struct pt_regs * regs, long error_code) { int recover=1; u32 alow, ahigh, high, low; u32 mcgstl, mcgsth; int i; + preempt_disable(); + rdmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth); if(mcgstl&(1<<0)) /* Recoverable ? */ recover=0; printk(KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n", smp_processor_id(), mcgsth, mcgstl); - preempt_disable(); - for (i=0;i:%016lx RSP %016lx\n", + regs->cs, regs->rip, regs->rsp); + + for(i=0;ibus->number==0 && PCI_FUNC(dev->devfn)==3 && + PCI_SLOT(dev->devfn) == (24+cpu)) + return dev; + } + return NULL; +} -static void mce_checkregs (void *info) +static void check_k8_nb(void) { - u32 low, high; - int i; + struct pci_dev *nb; + nb = find_k8_nb(); + if (nb == NULL) + return; - for (i=0; irip, regs->rsp); + + others: + generic_machine_check(regs, error_code); + preempt_enable(); +} + +static struct timer_list mcheck_timer; +int mcheck_interval = 30*HZ; -static void mce_timerfunc (unsigned long data) +#ifndef CONFIG_SMP +static void mcheck_timer_handler(unsigned long data) { - on_each_cpu (mce_checkregs, NULL, 1, 1); + k8_machine_check(NULL,0); + mcheck_timer.expires = jiffies + mcheck_interval; + add_timer(&mcheck_timer); +} +#else + +/* SMP needs a process context trampoline because smp_call_function cannot be + called from interrupt context. */ - /* Refresh the timer. */ - mce_timer.expires = jiffies + MCE_RATE; - add_timer (&mce_timer); +static void mcheck_timer_other(void *data) +{ + k8_machine_check(NULL, 0); +} + +static void mcheck_timer_dist(void *data) +{ + smp_call_function(mcheck_timer_other,0,0,0); + k8_machine_check(NULL, 0); + mcheck_timer.expires = jiffies + mcheck_interval; + add_timer(&mcheck_timer); +} + +static void mcheck_timer_handler(unsigned long data) +{ + static DECLARE_WORK(mcheck_work, mcheck_timer_dist, NULL); + schedule_work(&mcheck_work); } #endif +static int nok8 __initdata; + +static void __init k8_mcheck_init(struct cpuinfo_x86 *c) +{ + u64 cap; + int i; + struct pci_dev *nb; + + if (!test_bit(X86_FEATURE_MCE, &c->x86_capability) || + !test_bit(X86_FEATURE_MCA, &c->x86_capability)) + return; + + rdmsrl(MSR_IA32_MCG_CAP, cap); + banks = cap&0xff; + machine_check_vector = k8_machine_check; + for (i = 0; i < banks; i++) { + u64 val = ((1UL<devfn, reg, reg2); + ignored_banks |= (1UL<<4); + } + + set_in_cr4(X86_CR4_MCE); + + if (mcheck_interval && (smp_processor_id() == 0)) { + init_timer(&mcheck_timer); + mcheck_timer.function = (void (*)(unsigned long))mcheck_timer_handler; + mcheck_timer.expires = jiffies + mcheck_interval; + add_timer(&mcheck_timer); + } + + printk(KERN_INFO "Machine Check Reporting enabled for CPU#%d\n", smp_processor_id()); +} /* - * Set up machine check reporting for processors with Intel style MCE + * Set up machine check reporting for Intel processors */ -static void __init hammer_mcheck_init(struct cpuinfo_x86 *c) +static void __init generic_mcheck_init(struct cpuinfo_x86 *c) { u32 l, h; int i; @@ -154,33 +310,36 @@ * Check for MCE support */ - if( !test_bit(X86_FEATURE_MCE, c->x86_capability) ) + if( !test_bit(X86_FEATURE_MCE, &c->x86_capability) ) return; - /* Check for PPro style MCA */ - if( !test_bit(X86_FEATURE_MCA, c->x86_capability) ) + /* + * Check for PPro style MCA + */ + + if( !test_bit(X86_FEATURE_MCA, &c->x86_capability) ) return; /* Ok machine check is available */ - machine_check_vector = hammer_machine_check; + + machine_check_vector = generic_machine_check; wmb(); if(done==0) - printk(KERN_INFO "Machine check architecture supported.\n"); + printk(KERN_INFO "Intel machine check architecture supported.\n"); rdmsr(MSR_IA32_MCG_CAP, l, h); - if(l&(1<<8)) /* Control register present ? */ + if(l&(1<<8)) wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff); banks = l&0xff; - for(i=0; ix86_vendor) - { + switch(c->x86_vendor) { case X86_VENDOR_AMD: - hammer_mcheck_init(c); -#ifdef CONFIG_X86_MCE_NONFATAL - if (timerset == 0) { - /* Set the timer to check for non-fatal - errors every MCE_RATE seconds */ - init_timer (&mce_timer); - mce_timer.expires = jiffies + MCE_RATE; - mce_timer.data = 0; - mce_timer.function = &mce_timerfunc; - add_timer (&mce_timer); - timerset = 1; - printk(KERN_INFO "Machine check exception polling timer started.\n"); - } -#endif + if (c->x86 == 15 && !nok8) { + k8_mcheck_init(c); break; - + } + /* FALL THROUGH */ default: + case X86_VENDOR_INTEL: + generic_mcheck_init(c); break; } } @@ -224,16 +375,33 @@ return 0; } + +/* mce=off disable machine check + mce=nok8 disable k8 specific features + mce=disable disable bank NUMBER + mce=enable enable bank number + mce=device Enable device driver test reporting in NB + mce=NUMBER mcheck timer interval number seconds. + Can be also comma separated in a single mce= */ static int __init mcheck_enable(char *str) { - mce_disabled = -1; + char *p; + while ((p = strsep(&str,",")) != NULL) { + if (isdigit(*p)) + mcheck_interval = simple_strtol(p,NULL,0) * HZ; + else if (!strcmp(p,"off")) + mce_disabled = 1; + else if (!strncmp(p,"enable",6)) + disabled_banks &= ~(1< level2_kernel_pgt (so that __va works even before pagetable_init) */ .org 0xb000 +ENTRY(wakeup_level4_pgt) + .quad 0x0000000000102007 /* -> level3_ident_pgt */ + .fill 255,8,0 + .quad 0x000000000010a007 + .fill 254,8,0 + /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */ + .quad 0x0000000000103007 /* -> level3_kernel_pgt */ + +.org 0xc000 .data .align 16 @@ -371,3 +380,4 @@ .quad 0 .quad 0 .endr + diff -Nru a/arch/x86_64/kernel/head64.c b/arch/x86_64/kernel/head64.c --- a/arch/x86_64/kernel/head64.c Wed Apr 2 22:24:05 2003 +++ b/arch/x86_64/kernel/head64.c Wed Apr 2 22:24:05 2003 @@ -15,6 +15,7 @@ #include #include #include +#include /* Don't add a printk in there. printk relies on the PDA which is not initialized yet. */ @@ -51,7 +52,7 @@ printk("old bootloader convention, maybe loadlin?\n"); } command_line = (char *) ((u64)(new_data)); - memcpy(saved_command_line, command_line, 2048); + memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); printk("Bootdata ok (command line is %s)\n", saved_command_line); } diff -Nru a/arch/x86_64/kernel/i387.c b/arch/x86_64/kernel/i387.c --- a/arch/x86_64/kernel/i387.c Wed Apr 2 22:24:04 2003 +++ b/arch/x86_64/kernel/i387.c Wed Apr 2 22:24:04 2003 @@ -42,7 +42,7 @@ /* clean state in init */ stts(); - clear_thread_flag(TIF_USEDFPU); + current_thread_info()->status = 0; current->used_math = 0; } @@ -51,13 +51,12 @@ * so initialize it and set the mxcsr to its default. * remeber the current task has used the FPU. */ -void init_fpu(void) +void init_fpu(struct task_struct *child) { - struct task_struct *me = current; - memset(&me->thread.i387.fxsave, 0, sizeof(struct i387_fxsave_struct)); - me->thread.i387.fxsave.cwd = 0x37f; - me->thread.i387.fxsave.mxcsr = 0x1f80; - me->used_math = 1; + memset(&child->thread.i387.fxsave, 0, sizeof(struct i387_fxsave_struct)); + child->thread.i387.fxsave.cwd = 0x37f; + child->thread.i387.fxsave.mxcsr = 0x1f80; + child->used_math = 1; } /* @@ -81,7 +80,7 @@ if (!tsk->used_math) return 0; tsk->used_math = 0; /* trigger finit */ - if (test_thread_flag(TIF_USEDFPU)) { + if (tsk->thread_info->status & TS_USEDFPU) { err = save_i387_checking((struct i387_fxsave_struct *)buf); if (err) return err; stts(); @@ -99,7 +98,7 @@ int get_fpregs(struct user_i387_struct *buf, struct task_struct *tsk) { - empty_fpu(tsk); + init_fpu(tsk); return __copy_to_user((void *)buf, &tsk->thread.i387.fxsave, sizeof(struct user_i387_struct)) ? -EFAULT : 0; } diff -Nru a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c --- a/arch/x86_64/kernel/nmi.c Wed Apr 2 22:24:05 2003 +++ b/arch/x86_64/kernel/nmi.c Wed Apr 2 22:24:05 2003 @@ -25,13 +25,15 @@ #include #include #include +#include +#include extern void default_do_nmi(struct pt_regs *); unsigned int nmi_watchdog = NMI_LOCAL_APIC; static unsigned int nmi_hz = HZ; unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */ -extern void show_registers(struct pt_regs *regs); +int nmi_watchdog_disabled; #define K7_EVNTSEL_ENABLE (1 << 22) #define K7_EVNTSEL_INT (1 << 20) @@ -251,15 +253,13 @@ alert_counter[i] = 0; } -void nmi_watchdog_tick (struct pt_regs * regs) +void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason) { + if (nmi_watchdog_disabled) + return; + + int sum, cpu = safe_smp_processor_id(); - /* - * Since current_thread_info()-> is always on the stack, and we - * always switch the stack NMI-atomically, it's safe to use - * smp_processor_id(). - */ - int sum, cpu = smp_processor_id(); sum = read_pda(apic_timer_irqs); if (last_irq_sums[cpu] == sum) { @@ -269,6 +269,10 @@ */ alert_counter[cpu]++; if (alert_counter[cpu] == 5*nmi_hz) { + if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_BAD) { + alert_counter[cpu] = 0; + return; + } spin_lock(&nmi_print_lock); /* * We are in trouble anyway, lets at least try diff -Nru a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c --- a/arch/x86_64/kernel/pci-gart.c Wed Apr 2 22:24:05 2003 +++ b/arch/x86_64/kernel/pci-gart.c Wed Apr 2 22:24:05 2003 @@ -8,7 +8,7 @@ * See Documentation/DMA-mapping.txt for the interface specification. * * Copyright 2002 Andi Kleen, SuSE Labs. - * $Id: pci-gart.c,v 1.12 2002/09/19 19:25:32 ak Exp $ + * $Id: pci-gart.c,v 1.20 2003/03/12 08:23:29 ak Exp $ */ /* @@ -19,9 +19,12 @@ possible future tuning: fast path for sg streaming mappings - more intelligent flush strategy - flush only a single NB? + more intelligent flush strategy - flush only a single NB? flush only when + gart area fills up and alloc_iommu wraps. + don't flush on allocation - need to unmap the gart area first to avoid prefetches + by the CPU move boundary between IOMMU and AGP in GART dynamically - could use exact fit in the gart in alloc_consistent, not order of two. + */ #include @@ -49,7 +52,11 @@ int no_iommu; static int no_agp; +#ifdef CONFIG_IOMMU_DEBUG int force_mmu = 1; +#else +int force_mmu = 0; +#endif extern int fallback_aper_order; extern int fallback_aper_force; @@ -58,10 +65,9 @@ static spinlock_t iommu_bitmap_lock = SPIN_LOCK_UNLOCKED; static unsigned long *iommu_gart_bitmap; /* guarded by iommu_bitmap_lock */ -#define GPTE_MASK 0xfffffff000 #define GPTE_VALID 1 #define GPTE_COHERENT 2 -#define GPTE_ENCODE(x,flag) (((x) & 0xfffffff0) | ((x) >> 28) | GPTE_VALID | (flag)) +#define GPTE_ENCODE(x) (((x) & 0xfffff000) | (((x) >> 32) << 4) | GPTE_VALID | GPTE_COHERENT) #define GPTE_DECODE(x) (((x) & 0xfffff000) | (((u64)(x) & 0xff0) << 28)) #define for_all_nb(dev) \ @@ -72,7 +78,6 @@ #define EMERGENCY_PAGES 32 /* = 128KB */ #ifdef CONFIG_AGP -extern int agp_amdk8_init(void); extern int agp_init(void); #define AGPEXTERN extern #else @@ -130,7 +135,7 @@ { void *memory; int gfp = GFP_ATOMIC; - int order, i; + int i; unsigned long iommu_page; if (hwdev == NULL || hwdev->dma_mask < 0xffffffff || no_iommu) @@ -140,15 +145,15 @@ * First try to allocate continuous and use directly if already * in lowmem. */ - order = get_order(size); - memory = (void *)__get_free_pages(gfp, order); + size = round_up(size, PAGE_SIZE); + memory = (void *)__get_free_pages(gfp, get_order(size)); if (memory == NULL) { return NULL; } else { int high = (unsigned long)virt_to_bus(memory) + size >= 0xffffffff; int mmu = high; - if (force_mmu) + if (force_mmu && !(gfp & GFP_DMA)) mmu = 1; if (no_iommu) { if (high) goto error; @@ -161,19 +166,21 @@ } } - iommu_page = alloc_iommu(1<>= PAGE_SHIFT; + + iommu_page = alloc_iommu(size); if (iommu_page == -1) goto error; /* Fill in the GATT, allocating pages as needed. */ - for (i = 0; i < 1< 0) atomic_inc(&virt_to_page(mem)->count); phys_mem = virt_to_phys(mem); - BUG_ON(phys_mem & ~PTE_MASK); - iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem,GPTE_COHERENT); + BUG_ON(phys_mem & ~PHYSICAL_PAGE_MASK); + iommu_gatt_base[iommu_page + i] = GPTE_ENCODE(phys_mem); } flush_gart(); @@ -181,7 +188,7 @@ return memory; error: - free_pages((unsigned long)memory, order); + free_pages((unsigned long)memory, get_order(size)); return NULL; } @@ -193,30 +200,32 @@ void *vaddr, dma_addr_t bus) { u64 pte; - int order = get_order(size); unsigned long iommu_page; int i; + size = round_up(size, PAGE_SIZE); if (bus < iommu_bus_base || bus > iommu_bus_base + iommu_size) { - free_pages((unsigned long)vaddr, order); + free_pages((unsigned long)vaddr, get_order(size)); return; } + size >>= PAGE_SHIFT; iommu_page = (bus - iommu_bus_base) / PAGE_SIZE; - for (i = 0; i < 1<>10); return 0; @@ -530,8 +547,10 @@ off don't use the IOMMU leak turn on simple iommu leak tracing (only when CONFIG_IOMMU_LEAK is on) memaper[=order] allocate an own aperture over RAM with size 32MB^order. + noforce don't force IOMMU usage. Should be fastest. + force Force IOMMU and turn on unmap debugging. */ -__init int iommu_setup(char *opt, char **end) +__init int iommu_setup(char *opt) { int arg; char *p = opt; @@ -552,17 +571,21 @@ fallback_aper_order = arg; } #ifdef CONFIG_IOMMU_LEAK - if (!memcmp(p,"leak", 4)) + if (!memcmp(p,"leak", 4)) { leak_trace = 1; + p += 4; + if (*p == '=') ++p; + if (isdigit(*p) && get_option(&p, &arg)) + iommu_leak_pages = arg; + } else #endif if (isdigit(*p) && get_option(&p, &arg)) iommu_size = arg; do { - if (*p == ' ' || *p == 0) { - *end = p; + if (*p == ' ' || *p == 0) return 0; - } } while (*p++ != ','); } + return 1; } diff -Nru a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c --- a/arch/x86_64/kernel/process.c Wed Apr 2 22:24:05 2003 +++ b/arch/x86_64/kernel/process.c Wed Apr 2 22:24:05 2003 @@ -192,6 +192,8 @@ fs,fsindex,gs,gsindex,shadowgs); printk("CS: %04x DS: %04x ES: %04x CR0: %016lx\n", cs, ds, es, cr0); printk("CR2: %016lx CR3: %016lx CR4: %016lx\n", cr2, cr3, cr4); + + show_trace(®s->rsp); } extern void load_gs_index(unsigned); @@ -260,6 +262,14 @@ (((u32)desc->base2) << 24); } +/* + * This gets called before we allocate a new thread and copy + * the current task into it. + */ +void prepare_to_copy(struct task_struct *tsk) +{ + unlazy_fpu(tsk); +} int copy_thread(int nr, unsigned long clone_flags, unsigned long rsp, unsigned long unused, @@ -294,9 +304,6 @@ asm("movl %%es,%0" : "=m" (p->thread.es)); asm("movl %%ds,%0" : "=m" (p->thread.ds)); - unlazy_fpu(me); - p->thread.i387 = me->thread.i387; - if (unlikely(me->thread.io_bitmap_ptr != NULL)) { p->thread.io_bitmap_ptr = kmalloc((IO_BITMAP_SIZE+1)*4, GFP_KERNEL); if (!p->thread.io_bitmap_ptr) @@ -314,7 +321,7 @@ err = ia32_child_tls(p, childregs); else #endif - err = do_arch_prctl(p, ARCH_SET_FS, childregs->r10); + err = do_arch_prctl(p, ARCH_SET_FS, childregs->r8); if (err) goto out; } diff -Nru a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c --- a/arch/x86_64/kernel/ptrace.c Wed Apr 2 22:24:05 2003 +++ b/arch/x86_64/kernel/ptrace.c Wed Apr 2 22:24:05 2003 @@ -240,8 +240,8 @@ unsigned long tmp; ret = -EIO; - if ((addr & 3) || addr < 0 || - addr > sizeof(struct user) - 3) + if ((addr & 7) || addr < 0 || + addr > sizeof(struct user) - 7) break; tmp = 0; /* Default return condition */ @@ -250,7 +250,7 @@ if(addr >= (long) &dummy->u_debugreg[0] && addr <= (long) &dummy->u_debugreg[7]){ addr -= (long) &dummy->u_debugreg[0]; - addr = addr >> 2; + addr = addr >> 3; tmp = child->thread.debugreg[addr]; } ret = put_user(tmp,(unsigned long *) data); @@ -268,8 +268,8 @@ case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ ret = -EIO; - if ((addr & 3) || addr < 0 || - addr > sizeof(struct user) - 3) + if ((addr & 7) || addr < 0 || + addr > sizeof(struct user) - 7) break; if (addr < sizeof(struct user_regs_struct)) { @@ -290,6 +290,11 @@ if(addr < (long) &dummy->u_debugreg[4] && ((unsigned long) data) >= TASK_SIZE-3) break; + if (addr == (long) &dummy->u_debugreg[6]) { + if (data >> 32) + goto out_tsk; + } + if(addr == (long) &dummy->u_debugreg[7]) { data &= ~DR_CONTROL_RESERVED; for(i=0; i<4; i++) @@ -298,7 +303,7 @@ } addr -= (long) &dummy->u_debugreg; - addr = addr >> 2; + addr = addr >> 3; child->thread.debugreg[addr] = data; ret = 0; } diff -Nru a/arch/x86_64/kernel/reboot.c b/arch/x86_64/kernel/reboot.c --- a/arch/x86_64/kernel/reboot.c Wed Apr 2 22:24:07 2003 +++ b/arch/x86_64/kernel/reboot.c Wed Apr 2 22:24:07 2003 @@ -101,7 +101,6 @@ * Stop all CPUs and turn off local APICs and the IO-APIC, so * other OSs see a clean IRQ state. */ - if (notify_die(DIE_STOP,"cpustop",0,0) != NOTIFY_BAD) smp_send_stop(); disable_IO_APIC(); #endif diff -Nru a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c --- a/arch/x86_64/kernel/setup.c Wed Apr 2 22:24:04 2003 +++ b/arch/x86_64/kernel/setup.c Wed Apr 2 22:24:04 2003 @@ -197,12 +197,15 @@ if (!memcmp(from, "acpi=off", 8)) acpi_disabled = 1; + if (!memcmp(from, "disableapic", 11)) + disable_apic = 1; + if (!memcmp(from, "mem=", 4)) parse_memopt(from+4, &from); #ifdef CONFIG_GART_IOMMU if (!memcmp(from,"iommu=",6)) { - iommu_setup(from+6, &from); + iommu_setup(from+6); } #endif diff -Nru a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c --- a/arch/x86_64/kernel/setup64.c Wed Apr 2 22:24:04 2003 +++ b/arch/x86_64/kernel/setup64.c Wed Apr 2 22:24:04 2003 @@ -40,7 +40,7 @@ char boot_cpu_stack[IRQSTACKSIZE] __cacheline_aligned; unsigned long __supported_pte_mask = ~0UL; -static int do_not_nx = 0; +static int do_not_nx = 1; static int __init nonx_setup(char *str) { @@ -98,6 +98,8 @@ pda->cpudata_offset = 0; pda->kernelstack = (unsigned long)stack_thread_info() - PDA_STACKOFFSET + THREAD_SIZE; + pda->active_mm = &init_mm; + pda->mmu_state = 0; if (cpu == 0) { /* others are initialized in smpboot.c */ @@ -121,8 +123,6 @@ asm volatile("movq %0,%%cr3" :: "r" (__pa(level4))); pda->irqstackptr += IRQSTACKSIZE-64; - pda->active_mm = &init_mm; - pda->mmu_state = 0; } #define EXCEPTION_STK_ORDER 0 /* >= N_EXCEPTION_STACKS*EXCEPTION_STKSZ */ diff -Nru a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c --- a/arch/x86_64/kernel/signal.c Wed Apr 2 22:24:06 2003 +++ b/arch/x86_64/kernel/signal.c Wed Apr 2 22:24:06 2003 @@ -225,6 +225,7 @@ rsp = regs->rsp - 128; /* This is the X/Open sanctioned signal stack switching. */ + /* RED-PEN: redzone on that stack? */ if (ka->sa.sa_flags & SA_ONSTACK) { if (sas_ss_flags(rsp) == 0) rsp = current->sas_ss_sp + current->sas_ss_size; @@ -433,7 +434,8 @@ * have been cleared if the watchpoint triggered * inside the kernel. */ - __asm__("movq %0,%%db7" : : "r" (current->thread.debugreg[7])); + if (current->thread.debugreg[7]) + asm volatile("movq %0,%%db7" : : "r" (current->thread.debugreg[7])); /* Whee! Actually deliver the signal. */ handle_signal(signr, &info, oldset, regs); diff -Nru a/arch/x86_64/kernel/smp.c b/arch/x86_64/kernel/smp.c --- a/arch/x86_64/kernel/smp.c Wed Apr 2 22:24:04 2003 +++ b/arch/x86_64/kernel/smp.c Wed Apr 2 22:24:04 2003 @@ -485,16 +485,16 @@ } } - /* Slow. Should be only used for debugging. */ int slow_smp_processor_id(void) { int stack_location; unsigned long sp = (unsigned long)&stack_location; - int cpu; - unsigned long mask; + int offset = 0, cpu; + + for (offset = 0; (cpu_online_map >> offset); offset = cpu + 1) { + cpu = ffz(~(cpu_online_map >> offset)); - for_each_cpu(cpu, mask) { if (sp >= (u64)cpu_pda[cpu].irqstackptr - IRQSTACKSIZE && sp <= (u64)cpu_pda[cpu].irqstackptr) return cpu; diff -Nru a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c --- a/arch/x86_64/kernel/smpboot.c Wed Apr 2 22:24:08 2003 +++ b/arch/x86_64/kernel/smpboot.c Wed Apr 2 22:24:08 2003 @@ -318,8 +318,6 @@ */ smp_store_cpu_info(cpuid); - notify_die(DIE_CPUINIT, "cpuinit", NULL, 0); - local_irq_disable(); /* @@ -898,6 +896,8 @@ */ if (!skip_ioapic_setup && nr_ioapics) setup_IO_APIC(); + else + nr_ioapics = 0; setup_boot_APIC_clock(); diff -Nru a/arch/x86_64/kernel/suspend.c b/arch/x86_64/kernel/suspend.c --- a/arch/x86_64/kernel/suspend.c Wed Apr 2 22:24:05 2003 +++ b/arch/x86_64/kernel/suspend.c Wed Apr 2 22:24:05 2003 @@ -28,7 +28,7 @@ #include #include -static struct saved_context saved_context; +struct saved_context saved_context; unsigned long saved_context_eax, saved_context_ebx, saved_context_ecx, saved_context_edx; unsigned long saved_context_esp, saved_context_ebp, saved_context_esi, saved_context_edi; diff -Nru a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c --- a/arch/x86_64/kernel/traps.c Wed Apr 2 22:24:04 2003 +++ b/arch/x86_64/kernel/traps.c Wed Apr 2 22:24:04 2003 @@ -110,7 +110,7 @@ } #endif -static inline unsigned long *in_exception_stack(int cpu, unsigned long stack) +unsigned long *in_exception_stack(int cpu, unsigned long stack) { int k; for (k = 0; k < N_EXCEPTION_STACKS; k++) { @@ -249,7 +249,7 @@ void dump_stack(void) { unsigned long dummy; - show_stack(&dummy); + show_trace(&dummy); } void show_registers(struct pt_regs *regs) @@ -344,7 +344,6 @@ show_registers(regs); bust_spinlocks(0); spin_unlock_irq(&die_lock); - notify_die(DIE_OOPS, (char *)str, regs, err); do_exit(SIGSEGV); } @@ -419,6 +418,8 @@ #define DO_ERROR(trapnr, signr, str, name) \ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ { \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) == NOTIFY_BAD) \ + return; \ do_trap(trapnr, signr, str, regs, error_code, NULL); \ } @@ -430,10 +431,13 @@ info.si_errno = 0; \ info.si_code = sicode; \ info.si_addr = (void *)siaddr; \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) == NOTIFY_BAD) \ + return; \ do_trap(trapnr, signr, str, regs, error_code, &info); \ } DO_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->rip) +DO_ERROR( 3, SIGTRAP, "int3", int3); DO_ERROR( 4, SIGSEGV, "overflow", overflow) DO_ERROR( 5, SIGSEGV, "bounds", bounds) DO_ERROR_INFO( 6, SIGILL, "invalid operand", invalid_op, ILL_ILLOPN, regs->rip) @@ -446,13 +450,6 @@ DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, get_cr2()) DO_ERROR(18, SIGSEGV, "reserved", reserved) -asmlinkage void do_int3(struct pt_regs * regs, long error_code) -{ - if (notify_die(DIE_INT3, "int3", regs, error_code) == NOTIFY_BAD) - return; - do_trap(3, SIGTRAP, "int3", regs, error_code, NULL); -} - extern void dump_pagetable(unsigned long); asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) @@ -493,6 +490,8 @@ regs->rip = fixup->fixup; return; } + notify_die(DIE_GPF, "general protection fault", regs, error_code, + 13, SIGSEGV); die("general protection fault", regs, error_code); } } @@ -537,14 +536,14 @@ * so it must be the NMI watchdog. */ if (nmi_watchdog) { - nmi_watchdog_tick(regs); + nmi_watchdog_tick(regs,reason); return; } #endif unknown_nmi_error(reason, regs); return; } - if (notify_die(DIE_NMI, "nmi", regs, reason) == NOTIFY_BAD) + if (notify_die(DIE_NMI, "nmi", regs, reason, 0, SIGINT) == NOTIFY_BAD) return; if (reason & 0x80) mem_parity_error(reason, regs); @@ -569,6 +568,7 @@ #ifdef CONFIG_CHECKING { + /* RED-PEN interaction with debugger - could destroy gs */ unsigned long gs; struct x8664_pda *pda = cpu_pda + safe_smp_processor_id(); rdmsrl(MSR_GS_BASE, gs); @@ -583,9 +583,6 @@ conditional_sti(regs); - if (notify_die(DIE_DEBUG, "debug", regs, error_code) == NOTIFY_BAD) - return; - /* Mask out spurious debug traps due to lazy DR7 setting */ if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { if (!tsk->thread.debugreg[7]) { @@ -618,17 +615,22 @@ info.si_signo = SIGTRAP; info.si_errno = 0; info.si_code = TRAP_BRKPT; - info.si_addr = ((regs->cs & 3) == 0) ? (void *)tsk->thread.rip : - (void *)regs->rip; + if ((regs->cs & 3) == 0) + goto clear_dr7; + + info.si_addr = (void *)regs->rip; force_sig_info(SIGTRAP, &info, tsk); clear_dr7: - asm("movq %0,%%db7"::"r"(0UL)); + asm volatile("movq %0,%%db7"::"r"(0UL)); + notify_die(DIE_DEBUG, "debug", regs, error_code, 1, SIGTRAP); return; clear_TF_reenable: set_tsk_thread_flag(tsk, TIF_SINGLESTEP); clear_TF: + /* RED-PEN could cause spurious errors */ + if (notify_die(DIE_DEBUG, "debug2", regs, error_code, 1, SIGTRAP) != NOTIFY_BAD) regs->eflags &= ~TF_MASK; return; } @@ -775,9 +777,9 @@ clts(); /* Allow maths ops (or we recurse) */ if (!me->used_math) - init_fpu(); + init_fpu(me); restore_fpu_checking(&me->thread.i387.fxsave); - set_thread_flag(TIF_USEDFPU); + me->thread_info->status |= TS_USEDFPU; } asmlinkage void math_emulate(void) @@ -787,7 +789,7 @@ void do_call_debug(struct pt_regs *regs) { - notify_die(DIE_CALL, "debug call", regs, 0); + notify_die(DIE_CALL, "debug call", regs, 0, 255, SIGINT); } void __init trap_init(void) @@ -819,8 +821,6 @@ set_intr_gate(KDB_VECTOR, call_debug); - notify_die(DIE_TRAPINIT, "traps initialized", 0, 0); - /* * Should be a barrier for any external CPU state. */ diff -Nru a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c --- a/arch/x86_64/mm/fault.c Wed Apr 2 22:24:04 2003 +++ b/arch/x86_64/mm/fault.c Wed Apr 2 22:24:04 2003 @@ -57,29 +57,41 @@ } } +static int bad_address(void *p) +{ + unsigned long dummy; + return __get_user(dummy, (unsigned long *)p); +} + void dump_pagetable(unsigned long address) { - static char *name[] = { "PML4", "PGD", "PDE", "PTE" }; - int i, shift; - unsigned long page; + pml4_t *pml4; + asm("movq %%cr3,%0" : "=r" (pml4)); + + pml4 = __va((unsigned long)pml4 & PHYSICAL_PAGE_MASK); + pml4 += pml4_index(address); + printk("PML4 %lx ", pml4_val(*pml4)); + if (bad_address(pml4)) goto bad; + if (!pml4_present(*pml4)) goto ret; + + pgd_t *pgd = __pgd_offset_k((pgd_t *)pml4_page(*pml4), address); + if (bad_address(pgd)) goto bad; + printk("PGD %lx ", pgd_val(*pgd)); + if (!pgd_present(*pgd)) goto ret; + + pmd_t *pmd = pmd_offset(pgd, address); + if (bad_address(pmd)) goto bad; + printk("PMD %lx ", pmd_val(*pmd)); + if (!pmd_present(*pmd)) goto ret; - shift = 9+9+9+12; - address &= ~0xFFFF000000000000UL; - asm("movq %%cr3,%0" : "=r" (page)); - for (i = 0; i < 4; i++) { - unsigned long *padr = (unsigned long *) __va(page); - padr += (address >> shift) & 0x1FFU; - if (__get_user(page, padr)) { - printk("%s: bad %p\n", name[i], padr); - break; - } - printk("%s: %016lx ", name[i], page); - if ((page & (1 | (1<<7))) != 1) /* Not present or 2MB page */ - break; - page &= ~0xFFFUL; - shift -= (i == 0) ? 12 : 9; - } + pte_t *pte = pte_offset_kernel(pmd, address); + if (bad_address(pte)) goto bad; + printk("PTE %lx", pte_val(*pte)); +ret: printk("\n"); + return; +bad: + printk("BAD\n"); } int page_fault_trace; diff -Nru a/arch/x86_64/mm/ioremap.c b/arch/x86_64/mm/ioremap.c --- a/arch/x86_64/mm/ioremap.c Wed Apr 2 22:24:07 2003 +++ b/arch/x86_64/mm/ioremap.c Wed Apr 2 22:24:07 2003 @@ -150,7 +150,7 @@ */ offset = phys_addr & ~PAGE_MASK; phys_addr &= PAGE_MASK; - size = PAGE_ALIGN(last_addr) - phys_addr; + size = PAGE_ALIGN(last_addr+1) - phys_addr; /* * Ok, go for it.. diff -Nru a/arch/x86_64/mm/k8topology.c b/arch/x86_64/mm/k8topology.c --- a/arch/x86_64/mm/k8topology.c Wed Apr 2 22:24:07 2003 +++ b/arch/x86_64/mm/k8topology.c Wed Apr 2 22:24:07 2003 @@ -21,7 +21,7 @@ #include #include -static int find_northbridge(void) +static __init int find_northbridge(void) { int num; @@ -45,7 +45,8 @@ { unsigned long prevbase; struct node nodes[MAXNODE]; - int nodeid, numnodes, maxnode, i, nb; + int nodeid, i, nb; + int found = 0; nb = find_northbridge(); if (nb < 0) @@ -53,12 +54,13 @@ printk(KERN_INFO "Scanning NUMA topology in Northbridge %d\n", nb); - numnodes = (read_pci_config(0, nb, 0, 0x60 ) >> 4) & 3; + numnodes = (1 << ((read_pci_config(0, nb, 0, 0x60 ) >> 4) & 3)); + + printk(KERN_INFO "Assuming %d nodes\n", numnodes - 1); memset(&nodes,0,sizeof(nodes)); prevbase = 0; - maxnode = -1; - for (i = 0; i < MAXNODE; i++) { + for (i = 0; i < numnodes; i++) { unsigned long base,limit; base = read_pci_config(0, nb, 1, 0x40 + i*8); @@ -66,18 +68,16 @@ nodeid = limit & 3; if (!limit) { - printk(KERN_INFO "Skipping node entry %d (base %lx)\n", i, base); - continue; + printk(KERN_ERR "Skipping node entry %d (base %lx)\n", i, base); + return -1; } if ((base >> 8) & 3 || (limit >> 8) & 3) { printk(KERN_ERR "Node %d using interleaving mode %lx/%lx\n", nodeid, (base>>8)&3, (limit>>8) & 3); return -1; } - if (nodeid > maxnode) - maxnode = nodeid; if ((1UL << nodeid) & nodes_present) { - printk("Node %d already present. Skipping\n", nodeid); + printk(KERN_INFO "Node %d already present. Skipping\n", nodeid); continue; } @@ -98,17 +98,19 @@ base = start; if (limit > end) limit = end; - if (limit == base) + if (limit == base) { + printk(KERN_ERR "Empty node %d\n", nodeid); continue; + } if (limit < base) { - printk(KERN_INFO"Node %d bogus settings %lx-%lx. Ignored.\n", + printk(KERN_ERR "Node %d bogus settings %lx-%lx.\n", nodeid, base, limit); - continue; + return -1; } /* Could sort here, but pun for now. Should not happen anyroads. */ if (prevbase > base) { - printk(KERN_INFO "Node map not sorted %lx,%lx\n", + printk(KERN_ERR "Node map not sorted %lx,%lx\n", prevbase,base); return -1; } @@ -116,23 +118,26 @@ printk(KERN_INFO "Node %d MemBase %016lx Limit %016lx\n", nodeid, base, limit); + found++; + nodes[nodeid].start = base; nodes[nodeid].end = limit; prevbase = base; } - if (maxnode <= 0) + if (!found) return -1; - memnode_shift = compute_hash_shift(nodes,maxnode,end); + memnode_shift = compute_hash_shift(nodes); if (memnode_shift < 0) { printk(KERN_ERR "No NUMA node hash function found. Contact maintainer\n"); return -1; } printk(KERN_INFO "Using node hash shift of %d\n", memnode_shift); - early_for_all_nodes(i) { + for (i = 0; i < numnodes; i++) { + if (nodes[i].start != nodes[i].end) setup_node_bootmem(i, nodes[i].start, nodes[i].end); } diff -Nru a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c --- a/arch/x86_64/mm/numa.c Wed Apr 2 22:24:07 2003 +++ b/arch/x86_64/mm/numa.c Wed Apr 2 22:24:07 2003 @@ -26,11 +26,10 @@ static int numa_off __initdata; unsigned long nodes_present; -int maxnode; static int emunodes __initdata; -int compute_hash_shift(struct node *nodes, int numnodes, u64 maxmem) +int __init compute_hash_shift(struct node *nodes) { int i; int shift = 24; @@ -39,12 +38,16 @@ /* When in doubt use brute force. */ while (shift < 48) { memset(memnodemap,0xff,sizeof(*memnodemap) * NODEMAPSIZE); - early_for_all_nodes (i) { + for (i = 0; i < numnodes; i++) { + if (nodes[i].start == nodes[i].end) + continue; for (addr = nodes[i].start; addr < nodes[i].end; addr += (1UL << shift)) { - if (memnodemap[addr >> shift] != 0xff) { - printk("node %d shift %d addr %Lx conflict %d\n", + if (memnodemap[addr >> shift] != 0xff && + memnodemap[addr >> shift] != i) { + printk(KERN_INFO + "node %d shift %d addr %Lx conflict %d\n", i, shift, addr, memnodemap[addr>>shift]); goto next; } @@ -101,9 +104,8 @@ reserve_bootmem_node(NODE_DATA(nodeid), nodedata_phys, pgdat_size); reserve_bootmem_node(NODE_DATA(nodeid), bootmap_start, bootmap_pages< maxnode) - maxnode = nodeid; + if (nodeid + 1 > numnodes) + numnodes = nodeid + 1; nodes_present |= (1UL << nodeid); } @@ -151,6 +153,7 @@ int i; if (emunodes > MAXNODE) emunodes = MAXNODE; + memset(&nodes, 0, sizeof(nodes)); printk(KERN_INFO "Faking %d nodes of size %ld MB\n", emunodes, nodesize>>20); for (i = 0; i < emunodes; i++) { unsigned long end = (i+1)*nodesize; @@ -160,7 +163,7 @@ nodes[i].end = end; setup_node_bootmem(i, nodes[i].start, nodes[i].end); } - memnode_shift = compute_hash_shift(nodes, emunodes, nodes[i-1].end); + memnode_shift = compute_hash_shift(nodes); return 0; } diff -Nru a/arch/x86_64/pci/irq.c b/arch/x86_64/pci/irq.c --- a/arch/x86_64/pci/irq.c Wed Apr 2 22:24:06 2003 +++ b/arch/x86_64/pci/irq.c Wed Apr 2 22:24:06 2003 @@ -618,11 +618,20 @@ int pirq_enable_irq(struct pci_dev *dev) { u8 pin; + extern int interrupt_line_quirk; pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); if (pin && !pcibios_lookup_irq(dev, 1) && !dev->irq) { + /* With IDE legacy devices the IRQ lookup failure is not a problem.. */ + if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE && !(dev->class & 0x5)) + return 0; + printk(KERN_WARNING "PCI: No IRQ known for interrupt pin %c of device %s.\n", 'A' + pin - 1, dev->slot_name); } + /* VIA bridges use interrupt line for apic/pci steering across + the V-Link */ + else if (interrupt_line_quirk) + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); return 0; } diff -Nru a/crypto/Kconfig b/crypto/Kconfig --- a/crypto/Kconfig Wed Apr 2 22:24:07 2003 +++ b/crypto/Kconfig Wed Apr 2 22:24:07 2003 @@ -131,6 +131,16 @@ See http://csrc.nist.gov/encryption/aes/ for more information. +config CRYPTO_DEFLATE + tristate "Deflate compression algorithm" + depends on CRYPTO + default y if INET_IPCOMP=y || INET_IPCOMP=m + help + This is the Deflate algorithm (RFC1951), specified for use in + IPSec with the IPCOMP protocol (RFC3173, RFC2394). + + You will most probably want this if using IPSec. + config CRYPTO_TEST tristate "Testing module" depends on CRYPTO diff -Nru a/crypto/Makefile b/crypto/Makefile --- a/crypto/Makefile Wed Apr 2 22:24:07 2003 +++ b/crypto/Makefile Wed Apr 2 22:24:07 2003 @@ -20,5 +20,6 @@ obj-$(CONFIG_CRYPTO_TWOFISH) += twofish.o obj-$(CONFIG_CRYPTO_SERPENT) += serpent.o obj-$(CONFIG_CRYPTO_AES) += aes.o +obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o diff -Nru a/crypto/api.c b/crypto/api.c --- a/crypto/api.c Wed Apr 2 22:24:07 2003 +++ b/crypto/api.c Wed Apr 2 22:24:07 2003 @@ -127,7 +127,7 @@ if (tfm == NULL) goto out_put; - memset(tfm, 0, sizeof(*tfm)); + memset(tfm, 0, sizeof(*tfm) + alg->cra_ctxsize); tfm->__crt_alg = alg; diff -Nru a/crypto/compress.c b/crypto/compress.c --- a/crypto/compress.c Wed Apr 2 22:24:05 2003 +++ b/crypto/compress.c Wed Apr 2 22:24:05 2003 @@ -18,29 +18,46 @@ #include #include "internal.h" -static void crypto_compress(struct crypto_tfm *tfm) +static int crypto_compress(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) { - tfm->__crt_alg->cra_compress.coa_compress(); + return tfm->__crt_alg->cra_compress.coa_compress(crypto_tfm_ctx(tfm), + src, slen, dst, + dlen); } -static void crypto_decompress(struct crypto_tfm *tfm) +static int crypto_decompress(struct crypto_tfm *tfm, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) { - tfm->__crt_alg->cra_compress.coa_decompress(); + return tfm->__crt_alg->cra_compress.coa_decompress(crypto_tfm_ctx(tfm), + src, slen, dst, + dlen); } int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags) { - return crypto_cipher_flags(flags) ? -EINVAL : 0; + return flags ? -EINVAL : 0; } int crypto_init_compress_ops(struct crypto_tfm *tfm) { + int ret = 0; struct compress_tfm *ops = &tfm->crt_compress; + ret = tfm->__crt_alg->cra_compress.coa_init(crypto_tfm_ctx(tfm)); + if (ret) + goto out; + ops->cot_compress = crypto_compress; ops->cot_decompress = crypto_decompress; - return 0; + +out: + return ret; } void crypto_exit_compress_ops(struct crypto_tfm *tfm) -{ } +{ + tfm->__crt_alg->cra_compress.coa_exit(crypto_tfm_ctx(tfm)); +} diff -Nru a/crypto/crypto_null.c b/crypto/crypto_null.c --- a/crypto/crypto_null.c Wed Apr 2 22:24:05 2003 +++ b/crypto/crypto_null.c Wed Apr 2 22:24:05 2003 @@ -26,11 +26,13 @@ #define NULL_BLOCK_SIZE 1 #define NULL_DIGEST_SIZE 0 -static void null_compress(void) -{ } +static int null_compress(void *ctx, const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ return 0; } -static void null_decompress(void) -{ } +static int null_decompress(void *ctx, const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ return 0; } static void null_init(void *ctx) { } diff -Nru a/crypto/deflate.c b/crypto/deflate.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/crypto/deflate.c Wed Apr 2 22:24:08 2003 @@ -0,0 +1,224 @@ +/* + * Cryptographic API. + * + * Deflate algorithm (RFC 1951), implemented here primarily for use + * by IPCOMP (RFC 3173 & RFC 2394). + * + * Copyright (c) 2003 James Morris + * + * 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. + * + * FIXME: deflate transforms will require up to a total of about 436k of kernel + * memory on i386 (390k for compression, the rest for decompression), as the + * current zlib kernel code uses a worst case pre-allocation system by default. + * This needs to be fixed so that the amount of memory required is properly + * related to the winbits and memlevel parameters. + * + * The default winbits of 11 should suit most packets, and it may be something + * to configure on a per-tfm basis in the future. + * + * Currently, compression history is not maintained between tfm calls, as + * it is not needed for IPCOMP and keeps the code simpler. It can be + * implemented if someone wants it. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFLATE_DEF_LEVEL Z_DEFAULT_COMPRESSION +#define DEFLATE_DEF_WINBITS 11 +#define DEFLATE_DEF_MEMLEVEL MAX_MEM_LEVEL + +struct deflate_ctx { + int comp_initialized; + int decomp_initialized; + struct z_stream_s comp_stream; + struct z_stream_s decomp_stream; +}; + +static inline int deflate_gfp(void) +{ + return in_softirq() ? GFP_ATOMIC : GFP_KERNEL; +} + +static int deflate_init(void *ctx) +{ + return 0; +} + +static void deflate_exit(void *ctx) +{ + struct deflate_ctx *dctx = ctx; + + if (dctx->comp_initialized) + vfree(dctx->comp_stream.workspace); + if (dctx->decomp_initialized) + kfree(dctx->decomp_stream.workspace); +} + +/* + * Lazy initialization to make interface simple without allocating + * un-needed workspaces. Thus can be called in softirq context. + */ +static int deflate_comp_init(struct deflate_ctx *ctx) +{ + int ret = 0; + struct z_stream_s *stream = &ctx->comp_stream; + + stream->workspace = __vmalloc(zlib_deflate_workspacesize(), + deflate_gfp()|__GFP_HIGHMEM, + PAGE_KERNEL); + if (!stream->workspace ) { + ret = -ENOMEM; + goto out; + } + memset(stream->workspace, 0, sizeof(stream->workspace)); + ret = zlib_deflateInit2(stream, DEFLATE_DEF_LEVEL, Z_DEFLATED, + -DEFLATE_DEF_WINBITS, DEFLATE_DEF_MEMLEVEL, + Z_DEFAULT_STRATEGY); + if (ret != Z_OK) { + ret = -EINVAL; + goto out_free; + } + ctx->comp_initialized = 1; +out: + return ret; +out_free: + vfree(stream->workspace); + goto out; +} + +static int deflate_decomp_init(struct deflate_ctx *ctx) +{ + int ret = 0; + struct z_stream_s *stream = &ctx->decomp_stream; + + stream->workspace = kmalloc(zlib_inflate_workspacesize(), + deflate_gfp()); + if (!stream->workspace ) { + ret = -ENOMEM; + goto out; + } + memset(stream->workspace, 0, sizeof(stream->workspace)); + ret = zlib_inflateInit2(stream, -DEFLATE_DEF_WINBITS); + if (ret != Z_OK) { + ret = -EINVAL; + goto out_free; + } + ctx->decomp_initialized = 1; +out: + return ret; +out_free: + kfree(stream->workspace); + goto out; +} + +static int deflate_compress(void *ctx, const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ + int ret = 0; + struct deflate_ctx *dctx = ctx; + struct z_stream_s *stream = &dctx->comp_stream; + + if (!dctx->comp_initialized) { + ret = deflate_comp_init(dctx); + if (ret) + goto out; + } + + ret = zlib_deflateReset(stream); + if (ret != Z_OK) { + ret = -EINVAL; + goto out; + } + + stream->next_in = (u8 *)src; + stream->avail_in = slen; + stream->next_out = (u8 *)dst; + stream->avail_out = *dlen; + + ret = zlib_deflate(stream, Z_FINISH); + if (ret != Z_STREAM_END) { + ret = -EINVAL; + goto out; + } + ret = 0; + *dlen = stream->total_out; +out: + return ret; +} + +static int deflate_decompress(void *ctx, const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) +{ + + int ret = 0; + struct deflate_ctx *dctx = ctx; + struct z_stream_s *stream = &dctx->decomp_stream; + + if (!dctx->decomp_initialized) { + ret = deflate_decomp_init(dctx); + if (ret) + goto out; + } + + ret = zlib_inflateReset(stream); + if (ret != Z_OK) { + ret = -EINVAL; + goto out; + } + + stream->next_in = (u8 *)src; + stream->avail_in = slen; + stream->next_out = (u8 *)dst; + stream->avail_out = *dlen; + + ret = zlib_inflate(stream, Z_FINISH); + if (ret != Z_STREAM_END) { + ret = -EINVAL; + goto out; + } + ret = 0; + *dlen = stream->total_out; +out: + return ret; +} + +static struct crypto_alg alg = { + .cra_name = "deflate", + .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, + .cra_ctxsize = sizeof(struct deflate_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(alg.cra_list), + .cra_u = { .compress = { + .coa_init = deflate_init, + .coa_exit = deflate_exit, + .coa_compress = deflate_compress, + .coa_decompress = deflate_decompress } } +}; + +static int __init init(void) +{ + return crypto_register_alg(&alg); +} + +static void __exit fini(void) +{ + crypto_unregister_alg(&alg); +} + +module_init(init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Deflate Compression Algorithm for IPCOMP"); +MODULE_AUTHOR("James Morris "); + diff -Nru a/crypto/digest.c b/crypto/digest.c --- a/crypto/digest.c Wed Apr 2 22:24:04 2003 +++ b/crypto/digest.c Wed Apr 2 22:24:04 2003 @@ -61,7 +61,7 @@ int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags) { - return crypto_cipher_flags(flags) ? -EINVAL : 0; + return flags ? -EINVAL : 0; } int crypto_init_digest_ops(struct crypto_tfm *tfm) diff -Nru a/crypto/internal.h b/crypto/internal.h --- a/crypto/internal.h Wed Apr 2 22:24:04 2003 +++ b/crypto/internal.h Wed Apr 2 22:24:04 2003 @@ -13,9 +13,9 @@ #define _CRYPTO_INTERNAL_H #include #include +#include #include #include -#include #include extern enum km_type crypto_km_types[]; @@ -39,11 +39,6 @@ { if (!in_softirq()) cond_resched(); -} - -static inline u32 crypto_cipher_flags(u32 flags) -{ - return flags & (CRYPTO_TFM_MODE_MASK|CRYPTO_TFM_REQ_WEAK_KEY); } static inline void *crypto_tfm_ctx(struct crypto_tfm *tfm) diff -Nru a/crypto/proc.c b/crypto/proc.c --- a/crypto/proc.c Wed Apr 2 22:24:04 2003 +++ b/crypto/proc.c Wed Apr 2 22:24:04 2003 @@ -54,10 +54,10 @@ seq_printf(m, "name : %s\n", alg->cra_name); seq_printf(m, "module : %s\n", module_name(alg->cra_module)); - seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) { case CRYPTO_ALG_TYPE_CIPHER: + seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); seq_printf(m, "min keysize : %u\n", alg->cra_cipher.cia_min_keysize); seq_printf(m, "max keysize : %u\n", @@ -67,6 +67,7 @@ break; case CRYPTO_ALG_TYPE_DIGEST: + seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); seq_printf(m, "digestsize : %u\n", alg->cra_digest.dia_digestsize); break; diff -Nru a/crypto/tcrypt.c b/crypto/tcrypt.c --- a/crypto/tcrypt.c Wed Apr 2 22:24:07 2003 +++ b/crypto/tcrypt.c Wed Apr 2 22:24:07 2003 @@ -48,7 +48,7 @@ static char *check[] = { "des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish", - "twofish", "serpent", "sha384", "sha512", "md4", "aes", + "twofish", "serpent", "sha384", "sha512", "md4", "aes", "deflate", NULL }; @@ -2193,6 +2193,86 @@ } static void +test_deflate(void) +{ + unsigned int i; + char result[COMP_BUF_SIZE]; + struct crypto_tfm *tfm; + struct comp_testvec *tv; + unsigned int tsize; + + printk("\ntesting deflate compression\n"); + + tsize = sizeof (deflate_comp_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + return; + } + + memcpy(tvmem, deflate_comp_tv_template, tsize); + tv = (void *) tvmem; + + tfm = crypto_alloc_tfm("deflate", 0); + if (tfm == NULL) { + printk("failed to load transform for deflate\n"); + return; + } + + for (i = 0; i < DEFLATE_COMP_TEST_VECTORS; i++) { + int ilen, ret, dlen = COMP_BUF_SIZE; + + printk("test %u:\n", i + 1); + memset(result, 0, sizeof (result)); + + ilen = tv[i].inlen; + ret = crypto_comp_compress(tfm, tv[i].input, + ilen, result, &dlen); + if (ret) { + printk("fail: ret=%d\n", ret); + continue; + } + hexdump(result, dlen); + printk("%s (ratio %d:%d)\n", + memcmp(result, tv[i].output, dlen) ? "fail" : "pass", + ilen, dlen); + } + + printk("\ntesting deflate decompression\n"); + + tsize = sizeof (deflate_decomp_tv_template); + if (tsize > TVMEMSIZE) { + printk("template (%u) too big for tvmem (%u)\n", tsize, + TVMEMSIZE); + goto out; + } + + memcpy(tvmem, deflate_decomp_tv_template, tsize); + tv = (void *) tvmem; + + for (i = 0; i < DEFLATE_DECOMP_TEST_VECTORS; i++) { + int ilen, ret, dlen = COMP_BUF_SIZE; + + printk("test %u:\n", i + 1); + memset(result, 0, sizeof (result)); + + ilen = tv[i].inlen; + ret = crypto_comp_decompress(tfm, tv[i].input, + ilen, result, &dlen); + if (ret) { + printk("fail: ret=%d\n", ret); + continue; + } + hexdump(result, dlen); + printk("%s (ratio %d:%d)\n", + memcmp(result, tv[i].output, dlen) ? "fail" : "pass", + ilen, dlen); + } +out: + crypto_free_tfm(tfm); +} + +static void test_available(void) { char **name = check; @@ -2223,6 +2303,7 @@ test_aes(); test_sha384(); test_sha512(); + test_deflate(); #ifdef CONFIG_CRYPTO_HMAC test_hmac_md5(); test_hmac_sha1(); @@ -2276,6 +2357,10 @@ case 12: test_sha512(); + break; + + case 13: + test_deflate(); break; #ifdef CONFIG_CRYPTO_HMAC diff -Nru a/crypto/tcrypt.h b/crypto/tcrypt.h --- a/crypto/tcrypt.h Wed Apr 2 22:24:07 2003 +++ b/crypto/tcrypt.h Wed Apr 2 22:24:07 2003 @@ -1682,4 +1682,104 @@ }, }; +/* + * Compression stuff. + */ +#define COMP_BUF_SIZE 512 + +struct comp_testvec { + int inlen, outlen; + char input[COMP_BUF_SIZE]; + char output[COMP_BUF_SIZE]; +}; + +/* + * Deflate test vectors (null-terminated strings). + * Params: winbits=11, Z_DEFAULT_COMPRESSION, MAX_MEM_LEVEL. + */ +#define DEFLATE_COMP_TEST_VECTORS 2 +#define DEFLATE_DECOMP_TEST_VECTORS 2 + +struct comp_testvec deflate_comp_tv_template[] = { + { + 70, 38, + + "Join us now and share the software " + "Join us now and share the software ", + + { 0xf3, 0xca, 0xcf, 0xcc, 0x53, 0x28, 0x2d, 0x56, + 0xc8, 0xcb, 0x2f, 0x57, 0x48, 0xcc, 0x4b, 0x51, + 0x28, 0xce, 0x48, 0x2c, 0x4a, 0x55, 0x28, 0xc9, + 0x48, 0x55, 0x28, 0xce, 0x4f, 0x2b, 0x29, 0x07, + 0x71, 0xbc, 0x08, 0x2b, 0x01, 0x00 + }, + }, + + { + 191, 122, + + "This document describes a compression method based on the DEFLATE" + "compression algorithm. This document defines the application of " + "the DEFLATE algorithm to the IP Payload Compression Protocol.", + + { 0x5d, 0x8d, 0x31, 0x0e, 0xc2, 0x30, 0x10, 0x04, + 0xbf, 0xb2, 0x2f, 0xc8, 0x1f, 0x10, 0x04, 0x09, + 0x89, 0xc2, 0x85, 0x3f, 0x70, 0xb1, 0x2f, 0xf8, + 0x24, 0xdb, 0x67, 0xd9, 0x47, 0xc1, 0xef, 0x49, + 0x68, 0x12, 0x51, 0xae, 0x76, 0x67, 0xd6, 0x27, + 0x19, 0x88, 0x1a, 0xde, 0x85, 0xab, 0x21, 0xf2, + 0x08, 0x5d, 0x16, 0x1e, 0x20, 0x04, 0x2d, 0xad, + 0xf3, 0x18, 0xa2, 0x15, 0x85, 0x2d, 0x69, 0xc4, + 0x42, 0x83, 0x23, 0xb6, 0x6c, 0x89, 0x71, 0x9b, + 0xef, 0xcf, 0x8b, 0x9f, 0xcf, 0x33, 0xca, 0x2f, + 0xed, 0x62, 0xa9, 0x4c, 0x80, 0xff, 0x13, 0xaf, + 0x52, 0x37, 0xed, 0x0e, 0x52, 0x6b, 0x59, 0x02, + 0xd9, 0x4e, 0xe8, 0x7a, 0x76, 0x1d, 0x02, 0x98, + 0xfe, 0x8a, 0x87, 0x83, 0xa3, 0x4f, 0x56, 0x8a, + 0xb8, 0x9e, 0x8e, 0x5c, 0x57, 0xd3, 0xa0, 0x79, + 0xfa, 0x02 }, + }, +}; + +struct comp_testvec deflate_decomp_tv_template[] = { + { + 122, 191, + + { 0x5d, 0x8d, 0x31, 0x0e, 0xc2, 0x30, 0x10, 0x04, + 0xbf, 0xb2, 0x2f, 0xc8, 0x1f, 0x10, 0x04, 0x09, + 0x89, 0xc2, 0x85, 0x3f, 0x70, 0xb1, 0x2f, 0xf8, + 0x24, 0xdb, 0x67, 0xd9, 0x47, 0xc1, 0xef, 0x49, + 0x68, 0x12, 0x51, 0xae, 0x76, 0x67, 0xd6, 0x27, + 0x19, 0x88, 0x1a, 0xde, 0x85, 0xab, 0x21, 0xf2, + 0x08, 0x5d, 0x16, 0x1e, 0x20, 0x04, 0x2d, 0xad, + 0xf3, 0x18, 0xa2, 0x15, 0x85, 0x2d, 0x69, 0xc4, + 0x42, 0x83, 0x23, 0xb6, 0x6c, 0x89, 0x71, 0x9b, + 0xef, 0xcf, 0x8b, 0x9f, 0xcf, 0x33, 0xca, 0x2f, + 0xed, 0x62, 0xa9, 0x4c, 0x80, 0xff, 0x13, 0xaf, + 0x52, 0x37, 0xed, 0x0e, 0x52, 0x6b, 0x59, 0x02, + 0xd9, 0x4e, 0xe8, 0x7a, 0x76, 0x1d, 0x02, 0x98, + 0xfe, 0x8a, 0x87, 0x83, 0xa3, 0x4f, 0x56, 0x8a, + 0xb8, 0x9e, 0x8e, 0x5c, 0x57, 0xd3, 0xa0, 0x79, + 0xfa, 0x02 }, + + "This document describes a compression method based on the DEFLATE" + "compression algorithm. This document defines the application of " + "the DEFLATE algorithm to the IP Payload Compression Protocol.", + }, + + { + 38, 70, + + { 0xf3, 0xca, 0xcf, 0xcc, 0x53, 0x28, 0x2d, 0x56, + 0xc8, 0xcb, 0x2f, 0x57, 0x48, 0xcc, 0x4b, 0x51, + 0x28, 0xce, 0x48, 0x2c, 0x4a, 0x55, 0x28, 0xc9, + 0x48, 0x55, 0x28, 0xce, 0x4f, 0x2b, 0x29, 0x07, + 0x71, 0xbc, 0x08, 0x2b, 0x01, 0x00 + }, + + "Join us now and share the software " + "Join us now and share the software ", + }, +}; + #endif /* _CRYPTO_TCRYPT_H */ diff -Nru a/drivers/acorn/char/i2c.c b/drivers/acorn/char/i2c.c --- a/drivers/acorn/char/i2c.c Wed Apr 2 22:24:08 2003 +++ b/drivers/acorn/char/i2c.c Wed Apr 2 22:24:08 2003 @@ -303,11 +303,13 @@ } static struct i2c_adapter ioc_ops = { - .name = "IOC/IOMD", .id = I2C_HW_B_IOC, .algo_data = &ioc_data, .client_register = ioc_client_reg, .client_unregister = ioc_client_unreg + .dev = { + .name = "IOC/IOMD", + }, }; static int __init i2c_ioc_init(void) diff -Nru a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig --- a/drivers/acpi/Kconfig Wed Apr 2 22:24:07 2003 +++ b/drivers/acpi/Kconfig Wed Apr 2 22:24:07 2003 @@ -132,7 +132,7 @@ may be damaged without it. config ACPI_NUMA - bool "NUMA support" if NUMA && (IA64 && !IA64_HP_SIM || X86 && ACPI && !ACPI_HT_ONLY) + bool "NUMA support" if NUMA && (IA64 && !IA64_HP_SIM || X86 && ACPI && !ACPI_HT_ONLY && !X86_64) default y if IA64 && IA64_SGI_SN config ACPI_TOSHIBA diff -Nru a/drivers/acpi/acpi_ksyms.c b/drivers/acpi/acpi_ksyms.c --- a/drivers/acpi/acpi_ksyms.c Wed Apr 2 22:24:05 2003 +++ b/drivers/acpi/acpi_ksyms.c Wed Apr 2 22:24:05 2003 @@ -74,6 +74,8 @@ EXPORT_SYMBOL(acpi_remove_fixed_event_handler); EXPORT_SYMBOL(acpi_acquire_global_lock); EXPORT_SYMBOL(acpi_release_global_lock); +EXPORT_SYMBOL(acpi_install_gpe_block); +EXPORT_SYMBOL(acpi_remove_gpe_block); EXPORT_SYMBOL(acpi_get_current_resources); EXPORT_SYMBOL(acpi_get_possible_resources); EXPORT_SYMBOL(acpi_walk_resources); diff -Nru a/drivers/acpi/battery.c b/drivers/acpi/battery.c --- a/drivers/acpi/battery.c Wed Apr 2 22:24:06 2003 +++ b/drivers/acpi/battery.c Wed Apr 2 22:24:06 2003 @@ -28,6 +28,8 @@ #include #include #include +#include + #include #include diff -Nru a/drivers/acpi/ec.c b/drivers/acpi/ec.c --- a/drivers/acpi/ec.c Wed Apr 2 22:24:05 2003 +++ b/drivers/acpi/ec.c Wed Apr 2 22:24:05 2003 @@ -378,7 +378,7 @@ acpi_evaluate_object(ec->handle, object_name, NULL, NULL); end: - acpi_enable_event(ec->gpe_bit, ACPI_EVENT_GPE, 0); + acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR); } static void @@ -391,7 +391,7 @@ if (!ec) return; - acpi_disable_event(ec->gpe_bit, ACPI_EVENT_GPE, 0); + acpi_disable_gpe(NULL, ec->gpe_bit, ACPI_ISR); status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE, acpi_ec_gpe_query, ec); @@ -589,12 +589,13 @@ acpi_remove_address_space_handler(ACPI_ROOT_OBJECT, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler); - acpi_remove_gpe_handler(ec_ecdt->gpe_bit, &acpi_ec_gpe_handler); + acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit, &acpi_ec_gpe_handler); kfree(ec_ecdt); } /* Get GPE bit assignment (EC events). */ + /* TODO: Add support for _GPE returning a package */ status = acpi_evaluate_integer(ec->handle, "_GPE", NULL, &ec->gpe_bit); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, @@ -714,7 +715,7 @@ /* * Install GPE handler */ - status = acpi_install_gpe_handler(ec->gpe_bit, + status = acpi_install_gpe_handler(NULL, ec->gpe_bit, ACPI_EVENT_EDGE_TRIGGERED, &acpi_ec_gpe_handler, ec); if (ACPI_FAILURE(status)) { return_VALUE(-ENODEV); @@ -724,7 +725,7 @@ ACPI_ADR_SPACE_EC, &acpi_ec_space_handler, &acpi_ec_space_setup, ec); if (ACPI_FAILURE(status)) { - acpi_remove_gpe_handler(ec->gpe_bit, &acpi_ec_gpe_handler); + acpi_remove_gpe_handler(NULL, ec->gpe_bit, &acpi_ec_gpe_handler); return_VALUE(-ENODEV); } @@ -752,7 +753,7 @@ if (ACPI_FAILURE(status)) return_VALUE(-ENODEV); - status = acpi_remove_gpe_handler(ec->gpe_bit, &acpi_ec_gpe_handler); + status = acpi_remove_gpe_handler(NULL, ec->gpe_bit, &acpi_ec_gpe_handler); if (ACPI_FAILURE(status)) return_VALUE(-ENODEV); @@ -798,7 +799,7 @@ /* * Install GPE handler */ - status = acpi_install_gpe_handler(ec_ecdt->gpe_bit, + status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe_bit, ACPI_EVENT_EDGE_TRIGGERED, &acpi_ec_gpe_handler, ec_ecdt); if (ACPI_FAILURE(status)) { @@ -809,7 +810,7 @@ ACPI_ADR_SPACE_EC, &acpi_ec_space_handler, &acpi_ec_space_setup, ec_ecdt); if (ACPI_FAILURE(status)) { - acpi_remove_gpe_handler(ec_ecdt->gpe_bit, + acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit, &acpi_ec_gpe_handler); goto error; } diff -Nru a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c --- a/drivers/acpi/events/evevent.c Wed Apr 2 22:24:07 2003 +++ b/drivers/acpi/events/evevent.c Wed Apr 2 22:24:07 2003 @@ -78,9 +78,9 @@ } /* - * Initialize the Fixed and General Purpose acpi_events prior. This is - * done prior to enabling SCIs to prevent interrupts from occurring - * before handers are installed. + * Initialize the Fixed and General Purpose Events. This is + * done prior to enabling SCIs to prevent interrupts from + * occurring before handers are installed. */ status = acpi_ev_fixed_event_initialize (); if (ACPI_FAILURE (status)) { @@ -225,7 +225,7 @@ (void) acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_ENABLE, &fixed_enable); ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS, - "Fixed acpi_event Block: Enable %08X Status %08X\n", + "Fixed Event Block: Enable %08X Status %08X\n", fixed_enable, fixed_status)); /* @@ -282,7 +282,7 @@ 0, ACPI_MTX_DO_NOT_LOCK); ACPI_REPORT_ERROR ( - ("ev_gpe_dispatch: No installed handler for fixed event [%08X]\n", + ("No installed handler for fixed event [%08X]\n", event)); return (ACPI_INTERRUPT_NOT_HANDLED); diff -Nru a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c --- a/drivers/acpi/events/evgpe.c Wed Apr 2 22:24:06 2003 +++ b/drivers/acpi/events/evgpe.c Wed Apr 2 22:24:06 2003 @@ -53,44 +53,63 @@ * * FUNCTION: acpi_ev_get_gpe_event_info * - * PARAMETERS: gpe_number - Raw GPE number + * PARAMETERS: gpe_device - Device node. NULL for GPE0/GPE1 + * gpe_number - Raw GPE number * - * RETURN: None. + * RETURN: A GPE event_info struct. NULL if not a valid GPE * - * DESCRIPTION: Returns the event_info struct - * associated with this GPE. + * DESCRIPTION: Returns the event_info struct associated with this GPE. + * Validates the gpe_block and the gpe_number * - * TBD: this function will go away when full support of GPE block devices - * is implemented! + * Should be called only when the GPE lists are semaphore locked + * and not subject to change. * ******************************************************************************/ struct acpi_gpe_event_info * acpi_ev_get_gpe_event_info ( + acpi_handle gpe_device, u32 gpe_number) { + union acpi_operand_object *obj_desc; struct acpi_gpe_block_info *gpe_block; + acpi_native_uint i; - /* Examine GPE Block 0 */ + ACPI_FUNCTION_NAME ("ev_get_gpe_event_info"); - gpe_block = acpi_gbl_gpe_block_list_head; - if (!gpe_block) { - return (NULL); - } - if ((gpe_number >= gpe_block->block_base_number) && - (gpe_number < gpe_block->block_base_number + (gpe_block->register_count * 8))) { - return (&gpe_block->event_info[gpe_number - gpe_block->block_base_number]); - } + /* A NULL gpe_block means use the FADT-defined GPE block(s) */ - /* Examine GPE Block 1 */ + if (!gpe_device) { + /* Examine GPE Block 0 and 1 (These blocks are permanent) */ + + for (i = 0; i < ACPI_MAX_GPE_BLOCKS; i++) { + gpe_block = acpi_gbl_gpe_fadt_blocks[i]; + if (gpe_block) { + if ((gpe_number >= gpe_block->block_base_number) && + (gpe_number < gpe_block->block_base_number + (gpe_block->register_count * 8))) { + return (&gpe_block->event_info[gpe_number - gpe_block->block_base_number]); + } + } + } + + /* The gpe_number was not in the range of either FADT GPE block */ - gpe_block = gpe_block->next; - if (!gpe_block) { return (NULL); } + /* + * A Non-null gpe_device means this is a GPE Block Device. + */ + obj_desc = acpi_ns_get_attached_object ((struct acpi_namespace_node *) gpe_device); + if (!obj_desc || + !obj_desc->device.gpe_block) { + return (NULL); + } + + gpe_block = obj_desc->device.gpe_block; + if ((gpe_number >= gpe_block->block_base_number) && (gpe_number < gpe_block->block_base_number + (gpe_block->register_count * 8))) { return (&gpe_block->event_info[gpe_number - gpe_block->block_base_number]); @@ -99,11 +118,13 @@ return (NULL); } + /******************************************************************************* * * FUNCTION: acpi_ev_gpe_detect * - * PARAMETERS: None + * PARAMETERS: gpe_xrupt_list - Interrupt block for this interrupt. + * Can have multiple GPE blocks attached. * * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED * @@ -113,17 +134,19 @@ ******************************************************************************/ u32 -acpi_ev_gpe_detect (void) +acpi_ev_gpe_detect ( + struct acpi_gpe_xrupt_info *gpe_xrupt_list) { u32 int_status = ACPI_INTERRUPT_NOT_HANDLED; - u32 i; - u32 j; u8 enabled_status_byte; u8 bit_mask; struct acpi_gpe_register_info *gpe_register_info; u32 in_value; acpi_status status; struct acpi_gpe_block_info *gpe_block; + u32 gpe_number; + u32 i; + u32 j; ACPI_FUNCTION_NAME ("ev_gpe_detect"); @@ -131,7 +154,8 @@ /* Examine all GPE blocks attached to this interrupt level */ - gpe_block = acpi_gbl_gpe_block_list_head; + acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_ISR); + gpe_block = gpe_xrupt_list->gpe_block_list_head; while (gpe_block) { /* * Read all of the 8-bit GPE status and enable registers @@ -143,18 +167,22 @@ gpe_register_info = &gpe_block->register_info[i]; + /* Read the Status Register */ + status = acpi_hw_low_level_read (ACPI_GPE_REGISTER_WIDTH, &in_value, &gpe_register_info->status_address, 0); gpe_register_info->status = (u8) in_value; if (ACPI_FAILURE (status)) { - return (ACPI_INTERRUPT_NOT_HANDLED); + goto unlock_and_exit; } + /* Read the Enable Register */ + status = acpi_hw_low_level_read (ACPI_GPE_REGISTER_WIDTH, &in_value, &gpe_register_info->enable_address, 0); gpe_register_info->enable = (u8) in_value; if (ACPI_FAILURE (status)) { - return (ACPI_INTERRUPT_NOT_HANDLED); + goto unlock_and_exit; } ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS, @@ -184,8 +212,11 @@ * Found an active GPE. Dispatch the event to a handler * or method. */ + gpe_number = (i * ACPI_GPE_REGISTER_WIDTH) + j; + int_status |= acpi_ev_gpe_dispatch ( - &gpe_block->event_info[(i * ACPI_GPE_REGISTER_WIDTH) +j]); + &gpe_block->event_info[gpe_number], + gpe_number + gpe_block->register_info[gpe_number].base_gpe_number); } } } @@ -193,6 +224,9 @@ gpe_block = gpe_block->next; } +unlock_and_exit: + + acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_ISR); return (int_status); } @@ -201,7 +235,7 @@ * * FUNCTION: acpi_ev_asynch_execute_gpe_method * - * PARAMETERS: gpe_event_info - Info for this GPE + * PARAMETERS: Context (gpe_event_info) - Info for this GPE * * RETURN: None * @@ -209,7 +243,7 @@ * function is called from an invocation of acpi_os_queue_for_execution * (and therefore does NOT execute at interrupt level) so that * the control method itself is not executed in the context of - * the SCI interrupt handler. + * an interrupt handler. * ******************************************************************************/ @@ -220,44 +254,54 @@ struct acpi_gpe_event_info *gpe_event_info = (void *) context; u32 gpe_number = 0; acpi_status status; + struct acpi_gpe_event_info local_gpe_event_info; ACPI_FUNCTION_TRACE ("ev_asynch_execute_gpe_method"); - /* - * Take a snapshot of the GPE info for this level - we copy the - * info to prevent a race condition with remove_handler. - */ status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); if (ACPI_FAILURE (status)) { return_VOID; } + /* Must revalidate the gpe_number/gpe_block */ + + if (!acpi_ev_valid_gpe_event (gpe_event_info)) { + status = acpi_ut_release_mutex (ACPI_MTX_EVENTS); + return_VOID; + } + + /* + * Take a snapshot of the GPE info for this level - we copy the + * info to prevent a race condition with remove_handler/remove_block. + */ + ACPI_MEMCPY (&local_gpe_event_info, gpe_event_info, sizeof (struct acpi_gpe_event_info)); + status = acpi_ut_release_mutex (ACPI_MTX_EVENTS); if (ACPI_FAILURE (status)) { return_VOID; } - if (gpe_event_info->method_node) { + if (local_gpe_event_info.method_node) { /* * Invoke the GPE Method (_Lxx, _Exx): * (Evaluate the _Lxx/_Exx control method that corresponds to this GPE.) */ - status = acpi_ns_evaluate_by_handle (gpe_event_info->method_node, NULL, NULL); + status = acpi_ns_evaluate_by_handle (local_gpe_event_info.method_node, NULL, NULL); if (ACPI_FAILURE (status)) { - ACPI_REPORT_ERROR (("%s while evaluating method [%4.4s] for GPE[%2.2X]\n", + ACPI_REPORT_ERROR (("%s while evaluating method [%4.4s] for GPE[%2X]\n", acpi_format_exception (status), - gpe_event_info->method_node->name.ascii, gpe_number)); + local_gpe_event_info.method_node->name.ascii, gpe_number)); } } - if (gpe_event_info->type & ACPI_EVENT_LEVEL_TRIGGERED) { + if (local_gpe_event_info.flags & ACPI_EVENT_LEVEL_TRIGGERED) { /* * GPE is level-triggered, we clear the GPE status bit after handling * the event. */ - status = acpi_hw_clear_gpe (gpe_event_info); + status = acpi_hw_clear_gpe (&local_gpe_event_info); if (ACPI_FAILURE (status)) { return_VOID; } @@ -265,7 +309,7 @@ /* Enable this GPE */ - (void) acpi_hw_enable_gpe (gpe_event_info); + (void) acpi_hw_enable_gpe (&local_gpe_event_info); return_VOID; } @@ -274,21 +318,23 @@ * * FUNCTION: acpi_ev_gpe_dispatch * - * PARAMETERS: gpe_event_info - info for this GPE + * PARAMETERS: gpe_event_info - info for this GPE + * gpe_number - Number relative to the parent GPE block * * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED * * DESCRIPTION: Dispatch a General Purpose Event to either a function (e.g. EC) - * or method (e.g. _Lxx/_Exx) handler. This function executes - * at interrupt level. + * or method (e.g. _Lxx/_Exx) handler. + * + * This function executes at interrupt level. * ******************************************************************************/ u32 acpi_ev_gpe_dispatch ( - struct acpi_gpe_event_info *gpe_event_info) + struct acpi_gpe_event_info *gpe_event_info, + u32 gpe_number) { - u32 gpe_number = 0; /* TBD: remove */ acpi_status status; @@ -299,10 +345,10 @@ * If edge-triggered, clear the GPE status bit now. Note that * level-triggered events are cleared after the GPE is serviced. */ - if (gpe_event_info->type & ACPI_EVENT_EDGE_TRIGGERED) { + if (gpe_event_info->flags & ACPI_EVENT_EDGE_TRIGGERED) { status = acpi_hw_clear_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { - ACPI_REPORT_ERROR (("acpi_ev_gpe_dispatch: Unable to clear GPE[%2.2X]\n", + ACPI_REPORT_ERROR (("acpi_ev_gpe_dispatch: Unable to clear GPE[%2X]\n", gpe_number)); return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); } @@ -327,19 +373,18 @@ */ status = acpi_hw_disable_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { - ACPI_REPORT_ERROR (("acpi_ev_gpe_dispatch: Unable to disable GPE[%2.2X]\n", + ACPI_REPORT_ERROR (("acpi_ev_gpe_dispatch: Unable to disable GPE[%2X]\n", gpe_number)); return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); } - /* - * Execute the method associated with the GPE. - */ + /* Execute the method associated with the GPE. */ + if (ACPI_FAILURE (acpi_os_queue_for_execution (OSD_PRIORITY_GPE, acpi_ev_asynch_execute_gpe_method, gpe_event_info))) { ACPI_REPORT_ERROR (( - "acpi_ev_gpe_dispatch: Unable to queue handler for GPE[%2.2X], event is disabled\n", + "acpi_ev_gpe_dispatch: Unable to queue handler for GPE[%2X], event is disabled\n", gpe_number)); } } @@ -347,7 +392,7 @@ /* No handler or method to run! */ ACPI_REPORT_ERROR (( - "acpi_ev_gpe_dispatch: No handler or method for GPE[%2.2X], disabling event\n", + "acpi_ev_gpe_dispatch: No handler or method for GPE[%2X], disabling event\n", gpe_number)); /* @@ -356,19 +401,18 @@ */ status = acpi_hw_disable_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { - ACPI_REPORT_ERROR (("acpi_ev_gpe_dispatch: Unable to disable GPE[%2.2X]\n", + ACPI_REPORT_ERROR (("acpi_ev_gpe_dispatch: Unable to disable GPE[%2X]\n", gpe_number)); return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); } } - /* - * It is now safe to clear level-triggered evnets. - */ - if (gpe_event_info->type & ACPI_EVENT_LEVEL_TRIGGERED) { + /* It is now safe to clear level-triggered events. */ + + if (gpe_event_info->flags & ACPI_EVENT_LEVEL_TRIGGERED) { status = acpi_hw_clear_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { - ACPI_REPORT_ERROR (("acpi_ev_gpe_dispatch: Unable to clear GPE[%2.2X]\n", + ACPI_REPORT_ERROR (("acpi_ev_gpe_dispatch: Unable to clear GPE[%2X]\n", gpe_number)); return_VALUE (ACPI_INTERRUPT_NOT_HANDLED); } diff -Nru a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c --- a/drivers/acpi/events/evgpeblk.c Wed Apr 2 22:24:05 2003 +++ b/drivers/acpi/events/evgpeblk.c Wed Apr 2 22:24:05 2003 @@ -46,7 +46,107 @@ #include #define _COMPONENT ACPI_EVENTS - ACPI_MODULE_NAME ("evgpe") + ACPI_MODULE_NAME ("evgpeblk") + + +/******************************************************************************* + * + * FUNCTION: acpi_ev_valid_gpe_event + * + * PARAMETERS: gpe_event_info - Info for this GPE + * + * RETURN: TRUE if the gpe_event is valid + * + * DESCRIPTION: Validate a GPE event. DO NOT CALL FROM INTERRUPT LEVEL. + * Should be called only when the GPE lists are semaphore locked + * and not subject to change. + * + ******************************************************************************/ + +u8 +acpi_ev_valid_gpe_event ( + struct acpi_gpe_event_info *gpe_event_info) +{ + struct acpi_gpe_xrupt_info *gpe_xrupt_block; + struct acpi_gpe_block_info *gpe_block; + + + ACPI_FUNCTION_NAME ("ev_valid_gpe_event"); + + + /* No need for spin lock since we are not changing any list elements */ + + gpe_xrupt_block = acpi_gbl_gpe_xrupt_list_head; + while (gpe_xrupt_block) { + gpe_block = gpe_xrupt_block->gpe_block_list_head; + while (gpe_block) { + if ((&gpe_block->event_info[0] <= gpe_event_info) && + (&gpe_block->event_info[gpe_block->register_count * 8] > gpe_event_info)) { + return (TRUE); + } + + gpe_block = gpe_block->next; + } + + gpe_xrupt_block = gpe_xrupt_block->next; + } + + return (FALSE); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ev_walk_gpe_list + * + * PARAMETERS: gpe_walk_callback - Routine called for each GPE block + * + * RETURN: Status + * + * DESCRIPTION: Walk the GPE lists. + * FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED + * + ******************************************************************************/ + +acpi_status +acpi_ev_walk_gpe_list ( + ACPI_GPE_CALLBACK gpe_walk_callback) +{ + struct acpi_gpe_block_info *gpe_block; + struct acpi_gpe_xrupt_info *gpe_xrupt_info; + acpi_status status = AE_OK; + + + ACPI_FUNCTION_TRACE ("ev_walk_gpe_list"); + + + acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_ISR); + + /* Walk the interrupt level descriptor list */ + + gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head; + while (gpe_xrupt_info) { + /* Walk all Gpe Blocks attached to this interrupt level */ + + gpe_block = gpe_xrupt_info->gpe_block_list_head; + while (gpe_block) { + /* One callback per GPE block */ + + status = gpe_walk_callback (gpe_xrupt_info, gpe_block); + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; + } + + gpe_block = gpe_block->next; + } + + gpe_xrupt_info = gpe_xrupt_info->next; + } + +unlock_and_exit: + acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_ISR); + return_ACPI_STATUS (status); +} /******************************************************************************* @@ -131,11 +231,12 @@ /* Ensure that we have a valid GPE number for this GPE block */ if ((gpe_number < gpe_block->block_base_number) || - (gpe_number >= (gpe_block->register_count * 8))) { - /* Not valid, all we can do here is ignore it */ - - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "GPE number associated with method %s is not valid\n", name)); + (gpe_number >= (gpe_block->block_base_number + (gpe_block->register_count * 8)))) { + /* + * Not valid for this GPE block, just ignore it + * However, it may be valid for a different GPE block, since GPE0 and GPE1 + * methods both appear under \_GPE. + */ return (AE_OK); } @@ -145,7 +246,7 @@ */ gpe_event_info = &gpe_block->event_info[gpe_number - gpe_block->block_base_number]; - gpe_event_info->type = type; + gpe_event_info->flags = type; gpe_event_info->method_node = (struct acpi_namespace_node *) obj_handle; /* @@ -156,7 +257,8 @@ return (status); } - ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Registered GPE method %s as GPE number %2.2X\n", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Registered GPE method %s as GPE number 0x%.2X\n", name, gpe_number)); return (AE_OK); } @@ -164,9 +266,139 @@ /******************************************************************************* * + * FUNCTION: acpi_ev_get_gpe_xrupt_block + * + * PARAMETERS: interrupt_level - Interrupt for a GPE block + * + * RETURN: A GPE interrupt block + * + * DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt + * block per unique interrupt level used for GPEs. + * Should be called only when the GPE lists are semaphore locked + * and not subject to change. + * + ******************************************************************************/ + +struct acpi_gpe_xrupt_info * +acpi_ev_get_gpe_xrupt_block ( + u32 interrupt_level) +{ + struct acpi_gpe_xrupt_info *next_gpe_xrupt; + struct acpi_gpe_xrupt_info *gpe_xrupt; + acpi_status status; + + + /* No need for spin lock since we are not changing any list elements here */ + + next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head; + while (next_gpe_xrupt) { + if (next_gpe_xrupt->interrupt_level == interrupt_level) { + return (next_gpe_xrupt); + } + + next_gpe_xrupt = next_gpe_xrupt->next; + } + + /* Not found, must allocate a new xrupt descriptor */ + + gpe_xrupt = ACPI_MEM_CALLOCATE (sizeof (struct acpi_gpe_xrupt_info)); + if (!gpe_xrupt) { + return (NULL); + } + + gpe_xrupt->interrupt_level = interrupt_level; + + /* Install new interrupt descriptor with spin lock */ + + acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); + if (acpi_gbl_gpe_xrupt_list_head) { + next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head; + while (next_gpe_xrupt->next) { + next_gpe_xrupt = next_gpe_xrupt->next; + } + + next_gpe_xrupt->next = gpe_xrupt; + gpe_xrupt->previous = next_gpe_xrupt; + } + else { + acpi_gbl_gpe_xrupt_list_head = gpe_xrupt; + } + acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); + + /* Install new interrupt handler if not SCI_INT */ + + if (interrupt_level != acpi_gbl_FADT->sci_int) { + status = acpi_os_install_interrupt_handler (interrupt_level, + acpi_ev_gpe_xrupt_handler, gpe_xrupt); + } + + return (gpe_xrupt); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ev_delete_gpe_xrupt + * + * PARAMETERS: gpe_xrupt - A GPE interrupt info block + * + * RETURN: Status + * + * DESCRIPTION: Remove and free a gpe_xrupt block. Remove an associated + * interrupt handler if not the SCI interrupt. + * + ******************************************************************************/ + +acpi_status +acpi_ev_delete_gpe_xrupt ( + struct acpi_gpe_xrupt_info *gpe_xrupt) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ev_delete_gpe_xrupt"); + + + /* We never want to remove the SCI interrupt handler */ + + if (gpe_xrupt->interrupt_level == acpi_gbl_FADT->sci_int) { + gpe_xrupt->gpe_block_list_head = NULL; + return_ACPI_STATUS (AE_OK); + } + + /* Disable this interrupt */ + + status = acpi_os_remove_interrupt_handler (gpe_xrupt->interrupt_level, + acpi_ev_gpe_xrupt_handler); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Unlink the interrupt block with lock */ + + acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); + if (gpe_xrupt->previous) { + gpe_xrupt->previous->next = gpe_xrupt->next; + } + + if (gpe_xrupt->next) { + gpe_xrupt->next->previous = gpe_xrupt->previous; + } + acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); + + /* Free the block */ + + ACPI_MEM_FREE (gpe_xrupt); + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * * FUNCTION: acpi_ev_install_gpe_block * - * PARAMETERS: gpe_block - New GPE block + * PARAMETERS: gpe_block - New GPE block + * interrupt_level - Level to be associated with this GPE block * * RETURN: Status * @@ -176,21 +408,33 @@ acpi_status acpi_ev_install_gpe_block ( - struct acpi_gpe_block_info *gpe_block) + struct acpi_gpe_block_info *gpe_block, + u32 interrupt_level) { struct acpi_gpe_block_info *next_gpe_block; + struct acpi_gpe_xrupt_info *gpe_xrupt_block; acpi_status status; + ACPI_FUNCTION_TRACE ("ev_install_gpe_block"); + + status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); if (ACPI_FAILURE (status)) { - return (status); + return_ACPI_STATUS (status); } - /* Install the new block at the end of the global list */ + gpe_xrupt_block = acpi_ev_get_gpe_xrupt_block (interrupt_level); + if (!gpe_xrupt_block) { + status = AE_NO_MEMORY; + goto unlock_and_exit; + } - if (acpi_gbl_gpe_block_list_head) { - next_gpe_block = acpi_gbl_gpe_block_list_head; + /* Install the new block at the end of the list for this interrupt with lock */ + + acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); + if (gpe_xrupt_block->gpe_block_list_head) { + next_gpe_block = gpe_xrupt_block->gpe_block_list_head; while (next_gpe_block->next) { next_gpe_block = next_gpe_block->next; } @@ -199,11 +443,83 @@ gpe_block->previous = next_gpe_block; } else { - acpi_gbl_gpe_block_list_head = gpe_block; + gpe_xrupt_block->gpe_block_list_head = gpe_block; } + gpe_block->xrupt_block = gpe_xrupt_block; + acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); + +unlock_and_exit: status = acpi_ut_release_mutex (ACPI_MTX_EVENTS); - return (status); + return_ACPI_STATUS (status); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ev_delete_gpe_block + * + * PARAMETERS: gpe_block - Existing GPE block + * + * RETURN: Status + * + * DESCRIPTION: Install new GPE block with mutex support + * + ******************************************************************************/ + +acpi_status +acpi_ev_delete_gpe_block ( + struct acpi_gpe_block_info *gpe_block) +{ + acpi_status status; + + + ACPI_FUNCTION_TRACE ("ev_install_gpe_block"); + + + status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Disable all GPEs in this block */ + + status = acpi_hw_disable_gpe_block (gpe_block->xrupt_block, gpe_block); + + if (!gpe_block->previous && !gpe_block->next) { + /* This is the last gpe_block on this interrupt */ + + status = acpi_ev_delete_gpe_xrupt (gpe_block->xrupt_block); + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; + } + } + else { + /* Remove the block on this interrupt with lock */ + + acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); + if (gpe_block->previous) { + gpe_block->previous->next = gpe_block->next; + } + else { + gpe_block->xrupt_block->gpe_block_list_head = gpe_block->next; + } + + if (gpe_block->next) { + gpe_block->next->previous = gpe_block->previous; + } + acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); + } + + /* Free the gpe_block */ + + ACPI_MEM_FREE (gpe_block->register_info); + ACPI_MEM_FREE (gpe_block->event_info); + ACPI_MEM_FREE (gpe_block); + +unlock_and_exit: + status = acpi_ut_release_mutex (ACPI_MTX_EVENTS); + return_ACPI_STATUS (status); } @@ -259,12 +575,16 @@ goto error_exit; } + /* Save the new Info arrays in the GPE block */ + + gpe_block->register_info = gpe_register_info; + gpe_block->event_info = gpe_event_info; + /* * Initialize the GPE Register and Event structures. A goal of these * tables is to hide the fact that there are two separate GPE register sets * in a given gpe hardware block, the status registers occupy the first half, - * and the enable registers occupy the second half. Another goal is to hide - * the fact that there may be multiple GPE hardware blocks. + * and the enable registers occupy the second half. */ this_register = gpe_register_info; this_event = gpe_event_info; @@ -319,14 +639,10 @@ this_register++; } - gpe_block->register_info = gpe_register_info; - gpe_block->event_info = gpe_event_info; - return_ACPI_STATUS (AE_OK); error_exit: - if (gpe_register_info) { ACPI_MEM_FREE (gpe_register_info); } @@ -334,7 +650,7 @@ ACPI_MEM_FREE (gpe_event_info); } - return_ACPI_STATUS (AE_OK); + return_ACPI_STATUS (status); } @@ -342,7 +658,12 @@ * * FUNCTION: acpi_ev_create_gpe_block * - * PARAMETERS: TBD + * PARAMETERS: gpe_device - Handle to the parent GPE block + * gpe_block_address - Address and space_iD + * register_count - Number of GPE register pairs in the block + * gpe_block_base_number - Starting GPE number for the block + * interrupt_level - H/W interrupt for the block + * return_gpe_block - Where the new block descriptor is returned * * RETURN: Status * @@ -352,15 +673,15 @@ acpi_status acpi_ev_create_gpe_block ( - char *pathname, + struct acpi_namespace_node *gpe_device, struct acpi_generic_address *gpe_block_address, u32 register_count, u8 gpe_block_base_number, - u32 interrupt_level) + u32 interrupt_level, + struct acpi_gpe_block_info **return_gpe_block) { struct acpi_gpe_block_info *gpe_block; acpi_status status; - acpi_handle obj_handle; ACPI_FUNCTION_TRACE ("ev_create_gpe_block"); @@ -370,13 +691,6 @@ return_ACPI_STATUS (AE_OK); } - /* Get a handle to the parent object for this GPE block */ - - status = acpi_get_handle (NULL, pathname, &obj_handle); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - /* Allocate a new GPE block */ gpe_block = ACPI_MEM_CALLOCATE (sizeof (struct acpi_gpe_block_info)); @@ -400,9 +714,8 @@ } /* Install the new block in the global list(s) */ - /* TBD: Install block in the interrupt handler list */ - status = acpi_ev_install_gpe_block (gpe_block); + status = acpi_ev_install_gpe_block (gpe_block, interrupt_level); if (ACPI_FAILURE (status)) { ACPI_MEM_FREE (gpe_block); return_ACPI_STATUS (status); @@ -410,22 +723,30 @@ /* Dump info about this GPE block */ - ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "GPE Block: %X registers at %8.8X%8.8X\n", + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "GPE Block: [%4.4s] %X registers at %8.8X%8.8X on interrupt %d\n", + gpe_device->name.ascii, gpe_block->register_count, ACPI_HIDWORD (gpe_block->block_address.address), - ACPI_LODWORD (gpe_block->block_address.address))); + ACPI_LODWORD (gpe_block->block_address.address), + interrupt_level)); - ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "GPE Block defined as GPE%d to GPE%d\n", + ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "GPE Block defined as GPE 0x%.2X to GPE 0x%.2X\n", gpe_block->block_base_number, (u32) (gpe_block->block_base_number + ((gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH) -1)))); /* Find all GPE methods (_Lxx, _Exx) for this block */ - status = acpi_walk_namespace (ACPI_TYPE_METHOD, obj_handle, - ACPI_UINT32_MAX, acpi_ev_save_method_info, + status = acpi_ns_walk_namespace (ACPI_TYPE_METHOD, gpe_device, + ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK, acpi_ev_save_method_info, gpe_block, NULL); + /* Return the new block */ + + if (return_gpe_block) { + (*return_gpe_block) = gpe_block; + } + return_ACPI_STATUS (AE_OK); } @@ -448,11 +769,20 @@ u32 register_count0 = 0; u32 register_count1 = 0; u32 gpe_number_max = 0; + acpi_handle gpe_device; + acpi_status status; ACPI_FUNCTION_TRACE ("ev_gpe_initialize"); + /* Get a handle to the predefined _GPE object */ + + status = acpi_get_handle (NULL, "\\_GPE", &gpe_device); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + /* * Initialize the GPE Blocks defined in the FADT * @@ -474,6 +804,7 @@ * * Note: both GPE0 and GPE1 are optional, and either can exist without * the other. + * * If EITHER the register length OR the block address are zero, then that * particular block is not supported. */ @@ -485,8 +816,15 @@ gpe_number_max = (register_count0 * ACPI_GPE_REGISTER_WIDTH) - 1; - acpi_ev_create_gpe_block ("\\_GPE", &acpi_gbl_FADT->xgpe0_blk, - register_count0, 0, acpi_gbl_FADT->sci_int); + /* Install GPE Block 0 */ + + status = acpi_ev_create_gpe_block (gpe_device, &acpi_gbl_FADT->xgpe0_blk, + register_count0, 0, acpi_gbl_FADT->sci_int, &acpi_gbl_gpe_fadt_blocks[0]); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (( + "Could not create GPE Block 0, %s\n", + acpi_format_exception (status))); + } } if (acpi_gbl_FADT->gpe1_blk_len && @@ -510,8 +848,16 @@ register_count1 = 0; } else { - acpi_ev_create_gpe_block ("\\_GPE", &acpi_gbl_FADT->xgpe1_blk, - register_count1, acpi_gbl_FADT->gpe1_base, acpi_gbl_FADT->sci_int); + /* Install GPE Block 1 */ + + status = acpi_ev_create_gpe_block (gpe_device, &acpi_gbl_FADT->xgpe1_blk, + register_count1, acpi_gbl_FADT->gpe1_base, + acpi_gbl_FADT->sci_int, &acpi_gbl_gpe_fadt_blocks[1]); + if (ACPI_FAILURE (status)) { + ACPI_REPORT_ERROR (( + "Could not create GPE Block 1, %s\n", + acpi_format_exception (status))); + } /* * GPE0 and GPE1 do not have to be contiguous in the GPE number space, diff -Nru a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c --- a/drivers/acpi/events/evmisc.c Wed Apr 2 22:24:06 2003 +++ b/drivers/acpi/events/evmisc.c Wed Apr 2 22:24:06 2003 @@ -523,9 +523,6 @@ { acpi_native_uint i; acpi_status status; - struct acpi_gpe_block_info *gpe_block; - struct acpi_gpe_block_info *next_gpe_block; - struct acpi_gpe_event_info *gpe_event_info; ACPI_FUNCTION_TRACE ("ev_terminate"); @@ -537,66 +534,35 @@ * In all cases, on error, print a message but obviously we don't abort. */ - /* - * Disable all fixed events - */ + /* Disable all fixed events */ + for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { - status = acpi_disable_event ((u32) i, ACPI_EVENT_FIXED, 0); + status = acpi_disable_event ((u32) i, 0); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not disable fixed event %d\n", (u32) i)); } } - /* - * Disable all GPEs - */ - gpe_block = acpi_gbl_gpe_block_list_head; - while (gpe_block) { - gpe_event_info = gpe_block->event_info; - for (i = 0; i < (gpe_block->register_count * 8); i++) { - status = acpi_hw_disable_gpe (gpe_event_info); - if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not disable GPE %d\n", (u32) i)); - } + /* Disable all GPEs in all GPE blocks */ - gpe_event_info++; - } + status = acpi_ev_walk_gpe_list (acpi_hw_disable_gpe_block); - gpe_block = gpe_block->next; - } + /* Remove SCI handler */ - /* - * Remove SCI handler - */ status = acpi_ev_remove_sci_handler (); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not remove SCI handler\n")); } } - /* - * Return to original mode if necessary - */ + /* Return to original mode if necessary */ + if (acpi_gbl_original_mode == ACPI_SYS_MODE_LEGACY) { status = acpi_disable (); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "acpi_disable failed\n")); } } - - /* - * Free global GPE blocks and related info structures - */ - gpe_block = acpi_gbl_gpe_block_list_head; - while (gpe_block) { - next_gpe_block = gpe_block->next; - ACPI_MEM_FREE (gpe_block->event_info); - ACPI_MEM_FREE (gpe_block->register_info); - ACPI_MEM_FREE (gpe_block); - - gpe_block = next_gpe_block; - } - return_VOID; } diff -Nru a/drivers/acpi/events/evsci.c b/drivers/acpi/events/evsci.c --- a/drivers/acpi/events/evsci.c Wed Apr 2 22:24:06 2003 +++ b/drivers/acpi/events/evsci.c Wed Apr 2 22:24:06 2003 @@ -52,26 +52,26 @@ /******************************************************************************* * - * FUNCTION: acpi_ev_sci_handler + * FUNCTION: acpi_ev_sci_xrupt_handler * * PARAMETERS: Context - Calling Context * * RETURN: Status code indicates whether interrupt was handled. * * DESCRIPTION: Interrupt handler that will figure out what function or - * control method to call to deal with a SCI. Installed - * using BU interrupt support. + * control method to call to deal with a SCI. * ******************************************************************************/ static u32 ACPI_SYSTEM_XFACE -acpi_ev_sci_handler ( +acpi_ev_sci_xrupt_handler ( void *context) { + struct acpi_gpe_xrupt_info *gpe_xrupt_list = context; u32 interrupt_handled = ACPI_INTERRUPT_NOT_HANDLED; - ACPI_FUNCTION_TRACE("ev_sci_handler"); + ACPI_FUNCTION_TRACE("ev_sci_xrupt_handler"); /* @@ -80,16 +80,54 @@ */ /* - * Fixed acpi_events: - * Check for and dispatch any Fixed acpi_events that have occurred + * Fixed Events: + * Check for and dispatch any Fixed Events that have occurred */ interrupt_handled |= acpi_ev_fixed_event_detect (); /* + * General Purpose Events: + * Check for and dispatch any GPEs that have occurred + */ + interrupt_handled |= acpi_ev_gpe_detect (gpe_xrupt_list); + + return_VALUE (interrupt_handled); +} + + +/******************************************************************************* + * + * FUNCTION: acpi_ev_gpe_xrupt_handler + * + * PARAMETERS: Context - Calling Context + * + * RETURN: Status code indicates whether interrupt was handled. + * + * DESCRIPTION: Handler for GPE Block Device interrupts + * + ******************************************************************************/ + +u32 ACPI_SYSTEM_XFACE +acpi_ev_gpe_xrupt_handler ( + void *context) +{ + struct acpi_gpe_xrupt_info *gpe_xrupt_list = context; + u32 interrupt_handled = ACPI_INTERRUPT_NOT_HANDLED; + + + ACPI_FUNCTION_TRACE("ev_gpe_xrupt_handler"); + + + /* + * We are guaranteed by the ACPI CA initialization/shutdown code that + * if this interrupt handler is installed, ACPI is enabled. + */ + + /* * GPEs: * Check for and dispatch any GPEs that have occurred */ - interrupt_handled |= acpi_ev_gpe_detect (); + interrupt_handled |= acpi_ev_gpe_detect (gpe_xrupt_list); return_VALUE (interrupt_handled); } @@ -117,7 +155,7 @@ status = acpi_os_install_interrupt_handler ((u32) acpi_gbl_FADT->sci_int, - acpi_ev_sci_handler, NULL); + acpi_ev_sci_xrupt_handler, acpi_gbl_gpe_xrupt_list_head); return_ACPI_STATUS (status); } @@ -153,7 +191,7 @@ /* Just let the OS remove the handler and disable the level */ status = acpi_os_remove_interrupt_handler ((u32) acpi_gbl_FADT->sci_int, - acpi_ev_sci_handler); + acpi_ev_sci_xrupt_handler); return_ACPI_STATUS (status); } diff -Nru a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c --- a/drivers/acpi/events/evxface.c Wed Apr 2 22:24:06 2003 +++ b/drivers/acpi/events/evxface.c Wed Apr 2 22:24:06 2003 @@ -102,7 +102,7 @@ acpi_gbl_fixed_event_handlers[event].handler = handler; acpi_gbl_fixed_event_handlers[event].context = context; - status = acpi_enable_event (event, ACPI_EVENT_FIXED, 0); + status = acpi_enable_event (event, 0); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Could not enable fixed event.\n")); @@ -160,7 +160,7 @@ /* Disable the event before removing the handler */ - status = acpi_disable_event(event, ACPI_EVENT_FIXED, 0); + status = acpi_disable_event (event, 0); /* Always Remove the handler */ @@ -471,8 +471,8 @@ * * FUNCTION: acpi_install_gpe_handler * - * PARAMETERS: gpe_number - The GPE number. The numbering scheme is - * bank 0 first, then bank 1. + * PARAMETERS: gpe_number - The GPE number within the GPE block + * gpe_block - GPE block (NULL == FADT GPEs) * Type - Whether this GPE should be treated as an * edge- or level-triggered interrupt. * Handler - Address of the handler @@ -486,6 +486,7 @@ acpi_status acpi_install_gpe_handler ( + acpi_handle gpe_device, u32 gpe_number, u32 type, acpi_gpe_handler handler, @@ -504,42 +505,45 @@ return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* Ensure that we have a valid GPE number */ - - gpe_event_info = acpi_ev_get_gpe_event_info (gpe_number); - if (!gpe_event_info) { - return_ACPI_STATUS (AE_BAD_PARAMETER); - } - status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } + /* Ensure that we have a valid GPE number */ + + gpe_event_info = acpi_ev_get_gpe_event_info (gpe_device, gpe_number); + if (!gpe_event_info) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + /* Make sure that there isn't a handler there already */ if (gpe_event_info->handler) { status = AE_ALREADY_EXISTS; - goto cleanup; + goto unlock_and_exit; } /* Install the handler */ + acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); gpe_event_info->handler = handler; gpe_event_info->context = context; - gpe_event_info->type = (u8) type; + gpe_event_info->flags = (u8) type; + acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); /* Clear the GPE (of stale events), the enable it */ status = acpi_hw_clear_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { - goto cleanup; + goto unlock_and_exit; } status = acpi_hw_enable_gpe (gpe_event_info); -cleanup: +unlock_and_exit: (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); return_ACPI_STATUS (status); } @@ -550,6 +554,7 @@ * FUNCTION: acpi_remove_gpe_handler * * PARAMETERS: gpe_number - The event to remove a handler + * gpe_block - GPE block (NULL == FADT GPEs) * Handler - Address of the handler * * RETURN: Status @@ -560,6 +565,7 @@ acpi_status acpi_remove_gpe_handler ( + acpi_handle gpe_device, u32 gpe_number, acpi_gpe_handler handler) { @@ -576,23 +582,24 @@ return_ACPI_STATUS (AE_BAD_PARAMETER); } + status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + /* Ensure that we have a valid GPE number */ - gpe_event_info = acpi_ev_get_gpe_event_info (gpe_number); + gpe_event_info = acpi_ev_get_gpe_event_info (gpe_device, gpe_number); if (!gpe_event_info) { - return_ACPI_STATUS (AE_BAD_PARAMETER); + status = AE_BAD_PARAMETER; + goto unlock_and_exit; } /* Disable the GPE before removing the handler */ status = acpi_hw_disable_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - - status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + goto unlock_and_exit; } /* Make sure that the installed handler is the same */ @@ -600,16 +607,18 @@ if (gpe_event_info->handler != handler) { (void) acpi_hw_enable_gpe (gpe_event_info); status = AE_BAD_PARAMETER; - goto cleanup; + goto unlock_and_exit; } /* Remove the handler */ + acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); gpe_event_info->handler = NULL; gpe_event_info->context = NULL; + acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR); -cleanup: +unlock_and_exit: (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); return_ACPI_STATUS (status); } diff -Nru a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c --- a/drivers/acpi/events/evxfevnt.c Wed Apr 2 22:24:04 2003 +++ b/drivers/acpi/events/evxfevnt.c Wed Apr 2 22:24:04 2003 @@ -44,6 +44,7 @@ #include #include +#include #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME ("evxfevnt") @@ -116,6 +117,7 @@ ACPI_FUNCTION_TRACE ("acpi_disable"); + if (!acpi_gbl_FADT) { ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "No FADT information present!\n")); return_ACPI_STATUS (AE_NO_ACPI_TABLES); @@ -145,94 +147,121 @@ * * FUNCTION: acpi_enable_event * - * PARAMETERS: Event - The fixed event or GPE to be enabled - * Type - The type of event - * Flags - Just enable, or also wake enable? + * PARAMETERS: Event - The fixed eventto be enabled + * Flags - Reserved * * RETURN: Status * - * DESCRIPTION: Enable an ACPI event (fixed and general purpose) + * DESCRIPTION: Enable an ACPI event (fixed) * ******************************************************************************/ acpi_status acpi_enable_event ( u32 event, - u32 type, u32 flags) { acpi_status status = AE_OK; u32 value; - struct acpi_gpe_event_info *gpe_event_info; ACPI_FUNCTION_TRACE ("acpi_enable_event"); - /* The Type must be either Fixed Event or GPE */ - - switch (type) { - case ACPI_EVENT_FIXED: + /* Decode the Fixed Event */ - /* Decode the Fixed Event */ + if (event > ACPI_EVENT_MAX) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } - if (event > ACPI_EVENT_MAX) { - return_ACPI_STATUS (AE_BAD_PARAMETER); - } + /* + * Enable the requested fixed event (by writing a one to the + * enable register bit) + */ + status = acpi_set_register (acpi_gbl_fixed_event_info[event].enable_register_id, + 1, ACPI_MTX_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* Make sure that the hardware responded */ + + status = acpi_get_register (acpi_gbl_fixed_event_info[event].enable_register_id, + &value, ACPI_MTX_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + if (value != 1) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not enable %s event\n", acpi_ut_get_event_name (event))); + return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE); + } - /* - * Enable the requested fixed event (by writing a one to the - * enable register bit) - */ - status = acpi_set_register (acpi_gbl_fixed_event_info[event].enable_register_id, - 1, ACPI_MTX_LOCK); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } + return_ACPI_STATUS (status); +} - /* Make sure that the hardware responded */ - status = acpi_get_register (acpi_gbl_fixed_event_info[event].enable_register_id, - &value, ACPI_MTX_LOCK); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - - if (value != 1) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Could not enable %s event\n", acpi_ut_get_event_name (event))); - return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE); - } - break; +/******************************************************************************* + * + * FUNCTION: acpi_enable_gpe + * + * PARAMETERS: gpe_device - Parent GPE Device + * gpe_number - GPE level within the GPE block + * Flags - Just enable, or also wake enable? + * Called from ISR or not + * + * RETURN: Status + * + * DESCRIPTION: Enable an ACPI event (general purpose) + * + ******************************************************************************/ +acpi_status +acpi_enable_gpe ( + acpi_handle gpe_device, + u32 gpe_number, + u32 flags) +{ + acpi_status status = AE_OK; + struct acpi_gpe_event_info *gpe_event_info; - case ACPI_EVENT_GPE: - /* Ensure that we have a valid GPE number */ + ACPI_FUNCTION_TRACE ("acpi_enable_gpe"); - gpe_event_info = acpi_ev_get_gpe_event_info (event); - if (!gpe_event_info) { - return_ACPI_STATUS (AE_BAD_PARAMETER); - } - /* Enable the requested GPE number */ + /* Use semaphore lock if not executing at interrupt level */ - status = acpi_hw_enable_gpe (gpe_event_info); + if (flags & ACPI_NOT_ISR) { + status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } + } - if (flags & ACPI_EVENT_WAKE_ENABLE) { - acpi_hw_enable_gpe_for_wakeup (gpe_event_info); - } - break; + /* Ensure that we have a valid GPE number */ + + gpe_event_info = acpi_ev_get_gpe_event_info (gpe_device, gpe_number); + if (!gpe_event_info) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + /* Enable the requested GPE number */ - default: + status = acpi_hw_enable_gpe (gpe_event_info); + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; + } - status = AE_BAD_PARAMETER; + if (flags & ACPI_EVENT_WAKE_ENABLE) { + acpi_hw_enable_gpe_for_wakeup (gpe_event_info); } +unlock_and_exit: + if (flags & ACPI_NOT_ISR) { + (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); + } return_ACPI_STATUS (status); } @@ -241,92 +270,119 @@ * * FUNCTION: acpi_disable_event * - * PARAMETERS: Event - The fixed event or GPE to be enabled - * Type - The type of event, fixed or general purpose - * Flags - Wake disable vs. non-wake disable + * PARAMETERS: Event - The fixed eventto be enabled + * Flags - Reserved * * RETURN: Status * - * DESCRIPTION: Disable an ACPI event (fixed and general purpose) + * DESCRIPTION: Disable an ACPI event (fixed) * ******************************************************************************/ acpi_status acpi_disable_event ( u32 event, - u32 type, u32 flags) { acpi_status status = AE_OK; u32 value; - struct acpi_gpe_event_info *gpe_event_info; ACPI_FUNCTION_TRACE ("acpi_disable_event"); - /* The Type must be either Fixed Event or GPE */ + /* Decode the Fixed Event */ - switch (type) { - case ACPI_EVENT_FIXED: - - /* Decode the Fixed Event */ + if (event > ACPI_EVENT_MAX) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } - if (event > ACPI_EVENT_MAX) { - return_ACPI_STATUS (AE_BAD_PARAMETER); - } + /* + * Disable the requested fixed event (by writing a zero to the + * enable register bit) + */ + status = acpi_set_register (acpi_gbl_fixed_event_info[event].enable_register_id, + 0, ACPI_MTX_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + status = acpi_get_register (acpi_gbl_fixed_event_info[event].enable_register_id, + &value, ACPI_MTX_LOCK); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + if (value != 0) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not disable %s events\n", acpi_ut_get_event_name (event))); + return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE); + } - /* - * Disable the requested fixed event (by writing a zero to the - * enable register bit) - */ - status = acpi_set_register (acpi_gbl_fixed_event_info[event].enable_register_id, - 0, ACPI_MTX_LOCK); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } + return_ACPI_STATUS (status); +} - status = acpi_get_register (acpi_gbl_fixed_event_info[event].enable_register_id, - &value, ACPI_MTX_LOCK); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - if (value != 0) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, - "Could not disable %s events\n", acpi_ut_get_event_name (event))); - return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE); - } - break; +/******************************************************************************* + * + * FUNCTION: acpi_disable_gpe + * + * PARAMETERS: gpe_device - Parent GPE Device + * gpe_number - GPE level within the GPE block + * Flags - Just enable, or also wake enable? + * Called from ISR or not + * + * RETURN: Status + * + * DESCRIPTION: Disable an ACPI event (general purpose) + * + ******************************************************************************/ +acpi_status +acpi_disable_gpe ( + acpi_handle gpe_device, + u32 gpe_number, + u32 flags) +{ + acpi_status status = AE_OK; + struct acpi_gpe_event_info *gpe_event_info; - case ACPI_EVENT_GPE: - /* Ensure that we have a valid GPE number */ + ACPI_FUNCTION_TRACE ("acpi_disable_gpe"); - gpe_event_info = acpi_ev_get_gpe_event_info (event); - if (!gpe_event_info) { - return_ACPI_STATUS (AE_BAD_PARAMETER); - } - /* - * Only disable the requested GPE number for wake if specified. - * Otherwise, turn it totally off - */ + /* Use semaphore lock if not executing at interrupt level */ - if (flags & ACPI_EVENT_WAKE_DISABLE) { - acpi_hw_disable_gpe_for_wakeup (gpe_event_info); - } - else { - status = acpi_hw_disable_gpe (gpe_event_info); + if (flags & ACPI_NOT_ISR) { + status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } - break; + } + /* Ensure that we have a valid GPE number */ - default: + gpe_event_info = acpi_ev_get_gpe_event_info (gpe_device, gpe_number); + if (!gpe_event_info) { status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + /* + * Only disable the requested GPE number for wake if specified. + * Otherwise, turn it totally off + */ + if (flags & ACPI_EVENT_WAKE_DISABLE) { + acpi_hw_disable_gpe_for_wakeup (gpe_event_info); + } + else { + status = acpi_hw_disable_gpe (gpe_event_info); } +unlock_and_exit: + if (flags & ACPI_NOT_ISR) { + (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); + } return_ACPI_STATUS (status); } @@ -335,65 +391,91 @@ * * FUNCTION: acpi_clear_event * - * PARAMETERS: Event - The fixed event or GPE to be cleared - * Type - The type of event + * PARAMETERS: Event - The fixed event to be cleared * * RETURN: Status * - * DESCRIPTION: Clear an ACPI event (fixed and general purpose) + * DESCRIPTION: Clear an ACPI event (fixed) * ******************************************************************************/ acpi_status acpi_clear_event ( - u32 event, - u32 type) + u32 event) { acpi_status status = AE_OK; - struct acpi_gpe_event_info *gpe_event_info; ACPI_FUNCTION_TRACE ("acpi_clear_event"); - /* The Type must be either Fixed Event or GPE */ + /* Decode the Fixed Event */ - switch (type) { - case ACPI_EVENT_FIXED: + if (event > ACPI_EVENT_MAX) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } - /* Decode the Fixed Event */ + /* + * Clear the requested fixed event (By writing a one to the + * status register bit) + */ + status = acpi_set_register (acpi_gbl_fixed_event_info[event].status_register_id, + 1, ACPI_MTX_LOCK); - if (event > ACPI_EVENT_MAX) { - return_ACPI_STATUS (AE_BAD_PARAMETER); - } + return_ACPI_STATUS (status); +} - /* - * Clear the requested fixed event (By writing a one to the - * status register bit) - */ - status = acpi_set_register (acpi_gbl_fixed_event_info[event].status_register_id, - 1, ACPI_MTX_LOCK); - break; - - - case ACPI_EVENT_GPE: - - /* Ensure that we have a valid GPE number */ - - gpe_event_info = acpi_ev_get_gpe_event_info (event); - if (!gpe_event_info) { - return_ACPI_STATUS (AE_BAD_PARAMETER); - } - status = acpi_hw_clear_gpe (gpe_event_info); - break; +/******************************************************************************* + * + * FUNCTION: acpi_clear_gpe + * + * PARAMETERS: gpe_device - Parent GPE Device + * gpe_number - GPE level within the GPE block + * Flags - Called from an ISR or not + * + * RETURN: Status + * + * DESCRIPTION: Clear an ACPI event (general purpose) + * + ******************************************************************************/ + +acpi_status +acpi_clear_gpe ( + acpi_handle gpe_device, + u32 gpe_number, + u32 flags) +{ + acpi_status status = AE_OK; + struct acpi_gpe_event_info *gpe_event_info; + + ACPI_FUNCTION_TRACE ("acpi_clear_gpe"); - default: + /* Use semaphore lock if not executing at interrupt level */ + + if (flags & ACPI_NOT_ISR) { + status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + } + + /* Ensure that we have a valid GPE number */ + + gpe_event_info = acpi_ev_get_gpe_event_info (gpe_device, gpe_number); + if (!gpe_event_info) { status = AE_BAD_PARAMETER; + goto unlock_and_exit; } + status = acpi_hw_clear_gpe (gpe_event_info); + +unlock_and_exit: + if (flags & ACPI_NOT_ISR) { + (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); + } return_ACPI_STATUS (status); } @@ -402,9 +484,8 @@ * * FUNCTION: acpi_get_event_status * - * PARAMETERS: Event - The fixed event or GPE - * Type - The type of event - * Status - Where the current status of the event will + * PARAMETERS: Event - The fixed event + * Event Status - Where the current status of the event will * be returned * * RETURN: Status @@ -413,15 +494,12 @@ * ******************************************************************************/ - acpi_status acpi_get_event_status ( u32 event, - u32 type, acpi_event_status *event_status) { acpi_status status = AE_OK; - struct acpi_gpe_event_info *gpe_event_info; ACPI_FUNCTION_TRACE ("acpi_get_event_status"); @@ -431,45 +509,224 @@ return_ACPI_STATUS (AE_BAD_PARAMETER); } + /* Decode the Fixed Event */ - /* The Type must be either Fixed Event or GPE */ + if (event > ACPI_EVENT_MAX) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } - switch (type) { - case ACPI_EVENT_FIXED: + /* Get the status of the requested fixed event */ - /* Decode the Fixed Event */ + status = acpi_get_register (acpi_gbl_fixed_event_info[event].status_register_id, + event_status, ACPI_MTX_LOCK); - if (event > ACPI_EVENT_MAX) { - return_ACPI_STATUS (AE_BAD_PARAMETER); - } + return_ACPI_STATUS (status); +} - /* Get the status of the requested fixed event */ - status = acpi_get_register (acpi_gbl_fixed_event_info[event].status_register_id, - event_status, ACPI_MTX_LOCK); - break; +/******************************************************************************* + * + * FUNCTION: acpi_get_gpe_status + * + * PARAMETERS: gpe_device - Parent GPE Device + * gpe_number - GPE level within the GPE block + * Flags - Called from an ISR or not + * Event Status - Where the current status of the event will + * be returned + * + * RETURN: Status + * + * DESCRIPTION: Get status of an event (general purpose) + * + ******************************************************************************/ +acpi_status +acpi_get_gpe_status ( + acpi_handle gpe_device, + u32 gpe_number, + u32 flags, + acpi_event_status *event_status) +{ + acpi_status status = AE_OK; + struct acpi_gpe_event_info *gpe_event_info; - case ACPI_EVENT_GPE: - /* Ensure that we have a valid GPE number */ + ACPI_FUNCTION_TRACE ("acpi_get_gpe_status"); - gpe_event_info = acpi_ev_get_gpe_event_info (event); - if (!gpe_event_info) { - return_ACPI_STATUS (AE_BAD_PARAMETER); + + /* Use semaphore lock if not executing at interrupt level */ + + if (flags & ACPI_NOT_ISR) { + status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); } + } + + /* Ensure that we have a valid GPE number */ + + gpe_event_info = acpi_ev_get_gpe_event_info (gpe_device, gpe_number); + if (!gpe_event_info) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + /* Obtain status on the requested GPE number */ + + status = acpi_hw_get_gpe_status (gpe_event_info, event_status); + +unlock_and_exit: + if (flags & ACPI_NOT_ISR) { + (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS); + } + return_ACPI_STATUS (status); +} - /* Obtain status on the requested GPE number */ - status = acpi_hw_get_gpe_status (event, event_status); - break; +/******************************************************************************* + * + * FUNCTION: acpi_install_gpe_block + * + * PARAMETERS: gpe_device - Handle to the parent GPE Block Device + * gpe_block_address - Address and space_iD + * register_count - Number of GPE register pairs in the block + * interrupt_level - H/W interrupt for the block + * + * RETURN: Status + * + * DESCRIPTION: Create and Install a block of GPE registers + * + ******************************************************************************/ + +acpi_status +acpi_install_gpe_block ( + acpi_handle gpe_device, + struct acpi_generic_address *gpe_block_address, + u32 register_count, + u32 interrupt_level) +{ + acpi_status status; + union acpi_operand_object *obj_desc; + struct acpi_namespace_node *node; + struct acpi_gpe_block_info *gpe_block; - default: + ACPI_FUNCTION_TRACE ("acpi_install_gpe_block"); + + + if ((!gpe_device) || + (!gpe_block_address) || + (!register_count)) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } + + node = acpi_ns_map_handle_to_node (gpe_device); + if (!node) { status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + /* + * For user-installed GPE Block Devices, the gpe_block_base_number + * is always zero + */ + status = acpi_ev_create_gpe_block (node, gpe_block_address, register_count, + 0, interrupt_level, &gpe_block); + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; + } + + /* Get the device_object attached to the node */ + + obj_desc = acpi_ns_get_attached_object (node); + if (!obj_desc) { + /* No object, create a new one */ + + obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_DEVICE); + if (!obj_desc) { + status = AE_NO_MEMORY; + goto unlock_and_exit; + } + + status = acpi_ns_attach_object (node, obj_desc, ACPI_TYPE_DEVICE); + acpi_ut_remove_reference (obj_desc); + if (ACPI_FAILURE (status)) { + goto unlock_and_exit; + } } + /* Install the GPE block in the device_object */ + + obj_desc->device.gpe_block = gpe_block; + + +unlock_and_exit: + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); return_ACPI_STATUS (status); } + +/******************************************************************************* + * + * FUNCTION: acpi_remove_gpe_block + * + * PARAMETERS: gpe_device - Handle to the parent GPE Block Device + * + * RETURN: Status + * + * DESCRIPTION: Remove a previously installed block of GPE registers + * + ******************************************************************************/ + +acpi_status +acpi_remove_gpe_block ( + acpi_handle gpe_device) +{ + union acpi_operand_object *obj_desc; + acpi_status status; + struct acpi_namespace_node *node; + + + ACPI_FUNCTION_TRACE ("acpi_remove_gpe_block"); + + + if (!gpe_device) { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (status)) { + return (status); + } + + node = acpi_ns_map_handle_to_node (gpe_device); + if (!node) { + status = AE_BAD_PARAMETER; + goto unlock_and_exit; + } + + /* Get the device_object attached to the node */ + + obj_desc = acpi_ns_get_attached_object (node); + if (!obj_desc || + !obj_desc->device.gpe_block) { + return_ACPI_STATUS (AE_NULL_OBJECT); + } + + /* Delete the GPE block (but not the device_object) */ + + status = acpi_ev_delete_gpe_block (obj_desc->device.gpe_block); + if (ACPI_SUCCESS (status)) { + obj_desc->device.gpe_block = NULL; + } + +unlock_and_exit: + (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + return_ACPI_STATUS (status); +} diff -Nru a/drivers/acpi/fan.c b/drivers/acpi/fan.c --- a/drivers/acpi/fan.c Wed Apr 2 22:24:04 2003 +++ b/drivers/acpi/fan.c Wed Apr 2 22:24:04 2003 @@ -28,6 +28,8 @@ #include #include #include +#include + #include #include diff -Nru a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c --- a/drivers/acpi/hardware/hwgpe.c Wed Apr 2 22:24:04 2003 +++ b/drivers/acpi/hardware/hwgpe.c Wed Apr 2 22:24:04 2003 @@ -266,13 +266,12 @@ acpi_status acpi_hw_get_gpe_status ( - u32 gpe_number, + struct acpi_gpe_event_info *gpe_event_info, acpi_event_status *event_status) { u32 in_byte; u8 bit_mask; struct acpi_gpe_register_info *gpe_register_info; - struct acpi_gpe_event_info *gpe_event_info; acpi_status status; acpi_event_status local_event_status = 0; @@ -284,11 +283,6 @@ return (AE_BAD_PARAMETER); } - gpe_event_info = acpi_ev_get_gpe_event_info (gpe_number); - if (!gpe_event_info) { - return (AE_BAD_PARAMETER); - } - /* Get the info block for the entire GPE register */ gpe_register_info = gpe_event_info->register_info; @@ -301,7 +295,7 @@ status = acpi_hw_low_level_read (8, &in_byte, &gpe_register_info->enable_address, 0); if (ACPI_FAILURE (status)) { - return (status); + goto unlock_and_exit; } if (bit_mask & in_byte) { @@ -318,7 +312,7 @@ status = acpi_hw_low_level_read (8, &in_byte, &gpe_register_info->status_address, 0); if (ACPI_FAILURE (status)) { - return (status); + goto unlock_and_exit; } if (bit_mask & in_byte) { @@ -328,6 +322,150 @@ /* Set return value */ (*event_status) = local_event_status; + + +unlock_and_exit: + return (status); +} + + +/****************************************************************************** + * + * FUNCTION: acpi_hw_disable_gpe_block + * + * PARAMETERS: gpe_xrupt_info - GPE Interrupt info + * gpe_block - Gpe Block info + * + * RETURN: Status + * + * DESCRIPTION: Disable all GPEs within a GPE block + * + ******************************************************************************/ + +acpi_status +acpi_hw_disable_gpe_block ( + struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block) +{ + u32 i; + struct acpi_gpe_register_info *gpe_register_info; + acpi_status status; + + + /* Get the register info for the entire GPE block */ + + gpe_register_info = gpe_block->register_info; + + /* Examine each GPE Register within the block */ + + for (i = 0; i < gpe_block->register_count; i++) { + status = acpi_hw_low_level_write (8, 0x00, + &gpe_block->register_info[i].enable_address, (u32) i); + if (ACPI_FAILURE (status)) { + return (status); + } + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: acpi_hw_clear_gpe_block + * + * PARAMETERS: gpe_xrupt_info - GPE Interrupt info + * gpe_block - Gpe Block info + * + * RETURN: Status + * + * DESCRIPTION: Clear all GPEs within a GPE block + * + ******************************************************************************/ + +acpi_status +acpi_hw_clear_gpe_block ( + struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block) +{ + u32 i; + struct acpi_gpe_register_info *gpe_register_info; + acpi_status status; + + + /* Get the register info for the entire GPE block */ + + gpe_register_info = gpe_block->register_info; + + /* Examine each GPE Register within the block */ + + for (i = 0; i < gpe_block->register_count; i++) { + status = acpi_hw_low_level_write (8, 0xFF, + &gpe_block->register_info[i].status_address, (u32) i); + if (ACPI_FAILURE (status)) { + return (status); + } + } + + return (AE_OK); +} + + +/****************************************************************************** + * + * FUNCTION: acpi_hw_disable_non_wakeup_gpe_block + * + * PARAMETERS: gpe_xrupt_info - GPE Interrupt info + * gpe_block - Gpe Block info + * + * RETURN: Status + * + * DESCRIPTION: Disable all GPEs except wakeup GPEs in a GPE block + * + ******************************************************************************/ + +acpi_status +acpi_hw_disable_non_wakeup_gpe_block ( + struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block) +{ + u32 i; + struct acpi_gpe_register_info *gpe_register_info; + u32 in_value; + acpi_status status; + + + /* Get the register info for the entire GPE block */ + + gpe_register_info = gpe_block->register_info; + + /* Examine each GPE Register within the block */ + + for (i = 0; i < gpe_block->register_count; i++) { + /* + * Read the enabled status of all GPEs. We + * will be using it to restore all the GPEs later. + */ + status = acpi_hw_low_level_read (8, &in_value, + &gpe_register_info->enable_address, 0); + if (ACPI_FAILURE (status)) { + return (status); + } + + gpe_register_info->enable = (u8) in_value; + + /* + * Disable all GPEs except wakeup GPEs. + */ + status = acpi_hw_low_level_write (8, gpe_register_info->wake_enable, + &gpe_register_info->enable_address, 0); + if (ACPI_FAILURE (status)) { + return (status); + } + + gpe_register_info++; + } + return (AE_OK); } @@ -341,7 +479,7 @@ * RETURN: None * * DESCRIPTION: Disable all non-wakeup GPEs - * Call with interrupts disabled. The interrupt handler also + * Called with interrupts disabled. The interrupt handler also * modifies gpe_register_info->Enable, so it should not be * given the chance to run until after non-wake GPEs are * re-enabled. @@ -352,53 +490,64 @@ acpi_hw_disable_non_wakeup_gpes ( void) { + acpi_status status; + + + ACPI_FUNCTION_ENTRY (); + + + status = acpi_ev_walk_gpe_list (acpi_hw_disable_non_wakeup_gpe_block); + + return (status); +} + + +/****************************************************************************** + * + * FUNCTION: acpi_hw_enable_non_wakeup_gpe_block + * + * PARAMETERS: gpe_xrupt_info - GPE Interrupt info + * gpe_block - Gpe Block info + * + * RETURN: Status + * + * DESCRIPTION: Enable a single GPE. + * + ******************************************************************************/ + +acpi_status +acpi_hw_enable_non_wakeup_gpe_block ( + struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block) +{ u32 i; struct acpi_gpe_register_info *gpe_register_info; - u32 in_value; acpi_status status; - struct acpi_gpe_block_info *gpe_block; - ACPI_FUNCTION_ENTRY (); + /* This callback processes one entire GPE block */ + /* Get the register info for the entire GPE block */ - gpe_block = acpi_gbl_gpe_block_list_head; - while (gpe_block) { - /* Get the register info for the entire GPE block */ - - gpe_register_info = gpe_block->register_info; - if (!gpe_register_info) { - return (AE_BAD_PARAMETER); - } + gpe_register_info = gpe_block->register_info; - for (i = 0; i < gpe_block->register_count; i++) { - /* - * Read the enabled status of all GPEs. We - * will be using it to restore all the GPEs later. - */ - status = acpi_hw_low_level_read (8, &in_value, - &gpe_register_info->enable_address, 0); - if (ACPI_FAILURE (status)) { - return (status); - } - - gpe_register_info->enable = (u8) in_value; - - /* - * Disable all GPEs except wakeup GPEs. - */ - status = acpi_hw_low_level_write (8, gpe_register_info->wake_enable, - &gpe_register_info->enable_address, 0); - if (ACPI_FAILURE (status)) { - return (status); - } + /* Examine each GPE register within the block */ - gpe_register_info++; + for (i = 0; i < gpe_block->register_count; i++) { + /* + * We previously stored the enabled status of all GPEs. + * Blast them back in. + */ + status = acpi_hw_low_level_write (8, gpe_register_info->enable, + &gpe_register_info->enable_address, 0); + if (ACPI_FAILURE (status)) { + return (status); } - gpe_block = gpe_block->next; + gpe_register_info++; } + return (AE_OK); } @@ -419,40 +568,13 @@ acpi_hw_enable_non_wakeup_gpes ( void) { - u32 i; - struct acpi_gpe_register_info *gpe_register_info; acpi_status status; - struct acpi_gpe_block_info *gpe_block; ACPI_FUNCTION_ENTRY (); - gpe_block = acpi_gbl_gpe_block_list_head; - while (gpe_block) { - /* Get the register info for the entire GPE block */ - - gpe_register_info = gpe_block->register_info; - if (!gpe_register_info) { - return (AE_BAD_PARAMETER); - } - - for (i = 0; i < gpe_block->register_count; i++) { - /* - * We previously stored the enabled status of all GPEs. - * Blast them back in. - */ - status = acpi_hw_low_level_write (8, gpe_register_info->enable, - &gpe_register_info->enable_address, 0); - if (ACPI_FAILURE (status)) { - return (status); - } - - gpe_register_info++; - } + status = acpi_ev_walk_gpe_list (acpi_hw_enable_non_wakeup_gpe_block); - gpe_block = gpe_block->next; - } - - return (AE_OK); + return (status); } diff -Nru a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c --- a/drivers/acpi/hardware/hwregs.c Wed Apr 2 22:24:07 2003 +++ b/drivers/acpi/hardware/hwregs.c Wed Apr 2 22:24:07 2003 @@ -46,6 +46,7 @@ #include #include +#include #define _COMPONENT ACPI_HARDWARE ACPI_MODULE_NAME ("hwregs") @@ -66,9 +67,7 @@ acpi_status acpi_hw_clear_acpi_status (void) { - acpi_native_uint i; acpi_status status; - struct acpi_gpe_block_info *gpe_block; ACPI_FUNCTION_TRACE ("hw_clear_acpi_status"); @@ -102,18 +101,7 @@ /* Clear the GPE Bits in all GPE registers in all GPE blocks */ - gpe_block = acpi_gbl_gpe_block_list_head; - while (gpe_block) { - for (i = 0; i < gpe_block->register_count; i++) { - status = acpi_hw_low_level_write (8, 0xFF, - &gpe_block->register_info[i].status_address, (u32) i); - if (ACPI_FAILURE (status)) { - goto unlock_and_exit; - } - } - - gpe_block = gpe_block->next; - } + status = acpi_ev_walk_gpe_list (acpi_hw_clear_gpe_block); unlock_and_exit: (void) acpi_ut_release_mutex (ACPI_MTX_HARDWARE); diff -Nru a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c --- a/drivers/acpi/namespace/nsaccess.c Wed Apr 2 22:24:07 2003 +++ b/drivers/acpi/namespace/nsaccess.c Wed Apr 2 22:24:07 2003 @@ -73,6 +73,7 @@ const struct acpi_predefined_names *init_val = NULL; struct acpi_namespace_node *new_node; union acpi_operand_object *obj_desc; + acpi_string val = NULL; ACPI_FUNCTION_TRACE ("ns_root_initialize"); @@ -119,9 +120,7 @@ * initial value, create the initial value. */ if (init_val->val) { - acpi_string val; - - status = acpi_os_predefined_override(init_val, &val); + status = acpi_os_predefined_override (init_val, &val); if (ACPI_FAILURE (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not override predefined %s\n", init_val->name)); diff -Nru a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/namespace/nswalk.c --- a/drivers/acpi/namespace/nswalk.c Wed Apr 2 22:24:07 2003 +++ b/drivers/acpi/namespace/nswalk.c Wed Apr 2 22:24:07 2003 @@ -164,6 +164,7 @@ void **return_value) { acpi_status status; + acpi_status mutex_status; struct acpi_namespace_node *child_node; struct acpi_namespace_node *parent_node; acpi_object_type child_type; @@ -211,9 +212,9 @@ * callback function */ if (unlock_before_callback) { - status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + mutex_status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (mutex_status)) { + return_ACPI_STATUS (mutex_status); } } @@ -221,9 +222,9 @@ context, return_value); if (unlock_before_callback) { - status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); + mutex_status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (mutex_status)) { + return_ACPI_STATUS (mutex_status); } } diff -Nru a/drivers/acpi/osl.c b/drivers/acpi/osl.c --- a/drivers/acpi/osl.c Wed Apr 2 22:24:07 2003 +++ b/drivers/acpi/osl.c Wed Apr 2 22:24:07 2003 @@ -581,24 +581,32 @@ acpi_status acpi_os_write_pci_configuration ( - acpi_pci_id *pci_id, - u32 reg, - acpi_integer value, - u32 width) + struct acpi_pci_id *pci_id, + u32 reg, + acpi_integer value, + u32 width) { return (AE_SUPPORT); } acpi_status acpi_os_read_pci_configuration ( - acpi_pci_id *pci_id, - u32 reg, - void *value, - u32 width) + struct acpi_pci_id *pci_id, + u32 reg, + void *value, + u32 width) { return (AE_SUPPORT); } +void +acpi_os_derive_pci_id ( + acpi_handle rhandle, /* upper bound */ + acpi_handle chandle, /* current node */ + struct acpi_pci_id **id) +{ +} + #endif /*CONFIG_ACPI_PCI*/ static void @@ -667,6 +675,92 @@ } return_ACPI_STATUS (status); +} + +/* + * Allocate the memory for a spinlock and initialize it. + */ +acpi_status +acpi_os_create_lock ( + acpi_handle *out_handle) +{ + spinlock_t *lock_ptr; + + ACPI_FUNCTION_TRACE ("os_create_lock"); + + lock_ptr = acpi_os_allocate(sizeof(spinlock_t)); + + spin_lock_init(lock_ptr); + + ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Creating spinlock[%p].\n", lock_ptr)); + + *out_handle = lock_ptr; + + return_ACPI_STATUS (AE_OK); +} + + +/* + * Deallocate the memory for a spinlock. + */ +void +acpi_os_delete_lock ( + acpi_handle handle) +{ + ACPI_FUNCTION_TRACE ("os_create_lock"); + + ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Deleting spinlock[%p].\n", handle)); + + acpi_os_free(handle); + + return_VOID; +} + +/* + * Acquire a spinlock. + * + * handle is a pointer to the spinlock_t. + * flags is *not* the result of save_flags - it is an ACPI-specific flag variable + * that indicates whether we are at interrupt level. + */ +void +acpi_os_acquire_lock ( + acpi_handle handle, + u32 flags) +{ + ACPI_FUNCTION_TRACE ("os_acquire_lock"); + + ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Acquiring spinlock[%p] from %s level\n", handle, + ((flags & ACPI_NOT_ISR) ? "non-interrupt" : "interrupt"))); + + if (flags & ACPI_NOT_ISR) + ACPI_DISABLE_IRQS(); + + spin_lock(handle); + + return_VOID; +} + + +/* + * Release a spinlock. See above. + */ +void +acpi_os_release_lock ( + acpi_handle handle, + u32 flags) +{ + ACPI_FUNCTION_TRACE ("os_release_lock"); + + ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Releasing spinlock[%p] from %s level\n", handle, + ((flags & ACPI_NOT_ISR) ? "non-interrupt" : "interrupt"))); + + spin_unlock(handle); + + if (flags & ACPI_NOT_ISR) + ACPI_ENABLE_IRQS(); + + return_VOID; } diff -Nru a/drivers/acpi/processor.c b/drivers/acpi/processor.c --- a/drivers/acpi/processor.c Wed Apr 2 22:24:06 2003 +++ b/drivers/acpi/processor.c Wed Apr 2 22:24:06 2003 @@ -639,7 +639,7 @@ /* * C2 latency must be less than or equal to 100 microseconds. */ - if (acpi_fadt.plvl2_lat >= ACPI_PROCESSOR_MAX_C2_LATENCY) + if (acpi_fadt.plvl2_lat > ACPI_PROCESSOR_MAX_C2_LATENCY) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "C2 latency too large [%d]\n", acpi_fadt.plvl2_lat)); @@ -673,7 +673,7 @@ /* * C3 latency must be less than or equal to 1000 microseconds. */ - if (acpi_fadt.plvl3_lat >= ACPI_PROCESSOR_MAX_C3_LATENCY) + if (acpi_fadt.plvl3_lat > ACPI_PROCESSOR_MAX_C3_LATENCY) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "C3 latency too large [%d]\n", acpi_fadt.plvl3_lat)); diff -Nru a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c --- a/drivers/acpi/resources/rsxface.c Wed Apr 2 22:24:06 2003 +++ b/drivers/acpi/resources/rsxface.c Wed Apr 2 22:24:06 2003 @@ -240,12 +240,13 @@ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; struct acpi_resource *resource; + ACPI_FUNCTION_TRACE ("acpi_walk_resources"); if (!device_handle || (ACPI_STRNCMP (path, METHOD_NAME__CRS, sizeof (METHOD_NAME__CRS)) && - ACPI_STRNCMP (path, METHOD_NAME__PRS, sizeof (METHOD_NAME__PRS)))) { + ACPI_STRNCMP (path, METHOD_NAME__PRS, sizeof (METHOD_NAME__PRS)))) { return_ACPI_STATUS (AE_BAD_PARAMETER); } @@ -290,10 +291,10 @@ cleanup: acpi_os_free (buffer.pointer); - return_ACPI_STATUS (status); } + /******************************************************************************* * * FUNCTION: acpi_set_current_resources @@ -337,6 +338,7 @@ return_ACPI_STATUS (status); } + #define COPY_FIELD(out, in, field) out->field = in->field #define COPY_ADDRESS(out, in) \ COPY_FIELD(out, in, resource_type); \ @@ -352,48 +354,53 @@ COPY_FIELD(out, in, address_length); \ COPY_FIELD(out, in, resource_source); -/******************************************************************************* -* -* FUNCTION: acpi_resource_to_address64 -* -* PARAMETERS: resource - Pointer to a resource -* out - Pointer to the users's return -* buffer (a struct -* struct acpi_resource_address64) -* -* RETURN: Status -* -* DESCRIPTION: If the resource is an address16, address32, or address64, -* copy it to the address64 return buffer. This saves the -* caller from having to duplicate code for different-sized -* addresses. -* -******************************************************************************/ +/****************************************************************************** + * + * FUNCTION: acpi_resource_to_address64 + * + * PARAMETERS: resource - Pointer to a resource + * out - Pointer to the users's return + * buffer (a struct + * struct acpi_resource_address64) + * + * RETURN: Status + * + * DESCRIPTION: If the resource is an address16, address32, or address64, + * copy it to the address64 return buffer. This saves the + * caller from having to duplicate code for different-sized + * addresses. + * + ******************************************************************************/ acpi_status acpi_resource_to_address64 ( - struct acpi_resource *resource, - struct acpi_resource_address64 *out) + struct acpi_resource *resource, + struct acpi_resource_address64 *out) { - struct acpi_resource_address16 *address16; - struct acpi_resource_address32 *address32; - struct acpi_resource_address64 *address64; + struct acpi_resource_address16 *address16; + struct acpi_resource_address32 *address32; + struct acpi_resource_address64 *address64; + switch (resource->id) { case ACPI_RSTYPE_ADDRESS16: address16 = (struct acpi_resource_address16 *) &resource->data; COPY_ADDRESS(out, address16); break; + case ACPI_RSTYPE_ADDRESS32: address32 = (struct acpi_resource_address32 *) &resource->data; COPY_ADDRESS(out, address32); break; + case ACPI_RSTYPE_ADDRESS64: address64 = (struct acpi_resource_address64 *) &resource->data; COPY_ADDRESS(out, address64); break; + default: return (AE_BAD_PARAMETER); } + return (AE_OK); } diff -Nru a/drivers/acpi/tables/tbgetall.c b/drivers/acpi/tables/tbgetall.c --- a/drivers/acpi/tables/tbgetall.c Wed Apr 2 22:24:06 2003 +++ b/drivers/acpi/tables/tbgetall.c Wed Apr 2 22:24:06 2003 @@ -228,7 +228,7 @@ * any SSDTs. */ for (i = 0; i < acpi_gbl_rsdt_table_count; i++) { - /* Get the table addresss from the common internal XSDT */ + /* Get the table address from the common internal XSDT */ address.pointer.value = acpi_gbl_XSDT->table_offset_entry[i]; diff -Nru a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c --- a/drivers/acpi/thermal.c Wed Apr 2 22:24:07 2003 +++ b/drivers/acpi/thermal.c Wed Apr 2 22:24:07 2003 @@ -39,6 +39,8 @@ #include #include #include +#include + #include #include diff -Nru a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c --- a/drivers/acpi/utilities/utdelete.c Wed Apr 2 22:24:05 2003 +++ b/drivers/acpi/utilities/utdelete.c Wed Apr 2 22:24:05 2003 @@ -45,6 +45,7 @@ #include #include #include +#include #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME ("utdelete") @@ -127,6 +128,14 @@ /* Free the (variable length) element pointer array */ obj_pointer = object->package.elements; + break; + + + case ACPI_TYPE_DEVICE: + + if (object->device.gpe_block) { + (void) acpi_ev_delete_gpe_block (object->device.gpe_block); + } break; diff -Nru a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c --- a/drivers/acpi/utilities/utglobal.c Wed Apr 2 22:24:04 2003 +++ b/drivers/acpi/utilities/utglobal.c Wed Apr 2 22:24:04 2003 @@ -731,7 +731,9 @@ /* GPE support */ - acpi_gbl_gpe_block_list_head = NULL; + acpi_gbl_gpe_xrupt_list_head = NULL; + acpi_gbl_gpe_fadt_blocks[0] = NULL; + acpi_gbl_gpe_fadt_blocks[1] = NULL; /* Global notify handlers */ diff -Nru a/drivers/acpi/utilities/utinit.c b/drivers/acpi/utilities/utinit.c --- a/drivers/acpi/utilities/utinit.c Wed Apr 2 22:24:06 2003 +++ b/drivers/acpi/utilities/utinit.c Wed Apr 2 22:24:06 2003 @@ -166,20 +166,42 @@ * * RETURN: none * - * DESCRIPTION: free memory allocated for table storage. + * DESCRIPTION: free global memory * ******************************************************************************/ void acpi_ut_terminate (void) { + struct acpi_gpe_block_info *gpe_block; + struct acpi_gpe_block_info *next_gpe_block; + struct acpi_gpe_xrupt_info *gpe_xrupt_info; + struct acpi_gpe_xrupt_info *next_gpe_xrupt_info; + ACPI_FUNCTION_TRACE ("ut_terminate"); /* Free global tables, etc. */ - /* Nothing to do at this time */ + + /* Free global GPE blocks and related info structures */ + + gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head; + while (gpe_xrupt_info) { + gpe_block = gpe_xrupt_info->gpe_block_list_head; + while (gpe_block) { + next_gpe_block = gpe_block->next; + ACPI_MEM_FREE (gpe_block->event_info); + ACPI_MEM_FREE (gpe_block->register_info); + ACPI_MEM_FREE (gpe_block); + + gpe_block = next_gpe_block; + } + next_gpe_xrupt_info = gpe_xrupt_info->next; + ACPI_MEM_FREE (gpe_xrupt_info); + gpe_xrupt_info = next_gpe_xrupt_info; + } return_VOID; } diff -Nru a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c --- a/drivers/acpi/utilities/utmisc.c Wed Apr 2 22:24:04 2003 +++ b/drivers/acpi/utilities/utmisc.c Wed Apr 2 22:24:04 2003 @@ -556,6 +556,9 @@ } } + + status = acpi_os_create_lock (&acpi_gbl_gpe_lock); + return_ACPI_STATUS (AE_OK); } @@ -589,6 +592,7 @@ (void) acpi_ut_delete_mutex (i); } + (void) acpi_os_delete_lock (acpi_gbl_gpe_lock); return_VOID; } diff -Nru a/drivers/atm/iphase.c b/drivers/atm/iphase.c --- a/drivers/atm/iphase.c Wed Apr 2 22:24:07 2003 +++ b/drivers/atm/iphase.c Wed Apr 2 22:24:07 2003 @@ -2893,7 +2893,7 @@ struct tx_buf_desc *buf_desc_ptr; int desc; int comp_code; - int total_len, pad, last; + int total_len; struct cpcs_trailer *trailer; struct ia_vcc *iavcc; @@ -2975,9 +2975,7 @@ /* Figure out the exact length of the packet and padding required to make it aligned on a 48 byte boundary. */ total_len = skb->len + sizeof(struct cpcs_trailer); - last = total_len - (total_len/48)*48; - pad = 48 - last; - total_len = pad + total_len; + total_len = ((total_len + 47) / 48) * 48; IF_TX(printk("ia packet len:%d padding:%d\n", total_len, pad);) /* Put the packet in a tx buffer */ @@ -3283,7 +3281,7 @@ .name = DEV_LABEL, .id_table = ia_pci_tbl, .probe = ia_init_one, - .remove = ia_remove_one, + .remove = __devexit_p(ia_remove_one), }; static int __init ia_module_init(void) diff -Nru a/drivers/base/base.h b/drivers/base/base.h --- a/drivers/base/base.h Wed Apr 2 22:24:05 2003 +++ b/drivers/base/base.h Wed Apr 2 22:24:05 2003 @@ -1,5 +1,3 @@ -#undef DEBUG - extern struct semaphore device_sem; extern struct semaphore devclass_sem; diff -Nru a/drivers/base/cpu.c b/drivers/base/cpu.c --- a/drivers/base/cpu.c Wed Apr 2 22:24:05 2003 +++ b/drivers/base/cpu.c Wed Apr 2 22:24:05 2003 @@ -48,6 +48,9 @@ int __init cpu_dev_init(void) { - devclass_register(&cpu_devclass); - return driver_register(&cpu_driver); + int error; + if (!(error = devclass_register(&cpu_devclass))) + if ((error = driver_register(&cpu_driver))) + devclass_unregister(&cpu_devclass); + return error; } diff -Nru a/drivers/base/driver.c b/drivers/base/driver.c --- a/drivers/base/driver.c Wed Apr 2 22:24:07 2003 +++ b/drivers/base/driver.c Wed Apr 2 22:24:07 2003 @@ -82,6 +82,7 @@ int driver_register(struct device_driver * drv) { INIT_LIST_HEAD(&drv->devices); + INIT_LIST_HEAD(&drv->class_list); init_MUTEX_LOCKED(&drv->unload_sem); return bus_add_driver(drv); } diff -Nru a/drivers/base/memblk.c b/drivers/base/memblk.c --- a/drivers/base/memblk.c Wed Apr 2 22:24:07 2003 +++ b/drivers/base/memblk.c Wed Apr 2 22:24:07 2003 @@ -47,9 +47,12 @@ } -static int __init register_memblk_type(void) +int __init register_memblk_type(void) { - int error = devclass_register(&memblk_devclass); - return error ? error : driver_register(&memblk_driver); + int error; + if (!(error = devclass_register(&memblk_devclass))) + if (error = driver_register(&memblk_driver)) + devclass_unregister(&memblk_devclass); + return error; } postcore_initcall(register_memblk_type); diff -Nru a/drivers/base/node.c b/drivers/base/node.c --- a/drivers/base/node.c Wed Apr 2 22:24:04 2003 +++ b/drivers/base/node.c Wed Apr 2 22:24:04 2003 @@ -89,9 +89,12 @@ } -static int __init register_node_type(void) +int __init register_node_type(void) { - int error = devclass_register(&node_devclass); - return error ? error : driver_register(&node_driver); + int error; + if (!(error = devclass_register(&node_devclass))) + if (error = driver_register(&node_driver)) + devclass_unregister(&node_devclass); + return error; } postcore_initcall(register_node_type); diff -Nru a/drivers/block/scsi_ioctl.c b/drivers/block/scsi_ioctl.c --- a/drivers/block/scsi_ioctl.c Wed Apr 2 22:24:07 2003 +++ b/drivers/block/scsi_ioctl.c Wed Apr 2 22:24:07 2003 @@ -45,7 +45,8 @@ #define SCSI_SENSE_BUFFERSIZE 64 #endif -int blk_do_rq(request_queue_t *q, struct block_device *bdev, struct request *rq) +static int blk_do_rq(request_queue_t *q, struct block_device *bdev, + struct request *rq) { DECLARE_COMPLETION(wait); int err = 0; @@ -368,6 +369,7 @@ goto error; switch (opcode) { + case SEND_DIAGNOSTIC: case FORMAT_UNIT: rq->timeout = FORMAT_UNIT_TIMEOUT; break; @@ -398,7 +400,8 @@ if (in_len) rq->flags |= REQ_RW; - err = blk_do_rq(q, bdev, rq); + blk_do_rq(q, bdev, rq); + err = rq->errors & 0xff; /* only 8 bit SCSI status */ if (err) { if (rq->sense_len) if (copy_to_user(sic->data, rq->sense, rq->sense_len)) diff -Nru a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c --- a/drivers/cdrom/optcd.c Wed Apr 2 22:24:04 2003 +++ b/drivers/cdrom/optcd.c Wed Apr 2 22:24:04 2003 @@ -1598,19 +1598,17 @@ } +static struct gendisk *optcd_disk; + + static int cdromread(unsigned long arg, int blocksize, int cmd) { - int status, ret = 0; + int status; struct cdrom_msf msf; - char *buf; if (copy_from_user(&msf, (void *) arg, sizeof msf)) return -EFAULT; - buf = kmalloc(CD_FRAMESIZE_RAWER, GFP_KERNEL); - if (!buf) - return -ENOMEM; - bin2bcd(&msf); msf.cdmsf_min1 = 0; msf.cdmsf_sec1 = 0; @@ -1619,19 +1617,15 @@ DEBUG((DEBUG_VFS, "read cmd status 0x%x", status)); - if (!sleep_flag_low(FL_DTEN, SLEEP_TIMEOUT)) { - ret = -EIO; - goto cdr_free; - } + if (!sleep_flag_low(FL_DTEN, SLEEP_TIMEOUT)) + return -EIO; - fetch_data(buf, blocksize); + fetch_data(optcd_disk->private_data, blocksize); - if (copy_to_user((void *)arg, &buf, blocksize)) - ret = -EFAULT; + if (copy_to_user((void *)arg, optcd_disk->private_data, blocksize)) + return -EFAULT; -cdr_free: - kfree(buf); - return ret; + return 0; } @@ -1857,6 +1851,14 @@ if (!open_count && state == S_IDLE) { int status; + char *buf; + + buf = kmalloc(CD_FRAMESIZE_RAWER, GFP_KERNEL); + if (!buf) { + printk(KERN_INFO "optcd: cannot allocate read buffer\n"); + return -ENOMEM; + } + optcd_disk->private_data = buf; /* save read buffer */ toc_uptodate = 0; opt_invalidate_buffers(); @@ -1922,6 +1924,7 @@ status = exec_cmd(COMOPEN); DEBUG((DEBUG_VFS, "exec_cmd COMOPEN: %02x", -status)); } + kfree(optcd_disk->private_data); del_timer(&delay_timer); del_timer(&req_timer); } @@ -2009,8 +2012,6 @@ __setup("optcd=", optcd_setup); #endif /* MODULE */ - -static struct gendisk *optcd_disk; /* Test for presence of drive and initialize it. Called at boot time or during module initialisation. */ diff -Nru a/drivers/char/drm/Kconfig b/drivers/char/drm/Kconfig --- a/drivers/char/drm/Kconfig Wed Apr 2 22:24:07 2003 +++ b/drivers/char/drm/Kconfig Wed Apr 2 22:24:07 2003 @@ -22,7 +22,13 @@ Choose this option if you have a 3dfx Banshee or Voodoo3 (or later), graphics card. If M is selected, the module will be called tdfx. -# tristate ' 3dlabs GMX 2000' CONFIG_DRM_GAMMA +config DRM_GAMMA + tristate "3dlabs GMX 2000" + depends on DRM && n + help + This is the old gamma driver, disabled for now unless somebody + tells me it actually might work. + config DRM_R128 tristate "ATI Rage 128" depends on DRM @@ -60,4 +66,3 @@ Choose this option if you have a Matrox G200, G400 or G450 graphics card. If M is selected, the module will be called mga. AGP support is required for this driver to work. - diff -Nru a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile --- a/drivers/char/drm/Makefile Wed Apr 2 22:24:07 2003 +++ b/drivers/char/drm/Makefile Wed Apr 2 22:24:07 2003 @@ -7,7 +7,7 @@ r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o mga-objs := mga_drv.o mga_dma.o mga_state.o mga_warp.o mga_irq.o i810-objs := i810_drv.o i810_dma.o -i830-objs := i830_drv.o i830_dma.o +i830-objs := i830_drv.o i830_dma.o i830_irq.o radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o ffb-objs := ffb_drv.o ffb_context.o diff -Nru a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h --- a/drivers/char/drm/drmP.h Wed Apr 2 22:24:06 2003 +++ b/drivers/char/drm/drmP.h Wed Apr 2 22:24:06 2003 @@ -254,6 +254,7 @@ } \ } \ } while(0) +#define DRM_DROP_MAP(_map) /* Internal types and structures */ #define DRM_ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) @@ -268,6 +269,17 @@ (_map) = (_dev)->context_sareas[_ctx]; \ } while(0) +#define LOCK_TEST_WITH_RETURN( dev, filp ) \ +do { \ + if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || \ + dev->lock.filp != filp ) { \ + DRM_ERROR( "%s called without lock held\n", \ + __FUNCTION__ ); \ + return -EINVAL; \ + } \ +} while (0) + + typedef int drm_ioctl_t( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); @@ -316,7 +328,7 @@ __volatile__ int waiting; /* On kernel DMA queue */ __volatile__ int pending; /* On hardware DMA queue */ wait_queue_head_t dma_wait; /* Processes waiting */ - pid_t pid; /* PID of holding process */ + struct file *filp; /* Pointer to holding file descr */ int context; /* Kernel queue for this buffer */ int while_locked;/* Dispatch this buffer while locked */ enum { @@ -434,7 +446,7 @@ typedef struct drm_lock_data { drm_hw_lock_t *hw_lock; /* Hardware lock */ - pid_t pid; /* PID of lock holder (0=kernel) */ + struct file *filp; /* File descr of lock holder (0=kernel) */ wait_queue_head_t lock_queue; /* Queue of blocked processes */ unsigned long lock_time; /* Time of last lock in jiffies */ } drm_lock_data_t; @@ -516,6 +528,8 @@ drm_map_t *map; } drm_map_list_t; +typedef drm_map_t drm_local_map_t; + #if __HAVE_VBL_IRQ typedef struct drm_vbl_sig { @@ -591,6 +605,7 @@ atomic_t vbl_received; spinlock_t vbl_lock; drm_vbl_sig_t vbl_sigs; + unsigned int vbl_pending; #endif cycles_t ctx_start; cycles_t lck_start; @@ -807,15 +822,15 @@ extern int DRM(dma_setup)(drm_device_t *dev); extern void DRM(dma_takedown)(drm_device_t *dev); extern void DRM(free_buffer)(drm_device_t *dev, drm_buf_t *buf); -extern void DRM(reclaim_buffers)(drm_device_t *dev, pid_t pid); +extern void DRM(reclaim_buffers)( struct file *filp ); #if __HAVE_OLD_DMA /* GH: This is a dirty hack for now... */ extern void DRM(clear_next_buffer)(drm_device_t *dev); extern int DRM(select_queue)(drm_device_t *dev, void (*wrapper)(unsigned long)); -extern int DRM(dma_enqueue)(drm_device_t *dev, drm_dma_t *dma); -extern int DRM(dma_get_buffers)(drm_device_t *dev, drm_dma_t *dma); +extern int DRM(dma_enqueue)(struct file *filp, drm_dma_t *dma); +extern int DRM(dma_get_buffers)(struct file *filp, drm_dma_t *dma); #endif #if __HAVE_DMA_IRQ extern int DRM(control)( struct inode *inode, struct file *filp, diff -Nru a/drivers/char/drm/drm_agpsupport.h b/drivers/char/drm/drm_agpsupport.h --- a/drivers/char/drm/drm_agpsupport.h Wed Apr 2 22:24:04 2003 +++ b/drivers/char/drm/drm_agpsupport.h Wed Apr 2 22:24:04 2003 @@ -266,12 +266,12 @@ head->cant_use_aperture = head->agp_info.cant_use_aperture; head->page_mask = head->agp_info.page_mask; #endif - - DRM_DEBUG("AGP %d.%d, aperture @ 0x%08lx %ZuMB\n", - head->agp_info.version.major, - head->agp_info.version.minor, - head->agp_info.aper_base, - head->agp_info.aper_size); + + DRM_INFO("AGP %d.%d aperture @ 0x%08lx %ZuMB\n", + head->agp_info.version.major, + head->agp_info.version.minor, + head->agp_info.aper_base, + head->agp_info.aper_size); } return head; } diff -Nru a/drivers/char/drm/drm_bufs.h b/drivers/char/drm/drm_bufs.h --- a/drivers/char/drm/drm_bufs.h Wed Apr 2 22:24:04 2003 +++ b/drivers/char/drm/drm_bufs.h Wed Apr 2 22:24:04 2003 @@ -403,7 +403,7 @@ buf->waiting = 0; buf->pending = 0; init_waitqueue_head( &buf->dma_wait ); - buf->pid = 0; + buf->filp = 0; buf->dev_priv_size = sizeof(DRIVER_BUF_PRIV_T); buf->dev_private = DRM(alloc)( sizeof(DRIVER_BUF_PRIV_T), @@ -616,7 +616,7 @@ buf->waiting = 0; buf->pending = 0; init_waitqueue_head( &buf->dma_wait ); - buf->pid = 0; + buf->filp = 0; #if __HAVE_DMA_HISTOGRAM buf->time_queued = 0; buf->time_dispatched = 0; @@ -773,7 +773,7 @@ buf->waiting = 0; buf->pending = 0; init_waitqueue_head( &buf->dma_wait ); - buf->pid = 0; + buf->filp = 0; buf->dev_priv_size = sizeof(DRIVER_BUF_PRIV_T); buf->dev_private = DRM(alloc)( sizeof(DRIVER_BUF_PRIV_T), @@ -1011,9 +1011,9 @@ return -EINVAL; } buf = dma->buflist[idx]; - if ( buf->pid != current->pid ) { - DRM_ERROR( "Process %d freeing buffer owned by %d\n", - current->pid, buf->pid ); + if ( buf->filp != filp ) { + DRM_ERROR( "Process %d freeing buffer not owned\n", + current->pid ); return -EINVAL; } DRM(free_buffer)( dev, buf ); diff -Nru a/drivers/char/drm/drm_dma.h b/drivers/char/drm/drm_dma.h --- a/drivers/char/drm/drm_dma.h Wed Apr 2 22:24:06 2003 +++ b/drivers/char/drm/drm_dma.h Wed Apr 2 22:24:06 2003 @@ -188,7 +188,7 @@ buf->waiting = 0; buf->pending = 0; - buf->pid = 0; + buf->filp = 0; buf->used = 0; #if __HAVE_DMA_HISTOGRAM buf->time_completed = get_cycles(); @@ -210,14 +210,16 @@ } #if !__HAVE_DMA_RECLAIM -void DRM(reclaim_buffers)(drm_device_t *dev, pid_t pid) +void DRM(reclaim_buffers)( struct file *filp ) { + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; drm_device_dma_t *dma = dev->dma; int i; if (!dma) return; for (i = 0; i < dma->buf_count; i++) { - if (dma->buflist[i]->pid == pid) { + if (dma->buflist[i]->filp == filp) { switch (dma->buflist[i]->list) { case DRM_LIST_NONE: DRM(free_buffer)(dev, dma->buflist[i]); @@ -318,8 +320,10 @@ } -int DRM(dma_enqueue)(drm_device_t *dev, drm_dma_t *d) +int DRM(dma_enqueue)(struct file *filp, drm_dma_t *d) { + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; int i; drm_queue_t *q; drm_buf_t *buf; @@ -381,10 +385,10 @@ return -EINVAL; } buf = dma->buflist[ idx ]; - if (buf->pid != current->pid) { + if (buf->filp != filp) { atomic_dec(&q->use_count); - DRM_ERROR("Process %d using buffer owned by %d\n", - current->pid, buf->pid); + DRM_ERROR("Process %d using buffer not owned\n", + current->pid); return -EINVAL; } if (buf->list != DRM_LIST_NONE) { @@ -426,9 +430,11 @@ return 0; } -static int DRM(dma_get_buffers_of_order)(drm_device_t *dev, drm_dma_t *d, +static int DRM(dma_get_buffers_of_order)(struct file *filp, drm_dma_t *d, int order) { + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; int i; drm_buf_t *buf; drm_device_dma_t *dma = dev->dma; @@ -438,13 +444,13 @@ d->flags & _DRM_DMA_WAIT); if (!buf) break; if (buf->pending || buf->waiting) { - DRM_ERROR("Free buffer %d in use by %d (w%d, p%d)\n", + DRM_ERROR("Free buffer %d in use by %x (w%d, p%d)\n", buf->idx, - buf->pid, + buf->filp, buf->waiting, buf->pending); } - buf->pid = current->pid; + buf->filp = filp; if (copy_to_user(&d->request_indices[i], &buf->idx, sizeof(buf->idx))) @@ -461,7 +467,7 @@ } -int DRM(dma_get_buffers)(drm_device_t *dev, drm_dma_t *dma) +int DRM(dma_get_buffers)(struct file *filp, drm_dma_t *dma) { int order; int retcode = 0; @@ -470,7 +476,7 @@ order = DRM(order)(dma->request_size); dma->granted_count = 0; - retcode = DRM(dma_get_buffers_of_order)(dev, dma, order); + retcode = DRM(dma_get_buffers_of_order)(filp, dma, order); if (dma->granted_count < dma->request_count && (dma->flags & _DRM_DMA_SMALLER_OK)) { @@ -480,7 +486,7 @@ && tmp_order >= DRM_MIN_ORDER; --tmp_order) { - retcode = DRM(dma_get_buffers_of_order)(dev, dma, + retcode = DRM(dma_get_buffers_of_order)(filp, dma, tmp_order); } } @@ -493,7 +499,7 @@ && tmp_order <= DRM_MAX_ORDER; ++tmp_order) { - retcode = DRM(dma_get_buffers_of_order)(dev, dma, + retcode = DRM(dma_get_buffers_of_order)(filp, dma, tmp_order); } } @@ -540,6 +546,8 @@ spin_lock_init( &dev->vbl_lock ); INIT_LIST_HEAD( &dev->vbl_sigs.head ); + + dev->vbl_pending = 0; #endif /* Before installing handler */ @@ -622,6 +630,7 @@ switch ( vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK ) { case _DRM_VBLANK_RELATIVE: vblwait.request.sequence += atomic_read( &dev->vbl_received ); + vblwait.request.type &= ~_DRM_VBLANK_RELATIVE; case _DRM_VBLANK_ABSOLUTE: break; default: @@ -632,10 +641,38 @@ if ( flags & _DRM_VBLANK_SIGNAL ) { unsigned long irqflags; - drm_vbl_sig_t *vbl_sig = DRM_MALLOC( sizeof( drm_vbl_sig_t ) ); + drm_vbl_sig_t *vbl_sig; + + vblwait.reply.sequence = atomic_read( &dev->vbl_received ); + + spin_lock_irqsave( &dev->vbl_lock, irqflags ); + + /* Check if this task has already scheduled the same signal + * for the same vblank sequence number; nothing to be done in + * that case + */ + list_for_each( ( (struct list_head *) vbl_sig ), &dev->vbl_sigs.head ) { + if (vbl_sig->sequence == vblwait.request.sequence + && vbl_sig->info.si_signo == vblwait.request.signal + && vbl_sig->task == current) + { + spin_unlock_irqrestore( &dev->vbl_lock, irqflags ); + goto done; + } + } + + if ( dev->vbl_pending >= 100 ) { + spin_unlock_irqrestore( &dev->vbl_lock, irqflags ); + return -EBUSY; + } + + dev->vbl_pending++; - if ( !vbl_sig ) + spin_unlock_irqrestore( &dev->vbl_lock, irqflags ); + + if ( !( vbl_sig = DRM_MALLOC( sizeof( drm_vbl_sig_t ) ) ) ) { return -ENOMEM; + } memset( (void *)vbl_sig, 0, sizeof(*vbl_sig) ); @@ -643,9 +680,6 @@ vbl_sig->info.si_signo = vblwait.request.signal; vbl_sig->task = current; - vblwait.reply.sequence = atomic_read( &dev->vbl_received ); - - /* Hook signal entry into list */ spin_lock_irqsave( &dev->vbl_lock, irqflags ); list_add_tail( (struct list_head *) vbl_sig, &dev->vbl_sigs.head ); @@ -659,6 +693,7 @@ vblwait.reply.tval_usec = now.tv_usec; } +done: DRM_COPY_TO_USER_IOCTL( (drm_wait_vblank_t *)data, vblwait, sizeof(vblwait) ); @@ -667,25 +702,23 @@ void DRM(vbl_send_signals)( drm_device_t *dev ) { - struct list_head *entry, *tmp; + struct list_head *tmp; drm_vbl_sig_t *vbl_sig; unsigned int vbl_seq = atomic_read( &dev->vbl_received ); unsigned long flags; spin_lock_irqsave( &dev->vbl_lock, flags ); - list_for_each_safe( entry, tmp, &dev->vbl_sigs.head ) { - - vbl_sig = (drm_vbl_sig_t *) entry; - + list_for_each_safe( ( (struct list_head *) vbl_sig ), tmp, &dev->vbl_sigs.head ) { if ( ( vbl_seq - vbl_sig->sequence ) <= (1<<23) ) { - - vbl_sig->info.si_code = atomic_read( &dev->vbl_received ); + vbl_sig->info.si_code = vbl_seq; send_sig_info( vbl_sig->info.si_signo, &vbl_sig->info, vbl_sig->task ); - list_del( entry ); + list_del( (struct list_head *) vbl_sig ); + + DRM_FREE( vbl_sig, sizeof(*vbl_sig) ); - DRM_FREE( entry ); + dev->vbl_pending--; } } diff -Nru a/drivers/char/drm/drm_drv.h b/drivers/char/drm/drm_drv.h --- a/drivers/char/drm/drm_drv.h Wed Apr 2 22:24:07 2003 +++ b/drivers/char/drm/drm_drv.h Wed Apr 2 22:24:07 2003 @@ -323,6 +323,8 @@ dev->last_context = 0; dev->last_switch = 0; dev->last_checked = 0; + init_timer( &dev->timer ); + init_waitqueue_head( &dev->context_wait ); dev->ctx_start = 0; dev->lck_start = 0; @@ -494,7 +496,7 @@ #endif if ( dev->lock.hw_lock ) { dev->sigdata.lock = dev->lock.hw_lock = NULL; /* SHM removed */ - dev->lock.pid = 0; + dev->lock.filp = 0; wake_up_interruptible( &dev->lock.lock_queue ); } up( &dev->struct_sem ); @@ -545,9 +547,7 @@ drm_device_t *dev; int i; -#if __HAVE_CTX_BITMAP int retcode; -#endif DRM_DEBUG( "\n" ); #ifdef MODULE @@ -578,13 +578,9 @@ memset( (void *)dev, 0, sizeof(*dev) ); dev->count_lock = SPIN_LOCK_UNLOCKED; sema_init( &dev->struct_sem, 1 ); - init_timer( &dev->timer ); - init_waitqueue_head( &dev->context_wait ); - if ((DRM(minor)[i] = DRM(stub_register)(DRIVER_NAME, &DRM(fops),dev)) < 0) { - retcode = -EPERM; - goto fail_reg; - } + if ((DRM(minor)[i] = DRM(stub_register)(DRIVER_NAME, &DRM(fops),dev)) < 0) + return -EPERM; dev->device = MKDEV(DRM_MAJOR, DRM(minor)[i] ); dev->name = DRIVER_NAME; @@ -593,8 +589,9 @@ #if __MUST_HAVE_AGP if ( dev->agp == NULL ) { DRM_ERROR( "Cannot initialize the agpgart module.\n" ); - retcode = -ENOMEM; - goto fail; + DRM(stub_unregister)(DRM(minor)[i]); + DRM(takedown)( dev ); + return -ENOMEM; } #endif #if __REALLY_HAVE_MTRR @@ -610,7 +607,9 @@ retcode = DRM(ctxbitmap_init)( dev ); if( retcode ) { DRM_ERROR( "Cannot allocate memory for context bitmap.\n" ); - goto fail; + DRM(stub_unregister)(DRM(minor)[i]); + DRM(takedown)( dev ); + return retcode; } #endif DRM_INFO( "Initialized %s %d.%d.%d %s on minor %d\n", @@ -625,15 +624,6 @@ DRIVER_POSTINIT(); return 0; - -fail: - DRM(stub_unregister)(DRM(minor)[i]); - DRM(takedown)( dev ); - -fail_reg: - kfree (DRM(device)); - kfree (DRM(minor)); - return retcode; } /* drm_cleanup is called via cleanup_module at module unload time. @@ -740,8 +730,6 @@ return -ENODEV; } - DRM_DEBUG( "open_count = %d\n", dev->open_count ); - retcode = DRM(open_helper)( inode, filp, dev ); if ( !retcode ) { atomic_inc( &dev->counts[_DRM_STAT_OPENS] ); @@ -773,15 +761,15 @@ * Begin inline drm_release */ - DRM_DEBUG( "pid = %d, device = 0x%x, open_count = %d\n", - current->pid, dev->device, dev->open_count ); + DRM_DEBUG( "pid = %d, device = 0x%lx, open_count = %d\n", + current->pid, (long)dev->device, dev->open_count ); if ( dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) && - dev->lock.pid == current->pid ) { - DRM_DEBUG( "Process %d dead, freeing lock for context %d\n", - current->pid, - _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) ); + dev->lock.filp == filp ) { + DRM_DEBUG( "File %p released, freeing lock for context %d\n", + filp, + _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock) ); #if __HAVE_RELEASE DRIVER_RELEASE(); #endif @@ -797,6 +785,7 @@ else if ( dev->lock.hw_lock ) { /* The lock is required to reclaim buffers */ DECLARE_WAITQUEUE( entry, current ); + add_wait_queue( &dev->lock.lock_queue, &entry ); for (;;) { current->state = TASK_INTERRUPTIBLE; @@ -807,7 +796,7 @@ } if ( DRM(lock_take)( &dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT ) ) { - dev->lock.pid = priv->pid; + dev->lock.filp = filp; dev->lock.lock_time = jiffies; atomic_inc( &dev->counts[_DRM_STAT_LOCKS] ); break; /* Got lock */ @@ -831,7 +820,7 @@ } } #elif __HAVE_DMA - DRM(reclaim_buffers)( dev, priv->pid ); + DRM(reclaim_buffers)( filp ); #endif DRM(fasync)( -1, filp, 0 ); @@ -855,7 +844,7 @@ dev->file_last = priv->prev; } up( &dev->struct_sem ); - + DRM(free)( priv, sizeof(*priv), DRM_MEM_FILES ); /* ======================================================== @@ -880,6 +869,7 @@ spin_unlock( &dev->count_lock ); unlock_kernel(); + return retcode; } @@ -899,8 +889,9 @@ atomic_inc( &dev->counts[_DRM_STAT_IOCTLS] ); ++priv->ioctl_count; - DRM_DEBUG( "pid=%d, cmd=0x%02x, nr=0x%02x, dev 0x%x, auth=%d\n", - current->pid, cmd, nr, dev->device, priv->authenticated ); + DRM_DEBUG( "pid=%d, cmd=0x%02x, nr=0x%02x, dev 0x%lx, auth=%d\n", + current->pid, cmd, nr, (long)dev->device, + priv->authenticated ); if ( nr >= DRIVER_IOCTL_COUNT ) { retcode = -EINVAL; @@ -976,7 +967,7 @@ } if ( DRM(lock_take)( &dev->lock.hw_lock->lock, lock.context ) ) { - dev->lock.pid = current->pid; + dev->lock.filp = filp; dev->lock.lock_time = jiffies; atomic_inc( &dev->counts[_DRM_STAT_LOCKS] ); break; /* Got lock */ @@ -1058,7 +1049,7 @@ * agent to request it then we should just be able to * take it immediately and not eat the ioctl. */ - dev->lock.pid = 0; + dev->lock.filp = 0; { __volatile__ unsigned int *plock = &dev->lock.hw_lock->lock; unsigned int old, new, prev, ctx; diff -Nru a/drivers/char/drm/drm_fops.h b/drivers/char/drm/drm_fops.h --- a/drivers/char/drm/drm_fops.h Wed Apr 2 22:24:05 2003 +++ b/drivers/char/drm/drm_fops.h Wed Apr 2 22:24:05 2003 @@ -94,8 +94,8 @@ drm_file_t *priv = filp->private_data; drm_device_t *dev = priv->dev; - DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n", - current->pid, dev->device, dev->open_count); + DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n", + current->pid, (long)dev->device, dev->open_count); return 0; } @@ -105,7 +105,7 @@ drm_device_t *dev = priv->dev; int retcode; - DRM_DEBUG("fd = %d, device = 0x%x\n", fd, dev->device); + DRM_DEBUG("fd = %d, device = 0x%lx\n", fd, (long)dev->device); retcode = fasync_helper(fd, filp, on, &dev->buf_async); if (retcode < 0) return retcode; return 0; diff -Nru a/drivers/char/drm/drm_ioctl.h b/drivers/char/drm/drm_ioctl.h --- a/drivers/char/drm/drm_ioctl.h Wed Apr 2 22:24:04 2003 +++ b/drivers/char/drm/drm_ioctl.h Wed Apr 2 22:24:04 2003 @@ -40,6 +40,28 @@ if (copy_from_user(&p, (drm_irq_busid_t *)arg, sizeof(p))) return -EFAULT; +#ifdef __alpha__ + { + int domain = p.busnum >> 8; + p.busnum &= 0xff; + + /* + * Find the hose the device is on (the domain number is the + * hose index) and offset the bus by the root bus of that + * hose. + */ + for(dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,NULL); + dev; + dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,dev)) { + struct pci_controller *hose = dev->sysdata; + + if (hose->index == domain) { + p.busnum += hose->bus->number; + break; + } + } + } +#endif dev = pci_find_slot(p.busnum, PCI_DEVFN(p.devnum, p.funcnum)); if (!dev) { DRM_ERROR("pci_find_slot failed for %d:%d:%d\n", @@ -112,7 +134,7 @@ do { struct pci_dev *pci_dev; - int b, d, f; + int domain, b, d, f; char *p; for(p = dev->unique; p && *p && *p != ':'; p++); @@ -124,6 +146,27 @@ f = (int)simple_strtoul(p+1, &p, 10); if (*p) break; + domain = b >> 8; + b &= 0xff; + +#ifdef __alpha__ + /* + * Find the hose the device is on (the domain number is the + * hose index) and offset the bus by the root bus of that + * hose. + */ + for(pci_dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,NULL); + pci_dev; + pci_dev = pci_find_device(PCI_ANY_ID,PCI_ANY_ID,pci_dev)) { + struct pci_controller *hose = pci_dev->sysdata; + + if (hose->index == domain) { + b += hose->bus->number; + break; + } + } +#endif + pci_dev = pci_find_slot(b, PCI_DEVFN(d,f)); if (pci_dev) { dev->pdev = pci_dev; diff -Nru a/drivers/char/drm/drm_lists.h b/drivers/char/drm/drm_lists.h --- a/drivers/char/drm/drm_lists.h Wed Apr 2 22:24:07 2003 +++ b/drivers/char/drm/drm_lists.h Wed Apr 2 22:24:07 2003 @@ -72,8 +72,8 @@ left = DRM_LEFTCOUNT(bl); if (!left) { - DRM_ERROR("Overflow while adding buffer %d from pid %d\n", - buf->idx, buf->pid); + DRM_ERROR("Overflow while adding buffer %d from filp %p\n", + buf->idx, buf->filp); return -EINVAL; } #if __HAVE_DMA_HISTOGRAM diff -Nru a/drivers/char/drm/drm_lock.h b/drivers/char/drm/drm_lock.h --- a/drivers/char/drm/drm_lock.h Wed Apr 2 22:24:06 2003 +++ b/drivers/char/drm/drm_lock.h Wed Apr 2 22:24:06 2003 @@ -78,7 +78,7 @@ { unsigned int old, new, prev; - dev->lock.pid = 0; + dev->lock.filp = 0; do { old = *lock; new = context | _DRM_LOCK_HELD; @@ -91,19 +91,17 @@ __volatile__ unsigned int *lock, unsigned int context) { unsigned int old, new, prev; - pid_t pid = dev->lock.pid; - dev->lock.pid = 0; + dev->lock.filp = 0; do { old = *lock; new = 0; prev = cmpxchg(lock, old, new); } while (prev != old); if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) { - DRM_ERROR("%d freed heavyweight lock held by %d (pid %d)\n", + DRM_ERROR("%d freed heavyweight lock held by %d\n", context, - _DRM_LOCKING_CONTEXT(old), - pid); + _DRM_LOCKING_CONTEXT(old)); return 1; } wake_up_interruptible(&dev->lock.lock_queue); diff -Nru a/drivers/char/drm/drm_os_linux.h b/drivers/char/drm/drm_os_linux.h --- a/drivers/char/drm/drm_os_linux.h Wed Apr 2 22:24:07 2003 +++ b/drivers/char/drm/drm_os_linux.h Wed Apr 2 22:24:07 2003 @@ -2,16 +2,17 @@ #include /* For task queue support */ #include +#define DRMFILE struct file * #define DRM_IOCTL_ARGS struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data #define DRM_ERR(d) -(d) #define DRM_CURRENTPID current->pid #define DRM_UDELAY(d) udelay(d) -#define DRM_READ8(addr) readb(addr) -#define DRM_READ32(addr) readl(addr) -#define DRM_WRITE8(addr, val) writeb(val, addr) -#define DRM_WRITE32(addr, val) writel(val, addr) -#define DRM_READMEMORYBARRIER() mb() -#define DRM_WRITEMEMORYBARRIER() wmb() +#define DRM_READ8(map, offset) readb(((unsigned long)(map)->handle) + (offset)) +#define DRM_READ32(map, offset) readl(((unsigned long)(map)->handle) + (offset)) +#define DRM_WRITE8(map, offset, val) writeb(val, ((unsigned long)(map)->handle) + (offset)) +#define DRM_WRITE32(map, offset, val) writel(val, ((unsigned long)(map)->handle) + (offset)) +#define DRM_READMEMORYBARRIER(map) mb() +#define DRM_WRITEMEMORYBARRIER(map) wmb() #define DRM_DEVICE drm_file_t *priv = filp->private_data; \ drm_device_t *dev = priv->dev @@ -41,7 +42,7 @@ /* malloc/free without the overhead of DRM(alloc) */ #define DRM_MALLOC(x) kmalloc(x, GFP_KERNEL) -#define DRM_FREE(x) kfree(x) +#define DRM_FREE(x,size) kfree(x) #define DRM_GETSAREA() \ do { \ diff -Nru a/drivers/char/drm/drm_proc.h b/drivers/char/drm/drm_proc.h --- a/drivers/char/drm/drm_proc.h Wed Apr 2 22:24:04 2003 +++ b/drivers/char/drm/drm_proc.h Wed Apr 2 22:24:04 2003 @@ -147,10 +147,10 @@ *eof = 0; if (dev->unique) { - DRM_PROC_PRINT("%s 0x%x %s\n", - dev->name, dev->device, dev->unique); + DRM_PROC_PRINT("%s 0x%lx %s\n", + dev->name, (long)dev->device, dev->unique); } else { - DRM_PROC_PRINT("%s 0x%x\n", dev->name, dev->device); + DRM_PROC_PRINT("%s 0x%lx\n", dev->name, (long)dev->device); } if (len > request + offset) return request; diff -Nru a/drivers/char/drm/gamma_dma.c b/drivers/char/drm/gamma_dma.c --- a/drivers/char/drm/gamma_dma.c Wed Apr 2 22:24:07 2003 +++ b/drivers/char/drm/gamma_dma.c Wed Apr 2 22:24:07 2003 @@ -188,7 +188,7 @@ if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("Dispatching buffer %d from pid %d" " \"while locked\", but no lock held\n", - buf->idx, buf->pid); + buf->idx, current->pid); } } else { if (!locked && !gamma_lock_take(&dev->lock.hw_lock->lock, @@ -340,7 +340,8 @@ return retcode; } -static int gamma_dma_priority(drm_device_t *dev, drm_dma_t *d) +static int gamma_dma_priority(struct file *filp, + drm_device_t *dev, drm_dma_t *d) { unsigned long address; unsigned long length; @@ -378,15 +379,15 @@ continue; } buf = dma->buflist[ idx ]; - if (buf->pid != current->pid) { - DRM_ERROR("Process %d using buffer owned by %d\n", - current->pid, buf->pid); + if (buf->filp != filp) { + DRM_ERROR("Process %d using buffer not owned\n", + current->pid); retcode = -EINVAL; goto cleanup; } if (buf->list != DRM_LIST_NONE) { - DRM_ERROR("Process %d using %d's buffer on list %d\n", - current->pid, buf->pid, buf->list); + DRM_ERROR("Process %d using buffer on list %d\n", + current->pid, buf->list); retcode = -EINVAL; goto cleanup; } @@ -478,7 +479,8 @@ return retcode; } -static int gamma_dma_send_buffers(drm_device_t *dev, drm_dma_t *d) +static int gamma_dma_send_buffers(struct file *filp, + drm_device_t *dev, drm_dma_t *d) { DECLARE_WAITQUEUE(entry, current); drm_buf_t *last_buf = NULL; @@ -490,7 +492,7 @@ add_wait_queue(&last_buf->dma_wait, &entry); } - if ((retcode = gamma_dma_enqueue(dev, d))) { + if ((retcode = gamma_dma_enqueue(filp, d))) { if (d->flags & _DRM_DMA_BLOCK) remove_wait_queue(&last_buf->dma_wait, &entry); return retcode; @@ -520,14 +522,13 @@ } } if (retcode) { - DRM_ERROR("ctx%d w%d p%d c%d i%d l%d %d/%d\n", + DRM_ERROR("ctx%d w%d p%d c%ld i%d l%d pid:%d\n", d->context, last_buf->waiting, last_buf->pending, - DRM_WAITCOUNT(dev, d->context), + (long)DRM_WAITCOUNT(dev, d->context), last_buf->idx, last_buf->list, - last_buf->pid, current->pid); } } @@ -560,15 +561,15 @@ if (d.send_count) { if (d.flags & _DRM_DMA_PRIORITY) - retcode = gamma_dma_priority(dev, &d); + retcode = gamma_dma_priority(filp, dev, &d); else - retcode = gamma_dma_send_buffers(dev, &d); + retcode = gamma_dma_send_buffers(filp, dev, &d); } d.granted_count = 0; if (!retcode && d.request_count) { - retcode = gamma_dma_get_buffers(dev, &d); + retcode = gamma_dma_get_buffers(filp, &d); } DRM_DEBUG("%d returning, granted = %d\n", @@ -590,7 +591,7 @@ drm_buf_t *buf; int i; struct list_head *list; - unsigned int *pgt; + unsigned long *pgt; DRM_DEBUG( "%s\n", __FUNCTION__ ); @@ -643,7 +644,7 @@ for (i = 0; i < GLINT_DRI_BUF_COUNT; i++) { buf = dma->buflist[i]; - *pgt = (unsigned int)buf->address + 0x07; + *pgt = (unsigned long)buf->address + 0x07; pgt++; } diff -Nru a/drivers/char/drm/gamma_drv.h b/drivers/char/drm/gamma_drv.h --- a/drivers/char/drm/gamma_drv.h Wed Apr 2 22:24:05 2003 +++ b/drivers/char/drm/gamma_drv.h Wed Apr 2 22:24:05 2003 @@ -42,16 +42,6 @@ drm_map_t *mmio3; } drm_gamma_private_t; -#define LOCK_TEST_WITH_RETURN( dev ) \ -do { \ - if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || \ - dev->lock.pid != current->pid ) { \ - DRM_ERROR( "%s called without lock held\n", \ - __FUNCTION__ ); \ - return -EINVAL; \ - } \ -} while (0) - /* gamma_dma.c */ extern int gamma_dma_init( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg ); diff -Nru a/drivers/char/drm/i810.h b/drivers/char/drm/i810.h --- a/drivers/char/drm/i810.h Wed Apr 2 22:24:05 2003 +++ b/drivers/char/drm/i810.h Wed Apr 2 22:24:05 2003 @@ -86,7 +86,7 @@ */ #define __HAVE_RELEASE 1 #define DRIVER_RELEASE() do { \ - i810_reclaim_buffers( dev, priv->pid ); \ + i810_reclaim_buffers( filp ); \ } while (0) /* DMA customization: diff -Nru a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c --- a/drivers/char/drm/i810_dma.c Wed Apr 2 22:24:05 2003 +++ b/drivers/char/drm/i810_dma.c Wed Apr 2 22:24:05 2003 @@ -46,30 +46,10 @@ #define I810_BUF_UNMAPPED 0 #define I810_BUF_MAPPED 1 -#define RING_LOCALS unsigned int outring, ringmask; volatile char *virt; - -#define BEGIN_LP_RING(n) do { \ - if (0) DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", n, __FUNCTION__); \ - if (dev_priv->ring.space < n*4) \ - i810_wait_ring(dev, n*4); \ - dev_priv->ring.space -= n*4; \ - outring = dev_priv->ring.tail; \ - ringmask = dev_priv->ring.tail_mask; \ - virt = dev_priv->ring.virtual_start; \ -} while (0) - -#define ADVANCE_LP_RING() do { \ - if (0) DRM_DEBUG("ADVANCE_LP_RING\n"); \ - dev_priv->ring.tail = outring; \ - I810_WRITE(LP_RING + RING_TAIL, outring); \ -} while(0) - -#define OUT_RING(n) do { \ - if (0) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \ - *(volatile unsigned int *)(virt + outring) = n; \ - outring += 4; \ - outring &= ringmask; \ -} while (0) +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,2) +#define down_write down +#define up_write up +#endif static inline void i810_print_status_page(drm_device_t *dev) { @@ -178,11 +158,7 @@ if(buf_priv->currently_mapped == I810_BUF_MAPPED) return -EINVAL; -#if LINUX_VERSION_CODE <= 0x020402 - down( ¤t->mm->mmap_sem ); -#else down_write( ¤t->mm->mmap_sem ); -#endif old_fops = filp->f_op; filp->f_op = &i810_buffer_fops; dev_priv->mmap_buffer = buf; @@ -194,15 +170,12 @@ filp->f_op = old_fops; if ((unsigned long)buf_priv->virtual > -1024UL) { /* Real error */ - DRM_DEBUG("mmap error\n"); + DRM_ERROR("mmap error\n"); retcode = (signed int)buf_priv->virtual; buf_priv->virtual = 0; } -#if LINUX_VERSION_CODE <= 0x020402 - up( ¤t->mm->mmap_sem ); -#else up_write( ¤t->mm->mmap_sem ); -#endif + return retcode; } @@ -213,19 +186,13 @@ if(buf_priv->currently_mapped != I810_BUF_MAPPED) return -EINVAL; -#if LINUX_VERSION_CODE <= 0x020402 - down( ¤t->mm->mmap_sem ); -#else - down_write( ¤t->mm->mmap_sem ); -#endif + + down_write(¤t->mm->mmap_sem); retcode = do_munmap(current->mm, (unsigned long)buf_priv->virtual, (size_t) buf->total); -#if LINUX_VERSION_CODE <= 0x020402 - up( ¤t->mm->mmap_sem ); -#else - up_write( ¤t->mm->mmap_sem ); -#endif + up_write(¤t->mm->mmap_sem); + buf_priv->currently_mapped = I810_BUF_UNMAPPED; buf_priv->virtual = 0; @@ -235,7 +202,6 @@ static int i810_dma_get_buffer(drm_device_t *dev, drm_i810_dma_t *d, struct file *filp) { - drm_file_t *priv = filp->private_data; drm_buf_t *buf; drm_i810_buf_priv_t *buf_priv; int retcode = 0; @@ -250,10 +216,10 @@ retcode = i810_map_buffer(buf, filp); if(retcode) { i810_freelist_put(dev, buf); - DRM_DEBUG("mapbuf failed, retcode %d\n", retcode); + DRM_ERROR("mapbuf failed, retcode %d\n", retcode); return retcode; } - buf->pid = priv->pid; + buf->filp = filp; buf_priv = buf->dev_private; d->granted = 1; d->request_idx = buf->idx; @@ -314,7 +280,7 @@ end = jiffies + (HZ*3); iters++; - if((signed)(end - jiffies) <= 0) { + if(time_before(end, jiffies)) { DRM_ERROR("space: %d wanted %d\n", ring->space, n); DRM_ERROR("lockup\n"); goto out_wait_ring; @@ -882,8 +848,10 @@ } /* Must be called with the lock held */ -void i810_reclaim_buffers(drm_device_t *dev, pid_t pid) +void i810_reclaim_buffers(struct file *filp) { + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; drm_device_dma_t *dma = dev->dma; int i; @@ -897,7 +865,7 @@ drm_buf_t *buf = dma->buflist[ i ]; drm_i810_buf_priv_t *buf_priv = buf->dev_private; - if (buf->pid == pid && buf_priv) { + if (buf->filp == filp && buf_priv) { int used = cmpxchg(buf_priv->in_use, I810_BUF_CLIENT, I810_BUF_FREE); diff -Nru a/drivers/char/drm/i810_drv.h b/drivers/char/drm/i810_drv.h --- a/drivers/char/drm/i810_drv.h Wed Apr 2 22:24:07 2003 +++ b/drivers/char/drm/i810_drv.h Wed Apr 2 22:24:07 2003 @@ -88,7 +88,7 @@ unsigned int cmd, unsigned long arg); extern int i810_flush_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -extern void i810_reclaim_buffers(drm_device_t *dev, pid_t pid); +extern void i810_reclaim_buffers(struct file *filp); extern int i810_getage(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma); @@ -136,6 +136,33 @@ #define I810_READ16(reg) I810_DEREF16(reg) #define I810_WRITE16(reg,val) do { I810_DEREF16(reg) = val; } while (0) +#define I810_VERBOSE 0 +#define RING_LOCALS unsigned int outring, ringmask; \ + volatile char *virt; + +#define BEGIN_LP_RING(n) do { \ + if (I810_VERBOSE) \ + DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", n, __FUNCTION__); \ + if (dev_priv->ring.space < n*4) \ + i810_wait_ring(dev, n*4); \ + dev_priv->ring.space -= n*4; \ + outring = dev_priv->ring.tail; \ + ringmask = dev_priv->ring.tail_mask; \ + virt = dev_priv->ring.virtual_start; \ +} while (0) + +#define ADVANCE_LP_RING() do { \ + if (I810_VERBOSE) DRM_DEBUG("ADVANCE_LP_RING\n"); \ + dev_priv->ring.tail = outring; \ + I810_WRITE(LP_RING + RING_TAIL, outring); \ +} while(0) + +#define OUT_RING(n) do { \ + if (I810_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \ + *(volatile unsigned int *)(virt + outring) = n; \ + outring += 4; \ + outring &= ringmask; \ +} while (0) #define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23)) #define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23)) @@ -198,6 +225,7 @@ #define CMD_OP_Z_BUFFER_INFO ((0x0<<29)|(0x16<<23)) #define CMD_OP_DESTBUFFER_INFO ((0x0<<29)|(0x15<<23)) +#define CMD_OP_FRONTBUFFER_INFO ((0x0<<29)|(0x14<<23)) #define BR00_BITBLT_CLIENT 0x40000000 #define BR00_OP_COLOR_BLT 0x10000000 diff -Nru a/drivers/char/drm/i830.h b/drivers/char/drm/i830.h --- a/drivers/char/drm/i830.h Wed Apr 2 22:24:05 2003 +++ b/drivers/char/drm/i830.h Wed Apr 2 22:24:05 2003 @@ -45,22 +45,37 @@ #define DRIVER_NAME "i830" #define DRIVER_DESC "Intel 830M" -#define DRIVER_DATE "20020828" +#define DRIVER_DATE "20021108" +/* Interface history: + * + * 1.1: Original. + * 1.2: ? + * 1.3: New irq emit/wait ioctls. + * New pageflip ioctl. + * New getparam ioctl. + * State for texunits 3&4 in sarea. + * New (alternative) layout for texture state. + */ #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 2 -#define DRIVER_PATCHLEVEL 1 +#define DRIVER_MINOR 3 +#define DRIVER_PATCHLEVEL 2 #define DRIVER_IOCTLS \ [DRM_IOCTL_NR(DRM_IOCTL_I830_INIT)] = { i830_dma_init, 1, 1 }, \ - [DRM_IOCTL_NR(DRM_IOCTL_I830_VERTEX)] = { i830_dma_vertex, 1, 0 }, \ - [DRM_IOCTL_NR(DRM_IOCTL_I830_CLEAR)] = { i830_clear_bufs, 1, 0 }, \ - [DRM_IOCTL_NR(DRM_IOCTL_I830_FLUSH)] = { i830_flush_ioctl, 1, 0 }, \ - [DRM_IOCTL_NR(DRM_IOCTL_I830_GETAGE)] = { i830_getage, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I830_VERTEX)] = { i830_dma_vertex, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I830_CLEAR)] = { i830_clear_bufs, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I830_FLUSH)] = { i830_flush_ioctl, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I830_GETAGE)] = { i830_getage, 1, 0 }, \ [DRM_IOCTL_NR(DRM_IOCTL_I830_GETBUF)] = { i830_getbuf, 1, 0 }, \ - [DRM_IOCTL_NR(DRM_IOCTL_I830_SWAP)] = { i830_swap_bufs, 1, 0 }, \ - [DRM_IOCTL_NR(DRM_IOCTL_I830_COPY)] = { i830_copybuf, 1, 0 }, \ - [DRM_IOCTL_NR(DRM_IOCTL_I830_DOCOPY)] = { i830_docopy, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_I830_SWAP)] = { i830_swap_bufs, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I830_COPY)] = { i830_copybuf, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I830_DOCOPY)] = { i830_docopy, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I830_FLIP)] = { i830_flip_bufs, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I830_IRQ_EMIT)] = { i830_irq_emit, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I830_IRQ_WAIT)] = { i830_irq_wait, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I830_GETPARAM)] = { i830_getparam, 1, 0 }, \ + [DRM_IOCTL_NR(DRM_IOCTL_I830_SETPARAM)] = { i830_setparam, 1, 0 } #define __HAVE_COUNTERS 4 #define __HAVE_COUNTER6 _DRM_STAT_IRQ @@ -72,7 +87,7 @@ */ #define __HAVE_RELEASE 1 #define DRIVER_RELEASE() do { \ - i830_reclaim_buffers( dev, priv->pid ); \ + i830_reclaim_buffers( filp ); \ } while (0) /* DMA customization: @@ -87,10 +102,49 @@ i830_dma_quiescent( dev ); \ } while (0) -/* Don't need an irq any more. The template code will make sure that - * a noop stub is generated for compatibility. + +/* Driver will work either way: IRQ's save cpu time when waiting for + * the card, but are subject to subtle interactions between bios, + * hardware and the driver. */ -#define __HAVE_DMA_IRQ 0 +#define USE_IRQS 0 + + +#if USE_IRQS +#define __HAVE_DMA_IRQ 1 +#define __HAVE_SHARED_IRQ 1 + +#define DRIVER_PREINSTALL() do { \ + drm_i830_private_t *dev_priv = \ + (drm_i830_private_t *)dev->dev_private; \ + \ + I830_WRITE16( I830REG_HWSTAM, 0xffff ); \ + I830_WRITE16( I830REG_INT_MASK_R, 0x0 ); \ + I830_WRITE16( I830REG_INT_ENABLE_R, 0x0 ); \ +} while (0) + + +#define DRIVER_POSTINSTALL() do { \ + drm_i830_private_t *dev_priv = \ + (drm_i830_private_t *)dev->dev_private; \ + I830_WRITE16( I830REG_INT_ENABLE_R, 0x2 ); \ + atomic_set(&dev_priv->irq_received, 0); \ + atomic_set(&dev_priv->irq_emitted, 0); \ + init_waitqueue_head(&dev_priv->irq_queue); \ +} while (0) + + +/* This gets called too late to be useful: dev_priv has already been + * freed. + */ +#define DRIVER_UNINSTALL() do { \ +} while (0) + +#else +#define __HAVE_DMA_IRQ 0 +#endif + + /* Buffer customization: */ diff -Nru a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c --- a/drivers/char/drm/i830_dma.c Wed Apr 2 22:24:04 2003 +++ b/drivers/char/drm/i830_dma.c Wed Apr 2 22:24:04 2003 @@ -37,6 +37,7 @@ #include "i830_drm.h" #include "i830_drv.h" #include /* For task queue support */ +#include /* For FASTCALL on unlock_page() */ #include #define I830_BUF_FREE 2 @@ -46,8 +47,6 @@ #define I830_BUF_UNMAPPED 0 #define I830_BUF_MAPPED 1 -#define RING_LOCALS unsigned int outring, ringmask; volatile char *virt; - #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,2) #define down_write down #define up_write up @@ -60,32 +59,6 @@ #define UnlockPage(page) unlock_page(page) #endif -#define I830_VERBOSE 0 - -#define BEGIN_LP_RING(n) do { \ - if (I830_VERBOSE) \ - printk("BEGIN_LP_RING(%d) in %s\n", \ - n, __FUNCTION__); \ - if (dev_priv->ring.space < n*4) \ - i830_wait_ring(dev, n*4); \ - dev_priv->ring.space -= n*4; \ - outring = dev_priv->ring.tail; \ - ringmask = dev_priv->ring.tail_mask; \ - virt = dev_priv->ring.virtual_start; \ -} while (0) - -#define ADVANCE_LP_RING() do { \ - if (I830_VERBOSE) printk("ADVANCE_LP_RING %x\n", outring); \ - dev_priv->ring.tail = outring; \ - I830_WRITE(LP_RING + RING_TAIL, outring); \ -} while(0) - -#define OUT_RING(n) do { \ - if (I830_VERBOSE) printk(" OUT_RING %x\n", (int)(n)); \ - *(volatile unsigned int *)(virt + outring) = n; \ - outring += 4; \ - outring &= ringmask; \ -} while (0) static inline void i830_print_status_page(drm_device_t *dev) { @@ -237,7 +210,6 @@ static int i830_dma_get_buffer(drm_device_t *dev, drm_i830_dma_t *d, struct file *filp) { - drm_file_t *priv = filp->private_data; drm_buf_t *buf; drm_i830_buf_priv_t *buf_priv; int retcode = 0; @@ -245,7 +217,7 @@ buf = i830_freelist_get(dev); if (!buf) { retcode = -ENOMEM; - DRM_ERROR("retcode=%d\n", retcode); + DRM_DEBUG("retcode=%d\n", retcode); return retcode; } @@ -255,7 +227,7 @@ DRM_ERROR("mapbuf failed, retcode %d\n", retcode); return retcode; } - buf->pid = priv->pid; + buf->filp = filp; buf_priv = buf->dev_private; d->granted = 1; d->request_idx = buf->idx; @@ -279,12 +251,21 @@ dev_priv->ring.Size); } if(dev_priv->hw_status_page != 0UL) { - pci_free_consistent(dev->pdev, PAGE_SIZE, + pci_free_consistent(dev->pdev, PAGE_SIZE, (void *)dev_priv->hw_status_page, dev_priv->dma_status_page); /* Need to rewrite hardware status page */ I830_WRITE(0x02080, 0x1ffff000); } + + /* Disable interrupts here because after dev_private + * is freed, it's too late. + */ + if (dev->irq) { + I830_WRITE16( I830REG_INT_MASK_R, 0xffff ); + I830_WRITE16( I830REG_INT_ENABLE_R, 0x0 ); + } + DRM(free)(dev->dev_private, sizeof(drm_i830_private_t), DRM_MEM_DRIVER); dev->dev_private = NULL; @@ -298,7 +279,7 @@ return 0; } -static int i830_wait_ring(drm_device_t *dev, int n) +int i830_wait_ring(drm_device_t *dev, int n, const char *caller) { drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_ring_buffer_t *ring = &(dev_priv->ring); @@ -324,6 +305,7 @@ goto out_wait_ring; } udelay(1); + dev_priv->sarea_priv->perf_boxes |= I830_BOX_WAIT; } out_wait_ring: @@ -339,6 +321,9 @@ ring->tail = I830_READ(LP_RING + RING_TAIL) & TAIL_ADDR; ring->space = ring->head - (ring->tail+8); if (ring->space < 0) ring->space += ring->Size; + + if (ring->head == ring->tail) + dev_priv->sarea_priv->perf_boxes |= I830_BOX_RING_EMPTY; } static int i830_freelist_init(drm_device_t *dev, drm_i830_private_t *dev_priv) @@ -453,6 +438,8 @@ dev_priv->back_pitch = init->back_pitch; dev_priv->depth_pitch = init->depth_pitch; + dev_priv->do_boxes = 0; + dev_priv->use_mi_batchbuffer_start = 0; /* Program Hardware Status Page */ dev_priv->hw_status_page = @@ -467,7 +454,7 @@ memset((void *) dev_priv->hw_status_page, 0, PAGE_SIZE); DRM_DEBUG("hw status page @ %lx\n", dev_priv->hw_status_page); - I830_WRITE(0x02080, dev_priv->dma_status_page); + I830_WRITE(0x02080, virt_to_bus((void *)dev_priv->hw_status_page)); DRM_DEBUG("Enabled hardware status page\n"); /* Now we need to init our freelist */ @@ -528,11 +515,7 @@ unsigned int tmp; RING_LOCALS; - BEGIN_LP_RING( I830_CTX_SETUP_SIZE + 2 ); - - OUT_RING( GFX_OP_STIPPLE ); - OUT_RING( 0 ); - + BEGIN_LP_RING( I830_CTX_SETUP_SIZE + 4 ); for ( i = 0 ; i < I830_CTXREG_BLENDCOLR0 ; i++ ) { tmp = code[i]; @@ -570,38 +553,44 @@ ADVANCE_LP_RING(); } -static void i830EmitTexVerified( drm_device_t *dev, - volatile unsigned int *code ) +static void i830EmitTexVerified( drm_device_t *dev, unsigned int *code ) { drm_i830_private_t *dev_priv = dev->dev_private; int i, j = 0; unsigned int tmp; RING_LOCALS; - BEGIN_LP_RING( I830_TEX_SETUP_SIZE ); - - OUT_RING( GFX_OP_MAP_INFO ); - OUT_RING( code[I830_TEXREG_MI1] ); - OUT_RING( code[I830_TEXREG_MI2] ); - OUT_RING( code[I830_TEXREG_MI3] ); - OUT_RING( code[I830_TEXREG_MI4] ); - OUT_RING( code[I830_TEXREG_MI5] ); - - for ( i = 6 ; i < I830_TEX_SETUP_SIZE ; i++ ) { - tmp = code[i]; - OUT_RING( tmp ); - j++; - } + if (code[I830_TEXREG_MI0] == GFX_OP_MAP_INFO || + (code[I830_TEXREG_MI0] & ~(0xf*LOAD_TEXTURE_MAP0)) == + (STATE3D_LOAD_STATE_IMMEDIATE_2|4)) { + + BEGIN_LP_RING( I830_TEX_SETUP_SIZE ); + + OUT_RING( code[I830_TEXREG_MI0] ); /* TM0LI */ + OUT_RING( code[I830_TEXREG_MI1] ); /* TM0S0 */ + OUT_RING( code[I830_TEXREG_MI2] ); /* TM0S1 */ + OUT_RING( code[I830_TEXREG_MI3] ); /* TM0S2 */ + OUT_RING( code[I830_TEXREG_MI4] ); /* TM0S3 */ + OUT_RING( code[I830_TEXREG_MI5] ); /* TM0S4 */ + + for ( i = 6 ; i < I830_TEX_SETUP_SIZE ; i++ ) { + tmp = code[i]; + OUT_RING( tmp ); + j++; + } - if (j & 1) - OUT_RING( 0 ); + if (j & 1) + OUT_RING( 0 ); - ADVANCE_LP_RING(); + ADVANCE_LP_RING(); + } + else + printk("rejected packet %x\n", code[0]); } static void i830EmitTexBlendVerified( drm_device_t *dev, - volatile unsigned int *code, - volatile unsigned int num) + unsigned int *code, + unsigned int num) { drm_i830_private_t *dev_priv = dev->dev_private; int i, j = 0; @@ -611,7 +600,7 @@ if (!num) return; - BEGIN_LP_RING( num ); + BEGIN_LP_RING( num + 1 ); for ( i = 0 ; i < num ; i++ ) { tmp = code[i]; @@ -634,6 +623,8 @@ int i; RING_LOCALS; + return; + BEGIN_LP_RING( 258 ); if(is_shared == 1) { @@ -647,42 +638,41 @@ OUT_RING(palette[i]); } OUT_RING(0); + /* KW: WHERE IS THE ADVANCE_LP_RING? This is effectively a noop! + */ } /* Need to do some additional checking when setting the dest buffer. */ static void i830EmitDestVerified( drm_device_t *dev, - volatile unsigned int *code ) + unsigned int *code ) { drm_i830_private_t *dev_priv = dev->dev_private; unsigned int tmp; RING_LOCALS; - BEGIN_LP_RING( I830_DEST_SETUP_SIZE + 6 ); + BEGIN_LP_RING( I830_DEST_SETUP_SIZE + 10 ); + tmp = code[I830_DESTREG_CBUFADDR]; - if (tmp == dev_priv->front_di1) { - /* Don't use fence when front buffer rendering */ - OUT_RING( CMD_OP_DESTBUFFER_INFO ); - OUT_RING( BUF_3D_ID_COLOR_BACK | - BUF_3D_PITCH(dev_priv->back_pitch * dev_priv->cpp) ); - OUT_RING( tmp ); + if (tmp == dev_priv->front_di1 || tmp == dev_priv->back_di1) { + if (((int)outring) & 8) { + OUT_RING(0); + OUT_RING(0); + } OUT_RING( CMD_OP_DESTBUFFER_INFO ); - OUT_RING( BUF_3D_ID_DEPTH | - BUF_3D_PITCH(dev_priv->depth_pitch * dev_priv->cpp)); - OUT_RING( dev_priv->zi1 ); - } else if(tmp == dev_priv->back_di1) { - OUT_RING( CMD_OP_DESTBUFFER_INFO ); OUT_RING( BUF_3D_ID_COLOR_BACK | BUF_3D_PITCH(dev_priv->back_pitch * dev_priv->cpp) | BUF_3D_USE_FENCE); OUT_RING( tmp ); + OUT_RING( 0 ); OUT_RING( CMD_OP_DESTBUFFER_INFO ); OUT_RING( BUF_3D_ID_DEPTH | BUF_3D_USE_FENCE | BUF_3D_PITCH(dev_priv->depth_pitch * dev_priv->cpp)); OUT_RING( dev_priv->zi1 ); + OUT_RING( 0 ); } else { DRM_ERROR("bad di1 %x (allow %x or %x)\n", tmp, dev_priv->front_di1, dev_priv->back_di1); @@ -710,21 +700,35 @@ OUT_RING( 0 ); } - OUT_RING( code[I830_DESTREG_SENABLE] ); - OUT_RING( GFX_OP_SCISSOR_RECT ); OUT_RING( code[I830_DESTREG_SR1] ); OUT_RING( code[I830_DESTREG_SR2] ); + OUT_RING( 0 ); ADVANCE_LP_RING(); } +static void i830EmitStippleVerified( drm_device_t *dev, + unsigned int *code ) +{ + drm_i830_private_t *dev_priv = dev->dev_private; + RING_LOCALS; + + BEGIN_LP_RING( 2 ); + OUT_RING( GFX_OP_STIPPLE ); + OUT_RING( code[1] ); + ADVANCE_LP_RING(); +} + + static void i830EmitState( drm_device_t *dev ) { drm_i830_private_t *dev_priv = dev->dev_private; drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int dirty = sarea_priv->dirty; + DRM_DEBUG("%s %x\n", __FUNCTION__, dirty); + if (dirty & I830_UPLOAD_BUFFERS) { i830EmitDestVerified( dev, sarea_priv->BufferState ); sarea_priv->dirty &= ~I830_UPLOAD_BUFFERS; @@ -758,17 +762,154 @@ } if (dirty & I830_UPLOAD_TEX_PALETTE_SHARED) { - i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 1); + i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 1); + } else { + if (dirty & I830_UPLOAD_TEX_PALETTE_N(0)) { + i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 0); + sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(0); + } + if (dirty & I830_UPLOAD_TEX_PALETTE_N(1)) { + i830EmitTexPalette(dev, sarea_priv->Palette[1], 1, 0); + sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(1); + } + + /* 1.3: + */ +#if 0 + if (dirty & I830_UPLOAD_TEX_PALETTE_N(2)) { + i830EmitTexPalette(dev, sarea_priv->Palette2[0], 0, 0); + sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(2); + } + if (dirty & I830_UPLOAD_TEX_PALETTE_N(3)) { + i830EmitTexPalette(dev, sarea_priv->Palette2[1], 1, 0); + sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(2); + } +#endif + } + + /* 1.3: + */ + if (dirty & I830_UPLOAD_STIPPLE) { + i830EmitStippleVerified( dev, + sarea_priv->StippleState); + sarea_priv->dirty &= ~I830_UPLOAD_STIPPLE; + } + + if (dirty & I830_UPLOAD_TEX2) { + i830EmitTexVerified( dev, sarea_priv->TexState2 ); + sarea_priv->dirty &= ~I830_UPLOAD_TEX2; + } + + if (dirty & I830_UPLOAD_TEX3) { + i830EmitTexVerified( dev, sarea_priv->TexState3 ); + sarea_priv->dirty &= ~I830_UPLOAD_TEX3; + } + + + if (dirty & I830_UPLOAD_TEXBLEND2) { + i830EmitTexBlendVerified( + dev, + sarea_priv->TexBlendState2, + sarea_priv->TexBlendStateWordsUsed2); + + sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND2; + } + + if (dirty & I830_UPLOAD_TEXBLEND3) { + i830EmitTexBlendVerified( + dev, + sarea_priv->TexBlendState3, + sarea_priv->TexBlendStateWordsUsed3); + sarea_priv->dirty &= ~I830_UPLOAD_TEXBLEND3; + } +} + +/* ================================================================ + * Performance monitoring functions + */ + +static void i830_fill_box( drm_device_t *dev, + int x, int y, int w, int h, + int r, int g, int b ) +{ + drm_i830_private_t *dev_priv = dev->dev_private; + u32 color; + unsigned int BR13, CMD; + RING_LOCALS; + + BR13 = (0xF0 << 16) | (dev_priv->pitch * dev_priv->cpp) | (1<<24); + CMD = XY_COLOR_BLT_CMD; + x += dev_priv->sarea_priv->boxes[0].x1; + y += dev_priv->sarea_priv->boxes[0].y1; + + if (dev_priv->cpp == 4) { + BR13 |= (1<<25); + CMD |= (XY_COLOR_BLT_WRITE_ALPHA | XY_COLOR_BLT_WRITE_RGB); + color = (((0xff) << 24) | (r << 16) | (g << 8) | b); } else { - if (dirty & I830_UPLOAD_TEX_PALETTE_N(0)) { - i830EmitTexPalette(dev, sarea_priv->Palette[0], 0, 0); - sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(0); - } - if (dirty & I830_UPLOAD_TEX_PALETTE_N(1)) { - i830EmitTexPalette(dev, sarea_priv->Palette[1], 1, 0); - sarea_priv->dirty &= ~I830_UPLOAD_TEX_PALETTE_N(1); - } + color = (((r & 0xf8) << 8) | + ((g & 0xfc) << 3) | + ((b & 0xf8) >> 3)); } + + BEGIN_LP_RING( 6 ); + OUT_RING( CMD ); + OUT_RING( BR13 ); + OUT_RING( (y << 16) | x ); + OUT_RING( ((y+h) << 16) | (x+w) ); + + if ( dev_priv->current_page == 1 ) { + OUT_RING( dev_priv->front_offset ); + } else { + OUT_RING( dev_priv->back_offset ); + } + + OUT_RING( color ); + ADVANCE_LP_RING(); +} + +static void i830_cp_performance_boxes( drm_device_t *dev ) +{ + drm_i830_private_t *dev_priv = dev->dev_private; + + /* Purple box for page flipping + */ + if ( dev_priv->sarea_priv->perf_boxes & I830_BOX_FLIP ) + i830_fill_box( dev, 4, 4, 8, 8, 255, 0, 255 ); + + /* Red box if we have to wait for idle at any point + */ + if ( dev_priv->sarea_priv->perf_boxes & I830_BOX_WAIT ) + i830_fill_box( dev, 16, 4, 8, 8, 255, 0, 0 ); + + /* Blue box: lost context? + */ + if ( dev_priv->sarea_priv->perf_boxes & I830_BOX_LOST_CONTEXT ) + i830_fill_box( dev, 28, 4, 8, 8, 0, 0, 255 ); + + /* Yellow box for texture swaps + */ + if ( dev_priv->sarea_priv->perf_boxes & I830_BOX_TEXTURE_LOAD ) + i830_fill_box( dev, 40, 4, 8, 8, 255, 255, 0 ); + + /* Green box if hardware never idles (as far as we can tell) + */ + if ( !(dev_priv->sarea_priv->perf_boxes & I830_BOX_RING_EMPTY) ) + i830_fill_box( dev, 64, 4, 8, 8, 0, 255, 0 ); + + + /* Draw bars indicating number of buffers allocated + * (not a great measure, easily confused) + */ + if (dev_priv->dma_used) { + int bar = dev_priv->dma_used / 10240; + if (bar > 100) bar = 100; + if (bar < 1) bar = 1; + i830_fill_box( dev, 4, 16, bar, 4, 196, 128, 128 ); + dev_priv->dma_used = 0; + } + + dev_priv->sarea_priv->perf_boxes = 0; } static void i830_dma_dispatch_clear( drm_device_t *dev, int flags, @@ -786,6 +927,15 @@ unsigned int BR13, CMD, D_CMD; RING_LOCALS; + + if ( dev_priv->current_page == 1 ) { + unsigned int tmp = flags; + + flags &= ~(I830_FRONT | I830_BACK); + if ( tmp & I830_FRONT ) flags |= I830_BACK; + if ( tmp & I830_BACK ) flags |= I830_FRONT; + } + i830_kernel_lost_context(dev); switch(cpp) { @@ -865,13 +1015,17 @@ drm_clip_rect_t *pbox = sarea_priv->boxes; int pitch = dev_priv->pitch; int cpp = dev_priv->cpp; - int ofs = dev_priv->back_offset; int i; unsigned int CMD, BR13; RING_LOCALS; DRM_DEBUG("swapbuffers\n"); + i830_kernel_lost_context(dev); + + if (dev_priv->do_boxes) + i830_cp_performance_boxes( dev ); + switch(cpp) { case 2: BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24); @@ -888,7 +1042,6 @@ break; } - i830_kernel_lost_context(dev); if (nbox > I830_NR_SAREA_CLIPRECTS) nbox = I830_NR_SAREA_CLIPRECTS; @@ -908,23 +1061,72 @@ BEGIN_LP_RING( 8 ); OUT_RING( CMD ); OUT_RING( BR13 ); + OUT_RING( (pbox->y1 << 16) | pbox->x1 ); + OUT_RING( (pbox->y2 << 16) | pbox->x2 ); - OUT_RING( (pbox->y1 << 16) | - pbox->x1 ); - OUT_RING( (pbox->y2 << 16) | - pbox->x2 ); - - OUT_RING( dev_priv->front_offset ); - OUT_RING( (pbox->y1 << 16) | - pbox->x1 ); + if (dev_priv->current_page == 0) + OUT_RING( dev_priv->front_offset ); + else + OUT_RING( dev_priv->back_offset ); + OUT_RING( (pbox->y1 << 16) | pbox->x1 ); OUT_RING( BR13 & 0xffff ); - OUT_RING( ofs ); + + if (dev_priv->current_page == 0) + OUT_RING( dev_priv->back_offset ); + else + OUT_RING( dev_priv->front_offset ); ADVANCE_LP_RING(); } } +static void i830_dma_dispatch_flip( drm_device_t *dev ) +{ + drm_i830_private_t *dev_priv = dev->dev_private; + RING_LOCALS; + + DRM_DEBUG( "%s: page=%d pfCurrentPage=%d\n", + __FUNCTION__, + dev_priv->current_page, + dev_priv->sarea_priv->pf_current_page); + + i830_kernel_lost_context(dev); + + if (dev_priv->do_boxes) { + dev_priv->sarea_priv->perf_boxes |= I830_BOX_FLIP; + i830_cp_performance_boxes( dev ); + } + + + BEGIN_LP_RING( 2 ); + OUT_RING( INST_PARSER_CLIENT | INST_OP_FLUSH | INST_FLUSH_MAP_CACHE ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); + + BEGIN_LP_RING( 6 ); + OUT_RING( CMD_OP_DISPLAYBUFFER_INFO | ASYNC_FLIP ); + OUT_RING( 0 ); + if ( dev_priv->current_page == 0 ) { + OUT_RING( dev_priv->back_offset ); + dev_priv->current_page = 1; + } else { + OUT_RING( dev_priv->front_offset ); + dev_priv->current_page = 0; + } + OUT_RING(0); + ADVANCE_LP_RING(); + + + BEGIN_LP_RING( 2 ); + OUT_RING( MI_WAIT_FOR_EVENT | + MI_WAIT_FOR_PLANE_A_FLIP ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); + + + dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; +} static void i830_dma_dispatch_vertex(drm_device_t *dev, drm_buf_t *buf, @@ -977,8 +1179,10 @@ sarea_priv->vertex_prim | ((used/4)-2)); - vp[used/4] = MI_BATCH_BUFFER_END; - used += 4; + if (dev_priv->use_mi_batchbuffer_start) { + vp[used/4] = MI_BATCH_BUFFER_END; + used += 4; + } if (used & 4) { vp[used/4] = 0; @@ -1001,11 +1205,21 @@ ADVANCE_LP_RING(); } - BEGIN_LP_RING(2); - OUT_RING( MI_BATCH_BUFFER_START | (2<<6) ); - OUT_RING( start | MI_BATCH_NON_SECURE ); - ADVANCE_LP_RING(); - + if (dev_priv->use_mi_batchbuffer_start) { + BEGIN_LP_RING(2); + OUT_RING( MI_BATCH_BUFFER_START | (2<<6) ); + OUT_RING( start | MI_BATCH_NON_SECURE ); + ADVANCE_LP_RING(); + } + else { + BEGIN_LP_RING(4); + OUT_RING( MI_BATCH_BUFFER ); + OUT_RING( start | MI_BATCH_NON_SECURE ); + OUT_RING( start + used - 4 ); + OUT_RING( 0 ); + ADVANCE_LP_RING(); + } + } while (++i < nbox); } @@ -1043,7 +1257,7 @@ OUT_RING( 0 ); ADVANCE_LP_RING(); - i830_wait_ring( dev, dev_priv->ring.Size - 8 ); + i830_wait_ring( dev, dev_priv->ring.Size - 8, __FUNCTION__ ); } static int i830_flush_queue(drm_device_t *dev) @@ -1060,7 +1274,7 @@ OUT_RING( 0 ); ADVANCE_LP_RING(); - i830_wait_ring( dev, dev_priv->ring.Size - 8 ); + i830_wait_ring( dev, dev_priv->ring.Size - 8, __FUNCTION__ ); for (i = 0; i < dma->buf_count; i++) { drm_buf_t *buf = dma->buflist[ i ]; @@ -1079,8 +1293,10 @@ } /* Must be called with the lock held */ -void i830_reclaim_buffers(drm_device_t *dev, pid_t pid) +void i830_reclaim_buffers( struct file *filp ) { + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; drm_device_dma_t *dma = dev->dma; int i; @@ -1094,7 +1310,7 @@ drm_buf_t *buf = dma->buflist[ i ]; drm_i830_buf_priv_t *buf_priv = buf->dev_private; - if (buf->pid == pid && buf_priv) { + if (buf->filp == filp && buf_priv) { int used = cmpxchg(buf_priv->in_use, I830_BUF_CLIENT, I830_BUF_FREE); @@ -1200,6 +1416,53 @@ return 0; } + + +/* Not sure why this isn't set all the time: + */ +static void i830_do_init_pageflip( drm_device_t *dev ) +{ + drm_i830_private_t *dev_priv = dev->dev_private; + + DRM_DEBUG("%s\n", __FUNCTION__); + dev_priv->page_flipping = 1; + dev_priv->current_page = 0; + dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; +} + +int i830_do_cleanup_pageflip( drm_device_t *dev ) +{ + drm_i830_private_t *dev_priv = dev->dev_private; + + DRM_DEBUG("%s\n", __FUNCTION__); + if (dev_priv->current_page != 0) + i830_dma_dispatch_flip( dev ); + + dev_priv->page_flipping = 0; + return 0; +} + +int i830_flip_bufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_i830_private_t *dev_priv = dev->dev_private; + + DRM_DEBUG("%s\n", __FUNCTION__); + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i830_flip_buf called without lock held\n"); + return -EINVAL; + } + + if (!dev_priv->page_flipping) + i830_do_init_pageflip( dev ); + + i830_dma_dispatch_flip( dev ); + return 0; +} + int i830_getage(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -1261,5 +1524,68 @@ int i830_docopy(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { + return 0; +} + + + +int i830_getparam( struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_i830_private_t *dev_priv = dev->dev_private; + drm_i830_getparam_t param; + int value; + + if ( !dev_priv ) { + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); + return -EINVAL; + } + + if (copy_from_user(¶m, (drm_i830_getparam_t *)arg, sizeof(param) )) + return -EFAULT; + + switch( param.param ) { + case I830_PARAM_IRQ_ACTIVE: + value = dev->irq ? 1 : 0; + break; + default: + return -EINVAL; + } + + if ( copy_to_user( param.value, &value, sizeof(int) ) ) { + DRM_ERROR( "copy_to_user\n" ); + return -EFAULT; + } + + return 0; +} + + +int i830_setparam( struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_i830_private_t *dev_priv = dev->dev_private; + drm_i830_setparam_t param; + + if ( !dev_priv ) { + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); + return -EINVAL; + } + + if (copy_from_user(¶m, (drm_i830_setparam_t *)arg, sizeof(param) )) + return -EFAULT; + + switch( param.param ) { + case I830_SETPARAM_USE_MI_BATCHBUFFER_START: + dev_priv->use_mi_batchbuffer_start = param.value; + break; + default: + return -EINVAL; + } + return 0; } diff -Nru a/drivers/char/drm/i830_drm.h b/drivers/char/drm/i830_drm.h --- a/drivers/char/drm/i830_drm.h Wed Apr 2 22:24:05 2003 +++ b/drivers/char/drm/i830_drm.h Wed Apr 2 22:24:05 2003 @@ -3,6 +3,9 @@ /* WARNING: These defines must be the same as what the Xserver uses. * if you change them, you must change the defines in the Xserver. + * + * KW: Actually, you can't ever change them because doing so would + * break backwards compatibility. */ #ifndef _I830_DEFINES_ @@ -18,14 +21,12 @@ #define I830_NR_TEX_REGIONS 64 #define I830_LOG_MIN_TEX_REGION_SIZE 16 -/* if defining I830_ENABLE_4_TEXTURES, do it in i830_3d_reg.h, too */ -#if !defined(I830_ENABLE_4_TEXTURES) +/* KW: These aren't correct but someone set them to two and then + * released the module. Now we can't change them as doing so would + * break backwards compatibility. + */ #define I830_TEXTURE_COUNT 2 -#define I830_TEXBLEND_COUNT 2 /* always same as TEXTURE_COUNT? */ -#else /* defined(I830_ENABLE_4_TEXTURES) */ -#define I830_TEXTURE_COUNT 4 -#define I830_TEXBLEND_COUNT 4 /* always same as TEXTURE_COUNT? */ -#endif /* I830_ENABLE_4_TEXTURES */ +#define I830_TEXBLEND_COUNT I830_TEXTURE_COUNT #define I830_TEXBLEND_SIZE 12 /* (4 args + op) * 2 + COLOR_FACTOR */ @@ -57,6 +58,7 @@ #define I830_UPLOAD_TEXBLEND_MASK 0xf00000 #define I830_UPLOAD_TEX_PALETTE_N(n) (0x1000000 << (n)) #define I830_UPLOAD_TEX_PALETTE_SHARED 0x4000000 +#define I830_UPLOAD_STIPPLE 0x8000000 /* Indices into buf.Setup where various bits of state are mirrored per * context and per buffer. These can be fired at the card as a unit, @@ -73,7 +75,6 @@ */ #define I830_DESTREG_CBUFADDR 0 -/* Invarient */ #define I830_DESTREG_DBUFADDR 1 #define I830_DESTREG_DV0 2 #define I830_DESTREG_DV1 3 @@ -109,6 +110,13 @@ #define I830_CTXREG_MCSB1 16 #define I830_CTX_SETUP_SIZE 17 +/* 1.3: Stipple state + */ +#define I830_STPREG_ST0 0 +#define I830_STPREG_ST1 1 +#define I830_STP_SETUP_SIZE 2 + + /* Texture state (per tex unit) */ @@ -124,6 +132,18 @@ #define I830_TEXREG_MCS 9 /* GFX_OP_MAP_COORD_SETS */ #define I830_TEX_SETUP_SIZE 10 +#define I830_TEXREG_TM0LI 0 /* load immediate 2 texture map n */ +#define I830_TEXREG_TM0S0 1 +#define I830_TEXREG_TM0S1 2 +#define I830_TEXREG_TM0S2 3 +#define I830_TEXREG_TM0S3 4 +#define I830_TEXREG_TM0S4 5 +#define I830_TEXREG_NOP0 6 /* noop */ +#define I830_TEXREG_NOP1 7 /* noop */ +#define I830_TEXREG_NOP2 8 /* noop */ +#define __I830_TEXREG_MCS 9 /* GFX_OP_MAP_COORD_SETS -- shared */ +#define __I830_TEX_SETUP_SIZE 10 + #define I830_FRONT 0x1 #define I830_BACK 0x2 #define I830_DEPTH 0x4 @@ -199,8 +219,35 @@ int ctxOwner; /* last context to upload state */ int vertex_prim; + + int pf_enabled; /* is pageflipping allowed? */ + int pf_active; + int pf_current_page; /* which buffer is being displayed? */ + + int perf_boxes; /* performance boxes to be displayed */ + + /* Here's the state for texunits 2,3: + */ + unsigned int TexState2[I830_TEX_SETUP_SIZE]; + unsigned int TexBlendState2[I830_TEXBLEND_SIZE]; + unsigned int TexBlendStateWordsUsed2; + + unsigned int TexState3[I830_TEX_SETUP_SIZE]; + unsigned int TexBlendState3[I830_TEXBLEND_SIZE]; + unsigned int TexBlendStateWordsUsed3; + + unsigned int StippleState[I830_STP_SETUP_SIZE]; } drm_i830_sarea_t; +/* Flags for perf_boxes + */ +#define I830_BOX_RING_EMPTY 0x1 /* populated by kernel */ +#define I830_BOX_FLIP 0x2 /* populated by kernel */ +#define I830_BOX_WAIT 0x4 /* populated by kernel & client */ +#define I830_BOX_TEXTURE_LOAD 0x8 /* populated by kernel */ +#define I830_BOX_LOST_CONTEXT 0x10 /* populated by client */ + + /* I830 specific ioctls * The device specific ioctl range is 0x40 to 0x79. */ @@ -213,6 +260,11 @@ #define DRM_IOCTL_I830_SWAP DRM_IO ( 0x46) #define DRM_IOCTL_I830_COPY DRM_IOW( 0x47, drm_i830_copy_t) #define DRM_IOCTL_I830_DOCOPY DRM_IO ( 0x48) +#define DRM_IOCTL_I830_FLIP DRM_IO ( 0x49) +#define DRM_IOCTL_I830_IRQ_EMIT DRM_IOWR(0x4a, drm_i830_irq_emit_t) +#define DRM_IOCTL_I830_IRQ_WAIT DRM_IOW( 0x4b, drm_i830_irq_wait_t) +#define DRM_IOCTL_I830_GETPARAM DRM_IOWR(0x4c, drm_i830_getparam_t) +#define DRM_IOCTL_I830_SETPARAM DRM_IOWR(0x4d, drm_i830_setparam_t) typedef struct _drm_i830_clear { int clear_color; @@ -247,5 +299,37 @@ int request_size; int granted; } drm_i830_dma_t; + + +/* 1.3: Userspace can request & wait on irq's: + */ +typedef struct drm_i830_irq_emit { + int *irq_seq; +} drm_i830_irq_emit_t; + +typedef struct drm_i830_irq_wait { + int irq_seq; +} drm_i830_irq_wait_t; + + +/* 1.3: New ioctl to query kernel params: + */ +#define I830_PARAM_IRQ_ACTIVE 1 + +typedef struct drm_i830_getparam { + int param; + int *value; +} drm_i830_getparam_t; + + +/* 1.3: New ioctl to set kernel params: + */ +#define I830_SETPARAM_USE_MI_BATCHBUFFER_START 1 + +typedef struct drm_i830_setparam { + int param; + int value; +} drm_i830_setparam_t; + #endif /* _I830_DRM_H_ */ diff -Nru a/drivers/char/drm/i830_drv.h b/drivers/char/drm/i830_drv.h --- a/drivers/char/drm/i830_drv.h Wed Apr 2 22:24:06 2003 +++ b/drivers/char/drm/i830_drv.h Wed Apr 2 22:24:06 2003 @@ -78,6 +78,19 @@ int back_pitch; int depth_pitch; unsigned int cpp; + + int do_boxes; + int dma_used; + + int current_page; + int page_flipping; + + wait_queue_head_t irq_queue; + atomic_t irq_received; + atomic_t irq_emitted; + + int use_mi_batchbuffer_start; + } drm_i830_private_t; /* i830_dma.c */ @@ -88,7 +101,7 @@ unsigned int cmd, unsigned long arg); extern int i830_flush_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -extern void i830_reclaim_buffers(drm_device_t *dev, pid_t pid); +extern void i830_reclaim_buffers(struct file *filp); extern int i830_getage(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma); @@ -108,6 +121,23 @@ extern int i830_clear_bufs(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +extern int i830_flip_bufs(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg); + +extern int i830_getparam( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); + +extern int i830_setparam( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); + +/* i830_irq.c */ +extern int i830_irq_emit( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int i830_irq_wait( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ); +extern int i830_wait_irq(drm_device_t *dev, int irq_nr); +extern int i830_emit_irq(drm_device_t *dev); + #define I830_BASE(reg) ((unsigned long) \ dev_priv->mmio_map->handle) @@ -119,12 +149,53 @@ #define I830_READ16(reg) I830_DEREF16(reg) #define I830_WRITE16(reg,val) do { I830_DEREF16(reg) = val; } while (0) + + +#define I830_VERBOSE 0 + +#define RING_LOCALS unsigned int outring, ringmask, outcount; \ + volatile char *virt; + +#define BEGIN_LP_RING(n) do { \ + if (I830_VERBOSE) \ + printk("BEGIN_LP_RING(%d) in %s\n", \ + n, __FUNCTION__); \ + if (dev_priv->ring.space < n*4) \ + i830_wait_ring(dev, n*4, __FUNCTION__); \ + outcount = 0; \ + outring = dev_priv->ring.tail; \ + ringmask = dev_priv->ring.tail_mask; \ + virt = dev_priv->ring.virtual_start; \ +} while (0) + + +#define OUT_RING(n) do { \ + if (I830_VERBOSE) printk(" OUT_RING %x\n", (int)(n)); \ + *(volatile unsigned int *)(virt + outring) = n; \ + outcount++; \ + outring += 4; \ + outring &= ringmask; \ +} while (0) + +#define ADVANCE_LP_RING() do { \ + if (I830_VERBOSE) printk("ADVANCE_LP_RING %x\n", outring); \ + dev_priv->ring.tail = outring; \ + dev_priv->ring.space -= outcount * 4; \ + I830_WRITE(LP_RING + RING_TAIL, outring); \ +} while(0) + +extern int i830_wait_ring(drm_device_t *dev, int n, const char *caller); + + #define GFX_OP_USER_INTERRUPT ((0<<29)|(2<<23)) #define GFX_OP_BREAKPOINT_INTERRUPT ((0<<29)|(1<<23)) #define CMD_REPORT_HEAD (7<<23) #define CMD_STORE_DWORD_IDX ((0x21<<23) | 0x1) #define CMD_OP_BATCH_BUFFER ((0x0<<29)|(0x30<<23)|0x1) +#define STATE3D_LOAD_STATE_IMMEDIATE_2 ((0x3<<29)|(0x1d<<24)|(0x03<<16)) +#define LOAD_TEXTURE_MAP0 (1<<11) + #define INST_PARSER_CLIENT 0x00000000 #define INST_OP_FLUSH 0x02000000 #define INST_FLUSH_MAP_CACHE 0x00000001 @@ -140,6 +211,9 @@ #define I830REG_INT_MASK_R 0x020a8 #define I830REG_INT_ENABLE_R 0x020a0 +#define I830_IRQ_RESERVED ((1<<13)|(3<<2)) + + #define LP_RING 0x2030 #define HP_RING 0x2040 #define RING_TAIL 0x00 @@ -182,6 +256,9 @@ #define CMD_OP_DESTBUFFER_INFO ((0x3<<29)|(0x1d<<24)|(0x8e<<16)|1) +#define CMD_OP_DISPLAYBUFFER_INFO ((0x0<<29)|(0x14<<23)|2) +#define ASYNC_FLIP (1<<22) + #define CMD_3D (0x3<<29) #define STATE3D_CONST_BLEND_COLOR_CMD (CMD_3D|(0x1d<<24)|(0x88<<16)) #define STATE3D_MAP_COORD_SETBIND_CMD (CMD_3D|(0x1d<<24)|(0x02<<16)) @@ -213,6 +290,11 @@ #define MI_BATCH_BUFFER_END (0xA<<23) #define MI_BATCH_NON_SECURE (1) +#define MI_WAIT_FOR_EVENT ((0x3<<23)) +#define MI_WAIT_FOR_PLANE_A_FLIP (1<<2) +#define MI_WAIT_FOR_PLANE_A_SCANLINES (1<<1) + +#define MI_LOAD_SCAN_LINES_INCL ((0x12<<23)) #endif diff -Nru a/drivers/char/drm/i830_irq.c b/drivers/char/drm/i830_irq.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/char/drm/i830_irq.c Wed Apr 2 22:24:08 2003 @@ -0,0 +1,177 @@ +/* i830_dma.c -- DMA support for the I830 -*- linux-c -*- + * + * Copyright 2002 Tungsten Graphics, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: Keith Whitwell + * + */ + +#include "i830.h" +#include "drmP.h" +#include "drm.h" +#include "i830_drm.h" +#include "i830_drv.h" +#include /* For task queue support */ +#include + + +void DRM(dma_service)(int irq, void *device, struct pt_regs *regs) +{ + drm_device_t *dev = (drm_device_t *)device; + drm_i830_private_t *dev_priv = (drm_i830_private_t *)dev->dev_private; + u16 temp; + + temp = I830_READ16(I830REG_INT_IDENTITY_R); + printk("%s: %x\n", __FUNCTION__, temp); + + if(temp == 0) + return; + + I830_WRITE16(I830REG_INT_IDENTITY_R, temp); + + if (temp & 2) { + atomic_inc(&dev_priv->irq_received); + wake_up_interruptible(&dev_priv->irq_queue); + } +} + + +int i830_emit_irq(drm_device_t *dev) +{ + drm_i830_private_t *dev_priv = dev->dev_private; + RING_LOCALS; + + DRM_DEBUG("%s\n", __FUNCTION__); + + atomic_inc(&dev_priv->irq_emitted); + + BEGIN_LP_RING(2); + OUT_RING( 0 ); + OUT_RING( GFX_OP_USER_INTERRUPT ); + ADVANCE_LP_RING(); + + return atomic_read(&dev_priv->irq_emitted); +} + + +int i830_wait_irq(drm_device_t *dev, int irq_nr) +{ + drm_i830_private_t *dev_priv = + (drm_i830_private_t *)dev->dev_private; + DECLARE_WAITQUEUE(entry, current); + unsigned long end = jiffies + HZ*3; + int ret = 0; + + DRM_DEBUG("%s\n", __FUNCTION__); + + if (atomic_read(&dev_priv->irq_received) >= irq_nr) + return 0; + + dev_priv->sarea_priv->perf_boxes |= I830_BOX_WAIT; + + add_wait_queue(&dev_priv->irq_queue, &entry); + + for (;;) { + current->state = TASK_INTERRUPTIBLE; + if (atomic_read(&dev_priv->irq_received) >= irq_nr) + break; + if((signed)(end - jiffies) <= 0) { + DRM_ERROR("timeout iir %x imr %x ier %x hwstam %x\n", + I830_READ16( I830REG_INT_IDENTITY_R ), + I830_READ16( I830REG_INT_MASK_R ), + I830_READ16( I830REG_INT_ENABLE_R ), + I830_READ16( I830REG_HWSTAM )); + + ret = -EBUSY; /* Lockup? Missed irq? */ + break; + } + schedule_timeout(HZ*3); + if (signal_pending(current)) { + ret = -EINTR; + break; + } + } + + current->state = TASK_RUNNING; + remove_wait_queue(&dev_priv->irq_queue, &entry); + return ret; +} + + +/* Needs the lock as it touches the ring. + */ +int i830_irq_emit( struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_i830_private_t *dev_priv = dev->dev_private; + drm_i830_irq_emit_t emit; + int result; + + if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { + DRM_ERROR("i830_irq_emit called without lock held\n"); + return -EINVAL; + } + + if ( !dev_priv ) { + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); + return -EINVAL; + } + + if (copy_from_user( &emit, (drm_i830_irq_emit_t *)arg, sizeof(emit) )) + return -EFAULT; + + result = i830_emit_irq( dev ); + + if ( copy_to_user( emit.irq_seq, &result, sizeof(int) ) ) { + DRM_ERROR( "copy_to_user\n" ); + return -EFAULT; + } + + return 0; +} + + +/* Doesn't need the hardware lock. + */ +int i830_irq_wait( struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_i830_private_t *dev_priv = dev->dev_private; + drm_i830_irq_wait_t irqwait; + + if ( !dev_priv ) { + DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); + return -EINVAL; + } + + if (copy_from_user( &irqwait, (drm_i830_irq_wait_t *)arg, + sizeof(irqwait) )) + return -EFAULT; + + return i830_wait_irq( dev, irqwait.irq_seq ); +} + diff -Nru a/drivers/char/drm/mga_dma.c b/drivers/char/drm/mga_dma.c --- a/drivers/char/drm/mga_dma.c Wed Apr 2 22:24:07 2003 +++ b/drivers/char/drm/mga_dma.c Wed Apr 2 22:24:07 2003 @@ -686,7 +686,7 @@ drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; drm_lock_t lock; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); DRM_COPY_FROM_USER_IOCTL( lock, (drm_lock_t *)data, sizeof(lock) ); @@ -720,7 +720,7 @@ DRM_DEVICE; drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); return mga_do_dma_reset( dev_priv ); } @@ -730,7 +730,8 @@ * DMA buffer management */ -static int mga_dma_get_buffers( drm_device_t *dev, drm_dma_t *d ) +static int mga_dma_get_buffers( DRMFILE filp, + drm_device_t *dev, drm_dma_t *d ) { drm_buf_t *buf; int i; @@ -739,7 +740,7 @@ buf = mga_freelist_get( dev ); if ( !buf ) return DRM_ERR(EAGAIN); - buf->pid = DRM_CURRENTPID; + buf->filp = filp; if ( DRM_COPY_TO_USER( &d->request_indices[i], &buf->idx, sizeof(buf->idx) ) ) @@ -761,7 +762,7 @@ drm_dma_t d; int ret = 0; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); DRM_COPY_FROM_USER_IOCTL( d, (drm_dma_t *)data, sizeof(d) ); @@ -786,7 +787,7 @@ d.granted_count = 0; if ( d.request_count ) { - ret = mga_dma_get_buffers( dev, &d ); + ret = mga_dma_get_buffers( filp, dev, &d ); } DRM_COPY_TO_USER_IOCTL( (drm_dma_t *)data, d, sizeof(d) ); diff -Nru a/drivers/char/drm/mga_drv.h b/drivers/char/drm/mga_drv.h --- a/drivers/char/drm/mga_drv.h Wed Apr 2 22:24:07 2003 +++ b/drivers/char/drm/mga_drv.h Wed Apr 2 22:24:07 2003 @@ -90,14 +90,14 @@ unsigned int texture_offset; unsigned int texture_size; - drm_map_t *sarea; - drm_map_t *fb; - drm_map_t *mmio; - drm_map_t *status; - drm_map_t *warp; - drm_map_t *primary; - drm_map_t *buffers; - drm_map_t *agp_textures; + drm_local_map_t *sarea; + drm_local_map_t *fb; + drm_local_map_t *mmio; + drm_local_map_t *status; + drm_local_map_t *warp; + drm_local_map_t *primary; + drm_local_map_t *buffers; + drm_local_map_t *agp_textures; } drm_mga_private_t; /* mga_dma.c */ @@ -131,32 +131,30 @@ extern int mga_warp_install_microcode( drm_mga_private_t *dev_priv ); extern int mga_warp_init( drm_mga_private_t *dev_priv ); -#define mga_flush_write_combine() DRM_WRITEMEMORYBARRIER() - +#define mga_flush_write_combine() DRM_WRITEMEMORYBARRIER(dev_priv->primary) +#if defined(__linux__) && defined(__alpha__) #define MGA_BASE( reg ) ((unsigned long)(dev_priv->mmio->handle)) #define MGA_ADDR( reg ) (MGA_BASE(reg) + reg) #define MGA_DEREF( reg ) *(volatile u32 *)MGA_ADDR( reg ) #define MGA_DEREF8( reg ) *(volatile u8 *)MGA_ADDR( reg ) -#ifdef __alpha__ #define MGA_READ( reg ) (_MGA_READ((u32 *)MGA_ADDR(reg))) #define MGA_READ8( reg ) (_MGA_READ((u8 *)MGA_ADDR(reg))) -#define MGA_WRITE( reg, val ) do { DRM_WRITEMEMORYBARRIER(); MGA_DEREF( reg ) = val; } while (0) -#define MGA_WRITE8( reg, val ) do { DRM_WRITEMEMORYBARRIER(); MGA_DEREF8( reg ) = val; } while (0) +#define MGA_WRITE( reg, val ) do { DRM_WRITEMEMORYBARRIER(dev_priv->mmio); MGA_DEREF( reg ) = val; } while (0) +#define MGA_WRITE8( reg, val ) do { DRM_WRITEMEMORYBARRIER(dev_priv->mmio); MGA_DEREF8( reg ) = val; } while (0) static inline u32 _MGA_READ(u32 *addr) { - DRM_READMEMORYBARRIER(); + DRM_READMEMORYBARRIER(dev_priv->mmio); return *(volatile u32 *)addr; } - #else -#define MGA_READ( reg ) MGA_DEREF( reg ) -#define MGA_READ8( reg ) MGA_DEREF8( reg ) -#define MGA_WRITE( reg, val ) do { MGA_DEREF( reg ) = val; } while (0) -#define MGA_WRITE8( reg, val ) do { MGA_DEREF8( reg ) = val; } while (0) +#define MGA_READ8( reg ) DRM_READ8(dev_priv->mmio, (reg)) +#define MGA_READ( reg ) DRM_READ32(dev_priv->mmio, (reg)) +#define MGA_WRITE8( reg, val ) DRM_WRITE8(dev_priv->mmio, (reg), (val)) +#define MGA_WRITE( reg, val ) DRM_WRITE32(dev_priv->mmio, (reg), (val)) #endif #define DWGREG0 0x1c00 @@ -183,16 +181,6 @@ } else { \ mga_g200_emit_state( dev_priv ); \ } \ - } \ -} while (0) - -#define LOCK_TEST_WITH_RETURN( dev ) \ -do { \ - if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || \ - dev->lock.pid != DRM_CURRENTPID ) { \ - DRM_ERROR( "%s called without lock held\n", \ - __FUNCTION__ ); \ - return DRM_ERR(EINVAL); \ } \ } while (0) diff -Nru a/drivers/char/drm/mga_state.c b/drivers/char/drm/mga_state.c --- a/drivers/char/drm/mga_state.c Wed Apr 2 22:24:05 2003 +++ b/drivers/char/drm/mga_state.c Wed Apr 2 22:24:05 2003 @@ -887,7 +887,7 @@ drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; drm_mga_clear_t clear; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); DRM_COPY_FROM_USER_IOCTL( clear, (drm_mga_clear_t *)data, sizeof(clear) ); @@ -911,7 +911,7 @@ drm_mga_private_t *dev_priv = dev->dev_private; drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS ) sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS; @@ -936,7 +936,7 @@ drm_mga_buf_priv_t *buf_priv; drm_mga_vertex_t vertex; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); DRM_COPY_FROM_USER_IOCTL( vertex, (drm_mga_vertex_t *)data, @@ -975,7 +975,7 @@ drm_mga_buf_priv_t *buf_priv; drm_mga_indices_t indices; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); DRM_COPY_FROM_USER_IOCTL( indices, (drm_mga_indices_t *)data, @@ -1015,7 +1015,7 @@ drm_mga_iload_t iload; DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); DRM_COPY_FROM_USER_IOCTL( iload, (drm_mga_iload_t *)data, sizeof(iload) ); @@ -1055,7 +1055,7 @@ drm_mga_blit_t blit; DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); DRM_COPY_FROM_USER_IOCTL( blit, (drm_mga_blit_t *)data, sizeof(blit) ); diff -Nru a/drivers/char/drm/r128_cce.c b/drivers/char/drm/r128_cce.c --- a/drivers/char/drm/r128_cce.c Wed Apr 2 22:24:04 2003 +++ b/drivers/char/drm/r128_cce.c Wed Apr 2 22:24:04 2003 @@ -579,6 +579,7 @@ (dev_priv->ring.size / sizeof(u32)) - 1; dev_priv->ring.high_mark = 128; + dev_priv->ring.ring_rptr = dev_priv->ring_rptr; dev_priv->sarea_priv->last_frame = 0; R128_WRITE( R128_LAST_FRAME_REG, dev_priv->sarea_priv->last_frame ); @@ -663,7 +664,7 @@ drm_r128_private_t *dev_priv = dev->dev_private; DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( dev_priv->cce_running || dev_priv->cce_mode == R128_PM4_NONPM4 ) { DRM_DEBUG( "%s while CCE running\n", __FUNCTION__ ); @@ -686,7 +687,7 @@ int ret; DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); DRM_COPY_FROM_USER_IOCTL(stop, (drm_r128_cce_stop_t *)data, sizeof(stop) ); @@ -725,7 +726,7 @@ drm_r128_private_t *dev_priv = dev->dev_private; DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( !dev_priv ) { DRM_DEBUG( "%s called before init done\n", __FUNCTION__ ); @@ -746,7 +747,7 @@ drm_r128_private_t *dev_priv = dev->dev_private; DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( dev_priv->cce_running ) { r128_do_cce_flush( dev_priv ); @@ -760,7 +761,7 @@ DRM_DEVICE; DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); return r128_do_engine_reset( dev ); } @@ -807,7 +808,7 @@ DRM_DEVICE; drm_r128_fullscreen_t fs; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); DRM_COPY_FROM_USER_IOCTL( fs, (drm_r128_fullscreen_t *)data, sizeof(fs) ); @@ -889,7 +890,7 @@ for ( i = 0 ; i < dma->buf_count ; i++ ) { buf = dma->buflist[i]; buf_priv = buf->dev_private; - if ( buf->pid == 0 ) + if ( buf->filp == 0 ) return buf; } @@ -948,7 +949,7 @@ return DRM_ERR(EBUSY); } -static int r128_cce_get_buffers( drm_device_t *dev, drm_dma_t *d ) +static int r128_cce_get_buffers( DRMFILE filp, drm_device_t *dev, drm_dma_t *d ) { int i; drm_buf_t *buf; @@ -957,7 +958,7 @@ buf = r128_freelist_get( dev ); if ( !buf ) return DRM_ERR(EAGAIN); - buf->pid = DRM_CURRENTPID; + buf->filp = filp; if ( DRM_COPY_TO_USER( &d->request_indices[i], &buf->idx, sizeof(buf->idx) ) ) @@ -978,7 +979,7 @@ int ret = 0; drm_dma_t d; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); DRM_COPY_FROM_USER_IOCTL( d, (drm_dma_t *) data, sizeof(d) ); @@ -1001,7 +1002,7 @@ d.granted_count = 0; if ( d.request_count ) { - ret = r128_cce_get_buffers( dev, &d ); + ret = r128_cce_get_buffers( filp, dev, &d ); } DRM_COPY_TO_USER_IOCTL((drm_dma_t *) data, d, sizeof(d) ); diff -Nru a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h --- a/drivers/char/drm/r128_drv.h Wed Apr 2 22:24:08 2003 +++ b/drivers/char/drm/r128_drv.h Wed Apr 2 22:24:08 2003 @@ -34,8 +34,8 @@ #ifndef __R128_DRV_H__ #define __R128_DRV_H__ -#define GET_RING_HEAD(ring) DRM_READ32( (volatile u32 *) (ring)->head ) -#define SET_RING_HEAD(ring,val) DRM_WRITE32( (volatile u32 *) (ring)->head, (val) ) +#define GET_RING_HEAD(ring) DRM_READ32( (ring)->ring_rptr, 0 ) /* (ring)->head */ +#define SET_RING_HEAD(ring,val) DRM_WRITE32( (ring)->ring_rptr, 0, (val) ) /* (ring)->head */ typedef struct drm_r128_freelist { unsigned int age; @@ -56,6 +56,7 @@ int space; int high_mark; + drm_local_map_t *ring_rptr; } drm_r128_ring_buffer_t; typedef struct drm_r128_private { @@ -98,13 +99,13 @@ u32 depth_pitch_offset_c; u32 span_pitch_offset_c; - drm_map_t *sarea; - drm_map_t *fb; - drm_map_t *mmio; - drm_map_t *cce_ring; - drm_map_t *ring_rptr; - drm_map_t *buffers; - drm_map_t *agp_textures; + drm_local_map_t *sarea; + drm_local_map_t *fb; + drm_local_map_t *mmio; + drm_local_map_t *cce_ring; + drm_local_map_t *ring_rptr; + drm_local_map_t *buffers; + drm_local_map_t *agp_textures; } drm_r128_private_t; typedef struct drm_r128_buf_priv { @@ -370,15 +371,10 @@ #define R128_PERFORMANCE_BOXES 0 - -#define R128_BASE(reg) ((unsigned long)(dev_priv->mmio->handle)) -#define R128_ADDR(reg) (R128_BASE( reg ) + reg) - -#define R128_READ(reg) DRM_READ32( (volatile u32 *) R128_ADDR(reg) ) -#define R128_WRITE(reg,val) DRM_WRITE32( (volatile u32 *) R128_ADDR(reg), (val) ) - -#define R128_READ8(reg) DRM_READ8( (volatile u8 *) R128_ADDR(reg) ) -#define R128_WRITE8(reg,val) DRM_WRITE8( (volatile u8 *) R128_ADDR(reg), (val) ) +#define R128_READ(reg) DRM_READ32( dev_priv->mmio, (reg) ) +#define R128_WRITE(reg,val) DRM_WRITE32( dev_priv->mmio, (reg), (val) ) +#define R128_READ8(reg) DRM_READ8( dev_priv->mmio, (reg) ) +#define R128_WRITE8(reg,val) DRM_WRITE8( dev_priv->mmio, (reg), (val) ) #define R128_WRITE_PLL(addr,val) \ do { \ @@ -403,15 +399,6 @@ * Misc helper macros */ -#define LOCK_TEST_WITH_RETURN( dev ) \ -do { \ - if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || \ - dev->lock.pid != DRM_CURRENTPID ) { \ - DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); \ - return DRM_ERR(EINVAL); \ - } \ -} while (0) - #define RING_SPACE_TEST_WITH_RETURN( dev_priv ) \ do { \ drm_r128_ring_buffer_t *ring = &dev_priv->ring; int i; \ @@ -453,7 +440,7 @@ #if defined(__powerpc__) #define r128_flush_write_combine() (void) GET_RING_HEAD( &dev_priv->ring ) #else -#define r128_flush_write_combine() DRM_WRITEMEMORYBARRIER() +#define r128_flush_write_combine() DRM_WRITEMEMORYBARRIER(dev_priv->ring_rptr) #endif diff -Nru a/drivers/char/drm/r128_state.c b/drivers/char/drm/r128_state.c --- a/drivers/char/drm/r128_state.c Wed Apr 2 22:24:04 2003 +++ b/drivers/char/drm/r128_state.c Wed Apr 2 22:24:04 2003 @@ -778,7 +778,8 @@ sarea_priv->nbox = 0; } -static int r128_cce_dispatch_blit( drm_device_t *dev, +static int r128_cce_dispatch_blit( DRMFILE filp, + drm_device_t *dev, drm_r128_blit_t *blit ) { drm_r128_private_t *dev_priv = dev->dev_private; @@ -829,9 +830,9 @@ buf = dma->buflist[blit->idx]; buf_priv = buf->dev_private; - if ( buf->pid != DRM_CURRENTPID ) { - DRM_ERROR( "process %d using buffer owned by %d\n", - DRM_CURRENTPID, buf->pid ); + if ( buf->filp != filp ) { + DRM_ERROR( "process %d using buffer owned by %p\n", + DRM_CURRENTPID, buf->filp ); return DRM_ERR(EINVAL); } if ( buf->pending ) { @@ -896,7 +897,7 @@ int count, x, y; u32 *buffer; u8 *mask; - int i; + int i, buffer_size, mask_size; RING_LOCALS; DRM_DEBUG( "\n" ); @@ -908,25 +909,25 @@ return DRM_ERR(EFAULT); } - buffer = DRM_MALLOC( depth->n * sizeof(u32) ); + buffer_size = depth->n * sizeof(u32); + buffer = DRM_MALLOC( buffer_size ); if ( buffer == NULL ) return DRM_ERR(ENOMEM); - if ( DRM_COPY_FROM_USER( buffer, depth->buffer, - depth->n * sizeof(u32) ) ) { - DRM_FREE( buffer ); + if ( DRM_COPY_FROM_USER( buffer, depth->buffer, buffer_size ) ) { + DRM_FREE( buffer, buffer_size); return DRM_ERR(EFAULT); } + mask_size = depth->n * sizeof(u8); if ( depth->mask ) { - mask = DRM_MALLOC( depth->n * sizeof(u8) ); + mask = DRM_MALLOC( mask_size ); if ( mask == NULL ) { - DRM_FREE( buffer ); + DRM_FREE( buffer, buffer_size ); return DRM_ERR(ENOMEM); } - if ( DRM_COPY_FROM_USER( mask, depth->mask, - depth->n * sizeof(u8) ) ) { - DRM_FREE( buffer ); - DRM_FREE( mask ); + if ( DRM_COPY_FROM_USER( mask, depth->mask, mask_size ) ) { + DRM_FREE( buffer, buffer_size ); + DRM_FREE( mask, mask_size ); return DRM_ERR(EFAULT); } @@ -953,7 +954,7 @@ } } - DRM_FREE( mask ); + DRM_FREE( mask, mask_size ); } else { for ( i = 0 ; i < count ; i++, x++ ) { BEGIN_RING( 6 ); @@ -977,7 +978,7 @@ } } - DRM_FREE( buffer ); + DRM_FREE( buffer, buffer_size ); return 0; } @@ -989,60 +990,62 @@ int count, *x, *y; u32 *buffer; u8 *mask; - int i; + int i, xbuf_size, ybuf_size, buffer_size, mask_size; RING_LOCALS; DRM_DEBUG( "\n" ); count = depth->n; - x = DRM_MALLOC( count * sizeof(*x) ); + xbuf_size = count * sizeof(*x); + ybuf_size = count * sizeof(*y); + x = DRM_MALLOC( xbuf_size ); if ( x == NULL ) { return DRM_ERR(ENOMEM); } - y = DRM_MALLOC( count * sizeof(*y) ); + y = DRM_MALLOC( ybuf_size ); if ( y == NULL ) { - DRM_FREE( x ); + DRM_FREE( x, xbuf_size ); return DRM_ERR(ENOMEM); } - if ( DRM_COPY_FROM_USER( x, depth->x, count * sizeof(int) ) ) { - DRM_FREE( x ); - DRM_FREE( y ); + if ( DRM_COPY_FROM_USER( x, depth->x, xbuf_size ) ) { + DRM_FREE( x, xbuf_size ); + DRM_FREE( y, ybuf_size ); return DRM_ERR(EFAULT); } - if ( DRM_COPY_FROM_USER( y, depth->y, count * sizeof(int) ) ) { - DRM_FREE( x ); - DRM_FREE( y ); + if ( DRM_COPY_FROM_USER( y, depth->y, xbuf_size ) ) { + DRM_FREE( x, xbuf_size ); + DRM_FREE( y, ybuf_size ); return DRM_ERR(EFAULT); } - buffer = DRM_MALLOC( depth->n * sizeof(u32) ); + buffer_size = depth->n * sizeof(u32); + buffer = DRM_MALLOC( buffer_size ); if ( buffer == NULL ) { - DRM_FREE( x ); - DRM_FREE( y ); + DRM_FREE( x, xbuf_size ); + DRM_FREE( y, ybuf_size ); return DRM_ERR(ENOMEM); } - if ( DRM_COPY_FROM_USER( buffer, depth->buffer, - depth->n * sizeof(u32) ) ) { - DRM_FREE( x ); - DRM_FREE( y ); - DRM_FREE( buffer ); + if ( DRM_COPY_FROM_USER( buffer, depth->buffer, buffer_size ) ) { + DRM_FREE( x, xbuf_size ); + DRM_FREE( y, ybuf_size ); + DRM_FREE( buffer, buffer_size ); return DRM_ERR(EFAULT); } if ( depth->mask ) { - mask = DRM_MALLOC( depth->n * sizeof(u8) ); + mask_size = depth->n * sizeof(u8); + mask = DRM_MALLOC( mask_size ); if ( mask == NULL ) { - DRM_FREE( x ); - DRM_FREE( y ); - DRM_FREE( buffer ); + DRM_FREE( x, xbuf_size ); + DRM_FREE( y, ybuf_size ); + DRM_FREE( buffer, buffer_size ); return DRM_ERR(ENOMEM); } - if ( DRM_COPY_FROM_USER( mask, depth->mask, - depth->n * sizeof(u8) ) ) { - DRM_FREE( x ); - DRM_FREE( y ); - DRM_FREE( buffer ); - DRM_FREE( mask ); + if ( DRM_COPY_FROM_USER( mask, depth->mask, mask_size ) ) { + DRM_FREE( x, xbuf_size ); + DRM_FREE( y, ybuf_size ); + DRM_FREE( buffer, buffer_size ); + DRM_FREE( mask, mask_size ); return DRM_ERR(EFAULT); } @@ -1069,7 +1072,7 @@ } } - DRM_FREE( mask ); + DRM_FREE( mask, mask_size ); } else { for ( i = 0 ; i < count ; i++ ) { BEGIN_RING( 6 ); @@ -1093,9 +1096,9 @@ } } - DRM_FREE( x ); - DRM_FREE( y ); - DRM_FREE( buffer ); + DRM_FREE( x, xbuf_size ); + DRM_FREE( y, ybuf_size ); + DRM_FREE( buffer, buffer_size ); return 0; } @@ -1146,7 +1149,7 @@ { drm_r128_private_t *dev_priv = dev->dev_private; int count, *x, *y; - int i; + int i, xbuf_size, ybuf_size; RING_LOCALS; DRM_DEBUG( "%s\n", __FUNCTION__ ); @@ -1155,23 +1158,25 @@ count = dev_priv->depth_pitch; } - x = DRM_MALLOC( count * sizeof(*x) ); + xbuf_size = count * sizeof(*x); + ybuf_size = count * sizeof(*y); + x = DRM_MALLOC( xbuf_size ); if ( x == NULL ) { return DRM_ERR(ENOMEM); } - y = DRM_MALLOC( count * sizeof(*y) ); + y = DRM_MALLOC( ybuf_size ); if ( y == NULL ) { - DRM_FREE( x ); + DRM_FREE( x, xbuf_size ); return DRM_ERR(ENOMEM); } - if ( DRM_COPY_FROM_USER( x, depth->x, count * sizeof(int) ) ) { - DRM_FREE( x ); - DRM_FREE( y ); + if ( DRM_COPY_FROM_USER( x, depth->x, xbuf_size ) ) { + DRM_FREE( x, xbuf_size ); + DRM_FREE( y, ybuf_size ); return DRM_ERR(EFAULT); } - if ( DRM_COPY_FROM_USER( y, depth->y, count * sizeof(int) ) ) { - DRM_FREE( x ); - DRM_FREE( y ); + if ( DRM_COPY_FROM_USER( y, depth->y, ybuf_size ) ) { + DRM_FREE( x, xbuf_size ); + DRM_FREE( y, ybuf_size ); return DRM_ERR(EFAULT); } @@ -1199,8 +1204,8 @@ ADVANCE_RING(); } - DRM_FREE( x ); - DRM_FREE( y ); + DRM_FREE( x, xbuf_size ); + DRM_FREE( y, ybuf_size ); return 0; } @@ -1240,7 +1245,7 @@ drm_r128_clear_t clear; DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); DRM_COPY_FROM_USER_IOCTL( clear, (drm_r128_clear_t *) data, sizeof(clear) ); @@ -1266,7 +1271,7 @@ drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; DRM_DEBUG( "%s\n", __FUNCTION__ ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); RING_SPACE_TEST_WITH_RETURN( dev_priv ); @@ -1293,7 +1298,7 @@ drm_r128_buf_priv_t *buf_priv; drm_r128_vertex_t vertex; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); @@ -1324,9 +1329,9 @@ buf = dma->buflist[vertex.idx]; buf_priv = buf->dev_private; - if ( buf->pid != DRM_CURRENTPID ) { - DRM_ERROR( "process %d using buffer owned by %d\n", - DRM_CURRENTPID, buf->pid ); + if ( buf->filp != filp ) { + DRM_ERROR( "process %d using buffer owned by %p\n", + DRM_CURRENTPID, buf->filp ); return DRM_ERR(EINVAL); } if ( buf->pending ) { @@ -1353,7 +1358,7 @@ drm_r128_indices_t elts; int count; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); @@ -1383,9 +1388,9 @@ buf = dma->buflist[elts.idx]; buf_priv = buf->dev_private; - if ( buf->pid != DRM_CURRENTPID ) { - DRM_ERROR( "process %d using buffer owned by %d\n", - DRM_CURRENTPID, buf->pid ); + if ( buf->filp != filp ) { + DRM_ERROR( "process %d using buffer owned by %p\n", + DRM_CURRENTPID, buf->filp ); return DRM_ERR(EINVAL); } if ( buf->pending ) { @@ -1421,7 +1426,7 @@ drm_r128_private_t *dev_priv = dev->dev_private; drm_r128_blit_t blit; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); DRM_COPY_FROM_USER_IOCTL( blit, (drm_r128_blit_t *) data, sizeof(blit) ); @@ -1437,7 +1442,7 @@ RING_SPACE_TEST_WITH_RETURN( dev_priv ); VB_AGE_TEST_WITH_RETURN( dev_priv ); - return r128_cce_dispatch_blit( dev, &blit ); + return r128_cce_dispatch_blit( filp, dev, &blit ); } int r128_cce_depth( DRM_IOCTL_ARGS ) @@ -1446,7 +1451,7 @@ drm_r128_private_t *dev_priv = dev->dev_private; drm_r128_depth_t depth; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); DRM_COPY_FROM_USER_IOCTL( depth, (drm_r128_depth_t *) data, sizeof(depth) ); @@ -1474,7 +1479,7 @@ drm_r128_stipple_t stipple; u32 mask[32]; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); DRM_COPY_FROM_USER_IOCTL( stipple, (drm_r128_stipple_t *) data, sizeof(stipple) ); @@ -1502,7 +1507,7 @@ RING_LOCALS; #endif - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); @@ -1525,9 +1530,9 @@ buf = dma->buflist[indirect.idx]; buf_priv = buf->dev_private; - if ( buf->pid != DRM_CURRENTPID ) { - DRM_ERROR( "process %d using buffer owned by %d\n", - DRM_CURRENTPID, buf->pid ); + if ( buf->filp != filp ) { + DRM_ERROR( "process %d using buffer owned by %p\n", + DRM_CURRENTPID, buf->filp ); return DRM_ERR(EINVAL); } if ( buf->pending ) { diff -Nru a/drivers/char/drm/radeon.h b/drivers/char/drm/radeon.h --- a/drivers/char/drm/radeon.h Wed Apr 2 22:24:07 2003 +++ b/drivers/char/drm/radeon.h Wed Apr 2 22:24:07 2003 @@ -51,7 +51,7 @@ #define DRIVER_DATE "20020828" #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 7 +#define DRIVER_MINOR 8 #define DRIVER_PATCHLEVEL 0 /* Interface history: @@ -77,6 +77,7 @@ * and R200_PP_CUBIC_OFFSET_F1_[0..5]. * Added packets R200_EMIT_PP_CUBIC_FACES_[0..5] and * R200_EMIT_PP_CUBIC_OFFSETS_[0..5]. (brian) + * 1.8 - Remove need to call cleanup ioctls on last client exit (keith) */ #define DRIVER_IOCTLS \ [DRM_IOCTL_NR(DRM_IOCTL_DMA)] = { radeon_cp_buffers, 1, 0 }, \ @@ -105,11 +106,6 @@ [DRM_IOCTL_NR(DRM_IOCTL_RADEON_IRQ_WAIT)] = { radeon_irq_wait, 1, 0 }, -#define USE_IRQS 1 -#if USE_IRQS -#define __HAVE_DMA_IRQ 1 -#define __HAVE_VBL_IRQ 1 -#define __HAVE_SHARED_IRQ 1 /* When a client dies: * - Check for and clean up flipped page state @@ -117,35 +113,34 @@ * * DRM infrastructure takes care of reclaiming dma buffers. */ -#define DRIVER_PRERELEASE() do { \ +#define DRIVER_PRERELEASE() \ +do { \ if ( dev->dev_private ) { \ drm_radeon_private_t *dev_priv = dev->dev_private; \ if ( dev_priv->page_flipping ) { \ radeon_do_cleanup_pageflip( dev ); \ } \ - radeon_mem_release( dev_priv->agp_heap ); \ + radeon_mem_release( filp, dev_priv->agp_heap ); \ + radeon_mem_release( filp, dev_priv->fb_heap ); \ } \ } while (0) -/* On unloading the module: - * - Free memory heap structure - * - Remove mappings made at startup and free dev_private. +/* When the last client dies, shut down the CP and free dev->dev_priv. */ -#define DRIVER_PRETAKEDOWN() do { \ - if ( dev->dev_private ) { \ - drm_radeon_private_t *dev_priv = dev->dev_private; \ - radeon_mem_takedown( &(dev_priv->agp_heap) ); \ - radeon_do_cleanup_cp( dev ); \ - } \ +/* #define __HAVE_RELEASE 1 */ +#define DRIVER_PRETAKEDOWN() \ +do { \ + radeon_do_release( dev ); \ } while (0) -#else -#define __HAVE_DMA_IRQ 0 -#endif + /* DMA customization: */ #define __HAVE_DMA 1 +#define __HAVE_DMA_IRQ 1 +#define __HAVE_VBL_IRQ 1 +#define __HAVE_SHARED_IRQ 1 /* Buffer customization: diff -Nru a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c --- a/drivers/char/drm/radeon_cp.c Wed Apr 2 22:24:04 2003 +++ b/drivers/char/drm/radeon_cp.c Wed Apr 2 22:24:04 2003 @@ -926,11 +926,11 @@ RADEON_WRITE( RADEON_SCRATCH_UMSK, 0x7 ); /* Writeback doesn't seem to work everywhere, test it first */ - DRM_WRITE32( &dev_priv->scratch[1], 0 ); + DRM_WRITE32( dev_priv->ring_rptr, RADEON_SCRATCHOFF(1), 0 ); RADEON_WRITE( RADEON_SCRATCH_REG1, 0xdeadbeef ); for ( tmp = 0 ; tmp < dev_priv->usec_timeout ; tmp++ ) { - if ( DRM_READ32( &dev_priv->scratch[1] ) == 0xdeadbeef ) + if ( DRM_READ32( dev_priv->ring_rptr, RADEON_SCRATCHOFF(1) ) == 0xdeadbeef ) break; DRM_UDELAY( 1 ); } @@ -1217,6 +1217,7 @@ (dev_priv->ring.size / sizeof(u32)) - 1; dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK; + dev_priv->ring.ring_rptr = dev_priv->ring_rptr; #if __REALLY_HAVE_SG if ( dev_priv->is_pci ) { @@ -1322,7 +1323,7 @@ drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( dev_priv->cp_running ) { DRM_DEBUG( "%s while CP running\n", __FUNCTION__ ); @@ -1350,10 +1351,13 @@ int ret; DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); DRM_COPY_FROM_USER_IOCTL( stop, (drm_radeon_cp_stop_t *)data, sizeof(stop) ); + if (!dev_priv->cp_running) + return 0; + /* Flush any pending CP commands. This ensures any outstanding * commands are exectuted by the engine before we turn it off. */ @@ -1381,6 +1385,39 @@ return 0; } + +void radeon_do_release( drm_device_t *dev ) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + int ret; + + if (dev_priv) { + if (dev_priv->cp_running) { + /* Stop the cp */ + while ((ret = radeon_do_cp_idle( dev_priv )) != 0) { + DRM_DEBUG("radeon_do_cp_idle %d\n", ret); +#ifdef __linux__ + schedule(); +#else + tsleep(&ret, PZERO, "rdnrel", 1); +#endif + } + radeon_do_cp_stop( dev_priv ); + radeon_do_engine_reset( dev ); + } + + /* Disable *all* interrupts */ + RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 ); + + /* Free memory heap structures */ + radeon_mem_takedown( &(dev_priv->agp_heap) ); + radeon_mem_takedown( &(dev_priv->fb_heap) ); + + /* deallocate kernel resources */ + radeon_do_cleanup_cp( dev ); + } +} + /* Just reset the CP ring. Called as part of an X Server engine reset. */ int radeon_cp_reset( DRM_IOCTL_ARGS ) @@ -1389,7 +1426,7 @@ drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( !dev_priv ) { DRM_DEBUG( "%s called before init done\n", __FUNCTION__ ); @@ -1410,10 +1447,7 @@ drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); - -/* if (dev->irq) */ -/* radeon_emit_and_wait_irq( dev ); */ + LOCK_TEST_WITH_RETURN( dev, filp ); return radeon_do_cp_idle( dev_priv ); } @@ -1423,7 +1457,7 @@ DRM_DEVICE; DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); return radeon_do_engine_reset( dev ); } @@ -1482,7 +1516,7 @@ for ( i = start ; i < dma->buf_count ; i++ ) { buf = dma->buflist[i]; buf_priv = buf->dev_private; - if ( buf->pid == 0 || (buf->pending && + if ( buf->filp == 0 || (buf->pending && buf_priv->age <= done_age) ) { dev_priv->stats.requested_bufs++; buf->pending = 0; @@ -1509,7 +1543,7 @@ drm_buf_t *buf; int i, t; int start; - u32 done_age = DRM_READ32(&dev_priv->scratch[1]); + u32 done_age = DRM_READ32(dev_priv->ring_rptr, RADEON_SCRATCHOFF(1)); if ( ++dev_priv->last_buf >= dma->buf_count ) dev_priv->last_buf = 0; @@ -1521,7 +1555,7 @@ for ( i = start ; i < dma->buf_count ; i++ ) { buf = dma->buflist[i]; buf_priv = buf->dev_private; - if ( buf->pid == 0 || (buf->pending && + if ( buf->filp == 0 || (buf->pending && buf_priv->age <= done_age) ) { dev_priv->stats.requested_bufs++; buf->pending = 0; @@ -1586,7 +1620,7 @@ return DRM_ERR(EBUSY); } -static int radeon_cp_get_buffers( drm_device_t *dev, drm_dma_t *d ) +static int radeon_cp_get_buffers( DRMFILE filp, drm_device_t *dev, drm_dma_t *d ) { int i; drm_buf_t *buf; @@ -1595,7 +1629,7 @@ buf = radeon_freelist_get( dev ); if ( !buf ) return DRM_ERR(EBUSY); /* NOTE: broken client */ - buf->pid = DRM_CURRENTPID; + buf->filp = filp; if ( DRM_COPY_TO_USER( &d->request_indices[i], &buf->idx, sizeof(buf->idx) ) ) @@ -1616,7 +1650,7 @@ int ret = 0; drm_dma_t d; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); DRM_COPY_FROM_USER_IOCTL( d, (drm_dma_t *)data, sizeof(d) ); @@ -1639,7 +1673,7 @@ d.granted_count = 0; if ( d.request_count ) { - ret = radeon_cp_get_buffers( dev, &d ); + ret = radeon_cp_get_buffers( filp, dev, &d ); } DRM_COPY_TO_USER_IOCTL( (drm_dma_t *)data, d, sizeof(d) ); diff -Nru a/drivers/char/drm/radeon_drm.h b/drivers/char/drm/radeon_drm.h --- a/drivers/char/drm/radeon_drm.h Wed Apr 2 22:24:06 2003 +++ b/drivers/char/drm/radeon_drm.h Wed Apr 2 22:24:06 2003 @@ -382,7 +382,7 @@ #define DRM_IOCTL_RADEON_STIPPLE DRM_IOW( 0x4c, drm_radeon_stipple_t) #define DRM_IOCTL_RADEON_INDIRECT DRM_IOWR(0x4d, drm_radeon_indirect_t) #define DRM_IOCTL_RADEON_TEXTURE DRM_IOWR(0x4e, drm_radeon_texture_t) -#define DRM_IOCTL_RADEON_VERTEX2 DRM_IOW( 0x4f, drm_radeon_vertex_t) +#define DRM_IOCTL_RADEON_VERTEX2 DRM_IOW( 0x4f, drm_radeon_vertex2_t) #define DRM_IOCTL_RADEON_CMDBUF DRM_IOW( 0x50, drm_radeon_cmd_buffer_t) #define DRM_IOCTL_RADEON_GETPARAM DRM_IOWR(0x51, drm_radeon_getparam_t) #define DRM_IOCTL_RADEON_FLIP DRM_IO( 0x52) @@ -396,7 +396,7 @@ enum { RADEON_INIT_CP = 0x01, RADEON_CLEANUP_CP = 0x02, - RADEON_INIT_R200_CP = 0x03, + RADEON_INIT_R200_CP = 0x03 } func; unsigned long sarea_priv_offset; int is_pci; diff -Nru a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h --- a/drivers/char/drm/radeon_drv.h Wed Apr 2 22:24:05 2003 +++ b/drivers/char/drm/radeon_drv.h Wed Apr 2 22:24:05 2003 @@ -31,8 +31,8 @@ #ifndef __RADEON_DRV_H__ #define __RADEON_DRV_H__ -#define GET_RING_HEAD(ring) DRM_READ32( (volatile u32 *) (ring)->head ) -#define SET_RING_HEAD(ring,val) DRM_WRITE32( (volatile u32 *) (ring)->head , (val)) +#define GET_RING_HEAD(ring) DRM_READ32( (ring)->ring_rptr, 0 ) /* (ring)->head */ +#define SET_RING_HEAD(ring,val) DRM_WRITE32( (ring)->ring_rptr, 0, (val) ) /* (ring)->head */ typedef struct drm_radeon_freelist { unsigned int age; @@ -53,6 +53,7 @@ int space; int high_mark; + drm_local_map_t *ring_rptr; } drm_radeon_ring_buffer_t; typedef struct drm_radeon_depth_clear_t { @@ -67,7 +68,7 @@ struct mem_block *prev; int start; int size; - int pid; /* 0: free, -1: heap, other: real pids */ + DRMFILE filp; /* 0: free, -1: heap, other: real files */ }; typedef struct drm_radeon_private { @@ -126,13 +127,13 @@ drm_radeon_depth_clear_t depth_clear; - drm_map_t *sarea; - drm_map_t *fb; - drm_map_t *mmio; - drm_map_t *cp_ring; - drm_map_t *ring_rptr; - drm_map_t *buffers; - drm_map_t *agp_textures; + drm_local_map_t *sarea; + drm_local_map_t *fb; + drm_local_map_t *mmio; + drm_local_map_t *cp_ring; + drm_local_map_t *ring_rptr; + drm_local_map_t *buffers; + drm_local_map_t *agp_textures; struct mem_block *agp_heap; struct mem_block *fb_heap; @@ -183,7 +184,7 @@ extern int radeon_mem_free( DRM_IOCTL_ARGS ); extern int radeon_mem_init_heap( DRM_IOCTL_ARGS ); extern void radeon_mem_takedown( struct mem_block **heap ); -extern void radeon_mem_release( struct mem_block *heap ); +extern void radeon_mem_release( DRMFILE filp, struct mem_block *heap ); /* radeon_irq.c */ extern int radeon_irq_emit( DRM_IOCTL_ARGS ); @@ -193,6 +194,7 @@ extern int radeon_wait_irq(drm_device_t *dev, int swi_nr); extern int radeon_emit_irq(drm_device_t *dev); +extern void radeon_do_release(drm_device_t *dev); /* Flags for stats.boxes */ @@ -266,8 +268,10 @@ #define RADEON_SCRATCH_UMSK 0x0770 #define RADEON_SCRATCH_ADDR 0x0774 +#define RADEON_SCRATCHOFF( x ) (RADEON_SCRATCH_REG_OFFSET + 4*(x)) + #define GET_SCRATCH( x ) (dev_priv->writeback_works \ - ? DRM_READ32( &dev_priv->scratch[(x)] ) \ + ? DRM_READ32( dev_priv->ring_rptr, RADEON_SCRATCHOFF(x) ) \ : RADEON_READ( RADEON_SCRATCH_REG0 + 4*(x) ) ) @@ -686,15 +690,10 @@ #define RADEON_RING_HIGH_MARK 128 - -#define RADEON_BASE(reg) ((unsigned long)(dev_priv->mmio->handle)) -#define RADEON_ADDR(reg) (RADEON_BASE( reg ) + reg) - -#define RADEON_READ(reg) DRM_READ32( (volatile u32 *) RADEON_ADDR(reg) ) -#define RADEON_WRITE(reg,val) DRM_WRITE32( (volatile u32 *) RADEON_ADDR(reg), (val) ) - -#define RADEON_READ8(reg) DRM_READ8( (volatile u8 *) RADEON_ADDR(reg) ) -#define RADEON_WRITE8(reg,val) DRM_WRITE8( (volatile u8 *) RADEON_ADDR(reg), (val) ) +#define RADEON_READ(reg) DRM_READ32( dev_priv->mmio, (reg) ) +#define RADEON_WRITE(reg,val) DRM_WRITE32( dev_priv->mmio, (reg), (val) ) +#define RADEON_READ8(reg) DRM_READ8( dev_priv->mmio, (reg) ) +#define RADEON_WRITE8(reg,val) DRM_WRITE8( dev_priv->mmio, (reg), (val) ) #define RADEON_WRITE_PLL( addr, val ) \ do { \ @@ -771,16 +770,6 @@ * Misc helper macros */ -#define LOCK_TEST_WITH_RETURN( dev ) \ -do { \ - if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || \ - dev->lock.pid != DRM_CURRENTPID ) { \ - DRM_ERROR( "%s called without lock held\n", __FUNCTION__ ); \ - return DRM_ERR(EINVAL); \ - } \ -} while (0) - - /* Perfbox functionality only. */ #define RING_SPACE_TEST_WITH_RETURN( dev_priv ) \ @@ -823,13 +812,6 @@ * Ring control */ -#if defined(__powerpc__) -#define radeon_flush_write_combine() (void) GET_RING_HEAD( &dev_priv->ring ) -#else -#define radeon_flush_write_combine() DRM_WRITEMEMORYBARRIER() -#endif - - #define RADEON_VERBOSE 0 #define RING_LOCALS int write, _nr; unsigned int mask; u32 *ring; @@ -863,8 +845,13 @@ dev_priv->ring.tail = write; \ } while (0) -#define COMMIT_RING() do { \ - RADEON_WRITE( RADEON_CP_RB_WPTR, dev_priv->ring.tail ); \ +#define COMMIT_RING() do { \ + /* Flush writes to ring */ \ + DRM_READMEMORYBARRIER(dev_priv->mmio); \ + GET_RING_HEAD( &dev_priv->ring ); \ + RADEON_WRITE( RADEON_CP_RB_WPTR, dev_priv->ring.tail ); \ + /* read from PCI bus to ensure correct posting */ \ + RADEON_READ( RADEON_CP_RB_RPTR ); \ } while (0) #define OUT_RING( x ) do { \ diff -Nru a/drivers/char/drm/radeon_irq.c b/drivers/char/drm/radeon_irq.c --- a/drivers/char/drm/radeon_irq.c Wed Apr 2 22:24:07 2003 +++ b/drivers/char/drm/radeon_irq.c Wed Apr 2 22:24:07 2003 @@ -61,7 +61,11 @@ (drm_radeon_private_t *)dev->dev_private; u32 stat; - stat = RADEON_READ(RADEON_GEN_INT_STATUS); + /* Only consider the bits we're interested in - others could be used + * outside the DRM + */ + stat = RADEON_READ(RADEON_GEN_INT_STATUS) + & (RADEON_SW_INT_TEST | RADEON_CRTC_VBLANK_STAT); if (!stat) return; @@ -77,15 +81,14 @@ DRM(vbl_send_signals)( dev ); } - /* Acknowledge all the bits in GEN_INT_STATUS -- seem to get - * more than we asked for... - */ + /* Acknowledge interrupts we handle */ RADEON_WRITE(RADEON_GEN_INT_STATUS, stat); } static __inline__ void radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv) { - u32 tmp = RADEON_READ( RADEON_GEN_INT_STATUS ); + u32 tmp = RADEON_READ( RADEON_GEN_INT_STATUS ) + & (RADEON_SW_INT_TEST_ACK | RADEON_CRTC_VBLANK_STAT); if (tmp) RADEON_WRITE( RADEON_GEN_INT_STATUS, tmp ); } @@ -176,7 +179,7 @@ drm_radeon_irq_emit_t emit; int result; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); diff -Nru a/drivers/char/drm/radeon_mem.c b/drivers/char/drm/radeon_mem.c --- a/drivers/char/drm/radeon_mem.c Wed Apr 2 22:24:07 2003 +++ b/drivers/char/drm/radeon_mem.c Wed Apr 2 22:24:07 2003 @@ -40,7 +40,7 @@ */ static struct mem_block *split_block(struct mem_block *p, int start, int size, - int pid ) + DRMFILE filp ) { /* Maybe cut off the start of an existing block */ if (start > p->start) { @@ -49,7 +49,7 @@ goto out; newblock->start = start; newblock->size = p->size - (start - p->start); - newblock->pid = 0; + newblock->filp = 0; newblock->next = p->next; newblock->prev = p; p->next->prev = newblock; @@ -65,7 +65,7 @@ goto out; newblock->start = start + size; newblock->size = p->size - size; - newblock->pid = 0; + newblock->filp = 0; newblock->next = p->next; newblock->prev = p; p->next->prev = newblock; @@ -75,20 +75,20 @@ out: /* Our block is in the middle */ - p->pid = pid; + p->filp = filp; return p; } static struct mem_block *alloc_block( struct mem_block *heap, int size, - int align2, int pid ) + int align2, DRMFILE filp ) { struct mem_block *p; int mask = (1 << align2)-1; for (p = heap->next ; p != heap ; p = p->next) { int start = (p->start + mask) & ~mask; - if (p->pid == 0 && start + size <= p->start + p->size) - return split_block( p, start, size, pid ); + if (p->filp == 0 && start + size <= p->start + p->size) + return split_block( p, start, size, filp ); } return NULL; @@ -108,25 +108,25 @@ static void free_block( struct mem_block *p ) { - p->pid = 0; + p->filp = 0; - /* Assumes a single contiguous range. Needs a special pid in + /* Assumes a single contiguous range. Needs a special filp in * 'heap' to stop it being subsumed. */ - if (p->next->pid == 0) { + if (p->next->filp == 0) { struct mem_block *q = p->next; p->size += q->size; p->next = q->next; p->next->prev = p; - DRM_FREE(q); + DRM_FREE(q, sizeof(*q)); } - if (p->prev->pid == 0) { + if (p->prev->filp == 0) { struct mem_block *q = p->prev; q->size += p->size; q->next = p->next; q->next->prev = q; - DRM_FREE(p); + DRM_FREE(p, sizeof(*q)); } } @@ -141,47 +141,46 @@ *heap = DRM_MALLOC(sizeof(**heap)); if (!*heap) { - DRM_FREE( blocks ); + DRM_FREE( blocks, sizeof(*blocks) ); return -ENOMEM; } blocks->start = start; blocks->size = size; - blocks->pid = 0; + blocks->filp = 0; blocks->next = blocks->prev = *heap; memset( *heap, 0, sizeof(**heap) ); - (*heap)->pid = -1; + (*heap)->filp = (DRMFILE) -1; (*heap)->next = (*heap)->prev = blocks; return 0; } -/* Free all blocks associated with the releasing pid. +/* Free all blocks associated with the releasing file. */ -void radeon_mem_release( struct mem_block *heap ) +void radeon_mem_release( DRMFILE filp, struct mem_block *heap ) { - int pid = DRM_CURRENTPID; struct mem_block *p; if (!heap || !heap->next) return; for (p = heap->next ; p != heap ; p = p->next) { - if (p->pid == pid) - p->pid = 0; + if (p->filp == filp) + p->filp = 0; } - /* Assumes a single contiguous range. Needs a special pid in + /* Assumes a single contiguous range. Needs a special filp in * 'heap' to stop it being subsumed. */ for (p = heap->next ; p != heap ; p = p->next) { - while (p->pid == 0 && p->next->pid == 0) { + while (p->filp == 0 && p->next->filp == 0) { struct mem_block *q = p->next; p->size += q->size; p->next = q->next; p->next->prev = p; - DRM_FREE(q); + DRM_FREE(q, sizeof(*q)); } } } @@ -198,10 +197,10 @@ for (p = (*heap)->next ; p != *heap ; ) { struct mem_block *q = p; p = p->next; - DRM_FREE(q); + DRM_FREE(q, sizeof(*q)); } - DRM_FREE( *heap ); + DRM_FREE( *heap, sizeof(**heap) ); *heap = 0; } @@ -248,7 +247,7 @@ alloc.alignment = 12; block = alloc_block( *heap, alloc.size, alloc.alignment, - DRM_CURRENTPID ); + filp ); if (!block) return DRM_ERR(ENOMEM); @@ -287,7 +286,7 @@ if (!block) return DRM_ERR(EFAULT); - if (block->pid != DRM_CURRENTPID) + if (block->filp != filp) return DRM_ERR(EPERM); free_block( block ); diff -Nru a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c --- a/drivers/char/drm/radeon_state.c Wed Apr 2 22:24:07 2003 +++ b/drivers/char/drm/radeon_state.c Wed Apr 2 22:24:07 2003 @@ -1063,7 +1063,8 @@ #define RADEON_MAX_TEXTURE_SIZE (RADEON_BUFFER_SIZE - 8 * sizeof(u32)) -static int radeon_cp_dispatch_texture( drm_device_t *dev, +static int radeon_cp_dispatch_texture( DRMFILE filp, + drm_device_t *dev, drm_radeon_texture_t *tex, drm_radeon_tex_image_t *image ) { @@ -1073,7 +1074,7 @@ u32 *buffer; const u8 *data; int size, dwords, tex_width, blit_width; - u32 y, height; + u32 height; int i; RING_LOCALS; @@ -1138,10 +1139,9 @@ tex->offset >> 10, tex->pitch, tex->format, image->x, image->y, image->width, image->height ); - /* Make a copy of the parameters in case we have to + /* Make a copy of some parameters in case we have to * update them for a multi-pass texture blit. */ - y = image->y; height = image->height; data = (const u8 *)image->data; @@ -1156,11 +1156,6 @@ return 0; } - /* Update the input parameters for next time */ - image->y += height; - image->height -= height; - image->data += size; - buf = radeon_freelist_get( dev ); if ( 0 && !buf ) { radeon_do_cp_idle( dev_priv ); @@ -1190,7 +1185,7 @@ buffer[2] = (tex->pitch << 22) | (tex->offset >> 10); buffer[3] = 0xffffffff; buffer[4] = 0xffffffff; - buffer[5] = (y << 16) | image->x; + buffer[5] = (image->y << 16) | image->x; buffer[6] = (height << 16) | image->width; buffer[7] = dwords; buffer += 8; @@ -1222,11 +1217,15 @@ } } - buf->pid = DRM_CURRENTPID; + buf->filp = filp; buf->used = (dwords + 8) * sizeof(u32); radeon_cp_dispatch_indirect( dev, buf, 0, buf->used ); radeon_cp_discard_buffer( dev, buf ); + /* Update the input parameters for next time */ + image->y += height; + image->height -= height; + (const u8 *)image->data += size; } while (image->height > 0); /* Flush the pixel cache after the blit completes. This ensures @@ -1275,7 +1274,7 @@ drm_radeon_clear_rect_t depth_boxes[RADEON_NR_SAREA_CLIPRECTS]; DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); DRM_COPY_FROM_USER_IOCTL( clear, (drm_radeon_clear_t *)data, sizeof(clear) ); @@ -1344,7 +1343,7 @@ drm_radeon_private_t *dev_priv = dev->dev_private; DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); RING_SPACE_TEST_WITH_RETURN( dev_priv ); @@ -1364,7 +1363,7 @@ drm_radeon_sarea_t *sarea_priv = dev_priv->sarea_priv; DRM_DEBUG( "\n" ); - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); RING_SPACE_TEST_WITH_RETURN( dev_priv ); @@ -1388,7 +1387,7 @@ drm_radeon_vertex_t vertex; drm_radeon_tcl_prim_t prim; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); @@ -1418,9 +1417,9 @@ buf = dma->buflist[vertex.idx]; - if ( buf->pid != DRM_CURRENTPID ) { - DRM_ERROR( "process %d using buffer owned by %d\n", - DRM_CURRENTPID, buf->pid ); + if ( buf->filp != filp ) { + DRM_ERROR( "process %d using buffer owned by %p\n", + DRM_CURRENTPID, buf->filp ); return DRM_ERR(EINVAL); } if ( buf->pending ) { @@ -1475,7 +1474,7 @@ drm_radeon_tcl_prim_t prim; int count; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); @@ -1505,9 +1504,9 @@ buf = dma->buflist[elts.idx]; - if ( buf->pid != DRM_CURRENTPID ) { - DRM_ERROR( "process %d using buffer owned by %d\n", - DRM_CURRENTPID, buf->pid ); + if ( buf->filp != filp ) { + DRM_ERROR( "process %d using buffer owned by %p\n", + DRM_CURRENTPID, buf->filp ); return DRM_ERR(EINVAL); } if ( buf->pending ) { @@ -1570,7 +1569,7 @@ drm_radeon_tex_image_t image; int ret; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); DRM_COPY_FROM_USER_IOCTL( tex, (drm_radeon_texture_t *)data, sizeof(tex) ); @@ -1587,7 +1586,7 @@ RING_SPACE_TEST_WITH_RETURN( dev_priv ); VB_AGE_TEST_WITH_RETURN( dev_priv ); - ret = radeon_cp_dispatch_texture( dev, &tex, &image ); + ret = radeon_cp_dispatch_texture( filp, dev, &tex, &image ); COMMIT_RING(); return ret; @@ -1600,7 +1599,7 @@ drm_radeon_stipple_t stipple; u32 mask[32]; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); DRM_COPY_FROM_USER_IOCTL( stipple, (drm_radeon_stipple_t *)data, sizeof(stipple) ); @@ -1625,7 +1624,7 @@ drm_radeon_indirect_t indirect; RING_LOCALS; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); @@ -1647,9 +1646,9 @@ buf = dma->buflist[indirect.idx]; - if ( buf->pid != DRM_CURRENTPID ) { - DRM_ERROR( "process %d using buffer owned by %d\n", - DRM_CURRENTPID, buf->pid ); + if ( buf->filp != filp ) { + DRM_ERROR( "process %d using buffer owned by %p\n", + DRM_CURRENTPID, buf->filp ); return DRM_ERR(EINVAL); } if ( buf->pending ) { @@ -1702,7 +1701,7 @@ int i; unsigned char laststate; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); @@ -1727,9 +1726,9 @@ buf = dma->buflist[vertex.idx]; - if ( buf->pid != DRM_CURRENTPID ) { - DRM_ERROR( "process %d using buffer owned by %d\n", - DRM_CURRENTPID, buf->pid ); + if ( buf->filp != filp ) { + DRM_ERROR( "process %d using buffer owned by %p\n", + DRM_CURRENTPID, buf->filp ); return DRM_ERR(EINVAL); } @@ -2029,7 +2028,7 @@ drm_radeon_cmd_header_t header; int orig_nbox; - LOCK_TEST_WITH_RETURN( dev ); + LOCK_TEST_WITH_RETURN( dev, filp ); if ( !dev_priv ) { DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ ); @@ -2098,8 +2097,9 @@ } buf = dma->buflist[idx]; - if ( buf->pid != DRM_CURRENTPID || buf->pending ) { - DRM_ERROR( "bad buffer\n" ); + if ( buf->filp != filp || buf->pending ) { + DRM_ERROR( "bad buffer %p %p %d\n", + buf->filp, filp, buf->pending); return DRM_ERR(EINVAL); } diff -Nru a/drivers/char/drm/sis.h b/drivers/char/drm/sis.h --- a/drivers/char/drm/sis.h Wed Apr 2 22:24:07 2003 +++ b/drivers/char/drm/sis.h Wed Apr 2 22:24:07 2003 @@ -24,7 +24,7 @@ * DEALINGS IN THE SOFTWARE. * */ -/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/sis.h,v 1.2 2001/12/19 21:25:59 dawes Exp $ */ +/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/sis.h,v 1.3 2002/10/30 12:52:38 alanh Exp $ */ #ifndef __SIS_H__ #define __SIS_H__ diff -Nru a/drivers/char/drm/sis_mm.c b/drivers/char/drm/sis_mm.c --- a/drivers/char/drm/sis_mm.c Wed Apr 2 22:24:06 2003 +++ b/drivers/char/drm/sis_mm.c Wed Apr 2 22:24:06 2003 @@ -182,10 +182,10 @@ if(block){ /* TODO */ agp.offset = block->ofs; - agp.free = (unsigned int)block; + agp.free = (unsigned long)block; if(!add_alloc_set(agp.context, AGP_TYPE, agp.free)){ DRM_DEBUG("adding to allocation set fails\n"); - mmFreeMem((PMemBlock)agp.free); + mmFreeMem((PMemBlock)(unsigned long)agp.free); retval = -1; } } @@ -218,7 +218,7 @@ return -1; } - mmFreeMem((PMemBlock)agp.free); + mmFreeMem((PMemBlock)(unsigned long)agp.free); if(!del_alloc_set(agp.context, AGP_TYPE, agp.free)) retval = -1; @@ -288,7 +288,7 @@ retval = setFirst(set, &item); while(retval){ DRM_DEBUG("free agp memory 0x%x\n", item); - mmFreeMem((PMemBlock)item); + mmFreeMem((PMemBlock)(unsigned long)item); retval = setNext(set, &item); } setDestroy(set); diff -Nru a/drivers/char/hw_random.c b/drivers/char/hw_random.c --- a/drivers/char/hw_random.c Wed Apr 2 22:24:05 2003 +++ b/drivers/char/hw_random.c Wed Apr 2 22:24:05 2003 @@ -151,6 +151,7 @@ */ static struct pci_device_id rng_pci_tbl[] __initdata = { { 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_amd }, + { 0x1022, 0x746b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_amd }, { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel }, diff -Nru a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig --- a/drivers/char/ipmi/Kconfig Wed Apr 2 22:24:06 2003 +++ b/drivers/char/ipmi/Kconfig Wed Apr 2 22:24:06 2003 @@ -7,8 +7,14 @@ tristate 'IPMI top-level message handler' help This enables the central IPMI message handler, required for IPMI - to work. Note that you must have this enabled to do any other IPMI - things. See IPMI.txt for more details. + to work. + + IPMI is a standard for managing sensors (temperature, + voltage, etc.) in a system. + + See Documentation/IPMI.txt for more details on the driver. + + If unsure, say N. config IPMI_PANIC_EVENT bool 'Generate a panic event to all BMCs on a panic' diff -Nru a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c --- a/drivers/char/ipmi/ipmi_devintf.c Wed Apr 2 22:24:07 2003 +++ b/drivers/char/ipmi/ipmi_devintf.c Wed Apr 2 22:24:07 2003 @@ -449,7 +449,7 @@ if (if_num > MAX_DEVICES) return; - snprinf(name, sizeof(name), "ipmidev/%d", if_num); + snprintf(name, sizeof(name), "ipmidev/%d", if_num); handles[if_num] = devfs_register(NULL, name, DEVFS_FL_NONE, ipmi_major, if_num, diff -Nru a/drivers/char/ipmi/ipmi_kcs_intf.c b/drivers/char/ipmi/ipmi_kcs_intf.c --- a/drivers/char/ipmi/ipmi_kcs_intf.c Wed Apr 2 22:24:04 2003 +++ b/drivers/char/ipmi/ipmi_kcs_intf.c Wed Apr 2 22:24:04 2003 @@ -826,7 +826,7 @@ if (kcs_port && kcs_physaddr) return -EINVAL; - new_kcs = kmalloc(kcs_size(), GFP_KERNEL); + new_kcs = kmalloc(sizeof(*new_kcs), GFP_KERNEL); if (!new_kcs) { printk(KERN_ERR "ipmi_kcs: out of memory\n"); return -ENOMEM; diff -Nru a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c --- a/drivers/char/ipmi/ipmi_kcs_sm.c Wed Apr 2 22:24:04 2003 +++ b/drivers/char/ipmi/ipmi_kcs_sm.c Wed Apr 2 22:24:04 2003 @@ -468,7 +468,7 @@ break; case KCS_HOSED: - return KCS_SM_HOSED; + break; } if (kcs->state == KCS_HOSED) { diff -Nru a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c --- a/drivers/char/pcmcia/synclink_cs.c Wed Apr 2 22:24:05 2003 +++ b/drivers/char/pcmcia/synclink_cs.c Wed Apr 2 22:24:05 2003 @@ -76,7 +76,6 @@ #include #include #include -#include #ifdef CONFIG_SYNCLINK_SYNCPPP_MODULE #define CONFIG_SYNCLINK_SYNCPPP 1 @@ -241,7 +240,6 @@ dev_link_t link; dev_node_t node; int stop; - struct bus_operations *bus; /* SPPP/Cisco HDLC device parts */ int netcount; @@ -826,7 +824,6 @@ break; case CS_EVENT_CARD_INSERTION: link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - info->bus = args->bus; mgslpc_config(link); break; case CS_EVENT_PM_SUSPEND: diff -Nru a/drivers/char/pty.c b/drivers/char/pty.c --- a/drivers/char/pty.c Wed Apr 2 22:24:05 2003 +++ b/drivers/char/pty.c Wed Apr 2 22:24:05 2003 @@ -362,6 +362,7 @@ init_waitqueue_head(&pty_state[i].open_wait); memset(&pty_driver, 0, sizeof(struct tty_driver)); pty_driver.magic = TTY_DRIVER_MAGIC; + pty_driver.owner = THIS_MODULE; pty_driver.driver_name = "pty_master"; #ifdef CONFIG_DEVFS_FS pty_driver.name = "pty/m%d"; diff -Nru a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c --- a/drivers/char/rio/rio_linux.c Wed Apr 2 22:24:06 2003 +++ b/drivers/char/rio/rio_linux.c Wed Apr 2 22:24:06 2003 @@ -1139,7 +1139,6 @@ struct vpd_prom *vpdp; int okboard; - #ifdef CONFIG_PCI #ifndef TWO_ZERO struct pci_dev *pdev = NULL; @@ -1161,8 +1160,16 @@ rio_debug=-1; } + if (misc_register(&rio_fw_device) < 0) { + printk(KERN_ERR "RIO: Unable to register firmware loader driver.\n"); + return -EIO; + } + retval = rio_init_datastructures (); - if (retval < 0) return retval; + if (retval < 0) { + misc_deregister(&rio_fw_device); + return retval; + } #ifdef CONFIG_PCI if (pci_present ()) { @@ -1400,12 +1407,10 @@ if (found) { rio_dprintk (RIO_DEBUG_INIT, "rio: total of %d boards detected.\n", found); - - if (misc_register(&rio_fw_device) < 0) { - printk(KERN_ERR "RIO: Unable to register firmware loader driver.\n"); - return -EIO; - } rio_init_drivers (); + } else { + /* deregister the misc device we created earlier */ + misc_deregister(&rio_fw_device); } func_exit(); diff -Nru a/drivers/char/sonypi.c b/drivers/char/sonypi.c --- a/drivers/char/sonypi.c Wed Apr 2 22:24:06 2003 +++ b/drivers/char/sonypi.c Wed Apr 2 22:24:06 2003 @@ -532,7 +532,7 @@ ret = -EFAULT; break; case SONYPI_IOCGBAT1REM: - if (ec_read16(SONYPI_BAT1_FULL, &val16)) { + if (ec_read16(SONYPI_BAT1_LEFT, &val16)) { ret = -EIO; break; } @@ -540,7 +540,7 @@ ret = -EFAULT; break; case SONYPI_IOCGBAT2CAP: - if (ec_read16(SONYPI_BAT1_FULL, &val16)) { + if (ec_read16(SONYPI_BAT2_FULL, &val16)) { ret = -EIO; break; } @@ -548,7 +548,7 @@ ret = -EFAULT; break; case SONYPI_IOCGBAT2REM: - if (ec_read16(SONYPI_BAT1_FULL, &val16)) { + if (ec_read16(SONYPI_BAT2_LEFT, &val16)) { ret = -EIO; break; } diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c --- a/drivers/char/tty_io.c Wed Apr 2 22:24:06 2003 +++ b/drivers/char/tty_io.c Wed Apr 2 22:24:06 2003 @@ -1662,13 +1662,6 @@ return put_user(real_tty->session, arg); } -static int tiocttygstruct(struct tty_struct *tty, struct tty_struct *arg) -{ - if (copy_to_user(arg, tty, sizeof(*arg))) - return -EFAULT; - return 0; -} - static int tiocsetd(struct tty_struct *tty, int *arg) { int ldisc; @@ -1795,9 +1788,6 @@ case TIOCLINUX: return tioclinux(tty, arg); #endif - case TIOCTTYGSTRUCT: - return tiocttygstruct(tty, (struct tty_struct *) arg); - /* * Break handling */ @@ -2143,31 +2133,16 @@ */ int tty_unregister_driver(struct tty_driver *driver) { - int retval; - struct tty_driver *p; - int i, found = 0; + int retval, i; struct termios *tp; - const char *othername = NULL; - + if (*driver->refcount) return -EBUSY; - list_for_each_entry(p, &tty_drivers, tty_drivers) { - if (p == driver) - found++; - else if (p->major == driver->major) - othername = p->name; - } - - if (!found) - return -ENOENT; - - if (othername == NULL) { - retval = unregister_chrdev(driver->major, driver->name); - if (retval) - return retval; - } else - register_chrdev(driver->major, othername, &tty_fops); + retval = unregister_chrdev_region(driver->major, driver->minor_start, + driver->num, driver->name); + if (retval) + return retval; list_del(&driver->tty_drivers); @@ -2261,6 +2236,7 @@ */ memset(&dev_tty_driver, 0, sizeof(struct tty_driver)); dev_tty_driver.magic = TTY_DRIVER_MAGIC; + dev_tty_driver.owner = THIS_MODULE; dev_tty_driver.driver_name = "/dev/tty"; dev_tty_driver.name = dev_tty_driver.driver_name + 5; dev_tty_driver.name_base = 0; @@ -2274,6 +2250,7 @@ panic("Couldn't register /dev/tty driver\n"); dev_syscons_driver = dev_tty_driver; + dev_syscons_driver.owner = THIS_MODULE; dev_syscons_driver.driver_name = "/dev/console"; dev_syscons_driver.name = dev_syscons_driver.driver_name + 5; dev_syscons_driver.major = TTYAUX_MAJOR; @@ -2286,6 +2263,7 @@ #ifdef CONFIG_UNIX98_PTYS dev_ptmx_driver = dev_tty_driver; + dev_ptmx_driver.owner = THIS_MODULE; dev_ptmx_driver.driver_name = "/dev/ptmx"; dev_ptmx_driver.name = dev_ptmx_driver.driver_name + 5; dev_ptmx_driver.major= TTYAUX_MAJOR; @@ -2299,6 +2277,7 @@ #ifdef CONFIG_VT dev_console_driver = dev_tty_driver; + dev_console_driver.owner = THIS_MODULE; dev_console_driver.driver_name = "/dev/vc/0"; dev_console_driver.name = dev_console_driver.driver_name + 5; dev_console_driver.major = TTY_MAJOR; @@ -2347,9 +2326,6 @@ rs_8xx_init(); #endif /* CONFIG_8xx */ pty_init(); -#ifdef CONFIG_MOXA_SMARTIO - mxser_init(); -#endif #ifdef CONFIG_MOXA_INTELLIO moxa_init(); #endif diff -Nru a/drivers/char/vt.c b/drivers/char/vt.c --- a/drivers/char/vt.c Wed Apr 2 22:24:07 2003 +++ b/drivers/char/vt.c Wed Apr 2 22:24:07 2003 @@ -2502,6 +2502,7 @@ { memset(&console_driver, 0, sizeof(struct tty_driver)); console_driver.magic = TTY_DRIVER_MAGIC; + console_driver.owner = THIS_MODULE; console_driver.name = "vc/%d"; console_driver.name_base = 1; console_driver.major = TTY_MAJOR; diff -Nru a/drivers/char/watchdog/indydog.c b/drivers/char/watchdog/indydog.c --- a/drivers/char/watchdog/indydog.c Wed Apr 2 22:24:07 2003 +++ b/drivers/char/watchdog/indydog.c Wed Apr 2 22:24:07 2003 @@ -155,7 +155,7 @@ .fops = &indydog_fops, }; -static const char banner[] __initdata = KERN_INFO "Hardware Watchdog Timer for SGI IP22: 0.2\n"; +static char banner[] __initdata = KERN_INFO "Hardware Watchdog Timer for SGI IP22: 0.2\n"; static int __init watchdog_init(void) { diff -Nru a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig --- a/drivers/i2c/Kconfig Wed Apr 2 22:24:04 2003 +++ b/drivers/i2c/Kconfig Wed Apr 2 22:24:04 2003 @@ -196,17 +196,6 @@ . The module will be called i2c-dev. -config I2C_PROC - tristate "I2C /proc interface (required for hardware sensors)" - depends on I2C && SYSCTL - help - This provides support for i2c device entries in the /proc filesystem. - The entries will be found in /proc/sys/dev/sensors. - - This code is also available as a module. If you want to compile - it as a module, say M here and read . - The module will be called i2c-proc. - source drivers/i2c/busses/Kconfig source drivers/i2c/chips/Kconfig diff -Nru a/drivers/i2c/Makefile b/drivers/i2c/Makefile --- a/drivers/i2c/Makefile Wed Apr 2 22:24:04 2003 +++ b/drivers/i2c/Makefile Wed Apr 2 22:24:04 2003 @@ -14,5 +14,5 @@ obj-$(CONFIG_ITE_I2C_ADAP) += i2c-adap-ite.o obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o obj-$(CONFIG_SCx200_ACB) += scx200_acb.o -obj-$(CONFIG_I2C_PROC) += i2c-proc.o +obj-$(CONFIG_I2C_SENSOR) += i2c-sensor.o obj-y += busses/ chips/ diff -Nru a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig --- a/drivers/i2c/busses/Kconfig Wed Apr 2 22:24:07 2003 +++ b/drivers/i2c/busses/Kconfig Wed Apr 2 22:24:07 2003 @@ -1,13 +1,12 @@ # # Sensor device configuration -# All depend on EXPERIMENTAL, I2C and I2C_PROC. # menu "I2C Hardware Sensors Mainboard support" config I2C_ALI15X3 tristate " ALI 15x3" - depends on I2C && I2C_PROC && PCI && EXPERIMENTAL + depends on I2C && PCI && EXPERIMENTAL help If you say yes to this option, support will be included for the Acer Labs Inc. (ALI) M1514 and M1543 motherboard I2C interfaces. @@ -21,7 +20,7 @@ config I2C_AMD756 tristate " AMD 756/766" - depends on I2C && I2C_PROC + depends on I2C && EXPERIMENTAL help If you say yes to this option, support will be included for the AMD 756/766/768 mainboard I2C interfaces. @@ -38,7 +37,7 @@ config I2C_AMD8111 tristate " AMD 8111" - depends on I2C && I2C_PROC + depends on I2C && EXPERIMENTAL help If you say yes to this option, support will be included for the AMD 8111 mainboard I2C interfaces. @@ -55,7 +54,7 @@ config I2C_I801 tristate " Intel 801" - depends on I2C && I2C_PROC && PCI && EXPERIMENTAL + depends on I2C && PCI && EXPERIMENTAL help If you say yes to this option, support will be included for the Intel 801 family of mainboard I2C interfaces. Specifically, the following @@ -78,7 +77,7 @@ config I2C_ISA tristate " ISA Bus support" - depends on I2C && I2C_PROC && ISA && EXPERIMENTAL + depends on I2C && ISA && EXPERIMENTAL help If you say yes to this option, support will be included for i2c interfaces that are on the ISA bus. @@ -96,7 +95,7 @@ config I2C_PIIX4 tristate " Intel PIIX4" - depends on I2C && I2C_PROC && PCI && EXPERIMENTAL + depends on I2C && PCI && EXPERIMENTAL help If you say yes to this option, support will be included for the Intel PIIX4 family of mainboard I2C interfaces. Specifically, the following diff -Nru a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c --- a/drivers/i2c/busses/i2c-ali15x3.c Wed Apr 2 22:24:05 2003 +++ b/drivers/i2c/busses/i2c-ali15x3.c Wed Apr 2 22:24:05 2003 @@ -474,9 +474,11 @@ static struct i2c_adapter ali15x3_adapter = { .owner = THIS_MODULE, - .name = "unset", .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_ALI15X3, .algo = &smbus_algorithm, + .dev = { + .name = "unset", + }, }; static struct pci_device_id ali15x3_ids[] __devinitdata = { @@ -500,8 +502,8 @@ /* set up the driverfs linkage to our parent device */ ali15x3_adapter.dev.parent = &dev->dev; - sprintf(ali15x3_adapter.name, "SMBus ALI15X3 adapter at %04x", - ali15x3_smba); + snprintf(ali15x3_adapter.dev.name, DEVICE_NAME_SIZE, + "SMBus ALI15X3 adapter at %04x", ali15x3_smba); return i2c_add_adapter(&ali15x3_adapter); } diff -Nru a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c --- a/drivers/i2c/busses/i2c-amd756.c Wed Apr 2 22:24:07 2003 +++ b/drivers/i2c/busses/i2c-amd756.c Wed Apr 2 22:24:07 2003 @@ -312,9 +312,11 @@ static struct i2c_adapter amd756_adapter = { .owner = THIS_MODULE, - .name = "unset", .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD756, .algo = &smbus_algorithm, + .dev = { + .name = "unset", + }, }; enum chiptype { AMD756, AMD766, AMD768, NFORCE }; @@ -376,7 +378,7 @@ /* set up the driverfs linkage to our parent device */ amd756_adapter.dev.parent = &pdev->dev; - sprintf(amd756_adapter.name, + snprintf(amd756_adapter.dev.name, DEVICE_NAME_SIZE, "SMBus AMD75x adapter at %04x", amd756_ioport); error = i2c_add_adapter(&amd756_adapter); diff -Nru a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c --- a/drivers/i2c/busses/i2c-amd8111.c Wed Apr 2 22:24:07 2003 +++ b/drivers/i2c/busses/i2c-amd8111.c Wed Apr 2 22:24:07 2003 @@ -357,8 +357,8 @@ goto out_kfree; smbus->adapter.owner = THIS_MODULE; - sprintf(smbus->adapter.name, - "SMBus2 AMD8111 adapter at %04x", smbus->base); + snprintf(smbus->adapter.dev.name, DEVICE_NAME_SIZE, + "SMBus2 AMD8111 adapter at %04x", smbus->base); smbus->adapter.id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD8111; smbus->adapter.algo = &smbus_algorithm; smbus->adapter.algo_data = smbus; diff -Nru a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c --- a/drivers/i2c/busses/i2c-i801.c Wed Apr 2 22:24:05 2003 +++ b/drivers/i2c/busses/i2c-i801.c Wed Apr 2 22:24:05 2003 @@ -546,9 +546,11 @@ static struct i2c_adapter i801_adapter = { .owner = THIS_MODULE, - .name = "unset", .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_I801, .algo = &smbus_algorithm, + .dev = { + .name = "unset", + }, }; static struct pci_device_id i801_ids[] __devinitdata = { @@ -597,8 +599,8 @@ /* set up the driverfs linkage to our parent device */ i801_adapter.dev.parent = &dev->dev; - sprintf(i801_adapter.name, "SMBus I801 adapter at %04x", - i801_smba); + snprintf(i801_adapter.dev.name, DEVICE_NAME_SIZE, + "SMBus I801 adapter at %04x", i801_smba); return i2c_add_adapter(&i801_adapter); } diff -Nru a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c --- a/drivers/i2c/busses/i2c-isa.c Wed Apr 2 22:24:05 2003 +++ b/drivers/i2c/busses/i2c-isa.c Wed Apr 2 22:24:05 2003 @@ -39,9 +39,11 @@ /* There can only be one... */ static struct i2c_adapter isa_adapter = { .owner = THIS_MODULE, - .name = "ISA main adapter", .id = I2C_ALGO_ISA | I2C_HW_ISA, .algo = &isa_algorithm, + .dev = { + .name = "ISA main adapter", + }, }; static int __init i2c_isa_init(void) diff -Nru a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c --- a/drivers/i2c/busses/i2c-piix4.c Wed Apr 2 22:24:05 2003 +++ b/drivers/i2c/busses/i2c-piix4.c Wed Apr 2 22:24:05 2003 @@ -394,9 +394,11 @@ static struct i2c_adapter piix4_adapter = { .owner = THIS_MODULE, - .name = "unset", .id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_PIIX4, .algo = &smbus_algorithm, + .dev = { + .name = "unset", + }, }; static struct pci_device_id piix4_ids[] __devinitdata = { @@ -449,8 +451,8 @@ /* set up the driverfs linkage to our parent device */ piix4_adapter.dev.parent = &dev->dev; - sprintf(piix4_adapter.name, "SMBus PIIX4 adapter at %04x", - piix4_smba); + snprintf(piix4_adapter.dev.name, DEVICE_NAME_SIZE, + "SMBus PIIX4 adapter at %04x", piix4_smba); retval = i2c_add_adapter(&piix4_adapter); diff -Nru a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig --- a/drivers/i2c/chips/Kconfig Wed Apr 2 22:24:05 2003 +++ b/drivers/i2c/chips/Kconfig Wed Apr 2 22:24:05 2003 @@ -1,13 +1,13 @@ # # Sensor device configuration -# All depend on EXPERIMENTAL, I2C and I2C_PROC. +# All depend on EXPERIMENTAL and I2C # menu "I2C Hardware Sensors Chip support" config SENSORS_ADM1021 tristate " Analog Devices ADM1021 and compatibles" - depends on I2C && I2C_PROC + depends on I2C && EXPERIMENTAL help If you say yes here you get support for Analog Devices ADM1021 and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A, @@ -24,7 +24,7 @@ config SENSORS_LM75 tristate " National Semiconductors LM75 and compatibles" - depends on I2C && I2C_PROC + depends on I2C && EXPERIMENTAL help If you say yes here you get support for National Semiconductor LM75 sensor chips and clones: Dallas Semi DS75 and DS1775, TelCon @@ -36,5 +36,37 @@ You will also need the latest user-space utilties: you can find them in the lm_sensors package, which you can download at http://www.lm-sensors.nu + +config SENSORS_VIA686A + tristate " VIA686A" + depends on I2C && EXPERIMENTAL + help + support for via686a + If you say yes here you get support for the integrated sensors in + Via 686A/B South Bridges. This can also be built as a module + which can be inserted and removed while the kernel is running. + + You will also need the latest user-space utilties: you can find them + in the lm_sensors package, which you can download at + http://www.lm-sensors.nu + +config SENSORS_W83781D + tristate " Winbond W83781D, W83782D, W83783S, W83627HF, Asus AS99127F" + depends on I2C && EXPERIMENTAL + help + If you say yes here you get support for the Winbond W8378x series + of sensor chips: the W83781D, W83782D, W83783S and W83682HF, + and the similar Asus AS99127F. This + can also be built as a module which can be inserted and removed + while the kernel is running. + + You will also need the latest user-space utilties: you can find them + in the lm_sensors package, which you can download at + http://www.lm-sensors.nu + +config I2C_SENSOR + tristate + depends on SENSORS_ADM1021 || SENSORS_LM75 || SENSORS_VIA686A || SENSORS_W83781D + default m endmenu diff -Nru a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile --- a/drivers/i2c/chips/Makefile Wed Apr 2 22:24:04 2003 +++ b/drivers/i2c/chips/Makefile Wed Apr 2 22:24:04 2003 @@ -4,3 +4,5 @@ obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o obj-$(CONFIG_SENSORS_LM75) += lm75.o +obj-$(CONFIG_SENSORS_VIA686A) += via686a.o +obj-$(CONFIG_SENSORS_W83781D) += w83781d.o diff -Nru a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c --- a/drivers/i2c/chips/adm1021.c Wed Apr 2 22:24:04 2003 +++ b/drivers/i2c/chips/adm1021.c Wed Apr 2 22:24:04 2003 @@ -23,7 +23,7 @@ #include #include #include -#include +#include /* Registers */ @@ -53,34 +53,34 @@ /* The adm1021 registers */ /* Read-only */ -#define ADM1021_REG_TEMP 0x00 -#define ADM1021_REG_REMOTE_TEMP 0x01 -#define ADM1021_REG_STATUS 0x02 -#define ADM1021_REG_MAN_ID 0x0FE /* 0x41 = AMD, 0x49 = TI, 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi*/ -#define ADM1021_REG_DEV_ID 0x0FF /* ADM1021 = 0x0X, ADM1023 = 0x3X */ -#define ADM1021_REG_DIE_CODE 0x0FF /* MAX1617A */ +#define ADM1021_REG_TEMP 0x00 +#define ADM1021_REG_REMOTE_TEMP 0x01 +#define ADM1021_REG_STATUS 0x02 +#define ADM1021_REG_MAN_ID 0x0FE /* 0x41 = AMD, 0x49 = TI, 0x4D = Maxim, 0x23 = Genesys , 0x54 = Onsemi*/ +#define ADM1021_REG_DEV_ID 0x0FF /* ADM1021 = 0x0X, ADM1023 = 0x3X */ +#define ADM1021_REG_DIE_CODE 0x0FF /* MAX1617A */ /* These use different addresses for reading/writing */ -#define ADM1021_REG_CONFIG_R 0x03 -#define ADM1021_REG_CONFIG_W 0x09 -#define ADM1021_REG_CONV_RATE_R 0x04 -#define ADM1021_REG_CONV_RATE_W 0x0A +#define ADM1021_REG_CONFIG_R 0x03 +#define ADM1021_REG_CONFIG_W 0x09 +#define ADM1021_REG_CONV_RATE_R 0x04 +#define ADM1021_REG_CONV_RATE_W 0x0A /* These are for the ADM1023's additional precision on the remote temp sensor */ -#define ADM1021_REG_REM_TEMP_PREC 0x010 -#define ADM1021_REG_REM_OFFSET 0x011 -#define ADM1021_REG_REM_OFFSET_PREC 0x012 -#define ADM1021_REG_REM_TOS_PREC 0x013 -#define ADM1021_REG_REM_THYST_PREC 0x014 +#define ADM1021_REG_REM_TEMP_PREC 0x010 +#define ADM1021_REG_REM_OFFSET 0x011 +#define ADM1021_REG_REM_OFFSET_PREC 0x012 +#define ADM1021_REG_REM_TOS_PREC 0x013 +#define ADM1021_REG_REM_THYST_PREC 0x014 /* limits */ -#define ADM1021_REG_TOS_R 0x05 -#define ADM1021_REG_TOS_W 0x0B -#define ADM1021_REG_REMOTE_TOS_R 0x07 -#define ADM1021_REG_REMOTE_TOS_W 0x0D -#define ADM1021_REG_THYST_R 0x06 -#define ADM1021_REG_THYST_W 0x0C -#define ADM1021_REG_REMOTE_THYST_R 0x08 -#define ADM1021_REG_REMOTE_THYST_W 0x0E +#define ADM1021_REG_TOS_R 0x05 +#define ADM1021_REG_TOS_W 0x0B +#define ADM1021_REG_REMOTE_TOS_R 0x07 +#define ADM1021_REG_REMOTE_TOS_W 0x0D +#define ADM1021_REG_THYST_R 0x06 +#define ADM1021_REG_THYST_W 0x0C +#define ADM1021_REG_REMOTE_THYST_R 0x08 +#define ADM1021_REG_REMOTE_THYST_W 0x0E /* write-only */ -#define ADM1021_REG_ONESHOT 0x0F +#define ADM1021_REG_ONESHOT 0x0F /* Conversions. Rounding and limit checking is only done on the TO_REG @@ -88,8 +88,8 @@ these macros are called: arguments may be evaluated more than once. Fixing this is just not worth it. */ /* Conversions note: 1021 uses normal integer signed-byte format*/ -#define TEMP_FROM_REG(val) (val > 127 ? val-256 : val) -#define TEMP_TO_REG(val) (SENSORS_LIMIT((val < 0 ? val+256 : val),0,255)) +#define TEMP_FROM_REG(val) (val > 127 ? val-256 : val) +#define TEMP_TO_REG(val) (SENSORS_LIMIT((val < 0 ? val+256 : val),0,255)) /* Initial values */ @@ -97,44 +97,43 @@ they don't quite work like a thermostat the way the LM75 does. I.e., a lower temp than THYST actually triggers an alarm instead of clearing it. Weird, ey? --Phil */ -#define adm1021_INIT_TOS 60 -#define adm1021_INIT_THYST 20 -#define adm1021_INIT_REMOTE_TOS 60 -#define adm1021_INIT_REMOTE_THYST 20 +#define adm1021_INIT_TOS 60 +#define adm1021_INIT_THYST 20 +#define adm1021_INIT_REMOTE_TOS 60 +#define adm1021_INIT_REMOTE_THYST 20 /* Each client has this additional data */ struct adm1021_data { - int sysctl_id; enum chips type; struct semaphore update_lock; char valid; /* !=0 if following fields are valid */ unsigned long last_updated; /* In jiffies */ - u8 temp, temp_os, temp_hyst; /* Register values */ - u8 remote_temp, remote_temp_os, remote_temp_hyst, alarms, die_code; + u8 temp_max; /* Register values */ + u8 temp_hyst; + u8 temp_input; + u8 remote_temp_max; + u8 remote_temp_hyst; + u8 remote_temp_input; + u8 alarms; + /* special values for ADM1021 only */ + u8 die_code; /* Special values for ADM1023 only */ - u8 remote_temp_prec, remote_temp_os_prec, remote_temp_hyst_prec, - remote_temp_offset, remote_temp_offset_prec; + u8 remote_temp_prec; + u8 remote_temp_os_prec; + u8 remote_temp_hyst_prec; + u8 remote_temp_offset; + u8 remote_temp_offset_prec; }; static int adm1021_attach_adapter(struct i2c_adapter *adapter); -static int adm1021_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); +static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind); static void adm1021_init_client(struct i2c_client *client); static int adm1021_detach_client(struct i2c_client *client); static int adm1021_read_value(struct i2c_client *client, u8 reg); static int adm1021_write_value(struct i2c_client *client, u8 reg, u16 value); -static void adm1021_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1021_remote_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, - long *results); -static void adm1021_alarms(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); -static void adm1021_die_code(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); static void adm1021_update_client(struct i2c_client *client); /* (amalysh) read only mode, otherwise any limit's writing confuse BIOS */ @@ -144,52 +143,70 @@ /* This is the driver that will be inserted */ static struct i2c_driver adm1021_driver = { .owner = THIS_MODULE, - .name = "ADM1021, MAX1617 sensor driver", + .name = "ADM1021-MAX1617", .id = I2C_DRIVERID_ADM1021, .flags = I2C_DF_NOTIFY, .attach_adapter = adm1021_attach_adapter, .detach_client = adm1021_detach_client, }; -/* These files are created for each detected adm1021. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table adm1021_dir_table_template[] = { - {ADM1021_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1021_temp}, - {ADM1021_SYSCTL_REMOTE_TEMP, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1021_remote_temp}, - {ADM1021_SYSCTL_DIE_CODE, "die_code", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1021_die_code}, - {ADM1021_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1021_alarms}, - {0} -}; - -static ctl_table adm1021_max_dir_table_template[] = { - {ADM1021_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1021_temp}, - {ADM1021_SYSCTL_REMOTE_TEMP, "temp2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1021_remote_temp}, - {ADM1021_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &adm1021_alarms}, - {0} -}; - /* I choose here for semi-static allocation. Complete dynamic allocation could also be used; the code needed for this would probably take more memory than the datastructure takes now. */ static int adm1021_id = 0; +#define show(value) \ +static ssize_t show_##value(struct device *dev, char *buf) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct adm1021_data *data = i2c_get_clientdata(client); \ + int temp; \ + \ + adm1021_update_client(client); \ + temp = TEMP_FROM_REG(data->value); \ + return sprintf(buf, "%d\n", temp); \ +} +show(temp_max); +show(temp_hyst); +show(temp_input); +show(remote_temp_max); +show(remote_temp_hyst); +show(remote_temp_input); +show(alarms); +show(die_code); + +#define set(value, reg) \ +static ssize_t set_##value(struct device *dev, const char *buf, size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct adm1021_data *data = i2c_get_clientdata(client); \ + int temp = simple_strtoul(buf, NULL, 10); \ + \ + data->value = TEMP_TO_REG(temp); \ + adm1021_write_value(client, reg, data->value); \ + return count; \ +} +set(temp_max, ADM1021_REG_TOS_W); +set(temp_hyst, ADM1021_REG_THYST_W); +set(remote_temp_max, ADM1021_REG_REMOTE_TOS_W); +set(remote_temp_hyst, ADM1021_REG_REMOTE_THYST_W); + +static DEVICE_ATTR(temp_max1, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max); +static DEVICE_ATTR(temp_min1, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst); +static DEVICE_ATTR(temp_input1, S_IRUGO, show_temp_input, NULL); +static DEVICE_ATTR(temp_max2, S_IWUSR | S_IRUGO, show_remote_temp_max, set_remote_temp_max); +static DEVICE_ATTR(temp_min2, S_IWUSR | S_IRUGO, show_remote_temp_hyst, set_remote_temp_hyst); +static DEVICE_ATTR(temp_input2, S_IRUGO, show_remote_temp_input, NULL); +static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static DEVICE_ATTR(die_code, S_IRUGO, show_die_code, NULL); + + static int adm1021_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, adm1021_detect); } -static int adm1021_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) +static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind) { int i; struct i2c_client *new_client; @@ -202,8 +219,7 @@ at this moment; i2c_detect really won't call us. */ #ifdef DEBUG if (i2c_is_isa_adapter(adapter)) { - printk - ("adm1021.o: adm1021_detect called for an ISA bus adapter?!?\n"); + dev_dbg(&adapter->dev, "adm1021_detect called for an ISA bus adapter?!?\n"); return 0; } #endif @@ -221,44 +237,39 @@ err = -ENOMEM; goto error0; } + memset(new_client, 0x00, sizeof(struct i2c_client) + + sizeof(struct adm1021_data)); data = (struct adm1021_data *) (new_client + 1); + i2c_set_clientdata(new_client, data); new_client->addr = address; - new_client->data = data; new_client->adapter = adapter; new_client->driver = &adm1021_driver; new_client->flags = 0; /* Now, we do the remaining detection. */ - if (kind < 0) { - if ( - (adm1021_read_value(new_client, ADM1021_REG_STATUS) & - 0x03) != 0x00) + if ((adm1021_read_value(new_client, ADM1021_REG_STATUS) & 0x03) != 0x00) goto error1; } /* Determine the chip type. */ - if (kind <= 0) { i = adm1021_read_value(new_client, ADM1021_REG_MAN_ID); if (i == 0x41) - if ((adm1021_read_value (new_client, ADM1021_REG_DEV_ID) & 0x0F0) == 0x030) - kind = adm1023; - else - kind = adm1021; + if ((adm1021_read_value(new_client, ADM1021_REG_DEV_ID) & 0x0F0) == 0x030) + kind = adm1023; + else + kind = adm1021; else if (i == 0x49) kind = thmc10; else if (i == 0x23) kind = gl523sm; else if ((i == 0x4d) && - (adm1021_read_value - (new_client, ADM1021_REG_DEV_ID) == 0x01)) + (adm1021_read_value(new_client, ADM1021_REG_DEV_ID) == 0x01)) kind = max1617a; /* LM84 Mfr ID in a different place */ - else - if (adm1021_read_value - (new_client, ADM1021_REG_CONV_RATE_R) == 0x00) + else if (adm1021_read_value(new_client, ADM1021_REG_CONV_RATE_R) == 0x00) kind = lm84; else if (i == 0x54) kind = mc1066; @@ -291,15 +302,13 @@ type_name = "mc1066"; client_name = "MC1066 chip"; } else { -#ifdef DEBUG - printk("adm1021.o: Internal error: unknown kind (%d)?!?", - kind); -#endif + dev_err(&adapter->dev, "Internal error: unknown kind (%d)?!?", + kind); goto error1; } /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); + strncpy(new_client->dev.name, client_name, DEVICE_NAME_SIZE); data->type = kind; new_client->id = adm1021_id++; @@ -310,25 +319,24 @@ if ((err = i2c_attach_client(new_client))) goto error3; - /* Register a new directory entry with module sensors */ - err = i2c_register_entry(new_client, type_name, - (data->type == adm1021) ? - adm1021_dir_table_template : - adm1021_max_dir_table_template); - if (err < 0) - goto error4; + device_create_file(&new_client->dev, &dev_attr_temp_max1); + device_create_file(&new_client->dev, &dev_attr_temp_min1); + device_create_file(&new_client->dev, &dev_attr_temp_input1); + device_create_file(&new_client->dev, &dev_attr_temp_max2); + device_create_file(&new_client->dev, &dev_attr_temp_min2); + device_create_file(&new_client->dev, &dev_attr_temp_input2); + device_create_file(&new_client->dev, &dev_attr_alarms); + if (data->type == adm1021) + device_create_file(&new_client->dev, &dev_attr_die_code); - data->sysctl_id = err; /* Initialize the ADM1021 chip */ adm1021_init_client(new_client); return 0; - error4: - i2c_detach_client(new_client); - error3: - error1: +error3: +error1: kfree(new_client); - error0: +error0: return err; } @@ -351,22 +359,15 @@ static int adm1021_detach_client(struct i2c_client *client) { - int err; - i2c_deregister_entry(((struct adm1021_data *) (client->data))-> - sysctl_id); - if ((err = i2c_detach_client(client))) { - printk - ("adm1021.o: Client deregistration failed, client not detached.\n"); + dev_err(&client->dev, "Client deregistration failed, client not detached.\n"); return err; } kfree(client); - return 0; - } /* All registers are byte-sized */ @@ -384,45 +385,29 @@ static void adm1021_update_client(struct i2c_client *client) { - struct adm1021_data *data = client->data; + struct adm1021_data *data = i2c_get_clientdata(client); down(&data->update_lock); if ((jiffies - data->last_updated > HZ + HZ / 2) || (jiffies < data->last_updated) || !data->valid) { + dev_dbg(&client->dev, "Starting adm1021 update\n"); -#ifdef DEBUG - printk("Starting adm1021 update\n"); -#endif - - data->temp = adm1021_read_value(client, ADM1021_REG_TEMP); - data->temp_os = - adm1021_read_value(client, ADM1021_REG_TOS_R); - data->temp_hyst = - adm1021_read_value(client, ADM1021_REG_THYST_R); - data->remote_temp = - adm1021_read_value(client, ADM1021_REG_REMOTE_TEMP); - data->remote_temp_os = - adm1021_read_value(client, ADM1021_REG_REMOTE_TOS_R); - data->remote_temp_hyst = - adm1021_read_value(client, ADM1021_REG_REMOTE_THYST_R); - data->alarms = - adm1021_read_value(client, ADM1021_REG_STATUS) & 0xec; + data->temp_input = adm1021_read_value(client, ADM1021_REG_TEMP); + data->temp_max = adm1021_read_value(client, ADM1021_REG_TOS_R); + data->temp_hyst = adm1021_read_value(client, ADM1021_REG_THYST_R); + data->remote_temp_input = adm1021_read_value(client, ADM1021_REG_REMOTE_TEMP); + data->remote_temp_max = adm1021_read_value(client, ADM1021_REG_REMOTE_TOS_R); + data->remote_temp_hyst = adm1021_read_value(client, ADM1021_REG_REMOTE_THYST_R); + data->alarms = adm1021_read_value(client, ADM1021_REG_STATUS) & 0xec; if (data->type == adm1021) - data->die_code = - adm1021_read_value(client, - ADM1021_REG_DIE_CODE); + data->die_code = adm1021_read_value(client, ADM1021_REG_DIE_CODE); if (data->type == adm1023) { - data->remote_temp_prec = - adm1021_read_value(client, ADM1021_REG_REM_TEMP_PREC); - data->remote_temp_os_prec = - adm1021_read_value(client, ADM1021_REG_REM_TOS_PREC); - data->remote_temp_hyst_prec = - adm1021_read_value(client, ADM1021_REG_REM_THYST_PREC); - data->remote_temp_offset = - adm1021_read_value(client, ADM1021_REG_REM_OFFSET); - data->remote_temp_offset_prec = - adm1021_read_value(client, ADM1021_REG_REM_OFFSET_PREC); + data->remote_temp_prec = adm1021_read_value(client, ADM1021_REG_REM_TEMP_PREC); + data->remote_temp_os_prec = adm1021_read_value(client, ADM1021_REG_REM_TOS_PREC); + data->remote_temp_hyst_prec = adm1021_read_value(client, ADM1021_REG_REM_THYST_PREC); + data->remote_temp_offset = adm1021_read_value(client, ADM1021_REG_REM_OFFSET); + data->remote_temp_offset_prec = adm1021_read_value(client, ADM1021_REG_REM_OFFSET_PREC); } data->last_updated = jiffies; data->valid = 1; @@ -432,24 +417,27 @@ } +/* FIXME, remove these four functions, they are here to verify the sysfs + * conversion is correct, or not */ +__attribute__((unused)) static void adm1021_temp(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results) { - struct adm1021_data *data = client->data; + struct adm1021_data *data = i2c_get_clientdata(client); if (operation == SENSORS_PROC_REAL_INFO) *nrels_mag = 0; else if (operation == SENSORS_PROC_REAL_READ) { adm1021_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_os); + results[0] = TEMP_FROM_REG(data->temp_max); results[1] = TEMP_FROM_REG(data->temp_hyst); - results[2] = TEMP_FROM_REG(data->temp); + results[2] = TEMP_FROM_REG(data->temp_input); *nrels_mag = 3; } else if (operation == SENSORS_PROC_REAL_WRITE) { if (*nrels_mag >= 1) { - data->temp_os = TEMP_TO_REG(results[0]); + data->temp_max = TEMP_TO_REG(results[0]); adm1021_write_value(client, ADM1021_REG_TOS_W, - data->temp_os); + data->temp_max); } if (*nrels_mag >= 2) { data->temp_hyst = TEMP_TO_REG(results[1]); @@ -459,10 +447,11 @@ } } +__attribute__((unused)) static void adm1021_remote_temp(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results) { - struct adm1021_data *data = client->data; + struct adm1021_data *data = i2c_get_clientdata(client); int prec = 0; if (operation == SENSORS_PROC_REAL_INFO) @@ -470,72 +459,57 @@ else { *nrels_mag = 0; } else if (operation == SENSORS_PROC_REAL_READ) { adm1021_update_client(client); - results[0] = TEMP_FROM_REG(data->remote_temp_os); + results[0] = TEMP_FROM_REG(data->remote_temp_max); results[1] = TEMP_FROM_REG(data->remote_temp_hyst); - results[2] = TEMP_FROM_REG(data->remote_temp); + results[2] = TEMP_FROM_REG(data->remote_temp_input); if (data->type == adm1023) { - results[0]=results[0]*1000 + - ((data->remote_temp_os_prec >> 5) * 125); - results[1]=results[1]*1000 + - ((data->remote_temp_hyst_prec >> 5) * 125); - results[2]=(TEMP_FROM_REG(data->remote_temp_offset)*1000) + - ((data->remote_temp_offset_prec >> 5) * 125); - results[3]=TEMP_FROM_REG(data->remote_temp)*1000 + - ((data->remote_temp_prec >> 5) * 125); - *nrels_mag = 4; + results[0] = results[0]*1000 + ((data->remote_temp_os_prec >> 5) * 125); + results[1] = results[1]*1000 + ((data->remote_temp_hyst_prec >> 5) * 125); + results[2] = (TEMP_FROM_REG(data->remote_temp_offset)*1000) + ((data->remote_temp_offset_prec >> 5) * 125); + results[3] = (TEMP_FROM_REG(data->remote_temp_input)*1000) + ((data->remote_temp_prec >> 5) * 125); + *nrels_mag = 4; } else { - *nrels_mag = 3; + *nrels_mag = 3; } } else if (operation == SENSORS_PROC_REAL_WRITE) { if (*nrels_mag >= 1) { if (data->type == adm1023) { - prec=((results[0]-((results[0]/1000)*1000))/125)<<5; - adm1021_write_value(client, - ADM1021_REG_REM_TOS_PREC, - prec); - results[0]=results[0]/1000; - data->remote_temp_os_prec=prec; + prec = ((results[0]-((results[0]/1000)*1000))/125)<<5; + adm1021_write_value(client, ADM1021_REG_REM_TOS_PREC, prec); + results[0] = results[0]/1000; + data->remote_temp_os_prec=prec; } - data->remote_temp_os = TEMP_TO_REG(results[0]); - adm1021_write_value(client, - ADM1021_REG_REMOTE_TOS_W, - data->remote_temp_os); + data->remote_temp_max = TEMP_TO_REG(results[0]); + adm1021_write_value(client, ADM1021_REG_REMOTE_TOS_W, data->remote_temp_max); } if (*nrels_mag >= 2) { if (data->type == adm1023) { - prec=((results[1]-((results[1]/1000)*1000))/125)<<5; - adm1021_write_value(client, - ADM1021_REG_REM_THYST_PREC, - prec); - results[1]=results[1]/1000; - data->remote_temp_hyst_prec=prec; + prec = ((results[1]-((results[1]/1000)*1000))/125)<<5; + adm1021_write_value(client, ADM1021_REG_REM_THYST_PREC, prec); + results[1] = results[1]/1000; + data->remote_temp_hyst_prec=prec; } data->remote_temp_hyst = TEMP_TO_REG(results[1]); - adm1021_write_value(client, - ADM1021_REG_REMOTE_THYST_W, - data->remote_temp_hyst); + adm1021_write_value(client, ADM1021_REG_REMOTE_THYST_W, data->remote_temp_hyst); } if (*nrels_mag >= 3) { if (data->type == adm1023) { - prec=((results[2]-((results[2]/1000)*1000))/125)<<5; - adm1021_write_value(client, - ADM1021_REG_REM_OFFSET_PREC, - prec); - results[2]=results[2]/1000; - data->remote_temp_offset_prec=prec; - data->remote_temp_offset=results[2]; - adm1021_write_value(client, - ADM1021_REG_REM_OFFSET, - data->remote_temp_offset); + prec = ((results[2]-((results[2]/1000)*1000))/125)<<5; + adm1021_write_value(client, ADM1021_REG_REM_OFFSET_PREC, prec); + results[2]=results[2]/1000; + data->remote_temp_offset_prec=prec; + data->remote_temp_offset=results[2]; + adm1021_write_value(client, ADM1021_REG_REM_OFFSET, data->remote_temp_offset); } } } } +__attribute__((unused)) static void adm1021_die_code(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results) { - struct adm1021_data *data = client->data; + struct adm1021_data *data = i2c_get_clientdata(client); if (operation == SENSORS_PROC_REAL_INFO) *nrels_mag = 0; @@ -548,10 +522,11 @@ } } +__attribute__((unused)) static void adm1021_alarms(struct i2c_client *client, int operation, int ctl_name, int *nrels_mag, long *results) { - struct adm1021_data *data = client->data; + struct adm1021_data *data = i2c_get_clientdata(client); if (operation == SENSORS_PROC_REAL_INFO) *nrels_mag = 0; else if (operation == SENSORS_PROC_REAL_READ) { @@ -573,8 +548,8 @@ i2c_del_driver(&adm1021_driver); } -MODULE_AUTHOR - ("Frodo Looijaard and Philip Edelbrock "); +MODULE_AUTHOR ("Frodo Looijaard and " + "Philip Edelbrock "); MODULE_DESCRIPTION("adm1021 driver"); MODULE_LICENSE("GPL"); diff -Nru a/drivers/i2c/chips/lm75.c b/drivers/i2c/chips/lm75.c --- a/drivers/i2c/chips/lm75.c Wed Apr 2 22:24:04 2003 +++ b/drivers/i2c/chips/lm75.c Wed Apr 2 22:24:04 2003 @@ -18,14 +18,14 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* #define DEBUG 1 */ + #include #include #include #include -#include - +#include -#define LM75_SYSCTL_TEMP 1200 /* Degrees Celsius * 10 */ /* Addresses to scan */ static unsigned short normal_i2c[] = { SENSORS_I2C_END }; @@ -39,97 +39,113 @@ /* Many LM75 constants specified below */ /* The LM75 registers */ -#define LM75_REG_TEMP 0x00 -#define LM75_REG_CONF 0x01 -#define LM75_REG_TEMP_HYST 0x02 -#define LM75_REG_TEMP_OS 0x03 +#define LM75_REG_TEMP 0x00 +#define LM75_REG_CONF 0x01 +#define LM75_REG_TEMP_HYST 0x02 +#define LM75_REG_TEMP_OS 0x03 /* Conversions. Rounding and limit checking is only done on the TO_REG variants. Note that you should be a bit careful with which arguments these macros are called: arguments may be evaluated more than once. Fixing this is just not worth it. */ -#define TEMP_FROM_REG(val) ((((val & 0x7fff) >> 7) * 5) | ((val & 0x8000)?-256:0)) -#define TEMP_TO_REG(val) (SENSORS_LIMIT((val<0?(0x200+((val)/5))<<7:(((val) + 2) / 5) << 7),0,0xffff)) +#define TEMP_FROM_REG(val) ((((val & 0x7fff) >> 7) * 5) | ((val & 0x8000)?-256:0)) +#define TEMP_TO_REG(val) (SENSORS_LIMIT((val<0?(0x200+((val)/5))<<7:(((val) + 2) / 5) << 7),0,0xffff)) /* Initial values */ -#define LM75_INIT_TEMP_OS 600 -#define LM75_INIT_TEMP_HYST 500 +#define LM75_INIT_TEMP_OS 600 +#define LM75_INIT_TEMP_HYST 500 /* Each client has this additional data */ struct lm75_data { - int sysctl_id; - - struct semaphore update_lock; - char valid; /* !=0 if following fields are valid */ - unsigned long last_updated; /* In jiffies */ - - u16 temp, temp_os, temp_hyst; /* Register values */ + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + u16 temp_input; /* Register values */ + u16 temp_max; + u16 temp_hyst; }; static int lm75_attach_adapter(struct i2c_adapter *adapter); -static int lm75_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind); +static int lm75_detect(struct i2c_adapter *adapter, int address, int kind); static void lm75_init_client(struct i2c_client *client); static int lm75_detach_client(struct i2c_client *client); -static u16 swap_bytes(u16 val); static int lm75_read_value(struct i2c_client *client, u8 reg); static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value); -static void lm75_temp(struct i2c_client *client, int operation, - int ctl_name, int *nrels_mag, long *results); static void lm75_update_client(struct i2c_client *client); /* This is the driver that will be inserted */ static struct i2c_driver lm75_driver = { .owner = THIS_MODULE, - .name = "LM75 sensor chip driver", + .name = "lm75", .id = I2C_DRIVERID_LM75, .flags = I2C_DF_NOTIFY, .attach_adapter = lm75_attach_adapter, .detach_client = lm75_detach_client, }; -/* These files are created for each detected LM75. This is just a template; - though at first sight, you might think we could use a statically - allocated list, we need some way to get back to the parent - which - is done through one of the 'extra' fields which are initialized - when a new copy is allocated. */ -static ctl_table lm75_dir_table_template[] = { - {LM75_SYSCTL_TEMP, "temp", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real, NULL, &lm75_temp}, - {0} -}; - static int lm75_id = 0; +#define show(value) \ +static ssize_t show_##value(struct device *dev, char *buf) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct lm75_data *data = i2c_get_clientdata(client); \ + int temp; \ + \ + lm75_update_client(client); \ + temp = TEMP_FROM_REG(data->value); \ + return sprintf(buf, "%d\n", temp * 100); \ +} +show(temp_max); +show(temp_hyst); +show(temp_input); + +#define set(value, reg) \ +static ssize_t set_##value(struct device *dev, const char *buf, size_t count) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct lm75_data *data = i2c_get_clientdata(client); \ + int temp = simple_strtoul(buf, NULL, 10) / 100; \ + \ + data->value = TEMP_TO_REG(temp); \ + lm75_write_value(client, reg, data->value); \ + return count; \ +} +set(temp_max, LM75_REG_TEMP_OS); +set(temp_hyst, LM75_REG_TEMP_HYST); + +static DEVICE_ATTR(temp_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max); +static DEVICE_ATTR(temp_min, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst); +static DEVICE_ATTR(temp_input, S_IRUGO, show_temp_input, NULL); + static int lm75_attach_adapter(struct i2c_adapter *adapter) { return i2c_detect(adapter, &addr_data, lm75_detect); } /* This function is called by i2c_detect */ -static int lm75_detect(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) +static int lm75_detect(struct i2c_adapter *adapter, int address, int kind) { int i, cur, conf, hyst, os; struct i2c_client *new_client; struct lm75_data *data; int err = 0; - const char *type_name, *client_name; + const char *name; /* Make sure we aren't probing the ISA bus!! This is just a safety check at this moment; i2c_detect really won't call us. */ #ifdef DEBUG if (i2c_is_isa_adapter(adapter)) { - printk - ("lm75.o: lm75_detect called for an ISA bus adapter?!?\n"); - return 0; + dev_dbg(&adapter->dev, + "lm75_detect called for an ISA bus adapter?!?\n"); + goto exit; } #endif if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA)) - goto error0; + goto exit; /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. @@ -138,12 +154,14 @@ sizeof(struct lm75_data), GFP_KERNEL))) { err = -ENOMEM; - goto error0; + goto exit; } + memset(new_client, 0x00, sizeof(struct i2c_client) + + sizeof(struct lm75_data)); data = (struct lm75_data *) (new_client + 1); + i2c_set_clientdata(new_client, data); new_client->addr = address; - new_client->data = data; new_client->adapter = adapter; new_client->driver = &lm75_driver; new_client->flags = 0; @@ -155,16 +173,10 @@ hyst = i2c_smbus_read_word_data(new_client, 2); os = i2c_smbus_read_word_data(new_client, 3); for (i = 0; i <= 0x1f; i++) - if ( - (i2c_smbus_read_byte_data - (new_client, i * 8 + 1) != conf) - || - (i2c_smbus_read_word_data - (new_client, i * 8 + 2) != hyst) - || - (i2c_smbus_read_word_data - (new_client, i * 8 + 3) != os)) - goto error1; + if ((i2c_smbus_read_byte_data(new_client, i * 8 + 1) != conf) || + (i2c_smbus_read_word_data(new_client, i * 8 + 2) != hyst) || + (i2c_smbus_read_word_data(new_client, i * 8 + 3) != os)) + goto exit_free; } /* Determine the chip type - only one kind supported! */ @@ -172,15 +184,15 @@ kind = lm75; if (kind == lm75) { - type_name = "lm75"; - client_name = "LM75 chip"; + name = "lm75"; } else { - pr_debug("lm75.o: Internal error: unknown kind (%d)?!?", kind); - goto error1; + dev_dbg(&adapter->dev, "Internal error: unknown kind (%d)?!?", + kind); + goto exit_free; } /* Fill in the remaining client fields and put it into the global list */ - strcpy(new_client->name, client_name); + strncpy(new_client->dev.name, name, DEVICE_NAME_SIZE); new_client->id = lm75_id++; data->valid = 0; @@ -188,36 +200,23 @@ /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(new_client))) - goto error3; + goto exit_free; - /* Register a new directory entry with module sensors */ - i = i2c_register_entry(new_client, type_name, lm75_dir_table_template); - if (i < 0) { - err = i; - goto error4; - } - data->sysctl_id = i; + device_create_file(&new_client->dev, &dev_attr_temp_max); + device_create_file(&new_client->dev, &dev_attr_temp_min); + device_create_file(&new_client->dev, &dev_attr_temp_input); lm75_init_client(new_client); return 0; -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - error4: - i2c_detach_client(new_client); - error3: - error1: +exit_free: kfree(new_client); - error0: +exit: return err; } static int lm75_detach_client(struct i2c_client *client) { - struct lm75_data *data = client->data; - - i2c_deregister_entry(data->sysctl_id); i2c_detach_client(client); kfree(client); return 0; @@ -263,50 +262,22 @@ static void lm75_update_client(struct i2c_client *client) { - struct lm75_data *data = client->data; + struct lm75_data *data = i2c_get_clientdata(client); down(&data->update_lock); if ((jiffies - data->last_updated > HZ + HZ / 2) || (jiffies < data->last_updated) || !data->valid) { - pr_debug("Starting lm75 update\n"); + dev_dbg(&client->dev, "Starting lm75 update\n"); - data->temp = lm75_read_value(client, LM75_REG_TEMP); - data->temp_os = lm75_read_value(client, LM75_REG_TEMP_OS); - data->temp_hyst = - lm75_read_value(client, LM75_REG_TEMP_HYST); + data->temp_input = lm75_read_value(client, LM75_REG_TEMP); + data->temp_max = lm75_read_value(client, LM75_REG_TEMP_OS); + data->temp_hyst = lm75_read_value(client, LM75_REG_TEMP_HYST); data->last_updated = jiffies; data->valid = 1; } up(&data->update_lock); -} - - -static void lm75_temp(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) -{ - struct lm75_data *data = client->data; - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 1; - else if (operation == SENSORS_PROC_REAL_READ) { - lm75_update_client(client); - results[0] = TEMP_FROM_REG(data->temp_os); - results[1] = TEMP_FROM_REG(data->temp_hyst); - results[2] = TEMP_FROM_REG(data->temp); - *nrels_mag = 3; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - data->temp_os = TEMP_TO_REG(results[0]); - lm75_write_value(client, LM75_REG_TEMP_OS, - data->temp_os); - } - if (*nrels_mag >= 2) { - data->temp_hyst = TEMP_TO_REG(results[1]); - lm75_write_value(client, LM75_REG_TEMP_HYST, - data->temp_hyst); - } - } } static int __init sensors_lm75_init(void) diff -Nru a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/i2c/chips/via686a.c Wed Apr 2 22:24:08 2003 @@ -0,0 +1,930 @@ +/* + via686a.c - Part of lm_sensors, Linux kernel modules + for hardware monitoring + + Copyright (c) 1998 - 2002 Frodo Looijaard , + Kyösti Mälkki , + Mark Studebaker , + and Bob Dougherty + (Some conversion-factor data were contributed by Jonathan Teh Soon Yew + and Alex van Kaam .) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + Supports the Via VT82C686A, VT82C686B south bridges. + Reports all as a 686A. + See doc/chips/via686a for details. + Warning - only supports a single device. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* If force_addr is set to anything different from 0, we forcibly enable + the device at the given address. */ +static int force_addr = 0; +MODULE_PARM(force_addr, "i"); +MODULE_PARM_DESC(force_addr, + "Initialize the base address of the sensors"); + +/* Addresses to scan. + Note that we can't determine the ISA address until we have initialized + our module */ +static unsigned short normal_i2c[] = { SENSORS_I2C_END }; +static unsigned short normal_i2c_range[] = { SENSORS_I2C_END }; +static unsigned int normal_isa[] = { 0x0000, SENSORS_ISA_END }; +static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_1(via686a); + +/* + The Via 686a southbridge has a LM78-like chip integrated on the same IC. + This driver is a customized copy of lm78.c +*/ + +/* Many VIA686A constants specified below */ + +/* Length of ISA address segment */ +#define VIA686A_EXTENT 0x80 +#define VIA686A_BASE_REG 0x70 +#define VIA686A_ENABLE_REG 0x74 + +/* The VIA686A registers */ +/* ins numbered 0-4 */ +#define VIA686A_REG_IN_MAX(nr) (0x2b + ((nr) * 2)) +#define VIA686A_REG_IN_MIN(nr) (0x2c + ((nr) * 2)) +#define VIA686A_REG_IN(nr) (0x22 + (nr)) + +/* fans numbered 1-2 */ +#define VIA686A_REG_FAN_MIN(nr) (0x3a + (nr)) +#define VIA686A_REG_FAN(nr) (0x28 + (nr)) + +/* the following values are as speced by VIA: */ +static const u8 regtemp[] = { 0x20, 0x21, 0x1f }; +static const u8 regover[] = { 0x39, 0x3d, 0x1d }; +static const u8 reghyst[] = { 0x3a, 0x3e, 0x1e }; + +/* temps numbered 1-3 */ +#define VIA686A_REG_TEMP(nr) (regtemp[(nr) - 1]) +#define VIA686A_REG_TEMP_OVER(nr) (regover[(nr) - 1]) +#define VIA686A_REG_TEMP_HYST(nr) (reghyst[(nr) - 1]) +#define VIA686A_REG_TEMP_LOW1 0x4b // bits 7-6 +#define VIA686A_REG_TEMP_LOW23 0x49 // 2 = bits 5-4, 3 = bits 7-6 + +#define VIA686A_REG_ALARM1 0x41 +#define VIA686A_REG_ALARM2 0x42 +#define VIA686A_REG_FANDIV 0x47 +#define VIA686A_REG_CONFIG 0x40 +/* The following register sets temp interrupt mode (bits 1-0 for temp1, + 3-2 for temp2, 5-4 for temp3). Modes are: + 00 interrupt stays as long as value is out-of-range + 01 interrupt is cleared once register is read (default) + 10 comparator mode- like 00, but ignores hysteresis + 11 same as 00 */ +#define VIA686A_REG_TEMP_MODE 0x4b +/* We'll just assume that you want to set all 3 simultaneously: */ +#define VIA686A_TEMP_MODE_MASK 0x3F +#define VIA686A_TEMP_MODE_CONTINUOUS (0x00) + +/* Conversions. Rounding and limit checking is only done on the TO_REG + variants. + +********* VOLTAGE CONVERSIONS (Bob Dougherty) ******** + From HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew): + voltagefactor[0]=1.25/2628; (2628/1.25=2102.4) // Vccp + voltagefactor[1]=1.25/2628; (2628/1.25=2102.4) // +2.5V + voltagefactor[2]=1.67/2628; (2628/1.67=1573.7) // +3.3V + voltagefactor[3]=2.6/2628; (2628/2.60=1010.8) // +5V + voltagefactor[4]=6.3/2628; (2628/6.30=417.14) // +12V + in[i]=(data[i+2]*25.0+133)*voltagefactor[i]; + That is: + volts = (25*regVal+133)*factor + regVal = (volts/factor-133)/25 + (These conversions were contributed by Jonathan Teh Soon Yew + ) + + These get us close, but they don't completely agree with what my BIOS + says- they are all a bit low. But, it all we have to go on... */ +static inline u8 IN_TO_REG(long val, int inNum) +{ + /* to avoid floating point, we multiply everything by 100. + val is guaranteed to be positive, so we can achieve the effect of + rounding by (...*10+5)/10. Note that the *10 is hidden in the + /250 (which should really be /2500). + At the end, we need to /100 because we *100 everything and we need + to /10 because of the rounding thing, so we /1000. */ + if (inNum <= 1) + return (u8) + SENSORS_LIMIT(((val * 210240 - 13300) / 250 + 5) / 1000, + 0, 255); + else if (inNum == 2) + return (u8) + SENSORS_LIMIT(((val * 157370 - 13300) / 250 + 5) / 1000, + 0, 255); + else if (inNum == 3) + return (u8) + SENSORS_LIMIT(((val * 101080 - 13300) / 250 + 5) / 1000, + 0, 255); + else + return (u8) SENSORS_LIMIT(((val * 41714 - 13300) / 250 + 5) + / 1000, 0, 255); +} + +static inline long IN_FROM_REG(u8 val, int inNum) +{ + /* to avoid floating point, we multiply everything by 100. + val is guaranteed to be positive, so we can achieve the effect of + rounding by adding 0.5. Or, to avoid fp math, we do (...*10+5)/10. + We need to scale with *100 anyway, so no need to /100 at the end. */ + if (inNum <= 1) + return (long) (((250000 * val + 13300) / 210240 * 10 + 5) /10); + else if (inNum == 2) + return (long) (((250000 * val + 13300) / 157370 * 10 + 5) /10); + else if (inNum == 3) + return (long) (((250000 * val + 13300) / 101080 * 10 + 5) /10); + else + return (long) (((250000 * val + 13300) / 41714 * 10 + 5) /10); +} + +/********* FAN RPM CONVERSIONS ********/ +/* Higher register values = slower fans (the fan's strobe gates a counter). + But this chip saturates back at 0, not at 255 like all the other chips. + So, 0 means 0 RPM */ +static inline u8 FAN_TO_REG(long rpm, int div) +{ + if (rpm == 0) + return 0; + rpm = SENSORS_LIMIT(rpm, 1, 1000000); + return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 255); +} + +#define FAN_FROM_REG(val,div) ((val)==0?0:(val)==255?0:1350000/((val)*(div))) + +/******** TEMP CONVERSIONS (Bob Dougherty) *********/ +/* linear fits from HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew) + if(temp<169) + return double(temp)*0.427-32.08; + else if(temp>=169 && temp<=202) + return double(temp)*0.582-58.16; + else + return double(temp)*0.924-127.33; + + A fifth-order polynomial fits the unofficial data (provided by Alex van + Kaam ) a bit better. It also give more reasonable + numbers on my machine (ie. they agree with what my BIOS tells me). + Here's the fifth-order fit to the 8-bit data: + temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 - + 2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0. + + (2000-10-25- RFD: thanks to Uwe Andersen for + finding my typos in this formula!) + + Alas, none of the elegant function-fit solutions will work because we + aren't allowed to use floating point in the kernel and doing it with + integers doesn't rpovide enough precision. So we'll do boring old + look-up table stuff. The unofficial data (see below) have effectively + 7-bit resolution (they are rounded to the nearest degree). I'm assuming + that the transfer function of the device is monotonic and smooth, so a + smooth function fit to the data will allow us to get better precision. + I used the 5th-order poly fit described above and solved for + VIA register values 0-255. I *10 before rounding, so we get tenth-degree + precision. (I could have done all 1024 values for our 10-bit readings, + but the function is very linear in the useful range (0-80 deg C), so + we'll just use linear interpolation for 10-bit readings.) So, tempLUT + is the temp at via register values 0-255: */ +static const long tempLUT[] = + { -709, -688, -667, -646, -627, -607, -589, -570, -553, -536, -519, + -503, -487, -471, -456, -442, -428, -414, -400, -387, -375, + -362, -350, -339, -327, -316, -305, -295, -285, -275, -265, + -255, -246, -237, -229, -220, -212, -204, -196, -188, -180, + -173, -166, -159, -152, -145, -139, -132, -126, -120, -114, + -108, -102, -96, -91, -85, -80, -74, -69, -64, -59, -54, -49, + -44, -39, -34, -29, -25, -20, -15, -11, -6, -2, 3, 7, 12, 16, + 20, 25, 29, 33, 37, 42, 46, 50, 54, 59, 63, 67, 71, 75, 79, 84, + 88, 92, 96, 100, 104, 109, 113, 117, 121, 125, 130, 134, 138, + 142, 146, 151, 155, 159, 163, 168, 172, 176, 181, 185, 189, + 193, 198, 202, 206, 211, 215, 219, 224, 228, 232, 237, 241, + 245, 250, 254, 259, 263, 267, 272, 276, 281, 285, 290, 294, + 299, 303, 307, 312, 316, 321, 325, 330, 334, 339, 344, 348, + 353, 357, 362, 366, 371, 376, 380, 385, 390, 395, 399, 404, + 409, 414, 419, 423, 428, 433, 438, 443, 449, 454, 459, 464, + 469, 475, 480, 486, 491, 497, 502, 508, 514, 520, 526, 532, + 538, 544, 551, 557, 564, 571, 578, 584, 592, 599, 606, 614, + 621, 629, 637, 645, 654, 662, 671, 680, 689, 698, 708, 718, + 728, 738, 749, 759, 770, 782, 793, 805, 818, 830, 843, 856, + 870, 883, 898, 912, 927, 943, 958, 975, 991, 1008, 1026, 1044, + 1062, 1081, 1101, 1121, 1141, 1162, 1184, 1206, 1229, 1252, + 1276, 1301, 1326, 1352, 1378, 1406, 1434, 1462 +}; + +/* the original LUT values from Alex van Kaam + (for via register values 12-240): +{-50,-49,-47,-45,-43,-41,-39,-38,-37,-35,-34,-33,-32,-31, +-30,-29,-28,-27,-26,-25,-24,-24,-23,-22,-21,-20,-20,-19,-18,-17,-17,-16,-15, +-15,-14,-14,-13,-12,-12,-11,-11,-10,-9,-9,-8,-8,-7,-7,-6,-6,-5,-5,-4,-4,-3, +-3,-2,-2,-1,-1,0,0,1,1,1,3,3,3,4,4,4,5,5,5,6,6,7,7,8,8,9,9,9,10,10,11,11,12, +12,12,13,13,13,14,14,15,15,16,16,16,17,17,18,18,19,19,20,20,21,21,21,22,22, +22,23,23,24,24,25,25,26,26,26,27,27,27,28,28,29,29,30,30,30,31,31,32,32,33, +33,34,34,35,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,42,43,43,44,44,45, +45,46,46,47,48,48,49,49,50,51,51,52,52,53,53,54,55,55,56,57,57,58,59,59,60, +61,62,62,63,64,65,66,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,83,84, +85,86,88,89,91,92,94,96,97,99,101,103,105,107,109,110}; + + + Here's the reverse LUT. I got it by doing a 6-th order poly fit (needed + an extra term for a good fit to these inverse data!) and then + solving for each temp value from -50 to 110 (the useable range for + this chip). Here's the fit: + viaRegVal = -1.160370e-10*val^6 +3.193693e-08*val^5 - 1.464447e-06*val^4 + - 2.525453e-04*val^3 + 1.424593e-02*val^2 + 2.148941e+00*val +7.275808e+01) + Note that n=161: */ +static const u8 viaLUT[] = + { 12, 12, 13, 14, 14, 15, 16, 16, 17, 18, 18, 19, 20, 20, 21, 22, 23, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 39, 40, + 41, 43, 45, 46, 48, 49, 51, 53, 55, 57, 59, 60, 62, 64, 66, + 69, 71, 73, 75, 77, 79, 82, 84, 86, 88, 91, 93, 95, 98, 100, + 103, 105, 107, 110, 112, 115, 117, 119, 122, 124, 126, 129, + 131, 134, 136, 138, 140, 143, 145, 147, 150, 152, 154, 156, + 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, + 182, 183, 185, 187, 188, 190, 192, 193, 195, 196, 198, 199, + 200, 202, 203, 205, 206, 207, 208, 209, 210, 211, 212, 213, + 214, 215, 216, 217, 218, 219, 220, 221, 222, 222, 223, 224, + 225, 226, 226, 227, 228, 228, 229, 230, 230, 231, 232, 232, + 233, 233, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, + 239, 240 +}; + +/* Converting temps to (8-bit) hyst and over registers + No interpolation here. Just check the limits and go. + The +5 effectively rounds off properly and the +50 is because + the temps start at -50 */ +static inline u8 TEMP_TO_REG(long val) +{ + return (u8) + SENSORS_LIMIT(viaLUT[((val <= -500) ? 0 : (val >= 1100) ? 160 : + ((val + 5) / 10 + 50))], 0, 255); +} + +/* for 8-bit temperature hyst and over registers + The temp values are already *10, so we don't need to do that. + But we _will_ round these off to the nearest degree with (...*10+5)/10 */ +#define TEMP_FROM_REG(val) ((tempLUT[(val)]*10+5)/10) + +/* for 10-bit temperature readings + You might _think_ this is too long to inline, but's it's really only + called once... */ +static inline long TEMP_FROM_REG10(u16 val) +{ + /* the temp values are already *10, so we don't need to do that. */ + long temp; + u16 eightBits = val >> 2; + u16 twoBits = val & 3; + + /* handle the extremes first (they won't interpolate well! ;-) */ + if (val == 0) + return (long) tempLUT[0]; + if (val == 1023) + return (long) tempLUT[255]; + + if (twoBits == 0) + return (long) tempLUT[eightBits]; + else { + /* do some interpolation by multipying the lower and upper + bounds by 25, 50 or 75, then /100. */ + temp = ((25 * (4 - twoBits)) * tempLUT[eightBits] + + (25 * twoBits) * tempLUT[eightBits + 1]); + /* increase the magnitude by 50 to achieve rounding. */ + if (temp > 0) + temp += 50; + else + temp -= 50; + return (temp / 100); + } +} + +#define ALARMS_FROM_REG(val) (val) + +#define DIV_FROM_REG(val) (1 << (val)) +#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1) + +/* Initial limits */ +#define VIA686A_INIT_IN_0 200 +#define VIA686A_INIT_IN_1 250 +#define VIA686A_INIT_IN_2 330 +#define VIA686A_INIT_IN_3 500 +#define VIA686A_INIT_IN_4 1200 + +#define VIA686A_INIT_IN_PERCENTAGE 10 + +#define VIA686A_INIT_IN_MIN_0 (VIA686A_INIT_IN_0 - VIA686A_INIT_IN_0 \ + * VIA686A_INIT_IN_PERCENTAGE / 100) +#define VIA686A_INIT_IN_MAX_0 (VIA686A_INIT_IN_0 + VIA686A_INIT_IN_0 \ + * VIA686A_INIT_IN_PERCENTAGE / 100) +#define VIA686A_INIT_IN_MIN_1 (VIA686A_INIT_IN_1 - VIA686A_INIT_IN_1 \ + * VIA686A_INIT_IN_PERCENTAGE / 100) +#define VIA686A_INIT_IN_MAX_1 (VIA686A_INIT_IN_1 + VIA686A_INIT_IN_1 \ + * VIA686A_INIT_IN_PERCENTAGE / 100) +#define VIA686A_INIT_IN_MIN_2 (VIA686A_INIT_IN_2 - VIA686A_INIT_IN_2 \ + * VIA686A_INIT_IN_PERCENTAGE / 100) +#define VIA686A_INIT_IN_MAX_2 (VIA686A_INIT_IN_2 + VIA686A_INIT_IN_2 \ + * VIA686A_INIT_IN_PERCENTAGE / 100) +#define VIA686A_INIT_IN_MIN_3 (VIA686A_INIT_IN_3 - VIA686A_INIT_IN_3 \ + * VIA686A_INIT_IN_PERCENTAGE / 100) +#define VIA686A_INIT_IN_MAX_3 (VIA686A_INIT_IN_3 + VIA686A_INIT_IN_3 \ + * VIA686A_INIT_IN_PERCENTAGE / 100) +#define VIA686A_INIT_IN_MIN_4 (VIA686A_INIT_IN_4 - VIA686A_INIT_IN_4 \ + * VIA686A_INIT_IN_PERCENTAGE / 100) +#define VIA686A_INIT_IN_MAX_4 (VIA686A_INIT_IN_4 + VIA686A_INIT_IN_4 \ + * VIA686A_INIT_IN_PERCENTAGE / 100) + +#define VIA686A_INIT_FAN_MIN 3000 + +#define VIA686A_INIT_TEMP_OVER 600 +#define VIA686A_INIT_TEMP_HYST 500 + +/* For the VIA686A, we need to keep some data in memory. That + data is pointed to by via686a_list[NR]->data. The structure itself is + dynamically allocated, at the same time when a new via686a client is + allocated. */ +struct via686a_data { + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + u8 in[5]; /* Register value */ + u8 in_max[5]; /* Register value */ + u8 in_min[5]; /* Register value */ + u8 fan[2]; /* Register value */ + u8 fan_min[2]; /* Register value */ + u16 temp[3]; /* Register value 10 bit */ + u8 temp_over[3]; /* Register value */ + u8 temp_hyst[3]; /* Register value */ + u8 fan_div[2]; /* Register encoding, shifted right */ + u16 alarms; /* Register encoding, combined */ +}; + +static struct pci_dev *s_bridge; /* pointer to the (only) via686a */ + +static int via686a_attach_adapter(struct i2c_adapter *adapter); +static int via686a_detect(struct i2c_adapter *adapter, int address, int kind); +static int via686a_detach_client(struct i2c_client *client); + +static int via686a_read_value(struct i2c_client *client, u8 register); +static void via686a_write_value(struct i2c_client *client, u8 register, + u8 value); +static void via686a_update_client(struct i2c_client *client); +static void via686a_init_client(struct i2c_client *client); + +static int via686a_id = 0; + +/* The driver. I choose to use type i2c_driver, as at is identical to both + smbus_driver and isa_driver, and clients could be of either kind */ +static struct i2c_driver via686a_driver = { + .owner = THIS_MODULE, + .name = "VIA686A", + .id = I2C_DRIVERID_VIA686A, + .flags = I2C_DF_NOTIFY, + .attach_adapter = via686a_attach_adapter, + .detach_client = via686a_detach_client, +}; + + + +/* The /proc/sys entries */ + +/* -- SENSORS SYSCTL START -- */ +#define VIA686A_SYSCTL_IN0 1000 +#define VIA686A_SYSCTL_IN1 1001 +#define VIA686A_SYSCTL_IN2 1002 +#define VIA686A_SYSCTL_IN3 1003 +#define VIA686A_SYSCTL_IN4 1004 +#define VIA686A_SYSCTL_FAN1 1101 +#define VIA686A_SYSCTL_FAN2 1102 +#define VIA686A_SYSCTL_TEMP 1200 +#define VIA686A_SYSCTL_TEMP2 1201 +#define VIA686A_SYSCTL_TEMP3 1202 +#define VIA686A_SYSCTL_FAN_DIV 2000 +#define VIA686A_SYSCTL_ALARMS 2001 + +#define VIA686A_ALARM_IN0 0x01 +#define VIA686A_ALARM_IN1 0x02 +#define VIA686A_ALARM_IN2 0x04 +#define VIA686A_ALARM_IN3 0x08 +#define VIA686A_ALARM_TEMP 0x10 +#define VIA686A_ALARM_FAN1 0x40 +#define VIA686A_ALARM_FAN2 0x80 +#define VIA686A_ALARM_IN4 0x100 +#define VIA686A_ALARM_TEMP2 0x800 +#define VIA686A_ALARM_CHAS 0x1000 +#define VIA686A_ALARM_TEMP3 0x8000 + +/* -- SENSORS SYSCTL END -- */ + +#if 0 +/* These files are created for each detected VIA686A. This is just a template; + though at first sight, you might think we could use a statically + allocated list, we need some way to get back to the parent - which + is done through one of the 'extra' fields which are initialized + when a new copy is allocated. */ +static ctl_table via686a_dir_table_template[] = { + {VIA686A_SYSCTL_IN0, "in0", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &via686a_in}, + {VIA686A_SYSCTL_IN1, "in1", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &via686a_in}, + {VIA686A_SYSCTL_IN2, "in2", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &via686a_in}, + {VIA686A_SYSCTL_IN3, "in3", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &via686a_in}, + {VIA686A_SYSCTL_IN4, "in4", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &via686a_in}, + {VIA686A_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &via686a_fan}, + {VIA686A_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &via686a_fan}, + {VIA686A_SYSCTL_TEMP, "temp1", NULL, 0, 0644, NULL, &i2c_proc_real, + &i2c_sysctl_real, NULL, &via686a_temp}, + {VIA686A_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &via686a_temp}, + {VIA686A_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &via686a_temp}, + {VIA686A_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &via686a_fan_div}, + {VIA686A_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, + &i2c_proc_real, &i2c_sysctl_real, NULL, &via686a_alarms}, + {0} +}; +#endif + +static inline int via686a_read_value(struct i2c_client *client, u8 reg) +{ + return (inb_p(client->addr + reg)); +} + +static inline void via686a_write_value(struct i2c_client *client, u8 reg, + u8 value) +{ + outb_p(value, client->addr + reg); +} + +/* This is called when the module is loaded */ +static int via686a_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, via686a_detect); +} + +static int via686a_detect(struct i2c_adapter *adapter, int address, int kind) +{ + struct i2c_client *new_client; + struct via686a_data *data; + int err = 0; + const char *name = "via686a"; + u16 val; + + /* Make sure we are probing the ISA bus!! */ + if (!i2c_is_isa_adapter(adapter)) { + dev_err(&adapter->dev, + "via686a_detect called for an I2C bus adapter?!?\n"); + return 0; + } + + /* 8231 requires multiple of 256, we enforce that on 686 as well */ + if(force_addr) + address = force_addr & 0xFF00; + + if(force_addr) { + dev_warn(&adapter->dev,"forcing ISA address 0x%04X\n", address); + if (PCIBIOS_SUCCESSFUL != + pci_write_config_word(s_bridge, VIA686A_BASE_REG, address)) + return -ENODEV; + } + if (PCIBIOS_SUCCESSFUL != + pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val)) + return -ENODEV; + if (!(val & 0x0001)) { + dev_warn(&adapter->dev,"enabling sensors\n"); + if (PCIBIOS_SUCCESSFUL != + pci_write_config_word(s_bridge, VIA686A_ENABLE_REG, + val | 0x0001)) + return -ENODEV; + } + + /* Reserve the ISA region */ + if (!request_region(address, VIA686A_EXTENT, "via686a-sensor")) { + dev_err(&adapter->dev,"region 0x%x already in use!\n", + address); + return -ENODEV; + } + + if (!(new_client = kmalloc(sizeof(struct i2c_client) + + sizeof(struct via686a_data), + GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR0; + } + + memset(new_client,0x00, sizeof(struct i2c_client) + + sizeof(struct via686a_data)); + data = (struct via686a_data *) (new_client + 1); + i2c_set_clientdata(new_client, data); + new_client->addr = address; + new_client->adapter = adapter; + new_client->driver = &via686a_driver; + new_client->flags = 0; + + /* Fill in the remaining client fields and put into the global list */ + snprintf(new_client->dev.name, DEVICE_NAME_SIZE, name); + + new_client->id = via686a_id++; + data->valid = 0; + init_MUTEX(&data->update_lock); + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto ERROR3; + + /* Initialize the VIA686A chip */ + via686a_init_client(new_client); + return 0; + + ERROR3: + release_region(address, VIA686A_EXTENT); + kfree(new_client); + ERROR0: + return err; +} + +static int via686a_detach_client(struct i2c_client *client) +{ + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, + "Client deregistration failed, client not detached.\n"); + return err; + } + + release_region(client->addr, VIA686A_EXTENT); + kfree(client); + + return 0; +} + +/* Called when we have found a new VIA686A. Set limits, etc. */ +static void via686a_init_client(struct i2c_client *client) +{ + int i; + + /* Reset the device */ + via686a_write_value(client, VIA686A_REG_CONFIG, 0x80); + + /* Have to wait for reset to complete or else the following + initializations won't work reliably. The delay was arrived at + empirically, the datasheet doesn't tell you. + Waiting for the reset bit to clear doesn't work, it + clears in about 2-4 udelays and that isn't nearly enough. */ + udelay(50); + + via686a_write_value(client, VIA686A_REG_IN_MIN(0), + IN_TO_REG(VIA686A_INIT_IN_MIN_0, 0)); + via686a_write_value(client, VIA686A_REG_IN_MAX(0), + IN_TO_REG(VIA686A_INIT_IN_MAX_0, 0)); + via686a_write_value(client, VIA686A_REG_IN_MIN(1), + IN_TO_REG(VIA686A_INIT_IN_MIN_1, 1)); + via686a_write_value(client, VIA686A_REG_IN_MAX(1), + IN_TO_REG(VIA686A_INIT_IN_MAX_1, 1)); + via686a_write_value(client, VIA686A_REG_IN_MIN(2), + IN_TO_REG(VIA686A_INIT_IN_MIN_2, 2)); + via686a_write_value(client, VIA686A_REG_IN_MAX(2), + IN_TO_REG(VIA686A_INIT_IN_MAX_2, 2)); + via686a_write_value(client, VIA686A_REG_IN_MIN(3), + IN_TO_REG(VIA686A_INIT_IN_MIN_3, 3)); + via686a_write_value(client, VIA686A_REG_IN_MAX(3), + IN_TO_REG(VIA686A_INIT_IN_MAX_3, 3)); + via686a_write_value(client, VIA686A_REG_IN_MIN(4), + IN_TO_REG(VIA686A_INIT_IN_MIN_4, 4)); + via686a_write_value(client, VIA686A_REG_IN_MAX(4), + IN_TO_REG(VIA686A_INIT_IN_MAX_4, 4)); + via686a_write_value(client, VIA686A_REG_FAN_MIN(1), + FAN_TO_REG(VIA686A_INIT_FAN_MIN, 2)); + via686a_write_value(client, VIA686A_REG_FAN_MIN(2), + FAN_TO_REG(VIA686A_INIT_FAN_MIN, 2)); + for (i = 1; i <= 3; i++) { + via686a_write_value(client, VIA686A_REG_TEMP_OVER(i), + TEMP_TO_REG(VIA686A_INIT_TEMP_OVER)); + via686a_write_value(client, VIA686A_REG_TEMP_HYST(i), + TEMP_TO_REG(VIA686A_INIT_TEMP_HYST)); + } + + /* Start monitoring */ + via686a_write_value(client, VIA686A_REG_CONFIG, 0x01); + + /* Cofigure temp interrupt mode for continuous-interrupt operation */ + via686a_write_value(client, VIA686A_REG_TEMP_MODE, + via686a_read_value(client, VIA686A_REG_TEMP_MODE) & + !(VIA686A_TEMP_MODE_MASK | VIA686A_TEMP_MODE_CONTINUOUS)); +} + +static void via686a_update_client(struct i2c_client *client) +{ + struct via686a_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if ((jiffies - data->last_updated > HZ + HZ / 2) || + (jiffies < data->last_updated) || !data->valid) { + + for (i = 0; i <= 4; i++) { + data->in[i] = + via686a_read_value(client, VIA686A_REG_IN(i)); + data->in_min[i] = via686a_read_value(client, + VIA686A_REG_IN_MIN + (i)); + data->in_max[i] = + via686a_read_value(client, VIA686A_REG_IN_MAX(i)); + } + for (i = 1; i <= 2; i++) { + data->fan[i - 1] = + via686a_read_value(client, VIA686A_REG_FAN(i)); + data->fan_min[i - 1] = via686a_read_value(client, + VIA686A_REG_FAN_MIN(i)); + } + for (i = 1; i <= 3; i++) { + data->temp[i - 1] = via686a_read_value(client, + VIA686A_REG_TEMP(i)) << 2; + data->temp_over[i - 1] = + via686a_read_value(client, + VIA686A_REG_TEMP_OVER(i)); + data->temp_hyst[i - 1] = + via686a_read_value(client, + VIA686A_REG_TEMP_HYST(i)); + } + /* add in lower 2 bits + temp1 uses bits 7-6 of VIA686A_REG_TEMP_LOW1 + temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23 + temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23 + */ + data->temp[0] |= (via686a_read_value(client, + VIA686A_REG_TEMP_LOW1) + & 0xc0) >> 6; + data->temp[1] |= + (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) & + 0x30) >> 4; + data->temp[2] |= + (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) & + 0xc0) >> 6; + + i = via686a_read_value(client, VIA686A_REG_FANDIV); + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = i >> 6; + data->alarms = + via686a_read_value(client, + VIA686A_REG_ALARM1) | + (via686a_read_value(client, VIA686A_REG_ALARM2) << 8); + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); +} + + +/* The next few functions are the call-back functions of the /proc/sys and + sysctl files. Which function is used is defined in the ctl_table in + the extra1 field. + Each function must return the magnitude (power of 10 to divide the date + with) if it is called with operation==SENSORS_PROC_REAL_INFO. It must + put a maximum of *nrels elements in results reflecting the data of this + file, and set *nrels to the number it actually put in it, if operation== + SENSORS_PROC_REAL_READ. Finally, it must get upto *nrels elements from + results and write them to the chip, if operations==SENSORS_PROC_REAL_WRITE. + Note that on SENSORS_PROC_REAL_READ, I do not check whether results is + large enough (by checking the incoming value of *nrels). This is not very + good practice, but as long as you put less than about 5 values in results, + you can assume it is large enough. */ +/* FIXME, remove these functions, they are here to verify the sysfs conversion + * is correct, or not */ +__attribute__((unused)) +static void via686a_in(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct via686a_data *data = i2c_get_clientdata(client); + int nr = ctl_name - VIA686A_SYSCTL_IN0; + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 2; + else if (operation == SENSORS_PROC_REAL_READ) { + via686a_update_client(client); + results[0] = IN_FROM_REG(data->in_min[nr], nr); + results[1] = IN_FROM_REG(data->in_max[nr], nr); + results[2] = IN_FROM_REG(data->in[nr], nr); + *nrels_mag = 3; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag >= 1) { + data->in_min[nr] = IN_TO_REG(results[0], nr); + via686a_write_value(client, VIA686A_REG_IN_MIN(nr), + data->in_min[nr]); + } + if (*nrels_mag >= 2) { + data->in_max[nr] = IN_TO_REG(results[1], nr); + via686a_write_value(client, VIA686A_REG_IN_MAX(nr), + data->in_max[nr]); + } + } +} + +__attribute__((unused)) +static void via686a_fan(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct via686a_data *data = i2c_get_clientdata(client); + int nr = ctl_name - VIA686A_SYSCTL_FAN1 + 1; + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + via686a_update_client(client); + results[0] = FAN_FROM_REG(data->fan_min[nr - 1], + DIV_FROM_REG(data->fan_div + [nr - 1])); + results[1] = FAN_FROM_REG(data->fan[nr - 1], + DIV_FROM_REG(data->fan_div[nr - 1])); + *nrels_mag = 2; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag >= 1) { + data->fan_min[nr - 1] = FAN_TO_REG(results[0], + DIV_FROM_REG(data-> + fan_div[nr -1])); + via686a_write_value(client, + VIA686A_REG_FAN_MIN(nr), + data->fan_min[nr - 1]); + } + } +} + +__attribute__((unused)) +static void via686a_temp(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct via686a_data *data = i2c_get_clientdata(client); + int nr = ctl_name - VIA686A_SYSCTL_TEMP; + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 1; + else if (operation == SENSORS_PROC_REAL_READ) { + via686a_update_client(client); + results[0] = TEMP_FROM_REG(data->temp_over[nr]); + results[1] = TEMP_FROM_REG(data->temp_hyst[nr]); + results[2] = TEMP_FROM_REG10(data->temp[nr]); + *nrels_mag = 3; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + if (*nrels_mag >= 1) { + data->temp_over[nr] = TEMP_TO_REG(results[0]); + via686a_write_value(client, + VIA686A_REG_TEMP_OVER(nr + 1), + data->temp_over[nr]); + } + if (*nrels_mag >= 2) { + data->temp_hyst[nr] = TEMP_TO_REG(results[1]); + via686a_write_value(client, + VIA686A_REG_TEMP_HYST(nr + 1), + data->temp_hyst[nr]); + } + } +} + +__attribute__((unused)) +static void via686a_alarms(struct i2c_client *client, int operation, int ctl_name, + int *nrels_mag, long *results) +{ + struct via686a_data *data = i2c_get_clientdata(client); + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + via686a_update_client(client); + results[0] = ALARMS_FROM_REG(data->alarms); + *nrels_mag = 1; + } +} + +__attribute__((unused)) +static void via686a_fan_div(struct i2c_client *client, int operation, + int ctl_name, int *nrels_mag, long *results) +{ + struct via686a_data *data = i2c_get_clientdata(client); + int old; + + if (operation == SENSORS_PROC_REAL_INFO) + *nrels_mag = 0; + else if (operation == SENSORS_PROC_REAL_READ) { + via686a_update_client(client); + results[0] = DIV_FROM_REG(data->fan_div[0]); + results[1] = DIV_FROM_REG(data->fan_div[1]); + *nrels_mag = 2; + } else if (operation == SENSORS_PROC_REAL_WRITE) { + old = via686a_read_value(client, VIA686A_REG_FANDIV); + if (*nrels_mag >= 2) { + data->fan_div[1] = DIV_TO_REG(results[1]); + old = (old & 0x3f) | (data->fan_div[1] << 6); + } + if (*nrels_mag >= 1) { + data->fan_div[0] = DIV_TO_REG(results[0]); + old = (old & 0xcf) | (data->fan_div[0] << 4); + via686a_write_value(client, VIA686A_REG_FANDIV, + old); + } + } +} + + +static struct pci_device_id via686a_pci_ids[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_VIA, + .device = PCI_DEVICE_ID_VIA_82C686_4, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .class = 0, + .class_mask = 0, + .driver_data = 0, + }, + { 0, } +}; + +static int __devinit via686a_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + u16 val; + int addr = 0; + + if (PCIBIOS_SUCCESSFUL != + pci_read_config_word(dev, VIA686A_BASE_REG, &val)) + return -ENODEV; + + addr = val & ~(VIA686A_EXTENT - 1); + if (addr == 0 && force_addr == 0) { + dev_err(&dev->dev,"base address not set - upgrade BIOS or use force_addr=0xaddr\n"); + return -ENODEV; + } + if (force_addr) + addr = force_addr; /* so detect will get called */ + + if (!addr) { + dev_err(&dev->dev,"No Via 686A sensors found.\n"); + return -ENODEV; + } + normal_isa[0] = addr; + s_bridge = dev; + return i2c_add_driver(&via686a_driver); +} + +static void __devexit via686a_pci_remove(struct pci_dev *dev) +{ + i2c_del_driver(&via686a_driver); +} + +static struct pci_driver via686a_pci_driver = { + .name = "via686a", + .id_table = via686a_pci_ids, + .probe = via686a_pci_probe, + .remove = __devexit_p(via686a_pci_remove), +}; + +static int __init sm_via686a_init(void) +{ + return pci_module_init(&via686a_pci_driver); +} + +static void __exit sm_via686a_exit(void) +{ + pci_unregister_driver(&via686a_pci_driver); +} + +MODULE_AUTHOR("Kyösti Mälkki , " + "Mark Studebaker " + "and Bob Dougherty "); +MODULE_DESCRIPTION("VIA 686A Sensor device"); +MODULE_LICENSE("GPL"); + +module_init(sm_via686a_init); +module_exit(sm_via686a_exit); diff -Nru a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/i2c/chips/w83781d.c Wed Apr 2 22:24:08 2003 @@ -0,0 +1,1882 @@ +/* + w83781d.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998 - 2001 Frodo Looijaard , + Philip Edelbrock , + and Mark Studebaker + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + Supports following chips: + + Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA + as99127f 7 3 1? 3 0x30 0x12c3 yes no + asb100 "bach" (type_name = as99127f) 0x30 0x0694 yes no + w83781d 7 3 0 3 0x10 0x5ca3 yes yes + w83627hf 9 3 2 3 0x20 0x5ca3 yes yes(LPC) + w83782d 9 3 2-4 3 0x30 0x5ca3 yes yes + w83783s 5-6 3 2 1-2 0x40 0x5ca3 yes no + w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC) + +*/ + +#include +#include +#include +#include +#include +#include +#include + +/* RT Table support #defined so we can take it out if it gets bothersome */ +#define W83781D_RT 1 + +/* Addresses to scan */ +static unsigned short normal_i2c[] = { SENSORS_I2C_END }; +static unsigned short normal_i2c_range[] = { 0x20, 0x2f, SENSORS_I2C_END }; +static unsigned int normal_isa[] = { 0x0290, SENSORS_ISA_END }; +static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; + +/* Insmod parameters */ +SENSORS_INSMOD_6(w83781d, w83782d, w83783s, w83627hf, as99127f, w83697hf); +SENSORS_MODULE_PARM(force_subclients, "List of subclient addresses: " + "{bus, clientaddr, subclientaddr1, subclientaddr2}"); + +static int init = 1; +MODULE_PARM(init, "i"); +MODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); + +/* Constants specified below */ + +/* Length of ISA address segment */ +#define W83781D_EXTENT 8 + +/* Where are the ISA address/data registers relative to the base address */ +#define W83781D_ADDR_REG_OFFSET 5 +#define W83781D_DATA_REG_OFFSET 6 + +/* The W83781D registers */ +/* The W83782D registers for nr=7,8 are in bank 5 */ +#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \ + (0x554 + (((nr) - 7) * 2))) +#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \ + (0x555 + (((nr) - 7) * 2))) +#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ + (0x550 + (nr) - 7)) + +#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr)) +#define W83781D_REG_FAN(nr) (0x27 + (nr)) + +#define W83781D_REG_BANK 0x4E +#define W83781D_REG_TEMP2_CONFIG 0x152 +#define W83781D_REG_TEMP3_CONFIG 0x252 +#define W83781D_REG_TEMP(nr) ((nr == 3) ? (0x0250) : \ + ((nr == 2) ? (0x0150) : \ + (0x27))) +#define W83781D_REG_TEMP_HYST(nr) ((nr == 3) ? (0x253) : \ + ((nr == 2) ? (0x153) : \ + (0x3A))) +#define W83781D_REG_TEMP_OVER(nr) ((nr == 3) ? (0x255) : \ + ((nr == 2) ? (0x155) : \ + (0x39))) + +#define W83781D_REG_CONFIG 0x40 +#define W83781D_REG_ALARM1 0x41 +#define W83781D_REG_ALARM2 0x42 +#define W83781D_REG_ALARM3 0x450 /* not on W83781D */ + +#define W83781D_REG_IRQ 0x4C +#define W83781D_REG_BEEP_CONFIG 0x4D +#define W83781D_REG_BEEP_INTS1 0x56 +#define W83781D_REG_BEEP_INTS2 0x57 +#define W83781D_REG_BEEP_INTS3 0x453 /* not on W83781D */ + +#define W83781D_REG_VID_FANDIV 0x47 + +#define W83781D_REG_CHIPID 0x49 +#define W83781D_REG_WCHIPID 0x58 +#define W83781D_REG_CHIPMAN 0x4F +#define W83781D_REG_PIN 0x4B + +/* 782D/783S only */ +#define W83781D_REG_VBAT 0x5D + +/* PWM 782D (1-4) and 783S (1-2) only */ +#define W83781D_REG_PWM1 0x5B /* 782d and 783s/627hf datasheets disagree */ + /* on which is which; */ +#define W83781D_REG_PWM2 0x5A /* We follow the 782d convention here, */ + /* However 782d is probably wrong. */ +#define W83781D_REG_PWM3 0x5E +#define W83781D_REG_PWM4 0x5F +#define W83781D_REG_PWMCLK12 0x5C +#define W83781D_REG_PWMCLK34 0x45C +static const u8 regpwm[] = { W83781D_REG_PWM1, W83781D_REG_PWM2, + W83781D_REG_PWM3, W83781D_REG_PWM4 +}; + +#define W83781D_REG_PWM(nr) (regpwm[(nr) - 1]) + +#define W83781D_REG_I2C_ADDR 0x48 +#define W83781D_REG_I2C_SUBADDR 0x4A + +/* The following are undocumented in the data sheets however we + received the information in an email from Winbond tech support */ +/* Sensor selection - not on 781d */ +#define W83781D_REG_SCFG1 0x5D +static const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 }; + +#define W83781D_REG_SCFG2 0x59 +static const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 }; + +#define W83781D_DEFAULT_BETA 3435 + +/* RT Table registers */ +#define W83781D_REG_RT_IDX 0x50 +#define W83781D_REG_RT_VAL 0x51 + +/* Conversions. Rounding and limit checking is only done on the TO_REG + variants. Note that you should be a bit careful with which arguments + these macros are called: arguments may be evaluated more than once. + Fixing this is just not worth it. */ +#define IN_TO_REG(val) (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255)) +#define IN_FROM_REG(val) (((val) * 16) / 10) + +static inline u8 +FAN_TO_REG(long rpm, int div) +{ + if (rpm == 0) + return 255; + rpm = SENSORS_LIMIT(rpm, 1, 1000000); + return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); +} + +#define FAN_FROM_REG(val,div) ((val) == 0 ? -1 : \ + ((val) == 255 ? 0 : \ + 1350000 / ((val) * (div)))) + +#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val / 10) < 0 ? (((val / 10) - 5) / 10) : \ + ((val / 10) + 5) / 10), 0, 255)) +#define TEMP_FROM_REG(val) ((((val ) > 0x80 ? (val) - 0x100 : (val)) * 10) * 10) + +#define TEMP_ADD_TO_REG(val) (SENSORS_LIMIT(((((val / 10) + 2) / 5) << 7),\ + 0, 0xffff)) +#define TEMP_ADD_FROM_REG(val) ((((val) >> 7) * 5) * 10) + +#define AS99127_TEMP_ADD_TO_REG(val) (SENSORS_LIMIT((((((val / 10) + 2)*4)/10) \ + << 7), 0, 0xffff)) +#define AS99127_TEMP_ADD_FROM_REG(val) (((((val) >> 7) * 10) / 4) * 10) + +#define ALARMS_FROM_REG(val) (val) +#define PWM_FROM_REG(val) (val) +#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255)) +#define BEEP_MASK_FROM_REG(val) (val) +#define BEEP_MASK_TO_REG(val) ((val) & 0xffffff) + +#define BEEP_ENABLE_TO_REG(val) ((val) ? 1 : 0) +#define BEEP_ENABLE_FROM_REG(val) ((val) ? 1 : 0) + +#define DIV_FROM_REG(val) (1 << (val)) + +static inline u8 +DIV_TO_REG(long val, enum chips type) +{ + int i; + val = SENSORS_LIMIT(val, 1, + ((type == w83781d + || type == as99127f) ? 8 : 128)) >> 1; + for (i = 0; i < 6; i++) { + if (val == 0) + break; + val >>= 1; + } + return ((u8) i); +} + +/* Initial limits */ +#define W83781D_INIT_IN_0 (vid == 3500 ? 280 : vid / 10) +#define W83781D_INIT_IN_1 (vid == 3500 ? 280 : vid / 10) +#define W83781D_INIT_IN_2 330 +#define W83781D_INIT_IN_3 (((500) * 100) / 168) +#define W83781D_INIT_IN_4 (((1200) * 10) / 38) +#define W83781D_INIT_IN_5 (((-1200) * -604) / 2100) +#define W83781D_INIT_IN_6 (((-500) * -604) / 909) +#define W83781D_INIT_IN_7 (((500) * 100) / 168) +#define W83781D_INIT_IN_8 300 +/* Initial limits for 782d/783s negative voltages */ +/* Note level shift. Change min/max below if you change these. */ +#define W83782D_INIT_IN_5 ((((-1200) + 1491) * 100)/514) +#define W83782D_INIT_IN_6 ((( (-500) + 771) * 100)/314) + +#define W83781D_INIT_IN_PERCENTAGE 10 +#define W83781D_INIT_IN_MIN(val) (val - val * W83781D_INIT_IN_PERCENTAGE / 100) +#define W83781D_INIT_IN_MAX(val) (val + val * W83781D_INIT_IN_PERCENTAGE / 100) + +#define W83781D_INIT_IN_MIN_0 W83781D_INIT_IN_MIN(W83781D_INIT_IN_0) +#define W83781D_INIT_IN_MAX_0 W83781D_INIT_IN_MAX(W83781D_INIT_IN_0) +#define W83781D_INIT_IN_MIN_1 W83781D_INIT_IN_MIN(W83781D_INIT_IN_1) +#define W83781D_INIT_IN_MAX_1 W83781D_INIT_IN_MAX(W83781D_INIT_IN_1) +#define W83781D_INIT_IN_MIN_2 W83781D_INIT_IN_MIN(W83781D_INIT_IN_2) +#define W83781D_INIT_IN_MAX_2 W83781D_INIT_IN_MAX(W83781D_INIT_IN_2) +#define W83781D_INIT_IN_MIN_3 W83781D_INIT_IN_MIN(W83781D_INIT_IN_3) +#define W83781D_INIT_IN_MAX_3 W83781D_INIT_IN_MAX(W83781D_INIT_IN_3) +#define W83781D_INIT_IN_MIN_4 W83781D_INIT_IN_MIN(W83781D_INIT_IN_4) +#define W83781D_INIT_IN_MAX_4 W83781D_INIT_IN_MAX(W83781D_INIT_IN_4) +#define W83781D_INIT_IN_MIN_5 W83781D_INIT_IN_MIN(W83781D_INIT_IN_5) +#define W83781D_INIT_IN_MAX_5 W83781D_INIT_IN_MAX(W83781D_INIT_IN_5) +#define W83781D_INIT_IN_MIN_6 W83781D_INIT_IN_MIN(W83781D_INIT_IN_6) +#define W83781D_INIT_IN_MAX_6 W83781D_INIT_IN_MAX(W83781D_INIT_IN_6) +#define W83781D_INIT_IN_MIN_7 W83781D_INIT_IN_MIN(W83781D_INIT_IN_7) +#define W83781D_INIT_IN_MAX_7 W83781D_INIT_IN_MAX(W83781D_INIT_IN_7) +#define W83781D_INIT_IN_MIN_8 W83781D_INIT_IN_MIN(W83781D_INIT_IN_8) +#define W83781D_INIT_IN_MAX_8 W83781D_INIT_IN_MAX(W83781D_INIT_IN_8) + +/* Initial limits for 782d/783s negative voltages */ +/* These aren't direct multiples because of level shift */ +/* Beware going negative - check */ +#define W83782D_INIT_IN_MIN_5_TMP \ + (((-1200 * (100 + W83781D_INIT_IN_PERCENTAGE)) + (1491 * 100))/514) +#define W83782D_INIT_IN_MIN_5 \ + ((W83782D_INIT_IN_MIN_5_TMP > 0) ? W83782D_INIT_IN_MIN_5_TMP : 0) +#define W83782D_INIT_IN_MAX_5 \ + (((-1200 * (100 - W83781D_INIT_IN_PERCENTAGE)) + (1491 * 100))/514) +#define W83782D_INIT_IN_MIN_6_TMP \ + ((( -500 * (100 + W83781D_INIT_IN_PERCENTAGE)) + (771 * 100))/314) +#define W83782D_INIT_IN_MIN_6 \ + ((W83782D_INIT_IN_MIN_6_TMP > 0) ? W83782D_INIT_IN_MIN_6_TMP : 0) +#define W83782D_INIT_IN_MAX_6 \ + ((( -500 * (100 - W83781D_INIT_IN_PERCENTAGE)) + (771 * 100))/314) + +#define W83781D_INIT_FAN_MIN_1 3000 +#define W83781D_INIT_FAN_MIN_2 3000 +#define W83781D_INIT_FAN_MIN_3 3000 + +/* temp = value / 100 */ +#define W83781D_INIT_TEMP_OVER 6000 +#define W83781D_INIT_TEMP_HYST 12700 /* must be 127 for ALARM to work */ +#define W83781D_INIT_TEMP2_OVER 6000 +#define W83781D_INIT_TEMP2_HYST 5000 +#define W83781D_INIT_TEMP3_OVER 6000 +#define W83781D_INIT_TEMP3_HYST 5000 + +/* There are some complications in a module like this. First off, W83781D chips + may be both present on the SMBus and the ISA bus, and we have to handle + those cases separately at some places. Second, there might be several + W83781D chips available (well, actually, that is probably never done; but + it is a clean illustration of how to handle a case like that). Finally, + a specific chip may be attached to *both* ISA and SMBus, and we would + not like to detect it double. Fortunately, in the case of the W83781D at + least, a register tells us what SMBus address we are on, so that helps + a bit - except if there could be more than one SMBus. Groan. No solution + for this yet. */ + +/* This module may seem overly long and complicated. In fact, it is not so + bad. Quite a lot of bookkeeping is done. A real driver can often cut + some corners. */ + +/* For each registered W83781D, we need to keep some data in memory. That + data is pointed to by w83781d_list[NR]->data. The structure itself is + dynamically allocated, at the same time when a new w83781d client is + allocated. */ +struct w83781d_data { + struct semaphore lock; + enum chips type; + + struct semaphore update_lock; + char valid; /* !=0 if following fields are valid */ + unsigned long last_updated; /* In jiffies */ + + struct i2c_client *lm75; /* for secondary I2C addresses */ + /* pointer to array of 2 subclients */ + + u8 in[9]; /* Register value - 8 & 9 for 782D only */ + u8 in_max[9]; /* Register value - 8 & 9 for 782D only */ + u8 in_min[9]; /* Register value - 8 & 9 for 782D only */ + u8 fan[3]; /* Register value */ + u8 fan_min[3]; /* Register value */ + u8 temp; + u8 temp_min; /* Register value */ + u8 temp_max; /* Register value */ + u16 temp_add[2]; /* Register value */ + u16 temp_max_add[2]; /* Register value */ + u16 temp_min_add[2]; /* Register value */ + u8 fan_div[3]; /* Register encoding, shifted right */ + u8 vid; /* Register encoding, combined */ + u32 alarms; /* Register encoding, combined */ + u32 beep_mask; /* Register encoding, combined */ + u8 beep_enable; /* Boolean */ + u8 pwm[4]; /* Register value */ + u8 pwmenable[4]; /* Boolean */ + u16 sens[3]; /* 782D/783S only. + 1 = pentium diode; 2 = 3904 diode; + 3000-5000 = thermistor beta. + Default = 3435. + Other Betas unimplemented */ +#ifdef W83781D_RT + u8 rt[3][32]; /* Register value */ +#endif + u8 vrm; +}; + +static int w83781d_attach_adapter(struct i2c_adapter *adapter); +static int w83781d_detect(struct i2c_adapter *adapter, int address, int kind); +static int w83781d_detach_client(struct i2c_client *client); + +static int w83781d_read_value(struct i2c_client *client, u16 register); +static int w83781d_write_value(struct i2c_client *client, u16 register, + u16 value); +static void w83781d_update_client(struct i2c_client *client); +static void w83781d_init_client(struct i2c_client *client); + +static inline u16 swap_bytes(u16 val) +{ + return (val >> 8) | (val << 8); +} + +static struct i2c_driver w83781d_driver = { + .owner = THIS_MODULE, + .name = "w83781d", + .id = I2C_DRIVERID_W83781D, + .flags = I2C_DF_NOTIFY, + .attach_adapter = w83781d_attach_adapter, + .detach_client = w83781d_detach_client, +}; + +/* following are the sysfs callback functions */ +#define show_in_reg(reg) \ +static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct w83781d_data *data = i2c_get_clientdata(client); \ + \ + w83781d_update_client(client); \ + \ + return sprintf(buf,"%ld\n", (long)IN_FROM_REG(data->reg[nr])); \ +} +show_in_reg(in); +show_in_reg(in_min); +show_in_reg(in_max); + +#define store_in_reg(REG, reg) \ +static ssize_t store_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct w83781d_data *data = i2c_get_clientdata(client); \ + u32 val; \ + \ + val = simple_strtoul(buf, NULL, 10); \ + data->in_##reg[nr] = IN_TO_REG(val); \ + w83781d_write_value(client, W83781D_REG_IN_##REG(nr), data->in_##reg[nr]); \ + \ + return count; \ +} +store_in_reg(MIN, min); +store_in_reg(MAX, max); + +#define sysfs_in_offset(offset) \ +static ssize_t \ +show_regs_in_##offset (struct device *dev, char *buf) \ +{ \ + return show_in(dev, buf, 0x##offset); \ +} \ +static DEVICE_ATTR(in_input##offset, S_IRUGO, show_regs_in_##offset, NULL) + +#define sysfs_in_reg_offset(reg, offset) \ +static ssize_t show_regs_in_##reg##offset (struct device *dev, char *buf) \ +{ \ + return show_in_##reg (dev, buf, 0x##offset); \ +} \ +static ssize_t store_regs_in_##reg##offset (struct device *dev, const char *buf, size_t count) \ +{ \ + return store_in_##reg (dev, buf, count, 0x##offset); \ +} \ +static DEVICE_ATTR(in_##reg##offset, S_IRUGO| S_IWUSR, show_regs_in_##reg##offset, store_regs_in_##reg##offset) + +#define sysfs_in_offsets(offset) \ +sysfs_in_offset(offset); \ +sysfs_in_reg_offset(min, offset); \ +sysfs_in_reg_offset(max, offset); + +sysfs_in_offsets(0); +sysfs_in_offsets(1); +sysfs_in_offsets(2); +sysfs_in_offsets(3); +sysfs_in_offsets(4); +sysfs_in_offsets(5); +sysfs_in_offsets(6); +sysfs_in_offsets(7); +sysfs_in_offsets(8); + +#define device_create_file_in(client, offset) \ +device_create_file(&client->dev, &dev_attr_in_input##offset); \ +device_create_file(&client->dev, &dev_attr_in_min##offset); \ +device_create_file(&client->dev, &dev_attr_in_max##offset); + +#define show_fan_reg(reg) \ +static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct w83781d_data *data = i2c_get_clientdata(client); \ + \ + w83781d_update_client(client); \ + \ + return sprintf(buf,"%ld\n", \ + FAN_FROM_REG(data->reg[nr-1], (long)DIV_FROM_REG(data->fan_div[nr-1]))); \ +} +show_fan_reg(fan); +show_fan_reg(fan_min); + +static ssize_t +store_fan_min(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + data->fan_min[nr - 1] = + FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1])); + w83781d_write_value(client, W83781D_REG_FAN_MIN(nr), + data->fan_min[nr - 1]); + + return count; +} + +#define sysfs_fan_offset(offset) \ +static ssize_t show_regs_fan_##offset (struct device *dev, char *buf) \ +{ \ + return show_fan(dev, buf, 0x##offset); \ +} \ +static DEVICE_ATTR(fan_input##offset, S_IRUGO, show_regs_fan_##offset, NULL) + +#define sysfs_fan_min_offset(offset) \ +static ssize_t show_regs_fan_min##offset (struct device *dev, char *buf) \ +{ \ + return show_fan_min(dev, buf, 0x##offset); \ +} \ +static ssize_t store_regs_fan_min##offset (struct device *dev, const char *buf, size_t count) \ +{ \ + return store_fan_min(dev, buf, count, 0x##offset); \ +} \ +static DEVICE_ATTR(fan_min##offset, S_IRUGO | S_IWUSR, show_regs_fan_min##offset, store_regs_fan_min##offset) + +sysfs_fan_offset(1); +sysfs_fan_min_offset(1); +sysfs_fan_offset(2); +sysfs_fan_min_offset(2); +sysfs_fan_offset(3); +sysfs_fan_min_offset(3); + +#define device_create_file_fan(client, offset) \ +device_create_file(&client->dev, &dev_attr_fan_input##offset); \ +device_create_file(&client->dev, &dev_attr_fan_min##offset); \ + +#define show_temp_reg(reg) \ +static ssize_t show_##reg (struct device *dev, char *buf, int nr) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct w83781d_data *data = i2c_get_clientdata(client); \ + \ + w83781d_update_client(client); \ + \ + if (nr >= 2) { /* TEMP2 and TEMP3 */ \ + if (data->type == as99127f) { \ + return sprintf(buf,"%ld\n", \ + (long)AS99127_TEMP_ADD_FROM_REG(data->reg##_add[nr-2])); \ + } else { \ + return sprintf(buf,"%ld\n", \ + (long)TEMP_ADD_FROM_REG(data->reg##_add[nr-2])); \ + } \ + } else { /* TEMP1 */ \ + return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \ + } \ +} +show_temp_reg(temp); +show_temp_reg(temp_min); +show_temp_reg(temp_max); + +#define store_temp_reg(REG, reg) \ +static ssize_t store_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct w83781d_data *data = i2c_get_clientdata(client); \ + u32 val; \ + \ + val = simple_strtoul(buf, NULL, 10); \ + \ + if (nr >= 2) { /* TEMP2 and TEMP3 */ \ + if (data->type == as99127f) \ + data->temp_##reg##_add[nr-2] = AS99127_TEMP_ADD_TO_REG(val); \ + else \ + data->temp_##reg##_add[nr-2] = TEMP_ADD_TO_REG(val); \ + \ + w83781d_write_value(client, W83781D_REG_TEMP_##REG(nr), \ + data->temp_##reg##_add[nr-2]); \ + } else { /* TEMP1 */ \ + data->temp_##reg = TEMP_TO_REG(val); \ + w83781d_write_value(client, W83781D_REG_TEMP_##REG(nr), \ + data->temp_##reg); \ + } \ + \ + return count; \ +} +store_temp_reg(OVER, min); +store_temp_reg(HYST, max); + +#define sysfs_temp_offset(offset) \ +static ssize_t \ +show_regs_temp_##offset (struct device *dev, char *buf) \ +{ \ + return show_temp(dev, buf, 0x##offset); \ +} \ +static DEVICE_ATTR(temp_input##offset, S_IRUGO, show_regs_temp_##offset, NULL) + +#define sysfs_temp_reg_offset(reg, offset) \ +static ssize_t show_regs_temp_##reg##offset (struct device *dev, char *buf) \ +{ \ + return show_temp_##reg (dev, buf, 0x##offset); \ +} \ +static ssize_t store_regs_temp_##reg##offset (struct device *dev, const char *buf, size_t count) \ +{ \ + return store_temp_##reg (dev, buf, count, 0x##offset); \ +} \ +static DEVICE_ATTR(temp_##reg##offset, S_IRUGO| S_IWUSR, show_regs_temp_##reg##offset, store_regs_temp_##reg##offset) + +#define sysfs_temp_offsets(offset) \ +sysfs_temp_offset(offset); \ +sysfs_temp_reg_offset(min, offset); \ +sysfs_temp_reg_offset(max, offset); + +sysfs_temp_offsets(1); +sysfs_temp_offsets(2); +sysfs_temp_offsets(3); + +#define device_create_file_temp(client, offset) \ +device_create_file(&client->dev, &dev_attr_temp_input##offset); \ +device_create_file(&client->dev, &dev_attr_temp_max##offset); \ +device_create_file(&client->dev, &dev_attr_temp_min##offset); + +static ssize_t +show_vid_reg(struct device *dev, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + + w83781d_update_client(client); + + return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); +} + +static +DEVICE_ATTR(vid, S_IRUGO, show_vid_reg, NULL) +#define device_create_file_vid(client) \ +device_create_file(&client->dev, &dev_attr_vid); +static ssize_t +show_vrm_reg(struct device *dev, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + + w83781d_update_client(client); + + return sprintf(buf, "%ld\n", (long) data->vrm); +} + +static ssize_t +store_vrm_reg(struct device *dev, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + data->vrm = val; + + return count; +} + +static +DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg) +#define device_create_file_vrm(client) \ +device_create_file(&client->dev, &dev_attr_vrm); +static ssize_t +show_alarms_reg(struct device *dev, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + + w83781d_update_client(client); + + return sprintf(buf, "%ld\n", (long) ALARMS_FROM_REG(data->alarms)); +} + +static +DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL) +#define device_create_file_alarms(client) \ +device_create_file(&client->dev, &dev_attr_alarms); +#define show_beep_reg(REG, reg) \ +static ssize_t show_beep_##reg (struct device *dev, char *buf) \ +{ \ + struct i2c_client *client = to_i2c_client(dev); \ + struct w83781d_data *data = i2c_get_clientdata(client); \ + \ + w83781d_update_client(client); \ + \ + return sprintf(buf,"%ld\n", (long)BEEP_##REG##_FROM_REG(data->beep_##reg)); \ +} +show_beep_reg(ENABLE, enable); +show_beep_reg(MASK, mask); + +#define BEEP_ENABLE 0 /* Store beep_enable */ +#define BEEP_MASK 1 /* Store beep_mask */ + +static ssize_t +store_beep_reg(struct device *dev, const char *buf, size_t count, + int update_mask) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + u32 val, val2; + + val = simple_strtoul(buf, NULL, 10); + + if (update_mask == BEEP_MASK) { /* We are storing beep_mask */ + data->beep_mask = BEEP_MASK_TO_REG(val); + w83781d_write_value(client, W83781D_REG_BEEP_INTS1, + data->beep_mask & 0xff); + + if ((data->type != w83781d) && (data->type != as99127f)) { + w83781d_write_value(client, W83781D_REG_BEEP_INTS3, + ((data->beep_mask) >> 16) & 0xff); + } + + val2 = (data->beep_mask >> 8) & 0x7f; + } else { /* We are storing beep_enable */ + val2 = w83781d_read_value(client, W83781D_REG_BEEP_INTS2) & 0x7f; + data->beep_enable = BEEP_ENABLE_TO_REG(val); + } + + w83781d_write_value(client, W83781D_REG_BEEP_INTS2, + val2 | data->beep_enable << 7); + + return count; +} + +#define sysfs_beep(REG, reg) \ +static ssize_t show_regs_beep_##reg (struct device *dev, char *buf) \ +{ \ + return show_beep_##reg(dev, buf); \ +} \ +static ssize_t store_regs_beep_##reg (struct device *dev, const char *buf, size_t count) \ +{ \ + return store_beep_reg(dev, buf, count, BEEP_##REG); \ +} \ +static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, show_regs_beep_##reg, store_regs_beep_##reg) + +sysfs_beep(ENABLE, enable); +sysfs_beep(MASK, mask); + +#define device_create_file_beep(client) \ +device_create_file(&client->dev, &dev_attr_beep_enable); \ +device_create_file(&client->dev, &dev_attr_beep_mask); + +/* w83697hf only has two fans */ +static ssize_t +show_fan_div_reg(struct device *dev, char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + + w83781d_update_client(client); + + return sprintf(buf, "%ld\n", + (long) DIV_FROM_REG(data->fan_div[nr - 1])); +} + +/* w83697hf only has two fans */ +static ssize_t +store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + u32 val, old, old2, old3; + + val = simple_strtoul(buf, NULL, 10); + old = w83781d_read_value(client, W83781D_REG_VID_FANDIV); + + data->fan_div[nr - 1] = DIV_TO_REG(val, data->type); + + /* w83781d and as99127f don't have extended divisor bits */ + if ((data->type != w83781d) && data->type != as99127f) { + old3 = w83781d_read_value(client, W83781D_REG_VBAT); + } + if (nr >= 3 && data->type != w83697hf) { + old2 = w83781d_read_value(client, W83781D_REG_PIN); + old2 = (old2 & 0x3f) | ((data->fan_div[2] & 0x03) << 6); + w83781d_write_value(client, W83781D_REG_PIN, old2); + + if ((data->type != w83781d) && (data->type != as99127f)) { + old3 = (old3 & 0x7f) | ((data->fan_div[2] & 0x04) << 5); + } + } + if (nr >= 2) { + old = (old & 0x3f) | ((data->fan_div[1] & 0x03) << 6); + + if ((data->type != w83781d) && (data->type != as99127f)) { + old3 = (old3 & 0xbf) | ((data->fan_div[1] & 0x04) << 4); + } + } + if (nr >= 1) { + old = (old & 0xcf) | ((data->fan_div[0] & 0x03) << 4); + w83781d_write_value(client, W83781D_REG_VID_FANDIV, old); + + if ((data->type != w83781d) && (data->type != as99127f)) { + old3 = (old3 & 0xdf) | ((data->fan_div[0] & 0x04) << 3); + w83781d_write_value(client, W83781D_REG_VBAT, old3); + } + } + + return count; +} + +#define sysfs_fan_div(offset) \ +static ssize_t show_regs_fan_div_##offset (struct device *dev, char *buf) \ +{ \ + return show_fan_div_reg(dev, buf, offset); \ +} \ +static ssize_t store_regs_fan_div_##offset (struct device *dev, const char *buf, size_t count) \ +{ \ + return store_fan_div_reg(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(fan_div##offset, S_IRUGO | S_IWUSR, show_regs_fan_div_##offset, store_regs_fan_div_##offset) + +sysfs_fan_div(1); +sysfs_fan_div(2); +sysfs_fan_div(3); + +#define device_create_file_fan_div(client, offset) \ +device_create_file(&client->dev, &dev_attr_fan_div##offset); \ + +/* w83697hf only has two fans */ +static ssize_t +show_pwm_reg(struct device *dev, char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + + w83781d_update_client(client); + + return sprintf(buf, "%ld\n", (long) PWM_FROM_REG(data->pwm[nr - 1])); +} + +/* w83697hf only has two fans */ +static ssize_t +show_pwmenable_reg(struct device *dev, char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + + w83781d_update_client(client); + + return sprintf(buf, "%ld\n", (long) data->pwmenable[nr - 1]); +} + +static ssize_t +store_pwm_reg(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + u32 val; + + val = simple_strtoul(buf, NULL, 10); + + data->pwm[nr - 1] = PWM_TO_REG(val); + w83781d_write_value(client, W83781D_REG_PWM(nr), data->pwm[nr - 1]); + + return count; +} + +static ssize_t +store_pwmenable_reg(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + u32 val, j, k; + + val = simple_strtoul(buf, NULL, 10); + + /* only PWM2 can be enabled/disabled */ + if (nr == 2) { + j = w83781d_read_value(client, W83781D_REG_PWMCLK12); + k = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG); + + if (val > 0) { + if (!(j & 0x08)) + w83781d_write_value(client, + W83781D_REG_PWMCLK12, + j | 0x08); + if (k & 0x10) + w83781d_write_value(client, + W83781D_REG_BEEP_CONFIG, + k & 0xef); + + data->pwmenable[1] = 1; + } else { + if (j & 0x08) + w83781d_write_value(client, + W83781D_REG_PWMCLK12, + j & 0xf7); + if (!(k & 0x10)) + w83781d_write_value(client, + W83781D_REG_BEEP_CONFIG, + j | 0x10); + + data->pwmenable[1] = 0; + } + } + + return count; +} + +#define sysfs_pwm(offset) \ +static ssize_t show_regs_pwm_##offset (struct device *dev, char *buf) \ +{ \ + return show_pwm_reg(dev, buf, offset); \ +} \ +static ssize_t store_regs_pwm_##offset (struct device *dev, const char *buf, size_t count) \ +{ \ + return store_pwm_reg(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, show_regs_pwm_##offset, store_regs_pwm_##offset) + +#define sysfs_pwmenable(offset) \ +static ssize_t show_regs_pwmenable_##offset (struct device *dev, char *buf) \ +{ \ + return show_pwmenable_reg(dev, buf, offset); \ +} \ +static ssize_t store_regs_pwmenable_##offset (struct device *dev, const char *buf, size_t count) \ +{ \ + return store_pwmenable_reg(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(pwm_enable##offset, S_IRUGO | S_IWUSR, show_regs_pwmenable_##offset, store_regs_pwmenable_##offset) + +sysfs_pwm(1); +sysfs_pwm(2); +sysfs_pwmenable(2); /* only PWM2 can be enabled/disabled */ +sysfs_pwm(3); +sysfs_pwm(4); + +#define device_create_file_pwm(client, offset) \ +device_create_file(&client->dev, &dev_attr_pwm##offset); \ + +#define device_create_file_pwmenable(client, offset) \ +device_create_file(&client->dev, &dev_attr_pwm_enable##offset); \ + +static ssize_t +show_sensor_reg(struct device *dev, char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + + w83781d_update_client(client); + + return sprintf(buf, "%ld\n", (long) data->sens[nr - 1]); +} + +static ssize_t +store_sensor_reg(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + u32 val, tmp; + + val = simple_strtoul(buf, NULL, 10); + + switch (val) { + case 1: /* PII/Celeron diode */ + tmp = w83781d_read_value(client, W83781D_REG_SCFG1); + w83781d_write_value(client, W83781D_REG_SCFG1, + tmp | BIT_SCFG1[nr - 1]); + tmp = w83781d_read_value(client, W83781D_REG_SCFG2); + w83781d_write_value(client, W83781D_REG_SCFG2, + tmp | BIT_SCFG2[nr - 1]); + data->sens[nr - 1] = val; + break; + case 2: /* 3904 */ + tmp = w83781d_read_value(client, W83781D_REG_SCFG1); + w83781d_write_value(client, W83781D_REG_SCFG1, + tmp | BIT_SCFG1[nr - 1]); + tmp = w83781d_read_value(client, W83781D_REG_SCFG2); + w83781d_write_value(client, W83781D_REG_SCFG2, + tmp & ~BIT_SCFG2[nr - 1]); + data->sens[nr - 1] = val; + break; + case W83781D_DEFAULT_BETA: /* thermistor */ + tmp = w83781d_read_value(client, W83781D_REG_SCFG1); + w83781d_write_value(client, W83781D_REG_SCFG1, + tmp & ~BIT_SCFG1[nr - 1]); + data->sens[nr - 1] = val; + break; + default: + dev_err(&client->dev, + "Invalid sensor type %ld; must be 1, 2, or %d\n", + (long) val, W83781D_DEFAULT_BETA); + break; + } + + return count; +} + +#define sysfs_sensor(offset) \ +static ssize_t show_regs_sensor_##offset (struct device *dev, char *buf) \ +{ \ + return show_sensor_reg(dev, buf, offset); \ +} \ +static ssize_t store_regs_sensor_##offset (struct device *dev, const char *buf, size_t count) \ +{ \ + return store_sensor_reg(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(sensor##offset, S_IRUGO | S_IWUSR, show_regs_sensor_##offset, store_regs_sensor_##offset) + +sysfs_sensor(1); +sysfs_sensor(2); +sysfs_sensor(3); + +#define device_create_file_sensor(client, offset) \ +device_create_file(&client->dev, &dev_attr_sensor##offset); \ + +#ifdef W83781D_RT +static ssize_t +show_rt_reg(struct device *dev, char *buf, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + int i, j = 0; + + w83781d_update_client(client); + + for (i = 0; i < 32; i++) { + if (i > 0) + j += sprintf(buf, " %ld", (long) data->rt[nr - 1][i]); + else + j += sprintf(buf, "%ld", (long) data->rt[nr - 1][i]); + } + j += sprintf(buf, "\n"); + + return j; +} + +static ssize_t +store_rt_reg(struct device *dev, const char *buf, size_t count, int nr) +{ + struct i2c_client *client = to_i2c_client(dev); + struct w83781d_data *data = i2c_get_clientdata(client); + u32 val, i; + + for (i = 0; i < count; i++) { + val = simple_strtoul(buf + count, NULL, 10); + + /* fixme: no bounds checking 0-255 */ + data->rt[nr - 1][i] = val & 0xff; + w83781d_write_value(client, W83781D_REG_RT_IDX, i); + w83781d_write_value(client, W83781D_REG_RT_VAL, + data->rt[nr - 1][i]); + } + + return count; +} + +#define sysfs_rt(offset) \ +static ssize_t show_regs_rt_##offset (struct device *dev, char *buf) \ +{ \ + return show_rt_reg(dev, buf, offset); \ +} \ +static ssize_t store_regs_rt_##offset (struct device *dev, const char *buf, size_t count) \ +{ \ + return store_rt_reg(dev, buf, count, offset); \ +} \ +static DEVICE_ATTR(rt##offset, S_IRUGO | S_IWUSR, show_regs_rt_##offset, store_regs_rt_##offset) + +sysfs_rt(1); +sysfs_rt(2); +sysfs_rt(3); + +#define device_create_file_rt(client, offset) \ +device_create_file(&client->dev, &dev_attr_rt##offset); \ + +#endif /* ifdef W83781D_RT */ + +/* This function is called when: + * w83781d_driver is inserted (when this module is loaded), for each + available adapter + * when a new adapter is inserted (and w83781d_driver is still present) */ +static int +w83781d_attach_adapter(struct i2c_adapter *adapter) +{ + return i2c_detect(adapter, &addr_data, w83781d_detect); +} + +static int +w83781d_detect(struct i2c_adapter *adapter, int address, int kind) +{ + int i = 0, val1 = 0, val2, id; + struct i2c_client *new_client; + struct w83781d_data *data; + int err = 0; + const char *type_name = ""; + const char *client_name = ""; + int is_isa = i2c_is_isa_adapter(adapter); + enum vendor { winbond, asus } vendid; + + if (!is_isa + && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + goto ERROR0; + + if (is_isa) { + if (!request_region(address, W83781D_EXTENT, "w83781d")) + goto ERROR0; + release_region(address, W83781D_EXTENT); + } + + /* Probe whether there is anything available on this address. Already + done for SMBus clients */ + if (kind < 0) { + if (is_isa) { + +#define REALLY_SLOW_IO + /* We need the timeouts for at least some LM78-like chips. But only + if we read 'undefined' registers. */ + i = inb_p(address + 1); + if (inb_p(address + 2) != i) + goto ERROR0; + if (inb_p(address + 3) != i) + goto ERROR0; + if (inb_p(address + 7) != i) + goto ERROR0; +#undef REALLY_SLOW_IO + + /* Let's just hope nothing breaks here */ + i = inb_p(address + 5) & 0x7f; + outb_p(~i & 0x7f, address + 5); + if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { + outb_p(i, address + 5); + return 0; + } + } + } + + /* OK. For now, we presume we have a valid client. We now create the + client structure, even though we cannot fill it completely yet. + But it allows us to access w83781d_{read,write}_value. */ + + if (!(new_client = kmalloc(sizeof (struct i2c_client) + + sizeof (struct w83781d_data), GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR0; + } + + memset(new_client, 0x00, sizeof (struct i2c_client) + + sizeof (struct w83781d_data)); + + data = (struct w83781d_data *) (new_client + 1); + i2c_set_clientdata(new_client, data); + new_client->addr = address; + init_MUTEX(&data->lock); + new_client->adapter = adapter; + new_client->driver = &w83781d_driver; + new_client->flags = 0; + + /* Now, we do the remaining detection. */ + + /* The w8378?d may be stuck in some other bank than bank 0. This may + make reading other information impossible. Specify a force=... or + force_*=... parameter, and the Winbond will be reset to the right + bank. */ + if (kind < 0) { + if (w83781d_read_value(new_client, W83781D_REG_CONFIG) & 0x80) + goto ERROR1; + val1 = w83781d_read_value(new_client, W83781D_REG_BANK); + val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN); + /* Check for Winbond or Asus ID if in bank 0 */ + if ((!(val1 & 0x07)) && + (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3) + && (val2 != 0x94)) + || ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12) + && (val2 != 0x06)))) + goto ERROR1; + /* If Winbond SMBus, check address at 0x48. Asus doesn't support */ + if ((!is_isa) && (((!(val1 & 0x80)) && (val2 == 0xa3)) || + ((val1 & 0x80) && (val2 == 0x5c)))) { + if (w83781d_read_value + (new_client, W83781D_REG_I2C_ADDR) != address) + goto ERROR1; + } + } + + /* We have either had a force parameter, or we have already detected the + Winbond. Put it now into bank 0 and Vendor ID High Byte */ + w83781d_write_value(new_client, W83781D_REG_BANK, + (w83781d_read_value(new_client, + W83781D_REG_BANK) & 0x78) | + 0x80); + + /* Determine the chip type. */ + if (kind <= 0) { + /* get vendor ID */ + val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN); + if (val2 == 0x5c) + vendid = winbond; + else if ((val2 == 0x12) || (val2 == 0x06)) + vendid = asus; + else + goto ERROR1; + /* mask off lower bit, not reliable */ + val1 = + w83781d_read_value(new_client, W83781D_REG_WCHIPID) & 0xfe; + if (val1 == 0x10 && vendid == winbond) + kind = w83781d; + else if (val1 == 0x30 && vendid == winbond) + kind = w83782d; + else if (val1 == 0x40 && vendid == winbond && !is_isa) + kind = w83783s; + else if (val1 == 0x20 && vendid == winbond) + kind = w83627hf; + else if (val1 == 0x30 && vendid == asus && !is_isa) + kind = as99127f; + else if (val1 == 0x60 && vendid == winbond && is_isa) + kind = w83697hf; + else { + if (kind == 0) + dev_warn(&new_client->dev, + "Ignoring 'force' parameter for unknown chip at" + "adapter %d, address 0x%02x\n", + i2c_adapter_id(adapter), address); + goto ERROR1; + } + } + + if (kind == w83781d) { + type_name = "w83781d"; + client_name = "W83781D chip"; + } else if (kind == w83782d) { + type_name = "w83782d"; + client_name = "W83782D chip"; + } else if (kind == w83783s) { + type_name = "w83783s"; + client_name = "W83783S chip"; + } else if (kind == w83627hf) { + type_name = "w83627hf"; + client_name = "W83627HF chip"; + } else if (kind == as99127f) { + type_name = "as99127f"; + client_name = "AS99127F chip"; + } else if (kind == w83697hf) { + type_name = "w83697hf"; + client_name = "W83697HF chip"; + } else { + dev_err(&new_client->dev, "Internal error: unknown kind (%d)?!?", kind); + goto ERROR1; + } + + /* Reserve the ISA region */ + if (is_isa) + request_region(address, W83781D_EXTENT, type_name); + + /* Fill in the remaining client fields and put it into the global list */ + strncpy(new_client->dev.name, client_name, DEVICE_NAME_SIZE); + data->type = kind; + + data->valid = 0; + init_MUTEX(&data->update_lock); + + /* Tell the I2C layer a new client has arrived */ + if ((err = i2c_attach_client(new_client))) + goto ERROR3; + + /* attach secondary i2c lm75-like clients */ + if (!is_isa) { + if (!(data->lm75 = kmalloc(2 * sizeof (struct i2c_client), + GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR4; + } + + memset(data->lm75, 0x00, 2 * sizeof (struct i2c_client)); + + id = i2c_adapter_id(adapter); + if (force_subclients[0] == id && force_subclients[1] == address) { + for (i = 2; i <= 3; i++) { + if (force_subclients[i] < 0x48 || + force_subclients[i] > 0x4f) { + dev_err(&new_client->dev, + "Invalid subclient address %d; must be 0x48-0x4f\n", + force_subclients[i]); + goto ERROR5; + } + } + w83781d_write_value(new_client, + W83781D_REG_I2C_SUBADDR, + (force_subclients[2] & 0x07) | + ((force_subclients[3] & 0x07) << + 4)); + data->lm75[0].addr = force_subclients[2]; + } else { + val1 = w83781d_read_value(new_client, + W83781D_REG_I2C_SUBADDR); + data->lm75[0].addr = 0x48 + (val1 & 0x07); + } + if (kind != w83783s) { + if (force_subclients[0] == id && + force_subclients[1] == address) { + data->lm75[1].addr = force_subclients[3]; + } else { + data->lm75[1].addr = + 0x48 + ((val1 >> 4) & 0x07); + } + if (data->lm75[0].addr == data->lm75[1].addr) { + dev_err(&new_client->dev, + "Duplicate addresses 0x%x for subclients.\n", + data->lm75[0].addr); + goto ERROR5; + } + } + if (kind == w83781d) + client_name = "W83781D subclient"; + else if (kind == w83782d) + client_name = "W83782D subclient"; + else if (kind == w83783s) + client_name = "W83783S subclient"; + else if (kind == w83627hf) + client_name = "W83627HF subclient"; + else if (kind == as99127f) + client_name = "AS99127F subclient"; + + for (i = 0; i <= 1; i++) { + i2c_set_clientdata(&data->lm75[i], NULL); /* store all data in w83781d */ + data->lm75[i].adapter = adapter; + data->lm75[i].driver = &w83781d_driver; + data->lm75[i].flags = 0; + strncpy(data->lm75[i].dev.name, client_name, + DEVICE_NAME_SIZE); + if (kind == w83783s) + break; + } + } else { + data->lm75 = NULL; + } + + device_create_file_in(new_client, 0); + if (kind != w83783s && kind != w83697hf) + device_create_file_in(new_client, 1); + device_create_file_in(new_client, 2); + device_create_file_in(new_client, 3); + device_create_file_in(new_client, 4); + device_create_file_in(new_client, 5); + device_create_file_in(new_client, 6); + if (kind != as99127f && kind != w83781d && kind != w83783s) { + device_create_file_in(new_client, 7); + device_create_file_in(new_client, 8); + } + + device_create_file_fan(new_client, 1); + device_create_file_fan(new_client, 2); + if (kind != w83697hf) + device_create_file_fan(new_client, 3); + + device_create_file_temp(new_client, 1); + device_create_file_temp(new_client, 2); + if (kind != w83783s && kind != w83697hf) + device_create_file_temp(new_client, 3); + + if (kind != w83697hf) + device_create_file_vid(new_client); + + if (kind != w83697hf) + device_create_file_vrm(new_client); + + device_create_file_fan_div(new_client, 1); + device_create_file_fan_div(new_client, 2); + if (kind != w83697hf) + device_create_file_fan_div(new_client, 3); + + device_create_file_alarms(new_client); + + device_create_file_beep(new_client); + + if (kind != w83781d) { + device_create_file_pwm(new_client, 1); + device_create_file_pwm(new_client, 2); + device_create_file_pwmenable(new_client, 2); + } + if (kind == w83782d && !is_isa) { + device_create_file_pwm(new_client, 3); + device_create_file_pwm(new_client, 4); + } + + if (kind != as99127f && kind != w83781d) { + device_create_file_sensor(new_client, 1); + device_create_file_sensor(new_client, 2); + if (kind != w83783s && kind != w83697hf) + device_create_file_sensor(new_client, 3); + } +#ifdef W83781D_RT + if (kind == w83781d) { + device_create_file_rt(new_client, 1); + device_create_file_rt(new_client, 2); + device_create_file_rt(new_client, 3); + } +#endif + + /* Initialize the chip */ + w83781d_init_client(new_client); + return 0; + +/* OK, this is not exactly good programming practice, usually. But it is + very code-efficient in this case. */ + + ERROR5: + if (!is_isa) { + i2c_detach_client(&data->lm75[0]); + if (data->type != w83783s) + i2c_detach_client(&data->lm75[1]); + kfree(data->lm75); + } + ERROR4: + i2c_detach_client(new_client); + ERROR3: + if (is_isa) + release_region(address, W83781D_EXTENT); + ERROR1: + kfree(new_client); + ERROR0: + return err; +} + +static int +w83781d_detach_client(struct i2c_client *client) +{ + struct w83781d_data *data = i2c_get_clientdata(client); + int err; + + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, + "Client deregistration failed, client not detached.\n"); + return err; + } + + if (i2c_is_isa_client(client)) { + release_region(client->addr, W83781D_EXTENT); + } else { + i2c_detach_client(&data->lm75[0]); + if (data->type != w83783s) + i2c_detach_client(&data->lm75[1]); + kfree(data->lm75); + } + kfree(client); + + return 0; +} + +/* The SMBus locks itself, usually, but nothing may access the Winbond between + bank switches. ISA access must always be locked explicitly! + We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks, + would slow down the W83781D access and should not be necessary. + There are some ugly typecasts here, but the good news is - they should + nowhere else be necessary! */ +static int +w83781d_read_value(struct i2c_client *client, u16 reg) +{ + struct w83781d_data *data = i2c_get_clientdata(client); + int res, word_sized, bank; + struct i2c_client *cl; + + down(&data->lock); + if (i2c_is_isa_client(client)) { + word_sized = (((reg & 0xff00) == 0x100) + || ((reg & 0xff00) == 0x200)) + && (((reg & 0x00ff) == 0x50) + || ((reg & 0x00ff) == 0x53) + || ((reg & 0x00ff) == 0x55)); + if (reg & 0xff00) { + outb_p(W83781D_REG_BANK, + client->addr + W83781D_ADDR_REG_OFFSET); + outb_p(reg >> 8, + client->addr + W83781D_DATA_REG_OFFSET); + } + outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); + res = inb_p(client->addr + W83781D_DATA_REG_OFFSET); + if (word_sized) { + outb_p((reg & 0xff) + 1, + client->addr + W83781D_ADDR_REG_OFFSET); + res = + (res << 8) + inb_p(client->addr + + W83781D_DATA_REG_OFFSET); + } + if (reg & 0xff00) { + outb_p(W83781D_REG_BANK, + client->addr + W83781D_ADDR_REG_OFFSET); + outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); + } + } else { + bank = (reg >> 8) & 0x0f; + if (bank > 2) + /* switch banks */ + i2c_smbus_write_byte_data(client, W83781D_REG_BANK, + bank); + if (bank == 0 || bank > 2) { + res = i2c_smbus_read_byte_data(client, reg & 0xff); + } else { + /* switch to subclient */ + cl = &data->lm75[bank - 1]; + /* convert from ISA to LM75 I2C addresses */ + switch (reg & 0xff) { + case 0x50: /* TEMP */ + res = + swap_bytes(i2c_smbus_read_word_data(cl, 0)); + break; + case 0x52: /* CONFIG */ + res = i2c_smbus_read_byte_data(cl, 1); + break; + case 0x53: /* HYST */ + res = + swap_bytes(i2c_smbus_read_word_data(cl, 2)); + break; + case 0x55: /* OVER */ + default: + res = + swap_bytes(i2c_smbus_read_word_data(cl, 3)); + break; + } + } + if (bank > 2) + i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0); + } + up(&data->lock); + return res; +} + +static int +w83781d_write_value(struct i2c_client *client, u16 reg, u16 value) +{ + struct w83781d_data *data = i2c_get_clientdata(client); + int word_sized, bank; + struct i2c_client *cl; + + down(&data->lock); + if (i2c_is_isa_client(client)) { + word_sized = (((reg & 0xff00) == 0x100) + || ((reg & 0xff00) == 0x200)) + && (((reg & 0x00ff) == 0x53) + || ((reg & 0x00ff) == 0x55)); + if (reg & 0xff00) { + outb_p(W83781D_REG_BANK, + client->addr + W83781D_ADDR_REG_OFFSET); + outb_p(reg >> 8, + client->addr + W83781D_DATA_REG_OFFSET); + } + outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); + if (word_sized) { + outb_p(value >> 8, + client->addr + W83781D_DATA_REG_OFFSET); + outb_p((reg & 0xff) + 1, + client->addr + W83781D_ADDR_REG_OFFSET); + } + outb_p(value & 0xff, client->addr + W83781D_DATA_REG_OFFSET); + if (reg & 0xff00) { + outb_p(W83781D_REG_BANK, + client->addr + W83781D_ADDR_REG_OFFSET); + outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); + } + } else { + bank = (reg >> 8) & 0x0f; + if (bank > 2) + /* switch banks */ + i2c_smbus_write_byte_data(client, W83781D_REG_BANK, + bank); + if (bank == 0 || bank > 2) { + i2c_smbus_write_byte_data(client, reg & 0xff, + value & 0xff); + } else { + /* switch to subclient */ + cl = &data->lm75[bank - 1]; + /* convert from ISA to LM75 I2C addresses */ + switch (reg & 0xff) { + case 0x52: /* CONFIG */ + i2c_smbus_write_byte_data(cl, 1, value & 0xff); + break; + case 0x53: /* HYST */ + i2c_smbus_write_word_data(cl, 2, + swap_bytes(value)); + break; + case 0x55: /* OVER */ + i2c_smbus_write_word_data(cl, 3, + swap_bytes(value)); + break; + } + } + if (bank > 2) + i2c_smbus_write_byte_data(client, W83781D_REG_BANK, 0); + } + up(&data->lock); + return 0; +} + +/* Called when we have found a new W83781D. It should set limits, etc. */ +static void +w83781d_init_client(struct i2c_client *client) +{ + struct w83781d_data *data = i2c_get_clientdata(client); + int vid = 0, i, p; + int type = data->type; + u8 tmp; + + if (init && type != as99127f) { /* this resets registers we don't have + documentation for on the as99127f */ + /* save these registers */ + i = w83781d_read_value(client, W83781D_REG_BEEP_CONFIG); + p = w83781d_read_value(client, W83781D_REG_PWMCLK12); + /* Reset all except Watchdog values and last conversion values + This sets fan-divs to 2, among others */ + w83781d_write_value(client, W83781D_REG_CONFIG, 0x80); + /* Restore the registers and disable power-on abnormal beep. + This saves FAN 1/2/3 input/output values set by BIOS. */ + w83781d_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80); + w83781d_write_value(client, W83781D_REG_PWMCLK12, p); + /* Disable master beep-enable (reset turns it on). + Individual beep_mask should be reset to off but for some reason + disabling this bit helps some people not get beeped */ + w83781d_write_value(client, W83781D_REG_BEEP_INTS2, 0); + } + + if (type != w83697hf) { + vid = w83781d_read_value(client, W83781D_REG_VID_FANDIV) & 0x0f; + vid |= + (w83781d_read_value(client, W83781D_REG_CHIPID) & 0x01) << + 4; + data->vrm = DEFAULT_VRM; + vid = vid_from_reg(vid, data->vrm); + } + + if ((type != w83781d) && (type != as99127f)) { + tmp = w83781d_read_value(client, W83781D_REG_SCFG1); + for (i = 1; i <= 3; i++) { + if (!(tmp & BIT_SCFG1[i - 1])) { + data->sens[i - 1] = W83781D_DEFAULT_BETA; + } else { + if (w83781d_read_value + (client, + W83781D_REG_SCFG2) & BIT_SCFG2[i - 1]) + data->sens[i - 1] = 1; + else + data->sens[i - 1] = 2; + } + if ((type == w83783s || type == w83697hf) && (i == 2)) + break; + } + } +#ifdef W83781D_RT +/* + Fill up the RT Tables. + We assume that they are 32 bytes long, in order for temp 1-3. + Data sheet documentation is sparse. + We also assume that it is only for the 781D although I suspect + that the others support it as well.... +*/ + + if (init && type == w83781d) { + u16 k = 0; +/* + Auto-indexing doesn't seem to work... + w83781d_write_value(client,W83781D_REG_RT_IDX,0); +*/ + for (i = 0; i < 3; i++) { + int j; + for (j = 0; j < 32; j++) { + w83781d_write_value(client, + W83781D_REG_RT_IDX, k++); + data->rt[i][j] = + w83781d_read_value(client, + W83781D_REG_RT_VAL); + } + } + } +#endif /* W83781D_RT */ + + if (init) { + w83781d_write_value(client, W83781D_REG_IN_MIN(0), + IN_TO_REG(W83781D_INIT_IN_MIN_0)); + w83781d_write_value(client, W83781D_REG_IN_MAX(0), + IN_TO_REG(W83781D_INIT_IN_MAX_0)); + if (type != w83783s && type != w83697hf) { + w83781d_write_value(client, W83781D_REG_IN_MIN(1), + IN_TO_REG(W83781D_INIT_IN_MIN_1)); + w83781d_write_value(client, W83781D_REG_IN_MAX(1), + IN_TO_REG(W83781D_INIT_IN_MAX_1)); + } + + w83781d_write_value(client, W83781D_REG_IN_MIN(2), + IN_TO_REG(W83781D_INIT_IN_MIN_2)); + w83781d_write_value(client, W83781D_REG_IN_MAX(2), + IN_TO_REG(W83781D_INIT_IN_MAX_2)); + w83781d_write_value(client, W83781D_REG_IN_MIN(3), + IN_TO_REG(W83781D_INIT_IN_MIN_3)); + w83781d_write_value(client, W83781D_REG_IN_MAX(3), + IN_TO_REG(W83781D_INIT_IN_MAX_3)); + w83781d_write_value(client, W83781D_REG_IN_MIN(4), + IN_TO_REG(W83781D_INIT_IN_MIN_4)); + w83781d_write_value(client, W83781D_REG_IN_MAX(4), + IN_TO_REG(W83781D_INIT_IN_MAX_4)); + if (type == w83781d || type == as99127f) { + w83781d_write_value(client, W83781D_REG_IN_MIN(5), + IN_TO_REG(W83781D_INIT_IN_MIN_5)); + w83781d_write_value(client, W83781D_REG_IN_MAX(5), + IN_TO_REG(W83781D_INIT_IN_MAX_5)); + } else { + w83781d_write_value(client, W83781D_REG_IN_MIN(5), + IN_TO_REG(W83782D_INIT_IN_MIN_5)); + w83781d_write_value(client, W83781D_REG_IN_MAX(5), + IN_TO_REG(W83782D_INIT_IN_MAX_5)); + } + if (type == w83781d || type == as99127f) { + w83781d_write_value(client, W83781D_REG_IN_MIN(6), + IN_TO_REG(W83781D_INIT_IN_MIN_6)); + w83781d_write_value(client, W83781D_REG_IN_MAX(6), + IN_TO_REG(W83781D_INIT_IN_MAX_6)); + } else { + w83781d_write_value(client, W83781D_REG_IN_MIN(6), + IN_TO_REG(W83782D_INIT_IN_MIN_6)); + w83781d_write_value(client, W83781D_REG_IN_MAX(6), + IN_TO_REG(W83782D_INIT_IN_MAX_6)); + } + if ((type == w83782d) || (type == w83627hf) || + (type == w83697hf)) { + w83781d_write_value(client, W83781D_REG_IN_MIN(7), + IN_TO_REG(W83781D_INIT_IN_MIN_7)); + w83781d_write_value(client, W83781D_REG_IN_MAX(7), + IN_TO_REG(W83781D_INIT_IN_MAX_7)); + w83781d_write_value(client, W83781D_REG_IN_MIN(8), + IN_TO_REG(W83781D_INIT_IN_MIN_8)); + w83781d_write_value(client, W83781D_REG_IN_MAX(8), + IN_TO_REG(W83781D_INIT_IN_MAX_8)); + w83781d_write_value(client, W83781D_REG_VBAT, + (w83781d_read_value + (client, + W83781D_REG_VBAT) | 0x01)); + } + w83781d_write_value(client, W83781D_REG_FAN_MIN(1), + FAN_TO_REG(W83781D_INIT_FAN_MIN_1, 2)); + w83781d_write_value(client, W83781D_REG_FAN_MIN(2), + FAN_TO_REG(W83781D_INIT_FAN_MIN_2, 2)); + if (type != w83697hf) { + w83781d_write_value(client, W83781D_REG_FAN_MIN(3), + FAN_TO_REG(W83781D_INIT_FAN_MIN_3, + 2)); + } + + w83781d_write_value(client, W83781D_REG_TEMP_OVER(1), + TEMP_TO_REG(W83781D_INIT_TEMP_OVER)); + w83781d_write_value(client, W83781D_REG_TEMP_HYST(1), + TEMP_TO_REG(W83781D_INIT_TEMP_HYST)); + + if (type == as99127f) { + w83781d_write_value(client, W83781D_REG_TEMP_OVER(2), + AS99127_TEMP_ADD_TO_REG + (W83781D_INIT_TEMP2_OVER)); + w83781d_write_value(client, W83781D_REG_TEMP_HYST(2), + AS99127_TEMP_ADD_TO_REG + (W83781D_INIT_TEMP2_HYST)); + } else { + w83781d_write_value(client, W83781D_REG_TEMP_OVER(2), + TEMP_ADD_TO_REG + (W83781D_INIT_TEMP2_OVER)); + w83781d_write_value(client, W83781D_REG_TEMP_HYST(2), + TEMP_ADD_TO_REG + (W83781D_INIT_TEMP2_HYST)); + } + w83781d_write_value(client, W83781D_REG_TEMP2_CONFIG, 0x00); + + if (type == as99127f) { + w83781d_write_value(client, W83781D_REG_TEMP_OVER(3), + AS99127_TEMP_ADD_TO_REG + (W83781D_INIT_TEMP3_OVER)); + w83781d_write_value(client, W83781D_REG_TEMP_HYST(3), + AS99127_TEMP_ADD_TO_REG + (W83781D_INIT_TEMP3_HYST)); + } else if (type != w83783s && type != w83697hf) { + w83781d_write_value(client, W83781D_REG_TEMP_OVER(3), + TEMP_ADD_TO_REG + (W83781D_INIT_TEMP3_OVER)); + w83781d_write_value(client, W83781D_REG_TEMP_HYST(3), + TEMP_ADD_TO_REG + (W83781D_INIT_TEMP3_HYST)); + } + if (type != w83783s && type != w83697hf) { + w83781d_write_value(client, W83781D_REG_TEMP3_CONFIG, + 0x00); + } + if (type != w83781d) { + /* enable comparator mode for temp2 and temp3 so + alarm indication will work correctly */ + w83781d_write_value(client, W83781D_REG_IRQ, 0x41); + for (i = 0; i < 3; i++) + data->pwmenable[i] = 1; + } + } + + /* Start monitoring */ + w83781d_write_value(client, W83781D_REG_CONFIG, + (w83781d_read_value(client, + W83781D_REG_CONFIG) & 0xf7) + | 0x01); +} + +static void +w83781d_update_client(struct i2c_client *client) +{ + struct w83781d_data *data = i2c_get_clientdata(client); + int i; + + down(&data->update_lock); + + if (time_after + (jiffies - data->last_updated, (unsigned long) (HZ + HZ / 2)) + || time_before(jiffies, data->last_updated) || !data->valid) { + pr_debug(KERN_DEBUG "Starting device update\n"); + + for (i = 0; i <= 8; i++) { + if ((data->type == w83783s || data->type == w83697hf) + && (i == 1)) + continue; /* 783S has no in1 */ + data->in[i] = + w83781d_read_value(client, W83781D_REG_IN(i)); + data->in_min[i] = + w83781d_read_value(client, W83781D_REG_IN_MIN(i)); + data->in_max[i] = + w83781d_read_value(client, W83781D_REG_IN_MAX(i)); + if ((data->type != w83782d) && (data->type != w83697hf) + && (data->type != w83627hf) && (i == 6)) + break; + } + for (i = 1; i <= 3; i++) { + data->fan[i - 1] = + w83781d_read_value(client, W83781D_REG_FAN(i)); + data->fan_min[i - 1] = + w83781d_read_value(client, W83781D_REG_FAN_MIN(i)); + } + if (data->type != w83781d) { + for (i = 1; i <= 4; i++) { + data->pwm[i - 1] = + w83781d_read_value(client, + W83781D_REG_PWM(i)); + if (((data->type == w83783s) + || (data->type == w83627hf) + || (data->type == as99127f) + || (data->type == w83697hf) + || ((data->type == w83782d) + && i2c_is_isa_client(client))) + && i == 2) + break; + } + } + + data->temp = w83781d_read_value(client, W83781D_REG_TEMP(1)); + data->temp_min = + w83781d_read_value(client, W83781D_REG_TEMP_OVER(1)); + data->temp_max = + w83781d_read_value(client, W83781D_REG_TEMP_HYST(1)); + data->temp_add[0] = + w83781d_read_value(client, W83781D_REG_TEMP(2)); + data->temp_max_add[0] = + w83781d_read_value(client, W83781D_REG_TEMP_OVER(2)); + data->temp_min_add[0] = + w83781d_read_value(client, W83781D_REG_TEMP_HYST(2)); + if (data->type != w83783s && data->type != w83697hf) { + data->temp_add[1] = + w83781d_read_value(client, W83781D_REG_TEMP(3)); + data->temp_max_add[1] = + w83781d_read_value(client, + W83781D_REG_TEMP_OVER(3)); + data->temp_min_add[1] = + w83781d_read_value(client, + W83781D_REG_TEMP_HYST(3)); + } + i = w83781d_read_value(client, W83781D_REG_VID_FANDIV); + if (data->type != w83697hf) { + data->vid = i & 0x0f; + data->vid |= + (w83781d_read_value(client, W83781D_REG_CHIPID) & + 0x01) + << 4; + } + data->fan_div[0] = (i >> 4) & 0x03; + data->fan_div[1] = (i >> 6) & 0x03; + if (data->type != w83697hf) { + data->fan_div[2] = (w83781d_read_value(client, + W83781D_REG_PIN) + >> 6) & 0x03; + } + if ((data->type != w83781d) && (data->type != as99127f)) { + i = w83781d_read_value(client, W83781D_REG_VBAT); + data->fan_div[0] |= (i >> 3) & 0x04; + data->fan_div[1] |= (i >> 4) & 0x04; + if (data->type != w83697hf) + data->fan_div[2] |= (i >> 5) & 0x04; + } + data->alarms = + w83781d_read_value(client, + W83781D_REG_ALARM1) + + (w83781d_read_value(client, W83781D_REG_ALARM2) << 8); + if ((data->type == w83782d) || (data->type == w83627hf)) { + data->alarms |= + w83781d_read_value(client, + W83781D_REG_ALARM3) << 16; + } + i = w83781d_read_value(client, W83781D_REG_BEEP_INTS2); + data->beep_enable = i >> 7; + data->beep_mask = ((i & 0x7f) << 8) + + w83781d_read_value(client, W83781D_REG_BEEP_INTS1); + if ((data->type != w83781d) && (data->type != as99127f)) { + data->beep_mask |= + w83781d_read_value(client, + W83781D_REG_BEEP_INTS3) << 16; + } + data->last_updated = jiffies; + data->valid = 1; + } + + up(&data->update_lock); +} + +static int __init +sensors_w83781d_init(void) +{ + return i2c_add_driver(&w83781d_driver); +} + +static void __exit +sensors_w83781d_exit(void) +{ + i2c_del_driver(&w83781d_driver); +} + +MODULE_AUTHOR("Frodo Looijaard , " + "Philip Edelbrock , " + "and Mark Studebaker "); +MODULE_DESCRIPTION("W83781D driver"); +MODULE_LICENSE("GPL"); + +module_init(sensors_w83781d_init); +module_exit(sensors_w83781d_exit); diff -Nru a/drivers/i2c/i2c-algo-bit.c b/drivers/i2c/i2c-algo-bit.c --- a/drivers/i2c/i2c-algo-bit.c Wed Apr 2 22:24:05 2003 +++ b/drivers/i2c/i2c-algo-bit.c Wed Apr 2 22:24:05 2003 @@ -23,6 +23,8 @@ /* $Id: i2c-algo-bit.c,v 1.44 2003/01/21 08:08:16 kmalkki Exp $ */ +/* #define DEBUG 1 */ + #include #include #include @@ -338,16 +340,14 @@ while (count > 0) { c = *temp; - DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: %s sendbytes: writing %2.2X\n", - i2c_adap->name, c&0xff)); + DEB2(dev_dbg(&i2c_adap->dev, "sendbytes: writing %2.2X\n", c&0xff)); retval = i2c_outb(i2c_adap,c); if ((retval>0) || (nak_ok && (retval==0))) { /* ok or ignored NAK */ count--; temp++; wrcount++; } else { /* arbitration or no acknowledge */ - printk(KERN_ERR "i2c-algo-bit.o: %s sendbytes: error - bailout.\n", - i2c_adap->name); + dev_err(&i2c_adap->dev, "sendbytes: error - bailout.\n"); i2c_stop(adap); return (retval<0)? retval : -EFAULT; /* got a better one ?? */ @@ -527,13 +527,12 @@ struct i2c_algo_bit_data *bit_adap = adap->algo_data; if (bit_test) { - int ret = test_bus(bit_adap, adap->name); + int ret = test_bus(bit_adap, adap->dev.name); if (ret<0) return -ENODEV; } - DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: hw routines for %s registered.\n", - adap->name)); + DEB2(dev_dbg(&adap->dev, "hw routines registered.\n")); /* register new adapter to i2c module... */ diff -Nru a/drivers/i2c/i2c-algo-pcf.c b/drivers/i2c/i2c-algo-pcf.c --- a/drivers/i2c/i2c-algo-pcf.c Wed Apr 2 22:24:07 2003 +++ b/drivers/i2c/i2c-algo-pcf.c Wed Apr 2 22:24:07 2003 @@ -27,6 +27,8 @@ messages, proper stop/repstart signaling during receive, added detect code */ +/* #define DEBUG 1 */ /* to pick up dev_dbg calls */ + #include #include #include @@ -222,21 +224,19 @@ int wrcount, status, timeout; for (wrcount=0; wrcountname, buf[wrcount]&0xff)); + DEB2(dev_dbg(&i2c_adap->dev, "i2c_write: writing %2.2X\n", + buf[wrcount]&0xff)); i2c_outb(adap, buf[wrcount]); timeout = wait_for_pin(adap, &status); if (timeout) { i2c_stop(adap); - printk(KERN_ERR "i2c-algo-pcf.o: %s i2c_write: " - "error - timeout.\n", i2c_adap->name); + dev_err(&i2c_adap->dev, "i2c_write: error - timeout.\n"); return -EREMOTEIO; /* got a better one ?? */ } #ifndef STUB_I2C if (status & I2C_PCF_LRB) { i2c_stop(adap); - printk(KERN_ERR "i2c-algo-pcf.o: %s i2c_write: " - "error - no ack.\n", i2c_adap->name); + dev_err(&i2c_adap->dev, "i2c_write: error - no ack.\n"); return -EREMOTEIO; /* got a better one ?? */ } #endif @@ -263,14 +263,14 @@ if (wait_for_pin(adap, &status)) { i2c_stop(adap); - printk(KERN_ERR "i2c-algo-pcf.o: pcf_readbytes timed out.\n"); + dev_err(&i2c_adap->dev, "pcf_readbytes timed out.\n"); return (-1); } #ifndef STUB_I2C if ((status & I2C_PCF_LRB) && (i != count)) { i2c_stop(adap); - printk(KERN_ERR "i2c-algo-pcf.o: i2c_read: i2c_inb, No ack.\n"); + dev_err(&i2c_adap->dev, "i2c_read: i2c_inb, No ack.\n"); return (-1); } #endif @@ -445,8 +445,7 @@ struct i2c_algo_pcf_data *pcf_adap = adap->algo_data; int rval; - DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: hw routines for %s registered.\n", - adap->name)); + DEB2(dev_dbg(&adap->dev, "hw routines registered.\n")); /* register new adapter to i2c module... */ diff -Nru a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c --- a/drivers/i2c/i2c-core.c Wed Apr 2 22:24:04 2003 +++ b/drivers/i2c/i2c-core.c Wed Apr 2 22:24:04 2003 @@ -23,11 +23,12 @@ /* $Id: i2c-core.c,v 1.95 2003/01/22 05:25:08 kmalkki Exp $ */ +/* #define DEBUG 1 */ /* needed to pick up the dev_dbg() calls */ + #include #include #include #include -#include #include #include #include @@ -44,15 +45,6 @@ /**** debug level */ static int i2c_debug; -#ifdef CONFIG_PROC_FS -static int i2cproc_register(struct i2c_adapter *adap, int bus); -static void i2cproc_remove(int bus); -#else -# define i2cproc_register(adap, bus) 0 -# define i2cproc_remove(bus) do { } while (0) -#endif /* CONFIG_PROC_FS */ - - int i2c_device_probe(struct device *dev) { return -ENODEV; @@ -63,6 +55,14 @@ return 0; } +static struct device_driver i2c_generic_driver = { + .name = "i2c", + .bus = &i2c_bus_type, + .probe = i2c_device_probe, + .remove = i2c_device_remove, +}; + + /* --------------------------------------------------- * registering functions * --------------------------------------------------- @@ -82,17 +82,12 @@ if (NULL == adapters[i]) break; if (I2C_ADAP_MAX == i) { - printk(KERN_WARNING - " i2c-core.o: register_adapter(%s) - enlarge I2C_ADAP_MAX.\n", - adap->name); + dev_warn(&adap->dev, + "register_adapter - enlarge I2C_ADAP_MAX.\n"); res = -ENOMEM; goto out_unlock; } - res = i2cproc_register(adap, i); - if (res) - goto out_unlock; - adapters[i] = adap; init_MUTEX(&adap->bus); @@ -105,7 +100,7 @@ if (adap->dev.parent == NULL) adap->dev.parent = &legacy_bus; sprintf(adap->dev.bus_id, "i2c-%d", i); - strcpy(adap->dev.name, "i2c controller"); + adap->dev.driver = &i2c_generic_driver; device_register(&adap->dev); /* inform drivers of new adapters */ @@ -116,8 +111,7 @@ drivers[j]->attach_adapter(adap); up(&core_lists); - DEB(printk(KERN_DEBUG "i2c-core.o: adapter %s registered as adapter %d.\n", - adap->name,i)); + DEB(dev_dbg(&adap->dev, "registered as adapter %d.\n", i)); out_unlock: up(&core_lists); @@ -134,8 +128,7 @@ if (adap == adapters[i]) break; if (I2C_ADAP_MAX == i) { - printk( KERN_WARNING "i2c-core.o: unregister_adapter adap [%s] not found.\n", - adap->name); + dev_warn(&adap->dev, "unregister_adapter adap not found.\n"); res = -ENODEV; goto out_unlock; } @@ -148,9 +141,9 @@ for (j = 0; j < I2C_DRIVER_MAX; j++) if (drivers[j] && (drivers[j]->flags & I2C_DF_DUMMY)) if ((res = drivers[j]->attach_adapter(adap))) { - printk(KERN_WARNING "i2c-core.o: can't detach adapter %s " + dev_warn(&adap->dev, "can't detach adapter" "while detaching driver %s: driver not " - "detached!",adap->name,drivers[j]->name); + "detached!", drivers[j]->name); goto out_unlock; } @@ -164,23 +157,21 @@ * must be deleted, as this would cause invalid states. */ if ((res=client->driver->detach_client(client))) { - printk(KERN_ERR "i2c-core.o: adapter %s not " + dev_err(&adap->dev, "adapter not " "unregistered, because client at " "address %02x can't be detached. ", - adap->name, client->addr); + client->addr); goto out_unlock; } } } - i2cproc_remove(i); - /* clean up the sysfs representation */ device_unregister(&adap->dev); adapters[i] = NULL; - DEB(printk(KERN_DEBUG "i2c-core.o: adapter unregistered: %s\n",adap->name)); + DEB(dev_dbg(&adap->dev, "adapter unregistered\n")); out_unlock: up(&core_lists); @@ -272,8 +263,7 @@ struct i2c_adapter *adap = adapters[k]; if (adap == NULL) /* skip empty entries. */ continue; - DEB2(printk(KERN_DEBUG "i2c-core.o: examining adapter %s:\n", - adap->name)); + DEB2(dev_dbg(&adap->dev, "examining adapter\n")); if (driver->flags & I2C_DF_DUMMY) { /* DUMMY drivers do not register their clients, so we have to * use a trick here: we call driver->attach_adapter to @@ -281,11 +271,10 @@ * this or hell will break loose... */ if ((res = driver->attach_adapter(adap))) { - printk(KERN_WARNING "i2c-core.o: while unregistering " - "dummy driver %s, adapter %s could " + dev_warn(&adap->dev, "while unregistering " + "dummy driver %s, adapter could " "not be detached properly; driver " - "not unloaded!",driver->name, - adap->name); + "not unloaded!",driver->name); goto out_unlock; } } else { @@ -295,20 +284,17 @@ client->driver == driver) { DEB2(printk(KERN_DEBUG "i2c-core.o: " "detaching client %s:\n", - client->name)); - if ((res = driver-> - detach_client(client))) - { - printk(KERN_ERR "i2c-core.o: while " + client->dev.name)); + if ((res = driver->detach_client(client))) { + dev_err(&adap->dev, "while " "unregistering driver " "`%s', the client at " "address %02x of " - "adapter `%s' could not " + "adapter could not " "be detached; driver " "not unloaded!", driver->name, - client->addr, - adap->name); + client->addr); goto out_unlock; } } @@ -362,7 +348,7 @@ printk(KERN_WARNING " i2c-core.o: attach_client(%s) - enlarge I2C_CLIENT_MAX.\n", - client->name); + client->dev.name); out_unlock_list: up(&adapter->list); @@ -374,19 +360,27 @@ if (adapter->client_register) { if (adapter->client_register(client)) { - printk(KERN_DEBUG - "i2c-core.o: warning: client_register seems " - "to have failed for client %02x at adapter %s\n", - client->addr, adapter->name); + dev_warn(&adapter->dev, "warning: client_register " + "seems to have failed for client %02x\n", + client->addr); } } - DEB(printk(KERN_DEBUG - "i2c-core.o: client [%s] registered to adapter [%s] " - "(pos. %d).\n", client->name, adapter->name, i)); + DEB(dev_dbg(&adapter->dev, "client [%s] registered to adapter " + "(pos. %d).\n", client->dev.name, i)); if (client->flags & I2C_CLIENT_ALLOW_USE) client->usage_count = 0; + + client->dev.parent = &client->adapter->dev; + client->dev.driver = &client->driver->driver; + client->dev.bus = &i2c_bus_type; + + snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id), + "%d-%04x", i2c_adapter_id(adapter), client->addr); + printk("registering %s\n", client->dev.bus_id); + device_register(&client->dev); + return 0; } @@ -404,7 +398,7 @@ if (res) { printk(KERN_ERR "i2c-core.o: client_unregister [%s] failed, " - "client not detached", client->name); + "client not detached", client->dev.name); goto out; } } @@ -419,10 +413,11 @@ printk(KERN_WARNING " i2c-core.o: unregister_client [%s] not found\n", - client->name); + client->dev.name); res = -ENODEV; out_unlock: + device_unregister(&client->dev); up(&adapter->list); out: return res; @@ -484,173 +479,6 @@ return 0; } -#ifdef CONFIG_PROC_FS -/* This function generates the output for /proc/bus/i2c-? */ -static ssize_t i2cproc_bus_read(struct file *file, char *buf, - size_t count, loff_t *ppos) -{ - struct inode *inode = file->f_dentry->d_inode; - char *kbuf; - struct i2c_client *client; - int i,j,k,order_nr,len=0; - size_t len_total; - int order[I2C_CLIENT_MAX]; -#define OUTPUT_LENGTH_PER_LINE 70 - - len_total = file->f_pos + count; - if (len_total > (I2C_CLIENT_MAX * OUTPUT_LENGTH_PER_LINE) ) - /* adjust to maximum file size */ - len_total = (I2C_CLIENT_MAX * OUTPUT_LENGTH_PER_LINE); - for (i = 0; i < I2C_ADAP_MAX; i++) - if (adapters[i]->inode == inode->i_ino) { - /* We need a bit of slack in the kernel buffer; this makes the - sprintf safe. */ - if (! (kbuf = kmalloc(len_total + - OUTPUT_LENGTH_PER_LINE, - GFP_KERNEL))) - return -ENOMEM; - /* Order will hold the indexes of the clients - sorted by address */ - order_nr=0; - for (j = 0; j < I2C_CLIENT_MAX; j++) { - if ((client = adapters[i]->clients[j]) && - (client->driver->id != I2C_DRIVERID_I2CDEV)) { - for(k = order_nr; - (k > 0) && - adapters[i]->clients[order[k-1]]-> - addr > client->addr; - k--) - order[k] = order[k-1]; - order[k] = j; - order_nr++; - } - } - - - for (j = 0; (j < order_nr) && (len < len_total); j++) { - client = adapters[i]->clients[order[j]]; - len += sprintf(kbuf+len,"%02x\t%-32s\t%-32s\n", - client->addr, - client->name, - client->driver->name); - } - len = len - file->f_pos; - if (len > count) - len = count; - if (len < 0) - len = 0; - if (copy_to_user (buf,kbuf+file->f_pos, len)) { - kfree(kbuf); - return -EFAULT; - } - file->f_pos += len; - kfree(kbuf); - return len; - } - return -ENOENT; -} - -static struct file_operations i2cproc_operations = { - .read = i2cproc_bus_read, -}; - -/* This function generates the output for /proc/bus/i2c */ -static int bus_i2c_show(struct seq_file *s, void *p) -{ - int i; - - down(&core_lists); - for (i = 0; i < I2C_ADAP_MAX; i++) { - struct i2c_adapter *adapter = adapters[i]; - - if (!adapter) - continue; - - seq_printf(s, "i2c-%d\t", i); - - if (adapter->algo->smbus_xfer) { - if (adapter->algo->master_xfer) - seq_printf(s, "smbus/i2c"); - else - seq_printf(s, "smbus "); - } else if (adapter->algo->master_xfer) - seq_printf(s ,"i2c "); - else - seq_printf(s, "dummy "); - - seq_printf(s, "\t%-32s\t%-32s\n", - adapter->name, adapter->algo->name); - } - up(&core_lists); - - return 0; -} - -static int bus_i2c_open(struct inode *inode, struct file *file) -{ - return single_open(file, bus_i2c_show, NULL); -} - -static struct file_operations bus_i2c_fops = { - .open = bus_i2c_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - }; - -static int i2cproc_register(struct i2c_adapter *adap, int bus) -{ - struct proc_dir_entry *proc_entry; - char name[8]; - - sprintf(name, "i2c-%d", bus); - - proc_entry = create_proc_entry(name, 0, proc_bus); - if (!proc_entry) - goto fail; - - proc_entry->proc_fops = &i2cproc_operations; - proc_entry->owner = adap->owner; - adap->inode = proc_entry->low_ino; - return 0; - fail: - printk(KERN_ERR "i2c-core.o: Could not create /proc/bus/%s\n", name); - return -ENOENT; -} - -static void i2cproc_remove(int bus) -{ - char name[8]; - - sprintf(name,"i2c-%d", bus); - remove_proc_entry(name, proc_bus); -} - -static int __init i2cproc_init(void) -{ - struct proc_dir_entry *proc_bus_i2c; - - proc_bus_i2c = create_proc_entry("i2c", 0, proc_bus); - if (!proc_bus_i2c) - goto fail; - proc_bus_i2c->proc_fops = &bus_i2c_fops; - proc_bus_i2c->owner = THIS_MODULE; - return 0; - - fail: - printk(KERN_ERR "i2c-core.o: Could not create /proc/bus/i2c"); - return -ENOENT; -} - -static void __exit i2cproc_cleanup(void) -{ - remove_proc_entry("i2c",proc_bus); -} -#else -static int __init i2cproc_init(void) { return 0; } -static void __exit i2cproc_cleanup(void) { } -#endif /* CONFIG_PROC_FS */ - /* match always succeeds, as we want the probe() to tell if we really accept this match */ static int i2c_device_match(struct device *dev, struct device_driver *drv) { @@ -665,17 +493,15 @@ static int __init i2c_init(void) { - bus_register(&i2c_bus_type); - return i2cproc_init(); + return bus_register(&i2c_bus_type); } static void __exit i2c_exit(void) { - i2cproc_cleanup(); bus_unregister(&i2c_bus_type); } -module_init(i2c_init); +subsys_initcall(i2c_init); module_exit(i2c_exit); /* ---------------------------------------------------- @@ -688,8 +514,7 @@ int ret; if (adap->algo->master_xfer) { - DEB2(printk(KERN_DEBUG "i2c-core.o: master_xfer: %s with %d msgs.\n", - adap->name,num)); + DEB2(dev_dbg(&adap->dev, "master_xfer: with %d msgs.\n", num)); down(&adap->bus); ret = adap->algo->master_xfer(adap,msgs,num); @@ -697,8 +522,7 @@ return ret; } else { - printk(KERN_ERR "i2c-core.o: I2C adapter %04x: I2C level transfers not supported\n", - adap->id); + dev_err(&adap->dev, "I2C level transfers not supported\n"); return -ENOSYS; } } @@ -715,8 +539,8 @@ msg.len = count; (const char *)msg.buf = buf; - DEB2(printk(KERN_DEBUG "i2c-core.o: master_send: writing %d bytes on %s.\n", - count,client->adapter->name)); + DEB2(dev_dbg(&client->adapter->dev, "master_send: writing %d bytes.\n", + count)); down(&adap->bus); ret = adap->algo->master_xfer(adap,&msg,1); @@ -745,8 +569,8 @@ msg.len = count; msg.buf = buf; - DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: reading %d bytes on %s.\n", - count,client->adapter->name)); + DEB2(dev_dbg(&client->adapter->dev, "master_recv: reading %d bytes.\n", + count)); down(&adap->bus); ret = adap->algo->master_xfer(adap,&msg,1); diff -Nru a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c --- a/drivers/i2c/i2c-dev.c Wed Apr 2 22:24:07 2003 +++ b/drivers/i2c/i2c-dev.c Wed Apr 2 22:24:07 2003 @@ -30,6 +30,9 @@ /* $Id: i2c-dev.c,v 1.53 2003/01/21 08:08:16 kmalkki Exp $ */ +/* If you want debugging uncomment: */ +/* #define DEBUG 1 */ + #include #include #include @@ -41,10 +44,6 @@ #include #include -/* If you want debugging uncomment: */ -/* #define DEBUG */ - - /* struct file_operations changed too often in the 2.1 series for nice code */ static ssize_t i2cdev_read (struct file *file, char *buf, size_t count, @@ -87,7 +86,9 @@ }; static struct i2c_client i2cdev_client_template = { - .name = "I2C /dev entry", + .dev = { + .name = "I2C /dev entry", + }, .id = 1, .addr = -1, .driver = &i2cdev_driver, @@ -386,11 +387,11 @@ char name[12]; if ((i = i2c_adapter_id(adap)) < 0) { - printk(KERN_DEBUG "i2c-dev.o: Unknown adapter ?!?\n"); + dev_dbg(&adap->dev, "Unknown adapter ?!?\n"); return -ENODEV; } if (i >= I2CDEV_ADAPS_MAX) { - printk(KERN_DEBUG "i2c-dev.o: Adapter number too large?!? (%d)\n",i); + dev_dbg(&adap->dev, "Adapter number too large?!? (%d)\n",i); return -ENODEV; } @@ -401,14 +402,12 @@ DEVFS_FL_DEFAULT, I2C_MAJOR, i, S_IFCHR | S_IRUSR | S_IWUSR, &i2cdev_fops, NULL); - printk(KERN_DEBUG "i2c-dev.o: Registered '%s' as minor %d\n",adap->name,i); + dev_dbg(&adap->dev, "Registered as minor %d\n", i); } else { /* This is actually a detach_adapter call! */ devfs_remove("i2c/%d", i); i2cdev_adaps[i] = NULL; -#ifdef DEBUG - printk(KERN_DEBUG "i2c-dev.o: Adapter unregistered: %s\n",adap->name); -#endif + dev_dbg(&adap->dev, "Adapter unregistered\n"); } return 0; diff -Nru a/drivers/i2c/i2c-elektor.c b/drivers/i2c/i2c-elektor.c --- a/drivers/i2c/i2c-elektor.c Wed Apr 2 22:24:04 2003 +++ b/drivers/i2c/i2c-elektor.c Wed Apr 2 22:24:04 2003 @@ -174,10 +174,12 @@ }; static struct i2c_adapter pcf_isa_ops = { - .owner = THIS_MODULE, - .name = "PCF8584 ISA adapter", - .id = I2C_HW_P_ELEK, - .algo_data = &pcf_isa_data, + .owner = THIS_MODULE, + .id = I2C_HW_P_ELEK, + .algo_data = &pcf_isa_data, + .dev = { + .name = "PCF8584 ISA adapter", + }, }; static int __init i2c_pcfisa_init(void) diff -Nru a/drivers/i2c/i2c-elv.c b/drivers/i2c/i2c-elv.c --- a/drivers/i2c/i2c-elv.c Wed Apr 2 22:24:07 2003 +++ b/drivers/i2c/i2c-elv.c Wed Apr 2 22:24:07 2003 @@ -129,9 +129,11 @@ static struct i2c_adapter bit_elv_ops = { .owner = THIS_MODULE, - .name = "ELV Parallel port adaptor", .id = I2C_HW_B_ELV, .algo_data = &bit_elv_data, + .dev = { + .name = "ELV Parallel port adaptor", + }, }; static int __init i2c_bitelv_init(void) @@ -148,7 +150,7 @@ return -ENODEV; } } else { - bit_elv_ops.data=(void*)base; + i2c_set_adapdata(&bit_elv_ops, (void *)base); if (bit_elv_init()==0) { if(i2c_bit_add_bus(&bit_elv_ops) < 0) return -ENODEV; diff -Nru a/drivers/i2c/i2c-philips-par.c b/drivers/i2c/i2c-philips-par.c --- a/drivers/i2c/i2c-philips-par.c Wed Apr 2 22:24:04 2003 +++ b/drivers/i2c/i2c-philips-par.c Wed Apr 2 22:24:04 2003 @@ -151,8 +151,10 @@ static struct i2c_adapter bit_lp_ops = { .owner = THIS_MODULE, - .name = "Philips Parallel port adapter", .id = I2C_HW_B_LP, + .dev = { + .name = "Philips Parallel port adapter", + }, }; static void i2c_parport_attach (struct parport *port) diff -Nru a/drivers/i2c/i2c-proc.c b/drivers/i2c/i2c-proc.c --- a/drivers/i2c/i2c-proc.c Wed Apr 2 22:24:05 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,819 +0,0 @@ -/* - i2c-proc.c - Part of lm_sensors, Linux kernel modules for hardware - monitoring - Copyright (c) 1998 - 2001 Frodo Looijaard and - Mark D. Studebaker - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - This driver puts entries in /proc/sys/dev/sensors for each I2C device -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int i2c_parse_reals(int *nrels, void *buffer, int bufsize, - long *results, int magnitude); -static int i2c_write_reals(int nrels, void *buffer, size_t *bufsize, - long *results, int magnitude); -static int i2c_proc_chips(ctl_table * ctl, int write, - struct file *filp, void *buffer, - size_t * lenp); -static int i2c_sysctl_chips(ctl_table * table, int *name, int nlen, - void *oldval, size_t * oldlenp, - void *newval, size_t newlen, - void **context); - -#define SENSORS_ENTRY_MAX 20 -static struct ctl_table_header *i2c_entries[SENSORS_ENTRY_MAX]; - -static struct i2c_client *i2c_clients[SENSORS_ENTRY_MAX]; - -static ctl_table i2c_proc_dev_sensors[] = { - {SENSORS_CHIPS, "chips", NULL, 0, 0644, NULL, &i2c_proc_chips, - &i2c_sysctl_chips}, - {0} -}; - -static ctl_table i2c_proc_dev[] = { - {DEV_SENSORS, "sensors", NULL, 0, 0555, i2c_proc_dev_sensors}, - {0}, -}; - - -static ctl_table i2c_proc[] = { - {CTL_DEV, "dev", NULL, 0, 0555, i2c_proc_dev}, - {0} -}; - - -static struct ctl_table_header *i2c_proc_header; - -/* This returns a nice name for a new directory; for example lm78-isa-0310 - (for a LM78 chip on the ISA bus at port 0x310), or lm75-i2c-3-4e (for - a LM75 chip on the third i2c bus at address 0x4e). - name is allocated first. */ -static char *generate_name(struct i2c_client *client, const char *prefix) -{ - struct i2c_adapter *adapter = client->adapter; - int addr = client->addr; - char name_buffer[50], *name; - - if (i2c_is_isa_adapter(adapter)) { - sprintf(name_buffer, "%s-isa-%04x", prefix, addr); - } else if (adapter->algo->smbus_xfer || adapter->algo->master_xfer) { - int id = i2c_adapter_id(adapter); - if (id < 0) - return ERR_PTR(-ENOENT); - sprintf(name_buffer, "%s-i2c-%d-%02x", prefix, id, addr); - } else { /* dummy adapter, generate prefix */ - int end, i; - - sprintf(name_buffer, "%s-", prefix); - end = strlen(name_buffer); - - for (i = 0; i < 32; i++) { - if (adapter->algo->name[i] == ' ') - break; - name_buffer[end++] = tolower(adapter->algo->name[i]); - } - - name_buffer[end] = 0; - sprintf(name_buffer + end, "-%04x", addr); - } - - name = kmalloc(strlen(name_buffer) + 1, GFP_KERNEL); - if (unlikely(!name)) - return ERR_PTR(-ENOMEM); - strcpy(name, name_buffer); - return name; -} - -/* This rather complex function must be called when you want to add an entry - to /proc/sys/dev/sensors/chips. It also creates a new directory within - /proc/sys/dev/sensors/. - ctl_template should be a template of the newly created directory. It is - copied in memory. The extra2 field of each file is set to point to client. - If any driver wants subdirectories within the newly created directory, - this function must be updated! */ -int i2c_register_entry(struct i2c_client *client, const char *prefix, - struct ctl_table *leaf) -{ - struct { struct ctl_table root[2], dev[2], sensors[2]; } *tbl; - struct ctl_table_header *hdr; - struct ctl_table *tmp; - const char *name; - int id; - - name = generate_name(client, prefix); - if (IS_ERR(name)) - return PTR_ERR(name); - - for (id = 0; id < SENSORS_ENTRY_MAX; id++) { - if (!i2c_entries[id]) - goto free_slot; - } - - goto out_free_name; - - free_slot: - tbl = kmalloc(sizeof(*tbl), GFP_KERNEL); - if (unlikely(!tbl)) - goto out_free_name; - memset(tbl, 0, sizeof(*tbl)); - - for (tmp = leaf; tmp->ctl_name; tmp++) - tmp->extra2 = client; - - tbl->sensors->ctl_name = id+256; - tbl->sensors->procname = name; - tbl->sensors->mode = 0555; - tbl->sensors->child = leaf; - - tbl->dev->ctl_name = DEV_SENSORS; - tbl->dev->procname = "sensors"; - tbl->dev->mode = 0555; - tbl->dev->child = tbl->sensors; - - tbl->root->ctl_name = CTL_DEV; - tbl->root->procname = "dev"; - tbl->root->mode = 0555; - tbl->root->child = tbl->dev; - - hdr = register_sysctl_table(tbl->root, 0); - if (unlikely(!hdr)) - goto out_free_tbl; - - i2c_entries[id] = hdr; - i2c_clients[id] = client; - - return (id + 256); /* XXX(hch) why?? */ - - out_free_tbl: - kfree(tbl); - out_free_name: - kfree(name); - return -ENOMEM; -} - -void i2c_deregister_entry(int id) -{ - id -= 256; - - if (i2c_entries[id]) { - struct ctl_table_header *hdr = i2c_entries[id]; - struct ctl_table *tbl = hdr->ctl_table; - - unregister_sysctl_table(hdr); - kfree(tbl->child->child->procname); - kfree(tbl); /* actually the whole anonymous struct */ - } - - i2c_entries[id] = NULL; - i2c_clients[id] = NULL; -} - -static int i2c_proc_chips(ctl_table * ctl, int write, struct file *filp, - void *buffer, size_t * lenp) -{ - char BUF[SENSORS_PREFIX_MAX + 30]; - int buflen, curbufsize, i; - struct ctl_table *client_tbl; - - if (write) - return 0; - - /* If buffer is size 0, or we try to read when not at the start, we - return nothing. Note that I think writing when not at the start - does not work either, but anyway, this is straight from the kernel - sources. */ - if (!*lenp || (filp->f_pos && !write)) { - *lenp = 0; - return 0; - } - curbufsize = 0; - for (i = 0; i < SENSORS_ENTRY_MAX; i++) - if (i2c_entries[i]) { - client_tbl = - i2c_entries[i]->ctl_table->child->child; - buflen = - sprintf(BUF, "%d\t%s\n", client_tbl->ctl_name, - client_tbl->procname); - if (buflen + curbufsize > *lenp) - buflen = *lenp - curbufsize; - if(copy_to_user(buffer, BUF, buflen)) - return -EFAULT; - curbufsize += buflen; - (char *) buffer += buflen; - } - *lenp = curbufsize; - filp->f_pos += curbufsize; - return 0; -} - -static int i2c_sysctl_chips(ctl_table * table, int *name, int nlen, - void *oldval, size_t * oldlenp, void *newval, - size_t newlen, void **context) -{ - struct i2c_chips_data data; - int i, oldlen, nrels, maxels,ret=0; - struct ctl_table *client_tbl; - - if (oldval && oldlenp && !((ret = get_user(oldlen, oldlenp))) && - oldlen) { - maxels = oldlen / sizeof(struct i2c_chips_data); - nrels = 0; - for (i = 0; (i < SENSORS_ENTRY_MAX) && (nrels < maxels); - i++) - if (i2c_entries[i]) { - client_tbl = - i2c_entries[i]->ctl_table->child-> - child; - data.sysctl_id = client_tbl->ctl_name; - strcpy(data.name, client_tbl->procname); - if(copy_to_user(oldval, &data, - sizeof(struct - i2c_chips_data))) - return -EFAULT; - (char *) oldval += - sizeof(struct i2c_chips_data); - nrels++; - } - oldlen = nrels * sizeof(struct i2c_chips_data); - if(put_user(oldlen, oldlenp)) - return -EFAULT; - } - return ret; -} - - -/* This function reads or writes a 'real' value (encoded by the combination - of an integer and a magnitude, the last is the power of ten the value - should be divided with) to a /proc/sys directory. To use this function, - you must (before registering the ctl_table) set the extra2 field to the - client, and the extra1 field to a function of the form: - void func(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) - This function can be called for three values of operation. If operation - equals SENSORS_PROC_REAL_INFO, the magnitude should be returned in - nrels_mag. If operation equals SENSORS_PROC_REAL_READ, values should - be read into results. nrels_mag should return the number of elements - read; the maximum number is put in it on entry. Finally, if operation - equals SENSORS_PROC_REAL_WRITE, the values in results should be - written to the chip. nrels_mag contains on entry the number of elements - found. - In all cases, client points to the client we wish to interact with, - and ctl_name is the SYSCTL id of the file we are accessing. */ -int i2c_proc_real(ctl_table * ctl, int write, struct file *filp, - void *buffer, size_t * lenp) -{ -#define MAX_RESULTS 32 - int mag, nrels = MAX_RESULTS; - long results[MAX_RESULTS]; - i2c_real_callback callback = ctl->extra1; - struct i2c_client *client = ctl->extra2; - int res; - - /* If buffer is size 0, or we try to read when not at the start, we - return nothing. Note that I think writing when not at the start - does not work either, but anyway, this is straight from the kernel - sources. */ - if (!*lenp || (filp->f_pos && !write)) { - *lenp = 0; - return 0; - } - - /* Get the magnitude */ - callback(client, SENSORS_PROC_REAL_INFO, ctl->ctl_name, &mag, - NULL); - - if (write) { - /* Read the complete input into results, converting to longs */ - res = i2c_parse_reals(&nrels, buffer, *lenp, results, mag); - if (res) - return res; - - if (!nrels) - return 0; - - /* Now feed this information back to the client */ - callback(client, SENSORS_PROC_REAL_WRITE, ctl->ctl_name, - &nrels, results); - - filp->f_pos += *lenp; - return 0; - } else { /* read */ - /* Get the information from the client into results */ - callback(client, SENSORS_PROC_REAL_READ, ctl->ctl_name, - &nrels, results); - - /* And write them to buffer, converting to reals */ - res = i2c_write_reals(nrels, buffer, lenp, results, mag); - if (res) - return res; - filp->f_pos += *lenp; - return 0; - } -} - -/* This function is equivalent to i2c_proc_real, only it interacts with - the sysctl(2) syscall, and returns no reals, but integers */ -int i2c_sysctl_real(ctl_table * table, int *name, int nlen, - void *oldval, size_t * oldlenp, void *newval, - size_t newlen, void **context) -{ - long results[MAX_RESULTS]; - int oldlen, nrels = MAX_RESULTS,ret=0; - i2c_real_callback callback = table->extra1; - struct i2c_client *client = table->extra2; - - /* Check if we need to output the old values */ - if (oldval && oldlenp && !((ret=get_user(oldlen, oldlenp))) && oldlen) { - callback(client, SENSORS_PROC_REAL_READ, table->ctl_name, - &nrels, results); - - /* Note the rounding factor! */ - if (nrels * sizeof(long) < oldlen) - oldlen = nrels * sizeof(long); - oldlen = (oldlen / sizeof(long)) * sizeof(long); - if(copy_to_user(oldval, results, oldlen)) - return -EFAULT; - if(put_user(oldlen, oldlenp)) - return -EFAULT; - } - - if (newval && newlen) { - /* Note the rounding factor! */ - newlen -= newlen % sizeof(long); - nrels = newlen / sizeof(long); - if(copy_from_user(results, newval, newlen)) - return -EFAULT; - - /* Get the new values back to the client */ - callback(client, SENSORS_PROC_REAL_WRITE, table->ctl_name, - &nrels, results); - } - return ret; -} - - -/* nrels contains initially the maximum number of elements which can be - put in results, and finally the number of elements actually put there. - A magnitude of 1 will multiply everything with 10; etc. - buffer, bufsize is the character buffer we read from and its length. - results will finally contain the parsed integers. - - Buffer should contain several reals, separated by whitespace. A real - has the following syntax: - [ Minus ] Digit* [ Dot Digit* ] - (everything between [] is optional; * means zero or more). - When the next character is unparsable, everything is skipped until the - next whitespace. - - WARNING! This is tricky code. I have tested it, but there may still be - hidden bugs in it, even leading to crashes and things! -*/ -static int i2c_parse_reals(int *nrels, void *buffer, int bufsize, - long *results, int magnitude) -{ - int maxels, min, mag; - long res,ret=0; - char nextchar = 0; - - maxels = *nrels; - *nrels = 0; - - while (bufsize && (*nrels < maxels)) { - - /* Skip spaces at the start */ - while (bufsize && - !((ret=get_user(nextchar, (char *) buffer))) && - isspace((int) nextchar)) { - bufsize--; - ((char *) buffer)++; - } - - if (ret) - return -EFAULT; - /* Well, we may be done now */ - if (!bufsize) - return 0; - - /* New defaults for our result */ - min = 0; - res = 0; - mag = magnitude; - - /* Check for a minus */ - if (!((ret=get_user(nextchar, (char *) buffer))) - && (nextchar == '-')) { - min = 1; - bufsize--; - ((char *) buffer)++; - } - if (ret) - return -EFAULT; - - /* Digits before a decimal dot */ - while (bufsize && - !((ret=get_user(nextchar, (char *) buffer))) && - isdigit((int) nextchar)) { - res = res * 10 + nextchar - '0'; - bufsize--; - ((char *) buffer)++; - } - if (ret) - return -EFAULT; - - /* If mag < 0, we must actually divide here! */ - while (mag < 0) { - res = res / 10; - mag++; - } - - if (bufsize && (nextchar == '.')) { - /* Skip the dot */ - bufsize--; - ((char *) buffer)++; - - /* Read digits while they are significant */ - while (bufsize && (mag > 0) && - !((ret=get_user(nextchar, (char *) buffer))) && - isdigit((int) nextchar)) { - res = res * 10 + nextchar - '0'; - mag--; - bufsize--; - ((char *) buffer)++; - } - if (ret) - return -EFAULT; - } - /* If we are out of data, but mag > 0, we need to scale here */ - while (mag > 0) { - res = res * 10; - mag--; - } - - /* Skip everything until we hit whitespace */ - while (bufsize && - !((ret=get_user(nextchar, (char *) buffer))) && - isspace((int) nextchar)) { - bufsize--; - ((char *) buffer)++; - } - if (ret) - return -EFAULT; - - /* Put res in results */ - results[*nrels] = (min ? -1 : 1) * res; - (*nrels)++; - } - - /* Well, there may be more in the buffer, but we need no more data. - Ignore anything that is left. */ - return 0; -} - -static int i2c_write_reals(int nrels, void *buffer, size_t *bufsize, - long *results, int magnitude) -{ -#define BUFLEN 20 - char BUF[BUFLEN + 1]; /* An individual representation should fit! */ - char printfstr[10]; - int nr = 0; - int buflen, mag, times; - int curbufsize = 0; - - while ((nr < nrels) && (curbufsize < *bufsize)) { - mag = magnitude; - - if (nr != 0) { - if(put_user(' ', (char *) buffer)) - return -EFAULT; - curbufsize++; - ((char *) buffer)++; - } - - /* Fill BUF with the representation of the next string */ - if (mag <= 0) { - buflen = sprintf(BUF, "%ld", results[nr]); - if (buflen < 0) { /* Oops, a sprintf error! */ - *bufsize = 0; - return -EINVAL; - } - while ((mag < 0) && (buflen < BUFLEN)) { - BUF[buflen++] = '0'; - mag++; - } - BUF[buflen] = 0; - } else { - times = 1; - for (times = 1; mag-- > 0; times *= 10); - if (results[nr] < 0) { - BUF[0] = '-'; - buflen = 1; - } else - buflen = 0; - strcpy(printfstr, "%ld.%0Xld"); - printfstr[6] = magnitude + '0'; - buflen += - sprintf(BUF + buflen, printfstr, - abs(results[nr]) / times, - abs(results[nr]) % times); - if (buflen < 0) { /* Oops, a sprintf error! */ - *bufsize = 0; - return -EINVAL; - } - } - - /* Now copy it to the user-space buffer */ - if (buflen + curbufsize > *bufsize) - buflen = *bufsize - curbufsize; - if(copy_to_user(buffer, BUF, buflen)) - return -EFAULT; - curbufsize += buflen; - (char *) buffer += buflen; - - nr++; - } - if (curbufsize < *bufsize) { - if(put_user('\n', (char *) buffer)) - return -EFAULT; - curbufsize++; - } - *bufsize = curbufsize; - return 0; -} - - -/* Very inefficient for ISA detects, and won't work for 10-bit addresses! */ -int i2c_detect(struct i2c_adapter *adapter, - struct i2c_address_data *address_data, - i2c_found_addr_proc * found_proc) -{ - int addr, i, found, j, err; - struct i2c_force_data *this_force; - int is_isa = i2c_is_isa_adapter(adapter); - int adapter_id = - is_isa ? SENSORS_ISA_BUS : i2c_adapter_id(adapter); - - /* Forget it if we can't probe using SMBUS_QUICK */ - if ((!is_isa) - && !i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_QUICK)) return -1; - - for (addr = 0x00; addr <= (is_isa ? 0xffff : 0x7f); addr++) { - /* XXX: WTF is going on here??? */ - if ((is_isa && check_region(addr, 1)) || - (!is_isa && i2c_check_addr(adapter, addr))) - continue; - - /* If it is in one of the force entries, we don't do any - detection at all */ - found = 0; - for (i = 0; - !found - && (this_force = - address_data->forces + i, this_force->force); i++) { - for (j = 0; - !found - && (this_force->force[j] != SENSORS_I2C_END); - j += 2) { - if ( - ((adapter_id == this_force->force[j]) - || - ((this_force-> - force[j] == SENSORS_ANY_I2C_BUS) - && !is_isa)) - && (addr == this_force->force[j + 1])) { -#ifdef DEBUG - printk - (KERN_DEBUG "i2c-proc.o: found force parameter for adapter %d, addr %04x\n", - adapter_id, addr); -#endif - if ( - (err = - found_proc(adapter, addr, 0, - this_force-> - kind))) return err; - found = 1; - } - } - } - if (found) - continue; - - /* If this address is in one of the ignores, we can forget about it - right now */ - for (i = 0; - !found - && (address_data->ignore[i] != SENSORS_I2C_END); - i += 2) { - if ( - ((adapter_id == address_data->ignore[i]) - || - ((address_data-> - ignore[i] == SENSORS_ANY_I2C_BUS) - && !is_isa)) - && (addr == address_data->ignore[i + 1])) { -#ifdef DEBUG - printk - (KERN_DEBUG "i2c-proc.o: found ignore parameter for adapter %d, " - "addr %04x\n", adapter_id, addr); -#endif - found = 1; - } - } - for (i = 0; - !found - && (address_data->ignore_range[i] != SENSORS_I2C_END); - i += 3) { - if ( - ((adapter_id == address_data->ignore_range[i]) - || - ((address_data-> - ignore_range[i] == - SENSORS_ANY_I2C_BUS) & !is_isa)) - && (addr >= address_data->ignore_range[i + 1]) - && (addr <= address_data->ignore_range[i + 2])) { -#ifdef DEBUG - printk - (KERN_DEBUG "i2c-proc.o: found ignore_range parameter for adapter %d, " - "addr %04x\n", adapter_id, addr); -#endif - found = 1; - } - } - if (found) - continue; - - /* Now, we will do a detection, but only if it is in the normal or - probe entries */ - if (is_isa) { - for (i = 0; - !found - && (address_data->normal_isa[i] != - SENSORS_ISA_END); i += 1) { - if (addr == address_data->normal_isa[i]) { -#ifdef DEBUG - printk - (KERN_DEBUG "i2c-proc.o: found normal isa entry for adapter %d, " - "addr %04x\n", adapter_id, - addr); -#endif - found = 1; - } - } - for (i = 0; - !found - && (address_data->normal_isa_range[i] != - SENSORS_ISA_END); i += 3) { - if ((addr >= - address_data->normal_isa_range[i]) - && (addr <= - address_data->normal_isa_range[i + 1]) - && - ((addr - - address_data->normal_isa_range[i]) % - address_data->normal_isa_range[i + 2] == - 0)) { -#ifdef DEBUG - printk - (KERN_DEBUG "i2c-proc.o: found normal isa_range entry for adapter %d, " - "addr %04x", adapter_id, addr); -#endif - found = 1; - } - } - } else { - for (i = 0; - !found && (address_data->normal_i2c[i] != - SENSORS_I2C_END); i += 1) { - if (addr == address_data->normal_i2c[i]) { - found = 1; -#ifdef DEBUG - printk - (KERN_DEBUG "i2c-proc.o: found normal i2c entry for adapter %d, " - "addr %02x", adapter_id, addr); -#endif - } - } - for (i = 0; - !found - && (address_data->normal_i2c_range[i] != - SENSORS_I2C_END); i += 2) { - if ((addr >= - address_data->normal_i2c_range[i]) - && (addr <= - address_data->normal_i2c_range[i + 1])) - { -#ifdef DEBUG - printk - (KERN_DEBUG "i2c-proc.o: found normal i2c_range entry for adapter %d, " - "addr %04x\n", adapter_id, addr); -#endif - found = 1; - } - } - } - - for (i = 0; - !found && (address_data->probe[i] != SENSORS_I2C_END); - i += 2) { - if (((adapter_id == address_data->probe[i]) || - ((address_data-> - probe[i] == SENSORS_ANY_I2C_BUS) & !is_isa)) - && (addr == address_data->probe[i + 1])) { -#ifdef DEBUG - printk - (KERN_DEBUG "i2c-proc.o: found probe parameter for adapter %d, " - "addr %04x\n", adapter_id, addr); -#endif - found = 1; - } - } - for (i = 0; !found && - (address_data->probe_range[i] != SENSORS_I2C_END); - i += 3) { - if ( - ((adapter_id == address_data->probe_range[i]) - || - ((address_data->probe_range[i] == - SENSORS_ANY_I2C_BUS) & !is_isa)) - && (addr >= address_data->probe_range[i + 1]) - && (addr <= address_data->probe_range[i + 2])) { - found = 1; -#ifdef DEBUG - printk - (KERN_DEBUG "i2c-proc.o: found probe_range parameter for adapter %d, " - "addr %04x\n", adapter_id, addr); -#endif - } - } - if (!found) - continue; - - /* OK, so we really should examine this address. First check - whether there is some client here at all! */ - if (is_isa || - (i2c_smbus_xfer - (adapter, addr, 0, 0, 0, I2C_SMBUS_QUICK, NULL) >= 0)) - if ((err = found_proc(adapter, addr, 0, -1))) - return err; - } - return 0; -} - -static int __init i2c_proc_init(void) -{ - printk(KERN_INFO "i2c-proc.o version %s (%s)\n", I2C_VERSION, I2C_DATE); - if (! - (i2c_proc_header = - register_sysctl_table(i2c_proc, 0))) { - printk(KERN_ERR "i2c-proc.o: error: sysctl interface not supported by kernel!\n"); - return -EPERM; - } - i2c_proc_header->ctl_table->child->de->owner = THIS_MODULE; - return 0; -} - -static void __exit i2c_proc_exit(void) -{ - unregister_sysctl_table(i2c_proc_header); -} - -EXPORT_SYMBOL(i2c_register_entry); -EXPORT_SYMBOL(i2c_deregister_entry); -EXPORT_SYMBOL(i2c_proc_real); -EXPORT_SYMBOL(i2c_sysctl_real); -EXPORT_SYMBOL(i2c_detect); - -MODULE_AUTHOR("Frodo Looijaard "); -MODULE_DESCRIPTION("i2c-proc driver"); -MODULE_LICENSE("GPL"); - -module_init(i2c_proc_init); -module_exit(i2c_proc_exit); diff -Nru a/drivers/i2c/i2c-sensor.c b/drivers/i2c/i2c-sensor.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/i2c/i2c-sensor.c Wed Apr 2 22:24:05 2003 @@ -0,0 +1,182 @@ +/* + i2c-sensor.c - Part of lm_sensors, Linux kernel modules for hardware + monitoring + Copyright (c) 1998 - 2001 Frodo Looijaard and + Mark D. Studebaker + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* #define DEBUG 1 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Very inefficient for ISA detects, and won't work for 10-bit addresses! */ +int i2c_detect(struct i2c_adapter *adapter, + struct i2c_address_data *address_data, + i2c_found_addr_proc * found_proc) +{ + int addr, i, found, j, err; + struct i2c_force_data *this_force; + int is_isa = i2c_is_isa_adapter(adapter); + int adapter_id = + is_isa ? SENSORS_ISA_BUS : i2c_adapter_id(adapter); + + /* Forget it if we can't probe using SMBUS_QUICK */ + if ((!is_isa) && + !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) + return -1; + + for (addr = 0x00; addr <= (is_isa ? 0xffff : 0x7f); addr++) { + /* XXX: WTF is going on here??? */ + if ((is_isa && check_region(addr, 1)) || + (!is_isa && i2c_check_addr(adapter, addr))) + continue; + + /* If it is in one of the force entries, we don't do any + detection at all */ + found = 0; + for (i = 0; !found && (this_force = address_data->forces + i, this_force->force); i++) { + for (j = 0; !found && (this_force->force[j] != SENSORS_I2C_END); j += 2) { + if ( ((adapter_id == this_force->force[j]) || + ((this_force->force[j] == SENSORS_ANY_I2C_BUS) && !is_isa)) && + (addr == this_force->force[j + 1]) ) { + dev_dbg(&adapter->dev, "found force parameter for adapter %d, addr %04x\n", adapter_id, addr); + if ((err = found_proc(adapter, addr, this_force->kind))) + return err; + found = 1; + } + } + } + if (found) + continue; + + /* If this address is in one of the ignores, we can forget about it + right now */ + for (i = 0; !found && (address_data->ignore[i] != SENSORS_I2C_END); i += 2) { + if ( ((adapter_id == address_data->ignore[i]) || + ((address_data->ignore[i] == SENSORS_ANY_I2C_BUS) && + !is_isa)) && + (addr == address_data->ignore[i + 1])) { + dev_dbg(&adapter->dev, "found ignore parameter for adapter %d, addr %04x\n", adapter_id, addr); + found = 1; + } + } + for (i = 0; !found && (address_data->ignore_range[i] != SENSORS_I2C_END); i += 3) { + if ( ((adapter_id == address_data->ignore_range[i]) || + ((address_data-> ignore_range[i] == SENSORS_ANY_I2C_BUS) & + !is_isa)) && + (addr >= address_data->ignore_range[i + 1]) && + (addr <= address_data->ignore_range[i + 2])) { + dev_dbg(&adapter->dev, "found ignore_range parameter for adapter %d, addr %04x\n", adapter_id, addr); + found = 1; + } + } + if (found) + continue; + + /* Now, we will do a detection, but only if it is in the normal or + probe entries */ + if (is_isa) { + for (i = 0; !found && (address_data->normal_isa[i] != SENSORS_ISA_END); i += 1) { + if (addr == address_data->normal_isa[i]) { + dev_dbg(&adapter->dev, "found normal isa entry for adapter %d, addr %04x\n", adapter_id, addr); + found = 1; + } + } + for (i = 0; !found && (address_data->normal_isa_range[i] != SENSORS_ISA_END); i += 3) { + if ((addr >= address_data->normal_isa_range[i]) && + (addr <= address_data->normal_isa_range[i + 1]) && + ((addr - address_data->normal_isa_range[i]) % address_data->normal_isa_range[i + 2] == 0)) { + dev_dbg(&adapter->dev, "found normal isa_range entry for adapter %d, addr %04x", adapter_id, addr); + found = 1; + } + } + } else { + for (i = 0; !found && (address_data->normal_i2c[i] != SENSORS_I2C_END); i += 1) { + if (addr == address_data->normal_i2c[i]) { + found = 1; + dev_dbg(&adapter->dev, "found normal i2c entry for adapter %d, addr %02x", adapter_id, addr); + } + } + for (i = 0; !found && (address_data->normal_i2c_range[i] != SENSORS_I2C_END); i += 2) { + if ((addr >= address_data->normal_i2c_range[i]) && + (addr <= address_data->normal_i2c_range[i + 1])) { + dev_dbg(&adapter->dev, "found normal i2c_range entry for adapter %d, addr %04x\n", adapter_id, addr); + found = 1; + } + } + } + + for (i = 0; + !found && (address_data->probe[i] != SENSORS_I2C_END); + i += 2) { + if (((adapter_id == address_data->probe[i]) || + ((address_data-> + probe[i] == SENSORS_ANY_I2C_BUS) & !is_isa)) + && (addr == address_data->probe[i + 1])) { + dev_dbg(&adapter->dev, "found probe parameter for adapter %d, addr %04x\n", adapter_id, addr); + found = 1; + } + } + for (i = 0; !found && (address_data->probe_range[i] != SENSORS_I2C_END); i += 3) { + if ( ((adapter_id == address_data->probe_range[i]) || + ((address_data->probe_range[i] == SENSORS_ANY_I2C_BUS) & !is_isa)) && + (addr >= address_data->probe_range[i + 1]) && + (addr <= address_data->probe_range[i + 2])) { + found = 1; + dev_dbg(&adapter->dev, "found probe_range parameter for adapter %d, addr %04x\n", adapter_id, addr); + } + } + if (!found) + continue; + + /* OK, so we really should examine this address. First check + whether there is some client here at all! */ + if (is_isa || + (i2c_smbus_xfer (adapter, addr, 0, 0, 0, I2C_SMBUS_QUICK, NULL) >= 0)) + if ((err = found_proc(adapter, addr, -1))) + return err; + } + return 0; +} + +static int __init i2c_sensor_init(void) +{ + return 0; +} + +static void __exit i2c_sensor_exit(void) +{ +} + +EXPORT_SYMBOL(i2c_detect); + +MODULE_AUTHOR("Frodo Looijaard "); +MODULE_DESCRIPTION("i2c-sensor driver"); +MODULE_LICENSE("GPL"); + +module_init(i2c_sensor_init); +module_exit(i2c_sensor_exit); diff -Nru a/drivers/i2c/i2c-velleman.c b/drivers/i2c/i2c-velleman.c --- a/drivers/i2c/i2c-velleman.c Wed Apr 2 22:24:07 2003 +++ b/drivers/i2c/i2c-velleman.c Wed Apr 2 22:24:07 2003 @@ -114,9 +114,11 @@ static struct i2c_adapter bit_velle_ops = { .owner = THIS_MODULE, - .name = "Velleman K8000", .id = I2C_HW_B_VELLE, .algo_data = &bit_velle_data, + .dev = { + .name = "Velleman K8000", + }, }; static int __init i2c_bitvelle_init(void) diff -Nru a/drivers/i2c/scx200_acb.c b/drivers/i2c/scx200_acb.c --- a/drivers/i2c/scx200_acb.c Wed Apr 2 22:24:05 2003 +++ b/drivers/i2c/scx200_acb.c Wed Apr 2 22:24:05 2003 @@ -140,8 +140,7 @@ switch (iface->state) { case state_idle: - printk(KERN_WARNING NAME ": %s, interrupt in idle state\n", - iface->adapter.name); + dev_warn(&iface->adapter.dev, "interrupt in idle state\n"); break; case state_address: @@ -226,8 +225,8 @@ return; error: - printk(KERN_ERR NAME ": %s, %s in state %s\n", iface->adapter.name, - errmsg, scx200_acb_state_name[iface->state]); + dev_err(&iface->adapter.dev, "%s in state %s\n", errmsg, + scx200_acb_state_name[iface->state]); iface->state = state_idle; iface->result = -EIO; @@ -236,8 +235,8 @@ static void scx200_acb_timeout(struct scx200_acb_iface *iface) { - printk(KERN_ERR NAME ": %s, timeout in state %s\n", - iface->adapter.name, scx200_acb_state_name[iface->state]); + dev_err(&iface->adapter.dev, "timeout in state %s\n", + scx200_acb_state_name[iface->state]); iface->state = state_idle; iface->result = -EIO; @@ -290,7 +289,7 @@ char rw, u8 command, int size, union i2c_smbus_data *data) { - struct scx200_acb_iface *iface = adapter->data; + struct scx200_acb_iface *iface = i2c_get_adapdata(adapter); int len; u8 *buffer; u16 cur_word; @@ -331,13 +330,12 @@ size, address, command, len, rw == I2C_SMBUS_READ); if (!len && rw == I2C_SMBUS_READ) { - printk(KERN_WARNING NAME ": %s, zero length read\n", - adapter->name); + dev_warn(&adapter->dev, "zero length read\n"); return -EINVAL; } if (len && !buffer) { - printk(KERN_WARNING NAME ": %s, nonzero length but no buffer\n", adapter->name); + dev_warn(&adapter->dev, "nonzero length but no buffer\n"); return -EFAULT; } @@ -457,18 +455,18 @@ memset(iface, 0, sizeof(*iface)); adapter = &iface->adapter; - adapter->data = iface; - sprintf(adapter->name, "SCx200 ACB%d", index); + i2c_set_adapdata(adapter, iface); + snprintf(adapter->dev.name, DEVICE_NAME_SIZE, "SCx200 ACB%d", index); adapter->owner = THIS_MODULE; adapter->id = I2C_ALGO_SMBUS; adapter->algo = &scx200_acb_algorithm; init_MUTEX(&iface->sem); - sprintf(description, "NatSemi SCx200 ACCESS.bus [%s]", adapter->name); + snprintf(description, sizeof(description), "NatSemi SCx200 ACCESS.bus [%s]", adapter->dev.name); if (request_region(base, 8, description) == 0) { - printk(KERN_ERR NAME ": %s, can't allocate io 0x%x-0x%x\n", - adapter->name, base, base + 8-1); + dev_err(&adapter->dev, "can't allocate io 0x%x-0x%x\n", + base, base + 8-1); rc = -EBUSY; goto errout; } @@ -476,14 +474,14 @@ rc = scx200_acb_probe(iface); if (rc) { - printk(KERN_WARNING NAME ": %s, probe failed\n", adapter->name); + dev_warn(&adapter->dev, "probe failed\n"); goto errout; } scx200_acb_reset(iface); if (i2c_add_adapter(adapter) < 0) { - printk(KERN_ERR NAME ": %s, failed to register\n", adapter->name); + dev_err(&adapter->dev, "failed to register\n"); rc = -ENODEV; goto errout; } diff -Nru a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c --- a/drivers/ide/ide-disk.c Wed Apr 2 22:24:05 2003 +++ b/drivers/ide/ide-disk.c Wed Apr 2 22:24:05 2003 @@ -1098,6 +1098,7 @@ * in above order (i.e., if value of higher priority is available, * reset will be ignored). */ +#define IDE_STROKE_LIMIT (32000*1024*2) static void init_idedisk_capacity (ide_drive_t *drive) { struct hd_driveid *id = drive->id; @@ -1118,7 +1119,7 @@ drive->cyl = (unsigned int) capacity_2 / (drive->head * drive->sect); drive->select.b.lba = 1; set_max_ext = idedisk_read_native_max_address_ext(drive); - if (set_max_ext > capacity_2) { + if (set_max_ext > capacity_2 && capacity_2 > IDE_STROKE_LIMIT) { #ifdef CONFIG_IDEDISK_STROKE set_max_ext = idedisk_read_native_max_address_ext(drive); set_max_ext = idedisk_set_max_address_ext(drive, set_max_ext); @@ -1145,7 +1146,7 @@ drive->select.b.lba = 1; } - if (set_max > capacity) { + if (set_max > capacity && capacity > IDE_STROKE_LIMIT) { #ifdef CONFIG_IDEDISK_STROKE set_max = idedisk_read_native_max_address(drive); set_max = idedisk_set_max_address(drive, set_max); diff -Nru a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c --- a/drivers/ide/ide-iops.c Wed Apr 2 22:24:05 2003 +++ b/drivers/ide/ide-iops.c Wed Apr 2 22:24:05 2003 @@ -903,6 +903,14 @@ * Select the drive, and issue the SETFEATURES command */ disable_irq_nosync(hwif->irq); + + /* + * FIXME: we race against the running IRQ here if + * this is called from non IRQ context. If we use + * disable_irq() we hang on the error path. Work + * is needed. + */ + udelay(1); SELECT_DRIVE(drive); SELECT_MASK(drive, 0); diff -Nru a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c --- a/drivers/ide/ide-taskfile.c Wed Apr 2 22:24:04 2003 +++ b/drivers/ide/ide-taskfile.c Wed Apr 2 22:24:04 2003 @@ -1670,7 +1670,7 @@ #else - int err = 0; + int err = -EIO; u8 args[4], *argbuf = args; u8 xfer_rate = 0; int argsize = 0; diff -Nru a/drivers/ide/ide-timing.h b/drivers/ide/ide-timing.h --- a/drivers/ide/ide-timing.h Wed Apr 2 22:24:05 2003 +++ b/drivers/ide/ide-timing.h Wed Apr 2 22:24:05 2003 @@ -245,14 +245,6 @@ } /* - * If the drive is an ATAPI device it may need slower address setup timing, - * so we stay on the safe side. - */ - - if (drive->media != ide_disk) - p.setup = 120; - -/* * Convert the timing to bus clock counts. */ diff -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c --- a/drivers/ide/ide.c Wed Apr 2 22:24:04 2003 +++ b/drivers/ide/ide.c Wed Apr 2 22:24:05 2003 @@ -2019,7 +2019,7 @@ goto done; } #endif /* CONFIG_BLK_DEV_HT6560B */ -#if CONFIG_BLK_DEV_QD65XX +#ifdef CONFIG_BLK_DEV_QD65XX case -12: /* "qd65xx" */ { extern void init_qd65xx (void); diff -Nru a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c --- a/drivers/ieee1394/pcilynx.c Wed Apr 2 22:24:05 2003 +++ b/drivers/ieee1394/pcilynx.c Wed Apr 2 22:24:05 2003 @@ -138,10 +138,12 @@ }; static struct i2c_adapter bit_ops = { - .name = "PCILynx I2C adapter", .id = 0xAA, //FIXME: probably we should get an id in i2c-id.h .client_register = bit_reg, .client_unregister = bit_unreg, + .dev = { + .name = "PCILynx I2C", + }, }; diff -Nru a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c --- a/drivers/isdn/hisax/elsa_cs.c Wed Apr 2 22:24:05 2003 +++ b/drivers/isdn/hisax/elsa_cs.c Wed Apr 2 22:24:05 2003 @@ -53,7 +53,6 @@ #include #include #include -#include MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Elsa PCM cards"); MODULE_AUTHOR("Klaus Lichtenwalder"); @@ -163,17 +162,12 @@ "stopped" due to a power management event, or card ejection. The device IO routines can use a flag like this to throttle IO to a card that is not ready to accept it. - - The bus_operations pointer is used on platforms for which we need - to use special socket-specific versions of normal IO primitives - (inb, outb, readb, writeb, etc) for card IO. */ typedef struct local_info_t { dev_link_t link; dev_node_t node; int busy; - struct bus_operations *bus; } local_info_t; /*====================================================================*/ @@ -522,7 +516,6 @@ break; case CS_EVENT_CARD_INSERTION: link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - dev->bus = args->bus; elsa_cs_config(link); break; case CS_EVENT_PM_SUSPEND: diff -Nru a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c --- a/drivers/isdn/hisax/sedlbauer_cs.c Wed Apr 2 22:24:05 2003 +++ b/drivers/isdn/hisax/sedlbauer_cs.c Wed Apr 2 22:24:05 2003 @@ -53,7 +53,6 @@ #include #include #include -#include MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Sedlbauer cards"); MODULE_AUTHOR("Marcus Niemann"); @@ -171,17 +170,12 @@ "stopped" due to a power management event, or card ejection. The device IO routines can use a flag like this to throttle IO to a card that is not ready to accept it. - - The bus_operations pointer is used on platforms for which we need - to use special socket-specific versions of normal IO primitives - (inb, outb, readb, writeb, etc) for card IO. */ typedef struct local_info_t { dev_link_t link; dev_node_t node; int stop; - struct bus_operations *bus; } local_info_t; /*====================================================================*/ @@ -620,7 +614,6 @@ break; case CS_EVENT_CARD_INSERTION: link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - dev->bus = args->bus; sedlbauer_config(link); break; case CS_EVENT_PM_SUSPEND: diff -Nru a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c --- a/drivers/macintosh/adb.c Wed Apr 2 22:24:08 2003 +++ b/drivers/macintosh/adb.c Wed Apr 2 22:24:08 2003 @@ -102,6 +102,7 @@ void (*handler)(unsigned char *, int, struct pt_regs *, int); int original_address; int handler_id; + int busy; } adb_handler[16]; /* @@ -134,7 +135,7 @@ { if (current->pid && adb_probe_task_pid && adb_probe_task_pid == current->pid) { - current->state = TASK_UNINTERRUPTIBLE; + set_task_state(current, TASK_UNINTERRUPTIBLE); schedule_timeout(1 + ms * HZ / 1000); } else mdelay(ms); @@ -249,7 +250,7 @@ strcpy(current->comm, "kadbprobe"); sigfillset(&blocked); - sigprocmask(SIG_BLOCK, &blocked, NULL); + sigprocmask(SIG_BLOCK, &blocked, NULL); flush_signals(current); printk(KERN_INFO "adb: starting probe task...\n"); @@ -550,12 +551,17 @@ down(&adb_handler_sem); write_lock_irq(&adb_handler_lock); if (adb_handler[index].handler) { + while(adb_handler[index].busy) { + write_unlock_irq(&adb_handler_lock); + yield(); + write_lock_irq(&adb_handler_lock); + } ret = 0; adb_handler[index].handler = 0; } write_unlock_irq(&adb_handler_lock); up(&adb_handler_sem); - return 0; + return ret; } void @@ -563,6 +569,8 @@ { int i, id; static int dump_adb_input = 0; + unsigned long flags; + void (*handler)(unsigned char *, int, struct pt_regs *, int); /* We skip keystrokes and mouse moves when the sleep process @@ -578,11 +586,17 @@ printk(" %x", buf[i]); printk(", id = %d\n", id); } - read_lock(&adb_handler_lock); + write_lock_irqsave(&adb_handler_lock, flags); handler = adb_handler[id].handler; - if (handler != 0) + if (handler != NULL) + adb_handler[id].busy = 1; + write_unlock_irqrestore(&adb_handler_lock, flags); + if (handler != NULL) { (*handler)(buf, nb, regs, autopoll); - read_unlock(&adb_handler_lock); + wmb(); + adb_handler[id].busy = 0; + } + } /* Try to change handler to new_id. Will return 1 if successful. */ @@ -671,6 +685,29 @@ spin_unlock_irqrestore(&state->lock, flags); } +static int +do_adb_query(struct adb_request *req) +{ + int ret = -EINVAL; + + switch(req->data[1]) + { + case ADB_QUERY_GETDEVINFO: + if (req->nbytes < 3) + break; + down(&adb_handler_sem); + req->reply[0] = adb_handler[req->data[2]].original_address; + req->reply[1] = adb_handler[req->data[2]].handler_id; + up(&adb_handler_sem); + req->complete = 1; + req->reply_len = 2; + adb_write_done(req); + ret = 0; + break; + } + return ret; +} + static int adb_open(struct inode *inode, struct file *file) { struct adbdev_state *state; @@ -806,24 +843,32 @@ /* If a probe is in progress or we are sleeping, wait for it to complete */ down(&adb_probe_mutex); - up(&adb_probe_mutex); + /* Queries are special requests sent to the ADB driver itself */ + if (req->data[0] == ADB_QUERY) { + if (count > 1) + ret = do_adb_query(req); + else + ret = -EINVAL; + up(&adb_probe_mutex); + } /* Special case for ADB_BUSRESET request, all others are sent to the controller */ - if ((req->data[0] == ADB_PACKET)&&(count > 1) + else if ((req->data[0] == ADB_PACKET)&&(count > 1) &&(req->data[1] == ADB_BUSRESET)) { ret = do_adb_reset_bus(); + up(&adb_probe_mutex); atomic_dec(&state->n_pending); if (ret == 0) ret = count; goto out; } else { req->reply_expected = ((req->data[1] & 0xc) == 0xc); - if (adb_controller && adb_controller->send_request) ret = adb_controller->send_request(req, 0); else ret = -ENXIO; + up(&adb_probe_mutex); } if (ret != 0) { diff -Nru a/drivers/macintosh/apm_emu.c b/drivers/macintosh/apm_emu.c --- a/drivers/macintosh/apm_emu.c Wed Apr 2 22:24:07 2003 +++ b/drivers/macintosh/apm_emu.c Wed Apr 2 22:24:07 2003 @@ -436,40 +436,40 @@ int percentage = -1; int time_units = -1; int real_count = 0; - int charge = -1; - int current = 0; int i; char * p = buf; char charging = 0; + long charge = -1; + long current = 0; + unsigned long btype = 0; ac_line_status = ((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0); for (i=0; i 0) { battery_status = 0x03; battery_flag = 0x08; } else if (percentage <= APM_CRITICAL) { diff -Nru a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c --- a/drivers/macintosh/macio-adb.c Wed Apr 2 22:24:07 2003 +++ b/drivers/macintosh/macio-adb.c Wed Apr 2 22:24:07 2003 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include diff -Nru a/drivers/md/linear.c b/drivers/md/linear.c --- a/drivers/md/linear.c Wed Apr 2 22:24:05 2003 +++ b/drivers/md/linear.c Wed Apr 2 22:24:05 2003 @@ -37,7 +37,11 @@ linear_conf_t *conf = mddev_to_conf(mddev); sector_t block = sector >> 1; - hash = conf->hash_table + sector_div(block, conf->smallest->size); + /* + * sector_div(a,b) returns the remainer and sets a to a/b + */ + (void)sector_div(block, conf->smallest->size); + hash = conf->hash_table + block; if ((sector>>1) >= (hash->dev0->size + hash->dev0->offset)) return hash->dev1; @@ -75,8 +79,6 @@ unsigned int curr_offset; struct list_head *tmp; - MOD_INC_USE_COUNT; - conf = kmalloc (sizeof (*conf), GFP_KERNEL); if (!conf) goto out; @@ -163,7 +165,6 @@ out: if (conf) kfree(conf); - MOD_DEC_USE_COUNT; return 1; } @@ -174,8 +175,6 @@ kfree(conf->hash_table); kfree(conf); - MOD_DEC_USE_COUNT; - return 0; } @@ -189,7 +188,7 @@ block = bio->bi_sector >> 1; if (unlikely(!tmp_dev)) { - printk ("linear_make_request : hash->dev1==NULL for block %llu\n", + printk("linear_make_request: hash->dev1==NULL for block %llu\n", (unsigned long long)block); bio_io_error(bio, bio->bi_size); return 0; @@ -199,7 +198,7 @@ || block < tmp_dev->offset)) { char b[BDEVNAME_SIZE]; - printk ("linear_make_request: Block %llu out of bounds on " + printk("linear_make_request: Block %llu out of bounds on " "dev %s size %ld offset %ld\n", (unsigned long long)block, bdevname(tmp_dev->rdev->bdev, b), @@ -242,6 +241,7 @@ static mdk_personality_t linear_personality= { .name = "linear", + .owner = THIS_MODULE, .make_request = linear_make_request, .run = linear_run, .stop = linear_stop, diff -Nru a/drivers/md/md.c b/drivers/md/md.c --- a/drivers/md/md.c Wed Apr 2 22:24:05 2003 +++ b/drivers/md/md.c Wed Apr 2 22:24:05 2003 @@ -64,6 +64,7 @@ #endif static mdk_personality_t *pers[MAX_PERSONALITY]; +static spinlock_t pers_lock = SPIN_LOCK_UNLOCKED; /* * Current RAID-1,4,5 parallel reconstruction 'guaranteed speed limit' @@ -302,22 +303,6 @@ return 0; } - -#define BAD_MAGIC KERN_ERR \ -"md: invalid raid superblock magic on %s\n" - -#define BAD_MINOR KERN_ERR \ -"md: %s: invalid raid minor (%x)\n" - -#define OUT_OF_MEM KERN_ALERT \ -"md: out of memory.\n" - -#define NO_SB KERN_ERR \ -"md: disabled device %s, could not read superblock.\n" - -#define BAD_CSUM KERN_WARNING \ -"md: invalid superblock checksum on %s\n" - static int alloc_disk_sb(mdk_rdev_t * rdev) { if (rdev->sb_page) @@ -325,7 +310,7 @@ rdev->sb_page = alloc_page(GFP_KERNEL); if (!rdev->sb_page) { - printk(OUT_OF_MEM); + printk(KERN_ALERT "md: out of memory.\n"); return -EINVAL; } @@ -397,7 +382,8 @@ return 0; fail: - printk(NO_SB,bdev_partition_name(rdev->bdev)); + printk(KERN_ERR "md: disabled device %s, could not read superblock.\n", + bdev_partition_name(rdev->bdev)); return -EINVAL; } @@ -526,27 +512,30 @@ sb = (mdp_super_t*)page_address(rdev->sb_page); if (sb->md_magic != MD_SB_MAGIC) { - printk(BAD_MAGIC, bdev_partition_name(rdev->bdev)); + printk(KERN_ERR "md: invalid raid superblock magic on %s\n", + bdev_partition_name(rdev->bdev)); goto abort; } if (sb->major_version != 0 || sb->minor_version != 90) { printk(KERN_WARNING "Bad version number %d.%d on %s\n", - sb->major_version, sb->minor_version, - bdev_partition_name(rdev->bdev)); + sb->major_version, sb->minor_version, + bdev_partition_name(rdev->bdev)); goto abort; } if (sb->md_minor >= MAX_MD_DEVS) { - printk(BAD_MINOR, bdev_partition_name(rdev->bdev), sb->md_minor); + printk(KERN_ERR "md: %s: invalid raid minor (%x)\n", + bdev_partition_name(rdev->bdev), sb->md_minor); goto abort; } if (sb->raid_disks <= 0) goto abort; if (calc_sb_csum(sb) != sb->sb_csum) { - printk(BAD_CSUM, bdev_partition_name(rdev->bdev)); + printk(KERN_WARNING "md: invalid superblock checksum on %s\n", + bdev_partition_name(rdev->bdev)); goto abort; } @@ -565,14 +554,15 @@ mdp_super_t *refsb = (mdp_super_t*)page_address(refdev->sb_page); if (!uuid_equal(refsb, sb)) { printk(KERN_WARNING "md: %s has different UUID to %s\n", - bdev_partition_name(rdev->bdev), - bdev_partition_name(refdev->bdev)); + bdev_partition_name(rdev->bdev), + bdev_partition_name(refdev->bdev)); goto abort; } if (!sb_equal(refsb, sb)) { - printk(KERN_WARNING "md: %s has same UUID but different superblock to %s\n", - bdev_partition_name(rdev->bdev), - bdev_partition_name(refdev->bdev)); + printk(KERN_WARNING "md: %s has same UUID" + " but different superblock to %s\n", + bdev_partition_name(rdev->bdev), + bdev_partition_name(refdev->bdev)); goto abort; } ev1 = md_event(sb); @@ -826,7 +816,8 @@ return -EINVAL; if (calc_sb_1_csum(sb) != sb->sb_csum) { - printk(BAD_CSUM, bdev_partition_name(rdev->bdev)); + printk("md: invalid superblock checksum on %s\n", + bdev_partition_name(rdev->bdev)); return -EINVAL; } rdev->preferred_minor = 0xffff; @@ -843,9 +834,10 @@ sb->level != refsb->level || sb->layout != refsb->layout || sb->chunksize != refsb->chunksize) { - printk(KERN_WARNING "md: %s has strangely different superblock to %s\n", - bdev_partition_name(rdev->bdev), - bdev_partition_name(refdev->bdev)); + printk(KERN_WARNING "md: %s has strangely different" + " superblock to %s\n", + bdev_partition_name(rdev->bdev), + bdev_partition_name(refdev->bdev)); return -EINVAL; } ev1 = le64_to_cpu(sb->events); @@ -1020,11 +1012,12 @@ } same_pdev = match_dev_unit(mddev, rdev); if (same_pdev) - printk( KERN_WARNING -"md%d: WARNING: %s appears to be on the same physical disk as %s. True\n" -" protection against single-disk failure might be compromised.\n", + printk(KERN_WARNING + "md%d: WARNING: %s appears to be on the same physical" + " disk as %s. True\n protection against single-disk" + " failure might be compromised.\n", mdidx(mddev), bdev_partition_name(rdev->bdev), - bdev_partition_name(same_pdev->bdev)); + bdev_partition_name(same_pdev->bdev)); /* Verify rdev->desc_nr is unique. * If it is -1, assign a free number, else @@ -1099,7 +1092,8 @@ static void export_rdev(mdk_rdev_t * rdev) { - printk(KERN_INFO "md: export_rdev(%s)\n",bdev_partition_name(rdev->bdev)); + printk(KERN_INFO "md: export_rdev(%s)\n", + bdev_partition_name(rdev->bdev)); if (rdev->mddev) MD_BUG(); free_disk_sb(rdev); @@ -1135,11 +1129,6 @@ mddev->major_version = 0; } -#undef BAD_CSUM -#undef BAD_MAGIC -#undef OUT_OF_MEM -#undef NO_SB - static void print_desc(mdp_disk_t *desc) { printk(" DISK\n", desc->number, @@ -1151,14 +1140,16 @@ { int i; - printk(KERN_INFO "md: SB: (V:%d.%d.%d) ID:<%08x.%08x.%08x.%08x> CT:%08x\n", + printk(KERN_INFO + "md: SB: (V:%d.%d.%d) ID:<%08x.%08x.%08x.%08x> CT:%08x\n", sb->major_version, sb->minor_version, sb->patch_version, sb->set_uuid0, sb->set_uuid1, sb->set_uuid2, sb->set_uuid3, sb->ctime); - printk(KERN_INFO "md: L%d S%08d ND:%d RD:%d md%d LO:%d CS:%d\n", sb->level, - sb->size, sb->nr_disks, sb->raid_disks, sb->md_minor, - sb->layout, sb->chunk_size); - printk(KERN_INFO "md: UT:%08x ST:%d AD:%d WD:%d FD:%d SD:%d CSUM:%08x E:%08lx\n", + printk(KERN_INFO "md: L%d S%08d ND:%d RD:%d md%d LO:%d CS:%d\n", + sb->level, sb->size, sb->nr_disks, sb->raid_disks, + sb->md_minor, sb->layout, sb->chunk_size); + printk(KERN_INFO "md: UT:%08x ST:%d AD:%d WD:%d" + " FD:%d SD:%d CSUM:%08x E:%08lx\n", sb->utime, sb->state, sb->active_disks, sb->working_disks, sb->failed_disks, sb->spare_disks, sb->sb_csum, (unsigned long)sb->events_lo); @@ -1182,8 +1173,8 @@ static void print_rdev(mdk_rdev_t *rdev) { printk(KERN_INFO "md: rdev %s, SZ:%08llu F:%d S:%d DN:%d ", - bdev_partition_name(rdev->bdev), - (unsigned long long)rdev->size, rdev->faulty, rdev->in_sync, rdev->desc_nr); + bdev_partition_name(rdev->bdev), (unsigned long long)rdev->size, + rdev->faulty, rdev->in_sync, rdev->desc_nr); if (rdev->sb_loaded) { printk(KERN_INFO "md: rdev superblock:\n"); print_sb((mdp_super_t*)page_address(rdev->sb_page)); @@ -1227,13 +1218,15 @@ return 1; } - dprintk(KERN_INFO "(write) %s's sb offset: %llu\n", bdev_partition_name(rdev->bdev), + dprintk(KERN_INFO "(write) %s's sb offset: %llu\n", + bdev_partition_name(rdev->bdev), (unsigned long long)rdev->sb_offset); if (sync_page_io(rdev->bdev, rdev->sb_offset<<1, MD_SB_BYTES, rdev->sb_page, WRITE)) return 0; - printk("md: write_disk_sb failed for device %s\n", bdev_partition_name(rdev->bdev)); + printk("md: write_disk_sb failed for device %s\n", + bdev_partition_name(rdev->bdev)); return 1; } @@ -1278,8 +1271,9 @@ if (!mddev->persistent) return; - dprintk(KERN_INFO "md: updating md%d RAID superblock on device (in sync %d)\n", - mdidx(mddev),mddev->in_sync); + dprintk(KERN_INFO + "md: updating md%d RAID superblock on device (in sync %d)\n", + mdidx(mddev),mddev->in_sync); err = 0; ITERATE_RDEV(mddev,rdev,tmp) { @@ -1298,10 +1292,12 @@ } if (err) { if (--count) { - printk(KERN_ERR "md: errors occurred during superblock update, repeating\n"); + printk(KERN_ERR "md: errors occurred during superblock" + " update, repeating\n"); goto repeat; } - printk(KERN_ERR "md: excessive errors occurred during superblock update, exiting\n"); + printk(KERN_ERR \ + "md: excessive errors occurred during superblock update, exiting\n"); } } @@ -1323,7 +1319,8 @@ rdev = (mdk_rdev_t *) kmalloc(sizeof(*rdev), GFP_KERNEL); if (!rdev) { - printk(KERN_ERR "md: could not alloc mem for %s!\n", partition_name(newdev)); + printk(KERN_ERR "md: could not alloc mem for %s!\n", + partition_name(newdev)); return ERR_PTR(-ENOMEM); } memset(rdev, 0, sizeof(*rdev)); @@ -1345,9 +1342,9 @@ size = rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS; if (!size) { - printk(KERN_WARNING - "md: %s has zero or unknown size, marking faulty!\n", - bdev_partition_name(rdev->bdev)); + printk(KERN_WARNING + "md: %s has zero or unknown size, marking faulty!\n", + bdev_partition_name(rdev->bdev)); err = -EINVAL; goto abort_free; } @@ -1356,13 +1353,15 @@ err = super_types[super_format]. load_super(rdev, NULL, super_minor); if (err == -EINVAL) { - printk(KERN_WARNING "md: %s has invalid sb, not importing!\n", - bdev_partition_name(rdev->bdev)); + printk(KERN_WARNING + "md: %s has invalid sb, not importing!\n", + bdev_partition_name(rdev->bdev)); goto abort_free; } if (err < 0) { - printk(KERN_WARNING "md: could not read %s's sb, not importing!\n", - bdev_partition_name(rdev->bdev)); + printk(KERN_WARNING + "md: could not read %s's sb, not importing!\n", + bdev_partition_name(rdev->bdev)); goto abort_free; } } @@ -1384,20 +1383,6 @@ * Check a full RAID array for plausibility */ -#define INCONSISTENT KERN_ERR \ -"md: fatal superblock inconsistency in %s -- removing from array\n" - -#define OUT_OF_DATE KERN_ERR \ -"md: superblock update time inconsistency -- using the most recent one\n" - -#define OLD_VERSION KERN_ALERT \ -"md: md%d: unsupported raid array version %d.%d.%d\n" - -#define NOT_CLEAN_IGNORE KERN_ERR \ -"md: md%d: raid array is not clean -- starting background reconstruction\n" - -#define UNKNOWN_LEVEL KERN_ERR \ -"md: md%d: unsupported raid level %d\n" static int analyze_sbs(mddev_t * mddev) { @@ -1415,7 +1400,10 @@ case 0: break; default: - printk(INCONSISTENT, bdev_partition_name(rdev->bdev)); + printk( KERN_ERR \ + "md: fatal superblock inconsistency in %s" + " -- removing from array\n", + bdev_partition_name(rdev->bdev)); kick_rdev_from_array(rdev); } @@ -1428,8 +1416,9 @@ if (rdev != freshest) if (super_types[mddev->major_version]. validate_super(mddev, rdev)) { - printk(KERN_WARNING "md: kicking non-fresh %s from array!\n", - bdev_partition_name(rdev->bdev)); + printk(KERN_WARNING "md: kicking non-fresh %s" + " from array!\n", + bdev_partition_name(rdev->bdev)); kick_rdev_from_array(rdev); continue; } @@ -1446,26 +1435,24 @@ */ if (mddev->major_version != MD_MAJOR_VERSION || mddev->minor_version > MD_MINOR_VERSION) { - - printk(OLD_VERSION, mdidx(mddev), mddev->major_version, - mddev->minor_version, mddev->patch_version); + printk(KERN_ALERT + "md: md%d: unsupported raid array version %d.%d.%d\n", + mdidx(mddev), mddev->major_version, + mddev->minor_version, mddev->patch_version); goto abort; } if ((mddev->recovery_cp != MaxSector) && ((mddev->level == 1) || (mddev->level == 4) || (mddev->level == 5))) - printk(NOT_CLEAN_IGNORE, mdidx(mddev)); + printk(KERN_ERR "md: md%d: raid array is not clean" + " -- starting background reconstruction\n", + mdidx(mddev)); return 0; abort: return 1; } -#undef INCONSISTENT -#undef OUT_OF_DATE -#undef OLD_VERSION -#undef OLD_LEVEL - static int device_size_calculation(mddev_t * mddev) { int data_disks = 0; @@ -1484,9 +1471,11 @@ continue; if (rdev->size < mddev->chunk_size / 1024) { printk(KERN_WARNING - "md: Dev %s smaller than chunk_size: %lluk < %dk\n", + "md: Dev %s smaller than chunk_size:" + " %lluk < %dk\n", bdev_partition_name(rdev->bdev), - (unsigned long long)rdev->size, mddev->chunk_size / 1024); + (unsigned long long)rdev->size, + mddev->chunk_size / 1024); return -EINVAL; } } @@ -1517,7 +1506,8 @@ data_disks = mddev->raid_disks-1; break; default: - printk(UNKNOWN_LEVEL, mdidx(mddev), mddev->level); + printk(KERN_ERR "md: md%d: unsupported raid level %d\n", + mdidx(mddev), mddev->level); goto abort; } if (!md_size[mdidx(mddev)]) @@ -1539,7 +1529,7 @@ printk(KERN_INFO "md%d: %d data-disks, max readahead per data-disk: %ldk\n", - mdidx(mddev), data_disks, readahead/data_disks*(PAGE_SIZE/1024)); + mdidx(mddev), data_disks, readahead/data_disks*(PAGE_SIZE/1024)); return 0; abort: return 1; @@ -1589,14 +1579,6 @@ md_wakeup_thread(mddev->thread); } -#define TOO_BIG_CHUNKSIZE KERN_ERR \ -"too big chunk_size: %d > %d\n" - -#define TOO_SMALL_CHUNKSIZE KERN_ERR \ -"too small chunk_size: %d < %ld\n" - -#define BAD_CHUNKSIZE KERN_ERR \ -"no chunksize specified, see 'man raidtab'\n" static int do_md_run(mddev_t * mddev) { @@ -1639,11 +1621,13 @@ * we abort here to be on the safe side. We don't * want to continue the bad practice. */ - printk(BAD_CHUNKSIZE); + printk(KERN_ERR + "no chunksize specified, see 'man raidtab'\n"); return -EINVAL; } if (chunk_size > MAX_CHUNK_SIZE) { - printk(TOO_BIG_CHUNKSIZE, chunk_size, MAX_CHUNK_SIZE); + printk(KERN_ERR "too big chunk_size: %d > %d\n", + chunk_size, MAX_CHUNK_SIZE); return -EINVAL; } /* @@ -1654,7 +1638,8 @@ return -EINVAL; } if (chunk_size < PAGE_SIZE) { - printk(TOO_SMALL_CHUNKSIZE, chunk_size, PAGE_SIZE); + printk(KERN_ERR "too small chunk_size: %d < %ld\n", + chunk_size, PAGE_SIZE); return -EINVAL; } } @@ -1664,20 +1649,14 @@ return -EINVAL; } +#ifdef CONFIG_KMOD if (!pers[pnum]) { -#ifdef CONFIG_KMOD char module_name[80]; sprintf (module_name, "md-personality-%d", pnum); request_module (module_name); - if (!pers[pnum]) -#endif - { - printk(KERN_ERR "md: personality %d is not loaded!\n", - pnum); - return -EINVAL; - } } +#endif if (device_size_calculation(mddev)) return -EINVAL; @@ -1711,13 +1690,23 @@ disk = disks[mdidx(mddev)]; if (!disk) return -ENOMEM; + + spin_lock(&pers_lock); + if (!pers[pnum] || !try_module_get(pers[pnum]->owner)) { + spin_unlock(&pers_lock); + printk(KERN_ERR "md: personality %d is not loaded!\n", + pnum); + return -EINVAL; + } + mddev->pers = pers[pnum]; + spin_unlock(&pers_lock); blk_queue_make_request(&mddev->queue, mddev->pers->make_request); printk("%s: setting max_sectors to %d, segment boundary to %d\n", - disk->disk_name, - chunk_size >> 9, - (chunk_size>>1)-1); + disk->disk_name, + chunk_size >> 9, + (chunk_size>>1)-1); blk_queue_max_sectors(&mddev->queue, chunk_size >> 9); blk_queue_segment_boundary(&mddev->queue, (chunk_size>>1) - 1); mddev->queue.queuedata = mddev; @@ -1726,6 +1715,7 @@ if (err) { printk(KERN_ERR "md: pers->run() failed ...\n"); mddev->pers = NULL; + module_put(mddev->pers->owner); return -EINVAL; } atomic_set(&mddev->writes_pending,0); @@ -1741,9 +1731,6 @@ return (0); } -#undef TOO_BIG_CHUNKSIZE -#undef BAD_CHUNKSIZE - static int restart_array(mddev_t *mddev) { struct gendisk *disk = disks[mdidx(mddev)]; @@ -1765,8 +1752,8 @@ mddev->ro = 0; set_disk_ro(disk, 0); - printk(KERN_INFO - "md: md%d switched to read-write mode.\n", mdidx(mddev)); + printk(KERN_INFO "md: md%d switched to read-write mode.\n", + mdidx(mddev)); /* * Kick recovery or resync if necessary */ @@ -1783,18 +1770,13 @@ return err; } -#define STILL_MOUNTED KERN_WARNING \ -"md: md%d still mounted.\n" -#define STILL_IN_USE \ -"md: md%d still in use.\n" - static int do_md_stop(mddev_t * mddev, int ro) { int err = 0; struct gendisk *disk = disks[mdidx(mddev)]; if (atomic_read(&mddev->active)>2) { - printk(STILL_IN_USE, mdidx(mddev)); + printk("md: md%d still in use.\n",mdidx(mddev)); err = -EBUSY; goto out; } @@ -1824,6 +1806,7 @@ set_disk_ro(disk, 1); goto out; } + module_put(mddev->pers->owner); mddev->pers = NULL; if (mddev->ro) mddev->ro = 0; @@ -1850,7 +1833,8 @@ if (disk) set_capacity(disk, 0); } else - printk(KERN_INFO "md: md%d switched to read-only mode.\n", mdidx(mddev)); + printk(KERN_INFO "md: md%d switched to read-only mode.\n", + mdidx(mddev)); err = 0; out: return err; @@ -1905,11 +1889,13 @@ rdev0 = list_entry(pending_raid_disks.next, mdk_rdev_t, same_set); - printk(KERN_INFO "md: considering %s ...\n", bdev_partition_name(rdev0->bdev)); + printk(KERN_INFO "md: considering %s ...\n", + bdev_partition_name(rdev0->bdev)); INIT_LIST_HEAD(&candidates); ITERATE_RDEV_PENDING(rdev,tmp) if (super_90_load(rdev, rdev0, 0) >= 0) { - printk(KERN_INFO "md: adding %s ...\n", bdev_partition_name(rdev->bdev)); + printk(KERN_INFO "md: adding %s ...\n", + bdev_partition_name(rdev->bdev)); list_move(&rdev->same_set, &candidates); } /* @@ -1920,7 +1906,8 @@ mddev = mddev_find(rdev0->preferred_minor); if (!mddev) { - printk(KERN_ERR "md: cannot allocate memory for md drive.\n"); + printk(KERN_ERR + "md: cannot allocate memory for md drive.\n"); break; } if (mddev_lock(mddev)) @@ -1928,8 +1915,9 @@ mdidx(mddev)); else if (mddev->raid_disks || mddev->major_version || !list_empty(&mddev->disks)) { - printk(KERN_WARNING "md: md%d already running, cannot run %s\n", - mdidx(mddev), bdev_partition_name(rdev0->bdev)); + printk(KERN_WARNING + "md: md%d already running, cannot run %s\n", + mdidx(mddev), bdev_partition_name(rdev0->bdev)); mddev_unlock(mddev); } else { printk(KERN_INFO "md: created md%d\n", mdidx(mddev)); @@ -1956,33 +1944,6 @@ * if possible, the array gets run as well. */ -#define BAD_VERSION KERN_ERR \ -"md: %s has RAID superblock version 0.%d, autodetect needs v0.90 or higher\n" - -#define OUT_OF_MEM KERN_ALERT \ -"md: out of memory.\n" - -#define NO_DEVICE KERN_ERR \ -"md: disabled device %s\n" - -#define AUTOADD_FAILED KERN_ERR \ -"md: auto-adding devices to md%d FAILED (error %d).\n" - -#define AUTOADD_FAILED_USED KERN_ERR \ -"md: cannot auto-add device %s to md%d, already used.\n" - -#define AUTORUN_FAILED KERN_ERR \ -"md: auto-running md%d FAILED (error %d).\n" - -#define MDDEV_BUSY KERN_ERR \ -"md: cannot auto-add to md%d, already running.\n" - -#define AUTOADDING KERN_INFO \ -"md: auto-adding devices to md%d, based on %s's superblock.\n" - -#define AUTORUNNING KERN_INFO \ -"md: auto-running md%d.\n" - static int autostart_array(dev_t startdev) { int err = -EINVAL, i; @@ -1991,7 +1952,8 @@ start_rdev = md_import_device(startdev, 0, 0); if (IS_ERR(start_rdev)) { - printk(KERN_WARNING "md: could not import %s!\n", partition_name(startdev)); + printk(KERN_WARNING "md: could not import %s!\n", + partition_name(startdev)); return err; } @@ -2005,8 +1967,9 @@ } if (start_rdev->faulty) { - printk(KERN_WARNING "md: can not autostart based on faulty %s!\n", - bdev_partition_name(start_rdev->bdev)); + printk(KERN_WARNING + "md: can not autostart based on faulty %s!\n", + bdev_partition_name(start_rdev->bdev)); export_rdev(start_rdev); return err; } @@ -2025,8 +1988,9 @@ continue; rdev = md_import_device(dev, 0, 0); if (IS_ERR(rdev)) { - printk(KERN_WARNING "md: could not import %s, trying to run array nevertheless.\n", - partition_name(dev)); + printk(KERN_WARNING "md: could not import %s," + " trying to run array nevertheless.\n", + partition_name(dev)); continue; } list_add(&rdev->same_set, &pending_raid_disks); @@ -2040,15 +2004,6 @@ } -#undef BAD_VERSION -#undef OUT_OF_MEM -#undef NO_DEVICE -#undef AUTOADD_FAILED_USED -#undef AUTOADD_FAILED -#undef AUTORUN_FAILED -#undef AUTOADDING -#undef AUTORUNNING - static int get_version(void * arg) { @@ -2113,8 +2068,6 @@ return 0; } -#undef SET_FROM_SB - static int get_disk_info(mddev_t * mddev, void * arg) { @@ -2161,7 +2114,9 @@ /* expecting a device which has a superblock */ rdev = md_import_device(dev, mddev->major_version, mddev->minor_version); if (IS_ERR(rdev)) { - printk(KERN_WARNING "md: md_import_device returned %ld\n", PTR_ERR(rdev)); + printk(KERN_WARNING + "md: md_import_device returned %ld\n", + PTR_ERR(rdev)); return PTR_ERR(rdev); } if (!list_empty(&mddev->disks)) { @@ -2170,8 +2125,10 @@ int err = super_types[mddev->major_version] .load_super(rdev, rdev0, mddev->minor_version); if (err < 0) { - printk(KERN_WARNING "md: %s has different UUID to %s\n", - bdev_partition_name(rdev->bdev), bdev_partition_name(rdev0->bdev)); + printk(KERN_WARNING + "md: %s has different UUID to %s\n", + bdev_partition_name(rdev->bdev), + bdev_partition_name(rdev0->bdev)); export_rdev(rdev); return -EINVAL; } @@ -2190,14 +2147,17 @@ if (mddev->pers) { int err; if (!mddev->pers->hot_add_disk) { - printk(KERN_WARNING "md%d: personality does not support diskops!\n", + printk(KERN_WARNING + "md%d: personality does not support diskops!\n", mdidx(mddev)); return -EINVAL; } rdev = md_import_device(dev, mddev->major_version, mddev->minor_version); if (IS_ERR(rdev)) { - printk(KERN_WARNING "md: md_import_device returned %ld\n", PTR_ERR(rdev)); + printk(KERN_WARNING + "md: md_import_device returned %ld\n", + PTR_ERR(rdev)); return PTR_ERR(rdev); } rdev->in_sync = 0; /* just to be sure */ @@ -2223,7 +2183,9 @@ int err; rdev = md_import_device (dev, -1, 0); if (IS_ERR(rdev)) { - printk(KERN_WARNING "md: error, md_import_device() returned %ld\n", PTR_ERR(rdev)); + printk(KERN_WARNING + "md: error, md_import_device() returned %ld\n", + PTR_ERR(rdev)); return PTR_ERR(rdev); } rdev->desc_nr = info->number; @@ -2333,19 +2295,23 @@ partition_name(dev), mdidx(mddev)); if (mddev->major_version != 0) { - printk(KERN_WARNING "md%d: HOT_ADD may only be used with version-0 superblocks.\n", - mdidx(mddev)); + printk(KERN_WARNING "md%d: HOT_ADD may only be used with" + " version-0 superblocks.\n", + mdidx(mddev)); return -EINVAL; } if (!mddev->pers->hot_add_disk) { - printk(KERN_WARNING "md%d: personality does not support diskops!\n", - mdidx(mddev)); + printk(KERN_WARNING + "md%d: personality does not support diskops!\n", + mdidx(mddev)); return -EINVAL; } rdev = md_import_device (dev, -1, 0); if (IS_ERR(rdev)) { - printk(KERN_WARNING "md: error, md_import_device() returned %ld\n", PTR_ERR(rdev)); + printk(KERN_WARNING + "md: error, md_import_device() returned %ld\n", + PTR_ERR(rdev)); return -EINVAL; } @@ -2354,16 +2320,18 @@ rdev->size = size; if (size < mddev->size) { - printk(KERN_WARNING "md%d: disk size %llu blocks < array size %llu\n", - mdidx(mddev), (unsigned long long)size, - (unsigned long long)mddev->size); + printk(KERN_WARNING + "md%d: disk size %llu blocks < array size %llu\n", + mdidx(mddev), (unsigned long long)size, + (unsigned long long)mddev->size); err = -ENOSPC; goto abort_export; } if (rdev->faulty) { - printk(KERN_WARNING "md: can not hot-add faulty %s disk to md%d!\n", - bdev_partition_name(rdev->bdev), mdidx(mddev)); + printk(KERN_WARNING + "md: can not hot-add faulty %s disk to md%d!\n", + bdev_partition_name(rdev->bdev), mdidx(mddev)); err = -EINVAL; goto abort_export; } @@ -2378,7 +2346,7 @@ if (rdev->desc_nr == mddev->max_disks) { printk(KERN_WARNING "md%d: can not hot-add to full array!\n", - mdidx(mddev)); + mdidx(mddev)); err = -EBUSY; goto abort_unbind_export; } @@ -2426,8 +2394,9 @@ info->major_version >= sizeof(super_types)/sizeof(super_types[0]) || super_types[info->major_version].name == NULL) { /* maybe try to auto-load a module? */ - printk(KERN_INFO "md: superblock version %d not known\n", - info->major_version); + printk(KERN_INFO + "md: superblock version %d not known\n", + info->major_version); return -EINVAL; } mddev->major_version = info->major_version; @@ -2540,7 +2509,7 @@ err = autostart_array(arg); if (err) { printk(KERN_WARNING "md: autostart %s failed!\n", - partition_name(arg)); + partition_name(arg)); goto abort; } goto done; @@ -2548,8 +2517,9 @@ err = mddev_lock(mddev); if (err) { - printk(KERN_INFO "md: ioctl lock interrupted, reason %d, cmd %d\n", - err, cmd); + printk(KERN_INFO + "md: ioctl lock interrupted, reason %d, cmd %d\n", + err, cmd); goto abort; } @@ -2558,13 +2528,15 @@ case SET_ARRAY_INFO: if (!list_empty(&mddev->disks)) { - printk(KERN_WARNING "md: array md%d already has disks!\n", + printk(KERN_WARNING + "md: array md%d already has disks!\n", mdidx(mddev)); err = -EBUSY; goto abort_unlock; } if (mddev->raid_disks) { - printk(KERN_WARNING "md: array md%d already initialised!\n", + printk(KERN_WARNING + "md: array md%d already initialised!\n", mdidx(mddev)); err = -EBUSY; goto abort_unlock; @@ -2579,7 +2551,8 @@ } err = set_array_info(mddev, &info); if (err) { - printk(KERN_WARNING "md: couldn't set array info. %d\n", err); + printk(KERN_WARNING "md: couldn't set" + " array info. %d\n", err); goto abort_unlock; } } @@ -2701,9 +2674,10 @@ default: if (_IOC_TYPE(cmd) == MD_MAJOR) - printk(KERN_WARNING "md: %s(pid %d) used obsolete MD ioctl, " - "upgrade your software to use new ictls.\n", - current->comm, current->pid); + printk(KERN_WARNING "md: %s(pid %d) used" + " obsolete MD ioctl, upgrade your" + " software to use new ictls.\n", + current->comm, current->pid); err = -EINVAL; goto abort_unlock; } @@ -2879,7 +2853,8 @@ void md_error(mddev_t *mddev, mdk_rdev_t *rdev) { dprintk("md_error dev:(%d:%d), rdev:(%d:%d), (caller: %p,%p,%p,%p).\n", - MD_MAJOR,mdidx(mddev),MAJOR(rdev->bdev->bd_dev),MINOR(rdev->bdev->bd_dev), + MD_MAJOR,mdidx(mddev), + MAJOR(rdev->bdev->bd_dev), MINOR(rdev->bdev->bd_dev), __builtin_return_address(0),__builtin_return_address(1), __builtin_return_address(2),__builtin_return_address(3)); @@ -3038,10 +3013,12 @@ if (v == (void*)1) { seq_printf(seq, "Personalities : "); + spin_lock(&pers_lock); for (i = 0; i < MAX_PERSONALITY; i++) if (pers[i]) seq_printf(seq, "[%s] ", pers[i]->name); + spin_unlock(&pers_lock); seq_printf(seq, "\n"); return 0; } @@ -3125,13 +3102,16 @@ return -EINVAL; } + spin_lock(&pers_lock); if (pers[pnum]) { + spin_unlock(&pers_lock); MD_BUG(); return -EBUSY; } pers[pnum] = p; printk(KERN_INFO "md: %s personality registered as nr %d\n", p->name, pnum); + spin_unlock(&pers_lock); return 0; } @@ -3143,7 +3123,9 @@ } printk(KERN_INFO "md: %s personality unregistered\n", pers[pnum]->name); + spin_lock(&pers_lock); pers[pnum] = NULL; + spin_unlock(&pers_lock); return 0; } @@ -3228,7 +3210,8 @@ void md_handle_safemode(mddev_t *mddev) { if (signal_pending(current)) { - printk(KERN_INFO "md: md%d in immediate safe mode\n",mdidx(mddev)); + printk(KERN_INFO "md: md%d in immediate safe mode\n", + mdidx(mddev)); mddev->safemode = 2; flush_signals(current); } @@ -3271,8 +3254,9 @@ continue; if (mddev2->curr_resync && match_mddev_units(mddev,mddev2)) { - printk(KERN_INFO "md: delaying resync of md%d until md%d " - "has finished resync (they share one or more physical units)\n", + printk(KERN_INFO "md: delaying resync of md%d" + " until md%d has finished resync (they" + " share one or more physical units)\n", mdidx(mddev), mdidx(mddev2)); if (mddev < mddev2) {/* arbitrarily yield */ mddev->curr_resync = 1; @@ -3295,7 +3279,8 @@ max_sectors = mddev->size << 1; printk(KERN_INFO "md: syncing RAID array md%d\n", mdidx(mddev)); - printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed: %d KB/sec/disc.\n", sysctl_speed_limit_min); + printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed:" + " %d KB/sec/disc.\n", sysctl_speed_limit_min); printk(KERN_INFO "md: using maximum available idle IO bandwith " "(but not more than %d KB/sec) for reconstruction.\n", sysctl_speed_limit_max); @@ -3318,14 +3303,16 @@ */ window = 32*(PAGE_SIZE/512); printk(KERN_INFO "md: using %dk window, over a total of %d blocks.\n", - window/2,max_sectors/2); + window/2,max_sectors/2); atomic_set(&mddev->recovery_active, 0); init_waitqueue_head(&mddev->recovery_wait); last_check = 0; if (j) - printk(KERN_INFO "md: resuming recovery of md%d from checkpoint.\n", mdidx(mddev)); + printk(KERN_INFO + "md: resuming recovery of md%d from checkpoint.\n", + mdidx(mddev)); while (j < max_sectors) { int sectors; @@ -3367,7 +3354,8 @@ /* * got a signal, exit. */ - printk(KERN_INFO "md: md_do_sync() got signal ... exiting\n"); + printk(KERN_INFO + "md: md_do_sync() got signal ... exiting\n"); flush_signals(current); set_bit(MD_RECOVERY_INTR, &mddev->recovery); goto out; @@ -3408,7 +3396,9 @@ mddev->curr_resync > 2 && mddev->curr_resync > mddev->recovery_cp) { if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { - printk(KERN_INFO "md: checkpointing recovery of md%d.\n", mdidx(mddev)); + printk(KERN_INFO + "md: checkpointing recovery of md%d.\n", + mdidx(mddev)); mddev->recovery_cp = mddev->curr_resync; } else mddev->recovery_cp = MaxSector; @@ -3526,7 +3516,9 @@ mddev, "md%d_resync"); if (!mddev->sync_thread) { - printk(KERN_ERR "md%d: could not start resync thread...\n", mdidx(mddev)); + printk(KERN_ERR "md%d: could not start resync" + " thread...\n", + mdidx(mddev)); /* leave the spares where they are, it shouldn't hurt */ mddev->recovery = 0; } else { @@ -3590,7 +3582,8 @@ { int minor; - printk(KERN_INFO "md: md driver %d.%d.%d MAX_MD_DEVS=%d, MD_SB_DISKS=%d\n", + printk(KERN_INFO "md: md driver %d.%d.%d MAX_MD_DEVS=%d," + " MD_SB_DISKS=%d\n", MD_MAJOR_VERSION, MD_MINOR_VERSION, MD_PATCHLEVEL_VERSION, MAX_MD_DEVS, MD_SB_DISKS); diff -Nru a/drivers/md/multipath.c b/drivers/md/multipath.c --- a/drivers/md/multipath.c Wed Apr 2 22:24:05 2003 +++ b/drivers/md/multipath.c Wed Apr 2 22:24:05 2003 @@ -78,7 +78,7 @@ } spin_unlock_irq(&conf->device_lock); - printk (KERN_ERR "multipath_map(): no more operational IO paths?\n"); + printk(KERN_ERR "multipath_map(): no more operational IO paths?\n"); return (-1); } @@ -130,7 +130,8 @@ */ md_error (mp_bh->mddev, rdev); printk(KERN_ERR "multipath: %s: rescheduling sector %llu\n", - bdev_partition_name(rdev->bdev), (unsigned long long)bio->bi_sector); + bdev_partition_name(rdev->bdev), + (unsigned long long)bio->bi_sector); multipath_reschedule_retry(mp_bh); } atomic_dec(&rdev->nr_pending); @@ -198,16 +199,6 @@ seq_printf (seq, "]"); } -#define LAST_DISK KERN_ALERT \ -"multipath: only one IO path left and IO error.\n" - -#define NO_SPARE_DISK KERN_ALERT \ -"multipath: no spare IO path left!\n" - -#define DISK_FAILED KERN_ALERT \ -"multipath: IO failure on %s, disabling IO path. \n" \ -" Operation continuing on %d IO paths.\n" - /* * Careful, this can execute in IRQ contexts as well! @@ -222,7 +213,8 @@ * first check if this is a queued request for a device * which has just failed. */ - printk (LAST_DISK); + printk(KERN_ALERT + "multipath: only one IO path left and IO error.\n"); /* leave it active... it's all we have */ } else { /* @@ -233,17 +225,15 @@ rdev->faulty = 1; mddev->sb_dirty = 1; conf->working_disks--; - printk (DISK_FAILED, bdev_partition_name (rdev->bdev), + printk(KERN_ALERT "multipath: IO failure on %s," + " disabling IO path. \n Operation continuing" + " on %d IO paths.\n", + bdev_partition_name (rdev->bdev), conf->working_disks); } } } -#undef LAST_DISK -#undef NO_SPARE_DISK -#undef DISK_FAILED - - static void print_multipath_conf (multipath_conf_t *conf) { int i; @@ -302,7 +292,7 @@ if (p->rdev) { if (p->rdev->in_sync || atomic_read(&p->rdev->nr_pending)) { - printk(KERN_ERR "hot-remove-disk, slot %d is identified but is still operational!\n", number); + printk(KERN_ERR "hot-remove-disk, slot %d is identified" " but is still operational!\n", number); err = -EBUSY; goto abort; } @@ -318,11 +308,7 @@ return err; } -#define IO_ERROR KERN_ALERT \ -"multipath: %s: unrecoverable IO read error for block %llu\n" -#define REDIRECT_SECTOR KERN_ERR \ -"multipath: %s: redirecting sector %llu to another IO path\n" /* * This is a kernel thread which: @@ -354,59 +340,22 @@ rdev = NULL; if (multipath_map (mddev, &rdev)<0) { - printk(IO_ERROR, - bdev_partition_name(bio->bi_bdev), (unsigned long long)bio->bi_sector); + printk(KERN_ALERT "multipath: %s: unrecoverable IO read" + " error for block %llu\n", + bdev_partition_name(bio->bi_bdev), + (unsigned long long)bio->bi_sector); multipath_end_bh_io(mp_bh, 0); } else { - printk(REDIRECT_SECTOR, - bdev_partition_name(bio->bi_bdev), (unsigned long long)bio->bi_sector); + printk(KERN_ERR "multipath: %s: redirecting sector %llu" + " to another IO path\n", + bdev_partition_name(bio->bi_bdev), + (unsigned long long)bio->bi_sector); bio->bi_bdev = rdev->bdev; generic_make_request(bio); } } spin_unlock_irqrestore(&retry_list_lock, flags); } -#undef IO_ERROR -#undef REDIRECT_SECTOR - -#define INVALID_LEVEL KERN_WARNING \ -"multipath: md%d: raid level not set to multipath IO (%d)\n" - -#define NO_SB KERN_ERR \ -"multipath: disabled IO path %s (couldn't access raid superblock)\n" - -#define ERRORS KERN_ERR \ -"multipath: disabled IO path %s (errors detected)\n" - -#define NOT_IN_SYNC KERN_ERR \ -"multipath: making IO path %s a spare path (not in sync)\n" - -#define INCONSISTENT KERN_ERR \ -"multipath: disabled IO path %s (inconsistent descriptor)\n" - -#define ALREADY_RUNNING KERN_ERR \ -"multipath: disabled IO path %s (multipath %d already operational)\n" - -#define OPERATIONAL KERN_INFO \ -"multipath: device %s operational as IO path %d\n" - -#define MEM_ERROR KERN_ERR \ -"multipath: couldn't allocate memory for md%d\n" - -#define SPARE KERN_INFO \ -"multipath: spare IO path %s\n" - -#define NONE_OPERATIONAL KERN_ERR \ -"multipath: no operational IO paths for md%d\n" - -#define SB_DIFFERENCES KERN_ERR \ -"multipath: detected IO path differences!\n" - -#define ARRAY_IS_ACTIVE KERN_INFO \ -"multipath: array md%d active with %d out of %d IO paths\n" - -#define THREAD_ERROR KERN_ERR \ -"multipath: couldn't allocate thread for md%d\n" static int multipath_run (mddev_t *mddev) { @@ -416,10 +365,9 @@ mdk_rdev_t *rdev; struct list_head *tmp; - MOD_INC_USE_COUNT; - if (mddev->level != LEVEL_MULTIPATH) { - printk(INVALID_LEVEL, mdidx(mddev), mddev->level); + printk("multipath: md%d: raid level not set to multipath IO (%d)\n", + mdidx(mddev), mddev->level); goto out; } /* @@ -431,7 +379,9 @@ conf = kmalloc(sizeof(multipath_conf_t), GFP_KERNEL); mddev->private = conf; if (!conf) { - printk(MEM_ERROR, mdidx(mddev)); + printk(KERN_ERR + "multipath: couldn't allocate memory for md%d\n", + mdidx(mddev)); goto out; } memset(conf, 0, sizeof(*conf)); @@ -455,7 +405,8 @@ conf->device_lock = SPIN_LOCK_UNLOCKED; if (!conf->working_disks) { - printk(NONE_OPERATIONAL, mdidx(mddev)); + printk(KERN_ERR "multipath: no operational IO paths for md%d\n", + mdidx(mddev)); goto out_free_conf; } mddev->degraded = conf->raid_disks = conf->working_disks; @@ -464,7 +415,9 @@ mp_pool_alloc, mp_pool_free, NULL); if (conf->pool == NULL) { - printk(MEM_ERROR, mdidx(mddev)); + printk(KERN_ERR + "multipath: couldn't allocate memory for md%d\n", + mdidx(mddev)); goto out_free_conf; } @@ -473,13 +426,15 @@ mddev->thread = md_register_thread(multipathd, mddev, name); if (!mddev->thread) { - printk(THREAD_ERROR, mdidx(mddev)); + printk(KERN_ERR "multipath: couldn't allocate thread" + " for md%d\n", mdidx(mddev)); goto out_free_conf; } } - printk(ARRAY_IS_ACTIVE, mdidx(mddev), conf->working_disks, - mddev->raid_disks); + printk(KERN_INFO + "multipath: array md%d active with %d out of %d IO paths\n", + mdidx(mddev), conf->working_disks, mddev->raid_disks); /* * Ok, everything is just fine now */ @@ -491,21 +446,9 @@ kfree(conf); mddev->private = NULL; out: - MOD_DEC_USE_COUNT; return -EIO; } -#undef INVALID_LEVEL -#undef NO_SB -#undef ERRORS -#undef NOT_IN_SYNC -#undef INCONSISTENT -#undef ALREADY_RUNNING -#undef OPERATIONAL -#undef SPARE -#undef NONE_OPERATIONAL -#undef SB_DIFFERENCES -#undef ARRAY_IS_ACTIVE static int multipath_stop (mddev_t *mddev) { @@ -515,13 +458,13 @@ mempool_destroy(conf->pool); kfree(conf); mddev->private = NULL; - MOD_DEC_USE_COUNT; return 0; } static mdk_personality_t multipath_personality= { .name = "multipath", + .owner = THIS_MODULE, .make_request = multipath_make_request, .run = multipath_run, .stop = multipath_stop, diff -Nru a/drivers/md/raid0.c b/drivers/md/raid0.c --- a/drivers/md/raid0.c Wed Apr 2 22:24:05 2003 +++ b/drivers/md/raid0.c Wed Apr 2 22:24:05 2003 @@ -43,12 +43,15 @@ conf->nr_strip_zones = 0; ITERATE_RDEV(mddev,rdev1,tmp1) { - printk("raid0: looking at %s\n", bdev_partition_name(rdev1->bdev)); + printk("raid0: looking at %s\n", + bdev_partition_name(rdev1->bdev)); c = 0; ITERATE_RDEV(mddev,rdev2,tmp2) { printk("raid0: comparing %s(%llu) with %s(%llu)\n", - bdev_partition_name(rdev1->bdev), (unsigned long long)rdev1->size, - bdev_partition_name(rdev2->bdev), (unsigned long long)rdev2->size); + bdev_partition_name(rdev1->bdev), + (unsigned long long)rdev1->size, + bdev_partition_name(rdev2->bdev), + (unsigned long long)rdev2->size); if (rdev2 == rdev1) { printk("raid0: END\n"); break; @@ -94,7 +97,8 @@ goto abort; } if (zone->dev[j]) { - printk("raid0: multiple devices for %d - aborting!\n", j); + printk("raid0: multiple devices for %d - aborting!\n", + j); goto abort; } zone->dev[j] = rdev1; @@ -103,8 +107,8 @@ cnt++; } if (cnt != mddev->raid_disks) { - printk("raid0: too few disks (%d of %d) - aborting!\n", cnt, - mddev->raid_disks); + printk("raid0: too few disks (%d of %d) - aborting!\n", + cnt, mddev->raid_disks); goto abort; } zone->nb_dev = cnt; @@ -136,7 +140,7 @@ if (!smallest || (rdev->size size)) { smallest = rdev; printk(" (%llu) is smallest!.\n", - (unsigned long long)rdev->size); + (unsigned long long)rdev->size); } } else printk(" nope.\n"); @@ -144,7 +148,8 @@ zone->nb_dev = c; zone->size = (smallest->size - current_offset) * c; - printk("raid0: zone->nb_dev: %d, size: %llu\n",zone->nb_dev, (unsigned long long)zone->size); + printk("raid0: zone->nb_dev: %d, size: %llu\n", + zone->nb_dev, (unsigned long long)zone->size); if (!conf->smallest || (zone->size < conf->smallest->size)) conf->smallest = zone; @@ -153,7 +158,8 @@ curr_zone_offset += zone->size; current_offset = smallest->size; - printk("raid0: current zone offset: %llu\n", (unsigned long long)current_offset); + printk("raid0: current zone offset: %llu\n", + (unsigned long long)current_offset); } printk("raid0: done.\n"); return 0; @@ -191,8 +197,6 @@ s64 size; raid0_conf_t *conf; - MOD_INC_USE_COUNT; - conf = vmalloc(sizeof (raid0_conf_t)); if (!conf) goto out; @@ -201,8 +205,10 @@ if (create_strip_zones (mddev)) goto out_free_conf; - printk("raid0 : md_size is %llu blocks.\n", (unsigned long long)md_size[mdidx(mddev)]); - printk("raid0 : conf->smallest->size is %llu blocks.\n", (unsigned long long)conf->smallest->size); + printk("raid0 : md_size is %llu blocks.\n", + (unsigned long long)md_size[mdidx(mddev)]); + printk("raid0 : conf->smallest->size is %llu blocks.\n", + (unsigned long long)conf->smallest->size); { #if __GNUC__ < 3 volatile @@ -267,7 +273,6 @@ vfree(conf); mddev->private = NULL; out: - MOD_DEC_USE_COUNT; return 1; } @@ -282,7 +287,6 @@ vfree (conf); mddev->private = NULL; - MOD_DEC_USE_COUNT; return 0; } @@ -357,16 +361,21 @@ return 1; bad_map: - printk ("raid0_make_request bug: can't convert block across chunks or bigger than %dk %llu %d\n", chunk_size, (unsigned long long)bio->bi_sector, bio->bi_size >> 10); + printk("raid0_make_request bug: can't convert block across chunks" + " or bigger than %dk %llu %d\n", chunk_size, + (unsigned long long)bio->bi_sector, bio->bi_size >> 10); goto outerr; bad_hash: - printk("raid0_make_request bug: hash==NULL for block %llu\n", (unsigned long long)block); + printk("raid0_make_request bug: hash==NULL for block %llu\n", + (unsigned long long)block); goto outerr; bad_zone0: - printk ("raid0_make_request bug: hash->zone0==NULL for block %llu\n", (unsigned long long)block); + printk("raid0_make_request bug: hash->zone0==NULL for block %llu\n", + (unsigned long long)block); goto outerr; bad_zone1: - printk ("raid0_make_request bug: hash->zone1==NULL for block %llu\n", (unsigned long long)block); + printk("raid0_make_request bug: hash->zone1==NULL for block %llu\n", + (unsigned long long)block); outerr: bio_io_error(bio, bio->bi_size); return 0; @@ -411,6 +420,7 @@ static mdk_personality_t raid0_personality= { .name = "raid0", + .owner = THIS_MODULE, .make_request = raid0_make_request, .run = raid0_run, .stop = raid0_stop, diff -Nru a/drivers/md/raid1.c b/drivers/md/raid1.c --- a/drivers/md/raid1.c Wed Apr 2 22:24:05 2003 +++ b/drivers/md/raid1.c Wed Apr 2 22:24:05 2003 @@ -217,7 +217,7 @@ } spin_unlock_irq(&conf->device_lock); - printk (KERN_ERR "raid1_map(): huh, no more operational devices?\n"); + printk(KERN_ERR "raid1_map(): huh, no more operational devices?\n"); return -1; } @@ -305,7 +305,7 @@ * oops, read error: */ printk(KERN_ERR "raid1: %s: rescheduling sector %llu\n", - bdev_partition_name(conf->mirrors[mirror].rdev->bdev), (unsigned long long)r1_bio->sector); + bdev_partition_name(conf->mirrors[mirror].rdev->bdev), (unsigned long long)r1_bio->sector); reschedule_retry(r1_bio); } } else { @@ -584,22 +584,6 @@ seq_printf(seq, "]"); } -#define LAST_DISK KERN_ALERT \ -"raid1: only one disk left and IO error.\n" - -#define NO_SPARE_DISK KERN_ALERT \ -"raid1: no spare disk left, degrading mirror level by one.\n" - -#define DISK_FAILED KERN_ALERT \ -"raid1: Disk failure on %s, disabling device. \n" \ -" Operation continuing on %d devices\n" - -#define START_SYNCING KERN_ALERT \ -"raid1: start syncing spare disk.\n" - -#define ALREADY_SYNCING KERN_INFO \ -"raid1: syncing already in progress.\n" - static void error(mddev_t *mddev, mdk_rdev_t *rdev) { @@ -629,7 +613,9 @@ rdev->in_sync = 0; rdev->faulty = 1; mddev->sb_dirty = 1; - printk(DISK_FAILED, bdev_partition_name(rdev->bdev), conf->working_disks); + printk(KERN_ALERT "raid1: Disk failure on %s, disabling device. \n" + " Operation continuing on %d devices\n", + bdev_partition_name(rdev->bdev), conf->working_disks); } static void print_conf(conf_t *conf) @@ -643,14 +629,14 @@ return; } printk(" --- wd:%d rd:%d\n", conf->working_disks, - conf->raid_disks); + conf->raid_disks); for (i = 0; i < conf->raid_disks; i++) { tmp = conf->mirrors + i; if (tmp->rdev) printk(" disk %d, wo:%d, o:%d, dev:%s\n", - i, !tmp->rdev->in_sync, !tmp->rdev->faulty, - bdev_partition_name(tmp->rdev->bdev)); + i, !tmp->rdev->in_sync, !tmp->rdev->faulty, + bdev_partition_name(tmp->rdev->bdev)); } } @@ -743,11 +729,6 @@ return err; } -#define IO_ERROR KERN_ALERT \ -"raid1: %s: unrecoverable I/O read error for block %llu\n" - -#define REDIRECT_SECTOR KERN_ERR \ -"raid1: %s: redirecting sector %llu to another mirror\n" static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error) { @@ -823,7 +804,10 @@ * There is no point trying a read-for-reconstruct as * reconstruct is about to be aborted */ - printk(IO_ERROR, bdev_partition_name(bio->bi_bdev), (unsigned long long)r1_bio->sector); + printk(KERN_ALERT "raid1: %s: unrecoverable I/O read error" + " for block %llu\n", + bdev_partition_name(bio->bi_bdev), + (unsigned long long)r1_bio->sector); md_done_sync(mddev, r1_bio->master_bio->bi_size >> 9, 0); put_buf(r1_bio); return; @@ -874,7 +858,8 @@ * Nowhere to write this to... I guess we * must be done */ - printk(KERN_ALERT "raid1: sync aborting as there is nowhere to write sector %llu\n", + printk(KERN_ALERT "raid1: sync aborting as there is nowhere" + " to write sector %llu\n", (unsigned long long)r1_bio->sector); md_done_sync(mddev, r1_bio->master_bio->bi_size >> 9, 0); put_buf(r1_bio); @@ -928,12 +913,17 @@ case READ: case READA: if (map(mddev, &rdev) == -1) { - printk(IO_ERROR, bdev_partition_name(bio->bi_bdev), (unsigned long long)r1_bio->sector); + printk(KERN_ALERT "raid1: %s: unrecoverable I/O" + " read error for block %llu\n", + bdev_partition_name(bio->bi_bdev), + (unsigned long long)r1_bio->sector); raid_end_bio_io(r1_bio, 0); break; } - printk(REDIRECT_SECTOR, - bdev_partition_name(rdev->bdev), (unsigned long long)r1_bio->sector); + printk(KERN_ERR "raid1: %s: redirecting sector %llu to" + " another mirror\n", + bdev_partition_name(rdev->bdev), + (unsigned long long)r1_bio->sector); bio->bi_bdev = rdev->bdev; bio->bi_sector = r1_bio->sector + rdev->data_offset; bio->bi_rw = r1_bio->cmd; @@ -1063,45 +1053,6 @@ return nr_sectors; } -#define INVALID_LEVEL KERN_WARNING \ -"raid1: md%d: raid level not set to mirroring (%d)\n" - -#define NO_SB KERN_ERR \ -"raid1: disabled mirror %s (couldn't access raid superblock)\n" - -#define ERRORS KERN_ERR \ -"raid1: disabled mirror %s (errors detected)\n" - -#define NOT_IN_SYNC KERN_ERR \ -"raid1: disabled mirror %s (not in sync)\n" - -#define INCONSISTENT KERN_ERR \ -"raid1: disabled mirror %s (inconsistent descriptor)\n" - -#define ALREADY_RUNNING KERN_ERR \ -"raid1: disabled mirror %s (mirror %d already operational)\n" - -#define OPERATIONAL KERN_INFO \ -"raid1: device %s operational as mirror %d\n" - -#define MEM_ERROR KERN_ERR \ -"raid1: couldn't allocate memory for md%d\n" - -#define SPARE KERN_INFO \ -"raid1: spare disk %s\n" - -#define NONE_OPERATIONAL KERN_ERR \ -"raid1: no operational mirrors for md%d\n" - -#define ARRAY_IS_ACTIVE KERN_INFO \ -"raid1: raid set md%d active with %d out of %d mirrors\n" - -#define THREAD_ERROR KERN_ERR \ -"raid1: couldn't allocate thread for md%d\n" - -#define START_RESYNC KERN_WARNING \ -"raid1: raid set md%d not clean; reconstructing mirrors\n" - static int run(mddev_t *mddev) { conf_t *conf; @@ -1110,10 +1061,9 @@ mdk_rdev_t *rdev; struct list_head *tmp; - MOD_INC_USE_COUNT; - if (mddev->level != 1) { - printk(INVALID_LEVEL, mdidx(mddev), mddev->level); + printk("raid1: md%d: raid level not set to mirroring (%d)\n", + mdidx(mddev), mddev->level); goto out; } /* @@ -1124,7 +1074,8 @@ conf = kmalloc(sizeof(conf_t), GFP_KERNEL); mddev->private = conf; if (!conf) { - printk(MEM_ERROR, mdidx(mddev)); + printk(KERN_ERR "raid1: couldn't allocate memory for md%d\n", + mdidx(mddev)); goto out; } memset(conf, 0, sizeof(*conf)); @@ -1132,7 +1083,8 @@ conf->r1bio_pool = mempool_create(NR_RAID1_BIOS, r1bio_pool_alloc, r1bio_pool_free, NULL); if (!conf->r1bio_pool) { - printk(MEM_ERROR, mdidx(mddev)); + printk(KERN_ERR "raid1: couldn't allocate memory for md%d\n", + mdidx(mddev)); goto out; } @@ -1160,7 +1112,8 @@ init_waitqueue_head(&conf->wait_resume); if (!conf->working_disks) { - printk(NONE_OPERATIONAL, mdidx(mddev)); + printk(KERN_ERR "raid1: no operational mirrors for md%d\n", + mdidx(mddev)); goto out_free_conf; } @@ -1190,12 +1143,16 @@ { mddev->thread = md_register_thread(raid1d, mddev, "md%d_raid1"); if (!mddev->thread) { - printk(THREAD_ERROR, mdidx(mddev)); + printk(KERN_ERR + "raid1: couldn't allocate thread for md%d\n", + mdidx(mddev)); goto out_free_conf; } } - - printk(ARRAY_IS_ACTIVE, mdidx(mddev), mddev->raid_disks - mddev->degraded, mddev->raid_disks); + printk(KERN_INFO + "raid1: raid set md%d active with %d out of %d mirrors\n", + mdidx(mddev), mddev->raid_disks - mddev->degraded, + mddev->raid_disks); /* * Ok, everything is just fine now */ @@ -1207,7 +1164,6 @@ kfree(conf); mddev->private = NULL; out: - MOD_DEC_USE_COUNT; return -EIO; } @@ -1221,13 +1177,13 @@ mempool_destroy(conf->r1bio_pool); kfree(conf); mddev->private = NULL; - MOD_DEC_USE_COUNT; return 0; } static mdk_personality_t raid1_personality = { .name = "raid1", + .owner = THIS_MODULE, .make_request = make_request, .run = run, .stop = stop, diff -Nru a/drivers/md/raid5.c b/drivers/md/raid5.c --- a/drivers/md/raid5.c Wed Apr 2 22:24:04 2003 +++ b/drivers/md/raid5.c Wed Apr 2 22:24:04 2003 @@ -182,7 +182,8 @@ BUG(); CHECK_DEVLOCK(); - PRINTK("init_stripe called, stripe %llu\n", (unsigned long long)sh->sector); + PRINTK("init_stripe called, stripe %llu\n", + (unsigned long long)sh->sector); remove_hash(sh); @@ -338,7 +339,9 @@ if (bi == &sh->dev[i].req) break; - PRINTK("end_read_request %llu/%d, count: %d, uptodate %d.\n", (unsigned long long)sh->sector, i, atomic_read(&sh->count), uptodate); + PRINTK("end_read_request %llu/%d, count: %d, uptodate %d.\n", + (unsigned long long)sh->sector, i, atomic_read(&sh->count), + uptodate); if (i == disks) { BUG(); return 0; @@ -409,7 +412,9 @@ if (bi == &sh->dev[i].req) break; - PRINTK("end_write_request %llu/%d, count %d, uptodate: %d.\n", (unsigned long long)sh->sector, i, atomic_read(&sh->count), uptodate); + PRINTK("end_write_request %llu/%d, count %d, uptodate: %d.\n", + (unsigned long long)sh->sector, i, atomic_read(&sh->count), + uptodate); if (i == disks) { BUG(); return 0; @@ -533,7 +538,8 @@ *dd_idx = (*pd_idx + 1 + *dd_idx) % raid_disks; break; default: - printk ("raid5: unsupported algorithm %d\n", conf->algorithm); + printk("raid5: unsupported algorithm %d\n", + conf->algorithm); } /* @@ -573,7 +579,8 @@ i -= (sh->pd_idx + 1); break; default: - printk ("raid5: unsupported algorithm %d\n", conf->algorithm); + printk("raid5: unsupported algorithm %d\n", + conf->algorithm); } chunk_number = stripe * data_disks + i; @@ -655,7 +662,8 @@ int i, count, disks = conf->raid_disks; void *ptr[MAX_XOR_BLOCKS], *p; - PRINTK("compute_block, stripe %llu, idx %d\n", (unsigned long long)sh->sector, dd_idx); + PRINTK("compute_block, stripe %llu, idx %d\n", + (unsigned long long)sh->sector, dd_idx); ptr[0] = page_address(sh->dev[dd_idx].page); memset(ptr[0], 0, STRIPE_SIZE); @@ -667,7 +675,9 @@ if (test_bit(R5_UPTODATE, &sh->dev[i].flags)) ptr[count++] = p; else - printk("compute_block() %d, stripe %llu, %d not present\n", dd_idx, (unsigned long long)sh->sector, i); + printk("compute_block() %d, stripe %llu, %d" + " not present\n", dd_idx, + (unsigned long long)sh->sector, i); check_xor(); } @@ -683,7 +693,8 @@ void *ptr[MAX_XOR_BLOCKS]; struct bio *chosen; - PRINTK("compute_parity, stripe %llu, method %d\n", (unsigned long long)sh->sector, method); + PRINTK("compute_parity, stripe %llu, method %d\n", + (unsigned long long)sh->sector, method); count = 1; ptr[0] = page_address(sh->dev[pd_idx].page); @@ -768,7 +779,9 @@ struct bio **bip; raid5_conf_t *conf = sh->raid_conf; - PRINTK("adding bh b#%llu to stripe s#%llu\n", (unsigned long long)bi->bi_sector, (unsigned long long)sh->sector); + PRINTK("adding bh b#%llu to stripe s#%llu\n", + (unsigned long long)bi->bi_sector, + (unsigned long long)sh->sector); spin_lock(&sh->lock); @@ -789,7 +802,9 @@ spin_unlock_irq(&conf->device_lock); spin_unlock(&sh->lock); - PRINTK("added bi b#%llu to stripe s#%llu, disk %d.\n", (unsigned long long)bi->bi_sector, (unsigned long long)sh->sector, dd_idx); + PRINTK("added bi b#%llu to stripe s#%llu, disk %d.\n", + (unsigned long long)bi->bi_sector, + (unsigned long long)sh->sector, dd_idx); if (forwrite) { /* check if page is coverred */ @@ -838,7 +853,9 @@ int failed_num=0; struct r5dev *dev; - PRINTK("handling stripe %llu, cnt=%d, pd_idx=%d\n", (unsigned long long)sh->sector, atomic_read(&sh->count), sh->pd_idx); + PRINTK("handling stripe %llu, cnt=%d, pd_idx=%d\n", + (unsigned long long)sh->sector, atomic_read(&sh->count), + sh->pd_idx); spin_lock(&sh->lock); clear_bit(STRIPE_HANDLE, &sh->state); @@ -853,8 +870,8 @@ clear_bit(R5_Insync, &dev->flags); clear_bit(R5_Syncio, &dev->flags); - PRINTK("check %d: state 0x%lx read %p write %p written %p\n", i, - dev->flags, dev->toread, dev->towrite, dev->written); + PRINTK("check %d: state 0x%lx read %p write %p written %p\n", + i, dev->flags, dev->toread, dev->towrite, dev->written); /* maybe we can reply to a read */ if (test_bit(R5_UPTODATE, &dev->flags) && dev->toread) { struct bio *rbi, *rbi2; @@ -895,8 +912,9 @@ } else set_bit(R5_Insync, &dev->flags); } - PRINTK("locked=%d uptodate=%d to_read=%d to_write=%d failed=%d failed_num=%d\n", - locked, uptodate, to_read, to_write, failed, failed_num); + PRINTK("locked=%d uptodate=%d to_read=%d" + " to_write=%d failed=%d failed_num=%d\n", + locked, uptodate, to_read, to_write, failed, failed_num); /* check if the array has lost two devices and, if so, some requests might * need to be failed */ @@ -1015,7 +1033,8 @@ } #endif locked++; - PRINTK("Reading block %d (sync=%d)\n", i, syncing); + PRINTK("Reading block %d (sync=%d)\n", + i, syncing); if (syncing) md_sync_acct(conf->disks[i].rdev, STRIPE_SECTORS); } @@ -1055,7 +1074,8 @@ else rcw += 2*disks; } } - PRINTK("for sector %llu, rmw=%d rcw=%d\n", (unsigned long long)sh->sector, rmw, rcw); + PRINTK("for sector %llu, rmw=%d rcw=%d\n", + (unsigned long long)sh->sector, rmw, rcw); set_bit(STRIPE_HANDLE, &sh->state); if (rmw < rcw && rmw > 0) /* prefer read-modify-write, but need to get some data */ @@ -1204,7 +1224,8 @@ md_sync_acct(rdev, STRIPE_SECTORS); bi->bi_bdev = rdev->bdev; - PRINTK("for %llu schedule op %ld on disc %d\n", (unsigned long long)sh->sector, bi->bi_rw, i); + PRINTK("for %llu schedule op %ld on disc %d\n", + (unsigned long long)sh->sector, bi->bi_rw, i); atomic_inc(&sh->count); bi->bi_sector = sh->sector + rdev->data_offset; bi->bi_flags = 1 << BIO_UPTODATE; @@ -1217,7 +1238,8 @@ bi->bi_next = NULL; generic_make_request(bi); } else { - PRINTK("skip op %ld on disc %d for sector %llu\n", bi->bi_rw, i, (unsigned long long)sh->sector); + PRINTK("skip op %ld on disc %d for sector %llu\n", + bi->bi_rw, i, (unsigned long long)sh->sector); clear_bit(R5_LOCKED, &sh->dev[i].flags); set_bit(STRIPE_HANDLE, &sh->state); } @@ -1285,8 +1307,9 @@ new_sector = raid5_compute_sector(logical_sector, raid_disks, data_disks, &dd_idx, &pd_idx, conf); - PRINTK("raid5: make_request, sector %Lu logical %Lu\n", - (unsigned long long)new_sector, (unsigned long long)logical_sector); + PRINTK("raid5: make_request, sector %Lu logical %Lu\n", + (unsigned long long)new_sector, + (unsigned long long)logical_sector); sh = get_active_stripe(conf, new_sector, pd_idx, (bi->bi_rw&RWA_MASK)); if (sh) { @@ -1410,11 +1433,8 @@ struct disk_info *disk; struct list_head *tmp; - MOD_INC_USE_COUNT; - if (mddev->level != 5 && mddev->level != 4) { printk("raid5: md%d: raid level not set to 4/5 (%d)\n", mdidx(mddev), mddev->level); - MOD_DEC_USE_COUNT; return -EIO; } @@ -1450,7 +1470,9 @@ disk->rdev = rdev; if (rdev->in_sync) { - printk(KERN_INFO "raid5: device %s operational as raid disk %d\n", bdev_partition_name(rdev->bdev), raid_disk); + printk(KERN_INFO "raid5: device %s operational as raid" + " disk %d\n", bdev_partition_name(rdev->bdev), + raid_disk); conf->working_disks++; } } @@ -1467,48 +1489,62 @@ conf->max_nr_stripes = NR_STRIPES; if (!conf->chunk_size || conf->chunk_size % 4) { - printk(KERN_ERR "raid5: invalid chunk size %d for md%d\n", conf->chunk_size, mdidx(mddev)); + printk(KERN_ERR "raid5: invalid chunk size %d for md%d\n", + conf->chunk_size, mdidx(mddev)); goto abort; } if (conf->algorithm > ALGORITHM_RIGHT_SYMMETRIC) { - printk(KERN_ERR "raid5: unsupported parity algorithm %d for md%d\n", conf->algorithm, mdidx(mddev)); + printk(KERN_ERR + "raid5: unsupported parity algorithm %d for md%d\n", + conf->algorithm, mdidx(mddev)); goto abort; } if (mddev->degraded > 1) { - printk(KERN_ERR "raid5: not enough operational devices for md%d (%d/%d failed)\n", mdidx(mddev), conf->failed_disks, conf->raid_disks); + printk(KERN_ERR "raid5: not enough operational devices for md%d" + " (%d/%d failed)\n", + mdidx(mddev), conf->failed_disks, conf->raid_disks); goto abort; } if (mddev->degraded == 1 && mddev->recovery_cp != MaxSector) { - printk(KERN_ERR "raid5: cannot start dirty degraded array for md%d\n", mdidx(mddev)); + printk(KERN_ERR + "raid5: cannot start dirty degraded array for md%d\n", + mdidx(mddev)); goto abort; } { mddev->thread = md_register_thread(raid5d, mddev, "md%d_raid5"); if (!mddev->thread) { - printk(KERN_ERR "raid5: couldn't allocate thread for md%d\n", mdidx(mddev)); + printk(KERN_ERR + "raid5: couldn't allocate thread for md%d\n", + mdidx(mddev)); goto abort; } } - - memory = conf->max_nr_stripes * (sizeof(struct stripe_head) + +memory = conf->max_nr_stripes * (sizeof(struct stripe_head) + conf->raid_disks * ((sizeof(struct bio) + PAGE_SIZE))) / 1024; if (grow_stripes(conf, conf->max_nr_stripes)) { - printk(KERN_ERR "raid5: couldn't allocate %dkB for buffers\n", memory); + printk(KERN_ERR + "raid5: couldn't allocate %dkB for buffers\n", memory); shrink_stripes(conf); md_unregister_thread(mddev->thread); goto abort; } else - printk(KERN_INFO "raid5: allocated %dkB for md%d\n", memory, mdidx(mddev)); + printk(KERN_INFO "raid5: allocated %dkB for md%d\n", + memory, mdidx(mddev)); if (mddev->degraded == 0) - printk("raid5: raid level %d set md%d active with %d out of %d devices, algorithm %d\n", conf->level, mdidx(mddev), - mddev->raid_disks-mddev->degraded, mddev->raid_disks, conf->algorithm); + printk("raid5: raid level %d set md%d active with %d out of %d" + " devices, algorithm %d\n", conf->level, mdidx(mddev), + mddev->raid_disks-mddev->degraded, mddev->raid_disks, + conf->algorithm); else - printk(KERN_ALERT "raid5: raid level %d set md%d active with %d out of %d devices, algorithm %d\n", conf->level, mdidx(mddev), - mddev->raid_disks - mddev->degraded, mddev->raid_disks, conf->algorithm); + printk(KERN_ALERT "raid5: raid level %d set md%d active with %d" + " out of %d devices, algorithm %d\n", conf->level, + mdidx(mddev), mddev->raid_disks - mddev->degraded, + mddev->raid_disks, conf->algorithm); print_raid5_conf(conf); @@ -1524,7 +1560,6 @@ } mddev->private = NULL; printk(KERN_ALERT "raid5: failed to run raid set md%d\n", mdidx(mddev)); - MOD_DEC_USE_COUNT; return -EIO; } @@ -1540,7 +1575,6 @@ free_pages((unsigned long) conf->stripe_hashtbl, HASH_PAGES_ORDER); kfree(conf); mddev->private = NULL; - MOD_DEC_USE_COUNT; return 0; } @@ -1549,11 +1583,14 @@ { int i; - printk("sh %llu, pd_idx %d, state %ld.\n", (unsigned long long)sh->sector, sh->pd_idx, sh->state); - printk("sh %llu, count %d.\n", (unsigned long long)sh->sector, atomic_read(&sh->count)); + printk("sh %llu, pd_idx %d, state %ld.\n", + (unsigned long long)sh->sector, sh->pd_idx, sh->state); + printk("sh %llu, count %d.\n", + (unsigned long long)sh->sector, atomic_read(&sh->count)); printk("sh %llu, ", (unsigned long long)sh->sector); for (i = 0; i < sh->raid_conf->raid_disks; i++) { - printk("(cache%d: %p %ld) ", i, sh->dev[i].page, sh->dev[i].flags); + printk("(cache%d: %p %ld) ", + i, sh->dev[i].page, sh->dev[i].flags); } printk("\n"); } @@ -1693,6 +1730,7 @@ static mdk_personality_t raid5_personality= { .name = "raid5", + .owner = THIS_MODULE, .make_request = make_request, .run = run, .stop = stop, diff -Nru a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c --- a/drivers/media/radio/radio-cadet.c Wed Apr 2 22:24:05 2003 +++ b/drivers/media/radio/radio-cadet.c Wed Apr 2 22:24:05 2003 @@ -23,7 +23,9 @@ * 2002-01-17 Adam Belay * Updated to latest pnp code * -*/ + * 2003-01-31 Alan Cox + * Cleaned up locking, delay code, general odds and ends + */ #include /* Modules */ #include /* Initdata */ @@ -43,11 +45,11 @@ static int curtuner=0; static int tunestat=0; static int sigstrength=0; -static wait_queue_head_t tunerq,rdsq,readq; +static wait_queue_head_t readq; struct timer_list tunertimer,rdstimer,readtimer; static __u8 rdsin=0,rdsout=0,rdsstat=0; static unsigned char rdsbuf[RDS_BUFFER]; -static int cadet_lock=0; +static spinlock_t cadet_io_lock; static int cadet_probe(void); @@ -58,37 +60,19 @@ */ static __u16 sigtable[2][4]={{5,10,30,150},{28,40,63,1000}}; -static void cadet_wake(unsigned long qnum) -{ - switch(qnum) { - case 0: /* cadet_setfreq */ - wake_up(&tunerq); - break; - case 1: /* cadet_getrds */ - wake_up(&rdsq); - break; - } -} - - - static int cadet_getrds(void) { int rdsstat=0; - cadet_lock++; + spin_lock(&cadet_io_lock); outb(3,io); /* Select Decoder Control/Status */ outb(inb(io+1)&0x7f,io+1); /* Reset RDS detection */ - cadet_lock--; - init_timer(&rdstimer); - rdstimer.function=cadet_wake; - rdstimer.data=(unsigned long)1; - rdstimer.expires=jiffies+(HZ/10); - init_waitqueue_head(&rdsq); - add_timer(&rdstimer); - sleep_on(&rdsq); + spin_unlock(&cadet_io_lock); - cadet_lock++; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/10); + + spin_lock(&cadet_io_lock); outb(3,io); /* Select Decoder Control/Status */ if((inb(io+1)&0x80)!=0) { rdsstat|=VIDEO_TUNER_RDS_ON; @@ -96,32 +80,24 @@ if((inb(io+1)&0x10)!=0) { rdsstat|=VIDEO_TUNER_MBS_ON; } - cadet_lock--; + spin_unlock(&cadet_io_lock); return rdsstat; } - - - static int cadet_getstereo(void) { - if(curtuner!=0) { /* Only FM has stereo capability! */ + int ret = 0; + if(curtuner != 0) /* Only FM has stereo capability! */ return 0; - } - cadet_lock++; + + spin_lock(&cadet_io_lock); outb(7,io); /* Select tuner control */ - if((inb(io+1)&0x40)==0) { - cadet_lock--; - return 1; /* Stereo pilot detected */ - } - else { - cadet_lock--; - return 0; /* Mono */ - } + if( (inb(io+1) & 0x40) == 0) + ret = 1; + spin_unlock(&cadet_io_lock); + return ret; } - - static unsigned cadet_gettune(void) { int curvol,i; @@ -130,7 +106,9 @@ /* * Prepare for read */ - cadet_lock++; + + spin_lock(&cadet_io_lock); + outb(7,io); /* Select tuner control */ curvol=inb(io+1); /* Save current volume/mute setting */ outb(0x00,io+1); /* Ensure WRITE-ENABLE is LOW */ @@ -152,13 +130,11 @@ * Restore volume/mute setting */ outb(curvol,io+1); - cadet_lock--; + spin_unlock(&cadet_io_lock); return fifo; } - - static unsigned cadet_getfreq(void) { int i; @@ -191,14 +167,13 @@ return freq; } - - static void cadet_settune(unsigned fifo) { int i; unsigned test; - cadet_lock++; + spin_lock(&cadet_io_lock); + outb(7,io); /* Select tuner control */ /* * Write the shift register @@ -217,11 +192,9 @@ test=0x1c|((fifo>>23)&0x02); outb(test,io+1); } - cadet_lock--; + spin_unlock(&cadet_io_lock); } - - static void cadet_setfreq(unsigned freq) { unsigned fifo; @@ -253,92 +226,90 @@ /* * Save current volume/mute setting */ - cadet_lock++; + + spin_lock(&cadet_io_lock); outb(7,io); /* Select tuner control */ curvol=inb(io+1); + spin_unlock(&cadet_io_lock); /* * Tune the card */ for(j=3;j>-1;j--) { cadet_settune(fifo|(j<<16)); + + spin_lock(&cadet_io_lock); outb(7,io); /* Select tuner control */ outb(curvol,io+1); - cadet_lock--; - init_timer(&tunertimer); - tunertimer.function=cadet_wake; - tunertimer.data=(unsigned long)0; - tunertimer.expires=jiffies+(HZ/10); - init_waitqueue_head(&tunerq); - add_timer(&tunertimer); - sleep_on(&tunerq); + spin_unlock(&cadet_io_lock); + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/10); + cadet_gettune(); - if((tunestat&0x40)==0) { /* Tuned */ + if((tunestat & 0x40) == 0) { /* Tuned */ sigstrength=sigtable[curtuner][j]; return; } - cadet_lock++; } - cadet_lock--; sigstrength=0; } static int cadet_getvol(void) { - cadet_lock++; + int ret = 0; + + spin_lock(&cadet_io_lock); + outb(7,io); /* Select tuner control */ - if((inb(io+1)&0x20)!=0) { - cadet_lock--; - return 0xffff; - } - else { - cadet_lock--; - return 0; - } + if((inb(io + 1) & 0x20) != 0) + ret = 0xffff; + + spin_unlock(&cadet_io_lock); + return ret; } static void cadet_setvol(int vol) { - cadet_lock++; + spin_lock(&cadet_io_lock); outb(7,io); /* Select tuner control */ - if(vol>0) { + if(vol>0) outb(0x20,io+1); - } - else { + else outb(0x00,io+1); - } - cadet_lock--; + spin_unlock(&cadet_io_lock); } - - void cadet_handler(unsigned long data) { /* * Service the RDS fifo */ - if(cadet_lock==0) { + + if(spin_trylock(&cadet_io_lock)) + { outb(0x3,io); /* Select RDS Decoder Control */ if((inb(io+1)&0x20)!=0) { printk(KERN_CRIT "cadet: RDS fifo overflow\n"); } outb(0x80,io); /* Select RDS fifo */ while((inb(io)&0x80)!=0) { - rdsbuf[rdsin++]=inb(io+1); - if(rdsin==rdsout) { - printk(KERN_CRIT "cadet: RDS buffer overflow\n"); - } + rdsbuf[rdsin]=inb(io+1); + if(rdsin==rdsout) + printk(KERN_WARNING "cadet: RDS buffer overflow\n"); + else + rdsin++; } + spin_unlock(&cadet_io_lock); } /* * Service pending read */ - if( rdsin!=rdsout) { + if( rdsin!=rdsout) wake_up_interruptible(&readq); - } /* * Clean up and exit @@ -359,10 +330,10 @@ unsigned char readbuf[RDS_BUFFER]; if(rdsstat==0) { - cadet_lock++; + spin_lock(&cadet_io_lock); rdsstat=1; outb(0x80,io); /* Select RDS fifo */ - cadet_lock--; + spin_unlock(&cadet_io_lock); init_timer(&readtimer); readtimer.function=cadet_handler; readtimer.data=(unsigned long)0; @@ -370,14 +341,13 @@ add_timer(&readtimer); } if(rdsin==rdsout) { - if (file->f_flags & O_NONBLOCK) { + if (file->f_flags & O_NONBLOCK) return -EWOULDBLOCK; - } interruptible_sleep_on(&readq); } - while((iname, dname); + strncpy(client->dev.name, dname, DEVICE_NAME_SIZE); init_MUTEX(&encoder->lock); encoder->client = client; + i2c_set_clientdata(client, encoder); encoder->addr = addr; encoder->norm = VIDEO_MODE_PAL; encoder->input = 0; @@ -201,7 +203,7 @@ for (i=1; iname, rv); + printk(KERN_ERR "%s_attach: init error %d\n", client->dev.name, rv); break; } } @@ -211,7 +213,7 @@ i2c_smbus_write_byte_data(client,0x07, TR0MODE); i2c_smbus_read_byte_data(client,0x12); printk(KERN_INFO "%s_attach: %s rev. %d at 0x%02x\n", - client->name, dname, rv & 1, client->addr); + client->dev.name, dname, rv & 1, client->addr); } i2c_attach_client(client); @@ -229,7 +231,7 @@ static int adv717x_detach(struct i2c_client *client) { i2c_detach_client(client); - kfree(client->data); + kfree(i2c_get_clientdata(client)); kfree(client); return 0; } @@ -237,7 +239,7 @@ static int adv717x_command(struct i2c_client *client, unsigned int cmd, void *arg) { - struct adv7175 *encoder = client->data; + struct adv7175 *encoder = i2c_get_clientdata(client); int i, x_ntsc=13, x_pal=13; /* x_ntsc is number of entries in init_ntsc -1 */ /* x_pal is number of entries in init_pal -1 */ @@ -297,7 +299,7 @@ default: printk(KERN_ERR "%s: illegal norm: %d\n", - client->name, iarg); + client->dev.name, iarg); return -EINVAL; } @@ -353,7 +355,7 @@ default: printk(KERN_ERR "%s: illegal input: %d\n", - client->name, iarg); + client->dev.name, iarg); return -EINVAL; } @@ -419,8 +421,10 @@ }; static struct i2c_client client_template = { - .name = "adv7175_client", - .driver = &i2c_driver_adv7175 + .driver = &i2c_driver_adv7175, + .dev = { + .name = "adv7175_client", + }, }; static int adv717x_init(void) diff -Nru a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c --- a/drivers/media/video/bt819.c Wed Apr 2 22:24:04 2003 +++ b/drivers/media/video/bt819.c Wed Apr 2 22:24:04 2003 @@ -128,7 +128,7 @@ struct timing *timing; - decoder = client->data; + decoder = i2c_get_clientdata(client); timing = &timing_data[decoder->norm]; init[3 * 2 - 1] = (((timing->vdelay >> 8) & 0x03) << 6) | @@ -159,6 +159,7 @@ client = kmalloc(sizeof(*client), GFP_KERNEL); if(client == NULL) return -ENOMEM; + memset(client, 0, sizeof(*client)); client_template.adapter = adap; client_template.addr = addr; memcpy(client, &client_template, sizeof(*client)); @@ -170,8 +171,8 @@ } memset(decoder, 0, sizeof(struct bt819)); - strcpy(client->name, "bt819"); - client->data = decoder; + strncpy(client->dev.name, "bt819", DEVICE_NAME_SIZE); + i2c_set_clientdata(client, decoder); decoder->client = client; decoder->addr = addr; decoder->norm = VIDEO_MODE_NTSC; @@ -186,10 +187,10 @@ i = bt819_init(client); if (i < 0) { printk(KERN_ERR "%s: bt819_attach: init status %d\n", - decoder->client->name, i); + decoder->client->dev.name, i); } else { printk(KERN_INFO "%s: bt819_attach: chip version %x\n", - decoder->client->name, i2c_smbus_read_byte_data(client, + decoder->client->dev.name, i2c_smbus_read_byte_data(client, 0x17) & 0x0f); } init_MUTEX(&decoder->lock); @@ -205,7 +206,7 @@ static int bt819_detach(struct i2c_client *client) { i2c_detach_client(client); - kfree(client->data); + i2c_get_clientdata(client); kfree(client); MOD_DEC_USE_COUNT; return 0; @@ -215,7 +216,7 @@ { int temp; - struct bt819 *decoder = client->data; + struct bt819 *decoder = i2c_get_clientdata(client); //return 0; if (!decoder->initialized) { // First call to bt819_init could be @@ -268,7 +269,7 @@ *iarg = res; DEBUG(printk(KERN_INFO "%s-bt819: get status %x\n", - decoder->client->name, *iarg)); + decoder->client->dev.name, *iarg)); } break; @@ -278,7 +279,7 @@ struct timing *timing; DEBUG(printk(KERN_INFO "%s-bt819: set norm %x\n", - decoder->client->name, *iarg)); + decoder->client->dev.name, *iarg)); if (*iarg == VIDEO_MODE_NTSC) { bt819_setbit(decoder, 0x01, 0, 1); @@ -319,7 +320,7 @@ int *iarg = arg; DEBUG(printk(KERN_INFO "%s-bt819: set input %x\n", - decoder->client->name, *iarg)); + decoder->client->dev.name, *iarg)); if (*iarg < 0 || *iarg > 7) { return -EINVAL; @@ -344,7 +345,7 @@ int *iarg = arg; DEBUG(printk(KERN_INFO "%s-bt819: set output %x\n", - decoder->client->name, *iarg)); + decoder->client->dev.name, *iarg)); /* not much choice of outputs */ if (*iarg != 0) { @@ -360,7 +361,7 @@ DEBUG(printk (KERN_INFO "%s-bt819: enable output %x\n", - decoder->client->name, *iarg)); + decoder->client->dev.name, *iarg)); if (decoder->enable != enable) { decoder->enable = enable; @@ -381,7 +382,7 @@ DEBUG(printk (KERN_INFO "%s-bt819: set picture brightness %d contrast %d colour %d\n", - decoder->client->name, pic->brightness, + decoder->client->dev.name, pic->brightness, pic->contrast, pic->colour)); @@ -448,9 +449,11 @@ }; static struct i2c_client client_template = { - .name = "bt819_client", .id = -1, - .driver = &i2c_driver_bt819 + .driver = &i2c_driver_bt819, + .dev = { + .name = "bt819_client", + }, }; static int bt819_setup(void) diff -Nru a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c --- a/drivers/media/video/bt856.c Wed Apr 2 22:24:04 2003 +++ b/drivers/media/video/bt856.c Wed Apr 2 22:24:04 2003 @@ -106,6 +106,7 @@ client = kmalloc(sizeof(*client), GFP_KERNEL); if(client == NULL) return -ENOMEM; + memset(client, 0, sizeof(*client)); client_template.adapter = adap; client_template.addr = addr; memcpy(client, &client_template, sizeof(*client)); @@ -123,14 +124,14 @@ memset(encoder, 0, sizeof(struct bt856)); - strcpy(client->name, "bt856"); + strncpy(client->dev.name, "bt856", DEVICE_NAME_SIZE); encoder->client = client; - client->data = encoder; + i2c_set_clientdata(client, encoder); encoder->addr = client->addr; encoder->norm = VIDEO_MODE_NTSC; encoder->enable = 1; - DEBUG(printk(KERN_INFO "%s-bt856: attach\n", encoder->client->name)); + DEBUG(printk(KERN_INFO "%s-bt856: attach\n", encoder->client->dev.name)); i2c_smbus_write_byte_data(client, 0xdc, 0x18); encoder->reg[0xdc] = 0x18; @@ -171,7 +172,7 @@ static int bt856_detach(struct i2c_client *client) { i2c_detach_client(client); - kfree(client->data); + i2c_get_clientdata(client); kfree(client); MOD_DEC_USE_COUNT; return 0; @@ -180,7 +181,7 @@ static int bt856_command(struct i2c_client *client, unsigned int cmd, void *arg) { - struct bt856 *encoder = client->data; + struct bt856 *encoder = i2c_get_clientdata(client); switch (cmd) { @@ -190,7 +191,7 @@ DEBUG(printk (KERN_INFO "%s-bt856: get capabilities\n", - encoder->client->name)); + encoder->client->dev.name)); cap->flags = VIDEO_ENCODER_PAL @@ -205,7 +206,7 @@ int *iarg = arg; DEBUG(printk(KERN_INFO "%s-bt856: set norm %d\n", - encoder->client->name, *iarg)); + encoder->client->dev.name, *iarg)); switch (*iarg) { @@ -232,7 +233,7 @@ int *iarg = arg; DEBUG(printk(KERN_INFO "%s-bt856: set input %d\n", - encoder->client->name, *iarg)); + encoder->client->dev.name, *iarg)); /* We only have video bus. *iarg = 0: input is from bt819 @@ -268,7 +269,7 @@ int *iarg = arg; DEBUG(printk(KERN_INFO "%s-bt856: set output %d\n", - encoder->client->name, *iarg)); + encoder->client->dev.name, *iarg)); /* not much choice of outputs */ if (*iarg != 0) { @@ -285,7 +286,7 @@ DEBUG(printk (KERN_INFO "%s-bt856: enable output %d\n", - encoder->client->name, encoder->enable)); + encoder->client->dev.name, encoder->enable)); } break; @@ -309,9 +310,11 @@ }; static struct i2c_client client_template = { - .name = "bt856_client", .id = -1, - .driver = &i2c_driver_bt856 + .driver = &i2c_driver_bt856, + .dev = { + .name = "bt856_client", + }, }; static int bt856_init(void) diff -Nru a/drivers/media/video/bttv-if.c b/drivers/media/video/bttv-if.c --- a/drivers/media/video/bttv-if.c Wed Apr 2 22:24:04 2003 +++ b/drivers/media/video/bttv-if.c Wed Apr 2 22:24:04 2003 @@ -194,7 +194,7 @@ static int attach_inform(struct i2c_client *client) { - struct bttv *btv = (struct bttv*)client->adapter->data; + struct bttv *btv = i2c_get_adapdata(client->adapter); int i; for (i = 0; i < I2C_CLIENTS_MAX; i++) { @@ -207,13 +207,13 @@ bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type); if (bttv_verbose) printk("bttv%d: i2c attach [client=%s,%s]\n",btv->nr, - client->name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed"); + client->dev.name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed"); return 0; } static int detach_inform(struct i2c_client *client) { - struct bttv *btv = (struct bttv*)client->adapter->data; + struct bttv *btv = i2c_get_adapdata(client->adapter); int i; for (i = 0; i < I2C_CLIENTS_MAX; i++) { @@ -224,7 +224,7 @@ } if (bttv_verbose) printk("bttv%d: i2c detach [client=%s,%s]\n",btv->nr, - client->name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed"); + client->dev.name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed"); return 0; } @@ -261,15 +261,19 @@ static struct i2c_adapter bttv_i2c_adap_template = { .owner = THIS_MODULE, - .name = "bt848", .id = I2C_HW_B_BT848, .client_register = attach_inform, .client_unregister = detach_inform, + .dev = { + .name = "bt848", + }, }; static struct i2c_client bttv_i2c_client_template = { - .name = "bttv internal use only", - .id = -1, + .id = -1, + .dev = { + .name = "bttv internal", + }, }; @@ -343,10 +347,10 @@ memcpy(&btv->i2c_client, &bttv_i2c_client_template, sizeof(struct i2c_client)); - sprintf(btv->i2c_adap.name+strlen(btv->i2c_adap.name), + sprintf(btv->i2c_adap.dev.name+strlen(btv->i2c_adap.dev.name), " #%d", btv->nr); btv->i2c_algo.data = btv; - btv->i2c_adap.data = btv; + i2c_set_adapdata(&btv->i2c_adap, btv); btv->i2c_adap.algo_data = &btv->i2c_algo; btv->i2c_client.adapter = &btv->i2c_adap; diff -Nru a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c --- a/drivers/media/video/msp3400.c Wed Apr 2 22:24:06 2003 +++ b/drivers/media/video/msp3400.c Wed Apr 2 22:24:06 2003 @@ -349,7 +349,7 @@ static void msp3400c_set_scart(struct i2c_client *client, int in, int out) { - struct msp3400c *msp = client->data; + struct msp3400c *msp = i2c_get_clientdata(client); if (-1 == scarts[out][in]) return; @@ -411,7 +411,7 @@ static void msp3400c_setmode(struct i2c_client *client, int type) { - struct msp3400c *msp = client->data; + struct msp3400c *msp = i2c_get_clientdata(client); int i; dprintk("msp3400: setmode: %d\n",type); @@ -471,7 +471,7 @@ { static char *strmode[] = { "0", "mono", "stereo", "3", "lang1", "5", "6", "7", "lang2" }; - struct msp3400c *msp = client->data; + struct msp3400c *msp = i2c_get_clientdata(client); int nicam=0; /* channel source: FM/AM or nicam */ int src=0; @@ -599,7 +599,7 @@ static void msp3400c_restore_dfp(struct i2c_client *client) { - struct msp3400c *msp = client->data; + struct msp3400c *msp = i2c_get_clientdata(client); int i; for (i = 0; i < DFP_COUNT; i++) { @@ -627,7 +627,7 @@ static int autodetect_stereo(struct i2c_client *client) { - struct msp3400c *msp = client->data; + struct msp3400c *msp = i2c_get_clientdata(client); int val; int newstereo = msp->stereo; int newnicam = msp->nicam_on; @@ -727,7 +727,7 @@ /* stereo/multilang monitoring */ static void watch_stereo(struct i2c_client *client) { - struct msp3400c *msp = client->data; + struct msp3400c *msp = i2c_get_clientdata(client); if (autodetect_stereo(client)) { if (msp->stereo & VIDEO_SOUND_STEREO) @@ -746,7 +746,7 @@ static int msp3400c_thread(void *data) { struct i2c_client *client = data; - struct msp3400c *msp = client->data; + struct msp3400c *msp = i2c_get_clientdata(client); struct CARRIER_DETECT *cd; int count, max1,max2,val1,val2, val,this; @@ -1002,7 +1002,7 @@ static int msp3410d_thread(void *data) { struct i2c_client *client = data; - struct msp3400c *msp = client->data; + struct msp3400c *msp = i2c_get_clientdata(client); int mode,val,i,std; #ifdef CONFIG_SMP @@ -1226,9 +1226,11 @@ static struct i2c_client client_template = { - .name = "(unset)", .flags = I2C_CLIENT_ALLOW_USE, .driver = &driver, + .dev = { + .name = "(unset)", + }, }; static int msp_attach(struct i2c_adapter *adap, int addr, @@ -1265,7 +1267,7 @@ for (i = 0; i < DFP_COUNT; i++) msp->dfp_regs[i] = -1; - c->data = msp; + i2c_set_clientdata(c, msp); init_waitqueue_head(&msp->wq); if (-1 == msp3400c_reset(c)) { @@ -1291,7 +1293,7 @@ #endif msp3400c_setvolume(c,msp->muted,msp->left,msp->right); - sprintf(c->name,"MSP34%02d%c-%c%d", + snprintf(c->dev.name, DEVICE_NAME_SIZE, "MSP34%02d%c-%c%d", (rev2>>8)&0xff, (rev1&0xff)+'@', ((rev1>>8)&0xff)+'@', rev2&0x1f); msp->nicam = (((rev2>>8)&0xff) != 00) ? 1 : 0; @@ -1310,7 +1312,7 @@ msp->wake_stereo.data = (unsigned long)msp; /* hello world :-) */ - printk(KERN_INFO "msp34xx: init: chip=%s",c->name); + printk(KERN_INFO "msp34xx: init: chip=%s",c->dev.name); if (msp->nicam) printk(", has NICAM support"); printk("\n"); @@ -1340,7 +1342,7 @@ static int msp_detach(struct i2c_client *client) { DECLARE_MUTEX_LOCKED(sem); - struct msp3400c *msp = (struct msp3400c*)client->data; + struct msp3400c *msp = i2c_get_clientdata(client); int i; /* shutdown control thread */ @@ -1379,7 +1381,7 @@ static void msp_wake_thread(struct i2c_client *client) { - struct msp3400c *msp = (struct msp3400c*)client->data; + struct msp3400c *msp = i2c_get_clientdata(client); msp3400c_setvolume(client,msp->muted,0,0); msp->watch_stereo=0; @@ -1391,7 +1393,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) { - struct msp3400c *msp = (struct msp3400c*)client->data; + struct msp3400c *msp = i2c_get_clientdata(client); __u16 *sarg = arg; #if 0 int *iarg = (int*)arg; diff -Nru a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c --- a/drivers/media/video/saa5249.c Wed Apr 2 22:24:06 2003 +++ b/drivers/media/video/saa5249.c Wed Apr 2 22:24:06 2003 @@ -171,20 +171,21 @@ return -ENOMEM; } memset(t, 0, sizeof(*t)); - strcpy(client->name, IF_NAME); + strncpy(client->dev.name, IF_NAME, DEVICE_NAME_SIZE); init_MUTEX(&t->lock); /* * Now create a video4linux device */ - client->data = vd=(struct video_device *)kmalloc(sizeof(struct video_device), GFP_KERNEL); + vd = (struct video_device *)kmalloc(sizeof(struct video_device), GFP_KERNEL); if(vd==NULL) { kfree(t); kfree(client); return -ENOMEM; } + i2c_set_clientdata(client, vd); memcpy(vd, &saa_template, sizeof(*vd)); for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) @@ -234,7 +235,7 @@ static int saa5249_detach(struct i2c_client *client) { - struct video_device *vd=client->data; + struct video_device *vd = i2c_get_clientdata(client); i2c_detach_client(client); video_unregister_device(vd); kfree(vd->priv); @@ -264,9 +265,11 @@ }; static struct i2c_client client_template = { - .name = "(unset)", .id = -1, - .driver = &i2c_driver_videotext + .driver = &i2c_driver_videotext, + .dev = { + .name = "(unset)", + }, }; /* diff -Nru a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c --- a/drivers/media/video/saa7110.c Wed Apr 2 22:24:03 2003 +++ b/drivers/media/video/saa7110.c Wed Apr 2 22:24:03 2003 @@ -163,6 +163,7 @@ client=kmalloc(sizeof(*client), GFP_KERNEL); if(client == NULL) return -ENOMEM; + memset(client, 0, sizeof(*client)); client_template.adapter = adap; client_template.addr = addr; memcpy(client, &client_template, sizeof(*client)); @@ -175,9 +176,9 @@ /* clear our private data */ memset(decoder, 0, sizeof(*decoder)); - strcpy(client->name, IF_NAME); + strncpy(client->dev.name, IF_NAME, DEVICE_NAME_SIZE); decoder->client = client; - client->data = decoder; + i2c_set_clientdata(client, decoder); decoder->addr = addr; decoder->norm = VIDEO_MODE_PAL; decoder->input = 0; @@ -189,7 +190,7 @@ rv = i2c_master_send(client, initseq, sizeof(initseq)); if (rv < 0) - printk(KERN_ERR "%s_attach: init status %d\n", client->name, rv); + printk(KERN_ERR "%s_attach: init status %d\n", client->dev.name, rv); else { i2c_smbus_write_byte_data(client,0x21,0x16); i2c_smbus_write_byte_data(client,0x0D,0x04); @@ -213,7 +214,7 @@ static int saa7110_detach(struct i2c_client *client) { - struct saa7110* decoder = client->data; + struct saa7110* decoder = i2c_get_clientdata(client); i2c_detach_client(client); @@ -232,7 +233,7 @@ static int saa7110_command(struct i2c_client *client, unsigned int cmd, void *arg) { - struct saa7110* decoder = client->data; + struct saa7110* decoder = i2c_get_clientdata(client); int v; switch (cmd) { @@ -251,7 +252,7 @@ case DECODER_GET_STATUS: { - struct saa7110* decoder = client->data; + struct saa7110* decoder = i2c_get_clientdata(client); int status; int res = 0; @@ -390,9 +391,11 @@ .command = saa7110_command }; static struct i2c_client client_template = { - .name = "saa7110_client", .id = -1, - .driver = &i2c_driver_saa7110 + .driver = &i2c_driver_saa7110, + .dev = { + .name = "saa7110_client", + }, }; static int saa7110_init(void) diff -Nru a/drivers/media/video/saa7111.c b/drivers/media/video/saa7111.c --- a/drivers/media/video/saa7111.c Wed Apr 2 22:24:05 2003 +++ b/drivers/media/video/saa7111.c Wed Apr 2 22:24:05 2003 @@ -63,23 +63,9 @@ static unsigned short normal_i2c[] = { 34>>1, I2C_CLIENT_END }; static unsigned short normal_i2c_range[] = { I2C_CLIENT_END }; -static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short ignore_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END }; -static unsigned short force[2] = { I2C_CLIENT_END , I2C_CLIENT_END }; - -static struct i2c_client_address_data addr_data = { - .normal_i2c = normal_i2c, - .normal_i2c_range = normal_i2c_range, - .probe = probe, - .probe_range = probe_range, - .ignore = ignore, - .ignore_range = ignore_range, - .force = force -}; -static struct i2c_client client_template; +I2C_CLIENT_INSMOD; + /* ----------------------------------------------------------------------- */ static int saa7111_attach(struct i2c_adapter *adap, int addr, unsigned short flags, int kind) @@ -120,6 +106,7 @@ client = kmalloc(sizeof(*client), GFP_KERNEL); if(client == NULL) return -ENOMEM; + memset(client, 0, sizeof(*client)); client_template.adapter = adap; client_template.addr = addr; memcpy(client, &client_template, sizeof(*client)); @@ -132,9 +119,9 @@ } memset(decoder, 0, sizeof(*decoder)); - strcpy(client->name, "saa7111"); + strncpy(client->dev.name, "saa7111", DEVICE_NAME_SIZE); decoder->client = client; - client->data = decoder; + i2c_set_clientdata(client, decoder); decoder->addr = addr; decoder->norm = VIDEO_MODE_NTSC; decoder->input = 0; @@ -147,10 +134,10 @@ i = i2c_master_send(client, init, sizeof(init)); if (i < 0) { printk(KERN_ERR "%s_attach: init status %d\n", - client->name, i); + client->dev.name, i); } else { printk(KERN_INFO "%s_attach: chip version %x\n", - client->name, i2c_smbus_read_byte_data(client, 0x00) >> 4); + client->dev.name, i2c_smbus_read_byte_data(client, 0x00) >> 4); } init_MUTEX(&decoder->lock); i2c_attach_client(client); @@ -164,7 +151,7 @@ static int saa7111_detach(struct i2c_client *client) { - struct saa7111 *decoder = client->data; + struct saa7111 *decoder = i2c_get_clientdata(client); i2c_detach_client(client); kfree(decoder); kfree(client); @@ -175,7 +162,7 @@ static int saa7111_command(struct i2c_client *client, unsigned int cmd, void *arg) { - struct saa7111 *decoder = client->data; + struct saa7111 *decoder = i2c_get_clientdata(client); switch (cmd) { @@ -187,7 +174,7 @@ for (i = 0; i < 32; i += 16) { int j; - printk("KERN_DEBUG %s: %03x", client->name, + printk("KERN_DEBUG %s: %03x", client->dev.name, i); for (j = 0; j < 16; ++j) { printk(" %02x", @@ -407,9 +394,11 @@ }; static struct i2c_client client_template = { - .name = "saa7111_client", .id = -1, - .driver = &i2c_driver_saa7111 + .driver = &i2c_driver_saa7111, + .dev = { + .name = "saa7111_client", + }, }; static int saa7111_init(void) diff -Nru a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c --- a/drivers/media/video/saa7134/saa7134-i2c.c Wed Apr 2 22:24:04 2003 +++ b/drivers/media/video/saa7134/saa7134-i2c.c Wed Apr 2 22:24:04 2003 @@ -334,15 +334,19 @@ static struct i2c_adapter saa7134_adap_template = { .owner = THIS_MODULE, - .name = "saa7134", .id = I2C_ALGO_SAA7134, .algo = &saa7134_algo, .client_register = attach_inform, + .dev = { + .name = "saa7134", + }, }; static struct i2c_client saa7134_client_template = { - .name = "saa7134 internal", .id = -1, + .dev = { + .name = "saa7134 internal", + }, }; /* ----------------------------------------------------------- */ @@ -410,7 +414,7 @@ int saa7134_i2c_register(struct saa7134_dev *dev) { dev->i2c_adap = saa7134_adap_template; - strcpy(dev->i2c_adap.name,dev->name); + strncpy(dev->i2c_adap.dev.name, dev->name, DEVICE_NAME_SIZE); dev->i2c_adap.algo_data = dev; i2c_add_adapter(&dev->i2c_adap); diff -Nru a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c --- a/drivers/media/video/saa7185.c Wed Apr 2 22:24:04 2003 +++ b/drivers/media/video/saa7185.c Wed Apr 2 22:24:04 2003 @@ -191,6 +191,7 @@ client = kmalloc(sizeof(*client), GFP_KERNEL); if (client == NULL) return -ENOMEM; + memset(client, 0, sizeof(*client)); client_template.adapter = adap; client_template.addr = addr; memcpy(client, &client_template, sizeof(*client)); @@ -202,9 +203,9 @@ memset(encoder, 0, sizeof(*encoder)); - strcpy(client->name, "saa7185"); + strncpy(client->dev.name, "saa7185", DEVICE_NAME_SIZE); encoder->client = client; - client->data = encoder; + i2c_set_clientdata(client, encoder); encoder->addr = addr; encoder->norm = VIDEO_MODE_NTSC; encoder->enable = 1; @@ -215,11 +216,11 @@ sizeof(init_ntsc)); } if (i < 0) { - printk(KERN_ERR "%s_attach: init error %d\n", client->name, + printk(KERN_ERR "%s_attach: init error %d\n", client->dev.name, i); } else { printk(KERN_INFO "%s_attach: chip version %d\n", - client->name, i2c_smbus_read_byte(client) >> 5); + client->dev.name, i2c_smbus_read_byte(client) >> 5); } init_MUTEX(&encoder->lock); i2c_attach_client(client); @@ -233,7 +234,7 @@ static int saa7185_detach(struct i2c_client *client) { - struct saa7185 *encoder = client->data; + struct saa7185 *encoder = i2c_get_clientdata(client); i2c_detach_client(client); i2c_smbus_write_byte_data(client, 0x61, (encoder->reg[0x61]) | 0x40); /* SW: output off is active */ //i2c_smbus_write_byte_data(client, 0x3a, (encoder->reg[0x3a]) | 0x80); /* SW: color bar */ @@ -246,7 +247,7 @@ static int saa7185_command(struct i2c_client *client, unsigned int cmd, void *arg) { - struct saa7185 *encoder = client->data; + struct saa7185 *encoder = i2c_get_clientdata(client); switch (cmd) { @@ -365,9 +366,11 @@ }; static struct i2c_client client_template = { - .name = "saa7185_client", .id = -1, - .driver = &i2c_driver_saa7185 + .driver = &i2c_driver_saa7185, + .dev = { + .name = "saa7185_client", + }, }; static int saa7185_init(void) diff -Nru a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c --- a/drivers/media/video/tda7432.c Wed Apr 2 22:24:06 2003 +++ b/drivers/media/video/tda7432.c Wed Apr 2 22:24:06 2003 @@ -260,7 +260,7 @@ static int tda7432_set(struct i2c_client *client) { - struct tda7432 *t = client->data; + struct tda7432 *t = i2c_get_clientdata(client); unsigned char buf[16]; d2printk("tda7432: In tda7432_set\n"); @@ -287,7 +287,7 @@ static void do_tda7432_init(struct i2c_client *client) { - struct tda7432 *t = client->data; + struct tda7432 *t = i2c_get_clientdata(client); d2printk("tda7432: In tda7432_init\n"); t->input = TDA7432_STEREO_IN | /* Main (stereo) input */ @@ -328,11 +328,11 @@ memcpy(client,&client_template,sizeof(struct i2c_client)); client->adapter = adap; client->addr = addr; - client->data = t; + i2c_set_clientdata(client, t); do_tda7432_init(client); MOD_INC_USE_COUNT; - strcpy(client->name,"TDA7432"); + strncpy(client->dev.name, "TDA7432", DEVICE_NAME_SIZE); printk(KERN_INFO "tda7432: init\n"); i2c_attach_client(client); @@ -348,7 +348,7 @@ static int tda7432_detach(struct i2c_client *client) { - struct tda7432 *t = client->data; + struct tda7432 *t = i2c_get_clientdata(client); do_tda7432_init(client); i2c_detach_client(client); @@ -361,7 +361,7 @@ static int tda7432_command(struct i2c_client *client, unsigned int cmd, void *arg) { - struct tda7432 *t = client->data; + struct tda7432 *t = i2c_get_clientdata(client); d2printk("tda7432: In tda7432_command\n"); switch (cmd) { @@ -526,9 +526,11 @@ static struct i2c_client client_template = { - .name = "tda7432", .id = -1, .driver = &driver, + .dev = { + .name = "tda7432", + }, }; static int tda7432_init(void) diff -Nru a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c --- a/drivers/media/video/tda9875.c Wed Apr 2 22:24:05 2003 +++ b/drivers/media/video/tda9875.c Wed Apr 2 22:24:05 2003 @@ -158,7 +158,7 @@ static void tda9875_set(struct i2c_client *client) { - struct tda9875 *tda = client->data; + struct tda9875 *tda = i2c_get_clientdata(client); unsigned char a; dprintk(KERN_DEBUG "tda9875_set(%04x,%04x,%04x,%04x)\n",tda->lvol,tda->rvol,tda->bass,tda->treble); @@ -176,7 +176,7 @@ static void do_tda9875_init(struct i2c_client *client) { - struct tda9875 *t = client->data; + struct tda9875 *t = i2c_get_clientdata(client); dprintk("In tda9875_init\n"); tda9875_write(client, TDA9875_CFG, 0xd0 ); /*reg de config 0 (reset)*/ tda9875_write(client, TDA9875_MSR, 0x03 ); /* Monitor 0b00000XXX*/ @@ -256,7 +256,7 @@ memcpy(client,&client_template,sizeof(struct i2c_client)); client->adapter = adap; client->addr = addr; - client->data = t; + i2c_set_clientdata(client, t); if(!tda9875_checkit(adap,addr)) { kfree(t); @@ -265,7 +265,7 @@ do_tda9875_init(client); MOD_INC_USE_COUNT; - strcpy(client->name,"TDA9875"); + strncpy(client->dev.name, "TDA9875", DEVICE_NAME_SIZE); printk(KERN_INFO "tda9875: init\n"); i2c_attach_client(client); @@ -281,7 +281,7 @@ static int tda9875_detach(struct i2c_client *client) { - struct tda9875 *t = client->data; + struct tda9875 *t = i2c_get_clientdata(client); do_tda9875_init(client); i2c_detach_client(client); @@ -294,7 +294,7 @@ static int tda9875_command(struct i2c_client *client, unsigned int cmd, void *arg) { - struct tda9875 *t = client->data; + struct tda9875 *t = i2c_get_clientdata(client); dprintk("In tda9875_command...\n"); @@ -396,9 +396,11 @@ static struct i2c_client client_template = { - .name = "tda9875", .id = -1, .driver = &driver, + .dev = { + .name = "tda9875", + }, }; static int tda9875_init(void) diff -Nru a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c --- a/drivers/media/video/tda9887.c Wed Apr 2 22:24:04 2003 +++ b/drivers/media/video/tda9887.c Wed Apr 2 22:24:04 2003 @@ -359,7 +359,7 @@ return -ENOMEM; memset(t,0,sizeof(*t)); t->client = client_template; - t->client.data = t; + i2c_set_clientdata(&t->client, t); t->pinnacle_id = -1; i2c_attach_client(&t->client); @@ -376,12 +376,12 @@ case I2C_ALGO_BIT | I2C_HW_B_RIVA: case I2C_ALGO_SAA7134: printk("tda9887: probing %s i2c adapter [id=0x%x]\n", - adap->name,adap->id); + adap->dev.name,adap->id); rc = i2c_probe(adap, &addr_data, tda9887_attach); break; default: printk("tda9887: ignoring %s i2c adapter [id=0x%x]\n", - adap->name,adap->id); + adap->dev.name,adap->id); rc = 0; /* nothing */ } @@ -390,7 +390,7 @@ static int tda9887_detach(struct i2c_client *client) { - struct tda9887 *t = (struct tda9887*)client->data; + struct tda9887 *t = i2c_get_clientdata(client); i2c_detach_client(client); kfree(t); @@ -401,7 +401,7 @@ static int tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg) { - struct tda9887 *t = (struct tda9887*)client->data; + struct tda9887 *t = i2c_get_clientdata(client); switch (cmd) { @@ -456,9 +456,11 @@ }; static struct i2c_client client_template = { - .name = "tda9887", .flags = I2C_CLIENT_ALLOW_USE, .driver = &driver, + .dev = { + .name = "tda9887", + }, }; static int tda9887_init_module(void) diff -Nru a/drivers/media/video/tuner-3036.c b/drivers/media/video/tuner-3036.c --- a/drivers/media/video/tuner-3036.c Wed Apr 2 22:24:05 2003 +++ b/drivers/media/video/tuner-3036.c Wed Apr 2 22:24:05 2003 @@ -196,9 +196,11 @@ static struct i2c_client client_template = { - .name = "SAB3036", .id = -1, - .driver = &i2c_driver_tuner + .driver = &i2c_driver_tuner, + .dev = { + .name = "SAB3036", + }, }; int __init diff -Nru a/drivers/media/video/tuner.c b/drivers/media/video/tuner.c --- a/drivers/media/video/tuner.c Wed Apr 2 22:24:07 2003 +++ b/drivers/media/video/tuner.c Wed Apr 2 22:24:07 2003 @@ -226,7 +226,7 @@ { unsigned char byte; - struct tuner *t = (struct tuner*)c->data; + struct tuner *t = i2c_get_clientdata(c); if (t->type == TUNER_MT2032) return 0; @@ -276,7 +276,7 @@ { unsigned char buf[21]; int ret,xogc,xok=0; - struct tuner *t = (struct tuner*)c->data; + struct tuner *t = i2c_get_clientdata(c); buf[0]=0; ret=i2c_master_send(c,buf,1); @@ -517,7 +517,7 @@ { unsigned char buf[21]; int lint_try,ret,sel,lock=0; - struct tuner *t = (struct tuner*)c->data; + struct tuner *t = i2c_get_clientdata(c); dprintk("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n",rfin,if1,if2,from,to); @@ -594,7 +594,7 @@ u8 config; u16 div; struct tunertype *tun; - struct tuner *t = c->data; + struct tuner *t = i2c_get_clientdata(c); unsigned char buffer[4]; int rc; @@ -733,7 +733,7 @@ static void set_radio_freq(struct i2c_client *c, int freq) { struct tunertype *tun; - struct tuner *t = (struct tuner*)c->data; + struct tuner *t = i2c_get_clientdata(c); unsigned char buffer[4]; int rc,div; @@ -794,16 +794,17 @@ if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) return -ENOMEM; memcpy(client,&client_template,sizeof(struct i2c_client)); - client->data = t = kmalloc(sizeof(struct tuner),GFP_KERNEL); + t = kmalloc(sizeof(struct tuner),GFP_KERNEL); if (NULL == t) { kfree(client); return -ENOMEM; } + i2c_set_clientdata(client, t); memset(t,0,sizeof(struct tuner)); if (type >= 0 && type < TUNERS) { t->type = type; printk("tuner(bttv): type forced to %d (%s) [insmod]\n",t->type,tuners[t->type].name); - strncpy(client->name, tuners[t->type].name, sizeof(client->name)); + strncpy(client->dev.name, tuners[t->type].name, DEVICE_NAME_SIZE); } else { t->type = -1; } @@ -830,12 +831,12 @@ case I2C_ALGO_SAA7134: case I2C_ALGO_SAA7146: printk("tuner: probing %s i2c adapter [id=0x%x]\n", - adap->name,adap->id); + adap->dev.name,adap->id); rc = i2c_probe(adap, &addr_data, tuner_attach); break; default: printk("tuner: ignoring %s i2c adapter [id=0x%x]\n", - adap->name,adap->id); + adap->dev.name,adap->id); rc = 0; /* nothing */ } @@ -844,7 +845,7 @@ static int tuner_detach(struct i2c_client *client) { - struct tuner *t = (struct tuner*)client->data; + struct tuner *t = i2c_get_clientdata(client); i2c_detach_client(client); kfree(t); @@ -856,7 +857,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) { - struct tuner *t = (struct tuner*)client->data; + struct tuner *t = i2c_get_clientdata(client); int *iarg = (int*)arg; #if 0 __u16 *sarg = (__u16*)arg; @@ -875,7 +876,7 @@ t->type = *iarg; printk("tuner: type set to %d (%s)\n", t->type,tuners[t->type].name); - strncpy(client->name, tuners[t->type].name, sizeof(client->name)); + strncpy(client->dev.name, tuners[t->type].name, DEVICE_NAME_SIZE); if (t->type == TUNER_MT2032) mt2032_init(client); break; @@ -977,9 +978,11 @@ }; static struct i2c_client client_template = { - .name = "(tuner unset)", .flags = I2C_CLIENT_ALLOW_USE, .driver = &driver, + .dev = { + .name = "(tuner unset)", + }, }; static int tuner_init_module(void) diff -Nru a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c --- a/drivers/media/video/tvaudio.c Wed Apr 2 22:24:05 2003 +++ b/drivers/media/video/tvaudio.c Wed Apr 2 22:24:05 2003 @@ -161,22 +161,22 @@ unsigned char buffer[2]; if (-1 == subaddr) { - dprintk("%s: chip_write: 0x%x\n", chip->c.name, val); + dprintk("%s: chip_write: 0x%x\n", chip->c.dev.name, val); chip->shadow.bytes[1] = val; buffer[0] = val; if (1 != i2c_master_send(&chip->c,buffer,1)) { printk(KERN_WARNING "%s: I/O error (write 0x%x)\n", - chip->c.name, val); + chip->c.dev.name, val); return -1; } } else { - dprintk("%s: chip_write: reg%d=0x%x\n", chip->c.name, subaddr, val); + dprintk("%s: chip_write: reg%d=0x%x\n", chip->c.dev.name, subaddr, val); chip->shadow.bytes[subaddr+1] = val; buffer[0] = subaddr; buffer[1] = val; if (2 != i2c_master_send(&chip->c,buffer,2)) { printk(KERN_WARNING "%s: I/O error (write reg%d=0x%x)\n", - chip->c.name, subaddr, val); + chip->c.dev.name, subaddr, val); return -1; } } @@ -201,10 +201,10 @@ if (1 != i2c_master_recv(&chip->c,&buffer,1)) { printk(KERN_WARNING "%s: I/O error (read)\n", - chip->c.name); + chip->c.dev.name); return -1; } - dprintk("%s: chip_read: 0x%x\n",chip->c.name,buffer); + dprintk("%s: chip_read: 0x%x\n",chip->c.dev.name,buffer); return buffer; } @@ -220,11 +220,11 @@ if (2 != i2c_transfer(chip->c.adapter,msgs,2)) { printk(KERN_WARNING "%s: I/O error (read2)\n", - chip->c.name); + chip->c.dev.name); return -1; } dprintk("%s: chip_read2: reg%d=0x%x\n", - chip->c.name,subaddr,read[0]); + chip->c.dev.name,subaddr,read[0]); return read[0]; } @@ -237,7 +237,7 @@ /* update our shadow register set; print bytes if (debug > 0) */ dprintk("%s: chip_cmd(%s): reg=%d, data:", - chip->c.name,name,cmd->bytes[0]); + chip->c.dev.name,name,cmd->bytes[0]); for (i = 1; i < cmd->count; i++) { dprintk(" 0x%x",cmd->bytes[i]); chip->shadow.bytes[i+cmd->bytes[0]] = cmd->bytes[i]; @@ -246,7 +246,7 @@ /* send data to the chip */ if (cmd->count != i2c_master_send(&chip->c,cmd->bytes,cmd->count)) { - printk(KERN_WARNING "%s: I/O error (%s)\n", chip->c.name, name); + printk(KERN_WARNING "%s: I/O error (%s)\n", chip->c.dev.name, name); return -1; } return 0; @@ -273,19 +273,19 @@ #ifdef CONFIG_SMP lock_kernel(); #endif - daemonize("%s", chip->c.name); + daemonize("%s", chip->c.dev.name); chip->thread = current; #ifdef CONFIG_SMP unlock_kernel(); #endif - dprintk("%s: thread started\n", chip->c.name); + dprintk("%s: thread started\n", chip->c.dev.name); if(chip->notify != NULL) up(chip->notify); for (;;) { interruptible_sleep_on(&chip->wq); - dprintk("%s: thread wakeup\n", chip->c.name); + dprintk("%s: thread wakeup\n", chip->c.dev.name); if (chip->done || signal_pending(current)) break; @@ -301,7 +301,7 @@ } chip->thread = NULL; - dprintk("%s: thread exiting\n", chip->c.name); + dprintk("%s: thread exiting\n", chip->c.dev.name); if(chip->notify != NULL) up(chip->notify); @@ -316,7 +316,7 @@ if (mode == chip->prevmode) return; - dprintk("%s: thread checkmode\n", chip->c.name); + dprintk("%s: thread checkmode\n", chip->c.dev.name); chip->prevmode = mode; if (mode & VIDEO_SOUND_STEREO) @@ -1339,7 +1339,7 @@ memcpy(&chip->c,&client_template,sizeof(struct i2c_client)); chip->c.adapter = adap; chip->c.addr = addr; - chip->c.data = chip; + i2c_set_clientdata(&chip->c, chip); /* find description for the chip */ dprintk("tvaudio: chip found @ i2c-addr=0x%x\n", addr<<1); @@ -1364,7 +1364,7 @@ (desc->flags & CHIP_HAS_INPUTSEL) ? " audiomux" : ""); /* fill required data structures */ - strcpy(chip->c.name,desc->name); + strncpy(chip->c.dev.name, desc->name, DEVICE_NAME_SIZE); chip->type = desc-chiplist; chip->shadow.count = desc->registers+1; chip->prevmode = -1; @@ -1421,7 +1421,7 @@ static int chip_detach(struct i2c_client *client) { - struct CHIPSTATE *chip = client->data; + struct CHIPSTATE *chip = i2c_get_clientdata(client); del_timer(&chip->wt); if (NULL != chip->thread) { @@ -1447,10 +1447,10 @@ unsigned int cmd, void *arg) { __u16 *sarg = arg; - struct CHIPSTATE *chip = client->data; + struct CHIPSTATE *chip = i2c_get_clientdata(client); struct CHIPDESC *desc = chiplist + chip->type; - dprintk("%s: chip_command 0x%x\n",chip->c.name,cmd); + dprintk("%s: chip_command 0x%x\n",chip->c.dev.name,cmd); switch (cmd) { case AUDC_SET_INPUT: @@ -1558,9 +1558,11 @@ static struct i2c_client client_template = { - .name = "(unset)", .flags = I2C_CLIENT_ALLOW_USE, .driver = &driver, + .dev = { + .name = "(unset)", + }, }; static int audiochip_init_module(void) diff -Nru a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c --- a/drivers/media/video/tvmixer.c Wed Apr 2 22:24:07 2003 +++ b/drivers/media/video/tvmixer.c Wed Apr 2 22:24:07 2003 @@ -87,7 +87,7 @@ if (cmd == SOUND_MIXER_INFO) { mixer_info info; strncpy(info.id, "tv card", sizeof(info.id)); - strncpy(info.name, client->name, sizeof(info.name)); + strncpy(info.name, client->dev.name, sizeof(info.name)); info.modify_counter = 42 /* FIXME */; if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; @@ -96,7 +96,7 @@ if (cmd == SOUND_OLD_MIXER_INFO) { _old_mixer_info info; strncpy(info.id, "tv card", sizeof(info.id)); - strncpy(info.name, client->name, sizeof(info.name)); + strncpy(info.name, client->dev.name, sizeof(info.name)); if (copy_to_user((void *)arg, &info, sizeof(info))) return -EFAULT; return 0; @@ -237,7 +237,7 @@ int i; if (debug) - printk("tvmixer: adapter %s\n",adap->name); + printk("tvmixer: adapter %s\n",adap->dev.name); for (i=0; iclients[i]) continue; @@ -261,10 +261,10 @@ /* ignore that one */ if (debug) printk("tvmixer: %s is not a tv card\n", - client->adapter->name); + client->adapter->dev.name); return -1; } - printk("tvmixer: debug: %s\n",client->name); + printk("tvmixer: debug: %s\n",client->dev.name); /* unregister ?? */ for (i = 0; i < DEV_MAX; i++) { @@ -273,7 +273,7 @@ unregister_sound_mixer(devices[i].minor); devices[i].dev = NULL; devices[i].minor = -1; - printk("tvmixer: %s unregistered (#1)\n",client->name); + printk("tvmixer: %s unregistered (#1)\n",client->dev.name); return 0; } } @@ -298,13 +298,13 @@ if (0 != client->driver->command(client,VIDIOCGAUDIO,&va)) { if (debug) printk("tvmixer: %s: VIDIOCGAUDIO failed\n", - client->name); + client->dev.name); return -1; } if (0 == (va.flags & VIDEO_AUDIO_VOLUME)) { if (debug) printk("tvmixer: %s: has no volume control\n", - client->name); + client->dev.name); return -1; } @@ -318,7 +318,7 @@ devices[i].count = 0; devices[i].dev = client; printk("tvmixer: %s (%s) registered with minor %d\n", - client->name,client->adapter->name,minor); + client->dev.name,client->adapter->dev.name,minor); return 0; } @@ -344,7 +344,7 @@ if (devices[i].minor != -1) { unregister_sound_mixer(devices[i].minor); printk("tvmixer: %s unregistered (#2)\n", - devices[i].dev->name); + devices[i].dev->dev.name); } } } diff -Nru a/drivers/mtd/maps/epxa10db-flash.c b/drivers/mtd/maps/epxa10db-flash.c --- a/drivers/mtd/maps/epxa10db-flash.c Wed Apr 2 22:24:06 2003 +++ b/drivers/mtd/maps/epxa10db-flash.c Wed Apr 2 22:24:06 2003 @@ -199,12 +199,12 @@ printk("Using default partitions for %s\n",BOARD_NAME); npartitions=1; - parts = kmalloc(npartitions*sizeof(*parts)+strlen(name), GFP_KERNEL); - memzero(parts,npartitions*sizeof(*parts)+strlen(name)); + parts = kmalloc(npartitions*sizeof(*parts)+strlen(name)+1, GFP_KERNEL); if (!parts) { ret = -ENOMEM; goto out; } + memzero(parts,npartitions*sizeof(*parts)+strlen(name)); i=0; names = (char *)&parts[npartitions]; parts[i].name = names; @@ -218,10 +218,11 @@ parts[i].size = FLASH_SIZE-0x00180000; parts[i].offset = 0x00180000; #endif + ret = npartitions; out: *pparts = parts; - return npartitions; + return ret; } diff -Nru a/drivers/net/3c509.c b/drivers/net/3c509.c --- a/drivers/net/3c509.c Wed Apr 2 22:24:04 2003 +++ b/drivers/net/3c509.c Wed Apr 2 22:24:04 2003 @@ -208,7 +208,9 @@ static int el3_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data); #endif /* generic device remove for all device types */ +#if defined(CONFIG_EISA) || defined(CONFIG_MCA) static int el3_device_remove (struct device *device); +#endif #ifdef CONFIG_EISA struct eisa_device_id el3_eisa_ids[] = { diff -Nru a/drivers/net/Kconfig b/drivers/net/Kconfig --- a/drivers/net/Kconfig Wed Apr 2 22:24:07 2003 +++ b/drivers/net/Kconfig Wed Apr 2 22:24:07 2003 @@ -2262,7 +2262,7 @@ config PPP_FILTER bool "PPP filtering" - depends on PPP && FILTER + depends on PPP help Say Y here if you want to be able to filter the packets passing over PPP interfaces. This allows you to control which packets count as diff -Nru a/drivers/net/bonding.c b/drivers/net/bonding.c --- a/drivers/net/bonding.c Wed Apr 2 22:24:07 2003 +++ b/drivers/net/bonding.c Wed Apr 2 22:24:07 2003 @@ -258,10 +258,47 @@ * - correct ifr_data reference. Update ifr_data reference * to mii_ioctl_data struct values to avoid confusion. * - * * 2002/11/22 - Bert Barbe * - Add support for multiple arp_ip_target * + * 2002/12/13 - Jay Vosburgh + * - Changed to allow text strings for mode and multicast, e.g., + * insmod bonding mode=active-backup. The numbers still work. + * One change: an invalid choice will cause module load failure, + * rather than the previous behavior of just picking one. + * - Minor cleanups; got rid of dup ctype stuff, atoi function + * + * 2003/02/07 - Jay Vosburgh + * - Added use_carrier module parameter that causes miimon to + * use netif_carrier_ok() test instead of MII/ETHTOOL ioctls. + * - Minor cleanups; consolidated ioctl calls to one function. + * + * 2003/02/07 - Tony Cureington + * - Fix bond_mii_monitor() logic error that could result in + * bonding round-robin mode ignoring links after failover/recovery + * + * 2003/03/17 - Jay Vosburgh + * - kmalloc fix (GFP_KERNEL to GFP_ATOMIC) reported by + * Shmulik dot Hen at intel.com. + * - Based on discussion on mailing list, changed use of + * update_slave_cnt(), created wrapper functions for adding/removing + * slaves, changed bond_xmit_xor() to check slave_cnt instead of + * checking slave and slave->dev (which only worked by accident). + * - Misc code cleanup: get arp_send() prototype from header file, + * add max_bonds to bonding.txt. + * + * 2003/03/18 - Tsippy Mendelson and + * Shmulik Hen + * - Make sure only bond_attach_slave() and bond_detach_slave() can + * manipulate the slave list, including slave_cnt, even when in + * bond_release_all(). + * - Fixed hang in bond_release() while traffic is running. + * netdev_set_master() must not be called from within the bond lock. + * + * 2003/03/18 - Tsippy Mendelson and + * Shmulik Hen + * - Fixed hang in bond_enslave(): netdev_set_master() must not be + * called from within the bond lock while traffic is running. */ #include @@ -278,6 +315,7 @@ #include #include #include +#include #include #include #include @@ -288,7 +326,7 @@ #include #include #include -#include +#include #include #include @@ -298,8 +336,8 @@ #include #include -#define DRV_VERSION "2.4.20-20021210" -#define DRV_RELDATE "December 10, 2002" +#define DRV_VERSION "2.5.65-20030320" +#define DRV_RELDATE "March 20, 2003" #define DRV_NAME "bonding" #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" @@ -330,14 +368,30 @@ static int max_bonds = BOND_DEFAULT_MAX_BONDS; static int miimon = BOND_LINK_MON_INTERV; -static int mode = BOND_MODE_ROUNDROBIN; +static int use_carrier = 1; +static int bond_mode = BOND_MODE_ROUNDROBIN; static int updelay = 0; static int downdelay = 0; -#define BOND_MULTICAST_DISABLED 0 -#define BOND_MULTICAST_ACTIVE 1 -#define BOND_MULTICAST_ALL 2 -static int multicast = BOND_MULTICAST_ALL; +static char *mode = NULL; + +static struct bond_parm_tbl bond_mode_tbl[] = { +{ "balance-rr", BOND_MODE_ROUNDROBIN}, +{ "active-backup", BOND_MODE_ACTIVEBACKUP}, +{ "balance-xor", BOND_MODE_XOR}, +{ "broadcast", BOND_MODE_BROADCAST}, +{ NULL, -1}, +}; + +static int multicast_mode = BOND_MULTICAST_ALL; +static char *multicast = NULL; + +static struct bond_parm_tbl bond_mc_tbl[] = { +{ "disabled", BOND_MULTICAST_DISABLED}, +{ "active", BOND_MULTICAST_ACTIVE}, +{ "all", BOND_MULTICAST_ALL}, +{ NULL, -1}, +}; static int first_pass = 1; static struct bonding *these_bonds = NULL; @@ -347,25 +401,23 @@ MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); MODULE_PARM(miimon, "i"); MODULE_PARM_DESC(miimon, "Link check interval in milliseconds"); -MODULE_PARM(mode, "i"); +MODULE_PARM(use_carrier, "i"); +MODULE_PARM_DESC(use_carrier, "Use netif_carrier_ok (vs MII ioctls) in miimon; 09 for off, 1 for on (default)"); +MODULE_PARM(mode, "s"); +MODULE_PARM_DESC(mode, "Mode of operation : 0 for round robin, 1 for active-backup, 2 for xor"); MODULE_PARM(arp_interval, "i"); MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds"); MODULE_PARM(arp_ip_target, "1-" __MODULE_STRING(MAX_ARP_IP_TARGETS) "s"); MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form"); -MODULE_PARM_DESC(mode, "Mode of operation : 0 for round robin, 1 for active-backup, 2 for xor"); MODULE_PARM(updelay, "i"); MODULE_PARM_DESC(updelay, "Delay before considering link up, in milliseconds"); MODULE_PARM(downdelay, "i"); MODULE_PARM_DESC(downdelay, "Delay before considering link down, in milliseconds"); MODULE_PARM(primary, "s"); MODULE_PARM_DESC(primary, "Primary network device to use"); -MODULE_PARM(multicast, "i"); +MODULE_PARM(multicast, "s"); MODULE_PARM_DESC(multicast, "Mode for multicast support : 0 for none, 1 for active slave, 2 for all slaves (default)"); -extern void arp_send( int type, int ptype, u32 dest_ip, struct net_device *dev, - u32 src_ip, unsigned char *dest_hw, unsigned char *src_hw, - unsigned char *target_hw); - static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *dev); static int bond_xmit_xor(struct sk_buff *skb, struct net_device *dev); static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *dev); @@ -408,18 +460,20 @@ static void arp_send_all(slave_t *slave) { - int i; - for ( i=0; (idev, - my_ip, arp_target_hw_addr, slave->dev->dev_addr, - arp_target_hw_addr); - } + int i; + + for (i = 0; (idev, + my_ip, arp_target_hw_addr, slave->dev->dev_addr, + arp_target_hw_addr); + } } -static const char *bond_mode(void) +static const char * +bond_mode_name(void) { - switch (mode) { + switch (bond_mode) { case BOND_MODE_ROUNDROBIN : return "load balancing (round-robin)"; case BOND_MODE_ACTIVEBACKUP : @@ -433,9 +487,10 @@ } } -static const char *multicast_mode(void) +static const char * +multicast_mode_name(void) { - switch(multicast) { + switch(multicast_mode) { case BOND_MULTICAST_DISABLED : return "disabled"; case BOND_MULTICAST_ACTIVE : @@ -464,6 +519,29 @@ slave->dev->flags &= ~IFF_NOARP; } +/* + * This function counts and verifies the the number of attached + * slaves, checking the count against the expected value (given that incr + * is either 1 or -1, for add or removal of a slave). Only + * bond_xmit_xor() uses the slave_cnt value, but this is still a good + * consistency check. + */ +static inline void +update_slave_cnt(bonding_t *bond, int incr) +{ + slave_t *slave = NULL; + int expect = bond->slave_cnt + incr; + + bond->slave_cnt = 0; + for (slave = bond->prev; slave != (slave_t*)bond; + slave = slave->prev) { + bond->slave_cnt++; + } + + if (expect != bond->slave_cnt) + BUG(); +} + /* * This function detaches the slave from the list . * WARNING: no check is made to verify if the slave effectively @@ -471,8 +549,11 @@ * Nothing is freed on return, structures are just unchained. * If the bond->current_slave pointer was pointing to , * it's replaced with slave->next, or if not applicable. + * + * bond->lock held by caller. */ -static slave_t *bond_detach_slave(bonding_t *bond, slave_t *slave) +static slave_t * +bond_detach_slave(bonding_t *bond, slave_t *slave) { if ((bond == NULL) || (slave == NULL) || ((void *)bond == (void *)slave)) { @@ -499,8 +580,7 @@ } write_unlock(&bond->ptrlock); } - } - else { + } else { slave->prev->next = slave->next; if (bond->prev == slave) { /* is this slave the last one ? */ bond->prev = slave->prev; @@ -515,9 +595,44 @@ write_unlock(&bond->ptrlock); } + update_slave_cnt(bond, -1); + return slave; } +static void +bond_attach_slave(struct bonding *bond, struct slave *new_slave) +{ + /* + * queue to the end of the slaves list, make the first element its + * successor, the last one its predecessor, and make it the bond's + * predecessor. + * + * Just to clarify, so future bonding driver hackers don't go through + * the same confusion stage I did trying to figure this out, the + * slaves are stored in a double linked circular list, sortof. + * In the ->next direction, the last slave points to the first slave, + * bypassing bond; only the slaves are in the ->next direction. + * In the ->prev direction, however, the first slave points to bond + * and bond points to the last slave. + * + * It looks like a circle with a little bubble hanging off one side + * in the ->prev direction only. + * + * When going through the list once, its best to start at bond->prev + * and go in the ->prev direction, testing for bond. Doing this + * in the ->next direction doesn't work. Trust me, I know this now. + * :) -mts 2002.03.14 + */ + new_slave->prev = bond->prev; + new_slave->prev->next = new_slave; + bond->prev = new_slave; + new_slave->next = bond->next; + + update_slave_cnt(bond, 1); +} + + /* * Less bad way to call ioctl from within the kernel; this needs to be * done some other way to get the call out of interrupt context. @@ -534,17 +649,31 @@ /* * if supports MII link status reporting, check its link status. * + * We either do MII/ETHTOOL ioctls, or check netif_carrier_ok(), + * depening upon the setting of the use_carrier parameter. + * * Return either BMSR_LSTATUS, meaning that the link is up (or we * can't tell and just pretend it is), or 0, meaning that the link is * down. + * + * If reporting is non-zero, instead of faking link up, return -1 if + * both ETHTOOL and MII ioctls fail (meaning the device does not + * support them). If use_carrier is set, return whatever it says. + * It'd be nice if there was a good way to tell if a driver supports + * netif_carrier, but there really isn't. */ -static u16 bond_check_dev_link(struct net_device *dev) +static int +bond_check_dev_link(struct net_device *dev, int reporting) { static int (* ioctl)(struct net_device *, struct ifreq *, int); struct ifreq ifr; struct mii_ioctl_data *mii; struct ethtool_value etool; + if (use_carrier) { + return netif_carrier_ok(dev) ? BMSR_LSTATUS : 0; + } + ioctl = dev->do_ioctl; if (ioctl) { /* TODO: set pointer to correct ioctl on a per team member */ @@ -576,18 +705,24 @@ if (IOCTL(dev, &ifr, SIOCETHTOOL) == 0) { if (etool.data == 1) { return BMSR_LSTATUS; - } - else { + } else { #ifdef BONDING_DEBUG printk(KERN_INFO - ":: SIOCETHTOOL shows failure \n"); + ":: SIOCETHTOOL shows link down \n"); #endif - return(0); + return 0; } } } - return BMSR_LSTATUS; /* spoof link up ( we can't check it) */ + + /* + * If reporting, report that either there's no dev->do_ioctl, + * or both SIOCGMIIREG and SIOCETHTOOL failed (meaning that we + * cannot report link status). If not reporting, pretend + * we're ok. + */ + return reporting ? -1 : BMSR_LSTATUS; } static u16 bond_check_mii_link(bonding_t *bond) @@ -622,7 +757,7 @@ init_timer(arp_timer); arp_timer->expires = jiffies + (arp_interval * HZ / 1000); arp_timer->data = (unsigned long)dev; - if (mode == BOND_MODE_ACTIVEBACKUP) { + if (bond_mode == BOND_MODE_ACTIVEBACKUP) { arp_timer->function = (void *)&activebackup_arp_monitor; } else { arp_timer->function = (void *)&loadbalance_arp_monitor; @@ -692,7 +827,7 @@ static void bond_mc_add(bonding_t *bond, void *addr, int alen) { slave_t *slave; - switch (multicast) { + switch (multicast_mode) { case BOND_MULTICAST_ACTIVE : /* write lock already acquired */ if (bond->current_slave != NULL) @@ -713,7 +848,7 @@ static void bond_mc_delete(bonding_t *bond, void *addr, int alen) { slave_t *slave; - switch (multicast) { + switch (multicast_mode) { case BOND_MULTICAST_ACTIVE : /* write lock already acquired */ if (bond->current_slave != NULL) @@ -769,7 +904,7 @@ static void bond_set_promiscuity(bonding_t *bond, int inc) { slave_t *slave; - switch (multicast) { + switch (multicast_mode) { case BOND_MULTICAST_ACTIVE : /* write lock already acquired */ if (bond->current_slave != NULL) @@ -790,7 +925,7 @@ static void bond_set_allmulti(bonding_t *bond, int inc) { slave_t *slave; - switch (multicast) { + switch (multicast_mode) { case BOND_MULTICAST_ACTIVE : /* write lock already acquired */ if (bond->current_slave != NULL) @@ -827,7 +962,7 @@ struct dev_mc_list *dmi; unsigned long flags = 0; - if (multicast == BOND_MULTICAST_DISABLED) + if (multicast_mode == BOND_MULTICAST_DISABLED) return; /* * Lock the private data for the master @@ -865,7 +1000,7 @@ /* save master's multicast list */ bond_mc_list_destroy (bond); - bond_mc_list_copy (master->mc_list, bond, GFP_KERNEL); + bond_mc_list_copy (master->mc_list, bond, GFP_ATOMIC); write_unlock_irqrestore(&bond->lock, flags); } @@ -878,7 +1013,7 @@ { struct dev_mc_list *dmi; - switch(multicast) { + switch(multicast_mode) { case BOND_MULTICAST_ACTIVE : if (bond->device->flags & IFF_PROMISC) { if (old != NULL && new != old) @@ -907,20 +1042,6 @@ } } -/* - * This function counts the number of attached - * slaves for use by bond_xmit_xor. - */ -static void update_slave_cnt(bonding_t *bond) -{ - slave_t *slave = NULL; - - bond->slave_cnt = 0; - for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev) { - bond->slave_cnt++; - } -} - /* enslave device to bond device */ static int bond_enslave(struct net_device *master_dev, struct net_device *slave_dev) @@ -934,10 +1055,7 @@ struct dev_mc_list *dmi; struct in_ifaddr **ifap; struct in_ifaddr *ifa; - static int (* ioctl)(struct net_device *, struct ifreq *, int); - struct ifreq ifr; - struct ethtool_value etool; - int link_reporting = 0; + int link_reporting; if (master_dev == NULL || slave_dev == NULL) { return -ENODEV; @@ -949,14 +1067,12 @@ "Warning : no link monitoring support for %s\n", slave_dev->name); } - write_lock_irqsave(&bond->lock, flags); /* not running. */ if ((slave_dev->flags & IFF_UP) != IFF_UP) { #ifdef BONDING_DEBUG printk(KERN_CRIT "Error, slave_dev is not running\n"); #endif - write_unlock_irqrestore(&bond->lock, flags); return -EINVAL; } @@ -965,12 +1081,10 @@ #ifdef BONDING_DEBUG printk(KERN_CRIT "Error, Device was already enslaved\n"); #endif - write_unlock_irqrestore(&bond->lock, flags); return -EBUSY; } - if ((new_slave = kmalloc(sizeof(slave_t), GFP_KERNEL)) == NULL) { - write_unlock_irqrestore(&bond->lock, flags); + if ((new_slave = kmalloc(sizeof(slave_t), GFP_ATOMIC)) == NULL) { return -ENOMEM; } memset(new_slave, 0, sizeof(slave_t)); @@ -983,14 +1097,12 @@ #ifdef BONDING_DEBUG printk(KERN_CRIT "Error %d calling netdev_set_master\n", err); #endif - kfree(new_slave); - write_unlock_irqrestore(&bond->lock, flags); - return err; + goto err_free; } new_slave->dev = slave_dev; - if (multicast == BOND_MULTICAST_ALL) { + if (multicast_mode == BOND_MULTICAST_ALL) { /* set promiscuity level to new slave */ if (master_dev->flags & IFF_PROMISC) dev_set_promiscuity(slave_dev, 1); @@ -1004,64 +1116,24 @@ dev_mc_add (slave_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0); } - /* - * queue to the end of the slaves list, make the first element its - * successor, the last one its predecessor, and make it the bond's - * predecessor. - * - * Just to clarify, so future bonding driver hackers don't go through - * the same confusion stage I did trying to figure this out, the - * slaves are stored in a double linked circular list, sortof. - * In the ->next direction, the last slave points to the first slave, - * bypassing bond; only the slaves are in the ->next direction. - * In the ->prev direction, however, the first slave points to bond - * and bond points to the last slave. - * - * It looks like a circle with a little bubble hanging off one side - * in the ->prev direction only. - * - * When going through the list once, its best to start at bond->prev - * and go in the ->prev direction, testing for bond. Doing this - * in the ->next direction doesn't work. Trust me, I know this now. - * :) -mts 2002.03.14 - */ - new_slave->prev = bond->prev; - new_slave->prev->next = new_slave; - bond->prev = new_slave; - new_slave->next = bond->next; - + write_lock_irqsave(&bond->lock, flags); + + bond_attach_slave(bond, new_slave); new_slave->delay = 0; new_slave->link_failure_count = 0; - if (miimon > 0) { - /* if the network driver for the slave does not support - * ETHTOOL/MII link status reporting, warn the user of this - */ - if ((ioctl = slave_dev->do_ioctl) != NULL) { - etool.cmd = ETHTOOL_GLINK; - ifr.ifr_data = (char*)&etool; - if (IOCTL(slave_dev, &ifr, SIOCETHTOOL) == 0) { - link_reporting = 1; - } - else { - if (IOCTL(slave_dev, &ifr, SIOCGMIIPHY) == 0) { - /* Yes, the mii is overlaid on the - * ifreq.ifr_ifru - */ - ((struct mii_ioctl_data*) - (&ifr.ifr_data))->reg_num = 1; - if (IOCTL(slave_dev, &ifr, SIOCGMIIREG) - == 0) { - link_reporting = 1; - } - } - } - } + if (miimon > 0 && !use_carrier) { + link_reporting = bond_check_dev_link(slave_dev, 1); - if ((link_reporting == 0) && (arp_interval == 0)) { - /* miimon is set but a bonded network driver does - * not support ETHTOOL/MII and arp_interval is - * not set + if ((link_reporting == -1) && (arp_interval == 0)) { + /* + * miimon is set but a bonded network driver + * does not support ETHTOOL/MII and + * arp_interval is not set. Note: if + * use_carrier is enabled, we will never go + * here (because netif_carrier is always + * supported); thus, we don't need to change + * the messages for netif_carrier. */ printk(KERN_ERR "bond_enslave(): MII and ETHTOOL support not " @@ -1070,8 +1142,7 @@ "not specified, thus bonding will not detect " "link failures! see bonding.txt for details.\n", slave_dev->name); - } - else if (link_reporting == 0) { + } else if (link_reporting == -1) { /* unable get link status using mii/ethtool */ printk(KERN_WARNING "bond_enslave: can't get link status from " @@ -1085,7 +1156,7 @@ /* check for initial state */ if ((miimon <= 0) || - (bond_check_dev_link(slave_dev) == BMSR_LSTATUS)) { + (bond_check_dev_link(slave_dev, 0) == BMSR_LSTATUS)) { #ifdef BONDING_DEBUG printk(KERN_CRIT "Initial state of slave_dev is BOND_LINK_UP\n"); #endif @@ -1106,7 +1177,7 @@ * since we guarantee that current_slave always point to the last * usable interface, we just have to verify this interface's flag. */ - if (mode == BOND_MODE_ACTIVEBACKUP) { + if (bond_mode == BOND_MODE_ACTIVEBACKUP) { if (((bond->current_slave == NULL) || (bond->current_slave->dev->flags & IFF_NOARP)) && (new_slave->link == BOND_LINK_UP)) { @@ -1145,8 +1216,6 @@ bond->current_slave = new_slave; } - update_slave_cnt(bond); - write_unlock_irqrestore(&bond->lock, flags); /* @@ -1187,7 +1256,11 @@ new_slave->state == BOND_STATE_ACTIVE ? "n active" : " backup", new_slave->link == BOND_LINK_UP ? "n up" : " down"); + /* enslave is successful */ return 0; +err_free: + kfree(new_slave); + return err; } /* @@ -1276,13 +1349,13 @@ } else { printk (" but could not find any %s interface.\n", - (mode == BOND_MODE_ACTIVEBACKUP) ? "backup":"other"); + (bond_mode == BOND_MODE_ACTIVEBACKUP) ? "backup":"other"); write_lock(&bond->ptrlock); bond->current_slave = (slave_t *)NULL; write_unlock(&bond->ptrlock); return NULL; /* still no slave, return NULL */ } - } else if (mode == BOND_MODE_ACTIVEBACKUP) { + } else if (bond_mode == BOND_MODE_ACTIVEBACKUP) { /* make sure oldslave doesn't send arps - this could * cause a ping-pong effect between interfaces since they * would be able to tx arps - in active backup only one @@ -1311,7 +1384,7 @@ if (IS_UP(newslave->dev)) { if (newslave->link == BOND_LINK_UP) { /* this one is immediately usable */ - if (mode == BOND_MODE_ACTIVEBACKUP) { + if (bond_mode == BOND_MODE_ACTIVEBACKUP) { bond_set_slave_active_flags(newslave); bond_mc_update(bond, newslave, oldslave); printk (" and making interface %s the active one.\n", @@ -1358,8 +1431,8 @@ return bestslave; } - if ((mode == BOND_MODE_ACTIVEBACKUP) && - (multicast == BOND_MULTICAST_ACTIVE) && + if ((bond_mode == BOND_MODE_ACTIVEBACKUP) && + (multicast_mode == BOND_MULTICAST_ACTIVE) && (oldslave != NULL)) { /* flush bonds (master's) mc_list from oldslave since it wasn't * updated (and deleted) above @@ -1374,7 +1447,7 @@ } printk (" but could not find any %s interface.\n", - (mode == BOND_MODE_ACTIVEBACKUP) ? "backup":"other"); + (bond_mode == BOND_MODE_ACTIVEBACKUP) ? "backup":"other"); /* absolutely nothing found. let's return NULL */ write_lock(&bond->ptrlock); @@ -1406,16 +1479,14 @@ bond = (struct bonding *) master->priv; - write_lock_irqsave(&bond->lock, flags); - /* master already enslaved, or slave not enslaved, or no slave for this master */ if ((master->flags & IFF_SLAVE) || !(slave->flags & IFF_SLAVE)) { printk (KERN_DEBUG "%s: cannot release %s.\n", master->name, slave->name); - write_unlock_irqrestore(&bond->lock, flags); return -EINVAL; } + write_lock_irqsave(&bond->lock, flags); bond->current_arp_slave = NULL; our_slave = (slave_t *)bond; old_current = bond->current_slave; @@ -1434,60 +1505,62 @@ } else { printk(".\n"); } - - /* release the slave from its bond */ - - if (multicast == BOND_MULTICAST_ALL) { - /* flush master's mc_list from slave */ - bond_mc_list_flush (slave, master); - - /* unset promiscuity level from slave */ - if (master->flags & IFF_PROMISC) - dev_set_promiscuity(slave, -1); - - /* unset allmulti level from slave */ - if (master->flags & IFF_ALLMULTI) - dev_set_allmulti(slave, -1); - } - - netdev_set_master(slave, NULL); - - /* only restore its RUNNING flag if monitoring set it down */ - if (slave->flags & IFF_UP) { - slave->flags |= IFF_RUNNING; - } - - if (slave->flags & IFF_NOARP || - bond->current_slave != NULL) { - dev_close(slave); - our_slave->original_flags &= ~IFF_UP; - } - - bond_restore_slave_flags(our_slave); - kfree(our_slave); - + if (bond->current_slave == NULL) { printk(KERN_INFO "%s: now running without any active interface !\n", master->name); } - update_slave_cnt(bond); - if (bond->primary_slave == our_slave) { bond->primary_slave = NULL; } - write_unlock_irqrestore(&bond->lock, flags); - return 0; /* deletion OK */ + break; } - } - /* if we get here, it's because the device was not found */ + } write_unlock_irqrestore(&bond->lock, flags); + + if (our_slave == (slave_t *)bond) { + /* if we get here, it's because the device was not found */ + printk (KERN_INFO "%s: %s not enslaved\n", master->name, slave->name); + return -EINVAL; + } - printk (KERN_INFO "%s: %s not enslaved\n", master->name, slave->name); - return -EINVAL; + /* undo settings and restore original values */ + + if (multicast_mode == BOND_MULTICAST_ALL) { + /* flush master's mc_list from slave */ + bond_mc_list_flush (slave, master); + + /* unset promiscuity level from slave */ + if (master->flags & IFF_PROMISC) + dev_set_promiscuity(slave, -1); + + /* unset allmulti level from slave */ + if (master->flags & IFF_ALLMULTI) + dev_set_allmulti(slave, -1); + } + + netdev_set_master(slave, NULL); + + /* only restore its RUNNING flag if monitoring set it down */ + if (slave->flags & IFF_UP) { + slave->flags |= IFF_RUNNING; + } + + if (slave->flags & IFF_NOARP || + bond->current_slave != NULL) { + dev_close(slave); + our_slave->original_flags &= ~IFF_UP; + } + + bond_restore_slave_flags(our_slave); + + kfree(our_slave); + + return 0; /* deletion OK */ } /* @@ -1510,13 +1583,15 @@ bond = (struct bonding *) master->priv; bond->current_arp_slave = NULL; + bond->current_slave = NULL; + bond->primary_slave = NULL; while ((our_slave = bond->prev) != (slave_t *)bond) { slave_dev = our_slave->dev; - bond->prev = our_slave->prev; + bond_detach_slave(bond, our_slave); - if (multicast == BOND_MULTICAST_ALL - || (multicast == BOND_MULTICAST_ACTIVE + if (multicast_mode == BOND_MULTICAST_ALL + || (multicast_mode == BOND_MULTICAST_ACTIVE && bond->current_slave == our_slave)) { /* flush master's mc_list from slave */ @@ -1533,6 +1608,10 @@ kfree(our_slave); + /* + * Can be safely called from inside the bond lock + * since traffic and timers have already stopped + */ netdev_set_master(slave_dev, NULL); /* only restore its RUNNING flag if monitoring set it down */ @@ -1543,10 +1622,6 @@ dev_close(slave_dev); } - bond->current_slave = NULL; - bond->next = (slave_t *)bond; - bond->slave_cnt = 0; - bond->primary_slave = NULL; printk (KERN_INFO "%s: released all slaves\n", master->name); return 0; @@ -1579,9 +1654,9 @@ /* use updelay+1 to match an UP slave even when updelay is 0 */ int mindelay = updelay + 1; struct net_device *dev = slave->dev; - u16 link_state; + int link_state; - link_state = bond_check_dev_link(dev); + link_state = bond_check_dev_link(dev, 0); switch (slave->link) { case BOND_LINK_UP: /* the link was up */ @@ -1608,7 +1683,7 @@ "%s, disabling it in %d ms.\n", master->name, IS_UP(dev) - ? ((mode == BOND_MODE_ACTIVEBACKUP) + ? ((bond_mode == BOND_MODE_ACTIVEBACKUP) ? ((slave == oldcurrent) ? "active " : "backup ") : "") @@ -1628,7 +1703,7 @@ slave->link = BOND_LINK_DOWN; /* in active/backup mode, we must completely disable this interface */ - if (mode == BOND_MODE_ACTIVEBACKUP) { + if (bond_mode == BOND_MODE_ACTIVEBACKUP) { bond_set_slave_inactive_flags(slave); } printk(KERN_INFO @@ -1708,14 +1783,12 @@ slave->link = BOND_LINK_UP; slave->jiffies = jiffies; - if ( (mode == BOND_MODE_ACTIVEBACKUP) - || (slave != bond->primary_slave) ) { - /* prevent it from being the active one */ - slave->state = BOND_STATE_BACKUP; - } - else { + if (bond_mode != BOND_MODE_ACTIVEBACKUP) { /* make it immediately active */ slave->state = BOND_STATE_ACTIVE; + } else if (slave != bond->primary_slave) { + /* prevent it from being the active one */ + slave->state = BOND_STATE_BACKUP; } printk(KERN_INFO @@ -1775,7 +1848,7 @@ bestslave->jiffies = jiffies; } - if (mode == BOND_MODE_ACTIVEBACKUP) { + if (bond_mode == BOND_MODE_ACTIVEBACKUP) { bond_set_slave_active_flags(bestslave); bond_mc_update(bond, bestslave, NULL); } else { @@ -2171,19 +2244,6 @@ read_unlock_irqrestore(&bond->lock, flags); } - -#define isdigit(c) (c >= '0' && c <= '9') -__inline static int atoi( char **s) -{ -int i = 0; -while (isdigit(**s)) - i = i*20 + *((*s)++) - '0'; -return i; -} - -#define isascii(c) (((unsigned char)(c))<=0x7f) -#define LF 0xA -#define isspace(c) (c==' ' || c==' '|| c==LF) typedef uint32_t in_addr_t; int @@ -2279,7 +2339,7 @@ slave_t *slave; unsigned long flags; - info->bond_mode = mode; + info->bond_mode = bond_mode; info->num_slaves = 0; info->miimon = miimon; @@ -2416,7 +2476,7 @@ break; case BOND_CHANGE_ACTIVE_OLD: case SIOCBONDCHANGEACTIVE: - if (mode == BOND_MODE_ACTIVEBACKUP) { + if (bond_mode == BOND_MODE_ACTIVEBACKUP) { ret = bond_change_active(master_dev, slave_dev); } else { @@ -2567,20 +2627,13 @@ slave = bond->prev; /* we're at the root, get the first slave */ - if ((slave == NULL) || (slave->dev == NULL)) { + if (bond->slave_cnt == 0) { /* no suitable interface, frame not sent */ dev_kfree_skb(skb); read_unlock_irqrestore(&bond->lock, flags); return 0; } - if (bond->slave_cnt == 0) { - /* no slaves in the bond, frame not sent */ - dev_kfree_skb(skb); - read_unlock_irqrestore(&bond->lock, flags); - return 0; - } - slave_no = (data->h_dest[5]^slave->dev->dev_addr[5]) % bond->slave_cnt; while ( (slave_no > 0) && (slave != (slave_t *)bond) ) { @@ -2642,7 +2695,7 @@ * receive packets to stay up, and the only ones they receive are * broadcasts. */ - if ( (mode != BOND_MODE_ACTIVEBACKUP) && + if ( (bond_mode != BOND_MODE_ACTIVEBACKUP) && (arp_ip_count == 1) && (arp_interval > 0) && (arp_target_hw_addr == NULL) && (skb->protocol == __constant_htons(ETH_P_IP) ) ) { @@ -2743,9 +2796,10 @@ */ link = bond_check_mii_link(bond); - len += sprintf(buf + len, "Bonding Mode: %s\n", bond_mode()); + len += sprintf(buf + len, "Bonding Mode: %s\n", + bond_mode_name()); - if (mode == BOND_MODE_ACTIVEBACKUP) { + if (bond_mode == BOND_MODE_ACTIVEBACKUP) { read_lock_irqsave(&bond->lock, flags); read_lock(&bond->ptrlock); if (bond->current_slave != NULL) { @@ -2766,7 +2820,8 @@ updelay * miimon); len += sprintf(buf + len, "Down Delay (ms): %d\n", downdelay * miimon); - len += sprintf(buf + len, "Multicast Mode: %s\n", multicast_mode()); + len += sprintf(buf + len, "Multicast Mode: %s\n", + multicast_mode_name()); read_lock_irqsave(&bond->lock, flags); for (slave = bond->prev; slave != (slave_t *)bond; @@ -2884,16 +2939,21 @@ dev->priv = bond; /* Initialize the device structure. */ - if (mode == BOND_MODE_ACTIVEBACKUP) { + switch (bond_mode) { + case BOND_MODE_ACTIVEBACKUP: dev->hard_start_xmit = bond_xmit_activebackup; - } else if (mode == BOND_MODE_ROUNDROBIN) { + break; + case BOND_MODE_ROUNDROBIN: dev->hard_start_xmit = bond_xmit_roundrobin; - } else if (mode == BOND_MODE_XOR) { + break; + case BOND_MODE_XOR: dev->hard_start_xmit = bond_xmit_xor; - } else if (mode == BOND_MODE_BROADCAST) { + break; + case BOND_MODE_BROADCAST: dev->hard_start_xmit = bond_xmit_broadcast; - } else { - printk(KERN_ERR "Unknown bonding mode %d\n", mode); + break; + default: + printk(KERN_ERR "Unknown bonding mode %d\n", bond_mode); kfree(bond->stats); kfree(bond); return -EINVAL; @@ -2926,7 +2986,7 @@ } else { printk("out MII link monitoring"); } - printk(", in %s mode.\n", bond_mode()); + printk(", in %s mode.\n", bond_mode_name()); printk(KERN_INFO "%s registered with", dev->name); if (arp_interval > 0) { @@ -2986,6 +3046,28 @@ } */ +/* + * Convert string input module parms. Accept either the + * number of the mode or its string name. + */ +static inline int +bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl) +{ + int i; + + for (i = 0; tbl[i].modename != NULL; i++) { + if ((isdigit(*mode_arg) && + tbl[i].mode == simple_strtol(mode_arg, NULL, 0)) || + (0 == strncmp(mode_arg, tbl[i].modename, + strlen(tbl[i].modename)))) { + return tbl[i].mode; + } + } + + return -1; +} + + static int __init bonding_init(void) { int no; @@ -2996,6 +3078,29 @@ printk(KERN_INFO "%s", version); + /* + * Convert string parameters. + */ + if (mode) { + bond_mode = bond_parse_parm(mode, bond_mode_tbl); + if (bond_mode == -1) { + printk(KERN_WARNING + "bonding_init(): Invalid bonding mode \"%s\"\n", + mode == NULL ? "NULL" : mode); + return -EINVAL; + } + } + + if (multicast) { + multicast_mode = bond_parse_parm(multicast, bond_mc_tbl); + if (multicast_mode == -1) { + printk(KERN_WARNING + "bonding_init(): Invalid multicast mode \"%s\"\n", + multicast == NULL ? "NULL" : multicast); + return -EINVAL; + } + } + if (max_bonds < 1 || max_bonds > INT_MAX) { printk(KERN_WARNING "bonding_init(): max_bonds (%d) not in range %d-%d, " @@ -3125,27 +3230,17 @@ "link failures! see bonding.txt for details.\n"); } - if ((primary != NULL) && (mode != BOND_MODE_ACTIVEBACKUP)){ + if ((primary != NULL) && (bond_mode != BOND_MODE_ACTIVEBACKUP)){ /* currently, using a primary only makes sence * in active backup mode */ printk(KERN_WARNING "bonding_init(): %s primary device specified but has " " no effect in %s mode\n", - primary, bond_mode()); + primary, bond_mode_name()); primary = NULL; } - - if (multicast != BOND_MULTICAST_DISABLED && - multicast != BOND_MULTICAST_ACTIVE && - multicast != BOND_MULTICAST_ALL) { - printk(KERN_WARNING - "bonding_init(): unknown multicast module " - "parameter (%d), multicast reset to %d\n", - multicast, BOND_MULTICAST_ALL); - multicast = BOND_MULTICAST_ALL; - } for (no = 0; no < max_bonds; no++) { dev_bond->init = bond_init; diff -Nru a/drivers/net/gt96100eth.c b/drivers/net/gt96100eth.c --- a/drivers/net/gt96100eth.c Wed Apr 2 22:24:07 2003 +++ b/drivers/net/gt96100eth.c Wed Apr 2 22:24:07 2003 @@ -758,19 +758,6 @@ goto free_region; } - /* Initialize our private structure. */ - if (dev->priv == NULL) { - - gp = (struct gt96100_private *)kmalloc(sizeof(*gp), - GFP_KERNEL); - if (gp == NULL) { - retval = -ENOMEM; - goto free_region; - } - - dev->priv = gp; - } - gp = dev->priv; memset(gp, 0, sizeof(*gp)); // clear it @@ -854,8 +841,6 @@ free_region: release_region(gtif->iobase, GT96100_ETH_IO_SIZE); unregister_netdev(dev); - if (dev->priv != NULL) - kfree (dev->priv); kfree (dev); err("%s failed. Returns %d\n", __FUNCTION__, retval); return retval; @@ -1601,8 +1586,6 @@ (struct gt96100_private *)gtif->dev->priv; release_region(gtif->iobase, gp->io_size); unregister_netdev(gtif->dev); - if (gtif->dev->priv != NULL) - kfree (gtif->dev->priv); kfree (gtif->dev); } } diff -Nru a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c --- a/drivers/net/hamradio/dmascc.c Wed Apr 2 22:24:05 2003 +++ b/drivers/net/hamradio/dmascc.c Wed Apr 2 22:24:05 2003 @@ -285,9 +285,8 @@ /* Initialization variables */ static int io[MAX_NUM_DEVS] __initdata = { 0, }; -/* Beware! hw[] is also used in cleanup_module(). If __initdata also applies - to modules, we may not declare hw[] as __initdata */ -static struct scc_hardware hw[NUM_TYPES] __initdata = HARDWARE; +/* Beware! hw[] is also used in cleanup_module(). */ +static struct scc_hardware hw[NUM_TYPES] __initdata_or_module = HARDWARE; static char ax25_broadcast[7] __initdata = { 'Q'<<1, 'S'<<1, 'T'<<1, ' '<<1, ' '<<1, ' '<<1, '0'<<1 }; static char ax25_test[7] __initdata = diff -Nru a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c --- a/drivers/net/irda/irda-usb.c Wed Apr 2 22:24:05 2003 +++ b/drivers/net/irda/irda-usb.c Wed Apr 2 22:24:05 2003 @@ -402,7 +402,7 @@ usb_fill_bulk_urb(urb, self->usbdev, usb_sndbulkpipe(self->usbdev, self->bulk_out_ep), - skb->data, IRDA_USB_MAX_MTU, + skb->data, IRDA_SKB_MAX_MTU, write_bulk_callback, skb); urb->transfer_buffer_length = skb->len; /* Note : unlink *must* be Asynchronous because of the code in @@ -442,6 +442,9 @@ * would be lost in the noise - Jean II */ diff += IU_USB_MIN_RTT; #endif /* IU_USB_MIN_RTT */ + /* If the usec counter did wraparound, the diff will + * go negative (tv_usec is a long), so we need to + * correct it by one second. Jean II */ if (diff < 0) diff += 1000000; @@ -701,30 +704,11 @@ IRDA_DEBUG(2, "%s()\n", __FUNCTION__); - /* Check that we have an urb */ - if (!urb) { - WARNING("%s(), Bug : urb == NULL\n", __FUNCTION__); - return; - } - - /* Allocate new skb if it has not been recycled */ - if (!skb) { - skb = dev_alloc_skb(IRDA_USB_MAX_MTU + 1); - if (!skb) { - /* If this ever happen, we are in deep s***. - * Basically, the Rx path will stop... */ - WARNING("%s(), Failed to allocate Rx skb\n", __FUNCTION__); - return; - } - } else { - /* Reset recycled skb */ - skb->data = skb->tail = skb->head; - skb->len = 0; - } - /* Make sure IP header get aligned (IrDA header is 5 bytes ) */ - skb_reserve(skb, 1); + /* This should never happen */ + ASSERT(skb != NULL, return;); + ASSERT(urb != NULL, return;); - /* Save ourselves */ + /* Save ourselves in the skb */ cb = (struct irda_skb_cb *) skb->cb; cb->context = self; @@ -758,8 +742,10 @@ struct sk_buff *skb = (struct sk_buff *) urb->context; struct irda_usb_cb *self; struct irda_skb_cb *cb; - struct sk_buff *new; - + struct sk_buff *newskb; + struct sk_buff *dataskb; + int docopy; + IRDA_DEBUG(2, "%s(), len=%d\n", __FUNCTION__, urb->actual_length); /* Find ourselves */ @@ -808,39 +794,56 @@ */ do_gettimeofday(&self->stamp); - /* Fix skb, and remove USB-IrDA header */ - skb_put(skb, urb->actual_length); - skb_pull(skb, USB_IRDA_HEADER); - - /* Don't waste a lot of memory on small IrDA frames */ - if (skb->len < RX_COPY_THRESHOLD) { - new = dev_alloc_skb(skb->len+1); - if (!new) { - self->stats.rx_dropped++; - goto done; - } + /* Check if we need to copy the data to a new skb or not. + * For most frames, we use ZeroCopy and pass the already + * allocated skb up the stack. + * If the frame is small, it is more efficient to copy it + * to save memory (copy will be fast anyway - that's + * called Rx-copy-break). Jean II */ + docopy = (urb->actual_length < IRDA_RX_COPY_THRESHOLD); + + /* Allocate a new skb */ + newskb = dev_alloc_skb(docopy ? urb->actual_length : IRDA_SKB_MAX_MTU); + if (!newskb) { + self->stats.rx_dropped++; + /* We could deliver the current skb, but this would stall + * the Rx path. Better drop the packet... Jean II */ + goto done; + } + + /* Make sure IP header get aligned (IrDA header is 5 bytes) */ + /* But IrDA-USB header is 1 byte. Jean II */ + //skb_reserve(newskb, USB_IRDA_HEADER - 1); - /* Make sure IP header get aligned (IrDA header is 5 bytes) */ - skb_reserve(new, 1); - + if(docopy) { /* Copy packet, so we can recycle the original */ - memcpy(skb_put(new, skb->len), skb->data, skb->len); - /* We will cleanup the skb in irda_usb_submit() */ + memcpy(newskb->data, skb->data, urb->actual_length); + /* Deliver this new skb */ + dataskb = newskb; + /* And hook the old skb to the URB + * Note : we don't need to "clean up" the old skb, + * as we never touched it. Jean II */ } else { - /* Deliver the original skb */ - new = skb; - skb = NULL; + /* We are using ZeroCopy. Deliver old skb */ + dataskb = skb; + /* And hook the new skb to the URB */ + skb = newskb; } - - self->stats.rx_bytes += new->len; - self->stats.rx_packets++; + + /* Set proper length on skb & remove USB-IrDA header */ + skb_put(dataskb, urb->actual_length); + skb_pull(dataskb, USB_IRDA_HEADER); /* Ask the networking layer to queue the packet for the IrDA stack */ - new->dev = self->netdev; - new->mac.raw = new->data; - new->protocol = htons(ETH_P_IRDA); - netif_rx(new); - self->netdev->last_rx = jiffies; + dataskb->dev = self->netdev; + dataskb->mac.raw = dataskb->data; + dataskb->protocol = htons(ETH_P_IRDA); + netif_rx(dataskb); + + /* Keep stats up to date */ + self->stats.rx_bytes += dataskb->len; + self->stats.rx_packets++; + self->netdev->last_rx = jiffies; done: /* Note : at this point, the URB we've just received (urb) @@ -973,8 +976,17 @@ /* Now that we can pass data to IrLAP, allow the USB layer * to send us some data... */ - for (i = 0; i < IU_MAX_ACTIVE_RX_URBS; i++) - irda_usb_submit(self, NULL, self->rx_urb[i]); + for (i = 0; i < IU_MAX_ACTIVE_RX_URBS; i++) { + struct sk_buff *skb = dev_alloc_skb(IRDA_SKB_MAX_MTU); + if (!skb) { + /* If this ever happen, we are in deep s***. + * Basically, we can't start the Rx path... */ + WARNING("%s(), Failed to allocate Rx skb\n", __FUNCTION__); + return -1; + } + //skb_reserve(newskb, USB_IRDA_HEADER - 1); + irda_usb_submit(self, skb, self->rx_urb[i]); + } /* Ready to play !!! */ return 0; @@ -1167,9 +1179,6 @@ spin_lock_init(&self->lock); irda_usb_init_qos(self); - - /* Initialise list of skb beeing curently transmitted */ - self->tx_list = hashbin_new(HB_NOLOCK); /* unused */ /* Allocate the buffer for speed changes */ /* Don't change this buffer size and allocation without doing @@ -1228,8 +1237,6 @@ self->netdev = NULL; rtnl_unlock(); } - /* Delete all pending skbs */ - hashbin_delete(self->tx_list, (FREE_FUNC) &dev_kfree_skb_any); /* Remove the speed buffer */ if (self->speed_buff != NULL) { kfree(self->speed_buff); @@ -1492,8 +1499,10 @@ case 0: break; case -EPIPE: /* -EPIPE = -32 */ - usb_clear_halt(dev, usb_sndctrlpipe(dev, 0)); - IRDA_DEBUG(0, "%s(), Clearing stall on control interface\n", __FUNCTION__); + /* Martin Diehl says if we get a -EPIPE we should + * be fine and we don't need to do a usb_clear_halt(). + * - Jean II */ + IRDA_DEBUG(0, "%s(), Received -EPIPE, ignoring...\n", __FUNCTION__); break; default: IRDA_DEBUG(0, "%s(), Unknown error %d\n", __FUNCTION__, ret); diff -Nru a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c --- a/drivers/net/irda/sir_dev.c Wed Apr 2 22:24:06 2003 +++ b/drivers/net/irda/sir_dev.c Wed Apr 2 22:24:06 2003 @@ -223,25 +223,24 @@ } /* Read the characters into the buffer */ - while (count--) { - if (likely(atomic_read(&dev->enable_rx))) { + if (likely(atomic_read(&dev->enable_rx))) { + while (count--) /* Unwrap and destuff one byte */ async_unwrap_char(dev->netdev, &dev->stats, - &dev->rx_buff, *cp++); - } - else { + &dev->rx_buff, *cp++); + } else { + while (count--) { /* rx not enabled: save the raw bytes and never * trigger any netif_rx. The received bytes are flushed * later when we re-enable rx but might be read meanwhile * by the dongle driver. */ dev->rx_buff.data[dev->rx_buff.len++] = *cp++; - } - /* What should we do when the buffer is full? */ - if (unlikely(dev->rx_buff.len == dev->rx_buff.truesize)) - dev->rx_buff.len = 0; - + /* What should we do when the buffer is full? */ + if (unlikely(dev->rx_buff.len == dev->rx_buff.truesize)) + dev->rx_buff.len = 0; + } } return 0; @@ -423,19 +422,24 @@ static int sirdev_alloc_buffers(struct sir_dev *dev) { - dev->rx_buff.truesize = SIRBUF_ALLOCSIZE; dev->tx_buff.truesize = SIRBUF_ALLOCSIZE; + dev->rx_buff.truesize = IRDA_SKB_MAX_MTU; - dev->rx_buff.head = kmalloc(dev->rx_buff.truesize, GFP_KERNEL); - if (dev->rx_buff.head == NULL) + /* Bootstrap ZeroCopy Rx */ + dev->rx_buff.skb = __dev_alloc_skb(dev->rx_buff.truesize, GFP_KERNEL); + if (dev->rx_buff.skb == NULL) return -ENOMEM; - memset(dev->rx_buff.head, 0, dev->rx_buff.truesize); + skb_reserve(dev->rx_buff.skb, 1); + dev->rx_buff.head = dev->rx_buff.skb->data; + /* No need to memset the buffer, unless you are really pedantic */ dev->tx_buff.head = kmalloc(dev->tx_buff.truesize, GFP_KERNEL); if (dev->tx_buff.head == NULL) { - kfree(dev->rx_buff.head); + kfree_skb(dev->rx_buff.skb); + dev->rx_buff.skb = NULL; dev->rx_buff.head = NULL; return -ENOMEM; + /* Hu ??? This should not be here, Martin ? */ memset(dev->tx_buff.head, 0, dev->tx_buff.truesize); } @@ -451,11 +455,12 @@ static void sirdev_free_buffers(struct sir_dev *dev) { - if (dev->rx_buff.head) - kfree(dev->rx_buff.head); + if (dev->rx_buff.skb) + kfree_skb(dev->rx_buff.skb); if (dev->tx_buff.head) kfree(dev->tx_buff.head); dev->rx_buff.head = dev->tx_buff.head = NULL; + dev->rx_buff.skb = NULL; } static int sirdev_open(struct net_device *ndev) diff -Nru a/drivers/net/mace.c b/drivers/net/mace.c --- a/drivers/net/mace.c Wed Apr 2 22:24:04 2003 +++ b/drivers/net/mace.c Wed Apr 2 22:24:04 2003 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +64,7 @@ int chipid; struct device_node* of_node; struct net_device *next_mace; + spinlock_t lock; }; /* @@ -203,6 +205,7 @@ memset((char *) mp->tx_cmds, 0, (NCMDS_TX*N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd)); init_timer(&mp->tx_timeout); + spin_lock_init(&mp->lock); mp->timeout_active = 0; if (port_aaui >= 0) @@ -351,14 +354,14 @@ volatile struct mace *mb = mp->mace; unsigned long flags; - save_flags(flags); cli(); + spin_lock_irqsave(&mp->lock, flags); __mace_set_address(dev, addr); /* note: setting ADDRCHG clears ENRCV */ out_8(&mb->maccc, mp->maccc); - restore_flags(flags); + spin_unlock_irqrestore(&mp->lock, flags); return 0; } @@ -473,10 +476,7 @@ static inline void mace_set_timeout(struct net_device *dev) { struct mace_data *mp = (struct mace_data *) dev->priv; - unsigned long flags; - save_flags(flags); - cli(); if (mp->timeout_active) del_timer(&mp->tx_timeout); mp->tx_timeout.expires = jiffies + TX_TIMEOUT; @@ -484,7 +484,6 @@ mp->tx_timeout.data = (unsigned long) dev; add_timer(&mp->tx_timeout); mp->timeout_active = 1; - restore_flags(flags); } static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev) @@ -496,7 +495,7 @@ int fill, next, len; /* see if there's a free slot in the tx ring */ - save_flags(flags); cli(); + spin_lock_irqsave(&mp->lock, flags); fill = mp->tx_fill; next = fill + 1; if (next >= N_TX_RING) @@ -504,10 +503,10 @@ if (next == mp->tx_empty) { netif_stop_queue(dev); mp->tx_fullup = 1; - restore_flags(flags); + spin_unlock_irqrestore(&mp->lock, flags); return 1; /* can't take it at the moment */ } - restore_flags(flags); + spin_unlock_irqrestore(&mp->lock, flags); /* partially fill in the dma command block */ len = skb->len; @@ -524,8 +523,7 @@ out_le16(&np->command, DBDMA_STOP); /* poke the tx dma channel */ - save_flags(flags); - cli(); + spin_lock_irqsave(&mp->lock, flags); mp->tx_fill = next; if (!mp->tx_bad_runt && mp->tx_active < MAX_TX_ACTIVE) { out_le16(&cp->xfer_status, 0); @@ -538,7 +536,7 @@ next = 0; if (next == mp->tx_empty) netif_stop_queue(dev); - restore_flags(flags); + spin_unlock_irqrestore(&mp->lock, flags); return 0; } @@ -556,7 +554,9 @@ volatile struct mace *mb = mp->mace; int i, j; u32 crc; + unsigned long flags; + spin_lock_irqsave(&mp->lock, flags); mp->maccc &= ~PROM; if (dev->flags & IFF_PROMISC) { mp->maccc |= PROM; @@ -598,6 +598,7 @@ } /* reset maccc */ out_8(&mb->maccc, mp->maccc); + spin_unlock_irqrestore(&mp->lock, flags); } static void mace_handle_misc_intrs(struct mace_data *mp, int intr) @@ -630,8 +631,10 @@ volatile struct dbdma_cmd *cp; int intr, fs, i, stat, x; int xcount, dstat; + unsigned long flags; /* static int mace_last_fs, mace_last_xcount; */ + spin_lock_irqsave(&mp->lock, flags); intr = in_8(&mb->ir); /* read interrupt register */ in_8(&mb->xmtrc); /* get retries */ mace_handle_misc_intrs(mp, intr); @@ -761,6 +764,7 @@ out_le32(&td->control, ((RUN|WAKE) << 16) + (RUN|WAKE)); mace_set_timeout(dev); } + spin_unlock_irqrestore(&mp->lock, flags); } static void mace_tx_timeout(unsigned long data) @@ -774,8 +778,7 @@ unsigned long flags; int i; - save_flags(flags); - cli(); + spin_lock_irqsave(&mp->lock, flags); mp->timeout_active = 0; if (mp->tx_active == 0 && !mp->tx_bad_runt) goto out; @@ -827,7 +830,7 @@ out_8(&mb->maccc, mp->maccc); out: - restore_flags(flags); + spin_unlock_irqrestore(&mp->lock, flags); } static void mace_txdma_intr(int irq, void *dev_id, struct pt_regs *regs) @@ -845,7 +848,9 @@ unsigned frame_status; static int mace_lost_status; unsigned char *data; + unsigned long flags; + spin_lock_irqsave(&mp->lock, flags); for (i = mp->rx_empty; i != mp->rx_fill; ) { cp = mp->rx_cmds + i; stat = ld_le16(&cp->xfer_status); @@ -941,6 +946,7 @@ out_le32(&rd->control, ((RUN|WAKE) << 16) | (RUN|WAKE)); mp->rx_fill = i; } + spin_unlock_irqrestore(&mp->lock, flags); } MODULE_AUTHOR("Paul Mackerras"); diff -Nru a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c --- a/drivers/net/pcnet32.c Wed Apr 2 22:24:04 2003 +++ b/drivers/net/pcnet32.c Wed Apr 2 22:24:04 2003 @@ -468,10 +468,13 @@ /* search for PCnet32 VLB cards at known addresses */ for (port = pcnet32_portlist; (ioaddr = *port); port++) { - if (!check_region(ioaddr, PCNET32_TOTAL_SIZE)) { - /* check if there is really a pcnet chip on that ioaddr */ - if ((inb(ioaddr + 14) == 0x57) && (inb(ioaddr + 15) == 0x57)) - pcnet32_probe1(ioaddr, 0, 0, NULL); + if (request_region(ioaddr, PCNET32_TOTAL_SIZE, "pcnet32_probe_vlbus")) { + /* check if there is really a pcnet chip on that ioaddr */ + if ((inb(ioaddr + 14) == 0x57) && (inb(ioaddr + 15) == 0x57)) { + pcnet32_probe1(ioaddr, 0, 0, NULL); + } else { + release_region(ioaddr, PCNET32_TOTAL_SIZE); + } } } } @@ -500,6 +503,10 @@ printk(KERN_ERR PFX "architecture does not support 32bit PCI busmaster DMA\n"); return -ENODEV; } + if (request_region(ioaddr, PCNET32_TOTAL_SIZE, "pcnet32_probe_pci") == NULL) { + printk(KERN_ERR PFX "io address range already allocated\n"); + return -EBUSY; + } return pcnet32_probe1(ioaddr, pdev->irq, 1, pdev); } @@ -533,15 +540,19 @@ pcnet32_dwio_reset(ioaddr); if (pcnet32_dwio_read_csr(ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) { a = &pcnet32_dwio; - } else - return -ENODEV; + } else { + release_region(ioaddr, PCNET32_TOTAL_SIZE); + return -ENODEV; + } } chip_version = a->read_csr(ioaddr, 88) | (a->read_csr(ioaddr,89) << 16); if (pcnet32_debug > 2) printk(KERN_INFO " PCnet chip version is %#x.\n", chip_version); - if ((chip_version & 0xfff) != 0x003) - return -ENODEV; + if ((chip_version & 0xfff) != 0x003) { + release_region(ioaddr, PCNET32_TOTAL_SIZE); + return -ENODEV; + } /* initialize variables */ fdx = mii = fset = dxsuflo = ltint = 0; @@ -603,6 +614,7 @@ default: printk(KERN_INFO PFX "PCnet version %#x, no PCnet32 chip.\n", chip_version); + release_region(ioaddr, PCNET32_TOTAL_SIZE); return -ENODEV; } @@ -622,8 +634,10 @@ } dev = alloc_etherdev(0); - if(!dev) - return -ENOMEM; + if(!dev) { + release_region(ioaddr, PCNET32_TOTAL_SIZE); + return -ENOMEM; + } printk(KERN_INFO PFX "%s at %#3lx,", chipname, ioaddr); @@ -691,9 +705,6 @@ } dev->base_addr = ioaddr; - if (request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname) == NULL) - return -EBUSY; - /* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */ if ((lp = pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL) { release_region(ioaddr, PCNET32_TOTAL_SIZE); diff -Nru a/drivers/net/r8169.c b/drivers/net/r8169.c --- a/drivers/net/r8169.c Wed Apr 2 22:24:05 2003 +++ b/drivers/net/r8169.c Wed Apr 2 22:24:05 2003 @@ -1110,7 +1110,7 @@ .name = MODULENAME, .id_table = rtl8169_pci_tbl, .probe = rtl8169_init_one, - .remove = rtl8169_remove_one, + .remove = __devexit_p(rtl8169_remove_one), .suspend = NULL, .resume = NULL, }; diff -Nru a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c --- a/drivers/net/tulip/de4x5.c Wed Apr 2 22:24:04 2003 +++ b/drivers/net/tulip/de4x5.c Wed Apr 2 22:24:04 2003 @@ -452,7 +452,6 @@ #include #include #include -#include #include #include #include diff -Nru a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c --- a/drivers/net/tulip/dmfe.c Wed Apr 2 22:24:07 2003 +++ b/drivers/net/tulip/dmfe.c Wed Apr 2 22:24:07 2003 @@ -49,6 +49,10 @@ support. Updated PCI resource allocation. Do not forget to unmap PCI mapped skbs. + Alan Cox + Added new PCI identifiers provided by Clear Zhang at ALi + for their 1563 ethernet device. + TODO Implement pci_driver::suspend() and pci_driver::resume() @@ -75,7 +79,6 @@ #include #include #include -#include #include #include #include @@ -1975,6 +1978,7 @@ { 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9102_ID }, { 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9100_ID }, { 0x1282, 0x9009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9009_ID }, + { 0x10B9, 0x5261, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9102_ID }, { 0, } }; MODULE_DEVICE_TABLE(pci, dmfe_pci_tbl); diff -Nru a/drivers/net/znet.c b/drivers/net/znet.c --- a/drivers/net/znet.c Wed Apr 2 22:24:04 2003 +++ b/drivers/net/znet.c Wed Apr 2 22:24:04 2003 @@ -107,7 +107,7 @@ /* This include could be elsewhere, since it is not wireless specific */ #include "wireless/i82593.h" -static const char version[] __initdata = "znet.c:v1.02 9/23/94 becker@scyld.com\n"; +static char version[] __initdata = "znet.c:v1.02 9/23/94 becker@scyld.com\n"; #ifndef ZNET_DEBUG #define ZNET_DEBUG 1 diff -Nru a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c --- a/drivers/oprofile/buffer_sync.c Wed Apr 2 22:24:04 2003 +++ b/drivers/oprofile/buffer_sync.c Wed Apr 2 22:24:04 2003 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "oprofile_stats.h" @@ -67,6 +68,19 @@ } +static int module_load_notify(struct notifier_block * self, unsigned long val, void * data) +{ + if (val != MODULE_STATE_COMING) + return 0; + + sync_cpu_buffers(); + down(&buffer_sem); + add_event_entry(ESCAPE_CODE); + add_event_entry(MODULE_LOADED_CODE); + up(&buffer_sem); + return 0; +} + static struct notifier_block exit_task_nb = { .notifier_call = exit_task_notify, }; @@ -79,6 +93,10 @@ .notifier_call = mm_notify, }; +static struct notifier_block module_load_nb = { + .notifier_call = module_load_notify, +}; + int sync_start(void) { @@ -98,9 +116,14 @@ err = profile_event_register(EXEC_UNMAP, &exec_unmap_nb); if (err) goto out3; + err = register_module_notifier(&module_load_nb); + if (err) + goto out4; out: return err; +out4: + profile_event_unregister(EXEC_UNMAP, &exec_unmap_nb); out3: profile_event_unregister(EXIT_MMAP, &exit_mmap_nb); out2: @@ -113,6 +136,7 @@ void sync_stop(void) { + unregister_module_notifier(&module_load_nb); profile_event_unregister(EXIT_TASK, &exit_task_nb); profile_event_unregister(EXIT_MMAP, &exit_mmap_nb); profile_event_unregister(EXEC_UNMAP, &exec_unmap_nb); diff -Nru a/drivers/oprofile/event_buffer.h b/drivers/oprofile/event_buffer.h --- a/drivers/oprofile/event_buffer.h Wed Apr 2 22:24:04 2003 +++ b/drivers/oprofile/event_buffer.h Wed Apr 2 22:24:04 2003 @@ -24,12 +24,13 @@ * then one of the following codes, then the * relevant data. */ -#define ESCAPE_CODE ~0UL +#define ESCAPE_CODE ~0UL #define CTX_SWITCH_CODE 1 #define CPU_SWITCH_CODE 2 #define COOKIE_SWITCH_CODE 3 #define KERNEL_ENTER_SWITCH_CODE 4 #define KERNEL_EXIT_SWITCH_CODE 5 +#define MODULE_LOADED_CODE 6 /* add data to the event buffer */ void add_event_entry(unsigned long data); diff -Nru a/drivers/parisc/eisa_eeprom.c b/drivers/parisc/eisa_eeprom.c --- a/drivers/parisc/eisa_eeprom.c Wed Apr 2 22:24:07 2003 +++ b/drivers/parisc/eisa_eeprom.c Wed Apr 2 22:24:07 2003 @@ -96,11 +96,21 @@ int __init eisa_eeprom_init(unsigned long addr) { - if (addr) { - eeprom_addr = addr; - misc_register(&eisa_eeprom_dev); - printk(KERN_INFO "EISA EEPROM at 0x%lx\n", eeprom_addr); + int retval; + + /* XXX why return success when we haven't done anything? */ + if (!addr) + return 0; + + eeprom_addr = addr; + + retval = misc_register(&eisa_eeprom_dev); + if (retval < 0) { + printk(KERN_ERR "EISA EEPROM: cannot register misc device.\n"); + return retval; } + + printk(KERN_INFO "EISA EEPROM at 0x%lx\n", eeprom_addr); return 0; } diff -Nru a/drivers/pci/Makefile b/drivers/pci/Makefile --- a/drivers/pci/Makefile Wed Apr 2 22:24:07 2003 +++ b/drivers/pci/Makefile Wed Apr 2 22:24:07 2003 @@ -29,6 +29,9 @@ obj-y += setup-bus.o endif +# Hotplug (eg, cardbus) now requires setup-bus +obj-$(CONFIG_HOTPLUG) += setup-bus.o + ifndef CONFIG_X86 obj-y += syscall.o endif diff -Nru a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig --- a/drivers/pcmcia/Kconfig Wed Apr 2 22:24:06 2003 +++ b/drivers/pcmcia/Kconfig Wed Apr 2 22:24:06 2003 @@ -82,10 +82,26 @@ config PCMCIA_SA1100 tristate "SA1100 support" depends on ARM && ARCH_SA1100 && PCMCIA + help + Say Y here to include support for SA11x0-based PCMCIA or CF + sockets, found on HP iPAQs, Yopy, and other StrongARM(R)/ + Xscale(R) embedded machines. + + This driver is also available as a module called sa1100_cs. config PCMCIA_SA1111 tristate "SA1111 support" - depends on PCMCIA_SA1100 && SA1111 + depends on ARM && ARCH_SA1100 && SA1111 && PCMCIA + help + Say Y here to include support for SA1111-based PCMCIA or CF + sockets, found on the Jornada 720, Graphicsmaster and other + StrongARM(R)/Xscale(R) embedded machines. + + This driver is also available as a module called sa1111_cs. + +config PCMCIA_PROBE + bool + default y if ISA && !ARCH_SA1100 && !ARCH_CLPS711X endmenu diff -Nru a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile --- a/drivers/pcmcia/Makefile Wed Apr 2 22:24:07 2003 +++ b/drivers/pcmcia/Makefile Wed Apr 2 22:24:07 2003 @@ -2,46 +2,43 @@ # Makefile for the kernel pcmcia subsystem (c/o David Hinds) # -obj-$(CONFIG_PCMCIA) += pcmcia_core.o ds.o +obj-$(CONFIG_PCMCIA) += pcmcia_core.o ds.o ifeq ($(CONFIG_CARDBUS),y) - obj-$(CONFIG_PCMCIA) += yenta_socket.o + obj-$(CONFIG_PCMCIA) += yenta_socket.o endif -obj-$(CONFIG_I82365) += i82365.o -obj-$(CONFIG_I82092) += i82092.o -obj-$(CONFIG_TCIC) += tcic.o -obj-$(CONFIG_HD64465_PCMCIA) += hd64465_ss.o -obj-$(CONFIG_PCMCIA_SA1100) += sa1100_cs.o -obj-$(CONFIG_PCMCIA_SA1111) += sa1111_cs.o +obj-$(CONFIG_I82365) += i82365.o +obj-$(CONFIG_I82092) += i82092.o +obj-$(CONFIG_TCIC) += tcic.o +obj-$(CONFIG_HD64465_PCMCIA) += hd64465_ss.o +obj-$(CONFIG_PCMCIA_SA1100) += sa11xx_core.o sa1100_cs.o +obj-$(CONFIG_PCMCIA_SA1111) += sa11xx_core.o sa1111_cs.o -yenta_socket-objs := pci_socket.o yenta.o +yenta_socket-y += pci_socket.o yenta.o -pcmcia_core-objs-y := cistpl.o rsrc_mgr.o bulkmem.o cs.o -pcmcia_core-objs-$(CONFIG_CARDBUS) += cardbus.o -pcmcia_core-objs := $(pcmcia_core-objs-y) +pcmcia_core-y += cistpl.o rsrc_mgr.o bulkmem.o cs.o +pcmcia_core-$(CONFIG_CARDBUS) += cardbus.o -sa1111_cs-objs-y := sa1111_generic.o -sa1111_cs-objs-$(CONFIG_SA1100_ADSBITSY) += sa1100_adsbitsy.o -sa1111_cs-objs-$(CONFIG_ASSABET_NEPONSET) += sa1100_neponset.o -sa1111_cs-objs-$(CONFIG_SA1100_BADGE4) += sa1100_badge4.o -sa1111_cs-objs-$(CONFIG_SA1100_GRAPHICSMASTER) += sa1100_graphicsmaster.o -sa1111_cs-objs-$(CONFIG_SA1100_JORNADA720) += sa1100_jornada720.o -sa1111_cs-objs-$(CONFIG_SA1100_PFS168) += sa1100_pfs168.o -sa1111_cs-objs-$(CONFIG_SA1100_PT_SYSTEM3) += sa1100_system3.o -sa1111_cs-objs-$(CONFIG_SA1100_XP860) += sa1100_xp860.o -sa1111_cs-objs := $(sa1111_cs-objs-y) +sa1111_cs-y += sa1111_generic.o +sa1111_cs-$(CONFIG_SA1100_ADSBITSY) += sa1100_adsbitsy.o +sa1111_cs-$(CONFIG_ASSABET_NEPONSET) += sa1100_neponset.o +sa1111_cs-$(CONFIG_SA1100_BADGE4) += sa1100_badge4.o +sa1111_cs-$(CONFIG_SA1100_GRAPHICSMASTER) += sa1100_graphicsmaster.o +sa1111_cs-$(CONFIG_SA1100_JORNADA720) += sa1100_jornada720.o +sa1111_cs-$(CONFIG_SA1100_PFS168) += sa1100_pfs168.o +sa1111_cs-$(CONFIG_SA1100_PT_SYSTEM3) += sa1100_system3.o +sa1111_cs-$(CONFIG_SA1100_XP860) += sa1100_xp860.o -sa1100_cs-objs-y := sa1100_generic.o -sa1100_cs-objs-$(CONFIG_SA1100_ASSABET) += sa1100_assabet.o -sa1100_cs-objs-$(CONFIG_SA1100_CERF) += sa1100_cerf.o -sa1100_cs-objs-$(CONFIG_SA1100_FLEXANET) += sa1100_flexanet.o -sa1100_cs-objs-$(CONFIG_SA1100_FREEBIRD) += sa1100_freebird.o -sa1100_cs-objs-$(CONFIG_SA1100_GRAPHICSCLIENT) += sa1100_graphicsclient.o -sa1100_cs-objs-$(CONFIG_SA1100_H3600) += sa1100_h3600.o -sa1100_cs-objs-$(CONFIG_SA1100_PANGOLIN) += sa1100_pangolin.o -sa1100_cs-objs-$(CONFIG_SA1100_SHANNON) += sa1100_shannon.o -sa1100_cs-objs-$(CONFIG_SA1100_SIMPAD) += sa1100_simpad.o -sa1100_cs-objs-$(CONFIG_SA1100_STORK) += sa1100_stork.o -sa1100_cs-objs-$(CONFIG_SA1100_TRIZEPS) += sa1100_trizeps.o -sa1100_cs-objs-$(CONFIG_SA1100_YOPY) += sa1100_yopy.o -sa1100_cs-objs := $(sa1100_cs-objs-y) +sa1100_cs-y += sa1100_generic.o +sa1100_cs-$(CONFIG_SA1100_ASSABET) += sa1100_assabet.o +sa1100_cs-$(CONFIG_SA1100_CERF) += sa1100_cerf.o +sa1100_cs-$(CONFIG_SA1100_FLEXANET) += sa1100_flexanet.o +sa1100_cs-$(CONFIG_SA1100_FREEBIRD) += sa1100_freebird.o +sa1100_cs-$(CONFIG_SA1100_GRAPHICSCLIENT) += sa1100_graphicsclient.o +sa1100_cs-$(CONFIG_SA1100_H3600) += sa1100_h3600.o +sa1100_cs-$(CONFIG_SA1100_PANGOLIN) += sa1100_pangolin.o +sa1100_cs-$(CONFIG_SA1100_SHANNON) += sa1100_shannon.o +sa1100_cs-$(CONFIG_SA1100_SIMPAD) += sa1100_simpad.o +sa1100_cs-$(CONFIG_SA1100_STORK) += sa1100_stork.o +sa1100_cs-$(CONFIG_SA1100_TRIZEPS) += sa1100_trizeps.o +sa1100_cs-$(CONFIG_SA1100_YOPY) += sa1100_yopy.o diff -Nru a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c --- a/drivers/pcmcia/cardbus.c Wed Apr 2 22:24:04 2003 +++ b/drivers/pcmcia/cardbus.c Wed Apr 2 22:24:04 2003 @@ -87,10 +87,6 @@ #define PCDATA_CODE_TYPE 0x0014 #define PCDATA_INDICATOR 0x0015 -typedef struct cb_config_t { - struct pci_dev *dev[8]; -} cb_config_t; - /*===================================================================== Expansion ROM's have a special layout, and pointers specify an @@ -173,11 +169,10 @@ DEBUG(3, "cs: read_cb_mem(%d, %#x, %u)\n", space, addr, len); - if (!s->cb_config) + dev = pci_find_slot(s->cap.cb_dev->subordinate->number, 0); + if (!dev) goto fail; - dev = s->cb_config->dev[0]; - /* Config space? */ if (space == 0) { if (addr + len > 0x100) @@ -219,171 +214,61 @@ =====================================================================*/ -int cb_alloc(socket_info_t * s) +/* + * Since there is only one interrupt available to CardBus + * devices, all devices downstream of this device must + * be using this IRQ. + */ +static void cardbus_assign_irqs(struct pci_bus *bus, int irq) { - struct pci_bus *bus; - u_short vend, v, dev; - u_char i, hdr, fn; - cb_config_t *c; - int irq; - - bus = s->cap.cb_dev->subordinate; - - pci_bus_read_config_word(bus, 0, PCI_VENDOR_ID, &vend); - pci_bus_read_config_word(bus, 0, PCI_DEVICE_ID, &dev); - printk(KERN_INFO "cs: cb_alloc(bus %d): vendor 0x%04x, " - "device 0x%04x\n", bus->number, vend, dev); - - pci_bus_read_config_byte(bus, 0, PCI_HEADER_TYPE, &hdr); - fn = 1; - if (hdr & 0x80) { - do { - if (pci_bus_read_config_word(bus, fn, PCI_VENDOR_ID, &v) || - !v || v == 0xffff) - break; - fn++; - } while (fn < 8); - } - s->functions = fn; - - c = kmalloc(sizeof(struct cb_config_t), GFP_ATOMIC); - if (!c) - return CS_OUT_OF_RESOURCE; - memset(c, 0, sizeof(struct cb_config_t)); - - for (i = 0; i < fn; i++) { - c->dev[i] = kmalloc(sizeof(struct pci_dev), GFP_ATOMIC); - if (!c->dev[i]) { - for (; i--; ) - kfree(c->dev[i]); - kfree(c); - return CS_OUT_OF_RESOURCE; - } - memset(c->dev[i], 0, sizeof(struct pci_dev)); - } + struct pci_dev *dev; - irq = s->cap.pci_irq; - for (i = 0; i < fn; i++) { - struct pci_dev *dev = c->dev[i]; + list_for_each_entry(dev, &bus->devices, bus_list) { u8 irq_pin; - int r; - - dev->bus = bus; - dev->sysdata = bus->sysdata; - dev->dev.parent = bus->dev; - dev->dev.bus = &pci_bus_type; - dev->devfn = i; - - pci_read_config_word(dev, PCI_VENDOR_ID, &dev->vendor); - pci_read_config_word(dev, PCI_DEVICE_ID, &dev->device); - dev->hdr_type = hdr & 0x7f; - dev->dma_mask = 0xffffffff; - dev->dev.dma_mask = &dev->dma_mask; - - pci_setup_device(dev); - - strcpy(dev->dev.bus_id, dev->slot_name); - - /* We need to assign resources for expansion ROM. */ - for (r = 0; r < 7; r++) { - struct resource *res = dev->resource + r; - if (res->flags) - pci_assign_resource(dev, r); - } - /* Does this function have an interrupt at all? */ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin); - if (irq_pin) + if (irq_pin) { dev->irq = irq; - - /* pci_enable_device needs to be called after pci_assign_resource */ - /* because it returns an error if (!res->start && res->end). */ - if (pci_enable_device(dev)) - continue; - - if (irq_pin) - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); - - device_register(&dev->dev); - pci_insert_device(dev, bus); - } - - s->cb_config = c; - s->irq.AssignedIRQ = irq; - return CS_SUCCESS; -} - -void cb_free(socket_info_t * s) -{ - cb_config_t *c = s->cb_config; - - if (c) { - s->cb_config = NULL; - pci_remove_behind_bridge(s->cap.cb_dev); + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + } - kfree(c); - printk(KERN_INFO "cs: cb_free(bus %d)\n", s->cap.cb_dev->subordinate->number); + if (dev->subordinate) + cardbus_assign_irqs(dev->subordinate, irq); } } -/*===================================================================== - - cb_enable() has the job of configuring a socket for a Cardbus - card, and initializing the card's PCI configuration registers. - - It first sets up the Cardbus bridge windows, for IO and memory - accesses. Then, it initializes each card function's base address - registers, interrupt line register, and command register. - - It is called as part of the RequestConfiguration card service. - It should be called after a previous call to cb_config() (via the - RequestIO service). - -======================================================================*/ - -void cb_enable(socket_info_t * s) +int cb_alloc(socket_info_t * s) { + struct pci_bus *bus = s->cap.cb_dev->subordinate; struct pci_dev *dev; - u_char i; + unsigned int max, pass; - DEBUG(0, "cs: cb_enable(bus %d)\n", s->cap.cb_dev->subordinate->number); + s->functions = pci_scan_slot(bus, PCI_DEVFN(0, 0)); +// pcibios_fixup_bus(bus); - /* Configure bridge */ - cb_release_cis_mem(s); - - /* Set up PCI interrupt and command registers */ - for (i = 0; i < s->functions; i++) { - dev = s->cb_config->dev[i]; - pci_write_config_byte(dev, PCI_COMMAND, PCI_COMMAND_MASTER | - PCI_COMMAND_IO | PCI_COMMAND_MEMORY); - pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, - L1_CACHE_BYTES / 4); - } + max = bus->secondary; + for (pass = 0; pass < 2; pass++) + list_for_each_entry(dev, &bus->devices, bus_list) + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || + dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) + max = pci_scan_bridge(bus, dev, max, pass); + + /* + * Size all resources below the CardBus controller. + */ + pci_bus_size_bridges(bus); + pci_bus_assign_resources(bus); + cardbus_assign_irqs(bus, s->cap.pci_irq); + pci_enable_bridges(bus); + pci_bus_add_devices(bus); - if (s->irq.AssignedIRQ) { - for (i = 0; i < s->functions; i++) { - dev = s->cb_config->dev[i]; - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, - s->irq.AssignedIRQ); - } - s->socket.io_irq = s->irq.AssignedIRQ; - s->ss_entry->set_socket(s->sock, &s->socket); - } + s->irq.AssignedIRQ = s->cap.pci_irq; + return CS_SUCCESS; } -/*====================================================================== - - cb_disable() unconfigures a Cardbus card previously set up by - cb_enable(). - - It is called from the ReleaseConfiguration service. - -======================================================================*/ - -void cb_disable(socket_info_t * s) +void cb_free(socket_info_t * s) { - DEBUG(0, "cs: cb_disable(bus %d)\n", s->cap.cb_dev->subordinate->number); + struct pci_dev *bridge = s->cap.cb_dev; - /* Turn off bridge windows */ - cb_release_cis_mem(s); + pci_remove_behind_bridge(bridge); } diff -Nru a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c --- a/drivers/pcmcia/cistpl.c Wed Apr 2 22:24:05 2003 +++ b/drivers/pcmcia/cistpl.c Wed Apr 2 22:24:05 2003 @@ -47,7 +47,6 @@ #include #include -#include #include #include #include @@ -83,6 +82,52 @@ INT_MODULE_PARM(cis_width, 0); /* 16-bit CIS? */ +void release_cis_mem(socket_info_t *s) +{ + if (s->cis_mem.sys_start != 0) { + s->cis_mem.flags &= ~MAP_ACTIVE; + s->ss_entry->set_mem_map(s->sock, &s->cis_mem); + if (!(s->cap.features & SS_CAP_STATIC_MAP)) + release_mem_region(s->cis_mem.sys_start, s->cap.map_size); + iounmap(s->cis_virt); + s->cis_mem.sys_start = 0; + s->cis_virt = NULL; + } +} + +/* + * Map the card memory at "card_offset" into virtual space. + * If flags & MAP_ATTRIB, map the attribute space, otherwise + * map the memory space. + */ +static unsigned char * +set_cis_map(socket_info_t *s, unsigned int card_offset, unsigned int flags) +{ + pccard_mem_map *mem = &s->cis_mem; + if (!(s->cap.features & SS_CAP_STATIC_MAP) && + mem->sys_start == 0) { + int low = !(s->cap.features & SS_CAP_PAGE_REGS); + validate_mem(s); + mem->sys_start = 0; + if (find_mem_region(&mem->sys_start, s->cap.map_size, + s->cap.map_size, low, "card services", s)) { + printk(KERN_NOTICE "cs: unable to map card memory!\n"); + return NULL; + } + mem->sys_stop = mem->sys_start+s->cap.map_size-1; + s->cis_virt = ioremap(mem->sys_start, s->cap.map_size); + } + mem->card_start = card_offset; + mem->flags = flags; + s->ss_entry->set_mem_map(s->sock, mem); + if (s->cap.features & SS_CAP_STATIC_MAP) { + if (s->cis_virt) + iounmap(s->cis_virt); + s->cis_virt = ioremap(mem->sys_start, s->cap.map_size); + } + return s->cis_virt; +} + /*====================================================================== Low-level functions to read and write CIS memory. I think the @@ -94,60 +139,60 @@ #define IS_ATTR 1 #define IS_INDIRECT 8 -static int setup_cis_mem(socket_info_t *s); - -static void set_cis_map(socket_info_t *s, pccard_mem_map *mem) -{ - s->ss_entry->set_mem_map(s->sock, mem); - if (s->cap.features & SS_CAP_STATIC_MAP) { - if (s->cis_virt) - bus_iounmap(s->cap.bus, s->cis_virt); - s->cis_virt = bus_ioremap(s->cap.bus, mem->sys_start, - s->cap.map_size); - } -} - int read_cis_mem(socket_info_t *s, int attr, u_int addr, u_int len, void *ptr) { - pccard_mem_map *mem = &s->cis_mem; - u_char *sys, *buf = ptr; + u_char *sys, *end, *buf = ptr; DEBUG(3, "cs: read_cis_mem(%d, %#x, %u)\n", attr, addr, len); - if (setup_cis_mem(s) != 0) { - memset(ptr, 0xff, len); - return -1; - } - mem->flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0); if (attr & IS_INDIRECT) { /* Indirect accesses use a bunch of special registers at fixed locations in common memory */ u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN; - if (attr & IS_ATTR) { addr *= 2; flags = ICTRL0_AUTOINC; } - mem->card_start = 0; mem->flags = MAP_ACTIVE; - set_cis_map(s, mem); - sys = s->cis_virt; - bus_writeb(s->cap.bus, flags, sys+CISREG_ICTRL0); - bus_writeb(s->cap.bus, addr & 0xff, sys+CISREG_IADDR0); - bus_writeb(s->cap.bus, (addr>>8) & 0xff, sys+CISREG_IADDR1); - bus_writeb(s->cap.bus, (addr>>16) & 0xff, sys+CISREG_IADDR2); - bus_writeb(s->cap.bus, (addr>>24) & 0xff, sys+CISREG_IADDR3); + if (attr & IS_ATTR) { + addr *= 2; + flags = ICTRL0_AUTOINC; + } + + sys = set_cis_map(s, 0, MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0)); + if (!sys) { + memset(ptr, 0xff, len); + return -1; + } + + writeb(flags, sys+CISREG_ICTRL0); + writeb(addr & 0xff, sys+CISREG_IADDR0); + writeb((addr>>8) & 0xff, sys+CISREG_IADDR1); + writeb((addr>>16) & 0xff, sys+CISREG_IADDR2); + writeb((addr>>24) & 0xff, sys+CISREG_IADDR3); for ( ; len > 0; len--, buf++) - *buf = bus_readb(s->cap.bus, sys+CISREG_IDATA0); + *buf = readb(sys+CISREG_IDATA0); } else { - u_int inc = 1; - if (attr) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; } - sys += (addr & (s->cap.map_size-1)); - mem->card_start = addr & ~(s->cap.map_size-1); + u_int inc = 1, card_offset, flags; + + flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0); + if (attr) { + flags |= MAP_ATTRIB; + inc++; + addr *= 2; + } + + card_offset = addr & ~(s->cap.map_size-1); while (len) { - set_cis_map(s, mem); - sys = s->cis_virt + (addr & (s->cap.map_size-1)); + sys = set_cis_map(s, card_offset, flags); + if (!sys) { + memset(ptr, 0xff, len); + return -1; + } + end = sys + s->cap.map_size; + sys = sys + (addr & (s->cap.map_size-1)); for ( ; len > 0; len--, buf++, sys += inc) { - if (sys == s->cis_virt+s->cap.map_size) break; - *buf = bus_readb(s->cap.bus, sys); + if (sys == end) + break; + *buf = readb(sys); } - mem->card_start += s->cap.map_size; + card_offset += s->cap.map_size; addr = 0; } } @@ -160,40 +205,54 @@ void write_cis_mem(socket_info_t *s, int attr, u_int addr, u_int len, void *ptr) { - pccard_mem_map *mem = &s->cis_mem; - u_char *sys, *buf = ptr; + u_char *sys, *end, *buf = ptr; DEBUG(3, "cs: write_cis_mem(%d, %#x, %u)\n", attr, addr, len); - if (setup_cis_mem(s) != 0) return; - mem->flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0); if (attr & IS_INDIRECT) { /* Indirect accesses use a bunch of special registers at fixed locations in common memory */ u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN; - if (attr & IS_ATTR) { addr *= 2; flags = ICTRL0_AUTOINC; } - mem->card_start = 0; mem->flags = MAP_ACTIVE; - set_cis_map(s, mem); - sys = s->cis_virt; - bus_writeb(s->cap.bus, flags, sys+CISREG_ICTRL0); - bus_writeb(s->cap.bus, addr & 0xff, sys+CISREG_IADDR0); - bus_writeb(s->cap.bus, (addr>>8) & 0xff, sys+CISREG_IADDR1); - bus_writeb(s->cap.bus, (addr>>16) & 0xff, sys+CISREG_IADDR2); - bus_writeb(s->cap.bus, (addr>>24) & 0xff, sys+CISREG_IADDR3); + if (attr & IS_ATTR) { + addr *= 2; + flags = ICTRL0_AUTOINC; + } + + sys = set_cis_map(s, 0, MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0)); + if (!sys) + return; /* FIXME: Error */ + + writeb(flags, sys+CISREG_ICTRL0); + writeb(addr & 0xff, sys+CISREG_IADDR0); + writeb((addr>>8) & 0xff, sys+CISREG_IADDR1); + writeb((addr>>16) & 0xff, sys+CISREG_IADDR2); + writeb((addr>>24) & 0xff, sys+CISREG_IADDR3); for ( ; len > 0; len--, buf++) - bus_writeb(s->cap.bus, *buf, sys+CISREG_IDATA0); + writeb(*buf, sys+CISREG_IDATA0); } else { - int inc = 1; - if (attr & IS_ATTR) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; } - mem->card_start = addr & ~(s->cap.map_size-1); + u_int inc = 1, card_offset, flags; + + flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0); + if (attr & IS_ATTR) { + flags |= MAP_ATTRIB; + inc++; + addr *= 2; + } + + card_offset = addr & ~(s->cap.map_size-1); while (len) { - set_cis_map(s, mem); - sys = s->cis_virt + (addr & (s->cap.map_size-1)); + sys = set_cis_map(s, card_offset, flags); + if (!sys) + return; /* FIXME: error */ + + end = sys + s->cap.map_size; + sys = sys + (addr & (s->cap.map_size-1)); for ( ; len > 0; len--, buf++, sys += inc) { - if (sys == s->cis_virt+s->cap.map_size) break; - bus_writeb(s->cap.bus, *buf, sys); + if (sys == end) + break; + writeb(*buf, sys); } - mem->card_start += s->cap.map_size; + card_offset += s->cap.map_size; addr = 0; } } @@ -201,98 +260,6 @@ /*====================================================================== - This is tricky... when we set up CIS memory, we try to validate - the memory window space allocations. - -======================================================================*/ - -/* Scratch pointer to the socket we use for validation */ -static socket_info_t *vs = NULL; - -/* Validation function for cards with a valid CIS */ -static int cis_readable(u_long base) -{ - cisinfo_t info1, info2; - int ret; - vs->cis_mem.sys_start = base; - vs->cis_mem.sys_stop = base+vs->cap.map_size-1; - vs->cis_virt = bus_ioremap(vs->cap.bus, base, vs->cap.map_size); - ret = pcmcia_validate_cis(vs->clients, &info1); - /* invalidate mapping and CIS cache */ - bus_iounmap(vs->cap.bus, vs->cis_virt); vs->cis_used = 0; - if ((ret != 0) || (info1.Chains == 0)) - return 0; - vs->cis_mem.sys_start = base+vs->cap.map_size; - vs->cis_mem.sys_stop = base+2*vs->cap.map_size-1; - vs->cis_virt = bus_ioremap(vs->cap.bus, base+vs->cap.map_size, - vs->cap.map_size); - ret = pcmcia_validate_cis(vs->clients, &info2); - bus_iounmap(vs->cap.bus, vs->cis_virt); vs->cis_used = 0; - return ((ret == 0) && (info1.Chains == info2.Chains)); -} - -/* Validation function for simple memory cards */ -static int checksum(u_long base) -{ - int i, a, b, d; - vs->cis_mem.sys_start = base; - vs->cis_mem.sys_stop = base+vs->cap.map_size-1; - vs->cis_virt = bus_ioremap(vs->cap.bus, base, vs->cap.map_size); - vs->cis_mem.card_start = 0; - vs->cis_mem.flags = MAP_ACTIVE; - vs->ss_entry->set_mem_map(vs->sock, &vs->cis_mem); - /* Don't bother checking every word... */ - a = 0; b = -1; - for (i = 0; i < vs->cap.map_size; i += 44) { - d = bus_readl(vs->cap.bus, vs->cis_virt+i); - a += d; b &= d; - } - bus_iounmap(vs->cap.bus, vs->cis_virt); - return (b == -1) ? -1 : (a>>1); -} - -static int checksum_match(u_long base) -{ - int a = checksum(base), b = checksum(base+vs->cap.map_size); - return ((a == b) && (a >= 0)); -} - -static int setup_cis_mem(socket_info_t *s) -{ - if (!(s->cap.features & SS_CAP_STATIC_MAP) && - (s->cis_mem.sys_start == 0)) { - int low = !(s->cap.features & SS_CAP_PAGE_REGS); - vs = s; - validate_mem(cis_readable, checksum_match, low, s); - s->cis_mem.sys_start = 0; - vs = NULL; - if (find_mem_region(&s->cis_mem.sys_start, s->cap.map_size, - s->cap.map_size, low, "card services", s)) { - printk(KERN_NOTICE "cs: unable to map card memory!\n"); - return -1; - } - s->cis_mem.sys_stop = s->cis_mem.sys_start+s->cap.map_size-1; - s->cis_virt = bus_ioremap(s->cap.bus, s->cis_mem.sys_start, - s->cap.map_size); - } - return 0; -} - -void release_cis_mem(socket_info_t *s) -{ - if (s->cis_mem.sys_start != 0) { - s->cis_mem.flags &= ~MAP_ACTIVE; - s->ss_entry->set_mem_map(s->sock, &s->cis_mem); - if (!(s->cap.features & SS_CAP_STATIC_MAP)) - release_mem_region(s->cis_mem.sys_start, s->cap.map_size); - bus_iounmap(s->cap.bus, s->cis_virt); - s->cis_mem.sys_start = 0; - s->cis_virt = NULL; - } -} - -/*====================================================================== - This is a wrapper around read_cis_mem, with the same interface, but which caches information, for cards whose CIS may not be readable all the time. @@ -427,11 +394,9 @@ tuple->TupleLink = tuple->Flags = 0; #ifdef CONFIG_CARDBUS if (s->state & SOCKET_CARDBUS) { + struct pci_dev *dev = s->cap.cb_dev; u_int ptr; - struct pci_dev *dev = pci_find_slot (s->cap.cb_dev->subordinate->number, 0); - if (!dev) - return CS_BAD_HANDLE; - pci_read_config_dword(dev, 0x28, &ptr); + pci_bus_read_config_dword(dev->subordinate, 0, PCI_CARDBUS_CIS, &ptr); tuple->CISOffset = ptr & ~7; SPACE(tuple->Flags) = (ptr & 7); } else diff -Nru a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c --- a/drivers/pcmcia/cs.c Wed Apr 2 22:24:04 2003 +++ b/drivers/pcmcia/cs.c Wed Apr 2 22:24:04 2003 @@ -59,7 +59,6 @@ #include #include #include -#include #include "cs_internal.h" #ifdef CONFIG_PCI @@ -112,13 +111,6 @@ /* Access speed for IO windows */ INT_MODULE_PARM(io_speed, 0); /* ns */ -/* Optional features */ -#ifdef CONFIG_PM -INT_MODULE_PARM(do_apm, 1); -#else -INT_MODULE_PARM(do_apm, 0); -#endif - #ifdef PCMCIA_DEBUG INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); static const char *version = @@ -349,7 +341,6 @@ /* base address = 0, map = 0 */ s->cis_mem.flags = 0; s->cis_mem.speed = cis_speed; - s->use_bus_pm = cls_d->use_bus_pm; s->erase_busy.next = s->erase_busy.prev = &s->erase_busy; spin_lock_init(&s->lock); @@ -622,8 +613,10 @@ send_event(s, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW); } else if (s->state & SOCKET_SETUP_PENDING) { #ifdef CONFIG_CARDBUS - if (s->state & SOCKET_CARDBUS) + if (s->state & SOCKET_CARDBUS) { cb_alloc(s); + s->state |= SOCKET_CARDBUS_CONFIG; + } #endif send_event(s, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW); s->state &= ~SOCKET_SETUP_PENDING; @@ -654,6 +647,8 @@ DEBUG(1, "cs: send_event(sock %d, event %d, pri %d)\n", s->sock, event, priority); ret = 0; + if (s->state & SOCKET_CARDBUS) + return 0; for (; client; client = client->next) { if (client->state & (CLIENT_UNBOUND|CLIENT_STALE)) continue; @@ -755,33 +750,47 @@ parse_events(s, SS_DETECT); } -static int handle_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data) + +int pcmcia_socket_dev_suspend(struct device * dev, u32 state, u32 level) { - int i; - socket_info_t *s; + struct pcmcia_socket_class_data *cls_d = to_class_data(dev); + socket_info_t *s; + int i; - /* only for busses that don't suspend/resume slots directly */ + if ((!cls_d) || (level != SUSPEND_SAVE_STATE)) + return 0; - switch (rqst) { - case PM_SUSPEND: - DEBUG(1, "cs: received suspend notification\n"); - for (i = 0; i < sockets; i++) { - s = socket_table [i]; - if (!s->use_bus_pm) - pcmcia_suspend_socket (socket_table [i]); + s = (socket_info_t *) cls_d->s_info; + + for (i = 0; i < cls_d->nsock; i++) { + pcmcia_suspend_socket(s); + s++; } - break; - case PM_RESUME: - DEBUG(1, "cs: received resume notification\n"); - for (i = 0; i < sockets; i++) { - s = socket_table [i]; - if (!s->use_bus_pm) - pcmcia_resume_socket (socket_table [i]); + + return 0; +} +EXPORT_SYMBOL(pcmcia_socket_dev_suspend); + +int pcmcia_socket_dev_resume(struct device * dev, u32 level) +{ + struct pcmcia_socket_class_data *cls_d = to_class_data(dev); + socket_info_t *s; + int i; + + if ((!cls_d) || (level != RESUME_RESTORE_STATE)) + return 0; + + s = (socket_info_t *) cls_d->s_info; + + for (i = 0; i < cls_d->nsock; i++) { + pcmcia_resume_socket(s); + s++; } - break; - } - return 0; -} /* handle_pm_event */ + + return 0; +} +EXPORT_SYMBOL(pcmcia_socket_dev_resume); + /*====================================================================== @@ -1077,7 +1086,7 @@ config->Vcc = s->socket.Vcc; config->Vpp1 = config->Vpp2 = s->socket.Vpp; config->Option = s->cap.cb_dev->subordinate->number; - if (s->cb_config) { + if (s->state & SOCKET_CARDBUS_CONFIG) { config->Attributes = CONF_VALID_CLIENT; config->IntType = INT_CARDBUS; config->AssignedIRQ = s->irq.AssignedIRQ; @@ -1473,7 +1482,6 @@ client->event_handler = req->event_handler; client->event_callback_args = req->event_callback_args; client->event_callback_args.client_handle = client; - client->event_callback_args.bus = s->cap.bus; if (s->state & SOCKET_CARDBUS) client->state |= CLIENT_CARDBUS; @@ -1522,11 +1530,8 @@ s = SOCKET(handle); #ifdef CONFIG_CARDBUS - if (handle->state & CLIENT_CARDBUS) { - cb_disable(s); - s->lock_count = 0; + if (handle->state & CLIENT_CARDBUS) return CS_SUCCESS; - } #endif if (!(handle->state & CLIENT_STALE)) { @@ -1573,9 +1578,8 @@ s = SOCKET(handle); #ifdef CONFIG_CARDBUS - if (handle->state & CLIENT_CARDBUS) { + if (handle->state & CLIENT_CARDBUS) return CS_SUCCESS; - } #endif if (!(handle->state & CLIENT_STALE)) { @@ -1622,10 +1626,10 @@ } if (req->Attributes & IRQ_HANDLE_PRESENT) { - bus_free_irq(s->cap.bus, req->AssignedIRQ, req->Instance); + free_irq(req->AssignedIRQ, req->Instance); } -#ifdef CONFIG_ISA +#ifdef CONFIG_PCMCIA_PROBE if (req->AssignedIRQ != s->cap.pci_irq) undo_irq(req->Attributes, req->AssignedIRQ); #endif @@ -1678,16 +1682,8 @@ return CS_NO_CARD; #ifdef CONFIG_CARDBUS - if (handle->state & CLIENT_CARDBUS) { - if (!(req->IntType & INT_CARDBUS)) - return CS_UNSUPPORTED_MODE; - if (s->lock_count != 0) - return CS_CONFIGURATION_LOCKED; - cb_enable(s); - handle->state |= CLIENT_CONFIG_LOCKED; - s->lock_count++; - return CS_SUCCESS; - } + if (handle->state & CLIENT_CARDBUS) + return CS_UNSUPPORTED_MODE; #endif if (req->IntType & INT_CARDBUS) @@ -1887,7 +1883,7 @@ if (!s->cap.irq_mask) { irq = s->cap.pci_irq; ret = (irq) ? 0 : CS_IN_USE; -#ifdef CONFIG_ISA +#ifdef CONFIG_PCMCIA_PROBE } else if (s->irq.AssignedIRQ != 0) { /* If the interrupt is already assigned, it must match */ irq = s->irq.AssignedIRQ; @@ -1917,7 +1913,7 @@ if (ret != 0) return ret; if (req->Attributes & IRQ_HANDLE_PRESENT) { - if (bus_request_irq(s->cap.bus, irq, req->Handler, + if (request_irq(irq, req->Handler, ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) || (s->functions > 1) || (irq == s->cap.pci_irq)) ? SA_SHIRQ : 0, @@ -2441,8 +2437,6 @@ printk(KERN_INFO " %s\n", options); DEBUG(0, "%s\n", version); devclass_register(&pcmcia_socket_class); - if (do_apm) - pm_register(PM_SYS_DEV, PM_SYS_PCMCIA, handle_pm_event); #ifdef CONFIG_PROC_FS proc_pccard = proc_mkdir("pccard", proc_bus); #endif @@ -2458,8 +2452,6 @@ remove_proc_entry("pccard", proc_bus); } #endif - if (do_apm) - pm_unregister_all(handle_pm_event); release_resource_db(); devclass_unregister(&pcmcia_socket_class); } diff -Nru a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h --- a/drivers/pcmcia/cs_internal.h Wed Apr 2 22:24:04 2003 +++ b/drivers/pcmcia/cs_internal.h Wed Apr 2 22:24:04 2003 @@ -136,7 +136,6 @@ #ifdef CONFIG_CARDBUS struct resource * cb_cis_res; u_char *cb_cis_virt; - struct cb_config_t *cb_config; #endif struct { u_int AssignedIRQ; @@ -158,7 +157,6 @@ #ifdef CONFIG_PROC_FS struct proc_dir_entry *proc; #endif - int use_bus_pm; } socket_info_t; /* Flags in config state */ @@ -176,6 +174,7 @@ #define SOCKET_IO_REQ(i) (0x1000<<(i)) #define SOCKET_REGION_INFO 0x4000 #define SOCKET_CARDBUS 0x8000 +#define SOCKET_CARDBUS_CONFIG 0x10000 #define CHECK_HANDLE(h) \ (((h) == NULL) || ((h)->client_magic != CLIENT_MAGIC)) @@ -198,8 +197,6 @@ /* In cardbus.c */ int cb_alloc(socket_info_t *s); void cb_free(socket_info_t *s); -void cb_enable(socket_info_t *s); -void cb_disable(socket_info_t *s); int read_cb_mem(socket_info_t *s, int space, u_int addr, u_int len, void *ptr); void cb_release_cis_mem(socket_info_t *s); @@ -234,8 +231,7 @@ int copy_memory(memory_handle_t handle, copy_op_t *req); /* In rsrc_mgr */ -void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long), - int force_low, socket_info_t *s); +void validate_mem(socket_info_t *s); int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align, char *name, socket_info_t *s); int find_mem_region(u_long *base, u_long num, u_long align, diff -Nru a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c --- a/drivers/pcmcia/ds.c Wed Apr 2 22:24:06 2003 +++ b/drivers/pcmcia/ds.c Wed Apr 2 22:24:06 2003 @@ -48,6 +48,8 @@ #include #include #include +#include +#include #include #include @@ -55,6 +57,7 @@ #include #include #include +#include /*====================================================================*/ @@ -69,8 +72,6 @@ #ifdef PCMCIA_DEBUG INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static const char *version = -"ds.c 1.112 2001/10/13 00:08:28 (David Hinds)"; #else #define DEBUG(n, args...) #endif @@ -97,15 +98,18 @@ } user_info_t; /* Socket state information */ -typedef struct socket_info_t { - client_handle_t handle; - int state; - user_info_t *user; - int req_pending, req_result; - wait_queue_head_t queue, request; - struct timer_list removal; - socket_bind_t *bind; -} socket_info_t; +struct pcmcia_bus_socket { + client_handle_t handle; + int state; + user_info_t *user; + int req_pending, req_result; + wait_queue_head_t queue, request; + struct work_struct removal; + socket_bind_t *bind; + struct device *socket_dev; + struct list_head socket_list; + unsigned int socket_no; /* deprecated */ +}; #define SOCKET_PRESENT 0x01 #define SOCKET_BUSY 0x02 @@ -116,13 +120,13 @@ /* Device driver ID passed to Card Services */ static dev_info_t dev_info = "Driver Services"; -static int sockets = 0, major_dev = -1; -static socket_info_t *socket_table = NULL; +static int major_dev = -1; -extern struct proc_dir_entry *proc_pccard; +/* list of all sockets registered with the pcmcia bus driver */ +static DECLARE_RWSEM(bus_socket_list_rwsem); +static LIST_HEAD(bus_socket_list); -/* We use this to distinguish in-kernel from modular drivers */ -static int init_status = 1; +extern struct proc_dir_entry *proc_pccard; /*====================================================================*/ @@ -135,6 +139,7 @@ /*======================================================================*/ static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info); +static struct pcmcia_bus_socket * get_socket_info_by_nr(unsigned int nr); /** * pcmcia_register_driver - register a PCMCIA driver with the bus core @@ -147,7 +152,6 @@ return -EINVAL; driver->use_count = 0; - driver->status = init_status; driver->drv.bus = &pcmcia_bus_type; return driver_register(&driver->drv); @@ -160,17 +164,19 @@ void pcmcia_unregister_driver(struct pcmcia_driver *driver) { socket_bind_t *b; - int i; + struct pcmcia_bus_socket *bus_sock; if (driver->use_count > 0) { /* Blank out any left-over device instances */ driver->attach = NULL; driver->detach = NULL; - for (i = 0; i < sockets; i++) - for (b = socket_table[i].bind; b; b = b->next) + down_read(&bus_socket_list_rwsem); + list_for_each_entry(bus_sock, &bus_socket_list, socket_list) { + for (b = bus_sock->bind; b; b = b->next) if (b->driver == driver) b->instance = NULL; - } - + } + up_read(&bus_socket_list_rwsem); + } driver_unregister(&driver->drv); } EXPORT_SYMBOL(pcmcia_unregister_driver); @@ -181,33 +187,21 @@ void (*detach)(dev_link_t *)) { struct pcmcia_driver *driver; - socket_bind_t *b; - int i; DEBUG(0, "ds: register_pccard_driver('%s')\n", (char *)dev_info); driver = get_pcmcia_driver(dev_info); - if (!driver) { - driver = kmalloc(sizeof(struct pcmcia_driver), GFP_KERNEL); - if (!driver) return -ENOMEM; - memset(driver, 0, sizeof(struct pcmcia_driver)); - driver->drv.name = (char *)dev_info; - pcmcia_register_driver(driver); - } + if (driver) + return -EBUSY; + + driver = kmalloc(sizeof(struct pcmcia_driver), GFP_KERNEL); + if (!driver) return -ENOMEM; + memset(driver, 0, sizeof(struct pcmcia_driver)); + driver->drv.name = (char *)dev_info; + pcmcia_register_driver(driver); driver->attach = attach; driver->detach = detach; - if (driver->use_count == 0) return 0; - - /* Instantiate any already-bound devices */ - for (i = 0; i < sockets; i++) - for (b = socket_table[i].bind; b; b = b->next) { - if (b->driver != driver) continue; - b->instance = driver->attach(); - if (b->instance == NULL) - printk(KERN_NOTICE "ds: unable to create instance " - "of '%s'!\n", driver->drv.name); - } - + return 0; } /* register_pccard_driver */ @@ -238,8 +232,7 @@ struct pcmcia_driver *p_dev = container_of(driver, struct pcmcia_driver, drv); - *p += sprintf(*p, "%-24.24s %d %d\n", driver->name, p_dev->status, - p_dev->use_count); + *p += sprintf(*p, "%-24.24s 1 %d\n", driver->name, p_dev->use_count); d = (void *) p; return 0; @@ -282,7 +275,7 @@ user->event[user->event_head] = event; } -static void handle_event(socket_info_t *s, event_t event) +static void handle_event(struct pcmcia_bus_socket *s, event_t event) { user_info_t *user; for (user = s->user; user; user = user->next) @@ -290,7 +283,7 @@ wake_up_interruptible(&s->queue); } -static int handle_request(socket_info_t *s, event_t event) +static int handle_request(struct pcmcia_bus_socket *s, event_t event) { if (s->req_pending != 0) return CS_IN_USE; @@ -307,9 +300,9 @@ return CS_SUCCESS; } -static void handle_removal(u_long sn) +static void handle_removal(void *data) { - socket_info_t *s = &socket_table[sn]; + struct pcmcia_bus_socket *s = data; handle_event(s, CS_EVENT_CARD_REMOVAL); s->state &= ~SOCKET_REMOVAL_PENDING; } @@ -323,23 +316,19 @@ static int ds_event(event_t event, int priority, event_callback_args_t *args) { - socket_info_t *s; - int i; + struct pcmcia_bus_socket *s; DEBUG(1, "ds: ds_event(0x%06x, %d, 0x%p)\n", event, priority, args->client_handle); s = args->client_data; - i = s - socket_table; switch (event) { case CS_EVENT_CARD_REMOVAL: s->state &= ~SOCKET_PRESENT; if (!(s->state & SOCKET_REMOVAL_PENDING)) { - s->state |= SOCKET_REMOVAL_PENDING; - init_timer(&s->removal); - s->removal.expires = jiffies + HZ/10; - add_timer(&s->removal); + s->state |= SOCKET_REMOVAL_PENDING; + schedule_delayed_work(&s->removal, HZ/10); } break; @@ -366,21 +355,21 @@ ======================================================================*/ -static int bind_mtd(int i, mtd_info_t *mtd_info) +static int bind_mtd(struct pcmcia_bus_socket *bus_sock, mtd_info_t *mtd_info) { mtd_bind_t bind_req; int ret; bind_req.dev_info = &mtd_info->dev_info; bind_req.Attributes = mtd_info->Attributes; - bind_req.Socket = i; + bind_req.Socket = bus_sock->socket_no; bind_req.CardOffset = mtd_info->CardOffset; ret = pcmcia_bind_mtd(&bind_req); if (ret != CS_SUCCESS) { cs_error(NULL, BindMTD, ret); printk(KERN_NOTICE "ds: unable to bind MTD '%s' to socket %d" " offset 0x%x\n", - (char *)bind_req.dev_info, i, bind_req.CardOffset); + (char *)bind_req.dev_info, bus_sock->socket_no, bind_req.CardOffset); return -ENODEV; } return 0; @@ -395,24 +384,21 @@ ======================================================================*/ -static int bind_request(int i, bind_info_t *bind_info) +static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) { struct pcmcia_driver *driver; socket_bind_t *b; bind_req_t bind_req; - socket_info_t *s = &socket_table[i]; int ret; - DEBUG(2, "bind_request(%d, '%s')\n", i, + if (!s) + return -EINVAL; + + DEBUG(2, "bind_request(%d, '%s')\n", s->socket_no, (char *)bind_info->dev_info); driver = get_pcmcia_driver(&bind_info->dev_info); - if (driver == NULL) { - driver = kmalloc(sizeof(struct pcmcia_driver), GFP_KERNEL); - if (!driver) return -ENOMEM; - memset(driver, 0, sizeof(struct pcmcia_driver)); - driver->drv.name = bind_info->dev_info; - pcmcia_register_driver(driver); - } + if (!driver) + return -EINVAL; for (b = s->bind; b; b = b->next) if ((driver == b->driver) && @@ -423,14 +409,14 @@ return -EBUSY; } - bind_req.Socket = i; + bind_req.Socket = s->socket_no; bind_req.Function = bind_info->function; bind_req.dev_info = (dev_info_t *) driver->drv.name; ret = pcmcia_bind_device(&bind_req); if (ret != CS_SUCCESS) { cs_error(NULL, BindDevice, ret); printk(KERN_NOTICE "ds: unable to bind '%s' to socket %d\n", - (char *)dev_info, i); + (char *)dev_info, s->socket_no); return -ENODEV; } @@ -462,9 +448,8 @@ /*====================================================================*/ -static int get_device_info(int i, bind_info_t *bind_info, int first) +static int get_device_info(struct pcmcia_bus_socket *s, bind_info_t *bind_info, int first) { - socket_info_t *s = &socket_table[i]; socket_bind_t *b; dev_node_t *node; @@ -532,12 +517,11 @@ /*====================================================================*/ -static int unbind_request(int i, bind_info_t *bind_info) +static int unbind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info) { - socket_info_t *s = &socket_table[i]; socket_bind_t **b, *c; - DEBUG(2, "unbind_request(%d, '%s')\n", i, + DEBUG(2, "unbind_request(%d, '%s')\n", s->socket_no, (char *)bind_info->dev_info); for (b = &s->bind; *b; b = &(*b)->next) if ((strcmp((char *)(*b)->driver->drv.name, @@ -568,13 +552,15 @@ static int ds_open(struct inode *inode, struct file *file) { socket_t i = minor(inode->i_rdev); - socket_info_t *s; + struct pcmcia_bus_socket *s; user_info_t *user; DEBUG(0, "ds_open(socket %d)\n", i); - if ((i >= sockets) || (sockets == 0)) - return -ENODEV; - s = &socket_table[i]; + + s = get_socket_info_by_nr(i); + if (!s) + return -ENODEV; + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { if (s->state & SOCKET_BUSY) return -EBUSY; @@ -600,13 +586,15 @@ static int ds_release(struct inode *inode, struct file *file) { socket_t i = minor(inode->i_rdev); - socket_info_t *s; + struct pcmcia_bus_socket *s; user_info_t *user, **link; DEBUG(0, "ds_release(socket %d)\n", i); - if ((i >= sockets) || (sockets == 0)) - return 0; - s = &socket_table[i]; + + s = get_socket_info_by_nr(i); + if (!s) + return 0; + user = file->private_data; if (CHECK_USER(user)) goto out; @@ -632,16 +620,18 @@ size_t count, loff_t *ppos) { socket_t i = minor(file->f_dentry->d_inode->i_rdev); - socket_info_t *s; + struct pcmcia_bus_socket *s; user_info_t *user; DEBUG(2, "ds_read(socket %d)\n", i); - if ((i >= sockets) || (sockets == 0)) - return -ENODEV; if (count < 4) return -EINVAL; - s = &socket_table[i]; + + s = get_socket_info_by_nr(i); + if (!s) + return -ENODEV; + user = file->private_data; if (CHECK_USER(user)) return -EIO; @@ -661,18 +651,20 @@ size_t count, loff_t *ppos) { socket_t i = minor(file->f_dentry->d_inode->i_rdev); - socket_info_t *s; + struct pcmcia_bus_socket *s; user_info_t *user; DEBUG(2, "ds_write(socket %d)\n", i); - if ((i >= sockets) || (sockets == 0)) - return -ENODEV; if (count != 4) return -EINVAL; if ((file->f_flags & O_ACCMODE) == O_RDONLY) return -EBADF; - s = &socket_table[i]; + + s = get_socket_info_by_nr(i); + if (!s) + return -ENODEV; + user = file->private_data; if (CHECK_USER(user)) return -EIO; @@ -694,14 +686,15 @@ static u_int ds_poll(struct file *file, poll_table *wait) { socket_t i = minor(file->f_dentry->d_inode->i_rdev); - socket_info_t *s; + struct pcmcia_bus_socket *s; user_info_t *user; DEBUG(2, "ds_poll(socket %d)\n", i); - if ((i >= sockets) || (sockets == 0)) - return POLLERR; - s = &socket_table[i]; + s = get_socket_info_by_nr(i); + if (!s) + return POLLERR; + user = file->private_data; if (CHECK_USER(user)) return POLLERR; @@ -717,16 +710,16 @@ u_int cmd, u_long arg) { socket_t i = minor(inode->i_rdev); - socket_info_t *s; + struct pcmcia_bus_socket *s; u_int size; int ret, err; ds_ioctl_arg_t buf; DEBUG(2, "ds_ioctl(socket %d, %#x, %#lx)\n", i, cmd, arg); - if ((i >= sockets) || (sockets == 0)) - return -ENODEV; - s = &socket_table[i]; + s = get_socket_info_by_nr(i); + if (!s) + return -ENODEV; size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL; @@ -827,20 +820,20 @@ break; case DS_BIND_REQUEST: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - err = bind_request(i, &buf.bind_info); + err = bind_request(s, &buf.bind_info); break; case DS_GET_DEVICE_INFO: - err = get_device_info(i, &buf.bind_info, 1); + err = get_device_info(s, &buf.bind_info, 1); break; case DS_GET_NEXT_DEVICE: - err = get_device_info(i, &buf.bind_info, 0); + err = get_device_info(s, &buf.bind_info, 0); break; case DS_UNBIND_REQUEST: - err = unbind_request(i, &buf.bind_info); + err = unbind_request(s, &buf.bind_info); break; case DS_BIND_MTD: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - err = bind_mtd(i, &buf.mtd_info); + err = bind_mtd(s, &buf.mtd_info); break; default: err = -EINVAL; @@ -889,140 +882,198 @@ /*====================================================================*/ -struct bus_type pcmcia_bus_type = { - .name = "pcmcia", -}; -EXPORT_SYMBOL(pcmcia_bus_type); - -static int __init init_pcmcia_bus(void) +static int __devinit pcmcia_bus_add_socket(struct device *dev, unsigned int socket_nr) { - bus_register(&pcmcia_bus_type); - return 0; -} + client_reg_t client_reg; + bind_req_t bind; + struct pcmcia_bus_socket *s, *tmp_s; + int ret; + int i; -static int __init init_pcmcia_ds(void) -{ - client_reg_t client_reg; - servinfo_t serv; - bind_req_t bind; - socket_info_t *s; - int i, ret; - - DEBUG(0, "%s\n", version); - - /* - * Ugly. But we want to wait for the socket threads to have started up. - * We really should let the drivers themselves drive some of this.. - */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ/4); + s = kmalloc(sizeof(struct pcmcia_bus_socket), GFP_KERNEL); + if(!s) + return -ENOMEM; + memset(s, 0, sizeof(struct pcmcia_bus_socket)); + + /* + * Ugly. But we want to wait for the socket threads to have started up. + * We really should let the drivers themselves drive some of this.. + */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ/4); - pcmcia_get_card_services_info(&serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "ds: Card Services release does not match!\n"); - return -1; - } - if (serv.Count == 0) { - printk(KERN_NOTICE "ds: no socket drivers loaded!\n"); - return -1; - } - - sockets = serv.Count; - socket_table = kmalloc(sockets*sizeof(socket_info_t), GFP_KERNEL); - if (!socket_table) return -1; - for (i = 0, s = socket_table; i < sockets; i++, s++) { - s->state = 0; - s->user = NULL; - s->req_pending = 0; init_waitqueue_head(&s->queue); init_waitqueue_head(&s->request); - s->handle = NULL; - init_timer(&s->removal); - s->removal.data = i; - s->removal.function = &handle_removal; - s->bind = NULL; - } - - /* Set up hotline to Card Services */ - client_reg.dev_info = bind.dev_info = &dev_info; - client_reg.Attributes = INFO_MASTER_CLIENT; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_EJECTION_REQUEST | CS_EVENT_INSERTION_REQUEST | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &ds_event; - client_reg.Version = 0x0210; - for (i = 0; i < sockets; i++) { - bind.Socket = i; + + /* find the lowest, unused socket no. Please note that this is a + * temporary workaround until "struct pcmcia_socket" is introduced + * into cs.c which will include this number, and which will be + * accessible to ds.c directly */ + i = 0; + next_try: + list_for_each_entry(tmp_s, &bus_socket_list, socket_list) { + if (tmp_s->socket_no == i) { + i++; + goto next_try; + } + } + s->socket_no = i; + + /* initialize data */ + s->socket_dev = dev; + INIT_WORK(&s->removal, handle_removal, s); + + /* Set up hotline to Card Services */ + client_reg.dev_info = bind.dev_info = &dev_info; + + bind.Socket = s->socket_no; bind.Function = BIND_FN_ALL; ret = pcmcia_bind_device(&bind); if (ret != CS_SUCCESS) { - cs_error(NULL, BindDevice, ret); - break; + cs_error(NULL, BindDevice, ret); + kfree(s); + return -EINVAL; } - client_reg.event_callback_args.client_data = &socket_table[i]; - ret = pcmcia_register_client(&socket_table[i].handle, - &client_reg); + + client_reg.Attributes = INFO_MASTER_CLIENT; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_EJECTION_REQUEST | CS_EVENT_INSERTION_REQUEST | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &ds_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = s; + ret = pcmcia_register_client(&s->handle, &client_reg); if (ret != CS_SUCCESS) { - cs_error(NULL, RegisterClient, ret); - break; + cs_error(NULL, RegisterClient, ret); + kfree(s); + return -EINVAL; } - } - - /* Set up character device for user mode clients */ - i = register_chrdev(0, "pcmcia", &ds_fops); - if (i == -EBUSY) - printk(KERN_NOTICE "unable to find a free device # for " - "Driver Services\n"); - else - major_dev = i; -#ifdef CONFIG_PROC_FS - if (proc_pccard) - create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL); - init_status = 0; -#endif - return 0; + list_add(&s->socket_list, &bus_socket_list); + + return 0; } -static void __exit exit_pcmcia_ds(void) +static int __devinit pcmcia_bus_add_socket_dev(struct device *dev) +{ + struct pcmcia_socket_class_data *cls_d = dev->class_data; + unsigned int i; + unsigned int ret = 0; + + if (!cls_d) + return -ENODEV; + + down_write(&bus_socket_list_rwsem); + for (i = 0; i < cls_d->nsock; i++) + ret += pcmcia_bus_add_socket(dev, i); + up_write(&bus_socket_list_rwsem); + + return ret; +} + +static int __devexit pcmcia_bus_remove_socket_dev(struct device *dev) +{ + struct pcmcia_socket_class_data *cls_d = dev->class_data; + struct list_head *list_loop; + struct list_head *tmp_storage; + + if (!cls_d) + return -ENODEV; + + flush_scheduled_work(); + + down_write(&bus_socket_list_rwsem); + list_for_each_safe(list_loop, tmp_storage, &bus_socket_list) { + struct pcmcia_bus_socket *bus_sock = container_of(list_loop, struct pcmcia_bus_socket, socket_list); + if (bus_sock->socket_dev == dev) { + pcmcia_deregister_client(bus_sock->handle); + list_del(&bus_sock->socket_list); + kfree(bus_sock); + } + } + up_write(&bus_socket_list_rwsem); + return 0; +} + + +/* the pcmcia_bus_interface is used to handle pcmcia socket devices */ +static struct device_interface pcmcia_bus_interface = { + .name = "pcmcia-bus", + .devclass = &pcmcia_socket_class, + .add_device = &pcmcia_bus_add_socket_dev, + .remove_device = __devexit_p(&pcmcia_bus_remove_socket_dev), + .kset = { .subsys = &pcmcia_socket_class.subsys, }, + .devnum = 0, +}; + + +struct bus_type pcmcia_bus_type = { + .name = "pcmcia", +}; +EXPORT_SYMBOL(pcmcia_bus_type); + + +static int __init init_pcmcia_bus(void) { - int i; + int i; + + bus_register(&pcmcia_bus_type); + interface_register(&pcmcia_bus_interface); + + /* Set up character device for user mode clients */ + i = register_chrdev(0, "pcmcia", &ds_fops); + if (i == -EBUSY) + printk(KERN_NOTICE "unable to find a free device # for " + "Driver Services\n"); + else + major_dev = i; + #ifdef CONFIG_PROC_FS - if (proc_pccard) - remove_proc_entry("drivers", proc_pccard); + if (proc_pccard) + create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL); #endif - if (major_dev != -1) - unregister_chrdev(major_dev, "pcmcia"); - for (i = 0; i < sockets; i++) - pcmcia_deregister_client(socket_table[i].handle); - sockets = 0; - kfree(socket_table); - bus_unregister(&pcmcia_bus_type); + + return 0; } +fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that + * pcmcia_socket_class is already registered */ -#ifdef MODULE -/* init_pcmcia_bus must be done early, init_pcmcia_ds late. If we load this - * as a module, we can only specify one initcall, though... - */ -static int __init init_pcmcia_module(void) { - init_pcmcia_bus(); - return init_pcmcia_ds(); -} -module_init(init_pcmcia_module); - -#else /* !MODULE */ -subsys_initcall(init_pcmcia_bus); -late_initcall(init_pcmcia_ds); +static void __exit exit_pcmcia_bus(void) +{ + interface_unregister(&pcmcia_bus_interface); + +#ifdef CONFIG_PROC_FS + if (proc_pccard) + remove_proc_entry("drivers", proc_pccard); #endif + if (major_dev != -1) + unregister_chrdev(major_dev, "pcmcia"); + + bus_unregister(&pcmcia_bus_type); +} +module_exit(exit_pcmcia_bus); -module_exit(exit_pcmcia_ds); /* helpers for backwards-compatible functions */ + + +static struct pcmcia_bus_socket * get_socket_info_by_nr(unsigned int nr) +{ + struct pcmcia_bus_socket * s; + down_read(&bus_socket_list_rwsem); + list_for_each_entry(s, &bus_socket_list, socket_list) + if (s->socket_no == nr) { + up_read(&bus_socket_list_rwsem); + return s; + } + up_read(&bus_socket_list_rwsem); + return NULL; +} /* backwards-compatible accessing of driver --- by name! */ diff -Nru a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c --- a/drivers/pcmcia/hd64465_ss.c Wed Apr 2 22:24:06 2003 +++ b/drivers/pcmcia/hd64465_ss.c Wed Apr 2 22:24:06 2003 @@ -599,21 +599,6 @@ /*============================================================*/ -static int hs_get_io_map(unsigned int sock, struct pccard_io_map *io) -{ - hs_socket_t *sp = &hs_sockets[sock]; - int map = io->map; - - DPRINTK("hs_get_io_map(%d, %d)\n", sock, map); - if (map >= MAX_IO_WIN) - return -EINVAL; - - *io = sp->io_maps[map]; - return 0; -} - -/*============================================================*/ - static int hs_set_io_map(unsigned int sock, struct pccard_io_map *io) { hs_socket_t *sp = &hs_sockets[sock]; @@ -696,21 +681,6 @@ /*============================================================*/ -static int hs_get_mem_map(unsigned int sock, struct pccard_mem_map *mem) -{ - hs_socket_t *sp = &hs_sockets[sock]; - int map = mem->map; - - DPRINTK("hs_get_mem_map(%d, %d)\n", sock, map); - if (map >= MAX_WIN) - return -EINVAL; - - *mem = sp->mem_maps[map]; - return 0; -} - -/*============================================================*/ - static int hs_set_mem_map(unsigned int sock, struct pccard_mem_map *mem) { hs_socket_t *sp = &hs_sockets[sock]; @@ -894,9 +864,7 @@ .get_status = hs_get_status, .get_socket = hs_get_socket, .set_socket = hs_set_socket, - .get_io_map = hs_get_io_map, .set_io_map = hs_set_io_map, - .get_mem_map = hs_get_mem_map, .set_mem_map = hs_set_mem_map, .proc_setup = hs_proc_setup, }; @@ -1000,6 +968,8 @@ .name = "hd64465-pcmcia", .bus = &platform_bus_type, .devclass = &pcmcia_socket_class, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; static struct platform_device hd64465_device = { diff -Nru a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c --- a/drivers/pcmcia/i82092.c Wed Apr 2 22:24:08 2003 +++ b/drivers/pcmcia/i82092.c Wed Apr 2 22:24:08 2003 @@ -42,11 +42,23 @@ }; MODULE_DEVICE_TABLE(pci, i82092aa_pci_ids); +static int i82092aa_socket_suspend (struct pci_dev *dev, u32 state) +{ + return pcmcia_socket_dev_suspend(&dev->dev, state, 0); +} + +static int i82092aa_socket_resume (struct pci_dev *dev) +{ + return pcmcia_socket_dev_resume(&dev->dev, RESUME_RESTORE_STATE); +} + static struct pci_driver i82092aa_pci_drv = { .name = "i82092aa", .id_table = i82092aa_pci_ids, .probe = i82092aa_pci_probe, .remove = __devexit_p(i82092aa_pci_remove), + .suspend = i82092aa_socket_suspend, + .resume = i82092aa_socket_resume, .driver = { .devclass = &pcmcia_socket_class, }, @@ -63,9 +75,7 @@ .get_status = i82092aa_get_status, .get_socket = i82092aa_get_socket, .set_socket = i82092aa_set_socket, - .get_io_map = i82092aa_get_io_map, .set_io_map = i82092aa_set_io_map, - .get_mem_map = i82092aa_get_mem_map, .set_mem_map = i82092aa_set_mem_map, .proc_setup = i82092aa_proc_setup, }; @@ -304,11 +314,6 @@ return 0; } -static int to_ns(int cycles) -{ - return cycle_time*cycles; -} - /* Interrupt handler functionality */ @@ -688,34 +693,6 @@ return 0; } -static int i82092aa_get_io_map(unsigned int sock, struct pccard_io_map *io) -{ - unsigned char map, ioctl, addr; - - enter("i82092aa_get_io_map"); - map = io->map; - if (map > 1) { - leave("i82092aa_get_io_map with -EINVAL"); - return -EINVAL; - } - - /* FIXME: How does this fit in with the PCI resource (re)allocation */ - io->start = indirect_read16(sock, I365_IO(map)+I365_W_START); - io->stop = indirect_read16(sock, I365_IO(map)+I365_W_START); - - ioctl = indirect_read(sock,I365_IOCTL); /* IOCREG: I/O Control Register */ - addr = indirect_read(sock,I365_ADDRWIN); /* */ - - io->speed = to_ns(ioctl & I365_IOCTL_WAIT(map)) ? 1 : 0; /* check this out later */ - io->flags = 0; - - if (addr & I365_IOCTL_16BIT(map)) - io->flags |= MAP_AUTOSZ; - - leave("i82092aa_get_io_map"); - return 0; -} - static int i82092aa_set_io_map(unsigned sock, struct pccard_io_map *io) { unsigned char map, ioctl; @@ -757,64 +734,6 @@ leave("i82092aa_set_io_map"); return 0; -} - -static int i82092aa_get_mem_map(unsigned sock, struct pccard_mem_map *mem) -{ - unsigned short base, i; - unsigned char map, addr; - - enter("i82092aa_get_mem_map"); - - mem->flags = 0; - mem->speed = 0; - map = mem->map; - if (map > 4) { - leave("i82092aa_get_mem_map: -EINVAL"); - return -EINVAL; - } - - addr = indirect_read(sock, I365_ADDRWIN); - - if (addr & I365_ENA_MEM(map)) - mem->flags |= MAP_ACTIVE; /* yes this mapping is active */ - - base = I365_MEM(map); - - /* Find the start address - this register also has mapping info */ - - i = indirect_read16(sock,base+I365_W_START); - if (i & I365_MEM_16BIT) - mem->flags |= MAP_16BIT; - if (i & I365_MEM_0WS) - mem->flags |= MAP_0WS; - - mem->sys_start = ((unsigned long)(i & 0x0fff) << 12); - - /* Find the end address - this register also has speed info */ - i = indirect_read16(sock,base+I365_W_STOP); - if (i & I365_MEM_WS0) - mem->speed = 1; - if (i & I365_MEM_WS1) - mem->speed += 2; - mem->speed = to_ns(mem->speed); - mem->sys_stop = ( (unsigned long)(i & 0x0fff) << 12) + 0x0fff; - - /* Find the card start address, also some more MAP attributes */ - - i = indirect_read16(sock, base+I365_W_OFF); - if (i & I365_MEM_WRPROT) - mem->flags |= MAP_WRPROT; - if (i & I365_MEM_REG) - mem->flags |= MAP_ATTRIB; - mem->card_start = ( (unsigned long)(i & 0x3fff)<12) + mem->sys_start; - mem->card_start &= 0x3ffffff; - - printk("Card %i is from %lx to %lx \n",sock,mem->sys_start,mem->sys_stop); - - leave("i82092aa_get_mem_map"); - return 0; - } static int i82092aa_set_mem_map(unsigned sock, struct pccard_mem_map *mem) diff -Nru a/drivers/pcmcia/i82092aa.h b/drivers/pcmcia/i82092aa.h --- a/drivers/pcmcia/i82092aa.h Wed Apr 2 22:24:04 2003 +++ b/drivers/pcmcia/i82092aa.h Wed Apr 2 22:24:04 2003 @@ -29,9 +29,7 @@ static int i82092aa_get_status(unsigned int sock, u_int *value); static int i82092aa_get_socket(unsigned int sock, socket_state_t *state); static int i82092aa_set_socket(unsigned int sock, socket_state_t *state); -static int i82092aa_get_io_map(unsigned int sock, struct pccard_io_map *io); static int i82092aa_set_io_map(unsigned int sock, struct pccard_io_map *io); -static int i82092aa_get_mem_map(unsigned int sock, struct pccard_mem_map *mem); static int i82092aa_set_mem_map(unsigned int sock, struct pccard_mem_map *mem); static int i82092aa_init(unsigned int s); static int i82092aa_suspend(unsigned int sock); diff -Nru a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c --- a/drivers/pcmcia/i82365.c Wed Apr 2 22:24:07 2003 +++ b/drivers/pcmcia/i82365.c Wed Apr 2 22:24:07 2003 @@ -1250,29 +1250,6 @@ /*====================================================================*/ -static int i365_get_io_map(u_short sock, struct pccard_io_map *io) -{ - u_char map, ioctl, addr; - - map = io->map; - if (map > 1) return -EINVAL; - io->start = i365_get_pair(sock, I365_IO(map)+I365_W_START); - io->stop = i365_get_pair(sock, I365_IO(map)+I365_W_STOP); - ioctl = i365_get(sock, I365_IOCTL); - addr = i365_get(sock, I365_ADDRWIN); - io->speed = to_ns(ioctl & I365_IOCTL_WAIT(map)) ? 1 : 0; - io->flags = (addr & I365_ENA_IO(map)) ? MAP_ACTIVE : 0; - io->flags |= (ioctl & I365_IOCTL_0WS(map)) ? MAP_0WS : 0; - io->flags |= (ioctl & I365_IOCTL_16BIT(map)) ? MAP_16BIT : 0; - io->flags |= (ioctl & I365_IOCTL_IOCS16(map)) ? MAP_AUTOSZ : 0; - DEBUG(1, "i82365: GetIOMap(%d, %d) = %#2.2x, %d ns, " - "%#4.4x-%#4.4x\n", sock, map, io->flags, io->speed, - io->start, io->stop); - return 0; -} /* i365_get_io_map */ - -/*====================================================================*/ - static int i365_set_io_map(u_short sock, struct pccard_io_map *io) { u_char map, ioctl; @@ -1302,42 +1279,6 @@ /*====================================================================*/ -static int i365_get_mem_map(u_short sock, struct pccard_mem_map *mem) -{ - u_short base, i; - u_char map, addr; - - map = mem->map; - if (map > 4) return -EINVAL; - addr = i365_get(sock, I365_ADDRWIN); - mem->flags = (addr & I365_ENA_MEM(map)) ? MAP_ACTIVE : 0; - base = I365_MEM(map); - - i = i365_get_pair(sock, base+I365_W_START); - mem->flags |= (i & I365_MEM_16BIT) ? MAP_16BIT : 0; - mem->flags |= (i & I365_MEM_0WS) ? MAP_0WS : 0; - mem->sys_start = ((u_long)(i & 0x0fff) << 12); - - i = i365_get_pair(sock, base+I365_W_STOP); - mem->speed = (i & I365_MEM_WS0) ? 1 : 0; - mem->speed += (i & I365_MEM_WS1) ? 2 : 0; - mem->speed = to_ns(mem->speed); - mem->sys_stop = ((u_long)(i & 0x0fff) << 12) + 0x0fff; - - i = i365_get_pair(sock, base+I365_W_OFF); - mem->flags |= (i & I365_MEM_WRPROT) ? MAP_WRPROT : 0; - mem->flags |= (i & I365_MEM_REG) ? MAP_ATTRIB : 0; - mem->card_start = ((u_int)(i & 0x3fff) << 12) + mem->sys_start; - mem->card_start &= 0x3ffffff; - - DEBUG(1, "i82365: GetMemMap(%d, %d) = %#2.2x, %d ns, %#5.5lx-%#5." - "5lx, %#5.5x\n", sock, mem->map, mem->flags, mem->speed, - mem->sys_start, mem->sys_stop, mem->card_start); - return 0; -} /* i365_get_mem_map */ - -/*====================================================================*/ - static int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem) { u_short base, i; @@ -1506,14 +1447,6 @@ LOCKED(i365_set_socket(sock, state)); } -static int pcic_get_io_map(unsigned int sock, struct pccard_io_map *io) -{ - if (socket[sock].flags & IS_ALIVE) - return -EINVAL; - - LOCKED(i365_get_io_map(sock, io)); -} - static int pcic_set_io_map(unsigned int sock, struct pccard_io_map *io) { if (socket[sock].flags & IS_ALIVE) @@ -1522,14 +1455,6 @@ LOCKED(i365_set_io_map(sock, io)); } -static int pcic_get_mem_map(unsigned int sock, struct pccard_mem_map *mem) -{ - if (socket[sock].flags & IS_ALIVE) - return -EINVAL; - - LOCKED(i365_get_mem_map(sock, mem)); -} - static int pcic_set_mem_map(unsigned int sock, struct pccard_mem_map *mem) { if (socket[sock].flags & IS_ALIVE) @@ -1571,9 +1496,7 @@ .get_status = pcic_get_status, .get_socket = pcic_get_socket, .set_socket = pcic_set_socket, - .get_io_map = pcic_get_io_map, .set_io_map = pcic_set_io_map, - .get_mem_map = pcic_get_mem_map, .set_mem_map = pcic_set_mem_map, .proc_setup = pcic_proc_setup, }; @@ -1588,6 +1511,8 @@ .name = "i82365", .bus = &platform_bus_type, .devclass = &pcmcia_socket_class, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; static struct platform_device i82365_device = { diff -Nru a/drivers/pcmcia/pci_socket.c b/drivers/pcmcia/pci_socket.c --- a/drivers/pcmcia/pci_socket.c Wed Apr 2 22:24:07 2003 +++ b/drivers/pcmcia/pci_socket.c Wed Apr 2 22:24:07 2003 @@ -31,10 +31,6 @@ #include "pci_socket.h" -extern void pcmcia_suspend_socket (struct socket_info_t *socket); -extern void pcmcia_resume_socket (struct socket_info_t *socket); - - /* * Arbitrary define. This is the array of active cardbus * entries. @@ -105,15 +101,6 @@ return -EINVAL; } -static int pci_get_io_map(unsigned int sock, struct pccard_io_map *io) -{ - pci_socket_t *socket = pci_socket_array + sock; - - if (socket->op && socket->op->get_io_map) - return socket->op->get_io_map(socket, io); - return -EINVAL; -} - static int pci_set_io_map(unsigned int sock, struct pccard_io_map *io) { pci_socket_t *socket = pci_socket_array + sock; @@ -123,15 +110,6 @@ return -EINVAL; } -static int pci_get_mem_map(unsigned int sock, struct pccard_mem_map *mem) -{ - pci_socket_t *socket = pci_socket_array + sock; - - if (socket->op && socket->op->get_mem_map) - return socket->op->get_mem_map(socket, mem); - return -EINVAL; -} - static int pci_set_mem_map(unsigned int sock, struct pccard_mem_map *mem) { pci_socket_t *socket = pci_socket_array + sock; @@ -158,9 +136,7 @@ .get_status = pci_get_status, .get_socket = pci_get_socket, .set_socket = pci_set_socket, - .get_io_map = pci_get_io_map, .set_io_map = pci_set_io_map, - .get_mem_map = pci_get_mem_map, .set_mem_map = pci_set_mem_map, .proc_setup = pci_proc_setup, }; @@ -177,7 +153,6 @@ socket->cls_d.nsock = 1; /* yenta is 1, no other low-level driver uses this yet */ socket->cls_d.ops = &pci_socket_operations; - socket->cls_d.use_bus_pm = 1; dev->dev.class_data = &socket->cls_d; /* prepare pci_socket_t */ @@ -224,18 +199,12 @@ static int cardbus_suspend (struct pci_dev *dev, u32 state) { - pci_socket_t *socket = pci_get_drvdata(dev); - if (socket && socket->cls_d.s_info) - pcmcia_suspend_socket (socket->cls_d.s_info); - return 0; + return pcmcia_socket_dev_suspend(&dev->dev, state, 0); } static int cardbus_resume (struct pci_dev *dev) { - pci_socket_t *socket = pci_get_drvdata(dev); - if (socket && socket->cls_d.s_info) - pcmcia_resume_socket (socket->cls_d.s_info); - return 0; + return pcmcia_socket_dev_resume(&dev->dev, RESUME_RESTORE_STATE); } diff -Nru a/drivers/pcmcia/pci_socket.h b/drivers/pcmcia/pci_socket.h --- a/drivers/pcmcia/pci_socket.h Wed Apr 2 22:24:04 2003 +++ b/drivers/pcmcia/pci_socket.h Wed Apr 2 22:24:04 2003 @@ -37,9 +37,7 @@ int (*get_status)(struct pci_socket *, unsigned int *); int (*get_socket)(struct pci_socket *, socket_state_t *); int (*set_socket)(struct pci_socket *, socket_state_t *); - int (*get_io_map)(struct pci_socket *, struct pccard_io_map *); int (*set_io_map)(struct pci_socket *, struct pccard_io_map *); - int (*get_mem_map)(struct pci_socket *, struct pccard_mem_map *); int (*set_mem_map)(struct pci_socket *, struct pccard_mem_map *); void (*proc_setup)(struct pci_socket *, struct proc_dir_entry *base); }; diff -Nru a/drivers/pcmcia/ricoh.h b/drivers/pcmcia/ricoh.h --- a/drivers/pcmcia/ricoh.h Wed Apr 2 22:24:05 2003 +++ b/drivers/pcmcia/ricoh.h Wed Apr 2 22:24:05 2003 @@ -170,9 +170,7 @@ yenta_get_status, yenta_get_socket, yenta_set_socket, - yenta_get_io_map, yenta_set_io_map, - yenta_get_mem_map, yenta_set_mem_map, yenta_proc_setup }; diff -Nru a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c --- a/drivers/pcmcia/rsrc_mgr.c Wed Apr 2 22:24:06 2003 +++ b/drivers/pcmcia/rsrc_mgr.c Wed Apr 2 22:24:06 2003 @@ -60,7 +60,7 @@ #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") INT_MODULE_PARM(probe_mem, 1); /* memory probe? */ -#ifdef CONFIG_ISA +#ifdef CONFIG_PCMCIA_PROBE INT_MODULE_PARM(probe_io, 1); /* IO port probe? */ INT_MODULE_PARM(mem_limit, 0x10000); #endif @@ -83,7 +83,9 @@ /* IO port resource database */ static resource_map_t io_db = { 0, 0, &io_db }; -#ifdef CONFIG_ISA +static DECLARE_MUTEX(rsrc_sem); + +#ifdef CONFIG_PCMCIA_PROBE typedef struct irq_info_t { u_int Attributes; @@ -269,7 +271,7 @@ ======================================================================*/ -#ifdef CONFIG_ISA +#ifdef CONFIG_PCMCIA_PROBE static void do_io_probe(ioaddr_t base, ioaddr_t num) { @@ -333,15 +335,69 @@ /*====================================================================== + This is tricky... when we set up CIS memory, we try to validate + the memory window space allocations. + +======================================================================*/ + +/* Validation function for cards with a valid CIS */ +static int cis_readable(socket_info_t *s, u_long base) +{ + cisinfo_t info1, info2; + int ret; + s->cis_mem.sys_start = base; + s->cis_mem.sys_stop = base+s->cap.map_size-1; + s->cis_virt = ioremap(base, s->cap.map_size); + ret = pcmcia_validate_cis(s->clients, &info1); + /* invalidate mapping and CIS cache */ + iounmap(s->cis_virt); + s->cis_used = 0; + if ((ret != 0) || (info1.Chains == 0)) + return 0; + s->cis_mem.sys_start = base+s->cap.map_size; + s->cis_mem.sys_stop = base+2*s->cap.map_size-1; + s->cis_virt = ioremap(base+s->cap.map_size, s->cap.map_size); + ret = pcmcia_validate_cis(s->clients, &info2); + iounmap(s->cis_virt); + s->cis_used = 0; + return ((ret == 0) && (info1.Chains == info2.Chains)); +} + +/* Validation function for simple memory cards */ +static int checksum(socket_info_t *s, u_long base) +{ + int i, a, b, d; + s->cis_mem.sys_start = base; + s->cis_mem.sys_stop = base+s->cap.map_size-1; + s->cis_virt = ioremap(base, s->cap.map_size); + s->cis_mem.card_start = 0; + s->cis_mem.flags = MAP_ACTIVE; + s->ss_entry->set_mem_map(s->sock, &s->cis_mem); + /* Don't bother checking every word... */ + a = 0; b = -1; + for (i = 0; i < s->cap.map_size; i += 44) { + d = readl(s->cis_virt+i); + a += d; b &= d; + } + iounmap(s->cis_virt); + return (b == -1) ? -1 : (a>>1); +} + +static int checksum_match(socket_info_t *s, u_long base) +{ + int a = checksum(s, base), b = checksum(s, base+s->cap.map_size); + return ((a == b) && (a >= 0)); +} + +/*====================================================================== + The memory probe. If the memory list includes a 64K-aligned block below 1MB, we probe in 64K chunks, and as soon as we accumulate at least mem_limit free space, we quit. ======================================================================*/ -static int do_mem_probe(u_long base, u_long num, - int (*is_valid)(u_long), int (*do_cksum)(u_long), - socket_info_t *s) +static int do_mem_probe(u_long base, u_long num, socket_info_t *s) { u_long i, j, bad, fail, step; @@ -349,18 +405,21 @@ base, base+num-1); bad = fail = 0; step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff); + /* cis_readable wants to map 2x map_size */ + if (step < 2 * s->cap.map_size) + step = 2 * s->cap.map_size; for (i = j = base; i < base+num; i = j + step) { if (!fail) { for (j = i; j < base+num; j += step) if ((check_mem_resource(j, step, s->cap.cb_dev) == 0) && - is_valid(j)) + cis_readable(s, j)) break; fail = ((i == base) && (j == base+num)); } if (fail) { for (j = i; j < base+num; j += 2*step) if ((check_mem_resource(j, 2*step, s->cap.cb_dev) == 0) && - do_cksum(j) && do_cksum(j+step)) + checksum_match(s, j) && checksum_match(s, j + step)) break; } if (i != j) { @@ -374,16 +433,14 @@ return (num - bad); } -#ifdef CONFIG_ISA +#ifdef CONFIG_PCMCIA_PROBE -static u_long inv_probe(int (*is_valid)(u_long), - int (*do_cksum)(u_long), - resource_map_t *m, socket_info_t *s) +static u_long inv_probe(resource_map_t *m, socket_info_t *s) { u_long ok; if (m == &mem_db) return 0; - ok = inv_probe(is_valid, do_cksum, m->next, s); + ok = inv_probe(m->next, s); if (ok) { if (m->base >= 0x100000) sub_interval(&mem_db, m->base, m->num); @@ -391,32 +448,36 @@ } if (m->base < 0x100000) return 0; - return do_mem_probe(m->base, m->num, is_valid, do_cksum, s); + return do_mem_probe(m->base, m->num, s); } -void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long), - int force_low, socket_info_t *s) +void validate_mem(socket_info_t *s) { resource_map_t *m, *n; static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 }; static int hi = 0, lo = 0; u_long b, i, ok = 0; - - if (!probe_mem) return; + int force_low = !(s->cap.features & SS_CAP_PAGE_REGS); + + if (!probe_mem) + return; + + down(&rsrc_sem); /* We do up to four passes through the list */ if (!force_low) { - if (hi++ || (inv_probe(is_valid, do_cksum, mem_db.next, s) > 0)) - return; + if (hi++ || (inv_probe(mem_db.next, s) > 0)) + goto out; printk(KERN_NOTICE "cs: warning: no high memory space " "available!\n"); } - if (lo++) return; + if (lo++) + goto out; for (m = mem_db.next; m != &mem_db; m = n) { n = m->next; /* Only probe < 1 MB */ if (m->base >= 0x100000) continue; if ((m->base | m->num) & 0xffff) { - ok += do_mem_probe(m->base, m->num, is_valid, do_cksum, s); + ok += do_mem_probe(m->base, m->num, s); continue; } /* Special probe for 64K-aligned block */ @@ -426,28 +487,31 @@ if (ok >= mem_limit) sub_interval(&mem_db, b, 0x10000); else - ok += do_mem_probe(b, 0x10000, is_valid, do_cksum, s); + ok += do_mem_probe(b, 0x10000, s); } } } + out: + up(&rsrc_sem); } -#else /* CONFIG_ISA */ +#else /* CONFIG_PCMCIA_PROBE */ -void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long), - int force_low, socket_info_t *s) +void validate_mem(socket_info_t *s) { resource_map_t *m; static int done = 0; - if (!probe_mem || done++) - return; - for (m = mem_db.next; m != &mem_db; m = m->next) - if (do_mem_probe(m->base, m->num, is_valid, do_cksum, s)) - return; + if (probe_mem && done++ == 0) { + down(&rsrc_sem); + for (m = mem_db.next; m != &mem_db; m = m->next) + if (do_mem_probe(m->base, m->num, s)) + break; + up(&rsrc_sem); + } } -#endif /* CONFIG_ISA */ +#endif /* CONFIG_PCMCIA_PROBE */ /*====================================================================== @@ -467,7 +531,9 @@ { ioaddr_t try; resource_map_t *m; - + int ret = -1; + + down(&rsrc_sem); for (m = io_db.next; m != &io_db; m = m->next) { try = (m->base & ~(align-1)) + *base; for (try = (try >= m->base) ? try : try+align; @@ -475,12 +541,16 @@ try += align) { if (request_io_resource(try, num, name, s->cap.cb_dev) == 0) { *base = try; - return 0; + ret = 0; + goto out; } - if (!align) break; + if (!align) + break; } } - return -1; + out: + up(&rsrc_sem); + return ret; } int find_mem_region(u_long *base, u_long num, u_long align, @@ -488,26 +558,35 @@ { u_long try; resource_map_t *m; + int ret = -1; + down(&rsrc_sem); while (1) { for (m = mem_db.next; m != &mem_db; m = m->next) { /* first pass >1MB, second pass <1MB */ - if ((force_low != 0) ^ (m->base < 0x100000)) continue; + if ((force_low != 0) ^ (m->base < 0x100000)) + continue; + try = (m->base & ~(align-1)) + *base; for (try = (try >= m->base) ? try : try+align; (try >= m->base) && (try+num <= m->base+m->num); try += align) { if (request_mem_resource(try, num, name, s->cap.cb_dev) == 0) { *base = try; - return 0; + ret = 0; + goto out; } - if (!align) break; + if (!align) + break; } } - if (force_low) break; + if (force_low) + break; force_low++; } - return -1; + out: + up(&rsrc_sem); + return ret; } /*====================================================================== @@ -518,7 +597,7 @@ ======================================================================*/ -#ifdef CONFIG_ISA +#ifdef CONFIG_PCMCIA_PROBE static void fake_irq(int i, void *d, struct pt_regs *r) { } static inline int check_irq(int irq) @@ -532,66 +611,89 @@ int try_irq(u_int Attributes, int irq, int specific) { irq_info_t *info = &irq_table[irq]; + int ret = 0; + + down(&rsrc_sem); if (info->Attributes & RES_ALLOCATED) { switch (Attributes & IRQ_TYPE) { case IRQ_TYPE_EXCLUSIVE: - return CS_IN_USE; + ret = CS_IN_USE; + break; case IRQ_TYPE_TIME: if ((info->Attributes & RES_IRQ_TYPE) - != RES_IRQ_TYPE_TIME) - return CS_IN_USE; - if (Attributes & IRQ_FIRST_SHARED) - return CS_BAD_ATTRIBUTE; + != RES_IRQ_TYPE_TIME) { + ret = CS_IN_USE; + break; + } + if (Attributes & IRQ_FIRST_SHARED) { + ret = CS_BAD_ATTRIBUTE; + break; + } info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED; info->time_share++; break; case IRQ_TYPE_DYNAMIC_SHARING: if ((info->Attributes & RES_IRQ_TYPE) - != RES_IRQ_TYPE_DYNAMIC) - return CS_IN_USE; - if (Attributes & IRQ_FIRST_SHARED) - return CS_BAD_ATTRIBUTE; + != RES_IRQ_TYPE_DYNAMIC) { + ret = CS_IN_USE; + break; + } + if (Attributes & IRQ_FIRST_SHARED) { + ret = CS_BAD_ATTRIBUTE; + break; + } info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED; info->dyn_share++; break; } } else { - if ((info->Attributes & RES_RESERVED) && !specific) - return CS_IN_USE; - if (check_irq(irq) != 0) - return CS_IN_USE; + if ((info->Attributes & RES_RESERVED) && !specific) { + ret = CS_IN_USE; + goto out; + } + if (check_irq(irq) != 0) { + ret = CS_IN_USE; + goto out; + } switch (Attributes & IRQ_TYPE) { case IRQ_TYPE_EXCLUSIVE: info->Attributes |= RES_ALLOCATED; break; case IRQ_TYPE_TIME: - if (!(Attributes & IRQ_FIRST_SHARED)) - return CS_BAD_ATTRIBUTE; + if (!(Attributes & IRQ_FIRST_SHARED)) { + ret = CS_BAD_ATTRIBUTE; + break; + } info->Attributes |= RES_IRQ_TYPE_TIME | RES_ALLOCATED; info->time_share = 1; break; case IRQ_TYPE_DYNAMIC_SHARING: - if (!(Attributes & IRQ_FIRST_SHARED)) - return CS_BAD_ATTRIBUTE; + if (!(Attributes & IRQ_FIRST_SHARED)) { + ret = CS_BAD_ATTRIBUTE; + break; + } info->Attributes |= RES_IRQ_TYPE_DYNAMIC | RES_ALLOCATED; info->dyn_share = 1; break; } } - return 0; + out: + up(&rsrc_sem); + return ret; } #endif /*====================================================================*/ -#ifdef CONFIG_ISA +#ifdef CONFIG_PCMCIA_PROBE void undo_irq(u_int Attributes, int irq) { irq_info_t *info; info = &irq_table[irq]; + down(&rsrc_sem); switch (Attributes & IRQ_TYPE) { case IRQ_TYPE_EXCLUSIVE: info->Attributes &= RES_RESERVED; @@ -607,6 +709,7 @@ info->Attributes &= RES_RESERVED; break; } + up(&rsrc_sem); } #endif @@ -629,6 +732,8 @@ return CS_BAD_SIZE; ret = CS_SUCCESS; + + down(&rsrc_sem); switch (adj->Action) { case ADD_MANAGED_RESOURCE: ret = add_interval(&mem_db, base, num); @@ -647,6 +752,7 @@ default: ret = CS_UNSUPPORTED_FUNCTION; } + up(&rsrc_sem); return ret; } @@ -655,7 +761,7 @@ static int adjust_io(adjust_t *adj) { - int base, num; + int base, num, ret = CS_SUCCESS; base = adj->resource.io.BasePort; num = adj->resource.io.NumPorts; @@ -664,11 +770,14 @@ if ((num <= 0) || (base+num > 0x10000) || (base+num <= base)) return CS_BAD_SIZE; + down(&rsrc_sem); switch (adj->Action) { case ADD_MANAGED_RESOURCE: - if (add_interval(&io_db, base, num) != 0) - return CS_IN_USE; -#ifdef CONFIG_ISA + if (add_interval(&io_db, base, num) != 0) { + ret = CS_IN_USE; + break; + } +#ifdef CONFIG_PCMCIA_PROBE if (probe_io) do_io_probe(base, num); #endif @@ -677,18 +786,20 @@ sub_interval(&io_db, base, num); break; default: - return CS_UNSUPPORTED_FUNCTION; + ret = CS_UNSUPPORTED_FUNCTION; break; } + up(&rsrc_sem); - return CS_SUCCESS; + return ret; } /*====================================================================*/ static int adjust_irq(adjust_t *adj) { -#ifdef CONFIG_ISA + int ret = CS_SUCCESS; +#ifdef CONFIG_PCMCIA_PROBE int irq; irq_info_t *info; @@ -696,33 +807,41 @@ if ((irq < 0) || (irq > 15)) return CS_BAD_IRQ; info = &irq_table[irq]; - + + down(&rsrc_sem); switch (adj->Action) { case ADD_MANAGED_RESOURCE: if (info->Attributes & RES_REMOVED) info->Attributes &= ~(RES_REMOVED|RES_ALLOCATED); else - if (adj->Attributes & RES_ALLOCATED) - return CS_IN_USE; + if (adj->Attributes & RES_ALLOCATED) { + ret = CS_IN_USE; + break; + } if (adj->Attributes & RES_RESERVED) info->Attributes |= RES_RESERVED; else info->Attributes &= ~RES_RESERVED; break; case REMOVE_MANAGED_RESOURCE: - if (info->Attributes & RES_REMOVED) - return 0; - if (info->Attributes & RES_ALLOCATED) - return CS_IN_USE; + if (info->Attributes & RES_REMOVED) { + ret = 0; + break; + } + if (info->Attributes & RES_ALLOCATED) { + ret = CS_IN_USE; + break; + } info->Attributes |= RES_ALLOCATED|RES_REMOVED; info->Attributes &= ~RES_RESERVED; break; default: - return CS_UNSUPPORTED_FUNCTION; + ret = CS_UNSUPPORTED_FUNCTION; break; } + up(&rsrc_sem); #endif - return CS_SUCCESS; + return ret; } /*====================================================================*/ diff -Nru a/drivers/pcmcia/sa1100.h b/drivers/pcmcia/sa1100.h --- a/drivers/pcmcia/sa1100.h Wed Apr 2 22:24:06 2003 +++ b/drivers/pcmcia/sa1100.h Wed Apr 2 22:24:06 2003 @@ -152,36 +152,6 @@ struct pcmcia_low_level; -/* This structure encapsulates per-socket state which we might need to - * use when responding to a Card Services query of some kind. - */ -struct sa1100_pcmcia_socket { - /* - * Core PCMCIA state - */ - int nr; - struct resource res; - socket_state_t cs_state; - pccard_io_map io_map[MAX_IO_WIN]; - pccard_mem_map pc_mem_map[MAX_WIN]; - void (*handler)(void *, unsigned int); - void *handler_info; - - struct pcmcia_state k_state; - ioaddr_t phys_attr, phys_mem; - void *virt_io; - unsigned short speed_io, speed_attr, speed_mem; - - /* - * Info from low level handler - */ - unsigned int irq; - unsigned int irq_state; - - struct pcmcia_low_level *ops; -}; - - /* I/O pins replacing memory pins * (PCMCIA System Architecture, 2nd ed., by Don Anderson, p.75) * @@ -190,60 +160,5 @@ */ #define iostschg bvd1 #define iospkr bvd2 - - -/* - * Declaration for all machine specific init/exit functions. - */ -extern int pcmcia_adsbitsy_init(struct device *); -extern void pcmcia_adsbitsy_exit(struct device *); - -extern int pcmcia_assabet_init(struct device *); -extern void pcmcia_assabet_exit(struct device *); - -extern int pcmcia_badge4_init(struct device *); -extern void pcmcia_badge4_exit(struct device *); - -extern int pcmcia_cerf_init(struct device *); -extern void pcmcia_cerf_exit(struct device *); - -extern int pcmcia_flexanet_init(struct device *); -extern void pcmcia_flexanet_exit(struct device *); - -extern int pcmcia_freebird_init(struct device *); -extern void pcmcia_freebird_exit(struct device *); - -extern int pcmcia_gcplus_init(struct device *); -extern void pcmcia_gcplus_exit(struct device *); - -extern int pcmcia_graphicsmaster_init(struct device *); -extern void pcmcia_graphicsmaster_exit(struct device *); - -extern int pcmcia_pangolin_init(struct device *); -extern void pcmcia_pangolin_exit(struct device *); - -extern int pcmcia_pfs168_init(struct device *); -extern void pcmcia_pfs168_exit(struct device *); - -extern int pcmcia_shannon_init(struct device *); -extern void pcmcia_shannon_exit(struct device *); - -extern int pcmcia_simpad_init(struct device *); -extern void pcmcia_simpad_exit(struct device *); - -extern int pcmcia_stork_init(struct device *); -extern void pcmcia_stork_exit(struct device *); - -extern int pcmcia_system3_init(struct device *); -extern void pcmcia_system3_exit(struct device *); - -extern int pcmcia_trizeps_init(struct device *); -extern void pcmcia_trizeps_exit(struct device *); - -extern int pcmcia_xp860_init(struct device *); -extern void pcmcia_xp860_exit(struct device *); - -extern int pcmcia_yopy_init(struct device *); -extern void pcmcia_yopy_exit(struct device *); #endif /* !defined(_PCMCIA_SA1100_H) */ diff -Nru a/drivers/pcmcia/sa1100_adsbitsy.c b/drivers/pcmcia/sa1100_adsbitsy.c --- a/drivers/pcmcia/sa1100_adsbitsy.c Wed Apr 2 22:24:08 2003 +++ b/drivers/pcmcia/sa1100_adsbitsy.c Wed Apr 2 22:24:08 2003 @@ -18,93 +18,86 @@ #include #include -#include "sa1100_generic.h" #include "sa1111_generic.h" -static int adsbitsy_pcmcia_init(struct pcmcia_init *init) +static int adsbitsy_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) { - /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */ - PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); + /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */ + PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); - /* Disable Power 3.3V/5V for PCMCIA/CF */ - PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3; + /* Disable Power 3.3V/5V for PCMCIA/CF */ + PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3; - /* Why? */ - MECR = 0x09430943; + /* Why? */ + MECR = 0x09430943; - return sa1111_pcmcia_init(init); + return sa1111_pcmcia_init(skt); } static int -adsbitsy_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) +adsbitsy_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, const socket_state_t *state) { - unsigned int pa_dwr_mask, pa_dwr_set; - int ret; + unsigned int pa_dwr_mask, pa_dwr_set; + int ret; - switch (sock) { - case 0: - pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1; - - switch (conf->vcc) { - default: - case 0: pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1; break; - case 33: pa_dwr_set = GPIO_GPIO1; break; - case 50: pa_dwr_set = GPIO_GPIO0; break; - } - break; - - case 1: - pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3; - - switch (conf->vcc) { - default: - case 0: pa_dwr_set = 0; break; - case 33: pa_dwr_set = GPIO_GPIO2; break; - case 50: pa_dwr_set = GPIO_GPIO3; break; - } - - default: - return -1; - } - - if (conf->vpp != conf->vcc && conf->vpp != 0) { - printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n", - __FUNCTION__, conf->vpp); - return -1; - } - - ret = sa1111_pcmcia_configure_socket(sock, conf); - if (ret == 0) { - unsigned long flags; - - local_irq_save(flags); - PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set; - local_irq_restore(flags); - } + switch (skt->nr) { + case 0: + pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1; + + switch (state->Vcc) { + default: + case 0: pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1; break; + case 33: pa_dwr_set = GPIO_GPIO1; break; + case 50: pa_dwr_set = GPIO_GPIO0; break; + } + break; + + case 1: + pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3; + + switch (state->Vcc) { + default: + case 0: pa_dwr_set = 0; break; + case 33: pa_dwr_set = GPIO_GPIO2; break; + case 50: pa_dwr_set = GPIO_GPIO3; break; + } + + default: + return -1; + } + + if (state->Vpp != state->Vcc && state->Vpp != 0) { + printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n", + __FUNCTION__, state->Vpp); + return -1; + } + + ret = sa1111_pcmcia_configure_socket(skt, state); + if (ret == 0) { + unsigned long flags; + + local_irq_save(flags); + PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set; + local_irq_restore(flags); + } - return ret; + return ret; } static struct pcmcia_low_level adsbitsy_pcmcia_ops = { - .owner = THIS_MODULE, - .init = adsbitsy_pcmcia_init, - .shutdown = sa1111_pcmcia_shutdown, - .socket_state = sa1111_pcmcia_socket_state, - .configure_socket = adsbitsy_pcmcia_configure_socket, - - .socket_init = sa1111_pcmcia_socket_init, - .socket_suspend = sa1111_pcmcia_socket_suspend, + .owner = THIS_MODULE, + .hw_init = adsbitsy_pcmcia_hw_init, + .hw_shutdown = sa1111_pcmcia_hw_shutdown, + .socket_state = sa1111_pcmcia_socket_state, + .configure_socket = adsbitsy_pcmcia_configure_socket, + .socket_init = sa1111_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, }; int __init pcmcia_adsbitsy_init(struct device *dev) { int ret = -ENODEV; if (machine_is_adsbitsy()) - ret = sa1100_register_pcmcia(&adsbitsy_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &adsbitsy_pcmcia_ops, 0, 2); return ret; -} - -void __exit pcmcia_adsbitsy_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&adsbitsy_pcmcia_ops, dev); } diff -Nru a/drivers/pcmcia/sa1100_assabet.c b/drivers/pcmcia/sa1100_assabet.c --- a/drivers/pcmcia/sa1100_assabet.c Wed Apr 2 22:24:07 2003 +++ b/drivers/pcmcia/sa1100_assabet.c Wed Apr 2 22:24:07 2003 @@ -20,85 +20,47 @@ #include "sa1100_generic.h" -static struct irqs { - int irq; - const char *str; -} irqs[] = { - { ASSABET_IRQ_GPIO_CF_CD, "CF_CD" }, - { ASSABET_IRQ_GPIO_CF_BVD2, "CF_BVD2" }, - { ASSABET_IRQ_GPIO_CF_BVD1, "CF_BVD1" }, +static struct pcmcia_irqs irqs[] = { + { 1, ASSABET_IRQ_GPIO_CF_CD, "CF CD" }, + { 1, ASSABET_IRQ_GPIO_CF_BVD2, "CF BVD2" }, + { 1, ASSABET_IRQ_GPIO_CF_BVD1, "CF BVD1" }, }; -static int assabet_pcmcia_init(struct pcmcia_init *init) +static int assabet_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) { - int i, res; + skt->irq = ASSABET_IRQ_GPIO_CF_IRQ; - /* Register interrupts */ - for (i = 0; i < ARRAY_SIZE(irqs); i++) { - res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt, - SA_INTERRUPT, irqs[i].str, NULL); - if (res) - goto irq_err; - set_irq_type(irqs[i].irq, IRQT_NOEDGE); - } - - init->socket_irq[0] = NO_IRQ; - init->socket_irq[1] = ASSABET_IRQ_GPIO_CF_IRQ; - - /* There's only one slot, but it's "Slot 1": */ - return 2; - - irq_err: - printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n", - __FUNCTION__, irqs[i].irq, res); - - while (i--) - free_irq(irqs[i].irq, NULL); - - return res; + return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } /* * Release all resources. */ -static int assabet_pcmcia_shutdown(void) +static void assabet_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt) { - int i; - - for (i = 0; i < ARRAY_SIZE(irqs); i++) - free_irq(irqs[i].irq, NULL); - - return 0; + sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); } static void -assabet_pcmcia_socket_state(int sock, struct pcmcia_state *state) +assabet_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, struct pcmcia_state *state) { unsigned long levels = GPLR; - if (sock == 1) { - state->detect = (levels & ASSABET_GPIO_CF_CD) ? 0 : 1; - state->ready = (levels & ASSABET_GPIO_CF_IRQ) ? 1 : 0; - state->bvd1 = (levels & ASSABET_GPIO_CF_BVD1) ? 1 : 0; - state->bvd2 = (levels & ASSABET_GPIO_CF_BVD2) ? 1 : 0; - state->wrprot = 0; /* Not available on Assabet. */ - state->vs_3v = 1; /* Can only apply 3.3V on Assabet. */ - state->vs_Xv = 0; - } + state->detect = (levels & ASSABET_GPIO_CF_CD) ? 0 : 1; + state->ready = (levels & ASSABET_GPIO_CF_IRQ) ? 1 : 0; + state->bvd1 = (levels & ASSABET_GPIO_CF_BVD1) ? 1 : 0; + state->bvd2 = (levels & ASSABET_GPIO_CF_BVD2) ? 1 : 0; + state->wrprot = 0; /* Not available on Assabet. */ + state->vs_3v = 1; /* Can only apply 3.3V on Assabet. */ + state->vs_Xv = 0; } static int -assabet_pcmcia_configure_socket(int sock, const struct pcmcia_configure *configure) +assabet_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, const socket_state_t *state) { unsigned int mask; - if (sock > 1) - return -1; - - if (sock == 0) - return 0; - - switch (configure->vcc) { + switch (state->Vcc) { case 0: mask = 0; break; @@ -113,13 +75,13 @@ default: printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); + state->Vcc); return -1; } /* Silently ignore Vpp, output enable, speaker enable. */ - if (configure->reset) + if (state->flags & SS_RESET) mask |= ASSABET_BCR_CF_RST; ASSABET_BCR_frob(ASSABET_BCR_CF_RST | ASSABET_BCR_CF_PWR, mask); @@ -132,48 +94,36 @@ * be called at initialisation, power management event, or * pcmcia event. */ -static int assabet_pcmcia_socket_init(int sock) +static void assabet_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) { - int i; - - if (sock == 1) { - /* - * Enable CF bus - */ - ASSABET_BCR_clear(ASSABET_BCR_CF_BUS_OFF); + /* + * Enable CF bus + */ + ASSABET_BCR_clear(ASSABET_BCR_CF_BUS_OFF); - for (i = 0; i < ARRAY_SIZE(irqs); i++) - set_irq_type(irqs[i].irq, IRQT_BOTHEDGE); - } - - return 0; + sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } /* * Disable card status IRQs on suspend. */ -static int assabet_pcmcia_socket_suspend(int sock) +static void assabet_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt) { - int i; - - if (sock == 1) { - for (i = 0; i < ARRAY_SIZE(irqs); i++) - set_irq_type(irqs[i].irq, IRQT_NOEDGE); - - /* - * Tristate the CF bus signals. Also assert CF - * reset as per user guide page 4-11. - */ - ASSABET_BCR_set(ASSABET_BCR_CF_BUS_OFF | ASSABET_BCR_CF_RST); - } + sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); - return 0; + /* + * Tristate the CF bus signals. Also assert CF + * reset as per user guide page 4-11. + */ + ASSABET_BCR_set(ASSABET_BCR_CF_BUS_OFF | ASSABET_BCR_CF_RST); } static struct pcmcia_low_level assabet_pcmcia_ops = { .owner = THIS_MODULE, - .init = assabet_pcmcia_init, - .shutdown = assabet_pcmcia_shutdown, + + .hw_init = assabet_pcmcia_hw_init, + .hw_shutdown = assabet_pcmcia_hw_shutdown, + .socket_state = assabet_pcmcia_socket_state, .configure_socket = assabet_pcmcia_configure_socket, @@ -185,20 +135,8 @@ { int ret = -ENODEV; - if (machine_is_assabet()) { - if (!machine_has_neponset()) - ret = sa1100_register_pcmcia(&assabet_pcmcia_ops, dev); -#ifndef CONFIG_ASSABET_NEPONSET - else - printk(KERN_ERR "Card Services disabled: missing " - "Neponset support\n"); -#endif - } - return ret; -} + if (machine_is_assabet() && !machine_has_neponset()) + ret = sa11xx_drv_pcmcia_probe(dev, &assabet_pcmcia_ops, 1, 1); -void __exit pcmcia_assabet_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&assabet_pcmcia_ops, dev); + return ret; } - diff -Nru a/drivers/pcmcia/sa1100_badge4.c b/drivers/pcmcia/sa1100_badge4.c --- a/drivers/pcmcia/sa1100_badge4.c Wed Apr 2 22:24:04 2003 +++ b/drivers/pcmcia/sa1100_badge4.c Wed Apr 2 22:24:04 2003 @@ -24,7 +24,6 @@ #include #include -#include "sa1100_generic.h" #include "sa1111_generic.h" /* @@ -62,27 +61,6 @@ static int badge4_pcmvpp = 50; /* pins 2 and 4 jumpered on JP6 */ static int badge4_cfvcc = 33; /* pins 1 and 2 jumpered on JP10 */ -static int badge4_pcmcia_init(struct pcmcia_init *init) -{ - printk(KERN_INFO - "%s: badge4_pcmvcc=%d, badge4_pcmvpp=%d, badge4_cfvcc=%d\n", - __FUNCTION__, - badge4_pcmvcc, badge4_pcmvpp, badge4_cfvcc); - - return sa1111_pcmcia_init(init); -} - -static int badge4_pcmcia_shutdown(void) -{ - int rc = sa1111_pcmcia_shutdown(); - - /* be sure to disable 5v0 use */ - badge4_set_5V(BADGE4_5V_PCMCIA_SOCK0, 0); - badge4_set_5V(BADGE4_5V_PCMCIA_SOCK1, 0); - - return rc; -} - static void complain_about_jumpering(const char *whom, const char *supply, int given, int wanted) @@ -97,32 +75,32 @@ } static int -badge4_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) +badge4_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, const socket_state_t *state) { int ret; - switch (sock) { + switch (skt->nr) { case 0: - if ((conf->vcc != 0) && - (conf->vcc != badge4_pcmvcc)) { + if ((state->Vcc != 0) && + (state->Vcc != badge4_pcmvcc)) { complain_about_jumpering(__FUNCTION__, "pcmvcc", - badge4_pcmvcc, conf->vcc); + badge4_pcmvcc, state->Vcc); // Apply power regardless of the jumpering. // return -1; } - if ((conf->vpp != 0) && - (conf->vpp != badge4_pcmvpp)) { + if ((state->Vpp != 0) && + (state->Vpp != badge4_pcmvpp)) { complain_about_jumpering(__FUNCTION__, "pcmvpp", - badge4_pcmvpp, conf->vpp); + badge4_pcmvpp, state->Vpp); return -1; } break; case 1: - if ((conf->vcc != 0) && - (conf->vcc != badge4_cfvcc)) { + if ((state->Vcc != 0) && + (state->Vcc != badge4_cfvcc)) { complain_about_jumpering(__FUNCTION__, "cfvcc", - badge4_cfvcc, conf->vcc); + badge4_cfvcc, state->Vcc); return -1; } break; @@ -131,16 +109,16 @@ return -1; } - ret = sa1111_pcmcia_configure_socket(sock, conf); + ret = sa1111_pcmcia_configure_socket(skt, state); if (ret == 0) { unsigned long flags; int need5V; local_irq_save(flags); - need5V = ((conf->vcc == 50) || (conf->vpp == 50)); + need5V = ((state->Vcc == 50) || (state->Vpp == 50)); - badge4_set_5V(BADGE4_5V_PCMCIA_SOCK(conf->sock), need5V); + badge4_set_5V(BADGE4_5V_PCMCIA_SOCK(skt->nr), need5V); local_irq_restore(flags); } @@ -150,8 +128,8 @@ static struct pcmcia_low_level badge4_pcmcia_ops = { .owner = THIS_MODULE, - .init = badge4_pcmcia_init, - .shutdown = badge4_pcmcia_shutdown, + .init = sa1111_pcmcia_hw_init, + .shutdown = sa1111_pcmcia_hw_shutdown, .socket_state = sa1111_pcmcia_socket_state, .configure_socket = badge4_pcmcia_configure_socket, @@ -163,15 +141,16 @@ { int ret = -ENODEV; - if (machine_is_badge4()) - ret = sa1100_register_pcmcia(&badge4_pcmcia_ops, dev); + if (machine_is_badge4()) { + printk(KERN_INFO + "%s: badge4_pcmvcc=%d, badge4_pcmvpp=%d, badge4_cfvcc=%d\n", + __FUNCTION__, + badge4_pcmvcc, badge4_pcmvpp, badge4_cfvcc); - return ret; -} + ret = sa11xx_drv_pcmcia_probe(dev, &badge4_pcmcia_ops, 0, 2); + } -void __devexit pcmcia_badge4_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&badge4_pcmcia_ops, dev); + return ret; } static int __init pcmv_setup(char *s) diff -Nru a/drivers/pcmcia/sa1100_cerf.c b/drivers/pcmcia/sa1100_cerf.c --- a/drivers/pcmcia/sa1100_cerf.c Wed Apr 2 22:24:07 2003 +++ b/drivers/pcmcia/sa1100_cerf.c Wed Apr 2 22:24:07 2003 @@ -23,139 +23,91 @@ #define CERF_SOCKET 1 #endif -static struct irqs { - int irq; - const char *str; -} irqs[] = { - { IRQ_GPIO_CF_CD, "CF_CD" }, - { IRQ_GPIO_CF_BVD2, "CF_BVD2" }, - { IRQ_GPIO_CF_BVD1, "CF_BVD1" } +static struct pcmcia_irqs irqs[] = { + { CERF_SOCKET, IRQ_GPIO_CF_CD, "CF_CD" }, + { CERF_SOCKET, IRQ_GPIO_CF_BVD2, "CF_BVD2" }, + { CERF_SOCKET, IRQ_GPIO_CF_BVD1, "CF_BVD1" } }; -static int cerf_pcmcia_init(struct pcmcia_init *init) +static int cerf_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) { - int i, res; + skt->irq = IRQ_GPIO_CF_IRQ; - for (i = 0; i < ARRAY_SIZE(irqs); i++) { - res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt, SA_INTERRUPT, - irqs[i].str, NULL); - if (res) - goto irq_err; - set_irq_type(irqs[i].irq, IRQT_NOEDGE); - } - - init->socket_irq[CERF_SOCKET] = IRQ_GPIO_CF_IRQ; - - return 2; - - irq_err: - printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n", - __FUNCTION__, irqs[i].irq, res); - - while (i--) - free_irq(irqs[i].irq, NULL); - - return res; + return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int cerf_pcmcia_shutdown(void) +static void cerf_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt) { - int i; - - for (i = 0; i < ARRAY_SIZE(irqs); i++) - free_irq(irqs[i].irq, NULL); - - return 0; + sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static void cerf_pcmcia_socket_state(int sock, struct pcmcia_state *state) +static void +cerf_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, struct pcmcia_state *state) { - unsigned long levels=GPLR; + unsigned long levels = GPLR; - if (sock == CERF_SOCKET) { - state->detect=((levels & GPIO_CF_CD)==0)?1:0; - state->ready=(levels & GPIO_CF_IRQ)?1:0; - state->bvd1=(levels & GPIO_CF_BVD1)?1:0; - state->bvd2=(levels & GPIO_CF_BVD2)?1:0; - state->wrprot=0; - state->vs_3v=1; - state->vs_Xv=0; - } + state->detect=((levels & GPIO_CF_CD)==0)?1:0; + state->ready=(levels & GPIO_CF_IRQ)?1:0; + state->bvd1=(levels & GPIO_CF_BVD1)?1:0; + state->bvd2=(levels & GPIO_CF_BVD2)?1:0; + state->wrprot=0; + state->vs_3v=1; + state->vs_Xv=0; } -static int cerf_pcmcia_configure_socket(int sock, const struct pcmcia_configure - *configure) +static int +cerf_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, + const socket_state_t *state) { - if (sock>1) - return -1; - - if (sock != CERF_SOCKET) - return 0; + switch (state->Vcc) { + case 0: + break; - switch(configure->vcc){ - case 0: - break; - - case 50: - case 33: + case 50: + case 33: #ifdef CONFIG_SA1100_CERF_CPLD - GPCR = GPIO_PWR_SHUTDOWN; + GPCR = GPIO_PWR_SHUTDOWN; #endif - break; + break; - default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - return -1; - } + default: + printk(KERN_ERR "%s(): unrecognized Vcc %u\n", + __FUNCTION__, state->Vcc); + return -1; + } - if(configure->reset) - { + if (state->flags & SS_RESET) { #ifdef CONFIG_SA1100_CERF_CPLD - GPSR = GPIO_CF_RESET; + GPSR = GPIO_CF_RESET; #endif - } - else - { + } else { #ifdef CONFIG_SA1100_CERF_CPLD - GPCR = GPIO_CF_RESET; + GPCR = GPIO_CF_RESET; #endif - } + } - return 0; + return 0; } -static int cerf_pcmcia_socket_init(int sock) +static void cerf_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) { - int i; - - if (sock == CERF_SOCKET) - for (i = 0; i < ARRAY_SIZE(irqs); i++) - set_irq_type(irqs[i].irq, IRQT_BOTHEDGE); - - return 0; + sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int cerf_pcmcia_socket_suspend(int sock) +static void cerf_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt) { - int i; - - if (sock == CERF_SOCKET) - for (i = 0; i < ARRAY_SIZE(irqs); i++) - set_irq_type(irqs[i].irq, IRQT_NOEDGE); - - return 0; + sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } static struct pcmcia_low_level cerf_pcmcia_ops = { - .owner = THIS_MODULE, - .init = cerf_pcmcia_init, - .shutdown = cerf_pcmcia_shutdown, - .socket_state = cerf_pcmcia_socket_state, - .configure_socket = cerf_pcmcia_configure_socket, + .owner = THIS_MODULE, + .init = cerf_pcmcia_hw_init, + .shutdown = cerf_pcmcia_hw_shutdown, + .socket_state = cerf_pcmcia_socket_state, + .configure_socket = cerf_pcmcia_configure_socket, - .socket_init = cerf_pcmcia_socket_init, - .socket_suspend = cerf_pcmcia_socket_suspend, + .socket_init = cerf_pcmcia_socket_init, + .socket_suspend = cerf_pcmcia_socket_suspend, }; int __init pcmcia_cerf_init(struct device *dev) @@ -163,12 +115,7 @@ int ret = -ENODEV; if (machine_is_cerf()) - ret = sa1100_register_pcmcia(&cerf_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &cerf_pcmcia_ops, CERF_SOCKET, 1); return ret; -} - -void __exit pcmcia_cerf_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&cerf_pcmcia_ops, dev); } diff -Nru a/drivers/pcmcia/sa1100_flexanet.c b/drivers/pcmcia/sa1100_flexanet.c --- a/drivers/pcmcia/sa1100_flexanet.c Wed Apr 2 22:24:05 2003 +++ b/drivers/pcmcia/sa1100_flexanet.c Wed Apr 2 22:24:05 2003 @@ -16,69 +16,32 @@ #include #include "sa1100_generic.h" -static struct { - int irq; - const char *name; -} irqs[] = { - { IRQ_GPIO_CF1_CD, "CF1_CD" }, - { IRQ_GPIO_CF1_BVD1, "CF1_BVD1" }, - { IRQ_GPIO_CF2_CD, "CF2_CD" }, - { IRQ_GPIO_CF2_BVD1, "CF2_BVD1" } +static struct pcmcia_irqs irqs[] = { + { 0, IRQ_GPIO_CF1_CD, "CF1_CD" }, + { 0, IRQ_GPIO_CF1_BVD1, "CF1_BVD1" }, + { 1, IRQ_GPIO_CF2_CD, "CF2_CD" }, + { 1, IRQ_GPIO_CF2_BVD1, "CF2_BVD1" } }; /* * Socket initialization. * * Called by sa1100_pcmcia_driver_init on startup. - * Must return the number of slots. - * */ -static int flexanet_pcmcia_init(struct pcmcia_init *init) +static int flexanet_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) { - int i, res; - - /* Configure the GPIOs as inputs (BVD2 is not implemented) */ - GPDR &= ~(GPIO_CF1_NCD | GPIO_CF1_BVD1 | GPIO_CF1_IRQ | - GPIO_CF2_NCD | GPIO_CF2_BVD1 | GPIO_CF2_IRQ ); - - /* Register the socket interrupts (not the card interrupts) */ - for (i = 0; i < ARRAY_SIZE(irqs); i++) { - res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt, SA_INTERRUPT, - irqs[i].name, NULL); - if (res < 0) - break; - set_irq_type(irqs[i].irq, IRQT_NOEDGE); - } - - init->socket_irq[0] = IRQ_GPIO_CF1_IRQ; - init->socket_irq[1] = IRQ_GPIO_CF2_IRQ; - - /* If we failed, then free all interrupts requested thus far. */ - if (res < 0) { - printk(KERN_ERR "%s: request for IRQ%d failed: %d\n", - __FUNCTION__, irqs[i].irq, res); - while (i--) - free_irq(irqs[i].irq, NULL); - return res; - } + skt->irq = skt->nr ? IRQ_GPIO_CF2_IRQ : IRQ_GPIO_CF1_IRQ; - return 2; + return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } /* * Socket shutdown - * */ -static int flexanet_pcmcia_shutdown(void) +static void flexanet_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt) { - int i; - - /* disable IRQs */ - for (i = 0; i < ARRAY_SIZE(irqs); i++) - free_irq(irqs[i].irq, NULL); - - return 0; + sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); } @@ -88,109 +51,96 @@ * Sockets in Flexanet are 3.3V only, without BVD2. * */ -static void flexanet_pcmcia_socket_state(int sock, struct pcmcia_state *state) -{ - unsigned long levels = GPLR; /* Sense the GPIOs, asynchronously */ - - switch (sock) { - case 0: /* Socket 0 */ - state->detect = ((levels & GPIO_CF1_NCD)==0)?1:0; - state->ready = (levels & GPIO_CF1_IRQ)?1:0; - state->bvd1 = (levels & GPIO_CF1_BVD1)?1:0; - state->bvd2 = 1; - state->wrprot = 0; - state->vs_3v = 1; - state->vs_Xv = 0; - break; - - case 1: /* Socket 1 */ - state->detect = ((levels & GPIO_CF2_NCD)==0)?1:0; - state->ready = (levels & GPIO_CF2_IRQ)?1:0; - state->bvd1 = (levels & GPIO_CF2_BVD1)?1:0; - state->bvd2 = 1; - state->wrprot = 0; - state->vs_3v = 1; - state->vs_Xv = 0; - break; - } +static void +flexanet_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, + struct pcmcia_state *state) +{ + unsigned long levels = GPLR; /* Sense the GPIOs, asynchronously */ + + switch (skt->nr) { + ase 0: /* Socket 0 */ + state->detect = ((levels & GPIO_CF1_NCD)==0)?1:0; + state->ready = (levels & GPIO_CF1_IRQ)?1:0; + state->bvd1 = (levels & GPIO_CF1_BVD1)?1:0; + state->bvd2 = 1; + state->wrprot = 0; + state->vs_3v = 1; + state->vs_Xv = 0; + break; + + case 1: /* Socket 1 */ + state->detect = ((levels & GPIO_CF2_NCD)==0)?1:0; + state->ready = (levels & GPIO_CF2_IRQ)?1:0; + state->bvd1 = (levels & GPIO_CF2_BVD1)?1:0; + state->bvd2 = 1; + state->wrprot = 0; + state->vs_3v = 1; + state->vs_Xv = 0; + break; + } } /* * */ -static int flexanet_pcmcia_configure_socket(int sock, const struct pcmcia_configure - *configure) +static int +flexanet_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, + const socket_state_t *state) { - unsigned long value, flags, mask; - - if (sock > 1) - return -1; + unsigned long value, flags, mask; - /* Ignore the VCC level since it is 3.3V and always on */ - switch (configure->vcc) - { - case 0: - printk(KERN_WARNING "%s(): CS asked to power off.\n", __FUNCTION__); - break; + /* Ignore the VCC level since it is 3.3V and always on */ + switch (state->Vcc) { + case 0: + printk(KERN_WARNING "%s(): CS asked to power off.\n", + __FUNCTION__); + break; - case 50: - printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n", - __FUNCTION__); + case 50: + printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n", + __FUNCTION__); - case 33: - break; + case 33: + break; - default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - return -1; - } + default: + printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, + state->Vcc); + return -1; + } - /* Reset the slot(s) using the controls in the BCR */ - mask = 0; + /* Reset the slot(s) using the controls in the BCR */ + mask = 0; - switch (sock) - { - case 0 : mask = FHH_BCR_CF1_RST; break; - case 1 : mask = FHH_BCR_CF2_RST; break; - } + switch (skt->nr) { + case 0: + mask = FHH_BCR_CF1_RST; + break; + case 1: + mask = FHH_BCR_CF2_RST; + break; + } - local_irq_save(flags); + local_irq_save(flags); - value = flexanet_BCR; - value = (configure->reset) ? (value | mask) : (value & ~mask); - FHH_BCR = flexanet_BCR = value; + value = flexanet_BCR; + value = (state->flags & SS_RESET) ? (value | mask) : (value & ~mask); + FHH_BCR = flexanet_BCR = value; - local_irq_restore(flags); + local_irq_restore(flags); - return 0; + return 0; } -static int flexanet_pcmcia_socket_init(int sock) +static void flexanet_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) { - if (sock == 0) { - set_irq_type(IRQ_GPIO_CF1_CD, IRQT_BOTHEDGE); - set_irq_type(IRQ_GPIO_CF1_BVD1, IRQT_BOTHEDGE); - } else if (sock == 1) { - set_irq_type(IRQ_GPIO_CF2_CD, IRQT_BOTHEDGE); - set_irq_type(IRQ_GPIO_CF2_BVD1, IRQT_BOTHEDGE); - } - - return 0; + sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int flexanet_pcmcia_socket_suspend(int sock) +static void flexanet_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt) { - if (sock == 0) { - set_irq_type(IRQ_GPIO_CF1_CD, IRQT_NOEDGE); - set_irq_type(IRQ_GPIO_CF1_BVD1, IRQT_NOEDGE); - } else if (sock == 1) { - set_irq_type(IRQ_GPIO_CF2_CD, IRQT_NOEDGE); - set_irq_type(IRQ_GPIO_CF2_BVD1, IRQT_NOEDGE); - } - - return 0; + sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } /* @@ -198,14 +148,13 @@ * */ static struct pcmcia_low_level flexanet_pcmcia_ops = { - .owner = THIS_MODULE, - .init = flexanet_pcmcia_init, - .shutdown = flexanet_pcmcia_shutdown, - .socket_state = flexanet_pcmcia_socket_state, - .configure_socket = flexanet_pcmcia_configure_socket, - - .socket_init = flexanet_pcmcia_socket_init, - .socket_suspend = flexanet_pcmcia_socket_suspend, + .owner = THIS_MODULE, + .hw_init = flexanet_pcmcia_hw_init, + .hw_shutdown = flexanet_pcmcia_hw_shutdown, + .socket_state = flexanet_pcmcia_socket_state, + .configure_socket = flexanet_pcmcia_configure_socket, + .socket_init = flexanet_pcmcia_socket_init, + .socket_suspend = flexanet_pcmcia_socket_suspend, }; int __init pcmcia_flexanet_init(struct device *dev) @@ -213,13 +162,7 @@ int ret = -ENODEV; if (machine_is_flexanet()) - ret = sa1100_register_pcmcia(&flexanet_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &flexanet_pcmcia_ops, 0, 2); return ret; } - -void __exit pcmcia_flexanet_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&flexanet_pcmcia_ops, dev); -} - diff -Nru a/drivers/pcmcia/sa1100_freebird.c b/drivers/pcmcia/sa1100_freebird.c --- a/drivers/pcmcia/sa1100_freebird.c Wed Apr 2 22:24:04 2003 +++ b/drivers/pcmcia/sa1100_freebird.c Wed Apr 2 22:24:04 2003 @@ -15,155 +15,113 @@ #include #include "sa1100_generic.h" -static struct irqs { - int irq; - const char *str; -} irqs[] = { - { IRQ_GPIO_FREEBIRD_CF_CD, "CF_CD" }, - { IRQ_GPIO_FREEBIRD_CF_BVD, "CF_BVD1" }, +static struct pcmcia_irqs irqs[] = { + { 0, IRQ_GPIO_FREEBIRD_CF_CD, "CF_CD" }, + { 0, IRQ_GPIO_FREEBIRD_CF_BVD, "CF_BVD1" }, }; -static int freebird_pcmcia_init(struct pcmcia_init *init){ - int i, res; - - /* Enable Linkup CF card */ - LINKUP_PRC = 0xc0; - mdelay(100); - LINKUP_PRC = 0xc1; - mdelay(100); - LINKUP_PRC = 0xd1; - mdelay(100); - LINKUP_PRC = 0xd1; - mdelay(100); - LINKUP_PRC = 0xc0; - - /* Register interrupts */ - for (i = 0; i < ARRAY_SIZE(irqs); i++) { - res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt, SA_INTERRUPT, - irqs[i].str, NULL); - if (res) - goto irq_err; - set_irq_type(irqs[i].irq, IRQT_NOEDGE); - } - - init->socket_irq[0] = IRQ_GPIO_FREEBIRD_CF_IRQ; - - /* There's only one slot, but it's "Slot 1": */ - return 2; - -irq_err: - printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n", - __FUNCTION__, irqs[i].irq, res); +static int freebird_pcmcia_init(struct sa1100_pcmcia_socket *skt) +{ + /* Enable Linkup CF card */ + LINKUP_PRC = 0xc0; + mdelay(100); + LINKUP_PRC = 0xc1; + mdelay(100); + LINKUP_PRC = 0xd1; + mdelay(100); + LINKUP_PRC = 0xd1; + mdelay(100); + LINKUP_PRC = 0xc0; - while (i--) - free_irq(irqs[i].irq, NULL); + skt->irq = IRQ_GPIO_FREEBIRD_CF_IRQ; - return res; + return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int freebird_pcmcia_shutdown(void) +static void freebird_pcmcia_shutdown(struct sa1100_pcmcia_socket *skt) { - int i; - - /* disable IRQs */ - for (i = 0; i < ARRAY_SIZE(irqs); i++) - free_irq(irqs[i].irq, NULL); + sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs); - /* Disable CF card */ - LINKUP_PRC = 0x40; /* SSP=1 SOE=0 */ - mdelay(100); - - return 0; + /* Disable CF card */ + LINKUP_PRC = 0x40; /* SSP=1 SOE=0 */ + mdelay(100); } -static void freebird_pcmcia_socket_state(int sock, struct pcmcia_state *state) +static void +freebird_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, struct pcmcia_state *state) { - unsigned long levels = LINKUP_PRS; -//printk("LINKUP_PRS=%x\n",levels); + unsigned long levels = LINKUP_PRS; +// printk("LINKUP_PRS=%x\n",levels); - if (sock == 0) { - state->detect = ((levels & (LINKUP_CD1 | LINKUP_CD2))==0)?1:0; - state->ready = (levels & LINKUP_RDY)?1:0; - state->bvd1 = (levels & LINKUP_BVD1)?1:0; - state->bvd2 = (levels & LINKUP_BVD2)?1:0; - state->wrprot = 0; /* Not available on Assabet. */ - state->vs_3v = 1; /* Can only apply 3.3V on Assabet. */ - state->vs_Xv = 0; - } + state->detect = ((levels & (LINKUP_CD1 | LINKUP_CD2))==0)?1:0; + state->ready = (levels & LINKUP_RDY)?1:0; + state->bvd1 = (levels & LINKUP_BVD1)?1:0; + state->bvd2 = (levels & LINKUP_BVD2)?1:0; + state->wrprot = 0; /* Not available on Assabet. */ + state->vs_3v = 1; /* Can only apply 3.3V on Assabet. */ + state->vs_Xv = 0; } -static int freebird_pcmcia_configure_socket(int sock, const struct pcmcia_configure - *configure) +static int +freebird_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, + socket_state_t *state) { - unsigned long value, flags; - - if(sock>1) return -1; - - if(sock==1) return 0; - - local_irq_save(flags); + unsigned long value, flags; - value = 0xc0; /* SSP=1 SOE=1 CFE=1 */ + local_irq_save(flags); - switch(configure->vcc){ - case 0: + value = 0xc0; /* SSP=1 SOE=1 CFE=1 */ - break; + switch (state->Vcc) { + case 0: + break; - case 50: - printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n", - __FUNCTION__); + case 50: + printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n", + __FUNCTION__); - case 33: /* Can only apply 3.3V to the CF slot. */ - value |= LINKUP_S1; - break; + case 33: /* Can only apply 3.3V to the CF slot. */ + value |= LINKUP_S1; + break; - default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - local_irq_restore(flags); - return -1; - } + default: + printk(KERN_ERR "%s(): unrecognized Vcc %u\n", + __FUNCTION__, state->Vcc); + local_irq_restore(flags); + return -1; + } - if (configure->reset) - value = (configure->reset) ? (value | LINKUP_RESET) : (value & ~LINKUP_RESET); + if (state->flags & SS_RESET) + value |= LINKUP_RESET; - /* Silently ignore Vpp, output enable, speaker enable. */ + /* Silently ignore Vpp, output enable, speaker enable. */ - LINKUP_PRC = value; -//printk("LINKUP_PRC=%x\n",value); - local_irq_restore(flags); + LINKUP_PRC = value; +// printk("LINKUP_PRC=%x\n",value); + local_irq_restore(flags); - return 0; + return 0; } -static int freebird_pcmcia_socket_init(int sock) +static void freebird_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) { - if (sock == 1) { - set_irq_type(IRQ_GPIO_FREEBIRD_CF_CD, IRQT_BOTHEDGE); - set_irq_type(IRQ_GPIO_FREEBIRD_CF_BVD, IRQT_BOTHEDGE); - } - return 0; + sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int freebird_pcmcia_socket_suspend(int sock) +static void freebird_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt) { - if (sock == 1) { - set_irq_type(IRQ_GPIO_FREEBIRD_CF_CD, IRQT_NOEDGE); - set_irq_type(IRQ_GPIO_FREEBIRD_CF_BVD, IRQT_NOEDGE); - } - return 0; + sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } static struct pcmcia_low_level freebird_pcmcia_ops = { - .owner = THIS_MODULE, - .init = freebird_pcmcia_init, - .shutdown = freebird_pcmcia_shutdown, - .socket_state = freebird_pcmcia_socket_state, - .configure_socket = freebird_pcmcia_configure_socket, + .owner = THIS_MODULE, + .hw_init = freebird_pcmcia_hw_init, + .hw_shutdown = freebird_pcmcia_hw_shutdown, + .socket_state = freebird_pcmcia_socket_state, + .configure_socket = freebird_pcmcia_configure_socket, - .socket_init = freebird_pcmcia_socket_init, - .socket_suspend = freebird_pcmcia_socket_suspend, + .socket_init = freebird_pcmcia_socket_init, + .socket_suspend = freebird_pcmcia_socket_suspend, }; int __init pcmcia_freebird_init(struct device *dev) @@ -171,12 +129,7 @@ int ret = -ENODEV; if (machine_is_freebird()) - ret = sa1100_register_pcmcia(&freebird_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &freebird_pcmcia_ops, 0, 1); return ret; -} - -void __exit pcmcia_freebird_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&freebird_pcmcia_ops, dev); } diff -Nru a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c --- a/drivers/pcmcia/sa1100_generic.c Wed Apr 2 22:24:06 2003 +++ b/drivers/pcmcia/sa1100_generic.c Wed Apr 2 22:24:06 2003 @@ -37,1172 +37,124 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include #include #include #include #include -#include - -#include -#include -#include -#include -#include #include "sa1100.h" -#ifdef PCMCIA_DEBUG -static int pc_debug; -#endif - -/* This structure maintains housekeeping state for each socket, such - * as the last known values of the card detect pins, or the Card Services - * callback value associated with the socket: - */ -static int sa1100_pcmcia_socket_count; -static struct sa1100_pcmcia_socket sa1100_pcmcia_socket[SA1100_PCMCIA_MAX_SOCK]; - -#define PCMCIA_SOCKET(x) (sa1100_pcmcia_socket + (x)) - -/* Returned by the low-level PCMCIA interface: */ -static struct pcmcia_low_level *pcmcia_low_level; - -static struct timer_list poll_timer; -static struct work_struct sa1100_pcmcia_task; - -/* - * sa1100_pcmcia_default_mecr_timing - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * - * Calculate MECR clock wait states for given CPU clock - * speed and command wait state. This function can be over- - * written by a board specific version. - * - * The default is to simply calculate the BS values as specified in - * the INTEL SA1100 development manual - * "Expansion Memory (PCMCIA) Configuration Register (MECR)" - * that's section 10.2.5 in _my_ version of the manuial ;) - */ -static unsigned int -sa1100_pcmcia_default_mecr_timing(unsigned int sock, unsigned int cpu_speed, - unsigned int cmd_time) -{ - return sa1100_pcmcia_mecr_bs(cmd_time, cpu_speed); -} - -/* sa1100_pcmcia_set_mecr() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * - * set MECR value for socket based on this sockets - * io, mem and attribute space access speed. - * Call board specific BS value calculation to allow boards - * to tweak the BS values. - */ -static int -sa1100_pcmcia_set_mecr(struct sa1100_pcmcia_socket *skt, unsigned int cpu_clock) -{ - u32 mecr; - unsigned long flags; - unsigned int bs; - - local_irq_save(flags); - - bs = skt->ops->socket_get_timing(skt->nr, cpu_clock, skt->speed_io); - - mecr = MECR; - MECR_FAST_SET(mecr, skt->nr, 0); - MECR_BSIO_SET(mecr, skt->nr, bs ); - MECR_BSA_SET(mecr, skt->nr, bs ); - MECR_BSM_SET(mecr, skt->nr, bs ); - MECR = mecr; - - local_irq_restore(flags); - - DEBUG(4, "%s(): sock %u FAST %X BSM %X BSA %X BSIO %X\n", - __FUNCTION__, skt->nr, MECR_FAST_GET(mecr, skt->nr), - MECR_BSM_GET(mecr, skt->nr), MECR_BSA_GET(mecr, skt->nr), - MECR_BSIO_GET(mecr, skt->nr)); - - return 0; -} - -/* - * sa1100_pcmcia_config_skt - * ^^^^^^^^^^^^^^^^^^^^^^^^ - * - * Convert PCMCIA socket state to our socket configure structure. - */ -static int -sa1100_pcmcia_config_skt(struct sa1100_pcmcia_socket *skt, socket_state_t *state) -{ - struct pcmcia_configure conf; - int ret; - - conf.vcc = state->Vcc; - conf.vpp = state->Vpp; - conf.output = state->flags & SS_OUTPUT_ENA ? 1 : 0; - conf.speaker = state->flags & SS_SPKR_ENA ? 1 : 0; - conf.reset = state->flags & SS_RESET ? 1 : 0; - - ret = skt->ops->configure_socket(skt->nr, &conf); - if (ret == 0) { - /* - * This really needs a better solution. The IRQ - * may or may not be claimed by the driver. - */ - if (skt->irq_state != 1 && state->io_irq) { - skt->irq_state = 1; - set_irq_type(skt->irq, IRQT_FALLING); - } else if (skt->irq_state == 1 && state->io_irq == 0) { - skt->irq_state = 0; - set_irq_type(skt->irq, IRQT_NOEDGE); - } - - skt->cs_state = *state; - } - - if (ret < 0) - printk(KERN_ERR "sa1100_pcmcia: unable to configure " - "socket %d\n", skt->nr); - - return ret; -} - -/* sa1100_pcmcia_sock_init() - * ^^^^^^^^^^^^^^^^^^^^^^^^^ - * - * (Re-)Initialise the socket, turning on status interrupts - * and PCMCIA bus. This must wait for power to stabilise - * so that the card status signals report correctly. - * - * Returns: 0 - */ -static int sa1100_pcmcia_sock_init(unsigned int sock) -{ - struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); - - DEBUG(2, "%s(): initializing socket %u\n", __FUNCTION__, sock); - - sa1100_pcmcia_config_skt(skt, &dead_socket); - - return skt->ops->socket_init(skt->nr); -} - - -/* - * sa1100_pcmcia_suspend() - * ^^^^^^^^^^^^^^^^^^^^^^^ - * - * Remove power on the socket, disable IRQs from the card. - * Turn off status interrupts, and disable the PCMCIA bus. - * - * Returns: 0 - */ -static int sa1100_pcmcia_suspend(unsigned int sock) -{ - struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); - int ret; - - DEBUG(2, "%s(): suspending socket %u\n", __FUNCTION__, skt->nr); - - ret = sa1100_pcmcia_config_skt(skt, &dead_socket); - - if (ret == 0) - ret = skt->ops->socket_suspend(skt->nr); - - return ret; -} - - -/* sa1100_pcmcia_events() - * ^^^^^^^^^^^^^^^^^^^^^^ - * Helper routine to generate a Card Services event mask based on - * state information obtained from the kernel low-level PCMCIA layer - * in a recent (and previous) sampling. Updates `prev_state'. - * - * Returns: an event mask for the given socket state. - */ -static inline unsigned int -sa1100_pcmcia_events(struct pcmcia_state *state, - struct pcmcia_state *prev_state, - unsigned int mask, unsigned int flags) -{ - unsigned int events = 0; - - if (state->detect != prev_state->detect) { - DEBUG(3, "%s(): card detect value %u\n", __FUNCTION__, state->detect); - - events |= SS_DETECT; - } - - if (state->ready != prev_state->ready) { - DEBUG(3, "%s(): card ready value %u\n", __FUNCTION__, state->ready); - - events |= flags & SS_IOCARD ? 0 : SS_READY; - } - - if (state->bvd1 != prev_state->bvd1) { - DEBUG(3, "%s(): card BVD1 value %u\n", __FUNCTION__, state->bvd1); - - events |= flags & SS_IOCARD ? SS_STSCHG : SS_BATDEAD; - } - - if (state->bvd2 != prev_state->bvd2) { - DEBUG(3, "%s(): card BVD2 value %u\n", __FUNCTION__, state->bvd2); - - events |= flags & SS_IOCARD ? 0 : SS_BATWARN; - } - - *prev_state = *state; - - events &= mask; - - DEBUG(2, "events: %s%s%s%s%s%s\n", - events == 0 ? "" : "", - events & SS_DETECT ? "DETECT " : "", - events & SS_READY ? "READY " : "", - events & SS_BATDEAD ? "BATDEAD " : "", - events & SS_BATWARN ? "BATWARN " : "", - events & SS_STSCHG ? "STSCHG " : ""); - - return events; -} /* sa1100_pcmcia_events() */ - - -/* sa1100_pcmcia_task_handler() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Processes serviceable socket events using the "eventd" thread context. - * - * Event processing (specifically, the invocation of the Card Services event - * callback) occurs in this thread rather than in the actual interrupt - * handler due to the use of scheduling operations in the PCMCIA core. - */ -static void sa1100_pcmcia_task_handler(void *data) -{ - struct pcmcia_state state; - unsigned int all_events; - - DEBUG(4, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__); - - do { - unsigned int events; - int i; - - DEBUG(4, "%s(): interrogating low-level PCMCIA service\n", __FUNCTION__); - - all_events = 0; - - for (i = 0; i < sa1100_pcmcia_socket_count; i++) { - struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i); - - memset(&state, 0, sizeof(state)); - - skt->ops->socket_state(skt->nr, &state); - - events = sa1100_pcmcia_events(&state, &skt->k_state, - skt->cs_state.csc_mask, - skt->cs_state.flags); - - if (events && skt->handler != NULL) - skt->handler(skt->handler_info, events); - all_events |= events; - } - } while(all_events); -} /* sa1100_pcmcia_task_handler() */ - -static DECLARE_WORK(sa1100_pcmcia_task, sa1100_pcmcia_task_handler, NULL); - - -/* sa1100_pcmcia_poll_event() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Let's poll for events in addition to IRQs since IRQ only is unreliable... - */ -static void sa1100_pcmcia_poll_event(unsigned long dummy) -{ - DEBUG(4, "%s(): polling for events\n", __FUNCTION__); - init_timer(&poll_timer); - poll_timer.function = sa1100_pcmcia_poll_event; - poll_timer.expires = jiffies + SA1100_PCMCIA_POLL_PERIOD; - add_timer(&poll_timer); - schedule_work(&sa1100_pcmcia_task); -} - - -/* sa1100_pcmcia_interrupt() - * ^^^^^^^^^^^^^^^^^^^^^^^^^ - * Service routine for socket driver interrupts (requested by the - * low-level PCMCIA init() operation via sa1100_pcmcia_thread()). - * The actual interrupt-servicing work is performed by - * sa1100_pcmcia_thread(), largely because the Card Services event- - * handling code performs scheduling operations which cannot be - * executed from within an interrupt context. - */ -void sa1100_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs) -{ - DEBUG(3, "%s(): servicing IRQ %d\n", __FUNCTION__, irq); - schedule_work(&sa1100_pcmcia_task); -} - - -/* sa1100_pcmcia_register_callback() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Implements the register_callback() operation for the in-kernel - * PCMCIA service (formerly SS_RegisterCallback in Card Services). If - * the function pointer `handler' is not NULL, remember the callback - * location in the state for `sock', and increment the usage counter - * for the driver module. (The callback is invoked from the interrupt - * service routine, sa1100_pcmcia_interrupt(), to notify Card Services - * of interesting events.) Otherwise, clear the callback pointer in the - * socket state and decrement the module usage count. - * - * Returns: 0 - */ -static int -sa1100_pcmcia_register_callback(unsigned int sock, - void (*handler)(void *, unsigned int), - void *info) -{ - struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); - - if (handler && !try_module_get(skt->ops->owner)) - return -ENODEV; - if (handler == NULL) { - skt->handler = NULL; - } else { - skt->handler_info = info; - skt->handler = handler; - } - if (!handler) - module_put(skt->ops->owner); - - return 0; -} - - -/* sa1100_pcmcia_inquire_socket() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Implements the inquire_socket() operation for the in-kernel PCMCIA - * service (formerly SS_InquireSocket in Card Services). Of note is - * the setting of the SS_CAP_PAGE_REGS bit in the `features' field of - * `cap' to "trick" Card Services into tolerating large "I/O memory" - * addresses. Also set is SS_CAP_STATIC_MAP, which disables the memory - * resource database check. (Mapped memory is set up within the socket - * driver itself.) - * - * In conjunction with the STATIC_MAP capability is a new field, - * `io_offset', recommended by David Hinds. Rather than go through - * the SetIOMap interface (which is not quite suited for communicating - * window locations up from the socket driver), we just pass up - * an offset which is applied to client-requested base I/O addresses - * in alloc_io_space(). - * - * SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the - * force_low argument to validate_mem() in rsrc_mgr.c -- since in - * general, the mapped * addresses of the PCMCIA memory regions - * will not be within 0xffff, setting force_low would be - * undesirable. - * - * SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory - * resource database; we instead pass up physical address ranges - * and allow other parts of Card Services to deal with remapping. - * - * SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but - * not 32-bit CardBus devices. - * - * Return value is irrelevant; the pcmcia subsystem ignores it. - */ -static int -sa1100_pcmcia_inquire_socket(unsigned int sock, socket_cap_t *cap) -{ - struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); - int ret = -1; - - DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr); - - if (sock < sa1100_pcmcia_socket_count) { - cap->features = SS_CAP_PAGE_REGS | SS_CAP_STATIC_MAP | SS_CAP_PCCARD; - cap->irq_mask = 0; - cap->map_size = PAGE_SIZE; - cap->pci_irq = skt->irq; - cap->io_offset = (unsigned long)skt->virt_io; - - ret = 0; - } - - return ret; -} - - -/* sa1100_pcmcia_get_status() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Implements the get_status() operation for the in-kernel PCMCIA - * service (formerly SS_GetStatus in Card Services). Essentially just - * fills in bits in `status' according to internal driver state or - * the value of the voltage detect chipselect register. - * - * As a debugging note, during card startup, the PCMCIA core issues - * three set_socket() commands in a row the first with RESET deasserted, - * the second with RESET asserted, and the last with RESET deasserted - * again. Following the third set_socket(), a get_status() command will - * be issued. The kernel is looking for the SS_READY flag (see - * setup_socket(), reset_socket(), and unreset_socket() in cs.c). - * - * Returns: 0 - */ -static int -sa1100_pcmcia_get_status(unsigned int sock, unsigned int *status) -{ - struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); - struct pcmcia_state state; - unsigned int stat; - - DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr); - - memset(&state, 0, sizeof(state)); - - skt->ops->socket_state(skt->nr, &state); - skt->k_state = state; - - stat = state.detect ? SS_DETECT : 0; - stat |= state.ready ? SS_READY : 0; - stat |= state.vs_3v ? SS_3VCARD : 0; - stat |= state.vs_Xv ? SS_XVCARD : 0; - - /* The power status of individual sockets is not available - * explicitly from the hardware, so we just remember the state - * and regurgitate it upon request: - */ - stat |= skt->cs_state.Vcc ? SS_POWERON : 0; - - if (skt->cs_state.flags & SS_IOCARD) - stat |= state.bvd1 ? SS_STSCHG : 0; - else { - if (state.bvd1 == 0) - stat |= SS_BATDEAD; - else if (state.bvd2 == 0) - stat |= SS_BATWARN; - } - - DEBUG(3, "\tstatus: %s%s%s%s%s%s%s%s\n", - stat & SS_DETECT ? "DETECT " : "", - stat & SS_READY ? "READY " : "", - stat & SS_BATDEAD ? "BATDEAD " : "", - stat & SS_BATWARN ? "BATWARN " : "", - stat & SS_POWERON ? "POWERON " : "", - stat & SS_STSCHG ? "STSCHG " : "", - stat & SS_3VCARD ? "3VCARD " : "", - stat & SS_XVCARD ? "XVCARD " : ""); - - *status = stat; - - return 0; -} /* sa1100_pcmcia_get_status() */ - - -/* sa1100_pcmcia_get_socket() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Implements the get_socket() operation for the in-kernel PCMCIA - * service (formerly SS_GetSocket in Card Services). Not a very - * exciting routine. - * - * Returns: 0 - */ -static int -sa1100_pcmcia_get_socket(unsigned int sock, socket_state_t *state) -{ - struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); - - DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr); - - *state = skt->cs_state; - - return 0; -} - -/* sa1100_pcmcia_set_socket() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Implements the set_socket() operation for the in-kernel PCMCIA - * service (formerly SS_SetSocket in Card Services). We more or - * less punt all of this work and let the kernel handle the details - * of power configuration, reset, &c. We also record the value of - * `state' in order to regurgitate it to the PCMCIA core later. - * - * Returns: 0 - */ -static int -sa1100_pcmcia_set_socket(unsigned int sock, socket_state_t *state) -{ - struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); - - DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr); - - DEBUG(3, "\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n", - (state->csc_mask==0)?"":"", - (state->csc_mask&SS_DETECT)?"DETECT ":"", - (state->csc_mask&SS_READY)?"READY ":"", - (state->csc_mask&SS_BATDEAD)?"BATDEAD ":"", - (state->csc_mask&SS_BATWARN)?"BATWARN ":"", - (state->csc_mask&SS_STSCHG)?"STSCHG ":"", - (state->flags==0)?"":"", - (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"", - (state->flags&SS_IOCARD)?"IOCARD ":"", - (state->flags&SS_RESET)?"RESET ":"", - (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"", - (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":""); - DEBUG(3, "\tVcc %d Vpp %d irq %d\n", - state->Vcc, state->Vpp, state->io_irq); - - return sa1100_pcmcia_config_skt(skt, state); -} /* sa1100_pcmcia_set_socket() */ - - -/* sa1100_pcmcia_get_io_map() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Implements the get_io_map() operation for the in-kernel PCMCIA - * service (formerly SS_GetIOMap in Card Services). Just returns an - * I/O map descriptor which was assigned earlier by a set_io_map(). - * - * Returns: 0 on success, -1 if the map index was out of range - */ -static int -sa1100_pcmcia_get_io_map(unsigned int sock, struct pccard_io_map *map) -{ - struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); - int ret = -1; - - DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); - - if (map->map < MAX_IO_WIN) { - *map = skt->io_map[map->map]; - ret = 0; - } - - return ret; -} - - -/* sa1100_pcmcia_set_io_map() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Implements the set_io_map() operation for the in-kernel PCMCIA - * service (formerly SS_SetIOMap in Card Services). We configure - * the map speed as requested, but override the address ranges - * supplied by Card Services. - * - * Returns: 0 on success, -1 on error - */ -static int -sa1100_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *map) -{ - struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); - - DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr); - - DEBUG(3, "\tmap %u speed %u\n\tstart 0x%08x stop 0x%08x\n", - map->map, map->speed, map->start, map->stop); - DEBUG(3, "\tflags: %s%s%s%s%s%s%s%s\n", - (map->flags==0)?"":"", - (map->flags&MAP_ACTIVE)?"ACTIVE ":"", - (map->flags&MAP_16BIT)?"16BIT ":"", - (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"", - (map->flags&MAP_0WS)?"0WS ":"", - (map->flags&MAP_WRPROT)?"WRPROT ":"", - (map->flags&MAP_USE_WAIT)?"USE_WAIT ":"", - (map->flags&MAP_PREFETCH)?"PREFETCH ":""); - - if (map->map >= MAX_IO_WIN) { - printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, - map->map); - return -1; - } - - if (map->flags & MAP_ACTIVE) { - if ( map->speed == 0) - map->speed = SA1100_PCMCIA_IO_ACCESS; - - sa1100_pcmcia_set_mecr(skt, cpufreq_get(0)); - } - - if (map->stop == 1) - map->stop = PAGE_SIZE-1; - - map->stop -= map->start; - map->stop += (unsigned long)skt->virt_io; - map->start = (unsigned long)skt->virt_io; - - skt->io_map[map->map] = *map; - - return 0; -} /* sa1100_pcmcia_set_io_map() */ - - -/* sa1100_pcmcia_get_mem_map() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Implements the get_mem_map() operation for the in-kernel PCMCIA - * service (formerly SS_GetMemMap in Card Services). Just returns a - * memory map descriptor which was assigned earlier by a - * set_mem_map() request. - * - * Returns: 0 on success, -1 if the map index was out of range - */ -static int -sa1100_pcmcia_get_mem_map(unsigned int sock, struct pccard_mem_map *map) -{ - struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); - int ret = -1; - - DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); - - if (map->map < MAX_WIN) { - *map = skt->pc_mem_map[map->map]; - ret = 0; - } - - return ret; -} - - -/* sa1100_pcmcia_set_mem_map() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Implements the set_mem_map() operation for the in-kernel PCMCIA - * service (formerly SS_SetMemMap in Card Services). We configure - * the map speed as requested, but override the address ranges - * supplied by Card Services. - * - * Returns: 0 on success, -1 on error - */ -static int -sa1100_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map) -{ - struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); - unsigned long start; - - DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr); - - DEBUG(3, "\tmap %u speed %u sys_start %08lx sys_stop %08lx card_start %08x\n", - map->map, map->speed, map->sys_start, map->sys_stop, map->card_start); - DEBUG(3, "\tflags: %s%s%s%s%s%s%s%s\n", - (map->flags==0)?"":"", - (map->flags&MAP_ACTIVE)?"ACTIVE ":"", - (map->flags&MAP_16BIT)?"16BIT ":"", - (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"", - (map->flags&MAP_0WS)?"0WS ":"", - (map->flags&MAP_WRPROT)?"WRPROT ":"", - (map->flags&MAP_ATTRIB)?"ATTRIB ":"", - (map->flags&MAP_USE_WAIT)?"USE_WAIT ":""); - - if (map->map >= MAX_WIN) { - printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, - map->map); - return -1; - } - - if (map->flags & MAP_ACTIVE) { - /* - * When clients issue RequestMap, the access speed is not always - * properly configured. Choose some sensible defaults. - */ - if (map->speed == 0) { - if (skt->cs_state.Vcc == 33) - map->speed = SA1100_PCMCIA_3V_MEM_ACCESS; - else - map->speed = SA1100_PCMCIA_5V_MEM_ACCESS; - } - - sa1100_pcmcia_set_mecr(skt, cpufreq_get(0)); - - } - - if (map->sys_stop == 0) - map->sys_stop = PAGE_SIZE-1; - - start = (map->flags & MAP_ATTRIB) ? skt->phys_attr : skt->phys_mem; - map->sys_stop -= map->sys_start; - map->sys_stop += start + map->card_start; - map->sys_start = start + map->card_start; - - skt->pc_mem_map[map->map] = *map; - - return 0; -} /* sa1100_pcmcia_set_mem_map() */ - - -#if defined(CONFIG_PROC_FS) - -/* sa1100_pcmcia_proc_status() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Implements the /proc/bus/pccard/??/status file. - * - * Returns: the number of characters added to the buffer - */ -static int -sa1100_pcmcia_proc_status(char *buf, char **start, off_t pos, - int count, int *eof, void *data) -{ - struct sa1100_pcmcia_socket *skt = data; - unsigned int clock = cpufreq_get(0); - unsigned long mecr = MECR; - char *p = buf; - - p+=sprintf(p, "k_state : %s%s%s%s%s%s%s\n", - skt->k_state.detect ? "detect " : "", - skt->k_state.ready ? "ready " : "", - skt->k_state.bvd1 ? "bvd1 " : "", - skt->k_state.bvd2 ? "bvd2 " : "", - skt->k_state.wrprot ? "wrprot " : "", - skt->k_state.vs_3v ? "vs_3v " : "", - skt->k_state.vs_Xv ? "vs_Xv " : ""); - - p+=sprintf(p, "status : %s%s%s%s%s%s%s%s%s\n", - skt->k_state.detect ? "SS_DETECT " : "", - skt->k_state.ready ? "SS_READY " : "", - skt->cs_state.Vcc ? "SS_POWERON " : "", - skt->cs_state.flags & SS_IOCARD ? "SS_IOCARD " : "", - (skt->cs_state.flags & SS_IOCARD && - skt->k_state.bvd1) ? "SS_STSCHG " : "", - ((skt->cs_state.flags & SS_IOCARD)==0 && - (skt->k_state.bvd1==0)) ? "SS_BATDEAD " : "", - ((skt->cs_state.flags & SS_IOCARD)==0 && - (skt->k_state.bvd2==0)) ? "SS_BATWARN " : "", - skt->k_state.vs_3v ? "SS_3VCARD " : "", - skt->k_state.vs_Xv ? "SS_XVCARD " : ""); - - p+=sprintf(p, "mask : %s%s%s%s%s\n", - skt->cs_state.csc_mask & SS_DETECT ? "SS_DETECT " : "", - skt->cs_state.csc_mask & SS_READY ? "SS_READY " : "", - skt->cs_state.csc_mask & SS_BATDEAD ? "SS_BATDEAD " : "", - skt->cs_state.csc_mask & SS_BATWARN ? "SS_BATWARN " : "", - skt->cs_state.csc_mask & SS_STSCHG ? "SS_STSCHG " : ""); - - p+=sprintf(p, "cs_flags : %s%s%s%s%s\n", - skt->cs_state.flags & SS_PWR_AUTO ? "SS_PWR_AUTO " : "", - skt->cs_state.flags & SS_IOCARD ? "SS_IOCARD " : "", - skt->cs_state.flags & SS_RESET ? "SS_RESET " : "", - skt->cs_state.flags & SS_SPKR_ENA ? "SS_SPKR_ENA " : "", - skt->cs_state.flags & SS_OUTPUT_ENA ? "SS_OUTPUT_ENA " : ""); - - p+=sprintf(p, "Vcc : %d\n", skt->cs_state.Vcc); - p+=sprintf(p, "Vpp : %d\n", skt->cs_state.Vpp); - p+=sprintf(p, "IRQ : %d\n", skt->cs_state.io_irq); - - p+=sprintf(p, "I/O : %u (%u)\n", skt->speed_io, - sa1100_pcmcia_cmd_time(clock, MECR_BSIO_GET(mecr, skt->nr))); - - p+=sprintf(p, "attribute: %u (%u)\n", skt->speed_attr, - sa1100_pcmcia_cmd_time(clock, MECR_BSA_GET(mecr, skt->nr))); - - p+=sprintf(p, "common : %u (%u)\n", skt->speed_mem, - sa1100_pcmcia_cmd_time(clock, MECR_BSM_GET(mecr, skt->nr))); - - return p-buf; -} - -/* sa1100_pcmcia_proc_setup() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^ - * Implements the proc_setup() operation for the in-kernel PCMCIA - * service (formerly SS_ProcSetup in Card Services). - * - * Returns: 0 on success, -1 on error - */ -static void -sa1100_pcmcia_proc_setup(unsigned int sock, struct proc_dir_entry *base) -{ - struct proc_dir_entry *entry; - - DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); - - if ((entry = create_proc_entry("status", 0, base)) == NULL){ - printk(KERN_ERR "unable to install \"status\" procfs entry\n"); - return; - } - - entry->read_proc = sa1100_pcmcia_proc_status; - entry->data = PCMCIA_SOCKET(sock); -} - -#endif /* defined(CONFIG_PROC_FS) */ - -static struct pccard_operations sa1100_pcmcia_operations = { - .owner = THIS_MODULE, - .init = sa1100_pcmcia_sock_init, - .suspend = sa1100_pcmcia_suspend, - .register_callback = sa1100_pcmcia_register_callback, - .inquire_socket = sa1100_pcmcia_inquire_socket, - .get_status = sa1100_pcmcia_get_status, - .get_socket = sa1100_pcmcia_get_socket, - .set_socket = sa1100_pcmcia_set_socket, - .get_io_map = sa1100_pcmcia_get_io_map, - .set_io_map = sa1100_pcmcia_set_io_map, - .get_mem_map = sa1100_pcmcia_get_mem_map, - .set_mem_map = sa1100_pcmcia_set_mem_map, -#ifdef CONFIG_PROC_FS - .proc_setup = sa1100_pcmcia_proc_setup -#endif -}; - -#ifdef CONFIG_CPU_FREQ - -/* sa1100_pcmcia_update_mecr() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * When sa1100_pcmcia_notifier() decides that a MECR adjustment (due - * to a core clock frequency change) is needed, this routine establishes - * new BS_xx values consistent with the clock speed `clock'. - */ -static void sa1100_pcmcia_update_mecr(unsigned int clock) -{ - unsigned int sock; - - for (sock = 0; sock < SA1100_PCMCIA_MAX_SOCK; ++sock) { - struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); - sa1100_pcmcia_set_mecr(skt, clock); - } -} - -/* sa1100_pcmcia_notifier() - * ^^^^^^^^^^^^^^^^^^^^^^^^ - * When changing the processor core clock frequency, it is necessary - * to adjust the MECR timings accordingly. We've recorded the timings - * requested by Card Services, so this is just a matter of finding - * out what our current speed is, and then recomputing the new MECR - * values. - * - * Returns: 0 on success, -1 on error - */ -static int -sa1100_pcmcia_notifier(struct notifier_block *nb, unsigned long val, - void *data) -{ - struct cpufreq_freqs *freqs = data; - - switch (val) { - case CPUFREQ_PRECHANGE: - if (freqs->new > freqs->old) { - DEBUG(2, "%s(): new frequency %u.%uMHz > %u.%uMHz, " - "pre-updating\n", __FUNCTION__, - freqs->new / 1000, (freqs->new / 100) % 10, - freqs->old / 1000, (freqs->old / 100) % 10); - sa1100_pcmcia_update_mecr(freqs->new); - } - break; - - case CPUFREQ_POSTCHANGE: - if (freqs->new < freqs->old) { - DEBUG(2, "%s(): new frequency %u.%uMHz < %u.%uMHz, " - "post-updating\n", __FUNCTION__, - freqs->new / 1000, (freqs->new / 100) % 10, - freqs->old / 1000, (freqs->old / 100) % 10); - sa1100_pcmcia_update_mecr(freqs->new); - } - break; - } - - return 0; -} - -static struct notifier_block sa1100_pcmcia_notifier_block = { - .notifier_call = sa1100_pcmcia_notifier -}; -#endif - -/* sa1100_register_pcmcia() - * ^^^^^^^^^^^^^^^^^^^^^^^^ - * - * Register an SA1100 PCMCIA low level driver with the SA1100 core. - */ -int sa1100_register_pcmcia(struct pcmcia_low_level *ops, struct device *dev) -{ - struct pcmcia_init pcmcia_init; - struct pcmcia_socket_class_data *cls; - unsigned int i, cpu_clock; - int ret; - - /* - * Refuse to replace an existing driver. - */ - if (pcmcia_low_level) - return -EBUSY; - - pcmcia_low_level = ops; - - /* - * set default MECR calculation if the board specific - * code did not specify one... - */ - if (!ops->socket_get_timing) - ops->socket_get_timing = sa1100_pcmcia_default_mecr_timing; - - pcmcia_init.socket_irq[0] = NO_IRQ; - pcmcia_init.socket_irq[1] = NO_IRQ; - ret = ops->init(&pcmcia_init); - if (ret < 0) { - printk(KERN_ERR "Unable to initialize kernel PCMCIA service (%d).\n", ret); - goto out; - } - - sa1100_pcmcia_socket_count = ret; - - cpu_clock = cpufreq_get(0); - - for (i = 0; i < sa1100_pcmcia_socket_count; i++) { - struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i); - memset(skt, 0, sizeof(*skt)); - } - - /* - * We initialize the MECR to default values here, because we are - * not guaranteed to see a SetIOMap operation at runtime. - */ - for (i = 0; i < sa1100_pcmcia_socket_count; i++) { - struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i); - - skt->res.start = _PCMCIA(i); - skt->res.end = _PCMCIA(i) + PCMCIASp - 1; - skt->res.name = "PCMCIA"; - skt->res.flags = IORESOURCE_MEM; - - ret = request_resource(&iomem_resource, &skt->res); - if (ret) - goto out_err; - - skt->nr = i; - skt->ops = ops; - skt->irq = pcmcia_init.socket_irq[i]; - skt->irq_state = 0; - skt->speed_io = SA1100_PCMCIA_IO_ACCESS; - skt->speed_attr = SA1100_PCMCIA_5V_MEM_ACCESS; - skt->speed_mem = SA1100_PCMCIA_5V_MEM_ACCESS; - skt->phys_attr = _PCMCIAAttr(i); - skt->phys_mem = _PCMCIAMem(i); - skt->virt_io = ioremap(_PCMCIAIO(i), 0x10000); - - if (skt->virt_io == NULL) { - ret = -ENOMEM; - goto out_err; - } - - ops->socket_state(skt->nr, &skt->k_state); - sa1100_pcmcia_set_mecr(skt, cpu_clock); - } - - cls = kmalloc(sizeof(struct pcmcia_socket_class_data), GFP_KERNEL); - if (!cls) { - ret = -ENOMEM; - goto out_err; - } - - memset(cls, 0, sizeof(struct pcmcia_socket_class_data)); - - cls->ops = &sa1100_pcmcia_operations; - cls->nsock = sa1100_pcmcia_socket_count; - dev->class_data = cls; - - /* - * Start the event poll timer. It will reschedule by itself afterwards. - */ - sa1100_pcmcia_poll_event(0); - return 0; - - out_err: - for (i = 0; i < sa1100_pcmcia_socket_count; i++) { - struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i); - iounmap(skt->virt_io); - skt->virt_io = NULL; - if (skt->res.start) - release_resource(&skt->res); - } - - ops->shutdown(); - - out: - pcmcia_low_level = NULL; - return ret; -} -EXPORT_SYMBOL(sa1100_register_pcmcia); - -/* sa1100_unregister_pcmcia() - * ^^^^^^^^^^^^^^^^^^^^^^^^^^ - * - * Unregister a previously registered pcmcia driver - */ -void sa1100_unregister_pcmcia(struct pcmcia_low_level *ops, struct device *dev) -{ - int i; - - if (!ops) - return; - - if (ops != pcmcia_low_level) { - printk(KERN_DEBUG "PCMCIA: Trying to unregister wrong " - "low-level driver (%p != %p)", ops, - pcmcia_low_level); - return; - } - - del_timer_sync(&poll_timer); - - for (i = 0; i < sa1100_pcmcia_socket_count; i++) { - struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i); - - iounmap(skt->virt_io); - skt->virt_io = NULL; - - release_resource(&skt->res); - } - - ops->shutdown(); - - flush_scheduled_work(); - - kfree(dev->class_data); - dev->class_data = NULL; - - pcmcia_low_level = NULL; -} -EXPORT_SYMBOL(sa1100_unregister_pcmcia); - -static struct device_driver sa1100_pcmcia_driver = { - .name = "sa11x0-pcmcia", - .bus = &platform_bus_type, - .devclass = &pcmcia_socket_class, -}; - -static struct platform_device sa1100_pcmcia_device = { - .name = "sa11x0-pcmcia", - .id = 0, - .dev = { - .name = "Intel Corporation SA11x0 [PCMCIA]", - }, -}; - -struct ll_fns { - int (*init)(struct device *dev); - void (*exit)(struct device *dev); -}; - -static struct ll_fns sa1100_ll_fns[] = { +static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) = { #ifdef CONFIG_SA1100_ASSABET - { .init = pcmcia_assabet_init, .exit = pcmcia_assabet_exit, }, + pcmcia_assabet_init, #endif #ifdef CONFIG_SA1100_CERF - { .init = pcmcia_cerf_init, .exit = pcmcia_cerf_exit, }, + pcmcia_cerf_init, #endif #ifdef CONFIG_SA1100_FLEXANET - { .init = pcmcia_flexanet_init, .exit = pcmcia_flexanet_exit, }, + pcmcia_flexanet_init, #endif #ifdef CONFIG_SA1100_FREEBIRD - { .init = pcmcia_freebird_init, .exit = pcmcia_freebird_exit, }, + pcmcia_freebird_init, #endif #ifdef CONFIG_SA1100_GRAPHICSCLIENT - { .init = pcmcia_gcplus_init, .exit = pcmcia_gcplus_exit, }, + pcmcia_gcplus_init, #endif #ifdef CONFIG_SA1100_H3600 - { .init = pcmcia_h3600_init, .exit = pcmcia_h3600_exit, }, + pcmcia_h3600_init, #endif #ifdef CONFIG_SA1100_PANGOLIN - { .init = pcmcia_pangolin_init, .exit = pcmcia_pangolin_exit, }, + pcmcia_pangolin_init, #endif #ifdef CONFIG_SA1100_SHANNON - { .init = pcmcia_shannon_init, .exit = pcmcia_shannon_exit, }, + pcmcia_shannon_init, #endif #ifdef CONFIG_SA1100_SIMPAD - { .init = pcmcia_simpad_init, .exit = pcmcia_simpad_exit, }, + pcmcia_simpad_init, #endif #ifdef CONFIG_SA1100_STORK - { .init = pcmcia_stork_init, .exit = pcmcia_stork_exit, }, + pcmcia_stork_init, #endif #ifdef CONFIG_SA1100_TRIZEPS - { .init = pcmcia_trizeps_init, .exit = pcmcia_trizeps_exit, }, + pcmcia_trizeps_init, #endif #ifdef CONFIG_SA1100_YOPY - { .init = pcmcia_yopy_init, .exit = pcmcia_yopy_exit, }, + pcmcia_yopy_init, #endif }; -/* sa1100_pcmcia_init() - * ^^^^^^^^^^^^^^^^^^^^ - * - * This routine performs a basic sanity check to ensure that this - * kernel has been built with the appropriate board-specific low-level - * PCMCIA support, performs low-level PCMCIA initialization, registers - * this socket driver with Card Services, and then spawns the daemon - * thread which is the real workhorse of the socket driver. - * - * Returns: 0 on success, -1 on error - */ -static int __init sa1100_pcmcia_init(void) +static int sa11x0_drv_pcmcia_probe(struct device *dev) { - servinfo_t info; - int ret, i; - - printk(KERN_INFO "SA11x0 PCMCIA (CS release %s)\n", CS_RELEASE); - - CardServices(GetCardServicesInfo, &info); - if (info.Revision != CS_RELEASE_CODE) { - printk(KERN_ERR "Card Services release codes do not match\n"); - return -EINVAL; - } - -#ifdef CONFIG_CPU_FREQ - ret = cpufreq_register_notifier(&sa1100_pcmcia_notifier_block, - CPUFREQ_TRANSITION_NOTIFIER); - if (ret < 0) { - printk(KERN_ERR "Unable to register CPU frequency change " - "notifier (%d)\n", ret); - driver_unregister(&sa1100_pcmcia_driver); - return ret; - } -#endif - - driver_register(&sa1100_pcmcia_driver); + int i, ret = -ENODEV; /* * Initialise any "on-board" PCMCIA sockets. */ - for (i = 0; i < ARRAY_SIZE(sa1100_ll_fns); i++) { - ret = sa1100_ll_fns[i].init(&sa1100_pcmcia_device.dev); + for (i = 0; i < ARRAY_SIZE(sa11x0_pcmcia_hw_init); i++) { + ret = sa11x0_pcmcia_hw_init[i](dev); if (ret == 0) break; } - if (ret == 0) - platform_device_register(&sa1100_pcmcia_device); - - /* - * Don't fail if we don't find any on-board sockets. - */ - return 0; + return ret; } -/* sa1100_pcmcia_exit() +static struct device_driver sa11x0_pcmcia_driver = { + .probe = sa11x0_drv_pcmcia_probe, + .remove = sa11xx_drv_pcmcia_remove, + .name = "sa11x0-pcmcia", + .bus = &platform_bus_type, + .devclass = &pcmcia_socket_class, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, +}; + +static struct platform_device sa11x0_pcmcia_device = { + .name = "sa11x0-pcmcia", + .id = 0, + .dev = { + .name = "Intel Corporation SA11x0 [PCMCIA]", + }, +}; + +/* sa11x0_pcmcia_init() * ^^^^^^^^^^^^^^^^^^^^ - * Invokes the low-level kernel service to free IRQs associated with this - * socket controller and reset GPIO edge detection. + * + * This routine performs low-level PCMCIA initialization and then + * registers this socket driver with Card Services. + * + * Returns: 0 on success, -ve error code on failure */ -static void __exit sa1100_pcmcia_exit(void) +static int __init sa11x0_pcmcia_init(void) { - platform_device_unregister(&sa1100_pcmcia_device); + int ret; + ret = driver_register(&sa11x0_pcmcia_driver); + if (ret == 0) { + ret = platform_device_register(&sa11x0_pcmcia_device); + if (ret) + driver_unregister(&sa11x0_pcmcia_driver); + } -#ifdef CONFIG_CPU_FREQ - cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); -#endif + return ret; +} - driver_unregister(&sa1100_pcmcia_driver); +/* sa11x0_pcmcia_exit() + * ^^^^^^^^^^^^^^^^^^^^ + * Invokes the low-level kernel service to free IRQs associated with this + * socket controller and reset GPIO edge detection. + */ +static void __exit sa11x0_pcmcia_exit(void) +{ + platform_device_unregister(&sa11x0_pcmcia_device); + driver_unregister(&sa11x0_pcmcia_driver); } MODULE_AUTHOR("John Dorsey "); -MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-1100 Socket Controller"); +MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11x0 Socket Controller"); MODULE_LICENSE("Dual MPL/GPL"); -module_init(sa1100_pcmcia_init); -module_exit(sa1100_pcmcia_exit); +module_init(sa11x0_pcmcia_init); +module_exit(sa11x0_pcmcia_exit); diff -Nru a/drivers/pcmcia/sa1100_generic.h b/drivers/pcmcia/sa1100_generic.h --- a/drivers/pcmcia/sa1100_generic.h Wed Apr 2 22:24:06 2003 +++ b/drivers/pcmcia/sa1100_generic.h Wed Apr 2 22:24:06 2003 @@ -1,74 +1,23 @@ -/* - * linux/include/asm/arch/pcmcia.h - * - * Copyright (C) 2000 John G Dorsey - * - * This file contains definitions for the low-level SA-1100 kernel PCMCIA - * interface. Please see linux/Documentation/arm/SA1100/PCMCIA for details. - */ -#ifndef _ASM_ARCH_PCMCIA -#define _ASM_ARCH_PCMCIA +#include "sa11xx_core.h" -/* Ideally, we'd support up to MAX_SOCK sockets, but the SA-1100 only - * has support for two. This shows up in lots of hardwired ways, such - * as the fact that MECR only has enough bits to configure two sockets. - * Since it's so entrenched in the hardware, limiting the software - * in this way doesn't seem too terrible. +/* + * Declaration for all machine specific init/exit functions. */ -#define SA1100_PCMCIA_MAX_SOCK (2) - -struct pcmcia_init { - int socket_irq[SA1100_PCMCIA_MAX_SOCK]; -}; - -struct pcmcia_state { - unsigned detect: 1, - ready: 1, - bvd1: 1, - bvd2: 1, - wrprot: 1, - vs_3v: 1, - vs_Xv: 1; -}; - -struct pcmcia_configure { - unsigned vcc: 8, - vpp: 8, - output: 1, - speaker: 1, - reset: 1, - irq: 1; -}; - -struct pcmcia_low_level { - struct module *owner; - - int (*init)(struct pcmcia_init *); - int (*shutdown)(void); - void (*socket_state)(int sock, struct pcmcia_state *); - int (*configure_socket)(int sock, const struct pcmcia_configure *); - - /* - * Enable card status IRQs on (re-)initialisation. This can - * be called at initialisation, power management event, or - * pcmcia event. - */ - int (*socket_init)(int sock); - - /* - * Disable card status IRQs and PCMCIA bus on suspend. - */ - int (*socket_suspend)(int sock); - - /* - * Calculate MECR timing clock wait states - */ - unsigned int (*socket_get_timing)(unsigned int sock, - unsigned int cpu_speed, unsigned int cmd_time); -}; - -extern int sa1100_register_pcmcia(struct pcmcia_low_level *, struct device *); -extern void sa1100_unregister_pcmcia(struct pcmcia_low_level *, struct device *); -extern void sa1100_pcmcia_interrupt(int, void *, struct pt_regs *); - -#endif +extern int pcmcia_adsbitsy_init(struct device *); +extern int pcmcia_assabet_init(struct device *); +extern int pcmcia_badge4_init(struct device *); +extern int pcmcia_cerf_init(struct device *); +extern int pcmcia_flexanet_init(struct device *); +extern int pcmcia_freebird_init(struct device *); +extern int pcmcia_gcplus_init(struct device *); +extern int pcmcia_graphicsmaster_init(struct device *); +extern int pcmcia_h3600_init(struct device *); +extern int pcmcia_pangolin_init(struct device *); +extern int pcmcia_pfs168_init(struct device *); +extern int pcmcia_shannon_init(struct device *); +extern int pcmcia_simpad_init(struct device *); +extern int pcmcia_stork_init(struct device *); +extern int pcmcia_system3_init(struct device *); +extern int pcmcia_trizeps_init(struct device *); +extern int pcmcia_xp860_init(struct device *); +extern int pcmcia_yopy_init(struct device *); diff -Nru a/drivers/pcmcia/sa1100_graphicsclient.c b/drivers/pcmcia/sa1100_graphicsclient.c --- a/drivers/pcmcia/sa1100_graphicsclient.c Wed Apr 2 22:24:04 2003 +++ b/drivers/pcmcia/sa1100_graphicsclient.c Wed Apr 2 22:24:04 2003 @@ -34,126 +34,113 @@ static volatile unsigned long *PCMCIA_Power = ((volatile unsigned long *) ADS_p2v(_ADS_CS_PR)); -static int gcplus_pcmcia_init(struct pcmcia_init *init) -{ - int irq, res; - - // Reset PCMCIA - // Reset Timing for CPLD(U2) version 8001E or later - *PCMCIA_Power &= ~ ADS_CS_PR_A_RESET; - udelay(12); // 12 uSec +static struct pcmcia_irqs irqs[] = { + { 0, S0_CD_IRQ, "PCMCIA 0 CD" }, +}; - *PCMCIA_Power |= ADS_CS_PR_A_RESET; - mdelay(30); // 30 mSec +static int gcplus_pcmcia_init(struct sa1100_pcmcia_socket *skt) +{ + // Reset PCMCIA + // Reset Timing for CPLD(U2) version 8001E or later + *PCMCIA_Power &= ~ ADS_CS_PR_A_RESET; + udelay(12); // 12 uSec - // Turn off 5V - *PCMCIA_Power &= ~0x03; + *PCMCIA_Power |= ADS_CS_PR_A_RESET; + mdelay(30); // 30 mSec - /* Register interrupts */ - irq = S0_CD_IRQ; - res = request_irq(irq, sa1100_pcmcia_interrupt, SA_INTERRUPT, "PCMCIA 0 CD", NULL); - if (res < 0) { - printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n", - __FUNCTION__, irq, res); - return res; - } + // Turn off 5V + *PCMCIA_Power &= ~0x03; - init->socket_irq[0] = S0_STS_IRQ; + skt->irq = S0_STS_IRQ; - return 1; // 1 PCMCIA Slot + /* Register interrupts */ + return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int gcplus_pcmcia_shutdown(void) +static void gcplus_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt) { - /* disable IRQs */ - free_irq( S0_CD_IRQ, NULL); + /* disable IRQs */ + free_irq(S0_CD_IRQ, skt); - /* Shutdown PCMCIA power */ - mdelay(2); // 2msec - *PCMCIA_Power &= ~0x03; - - return 0; + /* Shutdown PCMCIA power */ + mdelay(2); // 2msec + *PCMCIA_Power &= ~0x03; } -static void gcplus_pcmcia_socket_state(int sock, struct pcmcia_state *state_array) +static void +gcplus_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, struct pcmcia_state *state) { - unsigned long levels = *PCMCIA_Status; + unsigned long levels = *PCMCIA_Status; - if (sock == 0) { - state->detect=(levels & ADS_CS_ST_A_CD)?1:0; - state->ready=(levels & ADS_CS_ST_A_READY)?1:0; - state->bvd1= 0; - state->bvd2= 0; - state->wrprot=0; - state->vs_3v=0; - state->vs_Xv=0; - } + state->detect=(levels & ADS_CS_ST_A_CD)?1:0; + state->ready=(levels & ADS_CS_ST_A_READY)?1:0; + state->bvd1= 0; + state->bvd2= 0; + state->wrprot=0; + state->vs_3v=0; + state->vs_Xv=0; } -static int gcplus_pcmcia_configure_socket(int sock, const struct pcmcia_configure - *configure) +static int +gcplus_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, + const socket_state_t *state) { - unsigned long flags; - - if(sock>1) return -1; + unsigned long flags; - local_irq_save(flags); + local_irq_save(flags); - switch (configure->vcc) { - case 0: - *PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER); - break; + switch (state->Vcc) { + case 0: + *PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER); + break; - case 50: - *PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER); - *PCMCIA_Power |= ADS_CS_PR_A_5V_POWER; - break; + case 50: + *PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER); + *PCMCIA_Power |= ADS_CS_PR_A_5V_POWER; + break; - case 33: - *PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER); - *PCMCIA_Power |= ADS_CS_PR_A_3V_POWER; - break; + case 33: + *PCMCIA_Power &= ~(ADS_CS_PR_A_3V_POWER | ADS_CS_PR_A_5V_POWER); + *PCMCIA_Power |= ADS_CS_PR_A_3V_POWER; + break; - default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - local_irq_restore(flags); - return -1; - } + default: + printk(KERN_ERR "%s(): unrecognized Vcc %u\n", + __FUNCTION__, state->Vcc); + local_irq_restore(flags); + return -1; + } - /* Silently ignore Vpp, output enable, speaker enable. */ + /* Silently ignore Vpp, output enable, speaker enable. */ - // Reset PCMCIA - *PCMCIA_Power &= ~ ADS_CS_PR_A_RESET; - udelay(12); + // Reset PCMCIA + *PCMCIA_Power &= ~ ADS_CS_PR_A_RESET; + udelay(12); - *PCMCIA_Power |= ADS_CS_PR_A_RESET; - mdelay(30); + *PCMCIA_Power |= ADS_CS_PR_A_RESET; + mdelay(30); - local_irq_restore(flags); + local_irq_restore(flags); - return 0; + return 0; } -static int gcplus_pcmcia_socket_init(int sock) +static void gcplus_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) { - return 0; } -static int gcplus_pcmcia_socket_suspend(int sock) +static void gcplus_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt) { - return 0; } static struct pcmcia_low_level gcplus_pcmcia_ops = { - .owner = THIS_MODULE, - .init = gcplus_pcmcia_init, - .shutdown = gcplus_pcmcia_shutdown, - .socket_state = gcplus_pcmcia_socket_state, - .configure_socket = gcplus_pcmcia_configure_socket, - - .socket_init = gcplus_pcmcia_socket_init, - .socket_suspend = gcplus_pcmcia_socket_suspend, + .owner = THIS_MODULE, + .hw_init = gcplus_pcmcia_hw_init, + .hw_shutdown = gcplus_pcmcia_hw_shutdown, + .socket_state = gcplus_pcmcia_socket_state, + .configure_socket = gcplus_pcmcia_configure_socket, + .socket_init = gcplus_pcmcia_socket_init, + .socket_suspend = gcplus_pcmcia_socket_suspend, }; int __init pcmcia_gcplus_init(struct device *dev) @@ -161,13 +148,7 @@ int ret = -ENODEV; if (machine_is_gcplus()) - ret = sa1100_register_pcmcia(&gcplus_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &gcplus_pcmcia_ops, 0, 1); return ret; } - -void __exit pcmcia_gcplus_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&gcplus_pcmcia_ops, dev); -} - diff -Nru a/drivers/pcmcia/sa1100_graphicsmaster.c b/drivers/pcmcia/sa1100_graphicsmaster.c --- a/drivers/pcmcia/sa1100_graphicsmaster.c Wed Apr 2 22:24:06 2003 +++ b/drivers/pcmcia/sa1100_graphicsmaster.c Wed Apr 2 22:24:06 2003 @@ -17,10 +17,9 @@ #include #include -#include "sa1100_generic.h" #include "sa1111_generic.h" -static int graphicsmaster_pcmcia_init(struct pcmcia_init *init) +static int graphicsmaster_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) { int return_val=0; @@ -33,65 +32,67 @@ /* why? */ MECR = 0x09430943; - return sa1111_pcmcia_init(init); + return sa1111_pcmcia_hwinit(skt); } static int -graphicsmaster_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) +graphicsmaster_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, + const socket_state_t *state) { - unsigned int pa_dwr_mask, pa_dwr_set; - int ret; + unsigned int pa_dwr_mask, pa_dwr_set; + int ret; - switch (sock) { - case 0: - pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1; - - switch (conf->vcc) { - default: - case 0: pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1; break; - case 33: pa_dwr_set = GPIO_GPIO1; break; - case 50: pa_dwr_set = GPIO_GPIO0; break; - } - break; - - case 1: - pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3; - - switch (conf->vcc) { - default: - case 0: pa_dwr_set = GPIO_GPIO2 | GPIO_GPIO3; break; - case 33: pa_dwr_set = GPIO_GPIO3; break; - case 50: pa_dwr_set = GPIO_GPIO2; break; - } - } - - if (conf->vpp != conf->vcc && conf->vpp != 0) { - printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__, - conf->vpp); - return -1; - } - - ret = sa1111_pcmcia_configure_socket(sock, conf); - if (ret == 0) { - unsigned long flags; - - local_irq_save(flags); - PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set; - local_irq_restore(flags); - } + switch (skt->nr) { + case 0: + pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1; + + switch (state->Vcc) { + default: + case 0: pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1; break; + case 33: pa_dwr_set = GPIO_GPIO1; break; + case 50: pa_dwr_set = GPIO_GPIO0; break; + } + break; + + case 1: + pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3; + + switch (state->Vcc) { + default: + case 0: pa_dwr_set = GPIO_GPIO2 | GPIO_GPIO3; break; + case 33: pa_dwr_set = GPIO_GPIO3; break; + case 50: pa_dwr_set = GPIO_GPIO2; break; + } + break; + } + + if (state->Vpp != state->Vcc && state->Vpp != 0) { + printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", + __FUNCTION__, state->Vpp); + return -1; + } + + ret = sa1111_pcmcia_configure_socket(skt, state); + if (ret == 0) { + unsigned long flags; + + local_irq_save(flags); + PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set; + local_irq_restore(flags); + } - return ret; + return ret; } static struct pcmcia_low_level graphicsmaster_pcmcia_ops = { - .owner = THIS_MODULE, - .init = graphicsmaster_pcmcia_init, - .shutdown = sa1111_pcmcia_shutdown, - .socket_state = sa1111_pcmcia_socket_state, - .configure_socket = graphicsmaster_pcmcia_configure_socket, + .owner = THIS_MODULE, + .hw_init = graphicsmaster_pcmcia_init, + .hw_shutdown = sa1111_pcmcia_hw_shutdown, + .socket_state = sa1111_pcmcia_socket_state, + .configure_socket = graphicsmaster_pcmcia_configure_socket, - .socket_init = sa1111_pcmcia_socket_init, - .socket_suspend = sa1111_pcmcia_socket_suspend, + .socket_init = sa1111_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, }; int __init pcmcia_graphicsmaster_init(struct device *dev) @@ -99,13 +100,7 @@ int ret = -ENODEV; if (machine_is_graphicsmaster()) - ret = sa1100_register_pcmcia(&graphicsmaster_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &graphicsmaster_pcmcia_ops, 0, 2); return ret; } - -void __exit pcmcia_graphicsmaster_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&graphicsmaster_pcmcia_ops, dev); -} - diff -Nru a/drivers/pcmcia/sa1100_h3600.c b/drivers/pcmcia/sa1100_h3600.c --- a/drivers/pcmcia/sa1100_h3600.c Wed Apr 2 22:24:06 2003 +++ b/drivers/pcmcia/sa1100_h3600.c Wed Apr 2 22:24:06 2003 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -17,65 +18,36 @@ #include "sa1100_generic.h" -static struct irqs { - int irq; - const char *str; -} irqs[] = { - { IRQ_GPIO_H3600_PCMCIA_CD0, "PCMCIA CD0" }, - { IRQ_GPIO_H3600_PCMCIA_CD1, "PCMCIA CD1" } +static struct pcmcia_irqs irqs[] = { + { 0, IRQ_GPIO_H3600_PCMCIA_CD0, "PCMCIA CD0" }, + { 1, IRQ_GPIO_H3600_PCMCIA_CD1, "PCMCIA CD1" } }; -static int h3600_pcmcia_init(struct pcmcia_init *init) +static int h3600_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) { - int i, res; + skt->irq = skt->nr ? IRQ_GPIO_H3600_PCMCIA_IRQ1 + : IRQ_GPIO_H3600_PCMCIA_IRQ0; - /* - * Register interrupts - */ - for (i = res = 0; i < ARRAY_SIZE(irqs); i++) { - res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt, - SA_INTERRUPT, irqs[i].str, NULL); - if (res) - break; - } - - if (res) { - printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n", - __FUNCTION__, irqs[i].irq, res); - while (i--) - free_irq(irqs[i].irq, NULL); - } - - init->socket_irq[0] = IRQ_GPIO_H3600_PCMCIA_IRQ0; - init->socket_irq[1] = IRQ_GPIO_H3600_PCMCIA_IRQ1; - - return res ? res : 2; + return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int h3600_pcmcia_shutdown(void) +static void h3600_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt) { - int i; - - /* - * disable IRQs - */ - for (i = 0; i < ARRAY_SIZE(irqs); i++) - free_irq(irqs[i].irq, NULL); + sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); /* Disable CF bus: */ clr_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON); clr_h3600_egpio(IPAQ_EGPIO_OPT_ON); set_h3600_egpio(IPAQ_EGPIO_OPT_RESET); - - return 0; } -static void h3600_pcmcia_socket_state(int sock, struct pcmcia_state *state) +static void +h3600_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, struct pcmcia_state *state) { unsigned long levels = GPLR; - switch (sock) { + switch (skt->nr) { case 0: state->detect = levels & GPIO_H3600_PCMCIA_CD0 ? 0 : 1; state->ready = levels & GPIO_H3600_PCMCIA_IRQ0 ? 1 : 0; @@ -99,18 +71,15 @@ } static int -h3600_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) +h3600_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, const socket_state_t *state) { - if (sock > 1) - return -1; - - if (conf->vcc != 0 && conf->vcc != 33 && conf->vcc != 50) { + if (state->Vcc != 0 && state->Vcc != 33 && state->Vcc != 50) { printk(KERN_ERR "h3600_pcmcia: unrecognized Vcc %u.%uV\n", - conf->vcc / 10, conf->vcc % 10); + state->Vcc / 10, state->Vcc % 10); return -1; } - if (conf->reset) + if (state->flags & SS_RESET) set_h3600_egpio(IPAQ_EGPIO_CARD_RESET); else clr_h3600_egpio(IPAQ_EGPIO_CARD_RESET); @@ -120,7 +89,7 @@ return 0; } -static int h3600_pcmcia_socket_init(int sock) +static void h3600_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) { /* Enable CF bus: */ set_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON); @@ -130,28 +99,12 @@ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(10*HZ / 1000); - switch (sock) { - case 0: - set_irq_type(IRQ_GPIO_H3600_PCMCIA_CD0, IRQT_BOTHEDGE); - break; - case 1: - set_irq_type(IRQ_GPIO_H3600_PCMCIA_CD1, IRQT_BOTHEDGE); - break; - } - - return 0; + sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int h3600_pcmcia_socket_suspend(int sock) +static void h3600_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt) { - switch (sock) { - case 0: - set_irq_type(IRQ_GPIO_H3600_PCMCIA_CD0, IRQT_NOEDGE); - break; - case 1: - set_irq_type(IRQ_GPIO_H3600_PCMCIA_CD1, IRQT_NOEDGE); - break; - } + sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); /* * FIXME: This doesn't fit well. We don't have the mechanism in @@ -159,20 +112,18 @@ * on one bus. We rely on the cs.c behaviour shutting down * socket 0 then socket 1. */ - if (sock == 1) { + if (skt->nr == 1) { clr_h3600_egpio(IPAQ_EGPIO_OPT_ON); clr_h3600_egpio(IPAQ_EGPIO_OPT_NVRAM_ON); /* hmm, does this suck power? */ set_h3600_egpio(IPAQ_EGPIO_OPT_RESET); } - - return 0; } struct pcmcia_low_level h3600_pcmcia_ops = { .owner = THIS_MODULE, - .init = h3600_pcmcia_init, - .shutdown = h3600_pcmcia_shutdown, + .hw_init = h3600_pcmcia_hw_init, + .hw_shutdown = h3600_pcmcia_hw_shutdown, .socket_state = h3600_pcmcia_socket_state, .configure_socket = h3600_pcmcia_configure_socket, @@ -185,12 +136,7 @@ int ret = -ENODEV; if (machine_is_h3600()) - ret = sa1100_register_pcmcia(&h3600_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &h3600_pcmcia_ops, 0, 2); return ret; -} - -void __exit pcmcia_h3600_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&h3600_pcmcia_ops, dev); } diff -Nru a/drivers/pcmcia/sa1100_jornada720.c b/drivers/pcmcia/sa1100_jornada720.c --- a/drivers/pcmcia/sa1100_jornada720.c Wed Apr 2 22:24:05 2003 +++ b/drivers/pcmcia/sa1100_jornada720.c Wed Apr 2 22:24:05 2003 @@ -15,7 +15,6 @@ #include #include -#include "sa1100_generic.h" #include "sa1111_generic.h" #define SOCKET0_POWER GPIO_GPIO0 @@ -24,7 +23,7 @@ #warning *** Does SOCKET1_3V actually do anything? #define SOCKET1_3V GPIO_GPIO3 -static int jornada720_pcmcia_init(struct pcmcia_init *init) +static int jornada720_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) { /* * What is all this crap for? @@ -46,23 +45,23 @@ PC_SDR = 0; PC_SSR = 0; - return sa1111_pcmcia_init(init); + return sa1111_pcmcia_hw_init(skt); } static int -jornada720_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) +jornada720_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, const socket_state_t *state) { unsigned int pa_dwr_mask, pa_dwr_set; int ret; printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__, - sock, conf->vcc, conf->vpp); + skt->nr, state->Vcc, state->Vpp); - switch (sock) { + switch (skt->nr) { case 0: pa_dwr_mask = SOCKET0_POWER | SOCKET0_3V; - switch (conf->vcc) { + switch (state->Vcc) { default: case 0: pa_dwr_set = 0; break; case 33: pa_dwr_set = SOCKET0_POWER | SOCKET0_3V; break; @@ -73,7 +72,7 @@ case 1: pa_dwr_mask = SOCKET1_POWER; - switch (conf->vcc) { + switch (state->Vcc) { default: case 0: pa_dwr_set = 0; break; case 33: pa_dwr_set = SOCKET1_POWER; break; @@ -85,13 +84,13 @@ return -1; } - if (conf->vpp != conf->vcc && conf->vpp != 0) { + if (state->Vpp != state->Vcc && state->Vpp != 0) { printk(KERN_ERR "%s(): slot cannot support VPP %u\n", - __FUNCTION__, conf->vpp); + __FUNCTION__, state->Vpp); return -1; } - ret = sa1111_pcmcia_configure_socket(sock, conf); + ret = sa1111_pcmcia_configure_socket(skt, state); if (ret == 0) { unsigned long flags; @@ -105,8 +104,8 @@ static struct pcmcia_low_level jornada720_pcmcia_ops = { .owner = THIS_MODULE, - .init = jornada720_pcmcia_init, - .shutdown = sa1111_pcmcia_shutdown, + .hw_init = jornada720_pcmcia_hw_init, + .hw_shutdown = sa1111_pcmcia_hw_shutdown, .socket_state = sa1111_pcmcia_socket_state, .configure_socket = jornada720_pcmcia_configure_socket, @@ -119,12 +118,7 @@ int ret = -ENODEV; if (machine_is_jornada720()) - ret = sa1100_register_pcmcia(&jornada720_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &jornada720_pcmcia_ops, 0, 2); return ret; -} - -void __devexit pcmcia_jornada720_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&jornada720_pcmcia_ops, dev); } diff -Nru a/drivers/pcmcia/sa1100_neponset.c b/drivers/pcmcia/sa1100_neponset.c --- a/drivers/pcmcia/sa1100_neponset.c Wed Apr 2 22:24:07 2003 +++ b/drivers/pcmcia/sa1100_neponset.c Wed Apr 2 22:24:07 2003 @@ -15,7 +15,6 @@ #include #include -#include "sa1100_generic.h" #include "sa1111_generic.h" /* @@ -42,52 +41,27 @@ * the corresponding truth table. */ -static int neponset_pcmcia_init(struct pcmcia_init *init) -{ - NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP); - - /* - * Set GPIO_A<3:0> to be outputs for the MAX1600, - * and switch to standby mode. - */ - PA_DDR = 0; - PA_SDR = 0; - PA_DWR = 0; - PA_SSR = 0; - - return sa1111_pcmcia_init(init); -} - static int -neponset_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) +neponset_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, const socket_state_t *state) { - unsigned int ncr_mask, pa_dwr_mask; - unsigned int ncr_set, pa_dwr_set; + unsigned int ncr_mask, ncr_set, pa_dwr_mask, pa_dwr_set; int ret; - switch (sock) { + switch (skt->nr) { case 0: pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1; ncr_mask = NCR_A0VPP | NCR_A1VPP; - switch (conf->vcc) { - default: - case 0: pa_dwr_set = 0; break; - case 33: pa_dwr_set = GPIO_GPIO1; break; - case 50: pa_dwr_set = GPIO_GPIO0; break; - } - - switch (conf->vpp) { - case 0: ncr_set = 0; break; - case 120: ncr_set = NCR_A1VPP; break; - default: - if (conf->vpp == conf->vcc) - ncr_set = NCR_A0VPP; - else { - printk(KERN_ERR "%s(): unrecognized VPP %u\n", - __FUNCTION__, conf->vpp); - return -1; - } + if (state->Vpp == 0) + ncr_set = 0; + else if (state->Vpp == 120) + ncr_set = NCR_A1VPP; + else if (state->Vpp == state->Vcc) + ncr_set = NCR_A0VPP; + else { + printk(KERN_ERR "%s(): unrecognized VPP %u\n", + __FUNCTION__, state->Vpp); + return -1; } break; @@ -96,16 +70,9 @@ ncr_mask = 0; ncr_set = 0; - switch (conf->vcc) { - default: - case 0: pa_dwr_set = 0; break; - case 33: pa_dwr_set = GPIO_GPIO2; break; - case 50: pa_dwr_set = GPIO_GPIO3; break; - } - - if (conf->vpp != conf->vcc && conf->vpp != 0) { + if (state->Vpp != state->Vcc && state->Vpp != 0) { printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n", - __FUNCTION__, conf->vpp); + __FUNCTION__, state->Vpp); return -1; } break; @@ -114,41 +81,64 @@ return -1; } - ret = sa1111_pcmcia_configure_socket(sock, conf); + /* + * pa_dwr_set is the mask for selecting Vcc on both sockets. + * pa_dwr_mask selects which bits (and therefore socket) we change. + */ + switch (state->Vcc) { + default: + case 0: pa_dwr_set = 0; break; + case 33: pa_dwr_set = GPIO_GPIO1|GPIO_GPIO2; break; + case 50: pa_dwr_set = GPIO_GPIO0|GPIO_GPIO3; break; + } + + ret = sa1111_pcmcia_configure_socket(skt, state); if (ret == 0) { unsigned long flags; local_irq_save(flags); NCR_0 = (NCR_0 & ~ncr_mask) | ncr_set; - PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set; + + PA_DWR = (PA_DWR & ~pa_dwr_mask) | (pa_dwr_set & pa_dwr_mask); local_irq_restore(flags); } return 0; } -static struct pcmcia_low_level neponset_pcmcia_ops = { - .owner = THIS_MODULE, - .init = neponset_pcmcia_init, - .shutdown = sa1111_pcmcia_shutdown, - .socket_state = sa1111_pcmcia_socket_state, - .configure_socket = neponset_pcmcia_configure_socket, +static void neponset_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) +{ + if (skt->nr == 0) + NCR_0 &= ~(NCR_A0VPP | NCR_A1VPP); - .socket_init = sa1111_pcmcia_socket_init, - .socket_suspend = sa1111_pcmcia_socket_suspend, + sa1111_pcmcia_socket_init(skt); +} + +static struct pcmcia_low_level neponset_pcmcia_ops = { + .owner = THIS_MODULE, + .hw_init = sa1111_pcmcia_hw_init, + .hw_shutdown = sa1111_pcmcia_hw_shutdown, + .socket_state = sa1111_pcmcia_socket_state, + .configure_socket = neponset_pcmcia_configure_socket, + .socket_init = neponset_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, }; int __init pcmcia_neponset_init(struct device *dev) { - int ret = -ENODEV; + int ret = -ENODEV; - if (machine_is_assabet()) - ret = sa1100_register_pcmcia(&neponset_pcmcia_ops, dev); + if (machine_is_assabet()) { + /* + * Set GPIO_A<3:0> to be outputs for the MAX1600, + * and switch to standby mode. + */ + PA_DDR = 0; + PA_DWR = 0; + PA_SDR = 0; + PA_SSR = 0; + ret = sa11xx_drv_pcmcia_probe(dev, &neponset_pcmcia_ops, 0, 2); + } return ret; -} - -void __devexit pcmcia_neponset_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&neponset_pcmcia_ops, dev); } diff -Nru a/drivers/pcmcia/sa1100_pangolin.c b/drivers/pcmcia/sa1100_pangolin.c --- a/drivers/pcmcia/sa1100_pangolin.c Wed Apr 2 22:24:04 2003 +++ b/drivers/pcmcia/sa1100_pangolin.c Wed Apr 2 22:24:04 2003 @@ -22,134 +22,118 @@ #define PANGOLIN_SOCK 0 #endif -static int pangolin_pcmcia_init(struct pcmcia_init *init){ - int res; +static struct pcmcia_irqs irqs[] = { + { PANGOLIN_SOCK, IRQ_PCMCIA_CD, "PCMCIA CD" }, +}; + +static int pangolin_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) +{ + int res; #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE - /* Enable PCMCIA bus: */ - GPCR = GPIO_PCMCIA_BUS_ON; + /* Enable PCMCIA bus: */ + GPCR = GPIO_PCMCIA_BUS_ON; #endif - init->socket_irq[PANGOLIN_SOCK] = IRQ_PCMCIA_IRQ; - - /* Set transition detect */ - set_irq_type(IRQ_PCMCIA_CD, IRQT_NOEDGE); - set_irq_type(IRQ_PCMCIA_IRQ, IRQT_FALLING); + skt->irq = IRQ_PCMCIA_IRQ; - /* Register interrupts */ - res = request_irq(IRQ_PCMCIA_CD, sa1100_pcmcia_interrupt, SA_INTERRUPT, - "PCMCIA_CD", NULL); - if (res >= 0) - /* There's only one slot, but it's "Slot 1": */ - return 2; - -irq_err: - printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n", - __FUNCTION__, IRQ_PCMCIA_CD, res); - - return res; + return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int pangolin_pcmcia_shutdown(void) +static void pangolin_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt) { - /* disable IRQs */ - free_irq(IRQ_PCMCIA_CD, NULL); + sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); + #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE - /* Disable PCMCIA bus: */ - GPSR = GPIO_PCMCIA_BUS_ON; + /* Disable PCMCIA bus: */ + GPSR = GPIO_PCMCIA_BUS_ON; #endif - return 0; } -static void pangolin_pcmcia_socket_state(int sock, struct pcmcia_state *state) +static void +pangolin_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, + struct pcmcia_state *state) { - unsigned long levels = GPLR;; + unsigned long levels = GPLR;; - if (sock == PANGOLIN_SOCK) { - state->detect=((levels & GPIO_PCMCIA_CD)==0)?1:0; - state->ready=(levels & GPIO_PCMCIA_IRQ)?1:0; - state->bvd1=1; /* Not available on Pangolin. */ - state->bvd2=1; /* Not available on Pangolin. */ - state->wrprot=0; /* Not available on Pangolin. */ - state->vs_3v=1; /* Can only apply 3.3V on Pangolin. */ - state->vs_Xv=0; - } + state->detect=((levels & GPIO_PCMCIA_CD)==0)?1:0; + state->ready=(levels & GPIO_PCMCIA_IRQ)?1:0; + state->bvd1=1; /* Not available on Pangolin. */ + state->bvd2=1; /* Not available on Pangolin. */ + state->wrprot=0; /* Not available on Pangolin. */ + state->vs_3v=1; /* Can only apply 3.3V on Pangolin. */ + state->vs_Xv=0; } -static int pangolin_pcmcia_configure_socket(int sock, const struct pcmcia_configure - *configure) +static int +pangolin_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, + const socket_state_t *state) { - unsigned long value, flags; + unsigned long value, flags; - if(sock>1) return -1; -#ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE - if(sock==0) return 0; -#endif - local_irq_save(flags); + local_irq_save(flags); - /* Murphy: BUS_ON different from POWER ? */ + /* Murphy: BUS_ON different from POWER ? */ - switch(configure->vcc){ - case 0: - break; + switch (state->Vcc) { + case 0: + break; #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE - case 50: - printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n", - __FUNCTION__); - case 33: /* Can only apply 3.3V to the CF slot. */ - break; + case 50: + printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n", + __FUNCTION__); + case 33: /* Can only apply 3.3V to the CF slot. */ + break; #else - case 50: - printk(KERN_WARNING "%s(): CS asked for 5V, determinded by jumper setting...\n", __FUNCTION__); - break; - case 33: - printk(KERN_WARNING "%s(): CS asked for 3.3V, determined by jumper setting...\n", __FUNCTION__); - break; + case 50: + printk(KERN_WARNING "%s(): CS asked for 5V, determinded by " + "jumper setting...\n", __FUNCTION__); + break; + case 33: + printk(KERN_WARNING "%s(): CS asked for 3.3V, determined by " + "jumper setting...\n", __FUNCTION__); + break; #endif - default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - local_irq_restore(flags); - return -1; - } + default: + printk(KERN_ERR "%s(): unrecognized Vcc %u\n", + __FUNCTION__, state->Vcc); + local_irq_restore(flags); + return -1; + } #ifdef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE - /* reset & unreset request */ - if(sock==0) { - if(configure->reset) { - GPSR |= GPIO_PCMCIA_RESET; - } else { - GPCR |= GPIO_PCMCIA_RESET; + /* reset & unreset request */ + if (skt->nr == 0) { + if (state->flags & SS_RESET) { + GPSR = GPIO_PCMCIA_RESET; + } else { + GPCR = GPIO_PCMCIA_RESET; + } } - } #endif - /* Silently ignore Vpp, output enable, speaker enable. */ - local_irq_restore(flags); - return 0; + /* Silently ignore Vpp, output enable, speaker enable. */ + local_irq_restore(flags); + return 0; } -static int pangolin_pcmcia_socket_init(int sock) +static void pangolin_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) { - if (sock == 1) - set_irq_type(IRQ_PCMCIA_CD, IRQT_BOTHEDGE); - return 0; + sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int pangolin_pcmcia_socket_suspend(int sock) +static void pangolin_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt) { - if (sock == 1) - set_irq_type(IRQ_PCMCIA_CD, IRQT_NOEDGE); - return 0; + sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } static struct pcmcia_low_level pangolin_pcmcia_ops = { - .owner = THIS_MODULE, - .init = pangolin_pcmcia_init, - .shutdown = pangolin_pcmcia_shutdown, - .socket_state = pangolin_pcmcia_socket_state, - .configure_socket = pangolin_pcmcia_configure_socket, + .owner = THIS_MODULE, + .hw_init = pangolin_pcmcia_hw_init, + .hw_shutdown = pangolin_pcmcia_hw_shutdown, + .socket_state = pangolin_pcmcia_socket_state, + .configure_socket = pangolin_pcmcia_configure_socket, - .socket_init = pangolin_pcmcia_socket_init, - .socket_suspend = pangolin_pcmcia_socket_suspend, + .socket_init = pangolin_pcmcia_socket_init, + .socket_suspend = pangolin_pcmcia_socket_suspend, }; int __init pcmcia_pangolin_init(struct device *dev) @@ -157,13 +141,7 @@ int ret = -ENODEV; if (machine_is_pangolin()) - ret = sa1100_register_pcmcia(&pangolin_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &pangolin_pcmcia_ops, PANGOLIN_SOCK, 1); return ret; } - -void __exit pcmcia_pangolin_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&pangolin_pcmcia_ops, dev); -} - diff -Nru a/drivers/pcmcia/sa1100_pfs168.c b/drivers/pcmcia/sa1100_pfs168.c --- a/drivers/pcmcia/sa1100_pfs168.c Wed Apr 2 22:24:05 2003 +++ b/drivers/pcmcia/sa1100_pfs168.c Wed Apr 2 22:24:05 2003 @@ -16,10 +16,9 @@ #include #include -#include "sa1100_generic.h" #include "sa1111_generic.h" -static int pfs168_pcmcia_init(struct pcmcia_init *init) +static int pfs168_pcmcia_init(struct sa1100_pcmcia_socket *skt) { /* TPS2211 to standby mode: */ PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); @@ -27,11 +26,12 @@ /* Set GPIO_A<3:0> to be outputs for PCMCIA (socket 0) power controller: */ PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); - return sa1111_pcmcia_init(init); + return sa1111_pcmcia_init(skt); } static int -pfs168_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) +pfs168_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, + const socket_state_t *state) { unsigned int pa_dwr_mask = 0, pa_dwr_set = 0; int ret; @@ -48,33 +48,33 @@ * */ - switch (sock) { + switch (skt->nr) { case 0: pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3; - switch (conf->vcc) { + switch (state->Vcc) { default: case 0: pa_dwr_set = 0; break; case 33: pa_dwr_set = GPIO_GPIO0; break; case 50: pa_dwr_set = GPIO_GPIO1; break; } - switch (conf->vpp) { + switch (state->Vpp) { case 0: break; case 120: printk(KERN_ERR "%s(): PFS-168 does not support VPP %uV\n", - __FUNCTION__, conf->vpp / 10); + __FUNCTION__, state->Vpp / 10); return -1; break; default: - if (conf->vpp == conf->vcc) + if (state->Vpp == state->Vcc) pa_dwr_set |= GPIO_GPIO3; else { printk(KERN_ERR "%s(): unrecognized VPP %u\n", __FUNCTION__, - conf->vpp); + state->Vpp); return -1; } } @@ -91,24 +91,24 @@ case 50: printk(KERN_ERR "%s(): PFS-168 CompactFlash socket does not support VCC %uV\n", - __FUNCTION__, conf->vcc / 10); + __FUNCTION__, state->Vcc / 10); return -1; default: printk(KERN_ERR "%s(): unrecognized VCC %u\n", __FUNCTION__, - conf->vcc); + state->Vcc); return -1; } - if (conf->vpp != conf->vcc && conf->vpp != 0) { + if (state->Vpp != state->Vcc && state->Vpp != 0) { printk(KERN_ERR "%s(): CompactFlash socket does not support VPP %uV\n" - __FUNCTION__, conf->vpp / 10); + __FUNCTION__, state->Vpp / 10); return -1; } break; } - ret = sa1111_pcmcia_configure_socket(sock, conf); + ret = sa1111_pcmcia_configure_socket(skt, state); if (ret == 0) { unsigned long flags; @@ -121,14 +121,13 @@ } static struct pcmcia_low_level pfs168_pcmcia_ops = { - .owner = THIS_MODULE, - .init = pfs168_pcmcia_init, - .shutdown = sa1111_pcmcia_shutdown, - .socket_state = sa1111_pcmcia_socket_state, - .configure_socket = pfs168_pcmcia_configure_socket, - - .socket_init = sa1111_pcmcia_socket_init, - .socket_suspend = sa1111_pcmcia_socket_suspend, + .owner = THIS_MODULE, + .hw_init = pfs168_pcmcia_hw_init, + .hw_shutdown = sa1111_pcmcia_hw_shutdown, + .socket_state = sa1111_pcmcia_socket_state, + .configure_socket = pfs168_pcmcia_configure_socket, + .socket_init = sa1111_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, }; int __init pcmcia_pfs168_init(struct device *dev) @@ -136,12 +135,7 @@ int ret = -ENODEV; if (machine_is_pfs168()) - ret = sa1100_register_pcmcia(&pfs168_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &pfs168_pcmcia_ops, 0, 2); return ret; -} - -void __exit pcmcia_pfs168_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&pfs168_pcmcia_ops, dev); } diff -Nru a/drivers/pcmcia/sa1100_shannon.c b/drivers/pcmcia/sa1100_shannon.c --- a/drivers/pcmcia/sa1100_shannon.c Wed Apr 2 22:24:07 2003 +++ b/drivers/pcmcia/sa1100_shannon.c Wed Apr 2 22:24:07 2003 @@ -16,64 +16,36 @@ #include #include "sa1100_generic.h" -static struct irqs { - int irq; - const char *str; -} irqs[] = { - { SHANNON_IRQ_GPIO_EJECT_0, "PCMCIA_CD_0" }, - { SHANNON_IRQ_GPIO_EJECT_1, "PCMCIA_CD_1" }, +static struct pcmcia_irqs irqs[] = { + { 0, SHANNON_IRQ_GPIO_EJECT_0, "PCMCIA_CD_0" }, + { 1, SHANNON_IRQ_GPIO_EJECT_1, "PCMCIA_CD_1" }, }; -static int shannon_pcmcia_init(struct pcmcia_init *init) +static int shannon_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) { - int i, res; - /* All those are inputs */ GPDR &= ~(SHANNON_GPIO_EJECT_0 | SHANNON_GPIO_EJECT_1 | SHANNON_GPIO_RDY_0 | SHANNON_GPIO_RDY_1); GAFR &= ~(SHANNON_GPIO_EJECT_0 | SHANNON_GPIO_EJECT_1 | SHANNON_GPIO_RDY_0 | SHANNON_GPIO_RDY_1); - init->socket_irq[0] = SHANNON_IRQ_GPIO_RDY_0; - init->socket_irq[1] = SHANNON_IRQ_GPIO_RDY_1; - - /* Register interrupts */ - for (i = 0; i < ARRAY_SIZE(irqs); i++) { - res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt, - SA_INTERRUPT, irqs[i].str, NULL); - if (res) - goto irq_err; - set_irq_type(irqs[i].irq, IRQT_NOEDGE); - } - - return 2; + skt->irq = skt->nr ? SHANNON_IRQ_GPIO_RDY_1 : SHANNON_IRQ_GPIO_RDY_0; - irq_err: - printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n", - __FUNCTION__, irqs[i].irq, res); - - while (i--) - free_irq(irqs[i].irq, NULL); - - return res; + return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int shannon_pcmcia_shutdown(void) +static void shannon_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt) { - int i; - - /* disable IRQs */ - for (i = 0; i < ARRAY_SIZE(irqs); i++) - free_irq(irqs[i].irq, NULL); - - return 0; + sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static void shannon_pcmcia_socket_state(int sock, struct pcmcia_state *state) +static void +shannon_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, + struct pcmcia_state *state) { unsigned long levels = GPLR; - switch (sock) { + switch (skt->nr) { case 0: state->detect = (levels & SHANNON_GPIO_EJECT_0) ? 0 : 1; state->ready = (levels & SHANNON_GPIO_RDY_0) ? 1 : 0; @@ -96,9 +68,11 @@ } } -static int shannon_pcmcia_configure_socket(int sock, const struct pcmcia_configure *configure) +static int +shannon_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, + const socket_state_t *state) { - switch (configure->vcc) { + switch (state->Vcc) { case 0: /* power off */ printk(KERN_WARNING __FUNCTION__"(): CS asked for 0V, still applying 3.3V..\n"); break; @@ -108,7 +82,7 @@ break; default: printk(KERN_ERR __FUNCTION__"(): unrecognized Vcc %u\n", - configure->vcc); + state->Vcc); return -1; } @@ -119,30 +93,20 @@ return 0; } -static int shannon_pcmcia_socket_init(int sock) +static void shannon_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) { - if (sock == 0) - set_irq_type(SHANNON_IRQ_GPIO_EJECT_0, IRQT_BOTHEDGE); - else if (sock == 1) - set_irq_Type(SHANNON_IRQ_GPIO_EJECT_1, IRQT_BOTHEDGE); - - return 0; + sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int shannon_pcmcia_socket_suspend(int sock) +static void shannon_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt) { - if (sock == 0) - set_irq_type(SHANNON_IRQ_GPIO_EJECT_0, IRQT_NOEDGE); - else if (sock == 1) - set_irq_type(SHANNON_IRQ_GPIO_EJECT_1, IRQT_NOEDGE); - - return 0; + sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } static struct pcmcia_low_level shannon_pcmcia_ops = { .owner = THIS_MODULE, - .init = shannon_pcmcia_init, - .shutdown = shannon_pcmcia_shutdown, + .hw_init = shannon_pcmcia_hw_init, + .hw_shutdown = shannon_pcmcia_hw_shutdown, .socket_state = shannon_pcmcia_socket_state, .configure_socket = shannon_pcmcia_configure_socket, @@ -155,12 +119,7 @@ int ret = -ENODEV; if (machine_is_shannon()) - ret = sa1100_register_pcmcia(&shannon_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &shannon_pcmcia_ops, 0, 2); return ret; -} - -void __exit pcmcia_shannon_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&shannon_pcmcia_ops, dev); } diff -Nru a/drivers/pcmcia/sa1100_simpad.c b/drivers/pcmcia/sa1100_simpad.c --- a/drivers/pcmcia/sa1100_simpad.c Wed Apr 2 22:24:07 2003 +++ b/drivers/pcmcia/sa1100_simpad.c Wed Apr 2 22:24:07 2003 @@ -19,134 +19,110 @@ extern void set_cs3_bit(int value); extern void clear_cs3_bit(int value); +static struct pcmcia_irqs irqs[] = { + { 1, IRQ_GPIO_CF_CD, "CF_CD" }, +}; -static int simpad_pcmcia_init(struct pcmcia_init *init){ - int irq, res; - - set_cs3_bit(PCMCIA_RESET); - clear_cs3_bit(PCMCIA_BUFF_DIS); - clear_cs3_bit(PCMCIA_RESET); - - clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1); - - init->socket_irq[1] = IRQ_GPIO_CF_IRQ; - - /* Register interrupts */ - irq = IRQ_GPIO_CF_CD; - res = request_irq(irq, sa1100_pcmcia_interrupt, SA_INTERRUPT, - "CF_CD", NULL ); - if( res < 0 ) goto irq_err; +static int simpad_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) +{ + set_cs3_bit(PCMCIA_RESET); + clear_cs3_bit(PCMCIA_BUFF_DIS); + clear_cs3_bit(PCMCIA_RESET); - set_irq_type( IRQ_GPIO_CF_CD, IRQT_NOEDGE ); + clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1); - /* There's only one slot, but it's "Slot 1": */ - return 2; + skt->irq = IRQ_GPIO_CF_IRQ; -irq_err: - printk( KERN_ERR "%s: request for IRQ%d failed (%d)\n", - __FUNCTION__, irq, res); - return res; + return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int simpad_pcmcia_shutdown(void) +static void simpad_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt) { - /* disable IRQs */ - free_irq( IRQ_GPIO_CF_CD, NULL ); - - /* Disable CF bus: */ - - //set_cs3_bit(PCMCIA_BUFF_DIS); - clear_cs3_bit(PCMCIA_RESET); - - return 0; + sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); + + /* Disable CF bus: */ + //set_cs3_bit(PCMCIA_BUFF_DIS); + clear_cs3_bit(PCMCIA_RESET); } -static void simpad_pcmcia_socket_state(int sock, struct pcmcia_state *state) +static void +simpad_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, + struct pcmcia_state *state) { - if (sock == 1) { - unsigned long levels = GPLR; - unsigned long *cs3reg = CS3_BASE; + unsigned long levels = GPLR; + unsigned long *cs3reg = CS3_BASE; - state->detect=((levels & GPIO_CF_CD)==0)?1:0; - state->ready=(levels & GPIO_CF_IRQ)?1:0; - state->bvd1=1; /* Not available on Simpad. */ - state->bvd2=1; /* Not available on Simpad. */ - state->wrprot=0; /* Not available on Simpad. */ + state->detect=((levels & GPIO_CF_CD)==0)?1:0; + state->ready=(levels & GPIO_CF_IRQ)?1:0; + state->bvd1=1; /* Not available on Simpad. */ + state->bvd2=1; /* Not available on Simpad. */ + state->wrprot=0; /* Not available on Simpad. */ - if((*cs3reg & 0x0c) == 0x0c) { - state->vs_3v=0; - state->vs_Xv=0; - } else { - state->vs_3v=1; - state->vs_Xv=0; - } - } + if((*cs3reg & 0x0c) == 0x0c) { + state->vs_3v=0; + state->vs_Xv=0; + } else { + state->vs_3v=1; + state->vs_Xv=0; + } } -static int simpad_pcmcia_configure_socket(int sock, const struct pcmcia_configure - *configure) +static int +simpad_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, + const socket_state_t *state) { - unsigned long value, flags; - - if(sock>1) return -1; - - if(sock==0) return 0; - - local_irq_save(flags); - - /* Murphy: see table of MIC2562a-1 */ + unsigned long value, flags; - switch(configure->vcc){ - case 0: - clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1); - break; + local_irq_save(flags); - case 33: - clear_cs3_bit(VCC_3V_EN|EN0); - set_cs3_bit(VCC_5V_EN|EN1); - break; + /* Murphy: see table of MIC2562a-1 */ + switch (state->Vcc) { + case 0: + clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1); + break; - case 50: - clear_cs3_bit(VCC_5V_EN|EN1); - set_cs3_bit(VCC_3V_EN|EN0); - break; + case 33: + clear_cs3_bit(VCC_3V_EN|EN0); + set_cs3_bit(VCC_5V_EN|EN1); + break; - default: - printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); - clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1); - local_irq_restore(flags); - return -1; - } + case 50: + clear_cs3_bit(VCC_5V_EN|EN1); + set_cs3_bit(VCC_3V_EN|EN0); + break; - /* Silently ignore Vpp, output enable, speaker enable. */ + default: + printk(KERN_ERR "%s(): unrecognized Vcc %u\n", + __FUNCTION__, state->Vcc); + clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1); + local_irq_restore(flags); + return -1; + } - local_irq_restore(flags); + /* Silently ignore Vpp, output enable, speaker enable. */ + local_irq_restore(flags); - return 0; + return 0; } -static int simpad_pcmcia_socket_init(int sock) +static void simpad_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) { - set_irq_type(IRQ_GPIO_CF_CD, IRQT_BOTHEDGE); - return 0; + sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int simpad_pcmcia_socket_suspend(int sock) +static void simpad_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt) { - set_irq_type(IRQ_GPIO_CF_CD, IRQT_NOEDGE); - return 0; + sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } static struct pcmcia_low_level simpad_pcmcia_ops = { - .owner = THIS_MODULE, - .init = simpad_pcmcia_init, - .shutdown = simpad_pcmcia_shutdown, - .socket_state = simpad_pcmcia_socket_state, - .configure_socket = simpad_pcmcia_configure_socket, - - .socket_init = simpad_pcmcia_socket_init, - .socket_suspend = simpad_pcmcia_socket_suspend, + .owner = THIS_MODULE, + .hw_init = simpad_pcmcia_hw_init, + .hw_shutdown = simpad_pcmcia_hw_shutdown, + .socket_state = simpad_pcmcia_socket_state, + .configure_socket = simpad_pcmcia_configure_socket, + .socket_init = simpad_pcmcia_socket_init, + .socket_suspend = simpad_pcmcia_socket_suspend, }; int __init pcmcia_simpad_init(struct device *dev) @@ -154,12 +130,7 @@ int ret = -ENODEV; if (machine_is_simpad()) - ret = sa1100_register_pcmcia(&simpad_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &simpad_pcmcia_ops, 1, 1); return ret; -} - -void __exit pcmcia_simpad_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&simpad_pcmcia_ops, dev); } diff -Nru a/drivers/pcmcia/sa1100_stork.c b/drivers/pcmcia/sa1100_stork.c --- a/drivers/pcmcia/sa1100_stork.c Wed Apr 2 22:24:05 2003 +++ b/drivers/pcmcia/sa1100_stork.c Wed Apr 2 22:24:05 2003 @@ -32,62 +32,39 @@ static int debug = 0; -static struct irqs { - int irq; - const char *str; -} irqs[] = { - { IRQ_GPIO_STORK_PCMCIA_A_CARD_DETECT, "PCMCIA_CD0" }, - { IRQ_GPIO_STORK_PCMCIA_B_CARD_DETECT, "PCMCIA_CD1" }, +static struct pcmcia_irqs irqs[] = { + { 0, IRQ_GPIO_STORK_PCMCIA_A_CARD_DETECT, "PCMCIA_CD0" }, + { 1, IRQ_GPIO_STORK_PCMCIA_B_CARD_DETECT, "PCMCIA_CD1" }, }; -static int stork_pcmcia_init(struct pcmcia_init *init) +static int stork_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) { - int irq, res; - printk("in stork_pcmcia_init\n"); - init->socket_irq[0] = IRQ_GPIO_STORK_PCMCIA_A_RDY; - init->socket_irq[1] = IRQ_GPIO_STORK_PCMCIA_B_RDY; - - /* Register interrupts */ - for (i = 0; i < ARRAY_SIZE(irqs); i++) { - res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt, - SA_INTERRUPT, irqs[i].str, NULL); - if (res) - goto irq_err; - set_irq_type(irqs[i].irq, IRQT_NOEDGE); - } - - return 2; - - irq_err: - printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n", - __FUNCTION__, irq, res); + skt->irq = skt->nr ? IRQ_GPIO_STORK_PCMCIA_B_RDY + : IRQ_GPIO_STORK_PCMCIA_A_RDY; - while (i--) - free_irq(irqs[i].irq, NULL); - - return res; + return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int stork_pcmcia_shutdown(void) +static void stork_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt) { int i; printk(__FUNCTION__ "\n"); /* disable IRQs */ - for (i = 0; i < ARRAY_SIZE(irqs); i++) - free_irq(irqs[i].irq, NULL); + sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); /* Disable CF bus: */ storkClearLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON); storkClearLatchA(STORK_PCMCIA_A_POWER_ON); storkClearLatchA(STORK_PCMCIA_B_POWER_ON); - return 0; } -static void stork_pcmcia_socket_state(int sock, struct pcmcia_state *state) +static void +stork_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, + struct pcmcia_state *state) { unsigned long levels = GPLR; @@ -95,7 +72,7 @@ printk(__FUNCTION__ " GPLR=%x IRQ[1:0]=%x\n", levels, (levels & (GPIO_STORK_PCMCIA_A_RDY|GPIO_STORK_PCMCIA_B_RDY))); - switch (sock) { + switch (skt->nr) { case 0: state->detect=((levels & GPIO_STORK_PCMCIA_A_CARD_DETECT)==0)?1:0; state->ready=(levels & GPIO_STORK_PCMCIA_A_RDY)?1:0; @@ -118,20 +95,19 @@ } } -static int stork_pcmcia_configure_socket(int sock, const struct pcmcia_configure *configure) +static int +stork_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, + const socket_state_t *state) { unsigned long flags; - int DETECT, RDY, POWER, RESET; - if (sock > 1) return -1; - - printk(__FUNCTION__ ": socket=%d vcc=%d vpp=%d reset=%d\n", - sock, configure->vcc, configure->vpp, configure->reset); + printk("%s: socket=%d vcc=%d vpp=%d reset=%d\n", __FUNCTION__, + skt->nr, state->Vcc, state->Vpp, state->flags & SS_RESET ? 1 : 0); local_irq_save(flags); - if (sock == 0) { + if (skt->nr == 0) { DETECT = GPIO_STORK_PCMCIA_A_CARD_DETECT; RDY = GPIO_STORK_PCMCIA_A_RDY; POWER = STORK_PCMCIA_A_POWER_ON; @@ -148,7 +124,7 @@ printk("no card detected - but resetting anyway\r\n"); } */ - switch (configure->vcc) { + switch (state->Vcc) { case 0: /* storkClearLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON); */ storkClearLatchA(POWER); @@ -162,12 +138,12 @@ default: printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); + state->Vcc); local_irq_restore(flags); return -1; } - if (configure->reset) + if (state->flags & SS_RESET) storkSetLatchB(RESET); else storkClearLatchB(RESET); @@ -176,43 +152,35 @@ /* silently ignore vpp and speaker enables. */ - printk(__FUNCTION__ ": finished\n"); + printk("%s: finished\n", __FUNCTION__); return 0; } -static int stork_pcmcia_socket_init(int sock) +static void stork_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) { storkSetLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON); - if (sock == 0) - set_irq_type(IRQ_GPIO_STORK_PCMCIA_A_CARD_DETECT, IRQT_BOTHEDGE); - else if (sock == 1) - set_irq_type(IRQ_GPIO_STORK_PCMCIA_B_CARD_DETECT, IRQT_BOTHEDGE); - - return 0; + sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int stork_pcmcia_socket_suspend(int sock) +static void stork_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt) { - if (sock == 0) - set_irq_type(IRQ_GPIO_STORK_PCMCIA_A_CARD_DETECT, IRQT_NOEDGE); - else if (sock == 1) { - set_irq_type(IRQ_GPIO_STORK_PCMCIA_B_CARD_DETECT, IRQT_NOEDGE); - - /* - * Hack! - */ + sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); + + /* + * Hack! + */ + if (skt->nr == 1) storkClearLatchA(STORK_PCMCIA_PULL_UPS_POWER_ON); - } return 0; } static struct pcmcia_low_level stork_pcmcia_ops = { .owner = THIS_MODULE, - .init = stork_pcmcia_init, - .shutdown = stork_pcmcia_shutdown, + .hw_init = stork_pcmcia_hw_init, + .hw_shutdown = stork_pcmcia_hw_shutdown, .socket_state = stork_pcmcia_socket_state, .configure_socket = stork_pcmcia_configure_socket, @@ -225,13 +193,7 @@ int ret = -ENODEV; if (machine_is_stork()) - ret = sa1100_register_pcmcia(&stork_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &stork_pcmcia_ops, 0, 2); return ret; } - -void __exit pcmcia_stork_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&stork_pcmcia_ops, dev); -} - diff -Nru a/drivers/pcmcia/sa1100_system3.c b/drivers/pcmcia/sa1100_system3.c --- a/drivers/pcmcia/sa1100_system3.c Wed Apr 2 22:24:07 2003 +++ b/drivers/pcmcia/sa1100_system3.c Wed Apr 2 22:24:07 2003 @@ -37,7 +37,6 @@ #include #include -#include "sa1100_generic.h" #include "sa1111_generic.h" #define DEBUG 0 @@ -48,34 +47,24 @@ # define DPRINTK( x, args... ) /* nix */ #endif -int system3_pcmcia_init(struct pcmcia_init *init) +static int system3_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) { - init->socket_irq[0] = IRQ_S0_READY_NINT; - init->socket_irq[1] = IRQ_S1_READY_NINT; + skt->irq = skt->nr ? IRQ_S1_READY_NINT : IRQ_S0_READY_NINT; /* Don't need no CD and BVD* interrupts */ - return 2; -} - -int system3_pcmcia_shutdown(void) -{ return 0; } -int system3_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) +void system3_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt) { - /* only CF ATM */ - if (sock == 0) - return -1; - - return sa1111_pcmcia_configure_socket(sock, conf); } -static void system3_pcmcia_socket_state(int sock, struct pcmcia_state *state) +static void +system3_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, struct pcmcia_state *state) { unsigned long status = PCSR; - switch (sock) { + switch (skt->nr) { #if 0 /* PCMCIA socket not yet connected */ case 0: state->detect = status & PCSR_S0_DETECT ? 0 : 1; @@ -100,15 +89,15 @@ } DPRINTK("Sock %d PCSR=0x%08lx, Sx_RDY_nIREQ=%d\n", - sock, status, state->ready); + skt->nr, status, state->ready); } struct pcmcia_low_level system3_pcmcia_ops = { .owner = THIS_MODULE, - .init = system3_pcmcia_init, - .shutdown = system3_pcmcia_shutdown, + .init = system3_pcmcia_hw_init, + .shutdown = system3_pcmcia_hw_shutdown, .socket_state = system3_pcmcia_socket_state, - .configure_socket = system3_pcmcia_configure_socket, + .configure_socket = sa1111_pcmcia_configure_socket, .socket_init = sa1111_pcmcia_socket_init, .socket_suspend = sa1111_pcmcia_socket_suspend, @@ -119,12 +108,8 @@ int ret = -ENODEV; if (machine_is_pt_system3()) - ret = sa1100_register_pcmcia(&system3_pcmcia_ops, dev); + /* only CF ATM */ + ret = sa11xx_drv_pcmcia_probe(dev, &system3_pcmcia_ops, 1, 1); return ret; -} - -void __exit pcmcia_system3_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&system3_pcmcia_ops, dev); } diff -Nru a/drivers/pcmcia/sa1100_trizeps.c b/drivers/pcmcia/sa1100_trizeps.c --- a/drivers/pcmcia/sa1100_trizeps.c Wed Apr 2 22:24:06 2003 +++ b/drivers/pcmcia/sa1100_trizeps.c Wed Apr 2 22:24:06 2003 @@ -23,15 +23,18 @@ #include "sa1100_generic.h" #define NUMBER_OF_TRIZEPS_PCMCIA_SLOTS 1 + +static struct pcmcia_irqs irqs[] = { + { 0, TRIZEPS_IRQ_PCMCIA_CD0, "PCMCIA_CD0" }, +}; + /** * * ******************************************************/ -static int trizeps_pcmcia_init(struct pcmcia_init *init) +static int trizeps_pcmcia_init(struct sa1100_pcmcia_socket *skt) { - int res; - - init->socket_irq[0] = TRIZEPS_IRQ_PCMCIA_IRQ0; + skt->irq = TRIZEPS_IRQ_PCMCIA_IRQ0; /* Enable CF bus: */ TRIZEPS_BCR_clear(TRIZEPS_BCR1, TRIZEPS_nPCM_ENA_REG); @@ -40,74 +43,54 @@ GPDR &= ~((GPIO_GPIO(TRIZEPS_GPIO_PCMCIA_CD0)) | (GPIO_GPIO(TRIZEPS_GPIO_PCMCIA_IRQ0))); - /* Register SOCKET interrupts */ - /* WHY? */ - res = request_irq(TRIZEPS_IRQ_PCMCIA_CD0, sa1100_pcmcia_interrupt, - SA_INTERRUPT, "PCMCIA_CD0", NULL ); - if( res < 0 ) goto irq_err; - set_irq_type(TRIZEPS_IRQ_PCMCIA_CD0, IRQT_NOEDGE); - - //MECR = 0x00060006; // Initialised on trizeps init - - // return=sa1100_pcmcia_socket_count (sa1100_generic.c) - // -> number of PCMCIA Slots - // Slot 0 -> Trizeps PCMCIA - // Slot 1 -> Trizeps ISA-Bus - return NUMBER_OF_TRIZEPS_PCMCIA_SLOTS; - - irq_err: - printk( KERN_ERR "%s(): PCMCIA Request for IRQ %u failed\n", __FUNCTION__, TRIZEPS_IRQ_PCMCIA_CD0 ); - return -1; + return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } /** * * ******************************************************/ -static int trizeps_pcmcia_shutdown(void) +static void trizeps_pcmcia_shutdown(struct sa1100_pcmcia_socket *skt) { printk(">>>>>PCMCIA TRIZEPS shutdown\n"); - /* disable IRQs */ - free_irq(TRIZEPS_IRQ_PCMCIA_CD0, NULL ); + + sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); /* Disable CF bus: */ TRIZEPS_BCR_set(TRIZEPS_BCR1, TRIZEPS_nPCM_ENA_REG); - - return 0; } /** * - ******************************************************/ -static void trizeps_pcmcia_socket_state(int sock, struct pcmcia_state *state_array) +static void +trizeps_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, + struct pcmcia_state *state_array) { unsigned long levels = GPLR; - if (sock == 0) { - state->detect = ((levels & GPIO_GPIO(TRIZEPS_GPIO_PCMCIA_CD0)) == 0) ? 1 : 0; - state->ready = ((levels & GPIO_GPIO(TRIZEPS_GPIO_PCMCIA_IRQ0)) != 0) ? 1 : 0; - state->bvd1 = ((TRIZEPS_BCR1 & TRIZEPS_PCM_BVD1) !=0 ) ? 1 : 0; - state->bvd2 = ((TRIZEPS_BCR1 & TRIZEPS_PCM_BVD2) != 0) ? 1 : 0; - state->wrprot = 0; // not write protected - state->vs_3v = ((TRIZEPS_BCR1 & TRIZEPS_nPCM_VS1) == 0) ? 1 : 0; //VS1=0 -> vs_3v=1 - state->vs_Xv = ((TRIZEPS_BCR1 & TRIZEPS_nPCM_VS2) == 0) ? 1 : 0; //VS2=0 -> vs_Xv=1 - } + state->detect = ((levels & GPIO_GPIO(TRIZEPS_GPIO_PCMCIA_CD0)) == 0) ? 1 : 0; + state->ready = ((levels & GPIO_GPIO(TRIZEPS_GPIO_PCMCIA_IRQ0)) != 0) ? 1 : 0; + state->bvd1 = ((TRIZEPS_BCR1 & TRIZEPS_PCM_BVD1) !=0 ) ? 1 : 0; + state->bvd2 = ((TRIZEPS_BCR1 & TRIZEPS_PCM_BVD2) != 0) ? 1 : 0; + state->wrprot = 0; // not write protected + state->vs_3v = ((TRIZEPS_BCR1 & TRIZEPS_nPCM_VS1) == 0) ? 1 : 0; //VS1=0 -> vs_3v=1 + state->vs_Xv = ((TRIZEPS_BCR1 & TRIZEPS_nPCM_VS2) == 0) ? 1 : 0; //VS2=0 -> vs_Xv=1 } /** * * ******************************************************/ -static int trizeps_pcmcia_configure_socket(int sock, const struct pcmcia_configure *configure) +static int +trizeps_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, + const socket_state_t *state) { unsigned long flags; - if(sock>1) return -1; - local_irq_save(flags); - switch (configure->vcc) { + switch (state->Vcc) { case 0: printk(">>> PCMCIA Power off\n"); TRIZEPS_BCR_clear(TRIZEPS_BCR1, TRIZEPS_PCM_V3_EN_REG); @@ -126,19 +109,19 @@ break; default: printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, - configure->vcc); + state->Vcc); local_irq_restore(flags); return -1; } - if (configure->reset) + if (state->flags & SS_RESET) TRIZEPS_BCR_set(TRIZEPS_BCR1, TRIZEPS_nPCM_RESET_DISABLE); // Reset else TRIZEPS_BCR_clear(TRIZEPS_BCR1, TRIZEPS_nPCM_RESET_DISABLE); // no Reset /* printk(" vcc=%u vpp=%u -->reset=%i\n", - configure->vcc, - configure->vpp, + state->Vcc, + state->Vpp, ((BCR_read(1) & nPCM_RESET_DISABLE)? 1:0)); */ local_irq_restore(flags); @@ -146,16 +129,14 @@ return 0; } -static int trizeps_pcmcia_socket_init(int sock) +static void trizeps_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) { - set_irq_type(TRIZEPS_IRQ_PCMCIA_CD0, IRQT_BOTHEDGE); - return 0; + sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int trizeps_pcmcia_socket_suspend(int sock) +static void trizeps_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt) { - set_irq_type(TRIZEPS_IRQ_PCMCIA_CD0, IRQT_NOEDGE); - return 0; + sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } /** @@ -164,8 +145,8 @@ ******************************************************/ struct pcmcia_low_level trizeps_pcmcia_ops = { .owner = THIS_MODULE, - .init = trizeps_pcmcia_init, - .shutdown = trizeps_pcmcia_shutdown, + .hw_init = trizeps_pcmcia_hw_init, + .hw_shutdown = trizeps_pcmcia_hw_shutdown, .socket_state = trizeps_pcmcia_socket_state, .configure_socket = trizeps_pcmcia_configure_socket, .socket_init = trizeps_pcmcia_socket_init, @@ -174,13 +155,11 @@ int __init pcmcia_trizeps_init(struct device *dev) { - if (machine_is_trizeps()) { - return sa1100_register_pcmcia(&trizeps_pcmcia_ops, dev); - } - return -ENODEV; -} + int ret = -ENODEV; -void __exit pcmcia_trizeps_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&trizeps_pcmcia_ops, dev); + if (machine_is_trizeps()) + ret = sa11xx_drv_pcmcia_probe(dev, &trizeps_pcmcia_ops, 0, + NUMBER_OF_TRIZEPS_PCMCIA_SLOTS); + + return ret; } diff -Nru a/drivers/pcmcia/sa1100_xp860.c b/drivers/pcmcia/sa1100_xp860.c --- a/drivers/pcmcia/sa1100_xp860.c Wed Apr 2 22:24:05 2003 +++ b/drivers/pcmcia/sa1100_xp860.c Wed Apr 2 22:24:05 2003 @@ -19,7 +19,7 @@ #define NCR_A0VPP (1<<16) #define NCR_A1VPP (1<<17) -static int xp860_pcmcia_init(struct pcmcia_init *init) +static int xp860_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) { /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */ PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3); @@ -38,11 +38,11 @@ GPDR |= (NCR_A0VPP | NCR_A1VPP); GPCR &= ~(NCR_A0VPP | NCR_A1VPP); - return sa1111_pcmcia_init(init); + return sa1111_pcmcia_hw_init(skt); } static int -xp860_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) +xp860_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, const socket_state_t *state) { unsigned int gpio_mask, pa_dwr_mask; unsigned int gpio_set, pa_dwr_set; @@ -72,28 +72,28 @@ * the corresponding truth table. */ - switch (sock) { + switch (skt->nr) { case 0: pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1; gpio_mask = NCR_A0VPP | NCR_A1VPP; - switch (conf->vcc) { + switch (state->Vcc) { default: case 0: pa_dwr_set = 0; break; case 33: pa_dwr_set = GPIO_GPIO1; break; case 50: pa_dwr_set = GPIO_GPIO0; break; } - switch (conf->vpp) { + switch (state->Vpp) { case 0: gpio_set = 0; break; case 120: gpio_set = NCR_A1VPP; break; default: - if (conf->vpp == conf->vcc) + if (state->Vpp == state->Vcc) gpio_set = NCR_A0VPP; else { printk(KERN_ERR "%s(): unrecognized Vpp %u\n", - __FUNCTION__, conf->vpp); + __FUNCTION__, state->Vpp); return -1; } } @@ -104,22 +104,22 @@ gpio_mask = 0; gpio_set = 0; - switch (conf->vcc) { + switch (state->Vcc) { default: case 0: pa_dwr_set = 0; break; case 33: pa_dwr_set = GPIO_GPIO2; break; case 50: pa_dwr_set = GPIO_GPIO3; break; } - if (conf->vpp != conf->vcc && conf->vpp != 0) { + if (state->Vpp != state->Vcc && state->Vpp != 0) { printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", - __FUNCTION__, conf->vpp); + __FUNCTION__, state->Vpp); return -1; } break; } - ret = sa1111_pcmcia_configure_socket(sock, conf); + ret = sa1111_pcmcia_configure_socket(skt, state); if (ret == 0) { unsigned long flags; @@ -134,14 +134,13 @@ } static struct pcmcia_low_level xp860_pcmcia_ops = { - .owner = THIS_MODULE, - .init = xp860_pcmcia_init, - .shutdown = sa1111_pcmcia_shutdown, - .socket_state = sa1111_pcmcia_socket_state, - .configure_socket = xp860_pcmcia_configure_socket, - - .socket_init = sa1111_pcmcia_socket_init, - .socket_suspend = sa1111_pcmcia_socket_suspend, + .owner = THIS_MODULE, + .hw_init = xp860_pcmcia_hw_init, + .hw_shutdown = sa1111_pcmcia_hw_shutdown, + .socket_state = sa1111_pcmcia_socket_state, + .configure_socket = xp860_pcmcia_configure_socket, + .socket_init = sa1111_pcmcia_socket_init, + .socket_suspend = sa1111_pcmcia_socket_suspend, }; int __init pcmcia_xp860_init(struct device *dev) @@ -149,13 +148,7 @@ int ret = -ENODEV; if (machine_is_xp860()) - ret = sa1100_register_pcmcia(&xp860_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &xp860_pcmcia_ops, 0, 2); return ret; } - -void __exit pcmcia_xp860_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&xp860_pcmcia_ops, dev); -} - diff -Nru a/drivers/pcmcia/sa1100_yopy.c b/drivers/pcmcia/sa1100_yopy.c --- a/drivers/pcmcia/sa1100_yopy.c Wed Apr 2 22:24:06 2003 +++ b/drivers/pcmcia/sa1100_yopy.c Wed Apr 2 22:24:06 2003 @@ -27,81 +27,51 @@ yopy_gpio_set(GPIO_CF_RESET, reset); } -static struct irqs { - int irq; - const char *str; -} irqs[] = { - { IRQ_CF_CD, "CF_CD" }, - { IRQ_CF_BVD2, "CF_BVD2" }, - { IRQ_CF_BVD1, "CF_BVD1" }, +static struct pcmcia_irqs irqs[] = { + { 0, IRQ_CF_CD, "CF_CD" }, + { 0, IRQ_CF_BVD2, "CF_BVD2" }, + { 0, IRQ_CF_BVD1, "CF_BVD1" }, }; -static int yopy_pcmcia_init(struct pcmcia_init *init) +static int yopy_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) { - int i, res; - - init->socket_irq[0] = IRQ_CF_IREQ; + skt->irq = IRQ_CF_IREQ; pcmcia_power(0); pcmcia_reset(1); - /* Register interrupts */ - for (i = 0; i < ARRAY_SIZE(irqs); i++) { - res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt, - SA_INTERRUPT, irqs[i].str, NULL); - if (res) - goto irq_err; - set_irq_type(irqs[i].irq, IRQT_NOEDGE); - } - - return 1; - - irq_err: - printk(KERN_ERR "%s: request for IRQ%d failed (%d)\n", - __FUNCTION__, irqs[i].irq, res); - - while (i--) - free_irq(irqs[i].irq, NULL); - - return res; + return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int yopy_pcmcia_shutdown(void) +static void yopy_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt) { - int i; - - /* disable IRQs */ - for (i = 0; i < ARRAY_SIZE(irqs); i++) - free_irq(irqs[i].irq, NULL); + sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); /* Disable CF */ pcmcia_reset(1); pcmcia_power(0); - - return 0; } -static void yopy_pcmcia_socket_state(int sock, struct pcmcia_state_array *state) +static void +yopy_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, + struct pcmcia_state_array *state) { unsigned long levels = GPLR; - if (sock == 0) { - state->detect = (levels & GPIO_CF_CD) ? 0 : 1; - state->ready = (levels & GPIO_CF_READY) ? 1 : 0; - state->bvd1 = (levels & GPIO_CF_BVD1) ? 1 : 0; - state->bvd2 = (levels & GPIO_CF_BVD2) ? 1 : 0; - state->wrprot = 0; /* Not available on Yopy. */ - state->vs_3v = 0; /* FIXME Can only apply 3.3V on Yopy. */ - state->vs_Xv = 0; - } + state->detect = (levels & GPIO_CF_CD) ? 0 : 1; + state->ready = (levels & GPIO_CF_READY) ? 1 : 0; + state->bvd1 = (levels & GPIO_CF_BVD1) ? 1 : 0; + state->bvd2 = (levels & GPIO_CF_BVD2) ? 1 : 0; + state->wrprot = 0; /* Not available on Yopy. */ + state->vs_3v = 0; /* FIXME Can only apply 3.3V on Yopy. */ + state->vs_Xv = 0; } -static int yopy_pcmcia_configure_socket(int sock, const struct pcmcia_configure *configure) +static int +yopy_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, + const socket_state_t *state) { - if (sock != 0) - return -1; - - switch (configure->vcc) { + switch (state->Vcc) { case 0: /* power off */ pcmcia_power(0); break; @@ -112,35 +82,25 @@ break; default: printk(KERN_ERR __FUNCTION__"(): unrecognized Vcc %u\n", - configure->vcc); + state->Vcc); return -1; } - pcmcia_reset(configure->reset); + pcmcia_reset(state->flags & SS_RESET ? 1 : 0); /* Silently ignore Vpp, output enable, speaker enable. */ return 0; } -static int yopy_pcmcia_socket_init(int sock) +static void yopy_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) { - int i; - - for (i = 0; i < ARRAY_SIZE(irqs); i++) - set_irq_type(irqs[i].irq, IRQT_BOTHEDGE); - - return 0; + sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static int yopy_pcmcia_socket_suspend(int sock) +static void yopy_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt) { - int i; - - for (i = 0; i < ARRAY_SIZE(irqs); i++) - set_irq_type(irqs[i].irq, IRQT_NOEDGE); - - return 0; + sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } static struct pcmcia_low_level yopy_pcmcia_ops = { @@ -159,13 +119,7 @@ int ret = -ENODEV; if (machine_is_yopy()) - ret = sa1100_register_pcmcia(&yopy_pcmcia_ops, dev); + ret = sa11xx_drv_pcmcia_probe(dev, &yopy_pcmcia_ops, 0, 1); return ret; } - -void __exit pcmcia_yopy_exit(struct device *dev) -{ - sa1100_unregister_pcmcia(&yopy_pcmcia_ops, dev); -} - diff -Nru a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c --- a/drivers/pcmcia/sa1111_generic.c Wed Apr 2 22:24:04 2003 +++ b/drivers/pcmcia/sa1111_generic.c Wed Apr 2 22:24:04 2003 @@ -1,5 +1,5 @@ /* - * linux/drivers/pcmcia/sa1100_sa1111.c + * linux/drivers/pcmcia/sa1111_generic.c * * We implement the generic parts of a SA1111 PCMCIA driver. This * basically means we handle everything except controlling the @@ -19,63 +19,34 @@ #include #include -#include "sa1100_generic.h" #include "sa1111_generic.h" -static struct irqs { - int irq; - const char *str; -} irqs[] = { - { IRQ_S0_CD_VALID, "SA1111 PCMCIA card detect" }, - { IRQ_S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1" }, - { IRQ_S1_CD_VALID, "SA1111 CF card detect" }, - { IRQ_S1_BVD1_STSCHG, "SA1111 CF BVD1" }, +static struct pcmcia_irqs irqs[] = { + { 0, IRQ_S0_CD_VALID, "SA1111 PCMCIA card detect" }, + { 0, IRQ_S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1" }, + { 1, IRQ_S1_CD_VALID, "SA1111 CF card detect" }, + { 1, IRQ_S1_BVD1_STSCHG, "SA1111 CF BVD1" }, }; -static struct sa1111_dev *pcmcia; - -int sa1111_pcmcia_init(struct pcmcia_init *init) +int sa1111_pcmcia_hw_init(struct sa1100_pcmcia_socket *skt) { - int i, ret; - - if (init->socket_irq[0] == NO_IRQ) - init->socket_irq[0] = IRQ_S0_READY_NINT; - if (init->socket_irq[1] == NO_IRQ) - init->socket_irq[1] = IRQ_S1_READY_NINT; - - for (i = ret = 0; i < ARRAY_SIZE(irqs); i++) { - ret = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt, - SA_INTERRUPT, irqs[i].str, NULL); - if (ret) - break; - set_irq_type(irqs[i].irq, IRQT_FALLING); - } + if (skt->irq == NO_IRQ) + skt->irq = skt->nr ? IRQ_S1_READY_NINT : IRQ_S0_READY_NINT; - if (i < ARRAY_SIZE(irqs)) { - printk(KERN_ERR "sa1111_pcmcia: unable to grab IRQ%d (%d)\n", - irqs[i].irq, ret); - while (i--) - free_irq(irqs[i].irq, NULL); - } - - return ret ? -1 : 2; + return sa11xx_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -int sa1111_pcmcia_shutdown(void) +void sa1111_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *skt) { - int i; - - for (i = 0; i < ARRAY_SIZE(irqs); i++) - free_irq(irqs[i].irq, NULL); - - return 0; + sa11xx_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -void sa1111_pcmcia_socket_state(int sock, struct pcmcia_state *state) +void sa1111_pcmcia_socket_state(struct sa1100_pcmcia_socket *skt, struct pcmcia_state *state) { - unsigned long status = sa1111_readl(pcmcia->mapbase + SA1111_PCSR); + struct sa1111_dev *sadev = SA1111_DEV(skt->dev); + unsigned long status = sa1111_readl(sadev->mapbase + SA1111_PCSR); - switch (sock) { + switch (skt->nr) { case 0: state->detect = status & PCSR_S0_DETECT ? 0 : 1; state->ready = status & PCSR_S0_READY ? 1 : 0; @@ -98,91 +69,61 @@ } } -int sa1111_pcmcia_configure_socket(int sock, const struct pcmcia_configure *conf) +int sa1111_pcmcia_configure_socket(struct sa1100_pcmcia_socket *skt, const socket_state_t *state) { - unsigned int rst, flt, wait, pse, irq, pccr_mask, val; + struct sa1111_dev *sadev = SA1111_DEV(skt->dev); + unsigned int pccr_skt_mask, pccr_set_mask, val; unsigned long flags; - switch (sock) { + switch (skt->nr) { case 0: - rst = PCCR_S0_RST; - flt = PCCR_S0_FLT; - wait = PCCR_S0_PWAITEN; - pse = PCCR_S0_PSE; - irq = IRQ_S0_READY_NINT; + pccr_skt_mask = PCCR_S0_RST|PCCR_S0_FLT|PCCR_S0_PWAITEN|PCCR_S0_PSE; break; case 1: - rst = PCCR_S1_RST; - flt = PCCR_S1_FLT; - wait = PCCR_S1_PWAITEN; - pse = PCCR_S1_PSE; - irq = IRQ_S1_READY_NINT; + pccr_skt_mask = PCCR_S1_RST|PCCR_S1_FLT|PCCR_S1_PWAITEN|PCCR_S1_PSE; break; default: return -1; } - switch (conf->vcc) { - case 0: - pccr_mask = 0; - break; + pccr_set_mask = 0; - case 33: - pccr_mask = wait; - break; - - case 50: - pccr_mask = pse | wait; - break; - - default: - printk(KERN_ERR "sa1111_pcmcia: unrecognised VCC %u\n", - conf->vcc); - return -1; - } - - if (conf->reset) - pccr_mask |= rst; - - if (conf->output) - pccr_mask |= flt; + if (state->Vcc != 0) + pccr_set_mask |= PCCR_S0_PWAITEN|PCCR_S1_PWAITEN; + if (state->Vcc == 50) + pccr_set_mask |= PCCR_S0_PSE|PCCR_S1_PSE; + if (state->flags & SS_RESET) + pccr_set_mask |= PCCR_S0_RST|PCCR_S1_RST; + if (state->flags & SS_OUTPUT_ENA) + pccr_set_mask |= PCCR_S0_FLT|PCCR_S1_FLT; local_irq_save(flags); - val = sa1111_readl(pcmcia->mapbase + SA1111_PCCR); - val = (val & ~(pse | flt | wait | rst)) | pccr_mask; - sa1111_writel(val, pcmcia->mapbase + SA1111_PCCR); + val = sa1111_readl(sadev->mapbase + SA1111_PCCR); + val &= ~pccr_skt_mask; + val |= pccr_set_mask & pccr_skt_mask; + sa1111_writel(val, sadev->mapbase + SA1111_PCCR); local_irq_restore(flags); return 0; } -int sa1111_pcmcia_socket_init(int sock) +void sa1111_pcmcia_socket_init(struct sa1100_pcmcia_socket *skt) { - return 0; + sa11xx_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -int sa1111_pcmcia_socket_suspend(int sock) +void sa1111_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *skt) { - return 0; + sa11xx_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } static int pcmcia_probe(struct device *dev) { struct sa1111_dev *sadev = SA1111_DEV(dev); - unsigned long flags; char *base; - local_irq_save(flags); - if (pcmcia) { - local_irq_restore(flags); - return -EBUSY; - } - - pcmcia = sadev; - local_irq_restore(flags); - if (!request_mem_region(sadev->res.start, 512, SA1111_DRIVER_NAME(sadev))) return -EBUSY; @@ -226,44 +167,8 @@ { struct sa1111_dev *sadev = SA1111_DEV(dev); -#ifdef CONFIG_SA1100_ADSBITSY - pcmcia_adsbitsy_exit(dev); -#endif -#ifdef CONFIG_SA1100_BADGE4 - pcmcia_badge4_exit(dev); -#endif -#ifdef CONFIG_SA1100_GRAPHICSMASTER - pcmcia_graphicsmaster_exit(dev); -#endif -#ifdef CONFIG_SA1100_JORNADA720 - pcmcia_jornada720_exit(dev); -#endif -#ifdef CONFIG_ASSABET_NEPONSET - pcmcia_neponset_exit(dev); -#endif -#ifdef CONFIG_SA1100_PFS168 - pcmcia_pfs_exit(dev); -#endif -#ifdef CONFIG_SA1100_PT_SYSTEM3 - pcmcia_system3_exit(dev); -#endif -#ifdef CONFIG_SA1100_XP860 - pcmcia_xp860_exit(dev); -#endif - + sa11xx_drv_pcmcia_remove(dev); release_mem_region(sadev->res.start, 512); - pcmcia = NULL; - - return 0; -} - -static int pcmcia_suspend(struct device *dev, u32 state, u32 level) -{ - return 0; -} - -static int pcmcia_resume(struct device *dev, u32 level) -{ return 0; } @@ -274,8 +179,8 @@ .devclass = &pcmcia_socket_class, .probe = pcmcia_probe, .remove = __devexit_p(pcmcia_remove), - .suspend = pcmcia_suspend, - .resume = pcmcia_resume, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }, .devid = SA1111_DEVID_PCMCIA, }; diff -Nru a/drivers/pcmcia/sa1111_generic.h b/drivers/pcmcia/sa1111_generic.h --- a/drivers/pcmcia/sa1111_generic.h Wed Apr 2 22:24:07 2003 +++ b/drivers/pcmcia/sa1111_generic.h Wed Apr 2 22:24:07 2003 @@ -1,14 +1,12 @@ -extern int sa1111_pcmcia_init(struct pcmcia_init *); -extern int sa1111_pcmcia_shutdown(void); -extern void sa1111_pcmcia_socket_state(int sock, struct pcmcia_state *); -extern int sa1111_pcmcia_configure_socket(int sock, const struct pcmcia_configure *); -extern int sa1111_pcmcia_socket_init(int); -extern int sa1111_pcmcia_socket_suspend(int); +#include "sa11xx_core.h" +extern int sa1111_pcmcia_hw_init(struct sa1100_pcmcia_socket *); +extern void sa1111_pcmcia_hw_shutdown(struct sa1100_pcmcia_socket *); +extern void sa1111_pcmcia_socket_state(struct sa1100_pcmcia_socket *, struct pcmcia_state *); +extern int sa1111_pcmcia_configure_socket(struct sa1100_pcmcia_socket *, const socket_state_t *); +extern void sa1111_pcmcia_socket_init(struct sa1100_pcmcia_socket *); +extern void sa1111_pcmcia_socket_suspend(struct sa1100_pcmcia_socket *); extern int pcmcia_jornada720_init(struct device *); -extern void pcmcia_jornada720_exit(struct device *); - extern int pcmcia_neponset_init(struct device *); -extern void pcmcia_neponset_exit(struct device *); diff -Nru a/drivers/pcmcia/sa11xx_core.c b/drivers/pcmcia/sa11xx_core.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pcmcia/sa11xx_core.c Wed Apr 2 22:24:08 2003 @@ -0,0 +1,1054 @@ +/*====================================================================== + + Device driver for the PCMCIA control functionality of StrongARM + SA-1100 microprocessors. + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is John G. Dorsey + . Portions created by John G. Dorsey are + Copyright (C) 1999 John G. Dorsey. All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU Public License version 2 (the "GPL"), in which + case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + +======================================================================*/ +/* + * Please see linux/Documentation/arm/SA1100/PCMCIA for more information + * on the low-level kernel interface. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "sa11xx_core.h" +#include "sa1100.h" + +#ifdef PCMCIA_DEBUG +static int pc_debug; +#endif + +/* This structure maintains housekeeping state for each socket, such + * as the last known values of the card detect pins, or the Card Services + * callback value associated with the socket: + */ +static struct sa1100_pcmcia_socket sa1100_pcmcia_socket[SA1100_PCMCIA_MAX_SOCK]; + +#define PCMCIA_SOCKET(x) (sa1100_pcmcia_socket + (x)) + +/* + * sa1100_pcmcia_default_mecr_timing + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * + * Calculate MECR clock wait states for given CPU clock + * speed and command wait state. This function can be over- + * written by a board specific version. + * + * The default is to simply calculate the BS values as specified in + * the INTEL SA1100 development manual + * "Expansion Memory (PCMCIA) Configuration Register (MECR)" + * that's section 10.2.5 in _my_ version of the manual ;) + */ +static unsigned int +sa1100_pcmcia_default_mecr_timing(struct sa1100_pcmcia_socket *skt, + unsigned int cpu_speed, + unsigned int cmd_time) +{ + return sa1100_pcmcia_mecr_bs(cmd_time, cpu_speed); +} + +static unsigned short +calc_speed(unsigned short *spds, int num, unsigned short dflt) +{ + unsigned short speed = 0; + int i; + + for (i = 0; i < num; i++) + if (speed < spds[i]) + speed = spds[i]; + if (speed == 0) + speed = dflt; + + return speed; +} + +/* sa1100_pcmcia_set_mecr() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * + * set MECR value for socket based on this sockets + * io, mem and attribute space access speed. + * Call board specific BS value calculation to allow boards + * to tweak the BS values. + */ +static int +sa1100_pcmcia_set_mecr(struct sa1100_pcmcia_socket *skt, unsigned int cpu_clock) +{ + u32 mecr, old_mecr; + unsigned long flags; + unsigned short speed; + unsigned int bs_io, bs_mem, bs_attr; + int i; + + speed = calc_speed(skt->spd_io, MAX_IO_WIN, SA1100_PCMCIA_IO_ACCESS); + bs_io = skt->ops->socket_get_timing(skt, cpu_clock, speed); + + speed = calc_speed(skt->spd_mem, MAX_WIN, SA1100_PCMCIA_3V_MEM_ACCESS); + bs_mem = skt->ops->socket_get_timing(skt, cpu_clock, speed); + + speed = calc_speed(skt->spd_attr, MAX_WIN, SA1100_PCMCIA_3V_MEM_ACCESS); + bs_attr = skt->ops->socket_get_timing(skt, cpu_clock, speed); + + local_irq_save(flags); + + old_mecr = mecr = MECR; + MECR_FAST_SET(mecr, skt->nr, 0); + MECR_BSIO_SET(mecr, skt->nr, bs_io); + MECR_BSA_SET(mecr, skt->nr, bs_attr); + MECR_BSM_SET(mecr, skt->nr, bs_mem); + if (old_mecr != mecr) + MECR = mecr; + + local_irq_restore(flags); + + DEBUG(4, "%s(): sock %u FAST %X BSM %X BSA %X BSIO %X\n", + __FUNCTION__, skt->nr, MECR_FAST_GET(mecr, skt->nr), + MECR_BSM_GET(mecr, skt->nr), MECR_BSA_GET(mecr, skt->nr), + MECR_BSIO_GET(mecr, skt->nr)); + + return 0; +} + +static unsigned int sa1100_pcmcia_skt_state(struct sa1100_pcmcia_socket *skt) +{ + struct pcmcia_state state; + unsigned int stat; + + memset(&state, 0, sizeof(struct pcmcia_state)); + + skt->ops->socket_state(skt, &state); + + stat = state.detect ? SS_DETECT : 0; + stat |= state.ready ? SS_READY : 0; + stat |= state.wrprot ? SS_WRPROT : 0; + stat |= state.vs_3v ? SS_3VCARD : 0; + stat |= state.vs_Xv ? SS_XVCARD : 0; + + /* The power status of individual sockets is not available + * explicitly from the hardware, so we just remember the state + * and regurgitate it upon request: + */ + stat |= skt->cs_state.Vcc ? SS_POWERON : 0; + + if (skt->cs_state.flags & SS_IOCARD) + stat |= state.bvd1 ? SS_STSCHG : 0; + else { + if (state.bvd1 == 0) + stat |= SS_BATDEAD; + else if (state.bvd2 == 0) + stat |= SS_BATWARN; + } + return stat; +} + +/* + * sa1100_pcmcia_config_skt + * ^^^^^^^^^^^^^^^^^^^^^^^^ + * + * Convert PCMCIA socket state to our socket configure structure. + */ +static int +sa1100_pcmcia_config_skt(struct sa1100_pcmcia_socket *skt, socket_state_t *state) +{ + int ret; + + ret = skt->ops->configure_socket(skt, state); + if (ret == 0) { + /* + * This really needs a better solution. The IRQ + * may or may not be claimed by the driver. + */ + if (skt->irq_state != 1 && state->io_irq) { + skt->irq_state = 1; + set_irq_type(skt->irq, IRQT_FALLING); + } else if (skt->irq_state == 1 && state->io_irq == 0) { + skt->irq_state = 0; + set_irq_type(skt->irq, IRQT_NOEDGE); + } + + skt->cs_state = *state; + } + + if (ret < 0) + printk(KERN_ERR "sa1100_pcmcia: unable to configure " + "socket %d\n", skt->nr); + + return ret; +} + +/* sa1100_pcmcia_sock_init() + * ^^^^^^^^^^^^^^^^^^^^^^^^^ + * + * (Re-)Initialise the socket, turning on status interrupts + * and PCMCIA bus. This must wait for power to stabilise + * so that the card status signals report correctly. + * + * Returns: 0 + */ +static int sa1100_pcmcia_sock_init(unsigned int sock) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + + DEBUG(2, "%s(): initializing socket %u\n", __FUNCTION__, skt->nr); + + skt->ops->socket_init(skt); + sa1100_pcmcia_config_skt(skt, &dead_socket); + + return 0; +} + + +/* + * sa1100_pcmcia_suspend() + * ^^^^^^^^^^^^^^^^^^^^^^^ + * + * Remove power on the socket, disable IRQs from the card. + * Turn off status interrupts, and disable the PCMCIA bus. + * + * Returns: 0 + */ +static int sa1100_pcmcia_suspend(unsigned int sock) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + int ret; + + DEBUG(2, "%s(): suspending socket %u\n", __FUNCTION__, skt->nr); + + ret = sa1100_pcmcia_config_skt(skt, &dead_socket); + if (ret == 0) + skt->ops->socket_suspend(skt); + + return ret; +} + + +/* sa1100_pcmcia_task_handler() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Processes serviceable socket events using the "eventd" thread context. + * + * Event processing (specifically, the invocation of the Card Services event + * callback) occurs in this thread rather than in the actual interrupt + * handler due to the use of scheduling operations in the PCMCIA core. + */ +static void sa1100_pcmcia_task_handler(void *data) +{ + struct sa1100_pcmcia_socket *skt = data; + unsigned int events; + + DEBUG(4, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__); + + do { + unsigned int status; + + status = sa1100_pcmcia_skt_state(skt); + + events = (status ^ skt->status) & skt->cs_state.csc_mask; + skt->status = status; + + DEBUG(2, "events: %s%s%s%s%s%s\n", + events == 0 ? "" : "", + events & SS_DETECT ? "DETECT " : "", + events & SS_READY ? "READY " : "", + events & SS_BATDEAD ? "BATDEAD " : "", + events & SS_BATWARN ? "BATWARN " : "", + events & SS_STSCHG ? "STSCHG " : ""); + + if (events && skt->handler != NULL) + skt->handler(skt->handler_info, events); + } while (events); +} + +/* sa1100_pcmcia_poll_event() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Let's poll for events in addition to IRQs since IRQ only is unreliable... + */ +static void sa1100_pcmcia_poll_event(unsigned long dummy) +{ + struct sa1100_pcmcia_socket *skt = (struct sa1100_pcmcia_socket *)dummy; + DEBUG(4, "%s(): polling for events\n", __FUNCTION__); + + mod_timer(&skt->poll_timer, jiffies + SA1100_PCMCIA_POLL_PERIOD); + + schedule_work(&skt->work); +} + + +/* sa1100_pcmcia_interrupt() + * ^^^^^^^^^^^^^^^^^^^^^^^^^ + * Service routine for socket driver interrupts (requested by the + * low-level PCMCIA init() operation via sa1100_pcmcia_thread()). + * The actual interrupt-servicing work is performed by + * sa1100_pcmcia_thread(), largely because the Card Services event- + * handling code performs scheduling operations which cannot be + * executed from within an interrupt context. + */ +static void sa1100_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs) +{ + struct sa1100_pcmcia_socket *skt = dev; + + DEBUG(3, "%s(): servicing IRQ %d\n", __FUNCTION__, irq); + + schedule_work(&skt->work); +} + +/* sa1100_pcmcia_register_callback() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the register_callback() operation for the in-kernel + * PCMCIA service (formerly SS_RegisterCallback in Card Services). If + * the function pointer `handler' is not NULL, remember the callback + * location in the state for `sock', and increment the usage counter + * for the driver module. (The callback is invoked from the interrupt + * service routine, sa1100_pcmcia_interrupt(), to notify Card Services + * of interesting events.) Otherwise, clear the callback pointer in the + * socket state and decrement the module usage count. + * + * Returns: 0 + */ +static int +sa1100_pcmcia_register_callback(unsigned int sock, + void (*handler)(void *, unsigned int), + void *info) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + + if (handler) { + if (!try_module_get(skt->ops->owner)) + return -ENODEV; + skt->handler_info = info; + skt->handler = handler; + } else { + skt->handler = NULL; + module_put(skt->ops->owner); + } + + return 0; +} + + +/* sa1100_pcmcia_inquire_socket() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the inquire_socket() operation for the in-kernel PCMCIA + * service (formerly SS_InquireSocket in Card Services). We set + * SS_CAP_STATIC_MAP, which disables the memory resource database + * check. (Mapped memory is set up within the socket driver itself.) + * + * In conjunction with the STATIC_MAP capability is a new field, + * `io_offset', recommended by David Hinds. Rather than go through + * the SetIOMap interface (which is not quite suited for communicating + * window locations up from the socket driver), we just pass up + * an offset which is applied to client-requested base I/O addresses + * in alloc_io_space(). + * + * SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory + * resource database; we instead pass up physical address ranges + * and allow other parts of Card Services to deal with remapping. + * + * SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but + * not 32-bit CardBus devices. + * + * Return value is irrelevant; the pcmcia subsystem ignores it. + */ +static int +sa1100_pcmcia_inquire_socket(unsigned int sock, socket_cap_t *cap) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + int ret = -1; + + if (skt) { + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr); + + cap->features = SS_CAP_STATIC_MAP|SS_CAP_PCCARD; + cap->irq_mask = 0; + cap->map_size = PAGE_SIZE; + cap->pci_irq = skt->irq; + cap->io_offset = (unsigned long)skt->virt_io; + + ret = 0; + } + + return ret; +} + + +/* sa1100_pcmcia_get_status() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the get_status() operation for the in-kernel PCMCIA + * service (formerly SS_GetStatus in Card Services). Essentially just + * fills in bits in `status' according to internal driver state or + * the value of the voltage detect chipselect register. + * + * As a debugging note, during card startup, the PCMCIA core issues + * three set_socket() commands in a row the first with RESET deasserted, + * the second with RESET asserted, and the last with RESET deasserted + * again. Following the third set_socket(), a get_status() command will + * be issued. The kernel is looking for the SS_READY flag (see + * setup_socket(), reset_socket(), and unreset_socket() in cs.c). + * + * Returns: 0 + */ +static int +sa1100_pcmcia_get_status(unsigned int sock, unsigned int *status) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + + skt->status = sa1100_pcmcia_skt_state(skt); + *status = skt->status; + + return 0; +} + + +/* sa1100_pcmcia_get_socket() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the get_socket() operation for the in-kernel PCMCIA + * service (formerly SS_GetSocket in Card Services). Not a very + * exciting routine. + * + * Returns: 0 + */ +static int +sa1100_pcmcia_get_socket(unsigned int sock, socket_state_t *state) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr); + + *state = skt->cs_state; + + return 0; +} + +/* sa1100_pcmcia_set_socket() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the set_socket() operation for the in-kernel PCMCIA + * service (formerly SS_SetSocket in Card Services). We more or + * less punt all of this work and let the kernel handle the details + * of power configuration, reset, &c. We also record the value of + * `state' in order to regurgitate it to the PCMCIA core later. + * + * Returns: 0 + */ +static int +sa1100_pcmcia_set_socket(unsigned int sock, socket_state_t *state) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr); + + DEBUG(3, "\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n", + (state->csc_mask==0)?"":"", + (state->csc_mask&SS_DETECT)?"DETECT ":"", + (state->csc_mask&SS_READY)?"READY ":"", + (state->csc_mask&SS_BATDEAD)?"BATDEAD ":"", + (state->csc_mask&SS_BATWARN)?"BATWARN ":"", + (state->csc_mask&SS_STSCHG)?"STSCHG ":"", + (state->flags==0)?"":"", + (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"", + (state->flags&SS_IOCARD)?"IOCARD ":"", + (state->flags&SS_RESET)?"RESET ":"", + (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"", + (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":""); + DEBUG(3, "\tVcc %d Vpp %d irq %d\n", + state->Vcc, state->Vpp, state->io_irq); + + return sa1100_pcmcia_config_skt(skt, state); +} /* sa1100_pcmcia_set_socket() */ + + +/* sa1100_pcmcia_set_io_map() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the set_io_map() operation for the in-kernel PCMCIA + * service (formerly SS_SetIOMap in Card Services). We configure + * the map speed as requested, but override the address ranges + * supplied by Card Services. + * + * Returns: 0 on success, -1 on error + */ +static int +sa1100_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *map) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + unsigned short speed = map->speed; + + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr); + + DEBUG(3, "\tmap %u speed %u\n\tstart 0x%08x stop 0x%08x\n", + map->map, map->speed, map->start, map->stop); + DEBUG(3, "\tflags: %s%s%s%s%s%s%s%s\n", + (map->flags==0)?"":"", + (map->flags&MAP_ACTIVE)?"ACTIVE ":"", + (map->flags&MAP_16BIT)?"16BIT ":"", + (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"", + (map->flags&MAP_0WS)?"0WS ":"", + (map->flags&MAP_WRPROT)?"WRPROT ":"", + (map->flags&MAP_USE_WAIT)?"USE_WAIT ":"", + (map->flags&MAP_PREFETCH)?"PREFETCH ":""); + + if (map->map >= MAX_IO_WIN) { + printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, + map->map); + return -1; + } + + if (map->flags & MAP_ACTIVE) { + if (speed == 0) + speed = SA1100_PCMCIA_IO_ACCESS; + } else { + speed = 0; + } + + skt->spd_io[map->map] = speed; + sa1100_pcmcia_set_mecr(skt, cpufreq_get(0)); + + if (map->stop == 1) + map->stop = PAGE_SIZE-1; + + map->stop -= map->start; + map->stop += (unsigned long)skt->virt_io; + map->start = (unsigned long)skt->virt_io; + + return 0; +} /* sa1100_pcmcia_set_io_map() */ + + +/* sa1100_pcmcia_set_mem_map() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the set_mem_map() operation for the in-kernel PCMCIA + * service (formerly SS_SetMemMap in Card Services). We configure + * the map speed as requested, but override the address ranges + * supplied by Card Services. + * + * Returns: 0 on success, -1 on error + */ +static int +sa1100_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map) +{ + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + struct resource *res; + unsigned short speed = map->speed; + + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, skt->nr); + + DEBUG(3, "\tmap %u speed %u card_start %08x\n", + map->map, map->speed, map->card_start); + DEBUG(3, "\tflags: %s%s%s%s%s%s%s%s\n", + (map->flags==0)?"":"", + (map->flags&MAP_ACTIVE)?"ACTIVE ":"", + (map->flags&MAP_16BIT)?"16BIT ":"", + (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"", + (map->flags&MAP_0WS)?"0WS ":"", + (map->flags&MAP_WRPROT)?"WRPROT ":"", + (map->flags&MAP_ATTRIB)?"ATTRIB ":"", + (map->flags&MAP_USE_WAIT)?"USE_WAIT ":""); + + if (map->map >= MAX_WIN) + return -EINVAL; + + if (map->flags & MAP_ACTIVE) { + if (speed == 0) + speed = 300; + } else { + speed = 0; + } + + if (map->flags & MAP_ATTRIB) { + res = &skt->res_attr; + skt->spd_attr[map->map] = speed; + skt->spd_mem[map->map] = 0; + } else { + res = &skt->res_mem; + skt->spd_attr[map->map] = 0; + skt->spd_mem[map->map] = speed; + } + + sa1100_pcmcia_set_mecr(skt, cpufreq_get(0)); + + map->sys_stop -= map->sys_start; + map->sys_stop += res->start + map->card_start; + map->sys_start = res->start + map->card_start; + + return 0; +} + + +#if defined(CONFIG_PROC_FS) + +struct bittbl { + unsigned int mask; + const char *name; +}; + +static struct bittbl status_bits[] = { + { SS_WRPROT, "SS_WRPROT" }, + { SS_BATDEAD, "SS_BATDEAD" }, + { SS_BATWARN, "SS_BATWARN" }, + { SS_READY, "SS_READY" }, + { SS_DETECT, "SS_DETECT" }, + { SS_POWERON, "SS_POWERON" }, + { SS_STSCHG, "SS_STSCHG" }, + { SS_3VCARD, "SS_3VCARD" }, + { SS_XVCARD, "SS_XVCARD" }, +}; + +static struct bittbl conf_bits[] = { + { SS_PWR_AUTO, "SS_PWR_AUTO" }, + { SS_IOCARD, "SS_IOCARD" }, + { SS_RESET, "SS_RESET" }, + { SS_DMA_MODE, "SS_DMA_MODE" }, + { SS_SPKR_ENA, "SS_SPKR_ENA" }, + { SS_OUTPUT_ENA, "SS_OUTPUT_ENA" }, + { SS_DEBOUNCED, "SS_DEBOUNCED" }, +}; + +static void +dump_bits(char **p, const char *prefix, unsigned int val, struct bittbl *bits, int sz) +{ + char *b = *p; + int i; + + b += sprintf(b, "%-9s:", prefix); + for (i = 0; i < sz; i++) + if (val & bits[i].mask) + b += sprintf(b, " %s", bits[i].name); + *b++ = '\n'; + *p = b; +} + +/* sa1100_pcmcia_proc_status() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the /proc/bus/pccard/??/status file. + * + * Returns: the number of characters added to the buffer + */ +static int +sa1100_pcmcia_proc_status(char *buf, char **start, off_t pos, + int count, int *eof, void *data) +{ + struct sa1100_pcmcia_socket *skt = data; + unsigned int clock = cpufreq_get(0); + unsigned long mecr = MECR; + char *p = buf; + + p+=sprintf(p, "slot : %d\n", skt->nr); + + dump_bits(&p, "status", skt->status, + status_bits, ARRAY_SIZE(status_bits)); + dump_bits(&p, "csc_mask", skt->cs_state.csc_mask, + status_bits, ARRAY_SIZE(status_bits)); + dump_bits(&p, "cs_flags", skt->cs_state.flags, + conf_bits, ARRAY_SIZE(conf_bits)); + + p+=sprintf(p, "Vcc : %d\n", skt->cs_state.Vcc); + p+=sprintf(p, "Vpp : %d\n", skt->cs_state.Vpp); + p+=sprintf(p, "IRQ : %d (%d)\n", skt->cs_state.io_irq, skt->irq); + + p+=sprintf(p, "I/O : %u (%u)\n", + calc_speed(skt->spd_io, MAX_IO_WIN, SA1100_PCMCIA_IO_ACCESS), + sa1100_pcmcia_cmd_time(clock, MECR_BSIO_GET(mecr, skt->nr))); + + p+=sprintf(p, "attribute: %u (%u)\n", + calc_speed(skt->spd_attr, MAX_WIN, SA1100_PCMCIA_3V_MEM_ACCESS), + sa1100_pcmcia_cmd_time(clock, MECR_BSA_GET(mecr, skt->nr))); + + p+=sprintf(p, "common : %u (%u)\n", + calc_speed(skt->spd_mem, MAX_WIN, SA1100_PCMCIA_3V_MEM_ACCESS), + sa1100_pcmcia_cmd_time(clock, MECR_BSM_GET(mecr, skt->nr))); + + return p-buf; +} + +/* sa1100_pcmcia_proc_setup() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the proc_setup() operation for the in-kernel PCMCIA + * service (formerly SS_ProcSetup in Card Services). + * + * Returns: 0 on success, -1 on error + */ +static void +sa1100_pcmcia_proc_setup(unsigned int sock, struct proc_dir_entry *base) +{ + struct proc_dir_entry *entry; + + if ((entry = create_proc_entry("status", 0, base)) == NULL){ + printk(KERN_ERR "unable to install \"status\" procfs entry\n"); + return; + } + entry->read_proc = sa1100_pcmcia_proc_status; + entry->data = PCMCIA_SOCKET(sock); +} +#else +#define sa1100_pcmcia_proc_setup NULL +#endif /* defined(CONFIG_PROC_FS) */ + +static struct pccard_operations sa11xx_pcmcia_operations = { + .owner = THIS_MODULE, + .init = sa1100_pcmcia_sock_init, + .suspend = sa1100_pcmcia_suspend, + .register_callback = sa1100_pcmcia_register_callback, + .inquire_socket = sa1100_pcmcia_inquire_socket, + .get_status = sa1100_pcmcia_get_status, + .get_socket = sa1100_pcmcia_get_socket, + .set_socket = sa1100_pcmcia_set_socket, + .set_io_map = sa1100_pcmcia_set_io_map, + .set_mem_map = sa1100_pcmcia_set_mem_map, + .proc_setup = sa1100_pcmcia_proc_setup +}; + +int sa11xx_request_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr) +{ + int i, res = 0; + + for (i = 0; i < nr; i++) { + if (irqs[i].sock != skt->nr) + continue; + res = request_irq(irqs[i].irq, sa1100_pcmcia_interrupt, + SA_INTERRUPT, irqs[i].str, skt); + if (res) + break; + set_irq_type(irqs[i].irq, IRQT_NOEDGE); + } + + if (res) { + printk(KERN_ERR "PCMCIA: request for IRQ%d failed (%d)\n", + irqs[i].irq, res); + + while (i--) + if (irqs[i].sock == skt->nr) + free_irq(irqs[i].irq, skt); + } + return res; +} +EXPORT_SYMBOL(sa11xx_request_irqs); + +void sa11xx_free_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr) +{ + int i; + + for (i = 0; i < nr; i++) + if (irqs[i].sock == skt->nr) + free_irq(irqs[i].irq, skt); +} +EXPORT_SYMBOL(sa11xx_free_irqs); + +void sa11xx_disable_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr) +{ + int i; + + for (i = 0; i < nr; i++) + if (irqs[i].sock == skt->nr) + set_irq_type(irqs[i].irq, IRQT_NOEDGE); +} +EXPORT_SYMBOL(sa11xx_disable_irqs); + +void sa11xx_enable_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr) +{ + int i; + + for (i = 0; i < nr; i++) + if (irqs[i].sock == skt->nr) { + set_irq_type(irqs[i].irq, IRQT_RISING); + set_irq_type(irqs[i].irq, IRQT_BOTHEDGE); + } +} +EXPORT_SYMBOL(sa11xx_enable_irqs); + +static const char *skt_names[] = { + "PCMCIA socket 0", + "PCMCIA socket 1", +}; + +int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr) +{ + struct pcmcia_socket_class_data *cls; + unsigned int cpu_clock; + int ret, i; + + cls = kmalloc(sizeof(struct pcmcia_socket_class_data), GFP_KERNEL); + if (!cls) { + ret = -ENOMEM; + goto out; + } + + memset(cls, 0, sizeof(struct pcmcia_socket_class_data)); + cls->ops = &sa11xx_pcmcia_operations; + cls->nsock = nr; + + /* + * set default MECR calculation if the board specific + * code did not specify one... + */ + if (!ops->socket_get_timing) + ops->socket_get_timing = sa1100_pcmcia_default_mecr_timing; + + cpu_clock = cpufreq_get(0); + + /* + * Initialise the per-socket structure. + */ + for (i = 0; i < nr; i++) { + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i); + memset(skt, 0, sizeof(*skt)); + + INIT_WORK(&skt->work, sa1100_pcmcia_task_handler, skt); + + init_timer(&skt->poll_timer); + skt->poll_timer.function = sa1100_pcmcia_poll_event; + skt->poll_timer.data = (unsigned long)skt; + skt->poll_timer.expires = jiffies + SA1100_PCMCIA_POLL_PERIOD; + + skt->nr = first + i; + skt->irq = NO_IRQ; + skt->dev = dev; + skt->ops = ops; + + skt->res_skt.start = _PCMCIA(skt->nr); + skt->res_skt.end = _PCMCIA(skt->nr) + PCMCIASp - 1; + skt->res_skt.name = skt_names[skt->nr]; + skt->res_skt.flags = IORESOURCE_MEM; + + ret = request_resource(&iomem_resource, &skt->res_skt); + if (ret) + goto out_err_1; + + skt->res_io.start = _PCMCIAIO(skt->nr); + skt->res_io.end = _PCMCIAIO(skt->nr) + PCMCIAIOSp - 1; + skt->res_io.name = "io"; + skt->res_io.flags = IORESOURCE_MEM | IORESOURCE_BUSY; + + ret = request_resource(&skt->res_skt, &skt->res_io); + if (ret) + goto out_err_2; + + skt->res_mem.start = _PCMCIAMem(skt->nr); + skt->res_mem.end = _PCMCIAMem(skt->nr) + PCMCIAMemSp - 1; + skt->res_mem.name = "memory"; + skt->res_mem.flags = IORESOURCE_MEM; + + ret = request_resource(&skt->res_skt, &skt->res_mem); + if (ret) + goto out_err_3; + + skt->res_attr.start = _PCMCIAAttr(skt->nr); + skt->res_attr.end = _PCMCIAAttr(skt->nr) + PCMCIAAttrSp - 1; + skt->res_attr.name = "attribute"; + skt->res_attr.flags = IORESOURCE_MEM; + + ret = request_resource(&skt->res_skt, &skt->res_attr); + if (ret) + goto out_err_4; + + skt->virt_io = ioremap(skt->res_io.start, 0x10000); + if (skt->virt_io == NULL) { + ret = -ENOMEM; + goto out_err_5; + } + + /* + * We initialize the MECR to default values here, because + * we are not guaranteed to see a SetIOMap operation at + * runtime. + */ + sa1100_pcmcia_set_mecr(skt, cpu_clock); + + ret = ops->hw_init(skt); + if (ret) + goto out_err_6; + + skt->status = sa1100_pcmcia_skt_state(skt); + add_timer(&skt->poll_timer); + } + + dev->class_data = cls; + return 0; + + do { + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i); + + del_timer_sync(&skt->poll_timer); + flush_scheduled_work(); + + ops->hw_shutdown(skt); + out_err_6: + iounmap(skt->virt_io); + out_err_5: + release_resource(&skt->res_attr); + out_err_4: + release_resource(&skt->res_mem); + out_err_3: + release_resource(&skt->res_io); + out_err_2: + release_resource(&skt->res_skt); + out_err_1: + i--; + } while (i > 0); + + kfree(cls); + + out: + return ret; +} +EXPORT_SYMBOL(sa11xx_drv_pcmcia_probe); + +int sa11xx_drv_pcmcia_remove(struct device *dev) +{ + struct pcmcia_socket_class_data *cls = dev->class_data; + int i; + + dev->class_data = NULL; + + for (i = 0; i < cls->nsock; i++) { + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(cls->sock_offset + i); + + skt->ops->hw_shutdown(skt); + + del_timer_sync(&skt->poll_timer); + flush_scheduled_work(); + + sa1100_pcmcia_config_skt(skt, &dead_socket); + + iounmap(skt->virt_io); + skt->virt_io = NULL; + release_resource(&skt->res_attr); + release_resource(&skt->res_mem); + release_resource(&skt->res_io); + release_resource(&skt->res_skt); + } + + kfree(cls); + + return 0; +} +EXPORT_SYMBOL(sa11xx_drv_pcmcia_remove); + +#ifdef CONFIG_CPU_FREQ + +/* sa1100_pcmcia_update_mecr() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * When sa1100_pcmcia_notifier() decides that a MECR adjustment (due + * to a core clock frequency change) is needed, this routine establishes + * new BS_xx values consistent with the clock speed `clock'. + */ +static void sa1100_pcmcia_update_mecr(unsigned int clock) +{ + unsigned int sock; + + for (sock = 0; sock < SA1100_PCMCIA_MAX_SOCK; ++sock) { + struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + sa1100_pcmcia_set_mecr(skt, clock); + } +} + +/* sa1100_pcmcia_notifier() + * ^^^^^^^^^^^^^^^^^^^^^^^^ + * When changing the processor core clock frequency, it is necessary + * to adjust the MECR timings accordingly. We've recorded the timings + * requested by Card Services, so this is just a matter of finding + * out what our current speed is, and then recomputing the new MECR + * values. + * + * Returns: 0 on success, -1 on error + */ +static int +sa1100_pcmcia_notifier(struct notifier_block *nb, unsigned long val, + void *data) +{ + struct cpufreq_freqs *freqs = data; + + switch (val) { + case CPUFREQ_PRECHANGE: + if (freqs->new > freqs->old) { + DEBUG(2, "%s(): new frequency %u.%uMHz > %u.%uMHz, " + "pre-updating\n", __FUNCTION__, + freqs->new / 1000, (freqs->new / 100) % 10, + freqs->old / 1000, (freqs->old / 100) % 10); + sa1100_pcmcia_update_mecr(freqs->new); + } + break; + + case CPUFREQ_POSTCHANGE: + if (freqs->new < freqs->old) { + DEBUG(2, "%s(): new frequency %u.%uMHz < %u.%uMHz, " + "post-updating\n", __FUNCTION__, + freqs->new / 1000, (freqs->new / 100) % 10, + freqs->old / 1000, (freqs->old / 100) % 10); + sa1100_pcmcia_update_mecr(freqs->new); + } + break; + } + + return 0; +} + +static struct notifier_block sa1100_pcmcia_notifier_block = { + .notifier_call = sa1100_pcmcia_notifier +}; + +static int __init sa11xx_pcmcia_init(void) +{ + int ret; + + printk(KERN_INFO "SA11xx PCMCIA (CS release %s)\n", CS_RELEASE); + + ret = cpufreq_register_notifier(&sa1100_pcmcia_notifier_block, + CPUFREQ_TRANSITION_NOTIFIER); + if (ret < 0) + printk(KERN_ERR "Unable to register CPU frequency change " + "notifier (%d)\n", ret); + + return ret; +} +module_init(sa11xx_pcmcia_init); + +static void __exit sa11xx_pcmcia_exit(void) +{ + cpufreq_unregister_notifier(&sa1100_pcmcia_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); +} + +module_exit(sa11xx_pcmcia_exit); +#endif + +MODULE_AUTHOR("John Dorsey "); +MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11xx core socket driver"); +MODULE_LICENSE("Dual MPL/GPL"); diff -Nru a/drivers/pcmcia/sa11xx_core.h b/drivers/pcmcia/sa11xx_core.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pcmcia/sa11xx_core.h Wed Apr 2 22:24:08 2003 @@ -0,0 +1,122 @@ +/* + * linux/include/asm/arch/pcmcia.h + * + * Copyright (C) 2000 John G Dorsey + * + * This file contains definitions for the low-level SA-1100 kernel PCMCIA + * interface. Please see linux/Documentation/arm/SA1100/PCMCIA for details. + */ +#ifndef _ASM_ARCH_PCMCIA +#define _ASM_ARCH_PCMCIA + +#include +/* include the world */ +#include +#include +#include +#include +#include +#include +#include "cs_internal.h" + +struct device; + +/* Ideally, we'd support up to MAX_SOCK sockets, but the SA-1100 only + * has support for two. This shows up in lots of hardwired ways, such + * as the fact that MECR only has enough bits to configure two sockets. + * Since it's so entrenched in the hardware, limiting the software + * in this way doesn't seem too terrible. + */ +#define SA1100_PCMCIA_MAX_SOCK (2) + +struct pcmcia_state { + unsigned detect: 1, + ready: 1, + bvd1: 1, + bvd2: 1, + wrprot: 1, + vs_3v: 1, + vs_Xv: 1; +}; + +/* + * This structure encapsulates per-socket state which we might need to + * use when responding to a Card Services query of some kind. + */ +struct sa1100_pcmcia_socket { + /* + * Info from low level handler + */ + struct device *dev; + unsigned int nr; + unsigned int irq; + + /* + * Core PCMCIA state + */ + struct pcmcia_low_level *ops; + + unsigned int status; + socket_state_t cs_state; + void (*handler)(void *, unsigned int); + void *handler_info; + + unsigned short spd_io[MAX_IO_WIN]; + unsigned short spd_mem[MAX_WIN]; + unsigned short spd_attr[MAX_WIN]; + + struct resource res_skt; + struct resource res_io; + struct resource res_mem; + struct resource res_attr; + void *virt_io; + + unsigned int irq_state; + + struct timer_list poll_timer; + struct work_struct work; +}; + +struct pcmcia_low_level { + struct module *owner; + + int (*hw_init)(struct sa1100_pcmcia_socket *); + void (*hw_shutdown)(struct sa1100_pcmcia_socket *); + + void (*socket_state)(struct sa1100_pcmcia_socket *, struct pcmcia_state *); + int (*configure_socket)(struct sa1100_pcmcia_socket *, const socket_state_t *); + + /* + * Enable card status IRQs on (re-)initialisation. This can + * be called at initialisation, power management event, or + * pcmcia event. + */ + void (*socket_init)(struct sa1100_pcmcia_socket *); + + /* + * Disable card status IRQs and PCMCIA bus on suspend. + */ + void (*socket_suspend)(struct sa1100_pcmcia_socket *); + + /* + * Calculate MECR timing clock wait states + */ + unsigned int (*socket_get_timing)(struct sa1100_pcmcia_socket *, + unsigned int cpu_speed, unsigned int cmd_time); +}; + +struct pcmcia_irqs { + int sock; + int irq; + const char *str; +}; + +int sa11xx_request_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr); +void sa11xx_free_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr); +void sa11xx_disable_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr); +void sa11xx_enable_irqs(struct sa1100_pcmcia_socket *skt, struct pcmcia_irqs *irqs, int nr); + +extern int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr); +extern int sa11xx_drv_pcmcia_remove(struct device *dev); + +#endif diff -Nru a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c --- a/drivers/pcmcia/tcic.c Wed Apr 2 22:24:06 2003 +++ b/drivers/pcmcia/tcic.c Wed Apr 2 22:24:06 2003 @@ -225,11 +225,6 @@ return 2*(ns-14)/cycle_time; } -static int to_ns(int cycles) -{ - return (cycles*cycle_time)/2 + 14; -} - /*====================================================================*/ static volatile u_int irq_hits; @@ -384,6 +379,8 @@ .name = "tcic-pcmcia", .bus = &platform_bus_type, .devclass = &pcmcia_socket_class, + .suspend = pcmcia_socket_dev_suspend, + .resume = pcmcia_socket_dev_resume, }; static struct platform_device tcic_device = { @@ -806,44 +803,6 @@ /*====================================================================*/ -static int tcic_get_io_map(unsigned int lsock, struct pccard_io_map *io) -{ - u_short psock = socket_table[lsock].psock; - u_short base, ioctl; - u_int addr; - - if (io->map > 1) return -EINVAL; - tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT)); - addr = TCIC_IWIN(psock, io->map); - tcic_setw(TCIC_ADDR, addr + TCIC_IBASE_X); - base = tcic_getw(TCIC_DATA); - tcic_setw(TCIC_ADDR, addr + TCIC_ICTL_X); - ioctl = tcic_getw(TCIC_DATA); - - if (ioctl & TCIC_ICTL_TINY) - io->start = io->stop = base; - else { - io->start = base & (base-1); - io->stop = io->start + (base ^ (base-1)); - } - io->speed = to_ns(ioctl & TCIC_ICTL_WSCNT_MASK); - io->flags = (ioctl & TCIC_ICTL_ENA) ? MAP_ACTIVE : 0; - switch (ioctl & TCIC_ICTL_BW_MASK) { - case TCIC_ICTL_BW_DYN: - io->flags |= MAP_AUTOSZ; break; - case TCIC_ICTL_BW_16: - io->flags |= MAP_16BIT; break; - default: - break; - } - DEBUG(1, "tcic: GetIOMap(%d, %d) = %#2.2x, %d ns, " - "%#4.4x-%#4.4x\n", lsock, io->map, io->flags, - io->speed, io->start, io->stop); - return 0; -} /* tcic_get_io_map */ - -/*====================================================================*/ - static int tcic_set_io_map(unsigned int lsock, struct pccard_io_map *io) { u_short psock = socket_table[lsock].psock; @@ -881,51 +840,6 @@ /*====================================================================*/ -static int tcic_get_mem_map(unsigned int lsock, struct pccard_mem_map *mem) -{ - u_short psock = socket_table[lsock].psock; - u_short addr, ctl; - u_long base, mmap; - - if (mem->map > 3) return -EINVAL; - tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT)); - addr = TCIC_MWIN(psock, mem->map); - - tcic_setw(TCIC_ADDR, addr + TCIC_MBASE_X); - base = tcic_getw(TCIC_DATA); - if (base & TCIC_MBASE_4K_BIT) { - mem->sys_start = base & TCIC_MBASE_HA_MASK; - mem->sys_stop = mem->sys_start; - } else { - base &= TCIC_MBASE_HA_MASK; - mem->sys_start = (base & (base-1)); - mem->sys_stop = mem->sys_start + (base ^ (base-1)); - } - mem->sys_start = mem->sys_start << TCIC_MBASE_HA_SHFT; - mem->sys_stop = (mem->sys_stop << TCIC_MBASE_HA_SHFT) + 0x0fff; - - tcic_setw(TCIC_ADDR, addr + TCIC_MMAP_X); - mmap = tcic_getw(TCIC_DATA); - mem->flags = (mmap & TCIC_MMAP_REG) ? MAP_ATTRIB : 0; - mmap &= TCIC_MMAP_CA_MASK; - mem->card_start = mem->sys_start + (mmap << TCIC_MMAP_CA_SHFT); - mem->card_start &= 0x3ffffff; - - tcic_setw(TCIC_ADDR, addr + TCIC_MCTL_X); - ctl = tcic_getw(TCIC_DATA); - mem->flags |= (ctl & TCIC_MCTL_ENA) ? MAP_ACTIVE : 0; - mem->flags |= (ctl & TCIC_MCTL_B8) ? 0 : MAP_16BIT; - mem->flags |= (ctl & TCIC_MCTL_WP) ? MAP_WRPROT : 0; - mem->speed = to_ns(ctl & TCIC_MCTL_WSCNT_MASK); - - DEBUG(1, "tcic: GetMemMap(%d, %d) = %#2.2x, %d ns, " - "%#5.5lx-%#5.5lx, %#5.5x\n", lsock, mem->map, mem->flags, - mem->speed, mem->sys_start, mem->sys_stop, mem->card_start); - return 0; -} /* tcic_get_mem_map */ - -/*====================================================================*/ - static int tcic_set_mem_map(unsigned int lsock, struct pccard_mem_map *mem) { u_short psock = socket_table[lsock].psock; @@ -1007,9 +921,7 @@ .get_status = tcic_get_status, .get_socket = tcic_get_socket, .set_socket = tcic_set_socket, - .get_io_map = tcic_get_io_map, .set_io_map = tcic_set_io_map, - .get_mem_map = tcic_get_mem_map, .set_mem_map = tcic_set_mem_map, .proc_setup = tcic_proc_setup, }; diff -Nru a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h --- a/drivers/pcmcia/ti113x.h Wed Apr 2 22:24:05 2003 +++ b/drivers/pcmcia/ti113x.h Wed Apr 2 22:24:05 2003 @@ -185,9 +185,7 @@ yenta_get_status, yenta_get_socket, yenta_set_socket, - yenta_get_io_map, yenta_set_io_map, - yenta_get_mem_map, yenta_set_mem_map, yenta_proc_setup }; @@ -230,9 +228,7 @@ yenta_get_status, yenta_get_socket, yenta_set_socket, - yenta_get_io_map, yenta_set_io_map, - yenta_get_mem_map, yenta_set_mem_map, yenta_proc_setup }; @@ -272,9 +268,7 @@ yenta_get_status, yenta_get_socket, yenta_set_socket, - yenta_get_io_map, yenta_set_io_map, - yenta_get_mem_map, yenta_set_mem_map, yenta_proc_setup }; diff -Nru a/drivers/pcmcia/yenta.c b/drivers/pcmcia/yenta.c --- a/drivers/pcmcia/yenta.c Wed Apr 2 22:24:06 2003 +++ b/drivers/pcmcia/yenta.c Wed Apr 2 22:24:06 2003 @@ -27,7 +27,7 @@ #include "i82365.h" #if 0 -#define DEBUG(x,args...) printk(__FUNCTION__ ": " x,##args) +#define DEBUG(x,args...) printk("%s: " x, __FUNCTION__, ##args) #else #define DEBUG(x,args...) #endif @@ -300,29 +300,6 @@ return 0; } -static int yenta_get_io_map(pci_socket_t *socket, struct pccard_io_map *io) -{ - int map; - unsigned char ioctl, addr; - - map = io->map; - if (map > 1) - return -EINVAL; - - io->start = exca_readw(socket, I365_IO(map)+I365_W_START); - io->stop = exca_readw(socket, I365_IO(map)+I365_W_STOP); - - ioctl = exca_readb(socket, I365_IOCTL); - addr = exca_readb(socket, I365_ADDRWIN); - io->speed = to_ns(ioctl & I365_IOCTL_WAIT(map)) ? 1 : 0; - io->flags = (addr & I365_ENA_IO(map)) ? MAP_ACTIVE : 0; - io->flags |= (ioctl & I365_IOCTL_0WS(map)) ? MAP_0WS : 0; - io->flags |= (ioctl & I365_IOCTL_16BIT(map)) ? MAP_16BIT : 0; - io->flags |= (ioctl & I365_IOCTL_IOCS16(map)) ? MAP_AUTOSZ : 0; - - return 0; -} - static int yenta_set_io_map(pci_socket_t *socket, struct pccard_io_map *io) { int map; @@ -356,41 +333,6 @@ return 0; } -static int yenta_get_mem_map(pci_socket_t *socket, struct pccard_mem_map *mem) -{ - int map; - unsigned char addr; - unsigned int start, stop, page, offset; - - map = mem->map; - if (map > 4) - return -EINVAL; - - addr = exca_readb(socket, I365_ADDRWIN); - mem->flags = (addr & I365_ENA_MEM(map)) ? MAP_ACTIVE : 0; - - start = exca_readw(socket, I365_MEM(map) + I365_W_START); - mem->flags |= (start & I365_MEM_16BIT) ? MAP_16BIT : 0; - mem->flags |= (start & I365_MEM_0WS) ? MAP_0WS : 0; - start = (start & 0x0fff) << 12; - - stop = exca_readw(socket, I365_MEM(map) + I365_W_STOP); - mem->speed = to_ns(stop >> 14); - stop = ((stop & 0x0fff) << 12) + 0x0fff; - - offset = exca_readw(socket, I365_MEM(map) + I365_W_OFF); - mem->flags |= (offset & I365_MEM_WRPROT) ? MAP_WRPROT : 0; - mem->flags |= (offset & I365_MEM_REG) ? MAP_ATTRIB : 0; - offset = ((offset & 0x3fff) << 12) + start; - mem->card_start = offset & 0x3ffffff; - - page = exca_readb(socket, CB_MEM_PAGE(map)) << 24; - mem->sys_start = start + page; - mem->sys_stop = start + page; - - return 0; -} - static int yenta_set_mem_map(pci_socket_t *socket, struct pccard_mem_map *mem) { int map; @@ -572,7 +514,6 @@ socket->cap.pci_irq = socket->cb_irq; socket->cap.irq_mask = yenta_probe_irq(socket, isa_irq_mask); socket->cap.cb_dev = socket->dev; - socket->cap.bus = NULL; printk("Yenta IRQ list %04x, PCI irq%d\n", socket->cap.irq_mask, socket->cb_irq); } @@ -935,9 +876,7 @@ yenta_get_status, yenta_get_socket, yenta_set_socket, - yenta_get_io_map, yenta_set_io_map, - yenta_get_mem_map, yenta_set_mem_map, yenta_proc_setup }; diff -Nru a/drivers/pnp/Kconfig b/drivers/pnp/Kconfig --- a/drivers/pnp/Kconfig Wed Apr 2 22:24:05 2003 +++ b/drivers/pnp/Kconfig Wed Apr 2 22:24:05 2003 @@ -47,11 +47,6 @@ Say Y here if you would like support for ISA Plug and Play devices. Some information is in . - This support is also available as a module called isapnp ( = - code which can be inserted in and removed from the running kernel - whenever you want). If you want to compile it as a module, say M - here and read . - If unsure, say Y. config PNPBIOS diff -Nru a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c --- a/drivers/s390/char/con3215.c Wed Apr 2 22:24:06 2003 +++ b/drivers/s390/char/con3215.c Wed Apr 2 22:24:06 2003 @@ -1178,6 +1178,7 @@ memset(&tty3215_driver, 0, sizeof(struct tty_driver)); tty3215_driver.magic = TTY_DRIVER_MAGIC; + tty3215_driver.owner = THIS_MODULE; tty3215_driver.driver_name = "tty3215"; tty3215_driver.name = "ttyS"; tty3215_driver.name_base = 0; diff -Nru a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c --- a/drivers/s390/char/sclp_tty.c Wed Apr 2 22:24:04 2003 +++ b/drivers/s390/char/sclp_tty.c Wed Apr 2 22:24:04 2003 @@ -743,6 +743,7 @@ memset (&sclp_tty_driver, 0, sizeof(struct tty_driver)); sclp_tty_driver.magic = TTY_DRIVER_MAGIC; + sclp_tty_driver.owner = THIS_MODULE; sclp_tty_driver.driver_name = "tty_sclp"; sclp_tty_driver.name = "ttyS"; sclp_tty_driver.name_base = 0; diff -Nru a/drivers/s390/char/tuball.c b/drivers/s390/char/tuball.c --- a/drivers/s390/char/tuball.c Wed Apr 2 22:24:07 2003 +++ b/drivers/s390/char/tuball.c Wed Apr 2 22:24:07 2003 @@ -218,18 +218,6 @@ } #endif /* Not a MODULE or a MODULE */ -void -tub_inc_use_count(void) -{ - MOD_INC_USE_COUNT; -} - -void -tub_dec_use_count(void) -{ - MOD_DEC_USE_COUNT; -} - static int tub3270_is_ours(s390_dev_info_t *dp) { diff -Nru a/drivers/s390/char/tubfs.c b/drivers/s390/char/tubfs.c --- a/drivers/s390/char/tubfs.c Wed Apr 2 22:24:06 2003 +++ b/drivers/s390/char/tubfs.c Wed Apr 2 22:24:06 2003 @@ -118,7 +118,6 @@ return -EBUSY; } - tub_inc_use_count(); fp->private_data = ip; tubp->mode = TBM_FS; tubp->intv = fs3270_int; @@ -144,7 +143,6 @@ fs3270_wait(tubp, &flags); tubp->fsopen = 0; tubp->fs_pid = 0; - tub_dec_use_count(); tubp->intv = NULL; tubp->mode = 0; tty3270_refresh(tubp); @@ -165,7 +163,6 @@ fs3270_wait(tubp, &flags); tubp->fsopen = 0; tubp->fs_pid = 0; - tub_dec_use_count(); tubp->intv = NULL; tubp->mode = 0; /*tty3270_refresh(tubp);*/ diff -Nru a/drivers/s390/char/tubio.h b/drivers/s390/char/tubio.h --- a/drivers/s390/char/tubio.h Wed Apr 2 22:24:05 2003 +++ b/drivers/s390/char/tubio.h Wed Apr 2 22:24:05 2003 @@ -421,8 +421,6 @@ return tubp; } -extern void tub_inc_use_count(void); -extern void tub_dec_use_count(void); extern int tub3270_movedata(bcb_t *, bcb_t *, int); #if 0 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) diff -Nru a/drivers/s390/char/tubtty.c b/drivers/s390/char/tubtty.c --- a/drivers/s390/char/tubtty.c Wed Apr 2 22:24:07 2003 +++ b/drivers/s390/char/tubtty.c Wed Apr 2 22:24:07 2003 @@ -80,6 +80,7 @@ /* Initialize for tty driver */ td->magic = TTY_DRIVER_MAGIC; + td->owner = THIS_MODULE; td->driver_name = "tty3270"; td->name = "tty3270"; td->major = IBM_TTY3270_MAJOR; @@ -189,7 +190,6 @@ return -ENODEV; } - tub_inc_use_count(); if ((rc = tty3270_wait(tubp, &flags)) != 0) goto do_fail; if (tubp->lnopen > 0) { @@ -231,7 +231,6 @@ tty3270_aid_fini(tubp); tty3270_rcl_fini(tubp); TUBUNLOCK(tubp->irq, flags); - tub_dec_use_count(); return rc; } @@ -253,7 +252,6 @@ tty3270_rcl_fini(tubp); tty3270_scl_fini(tubp); do_return: - tub_dec_use_count(); TUBUNLOCK(tubp->irq, flags); } diff -Nru a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c --- a/drivers/s390/cio/qdio.c Wed Apr 2 22:24:06 2003 +++ b/drivers/s390/cio/qdio.c Wed Apr 2 22:24:06 2003 @@ -65,7 +65,7 @@ /******************** HERE WE GO ***********************************/ -static const char *version="QDIO base support version 2 (" +static const char version[] = "QDIO base support version 2 (" VERSION_QDIO_C "/" VERSION_QDIO_H "/" VERSION_CIO_QDIO_H ")"; #ifdef QDIO_PERFORMANCE_STATS diff -Nru a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c --- a/drivers/s390/net/ctcmain.c Wed Apr 2 22:24:05 2003 +++ b/drivers/s390/net/ctcmain.c Wed Apr 2 22:24:05 2003 @@ -2761,7 +2761,6 @@ dev->addr_len = 0; dev->type = ARPHRD_SLIP; dev->tx_queue_len = 100; - dev_init_buffers(dev); dev->flags = IFF_POINTOPOINT | IFF_NOARP; return dev; } diff -Nru a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c --- a/drivers/s390/net/netiucv.c Wed Apr 2 22:24:06 2003 +++ b/drivers/s390/net/netiucv.c Wed Apr 2 22:24:06 2003 @@ -1630,7 +1630,6 @@ dev->addr_len = 0; dev->type = ARPHRD_SLIP; dev->tx_queue_len = NETIUCV_QUEUELEN_DEFAULT; - dev_init_buffers(dev); dev->flags = IFF_POINTOPOINT | IFF_NOARP; return dev; } diff -Nru a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c --- a/drivers/scsi/3w-xxxx.c Wed Apr 2 22:24:07 2003 +++ b/drivers/scsi/3w-xxxx.c Wed Apr 2 22:24:07 2003 @@ -677,7 +677,7 @@ dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_AEN_LISTEN.\n"); memset(tw_ioctl->data_buffer, 0, tw_ioctl->data_buffer_length); - spin_lock_irqsave(&tw_dev->host->host_lock, flags); + spin_lock_irqsave(tw_dev->host->host_lock, flags); if (tw_dev->aen_head == tw_dev->aen_tail) { tw_aen_code = TW_AEN_QUEUE_EMPTY; } else { @@ -688,7 +688,7 @@ tw_dev->aen_head = tw_dev->aen_head + 1; } } - spin_unlock_irqrestore(&tw_dev->tw_lock, flags); + spin_unlock_irqrestore(tw_dev->host->host_lock, flags); memcpy(tw_ioctl->data_buffer, &tw_aen_code, sizeof(tw_aen_code)); break; case TW_CMD_PACKET_WITH_DATA: diff -Nru a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig --- a/drivers/scsi/Kconfig Wed Apr 2 22:24:07 2003 +++ b/drivers/scsi/Kconfig Wed Apr 2 22:24:07 2003 @@ -1715,6 +1715,11 @@ If you have the NEC PC-9801-55 SCSI interface card or compatibles for NEC PC-9801/PC-9821, say Y. +config WD33C93_PIO + bool + depends on SCSI_PC980155 + default y + # bool 'Cyberstorm Mk III SCSI support (EXPERIMENTAL)' CONFIG_CYBERSTORMIII_SCSI # bool 'GVP Turbo 040/060 SCSI support (EXPERIMENTAL)' CONFIG_GVP_TURBO_SCSI endmenu diff -Nru a/drivers/scsi/Makefile b/drivers/scsi/Makefile --- a/drivers/scsi/Makefile Wed Apr 2 22:24:07 2003 +++ b/drivers/scsi/Makefile Wed Apr 2 22:24:07 2003 @@ -29,6 +29,7 @@ obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o obj-$(CONFIG_A2091_SCSI) += a2091.o wd33c93.o obj-$(CONFIG_GVP11_SCSI) += gvp11.o wd33c93.o +obj-$(CONFIG_SCSI_PC980155) += pc980155.o wd33c93.o obj-$(CONFIG_MVME147_SCSI) += mvme147.o wd33c93.o obj-$(CONFIG_SGIWD93_SCSI) += sgiwd93.o wd33c93.o obj-$(CONFIG_CYBERSTORM_SCSI) += NCR53C9x.o cyberstorm.o diff -Nru a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c --- a/drivers/scsi/aha152x.c Wed Apr 2 22:24:04 2003 +++ b/drivers/scsi/aha152x.c Wed Apr 2 22:24:04 2003 @@ -221,11 +221,6 @@ **************************************************************************/ #include - -#if defined(PCMCIA) -#undef MODULE -#endif - #include #include #include @@ -244,14 +239,16 @@ #include #include #include -#include #include +#include +#include +#include +#include +#include +#include "scsi.h" #include "aha152x.h" -#include -#include -#include /* DEFINES */ @@ -338,11 +335,11 @@ resetting = 0x0400, /* BUS DEVICE RESET is pending */ }; -#if defined(MODULE) MODULE_AUTHOR("Jürgen Fischer"); MODULE_DESCRIPTION(AHA152X_REVID); MODULE_LICENSE("GPL"); +#if defined(MODULE) && !defined(PCMCIA) MODULE_PARM(io, "1-2i"); MODULE_PARM_DESC(io,"base io address of controller"); static int io[] = {0, 0}; @@ -396,6 +393,7 @@ MODULE_PARM_DESC(aha152x1, "parameters for second controller"); static int aha152x1[] = {0, 11, 7, 1, 1, 1, DELAY_DEFAULT, 0, DEBUG_DEFAULT}; #endif /* !defined(AHA152X_DEBUG) */ +#endif /* MODULE && !PCMCIA */ #ifdef __ISAPNP__ static struct isapnp_device_id id_table[] __devinitdata = { @@ -404,28 +402,13 @@ }; MODULE_DEVICE_TABLE(isapnp, id_table); #endif /* ISAPNP */ -#endif /* MODULE */ /* set by aha152x_setup according to the command line */ -static int setup_count = 0; -static int registered_count = 0; -static struct aha152x_setup { - int io_port; - int irq; - int scsiid; - int reconnect; - int parity; - int synchronous; - int delay; - int ext_trans; - int tc1550; -#if defined(AHA152X_DEBUG) - int debug; -#endif - char *conf; -} setup[2]; - +static int setup_count; +static int registered_count; +static struct aha152x_setup setup[2]; static struct Scsi_Host *aha152x_host[2]; +static Scsi_Host_Template aha152x_driver_template; /* * internal states of the host @@ -809,7 +792,7 @@ } #if defined(PCMCIA) || !defined(MODULE) -void aha152x_setup(char *str, int *ints) +static void aha152x_setup(char *str, int *ints) { if(setup_count>=ARRAY_SIZE(setup)) { printk(KERN_ERR "aha152x: you can only configure up to two controllers\n"); @@ -835,10 +818,8 @@ printk(KERN_NOTICE "aha152x: usage: aha152x=[,[," "[,[,[,[,[,]]]]]]]\n"); #endif - return; } else { setup_count++; - return; } } #endif @@ -973,7 +954,142 @@ static struct pnp_dev *pnpdev[2]; static int num_pnpdevs; #endif -int aha152x_detect(Scsi_Host_Template * tpnt) + +struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup) +{ + struct Scsi_Host *shost, *shpnt; + struct aha152x_hostdata *aha; + + /* XXX: shpnt is needed for some broken macros */ + shost = shpnt = scsi_register(&aha152x_driver_template, + sizeof(struct aha152x_hostdata)); + if (!shost) { + printk(KERN_ERR "aha152x: scsi_register failed\n"); + return NULL; + } + + aha = (struct aha152x_hostdata *)&shost->hostdata; + memset(aha, 0, sizeof(*aha)); + + shost->io_port = setup->io_port; + shost->n_io_port = IO_RANGE; + shost->irq = setup->irq; + + if (!setup->tc1550) { + aha->io_port0 = setup->io_port; + aha->io_port1 = setup->io_port; + } else { + aha->io_port0 = setup->io_port+0x10; + aha->io_port1 = setup->io_port-0x10; + } + + spin_lock_init(&aha->lock); + aha->reconnect = setup->reconnect; + aha->synchronous = setup->synchronous; + aha->parity = setup->parity; + aha->delay = setup->delay; + aha->ext_trans = setup->ext_trans; + +#if defined(AHA152X_DEBUG) + aha->debug = setup->debug; +#endif + + SETPORT(SCSIID, setup->scsiid << 4); + shost->this_id = setup->scsiid; + + if (setup->reconnect) + shost->can_queue = AHA152X_MAXQUEUE; + + /* RESET OUT */ + printk("aha152x: resetting bus...\n"); + SETPORT(SCSISEQ, SCSIRSTO); + mdelay(256); + SETPORT(SCSISEQ, 0); + mdelay(DELAY); + + reset_ports(shost); + + printk(KERN_INFO + "aha152x%d%s: " + "vital data: rev=%x, " + "io=0x%03lx (0x%03lx/0x%03lx), " + "irq=%d, " + "scsiid=%d, " + "reconnect=%s, " + "parity=%s, " + "synchronous=%s, " + "delay=%d, " + "extended translation=%s\n", + shost->host_no, setup->tc1550 ? " (tc1550 mode)" : "", + GETPORT(REV) & 0x7, + shost->io_port, aha->io_port0, aha->io_port1, + shost->irq, + shost->this_id, + aha->reconnect ? "enabled" : "disabled", + aha->parity ? "enabled" : "disabled", + aha->synchronous ? "enabled" : "disabled", + aha->delay, + aha->ext_trans ? "enabled" : "disabled"); + + if (!request_region(shost->io_port, IO_RANGE, "aha152x")) + goto out_unregister; + + /* not expecting any interrupts */ + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, 0); + + if (request_irq(shost->irq, swintr, SA_INTERRUPT|SA_SHIRQ, + "aha152x", shost) < 0) { + printk(KERN_ERR "aha152x%d: driver needs an IRQ.\n", shost->host_no); + goto out_release_region; + } + + aha->swint = 0; + + printk(KERN_INFO "aha152x%d: trying software interrupt, ", + shost->host_no); + SETPORT(DMACNTRL0, SWINT|INTEN); + mdelay(1000); + free_irq(shost->irq, shost); + + if (!aha->swint) { + if (TESTHI(DMASTAT, INTSTAT)) { + printk("lost.\n"); + } else { + printk("failed.\n"); + } + + SETPORT(DMACNTRL0, INTEN); + + printk(KERN_ERR "aha152x%d: IRQ %d possibly wrong. " + "Please verify.\n", shost->host_no, shost->irq); + goto out_release_region; + } + printk("ok.\n"); + + + /* clear interrupts */ + SETPORT(SSTAT0, 0x7f); + SETPORT(SSTAT1, 0xef); + + if (request_irq(shost->irq, intr, SA_INTERRUPT|SA_SHIRQ, + "aha152x", shost) < 0) { + printk(KERN_ERR "aha152x%d: failed to reassign interrupt.\n", + shost->host_no); + goto out_release_region; + } + + aha152x_host[registered_count] = shost; + return shost; /* the pcmcia stub needs the return value; */ + +out_release_region: + release_region(shost->io_port, IO_RANGE); +out_unregister: + scsi_unregister(shost); + return NULL; +} + +static int aha152x_detect(Scsi_Host_Template * tpnt) { int i, j, ok; #if defined(AUTOCONF) @@ -982,10 +1098,6 @@ struct pnp_dev *dev = NULL; #endif #endif - tpnt->proc_name = "aha152x"; - - for (i = 0; i < ARRAY_SIZE(aha152x_host); i++) - aha152x_host[i] = (struct Scsi_Host *) NULL; if (setup_count) { printk(KERN_INFO "aha152x: processing commandline: "); @@ -1040,7 +1152,7 @@ } #endif -#if defined(MODULE) +#if defined(MODULE) && !defined(PCMCIA) if (setup_countio_port = setup[i].io_port; - shpnt->n_io_port = IO_RANGE; - shpnt->irq = setup[i].irq; - - if(!setup[i].tc1550) { - HOSTIOPORT0 = setup[i].io_port; - HOSTIOPORT1 = setup[i].io_port; - } else { - HOSTIOPORT0 = setup[i].io_port+0x10; - HOSTIOPORT1 = setup[i].io_port-0x10; - } - - ISSUE_SC = 0; - CURRENT_SC = 0; - DONE_SC = 0; - DISCONNECTED_SC = 0; - - QLOCK = SPIN_LOCK_UNLOCKED; - - STATE = 0; - PREVSTATE = 0; - LASTSTATE = 0; - - MSGILEN = 0; - MSGOLEN = 0; - - RECONNECT = setup[i].reconnect; - SYNCHRONOUS = setup[i].synchronous; - PARITY = setup[i].parity; - DELAY = setup[i].delay; - EXT_TRANS = setup[i].ext_trans; -#if defined(AHA152X_DEBUG) - HOSTDATA(shpnt)->debug = setup[i].debug; -#endif - HOSTDATA(shpnt)->in_intr = 0; - HOSTDATA(shpnt)->commands = 0; - -#if defined(AHA152X_STAT) - HOSTDATA(shpnt)->total_commands=0; - HOSTDATA(shpnt)->disconnections=0; - HOSTDATA(shpnt)->busfree_without_any_action=0; - HOSTDATA(shpnt)->busfree_without_old_command=0; - HOSTDATA(shpnt)->busfree_without_new_command=0; - HOSTDATA(shpnt)->busfree_without_done_command=0; - HOSTDATA(shpnt)->busfree_with_check_condition=0; - for (j = idle; jcount[j]=0; - HOSTDATA(shpnt)->count_trans[j]=0; - HOSTDATA(shpnt)->time[j]=0; - } -#endif - - for (j = 0; j < 8; j++) { - HOSTDATA(shpnt)->syncrate[j] = 0; - HOSTDATA(shpnt)->syncneg[j] = 0; - } - - SETPORT(SCSIID, setup[i].scsiid << 4); - shpnt->this_id = setup[i].scsiid; - - if (setup[i].reconnect) - shpnt->can_queue = AHA152X_MAXQUEUE; - - /* RESET OUT */ - printk("aha152x: resetting bus...\n"); - SETPORT(SCSISEQ, SCSIRSTO); - mdelay(256); - SETPORT(SCSISEQ, 0); - mdelay(DELAY); - - reset_ports(shpnt); - - printk(KERN_INFO - "aha152x%d%s: " - "vital data: rev=%x, " - "io=0x%03lx (0x%03lx/0x%03lx), " - "irq=%d, " - "scsiid=%d, " - "reconnect=%s, " - "parity=%s, " - "synchronous=%s, " - "delay=%d, " - "extended translation=%s\n", - HOSTNO, setup[i].tc1550 ? " (tc1550 mode)" : "", - GETPORT(REV) & 0x7, - shpnt->io_port, HOSTIOPORT0, HOSTIOPORT1, - shpnt->irq, - shpnt->this_id, - RECONNECT ? "enabled" : "disabled", - PARITY ? "enabled" : "disabled", - SYNCHRONOUS ? "enabled" : "disabled", - DELAY, - EXT_TRANS ? "enabled" : "disabled"); - - request_region(shpnt->io_port, IO_RANGE, "aha152x"); - - /* not expecting any interrupts */ - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, 0); - - ok = request_irq(shpnt->irq, swintr, SA_INTERRUPT|SA_SHIRQ, "aha152x", shpnt); - if (ok < 0) { - if (ok==-EINVAL) - printk(KERN_ERR "aha152x%d: bad IRQ %d.\n", HOSTNO, shpnt->irq); - else if(ok==-EBUSY) - printk(KERN_ERR "aha152x%d: IRQ %d already in use.\n", HOSTNO, shpnt->irq); - else - printk(KERN_ERR "aha152x%d: Unexpected error code %d on requesting IRQ %d.\n", HOSTNO, ok, shpnt->irq); - - printk(KERN_ERR "aha152x%d: driver needs an IRQ.\n", HOSTNO); - - scsi_unregister(shpnt); - registered_count--; - release_region(shpnt->io_port, IO_RANGE); - aha152x_host[registered_count] = 0; - shpnt = 0; - continue; - } - HOSTDATA(shpnt)->swint = 0; - - printk(KERN_INFO "aha152x%d: trying software interrupt, ", HOSTNO); - SETPORT(DMACNTRL0, SWINT|INTEN); - mdelay(1000); - free_irq(shpnt->irq, shpnt); - - if (!HOSTDATA(shpnt)->swint) { - if (TESTHI(DMASTAT, INTSTAT)) { - printk("lost.\n"); - } else { - printk("failed.\n"); - } - - SETPORT(DMACNTRL0, INTEN); - - printk(KERN_ERR "aha152x%d: IRQ %d possibly wrong. Please verify.\n", HOSTNO, shpnt->irq); - - registered_count--; - release_region(shpnt->io_port, IO_RANGE); - aha152x_host[registered_count] = 0; - scsi_unregister(shpnt); - shpnt=NULL; - continue; - } - printk("ok.\n"); - - - /* clear interrupts */ - SETPORT(SSTAT0, 0x7f); - SETPORT(SSTAT1, 0xef); - - if (request_irq(shpnt->irq, intr, SA_INTERRUPT|SA_SHIRQ, "aha152x", shpnt) < 0) { - printk(KERN_ERR "aha152x%d: failed to reassign interrupt.\n", HOSTNO); - - registered_count--; - release_region(shpnt->io_port, IO_RANGE); - aha152x_host[registered_count] = 0; - scsi_unregister(shpnt); - shpnt=NULL; - continue; - } + aha152x_probe_one(&setup[i]); + if (aha152x_host[registered_count]) + registered_count++; } return registered_count>0; } -int aha152x_release(struct Scsi_Host *shpnt) +static int aha152x_release(struct Scsi_Host *shpnt) { if (shpnt->irq) free_irq(shpnt->irq, shpnt); @@ -1474,7 +1417,7 @@ /* * Queue a command and setup interrupts for a free bus. */ -int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct semaphore *sem, int phase, Scsi_Cmnd *done_SC, void (*done)(Scsi_Cmnd *)) +static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct semaphore *sem, int phase, Scsi_Cmnd *done_SC, void (*done)(Scsi_Cmnd *)) { struct Scsi_Host *shpnt = SCpnt->device->host; unsigned long flags; @@ -1543,7 +1486,7 @@ return 0; } -int aha152x_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +static int aha152x_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { #if 0 if(*SCpnt->cmnd == REQUEST_SENSE) { @@ -1562,7 +1505,7 @@ * run a command * */ -void internal_done(Scsi_Cmnd *SCpnt) +static void internal_done(Scsi_Cmnd *SCpnt) { #if 0 struct Scsi_Host *shpnt = SCpnt->host; @@ -1573,7 +1516,7 @@ up(SCSEM(SCpnt)); } -int aha152x_command(Scsi_Cmnd * SCpnt) +static int aha152x_command(Scsi_Cmnd * SCpnt) { DECLARE_MUTEX_LOCKED(sem); @@ -1587,7 +1530,7 @@ * Abort a command * */ -int aha152x_abort(Scsi_Cmnd *SCpnt) +static int aha152x_abort(Scsi_Cmnd *SCpnt) { struct Scsi_Host *shpnt = SCpnt->device->host; Scsi_Cmnd *ptr; @@ -1661,7 +1604,7 @@ * FIXME: never seen this live. might lockup... * */ -int aha152x_device_reset(Scsi_Cmnd * SCpnt) +static int aha152x_device_reset(Scsi_Cmnd * SCpnt) { struct Scsi_Host *shpnt = SCpnt->device->host; DECLARE_MUTEX_LOCKED(sem); @@ -1719,7 +1662,7 @@ return ret; } -void free_hard_reset_SCs(struct Scsi_Host *shpnt, Scsi_Cmnd **SCs) +static void free_hard_reset_SCs(struct Scsi_Host *shpnt, Scsi_Cmnd **SCs) { Scsi_Cmnd *ptr; unsigned long flags; @@ -1748,7 +1691,7 @@ * Reset the bus * */ -int aha152x_bus_reset(Scsi_Cmnd *SCpnt) +static int aha152x_bus_reset(Scsi_Cmnd *SCpnt) { struct Scsi_Host *shpnt = SCpnt->device->host; unsigned long flags; @@ -1843,7 +1786,7 @@ * Return the "logical geometry" * */ -int aha152x_biosparam(struct scsi_device *sdev, struct block_device *bdev, +static int aha152x_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int *info_array) { struct Scsi_Host *shpnt = sdev->host; @@ -3744,7 +3687,7 @@ return (pos - start); } -int aha152x_set_info(char *buffer, int length, struct Scsi_Host *shpnt) +static int aha152x_set_info(char *buffer, int length, struct Scsi_Host *shpnt) { if(!shpnt || !buffer || length<8 || strncmp("aha152x ", buffer, 8)!=0) return -EINVAL; @@ -3791,7 +3734,7 @@ #define SPRINTF(args...) \ do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0) -int aha152x_proc_info(char *buffer, char **start, +static int aha152x_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) { int i; @@ -3935,7 +3878,28 @@ return thislength < length ? thislength : length; } -/* Eventually this will go into an include file, but this will be later */ -static Scsi_Host_Template driver_template = AHA152X; +static Scsi_Host_Template aha152x_driver_template = { + .module = THIS_MODULE, + .name = AHA152X_REVID, + .proc_name = "aha152x", + .proc_info = aha152x_proc_info, + .detect = aha152x_detect, + .command = aha152x_command, + .queuecommand = aha152x_queue, + .eh_abort_handler = aha152x_abort, + .eh_device_reset_handler = aha152x_device_reset, + .eh_bus_reset_handler = aha152x_bus_reset, + .eh_host_reset_handler = aha152x_host_reset, + .release = aha152x_release, + .bios_param = aha152x_biosparam, + .can_queue = 1, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = 1, + .use_clustering = DISABLE_CLUSTERING, +}; +#ifndef PCMCIA +#define driver_template aha152x_driver_template #include "scsi_module.c" +#endif diff -Nru a/drivers/scsi/aha152x.h b/drivers/scsi/aha152x.h --- a/drivers/scsi/aha152x.h Wed Apr 2 22:24:06 2003 +++ b/drivers/scsi/aha152x.h Wed Apr 2 22:24:06 2003 @@ -5,54 +5,12 @@ * $Id: aha152x.h,v 2.5 2002/04/14 11:24:12 fischer Exp $ */ -#if defined(__KERNEL__) - -#include -#include "scsi.h" -#include -#include - -int aha152x_detect(Scsi_Host_Template *); -int aha152x_command(Scsi_Cmnd *); -int aha152x_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -int aha152x_abort(Scsi_Cmnd *); -int aha152x_release(struct Scsi_Host *shpnt); -int aha152x_device_reset(Scsi_Cmnd *); -int aha152x_bus_reset(Scsi_Cmnd *); -int aha152x_host_reset(Scsi_Cmnd *); -int aha152x_biosparam(struct scsi_device *, struct block_device *, - sector_t, int*); -int aha152x_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout); - /* number of queueable commands (unless we support more than 1 cmd_per_lun this should do) */ #define AHA152X_MAXQUEUE 7 #define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 2.5 $" -/* Initial value of Scsi_Host entry */ -#define AHA152X { .proc_name = "aha152x", \ - .proc_info = aha152x_proc_info, \ - .name = AHA152X_REVID, \ - .detect = aha152x_detect, \ - .command = aha152x_command, \ - .queuecommand = aha152x_queue, \ - .eh_abort_handler = aha152x_abort, \ - .eh_device_reset_handler = aha152x_device_reset, \ - .eh_bus_reset_handler = aha152x_bus_reset, \ - .eh_host_reset_handler = aha152x_host_reset, \ - .release = aha152x_release, \ - .bios_param = aha152x_biosparam, \ - .can_queue = 1, \ - .this_id = 7, \ - .sg_tablesize = SG_ALL, \ - .cmd_per_lun = 1, \ - .present = 0, \ - .unchecked_isa_dma = 0, \ - .use_clustering = DISABLE_CLUSTERING } -#endif - - /* port addresses */ #define SCSISEQ (HOSTIOPORT0+0x00) /* SCSI sequence control */ #define SXFRCTL0 (HOSTIOPORT0+0x01) /* SCSI transfer control 0 */ @@ -354,5 +312,25 @@ debug_phases = 0x2000, }; #endif + +/* for the pcmcia stub */ +struct aha152x_setup { + int io_port; + int irq; + int scsiid; + int reconnect; + int parity; + int synchronous; + int delay; + int ext_trans; + int tc1550; +#if defined(AHA152X_DEBUG) + int debug; +#endif + char *conf; +}; + +struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *); +int aha152x_host_reset(struct scsi_cmnd *); #endif /* _AHA152X_H */ diff -Nru a/drivers/scsi/pc980155.c b/drivers/scsi/pc980155.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/scsi/pc980155.c Wed Apr 2 22:24:08 2003 @@ -0,0 +1,299 @@ +/* + * + * drivers/scsi/pc980155.c + * + * PC-9801-55 SCSI host adapter driver + * + * Copyright (C) 1997-2003 Kyoto University Microcomputer Club + * (Linux/98 project) + * Tomoharu Ugawa + * + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "scsi.h" +#include "hosts.h" +#include "wd33c93.h" +#include "pc980155.h" + +extern int pc98_bios_param(struct scsi_device *, struct block_device *, + sector_t, int *); +static int scsi_pc980155_detect(Scsi_Host_Template *); +static int scsi_pc980155_release(struct Scsi_Host *); + +#ifndef CMD_PER_LUN +#define CMD_PER_LUN 2 +#endif + +#ifndef CAN_QUEUE +#define CAN_QUEUE 16 +#endif + +#undef PC_9801_55_DEBUG +#undef PC_9801_55_DEBUG_VERBOSE + +#define NR_BASE_IOS 4 +static int nr_base_ios = NR_BASE_IOS; +static unsigned int base_ios[NR_BASE_IOS] = {0xcc0, 0xcd0, 0xce0, 0xcf0}; +static wd33c93_regs init_regs; +static int io; + +static struct Scsi_Host *pc980155_host = NULL; + +static void pc980155_intr_handle(int irq, void *dev_id, struct pt_regs *regp); + +static inline void pc980155_dma_enable(unsigned int base_io) +{ + outb(0x01, REG_CWRITE); +} + +static inline void pc980155_dma_disable(unsigned int base_io) +{ + outb(0x02, REG_CWRITE); +} + + +static void pc980155_intr_handle(int irq, void *dev_id, struct pt_regs *regp) +{ + wd33c93_intr(pc980155_host); +} + +static int dma_setup(Scsi_Cmnd *sc, int dir_in) +{ + /* + * sc->SCp.this_residual : transfer count + * sc->SCp.ptr : distination address (virtual address) + * dir_in : data direction (DATA_OUT_DIR:0 or DATA_IN_DIR:1) + * + * if success return 0 + */ + + /* + * DMA WRITE MODE + * bit 7,6 01b single mode (this mode only) + * bit 5 inc/dec (default:0 = inc) + * bit 4 auto initialize (normaly:0 = off) + * bit 3,2 01b memory -> io + * 10b io -> memory + * 00b verify + * bit 1,0 channel + */ + disable_dma(sc->device->host->dma_channel); + set_dma_mode(sc->device->host->dma_channel, + 0x40 | (dir_in ? 0x04 : 0x08)); + clear_dma_ff(sc->device->host->dma_channel); + set_dma_addr(sc->device->host->dma_channel, virt_to_phys(sc->SCp.ptr)); + set_dma_count(sc->device->host->dma_channel, sc->SCp.this_residual); +#ifdef PC_9801_55_DEBUG + printk("D%d(%x)D", sc->device->host->dma_channel, + sc->SCp.this_residual); +#endif + enable_dma(sc->device->host->dma_channel); + pc980155_dma_enable(sc->device->host->io_port); + return 0; +} + +static void dma_stop(struct Scsi_Host *instance, Scsi_Cmnd *sc, int status) +{ + /* + * instance: Hostadapter's instance + * sc: scsi command + * status: True if success + */ + pc980155_dma_disable(sc->device->host->io_port); + disable_dma(sc->device->host->dma_channel); +} + +/* return non-zero on detection */ +static inline int pc980155_test_port(wd33c93_regs regs) +{ + /* Quick and dirty test for presence of the card. */ + if (inb(regs.SASR) == 0xff) + return 0; + + return 1; +} + +static inline int pc980155_getconfig(unsigned int base_io, wd33c93_regs regs, + unsigned char* irq, unsigned char* dma, + unsigned char* scsi_id) +{ + static unsigned char irqs[] = {3, 5, 6, 9, 12, 13}; + unsigned char result; + + printk(KERN_DEBUG "PC-9801-55: base_io=%x SASR=%x SCMD=%x\n", + base_io, regs.SASR, regs.SCMD); + result = read_pc980155_resetint(regs); + printk(KERN_DEBUG "PC-9801-55: getting config (%x)\n", result); + *scsi_id = result & 0x07; + *irq = (result >> 3) & 0x07; + if (*irq > 5) { + printk(KERN_ERR "PC-9801-55 (base %#x): impossible IRQ (%d)" + " - other device here?\n", base_io, *irq); + return 0; + } + + *irq = irqs[*irq]; + result = inb(REG_STATRD); + *dma = result & 0x03; + if (*dma == 1) { + printk(KERN_ERR + "PC-9801-55 (base %#x): impossible DMA channl (%d)" + " - other device here?\n", base_io, *dma); + return 0; + } +#ifdef PC_9801_55_DEBUG + printk("PC-9801-55: end of getconfig\n"); +#endif + return 1; +} + +/* return non-zero on detection */ +static int scsi_pc980155_detect(Scsi_Host_Template* tpnt) +{ + unsigned int base_io; + unsigned char irq, dma, scsi_id; + int i; +#ifdef PC_9801_55_DEBUG + unsigned char debug; +#endif + + if (io) { + base_ios[0] = io; + nr_base_ios = 1; + } + + for (i = 0; i < nr_base_ios; i++) { + base_io = base_ios[i]; + init_regs.SASR = REG_ADDRST; + init_regs.SCMD = REG_CONTRL; +#ifdef PC_9801_55_DEBUG + printk("PC-9801-55: SASR(%x = %x)\n", SASR, REG_ADDRST); +#endif + if (!request_region(base_io, 6, "PC-9801-55")) + continue; + + if (pc980155_test_port(init_regs) && + pc980155_getconfig(base_io, init_regs, + &irq, &dma, &scsi_id)) + goto found; + + release_region(base_io, 6); + } + + printk("PC-9801-55: not found\n"); + return 0; + + found: +#ifdef PC_9801_55_DEBUG + printk("PC-9801-55: config: base io = %x, irq = %d, dma channel = %d, scsi id = %d\n", base_io, irq, dma, scsi_id); +#endif + if (request_irq(irq, pc980155_intr_handle, 0, "PC-9801-55", NULL)) { + printk(KERN_ERR "PC-9801-55: unable to allocate IRQ %d\n", irq); + goto err1; + } + + if (request_dma(dma, "PC-9801-55")) { + printk(KERN_ERR "PC-9801-55: unable to allocate DMA channel %d\n", dma); + goto err2; + } + + pc980155_host = scsi_register(tpnt, sizeof(struct WD33C93_hostdata)); + if (pc980155_host) { + pc980155_host->this_id = scsi_id; + pc980155_host->io_port = base_io; + pc980155_host->n_io_port = 6; + pc980155_host->irq = irq; + pc980155_host->dma_channel = dma; + printk("PC-9801-55: scsi host found at %x irq = %d, use dma channel %d.\n", base_io, irq, dma); + pc980155_int_enable(init_regs); + wd33c93_init(pc980155_host, init_regs, dma_setup, dma_stop, + WD33C93_FS_12_15); + return 1; + } + + printk(KERN_ERR "PC-9801-55: failed to register device\n"); + +err2: + free_irq(irq, NULL); +err1: + release_region(base_io, 6); + return 0; +} + +static int scsi_pc980155_release(struct Scsi_Host *shost) +{ + struct WD33C93_hostdata *hostdata + = (struct WD33C93_hostdata *)shost->hostdata; + + pc980155_int_disable(hostdata->regs); + release_region(shost->io_port, shost->n_io_port); + free_irq(shost->irq, NULL); + free_dma(shost->dma_channel); + wd33c93_release(); + return 1; +} + +static int pc980155_bus_reset(Scsi_Cmnd *cmd) +{ + struct WD33C93_hostdata *hostdata + = (struct WD33C93_hostdata *)cmd->device->host->hostdata; + + pc980155_int_disable(hostdata->regs); + pc980155_assert_bus_reset(hostdata->regs); + udelay(50); + pc980155_negate_bus_reset(hostdata->regs); + (void) inb(hostdata->regs.SASR); + (void) read_pc980155(hostdata->regs, WD_SCSI_STATUS); + pc980155_int_enable(hostdata->regs); + wd33c93_host_reset(cmd); + return SUCCESS; +} + + +#ifndef MODULE +static int __init pc980155_setup(char *str) +{ + int ints[4]; + + str = get_options(str, ARRAY_SIZE(ints), ints); + if (ints[0] > 0) + io = ints[1]; + return 1; +} +__setup("pc980155_io=", pc980155_setup); +#endif + +MODULE_PARM(io, "i"); +MODULE_AUTHOR("Tomoharu Ugawa "); +MODULE_DESCRIPTION("PC-9801-55 SCSI host adapter driver"); +MODULE_LICENSE("GPL"); + +static Scsi_Host_Template driver_template = { + .proc_info = wd33c93_proc_info, + .name = "SCSI PC-9801-55", + .detect = scsi_pc980155_detect, + .release = scsi_pc980155_release, + .queuecommand = wd33c93_queuecommand, + .eh_abort_handler = wd33c93_abort, + .eh_bus_reset_handler = pc980155_bus_reset, + .eh_host_reset_handler = wd33c93_host_reset, + .bios_param = pc98_bios_param, + .can_queue = CAN_QUEUE, + .this_id = 7, + .sg_tablesize = SG_ALL, + .cmd_per_lun = CMD_PER_LUN, /* dont use link command */ + .unchecked_isa_dma = 1, /* use dma **XXXX***/ + .use_clustering = ENABLE_CLUSTERING, + .proc_name = "PC_9801_55", +}; + +#include "scsi_module.c" diff -Nru a/drivers/scsi/pc980155.h b/drivers/scsi/pc980155.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/scsi/pc980155.h Wed Apr 2 22:24:08 2003 @@ -0,0 +1,52 @@ +/* + * + * drivers/scsi/pc980155.h + * + * PC-9801-55 SCSI host adapter driver + * + * Copyright (C) 1997-2003 Kyoto University Microcomputer Club + * (Linux/98 project) + * Tomoharu Ugawa + * + */ + +#ifndef __PC980155_H +#define __PC980155_H + +#include "wd33c93.h" + +#define REG_ADDRST (base_io) +#define REG_CONTRL (base_io + 2) +#define REG_CWRITE (base_io + 4) +#define REG_STATRD (base_io + 4) + +#define WD_MEMORYBANK 0x30 +#define WD_RESETINT 0x33 + +static inline uchar read_pc980155(const wd33c93_regs regs, uchar reg_num) +{ + outb(reg_num, regs.SASR); + return (uchar)inb(regs.SCMD); +} + +static inline void write_memorybank(const wd33c93_regs regs, uchar value) +{ + outb(WD_MEMORYBANK, regs.SASR); + outb(value, regs.SCMD); +} + +#define read_pc980155_resetint(regs) \ + read_pc980155((regs), WD_RESETINT) +#define pc980155_int_enable(regs) \ + write_memorybank((regs), read_pc980155((regs), WD_MEMORYBANK) | 0x04) + +#define pc980155_int_disable(regs) \ + write_memorybank((regs), read_pc980155((regs), WD_MEMORYBANK) & ~0x04) + +#define pc980155_assert_bus_reset(regs) \ + write_memorybank((regs), read_pc980155((regs), WD_MEMORYBANK) | 0x02) + +#define pc980155_negate_bus_reset(regs) \ + write_memorybank((regs), read_pc980155((regs), WD_MEMORYBANK) & ~0x02) + +#endif /* __PC980155_H */ diff -Nru a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c --- a/drivers/scsi/pcmcia/aha152x_stub.c Wed Apr 2 22:24:07 2003 +++ b/drivers/scsi/pcmcia/aha152x_stub.c Wed Apr 2 22:24:07 2003 @@ -49,6 +49,7 @@ #include "scsi.h" #include "hosts.h" +#include "aha152x.h" #include #include @@ -102,8 +103,6 @@ dev_node_t node[8]; } scsi_info_t; -extern void aha152x_setup(char *str, int *ints); - static void aha152x_release_cs(u_long arg); static int aha152x_event(event_t event, int priority, event_callback_args_t *args); @@ -111,11 +110,7 @@ static dev_link_t *aha152x_attach(void); static void aha152x_detach(dev_link_t *); -#define driver_template aha152x_driver_template -extern Scsi_Host_Template aha152x_driver_template; - -static dev_link_t *dev_list = NULL; - +static dev_link_t *dev_list; static dev_info_t dev_info = "aha152x_cs"; /*====================================================================*/ @@ -227,11 +222,12 @@ { client_handle_t handle = link->handle; scsi_info_t *info = link->priv; + struct aha152x_setup s; tuple_t tuple; cisparse_t parse; - int i, last_ret, last_fn, ints[8]; + int i, last_ret, last_fn; u_char tuple_data[64]; - Scsi_Device *dev; + struct scsi_device *dev; dev_node_t *node, **tail; struct Scsi_Host *host; @@ -247,7 +243,6 @@ link->conf.ConfigBase = parse.config.base; /* Configure card */ - driver_template.module = &__this_module; link->state |= DEV_CONFIG; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; @@ -276,29 +271,32 @@ /* A bad hack... */ release_region(link->io.BasePort1, link->io.NumPorts1); - + /* Set configuration options for the aha152x driver */ - ints[0] = 7; - ints[1] = link->io.BasePort1; - ints[2] = link->irq.AssignedIRQ; - ints[3] = host_id; - ints[4] = reconnect; - ints[5] = parity; - ints[6] = synchronous; - ints[7] = reset_delay; - if (ext_trans) { - ints[8] = ext_trans; ints[0] = 8; - } - aha152x_setup("PCMCIA setup", ints); - - scsi_register_host(&driver_template); + memset(&s, 0, sizeof(s)); + s.conf = "PCMCIA setup"; + s.io_port = link->io.BasePort1; + s.irq = link->irq.AssignedIRQ; + s.scsiid = host_id; + s.reconnect = reconnect; + s.parity = parity; + s.synchronous = synchronous; + s.delay = reset_delay; + if (ext_trans) + s.ext_trans = ext_trans; tail = &link->dev; info->ndev = 0; - for (host = scsi_host_get_next(NULL); host; - host = scsi_host_get_next(host)) - if (host->hostt == &driver_template) - list_for_each_entry (dev, &host->my_devices, siblings) { + + host = aha152x_probe_one(&s); + if (host == NULL) { + printk(KERN_INFO "aha152x_cs: no SCSI devices found\n"); + goto cs_failed; + } + + scsi_add_host(host, NULL); + + list_for_each_entry(dev, &host->my_devices, siblings) { u_long arg[2], id; kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg); id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) + @@ -328,11 +326,9 @@ *tail = node; tail = &node->next; info->ndev++; info->host = dev->host; - } + } + *tail = NULL; - if (info->ndev == 0) - printk(KERN_INFO "aha152x_cs: no SCSI devices found\n"); - link->state &= ~DEV_CONFIG_PENDING; return; @@ -340,41 +336,26 @@ cs_error(link->handle, last_fn, last_ret); aha152x_release_cs((u_long)link); return; - -} /* aha152x_config_cs */ - -/*====================================================================*/ +} static void aha152x_release_cs(u_long arg) { - dev_link_t *link = (dev_link_t *)arg; - - DEBUG(0, "aha152x_release_cs(0x%p)\n", link); + dev_link_t *link = (dev_link_t *)arg; + scsi_info_t *info = link->priv; -#warning This does not protect you. You need some real fix for your races. -#if 0 - if (GET_USE_COUNT(driver_template.module) != 0) { - DEBUG(1, "aha152x_cs: release postponed, " - "device still open\n"); - link->state |= DEV_STALE_CONFIG; - return; - } -#endif - - scsi_unregister_host(&driver_template); - link->dev = NULL; + scsi_remove_host(info->host); + link->dev = NULL; - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); - - link->state &= ~DEV_CONFIG; - if (link->state & DEV_STALE_LINK) - aha152x_detach(link); + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); -} /* aha152x_release_cs */ + link->state &= ~DEV_CONFIG; + scsi_unregister(info->host); -/*====================================================================*/ + if (link->state & DEV_STALE_LINK) + aha152x_detach(link); +} static int aha152x_event(event_t event, int priority, event_callback_args_t *args) @@ -414,28 +395,29 @@ break; } return 0; -} /* aha152x_event */ +} -/*====================================================================*/ +static struct pcmcia_driver aha152x_cs_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "aha152x_cs", + }, + .attach = aha152x_attach, + .detach = aha152x_detach, +}; -static int __init init_aha152x_cs(void) { - servinfo_t serv; - DEBUG(0, "%s\n", version); - CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "aha152x_cs: Card Services release " - "does not match!\n"); - return -1; - } - register_pccard_driver(&dev_info, &aha152x_attach, &aha152x_detach); - return 0; +static int __init init_aha152x_cs(void) +{ + return pcmcia_register_driver(&aha152x_cs_driver); } -static void __exit exit_aha152x_cs(void) { - DEBUG(0, "aha152x_cs: unloading\n"); - unregister_pccard_driver(&dev_info); - while (dev_list != NULL) - aha152x_detach(dev_list); +static void __exit exit_aha152x_cs(void) +{ + pcmcia_unregister_driver(&aha152x_cs_driver); + + /* XXX: this really needs to move into generic code.. */ + while (dev_list != NULL) + aha152x_detach(dev_list); } module_init(init_aha152x_cs); diff -Nru a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c --- a/drivers/scsi/pcmcia/fdomain_stub.c Wed Apr 2 22:24:06 2003 +++ b/drivers/scsi/pcmcia/fdomain_stub.c Wed Apr 2 22:24:06 2003 @@ -379,26 +379,27 @@ return 0; } /* fdomain_event */ -/*====================================================================*/ +static struct pcmcia_driver fdomain_cs_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "fdomain_cs", + }, + .attach = fdomain_attach, + .detach = fdomain_detach, +}; -static int __init init_fdomain_cs(void) { - servinfo_t serv; - DEBUG(0, "%s\n", version); - CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "fdomain_cs: Card Services release " - "does not match!\n"); - return -1; - } - register_pccard_driver(&dev_info, &fdomain_attach, &fdomain_detach); - return 0; +static int __init init_fdomain_cs(void) +{ + return pcmcia_register_driver(&fdomain_cs_driver); } -static void __exit exit_fdomain_cs(void) { - DEBUG(0, "fdomain_cs: unloading\n"); - unregister_pccard_driver(&dev_info); - while (dev_list != NULL) - fdomain_detach(dev_list); +static void __exit exit_fdomain_cs(void) +{ + pcmcia_unregister_driver(&fdomain_cs_driver); + + /* XXX: this really needs to move into generic code.. */ + while (dev_list != NULL) + fdomain_detach(dev_list); } module_init(init_fdomain_cs); diff -Nru a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c --- a/drivers/scsi/pcmcia/nsp_cs.c Wed Apr 2 22:24:07 2003 +++ b/drivers/scsi/pcmcia/nsp_cs.c Wed Apr 2 22:24:07 2003 @@ -62,7 +62,6 @@ #include #include #include -#include #include "nsp_cs.h" @@ -93,7 +92,6 @@ int ndev; dev_node_t node[8]; int stop; - struct bus_operations *bus; } scsi_info_t; @@ -1948,7 +1946,6 @@ case CS_EVENT_CARD_INSERTION: DEBUG(0, " event: insert\n"); link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - info->bus = args->bus; nsp_cs_config(link); break; diff -Nru a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c --- a/drivers/scsi/pcmcia/qlogic_stub.c Wed Apr 2 22:24:05 2003 +++ b/drivers/scsi/pcmcia/qlogic_stub.c Wed Apr 2 22:24:05 2003 @@ -397,25 +397,26 @@ return 0; } /* qlogic_event */ -/*====================================================================*/ + +static struct pcmcia_driver qlogic_cs_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "qlogic_cs", + }, + .attach = qlogic_attach, + .detach = qlogic_detach, +}; static int __init init_qlogic_cs(void) { - servinfo_t serv; - DEBUG(0, "%s\n", version); - CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "qlogic_cs: Card Services release " "does not match!\n"); - return -1; - } - register_pccard_driver(&dev_info, &qlogic_attach, &qlogic_detach); - return 0; + return pcmcia_register_driver(&qlogic_cs_driver); } static void __exit exit_qlogic_cs(void) { - DEBUG(0, "qlogic_cs: unloading\n"); - unregister_pccard_driver(&dev_info); + pcmcia_unregister_driver(&qlogic_cs_driver); + + /* XXX: this really needs to move into generic code.. */ while (dev_list != NULL) qlogic_detach(dev_list); } diff -Nru a/drivers/scsi/qlogicfc.c b/drivers/scsi/qlogicfc.c --- a/drivers/scsi/qlogicfc.c Wed Apr 2 22:24:06 2003 +++ b/drivers/scsi/qlogicfc.c Wed Apr 2 22:24:06 2003 @@ -643,6 +643,7 @@ u_char queued; u_char host_id; struct timer_list explore_timer; + struct id_name_map tempmap[QLOGICFC_MAX_ID + 1]; }; @@ -836,22 +837,13 @@ short param[8]; int i, j; - struct id_name_map *map; /* base of array [QLOGICFC_MAX_ID + 1] */ - struct id_name_map *mapx; /* array entry pointer */ struct isp2x00_hostdata *hostdata; - hostdata = (struct isp2x00_hostdata *) host->hostdata; - - map = kmalloc((QLOGICFC_MAX_ID + 1) * sizeof(struct id_name_map), GFP_ATOMIC); - if (!map) { - printk("qlogicfc%d : error getting memory -- cannot make port database.\n", - hostdata->host_id); - goto fini; - } - memset(map, 0, (QLOGICFC_MAX_ID + 1) * sizeof(struct id_name_map)); - isp2x00_disable_irqs(host); + hostdata = (struct isp2x00_hostdata *) host->hostdata; + memset(hostdata->tempmap, 0, sizeof(hostdata->tempmap)); + #if ISP2x00_FABRIC for (i = 0x81; i < QLOGICFC_MAX_ID; i++) { param[0] = MBOX_PORT_LOGOUT; @@ -876,74 +868,72 @@ if (param[0] == MBOX_COMMAND_COMPLETE) { hostdata->port_id = ((u_int) param[3]) << 16; hostdata->port_id |= param[2]; - map->loop_id = param[1]; - map->wwn = hostdata->wwn; + hostdata->tempmap[0].loop_id = param[1]; + hostdata->tempmap[0].wwn = hostdata->wwn; } else { printk("qlogicfc%d : error getting scsi id.\n", hostdata->host_id); } - for (i = 0, mapx = map; i <= QLOGICFC_MAX_ID; i++, mapx++) - mapx->loop_id = map->loop_id; + for (i = 0; i <=QLOGICFC_MAX_ID; i++) + hostdata->tempmap[i].loop_id = hostdata->tempmap[0].loop_id; - for (i = 0, j = 1, mapx = map + 1; i <= QLOGICFC_MAX_LOOP_ID; i++) { + for (i = 0, j = 1; i <= QLOGICFC_MAX_LOOP_ID; i++) { param[0] = MBOX_GET_PORT_NAME; param[1] = (i << 8) & 0xff00; isp2x00_mbox_command(host, param); if (param[0] == MBOX_COMMAND_COMPLETE) { - mapx->loop_id = i; - mapx->wwn = ((u64) (param[2] & 0xff)) << 56; - mapx->wwn |= ((u64) ((param[2] >> 8) & 0xff)) << 48; - mapx->wwn |= ((u64) (param[3] & 0xff)) << 40; - mapx->wwn |= ((u64) ((param[3] >> 8) & 0xff)) << 32; - mapx->wwn |= ((u64) (param[6] & 0xff)) << 24; - mapx->wwn |= ((u64) ((param[6] >> 8) & 0xff)) << 16; - mapx->wwn |= ((u64) (param[7] & 0xff)) << 8; - mapx->wwn |= ((u64) ((param[7] >> 8) & 0xff)); + hostdata->tempmap[j].loop_id = i; + hostdata->tempmap[j].wwn = ((u64) (param[2] & 0xff)) << 56; + hostdata->tempmap[j].wwn |= ((u64) ((param[2] >> 8) & 0xff)) << 48; + hostdata->tempmap[j].wwn |= ((u64) (param[3] & 0xff)) << 40; + hostdata->tempmap[j].wwn |= ((u64) ((param[3] >> 8) & 0xff)) << 32; + hostdata->tempmap[j].wwn |= ((u64) (param[6] & 0xff)) << 24; + hostdata->tempmap[j].wwn |= ((u64) ((param[6] >> 8) & 0xff)) << 16; + hostdata->tempmap[j].wwn |= ((u64) (param[7] & 0xff)) << 8; + hostdata->tempmap[j].wwn |= ((u64) ((param[7] >> 8) & 0xff)); j++; - mapx++; + } } #if ISP2x00_FABRIC - isp2x00_init_fabric(host, map, j); + isp2x00_init_fabric(host, hostdata->tempmap, j); #endif - for (i = 0, mapx = map; i <= QLOGICFC_MAX_ID; i++, mapx++) { - struct id_name_map *tmap; /* second array entry pointer */ - if (mapx->wwn != hostdata->port_db[i].wwn) { - for (j = 0, tmap = map; j <= QLOGICFC_MAX_ID; j++, tmap++) { - if (tmap->wwn == hostdata->port_db[i].wwn) { - hostdata->port_db[i].loop_id = tmap->loop_id; + for (i = 0; i <= QLOGICFC_MAX_ID; i++) { + if (hostdata->tempmap[i].wwn != hostdata->port_db[i].wwn) { + for (j = 0; j <= QLOGICFC_MAX_ID; j++) { + if (hostdata->tempmap[j].wwn == hostdata->port_db[i].wwn) { + hostdata->port_db[i].loop_id = hostdata->tempmap[j].loop_id; break; } } if (j == QLOGICFC_MAX_ID + 1) - hostdata->port_db[i].loop_id = map->loop_id; + hostdata->port_db[i].loop_id = hostdata->tempmap[0].loop_id; for (j = 0; j <= QLOGICFC_MAX_ID; j++) { - if (hostdata->port_db[j].wwn == mapx->wwn || !hostdata->port_db[j].wwn) { + if (hostdata->port_db[j].wwn == hostdata->tempmap[i].wwn || !hostdata->port_db[j].wwn) { break; } } if (j == QLOGICFC_MAX_ID + 1) printk("qlogicfc%d : Too many scsi devices, no more room in port map.\n", hostdata->host_id); if (!hostdata->port_db[j].wwn) { - hostdata->port_db[j].loop_id = mapx->loop_id; - hostdata->port_db[j].wwn = mapx->wwn; + hostdata->port_db[j].loop_id = hostdata->tempmap[i].loop_id; + hostdata->port_db[j].wwn = hostdata->tempmap[i].wwn; } } else - hostdata->port_db[i].loop_id = mapx->loop_id; + hostdata->port_db[i].loop_id = hostdata->tempmap[i].loop_id; } isp2x00_enable_irqs(host); - kfree(map); -fini: + return 0; } diff -Nru a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h --- a/drivers/scsi/scsi.h Wed Apr 2 22:24:04 2003 +++ b/drivers/scsi/scsi.h Wed Apr 2 22:24:04 2003 @@ -442,6 +442,7 @@ extern int scsi_retry_command(Scsi_Cmnd *); extern int scsi_attach_device(struct scsi_device *); extern void scsi_detach_device(struct scsi_device *); +extern void scsi_rescan_device(struct scsi_device *); extern int scsi_get_device_flags(unsigned char *vendor, unsigned char *model); /* diff -Nru a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c --- a/drivers/scsi/scsi_debug.c Wed Apr 2 22:24:06 2003 +++ b/drivers/scsi/scsi_debug.c Wed Apr 2 22:24:06 2003 @@ -20,8 +20,8 @@ * add timers for delayed responses [20020721] * Patrick Mansfield max_luns+scsi_level [20021031] * Mike Anderson sysfs work [20021118] - * dpg: change style of boot options to "scsi_debug.num_devs=2" and - * module options to "modprobe scsi_debug num_devs=2" [20021221] + * dpg: change style of boot options to "scsi_debug.num_tgts=2" and + * module options to "modprobe scsi_debug num_tgts=2" [20021221] */ #include @@ -54,18 +54,31 @@ #include "scsi_debug.h" -static const char * scsi_debug_version_str = "Version: 1.68 (20030314)"; +static const char * scsi_debug_version_str = "Version: 1.69 (20030329)"; + +/* Additional Sense Code (ASC) used */ +#define NO_ADDED_SENSE 0x0 +#define UNRECOVERED_READ_ERR 0x11 +#define INVALID_OPCODE 0x20 +#define ADDR_OUT_OF_RANGE 0x21 +#define INVALID_FIELD_IN_CDB 0x24 +#define POWERON_RESET 0x29 +#define SAVING_PARAMS_UNSUP 0x39 +#define THRESHHOLD_EXCEEDED 0x5d #define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */ /* Default values for driver parameters */ -#define DEF_NUM_DEVS 1 +#define DEF_NUM_HOST 1 +#define DEF_NUM_TGTS 1 +#define DEF_MAX_LUNS 1 +/* With these defaults, this driver will make 1 host with 1 target + * (id 0) containing 1 logical unit (lun 0). That is 1 device. + */ #define DEF_DEV_SIZE_MB 8 #define DEF_EVERY_NTH 0 #define DEF_DELAY 1 -#define DEF_MAX_LUNS 2 #define DEF_SCSI_LEVEL 3 -#define DEF_NUM_HOST 1 #define DEF_OPTS 0 /* bit mask values for scsi_debug_opts */ @@ -83,8 +96,12 @@ * sector on read commands: */ #define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */ +/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1) + * or "peripheral device" addressing (value 0) */ +#define SAM2_LUN_ADDRESS_METHOD 0 + static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB; -static int scsi_debug_num_devs = DEF_NUM_DEVS; /* max devs per host */ +static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */ static int scsi_debug_opts = DEF_OPTS; static int scsi_debug_every_nth = DEF_EVERY_NTH; static int scsi_debug_cmnd_count = 0; @@ -303,7 +320,7 @@ sbuff = devip->sense_buff; memcpy(buff, sbuff, (bufflen < SDEBUG_SENSE_LEN) ? bufflen : SDEBUG_SENSE_LEN); - mk_sense_buffer(devip, 0, 0x0, 0, 7); + mk_sense_buffer(devip, 0, NO_ADDED_SENSE, 0, 7); } else { memset(buff, 0, bufflen); buff[0] = 0x70; @@ -384,7 +401,8 @@ } errsts = resp_read(SCpnt, upper_blk, block, num, devip); if (inj_recovered && (0 == errsts)) { - mk_sense_buffer(devip, RECOVERED_ERROR, 0x5d, 0, 14); + mk_sense_buffer(devip, RECOVERED_ERROR, + THRESHHOLD_EXCEEDED, 0, 18); errsts = check_condition_result; } break; @@ -421,7 +439,8 @@ } errsts = resp_write(SCpnt, upper_blk, block, num, devip); if (inj_recovered && (0 == errsts)) { - mk_sense_buffer(devip, RECOVERED_ERROR, 0x5d, 0, 14); + mk_sense_buffer(devip, RECOVERED_ERROR, + THRESHHOLD_EXCEEDED, 0, 18); errsts = check_condition_result; } break; @@ -435,7 +454,7 @@ default: if ((errsts = check_reset(SCpnt, devip))) break; - mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x20, 0, 14); + mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0, 18); errsts = check_condition_result; break; } @@ -455,7 +474,7 @@ { if (devip->reset) { devip->reset = 0; - mk_sense_buffer(devip, UNIT_ATTENTION, 0x29, 0, 14); + mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0, 18); return check_condition_result; } return 0; @@ -516,7 +535,8 @@ pq_pdt = PERIPH_DEVICE_TYPE(target); arr[0] = pq_pdt; if (0x2 & cmd[1]) { /* CMDDT bit set */ - mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14); + mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, + 0, 18); return check_condition_result; } else if (0x1 & cmd[1]) { /* EVPD bit set */ int dev_id_num, len; @@ -541,7 +561,8 @@ dev_id_str, len); } else { /* Illegal request, invalid field in cdb */ - mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14); + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_CDB, 0, 18); return check_condition_result; } memcpy(buff, arr, min_len); @@ -654,7 +675,8 @@ memset(buff, 0, bufflen); memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); if (0x3 == pcontrol) { /* Saving values not supported */ - mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x39, 0, 14); + mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, + 0, 18); return check_condition_result; } dev_spec = DEV_READONLY(target) ? 0x80 : 0x0; @@ -697,7 +719,8 @@ offset += len; break; default: - mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14); + mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, + 0, 18); return check_condition_result; } if (msense_6) @@ -721,13 +744,15 @@ unsigned long iflags; if (upper_blk || (block + num > sdebug_capacity)) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x21, 0, 14); + mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, + 0, 18); return check_condition_result; } if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) && (block <= OPT_MEDIUM_ERR_ADDR) && ((block + num) > OPT_MEDIUM_ERR_ADDR)) { - mk_sense_buffer(devip, MEDIUM_ERROR, 0x11, 0, 14); + mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR, + 0, 18); /* claim unrecoverable read error */ return check_condition_result; } @@ -770,7 +795,8 @@ unsigned long iflags; if (upper_blk || (block + num > sdebug_capacity)) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x21, 0, 14); + mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, + 0, 18); return check_condition_result; } @@ -805,23 +831,33 @@ static int resp_report_luns(unsigned char * cmd, unsigned char * buff, int bufflen, struct sdebug_dev_info * devip) { - unsigned int alloc_len, lun_cnt, i; + unsigned int alloc_len; + int lun_cnt, i, upper; int select_report = (int)cmd[2]; ScsiLun *one_lun; alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); if ((alloc_len < 16) || (select_report > 2)) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x24, 0, 14); + mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, + 0, 18); return check_condition_result; } - if (bufflen > 3) { - lun_cnt = min((int)(bufflen / sizeof(ScsiLun)), - (int)scsi_debug_max_luns); + if (bufflen > 8) { /* can produce response with up to 16k luns + (lun 0 to lun 16383) */ memset(buff, 0, bufflen); - buff[3] = 8 * lun_cnt; - one_lun = (ScsiLun*) &buff[0]; - for (i = 0; i < lun_cnt; i++) - one_lun[i].scsi_lun[1] = i; + lun_cnt = scsi_debug_max_luns; + buff[2] = ((sizeof(ScsiLun) * lun_cnt) >> 8) & 0xff; + buff[3] = (sizeof(ScsiLun) * lun_cnt) & 0xff; + lun_cnt = min((int)((bufflen - 8) / sizeof(ScsiLun)), + lun_cnt); + one_lun = (ScsiLun*) &buff[8]; + for (i = 0; i < lun_cnt; i++) { + upper = (i >> 8) & 0x3f; + if (upper) + one_lun[i].scsi_lun[0] = + (upper | (SAM2_LUN_ADDRESS_METHOD << 6)); + one_lun[i].scsi_lun[1] = i & 0xff; + } } return 0; } @@ -1101,7 +1137,7 @@ if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) { printk(KERN_INFO "scsi_debug: cmd "); for (k = 0, num = cmnd->cmd_len; k < num; ++k) - printk("%02x ", (int)cmnd->cmnd[k]); + printk("%02x ", (int)cmnd->cmnd[k]); printk("\n"); if (scsi_result) { struct scsi_device * sdp = cmnd->device; @@ -1159,7 +1195,7 @@ * of sysfs parameters (which module_param doesn't yet support). * Sysfs parameters defined explicitly below. */ -module_param_named(num_devs, scsi_debug_num_devs, int, 0); +module_param_named(num_tgts, scsi_debug_num_tgts, int, 0); module_param_named(max_luns, scsi_debug_max_luns, int, 0); module_param_named(scsi_level, scsi_debug_scsi_level, int, 0); module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, 0); @@ -1172,7 +1208,7 @@ MODULE_DESCRIPTION("SCSI debug adapter driver"); MODULE_LICENSE("GPL"); -MODULE_PARM_DESC(num_devs, "number of SCSI devices per host to simulate"); +MODULE_PARM_DESC(num_tgts, "number of SCSI targets per host to simulate"); MODULE_PARM_DESC(max_luns, "number of SCSI LUNs per target to simulate"); MODULE_PARM_DESC(scsi_level, "SCSI level to simulate"); MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs"); @@ -1186,9 +1222,9 @@ static const char * scsi_debug_info(struct Scsi_Host * shp) { - sprintf(sdebug_info, "scsi_debug, %s, num_devs=%d, " + sprintf(sdebug_info, "scsi_debug, %s, num_tgts=%d, " "dev_size_mb=%d, opts=0x%x", scsi_debug_version_str, - scsi_debug_num_devs, scsi_debug_dev_size_mb, + scsi_debug_num_tgts, scsi_debug_dev_size_mb, scsi_debug_opts); return sdebug_info; } @@ -1221,13 +1257,13 @@ } begin = 0; pos = len = sprintf(buffer, "scsi_debug adapter driver, %s\n" - "num_devs=%d, shared (ram) size=%d MB, opts=0x%x, " + "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, " "every_nth=%d(curr:%d)\n" "delay=%d, max_luns=%d, scsi_level=%d\n" "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n" "number of aborts=%d, device_reset=%d, bus_resets=%d, " "host_resets=%d\n", - scsi_debug_version_str, scsi_debug_num_devs, + scsi_debug_version_str, scsi_debug_num_tgts, scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth, scsi_debug_cmnd_count, scsi_debug_delay, scsi_debug_max_luns, scsi_debug_scsi_level, @@ -1295,23 +1331,23 @@ DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show, sdebug_opts_store) -static ssize_t sdebug_num_devs_show(struct device_driver * ddp, char * buf) +static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_devs); + return snprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts); } -static ssize_t sdebug_num_devs_store(struct device_driver * ddp, +static ssize_t sdebug_num_tgts_store(struct device_driver * ddp, const char * buf, size_t count) { int n; if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { - scsi_debug_num_devs = n; + scsi_debug_num_tgts = n; return count; } return -EINVAL; } -DRIVER_ATTR(num_devs, S_IRUGO | S_IWUSR, sdebug_num_devs_show, - sdebug_num_devs_store) +DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show, + sdebug_num_tgts_store) static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf) { @@ -1342,7 +1378,19 @@ { return snprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns); } -DRIVER_ATTR(max_luns, S_IRUGO, sdebug_max_luns_show, NULL) +static ssize_t sdebug_max_luns_store(struct device_driver * ddp, + const char * buf, size_t count) +{ + int n; + + if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { + scsi_debug_max_luns = n; + return count; + } + return -EINVAL; +} +DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show, + sdebug_max_luns_store) static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf) { @@ -1391,7 +1439,7 @@ { driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay); driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts); - driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_devs); + driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth); driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns); @@ -1406,7 +1454,7 @@ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); - driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_devs); + driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay); } @@ -1567,7 +1615,7 @@ static int sdebug_driver_probe(struct device * dev) { - int k; + int k, devs_per_host; int error = 0; struct sdebug_host_info *sdbg_host; struct sdebug_dev_info *sdbg_devinfo; @@ -1584,7 +1632,8 @@ INIT_LIST_HEAD(&sdbg_host->dev_info_list); - for (k = 0; k < scsi_debug_num_devs; k++) { + devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns; + for (k = 0; k < devs_per_host; k++) { sdbg_devinfo = kmalloc(sizeof(*sdbg_devinfo),GFP_KERNEL); if (NULL == sdbg_devinfo) { printk(KERN_ERR "%s: out of memory at line %d\n", @@ -1608,7 +1657,11 @@ sdbg_host->shost = hpnt; sdbg_host->dev = dev; - hpnt->max_lun = scsi_debug_max_luns; + if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id)) + hpnt->max_id = scsi_debug_num_tgts + 1; + else + hpnt->max_id = scsi_debug_num_tgts; + hpnt->max_lun = scsi_debug_max_luns; error = scsi_add_host(hpnt, sdbg_host->dev); if (error) { diff -Nru a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c --- a/drivers/scsi/scsi_ioctl.c Wed Apr 2 22:24:07 2003 +++ b/drivers/scsi/scsi_ioctl.c Wed Apr 2 22:24:07 2003 @@ -298,6 +298,7 @@ goto error; switch (opcode) { + case SEND_DIAGNOSTIC: case FORMAT_UNIT: timeout = FORMAT_UNIT_TIMEOUT; retries = 1; diff -Nru a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c --- a/drivers/scsi/scsi_lib.c Wed Apr 2 22:24:05 2003 +++ b/drivers/scsi/scsi_lib.c Wed Apr 2 22:24:05 2003 @@ -810,7 +810,7 @@ cmd->device->host->host_no, (int) cmd->device->channel, (int) cmd->device->id, (int) cmd->device->lun); print_command(cmd->data_cmnd); - print_sense("sd", cmd); + print_sense("", cmd); cmd = scsi_end_request(cmd, 0, block_sectors, 1); return; default: @@ -830,7 +830,7 @@ struct Scsi_Device_Template *sdt; sdt = scsi_get_request_dev(cmd->request); - printk("SCSI %s error : host %d channel %d id %d lun %d return code = %x\n", + printk("SCSI %s error : <%d %d %d %d> return code = 0x%x\n", (sdt ? sdt->name : "device"), cmd->device->host->host_no, cmd->device->channel, @@ -838,7 +838,7 @@ cmd->device->lun, result); if (driver_byte(result) & DRIVER_SENSE) - print_sense("sd", cmd); + print_sense("", cmd); /* * Mark a single buffer as not uptodate. Queue the remainder. * We sometimes get this cruft in the event that a medium error @@ -1072,14 +1072,6 @@ if (shost->in_recovery || blk_queue_plugged(q)) return; - /* - * get next queueable request. We do this early to make sure - * that the request is fully prepared even if we cannot - * accept it. If there is no request, we'll detect this - * lower down. - */ - req = elv_next_request(q); - if (sdev->device_busy >= sdev->queue_depth) break; @@ -1134,11 +1126,12 @@ sdev->starved = 0; /* - * If we couldn't find a request that could be queued, then we - * can also quit. + * get next queueable request. We do this early to make sure + * that the request is fully prepared even if we cannot + * accept it. If there is no request, we'll detect this + * lower down. */ - if (blk_queue_empty(q)) - break; + req = elv_next_request(q); if (!req) { /* If the device is busy, a returning I/O diff -Nru a/drivers/scsi/scsi_pc98.c b/drivers/scsi/scsi_pc98.c --- a/drivers/scsi/scsi_pc98.c Wed Apr 2 22:24:04 2003 +++ b/drivers/scsi/scsi_pc98.c Wed Apr 2 22:24:04 2003 @@ -48,7 +48,7 @@ int pc98_bios_param(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int *ip) { - static struct Scsi_Host *first_real = first_real_host(); + struct Scsi_Host *first_real = first_real_host(); if (sdev->host == first_real && sdev->id < 7 && __PC9800SCA_TEST_BIT(PC9800SCA_DISK_EQUIPS, sdev->id)) diff -Nru a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c --- a/drivers/scsi/scsi_scan.c Wed Apr 2 22:24:07 2003 +++ b/drivers/scsi/scsi_scan.c Wed Apr 2 22:24:07 2003 @@ -191,6 +191,13 @@ {"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"SUN", "T300", "*", BLIST_SPARSELUN}, {"SUN", "T4", "*", BLIST_SPARSELUN}, + {"SGI", "RAID3", "*", BLIST_SPARSELUN}, + {"SGI", "RAID5", "*", BLIST_SPARSELUN}, + {"SGI", "TP9100", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"SGI", "TP9300", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"SGI", "TP9400", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"SGI", "TP9500", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"MYLEX", "DACARMRB", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, { NULL, NULL, NULL, 0 }, }; diff -Nru a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c --- a/drivers/scsi/scsi_sysfs.c Wed Apr 2 22:24:04 2003 +++ b/drivers/scsi/scsi_sysfs.c Wed Apr 2 22:24:04 2003 @@ -275,12 +275,8 @@ static ssize_t store_rescan_field (struct device *dev, const char *buf, size_t count) { - int ret = ENODEV; - struct scsi_device *sdev; - sdev = to_scsi_device(dev); - if (sdev) - ret = scsi_rescan_device(sdev); - return ret; + scsi_rescan_device(to_scsi_device(dev)); + return 0; } static DEVICE_ATTR(rescan, S_IRUGO | S_IWUSR, show_rescan_field, store_rescan_field) diff -Nru a/drivers/scsi/sym53c8xx.c b/drivers/scsi/sym53c8xx.c --- a/drivers/scsi/sym53c8xx.c Wed Apr 2 22:24:06 2003 +++ b/drivers/scsi/sym53c8xx.c Wed Apr 2 22:24:06 2003 @@ -4901,6 +4901,11 @@ u_long period; int i; +#ifdef CONFIG_PARISC + char scsi_mode = -1; + struct hardware_path hwpath; +#endif + /* ** Wide ? */ @@ -4972,6 +4977,31 @@ */ period = (4 * div_10M[0] + np->clock_khz - 1) / np->clock_khz; + +#ifdef CONFIG_PARISC + /* Host firmware (PDC) keeps a table for crippling SCSI capabilities. + * Many newer machines export one channel of 53c896 chip + * as SE, 50-pin HD. Also used for Multi-initiator SCSI clusters + * to set the SCSI Initiator ID. + */ + get_pci_node_path(np->pdev, &hwpath); + if (pdc_get_initiator(&hwpath, &np->myaddr, &period, &np->maxwide, &scsi_mode)) + { + if (np->maxwide) + np->features |= FE_WIDE; + if (scsi_mode >= 0) { + /* C3000 PDC reports period/mode */ + driver_setup.diff_support = 0; + switch(scsi_mode) { + case 0: np->scsi_mode = SMODE_SE; break; + case 1: np->scsi_mode = SMODE_HVD; break; + case 2: np->scsi_mode = SMODE_LVD; break; + default: break; + } + } + } +#endif + if (period <= 250) np->minsync = 10; else if (period <= 303) np->minsync = 11; else if (period <= 500) np->minsync = 12; diff -Nru a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c --- a/drivers/scsi/wd33c93.c Wed Apr 2 22:24:06 2003 +++ b/drivers/scsi/wd33c93.c Wed Apr 2 22:24:06 2003 @@ -162,8 +162,8 @@ { uchar data; - outb(reg_num, *regs.SASR); - data = inb(*regs.SCMD); + outb(reg_num, regs.SASR); + data = inb(regs.SCMD); return data; } @@ -172,33 +172,33 @@ { unsigned long value; - outb(WD_TRANSFER_COUNT_MSB, *regs.SASR); - value = inb(*regs.SCMD) << 16; - value |= inb(*regs.SCMD) << 8; - value |= inb(*regs.SCMD); + outb(WD_TRANSFER_COUNT_MSB, regs.SASR); + value = inb(regs.SCMD) << 16; + value |= inb(regs.SCMD) << 8; + value |= inb(regs.SCMD); return value; } static inline uchar read_aux_stat(const wd33c93_regs regs) { - return inb(*regs.SASR); + return inb(regs.SASR); } static inline void write_wd33c93(const wd33c93_regs regs, uchar reg_num, uchar value) { - outb(reg_num, *regs.SASR); - outb(value, *regs.SCMD); + outb(reg_num, regs.SASR); + outb(value, regs.SCMD); } static inline void write_wd33c93_count(const wd33c93_regs regs, unsigned long value) { - outb(WD_TRANSFER_COUNT_MSB, *regs.SASR); - outb((value >> 16) & 0xff, *regs.SCMD); - outb((value >> 8) & 0xff, *regs.SCMD); - outb( value & 0xff, *regs.SCMD); + outb(WD_TRANSFER_COUNT_MSB, regs.SASR); + outb((value >> 16) & 0xff, regs.SCMD); + outb((value >> 8) & 0xff, regs.SCMD); + outb( value & 0xff, regs.SCMD); } #define write_wd33c93_cmd(regs, cmd) \ @@ -209,9 +209,9 @@ { int i; - outb(WD_CDB_1, *regs.SASR); + outb(WD_CDB_1, regs.SASR); for (i=0; iresult = DID_RESET << 16; enable_irq(instance->irq); - return 0; + return SUCCESS; } int @@ -1591,7 +1591,7 @@ instance->host_no, cmd->pid); enable_irq(cmd->device->host->irq); cmd->scsi_done(cmd); - return SCSI_ABORT_SUCCESS; + return SUCCESS; } prev = tmp; tmp = (Scsi_Cmnd *) tmp->host_scribble; @@ -1666,7 +1666,7 @@ enable_irq(cmd->device->host->irq); cmd->scsi_done(cmd); - return SCSI_ABORT_SUCCESS; + return SUCCESS; } /* @@ -1681,9 +1681,9 @@ printk ("scsi%d: Abort - command %ld found on disconnected_Q - ", instance->host_no, cmd->pid); - printk("returning ABORT_SNOOZE. "); + printk("Abort SNOOZE. "); enable_irq(cmd->device->host->irq); - return SCSI_ABORT_SNOOZE; + return FAILED; } tmp = (Scsi_Cmnd *) tmp->host_scribble; } @@ -1704,7 +1704,7 @@ enable_irq(cmd->device->host->irq); printk("scsi%d: warning : SCSI command probably completed successfully" " before abortion. ", instance->host_no); - return SCSI_ABORT_NOT_RUNNING; + return FAILED; } #define MAX_WD33C93_HOSTS 4 @@ -1755,7 +1755,7 @@ return 1; } -__setup("wd33c9=", wd33c93_setup); +__setup("wd33c93=", wd33c93_setup); /* check_setup_args() returns index if key found, 0 if not */ @@ -2080,7 +2080,7 @@ { } -EXPORT_SYMBOL(wd33c93_reset); +EXPORT_SYMBOL(wd33c93_host_reset); EXPORT_SYMBOL(wd33c93_init); EXPORT_SYMBOL(wd33c93_release); EXPORT_SYMBOL(wd33c93_abort); diff -Nru a/drivers/scsi/wd33c93.h b/drivers/scsi/wd33c93.h --- a/drivers/scsi/wd33c93.h Wed Apr 2 22:24:04 2003 +++ b/drivers/scsi/wd33c93.h Wed Apr 2 22:24:04 2003 @@ -186,8 +186,13 @@ /* This is what the 3393 chip looks like to us */ typedef struct { +#ifdef CONFIG_WD33C93_PIO + unsigned int SASR; + unsigned int SCMD; +#else volatile unsigned char *SASR; volatile unsigned char *SCMD; +#endif } wd33c93_regs; @@ -334,7 +339,7 @@ int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)); void wd33c93_intr (struct Scsi_Host *instance); int wd33c93_proc_info(char *, char **, off_t, int, int, int); -int wd33c93_reset (Scsi_Cmnd *, unsigned int); +int wd33c93_host_reset (Scsi_Cmnd *); void wd33c93_release(void); #endif /* WD33C93_H */ diff -Nru a/drivers/serial/21285.c b/drivers/serial/21285.c --- a/drivers/serial/21285.c Wed Apr 2 22:24:06 2003 +++ b/drivers/serial/21285.c Wed Apr 2 22:24:06 2003 @@ -501,10 +501,11 @@ .index = -1, }; -static void __init rs285_console_init(void) +static int __init rs285_console_init(void) { serial21285_setup_ports(); register_console(&serial21285_console); + return 0; } console_initcall(rs285_console_init); diff -Nru a/drivers/serial/8250_cs.c b/drivers/serial/8250_cs.c --- a/drivers/serial/8250_cs.c Wed Apr 2 22:24:05 2003 +++ b/drivers/serial/8250_cs.c Wed Apr 2 22:24:05 2003 @@ -690,26 +690,25 @@ return 0; } -/*====================================================================*/ +static struct pcmcia_driver serial_cs_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "serial_cs", + }, + .attach = serial_attach, + .detach = serial_detach, +}; static int __init init_serial_cs(void) { - servinfo_t serv; - DEBUG(0, "%s\n", version); - CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "serial_cs: Card Services release " - "does not match!\n"); - return -1; - } - register_pccard_driver(&dev_info, &serial_attach, &serial_detach); - return 0; + return pcmcia_register_driver(&serial_cs_driver); } static void __exit exit_serial_cs(void) { - DEBUG(0, "serial_cs: unloading\n"); - unregister_pccard_driver(&dev_info); + pcmcia_unregister_driver(&serial_cs_driver); + + /* XXX: this really needs to move into generic code.. */ while (dev_list != NULL) serial_detach(dev_list); } diff -Nru a/drivers/serial/Kconfig b/drivers/serial/Kconfig --- a/drivers/serial/Kconfig Wed Apr 2 22:24:07 2003 +++ b/drivers/serial/Kconfig Wed Apr 2 22:24:07 2003 @@ -372,14 +372,25 @@ bool "Use NEC V850E on-chip UART for console" depends on V850E_NB85E_UART +config SERIAL98 + tristate "PC-9800 8251-based primary serial port support" + depends on X86_PC9800 + help + If you want to use standard primary serial ports on PC-9800, + say Y. Otherwise, say N. + +config SERIAL98_CONSOLE + bool "Support for console on PC-9800 standard serial port" + depends on SERIAL98=y + config SERIAL_CORE tristate - default m if SERIAL_AMBA!=y && SERIAL_CLPS711X!=y && SERIAL_21285!=y && !SERIAL_SA1100 && !SERIAL_ANAKIN && !SERIAL_UART00 && SERIAL_8250!=y && SERIAL_MUX!=y && !SERIAL_ROCKETPORT && !SERIAL_SUNCORE && !V850E_NB85E_UART && (SERIAL_AMBA=m || SERIAL_CLPS711X=m || SERIAL_21285=m || SERIAL_8250=m || SERIAL_MUX=m) - default y if SERIAL_AMBA=y || SERIAL_CLPS711X=y || SERIAL_21285=y || SERIAL_SA1100 || SERIAL_ANAKIN || SERIAL_UART00 || SERIAL_8250=y || SERIAL_MUX=y || SERIAL_ROCKETPORT || SERIAL_SUNCORE || V850E_NB85E_UART + default m if SERIAL_AMBA!=y && SERIAL_CLPS711X!=y && SERIAL_21285!=y && !SERIAL_SA1100 && !SERIAL_ANAKIN && !SERIAL_UART00 && SERIAL_8250!=y && SERIAL_MUX!=y && !SERIAL_ROCKETPORT && !SERIAL_SUNCORE && !V850E_NB85E_UART && (SERIAL_AMBA=m || SERIAL_CLPS711X=m || SERIAL_21285=m || SERIAL_8250=m || SERIAL_MUX=m || SERIAL98=m) + default y if SERIAL_AMBA=y || SERIAL_CLPS711X=y || SERIAL_21285=y || SERIAL_SA1100 || SERIAL_ANAKIN || SERIAL_UART00 || SERIAL_8250=y || SERIAL_MUX=y || SERIAL_ROCKETPORT || SERIAL_SUNCORE || V850E_NB85E_UART || SERIAL98=y config SERIAL_CORE_CONSOLE bool - depends on SERIAL_AMBA_CONSOLE || SERIAL_CLPS711X_CONSOLE || SERIAL_21285_CONSOLE || SERIAL_SA1100_CONSOLE || SERIAL_ANAKIN_CONSOLE || SERIAL_UART00_CONSOLE || SERIAL_8250_CONSOLE || SERIAL_MUX_CONSOLE || SERIAL_SUNCORE || V850E_NB85E_UART_CONSOLE + depends on SERIAL_AMBA_CONSOLE || SERIAL_CLPS711X_CONSOLE || SERIAL_21285_CONSOLE || SERIAL_SA1100_CONSOLE || SERIAL_ANAKIN_CONSOLE || SERIAL_UART00_CONSOLE || SERIAL_8250_CONSOLE || SERIAL_MUX_CONSOLE || SERIAL_SUNCORE || V850E_NB85E_UART_CONSOLE || SERIAL98_CONSOLE default y config SERIAL_68328 diff -Nru a/drivers/serial/Makefile b/drivers/serial/Makefile --- a/drivers/serial/Makefile Wed Apr 2 22:24:05 2003 +++ b/drivers/serial/Makefile Wed Apr 2 22:24:05 2003 @@ -27,3 +27,4 @@ obj-$(CONFIG_SERIAL_68360) += 68360serial.o obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o obj-$(CONFIG_V850E_NB85E_UART) += nb85e_uart.o +obj-$(CONFIG_SERIAL98) += serial98.o diff -Nru a/drivers/usb/Makefile b/drivers/usb/Makefile --- a/drivers/usb/Makefile Wed Apr 2 22:24:07 2003 +++ b/drivers/usb/Makefile Wed Apr 2 22:24:07 2003 @@ -14,6 +14,7 @@ obj-$(CONFIG_USB_ACM) += class/ obj-$(CONFIG_USB_AUDIO) += class/ obj-$(CONFIG_USB_BLUETOOTH_TTY) += class/ +obj-$(CONFIG_USB_MIDI) += class/ obj-$(CONFIG_USB_PRINTER) += class/ obj-$(CONFIG_USB_STORAGE) += storage/ diff -Nru a/drivers/usb/class/audio.c b/drivers/usb/class/audio.c --- a/drivers/usb/class/audio.c Wed Apr 2 22:24:07 2003 +++ b/drivers/usb/class/audio.c Wed Apr 2 22:24:07 2003 @@ -172,7 +172,6 @@ /*****************************************************************************/ -#include #include #include #include diff -Nru a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c --- a/drivers/usb/class/cdc-acm.c Wed Apr 2 22:24:06 2003 +++ b/drivers/usb/class/cdc-acm.c Wed Apr 2 22:24:06 2003 @@ -538,7 +538,7 @@ cfacm = dev->config + i; - dbg("probing config %d", cfacm->bConfigurationValue); + dbg("probing config %d", cfacm->desc.bConfigurationValue); if (cfacm->desc.bNumInterfaces != 2 || usb_interface_claimed(cfacm->interface + 0) || diff -Nru a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c --- a/drivers/usb/core/buffer.c Wed Apr 2 22:24:07 2003 +++ b/drivers/usb/core/buffer.c Wed Apr 2 22:24:07 2003 @@ -7,7 +7,6 @@ #include #include -#include #include #include #include diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c --- a/drivers/usb/core/hcd.c Wed Apr 2 22:24:06 2003 +++ b/drivers/usb/core/hcd.c Wed Apr 2 22:24:06 2003 @@ -1024,9 +1024,7 @@ */ urb->transfer_flags |= URB_NO_DMA_MAP; status = rh_urb_enqueue (hcd, urb); - if (status) - urb_unlink (urb); - return status; + goto done; } /* lower level hcd code should use *_dma exclusively, @@ -1051,8 +1049,11 @@ } status = hcd->driver->urb_enqueue (hcd, urb, mem_flags); - if (status) +done: + if (status) { + usb_put_urb (urb); urb_unlink (urb); + } return status; } diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c --- a/drivers/usb/core/hub.c Wed Apr 2 22:24:05 2003 +++ b/drivers/usb/core/hub.c Wed Apr 2 22:24:05 2003 @@ -135,8 +135,7 @@ default: /* presumably an error */ /* Cause a hub reset after 10 consecutive errors */ - dbg("hub '%s' status %d for interrupt transfer", - urb->dev->devpath, urb->status); + dev_dbg (&hub->intf->dev, "transfer --> %d\n", urb->status); if ((++hub->nerrors < 10) || hub->error) goto resubmit; hub->error = urb->status; @@ -158,10 +157,10 @@ spin_unlock_irqrestore(&hub_event_lock, flags); resubmit: - if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0) - err ("hub '%s-%s' status %d for interrupt resubmit", - urb->dev->bus->bus_name, urb->dev->devpath, - status); + if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0 + /* ENODEV means we raced disconnect() */ + && status != -ENODEV) + dev_err (&hub->intf->dev, "resubmit --> %d\n", urb->status); } /* USB 2.0 spec Section 11.24.2.3 */ @@ -648,12 +647,13 @@ struct usb_port_status *portsts; int ret = -ENOMEM; - portsts = kmalloc(sizeof(*portsts), GFP_KERNEL); + portsts = kmalloc(sizeof(*portsts), GFP_NOIO); if (portsts) { ret = usb_get_port_status(hub, port + 1, portsts); if (ret < 0) - err("%s(%s-%s) failed (err = %d)", __FUNCTION__, - hub->bus->bus_name, hub->devpath, ret); + dev_err (hubdev (hub), + "%s failed (err = %d)\n", __FUNCTION__, + ret); else { *status = le16_to_cpu(portsts->wPortStatus); *change = le16_to_cpu(portsts->wPortChange); @@ -759,8 +759,8 @@ ret = usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE); if (ret) - err("cannot disable port %d of hub %s (err = %d)", - port + 1, hub->devpath, ret); + dev_err(hubdev(hub), "cannot disable port %d (err = %d)\n", + port + 1, ret); } /* USB 2.0 spec, 7.1.7.3 / fig 7-29: @@ -983,12 +983,12 @@ spin_unlock_irqrestore(&hub_event_lock, flags); if (hub->error) { - dbg("resetting hub %s for error %d", - dev->devpath, hub->error); + dev_dbg (&hub->intf->dev, "resetting for error %d\n", + hub->error); if (usb_hub_reset(hub)) { - err("error resetting hub %s - disconnecting", - dev->devpath); + dev_dbg (&hub->intf->dev, + "can't reset; disconnecting\n"); up(&hub->khubd_sem); usb_hub_disconnect(dev); continue; @@ -1022,33 +1022,37 @@ if (!(portstatus & USB_PORT_STAT_ENABLE) && (portstatus & USB_PORT_STAT_CONNECTION) && (dev->children[i])) { - err("already running hub %s port %i " + dev_err (&hub->intf->dev, + "port %i " "disabled by hub (EMI?), " "re-enabling...", - dev->devpath, i + 1); + i + 1); usb_hub_port_connect_change(hub, i, portstatus, portchange); } } if (portchange & USB_PORT_STAT_C_SUSPEND) { - dbg("hub %s port %d suspend change", - dev->devpath, i + 1); + dev_dbg (&hub->intf->dev, + "suspend change on port %d\n", + i + 1); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_SUSPEND); } if (portchange & USB_PORT_STAT_C_OVERCURRENT) { - err("hub %s port %d over-current change", - dev->devpath, i + 1); + dev_err (&hub->intf->dev, + "over-current change on port %d\n", + i + 1); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_OVER_CURRENT); usb_hub_power_on(hub); } if (portchange & USB_PORT_STAT_C_RESET) { - dbg("hub %s port %d reset change", - dev->devpath, i + 1); + dev_dbg (&hub->intf->dev, + "reset change on port %d\n", + i + 1); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_RESET); } @@ -1056,16 +1060,16 @@ /* deal with hub status changes */ if (usb_get_hub_status(dev, &hubsts) < 0) - err("get_hub_status %s failed", dev->devpath); + dev_err (&hub->intf->dev, "get_hub_status failed\n"); else { hubstatus = le16_to_cpup(&hubsts.wHubStatus); hubchange = le16_to_cpup(&hubsts.wHubChange); if (hubchange & HUB_CHANGE_LOCAL_POWER) { - dbg("hub %s power change", dev->devpath); + dev_dbg (&hub->intf->dev, "power change\n"); usb_clear_hub_feature(dev, C_HUB_LOCAL_POWER); } if (hubchange & HUB_CHANGE_OVERCURRENT) { - dbg("hub %s overcurrent change", dev->devpath); + dev_dbg (&hub->intf->dev, "overcurrent change\n"); wait_ms(500); /* Cool down */ usb_clear_hub_feature(dev, C_HUB_OVER_CURRENT); usb_hub_power_on(hub); diff -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c --- a/drivers/usb/core/message.c Wed Apr 2 22:24:04 2003 +++ b/drivers/usb/core/message.c Wed Apr 2 22:24:04 2003 @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "hcd.h" /* for usbcore internals */ diff -Nru a/drivers/usb/core/usb-debug.c b/drivers/usb/core/usb-debug.c --- a/drivers/usb/core/usb-debug.c Wed Apr 2 22:24:07 2003 +++ b/drivers/usb/core/usb-debug.c Wed Apr 2 22:24:07 2003 @@ -5,7 +5,6 @@ * face, but so that you can still use them.. */ #include -#include #include #include #include diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c --- a/drivers/usb/core/usb.c Wed Apr 2 22:24:05 2003 +++ b/drivers/usb/core/usb.c Wed Apr 2 22:24:05 2003 @@ -866,14 +866,11 @@ } /** - * usb_connect - connects a new device during enumeration (usbcore-internal) - * @dev: partially enumerated device - * - * Connect a new USB device. This basically just initializes - * the USB device information and sets up the topology - it's - * up to the low-level driver to reset the port and actually - * do the setup (the upper levels don't know how to do that). + * usb_connect - pick device address (usbcore-internal) + * @dev: newly detected device (in DEFAULT state) * + * Picks a device address. It's up to the hub (or root hub) driver + * to handle and manage enumeration, starting from the DEFAULT state. * Only hub drivers (including virtual root hub drivers for host * controllers) should ever call this. */ @@ -983,7 +980,7 @@ } /* - * By the time we get here, the device has gotten a new device ID + * By the time we get here, we chose a new device address * and is in the default state. We need to identify the thing and * get the ball rolling.. * diff -Nru a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c --- a/drivers/usb/host/ohci-hcd.c Wed Apr 2 22:24:04 2003 +++ b/drivers/usb/host/ohci-hcd.c Wed Apr 2 22:24:04 2003 @@ -94,7 +94,6 @@ #include #include /* for in_interrupt () */ #include -#include #include "../core/hcd.h" #include diff -Nru a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c --- a/drivers/usb/host/ohci-pci.c Wed Apr 2 22:24:06 2003 +++ b/drivers/usb/host/ohci-pci.c Wed Apr 2 22:24:06 2003 @@ -389,7 +389,7 @@ if (usb_disabled()) return -ENODEV; - printk (KERN_DEBUG "%s: block sizes: ed %d td %d\n", hcd_name, + printk (KERN_DEBUG "%s: block sizes: ed %Zd td %Zd\n", hcd_name, sizeof (struct ed), sizeof (struct td)); return pci_module_init (&ohci_pci_driver); } diff -Nru a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c --- a/drivers/usb/image/mdc800.c Wed Apr 2 22:24:05 2003 +++ b/drivers/usb/image/mdc800.c Wed Apr 2 22:24:05 2003 @@ -85,7 +85,6 @@ * (20/10/1999) */ -#include #include #include #include diff -Nru a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c --- a/drivers/usb/media/ov511.c Wed Apr 2 22:24:05 2003 +++ b/drivers/usb/media/ov511.c Wed Apr 2 22:24:05 2003 @@ -36,7 +36,6 @@ */ #include -#include #include #include #include diff -Nru a/drivers/usb/media/stv680.c b/drivers/usb/media/stv680.c --- a/drivers/usb/media/stv680.c Wed Apr 2 22:24:06 2003 +++ b/drivers/usb/media/stv680.c Wed Apr 2 22:24:06 2003 @@ -60,7 +60,6 @@ #include #include -#include #include #include #include diff -Nru a/drivers/usb/misc/emi26.c b/drivers/usb/misc/emi26.c --- a/drivers/usb/misc/emi26.c Wed Apr 2 22:24:05 2003 +++ b/drivers/usb/misc/emi26.c Wed Apr 2 22:24:05 2003 @@ -78,19 +78,28 @@ return response; } +#define FW_LOAD_SIZE 1023 + static int emi26_load_firmware (struct usb_device *dev) { int err; int i; int pos = 0; /* Position in hex record */ __u32 addr; /* Address to write */ - __u8 buf[1023]; + __u8 *buf; + + buf = kmalloc(FW_LOAD_SIZE, GFP_KERNEL); + if (!buf) { + err( "%s - error loading firmware: error = %d", __FUNCTION__, -ENOMEM); + err = -ENOMEM; + goto wraperr; + } /* Assert reset (stop the CPU in the EMI) */ err = emi26_set_reset(dev,1); if (err < 0) { err( "%s - error loading firmware: error = %d", __FUNCTION__, err); - return err; + goto wraperr; } /* 1. We need to put the loader for the FPGA into the EZ-USB */ @@ -98,7 +107,7 @@ err = emi26_writememory(dev, g_Loader[i].address, g_Loader[i].data, g_Loader[i].length, ANCHOR_LOAD_INTERNAL); if (err < 0) { err("%s - error loading firmware: error = %d", __FUNCTION__, err); - return err; + goto wraperr; } } @@ -113,7 +122,7 @@ addr = g_bitstream[pos].address; /* intel hex records are terminated with type 0 element */ - while ((g_bitstream[pos].type == 0) && (i + g_bitstream[pos].length < sizeof(buf))) { + while ((g_bitstream[pos].type == 0) && (i + g_bitstream[pos].length < FW_LOAD_SIZE)) { memcpy(buf + i, g_bitstream[pos].data, g_bitstream[pos].length); i += g_bitstream[pos].length; pos++; @@ -121,7 +130,7 @@ err = emi26_writememory(dev, addr, buf, i, ANCHOR_LOAD_FPGA); if (err < 0) { err("%s - error loading firmware: error = %d", __FUNCTION__, err); - return err; + goto wraperr; } } while (i > 0); @@ -129,7 +138,7 @@ err = emi26_set_reset(dev,1); if (err < 0) { err("%s - error loading firmware: error = %d", __FUNCTION__, err); - return err; + goto wraperr; } /* 3. We need to put the loader for the firmware into the EZ-USB (again...) */ @@ -137,7 +146,7 @@ err = emi26_writememory(dev, g_Loader[i].address, g_Loader[i].data, g_Loader[i].length, ANCHOR_LOAD_INTERNAL); if (err < 0) { err("%s - error loading firmware: error = %d", __FUNCTION__, err); - return err; + goto wraperr; } } @@ -145,7 +154,7 @@ err = emi26_set_reset(dev,0); if (err < 0) { err("%s - error loading firmware: error = %d", __FUNCTION__, err); - return err; + goto wraperr; } /* 4. We put the part of the firmware that lies in the external RAM into the EZ-USB */ @@ -154,7 +163,7 @@ err = emi26_writememory(dev, g_Firmware[i].address, g_Firmware[i].data, g_Firmware[i].length, ANCHOR_LOAD_EXTERNAL); if (err < 0) { err("%s - error loading firmware: error = %d", __FUNCTION__, err); - return err; + goto wraperr; } } } @@ -163,7 +172,7 @@ err = emi26_set_reset(dev,1); if (err < 0) { err("%s - error loading firmware: error = %d", __FUNCTION__, err); - return err; + goto wraperr; } for (i=0; g_Firmware[i].type == 0; i++) { @@ -171,7 +180,7 @@ err = emi26_writememory(dev, g_Firmware[i].address, g_Firmware[i].data, g_Firmware[i].length, ANCHOR_LOAD_INTERNAL); if (err < 0) { err("%s - error loading firmware: error = %d", __FUNCTION__, err); - return err; + goto wraperr; } } } @@ -180,12 +189,16 @@ err = emi26_set_reset(dev,0); if (err < 0) { err("%s - error loading firmware: error = %d", __FUNCTION__, err); - return err; + goto wraperr; } /* return 1 to fail the driver inialization * and give real driver change to load */ return 1; + +wraperr: + kfree(buf); + return err; } static __devinitdata struct usb_device_id id_table [] = { diff -Nru a/drivers/usb/misc/speedtch.c b/drivers/usb/misc/speedtch.c --- a/drivers/usb/misc/speedtch.c Wed Apr 2 22:24:07 2003 +++ b/drivers/usb/misc/speedtch.c Wed Apr 2 22:24:07 2003 @@ -148,27 +148,15 @@ #define UDSL_SKB(x) ((struct udsl_control *)(x)->cb) -struct atmsar_vcc_data { - struct atmsar_vcc_data *next; - - /* general atmsar flags, per connection */ - int flags; - int type; - - /* connection specific non-atmsar data */ +struct udsl_vcc_data { + /* vpi/vci lookup */ + struct list_head list; + short vpi; + int vci; struct atm_vcc *vcc; - struct k_atm_aal_stats *stats; - unsigned short mtu; /* max is actually 65k for AAL5... */ - - /* cell data */ - unsigned int vp; - unsigned int vc; - unsigned char gfc; - unsigned char pti; - unsigned int headerFlags; - unsigned long atmHeader; /* raw cell reassembly */ + unsigned short mtu; struct sk_buff *reasBuffer; }; @@ -186,7 +174,7 @@ /* atm device part */ struct atm_dev *atm_dev; - struct atmsar_vcc_data *atmsar_vcc_list; + struct list_head vcc_list; /* receiving */ struct udsl_receiver all_receivers [UDSL_NUMBER_RCV_URBS]; @@ -258,73 +246,46 @@ ** decode ** *************/ -#define ATM_HDR_VPVC_MASK (ATM_HDR_VPI_MASK | ATM_HDR_VCI_MASK) -#define ATMSAR_USE_53BYTE_CELL 0x1L +static inline struct udsl_vcc_data *udsl_find_vcc (struct udsl_instance_data *instance, short vpi, int vci) +{ + struct udsl_vcc_data *vcc; -struct sk_buff *atmsar_decode_rawcell (struct atmsar_vcc_data *list, struct sk_buff *skb, - struct atmsar_vcc_data **ctx) + list_for_each_entry (vcc, &instance->vcc_list, list) + if ((vcc->vpi == vpi) && (vcc->vci == vci)) + return vcc; + return NULL; +} + +static struct sk_buff *udsl_decode_rawcell (struct udsl_instance_data *instance, struct sk_buff *skb, struct udsl_vcc_data **ctx) { + if (!instance || !skb || !ctx) + return NULL; + if (!skb->data || !skb->tail) + return NULL; + while (skb->len) { unsigned char *cell = skb->data; unsigned char *cell_payload; - struct atmsar_vcc_data *vcc = list; - unsigned long atmHeader = - ((unsigned long) (cell[0]) << 24) | ((unsigned long) (cell[1]) << 16) | - ((unsigned long) (cell[2]) << 8) | (cell[3] & 0xff); - - dbg ("atmsar_decode_rawcell (0x%p, 0x%p, 0x%p) called", list, skb, ctx); - dbg ("atmsar_decode_rawcell skb->data %p, skb->tail %p", skb->data, skb->tail); - - if (!list || !skb || !ctx) - return NULL; - if (!skb->data || !skb->tail) - return NULL; + struct udsl_vcc_data *vcc; + short vpi; + int vci; + + vpi = ((cell[0] & 0x0f) << 4) | (cell[1] >> 4); + vci = ((cell[1] & 0x0f) << 12) | (cell[2] << 4) | (cell[3] >> 4); + + dbg ("udsl_decode_rawcell (0x%p, 0x%p, 0x%p) called", instance, skb, ctx); + dbg ("udsl_decode_rawcell skb->data %p, skb->tail %p", skb->data, skb->tail); /* here should the header CRC check be... */ - /* look up correct vcc */ - for (; - vcc - && ((vcc->atmHeader & ATM_HDR_VPVC_MASK) != (atmHeader & ATM_HDR_VPVC_MASK)); - vcc = vcc->next); - - dbg ("atmsar_decode_rawcell found vcc %p for packet on vp %d, vc %d", vcc, - (int) ((atmHeader & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT), - (int) ((atmHeader & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT)); - - if (vcc && (skb->len >= (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52))) { - cell_payload = cell + (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 5 : 4); - - switch (vcc->type) { - case ATM_AAL0: - /* case ATM_AAL1: when we have a decode AAL1 function... */ - { - struct sk_buff *tmp = dev_alloc_skb (vcc->mtu); - - if (tmp) { - memcpy (tmp->tail, cell_payload, 48); - skb_put (tmp, 48); - - if (vcc->stats) - atomic_inc (&vcc->stats->rx); - - skb_pull (skb, - (vcc-> - flags & ATMSAR_USE_53BYTE_CELL ? 53 : - 52)); - dbg - ("atmsar_decode_rawcell returns ATM_AAL0 pdu 0x%p with length %d", - tmp, tmp->len); - return tmp; - }; - } - break; - case ATM_AAL1: - case ATM_AAL2: - case ATM_AAL34: - /* not supported */ - break; - case ATM_AAL5: + if (!(vcc = udsl_find_vcc (instance, vpi, vci))) + dbg ("udsl_decode_rawcell: no vcc found for packet on vpi %d, vci %d", vpi, vci); + else { + dbg ("udsl_decode_rawcell found vcc %p for packet on vpi %d, vci %d", vcc, vpi, vci); + + if (skb->len >= 53) { + cell_payload = cell + 5; + if (!vcc->reasBuffer) vcc->reasBuffer = dev_alloc_skb (vcc->mtu); @@ -347,43 +308,36 @@ /* the aal5 buffer ends here, cut the buffer. */ /* buffer will always have at least one whole cell, so */ /* don't need to check return from skb_pull */ - skb_pull (skb, - (vcc-> - flags & ATMSAR_USE_53BYTE_CELL ? 53 : - 52)); + skb_pull (skb, 53); *ctx = vcc; tmp = vcc->reasBuffer; vcc->reasBuffer = NULL; - dbg - ("atmsar_decode_rawcell returns ATM_AAL5 pdu 0x%p with length %d", - tmp, tmp->len); + dbg ("udsl_decode_rawcell returns ATM_AAL5 pdu 0x%p with length %d", tmp, tmp->len); return tmp; } } - break; - }; - /* flush the cell */ - /* buffer will always contain at least one whole cell, so don't */ - /* need to check return value from skb_pull */ - skb_pull (skb, (vcc->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52)); - } else { - /* If data is corrupt and skb doesn't hold a whole cell, flush the lot */ - if (skb_pull (skb, (list->flags & ATMSAR_USE_53BYTE_CELL ? 53 : 52)) == - NULL) - return NULL; + /* flush the cell */ + /* buffer will always contain at least one whole cell, so don't */ + /* need to check return value from skb_pull */ + skb_pull (skb, 53); + } else { + /* If data is corrupt and skb doesn't hold a whole cell, flush the lot */ + if (skb_pull (skb, 53) == NULL) + return NULL; + } } } return NULL; -}; +} -struct sk_buff *atmsar_decode_aal5 (struct atmsar_vcc_data *ctx, struct sk_buff *skb) +static struct sk_buff *udsl_decode_aal5 (struct udsl_vcc_data *ctx, struct sk_buff *skb) { uint crc = 0xffffffff; uint length, pdu_crc, pdu_length; - dbg ("atmsar_decode_aal5 (0x%p, 0x%p) called", ctx, skb); + dbg ("udsl_decode_aal5 (0x%p, 0x%p) called", ctx, skb); if (skb->len && (skb->len % 48)) return NULL; @@ -393,20 +347,18 @@ (skb->tail[-4] << 24) + (skb->tail[-3] << 16) + (skb->tail[-2] << 8) + skb->tail[-1]; pdu_length = ((length + 47 + 8) / 48) * 48; - dbg ("atmsar_decode_aal5: skb->len = %d, length = %d, pdu_crc = 0x%x, pdu_length = %d", - skb->len, length, pdu_crc, pdu_length); + dbg ("udsl_decode_aal5: skb->len = %d, length = %d, pdu_crc = 0x%x, pdu_length = %d", skb->len, length, pdu_crc, pdu_length); /* is skb long enough ? */ if (skb->len < pdu_length) { - if (ctx->stats) - atomic_inc (&ctx->stats->rx_err); + if (ctx->vcc->stats) + atomic_inc (&ctx->vcc->stats->rx_err); return NULL; } /* is skb too long ? */ if (skb->len > pdu_length) { - dbg ("atmsar_decode_aal5: Warning: readjusting illeagl size %d -> %d", - skb->len, pdu_length); + dbg ("udsl_decode_aal5: Warning: readjusting illegal size %d -> %d", skb->len, pdu_length); /* buffer is too long. we can try to recover * if we discard the first part of the skb. * the crc will decide whether this was ok @@ -418,9 +370,9 @@ /* check crc */ if (pdu_crc != crc) { - dbg ("atmsar_decode_aal5: crc check failed!"); - if (ctx->stats) - atomic_inc (&ctx->stats->rx_err); + dbg ("udsl_decode_aal5: crc check failed!"); + if (ctx->vcc->stats) + atomic_inc (&ctx->vcc->stats->rx_err); return NULL; } @@ -428,19 +380,20 @@ skb_trim (skb, length); /* update stats */ - if (ctx->stats) - atomic_inc (&ctx->stats->rx); + if (ctx->vcc->stats) + atomic_inc (&ctx->vcc->stats->rx); - dbg ("atmsar_decode_aal5 returns pdu 0x%p with length %d", skb, skb->len); + dbg ("udsl_decode_aal5 returns pdu 0x%p with length %d", skb, skb->len); return skb; -}; +} /************* ** encode ** *************/ -static void udsl_groom_skb (struct atm_vcc *vcc, struct sk_buff *skb) { +static void udsl_groom_skb (struct atm_vcc *vcc, struct sk_buff *skb) +{ struct udsl_control *ctrl = UDSL_SKB (skb); unsigned int i, zero_padding; unsigned char zero = 0; @@ -480,7 +433,8 @@ ctrl->aal5_trailer [7] = crc; } -unsigned int udsl_write_cells (unsigned int howmany, struct sk_buff *skb, unsigned char **target_p) { +static unsigned int udsl_write_cells (unsigned int howmany, struct sk_buff *skb, unsigned char **target_p) +{ struct udsl_control *ctrl = UDSL_SKB (skb); unsigned char *target = *target_p; unsigned int nc, ne, i; @@ -569,7 +523,7 @@ unsigned char *data_start; struct sk_buff *skb; struct urb *urb; - struct atmsar_vcc_data *atmsar_vcc = NULL; + struct udsl_vcc_data *atmsar_vcc = NULL; struct sk_buff *new = NULL, *tmp = NULL; int err; @@ -597,40 +551,28 @@ dbg ("skb->len = %d", skb->len); PACKETDEBUG (skb->data, skb->len); - while ((new = - atmsar_decode_rawcell (instance->atmsar_vcc_list, skb, - &atmsar_vcc)) != NULL) { + while ((new = udsl_decode_rawcell (instance, skb, &atmsar_vcc))) { dbg ("(after cell processing)skb->len = %d", new->len); - switch (atmsar_vcc->type) { - case ATM_AAL5: - tmp = new; - new = atmsar_decode_aal5 (atmsar_vcc, new); - - /* we can't send NULL skbs upstream, the ATM layer would try to close the vcc... */ - if (new) { - dbg ("(after aal5 decap) skb->len = %d", new->len); - if (new->len && atm_charge (atmsar_vcc->vcc, new->truesize)) { - PACKETDEBUG (new->data, new->len); - atmsar_vcc->vcc->push (atmsar_vcc->vcc, new); - } else { - dbg - ("dropping incoming packet : rx_inuse = %d, vcc->sk->rcvbuf = %d, skb->true_size = %d", - atomic_read (&atmsar_vcc->vcc->rx_inuse), - atmsar_vcc->vcc->sk->rcvbuf, new->truesize); - dev_kfree_skb (new); - } + tmp = new; + new = udsl_decode_aal5 (atmsar_vcc, new); + + /* we can't send NULL skbs upstream, the ATM layer would try to close the vcc... */ + if (new) { + dbg ("(after aal5 decap) skb->len = %d", new->len); + if (new->len && atm_charge (atmsar_vcc->vcc, new->truesize)) { + PACKETDEBUG (new->data, new->len); + atmsar_vcc->vcc->push (atmsar_vcc->vcc, new); } else { - dbg ("atmsar_decode_aal5 returned NULL!"); - dev_kfree_skb (tmp); + dbg + ("dropping incoming packet : rx_inuse = %d, vcc->sk->rcvbuf = %d, skb->true_size = %d", + atomic_read (&atmsar_vcc->vcc->rx_inuse), + atmsar_vcc->vcc->sk->rcvbuf, new->truesize); + dev_kfree_skb (new); } - break; - default: - /* not supported. we delete the skb. */ - printk (KERN_INFO - "SpeedTouch USB: illegal vcc type. Dropping packet.\n"); - dev_kfree_skb (new); - break; + } else { + dbg ("udsl_decode_aal5 returned NULL!"); + dev_kfree_skb (tmp); } } @@ -901,95 +843,6 @@ ** ATM ** **********/ -#define ATMSAR_DEF_MTU_AAL0 48 -#define ATMSAR_DEF_MTU_AAL1 47 -#define ATMSAR_DEF_MTU_AAL2 0 /* not supported */ -#define ATMSAR_DEF_MTU_AAL34 0 /* not supported */ -#define ATMSAR_DEF_MTU_AAL5 65535 /* max mtu .. */ - -struct atmsar_vcc_data *atmsar_open (struct atmsar_vcc_data **list, struct atm_vcc *vcc, uint type, - ushort vpi, ushort vci, unchar pti, unchar gfc, uint flags) -{ - struct atmsar_vcc_data *new; - - if (!vcc) - return NULL; - - new = kmalloc (sizeof (struct atmsar_vcc_data), GFP_KERNEL); - - if (!new) - return NULL; - - memset (new, 0, sizeof (struct atmsar_vcc_data)); - new->vcc = vcc; - new->stats = vcc->stats; - new->type = type; - new->next = NULL; - new->gfc = gfc; - new->vp = vpi; - new->vc = vci; - new->pti = pti; - - switch (type) { - case ATM_AAL0: - new->mtu = ATMSAR_DEF_MTU_AAL0; - break; - case ATM_AAL1: - new->mtu = ATMSAR_DEF_MTU_AAL1; - break; - case ATM_AAL2: - new->mtu = ATMSAR_DEF_MTU_AAL2; - break; - case ATM_AAL34: - /* not supported */ - new->mtu = ATMSAR_DEF_MTU_AAL34; - break; - case ATM_AAL5: - new->mtu = ATMSAR_DEF_MTU_AAL5; - break; - } - - new->atmHeader = ((unsigned long) gfc << ATM_HDR_GFC_SHIFT) - | ((unsigned long) vpi << ATM_HDR_VPI_SHIFT) - | ((unsigned long) vci << ATM_HDR_VCI_SHIFT) - | ((unsigned long) pti << ATM_HDR_PTI_SHIFT); - new->flags = flags; - new->next = NULL; - new->reasBuffer = NULL; - - new->next = *list; - *list = new; - - dbg ("Allocated new SARLib vcc 0x%p with vp %d vc %d", new, vpi, vci); - - return new; -} - -void atmsar_close (struct atmsar_vcc_data **list, struct atmsar_vcc_data *vcc) -{ - struct atmsar_vcc_data *work; - - if (*list == vcc) { - *list = (*list)->next; - } else { - for (work = *list; work && work->next && (work->next != vcc); work = work->next); - - /* return if not found */ - if (work->next != vcc) - return; - - work->next = work->next->next; - } - - if (vcc->reasBuffer) { - dev_kfree_skb (vcc->reasBuffer); - } - - dbg ("Allocated SARLib vcc 0x%p with vp %d vc %d", vcc, vcc->vp, vcc->vc); - - kfree (vcc); -} - static void udsl_atm_dev_close (struct atm_dev *dev) { struct udsl_instance_data *instance = dev->dev_data; @@ -1061,11 +914,10 @@ return 0; } -#define ATMSAR_SET_PTI 0x2L - static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci) { struct udsl_instance_data *instance = vcc->dev->dev_data; + struct udsl_vcc_data *new; dbg ("udsl_atm_open called"); @@ -1074,63 +926,97 @@ return -ENODEV; } - /* at the moment only AAL5 support */ + if ((vpi == ATM_VPI_ANY) || (vci == ATM_VCI_ANY)) + return -EINVAL; + + /* only support AAL5 */ if (vcc->qos.aal != ATM_AAL5) return -EINVAL; - MOD_INC_USE_COUNT; + down (&instance->serialize); /* vs self, udsl_atm_close */ - vcc->dev_data = - atmsar_open (&(instance->atmsar_vcc_list), vcc, ATM_AAL5, vpi, vci, 0, 0, - ATMSAR_USE_53BYTE_CELL | ATMSAR_SET_PTI); - if (!vcc->dev_data) { - MOD_DEC_USE_COUNT; - return -ENOMEM; /* this is the only reason atmsar_open can fail... */ + if (udsl_find_vcc (instance, vpi, vci)) { + up (&instance->serialize); + return -EADDRINUSE; + } + + if (!(new = kmalloc (sizeof (struct udsl_vcc_data), GFP_KERNEL))) { + up (&instance->serialize); + return -ENOMEM; } + memset (new, 0, sizeof (struct udsl_vcc_data)); + new->vcc = vcc; + new->vpi = vpi; + new->vci = vci; + new->mtu = UDSL_MAX_AAL5_MRU; + + vcc->dev_data = new; vcc->vpi = vpi; vcc->vci = vci; + + tasklet_disable (&instance->receive_tasklet); + list_add (&new->list, &instance->vcc_list); + tasklet_enable (&instance->receive_tasklet); + set_bit (ATM_VF_ADDR, &vcc->flags); set_bit (ATM_VF_PARTIAL, &vcc->flags); set_bit (ATM_VF_READY, &vcc->flags); - ((struct atmsar_vcc_data *)vcc->dev_data)->mtu = UDSL_MAX_AAL5_MRU; + up (&instance->serialize); + + dbg ("Allocated new SARLib vcc 0x%p with vpi %d vci %d", new, vpi, vci); + + MOD_INC_USE_COUNT; if (instance->firmware_loaded) udsl_fire_receivers (instance); dbg ("udsl_atm_open successful"); + return 0; } static void udsl_atm_close (struct atm_vcc *vcc) { struct udsl_instance_data *instance = vcc->dev->dev_data; + struct udsl_vcc_data *vcc_data = vcc->dev_data; dbg ("udsl_atm_close called"); - if (!instance) { - dbg ("NULL instance!"); + if (!instance || !vcc_data) { + dbg ("NULL data!"); return; } - /* freeing resources */ - /* cancel all sends on this vcc */ + dbg ("Deallocating SARLib vcc 0x%p with vpi %d vci %d", vcc_data, vcc_data->vpi, vcc_data->vci); + udsl_cancel_send (instance, vcc); - atmsar_close (&(instance->atmsar_vcc_list), vcc->dev_data); + down (&instance->serialize); /* vs self, udsl_atm_open */ + + tasklet_disable (&instance->receive_tasklet); + list_del (&vcc_data->list); + tasklet_enable (&instance->receive_tasklet); + + if (vcc_data->reasBuffer) + kfree_skb (vcc_data->reasBuffer); + vcc_data->reasBuffer = NULL; + + kfree (vcc_data); vcc->dev_data = NULL; - clear_bit (ATM_VF_PARTIAL, &vcc->flags); - /* freeing address */ vcc->vpi = ATM_VPI_UNSPEC; vcc->vci = ATM_VCI_UNSPEC; + clear_bit (ATM_VF_READY, &vcc->flags); + clear_bit (ATM_VF_PARTIAL, &vcc->flags); clear_bit (ATM_VF_ADDR, &vcc->flags); + up (&instance->serialize); + MOD_DEC_USE_COUNT; dbg ("udsl_atm_close successful"); - return; } static int udsl_atm_ioctl (struct atm_dev *dev, unsigned int cmd, void *arg) @@ -1208,6 +1094,8 @@ init_MUTEX (&instance->serialize); instance->usb_dev = dev; + + INIT_LIST_HEAD (&instance->vcc_list); spin_lock_init (&instance->spare_receivers_lock); INIT_LIST_HEAD (&instance->spare_receivers); diff -Nru a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c --- a/drivers/usb/misc/usbtest.c Wed Apr 2 22:24:07 2003 +++ b/drivers/usb/misc/usbtest.c Wed Apr 2 22:24:07 2003 @@ -881,6 +881,8 @@ init_completion (&completion); urb = simple_alloc_urb (testdev_to_usbdev (dev), pipe, size); + if (!urb) + return -ENOMEM; if (async) urb->transfer_flags |= URB_ASYNC_UNLINK; urb->context = &completion; @@ -1404,6 +1406,11 @@ /* re-enumerated usb test device firmware */ { USB_DEVICE (0xfff0, 0xfff0), + .driver_info = (unsigned long) &fw_info, + }, + + /* "Gadget Zero" firmware runs under Linux */ + { USB_DEVICE (0x0525, 0xa4a0), .driver_info = (unsigned long) &fw_info, }, diff -Nru a/drivers/usb/net/cdc-ether.c b/drivers/usb/net/cdc-ether.c --- a/drivers/usb/net/cdc-ether.c Wed Apr 2 22:24:04 2003 +++ b/drivers/usb/net/cdc-ether.c Wed Apr 2 22:24:04 2003 @@ -269,22 +269,8 @@ static int CDCEther_start_xmit( struct sk_buff *skb, struct net_device *net ) { ether_dev_t *ether_dev = net->priv; - int count; int res; - // If we are told to transmit an ethernet frame that fits EXACTLY - // into an integer number of USB packets, we force it to send one - // more byte so the device will get a runt USB packet signalling the - // end of the ethernet frame - if ( (skb->len) ^ (ether_dev->data_ep_out_size) ) { - // It was not an exact multiple - // no need to add anything extra - count = skb->len; - } else { - // Add one to make it NOT an exact multiple - count = skb->len + 1; - } - // Tell the kernel, "No more frames 'til we are done // with this one.' netif_stop_queue( net ); @@ -299,7 +285,10 @@ write_bulk_callback, ether_dev ); // Tell the URB how much it will be transporting today - ether_dev->tx_urb->transfer_buffer_length = count; + ether_dev->tx_urb->transfer_buffer_length = skb->len; + + /* Deal with the zero length problem, I hope */ + ether_dev->tx_urb->transfer_flags |= URB_ZERO_PACKET; // Send the URB on its merry way. if ((res = usb_submit_urb(ether_dev->tx_urb, GFP_ATOMIC))) { diff -Nru a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c --- a/drivers/usb/serial/generic.c Wed Apr 2 22:24:04 2003 +++ b/drivers/usb/serial/generic.c Wed Apr 2 22:24:04 2003 @@ -17,6 +17,7 @@ #include #include #include +#include #ifdef CONFIG_USB_SERIAL_DEBUG static int debug = 1; diff -Nru a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c --- a/drivers/usb/serial/kobil_sct.c Wed Apr 2 22:24:07 2003 +++ b/drivers/usb/serial/kobil_sct.c Wed Apr 2 22:24:07 2003 @@ -406,8 +406,6 @@ int result = 0; int todo = 0; struct kobil_private * priv; - int i; - char *data; if (count == 0) { dbg("%s - port %d write request of 0 bytes", __FUNCTION__, port->number); @@ -421,19 +419,6 @@ return -ENOMEM; } - // BEGIN DEBUG - data = (unsigned char *) kmalloc((3 * count + 10) * sizeof(char), GFP_KERNEL); - if (! data) { - return (-1); - } - memset(data, 0, (3 * count + 10)); - for (i = 0; i < count; i++) { - sprintf(data +3*i, "%02X ", buf[i]); - } - dbg(" %d --> %s", port->number, data ); - kfree(data); - // END DEBUG - // Copy data to buffer if (from_user) { if (copy_from_user(priv->buf + priv->filled, buf, count)) { @@ -442,6 +427,8 @@ } else { memcpy (priv->buf + priv->filled, buf, count); } + + usb_serial_debug_data (__FILE__, __FUNCTION__, count, priv->buf + priv->filled); priv->filled = priv->filled + count; diff -Nru a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c --- a/drivers/usb/storage/isd200.c Wed Apr 2 22:24:05 2003 +++ b/drivers/usb/storage/isd200.c Wed Apr 2 22:24:05 2003 @@ -405,11 +405,14 @@ { union ata_cdb ata; struct scsi_cmnd srb; + struct scsi_device srb_dev; struct isd200_info *info = (struct isd200_info *)us->extra; int status; memset(&ata, 0, sizeof(ata)); memset(&srb, 0, sizeof(srb)); + memset(&srb_dev, 0, sizeof(srb_dev)); + srb.device = &srb_dev; ata.generic.SignatureByte0 = info->ConfigData.ATAMajorCommand; ata.generic.SignatureByte1 = info->ConfigData.ATAMinorCommand; @@ -479,6 +482,7 @@ } memcpy(srb.cmnd, &ata, sizeof(ata.generic)); + srb.cmd_len = sizeof(ata.generic); status = usb_stor_Bulk_transport(&srb, us); if (status == USB_STOR_TRANSPORT_GOOD) status = ISD200_GOOD; @@ -538,6 +542,7 @@ /* send the command to the transport layer */ srb->resid = 0; memcpy(srb->cmnd, ataCdb, sizeof(ataCdb->generic)); + srb->cmd_len = sizeof(ataCdb->generic); transferStatus = usb_stor_Bulk_transport(srb, us); /* if the command gets aborted by the higher layers, we need to diff -Nru a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c --- a/drivers/usb/storage/scsiglue.c Wed Apr 2 22:24:05 2003 +++ b/drivers/usb/storage/scsiglue.c Wed Apr 2 22:24:05 2003 @@ -209,21 +209,14 @@ return result; } -/* This resets the device port, and simulates the device - * disconnect/reconnect for all drivers which have claimed - * interfaces, including ourself. */ +/* This resets the device port */ +/* It refuses to work if there's more than one interface in + this device, so that other users are not affected. */ /* This is always called with scsi_lock(srb->host) held */ -/* FIXME: This needs to be re-examined in the face of the new - * hotplug system -- this will implicitly cause a detach/reattach of - * usb-storage, which is not what we want now. - * - * Can we just skip over usb-storage in the while loop? - */ static int usb_storage_bus_reset( Scsi_Cmnd *srb ) { struct us_data *us; - int i; int result; /* we use the usb_reset_device() function to handle this for us */ @@ -231,36 +224,25 @@ scsi_unlock(srb->device->host); us = (struct us_data *)srb->device->host->hostdata[0]; - /* attempt to reset the port */ - result = usb_reset_device(us->pusb_dev); - US_DEBUGP("usb_reset_device returns %d\n", result); - if (result < 0) { - scsi_lock(srb->device->host); - return FAILED; + /* The USB subsystem doesn't handle synchronisation between + a device's several drivers. Therefore we reset only devices + with one interface which we of course own. + */ + + //FIXME: needs locking against config changes + + if ( us->pusb_dev->actconfig->desc.bNumInterfaces == 1) { + /* attempt to reset the port */ + result = usb_reset_device(us->pusb_dev); + US_DEBUGP("usb_reset_device returns %d\n", result); + } else { + result = -EBUSY; + US_DEBUGP("cannot reset a multiinterface device. failing to reset.\n"); } - /* FIXME: This needs to lock out driver probing while it's working - * or we can have race conditions */ - /* This functionality really should be provided by the khubd thread */ - for (i = 0; i < us->pusb_dev->actconfig->desc.bNumInterfaces; i++) { - struct usb_interface *intf = - &us->pusb_dev->actconfig->interface[i]; - - /* if this is an unclaimed interface, skip it */ - if (!intf->driver) { - continue; - } - - US_DEBUGP("Examining driver %s...", intf->driver->name); - - /* simulate a disconnect and reconnect for all interfaces */ - US_DEBUGPX("simulating disconnect/reconnect.\n"); - usb_device_remove (&intf->dev); - usb_device_probe (&intf->dev); - } US_DEBUGP("bus_reset() complete\n"); scsi_lock(srb->device->host); - return SUCCESS; + return result < 0 ? FAILED : SUCCESS; } /*********************************************************************** diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c --- a/drivers/usb/storage/transport.c Wed Apr 2 22:24:05 2003 +++ b/drivers/usb/storage/transport.c Wed Apr 2 22:24:05 2003 @@ -126,6 +126,7 @@ us->current_urb->actual_length = 0; us->current_urb->error_count = 0; us->current_urb->transfer_flags = URB_ASYNC_UNLINK; + us->current_urb->status = 0; /* submit the URB */ status = usb_submit_urb(us->current_urb, GFP_NOIO); @@ -900,7 +901,7 @@ bcb.DataTransferLength = cpu_to_le32(transfer_length); bcb.Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0; bcb.Tag = srb->serial_number; - bcb.Lun = srb->cmnd[1] >> 5; + bcb.Lun = srb->device->lun; if (us->flags & US_FL_SCM_MULT_TARG) bcb.Lun |= srb->device->id << 4; bcb.Length = srb->cmd_len; diff -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c --- a/drivers/usb/storage/usb.c Wed Apr 2 22:24:04 2003 +++ b/drivers/usb/storage/usb.c Wed Apr 2 22:24:04 2003 @@ -360,7 +360,7 @@ } else if (us->srb->device->lun > us->max_lun) { - US_DEBUGP("Bad LUN (%d/%d)\n", + US_DEBUGP("Bad LUN (%d:%d)\n", us->srb->device->id, us->srb->device->lun); us->srb->result = DID_BAD_TARGET << 16; } @@ -475,8 +475,6 @@ */ static void usb_stor_deallocate_urbs(struct us_data *ss) { - int result; - /* free the scatter-gather request block */ if (ss->current_sg) { kfree(ss->current_sg); @@ -486,8 +484,6 @@ /* free up the main URB for this device */ if (ss->current_urb) { US_DEBUGP("-- releasing main URB\n"); - result = usb_unlink_urb(ss->current_urb); - US_DEBUGP("-- usb_unlink_urb() returned %d\n", result); usb_free_urb(ss->current_urb); ss->current_urb = NULL; } diff -Nru a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c --- a/drivers/usb/usb-skeleton.c Wed Apr 2 22:24:05 2003 +++ b/drivers/usb/usb-skeleton.c Wed Apr 2 22:24:05 2003 @@ -72,13 +72,15 @@ MODULE_PARM_DESC(debug, "Debug enabled or not"); -/* Define these values to match your device */ +/* Define these values to match your devices */ #define USB_SKEL_VENDOR_ID 0xfff0 #define USB_SKEL_PRODUCT_ID 0xfff0 /* table of devices that work with this driver */ static struct usb_device_id skel_table [] = { { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) }, + /* "Gadget Zero" firmware runs under Linux */ + { USB_DEVICE(0x0525, 0xa4a0) }, { } /* Terminating entry */ }; @@ -707,7 +709,7 @@ /* register this driver with the USB subsystem */ result = usb_register(&skel_driver); if (result < 0) { - err("usb_register failed for the "__FILE__" driver. Error number %d", + err("usb_register failed. Error number %d", result); return -1; } diff -Nru a/drivers/video/Makefile b/drivers/video/Makefile --- a/drivers/video/Makefile Wed Apr 2 22:24:04 2003 +++ b/drivers/video/Makefile Wed Apr 2 22:24:04 2003 @@ -31,7 +31,7 @@ obj-$(CONFIG_FB_ANAKIN) += anakinfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_CYBER) += cyberfb.o -obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o +obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_SGIVW) += sgivwfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_3DFX) += tdfxfb.o cfbimgblt.o obj-$(CONFIG_FB_MAC) += macfb.o macmodes.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o diff -Nru a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c --- a/drivers/video/cyber2000fb.c Wed Apr 2 22:24:04 2003 +++ b/drivers/video/cyber2000fb.c Wed Apr 2 22:24:04 2003 @@ -55,12 +55,6 @@ #include #include -#include