# 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.6.4 -> 1.1630 # arch/i386/kernel/process.c 1.62 -> 1.63 # include/acpi/acglobal.h 1.28 -> 1.29 # drivers/video/aty/radeon_monitor.c 1.4 -> 1.5 # drivers/net/8139too.c 1.85 -> 1.86 # include/asm-parisc/ioctl.h 1.3 -> 1.4 # drivers/net/tulip/timer.c 1.7 -> 1.8 # drivers/char/viocons.c 1.2 -> 1.3 # fs/nfs/read.c 1.34 -> 1.36 # sound/pcmcia/Makefile 1.1 -> 1.2 # fs/ufs/super.c 1.38 -> 1.39 # arch/m68knommu/kernel/syscalltable.S 1.4 -> 1.5 # arch/sparc64/kernel/smp.c 1.66 -> 1.67 # include/acpi/acpixf.h 1.25 -> 1.26 # drivers/net/3c59x.c 1.43.1.2 -> 1.49 # drivers/scsi/megaraid.c 1.59 -> 1.61 # drivers/net/eexpress.c 1.16 -> 1.17 # sound/pci/emu10k1/emu10k1.c 1.14 -> 1.15 # arch/arm/common/sa1111-pcibuf.c 1.11 -> 1.12 # include/asm-x86_64/smp.h 1.16 -> 1.17 # include/asm-alpha/pci.h 1.19 -> 1.20 # include/asm-parisc/semaphore.h 1.6 -> 1.7 # drivers/ide/legacy/macide.c 1.5 -> 1.6 # arch/parisc/kernel/pci.c 1.15 -> 1.16 # drivers/scsi/sym53c8xx_2/sym_hipd.c 1.15 -> 1.16 # drivers/scsi/libata-core.c 1.22 -> 1.25 # include/linux/dm-ioctl.h 1.4 -> 1.5 # drivers/scsi/sata_sil.c 1.10 -> 1.12 # include/asm-parisc/unistd.h 1.11 -> 1.12 # arch/parisc/kernel/head64.S 1.4 -> 1.5 # sound/core/seq/oss/seq_oss_midi.c 1.9 -> 1.11 # fs/adfs/super.c 1.27 -> 1.28 # drivers/media/dvb/frontends/tda1004x.c 1.8 -> 1.9 # drivers/scsi/scsi_error.c 1.69 -> 1.71 # drivers/net/3c501.c 1.21 -> 1.22 # arch/x86_64/kernel/traps.c 1.34 -> 1.35 # drivers/md/dm-crypt.c 1.3 -> 1.5 # include/acpi/acutils.h 1.29 -> 1.30 # fs/nfs/nfs4state.c 1.17 -> 1.19 # fs/libfs.c 1.30 -> 1.31 # sound/pci/emu10k1/emupcm.c 1.16 -> 1.18 # drivers/parisc/eisa.c 1.9 -> 1.10 # sound/pci/Makefile 1.15 -> 1.19 # arch/x86_64/mm/fault.c 1.21 -> 1.22 # sound/drivers/opl3/Makefile 1.14 -> 1.16 # include/asm-ppc64/unistd.h 1.26 -> 1.27 # sound/pci/korg1212/korg1212.c 1.27 -> 1.29 # arch/m68k/kernel/entry.S 1.14 -> 1.15 # include/linux/cdrom.h 1.16 -> 1.17 # sound/pci/ac97/ac97_patch.h 1.13 -> 1.14 # arch/sparc/kernel/setup.c 1.25 -> 1.26 # drivers/md/raid6main.c 1.4 -> 1.6 # sound/ppc/tumbler.c 1.16 -> 1.20 # sound/core/seq/oss/seq_oss_synth.c 1.12 -> 1.13 # include/asm-arm/dma-mapping.h 1.8 -> 1.9 # drivers/net/tulip/de4x5.c 1.35 -> 1.36 # drivers/net/wan/cosa.c 1.29 -> 1.30 # fs/lockd/clntproc.c 1.9 -> 1.10 # drivers/net/bagetlance.c 1.10 -> 1.11 # sound/synth/Makefile 1.12 -> 1.13 # include/linux/libata.h 1.9 -> 1.12 # drivers/net/irda/vlsi_ir.c 1.29 -> 1.30 # drivers/char/Kconfig 1.30 -> 1.31 # drivers/net/forcedeth.c 1.6 -> 1.7 # include/asm-i386/edd.h 1.7 -> 1.8 # drivers/net/hamradio/baycom_ser_hdx.c 1.12 -> 1.13 # arch/x86_64/ia32/ia32_binfmt.c 1.22 -> 1.23 # drivers/net/bmac.c 1.19 -> 1.20 # drivers/message/fusion/mptctl.c 1.18 -> 1.19 # include/scsi/scsi_device.h 1.11 -> 1.14 # fs/cramfs/inode.c 1.36 -> 1.37 # drivers/scsi/oktagon_esp.c 1.13 -> 1.14 # drivers/mtd/devices/blkmtd.c 1.37 -> 1.38 # drivers/net/3c509.c 1.45 -> 1.46 # arch/x86_64/kernel/setup.c 1.30 -> 1.31 # sound/sparc/cs4231.c 1.12 -> 1.13 # net/ipv4/ipconfig.c 1.36 -> 1.37 # arch/parisc/defconfig 1.8 -> 1.9 # sound/pci/ice1712/ice1712.h 1.11 -> 1.13 # include/asm-x86_64/page.h 1.11 -> 1.12 # fs/open.c 1.56 -> 1.57 # drivers/acpi/parser/psscope.c 1.12 -> 1.13 # drivers/net/natsemi.c 1.57 -> 1.58 # drivers/scsi/hosts.c 1.96 -> 1.97 # include/sound/memalloc.h 1.3 -> 1.6 # net/Kconfig 1.28.1.2 -> 1.32 # sound/arm/sa11xx-uda1341.c 1.13 -> 1.14 # arch/i386/lib/Makefile 1.12 -> 1.13 # drivers/scsi/53c700.h 1.15 -> 1.16 # net/sunrpc/sysctl.c 1.8 -> 1.9 # drivers/net/hp-plus.c 1.13 -> 1.14 # drivers/scsi/cpqfcTSinit.c 1.43 -> 1.44 # drivers/net/sb1000.c 1.24 -> 1.25 # drivers/message/fusion/lsi/mpi_init.h 1.4 -> 1.5 # init/initramfs.c 1.14 -> 1.15 # drivers/net/wd.c 1.16 -> 1.17 # drivers/net/myri_sbus.c 1.18 -> 1.19 # fs/nfs/mount_clnt.c 1.7 -> 1.8 # arch/ppc64/kernel/pmac_smp.c 1.2 -> 1.3 # arch/x86_64/lib/io.c 1.2 -> 1.4 # mm/page_alloc.c 1.190 -> 1.195 # mm/readahead.c 1.40 -> 1.41 # arch/ia64/ia32/ia32_support.c 1.13 -> 1.14 # sound/core/seq/oss/seq_oss_init.c 1.6 -> 1.7 # drivers/acpi/utilities/uteval.c 1.21 -> 1.22 # arch/alpha/kernel/alpha_ksyms.c 1.35 -> 1.36 # sound/pci/cs46xx/cs46xx_lib.c 1.41 -> 1.44 # init/do_mounts_initrd.c 1.6 -> 1.7 # drivers/acpi/hardware/hwsleep.c 1.24 -> 1.25 # arch/sparc/kernel/sparc_ksyms.c 1.26 -> 1.27 # Documentation/sound/alsa/ALSA-Configuration.txt 1.28 -> 1.33 # sound/drivers/vx/vx_pcm.c 1.2 -> 1.3 # Documentation/scsi/sym53c8xx_2.txt 1.3 -> 1.4 # drivers/net/tokenring/skisa.c 1.15 -> 1.16 # arch/i386/kernel/head.S 1.30 -> 1.31 # include/linux/nfs_page.h 1.12 -> 1.13 # arch/s390/kernel/syscalls.S 1.7 -> 1.8 # drivers/net/fec.c 1.8 -> 1.9 # drivers/net/tulip/pnic2.c 1.2 -> 1.3 # sound/pci/ice1712/delta.c 1.11 -> 1.12 # include/asm-ia64/machvec_hpzx1.h 1.7 -> 1.8 # drivers/block/ll_rw_blk.c 1.231 -> 1.235 # sound/core/seq/seq_memory.c 1.9 -> 1.10 # sound/drivers/vx/Makefile 1.1 -> 1.2 # drivers/net/wireless/airo.c 1.84 -> 1.85 # drivers/acpi/utilities/utglobal.c 1.33 -> 1.34 # include/asm-ia64/unistd.h 1.38 -> 1.39 # drivers/net/8390.c 1.18.1.1 -> 1.20 # drivers/char/watchdog/pcwd_pci.c 1.1 -> 1.2 # sound/isa/sscape.c 1.10 -> 1.12 # drivers/net/smc-mca.c 1.13 -> 1.14 # arch/sparc/kernel/sun4d_smp.c 1.13 -> 1.14 # arch/s390/appldata/appldata_mem.c 1.1 -> 1.2 # include/acpi/acobject.h 1.22 -> 1.23 # sound/core/seq/seq_clientmgr.c 1.23 -> 1.24 # fs/coda/dir.c 1.26 -> 1.27 # drivers/ieee1394/sbp2.c 1.64 -> 1.65 # drivers/net/lasi_82596.c 1.23 -> 1.25 # include/asm-i386/module.h 1.9 -> 1.10 # sound/pci/ac97/ak4531_codec.c 1.6 -> 1.7 # drivers/net/tlan.c 1.30 -> 1.31 # fs/smbfs/inode.c 1.46 -> 1.48 # drivers/message/fusion/lsi/mpi.h 1.5 -> 1.6 # drivers/char/watchdog/eurotechwdt.c 1.17 -> 1.18 # mm/vmscan.c 1.178 -> 1.198 # include/asm-parisc/io.h 1.6 -> 1.7 # sound/pci/ac97/ac97_pcm.c 1.10 -> 1.11 # fs/proc/proc_misc.c 1.95 -> 1.96 # sound/isa/cmi8330.c 1.20 -> 1.23 # arch/sparc64/kernel/pci_iommu.c 1.9 -> 1.10 # arch/m68k/bvme6000/bvmeints.c 1.5 -> 1.6 # arch/sparc/kernel/process.c 1.35 -> 1.36 # drivers/net/smc-ultra.c 1.19 -> 1.20 # drivers/scsi/dc395x.c 1.26 -> 1.32 # drivers/net/sk98lin/skge.c 1.36 -> 1.37 # drivers/net/loopback.c 1.12 -> 1.13 # arch/ia64/hp/common/sba_iommu.c 1.37 -> 1.38 # arch/i386/Kconfig 1.104 -> 1.109 # drivers/cdrom/cdrom.c 1.48 -> 1.49 # include/scsi/scsi_host.h 1.13 -> 1.14 # drivers/message/fusion/lsi/mpi_targ.h 1.5 -> 1.6 # arch/ia64/sn/kernel/irq.c 1.20 -> 1.21 # drivers/scsi/53c700.c 1.46 -> 1.50 # Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl 1.3 -> 1.4 # include/asm-parisc/grfioctl.h 1.1 -> 1.2 # drivers/message/fusion/lsi/mpi_fc.h 1.4 -> 1.5 # arch/x86_64/kernel/x8664_ksyms.c 1.26 -> 1.28 # arch/m68k/kernel/sys_m68k.c 1.7 -> 1.8 # include/linux/udf_fs.h 1.9 -> 1.10 # include/asm-sparc64/unistd.h 1.28 -> 1.29 # drivers/message/fusion/mptbase.h 1.15 -> 1.18 # include/asm-sparc64/pci.h 1.18 -> 1.19 # sound/isa/opti9xx/opti92x-ad1848.c 1.24 -> 1.28 # drivers/acpi/parser/psparse.c 1.24 -> 1.25 # arch/x86_64/pci/Makefile 1.5 -> 1.6 # arch/x86_64/lib/Makefile 1.11 -> 1.12 # init/main.c 1.125 -> 1.126 # arch/i386/kernel/traps.c 1.65 -> 1.66 # include/asm-i386/topology.h 1.8 -> 1.9 # include/linux/lockd/lockd.h 1.7 -> 1.9 # include/asm-sparc/sbus.h 1.5 -> 1.6 # drivers/scsi/sata_via.c 1.5 -> 1.6 # arch/i386/kernel/Makefile 1.55 -> 1.57 # drivers/parisc/ccio-dma.c 1.15 -> 1.17 # drivers/mca/mca-bus.c 1.5 -> 1.6 # include/asm-generic/pci-dma-compat.h 1.3 -> 1.4 # Documentation/scsi/st.txt 1.13 -> 1.14 # sound/core/init.c 1.23 -> 1.25 # sound/sparc/amd7930.c 1.7 -> 1.8 # include/asm-sparc64/sbus.h 1.3 -> 1.4 # drivers/char/watchdog/machzwd.c 1.29 -> 1.30 # scripts/modpost.c 1.19 -> 1.20 # drivers/char/watchdog/sc1200wdt.c 1.10 -> 1.11 # arch/parisc/kernel/pacache.S 1.3 -> 1.4 # drivers/scsi/scsi_sysfs.c 1.39 -> 1.43 # fs/ufs/inode.c 1.21 -> 1.22 # arch/i386/kernel/vmlinux.lds.S 1.32 -> 1.33 # drivers/md/raid5.c 1.84 -> 1.86 # drivers/net/tulip/winbond-840.c 1.39 -> 1.40 # arch/x86_64/mm/init.c 1.25 -> 1.26 # arch/mips/mm/dma-noncoherent.c 1.1 -> 1.2 # arch/parisc/configs/a500_defconfig 1.1 -> 1.2 # arch/parisc/kernel/vmlinux.lds.S 1.16 -> 1.17 # drivers/char/synclinkmp.c 1.26 -> 1.27 # arch/x86_64/kernel/acpi/boot.c 1.15 -> 1.16 # security/dummy.c 1.32 -> 1.33 # sound/i2c/other/Makefile 1.2 -> 1.3 # drivers/net/ne2k-pci.c 1.19.1.1 -> 1.21 # sound/isa/cs423x/cs4231_lib.c 1.18 -> 1.21 # arch/parisc/kernel/entry.S 1.13 -> 1.14 # drivers/net/tulip/21142.c 1.10 -> 1.11 # drivers/char/watchdog/amd7xx_tco.c 1.14 -> 1.15 # drivers/net/hp.c 1.11 -> 1.12 # arch/i386/kernel/pci-dma.c 1.11 -> 1.12 # include/linux/blkdev.h 1.136 -> 1.138 # drivers/block/Kconfig 1.18 -> 1.19 # drivers/net/fc/iph5526.c 1.31 -> 1.32 # drivers/message/fusion/mptbase.c 1.18 -> 1.20 # drivers/block/cciss_scsi.c 1.18 -> 1.19 # drivers/ieee1394/ieee1394_core.c 1.53 -> 1.54 # drivers/net/pcmcia/3c574_cs.c 1.29 -> 1.30 # arch/x86_64/kernel/ioport.c 1.12 -> 1.13 # sound/pci/ice1712/ews.c 1.10 -> 1.11 # drivers/parisc/ccio-rm-dma.c 1.6 -> 1.7 # drivers/macintosh/mediabay.c 1.11 -> 1.12 # drivers/net/ethertap.c 1.12 -> 1.13 # drivers/net/rrunner.c 1.23 -> 1.25 # drivers/net/wireless/Kconfig 1.19 -> 1.20 # drivers/net/wan/comx-hw-munich.c 1.16 -> 1.17 # drivers/net/tulip/interrupt.c 1.23 -> 1.25 # drivers/media/dvb/frontends/alps_tdlb7.c 1.10 -> 1.11 # drivers/scsi/sr.c 1.99 -> 1.100 # drivers/net/wan/dscc4.c 1.59 -> 1.60 # drivers/net/starfire.c 1.34 -> 1.35 # arch/v850/kernel/rte_mb_a_pci.c 1.8 -> 1.9 # sound/drivers/vx/vx_mixer.c 1.1 -> 1.2 # include/linux/fs.h 1.287 -> 1.291 # drivers/net/tokenring/abyss.c 1.14 -> 1.15 # drivers/scsi/ini9100u.c 1.21 -> 1.22 # drivers/char/watchdog/alim1535_wdt.c 1.4 -> 1.5 # drivers/net/wireless/atmel.c 1.10 -> 1.11 # include/asm-parisc/keyboard.h 1.3 -> (deleted) # include/asm-ia64/hardirq.h 1.14 -> 1.15 # drivers/net/tulip/media.c 1.11 -> 1.12 # include/sound/emu10k1.h 1.23 -> 1.26 # drivers/md/dm-ioctl.c 1.31 -> 1.33 # fs/sysv/dir.c 1.15 -> 1.16 # drivers/net/pcnet32.c 1.45.1.16 -> 1.52 # fs/udf/dir.c 1.13 -> 1.15 # drivers/pci/pci.c 1.62 -> 1.63 # arch/sparc/kernel/smp.c 1.13 -> 1.14 # drivers/eisa/eisa-bus.c 1.14 -> 1.15 # drivers/net/Makefile 1.68.1.5 -> 1.73 # arch/x86_64/kernel/setup64.c 1.19 -> 1.20 # arch/alpha/kernel/smp.c 1.39 -> 1.40 # fs/lockd/svclock.c 1.7 -> 1.9 # drivers/char/watchdog/cpu5wdt.c 1.7 -> 1.8 # drivers/md/md.c 1.204 -> 1.205 # arch/x86_64/ia32/Makefile 1.20 -> 1.21 # arch/ia64/sn/io/machvec/pci_dma.c 1.26 -> 1.28 # arch/h8300/kernel/syscalls.S 1.3 -> 1.4 # arch/i386/mach-default/Makefile 1.8 -> 1.9 # drivers/net/sunlance.c 1.19 -> 1.20 # drivers/scsi/ncr53c8xx.c 1.37 -> 1.38 # Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl 1.21 -> 1.23 # include/linux/fb.h 1.62 -> 1.63 # drivers/net/ne2k_cbus.c 1.4 -> 1.5 # sound/usb/usbmixer.c 1.20 -> 1.21 # include/asm-ia64/sn/router.h 1.7 -> 1.8 # drivers/scsi/u14-34f.c 1.30 -> 1.31 # include/sound/sndmagic.h 1.17 -> 1.19 # arch/x86_64/kernel/mpparse.c 1.20 -> 1.21 # include/asm-parisc/superio.h 1.2 -> 1.3 # include/sound/cs46xx.h 1.13 -> 1.14 # sound/pci/emu10k1/emu10k1_callback.c 1.4 -> 1.5 # drivers/message/fusion/lsi/mpi_ioc.h 1.4 -> 1.5 # drivers/message/fusion/linux_compat.h 1.10 -> 1.11 # include/asm-v850/pci.h 1.4 -> 1.5 # fs/jffs2/super.c 1.28 -> 1.29 # fs/ext3/acl.c 1.15 -> 1.16 # sound/pci/rme9652/hdsp.c 1.29 -> 1.32 # sound/pci/ice1712/ice1712.c 1.25 -> 1.29 # drivers/net/sunhme.c 1.44 -> 1.45 # drivers/scsi/scsi_devinfo.c 1.7 -> 1.10 # arch/parisc/hpux/entry_hpux.S 1.3 -> 1.4 # include/asm-parisc/md.h 1.1 -> (deleted) # fs/afs/inode.c 1.9 -> 1.10 # arch/sparc64/kernel/setup.c 1.50 -> 1.51 # arch/i386/kernel/edd.c 1.20 -> 1.21 # drivers/scsi/aic7xxx/Kconfig.aic7xxx 1.12 -> 1.13 # sound/pci/ice1712/aureon.c 1.4 -> 1.5 # fs/hfs/super.c 1.26 -> 1.27 # drivers/net/atari_pamsnet.c 1.14 -> 1.15 # Documentation/i386/zero-page.txt 1.5 -> 1.6 # drivers/char/pcmcia/synclink_cs.c 1.30 -> 1.31 # sound/pci/Kconfig 1.13 -> 1.25 # arch/x86_64/kernel/entry.S 1.17 -> 1.18 # sound/pci/emu10k1/emuproc.c 1.9 -> 1.10 # include/asm-parisc/ide.h 1.10 -> 1.11 # include/linux/nfs_fs.h 1.64 -> 1.69 # sound/pci/rme96.c 1.22 -> 1.24 # drivers/net/wan/lapbether.c 1.20 -> 1.21 # drivers/char/synclink.c 1.48 -> 1.49 # arch/i386/kernel/asm-offsets.c 1.1 -> 1.2 # drivers/scsi/sym53c8xx_2/sym_hipd.h 1.4 -> 1.5 # arch/ppc/platforms/chrp_smp.c 1.9 -> 1.10 # fs/lockd/svc4proc.c 1.10 -> 1.12 # ipc/sem.c 1.26 -> 1.27 # include/sound/version.h 1.71 -> 1.72 # sound/pci/ac97/ac97_codec.c 1.61 -> 1.65 # sound/drivers/mpu401/mpu401_uart.c 1.18 -> 1.19 # fs/nfs/nfs2xdr.c 1.30 -> 1.31 # include/asm-ia64/machvec_sn2.h 1.11 -> 1.12 # drivers/net/yellowfin.c 1.28 -> 1.29 # arch/i386/mach-voyager/voyager_smp.c 1.18 -> 1.19 # init/do_mounts.c 1.61 -> 1.63 # include/sound/ymfpci.h 1.9 -> 1.10 # drivers/scsi/sym53c8xx_2/sym_defs.h 1.2 -> 1.3 # include/asm-ppc64/pci.h 1.19 -> 1.20 # arch/mips/mm/dma-coherent.c 1.1 -> 1.2 # drivers/scsi/aacraid/linit.c 1.26 -> 1.27 # net/sunrpc/clnt.c 1.50 -> 1.52 # include/asm-parisc/dma-mapping.h 1.5 -> 1.6 # fs/udf/truncate.c 1.7 -> 1.8 # arch/s390/kernel/sys_s390.c 1.9 -> 1.10 # drivers/net/pcmcia/xirc2ps_cs.c 1.30 -> 1.31 # Documentation/devices.txt 1.11 -> 1.12 # arch/i386/kernel/trampoline.S 1.8 -> 1.9 # sound/isa/wavefront/wavefront_synth.c 1.13 -> 1.14 # drivers/acpi/tables.c 1.21 -> 1.22 # arch/ia64/kernel/irq_ia64.c 1.17 -> 1.18 # mm/fadvise.c 1.10 -> 1.11 # drivers/char/watchdog/advantechwdt.c 1.21 -> 1.22 # drivers/net/at1700.c 1.20 -> 1.21 # kernel/signal.c 1.102 -> 1.103 # arch/m68k/mac/via.c 1.7 -> 1.8 # drivers/video/fm2fb.c 1.24 -> 1.25 # sound/isa/dt019x.c 1.19 -> 1.20 # sound/parisc/harmony.c 1.3 -> 1.5 # fs/afs/super.c 1.9 -> 1.10 # drivers/acpi/namespace/nseval.c 1.21 -> 1.22 # drivers/net/ne3210.c 1.12 -> 1.13 # fs/ufs/util.c 1.10 -> 1.11 # include/asm-x86_64/io.h 1.11 -> 1.12 # sound/core/pcm_lib.c 1.27 -> 1.29 # drivers/net/dl2k.c 1.31 -> 1.32 # sound/pci/trident/trident_synth.c 1.6 -> 1.7 # drivers/macintosh/Kconfig 1.4 -> 1.5 # include/asm-x86_64/pci.h 1.15 -> 1.16 # include/asm-i386/pci.h 1.26 -> 1.27 # sound/isa/es18xx.c 1.25 -> 1.28 # sound/usb/usbquirks.h 1.20 -> 1.23 # arch/parisc/kernel/hardware.c 1.5 -> 1.6 # sound/isa/gus/gus_pcm.c 1.11 -> 1.14 # drivers/message/fusion/scsi3.h 1.4 -> 1.5 # drivers/net/b44.c 1.14 -> 1.15 # drivers/scsi/aic7xxx/Kconfig.aic79xx 1.8 -> 1.9 # sound/ppc/Kconfig 1.1 -> 1.2 # arch/x86_64/ia32/sys_ia32.c 1.52 -> 1.53 # arch/sparc64/kernel/process.c 1.48 -> 1.49 # fs/udf/udfdecl.h 1.13 -> 1.14 # drivers/net/sis900.c 1.49 -> 1.50 # arch/x86_64/kernel/pci-gart.c 1.29 -> 1.31 # include/linux/usb.h 1.95 -> 1.96 # include/linux/usb_gadget.h 1.7 -> 1.8 # drivers/net/sunhme.h 1.6 -> 1.7 # drivers/net/wan/comx.c 1.21 -> 1.22 # sound/isa/sb/sb8_main.c 1.6 -> 1.9 # fs/super.c 1.114 -> 1.115 # drivers/ide/ide-cd.c 1.72 -> 1.73 # arch/ia64/pci/pci.c 1.41 -> 1.43 # sound/pci/rme9652/rme9652.c 1.24 -> 1.26 # arch/x86_64/ia32/ia32entry.S 1.28 -> 1.29 # drivers/net/tun.c 1.29 -> 1.30 # fs/fat/inode.c 1.88 -> 1.89 # fs/binfmt_elf.c 1.68 -> 1.69 # drivers/net/ne.c 1.18.1.1 -> 1.20 # mm/memory.c 1.153 -> 1.154 # sound/pci/ice1712/ice1724.c 1.18 -> 1.21 # drivers/net/ni5010.c 1.13 -> 1.14 # drivers/md/dm.h 1.12 -> 1.13 # drivers/net/e1000/e1000_ethtool.c 1.39 -> 1.40 # drivers/net/hplance.c 1.9 -> 1.10 # drivers/net/epic100.c 1.36 -> 1.37 # drivers/net/pcmcia/com20020_cs.c 1.17 -> 1.18 # drivers/video/modedb.c 1.10 -> 1.11 # include/linux/pci.h 1.119 -> 1.121 # drivers/net/hydra.c 1.12.1.2 -> 1.14 # arch/ia64/kernel/iosapic.c 1.35 -> 1.36 # arch/ia64/kernel/mca.c 1.59 -> 1.60 # sound/core/seq/seq_fifo.c 1.5 -> 1.6 # sound/isa/sb/sb16_main.c 1.11 -> 1.14 # include/asm-parisc/namei.h 1.1 -> 1.2 # arch/m68k/mac/oss.c 1.5 -> 1.6 # include/asm-m68k/unistd.h 1.10 -> 1.11 # arch/ia64/kernel/process.c 1.51 -> 1.52 # fs/readdir.c 1.24 -> 1.25 # arch/i386/kernel/setup.c 1.108 -> 1.110 # drivers/md/dm-stripe.c 1.9 -> 1.12 # drivers/char/watchdog/sc520_wdt.c 1.16 -> 1.17 # drivers/macintosh/therm_pm72.h 1.1 -> 1.2 # arch/m68k/kernel/ints.c 1.7 -> 1.8 # drivers/atm/idt77252.c 1.22 -> 1.23 # include/sound/pcm.h 1.18 -> 1.21 # fs/nfs/dir.c 1.68 -> 1.71 # drivers/acpi/dispatcher/dsmethod.c 1.19 -> 1.20 # arch/ia64/hp/sim/simserial.c 1.22 -> 1.23 # fs/nfs/nfs3proc.c 1.33 -> 1.35 # drivers/net/tokenring/smctr.c 1.28 -> 1.30 # include/asm-h8300/unistd.h 1.3 -> 1.4 # drivers/media/video/video-buf.c 1.15 -> 1.16 # drivers/message/fusion/isense.c 1.8 -> 1.9 # arch/x86_64/ia32/vsyscall.S 1.2 -> (deleted) # drivers/scsi/scsi_lib.c 1.120 -> 1.123 # drivers/message/fusion/mptlan.c 1.13 -> 1.16 # drivers/message/fusion/mptctl.h 1.7 -> 1.8 # drivers/message/fusion/lsi/mpi_raid.h 1.5 -> 1.6 # sound/pci/ice1712/amp.c 1.3 -> 1.4 # drivers/net/appletalk/cops.c 1.19 -> 1.20 # arch/m68k/q40/config.c 1.16 -> 1.17 # fs/coda/inode.c 1.34 -> 1.36 # net/sunrpc/pmap_clnt.c 1.8 -> 1.9 # fs/ncpfs/inode.c 1.48 -> 1.49 # arch/i386/boot/tools/build.c 1.3 -> 1.4 # net/core/dev.c 1.129.1.5 -> 1.133 # arch/ia64/sn/io/sn2/shub_intr.c 1.9 -> 1.10 # arch/ppc/platforms/pmac_smp.c 1.17 -> 1.18 # sound/pcmcia/Kconfig 1.2 -> 1.6 # drivers/message/fusion/lsi/mpi_lan.h 1.4 -> 1.5 # drivers/scsi/scsi.c 1.136.1.1 -> 1.139 # include/asm-m68knommu/unistd.h 1.3 -> 1.4 # drivers/usb/core/usb.c 1.152 -> 1.153 # arch/i386/mach-es7000/Makefile 1.1 -> 1.2 # fs/ufs/util.h 1.8 -> 1.9 # drivers/ieee1394/dma.c 1.7 -> 1.8 # drivers/acpi/namespace/nsalloc.c 1.19 -> 1.20 # drivers/net/mac89x0.c 1.14 -> 1.15 # drivers/char/watchdog/wdt.c 1.26 -> 1.28 # Documentation/sound/alsa/Joystick.txt 1.2 -> 1.3 # sound/pci/emu10k1/emufx.c 1.37 -> 1.39 # drivers/acpi/power.c 1.19 -> 1.20 # drivers/scsi/pcmcia/qlogic_stub.c 1.20 -> 1.26 # include/asm-parisc/floppy.h 1.1 -> 1.2 # drivers/net/pcmcia/ibmtr_cs.c 1.23 -> 1.24 # Documentation/DMA-mapping.txt 1.17 -> 1.18 # fs/ext3/dir.c 1.16 -> 1.17 # include/sound/ac97_codec.h 1.30 -> 1.31 # drivers/atm/fore200e.h 1.1 -> 1.2 # drivers/net/sunbmac.c 1.21 -> 1.22 # drivers/message/fusion/lsi/mpi_cnfg.h 1.5 -> 1.6 # include/asm-ia64/machvec.h 1.18 -> 1.19 # fs/ext2/dir.c 1.22 -> 1.23 # net/sunrpc/sched.c 1.30 -> 1.31 # drivers/net/mac8390.c 1.16 -> 1.17 # fs/lockd/host.c 1.6 -> 1.7 # drivers/md/raid0.c 1.43 -> 1.44 # include/acpi/acmacros.h 1.24 -> 1.25 # fs/cifs/cifsfs.c 1.35 -> 1.36 # drivers/char/watchdog/w83627hf_wdt.c 1.3 -> 1.4 # drivers/scsi/sym53c8xx_comm.h 1.15 -> 1.16 # drivers/md/dm-linear.c 1.7 -> 1.9 # drivers/net/tg3.c 1.120.1.16 -> 1.126 # arch/i386/mm/discontig.c 1.15 -> 1.16 # fs/reiserfs/dir.c 1.20 -> 1.21 # arch/x86_64/kernel/process.c 1.25 -> 1.27 # include/linux/mmzone.h 1.52 -> 1.54 # arch/i386/boot/setup.S 1.26 -> 1.27 # sound/pci/bt87x.c 1.1 -> 1.3 # include/linux/ufs_fs_i.h 1.3 -> 1.4 # drivers/net/3c527.c 1.21 -> 1.22 # sound/oss/wavfront.c 1.15 -> 1.17 # arch/m68k/mac/psc.c 1.5 -> 1.6 # drivers/net/a2065.c 1.17 -> 1.18 # drivers/net/amd8111e.c 1.12.1.1 -> 1.15 # fs/Kconfig 1.44 -> 1.46 # drivers/net/tokenring/tms380tr.c 1.19 -> 1.20 # include/linux/sunrpc/timer.h 1.6 -> 1.7 # drivers/net/hamradio/baycom_ser_fdx.c 1.13 -> 1.14 # drivers/block/loop.c 1.122 -> 1.124 # arch/parisc/configs/c3000_defconfig 1.1 -> 1.2 # sound/parisc/Kconfig 1.1 -> 1.2 # include/sound/trident.h 1.10 -> 1.11 # include/acpi/actypes.h 1.32 -> 1.33 # drivers/scsi/aacraid/sa.c 1.7 -> 1.8 # include/asm-x86_64/vsyscall32.h 1.2 -> 1.3 # net/sunrpc/auth_unix.c 1.12 -> 1.13 # drivers/net/arm/ether1.c 1.18 -> 1.19 # sound/pci/azt3328.c 1.9 -> 1.11 # drivers/acpi/events/evgpe.c 1.18 -> 1.19 # drivers/net/declance.c 1.19 -> 1.20 # fs/udf/file.c 1.16 -> 1.17 # sound/pci/ice1712/hoontech.c 1.2 -> 1.3 # drivers/net/tulip/tulip_core.c 1.52 -> 1.54 # sound/pci/maestro3.c 1.30 -> 1.32 # drivers/net/atari_bionet.c 1.13 -> 1.14 # include/sound/asequencer.h 1.7 -> 1.8 # MAINTAINERS 1.196.1.1 -> 1.199 # drivers/scsi/sata_svw.c 1.8 -> 1.10 # fs/jffs/inode-v23.c 1.59 -> 1.60 # drivers/net/zorro8390.c 1.9.1.1 -> 1.11 # drivers/net/sundance.c 1.53 -> 1.54 # sound/pci/intel8x0.c 1.61 -> 1.71 # sound/isa/es1688/es1688_lib.c 1.10 -> 1.13 # drivers/scsi/sym53c8xx_2/sym_nvram.c 1.3 -> 1.4 # sound/pci/ice1712/revo.c 1.4 -> 1.5 # fs/udf/misc.c 1.6 -> 1.7 # arch/x86_64/lib/iodebug.c 1.1 -> (deleted) # include/net/irda/vlsi_ir.h 1.12 -> 1.13 # mm/mempool.c 1.17 -> 1.18 # mm/mmap.c 1.102 -> 1.103 # sound/usb/usbaudio.h 1.19 -> 1.20 # sound/pci/ac97/Makefile 1.14 -> 1.15 # drivers/video/i810/i810_main.h 1.11 -> 1.12 # drivers/char/watchdog/w83877f_wdt.c 1.22 -> 1.23 # include/asm-mips/dma-mapping.h 1.4 -> 1.5 # arch/cris/kernel/process.c 1.14 -> 1.15 # drivers/message/fusion/lsi/mpi_type.h 1.3 -> 1.4 # drivers/message/i2o/i2o_core.c 1.23 -> 1.24 # fs/read_write.c 1.35 -> 1.36 # arch/sparc64/kernel/sys_sparc32.c 1.90 -> 1.91 # arch/x86_64/ia32/syscall32.c 1.5 -> 1.6 # drivers/net/typhoon.c 1.13 -> 1.14 # include/linux/compiler.h 1.23 -> 1.24 # sound/pci/trident/trident_main.c 1.28 -> 1.31 # sound/isa/ad1816a/ad1816a_lib.c 1.10 -> 1.13 # drivers/scsi/st.c 1.79 -> 1.80 # fs/qnx4/dir.c 1.7 -> 1.8 # include/asm-i386/unistd.h 1.33 -> 1.34 # drivers/net/ariadne.c 1.14 -> 1.15 # init/do_mounts.h 1.11 -> 1.12 # fs/udf/super.c 1.38 -> 1.39 # drivers/net/eepro100.c 1.68 -> 1.72 # include/asm-sh/pci.h 1.16 -> 1.17 # fs/nfs/file.c 1.33 -> 1.35 # include/sound/asound.h 1.21 -> 1.22 # include/asm-x86_64/calling.h 1.7 -> 1.8 # include/acpi/amlcode.h 1.18 -> 1.19 # drivers/net/wan/comx-hw-locomx.c 1.9 -> 1.10 # drivers/net/ac3200.c 1.16 -> 1.17 # drivers/message/fusion/Makefile 1.12 -> 1.13 # Makefile 1.463 -> 1.464 # drivers/parisc/superio.c 1.9 -> 1.10 # sound/pci/cmipci.c 1.36 -> 1.39 # drivers/base/map.c 1.2 -> 1.3 # arch/ia64/kernel/head.S 1.17 -> 1.18 # include/asm-x86_64/acpi.h 1.6 -> 1.7 # fs/lockd/svcproc.c 1.11 -> 1.13 # drivers/net/pcmcia/fmvj18x_cs.c 1.30 -> 1.31 # fs/udf/osta_udf.h 1.5 -> 1.6 # arch/i386/defconfig 1.106 -> 1.108 # drivers/net/stnic.c 1.9 -> 1.10 # net/sunrpc/xprt.c 1.76 -> 1.80 # drivers/net/pcmcia/smc91c92_cs.c 1.28 -> 1.29 # include/asm-m68k/irq.h 1.7 -> 1.8 # arch/x86_64/defconfig 1.33 -> 1.34 # arch/ppc64/mm/numa.c 1.20 -> 1.21 # sound/core/pcm_memory.c 1.13 -> 1.15 # fs/affs/super.c 1.41 -> 1.42 # sound/core/sgbuf.c 1.6 -> 1.9 # sound/pci/trident/trident_memory.c 1.6 -> 1.8 # drivers/scsi/scsi_priv.h 1.31 -> 1.32 # sound/pci/es1938.c 1.26 -> 1.28 # include/linux/device-mapper.h 1.4 -> 1.6 # drivers/net/tulip/pnic.c 1.9 -> 1.10 # drivers/video/console/fbcon.c 1.111 -> 1.112 # drivers/char/watchdog/sbc60xxwdt.c 1.35 -> 1.36 # sound/core/Makefile 1.32 -> 1.40 # include/linux/topology.h 1.3 -> 1.4 # include/asm-mips/pci.h 1.16 -> 1.17 # include/asm-x86_64/thread_info.h 1.14 -> 1.15 # include/linux/page-flags.h 1.43 -> 1.45 # net/sunrpc/xdr.c 1.17 -> 1.18 # drivers/parisc/lba_pci.c 1.9 -> 1.10 # drivers/net/fealnx.c 1.33 -> 1.34 # sound/pci/es1968.c 1.33 -> 1.35 # arch/ia64/sn/io/hwgfs/ramfs.c 1.4 -> 1.5 # drivers/net/8390.h 1.13 -> 1.14 # drivers/net/3c503.c 1.17 -> 1.18 # include/sound/pcm_oss.h 1.6 -> 1.7 # drivers/scsi/sata_promise.c 1.23 -> 1.25 # drivers/pci/probe.c 1.60 -> 1.61 # CREDITS 1.107 -> 1.108 # init/do_mounts_rd.c 1.9 -> 1.10 # sound/pci/sonicvibes.c 1.25 -> 1.27 # drivers/net/82596.c 1.17 -> 1.18 # drivers/scsi/constants.c 1.14 -> 1.15 # sound/core/Kconfig 1.2 -> 1.3 # arch/mips/mm/dma-ip27.c 1.1 -> 1.2 # fs/lockd/mon.c 1.9 -> 1.10 # drivers/net/7990.c 1.9 -> 1.10 # Documentation/filesystems/ufs.txt 1.1 -> 1.2 # kernel/module.c 1.104 -> 1.105 # include/linux/security.h 1.30 -> 1.31 # include/asm-parisc/pci.h 1.12 -> 1.13 # sound/usb/Kconfig 1.2 -> 1.4 # sound/drivers/Kconfig 1.1 -> 1.6 # drivers/ieee1394/dv1394.c 1.40 -> 1.41 # sound/usb/usbaudio.c 1.61 -> 1.69 # include/asm-ia64/dma-mapping.h 1.2 -> 1.3 # arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c 1.17 -> 1.18 # include/asm-ppc/pci.h 1.24 -> 1.25 # include/linux/sunrpc/xprt.h 1.28 -> 1.31 # fs/nfs/nfsroot.c 1.13 -> 1.14 # arch/ia64/lib/swiotlb.c 1.16 -> 1.17 # include/asm-sparc/pci.h 1.13 -> 1.14 # drivers/net/eepro.c 1.21 -> 1.23 # arch/x86_64/kernel/Makefile 1.32 -> 1.33 # init/do_mounts_devfs.c 1.5 -> 1.6 # fs/nfs/write.c 1.46 -> 1.49 # sound/sparc/Kconfig 1.1 -> 1.2 # drivers/char/watchdog/alim7101_wdt.c 1.12 -> 1.13 # arch/i386/kernel/cpu/mcheck/mce.c 1.4 -> 1.5 # include/asm-i386/pgtable.h 1.39 -> 1.40 # include/acpi/acconfig.h 1.50 -> 1.51 # fs/nfs/nfs4proc.c 1.43 -> 1.46 # drivers/net/oaknet.c 1.6 -> 1.7 # include/sound/info.h 1.11 -> 1.12 # drivers/scsi/sd.c 1.141 -> 1.142 # drivers/net/seeq8005.c 1.15 -> 1.16 # drivers/parisc/sba_iommu.c 1.12 -> 1.14 # drivers/macintosh/therm_pm72.c 1.1 -> 1.2 # fs/minix/dir.c 1.14 -> 1.15 # arch/m68k/hp300/time.c 1.6 -> 1.7 # drivers/net/smc9194.c 1.20 -> 1.21 # arch/i386/kernel/bootflag.c 1.3 -> 1.4 # drivers/net/gt96100eth.c 1.13 -> 1.14 # drivers/net/arm/am79c961a.c 1.15 -> 1.16 # drivers/net/3c507.c 1.15 -> 1.16 # drivers/media/dvb/frontends/sp887x.c 1.8 -> 1.9 # sound/core/pcm_misc.c 1.9 -> 1.10 # drivers/net/tokenring/olympic.c 1.28 -> 1.29 # arch/x86_64/kernel/vsyscall.c 1.13 -> 1.14 # mm/slab.c 1.120 -> 1.121 # include/linux/module.h 1.72 -> 1.74 # drivers/md/dm.c 1.38 -> 1.39 # fs/nfs/inode.c 1.96 -> 1.105 # drivers/net/tulip/xircom_cb.c 1.19 -> 1.20 # fs/ext2/acl.c 1.10 -> 1.11 # arch/x86_64/Kconfig 1.44 -> 1.45 # sound/pci/fm801.c 1.24 -> 1.27 # drivers/scsi/scsi_scan.c 1.115 -> 1.117 # kernel/sched.c 1.247 -> 1.248 # drivers/scsi/aacraid/rkt.c 1.2 -> 1.3 # drivers/acpi/executer/exmutex.c 1.13 -> 1.14 # drivers/net/es3210.c 1.11 -> 1.12 # arch/i386/mach-pc9800/Makefile 1.1 -> 1.2 # include/linux/ufs_fs.h 1.8 -> 1.9 # drivers/char/watchdog/wdt977.c 1.22 -> 1.23 # arch/x86_64/lib/csum-copy.S 1.5 -> 1.6 # drivers/scsi/Makefile 1.54 -> 1.57 # drivers/net/tulip/de2104x.c 1.26 -> 1.27 # drivers/block/Makefile 1.23 -> 1.24 # drivers/acpi/osl.c 1.45 -> 1.46 # drivers/net/cs89x0.c 1.21 -> 1.22 # include/linux/lockd/debug.h 1.2 -> 1.3 # drivers/scsi/st.h 1.16 -> 1.17 # sound/pci/ens1370.c 1.43 -> 1.45 # fs/ufs/dir.c 1.14 -> 1.15 # arch/h8300/kernel/sys_h8300.c 1.4 -> 1.5 # arch/x86_64/mm/numa.c 1.7 -> 1.8 # fs/udf/udf_sb.h 1.7 -> 1.8 # arch/sparc64/kernel/sparc64_ksyms.c 1.63 -> 1.64 # include/asm-x86_64/system.h 1.19 -> 1.20 # include/linux/nfs_xdr.h 1.45 -> 1.46 # kernel/timer.c 1.76 -> 1.77 # sound/pci/via82xx.c 1.74 -> 1.83 # drivers/net/eth16i.c 1.16 -> 1.17 # drivers/video/dnfb.c 1.23 -> 1.24 # arch/m68k/mac/macints.c 1.12 -> 1.13 # sound/core/seq/seq_midi.c 1.12 -> 1.15 # arch/i386/mach-visws/Makefile 1.6 -> 1.7 # drivers/ieee1394/dma.h 1.4 -> 1.5 # drivers/ieee1394/ohci1394.c 1.59 -> 1.60 # drivers/net/smc-ultra32.c 1.10 -> 1.11 # include/linux/dma-mapping.h 1.1 -> 1.2 # fs/freevxfs/vxfs_super.c 1.19 -> 1.20 # drivers/net/Kconfig 1.56.1.11 -> 1.61 # drivers/net/sun3lance.c 1.19 -> 1.20 # arch/sparc/kernel/sun4m_smp.c 1.11 -> 1.12 # Documentation/filesystems/udf.txt 1.3 -> 1.4 # sound/core/oss/pcm_oss.c 1.42 -> 1.45 # fs/udf/namei.c 1.27 -> 1.28 # drivers/scsi/eata.c 1.35 -> 1.36 # sound/drivers/opl4/Makefile 1.1 -> 1.3 # sound/isa/Kconfig 1.5 -> 1.9 # arch/i386/kernel/acpi/boot.c 1.50 -> 1.51 # net/sunrpc/sunrpc_syms.c 1.28 -> 1.29 # arch/parisc/kernel/sys_parisc.c 1.15 -> 1.16 # sound/pci/ymfpci/ymfpci_main.c 1.29 -> 1.31 # drivers/scsi/sym53c8xx_2/sym_misc.c 1.3 -> 1.4 # drivers/net/arm/etherh.c 1.20 -> 1.21 # arch/ppc64/kernel/misc.S 1.71 -> 1.72 # drivers/parport/parport_gsc.c 1.13 -> 1.14 # arch/m68k/q40/q40ints.c 1.18 -> 1.19 # arch/x86_64/Makefile 1.37 -> 1.38 # include/asm-x86_64/proto.h 1.19 -> 1.20 # drivers/video/fbmon.c 1.11 -> 1.12 # arch/parisc/kernel/drivers.c 1.10 -> 1.11 # include/asm-i386/acpi.h 1.13 -> 1.15 # fs/nfs/direct.c 1.4 -> 1.5 # sound/usb/usbmidi.c 1.24 -> 1.27 # sound/pci/emu10k1/memory.c 1.9 -> 1.11 # drivers/net/tulip/dmfe.c 1.36 -> 1.37 # fs/bfs/dir.c 1.21 -> 1.22 # fs/proc/inode.c 1.26 -> 1.27 # drivers/scsi/Kconfig 1.56 -> 1.60 # sound/drivers/vx/vx_core.c 1.4 -> 1.6 # include/asm-generic/dma-mapping.h 1.4 -> 1.5 # sound/arm/Kconfig 1.1 -> 1.2 # arch/i386/lib/iodebug.c 1.2 -> (deleted) # include/linux/device.h 1.115 -> 1.116 # arch/m68knommu/kernel/sys_m68k.c 1.2 -> 1.3 # arch/ppc/kernel/ppc_ksyms.c 1.52 -> 1.53 # drivers/net/e2100.c 1.15 -> 1.16 # drivers/net/lne390.c 1.11 -> 1.12 # sound/pci/ice1712/prodigy.c 1.3 -> 1.4 # drivers/char/watchdog/ib700wdt.c 1.26 -> 1.27 # arch/ppc/kernel/misc.S 1.52 -> 1.53 # arch/ppc/platforms/pmac_feature.c 1.22 -> 1.23 # fs/nfs/pagelist.c 1.15 -> 1.16 # drivers/net/sb1250-mac.c 1.9 -> 1.10 # include/asm-ia64/pci.h 1.24 -> 1.25 # include/asm-x86_64/msr.h 1.7 -> 1.8 # arch/parisc/kernel/pci-dma.c 1.7 -> 1.9 # drivers/net/sgiseeq.c 1.17 -> 1.18 # fs/udf/unicode.c 1.4 -> 1.5 # drivers/char/genrtc.c 1.11 -> 1.12 # sound/pci/ac97/ac97_patch.c 1.32 -> 1.37 # fs/nfs/proc.c 1.28 -> 1.31 # init/do_mounts_md.c 1.4 -> 1.6 # arch/m68k/mac/iop.c 1.10 -> 1.11 # kernel/kthread.c 1.1 -> 1.2 # sound/pci/als4000.c 1.20 -> 1.23 # sound/pci/ali5451/ali5451.c 1.33 -> 1.35 # drivers/char/applicom.c 1.10 -> 1.11 # drivers/net/tulip/eeprom.c 1.9 -> 1.10 # drivers/char/watchdog/wafer5823wdt.c 1.14 -> 1.15 # drivers/acpi/executer/excreate.c 1.19 -> 1.20 # net/core/Makefile 1.18 -> 1.19 # include/linux/netdevice.h 1.70.1.1 -> 1.73 # security/selinux/hooks.c 1.25 -> 1.26 # drivers/net/tokenring/madgemc.c 1.19 -> 1.20 # arch/ppc/kernel/smp.c 1.41 -> 1.42 # fs/nfs/unlink.c 1.8 -> 1.9 # drivers/scsi/BusLogic.c 1.29 -> 1.30 # arch/ia64/Kconfig 1.62 -> 1.63 # drivers/net/hamradio/baycom_par.c 1.11 -> 1.12 # drivers/net/pcmcia/3c589_cs.c 1.26 -> 1.27 # include/asm-ppc64/mmzone.h 1.15 -> 1.16 # sound/pci/cs4281.c 1.32 -> 1.34 # include/asm-ia64/sal.h 1.21 -> 1.23 # mm/truncate.c 1.11 -> 1.12 # sound/usb/usbmixer_maps.c 1.4 -> 1.5 # include/linux/kernel_stat.h 1.13 -> 1.14 # include/linux/compat_ioctl.h 1.16 -> 1.17 # drivers/net/tokenring/proteon.c 1.8 -> 1.9 # arch/ia64/kernel/sal.c 1.7 -> 1.9 # drivers/net/sungem.c 1.52 -> 1.53 # drivers/acpi/namespace/nsaccess.c 1.24 -> 1.25 # drivers/parisc/gsc.c 1.3 -> 1.4 # drivers/acpi/sleep/poweroff.c 1.1 -> 1.2 # sound/isa/ad1848/ad1848_lib.c 1.18 -> 1.21 # drivers/net/isa-skeleton.c 1.11 -> 1.12 # drivers/scsi/dc395x.h 1.3 -> 1.4 # sound/pci/emu10k1/emu10k1_main.c 1.19 -> 1.21 # arch/x86_64/ia32/ia32_signal.c 1.18 -> 1.19 # drivers/net/via-rhine.c 1.49 -> 1.51 # include/asm-x86_64/processor.h 1.29 -> 1.30 # sound/core/memalloc.c 1.16 -> 1.24 # drivers/net/arm/ether3.c 1.20 -> 1.21 # drivers/md/dm-table.c 1.32 -> 1.34 # drivers/scsi/sym53c8xx_2/sym_fw.c 1.4 -> 1.5 # drivers/net/tokenring/3c359.c 1.18 -> 1.19 # drivers/net/plip.c 1.19 -> 1.20 # arch/parisc/kernel/smp.c 1.9 -> 1.10 # drivers/md/dm-target.c 1.10 -> 1.13 # kernel/workqueue.c 1.15 -> 1.16 # include/scsi/scsi.h 1.17 -> 1.20 # arch/sparc/kernel/ioport.c 1.13 -> 1.14 # fs/inode.c 1.109 -> 1.110 # arch/parisc/configs/712_defconfig 1.1 -> 1.2 # arch/parisc/kernel/process.c 1.14 -> 1.16 # sound/pci/rme32.c 1.22 -> 1.24 # drivers/net/e100.c 1.8 -> 1.10 # arch/i386/kernel/i386_ksyms.c 1.57 -> 1.58 # include/asm-i386/io.h 1.25 -> 1.26 # drivers/atm/fore200e.c 1.23 -> 1.24 # drivers/net/atp.c 1.16 -> 1.17 # fs/proc/kmsg.c 1.5 -> 1.6 # fs/nfs/nfs4xdr.c 1.39 -> 1.41 # arch/ia64/sn/io/sn2/pciio.c 1.15 -> 1.16 # drivers/block/scsi_ioctl.c 1.40 -> 1.41 # drivers/net/ne2.c 1.13 -> 1.14 # drivers/net/hamradio/baycom_epp.c 1.21 -> 1.22 # drivers/net/apne.c 1.13 -> 1.14 # fs/proc/generic.c 1.25 -> 1.26 # drivers/scsi/sym53c8xx_2/sym_glue.h 1.16 -> 1.17 # drivers/scsi/sym53c8xx_2/sym53c8xx.h 1.11 -> 1.12 # drivers/char/sn_serial.c 1.5 -> 1.8 # drivers/net/hamachi.c 1.31 -> 1.32 # arch/parisc/kernel/parisc_ksyms.c 1.16 -> 1.17 # include/linux/sunrpc/xdr.h 1.13 -> 1.14 # drivers/message/fusion/mptscsih.h 1.20 -> 1.21 # drivers/scsi/sym53c8xx_2/sym_misc.h 1.2 -> 1.3 # sound/drivers/mpu401/Makefile 1.15 -> 1.16 # arch/sparc64/kernel/sbus.c 1.14 -> 1.15 # include/linux/loop.h 1.20 -> 1.21 # sound/core/pcm.c 1.22 -> 1.24 # drivers/scsi/qlogicfas.c 1.24 -> 1.34 # arch/m68k/sun3/sun3ints.c 1.8 -> 1.9 # include/asm-i386/dma-mapping.h 1.2 -> 1.3 # arch/x86_64/kernel/smpboot.c 1.23 -> 1.24 # fs/nfs/nfs3xdr.c 1.27 -> 1.29 # fs/ufs/namei.c 1.23 -> 1.24 # arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c 1.29 -> 1.30 # drivers/net/wireless/orinoco.c 1.26 -> 1.27 # sound/ppc/pmac.c 1.17 -> 1.18 # arch/m68k/amiga/amiints.c 1.8 -> 1.9 # drivers/message/fusion/Kconfig 1.3.1.1 -> 1.5 # include/asm-s390/unistd.h 1.20 -> 1.21 # drivers/scsi/aacraid/rx.c 1.7 -> 1.8 # fs/block_dev.c 1.153 -> 1.155 # drivers/net/sis190.c 1.18 -> 1.19 # Documentation/kernel-parameters.txt 1.41 -> 1.42 # fs/udf/inode.c 1.35 -> 1.36 # arch/parisc/kernel/module.c 1.8 -> 1.9 # drivers/net/wireless/Makefile 1.15 -> 1.16 # include/asm-m68k/bitops.h 1.10 -> 1.11 # drivers/scsi/sym53c8xx_2/sym_glue.c 1.40 -> 1.42 # drivers/net/sk_g16.c 1.15 -> 1.16 # drivers/message/fusion/mptscsih.c 1.34 -> 1.37 # include/linux/sunrpc/debug.h 1.4 -> 1.6 # (new) -> 1.3 sound/pcmcia/pdaudiocf/pdaudiocf.h # (new) -> 1.3 drivers/net/wireless/prism54/islpci_dev.c # (new) -> 1.1 sound/pci/au88x0/au88x0_a3d.h # (new) -> 1.1 sound/pci/mixart/Makefile # (new) -> 1.3 sound/pci/mixart/mixart.h # (new) -> 1.2 drivers/net/wireless/prism54/islpci_eth.c # (new) -> 1.1 drivers/scsi/scsi_transport_fc.c # (new) -> 1.1 sound/pci/au88x0/au88x0_game.c # (new) -> 1.1 sound/pci/au88x0/au8820.h # (new) -> 1.1 Documentation/networking/netconsole.txt # (new) -> 1.1 arch/x86_64/ia32/vsyscall-sigreturn.S # (new) -> 1.1 include/linux/netpoll.h # (new) -> 1.1 drivers/message/fusion/lsi/mpi_inb.h # (new) -> 1.2 drivers/net/wireless/prism54/islpci_mgt.h # (new) -> 1.1 arch/x86_64/pci/mmconfig.c # (new) -> 1.3 drivers/scsi/qlogicfas.h # (new) -> 1.1 sound/pci/au88x0/au8810.c # (new) -> 1.1 arch/parisc/configs/b180_defconfig # (new) -> 1.5 include/scsi/scsi_transport_spi.h # (new) -> 1.1 sound/pci/au88x0/au8830.c # (new) -> 1.1 sound/pci/au88x0/au88x0_mixer.c # (new) -> 1.1 sound/pci/au88x0/au88x0_sb.h # (new) -> 1.1 sound/pcmcia/pdaudiocf/pdaudiocf_core.c # (new) -> 1.3 sound/pcmcia/pdaudiocf/pdaudiocf.c # (new) -> 1.3 drivers/net/wireless/prism54/isl_ioctl.c # (new) -> 1.1 sound/pci/mixart/mixart_mixer.h # (new) -> 1.1 include/scsi/scsi_transport_fc.h # (new) -> 1.1 drivers/parisc/iommu-helpers.h # (new) -> 1.1 sound/pci/au88x0/au88x0_xtalk.h # (new) -> 1.2 drivers/net/wireless/prism54/islpci_dev.h # (new) -> 1.1 sound/pcmcia/pdaudiocf/Makefile # (new) -> 1.1 drivers/message/fusion/lsi/mpi_tool.h # (new) -> 1.1 sound/pci/au88x0/au8830.h # (new) -> 1.2 sound/pci/mixart/mixart_mixer.c # (new) -> 1.2 drivers/net/wireless/prism54/Makefile # (new) -> 1.4 drivers/net/netconsole.c # (new) -> 1.2 drivers/net/wireless/prism54/islpci_hotplug.c # (new) -> 1.5 drivers/scsi/scsi_transport_spi.c # (new) -> 1.1 drivers/net/wireless/prism54/isl_38xx.c # (new) -> 1.1 sound/pci/au88x0/au88x0_pcm.c # (new) -> 1.2 sound/pci/au88x0/au88x0.c # (new) -> 1.1 sound/pci/au88x0/au88x0_a3d.c # (new) -> 1.1 sound/pci/au88x0/au88x0_eqdata.c # (new) -> 1.2 drivers/net/wireless/prism54/isl_ioctl.h # (new) -> 1.1 sound/pci/au88x0/au88x0_wt.h # (new) -> 1.1 sound/pci/intel8x0m.c # (new) -> 1.2 drivers/scsi/sata_vsc.c # (new) -> 1.1 sound/pci/atiixp.c # (new) -> 1.1 sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c # (new) -> 1.2 sound/i2c/other/ak4117.c # (new) -> 1.1 sound/pci/au88x0/au88x0.h # (new) -> 1.1 sound/pci/au88x0/Makefile # (new) -> 1.1 drivers/net/wireless/prism54/isl_oid.h # (new) -> 1.1 sound/pci/mixart/mixart_core.h # (new) -> 1.1 arch/ia64/configs/zx1_defconfig # (new) -> 1.2 sound/pcmcia/pdaudiocf/pdaudiocf_irq.c # (new) -> 1.1 Documentation/sound/alsa/MIXART.txt # (new) -> 1.1 sound/pci/au88x0/au8810.h # (new) -> 1.3 drivers/net/wireless/prism54/islpci_mgt.c # (new) -> 1.1 sound/pci/au88x0/au88x0_synth.c # (new) -> 1.6 sound/pci/mixart/mixart.c # (new) -> 1.1 include/sound/ak4117.h # (new) -> 1.1 sound/pci/au88x0/au88x0_mpu401.c # (new) -> 1.1 sound/pci/au88x0/au88x0_eq.h # (new) -> 1.1 sound/pci/au88x0/au8820.c # (new) -> 1.1 sound/pci/au88x0/au88x0_xtalk.c # (new) -> 1.2 drivers/block/carmel.c # (new) -> 1.1 sound/pci/au88x0/au88x0_a3ddata.c # (new) -> 1.1 include/scsi/scsi_transport.h # (new) -> 1.1 arch/x86_64/ia32/vsyscall-sysenter.S # (new) -> 1.1 drivers/scsi/sym53c8xx_2/sym_nvram.h # (new) -> 1.1 sound/pci/au88x0/au88x0_eq.c # (new) -> 1.1 drivers/net/wireless/prism54/islpci_eth.h # (new) -> 1.1 sound/pci/au88x0/au88x0_core.c # (new) -> 1.1 drivers/net/wireless/prism54/oid_mgt.c # (new) -> 1.1 sound/pci/mixart/mixart_hwdep.h # (new) -> 1.1 drivers/net/wireless/prism54/oid_mgt.h # (new) -> 1.7 net/core/netpoll.c # (new) -> 1.6 sound/pci/mixart/mixart_core.c # (new) -> 1.1 drivers/message/fusion/lsi/mpi_sas.h # (new) -> 1.1 arch/x86_64/ia32/vsyscall-syscall.S # (new) -> 1.5 sound/pci/mixart/mixart_hwdep.c # (new) -> 1.1 drivers/net/wireless/prism54/isl_38xx.h # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 04/03/10 torvalds@ppc970.osdl.org 1.1608.83.7 # Linux 2.6.4 # -------------------------------------------- # 04/03/10 jgarzik@redhat.com 1.1611 # Merge redhat.com:/spare/repo/linux-2.5 # into redhat.com:/spare/repo/netdev-2.6/netpoll # -------------------------------------------- # 04/03/10 benh@kernel.crashing.org 1.1608.83.8 # [PATCH] G5 temperature control update # # This makes the temperature control code more robust, putting less # pressure on i2c, and work around occasional misconfiguration of the ADC # chips leading to incorrect temperature readings. # -------------------------------------------- # 04/03/10 len.brown@intel.com 1.1608.1.39 # Merge intel.com:/home/lenb/bk/linux-2.6.4 # into intel.com:/home/lenb/src/linux-acpi-test-2.6.4 # -------------------------------------------- # 04/03/10 jgarzik@redhat.com 1.1608.55.32 # Merge redhat.com:/spare/repo/linux-2.5 # into redhat.com:/spare/repo/libata-2.5 # -------------------------------------------- # 04/03/10 jejb@mulgrave.(none) 1.1608.85.1 # Merge qboosh/emoore conflict # -------------------------------------------- # 04/03/10 len.brown@intel.com 1.1557.76.8 # Delete (void)func() casts considered cruft in Linux style. # # GCC's inability to warn when return values are ignored has conditioned # Linux programmers into thinking that this is actually normal. # # delete some #define's -- suggested by Matt Wilcox # -------------------------------------------- # 04/03/10 len.brown@intel.com 1.1557.76.9 # [ACPI] fix printk and build warning from previous csets # -------------------------------------------- # 04/03/10 len.brown@intel.com 1.1608.1.40 # merge 2.6.3 into 2.6.4 # -------------------------------------------- # 04/03/10 ak@suse.de 1.1608.83.9 # [PATCH] x86-64 merge for 2.6.4 # # The biggest new feature is fixed 32bit vsyscall (SYSCALL+SYSENTER) # support, mostly from Jakub Jelinek. This increases 32bit syscall # performance greatly (latency halved and better). The SYSENTER for Intel # support required some infrastructure changes, but seems to work now too. # # The 64bit vsyscall vtime() just references xtime.tv_sec now. This # should make it a lot faster too. # # A fix for some Intel IA32e systems. Also a few long standing bugs in # NMI like exception handlers were fixed. # # And a lot of other bug fixes. # # Full changeLog: # - Clean up 32bit address room limit handling, fix 3gb personality # - Move memcpy_{from,to}io export to ksyms.c file. This seems to work # around a toolchain bug (Andreas Gruenbacher) # - Update defconfig # - ACPI merges from i386 (SBF should work now, acpi=strict) # - Implement mmconfig support based on i386 code (untested) # - Fix i386/x86-64 pci source file sharing # - Implement ptrace access for 32bit vsyscall page # - Always initialize all 32bit SYSENTER/SYSCALL MSRs. # - Export run time cache line size to generic kernel # - Remove explicit CPUID in ia32 syscall code # - Fill in most of boot_cpu_data early # - Remove unused PER_LINUX32 setup # - Fix syscall trace in fast 32bit calls (Suresh B. Siddha) # - Tighten first line of the oops again. # - Set up ptrace registers correctly for debug,ss,double fault exceptions # - Fix 64bit bug in sys_time64 # - Optimize time syscall/vsyscall to only read xtime # - Fix csum_partial_copy_nocheck # - Remove last traces of FPU emulation # - Check properly for rescheduling in exceptions with own stack # - Harden exception stack entries (#SS,#NMI,#MC,#DF,#DB) against bogus GS # - Use an exception stack for machine checks # - Handle TIF_SINGLESTEP properly in kernel exit # - Add exception stack for debug handler # - Disable X86_HT for Opteron optimized builds because it pulls in ACPI_BOOT # - Fix CONFIG_ACPI_BOOT compilation without CONFIG_ACPI # - Fix eflags handling in SYSENTER path (Jakub Jelinek) # - Use atomic counter for enable/disable_hlt # - Support 32bit SYSENTER vsyscall too (Jakub Jelinek) # - Don't redefine Dprintk # - Change some cpu/apic id arrays to char # - Support arbitary cpu<->apicid in hard_smp_processor_id (Surresh B Sidda) # - Move K8 erratum #100 workaround into slow path of page fault handler. # - Fix 32bit cdrom direct access ioctls (Jens Axboe) # - Enable 32bit vsyscalls by default # - Fix 32bit vsyscalls (Jakub Jelinek) # -------------------------------------------- # 04/03/10 ak@suse.de 1.1608.83.10 # [PATCH] Fix a 64bit bug in kobject module request # # From Takashi Iwai # # kobj_lookup had a 64bit bug, which caused the request of a unknown # character device to burn CPU instead of failing quickly. # -------------------------------------------- # 04/03/10 davidm@tiger.hpl.hp.com 1.1608.81.36 # Merge tiger.hpl.hp.com:/data1/bk/vanilla/linux-2.5 # into tiger.hpl.hp.com:/data1/bk/lia64/to-linus-2.5 # -------------------------------------------- # 04/03/10 kaneshige.kenji@jp.fujitsu.com 1.1608.81.37 # ia64: don't unmask iosapic interrupts by default # # In ia64 kernel, IOSAPIC's RTEs for PCI interrupts are unmasked at the # boot time before installing device drivers. I think it is very dangerous. # If some PCI devices without device driver generate interrupts, interrupts # are generated repeatedly because these interrupt requests are never # cleared. I think RTEs for PCI interrupts should be unmasked by device # driver. This patch fixes the problem. # -------------------------------------------- # 04/03/11 willy@debian.org 1.1608.81.38 # [PATCH] ia64: Convert to use the generic drivers/Kconfig mechanism. # # -------------------------------------------- # 04/03/11 jbarnes@sgi.com 1.1608.81.39 # [PATCH] ia64: fix misc. sn2 warnings # # This patch fixes a few warnings that have cropped up in the sn2 code: # - hwgfs function prototype mismatch # - pconn uninitialized in pciio.c # - printk formatting fixes in pcibr_dvr.c # - kill volatile qualifier in pcibr_intr.c # -------------------------------------------- # 04/03/12 sfr@canb.auug.org.au 1.1608.83.11 # [PATCH] fix PPC64 iSeries virtual console devices # # While playing with udev, I discovered that the virtual console # devices on iSeries had there minor numbers off by one i.e. /dev/tty1 # was minor 2! # # This fixes it. # -------------------------------------------- # 04/03/12 axboe@suse.de 1.1608.83.12 # [PATCH] user data -> request mapping # # This patch allows you to map a request with user data for io, similarly # to what you can do with bio_map_user() already to a bio. However, this # goes one step further and populates the request so the user only has to # fill in the cdb (almost) and put it on the queue for execution. Patch # converts sg_io() to use it, next patch I'll send adapts cdrom layer to # use it for zero copy cdda dma extraction. # -------------------------------------------- # 04/03/12 axboe@suse.de 1.1608.83.13 # [PATCH] CDROMREADAUDIO dma support # # This small patch builds on top of the blk_rq_map_user() patch just sent, # and enables us to easily support DMA for CDROMREADAUDIO cdda extraction. # It's quite amazing how much cool stuff you can with the new block layer # :-) # # Patch has intelligent fall back from multi frame dma to single frame # dma, and further to old-style pio ripping in case of hardware problems. # -------------------------------------------- # 04/03/12 anton@samba.org 1.1608.83.14 # [PATCH] fix ppc64 in kernel syscalls # # Thanks to some great debugging work by Olaf Hering and Marcus Meissner # it has been noticed that the current ppc64 syscall code is corrupting # 4 bytes past errno. Why we even bothered to set errno beats me, its # unusable in the kernel. # # Since we had to reinstate the inline syscall code we can go back to # using it for those few syscalls that we call. Especially now with # Randy's syscall prototype cleanup we should be calling them directly # but we can do that sometime later. # -------------------------------------------- # 04/03/12 benh@kernel.crashing.org 1.1608.83.15 # [PATCH] ppc32: Fix G5 config space access lockup # # Fix a typo in the code that prevents lockup on config space access # to sleeping devices on ppc32/G5. Please apply. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.16 # [PATCH] print kernel version in oops messages # # From: Arjan van de Ven # # Unfortunatly a large portion of the oops reports lack the basic # information about what kernel version the oops is for; it's trivial to just # print this in the oops as well to improve the usefulness of bugreports... # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.17 # [PATCH] ppc64: fix initialisation of NUMA arrays # # From: Anton Blanchard # # We were hitting problems on machines with cpu_possible != cpu_online when # NUMA was enabled. The debug checks would trip during scheduler init # because we iterate through all possible cpus whereas we only set up NUMA # information for online cpus. # # Longer term we should have a cpu_up hook which sets up its NUMA information # but for now we initalise all possible cpus and memory to node 0. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.18 # [PATCH] Clean up sys_ioperm stubs # # From: Brian Gerst # # Remove stubs for sys_ioperm for non-x86 arches, using sys_ni_syscall # instead where applicable. Support for sys_ioperm is unconditionally no for # non-x86 arches. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.19 # [PATCH] readdir() cleanups # # From: # # cramfs and freevxfs explicitly mark themselves readonly (as other r/o fs # do). # # afs marked noatime (ACKed by maintainer) # # filesystems that do not do update_atime() in their ->readdir() had been # explicitly marked nodiratime. NOTE: cifs, coda and ncpfs almost certainly # need full noatime as we currently have in nfs and afs. # # update_atime() call shifted to callers of ->readdir() and out of # ->readdir() instances. Bugs caught: # # dcache_readdir() updated atime only if it reached EOF. # # bfs_readdir() - ditto. # # qnx4_readdir() - ditto. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.20 # [PATCH] adaptive lazy readahead # # From: Suparna Bhattacharya # # From: Ram Pai # # Pipelined readahead behaviour is suitable for sequential reads, but not for # large random reads (typical of database workloads), where lazy readahead # provides a big performance boost. # # One option (suggested by Andrew Morton) would be to have the application # pass hints to turn off readahead by setting the readahead window to zero # using posix_fadvise64(POSIX_FADV_RANDOM), and to special-case that in # do_generic_mapping_read to completely bypass the readahead logic and # instead read in all the pages needed directly. # # This was the idea I started with. But then I thought, we can do a still # better job ? How about adapting the readahead algorithm to lazy-read or # non-lazy-read based on the past i/o patterns ? # # The overall idea is to keep track of average number of contiguous pages # accessed in a file. If the average at any given time is above ra->pages # the pattern is sequential. If not the pattern is random. If pattern is # sequential do non-lazy-readahead( read as soon as the first page in the # active window is touched) else do lazy-readahead. # # I have studied the behaviour of this patch using my user-level simulator. # It adapts pretty well. # # Note from Suparna: This appears to bring streaming AIO read performance for # large (64KB) random AIO reads back to sane values (since the lazy readahead # backout in the mainline). # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.21 # [PATCH] read-only support for UFS2 # # From: Niraj Kumar # # This patch adds read-only support for ufs2 (used in FreeBSD 5.x) variant of # ufs filesystem. For filesystem specific tools, see # http://ufs-linux.sourceforge.com . # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.22 # [PATCH] fb_console_init fix # # From: James Simmons # # This patch fixes fb_console_init from being called twice. I still need to # fix set_con2fb but this helps but this is still important to get in. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.23 # [PATCH] time interpolator fix # # From: john stultz # # In developing the ia64-cyclone patch, which implements a cyclone based time # interpolator, I found the following bug which could cause time # inconsistencies. # # In update_wall_time_one_tick(), which is called each timer interrupt, we # call time_interpolator_update(delta_nsec) where delta_nsec is approximately # NSEC_PER_SEC/HZ. This directly correlates with the changes to xtime which # occurs in update_wall_time_one_tick(). # # However in update_wall_time(), on a second overflow, we again call # time_interpolator_update(NSEC_PER_SEC). However while the components of # xtime are being changed, the overall value of xtime does not (nsec is # decremented NSEC_PER_SEC and sec is incremented). Thus this call to # time_interpolator_update is incorrect. # # This patch removes the incorrect call to time_interpolator_update and was # found to resolve the time inconsistencies I had seen while developing the # ia64-cyclone patch. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.24 # [PATCH] teach /proc/kmsg about O_NONBLOCK # # If there's nothing available and the file is O_NONBLOCK, return -EAGAIN. # # This is a bit grubby - really we should push the file* down into do_syslog() # and handle it inside the spinlock. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.25 # [PATCH] remove __io_virt_debug # # From: Brian Gerst # # Drivers should all be converted to use ioremap() or isa_*() by now. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.26 # [PATCH] genrtc: cleanups # # From: "Randy.Dunlap" # # From: Luiz Fernando Capitulino # # remove ifdef/endif in rtc_generic_init(). # use returned error code; # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.27 # [PATCH] i386 very early memory detection cleanup patch # # From: "H. Peter Anvin" # # This patch cleans up the very early memory setup on the i386 platform. In # particular, it removes the hard-coded 8 MB limit completely by dynamically # creating the early-boot pagetables rather than having them hard coded. # # While I was at it, I changed head.S so that it always sets up a local GDT; # this means among other things that SMP and VISWS are no longer special # cases, and is conceptually cleaner to boot. The VISWS people have # confirmed it works on VISWS. # # It also uses a separate entrypoint for non-boot processors since this is # completely kernel-internal anyway. This eliminates the need to set %bx on # boot. (If you think this is a bad idea I can eliminate this change; it # just seemed cleaner to me to do it this way.) # # Additionally, zero bss with rep;stosl rather that rep;stosb. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.28 # [PATCH] Allow X86_MCE_NONFATAL to be a module # # From: Herbert Xu # # By allowing X86_MCE_NONFATAL to be a module, it can be included in # distribution kernels without upsetting those with strange hardware. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.29 # [PATCH] dm: endio method # # From: Joe Thornber # # Add an endio method to targets. This method is allowed to request another # shot at failed ios (think multipath). Context can be passed between the map # method and the endio method. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.30 # [PATCH] dm: list_for_each_entry audit # # From: Joe Thornber # # Audit for list_for_each_*entry* # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.31 # [PATCH] dm: default queue limits # # From: Joe Thornber # # Fill in missing queue limitations when table is complete instead of enforcing # the "default" limits on every dm device. Problem noticed by Mike Christie. # # [Christophe Saout] # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.32 # [PATCH] dm: list targets cmd # # From: Joe Thornber # # List targets ioctl. [Patrick Caulfield] # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.33 # [PATCH] dm: stripe width fix # # dm-stripe.c: The stripe width must be at least the page size. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.34 # [PATCH] selinux: clean up binary mount data # # From: James Morris # # selinux is currently inspecting the filesystem name ("nfs" vs "coda" vs # watever) to work out whether it needs to hanbdle binary mount data. # # Eliminate all that by adding a flag to file_system_type.fs_flags. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.35 # [PATCH] UDF filesystem update # # From: Ben Fennema # # - added udf 2.5 #defines # # - fixed prealloc discard race # # - fixed several bugs in inode_getblk # # - added S_IFSOCK support # # - fix unicode encoding bug # # - change partition allocation from kmalloc to vmalloc for large # allocations # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.36 # [PATCH] kbuild: Remove CFLAGS assignment in i386/mach-*/Makefile # # From: Sam Ravnborg # # The EXTRA_CFLAGS assignments in the following files are a left-over from # the early 2.5 days where the source was not compiled from the root of the # source tree. # # Removing these wrong assignments fixes # http://bugme.osdl.org/show_bug.cgi?id=2210 # # A script named 'kernel' in the .. directory no longer halt compilation. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.37 # [PATCH] NUMA-aware zonelist builder # # From: # # The attached patch is NUMA-aware zonelist builder patch, which sorts # zonelist in the order that near-node first, far-node last. In lse-tech and # linux-ia64, where most of NUMA people resides, no objections are raised so # far. # # The patch adds NUMA-specific version of build_zonelists which calls # find_next_best_node to select the next-nearest node to add to zonelist. # # The patch has no effect on flat NUMA platform. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.38 # [PATCH] Redundant unplug_timer deletion # # From: "Chen, Kenneth W" # # The only path to get to del_timer call in __generic_unplug_device() is when # blk_remove_plug() returns 1, and in that case it already removed the # unplug_timer. # # Patch to remove this redundant call. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.39 # [PATCH] compiler.h scoping fixes # # From: Ville Nuorvala # # There are a few kernel-only things in compiler.h which should have been # placed inside __KERNEL__. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.40 # [PATCH] Fix elf mapping of the zero page # # From: William Lee Irwin III # # Using PAGE_SIZE rather than 4096 so that mmap() granularity is honored by # whatever non-i386 architectures use MMAP_PAGE_ZERO. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.41 # [PATCH] kbuild: Cause `make clean' to remove more files # # From: Sam Ravnborg # # Make the difference between 'make clean' and 'make distclean/mrproper' more # explicit. # # make clean now removes all generated files except .config* and .version. # The result is much easier to understand now. # # make clean deletes all generated files (except .config* and .version). # make mrproper deletes configuration and all temporary files left by patch, # editors and the like. # # Example output: # > make mrproper # CLEAN init # CLEAN usr # CLEAN scripts/kconfig # CLEAN scripts # CLEAN .tmp_versions include/config # CLEAN include/asm-i386/asm_offsets.h include/linux/autoconf.h include/linux/version.h include/asm .tmp_versions # CLEAN .version .config # # Form the list of files/directories deleted during make clean, removed all # references that is no longer relevant for the current kernel. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.42 # [PATCH] LOOP_CHANGE_FD ioctl # # From: Arjan van de Ven # # The patch below (written by Al Viro) solves a nasty chicken-and-egg issue # for operating system installers (well at least anaconda but the problem # domain is not exclusive to that) # # The basic problem is this: # # - The small first stage installer locates the image file of the second # stage installer (which has X and all the graphical stuff); this image can # be on the same CD, but it can come via NFS, http or ftp or ... as well. # # - The first stage installer loop-back mounts this image and gives control # to the second stage installer by calling some binary there. # # - The graphical installer then asks the user all those questions and # starts installing packages. Again the packages can come from the CD but # also from NFS or http or ... # # Now in case of a CD install, once all requested packages from the first CD # are installed, the installer wants to unmount and eject the CD and prompt # the user to put CD 2 in....... EXCEPT that the unmount can't work since # the installer is actually running from a loopback mount of this cd. # # The solution is a "LOOP_CHANGE_FD" ioctl, where basically the installer # copies the image to the harddisk (which can only be done late since only # late the target harddisk is mkfs'd) and then magically switches the backing # store FD from underneath the loop device to the one on the target harddisk # (and thus unbusying the CD mount). # # This is obviously only allowed if the size of the new image is identical # and if the loop image is read-only in the first place. It's the # responsibility of root to make sure the contents is the same (but that's of # the give-root-enough-rope kind) # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.43 # [PATCH] loop setup race fix # # From: Chris Mason # # There's a race in loopback setup, it's easiest to trigger with one or more # procs doing loopback mounts at the same time. The problem is that # fs/block_dev.c:do_open() only calls bdev_set_size on the first open. # Picture two procs: # # proc1: mount -o loop file1 mnt1 # proc2: mount -o loop file2 mnt2 # # proc1 proc2 # open /dev/loop0 # bd_openers now 1 # do_open # bd_set_size(bdev, 0) # loop unbound, so bdev size is 0 # open /dev/loop0 # bd_openers now 2 # loop_set_fd # disk capacity now correct, but # # bdev not updated # mount /dev/loop0 /mnt # do_open # # Because bd_openers != 0 for the last do_open, bd_set_size is not called # again and a size of 0 is used. This eventually leads to an oops when the # loop device is unmounted, because fsync_bdev calls block_write_full_page # who decides every page on the block device is outside i_size and unmaps # them. # # When ext2 or reiserfs try to sync a metadata buffer, we get an oops on # because the buffers are no longer mapped. # # The patch below changes loop_set_fd and loop_clr_fd to also manipulate the # size of the block device, which fixes things for me. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.44 # [PATCH] kbuild: fix usage with directories containing '.o' # # From: Sam Ravnborg # # From: Daniel Mack , me # # modpost unconditionally searched for ".o" assuming this is always the # suffix of the module. This fails in two cases: # # a) when building external modules where any directory include ".o" in # the name. One example is a directory named: .../cvs.alsa.org/... # # b) when someone names a kernel directory so it contains ".o". One # example is drivers/scsi/aic.ok/... # # case b) was triggered by renaming the directory for aic7xxx, and modifying # Makefile and Kconfig. This caused make modules to fail. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.45 # [PATCH] Remove unneeded unlock in ipc/sem.c # # From: Manfred Spraul # # sem_revalidate checks that a semaphore array didn't disappear while the # code was running without the semaphore array spinlock. If the array # disappeared, then it will return without holding a lock. find_undo calls # sem_revalidate and then sem_unlock, even if sem_revalidate failed. The # sem_unlock call must be removed. # # Mingming Cao reported a spinlock deadlock with sysv semaphores. A # superflous unlock doesn't explain the deadlock, but it's obviously a bug. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.46 # [PATCH] /proc data corruption check # # From: Arjan van de Ven # # If someone removes a /proc directory which still has subdirectories it will # lead to very nasty things (dentries remaining on hash chains etc etc etc). # The BUG_ON in the patch below will catch this nasty situation. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.47 # [PATCH] Enable i810 fb on x86-64 # # From: Andi Kleen # # i810fb most likely is needed on x86-64 too because there are Intel chipsets # for it now. So far it only linked on i386, fix this. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.48 # [PATCH] Remove arbitrary #acl entries limits on ext[23] when reading # # From: Andreas Gruenbacher # # Remove the arbitrary limit of 32 ACL entries on ext[23] when reading from # disk. This change is backward compatible; we need to have this change in # to be able to also allow writing big ACLs. # # The second patch that removes the ACL entry limit for writes is not # included. I don't want to push that patch now, because large ACLs would # cause 2.4 and current 2.6 kernels to fail. My plan is to remove the second # limit later, in a half-year or year or so. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.49 # [PATCH] watchdog: moduleparam-patches # # From: Wim Van Sebroeck # # Convert last set of watchdog drivers to new moduleparam system. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.50 # [PATCH] AMD ELAN Kconfig fix # # From: Adrian Bunk # # - remove an MELAN entry that was forgotten in the i386 processor # selection menu # # - s/CONFIG_MELAN/CONFIG_X86_ELAN/ was missing in module.h # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.51 # [PATCH] fadvise(POSIX_FADV_DONTNEED) fixups # # From: WU Fengguang # # - In sys_fadvise64_64(): if the start and/or end offsets do not fall on # page boundaries, preserve the partial pages. The thinking here is that it # is better to preserve needed memory than to not shoot down unneeded memory. # # - In invalidate_mapping_pages(): we were invalidating an entire pagevec's # worth of pages each time around, even if that went beyond the part of the # file which the caller asked to be invalidated. Fix that up. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.52 # [PATCH] Fix and harden validate_mm # # From: Andi Kleen # # I was debugging some code that corrupted the vma rb lists and for that I # fixed validate_mm to not be recursive and do some more checks. # # It's slower now, but that shouldn't be a problem. # # Also make it non static to allow easier checks elsewhere. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.53 # [PATCH] current_is_keventd() speedup # # From: Srivatsa Vaddagiri # # current_is_keventd() doesn't need to search across all the CPUs to identify # itself. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.54 # [PATCH] Fix rootfs on ramdisk # # From: vda # # Add a missing test for the "root=/dev/ram" kernel boot option. It's just an # alias for /dev/ram0, but it worked in 2.4... # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.55 # [PATCH] Fix reading the last block on a bdev # # From: Chris Mason # # This patch fixes a problem we're hitting on ia64 with page sizes > 4k. # # When the page size is greater than the block size, and parts of the page # fall past the end of the device, readpage will fail because # blkdev_get_block returns -EIO for blocks past i_size. # # The attached patch changes blkdev_get_block to return holes when reading # past the end of the device, which allows us to read that last valid 4k # block and then fill the rest of the page with zeros. Writes will still # fail with -EIO. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.56 # [PATCH] wavfront.c needs syscalls.h # # sound/oss/wavfront.c: In function `wavefront_download_firmware': # sound/oss/wavfront.c:2524: warning: implicit declaration of function `sys_open' # sound/oss/wavfront.c:2533: warning: implicit declaration of function `sys_read' # sound/oss/wavfront.c:2582: warning: implicit declaration of function `sys_close # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.57 # [PATCH] EDD: Get Legacy Parameters # # From: Matt Domsch # # Patch below from Patrick J. LoPresti and myself. Patrick describes: # # Why this patch? The problem is that the legacy BIOS interface # (INT13/AH=3D08) for querying the disk geometry returns different values # than the extended INT13 interface which the EDD code currently uses. This # is because the legacy interface only provides a 10-bit cylinder field, so # modern BIOSes "lie" about the head/sector counts in order to make more of # the disk visible within the first 1024 cylinders. # # Many non-Linux applications, including the stock Windows boot loader, DOS # fdisk, etc., rely upon the legacy interface and geometry. So it is useful # to be able to obtain the legacy values from a running Linux kernel. # # What this patch does is to add new entries under # /sys/firmware/edd/int13_devXX named "legacy_cylinders", "legacy_heads", and # "legacy_sectors". These provide the geometry given by the legacy # INT13/AH=3D08 BIOS interface, just like the current "default_cylinders" # etc. provide the the geometry given by the INT13/AH=3D48 interface. # # Without this patch, I cannot use Linux to partition a drive and install # Windows, which happens to be my application. # # - Pat # http://unattended.sourceforge.net/ # # In addition, this adds two buggy BIOS workarounds in the EDD int13 # calls as suggested by Ralf Brown's interrupt list. # # I'm also interested in moving this code out of arch/i386/kernel/edd.c and # include/asm-i386/edd.h, as I believe it is applicable on x86-64 as well. # However, there's no good place under drivers/ to put edd.c when it's not # tied to a bus, but to several CPU architectures and their firmwares... # Maybe a new directory drivers/firmware? # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.58 # [PATCH] cciss: init section fix # # From: "Randy.Dunlap" # # cciss_scsi_detect() can be called after init (for TAPE support). # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.59 # [PATCH] add nowarn to a few pte chain allocators # # From: Arjan van de Ven # # Several of the pte_chain_alloc() allocators that use GFP_ATOMIC have a # fallback for failure that sleeps; they thus need to not warn on failure.. # Seen during a big fork on a busy system. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.60 # [PATCH] Disable Macintosh device drivers for all but PPC || MAC # # From: Marc-Christian Petersen # # The attached patch is needed to stop showing us "Macintosh device drivers" # for all architectures via menuconfig || xconfig || gconfig. It's only # necessary for PPC and/or MAC. # # ACKed by benh. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.61 # [PATCH] Applicom warning # # From: Geert Uytterhoeven # # Add missing include (needed for struct inode) # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.62 # [PATCH] Fix CONFIG_NVRAM dependencies # # From: Geert Uytterhoeven # # Make CONFIG_NVRAM depend on the prerequisites that are explicitly checked # for in drivers/char/nvram.c, or on CONFIG_GENERIC_NVRAM (for PPC). # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.63 # [PATCH] module.h __attribute_used__ fix # # From: Rusty Russell # # Someone added __attribute_used__ throughout module.h, but didn't remove the # ", unused". Looks like some arch/gcc combos still consider it unused, and # discard the fn. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.64 # [PATCH] fix raid0 readahead size # # From: Arjan van de Ven # # Readahead of raid0 was suboptimal; it read only 1 stride ahead. The # problem with this is that while it will keep all spindles busy, it will not # actually manage to make larger IO's, eg each disk would just do the chunk # size IO. Doing at least 2 chunks is more than appropriate so that each # spindle will get a chance to merge IO's. # # (Neil fixed raid6 and raid6 too) # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.65 # [PATCH] Fix NULL pointer dereference in blkmtd.c # # From: Michel Marti # # The blkmtd driver oopses in add_device(). The following trivial patch # fixes this. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.66 # [PATCH] fbdev: monitor detection fixes # # From: James Simmons , # Kronos # # Various fixes and enhancements to the monitor hardware detection code. The # only driver that uses it is the radeon driver. # # Old EDID parsing code was very verbose, half of the patch address this (ie. # print lots of stuff iff DEBUG). The other big change is the FB_MODE_IS_* # stuff: we really need a way to know the origin of a video mode. In this way # we can select video mode that comes from EDID instead of VESA or GTF. # # Drivers other than radeonfb won't be affected because they cannot (yet) get # EDID from the monitor and don't use EDID related code. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.67 # [PATCH] m68k: __test_and_set_bit() # # From: Geert Uytterhoeven # # Add missing implementation for non-atomic __test_and_set_bit() # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.68 # [PATCH] m68k: Amiga Framemaster II fb sysfsification # # From: Geert Uytterhoeven # # Amiga Framemaster II fb: Add sysfs support (from James Simmons) # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.69 # [PATCH] Apollo fb sysfsification # # From: Geert Uytterhoeven # # Apollo fb: Add sysfs support (from James Simmons) # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.70 # [PATCH] m68k: Macintosh IDE fixes # # From: Geert Uytterhoeven # # Mac IDE: Make sure the core IDE driver doesn't try to request the MMIO # ports a second time, since this will fail. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.71 # [PATCH] m68k: interrupt management cleanups # # From: Geert Uytterhoeven # # M68k interrupt management: rename routines to not confuse them with # syscalls # # - sys_{request,free}_irq() -> cpu_{request,free}_irq() # # - q40_sys_default_handler[] -> q40_default_handler # # - sys_default_handler() -> default_handler() # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.72 # [PATCH] Add barriers to avoid race in mempool_alloc/free # # From: Chris Mason # # mempool_alloc() and mempool_free() check pool->curr_nr without any locks # held. This can lead to skipping a wakeup when there are people waiting, # and sleeping when there are free elements in the pool. # # I can't trigger this reliably, but sooner or later someone on ppc is # probably going to hit it. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.73 # [PATCH] synclinkmp.c update # # From: Paul Fulghum # # Patch for synclinkmp.c # # * Track driver API changes # * Remove cast (kernel janitor) # * Replace page_free call with kfree (to match kmalloc allocation) # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.74 # [PATCH] synclink_cs.c update # # From: Paul Fulghum # # * Track driver API changes # * Remove cast (kernel janitor) # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.75 # [PATCH] synclink.c update # # From: Paul Fulghum # # * track driver API changes # * remove cast (kernel janitor) # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.76 # [PATCH] vm: per-zone vmscan instrumentation # # To check on zone balancing, split the /proc/vmstat:pgsteal, pgreclaim pgalloc # and pgscan stats into per-zone counters. # # Additionally, split the pgscan stats into pgscan_direct and pgscan_kswapd to # see who's doing how much scanning. # # And add a metric for the number of slab objects which were scanned. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.77 # [PATCH] return remaining jiffies from blk_congestion_wait() # # Teach blk_congestion_wait() to return the number of jiffies remaining. This # is for debug, but it is also nicely consistent. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.78 # [PATCH] Narrow blk_congestion_wait races # # From: Nick Piggin # # The addition of the smp_mb and the other change is to try to close the # window for races a bit. Obviously they can still happen, it's a racy # interface and it doesn't matter much. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.79 # [PATCH] mm/vmscan.c: remove unused priority argument. # # From: Nikita Danilov # # Now that decision to reclaim mapped memory is taken on the basis of # zone->prev_priority, priority argument is no longer needed. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.80 # [PATCH] kswapd throttling fixes # # The logic in balance_pgdat() is all bollixed up. # # - the incoming arg `nr_pages' should be used to determine if we're being # asked to free a specific number of pages, not `to_free'. # # - local variable `to_free' is not appropriate for the determination of # whether we failed to bring all zones to appropriate free pages levels. # # Fix this by correctly calculating `all_zones_ok' and then use # all_zones_ok to determine whether we need to throttle kswapd. # # So the logic now is: # # # for (increasing priority) { # # all_zones_ok = 1; # # for (all zones) { # to_reclaim = number of pages to try to reclaim # from this zone; # max_scan = number of pages to scan in this pass # (gets larger as `priority' decreases) # /* # * set `reclaimed' to the number of pages which were # * actually freed up # */ # reclaimed = scan(max_scan pages); # reclaimed += shrink_slab(); # # to_free -= reclaimed; /* for the `nr_pages>0' case */ # # /* # * If this scan failed to reclaim `to_reclaim' or more # * pages, we're getting into trouble. Need to scan # * some more, and throttle kswapd. Note that this # * zone may now have sufficient free pages due to # * freeing activity by some other process. That's # * OK - we'll pick that info up on the next pass # * through the loop. # */ # if (reclaimed < to_reclaim) # all_zones_ok = 0; # } # if (to_free > 0) # continue; /* swsusp: need to do more work */ # if (all_zones_ok) # break; /* kswapd is done */ # /* # * OK, kswapd is getting into trouble. Take a nap, then take # * another pass across the zones. # */ # blk_congestion_wait(); # } # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.81 # [PATCH] vmscan: preserve page referenced info in refill_inactive() # # From: Nick Piggin # # If refill_inactive_zone() is running in its dont-reclaim-mapped-memory mode # we are tossing away the referenced infomation on active mapped pages. # # So put that info back if we're not going to deactivate the page. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.82 # [PATCH] shrink_slab: math precision fix # # From: Nick Piggin # # In shrink_slab(), do the multiply before the divide to avoid losing # precision. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.83 # [PATCH] vm: shrink slab evenly in try_to_free_pages() # # From: Nick Piggin # # In try_to_free_pages(), put even pressure on the slab even if we have # reclaimed enough pages from the LRU. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.84 # [PATCH] vmscan: fix calculation of number of pages scanned # # From: Nick Piggin # # The logic which calculates the numberof pages which were scanned is mucked # up. Fix. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.85 # [PATCH] vm: scan slab in response to highmem scanning # # The patch which went in six months or so back which said "only reclaim slab # if we're scanning lowmem pagecache" was wrong. I must have been asleep at # the time. # # We do need to scan slab in response to highmem page reclaim as well. Because # all the math is based around the total amount of memory in the machine, and # we know that if we're performing highmem page reclaim then the lower zones # have no free memory. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.86 # [PATCH] vmscan: zone balancing fix # # We currently have a problem with the balancing of reclaim between zones: much # more reclaim happens against highmem than against lowmem. # # This patch partially fixes this by changing the direct reclaim path so it # does not bale out of the zone walk after having reclaimed sufficient pages # from highmem: go on to reclaim from lowmem regardless of how many pages we # reclaimed from lowmem. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.87 # [PATCH] vmscan: drive everything via nr_to_scan # # Page reclaim is currently a bit schitzo: sometimes we say "go and scan this # many pages and tell me how many pages were freed" and at other times we say # "go and scan this many pages, but stop if you freed this many". # # It makes the logic harder to control and to understand. This patch coverts # everything into the "go and scan this many pages and tell me how many pages # were freed" model. # # It doesn't seem to affect performance much either way. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.88 # [PATCH] Balance inter-zone scan rates # # When page reclaim is working out how many pages to san in a zone (max-scan) # it presently rounds that number up if it looks too small - for work batching. # # Problem is, this can result in excessive scanning against small zones which # have few inactive pages. So remove it. # # Not that it is possible for max_scan to be zero. That's OK - it'll become # non-zero as the priority increases. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.89 # [PATCH] vmscan: avoid bogus throttling # # - If max_scan evaluates to zero due to a very small inactive list and high # `priority' numbers, we don't want to thrlttle yet. # # - In balance_pgdat(), we may end up not scanning any pages because all # zones happened to be above pages_high. Avoid throttling in this case too. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.90 # [PATCH] kswapd: avoid unnecessary reclaiming from higher zones # # Currently kswapd walks across all zones in dma->normal->highmem order, # performing proportional scanning until all zones are OK. This means that # pressure against ZONE_NORMAL causes unnecessary reclaim of ZONE_HIGHMEM. # # To fix that up we change kswapd so that it walks the zones in the # high->normal->dma direction, skipping zones which are OK. Once it encounters # a zone which needs some reclaim kswapd will perform proportional scanning # against that zone as well as all the succeeding lower zones. # # We scan the lower zones even if they have sufficient free pages. This is # because # # a) the lower zone may be above pages_high, but because of the incremental # min, the lower zone may still not be eligible for allocations. That's bad # because cache in that lower zone will then not be scanned at the correct # rate. # # b) pages in this lower zone are usable for allocations against the higher # zone. So we do want to san all the relevant zones at an equal rate. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.91 # [PATCH] kswapd: fix lumpy page reclaim # # As kswapd is now scanning zones in the highmem->normal->dma direction it can # get into competition with the page allocator: kswapd keep on trying to free # pages from highmem, then kswapd moves onto lowmem. By the time kswapd has # done proportional scanning in lowmem, someone has come in and allocated a few # pages from highmem. So kswapd goes back and frees some highmem, then some # lowmem again. But nobody has allocated any lowmem yet. So we keep on and on # scanning lowmem in response to highmem page allocations. # # With a simple `dd' on a 1G box we get: # # r b swpd free buff cache si so bi bo in cs us sy wa id # 0 3 0 59340 4628 922348 0 0 4 28188 1072 808 0 10 46 44 # 0 3 0 29932 4660 951760 0 0 0 30752 1078 441 1 6 30 64 # 0 3 0 57568 4556 924052 0 0 0 30748 1075 478 0 8 43 49 # 0 3 0 29664 4584 952176 0 0 0 30752 1075 472 0 6 34 60 # 0 3 0 5304 4620 976280 0 0 4 40484 1073 456 1 7 52 41 # 0 3 0 104856 4508 877112 0 0 0 18452 1074 97 0 7 67 26 # 0 3 0 70768 4540 911488 0 0 0 35876 1078 746 0 7 34 59 # 1 2 0 42544 4568 939680 0 0 0 21524 1073 556 0 5 43 51 # 0 3 0 5520 4608 976428 0 0 4 37924 1076 836 0 7 41 51 # 0 2 0 4848 4632 976812 0 0 32 12308 1092 94 0 1 33 66 # # Simple fix: go back to scanning the zones in the dma->normal->highmem # direction so we meet the page allocator in the middle somewhere. # # r b swpd free buff cache si so bi bo in cs us sy wa id # 1 3 0 5152 3468 976548 0 0 4 37924 1071 650 0 8 64 28 # 1 2 0 4888 3496 976588 0 0 0 23576 1075 726 0 6 66 27 # 0 3 0 5336 3532 976348 0 0 0 31264 1072 708 0 8 60 32 # 0 3 0 6168 3560 975504 0 0 0 40992 1072 683 0 6 63 31 # 0 3 0 4560 3580 976844 0 0 0 18448 1073 233 0 4 59 37 # 0 3 0 5840 3624 975712 0 0 4 26660 1072 800 1 8 46 45 # 0 3 0 4816 3648 976640 0 0 0 40992 1073 526 0 6 47 47 # 0 3 0 5456 3672 976072 0 0 0 19984 1070 320 0 5 60 35 # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.92 # [PATCH] fix the kswapd zone scanning algorithm # # This removes a vestige of the old algorithm. We don't want to skip zones if # all_zones_ok is true: we've already precalculated which zones need scanning # and this just stops us from ever performing kswapd reclaim from the DMA zone. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.93 # [PATCH] vmscan: less throttling of page allocators and kswapd # # This is just a random unsubstantiated tuning tweak: don't immediately # throttle page allocators and kwapd when the going is getting heavier: scan a # bit more of the LRU before throttling. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.94 # [PATCH] vmscan: batch up inactive list scanning work # # From: Nick Piggin # # Use a "refill_counter" for inactive list scanning, similar to the one used # for active list scanning. This batches up scanning now that we precisely # balance ratios, and don't round up the amount to be done. # # No observed benefits, but I imagine it would lower the acquisition # frequency of the lru locks in some cases, and make codepaths more efficient # in general due to cache niceness. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.95 # [PATCH] fix vm-batch-inactive-scanning.patch # # - prevent nr_scan_inactive from going negative # # - compare `count' with SWAP_CLUSTER_MAX, not `max_scan' # # - Use ">= SWAP_CLUSTER_MAX", not "> SWAP_CLUSTER_MAX". # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.96 # [PATCH] vm: balance inactive zone refill rates # # The current refill logic in refill_inactive_zone() takes an arbitrarily large # number of pages and chops it down to SWAP_CLUSTER_MAX*4, regardless of the # size of the zone. # # This has the effect of reducing the amount of refilling of large zones # proportionately much more than of small zones. # # We made this change in may 2003 and I'm damned if I remember why. let's put # it back so we don't truncate the refill count and see what happens. # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.97 # [PATCH] vmscan: add lru_to_page() helper # # From: Nick Piggin # # Add a little helper macro for a common list extraction operation in vmscan.c # -------------------------------------------- # 04/03/12 akpm@osdl.org 1.1608.83.98 # [PATCH] slab: avoid higher-order allocations # # From: Manfred Spraul # # At present slab is using 2-order allocations for the size-2048 cache. Of # course, this can affect networking quite seriously. # # The patch ensures that slab will never use more than a 1-order allocation # for objects which have a size of less than 2*PAGE_SIZE. # -------------------------------------------- # 04/03/12 torvalds@ppc970.osdl.org 1.1608.83.99 # Revert attribute_used changes in module.h. They were wrong. # # Cset exclude: akpm@osdl.org|ChangeSet|20040312161945|47751 # -------------------------------------------- # 04/03/12 torvalds@ppc970.osdl.org 1.1608.81.40 # Merge http://lia64.bkbits.net/to-linus-2.5 # into ppc970.osdl.org:/home/torvalds/v2.5/linux # -------------------------------------------- # 04/03/12 torvalds@ppc970.osdl.org 1.1608.81.41 # Merge bk://linux-scsi.bkbits.net/scsi-for-linus-2.6 # into ppc970.osdl.org:/home/torvalds/v2.5/linux # -------------------------------------------- # 04/03/12 jgarzik@redhat.com 1.1608.86.1 # [wireless] Add new Prism54 wireless driver. # -------------------------------------------- # 04/03/12 jgarzik@redhat.com 1.1608.86.2 # [wireless prism54] remove WIRELESS_EXT ifdefs # -------------------------------------------- # 04/03/12 trivial@rustcorp.com.au 1.1608.81.42 # [PATCH] drivers_net_wireless_airo.c '< 0' comparison make sense # # From: # # The sense of the comparison was signed, but the code was testing # an unsigned variable for less-than-zero. # -------------------------------------------- # 04/03/12 manfred@colorfullife.com 1.1608.81.43 # [PATCH] forcedeth update # # Andrew de Quincey added wol support to forcedeth. # The patch also renames additional function, to help analyzing backtraces. # -------------------------------------------- # 04/03/12 rddunlap@osdl.org 1.1608.81.44 # [PATCH] eepro init section usage # # eepro_print_info() can be __init. # -------------------------------------------- # 04/03/12 rddunlap@osdl.org 1.1608.81.45 # [PATCH] smctr: fix init section usage # # smctr_chk_mca() can be __init. # -------------------------------------------- # 04/03/12 brazilnut@us.ibm.com 1.1608.81.46 # [PATCH] pcnet32 correct names for changes # # This patch corrects the names of contributors of changes to the pcnet32 # driver. # -------------------------------------------- # 04/03/12 brazilnut@us.ibm.com 1.1608.81.47 # [PATCH] netdevice.h add netif_msg_init helper # # This patch adds a helper function to initialize the debug bit mask # for use with netif_msg_*. When the debug_value is out of range # it returns the default_msg_enable_bits. Tested IA32. # -------------------------------------------- # 04/03/12 arjanv@redhat.com 1.1608.81.48 # [PATCH] xirc2ps ethtool fix # # patch below adds bus_info for xirc2ps_cs; anaconda depends on this info to # be there. # -------------------------------------------- # 04/03/12 torvalds@ppc970.osdl.org 1.1608.87.1 # Merge bk://gkernel.bkbits.net/prism54-2.5 # into ppc970.osdl.org:/home/torvalds/v2.5/linux # -------------------------------------------- # 04/03/12 rddunlap@osdl.org 1.1608.81.49 # [PATCH] use netdev_priv() in appletalk & fc # -------------------------------------------- # 04/03/12 rddunlap@osdl.org 1.1608.81.50 # [PATCH] use netdev_priv() in /hamradio/ # -------------------------------------------- # 04/03/12 rddunlap@osdl.org 1.1608.81.51 # [PATCH] use netdev_priv() in 3com net drivers # -------------------------------------------- # 04/03/12 rddunlap@osdl.org 1.1608.81.52 # [PATCH] use netdev_priv() in net/ lance drivers # -------------------------------------------- # 04/03/12 rddunlap@osdl.org 1.1608.81.53 # [PATCH] use netdev_priv() in net/arm drivers # -------------------------------------------- # 04/03/12 rddunlap@osdl.org 1.1608.81.54 # [PATCH] use netdev_priv() in net/ intel drivers # -------------------------------------------- # 04/03/12 rddunlap@osdl.org 1.1608.81.55 # [PATCH] use netdev_priv() in net/pcmcia/ drivers # -------------------------------------------- # 04/03/12 rddunlap@osdl.org 1.1608.81.56 # [PATCH] use netdev_priv() in net/tulip drivers # -------------------------------------------- # 04/03/12 rddunlap@osdl.org 1.1608.81.57 # [PATCH] use netdev_priv() in net/tokenring/ drivers # -------------------------------------------- # 04/03/12 rddunlap@osdl.org 1.1608.81.58 # [PATCH] use netdev_priv() in net/wireless/ drivers # -------------------------------------------- # 04/03/12 rddunlap@osdl.org 1.1608.81.59 # [PATCH] use netdev_priv() in tap/tun/plip/loop/skel # -------------------------------------------- # 04/03/12 rddunlap@osdl.org 1.1608.81.60 # [PATCH] use netdev_priv() in fusion/mptlan # -------------------------------------------- # 04/03/12 rddunlap@osdl.org 1.1608.81.61 # [PATCH] use netdev_priv() in net/wan drivers # -------------------------------------------- # 04/03/12 rddunlap@osdl.org 1.1608.81.62 # [PATCH] use netdev_priv() in drivers/net/ (others) # -------------------------------------------- # 04/03/12 rene.herman@keyaccess.nl 1.1608.81.63 # [PATCH] 8139too assertions # -------------------------------------------- # 04/03/12 jgarzik@redhat.com 1.1608.87.2 # Add Promise SX8 (carmel) block driver. # -------------------------------------------- # 04/03/12 jgarzik@redhat.com 1.1608.55.33 # Merge redhat.com:/spare/repo/linux-2.5 # into redhat.com:/spare/repo/libata-2.5 # -------------------------------------------- # 04/03/12 jgarzik@redhat.com 1.1612 # Merge redhat.com:/spare/repo/netdev-2.6/netpoll # into redhat.com:/spare/repo/netconsole-2.5 # -------------------------------------------- # 04/03/12 jgarzik@redhat.com 1.1608.81.64 # Merge kernel.bkbits.net:net-drivers-2.5 # into redhat.com:/spare/repo/net-drivers-2.5 # -------------------------------------------- # 04/03/12 torvalds@ppc970.osdl.org 1.1613 # Merge bk://kernel.bkbits.net/jgarzik/netconsole-2.5 # into ppc970.osdl.org:/home/torvalds/v2.5/linux # -------------------------------------------- # 04/03/12 torvalds@ppc970.osdl.org 1.1614 # Merge bk://gkernel.bkbits.net/libata-2.5 # into ppc970.osdl.org:/home/torvalds/v2.5/linux # -------------------------------------------- # 04/03/12 jejb@mulgrave.(none) 1.1615 # MPT Fusion driver 3.01.01 update # # From: Moore, Eric Dean # # This is an update for the MPT Fusion drivers 2.6 kernel. # Version 3.01.01. # # This is a fix for poor performance in RAID Volumes. # The dvStatus was being cleared for hidden physical disks # when mptscsih_slave_destroy is called. # # Also, I have fixed the warning comming from mptscsih_reset_timeouts. # -------------------------------------------- # 04/03/12 markh@osdl.org 1.1616 # [PATCH] aacraid driver patch # # I submitted a patch last month for the aacraid driver's reset handler. # I left out setting function pointers in the adapter_ops structure for # the adapter_check_health element. # -------------------------------------------- # 04/03/12 willy@debian.org 1.1617 # [PATCH] sym2 2.1.18i # # - Correct a typo "mvram" -> "nvram". # - Re-do the PQS/PDS support which I'd #if 0 out. Should even work on # multiple-domain boxes now ;-) # - Move all the nvram definitions to sym_nvram.h (from Gerard's 2.1.19-pre3) # - hcb_p -> struct sym_hcb * # - sdev_p -> struct sym_device * # - Delete a lot of unused macros from sym_misc.h # - Move READ_BARRIER and WRITE_BARRIER definitions to sym_glue.h # - SYM_CONF_NVRAM_WRITE_SUPPORT (from Gerard's 2.1.19-pre3). Not enabled # yet. # - Fix some -W warnings (some courtesy of Adrian Bunk). # -------------------------------------------- # 04/03/12 markh@osdl.org 1.1618 # [PATCH] add adapter support to aacraid driver (update) # # Mark S. said that there was another adapter added, and that they changed # the names of some boards. Here is the updated version. # -------------------------------------------- # 04/03/12 James.Bottomley@steeleye.com 1.1619 # [PATCH] add device quiescing to the SCSI API # # This patch adds the ability to quiesce a SCSI device. The idea is that # user issued commands (including filesystem ones) would get blocked, # while mid-layer and device issued ones would be allowed to proceed. # This is for things like Domain Validation which like to operate on an # otherwise quiet device. # # There is one big change: to get all of this to happen correctly, # scsi_do_req() has to queue on the *head* of the request queue, not the # tail as it was doing previously. The reason is that deferred requests # block the queue, so anything needing executing after a deferred request # has to go in front of it. I don't think there are any untoward # consequences of this. # -------------------------------------------- # 04/03/12 James.Bottomley@steeleye.com 1.1620 # [PATCH] more SPI transport attribute updates # # This does three things # # - Fix the signedness of the bit attributes (otherwise they show up as -1 # when on, not 1) # - Make the period adjust to the closest value rather than ignoring # values it doesn't understand. # - Add a visibility field to attributes, so drivers can get rid of # attributes they're never going to care about # -------------------------------------------- # 04/03/12 James.Bottomley@steeleye.com 1.1621 # [PATCH] update the 53c700 use of transport attributes # # This patch just brings it up to date with the previous transport # attribute patch, moving it to the model where it sets the min/max of the # attribute if asked for something outside its range. It also only makes # period and offset visible (it doesn't care about any of the others). # -------------------------------------------- # 04/03/12 scott.feldman@intel.com 1.1608.81.65 # [netdrvr e100] fix stray skb pointer # # * Not setting cb->skb = NULL after releasing skb to OS or during # initialization of cbs. Reported by Deepak Saxena # [dsaxena@plexity.net]. # -------------------------------------------- # 04/03/13 len.brown@intel.com 1.1608.1.41 # [ACPI] SMP poweroff (David Shaohua Li) # http://bugzilla.kernel.org/show_bug.cgi?id=1141 # -------------------------------------------- # 04/03/13 len.brown@intel.com 1.1608.1.42 # [ACPI] ACPICA 20040311 from Bob Moore # # Fixed a problem where errors occurring during the parse phase of control # method execution did not abort cleanly. For example, objects created # and installed in the namespace were not deleted. This caused all # subsequent invocations of the method to return the AE_ALREADY_EXISTS # exception. # # Implemented a mechanism to force a control method to "Serialized" # execution if the method attempts to create namespace objects. # (The root of the AE_ALREADY_EXISTS problem.) # # Implemented support for the predefined _OSI "internal" control method. # Initial supported strings are "Linux", "Windows 2000", "Windows 2001", # and "Windows 2001.1", and can be easily upgraded for new strings as # necessary. This feature allows Linux to execute # the fully tested, "Windows" code path through the ASL code # # Global Lock Support: Now allows multiple acquires and releases with any # internal thread. Removed concept of "owning thread" for this special # mutex. # # Fixed two functions that were inappropriately declaring large objects on # the CPU stack: ps_parse_loop() and ns_evaluate_relative(). # Reduces the stack usage during method execution considerably. # # Fixed a problem in the ACPI 2.0 FACS descriptor (actbl2.h) where the # S4Bios_f field was incorrectly defined as UINT32 instead of UINT32_BIT. # # Fixed a problem where acpi_ev_gpe_detect() would fault # if there were no GPEs defined on the machine. # # Implemented two runtime options: One to force all control method # execution to "Serialized" to mimic Windows behavior, another to disable # _OSI support if it causes problems on a given machine. # -------------------------------------------- # 04/03/13 jgarzik@redhat.com 1.1614.1.1 # [blk carmel] fix bug, minor cleanups # # * the scan-channels message seemed to always give invalid output. # Look at the constant, and discover we are sending another # message entirely. Fix the constant (CARM_MSG_IOCTL). # # * s/MISC_SYNC_TIME/MISC_SET_TIME/ # # * list some additional messages # # * bump version number # -------------------------------------------- # 04/03/13 len.brown@intel.com 1.1614.2.1 # Merge intel.com:/home/lenb/bk/linux-2.6.5 # into intel.com:/home/lenb/src/linux-acpi-test-2.6.5 # -------------------------------------------- # 04/03/13 len.brown@intel.com 1.1614.2.2 # Merge intel.com:/home/lenb/src/linux-acpi-test-2.6.4 # into intel.com:/home/lenb/src/linux-acpi-test-2.6.5 # -------------------------------------------- # 04/03/13 len.brown@intel.com 1.1608.1.43 # [ACPI] add boot parameters "acpi_osi=" and "acpi_serialize" # acpi_osi= will disable the _OSI method -- which by default # tells the BIOS to behave as if Windows is the OS. # acpi_serialize is for debugging AE_ALREADY_EXISTS failures # -------------------------------------------- # 04/03/13 len.brown@intel.com 1.1614.2.3 # Merge intel.com:/home/lenb/src/linux-acpi-test-2.6.4 # into intel.com:/home/lenb/src/linux-acpi-test-2.6.5 # -------------------------------------------- # 04/03/13 jgarzik@redhat.com 1.1614.3.1 # Merge redhat.com:/spare/repo/linux-2.5 # into redhat.com:/spare/repo/net-drivers-2.5 # -------------------------------------------- # 04/03/13 James.Bottomley@steeleye.com 1.1622 # [PATCH] Add Domain Validation to the SPI transport class # # Domain Validation is a fairly essential element to the SCSI Parallel # Interface (although if you look very few drivers actually do it). The # premise is that the Parallel Bus, being a transmission line, might not # be correctly tuned to the transfers you want do perform. DV probes the # parameters of the transport until it finds a setting that works (for the # interested, see http://www.t10.org/ftp/t10/drafts/sdv/sdv-r08b.pdf) # # The current code employs rather simplistic DV heuristics, although those # can be improved over time. The change in scsi_scan.c is so that DV may # be done easily from the slave_configure routine, which is the most # natural place to begin. # -------------------------------------------- # 04/03/13 torvalds@ppc970.osdl.org 1.1614.1.2 # Merge bk://gkernel.bkbits.net/net-drivers-2.5 # into ppc970.osdl.org:/home/torvalds/v2.5/linux # -------------------------------------------- # 04/03/13 perex@suse.cz 1.1614.4.1 # Merge suse.cz:/home/perex/bk/linux-sound/linux-2.5 # into suse.cz:/home/perex/bk/linux-sound/linux-sound # -------------------------------------------- # 04/03/13 perex@suse.cz 1.1614.4.2 # ALSA CVS update - Clemens Ladisch # ALSA sequencer # remove superfluous call to snd_seq_event_port_detach # -------------------------------------------- # 04/03/13 perex@suse.cz 1.1614.4.3 # ALSA CVS update - Clemens Ladisch # ALSA sequencer,ALSA<-OSS sequencer # use wrapper function for DELETE_PORT ioctl calls # -------------------------------------------- # 04/03/13 perex@suse.cz 1.1614.4.4 # ALSA CVS update - Clemens Ladisch # USB generic driver # use MIN_PACKS_URB as lower bound for nrpacks parameter # -------------------------------------------- # 04/03/13 perex@suse.cz 1.1614.4.5 # ALSA CVS update - Clemens Ladisch # USB generic driver # show one decimal place of momentary frequency in proc file # -------------------------------------------- # 04/03/13 perex@suse.cz 1.1614.4.6 # ALSA CVS update - Clemens Ladisch # USB generic driver # prevent twenty-seconds wait when unplugging USB MIDI device with a port subscription # -------------------------------------------- # 04/03/13 perex@suse.cz 1.1614.4.7 # ALSA CVS update - Takashi Iwai # VIA82xx driver # restrict the PCM sample rates to 32, 44.1 and 48kHz when the SPDIF # switch is on. # -------------------------------------------- # 04/03/13 perex@suse.cz 1.1614.4.8 # ALSA CVS update - Jaroslav Kysela # DT019x driver # Fixed warnings # -------------------------------------------- # 04/03/13 perex@suse.cz 1.1614.4.9 # ALSA CVS update - Takashi Iwai # VIA82xx driver # patch was applied wrongly. fixed the rate restriction of spdif output # again. # -------------------------------------------- # 04/03/13 perex@suse.cz 1.1614.4.10 # ALSA CVS update - Takashi Iwai # Documentation,PCI drivers,au88x0 driver # added the au88x0 drivers for Aureal soundcards by Manuel Jander # -------------------------------------------- # 04/03/13 perex@suse.cz 1.1614.4.11 # ALSA CVS update - Takashi Iwai # PPC Tumbler driver # added input source switch to select mic/line-in. # -------------------------------------------- # 04/03/13 perex@suse.cz 1.1614.4.12 # ALSA CVS update - Takashi Iwai # Documentation # changed the description of the buffer allocation routines # for the new designed functions. # -------------------------------------------- # 04/03/13 perex@suse.cz 1.1614.4.13 # ALSA CVS update - Takashi Iwai # Documentation # fixed the files to include. # -------------------------------------------- # 04/03/13 perex@suse.cz 1.1614.4.14 # ALSA CVS update - Takashi Iwai # USB generic driver # added fix and workaround for the mixer problem on SB Extigy. # -------------------------------------------- # 04/03/13 perex@suse.cz 1.1614.4.15 # ALSA CVS update - Takashi Iwai # PPC Tumbler driver # fixed the info callback of mixer input source (for enum type). # -------------------------------------------- # 04/03/13 perex@suse.cz 1.1614.4.16 # ALSA CVS update - Takashi Iwai # au88x0 driver # removed EXPORT_NO_SYMBOLS. # -------------------------------------------- # 04/03/13 perex@suse.cz 1.1614.4.17 # ALSA CVS update - Takashi Iwai # EMU10K1/EMU10K2 driver # disabled Dell OEM Emu10k1x from the pci id list. # the board isn't compatible with the normal emu10k1. # -------------------------------------------- # 04/03/13 perex@suse.cz 1.1614.4.18 # ALSA CVS update - Takashi Iwai # MIXART driver # fixed the compile warning. # -------------------------------------------- # 04/03/13 perex@suse.cz 1.1614.4.19 # ALSA CVS update - Takashi Iwai # Documentation,PCI drivers,ATIIXP driver # added snd-atiixp driver for the ATI IXP150/200/250 AC97 controllers. # -------------------------------------------- # 04/03/13 perex@suse.cz 1.1614.4.20 # ALSA CVS update - Takashi Iwai # Documentation,PCI drivers,Intel8x0-modem driver # added Intel-compatible onboard MC97 modem driver # by Sasha Khapyorsky # -------------------------------------------- # 04/03/13 perex@suse.cz 1.1614.4.21 # ALSA CVS update - Takashi Iwai # ALSA Core # added the new magic numbers for atiixp and au88x0 drivers. # -------------------------------------------- # 04/03/13 perex@suse.cz 1.1614.4.22 # ALSA CVS update - Takashi Iwai # ALSA Core # fixed the wrong release of id proc file. # -------------------------------------------- # 04/03/13 James.Bottomley@steeleye.com 1.1623 # [PATCH] Fix removable USB drive oops # # The actual problem reported was because there wasn't a corresponding # check on transport_classdev.class in the unregister. # # However, on closer inspection I also turned up a nasty thinko in the # reference counting. For reasons best known to the class code authors, # class devices have to obtain their own references to the devices they're # attached to which they release again in their .release routines, so you # have to remember to do a get_device() in the correct place after the # class_device_add(). I put comments in the code so that, hopefully, we # can avoid the problem in future. # -------------------------------------------- # 04/03/13 wim@iguana.be 1.1614.1.3 # [WATCHDOG] v2.6.4 pcwd_pci-v1.00_20040313-patch # # Two small fixes: # * Make cards_found a global variable so that if we remove the # pci device we can count down. # * If we can't find a correct I/O address for the card, then we # should disable the card again. # -------------------------------------------- # 04/03/13 wim@iguana.be 1.1614.1.4 # WATCHDOG] v2.6.4 wdt977-v0.03-patch # # Version 0.03 of wdt977.c - Changes that were made are: # * Extract the stop code in a seperate function (wdt977_stop) # * Extract the start code in a seperate function (wdt977_start) # * Rename kick_wdog to wdt977_keepalive for consistency # * Extract the watchdog's status code to a seperate function (wdt977_get_status) # * Change the way we deal with the watchdog timeout: # Up till now we used timeoutM (in minutes) as the correct value and then # calculated timeout as being timeoutM*60 or *timeoutM*120 (depending on # wether or not we have the netwinder hardware bug). # # From now on timeout is the correct value and we calculate timeoutM out # of it. Because of this we start with checking wether or not we have a # correct timeout value (if not we reset it to the default value) and we # automatically calculate timeoutM. Each time we change timeout with a # correct timeout value, we recalculate timeoutM. # * Extended ioctl code with WDIOC_SETOPTIONS and updated the watchdog_info structure # * Added notifier support # # Code has been tested by Woody # -------------------------------------------- # 04/03/13 wim@iguana.be 1.1614.1.5 # [WATCHDOG] v2.6.4 notifier_block-patches # # Remove unnecessary initialization in notifier_block # -------------------------------------------- # 04/03/13 trond.myklebust@fys.uio.no 1.1614.5.1 # NFSv2/v3/v4: New attribute revalidation code that no # longer relies on ctime for correctness in avoiding # update races. # # VFS: allow filesystems to disable inode_update_time() on # a per-inode basis. # -------------------------------------------- # 04/03/13 trond.myklebust@fys.uio.no 1.1614.5.2 # NFSv2/v3/v4: New file writeout strategy. Defer writes until a flush # is requested by the application (or memory pressure). # -------------------------------------------- # 04/03/13 trond.myklebust@fys.uio.no 1.1614.5.3 # Configuration: simplify configuration options. Automatically select RPCSEC_GSS # if NFSv4 is selected. Remove need for user to select SUNRPC_GSS, and the # crypto options. # Make NFSv3 a recommended option. # -------------------------------------------- # 04/03/13 trond.myklebust@fys.uio.no 1.1614.5.4 # NFSv2/v3: Ensure that we only use GETATTR+STATFS (NFSv2) and FSINFO (NFSv3) when # mounting. This should allow us to use AUTH_SYS credentials when mounting, # (even when the user requests RPCSEC_GSS authentication) due to the hack # described in RFC2623. # # Remove the broken NFS_INO_FAKE_ROOT hack. # -------------------------------------------- # 04/03/13 trond.myklebust@fys.uio.no 1.1614.5.5 # NFSv2/v3/v4: Ensure that fsync() flushes all writebacks to disk rather than just the # ones labelled as belonging to our file. This fixes a bug in which msync(MS_SYNC) # will fail to flush the pages to disk. # -------------------------------------------- # 04/03/13 trond.myklebust@fys.uio.no 1.1614.5.6 # NFSv2/v3/v4: A patch by Greg Banks that fixes the "VFS: Busy inodes after unmount." # problem. # -------------------------------------------- # 04/03/13 trond.myklebust@fys.uio.no 1.1614.5.7 # RPC: Make XIDs unique on a per-transport basis rather than globally unique. Gets rid # of an unnecessary global spinlock. # -------------------------------------------- # 04/03/13 trond.myklebust@fys.uio.no 1.1614.5.8 # RPC: Sync rpc_set_timeo() up to the 2.4.x version. In particular, this will # ensure that the timeout shift is clamped to a maximum value of 8. # # RPC: Fix by Olaf Kirch to the rpc scheduler to ensure sync tasks respect the # "intr" mount flag. # -------------------------------------------- # 04/03/13 trond.myklebust@fys.uio.no 1.1614.5.9 # RPC: Ensure that we have the correct capabilities when binding a socket to a reserved # port. Fixes a privilege bug when CONFIG_SECURITY is set. # RPC: When trying to reconnect to a TCP port, try to bind() to the last used port number # in order to ensure that the servers NFS replay cache recognizes this as being the # same mount as before. # -------------------------------------------- # 04/03/13 trond.myklebust@fys.uio.no 1.1614.5.10 # RPC,NFSv2/v3/v4: Ensure that xprt_create_proto() and rpc_create_client() return # full error codes. Should allow the "mount" program to print more useful error # diagnostics. # -------------------------------------------- # 04/03/13 trond.myklebust@fys.uio.no 1.1614.5.11 # NFSv2/v3/v4: Parenthesize #defines in nfs?xdr.c. Fix an off-by-one error on the value # of compound_decode_hdr_maxsz. # NFSv4: fix a printk() typo (spotted by Linda Dunaphant). # NFSv4: Ensure that nfs4_open_reclaim() copies the value of the new stateid back into # the shared nfsv4 state structure. # NFSv4: Don't leak NFS4ERR_WRONGSEC errors back into nfs_lookup(). # RPC,NFS,Lockd: Mark the debugging code as "unlikely" so that gcc moves it out of the # mainline code paths. # -------------------------------------------- # 04/03/13 trond.myklebust@fys.uio.no 1.1614.5.12 # NFSv2/v3 locking: Patch by Patrice Dumas to implement nlmsvc_proc_granted_res. # When a server receives that callback it should deallocate the corresponding blocked # lock using the nlmsvc_grant_reply function. # -------------------------------------------- # 04/03/13 trond.myklebust@fys.uio.no 1.1614.5.13 # NFSv2/v3 locking: Patch by Patrice Dumas that adds a check to ensure we really # were requesting a blocking lock when we get a reply from the server asking us to # block. # -------------------------------------------- # 04/03/13 trond.myklebust@fys.uio.no 1.1614.5.14 # NFSv2/v3 locking: Patch by Patrice Dumas to ensure that the server index blocks uniquely # by using the client address in addition to the value of the NLM cookie field. # -------------------------------------------- # 04/03/13 trond.myklebust@fys.uio.no 1.1614.5.15 # NFSv2/v3 locking: A patch to ensure that blocks which are not going to time out # are placed last on the ordered list nlm_block (problem reported by Olaf # Kirch). # -------------------------------------------- # 04/03/13 trond.myklebust@fys.uio.no 1.1614.5.16 # RPC,NFSv3: remove the redundant "memset()" in call_encode(). Fix up the only places # where this causes a padding error: xdr_encode_fhandle() and unx_marshal() # -------------------------------------------- # 04/03/13 trond.myklebust@fys.uio.no 1.1614.5.17 # RPC: patch by Chuck Lever to make the number of RPC slots a tunable parameter. # This is wanted in order to allow the NFS client to send more requests before # is has to block and wait for replies. # This is mainly useful if you have a WAN and want to ensure that the bandwidth # is being used efficiently. # -------------------------------------------- # 04/03/13 trond.myklebust@fys.uio.no 1.1614.5.18 # NFSv2: Fix up NFSv2 reads so that they report when the server returned a short # read due to EOF. # -------------------------------------------- # 04/03/13 trond.myklebust@fys.uio.no 1.1614.5.19 # NFSv4: Fix a list corruption in the NFSv4 state engine. # -------------------------------------------- # 04/03/13 trond.myklebust@fys.uio.no 1.1614.5.20 # NFS: From the suse kenrel RPM: handle ENOMEM from nfs_fhget(). # -------------------------------------------- # 04/03/13 trond.myklebust@fys.uio.no 1.1614.5.21 # From: # # Forward-port from 2.4: # # The following patch pulls an NFS server IP address off root_server_path # (handed out via the DHCP root-path option), if it is present. For example, # you can do this sort of thing in dhcpd.conf: # # root-path = 192.168.1.33:/tftpboot/yip.zImage # # This lets you mount your root filesystem off a different machine than you # booted from, without needing to use kernel command-line parameters. # # The patch appears to be backwards compatible. # # RFC2132 says this about the root-path option: # # This option specifies the path-name that contains the client's root # disk. The path is formatted as a character string consisting of # characters from the NVT ASCII character set. # # This is sufficiently vague to allow the path-name to include an IP-address. # Also, I found some documentation for FreeBSD saying it does this too, so it # must be right, because those FreeBSD guys are really smart... :-) # # The only downside of the patch is that the summary that ipconfig prints can # be a little odd when the kernel command line overrides whatever ipconfig gets # from (say) DHCP. The address from the kernel command line seems to get # stripped off early, so ipconfig reports it, but it doesn't report the kernel # command line NFS path, since that's handled a bit later... This small # cosmetic problem looks difficult to "fix" without rewriting quite a bit of # stuff... # -------------------------------------------- # 04/03/13 trond.myklebust@fys.uio.no 1.1614.5.22 # akpm@odsl.org: For complex reasons it is not possible to hold i_sem in nfs_update_inode(). # Hence the i_size_write() in there is deadlocky. Go back to the old way. # -------------------------------------------- # 04/03/13 trond.myklebust@fys.uio.no 1.1614.1.6 # Merge http://nfsclient.bkbits.net/linux-2.5 # into fys.uio.no:/home/linux/bitkeeper/nfsclient-2.5 # -------------------------------------------- # 04/03/13 akpm@osdl.org 1.1614.6.1 # [PATCH] ppc64: fix NUMA compile with large cpumasks # # From: Anton Blanchard # # The recent NUMA changes fail to compile with large cpumasks, we need to use # a temporary to get around the type checking. # -------------------------------------------- # 04/03/13 akpm@osdl.org 1.1614.6.2 # [PATCH] Use 64-bit counters for scheduler stats # # From: Kingsley Cheung # # A number of scheduler counters wrap around after 47 days. The context-switch # counter can wrap around after considerably less time. # # Convert them to 64-bit values. # -------------------------------------------- # 04/03/13 akpm@osdl.org 1.1614.6.3 # [PATCH] Manfred's patch to distribute boot allocations across nodes # # From: Anton Blanchard # # Distribute boot time memory allocations across all nodes, from Manfred # Spraul. # # We want to spread memory across nodes to avoid all allocations ending # up on node 0. # # Spreading boot time allocations around also helps us to avoid node 0 # becoming the hot node. # # I took it for a spin: # # buddyinfo before: # Node 7, 0 2 1 1 0 2 1 2 1 2 1 2 741 # Node 6, 0 0 0 2 0 2 1 1 2 2 2 2 1002 # Node 5, 0 0 0 2 0 2 1 2 1 2 2 2 2006 # Node 4, 0 0 0 2 0 2 1 2 1 2 2 2 2006 # Node 3, 0 0 0 2 0 2 1 2 1 2 2 2 2006 # Node 2, 0 0 0 2 0 2 1 2 1 2 2 2 2006 # Node 1, 0 0 0 2 0 2 1 1 2 2 2 2 1002 # Node 0, 0 0 38 7 0 1 1 1 0 0 0 0 1998 # # buddyinfo after: # Node 7, 0 1 0 1 1 1 1 0 0 0 1 2 738 # Node 6, 0 1 0 1 1 1 0 1 0 0 2 2 1002 # Node 5, 0 0 0 1 1 1 1 0 0 0 2 2 2006 # Node 4, 0 1 0 1 0 1 1 0 0 0 2 2 2006 # Node 3, 0 0 0 1 0 1 1 0 0 0 2 2 2005 # Node 2, 0 1 0 0 0 0 0 1 0 0 2 2 2006 # Node 1, 0 2 1 1 0 1 1 1 0 0 2 2 1002 # Node 0, 0 20 45 8 3 0 1 1 1 1 0 1 2004 # # Change in free memory due to patch: # # Node 7 -54.08 MB # Node 6 -6.33 MB # Node 5 -6.09 MB # Node 4 -6.14 MB # Node 3 -22.15 MB # Node 2 -6.05 MB # Node 1 -6.12 MB # Node 0 107.35 MB # # As you can see we gained over 100MB on node 0. # -------------------------------------------- # 04/03/13 akpm@osdl.org 1.1614.6.4 # [PATCH] further __KERNEL_SYSCALLS__ removal # # From: Arnd Bergmann # # Dave Jones already removed some of the useless __KERNEL_SYSCALLS__ defines # in various files, this gets rid of almost all the others. Replacing # execve() is nontrivial, so I left those in for now. # # For all the other system calls that are currently used from inside the # kernel, calling the sys_* function directly should always have an identical # effect. # -------------------------------------------- # 04/03/13 akpm@osdl.org 1.1614.6.5 # [PATCH] use wait_task_inactive() in kthread_bind() # # From: Rusty Russell # # Make it clear that the reason we do wait_task_inactive is because # kthread_bind frobs with k->thread_info->cpu, which is only legal because # the task is definitely not running. # # We can't use the normal migration thread code here, because it doesn't let # us bind to cpus which are offline yet, and also because we use this to # start the migration threads themselves. # -------------------------------------------- # 04/03/13 akpm@osdl.org 1.1614.6.6 # [PATCH] md: use "shedule_timeout()" instead of yield() # # From: NeilBrown # # Use "shedule_timeout()" instead of yield() as it seems to wait for less # time. # -------------------------------------------- # 04/03/13 akpm@osdl.org 1.1614.6.7 # [PATCH] md: allow assembling of partitioned arrays at boot time. # # From: NeilBrown # # kernel parameters: # # raid=partitionable # will make all auto-detected md arrays partitionable # # md=d.... # will assemble an array as a partitionable array. # -------------------------------------------- # 04/03/13 akpm@osdl.org 1.1614.6.8 # [PATCH] Work around an AMD768MPX erratum # # From: Andi Kleen # # This patch has been in the SuSE 2.4 kernel forever, but for some reason # never made it mainline. # # It works around the infamous "only works stable when a mouse is plugged in" # problem some AMD 768MPX Dual Athlon chipsets have. The problem happens # because the chipset can hang when PCI prefetch strides from a RAM page into # the VGA text buffer. When a PS2 mouse is plugged in the BIOS reserves a # page before the VGA text buffer, which stops the prefetch early. # # This patch always reserves this page when the chipset could be AMD768MPX. # This can be only done early in bootmem setup. Because it's difficult to # scan the PCI bus that early it just always reserves this page when the CPU # is an Athlon. Normally it should not make a difference because the BIOS # will have reserved that page anyways when a PS/2 mouse is plugged in. # -------------------------------------------- # 04/03/13 trond.myklebust@fys.uio.no 1.1614.1.7 # Merge http://nfsclient.bkbits.net/linux-2.5 # into fys.uio.no:/home/linux/bitkeeper/nfsclient-2.5 # -------------------------------------------- # 04/03/14 James.Bottomley@steeleye.com 1.1624 # [PATCH] Add Domain Validation to 53c700 driver # # This simply throws out the 53c700 driver's optimistic setting of the # best possible transport parameters and replaces it with DV # determination. It also adds a missing report_bus_reset() callback and # finally does a delayed DV on device errors. # -------------------------------------------- # 04/03/14 akpm@osdl.org 1.1614.6.9 # [PATCH] DMA: Fill gaping hole in DMA API interfaces. # # From: "David S. Miller" # # Currently, for an existing DMA mapping, there is a way to transfer buffer # ownership back to the cpu, yet there is no way to give it back to the device # again explicitly. The latter really is needed on platforms where the PCI # subsystem does not snoop the cpu caches, MIPS is one example. # # Many drivers were expecting the existing DMA sync interface to handle both # directions, which was wrong. # # Now, with this change, we have explicit interfaces for DMA syncing to/from # the device and the cpu. # -------------------------------------------- # 04/03/14 akpm@osdl.org 1.1614.6.10 # [PATCH] module unload deadlock fix # # From: Rusty Russell # # From: Andrea Arcangeli # # We should drop module sem before calling mod->exit, for practical reasons: # too many module exit functions oops or hang, resulting in a permenantly held # module sem, which blocks all module ops including lsmod. # -------------------------------------------- # 04/03/14 akpm@osdl.org 1.1614.6.11 # [PATCH] gcc-3.5 libata build fix # # drivers/scsi/sata_vsc.c: In function `vsc_sata_interrupt': # include/linux/libata.h:414: sorry, unimplemented: inlining failed in call to 'ata_host_intr': function body not available # drivers/scsi/sata_vsc.c:187: sorry, unimplemented: called from here # -------------------------------------------- # 04/03/14 torvalds@ppc970.osdl.org 1.1625 # Merge bk://linux-scsi.bkbits.net/scsi-for-linus-2.6 # into ppc970.osdl.org:/home/torvalds/v2.5/linux # -------------------------------------------- # 04/03/14 torvalds@ppc970.osdl.org 1.1626 # Merge bk://linux-acpi.bkbits.net/linux-acpi-release-2.6.5 # into ppc970.osdl.org:/home/torvalds/v2.5/linux # -------------------------------------------- # 04/03/14 torvalds@ppc970.osdl.org 1.1627 # Merge http://linux-sound.bkbits.net/linux-sound # into ppc970.osdl.org:/home/torvalds/v2.5/linux # -------------------------------------------- # 04/03/14 willy@debian.org 1.1628 # [PATCH] PA-RISC update # # Updates for 2.6.4 for PARISC: # # - defconfigs (Randolph Chung) # - copyright updates (Grant Grundler) # - Fix DOS hole in sys_clone (James Bottomley) # - missing hardware ID (Andy Walker) # - disable interrupts during cache-flushes (LaMont Jones) # - Fix crash on machines with <256MB ram (Randolph Chung) # - Make SuckyIO IDE work better (Randolph Chung) # - Align data_start so the extable is writable (Randolph Chung) # - Extensive rewrite of virtual merging code (James Bottomley) # - Fix EISA, non-PCI module builds (Matthew Wilcox) # - Fix Elroy PCI config space byte & word writes (Grant Grundler) # - Eliminate a warning in parport_gsc (Helge Deller) # - Fix endian problem with ide mmio macros (Randolph Chung) # - Delete asm/keyboard.h (Matthew Wilcox) # - Delete asm/md.h (Grant Grundler) # - Eliminate a warning in ALSA harmony (Matthew Wilcox) # -------------------------------------------- # 04/03/14 trond.myklebust@fys.uio.no 1.1629 # Merge http://nfsclient.bkbits.net/linux-2.5 # into fys.uio.no:/home/linux/bitkeeper/nfsclient-2.5 # -------------------------------------------- # 04/03/14 akpm@osdl.org 1.1628.1.1 # [PATCH] move consistent_dma_mask to the generic device # # From: James Bottomley # # pci_dev.consistent_dma_mask was introduced to get around problems in the # IA64 Altix machine. # # Now, we have a use for it in x86: the aacraid needs coherent memory in a # 31 bit address range (2GB). Unfortunately, x86 is converted to the dma # model, so it can't see the pci_dev by the time coherent memory is # allocated. # # The solution to all of this is to move pci_dev.consistent_dma_mask to # dev.coherent_dma_mask and make x86 use it in the dma_alloc_coherent() # calls. # # This should allow me to make the aacraid set the coherent mask instead # of using it's current dma_mask juggling. # -------------------------------------------- # 04/03/14 akpm@osdl.org 1.1628.1.2 # [PATCH] s390: update for altered page_state structure # # From: Olaf Hering # # This patch is needed on s390. # -------------------------------------------- # 04/03/14 akpm@osdl.org 1.1628.1.3 # [PATCH] __kill_pg_info() return value fix # # Fix a bug which was spotted by Alex Lyashkov # # The fairly unobvious coding in __kill_pg_info() will cause a zero value to be # incorrectly returned if the second or succeeding call to # group_send_sig_info() returns an error. # -------------------------------------------- # 04/03/14 James.Bottomley@SteelEye.com 1.1628.1.4 # [PATCH] Fix voyager to boot again # # The very early memory detection patch broke voyager. # # This fixes it again. # -------------------------------------------- # 04/03/14 torvalds@ppc970.osdl.org 1.1630 # Merge http://nfsclient.bkbits.net/linux-2.5 # into ppc970.osdl.org:/home/torvalds/v2.5/linux # -------------------------------------------- # diff -Nru a/CREDITS b/CREDITS --- a/CREDITS Sun Mar 14 14:20:08 2004 +++ b/CREDITS Sun Mar 14 14:20:08 2004 @@ -975,8 +975,7 @@ E: bfennema@falcon.csc.calpoly.edu W: http://www.csc.calpoly.edu/~bfennema D: UDF filesystem -S: 21760 Irma Lyle Drive -S: Los Gatos, CA 95033-8942 +S: (ask for current address) S: USA N: Jürgen Fischer diff -Nru a/Documentation/DMA-mapping.txt b/Documentation/DMA-mapping.txt --- a/Documentation/DMA-mapping.txt Sun Mar 14 14:20:07 2004 +++ b/Documentation/DMA-mapping.txt Sun Mar 14 14:20:07 2004 @@ -283,7 +283,7 @@ in order to get correct behavior on all platforms. - Streaming DMA mappings which are usually mapped for one DMA transfer, - unmapped right after it (unless you use pci_dma_sync below) and for which + unmapped right after it (unless you use pci_dma_sync_* below) and for which hardware can optimize for sequential accesses. This of "streaming" as "asynchronous" or "outside the coherency @@ -543,14 +543,30 @@ all bus addresses. If you need to use the same streaming DMA region multiple times and touch -the data in between the DMA transfers, just map it with -pci_map_{single,sg}, and after each DMA transfer call either: +the data in between the DMA transfers, the buffer needs to be synced +properly in order for the cpu and device to see the most uptodate and +correct copy of the DMA buffer. - pci_dma_sync_single(dev, dma_handle, size, direction); +So, firstly, just map it with pci_map_{single,sg}, and after each DMA +transfer call either: + + pci_dma_sync_single_for_cpu(dev, dma_handle, size, direction); or: - pci_dma_sync_sg(dev, sglist, nents, direction); + pci_dma_sync_sg_for_cpu(dev, sglist, nents, direction); + +as appropriate. + +Then, if you wish to let the device get at the DMA area again, +finish accessing the data with the cpu, and then before actually +giving the buffer to the hardware call either: + + pci_dma_sync_single_for_device(dev, dma_handle, size, direction); + +or: + + pci_dma_sync_sg_for_device(dev, sglist, nents, direction); as appropriate. @@ -590,8 +606,9 @@ * the DMA transfer with the CPU first * so that we see updated contents. */ - pci_dma_sync_single(cp->pdev, cp->rx_dma, cp->rx_len, - PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(cp->pdev, cp->rx_dma, + cp->rx_len, + PCI_DMA_FROMDEVICE); /* Now it is safe to examine the buffer. */ hp = (struct my_card_header *) cp->rx_buf; @@ -601,7 +618,13 @@ pass_to_upper_layers(cp->rx_buf); make_and_setup_new_rx_buf(cp); } else { - /* Just give the buffer back to the card. */ + /* Just sync the buffer and give it back + * to the card. + */ + pci_dma_sync_single_for_device(cp->pdev, + cp->rx_dma, + cp->rx_len, + PCI_DMA_FROMDEVICE); give_rx_buf_to_card(cp); } } @@ -709,12 +732,21 @@ When the DMA transfer is complete, invoke: - void pci_dac_dma_sync_single(struct pci_dev *pdev, - dma64_addr_t dma_addr, - size_t len, int direction); + void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, + dma64_addr_t dma_addr, + size_t len, int direction); This must be done before the CPU looks at the buffer again. -This interface behaves identically to pci_dma_sync_{single,sg}(). +This interface behaves identically to pci_dma_sync_{single,sg}_for_cpu(). + +And likewise, if you wish to let the device get back at the buffer after +the cpu has read/written it, invoke: + + void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, + dma64_addr_t dma_addr, + size_t len, int direction); + +before letting the device access the DMA area again. If you need to get back to the PAGE/OFFSET tuple from a dma64_addr_t the following interfaces are provided: diff -Nru a/Documentation/devices.txt b/Documentation/devices.txt --- a/Documentation/devices.txt Sun Mar 14 14:20:07 2004 +++ b/Documentation/devices.txt Sun Mar 14 14:20:07 2004 @@ -2046,6 +2046,21 @@ 1 = /dev/gpib1 Second GPIB bus ... +160 block Carmel 8-port SATA Disks on First Controller + 0 = /dev/carmel/0 SATA disk 0 whole disk + 1 = /dev/carmel/0p1 SATA disk 0 partition 1 + ... + 31 = /dev/carmel/0p31 SATA disk 0 partition 31 + + 32 = /dev/carmel/1 SATA disk 1 whole disk + 64 = /dev/carmel/2 SATA disk 2 whole disk + ... + 224 = /dev/carmel/7 SATA disk 7 whole disk + + Partitions are handled in the same way as for IDE + disks (see major number 3) except that the limit on + partitions is 31. + 161 char IrCOMM devices (IrDA serial/parallel emulation) 0 = /dev/ircomm0 First IrCOMM device 1 = /dev/ircomm1 Second IrCOMM device @@ -2053,6 +2068,21 @@ 16 = /dev/irlpt0 First IrLPT device 17 = /dev/irlpt1 Second IrLPT device ... + +161 block Carmel 8-port SATA Disks on Second Controller + 0 = /dev/carmel/8 SATA disk 8 whole disk + 1 = /dev/carmel/8p1 SATA disk 8 partition 1 + ... + 31 = /dev/carmel/8p31 SATA disk 8 partition 31 + + 32 = /dev/carmel/9 SATA disk 9 whole disk + 64 = /dev/carmel/10 SATA disk 10 whole disk + ... + 224 = /dev/carmel/15 SATA disk 15 whole disk + + Partitions are handled in the same way as for IDE + disks (see major number 3) except that the limit on + partitions is 31. 162 char Raw block device interface 0 = /dev/rawctl Raw I/O control device diff -Nru a/Documentation/filesystems/udf.txt b/Documentation/filesystems/udf.txt --- a/Documentation/filesystems/udf.txt Sun Mar 14 14:20:08 2004 +++ b/Documentation/filesystems/udf.txt Sun Mar 14 14:20:08 2004 @@ -1,7 +1,7 @@ * * ./Documentation/filesystems/udf.txt * -UDF Filesystem version 0.9.5 +UDF Filesystem version 0.9.8.1 If you encounter problems with reading UDF discs using this driver, please report them to linux_udf@hpesjro.fc.hp.com, which is the @@ -16,7 +16,7 @@ gid= Set the default group. umask= Set the default umask. uid= Set the default user. - bs= Set the block size. + bs= Set the block size. unhide Show otherwise hidden files. undelete Show deleted files in lists. adinicb Embed data in the inode (default) @@ -47,15 +47,11 @@ ------------------------------------------------------------------------------- -For more information see: - http://www.trylinux.com/projects/udf/index.html - For the latest version and toolset see: - http://www.csc.calpoly.edu/~bfennema/udf.html http://linux-udf.sourceforge.net/ Documentation on UDF and ECMA 167 is available FREE from: - http://www.osta.org/ - http://www.ecma.ch/ + http://www.osta.org/ + http://www.ecma-international.org/ Ben Fennema diff -Nru a/Documentation/filesystems/ufs.txt b/Documentation/filesystems/ufs.txt --- a/Documentation/filesystems/ufs.txt Sun Mar 14 14:20:08 2004 +++ b/Documentation/filesystems/ufs.txt Sun Mar 14 14:20:08 2004 @@ -20,6 +20,9 @@ 44bsd used in FreeBSD, NetBSD, OpenBSD supported os read-write + ufs2 used in FreeBSD 5.x + supported os read-only + sun used in SunOS (Solaris) supported as read-write diff -Nru a/Documentation/i386/zero-page.txt b/Documentation/i386/zero-page.txt --- a/Documentation/i386/zero-page.txt Sun Mar 14 14:20:06 2004 +++ b/Documentation/i386/zero-page.txt Sun Mar 14 14:20:06 2004 @@ -75,7 +75,7 @@ 0x2cc 4 bytes DISK80_SIG_BUFFER (setup.S) 0x2d0 - 0x600 E820MAP 0x600 - 0x7ff EDDBUF (setup.S) for disk signature read sector -0x600 - 0x7d3 EDDBUF (setup.S) for edd data +0x600 - 0x7eb EDDBUF (setup.S) for edd data 0x800 string, 2K max COMMAND_LINE, the kernel commandline as copied using CL_OFFSET. diff -Nru a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt --- a/Documentation/kernel-parameters.txt Sun Mar 14 14:20:09 2004 +++ b/Documentation/kernel-parameters.txt Sun Mar 14 14:20:09 2004 @@ -116,6 +116,10 @@ acpi_irq_isa= [HW,ACPI] If irq_balance, Mark listed IRQs used by ISA Format: ,... + acpi_osi= [HW,ACPI] empty param disables _OSI + + acpi_serialize [HW,ACPI] force serialization of AML methods + ad1816= [HW,OSS] Format: ,,, See also Documentation/sound/oss/AD1816. diff -Nru a/Documentation/networking/netconsole.txt b/Documentation/networking/netconsole.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/networking/netconsole.txt Sun Mar 14 14:20:09 2004 @@ -0,0 +1,57 @@ + +started by Ingo Molnar , 2001.09.17 +2.6 port and netpoll api by Matt Mackall , Sep 9 2003 + +Please send bug reports to Matt Mackall + +This module logs kernel printk messages over UDP allowing debugging of +problem where disk logging fails and serial consoles are impractical. + +It can be used either built-in or as a module. As a built-in, +netconsole initializes immediately after NIC cards and will bring up +the specified interface as soon as possible. While this doesn't allow +capture of early kernel panics, it does capture most of the boot +process. + +It takes a string configuration parameter "netconsole" in the +following format: + + netconsole=[src-port]@[src-ip]/[],[tgt-port]@/[tgt-macaddr] + + where + src-port source for UDP packets (defaults to 6665) + src-ip source IP to use (interface address) + dev network interface (eth0) + tgt-port port for logging agent (6666) + tgt-ip IP address for logging agent + tgt-macaddr ethernet MAC address for logging agent (broadcast) + +Examples: + + linux netconsole=4444@10.0.0.1/eth1,9353@10.0.0.2/12:34:56:78:9a:bc + + or + + insmod netconsole netconsole=@/,@10.0.0.2/ + +Built-in netconsole starts immediately after the TCP stack is +initialized and attempts to bring up the supplied dev at the supplied +address. + +The remote host can run either 'netcat -u -l -p ' or syslogd. + +WARNING: the default target ethernet setting uses the broadcast +ethernet address to send packets, which can cause increased load on +other systems on the same ethernet segment. + +NOTE: the network device (eth1 in the above case) can run any kind +of other network traffic, netconsole is not intrusive. Netconsole +might cause slight delays in other traffic if the volume of kernel +messages is high, but should have no other impact. + +Netconsole was designed to be as instantaneous as possible, to +enable the logging of even the most critical kernel bugs. It works +from IRQ contexts as well, and does not enable interrupts while +sending packets. Due to these unique needs, configuration can not +be more automatic, and some fundamental limitations will remain: +only IP networks, UDP packets and ethernet devices are supported. diff -Nru a/Documentation/scsi/st.txt b/Documentation/scsi/st.txt --- a/Documentation/scsi/st.txt Sun Mar 14 14:20:06 2004 +++ b/Documentation/scsi/st.txt Sun Mar 14 14:20:06 2004 @@ -2,7 +2,7 @@ The driver is currently maintained by Kai Mäkisara (email Kai.Makisara@kolumbus.fi) -Last modified: Thu Feb 19 21:57:30 2004 by makisara +Last modified: Wed Feb 25 14:09:08 2004 by makisara BASICS @@ -36,8 +36,9 @@ manager. The changes persist until the defaults again come into effect. -3. Up to four modes can be defined and selected using the minor number -(bits 5 and 6). Mode 0 corresponds to the defaults discussed +3. By default, up to four modes can be defined and selected using the minor +number (bits 5 and 6). The number of modes can be changed by changing +ST_NBR_MODE_BITS in st.h. Mode 0 corresponds to the defaults discussed above. Additional modes are dormant until they are defined by the system manager (root). When specification of a new mode is started, the configuration of mode 0 is used to provide a starting point for @@ -107,7 +108,7 @@ dev_upper non-rew mode dev-lower 20 - 8 7 6 5 4 0 The non-rewind bit is always bit 7 (the uppermost bit in the lowermost -byte). The bits defining the mode are next to the non-rewind bits. The +byte). The bits defining the mode are below the non-rewind bit. The remaining bits define the tape device number. This numbering is backward compatible with the numbering used when the minor number was only 8 bits wide. @@ -117,10 +118,10 @@ The driver creates the directory /sys/class/scsi_tape and populates it with directories corresponding to the existing tape devices. There are autorewind -and non-rewind entries for each mode. The names are stxmy and stxmyn, where x -is the tape number and y is the mode. For example, the directories for the -first tape device are (assuming four modes): st0m0 st0m0n st0m1 st0m1n -st0m2 st0m2n st0m3 st0m3n. +and non-rewind entries for each mode. The names are stxy and nstxy, where x +is the tape number and y a character corresponding to the mode (none, l, m, +a). For example, the directories for the first tape device are (assuming four +modes): st0 nst0 st0l nst0l st0m nst0m st0a nst0a. Each directory contains the entries: default_blksize default_compression default_density defined dev device driver. The file 'defined' contains 1 @@ -130,7 +131,7 @@ 'device' and 'driver' point to the SCSI device and driver entries. A link named 'tape' is made from the SCSI device directory to the class -directory corresponding to the mode 0 auto-rewind device (e.g., st0m0). +directory corresponding to the mode 0 auto-rewind device (e.g., st0). BSD AND SYS V SEMANTICS diff -Nru a/Documentation/scsi/sym53c8xx_2.txt b/Documentation/scsi/sym53c8xx_2.txt --- a/Documentation/scsi/sym53c8xx_2.txt Sun Mar 14 14:20:06 2004 +++ b/Documentation/scsi/sym53c8xx_2.txt Sun Mar 14 14:20:06 2004 @@ -567,7 +567,7 @@ nvram:n do not look for serial NVRAM nvram:y test controllers for onboard serial NVRAM (alternate binary form) - mvram= + nvram= 0x01 look for NVRAM (equivalent to nvram=y) 0x02 ignore NVRAM "Synchronous negotiation" parameters for all devices 0x04 ignore NVRAM "Wide negotiation" parameter for all devices @@ -661,7 +661,7 @@ The 'nvram' boot option can be entered in hexadecimal form in order to ignore some options configured in the NVRAM, as follow: -mvram= +nvram= 0x01 look for NVRAM (equivalent to nvram=y) 0x02 ignore NVRAM "Synchronous negotiation" parameters for all devices 0x04 ignore NVRAM "Wide negotiation" parameter for all devices diff -Nru a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt --- a/Documentation/sound/alsa/ALSA-Configuration.txt Sun Mar 14 14:20:06 2004 +++ b/Documentation/sound/alsa/ALSA-Configuration.txt Sun Mar 14 14:20:06 2004 @@ -112,7 +112,8 @@ - value is used for /proc/asound filesystem - this value can be used by applications for identification of card if user does not want identify card with index number - enable - enable card (only first card is enabled by default) + enable - enable card. (all cards enabled for PCI and ISA PnP cards + as default.) Module snd-ad1816a ------------------ @@ -178,6 +179,42 @@ Module supports up to 8 cards, autoprobe and PnP. + Module snd-atiixp + ----------------- + + Module for ATI IXP 150/200/250 AC97 controllers. + + ac97_clock - AC'97 clock (defalut = 48000) + spdif_aclink - S/PDIF transfer over AC-link (default = 1) + + This module supports up to 8 cards and autoprobe. + + Module snd-au8810, snd-au8820, snd-au8830 + ----------------------------------------- + + Module for Aureal Vortex, Vortex2 and Advantage device. + + pcifix - Control PCI workarounds + 0 = Disable all workarounds + 1 = Force the PCI latency of the Aureal card to 0xff + 2 = Force the Extend PCI#2 Internal Master for Efficient + Handling of Dummy Requests on the VIA KT133 AGP Bridge + 3 = Force both settings + 255 = Autodetect what is required (default) + + This module supports all ADB PCM channels, ac97 mixer, SPDIF, hardware + EQ, mpu401, gameport. A3D and wavetable support are still in development. + Development and reverse engineering work is being coordinated at + http://savannah.nongnu.org/projects/openvortex/ + SPDIF output has a copy of the AC97 codec output, unless you use the + "spdif" pcm device, which allows raw data passthru. + The hardware EQ hardware and SPDIF is only present in the Vortex2 and + Advantage. + + Note: Some ALSA mixer applicactions don't handle the SPDIF samplerate + control correctly. If you have problems regarding this, try + another ALSA compliant mixer (alsamixer works). + Module snd-azt2320 ------------------ @@ -608,6 +645,7 @@ 1 = use headphone control as master 2 = swap headphone and master controls 3 = for AD1985, turn on OMS bit and use headphone + 4 = for ALC65x, turn on the jack sense mode Module supports autoprobe and multiple bus-master chips (max 8). @@ -627,6 +665,15 @@ The power-management is supported. + Module snd-intel8x0m + -------------------- + + Module for Intel ICH (i8x0) chipset MC97 modems. + + ac97_clock - AC'97 codec clock base (0 = auto-detect) + + This module supports up to 8 cards and autoprobe. + Module snd-interwave -------------------- @@ -692,6 +739,15 @@ The power-management is supported. + Module snd-mixart + ----------------- + + Module for Digigram miXart8 soundcards. + + Module supports multiple cards. + Note: One miXart8 board will be represented as 4 alsa cards. + See MIXART.txt for details. + Module snd-mpu401 ----------------- @@ -1169,6 +1225,16 @@ Module supports autoprobe and multiple chips (max 8). The power-management is supported. + + Module snd-pdaudiocf + -------------------- + + Module for Sound Core PDAudioCF soundcard. + + irq_mask - IRQ mask (PCMCIA type) + irq_list - List of available interrupts for this soundcard + + Note: the driver is build only when CONFIG_ISA is set. Configuring Non-ISAPNP Cards diff -Nru a/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl b/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl --- a/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl Sun Mar 14 14:20:06 2004 +++ b/Documentation/sound/alsa/DocBook/alsa-driver-api.tmpl Sun Mar 14 14:20:06 2004 @@ -49,7 +49,6 @@ !Esound/core/memory.c !Iinclude/sound/sndmagic.h !Esound/core/memalloc.c -!Esound/core/sgbuf.c PCM API @@ -71,6 +70,7 @@ AC97 Codec API !Esound/pci/ac97/ac97_codec.c +!Esound/pci/ac97/ac97_pcm.c MIDI API diff -Nru a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl --- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl Sun Mar 14 14:20:06 2004 +++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl Sun Mar 14 14:20:06 2004 @@ -18,8 +18,8 @@ - Mar. 26, 2003 - 0.3 + Mar. 6, 2004 + 0.3.1 @@ -30,7 +30,7 @@ - Copyright (c) 2002, 2003 Takashi Iwai tiwai@suse.de + Copyright (c) 2002-2004 Takashi Iwai tiwai@suse.de @@ -111,18 +111,18 @@ One is the the trees provided as a tarball or via cvs from the - ALSA's ftp site, and another is the 2.5 (or later) Linux kernel + ALSA's ftp site, and another is the 2.6 (or later) Linux kernel tree. To synchronize both, the ALSA driver tree is split to two different trees: alsa-kernel and alsa-driver. The former - contains purely the source codes for the Linux 2.5 (or later) - tree. This tree is designed only for compilation on 2.5 or + contains purely the source codes for the Linux 2.6 (or later) + tree. This tree is designed only for compilation on 2.6 or later environment. The latter, alsa-driver, contains many subtle files for compiling the ALSA driver on the outside of Linux kernel like configure script, the wrapper functions for older, 2.2 and 2.4 kernels, to adapt the latest kernel API, and additional drivers which are still in development or in tests. The drivers in alsa-driver tree will be moved to - alsa-kernel (eventually 2.5 kernel tree) once when they are + alsa-kernel (eventually 2.6 kernel tree) once when they are finished and confirmed to work fine. @@ -346,7 +346,7 @@
oss directory - The OSS/Lite source files are stored here on Linux 2.5 (or + The OSS/Lite source files are stored here on Linux 2.6 (or later) tree. (In the ALSA driver tarball, it's empty, of course :)
@@ -1815,7 +1815,7 @@ Oh, one thing was forgotten. If you have no exported symbols, - you need to declare it on 2.2 or 2.4 kernels (on 2.5 kernels + you need to declare it on 2.2 or 2.4 kernels (on 2.6 kernels it's not necessary, though). @@ -2075,8 +2075,9 @@ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mychip_capture_ops); /* pre-allocation of buffers */ - snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, - 64*1024, 64*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), + 64*1024, 64*1024); return 0; } ]]> @@ -2202,8 +2203,9 @@ pci, pcm, - 64*1024, 64*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), + 64*1024, 64*1024); ]]> @@ -3769,14 +3771,20 @@ value.enumerated.items = 4; - if (uinfo->value.enumerated.item > 3) - uinfo->value.enumerated.item = 3; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); + snd_ctl_elem_info_t *uinfo) + { + static char *texts[4] = { + "First", "Second", "Third", "Fourth" + }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 4; + if (uinfo->value.enumerated.item > 3) + uinfo->value.enumerated.item = 3; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + return 0; + } ]]> @@ -4718,7 +4726,8 @@ @@ -4728,8 +4737,25 @@ size to be changed via prealloc proc file. The allocator will try to get as the large area as possible within the given size. - There are different versions of pre-allocator for different - buses. + + + + The second argument (type) and the third argument (device pointer) + are dependent on the bus. + In the case of ISA bus, pass snd_dma_isa_data() + as the third argument with SNDRV_DMA_TYPE_DEV type. + For the continuous buffer unrelated to the bus can be pre-allocated + with SNDRV_DMA_TYPE_CONTINUOUS type and the + snd_dma_continuous_data(GFP_KERNEL) device pointer, + whereh GFP_KERNEL is the kernel allocation flag to + use. For the SBUS, SNDRV_DMA_TYPE_SBUS and + snd_dma_sbus_data(sbus_dev) are used instead. + For the PCI scatter-gather buffers, use + SNDRV_DMA_TYPE_DEV_SG with + snd_dma_pci_data(pci) + (see the section + Non-Contiguous Buffers + ). @@ -4936,11 +4962,13 @@ For creating the SG-buffer handler, call - snd_pcm_lib_preallocate_sg_pages() or - snd_pcm_lib_preallocate_sg_pages_for_all() + snd_pcm_lib_preallocate_pages() or + snd_pcm_lib_preallocate_pages_for_all() + with SNDRV_DMA_TYPE_DEV_SG in the PCM constructor like other PCI pre-allocator. - You need to pass the - pci_dev struct pointer of the chip. + You need to pass the snd_dma_pci_data(pci), + where pci is the struct pci_dev pointer + of the chip as well. The snd_sg_buf_t instance is created as substream->dma_private. You can cast the pointer like: @@ -5274,7 +5302,7 @@ - For keeping the readability of 2.5 source code, it's recommended to + For keeping the readability of 2.6 source code, it's recommended to separate the above ifdef condition as the patch file in alsa-driver directory. See alsa-driver/pci/ali5451.c for example. @@ -5606,7 +5634,7 @@ tree. Then the driver is evaluated, audited and tested by developers and users. After a certain time, the driver will go to alsa-kernel tree and eventually integrated into - Linux 2.5 tree. + Linux 2.6 tree. @@ -5642,61 +5670,44 @@ - Modify alsa-driver/acore/Makefile + Create the Kconfig entry - Here define the dependent modules. + Add the new entry of Kconfig for your xyz driver. - If the driver supports PCM, snd-pcm.o, - snd-timer.o and snd-page-alloc.o - will be needed. - - - For rawmidi, snd-rawmidi.o is needed in addition. - The MIDI stuff is also related to the sequencer. - You'll need to modify alsa-driver/acore/seq/Makefile. + the line, select SND_PCM, specifies that the driver xyz supports + PCM. In addition to SND_PCM, the following components are + supported for select command: + SND_RAWMIDI, SND_TIMER, SND_HWDEP, SND_MPU401_UART, + SND_OPL3_LIB, SND_OPL4_LIB, SND_VX_LIB, SND_AC97_CODEC. + Add the select command for each supported component. - For OPL3, snd-hwdep.o is needed, too. - It's involved with the sequencer, and as well as rawmidi, - you'll need to modify alsa-driver/acore/seq/Makefile - and acore/seq/instr/Makefile in addition. - Also, a new entry is necessary in - alsa-driver/drivers/opl3/Makefile. + Note that some selections imply the lowlevel selections. + For example, PCM includes TIMER, MPU401_UART includes RAWMIDI, + AC97_CODEC includes PCM, and OPL3_LIB includes HWDEP. + You don't need to give the lowlevel selections again. - - - - Modify alsa-driver/utils/Modules.dep + For the details of Kconfig script, refer to the kbuild + documentation. - - Add the module definition for configure, here. - The beginning of the line must be a vertical bar, following - the card module name (snd-xyz) and the list of its all - dependent modules. - - - - - - - @@ -5724,7 +5735,7 @@ @@ -5739,13 +5750,13 @@ Sample Makefile for a driver xyz - Modify alsa-driver/acore/Makefile + Create the Kconfig entry This procedure is as same as in the last section. - - - - - - Modify alsa-driver/utils/Modules.dep - - - - - - - - diff -Nru a/Documentation/sound/alsa/Joystick.txt b/Documentation/sound/alsa/Joystick.txt --- a/Documentation/sound/alsa/Joystick.txt Sun Mar 14 14:20:07 2004 +++ b/Documentation/sound/alsa/Joystick.txt Sun Mar 14 14:20:07 2004 @@ -43,7 +43,8 @@ ens1370 joystick 0 = disable (default), 1 = enable ens1371 joystick_port 0 = disable (default), 1 = auto-detect, manual: 0x200, 0x208, 0x210, 0x218 - cmipci joystick 0 = disable (default), 1 = enable + cmipci joystick_port 0 = disable (default), 1 = auto-detect, + manual: any address (e.g. 0x200) cs4281 N/A N/A cs46xx N/A N/A es1938 N/A N/A diff -Nru a/Documentation/sound/alsa/MIXART.txt b/Documentation/sound/alsa/MIXART.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/sound/alsa/MIXART.txt Sun Mar 14 14:20:09 2004 @@ -0,0 +1,96 @@ + Alsa driver for Digigram miXart8 and miXart8AES/EBU soundcards + Digigram + + +GENERAL +======= + +The miXart8 is a multichannel audio processing and mixing soundcard +that has 4 stereo audio inputs and 4 stereo audio outputs. +The miXart8AES/EBU is the same with a add-on card that offers further +4 digital stereo audio inputs and outputs. +Furthermore the add-on card offers external clock synchronisation +(AES/EBU, Word Clock, Time Code and Video Synchro) + +The mainboard has a PowerPC that offers onboard mpeg encoding and +decoding, samplerate conversions and various effects. + +The driver don't work properly at all until the certain firmwares +are loaded, i.e. no PCM nor mixer devices will appear. +Use the mixartloader that can be found in the alsa-tools package. + + +VERSION 0.1.0 +============= + +One miXart8 board will be represented as 4 alsa cards, each with 1 +stereo analog capture 'pcm0c' and 1 stereo analog playback 'pcm0p' device. +With a miXart8AES/EBU there is in addition 1 stereo digital input +'pcm1c' and 1 stereo digital output 'pcm1p' per card. + +Formats +------- +U8, S16_LE, S16_BE, S24_3LE, S24_3BE, FLOAT_LE, FLOAT_BE +Sample rates : 8000 - 48000 Hz continously + +Playback +-------- +For instance the playback devices are configured to have max. 4 +substreams performing hardware mixing. This could be changed to a +maximum of 24 substreams if wished. +Mono files will be played on the left and right channel. Each channel +can be muted for each stream to use 8 analog/digital outputs seperately. + +Capture +------- +There is one substream per capture device. For instance only stereo +formats are supported. + +Mixer +----- + and : analog volume control of playback and capture PCM. + and : digital volume control of each analog substream. + and : digital volume control of each AES/EBU substream. + : Loopback from 'pcm0c' to 'pcm0p' with digital volume +and mute control. + +Rem : for best audio quality try to keep a 0 attenuation on the PCM +and AES volume controls which is set by 219 in the range from 0 to 255 +(about 86% with alsamixer) + + +NOT YET IMPLEMENTED +=================== + +- external clock support (AES/EBU, Word Clock, Time Code, Video Sync) +- MPEG audio formats +- mono record +- on-board effects and samplerate conversions +- linked streams + + +FIRMWARE +======== + +For loading the firmware automatically after the module is loaded, use +the post-install command. For example, add the following entry to +/etc/modprobe.conf for miXart driver: + + install snd-mixart /sbin/modprobe --first-time -i snd-mixart && \ + /usr/bin/mixartloader +(for 2.2/2.4 kernels, add "post-install snd-mixart /usr/bin/vxloader" to + /etc/modules.conf, instead.) + +The firmware binaries are installed on /usr/share/alsa/firmware +(or /usr/local/share/alsa/firmware, depending to the prefix option of +configure). There will be a miXart.conf file, which define the dsp image +files. + +The firmware files are copyright by Digigram SA + + +COPYRIGHT +========= + +Copyright (c) 2003 Digigram SA +Distributalbe under GPL. diff -Nru a/MAINTAINERS b/MAINTAINERS --- a/MAINTAINERS Sun Mar 14 14:20:07 2004 +++ b/MAINTAINERS Sun Mar 14 14:20:07 2004 @@ -2037,8 +2037,6 @@ UDF FILESYSTEM P: Ben Fennema M: bfennema@falcon.csc.calpoly.edu -P: Dave Boynton -M: dave@trylinux.com L: linux_udf@hpesjro.fc.hp.com W: http://linux-udf.sourceforge.net S: Maintained diff -Nru a/Makefile b/Makefile --- a/Makefile Sun Mar 14 14:20:07 2004 +++ b/Makefile Sun Mar 14 14:20:07 2004 @@ -757,26 +757,15 @@ # Any core files spread around are deleted as well # make distclean Remove editor backup files, patch leftover files and the like -# Files removed with 'make clean' -CLEAN_FILES += vmlinux System.map MC* +# Directories & files removed with 'make clean' +CLEAN_DIRS += $(MODVERDIR) include/config include2 +CLEAN_FILES += vmlinux System.map \ + include/linux/autoconf.h include/linux/version.h \ + include/asm include/linux/modversions.h \ + kernel.spec .tmp* # Files removed with 'make mrproper' -MRPROPER_FILES += \ - include/linux/autoconf.h include/linux/version.h \ - .version .config .config.old config.in config.old \ - .menuconfig.log \ - include/asm \ - .hdepend include/linux/modversions.h \ - tags TAGS cscope* kernel.spec \ - .tmp* - -# Directories removed with 'make mrproper' -MRPROPER_DIRS += \ - $(MODVERDIR) \ - .tmp_export-objs \ - include/config \ - include/linux/modules \ - include2 +MRPROPER_FILES += .version .config .config.old tags TAGS cscope* # clean - Delete all intermediate files # @@ -785,28 +774,36 @@ $(clean-dirs): $(Q)$(MAKE) $(clean)=$(patsubst _clean_%,%,$@) -quiet_cmd_rmclean = RM $$(CLEAN_FILES) -cmd_rmclean = rm -f $(CLEAN_FILES) +clean: rm-dirs := $(wildcard $(CLEAN_DIRS)) +mrproper: rm-dirs := $(wildcard $(MRPROPER_DIRS)) +quiet_cmd_rmdirs = $(if $(rm-dirs),CLEAN $(rm-dirs)) + cmd_rmdirs = rm -rf $(rm-dirs) + +clean: rm-files := $(wildcard $(CLEAN_FILES)) +mrproper: rm-files := $(wildcard $(MRPROPER_FILES)) +quiet_cmd_rmfiles = $(if $(rm-files),CLEAN $(rm-files)) + cmd_rmfiles = rm -rf $(rm-files) + clean: archclean $(clean-dirs) - $(call cmd,rmclean) + $(call cmd,rmdirs) + $(call cmd,rmfiles) @find . $(RCS_FIND_IGNORE) \ \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \ -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \) \ -type f -print | xargs rm -f -# mrproper - delete configuration + modules + core files +# mrproper # -quiet_cmd_mrproper = RM $$(MRPROPER_DIRS) + $$(MRPROPER_FILES) -cmd_mrproper = rm -rf $(MRPROPER_DIRS) && rm -f $(MRPROPER_FILES) -mrproper distclean: clean archmrproper - @echo ' Making $@ in the srctree' +distclean: mrproper +mrproper: clean archmrproper + $(call cmd,rmdirs) + $(call cmd,rmfiles) @find . $(RCS_FIND_IGNORE) \ \( -name '*.orig' -o -name '*.rej' -o -name '*~' \ -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \ -o -name '.*.rej' -o -size 0 \ -o -name '*%' -o -name '.*.cmd' -o -name 'core' \) \ -type f -print | xargs rm -f - $(call cmd,mrproper) # Generate tags for editors # --------------------------------------------------------------------------- diff -Nru a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c --- a/arch/alpha/kernel/alpha_ksyms.c Sun Mar 14 14:20:06 2004 +++ b/arch/alpha/kernel/alpha_ksyms.c Sun Mar 14 14:20:06 2004 @@ -35,9 +35,6 @@ #include #include -#define __KERNEL_SYSCALLS__ -#include - extern struct hwrpb_struct *hwrpb; extern void dump_thread(struct pt_regs *, struct user *); extern spinlock_t rtc_lock; diff -Nru a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c --- a/arch/alpha/kernel/smp.c Sun Mar 14 14:20:06 2004 +++ b/arch/alpha/kernel/smp.c Sun Mar 14 14:20:06 2004 @@ -39,9 +39,6 @@ #include #include -#define __KERNEL_SYSCALLS__ -#include - #include "proto.h" #include "irq_impl.h" diff -Nru a/arch/arm/common/sa1111-pcibuf.c b/arch/arm/common/sa1111-pcibuf.c --- a/arch/arm/common/sa1111-pcibuf.c Sun Mar 14 14:20:05 2004 +++ b/arch/arm/common/sa1111-pcibuf.c Sun Mar 14 14:20:05 2004 @@ -457,8 +457,8 @@ local_irq_restore(flags); } -void sa1111_dma_sync_single(struct device *dev, dma_addr_t dma_addr, - size_t size, enum dma_data_direction dir) +void sa1111_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_addr, + size_t size, enum dma_data_direction dir) { unsigned long flags; @@ -472,8 +472,44 @@ local_irq_restore(flags); } -void sa1111_dma_sync_sg(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction dir) +void sa1111_dma_sync_single_for_device(struct device *dev, dma_addr_t dma_addr, + size_t size, enum dma_data_direction dir) +{ + unsigned long flags; + + dev_dbg(dev, "%s(ptr=%08lx,size=%d,dir=%x)\n", + __func__, dma_addr, size, dir); + + local_irq_save(flags); + + sync_single(dev, dma_addr, size, dir); + + local_irq_restore(flags); +} + +void sa1111_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir) +{ + unsigned long flags; + int i; + + dev_dbg(dev, "%s(sg=%p,nents=%d,dir=%x)\n", + __func__, sg, nents, dir); + + local_irq_save(flags); + + for (i = 0; i < nents; i++, sg++) { + dma_addr_t dma_addr = sg->dma_address; + unsigned int length = sg->length; + + sync_single(dev, dma_addr, length, dir); + } + + local_irq_restore(flags); +} + +void sa1111_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction dir) { unsigned long flags; int i; @@ -497,8 +533,10 @@ EXPORT_SYMBOL(sa1111_unmap_single); EXPORT_SYMBOL(sa1111_map_sg); EXPORT_SYMBOL(sa1111_unmap_sg); -EXPORT_SYMBOL(sa1111_dma_sync_single); -EXPORT_SYMBOL(sa1111_dma_sync_sg); +EXPORT_SYMBOL(sa1111_dma_sync_single_for_cpu); +EXPORT_SYMBOL(sa1111_dma_sync_single_for_device); +EXPORT_SYMBOL(sa1111_dma_sync_sg_for_cpu); +EXPORT_SYMBOL(sa1111_dma_sync_sg_for_device); /* **************************************** */ diff -Nru a/arch/cris/kernel/process.c b/arch/cris/kernel/process.c --- a/arch/cris/kernel/process.c Sun Mar 14 14:20:07 2004 +++ b/arch/cris/kernel/process.c Sun Mar 14 14:20:07 2004 @@ -91,8 +91,6 @@ * This file handles the architecture-dependent parts of process handling.. */ -#define __KERNEL_SYSCALLS__ - #include #include #include diff -Nru a/arch/h8300/kernel/sys_h8300.c b/arch/h8300/kernel/sys_h8300.c --- a/arch/h8300/kernel/sys_h8300.c Sun Mar 14 14:20:08 2004 +++ b/arch/h8300/kernel/sys_h8300.c Sun Mar 14 14:20:08 2004 @@ -260,11 +260,6 @@ return -EINVAL; } -asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on) -{ - return -ENOSYS; -} - /* sys_cacheflush -- no support. */ asmlinkage int sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len) diff -Nru a/arch/h8300/kernel/syscalls.S b/arch/h8300/kernel/syscalls.S --- a/arch/h8300/kernel/syscalls.S Sun Mar 14 14:20:06 2004 +++ b/arch/h8300/kernel/syscalls.S Sun Mar 14 14:20:06 2004 @@ -116,7 +116,7 @@ .long SYMBOL_NAME(sys_ni_syscall) /* old profil syscall holder */ .long SYMBOL_NAME(sys_statfs) .long SYMBOL_NAME(sys_fstatfs) /* 100 */ - .long SYMBOL_NAME(sys_ioperm) + .long SYMBOL_NAME(sys_ni_syscall) /* ioperm for i386 */ .long SYMBOL_NAME(sys_socketcall) .long SYMBOL_NAME(sys_syslog) .long SYMBOL_NAME(sys_setitimer) diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig --- a/arch/i386/Kconfig Sun Mar 14 14:20:06 2004 +++ b/arch/i386/Kconfig Sun Mar 14 14:20:06 2004 @@ -269,9 +269,6 @@ use of some extended instructions, and passes appropriate optimization flags to GCC. -config MELAN - bool "Elan" - config MCRUSOE bool "Crusoe" help @@ -552,7 +549,7 @@ the 386 and 486, so nearly everyone can say Y here. config X86_MCE_NONFATAL - bool "Check for non-fatal errors on AMD Athlon/Duron / Intel Pentium 4" + tristate "Check for non-fatal errors on AMD Athlon/Duron / Intel Pentium 4" depends on X86_MCE help Enabling this feature starts a timer that triggers every 5 seconds which @@ -1241,17 +1238,6 @@ allocation as well as poisoning memory on free to catch use of freed memory. -config DEBUG_IOVIRT - bool "Memory mapped I/O debugging" - depends on DEBUG_KERNEL - help - Say Y here to get warned whenever an attempt is made to do I/O on - obviously invalid addresses such as those generated when ioremap() - calls are forgotten. Memory mapped I/O will go through an extra - check to catch access to unmapped ISA addresses, an access method - that can still be used by old drivers that are being ported from - 2.0/2.2. - config MAGIC_SYSRQ bool "Magic SysRq key" depends on DEBUG_KERNEL @@ -1348,7 +1334,7 @@ config X86_TRAMPOLINE bool - depends on SMP || X86_VISWS + depends on X86_SMP || (X86_VOYAGER && SMP) default y config PC diff -Nru a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S --- a/arch/i386/boot/setup.S Sun Mar 14 14:20:07 2004 +++ b/arch/i386/boot/setup.S Sun Mar 14 14:20:07 2004 @@ -51,6 +51,8 @@ * projects 1572D, 1484D, 1386D, 1226DT * disk signature read by Matt Domsch * and Andrew Wilks September 2003 + * legacy CHS retreival by Patrick J. LoPresti + * March 2004 */ #include @@ -592,7 +594,11 @@ pushw %ds popw %es movw $EDDBUF, %bx - int $0x13 + pushw %dx # work around buggy BIOSes + stc # work around buggy BIOSes + int $0x13 + sti # work around buggy BIOSes + popw %dx jc disk_sig_done movl (EDDBUF+MBR_SIG_OFFSET), %eax movl %eax, (DISK80_SIG_BUFFER) # store success @@ -603,32 +609,34 @@ # This consists of two calls: # int 13h ah=41h "Check Extensions Present" # int 13h ah=48h "Get Device Parameters" +# int 13h ah=08h "Legacy Get Device Parameters" # # A buffer of size EDDMAXNR*(EDDEXTSIZE+EDDPARMSIZE) is reserved for our use # in the empty_zero_page at EDDBUF. The first four bytes of which are # used to store the device number, interface support map and version -# results from fn41. The following 74 bytes are used to store -# the results from fn48. Starting from device 80h, fn41, then fn48 +# results from fn41. The next four bytes are used to store the legacy +# cylinders, heads, and sectors from fn08. The following 74 bytes are used to +# store the results from fn48. Starting from device 80h, fn41, then fn48 # are called and their results stored in EDDBUF+n*(EDDEXTSIZE+EDDPARMIZE). # Then the pointer is incremented to store the data for the next call. # This repeats until either a device doesn't exist, or until EDDMAXNR # devices have been stored. -# The one tricky part is that ds:si always points four bytes into -# the structure, and the fn41 results are stored at offsets +# The one tricky part is that ds:si always points EDDEXTSIZE bytes into +# the structure, and the fn41 and fn08 results are stored at offsets # from there. This removes the need to increment the pointer for # every store, and leaves it ready for the fn48 call. # A second one-byte buffer, EDDNR, in the empty_zero_page stores # the number of BIOS devices which exist, up to EDDMAXNR. # In setup.c, copy_edd() stores both empty_zero_page buffers away -# for later use, as they would get overwritten otherwise. +# for later use, as they would get overwritten otherwise. # This code is sensitive to the size of the structs in edd.h -edd_start: +edd_start: # %ds points to the bootsector # result buffer for fn48 - movw $EDDBUF+EDDEXTSIZE, %si # in ds:si, fn41 results - # kept just before that + movw $EDDBUF+EDDEXTSIZE, %si # in ds:si, fn41 results + # kept just before that movb $0, (EDDNR) # zero value at EDDNR - movb $0x80, %dl # BIOS device 0x80 + movb $0x80, %dl # BIOS device 0x80 edd_check_ext: movb $CHECKEXTENSIONSPRESENT, %ah # Function 41 @@ -636,30 +644,56 @@ int $0x13 # make the call jc edd_done # no more BIOS devices - cmpw $EDDMAGIC2, %bx # is magic right? + cmpw $EDDMAGIC2, %bx # is magic right? jne edd_next # nope, next... - movb %dl, %ds:-4(%si) # store device number - movb %ah, %ds:-3(%si) # store version - movw %cx, %ds:-2(%si) # store extensions + movb %dl, %ds:-8(%si) # store device number + movb %ah, %ds:-7(%si) # store version + movw %cx, %ds:-6(%si) # store extensions incb (EDDNR) # note that we stored something - -edd_get_device_params: + +edd_get_device_params: movw $EDDPARMSIZE, %ds:(%si) # put size - movb $GETDEVICEPARAMETERS, %ah # Function 48 + movw $0x0, %ds:2(%si) # work around buggy BIOSes + movb $GETDEVICEPARAMETERS, %ah # Function 48 int $0x13 # make the call # Don't check for fail return # it doesn't matter. +edd_get_legacy_chs: + xorw %ax, %ax + movw %ax, %ds:-4(%si) + movw %ax, %ds:-2(%si) + # Ralf Brown's Interrupt List says to set ES:DI to + # 0000h:0000h "to guard against BIOS bugs" + pushw %es + movw %ax, %es + movw %ax, %di + pushw %dx # legacy call clobbers %dl + movb $LEGACYGETDEVICEPARAMETERS, %ah # Function 08 + int $0x13 # make the call + jc edd_legacy_done # failed + movb %cl, %al # Low 6 bits are max + andb $0x3F, %al # sector number + movb %al, %ds:-1(%si) # Record max sect + movb %dh, %ds:-2(%si) # Record max head number + movb %ch, %al # Low 8 bits of max cyl + shr $6, %cl + movb %cl, %ah # High 2 bits of max cyl + movw %ax, %ds:-4(%si) + +edd_legacy_done: + popw %dx + popw %es movw %si, %ax # increment si addw $EDDPARMSIZE+EDDEXTSIZE, %ax movw %ax, %si edd_next: - incb %dl # increment to next device - cmpb $EDDMAXNR, (EDDNR) # Out of space? + incb %dl # increment to next device + cmpb $EDDMAXNR, (EDDNR) # Out of space? jb edd_check_ext # keep looping - -edd_done: + +edd_done: #endif # Now we want to move to protected mode ... diff -Nru a/arch/i386/boot/tools/build.c b/arch/i386/boot/tools/build.c --- a/arch/i386/boot/tools/build.c Sun Mar 14 14:20:07 2004 +++ b/arch/i386/boot/tools/build.c Sun Mar 14 14:20:07 2004 @@ -150,10 +150,8 @@ sz = sb.st_size; fprintf (stderr, "System is %d kB\n", sz/1024); sys_size = (sz + 15) / 16; - /* 0x40000*16 = 4.0 MB, reasonable estimate for the current maximum */ - if (sys_size > (is_big_kernel ? 0x40000 : DEF_SYSSIZE)) - die("System is too big. Try using %smodules.", - is_big_kernel ? "" : "bzImage or "); + if (!is_big_kernel && sys_size > DEF_SYSSIZE) + die("System is too big. Try using bzImage or modules."); while (sz > 0) { int l, n; diff -Nru a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c --- a/arch/i386/kernel/acpi/boot.c Sun Mar 14 14:20:08 2004 +++ b/arch/i386/kernel/acpi/boot.c Sun Mar 14 14:20:08 2004 @@ -128,7 +128,9 @@ return 0; } -#endif /* CONFIG_PCI_MMCONFIG */ +#else +#define acpi_parse_mcfg NULL +#endif /* !CONFIG_PCI_MMCONFIG */ #ifdef CONFIG_X86_LOCAL_APIC static int __init @@ -424,6 +426,8 @@ hpet_address); return 0; } +#else +#define acpi_parse_hpet NULL #endif /* detect the location of the ACPI PM Timer */ @@ -454,6 +458,8 @@ printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n", pmtmr_ioport); return 0; } +#else +#define acpi_parse_fadt NULL #endif @@ -666,7 +672,7 @@ return error; } - (void) acpi_table_parse(ACPI_BOOT, acpi_parse_sbf); + acpi_table_parse(ACPI_BOOT, acpi_parse_sbf); /* * blacklist may disable ACPI entirely @@ -683,19 +689,9 @@ */ acpi_process_madt(); -#ifdef CONFIG_X86_PM_TIMER acpi_table_parse(ACPI_FADT, acpi_parse_fadt); -#endif - -#ifdef CONFIG_HPET_TIMER - (void) acpi_table_parse(ACPI_HPET, acpi_parse_hpet); -#endif - -#ifdef CONFIG_PCI_MMCONFIG - error = acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg); - if (error) - printk(KERN_ERR PREFIX "Error %d parsing MCFG\n", error); -#endif + acpi_table_parse(ACPI_HPET, acpi_parse_hpet); + acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg); return 0; } diff -Nru a/arch/i386/kernel/asm-offsets.c b/arch/i386/kernel/asm-offsets.c --- a/arch/i386/kernel/asm-offsets.c Sun Mar 14 14:20:07 2004 +++ b/arch/i386/kernel/asm-offsets.c Sun Mar 14 14:20:07 2004 @@ -4,9 +4,11 @@ * to extract and format the required data. */ +#include #include #include #include "sigframe.h" +#include #define DEFINE(sym, val) \ asm volatile("\n->" #sym " %0 " #val : : "i" (val)) @@ -28,4 +30,6 @@ DEFINE(RT_SIGFRAME_sigcontext, offsetof (struct rt_sigframe, uc.uc_mcontext)); + + DEFINE(PAGE_SIZE_asm, PAGE_SIZE); } diff -Nru a/arch/i386/kernel/bootflag.c b/arch/i386/kernel/bootflag.c --- a/arch/i386/kernel/bootflag.c Sun Mar 14 14:20:08 2004 +++ b/arch/i386/kernel/bootflag.c Sun Mar 14 14:20:08 2004 @@ -48,7 +48,7 @@ if(!parity(v)) v|=SBF_PARITY; - printk(KERN_INFO "Simple Boot Flag 0x%x\n", v); + printk(KERN_INFO "Simple Boot Flag at 0x%x set to 0x%x\n", sbf_port, v); spin_lock_irqsave(&rtc_lock, flags); CMOS_WRITE(v, sbf_port); diff -Nru a/arch/i386/kernel/cpu/mcheck/mce.c b/arch/i386/kernel/cpu/mcheck/mce.c --- a/arch/i386/kernel/cpu/mcheck/mce.c Sun Mar 14 14:20:08 2004 +++ b/arch/i386/kernel/cpu/mcheck/mce.c Sun Mar 14 14:20:08 2004 @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -17,6 +18,8 @@ int mce_disabled __initdata = 0; int nr_mce_banks; + +EXPORT_SYMBOL_GPL(nr_mce_banks); /* non-fatal.o */ /* Handle unconfigured int18 (should never happen) */ static asmlinkage void unexpected_machine_check(struct pt_regs * regs, long error_code) diff -Nru a/arch/i386/kernel/edd.c b/arch/i386/kernel/edd.c --- a/arch/i386/kernel/edd.c Sun Mar 14 14:20:06 2004 +++ b/arch/i386/kernel/edd.c Sun Mar 14 14:20:06 2004 @@ -1,8 +1,9 @@ /* * linux/arch/i386/kernel/edd.c - * Copyright (C) 2002, 2003 Dell Inc. + * Copyright (C) 2002, 2003, 2004 Dell Inc. * by Matt Domsch * disk80 signature by Matt Domsch, Andrew Wilks, and Sandeep K. Shandilya + * legacy CHS by Patrick J. LoPresti * * BIOS Enhanced Disk Drive Services (EDD) * conformant to T13 Committee www.t13.org @@ -60,7 +61,7 @@ MODULE_DESCRIPTION("sysfs interface to BIOS EDD information"); MODULE_LICENSE("GPL"); -#define EDD_VERSION "0.12 2004-Jan-26" +#define EDD_VERSION "0.13 2004-Mar-09" #define EDD_DEVICE_NAME_SIZE 16 #define REPORT_URL "http://linux.dell.com/edd/results.html" @@ -231,7 +232,7 @@ edd_show_raw_data(struct edd_device *edev, char *buf) { struct edd_info *info = edd_dev_get_info(edev); - ssize_t len = sizeof (*info) - 4; + ssize_t len = sizeof (info->params); if (!edev || !info || !buf) { return -EINVAL; } @@ -240,10 +241,10 @@ len = info->params.length; /* In case of buggy BIOSs */ - if (len > (sizeof(*info) - 4)) - len = sizeof(*info) - 4; + if (len > (sizeof(info->params))) + len = sizeof(info->params); - memcpy(buf, ((char *)info) + 4, len); + memcpy(buf, &info->params, len); return len; } @@ -321,6 +322,45 @@ } static ssize_t +edd_show_legacy_cylinders(struct edd_device *edev, char *buf) +{ + struct edd_info *info = edd_dev_get_info(edev); + char *p = buf; + if (!edev || !info || !buf) { + return -EINVAL; + } + + p += snprintf(p, left, "0x%x\n", info->legacy_cylinders); + return (p - buf); +} + +static ssize_t +edd_show_legacy_heads(struct edd_device *edev, char *buf) +{ + struct edd_info *info = edd_dev_get_info(edev); + char *p = buf; + if (!edev || !info || !buf) { + return -EINVAL; + } + + p += snprintf(p, left, "0x%x\n", info->legacy_heads); + return (p - buf); +} + +static ssize_t +edd_show_legacy_sectors(struct edd_device *edev, char *buf) +{ + struct edd_info *info = edd_dev_get_info(edev); + char *p = buf; + if (!edev || !info || !buf) { + return -EINVAL; + } + + p += snprintf(p, left, "0x%x\n", info->legacy_sectors); + return (p - buf); +} + +static ssize_t edd_show_default_cylinders(struct edd_device *edev, char *buf) { struct edd_info *info = edd_dev_get_info(edev); @@ -384,6 +424,33 @@ */ static int +edd_has_legacy_cylinders(struct edd_device *edev) +{ + struct edd_info *info = edd_dev_get_info(edev); + if (!edev || !info) + return -EINVAL; + return info->legacy_cylinders > 0; +} + +static int +edd_has_legacy_heads(struct edd_device *edev) +{ + struct edd_info *info = edd_dev_get_info(edev); + if (!edev || !info) + return -EINVAL; + return info->legacy_heads > 0; +} + +static int +edd_has_legacy_sectors(struct edd_device *edev) +{ + struct edd_info *info = edd_dev_get_info(edev); + if (!edev || !info) + return -EINVAL; + return info->legacy_sectors > 0; +} + +static int edd_has_default_cylinders(struct edd_device *edev) { struct edd_info *info = edd_dev_get_info(edev); @@ -452,6 +519,12 @@ static EDD_DEVICE_ATTR(extensions, 0444, edd_show_extensions, NULL); static EDD_DEVICE_ATTR(info_flags, 0444, edd_show_info_flags, NULL); static EDD_DEVICE_ATTR(sectors, 0444, edd_show_sectors, NULL); +static EDD_DEVICE_ATTR(legacy_cylinders, 0444, edd_show_legacy_cylinders, + edd_has_legacy_cylinders); +static EDD_DEVICE_ATTR(legacy_heads, 0444, edd_show_legacy_heads, + edd_has_legacy_heads); +static EDD_DEVICE_ATTR(legacy_sectors, 0444, edd_show_legacy_sectors, + edd_has_legacy_sectors); static EDD_DEVICE_ATTR(default_cylinders, 0444, edd_show_default_cylinders, edd_has_default_cylinders); static EDD_DEVICE_ATTR(default_heads, 0444, edd_show_default_heads, @@ -478,6 +551,9 @@ /* These attributes are conditional and only added for some devices. */ static struct edd_attribute * edd_attrs[] = { + &edd_attr_legacy_cylinders, + &edd_attr_legacy_heads, + &edd_attr_legacy_sectors, &edd_attr_default_cylinders, &edd_attr_default_heads, &edd_attr_default_sectors_per_track, diff -Nru a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S --- a/arch/i386/kernel/head.S Sun Mar 14 14:20:06 2004 +++ b/arch/i386/kernel/head.S Sun Mar 14 14:20:06 2004 @@ -17,7 +17,7 @@ #include #include #include - +#include #define OLD_CL_MAGIC_ADDR 0x90020 #define OLD_CL_MAGIC 0xA33F @@ -40,49 +40,89 @@ #define X86_VENDOR_ID CPU_PARAMS+36 /* offset dependent on NCAPINTS */ /* - * Initialize page tables + * This is how much memory *in addition to the memory covered up to + * and including _end* we need mapped initially. We need one bit for + * each possible page, but only in low memory, which means + * 2^32/4096/8 = 128K worst case (4G/4G split.) + * + * Modulo rounding, each megabyte assigned here requires a kilobyte of + * memory, which is currently unreclaimed. + * + * This should be a multiple of a page. */ -#define INIT_PAGE_TABLES \ - movl $pg0 - __PAGE_OFFSET, %edi; \ - /* "007" doesn't mean with license to kill, but PRESENT+RW+USER */ \ - movl $007, %eax; \ -2: stosl; \ - add $0x1000, %eax; \ - cmp $empty_zero_page - __PAGE_OFFSET, %edi; \ - jne 2b; +#define INIT_MAP_BEYOND_END (128*1024) + /* - * swapper_pg_dir is the main page directory, address 0x00101000 - * - * On entry, %esi points to the real-mode code as a 32-bit pointer. + * 32-bit kernel entrypoint; only used by the boot CPU. On entry, + * %esi points to the real-mode code as a 32-bit pointer. + * CS and DS must be 4 GB flat segments, but we don't depend on + * any particular GDT layout, because we load our own as soon as we + * can. */ ENTRY(startup_32) -#ifdef CONFIG_X86_VISWS /* - * On SGI Visual Workstations boot CPU starts in protected mode. + * Set segments to known values. */ - orw %bx, %bx - jnz 1f - INIT_PAGE_TABLES - movl $swapper_pg_dir - __PAGE_OFFSET, %eax - movl %eax, %cr3 - lgdt boot_gdt -1: -#endif + cld + lgdt boot_gdt_descr - __PAGE_OFFSET + movl $(__BOOT_DS),%eax + movl %eax,%ds + movl %eax,%es + movl %eax,%fs + movl %eax,%gs /* - * Set segments to known values + * Initialize page tables. This creates a PDE and a set of page + * tables, which are located immediately beyond _end. The variable + * init_pg_tables_end is set up to point to the first "safe" location. + * + * Warning: don't use %esi or the stack in this code. However, %esp + * can be used as a GPR if you really need it... */ +page_pde_offset = (__PAGE_OFFSET >> 20); + + movl $(pg0 - __PAGE_OFFSET), %edi + movl $(swapper_pg_dir - __PAGE_OFFSET), %edx + movl $0x007, %eax /* 0x007 = PRESENT+RW+USER */ +10: + leal 0x007(%edi),%ecx /* Create PDE entry */ + movl %ecx,(%edx) /* Store identity PDE entry */ + movl %ecx,page_pde_offset(%edx) /* Store kernel PDE entry */ + addl $4,%edx + movl $1024, %ecx +11: + stosl + addl $0x1000,%eax + loop 11b + /* End condition: we must map up to and including INIT_MAP_BEYOND_END */ + /* bytes beyond the end of our own page tables; the +0x007 is the attribute bits */ + leal (INIT_MAP_BEYOND_END+0x007)(%edi),%ebp + cmpl %ebp,%eax + jb 10b + movl %edi,(init_pg_tables_end - __PAGE_OFFSET) + +#ifdef CONFIG_SMP + xorl %ebx,%ebx /* This is the boot CPU (BSP) */ + jmp 3f + +/* + * Non-boot CPU entry point; entered from trampoline.S + * We can't lgdt here, because lgdt itself uses a data segment, but + * we know the trampoline has already loaded the boot_gdt_table GDT + * for us. + */ +ENTRY(startup_32_smp) cld movl $(__BOOT_DS),%eax movl %eax,%ds movl %eax,%es movl %eax,%fs movl %eax,%gs -#ifdef CONFIG_SMP - orw %bx,%bx - jz 1f + + xorl %ebx,%ebx + incl %ebx /* This is a secondary processor (AP) */ /* * New page tables may be in 4Mbyte page mode and may @@ -99,37 +139,40 @@ * not yet offset PAGE_OFFSET.. */ #define cr4_bits mmu_cr4_features-__PAGE_OFFSET - cmpl $0,cr4_bits - je 3f + movl cr4_bits,%edx + andl %edx,%edx + jz 3f movl %cr4,%eax # Turn on paging options (PSE,PAE,..) - orl cr4_bits,%eax + orl %edx,%eax movl %eax,%cr4 - jmp 3f -1: -#endif - INIT_PAGE_TABLES + +3: +#endif /* CONFIG_SMP */ + /* * Enable paging */ -3: movl $swapper_pg_dir-__PAGE_OFFSET,%eax movl %eax,%cr3 /* set the page table pointer.. */ movl %cr0,%eax orl $0x80000000,%eax movl %eax,%cr0 /* ..and set paging (PG) bit */ - jmp 1f /* flush the prefetch-queue */ -1: - movl $1f,%eax - jmp *%eax /* make sure eip is relocated */ + ljmp $__BOOT_CS,$1f /* Clear prefetch and normalize %eip */ 1: /* Set up the stack pointer */ lss stack_start,%esp -#ifdef CONFIG_SMP - orw %bx,%bx - jz 1f /* Initial CPU cleans BSS */ +/* + * Initialize eflags. Some BIOS's leave bits like NT set. This would + * confuse the debugger if this code is traced. + * XXX - best to initialize before switching to protected mode. + */ pushl $0 popfl + +#ifdef CONFIG_SMP + andl %ebx,%ebx + jz 1f /* Initial CPU cleans BSS */ jmp checkCPUtype 1: #endif /* CONFIG_SMP */ @@ -142,21 +185,15 @@ movl $__bss_start,%edi movl $__bss_stop,%ecx subl %edi,%ecx - rep - stosb + shrl $2,%ecx + rep ; stosl /* * start system 32-bit setup. We need to re-do some of the things done * in 16-bit mode for the "real" operations. */ call setup_idt -/* - * Initialize eflags. Some BIOS's leave bits like NT set. This would - * confuse the debugger if this code is traced. - * XXX - best to initialize before switching to protected mode. - */ - pushl $0 - popfl + /* * Copy bootup parameters out of the way. First 2kB of * _empty_zero_page is for boot parameters, second 2kB @@ -273,7 +310,7 @@ call initialize_secondary jmp L6 1: -#endif +#endif /* CONFIG_SMP */ call start_kernel L6: jmp L6 # main should never return here, but @@ -309,6 +346,8 @@ * and the kernel moved to PAGE_OFFSET. Interrupts * are enabled elsewhere, when we can be relatively * sure everything is ok. + * + * Warning: %esi is live across this function. */ setup_idt: lea ignore_int,%edx @@ -332,7 +371,7 @@ /* This is the default interrupt "handler" :-) */ int_msg: - .asciz "Unknown interrupt\n" + .asciz "Unknown interrupt or fault at EIP %p %p %p\n" ALIGN ignore_int: cld @@ -344,9 +383,13 @@ movl $(__KERNEL_DS),%eax movl %eax,%ds movl %eax,%es + pushl 16(%esp) + pushl 24(%esp) + pushl 32(%esp) + pushl 40(%esp) pushl $int_msg call printk - popl %eax + addl $(5*4),%esp popl %ds popl %es popl %edx @@ -361,10 +404,17 @@ * segment size, and 32-bit linear address value: */ +.globl boot_gdt_descr .globl idt_descr .globl cpu_gdt_descr ALIGN +# early boot GDT descriptor (must use 1:1 address mapping) + .word 0 # 32 bit align gdt_desc.address +boot_gdt_descr: + .word __BOOT_DS+7 + .long boot_gdt_table - __PAGE_OFFSET + .word 0 # 32-bit align idt_desc.address idt_descr: .word IDT_ENTRIES*8-1 # idt contains 256 entries @@ -379,41 +429,25 @@ .fill NR_CPUS-1,8,0 # space for the other GDT descriptors /* - * This is initialized to create an identity-mapping at 0-8M (for bootup - * purposes) and another mapping of the 0-8M area at virtual address - * PAGE_OFFSET. + * swapper_pg_dir is the main page directory, address 0x00101000 + * + * This is initialized to create an identity-mapping at 0 (for bootup + * purposes) and another mapping at virtual address PAGE_OFFSET. The + * values put here should be all invalid (zero); the valid + * entries are created dynamically at boot time. + * + * The code creates enough page tables to map 0-_end, the page tables + * themselves, plus INIT_MAP_BEYOND_END bytes; see comment at beginning. */ .org 0x1000 ENTRY(swapper_pg_dir) - .long 0x00102007 - .long 0x00103007 - .fill BOOT_USER_PGD_PTRS-2,4,0 - /* default: 766 entries */ - .long 0x00102007 - .long 0x00103007 - /* default: 254 entries */ - .fill BOOT_KERNEL_PGD_PTRS-2,4,0 + .fill 1024,4,0 -/* - * The page tables are initialized to only 8MB here - the final page - * tables are set up later depending on memory size. - */ .org 0x2000 -ENTRY(pg0) - -.org 0x3000 -ENTRY(pg1) - -/* - * empty_zero_page must immediately follow the page tables ! (The - * initialization loop counts until empty_zero_page) - */ - -.org 0x4000 ENTRY(empty_zero_page) + .fill 4096,1,0 -.org 0x5000 - +.org 0x3000 /* * Real beginning of normal "text" segment */ @@ -428,20 +462,19 @@ .data /* - * The Global Descriptor Table contains 28 quadwords, per-CPU. - */ -#if defined(CONFIG_SMP) || defined(CONFIG_X86_VISWS) -/* * The boot_gdt_table must mirror the equivalent in setup.S and is - * used only by the trampoline for booting other CPUs + * used only for booting. */ .align L1_CACHE_BYTES ENTRY(boot_gdt_table) .fill GDT_ENTRY_BOOT_CS,8,0 .quad 0x00cf9a000000ffff /* kernel 4GB code at 0x00000000 */ .quad 0x00cf92000000ffff /* kernel 4GB data at 0x00000000 */ -#endif - .align L1_CACHE_BYTES + +/* + * The Global Descriptor Table contains 28 quadwords, per-CPU. + */ + .align PAGE_SIZE_asm ENTRY(cpu_gdt_table) .quad 0x0000000000000000 /* NULL descriptor */ .quad 0x0000000000000000 /* 0x0b reserved */ @@ -488,4 +521,3 @@ #ifdef CONFIG_SMP .fill (NR_CPUS-1)*GDT_ENTRIES,8,0 /* other CPU's GDT */ #endif - diff -Nru a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c --- a/arch/i386/kernel/i386_ksyms.c Sun Mar 14 14:20:08 2004 +++ b/arch/i386/kernel/i386_ksyms.c Sun Mar 14 14:20:08 2004 @@ -88,10 +88,6 @@ EXPORT_SYMBOL(cpu_khz); EXPORT_SYMBOL(apm_info); -#ifdef CONFIG_DEBUG_IOVIRT -EXPORT_SYMBOL(__io_virt_debug); -#endif - EXPORT_SYMBOL_NOVERS(__down_failed); EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); EXPORT_SYMBOL_NOVERS(__down_failed_trylock); diff -Nru a/arch/i386/kernel/pci-dma.c b/arch/i386/kernel/pci-dma.c --- a/arch/i386/kernel/pci-dma.c Sun Mar 14 14:20:06 2004 +++ b/arch/i386/kernel/pci-dma.c Sun Mar 14 14:20:06 2004 @@ -20,8 +20,9 @@ /* ignore region specifiers */ gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); - if (dev == NULL || (*dev->dma_mask < 0xffffffff)) + if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff)) gfp |= GFP_DMA; + ret = (void *)__get_free_pages(gfp, get_order(size)); if (ret != NULL) { diff -Nru a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c --- a/arch/i386/kernel/process.c Sun Mar 14 14:20:05 2004 +++ b/arch/i386/kernel/process.c Sun Mar 14 14:20:05 2004 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -222,7 +223,7 @@ if (regs->xcs & 3) printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp); - printk(" EFLAGS: %08lx %s\n",regs->eflags, print_tainted()); + printk(" EFLAGS: %08lx %s (%s)\n",regs->eflags, print_tainted(),UTS_RELEASE); printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", regs->eax,regs->ebx,regs->ecx,regs->edx); printk("ESI: %08lx EDI: %08lx EBP: %08lx", diff -Nru a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c --- a/arch/i386/kernel/setup.c Sun Mar 14 14:20:07 2004 +++ b/arch/i386/kernel/setup.c Sun Mar 14 14:20:07 2004 @@ -50,6 +50,11 @@ #include "setup_arch_pre.h" #include "mach_resources.h" +/* This value is set up by the early boot code to point to the value + immediately after the boot time page tables. It contains a *physical* + address, and must not be in the .bss segment! */ +unsigned long init_pg_tables_end __initdata = ~0UL; + int disable_pse __initdata = 0; static inline char * __init machine_specific_memory_setup(void); @@ -115,7 +120,6 @@ extern void dmi_scan_machine(void); extern void generic_apic_probe(char *); extern int root_mountflags; -extern char _end[]; unsigned long saved_videomode; @@ -790,7 +794,7 @@ * partially used pages are not usable - thus * we are rounding upwards: */ - start_pfn = PFN_UP(__pa(_end)); + start_pfn = PFN_UP(init_pg_tables_end); find_max_pfn(); @@ -828,6 +832,13 @@ */ reserve_bootmem(0, PAGE_SIZE); + /* could be an AMD 768MPX chipset. Reserve a page before VGA to prevent + PCI prefetch into it (errata #56). Usually the page is reserved anyways, + unless you have no PS/2 mouse plugged in. */ + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && + boot_cpu_data.x86 == 6) + reserve_bootmem(0xa0000 - 4096, 4096); + #ifdef CONFIG_SMP /* * But first pinch a few for the stack/trampoline stuff @@ -1102,7 +1113,7 @@ init_mm.start_code = (unsigned long) _text; init_mm.end_code = (unsigned long) _etext; init_mm.end_data = (unsigned long) _edata; - init_mm.brk = (unsigned long) _end; + init_mm.brk = init_pg_tables_end + PAGE_OFFSET; code_resource.start = virt_to_phys(_text); code_resource.end = virt_to_phys(_etext)-1; diff -Nru a/arch/i386/kernel/trampoline.S b/arch/i386/kernel/trampoline.S --- a/arch/i386/kernel/trampoline.S Sun Mar 14 14:20:07 2004 +++ b/arch/i386/kernel/trampoline.S Sun Mar 14 14:20:07 2004 @@ -23,9 +23,13 @@ * and IP is zero. Thus, data addresses need to be absolute * (no relocation) and are taken with regard to r_base. * - * If you work on this file, check the object module with objdump - * --full-contents --reloc to make sure there are no relocation - * entries except for the gdt one.. + * If you work on this file, check the object module with + * objdump --reloc to make sure there are no relocation + * entries except for: + * + * TYPE VALUE + * R_386_32 startup_32_smp + * R_386_32 boot_gdt_table */ #include @@ -42,7 +46,6 @@ mov %cs, %ax # Code and data in the same place mov %ax, %ds - mov $1, %bx # Flag an SMP trampoline cli # We should be safe anyway movl $0xA5A5A5A5, trampoline_data - r_base @@ -54,22 +57,18 @@ xor %ax, %ax inc %ax # protected mode (PE) bit lmsw %ax # into protected mode - jmp flush_instr -flush_instr: - ljmpl $__BOOT_CS, $0x00100000 - # jump to startup_32 in arch/i386/kernel/head.S + # flush prefetch and jump to startup_32_smp in arch/i386/kernel/head.S + ljmpl $__BOOT_CS, $(startup_32_smp-__PAGE_OFFSET) -boot_idt: - .word 0 # idt limit = 0 - .word 0, 0 # idt base = 0L - -# -# NOTE: here we actually use CPU#0's GDT - but that is OK, we reload -# the proper GDT shortly after booting up the secondary CPUs. -# -ENTRY(boot_gdt) + # These need to be in the same 64K segment as the above; + # hence we don't use the boot_gdt_descr defined in head.S +boot_gdt: .word __BOOT_DS + 7 # gdt limit - .long boot_gdt_table-__PAGE_OFFSET # gdt base = gdt (first SMP CPU) + .long boot_gdt_table-__PAGE_OFFSET # gdt base + +boot_idt: + .word 0 # idt limit = 0 + .long 0 # idt base = 0L .globl trampoline_end trampoline_end: diff -Nru a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c --- a/arch/i386/kernel/traps.c Sun Mar 14 14:20:06 2004 +++ b/arch/i386/kernel/traps.c Sun Mar 14 14:20:06 2004 @@ -25,6 +25,7 @@ #include #include #include +#include #ifdef CONFIG_EISA #include @@ -175,9 +176,10 @@ ss = regs->xss & 0xffff; } print_modules(); - printk("CPU: %d\nEIP: %04x:[<%08lx>] %s\nEFLAGS: %08lx\n", - smp_processor_id(), 0xffff & regs->xcs, regs->eip, print_tainted(), regs->eflags); - + printk("CPU: %d\nEIP: %04x:[<%08lx>] %s\nEFLAGS: %08lx" + " (%s) \n", + smp_processor_id(), 0xffff & regs->xcs, regs->eip, + print_tainted(), regs->eflags, UTS_RELEASE); print_symbol("EIP is at %s\n", regs->eip); printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", regs->eax, regs->ebx, regs->ecx, regs->edx); diff -Nru a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S --- a/arch/i386/kernel/vmlinux.lds.S Sun Mar 14 14:20:06 2004 +++ b/arch/i386/kernel/vmlinux.lds.S Sun Mar 14 14:20:06 2004 @@ -105,9 +105,14 @@ __bss_start = .; /* BSS */ .bss : { *(.bss) } + . = ALIGN(4); __bss_stop = .; _end = . ; + + /* This is where the kernel creates the early boot page tables */ + . = ALIGN(4096); + pg0 = .; /* Sections to be discarded */ /DISCARD/ : { diff -Nru a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile --- a/arch/i386/lib/Makefile Sun Mar 14 14:20:06 2004 +++ b/arch/i386/lib/Makefile Sun Mar 14 14:20:06 2004 @@ -9,4 +9,3 @@ lib-$(CONFIG_X86_USE_3DNOW) += mmx.o lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o -lib-$(CONFIG_DEBUG_IOVIRT) += iodebug.o diff -Nru a/arch/i386/lib/iodebug.c b/arch/i386/lib/iodebug.c --- a/arch/i386/lib/iodebug.c Sun Mar 14 14:20:08 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,11 +0,0 @@ -#include - -void * __io_virt_debug(unsigned long x, const char *file, int line) -{ - if (x < PAGE_OFFSET) { - printk("io mapaddr 0x%05lx not valid at %s:%d!\n", x, file, line); - return __va(x); - } - return (void *)x; -} - diff -Nru a/arch/i386/mach-default/Makefile b/arch/i386/mach-default/Makefile --- a/arch/i386/mach-default/Makefile Sun Mar 14 14:20:06 2004 +++ b/arch/i386/mach-default/Makefile Sun Mar 14 14:20:06 2004 @@ -2,6 +2,4 @@ # Makefile for the linux kernel. # -EXTRA_CFLAGS += -I../kernel - obj-y := setup.o topology.o diff -Nru a/arch/i386/mach-es7000/Makefile b/arch/i386/mach-es7000/Makefile --- a/arch/i386/mach-es7000/Makefile Sun Mar 14 14:20:07 2004 +++ b/arch/i386/mach-es7000/Makefile Sun Mar 14 14:20:07 2004 @@ -2,6 +2,4 @@ # Makefile for the linux kernel. # -EXTRA_CFLAGS += -I../kernel - obj-y := setup.o topology.o es7000.o diff -Nru a/arch/i386/mach-pc9800/Makefile b/arch/i386/mach-pc9800/Makefile --- a/arch/i386/mach-pc9800/Makefile Sun Mar 14 14:20:08 2004 +++ b/arch/i386/mach-pc9800/Makefile Sun Mar 14 14:20:08 2004 @@ -2,6 +2,4 @@ # Makefile for the linux kernel. # -EXTRA_CFLAGS += -I../kernel - obj-y := setup.o topology.o diff -Nru a/arch/i386/mach-visws/Makefile b/arch/i386/mach-visws/Makefile --- a/arch/i386/mach-visws/Makefile Sun Mar 14 14:20:08 2004 +++ b/arch/i386/mach-visws/Makefile Sun Mar 14 14:20:08 2004 @@ -2,8 +2,6 @@ # Makefile for the linux kernel. # -EXTRA_CFLAGS += -I../kernel - obj-y := setup.o traps.o reboot.o obj-$(CONFIG_X86_VISWS_APIC) += visws_apic.o diff -Nru a/arch/i386/mach-voyager/voyager_smp.c b/arch/i386/mach-voyager/voyager_smp.c --- a/arch/i386/mach-voyager/voyager_smp.c Sun Mar 14 14:20:07 2004 +++ b/arch/i386/mach-voyager/voyager_smp.c Sun Mar 14 14:20:07 2004 @@ -623,7 +623,9 @@ ((virt_to_phys(page_table_copies)) & PAGE_MASK) | _PAGE_RW | _PAGE_USER | _PAGE_PRESENT; #else - ((unsigned long *)swapper_pg_dir)[0] = 0x102007; + ((unsigned long *)swapper_pg_dir)[0] = + (virt_to_phys(pg0) & PAGE_MASK) + | _PAGE_RW | _PAGE_USER | _PAGE_PRESENT; #endif if(quad_boot) { diff -Nru a/arch/i386/mm/discontig.c b/arch/i386/mm/discontig.c --- a/arch/i386/mm/discontig.c Sun Mar 14 14:20:07 2004 +++ b/arch/i386/mm/discontig.c Sun Mar 14 14:20:07 2004 @@ -66,7 +66,7 @@ extern void one_highpage_init(struct page *, int, int); extern struct e820map e820; -extern char _end; +extern unsigned long init_pg_tables_end; extern unsigned long highend_pfn, highstart_pfn; extern unsigned long max_low_pfn; extern unsigned long totalram_pages; @@ -237,7 +237,7 @@ reserve_pages = calculate_numa_remap_pages(); /* partially used pages are not usable - thus round upwards */ - system_start_pfn = min_low_pfn = PFN_UP(__pa(&_end)); + system_start_pfn = min_low_pfn = PFN_UP(init_pg_tables_end); find_max_pfn(); system_max_low_pfn = max_low_pfn = find_max_low_pfn(); diff -Nru a/arch/ia64/Kconfig b/arch/ia64/Kconfig --- a/arch/ia64/Kconfig Sun Mar 14 14:20:08 2004 +++ b/arch/ia64/Kconfig Sun Mar 14 14:20:08 2004 @@ -416,92 +416,13 @@ source "drivers/pcmcia/Kconfig" -source "drivers/parport/Kconfig" - endif endmenu -source "drivers/base/Kconfig" - -if !IA64_HP_SIM - -source "drivers/mtd/Kconfig" - -source "drivers/pnp/Kconfig" - -source "drivers/block/Kconfig" - -source "drivers/ide/Kconfig" - -source "drivers/ieee1394/Kconfig" - -source "drivers/message/i2o/Kconfig" - -source "drivers/md/Kconfig" - -source "drivers/message/fusion/Kconfig" - -endif - - -source "drivers/scsi/Kconfig" - -source "net/Kconfig" - - -if !IA64_HP_SIM - -source "drivers/isdn/Kconfig" - -source "drivers/cdrom/Kconfig" - -# -# input before char - char/joystick depends on it. As does USB. -# -source "drivers/input/Kconfig" - -source "drivers/char/Kconfig" - -source "drivers/i2c/Kconfig" - -#source drivers/misc/Config.in -source "drivers/media/Kconfig" - -endif - - -menu "Block devices" - depends on IA64_HP_SIM - -config BLK_DEV_LOOP - tristate "Loopback device support" - -config BLK_DEV_NBD - tristate "Network block device support" - depends on NET - -config BLK_DEV_RAM - tristate "RAM disk support" - -config BLK_DEV_RAM_SIZE - int "Default RAM disk size" - depends on BLK_DEV_RAM - default "4096" - -endmenu +source "drivers/Kconfig" source "fs/Kconfig" - -if !IA64_HP_SIM - -source "drivers/video/Kconfig" - -source "sound/Kconfig" - -source "drivers/usb/Kconfig" - -endif source "lib/Kconfig" diff -Nru a/arch/ia64/configs/zx1_defconfig b/arch/ia64/configs/zx1_defconfig --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/ia64/configs/zx1_defconfig Sun Mar 14 14:20:09 2004 @@ -0,0 +1,1078 @@ +# +# Automatically generated make config: don't edit +# + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_CLEAN_COMPILE is not set +CONFIG_STANDALONE=y +CONFIG_BROKEN=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_SYSCTL=y +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_HOTPLUG=y +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# Processor type and features +# +CONFIG_IA64=y +CONFIG_64BIT=y +CONFIG_MMU=y +CONFIG_RWSEM_XCHGADD_ALGORITHM=y +CONFIG_TIME_INTERPOLATION=y +CONFIG_EFI=y +# CONFIG_ITANIUM is not set +CONFIG_MCKINLEY=y +# CONFIG_IA64_GENERIC is not set +# CONFIG_IA64_DIG is not set +CONFIG_IA64_HP_ZX1=y +# CONFIG_IA64_SGI_SN2 is not set +# CONFIG_IA64_HP_SIM is not set +# CONFIG_IA64_PAGE_SIZE_4KB is not set +# CONFIG_IA64_PAGE_SIZE_8KB is not set +CONFIG_IA64_PAGE_SIZE_16KB=y +# CONFIG_IA64_PAGE_SIZE_64KB is not set +CONFIG_ACPI=y +CONFIG_ACPI_INTERPRETER=y +CONFIG_ACPI_KERNEL_CONFIG=y +CONFIG_IA64_L1_CACHE_SHIFT=7 +# CONFIG_MCKINLEY_ASTEP_SPECIFIC is not set +# CONFIG_NUMA is not set +CONFIG_VIRTUAL_MEM_MAP=y +CONFIG_IA64_MCA=y +# CONFIG_IA64_CYCLONE is not set +CONFIG_PM=y +CONFIG_IOSAPIC=y +CONFIG_FORCE_MAX_ZONEORDER=18 +# CONFIG_HUGETLB_PAGE_SIZE_4GB is not set +# CONFIG_HUGETLB_PAGE_SIZE_1GB is not set +# CONFIG_HUGETLB_PAGE_SIZE_256MB is not set +CONFIG_HUGETLB_PAGE_SIZE_64MB=y +# CONFIG_HUGETLB_PAGE_SIZE_16MB is not set +# CONFIG_HUGETLB_PAGE_SIZE_4MB is not set +# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set +# CONFIG_HUGETLB_PAGE_SIZE_256KB is not set +CONFIG_IA64_PAL_IDLE=y +CONFIG_SMP=y +CONFIG_NR_CPUS=16 +# CONFIG_PREEMPT is not set +CONFIG_HAVE_DEC_LOCK=y +CONFIG_IA32_SUPPORT=y +CONFIG_COMPAT=y +CONFIG_PERFMON=y +CONFIG_IA64_PALINFO=y +CONFIG_EFI_VARS=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_MISC=y + +# +# ACPI (Advanced Configuration and Power Interface) Support +# +CONFIG_ACPI_BOOT=y +CONFIG_ACPI_BUTTON=y +CONFIG_ACPI_FAN=y +CONFIG_ACPI_PROCESSOR=y +CONFIG_ACPI_THERMAL=y +# CONFIG_ACPI_DEBUG is not set +CONFIG_ACPI_BUS=y +CONFIG_ACPI_POWER=y +CONFIG_ACPI_PCI=y +CONFIG_ACPI_SYSTEM=y +# CONFIG_ACPI_RELAXED_AML is not set +CONFIG_PCI=y +CONFIG_PCI_DOMAINS=y +CONFIG_PCI_LEGACY_PROC=y +CONFIG_PCI_NAMES=y + +# +# PCI Hotplug Support +# +CONFIG_HOTPLUG_PCI=y +# CONFIG_HOTPLUG_PCI_FAKE is not set +CONFIG_HOTPLUG_PCI_ACPI=y +# CONFIG_HOTPLUG_PCI_CPCI is not set +# CONFIG_HOTPLUG_PCI_PCIE is not set +# CONFIG_HOTPLUG_PCI_SHPC is not set + +# +# PCMCIA/CardBus support +# +# CONFIG_PCMCIA is not set + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Generic Driver Options +# +# CONFIG_FW_LOADER is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play support +# + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_DCSSBLK is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set +CONFIG_BLK_DEV_IDECD=y +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set +# CONFIG_IDE_TASKFILE_IO is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=y +# CONFIG_BLK_DEV_OPTI621 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +# CONFIG_IDEDMA_PCI_AUTO is not set +CONFIG_BLK_DEV_ADMA=y +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +CONFIG_BLK_DEV_CMD64X=y +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +# CONFIG_BLK_DEV_VIA82CXXX is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +# CONFIG_BLK_DEV_HD is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set + +# +# Fusion MPT device support +# +CONFIG_FUSION=y +CONFIG_FUSION_BOOT=y +CONFIG_FUSION_MAX_SGE=40 + +# +# SCSI device support +# +CONFIG_SCSI=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=y +CONFIG_CHR_DEV_OSST=y +CONFIG_BLK_DEV_SR=y +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=y + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_REPORT_LUNS=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AACRAID is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_ADVANSYS is not set +CONFIG_SCSI_MEGARAID=y +# CONFIG_SCSI_SATA is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INITIO is not set +# CONFIG_SCSI_INIA100 is not set +CONFIG_SCSI_SYM53C8XX_2=y +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_PCI2000 is not set +# CONFIG_SCSI_PCI2220I is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +CONFIG_SCSI_QLOGIC_1280=y +CONFIG_SCSI_QLA2XXX=y +# CONFIG_SCSI_QLA21XX is not set +# CONFIG_SCSI_QLA22XX is not set +# CONFIG_SCSI_QLA2300 is not set +# CONFIG_SCSI_QLA2322 is not set +# CONFIG_SCSI_QLA6312 is not set +# CONFIG_SCSI_QLA6322 is not set +# CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +# CONFIG_NETLINK_DEV is not set +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set + +# +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS is not set +# CONFIG_IPV6 is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set + +# +# IP: Netfilter Configuration +# +# CONFIG_IP_NF_CONNTRACK is not set +# CONFIG_IP_NF_QUEUE is not set +# CONFIG_IP_NF_IPTABLES is not set +CONFIG_IP_NF_ARPTABLES=y +# CONFIG_IP_NF_ARPFILTER is not set +# CONFIG_IP_NF_ARP_MANGLE is not set +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +CONFIG_IPV6_SCTP__=y +# CONFIG_IP_SCTP is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +CONFIG_DUMMY=y +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set + +# +# Tulip family network device support +# +CONFIG_NET_TULIP=y +# CONFIG_DE2104X is not set +CONFIG_TULIP=y +CONFIG_TULIP_MWI=y +CONFIG_TULIP_MMIO=y +CONFIG_TULIP_NAPI=y +CONFIG_TULIP_NAPI_HW_MITIGATION=y +# CONFIG_DE4X5 is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_DM9102 is not set +# CONFIG_HP100 is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set +# CONFIG_DGRS is not set +# CONFIG_EEPRO100 is not set +CONFIG_E100=y +# CONFIG_E100_NAPI is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_VIA_RHINE is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +CONFIG_E1000=y +# CONFIG_E1000_NAPI is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SIS190 is not set +# CONFIG_SK98LIN is not set +CONFIG_TIGON3=y + +# +# Ethernet (10000 Mbit) +# +# CONFIG_IXGB is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +# CONFIG_NET_RADIO is not set + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# Bluetooth support +# +# CONFIG_BT is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +CONFIG_INPUT_JOYDEV=y +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PCIPS2 is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_HCDP=y +CONFIG_SERIAL_8250_ACPI=y +CONFIG_SERIAL_8250_NR_UARTS=8 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_RSA is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_NVRAM is not set +# CONFIG_GEN_RTC is not set +CONFIG_EFI_RTC=y +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +CONFIG_AGP=y +CONFIG_AGP_HP_ZX1=y +CONFIG_DRM=y +# CONFIG_DRM_TDFX is not set +# CONFIG_DRM_GAMMA is not set +# CONFIG_DRM_R128 is not set +CONFIG_DRM_RADEON=y +# CONFIG_DRM_MGA is not set +# CONFIG_DRM_SIS is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=y +CONFIG_I2C_ALGOPCF=y + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +# CONFIG_I2C_ELV is not set +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_I810 is not set +# CONFIG_I2C_ISA is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PROSAVAGE is not set +# CONFIG_I2C_SAVAGE4 is not set +# CONFIG_SCx200_ACB is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_VELLEMAN is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VOODOO3 is not set + +# +# I2C Hardware Sensors Chip support +# +# CONFIG_I2C_SENSOR is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ASB100 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_VIA686A is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +# CONFIG_EXT2_FS_POSIX_ACL is not set +# CONFIG_EXT2_FS_SECURITY is not set +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_XATTR=y +# CONFIG_EXT3_FS_POSIX_ACL is not set +# CONFIG_EXT3_FS_SECURITY is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +CONFIG_FS_MBCACHE=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +CONFIG_AUTOFS_FS=y +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +CONFIG_UDF_FS=y + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +CONFIG_HUGETLBFS=y +CONFIG_HUGETLB_PAGE=y +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V4=y +# CONFIG_NFS_DIRECTIO is not set +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +# CONFIG_NFSD_V4 is not set +# CONFIG_NFSD_TCP is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=y +CONFIG_SUNRPC=y +CONFIG_SUNRPC_GSS=y +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_NEC98_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +CONFIG_EFI_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_CODEPAGE_737=y +CONFIG_NLS_CODEPAGE_775=y +CONFIG_NLS_CODEPAGE_850=y +CONFIG_NLS_CODEPAGE_852=y +CONFIG_NLS_CODEPAGE_855=y +CONFIG_NLS_CODEPAGE_857=y +CONFIG_NLS_CODEPAGE_860=y +CONFIG_NLS_CODEPAGE_861=y +CONFIG_NLS_CODEPAGE_862=y +CONFIG_NLS_CODEPAGE_863=y +CONFIG_NLS_CODEPAGE_864=y +CONFIG_NLS_CODEPAGE_865=y +CONFIG_NLS_CODEPAGE_866=y +CONFIG_NLS_CODEPAGE_869=y +CONFIG_NLS_CODEPAGE_936=y +CONFIG_NLS_CODEPAGE_950=y +CONFIG_NLS_CODEPAGE_932=y +CONFIG_NLS_CODEPAGE_949=y +CONFIG_NLS_CODEPAGE_874=y +CONFIG_NLS_ISO8859_8=y +# CONFIG_NLS_CODEPAGE_1250 is not set +CONFIG_NLS_CODEPAGE_1251=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_ISO8859_2=y +CONFIG_NLS_ISO8859_3=y +CONFIG_NLS_ISO8859_4=y +CONFIG_NLS_ISO8859_5=y +CONFIG_NLS_ISO8859_6=y +CONFIG_NLS_ISO8859_7=y +CONFIG_NLS_ISO8859_9=y +CONFIG_NLS_ISO8859_13=y +CONFIG_NLS_ISO8859_14=y +CONFIG_NLS_ISO8859_15=y +CONFIG_NLS_KOI8_R=y +CONFIG_NLS_KOI8_U=y +CONFIG_NLS_UTF8=y + +# +# Graphics support +# +CONFIG_FB=y +# CONFIG_FB_CIRRUS is not set +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_IMSTT is not set +# CONFIG_FB_RIVA is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON_OLD is not set +CONFIG_FB_RADEON=y +CONFIG_FB_RADEON_I2C=y +CONFIG_FB_RADEON_DEBUG=y +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_PM3 is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +CONFIG_VGA_CONSOLE=y +# CONFIG_MDA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_PCI_CONSOLE=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Logo configuration +# +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LOGO_LINUX_CLUT224=y + +# +# Sound +# +CONFIG_SOUND=y + +# +# Advanced Linux Sound Architecture +# +CONFIG_SND=y +CONFIG_SND_SEQUENCER=y +# CONFIG_SND_SEQ_DUMMY is not set +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=y +CONFIG_SND_PCM_OSS=y +CONFIG_SND_SEQUENCER_OSS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set + +# +# Generic devices +# +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_VIRMIDI is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set + +# +# PCI devices +# +# CONFIG_SND_ALI5451 is not set +# CONFIG_SND_AZT3328 is not set +# CONFIG_SND_BT87X is not set +# CONFIG_SND_CS46XX is not set +# CONFIG_SND_CS4281 is not set +# CONFIG_SND_EMU10K1 is not set +# CONFIG_SND_KORG1212 is not set +# CONFIG_SND_NM256 is not set +# CONFIG_SND_RME32 is not set +# CONFIG_SND_RME96 is not set +# CONFIG_SND_RME9652 is not set +# CONFIG_SND_HDSP is not set +# CONFIG_SND_TRIDENT is not set +# CONFIG_SND_YMFPCI is not set +# CONFIG_SND_ALS4000 is not set +# CONFIG_SND_CMIPCI is not set +# CONFIG_SND_ENS1370 is not set +# CONFIG_SND_ENS1371 is not set +# CONFIG_SND_ES1938 is not set +# CONFIG_SND_ES1968 is not set +# CONFIG_SND_MAESTRO3 is not set +CONFIG_SND_FM801=y +# CONFIG_SND_ICE1712 is not set +# CONFIG_SND_ICE1724 is not set +# CONFIG_SND_INTEL8X0 is not set +# CONFIG_SND_SONICVIBES is not set +# CONFIG_SND_VIA82XX is not set +# CONFIG_SND_VX222 is not set + +# +# ALSA USB devices +# +# CONFIG_SND_USB_AUDIO is not set + +# +# Open Sound System +# +# CONFIG_SOUND_PRIME is not set + +# +# USB support +# +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +CONFIG_USB_BANDWIDTH=y +# CONFIG_USB_DYNAMIC_MINORS is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_UHCI_HCD=y + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH_TTY is not set +# CONFIG_USB_MIDI is not set +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=y +CONFIG_USB_HIDINPUT=y +# CONFIG_HID_FF is not set +CONFIG_USB_HIDDEV=y +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_XPAD is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# +# CONFIG_USB_DABUSB is not set + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set + +# +# USB port drivers +# + +# +# USB Serial Converter support +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_TIGL is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_BRLVGER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# Library routines +# +CONFIG_CRC32=y + +# +# Profiling support +# +# CONFIG_PROFILING is not set + +# +# Kernel hacking +# +CONFIG_IA64_GRANULE_16MB=y +# CONFIG_IA64_GRANULE_64MB is not set +CONFIG_DEBUG_KERNEL=y +CONFIG_IA64_PRINT_HAZARDS=y +# CONFIG_DISABLE_VHPT is not set +CONFIG_MAGIC_SYSRQ=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set +# CONFIG_IA64_DEBUG_CMPXCHG is not set +# CONFIG_IA64_DEBUG_IRQ is not set +# CONFIG_DEBUG_INFO is not set + +# +# Security options +# +# CONFIG_SECURITY is not set + +# +# Cryptographic options +# +# CONFIG_CRYPTO is not set diff -Nru a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c --- a/arch/ia64/hp/common/sba_iommu.c Sun Mar 14 14:20:06 2004 +++ b/arch/ia64/hp/common/sba_iommu.c Sun Mar 14 14:20:06 2004 @@ -1479,7 +1479,6 @@ #ifdef FULL_VALID_PDIR unsigned long index; #endif - unsigned int i; /* ** Firmware programs the base and size of a "safe IOVA space" @@ -1574,18 +1573,6 @@ /* Enable IOVA translation */ WRITE_REG(ioc->ibase | 1, ioc->ioc_hpa + IOC_IBASE); READ_REG(ioc->ioc_hpa + IOC_IBASE); - - /* Clear ROPE(N)_CONFIG AO bit. - ** Disables "NT Ordering" (~= !"Relaxed Ordering") - ** Overrides bit 1 in DMA Hint Sets. - ** Improves netperf UDP_STREAM by ~10% for tg3 on bcm5701. - */ - for (i=0; i<(8*8); i+=8) { - unsigned long rope_config; - rope_config = READ_REG(ioc->ioc_hpa + IOC_ROPE0_CFG + i); - rope_config &= ~IOC_ROPE_AO; - WRITE_REG(rope_config, ioc->ioc_hpa + IOC_ROPE0_CFG + i); - } } static void __init @@ -1659,26 +1646,25 @@ static void __init ioc_zx1_init(struct ioc *ioc) { + unsigned long rope_config; + unsigned int i; + if (ioc->rev < 0x20) panic(PFX "IOC 2.0 or later required for IOMMU support\n"); - ioc->dma_mask = 0xFFFFFFFFFFUL; + /* 38 bit memory controller + extra bit for range displaced by MMIO */ + ioc->dma_mask = (0x1UL << 39) - 1; - if (!iovp_shift) { - /* 64k is max iommu page size */ - iovp_shift = min(PAGE_SHIFT, 16); - iovp_size = (1 << iovp_shift); - iovp_mask = ~(iovp_size - 1); - } -} - -static void __init -ioc_sx1000_init(struct ioc *ioc) -{ - if (!iovp_shift) { - iovp_shift = 12; /* 4K for now */ - iovp_size = (1 << iovp_shift); - iovp_mask = ~(iovp_size - 1); + /* + ** Clear ROPE(N)_CONFIG AO bit. + ** Disables "NT Ordering" (~= !"Relaxed Ordering") + ** Overrides bit 1 in DMA Hint Sets. + ** Improves netperf UDP_STREAM by ~10% for tg3 on bcm5701. + */ + for (i=0; i<(8*8); i+=8) { + rope_config = READ_REG(ioc->ioc_hpa + IOC_ROPE0_CFG + i); + rope_config &= ~IOC_ROPE_AO; + WRITE_REG(rope_config, ioc->ioc_hpa + IOC_ROPE0_CFG + i); } } @@ -1692,8 +1678,6 @@ static struct ioc_iommu ioc_iommu_info[] __initdata = { { ZX1_IOC_ID, "zx1", ioc_zx1_init }, - { REO_IOC_ID, "REO", ioc_sx1000_init }, - { SX1000_IOC_ID, "sx1000", ioc_sx1000_init }, }; static struct ioc * __init @@ -1718,11 +1702,6 @@ ioc->rev = READ_REG(ioc->ioc_hpa + IOC_FCLASS) & 0xFFUL; ioc->dma_mask = 0xFFFFFFFFFFFFFFFFUL; /* conservative */ - if (iovp_shift) { - iovp_size = (1 << iovp_shift); - iovp_mask = ~(iovp_size - 1); - } - for (info = ioc_iommu_info; info < ioc_iommu_info + ARRAY_SIZE(ioc_iommu_info); info++) { if (ioc->func_id == info->func_id) { ioc->name = info->name; @@ -1730,6 +1709,10 @@ (info->init)(ioc); } } + + iovp_size = (1 << iovp_shift); + iovp_mask = ~(iovp_size - 1); + DBG_INIT("%s: PAGE_SIZE %ldK, iovp_size %ldK\n", __FUNCTION__, PAGE_SIZE >> 10, iovp_size >> 10); @@ -1929,9 +1912,20 @@ * For HWP0001, only SBA appears in ACPI namespace. It encloses the PCI * root bridges, and its CSR space includes the IOC function. */ - if (strncmp("HWP0001", dev_info->hardware_id.value, 7) == 0) + if (strncmp("HWP0001", dev_info->hardware_id.value, 7) == 0) { hpa += ZX1_IOC_OFFSET; + /* zx1 based systems default to kernel page size iommu pages */ + if (!iovp_shift) + iovp_shift = min(PAGE_SHIFT, 16); + } ACPI_MEM_FREE(dev_info); + + /* + * default anything not caught above or specified on cmdline to 4k + * iommu page size + */ + if (!iovp_shift) + iovp_shift = 12; ioc = ioc_init(hpa, device->handle); if (!ioc) diff -Nru a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c --- a/arch/ia64/hp/sim/simserial.c Sun Mar 14 14:20:07 2004 +++ b/arch/ia64/hp/sim/simserial.c Sun Mar 14 14:20:07 2004 @@ -636,7 +636,6 @@ #ifdef SIMSERIAL_DEBUG printk("rs_close: hung_up\n"); #endif - MOD_DEC_USE_COUNT; local_irq_restore(flags); return; } @@ -661,7 +660,6 @@ state->count = 0; } if (state->count) { - MOD_DEC_USE_COUNT; local_irq_restore(flags); return; } @@ -686,7 +684,6 @@ } info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); - MOD_DEC_USE_COUNT; } /* @@ -874,17 +871,12 @@ int retval, line; unsigned long page; - MOD_INC_USE_COUNT; line = tty->index; - if ((line < 0) || (line >= NR_PORTS)) { - MOD_DEC_USE_COUNT; + if ((line < 0) || (line >= NR_PORTS)) return -ENODEV; - } retval = get_async_struct(line, &info); - if (retval) { - MOD_DEC_USE_COUNT; + if (retval) return retval; - } tty->driver_data = info; info->tty = tty; @@ -895,10 +887,8 @@ if (!tmp_buf) { page = get_zeroed_page(GFP_KERNEL); - if (!page) { - /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */ + if (!page) return -ENOMEM; - } if (tmp_buf) free_page(page); else @@ -912,7 +902,6 @@ (info->flags & ASYNC_CLOSING)) { if (info->flags & ASYNC_CLOSING) interruptible_sleep_on(&info->close_wait); - /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */ #ifdef SERIAL_DO_RESTART return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); @@ -926,7 +915,6 @@ */ retval = startup(info); if (retval) { - /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */ return retval; } @@ -1042,6 +1030,7 @@ /* Initialize the tty_driver structure */ + hp_simserial_driver->owner = THIS_MODULE; hp_simserial_driver->driver_name = "simserial"; hp_simserial_driver->name = "ttyS"; hp_simserial_driver->major = TTY_MAJOR; diff -Nru a/arch/ia64/ia32/ia32_support.c b/arch/ia64/ia32/ia32_support.c --- a/arch/ia64/ia32/ia32_support.c Sun Mar 14 14:20:06 2004 +++ b/arch/ia64/ia32/ia32_support.c Sun Mar 14 14:20:06 2004 @@ -134,8 +134,6 @@ regs->r17 = (_TSS << 48) | (_LDT << 32) | (__u32) regs->r17; regs->r30 = load_desc(_LDT); /* LDTD */ load_TLS(&t->thread, smp_processor_id()); - - put_cpu(); } /* diff -Nru a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S --- a/arch/ia64/kernel/head.S Sun Mar 14 14:20:07 2004 +++ b/arch/ia64/kernel/head.S Sun Mar 14 14:20:07 2004 @@ -816,7 +816,7 @@ br.ret.sptk.many rp END(ia64_delay_loop) -GLOBAL_ENTRY(ia64_invoke_kernel_thread_helper) +GLOBAL_ENTRY(start_kernel_thread) .prologue .save rp, r0 // this is the end of the call-chain .body @@ -827,7 +827,7 @@ mov out0 = r8 br.call.sptk.many rp = sys_exit;; 1: br.sptk.few 1b // not reached -END(ia64_invoke_kernel_thread_helper) +END(start_kernel_thread) #ifdef CONFIG_IA64_BRL_EMU diff -Nru a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c --- a/arch/ia64/kernel/iosapic.c Sun Mar 14 14:20:07 2004 +++ b/arch/ia64/kernel/iosapic.c Sun Mar 14 14:20:07 2004 @@ -170,7 +170,7 @@ } static void -set_rte (unsigned int vector, unsigned int dest) +set_rte (unsigned int vector, unsigned int dest, int mask) { unsigned long pol, trigger, dmode; u32 low32, high32; @@ -205,6 +205,7 @@ low32 = ((pol << IOSAPIC_POLARITY_SHIFT) | (trigger << IOSAPIC_TRIGGER_SHIFT) | (dmode << IOSAPIC_DELIVERY_SHIFT) | + ((mask ? 1 : 0) << IOSAPIC_MASK_SHIFT) | vector); /* dest contains both id and eid */ @@ -509,7 +510,7 @@ (trigger == IOSAPIC_EDGE ? "edge" : "level"), dest, vector); /* program the IOSAPIC routing table */ - set_rte(vector, dest); + set_rte(vector, dest, 0); return vector; } @@ -557,7 +558,7 @@ (trigger == IOSAPIC_EDGE ? "edge" : "level"), dest, vector); /* program the IOSAPIC routing table */ - set_rte(vector, dest); + set_rte(vector, dest, 0); return vector; } @@ -583,7 +584,7 @@ trigger == IOSAPIC_EDGE ? "edge" : "level", dest, vector); /* program the IOSAPIC routing table */ - set_rte(vector, dest); + set_rte(vector, dest, 0); } void __init @@ -669,7 +670,7 @@ /* direct the interrupt vector to the running cpu id */ dest = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff; #endif - set_rte(vector, dest); + set_rte(vector, dest, 1); printk(KERN_INFO "IOSAPIC: vector %d -> CPU 0x%04x, enabled\n", vector, dest); diff -Nru a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c --- a/arch/ia64/kernel/irq_ia64.c Sun Mar 14 14:20:07 2004 +++ b/arch/ia64/kernel/irq_ia64.c Sun Mar 14 14:20:07 2004 @@ -57,6 +57,21 @@ }; EXPORT_SYMBOL(isa_irq_to_vector_map); +static inline void +irq_enter (void) +{ + preempt_count() += HARDIRQ_OFFSET; +} + +static inline void +irq_exit (void) +{ + preempt_count() -= IRQ_EXIT_OFFSET; + if (!in_interrupt() && local_softirq_pending()) + do_softirq(); + preempt_enable_no_resched(); +} + int ia64_alloc_vector (void) { diff -Nru a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c --- a/arch/ia64/kernel/mca.c Sun Mar 14 14:20:07 2004 +++ b/arch/ia64/kernel/mca.c Sun Mar 14 14:20:07 2004 @@ -103,8 +103,6 @@ static ia64_mc_info_t ia64_mc_info; -extern struct hw_interrupt_type irq_type_iosapic_level; - struct ia64_mca_tlb_info ia64_mca_tlb_list[NR_CPUS]; #define MAX_CPE_POLL_INTERVAL (15*60*HZ) /* 15 minutes */ @@ -1253,7 +1251,6 @@ if (irq_to_vector(irq) == cpev) { desc = irq_descp(irq); desc->status |= IRQ_PER_CPU; - desc->handler = &irq_type_iosapic_level; setup_irq(irq, &mca_cpe_irqaction); } ia64_mca_register_cpev(cpev); diff -Nru a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c --- a/arch/ia64/kernel/process.c Sun Mar 14 14:20:07 2004 +++ b/arch/ia64/kernel/process.c Sun Mar 14 14:20:07 2004 @@ -574,8 +574,8 @@ pid_t kernel_thread (int (*fn)(void *), void *arg, unsigned long flags) { - extern void ia64_invoke_kernel_thread_helper (void); - unsigned long *helper_fptr = (unsigned long *) &ia64_invoke_kernel_thread_helper; + extern void start_kernel_thread (void); + unsigned long *helper_fptr = (unsigned long *) &start_kernel_thread; struct { struct switch_stack sw; struct pt_regs pt; diff -Nru a/arch/ia64/kernel/sal.c b/arch/ia64/kernel/sal.c --- a/arch/ia64/kernel/sal.c Sun Mar 14 14:20:08 2004 +++ b/arch/ia64/kernel/sal.c Sun Mar 14 14:20:08 2004 @@ -10,7 +10,6 @@ #include #include -#include #include #include @@ -21,6 +20,12 @@ spinlock_t sal_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED; unsigned long sal_platform_features; +unsigned short sal_revision; +unsigned short sal_version; + +#define SAL_MAJOR(x) ((x) >> 8) +#define SAL_MINOR(x) ((x) & 0xff) + static struct { void *addr; /* function entry point */ void *gpval; /* gp value to use */ @@ -86,13 +91,98 @@ ia64_sal = (ia64_sal_handler) &pdesc; } +static void __init +check_versions (struct ia64_sal_systab *systab) +{ + sal_revision = (systab->sal_rev_major << 8) | systab->sal_rev_minor; + sal_version = (systab->sal_b_rev_major << 8) | systab->sal_b_rev_minor; + + /* Check for broken firmware */ + if ((sal_revision == SAL_VERSION_CODE(49, 29)) + && (sal_version == SAL_VERSION_CODE(49, 29))) + { + /* + * Old firmware for zx2000 prototypes have this weird version number, + * reset it to something sane. + */ + sal_revision = SAL_VERSION_CODE(2, 8); + sal_version = SAL_VERSION_CODE(0, 0); + } +} + +static void __init +sal_desc_entry_point (void *p) +{ + struct ia64_sal_desc_entry_point *ep = p; + ia64_pal_handler_init(__va(ep->pal_proc)); + ia64_sal_handler_init(__va(ep->sal_proc), __va(ep->gp)); +} + +#ifdef CONFIG_SMP +static void __init +set_smp_redirect (int flag) +{ + if (no_int_routing) + smp_int_redirect &= ~flag; + else + smp_int_redirect |= flag; +} +#else +#define set_smp_redirect(flag) do { } while (0) +#endif + +static void __init +sal_desc_platform_feature (void *p) +{ + struct ia64_sal_desc_platform_feature *pf = p; + sal_platform_features = pf->feature_mask; + + printk(KERN_INFO "SAL Platform features:"); + if (!sal_platform_features) { + printk(" None\n"); + return; + } + + if (sal_platform_features & IA64_SAL_PLATFORM_FEATURE_BUS_LOCK) + printk(" BusLock"); + if (sal_platform_features & IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT) { + printk(" IRQ_Redirection"); + set_smp_redirect(SMP_IRQ_REDIRECTION); + } + if (sal_platform_features & IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT) { + printk(" IPI_Redirection"); + set_smp_redirect(SMP_IPI_REDIRECTION); + } + if (sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT) + printk(" ITC_Drift"); + printk("\n"); +} + +#ifdef CONFIG_SMP +static void __init +sal_desc_ap_wakeup (void *p) +{ + struct ia64_sal_desc_ap_wakeup *ap = p; + + switch (ap->mechanism) { + case IA64_SAL_AP_EXTERNAL_INT: + ap_wakeup_vector = ap->vector; + printk(KERN_INFO "SAL: AP wakeup using external interrupt " + "vector 0x%lx\n", ap_wakeup_vector); + break; + default: + printk(KERN_ERR "SAL: AP wakeup mechanism unsupported!\n"); + break; + } +} +#else +static void __init sal_desc_ap_wakeup(void *p) { } +#endif void __init ia64_sal_init (struct ia64_sal_systab *systab) { - unsigned long min, max; char *p; - struct ia64_sal_desc_entry_point *ep; int i; if (!systab) { @@ -103,85 +193,34 @@ if (strncmp(systab->signature, "SST_", 4) != 0) printk(KERN_ERR "bad signature in system table!"); - /* - * revisions are coded in BCD, so %x does the job for us - */ - printk(KERN_INFO "SAL v%x.%x: oem=%.32s, product=%.32s\n", - systab->sal_rev_major, systab->sal_rev_minor, - systab->oem_id, systab->product_id); + check_versions(systab); - min = ~0UL; - max = 0; + /* revisions are coded in BCD, so %x does the job for us */ + printk(KERN_INFO "SAL %x.%x: %.32s %.32s%sversion %x.%x\n", + SAL_MAJOR(sal_revision), SAL_MINOR(sal_revision), + systab->oem_id, systab->product_id, + systab->product_id[0] ? " " : "", + SAL_MAJOR(sal_version), SAL_MINOR(sal_version)); p = (char *) (systab + 1); for (i = 0; i < systab->entry_count; i++) { /* - * The first byte of each entry type contains the type descriptor. + * The first byte of each entry type contains the type + * descriptor. */ switch (*p) { - case SAL_DESC_ENTRY_POINT: - ep = (struct ia64_sal_desc_entry_point *) p; - printk(KERN_INFO "SAL: entry: pal_proc=0x%lx, sal_proc=0x%lx\n", - ep->pal_proc, ep->sal_proc); - ia64_pal_handler_init(__va(ep->pal_proc)); - ia64_sal_handler_init(__va(ep->sal_proc), __va(ep->gp)); + case SAL_DESC_ENTRY_POINT: + sal_desc_entry_point(p); break; - - case SAL_DESC_PTC: + case SAL_DESC_PLATFORM_FEATURE: + sal_desc_platform_feature(p); + break; + case SAL_DESC_PTC: ia64_ptc_domain_info = (ia64_sal_desc_ptc_t *)p; break; - - case SAL_DESC_AP_WAKEUP: -#ifdef CONFIG_SMP - { - struct ia64_sal_desc_ap_wakeup *ap = (void *) p; - - switch (ap->mechanism) { - case IA64_SAL_AP_EXTERNAL_INT: - ap_wakeup_vector = ap->vector; - printk(KERN_INFO "SAL: AP wakeup using external interrupt " - "vector 0x%lx\n", ap_wakeup_vector); - break; - - default: - printk(KERN_ERR "SAL: AP wakeup mechanism unsupported!\n"); - break; - } - break; - } -#endif - case SAL_DESC_PLATFORM_FEATURE: - { - struct ia64_sal_desc_platform_feature *pf = (void *) p; - sal_platform_features = pf->feature_mask; - printk(KERN_INFO "SAL: Platform features "); - - if (pf->feature_mask & IA64_SAL_PLATFORM_FEATURE_BUS_LOCK) - printk("BusLock "); - if (pf->feature_mask & IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT) { - printk("IRQ_Redirection "); -#ifdef CONFIG_SMP - if (no_int_routing) - smp_int_redirect &= ~SMP_IRQ_REDIRECTION; - else - smp_int_redirect |= SMP_IRQ_REDIRECTION; -#endif - } - if (pf->feature_mask & IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT) { - printk("IPI_Redirection "); -#ifdef CONFIG_SMP - if (no_int_routing) - smp_int_redirect &= ~SMP_IPI_REDIRECTION; - else - smp_int_redirect |= SMP_IPI_REDIRECTION; -#endif - } - if (pf->feature_mask & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT) - printk("ITC_Drift "); - printk("\n"); - break; - } - + case SAL_DESC_AP_WAKEUP: + sal_desc_ap_wakeup(p); + break; } p += SAL_DESC_SIZE(*p); } diff -Nru a/arch/ia64/lib/swiotlb.c b/arch/ia64/lib/swiotlb.c --- a/arch/ia64/lib/swiotlb.c Sun Mar 14 14:20:08 2004 +++ b/arch/ia64/lib/swiotlb.c Sun Mar 14 14:20:08 2004 @@ -47,7 +47,7 @@ #define IO_TLB_SHIFT 11 /* - * Used to do a quick range check in swiotlb_unmap_single and swiotlb_sync_single, to see + * Used to do a quick range check in swiotlb_unmap_single and swiotlb_sync_single_*, to see * if the memory was in fact allocated by this API. */ static char *io_tlb_start, *io_tlb_end; @@ -381,11 +381,24 @@ * * If you perform a swiotlb_map_single() but wish to interrogate the buffer using the cpu, * yet do not wish to teardown the PCI dma mapping, you must call this function before - * doing so. At the next point you give the PCI dma address back to the card, the device - * again owns the buffer. + * doing so. At the next point you give the PCI dma address back to the card, you must + * first perform a swiotlb_dma_sync_for_device, and then the device again owns the buffer */ void -swiotlb_sync_single (struct device *hwdev, dma_addr_t dev_addr, size_t size, int dir) +swiotlb_sync_single_for_cpu (struct device *hwdev, dma_addr_t dev_addr, size_t size, int dir) +{ + char *dma_addr = phys_to_virt(dev_addr); + + if (dir == DMA_NONE) + BUG(); + if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end) + sync_single(hwdev, dma_addr, size, dir); + else if (dir == DMA_FROM_DEVICE) + mark_clean(dma_addr, size); +} + +void +swiotlb_sync_single_for_device (struct device *hwdev, dma_addr_t dev_addr, size_t size, int dir) { char *dma_addr = phys_to_virt(dev_addr); @@ -456,11 +469,24 @@ * Make physical memory consistent for a set of streaming mode DMA translations after a * transfer. * - * The same as swiotlb_dma_sync_single but for a scatter-gather list, same rules and + * The same as swiotlb_sync_single_* but for a scatter-gather list, same rules and * usage. */ void -swiotlb_sync_sg (struct device *hwdev, struct scatterlist *sg, int nelems, int dir) +swiotlb_sync_sg_for_cpu (struct device *hwdev, struct scatterlist *sg, int nelems, int dir) +{ + int i; + + if (dir == DMA_NONE) + BUG(); + + for (i = 0; i < nelems; i++, sg++) + if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg)) + sync_single(hwdev, (void *) sg->dma_address, sg->dma_length, dir); +} + +void +swiotlb_sync_sg_for_device (struct device *hwdev, struct scatterlist *sg, int nelems, int dir) { int i; @@ -488,8 +514,10 @@ EXPORT_SYMBOL(swiotlb_unmap_single); EXPORT_SYMBOL(swiotlb_map_sg); EXPORT_SYMBOL(swiotlb_unmap_sg); -EXPORT_SYMBOL(swiotlb_sync_single); -EXPORT_SYMBOL(swiotlb_sync_sg); +EXPORT_SYMBOL(swiotlb_sync_single_for_cpu); +EXPORT_SYMBOL(swiotlb_sync_single_for_device); +EXPORT_SYMBOL(swiotlb_sync_sg_for_cpu); +EXPORT_SYMBOL(swiotlb_sync_sg_for_device); EXPORT_SYMBOL(swiotlb_alloc_coherent); EXPORT_SYMBOL(swiotlb_free_coherent); EXPORT_SYMBOL(swiotlb_dma_supported); diff -Nru a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c --- a/arch/ia64/pci/pci.c Sun Mar 14 14:20:07 2004 +++ b/arch/ia64/pci/pci.c Sun Mar 14 14:20:07 2004 @@ -57,17 +57,16 @@ ((u64)(seg << 24) | (u64)(bus << 16) | \ (u64)(devfn << 8) | (u64)(reg)) - static int pci_sal_read (int seg, int bus, int devfn, int reg, int len, u32 *value) { int result = 0; u64 data = 0; - if (!value || (seg > 255) || (bus > 255) || (devfn > 255) || (reg > 255)) + if ((seg > 255) || (bus > 255) || (devfn > 255) || (reg > 255)) return -EINVAL; - result = ia64_sal_pci_config_read(PCI_SAL_ADDRESS(seg, bus, devfn, reg), len, &data); + result = ia64_sal_pci_config_read(PCI_SAL_ADDRESS(seg, bus, devfn, reg), 0, len, &data); *value = (u32) data; @@ -80,15 +79,62 @@ if ((seg > 255) || (bus > 255) || (devfn > 255) || (reg > 255)) return -EINVAL; - return ia64_sal_pci_config_write(PCI_SAL_ADDRESS(seg, bus, devfn, reg), len, value); + return ia64_sal_pci_config_write(PCI_SAL_ADDRESS(seg, bus, devfn, reg), 0, len, value); } -struct pci_raw_ops pci_sal_ops = { +static struct pci_raw_ops pci_sal_ops = { .read = pci_sal_read, .write = pci_sal_write }; -struct pci_raw_ops *raw_pci_ops = &pci_sal_ops; /* default to SAL */ +/* SAL 3.2 adds support for extended config space. */ + +#define PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg) \ + ((u64)(seg << 28) | (u64)(bus << 20) | \ + (u64)(devfn << 12) | (u64)(reg)) + +static int +pci_sal_ext_read (int seg, int bus, int devfn, int reg, int len, u32 *value) +{ + int result = 0; + u64 data = 0; + + if ((seg > 65535) || (bus > 255) || (devfn > 255) || (reg > 4095)) + return -EINVAL; + + result = ia64_sal_pci_config_read(PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg), 1, len, &data); + + *value = (u32) data; + + return result; +} + +static int +pci_sal_ext_write (int seg, int bus, int devfn, int reg, int len, u32 value) +{ + if ((seg > 65535) || (bus > 255) || (devfn > 255) || (reg > 4095)) + return -EINVAL; + + return ia64_sal_pci_config_write(PCI_SAL_EXT_ADDRESS(seg, bus, devfn, reg), 1, len, value); +} + +static struct pci_raw_ops pci_sal_ext_ops = { + .read = pci_sal_ext_read, + .write = pci_sal_ext_write +}; + +struct pci_raw_ops *raw_pci_ops = &pci_sal_ops; /* default to SAL < 3.2 */ + +static int __init +pci_set_sal_ops (void) +{ + if (sal_version >= SAL_VERSION_CODE(3, 2)) { + raw_pci_ops = &pci_sal_ext_ops; + } + return 0; +} + +arch_initcall(pci_set_sal_ops); static int @@ -139,7 +185,8 @@ } static int __devinit -alloc_resource (char *name, struct resource *root, unsigned long start, unsigned long end, unsigned long flags) +alloc_resource (char *name, struct resource *root, unsigned long start, unsigned long end, + unsigned long flags) { struct resource *res; diff -Nru a/arch/ia64/sn/io/hwgfs/ramfs.c b/arch/ia64/sn/io/hwgfs/ramfs.c --- a/arch/ia64/sn/io/hwgfs/ramfs.c Sun Mar 14 14:20:07 2004 +++ b/arch/ia64/sn/io/hwgfs/ramfs.c Sun Mar 14 14:20:07 2004 @@ -84,7 +84,7 @@ return hwgfs_mknod(dir, dentry, mode | S_IFDIR, 0); } -static int hwgfs_create(struct inode *dir, struct dentry *dentry, int mode) +static int hwgfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *unused) { return hwgfs_mknod(dir, dentry, mode | S_IFREG, 0); } diff -Nru a/arch/ia64/sn/io/machvec/pci_dma.c b/arch/ia64/sn/io/machvec/pci_dma.c --- a/arch/ia64/sn/io/machvec/pci_dma.c Sun Mar 14 14:20:06 2004 +++ b/arch/ia64/sn/io/machvec/pci_dma.c Sun Mar 14 14:20:06 2004 @@ -152,7 +152,7 @@ * pcibr_dmatrans_addr ignores a missing PCIIO_DMA_A64 flag on * PCI-X buses. */ - if (hwdev->consistent_dma_mask == ~0UL) + if (hwdev->dev.coherent_dma_mask == ~0UL) *dma_handle = pcibr_dmatrans_addr(vhdl, NULL, phys_addr, size, PCIIO_DMA_CMD | PCIIO_DMA_A64); else { @@ -169,7 +169,7 @@ } } - if (!*dma_handle || *dma_handle > hwdev->consistent_dma_mask) { + if (!*dma_handle || *dma_handle > hwdev->dev.coherent_dma_mask) { if (dma_map) { pcibr_dmamap_done(dma_map); pcibr_dmamap_free(dma_map); @@ -437,7 +437,8 @@ } /** - * sn_pci_dma_sync_single - make sure all DMAs have completed + * sn_pci_dma_sync_single_* - make sure all DMAs or CPU accesses + * have completed * @hwdev: device to sync * @dma_handle: DMA address to sync * @size: size of region @@ -448,14 +449,19 @@ * anything on our platform. */ void -sn_pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction) +sn_pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction) { return; +} +void +sn_pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction) +{ + return; } /** - * sn_pci_dma_sync_sg - make sure all DMAs have completed + * sn_pci_dma_sync_sg_* - make sure all DMAs or CPU accesses have completed * @hwdev: device to sync * @sg: scatterlist to sync * @nents: number of entries in the scatterlist @@ -466,10 +472,15 @@ * on our platform. */ void -sn_pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) +sn_pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) { return; +} +void +sn_pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) +{ + return; } /** @@ -602,28 +613,51 @@ EXPORT_SYMBOL(sn_dma_unmap_sg); void -sn_dma_sync_single(struct device *dev, dma_addr_t dma_handle, size_t size, +sn_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, + int direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + sn_pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle, size, (int)direction); +} +EXPORT_SYMBOL(sn_dma_sync_single_for_cpu); + +void +sn_dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, int direction) { BUG_ON(dev->bus != &pci_bus_type); - sn_pci_dma_sync_single(to_pci_dev(dev), dma_handle, size, (int)direction); + sn_pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle, size, (int)direction); +} +EXPORT_SYMBOL(sn_dma_sync_single_for_device); + +void +sn_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, + int direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + sn_pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg, nelems, (int)direction); } -EXPORT_SYMBOL(sn_dma_sync_single); +EXPORT_SYMBOL(sn_dma_sync_sg_for_cpu); void -sn_dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems, +sn_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, int direction) { BUG_ON(dev->bus != &pci_bus_type); - sn_pci_dma_sync_sg(to_pci_dev(dev), sg, nelems, (int)direction); + sn_pci_dma_sync_sg_for_device(to_pci_dev(dev), sg, nelems, (int)direction); } -EXPORT_SYMBOL(sn_dma_sync_sg); +EXPORT_SYMBOL(sn_dma_sync_sg_for_device); EXPORT_SYMBOL(sn_pci_unmap_single); EXPORT_SYMBOL(sn_pci_map_single); -EXPORT_SYMBOL(sn_pci_dma_sync_single); +EXPORT_SYMBOL(sn_pci_dma_sync_single_for_cpu); +EXPORT_SYMBOL(sn_pci_dma_sync_single_for_device); +EXPORT_SYMBOL(sn_pci_dma_sync_sg_for_cpu); +EXPORT_SYMBOL(sn_pci_dma_sync_sg_for_device); EXPORT_SYMBOL(sn_pci_map_sg); EXPORT_SYMBOL(sn_pci_unmap_sg); EXPORT_SYMBOL(sn_pci_alloc_consistent); diff -Nru a/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c Sun Mar 14 14:20:08 2004 +++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_dvr.c Sun Mar 14 14:20:08 2004 @@ -2501,7 +2501,7 @@ if (pcibr_soft->bs_pcix_num_funcs) { if (pcibr_soft->bs_pcix_num_funcs > NUM_RBAR) { printk(KERN_WARNING - "%lx: Must oversubscribe Read Buffer Attribute Registers" + "%s: Must oversubscribe Read Buffer Attribute Registers" "(RBAR). Bus has %d RBARs but %d funcs need them.\n", pcibr_soft->bs_name, NUM_RBAR, pcibr_soft->bs_pcix_num_funcs); percent_allowed = 0; @@ -2603,7 +2603,7 @@ memset(buffer, 0, 1024); vsnprintf(buffer, 1024, format, ap); va_end(ap); - printk("", "%s", buffer); + printk("%s", buffer); kfree(buffer); } } diff -Nru a/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c b/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c --- a/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c Sun Mar 14 14:20:08 2004 +++ b/arch/ia64/sn/io/sn2/pcibr/pcibr_intr.c Sun Mar 14 14:20:08 2004 @@ -101,7 +101,7 @@ { nasid_t nasid; int wid_num; - volatile struct sn_flush_device_list *p; + struct sn_flush_device_list *p; int i,j; int bwin; unsigned long flags; diff -Nru a/arch/ia64/sn/io/sn2/pciio.c b/arch/ia64/sn/io/sn2/pciio.c --- a/arch/ia64/sn/io/sn2/pciio.c Sun Mar 14 14:20:08 2004 +++ b/arch/ia64/sn/io/sn2/pciio.c Sun Mar 14 14:20:08 2004 @@ -822,7 +822,7 @@ pciio_info_t pciio_info) { char name[32]; - vertex_hdl_t pconn; + vertex_hdl_t pconn = NULL; if (!pciio_info) return; @@ -835,7 +835,6 @@ hwgraph_vertex_unref(pconn); hwgraph_vertex_destroy(pconn); - } /*ARGSUSED */ diff -Nru a/arch/ia64/sn/io/sn2/shub_intr.c b/arch/ia64/sn/io/sn2/shub_intr.c --- a/arch/ia64/sn/io/sn2/shub_intr.c Sun Mar 14 14:20:07 2004 +++ b/arch/ia64/sn/io/sn2/shub_intr.c Sun Mar 14 14:20:07 2004 @@ -200,7 +200,6 @@ int cpuphys, slice; nasid_t nasid; unsigned long xtalk_addr; - void *bridge = intr->bi_soft->bs_base; int irq; int i; int old_cpu; @@ -237,13 +236,13 @@ for (bit = 0; bit < 8; bit++) { if (intr->bi_ibits & (1 << bit) ) { /* Disable interrupts. */ - pcireg_intr_enable_bit_clr(bridge, bit); + pcireg_intr_enable_bit_clr(intr->bi_soft, bit); /* Reset Host address (Interrupt destination) */ - pcireg_intr_addr_addr_set(bridge, bit, xtalk_addr); + pcireg_intr_addr_addr_set(intr->bi_soft, bit, xtalk_addr); /* Enable interrupt */ - pcireg_intr_enable_bit_set(bridge, bit); + pcireg_intr_enable_bit_set(intr->bi_soft, bit); /* Force an interrupt, just in case. */ - pcireg_force_intr_set(bridge, bit); + pcireg_force_intr_set(intr->bi_soft, bit); } } irq = intr->bi_irq; diff -Nru a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c --- a/arch/ia64/sn/kernel/irq.c Sun Mar 14 14:20:06 2004 +++ b/arch/ia64/sn/kernel/irq.c Sun Mar 14 14:20:06 2004 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -118,10 +119,11 @@ } static void -sn_set_affinity_irq(unsigned int irq, unsigned long cpu) +sn_set_affinity_irq(unsigned int irq, cpumask_t mask) { #ifdef CONFIG_SMP int redir = 0; + int cpu; struct sn_intr_list_t *p = sn_intr_list[irq]; pcibr_intr_t intr; extern void sn_shub_redirect_intr(pcibr_intr_t intr, unsigned long cpu); @@ -135,7 +137,9 @@ if (intr == NULL) return; + cpu = first_cpu(mask); sn_shub_redirect_intr(intr, cpu); + irq = irq & 0xff; /* strip off redirect bit, if someone stuck it on. */ (void) set_irq_affinity_info(irq, cpu_physical_id(intr->bi_cpu), redir); #endif /* CONFIG_SMP */ } diff -Nru a/arch/m68k/amiga/amiints.c b/arch/m68k/amiga/amiints.c --- a/arch/m68k/amiga/amiints.c Sun Mar 14 14:20:09 2004 +++ b/arch/m68k/amiga/amiints.c Sun Mar 14 14:20:09 2004 @@ -197,7 +197,7 @@ } if (irq >= IRQ_AMIGA_AUTO) - return sys_request_irq(irq - IRQ_AMIGA_AUTO, handler, + return cpu_request_irq(irq - IRQ_AMIGA_AUTO, handler, flags, devname, dev_id); if (irq >= IRQ_AMIGA_CIAB) @@ -244,7 +244,7 @@ } if (irq >= IRQ_AMIGA_AUTO) - sys_free_irq(irq - IRQ_AMIGA_AUTO, dev_id); + cpu_free_irq(irq - IRQ_AMIGA_AUTO, dev_id); if (irq >= IRQ_AMIGA_CIAB) { cia_free_irq(&ciab_base, irq - IRQ_AMIGA_CIAB, dev_id); diff -Nru a/arch/m68k/bvme6000/bvmeints.c b/arch/m68k/bvme6000/bvmeints.c --- a/arch/m68k/bvme6000/bvmeints.c Sun Mar 14 14:20:06 2004 +++ b/arch/m68k/bvme6000/bvmeints.c Sun Mar 14 14:20:06 2004 @@ -73,7 +73,7 @@ */ if (irq >= VEC_INT1 && irq <= VEC_INT7) - return sys_request_irq(irq - VEC_SPUR, handler, flags, + return cpu_request_irq(irq - VEC_SPUR, handler, flags, devname, dev_id); #endif if (!(irq_tab[irq].flags & IRQ_FLG_STD)) { @@ -103,7 +103,7 @@ } #if 0 if (irq >= VEC_INT1 && irq <= VEC_INT7) { - sys_free_irq(irq - VEC_SPUR, dev_id); + cpu_free_irq(irq - VEC_SPUR, dev_id); return; } #endif diff -Nru a/arch/m68k/hp300/time.c b/arch/m68k/hp300/time.c --- a/arch/m68k/hp300/time.c Sun Mar 14 14:20:08 2004 +++ b/arch/m68k/hp300/time.c Sun Mar 14 14:20:08 2004 @@ -68,7 +68,7 @@ asm volatile(" movpw %0,%1@(5)" : : "d" (INTVAL), "a" (CLOCKBASE)); - sys_request_irq(6, hp300_tick, IRQ_FLG_STD, "timer tick", vector); + cpu_request_irq(6, hp300_tick, IRQ_FLG_STD, "timer tick", vector); out_8(CLOCKBASE + CLKCR2, 0x1); /* select CR1 */ out_8(CLOCKBASE + CLKCR1, 0x40); /* enable irq */ diff -Nru a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S --- a/arch/m68k/kernel/entry.S Sun Mar 14 14:20:05 2004 +++ b/arch/m68k/kernel/entry.S Sun Mar 14 14:20:05 2004 @@ -528,7 +528,7 @@ .long sys_ni_syscall /* old profil syscall holder */ .long sys_statfs .long sys_fstatfs /* 100 */ - .long sys_ioperm + .long sys_ni_syscall /* ioperm for i386 */ .long sys_socketcall .long sys_syslog .long sys_setitimer diff -Nru a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c --- a/arch/m68k/kernel/ints.c Sun Mar 14 14:20:07 2004 +++ b/arch/m68k/kernel/ints.c Sun Mar 14 14:20:07 2004 @@ -137,8 +137,8 @@ EXPORT_SYMBOL(free_irq); -int sys_request_irq(unsigned int irq, - irqreturn_t (*handler)(int, void *, struct pt_regs *), +int cpu_request_irq(unsigned int irq, + irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id) { if (irq < IRQ1 || irq > IRQ7) { @@ -169,7 +169,7 @@ return 0; } -void sys_free_irq(unsigned int irq, void *dev_id) +void cpu_free_irq(unsigned int irq, void *dev_id) { if (irq < IRQ1 || irq > IRQ7) { printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq); diff -Nru a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c --- a/arch/m68k/kernel/sys_m68k.c Sun Mar 14 14:20:06 2004 +++ b/arch/m68k/kernel/sys_m68k.c Sun Mar 14 14:20:06 2004 @@ -261,12 +261,6 @@ return -EINVAL; } -asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on) -{ - return -ENOSYS; -} - - /* Convert virtual (user) address VADDR to physical address PADDR */ #define virt_to_phys_040(vaddr) \ ({ \ diff -Nru a/arch/m68k/mac/iop.c b/arch/m68k/mac/iop.c --- a/arch/m68k/mac/iop.c Sun Mar 14 14:20:08 2004 +++ b/arch/m68k/mac/iop.c Sun Mar 14 14:20:08 2004 @@ -317,7 +317,7 @@ { if (iop_ism_present) { if (oss_present) { - sys_request_irq(OSS_IRQLEV_IOPISM, iop_ism_irq, + cpu_request_irq(OSS_IRQLEV_IOPISM, iop_ism_irq, IRQ_FLG_LOCK, "ISM IOP", (void *) IOP_NUM_ISM); oss_irq_enable(IRQ_MAC_ADB); diff -Nru a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c --- a/arch/m68k/mac/macints.c Sun Mar 14 14:20:08 2004 +++ b/arch/m68k/mac/macints.c Sun Mar 14 14:20:08 2004 @@ -261,7 +261,8 @@ if (psc_present) psc_register_interrupts(); if (baboon_present) baboon_register_interrupts(); iop_register_interrupts(); - sys_request_irq(7, mac_nmi_handler, IRQ_FLG_LOCK, "NMI", mac_nmi_handler); + cpu_request_irq(7, mac_nmi_handler, IRQ_FLG_LOCK, "NMI", + mac_nmi_handler); #ifdef DEBUG_MACINTS printk("mac_init_IRQ(): Done!\n"); #endif @@ -507,7 +508,7 @@ #endif if (irq < VIA1_SOURCE_BASE) { - return sys_request_irq(irq, handler, flags, devname, dev_id); + return cpu_request_irq(irq, handler, flags, devname, dev_id); } if (irq >= NUM_MAC_SOURCES) { @@ -544,7 +545,7 @@ #endif if (irq < VIA1_SOURCE_BASE) { - return sys_free_irq(irq, dev_id); + return cpu_free_irq(irq, dev_id); } if (irq >= NUM_MAC_SOURCES) { diff -Nru a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c --- a/arch/m68k/mac/oss.c Sun Mar 14 14:20:07 2004 +++ b/arch/m68k/mac/oss.c Sun Mar 14 14:20:07 2004 @@ -67,15 +67,15 @@ void __init oss_register_interrupts(void) { - sys_request_irq(OSS_IRQLEV_SCSI, oss_irq, IRQ_FLG_LOCK, + cpu_request_irq(OSS_IRQLEV_SCSI, oss_irq, IRQ_FLG_LOCK, "scsi", (void *) oss); - sys_request_irq(OSS_IRQLEV_IOPSCC, mac_scc_dispatch, IRQ_FLG_LOCK, + cpu_request_irq(OSS_IRQLEV_IOPSCC, mac_scc_dispatch, IRQ_FLG_LOCK, "scc", mac_scc_dispatch); - sys_request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, IRQ_FLG_LOCK, + cpu_request_irq(OSS_IRQLEV_NUBUS, oss_nubus_irq, IRQ_FLG_LOCK, "nubus", (void *) oss); - sys_request_irq(OSS_IRQLEV_SOUND, oss_irq, IRQ_FLG_LOCK, + cpu_request_irq(OSS_IRQLEV_SOUND, oss_irq, IRQ_FLG_LOCK, "sound", (void *) oss); - sys_request_irq(OSS_IRQLEV_VIA1, via1_irq, IRQ_FLG_LOCK, + cpu_request_irq(OSS_IRQLEV_VIA1, via1_irq, IRQ_FLG_LOCK, "via1", (void *) via1); } diff -Nru a/arch/m68k/mac/psc.c b/arch/m68k/mac/psc.c --- a/arch/m68k/mac/psc.c Sun Mar 14 14:20:07 2004 +++ b/arch/m68k/mac/psc.c Sun Mar 14 14:20:07 2004 @@ -117,14 +117,10 @@ void __init psc_register_interrupts(void) { - sys_request_irq(3, psc_irq, IRQ_FLG_LOCK, "psc3", - (void *) 0x30); - sys_request_irq(4, psc_irq, IRQ_FLG_LOCK, "psc4", - (void *) 0x40); - sys_request_irq(5, psc_irq, IRQ_FLG_LOCK, "psc5", - (void *) 0x50); - sys_request_irq(6, psc_irq, IRQ_FLG_LOCK, "psc6", - (void *) 0x60); + cpu_request_irq(3, psc_irq, IRQ_FLG_LOCK, "psc3", (void *) 0x30); + cpu_request_irq(4, psc_irq, IRQ_FLG_LOCK, "psc4", (void *) 0x40); + cpu_request_irq(5, psc_irq, IRQ_FLG_LOCK, "psc5", (void *) 0x50); + cpu_request_irq(6, psc_irq, IRQ_FLG_LOCK, "psc6", (void *) 0x60); } /* diff -Nru a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c --- a/arch/m68k/mac/via.c Sun Mar 14 14:20:07 2004 +++ b/arch/m68k/mac/via.c Sun Mar 14 14:20:07 2004 @@ -260,24 +260,27 @@ void __init via_register_interrupts(void) { if (via_alt_mapping) { - sys_request_irq(IRQ_AUTO_1, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, - "software", (void *) via1); - sys_request_irq(IRQ_AUTO_6, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, - "via1", (void *) via1); + cpu_request_irq(IRQ_AUTO_1, via1_irq, + IRQ_FLG_LOCK|IRQ_FLG_FAST, "software", + (void *) via1); + cpu_request_irq(IRQ_AUTO_6, via1_irq, + IRQ_FLG_LOCK|IRQ_FLG_FAST, "via1", + (void *) via1); } else { - sys_request_irq(IRQ_AUTO_1, via1_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, - "via1", (void *) via1); + cpu_request_irq(IRQ_AUTO_1, via1_irq, + IRQ_FLG_LOCK|IRQ_FLG_FAST, "via1", + (void *) via1); #if 0 /* interferes with serial on some machines */ if (!psc_present) { - sys_request_irq(IRQ_AUTO_6, mac_bang, IRQ_FLG_LOCK, + cpu_request_irq(IRQ_AUTO_6, mac_bang, IRQ_FLG_LOCK, "Off Switch", mac_bang); } #endif } - sys_request_irq(IRQ_AUTO_2, via2_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, + cpu_request_irq(IRQ_AUTO_2, via2_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, "via2", (void *) via2); if (!psc_present) { - sys_request_irq(IRQ_AUTO_4, mac_scc_dispatch, IRQ_FLG_LOCK, + cpu_request_irq(IRQ_AUTO_4, mac_scc_dispatch, IRQ_FLG_LOCK, "scc", mac_scc_dispatch); } request_irq(IRQ_MAC_NUBUS, via_nubus_irq, IRQ_FLG_LOCK|IRQ_FLG_FAST, diff -Nru a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c --- a/arch/m68k/q40/config.c Sun Mar 14 14:20:07 2004 +++ b/arch/m68k/q40/config.c Sun Mar 14 14:20:07 2004 @@ -40,7 +40,7 @@ extern void floppy_setup(char *str, int *ints); extern irqreturn_t q40_process_int (int level, struct pt_regs *regs); -extern irqreturn_t (*q40_sys_default_handler[]) (int, void *, struct pt_regs *); /* added just for debugging */ +extern irqreturn_t (*q40_default_handler[]) (int, void *, struct pt_regs *); /* added just for debugging */ extern void q40_init_IRQ (void); extern void q40_free_irq (unsigned int, void *); extern int show_q40_interrupts (struct seq_file *, void *); @@ -185,7 +185,7 @@ mach_request_irq = q40_request_irq; enable_irq = q40_enable_irq; disable_irq = q40_disable_irq; - mach_default_handler = &q40_sys_default_handler; + mach_default_handler = &q40_default_handler; mach_get_model = q40_get_model; mach_get_hardware_list = q40_get_hardware_list; diff -Nru a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c --- a/arch/m68k/q40/q40ints.c Sun Mar 14 14:20:08 2004 +++ b/arch/m68k/q40/q40ints.c Sun Mar 14 14:20:08 2004 @@ -46,10 +46,8 @@ irqreturn_t q40_irq2_handler (int, void *, struct pt_regs *fp); -extern irqreturn_t (*q40_sys_default_handler[]) (int, void *, struct pt_regs *); - static irqreturn_t q40_defhand (int irq, void *dev_id, struct pt_regs *fp); -static irqreturn_t sys_default_handler(int lev, void *dev_id, struct pt_regs *regs); +static irqreturn_t default_handler(int lev, void *dev_id, struct pt_regs *regs); #define DEVNAME_SIZE 24 @@ -96,7 +94,8 @@ } /* setup handler for ISA ints */ - sys_request_irq(IRQ2,q40_irq2_handler, 0, "q40 ISA and master chip", NULL); + cpu_request_irq(IRQ2, q40_irq2_handler, 0, "q40 ISA and master chip", + NULL); /* now enable some ints.. */ master_outb(1,EXT_ENABLE_REG); /* ISA IRQ 5-15 */ @@ -153,8 +152,8 @@ } else { /* Q40_IRQ_SAMPLE :somewhat special actions required here ..*/ - sys_request_irq(4,handler,flags,devname,dev_id); - sys_request_irq(6,handler,flags,devname,dev_id); + cpu_request_irq(4, handler, flags, devname, dev_id); + cpu_request_irq(6, handler, flags, devname, dev_id); return 0; } } @@ -192,8 +191,8 @@ } else { /* == Q40_IRQ_SAMPLE */ - sys_free_irq(4,dev_id); - sys_free_irq(6,dev_id); + cpu_free_irq(4, dev_id); + cpu_free_irq(6, dev_id); } } @@ -417,16 +416,16 @@ else master_outb(-1,KEYBOARD_UNLOCK_REG); return IRQ_NONE; } -static irqreturn_t sys_default_handler(int lev, void *dev_id, struct pt_regs *regs) +static irqreturn_t default_handler(int lev, void *dev_id, struct pt_regs *regs) { printk ("Uninitialised interrupt level %d\n", lev); return IRQ_NONE; } - irqreturn_t (*q40_sys_default_handler[SYS_IRQS]) (int, void *, struct pt_regs *) = { - sys_default_handler,sys_default_handler,sys_default_handler,sys_default_handler, - sys_default_handler,sys_default_handler,sys_default_handler,sys_default_handler - }; +irqreturn_t (*q40_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = { + default_handler, default_handler, default_handler, default_handler, + default_handler, default_handler, default_handler, default_handler +}; void q40_enable_irq (unsigned int irq) diff -Nru a/arch/m68k/sun3/sun3ints.c b/arch/m68k/sun3/sun3ints.c --- a/arch/m68k/sun3/sun3ints.c Sun Mar 14 14:20:08 2004 +++ b/arch/m68k/sun3/sun3ints.c Sun Mar 14 14:20:08 2004 @@ -153,8 +153,8 @@ for(i = 0; i < SYS_IRQS; i++) { if(dev_names[i]) - sys_request_irq(i, sun3_default_handler[i], - 0, dev_names[i], NULL); + cpu_request_irq(i, sun3_default_handler[i], 0, + dev_names[i], NULL); } for(i = 0; i < 192; i++) @@ -178,7 +178,8 @@ dev_names[irq] = devname; /* setting devname would be nice */ - sys_request_irq(irq, sun3_default_handler[irq], 0, devname, NULL); + cpu_request_irq(irq, sun3_default_handler[irq], 0, devname, + NULL); return 0; } else { diff -Nru a/arch/m68knommu/kernel/sys_m68k.c b/arch/m68knommu/kernel/sys_m68k.c --- a/arch/m68knommu/kernel/sys_m68k.c Sun Mar 14 14:20:08 2004 +++ b/arch/m68knommu/kernel/sys_m68k.c Sun Mar 14 14:20:08 2004 @@ -193,12 +193,6 @@ return -EINVAL; } -asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on) -{ - return -ENOSYS; -} - - /* sys_cacheflush -- flush (part of) the processor cache. */ asmlinkage int sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len) diff -Nru a/arch/m68knommu/kernel/syscalltable.S b/arch/m68knommu/kernel/syscalltable.S --- a/arch/m68knommu/kernel/syscalltable.S Sun Mar 14 14:20:05 2004 +++ b/arch/m68knommu/kernel/syscalltable.S Sun Mar 14 14:20:05 2004 @@ -120,7 +120,7 @@ .long sys_ni_syscall /* old profil syscall holder */ .long sys_statfs .long sys_fstatfs /* 100 */ - .long sys_ioperm + .long sys_ni_syscall /* ioperm for i386 */ .long sys_socketcall .long sys_syslog .long sys_setitimer diff -Nru a/arch/mips/mm/dma-coherent.c b/arch/mips/mm/dma-coherent.c --- a/arch/mips/mm/dma-coherent.c Sun Mar 14 14:20:07 2004 +++ b/arch/mips/mm/dma-coherent.c Sun Mar 14 14:20:07 2004 @@ -119,30 +119,55 @@ EXPORT_SYMBOL(dma_unmap_sg); -void dma_sync_single(struct device *dev, dma_addr_t dma_handle, size_t size, +void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, enum dma_data_direction direction) { BUG_ON(direction == DMA_NONE); } -EXPORT_SYMBOL(dma_sync_single); +EXPORT_SYMBOL(dma_sync_single_for_cpu); -void dma_sync_single_range(struct device *dev, dma_addr_t dma_handle, +void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(direction == DMA_NONE); +} + +EXPORT_SYMBOL(dma_sync_single_for_device); + +void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(direction == DMA_NONE); +} + +EXPORT_SYMBOL(dma_sync_single_range_for_cpu); + +void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, unsigned long offset, size_t size, enum dma_data_direction direction) { BUG_ON(direction == DMA_NONE); } -EXPORT_SYMBOL(dma_sync_single_range); +EXPORT_SYMBOL(dma_sync_single_range_for_device); -void dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems, +void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, enum dma_data_direction direction) { BUG_ON(direction == DMA_NONE); } -EXPORT_SYMBOL(dma_sync_sg); +EXPORT_SYMBOL(dma_sync_sg_for_cpu); + +void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ + BUG_ON(direction == DMA_NONE); +} + +EXPORT_SYMBOL(dma_sync_sg_for_device); int dma_supported(struct device *dev, u64 mask) { @@ -204,12 +229,20 @@ EXPORT_SYMBOL(pci_dac_dma_to_offset); -void pci_dac_dma_sync_single(struct pci_dev *pdev, +void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, + dma64_addr_t dma_addr, size_t len, int direction) +{ + BUG_ON(direction == PCI_DMA_NONE); +} + +EXPORT_SYMBOL(pci_dac_dma_sync_single_for_cpu); + +void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction) { BUG_ON(direction == PCI_DMA_NONE); } -EXPORT_SYMBOL(pci_dac_dma_sync_single); +EXPORT_SYMBOL(pci_dac_dma_sync_single_for_device); #endif /* CONFIG_PCI */ diff -Nru a/arch/mips/mm/dma-ip27.c b/arch/mips/mm/dma-ip27.c --- a/arch/mips/mm/dma-ip27.c Sun Mar 14 14:20:08 2004 +++ b/arch/mips/mm/dma-ip27.c Sun Mar 14 14:20:08 2004 @@ -125,30 +125,55 @@ EXPORT_SYMBOL(dma_unmap_sg); -void dma_sync_single(struct device *dev, dma_addr_t dma_handle, size_t size, +void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, enum dma_data_direction direction) { BUG_ON(direction == DMA_NONE); } -EXPORT_SYMBOL(dma_sync_single); +EXPORT_SYMBOL(dma_sync_single_for_cpu); -void dma_sync_single_range(struct device *dev, dma_addr_t dma_handle, +void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(direction == DMA_NONE); +} + +EXPORT_SYMBOL(dma_sync_single_for_device); + +void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + BUG_ON(direction == DMA_NONE); +} + +EXPORT_SYMBOL(dma_sync_single_range_for_cpu); + +void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, unsigned long offset, size_t size, enum dma_data_direction direction) { BUG_ON(direction == DMA_NONE); } -EXPORT_SYMBOL(dma_sync_single_range); +EXPORT_SYMBOL(dma_sync_single_range_for_device); -void dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems, +void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, enum dma_data_direction direction) { BUG_ON(direction == DMA_NONE); } -EXPORT_SYMBOL(dma_sync_sg); +EXPORT_SYMBOL(dma_sync_sg_for_cpu); + +void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ + BUG_ON(direction == DMA_NONE); +} + +EXPORT_SYMBOL(dma_sync_sg_for_device); int dma_supported(struct device *dev, u64 mask) { @@ -208,10 +233,18 @@ EXPORT_SYMBOL(pci_dac_dma_to_offset); -void pci_dac_dma_sync_single(struct pci_dev *pdev, +void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, + dma64_addr_t dma_addr, size_t len, int direction) +{ + BUG_ON(direction == PCI_DMA_NONE); +} + +EXPORT_SYMBOL(pci_dac_dma_sync_single_for_cpu); + +void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction) { BUG_ON(direction == PCI_DMA_NONE); } -EXPORT_SYMBOL(pci_dac_dma_sync_single); +EXPORT_SYMBOL(pci_dac_dma_sync_single_for_device); diff -Nru a/arch/mips/mm/dma-noncoherent.c b/arch/mips/mm/dma-noncoherent.c --- a/arch/mips/mm/dma-noncoherent.c Sun Mar 14 14:20:06 2004 +++ b/arch/mips/mm/dma-noncoherent.c Sun Mar 14 14:20:06 2004 @@ -226,7 +226,7 @@ EXPORT_SYMBOL(dma_unmap_sg); -void dma_sync_single(struct device *dev, dma_addr_t dma_handle, size_t size, +void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, enum dma_data_direction direction) { unsigned long addr; @@ -237,9 +237,35 @@ __dma_sync(addr, size, direction); } -EXPORT_SYMBOL(dma_sync_single); +EXPORT_SYMBOL(dma_sync_single_for_cpu); -void dma_sync_single_range(struct device *dev, dma_addr_t dma_handle, +void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) +{ + unsigned long addr; + + BUG_ON(direction == DMA_NONE); + + addr = dma_handle + PAGE_OFFSET; + __dma_sync(addr, size, direction); +} + +EXPORT_SYMBOL(dma_sync_single_for_device); + +void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, enum dma_data_direction direction) +{ + unsigned long addr; + + BUG_ON(direction == DMA_NONE); + + addr = dma_handle + offset + PAGE_OFFSET; + __dma_sync(addr, size, direction); +} + +EXPORT_SYMBOL(dma_sync_single_range_for_cpu); + +void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, unsigned long offset, size_t size, enum dma_data_direction direction) { unsigned long addr; @@ -250,9 +276,9 @@ __dma_sync(addr, size, direction); } -EXPORT_SYMBOL(dma_sync_single_range); +EXPORT_SYMBOL(dma_sync_single_range_for_device); -void dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems, +void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, enum dma_data_direction direction) { int i; @@ -265,7 +291,22 @@ sg->length, direction); } -EXPORT_SYMBOL(dma_sync_sg); +EXPORT_SYMBOL(dma_sync_sg_for_cpu); + +void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ + int i; + + BUG_ON(direction == DMA_NONE); + + /* Make sure that gcc doesn't leave the empty loop body. */ + for (i = 0; i < nelems; i++, sg++) + __dma_sync((unsigned long)page_address(sg->page), + sg->length, direction); +} + +EXPORT_SYMBOL(dma_sync_sg_for_device); int dma_supported(struct device *dev, u64 mask) { @@ -329,7 +370,17 @@ EXPORT_SYMBOL(pci_dac_dma_to_offset); -void pci_dac_dma_sync_single(struct pci_dev *pdev, +void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, + dma64_addr_t dma_addr, size_t len, int direction) +{ + BUG_ON(direction == PCI_DMA_NONE); + + dma_cache_wback_inv(dma_addr + PAGE_OFFSET, len); +} + +EXPORT_SYMBOL(pci_dac_dma_sync_single_for_cpu); + +void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction) { BUG_ON(direction == PCI_DMA_NONE); @@ -337,6 +388,6 @@ dma_cache_wback_inv(dma_addr + PAGE_OFFSET, len); } -EXPORT_SYMBOL(pci_dac_dma_sync_single); +EXPORT_SYMBOL(pci_dac_dma_sync_single_for_device); #endif /* CONFIG_PCI */ diff -Nru a/arch/parisc/configs/712_defconfig b/arch/parisc/configs/712_defconfig --- a/arch/parisc/configs/712_defconfig Sun Mar 14 14:20:08 2004 +++ b/arch/parisc/configs/712_defconfig Sun Mar 14 14:20:08 2004 @@ -22,6 +22,7 @@ # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y CONFIG_LOG_BUF_SHIFT=15 +# CONFIG_HOTPLUG is not set # CONFIG_IKCONFIG is not set # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y @@ -30,6 +31,7 @@ CONFIG_IOSCHED_NOOP=y CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # # Loadable module support @@ -64,7 +66,6 @@ # CONFIG_PCI is not set # CONFIG_CHASSIS_LCD_LED is not set # CONFIG_PDC_CHASSIS is not set -# CONFIG_HOTPLUG is not set # # Executable file formats @@ -79,6 +80,7 @@ # # Generic Driver Options # +CONFIG_DEBUG_DRIVER=y # # Memory Technology Devices (MTD) @@ -99,7 +101,6 @@ # # Plug and Play support # -# CONFIG_PNP is not set # # Block devices @@ -110,7 +111,6 @@ CONFIG_BLK_DEV_CRYPTOLOOP=y # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set # # ATA/ATAPI/MFM/RLL support @@ -144,7 +144,6 @@ # # SCSI low-level drivers # -# CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_EATA_PIO is not set # CONFIG_SCSI_PPA is not set @@ -170,13 +169,21 @@ # # Fusion MPT device support # -# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set # # I2O device support # # +# Macintosh device drivers +# + +# # Networking support # CONFIG_NET=y @@ -287,7 +294,7 @@ # # ISDN subsystem # -# CONFIG_ISDN_BOOL is not set +# CONFIG_ISDN is not set # # Telephony Support @@ -318,8 +325,8 @@ CONFIG_SOUND_GAMEPORT=y CONFIG_SERIO=y # CONFIG_SERIO_SERPORT is not set -# CONFIG_SERIO_CT82C710 is not set # CONFIG_SERIO_PARKBD is not set +CONFIG_SERIO_GSCPS2=y # CONFIG_HP_SDC is not set # @@ -331,15 +338,17 @@ # CONFIG_KEYBOARD_XTKBD is not set # CONFIG_KEYBOARD_NEWTON is not set # CONFIG_KEYBOARD_HIL_OLD is not set +# CONFIG_KEYBOARD_HIL is not set CONFIG_INPUT_MOUSE=y # CONFIG_MOUSE_PS2 is not set # CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_HIL is not set # CONFIG_INPUT_JOYSTICK is not set # CONFIG_INPUT_TOUCHSCREEN is not set CONFIG_INPUT_MISC=y # CONFIG_INPUT_PCSPKR is not set # CONFIG_INPUT_UINPUT is not set -CONFIG_INPUT_GSC=y +# CONFIG_HP_SDC_RTC is not set # # Character devices @@ -370,31 +379,14 @@ CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 CONFIG_PRINTER=y # CONFIG_LP_CONSOLE is not set # CONFIG_PPDEV is not set # CONFIG_TIPAR is not set # -# I2C support -# -# CONFIG_I2C is not set - -# -# I2C Algorithms -# - -# -# I2C Hardware Bus support -# - -# -# I2C Hardware Sensors Chip support -# -# CONFIG_I2C_SENSOR is not set - -# # Mice # # CONFIG_BUSMOUSE is not set @@ -425,6 +417,15 @@ # CONFIG_RAW_DRIVER is not set # +# I2C support +# +# CONFIG_I2C is not set + +# +# Misc devices +# + +# # Multimedia devices # # CONFIG_VIDEO_DEV is not set @@ -444,7 +445,6 @@ # # Console display driver support # -# CONFIG_VGA_CONSOLE is not set # CONFIG_MDA_CONSOLE is not set CONFIG_STI_CONSOLE=y CONFIG_DUMMY_CONSOLE_COLUMNS=160 @@ -475,6 +475,11 @@ # # +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# # File systems # CONFIG_EXT2_FS=y @@ -511,7 +516,6 @@ # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y -CONFIG_DEVPTS_FS=y # CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y # CONFIG_HUGETLB_PAGE is not set @@ -520,6 +524,7 @@ # # Miscellaneous filesystems # +# CONFIG_HFSPLUS_FS is not set # CONFIG_CRAMFS is not set # CONFIG_VXFS_FS is not set # CONFIG_HPFS_FS is not set @@ -549,11 +554,11 @@ # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y -CONFIG_NLS=y # # Native Language Support # +CONFIG_NLS=y CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_CODEPAGE_437 is not set # CONFIG_NLS_CODEPAGE_737 is not set @@ -628,6 +633,7 @@ # CONFIG_CRYPTO_AES is not set # CONFIG_CRYPTO_CAST5 is not set # CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_ARC4 is not set # CONFIG_CRYPTO_DEFLATE is not set # CONFIG_CRYPTO_TEST is not set diff -Nru a/arch/parisc/configs/a500_defconfig b/arch/parisc/configs/a500_defconfig --- a/arch/parisc/configs/a500_defconfig Sun Mar 14 14:20:06 2004 +++ b/arch/parisc/configs/a500_defconfig Sun Mar 14 14:20:06 2004 @@ -23,6 +23,7 @@ # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y CONFIG_LOG_BUF_SHIFT=16 +CONFIG_HOTPLUG=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_EMBEDDED=y @@ -72,7 +73,6 @@ # CONFIG_SUPERIO is not set CONFIG_CHASSIS_LCD_LED=y # CONFIG_PDC_CHASSIS is not set -CONFIG_HOTPLUG=y # # PCMCIA/CardBus support @@ -102,6 +102,7 @@ # Generic Driver Options # # CONFIG_FW_LOADER is not set +CONFIG_DEBUG_DRIVER=y # # Memory Technology Devices (MTD) @@ -116,7 +117,6 @@ # # Plug and Play support # -# CONFIG_PNP is not set # # Block devices @@ -195,9 +195,15 @@ CONFIG_SCSI_QLOGIC_FC=m # CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set CONFIG_SCSI_QLOGIC_1280=m +CONFIG_SCSI_QLA2XXX=y +# CONFIG_SCSI_QLA21XX is not set +# CONFIG_SCSI_QLA22XX is not set +CONFIG_SCSI_QLA2300=m +CONFIG_SCSI_QLA2322=m +CONFIG_SCSI_QLA6312=m +CONFIG_SCSI_QLA6322=m # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set -# CONFIG_SCSI_NSP32 is not set CONFIG_SCSI_DEBUG=m # @@ -215,6 +221,7 @@ CONFIG_MD_RAID0=y CONFIG_MD_RAID1=y # CONFIG_MD_RAID5 is not set +# CONFIG_MD_RAID6 is not set # CONFIG_MD_MULTIPATH is not set # CONFIG_BLK_DEV_DM is not set @@ -227,14 +234,17 @@ CONFIG_FUSION_CTL=m # -# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# IEEE 1394 (FireWire) support # # CONFIG_IEEE1394 is not set # # I2O device support # -# CONFIG_I2O is not set + +# +# Macintosh device drivers +# # # Networking support @@ -362,7 +372,7 @@ # # Network testing # -# CONFIG_NET_PKTGEN is not set +CONFIG_NET_PKTGEN=m CONFIG_NETDEVICES=y # @@ -391,9 +401,10 @@ # CONFIG_NET_TULIP=y CONFIG_DE2104X=m -CONFIG_TULIP=y +CONFIG_TULIP=m # CONFIG_TULIP_MWI is not set CONFIG_TULIP_MMIO=y +# CONFIG_TULIP_NAPI is not set # CONFIG_DE4X5 is not set # CONFIG_WINBOND_840 is not set # CONFIG_DM9102 is not set @@ -405,10 +416,12 @@ # CONFIG_AMD8111_ETH is not set # CONFIG_ADAPTEC_STARFIRE is not set # CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set # CONFIG_DGRS is not set CONFIG_EEPRO100=m # CONFIG_EEPRO100_PIO is not set CONFIG_E100=m +CONFIG_E100_NAPI=y # CONFIG_FEALNX is not set CONFIG_NATSEMI=m # CONFIG_NE2K_PCI is not set @@ -418,6 +431,7 @@ # CONFIG_8139TOO_TUNE_TWISTER is not set # CONFIG_8139TOO_8129 is not set # CONFIG_8139_OLD_RX_RESET is not set +CONFIG_8139_RXBUF_IDX=1 # CONFIG_SIS900 is not set CONFIG_EPIC100=m # CONFIG_SUNDANCE is not set @@ -482,13 +496,13 @@ CONFIG_PLX_HERMES=m CONFIG_TMD_HERMES=m CONFIG_PCI_HERMES=m +# CONFIG_ATMEL is not set # # Wireless 802.11b Pcmcia/Cardbus cards support # CONFIG_PCMCIA_HERMES=m CONFIG_AIRO_CS=m -# CONFIG_PCMCIA_ATMEL is not set # CONFIG_PCMCIA_WL3501 is not set CONFIG_NET_WIRELESS=y @@ -535,7 +549,7 @@ # # ISDN subsystem # -# CONFIG_ISDN_BOOL is not set +# CONFIG_ISDN is not set # # Telephony Support @@ -602,25 +616,7 @@ CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 - -# -# I2C support -# -# CONFIG_I2C is not set - -# -# I2C Algorithms -# - -# -# I2C Hardware Bus support -# - -# -# I2C Hardware Sensors Chip support -# -# CONFIG_I2C_SENSOR is not set +# CONFIG_LEGACY_PTYS is not set # # Mice @@ -659,6 +655,15 @@ CONFIG_MAX_RAW_DEVS=256 # +# I2C support +# +# CONFIG_I2C is not set + +# +# Misc devices +# + +# # Multimedia devices # # CONFIG_VIDEO_DEV is not set @@ -676,7 +681,6 @@ # # Console display driver support # -# CONFIG_VGA_CONSOLE is not set # CONFIG_MDA_CONSOLE is not set # CONFIG_STI_CONSOLE is not set CONFIG_DUMMY_CONSOLE_COLUMNS=160 @@ -692,6 +696,10 @@ # USB support # # CONFIG_USB is not set + +# +# USB Gadget Support +# # CONFIG_USB_GADGET is not set # @@ -711,6 +719,7 @@ CONFIG_XFS_FS=m # CONFIG_XFS_RT is not set # CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_SECURITY is not set # CONFIG_XFS_POSIX_ACL is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set @@ -740,7 +749,6 @@ CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y # CONFIG_DEVFS_FS is not set -CONFIG_DEVPTS_FS=y # CONFIG_DEVPTS_FS_XATTR is not set # CONFIG_TMPFS is not set # CONFIG_HUGETLBFS is not set @@ -753,6 +761,7 @@ # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set @@ -876,6 +885,7 @@ CONFIG_CRYPTO_AES=m CONFIG_CRYPTO_CAST5=m CONFIG_CRYPTO_CAST6=m +# CONFIG_CRYPTO_ARC4 is not set CONFIG_CRYPTO_DEFLATE=m CONFIG_CRYPTO_TEST=m diff -Nru a/arch/parisc/configs/b180_defconfig b/arch/parisc/configs/b180_defconfig --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/parisc/configs/b180_defconfig Sun Mar 14 14:20:09 2004 @@ -0,0 +1,776 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_PARISC=y +CONFIG_MMU=y +CONFIG_STACK_GROWSUP=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y + +# +# Code maturity level options +# +# CONFIG_EXPERIMENTAL is not set +CONFIG_CLEAN_COMPILE=y +CONFIG_STANDALONE=y +CONFIG_BROKEN_ON_SMP=y + +# +# General setup +# +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y +CONFIG_LOG_BUF_SHIFT=15 +# CONFIG_HOTPLUG is not set +# CONFIG_IKCONFIG is not set +# CONFIG_EMBEDDED is not set +CONFIG_KALLSYMS=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODULE_UNLOAD is not set +CONFIG_OBSOLETE_MODPARM=y +# CONFIG_KMOD is not set + +# +# Processor type and features +# +# CONFIG_PA7000 is not set +# CONFIG_PA7100LC is not set +CONFIG_PA7200=y +# CONFIG_PA8X00 is not set +CONFIG_PA11=y +# CONFIG_64BIT is not set +# CONFIG_SMP is not set +# CONFIG_PREEMPT is not set +# CONFIG_HPUX is not set + +# +# Bus options (PCI, PCMCIA, EISA, GSC, ISA) +# +CONFIG_GSC=y +# CONFIG_HPPB is not set +# CONFIG_IOMMU_CCIO is not set +CONFIG_GSC_LASI=y +CONFIG_GSC_WAX=y +CONFIG_EISA=y +CONFIG_EISA_NAMES=y +CONFIG_ISA=y +CONFIG_PCI=y +CONFIG_PCI_LEGACY_PROC=y +CONFIG_PCI_NAMES=y +CONFIG_GSC_DINO=y +# CONFIG_PCI_LBA is not set +# CONFIG_CHASSIS_LCD_LED is not set +# CONFIG_PDC_CHASSIS is not set + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_DEBUG_DRIVER=y + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Parallel port support +# +CONFIG_PARPORT=y +CONFIG_PARPORT_PC=y +CONFIG_PARPORT_PC_CML1=y +# CONFIG_PARPORT_SERIAL is not set +CONFIG_PARPORT_GSC=y +# CONFIG_PARPORT_OTHER is not set +# CONFIG_PARPORT_1284 is not set + +# +# Plug and Play support +# +# CONFIG_PNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_BLK_DEV_DAC960 is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_CRYPTOLOOP=y +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI=y +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=y +# CONFIG_CHR_DEV_OSST is not set +CONFIG_BLK_DEV_SR=y +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=y + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_REPORT_LUNS is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set + +# +# SCSI low-level drivers +# +# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +# CONFIG_SCSI_7000FASST is not set +# CONFIG_SCSI_ACARD is not set +# CONFIG_SCSI_AHA152X is not set +# CONFIG_SCSI_AHA1542 is not set +# CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AIC7XXX is not set +# CONFIG_SCSI_AIC7XXX_OLD is not set +# CONFIG_SCSI_AIC79XX is not set +# CONFIG_SCSI_ADVANSYS is not set +# CONFIG_SCSI_IN2000 is not set +# CONFIG_SCSI_MEGARAID is not set +# CONFIG_SCSI_BUSLOGIC is not set +# CONFIG_SCSI_CPQFCTS is not set +# CONFIG_SCSI_DMX3191D is not set +# CONFIG_SCSI_DTC3280 is not set +# CONFIG_SCSI_EATA is not set +# CONFIG_SCSI_EATA_PIO is not set +# CONFIG_SCSI_FUTURE_DOMAIN is not set +# CONFIG_SCSI_GDTH is not set +# CONFIG_SCSI_GENERIC_NCR5380 is not set +# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set +# CONFIG_SCSI_IPS is not set +# CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_PPA is not set +# CONFIG_SCSI_IMM is not set +# CONFIG_SCSI_NCR53C406A is not set +CONFIG_SCSI_LASI700=y +CONFIG_53C700_MEM_MAPPED=y +CONFIG_53C700_LE_ON_BE=y +CONFIG_SCSI_SYM53C8XX_2=y +CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0 +CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16 +CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64 +# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set +# CONFIG_SCSI_ZALON is not set +# CONFIG_SCSI_PAS16 is not set +# CONFIG_SCSI_PSI240I is not set +# CONFIG_SCSI_QLOGIC_FAS is not set +# CONFIG_SCSI_QLOGIC_ISP is not set +# CONFIG_SCSI_QLOGIC_FC is not set +# CONFIG_SCSI_QLOGIC_1280 is not set +CONFIG_SCSI_QLA2XXX=y +# CONFIG_SCSI_QLA21XX is not set +# CONFIG_SCSI_QLA22XX is not set +# CONFIG_SCSI_QLA2300 is not set +# CONFIG_SCSI_QLA2322 is not set +# CONFIG_SCSI_QLA6312 is not set +# CONFIG_SCSI_QLA6322 is not set +# CONFIG_SCSI_SIM710 is not set +# CONFIG_SCSI_SYM53C416 is not set +# CONFIG_SCSI_DC390T is not set +# CONFIG_SCSI_T128 is not set +# CONFIG_SCSI_U14_34F is not set +# CONFIG_SCSI_NSP32 is not set +# CONFIG_SCSI_DEBUG is not set + +# +# Old CD-ROM drivers (not SCSI, not IDE) +# +# CONFIG_CD_NO_IDESCSI is not set + +# +# Multi-device support (RAID and LVM) +# +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=y +CONFIG_MD_RAID0=y +CONFIG_MD_RAID1=y +CONFIG_MD_RAID5=y +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_DM is not set + +# +# Fusion MPT device support +# +# CONFIG_FUSION is not set + +# +# IEEE 1394 (FireWire) support +# +# CONFIG_IEEE1394 is not set + +# +# I2O device support +# +# CONFIG_I2O is not set + +# +# Macintosh device drivers +# + +# +# Networking support +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_NETLINK_DEV=y +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +CONFIG_IP_PNP_BOOTP=y +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_IP_MROUTE is not set +CONFIG_INET_ECN=y +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_NETFILTER is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_MII is not set +# CONFIG_LASI_82596 is not set +# CONFIG_HAPPYMEAL is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set + +# +# Tulip family network device support +# +CONFIG_NET_TULIP=y +CONFIG_TULIP=y +# CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP_NAPI is not set +# CONFIG_DE4X5 is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_DM9102 is not set +# CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +# CONFIG_NET_PCI is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set + +# +# Ethernet (10000 Mbit) +# +# CONFIG_IXGB is not set +# CONFIG_FDDI is not set +# CONFIG_PLIP is not set +CONFIG_PPP=y +# CONFIG_PPP_FILTER is not set +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPP_DEFLATE is not set +# CONFIG_PPP_BSDCOMP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y + +# +# Obsolete Wireless cards support (pre-802.11) +# +# CONFIG_STRIP is not set +# CONFIG_ARLAN is not set +# CONFIG_WAVELAN is not set + +# +# Wireless 802.11b ISA/PCI cards support +# +# CONFIG_AIRO is not set +# CONFIG_HERMES is not set +CONFIG_NET_WIRELESS=y + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# Bluetooth support +# +# CONFIG_BT is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Telephony Support +# +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set + +# +# Input I/O drivers +# +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +CONFIG_SERIO=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_PARKBD is not set +CONFIG_SERIO_GSCPS2=y +# CONFIG_HP_SDC is not set +# CONFIG_SERIO_PCIPS2 is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_HIL_OLD is not set +# CONFIG_KEYBOARD_HIL is not set +CONFIG_INPUT_MOUSE=y +# CONFIG_MOUSE_PS2 is not set +# CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_INPORT is not set +# CONFIG_MOUSE_LOGIBM is not set +# CONFIG_MOUSE_PC110PAD is not set +# CONFIG_MOUSE_HIL is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +CONFIG_INPUT_MISC=y +# CONFIG_INPUT_PCSPKR is not set +# CONFIG_INPUT_UINPUT is not set +# CONFIG_HP_SDC_RTC is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=4 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_RSA is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MUX is not set +# CONFIG_PDC_CONSOLE is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +CONFIG_PRINTER=y +# CONFIG_LP_CONSOLE is not set +# CONFIG_PPDEV is not set +# CONFIG_TIPAR is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_QIC02_TAPE is not set + +# +# IPMI +# +# CONFIG_IPMI_HANDLER is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +CONFIG_GEN_RTC=y +# CONFIG_GEN_RTC_X is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# Misc devices +# + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# +# Graphics support +# +CONFIG_FB=y +# CONFIG_FB_PM2 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_IMSTT is not set +CONFIG_FB_STI=y +# CONFIG_FB_RIVA is not set +# CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON_OLD is not set +# CONFIG_FB_RADEON is not set +# CONFIG_FB_ATY128 is not set +# CONFIG_FB_ATY is not set +# CONFIG_FB_SIS is not set +# CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set +# CONFIG_FB_3DFX is not set +# CONFIG_FB_VOODOO1 is not set +# CONFIG_FB_TRIDENT is not set +# CONFIG_FB_VIRTUAL is not set + +# +# Console display driver support +# +# CONFIG_MDA_CONSOLE is not set +CONFIG_STI_CONSOLE=y +CONFIG_DUMMY_CONSOLE_COLUMNS=160 +CONFIG_DUMMY_CONSOLE_ROWS=64 +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_PCI_CONSOLE=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Logo configuration +# +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_MONO=y +CONFIG_LOGO_LINUX_VGA16=y +CONFIG_LOGO_LINUX_CLUT224=y +CONFIG_LOGO_PARISC_CLUT224=y + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# USB Gadget Support +# +# CONFIG_USB_GADGET is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_FS_XATTR is not set +CONFIG_JBD=y +# CONFIG_JBD_DEBUG is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +# CONFIG_ZISOFS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_FAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +# CONFIG_DEVPTS_FS_XATTR is not set +CONFIG_TMPFS=y +# CONFIG_HUGETLB_PAGE is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_HFSPLUS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set + +# +# Network File Systems +# +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFSD=y +CONFIG_NFSD_V3=y +CONFIG_ROOT_NFS=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_EXPORTFS=y +CONFIG_SUNRPC=y +# CONFIG_SMB_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y + +# +# Native Language Support +# +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +# CONFIG_NLS_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Kernel hacking +# +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_FRAME_POINTER=y +# CONFIG_DEBUG_INFO is not set + +# +# Security options +# +CONFIG_SECURITY=y +# CONFIG_SECURITY_NETWORK is not set +CONFIG_SECURITY_CAPABILITIES=y +# CONFIG_SECURITY_SELINUX is not set + +# +# Cryptographic options +# +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_TEST is not set + +# +# Library routines +# +CONFIG_CRC32=y diff -Nru a/arch/parisc/configs/c3000_defconfig b/arch/parisc/configs/c3000_defconfig --- a/arch/parisc/configs/c3000_defconfig Sun Mar 14 14:20:07 2004 +++ b/arch/parisc/configs/c3000_defconfig Sun Mar 14 14:20:07 2004 @@ -23,6 +23,7 @@ # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y CONFIG_LOG_BUF_SHIFT=16 +CONFIG_HOTPLUG=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_EMBEDDED=y @@ -71,7 +72,6 @@ CONFIG_SUPERIO=y # CONFIG_CHASSIS_LCD_LED is not set # CONFIG_PDC_CHASSIS is not set -CONFIG_HOTPLUG=y # # PCMCIA/CardBus support @@ -101,6 +101,7 @@ # Generic Driver Options # CONFIG_FW_LOADER=y +CONFIG_DEBUG_DRIVER=y # # Memory Technology Devices (MTD) @@ -128,7 +129,6 @@ # CONFIG_BLK_DEV_CRYPTOLOOP is not set # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_RAM is not set -# CONFIG_BLK_DEV_INITRD is not set # # ATA/ATAPI/MFM/RLL support @@ -153,6 +153,7 @@ # # IDE chipset support/bugfixes # +CONFIG_IDE_GENERIC=y CONFIG_BLK_DEV_IDEPCI=y CONFIG_IDEPCI_SHARE_IRQ=y # CONFIG_BLK_DEV_OFFBOARD is not set @@ -161,7 +162,6 @@ CONFIG_BLK_DEV_IDEDMA_PCI=y # CONFIG_BLK_DEV_IDEDMA_FORCED is not set # CONFIG_IDEDMA_PCI_AUTO is not set -# CONFIG_IDEDMA_PCI_WIP is not set CONFIG_BLK_DEV_ADMA=y # CONFIG_BLK_DEV_AEC62XX is not set # CONFIG_BLK_DEV_ALI15X3 is not set @@ -252,11 +252,13 @@ CONFIG_SCSI_QLOGIC_FC=m # CONFIG_SCSI_QLOGIC_FC_FIRMWARE is not set CONFIG_SCSI_QLOGIC_1280=m -CONFIG_SCSI_QLA2XXX_CONFIG=y -CONFIG_SCSI_QLA2XXX=m +CONFIG_SCSI_QLA2XXX=y # CONFIG_SCSI_QLA21XX is not set # CONFIG_SCSI_QLA22XX is not set -CONFIG_SCSI_QLA23XX=m +CONFIG_SCSI_QLA2300=m +CONFIG_SCSI_QLA2322=m +CONFIG_SCSI_QLA6312=m +CONFIG_SCSI_QLA6322=m # CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_NSP32 is not set @@ -280,8 +282,9 @@ CONFIG_MD_RAID1=y # CONFIG_MD_RAID5 is not set # CONFIG_MD_RAID6 is not set -# CONFIG_MD_MULTIPATH is not set -# CONFIG_BLK_DEV_DM is not set +CONFIG_MD_MULTIPATH=y +CONFIG_BLK_DEV_DM=y +# CONFIG_DM_CRYPT is not set # # Fusion MPT device support @@ -292,7 +295,7 @@ CONFIG_FUSION_CTL=m # -# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# IEEE 1394 (FireWire) support # # CONFIG_IEEE1394 is not set @@ -302,6 +305,10 @@ # CONFIG_I2O is not set # +# Macintosh device drivers +# + +# # Networking support # CONFIG_NET=y @@ -457,6 +464,7 @@ CONFIG_TULIP=y # CONFIG_TULIP_MWI is not set # CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP_NAPI is not set CONFIG_DE4X5=m CONFIG_WINBOND_840=m # CONFIG_DM9102 is not set @@ -474,6 +482,7 @@ CONFIG_EEPRO100=m # CONFIG_EEPRO100_PIO is not set CONFIG_E100=m +# CONFIG_E100_NAPI is not set # CONFIG_FEALNX is not set CONFIG_NATSEMI=m # CONFIG_NE2K_PCI is not set @@ -483,6 +492,7 @@ # CONFIG_8139TOO_TUNE_TWISTER is not set # CONFIG_8139TOO_8129 is not set # CONFIG_8139_OLD_RX_RESET is not set +CONFIG_8139_RXBUF_IDX=1 # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set @@ -571,7 +581,7 @@ # # ISDN subsystem # -# CONFIG_ISDN_BOOL is not set +# CONFIG_ISDN is not set # # Telephony Support @@ -652,7 +662,8 @@ CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 # # Mice @@ -696,6 +707,10 @@ # CONFIG_I2C is not set # +# Misc devices +# + +# # Multimedia devices # # CONFIG_VIDEO_DEV is not set @@ -716,6 +731,7 @@ CONFIG_FB_STI=y # CONFIG_FB_RIVA is not set # CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON_OLD is not set # CONFIG_FB_RADEON is not set # CONFIG_FB_ATY128 is not set # CONFIG_FB_ATY is not set @@ -731,7 +747,6 @@ # # Console display driver support # -# CONFIG_VGA_CONSOLE is not set # CONFIG_MDA_CONSOLE is not set CONFIG_STI_CONSOLE=y CONFIG_DUMMY_CONSOLE_COLUMNS=160 @@ -823,7 +838,6 @@ # USB Imaging devices # CONFIG_USB_MDC800=m -CONFIG_USB_SCANNER=m CONFIG_USB_MICROTEK=m CONFIG_USB_HPUSBSCSI=m @@ -867,6 +881,10 @@ # CONFIG_USB_LCD is not set # CONFIG_USB_LED is not set # CONFIG_USB_TEST is not set + +# +# USB Gadget Support +# # CONFIG_USB_GADGET is not set # @@ -883,6 +901,7 @@ CONFIG_XFS_FS=m # CONFIG_XFS_RT is not set # CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_SECURITY is not set # CONFIG_XFS_POSIX_ACL is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set @@ -912,7 +931,6 @@ CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y # CONFIG_DEVFS_FS is not set -CONFIG_DEVPTS_FS=y # CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y # CONFIG_HUGETLBFS is not set @@ -925,6 +943,7 @@ # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set @@ -1046,6 +1065,7 @@ CONFIG_CRYPTO_AES=m CONFIG_CRYPTO_CAST5=m CONFIG_CRYPTO_CAST6=m +# CONFIG_CRYPTO_ARC4 is not set CONFIG_CRYPTO_DEFLATE=m CONFIG_CRYPTO_TEST=m diff -Nru a/arch/parisc/defconfig b/arch/parisc/defconfig --- a/arch/parisc/defconfig Sun Mar 14 14:20:06 2004 +++ b/arch/parisc/defconfig Sun Mar 14 14:20:06 2004 @@ -22,6 +22,7 @@ # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y CONFIG_LOG_BUF_SHIFT=15 +# CONFIG_HOTPLUG is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y # CONFIG_EMBEDDED is not set @@ -31,6 +32,7 @@ CONFIG_IOSCHED_NOOP=y CONFIG_IOSCHED_AS=y CONFIG_IOSCHED_DEADLINE=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # # Loadable module support @@ -71,7 +73,6 @@ CONFIG_SUPERIO=y CONFIG_CHASSIS_LCD_LED=y CONFIG_PDC_CHASSIS=y -# CONFIG_HOTPLUG is not set # # Executable file formats @@ -86,6 +87,7 @@ # # Generic Driver Options # +# CONFIG_DEBUG_DRIVER is not set # # Memory Technology Devices (MTD) @@ -108,7 +110,6 @@ # # Plug and Play support # -# CONFIG_PNP is not set # # Block devices @@ -195,8 +196,16 @@ # CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_QLOGIC_1280 is not set +CONFIG_SCSI_QLA2XXX=y +# CONFIG_SCSI_QLA21XX is not set +# CONFIG_SCSI_QLA22XX is not set +# CONFIG_SCSI_QLA2300 is not set +# CONFIG_SCSI_QLA2322 is not set +# CONFIG_SCSI_QLA6312 is not set +# CONFIG_SCSI_QLA6322 is not set # CONFIG_SCSI_SIM710 is not set # CONFIG_SCSI_DC395x is not set +# CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set @@ -209,6 +218,7 @@ CONFIG_MD_RAID0=y CONFIG_MD_RAID1=y CONFIG_MD_RAID5=y +# CONFIG_MD_RAID6 is not set # CONFIG_MD_MULTIPATH is not set # CONFIG_BLK_DEV_DM is not set @@ -218,7 +228,7 @@ # CONFIG_FUSION is not set # -# IEEE 1394 (FireWire) support (EXPERIMENTAL) +# IEEE 1394 (FireWire) support # # CONFIG_IEEE1394 is not set @@ -228,6 +238,10 @@ # CONFIG_I2O is not set # +# Macintosh device drivers +# + +# # Networking support # CONFIG_NET=y @@ -319,6 +333,7 @@ CONFIG_TULIP=y # CONFIG_TULIP_MWI is not set # CONFIG_TULIP_MMIO is not set +# CONFIG_TULIP_NAPI is not set # CONFIG_DE4X5 is not set # CONFIG_WINBOND_840 is not set # CONFIG_DM9102 is not set @@ -330,6 +345,7 @@ # CONFIG_ADAPTEC_STARFIRE is not set # CONFIG_AC3200 is not set # CONFIG_B44 is not set +# CONFIG_FORCEDETH is not set # CONFIG_DGRS is not set # CONFIG_EEPRO100 is not set # CONFIG_E100 is not set @@ -386,6 +402,7 @@ # CONFIG_AIRO=y # CONFIG_HERMES is not set +# CONFIG_ATMEL is not set CONFIG_NET_WIRELESS=y # @@ -419,7 +436,7 @@ # # ISDN subsystem # -# CONFIG_ISDN_BOOL is not set +# CONFIG_ISDN is not set # # Telephony Support @@ -450,10 +467,10 @@ CONFIG_SOUND_GAMEPORT=y CONFIG_SERIO=y # CONFIG_SERIO_SERPORT is not set -# CONFIG_SERIO_CT82C710 is not set # CONFIG_SERIO_PARKBD is not set +CONFIG_SERIO_GSCPS2=y CONFIG_HP_SDC=y -# CONFIG_HIL_MLC is not set +CONFIG_HIL_MLC=y # CONFIG_SERIO_PCIPS2 is not set # @@ -464,10 +481,11 @@ # CONFIG_KEYBOARD_SUNKBD is not set # CONFIG_KEYBOARD_XTKBD is not set # CONFIG_KEYBOARD_NEWTON is not set -# CONFIG_KEYBOARD_HIL_OLD is not set +CONFIG_KEYBOARD_HIL=y CONFIG_INPUT_MOUSE=y # CONFIG_MOUSE_PS2 is not set # CONFIG_MOUSE_SERIAL is not set +# CONFIG_MOUSE_HIL is not set CONFIG_INPUT_JOYSTICK=y # CONFIG_JOYSTICK_IFORCE is not set # CONFIG_JOYSTICK_WARRIOR is not set @@ -485,7 +503,6 @@ CONFIG_INPUT_MISC=y # CONFIG_INPUT_PCSPKR is not set # CONFIG_INPUT_UINPUT is not set -CONFIG_INPUT_GSC=y CONFIG_HP_SDC_RTC=y # @@ -517,31 +534,14 @@ CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 CONFIG_PRINTER=y # CONFIG_LP_CONSOLE is not set # CONFIG_PPDEV is not set # CONFIG_TIPAR is not set # -# I2C support -# -# CONFIG_I2C is not set - -# -# I2C Algorithms -# - -# -# I2C Hardware Bus support -# - -# -# I2C Hardware Sensors Chip support -# -# CONFIG_I2C_SENSOR is not set - -# # Mice # # CONFIG_BUSMOUSE is not set @@ -572,6 +572,15 @@ # CONFIG_RAW_DRIVER is not set # +# I2C support +# +# CONFIG_I2C is not set + +# +# Misc devices +# + +# # Multimedia devices # # CONFIG_VIDEO_DEV is not set @@ -585,16 +594,19 @@ # Graphics support # CONFIG_FB=y +# CONFIG_FB_PM2 is not set # CONFIG_FB_CYBER2000 is not set # CONFIG_FB_IMSTT is not set CONFIG_FB_STI=y # CONFIG_FB_RIVA is not set # CONFIG_FB_MATROX is not set +# CONFIG_FB_RADEON_OLD is not set # CONFIG_FB_RADEON is not set # CONFIG_FB_ATY128 is not set # CONFIG_FB_ATY is not set # CONFIG_FB_SIS is not set # CONFIG_FB_NEOMAGIC is not set +# CONFIG_FB_KYRO is not set # CONFIG_FB_3DFX is not set # CONFIG_FB_VOODOO1 is not set # CONFIG_FB_TRIDENT is not set @@ -603,7 +615,6 @@ # # Console display driver support # -# CONFIG_VGA_CONSOLE is not set # CONFIG_MDA_CONSOLE is not set CONFIG_STI_CONSOLE=y CONFIG_DUMMY_CONSOLE_COLUMNS=160 @@ -686,7 +697,6 @@ # USB Imaging devices # # CONFIG_USB_MDC800 is not set -# CONFIG_USB_SCANNER is not set # CONFIG_USB_MICROTEK is not set # CONFIG_USB_HPUSBSCSI is not set @@ -721,11 +731,19 @@ # # USB Miscellaneous drivers # +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set # CONFIG_USB_TIGL is not set # CONFIG_USB_AUERSWALD is not set # CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set # CONFIG_USB_BRLVGER is not set # CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set + +# +# USB Gadget Support +# # CONFIG_USB_GADGET is not set # @@ -766,7 +784,6 @@ CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y # CONFIG_DEVFS_FS is not set -CONFIG_DEVPTS_FS=y # CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y # CONFIG_HUGETLB_PAGE is not set @@ -778,6 +795,7 @@ # CONFIG_ADFS_FS is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set # CONFIG_BEFS_FS is not set # CONFIG_BFS_FS is not set # CONFIG_EFS_FS is not set @@ -809,7 +827,6 @@ # CONFIG_CIFS is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set -# CONFIG_INTERMEZZO_FS is not set # CONFIG_AFS_FS is not set # @@ -817,11 +834,11 @@ # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y -CONFIG_NLS=y # # Native Language Support # +CONFIG_NLS=y CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_CODEPAGE_437 is not set # CONFIG_NLS_CODEPAGE_737 is not set @@ -899,6 +916,7 @@ # CONFIG_CRYPTO_AES is not set # CONFIG_CRYPTO_CAST5 is not set # CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_ARC4 is not set # CONFIG_CRYPTO_DEFLATE is not set # CONFIG_CRYPTO_TEST is not set diff -Nru a/arch/parisc/hpux/entry_hpux.S b/arch/parisc/hpux/entry_hpux.S --- a/arch/parisc/hpux/entry_hpux.S Sun Mar 14 14:20:06 2004 +++ b/arch/parisc/hpux/entry_hpux.S Sun Mar 14 14:20:06 2004 @@ -1,10 +1,22 @@ -/* +/* syscall table for HPUX specific syscalls * - * Linux/PARISC Project (http://www.parisc-linux.org/) + * Linux/PA-RISC Project (http://www.parisc-linux.org/) + * Copyright (C) 1999 Matthew Wilcox * - * modified by Matthew Wilcox 1999-07-26 + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - #include #include diff -Nru a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c --- a/arch/parisc/kernel/drivers.c Sun Mar 14 14:20:08 2004 +++ b/arch/parisc/kernel/drivers.c Sun Mar 14 14:20:08 2004 @@ -618,6 +618,7 @@ tmp1); /* make the generic dma mask a pointer to the parisc one */ dev->dev.dma_mask = &dev->dma_mask; + dev->dev.coherent_dma_mask = dev->dma_mask; pr_debug("device_register(%s)\n", dev->dev.bus_id); device_register(&dev->dev); } diff -Nru a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S --- a/arch/parisc/kernel/entry.S Sun Mar 14 14:20:06 2004 +++ b/arch/parisc/kernel/entry.S Sun Mar 14 14:20:06 2004 @@ -533,7 +533,7 @@ ldil L%CLONE_UNTRACED, %r26 ldo CLONE_VM(%r26), %r26 /* Force CLONE_VM since only init_mm */ or %r26, %r24, %r26 /* will have kernel mappings. */ - copy %r0, %r25 /* stack_start */ + ldi 1, %r25 /* stack_start, signals kernel thread */ stw %r0, -52(%r30) /* user_tid */ #ifdef __LP64__ ldo -16(%r30),%r29 /* Reference param save area */ diff -Nru a/arch/parisc/kernel/hardware.c b/arch/parisc/kernel/hardware.c --- a/arch/parisc/kernel/hardware.c Sun Mar 14 14:20:07 2004 +++ b/arch/parisc/kernel/hardware.c Sun Mar 14 14:20:07 2004 @@ -333,8 +333,9 @@ {HPHW_A_DMA, 0x01F, 0x00089, 0x80, "SkyHawk 100/120 FW-SCSI"}, {HPHW_A_DMA, 0x027, 0x00089, 0x80, "Piranha 100 FW-SCSI"}, {HPHW_A_DMA, 0x032, 0x00089, 0x80, "Raven T' Core FW-SCSI"}, - {HPHW_A_DMA, 0x03b, 0x00089, 0x80, "Raven U/L2 Core FW-SCSI"}, - {HPHW_A_DMA, 0x03d, 0x00089, 0x80, "Merlin 160 Core FW-SCSI"}, + {HPHW_A_DMA, 0x03B, 0x00089, 0x80, "Raven U/L2 Core FW-SCSI"}, + {HPHW_A_DMA, 0x03C, 0x00089, 0x80, "Merlin 132 Core FW-SCSI"}, + {HPHW_A_DMA, 0x03D, 0x00089, 0x80, "Merlin 160 Core FW-SCSI"}, {HPHW_A_DMA, 0x044, 0x00089, 0x80, "Mohawk Core FW-SCSI"}, {HPHW_A_DMA, 0x051, 0x00089, 0x80, "Firehawk FW-SCSI"}, {HPHW_A_DMA, 0x058, 0x00089, 0x80, "FireHawk 200 FW-SCSI"}, diff -Nru a/arch/parisc/kernel/head64.S b/arch/parisc/kernel/head64.S --- a/arch/parisc/kernel/head64.S Sun Mar 14 14:20:05 2004 +++ b/arch/parisc/kernel/head64.S Sun Mar 14 14:20:05 2004 @@ -165,9 +165,9 @@ #endif /* CONFIG_SMP */ /* Save the rfi target address */ - ldo -THREAD_SZ_ALGN(%sp), %r1 - ldd TI_TASK(%r1), %r1 - std %r11, TASK_PT_GR11(%r1) + ldd TI_TASK-THREAD_SZ_ALGN(%sp), %r10 + tophys_r1 %r10 + std %r11, TASK_PT_GR11(%r10) #ifndef CONFIG_PDC_NARROW /* Switch to wide mode; Superdome doesn't support narrow PDC @@ -197,9 +197,9 @@ stext_pdc_ret: /* restore rfi target address*/ - ldo -THREAD_SZ_ALGN(%sp), %r1 - ldd TI_TASK(%r1), %r1 - ldd TASK_PT_GR11(%r1), %r11 + ldd TI_TASK-THREAD_SZ_ALGN(%sp), %r10 + tophys_r1 %r10 + ldd TASK_PT_GR11(%r10), %r11 /* PARANOID: clear user scratch/user space SR's */ mtsp %r0,%sr0 @@ -302,6 +302,7 @@ /* Initialize the SP - monarch sets up smp_init_current_idle_task */ load32 PA(smp_init_current_idle_task),%sp ldd 0(%sp),%sp /* load task address */ + ldd TASK_THREAD_INFO(%sp), %sp mtctl %sp,%cr30 /* store in cr30 */ ldo THREAD_SZ_ALGN(%sp),%sp tophys_r1 %sp diff -Nru a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c --- a/arch/parisc/kernel/module.c Sun Mar 14 14:20:09 2004 +++ b/arch/parisc/kernel/module.c Sun Mar 14 14:20:09 2004 @@ -1,25 +1,28 @@ -/* Kernel module help for parisc. +/* Kernel dynamically loadable module help for PARISC. + * + * The best reference for this stuff is probably the Processor- + * Specific ELF Supplement for PA-RISC: + * http://ftp.parisc-linux.org/docs/elf-pa-hp.pdf + * + * Linux/PA-RISC Project (http://www.parisc-linux.org/) + * Copyright (C) 2003 Randolph Chung + * + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ - 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - (c) 2003 Randolph Chung - - The best reference for this stuff is probably the Processor- - Specific ELF Supplement for PA-RISC: - http://ftp.parisc-linux.org/docs/elf-pa-hp.pdf -*/ #include #include #include diff -Nru a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S --- a/arch/parisc/kernel/pacache.S Sun Mar 14 14:20:06 2004 +++ b/arch/parisc/kernel/pacache.S Sun Mar 14 14:20:06 2004 @@ -221,6 +221,7 @@ LDREG ICACHE_STRIDE(%r1),%arg1 LDREG ICACHE_COUNT(%r1),%arg2 LDREG ICACHE_LOOP(%r1),%arg3 + rsm PSW_SM_I,%r22 /* No mmgt ops during loop*/ ADDIB= -1,%arg3,fioneloop /* Preadjust and test */ movb,<,n %arg3,%r31,fisync /* If loop < 0, do sync */ @@ -237,6 +238,7 @@ fisync: sync + mtsm %r22 bv %r0(%r2) nop .exit diff -Nru a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c --- a/arch/parisc/kernel/parisc_ksyms.c Sun Mar 14 14:20:08 2004 +++ b/arch/parisc/kernel/parisc_ksyms.c Sun Mar 14 14:20:08 2004 @@ -67,8 +67,10 @@ #include EXPORT_SYMBOL(lcopy_to_user); EXPORT_SYMBOL(lcopy_from_user); -EXPORT_SYMBOL(lstrnlen_user); +EXPORT_SYMBOL(lcopy_in_user); +EXPORT_SYMBOL(lstrncpy_from_user); EXPORT_SYMBOL(lclear_user); +EXPORT_SYMBOL(lstrnlen_user); #ifndef __LP64__ /* Needed so insmod can set dp value */ diff -Nru a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c --- a/arch/parisc/kernel/pci-dma.c Sun Mar 14 14:20:08 2004 +++ b/arch/parisc/kernel/pci-dma.c Sun Mar 14 14:20:08 2004 @@ -372,7 +372,7 @@ ** ISA cards will certainly only support 24-bit DMA addressing. ** Not clear if we can, want, or need to support ISA. */ - if (!dev || *dev->dma_mask != 0xffffffff) + if (!dev || *dev->coherent_dma_mask < 0xffffffff) gfp |= GFP_DMA; #endif return (void *)vaddr; @@ -413,7 +413,7 @@ /* * For PCI_DMA_FROMDEVICE this flush is not necessary for the * simple map/unmap case. However, it IS necessary if if - * pci_dma_sync_single has been called and the buffer reused. + * pci_dma_sync_single_* has been called and the buffer reused. */ flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), size); @@ -453,7 +453,7 @@ return; } -static void pa11_dma_sync_single(struct device *dev, dma_addr_t dma_handle, unsigned long offset, size_t size, enum dma_data_direction direction) +static void pa11_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, unsigned long offset, size_t size, enum dma_data_direction direction) { if (direction == DMA_NONE) BUG(); @@ -461,7 +461,25 @@ flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle) + offset, size); } -static void pa11_dma_sync_sg(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction) +static void pa11_dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, unsigned long offset, size_t size, enum dma_data_direction direction) +{ + if (direction == DMA_NONE) + BUG(); + + flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle) + offset, size); +} + +static void pa11_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction) +{ + int i; + + /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ + + for (i = 0; i < nents; i++, sglist++ ) + flush_kernel_dcache_range(sg_virt_addr(sglist), sglist->length); +} + +static void pa11_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction) { int i; @@ -480,8 +498,10 @@ .unmap_single = pa11_dma_unmap_single, .map_sg = pa11_dma_map_sg, .unmap_sg = pa11_dma_unmap_sg, - .dma_sync_single = pa11_dma_sync_single, - .dma_sync_sg = pa11_dma_sync_sg, + .dma_sync_single_for_cpu = pa11_dma_sync_single_for_cpu, + .dma_sync_single_for_device = pa11_dma_sync_single_for_device, + .dma_sync_sg_for_cpu = pa11_dma_sync_sg_for_cpu, + .dma_sync_sg_for_device = pa11_dma_sync_sg_for_device, }; static void *fail_alloc_consistent(struct device *dev, size_t size, @@ -519,8 +539,10 @@ .unmap_single = pa11_dma_unmap_single, .map_sg = pa11_dma_map_sg, .unmap_sg = pa11_dma_unmap_sg, - .dma_sync_single = pa11_dma_sync_single, - .dma_sync_sg = pa11_dma_sync_sg, + .dma_sync_single_cpu = pa11_dma_sync_single_cpu, + .dma_sync_single_device = pa11_dma_sync_single_device, + .dma_sync_sg_cpu = pa11_dma_sync_sg_cpu, + .dma_sync_sg_device = pa11_dma_sync_sg_device, }; diff -Nru a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c --- a/arch/parisc/kernel/pci.c Sun Mar 14 14:20:05 2004 +++ b/arch/parisc/kernel/pci.c Sun Mar 14 14:20:05 2004 @@ -21,6 +21,7 @@ #include #include #include /* for L1_CACHE_BYTES */ +#include #define DEBUG_RESOURCES 0 #define DEBUG_CONFIG 0 @@ -145,9 +146,13 @@ return str; } - /* Used in drivers/pci/quirks.c */ -struct pci_fixup pcibios_fixups[] = { {0} }; +struct pci_fixup pcibios_fixups[] = { +#ifdef CONFIG_SUPERIO + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415, superio_fixup_pci }, +#endif + { 0 } +}; /* diff -Nru a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c --- a/arch/parisc/kernel/process.c Sun Mar 14 14:20:08 2004 +++ b/arch/parisc/kernel/process.c Sun Mar 14 14:20:08 2004 @@ -32,7 +32,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define __KERNEL_SYSCALLS__ #include #include @@ -251,6 +250,16 @@ struct pt_regs *regs) { int *user_tid = (int *)regs->gr[26]; + + /* usp must be word aligned. This also prevents users from + * passing in the value 1 (which is the signal for a special + * return for a kernel thread) */ + usp = ALIGN(usp, 4); + + /* A zero value for usp means use the current stack */ + if(usp == 0) + usp = regs->gr[30]; + return do_fork(clone_flags & ~CLONE_IDLETASK, usp, regs, 0, user_tid, NULL); } @@ -291,7 +300,7 @@ * We rely on the fact that kernel_thread passes * in zero for usp. */ - if (usp == 0) { + if (usp == 1) { /* kernel thread */ cregs->ksp = (((unsigned long)(ti)) + THREAD_SZ_ALGN); /* Must exit via ret_from_kernel_thread in order diff -Nru a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c --- a/arch/parisc/kernel/smp.c Sun Mar 14 14:20:08 2004 +++ b/arch/parisc/kernel/smp.c Sun Mar 14 14:20:08 2004 @@ -16,7 +16,6 @@ ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. */ -#define __KERNEL_SYSCALLS__ #undef ENTRY_SYS_CPUS /* syscall support for iCOD-like functionality */ #include diff -Nru a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c --- a/arch/parisc/kernel/sys_parisc.c Sun Mar 14 14:20:08 2004 +++ b/arch/parisc/kernel/sys_parisc.c Sun Mar 14 14:20:08 2004 @@ -242,14 +242,6 @@ return sys_readahead(fd, (loff_t)high << 32 | low, count); } -/* - * This changes the io permissions bitmap in the current task. - */ -asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) -{ - return -ENOSYS; -} - asmlinkage unsigned long sys_alloc_hugepages(int key, unsigned long addr, unsigned long len, int prot, int flag) { return -ENOMEM; diff -Nru a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S --- a/arch/parisc/kernel/vmlinux.lds.S Sun Mar 14 14:20:06 2004 +++ b/arch/parisc/kernel/vmlinux.lds.S Sun Mar 14 14:20:06 2004 @@ -61,6 +61,9 @@ RODATA /* writeable */ + . = ALIGN(4096); /* Make sure this is paged aligned so + that we can properly leave these + as writable */ data_start = .; . = ALIGN(16); /* Exception table */ diff -Nru a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S --- a/arch/ppc/kernel/misc.S Sun Mar 14 14:20:08 2004 +++ b/arch/ppc/kernel/misc.S Sun Mar 14 14:20:08 2004 @@ -1108,17 +1108,7 @@ li r3,-1; \ blr -#define __NR__exit __NR_exit - -SYSCALL(setsid) -SYSCALL(open) -SYSCALL(read) -SYSCALL(write) -SYSCALL(lseek) -SYSCALL(close) -SYSCALL(dup) SYSCALL(execve) -SYSCALL(waitpid) /* Why isn't this a) automatic, b) written in 'C'? */ .data diff -Nru a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c --- a/arch/ppc/kernel/ppc_ksyms.c Sun Mar 14 14:20:08 2004 +++ b/arch/ppc/kernel/ppc_ksyms.c Sun Mar 14 14:20:08 2004 @@ -32,8 +32,6 @@ #include #include #include -#define __KERNEL_SYSCALLS__ -#include #include #include #include @@ -189,10 +187,6 @@ EXPORT_SYMBOL(flush_dcache_all); #endif -EXPORT_SYMBOL(open); -EXPORT_SYMBOL(read); -EXPORT_SYMBOL(lseek); -EXPORT_SYMBOL(close); EXPORT_SYMBOL(start_thread); EXPORT_SYMBOL(kernel_thread); diff -Nru a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c --- a/arch/ppc/kernel/smp.c Sun Mar 14 14:20:08 2004 +++ b/arch/ppc/kernel/smp.c Sun Mar 14 14:20:08 2004 @@ -17,8 +17,6 @@ #include #include #include -#define __KERNEL_SYSCALLS__ -#include #include #include #include diff -Nru a/arch/ppc/platforms/chrp_smp.c b/arch/ppc/platforms/chrp_smp.c --- a/arch/ppc/platforms/chrp_smp.c Sun Mar 14 14:20:07 2004 +++ b/arch/ppc/platforms/chrp_smp.c Sun Mar 14 14:20:07 2004 @@ -16,8 +16,6 @@ #include #include #include -#define __KERNEL_SYSCALLS__ -#include #include #include diff -Nru a/arch/ppc/platforms/pmac_feature.c b/arch/ppc/platforms/pmac_feature.c --- a/arch/ppc/platforms/pmac_feature.c Sun Mar 14 14:20:08 2004 +++ b/arch/ppc/platforms/pmac_feature.c Sun Mar 14 14:20:08 2004 @@ -1360,7 +1360,7 @@ mb(); k2_skiplist[1] = NULL; } else { - k2_skiplist[0] = pdev; + k2_skiplist[1] = pdev; mb(); MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE); } diff -Nru a/arch/ppc/platforms/pmac_smp.c b/arch/ppc/platforms/pmac_smp.c --- a/arch/ppc/platforms/pmac_smp.c Sun Mar 14 14:20:07 2004 +++ b/arch/ppc/platforms/pmac_smp.c Sun Mar 14 14:20:07 2004 @@ -29,8 +29,6 @@ #include #include #include -#define __KERNEL_SYSCALLS__ -#include #include #include #include diff -Nru a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S --- a/arch/ppc64/kernel/misc.S Sun Mar 14 14:20:08 2004 +++ b/arch/ppc64/kernel/misc.S Sun Mar 14 14:20:08 2004 @@ -565,35 +565,6 @@ ld r30,-16(r1) blr - .section ".toc","aw" -.SYSCALL_ERRNO: - .tc errno[TC],errno - - .section ".text" - .align 3 - -#define SYSCALL(name) \ -_GLOBAL(name) \ - li r0,__NR_##name; \ - sc; \ - bnslr; \ - ld r4,.SYSCALL_ERRNO@toc(2); \ - std r3,0(r4); \ - li r3,-1; \ - blr - -#define __NR__exit __NR_exit - -SYSCALL(setsid) -SYSCALL(open) -SYSCALL(read) -SYSCALL(write) -SYSCALL(lseek) -SYSCALL(close) -SYSCALL(dup) -SYSCALL(execve) -SYSCALL(waitpid) - #ifdef CONFIG_PPC_ISERIES /* hack hack hack */ #define ppc_rtas sys_ni_syscall #endif diff -Nru a/arch/ppc64/kernel/pmac_smp.c b/arch/ppc64/kernel/pmac_smp.c --- a/arch/ppc64/kernel/pmac_smp.c Sun Mar 14 14:20:06 2004 +++ b/arch/ppc64/kernel/pmac_smp.c Sun Mar 14 14:20:06 2004 @@ -29,8 +29,6 @@ #include #include #include -#define __KERNEL_SYSCALLS__ -#include #include #include #include diff -Nru a/arch/ppc64/mm/numa.c b/arch/ppc64/mm/numa.c --- a/arch/ppc64/mm/numa.c Sun Mar 14 14:20:07 2004 +++ b/arch/ppc64/mm/numa.c Sun Mar 14 14:20:07 2004 @@ -22,9 +22,17 @@ #define dbg(args...) #endif -int numa_cpu_lookup_table[NR_CPUS] = { [ 0 ... (NR_CPUS - 1)] = -1}; +#ifdef DEBUG_NUMA +#define ARRAY_INITIALISER -1 +#else +#define ARRAY_INITIALISER 0 +#endif + +int numa_cpu_lookup_table[NR_CPUS] = { [ 0 ... (NR_CPUS - 1)] = + ARRAY_INITIALISER}; int numa_memory_lookup_table[MAX_MEMORY >> MEMORY_INCREMENT_SHIFT] = - { [ 0 ... ((MAX_MEMORY >> MEMORY_INCREMENT_SHIFT) - 1)] = -1}; + { [ 0 ... ((MAX_MEMORY >> MEMORY_INCREMENT_SHIFT) - 1)] = + ARRAY_INITIALISER}; cpumask_t numa_cpumask_lookup_table[MAX_NUMNODES]; int nr_cpus_in_node[MAX_NUMNODES] = { [0 ... (MAX_NUMNODES -1)] = 0}; diff -Nru a/arch/s390/appldata/appldata_mem.c b/arch/s390/appldata/appldata_mem.c --- a/arch/s390/appldata/appldata_mem.c Sun Mar 14 14:20:06 2004 +++ b/arch/s390/appldata/appldata_mem.c Sun Mar 14 14:20:06 2004 @@ -54,7 +54,9 @@ u64 freeswap; /* free swap space */ // New in 2.6 --> - u64 pgalloc; /* page allocations */ + u64 pgalloc_high; /* page allocations */ + u64 pgalloc_normal; + u64 pgalloc_dma; u64 pgfault; /* page faults (major+minor) */ u64 pgmajfault; /* page faults (major only) */ // <-- New in 2.6 @@ -69,7 +71,9 @@ P_DEBUG("pgpgout = %8lu KB\n", mem_data->pgpgout); P_DEBUG("pswpin = %8lu Pages\n", mem_data->pswpin); P_DEBUG("pswpout = %8lu Pages\n", mem_data->pswpout); - P_DEBUG("pgalloc = %8lu \n", mem_data->pgalloc); + P_DEBUG("pgalloc_high = %8lu \n", mem_data->pgalloc_high); + P_DEBUG("pgalloc_normal = %8lu \n", mem_data->pgalloc_normal); + P_DEBUG("pgalloc_dma = %8lu \n", mem_data->pgalloc_dma); P_DEBUG("pgfault = %8lu \n", mem_data->pgfault); P_DEBUG("pgmajfault = %8lu \n", mem_data->pgmajfault); P_DEBUG("sharedram = %8lu KB\n", mem_data->sharedram); @@ -105,11 +109,14 @@ mem_data->pgpgout = ps.pgpgout >> 1; mem_data->pswpin = ps.pswpin; mem_data->pswpout = ps.pswpout; - mem_data->pgalloc = ps.pgalloc; + mem_data->pgalloc_high = ps.pgalloc_high; + mem_data->pgalloc_normal = ps.pgalloc_normal; + mem_data->pgalloc_dma = ps.pgalloc_dma; mem_data->pgfault = ps.pgfault; mem_data->pgmajfault = ps.pgmajfault; -P_DEBUG("pgalloc = %lu, pgfree = %lu\n", ps.pgalloc, ps.pgfree); +P_DEBUG("pgalloc_high = %lu, pgalloc_normal = %lu, pgalloc_dma = %lu, pgfree = %lu\n", + ps.pgalloc_high, ps.pgalloc_normal, ps.pgalloc_dma, ps.pgfree); si_meminfo(&val); mem_data->sharedram = val.sharedram; diff -Nru a/arch/s390/kernel/sys_s390.c b/arch/s390/kernel/sys_s390.c --- a/arch/s390/kernel/sys_s390.c Sun Mar 14 14:20:07 2004 +++ b/arch/s390/kernel/sys_s390.c Sun Mar 14 14:20:07 2004 @@ -289,11 +289,6 @@ return error; } -asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on) -{ - return -ENOSYS; -} - #else /* CONFIG_ARCH_S390X */ asmlinkage int s390x_newuname(struct new_utsname * name) diff -Nru a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S --- a/arch/s390/kernel/syscalls.S Sun Mar 14 14:20:06 2004 +++ b/arch/s390/kernel/syscalls.S Sun Mar 14 14:20:06 2004 @@ -109,7 +109,7 @@ NI_SYSCALL /* old profil syscall */ SYSCALL(sys_statfs,sys_statfs,compat_sys_statfs_wrapper) SYSCALL(sys_fstatfs,sys_fstatfs,compat_sys_fstatfs_wrapper) /* 100 */ -SYSCALL(sys_ioperm,sys_ni_syscall,sys_ni_syscall) +NI_SYSCALL /* ioperm for i386 */ SYSCALL(sys_socketcall,sys_socketcall,compat_sys_socketcall_wrapper) SYSCALL(sys_syslog,sys_syslog,sys32_syslog_wrapper) SYSCALL(sys_setitimer,sys_setitimer,compat_sys_setitimer_wrapper) diff -Nru a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c --- a/arch/sparc/kernel/ioport.c Sun Mar 14 14:20:08 2004 +++ b/arch/sparc/kernel/ioport.c Sun Mar 14 14:20:08 2004 @@ -360,7 +360,7 @@ /* */ -void sbus_dma_sync_single(struct sbus_dev *sdev, dma_addr_t ba, size_t size, int direction) +void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t ba, size_t size, int direction) { #if 0 unsigned long va; @@ -380,9 +380,34 @@ #endif } -void sbus_dma_sync_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction) +void sbus_dma_sync_single_for_device(struct sbus_dev *sdev, dma_addr_t ba, size_t size, int direction) { - printk("sbus_dma_sync_sg: not implemented yet\n"); +#if 0 + unsigned long va; + struct resource *res; + + /* We do not need the resource, just print a message if invalid. */ + res = _sparc_find_resource(&_sparc_dvma, ba); + if (res == NULL) + panic("sbus_dma_sync_single: 0x%x\n", ba); + + va = page_address(mmu_translate_dvma(ba)); /* XXX higmem */ + /* + * XXX This bogosity will be fixed with the iommu rewrite coming soon + * to a kernel near you. - Anton + */ + /* mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); */ +#endif +} + +void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction) +{ + printk("sbus_dma_sync_sg_for_cpu: not implemented yet\n"); +} + +void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction) +{ + printk("sbus_dma_sync_sg_for_device: not implemented yet\n"); } #endif /* CONFIG_SBUS */ @@ -482,7 +507,7 @@ * The 32-bit bus address to use is returned. * * Once the device is given the dma address, the device owns this memory - * until either pci_unmap_single or pci_dma_sync_single is performed. + * until either pci_unmap_single or pci_dma_sync_single_* is performed. */ dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction) @@ -591,10 +616,21 @@ * If you perform a pci_map_single() but wish to interrogate the * buffer using the cpu, yet do not wish to teardown the PCI dma * mapping, you must call this function before doing so. At the - * next point you give the PCI dma address back to the card, the + * next point you give the PCI dma address back to the card, you + * must first perform a pci_dma_sync_for_device, and then the * device again owns the buffer. */ -void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t ba, size_t size, int direction) +void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t ba, size_t size, int direction) +{ + if (direction == PCI_DMA_NONE) + BUG(); + if (direction != PCI_DMA_TODEVICE) { + mmu_inval_dma_area((unsigned long)phys_to_virt(ba), + (size + PAGE_SIZE-1) & PAGE_MASK); + } +} + +void pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t ba, size_t size, int direction) { if (direction == PCI_DMA_NONE) BUG(); @@ -607,10 +643,27 @@ /* Make physical memory consistent for a set of streaming * mode DMA translations after a transfer. * - * The same as pci_dma_sync_single but for a scatter-gather list, + * The same as pci_dma_sync_single_* but for a scatter-gather list, * same rules and usage. */ -void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) +void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) +{ + int n; + + if (direction == PCI_DMA_NONE) + BUG(); + if (direction != PCI_DMA_TODEVICE) { + for (n = 0; n < nents; n++) { + if (page_address(sg->page) == NULL) BUG(); + mmu_inval_dma_area( + (unsigned long) page_address(sg->page), + (sg->length + PAGE_SIZE-1) & PAGE_MASK); + sg++; + } + } +} + +void pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) { int n; diff -Nru a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c --- a/arch/sparc/kernel/process.c Sun Mar 14 14:20:06 2004 +++ b/arch/sparc/kernel/process.c Sun Mar 14 14:20:06 2004 @@ -9,7 +9,6 @@ * This file handles the architecture-dependent parts of process handling.. */ -#define __KERNEL_SYSCALLS__ #include #include @@ -19,7 +18,6 @@ #include #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 Sun Mar 14 14:20:05 2004 +++ b/arch/sparc/kernel/setup.c Sun Mar 14 14:20:05 2004 @@ -389,11 +389,6 @@ } console_initcall(set_preferred_console); -asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on) -{ - return -EIO; -} - extern char *sparc_cpu_type[]; extern char *sparc_fpu_type[]; diff -Nru a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c --- a/arch/sparc/kernel/smp.c Sun Mar 14 14:20:06 2004 +++ b/arch/sparc/kernel/smp.c Sun Mar 14 14:20:06 2004 @@ -33,9 +33,6 @@ #include #include -#define __KERNEL_SYSCALLS__ -#include - #define IRQ_RESCHEDULE 13 #define IRQ_STOP_CPU 14 #define IRQ_CROSS_CALL 15 diff -Nru a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c --- a/arch/sparc/kernel/sparc_ksyms.c Sun Mar 14 14:20:06 2004 +++ b/arch/sparc/kernel/sparc_ksyms.c Sun Mar 14 14:20:06 2004 @@ -205,8 +205,10 @@ EXPORT_SYMBOL(sbus_unmap_single); EXPORT_SYMBOL(sbus_map_sg); EXPORT_SYMBOL(sbus_unmap_sg); -EXPORT_SYMBOL(sbus_dma_sync_single); -EXPORT_SYMBOL(sbus_dma_sync_sg); +EXPORT_SYMBOL(sbus_dma_sync_single_for_cpu); +EXPORT_SYMBOL(sbus_dma_sync_single_for_device); +EXPORT_SYMBOL(sbus_dma_sync_sg_for_cpu); +EXPORT_SYMBOL(sbus_dma_sync_sg_for_device); EXPORT_SYMBOL(sbus_iounmap); EXPORT_SYMBOL(sbus_ioremap); #endif @@ -218,7 +220,10 @@ EXPORT_SYMBOL(pci_free_consistent); EXPORT_SYMBOL(pci_map_single); EXPORT_SYMBOL(pci_unmap_single); -EXPORT_SYMBOL(pci_dma_sync_single); +EXPORT_SYMBOL(pci_dma_sync_single_for_cpu); +EXPORT_SYMBOL(pci_dma_sync_single_for_device); +EXPORT_SYMBOL(pci_dma_sync_sg_for_cpu); +EXPORT_SYMBOL(pci_dma_sync_sg_for_device); /* Actually, ioremap/iounmap are not PCI specific. But it is ok for drivers. */ EXPORT_SYMBOL(ioremap); EXPORT_SYMBOL(iounmap); diff -Nru a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c --- a/arch/sparc/kernel/sun4d_smp.c Sun Mar 14 14:20:06 2004 +++ b/arch/sparc/kernel/sun4d_smp.c Sun Mar 14 14:20:06 2004 @@ -32,9 +32,6 @@ #include #include -#define __KERNEL_SYSCALLS__ -#include - #define IRQ_CROSS_CALL 15 extern ctxd_t *srmmu_ctx_table_phys; diff -Nru a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c --- a/arch/sparc/kernel/sun4m_smp.c Sun Mar 14 14:20:08 2004 +++ b/arch/sparc/kernel/sun4m_smp.c Sun Mar 14 14:20:08 2004 @@ -27,9 +27,6 @@ #include #include -#define __KERNEL_SYSCALLS__ -#include - #define IRQ_RESCHEDULE 13 #define IRQ_STOP_CPU 14 #define IRQ_CROSS_CALL 15 diff -Nru a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c --- a/arch/sparc64/kernel/pci_iommu.c Sun Mar 14 14:20:06 2004 +++ b/arch/sparc64/kernel/pci_iommu.c Sun Mar 14 14:20:06 2004 @@ -661,7 +661,7 @@ /* Make physical memory consistent for a single * streaming mode DMA translation after a transfer. */ -void pci_dma_sync_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) +void pci_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) { struct pcidev_cookie *pcp; struct pci_iommu *iommu; @@ -722,7 +722,7 @@ /* Make physical memory consistent for a set of streaming * mode DMA translations after a transfer. */ -void pci_dma_sync_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) +void pci_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) { struct pcidev_cookie *pcp; struct pci_iommu *iommu; diff -Nru a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c --- a/arch/sparc64/kernel/process.c Sun Mar 14 14:20:07 2004 +++ b/arch/sparc64/kernel/process.c Sun Mar 14 14:20:07 2004 @@ -10,7 +10,6 @@ * This file handles the architecture-dependent parts of process handling.. */ -#define __KERNEL_SYSCALLS__ #include #include @@ -22,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -43,6 +41,7 @@ #include #include #include +#include /* #define VERBOSE_SHOWREGS */ diff -Nru a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c --- a/arch/sparc64/kernel/sbus.c Sun Mar 14 14:20:08 2004 +++ b/arch/sparc64/kernel/sbus.c Sun Mar 14 14:20:08 2004 @@ -540,7 +540,7 @@ spin_unlock_irqrestore(&iommu->lock, flags); } -void sbus_dma_sync_single(struct sbus_dev *sdev, dma_addr_t base, size_t size, int direction) +void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t base, size_t size, int direction) { struct sbus_iommu *iommu = sdev->bus->iommu; unsigned long flags; @@ -552,7 +552,11 @@ spin_unlock_irqrestore(&iommu->lock, flags); } -void sbus_dma_sync_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int direction) +void sbus_dma_sync_single_for_device(struct sbus_dev *sdev, dma_addr_t base, size_t size, int direction) +{ +} + +void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int direction) { struct sbus_iommu *iommu = sdev->bus->iommu; unsigned long flags, size; @@ -570,6 +574,10 @@ spin_lock_irqsave(&iommu->lock, flags); strbuf_flush(iommu, base, size >> IO_PAGE_SHIFT); spin_unlock_irqrestore(&iommu->lock, flags); +} + +void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int direction) +{ } /* Enable 64-bit DVMA mode for the given device. */ diff -Nru a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c --- a/arch/sparc64/kernel/setup.c Sun Mar 14 14:20:06 2004 +++ b/arch/sparc64/kernel/setup.c Sun Mar 14 14:20:06 2004 @@ -603,11 +603,6 @@ } console_initcall(set_preferred_console); -asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on) -{ - return -EIO; -} - /* BUFFER is PAGE_SIZE bytes long. */ extern char *sparc_cpu_type; diff -Nru a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c --- a/arch/sparc64/kernel/smp.c Sun Mar 14 14:20:05 2004 +++ b/arch/sparc64/kernel/smp.c Sun Mar 14 14:20:05 2004 @@ -36,9 +36,6 @@ #include #include -#define __KERNEL_SYSCALLS__ -#include - extern int linux_num_cpus; extern void calibrate_delay(void); diff -Nru a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c --- a/arch/sparc64/kernel/sparc64_ksyms.c Sun Mar 14 14:20:08 2004 +++ b/arch/sparc64/kernel/sparc64_ksyms.c Sun Mar 14 14:20:08 2004 @@ -213,8 +213,8 @@ EXPORT_SYMBOL(sbus_unmap_single); EXPORT_SYMBOL(sbus_map_sg); EXPORT_SYMBOL(sbus_unmap_sg); -EXPORT_SYMBOL(sbus_dma_sync_single); -EXPORT_SYMBOL(sbus_dma_sync_sg); +EXPORT_SYMBOL(sbus_dma_sync_single_for_cpu); +EXPORT_SYMBOL(sbus_dma_sync_sg_for_cpu); #endif EXPORT_SYMBOL(outsb); EXPORT_SYMBOL(outsw); @@ -232,8 +232,8 @@ EXPORT_SYMBOL(pci_unmap_single); EXPORT_SYMBOL(pci_map_sg); EXPORT_SYMBOL(pci_unmap_sg); -EXPORT_SYMBOL(pci_dma_sync_single); -EXPORT_SYMBOL(pci_dma_sync_sg); +EXPORT_SYMBOL(pci_dma_sync_single_for_cpu); +EXPORT_SYMBOL(pci_dma_sync_sg_for_cpu); EXPORT_SYMBOL(pci_dma_supported); #endif diff -Nru a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c --- a/arch/sparc64/kernel/sys_sparc32.c Sun Mar 14 14:20:07 2004 +++ b/arch/sparc64/kernel/sys_sparc32.c Sun Mar 14 14:20:07 2004 @@ -282,11 +282,6 @@ __put_user(i->tv_usec, &o->tv_usec))); } -asmlinkage long sys32_ioperm(u32 from, u32 num, int on) -{ - return sys_ioperm((unsigned long)from, (unsigned long)num, on); -} - struct msgbuf32 { s32 mtype; char mtext[1]; }; struct ipc_perm32 diff -Nru a/arch/v850/kernel/rte_mb_a_pci.c b/arch/v850/kernel/rte_mb_a_pci.c --- a/arch/v850/kernel/rte_mb_a_pci.c Sun Mar 14 14:20:06 2004 +++ b/arch/v850/kernel/rte_mb_a_pci.c Sun Mar 14 14:20:06 2004 @@ -687,10 +687,11 @@ If you perform a pci_map_single() but wish to interrogate the buffer using the cpu, yet do not wish to teardown the PCI dma mapping, you must call this function before doing so. At the next - point you give the PCI dma address back to the card, the device - again owns the buffer. */ + point you give the PCI dma address back to the card, you must first + perform a pci_dma_sync_for_device, and then the device again owns + the buffer. */ void -pci_dma_sync_single (struct pci_dev *pdev, dma_addr_t dma_addr, size_t size, +pci_dma_sync_single_for_cpu (struct pci_dev *pdev, dma_addr_t dma_addr, size_t size, int dir) { void *mb_sram_addr = PCI_TO_MB_SRAM (dma_addr); @@ -700,6 +701,22 @@ if (dir == PCI_DMA_FROMDEVICE) memcpy (mapping->cpu_addr, mb_sram_addr, size); else if (dir == PCI_DMA_TODEVICE) + ; /* nothing to do */ + else + panic("pci_dma_sync_single: unsupported sync dir: %d", dir); +} + +void +pci_dma_sync_single_for_device (struct pci_dev *pdev, dma_addr_t dma_addr, size_t size, + int dir) +{ + void *mb_sram_addr = PCI_TO_MB_SRAM (dma_addr); + struct dma_mapping *mapping = find_dma_mapping (mb_sram_addr); + + /* Synchronize the DMA buffer with the CPU buffer if necessary. */ + if (dir == PCI_DMA_FROMDEVICE) + ; /* nothing to do */ + else if (dir == PCI_DMA_TODEVICE) memcpy (mb_sram_addr, mapping->cpu_addr, size); else panic("pci_dma_sync_single: unsupported sync dir: %d", dir); @@ -724,11 +741,18 @@ } /* Make physical memory consistent for a set of streaming mode DMA - translations after a transfer. The same as pci_dma_sync_single but + translations after a transfer. The same as pci_dma_sync_single_* but for a scatter-gather list, same rules and usage. */ void -pci_dma_sync_sg (struct pci_dev *dev, struct scatterlist *sg, int sg_len, +pci_dma_sync_sg_for_cpu (struct pci_dev *dev, struct scatterlist *sg, int sg_len, + int dir) +{ + BUG (); +} + +void +pci_dma_sync_sg_for_device (struct pci_dev *dev, struct scatterlist *sg, int sg_len, int dir) { BUG (); @@ -770,4 +794,5 @@ EXPORT_SYMBOL (pci_unmap_single); EXPORT_SYMBOL (pci_alloc_consistent); EXPORT_SYMBOL (pci_free_consistent); -EXPORT_SYMBOL (pci_dma_sync_single); +EXPORT_SYMBOL (pci_dma_sync_single_for_cpu); +EXPORT_SYMBOL (pci_dma_sync_single_for_device); diff -Nru a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig --- a/arch/x86_64/Kconfig Sun Mar 14 14:20:08 2004 +++ b/arch/x86_64/Kconfig Sun Mar 14 14:20:08 2004 @@ -160,9 +160,10 @@ with major 203 and minors 0 to 31 for /dev/cpu/0/cpuid to /dev/cpu/31/cpuid. +# disable it for opteron optimized builds because it pulls in ACPI_BOOT config X86_HT bool - depends on SMP + depends on SMP && !MK8 default y config MATH_EMULATION @@ -329,6 +330,11 @@ bool depends on PCI default y + +config PCI_MMCONFIG + bool "Support mmconfig PCI config space access" + depends on PCI + select ACPI_BOOT # the drivers/pci/msi.c code needs to be fixed first before enabling config PCI_USE_VECTOR diff -Nru a/arch/x86_64/Makefile b/arch/x86_64/Makefile --- a/arch/x86_64/Makefile Sun Mar 14 14:20:08 2004 +++ b/arch/x86_64/Makefile Sun Mar 14 14:20:08 2004 @@ -63,7 +63,7 @@ libs-y += arch/x86_64/lib/ core-y += arch/x86_64/kernel/ arch/x86_64/mm/ core-$(CONFIG_IA32_EMULATION) += arch/x86_64/ia32/ -drivers-$(CONFIG_PCI) += arch/i386/pci/ +drivers-$(CONFIG_PCI) += arch/x86_64/pci/ drivers-$(CONFIG_OPROFILE) += arch/x86_64/oprofile/ boot := arch/x86_64/boot diff -Nru a/arch/x86_64/defconfig b/arch/x86_64/defconfig --- a/arch/x86_64/defconfig Sun Mar 14 14:20:07 2004 +++ b/arch/x86_64/defconfig Sun Mar 14 14:20:07 2004 @@ -26,7 +26,7 @@ CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y -CONFIG_LOG_BUF_SHIFT=18 +CONFIG_LOG_BUF_SHIFT=17 # CONFIG_HOTPLUG is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y @@ -47,7 +47,8 @@ CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_OBSOLETE_MODPARM=y # CONFIG_MODVERSIONS is not set -# CONFIG_KMOD is not set +CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y # # Processor type and features @@ -93,20 +94,19 @@ CONFIG_ACPI_SLEEP=y CONFIG_ACPI_SLEEP_PROC_FS=y CONFIG_ACPI_AC=y -CONFIG_ACPI_BATTERY=y +# CONFIG_ACPI_BATTERY is not set CONFIG_ACPI_BUTTON=y CONFIG_ACPI_FAN=y CONFIG_ACPI_PROCESSOR=y CONFIG_ACPI_THERMAL=y # CONFIG_ACPI_ASUS is not set -CONFIG_ACPI_TOSHIBA=y -CONFIG_ACPI_DEBUG=y +# CONFIG_ACPI_TOSHIBA is not set +# CONFIG_ACPI_DEBUG is not set CONFIG_ACPI_BUS=y CONFIG_ACPI_EC=y CONFIG_ACPI_POWER=y CONFIG_ACPI_PCI=y CONFIG_ACPI_SYSTEM=y -# CONFIG_ACPI_RELAXED_AML is not set # CONFIG_X86_PM_TIMER is not set # @@ -119,16 +119,17 @@ # CONFIG_PCI=y CONFIG_PCI_DIRECT=y -# CONFIG_PCI_LEGACY_PROC is not set +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_LEGACY_PROC=y # CONFIG_PCI_NAMES is not set # # Executable file formats / Emulations # CONFIG_BINFMT_ELF=y -# CONFIG_BINFMT_MISC is not set +CONFIG_BINFMT_MISC=y CONFIG_IA32_EMULATION=y -# CONFIG_IA32_AOUT is not set +CONFIG_IA32_AOUT=y CONFIG_COMPAT=y CONFIG_UID16=y @@ -139,6 +140,7 @@ # # Generic Driver Options # +# CONFIG_DEBUG_DRIVER is not set # # Memory Technology Devices (MTD) @@ -148,7 +150,14 @@ # # Parallel port support # -# CONFIG_PARPORT is not set +CONFIG_PARPORT=y +CONFIG_PARPORT_PC=y +CONFIG_PARPORT_PC_CML1=y +# CONFIG_PARPORT_SERIAL is not set +# CONFIG_PARPORT_PC_FIFO is not set +# CONFIG_PARPORT_PC_SUPERIO is not set +# CONFIG_PARPORT_OTHER is not set +CONFIG_PARPORT_1284=y # # Plug and Play support @@ -158,6 +167,7 @@ # Block devices # CONFIG_BLK_DEV_FD=y +# CONFIG_PARIDE is not set # CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set @@ -165,11 +175,8 @@ CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_CRYPTOLOOP is not set # CONFIG_BLK_DEV_NBD is not set -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=4096 -CONFIG_BLK_DEV_INITRD=y -CONFIG_LBD=y -# CONFIG_DCSSBLK is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_LBD is not set # # ATA/ATAPI/MFM/RLL support @@ -187,7 +194,7 @@ CONFIG_BLK_DEV_IDECD=y # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set -# CONFIG_BLK_DEV_IDESCSI is not set +CONFIG_BLK_DEV_IDESCSI=m # CONFIG_IDE_TASK_IOCTL is not set # CONFIG_IDE_TASKFILE_IO is not set @@ -195,11 +202,12 @@ # IDE chipset support/bugfixes # CONFIG_IDE_GENERIC=y -# CONFIG_BLK_DEV_CMD640 is not set +CONFIG_BLK_DEV_CMD640=y +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set CONFIG_BLK_DEV_IDEPCI=y -# CONFIG_IDEPCI_SHARE_IRQ is not set +CONFIG_IDEPCI_SHARE_IRQ=y # CONFIG_BLK_DEV_OFFBOARD is not set -# CONFIG_BLK_DEV_GENERIC is not set +CONFIG_BLK_DEV_GENERIC=y # CONFIG_BLK_DEV_OPTI621 is not set # CONFIG_BLK_DEV_RZ1000 is not set CONFIG_BLK_DEV_IDEDMA_PCI=y @@ -218,16 +226,16 @@ # CONFIG_BLK_DEV_HPT34X is not set # CONFIG_BLK_DEV_HPT366 is not set # CONFIG_BLK_DEV_SC1200 is not set -CONFIG_BLK_DEV_PIIX=y +# CONFIG_BLK_DEV_PIIX is not set # CONFIG_BLK_DEV_NS87415 is not set # CONFIG_BLK_DEV_PDC202XX_OLD is not set # CONFIG_BLK_DEV_PDC202XX_NEW is not set # CONFIG_BLK_DEV_SVWKS is not set # CONFIG_BLK_DEV_SIIMAGE is not set -# CONFIG_BLK_DEV_SIS5513 is not set +CONFIG_BLK_DEV_SIS5513=y # CONFIG_BLK_DEV_SLC90E66 is not set # CONFIG_BLK_DEV_TRM290 is not set -# CONFIG_BLK_DEV_VIA82CXXX is not set +CONFIG_BLK_DEV_VIA82CXXX=y CONFIG_BLK_DEV_IDEDMA=y # CONFIG_IDEDMA_IVB is not set CONFIG_IDEDMA_AUTO=y @@ -246,8 +254,9 @@ CONFIG_BLK_DEV_SD=y # CONFIG_CHR_DEV_ST is not set # CONFIG_CHR_DEV_OSST is not set -# CONFIG_BLK_DEV_SR is not set -# CONFIG_CHR_DEV_SG is not set +CONFIG_BLK_DEV_SR=m +# CONFIG_BLK_DEV_SR_VENDOR is not set +CONFIG_CHR_DEV_SG=m # # Some SCSI devices (e.g. CD jukebox) support multiple LUNs @@ -260,7 +269,7 @@ # # SCSI low-level drivers # -# CONFIG_BLK_DEV_3W_XXXX_RAID is not set +CONFIG_BLK_DEV_3W_XXXX_RAID=y # CONFIG_SCSI_ACARD is not set # CONFIG_SCSI_AACRAID is not set # CONFIG_SCSI_AIC7XXX is not set @@ -268,7 +277,11 @@ # CONFIG_SCSI_AIC79XX is not set # CONFIG_SCSI_ADVANSYS is not set # CONFIG_SCSI_MEGARAID is not set -# CONFIG_SCSI_SATA is not set +CONFIG_SCSI_SATA=y +# CONFIG_SCSI_SATA_SVW is not set +CONFIG_SCSI_ATA_PIIX=y +# CONFIG_SCSI_SATA_PROMISE is not set +CONFIG_SCSI_SATA_VIA=y # CONFIG_SCSI_BUSLOGIC is not set # CONFIG_SCSI_CPQFCTS is not set # CONFIG_SCSI_DMX3191D is not set @@ -278,6 +291,8 @@ # CONFIG_SCSI_GDTH is not set # CONFIG_SCSI_IPS is not set # CONFIG_SCSI_INIA100 is not set +# CONFIG_SCSI_PPA is not set +# CONFIG_SCSI_IMM is not set # CONFIG_SCSI_SYM53C8XX_2 is not set # CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set @@ -330,37 +345,111 @@ # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -# CONFIG_NETLINK_DEV is not set +CONFIG_NETLINK_DEV=y CONFIG_UNIX=y -# CONFIG_NET_KEY is not set +CONFIG_NET_KEY=m CONFIG_INET=y CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set # CONFIG_IP_PNP is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -# CONFIG_IP_MROUTE is not set +CONFIG_IP_MROUTE=y +# CONFIG_IP_PIMSM_V1 is not set +# CONFIG_IP_PIMSM_V2 is not set # CONFIG_ARPD is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m + +# +# IP: Virtual Server Configuration +# +# CONFIG_IP_VS is not set CONFIG_IPV6=y -# CONFIG_IPV6_PRIVACY is not set +CONFIG_IPV6_PRIVACY=y # CONFIG_INET6_AH is not set -# CONFIG_INET6_ESP is not set -# CONFIG_INET6_IPCOMP is not set +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m # CONFIG_IPV6_TUNNEL is not set # CONFIG_DECNET is not set # CONFIG_BRIDGE is not set -# CONFIG_NETFILTER is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set + +# +# IP: Netfilter Configuration +# +CONFIG_IP_NF_CONNTRACK=m +CONFIG_IP_NF_FTP=m +CONFIG_IP_NF_IRC=m +# CONFIG_IP_NF_TFTP is not set +# CONFIG_IP_NF_AMANDA is not set +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=m +# CONFIG_IP_NF_MATCH_LIMIT is not set +# CONFIG_IP_NF_MATCH_IPRANGE is not set +# CONFIG_IP_NF_MATCH_MAC is not set +# CONFIG_IP_NF_MATCH_PKTTYPE is not set +# CONFIG_IP_NF_MATCH_MARK is not set +# CONFIG_IP_NF_MATCH_MULTIPORT is not set +# CONFIG_IP_NF_MATCH_TOS is not set +# CONFIG_IP_NF_MATCH_RECENT is not set +# CONFIG_IP_NF_MATCH_ECN is not set +# CONFIG_IP_NF_MATCH_DSCP is not set +# CONFIG_IP_NF_MATCH_AH_ESP is not set +# CONFIG_IP_NF_MATCH_LENGTH is not set +# CONFIG_IP_NF_MATCH_TTL is not set +# CONFIG_IP_NF_MATCH_TCPMSS is not set +# CONFIG_IP_NF_MATCH_HELPER is not set +CONFIG_IP_NF_MATCH_STATE=m +CONFIG_IP_NF_MATCH_CONNTRACK=m +# CONFIG_IP_NF_MATCH_OWNER is not set +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=m +# CONFIG_IP_NF_TARGET_REDIRECT is not set +# CONFIG_IP_NF_TARGET_NETMAP is not set +# CONFIG_IP_NF_TARGET_SAME is not set +# CONFIG_IP_NF_NAT_LOCAL is not set +# CONFIG_IP_NF_NAT_SNMP_BASIC is not set +CONFIG_IP_NF_NAT_IRC=m +CONFIG_IP_NF_NAT_FTP=m +CONFIG_IP_NF_MANGLE=m +# CONFIG_IP_NF_TARGET_TOS is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_DSCP is not set +CONFIG_IP_NF_TARGET_MARK=m +# CONFIG_IP_NF_TARGET_CLASSIFY is not set +CONFIG_IP_NF_TARGET_LOG=m +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_IP_NF_TARGET_TCPMSS=m +# CONFIG_IP_NF_ARPTABLES is not set +# CONFIG_IP_NF_COMPAT_IPCHAINS is not set +# CONFIG_IP_NF_COMPAT_IPFWADM is not set + +# +# IPv6: Netfilter Configuration +# +# CONFIG_IP6_NF_QUEUE is not set +# CONFIG_IP6_NF_IPTABLES is not set +CONFIG_XFRM=y +CONFIG_XFRM_USER=m # # SCTP Configuration (EXPERIMENTAL) # CONFIG_IPV6_SCTP__=y -# CONFIG_IP_SCTP is not set +CONFIG_IP_SCTP=m +# CONFIG_SCTP_DBG_MSG is not set +# CONFIG_SCTP_DBG_OBJCNT is not set +CONFIG_SCTP_HMAC_NONE=y +# CONFIG_SCTP_HMAC_SHA1 is not set +# CONFIG_SCTP_HMAC_MD5 is not set # CONFIG_ATM is not set # CONFIG_VLAN_8021Q is not set # CONFIG_LLC2 is not set @@ -389,10 +478,11 @@ # ARCnet devices # # CONFIG_ARCNET is not set -# CONFIG_DUMMY is not set +CONFIG_DUMMY=m # CONFIG_BONDING is not set # CONFIG_EQUALIZER is not set -# CONFIG_TUN is not set +CONFIG_TUN=m +CONFIG_ETHERTAP=m # # Ethernet (10 or 100Mbit) @@ -401,7 +491,9 @@ CONFIG_MII=y # CONFIG_HAPPYMEAL is not set # CONFIG_SUNGEM is not set -# CONFIG_NET_VENDOR_3COM is not set +CONFIG_NET_VENDOR_3COM=y +CONFIG_VORTEX=m +# CONFIG_TYPHOON is not set # # Tulip family network device support @@ -409,25 +501,25 @@ # CONFIG_NET_TULIP is not set # CONFIG_HP100 is not set CONFIG_NET_PCI=y -# CONFIG_PCNET32 is not set -CONFIG_AMD8111_ETH=y +CONFIG_PCNET32=y +CONFIG_AMD8111_ETH=m # CONFIG_ADAPTEC_STARFIRE is not set # CONFIG_B44 is not set -CONFIG_FORCEDETH=y +# CONFIG_FORCEDETH is not set # CONFIG_DGRS is not set # CONFIG_EEPRO100 is not set # CONFIG_E100 is not set # CONFIG_FEALNX is not set # CONFIG_NATSEMI is not set # CONFIG_NE2K_PCI is not set -CONFIG_8139CP=m -CONFIG_8139TOO=m +# CONFIG_8139CP is not set +CONFIG_8139TOO=y # CONFIG_8139TOO_PIO is not set # CONFIG_8139TOO_TUNE_TWISTER is not set # CONFIG_8139TOO_8129 is not set # CONFIG_8139_OLD_RX_RESET is not set CONFIG_8139_RXBUF_IDX=2 -# CONFIG_SIS900 is not set +CONFIG_SIS900=m # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set # CONFIG_VIA_RHINE is not set @@ -437,7 +529,7 @@ # # CONFIG_ACENIC is not set # CONFIG_DL2K is not set -CONFIG_E1000=y +CONFIG_E1000=m # CONFIG_E1000_NAPI is not set # CONFIG_NS83820 is not set # CONFIG_HAMACHI is not set @@ -453,7 +545,15 @@ # CONFIG_IXGB is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set -# CONFIG_PPP is not set +# CONFIG_PLIP is not set +CONFIG_PPP=m +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_SYNC_TTY is not set +# CONFIG_PPP_DEFLATE is not set +# CONFIG_PPP_BSDCOMP is not set +CONFIG_PPPOE=m # CONFIG_SLIP is not set # @@ -512,7 +612,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 # CONFIG_INPUT_JOYDEV is not set # CONFIG_INPUT_TSDEV is not set -CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVDEV is not set # CONFIG_INPUT_EVBUG is not set # @@ -524,6 +624,7 @@ CONFIG_SERIO_I8042=y # CONFIG_SERIO_SERPORT is not set # CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PARKBD is not set # CONFIG_SERIO_PCIPS2 is not set # @@ -547,7 +648,12 @@ CONFIG_VT=y CONFIG_VT_CONSOLE=y CONFIG_HW_CONSOLE=y -# CONFIG_SERIAL_NONSTANDARD is not set +CONFIG_SERIAL_NONSTANDARD=y +CONFIG_ROCKETPORT=m +# CONFIG_SYNCLINK is not set +# CONFIG_SYNCLINKMP is not set +# CONFIG_N_HDLC is not set +# CONFIG_STALDRV is not set # # Serial drivers @@ -564,13 +670,16 @@ CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y -CONFIG_LEGACY_PTYS=y -CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_LEGACY_PTYS is not set +CONFIG_PRINTER=y +# CONFIG_LP_CONSOLE is not set +# CONFIG_PPDEV is not set +# CONFIG_TIPAR is not set # # Mice # -# CONFIG_BUSMOUSE is not set +CONFIG_BUSMOUSE=y # CONFIG_QIC02_TAPE is not set # @@ -594,12 +703,17 @@ # CONFIG_AGP=y CONFIG_AGP_AMD64=y -CONFIG_AGP_INTEL=y -# CONFIG_DRM is not set +# CONFIG_AGP_INTEL is not set +CONFIG_DRM=y +# CONFIG_DRM_TDFX is not set +# CONFIG_DRM_GAMMA is not set +# CONFIG_DRM_R128 is not set +CONFIG_DRM_RADEON=m +# CONFIG_DRM_SIS is not set # CONFIG_MWAVE is not set -CONFIG_RAW_DRIVER=y +CONFIG_RAW_DRIVER=m CONFIG_MAX_RAW_DEVS=256 -CONFIG_HANGCHECK_TIMER=y +# CONFIG_HANGCHECK_TIMER is not set # # I2C support @@ -607,6 +721,11 @@ # CONFIG_I2C is not set # +# Misc devices +# +# CONFIG_IBM_ASM is not set + +# # Multimedia devices # # CONFIG_VIDEO_DEV is not set @@ -642,10 +761,11 @@ # # Open Sound System # -CONFIG_SOUND_PRIME=y +CONFIG_SOUND_PRIME=m # CONFIG_SOUND_BT878 is not set # CONFIG_SOUND_CMPCI is not set -# CONFIG_SOUND_EMU10K1 is not set +CONFIG_SOUND_EMU10K1=m +# CONFIG_MIDI_EMU10K1 is not set # CONFIG_SOUND_FUSION is not set # CONFIG_SOUND_CS4281 is not set # CONFIG_SOUND_ES1370 is not set @@ -653,12 +773,13 @@ # CONFIG_SOUND_ESSSOLO1 is not set # CONFIG_SOUND_MAESTRO is not set # CONFIG_SOUND_MAESTRO3 is not set -CONFIG_SOUND_ICH=y +CONFIG_SOUND_ICH=m # CONFIG_SOUND_SONICVIBES is not set # CONFIG_SOUND_TRIDENT is not set # CONFIG_SOUND_MSNDCLAS is not set # CONFIG_SOUND_MSNDPIN is not set -# CONFIG_SOUND_VIA82CXXX is not set +CONFIG_SOUND_VIA82CXXX=m +# CONFIG_MIDI_VIA82CXXX is not set # CONFIG_SOUND_OSS is not set # CONFIG_SOUND_ALI5455 is not set # CONFIG_SOUND_FORTE is not set @@ -668,7 +789,151 @@ # # USB support # -# CONFIG_USB is not set +CONFIG_USB=m +# CONFIG_USB_DEBUG is not set + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +CONFIG_USB_BANDWIDTH=y +# CONFIG_USB_DYNAMIC_MINORS is not set + +# +# USB Host Controller Drivers +# +CONFIG_USB_EHCI_HCD=m +CONFIG_USB_OHCI_HCD=m +CONFIG_USB_UHCI_HCD=m + +# +# USB Device Class drivers +# +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_BLUETOOTH_TTY is not set +# CONFIG_USB_MIDI is not set +# CONFIG_USB_ACM is not set +CONFIG_USB_PRINTER=m +CONFIG_USB_STORAGE=m +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_HP8200e is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set + +# +# USB Human Interface Devices (HID) +# +CONFIG_USB_HID=m +CONFIG_USB_HIDINPUT=y +# CONFIG_HID_FF is not set +# CONFIG_USB_HIDDEV is not set + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set +# CONFIG_USB_AIPTEK is not set +# CONFIG_USB_WACOM is not set +# CONFIG_USB_KBTAB is not set +# CONFIG_USB_POWERMATE is not set +# CONFIG_USB_XPAD is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_HPUSBSCSI is not set + +# +# USB Multimedia devices +# +# CONFIG_USB_DABUSB is not set + +# +# Video4Linux support is needed for USB Multimedia device support +# + +# +# USB Network adaptors +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +CONFIG_USB_USBNET=m + +# +# USB Host-to-Host Cables +# +CONFIG_USB_AN2720=y +CONFIG_USB_BELKIN=y +CONFIG_USB_GENESYS=y +CONFIG_USB_NET1080=y +CONFIG_USB_PL2301=y + +# +# Intelligent USB Devices/Gadgets +# +CONFIG_USB_ARMLINUX=y +CONFIG_USB_EPSON2888=y +# CONFIG_USB_ZAURUS is not set +# CONFIG_USB_CDCETHER is not set + +# +# USB Network Adapters +# +CONFIG_USB_AX8817X=y + +# +# USB port drivers +# +# CONFIG_USB_USS720 is not set + +# +# USB Serial Converter support +# +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_BELKIN=m +# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set +# CONFIG_USB_SERIAL_EMPEG is not set +# CONFIG_USB_SERIAL_FTDI_SIO is not set +# CONFIG_USB_SERIAL_VISOR is not set +# CONFIG_USB_SERIAL_IPAQ is not set +# CONFIG_USB_SERIAL_IR is not set +# CONFIG_USB_SERIAL_EDGEPORT is not set +# CONFIG_USB_SERIAL_EDGEPORT_TI is not set +# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set +# CONFIG_USB_SERIAL_KEYSPAN is not set +# CONFIG_USB_SERIAL_KLSI is not set +# CONFIG_USB_SERIAL_KOBIL_SCT is not set +# CONFIG_USB_SERIAL_MCT_U232 is not set +# CONFIG_USB_SERIAL_PL2303 is not set +# CONFIG_USB_SERIAL_SAFE is not set +# CONFIG_USB_SERIAL_CYBERJACK is not set +# CONFIG_USB_SERIAL_XIRCOM is not set +# CONFIG_USB_SERIAL_OMNINET is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_TIGL is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_BRLVGER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_TEST is not set # # USB Gadget Support @@ -680,20 +945,17 @@ # CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT2_FS_POSIX_ACL=y +# CONFIG_EXT2_FS_POSIX_ACL is not set # CONFIG_EXT2_FS_SECURITY is not set CONFIG_EXT3_FS=y -CONFIG_EXT3_FS_XATTR=y -CONFIG_EXT3_FS_POSIX_ACL=y -# CONFIG_EXT3_FS_SECURITY is not set +# CONFIG_EXT3_FS_XATTR is not set CONFIG_JBD=y # CONFIG_JBD_DEBUG is not set CONFIG_FS_MBCACHE=y CONFIG_REISERFS_FS=y # CONFIG_REISERFS_CHECK is not set -# CONFIG_REISERFS_PROC_INFO is not set +CONFIG_REISERFS_PROC_INFO=y # CONFIG_JFS_FS is not set -CONFIG_FS_POSIX_ACL=y # CONFIG_XFS_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set @@ -705,14 +967,16 @@ # CD-ROM/DVD Filesystems # CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set +CONFIG_JOLIET=y # CONFIG_ZISOFS is not set -# CONFIG_UDF_FS is not set +CONFIG_UDF_FS=m # # DOS/FAT/NT Filesystems # -# CONFIG_FAT_FS is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=m # CONFIG_NTFS_FS is not set # @@ -723,8 +987,8 @@ # CONFIG_DEVFS_FS is not set # CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y -CONFIG_HUGETLBFS=y -CONFIG_HUGETLB_PAGE=y +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y # @@ -750,7 +1014,7 @@ CONFIG_NFS_FS=y CONFIG_NFS_V3=y # CONFIG_NFS_V4 is not set -# CONFIG_NFS_DIRECTIO is not set +CONFIG_NFS_DIRECTIO=y CONFIG_NFSD=y CONFIG_NFSD_V3=y # CONFIG_NFSD_V4 is not set @@ -775,7 +1039,45 @@ # # Native Language Support # -# CONFIG_NLS is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set # # Profiling support @@ -803,9 +1105,28 @@ # # Cryptographic options # -# CONFIG_CRYPTO is not set +CONFIG_CRYPTO=y +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=m +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +CONFIG_CRYPTO_DES=m +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_ARC4 is not set +CONFIG_CRYPTO_DEFLATE=m +# CONFIG_CRYPTO_TEST is not set # # Library routines # CONFIG_CRC32=y +CONFIG_ZLIB_INFLATE=m +CONFIG_ZLIB_DEFLATE=m diff -Nru a/arch/x86_64/ia32/Makefile b/arch/x86_64/ia32/Makefile --- a/arch/x86_64/ia32/Makefile Sun Mar 14 14:20:06 2004 +++ b/arch/x86_64/ia32/Makefile Sun Mar 14 14:20:06 2004 @@ -11,18 +11,22 @@ obj-$(CONFIG_IA32_AOUT) += ia32_aout.o -$(obj)/syscall32.o: $(src)/syscall32.c $(obj)/vsyscall.so +$(obj)/syscall32.o: $(src)/syscall32.c \ + $(foreach F,sysenter syscall,$(obj)/vsyscall-$F.so) # Teach kbuild about targets -targets := vsyscall.o vsyscall.so +targets := $(foreach F,sysenter syscall,vsyscall-$F.o vsyscall-$F.so) # The DSO images are built using a special linker script -quiet_cmd_vsyscall = SYSCALL $@ - cmd_vsyscall = $(CC) -m32 -nostdlib -shared -s \ +quiet_cmd_syscall = SYSCALL $@ + cmd_syscall = $(CC) -m32 -nostdlib -shared -s \ -Wl,-soname=linux-gate.so.1 -o $@ \ -Wl,-T,$(filter-out FORCE,$^) -$(obj)/vsyscall.so: $(src)/vsyscall.lds $(obj)/vsyscall.o FORCE - $(call if_changed,vsyscall) -AFLAGS_vsyscall.o = -m32 +$(obj)/vsyscall-sysenter.so $(obj)/vsyscall-syscall.so: \ +$(obj)/vsyscall-%.so: $(src)/vsyscall.lds $(obj)/vsyscall-%.o FORCE + $(call if_changed,syscall) + +AFLAGS_vsyscall-sysenter.o = -m32 +AFLAGS_vsyscall-syscall.o = -m32 CFLAGS_ia32_ioctl.o += -Ifs/ diff -Nru a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c --- a/arch/x86_64/ia32/ia32_binfmt.c Sun Mar 14 14:20:06 2004 +++ b/arch/x86_64/ia32/ia32_binfmt.c Sun Mar 14 14:20:06 2004 @@ -32,7 +32,7 @@ #define AT_SYSINFO 32 #define AT_SYSINFO_EHDR 33 -int sysctl_vsyscall32; +int sysctl_vsyscall32 = 1; #define ARCH_DLINFO do { \ if (sysctl_vsyscall32) { \ @@ -46,7 +46,7 @@ #define IA32_EMULATOR 1 -#define ELF_ET_DYN_BASE (IA32_PAGE_OFFSET/3 + 0x1000000) +#define ELF_ET_DYN_BASE (TASK_UNMAPPED_32 + 0x1000000) #undef ELF_ARCH #define ELF_ARCH EM_386 @@ -261,7 +261,6 @@ set_thread_flag(TIF_ABI_PENDING); \ else \ clear_thread_flag(TIF_ABI_PENDING); \ - set_personality((ibcs2)?PER_SVR4:current->personality); \ } while (0) /* Override some function names */ 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 Sun Mar 14 14:20:08 2004 +++ b/arch/x86_64/ia32/ia32_signal.c Sun Mar 14 14:20:08 2004 @@ -273,8 +273,6 @@ sigset_t set; unsigned int eax; - set_thread_flag(TIF_IRET); - if (verify_area(VERIFY_READ, frame, sizeof(*frame))) goto badframe; if (__get_user(set.sig[0], &frame->sc.oldmask) @@ -304,8 +302,6 @@ sigset_t set; stack_t st; unsigned int eax; - - set_thread_flag(TIF_IRET); if (verify_area(VERIFY_READ, frame, sizeof(*frame))) goto badframe; diff -Nru a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S --- a/arch/x86_64/ia32/ia32entry.S Sun Mar 14 14:20:07 2004 +++ b/arch/x86_64/ia32/ia32entry.S Sun Mar 14 14:20:07 2004 @@ -12,6 +12,7 @@ #include #include #include +#include #include .macro IA32_ARG_FIXUP noebp=0 @@ -25,6 +26,99 @@ movl %edx,%edx /* zero extension */ .endm + /* clobbers %eax */ + .macro CLEAR_RREGS + xorl %eax,%eax + movq %rax,R11(%rsp) + movq %rax,R10(%rsp) + movq %rax,R9(%rsp) + movq %rax,R8(%rsp) + .endm + +/* + * 32bit SYSENTER instruction entry. + * + * Arguments: + * %eax System call number. + * %ebx Arg1 + * %ecx Arg2 + * %edx Arg3 + * %esi Arg4 + * %edi Arg5 + * %ebp user stack + * 0(%ebp) Arg6 + * + * Interrupts off. + * + * This is purely a fast path. For anything complicated we use the int 0x80 + * path below. Set up a complete hardware stack frame to share code + * with the int 0x80 path. + */ +ENTRY(ia32_sysenter_target) + CFI_STARTPROC + swapgs + movq %gs:pda_kernelstack, %rsp + addq $(PDA_STACKOFFSET),%rsp + sti + movl %ebp,%ebp /* zero extension */ + pushq $__USER32_DS + pushq %rbp + pushfq + movl $VSYSCALL32_SYSEXIT, %r10d + pushq $__USER32_CS + movl %eax, %eax + pushq %r10 + pushq %rax + cld + SAVE_ARGS 0,0,1 + /* no need to do an access_ok check here because rbp has been + 32bit zero extended */ +1: movl (%rbp),%r9d + .section __ex_table,"a" + .quad 1b,ia32_badarg + .previous + GET_THREAD_INFO(%r10) + bt $TIF_SYSCALL_TRACE,threadinfo_flags(%r10) + jc sysenter_tracesys +sysenter_do_call: + cmpl $(IA32_NR_syscalls),%eax + jae ia32_badsys + IA32_ARG_FIXUP 1 + call *ia32_sys_call_table(,%rax,8) + movq %rax,RAX-ARGOFFSET(%rsp) + GET_THREAD_INFO(%r10) + cli + testl $_TIF_ALLWORK_MASK,threadinfo_flags(%r10) + jnz int_ret_from_sys_call + /* clear IF, that popfq doesn't enable interrupts early */ + andl $~0x200,EFLAGS-R11(%rsp) + RESTORE_ARGS 1,24,1,1,1,1 + popfq + popq %rcx /* User %esp */ + movl $VSYSCALL32_SYSEXIT,%edx /* User %eip */ + swapgs + sti /* sti only takes effect after the next instruction */ + /* sysexit */ + .byte 0xf, 0x35 + +sysenter_tracesys: + SAVE_REST + CLEAR_RREGS + movq $-ENOSYS,RAX(%rsp) /* really needed? */ + movq %rsp,%rdi /* &pt_regs -> arg1 */ + call syscall_trace + LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */ + RESTORE_REST + movl %ebp, %ebp + /* no need to do an access_ok check here because rbp has been + 32bit zero extended */ +1: movl (%rbp),%r9d + .section __ex_table,"a" + .quad 1b,ia32_badarg + .previous + jmp sysenter_do_call + CFI_ENDPROC + /* * 32bit SYSCALL instruction entry. * @@ -51,7 +145,7 @@ movl %esp,%r8d movq %gs:pda_kernelstack,%rsp sti - SAVE_ARGS 8,1 + SAVE_ARGS 8,1,1 movl %eax,%eax /* zero extension */ movq %rax,ORIG_RAX-ARGOFFSET(%rsp) movq %rcx,RIP-ARGOFFSET(%rsp) @@ -66,47 +160,48 @@ /* hardware stack frame is complete now */ 1: movl (%r8),%r9d .section __ex_table,"a" - .quad 1b,cstar_badarg + .quad 1b,ia32_badarg .previous GET_THREAD_INFO(%r10) bt $TIF_SYSCALL_TRACE,threadinfo_flags(%r10) - jc ia32_tracesys + jc cstar_tracesys cstar_do_call: cmpl $IA32_NR_syscalls,%eax jae ia32_badsys IA32_ARG_FIXUP 1 call *ia32_sys_call_table(,%rax,8) - .globl cstar_sysret - /* label must directly follow call */ -cstar_sysret: movq %rax,RAX-ARGOFFSET(%rsp) GET_THREAD_INFO(%r10) cli testl $_TIF_ALLWORK_MASK,threadinfo_flags(%r10) - jnz 1f - RESTORE_ARGS 1,-ARG_SKIP,1,1 + jnz int_ret_from_sys_call + RESTORE_ARGS 1,-ARG_SKIP,1,1,1 movl RIP-ARGOFFSET(%rsp),%ecx movl EFLAGS-ARGOFFSET(%rsp),%r11d movl RSP-ARGOFFSET(%rsp),%esp swapgs sysretl -1: - btc $TIF_IRET,threadinfo_flags(%r10) - jmp int_ret_from_sys_call - cstar_tracesys: SAVE_REST + CLEAR_RREGS movq $-ENOSYS,RAX(%rsp) /* really needed? */ movq %rsp,%rdi /* &pt_regs -> arg1 */ call syscall_trace LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */ RESTORE_REST + movl RSP-ARGOFFSET(%rsp), %r8d + /* no need to do an access_ok check here because r8 has been + 32bit zero extended */ +1: movl (%r8),%r9d + .section __ex_table,"a" + .quad 1b,ia32_badarg + .previous jmp cstar_do_call -cstar_badarg: +ia32_badarg: movq $-EFAULT,%rax - jmp cstar_sysret + jmp ia32_sysret CFI_ENDPROC /* @@ -139,7 +234,7 @@ cld /* note the registers are not zero extended to the sf. this could be a problem. */ - SAVE_ARGS + SAVE_ARGS 0,0,1 GET_THREAD_INFO(%r10) bt $TIF_SYSCALL_TRACE,threadinfo_flags(%r10) jc ia32_tracesys @@ -148,6 +243,7 @@ jae ia32_badsys IA32_ARG_FIXUP call *ia32_sys_call_table(,%rax,8) # xxx: rip relative +ia32_sysret: movq %rax,RAX-ARGOFFSET(%rsp) jmp int_ret_from_sys_call @@ -200,8 +296,7 @@ call *%rax movq %r15, %r11 RESTORE_REST - cmpq $cstar_sysret,%r11 - je int_ret_from_sys_call /* misbalances the call/ret stack. sorry */ + leaq ia32_sysret(%rip),%r11 pushq %r11 ret CFI_ENDPROC 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 Sun Mar 14 14:20:07 2004 +++ b/arch/x86_64/ia32/sys_ia32.c Sun Mar 14 14:20:07 2004 @@ -1876,18 +1876,9 @@ cond_syscall(sys32_ipc) -struct exec_domain ia32_exec_domain = { - .name = "linux/x86", - .pers_low = PER_LINUX32, - .pers_high = PER_LINUX32, -}; - static int __init ia32_init (void) { printk("IA32 emulation $Id: sys_ia32.c,v 1.32 2002/03/24 13:02:28 ak Exp $\n"); - ia32_exec_domain.signal_map = default_exec_domain.signal_map; - ia32_exec_domain.signal_invmap = default_exec_domain.signal_invmap; - register_exec_domain(&ia32_exec_domain); return 0; } diff -Nru a/arch/x86_64/ia32/syscall32.c b/arch/x86_64/ia32/syscall32.c --- a/arch/x86_64/ia32/syscall32.c Sun Mar 14 14:20:07 2004 +++ b/arch/x86_64/ia32/syscall32.c Sun Mar 14 14:20:07 2004 @@ -13,16 +13,22 @@ #include #include -/* 32bit VDSO mapped into user space. */ +/* 32bit VDSOs mapped into user space. */ asm(".section \".init.data\",\"aw\"\n" - "syscall32:\n" - ".incbin \"arch/x86_64/ia32/vsyscall.so\"\n" - "syscall32_end:\n" + "syscall32_syscall:\n" + ".incbin \"arch/x86_64/ia32/vsyscall-syscall.so\"\n" + "syscall32_syscall_end:\n" + "syscall32_sysenter:\n" + ".incbin \"arch/x86_64/ia32/vsyscall-sysenter.so\"\n" + "syscall32_sysenter_end:\n" ".previous"); -extern unsigned char syscall32[], syscall32_end[]; +extern unsigned char syscall32_syscall[], syscall32_syscall_end[]; +extern unsigned char syscall32_sysenter[], syscall32_sysenter_end[]; +extern int sysctl_vsyscall32; char *syscall32_page; +static int use_sysenter __initdata = -1; /* RED-PEN: This knows too much about high level VM */ /* Alternative would be to generate a vma with appropriate backing options @@ -58,8 +64,28 @@ if (!syscall32_page) panic("Cannot allocate syscall32 page"); SetPageReserved(virt_to_page(syscall32_page)); - memcpy(syscall32_page, syscall32, syscall32_end - syscall32); + if (use_sysenter > 0) { + memcpy(syscall32_page, syscall32_sysenter, + syscall32_sysenter_end - syscall32_sysenter); + } else { + memcpy(syscall32_page, syscall32_syscall, + syscall32_syscall_end - syscall32_syscall); + } return 0; } __initcall(init_syscall32); + +void __init syscall32_cpu_init(void) +{ + if (use_sysenter < 0) + use_sysenter = (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL); + + /* Load these always in case some future AMD CPU supports + SYSENTER from compat mode too. */ + wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0); + wrmsr(MSR_IA32_SYSENTER_ESP, 0, 0); + wrmsrl(MSR_IA32_SYSENTER_EIP, ia32_sysenter_target); + + wrmsrl(MSR_CSTAR, ia32_cstar_target); +} diff -Nru a/arch/x86_64/ia32/vsyscall-sigreturn.S b/arch/x86_64/ia32/vsyscall-sigreturn.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/x86_64/ia32/vsyscall-sigreturn.S Sun Mar 14 14:20:09 2004 @@ -0,0 +1,120 @@ +/* + * Common code for the sigreturn entry points on the vsyscall page. + * This code uses SYSCALL_ENTER_KERNEL (either syscall or int $0x80) + * to enter the kernel. + * This file is #include'd by vsyscall-*.S to define them after the + * vsyscall entry point. The addresses we get for these entry points + * by doing ".balign 32" must match in both versions of the page. + */ + + .section .text.sigreturn,"ax" + .balign 32 + .globl __kernel_sigreturn + .type __kernel_sigreturn,@function +__kernel_sigreturn: +.LSTART_sigreturn: + popl %eax + movl $__NR_ia32_sigreturn, %eax + SYSCALL_ENTER_KERNEL +.LEND_sigreturn: + .size __kernel_sigreturn,.-.LSTART_sigreturn + + .section .text.rtsigreturn,"ax" + .balign 32 + .globl __kernel_rt_sigreturn + .type __kernel_rt_sigreturn,@function +__kernel_rt_sigreturn: +.LSTART_rt_sigreturn: + movl $__NR_ia32_rt_sigreturn, %eax + SYSCALL_ENTER_KERNEL +.LEND_rt_sigreturn: + .size __kernel_rt_sigreturn,.-.LSTART_rt_sigreturn + + .section .eh_frame,"a",@progbits + .long .LENDFDE2-.LSTARTFDE2 /* Length FDE */ +.LSTARTFDE2: + .long .LSTARTFDE2-.LSTARTFRAME /* CIE pointer */ + /* HACK: The dwarf2 unwind routines will subtract 1 from the + return address to get an address in the middle of the + presumed call instruction. Since we didn't get here via + a call, we need to include the nop before the real start + to make up for it. */ + .long .LSTART_sigreturn-1-. /* PC-relative start address */ + .long .LEND_sigreturn-.LSTART_sigreturn+1 + .uleb128 0 /* Augmentation length */ + /* What follows are the instructions for the table generation. + We record the locations of each register saved. This is + complicated by the fact that the "CFA" is always assumed to + be the value of the stack pointer in the caller. This means + that we must define the CFA of this body of code to be the + saved value of the stack pointer in the sigcontext. Which + also means that there is no fixed relation to the other + saved registers, which means that we must use DW_CFA_expression + to compute their addresses. It also means that when we + adjust the stack with the popl, we have to do it all over again. */ + +#define do_cfa_expr(offset) \ + .byte 0x0f; /* DW_CFA_def_cfa_expression */ \ + .uleb128 1f-0f; /* length */ \ +0: .byte 0x74; /* DW_OP_breg4 */ \ + .sleb128 offset; /* offset */ \ + .byte 0x06; /* DW_OP_deref */ \ +1: + +#define do_expr(regno, offset) \ + .byte 0x10; /* DW_CFA_expression */ \ + .uleb128 regno; /* regno */ \ + .uleb128 1f-0f; /* length */ \ +0: .byte 0x74; /* DW_OP_breg4 */ \ + .sleb128 offset; /* offset */ \ +1: + + do_cfa_expr(IA32_SIGCONTEXT_esp+4) + do_expr(0, IA32_SIGCONTEXT_eax+4) + do_expr(1, IA32_SIGCONTEXT_ecx+4) + do_expr(2, IA32_SIGCONTEXT_edx+4) + do_expr(3, IA32_SIGCONTEXT_ebx+4) + do_expr(5, IA32_SIGCONTEXT_ebp+4) + do_expr(6, IA32_SIGCONTEXT_esi+4) + do_expr(7, IA32_SIGCONTEXT_edi+4) + do_expr(8, IA32_SIGCONTEXT_eip+4) + + .byte 0x42 /* DW_CFA_advance_loc 2 -- nop; popl eax. */ + + do_cfa_expr(IA32_SIGCONTEXT_esp) + do_expr(0, IA32_SIGCONTEXT_eax) + do_expr(1, IA32_SIGCONTEXT_ecx) + do_expr(2, IA32_SIGCONTEXT_edx) + do_expr(3, IA32_SIGCONTEXT_ebx) + do_expr(5, IA32_SIGCONTEXT_ebp) + do_expr(6, IA32_SIGCONTEXT_esi) + do_expr(7, IA32_SIGCONTEXT_edi) + do_expr(8, IA32_SIGCONTEXT_eip) + + .align 4 +.LENDFDE2: + + .long .LENDFDE3-.LSTARTFDE3 /* Length FDE */ +.LSTARTFDE3: + .long .LSTARTFDE3-.LSTARTFRAME /* CIE pointer */ + /* HACK: See above wrt unwind library assumptions. */ + .long .LSTART_rt_sigreturn-1-. /* PC-relative start address */ + .long .LEND_rt_sigreturn-.LSTART_rt_sigreturn+1 + .uleb128 0 /* Augmentation */ + /* What follows are the instructions for the table generation. + We record the locations of each register saved. This is + slightly less complicated than the above, since we don't + modify the stack pointer in the process. */ + + do_cfa_expr(IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_esp) + do_expr(0, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_eax) + do_expr(1, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_ecx) + do_expr(2, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_edx) + do_expr(3, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_ebx) + do_expr(5, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_ebp) + do_expr(6, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_esi) + do_expr(7, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_edi) + do_expr(8, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_eip) + + .align 4 +.LENDFDE3: diff -Nru a/arch/x86_64/ia32/vsyscall-syscall.S b/arch/x86_64/ia32/vsyscall-syscall.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/x86_64/ia32/vsyscall-syscall.S Sun Mar 14 14:20:09 2004 @@ -0,0 +1,68 @@ +/* + * Code for the vsyscall page. This version uses the syscall instruction. + */ + +#include +#include +#include + + .text + .section .text.vsyscall,"ax" + .globl __kernel_vsyscall + .type __kernel_vsyscall,@function +__kernel_vsyscall: +.LSTART_vsyscall: + push %ebp +.Lpush_ebp: + movl %ecx, %ebp + syscall + movl $__USER32_DS, %ecx + movl %ecx, %ss + movl %ebp, %ecx + popl %ebp +.Lpop_ebp: + ret +.LEND_vsyscall: + .size __kernel_vsyscall,.-.LSTART_vsyscall + + .section .eh_frame,"a",@progbits +.LSTARTFRAME: + .long .LENDCIE-.LSTARTCIE +.LSTARTCIE: + .long 0 /* CIE ID */ + .byte 1 /* Version number */ + .string "zR" /* NUL-terminated augmentation string */ + .uleb128 1 /* Code alignment factor */ + .sleb128 -4 /* Data alignment factor */ + .byte 8 /* Return address register column */ + .uleb128 1 /* Augmentation value length */ + .byte 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */ + .byte 0x0c /* DW_CFA_def_cfa */ + .uleb128 4 + .uleb128 4 + .byte 0x88 /* DW_CFA_offset, column 0x8 */ + .uleb128 1 + .align 4 +.LENDCIE: + + .long .LENDFDE1-.LSTARTFDE1 /* Length FDE */ +.LSTARTFDE1: + .long .LSTARTFDE1-.LSTARTFRAME /* CIE pointer */ + .long .LSTART_vsyscall-. /* PC-relative start address */ + .long .LEND_vsyscall-.LSTART_vsyscall + .uleb128 0 /* Augmentation length */ + /* What follows are the instructions for the table generation. + We have to record all changes of the stack pointer. */ + .byte 0x40 + .Lpush_ebp-.LSTART_vsyscall /* DW_CFA_advance_loc */ + .byte 0x0e /* DW_CFA_def_cfa_offset */ + .uleb128 8 + .byte 0x85, 0x02 /* DW_CFA_offset %ebp -8 */ + .byte 0x40 + .Lpop_ebp-.Lpush_ebp /* DW_CFA_advance_loc */ + .byte 0xc5 /* DW_CFA_restore %ebp */ + .byte 0x0e /* DW_CFA_def_cfa_offset */ + .uleb128 4 + .align 4 +.LENDFDE1: + +#define SYSCALL_ENTER_KERNEL syscall +#include "vsyscall-sigreturn.S" diff -Nru a/arch/x86_64/ia32/vsyscall-sysenter.S b/arch/x86_64/ia32/vsyscall-sysenter.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/x86_64/ia32/vsyscall-sysenter.S Sun Mar 14 14:20:09 2004 @@ -0,0 +1,94 @@ +/* + * Code for the vsyscall page. This version uses the sysenter instruction. + */ + +#include +#include + + .text + .section .text.vsyscall,"ax" + .globl __kernel_vsyscall + .type __kernel_vsyscall,@function +__kernel_vsyscall: +.LSTART_vsyscall: + push %ecx +.Lpush_ecx: + push %edx +.Lpush_edx: + push %ebp +.Lenter_kernel: + movl %esp,%ebp + sysenter + .space 7,0x90 + jmp .Lenter_kernel + /* 16: System call normal return point is here! */ + pop %ebp +.Lpop_ebp: + pop %edx +.Lpop_edx: + pop %ecx +.Lpop_ecx: + ret +.LEND_vsyscall: + .size __kernel_vsyscall,.-.LSTART_vsyscall + + .section .eh_frame,"a",@progbits +.LSTARTFRAME: + .long .LENDCIE-.LSTARTCIE +.LSTARTCIE: + .long 0 /* CIE ID */ + .byte 1 /* Version number */ + .string "zR" /* NUL-terminated augmentation string */ + .uleb128 1 /* Code alignment factor */ + .sleb128 -4 /* Data alignment factor */ + .byte 8 /* Return address register column */ + .uleb128 1 /* Augmentation value length */ + .byte 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */ + .byte 0x0c /* DW_CFA_def_cfa */ + .uleb128 4 + .uleb128 4 + .byte 0x88 /* DW_CFA_offset, column 0x8 */ + .uleb128 1 + .align 4 +.LENDCIE: + + .long .LENDFDE1-.LSTARTFDE1 /* Length FDE */ +.LSTARTFDE1: + .long .LSTARTFDE1-.LSTARTFRAME /* CIE pointer */ + .long .LSTART_vsyscall-. /* PC-relative start address */ + .long .LEND_vsyscall-.LSTART_vsyscall + .uleb128 0 /* Augmentation length */ + /* What follows are the instructions for the table generation. + We have to record all changes of the stack pointer. */ + .byte 0x04 /* DW_CFA_advance_loc4 */ + .long .Lpush_ecx-.LSTART_vsyscall + .byte 0x0e /* DW_CFA_def_cfa_offset */ + .byte 0x08 /* RA at offset 8 now */ + .byte 0x04 /* DW_CFA_advance_loc4 */ + .long .Lpush_edx-.Lpush_ecx + .byte 0x0e /* DW_CFA_def_cfa_offset */ + .byte 0x0c /* RA at offset 12 now */ + .byte 0x04 /* DW_CFA_advance_loc4 */ + .long .Lenter_kernel-.Lpush_edx + .byte 0x0e /* DW_CFA_def_cfa_offset */ + .byte 0x10 /* RA at offset 16 now */ + .byte 0x85, 0x04 /* DW_CFA_offset %ebp -16 */ + /* Finally the epilogue. */ + .byte 0x04 /* DW_CFA_advance_loc4 */ + .long .Lpop_ebp-.Lenter_kernel + .byte 0x0e /* DW_CFA_def_cfa_offset */ + .byte 0x12 /* RA at offset 12 now */ + .byte 0xc5 /* DW_CFA_restore %ebp */ + .byte 0x04 /* DW_CFA_advance_loc4 */ + .long .Lpop_edx-.Lpop_ebp + .byte 0x0e /* DW_CFA_def_cfa_offset */ + .byte 0x08 /* RA at offset 8 now */ + .byte 0x04 /* DW_CFA_advance_loc4 */ + .long .Lpop_ecx-.Lpop_edx + .byte 0x0e /* DW_CFA_def_cfa_offset */ + .byte 0x04 /* RA at offset 4 now */ + .align 4 +.LENDFDE1: + +#define SYSCALL_ENTER_KERNEL int $0x80 +#include "vsyscall-sigreturn.S" diff -Nru a/arch/x86_64/ia32/vsyscall.S b/arch/x86_64/ia32/vsyscall.S --- a/arch/x86_64/ia32/vsyscall.S Sun Mar 14 14:20:07 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,172 +0,0 @@ -/* - * Code for the vsyscall page. This version uses the syscall instruction. - */ - -#include -#include - - .text - .section .text.vsyscall,"ax" - .globl __kernel_vsyscall - .type __kernel_vsyscall,@function -__kernel_vsyscall: -.LSTART_vsyscall: - push %ebp -.Lpush_ebp: - movl %ecx, %ebp - syscall - popl %ebp -.Lpop_ebp: - ret -.LEND_vsyscall: - .size __kernel_vsyscall,.-.LSTART_vsyscall - - .section .text.sigreturn,"ax" - .balign 32 - .globl __kernel_sigreturn - .type __kernel_sigreturn,@function -__kernel_sigreturn: -.LSTART_sigreturn: - popl %eax - movl $__NR_ia32_sigreturn, %eax - syscall -.LEND_sigreturn: - .size __kernel_sigreturn,.-.LSTART_sigreturn - - .section .text.rtsigreturn,"ax" - .balign 32 - .globl __kernel_rt_sigreturn - .type __kernel_rt_sigreturn,@function -__kernel_rt_sigreturn: -.LSTART_rt_sigreturn: - movl $__NR_ia32_rt_sigreturn, %eax - syscall -.LEND_rt_sigreturn: - .size __kernel_rt_sigreturn,.-.LSTART_rt_sigreturn - - .section .eh_frame,"a",@progbits -.LSTARTFRAME: - .long .LENDCIE-.LSTARTCIE -.LSTARTCIE: - .long 0 /* CIE ID */ - .byte 1 /* Version number */ - .string "zR" /* NUL-terminated augmentation string */ - .uleb128 1 /* Code alignment factor */ - .sleb128 -4 /* Data alignment factor */ - .byte 8 /* Return address register column */ - .uleb128 1 /* Augmentation value length */ - .byte 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */ - .byte 0x0c /* DW_CFA_def_cfa */ - .uleb128 4 - .uleb128 4 - .byte 0x88 /* DW_CFA_offset, column 0x8 */ - .uleb128 1 - .align 4 -.LENDCIE: - - .long .LENDFDE1-.LSTARTFDE1 /* Length FDE */ -.LSTARTFDE1: - .long .LSTARTFDE1-.LSTARTFRAME /* CIE pointer */ - .long .LSTART_vsyscall-. /* PC-relative start address */ - .long .LEND_vsyscall-.LSTART_vsyscall - .uleb128 0 /* Augmentation length */ - /* What follows are the instructions for the table generation. - We have to record all changes of the stack pointer. */ - .byte 0x40 + .Lpush_ebp-.LSTART_vsyscall /* DW_CFA_advance_loc */ - .byte 0x0e /* DW_CFA_def_cfa_offset */ - .uleb128 8 - .byte 0x85, 0x02 /* DW_CFA_offset %ebp -8 */ - .byte 0x40 + .Lpop_ebp-.Lpush_ebp /* DW_CFA_advance_loc */ - .byte 0xc5 /* DW_CFA_restore %ebp */ - .byte 0x0e /* DW_CFA_def_cfa_offset */ - .uleb128 4 - .align 4 -.LENDFDE1: - - .long .LENDFDE2-.LSTARTFDE2 /* Length FDE */ -.LSTARTFDE2: - .long .LSTARTFDE2-.LSTARTFRAME /* CIE pointer */ - /* HACK: The dwarf2 unwind routines will subtract 1 from the - return address to get an address in the middle of the - presumed call instruction. Since we didn't get here via - a call, we need to include the nop before the real start - to make up for it. */ - .long .LSTART_sigreturn-1-. /* PC-relative start address */ - .long .LEND_sigreturn-.LSTART_sigreturn+1 - .uleb128 0 /* Augmentation length */ - /* What follows are the instructions for the table generation. - We record the locations of each register saved. This is - complicated by the fact that the "CFA" is always assumed to - be the value of the stack pointer in the caller. This means - that we must define the CFA of this body of code to be the - saved value of the stack pointer in the sigcontext. Which - also means that there is no fixed relation to the other - saved registers, which means that we must use DW_CFA_expression - to compute their addresses. It also means that when we - adjust the stack with the popl, we have to do it all over again. */ - -#define do_cfa_expr(offset) \ - .byte 0x0f; /* DW_CFA_def_cfa_expression */ \ - .uleb128 1f-0f; /* length */ \ -0: .byte 0x74; /* DW_OP_breg4 */ \ - .sleb128 offset; /* offset */ \ - .byte 0x06; /* DW_OP_deref */ \ -1: - -#define do_expr(regno, offset) \ - .byte 0x10; /* DW_CFA_expression */ \ - .uleb128 regno; /* regno */ \ - .uleb128 1f-0f; /* length */ \ -0: .byte 0x74; /* DW_OP_breg4 */ \ - .sleb128 offset; /* offset */ \ -1: - - do_cfa_expr(IA32_SIGCONTEXT_esp+4) - do_expr(0, IA32_SIGCONTEXT_eax+4) - do_expr(1, IA32_SIGCONTEXT_ecx+4) - do_expr(2, IA32_SIGCONTEXT_edx+4) - do_expr(3, IA32_SIGCONTEXT_ebx+4) - do_expr(5, IA32_SIGCONTEXT_ebp+4) - do_expr(6, IA32_SIGCONTEXT_esi+4) - do_expr(7, IA32_SIGCONTEXT_edi+4) - do_expr(8, IA32_SIGCONTEXT_eip+4) - - .byte 0x42 /* DW_CFA_advance_loc 2 -- nop; popl eax. */ - - do_cfa_expr(IA32_SIGCONTEXT_esp) - do_expr(0, IA32_SIGCONTEXT_eax) - do_expr(1, IA32_SIGCONTEXT_ecx) - do_expr(2, IA32_SIGCONTEXT_edx) - do_expr(3, IA32_SIGCONTEXT_ebx) - do_expr(5, IA32_SIGCONTEXT_ebp) - do_expr(6, IA32_SIGCONTEXT_esi) - do_expr(7, IA32_SIGCONTEXT_edi) - do_expr(8, IA32_SIGCONTEXT_eip) - - .align 4 -.LENDFDE2: - - .long .LENDFDE3-.LSTARTFDE3 /* Length FDE */ -.LSTARTFDE3: - .long .LSTARTFDE3-.LSTARTFRAME /* CIE pointer */ - /* HACK: See above wrt unwind library assumptions. */ - .long .LSTART_rt_sigreturn-1-. /* PC-relative start address */ - .long .LEND_rt_sigreturn-.LSTART_rt_sigreturn+1 - .uleb128 0 /* Augmentation */ - /* What follows are the instructions for the table generation. - We record the locations of each register saved. This is - slightly less complicated than the above, since we don't - modify the stack pointer in the process. */ - - do_cfa_expr(IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_esp) - do_expr(0, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_eax) - do_expr(1, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_ecx) - do_expr(2, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_edx) - do_expr(3, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_ebx) - do_expr(5, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_ebp) - do_expr(6, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_esi) - do_expr(7, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_edi) - do_expr(8, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_eip) - - .align 4 -.LENDFDE3: diff -Nru a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile --- a/arch/x86_64/kernel/Makefile Sun Mar 14 14:20:08 2004 +++ b/arch/x86_64/kernel/Makefile Sun Mar 14 14:20:08 2004 @@ -8,10 +8,9 @@ ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_x86_64.o \ x8664_ksyms.o i387.o syscall.o vsyscall.o \ setup64.o bootflag.o e820.o reboot.o warmreboot.o -obj-y += mce.o +obj-y += mce.o acpi/ obj-$(CONFIG_MTRR) += ../../i386/kernel/cpu/mtrr/ -obj-$(CONFIG_ACPI) += acpi/ obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_MICROCODE) += microcode.o obj-$(CONFIG_X86_CPUID) += cpuid.o diff -Nru a/arch/x86_64/kernel/acpi/boot.c b/arch/x86_64/kernel/acpi/boot.c --- a/arch/x86_64/kernel/acpi/boot.c Sun Mar 14 14:20:06 2004 +++ b/arch/x86_64/kernel/acpi/boot.c Sun Mar 14 14:20:06 2004 @@ -78,6 +78,31 @@ return NULL; } +#ifdef CONFIG_PCI_MMCONFIG +static int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size) +{ + struct acpi_table_mcfg *mcfg; + + if (!phys_addr || !size) + return -EINVAL; + + mcfg = (struct acpi_table_mcfg *) __acpi_map_table(phys_addr, size); + if (!mcfg) { + printk(KERN_WARNING PREFIX "Unable to map MCFG\n"); + return -ENODEV; + } + + if (mcfg->base_reserved) { + printk(KERN_ERR PREFIX "MMCONFIG not in low 4GB of memory\n"); + return -ENODEV; + } + + pci_mmcfg_base_addr = mcfg->base_address; + + return 0; +} +#endif /* CONFIG_PCI_MMCONFIG */ + #ifdef CONFIG_X86_LOCAL_APIC static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE; @@ -234,6 +259,24 @@ #endif /*CONFIG_X86_IO_APIC*/ +static int __init acpi_parse_sbf(unsigned long phys_addr, unsigned long size) +{ + struct acpi_table_sbf *sb; + + if (!phys_addr || !size) + return -EINVAL; + + sb = (struct acpi_table_sbf *) __acpi_map_table(phys_addr, size); + if (!sb) { + printk(KERN_WARNING PREFIX "Unable to map SBF\n"); + return -ENODEV; + } + + sbf_port = sb->sbf_cmos; /* Save CMOS port */ + + return 0; +} + #ifdef CONFIG_HPET_TIMER static int __init acpi_parse_hpet ( @@ -404,6 +447,8 @@ return result; } + (void) acpi_table_parse(ACPI_BOOT, acpi_parse_sbf); + result = acpi_blacklisted(); if (result) { printk(KERN_WARNING PREFIX "BIOS listed in blacklist, disabling ACPI support\n"); @@ -548,6 +593,12 @@ result = acpi_table_parse(ACPI_HPET, acpi_parse_hpet); if (result < 0) printk("ACPI: no HPET table found (%d).\n", result); +#endif + +#ifdef CONFIG_PCI_MMCONFIG + result = acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg); + if (result) + printk(KERN_ERR PREFIX "Error %d parsing MCFG\n", result); #endif return 0; diff -Nru a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S --- a/arch/x86_64/kernel/entry.S Sun Mar 14 14:20:07 2004 +++ b/arch/x86_64/kernel/entry.S Sun Mar 14 14:20:07 2004 @@ -226,7 +226,7 @@ /* Handle a signal */ sysret_signal: sti - testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME),%edx + testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx jz 1f /* Really a signal */ @@ -307,7 +307,7 @@ jmp int_restore_rest int_signal: - testl $(_TIF_NOTIFY_RESUME|_TIF_SIGPENDING),%edx + testl $(_TIF_NOTIFY_RESUME|_TIF_SIGPENDING|_TIF_SINGLESTEP),%edx jz 1f movq %rsp,%rdi # &ptregs -> arg1 xorl %esi,%esi # oldset -> arg2 @@ -489,7 +489,7 @@ jmp retint_check retint_signal: - testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME),%edx + testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx jz retint_swapgs sti SAVE_REST @@ -572,6 +572,24 @@ jmp error_entry .endm + /* error code is on the stack already */ + /* handle NMI like exceptions that can happen everywhere */ + .macro paranoidentry sym + SAVE_ALL + cld + movl $1,%ebx + movl $MSR_GS_BASE,%ecx + rdmsr + testl %edx,%edx + js 1f + swapgs + xorl %ebx,%ebx +1: movq %rsp,%rdi + movq ORIG_RAX(%rsp),%rsi + movq $-1,ORIG_RAX(%rsp) + call \sym + .endm + /* * Exception entry point. This expects an error code/orig_rax on the stack * and the exception handler in %rax. @@ -625,6 +643,7 @@ movq ORIG_RAX(%rsp),%rsi /* get error code */ movq $-1,ORIG_RAX(%rsp) call *%rax + /* ebx: no swapgs flag (1: don't need swapgs, 0: need it) */ error_exit: movl %ebx,%eax RESTORE_REST @@ -776,48 +795,59 @@ zeroentry do_simd_coprocessor_error ENTRY(device_not_available) - CFI_STARTPROC - pushq $-1 #error code - SAVE_ALL - movl $1,%ebx - testl $3,CS(%rsp) - je 1f - xorl %ebx,%ebx - swapgs -1: movq %cr0,%rax - leaq math_state_restore(%rip),%rcx - leaq math_emulate(%rip),%rdx - testl $0x4,%eax - cmoveq %rcx,%rdx - call *%rdx - jmp error_exit - CFI_ENDPROC + zeroentry math_state_restore + /* runs on exception stack */ ENTRY(debug) - zeroentry do_debug + CFI_STARTPROC + pushq $0 + CFI_ADJUST_CFA_OFFSET 8 + paranoidentry do_debug +paranoid_stack_switch: + testq %rax,%rax + jz paranoid_exit + /* switch back to process stack to restore the state ptrace touched */ + movq %rax,%rsp + jmp paranoid_exit + CFI_ENDPROC + /* runs on exception stack */ ENTRY(nmi) CFI_STARTPROC pushq $-1 - SAVE_ALL - /* NMI could happen inside the critical section of a swapgs, - so it is needed to use this expensive way to check. */ - movl $MSR_GS_BASE,%ecx - rdmsr - xorl %ebx,%ebx - testl %edx,%edx - js 1f - swapgs - movl $1,%ebx -1: movq %rsp,%rdi # regs -> arg1 - call do_nmi - /* XXX: should do preemption checks here */ + CFI_ADJUST_CFA_OFFSET 8 + paranoidentry do_nmi + /* ebx: no swapgs flag */ +paranoid_exit: + testl $3,CS(%rsp) + jnz paranoid_userspace + testl %ebx,%ebx /* swapgs needed? */ + jnz paranoid_restore +paranoid_swapgs: cli - testl %ebx,%ebx - jz 2f swapgs -2: RESTORE_ALL 8 +paranoid_restore: + RESTORE_ALL 8 iretq +paranoid_userspace: + cli + GET_THREAD_INFO(%rcx) + movl threadinfo_flags(%rcx),%edx + testl $_TIF_NEED_RESCHED,%edx + jnz paranoid_resched + testl $(_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SINGLESTEP),%edx + jnz paranoid_signal + jmp paranoid_swapgs +paranoid_resched: + sti + call schedule + jmp paranoid_exit +paranoid_signal: + sti + xorl %esi,%esi /* oldset */ + movq %rsp,%rdi /* &pt_regs */ + call do_notify_resume + jmp paranoid_exit CFI_ENDPROC ENTRY(int3) @@ -838,8 +868,10 @@ ENTRY(reserved) zeroentry do_reserved + /* runs on exception stack */ ENTRY(double_fault) - errorentry do_double_fault + paranoidentry do_double_fault + jmp paranoid_stack_switch ENTRY(invalid_TSS) errorentry do_invalid_TSS @@ -847,8 +879,10 @@ ENTRY(segment_not_present) errorentry do_segment_not_present + /* runs on exception stack */ ENTRY(stack_segment) - errorentry do_stack_segment + paranoidentry do_stack_segment + jmp paranoid_stack_switch ENTRY(general_protection) errorentry do_general_protection @@ -862,8 +896,14 @@ ENTRY(spurious_interrupt_bug) zeroentry do_spurious_interrupt_bug + /* runs on exception stack */ ENTRY(machine_check) - zeroentry do_machine_check + CFI_STARTPROC + pushq $0 + CFI_ADJUST_CFA_OFFSET 8 + paranoidentry do_machine_check + jmp paranoid_exit + CFI_ENDPROC ENTRY(call_debug) zeroentry do_call_debug diff -Nru a/arch/x86_64/kernel/ioport.c b/arch/x86_64/kernel/ioport.c --- a/arch/x86_64/kernel/ioport.c Sun Mar 14 14:20:06 2004 +++ b/arch/x86_64/kernel/ioport.c Sun Mar 14 14:20:06 2004 @@ -95,7 +95,5 @@ return -EPERM; } regs.eflags = (regs.eflags &~ 0x3000UL) | (level << 12); - /* Make sure we return the long way (not sysenter) */ - set_thread_flag(TIF_IRET); return 0; } diff -Nru a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c --- a/arch/x86_64/kernel/mpparse.c Sun Mar 14 14:20:06 2004 +++ b/arch/x86_64/kernel/mpparse.c Sun Mar 14 14:20:06 2004 @@ -880,6 +880,7 @@ void __init mp_config_ioapic_for_sci(int irq) { +#ifdef CONFIG_ACPI_INTERPRETER int ioapic; int ioapic_pin; struct acpi_table_madt *madt; @@ -939,6 +940,7 @@ */ io_apic_set_pci_routing(ioapic, ioapic_pin, irq, (flags.trigger == 1 ? 0 : 1), (flags.polarity == 1 ? 0 : 1)); +#endif } #ifdef CONFIG_ACPI_PCI 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 Sun Mar 14 14:20:07 2004 +++ b/arch/x86_64/kernel/pci-gart.c Sun Mar 14 14:20:07 2004 @@ -50,6 +50,12 @@ #endif int iommu_merge = 0; int iommu_sac_force = 0; + +/* If this is disabled the IOMMU will use an optimized flushing strategy + of only flushing when an mapping is reused. With it true the GART is flushed + for every mapping. Problem is that doing the lazy flush seems to trigger + bugs with some popular PCI cards, in particular 3ware (but has been also + also seen with Qlogic at least). */ int iommu_fullflush = 1; #define MAX_NB 8 @@ -177,7 +183,7 @@ gfp |= GFP_DMA; dma_mask = 0xffffffff; } else { - dma_mask = hwdev->consistent_dma_mask; + dma_mask = hwdev->dev.coherent_dma_mask; } if (dma_mask == 0) diff -Nru a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c --- a/arch/x86_64/kernel/process.c Sun Mar 14 14:20:07 2004 +++ b/arch/x86_64/kernel/process.c Sun Mar 14 14:20:07 2004 @@ -16,7 +16,6 @@ * This file handles the architecture-dependent parts of process handling.. */ -#define __KERNEL_SYSCALLS__ #include #include @@ -25,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -53,7 +51,7 @@ unsigned long kernel_thread_flags = CLONE_VM | CLONE_UNTRACED; -int hlt_counter; +atomic_t hlt_counter = ATOMIC_INIT(0); /* * Powermanagement idle function, if any.. @@ -62,14 +60,14 @@ void disable_hlt(void) { - hlt_counter++; + atomic_inc(&hlt_counter); } EXPORT_SYMBOL(disable_hlt); void enable_hlt(void) { - hlt_counter--; + atomic_dec(&hlt_counter); } EXPORT_SYMBOL(enable_hlt); @@ -80,7 +78,7 @@ */ void default_idle(void) { - if (!hlt_counter) { + if (!atomic_read(&hlt_counter)) { local_irq_disable(); if (!need_resched()) safe_halt(); diff -Nru a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c --- a/arch/x86_64/kernel/setup.c Sun Mar 14 14:20:06 2004 +++ b/arch/x86_64/kernel/setup.c Sun Mar 14 14:20:06 2004 @@ -218,6 +218,11 @@ if (!memcmp(from, "acpi=ht", 7)) { acpi_ht = 1; } + + /* acpi=strict disables out-of-spec workarounds */ + else if (!memcmp(from, "acpi=strict", 11)) { + acpi_strict = 1; + } #endif if (!memcmp(from, "nolapic", 7) || @@ -793,13 +798,12 @@ char *model_names[16]; }; -/* - * This does the hard work of actually picking apart the CPU stuff... - */ -void __init identify_cpu(struct cpuinfo_x86 *c) +/* Do some early cpuid on the boot CPU to get some parameter that are + needed before check_bugs. Everything advanced is in identify_cpu + below. */ +void __init early_identify_cpu(struct cpuinfo_x86 *c) { - int i; - u32 xlvl, tfms; + u32 tfms; c->loops_per_jiffy = loops_per_jiffy; c->x86_cache_size = -1; @@ -807,6 +811,7 @@ c->x86_model = c->x86_mask = 0; /* So far unknown... */ c->x86_vendor_id[0] = '\0'; /* Unset */ c->x86_model_id[0] = '\0'; /* Unset */ + c->x86_clflush_size = 64; memset(&c->x86_capability, 0, sizeof c->x86_capability); /* Get vendor name */ @@ -816,6 +821,7 @@ (int *)&c->x86_vendor_id[4]); get_cpu_vendor(c); + /* Initialize the standard set of capabilities */ /* Note that the vendor-specific code below might override */ @@ -837,6 +843,17 @@ /* Have CPUID level 0 only - unheard of */ c->x86 = 4; } +} + +/* + * This does the hard work of actually picking apart the CPU stuff... + */ +void __init identify_cpu(struct cpuinfo_x86 *c) +{ + int i; + u32 xlvl; + + early_identify_cpu(c); /* AMD-defined flags: level 0x80000001 */ xlvl = cpuid_eax(0x80000000); @@ -853,7 +870,6 @@ if ( xlvl >= 0x80860001 ) c->x86_capability[2] = cpuid_edx(0x80860001); } - /* * Vendor-specific initialization. In this section we diff -Nru a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c --- a/arch/x86_64/kernel/setup64.c Sun Mar 14 14:20:06 2004 +++ b/arch/x86_64/kernel/setup64.c Sun Mar 14 14:20:06 2004 @@ -202,7 +202,7 @@ wrmsrl(MSR_LSTAR, system_call); #ifdef CONFIG_IA32_EMULATION - wrmsrl(MSR_CSTAR, ia32_cstar_target); + syscall32_cpu_init (); #endif /* Flags to clear on syscall */ @@ -274,6 +274,9 @@ asm volatile("pushfq ; popq %%rax ; btr $14,%%rax ; pushq %%rax ; popfq" ::: "eax"); + if (cpu == 0) + early_identify_cpu(&boot_cpu_data); + syscall_init(); wrmsrl(MSR_FS_BASE, 0); @@ -287,7 +290,8 @@ */ for (v = 0; v < N_EXCEPTION_STACKS; v++) { if (cpu) { - estacks = (char *)__get_free_pages(GFP_ATOMIC, 0); + estacks = (char *)__get_free_pages(GFP_ATOMIC, + EXCEPTION_STACK_ORDER); if (!estacks) panic("Cannot allocate exception stack %ld %d\n", v, cpu); diff -Nru a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c --- a/arch/x86_64/kernel/smpboot.c Sun Mar 14 14:20:08 2004 +++ b/arch/x86_64/kernel/smpboot.c Sun Mar 14 14:20:08 2004 @@ -55,11 +55,16 @@ /* Number of siblings per CPU package */ int smp_num_siblings = 1; -int phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */ +char phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */ /* Bitmask of currently online CPUs */ cpumask_t cpu_online_map; +/* which CPU (physical APIC ID) maps to which logical CPU number */ +volatile char x86_apicid_to_cpu[NR_CPUS]; +/* which logical CPU number maps to which CPU (physical APIC ID) */ +volatile char x86_cpu_to_apicid[NR_CPUS]; + static cpumask_t cpu_callin_map; cpumask_t cpu_callout_map; static cpumask_t smp_commenced_mask; @@ -70,7 +75,7 @@ /* Set when the idlers are all forked */ int smp_threads_ready; -int cpu_sibling_map[NR_CPUS] __cacheline_aligned; +char cpu_sibling_map[NR_CPUS] __cacheline_aligned; /* * Trampoline 80x86 program as an array. @@ -574,6 +579,9 @@ if (IS_ERR(idle)) panic("failed fork for CPU %d", cpu); wake_up_forked_process(idle); + x86_cpu_to_apicid[cpu] = apicid; + x86_apicid_to_cpu[apicid] = cpu; + /* * We remove it from the pidhash and the runqueue @@ -885,7 +893,7 @@ break; } } - if (cpu_sibling_map[cpu] == NO_PROC_ID) { + if (cpu_sibling_map[cpu] == (char)NO_PROC_ID) { smp_num_siblings = 1; printk(KERN_WARNING "WARNING: No sibling found for CPU %d.\n", cpu); } diff -Nru a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c --- a/arch/x86_64/kernel/traps.c Sun Mar 14 14:20:05 2004 +++ b/arch/x86_64/kernel/traps.c Sun Mar 14 14:20:05 2004 @@ -351,24 +351,19 @@ void __die(const char * str, struct pt_regs * regs, long err) { - int nl = 0; static int die_counter; - printk(KERN_EMERG "%s: %04lx [%u]\n", str, err & 0xffff,++die_counter); - notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV); + printk(KERN_EMERG "%s: %04lx [%u] ", str, err & 0xffff,++die_counter); #ifdef CONFIG_PREEMPT printk("PREEMPT "); - nl = 1; #endif #ifdef CONFIG_SMP printk("SMP "); - nl = 1; #endif #ifdef CONFIG_DEBUG_PAGEALLOC printk("DEBUG_PAGEALLOC"); - nl = 1; #endif - if (nl) printk("\n"); + notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV); show_registers(regs); /* Executive summary in case the oops scrolled away */ printk("RIP "); @@ -475,14 +470,27 @@ DO_ERROR( 5, SIGSEGV, "bounds", bounds) DO_ERROR_INFO( 6, SIGILL, "invalid operand", invalid_op, ILL_ILLOPN, regs->rip) DO_ERROR( 7, SIGSEGV, "device not available", device_not_available) -DO_ERROR( 8, SIGSEGV, "double fault", double_fault) DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun) DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) -DO_ERROR(12, SIGBUS, "stack segment", stack_segment) DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, get_cr2()) DO_ERROR(18, SIGSEGV, "reserved", reserved) +#define DO_ERROR_STACK(trapnr, signr, str, name) \ +asmlinkage unsigned long do_##name(struct pt_regs * regs, long error_code) \ +{ \ + struct pt_regs *pr = ((struct pt_regs *)(current->thread.rsp0))-1; \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) == NOTIFY_BAD) \ + return 0; \ + if (regs->cs & 3) \ + memcpy(pr, regs, sizeof(struct pt_regs)); \ + do_trap(trapnr, signr, str, regs, error_code, NULL); \ + return (regs->cs & 3) ? (unsigned long)pr : 0; \ +} + +DO_ERROR_STACK(12, SIGBUS, "stack segment", stack_segment) +DO_ERROR_STACK( 8, SIGSEGV, "double fault", double_fault) + asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) { conditional_sti(regs); @@ -596,12 +604,18 @@ inb(0x71); /* dummy */ } -asmlinkage void do_debug(struct pt_regs * regs, long error_code) +/* runs on IST stack. */ +asmlinkage unsigned long do_debug(struct pt_regs * regs, unsigned long error_code) { + struct pt_regs *processregs; unsigned long condition; struct task_struct *tsk = current; siginfo_t info; + processregs = (struct pt_regs *)(current->thread.rsp0)-1; + if (regs->cs & 3) + memcpy(processregs, regs, sizeof(struct pt_regs)); + #ifdef CONFIG_CHECKING { /* RED-PEN interaction with debugger - could destroy gs */ @@ -658,17 +672,21 @@ force_sig_info(SIGTRAP, &info, tsk); clear_dr7: asm volatile("movq %0,%%db7"::"r"(0UL)); - notify_die(DIE_DEBUG, "debug", regs, error_code, 1, SIGTRAP); - return; + notify_die(DIE_DEBUG, "debug", regs, condition, 1, SIGTRAP); +out: + return (regs->cs & 3) ? (unsigned long)processregs : 0; clear_TF_reenable: + printk("clear_tf_reenable\n"); 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) + if (notify_die(DIE_DEBUG, "debug2", regs, condition, 1, SIGTRAP) + != NOTIFY_BAD) regs->eflags &= ~TF_MASK; - return; + + goto out; } /* @@ -730,7 +748,7 @@ force_sig_info(SIGFPE, &info, task); } -asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code) +asmlinkage void do_coprocessor_error(struct pt_regs * regs) { conditional_sti(regs); math_error((void *)regs->rip); @@ -789,8 +807,7 @@ force_sig_info(SIGFPE, &info, task); } -asmlinkage void do_simd_coprocessor_error(struct pt_regs * regs, - long error_code) +asmlinkage void do_simd_coprocessor_error(struct pt_regs * regs) { conditional_sti(regs); simd_math_error((void *)regs->rip); @@ -818,11 +835,6 @@ me->thread_info->status |= TS_USEDFPU; } -asmlinkage void math_emulate(void) -{ - BUG(); -} - void do_call_debug(struct pt_regs *regs) { notify_die(DIE_CALL, "debug call", regs, 0, 255, SIGINT); @@ -831,7 +843,7 @@ void __init trap_init(void) { set_intr_gate(0,÷_error); - set_intr_gate(1,&debug); + set_intr_gate_ist(1,&debug,DEBUG_STACK); set_intr_gate_ist(2,&nmi,NMI_STACK); set_system_gate(3,&int3); /* int3-5 can be called from all */ set_system_gate(4,&overflow); @@ -848,7 +860,7 @@ set_intr_gate(15,&spurious_interrupt_bug); set_intr_gate(16,&coprocessor_error); set_intr_gate(17,&alignment_check); - set_intr_gate(18,&machine_check); + set_intr_gate_ist(18,&machine_check, MCE_STACK); set_intr_gate(19,&simd_coprocessor_error); #ifdef CONFIG_IA32_EMULATION diff -Nru a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c --- a/arch/x86_64/kernel/vsyscall.c Sun Mar 14 14:20:08 2004 +++ b/arch/x86_64/kernel/vsyscall.c Sun Mar 14 14:20:08 2004 @@ -31,9 +31,6 @@ * broken programs will segfault and there's no security risk until we choose to * fix it. * - * Add HPET support (port from 2.4). Still needed? - * Nop out vsyscall syscall to avoid anchor for buffer overflows when sysctl off. - * * These are not urgent things that we need to address only before shipping the first * production binary kernels. */ @@ -89,7 +86,7 @@ if (t < __vxtime.last_tsc) t = __vxtime.last_tsc; usec += ((t - __vxtime.last_tsc) * __vxtime.tsc_quot) >> 32; - /* See comment in x86_64 do_gettimeopfday. */ + /* See comment in x86_64 do_gettimeofday. */ } else { usec += ((readl(fix_to_virt(VSYSCALL_HPET) + 0xf0) - __vxtime.last) * __vxtime.quot) >> 32; @@ -106,6 +103,7 @@ *tz = __sys_tz; } + static force_inline int gettimeofday(struct timeval *tv, struct timezone *tz) { int ret; @@ -115,6 +113,15 @@ return ret; } +static force_inline long time_syscall(long *t) +{ + long secs; + asm volatile("syscall" + : "=a" (secs) + : "0" (__NR_time),"D" (t) : __syscall_clobber); + return secs; +} + static int __vsyscall(0) vgettimeofday(struct timeval * tv, struct timezone * tz) { if (unlikely(!__sysctl_vsyscall)) @@ -126,16 +133,15 @@ return 0; } -static time_t __vsyscall(1) vtime(time_t * t) +/* This will break when the xtime seconds get inaccurate, but that is + * unlikely */ +static time_t __vsyscall(1) vtime(time_t *t) { - struct timeval tv; if (unlikely(!__sysctl_vsyscall)) - gettimeofday(&tv, NULL); - else - do_vgettimeofday(&tv); - if (t) - *t = tv.tv_sec; - return tv.tv_sec; + return time_syscall(t); + else if (t) + *t = __xtime.tv_sec; + return __xtime.tv_sec; } static long __vsyscall(2) venosys_0(void) diff -Nru a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms.c --- a/arch/x86_64/kernel/x8664_ksyms.c Sun Mar 14 14:20:06 2004 +++ b/arch/x86_64/kernel/x8664_ksyms.c Sun Mar 14 14:20:06 2004 @@ -63,10 +63,6 @@ EXPORT_SYMBOL(pm_power_off); EXPORT_SYMBOL(get_cmos_time); -#ifdef CONFIG_IO_DEBUG -EXPORT_SYMBOL(__io_virt_debug); -#endif - EXPORT_SYMBOL_NOVERS(__down_failed); EXPORT_SYMBOL_NOVERS(__down_failed_interruptible); EXPORT_SYMBOL_NOVERS(__down_failed_trylock); @@ -225,3 +221,6 @@ #endif EXPORT_SYMBOL(sys_ioctl); + +EXPORT_SYMBOL(memcpy_toio); +EXPORT_SYMBOL(memcpy_fromio); diff -Nru a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile --- a/arch/x86_64/lib/Makefile Sun Mar 14 14:20:06 2004 +++ b/arch/x86_64/lib/Makefile Sun Mar 14 14:20:06 2004 @@ -9,5 +9,4 @@ thunk.o io.o clear_page.o copy_page.o bitstr.o lib-y += memcpy.o memmove.o memset.o copy_user.o -lib-$(CONFIG_IO_DEBUG) += iodebug.o lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o diff -Nru a/arch/x86_64/lib/csum-copy.S b/arch/x86_64/lib/csum-copy.S --- a/arch/x86_64/lib/csum-copy.S Sun Mar 14 14:20:08 2004 +++ b/arch/x86_64/lib/csum-copy.S Sun Mar 14 14:20:08 2004 @@ -220,10 +220,14 @@ /* Exception handlers. Very simple, zeroing is done in the wrappers */ .Lbad_source: movq (%rsp),%rax + testq %rax,%rax + jz .Lende movl $-EFAULT,(%rax) jmp .Lende .Lbad_dest: movq 8(%rsp),%rax + testq %rax,%rax + jz .Lende movl $-EFAULT,(%rax) jmp .Lende diff -Nru a/arch/x86_64/lib/io.c b/arch/x86_64/lib/io.c --- a/arch/x86_64/lib/io.c Sun Mar 14 14:20:06 2004 +++ b/arch/x86_64/lib/io.c Sun Mar 14 14:20:06 2004 @@ -4,14 +4,10 @@ void *memcpy_toio(void *dst,const void*src,unsigned len) { - return __inline_memcpy(__io_virt(dst),src,len); + return __inline_memcpy(dst,src,len); } void *memcpy_fromio(void *dst,const void*src,unsigned len) { - return __inline_memcpy(dst,__io_virt(src),len); + return __inline_memcpy(dst,src,len); } - -EXPORT_SYMBOL(memcpy_toio); -EXPORT_SYMBOL(memcpy_fromio); - diff -Nru a/arch/x86_64/lib/iodebug.c b/arch/x86_64/lib/iodebug.c --- a/arch/x86_64/lib/iodebug.c Sun Mar 14 14:20:07 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,11 +0,0 @@ -#include - -void * __io_virt_debug(unsigned long x, const char *file, int line) -{ - if (x < PAGE_OFFSET) { - printk("io mapaddr 0x%05lx not valid at %s:%d!\n", x, file, line); - return __va(x); - } - return (void *)x; -} - diff -Nru a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c --- a/arch/x86_64/mm/fault.c Sun Mar 14 14:20:05 2004 +++ b/arch/x86_64/mm/fault.c Sun Mar 14 14:20:05 2004 @@ -280,15 +280,6 @@ if (unlikely(in_atomic() || !mm)) goto bad_area_nosemaphore; - /* Work around K8 erratum #100 - K8 in compat mode occasionally jumps to illegal addresses >4GB. - We catch this here in the page fault handler because these - addresses are not reachable. Just detect this case and return. - Any code segment in LDT is compatibility mode. */ - if ((regs->cs == __USER32_CS || (regs->cs & (1<<2))) && - (address >> 32)) - return; - again: down_read(&mm->mmap_sem); @@ -371,6 +362,16 @@ /* User mode accesses just cause a SIGSEGV */ if (error_code & 4) { if (is_prefetch(regs, address)) + return; + + /* Work around K8 erratum #100 K8 in compat mode + occasionally jumps to illegal addresses >4GB. We + catch this here in the page fault handler because + these addresses are not reachable. Just detect this + case and return. Any code segment in LDT is + compatibility mode. */ + if ((regs->cs == __USER32_CS || (regs->cs & (1<<2))) && + (address >> 32)) return; if (exception_trace && !unhandled_signal(tsk, SIGSEGV)) { diff -Nru a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c --- a/arch/x86_64/mm/init.c Sun Mar 14 14:20:06 2004 +++ b/arch/x86_64/mm/init.c Sun Mar 14 14:20:06 2004 @@ -37,7 +37,9 @@ #include #include +#ifndef Dprintk #define Dprintk(x...) +#endif extern char _stext[]; @@ -577,3 +579,32 @@ } __initcall(x8664_sysctl_init); #endif + +/* Pseudo VMAs to allow ptrace access for the vsyscall pages. x86-64 has two + different ones: one for 32bit and one for 64bit. Use the appropiate + for the target task. */ + +static struct vm_area_struct gate_vma = { + .vm_start = VSYSCALL_START, + .vm_end = VSYSCALL_END, + .vm_page_prot = PAGE_READONLY +}; + +static struct vm_area_struct gate32_vma = { + .vm_start = VSYSCALL32_BASE, + .vm_end = VSYSCALL32_END, + .vm_page_prot = PAGE_READONLY +}; + +struct vm_area_struct *get_gate_vma(struct task_struct *tsk) +{ + return test_tsk_thread_flag(tsk, TIF_IA32) ? &gate32_vma : &gate_vma; +} + +int in_gate_area(struct task_struct *task, unsigned long addr) +{ + struct vm_area_struct *vma = &gate_vma; + if (test_tsk_thread_flag(task, TIF_IA32)) + vma = &gate32_vma; + return (addr >= vma->vm_start) && (addr < vma->vm_end); +} diff -Nru a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c --- a/arch/x86_64/mm/numa.c Sun Mar 14 14:20:08 2004 +++ b/arch/x86_64/mm/numa.c Sun Mar 14 14:20:08 2004 @@ -14,7 +14,9 @@ #include #include +#ifndef Dprintk #define Dprintk(x...) +#endif struct pglist_data *node_data[MAXNODE]; bootmem_data_t plat_node_bdata[MAX_NUMNODES]; diff -Nru a/arch/x86_64/pci/Makefile b/arch/x86_64/pci/Makefile --- a/arch/x86_64/pci/Makefile Sun Mar 14 14:20:06 2004 +++ b/arch/x86_64/pci/Makefile Sun Mar 14 14:20:06 2004 @@ -1,29 +1,22 @@ # # Makefile for X86_64 specific PCI routines # -# Reuse the i386 PCI subsystem using symlinks +# Reuse the i386 PCI subsystem # +CFLAGS += -I arch/i386/pci + obj-y := i386.o obj-$(CONFIG_PCI_DIRECT)+= direct.o obj-y += fixup.o obj-$(CONFIG_ACPI_PCI) += acpi.o obj-y += legacy.o irq.o common.o +# mmconfig has a 64bit special +obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o -$(obj)/direct.c: $(obj)/pci.h - @ln -sf ../../i386/pci/direct.c $(obj)/direct.c -$(obj)/legacy.c: $(obj)/pci.h - @ln -sf ../../i386/pci/legacy.c $(obj)/legacy.c -$(obj)/common.c: $(obj)/pci.h - @ln -sf ../../i386/pci/common.c $(obj)/common.c -$(obj)/acpi.c: $(obj)/pci.h - @ln -sf ../../i386/pci/acpi.c $(obj)/acpi.c -$(obj)/pci.h: - @ln -sf ../../i386/pci/pci.h $(obj)/pci.h -$(obj)/irq.c: $(obj)/pci.h - @ln -sf ../../i386/pci/irq.c $(obj)/irq.c -$(obj)/fixup.c: $(obj)/pci.h - @ln -sf ../../i386/pci/fixup.c $(obj)/fixup.c -$(obj)/i386.c: $(obj)/pci.h - @ln -sf ../../i386/pci/i386.c $(obj)/i386.c - -clean-files += i386.c legacy.c fixup.c acpi.c irq.c pci.h common.c direct.c +direct-y += ../../i386/pci/direct.o +acpi-y += ../../i386/pci/acpi.o +legacy-y += ../../i386/pci/legacy.o +irq-y += ../../i386/pci/irq.o +common-y += ../../i386/pci/common.o +fixup-y += ../../i386/pci/fixup.o +i386-y += ../../i386/pci/i386.o diff -Nru a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/x86_64/pci/mmconfig.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,98 @@ +/* + * mmconfig.c - Low-level direct PCI config space access via MMCONFIG + * + * This is an 64bit optimized version that always keeps the full mmconfig + * space mapped. This allows lockless config space operation. + */ + +#include +#include +#include "pci.h" + +#define MMCONFIG_APER_SIZE (256*1024*1024) + +/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */ +u32 pci_mmcfg_base_addr; + +/* Static virtual mapping of the MMCONFIG aperture */ +char *pci_mmcfg_virt; + +static inline char *pci_dev_base(int bus, int devfn) +{ + return pci_mmcfg_virt + ((bus << 20) | (devfn << 12)); +} + +static int pci_mmcfg_read(int seg, int bus, int devfn, int reg, int len, u32 *value) +{ + char *addr = pci_dev_base(bus, devfn); + + if (unlikely(!value || (bus > 255) || (devfn > 255) || (reg > 4095))) + return -EINVAL; + + switch (len) { + case 1: + *value = readb(addr + reg); + break; + case 2: + *value = readw(addr + reg); + break; + case 4: + *value = readl(addr + reg); + break; + } + + return 0; +} + +static int pci_mmcfg_write(int seg, int bus, int devfn, int reg, int len, u32 value) +{ + char *addr = pci_dev_base(bus,devfn); + + if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) + return -EINVAL; + + switch (len) { + case 1: + writeb(value, addr + reg); + break; + case 2: + writew(value, addr + reg); + break; + case 4: + writel(value, addr + reg); + break; + } + + /* Dummy read to flush PCI write */ + readl(addr); + + return 0; +} + +static struct pci_raw_ops pci_mmcfg = { + .read = pci_mmcfg_read, + .write = pci_mmcfg_write, +}; + +static int __init pci_mmcfg_init(void) +{ + if ((pci_probe & PCI_PROBE_MMCONF) == 0) + return 0; + if (!pci_mmcfg_base_addr) + return 0; + + /* RED-PEN i386 doesn't do _nocache right now */ + pci_mmcfg_virt = ioremap_nocache(pci_mmcfg_base_addr, MMCONFIG_APER_SIZE); + if (!pci_mmcfg_virt) { + printk("PCI: Cannot map mmconfig aperture\n"); + return 0; + } + + printk(KERN_INFO "PCI: Using MMCONFIG at %lx\n", pci_mmcfg_base_addr); + raw_pci_ops = &pci_mmcfg; + pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; + + return 0; +} + +arch_initcall(pci_mmcfg_init); diff -Nru a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c --- a/drivers/acpi/dispatcher/dsmethod.c Sun Mar 14 14:20:07 2004 +++ b/drivers/acpi/dispatcher/dsmethod.c Sun Mar 14 14:20:07 2004 @@ -106,7 +106,7 @@ /* Create a mutex for the method if there is a concurrency limit */ - if ((obj_desc->method.concurrency != INFINITE_CONCURRENCY) && + if ((obj_desc->method.concurrency != ACPI_INFINITE_CONCURRENCY) && (!obj_desc->method.semaphore)) { status = acpi_os_create_semaphore (obj_desc->method.concurrency, obj_desc->method.concurrency, @@ -300,34 +300,37 @@ return_ACPI_STATUS (status); } - /* 1) Parse: Create a new walk state for the preempting walk */ + if (!(obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY)) { + /* 1) Parse: Create a new walk state for the preempting walk */ - next_walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id, - op, obj_desc, NULL); - if (!next_walk_state) { - return_ACPI_STATUS (AE_NO_MEMORY); - } + next_walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id, + op, obj_desc, NULL); + if (!next_walk_state) { + return_ACPI_STATUS (AE_NO_MEMORY); + } - /* Create and init a Root Node */ - op = acpi_ps_create_scope_op (); - if (!op) { - status = AE_NO_MEMORY; - goto cleanup; - } + /* Create and init a Root Node */ - status = acpi_ds_init_aml_walk (next_walk_state, op, method_node, - obj_desc->method.aml_start, obj_desc->method.aml_length, - NULL, NULL, 1); - if (ACPI_FAILURE (status)) { - acpi_ds_delete_walk_state (next_walk_state); - goto cleanup; - } + op = acpi_ps_create_scope_op (); + if (!op) { + status = AE_NO_MEMORY; + goto cleanup; + } + + status = acpi_ds_init_aml_walk (next_walk_state, op, method_node, + obj_desc->method.aml_start, obj_desc->method.aml_length, + NULL, NULL, 1); + if (ACPI_FAILURE (status)) { + acpi_ds_delete_walk_state (next_walk_state); + goto cleanup; + } - /* Begin AML parse */ + /* Begin AML parse */ - status = acpi_ps_parse_aml (next_walk_state); - acpi_ps_delete_parse_tree (op); + status = acpi_ps_parse_aml (next_walk_state); + acpi_ps_delete_parse_tree (op); + } /* 2) Execute: Create a new state for the preempting walk */ @@ -337,7 +340,6 @@ status = AE_NO_MEMORY; goto cleanup; } - /* * The resolved arguments were put on the previous walk state's operand * stack. Operands on the previous walk state stack always @@ -369,16 +371,25 @@ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Starting nested execution, newstate=%p\n", next_walk_state)); + if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { + status = obj_desc->method.implementation (next_walk_state); + return_ACPI_STATUS (status); + } + return_ACPI_STATUS (AE_OK); /* On error, we must delete the new walk state */ cleanup: + if (next_walk_state->method_desc) { + /* Decrement the thread count on the method parse tree */ + + next_walk_state->method_desc->method.thread_count--; + } (void) acpi_ds_terminate_control_method (next_walk_state); acpi_ds_delete_walk_state (next_walk_state); return_ACPI_STATUS (status); - } @@ -500,10 +511,30 @@ } } - /* Decrement the thread count on the method parse tree */ + if (walk_state->method_desc->method.thread_count) { + ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, + "*** Not deleting method namespace, there are still %d threads\n", + walk_state->method_desc->method.thread_count)); + } - walk_state->method_desc->method.thread_count--; if (!walk_state->method_desc->method.thread_count) { + /* + * Support to dynamically change a method from not_serialized to + * Serialized if it appears that the method is written foolishly and + * does not support multiple thread execution. The best example of this + * is if such a method creates namespace objects and blocks. A second + * thread will fail with an AE_ALREADY_EXISTS exception + * + * This code is here because we must wait until the last thread exits + * before creating the synchronization semaphore. + */ + if ((walk_state->method_desc->method.concurrency == 1) && + (!walk_state->method_desc->method.semaphore)) { + status = acpi_os_create_semaphore (1, + 1, + &walk_state->method_desc->method.semaphore); + } + /* * There are no more threads executing this method. Perform * additional cleanup. diff -Nru a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c --- a/drivers/acpi/events/evgpe.c Sun Mar 14 14:20:07 2004 +++ b/drivers/acpi/events/evgpe.c Sun Mar 14 14:20:07 2004 @@ -149,6 +149,11 @@ ACPI_FUNCTION_NAME ("ev_gpe_detect"); + /* Check for the case where there are no GPEs */ + + if (!gpe_xrupt_list) { + return (int_status); + } /* Examine all GPE blocks attached to this interrupt level */ diff -Nru a/drivers/acpi/executer/excreate.c b/drivers/acpi/executer/excreate.c --- a/drivers/acpi/executer/excreate.c Sun Mar 14 14:20:08 2004 +++ b/drivers/acpi/executer/excreate.c Sun Mar 14 14:20:08 2004 @@ -587,27 +587,33 @@ obj_desc->method.aml_start = aml_start; obj_desc->method.aml_length = aml_length; - /* disassemble the method flags */ - + /* + * Disassemble the method flags. Split off the Arg Count + * for efficiency + */ method_flags = (u8) operand[1]->integer.value; - obj_desc->method.method_flags = method_flags; - obj_desc->method.param_count = (u8) (method_flags & METHOD_FLAGS_ARG_COUNT); + obj_desc->method.method_flags = (u8) (method_flags & ~AML_METHOD_ARG_COUNT); + obj_desc->method.param_count = (u8) (method_flags & AML_METHOD_ARG_COUNT); /* * Get the concurrency count. If required, a semaphore will be * created for this method when it is parsed. */ - if (method_flags & METHOD_FLAGS_SERIALIZED) { + if (acpi_gbl_all_methods_serialized) { + obj_desc->method.concurrency = 1; + obj_desc->method.method_flags |= AML_METHOD_SERIALIZED; + } + else if (method_flags & AML_METHOD_SERIALIZED) { /* * ACPI 1.0: Concurrency = 1 * ACPI 2.0: Concurrency = (sync_level (in method declaration) + 1) */ obj_desc->method.concurrency = (u8) - (((method_flags & METHOD_FLAGS_SYNCH_LEVEL) >> 4) + 1); + (((method_flags & AML_METHOD_SYNCH_LEVEL) >> 4) + 1); } else { - obj_desc->method.concurrency = INFINITE_CONCURRENCY; + obj_desc->method.concurrency = ACPI_INFINITE_CONCURRENCY; } /* Attach the new object to the method Node */ diff -Nru a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c --- a/drivers/acpi/executer/exmutex.c Sun Mar 14 14:20:08 2004 +++ b/drivers/acpi/executer/exmutex.c Sun Mar 14 14:20:08 2004 @@ -176,15 +176,18 @@ /* * Support for multiple acquires by the owning thread */ + if (obj_desc->mutex.owner_thread) { + /* Special case for Global Lock, allow all threads */ - if ((obj_desc->mutex.owner_thread) && - (obj_desc->mutex.owner_thread->thread_id == walk_state->thread->thread_id)) { - /* - * The mutex is already owned by this thread, - * just increment the acquisition depth - */ - obj_desc->mutex.acquisition_depth++; - return_ACPI_STATUS (AE_OK); + if ((obj_desc->mutex.owner_thread->thread_id == walk_state->thread->thread_id) || + (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore)) { + /* + * The mutex is already owned by this thread, + * just increment the acquisition depth + */ + obj_desc->mutex.acquisition_depth++; + return_ACPI_STATUS (AE_OK); + } } /* Acquire the mutex, wait if necessary */ @@ -254,9 +257,12 @@ return_ACPI_STATUS (AE_AML_INTERNAL); } - /* The Mutex is owned, but this thread must be the owner */ - - if (obj_desc->mutex.owner_thread->thread_id != walk_state->thread->thread_id) { + /* + * The Mutex is owned, but this thread must be the owner. + * Special case for Global Lock, any thread can release + */ + if ((obj_desc->mutex.owner_thread->thread_id != walk_state->thread->thread_id) && + (obj_desc->mutex.semaphore != acpi_gbl_global_lock_semaphore)) { ACPI_REPORT_ERROR (( "Thread %X cannot release Mutex [%4.4s] acquired by thread %X\n", walk_state->thread->thread_id, diff -Nru a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c --- a/drivers/acpi/hardware/hwsleep.c Sun Mar 14 14:20:06 2004 +++ b/drivers/acpi/hardware/hwsleep.c Sun Mar 14 14:20:06 2004 @@ -394,7 +394,7 @@ * ******************************************************************************/ -acpi_status +acpi_status asmlinkage acpi_enter_sleep_state_s4bios ( void) { diff -Nru a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c --- a/drivers/acpi/namespace/nsaccess.c Sun Mar 14 14:20:08 2004 +++ b/drivers/acpi/namespace/nsaccess.c Sun Mar 14 14:20:08 2004 @@ -105,8 +105,15 @@ "Entering predefined entries into namespace\n")); for (init_val = acpi_gbl_pre_defined_names; init_val->name; init_val++) { + /* _OSI is optional for now, will be permanent later */ + + if (!ACPI_STRCMP (init_val->name, "_OSI") && !acpi_gbl_create_osi_method) { + continue; + } + status = acpi_ns_lookup (NULL, init_val->name, init_val->type, - ACPI_IMODE_LOAD_PASS2, ACPI_NS_NO_UPSEARCH, NULL, &new_node); + ACPI_IMODE_LOAD_PASS2, ACPI_NS_NO_UPSEARCH, + NULL, &new_node); if (ACPI_FAILURE (status) || (!new_node)) /* Must be on same line for code converter */ { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, @@ -122,7 +129,8 @@ if (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", + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, + "Could not override predefined %s\n", init_val->name)); } @@ -147,15 +155,20 @@ */ switch (init_val->type) { case ACPI_TYPE_METHOD: - obj_desc->method.param_count = - (u8) ACPI_STRTOUL (val, NULL, 10); + obj_desc->method.param_count = (u8) ACPI_STRTOUL + (val, NULL, 10); obj_desc->common.flags |= AOPOBJ_DATA_VALID; -#if defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY) +#if defined (_ACPI_ASL_COMPILER) || defined (_ACPI_DUMP_App) - /* Compiler cheats by putting parameter count in the owner_iD */ + /* i_aSL Compiler cheats by putting parameter count in the owner_iD */ new_node->owner_id = obj_desc->method.param_count; +#else + /* Mark this as a very SPECIAL method */ + + obj_desc->method.method_flags = AML_METHOD_INTERNAL_ONLY; + obj_desc->method.implementation = acpi_ut_osi_implementation; #endif break; @@ -180,8 +193,8 @@ case ACPI_TYPE_MUTEX: obj_desc->mutex.node = new_node; - obj_desc->mutex.sync_level = - (u16) ACPI_STRTOUL (val, NULL, 10); + obj_desc->mutex.sync_level = (u16) ACPI_STRTOUL + (val, NULL, 10); if (ACPI_STRCMP (init_val->name, "_GL_") == 0) { /* @@ -213,6 +226,7 @@ default: + ACPI_REPORT_ERROR (("Unsupported initial type value %X\n", init_val->type)); acpi_ut_remove_reference (obj_desc); diff -Nru a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c --- a/drivers/acpi/namespace/nsalloc.c Sun Mar 14 14:20:07 2004 +++ b/drivers/acpi/namespace/nsalloc.c Sun Mar 14 14:20:07 2004 @@ -334,10 +334,11 @@ node->owner_id = owner_id; node->type = (u8) type; - ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%4.4s (%s) added to %4.4s (%s) %p at %p\n", - acpi_ut_get_node_name (node), acpi_ut_get_type_name (node->type), + ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, + "%4.4s (%s) [Node %p Owner %X] added to %4.4s (%s) [Node %p]\n", + acpi_ut_get_node_name (node), acpi_ut_get_type_name (node->type), node, owner_id, acpi_ut_get_node_name (parent_node), acpi_ut_get_type_name (parent_node->type), - parent_node, node)); + parent_node)); /* * Increment the reference count(s) of all parents up to diff -Nru a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c --- a/drivers/acpi/namespace/nseval.c Sun Mar 14 14:20:07 2004 +++ b/drivers/acpi/namespace/nseval.c Sun Mar 14 14:20:07 2004 @@ -82,11 +82,11 @@ union acpi_operand_object **params, union acpi_operand_object **return_object) { - struct acpi_namespace_node *prefix_node; acpi_status status; + struct acpi_namespace_node *prefix_node; struct acpi_namespace_node *node = NULL; + union acpi_generic_state *scope_info; char *internal_path = NULL; - union acpi_generic_state scope_info; ACPI_FUNCTION_TRACE ("ns_evaluate_relative"); @@ -106,6 +106,11 @@ return_ACPI_STATUS (status); } + scope_info = acpi_ut_create_generic_state (); + if (!scope_info) { + goto cleanup1; + } + /* Get the prefix handle and Node */ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE); @@ -122,8 +127,8 @@ /* Lookup the name in the namespace */ - scope_info.scope.node = prefix_node; - status = acpi_ns_lookup (&scope_info, internal_path, ACPI_TYPE_ANY, + scope_info->scope.node = prefix_node; + status = acpi_ns_lookup (scope_info, internal_path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, NULL, &node); @@ -148,7 +153,9 @@ pathname)); cleanup: + acpi_ut_delete_generic_state (scope_info); +cleanup1: ACPI_MEM_FREE (internal_path); return_ACPI_STATUS (status); } diff -Nru a/drivers/acpi/osl.c b/drivers/acpi/osl.c --- a/drivers/acpi/osl.c Sun Mar 14 14:20:08 2004 +++ b/drivers/acpi/osl.c Sun Mar 14 14:20:08 2004 @@ -1012,3 +1012,39 @@ } __setup("acpi_os_name=", acpi_os_name_setup); + +/* + * _OSI control + * empty string disables _OSI + * TBD additional string adds to _OSI + */ +int __init +acpi_osi_setup(char *str) +{ + if (str == NULL || *str == '\0') { + printk(KERN_INFO PREFIX "_OSI method disabled\n"); + acpi_gbl_create_osi_method = FALSE; + } else + { + /* TBD */ + printk(KERN_ERR PREFIX "_OSI additional string ignored -- %s\n", str); + } + + return 1; +} + +__setup("acpi_osi=", acpi_osi_setup); + +/* enable serialization to combat AE_ALREADY_EXISTS errors */ +int __init +acpi_serialize_setup(char *str) +{ + printk(KERN_INFO PREFIX "serialize enabled\n"); + + acpi_gbl_all_methods_serialized = TRUE; + + return 1; +} + +__setup("acpi_serialize", acpi_serialize_setup); + diff -Nru a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c --- a/drivers/acpi/parser/psparse.c Sun Mar 14 14:20:06 2004 +++ b/drivers/acpi/parser/psparse.c Sun Mar 14 14:20:06 2004 @@ -426,7 +426,7 @@ acpi_status status = AE_OK; union acpi_parse_object *op = NULL; /* current op */ union acpi_parse_object *arg = NULL; - union acpi_parse_object pre_op; + union acpi_parse_object *pre_op = NULL; struct acpi_parse_state *parser_state; u8 *aml_op_start = NULL; @@ -547,8 +547,17 @@ /* Create Op structure and append to parent's argument list */ if (walk_state->op_info->flags & AML_NAMED) { - pre_op.common.value.arg = NULL; - pre_op.common.aml_opcode = walk_state->opcode; + /* Allocate a new pre_op if necessary */ + + if (!pre_op) { + pre_op = acpi_ps_alloc_op (walk_state->opcode); + if (!pre_op) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + } + + pre_op->common.value.arg = NULL; + pre_op->common.aml_opcode = walk_state->opcode; /* * Get and append arguments until we find the node that contains @@ -562,7 +571,7 @@ goto close_this_op; } - acpi_ps_append_arg (&pre_op, arg); + acpi_ps_append_arg (pre_op, arg); INCREMENT_ARG_LIST (walk_state->arg_types); } @@ -603,7 +612,7 @@ goto close_this_op; } - acpi_ps_append_arg (op, pre_op.common.value.arg); + acpi_ps_append_arg (op, pre_op->common.value.arg); acpi_gbl_depth++; if (op->common.aml_opcode == AML_REGION_OP) { @@ -854,6 +863,10 @@ acpi_ps_complete_this_op (walk_state, op); op = NULL; + if (pre_op) { + acpi_ps_free_op (pre_op); + pre_op = NULL; + } switch (status) { case AE_OK: @@ -1118,6 +1131,27 @@ else if (status != AE_OK) { ACPI_REPORT_METHOD_ERROR ("Method execution failed", walk_state->method_node, NULL, status); + + /* Check for possible multi-thread reentrancy problem */ + + if ((status == AE_ALREADY_EXISTS) && + (!walk_state->method_desc->method.semaphore)) { + /* + * This method is marked not_serialized, but it tried to create a named + * object, causing the second thread entrance to fail. We will workaround + * this by marking the method permanently as Serialized. + */ + walk_state->method_desc->method.method_flags |= AML_METHOD_SERIALIZED; + walk_state->method_desc->method.concurrency = 1; + } + } + + if (walk_state->method_desc) { + /* Decrement the thread count on the method parse tree */ + + if (walk_state->method_desc->method.thread_count) { + walk_state->method_desc->method.thread_count--; + } } /* We are done with this walk, move on to the parent if any */ diff -Nru a/drivers/acpi/parser/psscope.c b/drivers/acpi/parser/psscope.c --- a/drivers/acpi/parser/psscope.c Sun Mar 14 14:20:06 2004 +++ b/drivers/acpi/parser/psscope.c Sun Mar 14 14:20:06 2004 @@ -167,7 +167,6 @@ return_ACPI_STATUS (AE_NO_MEMORY); } - scope->common.data_type = ACPI_DESC_TYPE_STATE_PSCOPE; scope->parse_scope.op = op; scope->parse_scope.arg_list = remaining_args; @@ -178,13 +177,11 @@ acpi_ut_push_generic_state (&parser_state->scope, scope); - if (arg_count == ACPI_VAR_ARGS) { /* multiple arguments */ scope->parse_scope.arg_end = parser_state->pkg_end; } - else { /* single argument */ @@ -241,7 +238,6 @@ acpi_ut_delete_generic_state (scope); } - else { /* empty parse stack, prepare to fetch next opcode */ @@ -250,7 +246,6 @@ *arg_count = 0; } - ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped Op %p Args %X\n", *op, *arg_count)); return_VOID; } @@ -275,13 +270,13 @@ { union acpi_generic_state *scope; + ACPI_FUNCTION_TRACE_PTR ("ps_cleanup_scope", parser_state); if (!parser_state) { - return; + return_VOID; } - /* Delete anything on the scope stack */ diff -Nru a/drivers/acpi/power.c b/drivers/acpi/power.c --- a/drivers/acpi/power.c Sun Mar 14 14:20:07 2004 +++ b/drivers/acpi/power.c Sun Mar 14 14:20:07 2004 @@ -23,6 +23,18 @@ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ +/* + * ACPI power-managed devices may be controlled in two ways: + * 1. via "Device Specific (D-State) Control" + * 2. via "Power Resource Control". + * This module is used to manage devices relying on Power Resource Control. + * + * An ACPI "power resource object" describes a software controllable power + * plane, clock plane, or other resource used by a power managed device. + * A device may rely on multiple power resources, and a power resource + * may be shared by multiple devices. + */ + #include #include #include diff -Nru a/drivers/acpi/sleep/poweroff.c b/drivers/acpi/sleep/poweroff.c --- a/drivers/acpi/sleep/poweroff.c Sun Mar 14 14:20:08 2004 +++ b/drivers/acpi/sleep/poweroff.c Sun Mar 14 14:20:08 2004 @@ -8,11 +8,14 @@ #include #include #include +#include static void acpi_power_off (void) { printk("%s called\n",__FUNCTION__); + /* Some SMP machines only can poweroff in boot CPU */ + set_cpus_allowed(current, cpumask_of_cpu(0)); acpi_enter_sleep_state_prep(ACPI_STATE_S5); ACPI_DISABLE_IRQS(); acpi_enter_sleep_state(ACPI_STATE_S5); diff -Nru a/drivers/acpi/tables.c b/drivers/acpi/tables.c --- a/drivers/acpi/tables.c Sun Mar 14 14:20:07 2004 +++ b/drivers/acpi/tables.c Sun Mar 14 14:20:07 2004 @@ -386,8 +386,13 @@ for (i = 0; i < sdt_count; i++) { if (sdt_entry[i].id != id) continue; - handler(sdt_entry[i].pa, sdt_entry[i].size); count++; + if (count == 1) + handler(sdt_entry[i].pa, sdt_entry[i].size); + + else + printk(KERN_WARNING PREFIX "%d duplicate %s table ignored.\n", + count, acpi_table_signatures[id]); } return count; diff -Nru a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c --- a/drivers/acpi/utilities/uteval.c Sun Mar 14 14:20:06 2004 +++ b/drivers/acpi/utilities/uteval.c Sun Mar 14 14:20:06 2004 @@ -53,6 +53,62 @@ /******************************************************************************* * + * FUNCTION: acpi_ut_osi_implementation + * + * PARAMETERS: walk_state - Current walk state + * + * RETURN: Status + * + * DESCRIPTION: Implementation of _OSI predefined control method + * Supported = _OSI (String) + * + ******************************************************************************/ + +acpi_status +acpi_ut_osi_implementation ( + struct acpi_walk_state *walk_state) +{ + union acpi_operand_object *string_desc; + union acpi_operand_object *return_desc; + acpi_native_uint i; + + + ACPI_FUNCTION_TRACE ("ut_osi_implementation"); + + + /* Validate the string input argument */ + + string_desc = walk_state->arguments[0].object; + if (!string_desc || (string_desc->common.type != ACPI_TYPE_STRING)) { + return_ACPI_STATUS (AE_TYPE); + } + + /* Create a return object (Default value = 0) */ + + return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER); + if (!return_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Compare input string to table of supported strings */ + + for (i = 0; i < ACPI_NUM_OSI_STRINGS; i++) { + if (!ACPI_STRCMP (string_desc->string.pointer, + (char *) acpi_gbl_valid_osi_strings[i])) { + /* This string is supported */ + + return_desc->integer.value = 0xFFFFFFFF; + break; + } + } + + walk_state->return_desc = return_desc; + return_ACPI_STATUS (AE_CTRL_TERMINATE); +} + + +/******************************************************************************* + * * FUNCTION: acpi_ut_evaluate_object * * PARAMETERS: prefix_node - Starting node diff -Nru a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c --- a/drivers/acpi/utilities/utglobal.c Sun Mar 14 14:20:06 2004 +++ b/drivers/acpi/utilities/utglobal.c Sun Mar 14 14:20:06 2004 @@ -185,6 +185,15 @@ "_S3D", "_S4D"}; +/* Strings supported by the _OSI predefined (internal) method */ + +const char *acpi_gbl_valid_osi_strings[ACPI_NUM_OSI_STRINGS] = { + "Linux", + "Windows 2000", + "Windows 2001", + "Windows 2001.1"}; + + /****************************************************************************** * * Namespace globals @@ -195,14 +204,10 @@ /* * Predefined ACPI Names (Built-in to the Interpreter) * - * Initial values are currently supported only for types String and Number. - * Both are specified as strings in this table. - * * NOTES: - * 1) _SB_ is defined to be a device to allow _SB_/_INI to be run + * 1) _SB_ is defined to be a device to allow \_SB_._INI to be run * during the initialization sequence. */ - const struct acpi_predefined_names acpi_gbl_pre_defined_names[] = { {"_GPE", ACPI_TYPE_LOCAL_SCOPE, NULL}, {"_PR_", ACPI_TYPE_LOCAL_SCOPE, NULL}, @@ -213,7 +218,7 @@ {"_OS_", ACPI_TYPE_STRING, ACPI_OS_NAME}, {"_GL_", ACPI_TYPE_MUTEX, "0"}, -#if defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY) +#if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY) {"_OSI", ACPI_TYPE_METHOD, "1"}, #endif {NULL, ACPI_TYPE_ANY, NULL} /* Table terminator */ @@ -224,7 +229,6 @@ * Properties of the ACPI Object Types, both internal and external. * The table is indexed by values of acpi_object_type */ - const u8 acpi_gbl_ns_properties[] = { ACPI_NS_NORMAL, /* 00 Any */ @@ -303,10 +307,8 @@ * ******************************************************************************/ - struct acpi_table_list acpi_gbl_table_lists[NUM_ACPI_TABLE_TYPES]; - struct acpi_table_support acpi_gbl_table_data[NUM_ACPI_TABLE_TYPES] = { /*********** Name, Signature, Global typed pointer Signature size, Type How many allowed?, Contains valid AML? */ @@ -470,9 +472,8 @@ * * The type ACPI_TYPE_ANY (Untyped) is used as a "don't care" when searching; when * stored in a table it really means that we have thus far seen no evidence to - * indicatewhat type is actually going to be stored for this entry. + * indicate what type is actually going to be stored for this entry. */ - static const char acpi_gbl_bad_type[] = "UNDEFINED"; #define TYPE_NAME_LENGTH 12 /* Maximum length of each string */ @@ -776,6 +777,11 @@ ACPI_FUNCTION_TRACE ("ut_init_globals"); + + /* Runtime configuration */ + + acpi_gbl_create_osi_method = TRUE; + acpi_gbl_all_methods_serialized = FALSE; /* Memory allocation and cache lists */ diff -Nru a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c --- a/drivers/atm/fore200e.c Sun Mar 14 14:20:08 2004 +++ b/drivers/atm/fore200e.c Sun Mar 14 14:20:08 2004 @@ -482,11 +482,19 @@ static void -fore200e_pca_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size, int direction) +fore200e_pca_dma_sync_for_cpu(struct fore200e* fore200e, u32 dma_addr, int size, int direction) { DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); - pci_dma_sync_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction); + pci_dma_sync_single_for_cpu((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction); +} + +static void +fore200e_pca_dma_sync_for_device(struct fore200e* fore200e, u32 dma_addr, int size, int direction) +{ + DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); + + pci_dma_sync_single_for_device((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction); } @@ -761,11 +769,19 @@ static void -fore200e_sba_dma_sync(struct fore200e* fore200e, u32 dma_addr, int size, int direction) +fore200e_sba_dma_sync_for_cpu(struct fore200e* fore200e, u32 dma_addr, int size, int direction) { DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); - sbus_dma_sync_single((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction); + sbus_dma_sync_single_for_cpu((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction); +} + +static void +fore200e_sba_dma_sync_for_device(struct fore200e* fore200e, u32 dma_addr, int size, int direction) +{ + DPRINTK(3, "SBUS DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction); + + sbus_dma_sync_single_for_device((struct sbus_dev*)fore200e->bus_dev, dma_addr, size, direction); } @@ -1149,10 +1165,13 @@ /* rebuild rx buffer address from rsd handle */ buffer = FORE200E_HDL2BUF(rpd->rsd[ i ].handle); - /* ensure DMA synchronisation */ - fore200e->bus->dma_sync(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length, FORE200E_DMA_FROMDEVICE); + /* Make device DMA transfer visible to CPU. */ + fore200e->bus->dma_sync_for_cpu(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length, FORE200E_DMA_FROMDEVICE); memcpy(skb_put(skb, rpd->rsd[ i ].length), buffer->data.align_addr, rpd->rsd[ i ].length); + + /* Now let the device get at it again. */ + fore200e->bus->dma_sync_for_device(fore200e, buffer->data.dma_addr, rpd->rsd[ i ].length, FORE200E_DMA_FROMDEVICE); } DPRINTK(3, "rx skb: len = %d, truesize = %d\n", skb->len, skb->truesize); @@ -1584,8 +1603,9 @@ tasklet_enable(&fore200e->tasklet); - /* ensure DMA synchronisation */ - fore200e->bus->dma_sync(fore200e, tpd->tsd[ 0 ].buffer, tpd->tsd[ 0 ].length, FORE200E_DMA_TODEVICE); + /* The dma_map call above implies a dma_sync so the device can use it, + * thus no explicit dma_sync call is necessary here. + */ DPRINTK(3, "tx on %d.%d.%d:%d, len = %u (%u)\n", vcc->itf, vcc->vpi, vcc->vci, fore200e_atm2fore_aal(vcc->qos.aal), @@ -2918,7 +2938,8 @@ fore200e_pca_write, fore200e_pca_dma_map, fore200e_pca_dma_unmap, - fore200e_pca_dma_sync, + fore200e_pca_dma_sync_for_cpu, + fore200e_pca_dma_sync_for_device, fore200e_pca_dma_chunk_alloc, fore200e_pca_dma_chunk_free, fore200e_pca_detect, @@ -2940,7 +2961,8 @@ fore200e_sba_write, fore200e_sba_dma_map, fore200e_sba_dma_unmap, - fore200e_sba_dma_sync, + fore200e_sba_dma_sync_for_cpu, + fore200e_sba_dma_sync_for_device, fore200e_sba_dma_chunk_alloc, fore200e_sba_dma_chunk_free, fore200e_sba_detect, diff -Nru a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h --- a/drivers/atm/fore200e.h Sun Mar 14 14:20:07 2004 +++ b/drivers/atm/fore200e.h Sun Mar 14 14:20:07 2004 @@ -801,7 +801,8 @@ void (*write)(u32, volatile u32*); u32 (*dma_map)(struct fore200e*, void*, int, int); void (*dma_unmap)(struct fore200e*, u32, int, int); - void (*dma_sync)(struct fore200e*, u32, int, int); + void (*dma_sync_for_cpu)(struct fore200e*, u32, int, int); + void (*dma_sync_for_device)(struct fore200e*, u32, int, int); int (*dma_chunk_alloc)(struct fore200e*, struct chunk*, int, int, int); void (*dma_chunk_free)(struct fore200e*, struct chunk*); struct fore200e* (*detect)(const struct fore200e_bus*, int); diff -Nru a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c --- a/drivers/atm/idt77252.c Sun Mar 14 14:20:07 2004 +++ b/drivers/atm/idt77252.c Sun Mar 14 14:20:07 2004 @@ -1064,8 +1064,8 @@ vcc = vc->rx_vcc; - pci_dma_sync_single(card->pcidev, IDT77252_PRV_PADDR(skb), - skb->end - skb->data, PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(card->pcidev, IDT77252_PRV_PADDR(skb), + skb->end - skb->data, PCI_DMA_FROMDEVICE); if ((vcc->qos.aal == ATM_AAL0) || (vcc->qos.aal == ATM_AAL34)) { @@ -1902,6 +1902,9 @@ { u32 handle = IDT77252_PRV_POOL(skb); int err; + + pci_dma_sync_single_for_device(card->pcidev, IDT77252_PRV_PADDR(skb), + skb->end - skb->data, PCI_DMA_FROMDEVICE); err = push_rx_skb(card, skb, POOL_QUEUE(handle)); if (err) { diff -Nru a/drivers/base/map.c b/drivers/base/map.c --- a/drivers/base/map.c Sun Mar 14 14:20:07 2004 +++ b/drivers/base/map.c Sun Mar 14 14:20:07 2004 @@ -96,7 +96,7 @@ { struct kobject *kobj; struct probe *p; - unsigned best = ~0U; + unsigned long best = ~0UL; retry: down_read(domain->sem); diff -Nru a/drivers/block/Kconfig b/drivers/block/Kconfig --- a/drivers/block/Kconfig Sun Mar 14 14:20:06 2004 +++ b/drivers/block/Kconfig Sun Mar 14 14:20:06 2004 @@ -292,6 +292,15 @@ If unsure, say N. +config BLK_DEV_CARMEL + tristate "Promise SATA SX8 (carmel) support" + depends on PCI + ---help--- + Saying Y or M here will enable support for the + Promise SATA SX8 ("carmel") controllers. + + Use devices /dev/carmel/$N and /dev/carmel/$Np$M. + config BLK_DEV_RAM tristate "RAM disk support" ---help--- diff -Nru a/drivers/block/Makefile b/drivers/block/Makefile --- a/drivers/block/Makefile Sun Mar 14 14:20:08 2004 +++ b/drivers/block/Makefile Sun Mar 14 14:20:08 2004 @@ -40,3 +40,5 @@ obj-$(CONFIG_BLK_DEV_CRYPTOLOOP) += cryptoloop.o obj-$(CONFIG_VIODASD) += viodasd.o +obj-$(CONFIG_BLK_DEV_CARMEL) += carmel.o + diff -Nru a/drivers/block/carmel.c b/drivers/block/carmel.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/block/carmel.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,1731 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Jeff Garzik"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Promise SX8 (carmel) block driver"); + +#if 0 +#define CARM_DEBUG +#define CARM_VERBOSE_DEBUG +#else +#undef CARM_DEBUG +#undef CARM_VERBOSE_DEBUG +#endif +#undef CARM_NDEBUG + +#define DRV_NAME "carmel" +#define DRV_VERSION "0.7" +#define PFX DRV_NAME ": " + +#define NEXT_RESP(idx) ((idx + 1) % RMSG_Q_LEN) + +/* 0xf is just arbitrary, non-zero noise; this is sorta like poisoning */ +#define TAG_ENCODE(tag) (((tag) << 16) | 0xf) +#define TAG_DECODE(tag) (((tag) >> 16) & 0x1f) +#define TAG_VALID(tag) ((((tag) & 0xf) == 0xf) && (TAG_DECODE(tag) < 32)) + +/* note: prints function name for you */ +#ifdef CARM_DEBUG +#define DPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args) +#ifdef CARM_VERBOSE_DEBUG +#define VPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args) +#else +#define VPRINTK(fmt, args...) +#endif /* CARM_VERBOSE_DEBUG */ +#else +#define DPRINTK(fmt, args...) +#define VPRINTK(fmt, args...) +#endif /* CARM_DEBUG */ + +#ifdef CARM_NDEBUG +#define assert(expr) +#else +#define assert(expr) \ + if(unlikely(!(expr))) { \ + printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \ + #expr,__FILE__,__FUNCTION__,__LINE__); \ + } +#endif + +/* defines only for the constants which don't work well as enums */ +struct carm_host; + +enum { + /* adapter-wide limits */ + CARM_MAX_PORTS = 8, + CARM_SHM_SIZE = (4096 << 7), + CARM_MINORS_PER_MAJOR = 256 / CARM_MAX_PORTS, + CARM_MAX_WAIT_Q = CARM_MAX_PORTS + 1, + + /* command message queue limits */ + CARM_MAX_REQ = 64, /* max command msgs per host */ + CARM_MAX_Q = 1, /* one command at a time */ + CARM_MSG_LOW_WATER = (CARM_MAX_REQ / 4), /* refill mark */ + + /* S/G limits, host-wide and per-request */ + CARM_MAX_REQ_SG = 32, /* max s/g entries per request */ + CARM_SG_BOUNDARY = 0xffffUL, /* s/g segment boundary */ + CARM_MAX_HOST_SG = 600, /* max s/g entries per host */ + CARM_SG_LOW_WATER = (CARM_MAX_HOST_SG / 4), /* re-fill mark */ + + /* hardware registers */ + CARM_IHQP = 0x1c, + CARM_INT_STAT = 0x10, /* interrupt status */ + CARM_INT_MASK = 0x14, /* interrupt mask */ + CARM_HMUC = 0x18, /* host message unit control */ + RBUF_ADDR_LO = 0x20, /* response msg DMA buf low 32 bits */ + RBUF_ADDR_HI = 0x24, /* response msg DMA buf high 32 bits */ + RBUF_BYTE_SZ = 0x28, + CARM_RESP_IDX = 0x2c, + CARM_CMS0 = 0x30, /* command message size reg 0 */ + CARM_LMUC = 0x48, + CARM_HMPHA = 0x6c, + CARM_INITC = 0xb5, + + /* bits in CARM_INT_{STAT,MASK} */ + INT_RESERVED = 0xfffffff0, + INT_WATCHDOG = (1 << 3), /* watchdog timer */ + INT_Q_OVERFLOW = (1 << 2), /* cmd msg q overflow */ + INT_Q_AVAILABLE = (1 << 1), /* cmd msg q has free space */ + INT_RESPONSE = (1 << 0), /* response msg available */ + INT_ACK_MASK = INT_WATCHDOG | INT_Q_OVERFLOW, + INT_DEF_MASK = INT_RESERVED | INT_Q_OVERFLOW | + INT_RESPONSE, + + /* command messages, and related register bits */ + CARM_HAVE_RESP = 0x01, + CARM_MSG_READ = 1, + CARM_MSG_WRITE = 2, + CARM_MSG_VERIFY = 3, + CARM_MSG_GET_CAPACITY = 4, + CARM_MSG_FLUSH = 5, + CARM_MSG_IOCTL = 6, + CARM_MSG_ARRAY = 8, + CARM_MSG_MISC = 9, + CARM_CME = (1 << 2), + CARM_RME = (1 << 1), + CARM_WZBC = (1 << 0), + CARM_RMI = (1 << 0), + CARM_Q_FULL = (1 << 3), + CARM_MSG_SIZE = 288, + CARM_Q_LEN = 48, + + /* CARM_MSG_IOCTL messages */ + CARM_IOC_SCAN_CHAN = 5, /* scan channels for devices */ + CARM_IOC_GET_TCQ = 13, /* get tcq/ncq depth */ + CARM_IOC_SET_TCQ = 14, /* set tcq/ncq depth */ + + IOC_SCAN_CHAN_NODEV = 0x1f, + IOC_SCAN_CHAN_OFFSET = 0x40, + + /* CARM_MSG_ARRAY messages */ + CARM_ARRAY_INFO = 0, + + ARRAY_NO_EXIST = (1 << 31), + + /* response messages */ + RMSG_SZ = 8, /* sizeof(struct carm_response) */ + RMSG_Q_LEN = 48, /* resp. msg list length */ + RMSG_OK = 1, /* bit indicating msg was successful */ + /* length of entire resp. msg buffer */ + RBUF_LEN = RMSG_SZ * RMSG_Q_LEN, + + PDC_SHM_SIZE = (4096 << 7), /* length of entire h/w buffer */ + + /* CARM_MSG_MISC messages */ + MISC_GET_FW_VER = 2, + MISC_ALLOC_MEM = 3, + MISC_SET_TIME = 5, + + /* MISC_GET_FW_VER feature bits */ + FW_VER_4PORT = (1 << 2), /* 1=4 ports, 0=8 ports */ + FW_VER_NON_RAID = (1 << 1), /* 1=non-RAID firmware, 0=RAID */ + FW_VER_ZCR = (1 << 0), /* zero channel RAID (whatever that is) */ + + /* carm_host flags */ + FL_DAC = (1 << 0), + FL_NON_RAID = FW_VER_NON_RAID, + FL_4PORT = FW_VER_4PORT, + FL_FW_VER_MASK = (FW_VER_NON_RAID | FW_VER_4PORT), +}; + +enum scatter_gather_types { + SGT_32BIT = 0, + SGT_64BIT = 1, +}; + +enum host_states { + HST_INVALID, /* invalid state; never used */ + HST_ALLOC_BUF, /* setting up master SHM area */ + HST_ERROR, /* we never leave here */ + HST_PORT_SCAN, /* start dev scan */ + HST_DEV_SCAN_START, /* start per-device probe */ + HST_DEV_SCAN, /* continue per-device probe */ + HST_DEV_ACTIVATE, /* activate devices we found */ + HST_PROBE_FINISHED, /* probe is complete */ + HST_PROBE_START, /* initiate probe */ + HST_SYNC_TIME, /* tell firmware what time it is */ + HST_GET_FW_VER, /* get firmware version, adapter port cnt */ +}; + +#ifdef CARM_DEBUG +static const char *state_name[] = { + "HST_INVALID", + "HST_ALLOC_BUF", + "HST_ERROR", + "HST_PORT_SCAN", + "HST_DEV_SCAN_START", + "HST_DEV_SCAN", + "HST_DEV_ACTIVATE", + "HST_PROBE_FINISHED", + "HST_PROBE_START", + "HST_SYNC_TIME", + "HST_GET_FW_VER", +}; +#endif + +struct carm_port { + unsigned int port_no; + unsigned int n_queued; + struct gendisk *disk; + struct carm_host *host; + + /* attached device characteristics */ + u64 capacity; + char name[41]; + u16 dev_geom_head; + u16 dev_geom_sect; + u16 dev_geom_cyl; +}; + +struct carm_request { + unsigned int tag; + int n_elem; + unsigned int msg_type; + unsigned int msg_subtype; + unsigned int msg_bucket; + struct request *rq; + struct carm_port *port; + struct scatterlist sg[CARM_MAX_REQ_SG]; +}; + +struct carm_host { + unsigned long flags; + void *mmio; + void *shm; + dma_addr_t shm_dma; + int major; + spinlock_t lock; + struct pci_dev *pdev; + unsigned int state; + u32 fw_ver; + + request_queue_t *oob_q; + unsigned int n_oob; + + unsigned int hw_sg_used; + + unsigned int resp_idx; + + unsigned int wait_q_prod; + unsigned int wait_q_cons; + request_queue_t *wait_q[CARM_MAX_WAIT_Q]; + + unsigned int n_msgs; + u64 msg_alloc; + struct carm_request req[CARM_MAX_REQ]; + void *msg_base; + dma_addr_t msg_dma; + + int cur_scan_dev; + unsigned long dev_active; + unsigned long dev_present; + struct carm_port port[CARM_MAX_PORTS]; + + struct work_struct fsm_task; + + struct semaphore probe_sem; +}; + +struct carm_response { + u32 ret_handle; + u32 status; +} __attribute__((packed)); + +struct carm_msg_sg { + u32 start; + u32 len; +} __attribute__((packed)); + +struct carm_msg_rw { + u8 type; + u8 id; + u8 sg_count; + u8 sg_type; + u32 handle; + u32 lba; + u16 lba_count; + u16 lba_high; + struct carm_msg_sg sg[32]; +} __attribute__((packed)); + +struct carm_msg_allocbuf { + u8 type; + u8 subtype; + u8 n_sg; + u8 sg_type; + u32 handle; + u32 addr; + u32 len; + u32 evt_pool; + u32 n_evt; + u32 rbuf_pool; + u32 n_rbuf; + u32 msg_pool; + u32 n_msg; + struct carm_msg_sg sg[8]; +} __attribute__((packed)); + +struct carm_msg_ioctl { + u8 type; + u8 subtype; + u8 array_id; + u8 reserved1; + u32 handle; + u32 data_addr; + u32 reserved2; +} __attribute__((packed)); + +struct carm_msg_sync_time { + u8 type; + u8 subtype; + u16 reserved1; + u32 handle; + u32 reserved2; + u32 timestamp; +} __attribute__((packed)); + +struct carm_msg_get_fw_ver { + u8 type; + u8 subtype; + u16 reserved1; + u32 handle; + u32 data_addr; + u32 reserved2; +} __attribute__((packed)); + +struct carm_fw_ver { + u32 version; + u8 features; + u8 reserved1; + u16 reserved2; +} __attribute__((packed)); + +struct carm_array_info { + u32 size; + + u16 size_hi; + u16 stripe_size; + + u32 mode; + + u16 stripe_blk_sz; + u16 reserved1; + + u16 cyl; + u16 head; + + u16 sect; + u8 array_id; + u8 reserved2; + + char name[40]; + + u32 array_status; + + /* device list continues beyond this point? */ +} __attribute__((packed)); + +static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); +static void carm_remove_one (struct pci_dev *pdev); +static int carm_bdev_ioctl(struct inode *ino, struct file *fil, + unsigned int cmd, unsigned long arg); + +static struct pci_device_id carm_pci_tbl[] = { + { PCI_VENDOR_ID_PROMISE, 0x8000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + { PCI_VENDOR_ID_PROMISE, 0x8002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, + { } /* terminate list */ +}; +MODULE_DEVICE_TABLE(pci, carm_pci_tbl); + +static struct pci_driver carm_driver = { + .name = DRV_NAME, + .id_table = carm_pci_tbl, + .probe = carm_init_one, + .remove = carm_remove_one, +}; + +static struct block_device_operations carm_bd_ops = { + .owner = THIS_MODULE, + .ioctl = carm_bdev_ioctl, +}; + +static unsigned int carm_host_id; + + + +static int carm_bdev_ioctl(struct inode *ino, struct file *fil, + unsigned int cmd, unsigned long arg) +{ + void __user *usermem = (void *) arg; + struct carm_port *port = ino->i_bdev->bd_disk->private_data; + struct hd_geometry geom; + + switch (cmd) { + case HDIO_GETGEO: + if (!usermem) + return -EINVAL; + + geom.heads = (u8) port->dev_geom_head; + geom.sectors = (u8) port->dev_geom_sect; + geom.cylinders = port->dev_geom_cyl; + geom.start = get_start_sect(ino->i_bdev); + + if (copy_to_user(usermem, &geom, sizeof(geom))) + return -EFAULT; + return 0; + + default: + break; + } + + return -EOPNOTSUPP; +} + +static inline unsigned long msecs_to_jiffies(unsigned long msecs) +{ + return ((HZ * msecs + 999) / 1000); +} + +static void msleep(unsigned long msecs) +{ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(msecs_to_jiffies(msecs)); +} + +static const u32 msg_sizes[] = { 32, 64, 128, CARM_MSG_SIZE }; + +static inline int carm_lookup_bucket(u32 msg_size) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(msg_sizes); i++) + if (msg_size <= msg_sizes[i]) + return i; + + return -ENOENT; +} + +static void carm_init_buckets(void *mmio) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(msg_sizes); i++) + writel(msg_sizes[i], mmio + CARM_CMS0 + (4 * i)); +} + +static inline void *carm_ref_msg(struct carm_host *host, + unsigned int msg_idx) +{ + return host->msg_base + (msg_idx * CARM_MSG_SIZE); +} + +static inline dma_addr_t carm_ref_msg_dma(struct carm_host *host, + unsigned int msg_idx) +{ + return host->msg_dma + (msg_idx * CARM_MSG_SIZE); +} + +static int carm_send_msg(struct carm_host *host, + struct carm_request *crq) +{ + void *mmio = host->mmio; + u32 msg = (u32) carm_ref_msg_dma(host, crq->tag); + u32 cm_bucket = crq->msg_bucket; + u32 tmp; + int rc = 0; + + VPRINTK("ENTER\n"); + + tmp = readl(mmio + CARM_HMUC); + if (tmp & CARM_Q_FULL) { +#if 0 + tmp = readl(mmio + CARM_INT_MASK); + tmp |= INT_Q_AVAILABLE; + writel(tmp, mmio + CARM_INT_MASK); + readl(mmio + CARM_INT_MASK); /* flush */ +#endif + DPRINTK("host msg queue full\n"); + rc = -EBUSY; + } else { + writel(msg | (cm_bucket << 1), mmio + CARM_IHQP); + readl(mmio + CARM_IHQP); /* flush */ + } + + return rc; +} + +static struct carm_request *carm_get_request(struct carm_host *host) +{ + unsigned int i; + + /* obey global hardware limit on S/G entries */ + if (host->hw_sg_used >= (CARM_MAX_HOST_SG - CARM_MAX_REQ_SG)) + return NULL; + + for (i = 0; i < CARM_MAX_Q; i++) + if ((host->msg_alloc & (1ULL << i)) == 0) { + struct carm_request *crq = &host->req[i]; + crq->port = NULL; + crq->n_elem = 0; + + host->msg_alloc |= (1ULL << i); + host->n_msgs++; + + assert(host->n_msgs <= CARM_MAX_REQ); + return crq; + } + + DPRINTK("no request available, returning NULL\n"); + return NULL; +} + +static int carm_put_request(struct carm_host *host, struct carm_request *crq) +{ + assert(crq->tag < CARM_MAX_Q); + + if (unlikely((host->msg_alloc & (1ULL << crq->tag)) == 0)) + return -EINVAL; /* tried to clear a tag that was not active */ + + assert(host->hw_sg_used >= crq->n_elem); + + host->msg_alloc &= ~(1ULL << crq->tag); + host->hw_sg_used -= crq->n_elem; + host->n_msgs--; + + return 0; +} + +static struct carm_request *carm_get_special(struct carm_host *host) +{ + unsigned long flags; + struct carm_request *crq = NULL; + struct request *rq; + int tries = 5000; + + while (tries-- > 0) { + spin_lock_irqsave(&host->lock, flags); + crq = carm_get_request(host); + spin_unlock_irqrestore(&host->lock, flags); + + if (crq) + break; + msleep(10); + } + + if (!crq) + return NULL; + + rq = blk_get_request(host->oob_q, WRITE /* bogus */, GFP_KERNEL); + if (!rq) { + spin_lock_irqsave(&host->lock, flags); + carm_put_request(host, crq); + spin_unlock_irqrestore(&host->lock, flags); + return NULL; + } + + crq->rq = rq; + return crq; +} + +static int carm_array_info (struct carm_host *host, unsigned int array_idx) +{ + struct carm_msg_ioctl *ioc; + unsigned int idx; + u32 msg_data; + dma_addr_t msg_dma; + struct carm_request *crq; + int rc; + + crq = carm_get_special(host); + if (!crq) { + rc = -ENOMEM; + goto err_out; + } + + idx = crq->tag; + + ioc = carm_ref_msg(host, idx); + msg_dma = carm_ref_msg_dma(host, idx); + msg_data = (u32) (msg_dma + sizeof(struct carm_array_info)); + + crq->msg_type = CARM_MSG_ARRAY; + crq->msg_subtype = CARM_ARRAY_INFO; + rc = carm_lookup_bucket(sizeof(struct carm_msg_ioctl) + + sizeof(struct carm_array_info)); + BUG_ON(rc < 0); + crq->msg_bucket = (u32) rc; + + memset(ioc, 0, sizeof(*ioc)); + ioc->type = CARM_MSG_ARRAY; + ioc->subtype = CARM_ARRAY_INFO; + ioc->array_id = (u8) array_idx; + ioc->handle = cpu_to_le32(TAG_ENCODE(idx)); + ioc->data_addr = cpu_to_le32(msg_data); + + spin_lock_irq(&host->lock); + assert(host->state == HST_DEV_SCAN_START || + host->state == HST_DEV_SCAN); + spin_unlock_irq(&host->lock); + + DPRINTK("blk_insert_request, tag == %u\n", idx); + blk_insert_request(host->oob_q, crq->rq, 1, crq, 0); + + return 0; + +err_out: + spin_lock_irq(&host->lock); + host->state = HST_ERROR; + spin_unlock_irq(&host->lock); + return rc; +} + +typedef unsigned int (*carm_sspc_t)(struct carm_host *, unsigned int, void *); + +static int carm_send_special (struct carm_host *host, carm_sspc_t func) +{ + struct carm_request *crq; + struct carm_msg_ioctl *ioc; + void *mem; + unsigned int idx, msg_size; + int rc; + + crq = carm_get_special(host); + if (!crq) + return -ENOMEM; + + idx = crq->tag; + + mem = carm_ref_msg(host, idx); + + msg_size = func(host, idx, mem); + + ioc = mem; + crq->msg_type = ioc->type; + crq->msg_subtype = ioc->subtype; + rc = carm_lookup_bucket(msg_size); + BUG_ON(rc < 0); + crq->msg_bucket = (u32) rc; + + DPRINTK("blk_insert_request, tag == %u\n", idx); + blk_insert_request(host->oob_q, crq->rq, 1, crq, 0); + + return 0; +} + +static unsigned int carm_fill_sync_time(struct carm_host *host, + unsigned int idx, void *mem) +{ + struct timeval tv; + struct carm_msg_sync_time *st = mem; + + do_gettimeofday(&tv); + + memset(st, 0, sizeof(*st)); + st->type = CARM_MSG_MISC; + st->subtype = MISC_SET_TIME; + st->handle = cpu_to_le32(TAG_ENCODE(idx)); + st->timestamp = cpu_to_le32(tv.tv_sec); + + return sizeof(struct carm_msg_sync_time); +} + +static unsigned int carm_fill_alloc_buf(struct carm_host *host, + unsigned int idx, void *mem) +{ + struct carm_msg_allocbuf *ab = mem; + + memset(ab, 0, sizeof(*ab)); + ab->type = CARM_MSG_MISC; + ab->subtype = MISC_ALLOC_MEM; + ab->handle = cpu_to_le32(TAG_ENCODE(idx)); + ab->n_sg = 1; + ab->sg_type = SGT_32BIT; + ab->addr = cpu_to_le32(host->shm_dma + (PDC_SHM_SIZE >> 1)); + ab->len = cpu_to_le32(PDC_SHM_SIZE >> 1); + ab->evt_pool = cpu_to_le32(host->shm_dma + (16 * 1024)); + ab->n_evt = cpu_to_le32(1024); + ab->rbuf_pool = cpu_to_le32(host->shm_dma); + ab->n_rbuf = cpu_to_le32(RMSG_Q_LEN); + ab->msg_pool = cpu_to_le32(host->shm_dma + RBUF_LEN); + ab->n_msg = cpu_to_le32(CARM_Q_LEN); + ab->sg[0].start = cpu_to_le32(host->shm_dma + (PDC_SHM_SIZE >> 1)); + ab->sg[0].len = cpu_to_le32(65536); + + return sizeof(struct carm_msg_allocbuf); +} + +static unsigned int carm_fill_scan_channels(struct carm_host *host, + unsigned int idx, void *mem) +{ + struct carm_msg_ioctl *ioc = mem; + u32 msg_data = (u32) (carm_ref_msg_dma(host, idx) + + IOC_SCAN_CHAN_OFFSET); + + memset(ioc, 0, sizeof(*ioc)); + ioc->type = CARM_MSG_IOCTL; + ioc->subtype = CARM_IOC_SCAN_CHAN; + ioc->handle = cpu_to_le32(TAG_ENCODE(idx)); + ioc->data_addr = cpu_to_le32(msg_data); + + /* fill output data area with "no device" default values */ + mem += IOC_SCAN_CHAN_OFFSET; + memset(mem, IOC_SCAN_CHAN_NODEV, CARM_MAX_PORTS); + + return IOC_SCAN_CHAN_OFFSET + CARM_MAX_PORTS; +} + +static unsigned int carm_fill_get_fw_ver(struct carm_host *host, + unsigned int idx, void *mem) +{ + struct carm_msg_get_fw_ver *ioc = mem; + u32 msg_data = (u32) (carm_ref_msg_dma(host, idx) + sizeof(*ioc)); + + memset(ioc, 0, sizeof(*ioc)); + ioc->type = CARM_MSG_MISC; + ioc->subtype = MISC_GET_FW_VER; + ioc->handle = cpu_to_le32(TAG_ENCODE(idx)); + ioc->data_addr = cpu_to_le32(msg_data); + + return sizeof(struct carm_msg_get_fw_ver) + + sizeof(struct carm_fw_ver); +} + +static inline void carm_end_request_queued(struct carm_host *host, + struct carm_request *crq, + int uptodate) +{ + struct request *req = crq->rq; + int rc; + + rc = end_that_request_first(req, uptodate, req->hard_nr_sectors); + assert(rc == 0); + + end_that_request_last(req); + + rc = carm_put_request(host, crq); + assert(rc == 0); +} + +static inline void carm_push_q (struct carm_host *host, request_queue_t *q) +{ + unsigned int idx = host->wait_q_prod % CARM_MAX_WAIT_Q; + + blk_stop_queue(q); + VPRINTK("STOPPED QUEUE %p\n", q); + + host->wait_q[idx] = q; + host->wait_q_prod++; + BUG_ON(host->wait_q_prod == host->wait_q_cons); /* overrun */ +} + +static inline request_queue_t *carm_pop_q(struct carm_host *host) +{ + unsigned int idx; + + if (host->wait_q_prod == host->wait_q_cons) + return NULL; + + idx = host->wait_q_cons % CARM_MAX_WAIT_Q; + host->wait_q_cons++; + + return host->wait_q[idx]; +} + +static inline void carm_round_robin(struct carm_host *host) +{ + request_queue_t *q = carm_pop_q(host); + if (q) { + blk_start_queue(q); + VPRINTK("STARTED QUEUE %p\n", q); + } +} + +static inline void carm_end_rq(struct carm_host *host, struct carm_request *crq, + int is_ok) +{ + carm_end_request_queued(host, crq, is_ok); + if (CARM_MAX_Q == 1) + carm_round_robin(host); + else if ((host->n_msgs <= CARM_MSG_LOW_WATER) && + (host->hw_sg_used <= CARM_SG_LOW_WATER)) { + carm_round_robin(host); + } +} + +static void carm_oob_rq_fn(request_queue_t *q) +{ + struct carm_host *host = q->queuedata; + struct carm_request *crq; + struct request *rq; + int rc; + + while (1) { + DPRINTK("get req\n"); + rq = elv_next_request(q); + if (!rq) + break; + + blkdev_dequeue_request(rq); + + crq = rq->special; + assert(crq != NULL); + assert(crq->rq == rq); + + crq->n_elem = 0; + + DPRINTK("send req\n"); + rc = carm_send_msg(host, crq); + if (rc) { + blk_requeue_request(q, rq); + carm_push_q(host, q); + return; /* call us again later, eventually */ + } + } +} + +static void carm_rq_fn(request_queue_t *q) +{ + struct carm_port *port = q->queuedata; + struct carm_host *host = port->host; + struct carm_msg_rw *msg; + struct carm_request *crq; + struct request *rq; + struct scatterlist *sg; + int writing = 0, pci_dir, i, n_elem, rc; + u32 tmp; + unsigned int msg_size; + +queue_one_request: + VPRINTK("get req\n"); + rq = elv_next_request(q); + if (!rq) + return; + + crq = carm_get_request(host); + if (!crq) { + carm_push_q(host, q); + return; /* call us again later, eventually */ + } + crq->rq = rq; + + blkdev_dequeue_request(rq); + + if (rq_data_dir(rq) == WRITE) { + writing = 1; + pci_dir = PCI_DMA_TODEVICE; + } else { + pci_dir = PCI_DMA_FROMDEVICE; + } + + /* get scatterlist from block layer */ + sg = &crq->sg[0]; + n_elem = blk_rq_map_sg(q, rq, sg); + if (n_elem <= 0) { + carm_end_rq(host, crq, 0); + return; /* request with no s/g entries? */ + } + + /* map scatterlist to PCI bus addresses */ + n_elem = pci_map_sg(host->pdev, sg, n_elem, pci_dir); + if (n_elem <= 0) { + carm_end_rq(host, crq, 0); + return; /* request with no s/g entries? */ + } + crq->n_elem = n_elem; + crq->port = port; + host->hw_sg_used += n_elem; + + /* + * build read/write message + */ + + VPRINTK("build msg\n"); + msg = (struct carm_msg_rw *) carm_ref_msg(host, crq->tag); + + if (writing) { + msg->type = CARM_MSG_WRITE; + crq->msg_type = CARM_MSG_WRITE; + } else { + msg->type = CARM_MSG_READ; + crq->msg_type = CARM_MSG_READ; + } + + msg->id = port->port_no; + msg->sg_count = n_elem; + msg->sg_type = SGT_32BIT; + msg->handle = cpu_to_le32(TAG_ENCODE(crq->tag)); + msg->lba = cpu_to_le32(rq->sector & 0xffffffff); + tmp = (rq->sector >> 16) >> 16; + msg->lba_high = cpu_to_le16( (u16) tmp ); + msg->lba_count = cpu_to_le16(rq->nr_sectors); + + msg_size = sizeof(struct carm_msg_rw) - sizeof(msg->sg); + for (i = 0; i < n_elem; i++) { + struct carm_msg_sg *carm_sg = &msg->sg[i]; + carm_sg->start = cpu_to_le32(sg_dma_address(&crq->sg[i])); + carm_sg->len = cpu_to_le32(sg_dma_len(&crq->sg[i])); + msg_size += sizeof(struct carm_msg_sg); + } + + rc = carm_lookup_bucket(msg_size); + BUG_ON(rc < 0); + crq->msg_bucket = (u32) rc; + + /* + * queue read/write message to hardware + */ + + VPRINTK("send msg, tag == %u\n", crq->tag); + rc = carm_send_msg(host, crq); + if (rc) { + carm_put_request(host, crq); + blk_requeue_request(q, rq); + carm_push_q(host, q); + return; /* call us again later, eventually */ + } + + goto queue_one_request; +} + +static void carm_handle_array_info(struct carm_host *host, + struct carm_request *crq, u8 *mem, + int is_ok) +{ + struct carm_port *port; + u8 *msg_data = mem + sizeof(struct carm_array_info); + struct carm_array_info *desc = (struct carm_array_info *) msg_data; + u64 lo, hi; + int cur_port; + size_t slen; + + DPRINTK("ENTER\n"); + + carm_end_rq(host, crq, is_ok); + + if (!is_ok) + goto out; + if (le32_to_cpu(desc->array_status) & ARRAY_NO_EXIST) + goto out; + + cur_port = host->cur_scan_dev; + + /* should never occur */ + if ((cur_port < 0) || (cur_port >= CARM_MAX_PORTS)) { + printk(KERN_ERR PFX "BUG: cur_scan_dev==%d, array_id==%d\n", + cur_port, (int) desc->array_id); + goto out; + } + + port = &host->port[cur_port]; + + lo = (u64) le32_to_cpu(desc->size); + hi = (u64) le32_to_cpu(desc->size_hi); + + port->capacity = lo | (hi << 32); + port->dev_geom_head = le16_to_cpu(desc->head); + port->dev_geom_sect = le16_to_cpu(desc->sect); + port->dev_geom_cyl = le16_to_cpu(desc->cyl); + + host->dev_active |= (1 << cur_port); + + strncpy(port->name, desc->name, sizeof(port->name)); + port->name[sizeof(port->name) - 1] = 0; + slen = strlen(port->name); + while (slen && (port->name[slen - 1] == ' ')) { + port->name[slen - 1] = 0; + slen--; + } + + printk(KERN_INFO DRV_NAME "(%s): port %u device %Lu sectors\n", + pci_name(host->pdev), port->port_no, port->capacity); + printk(KERN_INFO DRV_NAME "(%s): port %u device \"%s\"\n", + pci_name(host->pdev), port->port_no, port->name); + +out: + assert(host->state == HST_DEV_SCAN); + schedule_work(&host->fsm_task); +} + +static void carm_handle_scan_chan(struct carm_host *host, + struct carm_request *crq, u8 *mem, + int is_ok) +{ + u8 *msg_data = mem + IOC_SCAN_CHAN_OFFSET; + unsigned int i, dev_count = 0; + int new_state = HST_DEV_SCAN_START; + + DPRINTK("ENTER\n"); + + carm_end_rq(host, crq, is_ok); + + if (!is_ok) { + new_state = HST_ERROR; + goto out; + } + + /* TODO: scan and support non-disk devices */ + for (i = 0; i < 8; i++) + if (msg_data[i] == 0) { /* direct-access device (disk) */ + host->dev_present |= (1 << i); + dev_count++; + } + + printk(KERN_INFO DRV_NAME "(%s): found %u interesting devices\n", + pci_name(host->pdev), dev_count); + +out: + assert(host->state == HST_PORT_SCAN); + host->state = new_state; + schedule_work(&host->fsm_task); +} + +static void carm_handle_generic(struct carm_host *host, + struct carm_request *crq, int is_ok, + int cur_state, int next_state) +{ + DPRINTK("ENTER\n"); + + carm_end_rq(host, crq, is_ok); + + assert(host->state == cur_state); + if (is_ok) + host->state = next_state; + else + host->state = HST_ERROR; + schedule_work(&host->fsm_task); +} + +static inline void carm_handle_rw(struct carm_host *host, + struct carm_request *crq, int is_ok) +{ + int pci_dir; + + VPRINTK("ENTER\n"); + + if (rq_data_dir(crq->rq) == WRITE) + pci_dir = PCI_DMA_TODEVICE; + else + pci_dir = PCI_DMA_FROMDEVICE; + + pci_unmap_sg(host->pdev, &crq->sg[0], crq->n_elem, pci_dir); + + carm_end_rq(host, crq, is_ok); +} + +static inline void carm_handle_resp(struct carm_host *host, + u32 ret_handle_le, u32 status) +{ + u32 handle = le32_to_cpu(ret_handle_le); + unsigned int msg_idx; + struct carm_request *crq; + int is_ok = (status == RMSG_OK); + u8 *mem; + + VPRINTK("ENTER, handle == 0x%x\n", handle); + + if (unlikely(!TAG_VALID(handle))) { + printk(KERN_ERR DRV_NAME "(%s): BUG: invalid tag 0x%x\n", + pci_name(host->pdev), handle); + return; + } + + msg_idx = TAG_DECODE(handle); + VPRINTK("tag == %u\n", msg_idx); + + crq = &host->req[msg_idx]; + + /* fast path */ + if (likely(crq->msg_type == CARM_MSG_READ || + crq->msg_type == CARM_MSG_WRITE)) { + carm_handle_rw(host, crq, is_ok); + return; + } + + mem = carm_ref_msg(host, msg_idx); + + switch (crq->msg_type) { + case CARM_MSG_IOCTL: { + switch (crq->msg_subtype) { + case CARM_IOC_SCAN_CHAN: + carm_handle_scan_chan(host, crq, mem, is_ok); + break; + default: + /* unknown / invalid response */ + goto err_out; + } + break; + } + + case CARM_MSG_MISC: { + switch (crq->msg_subtype) { + case MISC_ALLOC_MEM: + carm_handle_generic(host, crq, is_ok, + HST_ALLOC_BUF, HST_SYNC_TIME); + break; + case MISC_SET_TIME: + carm_handle_generic(host, crq, is_ok, + HST_SYNC_TIME, HST_GET_FW_VER); + break; + case MISC_GET_FW_VER: { + struct carm_fw_ver *ver = (struct carm_fw_ver *) + mem + sizeof(struct carm_msg_get_fw_ver); + if (is_ok) { + host->fw_ver = le32_to_cpu(ver->version); + host->flags |= (ver->features & FL_FW_VER_MASK); + } + carm_handle_generic(host, crq, is_ok, + HST_GET_FW_VER, HST_PORT_SCAN); + break; + } + default: + /* unknown / invalid response */ + goto err_out; + } + break; + } + + case CARM_MSG_ARRAY: { + switch (crq->msg_subtype) { + case CARM_ARRAY_INFO: + carm_handle_array_info(host, crq, mem, is_ok); + break; + default: + /* unknown / invalid response */ + goto err_out; + } + break; + } + + default: + /* unknown / invalid response */ + goto err_out; + } + + return; + +err_out: + printk(KERN_WARNING DRV_NAME "(%s): BUG: unhandled message type %d/%d\n", + pci_name(host->pdev), crq->msg_type, crq->msg_subtype); + carm_end_rq(host, crq, 0); +} + +static inline void carm_handle_responses(struct carm_host *host) +{ + void *mmio = host->mmio; + struct carm_response *resp = (struct carm_response *) host->shm; + unsigned int work = 0; + unsigned int idx = host->resp_idx % RMSG_Q_LEN; + + while (1) { + u32 status = le32_to_cpu(resp[idx].status); + + if (status == 0xffffffff) { + VPRINTK("ending response on index %u\n", idx); + writel(idx << 3, mmio + CARM_RESP_IDX); + break; + } + + /* response to a message we sent */ + else if ((status & (1 << 31)) == 0) { + VPRINTK("handling msg response on index %u\n", idx); + carm_handle_resp(host, resp[idx].ret_handle, status); + resp[idx].status = 0xffffffff; + } + + /* asynchronous events the hardware throws our way */ + else if ((status & 0xff000000) == (1 << 31)) { + u8 *evt_type_ptr = (u8 *) &resp[idx]; + u8 evt_type = *evt_type_ptr; + printk(KERN_WARNING DRV_NAME "(%s): unhandled event type %d\n", + pci_name(host->pdev), (int) evt_type); + resp[idx].status = 0xffffffff; + } + + idx = NEXT_RESP(idx); + work++; + } + + VPRINTK("EXIT, work==%u\n", work); + host->resp_idx += work; +} + +static irqreturn_t carm_interrupt(int irq, void *__host, struct pt_regs *regs) +{ + struct carm_host *host = __host; + void *mmio; + u32 mask; + int handled = 0; + unsigned long flags; + + if (!host) { + VPRINTK("no host\n"); + return IRQ_NONE; + } + + spin_lock_irqsave(&host->lock, flags); + + mmio = host->mmio; + + /* reading should also clear interrupts */ + mask = readl(mmio + CARM_INT_STAT); + + if (mask == 0 || mask == 0xffffffff) { + VPRINTK("no work, mask == 0x%x\n", mask); + goto out; + } + + if (mask & INT_ACK_MASK) + writel(mask, mmio + CARM_INT_STAT); + + if (unlikely(host->state == HST_INVALID)) { + VPRINTK("not initialized yet, mask = 0x%x\n", mask); + goto out; + } + + if (mask & CARM_HAVE_RESP) { + handled = 1; + carm_handle_responses(host); + } + +out: + spin_unlock_irqrestore(&host->lock, flags); + VPRINTK("EXIT\n"); + return IRQ_RETVAL(handled); +} + +static void carm_fsm_task (void *_data) +{ + struct carm_host *host = _data; + unsigned long flags; + unsigned int state; + int rc, i, next_dev; + int reschedule = 0; + int new_state = HST_INVALID; + + spin_lock_irqsave(&host->lock, flags); + state = host->state; + spin_unlock_irqrestore(&host->lock, flags); + + DPRINTK("ENTER, state == %s\n", state_name[state]); + + switch (state) { + case HST_PROBE_START: + new_state = HST_ALLOC_BUF; + reschedule = 1; + break; + + case HST_ALLOC_BUF: + rc = carm_send_special(host, carm_fill_alloc_buf); + if (rc) { + new_state = HST_ERROR; + reschedule = 1; + } + break; + + case HST_SYNC_TIME: + rc = carm_send_special(host, carm_fill_sync_time); + if (rc) { + new_state = HST_ERROR; + reschedule = 1; + } + break; + + case HST_GET_FW_VER: + rc = carm_send_special(host, carm_fill_get_fw_ver); + if (rc) { + new_state = HST_ERROR; + reschedule = 1; + } + break; + + case HST_PORT_SCAN: + rc = carm_send_special(host, carm_fill_scan_channels); + if (rc) { + new_state = HST_ERROR; + reschedule = 1; + } + break; + + case HST_DEV_SCAN_START: + host->cur_scan_dev = -1; + new_state = HST_DEV_SCAN; + reschedule = 1; + break; + + case HST_DEV_SCAN: + next_dev = -1; + for (i = host->cur_scan_dev + 1; i < CARM_MAX_PORTS; i++) + if (host->dev_present & (1 << i)) { + next_dev = i; + break; + } + + if (next_dev >= 0) { + host->cur_scan_dev = next_dev; + rc = carm_array_info(host, next_dev); + if (rc) { + new_state = HST_ERROR; + reschedule = 1; + } + } else { + new_state = HST_DEV_ACTIVATE; + reschedule = 1; + } + break; + + case HST_DEV_ACTIVATE: { + int activated = 0; + for (i = 0; i < CARM_MAX_PORTS; i++) + if (host->dev_active & (1 << i)) { + struct carm_port *port = &host->port[i]; + struct gendisk *disk = port->disk; + + set_capacity(disk, port->capacity); + add_disk(disk); + activated++; + } + + printk(KERN_INFO DRV_NAME "(%s): %d ports activated\n", + pci_name(host->pdev), activated); + + new_state = HST_PROBE_FINISHED; + reschedule = 1; + break; + } + + case HST_PROBE_FINISHED: + up(&host->probe_sem); + break; + + case HST_ERROR: + /* FIXME: TODO */ + break; + + default: + /* should never occur */ + printk(KERN_ERR PFX "BUG: unknown state %d\n", state); + assert(0); + break; + } + + if (new_state != HST_INVALID) { + spin_lock_irqsave(&host->lock, flags); + host->state = new_state; + spin_unlock_irqrestore(&host->lock, flags); + } + if (reschedule) + schedule_work(&host->fsm_task); +} + +static int carm_init_wait(void *mmio, u32 bits, unsigned int test_bit) +{ + unsigned int i; + + for (i = 0; i < 50000; i++) { + u32 tmp = readl(mmio + CARM_LMUC); + udelay(100); + + if (test_bit) { + if ((tmp & bits) == bits) + return 0; + } else { + if ((tmp & bits) == 0) + return 0; + } + + cond_resched(); + } + + printk(KERN_ERR PFX "carm_init_wait timeout, bits == 0x%x, test_bit == %s\n", + bits, test_bit ? "yes" : "no"); + return -EBUSY; +} + +static void carm_init_responses(struct carm_host *host) +{ + void *mmio = host->mmio; + unsigned int i; + struct carm_response *resp = (struct carm_response *) host->shm; + + for (i = 0; i < RMSG_Q_LEN; i++) + resp[i].status = 0xffffffff; + + writel(0, mmio + CARM_RESP_IDX); +} + +static int carm_init_host(struct carm_host *host) +{ + void *mmio = host->mmio; + u32 tmp; + u8 tmp8; + int rc; + + DPRINTK("ENTER\n"); + + writel(0, mmio + CARM_INT_MASK); + + tmp8 = readb(mmio + CARM_INITC); + if (tmp8 & 0x01) { + tmp8 &= ~0x01; + writeb(tmp8, CARM_INITC); + readb(mmio + CARM_INITC); /* flush */ + + DPRINTK("snooze...\n"); + msleep(5000); + } + + tmp = readl(mmio + CARM_HMUC); + if (tmp & CARM_CME) { + DPRINTK("CME bit present, waiting\n"); + rc = carm_init_wait(mmio, CARM_CME, 1); + if (rc) { + DPRINTK("EXIT, carm_init_wait 1 failed\n"); + return rc; + } + } + if (tmp & CARM_RME) { + DPRINTK("RME bit present, waiting\n"); + rc = carm_init_wait(mmio, CARM_RME, 1); + if (rc) { + DPRINTK("EXIT, carm_init_wait 2 failed\n"); + return rc; + } + } + + tmp &= ~(CARM_RME | CARM_CME); + writel(tmp, mmio + CARM_HMUC); + readl(mmio + CARM_HMUC); /* flush */ + + rc = carm_init_wait(mmio, CARM_RME | CARM_CME, 0); + if (rc) { + DPRINTK("EXIT, carm_init_wait 3 failed\n"); + return rc; + } + + carm_init_buckets(mmio); + + writel(host->shm_dma & 0xffffffff, mmio + RBUF_ADDR_LO); + writel((host->shm_dma >> 16) >> 16, mmio + RBUF_ADDR_HI); + writel(RBUF_LEN, mmio + RBUF_BYTE_SZ); + + tmp = readl(mmio + CARM_HMUC); + tmp |= (CARM_RME | CARM_CME | CARM_WZBC); + writel(tmp, mmio + CARM_HMUC); + readl(mmio + CARM_HMUC); /* flush */ + + rc = carm_init_wait(mmio, CARM_RME | CARM_CME, 1); + if (rc) { + DPRINTK("EXIT, carm_init_wait 4 failed\n"); + return rc; + } + + writel(0, mmio + CARM_HMPHA); + writel(INT_DEF_MASK, mmio + CARM_INT_MASK); + + carm_init_responses(host); + + /* start initialization, probing state machine */ + spin_lock_irq(&host->lock); + assert(host->state == HST_INVALID); + host->state = HST_PROBE_START; + spin_unlock_irq(&host->lock); + schedule_work(&host->fsm_task); + + DPRINTK("EXIT\n"); + return 0; +} + +static int carm_init_disks(struct carm_host *host) +{ + unsigned int i; + int rc = 0; + + for (i = 0; i < CARM_MAX_PORTS; i++) { + struct gendisk *disk; + request_queue_t *q; + struct carm_port *port; + + port = &host->port[i]; + port->host = host; + port->port_no = i; + + disk = alloc_disk(CARM_MINORS_PER_MAJOR); + if (!disk) { + rc = -ENOMEM; + break; + } + + port->disk = disk; + sprintf(disk->disk_name, DRV_NAME "%u_%u", carm_host_id, i); + sprintf(disk->devfs_name, DRV_NAME "/%u_%u", carm_host_id, i); + disk->major = host->major; + disk->first_minor = i * CARM_MINORS_PER_MAJOR; + disk->fops = &carm_bd_ops; + disk->private_data = port; + + q = blk_init_queue(carm_rq_fn, &host->lock); + if (!q) { + rc = -ENOMEM; + break; + } + disk->queue = q; + blk_queue_max_hw_segments(q, CARM_MAX_REQ_SG); + blk_queue_max_phys_segments(q, CARM_MAX_REQ_SG); + blk_queue_segment_boundary(q, CARM_SG_BOUNDARY); + + q->queuedata = port; + } + + return rc; +} + +static void carm_free_disks(struct carm_host *host) +{ + unsigned int i; + + for (i = 0; i < CARM_MAX_PORTS; i++) { + struct gendisk *disk = host->port[i].disk; + if (disk) { + request_queue_t *q = disk->queue; + if (q) + blk_cleanup_queue(q); + put_disk(disk); + } + } +} + +static int carm_init_shm(struct carm_host *host) +{ + host->shm = pci_alloc_consistent(host->pdev, CARM_SHM_SIZE, + &host->shm_dma); + if (!host->shm) + return -ENOMEM; + + host->msg_base = host->shm + RBUF_LEN; + host->msg_dma = host->shm_dma + RBUF_LEN; + + memset(host->shm, 0xff, RBUF_LEN); + memset(host->msg_base, 0, PDC_SHM_SIZE - RBUF_LEN); + + return 0; +} + +static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static unsigned int printed_version; + struct carm_host *host; + unsigned int pci_dac; + int rc; + request_queue_t *q; + unsigned int i; + + if (!printed_version++) + printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + + rc = pci_enable_device(pdev); + if (rc) + return rc; + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto err_out; + +#if IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */ + rc = pci_set_dma_mask(pdev, 0xffffffffffffffffULL); + if (!rc) { + rc = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL); + if (rc) { + printk(KERN_ERR DRV_NAME "(%s): consistent DMA mask failure\n", + pci_name(pdev)); + goto err_out_regions; + } + pci_dac = 1; + } else { +#endif + rc = pci_set_dma_mask(pdev, 0xffffffffULL); + if (rc) { + printk(KERN_ERR DRV_NAME "(%s): DMA mask failure\n", + pci_name(pdev)); + goto err_out_regions; + } + pci_dac = 0; +#if IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */ + } +#endif + + host = kmalloc(sizeof(*host), GFP_KERNEL); + if (!host) { + printk(KERN_ERR DRV_NAME "(%s): memory alloc failure\n", + pci_name(pdev)); + rc = -ENOMEM; + goto err_out_regions; + } + + memset(host, 0, sizeof(*host)); + host->pdev = pdev; + host->flags = pci_dac ? FL_DAC : 0; + spin_lock_init(&host->lock); + INIT_WORK(&host->fsm_task, carm_fsm_task, host); + init_MUTEX_LOCKED(&host->probe_sem); + + for (i = 0; i < ARRAY_SIZE(host->req); i++) + host->req[i].tag = i; + + host->mmio = ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (!host->mmio) { + printk(KERN_ERR DRV_NAME "(%s): MMIO alloc failure\n", + pci_name(pdev)); + rc = -ENOMEM; + goto err_out_kfree; + } + + rc = carm_init_shm(host); + if (rc) { + printk(KERN_ERR DRV_NAME "(%s): DMA SHM alloc failure\n", + pci_name(pdev)); + goto err_out_iounmap; + } + + q = blk_init_queue(carm_oob_rq_fn, &host->lock); + if (!q) { + printk(KERN_ERR DRV_NAME "(%s): OOB queue alloc failure\n", + pci_name(pdev)); + rc = -ENOMEM; + goto err_out_pci_free; + } + host->oob_q = q; + q->queuedata = host; + + rc = register_blkdev(0, DRV_NAME); + if (rc < 0) + goto err_out_free_oob; + host->major = rc; + + devfs_mk_dir(DRV_NAME); + + rc = carm_init_disks(host); + if (rc) + goto err_out_blkdev_disks; + + pci_set_master(pdev); + + rc = request_irq(pdev->irq, carm_interrupt, SA_SHIRQ, DRV_NAME, host); + if (rc) { + printk(KERN_ERR DRV_NAME "(%s): irq alloc failure\n", + pci_name(pdev)); + goto err_out_blkdev_disks; + } + + rc = carm_init_host(host); + if (rc) + goto err_out_free_irq; + + DPRINTK("waiting for probe_sem\n"); + down(&host->probe_sem); + + /* TODO: wait for probing to end */ + + printk(KERN_ERR DRV_NAME "(%s): registered host, %d ports, mmio %lx\n", + pci_name(pdev), (int) CARM_MAX_PORTS, + pci_resource_start(pdev, 0)); + carm_host_id++; + pci_set_drvdata(pdev, host); + return 0; + +err_out_free_irq: + free_irq(pdev->irq, host); +err_out_blkdev_disks: + carm_free_disks(host); + unregister_blkdev(host->major, DRV_NAME); +err_out_free_oob: + blk_cleanup_queue(host->oob_q); +err_out_pci_free: + pci_free_consistent(pdev, CARM_SHM_SIZE, host->shm, host->shm_dma); +err_out_iounmap: + iounmap(host->mmio); +err_out_kfree: + kfree(host); +err_out_regions: + pci_release_regions(pdev); +err_out: + pci_disable_device(pdev); + return rc; +} + +static void carm_remove_one (struct pci_dev *pdev) +{ + struct carm_host *host = pci_get_drvdata(pdev); + + if (!host) { + printk(KERN_ERR PFX "BUG: no host data for PCI(%s)\n", + pci_name(pdev)); + return; + } + + free_irq(pdev->irq, host); + carm_free_disks(host); + devfs_remove(DRV_NAME); + unregister_blkdev(host->major, DRV_NAME); + blk_cleanup_queue(host->oob_q); + pci_free_consistent(pdev, CARM_SHM_SIZE, host->shm, host->shm_dma); + iounmap(host->mmio); + kfree(host); + pci_release_regions(pdev); + pci_disable_device(pdev); +} + +static int __init carm_init(void) +{ + return pci_module_init(&carm_driver); +} + +static void __exit carm_exit(void) +{ + pci_unregister_driver(&carm_driver); +} + +module_init(carm_init); +module_exit(carm_exit); + + diff -Nru a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c --- a/drivers/block/cciss_scsi.c Sun Mar 14 14:20:06 2004 +++ b/drivers/block/cciss_scsi.c Sun Mar 14 14:20:06 2004 @@ -693,7 +693,7 @@ scsi_cmd_free(ctlr, cp); } -static int __init +static int cciss_scsi_detect(int ctlr) { struct Scsi_Host *sh; diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c --- a/drivers/block/ll_rw_blk.c Sun Mar 14 14:20:06 2004 +++ b/drivers/block/ll_rw_blk.c Sun Mar 14 14:20:06 2004 @@ -28,6 +28,11 @@ #include #include +/* + * for max sense size + */ +#include + static void blk_unplug_work(void *data); static void blk_unplug_timeout(unsigned long data); @@ -104,6 +109,7 @@ bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested; clear_bit(bit, &q->backing_dev_info.state); + smp_mb__after_clear_bit(); if (waitqueue_active(wqh)) wake_up(wqh); } @@ -1136,8 +1142,6 @@ if (!blk_remove_plug(q)) return; - del_timer(&q->unplug_timer); - /* * was plugged, fire request_fn if queue has stuff to do */ @@ -1543,7 +1547,6 @@ if (rl->count[rw] < queue_congestion_off_threshold(q)) clear_queue_congested(q, rw); if (rl->count[rw]+1 <= q->nr_requests) { - smp_mb(); if (waitqueue_active(&rl->wait[rw])) wake_up(&rl->wait[rw]); if (!waitqueue_active(&rl->wait[rw])) @@ -1625,6 +1628,7 @@ rq->rl = rl; rq->waiting = NULL; rq->special = NULL; + rq->data_len = 0; rq->data = NULL; rq->sense = NULL; @@ -1770,6 +1774,144 @@ EXPORT_SYMBOL(blk_insert_request); +/** + * blk_rq_map_user - map user data to a request, for REQ_BLOCK_PC usage + * @q: request queue where request should be inserted + * @rw: READ or WRITE data + * @ubuf: the user buffer + * @len: length of user data + * + * Description: + * Data will be mapped directly for zero copy io, if possible. Otherwise + * a kernel bounce buffer is used. + * + * A matching blk_rq_unmap_user() must be issued at the end of io, while + * still in process context. + */ +struct request *blk_rq_map_user(request_queue_t *q, int rw, void __user *ubuf, + unsigned int len) +{ + struct request *rq = NULL; + char *buf = NULL; + struct bio *bio; + int ret; + + rq = blk_get_request(q, rw, __GFP_WAIT); + if (!rq) + return ERR_PTR(-ENOMEM); + + bio = bio_map_user(q, NULL, (unsigned long) ubuf, len, rw == READ); + if (!bio) { + int bytes = (len + 511) & ~511; + + buf = kmalloc(bytes, q->bounce_gfp | GFP_USER); + if (!buf) { + ret = -ENOMEM; + goto fault; + } + + if (rw == WRITE) { + if (copy_from_user(buf, ubuf, len)) { + ret = -EFAULT; + goto fault; + } + } else + memset(buf, 0, len); + } + + rq->bio = rq->biotail = bio; + if (rq->bio) + blk_rq_bio_prep(q, rq, bio); + + rq->buffer = rq->data = buf; + rq->data_len = len; + return rq; +fault: + if (buf) + kfree(buf); + if (bio) + bio_unmap_user(bio, 1); + if (rq) + blk_put_request(rq); + + return ERR_PTR(ret); +} + +EXPORT_SYMBOL(blk_rq_map_user); + +/** + * blk_rq_unmap_user - unmap a request with user data + * @rq: request to be unmapped + * @ubuf: user buffer + * @ulen: length of user buffer + * + * Description: + * Unmap a request previously mapped by blk_rq_map_user(). + */ +int blk_rq_unmap_user(struct request *rq, void __user *ubuf, unsigned int ulen) +{ + const int read = rq_data_dir(rq) == READ; + int ret = 0; + + if (rq->biotail) + bio_unmap_user(rq->biotail, read); + if (rq->buffer) { + if (read && copy_to_user(ubuf, rq->buffer, ulen)) + ret = -EFAULT; + kfree(rq->buffer); + } + + blk_put_request(rq); + return ret; +} + +EXPORT_SYMBOL(blk_rq_unmap_user); + +/** + * blk_execute_rq - insert a request into queue for execution + * @q: queue to insert the request in + * @bd_disk: matching gendisk + * @rq: request to insert + * + * Description: + * Insert a fully prepared request at the back of the io scheduler queue + * for execution. + */ +int blk_execute_rq(request_queue_t *q, struct gendisk *bd_disk, + struct request *rq) +{ + DECLARE_COMPLETION(wait); + char sense[SCSI_SENSE_BUFFERSIZE]; + int err = 0; + + rq->rq_disk = bd_disk; + + /* + * we need an extra reference to the request, so we can look at + * it after io completion + */ + rq->ref_count++; + + if (!rq->sense) { + memset(sense, 0, sizeof(sense)); + rq->sense = sense; + rq->sense_len = 0; + } + + rq->flags |= REQ_NOMERGE; + rq->waiting = &wait; + elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1); + generic_unplug_device(q); + wait_for_completion(&wait); + + if (rq->errors) + err = -EIO; + + return err; +} + +EXPORT_SYMBOL(blk_execute_rq); + void drive_stat_acct(struct request *rq, int nr_sectors, int new_io) { int rw = rq_data_dir(rq); @@ -1898,15 +2040,17 @@ * If no queues are congested then just wait for the next request to be * returned. */ -void blk_congestion_wait(int rw, long timeout) +long blk_congestion_wait(int rw, long timeout) { + long ret; DEFINE_WAIT(wait); wait_queue_head_t *wqh = &congestion_wqh[rw]; blk_run_queues(); prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE); - io_schedule_timeout(timeout); + ret = io_schedule_timeout(timeout); finish_wait(wqh, &wait); + return ret; } EXPORT_SYMBOL(blk_congestion_wait); diff -Nru a/drivers/block/loop.c b/drivers/block/loop.c --- a/drivers/block/loop.c Sun Mar 14 14:20:07 2004 +++ b/drivers/block/loop.c Sun Mar 14 14:20:07 2004 @@ -66,6 +66,7 @@ #include #include #include /* for invalidate_bdev() */ +#include #include @@ -148,14 +149,12 @@ &xor_funcs }; -static int -figure_loop_size(struct loop_device *lo) +static loff_t get_loop_size(struct loop_device *lo, struct file *file) { loff_t size, offset, loopsize; - sector_t x; /* Compute loopsize in bytes */ - size = i_size_read(lo->lo_backing_file->f_mapping->host); + size = i_size_read(file->f_mapping->host); offset = lo->lo_offset; loopsize = size - offset; if (lo->lo_sizelimit > 0 && lo->lo_sizelimit < loopsize) @@ -165,8 +164,14 @@ * Unfortunately, if we want to do I/O on the device, * the number of 512-byte sectors has to fit into a sector_t. */ - size = loopsize >> 9; - x = (sector_t)size; + return loopsize >> 9; +} + +static int +figure_loop_size(struct loop_device *lo) +{ + loff_t size = get_loop_size(lo, lo->lo_backing_file); + sector_t x = (sector_t)size; if ((loff_t)x != size) return -EFBIG; @@ -429,12 +434,24 @@ goto out; } +struct switch_request { + struct file *file; + struct completion wait; +}; + +static void do_loop_switch(struct loop_device *, struct switch_request *); + static inline void loop_handle_bio(struct loop_device *lo, struct bio *bio) { int ret; - ret = do_bio_filebacked(lo, bio); - bio_endio(bio, bio->bi_size, ret); + if (unlikely(!bio->bi_bdev)) { + do_loop_switch(lo, bio->bi_private); + bio_put(bio); + } else { + ret = do_bio_filebacked(lo, bio); + bio_endio(bio, bio->bi_size, ret); + } } /* @@ -495,6 +512,103 @@ return 0; } +/* + * loop_switch performs the hard work of switching a backing store. + * First it needs to flush existing IO, it does this by sending a magic + * BIO down the pipe. The completion of this BIO does the actual switch. + */ +static int loop_switch(struct loop_device *lo, struct file *file) +{ + struct switch_request w; + struct bio *bio = bio_alloc(GFP_KERNEL, 1); + if (!bio) + return -ENOMEM; + init_completion(&w.wait); + w.file = file; + bio->bi_private = &w; + bio->bi_bdev = NULL; + loop_make_request(lo->lo_queue, bio); + wait_for_completion(&w.wait); + return 0; +} + +/* + * Do the actual switch; called from the BIO completion routine + */ +static void do_loop_switch(struct loop_device *lo, struct switch_request *p) +{ + struct file *file = p->file; + struct file *old_file = lo->lo_backing_file; + struct address_space *mapping = file->f_mapping; + + mapping_set_gfp_mask(old_file->f_mapping, lo->old_gfp_mask); + lo->lo_backing_file = file; + lo->lo_blocksize = mapping->host->i_blksize; + lo->old_gfp_mask = mapping_gfp_mask(mapping); + mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS)); + complete(&p->wait); +} + + +/* + * loop_change_fd switched the backing store of a loopback device to + * a new file. This is useful for operating system installers to free up + * the original file and in High Availability environments to switch to + * an alternative location for the content in case of server meltdown. + * This can only work if the loop device is used read-only, and if the + * new backing store is the same size and type as the old backing store. + */ +static int loop_change_fd(struct loop_device *lo, struct file *lo_file, + struct block_device *bdev, unsigned int arg) +{ + struct file *file, *old_file; + struct inode *inode; + int error; + + error = -ENXIO; + if (lo->lo_state != Lo_bound) + goto out; + + /* the loop device has to be read-only */ + error = -EINVAL; + if (lo->lo_flags != LO_FLAGS_READ_ONLY) + goto out; + + error = -EBADF; + file = fget(arg); + if (!file) + goto out; + + inode = file->f_mapping->host; + old_file = lo->lo_backing_file; + + error = -EINVAL; + + if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode)) + goto out_putf; + + /* new backing store needs to support loop (eg sendfile) */ + if (!inode->i_fop->sendfile) + goto out_putf; + + /* size of the new backing store needs to be the same */ + if (get_loop_size(lo, file) != get_loop_size(lo, old_file)) + goto out_putf; + + /* and ... switch */ + error = loop_switch(lo, file); + if (error) + goto out_putf; + + fput(old_file); + return 0; + + out_putf: + fput(file); + out: + return error; +} + static int loop_set_fd(struct loop_device *lo, struct file *lo_file, struct block_device *bdev, unsigned int arg) { @@ -505,6 +619,7 @@ unsigned lo_blocksize; int lo_flags = 0; int error; + loff_t size; /* This is safe, since we have a reference from open(). */ __module_get(THIS_MODULE); @@ -543,6 +658,13 @@ goto out_putf; } + size = get_loop_size(lo, file); + + if ((loff_t)(sector_t)size != size) { + error = -EFBIG; + goto out_putf; + } + if (!(lo_file->f_mode & FMODE_WRITE)) lo_flags |= LO_FLAGS_READ_ONLY; @@ -555,10 +677,7 @@ lo->transfer = NULL; lo->ioctl = NULL; lo->lo_sizelimit = 0; - if (figure_loop_size(lo)) { - error = -EFBIG; - goto out_putf; - } + bd_set_size(bdev,(loff_t)get_capacity(disks[lo->lo_number])<<9); lo->old_gfp_mask = mapping_gfp_mask(mapping); mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS)); @@ -571,6 +690,8 @@ blk_queue_make_request(lo->lo_queue, loop_make_request); lo->lo_queue->queuedata = lo; + set_capacity(disks[lo->lo_number], size); + set_blocksize(bdev, lo_blocksize); kernel_thread(loop_thread, lo, CLONE_KERNEL); @@ -660,6 +781,7 @@ memset(lo->lo_file_name, 0, LO_NAME_SIZE); invalidate_bdev(bdev, 0); set_capacity(disks[lo->lo_number], 0); + bd_set_size(bdev, 0); mapping_set_gfp_mask(filp->f_mapping, gfp); lo->lo_state = Lo_unbound; fput(filp); @@ -880,6 +1002,9 @@ switch (cmd) { case LOOP_SET_FD: err = loop_set_fd(lo, file, inode->i_bdev, arg); + break; + case LOOP_CHANGE_FD: + err = loop_change_fd(lo, file, inode->i_bdev, arg); break; case LOOP_CLR_FD: err = loop_clr_fd(lo, inode->i_bdev); diff -Nru a/drivers/block/scsi_ioctl.c b/drivers/block/scsi_ioctl.c --- a/drivers/block/scsi_ioctl.c Sun Mar 14 14:20:08 2004 +++ b/drivers/block/scsi_ioctl.c Sun Mar 14 14:20:08 2004 @@ -24,13 +24,12 @@ #include #include #include -#include #include #include #include #include - +#include /* Command group 3 is reserved and should never be used. */ const unsigned char scsi_command_size[8] = @@ -39,45 +38,9 @@ 16, 12, 10, 10 }; -#define BLK_DEFAULT_TIMEOUT (60 * HZ) - -/* defined in ../scsi/scsi.h ... should it be included? */ -#ifndef SCSI_SENSE_BUFFERSIZE -#define SCSI_SENSE_BUFFERSIZE 64 -#endif - -static int blk_do_rq(request_queue_t *q, struct gendisk *bd_disk, - struct request *rq) -{ - char sense[SCSI_SENSE_BUFFERSIZE]; - DECLARE_COMPLETION(wait); - int err = 0; - - rq->rq_disk = bd_disk; - - /* - * we need an extra reference to the request, so we can look at - * it after io completion - */ - rq->ref_count++; - - if (!rq->sense) { - memset(sense, 0, sizeof(sense)); - rq->sense = sense; - rq->sense_len = 0; - } - - rq->flags |= REQ_NOMERGE; - rq->waiting = &wait; - elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1); - generic_unplug_device(q); - wait_for_completion(&wait); - - if (rq->errors) - err = -EIO; +EXPORT_SYMBOL(scsi_command_size); - return err; -} +#define BLK_DEFAULT_TIMEOUT (60 * HZ) #include @@ -148,9 +111,7 @@ unsigned long start_time; int reading, writing; struct request *rq; - struct bio *bio; char sense[SCSI_SENSE_BUFFERSIZE]; - void *buffer; if (hdr->interface_id != 'S') return -EINVAL; @@ -167,11 +128,7 @@ return -EIO; reading = writing = 0; - buffer = NULL; - bio = NULL; if (hdr->dxfer_len) { - unsigned int bytes = (hdr->dxfer_len + 511) & ~511; - switch (hdr->dxfer_direction) { default: return -EINVAL; @@ -186,31 +143,13 @@ break; } - /* - * first try to map it into a bio. reading from device will - * be a write to vm. - */ - bio = bio_map_user(q, NULL, (unsigned long) hdr->dxferp, - hdr->dxfer_len, reading); - - /* - * if bio setup failed, fall back to slow approach - */ - if (!bio) { - buffer = kmalloc(bytes, q->bounce_gfp | GFP_USER); - if (!buffer) - return -ENOMEM; - - if (writing) { - if (copy_from_user(buffer, hdr->dxferp, - hdr->dxfer_len)) - goto out_buffer; - } else - memset(buffer, 0, hdr->dxfer_len); - } - } + rq = blk_rq_map_user(q, writing ? WRITE : READ, hdr->dxferp, + hdr->dxfer_len); - rq = blk_get_request(q, writing ? WRITE : READ, __GFP_WAIT); + if (IS_ERR(rq)) + return PTR_ERR(rq); + } else + rq = blk_get_request(q, READ, __GFP_WAIT); /* * fill in request structure @@ -226,14 +165,6 @@ rq->flags |= REQ_BLOCK_PC; - rq->bio = rq->biotail = NULL; - - if (bio) - blk_rq_bio_prep(q, rq, bio); - - rq->data = buffer; - rq->data_len = hdr->dxfer_len; - rq->timeout = (hdr->timeout * HZ) / 1000; if (!rq->timeout) rq->timeout = q->sg_timeout; @@ -246,10 +177,7 @@ * (if he doesn't check that is his problem). * N.B. a non-zero SCSI status is _not_ necessarily an error. */ - blk_do_rq(q, bd_disk, rq); - - if (bio) - bio_unmap_user(bio, reading); + blk_execute_rq(q, bd_disk, rq); /* write to all output members */ hdr->status = rq->errors; @@ -271,22 +199,12 @@ hdr->sb_len_wr = len; } - blk_put_request(rq); - - if (buffer) { - if (reading) - if (copy_to_user(hdr->dxferp, buffer, hdr->dxfer_len)) - goto out_buffer; - - kfree(buffer); - } + if (blk_rq_unmap_user(rq, hdr->dxferp, hdr->dxfer_len)) + return -EFAULT; /* may not have succeeded, but output values written to control * structure (struct sg_io_hdr). */ return 0; -out_buffer: - kfree(buffer); - return -EFAULT; } #define FORMAT_UNIT_TIMEOUT (2 * 60 * 60 * HZ) @@ -369,7 +287,7 @@ rq->data_len = bytes; rq->flags |= REQ_BLOCK_PC; - blk_do_rq(q, bd_disk, rq); + blk_execute_rq(q, bd_disk, rq); err = rq->errors & 0xff; /* only 8 bit SCSI status */ if (err) { if (rq->sense_len && rq->sense) { @@ -447,6 +365,8 @@ old_cdb = hdr.cmdp; hdr.cmdp = cdb; err = sg_io(q, bd_disk, &hdr); + if (err == -EFAULT) + break; hdr.cmdp = old_cdb; if (copy_to_user((struct sg_io_hdr *) arg, &hdr, sizeof(hdr))) @@ -457,10 +377,9 @@ struct cdrom_generic_command cgc; struct sg_io_hdr hdr; - if (copy_from_user(&cgc, (struct cdrom_generic_command *) arg, sizeof(cgc))) { - err = -EFAULT; + err = -EFAULT; + if (copy_from_user(&cgc, (struct cdrom_generic_command *) arg, sizeof(cgc))) break; - } cgc.timeout = clock_t_to_jiffies(cgc.timeout); memset(&hdr, 0, sizeof(hdr)); hdr.interface_id = 'S'; @@ -493,7 +412,10 @@ hdr.timeout = cgc.timeout; hdr.cmdp = cgc.cmd; hdr.cmd_len = sizeof(cgc.cmd); + err = sg_io(q, bd_disk, &hdr); + if (err == -EFAULT) + break; if (hdr.status) err = -EIO; @@ -529,7 +451,7 @@ rq->cmd[0] = GPCMD_START_STOP_UNIT; rq->cmd[4] = 0x02 + (close != 0); rq->cmd_len = 6; - err = blk_do_rq(q, bd_disk, rq); + err = blk_execute_rq(q, bd_disk, rq); blk_put_request(rq); break; default: @@ -541,4 +463,3 @@ } EXPORT_SYMBOL(scsi_cmd_ioctl); -EXPORT_SYMBOL(scsi_command_size); diff -Nru a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c --- a/drivers/cdrom/cdrom.c Sun Mar 14 14:20:06 2004 +++ b/drivers/cdrom/cdrom.c Sun Mar 14 14:20:06 2004 @@ -406,6 +406,11 @@ if (CDROM_CAN(CDC_MRW_W)) cdi->exit = cdrom_mrw_exit; + if (cdi->disk) + cdi->cdda_method = CDDA_BPC_FULL; + else + cdi->cdda_method = CDDA_OLD; + cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); spin_lock(&cdrom_lock); cdi->next = topCdromPtr; @@ -1788,6 +1793,149 @@ return cdo->generic_packet(cdi, cgc); } +static int cdrom_read_cdda_old(struct cdrom_device_info *cdi, __u8 __user *ubuf, + int lba, int nframes) +{ + struct cdrom_generic_command cgc; + int nr, ret; + + memset(&cgc, 0, sizeof(cgc)); + + /* + * start with will ra.nframes size, back down if alloc fails + */ + nr = nframes; + do { + cgc.buffer = kmalloc(CD_FRAMESIZE_RAW * nr, GFP_KERNEL); + if (cgc.buffer) + break; + + nr >>= 1; + } while (nr); + + if (!nr) + return -ENOMEM; + + if (!access_ok(VERIFY_WRITE, ubuf, nframes * CD_FRAMESIZE_RAW)) { + kfree(cgc.buffer); + return -EFAULT; + } + + cgc.data_direction = CGC_DATA_READ; + while (nframes > 0) { + if (nr > nframes) + nr = nframes; + + ret = cdrom_read_block(cdi, &cgc, lba, nr, 1, CD_FRAMESIZE_RAW); + if (ret) + break; + __copy_to_user(ubuf, cgc.buffer, CD_FRAMESIZE_RAW * nr); + ubuf += CD_FRAMESIZE_RAW * nr; + nframes -= nr; + lba += nr; + } + kfree(cgc.buffer); + return 0; +} + +static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, + int lba, int nframes) +{ + request_queue_t *q = cdi->disk->queue; + struct request *rq; + unsigned int len; + int nr, ret = 0; + + if (!q) + return -ENXIO; + + while (nframes) { + nr = nframes; + if (cdi->cdda_method == CDDA_BPC_SINGLE) + nr = 1; + if (nr * CD_FRAMESIZE_RAW > (q->max_sectors << 9)) + nr = (q->max_sectors << 9) / CD_FRAMESIZE_RAW; + + len = nr * CD_FRAMESIZE_RAW; + + rq = blk_rq_map_user(q, READ, ubuf, len); + if (IS_ERR(rq)) + return PTR_ERR(rq); + + memset(rq->cmd, 0, sizeof(rq->cmd)); + rq->cmd[0] = GPCMD_READ_CD; + rq->cmd[1] = 1 << 2; + rq->cmd[2] = (lba >> 24) & 0xff; + rq->cmd[3] = (lba >> 16) & 0xff; + rq->cmd[4] = (lba >> 8) & 0xff; + rq->cmd[5] = lba & 0xff; + rq->cmd[6] = (nr >> 16) & 0xff; + rq->cmd[7] = (nr >> 8) & 0xff; + rq->cmd[8] = nr & 0xff; + rq->cmd[9] = 0xf8; + + rq->cmd_len = 12; + rq->flags |= REQ_BLOCK_PC; + rq->timeout = 60 * HZ; + + if (blk_execute_rq(q, cdi->disk, rq)) { + struct request_sense *s = rq->sense; + ret = -EIO; + cdi->last_sense = s->sense_key; + } + + if (blk_rq_unmap_user(rq, ubuf, len)) + ret = -EFAULT; + + if (ret) + break; + + nframes -= nr; + lba += nr; + } + + return ret; +} + +static int cdrom_read_cdda(struct cdrom_device_info *cdi, __u8 __user *ubuf, + int lba, int nframes) +{ + int ret; + + if (cdi->cdda_method == CDDA_OLD) + return cdrom_read_cdda_old(cdi, ubuf, lba, nframes); + +retry: + /* + * for anything else than success and io error, we need to retry + */ + ret = cdrom_read_cdda_bpc(cdi, ubuf, lba, nframes); + if (!ret || ret != -EIO) + return ret; + + /* + * I've seen drives get sense 4/8/3 udma crc errors on multi + * frame dma, so drop to single frame dma if we need to + */ + if (cdi->cdda_method == CDDA_BPC_FULL && nframes > 1) { + printk("cdrom: dropping to single frame dma\n"); + cdi->cdda_method = CDDA_BPC_SINGLE; + goto retry; + } + + /* + * so we have an io error of some sort with multi frame dma. if the + * condition wasn't a hardware error + * problems, not for any error + */ + if (cdi->last_sense != 0x04 && cdi->last_sense != 0x0b) + return ret; + + printk("cdrom: dropping to old style cdda (sense=%x)\n", cdi->last_sense); + cdi->cdda_method = CDDA_OLD; + return cdrom_read_cdda_old(cdi, ubuf, lba, nframes); +} + /* Just about every imaginable ioctl is supported in the Uniform layer * these days. ATAPI / SCSI specific code now mainly resides in * mmc_ioct(). @@ -2280,7 +2428,7 @@ } case CDROMREADAUDIO: { struct cdrom_read_audio ra; - int lba, nr; + int lba; IOCTL_IN(arg, struct cdrom_read_audio, ra); @@ -2297,40 +2445,7 @@ if (lba < 0 || ra.nframes <= 0 || ra.nframes > CD_FRAMES) return -EINVAL; - /* - * start with will ra.nframes size, back down if alloc fails - */ - nr = ra.nframes; - do { - cgc.buffer = kmalloc(CD_FRAMESIZE_RAW * nr, GFP_KERNEL); - if (cgc.buffer) - break; - - nr >>= 1; - } while (nr); - - if (!nr) - return -ENOMEM; - - if (!access_ok(VERIFY_WRITE, ra.buf, ra.nframes*CD_FRAMESIZE_RAW)) { - kfree(cgc.buffer); - return -EFAULT; - } - cgc.data_direction = CGC_DATA_READ; - while (ra.nframes > 0) { - if (nr > ra.nframes) - nr = ra.nframes; - - ret = cdrom_read_block(cdi, &cgc, lba, nr, 1, CD_FRAMESIZE_RAW); - if (ret) - break; - __copy_to_user(ra.buf, cgc.buffer, CD_FRAMESIZE_RAW*nr); - ra.buf += CD_FRAMESIZE_RAW * nr; - ra.nframes -= nr; - lba += nr; - } - kfree(cgc.buffer); - return ret; + return cdrom_read_cdda(cdi, ra.buf, lba, ra.nframes); } case CDROMSUBCHNL: { struct cdrom_subchnl q; diff -Nru a/drivers/char/Kconfig b/drivers/char/Kconfig --- a/drivers/char/Kconfig Sun Mar 14 14:20:06 2004 +++ b/drivers/char/Kconfig Sun Mar 14 14:20:06 2004 @@ -740,6 +740,7 @@ config NVRAM tristate "/dev/nvram support" + depends on ATARI || X86 || X86_64 || ARM || GENERIC_NVRAM ---help--- If you say Y here and create a character special file /dev/nvram with major number 10 and minor number 144 using mknod ("man mknod"), diff -Nru a/drivers/char/applicom.c b/drivers/char/applicom.c --- a/drivers/char/applicom.c Sun Mar 14 14:20:08 2004 +++ b/drivers/char/applicom.c Sun Mar 14 14:20:08 2004 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include diff -Nru a/drivers/char/genrtc.c b/drivers/char/genrtc.c --- a/drivers/char/genrtc.c Sun Mar 14 14:20:08 2004 +++ b/drivers/char/genrtc.c Sun Mar 14 14:20:08 2004 @@ -466,6 +466,17 @@ return len; } +static int __init gen_rtc_proc_init(void) +{ + struct proc_dir_entry *r; + + r = create_proc_read_entry("driver/rtc", 0, 0, gen_rtc_read_proc, NULL); + if (!r) + return -ENOMEM; + return 0; +} +#else +static inline int gen_rtc_proc_init(void) { return 0; } #endif /* CONFIG_PROC_FS */ @@ -498,15 +509,14 @@ printk(KERN_INFO "Generic RTC Driver v%s\n", RTC_VERSION); retval = misc_register(&rtc_gen_dev); - if(retval < 0) + if (retval < 0) return retval; -#ifdef CONFIG_PROC_FS - if((create_proc_read_entry ("driver/rtc", 0, 0, gen_rtc_read_proc, NULL)) == NULL){ + retval = gen_rtc_proc_init(); + if (retval) { misc_deregister(&rtc_gen_dev); - return -ENOMEM; + return retval; } -#endif return 0; } diff -Nru a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c --- a/drivers/char/pcmcia/synclink_cs.c Sun Mar 14 14:20:07 2004 +++ b/drivers/char/pcmcia/synclink_cs.c Sun Mar 14 14:20:07 2004 @@ -1,7 +1,7 @@ /* * linux/drivers/char/pcmcia/synclink_cs.c * - * $Id: synclink_cs.c,v 4.15 2003/09/05 15:26:02 paulkf Exp $ + * $Id: synclink_cs.c,v 4.21 2004/03/08 15:29:23 paulkf Exp $ * * Device driver for Microgate SyncLink PC Card * multiprotocol serial adapter. @@ -489,7 +489,7 @@ MODULE_LICENSE("GPL"); static char *driver_name = "SyncLink PC Card driver"; -static char *driver_version = "$Revision: 4.15 $"; +static char *driver_version = "$Revision: 4.21 $"; static struct tty_driver *serial_driver; @@ -4233,12 +4233,13 @@ info->if_ptr = &info->pppdev; info->netdev = info->pppdev.dev = d; - sppp_attach(&info->pppdev); - d->base_addr = info->io_base; d->irq = info->irq_level; d->priv = info; + sppp_attach(&info->pppdev); + mgslpc_setup(d); + if (register_netdev(d)) { printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); sppp_detach(info->netdev); @@ -4413,7 +4414,7 @@ int mgslpc_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - MGSLPC_INFO *info = (MGSLPC_INFO *)dev->priv; + MGSLPC_INFO *info = dev->priv; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgslpc_ioctl %s cmd=%08X\n", __FILE__,__LINE__, info->netname, cmd ); diff -Nru a/drivers/char/sn_serial.c b/drivers/char/sn_serial.c --- a/drivers/char/sn_serial.c Sun Mar 14 14:20:08 2004 +++ b/drivers/char/sn_serial.c Sun Mar 14 14:20:08 2004 @@ -82,7 +82,6 @@ static unsigned long sn_interrupt_timeout; extern u64 master_node_bedrock_address; - static int sn_debug_printf(const char *fmt, ...); #undef DEBUG @@ -105,7 +104,6 @@ static struct sn_sal_ops *sn_func; /* Prototypes */ -static void __init sn_sal_serial_console_init(void); static int snt_hw_puts(const char *, int); static int snt_poll_getc(void); static int snt_poll_input_pending(void); @@ -921,9 +919,6 @@ printk(KERN_ERR "sn_serial: Unable to register tty driver\n"); return retval; } -#ifdef CONFIG_SGI_L1_SERIAL_CONSOLE - sn_sal_serial_console_init(); -#endif /* CONFIG_SGI_L1_SERIAL_CONSOLE */ return 0; } @@ -952,6 +947,7 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count) { unsigned long flags; + const char *s1; BUG_ON(!sn_sal_is_asynch); @@ -959,15 +955,36 @@ * oops, kdb, panic, etc. make sure they get it. */ if (spin_is_locked(&sn_sal_lock)) { synch_flush_xmit(); + /* Output '\r' before each '\n' */ + while ((s1 = memchr(s, '\n', count)) != NULL) { + sn_func->sal_puts(s, s1 - s); + sn_func->sal_puts("\r\n", 2); + count -= s1 + 1 - s; + s = s1 + 1; + } sn_func->sal_puts(s, count); } else if (in_interrupt()) { spin_lock_irqsave(&sn_sal_lock, flags); synch_flush_xmit(); spin_unlock_irqrestore(&sn_sal_lock, flags); + /* Output '\r' before each '\n' */ + while ((s1 = memchr(s, '\n', count)) != NULL) { + sn_func->sal_puts(s, s1 - s); + sn_func->sal_puts("\r\n", 2); + count -= s1 + 1 - s; + s = s1 + 1; + } sn_func->sal_puts(s, count); } else + /* Output '\r' before each '\n' */ + while ((s1 = memchr(s, '\n', count)) != NULL) { + sn_sal_write(NULL, 0, s, s1 - s); + sn_sal_write(NULL, 0, "\r\n", 2); + count -= s1 + 1 - s; + s = s1 + 1; + } sn_sal_write(NULL, 0, s, count); } @@ -993,7 +1010,7 @@ .index = -1 }; -static void __init +static int __init sn_sal_serial_console_init(void) { if (ia64_platform_is("sn2")) { @@ -1001,6 +1018,8 @@ sn_debug_printf("sn_sal_serial_console_init : register console\n"); register_console(&sal_console); } + return 0; } +console_initcall(sn_sal_serial_console_init); #endif /* CONFIG_SGI_L1_SERIAL_CONSOLE */ diff -Nru a/drivers/char/synclink.c b/drivers/char/synclink.c --- a/drivers/char/synclink.c Sun Mar 14 14:20:07 2004 +++ b/drivers/char/synclink.c Sun Mar 14 14:20:07 2004 @@ -1,7 +1,7 @@ /* * linux/drivers/char/synclink.c * - * $Id: synclink.c,v 4.16 2003/09/05 15:26:02 paulkf Exp $ + * $Id: synclink.c,v 4.21 2004/03/08 15:29:22 paulkf Exp $ * * Device driver for Microgate SyncLink ISA and PCI * high speed multiprotocol serial adapters. @@ -909,7 +909,7 @@ MODULE_PARM(txholdbufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i"); static char *driver_name = "SyncLink serial driver"; -static char *driver_version = "$Revision: 4.16 $"; +static char *driver_version = "$Revision: 4.21 $"; static int synclink_init_one (struct pci_dev *dev, const struct pci_device_id *ent); @@ -7846,13 +7846,14 @@ info->if_ptr = &info->pppdev; info->netdev = info->pppdev.dev = d; - sppp_attach(&info->pppdev); - d->base_addr = info->io_base; d->irq = info->irq_level; d->dma = info->dma_level; d->priv = info; + sppp_attach(&info->pppdev); + mgsl_setup(d); + if (register_netdev(d)) { printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); sppp_detach(info->netdev); @@ -8022,7 +8023,7 @@ int mgsl_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct mgsl_struct *info = (struct mgsl_struct *)dev->priv; + struct mgsl_struct *info = dev->priv; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgsl_ioctl %s cmd=%08X\n", __FILE__,__LINE__, info->netname, cmd ); diff -Nru a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c --- a/drivers/char/synclinkmp.c Sun Mar 14 14:20:06 2004 +++ b/drivers/char/synclinkmp.c Sun Mar 14 14:20:06 2004 @@ -1,5 +1,5 @@ /* - * $Id: synclinkmp.c,v 4.14 2003/09/05 15:26:03 paulkf Exp $ + * $Id: synclinkmp.c,v 4.19 2004/03/08 15:29:23 paulkf Exp $ * * Device driver for Microgate SyncLink Multiport * high speed multiprotocol serial adapter. @@ -494,7 +494,7 @@ MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICES) "i"); static char *driver_name = "SyncLink MultiPort driver"; -static char *driver_version = "$Revision: 4.14 $"; +static char *driver_version = "$Revision: 4.19 $"; static int synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent); static void synclinkmp_remove_one(struct pci_dev *dev); @@ -1653,11 +1653,12 @@ info->if_ptr = &info->pppdev; info->netdev = info->pppdev.dev = d; - sppp_attach(&info->pppdev); - d->irq = info->irq_level; d->priv = info; + sppp_attach(&info->pppdev); + cb_setup(d); + if (register_netdev(d)) { printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); sppp_detach(info->netdev); @@ -1828,7 +1829,7 @@ static int sppp_cb_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - SLMP_INFO *info = (SLMP_INFO *)dev->priv; + SLMP_INFO *info = dev->priv; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):ioctl %s cmd=%08X\n", __FILE__,__LINE__, info->netname, cmd ); @@ -2604,7 +2605,7 @@ del_timer(&info->status_timer); if (info->tx_buf) { - free_page((unsigned long) info->tx_buf); + kfree(info->tx_buf); info->tx_buf = 0; } diff -Nru a/drivers/char/viocons.c b/drivers/char/viocons.c --- a/drivers/char/viocons.c Sun Mar 14 14:20:05 2004 +++ b/drivers/char/viocons.c Sun Mar 14 14:20:05 2004 @@ -1365,6 +1365,7 @@ viotty_driver->driver_name = "vioconsole"; viotty_driver->devfs_name = "vcs/"; viotty_driver->name = "tty"; + viotty_driver->name_base = 1; viotty_driver->major = TTY_MAJOR; viotty_driver->minor_start = 1; viotty_driver->type = TTY_DRIVER_TYPE_CONSOLE; diff -Nru a/drivers/char/watchdog/advantechwdt.c b/drivers/char/watchdog/advantechwdt.c --- a/drivers/char/watchdog/advantechwdt.c Sun Mar 14 14:20:07 2004 +++ b/drivers/char/watchdog/advantechwdt.c Sun Mar 14 14:20:07 2004 @@ -256,8 +256,6 @@ static struct notifier_block advwdt_notifier = { .notifier_call = advwdt_notify_sys, - .next = NULL, - .priority = 0, }; static int __init diff -Nru a/drivers/char/watchdog/alim1535_wdt.c b/drivers/char/watchdog/alim1535_wdt.c --- a/drivers/char/watchdog/alim1535_wdt.c Sun Mar 14 14:20:06 2004 +++ b/drivers/char/watchdog/alim1535_wdt.c Sun Mar 14 14:20:06 2004 @@ -385,8 +385,6 @@ static struct notifier_block ali_notifier = { .notifier_call = ali_notify_sys, - .next = NULL, - .priority = 0, }; /* diff -Nru a/drivers/char/watchdog/alim7101_wdt.c b/drivers/char/watchdog/alim7101_wdt.c --- a/drivers/char/watchdog/alim7101_wdt.c Sun Mar 14 14:20:08 2004 +++ b/drivers/char/watchdog/alim7101_wdt.c Sun Mar 14 14:20:08 2004 @@ -303,8 +303,6 @@ static struct notifier_block wdt_notifier= { .notifier_call = wdt_notify_sys, - .next = 0, - .priority = 0, }; static void __exit alim7101_wdt_unload(void) diff -Nru a/drivers/char/watchdog/amd7xx_tco.c b/drivers/char/watchdog/amd7xx_tco.c --- a/drivers/char/watchdog/amd7xx_tco.c Sun Mar 14 14:20:06 2004 +++ b/drivers/char/watchdog/amd7xx_tco.c Sun Mar 14 14:20:06 2004 @@ -365,25 +365,6 @@ unregister_reboot_notifier(&amdtco_notifier); } - -#ifndef MODULE -static int __init amdtco_setup(char *str) -{ - int ints[4]; - - str = get_options (str, ARRAY_SIZE(ints), ints); - if (ints[0] > 0) - timeout = ints[1]; - - if (!timeout || timeout > MAX_TIMEOUT) - timeout = MAX_TIMEOUT; - - return 1; -} - -__setup("amd7xx_tco=", amdtco_setup); -#endif - module_init(amdtco_init); module_exit(amdtco_exit); diff -Nru a/drivers/char/watchdog/cpu5wdt.c b/drivers/char/watchdog/cpu5wdt.c --- a/drivers/char/watchdog/cpu5wdt.c Sun Mar 14 14:20:06 2004 +++ b/drivers/char/watchdog/cpu5wdt.c Sun Mar 14 14:20:06 2004 @@ -20,6 +20,7 @@ */ #include +#include #include #include #include @@ -295,11 +296,11 @@ MODULE_LICENSE("GPL"); MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); -MODULE_PARM(port, "i"); +module_param(port, int, 0); MODULE_PARM_DESC(port, "base address of watchdog card, default is 0x91"); -MODULE_PARM(verbose, "i"); +module_param(verbose, int, 0); MODULE_PARM_DESC(verbose, "be verbose, default is 0 (no)"); -MODULE_PARM(ticks, "i"); +module_param(ticks, int, 0); MODULE_PARM_DESC(ticks, "count down ticks, default is 10000"); diff -Nru a/drivers/char/watchdog/eurotechwdt.c b/drivers/char/watchdog/eurotechwdt.c --- a/drivers/char/watchdog/eurotechwdt.c Sun Mar 14 14:20:06 2004 +++ b/drivers/char/watchdog/eurotechwdt.c Sun Mar 14 14:20:06 2004 @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -77,7 +78,7 @@ static int nowayout = 0; #endif -MODULE_PARM(nowayout,"i"); +module_param(nowayout, int, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); /* @@ -94,41 +95,11 @@ #define WDT_TIMER_CFG 0xf3 -#ifndef MODULE - -/** - * eurwdt_setup: - * @str: command line string - * - * Setup options. The board isn't really probe-able so we have to - * get the user to tell us the configuration. Sane people build it - * modular but the others come here. - */ - -static int __init eurwdt_setup(char *str) -{ - int ints[4]; - -str = get_options (str, ARRAY_SIZE(ints), ints); - - if (ints[0] > 0) { - io = ints[1]; - if (ints[0] > 1) - irq = ints[2]; - } - - return 1; -} - -__setup("eurwdt=", eurwdt_setup); - -#endif /* !MODULE */ - -MODULE_PARM(io, "i"); +module_param(io, int, 0); MODULE_PARM_DESC(io, "Eurotech WDT io port (default=0x3f0)"); -MODULE_PARM(irq, "i"); +module_param(irq, int, 0); MODULE_PARM_DESC(irq, "Eurotech WDT irq (default=10)"); -MODULE_PARM(ev, "s"); +module_param(ev, charp, 0); MODULE_PARM_DESC(ev, "Eurotech WDT event type (default is `int')"); diff -Nru a/drivers/char/watchdog/ib700wdt.c b/drivers/char/watchdog/ib700wdt.c --- a/drivers/char/watchdog/ib700wdt.c Sun Mar 14 14:20:08 2004 +++ b/drivers/char/watchdog/ib700wdt.c Sun Mar 14 14:20:08 2004 @@ -284,8 +284,6 @@ static struct notifier_block ibwdt_notifier = { .notifier_call = ibwdt_notify_sys, - .next = NULL, - .priority = 0, }; static int __init ibwdt_init(void) diff -Nru a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c --- a/drivers/char/watchdog/machzwd.c Sun Mar 14 14:20:06 2004 +++ b/drivers/char/watchdog/machzwd.c Sun Mar 14 14:20:06 2004 @@ -447,8 +447,6 @@ */ static struct notifier_block zf_notifier = { .notifier_call = zf_notify_sys, - .next = NULL, - .priority = 0, }; static void __init zf_show_action(int act) diff -Nru a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c --- a/drivers/char/watchdog/pcwd_pci.c Sun Mar 14 14:20:06 2004 +++ b/drivers/char/watchdog/pcwd_pci.c Sun Mar 14 14:20:06 2004 @@ -49,7 +49,7 @@ /* Module and version information */ #define WATCHDOG_VERSION "1.00" -#define WATCHDOG_DATE "09/02/2004" +#define WATCHDOG_DATE "13/03/2004" #define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog" #define WATCHDOG_NAME "pcwd_pci" #define PFX WATCHDOG_NAME ": " @@ -82,6 +82,9 @@ #define CMD_READ_WATCHDOG_TIMEOUT 0x18 #define CMD_WRITE_WATCHDOG_TIMEOUT 0x19 +/* We can only use 1 card due to the /dev/watchdog restriction */ +static int cards_found; + /* internal variables */ static int temp_panic; static unsigned long is_active; @@ -505,7 +508,6 @@ static int __devinit pcipcwd_card_init(struct pci_dev *pdev, const struct pci_device_id *ent) { - static int cards_found; int ret = -EIO; int got_fw_rev, fw_rev_major, fw_rev_minor; char fw_ver_str[20]; @@ -527,7 +529,8 @@ if (pci_resource_start(pdev, 0) == 0x0000) { printk(KERN_ERR PFX "No I/O-Address for card detected\n"); - return -ENODEV; + ret = -ENODEV; + goto err_out_disable_device; } pcipcwd_private.pdev = pdev; @@ -643,6 +646,7 @@ unregister_reboot_notifier(&pcipcwd_notifier); pci_release_regions(pdev); pci_disable_device(pdev); + cards_found--; } static struct pci_device_id pcipcwd_pci_tbl[] = { diff -Nru a/drivers/char/watchdog/sbc60xxwdt.c b/drivers/char/watchdog/sbc60xxwdt.c --- a/drivers/char/watchdog/sbc60xxwdt.c Sun Mar 14 14:20:07 2004 +++ b/drivers/char/watchdog/sbc60xxwdt.c Sun Mar 14 14:20:07 2004 @@ -322,8 +322,6 @@ static struct notifier_block wdt_notifier= { .notifier_call = wdt_notify_sys, - .next = NULL, - .priority = 0, }; static void __exit sbc60xxwdt_unload(void) diff -Nru a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c --- a/drivers/char/watchdog/sc1200wdt.c Sun Mar 14 14:20:06 2004 +++ b/drivers/char/watchdog/sc1200wdt.c Sun Mar 14 14:20:06 2004 @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -80,13 +81,13 @@ static int isapnp = 1; static struct pnp_dev *wdt_dev; -MODULE_PARM(isapnp, "i"); +module_param(isapnp, int, 0); MODULE_PARM_DESC(isapnp, "When set to 0 driver ISA PnP support will be disabled"); #endif -MODULE_PARM(io, "i"); +module_param(io, int, 0); MODULE_PARM_DESC(io, "io port"); -MODULE_PARM(timeout, "i"); +module_param(timeout, int, 0); MODULE_PARM_DESC(timeout, "range is 0-255 minutes, default is 1"); #ifdef CONFIG_WATCHDOG_NOWAYOUT @@ -95,7 +96,7 @@ static int nowayout = 0; #endif -MODULE_PARM(nowayout,"i"); +module_param(nowayout, int, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); @@ -453,32 +454,6 @@ #endif release_region(io, io_len); } - - -#ifndef MODULE -static int __init sc1200wdt_setup(char *str) -{ - int ints[4]; - - str = get_options (str, ARRAY_SIZE(ints), ints); - - if (ints[0] > 0) { - io = ints[1]; - if (ints[0] > 1) - timeout = ints[2]; - -#if defined CONFIG_PNP - if (ints[0] > 2) - isapnp = ints[3]; -#endif - } - - return 1; -} - -__setup("sc1200wdt=", sc1200wdt_setup); -#endif /* MODULE */ - module_init(sc1200wdt_init); module_exit(sc1200wdt_exit); diff -Nru a/drivers/char/watchdog/sc520_wdt.c b/drivers/char/watchdog/sc520_wdt.c --- a/drivers/char/watchdog/sc520_wdt.c Sun Mar 14 14:20:07 2004 +++ b/drivers/char/watchdog/sc520_wdt.c Sun Mar 14 14:20:07 2004 @@ -354,8 +354,6 @@ static struct notifier_block wdt_notifier= { .notifier_call = wdt_notify_sys, - .next = NULL, - .priority = 0, }; static void __exit sc520_wdt_unload(void) diff -Nru a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c --- a/drivers/char/watchdog/w83627hf_wdt.c Sun Mar 14 14:20:07 2004 +++ b/drivers/char/watchdog/w83627hf_wdt.c Sun Mar 14 14:20:07 2004 @@ -257,8 +257,6 @@ static struct notifier_block wdt_notifier = { .notifier_call = wdt_notify_sys, - .next = NULL, - .priority = 0, }; static int __init diff -Nru a/drivers/char/watchdog/w83877f_wdt.c b/drivers/char/watchdog/w83877f_wdt.c --- a/drivers/char/watchdog/w83877f_wdt.c Sun Mar 14 14:20:07 2004 +++ b/drivers/char/watchdog/w83877f_wdt.c Sun Mar 14 14:20:07 2004 @@ -341,8 +341,6 @@ static struct notifier_block wdt_notifier= { .notifier_call = wdt_notify_sys, - .next = NULL, - .priority = 0, }; static void __exit w83877f_wdt_unload(void) diff -Nru a/drivers/char/watchdog/wafer5823wdt.c b/drivers/char/watchdog/wafer5823wdt.c --- a/drivers/char/watchdog/wafer5823wdt.c Sun Mar 14 14:20:08 2004 +++ b/drivers/char/watchdog/wafer5823wdt.c Sun Mar 14 14:20:08 2004 @@ -252,8 +252,6 @@ static struct notifier_block wafwdt_notifier = { .notifier_call = wafwdt_notify_sys, - .next = NULL, - .priority = 0, }; static int __init wafwdt_init(void) diff -Nru a/drivers/char/watchdog/wdt.c b/drivers/char/watchdog/wdt.c --- a/drivers/char/watchdog/wdt.c Sun Mar 14 14:20:07 2004 +++ b/drivers/char/watchdog/wdt.c Sun Mar 14 14:20:07 2004 @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -70,43 +71,12 @@ static int nowayout = 0; #endif -MODULE_PARM(nowayout,"i"); +module_param(nowayout, int, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); -#ifndef MODULE - -/** - * wdt_setup: - * @str: command line string - * - * Setup options. The board isn't really probe-able so we have to - * get the user to tell us the configuration. Sane people build it - * modular but the others come here. - */ - -static int __init wdt_setup(char *str) -{ - int ints[4]; - - str = get_options (str, ARRAY_SIZE(ints), ints); - - if (ints[0] > 0) - { - io = ints[1]; - if(ints[0] > 1) - irq = ints[2]; - } - - return 1; -} - -__setup("wdt=", wdt_setup); - -#endif /* !MODULE */ - -MODULE_PARM(io, "i"); +module_param(io, int, 0); MODULE_PARM_DESC(io, "WDT io port (default=0x240)"); -MODULE_PARM(irq, "i"); +module_param(irq, int, 0); MODULE_PARM_DESC(irq, "WDT irq (default=11)"); /* @@ -489,8 +459,6 @@ static struct notifier_block wdt_notifier= { .notifier_call = wdt_notify_sys, - .next = NULL, - .priority = 0, }; /** diff -Nru a/drivers/char/watchdog/wdt977.c b/drivers/char/watchdog/wdt977.c --- a/drivers/char/watchdog/wdt977.c Sun Mar 14 14:20:08 2004 +++ b/drivers/char/watchdog/wdt977.c Sun Mar 14 14:20:08 2004 @@ -1,5 +1,5 @@ /* - * Wdt977 0.02: A Watchdog Device for Netwinder W83977AF chip + * Wdt977 0.03: A Watchdog Device for Netwinder W83977AF chip * * (c) Copyright 1998 Rebel.com (Woody Suwalski ) * @@ -29,24 +29,27 @@ #include #include #include +#include +#include #include #include #include #include +#define PFX "Wdt977: " #define WATCHDOG_MINOR 130 -#define DEFAULT_TIMEOUT 1 /* default timeout = 1 minute */ +#define DEFAULT_TIMEOUT 60 /* default timeout in seconds */ -static int timeout = DEFAULT_TIMEOUT*60; /* TO in seconds from user */ -static int timeoutM = DEFAULT_TIMEOUT; /* timeout in minutes */ +static int timeout = DEFAULT_TIMEOUT; +static int timeoutM; /* timeout in minutes */ static unsigned long timer_alive; static int testmode; static char expect_close; module_param(timeout, int, 0); -MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (60..15300), default=60"); +MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (60..15300), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")"); module_param(testmode, int, 0); MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0"); @@ -59,21 +62,102 @@ module_param(nowayout, int, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); +/* + * Start the watchdog + */ -/* This is kicking the watchdog by simply re-writing the timeout to reg. 0xF2 */ -static int kick_wdog(void) +static int wdt977_start(void) { - /* - * Refresh the timer. + /* unlock the SuperIO chip */ + outb(0x87,0x370); + outb(0x87,0x370); + + /* select device Aux2 (device=8) and set watchdog regs F2, F3 and F4 + * F2 has the timeout in minutes + * F3 could be set to the POWER LED blink (with GP17 set to PowerLed) + * at timeout, and to reset timer on kbd/mouse activity (not impl.) + * F4 is used to just clear the TIMEOUT'ed state (bit 0) */ + outb(0x07,0x370); + outb(0x08,0x371); + outb(0xF2,0x370); + outb(timeoutM,0x371); + outb(0xF3,0x370); + outb(0x00,0x371); /* another setting is 0E for kbd/mouse/LED */ + outb(0xF4,0x370); + outb(0x00,0x371); + + /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */ + /* in test mode watch the bit 1 on F4 to indicate "triggered" */ + if (!testmode) + { + outb(0x07,0x370); + outb(0x07,0x371); + outb(0xE6,0x370); + outb(0x08,0x371); + } + /* lock the SuperIO chip */ + outb(0xAA,0x370); + + printk(KERN_INFO PFX "activated.\n"); + + return 0; +} + +/* + * Stop the watchdog + */ + +static int wdt977_stop(void) +{ + /* unlock the SuperIO chip */ + outb(0x87,0x370); + outb(0x87,0x370); + + /* select device Aux2 (device=8) and set watchdog regs F2,F3 and F4 + * F3 is reset to its default state + * F4 can clear the TIMEOUT'ed state (bit 0) - back to default + * We can not use GP17 as a PowerLed, as we use its usage as a RedLed + */ + outb(0x07,0x370); + outb(0x08,0x371); + outb(0xF2,0x370); + outb(0xFF,0x371); + outb(0xF3,0x370); + outb(0x00,0x371); + outb(0xF4,0x370); + outb(0x00,0x371); + outb(0xF2,0x370); + outb(0x00,0x371); + + /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */ + outb(0x07,0x370); + outb(0x07,0x371); + outb(0xE6,0x370); + outb(0x08,0x371); + + /* lock the SuperIO chip */ + outb(0xAA,0x370); + + printk(KERN_INFO PFX "shutdown.\n"); + + return 0; +} + +/* + * Send a keepalive ping to the watchdog + * This is done by simply re-writing the timeout to reg. 0xF2 + */ + +static int wdt977_keepalive(void) +{ /* unlock the SuperIO chip */ outb(0x87,0x370); outb(0x87,0x370); /* select device Aux2 (device=8) and kicks watchdog reg F2 */ /* F2 has the timeout in minutes */ - outb(0x07,0x370); outb(0x08,0x371); outb(0xF2,0x370); @@ -85,77 +169,77 @@ return 0; } - /* - * Allow only one person to hold it open + * Set the watchdog timeout value */ -static int wdt977_open(struct inode *inode, struct file *file) +static int wdt977_set_timeout(int t) { - - if( test_and_set_bit(0,&timer_alive) ) - return -EBUSY; + int tmrval; /* convert seconds to minutes, rounding up */ - timeoutM = timeout + 59; - timeoutM /= 60; - - if (nowayout) - { - __module_get(THIS_MODULE); + tmrval = (t + 59) / 60; - /* do not permit disabling the watchdog by writing 0 to reg. 0xF2 */ - if (!timeoutM) timeoutM = DEFAULT_TIMEOUT; - } - - if (machine_is_netwinder()) - { + if (machine_is_netwinder()) { /* we have a hw bug somewhere, so each 977 minute is actually only 30sec * this limits the max timeout to half of device max of 255 minutes... */ - timeoutM += timeoutM; + tmrval += tmrval; } - /* max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog. */ - if (timeoutM > 255) timeoutM = 255; + if ((tmrval < 1) || (tmrval > 255)) + return -EINVAL; - /* convert seconds to minutes */ - printk(KERN_INFO "Wdt977 Watchdog activated: timeout = %d sec, nowayout = %i, testmode = %i.\n", - machine_is_netwinder() ? (timeoutM>>1)*60 : timeoutM*60, - nowayout, testmode); + /* timeout is the timeout in seconds, timeoutM is the timeout in minutes) */ + timeout = t; + timeoutM = tmrval; + return 0; +} + +/* + * Get the watchdog status + */ + +static int wdt977_get_status(int *status) +{ + int new_status; + + *status=0; /* unlock the SuperIO chip */ outb(0x87,0x370); outb(0x87,0x370); - /* select device Aux2 (device=8) and set watchdog regs F2, F3 and F4 - * F2 has the timeout in minutes - * F3 could be set to the POWER LED blink (with GP17 set to PowerLed) - * at timeout, and to reset timer on kbd/mouse activity (not impl.) - * F4 is used to just clear the TIMEOUT'ed state (bit 0) - */ + /* select device Aux2 (device=8) and read watchdog reg F4 */ outb(0x07,0x370); outb(0x08,0x371); - outb(0xF2,0x370); - outb(timeoutM,0x371); - outb(0xF3,0x370); - outb(0x00,0x371); /* another setting is 0E for kbd/mouse/LED */ outb(0xF4,0x370); - outb(0x00,0x371); - - /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */ - /* in test mode watch the bit 1 on F4 to indicate "triggered" */ - if (!testmode) - { - outb(0x07,0x370); - outb(0x07,0x371); - outb(0xE6,0x370); - outb(0x08,0x371); - } + new_status = inb(0x371); /* lock the SuperIO chip */ outb(0xAA,0x370); + if (new_status & 1) + *status |= WDIOF_CARDRESET; + + return 0; +} + + +/* + * /dev/watchdog handling + */ + +static int wdt977_open(struct inode *inode, struct file *file) +{ + /* If the watchdog is alive we don't need to start it again */ + if( test_and_set_bit(0,&timer_alive) ) + return -EBUSY; + + if (nowayout) + __module_get(THIS_MODULE); + + wdt977_start(); return 0; } @@ -167,40 +251,11 @@ */ if (expect_close == 42) { - /* unlock the SuperIO chip */ - outb(0x87,0x370); - outb(0x87,0x370); - - /* select device Aux2 (device=8) and set watchdog regs F2,F3 and F4 - * F3 is reset to its default state - * F4 can clear the TIMEOUT'ed state (bit 0) - back to default - * We can not use GP17 as a PowerLed, as we use its usage as a RedLed - */ - outb(0x07,0x370); - outb(0x08,0x371); - outb(0xF2,0x370); - outb(0xFF,0x371); - outb(0xF3,0x370); - outb(0x00,0x371); - outb(0xF4,0x370); - outb(0x00,0x371); - outb(0xF2,0x370); - outb(0x00,0x371); - - /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */ - outb(0x07,0x370); - outb(0x07,0x371); - outb(0xE6,0x370); - outb(0x08,0x371); - - /* lock the SuperIO chip */ - outb(0xAA,0x370); - + wdt977_stop(); clear_bit(0,&timer_alive); - - printk(KERN_INFO "Wdt977 Watchdog: shutdown\n"); } else { - printk(KERN_CRIT "WDT device closed unexpectedly. WDT will not stop!\n"); + printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); + wdt977_keepalive(); } expect_close = 0; return 0; @@ -240,7 +295,7 @@ } } - kick_wdog(); + wdt977_keepalive(); } return count; } @@ -257,14 +312,19 @@ */ static struct watchdog_info ident = { - .options = WDIOF_SETTIMEOUT, - .identity = "Winbond 83977", + .options = WDIOF_SETTIMEOUT | + WDIOF_MAGICCLOSE | + WDIOF_KEEPALIVEPING, + .firmware_version = 1, + .identity = "Winbond 83977", }; static int wdt977_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - int temp; + int status; + int new_options, retval = -EINVAL; + int new_timeout; switch(cmd) { @@ -272,62 +332,59 @@ return -ENOIOCTLCMD; case WDIOC_GETSUPPORT: - return copy_to_user((struct watchdog_info *)arg, &ident, + return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)) ? -EFAULT : 0; + case WDIOC_GETSTATUS: + wdt977_get_status(&status); + return put_user(status, (int *) arg); + case WDIOC_GETBOOTSTATUS: return put_user(0, (int *) arg); - case WDIOC_GETSTATUS: - /* unlock the SuperIO chip */ - outb(0x87,0x370); - outb(0x87,0x370); + case WDIOC_KEEPALIVE: + wdt977_keepalive(); + return 0; - /* select device Aux2 (device=8) and read watchdog reg F4 */ - outb(0x07,0x370); - outb(0x08,0x371); - outb(0xF4,0x370); - temp = inb(0x371); + case WDIOC_SETOPTIONS: + if (get_user (new_options, (int *) arg)) + return -EFAULT; - /* lock the SuperIO chip */ - outb(0xAA,0x370); + if (new_options & WDIOS_DISABLECARD) { + wdt977_stop(); + retval = 0; + } - /* return info if "expired" in test mode */ - return put_user(temp & 1, (int *) arg); + if (new_options & WDIOS_ENABLECARD) { + wdt977_start(); + retval = 0; + } - case WDIOC_KEEPALIVE: - kick_wdog(); - return 0; + return retval; case WDIOC_SETTIMEOUT: - if (copy_from_user(&temp, (int *) arg, sizeof(int))) + if (get_user(new_timeout, (int *) arg)) return -EFAULT; - /* convert seconds to minutes, rounding up */ - temp += 59; - temp /= 60; - - /* we have a hw bug somewhere, so each 977 minute is actually only 30sec - * this limits the max timeout to half of device max of 255 minutes... - */ - if (machine_is_netwinder()) - { - temp += temp; - } + if (wdt977_set_timeout(new_timeout)) + return -EINVAL; - /* Sanity check */ - if (temp < 0 || temp > 255) - return -EINVAL; + wdt977_keepalive(); + /* Fall */ - if (!temp && nowayout) - return -EINVAL; + case WDIOC_GETTIMEOUT: + return put_user(timeout, (int *)arg); - timeoutM = temp; - kick_wdog(); - return 0; } } +static int wdt977_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if(code==SYS_DOWN || code==SYS_HALT) + wdt977_stop(); + return NOTIFY_DONE; +} static struct file_operations wdt977_fops= { @@ -345,21 +402,48 @@ .fops = &wdt977_fops, }; +static struct notifier_block wdt977_notifier = { + .notifier_call = wdt977_notify_sys, +}; + static int __init nwwatchdog_init(void) { int retval; if (!machine_is_netwinder()) return -ENODEV; + /* Check that the timeout value is within it's range ; if not reset to the default */ + if (wdt977_set_timeout(timeout)) { + wdt977_set_timeout(DEFAULT_TIMEOUT); + printk(KERN_INFO PFX "timeout value must be 60dev.parent = root->dev; edev->dev.bus = &eisa_bus_type; edev->dev.dma_mask = &edev->dma_mask; + edev->dev.coherent_dma_mask = edev->dma_mask; sprintf (edev->dev.bus_id, "%02X:%02X", root->bus_nr, slot); for (i = 0; i < EISA_MAX_RESOURCES; i++) { diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c --- a/drivers/ide/ide-cd.c Sun Mar 14 14:20:07 2004 +++ b/drivers/ide/ide-cd.c Sun Mar 14 14:20:07 2004 @@ -2931,6 +2931,7 @@ if (!CDROM_CONFIG_FLAGS(drive)->mrw_w) devinfo->mask |= CDC_MRW_W; + devinfo->disk = drive->disk; return register_cdrom(devinfo); } diff -Nru a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c --- a/drivers/ide/legacy/macide.c Sun Mar 14 14:20:05 2004 +++ b/drivers/ide/legacy/macide.c Sun Mar 14 14:20:05 2004 @@ -94,6 +94,7 @@ void macide_init(void) { hw_regs_t hw; + ide_hwif_t *hwif; int index = -1; switch (macintosh_config->ide_type) { @@ -102,21 +103,21 @@ 0, 0, macide_ack_intr, // quadra_ide_iops, IRQ_NUBUS_F); - index = ide_register_hw(&hw, NULL); + index = ide_register_hw(&hw, &hwif); break; case MAC_IDE_PB: ide_setup_ports(&hw, IDE_BASE, macide_offsets, 0, 0, macide_ack_intr, // macide_pb_iops, IRQ_NUBUS_C); - index = ide_register_hw(&hw, NULL); + index = ide_register_hw(&hw, &hwif); break; case MAC_IDE_BABOON: ide_setup_ports(&hw, BABOON_BASE, macide_offsets, 0, 0, NULL, // macide_baboon_iops, IRQ_BABOON_1); - index = ide_register_hw(&hw, NULL); + index = ide_register_hw(&hw, &hwif); if (index == -1) break; if (macintosh_config->ident == MAC_MODEL_PB190) { @@ -141,6 +142,7 @@ } if (index != -1) { + hwif->mmio = 2; if (macintosh_config->ide_type == MAC_IDE_QUADRA) printk(KERN_INFO "ide%d: Macintosh Quadra IDE interface\n", index); else if (macintosh_config->ide_type == MAC_IDE_PB) diff -Nru a/drivers/ieee1394/dma.c b/drivers/ieee1394/dma.c --- a/drivers/ieee1394/dma.c Sun Mar 14 14:20:07 2004 +++ b/drivers/ieee1394/dma.c Sun Mar 14 14:20:07 2004 @@ -168,7 +168,7 @@ return sg_dma_address(sg) + rem; } -void dma_region_sync(struct dma_region *dma, unsigned long offset, unsigned long len) +void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset, unsigned long len) { int first, last; unsigned long rem; @@ -179,7 +179,21 @@ first = dma_region_find(dma, offset, &rem); last = dma_region_find(dma, offset + len - 1, &rem); - pci_dma_sync_sg(dma->dev, &dma->sglist[first], last - first + 1, dma->direction); + pci_dma_sync_sg_for_cpu(dma->dev, &dma->sglist[first], last - first + 1, dma->direction); +} + +void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset, unsigned long len) +{ + int first, last; + unsigned long rem; + + if (!len) + len = 1; + + first = dma_region_find(dma, offset, &rem); + last = dma_region_find(dma, offset + len - 1, &rem); + + pci_dma_sync_sg_for_device(dma->dev, &dma->sglist[first], last - first + 1, dma->direction); } /* nopage() handler for mmap access */ diff -Nru a/drivers/ieee1394/dma.h b/drivers/ieee1394/dma.h --- a/drivers/ieee1394/dma.h Sun Mar 14 14:20:08 2004 +++ b/drivers/ieee1394/dma.h Sun Mar 14 14:20:08 2004 @@ -60,8 +60,10 @@ /* unmap and free the buffer */ void dma_region_free(struct dma_region *dma); -/* sync the IO bus' view of the buffer with the CPU's view */ -void dma_region_sync(struct dma_region *dma, unsigned long offset, unsigned long len); +/* sync the CPU's view of the buffer */ +void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset, unsigned long len); +/* sync the IO bus' view of the buffer */ +void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset, unsigned long len); /* map the buffer into a user space process */ int dma_region_mmap(struct dma_region *dma, struct file *file, struct vm_area_struct *vma); diff -Nru a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c --- a/drivers/ieee1394/dv1394.c Sun Mar 14 14:20:08 2004 +++ b/drivers/ieee1394/dv1394.c Sun Mar 14 14:20:08 2004 @@ -553,7 +553,7 @@ *(f->frame_end_branch) = cpu_to_le32(f->descriptor_pool_dma | f->first_n_descriptors); /* make the latest version of this frame visible to the PCI card */ - dma_region_sync(&video->dv_buf, f->data - (unsigned long) video->dv_buf.kvirt, video->frame_size); + dma_region_sync_for_device(&video->dv_buf, f->data - (unsigned long) video->dv_buf.kvirt, video->frame_size); /* lock against DMA interrupt */ spin_lock_irqsave(&video->spinlock, irq_flags); @@ -2033,9 +2033,9 @@ struct packet *p = dma_region_i(&video->packet_buf, struct packet, video->current_packet); /* make sure we are seeing the latest changes to p */ - dma_region_sync(&video->packet_buf, - (unsigned long) p - (unsigned long) video->packet_buf.kvirt, - sizeof(struct packet)); + dma_region_sync_for_cpu(&video->packet_buf, + (unsigned long) p - (unsigned long) video->packet_buf.kvirt, + sizeof(struct packet)); packet_length = le16_to_cpu(p->data_length); packet_time = le16_to_cpu(p->timestamp); diff -Nru a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c --- a/drivers/ieee1394/ieee1394_core.c Sun Mar 14 14:20:06 2004 +++ b/drivers/ieee1394/ieee1394_core.c Sun Mar 14 14:20:06 2004 @@ -1201,7 +1201,8 @@ EXPORT_SYMBOL(dma_region_init); EXPORT_SYMBOL(dma_region_alloc); EXPORT_SYMBOL(dma_region_free); -EXPORT_SYMBOL(dma_region_sync); +EXPORT_SYMBOL(dma_region_sync_for_cpu); +EXPORT_SYMBOL(dma_region_sync_for_device); EXPORT_SYMBOL(dma_region_mmap); EXPORT_SYMBOL(dma_region_offset_to_bus); diff -Nru a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c --- a/drivers/ieee1394/ohci1394.c Sun Mar 14 14:20:08 2004 +++ b/drivers/ieee1394/ohci1394.c Sun Mar 14 14:20:08 2004 @@ -1732,7 +1732,7 @@ /* OK, the block is finished... */ /* sync our view of the block */ - dma_region_sync(&iso->data_buf, recv->block_dma*recv->buf_stride, recv->buf_stride); + dma_region_sync_for_cpu(&iso->data_buf, recv->block_dma*recv->buf_stride, recv->buf_stride); /* reset the DMA descriptor */ im->status = recv->buf_stride; @@ -1789,7 +1789,7 @@ } /* sync our view of the buffer */ - dma_region_sync(&iso->data_buf, iso->pkt_dma * recv->buf_stride, recv->buf_stride); + dma_region_sync_for_cpu(&iso->data_buf, iso->pkt_dma * recv->buf_stride, recv->buf_stride); /* record the per-packet info */ { @@ -2016,7 +2016,7 @@ sy = info->sy; /* sync up the card's view of the buffer */ - dma_region_sync(&iso->data_buf, offset, len); + dma_region_sync_for_device(&iso->data_buf, offset, len); /* append first_packet to the DMA chain */ /* by linking the previous descriptor to it */ diff -Nru a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c --- a/drivers/ieee1394/sbp2.c Sun Mar 14 14:20:06 2004 +++ b/drivers/ieee1394/sbp2.c Sun Mar 14 14:20:06 2004 @@ -1948,12 +1948,12 @@ SBP2_ORB_DEBUG("sending command orb %p, total orbs = %x", command_orb, global_outstanding_command_orbs); - pci_dma_sync_single(hi->host->pdev, command->command_orb_dma, - sizeof(struct sbp2_command_orb), - PCI_DMA_BIDIRECTIONAL); - pci_dma_sync_single(hi->host->pdev, command->sge_dma, - sizeof(command->scatter_gather_element), - PCI_DMA_BIDIRECTIONAL); + pci_dma_sync_single_for_device(hi->host->pdev, command->command_orb_dma, + sizeof(struct sbp2_command_orb), + PCI_DMA_BIDIRECTIONAL); + pci_dma_sync_single_for_device(hi->host->pdev, command->sge_dma, + sizeof(command->scatter_gather_element), + PCI_DMA_BIDIRECTIONAL); /* * Check to see if there are any previous orbs to use */ @@ -1994,9 +1994,9 @@ cpu_to_be32(command->command_orb_dma); /* Tells hardware that this pointer is valid */ scsi_id->last_orb->next_ORB_hi = 0x0; - pci_dma_sync_single(hi->host->pdev, scsi_id->last_orb_dma, - sizeof(struct sbp2_command_orb), - PCI_DMA_BIDIRECTIONAL); + pci_dma_sync_single_for_device(hi->host->pdev, scsi_id->last_orb_dma, + sizeof(struct sbp2_command_orb), + PCI_DMA_BIDIRECTIONAL); /* * Ring the doorbell @@ -2358,12 +2358,12 @@ if (command) { SBP2_DEBUG("Found status for command ORB"); - pci_dma_sync_single(hi->host->pdev, command->command_orb_dma, - sizeof(struct sbp2_command_orb), - PCI_DMA_BIDIRECTIONAL); - pci_dma_sync_single(hi->host->pdev, command->sge_dma, - sizeof(command->scatter_gather_element), - PCI_DMA_BIDIRECTIONAL); + pci_dma_sync_single_for_cpu(hi->host->pdev, command->command_orb_dma, + sizeof(struct sbp2_command_orb), + PCI_DMA_BIDIRECTIONAL); + pci_dma_sync_single_for_cpu(hi->host->pdev, command->sge_dma, + sizeof(command->scatter_gather_element), + PCI_DMA_BIDIRECTIONAL); SBP2_ORB_DEBUG("matched command orb %p", &command->command_orb); outstanding_orb_decr; @@ -2534,12 +2534,12 @@ SBP2_DEBUG("Found pending command to complete"); lh = scsi_id->sbp2_command_orb_inuse.next; command = list_entry(lh, struct sbp2_command_info, list); - pci_dma_sync_single(hi->host->pdev, command->command_orb_dma, - sizeof(struct sbp2_command_orb), - PCI_DMA_BIDIRECTIONAL); - pci_dma_sync_single(hi->host->pdev, command->sge_dma, - sizeof(command->scatter_gather_element), - PCI_DMA_BIDIRECTIONAL); + pci_dma_sync_single_for_cpu(hi->host->pdev, command->command_orb_dma, + sizeof(struct sbp2_command_orb), + PCI_DMA_BIDIRECTIONAL); + pci_dma_sync_single_for_cpu(hi->host->pdev, command->sge_dma, + sizeof(command->scatter_gather_element), + PCI_DMA_BIDIRECTIONAL); sbp2util_mark_command_completed(scsi_id, command); if (command->Current_SCpnt) { void (*done)(Scsi_Cmnd *) = command->Current_done; @@ -2699,14 +2699,14 @@ command = sbp2util_find_command_for_SCpnt(scsi_id, SCpnt); if (command) { SBP2_DEBUG("Found command to abort"); - pci_dma_sync_single(hi->host->pdev, - command->command_orb_dma, - sizeof(struct sbp2_command_orb), - PCI_DMA_BIDIRECTIONAL); - pci_dma_sync_single(hi->host->pdev, - command->sge_dma, - sizeof(command->scatter_gather_element), - PCI_DMA_BIDIRECTIONAL); + pci_dma_sync_single_for_cpu(hi->host->pdev, + command->command_orb_dma, + sizeof(struct sbp2_command_orb), + PCI_DMA_BIDIRECTIONAL); + pci_dma_sync_single_for_cpu(hi->host->pdev, + command->sge_dma, + sizeof(command->scatter_gather_element), + PCI_DMA_BIDIRECTIONAL); sbp2util_mark_command_completed(scsi_id, command); if (command->Current_SCpnt) { void (*done)(Scsi_Cmnd *) = command->Current_done; diff -Nru a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig --- a/drivers/macintosh/Kconfig Sun Mar 14 14:20:07 2004 +++ b/drivers/macintosh/Kconfig Sun Mar 14 14:20:07 2004 @@ -1,5 +1,6 @@ menu "Macintosh device drivers" + depends on PPC || MAC config ADB bool "Apple Desktop Bus (ADB) support" diff -Nru a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c --- a/drivers/macintosh/mediabay.c Sun Mar 14 14:20:06 2004 +++ b/drivers/macintosh/mediabay.c Sun Mar 14 14:20:06 2004 @@ -10,8 +10,6 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ -#define __KERNEL_SYSCALLS__ - #include #include #include @@ -21,7 +19,6 @@ #include #include #include -#include #include #include #include diff -Nru a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c --- a/drivers/macintosh/therm_pm72.c Sun Mar 14 14:20:08 2004 +++ b/drivers/macintosh/therm_pm72.c Sun Mar 14 14:20:08 2004 @@ -2,7 +2,7 @@ * Device driver for the thermostats & fan controller of the * Apple G5 "PowerMac7,2" desktop machines. * - * (c) Copyright IBM Corp. 2003 + * (c) Copyright IBM Corp. 2003-2004 * * Maintained by: Benjamin Herrenschmidt * @@ -45,7 +45,7 @@ * - Add things like /sbin/overtemp for non-critical * overtemp conditions so userland can take some policy * decisions, like slewing down CPUs - * - Deal with fan failures + * - Deal with fan and i2c failures in a better way * * History: * @@ -63,9 +63,16 @@ * - Move back statics definitions to .c file * - Avoid calling schedule_timeout with a negative number * - * Dev. 18, 2003 : 0.8 + * Dec. 18, 2003 : 0.8 * - Fix typo when reading back fan speed on 2 CPU machines * + * Mar. 11, 2004 : 0.9 + * - Rework code accessing the ADC chips, make it more robust and + * closer to the chip spec. Also make sure it is configured properly, + * I've seen yet unexplained cases where on startup, I would have stale + * values in the configuration register + * - Switch back to use of target fan speed for PID, thus lowering + * pressure on i2c */ #include @@ -94,14 +101,14 @@ #include "therm_pm72.h" -#define VERSION "0.8" +#define VERSION "0.9" #undef DEBUG #ifdef DEBUG #define DBG(args...) printk(args) #else -#define DBG(args...) +#define DBG(args...) do { } while(0) #endif @@ -194,14 +201,76 @@ /* * Here are the i2c chip access wrappers */ -static int read_smon_adc(struct i2c_client *chip, int chan) + +static void initialize_adc(struct cpu_pid_state *state) +{ + int rc; + u8 buf[2]; + + /* Read ADC the configuration register and cache it. We + * also make sure Config2 contains proper values, I've seen + * cases where we got stale grabage in there, thus preventing + * proper reading of conv. values + */ + + /* Clear Config2 */ + buf[0] = 5; + buf[1] = 0; + i2c_master_send(state->monitor, buf, 2); + + /* Read & cache Config1 */ + buf[0] = 1; + rc = i2c_master_send(state->monitor, buf, 1); + if (rc > 0) { + rc = i2c_master_recv(state->monitor, buf, 1); + if (rc > 0) { + state->adc_config = buf[0]; + DBG("ADC config reg: %02x\n", state->adc_config); + /* Disable shutdown mode */ + state->adc_config &= 0xfe; + buf[0] = 1; + buf[1] = state->adc_config; + rc = i2c_master_send(state->monitor, buf, 2); + } + } + if (rc <= 0) + printk(KERN_ERR "therm_pm72: Error reading ADC config" + " register !\n"); +} + +static int read_smon_adc(struct cpu_pid_state *state, int chan) { - int ctrl; + int rc, data, tries = 0; + u8 buf[2]; - ctrl = i2c_smbus_read_byte_data(chip, 1); - i2c_smbus_write_byte_data(chip, 1, (ctrl & 0x1f) | (chan << 5)); - wait_ms(1); - return le16_to_cpu(i2c_smbus_read_word_data(chip, 4)) >> 6; + for (;;) { + /* Set channel */ + buf[0] = 1; + buf[1] = (state->adc_config & 0x1f) | (chan << 5); + rc = i2c_master_send(state->monitor, buf, 2); + if (rc <= 0) + goto error; + /* Wait for convertion */ + wait_ms(1); + /* Switch to data register */ + buf[0] = 4; + rc = i2c_master_send(state->monitor, buf, 1); + if (rc <= 0) + goto error; + /* Read result */ + rc = i2c_master_recv(state->monitor, buf, 2); + if (rc < 0) + goto error; + data = ((u16)buf[0]) << 8 | (u16)buf[1]; + return data >> 6; + error: + DBG("Error reading ADC, retrying...\n"); + if (++tries > 10) { + printk(KERN_ERR "therm_pm72: Error reading ADC !\n"); + return -1; + } + wait_ms(10); + } } static int fan_read_reg(int reg, unsigned char *buf, int nb) @@ -460,9 +529,13 @@ DBG(" current rpm: %d\n", state->rpm); /* Get some sensor readings and scale it */ - temp = read_smon_adc(state->monitor, 1); - voltage = read_smon_adc(state->monitor, 3); - current_a = read_smon_adc(state->monitor, 4); + temp = read_smon_adc(state, 1); + if (temp == -1) { + state->overtemp++; + return; + } + voltage = read_smon_adc(state, 3); + current_a = read_smon_adc(state, 4); /* Fixup temperature according to diode calibration */ @@ -476,7 +549,8 @@ * full blown immediately and try to trigger a shutdown */ if (temp >= ((state->mpu.tmax + 8) << 16)) { - printk(KERN_WARNING "Warning ! CPU %d temperature way above maximum (%d) !\n", + printk(KERN_WARNING "Warning ! CPU %d temperature way above maximum" + " (%d) !\n", state->index, temp >> 16); state->overtemp = CPU_MAX_OVERTEMP; } else if (temp > (state->mpu.tmax << 16)) @@ -613,6 +687,7 @@ state->first = 1; state->rpm = 1000; state->overtemp = 0; + state->adc_config = 0x00; if (index == 0) state->monitor = attach_i2c_chip(SUPPLY_MONITOR_ID, "CPU0_monitor"); @@ -941,8 +1016,17 @@ DBG("main_control_loop started\n"); + down(&driver_lock); + /* Set the PCI fan once for now */ set_pwm_fan(SLOTS_FAN_PWM_ID, SLOTS_FAN_DEFAULT_PWM); + + /* Initialize ADCs */ + initialize_adc(&cpu_state[0]); + if (cpu_state[1].monitor != NULL) + initialize_adc(&cpu_state[1]); + + up(&driver_lock); while (state == state_attached) { unsigned long elapsed, start; diff -Nru a/drivers/macintosh/therm_pm72.h b/drivers/macintosh/therm_pm72.h --- a/drivers/macintosh/therm_pm72.h Sun Mar 14 14:20:07 2004 +++ b/drivers/macintosh/therm_pm72.h Sun Mar 14 14:20:07 2004 @@ -85,7 +85,7 @@ * I'm not sure which of these Apple's algorithm is supposed * to use */ -#define RPM_PID_USE_ACTUAL_SPEED 1 +#define RPM_PID_USE_ACTUAL_SPEED 0 /* * i2c IDs. Currently, we hard code those and assume that @@ -220,6 +220,7 @@ s32 current_a; s32 last_temp; int first; + u8 adc_config; }; /* diff -Nru a/drivers/mca/mca-bus.c b/drivers/mca/mca-bus.c --- a/drivers/mca/mca-bus.c Sun Mar 14 14:20:06 2004 +++ b/drivers/mca/mca-bus.c Sun Mar 14 14:20:06 2004 @@ -106,6 +106,7 @@ sprintf (mca_dev->dev.bus_id, "%02d:%02X", bus, mca_dev->slot); mca_dev->dma_mask = mca_bus->default_dma_mask; mca_dev->dev.dma_mask = &mca_dev->dma_mask; + mca_dev->dev.coherent_dma_mask = mca_dev->dma_mask; if (device_register(&mca_dev->dev)) return 0; diff -Nru a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c --- a/drivers/md/dm-crypt.c Sun Mar 14 14:20:05 2004 +++ b/drivers/md/dm-crypt.c Sun Mar 14 14:20:05 2004 @@ -621,7 +621,8 @@ return clone; } -static int crypt_map(struct dm_target *ti, struct bio *bio) +static int crypt_map(struct dm_target *ti, struct bio *bio, + union map_info *map_context) { struct crypt_config *cc = (struct crypt_config *) ti->private; struct crypt_io *io = mempool_alloc(cc->io_pool, GFP_NOIO); @@ -739,6 +740,7 @@ static struct target_type crypt_target = { .name = "crypt", + .version= {1, 0, 0}, .module = THIS_MODULE, .ctr = crypt_ctr, .dtr = crypt_dtr, diff -Nru a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c --- a/drivers/md/dm-ioctl.c Sun Mar 14 14:20:06 2004 +++ b/drivers/md/dm-ioctl.c Sun Mar 14 14:20:06 2004 @@ -33,6 +33,14 @@ struct dm_table *new_map; }; +struct vers_iter { + size_t param_size; + struct dm_target_versions *vers, *old_vers; + char *end; + uint32_t flags; +}; + + #define NUM_BUCKETS 64 #define MASK_BUCKETS (NUM_BUCKETS - 1) static struct list_head _name_buckets[NUM_BUCKETS]; @@ -88,30 +96,24 @@ *---------------------------------------------------------------*/ static struct hash_cell *__get_name_cell(const char *str) { - struct list_head *tmp; struct hash_cell *hc; unsigned int h = hash_str(str); - list_for_each (tmp, _name_buckets + h) { - hc = list_entry(tmp, struct hash_cell, name_list); + list_for_each_entry (hc, _name_buckets + h, name_list) if (!strcmp(hc->name, str)) return hc; - } return NULL; } static struct hash_cell *__get_uuid_cell(const char *str) { - struct list_head *tmp; struct hash_cell *hc; unsigned int h = hash_str(str); - list_for_each (tmp, _uuid_buckets + h) { - hc = list_entry(tmp, struct hash_cell, uuid_list); + list_for_each_entry (hc, _uuid_buckets + h, uuid_list) if (!strcmp(hc->uuid, str)) return hc; - } return NULL; } @@ -415,6 +417,80 @@ return 0; } +static void list_version_get_needed(struct target_type *tt, void *param) +{ + int *needed = param; + + *needed += strlen(tt->name); + *needed += sizeof(tt->version); + *needed += ALIGN_MASK; +} + +static void list_version_get_info(struct target_type *tt, void *param) +{ + struct vers_iter *info = param; + + /* Check space - it might have changed since the first iteration */ + if ((char *)info->vers + sizeof(tt->version) + strlen(tt->name) + 1 > + info->end) { + + info->flags = DM_BUFFER_FULL_FLAG; + return; + } + + if (info->old_vers) + info->old_vers->next = (uint32_t) ((void *)info->vers - + (void *)info->old_vers); + info->vers->version[0] = tt->version[0]; + info->vers->version[1] = tt->version[1]; + info->vers->version[2] = tt->version[2]; + info->vers->next = 0; + strcpy(info->vers->name, tt->name); + + info->old_vers = info->vers; + info->vers = align_ptr(((void *) ++info->vers) + strlen(tt->name) + 1); +} + +static int list_versions(struct dm_ioctl *param, size_t param_size) +{ + size_t len, needed = 0; + struct dm_target_versions *vers; + struct vers_iter iter_info; + + /* + * Loop through all the devices working out how much + * space we need. + */ + dm_target_iterate(list_version_get_needed, &needed); + + /* + * Grab our output buffer. + */ + vers = get_result_buffer(param, param_size, &len); + if (len < needed) { + param->flags |= DM_BUFFER_FULL_FLAG; + goto out; + } + param->data_size = param->data_start + needed; + + iter_info.param_size = param_size; + iter_info.old_vers = NULL; + iter_info.vers = vers; + iter_info.flags = 0; + iter_info.end = (char *)vers+len; + + /* + * Now loop through filling out the names & versions. + */ + dm_target_iterate(list_version_get_info, &iter_info); + param->flags |= iter_info.flags; + + out: + return 0; +} + + + static int check_name(const char *name) { if (strchr(name, '/')) { @@ -935,6 +1011,7 @@ unsigned int count = 0; struct list_head *tmp; size_t len, needed; + struct dm_dev *dd; struct dm_target_deps *deps; deps = get_result_buffer(param, param_size, &len); @@ -942,7 +1019,7 @@ /* * Count the devices. */ - list_for_each(tmp, dm_table_get_devices(table)) + list_for_each (tmp, dm_table_get_devices(table)) count++; /* @@ -959,10 +1036,8 @@ */ deps->count = count; count = 0; - list_for_each(tmp, dm_table_get_devices(table)) { - struct dm_dev *dd = list_entry(tmp, struct dm_dev, list); + list_for_each_entry (dd, dm_table_get_devices(table), list) deps->dev[count++] = huge_encode_dev(dd->bdev->bd_dev); - } param->data_size = param->data_start + needed; } @@ -1045,7 +1120,9 @@ {DM_TABLE_LOAD_CMD, table_load}, {DM_TABLE_CLEAR_CMD, table_clear}, {DM_TABLE_DEPS_CMD, table_deps}, - {DM_TABLE_STATUS_CMD, table_status} + {DM_TABLE_STATUS_CMD, table_status}, + + {DM_LIST_VERSIONS_CMD, list_versions} }; return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn; @@ -1119,7 +1196,9 @@ param->flags &= ~DM_BUFFER_FULL_FLAG; /* Ignores parameters */ - if (cmd == DM_REMOVE_ALL_CMD || cmd == DM_LIST_DEVICES_CMD) + if (cmd == DM_REMOVE_ALL_CMD || + cmd == DM_LIST_DEVICES_CMD || + cmd == DM_LIST_VERSIONS_CMD) return 0; /* Unless creating, either name or uuid but not both */ diff -Nru a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c --- a/drivers/md/dm-linear.c Sun Mar 14 14:20:07 2004 +++ b/drivers/md/dm-linear.c Sun Mar 14 14:20:07 2004 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001 Sistina Software (UK) Limited. + * Copyright (C) 2001-2003 Sistina Software (UK) Limited. * * This file is released under the GPL. */ @@ -65,7 +65,8 @@ kfree(lc); } -static int linear_map(struct dm_target *ti, struct bio *bio) +static int linear_map(struct dm_target *ti, struct bio *bio, + union map_info *map_context) { struct linear_c *lc = (struct linear_c *) ti->private; @@ -96,6 +97,7 @@ static struct target_type linear_target = { .name = "linear", + .version= {1, 0, 1}, .module = THIS_MODULE, .ctr = linear_ctr, .dtr = linear_dtr, diff -Nru a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c --- a/drivers/md/dm-stripe.c Sun Mar 14 14:20:07 2004 +++ b/drivers/md/dm-stripe.c Sun Mar 14 14:20:07 2004 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001 Sistina Software (UK) Limited. + * Copyright (C) 2001-2003 Sistina Software (UK) Limited. * * This file is released under the GPL. */ @@ -97,7 +97,8 @@ /* * chunk_size is a power of two */ - if (!chunk_size || (chunk_size & (chunk_size - 1))) { + if (!chunk_size || (chunk_size & (chunk_size - 1)) || + (chunk_size < (PAGE_SIZE >> SECTOR_SHIFT))) { ti->error = "dm-stripe: Invalid chunk size"; return -EINVAL; } @@ -166,7 +167,8 @@ kfree(sc); } -static int stripe_map(struct dm_target *ti, struct bio *bio) +static int stripe_map(struct dm_target *ti, struct bio *bio, + union map_info *map_context) { struct stripe_c *sc = (struct stripe_c *) ti->private; @@ -211,6 +213,7 @@ static struct target_type stripe_target = { .name = "striped", + .version= {1, 0, 1}, .module = THIS_MODULE, .ctr = stripe_ctr, .dtr = stripe_dtr, diff -Nru a/drivers/md/dm-table.c b/drivers/md/dm-table.c --- a/drivers/md/dm-table.c Sun Mar 14 14:20:08 2004 +++ b/drivers/md/dm-table.c Sun Mar 14 14:20:08 2004 @@ -329,13 +329,11 @@ */ static struct dm_dev *find_device(struct list_head *l, dev_t dev) { - struct list_head *tmp; + struct dm_dev *dd; - list_for_each(tmp, l) { - struct dm_dev *dd = list_entry(tmp, struct dm_dev, list); + list_for_each_entry (dd, l, list) if (dd->bdev->bd_dev == dev) return dd; - } return NULL; } @@ -631,14 +629,20 @@ return 0; } -static void set_default_limits(struct io_restrictions *rs) +static void check_for_valid_limits(struct io_restrictions *rs) { - rs->max_sectors = MAX_SECTORS; - rs->max_phys_segments = MAX_PHYS_SEGMENTS; - rs->max_hw_segments = MAX_HW_SEGMENTS; - rs->hardsect_size = 1 << SECTOR_SHIFT; - rs->max_segment_size = MAX_SEGMENT_SIZE; - rs->seg_boundary_mask = -1; + if (!rs->max_sectors) + rs->max_sectors = MAX_SECTORS; + if (!rs->max_phys_segments) + rs->max_phys_segments = MAX_PHYS_SEGMENTS; + if (!rs->max_hw_segments) + rs->max_hw_segments = MAX_HW_SEGMENTS; + if (!rs->hardsect_size) + rs->hardsect_size = 1 << SECTOR_SHIFT; + if (!rs->max_segment_size) + rs->max_segment_size = MAX_SEGMENT_SIZE; + if (!rs->seg_boundary_mask) + rs->seg_boundary_mask = -1; } int dm_table_add_target(struct dm_table *t, const char *type, @@ -653,7 +657,6 @@ tgt = t->targets + t->num_targets; memset(tgt, 0, sizeof(*tgt)); - set_default_limits(&tgt->limits); if (!len) { tgt->error = "zero-length target"; @@ -737,6 +740,8 @@ { int r = 0; unsigned int leaf_nodes; + + check_for_valid_limits(&t->limits); /* how many indexes will the btree have ? */ leaf_nodes = dm_div_up(t->num_targets, KEYS_PER_NODE); diff -Nru a/drivers/md/dm-target.c b/drivers/md/dm-target.c --- a/drivers/md/dm-target.c Sun Mar 14 14:20:08 2004 +++ b/drivers/md/dm-target.c Sun Mar 14 14:20:08 2004 @@ -25,15 +25,11 @@ static inline struct tt_internal *__find_target_type(const char *name) { - struct list_head *tih; struct tt_internal *ti; - list_for_each(tih, &_targets) { - ti = list_entry(tih, struct tt_internal, list); - + list_for_each_entry (ti, &_targets, list) if (!strcmp(name, ti->tt.name)) return ti; - } return NULL; } @@ -100,6 +96,20 @@ return ti; } + +int dm_target_iterate(void (*iter_func)(struct target_type *tt, + void *param), void *param) +{ + struct tt_internal *ti; + + down_read(&_lock); + list_for_each_entry (ti, &_targets, list) + iter_func(&ti->tt, param); + up_read(&_lock); + + return 0; +} + int dm_register_target(struct target_type *t) { int rv = 0; @@ -157,13 +167,15 @@ /* empty */ } -static int io_err_map(struct dm_target *ti, struct bio *bio) +static int io_err_map(struct dm_target *ti, struct bio *bio, + union map_info *map_context) { return -EIO; } static struct target_type error_target = { .name = "error", + .version = {1, 0, 1}, .ctr = io_err_ctr, .dtr = io_err_dtr, .map = io_err_map, diff -Nru a/drivers/md/dm.c b/drivers/md/dm.c --- a/drivers/md/dm.c Sun Mar 14 14:20:08 2004 +++ b/drivers/md/dm.c Sun Mar 14 14:20:08 2004 @@ -21,6 +21,9 @@ static unsigned int major = 0; static unsigned int _major = 0; +/* + * One of these is allocated per bio. + */ struct dm_io { struct mapped_device *md; int error; @@ -29,6 +32,16 @@ }; /* + * One of these is allocated per target within a bio. Hopefully + * this will be simplified out one day. + */ +struct target_io { + struct dm_io *io; + struct dm_target *ti; + union map_info info; +}; + +/* * Bits for the md->flags field. */ #define DMF_BLOCK_IO 0 @@ -59,6 +72,7 @@ * io objects are allocated from here. */ mempool_t *io_pool; + mempool_t *tio_pool; /* * Event handling. @@ -69,6 +83,7 @@ #define MIN_IOS 256 static kmem_cache_t *_io_cache; +static kmem_cache_t *_tio_cache; static __init int local_init(void) { @@ -80,9 +95,18 @@ if (!_io_cache) return -ENOMEM; + /* allocate a slab for the target ios */ + _tio_cache = kmem_cache_create("dm_tio", sizeof(struct target_io), + 0, 0, NULL, NULL); + if (!_tio_cache) { + kmem_cache_destroy(_io_cache); + return -ENOMEM; + } + _major = major; r = register_blkdev(_major, _name); if (r < 0) { + kmem_cache_destroy(_tio_cache); kmem_cache_destroy(_io_cache); return r; } @@ -95,6 +119,7 @@ static void local_exit(void) { + kmem_cache_destroy(_tio_cache); kmem_cache_destroy(_io_cache); if (unregister_blkdev(_major, _name) < 0) @@ -184,6 +209,16 @@ mempool_free(io, md->io_pool); } +static inline struct target_io *alloc_tio(struct mapped_device *md) +{ + return mempool_alloc(md->tio_pool, GFP_NOIO); +} + +static inline void free_tio(struct mapped_device *md, struct target_io *tio) +{ + mempool_free(tio, md->tio_pool); +} + /* * Add the bio to the list of deferred io. */ @@ -232,17 +267,30 @@ static int clone_endio(struct bio *bio, unsigned int done, int error) { - struct dm_io *io = bio->bi_private; + int r = 0; + struct target_io *tio = bio->bi_private; + struct dm_io *io = tio->io; + dm_endio_fn endio = tio->ti->type->end_io; if (bio->bi_size) return 1; + if (endio) { + r = endio(tio->ti, bio, error, &tio->info); + if (r < 0) + error = r; + + else if (r > 0) + /* the target wants another shot at the io */ + return 1; + } + + free_tio(io->md, tio); dec_pending(io, error); bio_put(bio); - return 0; + return r; } - static sector_t max_io_len(struct mapped_device *md, sector_t sector, struct dm_target *ti) { @@ -263,7 +311,8 @@ return len; } -static void __map_bio(struct dm_target *ti, struct bio *clone, struct dm_io *io) +static void __map_bio(struct dm_target *ti, struct bio *clone, + struct target_io *tio) { int r; @@ -273,22 +322,25 @@ BUG_ON(!clone->bi_size); clone->bi_end_io = clone_endio; - clone->bi_private = io; + clone->bi_private = tio; /* * Map the clone. If r == 0 we don't need to do * anything, the target has assumed ownership of * this io. */ - atomic_inc(&io->io_count); - r = ti->type->map(ti, clone); + atomic_inc(&tio->io->io_count); + r = ti->type->map(ti, clone, &tio->info); if (r > 0) /* the bio has been remapped so dispatch it */ generic_make_request(clone); - else if (r < 0) + else if (r < 0) { /* error the io and bail out */ + struct dm_io *io = tio->io; + free_tio(tio->io->md, tio); dec_pending(io, -EIO); + } } struct clone_info { @@ -348,6 +400,15 @@ struct bio *clone, *bio = ci->bio; struct dm_target *ti = dm_table_find_target(ci->md->map, ci->sector); sector_t len = 0, max = max_io_len(ci->md, ci->sector, ti); + struct target_io *tio; + + /* + * Allocate a target io object. + */ + tio = alloc_tio(ci->md); + tio->io = ci->io; + tio->ti = ti; + memset(&tio->info, 0, sizeof(tio->info)); if (ci->sector_count <= max) { /* @@ -356,7 +417,7 @@ */ clone = clone_bio(bio, ci->sector, ci->idx, bio->bi_vcnt - ci->idx, ci->sector_count); - __map_bio(ti, clone, ci->io); + __map_bio(ti, clone, tio); ci->sector_count = 0; } else if (to_sector(bio->bi_io_vec[ci->idx].bv_len) <= max) { @@ -379,7 +440,7 @@ } clone = clone_bio(bio, ci->sector, ci->idx, i - ci->idx, len); - __map_bio(ti, clone, ci->io); + __map_bio(ti, clone, tio); ci->sector += len; ci->sector_count -= len; @@ -394,7 +455,7 @@ clone = split_bvec(bio, ci->sector, ci->idx, bv->bv_offset, max); - __map_bio(ti, clone, ci->io); + __map_bio(ti, clone, tio); ci->sector += max; ci->sector_count -= max; @@ -403,7 +464,11 @@ len = to_sector(bv->bv_len) - max; clone = split_bvec(bio, ci->sector, ci->idx, bv->bv_offset + to_bytes(max), len); - __map_bio(ti, clone, ci->io); + tio = alloc_tio(ci->md); + tio->io = ci->io; + tio->ti = ti; + memset(&tio->info, 0, sizeof(tio->info)); + __map_bio(ti, clone, tio); ci->sector += len; ci->sector_count -= len; @@ -441,6 +506,16 @@ *---------------------------------------------------------------*/ +static inline void __dm_request(struct mapped_device *md, struct bio *bio) +{ + if (!md->map) { + bio_io_error(bio, bio->bi_size); + return; + } + + __split_bio(md, bio); +} + /* * The request function that just remaps the bio built up by * dm_merge_bvec. @@ -479,12 +554,7 @@ down_read(&md->lock); } - if (!md->map) { - bio_io_error(bio, bio->bi_size); - return 0; - } - - __split_bio(md, bio); + __dm_request(md, bio); up_read(&md->lock); return 0; } @@ -574,9 +644,14 @@ if (!md->io_pool) goto bad2; + md->tio_pool = mempool_create(MIN_IOS, mempool_alloc_slab, + mempool_free_slab, _tio_cache); + if (!md->tio_pool) + goto bad3; + md->disk = alloc_disk(1); if (!md->disk) - goto bad3; + goto bad4; md->disk->major = _major; md->disk->first_minor = minor; @@ -592,7 +667,8 @@ return md; - + bad4: + mempool_destroy(md->tio_pool); bad3: mempool_destroy(md->io_pool); bad2: @@ -606,6 +682,7 @@ static void free_dev(struct mapped_device *md) { free_minor(md->disk->first_minor); + mempool_destroy(md->tio_pool); mempool_destroy(md->io_pool); del_gendisk(md->disk); put_disk(md->disk); @@ -644,13 +721,13 @@ { request_queue_t *q = md->queue; sector_t size; - md->map = t; size = dm_table_get_size(t); __set_size(md->disk, size); if (size == 0) return 0; + md->map = t; dm_table_event_callback(md->map, event_callback, md); dm_table_get(t); @@ -710,16 +787,16 @@ } /* - * Requeue the deferred bios by calling generic_make_request. + * Process the deferred bios */ -static void flush_deferred_io(struct bio *c) +static void __flush_deferred_io(struct mapped_device *md, struct bio *c) { struct bio *n; while (c) { n = c->bi_next; c->bi_next = NULL; - generic_make_request(c); + __dm_request(md, c); c = n; } } @@ -814,10 +891,11 @@ dm_table_resume_targets(md->map); clear_bit(DMF_SUSPENDED, &md->flags); clear_bit(DMF_BLOCK_IO, &md->flags); + def = bio_list_get(&md->deferred); + __flush_deferred_io(md, def); up_write(&md->lock); - flush_deferred_io(def); blk_run_queues(); return 0; diff -Nru a/drivers/md/dm.h b/drivers/md/dm.h --- a/drivers/md/dm.h Sun Mar 14 14:20:07 2004 +++ b/drivers/md/dm.h Sun Mar 14 14:20:07 2004 @@ -123,6 +123,8 @@ void dm_target_exit(void); struct target_type *dm_get_target_type(const char *name); void dm_put_target_type(struct target_type *t); +int dm_target_iterate(void (*iter_func)(struct target_type *tt, + void *param), void *param); /*----------------------------------------------------------------- diff -Nru a/drivers/md/md.c b/drivers/md/md.c --- a/drivers/md/md.c Sun Mar 14 14:20:06 2004 +++ b/drivers/md/md.c Sun Mar 14 14:20:06 2004 @@ -57,7 +57,7 @@ #ifndef MODULE -static void autostart_arrays (void); +static void autostart_arrays (int part); #endif static mdk_personality_t *pers[MAX_PERSONALITY]; @@ -1447,7 +1447,7 @@ return 1; } -static int mdp_major = 0; +int mdp_major = 0; static struct kobject *md_probe(dev_t dev, int *part, void *data) { @@ -1792,7 +1792,7 @@ * * If "unit" is allocated, then bump its reference count */ -static void autorun_devices(void) +static void autorun_devices(int part) { struct list_head candidates; struct list_head *tmp; @@ -1825,7 +1825,12 @@ bdevname(rdev0->bdev, b), rdev0->preferred_minor); break; } - dev = MKDEV(MD_MAJOR, rdev0->preferred_minor); + if (part) + dev = MKDEV(mdp_major, + rdev0->preferred_minor << MdpMinorShift); + else + dev = MKDEV(MD_MAJOR, rdev0->preferred_minor); + md_probe(dev, NULL, NULL); mddev = mddev_find(dev); if (!mddev) { @@ -1922,7 +1927,7 @@ /* * possibly return codes */ - autorun_devices(); + autorun_devices(0); return 0; } @@ -2407,7 +2412,7 @@ #ifndef MODULE case RAID_AUTORUN: err = 0; - autostart_arrays(); + autostart_arrays(arg); goto done; #endif default:; @@ -3577,7 +3582,7 @@ } -static void autostart_arrays(void) +static void autostart_arrays(int part) { char b[BDEVNAME_SIZE]; mdk_rdev_t *rdev; @@ -3602,7 +3607,7 @@ } dev_cnt = 0; - autorun_devices(); + autorun_devices(part); } #endif diff -Nru a/drivers/md/raid0.c b/drivers/md/raid0.c --- a/drivers/md/raid0.c Sun Mar 14 14:20:07 2004 +++ b/drivers/md/raid0.c Sun Mar 14 14:20:07 2004 @@ -313,8 +313,8 @@ /* calculate the max read-ahead size. * For read-ahead of large files to be effective, we need to - * readahead at least a whole stripe. i.e. number of devices - * multiplied by chunk size. + * readahead at least twice a whole stripe. i.e. number of devices + * multiplied by chunk size times 2. * If an individual device has an ra_pages greater than the * chunk size, then we will not drive that device as hard as it * wants. We consider this a configuration error: a larger @@ -322,8 +322,8 @@ */ { int stripe = mddev->raid_disks * mddev->chunk_size / PAGE_CACHE_SIZE; - if (mddev->queue->backing_dev_info.ra_pages < stripe) - mddev->queue->backing_dev_info.ra_pages = stripe; + if (mddev->queue->backing_dev_info.ra_pages < 2* stripe) + mddev->queue->backing_dev_info.ra_pages = 2* stripe; } diff -Nru a/drivers/md/raid5.c b/drivers/md/raid5.c --- a/drivers/md/raid5.c Sun Mar 14 14:20:06 2004 +++ b/drivers/md/raid5.c Sun Mar 14 14:20:06 2004 @@ -1409,7 +1409,8 @@ /* make sure we don't swamp the stripe cache if someone else * is trying to get access */ - yield(); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); } spin_lock(&sh->lock); set_bit(STRIPE_SYNCING, &sh->state); @@ -1602,14 +1603,14 @@ print_raid5_conf(conf); - /* read-ahead size must cover a whole stripe, which is - * (n-1) * chunksize where 'n' is the number of raid devices + /* read-ahead size must cover two whole stripes, which is + * 2 * (n-1) * chunksize where 'n' is the number of raid devices */ { int stripe = (mddev->raid_disks-1) * mddev->chunk_size / PAGE_CACHE_SIZE; - if (mddev->queue->backing_dev_info.ra_pages < stripe) - mddev->queue->backing_dev_info.ra_pages = stripe; + if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe) + mddev->queue->backing_dev_info.ra_pages = 2 * stripe; } /* Ok, everything is just fine now */ diff -Nru a/drivers/md/raid6main.c b/drivers/md/raid6main.c --- a/drivers/md/raid6main.c Sun Mar 14 14:20:05 2004 +++ b/drivers/md/raid6main.c Sun Mar 14 14:20:06 2004 @@ -1571,7 +1571,8 @@ /* make sure we don't swamp the stripe cache if someone else * is trying to get access */ - yield(); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); } spin_lock(&sh->lock); set_bit(STRIPE_SYNCING, &sh->state); @@ -1771,14 +1772,14 @@ print_raid6_conf(conf); - /* read-ahead size must cover a whole stripe, which is - * (n-2) * chunksize where 'n' is the number of raid devices + /* read-ahead size must cover two whole stripes, which is + * 2 * (n-2) * chunksize where 'n' is the number of raid devices */ { int stripe = (mddev->raid_disks-2) * mddev->chunk_size / PAGE_CACHE_SIZE; - if (mddev->queue->backing_dev_info.ra_pages < stripe) - mddev->queue->backing_dev_info.ra_pages = stripe; + if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe) + mddev->queue->backing_dev_info.ra_pages = 2 * stripe; } /* Ok, everything is just fine now */ diff -Nru a/drivers/media/dvb/frontends/alps_tdlb7.c b/drivers/media/dvb/frontends/alps_tdlb7.c --- a/drivers/media/dvb/frontends/alps_tdlb7.c Sun Mar 14 14:20:06 2004 +++ b/drivers/media/dvb/frontends/alps_tdlb7.c Sun Mar 14 14:20:06 2004 @@ -29,8 +29,6 @@ */ - -#define __KERNEL_SYSCALLS__ #include #include #include @@ -58,8 +56,6 @@ #define SP8870_FIRMWARE_OFFSET 0x0A -static int errno; - static struct dvb_frontend_info tdlb7_info = { .name = "Alps TDLB7", .type = FE_OFDM, @@ -174,13 +170,13 @@ loff_t filesize; char *dp; - fd = open(fn, 0, 0); + fd = sys_open(fn, 0, 0); if (fd == -1) { printk("%s: unable to open '%s'.\n", __FUNCTION__, fn); return -EIO; } - filesize = lseek(fd, 0L, 2); + filesize = sys_lseek(fd, 0L, 2); if (filesize <= 0 || filesize < SP8870_FIRMWARE_OFFSET + SP8870_FIRMWARE_SIZE) { printk("%s: firmware filesize to small '%s'\n", __FUNCTION__, fn); sys_close(fd); @@ -194,8 +190,8 @@ return -EIO; } - lseek(fd, SP8870_FIRMWARE_OFFSET, 0); - if (read(fd, dp, SP8870_FIRMWARE_SIZE) != SP8870_FIRMWARE_SIZE) { + sys_lseek(fd, SP8870_FIRMWARE_OFFSET, 0); + if (sys_read(fd, dp, SP8870_FIRMWARE_SIZE) != SP8870_FIRMWARE_SIZE) { printk("%s: failed to read '%s'.\n",__FUNCTION__, fn); vfree(dp); sys_close(fd); diff -Nru a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c --- a/drivers/media/dvb/frontends/sp887x.c Sun Mar 14 14:20:08 2004 +++ b/drivers/media/dvb/frontends/sp887x.c Sun Mar 14 14:20:08 2004 @@ -12,7 +12,6 @@ next 0x4000 loaded. This may change in future versions. */ -#define __KERNEL_SYSCALLS__ #include #include #include @@ -68,8 +67,6 @@ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_RECOVER }; -static int errno; - static int i2c_writebytes (struct dvb_frontend *fe, u8 addr, u8 *buf, u8 len) { @@ -216,13 +213,13 @@ // Load the firmware set_fs(get_ds()); - fd = open(sp887x_firmware, 0, 0); + fd = sys_open(sp887x_firmware, 0, 0); if (fd < 0) { printk(KERN_WARNING "%s: Unable to open firmware %s\n", __FUNCTION__, sp887x_firmware); return -EIO; } - filesize = lseek(fd, 0L, 2); + filesize = sys_lseek(fd, 0L, 2); if (filesize <= 0) { printk(KERN_WARNING "%s: Firmware %s is empty\n", __FUNCTION__, sp887x_firmware); @@ -244,8 +241,8 @@ // read it! // read the first 16384 bytes from the file // ignore the first 10 bytes - lseek(fd, 10, 0); - if (read(fd, firmware, fw_size) != fw_size) { + sys_lseek(fd, 10, 0); + if (sys_read(fd, firmware, fw_size) != fw_size) { printk(KERN_WARNING "%s: Failed to read firmware\n", __FUNCTION__); vfree(firmware); sys_close(fd); diff -Nru a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c --- a/drivers/media/dvb/frontends/tda1004x.c Sun Mar 14 14:20:05 2004 +++ b/drivers/media/dvb/frontends/tda1004x.c Sun Mar 14 14:20:05 2004 @@ -32,7 +32,6 @@ */ -#define __KERNEL_SYSCALLS__ #include #include #include @@ -41,7 +40,6 @@ #include #include #include -#include #include #include #include "dvb_frontend.h" @@ -399,13 +397,13 @@ // Load the firmware set_fs(get_ds()); - fd = open(tda1004x_firmware, 0, 0); + fd = sys_open(tda1004x_firmware, 0, 0); if (fd < 0) { printk("%s: Unable to open firmware %s\n", __FUNCTION__, tda1004x_firmware); return -EIO; } - filesize = lseek(fd, 0L, 2); + filesize = sys_lseek(fd, 0L, 2); if (filesize <= 0) { printk("%s: Firmware %s is empty\n", __FUNCTION__, tda1004x_firmware); @@ -436,8 +434,8 @@ } // read it! - lseek(fd, fw_offset, 0); - if (read(fd, firmware, fw_size) != fw_size) { + sys_lseek(fd, fw_offset, 0); + if (sys_read(fd, firmware, fw_size) != fw_size) { printk("%s: Failed to read firmware\n", __FUNCTION__); vfree(firmware); sys_close(fd); diff -Nru a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c --- a/drivers/media/video/video-buf.c Sun Mar 14 14:20:07 2004 +++ b/drivers/media/video/video-buf.c Sun Mar 14 14:20:07 2004 @@ -215,7 +215,7 @@ BUG(); if (!dma->bus_addr) - pci_dma_sync_sg(dev,dma->sglist,dma->nr_pages,dma->direction); + pci_dma_sync_sg_for_cpu(dev,dma->sglist,dma->nr_pages,dma->direction); return 0; } diff -Nru a/drivers/message/fusion/Kconfig b/drivers/message/fusion/Kconfig --- a/drivers/message/fusion/Kconfig Sun Mar 14 14:20:09 2004 +++ b/drivers/message/fusion/Kconfig Sun Mar 14 14:20:09 2004 @@ -3,7 +3,7 @@ config FUSION tristate "Fusion MPT (base + ScsiHost) drivers" - depends on BLK_DEV_SD && PCI + depends on PCI ---help--- LSI Logic Fusion(TM) Message Passing Technology (MPT) device support provides high performance SCSI host initiator, and LAN [1] interface @@ -14,41 +14,6 @@ [1] LAN is not supported on parallel SCSI medium. - These drivers require a Fusion MPT compatible PCI adapter installed - in the host system. MPT adapters contain specialized I/O processors - to handle I/O workload, and more importantly to offload this work - from the host CPU(s). - - If you have Fusion MPT hardware and want to use it, you can say - Y or M here to add MPT (base + ScsiHost) drivers. - = build lib (fusion), and link [static] into the kernel [2] - proper - = compiled as [dynamic] modules [3] named: (mptbase, - mptscsih) - - [2] In order enable capability to boot the linux kernel - natively from a Fusion MPT target device, you MUST - answer Y here! (currently requires CONFIG_BLK_DEV_SD) - [3] To compile this support as modules, choose M here. - - If unsure, say N. - - If you say Y or M here you will get a choice of these - additional protocol and support module options: Module Name: - Enhanced SCSI error reporting (isense) - Fusion MPT misc device (ioctl) driver (mptctl) - Fusion MPT LAN driver (mptlan) - - --- - Fusion MPT is trademark of LSI Logic Corporation, and its - architecture is based on LSI Logic's Message Passing Interface (MPI) - specification. - -config FUSION_BOOT - bool - depends on FUSION=y - default y - config FUSION_MAX_SGE int "Maximum number of scatter gather entries" depends on FUSION @@ -62,7 +27,6 @@ necessary (or recommended) unless the user will be running large I/O's via the raw interface. -# How can we force these options to module or nothing? config FUSION_ISENSE tristate "Enhanced SCSI error reporting" depends on MODULES && FUSION && m @@ -132,17 +96,4 @@ If unsure whether you really want or need this, say N. - NOTES: This feature is NOT available nor supported for linux-2.2.x - kernels. You must be building a linux-2.3.x or linux-2.4.x kernel - in order to configure this option. - Support for building this feature into the linux kernel is not - yet available. - -# if [ "$CONFIG_FUSION_LAN" != "n" ]; then -# define_bool CONFIG_NET_FC y -# fi -# These be define_tristate, but we leave them define_bool -# for backward compatibility with pre-linux-2.2.15 kernels. -# (Bugzilla:fibrebugs, #384) endmenu - diff -Nru a/drivers/message/fusion/Makefile b/drivers/message/fusion/Makefile --- a/drivers/message/fusion/Makefile Sun Mar 14 14:20:07 2004 +++ b/drivers/message/fusion/Makefile Sun Mar 14 14:20:07 2004 @@ -17,10 +17,16 @@ # Fusion MPT drivers; recognized debug defines... # MPT general: -#EXTRA_CFLAGS += -DDEBUG +#EXTRA_CFLAGS += -DMPT_DEBUG_SCSI #EXTRA_CFLAGS += -DMPT_DEBUG #EXTRA_CFLAGS += -DMPT_DEBUG_MSG_FRAME #EXTRA_CFLAGS += -DMPT_DEBUG_SG + +# This is a temporary fix for the reply/request fifo +# for some 64bit archs. Uncommenting this line +# will place the fifo's in 32bit space +#EXTRA_CFLAGS += -DMPTBASE_MEM_ALLOC_FIFO_FIX + # # driver/module specifics... # diff -Nru a/drivers/message/fusion/isense.c b/drivers/message/fusion/isense.c --- a/drivers/message/fusion/isense.c Sun Mar 14 14:20:07 2004 +++ b/drivers/message/fusion/isense.c Sun Mar 14 14:20:07 2004 @@ -5,7 +5,7 @@ * Error Report logging output. This module implements SCSI-3 * Opcode lookup and a sorted table of SCSI-3 ASC/ASCQ strings. * - * Copyright (c) 1991-2003 Steven J. Ralston + * Copyright (c) 1991-2004 Steven J. Ralston * Written By: Steven J. Ralston * (yes I wrote some of the orig. code back in 1991!) * (mailto:sjralston1@netscape.net) @@ -66,7 +66,7 @@ #endif #define MODULEAUTHOR "Steven J. Ralston" -#define COPYRIGHT "Copyright (c) 2001-2003 " MODULEAUTHOR +#define COPYRIGHT "Copyright (c) 2001-2004 " MODULEAUTHOR #include "mptbase.h" #include "isense.h" diff -Nru a/drivers/message/fusion/linux_compat.h b/drivers/message/fusion/linux_compat.h --- a/drivers/message/fusion/linux_compat.h Sun Mar 14 14:20:06 2004 +++ b/drivers/message/fusion/linux_compat.h Sun Mar 14 14:20:06 2004 @@ -15,25 +15,7 @@ #define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0) #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) -#define SET_NICE(current,x) do {(current)->nice = (x);} while (0) -#else -#define SET_NICE(current,x) -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) -#define pci_enable_device(pdev) (0) -#define SCSI_DATA_UNKNOWN 0 -#define SCSI_DATA_WRITE 1 -#define SCSI_DATA_READ 2 -#define SCSI_DATA_NONE 3 -#endif - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4) -#define pci_set_dma_mask(pdev, mask) (0) -#define scsi_set_pci_device(sh, pdev) (0) -#endif +#define SET_NICE(current,x) do {(current)->nice = (x);} while (0) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) # if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) @@ -147,31 +129,9 @@ /* PCI/driver subsystem { */ -#if 0 /* FIXME Don't know what to use to check for the proper kernel version */ -#define DEVICE_COUNT_RESOURCE 6 -#define PCI_BASEADDR_FLAGS(idx) base_address[idx] -#define PCI_BASEADDR_START(idx) base_address[idx] & ~0xFUL -/* - * We have to keep track of the original value using - * a temporary, and not by just sticking pdev->base_address[x] - * back. pdev->base_address[x] is an opaque cookie that can - * be used by the PCI implementation on a given Linux port - * for any purpose. -DaveM - */ -#define PCI_BASEADDR_SIZE(__pdev, __idx) \ -({ unsigned int size, tmp; \ - pci_read_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), &tmp); \ - pci_write_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), 0xffffffff); \ - pci_read_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), &size); \ - pci_write_config_dword(__pdev, PCI_BASE_ADDRESS_0 + (4*(__idx)), tmp); \ - (4 - size); \ -}) -#else #define PCI_BASEADDR_FLAGS(idx) resource[idx].flags #define PCI_BASEADDR_START(idx) resource[idx].start #define PCI_BASEADDR_SIZE(dev,idx) (dev)->resource[idx].end - (dev)->resource[idx].start + 1 -#endif /* } ifndef 0 */ - /* Compatability for the 2.3.x PCI DMA API. */ #ifndef PCI_DMA_BIDIRECTIONAL @@ -227,54 +187,10 @@ /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #endif /* PCI_DMA_BIDIRECTIONAL */ -/* - * With the new command queuing code in the SCSI mid-layer we no longer have - * to hold the io_request_lock spin lock when calling the scsi_done routine. - * For now we only do this with the 2.5.1 kernel or newer. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1) - #define MPT_HOST_LOCK(flags) - #define MPT_HOST_UNLOCK(flags) -#else - #define MPT_HOST_LOCK(flags) \ - spin_lock_irqsave(&io_request_lock, flags) - #define MPT_HOST_UNLOCK(flags) \ - spin_unlock_irqrestore(&io_request_lock, flags) -#endif - -/* - * We use our new error handling code if the kernel version is 2.4.18 or newer. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,18) - #define MPT_SCSI_USE_NEW_EH -#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,41) #define mpt_work_struct work_struct #define MPT_INIT_WORK(_task, _func, _data) INIT_WORK(_task, _func, _data) -#else -#define mpt_work_struct tq_struct -#define MPT_INIT_WORK(_task, _func, _data) \ -({ (_task)->sync = 0; \ - (_task)->routine = (_func); \ - (_task)->data = (void *) (_data); \ -}) -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28) -#define mptscsih_sync_irq(_irq) synchronize_irq(_irq) -#else -#define mptscsih_sync_irq(_irq) synchronize_irq() -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,58) -#define mpt_inc_use_count() -#define mpt_dec_use_count() -#else -#define mpt_inc_use_count() MOD_INC_USE_COUNT -#define mpt_dec_use_count() MOD_DEC_USE_COUNT -#endif - +#define mpt_sync_irq(_irq) synchronize_irq(_irq) /*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #endif /* _LINUX_COMPAT_H */ diff -Nru a/drivers/message/fusion/lsi/mpi.h b/drivers/message/fusion/lsi/mpi.h --- a/drivers/message/fusion/lsi/mpi.h Sun Mar 14 14:20:06 2004 +++ b/drivers/message/fusion/lsi/mpi.h Sun Mar 14 14:20:06 2004 @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2002 LSI Logic Corporation. + * Copyright (c) 2000-2003 LSI Logic Corporation. * * - * Name: MPI.H + * Name: mpi.h * Title: MPI Message independent structures and definitions * Creation Date: July 27, 2000 * - * MPI.H Version: 01.02.07 + * mpi.h Version: 01.05.xx * * Version History * --------------- @@ -48,6 +48,10 @@ * 05-31-02 01.02.05 Bumped MPI_HEADER_VERSION_UNIT. * 07-12-02 01.02.06 Added define for MPI_FUNCTION_MAILBOX. * 09-16-02 01.02.07 Bumped value for MPI_HEADER_VERSION_UNIT. + * 11-15-02 01.02.08 Added define MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX and + * obsoleted define MPI_IOCSTATUS_TARGET_INVALID_IOCINDEX. + * 04-01-03 01.02.09 New IOCStatus code: MPI_IOCSTATUS_FC_EXCHANGE_CANCELED + * 06-26-03 01.02.10 Bumped MPI_HEADER_VERSION_UNIT value. * -------------------------------------------------------------------------- */ @@ -62,7 +66,7 @@ *****************************************************************************/ #define MPI_VERSION_MAJOR (0x01) -#define MPI_VERSION_MINOR (0x02) +#define MPI_VERSION_MINOR (0x05) #define MPI_VERSION_MAJOR_MASK (0xFF00) #define MPI_VERSION_MAJOR_SHIFT (8) #define MPI_VERSION_MINOR_MASK (0x00FF) @@ -73,10 +77,12 @@ #define MPI_VERSION_01_00 (0x0100) #define MPI_VERSION_01_01 (0x0101) #define MPI_VERSION_01_02 (0x0102) +#define MPI_VERSION_01_03 (0x0103) +#define MPI_VERSION_01_05 (0x0105) /* Note: The major versions of 0xe0 through 0xff are reserved */ /* versioning for this MPI header set */ -#define MPI_HEADER_VERSION_UNIT (0x09) +#define MPI_HEADER_VERSION_UNIT (0x00) #define MPI_HEADER_VERSION_DEV (0x00) #define MPI_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI_HEADER_VERSION_UNIT_SHIFT (8) @@ -171,6 +177,8 @@ #define MPI_REPLY_POST_FIFO_OFFSET (0x00000044) #define MPI_REPLY_FREE_FIFO_OFFSET (0x00000044) +#define MPI_HI_PRI_REQUEST_QUEUE_OFFSET (0x00000048) + /***************************************************************************** @@ -230,10 +238,6 @@ #define MPI_FUNCTION_TARGET_ASSIST (0x0B) #define MPI_FUNCTION_TARGET_STATUS_SEND (0x0C) #define MPI_FUNCTION_TARGET_MODE_ABORT (0x0D) -#define MPI_FUNCTION_TARGET_FC_BUF_POST_LINK_SRVC (0x0E) /* obsolete name */ -#define MPI_FUNCTION_TARGET_FC_RSP_LINK_SRVC (0x0F) /* obsolete name */ -#define MPI_FUNCTION_TARGET_FC_EX_SEND_LINK_SRVC (0x10) /* obsolete name */ -#define MPI_FUNCTION_TARGET_FC_ABORT (0x11) /* obsolete name */ #define MPI_FUNCTION_FC_LINK_SRVC_BUF_POST (0x0E) #define MPI_FUNCTION_FC_LINK_SRVC_RSP (0x0F) #define MPI_FUNCTION_FC_EX_LINK_SRVC_SEND (0x10) @@ -251,16 +255,46 @@ #define MPI_FUNCTION_MAILBOX (0x19) +#define MPI_FUNCTION_SMP_PASSTHROUGH (0x1A) +#define MPI_FUNCTION_SAS_IO_UNIT_CONTROL (0x1B) + +#define MPI_DIAG_BUFFER_POST (0x1D) +#define MPI_DIAG_RELEASE (0x1E) + +#define MPI_FUNCTION_SCSI_IO_32 (0x1F) + #define MPI_FUNCTION_LAN_SEND (0x20) #define MPI_FUNCTION_LAN_RECEIVE (0x21) #define MPI_FUNCTION_LAN_RESET (0x22) +#define MPI_FUNCTION_INBAND_BUFFER_POST (0x28) +#define MPI_FUNCTION_INBAND_SEND (0x29) +#define MPI_FUNCTION_INBAND_RSP (0x2A) +#define MPI_FUNCTION_INBAND_ABORT (0x2B) + #define MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40) #define MPI_FUNCTION_IO_UNIT_RESET (0x41) #define MPI_FUNCTION_HANDSHAKE (0x42) #define MPI_FUNCTION_REPLY_FRAME_REMOVAL (0x43) +/* standard version format */ +typedef struct _MPI_VERSION_STRUCT +{ + U8 Dev; /* 00h */ + U8 Unit; /* 01h */ + U8 Minor; /* 02h */ + U8 Major; /* 03h */ +} MPI_VERSION_STRUCT, MPI_POINTER PTR_MPI_VERSION_STRUCT, + MpiVersionStruct_t, MPI_POINTER pMpiVersionStruct; + +typedef union _MPI_VERSION_FORMAT +{ + MPI_VERSION_STRUCT Struct; + U32 Word; +} MPI_VERSION_FORMAT, MPI_POINTER PTR_MPI_VERSION_FORMAT, + MpiVersionFormat_t, MPI_POINTER pMpiVersionFormat_t; + /***************************************************************************** * @@ -573,44 +607,54 @@ /* Common IOCStatus values for all replies */ /****************************************************************************/ -#define MPI_IOCSTATUS_SUCCESS (0x0000) -#define MPI_IOCSTATUS_INVALID_FUNCTION (0x0001) -#define MPI_IOCSTATUS_BUSY (0x0002) -#define MPI_IOCSTATUS_INVALID_SGL (0x0003) -#define MPI_IOCSTATUS_INTERNAL_ERROR (0x0004) -#define MPI_IOCSTATUS_RESERVED (0x0005) -#define MPI_IOCSTATUS_INSUFFICIENT_RESOURCES (0x0006) -#define MPI_IOCSTATUS_INVALID_FIELD (0x0007) -#define MPI_IOCSTATUS_INVALID_STATE (0x0008) +#define MPI_IOCSTATUS_SUCCESS (0x0000) +#define MPI_IOCSTATUS_INVALID_FUNCTION (0x0001) +#define MPI_IOCSTATUS_BUSY (0x0002) +#define MPI_IOCSTATUS_INVALID_SGL (0x0003) +#define MPI_IOCSTATUS_INTERNAL_ERROR (0x0004) +#define MPI_IOCSTATUS_RESERVED (0x0005) +#define MPI_IOCSTATUS_INSUFFICIENT_RESOURCES (0x0006) +#define MPI_IOCSTATUS_INVALID_FIELD (0x0007) +#define MPI_IOCSTATUS_INVALID_STATE (0x0008) +#define MPI_IOCSTATUS_OP_STATE_NOT_SUPPORTED (0x0009) /****************************************************************************/ /* Config IOCStatus values */ /****************************************************************************/ -#define MPI_IOCSTATUS_CONFIG_INVALID_ACTION (0x0020) -#define MPI_IOCSTATUS_CONFIG_INVALID_TYPE (0x0021) -#define MPI_IOCSTATUS_CONFIG_INVALID_PAGE (0x0022) -#define MPI_IOCSTATUS_CONFIG_INVALID_DATA (0x0023) -#define MPI_IOCSTATUS_CONFIG_NO_DEFAULTS (0x0024) -#define MPI_IOCSTATUS_CONFIG_CANT_COMMIT (0x0025) +#define MPI_IOCSTATUS_CONFIG_INVALID_ACTION (0x0020) +#define MPI_IOCSTATUS_CONFIG_INVALID_TYPE (0x0021) +#define MPI_IOCSTATUS_CONFIG_INVALID_PAGE (0x0022) +#define MPI_IOCSTATUS_CONFIG_INVALID_DATA (0x0023) +#define MPI_IOCSTATUS_CONFIG_NO_DEFAULTS (0x0024) +#define MPI_IOCSTATUS_CONFIG_CANT_COMMIT (0x0025) /****************************************************************************/ /* SCSIIO Reply (SPI & FCP) initiator values */ /****************************************************************************/ -#define MPI_IOCSTATUS_SCSI_RECOVERED_ERROR (0x0040) -#define MPI_IOCSTATUS_SCSI_INVALID_BUS (0x0041) -#define MPI_IOCSTATUS_SCSI_INVALID_TARGETID (0x0042) -#define MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE (0x0043) -#define MPI_IOCSTATUS_SCSI_DATA_OVERRUN (0x0044) -#define MPI_IOCSTATUS_SCSI_DATA_UNDERRUN (0x0045) -#define MPI_IOCSTATUS_SCSI_IO_DATA_ERROR (0x0046) -#define MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR (0x0047) -#define MPI_IOCSTATUS_SCSI_TASK_TERMINATED (0x0048) -#define MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH (0x0049) -#define MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED (0x004A) -#define MPI_IOCSTATUS_SCSI_IOC_TERMINATED (0x004B) -#define MPI_IOCSTATUS_SCSI_EXT_TERMINATED (0x004C) +#define MPI_IOCSTATUS_SCSI_RECOVERED_ERROR (0x0040) +#define MPI_IOCSTATUS_SCSI_INVALID_BUS (0x0041) +#define MPI_IOCSTATUS_SCSI_INVALID_TARGETID (0x0042) +#define MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE (0x0043) +#define MPI_IOCSTATUS_SCSI_DATA_OVERRUN (0x0044) +#define MPI_IOCSTATUS_SCSI_DATA_UNDERRUN (0x0045) +#define MPI_IOCSTATUS_SCSI_IO_DATA_ERROR (0x0046) +#define MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR (0x0047) +#define MPI_IOCSTATUS_SCSI_TASK_TERMINATED (0x0048) +#define MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH (0x0049) +#define MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED (0x004A) +#define MPI_IOCSTATUS_SCSI_IOC_TERMINATED (0x004B) +#define MPI_IOCSTATUS_SCSI_EXT_TERMINATED (0x004C) + +/****************************************************************************/ +/* For use by SCSI Initiator and SCSI Target end-to-end data protection */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_EEDP_CRC_ERROR (0x004D) +#define MPI_IOCSTATUS_EEDP_LBA_TAG_ERROR (0x004E) +#define MPI_IOCSTATUS_EEDP_APP_TAG_ERROR (0x004F) + /****************************************************************************/ /* SCSI (SPI & FCP) target values */ @@ -618,7 +662,8 @@ #define MPI_IOCSTATUS_TARGET_PRIORITY_IO (0x0060) #define MPI_IOCSTATUS_TARGET_INVALID_PORT (0x0061) -#define MPI_IOCSTATUS_TARGET_INVALID_IOCINDEX (0x0062) +#define MPI_IOCSTATUS_TARGET_INVALID_IOCINDEX (0x0062) /* obsolete */ +#define MPI_IOCSTATUS_TARGET_INVALID_IO_INDEX (0x0062) #define MPI_IOCSTATUS_TARGET_ABORTED (0x0063) #define MPI_IOCSTATUS_TARGET_NO_CONN_RETRYABLE (0x0064) #define MPI_IOCSTATUS_TARGET_NO_CONNECTION (0x0065) @@ -626,7 +671,7 @@ #define MPI_IOCSTATUS_TARGET_STS_DATA_NOT_SENT (0x006B) /****************************************************************************/ -/* Additional FCP target values */ +/* Additional FCP target values (obsolete) */ /****************************************************************************/ #define MPI_IOCSTATUS_TARGET_FC_ABORTED (0x0066) /* obsolete */ @@ -642,6 +687,7 @@ #define MPI_IOCSTATUS_FC_RX_ID_INVALID (0x0067) #define MPI_IOCSTATUS_FC_DID_INVALID (0x0068) #define MPI_IOCSTATUS_FC_NODE_LOGGED_OUT (0x0069) +#define MPI_IOCSTATUS_FC_EXCHANGE_CANCELED (0x006C) /****************************************************************************/ /* LAN values */ @@ -656,6 +702,25 @@ #define MPI_IOCSTATUS_LAN_PARTIAL_PACKET (0x0086) #define MPI_IOCSTATUS_LAN_CANCELED (0x0087) +/****************************************************************************/ +/* Serial Attached SCSI values */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_SAS_SMP_REQUEST_FAILED (0x0090) + +/****************************************************************************/ +/* Inband values */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_INBAND_ABORTED (0x0098) +#define MPI_IOCSTATUS_INBAND_NO_CONNECTION (0x0099) + +/****************************************************************************/ +/* Diagnostic Tools values */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_DIAGNOSTIC_RELEASED (0x00A0) + /****************************************************************************/ /* IOCStatus flag to indicate that log info is available */ @@ -669,9 +734,12 @@ /****************************************************************************/ #define MPI_IOCLOGINFO_TYPE_MASK (0xF0000000) +#define MPI_IOCLOGINFO_TYPE_SHIFT (28) #define MPI_IOCLOGINFO_TYPE_NONE (0x0) #define MPI_IOCLOGINFO_TYPE_SCSI (0x1) #define MPI_IOCLOGINFO_TYPE_FC (0x2) +#define MPI_IOCLOGINFO_TYPE_SAS (0x3) +#define MPI_IOCLOGINFO_TYPE_ISCSI (0x4) #define MPI_IOCLOGINFO_LOG_DATA_MASK (0x0FFFFFFF) diff -Nru a/drivers/message/fusion/lsi/mpi_cnfg.h b/drivers/message/fusion/lsi/mpi_cnfg.h --- a/drivers/message/fusion/lsi/mpi_cnfg.h Sun Mar 14 14:20:07 2004 +++ b/drivers/message/fusion/lsi/mpi_cnfg.h Sun Mar 14 14:20:07 2004 @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2002 LSI Logic Corporation. + * Copyright (c) 2000-2003 LSI Logic Corporation. * * - * Name: MPI_CNFG.H + * Name: mpi_cnfg.h * Title: MPI Config message, structures, and Pages * Creation Date: July 27, 2000 * - * MPI_CNFG.H Version: 01.02.09 + * mpi_cnfg.h Version: 01.05.xx * * Version History * --------------- @@ -127,7 +127,24 @@ * MPI_SCSIDEVPAGE1_CONF_EXTENDED_PARAMS_ENABLE. * Added new config page: CONFIG_PAGE_SCSI_DEVICE_3. * Modified MPI_FCPORTPAGE5_FLAGS_ defines. - * 09-16-02 01.02.09 Added more MPI_SCSIDEVPAGE1_CONF_FORCE_PPR_MSG define. + * 09-16-02 01.02.09 Added MPI_SCSIDEVPAGE1_CONF_FORCE_PPR_MSG define. + * 11-15-02 01.02.10 Added ConnectedID defines for CONFIG_PAGE_SCSI_PORT_0. + * Added more Flags defines for CONFIG_PAGE_FC_PORT_1. + * Added more Flags defines for CONFIG_PAGE_FC_DEVICE_0. + * 04-01-03 01.02.11 Added RR_TOV field and additional Flags defines for + * CONFIG_PAGE_FC_PORT_1. + * Added define MPI_FCPORTPAGE5_FLAGS_DISABLE to disable + * an alias. + * Added more device id defines. + * 06-26-03 01.02.12 Added MPI_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID define. + * Added TargetConfig and IDConfig fields to + * CONFIG_PAGE_SCSI_PORT_1. + * Added more PortFlags defines for CONFIG_PAGE_SCSI_PORT_2 + * to control DV. + * Added more Flags defines for CONFIG_PAGE_FC_PORT_1. + * In CONFIG_PAGE_FC_DEVICE_0, replaced Reserved1 field + * with ADISCHardALPA. + * Added MPI_FC_DEVICE_PAGE0_PROT_FCP_RETRY define. * -------------------------------------------------------------------------- */ @@ -159,6 +176,19 @@ } ConfigPageHeaderUnion, MPI_POINTER pConfigPageHeaderUnion, fCONFIG_PAGE_HEADER_UNION, MPI_POINTER PTR_CONFIG_PAGE_HEADER_UNION; +typedef struct _CONFIG_EXTENDED_PAGE_HEADER +{ + U8 PageVersion; /* 00h */ + U8 Reserved1; /* 01h */ + U8 PageNumber; /* 02h */ + U8 PageType; /* 03h */ + U16 ExtPageLength; /* 04h */ + U8 ExtPageType; /* 06h */ + U8 Reserved2; /* 07h */ +} fCONFIG_EXTENDED_PAGE_HEADER, MPI_POINTER PTR_CONFIG_EXTENDED_PAGE_HEADER, + ConfigExtendedPageHeader_t, MPI_POINTER pConfigExtendedPageHeader_t; + + /**************************************************************************** * PageType field values @@ -180,12 +210,23 @@ #define MPI_CONFIG_PAGETYPE_RAID_VOLUME (0x08) #define MPI_CONFIG_PAGETYPE_MANUFACTURING (0x09) #define MPI_CONFIG_PAGETYPE_RAID_PHYSDISK (0x0A) +#define MPI_CONFIG_PAGETYPE_INBAND (0x0B) +#define MPI_CONFIG_PAGETYPE_EXTENDED (0x0F) #define MPI_CONFIG_PAGETYPE_MASK (0x0F) #define MPI_CONFIG_TYPENUM_MASK (0x0FFF) /**************************************************************************** +* ExtPageType field values +****************************************************************************/ +#define MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT (0x10) +#define MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER (0x11) +#define MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE (0x12) +#define MPI_CONFIG_EXTPAGETYPE_SAS_PHY (0x13) + + +/**************************************************************************** * PageAddress field values ****************************************************************************/ #define MPI_SCSI_PORT_PGAD_PORT_MASK (0x000000FF) @@ -219,6 +260,24 @@ #define MPI_PHYSDISK_PGAD_PHYSDISKNUM_MASK (0x000000FF) #define MPI_PHYSDISK_PGAD_PHYSDISKNUM_SHIFT (0) +#define MPI_SAS_DEVICE_PGAD_FORM_MASK (0xF0000000) +#define MPI_SAS_DEVICE_PGAD_FORM_SHIFT (28) +#define MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) +#define MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID (0x00000001) +#define MPI_SAS_DEVICE_PGAD_FORM_HANDLE (0x00000002) +#define MPI_SAS_DEVICE_PGAD_GNH_HANDLE_MASK (0x0000FFFF) +#define MPI_SAS_DEVICE_PGAD_GNH_HANDLE_SHIFT (0) +#define MPI_SAS_DEVICE_PGAD_BT_BUS_MASK (0x0000FF00) +#define MPI_SAS_DEVICE_PGAD_BT_BUS_SHIFT (8) +#define MPI_SAS_DEVICE_PGAD_BT_TID_MASK (0x000000FF) +#define MPI_SAS_DEVICE_PGAD_BT_TID_SHIFT (0) +#define MPI_SAS_DEVICE_PGAD_H_HANDLE_MASK (0x0000FFFF) +#define MPI_SAS_DEVICE_PGAD_H_HANDLE_SHIFT (0) + +#define MPI_SAS_PHY_PGAD_PHY_NUMBER_MASK (0x00FF0000) +#define MPI_SAS_PHY_PGAD_PHY_NUMBER_SHIFT (16) +#define MPI_SAS_PHY_PGAD_DEVHANDLE_MASK (0x0000FFFF) +#define MPI_SAS_PHY_PGAD_DEVHANDLE_SHIFT (0) /**************************************************************************** @@ -230,7 +289,8 @@ U8 Reserved; /* 01h */ U8 ChainOffset; /* 02h */ U8 Function; /* 03h */ - U8 Reserved1[3]; /* 04h */ + U16 ExtPageLength; /* 04h */ + U8 ExtPageType; /* 06h */ U8 MsgFlags; /* 07h */ U32 MsgContext; /* 08h */ U8 Reserved2[8]; /* 0Ch */ @@ -260,7 +320,8 @@ U8 Reserved; /* 01h */ U8 MsgLength; /* 02h */ U8 Function; /* 03h */ - U8 Reserved1[3]; /* 04h */ + U16 ExtPageLength; /* 04h */ + U8 ExtPageType; /* 06h */ U8 MsgFlags; /* 07h */ U32 MsgContext; /* 08h */ U8 Reserved2[2]; /* 0Ch */ @@ -281,23 +342,22 @@ /**************************************************************************** * Manufacturing Config pages ****************************************************************************/ +#define MPI_MANUFACTPAGE_VENDORID_LSILOGIC (0x1000) +/* Fibre Channel */ #define MPI_MANUFACTPAGE_DEVICEID_FC909 (0x0621) #define MPI_MANUFACTPAGE_DEVICEID_FC919 (0x0624) #define MPI_MANUFACTPAGE_DEVICEID_FC929 (0x0622) #define MPI_MANUFACTPAGE_DEVICEID_FC919X (0x0628) #define MPI_MANUFACTPAGE_DEVICEID_FC929X (0x0626) - +/* SCSI */ #define MPI_MANUFACTPAGE_DEVID_53C1030 (0x0030) #define MPI_MANUFACTPAGE_DEVID_53C1030ZC (0x0031) #define MPI_MANUFACTPAGE_DEVID_1030_53C1035 (0x0032) #define MPI_MANUFACTPAGE_DEVID_1030ZC_53C1035 (0x0033) #define MPI_MANUFACTPAGE_DEVID_53C1035 (0x0040) #define MPI_MANUFACTPAGE_DEVID_53C1035ZC (0x0041) - -#define MPI_MANUFACTPAGE_DEVID_SA2010 (0x0804) -#define MPI_MANUFACTPAGE_DEVID_SA2010ZC (0x0805) -#define MPI_MANUFACTPAGE_DEVID_SA2020 (0x0806) -#define MPI_MANUFACTPAGE_DEVID_SA2020ZC (0x0807) +/* SAS */ +#define MPI_MANUFACTPAGE_DEVID_SAS1064 (0x0050) typedef struct _CONFIG_PAGE_MANUFACTURING_0 @@ -381,8 +441,8 @@ U8 InfoOffset1; /* 0Ah */ U8 InfoSize1; /* 0Bh */ U8 InquirySize; /* 0Ch */ - U8 Reserved2; /* 0Dh */ - U16 Reserved3; /* 0Eh */ + U8 Flags; /* 0Dh */ + U16 Reserved2; /* 0Eh */ U8 InquiryData[56]; /* 10h */ U32 ISVolumeSettings; /* 48h */ U32 IMEVolumeSettings; /* 4Ch */ @@ -390,7 +450,30 @@ } fCONFIG_PAGE_MANUFACTURING_4, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_4, ManufacturingPage4_t, MPI_POINTER pManufacturingPage4_t; -#define MPI_MANUFACTURING4_PAGEVERSION (0x00) +#define MPI_MANUFACTURING4_PAGEVERSION (0x01) + +/* defines for the Flags field */ +#define MPI_MANPAGE4_IR_NO_MIX_SAS_SATA (0x01) + + +typedef struct _CONFIG_PAGE_MANUFACTURING_5 +{ + fCONFIG_PAGE_HEADER Header; /* 00h */ + U64 BaseWWID; /* 04h */ +} fCONFIG_PAGE_MANUFACTURING_5, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_5, + ManufacturingPage5_t, MPI_POINTER pManufacturingPage5_t; + +#define MPI_MANUFACTURING5_PAGEVERSION (0x00) + + +typedef struct _CONFIG_PAGE_MANUFACTURING_6 +{ + fCONFIG_PAGE_HEADER Header; /* 00h */ + U32 ProductSpecificInfo;/* 04h */ +} fCONFIG_PAGE_MANUFACTURING_6, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_6, + ManufacturingPage6_t, MPI_POINTER pManufacturingPage6_t; + +#define MPI_MANUFACTURING6_PAGEVERSION (0x00) /**************************************************************************** @@ -414,16 +497,18 @@ } fCONFIG_PAGE_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_IO_UNIT_1, IOUnitPage1_t, MPI_POINTER pIOUnitPage1_t; -#define MPI_IOUNITPAGE1_PAGEVERSION (0x00) +#define MPI_IOUNITPAGE1_PAGEVERSION (0x01) /* IO Unit Page 1 Flags defines */ - #define MPI_IOUNITPAGE1_MULTI_FUNCTION (0x00000000) #define MPI_IOUNITPAGE1_SINGLE_FUNCTION (0x00000001) #define MPI_IOUNITPAGE1_MULTI_PATHING (0x00000002) #define MPI_IOUNITPAGE1_SINGLE_PATHING (0x00000000) +#define MPI_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID (0x00000004) +#define MPI_IOUNITPAGE1_DISABLE_QUEUE_FULL_HANDLING (0x00000020) #define MPI_IOUNITPAGE1_DISABLE_IR (0x00000040) #define MPI_IOUNITPAGE1_FORCE_32 (0x00000080) +#define MPI_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE (0x00000100) typedef struct _MPI_ADAPTER_INFO @@ -453,6 +538,11 @@ #define MPI_IOUNITPAGE2_FLAGS_COLOR_VIDEO_DISABLE (0x00000008) #define MPI_IOUNITPAGE2_FLAGS_DONT_HOOK_INT_40 (0x00000010) +#define MPI_IOUNITPAGE2_FLAGS_DEV_LIST_DISPLAY_MASK (0x000000E0) +#define MPI_IOUNITPAGE2_FLAGS_INSTALLED_DEV_DISPLAY (0x00000000) +#define MPI_IOUNITPAGE2_FLAGS_ADAPTER_DISPLAY (0x00000020) +#define MPI_IOUNITPAGE2_FLAGS_ADAPTER_DEV_DISPLAY (0x00000040) + /* * Host code (drivers, BIOS, utilities, etc.) should leave this define set to @@ -515,6 +605,12 @@ #define MPI_IOCPAGE1_PAGEVERSION (0x01) +/* defines for the Flags field */ +#define MPI_IOCPAGE1_EEDP_HOST_SUPPORTS_DIF (0x08000000) +#define MPI_IOCPAGE1_EEDP_MODE_MASK (0x07000000) +#define MPI_IOCPAGE1_EEDP_MODE_OFF (0x00000000) +#define MPI_IOCPAGE1_EEDP_MODE_T10 (0x01000000) +#define MPI_IOCPAGE1_EEDP_MODE_LSI_1 (0x02000000) #define MPI_IOCPAGE1_REPLY_COALESCING (0x00000001) #define MPI_IOCPAGE1_PCISLOTNUM_UNKNOWN (0xFF) @@ -655,7 +751,7 @@ typedef struct _CONFIG_PAGE_IOC_5 { - fCONFIG_PAGE_HEADER Header; /* 00h */ + fCONFIG_PAGE_HEADER Header; /* 00h */ U32 Reserved1; /* 04h */ U8 NumHotSpares; /* 08h */ U8 Reserved2; /* 09h */ @@ -667,6 +763,57 @@ #define MPI_IOCPAGE5_PAGEVERSION (0x00) +/**************************************************************************** +* BIOS Port Config Pages +****************************************************************************/ + +typedef struct _CONFIG_PAGE_BIOS_1 +{ + fCONFIG_PAGE_HEADER Header; /* 00h */ + U32 BiosOptions; /* 04h */ + U32 IOCSettings; /* 08h */ + U32 Reserved1; /* 0Ch */ + U32 DeviceSettings; /* 10h */ + U16 NumberOfDevices; /* 14h */ + U16 Reserved2; /* 16h */ + U16 IOTimeoutBlockDevicesNonRM; /* 18h */ + U16 IOTimeoutSequential; /* 1Ah */ + U16 IOTimeoutOther; /* 1Ch */ + U16 IOTimeoutBlockDevicesRM; /* 1Eh */ +} fCONFIG_PAGE_BIOS_1, MPI_POINTER PTR_CONFIG_PAGE_BIOS_1, + BIOSPage1_t, MPI_POINTER pBIOSPage1_t; + +#define MPI_BIOSPAGE1_PAGEVERSION (0x00) + +/* values for the BiosOptions field */ +#define MPI_BIOSPAGE1_OPTIONS_SPI_ENABLE (0x00000400) +#define MPI_BIOSPAGE1_OPTIONS_FC_ENABLE (0x00000200) +#define MPI_BIOSPAGE1_OPTIONS_SAS_ENABLE (0x00000100) +#define MPI_BIOSPAGE1_OPTIONS_DISABLE_BIOS (0x00000001) + +/* values for the IOCSettings field */ +#define MPI_BIOSPAGE1_IOCSET_MASK_SPINUP_DELAY (0x00000F00) +#define MPI_BIOSPAGE1_IOCSET_SHIFT_SPINUP_DELAY (8) + +#define MPI_BIOSPAGE1_IOCSET_MASK_RM_SETTING (0x000000C0) +#define MPI_BIOSPAGE1_IOCSET_NONE_RM_SETTING (0x00000000) +#define MPI_BIOSPAGE1_IOCSET_BOOT_RM_SETTING (0x00000040) +#define MPI_BIOSPAGE1_IOCSET_MEDIA_RM_SETTING (0x00000080) + +#define MPI_BIOSPAGE1_IOCSET_MASK_ADAPTER_SUPPORT (0x00000030) +#define MPI_BIOSPAGE1_IOCSET_NO_SUPPORT (0x00000000) +#define MPI_BIOSPAGE1_IOCSET_BIOS_SUPPORT (0x00000010) +#define MPI_BIOSPAGE1_IOCSET_OS_SUPPORT (0x00000020) +#define MPI_BIOSPAGE1_IOCSET_ALL_SUPPORT (0x00000030) + +#define MPI_BIOSPAGE1_IOCSET_ALTERNATE_CHS (0x00000008) + +/* values for the DeviceSettings field */ +#define MPI_BIOSPAGE1_DEVSET_DISABLE_SEQ_LUN (0x00000008) +#define MPI_BIOSPAGE1_DEVSET_DISABLE_RM_LUN (0x00000004) +#define MPI_BIOSPAGE1_DEVSET_DISABLE_NON_RM_LUN (0x00000002) +#define MPI_BIOSPAGE1_DEVSET_DISABLE_OTHER_LUN (0x00000001) + /**************************************************************************** * SCSI Port Config Pages @@ -686,7 +833,27 @@ #define MPI_SCSIPORTPAGE0_CAP_DT (0x00000002) #define MPI_SCSIPORTPAGE0_CAP_QAS (0x00000004) #define MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK (0x0000FF00) +#define MPI_SCSIPORTPAGE0_SYNC_ASYNC (0x00) +#define MPI_SCSIPORTPAGE0_SYNC_5 (0x32) +#define MPI_SCSIPORTPAGE0_SYNC_10 (0x19) +#define MPI_SCSIPORTPAGE0_SYNC_20 (0x0C) +#define MPI_SCSIPORTPAGE0_SYNC_33_33 (0x0B) +#define MPI_SCSIPORTPAGE0_SYNC_40 (0x0A) +#define MPI_SCSIPORTPAGE0_SYNC_80 (0x09) +#define MPI_SCSIPORTPAGE0_SYNC_160 (0x08) +#define MPI_SCSIPORTPAGE0_SYNC_UNKNOWN (0xFF) + +#define MPI_SCSIPORTPAGE0_CAP_SHIFT_MIN_SYNC_PERIOD (8) +#define MPI_SCSIPORTPAGE0_CAP_GET_MIN_SYNC_PERIOD(Cap) \ + ( ((Cap) & MPI_SCSIPORTPAGE0_CAP_MASK_MIN_SYNC_PERIOD) \ + >> MPI_SCSIPORTPAGE0_CAP_SHIFT_MIN_SYNC_PERIOD \ + ) #define MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK (0x00FF0000) +#define MPI_SCSIPORTPAGE0_CAP_SHIFT_MAX_SYNC_OFFSET (16) +#define MPI_SCSIPORTPAGE0_CAP_GET_MAX_SYNC_OFFSET(Cap) \ + ( ((Cap) & MPI_SCSIPORTPAGE0_CAP_MASK_MAX_SYNC_OFFSET) \ + >> MPI_SCSIPORTPAGE0_CAP_SHIFT_MAX_SYNC_OFFSET \ + ) #define MPI_SCSIPORTPAGE0_CAP_WIDE (0x20000000) #define MPI_SCSIPORTPAGE0_CAP_AIP (0x80000000) @@ -694,6 +861,10 @@ #define MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD (0x01) #define MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE (0x02) #define MPI_SCSIPORTPAGE0_PHY_SIGNAL_LVD (0x03) +#define MPI_SCSIPORTPAGE0_PHY_MASK_CONNECTED_ID (0xFF000000) +#define MPI_SCSIPORTPAGE0_PHY_SHIFT_CONNECTED_ID (24) +#define MPI_SCSIPORTPAGE0_PHY_BUS_FREE_CONNECTED_ID (0xFE) +#define MPI_SCSIPORTPAGE0_PHY_UNKNOWN_CONNECTED_ID (0xFF) typedef struct _CONFIG_PAGE_SCSI_PORT_1 @@ -701,13 +872,22 @@ fCONFIG_PAGE_HEADER Header; /* 00h */ U32 Configuration; /* 04h */ U32 OnBusTimerValue; /* 08h */ + U8 TargetConfig; /* 0Ch */ + U8 Reserved1; /* 0Dh */ + U16 IDConfig; /* 0Eh */ } fCONFIG_PAGE_SCSI_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_1, SCSIPortPage1_t, MPI_POINTER pSCSIPortPage1_t; -#define MPI_SCSIPORTPAGE1_PAGEVERSION (0x02) +#define MPI_SCSIPORTPAGE1_PAGEVERSION (0x03) +/* Configuration values */ #define MPI_SCSIPORTPAGE1_CFG_PORT_SCSI_ID_MASK (0x000000FF) #define MPI_SCSIPORTPAGE1_CFG_PORT_RESPONSE_ID_MASK (0xFFFF0000) +#define MPI_SCSIPORTPAGE1_CFG_SHIFT_PORT_RESPONSE_ID (16) + +/* TargetConfig values */ +#define MPI_SCSIPORTPAGE1_TARGCONFIG_TARG_ONLY (0x01) +#define MPI_SCSIPORTPAGE1_TARGCONFIG_INIT_TARG (0x02) typedef struct _MPI_DEVICE_INFO @@ -727,13 +907,21 @@ } fCONFIG_PAGE_SCSI_PORT_2, MPI_POINTER PTR_CONFIG_PAGE_SCSI_PORT_2, SCSIPortPage2_t, MPI_POINTER pSCSIPortPage2_t; -#define MPI_SCSIPORTPAGE2_PAGEVERSION (0x01) +#define MPI_SCSIPORTPAGE2_PAGEVERSION (0x02) +/* PortFlags values */ #define MPI_SCSIPORTPAGE2_PORT_FLAGS_SCAN_HIGH_TO_LOW (0x00000001) #define MPI_SCSIPORTPAGE2_PORT_FLAGS_AVOID_SCSI_RESET (0x00000004) #define MPI_SCSIPORTPAGE2_PORT_FLAGS_ALTERNATE_CHS (0x00000008) #define MPI_SCSIPORTPAGE2_PORT_FLAGS_TERMINATION_DISABLE (0x00000010) +#define MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK (0x00000060) +#define MPI_SCSIPORTPAGE2_PORT_FLAGS_FULL_DV (0x00000000) +#define MPI_SCSIPORTPAGE2_PORT_FLAGS_BASIC_DV_ONLY (0x00000020) +#define MPI_SCSIPORTPAGE2_PORT_FLAGS_OFF_DV (0x00000060) + + +/* PortSettings values */ #define MPI_SCSIPORTPAGE2_PORT_HOST_ID_MASK (0x0000000F) #define MPI_SCSIPORTPAGE2_PORT_MASK_INIT_HBA (0x00000030) #define MPI_SCSIPORTPAGE2_PORT_DISABLE_INIT_HBA (0x00000000) @@ -741,7 +929,11 @@ #define MPI_SCSIPORTPAGE2_PORT_OS_INIT_HBA (0x00000020) #define MPI_SCSIPORTPAGE2_PORT_BIOS_OS_INIT_HBA (0x00000030) #define MPI_SCSIPORTPAGE2_PORT_REMOVABLE_MEDIA (0x000000C0) +#define MPI_SCSIPORTPAGE2_PORT_RM_NONE (0x00000000) +#define MPI_SCSIPORTPAGE2_PORT_RM_BOOT_ONLY (0x00000040) +#define MPI_SCSIPORTPAGE2_PORT_RM_WITH_MEDIA (0x00000080) #define MPI_SCSIPORTPAGE2_PORT_SPINUP_DELAY_MASK (0x00000F00) +#define MPI_SCSIPORTPAGE2_PORT_SHIFT_SPINUP_DELAY (8) #define MPI_SCSIPORTPAGE2_PORT_MASK_NEGO_MASTER_SETTINGS (0x00003000) #define MPI_SCSIPORTPAGE2_PORT_NEGO_MASTER_SETTINGS (0x00000000) #define MPI_SCSIPORTPAGE2_PORT_NONE_MASTER_SETTINGS (0x00001000) @@ -778,7 +970,9 @@ #define MPI_SCSIDEVPAGE0_NP_RTI (0x00000040) #define MPI_SCSIDEVPAGE0_NP_PCOMP_EN (0x00000080) #define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK (0x0000FF00) +#define MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_PERIOD (8) #define MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK (0x00FF0000) +#define MPI_SCSIDEVPAGE0_NP_SHIFT_SYNC_OFFSET (16) #define MPI_SCSIDEVPAGE0_NP_WIDE (0x20000000) #define MPI_SCSIDEVPAGE0_NP_AIP (0x80000000) @@ -808,7 +1002,9 @@ #define MPI_SCSIDEVPAGE1_RP_RTI (0x00000040) #define MPI_SCSIDEVPAGE1_RP_PCOMP_EN (0x00000080) #define MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK (0x0000FF00) +#define MPI_SCSIDEVPAGE1_RP_SHIFT_MIN_SYNC_PERIOD (8) #define MPI_SCSIDEVPAGE1_RP_MAX_SYNC_OFFSET_MASK (0x00FF0000) +#define MPI_SCSIDEVPAGE1_RP_SHIFT_MAX_SYNC_OFFSET (16) #define MPI_SCSIDEVPAGE1_RP_WIDE (0x20000000) #define MPI_SCSIDEVPAGE1_RP_AIP (0x80000000) @@ -915,7 +1111,7 @@ #define MPI_FCPORTPAGE0_FLAGS_ALIAS_ALPA_SUPPORTED (0x00000010) #define MPI_FCPORTPAGE0_FLAGS_ALIAS_WWN_SUPPORTED (0x00000020) -#define MPI_FCPORTPAGE0_FLAGS_FABRIC_WWN_VALID (0x00000030) +#define MPI_FCPORTPAGE0_FLAGS_FABRIC_WWN_VALID (0x00000040) #define MPI_FCPORTPAGE0_FLAGS_ATTACH_TYPE_MASK (0x00000F00) #define MPI_FCPORTPAGE0_FLAGS_ATTACH_NO_INIT (0x00000000) @@ -954,13 +1150,19 @@ #define MPI_FCPORTPAGE0_SUPPORT_CLASS_2 (0x00000002) #define MPI_FCPORTPAGE0_SUPPORT_CLASS_3 (0x00000004) -#define MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED (0x00000001) /* (SNIA)HBA_PORTSPEED_1GBIT 1 1 GBit/sec */ -#define MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED (0x00000002) /* (SNIA)HBA_PORTSPEED_2GBIT 2 2 GBit/sec */ -#define MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED (0x00000004) /* (SNIA)HBA_PORTSPEED_10GBIT 4 10 GBit/sec */ +#define MPI_FCPORTPAGE0_SUPPORT_SPEED_UKNOWN (0x00000000) /* (SNIA)HBA_PORTSPEED_UNKNOWN 0 Unknown - transceiver incapable of reporting */ +#define MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED (0x00000001) /* (SNIA)HBA_PORTSPEED_1GBIT 1 1 GBit/sec */ +#define MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED (0x00000002) /* (SNIA)HBA_PORTSPEED_2GBIT 2 2 GBit/sec */ +#define MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED (0x00000004) /* (SNIA)HBA_PORTSPEED_10GBIT 4 10 GBit/sec */ +#define MPI_FCPORTPAGE0_SUPPORT_4GBIT_SPEED (0x00000008) /* (SNIA)HBA_PORTSPEED_4GBIT 8 4 GBit/sec */ +#define MPI_FCPORTPAGE0_CURRENT_SPEED_UKNOWN MPI_FCPORTPAGE0_SUPPORT_SPEED_UKNOWN #define MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED #define MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED #define MPI_FCPORTPAGE0_CURRENT_SPEED_10GBIT MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED +#define MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT MPI_FCPORTPAGE0_SUPPORT_4GBIT_SPEED +#define MPI_FCPORTPAGE0_CURRENT_SPEED_NOT_NEGOTIATED (0x00008000) /* (SNIA)HBA_PORTSPEED_NOT_NEGOTIATED (1<<15) Speed not established */ + typedef struct _CONFIG_PAGE_FC_PORT_1 @@ -974,15 +1176,25 @@ U8 TopologyConfig; /* 1Ah */ U8 AltConnector; /* 1Bh */ U8 NumRequestedAliases; /* 1Ch */ - U8 Reserved1; /* 1Dh */ - U16 Reserved2; /* 1Eh */ + U8 RR_TOV; /* 1Dh */ + U8 InitiatorDeviceTimeout; /* 1Eh */ + U8 InitiatorIoPendTimeout; /* 1Fh */ } fCONFIG_PAGE_FC_PORT_1, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_1, FCPortPage1_t, MPI_POINTER pFCPortPage1_t; -#define MPI_FCPORTPAGE1_PAGEVERSION (0x04) +#define MPI_FCPORTPAGE1_PAGEVERSION (0x06) #define MPI_FCPORTPAGE1_FLAGS_EXT_FCP_STATUS_EN (0x08000000) #define MPI_FCPORTPAGE1_FLAGS_IMMEDIATE_ERROR_REPLY (0x04000000) +#define MPI_FCPORTPAGE1_FLAGS_FORCE_USE_NOSEEPROM_WWNS (0x02000000) +#define MPI_FCPORTPAGE1_FLAGS_VERBOSE_RESCAN_EVENTS (0x01000000) +#define MPI_FCPORTPAGE1_FLAGS_TARGET_MODE_OXID (0x00800000) +#define MPI_FCPORTPAGE1_FLAGS_PORT_OFFLINE (0x00400000) +#define MPI_FCPORTPAGE1_FLAGS_SOFT_ALPA_FALLBACK (0x00200000) +#define MPI_FCPORTPAGE1_FLAGS_MASK_RR_TOV_UNITS (0x00000070) +#define MPI_FCPORTPAGE1_FLAGS_SUPPRESS_PROT_REG (0x00000008) +#define MPI_FCPORTPAGE1_FLAGS_PLOGI_ON_LOGO (0x00000004) +#define MPI_FCPORTPAGE1_FLAGS_MAINTAIN_LOGINS (0x00000002) #define MPI_FCPORTPAGE1_FLAGS_SORT_BY_DID (0x00000001) #define MPI_FCPORTPAGE1_FLAGS_SORT_BY_WWN (0x00000000) @@ -993,6 +1205,11 @@ #define MPI_FCPORTPAGE1_FLAGS_PROT_LAN ((U32)MPI_PORTFACTS_PROTOCOL_LAN << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT) #define MPI_FCPORTPAGE1_FLAGS_PROT_LOGBUSADDR ((U32)MPI_PORTFACTS_PROTOCOL_LOGBUSADDR << MPI_FCPORTPAGE1_FLAGS_PROT_SHIFT) +#define MPI_FCPORTPAGE1_FLAGS_NONE_RR_TOV_UNITS (0x00000000) +#define MPI_FCPORTPAGE1_FLAGS_THOUSANDTH_RR_TOV_UNITS (0x00000010) +#define MPI_FCPORTPAGE1_FLAGS_TENTH_RR_TOV_UNITS (0x00000030) +#define MPI_FCPORTPAGE1_FLAGS_TEN_RR_TOV_UNITS (0x00000050) + #define MPI_FCPORTPAGE1_HARD_ALPA_NOT_USED (0xFF) #define MPI_FCPORTPAGE1_LCONFIG_SPEED_MASK (0x0F) @@ -1009,6 +1226,8 @@ #define MPI_FCPORTPAGE1_ALT_CONN_UNKNOWN (0x00) +#define MPI_FCPORTPAGE1_INITIATOR_DEV_TIMEOUT_MASK (0x7F) + typedef struct _CONFIG_PAGE_FC_PORT_2 { @@ -1108,12 +1327,13 @@ } fCONFIG_PAGE_FC_PORT_5, MPI_POINTER PTR_CONFIG_PAGE_FC_PORT_5, FCPortPage5_t, MPI_POINTER pFCPortPage5_t; -#define MPI_FCPORTPAGE5_PAGEVERSION (0x01) +#define MPI_FCPORTPAGE5_PAGEVERSION (0x02) #define MPI_FCPORTPAGE5_FLAGS_ALPA_ACQUIRED (0x01) #define MPI_FCPORTPAGE5_FLAGS_HARD_ALPA (0x02) #define MPI_FCPORTPAGE5_FLAGS_HARD_WWNN (0x04) #define MPI_FCPORTPAGE5_FLAGS_HARD_WWPN (0x08) +#define MPI_FCPORTPAGE5_FLAGS_DISABLE (0x10) typedef struct _CONFIG_PAGE_FC_PORT_6 { @@ -1322,7 +1542,7 @@ U8 Flags; /* 19h */ U16 BBCredit; /* 1Ah */ U16 MaxRxFrameSize; /* 1Ch */ - U8 Reserved1; /* 1Eh */ + U8 ADISCHardALPA; /* 1Eh */ U8 PortNumber; /* 1Fh */ U8 FcPhLowestVersion; /* 20h */ U8 FcPhHighestVersion; /* 21h */ @@ -1331,13 +1551,16 @@ } fCONFIG_PAGE_FC_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_FC_DEVICE_0, FCDevicePage0_t, MPI_POINTER pFCDevicePage0_t; -#define MPI_FC_DEVICE_PAGE0_PAGEVERSION (0x02) +#define MPI_FC_DEVICE_PAGE0_PAGEVERSION (0x03) #define MPI_FC_DEVICE_PAGE0_FLAGS_TARGETID_BUS_VALID (0x01) +#define MPI_FC_DEVICE_PAGE0_FLAGS_PLOGI_INVALID (0x02) +#define MPI_FC_DEVICE_PAGE0_FLAGS_PRLI_INVALID (0x04) #define MPI_FC_DEVICE_PAGE0_PROT_IP (0x01) #define MPI_FC_DEVICE_PAGE0_PROT_FCP_TARGET (0x02) #define MPI_FC_DEVICE_PAGE0_PROT_FCP_INITIATOR (0x04) +#define MPI_FC_DEVICE_PAGE0_PROT_FCP_RETRY (0x08) #define MPI_FC_DEVICE_PAGE0_PGAD_PORT_MASK (MPI_FC_DEVICE_PGAD_PORT_MASK) #define MPI_FC_DEVICE_PAGE0_PGAD_FORM_MASK (MPI_FC_DEVICE_PGAD_FORM_MASK) @@ -1348,6 +1571,7 @@ #define MPI_FC_DEVICE_PAGE0_PGAD_BUS_SHIFT (MPI_FC_DEVICE_PGAD_BT_BUS_SHIFT) #define MPI_FC_DEVICE_PAGE0_PGAD_TID_MASK (MPI_FC_DEVICE_PGAD_BT_TID_MASK) +#define MPI_FC_DEVICE_PAGE0_HARD_ALPA_UNKNOWN (0xFF) /**************************************************************************** * RAID Volume Config Pages @@ -1564,6 +1788,318 @@ #define MPI_LAN_PAGE1_DEV_STATE_RESET (0x00) #define MPI_LAN_PAGE1_DEV_STATE_OPERATIONAL (0x01) + + +/**************************************************************************** +* Inband Config Pages +****************************************************************************/ + +typedef struct _CONFIG_PAGE_INBAND_0 +{ + fCONFIG_PAGE_HEADER Header; /* 00h */ + MPI_VERSION_FORMAT InbandVersion; /* 04h */ + U16 MaximumBuffers; /* 08h */ + U16 Reserved1; /* 0Ah */ +} fCONFIG_PAGE_INBAND_0, MPI_POINTER PTR_CONFIG_PAGE_INBAND_0, + InbandPage0_t, MPI_POINTER pInbandPage0_t; + +#define MPI_INBAND_PAGEVERSION (0x00) + + + +/**************************************************************************** +* SAS IO Unit Config Pages +****************************************************************************/ + +typedef struct _MPI_SAS_IO_UNIT0_PHY_DATA +{ + U8 Port; /* 00h */ + U8 PortFlags; /* 01h */ + U8 PhyFlags; /* 02h */ + U8 NegotiatedLinkRate; /* 03h */ + U32 ControllerPhyDeviceInfo;/* 04h */ + U16 AttachedDeviceHandle; /* 08h */ + U16 ControllerDevHandle; /* 0Ah */ + U32 Reserved2; /* 0Ch */ +} MPI_SAS_IO_UNIT0_PHY_DATA, MPI_POINTER PTR_MPI_SAS_IO_UNIT0_PHY_DATA, + SasIOUnit0PhyData, MPI_POINTER pSasIOUnit0PhyData; + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI_SAS_IOUNIT0_PHY_MAX +#define MPI_SAS_IOUNIT0_PHY_MAX (1) +#endif + +typedef struct _CONFIG_PAGE_SAS_IO_UNIT_0 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U8 NumPhys; /* 0Ch */ + U8 Reserved2; /* 0Dh */ + U16 Reserved3; /* 0Eh */ + MPI_SAS_IO_UNIT0_PHY_DATA PhyData[MPI_SAS_IOUNIT0_PHY_MAX]; /* 10h */ +} fCONFIG_PAGE_SAS_IO_UNIT_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_0, + SasIOUnitPage0_t, MPI_POINTER pSasIOUnitPage0_t; + +#define MPI_SASIOUNITPAGE0_PAGEVERSION (0x00) + +/* values for SAS IO Unit Page 0 PortFlags */ +#define MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS (0x08) +#define MPI_SAS_IOUNIT0_PORT_FLAGS_0_TARGET_IOC_NUM (0x00) +#define MPI_SAS_IOUNIT0_PORT_FLAGS_1_TARGET_IOC_NUM (0x04) +#define MPI_SAS_IOUNIT0_PORT_FLAGS_WAIT_FOR_PORTENABLE (0x02) +#define MPI_SAS_IOUNIT0_PORT_FLAGS_AUTO_PORT_CONFIG (0x01) + +/* values for SAS IO Unit Page 0 PhyFlags */ +#define MPI_SAS_IOUNIT0_PHY_FLAGS_PHY_DISABLED (0x04) +#define MPI_SAS_IOUNIT0_PHY_FLAGS_TX_INVERT (0x02) +#define MPI_SAS_IOUNIT0_PHY_FLAGS_RX_INVERT (0x01) + +/* values for SAS IO Unit Page 0 NegotiatedLinkRate */ +#define MPI_SAS_IOUNIT0_RATE_UNKNOWN (0x00) +#define MPI_SAS_IOUNIT0_RATE_PHY_DISABLED (0x01) +#define MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION (0x02) +#define MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE (0x03) +#define MPI_SAS_IOUNIT0_RATE_1_5 (0x08) +#define MPI_SAS_IOUNIT0_RATE_3_0 (0x09) + +/* see mpi_sas.h for values for SAS IO Unit Page 0 ControllerPhyDeviceInfo values */ + + +typedef struct _MPI_SAS_IO_UNIT1_PHY_DATA +{ + U8 Port; /* 00h */ + U8 PortFlags; /* 01h */ + U8 PhyFlags; /* 02h */ + U8 MaxMinLinkRate; /* 03h */ + U32 ControllerPhyDeviceInfo;/* 04h */ + U32 Reserved1; /* 08h */ +} MPI_SAS_IO_UNIT1_PHY_DATA, MPI_POINTER PTR_MPI_SAS_IO_UNIT1_PHY_DATA, + SasIOUnit1PhyData, MPI_POINTER pSasIOUnit1PhyData; + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check Header.PageLength at runtime. + */ +#ifndef MPI_SAS_IOUNIT1_PHY_MAX +#define MPI_SAS_IOUNIT1_PHY_MAX (1) +#endif + +typedef struct _CONFIG_PAGE_SAS_IO_UNIT_1 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U8 NumPhys; /* 0Ch */ + U8 Reserved2; /* 0Dh */ + U16 Reserved3; /* 0Eh */ + MPI_SAS_IO_UNIT1_PHY_DATA PhyData[MPI_SAS_IOUNIT1_PHY_MAX]; /* 10h */ +} fCONFIG_PAGE_SAS_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_1, + SasIOUnitPage1_t, MPI_POINTER pSasIOUnitPage1_t; + +#define MPI_SASIOUNITPAGE1_PAGEVERSION (0x00) + +/* values for SAS IO Unit Page 0 PortFlags */ +#define MPI_SAS_IOUNIT1_PORT_FLAGS_0_TARGET_IOC_NUM (0x00) +#define MPI_SAS_IOUNIT1_PORT_FLAGS_1_TARGET_IOC_NUM (0x04) +#define MPI_SAS_IOUNIT1_PORT_FLAGS_WAIT_FOR_PORTENABLE (0x02) +#define MPI_SAS_IOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG (0x01) + +/* values for SAS IO Unit Page 0 PhyFlags */ +#define MPI_SAS_IOUNIT1_PHY_FLAGS_PHY_DISABLE (0x04) +#define MPI_SAS_IOUNIT1_PHY_FLAGS_TX_INVERT (0x02) +#define MPI_SAS_IOUNIT1_PHY_FLAGS_RX_INVERT (0x01) + +/* values for SAS IO Unit Page 0 MaxMinLinkRate */ +#define MPI_SAS_IOUNIT1_MAX_RATE_MASK (0xF0) +#define MPI_SAS_IOUNIT1_MAX_RATE_1_5 (0x80) +#define MPI_SAS_IOUNIT1_MAX_RATE_3_0 (0x90) +#define MPI_SAS_IOUNIT1_MIN_RATE_MASK (0x0F) +#define MPI_SAS_IOUNIT1_MIN_RATE_1_5 (0x08) +#define MPI_SAS_IOUNIT1_MIN_RATE_3_0 (0x09) + +/* see mpi_sas.h for values for SAS IO Unit Page 1 ControllerPhyDeviceInfo values */ + + +typedef struct _CONFIG_PAGE_SAS_IO_UNIT_2 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U16 MaxPersistentIDs; /* 0Ch */ + U16 NumPersistentIDsUsed; /* 0Eh */ + U8 Status; /* 10h */ + U8 Flags; /* 11h */ + U16 Reserved2; /* 12h */ +} fCONFIG_PAGE_SAS_IO_UNIT_2, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_2, + SasIOUnitPage2_t, MPI_POINTER pSasIOUnitPage2_t; + +#define MPI_SASIOUNITPAGE2_PAGEVERSION (0x00) + +/* values for SAS IO Unit Page 2 Status field */ +#define MPI_SAS_IOUNIT2_STATUS_DISABLED_PERSISTENT_MAPPINGS (0x02) +#define MPI_SAS_IOUNIT2_STATUS_FULL_PERSISTENT_MAPPINGS (0x01) + +/* values for SAS IO Unit Page 2 Flags field */ +#define MPI_SAS_IOUNIT2_FLAGS_DISABLE_PERSISTENT_MAPPINGS (0x01) + + +typedef struct _CONFIG_PAGE_SAS_IO_UNIT_3 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U32 MaxInvalidDwordCount; /* 0Ch */ + U32 InvalidDwordCountTime; /* 10h */ + U32 MaxRunningDisparityErrorCount; /* 14h */ + U32 RunningDisparityErrorTime; /* 18h */ + U32 MaxLossDwordSynchCount; /* 1Ch */ + U32 LossDwordSynchCountTime; /* 20h */ + U32 MaxPhyResetProblemCount; /* 24h */ + U32 PhyResetProblemTime; /* 28h */ +} fCONFIG_PAGE_SAS_IO_UNIT_3, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_3, + SasIOUnitPage3_t, MPI_POINTER pSasIOUnitPage3_t; + +#define MPI_SASIOUNITPAGE3_PAGEVERSION (0x00) + + +typedef struct _CONFIG_PAGE_SAS_EXPANDER_0 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U64 SASAddress; /* 0Ch */ + U32 Reserved2; /* 14h */ + U16 DevHandle; /* 18h */ + U16 ParentDevHandle; /* 1Ah */ + U16 ExpanderChangeCount; /* 1Ch */ + U16 ExpanderRouteIndexes; /* 1Eh */ + U8 NumPhys; /* 20h */ + U8 SASLevel; /* 21h */ + U8 Flags; /* 22h */ + U8 Reserved3; /* 23h */ +} fCONFIG_PAGE_SAS_EXPANDER_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_EXPANDER_0, + SasExpanderPage0_t, MPI_POINTER pSasExpanderPage0_t; + +#define MPI_SASEXPANDER0_PAGEVERSION (0x00) + +/* values for SAS Expander Page 0 Flags field */ +#define MPI_SAS_EXPANDER0_FLAGS_ROUTE_TABLE_CONFIG (0x02) +#define MPI_SAS_EXPANDER0_FLAGS_CONFIG_IN_PROGRESS (0x01) + + +typedef struct _CONFIG_PAGE_SAS_DEVICE_0 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U64 SASAddress; /* 0Ch */ + U32 Reserved2; /* 14h */ + U16 DevHandle; /* 18h */ + U8 TargetID; /* 1Ah */ + U8 Bus; /* 1Bh */ + U32 DeviceInfo; /* 1Ch */ + U16 Flags; /* 20h */ + U8 PhysicalPort; /* 22h */ + U8 Reserved3; /* 23h */ +} fCONFIG_PAGE_SAS_DEVICE_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_DEVICE_0, + SasDevicePage0_t, MPI_POINTER pSasDevicePage0_t; + +#define MPI_SASDEVICE0_PAGEVERSION (0x00) + +/* values for SAS Device Page 0 Flags field */ +#define MPI_SAS_DEVICE0_FLAGS_MAPPING_PERSISTENT (0x04) +#define MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED (0x02) +#define MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x01) + +/* see mpi_sas.h for values for SAS Device Page 0 DeviceInfo values */ + + +typedef struct _CONFIG_PAGE_SAS_DEVICE_1 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U64 SASAddress; /* 0Ch */ + U32 Reserved2; /* 14h */ + U16 DevHandle; /* 18h */ + U8 TargetID; /* 1Ah */ + U8 Bus; /* 1Bh */ + U8 InitialRegDeviceFIS[20];/* 1Ch */ +} fCONFIG_PAGE_SAS_DEVICE_1, MPI_POINTER PTR_CONFIG_PAGE_SAS_DEVICE_1, + SasDevicePage1_t, MPI_POINTER pSasDevicePage1_t; + +#define MPI_SASDEVICE1_PAGEVERSION (0x00) + + +typedef struct _CONFIG_PAGE_SAS_PHY_0 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U64 SASAddress; /* 0Ch */ + U16 AttachedDevHandle; /* 14h */ + U8 AttachedPhyIdentifier; /* 16h */ + U8 Reserved2; /* 17h */ + U32 AttachedDeviceInfo; /* 18h */ + U8 ProgrammedLinkRate; /* 20h */ + U8 HwLinkRate; /* 21h */ + U8 ChangeCount; /* 22h */ + U8 Reserved3; /* 23h */ + U32 PhyInfo; /* 24h */ +} fCONFIG_PAGE_SAS_PHY_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_PHY_0, + SasPhyPage0_t, MPI_POINTER pSasPhyPage0_t; + +#define MPI_SASPHY0_PAGEVERSION (0x00) + +/* values for SAS PHY Page 0 ProgrammedLinkRate field */ +#define MPI_SAS_PHY0_PRATE_MAX_RATE_MASK (0xF0) +#define MPI_SAS_PHY0_PRATE_MAX_RATE_NOT_PROGRAMMABLE (0x00) +#define MPI_SAS_PHY0_PRATE_MAX_RATE_1_5 (0x80) +#define MPI_SAS_PHY0_PRATE_MAX_RATE_3_0 (0x90) +#define MPI_SAS_PHY0_PRATE_MIN_RATE_MASK (0x0F) +#define MPI_SAS_PHY0_PRATE_MIN_RATE_NOT_PROGRAMMABLE (0x00) +#define MPI_SAS_PHY0_PRATE_MIN_RATE_1_5 (0x08) +#define MPI_SAS_PHY0_PRATE_MIN_RATE_3_0 (0x09) + +/* values for SAS PHY Page 0 HwLinkRate field */ +#define MPI_SAS_PHY0_HWRATE_MAX_RATE_MASK (0xF0) +#define MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5 (0x80) +#define MPI_SAS_PHY0_HWRATE_MAX_RATE_3_0 (0x90) +#define MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK (0x0F) +#define MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5 (0x08) +#define MPI_SAS_PHY0_HWRATE_MIN_RATE_3_0 (0x09) + +/* values for SAS PHY Page 0 PhyInfo field */ +#define MPI_SAS_PHY0_PHYINFO_SATA_PORT_ACTIVE (0x00004000) +#define MPI_SAS_PHY0_PHYINFO_SATA_PORT_SELECTOR (0x00002000) +#define MPI_SAS_PHY0_PHYINFO_VIRTUAL_PHY (0x00001000) + +#define MPI_SAS_PHY0_PHYINFO_MASK_PARTIAL_PATHWAY_TIME (0x00000F00) +#define MPI_SAS_PHY0_PHYINFO_SHIFT_PARTIAL_PATHWAY_TIME (8) + +#define MPI_SAS_PHY0_PHYINFO_MASK_ROUTING_ATTRIBUTE (0x000000F0) +#define MPI_SAS_PHY0_PHYINFO_DIRECT_ROUTING (0x00000000) +#define MPI_SAS_PHY0_PHYINFO_SUBTRACTIVE_ROUTING (0x00000010) +#define MPI_SAS_PHY0_PHYINFO_TABLE_ROUTING (0x00000020) + +#define MPI_SAS_PHY0_PHYINFO_MASK_LINK_RATE (0x0000000F) +#define MPI_SAS_PHY0_PHYINFO_UNKNOWN_LINK_RATE (0x00000000) +#define MPI_SAS_PHY0_PHYINFO_PHY_DISABLED (0x00000001) +#define MPI_SAS_PHY0_PHYINFO_NEGOTIATION_FAILED (0x00000002) +#define MPI_SAS_PHY0_PHYINFO_SATA_OOB_COMPLETE (0x00000003) +#define MPI_SAS_PHY0_PHYINFO_RATE_1_5 (0x00000008) +#define MPI_SAS_PHY0_PHYINFO_RATE_3_0 (0x00000009) + + +typedef struct _CONFIG_PAGE_SAS_PHY_1 +{ + fCONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 08h */ + U32 InvalidDwordCount; /* 0Ch */ + U32 RunningDisparityErrorCount; /* 10h */ + U32 LossDwordSynchCount; /* 14h */ + U32 PhyResetProblemCount; /* 18h */ +} fCONFIG_PAGE_SAS_PHY_1, MPI_POINTER PTR_CONFIG_PAGE_SAS_PHY_1, + SasPhyPage1_t, MPI_POINTER pSasPhyPage1_t; + +#define MPI_SASPHY1_PAGEVERSION (0x00) + #endif diff -Nru a/drivers/message/fusion/lsi/mpi_fc.h b/drivers/message/fusion/lsi/mpi_fc.h --- a/drivers/message/fusion/lsi/mpi_fc.h Sun Mar 14 14:20:06 2004 +++ b/drivers/message/fusion/lsi/mpi_fc.h Sun Mar 14 14:20:06 2004 @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2002 LSI Logic Corporation. + * Copyright (c) 2000-2003 LSI Logic Corporation. * * - * Name: MPI_FC.H + * Name: mpi_fc.h * Title: MPI Fibre Channel messages and structures * Creation Date: June 12, 2000 * - * MPI_FC.H Version: 01.02.03 + * mpi_fc.h Version: 01.05.xx * * Version History * --------------- @@ -45,7 +45,7 @@ /***************************************************************************** * -* F C T a r g e t M o d e M e s s a g e s +* F C D i r e c t A c c e s s M e s s a g e s * *****************************************************************************/ @@ -334,6 +334,7 @@ FcPrimitiveSendRequest_t, MPI_POINTER pFcPrimitiveSendRequest_t; #define MPI_FC_PRIM_SEND_FLAGS_PORT_MASK (0x01) +#define MPI_FC_PRIM_SEND_FLAGS_ML_RESET_LINK (0x02) #define MPI_FC_PRIM_SEND_FLAGS_RESET_LINK (0x04) #define MPI_FC_PRIM_SEND_FLAGS_STOP_SEND (0x08) #define MPI_FC_PRIM_SEND_FLAGS_SEND_ONCE (0x10) diff -Nru a/drivers/message/fusion/lsi/mpi_inb.h b/drivers/message/fusion/lsi/mpi_inb.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/message/fusion/lsi/mpi_inb.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2003 LSI Logic Corporation. + * + * + * Name: mpi_inb.h + * Title: MPI Inband structures and definitions + * Creation Date: September 30, 2003 + * + * mpi_inb.h Version: 01.03.xx + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * ??-??-?? 01.03.01 Original release. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI_INB_H +#define MPI_INB_H + +/****************************************************************************** +* +* I n b a n d M e s s a g e s +* +*******************************************************************************/ + + +/****************************************************************************/ +/* Inband Buffer Post Request */ +/****************************************************************************/ + +typedef struct _MSG_INBAND_BUFFER_POST_REQUEST +{ + U8 Reserved1; /* 00h */ + U8 BufferCount; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 Reserved4; /* 0Ch */ + SGE_TRANS_SIMPLE_UNION SGL; /* 10h */ +} MSG_INBAND_BUFFER_POST_REQUEST, MPI_POINTER PTR_MSG_INBAND_BUFFER_POST_REQUEST, + MpiInbandBufferPostRequest_t , MPI_POINTER pMpiInbandBufferPostRequest_t; + + +typedef struct _WWN_FC_FORMAT +{ + U64 NodeName; /* 00h */ + U64 PortName; /* 08h */ +} WWN_FC_FORMAT, MPI_POINTER PTR_WWN_FC_FORMAT, + WwnFcFormat_t, MPI_POINTER pWwnFcFormat_t; + +typedef struct _WWN_SAS_FORMAT +{ + U64 WorldWideID; /* 00h */ + U32 Reserved1; /* 08h */ + U32 Reserved2; /* 0Ch */ +} WWN_SAS_FORMAT, MPI_POINTER PTR_WWN_SAS_FORMAT, + WwnSasFormat_t, MPI_POINTER pWwnSasFormat_t; + +typedef union _WWN_INBAND_FORMAT +{ + WWN_FC_FORMAT Fc; + WWN_SAS_FORMAT Sas; +} WWN_INBAND_FORMAT, MPI_POINTER PTR_WWN_INBAND_FORMAT, + WwnInbandFormat, MPI_POINTER pWwnInbandFormat; + + +/* Inband Buffer Post reply message */ + +typedef struct _MSG_INBAND_BUFFER_POST_REPLY +{ + U16 Reserved1; /* 00h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved4; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ + U32 TransferLength; /* 14h */ + U32 TransactionContext; /* 18h */ + WWN_INBAND_FORMAT Wwn; /* 1Ch */ + U32 IOCIdentifier[4]; /* 2Ch */ +} MSG_INBAND_BUFFER_POST_REPLY, MPI_POINTER PTR_MSG_INBAND_BUFFER_POST_REPLY, + MpiInbandBufferPostReply_t, MPI_POINTER pMpiInbandBufferPostReply_t; + + +/****************************************************************************/ +/* Inband Send Request */ +/****************************************************************************/ + +typedef struct _MSG_INBAND_SEND_REQUEST +{ + U16 Reserved1; /* 00h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 Reserved4; /* 0Ch */ + WWN_INBAND_FORMAT Wwn; /* 10h */ + U32 Reserved5; /* 20h */ + SGE_IO_UNION SGL; /* 24h */ +} MSG_INBAND_SEND_REQUEST, MPI_POINTER PTR_MSG_INBAND_SEND_REQUEST, + MpiInbandSendRequest_t , MPI_POINTER pMpiInbandSendRequest_t; + + +/* Inband Send reply message */ + +typedef struct _MSG_INBAND_SEND_REPLY +{ + U16 Reserved1; /* 00h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved4; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ + U32 ResponseLength; /* 14h */ +} MSG_INBAND_SEND_REPLY, MPI_POINTER PTR_MSG_INBAND_SEND_REPLY, + MpiInbandSendReply_t, MPI_POINTER pMpiInbandSendReply_t; + + +/****************************************************************************/ +/* Inband Response Request */ +/****************************************************************************/ + +typedef struct _MSG_INBAND_RSP_REQUEST +{ + U16 Reserved1; /* 00h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 Reserved4; /* 0Ch */ + WWN_INBAND_FORMAT Wwn; /* 10h */ + U32 IOCIdentifier[4]; /* 20h */ + U32 ResponseLength; /* 30h */ + SGE_IO_UNION SGL; /* 34h */ +} MSG_INBAND_RSP_REQUEST, MPI_POINTER PTR_MSG_INBAND_RSP_REQUEST, + MpiInbandRspRequest_t , MPI_POINTER pMpiInbandRspRequest_t; + + +/* Inband Response reply message */ + +typedef struct _MSG_INBAND_RSP_REPLY +{ + U16 Reserved1; /* 00h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved4; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ +} MSG_INBAND_RSP_REPLY, MPI_POINTER PTR_MSG_INBAND_RSP_REPLY, + MpiInbandRspReply_t, MPI_POINTER pMpiInbandRspReply_t; + + +/****************************************************************************/ +/* Inband Abort Request */ +/****************************************************************************/ + +typedef struct _MSG_INBAND_ABORT_REQUEST +{ + U8 Reserved1; /* 00h */ + U8 AbortType; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 Reserved4; /* 0Ch */ + U32 ContextToAbort; /* 10h */ +} MSG_INBAND_ABORT_REQUEST, MPI_POINTER PTR_MSG_INBAND_ABORT_REQUEST, + MpiInbandAbortRequest_t , MPI_POINTER pMpiInbandAbortRequest_t; + +#define MPI_INBAND_ABORT_TYPE_ALL_BUFFERS (0x00) +#define MPI_INBAND_ABORT_TYPE_EXACT_BUFFER (0x01) +#define MPI_INBAND_ABORT_TYPE_SEND_REQUEST (0x02) +#define MPI_INBAND_ABORT_TYPE_RESPONSE_REQUEST (0x03) + + +/* Inband Abort reply message */ + +typedef struct _MSG_INBAND_ABORT_REPLY +{ + U8 Reserved1; /* 00h */ + U8 AbortType; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved4; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ +} MSG_INBAND_ABORT_REPLY, MPI_POINTER PTR_MSG_INBAND_ABORT_REPLY, + MpiInbandAbortReply_t, MPI_POINTER pMpiInbandAbortReply_t; + + +#endif + diff -Nru a/drivers/message/fusion/lsi/mpi_init.h b/drivers/message/fusion/lsi/mpi_init.h --- a/drivers/message/fusion/lsi/mpi_init.h Sun Mar 14 14:20:06 2004 +++ b/drivers/message/fusion/lsi/mpi_init.h Sun Mar 14 14:20:06 2004 @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2002 LSI Logic Corporation. + * Copyright (c) 2000-2003 LSI Logic Corporation. * * - * Name: MPI_INIT.H + * Name: mpi_init.h * Title: MPI initiator mode messages and structures * Creation Date: June 8, 2000 * - * MPI_INIT.H Version: 01.02.05 + * mpi_init.h Version: 01.05.xx * * Version History * --------------- @@ -31,6 +31,8 @@ * 10-04-01 01.02.04 Added defines for SEP request Action field. * 05-31-02 01.02.05 Added MPI_SCSIIO_MSGFLGS_CMD_DETERMINES_DATA_DIR define * for SCSI IO requests. + * 11-15-02 01.02.06 Added special extended SCSI Status defines for FCP. + * 06-26-03 01.02.07 Added MPI_SCSI_STATUS_FCPEXT_UNASSIGNED define. * -------------------------------------------------------------------------- */ @@ -45,7 +47,7 @@ *****************************************************************************/ /****************************************************************************/ -/* SCSI IO messages and assocaited structures */ +/* SCSI IO messages and associated structures */ /****************************************************************************/ typedef struct _MSG_SCSI_IO_REQUEST @@ -78,6 +80,16 @@ #define MPI_SCSIIO_MSGFLGS_SENSE_LOC_HOST (0x00) #define MPI_SCSIIO_MSGFLGS_SENSE_LOC_IOC (0x02) #define MPI_SCSIIO_MSGFLGS_CMD_DETERMINES_DATA_DIR (0x04) +#define MPI_SCSIIO_MSGFLGS_EEDP_TYPE_MASK (0xE0) +#define MPI_SCSIIO_MSGFLGS_EEDP_NONE (0x00) +#define MPI_SCSIIO_MSGFLGS_EEDP_RDPROTECT_T10 (0x20) +#define MPI_SCSIIO_MSGFLGS_EEDP_VRPROTECT_T10 (0x40) +#define MPI_SCSIIO_MSGFLGS_EEDP_WRPROTECT_T10 (0x60) +#define MPI_SCSIIO_MSGFLGS_EEDP_520_READ_MODE1 (0x20) +#define MPI_SCSIIO_MSGFLGS_EEDP_520_WRITE_MODE1 (0x40) +#define MPI_SCSIIO_MSGFLGS_EEDP_8_9_READ_MODE1 (0x60) +#define MPI_SCSIIO_MSGFLGS_EEDP_8_9_WRITE_MODE1 (0x80) + /* SCSI IO LUN fields */ @@ -153,6 +165,10 @@ #define MPI_SCSI_STATUS_TASK_SET_FULL (0x28) #define MPI_SCSI_STATUS_ACA_ACTIVE (0x30) +#define MPI_SCSI_STATUS_FCPEXT_DEVICE_LOGGED_OUT (0x80) +#define MPI_SCSI_STATUS_FCPEXT_NO_LINK (0x81) +#define MPI_SCSI_STATUS_FCPEXT_UNASSIGNED (0x82) + /* SCSI IO Reply SCSIState values */ @@ -176,6 +192,33 @@ /****************************************************************************/ +/* SCSI IO 32 Request message structure */ +/****************************************************************************/ + +typedef struct _MSG_SCSI_IO32_REQUEST +{ + U8 TargetID; /* 00h */ + U8 Bus; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U8 CDBLength; /* 04h */ + U8 SenseBufferLength; /* 05h */ + U8 Reserved; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U8 LUN[8]; /* 0Ch */ + U32 Control; /* 14h */ + U8 CDB[32]; /* 18h */ + U32 DataLength; /* 38h */ + U32 SenseBufferLowAddr; /* 3Ch */ + SGE_IO_UNION SGL; /* 40h */ +} MSG_SCSI_IO32_REQUEST, MPI_POINTER PTR_MSG_SCSI_IO32_REQUEST, + SCSIIO32Request_t, MPI_POINTER pSCSIIO32Request_t; + +/* SCSI IO 32 uses the same defines as above for SCSI IO */ + + +/****************************************************************************/ /* SCSI Task Management messages */ /****************************************************************************/ @@ -203,6 +246,7 @@ #define MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x03) #define MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS (0x04) #define MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05) +#define MPI_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06) /* MsgFlags bits */ #define MPI_SCSITASKMGMT_MSGFLAGS_TARGET_RESET_OPTION (0x00) diff -Nru a/drivers/message/fusion/lsi/mpi_ioc.h b/drivers/message/fusion/lsi/mpi_ioc.h --- a/drivers/message/fusion/lsi/mpi_ioc.h Sun Mar 14 14:20:06 2004 +++ b/drivers/message/fusion/lsi/mpi_ioc.h Sun Mar 14 14:20:06 2004 @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2002 LSI Logic Corporation. + * Copyright (c) 2000-2003 LSI Logic Corporation. * * - * Name: MPI_IOC.H + * Name: mpi_ioc.h * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages * Creation Date: August 11, 2000 * - * MPI_IOC.H Version: 01.02.06 + * mpi_ioc.h Version: 01.05.xx * * Version History * --------------- @@ -55,6 +55,8 @@ * 05-31-02 01.02.06 Added define for * MPI_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID. * Added AliasIndex to EVENT_DATA_LOGOUT structure. + * 04-01-03 01.02.07 Added defines for MPI_FW_HEADER_SIGNATURE_. + * 06-26-03 01.02.08 Added new values to the product family defines. * -------------------------------------------------------------------------- */ @@ -87,19 +89,21 @@ U8 Reserved1[2]; /* 0Eh */ U32 HostMfaHighAddr; /* 10h */ U32 SenseBufferHighAddr; /* 14h */ + U32 ReplyFifoHostSignalingAddr; /* 18h */ } MSG_IOC_INIT, MPI_POINTER PTR_MSG_IOC_INIT, IOCInit_t, MPI_POINTER pIOCInit_t; /* WhoInit values */ -#define MPI_WHOINIT_NO_ONE (0x00) -#define MPI_WHOINIT_SYSTEM_BIOS (0x01) -#define MPI_WHOINIT_ROM_BIOS (0x02) -#define MPI_WHOINIT_PCI_PEER (0x03) -#define MPI_WHOINIT_HOST_DRIVER (0x04) -#define MPI_WHOINIT_MANUFACTURER (0x05) +#define MPI_WHOINIT_NO_ONE (0x00) +#define MPI_WHOINIT_SYSTEM_BIOS (0x01) +#define MPI_WHOINIT_ROM_BIOS (0x02) +#define MPI_WHOINIT_PCI_PEER (0x03) +#define MPI_WHOINIT_HOST_DRIVER (0x04) +#define MPI_WHOINIT_MANUFACTURER (0x05) /* Flags values */ -#define MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE (0x01) +#define MPI_IOCINIT_FLAGS_DISCARD_FW_IMAGE (0x01) +#define MPI_IOCINIT_FLAGS_REPLY_FIFO_HOST_SIGNAL (0x02) typedef struct _MSG_IOC_INIT_REPLY { @@ -179,8 +183,10 @@ U8 MaxDevices; /* 2Eh */ U8 MaxBuses; /* 2Fh */ U32 FWImageSize; /* 30h */ - U32 Reserved4; /* 34h */ + U32 IOCCapabilities; /* 34h */ MPI_FW_VERSION FWVersion; /* 38h */ + U16 HighPriorityQueueDepth; /* 3Ch */ + U16 Reserved2; /* 3Eh */ } MSG_IOC_FACTS_REPLY, MPI_POINTER PTR_MSG_IOC_FACTS_REPLY, IOCFactsReply_t, MPI_POINTER pIOCFactsReply_t; @@ -192,12 +198,22 @@ #define MPI_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL (0x0001) #define MPI_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID (0x0002) +#define MPI_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL (0x0004) +#define MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL (0x0008) #define MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT (0x01) #define MPI_IOCFACTS_EVENTSTATE_DISABLED (0x00) #define MPI_IOCFACTS_EVENTSTATE_ENABLED (0x01) +#define MPI_IOCFACTS_CAPABILITY_HIGH_PRI_Q (0x00000001) +#define MPI_IOCFACTS_CAPABILITY_REPLY_HOST_SIGNAL (0x00000002) +#define MPI_IOCFACTS_CAPABILITY_QUEUE_FULL_HANDLING (0x00000004) +#define MPI_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER (0x00000008) +#define MPI_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER (0x00000010) +#define MPI_IOCFACTS_CAPABILITY_EXTENDED_BUFFER (0x00000020) +#define MPI_IOCFACTS_CAPABILITY_EEDP (0x00000040) + /***************************************************************************** @@ -253,6 +269,8 @@ #define MPI_PORTFACTS_PORTTYPE_INACTIVE (0x00) #define MPI_PORTFACTS_PORTTYPE_SCSI (0x01) #define MPI_PORTFACTS_PORTTYPE_FC (0x10) +#define MPI_PORTFACTS_PORTTYPE_ISCSI (0x20) +#define MPI_PORTFACTS_PORTTYPE_SAS (0x30) /* ProtocolFlags values */ @@ -386,6 +404,10 @@ #define MPI_EVENT_INTEGRATED_RAID (0x0000000B) #define MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE (0x0000000C) #define MPI_EVENT_ON_BUS_TIMER_EXPIRED (0x0000000D) +#define MPI_EVENT_QUEUE_FULL (0x0000000E) +#define MPI_EVENT_SAS_DEVICE_STATUS_CHANGE (0x0000000F) +#define MPI_EVENT_SAS_SES (0x00000010) +#define MPI_EVENT_PERSISTENT_TABLE_FULL (0x00000011) /* AckRequired field values */ @@ -433,6 +455,39 @@ #define MPI_EVENT_SCSI_DEV_STAT_RC_NOT_RESPONDING (0x04) #define MPI_EVENT_SCSI_DEV_STAT_RC_SMART_DATA (0x05) +/* SAS Device Status Change Event data */ + +typedef struct _EVENT_DATA_SAS_DEVICE_STATUS_CHANGE +{ + U8 TargetID; /* 00h */ + U8 Bus; /* 01h */ + U8 ReasonCode; /* 02h */ + U8 Reserved; /* 03h */ + U8 ASC; /* 04h */ + U8 ASCQ; /* 05h */ + U16 DevHandle; /* 06h */ + U32 DeviceInfo; /* 08h */ +} EVENT_DATA_SAS_DEVICE_STATUS_CHANGE, + MPI_POINTER PTR_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE, + MpiEventDataSasDeviceStatusChange_t, + MPI_POINTER pMpiEventDataSasDeviceStatusChange_t; + +/* MPI SAS Device Status Change Event data ReasonCode values */ +#define MPI_EVENT_SAS_DEV_STAT_RC_ADDED (0x03) +#define MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING (0x04) +#define MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA (0x05) +#define MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED (0x06) + +/* SCSI Event data for Queue Full event */ + +typedef struct _EVENT_DATA_QUEUE_FULL +{ + U8 TargetID; /* 00h */ + U8 Bus; /* 01h */ + U16 CurrentDepth; /* 02h */ +} EVENT_DATA_QUEUE_FULL, MPI_POINTER PTR_EVENT_DATA_QUEUE_FULL, + EventDataQueueFull_t, MPI_POINTER pEventDataQueueFull_t; + /* MPI Link Status Change Event data */ typedef struct _EVENT_DATA_LINK_STATUS @@ -538,6 +593,7 @@ #define MPI_FW_DOWNLOAD_ITYPE_FW (0x01) #define MPI_FW_DOWNLOAD_ITYPE_BIOS (0x02) #define MPI_FW_DOWNLOAD_ITYPE_NVDATA (0x03) +#define MPI_FW_DOWNLOAD_ITYPE_BOOTLOADER (0x04) typedef struct _FWDownloadTCSGE @@ -590,6 +646,7 @@ #define MPI_FW_UPLOAD_ITYPE_FW_FLASH (0x01) #define MPI_FW_UPLOAD_ITYPE_BIOS_FLASH (0x02) #define MPI_FW_UPLOAD_ITYPE_NVDATA (0x03) +#define MPI_FW_UPLOAD_ITYPE_BOOTLOADER (0x04) typedef struct _FWUploadTCSGE { @@ -653,6 +710,11 @@ #define MPI_FW_HEADER_PID_TYPE_MASK (0xF000) #define MPI_FW_HEADER_PID_TYPE_SCSI (0x0000) #define MPI_FW_HEADER_PID_TYPE_FC (0x1000) +#define MPI_FW_HEADER_PID_TYPE_SAS (0x2000) + +#define MPI_FW_HEADER_SIGNATURE_0 (0x5AEAA55A) +#define MPI_FW_HEADER_SIGNATURE_1 (0xA55AEAA5) +#define MPI_FW_HEADER_SIGNATURE_2 (0x5AA55AEA) #define MPI_FW_HEADER_PID_PROD_MASK (0x0F00) #define MPI_FW_HEADER_PID_PROD_INITIATOR_SCSI (0x0100) @@ -663,6 +725,7 @@ #define MPI_FW_HEADER_PID_PROD_CTX_SCSI (0x0600) #define MPI_FW_HEADER_PID_FAMILY_MASK (0x00FF) +/* SCSI */ #define MPI_FW_HEADER_PID_FAMILY_1030A0_SCSI (0x0001) #define MPI_FW_HEADER_PID_FAMILY_1030B0_SCSI (0x0002) #define MPI_FW_HEADER_PID_FAMILY_1030B1_SCSI (0x0003) @@ -673,9 +736,17 @@ #define MPI_FW_HEADER_PID_FAMILY_1020C0_SCSI (0x0008) #define MPI_FW_HEADER_PID_FAMILY_1035A0_SCSI (0x0009) #define MPI_FW_HEADER_PID_FAMILY_1035B0_SCSI (0x000A) +#define MPI_FW_HEADER_PID_FAMILY_1030TA0_SCSI (0x000B) +#define MPI_FW_HEADER_PID_FAMILY_1020TA0_SCSI (0x000C) +/* Fibre Channel */ #define MPI_FW_HEADER_PID_FAMILY_909_FC (0x0000) #define MPI_FW_HEADER_PID_FAMILY_919_FC (0x0001) #define MPI_FW_HEADER_PID_FAMILY_919X_FC (0x0002) +#define MPI_FW_HEADER_PID_FAMILY_919XL_FC (0x0003) +#define MPI_FW_HEADER_PID_FAMILY_949_FC (0x0004) +#define MPI_FW_HEADER_PID_FAMILY_959_FC (0x0005) +/* SAS */ +#define MPI_FW_HEADER_PID_FAMILY_1064_SAS (0x0001) typedef struct _MPI_EXT_IMAGE_HEADER { @@ -694,5 +765,6 @@ #define MPI_EXT_IMAGE_TYPE_UNSPECIFIED (0x00) #define MPI_EXT_IMAGE_TYPE_FW (0x01) #define MPI_EXT_IMAGE_TYPE_NVDATA (0x03) +#define MPI_EXT_IMAGE_TYPE_BOOTLOADER (0x04) #endif diff -Nru a/drivers/message/fusion/lsi/mpi_lan.h b/drivers/message/fusion/lsi/mpi_lan.h --- a/drivers/message/fusion/lsi/mpi_lan.h Sun Mar 14 14:20:07 2004 +++ b/drivers/message/fusion/lsi/mpi_lan.h Sun Mar 14 14:20:07 2004 @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2002 LSI Logic Corporation. + * Copyright (c) 2000-2003 LSI Logic Corporation. * * - * Name: MPI_LAN.H + * Name: mpi_lan.h * Title: MPI LAN messages and structures * Creation Date: June 30, 2000 * - * MPI_LAN.H Version: 01.02.01 + * mpi_lan.h Version: 01.05.xx * * Version History * --------------- diff -Nru a/drivers/message/fusion/lsi/mpi_raid.h b/drivers/message/fusion/lsi/mpi_raid.h --- a/drivers/message/fusion/lsi/mpi_raid.h Sun Mar 14 14:20:07 2004 +++ b/drivers/message/fusion/lsi/mpi_raid.h Sun Mar 14 14:20:07 2004 @@ -1,12 +1,12 @@ /* - * Copyright (c) 2001-2002 LSI Logic Corporation. + * Copyright (c) 2001-2003 LSI Logic Corporation. * * - * Name: MPI_RAID.H + * Name: mpi_raid.h * Title: MPI RAID message and structures * Creation Date: February 27, 2001 * - * MPI_RAID.H Version: 01.02.07 + * mpi_raid.h Version: 01.05.xx * * Version History * --------------- @@ -25,6 +25,9 @@ * MPI_RAID_ACTION_INACTIVATE_VOLUME, and * MPI_RAID_ACTION_ADATA_INACTIVATE_ALL. * 07-12-02 01.02.07 Added structures for Mailbox request and reply. + * 11-15-02 01.02.08 Added missing MsgContext field to MSG_MAILBOX_REQUEST. + * 04-01-03 01.02.09 New action data option flag for + * MPI_RAID_ACTION_DELETE_VOLUME. * -------------------------------------------------------------------------- */ @@ -40,7 +43,7 @@ /****************************************************************************/ -/* RAID Volume Request */ +/* RAID Action Request */ /****************************************************************************/ typedef struct _MSG_RAID_ACTION @@ -90,6 +93,9 @@ #define MPI_RAID_ACTION_ADATA_KEEP_PHYS_DISKS (0x00000000) #define MPI_RAID_ACTION_ADATA_DEL_PHYS_DISKS (0x00000001) +#define MPI_RAID_ACTION_ADATA_KEEP_LBA0 (0x00000000) +#define MPI_RAID_ACTION_ADATA_ZERO_LBA0 (0x00000002) + /* ActionDataWord defines for use with MPI_RAID_ACTION_ACTIVATE_VOLUME action */ #define MPI_RAID_ACTION_ADATA_INACTIVATE_ALL (0x00000001) @@ -184,7 +190,7 @@ /****************************************************************************/ -/* Mailbox request structure */ +/* Mailbox reqeust structure */ /****************************************************************************/ typedef struct _MSG_MAILBOX_REQUEST @@ -195,6 +201,7 @@ U16 Reserved2; U8 Reserved3; U8 MsgFlags; + U32 MsgContext; U8 Command[10]; U16 Reserved4; SGE_IO_UNION SGL; diff -Nru a/drivers/message/fusion/lsi/mpi_sas.h b/drivers/message/fusion/lsi/mpi_sas.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/message/fusion/lsi/mpi_sas.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2003 LSI Logic Corporation. + * + * + * Name: mpi_sas.h + * Title: MPI Serial Attached SCSI structures and definitions + * Creation Date: April 23, 2003 + * + * mpi_sas.h Version: 01.05.xx + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * xx-yy-zz 01.05.01 Original release. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI_SAS_H +#define MPI_SAS_H + +/***************************************************************************** +* +* S e r i a l A t t a c h e d S C S I M e s s a g e s +* +*****************************************************************************/ + +/****************************************************************************/ +/* Serial Management Protocol Passthrough Request */ +/****************************************************************************/ + +typedef struct _MSG_SMP_PASSTHROUGH_REQUEST +{ + U8 PassthroughFlags; /* 00h */ + U8 PhysicalPort; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 RequestDataLength; /* 04h */ + U8 ConnectionRate; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 Reserved1; /* 0Ch */ + U64 SASAddress; /* 10h */ + U32 Reserved2; /* 18h */ + U32 Reserved3; /* 1Ch */ + SGE_SIMPLE_UNION SGL; /* 20h */ +} MSG_SMP_PASSTHROUGH_REQUEST, MPI_POINTER PTR_MSG_SMP_PASSTHROUGH_REQUEST, + SmpPassthroughRequest_t, MPI_POINTER pSmpPassthroughRequest_t; + +#define MPI_SMP_PT_REQ_PT_FLAGS_IMMEDIATE (0x80) + +#define MPI_SMP_PT_REQ_CONNECT_RATE_NEGOTIATED (0x00) +#define MPI_SMP_PT_REQ_CONNECT_RATE_1_5 (0x08) +#define MPI_SMP_PT_REQ_CONNECT_RATE_3_0 (0x09) + + +/* Serial Management Protocol Passthrough Reply */ +typedef struct _MSG_SMP_PASSTHROUGH_REPLY +{ + U8 PassthroughFlags; /* 00h */ + U8 PhysicalPort; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 ResponseDataLength; /* 04h */ + U8 Reserved1; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U8 Reserved2; /* 0Ch */ + U8 SASStatus; /* 0Dh */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ + U32 Reserved3; /* 14h */ + U8 ResponseData[4]; /* 18h */ +} MSG_SMP_PASSTHROUGH_REPLY, MPI_POINTER PTR_MSG_SMP_PASSTHROUGH_REPLY, + SmpPassthroughReply_t, MPI_POINTER pSmpPassthroughReply_t; + +#define MPI_SMP_PT_REPLY_PT_FLAGS_IMMEDIATE (0x80) + +/* values for the SASStatus field */ +#define MPI_SASSTATUS_SUCCESS (0x00) +#define MPI_SASSTATUS_UNKNOWN_ERROR (0x01) +#define MPI_SASSTATUS_INVALID_FRAME (0x02) +#define MPI_SASSTATUS_UTC_BAD_DEST (0x03) +#define MPI_SASSTATUS_UTC_BREAK_RECEIVED (0x04) +#define MPI_SASSTATUS_UTC_CONNECT_RATE_NOT_SUPPORTED (0x05) +#define MPI_SASSTATUS_UTC_PORT_LAYER_REQUEST (0x06) +#define MPI_SASSTATUS_UTC_PROTOCOL_NOT_SUPPORTED (0x07) +#define MPI_SASSTATUS_UTC_STP_RESOURCES_BUSY (0x08) +#define MPI_SASSTATUS_UTC_WRONG_DESTINATION (0x09) +#define MPI_SASSTATUS_SHORT_INFORMATION_UNIT (0x0A) +#define MPI_SASSTATUS_LONG_INFORMATION_UNIT (0x0B) +#define MPI_SASSTATUS_XFER_RDY_INCORRECT_WRITE_DATA (0x0C) +#define MPI_SASSTATUS_XFER_RDY_REQUEST_OFFSET_ERROR (0x0D) +#define MPI_SASSTATUS_XFER_RDY_NOT_EXPECTED (0x0E) +#define MPI_SASSTATUS_DATA_INCORRECT_DATA_LENGTH (0x0F) +#define MPI_SASSTATUS_DATA_TOO_MUCH_READ_DATA (0x10) +#define MPI_SASSTATUS_DATA_OFFSET_ERROR (0x11) +#define MPI_SASSTATUS_SDSF_NAK_RECEIVED (0x12) +#define MPI_SASSTATUS_SDSF_CONNECTION_FAILED (0x13) +#define MPI_SASSTATUS_INITIATOR_RESPONSE_TIMEOUT (0x14) + + +/* + * Values for the SAS DeviceInfo field used in SAS Device Status Change Event + * data and SAS IO Unit Configuration pages. + */ +#define MPI_SAS_DEVICE_INFO_ATAPI_DEVICE (0x00002000) +#define MPI_SAS_DEVICE_INFO_LSI_DEVICE (0x00001000) +#define MPI_SAS_DEVICE_INFO_DIRECT_ATTACH (0x00000800) +#define MPI_SAS_DEVICE_INFO_SSP_TARGET (0x00000400) +#define MPI_SAS_DEVICE_INFO_STP_TARGET (0x00000200) +#define MPI_SAS_DEVICE_INFO_SMP_TARGET (0x00000100) +#define MPI_SAS_DEVICE_INFO_SATA_DEVICE (0x00000080) +#define MPI_SAS_DEVICE_INFO_SSP_INITIATOR (0x00000040) +#define MPI_SAS_DEVICE_INFO_STP_INITIATOR (0x00000020) +#define MPI_SAS_DEVICE_INFO_SMP_INITIATOR (0x00000010) +#define MPI_SAS_DEVICE_INFO_SATA_HOST (0x00000008) + +#define MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE (0x00000007) +#define MPI_SAS_DEVICE_INFO_NO_DEVICE (0x00000000) +#define MPI_SAS_DEVICE_INFO_END_DEVICE (0x00000001) +#define MPI_SAS_DEVICE_INFO_EDGE_EXPANDER (0x00000002) +#define MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER (0x00000003) + + +/****************************************************************************/ +/* SAS IO Unit Control Request */ +/****************************************************************************/ + +typedef struct _MSG_SAS_IOUNIT_CONTROL_REQUEST +{ + U8 Operation; /* 00h */ + U8 Reserved1; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U8 TargetID; /* 0Ch */ + U8 Bus; /* 0Dh */ + U8 PhyNum; /* 0Eh */ + U8 Reserved4; /* 0Fh */ + U32 Reserved5; /* 10h */ + U64 SASAddress; /* 14h */ + U32 Reserved6; /* 1Ch */ +} MSG_SAS_IOUNIT_CONTROL_REQUEST, MPI_POINTER PTR_MSG_SAS_IOUNIT_CONTROL_REQUEST, + SasIoUnitControlRequest_t, MPI_POINTER pSasIoUnitControlRequest_t; + +/* values for the ... field */ +#define MPI_SAS_OP_CLEAR_NOT_PRESENT (0x01) +#define MPI_SAS_OP_CLEAR_ALL (0x02) +#define MPI_SAS_OP_MAP (0x03) +#define MPI_SAS_OP_MOVE (0x04) +#define MPI_SAS_OP_CLEAR (0x05) +#define MPI_SAS_OP_PHY_LINK_RESET (0x06) +#define MPI_SAS_OP_PHY_HARD_RESET (0x07) +#define MPI_SAS_OP_PHY_CLEAR_ERROR_LOG (0x08) + + +/* SAS IO Unit Control Reply */ +typedef struct _MSG_SAS_IOUNIT_CONTROL_REPLY +{ + U8 Operation; /* 00h */ + U8 Reserved1; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved4; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ +} MSG_SAS_IOUNIT_CONTROL_REPLY, MPI_POINTER PTR_MSG_SAS_IOUNIT_CONTROL_REPLY, + SasIoUnitControlReply_t, MPI_POINTER pSasIoUnitControlReply_t; + +#endif + + diff -Nru a/drivers/message/fusion/lsi/mpi_targ.h b/drivers/message/fusion/lsi/mpi_targ.h --- a/drivers/message/fusion/lsi/mpi_targ.h Sun Mar 14 14:20:06 2004 +++ b/drivers/message/fusion/lsi/mpi_targ.h Sun Mar 14 14:20:06 2004 @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2002 LSI Logic Corporation. + * Copyright (c) 2000-2003 LSI Logic Corporation. * * - * Name: MPI_TARG.H + * Name: mpi_targ.h * Title: MPI Target mode messages and structures * Creation Date: June 22, 2000 * - * MPI_TARG.H Version: 01.02.07 + * mpi_targ.h Version: 01.05.xx * * Version History * --------------- @@ -41,6 +41,8 @@ * Added AliasIndex field to MPI_TARGET_FCP_CMD_BUFFER. * 09-16-02 01.02.07 Added flags for confirmed completion. * Added PRIORITY_REASON_TARGET_BUSY. + * 11-15-02 01.02.08 Added AliasID field to MPI_TARGET_SCSI_SPI_CMD_BUFFER. + * 04-01-03 01.02.09 Added OptionalOxid field to MPI_TARGET_FCP_CMD_BUFFER. * -------------------------------------------------------------------------- */ @@ -171,7 +173,7 @@ U32 FcpDl; /* 1Ch */ U8 AliasIndex; /* 20h */ U8 Reserved1; /* 21h */ - U16 Reserved2; /* 22h */ + U16 OptionalOxid; /* 22h */ } MPI_TARGET_FCP_CMD_BUFFER, MPI_POINTER PTR_MPI_TARGET_FCP_CMD_BUFFER, MpiTargetFcpCmdBuffer, MPI_POINTER pMpiTargetFcpCmdBuffer; @@ -190,6 +192,10 @@ U8 TaskManagementFlags; /* 12h */ U8 AdditionalCDBLength; /* 13h */ U8 CDB[16]; /* 14h */ + /* Alias ID */ + U8 AliasID; /* 24h */ + U8 Reserved1; /* 25h */ + U16 Reserved2; /* 26h */ } MPI_TARGET_SCSI_SPI_CMD_BUFFER, MPI_POINTER PTR_MPI_TARGET_SCSI_SPI_CMD_BUFFER, MpiTargetScsiSpiCmdBuffer, MPI_POINTER pMpiTargetScsiSpiCmdBuffer; diff -Nru a/drivers/message/fusion/lsi/mpi_tool.h b/drivers/message/fusion/lsi/mpi_tool.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/message/fusion/lsi/mpi_tool.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2001-2003 LSI Logic Corporation. + * + * + * Name: mpi_tool.h + * Title: MPI Toolbox structures and definitions + * Creation Date: July 30, 2001 + * + * mpi_tool.h Version: 01.05.xx + * + * Version History + * --------------- + * + * Date Version Description + * -------- -------- ------------------------------------------------------ + * 08-08-01 01.02.01 Original release. + * 08-29-01 01.02.02 Added DIAG_DATA_UPLOAD_HEADER and related defines. + * -------------------------------------------------------------------------- + */ + +#ifndef MPI_TOOL_H +#define MPI_TOOL_H + +#define MPI_TOOLBOX_CLEAN_TOOL (0x00) +#define MPI_TOOLBOX_MEMORY_MOVE_TOOL (0x01) +#define MPI_TOOLBOX_DIAG_DATA_UPLOAD_TOOL (0x02) +#define MPI_TOOLBOX_ISTWI_READ_WRITE_TOOL (0x03) +#define MPI_TOOLBOX_FC_MANAGEMENT_TOOL (0x04) + + +/****************************************************************************/ +/* Toolbox reply */ +/****************************************************************************/ + +typedef struct _MSG_TOOLBOX_REPLY +{ + U8 Tool; /* 00h */ + U8 Reserved; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved3; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ +} MSG_TOOLBOX_REPLY, MPI_POINTER PTR_MSG_TOOLBOX_REPLY, + ToolboxReply_t, MPI_POINTER pToolboxReply_t; + + +/****************************************************************************/ +/* Toolbox Clean Tool request */ +/****************************************************************************/ + +typedef struct _MSG_TOOLBOX_CLEAN_REQUEST +{ + U8 Tool; /* 00h */ + U8 Reserved; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 Flags; /* 0Ch */ +} MSG_TOOLBOX_CLEAN_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_CLEAN_REQUEST, + ToolboxCleanRequest_t, MPI_POINTER pToolboxCleanRequest_t; + +#define MPI_TOOLBOX_CLEAN_NVSRAM (0x00000001) +#define MPI_TOOLBOX_CLEAN_SEEPROM (0x00000002) +#define MPI_TOOLBOX_CLEAN_FLASH (0x00000004) +#define MPI_TOOLBOX_CLEAN_BOOTLOADER (0x04000000) +#define MPI_TOOLBOX_CLEAN_FW_BACKUP (0x08000000) +#define MPI_TOOLBOX_CLEAN_FW_CURRENT (0x10000000) +#define MPI_TOOLBOX_CLEAN_OTHER_PERSIST_PAGES (0x20000000) +#define MPI_TOOLBOX_CLEAN_PERSIST_MANUFACT_PAGES (0x40000000) +#define MPI_TOOLBOX_CLEAN_BOOT_SERVICES (0x80000000) + + +/****************************************************************************/ +/* Toolbox Memory Move request */ +/****************************************************************************/ + +typedef struct _MSG_TOOLBOX_MEM_MOVE_REQUEST +{ + U8 Tool; /* 00h */ + U8 Reserved; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + SGE_SIMPLE_UNION SGL; /* 0Ch */ +} MSG_TOOLBOX_MEM_MOVE_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_MEM_MOVE_REQUEST, + ToolboxMemMoveRequest_t, MPI_POINTER pToolboxMemMoveRequest_t; + + +/****************************************************************************/ +/* Toolbox Diagnostic Data Upload request */ +/****************************************************************************/ + +typedef struct _MSG_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST +{ + U8 Tool; /* 00h */ + U8 Reserved; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 Flags; /* 0Ch */ + U32 Reserved3; /* 10h */ + SGE_SIMPLE_UNION SGL; /* 14h */ +} MSG_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST, + ToolboxDiagDataUploadRequest_t, MPI_POINTER pToolboxDiagDataUploadRequest_t; + +typedef struct _DIAG_DATA_UPLOAD_HEADER +{ + U32 DiagDataLength; /* 00h */ + U8 FormatCode; /* 04h */ + U8 Reserved; /* 05h */ + U16 Reserved1; /* 06h */ +} DIAG_DATA_UPLOAD_HEADER, MPI_POINTER PTR_DIAG_DATA_UPLOAD_HEADER, + DiagDataUploadHeader_t, MPI_POINTER pDiagDataUploadHeader_t; + +#define MPI_TB_DIAG_FORMAT_SCSI_PRINTF_1 (0x01) +#define MPI_TB_DIAG_FORMAT_SCSI_2 (0x02) +#define MPI_TB_DIAG_FORMAT_SCSI_3 (0x03) +#define MPI_TB_DIAG_FORMAT_FC_TRACE_1 (0x04) + + +/****************************************************************************/ +/* Toolbox ISTWI Read Write request */ +/****************************************************************************/ + +typedef struct _MSG_TOOLBOX_ISTWI_READ_WRITE_REQUEST +{ + U8 Tool; /* 00h */ + U8 Reserved; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U8 Flags; /* 0Ch */ + U8 BusNum; /* 0Dh */ + U16 Reserved3; /* 0Eh */ + U8 NumAddressBytes; /* 10h */ + U8 Reserved4; /* 11h */ + U16 DataLength; /* 12h */ + U8 DeviceAddr; /* 14h */ + U8 Addr1; /* 15h */ + U8 Addr2; /* 16h */ + U8 Addr3; /* 17h */ + U32 Reserved5; /* 18h */ + SGE_SIMPLE_UNION SGL; /* 1Ch */ +} MSG_TOOLBOX_ISTWI_READ_WRITE_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_ISTWI_READ_WRITE_REQUEST, + ToolboxIstwiReadWriteRequest_t, MPI_POINTER pToolboxIstwiReadWriteRequest_t; + +#define MPI_TB_ISTWI_FLAGS_WRITE (0x00) +#define MPI_TB_ISTWI_FLAGS_READ (0x01) + + +/****************************************************************************/ +/* Toolbox FC Management request */ +/****************************************************************************/ + +/* ActionInfo for Bus and TargetId */ +typedef struct _MPI_TB_FC_MANAGE_BUS_TID_AI +{ + U16 Reserved; /* 00h */ + U8 Bus; /* 02h */ + U8 TargetId; /* 03h */ +} MPI_TB_FC_MANAGE_BUS_TID_AI, MPI_POINTER PTR_MPI_TB_FC_MANAGE_BUS_TID_AI, + MpiTbFcManageBusTidAi_t, MPI_POINTER pMpiTbFcManageBusTidAi_t; + +/* ActionInfo for port identifier */ +typedef struct _MPI_TB_FC_MANAGE_PID_AI +{ + U32 PortIdentifier; /* 00h */ +} MPI_TB_FC_MANAGE_PID_AI, MPI_POINTER PTR_MPI_TB_FC_MANAGE_PID_AI, + MpiTbFcManagePidAi_t, MPI_POINTER pMpiTbFcManagePidAi_t; + +/* union of ActionInfo */ +typedef union _MPI_TB_FC_MANAGE_AI_UNION +{ + MPI_TB_FC_MANAGE_BUS_TID_AI BusTid; + MPI_TB_FC_MANAGE_PID_AI Port; +} MPI_TB_FC_MANAGE_AI_UNION, MPI_POINTER PTR_MPI_TB_FC_MANAGE_AI_UNION, + MpiTbFcManageAiUnion_t, MPI_POINTER pMpiTbFcManageAiUnion_t; + +typedef struct _MSG_TOOLBOX_FC_MANAGE_REQUEST +{ + U8 Tool; /* 00h */ + U8 Reserved; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U8 Action; /* 0Ch */ + U8 Reserved3; /* 0Dh */ + U16 Reserved4; /* 0Eh */ + MPI_TB_FC_MANAGE_AI_UNION ActionInfo; /* 10h */ +} MSG_TOOLBOX_FC_MANAGE_REQUEST, MPI_POINTER PTR_MSG_TOOLBOX_FC_MANAGE_REQUEST, + ToolboxFcManageRequest_t, MPI_POINTER pToolboxFcManageRequest_t; + +/* defines for the Action field */ +#define MPI_TB_FC_MANAGE_ACTION_DISC_ALL (0x00) +#define MPI_TB_FC_MANAGE_ACTION_DISC_PID (0x01) +#define MPI_TB_FC_MANAGE_ACTION_DISC_BUS_TID (0x02) + + +/****************************************************************************/ +/* Diagnostic Buffer Post request */ +/****************************************************************************/ + +typedef struct _MSG_DIAG_BUFFER_POST_REQUEST +{ + U8 TraceLevel; /* 00h */ + U8 BufferType; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved1; /* 04h */ + U8 Reserved2; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 ExtendedType; /* 0Ch */ + U32 BufferLength; /* 10h */ + U32 ProductSpecific[4]; /* 14h */ + U32 Reserved3; /* 18h */ + SGE_SIMPLE_UNION SGL; /* 28h */ +} MSG_DIAG_BUFFER_POST_REQUEST, MPI_POINTER PTR_MSG_DIAG_BUFFER_POST_REQUEST, + DiagBufferPostRequest_t, MPI_POINTER pDiagBufferPostRequest_t; + +#define MPI_DIAG_BUF_TYPE_TRACE (0x00) +#define MPI_DIAG_BUF_TYPE_SNAPSHOT (0x01) +#define MPI_DIAG_BUF_TYPE_EXTENDED (0x02) + +#define MPI_DIAG_EXTENDED_QTAG (0x00000001) + + +/* Diagnostic Buffer Post reply */ +typedef struct _MSG_DIAG_BUFFER_POST_REPLY +{ + U8 Reserved1; /* 00h */ + U8 BufferType; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved4; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ + U32 TransferLength; /* 14h */ +} MSG_DIAG_BUFFER_POST_REPLY, MPI_POINTER PTR_MSG_DIAG_BUFFER_POST_REPLY, + DiagBufferPostReply_t, MPI_POINTER pDiagBufferPostReply_t; + + +/****************************************************************************/ +/* Diagnostic Release request */ +/****************************************************************************/ + +typedef struct _MSG_DIAG_RELEASE_REQUEST +{ + U8 Reserved1; /* 00h */ + U8 BufferType; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ +} MSG_DIAG_RELEASE_REQUEST, MPI_POINTER PTR_MSG_DIAG_RELEASE_REQUEST, + DiagReleaseRequest_t, MPI_POINTER pDiagReleaseRequest_t; + + +/* Diagnostic Release reply */ +typedef struct _MSG_DIAG_RELEASE_REPLY +{ + U8 Reserved1; /* 00h */ + U8 BufferType; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U16 Reserved2; /* 04h */ + U8 Reserved3; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U16 Reserved4; /* 0Ch */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ +} MSG_DIAG_RELEASE_REPLY, MPI_POINTER PTR_MSG_DIAG_RELEASE_REPLY, + DiagReleaseReply_t, MPI_POINTER pDiagReleaseReply_t; + + +#endif + + diff -Nru a/drivers/message/fusion/lsi/mpi_type.h b/drivers/message/fusion/lsi/mpi_type.h --- a/drivers/message/fusion/lsi/mpi_type.h Sun Mar 14 14:20:07 2004 +++ b/drivers/message/fusion/lsi/mpi_type.h Sun Mar 14 14:20:07 2004 @@ -1,12 +1,12 @@ /* - * Copyright (c) 2000-2002 LSI Logic Corporation. + * Copyright (c) 2000-2003 LSI Logic Corporation. * * - * Name: MPI_TYPE.H + * Name: mpi_type.h * Title: MPI Basic type definitions * Creation Date: June 6, 2000 * - * MPI Version: 01.02.01 + * mpi_type.h Version: 01.05.xx * * Version History * --------------- diff -Nru a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c --- a/drivers/message/fusion/mptbase.c Sun Mar 14 14:20:06 2004 +++ b/drivers/message/fusion/mptbase.c Sun Mar 14 14:20:06 2004 @@ -44,7 +44,7 @@ * for gobs of hard work fixing and optimizing LAN code. * THANK YOU! * - * Copyright (c) 1999-2003 LSI Logic Corporation + * Copyright (c) 1999-2004 LSI Logic Corporation * Originally By: Steven J. Ralston * (mailto:sjralston1@netscape.net) * (mailto:mpt_linux_developer@lsil.com) @@ -209,8 +209,8 @@ static int GetIoUnitPage2(MPT_ADAPTER *ioc); static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum); static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum); -static int mpt_findImVolumes(MPT_ADAPTER *ioc); static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc); +static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc); static void mpt_timer_expired(unsigned long data); static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch); static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp); @@ -347,14 +347,14 @@ MPT_FRAME_HDR *mf; MPT_FRAME_HDR *mr; u32 pa; - int req_idx = -1; + int req_idx; int cb_idx; int type; int freeme; - int count = 0; ioc = bus_id; +#ifdef MPT_DEBUG_IRQ /* * Verify ioc pointer is ok */ @@ -369,6 +369,7 @@ return IRQ_NONE; } } +#endif /* * Drain the reply FIFO! @@ -521,17 +522,7 @@ spin_unlock_irqrestore(&ioc->FreeQlock, flags); } - count++; - dirqprintk((MYIOC_s_INFO_FMT "ISR processed frame #%d\n", ioc->name, count)); mb(); - - if (count >= MPT_MAX_REPLIES_PER_ISR) { - dirqprintk((MYIOC_s_INFO_FMT "ISR processed %d replies.", - ioc->name, count)); - dirqprintk((" Giving this ISR a break!\n")); - return IRQ_HANDLED; - } - } /* drain reply FIFO */ return IRQ_HANDLED; @@ -605,7 +596,8 @@ } else if (func == MPI_FUNCTION_EVENT_ACK) { dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n", ioc->name)); - } else if (func == MPI_FUNCTION_CONFIG) { + } else if (func == MPI_FUNCTION_CONFIG || + func == MPI_FUNCTION_TOOLBOX) { CONFIGPARMS *pCfg; unsigned long flags; @@ -714,11 +706,7 @@ MptCallbacks[i] = cbfunc; MptDriverClass[i] = dclass; MptEvHandlers[i] = NULL; - MptDeviceDriverHandlers[i] = NULL; last_drv_idx = i; - if (cbfunc != mpt_base_reply) { - mpt_inc_use_count(); - } break; } } @@ -745,10 +733,6 @@ last_drv_idx++; if (isense_idx != -1 && isense_idx <= cb_idx) isense_idx++; - - if (cb_idx != mpt_base_index) { - mpt_dec_use_count(); - } } } @@ -890,7 +874,7 @@ MPT_FRAME_HDR* mpt_get_msg_frame(int handle, int iocid) { - MPT_FRAME_HDR *mf = NULL; + MPT_FRAME_HDR *mf; MPT_ADAPTER *iocp; unsigned long flags; @@ -922,6 +906,8 @@ iocp->mfcnt++; #endif } + else + mf = NULL; spin_unlock_irqrestore(&iocp->FreeQlock, flags); #ifdef MFCNT @@ -986,7 +972,11 @@ mf_dma_addr = iocp->req_frames_low_dma + req_offset; CHIPREG_WRITE32(&iocp->chip->RequestFifo, mf_dma_addr); + } else { + printk (KERN_ERR + "mpt_put_msg_frame: Invalid iocid=%d\n", iocid); } + } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -1135,7 +1125,7 @@ ((reqBytes/4)<chip->IntStatus, 0); - if ((r = WaitForDoorbellAck(iocp, 1, sleepFlag)) < 0) { + if ((r = WaitForDoorbellAck(iocp, 5, sleepFlag)) < 0) { return -2; } @@ -1162,7 +1152,7 @@ (req_as_bytes[(ii*4) + 2] << 16) | (req_as_bytes[(ii*4) + 3] << 24)); CHIPREG_WRITE32(&iocp->chip->Doorbell, word); - if ((r = WaitForDoorbellAck(iocp, 1, sleepFlag)) < 0) { + if ((r = WaitForDoorbellAck(iocp, 5, sleepFlag)) < 0) { r = -3; break; } @@ -1190,10 +1180,12 @@ MPT_ADAPTER * mpt_adapter_find_first(void) { - MPT_ADAPTER *this = NULL; + MPT_ADAPTER *this; if (! Q_IS_EMPTY(&MptAdapters)) this = MptAdapters.head; + else + this = NULL; return this; } @@ -1208,10 +1200,12 @@ MPT_ADAPTER * mpt_adapter_find_next(MPT_ADAPTER *prev) { - MPT_ADAPTER *next = NULL; + MPT_ADAPTER *next; if (prev && (prev->forw != (MPT_ADAPTER*)&MptAdapters.head)) next = prev->forw; + else + next = NULL; return next; } @@ -1272,10 +1266,12 @@ int ii; int r = -ENODEV; u64 mask = 0xffffffffffffffffULL; + u8 revision; + u8 pcixcmd; if (pci_enable_device(pdev)) return r; - + if (!pci_set_dma_mask(pdev, mask)) { dprintk((KERN_INFO MYNAM ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n")); @@ -1296,12 +1292,30 @@ printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n"); return -ENOMEM; } - memset(ioc, 0, sizeof(*ioc)); + memset(ioc, 0, sizeof(MPT_ADAPTER)); ioc->alloc_total = sizeof(MPT_ADAPTER); ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */ - ioc->reply_sz = ioc->req_sz; + ioc->reply_sz = MPT_REPLY_FRAME_SIZE; ioc->pcidev = pdev; + +#if defined(MPTBASE_MEM_ALLOC_FIFO_FIX) + memcpy(&ioc->pcidev32,ioc->pcidev,sizeof(struct pci_dev)); + if (pci_set_dma_mask(&ioc->pcidev32, 0xFFFFFFFF)) { + dprintk((KERN_INFO MYNAM + ": error setting 32bit mask\n")); + kfree(ioc); + return -ENODEV; + } + + if (pci_set_consistent_dma_mask(&ioc->pcidev32, 0xFFFFFFFF)) { + dprintk((KERN_INFO MYNAM + ": error setting 32bit mask\n")); + kfree(ioc); + return -ENODEV; + } +#endif + ioc->diagPending = 0; spin_lock_init(&ioc->diagLock); @@ -1412,48 +1426,45 @@ } else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) { ioc->chip_type = FC929X; - ioc->prod_name = "LSIFC929X"; - { + pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); + if (revision < XL_929) { + ioc->prod_name = "LSIFC929X"; /* 929X Chip Fix. Set Split transactions level - * for PCIX. Set bits 5 - 6 to zero, turn on bit 4. - */ - u16 pcixcmd = 0; - pci_read_config_word(pdev, 0x6a, &pcixcmd); - pcixcmd &= 0xFF9F; - pcixcmd |= 0x0010; - pci_write_config_word(pdev, 0x6a, pcixcmd); + * for PCIX. Set MOST bits to zero. + */ + pci_read_config_byte(pdev, 0x6a, &pcixcmd); + pcixcmd &= 0x8F; + pci_write_config_byte(pdev, 0x6a, pcixcmd); + } else { + ioc->prod_name = "LSIFC929XL"; + /* 929XL Chip Fix. Set MMRBC to 0x08. + */ + pci_read_config_byte(pdev, 0x6a, &pcixcmd); + pcixcmd |= 0x08; + pci_write_config_byte(pdev, 0x6a, pcixcmd); } } else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) { ioc->chip_type = FC919X; ioc->prod_name = "LSIFC919X"; - { - /* 919X Chip Fix. Set Split transactions level - * for PCIX. Set bits 5 - 6 to zero, turn on bit 4. - */ - u16 pcixcmd = 0; - pci_read_config_word(pdev, 0x6a, &pcixcmd); - pcixcmd &= 0xFF9F; - pcixcmd |= 0x0010; - pci_write_config_word(pdev, 0x6a, pcixcmd); - } + /* 919X Chip Fix. Set Split transactions level + * for PCIX. Set MOST bits to zero. + */ + pci_read_config_byte(pdev, 0x6a, &pcixcmd); + pcixcmd &= 0x8F; + pci_write_config_byte(pdev, 0x6a, pcixcmd); } else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) { ioc->chip_type = C1030; ioc->prod_name = "LSI53C1030"; - { - u8 revision; - - /* 1030 Chip Fix. Disable Split transactions - * for PCIX. Set bits 4 - 6 to zero if Rev < C0( = 8) - */ - pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); - if (revision < 0x08) { - u16 pcixcmd = 0; - pci_read_config_word(pdev, 0x6a, &pcixcmd); - pcixcmd &= 0xFF8F; - pci_write_config_word(pdev, 0x6a, pcixcmd); - } + /* 1030 Chip Fix. Disable Split transactions + * for PCIX. Set MOST bits to zero if Rev < C0( = 8). + */ + pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); + if (revision < C0_1030) { + pci_read_config_byte(pdev, 0x6a, &pcixcmd); + pcixcmd &= 0x8F; + pci_write_config_byte(pdev, 0x6a, pcixcmd); } } else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) { @@ -1515,17 +1526,18 @@ || (ioc->chip_type == C1035) || (ioc->chip_type == FC929X)) mpt_detect_bound_ports(ioc, pdev); - if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0) { - printk(KERN_WARNING MYNAM ": WARNING - %s did not initialize properly! (%d)\n", - ioc->name, r); - } + if ((r = mpt_do_ioc_recovery(ioc, + MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0) { + printk(KERN_WARNING MYNAM + ": WARNING - %s did not initialize properly! (%d)\n", + ioc->name, r); - if(r != 0 ) { Q_DEL_ITEM(ioc); mpt_adapters[ioc->id] = NULL; free_irq(ioc->pci_irq, ioc); iounmap(mem); kfree(ioc); + pci_set_drvdata(pdev, NULL); return r; } @@ -1565,6 +1577,7 @@ CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); ioc->active = 0; + mpt_sync_irq(pdev->irq); /* Clear any lingering interrupt */ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); @@ -1574,7 +1587,6 @@ Q_DEL_ITEM(ioc); mpt_adapter_dispose(ioc); - mptscsih_sync_irq(pdev->irq); pci_set_drvdata(pdev, NULL); } @@ -1755,20 +1767,23 @@ int r; int ii; int handlers; + int ret = 0; + int reset_alt_ioc_active = 0; printk(KERN_INFO MYNAM ": Initiating %s %s\n", ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery"); - /* Disable reply interrupts */ + /* Disable reply interrupts (also blocks FreeQ) */ CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); ioc->active = 0; - /* NOTE: Access to IOC's request FreeQ is now blocked! */ if (ioc->alt_ioc) { - /* Disable alt-IOC's reply interrupts for a bit ... */ + if (ioc->alt_ioc->active) + reset_alt_ioc_active = 1; + + /* Disable alt-IOC's reply interrupts (and FreeQ) for a bit ... */ CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, 0xFFFFFFFF); ioc->alt_ioc->active = 0; - /* NOTE: Access to alt-IOC's request FreeQ is now blocked! */ } hard = 1; @@ -1776,15 +1791,29 @@ hard = 0; if ((hard_reset_done = MakeIocReady(ioc, hard, sleepFlag)) < 0) { - printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n", - ioc->name); + if (hard_reset_done == -4) { + printk(KERN_WARNING MYNAM ": %s Owned by PEER..skipping!\n", + ioc->name); + + if (reset_alt_ioc_active && ioc->alt_ioc) { + /* (re)Enable alt-IOC! (reply interrupt, FreeQ) */ + dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n", + ioc->alt_ioc->name)); + CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, ~(MPI_HIM_RIM)); + ioc->alt_ioc->active = 1; + } + + } else { + printk(KERN_WARNING MYNAM ": %s NOT READY WARNING!\n", + ioc->name); + } return -1; } /* hard_reset_done = 0 if a soft reset was performed * and 1 if a hard reset was performed. */ - if (hard_reset_done && ioc->alt_ioc) { + if (hard_reset_done && reset_alt_ioc_active && ioc->alt_ioc) { if ((r = MakeIocReady(ioc->alt_ioc, 0, sleepFlag)) == 0) alt_ioc_ready = 1; else @@ -1793,42 +1822,55 @@ ioc->alt_ioc->name, r); } - /* Get IOC facts! */ + /* Get IOC facts! Allow 1 retry */ if ((r = GetIocFacts(ioc, sleepFlag, reason)) != 0) - return -2; - if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { + r = GetIocFacts(ioc, sleepFlag, reason); + + if (r) { + ret = -2; + } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { MptDisplayIocCapabilities(ioc); } if (alt_ioc_ready) { - if ((r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) - return -2; - if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { + if ((r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) { + /* Retry - alt IOC was initialized once + */ + r = GetIocFacts(ioc->alt_ioc, sleepFlag, reason); + } + if (r) { + alt_ioc_ready = 0; + reset_alt_ioc_active = 0; + } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { MptDisplayIocCapabilities(ioc->alt_ioc); } } - /* - * Prime reply & request queues! + /* Prime reply & request queues! * (mucho alloc's) Must be done prior to * init as upper addresses are needed for init. + * If fails, continue with alt-ioc processing */ - if ((r = PrimeIocFifos(ioc)) != 0) - return -3; + if ((ret == 0) && ((r = PrimeIocFifos(ioc)) != 0)) + ret = -3; - // May need to check/upload firmware & data here! - if ((r = SendIocInit(ioc, sleepFlag)) != 0) - return -4; + /* May need to check/upload firmware & data here! + * If fails, continue with alt-ioc processing + */ + if ((ret == 0) && ((r = SendIocInit(ioc, sleepFlag)) != 0)) + ret = -4; // NEW! if (alt_ioc_ready && ((r = PrimeIocFifos(ioc->alt_ioc)) != 0)) { printk(KERN_WARNING MYNAM ": alt-%s: (%d) FIFO mgmt alloc WARNING!\n", ioc->alt_ioc->name, r); alt_ioc_ready = 0; + reset_alt_ioc_active = 0; } if (alt_ioc_ready) { if ((r = SendIocInit(ioc->alt_ioc, sleepFlag)) != 0) { alt_ioc_ready = 0; + reset_alt_ioc_active = 0; printk(KERN_WARNING MYNAM ": alt-%s: (%d) init failure WARNING!\n", ioc->alt_ioc->name, r); @@ -1840,9 +1882,14 @@ ddlprintk((MYIOC_s_INFO_FMT "firmware upload required!\n", ioc->name)); - r = mpt_do_upload(ioc, sleepFlag); - if (r != 0) - printk(KERN_WARNING MYNAM ": firmware upload failure!\n"); + /* Controller is not operational, cannot do upload + */ + if (ret == 0) { + r = mpt_do_upload(ioc, sleepFlag); + if (r != 0) + printk(KERN_WARNING MYNAM ": firmware upload failure!\n"); + } + /* Handle the alt IOC too */ if ((alt_ioc_ready) && (ioc->alt_ioc->upload_fw)){ ddlprintk((MYIOC_s_INFO_FMT @@ -1855,12 +1902,13 @@ } } + if (ret == 0) { + /* Enable! (reply interrupt) */ + CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM)); + ioc->active = 1; + } - /* Enable! (reply interrupt) */ - CHIPREG_WRITE32(&ioc->chip->IntMask, ~(MPI_HIM_RIM)); - ioc->active = 1; - - if (ioc->alt_ioc) { + if (reset_alt_ioc_active && ioc->alt_ioc) { /* (re)Enable alt-IOC! (reply interrupt) */ dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n", ioc->alt_ioc->name)); @@ -1872,7 +1920,7 @@ * Enable MPT base driver management of EventNotification * and EventAck handling. */ - if (!ioc->facts.EventState) + if ((ret == 0) && (!ioc->facts.EventState)) (void) SendEventNotification(ioc, 1); /* 1=Enable EventNotification */ if (ioc->alt_ioc && alt_ioc_ready && !ioc->alt_ioc->facts.EventState) @@ -1886,7 +1934,7 @@ * routine calls HardResetHandler, which calls into here again, * and we try GetLanConfigPages again... */ - if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { + if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) { if ((int)ioc->chip_type <= (int)FC929) { /* * Pre-fetch FC port WWN and stuff... @@ -1928,6 +1976,8 @@ /* Check, and possibly reset, the coalescing value */ mpt_read_ioc_pg_1(ioc); + + mpt_read_ioc_pg_4(ioc); } GetIoUnitPage2(ioc); @@ -1942,24 +1992,24 @@ if (hard_reset_done) { r = handlers = 0; for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) { - if (MptResetHandlers[ii]) { + if ((ret == 0) && MptResetHandlers[ii]) { dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n", ioc->name, ii)); r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_POST_RESET); handlers++; + } - if (alt_ioc_ready) { - dprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n", - ioc->name, ioc->alt_ioc->name, ii)); - r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET); - handlers++; - } + if (alt_ioc_ready && MptResetHandlers[ii]) { + dprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n", + ioc->name, ioc->alt_ioc->name, ii)); + r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET); + handlers++; } } /* FIXME? Examine results here? */ } - return 0; + return ret; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -2114,6 +2164,15 @@ kfree(this->spi_data.pIocPg3); this->spi_data.pIocPg3 = NULL; } + + if (freeup && this->spi_data.pIocPg4 != NULL) { + sz = this->spi_data.IocPg4Sz; + pci_free_consistent(this->pcidev, sz, + this->spi_data.pIocPg4, + this->spi_data.IocPg4_dma); + this->spi_data.pIocPg4 = NULL; + this->alloc_total -= sz; + } } } @@ -2429,7 +2488,7 @@ * 1 byte in size, so we can just fire it off as is. */ r = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_facts, - reply_sz, (u16*)facts, 3 /*seconds*/, sleepFlag); + reply_sz, (u16*)facts, 5 /*seconds*/, sleepFlag); if (r != 0) return r; @@ -2510,7 +2569,7 @@ */ ioc->req_sz = MIN(MPT_DEFAULT_FRAME_SIZE, facts->RequestFrameSize * 4); ioc->req_depth = MIN(MPT_MAX_REQ_DEPTH, facts->GlobalCredits); - ioc->reply_sz = ioc->req_sz; + ioc->reply_sz = MPT_REPLY_FRAME_SIZE; ioc->reply_depth = MIN(MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth); dprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n", @@ -2578,7 +2637,7 @@ * 1 byte in size, so we can just fire it off as is. */ ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&get_pfacts, - reply_sz, (u16*)pfacts, 3 /*seconds*/, sleepFlag); + reply_sz, (u16*)pfacts, 5 /*seconds*/, sleepFlag); if (ii != 0) return ii; @@ -2651,6 +2710,8 @@ /* ioc_init.MsgFlags = 0; */ /* ioc_init.MsgContext = cpu_to_le32(0x00000000); */ ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */ + + ioc->facts.RequestFrameSize = ioc_init.ReplyFrameSize; if (sizeof(dma_addr_t) == sizeof(u64)) { /* Save the upper 32-bits of the request @@ -2663,6 +2724,9 @@ ioc_init.HostMfaHighAddr = cpu_to_le32(0); ioc_init.SenseBufferHighAddr = cpu_to_le32(0); } + + ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr; + ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr; dprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n", ioc->name, &ioc_init)); @@ -2773,8 +2837,8 @@ void * mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz) { - fw_image_t **cached_fw = NULL; - u8 *mem = NULL; + fw_image_t **cached_fw; + u8 *mem; dma_addr_t fw_dma; int alloc_total = 0; int bytes_left, bytes, num_frags; @@ -2922,7 +2986,7 @@ u8 reply[sizeof(FWUploadReply_t)]; FWUpload_t *prequest; FWUploadReply_t *preply; - FWUploadTCSGE_t *ptcsge = NULL; + FWUploadTCSGE_t *ptcsge; int sgeoffset; int ii, sz, reply_sz; int cmdStatus, freeMem = 0; @@ -3054,16 +3118,16 @@ static int mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag) { - MpiFwHeader_t *FwHdr = NULL; + MpiFwHeader_t *FwHdr; MpiExtImageHeader_t *ExtHdr; - fw_image_t **pCached = NULL; + fw_image_t **pCached=NULL; int fw_sz; u32 diag0val; #ifdef MPT_DEBUG u32 diag1val = 0; #endif int count = 0; - u32 *ptru32 = NULL; + u32 *ptru32; u32 diagRwData; u32 nextImage; u32 ext_offset; @@ -3097,11 +3161,11 @@ pCached = (fw_image_t **)ioc->cached_fw; else if (ioc->alt_ioc && (ioc->alt_ioc->cached_fw != NULL)) pCached = (fw_image_t **)ioc->alt_ioc->cached_fw; + else + return -2; ddlprintk((MYIOC_s_INFO_FMT "DbGb2: FW Image @ %p\n", ioc->name, pCached)); - if (!pCached) - return -2; /* Write magic sequence to WriteSequence register * until enter diagnostic mode @@ -3351,6 +3415,7 @@ SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag); if (sleepFlag == CAN_SLEEP) { + set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ); } else { mdelay (1000); @@ -3551,11 +3616,11 @@ } else { /* Wait for FW to reload and for board * to go to the READY state. - * Maximum wait is 30 seconds. + * Maximum wait is 60 seconds. * If fail, no error will check again * with calling program. */ - for (count = 0; count < 30; count ++) { + for (count = 0; count < 60; count ++) { doorbell = CHIPREG_READ32(&ioc->chip->Doorbell); doorbell &= MPI_IOC_STATE_MASK; @@ -3673,7 +3738,7 @@ dprintk((KERN_WARNING MYNAM ": %s: Sending IOC reset(0x%02x)!\n", ioc->name, reset_type)); CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<reply_frames == NULL) { sz = (ioc->reply_sz * ioc->reply_depth) + 128; +#if defined(MPTBASE_MEM_ALLOC_FIFO_FIX) + mem = pci_alloc_consistent(&ioc->pcidev32, sz, &ioc->reply_alloc_dma); +#else mem = pci_alloc_consistent(ioc->pcidev, sz, &ioc->reply_alloc_dma); +#endif if (mem == NULL) goto out_fail; @@ -3778,7 +3847,11 @@ */ sz = ((sz + 0x1000UL - 1UL) / 0x1000) * 0x1000; +#if defined(MPTBASE_MEM_ALLOC_FIFO_FIX) + mem = pci_alloc_consistent(&ioc->pcidev32, sz, &ioc->req_alloc_dma); +#else mem = pci_alloc_consistent(ioc->pcidev, sz, &ioc->req_alloc_dma); +#endif if (mem == NULL) goto out_fail; @@ -3894,8 +3967,8 @@ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** - * mpt_handshake_req_reply_wait - Send MPT request to and receive reply from - * IOC via doorbell handshake method. + * mpt_handshake_req_reply_wait - Send MPT request to and receive reply + * from IOC via doorbell handshake method. * @ioc: Pointer to MPT_ADAPTER structure * @reqBytes: Size of the request in bytes * @req: Pointer to MPT request frame @@ -3955,7 +4028,7 @@ * our handshake request. */ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); - if (!failcnt && (t = WaitForDoorbellAck(ioc, 2, sleepFlag)) < 0) + if (!failcnt && (t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) failcnt++; if (!failcnt) { @@ -3973,7 +4046,7 @@ (req_as_bytes[(ii*4) + 3] << 24)); CHIPREG_WRITE32(&ioc->chip->Doorbell, word); - if ((t = WaitForDoorbellAck(ioc, 2, sleepFlag)) < 0) + if ((t = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) failcnt++; } @@ -4137,7 +4210,7 @@ } else { hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF); CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); - if ((t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0) + if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) failcnt++; else { hs_reply[u16cnt++] = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF); @@ -4154,7 +4227,7 @@ * reply 16 bits at a time. */ for (u16cnt=2; !failcnt && u16cnt < (2 * mptReply->MsgLength); u16cnt++) { - if ((t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0) + if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) failcnt++; hword = le16_to_cpu(CHIPREG_READ32(&ioc->chip->Doorbell) & 0x0000FFFF); /* don't overflow our IOC hs_reply[] buffer! */ @@ -4163,7 +4236,7 @@ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); } - if (!failcnt && (t = WaitForDoorbellInt(ioc, 2, sleepFlag)) < 0) + if (!failcnt && (t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0) failcnt++; CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); @@ -4466,7 +4539,7 @@ static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) { - u8 *pbuf = NULL; + u8 *pbuf; dma_addr_t buf_dma; CONFIGPARMS cfg; ConfigPageHeader_t header; @@ -4528,6 +4601,9 @@ pPP0->Capabilities = le32_to_cpu(pPP0->Capabilities); pPP0->PhysicalInterface = le32_to_cpu(pPP0->PhysicalInterface); + if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) + ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS; + ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0; data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MAX_SYNC_OFFSET_MASK; if (data) { @@ -4552,7 +4628,6 @@ } if (pbuf) { pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma); - pbuf = NULL; } } } @@ -4589,6 +4664,8 @@ /* Save the Port Page 2 data * (reformat into a 32bit quantity) */ + data = le32_to_cpu(pPP2->PortFlags) & MPI_SCSIPORTPAGE2_PORT_FLAGS_DV_MASK; + ioc->spi_data.PortFlags = data; for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { pdevice = &pPP2->DeviceSettings[ii]; data = (le16_to_cpu(pdevice->DeviceFlags) << 16) | @@ -4598,7 +4675,6 @@ } pci_free_consistent(ioc->pcidev, header.PageLength * 4, pbuf, buf_dma); - pbuf = NULL; } } @@ -4671,11 +4747,12 @@ * -EFAULT if read of config page header fails or data pointer not NULL * -ENOMEM if pci_alloc failed */ -static int +int mpt_findImVolumes(MPT_ADAPTER *ioc) { - IOCPage2_t *pIoc2 = NULL; - ConfigPageIoc2RaidVol_t *pIocRv = NULL; + IOCPage2_t *pIoc2; + u8 *mem; + ConfigPageIoc2RaidVol_t *pIocRv; dma_addr_t ioc2_dma; CONFIGPARMS cfg; ConfigPageHeader_t header; @@ -4685,9 +4762,6 @@ u8 nVols, nPhys; u8 vid, vbus, vioc; - if (ioc->spi_data.pIocPg3) - return -EFAULT; - /* Read IOCP2 header then the page. */ header.PageVersion = 0; @@ -4716,11 +4790,22 @@ if (mpt_config(ioc, &cfg) != 0) goto done_and_free; + if ( (mem = (u8 *)ioc->spi_data.pIocPg2) == NULL ) { + mem = kmalloc(iocpage2sz, GFP_ATOMIC); + if (mem) { + ioc->spi_data.pIocPg2 = (IOCPage2_t *) mem; + } else { + goto done_and_free; + } + } + memcpy(mem, (u8 *)pIoc2, iocpage2sz); + /* Identify RAID Volume Id's */ nVols = pIoc2->NumActiveVolumes; if ( nVols == 0) { - /* No RAID Volumes. Done. + /* No RAID Volume. */ + goto done_and_free; } else { /* At least 1 RAID Volume */ @@ -4745,17 +4830,14 @@ /* Identify Hidden Physical Disk Id's */ nPhys = pIoc2->NumActivePhysDisks; if (nPhys == 0) { - /* No physical disks. Done. + /* No physical disks. */ } else { mpt_read_ioc_pg_3(ioc); } done_and_free: - if (pIoc2) { - pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma); - pIoc2 = NULL; - } + pci_free_consistent(ioc->pcidev, iocpage2sz, pIoc2, ioc2_dma); return rc; } @@ -4763,7 +4845,7 @@ int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc) { - IOCPage3_t *pIoc3 = NULL; + IOCPage3_t *pIoc3; u8 *mem; CONFIGPARMS cfg; ConfigPageHeader_t header; @@ -4816,18 +4898,66 @@ } } - if (pIoc3) { - pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma); - pIoc3 = NULL; - } + pci_free_consistent(ioc->pcidev, iocpage3sz, pIoc3, ioc3_dma); return 0; } static void +mpt_read_ioc_pg_4(MPT_ADAPTER *ioc) +{ + IOCPage4_t *pIoc4; + CONFIGPARMS cfg; + ConfigPageHeader_t header; + dma_addr_t ioc4_dma; + int iocpage4sz; + + /* Read and save IOC Page 4 + */ + header.PageVersion = 0; + header.PageLength = 0; + header.PageNumber = 4; + header.PageType = MPI_CONFIG_PAGETYPE_IOC; + cfg.hdr = &header; + cfg.physAddr = -1; + cfg.pageAddr = 0; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; + cfg.timeout = 0; + if (mpt_config(ioc, &cfg) != 0) + return; + + if (header.PageLength == 0) + return; + + if ( (pIoc4 = ioc->spi_data.pIocPg4) == NULL ) { + iocpage4sz = (header.PageLength + 4) * 4; /* Allow 4 additional SEP's */ + pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma); + if (!pIoc4) + return; + } else { + ioc4_dma = ioc->spi_data.IocPg4_dma; + iocpage4sz = ioc->spi_data.IocPg4Sz; + } + + /* Read the Page into dma memory. + */ + cfg.physAddr = ioc4_dma; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + if (mpt_config(ioc, &cfg) == 0) { + ioc->spi_data.pIocPg4 = (IOCPage4_t *) pIoc4; + ioc->spi_data.IocPg4_dma = ioc4_dma; + ioc->spi_data.IocPg4Sz = iocpage4sz; + } else { + pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma); + ioc->spi_data.pIocPg4 = NULL; + } +} + +static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc) { - IOCPage1_t *pIoc1 = NULL; + IOCPage1_t *pIoc1; CONFIGPARMS cfg; ConfigPageHeader_t header; dma_addr_t ioc1_dma; @@ -4903,10 +5033,7 @@ } } - if (pIoc1) { - pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma); - pIoc1 = NULL; - } + pci_free_consistent(ioc->pcidev, iocpage1sz, pIoc1, ioc1_dma); return; } @@ -5022,9 +5149,8 @@ pReq->Reserved = 0; pReq->ChainOffset = 0; pReq->Function = MPI_FUNCTION_CONFIG; - pReq->Reserved1[0] = 0; - pReq->Reserved1[1] = 0; - pReq->Reserved1[2] = 0; + pReq->ExtPageLength = 0; + pReq->ExtPageType = 0; pReq->MsgFlags = 0; for (ii=0; ii < 8; ii++) pReq->Reserved2[ii] = 0; @@ -5083,6 +5209,112 @@ } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_toolbox - Generic function to issue toolbox message + * @ioc - Pointer to an adapter structure + * @cfg - Pointer to a toolbox structure. Struct contains + * action, page address, direction, physical address + * and pointer to a configuration page header + * Page header is updated. + * + * Returns 0 for success + * -EPERM if not allowed due to ISR context + * -EAGAIN if no msg frames currently available + * -EFAULT for non-successful reply or no reply (timeout) + */ +int +mpt_toolbox(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) +{ + ToolboxIstwiReadWriteRequest_t *pReq; + MPT_FRAME_HDR *mf; + unsigned long flags; + int rc; + int flagsLength; + int in_isr; + + /* (Bugzilla:fibrebugs, #513) + * Bug fix (part 1)! 20010905 -sralston + * Prevent calling wait_event() (below), if caller happens + * to be in ISR context, because that is fatal! + */ + in_isr = in_interrupt(); + if (in_isr) { + dcprintk((MYIOC_s_WARN_FMT "toobox request not allowed in ISR context!\n", + ioc->name)); + return -EPERM; + } + + /* Get and Populate a free Frame + */ + if ((mf = mpt_get_msg_frame(mpt_base_index, ioc->id)) == NULL) { + dcprintk((MYIOC_s_WARN_FMT "mpt_toolbox: no msg frames!\n", + ioc->name)); + return -EAGAIN; + } + pReq = (ToolboxIstwiReadWriteRequest_t *)mf; + pReq->Tool = pCfg->action; + pReq->Reserved = 0; + pReq->ChainOffset = 0; + pReq->Function = MPI_FUNCTION_TOOLBOX; + pReq->Reserved1 = 0; + pReq->Reserved2 = 0; + pReq->MsgFlags = 0; + pReq->Flags = pCfg->dir; + pReq->BusNum = 0; + pReq->Reserved3 = 0; + pReq->NumAddressBytes = 0x01; + pReq->Reserved4 = 0; + pReq->DataLength = 0x04; + pReq->DeviceAddr = 0xB0; + pReq->Addr1 = 0; + pReq->Addr2 = 0; + pReq->Addr3 = 0; + pReq->Reserved5 = 0; + + /* Add a SGE to the config request. + */ + + flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ | 4; + + mpt_add_sge((char *)&pReq->SGL, flagsLength, pCfg->physAddr); + + dcprintk((MYIOC_s_INFO_FMT "Sending Toolbox request, Tool=%x\n", + ioc->name, pReq->Tool)); + + /* Append pCfg pointer to end of mf + */ + *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg; + + /* Initalize the timer + */ + init_timer(&pCfg->timer); + pCfg->timer.data = (unsigned long) ioc; + pCfg->timer.function = mpt_timer_expired; + pCfg->wait_done = 0; + + /* Set the timer; ensure 10 second minimum */ + if (pCfg->timeout < 10) + pCfg->timer.expires = jiffies + HZ*10; + else + pCfg->timer.expires = jiffies + HZ*pCfg->timeout; + + /* Add to end of Q, set timer and then issue this command */ + spin_lock_irqsave(&ioc->FreeQlock, flags); + Q_ADD_TAIL(&ioc->configQ.head, &pCfg->linkage, Q_ITEM); + spin_unlock_irqrestore(&ioc->FreeQlock, flags); + + add_timer(&pCfg->timer); + mpt_put_msg_frame(mpt_base_index, ioc->id, mf); + wait_event(mpt_waitq, pCfg->wait_done); + + /* mf has been freed - do not access */ + + rc = pCfg->status; + + return rc; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * mpt_timer_expired - Call back for timer process. * Used only internal config functionality. @@ -5124,9 +5356,12 @@ dprintk((KERN_WARNING MYNAM ": IOC %s_reset routed to MPT base driver!\n", - reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")); + reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( + reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); - if (reset_phase == MPT_IOC_PRE_RESET) { + if (reset_phase == MPT_IOC_SETUP_RESET) { + ; + } else if (reset_phase == MPT_IOC_PRE_RESET) { /* If the internal config Q is not empty - * delete timer. MF resources will be freed when * the FIFO's are primed. @@ -5590,7 +5825,7 @@ int rc; unsigned long flags; - dprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name)); + dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name)); #ifdef MFCNT printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name); printk("MF count 0x%x !\n", ioc->mfcnt); @@ -5611,6 +5846,29 @@ /* FIXME: If do_ioc_recovery fails, repeat.... */ + /* The SCSI driver needs to adjust timeouts on all current + * commands prior to the diagnostic reset being issued. + * Prevents timeouts occuring during a diagnostic reset...very bad. + * For all other protocol drivers, this is a no-op. + */ + { + int ii; + int r = 0; + + for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) { + if (MptResetHandlers[ii]) { + dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n", + ioc->name, ii)); + r += (*(MptResetHandlers[ii]))(ioc, MPT_IOC_SETUP_RESET); + if (ioc->alt_ioc) { + dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n", + ioc->name, ioc->alt_ioc->name, ii)); + r += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_SETUP_RESET); + } + } + } + } + if ((rc = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_RECOVER, sleepFlag)) != 0) { printk(KERN_WARNING MYNAM ": WARNING - (%d) Cannot recover %s\n", rc, ioc->name); @@ -5625,7 +5883,7 @@ ioc->alt_ioc->diagPending = 0; spin_unlock_irqrestore(&ioc->diagLock, flags); - dprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc)); + dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc)); return rc; } @@ -5634,7 +5892,7 @@ static char * EventDescriptionStr(u8 event, u32 evData0) { - char *ds = NULL; + char *ds; switch(event) { case MPI_EVENT_NONE: @@ -5839,109 +6097,11 @@ "FCP Initiator", "FCP Target", "LAN", "MPI Message Layer", "FC Link", "Context Manager", "Invalid Field Offset", "State Change Info" }; - char *desc = "unknown"; u8 subcl = (log_info >> 24) & 0x7; - u32 SubCl = log_info & 0x27000000; - - switch(log_info) { -/* FCP Initiator */ - case MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME: - desc = "Received an out of order frame - unsupported"; - break; - case MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME: - desc = "Bad start of frame primative"; - break; - case MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_END_OF_FRAME: - desc = "Bad end of frame primative"; - break; - case MPI_IOCLOGINFO_FC_INIT_ERROR_OVER_RUN: - desc = "Receiver hardware detected overrun"; - break; - case MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OTHER: - desc = "Other errors caught by IOC which require retries"; - break; - case MPI_IOCLOGINFO_FC_INIT_ERROR_SUBPROC_DEAD: - desc = "Main processor could not initialize sub-processor"; - break; -/* FC Target */ - case MPI_IOCLOGINFO_FC_TARGET_NO_PDISC: - desc = "Not sent because we are waiting for a PDISC from the initiator"; - break; - case MPI_IOCLOGINFO_FC_TARGET_NO_LOGIN: - desc = "Not sent because we are not logged in to the remote node"; - break; - case MPI_IOCLOGINFO_FC_TARGET_DOAR_KILLED_BY_LIP: - desc = "Data Out, Auto Response, not sent due to a LIP"; - break; - case MPI_IOCLOGINFO_FC_TARGET_DIAR_KILLED_BY_LIP: - desc = "Data In, Auto Response, not sent due to a LIP"; - break; - case MPI_IOCLOGINFO_FC_TARGET_DIAR_MISSING_DATA: - desc = "Data In, Auto Response, missing data frames"; - break; - case MPI_IOCLOGINFO_FC_TARGET_DONR_KILLED_BY_LIP: - desc = "Data Out, No Response, not sent due to a LIP"; - break; - case MPI_IOCLOGINFO_FC_TARGET_WRSP_KILLED_BY_LIP: - desc = "Auto-response after a write not sent due to a LIP"; - break; - case MPI_IOCLOGINFO_FC_TARGET_DINR_KILLED_BY_LIP: - desc = "Data In, No Response, not completed due to a LIP"; - break; - case MPI_IOCLOGINFO_FC_TARGET_DINR_MISSING_DATA: - desc = "Data In, No Response, missing data frames"; - break; - case MPI_IOCLOGINFO_FC_TARGET_MRSP_KILLED_BY_LIP: - desc = "Manual Response not sent due to a LIP"; - break; - case MPI_IOCLOGINFO_FC_TARGET_NO_CLASS_3: - desc = "Not sent because remote node does not support Class 3"; - break; - case MPI_IOCLOGINFO_FC_TARGET_LOGIN_NOT_VALID: - desc = "Not sent because login to remote node not validated"; - break; - case MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND: - desc = "Cleared from the outbound queue after a logout"; - break; - case MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN: - desc = "Cleared waiting for data after a logout"; - break; -/* LAN */ - case MPI_IOCLOGINFO_FC_LAN_TRANS_SGL_MISSING: - desc = "Transaction Context Sgl Missing"; - break; - case MPI_IOCLOGINFO_FC_LAN_TRANS_WRONG_PLACE: - desc = "Transaction Context found before an EOB"; - break; - case MPI_IOCLOGINFO_FC_LAN_TRANS_RES_BITS_SET: - desc = "Transaction Context value has reserved bits set"; - break; - case MPI_IOCLOGINFO_FC_LAN_WRONG_SGL_FLAG: - desc = "Invalid SGL Flags"; - break; -/* FC Link */ - case MPI_IOCLOGINFO_FC_LINK_LOOP_INIT_TIMEOUT: - desc = "Loop initialization timed out"; - break; - case MPI_IOCLOGINFO_FC_LINK_ALREADY_INITIALIZED: - desc = "Another system controller already initialized the loop"; - break; - case MPI_IOCLOGINFO_FC_LINK_LINK_NOT_ESTABLISHED: - desc = "Not synchronized to signal or still negotiating (possible cable problem)"; - break; - case MPI_IOCLOGINFO_FC_LINK_CRC_ERROR: - desc = "CRC check detected error on received frame"; - break; - } +// u32 SubCl = log_info & 0x27000000; printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): SubCl={%s}", ioc->name, log_info, subcl_str[subcl]); - if (SubCl == MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET) - printk(", byte_offset=%d\n", log_info & MPI_IOCLOGINFO_FC_INVALID_FIELD_MAX_OFFSET); - else if (SubCl == MPI_IOCLOGINFO_FC_STATE_CHANGE) - printk("\n"); /* StateChg in LogInfo & 0x00FFFFFF, above */ - else - printk("\n" KERN_INFO " %s\n", desc); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -6021,7 +6181,6 @@ isense_idx = last_drv_idx; r = 1; } - mpt_inc_use_count(); return r; } @@ -6040,7 +6199,6 @@ mpt_ScsiOpcodesPtr = NULL; printk(KERN_INFO MYNAM ": English readable SCSI-3 strings disabled)-:\n"); isense_idx = -1; - mpt_dec_use_count(); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -6072,6 +6230,8 @@ EXPORT_SYMBOL(mpt_stm_index); EXPORT_SYMBOL(mpt_HardResetHandler); EXPORT_SYMBOL(mpt_config); +EXPORT_SYMBOL(mpt_toolbox); +EXPORT_SYMBOL(mpt_findImVolumes); EXPORT_SYMBOL(mpt_read_ioc_pg_3); EXPORT_SYMBOL(mpt_alloc_fw_memory); EXPORT_SYMBOL(mpt_free_fw_memory); diff -Nru a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h --- a/drivers/message/fusion/mptbase.h Sun Mar 14 14:20:06 2004 +++ b/drivers/message/fusion/mptbase.h Sun Mar 14 14:20:06 2004 @@ -8,7 +8,7 @@ * Credits: * (see mptbase.c) * - * Copyright (c) 1999-2003 LSI Logic Corporation + * Copyright (c) 1999-2004 LSI Logic Corporation * Originally By: Steven J. Ralston * (mailto:sjralston1@netscape.net) * (mailto:mpt_linux_developer@lsil.com) @@ -68,6 +68,7 @@ #include "lsi/mpi_fc.h" /* Fibre Channel (lowlevel) support */ #include "lsi/mpi_targ.h" /* SCSI/FCP Target protcol support */ +#include "lsi/mpi_tool.h" /* Tools support */ #include "lsi/fc_log.h" /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -77,11 +78,11 @@ #endif #ifndef COPYRIGHT -#define COPYRIGHT "Copyright (c) 1999-2003 " MODULEAUTHOR +#define COPYRIGHT "Copyright (c) 1999-2004 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.00.03" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.00.03" +#define MPT_LINUX_VERSION_COMMON "3.01.01" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.01.01" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ @@ -93,10 +94,10 @@ */ #define MPT_MAX_ADAPTERS 18 #define MPT_MAX_PROTOCOL_DRIVERS 16 -#define MPT_MAX_BUS 1 +#define MPT_MAX_BUS 1 /* Do not change */ #define MPT_MAX_FC_DEVICES 255 #define MPT_MAX_SCSI_DEVICES 16 -#define MPT_LAST_LUN 31 +#define MPT_LAST_LUN 255 #define MPT_SENSE_BUFFER_ALLOC 64 /* allow for 256 max sense alloc, but only 255 max request */ #if MPT_SENSE_BUFFER_ALLOC >= 256 @@ -127,6 +128,8 @@ #define MPT_MAX_FRAME_SIZE 128 #define MPT_DEFAULT_FRAME_SIZE 128 +#define MPT_REPLY_FRAME_SIZE 0x40 /* Must be a multiple of 8 */ + #define MPT_SG_REQ_128_SCALE 1 #define MPT_SG_REQ_96_SCALE 2 #define MPT_SG_REQ_64_SCALE 4 @@ -150,6 +153,9 @@ #define MPT_NARROW 0 #define MPT_WIDE 1 +#define C0_1030 0x08 +#define XL_929 0x01 + #ifdef __KERNEL__ /* { */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -185,8 +191,8 @@ void (*remove) (struct pci_dev *dev); void (*shutdown) (struct device * dev); #ifdef CONFIG_PM - int (*suspend) (struct pci_dev *dev, u32 state); int (*resume) (struct pci_dev *dev); + int (*suspend) (struct pci_dev *dev, u32 state); #endif }; @@ -201,9 +207,6 @@ u32 arg1; u32 pad; void *argp1; -#ifndef MPT_SCSI_USE_NEW_EH - void *argp2; -#endif } linkage; /* * NOTE: When request frames are free, on the linkage structure @@ -255,6 +258,7 @@ MPIHeader_t hdr; SCSIIORequest_t scsireq; SCSIIOReply_t sreply; + ConfigReply_t configreply; MPIDefaultReply_t reply; MPT_FRAME_TRACKER frame; } u; @@ -408,12 +412,9 @@ ScsiCmndTracker SentQ; ScsiCmndTracker DoneQ; u32 num_luns; -//--- LUN split here? - u32 luns; /* Max LUNs is 32 */ - u8 inq_data[SCSI_STD_INQUIRY_BYTES]; /* 36 */ - u8 pad0[4]; - u8 inq00_data[20]; - u8 pad1[4]; + u32 luns[8]; /* Max LUNs is 256 */ + u8 pad[4]; + u8 inq_data[8]; /* IEEE Registered Extended Identifier obtained via INQUIRY VPD page 0x83 */ /* NOTE: Do not separate uniq_prepad and uniq_data @@ -421,26 +422,17 @@ u8 uniq_prepad[8]; u8 uniq_data[20]; u8 pad2[4]; - u8 inqC3_data[12]; - u8 pad3[4]; - u8 inqC9_data[12]; - u8 pad4[4]; - u8 dev_vol_name[64]; } VirtDevice; /* * Fibre Channel (SCSI) target device and associated defines... */ -#define MPT_TARGET_DEFAULT_DV_STATUS 0 -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,55) -#define MPT_TARGET_FLAGS_CONFIGURED 0x02 -#define MPT_TARGET_FLAGS_Q_YES 0x08 -#else +#define MPT_TARGET_DEFAULT_DV_STATUS 0x00 #define MPT_TARGET_FLAGS_VALID_NEGO 0x01 #define MPT_TARGET_FLAGS_VALID_INQUIRY 0x02 #define MPT_TARGET_FLAGS_Q_YES 0x08 #define MPT_TARGET_FLAGS_VALID_56 0x10 -#endif +#define MPT_TARGET_FLAGS_SAF_TE_ISSUED 0x20 #define MPT_TARGET_NO_NEGO_WIDE 0x01 #define MPT_TARGET_NO_NEGO_SYNC 0x02 @@ -539,8 +531,13 @@ /* #define MPT_SCSICFG_BLK_NEGO 0x10 WriteSDP1 with WDTR and SDTR disabled */ typedef struct _ScsiCfgData { + u32 PortFlags; int *nvram; /* table of device NVRAM values */ + IOCPage2_t *pIocPg2; /* table of Raid Volumes */ IOCPage3_t *pIocPg3; /* table of physical disks */ + IOCPage4_t *pIocPg4; /* SEP devices addressing */ + dma_addr_t IocPg4_dma; /* Phys Addr of IOCPage4 data */ + int IocPg4Sz; /* IOCPage4 size */ u8 dvStatus[MPT_MAX_SCSI_DEVICES]; int isRaid; /* bit field, 1 if RAID */ u8 minSyncFactor; /* 0xFF if async */ @@ -554,7 +551,8 @@ u8 dvScheduled; /* 1 if scheduled */ u8 forceDv; /* 1 to force DV scheduling */ u8 noQas; /* Disable QAS for this adapter */ - u8 rsvd[2]; + u8 Saf_Te; /* 1 to force all Processors as SAF-TE if Inquiry data length is too short to check for SAF-TE */ + u8 rsvd[1]; } ScsiCfgData; typedef struct _fw_image { @@ -610,6 +608,9 @@ u32 sense_buf_low_dma; int mtrr_reg; struct pci_dev *pcidev; /* struct pci_dev pointer */ +#if defined(MPTBASE_MEM_ALLOC_FIFO_FIX) + struct pci_dev pcidev32; /* struct pci_dev pointer */ +#endif u8 *memmap; /* mmap address */ struct Scsi_Host *sh; /* Scsi Host pointer */ ScsiCfgData spi_data; /* Scsi config. data */ @@ -622,6 +623,12 @@ int eventTypes; /* Event logging parameters */ int eventContext; /* Next event context */ int eventLogSize; /* Max number of cached events */ +#ifdef MPTSCSIH_DBG_TIMEOUT + int timeout_hard; + int timeout_delta; + int timeout_cnt; + int timeout_maxcnt; +#endif struct _mpt_ioctl_events *events; /* pointer to event log */ fw_image_t **cached_fw; /* Pointer to FW SG List */ Q_TRACKER configQ; /* linked list of config. requests */ @@ -665,6 +672,7 @@ /* reset_phase defs */ #define MPT_IOC_PRE_RESET 0 #define MPT_IOC_POST_RESET 1 +#define MPT_IOC_SETUP_RESET 2 /* * Invent MPT host event (super-set of MPI Events) @@ -880,14 +888,12 @@ #define MPT_NVRAM_WIDE_DISABLE (0x00100000) #define MPT_NVRAM_BOOT_CHOICE (0x00200000) -#ifdef MPT_SCSI_USE_NEW_EH /* The TM_STATE variable is used to provide strict single threading of TM * requests as well as communicate TM error conditions. */ #define TM_STATE_NONE (0) #define TM_STATE_IN_PROGRESS (1) #define TM_STATE_ERROR (2) -#endif typedef struct _MPT_SCSI_HOST { MPT_ADAPTER *ioc; @@ -928,12 +934,8 @@ u8 is_spi; /* Parallel SCSI i/f */ u8 negoNvram; /* DV disabled, nego NVRAM */ u8 is_multipath; /* Multi-path compatible */ -#ifdef MPT_SCSI_USE_NEW_EH u8 tmState; u8 rsvd[1]; -#else - u8 rsvd[2]; -#endif MPT_FRAME_HDR *tmPtr; /* Ptr to TM request*/ MPT_FRAME_HDR *cmdPtr; /* Ptr to nonOS request */ struct scsi_cmnd *abortSCpnt; @@ -1033,8 +1035,10 @@ extern void mpt_print_ioc_summary(MPT_ADAPTER *ioc, char *buf, int *size, int len, int showlan); extern int mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag); extern int mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *cfg); +extern int mpt_toolbox(MPT_ADAPTER *ioc, CONFIGPARMS *cfg); extern void *mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size, int *frags, int *alloc_sz); extern void mpt_free_fw_memory(MPT_ADAPTER *ioc, fw_image_t **alt_img); +extern int mpt_findImVolumes(MPT_ADAPTER *ioc); extern int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc); /* diff -Nru a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c --- a/drivers/message/fusion/mptctl.c Sun Mar 14 14:20:06 2004 +++ b/drivers/message/fusion/mptctl.c Sun Mar 14 14:20:06 2004 @@ -29,7 +29,7 @@ * * (see also mptbase.c) * - * Copyright (c) 1999-2003 LSI Logic Corporation + * Copyright (c) 1999-2004 LSI Logic Corporation * Originally By: Steven J. Ralston, Noah Romer * (mailto:sjralston1@netscape.net) * (mailto:mpt_linux_developer@lsil.com) @@ -82,6 +82,7 @@ #include #include #include +#include #include #include @@ -91,7 +92,7 @@ #include "../../scsi/scsi.h" #include "../../scsi/hosts.h" -#define COPYRIGHT "Copyright (c) 1999-2003 LSI Logic Corporation" +#define COPYRIGHT "Copyright (c) 1999-2004 LSI Logic Corporation" #define MODULEAUTHOR "Steven J. Ralston, Noah Romer, Pamela Delaney" #include "mptbase.h" #include "mptctl.h" @@ -260,6 +261,7 @@ iocStatus = reply->u.reply.IOCStatus & MPI_IOCSTATUS_MASK; if (iocStatus == MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED) { if (ioc->ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE) { + ioc->ioctl->reset &= ~MPTCTL_RESET_OK; del_timer (&ioc->ioctl->timer); ioc->ioctl->timer.expires = jiffies + HZ; add_timer(&ioc->ioctl->timer); @@ -456,7 +458,7 @@ unsigned long flags; spin_lock_irqsave(&hd->ioc->FreeQlock, flags); -#ifdef MPT_SCSI_USE_NEW_EH + if (hd->tmState == TM_STATE_NONE) { hd->tmState = TM_STATE_IN_PROGRESS; hd->tmPending = 1; @@ -465,15 +467,7 @@ spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); return -EBUSY; } -#else - if (hd->tmPending) { - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - return -EBUSY; - } else { - hd->tmPending = 1; - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - } -#endif + return 0; } @@ -488,14 +482,10 @@ return; spin_lock_irqsave(&ioc->FreeQlock, flags); -#ifdef MPT_SCSI_USE_NEW_EH + hd->tmState = TM_STATE_ERROR; hd->tmPending = 0; spin_unlock_irqrestore(&ioc->FreeQlock, flags); -#else - hd->tmPending = 0; - spin_unlock_irqrestore(&ioc->FreeQlock, flags); -#endif return; } @@ -513,9 +503,12 @@ { MPT_IOCTL *ioctl = ioc->ioctl; dctlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to IOCTL driver!\n", - reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")); + reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( + reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); - if (reset_phase == MPT_IOC_PRE_RESET){ + if (reset_phase == MPT_IOC_SETUP_RESET){ + ; + } else if (reset_phase == MPT_IOC_PRE_RESET){ /* Someone has called the reset handler to * do a hard reset. No more replies from the FW. @@ -532,13 +525,15 @@ } } else { + ioctl->tmPtr = NULL; + /* Set the status and continue IOCTL * processing. All memory will be free'd * by originating thread after wake_up is * called. */ if (ioctl && (ioctl->status & MPT_IOCTL_STATUS_TIMER_ACTIVE)){ - ioctl->status = MPT_IOCTL_STATUS_DID_IOCRESET; + ioctl->status |= MPT_IOCTL_STATUS_DID_IOCRESET; /* Wake up the calling process */ @@ -620,7 +615,11 @@ return -ENODEV; } - + if (!iocp->active) { + printk(KERN_ERR "%s::mptctl_ioctl() @%d - Controller disabled.\n", + __FILE__, __LINE__); + return -EFAULT; + } /* Handle those commands that are just returning * information stored in the driver. @@ -691,7 +690,7 @@ return -ENODEV; /* (-6) No such device or address */ } - if (mpt_HardResetHandler(iocp, NO_SLEEP) != 0) { + if (mpt_HardResetHandler(iocp, CAN_SLEEP) != 0) { printk (KERN_ERR "%s@%d::mptctl_do_reset - reset failed.\n", __FILE__, __LINE__); return -1; @@ -1254,10 +1253,10 @@ /* Fill in the data and return the structure to the calling * program */ - if (ioc->chip_type == C1030) - karg.adapterType = MPT_IOCTL_INTERFACE_SCSI; - else + if ((int)ioc->chip_type <= (int) FC929) karg.adapterType = MPT_IOCTL_INTERFACE_FC; + else + karg.adapterType = MPT_IOCTL_INTERFACE_SCSI; port = karg.hdr.port; @@ -1307,7 +1306,8 @@ /* Set the Version Strings. */ - strlcpy (karg.driverVersion, MPT_LINUX_PACKAGE_NAME, MPT_IOCTL_VERSION_LENGTH); + strncpy (karg.driverVersion, MPT_LINUX_PACKAGE_NAME, MPT_IOCTL_VERSION_LENGTH); + karg.driverVersion[MPT_IOCTL_VERSION_LENGTH-1]='\0'; karg.busChangeEvent = 0; karg.hostId = ioc->pfacts[port].PortSCSIID; @@ -1343,15 +1343,18 @@ MPT_ADAPTER *ioc; struct Scsi_Host *sh; MPT_SCSI_HOST *hd; + VirtDevice *vdev; char *pmem; int *pdata; + IOCPage2_t *pIoc2; int iocnum; int numDevices = 0; unsigned int max_id; - int ii, jj, lun; + int id, jj, indexed_lun, lun_index; + u32 lun; int maxWordsLeft; int numBytes; - u8 port; + u8 port, devType, bus_id; dctlprintk(("mptctl_gettargetinfo called.\n")); if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_targetinfo))) { @@ -1418,27 +1421,59 @@ * sh->max_id = maximum target ID + 1 */ if (hd && hd->Targets) { - ii = 0; - while (ii <= max_id) { - if (hd->Targets[ii]) { - for (jj = 0; jj <= MPT_LAST_LUN; jj++) { - lun = (1 << jj); - if (hd->Targets[ii]->luns & lun) { - numDevices++; - *pdata = (jj << 16) | ii; - --maxWordsLeft; - - pdata++; - - if (maxWordsLeft <= 0) - break; + mpt_findImVolumes(ioc); + pIoc2 = ioc->spi_data.pIocPg2; + for ( id = 0; id <= max_id; id++ ) { + if ( pIoc2 && pIoc2->NumActiveVolumes && + ( id == pIoc2->RaidVolume[0].VolumeID ) ) { + if (maxWordsLeft <= 0) { + printk(KERN_ERR "mptctl_gettargetinfo - " + "buffer is full but volume is available on ioc %d\n, numDevices=%d", iocnum, numDevices); + goto data_space_full; + } + if ( ( pIoc2->RaidVolume[0].Flags & MPI_IOCPAGE2_FLAG_VOLUME_INACTIVE ) == 0 ) + devType = 0x80; + else + devType = 0xC0; + bus_id = pIoc2->RaidVolume[0].VolumeBus; + numDevices++; + *pdata = ( (devType << 24) | (bus_id << 8) | id ); + dctlprintk((KERN_ERR "mptctl_gettargetinfo - " + "volume ioc=%d target=%x numDevices=%d pdata=%p\n", iocnum, *pdata, numDevices, pdata)); + pdata++; + --maxWordsLeft; + } else { + vdev = hd->Targets[id]; + if (vdev) { + for (jj = 0; jj <= MPT_LAST_LUN; jj++) { + lun_index = (jj >> 5); + indexed_lun = (jj % 32); + lun = (1 << indexed_lun); + if (vdev->luns[lun_index] & lun) { + if (maxWordsLeft <= 0) { + printk(KERN_ERR + "mptctl_gettargetinfo - " + "buffer is full but more targets are available on ioc %d numDevices=%d\n", + iocnum, numDevices); + goto data_space_full; + } + bus_id = vdev->bus_id; + numDevices++; + *pdata = ( (jj << 16) | (bus_id << 8) | id ); + dctlprintk((KERN_ERR + "mptctl_gettargetinfo - " + "target ioc=%d target=%x numDevices=%d pdata=%p\n", + iocnum, *pdata, numDevices, pdata)); + pdata++; + --maxWordsLeft; + } } } } - ii++; } } } +data_space_full: karg.numDevices = numDevices; /* Copy part of the data from kernel memory to user memory @@ -1507,8 +1542,10 @@ #else karg.chip_type = ioc->chip_type; #endif - strlcpy (karg.name, ioc->name, MPT_MAX_NAME); - strlcpy (karg.product, ioc->prod_name, MPT_PRODUCT_LENGTH); + strncpy (karg.name, ioc->name, MPT_MAX_NAME); + karg.name[MPT_MAX_NAME-1]='\0'; + strncpy (karg.product, ioc->prod_name, MPT_PRODUCT_LENGTH); + karg.product[MPT_PRODUCT_LENGTH-1]='\0'; /* Copy the data from kernel memory to user memory */ @@ -1806,22 +1843,20 @@ MPT_FRAME_HDR *mf = NULL; MPIHeader_t *hdr; char *psge; - MptSge_t *this_sge = NULL; - MptSge_t *sglbuf = NULL; struct buflist bufIn; /* data In buffer */ struct buflist bufOut; /* data Out buffer */ - dma_addr_t sglbuf_dma; - dma_addr_t dma_addr; + dma_addr_t dma_addr_in; + dma_addr_t dma_addr_out; int dir; /* PCI data direction */ int sgSize = 0; /* Num SG elements */ - int this_alloc; - int iocnum, flagsLength; - int sz, rc = 0; - int msgContext; + int iocnum, flagsLength; + int sz, rc = 0; + int msgContext; int tm_flags_set = 0; u16 req_idx; dctlprintk(("mptctl_do_mpt_command called.\n")); + bufIn.kptr = bufOut.kptr = NULL; if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { @@ -1848,7 +1883,7 @@ if (karg.dataOutSize > 0) sz += sizeof(dma_addr_t) + sizeof(u32); - if ( sz > ioc->req_sz) { + if (sz > ioc->req_sz) { printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " "Request frame too large (%d) maximum (%d)\n", __FILE__, __LINE__, sz, ioc->req_sz); @@ -1891,6 +1926,9 @@ switch (hdr->Function) { case MPI_FUNCTION_IOC_FACTS: case MPI_FUNCTION_PORT_FACTS: + karg.dataOutSize = karg.dataInSize = 0; + break; + case MPI_FUNCTION_CONFIG: case MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND: case MPI_FUNCTION_FC_EX_LINK_SRVC_SEND: @@ -1928,12 +1966,14 @@ */ if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE) pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; + else + pScsiReq->SenseBufferLength = karg.maxSenseBytes; pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma + (req_idx * MPT_SENSE_BUFFER_ALLOC)); - if ( (hd = (MPT_SCSI_HOST *) ioc->sh->hostdata)) { + if ((hd = (MPT_SCSI_HOST *) ioc->sh->hostdata)) { if (hd->Targets) pTarget = hd->Targets[target]; } @@ -1944,11 +1984,10 @@ /* Have the IOCTL driver set the direction based * on the dataOutSize (ordering issue with Sparc). */ - if (karg.dataOutSize > 0 ) { + if (karg.dataOutSize > 0) { scsidir = MPI_SCSIIO_CONTROL_WRITE; dataSize = karg.dataOutSize; - } - else { + } else { scsidir = MPI_SCSIIO_CONTROL_READ; dataSize = karg.dataInSize; } @@ -1990,6 +2029,8 @@ */ if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE) pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; + else + pScsiReq->SenseBufferLength = karg.maxSenseBytes; pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma @@ -2001,11 +2042,10 @@ /* Have the IOCTL driver set the direction based * on the dataOutSize (ordering issue with Sparc). */ - if (karg.dataOutSize > 0 ) { + if (karg.dataOutSize > 0) { scsidir = MPI_SCSIIO_CONTROL_WRITE; dataSize = karg.dataOutSize; - } - else { + } else { scsidir = MPI_SCSIIO_CONTROL_READ; dataSize = karg.dataInSize; } @@ -2033,7 +2073,7 @@ __FILE__, __LINE__); rc = -EFAULT; goto done_free_mem; - } else if (mptctl_set_tm_flags(hd) != 0) { + } else if (mptctl_set_tm_flags(hd) != 0) { rc = -EPERM; goto done_free_mem; } @@ -2107,7 +2147,7 @@ * preceede the data in (read) SGE. psgList is used to free the * allocated memory. */ - psge = (char *) ( ((int *) mf) + karg.dataSgeOffset); + psge = (char *) (((int *) mf) + karg.dataSgeOffset); flagsLength = 0; /* bufIn and bufOut are used for user to kernel space transfers @@ -2115,30 +2155,18 @@ bufIn.kptr = bufOut.kptr = NULL; bufIn.len = bufOut.len = 0; - if (karg.dataOutSize > 0 ) + if (karg.dataOutSize > 0) sgSize ++; - if (karg.dataInSize > 0 ) + if (karg.dataInSize > 0) sgSize ++; if (sgSize > 0) { - /* Allocate memory for the SGL. - * Used to free kernel memory once - * the MF is freed. - */ - sglbuf = pci_alloc_consistent (ioc->pcidev, - sgSize*sizeof(MptSge_t), &sglbuf_dma); - if (sglbuf == NULL) { - rc = -ENOMEM; - goto done_free_mem; - } - this_sge = sglbuf; - /* Set up the dataOut memory allocation */ if (karg.dataOutSize > 0) { dir = PCI_DMA_TODEVICE; - if (karg.dataInSize > 0 ) { + if (karg.dataInSize > 0) { flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_DIRECTION | mpt_addr_size() ) @@ -2147,22 +2175,25 @@ flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE; } flagsLength |= karg.dataOutSize; - - this_alloc = karg.dataOutSize; - bufOut.len = this_alloc; + bufOut.len = karg.dataOutSize; bufOut.kptr = pci_alloc_consistent( - ioc->pcidev, this_alloc, &dma_addr); + ioc->pcidev, bufOut.len, &dma_addr_out); if (bufOut.kptr == NULL) { rc = -ENOMEM; goto done_free_mem; } else { + /* Set up this SGE. + * Copy to MF and to sglbuf + */ + mpt_add_sge(psge, flagsLength, dma_addr_out); + psge += (sizeof(u32) + sizeof(dma_addr_t)); + /* Copy user data to kernel space. */ if (copy_from_user(bufOut.kptr, karg.dataOutBufPtr, bufOut.len)) { - printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - Unable " "to read user data " @@ -2171,16 +2202,6 @@ rc = -EFAULT; goto done_free_mem; } - - /* Set up this SGE. - * Copy to MF and to sglbuf - */ - mpt_add_sge(psge, flagsLength, dma_addr); - psge += (sizeof(u32) + sizeof(dma_addr_t)); - - this_sge->FlagsLength = flagsLength; - this_sge->Address = dma_addr; - this_sge++; } } @@ -2189,10 +2210,10 @@ flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; flagsLength |= karg.dataInSize; - this_alloc = karg.dataInSize; - bufIn.len = this_alloc; + bufIn.len = karg.dataInSize; bufIn.kptr = pci_alloc_consistent(ioc->pcidev, - this_alloc, &dma_addr); + bufIn.len, &dma_addr_in); + if (bufIn.kptr == NULL) { rc = -ENOMEM; goto done_free_mem; @@ -2200,11 +2221,7 @@ /* Set up this SGE * Copy to MF and to sglbuf */ - mpt_add_sge(psge, flagsLength, dma_addr); - - this_sge->FlagsLength = flagsLength; - this_sge->Address = dma_addr; - this_sge++; + mpt_add_sge(psge, flagsLength, dma_addr_in); } } } else { @@ -2228,7 +2245,7 @@ if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) { rc = mpt_send_handshake_request(mptctl_id, ioc->id, - sizeof(SCSITaskMgmt_t), (u32*)mf, NO_SLEEP); + sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP); if (rc == 0) { wait_event(mptctl_wait, ioc->ioctl->wait_done); } else { @@ -2236,45 +2253,41 @@ tm_flags_set= 0; del_timer(&ioc->ioctl->timer); ioc->ioctl->status &= ~MPT_IOCTL_STATUS_TIMER_ACTIVE; - ioc->ioctl->status = MPT_IOCTL_STATUS_TM_FAILED; + ioc->ioctl->status |= MPT_IOCTL_STATUS_TM_FAILED; + mpt_free_msg_frame(mptctl_id, ioc->id, mf); } } else { mpt_put_msg_frame(mptctl_id, ioc->id, mf); wait_event(mptctl_wait, ioc->ioctl->wait_done); } - /* The command is complete. * Return data to the user. + mf = NULL; + + /* MF Cleanup: + * If command failed and failure triggered a diagnostic reset + * OR a diagnostic reset happens during command processing, + * no data, messaging queues are reset (mf cannot be accessed), + * and status is DID_IOCRESET * - * If command completed, mf has been freed so cannot - * use this memory. + * If a user-requested bus reset fails to be handshaked, then + * mf is returned to free queue and status is TM_FAILED. * - * If timeout, a recovery mechanism has been called. - * Need to free the mf. + * Otherise, the command completed and the mf was freed + # by ISR (mf cannot be touched). */ if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_IOCRESET) { - - /* A timeout - there is no data to return to the - * the user other than an error. - * The timer callback deleted the + /* The timer callback deleted the * timer and reset the adapter queues. */ printk(KERN_WARNING "%s@%d::mptctl_do_mpt_command - " "Timeout Occurred on IOCTL! Reset IOC.\n", __FILE__, __LINE__); tm_flags_set= 0; rc = -ETIME; - - /* Free memory and return to the calling function - */ - goto done_free_mem; } else if (ioc->ioctl->status & MPT_IOCTL_STATUS_TM_FAILED) { - /* User TM request failed! + /* User TM request failed! mf has not been freed. */ rc = -ENODATA; } else { - /* Callback freed request frame. - */ - mf = NULL; - /* If a valid reply frame, copy to the user. * Offset 2: reply length in U32's */ @@ -2332,42 +2345,31 @@ } done_free_mem: - /* Clear status bits. - */ - ioc->ioctl->status = 0; + /* Clear all status bits except TMTIMER_ACTIVE, this bit is cleared + * upon completion of the TM command. + * ioc->ioctl->status = 0; + */ + ioc->ioctl->status &= ~(MPT_IOCTL_STATUS_TIMER_ACTIVE | MPT_IOCTL_STATUS_TM_FAILED | + MPT_IOCTL_STATUS_COMMAND_GOOD | MPT_IOCTL_STATUS_SENSE_VALID | + MPT_IOCTL_STATUS_RF_VALID | MPT_IOCTL_STATUS_DID_IOCRESET); if (tm_flags_set) mptctl_free_tm_flags(ioc); - if (sglbuf) { - this_sge = sglbuf; - - /* Free the allocated memory. - */ - if (bufOut.kptr != NULL ) { - dma_addr = this_sge->Address; - this_sge++; /* go to next structure */ - this_alloc = bufOut.len; - pci_free_consistent(ioc->pcidev, - this_alloc, (void *) bufOut.kptr, dma_addr); - } - - if (bufIn.kptr != NULL ) { - dma_addr = this_sge->Address; - this_alloc = bufIn.len; - - pci_free_consistent(ioc->pcidev, - this_alloc, (void *) bufIn.kptr, dma_addr); - } - - this_alloc = sgSize * sizeof(MptSge_t); + /* Free the allocated memory. + */ + if (bufOut.kptr != NULL) { pci_free_consistent(ioc->pcidev, - this_alloc, (void *) sglbuf, sglbuf_dma); + bufOut.len, (void *) bufOut.kptr, dma_addr_out); + } + if (bufIn.kptr != NULL) { + pci_free_consistent(ioc->pcidev, + bufIn.len, (void *) bufIn.kptr, dma_addr_in); } - /* mf will be null if allocation failed OR - * if command completed OK (callback freed) + /* mf is null if command issued successfully + * otherwise, failure occured after mf acquired. */ if (mf) mpt_free_msg_frame(mptctl_id, ioc->id, mf); @@ -2405,7 +2407,7 @@ */ if (data_size == sizeof(hp_host_info_t)) cim_rev = 1; - else if (data_size == (sizeof(hp_host_info_t) + 12)) + else if (data_size == sizeof(hp_host_info_rev0_t)) cim_rev = 0; /* obsolete */ else return -EFAULT; @@ -2478,7 +2480,7 @@ cfg.dir = 0; /* read */ cfg.timeout = 10; - strlcpy(karg.serial_number, " ", sizeof(karg.serial_number)); + strncpy(karg.serial_number, " ", 24); if (mpt_config(ioc, &cfg) == 0) { if (cfg.hdr->PageLength > 0) { /* Issue the second config page request */ @@ -2489,9 +2491,10 @@ cfg.physAddr = buf_dma; if (mpt_config(ioc, &cfg) == 0) { ManufacturingPage0_t *pdata = (ManufacturingPage0_t *) pbuf; - if (strlen(pdata->BoardTracerNumber) > 1) - strlcpy(karg.serial_number, pdata->BoardTracerNumber, - sizeof(karg.serial_number)); + if (strlen(pdata->BoardTracerNumber) > 1) { + strncpy(karg.serial_number, pdata->BoardTracerNumber, 24); + karg.serial_number[24-1]='\0'; + } } pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma); pbuf = NULL; @@ -2535,6 +2538,20 @@ } } + cfg.pageAddr = 0; + cfg.action = MPI_TOOLBOX_ISTWI_READ_WRITE_TOOL; + cfg.dir = MPI_TB_ISTWI_FLAGS_READ; + cfg.timeout = 10; + pbuf = pci_alloc_consistent(ioc->pcidev, 4, &buf_dma); + if (pbuf) { + cfg.physAddr = buf_dma; + if ((mpt_toolbox(ioc, &cfg)) == 0) { + karg.rsvd = *(u32 *)pbuf; + } + pci_free_consistent(ioc->pcidev, 4, pbuf, buf_dma); + pbuf = NULL; + } + /* Copy the data from kernel memory to user memory */ if (copy_to_user((char *)arg, &karg, @@ -2736,6 +2753,19 @@ * to ensure the structure contents is properly processed by mptctl. */ static int +compat_mptctl_ioctl(unsigned int fd, unsigned int cmd, + unsigned long arg, struct file *filp) +{ + int ret; + + lock_kernel(); + dctlprintk((KERN_INFO MYNAM "::compat_mptctl_ioctl() called\n")); + ret = mptctl_ioctl(filp->f_dentry->d_inode, filp, cmd, arg); + unlock_kernel(); + return ret; +} + +static int compat_mptfwxfer_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *filp) { @@ -2875,30 +2905,30 @@ } #ifdef CONFIG_COMPAT - err = register_ioctl32_conversion(MPTIOCINFO, NULL); + err = register_ioctl32_conversion(MPTIOCINFO, compat_mptctl_ioctl); if (++where && err) goto out_fail; - err = register_ioctl32_conversion(MPTIOCINFO1, NULL); + err = register_ioctl32_conversion(MPTIOCINFO1, compat_mptctl_ioctl); if (++where && err) goto out_fail; - err = register_ioctl32_conversion(MPTTARGETINFO, NULL); + err = register_ioctl32_conversion(MPTTARGETINFO, compat_mptctl_ioctl); if (++where && err) goto out_fail; - err = register_ioctl32_conversion(MPTTEST, NULL); + err = register_ioctl32_conversion(MPTTEST, compat_mptctl_ioctl); if (++where && err) goto out_fail; - err = register_ioctl32_conversion(MPTEVENTQUERY, NULL); + err = register_ioctl32_conversion(MPTEVENTQUERY, compat_mptctl_ioctl); if (++where && err) goto out_fail; - err = register_ioctl32_conversion(MPTEVENTENABLE, NULL); + err = register_ioctl32_conversion(MPTEVENTENABLE, compat_mptctl_ioctl); if (++where && err) goto out_fail; - err = register_ioctl32_conversion(MPTEVENTREPORT, NULL); + err = register_ioctl32_conversion(MPTEVENTREPORT, compat_mptctl_ioctl); if (++where && err) goto out_fail; - err = register_ioctl32_conversion(MPTHARDRESET, NULL); + err = register_ioctl32_conversion(MPTHARDRESET, compat_mptctl_ioctl); if (++where && err) goto out_fail; err = register_ioctl32_conversion(MPTCOMMAND32, compat_mpt_command); if (++where && err) goto out_fail; err = register_ioctl32_conversion(MPTFWDOWNLOAD32, compat_mptfwxfer_ioctl); if (++where && err) goto out_fail; - err = register_ioctl32_conversion(HP_GETHOSTINFO, NULL); + err = register_ioctl32_conversion(HP_GETHOSTINFO, compat_mptctl_ioctl); if (++where && err) goto out_fail; - err = register_ioctl32_conversion(HP_GETTARGETINFO, NULL); + err = register_ioctl32_conversion(HP_GETTARGETINFO, compat_mptctl_ioctl); if (++where && err) goto out_fail; #endif diff -Nru a/drivers/message/fusion/mptctl.h b/drivers/message/fusion/mptctl.h --- a/drivers/message/fusion/mptctl.h Sun Mar 14 14:20:07 2004 +++ b/drivers/message/fusion/mptctl.h Sun Mar 14 14:20:07 2004 @@ -15,7 +15,7 @@ * * (see also mptbase.c) * - * Copyright (c) 1999-2003 LSI Logic Corporation + * Copyright (c) 1999-2004 LSI Logic Corporation * Originally By: Steven J. Ralston * (mailto:sjralston1@netscape.net) * (mailto:mpt_linux_developer@lsil.com) @@ -342,6 +342,7 @@ #define CPQFCTS_IOC_MAGIC 'Z' #define HP_IOC_MAGIC 'Z' #define HP_GETHOSTINFO _IOR(HP_IOC_MAGIC, 20, hp_host_info_t) +#define HP_GETHOSTINFO1 _IOR(HP_IOC_MAGIC, 20, hp_host_info_rev0_t) #define HP_GETTARGETINFO _IOR(HP_IOC_MAGIC, 21, hp_target_info_t) /* All HP IOCTLs must include this header @@ -357,7 +358,7 @@ /* * Header: * iocnum required (input) - * host ignored + * host ignored * channe ignored * id ignored * lun ignored @@ -371,9 +372,9 @@ u8 devfn; u8 bus; ushort host_no; /* SCSI Host number, if scsi driver not loaded*/ - u8 fw_version[16]; /* string */ + u8 fw_version[16]; /* string */ u8 serial_number[24]; /* string */ - u32 ioc_status; + u32 ioc_status; u32 bus_phys_width; u32 base_io_addr; u32 rsvd; @@ -382,10 +383,33 @@ unsigned int timeouts; /* num timeouts */ } hp_host_info_t; +/* replace ulongs with uints, need to preserve backwards + * compatibility. + */ +typedef struct _hp_host_info_rev0 { + hp_header_t hdr; + u16 vendor; + u16 device; + u16 subsystem_vendor; + u16 subsystem_id; + u8 devfn; + u8 bus; + ushort host_no; /* SCSI Host number, if scsi driver not loaded*/ + u8 fw_version[16]; /* string */ + u8 serial_number[24]; /* string */ + u32 ioc_status; + u32 bus_phys_width; + u32 base_io_addr; + u32 rsvd; + unsigned long hard_resets; /* driver initiated resets */ + unsigned long soft_resets; /* ioc, external resets */ + unsigned long timeouts; /* num timeouts */ +} hp_host_info_rev0_t; + /* * Header: * iocnum required (input) - * host required + * host required * channel required (bus number) * id required * lun ignored diff -Nru a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c --- a/drivers/message/fusion/mptlan.c Sun Mar 14 14:20:07 2004 +++ b/drivers/message/fusion/mptlan.c Sun Mar 14 14:20:07 2004 @@ -23,7 +23,7 @@ * * (see also mptbase.c) * - * Copyright (c) 2000-2003 LSI Logic Corporation + * Copyright (c) 2000-2004 LSI Logic Corporation * Originally By: Noah Romer * (mailto:mpt_linux_developer@lsil.com) * @@ -337,15 +337,18 @@ mpt_lan_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) { struct net_device *dev = mpt_landev[ioc->id]; - struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); dlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to LAN driver!\n", - reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")); + reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( + reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); if (priv->mpt_rxfidx == NULL) return (1); - if (reset_phase == MPT_IOC_PRE_RESET) { + if (reset_phase == MPT_IOC_SETUP_RESET) { + ; + } else if (reset_phase == MPT_IOC_PRE_RESET) { int i; unsigned long flags; @@ -406,7 +409,7 @@ static int mpt_lan_open(struct net_device *dev) { - struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); int i; if (mpt_lan_reset(dev) != 0) { @@ -497,7 +500,7 @@ { MPT_FRAME_HDR *mf; LANResetRequest_t *pResetReq; - struct mpt_lan_priv *priv = (struct mpt_lan_priv *)dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); mf = mpt_get_msg_frame(LanCtx, priv->mpt_dev->id); @@ -526,7 +529,7 @@ static int mpt_lan_close(struct net_device *dev) { - struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); MPT_ADAPTER *mpt_dev = priv->mpt_dev; unsigned int timeout; int i; @@ -587,7 +590,7 @@ static struct net_device_stats * mpt_lan_get_stats(struct net_device *dev) { - struct mpt_lan_priv *priv = (struct mpt_lan_priv *)dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); return (struct net_device_stats *) &priv->stats; } @@ -607,7 +610,7 @@ static void mpt_lan_tx_timeout(struct net_device *dev) { - struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); MPT_ADAPTER *mpt_dev = priv->mpt_dev; if (mpt_dev->active) { @@ -621,7 +624,7 @@ static int mpt_lan_send_turbo(struct net_device *dev, u32 tmsg) { - struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); MPT_ADAPTER *mpt_dev = priv->mpt_dev; struct sk_buff *sent; unsigned long flags; @@ -654,7 +657,7 @@ static int mpt_lan_send_reply(struct net_device *dev, LANSendReply_t *pSendRep) { - struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); MPT_ADAPTER *mpt_dev = priv->mpt_dev; struct sk_buff *sent; unsigned long flags; @@ -727,7 +730,7 @@ static int mpt_lan_sdu_send (struct sk_buff *skb, struct net_device *dev) { - struct mpt_lan_priv *priv = (struct mpt_lan_priv *) dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); MPT_ADAPTER *mpt_dev = priv->mpt_dev; MPT_FRAME_HDR *mf; LANSendRequest_t *pSendReq; @@ -955,11 +958,13 @@ return -ENOMEM; } - pci_dma_sync_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, - priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE); memcpy(skb_put(skb, len), old_skb->data, len); + pci_dma_sync_single_for_device(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE); goto out; } @@ -1113,12 +1118,17 @@ // IOC_AND_NETDEV_NAMES_s_s(dev), // i, l)); - pci_dma_sync_single(mpt_dev->pcidev, - priv->RcvCtl[ctx].dma, - priv->RcvCtl[ctx].len, - PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(mpt_dev->pcidev, + priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, + PCI_DMA_FROMDEVICE); memcpy(skb_put(skb, l), old_skb->data, l); + pci_dma_sync_single_for_device(mpt_dev->pcidev, + priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, + PCI_DMA_FROMDEVICE); + priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; szrem -= l; } @@ -1136,11 +1146,18 @@ return -ENOMEM; } - pci_dma_sync_single(mpt_dev->pcidev, priv->RcvCtl[ctx].dma, - priv->RcvCtl[ctx].len, PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(mpt_dev->pcidev, + priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, + PCI_DMA_FROMDEVICE); memcpy(skb_put(skb, len), old_skb->data, len); + pci_dma_sync_single_for_device(mpt_dev->pcidev, + priv->RcvCtl[ctx].dma, + priv->RcvCtl[ctx].len, + PCI_DMA_FROMDEVICE); + spin_lock_irqsave(&priv->rxfidx_lock, flags); priv->mpt_rxfidx[++priv->mpt_rxfidx_tail] = ctx; spin_unlock_irqrestore(&priv->rxfidx_lock, flags); @@ -1369,7 +1386,7 @@ dev->mtu = MPT_LAN_MTU; - priv = (struct mpt_lan_priv *) dev->priv; + priv = netdev_priv(dev); priv->mpt_dev = mpt_dev; priv->pnum = pnum; diff -Nru a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c --- a/drivers/message/fusion/mptscsih.c Sun Mar 14 14:20:09 2004 +++ b/drivers/message/fusion/mptscsih.c Sun Mar 14 14:20:09 2004 @@ -21,7 +21,7 @@ * * (see mptbase.c) * - * Copyright (c) 1999-2003 LSI Logic Corporation + * Copyright (c) 1999-2004 LSI Logic Corporation * Original author: Steven J. Ralston * (mailto:sjralston1@netscape.net) * (mailto:mpt_linux_developer@lsil.com) @@ -165,17 +165,19 @@ static MPT_FRAME_HDR *mptscsih_search_pendingQ(MPT_SCSI_HOST *hd, int scpnt_idx); static void post_pendingQ_commands(MPT_SCSI_HOST *hd); -static int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag); -static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag); +static int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag); +static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag); static int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset); static int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply); -static void mptscsih_target_settings(MPT_SCSI_HOST *hd, VirtDevice *target, Scsi_Device *sdev); +static void mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen); +void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56); static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq); static void mptscsih_setDevicePage1Flags (u8 width, u8 factor, u8 offset, int *requestedPtr, int *configurationPtr, u8 flags); static void mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id); static int mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target, int flags); +static int mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus); static int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r); static void mptscsih_timer_expired(unsigned long data); static void mptscsih_taskmgmt_timeout(unsigned long data); @@ -190,7 +192,7 @@ static void mptscsih_domainValidation(void *hd); static int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id); static void mptscsih_qas_check(MPT_SCSI_HOST *hd, int id); -static int mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int target); +static int mptscsih_doDv(MPT_SCSI_HOST *hd, int channel, int target); static void mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage); static void mptscsih_fillbuf(char *buffer, int size, int index, int width); #endif @@ -200,8 +202,8 @@ static int __init mptscsih_init (void); static void __exit mptscsih_exit (void); -static int __devinit mptscsih_probe (struct pci_dev *, const struct pci_device_id *); -static void __devexit mptscsih_remove(struct pci_dev *); +static int mptscsih_probe (struct pci_dev *, const struct pci_device_id *); +static void mptscsih_remove(struct pci_dev *); static void mptscsih_shutdown(struct device *); #ifdef CONFIG_PM static int mptscsih_suspend(struct pci_dev *pdev, u32 state); @@ -214,7 +216,6 @@ */ static int mpt_scsi_hosts = 0; -static atomic_t queue_depth; static int ScsiDoneCtx = -1; static int ScsiTaskCtx = -1; @@ -243,6 +244,10 @@ static struct mptscsih_driver_setup driver_setup = MPTSCSIH_DRIVER_SETUP; +#ifdef MPTSCSIH_DBG_TIMEOUT +static Scsi_Cmnd *foo_to[8]; +#endif + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* see mptscsih.h */ @@ -438,10 +443,10 @@ static inline int mptscsih_getFreeChainBuffer(MPT_SCSI_HOST *hd, int *retIndex) { - MPT_FRAME_HDR *chainBuf = NULL; + MPT_FRAME_HDR *chainBuf; unsigned long flags; - int rc = FAILED; - int chain_idx = MPT_HOST_NO_CHAIN; + int rc; + int chain_idx; spin_lock_irqsave(&hd->ioc->FreeQlock, flags); if (!Q_IS_EMPTY(&hd->FreeChainQ)) { @@ -454,6 +459,10 @@ chain_idx = offset / hd->ioc->req_sz; rc = SUCCESS; } + else { + rc = FAILED; + chain_idx = MPT_HOST_NO_CHAIN; + } spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); @@ -506,13 +515,12 @@ /* Map the data portion, if any. * sges_left = 0 if no data transfer. */ - sges_left = SCpnt->use_sg; - if (SCpnt->use_sg) { + if ( (sges_left = SCpnt->use_sg) ) { sges_left = pci_map_sg(hd->ioc->pcidev, (struct scatterlist *) SCpnt->request_buffer, SCpnt->use_sg, scsi_to_pci_dma_dir(SCpnt->sc_data_direction)); - if (sges_left == 0) + if (sges_left == 0) return FAILED; } else if (SCpnt->request_bufflen) { dma_addr_t buf_dma_addr; @@ -729,50 +737,67 @@ hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; - if ((mf == NULL) || - (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) { - printk(MYIOC_s_ERR_FMT "%s req frame ptr! (=%p)!\n", - ioc->name, mf?"BAD":"NULL", (void *) mf); - return 0; - } - req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); sc = hd->ScsiLookup[req_idx]; if (sc == NULL) { + MPIHeader_t *hdr = (MPIHeader_t *)mf; + /* Remark: writeSDP1 will use the ScsiDoneCtx * If a SCSI I/O cmd, device disabled by OS and * completion done. Cannot touch sc struct. Just free mem. */ - atomic_dec(&queue_depth); + if (hdr->Function == MPI_FUNCTION_SCSI_IO_REQUEST) + printk(MYIOC_s_ERR_FMT "NULL ScsiCmd ptr!\n", + ioc->name); mptscsih_freeChainBuffers(hd, req_idx); return 1; } - dmfprintk((MYIOC_s_INFO_FMT "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n", - ioc->name, mf, mr, sc, req_idx)); - - atomic_dec(&queue_depth); + dmfprintk((MYIOC_s_INFO_FMT + "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n", + ioc->name, mf, mr, sc, req_idx)); sc->result = DID_OK << 16; /* Set default reply as OK */ pScsiReq = (SCSIIORequest_t *) mf; pScsiReply = (SCSIIOReply_t *) mr; +#ifdef MPTSCSIH_DBG_TIMEOUT + if (ioc->timeout_cnt > 0) { + int ii, left = 0; + + for (ii=0; ii < 8; ii++) { + if (sc == foo_to[ii]) { + printk(MYIOC_s_INFO_FMT "complete (%p, %ld)\n", + ioc->name, sc, jiffies); + foo_to[ii] = NULL; + } + if (foo_to[ii] != NULL) + left++; + } + + if (left == 0) { + ioc->timeout_maxcnt = 0; + ioc->timeout_cnt = 0; + } + } +#endif + if (pScsiReply == NULL) { /* special context reply handling */ ; } else { u32 xfer_cnt; u16 status; - u8 scsi_state; + u8 scsi_state, scsi_status; status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK; scsi_state = pScsiReply->SCSIState; - dsprintk((KERN_NOTICE " Uh-Oh! (%d:%d:%d) mf=%p, mr=%p, sc=%p\n", + dprintk((KERN_NOTICE " Uh-Oh! (%d:%d:%d) mf=%p, mr=%p, sc=%p\n", ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1], mf, mr, sc)); - dsprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh" + dprintk((KERN_NOTICE " IOCStatus=%04xh, SCSIState=%02xh" ", SCSIStatus=%02xh, IOCLogInfo=%08xh\n", status, scsi_state, pScsiReply->SCSIStatus, le32_to_cpu(pScsiReply->IOCLogInfo))); @@ -780,14 +805,6 @@ if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) copy_sense_data(sc, hd, mf, pScsiReply); - /* - * Look for + dump FCP ResponseInfo[]! - */ - if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID) { - dprintk((KERN_NOTICE " FCP_ResponseInfo=%08xh\n", - le32_to_cpu(pScsiReply->ResponseInfo))); - } - switch(status) { case MPI_IOCSTATUS_BUSY: /* 0x0002 */ /* CHECKME! @@ -827,52 +844,45 @@ case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */ case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ /* - * YIKES! I just discovered that SCSI IO which - * returns check condition, SenseKey=05 (ILLEGAL REQUEST) - * and ASC/ASCQ=94/01 (LSI Logic RAID vendor specific), - * comes down this path! * Do upfront check for valid SenseData and give it * precedence! */ - sc->result = (DID_OK << 16) | pScsiReply->SCSIStatus; - if (scsi_state == 0) { - ; - } else if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) { + scsi_status = pScsiReply->SCSIStatus; + sc->result = (DID_OK << 16) | scsi_status; + xfer_cnt = le32_to_cpu(pScsiReply->TransferCount); + if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) { /* Have already saved the status and sense data */ ; - } else if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) { - /* What to do? - */ - sc->result = DID_SOFT_ERROR << 16; - } - else if (scsi_state & MPI_SCSI_STATE_TERMINATED) { - /* Not real sure here either... */ - sc->result = DID_RESET << 16; + } else { + if ( (xfer_cnt == 0) || (sc->underflow > xfer_cnt)) { + sc->result = DID_SOFT_ERROR << 16; + } + if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) { + /* What to do? + */ + sc->result = DID_SOFT_ERROR << 16; + } + else if (scsi_state & MPI_SCSI_STATE_TERMINATED) { + /* Not real sure here either... */ + sc->result = DID_RESET << 16; + } } /* Give report and update residual count. */ - xfer_cnt = le32_to_cpu(pScsiReply->TransferCount); dprintk((KERN_NOTICE " sc->underflow={report ERR if < %02xh bytes xfer'd}\n", sc->underflow)); dprintk((KERN_NOTICE " ActBytesXferd=%02xh\n", xfer_cnt)); sc->resid = sc->request_bufflen - xfer_cnt; dprintk((KERN_NOTICE " SET sc->resid=%02xh\n", sc->resid)); - - if(sc->underflow > xfer_cnt) { - printk(MYIOC_s_INFO_FMT - "SCSI data underrun: underflow=%02x, xfercnt=%02x\n", - ioc->name, sc->underflow, xfer_cnt); - sc->result = DID_SOFT_ERROR << 16; - } - + /* Report Queue Full */ - if (sc->result == MPI_SCSI_STATUS_TASK_SET_FULL) + if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL) mptscsih_report_queue_full(sc, pScsiReply, pScsiReq); - + break; case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ @@ -965,9 +975,7 @@ hd->ScsiLookup[req_idx] = NULL; - MPT_HOST_LOCK(flags); sc->scsi_done(sc); /* Issue the command callback */ - MPT_HOST_UNLOCK(flags); /* Free Chain buffers */ mptscsih_freeChainBuffers(hd, req_idx); @@ -988,7 +996,7 @@ /* Flush the doneQ. */ - dprintk((KERN_INFO MYNAM ": flush_doneQ called\n")); + dtmprintk((KERN_INFO MYNAM ": flush_doneQ called\n")); while (1) { spin_lock_irqsave(&hd->freedoneQlock, flags); if (Q_IS_EMPTY(&hd->doneQ)) { @@ -1013,9 +1021,7 @@ /* Do the OS callback. */ - MPT_HOST_LOCK(flags); SCpnt->scsi_done(SCpnt); - MPT_HOST_UNLOCK(flags); } return; @@ -1055,6 +1061,26 @@ return; } +static void +mptscsih_reset_timeouts (MPT_SCSI_HOST *hd) +{ + Scsi_Cmnd *SCpnt; + int ii; + int max = hd->ioc->req_depth; + + + for (ii= 0; ii < max; ii++) { + if ((SCpnt = hd->ScsiLookup[ii]) != NULL) { + /* calling mod_timer() panics in 2.6 kernel... + * need to investigate + */ +// mod_timer(&SCpnt->eh_timeout, jiffies + (HZ * 60)); + dtmprintk((MYIOC_s_WARN_FMT "resetting SCpnt=%p timeout + 60HZ", + (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt)); + } + } +} + /* * mptscsih_flush_running_cmds - For each command found, search * Scsi_Host instance taskQ and reply to OS. @@ -1068,23 +1094,24 @@ static void mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd) { - Scsi_Cmnd *SCpnt = NULL; - MPT_FRAME_HDR *mf = NULL; + Scsi_Cmnd *SCpnt; + MPT_FRAME_HDR *mf; + MPT_DONE_Q *buffer; int ii; int max = hd->ioc->req_depth; + unsigned long flags; dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n")); for (ii= 0; ii < max; ii++) { if ((SCpnt = hd->ScsiLookup[ii]) != NULL) { /* Command found. - * - * Search pendingQ, if found, - * delete from Q. If found, do not decrement - * queue_depth, command never posted. */ - if (mptscsih_search_pendingQ(hd, ii) == NULL) - atomic_dec(&queue_depth); + + /* Search pendingQ, if found, + * delete from Q. + */ + mptscsih_search_pendingQ(hd, ii); /* Null ScsiLookup index */ @@ -1111,15 +1138,39 @@ } SCpnt->result = DID_RESET << 16; SCpnt->host_scribble = NULL; - MPT_HOST_LOCK(flags); - SCpnt->scsi_done(SCpnt); /* Issue the command callback */ - MPT_HOST_UNLOCK(flags); /* Free Chain buffers */ mptscsih_freeChainBuffers(hd, ii); /* Free Message frames */ mpt_free_msg_frame(ScsiDoneCtx, hd->ioc->id, mf); + +#if 1 + /* Post to doneQ, do not reply until POST phase + * of reset handler....prevents new commands from + * being queued. + */ + spin_lock_irqsave(&hd->freedoneQlock, flags); + if (!Q_IS_EMPTY(&hd->freeQ)) { + buffer = hd->freeQ.head; + Q_DEL_ITEM(buffer); + + /* Set the Scsi_Cmnd pointer + */ + buffer->argp = (void *)SCpnt; + + /* Add to the doneQ + */ + Q_ADD_TAIL(&hd->doneQ.head, buffer, MPT_DONE_Q); + spin_unlock_irqrestore(&hd->freedoneQlock, flags); + } else { + spin_unlock_irqrestore(&hd->freedoneQlock, flags); + SCpnt->scsi_done(SCpnt); + } +#else + SCpnt->scsi_done(SCpnt); /* Issue the command callback */ +#endif + } } @@ -1147,8 +1198,8 @@ int ii; int max = hd->ioc->req_depth; - dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d numIos %d\n", - target, lun, max, atomic_read(&queue_depth))); + dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d\n", + target, lun, max)); for (ii=0; ii < max; ii++) { if (hd->ScsiLookup[ii] != NULL) { @@ -1161,11 +1212,6 @@ if ((mf->TargetID != ((u8)target)) || (mf->LUN[1] != ((u8) lun))) continue; - /* If cmd pended, do not decrement queue_depth, command never posted. - */ - if (mptscsih_search_pendingQ(hd, ii) == NULL) - atomic_dec(&queue_depth); - /* Cleanup */ hd->ScsiLookup[ii] = NULL; @@ -1177,73 +1223,6 @@ return; } -#ifdef DROP_TEST -/* mptscsih_flush_drop_test - Free resources and do callback if - * DROP_TEST enabled. - * - * @hd: Pointer to a SCSI HOST structure - * - * Returns: None. - * - * Must be called while new I/Os are being queued. - */ -static void -mptscsih_flush_drop_test (MPT_SCSI_HOST *hd) -{ - Scsi_Cmnd *sc; - unsigned long flags; - u16 req_idx; - - /* Free resources for the drop test MF - * and chain buffers. - */ - if (dropMfPtr) { - req_idx = le16_to_cpu(dropMfPtr->u.frame.hwhdr.msgctxu.fld.req_idx); - sc = hd->ScsiLookup[req_idx]; - if (sc == NULL) { - printk(MYIOC_s_ERR_FMT "Drop Test: NULL ScsiCmd ptr!\n", - ioc->name); - } else { - /* unmap OS resources, set status, do callback - * free driver resources - */ - if (sc->use_sg) { - pci_unmap_sg(ioc->pcidev, (struct scatterlist *) sc->request_buffer, - sc->use_sg, scsi_to_pci_dma_dir(sc->sc_data_direction)); - } else if (sc->request_bufflen) { - scPrivate *my_priv; - - my_priv = (scPrivate *) &sc->SCp; - pci_unmap_single(ioc->pcidev, (dma_addr_t)(ulong)my_priv->p1, - sc->request_bufflen, - scsi_to_pci_dma_dir(sc->sc_data_direction)); - } - - sc->host_scribble = NULL; - sc->result = DID_RESET << 16; - hd->ScsiLookup[req_idx] = NULL; - atomic_dec(&queue_depth); - MPT_HOST_LOCK(flags); - sc->scsi_done(sc); /* Issue callback */ - MPT_HOST_UNLOCK(flags); - } - - mptscsih_freeChainBuffers(hd, req_idx); - mpt_free_msg_frame(ScsiDoneCtx, ioc->id, dropMfPtr); - printk(MYIOC_s_INFO_FMT "Free'd Dropped cmd (%p)\n", - hd->ioc->name, sc); - printk(MYIOC_s_INFO_FMT "mf (%p) reqidx (%4x)\n", - hd->ioc->name, dropMfPtr, req_idx); - printk(MYIOC_s_INFO_FMT "Num Tot (%d) Good (%d) Bad (%d) \n", - hd->ioc->name, dropTestNum, - dropTestOK, dropTestBad); - } - dropMfPtr = NULL; - - return; -} -#endif - /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * mptscsih_initChainBuffers - Allocate memory for and initialize @@ -1263,18 +1242,15 @@ /* ReqToChain size must equal the req_depth * index = req_idx */ - sz = hd->ioc->req_depth * sizeof(int); if (hd->ReqToChain == NULL) { + sz = hd->ioc->req_depth * sizeof(int); mem = kmalloc(sz, GFP_ATOMIC); if (mem == NULL) return -1; hd->ReqToChain = (int *) mem; - } else { - mem = (u8 *) hd->ReqToChain; } -/* memset(mem, 0xFF, sz); */ - for(ii=0;iiioc->req_depth;ii++) + for (ii = 0; ii < hd->ioc->req_depth; ii++) hd->ReqToChain[ii] = MPT_HOST_NO_CHAIN; /* ChainToChain size must equal the total number @@ -1322,7 +1298,11 @@ if (hd->ChainBuffer == NULL) { /* Allocate free chain buffer pool */ +#if defined(MPTBASE_MEM_ALLOC_FIFO_FIX) + mem = pci_alloc_consistent(&hd->ioc->pcidev32, sz, &hd->ChainBufferDMA); +#else mem = pci_alloc_consistent(hd->ioc->pcidev, sz, &hd->ChainBufferDMA); +#endif if (mem == NULL) return -1; @@ -1405,310 +1385,333 @@ * */ -static int __devinit +static int mptscsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - struct Scsi_Host *sh = NULL; - MPT_SCSI_HOST *hd = NULL; + struct Scsi_Host *sh; + MPT_SCSI_HOST *hd; MPT_ADAPTER *ioc = pci_get_drvdata(pdev); - int portnum; MPT_DONE_Q *freedoneQ; unsigned long flags; int sz, ii; int numSGE = 0; int scale; + int ioc_cap; u8 *mem; int error=0; - for (portnum=0; portnum < ioc->facts.NumberOfPorts; portnum++) { - /* 20010215 -sralston - * Added sanity check on SCSI Initiator-mode enabled - * for this MPT adapter. - */ - if (!(ioc->pfacts[portnum].ProtocolFlags & - MPI_PORTFACTS_PROTOCOL_INITIATOR)) { - printk(MYIOC_s_WARN_FMT - "Skipping because SCSI Initiator mode is NOT enabled!\n", - ioc->name); - continue; - } - - /* 20010202 -sralston - * Added sanity check on readiness of the MPT adapter. - */ - if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) { - printk(MYIOC_s_WARN_FMT - "Skipping because it's not operational!\n", - ioc->name); - continue; - } - - sh = scsi_host_alloc(&driver_template, sizeof(MPT_SCSI_HOST)); - if (sh != NULL) { - spin_lock_irqsave(&ioc->FreeQlock, flags); - - /* Attach the SCSI Host to the IOC structure - */ - ioc->sh = sh; - - sh->io_port = 0; - sh->n_io_port = 0; - sh->irq = 0; - - /* set 16 byte cdb's */ - sh->max_cmd_len = 16; - - /* Yikes! This is important! - * Otherwise, by default, linux - * only scans target IDs 0-7! - * pfactsN->MaxDevices unreliable - * (not supported in early - * versions of the FW). - * max_id = 1 + actual max id, - * max_lun = 1 + actual last lun, - * see hosts.h :o( - */ - if ((int)ioc->chip_type > (int)FC929) { - sh->max_id = MPT_MAX_SCSI_DEVICES; - } else { - /* For FC, increase the queue depth - * from MPT_SCSI_CAN_QUEUE (31) - * to MPT_FC_CAN_QUEUE (63). - */ - sh->can_queue = MPT_FC_CAN_QUEUE; - sh->max_id = - MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255; - } - - sh->max_lun = MPT_LAST_LUN + 1; - sh->max_sectors = MPT_SCSI_MAX_SECTORS; - sh->this_id = ioc->pfacts[portnum].PortSCSIID; - - /* Required entry. - */ - sh->unique_id = ioc->id; - - /* Verify that we won't exceed the maximum - * number of chain buffers - * We can optimize: ZZ = req_sz/sizeof(SGE) - * For 32bit SGE's: - * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ - * + (req_sz - 64)/sizeof(SGE) - * A slightly different algorithm is required for - * 64bit SGEs. - */ - scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); - if (sizeof(dma_addr_t) == sizeof(u64)) { - numSGE = (scale - 1) * - (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 60) / (sizeof(dma_addr_t) + - sizeof(u32)); - } else { - numSGE = 1 + (scale - 1) * - (ioc->facts.MaxChainDepth-1) + scale + - (ioc->req_sz - 64) / (sizeof(dma_addr_t) + - sizeof(u32)); - } - - if (numSGE < sh->sg_tablesize) { - /* Reset this value */ - dprintk((MYIOC_s_INFO_FMT - "Resetting sg_tablesize to %d from %d\n", - ioc->name, numSGE, sh->sg_tablesize)); - sh->sg_tablesize = numSGE; - } - - /* Set the pci device pointer in Scsi_Host structure. - */ - scsi_set_device(sh, &ioc->pcidev->dev); - - spin_unlock_irqrestore(&ioc->FreeQlock, flags); - - hd = (MPT_SCSI_HOST *) sh->hostdata; - hd->ioc = ioc; - hd->max_sge = sh->sg_tablesize; - - if ((int)ioc->chip_type > (int)FC929) - hd->is_spi = 1; + /* 20010202 -sralston + * Added sanity check on readiness of the MPT adapter. + */ + if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) { + printk(MYIOC_s_WARN_FMT + "Skipping because it's not operational!\n", + ioc->name); + return -ENODEV; + } - if (DmpService && (ioc->chip_type == FC919 || - ioc->chip_type == FC929)) { - hd->is_multipath = 1; - } - hd->port = 0; /* FIXME! */ + if (!ioc->active) { + printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n", + ioc->name); + return -ENODEV; + } - /* SCSI needs Scsi_Cmnd lookup table! - * (with size equal to req_depth*PtrSz!) - */ - sz = hd->ioc->req_depth * sizeof(void *); - mem = kmalloc(sz, GFP_ATOMIC); - if (mem == NULL) { - error = -ENOMEM; - goto mptscsih_probe_failed; - } + /* Sanity check - ensure at least 1 port is INITIATOR capable + */ + ioc_cap = 0; + for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) { + if (ioc->pfacts[ii].ProtocolFlags & + MPI_PORTFACTS_PROTOCOL_INITIATOR) + ioc_cap ++; + } - memset(mem, 0, sz); - hd->ScsiLookup = (struct scsi_cmnd **) mem; + if (!ioc_cap) { + printk(MYIOC_s_WARN_FMT + "Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n", + ioc->name, ioc); + return -ENODEV; + } - dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n", - ioc->name, hd->ScsiLookup, sz)); + sh = scsi_host_alloc(&driver_template, sizeof(MPT_SCSI_HOST)); + + if (!sh) { + printk(MYIOC_s_WARN_FMT + "Unable to register controller with SCSI subsystem\n", + ioc->name); + return -1; + } + + spin_lock_irqsave(&ioc->FreeQlock, flags); - if (mptscsih_initChainBuffers(hd, 1) < 0) { - error = -EINVAL; - goto mptscsih_probe_failed; - } + /* Attach the SCSI Host to the IOC structure + */ + ioc->sh = sh; - /* Allocate memory for free and doneQ's - */ - sz = sh->can_queue * sizeof(MPT_DONE_Q); - mem = kmalloc(sz, GFP_ATOMIC); - if (mem == NULL) { - error = -ENOMEM; - goto mptscsih_probe_failed; - } + sh->io_port = 0; + sh->n_io_port = 0; + sh->irq = 0; + + /* set 16 byte cdb's */ + sh->max_cmd_len = 16; + + /* Yikes! This is important! + * Otherwise, by default, linux + * only scans target IDs 0-7! + * pfactsN->MaxDevices unreliable + * (not supported in early + * versions of the FW). + * max_id = 1 + actual max id, + * max_lun = 1 + actual last lun, + * see hosts.h :o( + */ + if ((int)ioc->chip_type > (int)FC929) { + sh->max_id = MPT_MAX_SCSI_DEVICES; + } else { + /* For FC, increase the queue depth + * from MPT_SCSI_CAN_QUEUE (31) + * to MPT_FC_CAN_QUEUE (63). + */ + sh->can_queue = MPT_FC_CAN_QUEUE; + sh->max_id = + MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255; + } + + sh->max_lun = MPT_LAST_LUN + 1; + sh->max_sectors = MPT_SCSI_MAX_SECTORS; + sh->max_channel = 0; + sh->this_id = ioc->pfacts[0].PortSCSIID; + + /* Required entry. + */ + sh->unique_id = ioc->id; + + /* Verify that we won't exceed the maximum + * number of chain buffers + * We can optimize: ZZ = req_sz/sizeof(SGE) + * For 32bit SGE's: + * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ + * + (req_sz - 64)/sizeof(SGE) + * A slightly different algorithm is required for + * 64bit SGEs. + */ + scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); + if (sizeof(dma_addr_t) == sizeof(u64)) { + numSGE = (scale - 1) * + (ioc->facts.MaxChainDepth-1) + scale + + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + + sizeof(u32)); + } else { + numSGE = 1 + (scale - 1) * + (ioc->facts.MaxChainDepth-1) + scale + + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + + sizeof(u32)); + } + + if (numSGE < sh->sg_tablesize) { + /* Reset this value */ + dprintk((MYIOC_s_INFO_FMT + "Resetting sg_tablesize to %d from %d\n", + ioc->name, numSGE, sh->sg_tablesize)); + sh->sg_tablesize = numSGE; + } - memset(mem, 0xFF, sz); - hd->memQ = mem; + /* Set the pci device pointer in Scsi_Host structure. + */ + scsi_set_device(sh, &ioc->pcidev->dev); - /* Initialize the free, done and pending Qs. - */ - Q_INIT(&hd->freeQ, MPT_DONE_Q); - Q_INIT(&hd->doneQ, MPT_DONE_Q); - Q_INIT(&hd->pendingQ, MPT_DONE_Q); - spin_lock_init(&hd->freedoneQlock); - - mem = hd->memQ; - for (ii=0; ii < sh->can_queue; ii++) { - freedoneQ = (MPT_DONE_Q *) mem; - Q_ADD_TAIL(&hd->freeQ.head, freedoneQ, MPT_DONE_Q); - mem += sizeof(MPT_DONE_Q); - } + spin_unlock_irqrestore(&ioc->FreeQlock, flags); - /* Initialize this Scsi_Host - * internal task Q. - */ - Q_INIT(&hd->taskQ, MPT_FRAME_HDR); - hd->taskQcnt = 0; + hd = (MPT_SCSI_HOST *) sh->hostdata; + hd->ioc = ioc; + hd->max_sge = sh->sg_tablesize; + + if ((int)ioc->chip_type > (int)FC929) + hd->is_spi = 1; + + if (DmpService && (ioc->chip_type == FC919 || + ioc->chip_type == FC929)) { + hd->is_multipath = 1; + } + + /* SCSI needs Scsi_Cmnd lookup table! + * (with size equal to req_depth*PtrSz!) + */ + sz = hd->ioc->req_depth * sizeof(void *); + mem = kmalloc(sz, GFP_ATOMIC); + if (mem == NULL) { + error = -ENOMEM; + goto mptscsih_probe_failed; + } - /* Allocate memory for the device structures. - * A non-Null pointer at an offset - * indicates a device exists. - * max_id = 1 + maximum id (hosts.h) - */ - sz = sh->max_id * sizeof(void *); - mem = kmalloc(sz, GFP_ATOMIC); - if (mem == NULL) { - error = -ENOMEM; - goto mptscsih_probe_failed; - } + memset(mem, 0, sz); + hd->ScsiLookup = (struct scsi_cmnd **) mem; - memset(mem, 0, sz); - hd->Targets = (VirtDevice **) mem; + dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n", + ioc->name, hd->ScsiLookup, sz)); + + if (mptscsih_initChainBuffers(hd, 1) < 0) { + error = -EINVAL; + goto mptscsih_probe_failed; + } + + /* Allocate memory for free and doneQ's + */ + sz = sh->can_queue * sizeof(MPT_DONE_Q); + mem = kmalloc(sz, GFP_ATOMIC); + if (mem == NULL) { + error = -ENOMEM; + goto mptscsih_probe_failed; + } - dprintk((KERN_INFO - " Targets @ %p, sz=%d\n", hd->Targets, sz)); + memset(mem, 0xFF, sz); + hd->memQ = mem; + /* Initialize the free, done and pending Qs. + */ + Q_INIT(&hd->freeQ, MPT_DONE_Q); + Q_INIT(&hd->doneQ, MPT_DONE_Q); + Q_INIT(&hd->pendingQ, MPT_DONE_Q); + spin_lock_init(&hd->freedoneQlock); + + mem = hd->memQ; + for (ii=0; ii < sh->can_queue; ii++) { + freedoneQ = (MPT_DONE_Q *) mem; + Q_ADD_TAIL(&hd->freeQ.head, freedoneQ, MPT_DONE_Q); + mem += sizeof(MPT_DONE_Q); + } + + /* Initialize this Scsi_Host + * internal task Q. + */ + Q_INIT(&hd->taskQ, MPT_FRAME_HDR); + hd->taskQcnt = 0; + + /* Allocate memory for the device structures. + * A non-Null pointer at an offset + * indicates a device exists. + * max_id = 1 + maximum id (hosts.h) + */ + sz = sh->max_id * sizeof(void *); + mem = kmalloc(sz, GFP_ATOMIC); + if (mem == NULL) { + error = -ENOMEM; + goto mptscsih_probe_failed; + } - /* Clear the TM flags - */ - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - hd->resetPending = 0; - hd->abortSCpnt = NULL; - hd->tmPtr = NULL; - hd->numTMrequests = 0; + memset(mem, 0, sz); + hd->Targets = (VirtDevice **) mem; - /* Clear the pointer used to store - * single-threaded commands, i.e., those - * issued during a bus scan, dv and - * configuration pages. - */ - hd->cmdPtr = NULL; + dprintk((KERN_INFO + " Targets @ %p, sz=%d\n", hd->Targets, sz)); - /* Initialize this SCSI Hosts' timers - * To use, set the timer expires field - * and add_timer - */ - init_timer(&hd->timer); - hd->timer.data = (unsigned long) hd; - hd->timer.function = mptscsih_timer_expired; - - init_timer(&hd->TMtimer); - hd->TMtimer.data = (unsigned long) hd; - hd->TMtimer.function = mptscsih_taskmgmt_timeout; - hd->qtag_tick = jiffies; + /* Clear the TM flags + */ + hd->tmPending = 0; + hd->tmState = TM_STATE_NONE; + hd->resetPending = 0; + hd->abortSCpnt = NULL; + hd->tmPtr = NULL; + hd->numTMrequests = 0; + + /* Clear the pointer used to store + * single-threaded commands, i.e., those + * issued during a bus scan, dv and + * configuration pages. + */ + hd->cmdPtr = NULL; - /* Moved Earlier Pam D */ - /* ioc->sh = sh; */ + /* Initialize this SCSI Hosts' timers + * To use, set the timer expires field + * and add_timer + */ + init_timer(&hd->timer); + hd->timer.data = (unsigned long) hd; + hd->timer.function = mptscsih_timer_expired; + + init_timer(&hd->TMtimer); + hd->TMtimer.data = (unsigned long) hd; + hd->TMtimer.function = mptscsih_taskmgmt_timeout; + hd->qtag_tick = jiffies; + + /* Moved Earlier Pam D */ + /* ioc->sh = sh; */ + +#ifdef MPTSCSIH_DBG_TIMEOUT + hd->ioc->timeout_hard = 0; + hd->ioc->timeout_delta = 30 * HZ; + hd->ioc->timeout_maxcnt = 0; + hd->ioc->timeout_cnt = 0; + for (ii=0; ii < 8; ii++) + foo_to[ii] = NULL; +#endif + if (hd->is_spi) { + /* Update with the driver setup + * values. + */ + if (hd->ioc->spi_data.maxBusWidth > + driver_setup.max_width) { + hd->ioc->spi_data.maxBusWidth = + driver_setup.max_width; + } - if (hd->is_spi) { - /* Update with the driver setup - * values. - */ - if (hd->ioc->spi_data.maxBusWidth > - driver_setup.max_width) { - hd->ioc->spi_data.maxBusWidth = - driver_setup.max_width; - } + if (hd->ioc->spi_data.minSyncFactor < + driver_setup.min_sync_fac) { + hd->ioc->spi_data.minSyncFactor = + driver_setup.min_sync_fac; + } - if (hd->ioc->spi_data.minSyncFactor < - driver_setup.min_sync_fac) { - hd->ioc->spi_data.minSyncFactor = - driver_setup.min_sync_fac; - } + if (hd->ioc->spi_data.minSyncFactor == MPT_ASYNC) { + hd->ioc->spi_data.maxSyncOffset = 0; + } - if (hd->ioc->spi_data.minSyncFactor == MPT_ASYNC) { - hd->ioc->spi_data.maxSyncOffset = 0; - } + hd->ioc->spi_data.Saf_Te = driver_setup.saf_te; - hd->negoNvram = 0; + hd->negoNvram = 0; #ifndef MPTSCSIH_ENABLE_DOMAIN_VALIDATION - hd->negoNvram = MPT_SCSICFG_USE_NVRAM; + hd->negoNvram = MPT_SCSICFG_USE_NVRAM; #endif - if (driver_setup.dv == 0) { - hd->negoNvram = MPT_SCSICFG_USE_NVRAM; - } - - hd->ioc->spi_data.forceDv = 0; - for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { - hd->ioc->spi_data.dvStatus[ii] = - MPT_SCSICFG_NEGOTIATE; - } - - if (hd->negoNvram == 0) { - for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) - hd->ioc->spi_data.dvStatus[ii] |= - MPT_SCSICFG_DV_NOT_DONE; - } + if (driver_setup.dv == 0) { + hd->negoNvram = MPT_SCSICFG_USE_NVRAM; + } - ddvprintk((MYIOC_s_INFO_FMT - "dv %x width %x factor %x \n", - hd->ioc->name, driver_setup.dv, - driver_setup.max_width, - driver_setup.min_sync_fac)); + hd->ioc->spi_data.forceDv = 0; + for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { + hd->ioc->spi_data.dvStatus[ii] = + MPT_SCSICFG_NEGOTIATE; + } - } + if (hd->negoNvram == 0) { + for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) + hd->ioc->spi_data.dvStatus[ii] |= + MPT_SCSICFG_DV_NOT_DONE; + } - mpt_scsi_hosts++; + ddvprintk((MYIOC_s_INFO_FMT + "dv %x width %x factor %x saf_te %x\n", + hd->ioc->name, driver_setup.dv, + driver_setup.max_width, + driver_setup.min_sync_fac, + driver_setup.saf_te)); + } - error = scsi_add_host (sh, &ioc->pcidev->dev); - if(error) { - dprintk((KERN_ERR MYNAM, - "scsi_add_host failed\n")); - goto mptscsih_probe_failed; - } + mpt_scsi_hosts++; - scsi_scan_host(sh); - return 0; - } /* scsi_host_alloc */ + error = scsi_add_host (sh, &ioc->pcidev->dev); + if(error) { + dprintk((KERN_ERR MYNAM + "scsi_add_host failed\n")); + goto mptscsih_probe_failed; + } - } /* for each adapter port */ + scsi_scan_host(sh); + return 0; mptscsih_probe_failed: mptscsih_remove(pdev); return error; + } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -1718,7 +1721,7 @@ * * */ -static void __devexit +static void mptscsih_remove(struct pci_dev *pdev) { MPT_ADAPTER *ioc = pci_get_drvdata(pdev); @@ -1920,7 +1923,7 @@ static struct mpt_pci_driver mptscsih_driver = { .probe = mptscsih_probe, - .remove = __devexit_p(mptscsih_remove), + .remove = mptscsih_remove, .shutdown = mptscsih_shutdown, #ifdef CONFIG_PM .suspend = mptscsih_suspend, @@ -2023,7 +2026,7 @@ const char * mptscsih_info(struct Scsi_Host *SChost) { - MPT_SCSI_HOST *h = NULL; + MPT_SCSI_HOST *h; int size = 0; if (info_kbuf == NULL) @@ -2099,101 +2102,20 @@ return ((info.pos > info.offset) ? info.pos - info.offset : 0); } -struct mptscsih_usrcmd { - ulong target; - ulong lun; - ulong data; - ulong cmd; -}; - -#define UC_GET_SPEED 0x10 - -static void mptscsih_exec_user_cmd(MPT_ADAPTER *ioc, struct mptscsih_usrcmd *uc) +#ifndef MPTSCSIH_DBG_TIMEOUT +static int mptscsih_user_command(MPT_ADAPTER *ioc, char *pbuf, int len) { - CONFIGPARMS cfg; - dma_addr_t cfg_dma_addr = -1; - ConfigPageHeader_t header; - - dprintk(("exec_user_command: ioc %p cmd %ld target=%ld\n", - ioc, uc->cmd, uc->target)); - - switch (uc->cmd) { - case UC_GET_SPEED: - { - SCSIDevicePage0_t *pData = NULL; - - if (ioc->spi_data.sdp0length == 0) - return; - - pData = (SCSIDevicePage0_t *)pci_alloc_consistent(ioc->pcidev, - ioc->spi_data.sdp0length * 4, &cfg_dma_addr); - - if (pData == NULL) - return; - - header.PageVersion = ioc->spi_data.sdp0version; - header.PageLength = ioc->spi_data.sdp0length; - header.PageNumber = 0; - header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; - - cfg.hdr = &header; - cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; - cfg.dir = 0; - cfg.pageAddr = (u32) uc->target; /* bus << 8 | target */ - cfg.physAddr = cfg_dma_addr; - - if (mpt_config(ioc, &cfg) == 0) { - u32 np = le32_to_cpu(pData->NegotiatedParameters); - u32 tmp = np & MPI_SCSIDEVPAGE0_NP_WIDE; - - printk("Target %d: %s;", - (u32) uc->target, - tmp ? "Wide" : "Narrow"); - - tmp = np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK; - if (tmp) { - u32 speed = 0; - printk(" Synchronous"); - tmp = (tmp >> 16); - printk(" (Offset=0x%x", tmp); - tmp = np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK; - tmp = (tmp >> 8); - printk(" Factor=0x%x)", tmp); - if (tmp <= MPT_ULTRA320) - speed=160; - else if (tmp <= MPT_ULTRA160) - speed=80; - else if (tmp <= MPT_ULTRA2) - speed=40; - else if (tmp <= MPT_ULTRA) - speed=20; - else if (tmp <= MPT_FAST) - speed=10; - else if (tmp <= MPT_SCSI) - speed=5; - - if (np & MPI_SCSIDEVPAGE0_NP_WIDE) - speed*=2; - - printk(" %dMB/sec\n", speed); - - } else - printk(" Asynchronous.\n"); - } else { - printk("failed\n" ); - } - - pci_free_consistent(ioc->pcidev, ioc->spi_data.sdp0length * 4, - pData, cfg_dma_addr); - } - break; - } + /* Not yet implemented */ + return len; } - +#else #define is_digit(c) ((c) >= '0' && (c) <= '9') #define digit_to_bin(c) ((c) - '0') #define is_space(c) ((c) == ' ' || (c) == '\t') +#define UC_DBG_TIMEOUT 0x01 +#define UC_DBG_HARDRESET 0x02 + static int skip_spaces(char *ptr, int len) { int cnt, c; @@ -2242,50 +2164,66 @@ static int mptscsih_user_command(MPT_ADAPTER *ioc, char *buffer, int length) { - char *ptr = buffer; - struct mptscsih_usrcmd cmd, *uc = &cmd; - ulong target; - int arg_len; - int len = length; + char *ptr = buffer; + char btmp[24]; /* REMOVE */ + int arg_len; + int len = length; + int cmd; + ulong number = 1; + ulong delta = 10; - uc->target = uc->cmd = uc->lun = uc->data = 0; - if ((len > 0) && (ptr[len -1] == '\n')) --len; - if ((arg_len = is_keyword(ptr, len, "getspeed")) != 0) - uc->cmd = UC_GET_SPEED; - else - arg_len = 0; - - dprintk(("user_command: arg_len=%d, cmd=%ld\n", arg_len, uc->cmd)); + if (len < 22) { + strncpy(btmp, buffer, len); + btmp[len+1]='\0'; + } else { + strncpy(btmp, buffer, 22); + btmp[23]='\0'; + } + printk("user_command: ioc %d, buffer %s, length %d\n", + ioc->id, btmp, length); - if (!arg_len) + if ((arg_len = is_keyword(ptr, len, "timeout")) != 0) + cmd = UC_DBG_TIMEOUT; + else if ((arg_len = is_keyword(ptr, len, "hardreset")) != 0) + cmd = UC_DBG_HARDRESET; + else return -EINVAL; ptr += arg_len; len -= arg_len; - switch(uc->cmd) { - case UC_GET_SPEED: + switch(cmd) { + case UC_DBG_TIMEOUT: SKIP_SPACES(1); - GET_INT_ARG(target); - uc->target = target; + GET_INT_ARG(number); + SKIP_SPACES(1); + GET_INT_ARG(delta); break; } - dprintk(("user_command: target=%ld len=%d\n", uc->target, len)); + printk("user_command: cnt=%ld delta=%ld\n", number, delta); if (len) return -EINVAL; else { - /* process this command ... - */ - mptscsih_exec_user_cmd(ioc, uc); + if (cmd == UC_DBG_HARDRESET) { + ioc->timeout_hard = 1; + } else if (cmd == UC_DBG_TIMEOUT) { + /* process this command ... + */ + ioc->timeout_maxcnt = 0; + ioc->timeout_delta = delta < 2 ? 2 : delta; + ioc->timeout_cnt = 0; + ioc->timeout_maxcnt = number < 8 ? number: 8; + } } /* Not yet implemented */ return length; } +#endif /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** @@ -2303,7 +2241,7 @@ int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int func) { - MPT_ADAPTER *ioc = NULL; + MPT_ADAPTER *ioc; MPT_SCSI_HOST *hd = NULL; int size = 0; @@ -2334,49 +2272,8 @@ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - static int max_qd = 1; #define ADD_INDEX_LOG(req_ent) do { } while(0) -#ifdef DROP_TEST -#define DROP_IOC 1 /* IOC to force failures */ -#define DROP_TARGET 3 /* Target ID to force failures */ -#define DROP_THIS_CMD 10000 /* iteration to drop command */ -static int dropCounter = 0; -static int dropTestOK = 0; /* num did good */ -static int dropTestBad = 0; /* num did bad */ -static int dropTestNum = 0; /* total = good + bad + incomplete */ -static int numTotCmds = 0; -static MPT_FRAME_HDR *dropMfPtr = NULL; -static int numTMrequested = 0; -#endif - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * mptscsih_put_msgframe - Wrapper routine to post message frame to F/W. - * @context: Call back context (ScsiDoneCtx, ScsiScanDvCtx) - * @id: IOC id number - * @mf: Pointer to message frame - * - * Handles the call to mptbase for posting request and queue depth - * tracking. - * - * Returns none. - */ -static inline void -mptscsih_put_msgframe(int context, int id, MPT_FRAME_HDR *mf) -{ - /* Main banana... */ - atomic_inc(&queue_depth); - if (atomic_read(&queue_depth) > max_qd) { - max_qd = atomic_read(&queue_depth); - dprintk((KERN_INFO MYNAM ": Queue depth now %d.\n", max_qd)); - } - - mpt_put_msg_frame(context, id, mf); - - return; -} - /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** * mptscsih_qcmd - Primary Fusion MPT SCSI initiator IO start routine. @@ -2396,7 +2293,7 @@ MPT_FRAME_HDR *mf; SCSIIORequest_t *pScsiReq; VirtDevice *pTarget; - MPT_DONE_Q *buffer = NULL; + MPT_DONE_Q *buffer; unsigned long flags; int target; int lun; @@ -2424,9 +2321,14 @@ if (hd->resetPending) { /* Prevent new commands from being issued - * while reloading the FW. + * while reloading the FW. Reset timer to 60 seconds, + * as the FW can take some time to come ready. + * For New EH, cmds on doneQ posted to FW. */ did_errcode = 1; + mod_timer(&SCpnt->eh_timeout, jiffies + (HZ * 60)); + dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n", + (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt)); goto did_error; } @@ -2481,8 +2383,8 @@ /* Use the above information to set up the message frame */ - pScsiReq->TargetID = target; - pScsiReq->Bus = hd->port; + pScsiReq->TargetID = (u8) target; + pScsiReq->Bus = (u8) SCpnt->device->channel; pScsiReq->ChainOffset = 0; pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST; pScsiReq->CDBLength = SCpnt->cmd_len; @@ -2501,12 +2403,14 @@ /* * Write SCSI CDB into the message - * Should write from cmd_len up to 16, but skip for performance reasons. */ cmd_len = SCpnt->cmd_len; for (ii=0; ii < cmd_len; ii++) pScsiReq->CDB[ii] = SCpnt->cmnd[ii]; + for (ii=cmd_len; ii < 16; ii++) + pScsiReq->CDB[ii] = 0; + /* DataLength */ pScsiReq->DataLength = cpu_to_le32(datalen); @@ -2532,39 +2436,6 @@ hd->ScsiLookup[my_idx] = SCpnt; SCpnt->host_scribble = NULL; -#ifdef DROP_TEST - numTotCmds++; - /* If the IOC number and target match, increment - * counter. If counter matches DROP_THIS, do not - * issue command to FW to force a reset. - * Save the MF pointer so we can free resources - * when task mgmt completes. - */ - if ((hd->ioc->id == DROP_IOC) && (target == DROP_TARGET)) { - dropCounter++; - - if (dropCounter == DROP_THIS_CMD) { - dropCounter = 0; - - /* If global is set, then we are already - * doing something - so keep issuing commands. - */ - if (dropMfPtr == NULL) { - dropTestNum++; - dropMfPtr = mf; - atomic_inc(&queue_depth); - printk(MYIOC_s_INFO_FMT - "Dropped SCSI cmd (%p)\n", - hd->ioc->name, SCpnt); - printk("mf (%p) req (%4x) tot cmds (%d)\n", - mf, my_idx, numTotCmds); - - return 0; - } - } - } -#endif - /* SCSI specific processing */ issueCmd = 1; if (hd->is_spi) { @@ -2617,8 +2488,20 @@ } } +#ifdef MPTSCSIH_DBG_TIMEOUT + if (hd->ioc->timeout_cnt < hd->ioc->timeout_maxcnt) { + foo_to[hd->ioc->timeout_cnt] = SCpnt; + hd->ioc->timeout_cnt++; + //mod_timer(&SCpnt->eh_timeout, jiffies + hd->ioc->timeout_delta); + issueCmd = 0; + printk(MYIOC_s_WARN_FMT + "to pendingQ: (sc=%p, mf=%p, time=%ld)\n", + hd->ioc->name, SCpnt, mf, jiffies); + } +#endif + if (issueCmd) { - mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf); + mpt_put_msg_frame(ScsiDoneCtx, hd->ioc->id, mf); dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n", hd->ioc->name, SCpnt, mf, my_idx)); } else { @@ -2660,6 +2543,8 @@ SCpnt->result = (DID_BUS_BUSY << 16); spin_lock_irqsave(&hd->freedoneQlock, flags); if (!Q_IS_EMPTY(&hd->freeQ)) { + dtmprintk((MYIOC_s_WARN_FMT "SCpnt=%p to doneQ\n", + (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt)); buffer = hd->freeQ.head; Q_DEL_ITEM(buffer); @@ -2692,7 +2577,7 @@ static void mptscsih_freeChainBuffers(MPT_SCSI_HOST *hd, int req_idx) { - MPT_FRAME_HDR *chain = NULL; + MPT_FRAME_HDR *chain; unsigned long flags; int chain_idx; int next; @@ -2755,9 +2640,9 @@ * Returns 0 for SUCCESS or -1 if FAILED. */ static int -mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag) +mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag) { - MPT_ADAPTER *ioc = NULL; + MPT_ADAPTER *ioc; int rc = -1; int doTask = 1; u32 ioc_raw_state; @@ -2770,19 +2655,18 @@ return 0; ioc = hd->ioc; - dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name)); - if (ioc == NULL) { printk(KERN_ERR MYNAM " TMHandler" " NULL ioc!\n"); - return 0; + return FAILED; } + dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name)); // SJR - CHECKME - Can we avoid this here? // (mpt_HardResetHandler has this check...) spin_lock_irqsave(&ioc->diagLock, flags); if ((ioc->diagPending) || (ioc->alt_ioc && ioc->alt_ioc->diagPending)) { spin_unlock_irqrestore(&ioc->diagLock, flags); - return 0; + return FAILED; } spin_unlock_irqrestore(&ioc->diagLock, flags); @@ -2792,6 +2676,37 @@ if (hd->numTMrequests > MPT_HOST_TOO_MANY_TM) doTask = 0; + /* Wait a fixed amount of time for the TM pending flag to be cleared. + * If we time out and not bus reset, then we return a FAILED status to the caller. + * The call to mptscsih_tm_pending_wait() will set the pending flag if we are + * successful. Otherwise, reload the FW. + */ + if (mptscsih_tm_pending_wait(hd) == FAILED) { + if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) { + dtmprintk((KERN_WARNING MYNAM ": %s: TMHandler abort: " + "Timed out waiting for last TM (%d) to complete! \n", + hd->ioc->name, hd->tmPending)); + return FAILED; + } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) { + dtmprintk((KERN_WARNING MYNAM ": %s: TMHandler target reset: " + "Timed out waiting for last TM (%d) to complete! \n", + hd->ioc->name, hd->tmPending)); + return FAILED; + } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) { + dtmprintk((KERN_WARNING MYNAM ": %s: TMHandler bus reset: " + "Timed out waiting for last TM (%d) to complete! \n", + hd->ioc->name, hd->tmPending)); + if (hd->tmPending & (1 << MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)) + return FAILED; + + doTask = 0; + } + } else { + spin_lock_irqsave(&hd->ioc->FreeQlock, flags); + hd->tmPending |= (1 << type); + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + } + /* Is operational? */ ioc_raw_state = mpt_GetIocState(hd->ioc, 0); @@ -2799,7 +2714,7 @@ #ifdef MPT_DEBUG_RESET if ((ioc_raw_state & MPI_IOC_STATE_MASK) != MPI_IOC_STATE_OPERATIONAL) { printk(MYIOC_s_WARN_FMT - "TM Handler: IOC Not operational! state 0x%x Calling HardResetHandler\n", + "TM Handler: IOC Not operational(0x%x)!\n", hd->ioc->name, ioc_raw_state); } #endif @@ -2811,23 +2726,24 @@ */ if (hd->hard_resets < -1) hd->hard_resets++; - rc = mptscsih_IssueTaskMgmt(hd, type, target, lun, ctx2abort, timeout, sleepFlag); + rc = mptscsih_IssueTaskMgmt(hd, type, channel, target, lun, ctx2abort, timeout, sleepFlag); if (rc) { printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name); } else { dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name)); } } -#ifdef DROP_TEST - numTMrequested++; - if (numTMrequested > 5) { - rc = 0; /* set to 1 to force a hard reset */ - numTMrequested = 0; - } + +#ifdef MPTSCSIH_DBG_TIMEOUT + if (hd->ioc->timeout_hard) + rc = 1; #endif - if (rc || ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw)) { - dtmprintk((MYIOC_s_INFO_FMT "Falling through to HardReset! \n", + /* Only fall through to the HRH if this is a bus reset + */ + if ((type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) && (rc || + ioc->reload_fw || (ioc->alt_ioc && ioc->alt_ioc->reload_fw))) { + dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n", hd->ioc->name)); rc = mpt_HardResetHandler(hd->ioc, sleepFlag); } @@ -2857,7 +2773,7 @@ * else other non-zero value returned. */ static int -mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag) +mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout, int sleepFlag) { MPT_FRAME_HDR *mf; SCSITaskMgmt_t *pScsiTm; @@ -2879,7 +2795,7 @@ */ pScsiTm = (SCSITaskMgmt_t *) mf; pScsiTm->TargetID = target; - pScsiTm->Bus = hd->port; + pScsiTm->Bus = channel; pScsiTm->ChainOffset = 0; pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT; @@ -2953,8 +2869,11 @@ return FAILED; } - printk(KERN_WARNING MYNAM ": %s: >> Attempting task abort! (sc=%p, numIOs=%d)\n", - hd->ioc->name, SCpnt, atomic_read(&queue_depth)); + if (hd->resetPending) + return FAILED; + + printk(KERN_WARNING MYNAM ": %s: >> Attempting task abort! (sc=%p)\n", + hd->ioc->name, SCpnt); if (hd->timeouts < -1) hd->timeouts++; @@ -2968,38 +2887,21 @@ search_doneQ_for_cmd(hd, SCpnt); SCpnt->result = DID_RESET << 16; - SCpnt->scsi_done(SCpnt); dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: " "Command not in the active list! (sc=%p)\n", hd->ioc->name, SCpnt)); return SUCCESS; } - /* Wait a fixed amount of time for the TM pending flag to be cleared. - * If we time out, then we return a FAILED status to the caller. This - * call to mptscsih_tm_pending_wait() will set the pending flag if we are - * successful. - */ - spin_unlock_irq(host_lock); - if (mptscsih_tm_pending_wait(hd) == FAILED){ - dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: " - "Timed out waiting for previous TM to complete! " - "(sc = %p)\n", - hd->ioc->name, SCpnt)); - spin_lock_irq(host_lock); - return FAILED; - } - spin_lock_irq(host_lock); - /* If this command is pended, then timeout/hang occurred * during DV. Post command and flush pending Q * and then following up with the reset request. */ if ((mf = mptscsih_search_pendingQ(hd, scpnt_idx)) != NULL) { - mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf); + mpt_put_msg_frame(ScsiDoneCtx, hd->ioc->id, mf); post_pendingQ_commands(hd); dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: " - "Found command in pending queue! (sc=%p)\n", + "Posting pended cmd! (sc=%p)\n", hd->ioc->name, SCpnt)); } @@ -3017,7 +2919,7 @@ spin_unlock_irq(host_lock); if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK, - SCpnt->device->id, SCpnt->device->lun, + SCpnt->device->channel, SCpnt->device->id, SCpnt->device->lun, ctx2abort, (HZ*2) /* 2 second timeout */,CAN_SLEEP) < 0) { @@ -3064,31 +2966,21 @@ return FAILED; } - printk(KERN_WARNING MYNAM ": %s: >> Attempting target reset! (sc=%p, numIOs=%d)\n", - hd->ioc->name, SCpnt, atomic_read(&queue_depth)); + if (hd->resetPending) + return FAILED; - /* Unsupported for SCSI. Suppored for FCP + printk(KERN_WARNING MYNAM ": %s: >> Attempting target reset! (sc=%p)\n", + hd->ioc->name, SCpnt); + + /* Unsupported for SCSI. Supported for FCP */ if (hd->is_spi) return FAILED; - /* Wait a fixed amount of time for the TM pending flag to be cleared. - * If we time out, then we return a FAILED status to the caller. This - * call to mptscsih_tm_pending_wait() will set the pending flag if we are - * successful. - */ spin_unlock_irq(host_lock); - if (mptscsih_tm_pending_wait(hd) == FAILED) { - dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_dev_reset: " - "Timed out waiting for previous TM to complete! " - "(sc = %p)\n", - hd->ioc->name, SCpnt)); - spin_lock_irq(host_lock); - return FAILED; - } - if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, - SCpnt->device->id, 0, 0, (HZ*5) /* 5 second timeout */, CAN_SLEEP) + SCpnt->device->channel, SCpnt->device->id, + 0, 0, (HZ*5) /* 5 second timeout */, CAN_SLEEP) < 0){ /* The TM request failed and the subsequent FW-reload failed! * Fatal error case. @@ -3129,30 +3021,19 @@ return FAILED; } - printk(KERN_WARNING MYNAM ": %s: >> Attempting bus reset! (sc=%p, numIOs=%d)\n", - hd->ioc->name, SCpnt, atomic_read(&queue_depth)); + printk(KERN_WARNING MYNAM ": %s: >> Attempting bus reset! (sc=%p)\n", + hd->ioc->name, SCpnt); if (hd->timeouts < -1) hd->timeouts++; - /* Wait a fixed amount of time for the TM pending flag to be cleared. - * If we time out, then we return a FAILED status to the caller. This - * call to mptscsih_tm_pending_wait() will set the pending flag if we are - * successful. - */ - spin_unlock_irq(host_lock); - if (mptscsih_tm_pending_wait(hd) == FAILED) { - dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_bus_reset: " - "Timed out waiting for previous TM to complete! " - "(sc = %p)\n", - hd->ioc->name, SCpnt)); - spin_lock_irq(host_lock); - return FAILED; - } - /* We are now ready to execute the task management request. */ + spin_unlock_irq(host_lock); +// printk("testing start : mptscsih_schedule_reset\n"); +// mptscsih_schedule_reset(hd); +// printk("testing end: mptscsih_schedule_reset\n"); if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, - 0, 0, 0, (HZ*5) /* 5 second timeout */, CAN_SLEEP) + SCpnt->device->channel, 0, 0, 0, (HZ*5) /* 5 second timeout */, CAN_SLEEP) < 0){ /* The TM request failed and the subsequent FW-reload failed! @@ -3197,8 +3078,6 @@ printk(KERN_WARNING MYNAM ": %s: >> Attempting host reset! (sc=%p)\n", hd->ioc->name, SCpnt); - printk(KERN_WARNING MYNAM ": %s: IOs outstanding = %d\n", - hd->ioc->name, atomic_read(&queue_depth)); /* If our attempts to reset the host failed, then return a failed * status. The host will be taken off line by the SCSI mid-layer. @@ -3274,7 +3153,7 @@ { SCSITaskMgmtReply_t *pScsiTmReply; SCSITaskMgmt_t *pScsiTmReq; - MPT_SCSI_HOST *hd = NULL; + MPT_SCSI_HOST *hd; unsigned long flags; u8 tmType = 0; @@ -3325,10 +3204,7 @@ */ if (tmType == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) hd->abortSCpnt = NULL; -#ifdef DROP_TEST - if (dropMfPtr) - dropTestBad++; -#endif + /* If an internal command is present * or the TM failed - reload the FW. * FC FW may respond FAILED to an ABORT @@ -3349,17 +3225,9 @@ hd->abortSCpnt = NULL; flush_doneQ(hd); -#ifdef DROP_TEST - if (dropMfPtr) - dropTestOK++; -#endif } } -#ifdef DROP_TEST - mptscsih_flush_drop_test(hd); -#endif - hd->tmPtr = NULL; spin_lock_irqsave(&ioc->FreeQlock, flags); hd->tmPending = 0; @@ -3438,15 +3306,14 @@ hd = (MPT_SCSI_HOST *)host->hostdata; - if (hd == NULL) - return ENODEV; + return -ENODEV; if ((vdev = hd->Targets[device->id]) == NULL) { if ((vdev = kmalloc(sizeof(VirtDevice), GFP_ATOMIC)) == NULL) { printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%d) FAILED!\n", - hd->ioc->name, (int)sizeof(VirtDevice)); - return ENOMEM; + hd->ioc->name, (int)sizeof(VirtDevice)); + return -ENOMEM; } else { memset(vdev, 0, sizeof(VirtDevice)); rwlock_init(&vdev->VdevLock); @@ -3476,9 +3343,10 @@ struct Scsi_Host *host = device->host; MPT_SCSI_HOST *hd; VirtDevice *vdev; + int raid_volume=0; hd = (MPT_SCSI_HOST *)host->hostdata; - + if (hd == NULL) return; @@ -3489,8 +3357,8 @@ if ((vdev = hd->Targets[device->id]) != NULL) { vdev->num_luns--; - if (vdev->luns & (1 << device->lun)) - vdev->luns &= ~(1 << device->lun); + if (vdev->luns[0] & (1 << device->lun)) + vdev->luns[0] &= ~(1 << device->lun); /* Free device structure only if number of luns is 0. */ @@ -3498,21 +3366,33 @@ kfree(hd->Targets[device->id]); hd->Targets[device->id] = NULL; - if (hd->is_spi) { - hd->ioc->spi_data.dvStatus[device->id] = MPT_SCSICFG_NEGOTIATE; + if (!hd->is_spi) + return; - if (hd->negoNvram == 0) - hd->ioc->spi_data.dvStatus[device->id] |= MPT_SCSICFG_DV_NOT_DONE; + if((hd->ioc->spi_data.isRaid) && (hd->ioc->spi_data.pIocPg3)) { + int i; + for(i=0;iioc->spi_data.pIocPg3->NumPhysDisks && + raid_volume==0;i++) + + if(device->id == + hd->ioc->spi_data.pIocPg3->PhysDisk[i].PhysDiskNum) { + raid_volume=1; + hd->ioc->spi_data.forceDv |= + MPT_SCSICFG_RELOAD_IOC_PG3; + } + } - /* Don't alter isRaid, not allowed to move - * volumes on a running system. - */ - if (hd->ioc->spi_data.isRaid & (1 << (device->id))) - hd->ioc->spi_data.forceDv |= MPT_SCSICFG_RELOAD_IOC_PG3; + if(!raid_volume){ + hd->ioc->spi_data.dvStatus[device->id] = + MPT_SCSICFG_NEGOTIATE; + + if (hd->negoNvram == 0) + hd->ioc->spi_data.dvStatus[device->id] + |= MPT_SCSICFG_DV_NOT_DONE; } } } - + return; } @@ -3525,205 +3405,76 @@ int mptscsih_slave_configure(Scsi_Device *device) { - struct Scsi_Host *host = device->host; - VirtDevice *vdev; - MPT_SCSI_HOST *hd; - - hd = (MPT_SCSI_HOST *)host->hostdata; - - dsprintk((KERN_INFO "slave_configure: device @ %p, id=%d, LUN=%d, channel=%d\n", - device, device->id, device->lun, device->channel)); - dsprintk((KERN_INFO "sdtr %d wdtr %d ppr %d inq length=%d\n", - device->sdtr, device->wdtr, device->ppr, device->inquiry_len)); - dsprintk(("tagged %d simple %d ordered %d\n", - device->tagged_supported, device->simple_tags, device->ordered_tags)); - - /* set target parameters, queue depths, set dv flags ? */ - if (hd && (hd->Targets != NULL)) { - vdev = hd->Targets[device->id]; - - if (vdev && !(vdev->tflags & MPT_TARGET_FLAGS_CONFIGURED)) { - /* Configure only the first discovered LUN - */ - vdev->raidVolume = 0; - if (hd->is_spi && (hd->ioc->spi_data.isRaid & (1 << (device->id)))) { - vdev->raidVolume = 1; - ddvtprintk((KERN_INFO "RAID Volume @ id %d\n", device->id)); - } - - mptscsih_target_settings(hd, vdev, device); + struct Scsi_Host *sh = device->host; + VirtDevice *pTarget; + MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sh->hostdata; - vdev->tflags |= MPT_TARGET_FLAGS_CONFIGURED; - } + if ((hd == NULL) || (hd->Targets == NULL)) { + return 0; + } - if (vdev) { - /* set the queue depth for all devices - */ - if (!device->tagged_supported || - !(vdev->tflags & MPT_TARGET_FLAGS_Q_YES)) { + dsprintk((MYIOC_s_INFO_FMT + "device @ %p, id=%d, LUN=%d, channel=%d\n", + hd->ioc->name, device, device->id, device->lun, device->channel)); + dsprintk((MYIOC_s_INFO_FMT + "sdtr %d wdtr %d ppr %d inq length=%d\n", + hd->ioc->name, device->sdtr, device->wdtr, + device->ppr, device->inquiry_len)); + + if (device->id > sh->max_id) { + /* error case, should never happen */ + scsi_adjust_queue_depth(device, 0, 1); + goto slave_configure_exit; + } + + pTarget = hd->Targets[device->id]; + + if (pTarget == NULL) { + /* error case - don't know about this device */ + scsi_adjust_queue_depth(device, 0, 1); + goto slave_configure_exit; + } + + mptscsih_initTarget(hd, device->channel, device->id, device->lun, + device->inquiry, device->inquiry_len ); + scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG, + MPT_SCSI_CMD_PER_DEV_HIGH); + if ( hd->is_spi ) { + if (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) { + if (!(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) scsi_adjust_queue_depth(device, 0, 1); - } else if (vdev->type == 0x00 - && (vdev->minSyncFactor <= MPT_ULTRA160 || !hd->is_spi)) { + else if (((pTarget->inq_data[0] & 0x1f) == 0x00) + && (pTarget->minSyncFactor <= MPT_ULTRA160 )) scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG, - MPT_SCSI_CMD_PER_DEV_HIGH); - } else { + MPT_SCSI_CMD_PER_DEV_HIGH); + else scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG, - MPT_SCSI_CMD_PER_DEV_LOW); - } - - vdev->luns |= (1 << device->lun); - vdev->tflags |= MPT_TARGET_FLAGS_CONFIGURED; - } - } - return 0; -} -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* - * Update the target negotiation parameters based on the - * the Inquiry data, adapter capabilities, and NVRAM settings. - * - */ -static void -mptscsih_target_settings(MPT_SCSI_HOST *hd, VirtDevice *target, Scsi_Device *sdev) -{ - ScsiCfgData *pspi_data = &hd->ioc->spi_data; - int id = (int) target->target_id; - int nvram; - u8 width = MPT_NARROW; - u8 factor = MPT_ASYNC; - u8 offset = 0; - u8 nfactor; - u8 noQas = 1; - - ddvtprintk((KERN_INFO "set Target: (id %d) \n", id)); - - if (!hd->is_spi) { - /* FC - only care about QTag support - */ - if (sdev->tagged_supported) - target->tflags |= MPT_TARGET_FLAGS_Q_YES; - return; - } - - /* SCSI - Set flags based on Inquiry data - */ - if (sdev->scsi_level < 2) { - width = 0; - factor = MPT_ULTRA2; - offset = pspi_data->maxSyncOffset; - } else { - width = sdev->wdtr; - if (sdev->sdtr) { - if (sdev->ppr) { - /* U320 requires IU capability */ - if ((sdev->inquiry_len > 56) && (sdev->inquiry[56] & 0x01)) - factor = MPT_ULTRA320; - else - factor = MPT_ULTRA160; - } else - factor = MPT_ULTRA2; - - /* If RAID, never disable QAS - * else if non RAID, do not disable - * QAS if bit 1 is set - * bit 1 QAS support, non-raid only - * bit 0 IU support - */ - if ((target->raidVolume == 1) || - ((sdev->inquiry_len > 56) && (sdev->inquiry[56] & 0x02))) - noQas = 0; - - offset = pspi_data->maxSyncOffset; - + MPT_SCSI_CMD_PER_DEV_LOW); } else { - factor = MPT_ASYNC; - offset = 0; + /* error case - No Inq. Data */ + scsi_adjust_queue_depth(device, 0, 1); } } - /* Update tflags based on NVRAM settings. (SCSI only) - */ - if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) { - nvram = pspi_data->nvram[id]; - nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8; - - if (width) - width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1; - - if (offset > 0) { - /* Ensure factor is set to the - * maximum of: adapter, nvram, inquiry - */ - if (nfactor) { - if (nfactor < pspi_data->minSyncFactor ) - nfactor = pspi_data->minSyncFactor; - - factor = MAX (factor, nfactor); - if (factor == MPT_ASYNC) - offset = 0; - } else { - offset = 0; - factor = MPT_ASYNC; - } - } else - factor = MPT_ASYNC; - } - - /* Make sure data is consistent - */ - if ((!width) && (factor < MPT_ULTRA2)) - factor = MPT_ULTRA2; - - /* Save the data to the target structure. - */ - target->minSyncFactor = factor; - target->maxOffset = offset; - target->maxWidth = width; - if (sdev->tagged_supported) - target->tflags |= MPT_TARGET_FLAGS_Q_YES; - - /* Disable unused features. - */ - target->negoFlags = pspi_data->noQas; - if (!width) - target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE; - - if (!offset) - target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC; + dsprintk((MYIOC_s_INFO_FMT + "Queue depth=%d, tflags=%x\n", + hd->ioc->name, device->queue_depth, pTarget->tflags)); - if (noQas) - target->negoFlags |= MPT_TARGET_NO_NEGO_QAS; + dsprintk((MYIOC_s_INFO_FMT + "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n", + hd->ioc->name, pTarget->negoFlags, pTarget->maxOffset, pTarget->minSyncFactor)); - /* GEM, processor WORKAROUND - */ - target->type = sdev->inquiry[0] & 0x1F; - if ((target->type == 0x03) || (target->type > 0x08)){ - target->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC); - pspi_data->dvStatus[id] |= MPT_SCSICFG_BLK_NEGO; - } +slave_configure_exit: - /* Disable QAS if mixed configuration case - */ - if ((noQas) && (!pspi_data->noQas) && (target->type == 0x00)){ - VirtDevice *vdev; - int ii; + dsprintk((MYIOC_s_INFO_FMT + "tagged %d, simple %d, ordered %d\n", + hd->ioc->name,device->tagged_supported, device->simple_tags, + device->ordered_tags)); - ddvtprintk((KERN_INFO "Disabling QAS!\n")); - pspi_data->noQas = MPT_TARGET_NO_NEGO_QAS; - for (ii = 0; ii < id; ii++) { - vdev = hd->Targets[id]; - if (vdev != NULL) - vdev->negoFlags |= MPT_TARGET_NO_NEGO_QAS; - } - } - - ddvtprintk((KERN_INFO "Final settings id %d: dvstatus 0x%x\n", sdev->id, pspi_data->dvStatus[id])); - ddvtprintk(("wide %d, factor 0x%x offset 0x%x neg flags 0x%x flags 0x%x\n", - width, factor, offset, target->negoFlags, target->tflags)); - - return; + return 0; } + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * Private routines... @@ -3789,11 +3540,10 @@ thisIo.SCSIStatus = pScsiReply->SCSIStatus; thisIo.DoDisplay = 1; if (hd->is_multipath) - sprintf(devFoo, "%d:%d:%d \"%s\"", + sprintf(devFoo, "%d:%d:%d", hd->ioc->id, pReq->TargetID, - pReq->LUN[1], - target->dev_vol_name); + pReq->LUN[1]); else sprintf(devFoo, "%d:%d:%d", hd->ioc->id, sc->device->id, sc->device->lun); thisIo.DevIDStr = devFoo; @@ -3842,7 +3592,7 @@ unsigned long flags; MPT_DONE_Q *buffer; MPT_FRAME_HDR *mf = NULL; - MPT_FRAME_HDR *cmdMfPtr = NULL; + MPT_FRAME_HDR *cmdMfPtr; ddvtprintk((MYIOC_s_INFO_FMT ": search_pendingQ ...", hd->ioc->name)); cmdMfPtr = MPT_INDEX_2_MFPTR(hd->ioc, scpnt_idx); @@ -3911,7 +3661,7 @@ continue; } - mptscsih_put_msgframe(ScsiDoneCtx, hd->ioc->id, mf); + mpt_put_msg_frame(ScsiDoneCtx, hd->ioc->id, mf); #if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY) { @@ -3930,12 +3680,13 @@ static int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) { - MPT_SCSI_HOST *hd = NULL; + MPT_SCSI_HOST *hd; unsigned long flags; dtmprintk((KERN_WARNING MYNAM ": IOC %s_reset routed to SCSI host driver!\n", - reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")); + reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( + reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post"))); /* If a FW reload request arrives after base installed but * before all scsi hosts have been attached, then an alt_ioc @@ -3946,9 +3697,8 @@ else hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; - if (reset_phase == MPT_IOC_PRE_RESET) { - dtmprintk((MYIOC_s_WARN_FMT "Do Pre-Diag Reset handling\n", - ioc->name)); + if (reset_phase == MPT_IOC_SETUP_RESET) { + dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name)); /* Clean Up: * 1. Set Hard Reset Pending Flag @@ -3956,6 +3706,11 @@ */ hd->resetPending = 1; + mptscsih_reset_timeouts (hd); + + } else if (reset_phase == MPT_IOC_PRE_RESET) { + dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name)); + /* 2. Flush running commands * Clean drop test code - if compiled * Clean ScsiLookup (and associated memory) @@ -3964,9 +3719,6 @@ /* 2a. Drop Test Command. */ -#ifdef DROP_TEST - mptscsih_flush_drop_test(hd); -#endif /* 2b. Reply to OS all known outstanding I/O commands. */ @@ -3979,7 +3731,6 @@ if (hd->cmdPtr) { del_timer(&hd->timer); mpt_free_msg_frame(ScsiScanDvCtx, ioc->id, hd->cmdPtr); - atomic_dec(&queue_depth); } /* 2d. If a task management has not completed, @@ -3990,12 +3741,14 @@ mpt_free_msg_frame(ScsiTaskCtx, ioc->id, hd->tmPtr); } - dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset handling complete.\n", - ioc->name)); +#ifdef MPTSCSIH_DBG_TIMEOUT + ioc->timeout_hard = 0; +#endif + + dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name)); } else { - dtmprintk((MYIOC_s_WARN_FMT "Do Post-Diag Reset handling\n", - ioc->name)); + dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name)); /* Once a FW reload begins, all new OS commands are * redirected to the doneQ w/ a reset status. @@ -4052,10 +3805,6 @@ */ flush_doneQ(hd); - dtmprintk((MYIOC_s_WARN_FMT "Post-Reset handling complete.\n", - ioc->name)); - - /* 8. Set flag to force DV and re-read IOC Page 3 */ if (hd->is_spi) { @@ -4063,6 +3812,8 @@ ddvtprintk(("Set reload IOC Pg3 Flag\n")); } + dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name)); + } return 1; /* currently means nothing really */ @@ -4571,6 +4322,268 @@ } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mptscsih_initTarget - Target, LUN alloc/free functionality. + * @hd: Pointer to MPT_SCSI_HOST structure + * @bus_id: Bus number (?) + * @target_id: SCSI target id + * @lun: SCSI LUN id + * @data: Pointer to data + * @dlen: Number of INQUIRY bytes + * + * NOTE: It's only SAFE to call this routine if data points to + * sane & valid STANDARD INQUIRY data! + * + * Allocate and initialize memory for this target. + * Save inquiry data. + * + */ +static void +mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char *data, int dlen) +{ + int indexed_lun, lun_index; + VirtDevice *vdev; + char data_56; + + dprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n", + hd->ioc->name, bus_id, target_id, lun, hd)); + + /* Is LUN supported? If so, upper 3 bits will be 0 + * in first byte of inquiry data. + */ + if (data[0] & 0xe0) + return; + + vdev = hd->Targets[target_id]; + + lun_index = (lun >> 5); /* 32 luns per lun_index */ + indexed_lun = (lun % 32); + vdev->luns[lun_index] |= (1 << indexed_lun); + + vdev->raidVolume = 0; + if (hd->is_spi) { + if (hd->ioc->spi_data.isRaid & (1 << target_id)) { + vdev->raidVolume = 1; + ddvtprintk((KERN_INFO "RAID Volume @ id %d\n", target_id)); + } + } + + if (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) { + if ( dlen > 8 ) { + memcpy (vdev->inq_data, data, 8); + } else { + memcpy (vdev->inq_data, data, dlen); + } + vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY; + + /* If LUN 0, tape and have not done DV, set the DV flag. + */ + if (hd->is_spi && (lun == 0) && (data[0] == SCSI_TYPE_TAPE)) { + ScsiCfgData *pSpi = &hd->ioc->spi_data; + if (pSpi->dvStatus[target_id] & MPT_SCSICFG_DV_NOT_DONE) + pSpi->dvStatus[target_id] |= MPT_SCSICFG_NEED_DV; + } + + if ( (data[0] == SCSI_TYPE_PROC) && + !(vdev->tflags & MPT_TARGET_FLAGS_SAF_TE_ISSUED )) { + if ( dlen > 49 ) { + vdev->tflags |= MPT_TARGET_FLAGS_VALID_INQUIRY; + if ( data[44] == 'S' && + data[45] == 'A' && + data[46] == 'F' && + data[47] == '-' && + data[48] == 'T' && + data[49] == 'E' ) { + vdev->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED; + mptscsih_writeIOCPage4(hd, target_id, bus_id); + } + } else { + /* Treat all Processors as SAF-TE if + * command line option is set */ + if ( hd->ioc->spi_data.Saf_Te ) { + vdev->tflags |= MPT_TARGET_FLAGS_SAF_TE_ISSUED; + mptscsih_writeIOCPage4(hd, target_id, bus_id); + } + } + } + + data_56 = 0; + if (dlen > 56) { + if ( (!(vdev->tflags & MPT_TARGET_FLAGS_VALID_56))) { + /* Update the target capabilities + */ + data_56 = data[56]; + vdev->tflags |= MPT_TARGET_FLAGS_VALID_56; + } + } + mptscsih_setTargetNegoParms(hd, vdev, data_56); + } + + dprintk((KERN_INFO " target = %p\n", vdev)); + return; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * Update the target negotiation parameters based on the + * the Inquiry data, adapter capabilities, and NVRAM settings. + * + */ +void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56) +{ + ScsiCfgData *pspi_data = &hd->ioc->spi_data; + int id = (int) target->target_id; + int nvram; + char canQ = 0; + VirtDevice *vdev; + int ii; + u8 width = MPT_NARROW; + u8 factor = MPT_ASYNC; + u8 offset = 0; + u8 version, nfactor; + u8 noQas = 1; + + if (!hd->is_spi) { + if (target->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) { + if (target->inq_data[7] & 0x02) + target->tflags |= MPT_TARGET_FLAGS_Q_YES; + } + return; + } + + target->negoFlags = pspi_data->noQas; + + /* noQas == 0 => device supports QAS. Need byte 56 of Inq to determine + * support. If available, default QAS to off and allow enabling. + * If not available, default QAS to on, turn off for non-disks. + */ + + /* Set flags based on Inquiry data + */ + if (target->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) { + version = target->inq_data[2] & 0x07; + if (version < 2) { + width = 0; + factor = MPT_ULTRA2; + offset = pspi_data->maxSyncOffset; + } else { + if (target->inq_data[7] & 0x20) { + width = 1; + } + + if (target->inq_data[7] & 0x10) { + /* bits 2 & 3 show DT support + */ + if ((byte56 & 0x04) == 0) + factor = MPT_ULTRA2; + else if ((byte56 & 0x03) == 0) + factor = MPT_ULTRA160; + else + factor = MPT_ULTRA320; + offset = pspi_data->maxSyncOffset; + + /* If RAID, never disable QAS + * else if non RAID, do not disable + * QAS if bit 1 is set + * bit 1 QAS support, non-raid only + * bit 0 IU support + */ + if ((target->raidVolume == 1) || ((byte56 & 0x02) != 0)) + noQas = 0; + } else { + factor = MPT_ASYNC; + offset = 0; + } + } + + if (target->inq_data[7] & 0x02) { + canQ = 1; + } + + /* Update tflags based on NVRAM settings. (SCSI only) + */ + if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) { + nvram = pspi_data->nvram[id]; + nfactor = (nvram & MPT_NVRAM_SYNC_MASK) >> 8; + + if (width) + width = nvram & MPT_NVRAM_WIDE_DISABLE ? 0 : 1; + + if (offset > 0) { + /* Ensure factor is set to the + * maximum of: adapter, nvram, inquiry + */ + if (nfactor) { + if (nfactor < pspi_data->minSyncFactor ) + nfactor = pspi_data->minSyncFactor; + + factor = MAX (factor, nfactor); + if (factor == MPT_ASYNC) + offset = 0; + } else { + offset = 0; + factor = MPT_ASYNC; + } + } else { + factor = MPT_ASYNC; + } + } + + /* Make sure data is consistent + */ + if ((!width) && (factor < MPT_ULTRA2)) { + factor = MPT_ULTRA2; + } + + /* Save the data to the target structure. + */ + target->minSyncFactor = factor; + target->maxOffset = offset; + target->maxWidth = width; + if (canQ) { + target->tflags |= MPT_TARGET_FLAGS_Q_YES; + } + + target->tflags |= MPT_TARGET_FLAGS_VALID_NEGO; + + /* Disable unused features. + */ + if (!width) + target->negoFlags |= MPT_TARGET_NO_NEGO_WIDE; + + if (!offset) + target->negoFlags |= MPT_TARGET_NO_NEGO_SYNC; + + /* GEM, processor WORKAROUND + */ + if (((target->inq_data[0] & 0x1F) == 0x03) + || ((target->inq_data[0] & 0x1F) > 0x08)) { + target->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC); + pspi_data->dvStatus[id] |= MPT_SCSICFG_BLK_NEGO; + } else { + if (noQas && (pspi_data->noQas == 0)) { + pspi_data->noQas |= MPT_TARGET_NO_NEGO_QAS; + target->negoFlags |= MPT_TARGET_NO_NEGO_QAS; + + /* Disable QAS in a mixed configuration case + */ + +// ddvtprintk((KERN_INFO "Disabling QAS!\n")); + for (ii = 0; ii < id; ii++) { + if ( (vdev = hd->Targets[ii]) ) { + vdev->negoFlags |= MPT_TARGET_NO_NEGO_QAS; + } + } + } + } + } + + return; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* If DV disabled (negoNvram set to USE_NVARM) or if not LUN 0, return. * Else set the NEED_DV flag after Read Capacity Issued (disks) * or Mode Sense (cdroms). @@ -4581,7 +4594,7 @@ static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq) { u8 cmd; - + if ((pReq->LUN[1] != 0) || (hd->negoNvram != 0)) return; @@ -4609,16 +4622,14 @@ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* - * If no Target (old) or Target unconfigured (new) and bus reset on 1st I/O, - * set the flag to prevent any future negotiations to this device. + * If no Target, bus reset on 1st I/O. Set the flag to + * prevent any future negotiations to this device. */ static void mptscsih_no_negotiate(MPT_SCSI_HOST *hd, int target_id) { - if (hd->Targets) { - VirtDevice *vdev = hd->Targets[target_id]; - if ((vdev == NULL) || !(vdev->tflags & MPT_TARGET_FLAGS_CONFIGURED)) - hd->ioc->spi_data.dvStatus[target_id] |= MPT_SCSICFG_BLK_NEGO; - } + + if ((hd->Targets) && (hd->Targets[target_id] == NULL)) + hd->ioc->spi_data.dvStatus[target_id] |= MPT_SCSICFG_BLK_NEGO; return; } @@ -4691,9 +4702,9 @@ mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags) { MPT_ADAPTER *ioc = hd->ioc; - Config_t *pReq = NULL; - SCSIDevicePage1_t *pData = NULL; - VirtDevice *pTarget = NULL; + Config_t *pReq; + SCSIDevicePage1_t *pData; + VirtDevice *pTarget; MPT_FRAME_HDR *mf; dma_addr_t dataDma; u16 req_idx; @@ -4784,13 +4795,11 @@ /* If id is not a raid volume, get the updated * transmission settings from the target structure. */ - if (hd->Targets && (pTarget = hd->Targets[id]) && !pTarget->raidVolume - && (pTarget->tflags & MPT_TARGET_FLAGS_CONFIGURED)) { + if (hd->Targets && (pTarget = hd->Targets[id]) && !pTarget->raidVolume) { width = pTarget->maxWidth; factor = pTarget->minSyncFactor; offset = pTarget->maxOffset; negoFlags = pTarget->negoFlags; - pTarget = NULL; } if (flags & MPT_SCSICFG_BLK_NEGO) @@ -4832,9 +4841,8 @@ pReq->Reserved = 0; pReq->ChainOffset = 0; pReq->Function = MPI_FUNCTION_CONFIG; - pReq->Reserved1[0] = 0; - pReq->Reserved1[1] = 0; - pReq->Reserved1[2] = 0; + pReq->ExtPageLength = 0; + pReq->ExtPageType = 0; pReq->MsgFlags = 0; for (ii=0; ii < 8; ii++) { pReq->Reserved2[ii] = 0; @@ -4861,14 +4869,93 @@ pData->Reserved = 0; pData->Configuration = cpu_to_le32(configuration); - dsprintk((MYIOC_s_INFO_FMT + dprintk((MYIOC_s_INFO_FMT "write SDP1: id %d pgaddr 0x%x req 0x%x config 0x%x\n", ioc->name, id, (id | (bus<<8)), requested, configuration)); - mptscsih_put_msgframe(ScsiDoneCtx, ioc->id, mf); + mpt_put_msg_frame(ScsiDoneCtx, ioc->id, mf); + } + + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* mptscsih_writeIOCPage4 - write IOC Page 4 + * @hd: Pointer to a SCSI Host Structure + * @target_id: write IOC Page4 for this ID & Bus + * + * Return: -EAGAIN if unable to obtain a Message Frame + * or 0 if success. + * + * Remark: We do not wait for a return, write pages sequentially. + */ +static int +mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus) +{ + MPT_ADAPTER *ioc = hd->ioc; + Config_t *pReq; + IOCPage4_t *IOCPage4Ptr; + MPT_FRAME_HDR *mf; + dma_addr_t dataDma; + u16 req_idx; + u32 frameOffset; + u32 flagsLength; + int ii; + + /* Get a MF for this command. + */ + if ((mf = mpt_get_msg_frame(ScsiDoneCtx, ioc->id)) == NULL) { + dprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n", + ioc->name)); + return -EAGAIN; + } + + ddvprintk((MYIOC_s_INFO_FMT "writeIOCPage4 (mf=%p, id=%d)\n", + ioc->name, mf, target_id)); + + /* Set the request and the data pointers. + * Place data at end of MF. + */ + pReq = (Config_t *)mf; + + req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); + frameOffset = ioc->req_sz - sizeof(IOCPage4_t); + + /* Complete the request frame (same for all requests). + */ + pReq->Action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; + pReq->Reserved = 0; + pReq->ChainOffset = 0; + pReq->Function = MPI_FUNCTION_CONFIG; + pReq->ExtPageLength = 0; + pReq->ExtPageType = 0; + pReq->MsgFlags = 0; + for (ii=0; ii < 8; ii++) { + pReq->Reserved2[ii] = 0; } + IOCPage4Ptr = ioc->spi_data.pIocPg4; + dataDma = ioc->spi_data.IocPg4_dma; + ii = IOCPage4Ptr->ActiveSEP++; + IOCPage4Ptr->SEP[ii].SEPTargetID = target_id; + IOCPage4Ptr->SEP[ii].SEPBus = bus; + pReq->Header = IOCPage4Ptr->Header; + pReq->PageAddress = cpu_to_le32(target_id | (bus << 8 )); + + /* Add a SGE to the config request. + */ + flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE | + (IOCPage4Ptr->Header.PageLength + ii) * 4; + + mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma); + + dsprintk((MYIOC_s_INFO_FMT + "writeIOCPage4: pgaddr 0x%x\n", + ioc->name, (target_id | (bus<<8)))); + + mpt_put_msg_frame(ScsiDoneCtx, ioc->id, mf); + return 0; } @@ -4982,8 +5069,6 @@ ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n", hd->ioc->name, mf, mr, req_idx)); - atomic_dec(&queue_depth); - hd->pLocal = &hd->localReply; hd->pLocal->scsiStatus = 0; @@ -5042,7 +5127,7 @@ u8 *sense_data; int sz; - /* save sense data in global & target structure + /* save sense data in global structure */ completionCode = MPT_SCANDV_SENSE; hd->pLocal->scsiStatus = pReply->SCSIStatus; @@ -5215,7 +5300,7 @@ hd->cmdPtr = mf; add_timer(&hd->timer); - mptscsih_put_msgframe(ScsiScanDvCtx, hd->ioc->id, mf); + mpt_put_msg_frame(ScsiScanDvCtx, hd->ioc->id, mf); wait_event(scandv_waitq, scandv_wait_done); if ((hd->pLocal == NULL) || (hd->pLocal->completion != MPT_SCANDV_GOOD)) @@ -5452,7 +5537,7 @@ hd->cmdPtr = mf; add_timer(&hd->timer); - mptscsih_put_msgframe(ScsiScanDvCtx, hd->ioc->id, mf); + mpt_put_msg_frame(ScsiScanDvCtx, hd->ioc->id, mf); wait_event(scandv_waitq, scandv_wait_done); if (hd->pLocal) { @@ -5490,7 +5575,7 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum) { MPT_ADAPTER *ioc= hd->ioc; - VirtDevice *pTarget = NULL; + VirtDevice *pTarget; SCSIDevicePage1_t *pcfg1Data = NULL; INTERNAL_CMD iocmd; CONFIGPARMS cfg; @@ -5498,7 +5583,8 @@ ConfigPageHeader_t header1; int bus = 0; int id = 0; - int lun = 0; + int lun; + int indexed_lun, lun_index; int hostId = ioc->pfacts[portnum].PortSCSIID; int max_id; int requested, configuration, data; @@ -5593,7 +5679,9 @@ for (lun=0; lun <= MPT_LAST_LUN; lun++) { /* If LUN present, issue the command */ - if (pTarget->luns & (1<> 5); /* 32 luns per lun_index */ + indexed_lun = (lun % 32); + if (pTarget->luns[lun_index] & (1<Targets == NULL) @@ -5843,15 +5931,15 @@ * Return: None. */ static int -mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int id) +mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) { MPT_ADAPTER *ioc = hd->ioc; - VirtDevice *pTarget = NULL; - SCSIDevicePage1_t *pcfg1Data = NULL; - SCSIDevicePage0_t *pcfg0Data = NULL; - u8 *pbuf1 = NULL; - u8 *pbuf2 = NULL; - u8 *pDvBuf = NULL; + VirtDevice *pTarget; + SCSIDevicePage1_t *pcfg1Data; + SCSIDevicePage0_t *pcfg0Data; + u8 *pbuf1; + u8 *pbuf2; + u8 *pDvBuf; dma_addr_t dvbuf_dma = -1; dma_addr_t buf1_dma = -1; dma_addr_t buf2_dma = -1; @@ -5871,6 +5959,7 @@ int patt; int repeat; int retcode = 0; + int nfactor = MPT_ULTRA320; char firstPass = 1; char doFallback = 0; char readPage0; @@ -5883,14 +5972,17 @@ if (ioc->spi_data.sdp0length == 0) return 0; - if (id == ioc->pfacts[portnum].PortSCSIID) + /* If multiple buses are used, require that the initiator + * id be the same on all buses. + */ + if (id == ioc->pfacts[0].PortSCSIID) return 0; lun = 0; - bus = 0; + bus = (u8) bus_number; ddvtprintk((MYIOC_s_NOTE_FMT - "DV started: numIOs %d bus=%d, id %d dv @ %p\n", - ioc->name, atomic_read(&queue_depth), bus, id, &dv)); + "DV started: bus=%d, id %d dv @ %p\n", + ioc->name, bus, id, &dv)); /* Prep DV structure */ @@ -5916,11 +6008,11 @@ iocmd.rsvd = iocmd.rsvd2 = 0; pTarget = hd->Targets[id]; - if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_CONFIGURED)) { + if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY)) { /* Another GEM workaround. Check peripheral device type, * if PROCESSOR, quit DV. */ - if ((pTarget->type == 0x03) || (pTarget->type > 0x08)) { + if (((pTarget->inq_data[0] & 0x1F) == 0x03) || ((pTarget->inq_data[0] & 0x1F) > 0x08)) { pTarget->negoFlags |= (MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC); return 0; } @@ -5992,24 +6084,34 @@ /* Skip this ID? Set cfg.hdr to force config page write */ - if ((ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID) && - (!(ioc->spi_data.nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE))) { + { + ScsiCfgData *pspi_data = &hd->ioc->spi_data; + if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) { + /* Set the factor from nvram */ + nfactor = (pspi_data->nvram[id] & MPT_NVRAM_SYNC_MASK) >> 8; + if (nfactor < pspi_data->minSyncFactor ) + nfactor = pspi_data->minSyncFactor; - ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n", - ioc->name, bus, id, lun)); + if (!(pspi_data->nvram[id] & MPT_NVRAM_ID_SCAN_ENABLE) || + (pspi_data->PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_OFF_DV) ) { - dv.cmd = MPT_SET_MAX; - mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data); - cfg.hdr = &header1; - /* Double writes to SDP1 can cause problems, - * skip save of the final negotiated settings to - * SCSI device page 1. - */ - cfg.physAddr = cfg1_dma_addr; - cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; - cfg.dir = 1; - mpt_config(hd->ioc, &cfg); - goto target_done; + ddvprintk((MYIOC_s_NOTE_FMT "DV Skipped: bus, id, lun (%d, %d, %d)\n", + ioc->name, bus, id, lun)); + + dv.cmd = MPT_SET_MAX; + mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data); + cfg.hdr = &header1; + + /* Save the final negotiated settings to + * SCSI device page 1. + */ + cfg.physAddr = cfg1_dma_addr; + cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; + cfg.dir = 1; + mpt_config(hd->ioc, &cfg); + goto target_done; + } + } } /* Finish iocmd inititialization - hidden or visible disk? */ @@ -6059,7 +6161,7 @@ sz = SCSI_STD_INQUIRY_BYTES; rc = MPT_SCANDV_GOOD; while (1) { - ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test.\n", ioc->name)); + ddvprintk((MYIOC_s_NOTE_FMT "DV: Start Basic test on id=%d\n", ioc->name, id)); retcode = 0; dv.cmd = MPT_SET_MIN; mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data); @@ -6131,6 +6233,14 @@ } } + /* Reset the size for disks + */ + inq0 = (*pbuf1) & 0x1F; + if ((inq0 == 0) && pTarget && !pTarget->raidVolume) { + sz = 0x40; + iocmd.size = sz; + } + /* Another GEM workaround. Check peripheral device type, * if PROCESSOR, quit DV. */ @@ -6140,6 +6250,28 @@ if (mptscsih_do_cmd(hd, &iocmd) < 0) goto target_done; + if (sz == 0x40) { + if ((pTarget->maxWidth == 1) && (pTarget->maxOffset) && (nfactor < 0x0A) + && (pTarget->minSyncFactor > 0x09)) { + if ((pbuf1[56] & 0x04) == 0) + ; + else if ((pbuf1[56] & 0x01) == 1) { + pTarget->minSyncFactor = + nfactor > MPT_ULTRA320 ? nfactor : MPT_ULTRA320; + } else { + pTarget->minSyncFactor = + nfactor > MPT_ULTRA160 ? nfactor : MPT_ULTRA160; + } + + dv.max.factor = pTarget->minSyncFactor; + + if ((pbuf1[56] & 0x02) == 0) { + pTarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS; + hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS; + } + } + } + if (doFallback) dv.cmd = MPT_FALLBACK; else @@ -6223,7 +6355,7 @@ firstPass = 0; } } - ddvprintk((MYIOC_s_NOTE_FMT "DV: Basic test completed OK.\n", ioc->name)); + ddvprintk((MYIOC_s_NOTE_FMT "DV: Basic test on id=%d completed OK.\n", ioc->name, id)); inq0 = (*pbuf1) & 0x1F; /* Continue only for disks @@ -6231,6 +6363,9 @@ if (inq0 != 0) goto target_done; + if ( ioc->spi_data.PortFlags == MPI_SCSIPORTPAGE2_PORT_FLAGS_BASIC_DV_ONLY ) + goto target_done; + /* Start the Enhanced Test. * 0) issue TUR to clear out check conditions * 1) read capacity of echo (regular) buffer @@ -6671,8 +6806,8 @@ if (pDvBuf) pci_free_consistent(ioc->pcidev, dv_alloc, pDvBuf, dvbuf_dma); - ddvtprintk((MYIOC_s_INFO_FMT "DV Done. IOs outstanding = %d\n", - ioc->name, atomic_read(&queue_depth))); + ddvtprintk((MYIOC_s_INFO_FMT "DV Done.\n", + ioc->name)); return retcode; } @@ -6687,9 +6822,9 @@ static void mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage) { - VirtDevice *pTarget = NULL; - SCSIDevicePage0_t *pPage0 = NULL; - SCSIDevicePage1_t *pPage1 = NULL; + VirtDevice *pTarget; + SCSIDevicePage0_t *pPage0; + SCSIDevicePage1_t *pPage1; int val = 0, data, configuration; u8 width = 0; u8 offset = 0; @@ -6841,7 +6976,6 @@ factor = MPT_ULTRA; width = MPT_WIDE; } else if ((factor == MPT_ULTRA) && width) { - factor = MPT_ULTRA; width = MPT_NARROW; } else if (factor < MPT_FAST) { factor = MPT_FAST; @@ -7072,9 +7206,9 @@ /* Commandline Parsing routines and defines. * * insmod format: - * insmod mptscsih mptscsih="width:1 dv:n factor:0x09" + * insmod mptscsih mptscsih="width:1 dv:n factor:0x09 saf-te:1" * boot format: - * mptscsih=width:1,dv:n,factor:0x8 + * mptscsih=width:1,dv:n,factor:0x8,saf-te:1 * */ #ifdef MODULE @@ -7087,11 +7221,13 @@ "dv:" "width:" "factor:" - ; /* DONNOT REMOVE THIS ';' */ + "saf-te:" + ; /* DO NOT REMOVE THIS ';' */ #define OPT_DV 1 #define OPT_MAX_WIDTH 2 #define OPT_MIN_SYNC_FACTOR 3 +#define OPT_SAF_TE 4 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static int @@ -7146,6 +7282,10 @@ case OPT_MIN_SYNC_FACTOR: driver_setup.min_sync_fac = val; + break; + + case OPT_SAF_TE: + driver_setup.saf_te = val; break; default: diff -Nru a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h --- a/drivers/message/fusion/mptscsih.h Sun Mar 14 14:20:08 2004 +++ b/drivers/message/fusion/mptscsih.h Sun Mar 14 14:20:08 2004 @@ -15,7 +15,7 @@ * * (see also mptbase.c) * - * Copyright (c) 1999-2003 LSI Logic Corporation + * Copyright (c) 1999-2004 LSI Logic Corporation * Originally By: Steven J. Ralston * (mailto:netscape.net) * (mailto:mpt_linux_developer@lsil.com) @@ -70,11 +70,7 @@ * Try to keep these at 2^N-1 */ #define MPT_FC_CAN_QUEUE 127 -#if defined MPT_SCSI_USE_NEW_EH - #define MPT_SCSI_CAN_QUEUE 127 -#else - #define MPT_SCSI_CAN_QUEUE 63 -#endif +#define MPT_SCSI_CAN_QUEUE 127 #define MPT_SCSI_CMD_PER_DEV_HIGH 31 #define MPT_SCSI_CMD_PER_DEV_LOW 7 @@ -98,7 +94,7 @@ #define MPT_SCSI_SG_DEPTH 40 #endif -/* To disable domain validation, comment the +/* To disable domain validation, uncomment the * following line. No effect for FC devices. * For SCSI devices, driver will negotiate to * NVRAM settings (if available) or to maximum adapter @@ -114,12 +110,14 @@ #define MPTSCSIH_DOMAIN_VALIDATION 1 #define MPTSCSIH_MAX_WIDTH 1 #define MPTSCSIH_MIN_SYNC 0x08 +#define MPTSCSIH_SAF_TE 0 struct mptscsih_driver_setup { u8 dv; u8 max_width; u8 min_sync_fac; + u8 saf_te; }; @@ -128,6 +126,7 @@ MPTSCSIH_DOMAIN_VALIDATION, \ MPTSCSIH_MAX_WIDTH, \ MPTSCSIH_MIN_SYNC, \ + MPTSCSIH_SAF_TE, \ } diff -Nru a/drivers/message/fusion/scsi3.h b/drivers/message/fusion/scsi3.h --- a/drivers/message/fusion/scsi3.h Sun Mar 14 14:20:07 2004 +++ b/drivers/message/fusion/scsi3.h Sun Mar 14 14:20:07 2004 @@ -4,7 +4,7 @@ * (Ultimately) SCSI-3 definitions; for now, inheriting * SCSI-2 definitions. * - * Copyright (c) 1996-2003 Steven J. Ralston + * Copyright (c) 1996-2004 Steven J. Ralston * Written By: Steven J. Ralston (19960517) * (mailto:sjralston1@netscape.net) * (mailto:mpt_linux_developer@lsil.com) diff -Nru a/drivers/message/i2o/i2o_core.c b/drivers/message/i2o/i2o_core.c --- a/drivers/message/i2o/i2o_core.c Sun Mar 14 14:20:07 2004 +++ b/drivers/message/i2o/i2o_core.c Sun Mar 14 14:20:07 2004 @@ -1179,7 +1179,7 @@ * the processor */ - pci_dma_sync_single(c->pdev, c->page_frame_map, MSG_FRAME_SIZE, PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(c->pdev, c->page_frame_map, MSG_FRAME_SIZE, PCI_DMA_FROMDEVICE); /* * Despatch it diff -Nru a/drivers/mtd/devices/blkmtd.c b/drivers/mtd/devices/blkmtd.c --- a/drivers/mtd/devices/blkmtd.c Sun Mar 14 14:20:06 2004 +++ b/drivers/mtd/devices/blkmtd.c Sun Mar 14 14:20:06 2004 @@ -664,12 +664,12 @@ } memset(dev, 0, sizeof(struct blkmtd_dev)); + dev->blkdev = bdev; atomic_set(&(dev->blkdev->bd_inode->i_mapping->truncate_count), 0); if(!readonly) { init_MUTEX(&dev->wrbuf_mutex); } - dev->blkdev = bdev; dev->mtd_info.size = dev->blkdev->bd_inode->i_size & PAGE_MASK; /* Setup the MTD structure */ diff -Nru a/drivers/net/3c501.c b/drivers/net/3c501.c --- a/drivers/net/3c501.c Sun Mar 14 14:20:05 2004 +++ b/drivers/net/3c501.c Sun Mar 14 14:20:05 2004 @@ -306,7 +306,7 @@ printk(KERN_DEBUG "%s", version); memset(dev->priv, 0, sizeof(struct net_local)); - lp=dev->priv; + lp = netdev_priv(dev); spin_lock_init(&lp->lock); /* @@ -341,7 +341,7 @@ { int retval; int ioaddr = dev->base_addr; - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned long flags; if (el_debug > 2) @@ -371,7 +371,7 @@ static void el_timeout(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; if (el_debug) @@ -411,7 +411,7 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; unsigned long flags; @@ -524,7 +524,7 @@ int axsr; /* Aux. status reg. */ ioaddr = dev->base_addr; - lp = (struct net_local *)dev->priv; + lp = netdev_priv(dev); spin_lock(&lp->lock); @@ -698,7 +698,7 @@ static void el_receive(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int pkt_len; struct sk_buff *skb; @@ -764,7 +764,7 @@ static void el_reset(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; if (el_debug> 2) @@ -828,7 +828,7 @@ static struct net_device_stats *el1_get_stats(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); return &lp->stats; } diff -Nru a/drivers/net/3c503.c b/drivers/net/3c503.c --- a/drivers/net/3c503.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/3c503.c Sun Mar 14 14:20:08 2004 @@ -337,6 +337,9 @@ dev->open = &el2_open; dev->stop = &el2_close; dev->ethtool_ops = &netdev_ethtool_ops; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif if (dev->mem_start) printk("%s: %s - %dkB RAM, 8kB shared mem window at %#6lx-%#6lx.\n", diff -Nru a/drivers/net/3c507.c b/drivers/net/3c507.c --- a/drivers/net/3c507.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/3c507.c Sun Mar 14 14:20:08 2004 @@ -441,7 +441,7 @@ if (net_debug) printk(version); - lp = dev->priv; + lp = netdev_priv(dev); memset(lp, 0, sizeof(*lp)); spin_lock_init(&lp->lock); @@ -471,7 +471,7 @@ static void el16_tx_timeout (struct net_device *dev) { - struct net_local *lp = (struct net_local *) dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; unsigned long shmem = dev->mem_start; @@ -501,7 +501,7 @@ static int el16_send_packet (struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = (struct net_local *) dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; unsigned long flags; short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; @@ -546,7 +546,7 @@ } ioaddr = dev->base_addr; - lp = (struct net_local *)dev->priv; + lp = netdev_priv(dev); shmem = dev->mem_start; spin_lock(&lp->lock); @@ -660,7 +660,7 @@ closed. */ static struct net_device_stats *el16_get_stats(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); /* ToDo: decide if there are any useful statistics from the SCB. */ @@ -670,7 +670,7 @@ /* Initialize the Rx-block list. */ static void init_rx_bufs(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned long write_ptr; unsigned short SCB_base = SCB_BASE; @@ -713,7 +713,7 @@ static void init_82586_mem(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); short ioaddr = dev->base_addr; unsigned long shmem = dev->mem_start; @@ -771,7 +771,7 @@ static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); short ioaddr = dev->base_addr; ushort tx_block = lp->tx_head; unsigned long write_ptr = dev->mem_start + tx_block; @@ -820,7 +820,7 @@ static void el16_rx(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned long shmem = dev->mem_start; ushort rx_head = lp->rx_head; ushort rx_tail = lp->rx_tail; diff -Nru a/drivers/net/3c509.c b/drivers/net/3c509.c --- a/drivers/net/3c509.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/3c509.c Sun Mar 14 14:20:06 2004 @@ -304,7 +304,7 @@ static int __init el3_common_init(struct net_device *dev) { - struct el3_private *lp = dev->priv; + struct el3_private *lp = netdev_priv(dev); short i; int err; @@ -355,7 +355,7 @@ static void el3_common_remove (struct net_device *dev) { - struct el3_private *lp = dev->priv; + struct el3_private *lp = netdev_priv(dev); (void) lp; /* Keep gcc quiet... */ #ifdef CONFIG_PM @@ -575,7 +575,7 @@ dev->base_addr = ioaddr; dev->irq = irq; dev->if_port = if_port; - lp = dev->priv; + lp = netdev_priv(dev); #if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800) lp->dev = &idev->dev; #endif @@ -671,7 +671,7 @@ dev->base_addr = ioaddr; dev->irq = irq; dev->if_port = if_port; - lp = dev->priv; + lp = netdev_priv(dev); lp->dev = device; lp->type = EL3_MCA; device->driver_data = dev; @@ -732,7 +732,7 @@ dev->base_addr = ioaddr; dev->irq = irq; dev->if_port = if_port; - lp = dev->priv; + lp = netdev_priv(dev); lp->dev = device; lp->type = EL3_EISA; eisa_set_drvdata (edev, dev); @@ -829,7 +829,7 @@ static void el3_tx_timeout (struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); int ioaddr = dev->base_addr; /* Transmitter timeout, serious problems. */ @@ -849,7 +849,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); int ioaddr = dev->base_addr; unsigned long flags; @@ -943,7 +943,7 @@ return IRQ_NONE; } - lp = (struct el3_private *)dev->priv; + lp = netdev_priv(dev); spin_lock(&lp->lock); ioaddr = dev->base_addr; @@ -975,7 +975,7 @@ outw(AckIntr | RxEarly, ioaddr + EL3_CMD); } if (status & TxComplete) { /* Really Tx error. */ - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); short tx_status; int i = 4; @@ -1022,7 +1022,7 @@ static struct net_device_stats * el3_get_stats(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); unsigned long flags; /* @@ -1043,7 +1043,7 @@ */ static void update_stats(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); int ioaddr = dev->base_addr; if (el3_debug > 5) @@ -1073,7 +1073,7 @@ static int el3_rx(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); int ioaddr = dev->base_addr; short rx_status; @@ -1145,7 +1145,7 @@ set_multicast_list(struct net_device *dev) { unsigned long flags; - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); int ioaddr = dev->base_addr; if (el3_debug > 1) { @@ -1172,7 +1172,7 @@ el3_close(struct net_device *dev) { int ioaddr = dev->base_addr; - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); if (el3_debug > 2) printk("%s: Shutting down ethercard.\n", dev->name); @@ -1317,7 +1317,7 @@ netdev_ethtool_ioctl (struct net_device *dev, void *useraddr) { u32 ethcmd; - struct el3_private *lp = dev->priv; + struct el3_private *lp = netdev_priv(dev); /* dev_ioctl() in ../../net/core/dev.c has already checked capable(CAP_NET_ADMIN), so don't bother with that here. */ @@ -1558,7 +1558,7 @@ return -EINVAL; dev = (struct net_device *)pdev->data; - lp = (struct el3_private *)dev->priv; + lp = netdev_priv(dev); ioaddr = dev->base_addr; spin_lock_irqsave(&lp->lock, flags); @@ -1585,7 +1585,7 @@ return -EINVAL; dev = (struct net_device *)pdev->data; - lp = (struct el3_private *)dev->priv; + lp = netdev_priv(dev); ioaddr = dev->base_addr; spin_lock_irqsave(&lp->lock, flags); diff -Nru a/drivers/net/3c527.c b/drivers/net/3c527.c --- a/drivers/net/3c527.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/3c527.c Sun Mar 14 14:20:07 2004 @@ -226,7 +226,7 @@ static void cleanup_card(struct net_device *dev) { - struct mc32_local *lp=dev->priv; + struct mc32_local *lp = netdev_priv(dev); unsigned slot = lp->slot; mca_mark_as_unused(slot); mca_set_adapter_name(slot, NULL); @@ -307,7 +307,7 @@ int i, err; u8 POS; u32 base; - struct mc32_local *lp = dev->priv; + struct mc32_local *lp = netdev_priv(dev); static u16 mca_io_bases[]={ 0x7280,0x7290, 0x7680,0x7690, @@ -573,7 +573,7 @@ static int mc32_command_nowait(struct net_device *dev, u16 cmd, void *data, int len) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int ret = -1; @@ -619,7 +619,7 @@ static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int ret = 0; @@ -671,7 +671,7 @@ static void mc32_start_transceiver(struct net_device *dev) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; /* Ignore RX overflow on device closure */ @@ -706,7 +706,7 @@ static void mc32_halt_transceiver(struct net_device *dev) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; mc32_ready_poll(dev); @@ -743,7 +743,7 @@ static int mc32_load_rx_ring(struct net_device *dev) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); int i; u16 rx_base; volatile struct skb_header *p; @@ -792,7 +792,7 @@ static void mc32_flush_rx_ring(struct net_device *dev) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); int i; for(i=0; i < RX_RING_LEN; i++) @@ -824,7 +824,7 @@ static void mc32_load_tx_ring(struct net_device *dev) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); volatile struct skb_header *p; int i; u16 tx_base; @@ -861,7 +861,7 @@ static void mc32_flush_tx_ring(struct net_device *dev) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); int i; for (i=0; i < TX_RING_LEN; i++) @@ -899,7 +899,7 @@ static int mc32_open(struct net_device *dev) { int ioaddr = dev->base_addr; - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); u8 one=1; u8 regs; u16 descnumbuffs[2] = {TX_RING_LEN, RX_RING_LEN}; @@ -1022,7 +1022,7 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); u32 head = atomic_read(&lp->tx_ring_head); volatile struct skb_header *p, *np; @@ -1092,7 +1092,7 @@ static void mc32_update_stats(struct net_device *dev) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); volatile struct mc32_stats *st = lp->stats; u32 rx_errors=0; @@ -1143,7 +1143,7 @@ static void mc32_rx_ring(struct net_device *dev) { - struct mc32_local *lp=dev->priv; + struct mc32_local *lp = netdev_priv(dev); volatile struct skb_header *p; u16 rx_ring_tail; u16 rx_old_tail; @@ -1236,7 +1236,7 @@ static void mc32_tx_ring(struct net_device *dev) { - struct mc32_local *lp=(struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); volatile struct skb_header *np; /* @@ -1333,7 +1333,7 @@ } ioaddr = dev->base_addr; - lp = (struct mc32_local *)dev->priv; + lp = netdev_priv(dev); /* See whats cooking */ @@ -1450,7 +1450,7 @@ static int mc32_close(struct net_device *dev) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; u8 regs; @@ -1499,7 +1499,7 @@ static struct net_device_stats *mc32_get_stats(struct net_device *dev) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); mc32_update_stats(dev); return &lp->net_stats; @@ -1531,7 +1531,7 @@ static void do_mc32_set_multicast_list(struct net_device *dev, int retry) { - struct mc32_local *lp = (struct mc32_local *)dev->priv; + struct mc32_local *lp = netdev_priv(dev); u16 filt = (1<<2); /* Save Bad Packets, for stats purposes */ if (dev->flags&IFF_PROMISC) diff -Nru a/drivers/net/3c59x.c b/drivers/net/3c59x.c --- a/drivers/net/3c59x.c Sun Mar 14 14:20:05 2004 +++ b/drivers/net/3c59x.c Sun Mar 14 14:20:05 2004 @@ -927,6 +927,18 @@ static int vortex_cards_found; +#ifdef CONFIG_NET_POLL_CONTROLLER +static void poll_vortex(struct net_device *dev) +{ + struct vortex_private *vp = (struct vortex_private *)dev->priv; + unsigned long flags; + local_save_flags(flags); + local_irq_disable(); + (vp->full_bus_master_rx ? boomerang_interrupt:vortex_interrupt)(dev->irq,dev,NULL); + local_irq_restore(flags); +} +#endif + #ifdef CONFIG_PM static int vortex_suspend (struct pci_dev *pdev, u32 state) @@ -1013,7 +1025,7 @@ BUG(); } - vp = dev->priv; + vp = netdev_priv(dev); ioaddr = dev->base_addr; unregister_netdev (dev); @@ -1115,7 +1127,7 @@ } SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, gendev); - vp = dev->priv; + vp = netdev_priv(dev); option = global_options; @@ -1463,6 +1475,9 @@ dev->set_multicast_list = set_rx_mode; dev->tx_timeout = vortex_tx_timeout; dev->watchdog_timeo = (watchdog * HZ) / 1000; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = poll_vortex; +#endif if (pdev && vp->enable_wol) { vp->pm_state_valid = 1; pci_save_state(VORTEX_PCI(vp), vp->power_state); @@ -1516,7 +1531,7 @@ vortex_up(struct net_device *dev) { long ioaddr = dev->base_addr; - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); unsigned int config; int i; @@ -1714,7 +1729,7 @@ static int vortex_open(struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); int i; int retval; @@ -1772,7 +1787,7 @@ vortex_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr = dev->base_addr; int next_tick = 60*HZ; int ok = 0; @@ -1898,7 +1913,7 @@ static void vortex_tx_timeout(struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr = dev->base_addr; printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n", @@ -1968,7 +1983,7 @@ static void vortex_error(struct net_device *dev, int status) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr = dev->base_addr; int do_tx_reset = 0, reset_mask = 0; unsigned char tx_status = 0; @@ -2070,7 +2085,7 @@ static int vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr = dev->base_addr; /* Put out the doubleword header... */ @@ -2125,7 +2140,7 @@ static int boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr = dev->base_addr; /* Calculate the next Tx descriptor entry. */ int entry = vp->cur_tx % TX_RING_SIZE; @@ -2225,7 +2240,7 @@ vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr; int status; int work_done = max_interrupt_work; @@ -2330,7 +2345,7 @@ boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr; int status; int work_done = max_interrupt_work; @@ -2455,7 +2470,7 @@ static int vortex_rx(struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr = dev->base_addr; int i; short rx_status; @@ -2525,7 +2540,7 @@ static int boomerang_rx(struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); int entry = vp->cur_rx % RX_RING_SIZE; long ioaddr = dev->base_addr; int rx_status; @@ -2562,11 +2577,12 @@ if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != 0) { skb->dev = dev; skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - pci_dma_sync_single(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); /* 'skb_put()' points to the start of sk_buff data area. */ memcpy(skb_put(skb, pkt_len), vp->rx_skbuff[entry]->tail, pkt_len); + pci_dma_sync_single_for_device(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE); vp->rx_copy++; } else { /* Pass up the skbuff already on the Rx ring. */ @@ -2627,7 +2643,7 @@ rx_oom_timer(unsigned long arg) { struct net_device *dev = (struct net_device *)arg; - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); spin_lock_irq(&vp->lock); if ((vp->cur_rx - vp->dirty_rx) == RX_RING_SIZE) /* This test is redundant, but makes me feel good */ @@ -2642,7 +2658,7 @@ static void vortex_down(struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr = dev->base_addr; netif_stop_queue (dev); @@ -2678,7 +2694,7 @@ static int vortex_close(struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr = dev->base_addr; int i; @@ -2740,7 +2756,7 @@ dump_tx_ring(struct net_device *dev) { if (vortex_debug > 0) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr = dev->base_addr; if (vp->full_bus_master_tx) { @@ -2773,7 +2789,7 @@ static struct net_device_stats *vortex_get_stats(struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); unsigned long flags; if (netif_device_present(dev)) { /* AKPM: Used to be netif_running */ @@ -2793,7 +2809,7 @@ */ static void update_stats(long ioaddr, struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); int old_window = inw(ioaddr + EL3_CMD); if (old_window == 0xffff) /* Chip suspended or ejected. */ @@ -2834,7 +2850,7 @@ static void vortex_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct vortex_private *vp = dev->priv; + struct vortex_private *vp = netdev_priv(dev); strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); @@ -2855,7 +2871,7 @@ static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr = dev->base_addr; struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; int phy = vp->phys[0] & 0x1f; @@ -2942,7 +2958,7 @@ static int mdio_read(struct net_device *dev, int phy_id, int location) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); int i; long ioaddr = dev->base_addr; int read_cmd = (0xf6 << 10) | (phy_id << 5) | location; @@ -2976,7 +2992,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int value) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr = dev->base_addr; int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value; long mdio_addr = ioaddr + Wn4_PhysicalMgmt; @@ -3010,7 +3026,7 @@ /* Set Wake-On-LAN mode and put the board into D3 (power-down) state. */ static void acpi_set_WOL(struct net_device *dev) { - struct vortex_private *vp = (struct vortex_private *)dev->priv; + struct vortex_private *vp = netdev_priv(dev); long ioaddr = dev->base_addr; /* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */ @@ -3036,7 +3052,7 @@ BUG(); } - vp = dev->priv; + vp = netdev_priv(dev); /* AKPM: FIXME: we should have * if (vp->cb_fn_base) iounmap(vp->cb_fn_base); diff -Nru a/drivers/net/7990.c b/drivers/net/7990.c --- a/drivers/net/7990.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/7990.c Sun Mar 14 14:20:08 2004 @@ -99,7 +99,7 @@ /* Set up the Lance Rx and Tx rings and the init block */ static void lance_init_ring (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; volatile struct lance_init_block *aib; /* for LANCE_ADDR computations */ int leptr; @@ -216,7 +216,7 @@ static int lance_reset (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); int status; DECLARE_LL; @@ -236,7 +236,7 @@ static int lance_rx (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; volatile struct lance_rx_desc *rd; unsigned char bits; @@ -316,7 +316,7 @@ static int lance_tx (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; volatile struct lance_tx_desc *td; int i, j; @@ -401,7 +401,7 @@ lance_interrupt (int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_id; - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); int csr0; DECLARE_LL; @@ -457,7 +457,7 @@ int lance_open (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); int res; DECLARE_LL; @@ -474,7 +474,7 @@ int lance_close (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); DECLARE_LL; netif_stop_queue (dev); @@ -499,7 +499,7 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; int entry, skblen, len; static int outs; @@ -556,7 +556,7 @@ struct net_device_stats *lance_get_stats (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); return &lp->stats; } @@ -564,7 +564,7 @@ /* taken from the depca driver via a2065.c */ static void lance_load_multicast (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; volatile u16 *mcast_table = (u16 *)&ib->filter; struct dev_mc_list *dmi=dev->mc_list; @@ -601,7 +601,7 @@ void lance_set_multicast (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; int stopped; DECLARE_LL; diff -Nru a/drivers/net/8139too.c b/drivers/net/8139too.c --- a/drivers/net/8139too.c Sun Mar 14 14:20:05 2004 +++ b/drivers/net/8139too.c Sun Mar 14 14:20:05 2004 @@ -968,12 +968,11 @@ if (i < 0) return i; + assert (dev != NULL); tp = dev->priv; + assert (tp != NULL); ioaddr = tp->mmio_addr; - assert (ioaddr != NULL); - assert (dev != NULL); - assert (tp != NULL); addr_len = read_eeprom (ioaddr, 0, 8) == 0x8129 ? 8 : 6; for (i = 0; i < 3; i++) diff -Nru a/drivers/net/82596.c b/drivers/net/82596.c --- a/drivers/net/82596.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/82596.c Sun Mar 14 14:20:08 2004 @@ -458,7 +458,7 @@ static void i596_display_data(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = netdev_priv(dev); struct i596_cmd *cmd; struct i596_rfd *rfd; struct i596_rbd *rbd; @@ -528,7 +528,7 @@ static inline void init_rx_bufs(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *)dev->priv; + struct i596_private *lp = netdev_priv(dev); int i; struct i596_rfd *rfd; struct i596_rbd *rbd; @@ -579,7 +579,7 @@ static inline void remove_rx_bufs(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *)dev->priv; + struct i596_private *lp = netdev_priv(dev); struct i596_rbd *rbd; int i; @@ -593,7 +593,7 @@ static void rebuild_rx_bufs(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = netdev_priv(dev); int i; /* Ensure rx frame/buffer descriptors are tidy */ @@ -612,7 +612,7 @@ static int init_i596_mem(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = netdev_priv(dev); #if !defined(ENABLE_MVME16x_NET) && !defined(ENABLE_BVME6000_NET) short ioaddr = dev->base_addr; #endif @@ -765,7 +765,7 @@ static inline int i596_rx(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *)dev->priv; + struct i596_private *lp = netdev_priv(dev); struct i596_rfd *rfd; struct i596_rbd *rbd; int frames = 0; @@ -960,7 +960,7 @@ static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = netdev_priv(dev); int ioaddr = dev->base_addr; unsigned long flags; @@ -1030,7 +1030,7 @@ static void i596_tx_timeout (struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = netdev_priv(dev); int ioaddr = dev->base_addr; /* Transmitter timeout, serious problems. */ @@ -1059,7 +1059,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = netdev_priv(dev); struct tx_cmd *tx_cmd; struct i596_tbd *tbd; short length = skb->len; @@ -1245,7 +1245,7 @@ dev->priv = (void *)(dev->mem_start); - lp = (struct i596_private *) dev->priv; + lp = netdev_priv(dev); DEB(DEB_INIT,printk(KERN_DEBUG "%s: lp at 0x%08lx (%d bytes), lp->scb at 0x%08lx\n", dev->name, (unsigned long)lp, sizeof(struct i596_private), (unsigned long)&lp->scb)); @@ -1305,7 +1305,7 @@ } ioaddr = dev->base_addr; - lp = (struct i596_private *) dev->priv; + lp = netdev_priv(dev); spin_lock (&lp->lock); @@ -1448,7 +1448,7 @@ static int i596_close(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = netdev_priv(dev); unsigned long flags; netif_stop_queue(dev); @@ -1495,7 +1495,7 @@ static struct net_device_stats * i596_get_stats(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = netdev_priv(dev); return &lp->stats; } @@ -1506,7 +1506,7 @@ static void set_multicast_list(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = netdev_priv(dev); int config = 0, cnt; DEB(DEB_MULTI,printk(KERN_DEBUG "%s: set multicast list, %d entries, promisc %s, allmulti %s\n", diff -Nru a/drivers/net/8390.c b/drivers/net/8390.c --- a/drivers/net/8390.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/8390.c Sun Mar 14 14:20:06 2004 @@ -516,6 +516,15 @@ return IRQ_RETVAL(nr_serviced > 0); } +#ifdef CONFIG_NET_POLL_CONTROLLER +void ei_poll(struct net_device *dev) +{ + disable_irq(dev->irq); + ei_interrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif + /** * ei_tx_err - handle transmitter error * @dev: network device which threw the exception @@ -1124,6 +1133,9 @@ EXPORT_SYMBOL(ei_open); EXPORT_SYMBOL(ei_close); EXPORT_SYMBOL(ei_interrupt); +#ifdef CONFIG_NET_POLL_CONTROLLER +EXPORT_SYMBOL(ei_poll); +#endif EXPORT_SYMBOL(ei_tx_timeout); EXPORT_SYMBOL(NS8390_init); EXPORT_SYMBOL(__alloc_ei_netdev); diff -Nru a/drivers/net/8390.h b/drivers/net/8390.h --- a/drivers/net/8390.h Sun Mar 14 14:20:07 2004 +++ b/drivers/net/8390.h Sun Mar 14 14:20:07 2004 @@ -39,6 +39,10 @@ #define ei_debug 1 #endif +#ifdef CONFIG_NET_POLL_CONTROLLER +extern void ei_poll(struct net_device *dev); +#endif + extern void NS8390_init(struct net_device *dev, int startp); extern int ei_open(struct net_device *dev); extern int ei_close(struct net_device *dev); diff -Nru a/drivers/net/Kconfig b/drivers/net/Kconfig --- a/drivers/net/Kconfig Sun Mar 14 14:20:08 2004 +++ b/drivers/net/Kconfig Sun Mar 14 14:20:08 2004 @@ -2495,6 +2495,13 @@ To compile this driver as a module, choose M here: the module will be called shaper. If unsure, say N. +config NETCONSOLE + tristate "Network console logging support (EXPERIMENTAL)" + depends on NETDEVICES && EXPERIMENTAL + ---help--- + If you want to log kernel messages over the network, enable this. + See Documentation/networking/netconsole.txt for details. + source "drivers/net/wan/Kconfig" source "drivers/net/pcmcia/Kconfig" diff -Nru a/drivers/net/Makefile b/drivers/net/Makefile --- a/drivers/net/Makefile Sun Mar 14 14:20:06 2004 +++ b/drivers/net/Makefile Sun Mar 14 14:20:06 2004 @@ -188,3 +188,4 @@ obj-$(CONFIG_HAMRADIO) += hamradio/ obj-$(CONFIG_IRDA) += irda/ +obj-$(CONFIG_NETCONSOLE) += netconsole.o diff -Nru a/drivers/net/a2065.c b/drivers/net/a2065.c --- a/drivers/net/a2065.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/a2065.c Sun Mar 14 14:20:07 2004 @@ -164,7 +164,7 @@ /* Setup the Lance Rx and Tx rings */ static void lance_init_ring (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; volatile struct lance_init_block *aib; /* for LANCE_ADDR computations */ int leptr; @@ -265,7 +265,7 @@ static int lance_rx (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; volatile struct lance_regs *ll = lp->ll; volatile struct lance_rx_desc *rd; @@ -342,7 +342,7 @@ static int lance_tx (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; volatile struct lance_regs *ll = lp->ll; volatile struct lance_tx_desc *td; @@ -433,7 +433,7 @@ dev = (struct net_device *) dev_id; - lp = (struct lance_private *) dev->priv; + lp = netdev_priv(dev); ll = lp->ll; ll->rap = LE_CSR0; /* LANCE Controller Status */ @@ -481,7 +481,7 @@ static int lance_open (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; int ret; @@ -506,7 +506,7 @@ static int lance_close (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; netif_stop_queue(dev); @@ -522,7 +522,7 @@ static inline int lance_reset (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; int status; @@ -545,7 +545,7 @@ static void lance_tx_timeout(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; printk(KERN_ERR "%s: transmit timed out, status %04x, reset\n", @@ -556,7 +556,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; volatile struct lance_init_block *ib = lp->init_block; int entry, skblen, len; @@ -624,7 +624,7 @@ static struct net_device_stats *lance_get_stats (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); return &lp->stats; } @@ -632,7 +632,7 @@ /* taken from the depca driver */ static void lance_load_multicast (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; volatile u16 *mcast_table = (u16 *)&ib->filter; struct dev_mc_list *dmi=dev->mc_list; @@ -668,7 +668,7 @@ static void lance_set_multicast (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; volatile struct lance_regs *ll = lp->ll; @@ -748,7 +748,7 @@ } SET_MODULE_OWNER(dev); - priv = dev->priv; + priv = netdev_priv(dev); r1->name = dev->name; r2->name = dev->name; diff -Nru a/drivers/net/ac3200.c b/drivers/net/ac3200.c --- a/drivers/net/ac3200.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/ac3200.c Sun Mar 14 14:20:07 2004 @@ -276,6 +276,9 @@ dev->open = &ac_open; dev->stop = &ac_close_card; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; out1: diff -Nru a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c --- a/drivers/net/amd8111e.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/amd8111e.c Sun Mar 14 14:20:07 2004 @@ -174,7 +174,7 @@ */ static int amd8111e_mdio_read(struct net_device * dev, int phy_id, int reg_num) { - struct amd8111e_priv* lp = dev->priv; + struct amd8111e_priv* lp = netdev_priv(dev); unsigned int reg_val; amd8111e_read_phy(lp,phy_id,reg_num,®_val); @@ -187,7 +187,7 @@ */ static void amd8111e_mdio_write(struct net_device * dev, int phy_id, int reg_num, int val) { - struct amd8111e_priv* lp = dev->priv; + struct amd8111e_priv* lp = netdev_priv(dev); amd8111e_write_phy(lp, phy_id, reg_num, val); } @@ -197,7 +197,7 @@ */ static void amd8111e_set_ext_phy(struct net_device *dev) { - struct amd8111e_priv *lp = (struct amd8111e_priv *)dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); u32 bmcr,advert,tmp; /* Determine mii register values to set the speed */ @@ -239,7 +239,7 @@ */ static int amd8111e_free_skbs(struct net_device *dev) { - struct amd8111e_priv *lp = (struct amd8111e_priv *)dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); struct sk_buff* rx_skbuff; int i; @@ -272,7 +272,7 @@ */ static inline void amd8111e_set_rx_buff_len(struct net_device* dev) { - struct amd8111e_priv* lp = dev->priv; + struct amd8111e_priv* lp = netdev_priv(dev); unsigned int mtu = dev->mtu; if (mtu > ETH_DATA_LEN){ @@ -290,7 +290,7 @@ */ static int amd8111e_init_ring(struct net_device *dev) { - struct amd8111e_priv *lp = (struct amd8111e_priv *)dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); int i; lp->rx_idx = lp->tx_idx = 0; @@ -371,7 +371,7 @@ unsigned int timeout; unsigned int event_count; - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); void* mmio = lp->mmio; struct amd8111e_coalesce_conf * coal_conf = &lp->coal_conf; @@ -429,7 +429,7 @@ */ static int amd8111e_restart(struct net_device *dev) { - struct amd8111e_priv *lp = (struct amd8111e_priv* )dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); void * mmio = lp->mmio; int i,reg_val; @@ -663,7 +663,7 @@ */ static int amd8111e_tx(struct net_device *dev) { - struct amd8111e_priv* lp = dev->priv; + struct amd8111e_priv* lp = netdev_priv(dev); int tx_index = lp->tx_complete_idx & TX_RING_DR_MOD_MASK; int status; /* Complete all the transmit packet */ @@ -705,7 +705,7 @@ */ static int amd8111e_rx(struct net_device *dev) { - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); struct sk_buff *skb,*new_skb; int rx_index = lp->rx_idx & RX_RING_DR_MOD_MASK; int min_pkt_len, status; @@ -809,7 +809,7 @@ */ static int amd8111e_link_change(struct net_device* dev) { - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); int status0,speed; /* read the link change */ @@ -871,7 +871,7 @@ */ static struct net_device_stats *amd8111e_get_stats(struct net_device * dev) { - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); void * mmio = lp->mmio; unsigned long flags; /* struct net_device_stats *prev_stats = &lp->prev_stats; */ @@ -966,7 +966,7 @@ */ static int amd8111e_calc_coalesce(struct net_device *dev) { - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); struct amd8111e_coalesce_conf * coal_conf = &lp->coal_conf; int tx_pkt_rate; int rx_pkt_rate; @@ -1102,7 +1102,7 @@ { struct net_device * dev = (struct net_device *) dev_id; - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); void * mmio = lp->mmio; unsigned int intr0; unsigned int handled = 1; @@ -1153,12 +1153,23 @@ return IRQ_RETVAL(handled); } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void amd8111e_poll(struct net_device *dev) +{ + unsigned long flags; + local_save_flags(flags); + local_irq_disable(); + amd8111e_interrupt(0, dev, NULL); + local_irq_restore(flags); +} +#endif + /* This function closes the network interface and updates the statistics so that most recent statistics will be available after the interface is down. */ static int amd8111e_close(struct net_device * dev) { - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); netif_stop_queue(dev); spin_lock_irq(&lp->lock); @@ -1185,7 +1196,7 @@ */ static int amd8111e_open(struct net_device * dev ) { - struct amd8111e_priv *lp = (struct amd8111e_priv *)dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); if(dev->irq ==0 || request_irq(dev->irq, amd8111e_interrupt, SA_SHIRQ, dev->name, dev)) @@ -1231,7 +1242,7 @@ static int amd8111e_start_xmit(struct sk_buff *skb, struct net_device * dev) { - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); int tx_index; unsigned long flags; @@ -1338,7 +1349,7 @@ static void amd8111e_set_multicast_list(struct net_device *dev) { struct dev_mc_list* mc_ptr; - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); u32 mc_filter[2] ; int i,bit_num; if(dev->flags & IFF_PROMISC){ @@ -1388,7 +1399,7 @@ static int amd8111e_ethtool_ioctl(struct net_device* dev, void* useraddr) { - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); struct pci_dev *pci_dev = lp->pci_dev; u32 ethcmd; @@ -1510,7 +1521,7 @@ static int amd8111e_ioctl(struct net_device * dev , struct ifreq *ifr, int cmd) { struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data; - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); int err; u32 mii_regval; @@ -1554,7 +1565,7 @@ */ int amd8111e_change_mtu(struct net_device *dev, int new_mtu) { - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); int err; if ((new_mtu < AMD8111E_MIN_MTU) || (new_mtu > AMD8111E_MAX_MTU)) @@ -1584,7 +1595,7 @@ #if AMD8111E_VLAN_TAG_USED static void amd8111e_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) { - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); spin_lock_irq(&lp->lock); lp->vlgrp = grp; spin_unlock_irq(&lp->lock); @@ -1592,7 +1603,7 @@ static void amd8111e_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) { - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); spin_lock_irq(&lp->lock); if (lp->vlgrp) lp->vlgrp->vlan_devices[vid] = NULL; @@ -1623,7 +1634,7 @@ static void amd8111e_tx_timeout(struct net_device *dev) { - struct amd8111e_priv* lp = dev->priv; + struct amd8111e_priv* lp = netdev_priv(dev); int err; printk(KERN_ERR "%s: transmit timed out, resetting\n", @@ -1637,7 +1648,7 @@ static int amd8111e_suspend(struct pci_dev *pci_dev, u32 state) { struct net_device *dev = pci_get_drvdata(pci_dev); - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); if (!netif_running(dev)) return 0; @@ -1680,7 +1691,7 @@ static int amd8111e_resume(struct pci_dev *pci_dev) { struct net_device *dev = pci_get_drvdata(pci_dev); - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); if (!netif_running(dev)) return 0; @@ -1719,7 +1730,7 @@ } static void amd8111e_config_ipg(struct net_device* dev) { - struct amd8111e_priv *lp = dev->priv; + struct amd8111e_priv *lp = netdev_priv(dev); struct ipg_info* ipg_data = &lp->ipg_data; void * mmio = lp->mmio; unsigned int prev_col_cnt = ipg_data->col_cnt; @@ -1841,7 +1852,7 @@ dev->vlan_rx_kill_vid = amd8111e_vlan_rx_kill_vid; #endif - lp = dev->priv; + lp = netdev_priv(dev); lp->pci_dev = pdev; lp->amd8111e_net_dev = dev; lp->pm_cap = pm_cap; @@ -1884,6 +1895,9 @@ dev->irq =pdev->irq; dev->tx_timeout = amd8111e_tx_timeout; dev->watchdog_timeo = AMD8111E_TX_TIMEOUT; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = amd8111e_poll; +#endif #if AMD8111E_VLAN_TAG_USED dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; diff -Nru a/drivers/net/apne.c b/drivers/net/apne.c --- a/drivers/net/apne.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/apne.c Sun Mar 14 14:20:08 2004 @@ -333,6 +333,9 @@ ei_status.get_8390_hdr = &apne_get_8390_hdr; dev->open = &apne_open; dev->stop = &apne_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); pcmcia_ack_int(pcmcia_get_intreq()); /* ack PCMCIA int req */ diff -Nru a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c --- a/drivers/net/appletalk/cops.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/appletalk/cops.c Sun Mar 14 14:20:07 2004 @@ -333,7 +333,7 @@ dev->base_addr = ioaddr; - lp = (struct cops_local *)dev->priv; + lp = netdev_priv(dev); memset(lp, 0, sizeof(struct cops_local)); spin_lock_init(&lp->lock); @@ -422,7 +422,7 @@ */ static int cops_open(struct net_device *dev) { - struct cops_local *lp = (struct cops_local *)dev->priv; + struct cops_local *lp = netdev_priv(dev); if(dev->irq==0) { @@ -456,7 +456,7 @@ */ static int cops_jumpstart(struct net_device *dev) { - struct cops_local *lp = (struct cops_local *)dev->priv; + struct cops_local *lp = netdev_priv(dev); /* * Once the card has the firmware loaded and has acquired @@ -490,7 +490,7 @@ */ static void cops_reset(struct net_device *dev, int sleep) { - struct cops_local *lp = (struct cops_local *)dev->priv; + struct cops_local *lp = netdev_priv(dev); int ioaddr=dev->base_addr; if(lp->board==TANGENT) @@ -525,7 +525,7 @@ { struct ifreq ifr; struct ltfirmware *ltf= (struct ltfirmware *)&ifr.ifr_data; - struct cops_local *lp=(struct cops_local *)dev->priv; + struct cops_local *lp = netdev_priv(dev); int ioaddr=dev->base_addr; int length, i = 0; @@ -618,7 +618,7 @@ */ static int cops_nodeid (struct net_device *dev, int nodeid) { - struct cops_local *lp = (struct cops_local *) dev->priv; + struct cops_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; if(lp->board == DAYNA) @@ -730,7 +730,7 @@ int boguscount = 0; ioaddr = dev->base_addr; - lp = (struct cops_local *)dev->priv; + lp = netdev_priv(dev); if(lp->board==DAYNA) { @@ -765,7 +765,7 @@ int pkt_len = 0; int rsp_type = 0; struct sk_buff *skb = NULL; - struct cops_local *lp = dev->priv; + struct cops_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int boguscount = 0; unsigned long flags; @@ -869,7 +869,7 @@ static void cops_timeout(struct net_device *dev) { - struct cops_local *lp = (struct cops_local *)dev->priv; + struct cops_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; lp->stats.tx_errors++; @@ -891,7 +891,7 @@ static int cops_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct cops_local *lp = (struct cops_local *)dev->priv; + struct cops_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; unsigned long flags; @@ -966,7 +966,7 @@ static int cops_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct cops_local *lp = (struct cops_local *)dev->priv; + struct cops_local *lp = netdev_priv(dev); struct sockaddr_at *sa = (struct sockaddr_at *)&ifr->ifr_addr; struct atalk_addr *aa = (struct atalk_addr *)&lp->node_addr; @@ -1002,7 +1002,7 @@ static int cops_close(struct net_device *dev) { - struct cops_local *lp = (struct cops_local *)dev->priv; + struct cops_local *lp = netdev_priv(dev); /* If we were running polled, yank the timer. */ @@ -1019,7 +1019,7 @@ */ static struct net_device_stats *cops_get_stats(struct net_device *dev) { - struct cops_local *lp = (struct cops_local *)dev->priv; + struct cops_local *lp = netdev_priv(dev); return &lp->stats; } diff -Nru a/drivers/net/ariadne.c b/drivers/net/ariadne.c --- a/drivers/net/ariadne.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/ariadne.c Sun Mar 14 14:20:07 2004 @@ -184,7 +184,7 @@ } SET_MODULE_OWNER(dev); - priv = dev->priv; + priv = netdev_priv(dev); r1->name = dev->name; r2->name = dev->name; @@ -333,7 +333,7 @@ static void ariadne_init_ring(struct net_device *dev) { - struct ariadne_private *priv = (struct ariadne_private *)dev->priv; + struct ariadne_private *priv = netdev_priv(dev); volatile struct lancedata *lancedata = (struct lancedata *)dev->mem_start; int i; @@ -379,7 +379,7 @@ static int ariadne_close(struct net_device *dev) { - struct ariadne_private *priv = (struct ariadne_private *)dev->priv; + struct ariadne_private *priv = netdev_priv(dev); volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; netif_stop_queue(dev); @@ -434,7 +434,7 @@ if (!(lance->RDP & INTR)) /* Check if any interrupt has been */ return IRQ_NONE; /* generated by the board. */ - priv = (struct ariadne_private *)dev->priv; + priv = netdev_priv(dev); boguscnt = 10; while ((csr0 = lance->RDP) & (ERR|RINT|TINT) && --boguscnt >= 0) { @@ -589,7 +589,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct ariadne_private *priv = (struct ariadne_private *)dev->priv; + struct ariadne_private *priv = netdev_priv(dev); volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; int entry; unsigned long flags; @@ -697,7 +697,7 @@ static int ariadne_rx(struct net_device *dev) { - struct ariadne_private *priv = (struct ariadne_private *)dev->priv; + struct ariadne_private *priv = netdev_priv(dev); int entry = priv->cur_rx % RX_RING_SIZE; int i; @@ -787,7 +787,7 @@ static struct net_device_stats *ariadne_get_stats(struct net_device *dev) { - struct ariadne_private *priv = (struct ariadne_private *)dev->priv; + struct ariadne_private *priv = netdev_priv(dev); volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr; short saved_addr; unsigned long flags; diff -Nru a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c --- a/drivers/net/arm/am79c961a.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/arm/am79c961a.c Sun Mar 14 14:20:08 2004 @@ -196,7 +196,7 @@ static void am79c961_init_for_open(struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); unsigned long flags; unsigned char *p; u_int hdr_addr, first_free_addr; @@ -271,7 +271,7 @@ static void am79c961_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); unsigned int lnkstat, carrier; lnkstat = read_ireg(dev->base_addr, ISALED0) & ISALED0_LNKST; @@ -291,7 +291,7 @@ static int am79c961_open(struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); int ret; memset (&priv->stats, 0, sizeof (priv->stats)); @@ -318,7 +318,7 @@ static int am79c961_close(struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); unsigned long flags; del_timer_sync(&priv->timer); @@ -341,7 +341,7 @@ */ static struct net_device_stats *am79c961_getstats (struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); return &priv->stats; } @@ -365,7 +365,7 @@ */ static void am79c961_setmulticastlist (struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); unsigned long flags; unsigned short multi_hash[4], mode; int i, stopped; @@ -444,7 +444,7 @@ static int am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); unsigned int hdraddr, bufaddr; unsigned int head; unsigned long flags; @@ -593,7 +593,7 @@ am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_id; - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); u_int status, n = 100; int handled = 0; @@ -630,7 +630,7 @@ static int am79c961_hw_init(struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); spin_lock_irq(&priv->chip_lock); write_rreg (dev->base_addr, CSR0, CSR0_STOP); @@ -662,7 +662,7 @@ if (!dev) goto out; - priv = dev->priv; + priv = netdev_priv(dev); /* * Fixed address and IRQ lines here. diff -Nru a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c --- a/drivers/net/arm/ether1.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/arm/ether1.c Sun Mar 14 14:20:07 2004 @@ -447,7 +447,7 @@ static int ether1_init_for_open (struct net_device *dev) { - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + struct ether1_priv *priv = netdev_priv(dev); int i, status, addr, next, next2; int failures = 0; unsigned long timeout; @@ -616,7 +616,7 @@ static int ether1_txalloc (struct net_device *dev, int size) { - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + struct ether1_priv *priv = netdev_priv(dev); int start, tail; size = (size + 1) & ~1; @@ -642,7 +642,7 @@ static int ether1_open (struct net_device *dev) { - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + struct ether1_priv *priv = netdev_priv(dev); if (!is_valid_ether_addr(dev->dev_addr)) { printk(KERN_WARNING "%s: invalid ethernet MAC address\n", @@ -668,7 +668,7 @@ static void ether1_timeout(struct net_device *dev) { - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + struct ether1_priv *priv = netdev_priv(dev); printk(KERN_WARNING "%s: transmit timeout, network cable problem?\n", dev->name); @@ -686,7 +686,7 @@ static int ether1_sendpacket (struct sk_buff *skb, struct net_device *dev) { - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + struct ether1_priv *priv = netdev_priv(dev); int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr; unsigned long flags; tx_t tx; @@ -762,7 +762,7 @@ static void ether1_xmit_done (struct net_device *dev) { - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + struct ether1_priv *priv = netdev_priv(dev); nop_t nop; int caddr, tst; @@ -863,7 +863,7 @@ static void ether1_recv_done (struct net_device *dev) { - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + struct ether1_priv *priv = netdev_priv(dev); int status; int nexttail, rbdaddr; rbd_t rbd; @@ -919,7 +919,7 @@ ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_id; - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + struct ether1_priv *priv = netdev_priv(dev); int status; status = ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS); @@ -978,7 +978,7 @@ static struct net_device_stats * ether1_getstats (struct net_device *dev) { - struct ether1_priv *priv = (struct ether1_priv *)dev->priv; + struct ether1_priv *priv = netdev_priv(dev); return &priv->stats; } @@ -1030,7 +1030,7 @@ request_region(dev->base_addr, 16, dev->name); request_region(dev->base_addr + 0x800, 4096, dev->name); - priv = (struct ether1_priv *)dev->priv; + priv = netdev_priv(dev); if ((priv->bus_type = ether1_reset(dev)) == 0) { ret = -ENODEV; goto release; diff -Nru a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c --- a/drivers/net/arm/ether3.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/arm/ether3.c Sun Mar 14 14:20:08 2004 @@ -121,7 +121,7 @@ static int ether3_setbuffer(struct net_device *dev, buffer_rw_t read, int start) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); int timeout = 1000; ether3_outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1); @@ -180,7 +180,7 @@ ether3_ledoff(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); ether3_outw(priv->regs.config2 |= CFG2_CTRLO, REG_CONFIG2); } @@ -280,7 +280,7 @@ static int __init ether3_init_2(struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); int i; priv->regs.config1 = CFG1_RECVCOMPSTAT0|CFG1_DMABURST8; @@ -330,7 +330,7 @@ static void ether3_init_for_open(struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); int i; memset(&priv->stats, 0, sizeof(struct net_device_stats)); @@ -434,7 +434,7 @@ static int ether3_close(struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); netif_stop_queue(dev); @@ -457,7 +457,7 @@ */ static struct net_device_stats *ether3_getstats(struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); return &priv->stats; } @@ -469,7 +469,7 @@ */ static void ether3_setmulticastlist(struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); priv->regs.config1 &= ~CFG1_RECVPROMISC; @@ -487,7 +487,7 @@ static void ether3_timeout(struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); unsigned long flags; del_timer(&priv->timer); @@ -518,7 +518,7 @@ static int ether3_sendpacket(struct sk_buff *skb, struct net_device *dev) { - struct dev_priv *priv = (struct dev_priv *)dev->priv; + struct dev_priv *priv = netdev_priv(dev); unsigned long flags; unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned int ptr, next_ptr; @@ -594,7 +594,7 @@ printk("eth3irq: %d ", irq); #endif - priv = (struct dev_priv *)dev->priv; + priv = netdev_priv(dev); status = ether3_inw(REG_STATUS); @@ -844,7 +844,7 @@ goto free; } - priv = (struct dev_priv *) dev->priv; + priv = netdev_priv(dev); init_timer(&priv->timer); /* Reset card... diff -Nru a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c --- a/drivers/net/arm/etherh.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/arm/etherh.c Sun Mar 14 14:20:08 2004 @@ -144,7 +144,7 @@ static void etherh_setif(struct net_device *dev) { - struct etherh_priv *eh = (struct etherh_priv *)dev->priv; + struct etherh_priv *eh = netdev_priv(dev); struct ei_device *ei_local = &eh->eidev; unsigned long addr, flags; @@ -188,7 +188,7 @@ static int etherh_getifstat(struct net_device *dev) { - struct etherh_priv *eh = (struct etherh_priv *)dev->priv; + struct etherh_priv *eh = netdev_priv(dev); struct ei_device *ei_local = &eh->eidev; int stat = 0; @@ -256,7 +256,7 @@ static void etherh_reset(struct net_device *dev) { - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = netdev_priv(dev); outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, dev->base_addr); @@ -283,7 +283,7 @@ static void etherh_block_output (struct net_device *dev, int count, const unsigned char *buf, int start_page) { - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = netdev_priv(dev); unsigned int addr, dma_addr; unsigned long dma_start; @@ -349,7 +349,7 @@ static void etherh_block_input (struct net_device *dev, int count, struct sk_buff *skb, int ring_offset) { - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = netdev_priv(dev); unsigned int addr, dma_addr; unsigned char *buf; @@ -390,7 +390,7 @@ static void etherh_get_header (struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) { - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = netdev_priv(dev); unsigned int addr, dma_addr; if (ei_local->dmaing) { @@ -432,7 +432,7 @@ static int etherh_open(struct net_device *dev) { - struct ei_device *ei_local = (struct ei_device *) dev->priv; + struct ei_device *ei_local = netdev_priv(dev); if (!is_valid_ether_addr(dev->dev_addr)) { printk(KERN_WARNING "%s: invalid ethernet MAC address\n", @@ -557,7 +557,7 @@ goto out; } - eh = dev->priv; + eh = netdev_priv(dev); spin_lock_init(&eh->eidev.page_lock); @@ -653,7 +653,7 @@ break; } - ei_local = (struct ei_device *) dev->priv; + ei_local = netdev_priv(dev); if (ec->cid.product == PROD_ANT_ETHERM) { ei_local->tx_start_page = ETHERM_TX_START_PAGE; ei_local->stop_page = ETHERM_STOP_PAGE; diff -Nru a/drivers/net/at1700.c b/drivers/net/at1700.c --- a/drivers/net/at1700.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/at1700.c Sun Mar 14 14:20:07 2004 @@ -241,7 +241,7 @@ static void cleanup_card(struct net_device *dev) { #ifdef CONFIG_MCA - struct net_local *lp = dev->priv; + struct net_local *lp = netdev_priv(dev); if (lp->mca_slot) mca_mark_as_unused(lp->mca_slot); #endif @@ -319,8 +319,8 @@ char at1700_irqmap[8] = {3, 4, 5, 9, 10, 11, 14, 15}; unsigned int i, irq, is_fmv18x = 0, is_at1700 = 0; int slot, ret = -ENODEV; - struct net_local *lp = dev->priv; - + struct net_local *lp = netdev_priv(dev); + #ifndef CONFIG_X86_PC9800 if (!request_region(ioaddr, AT1700_IO_EXTENT, dev->name)) return -EBUSY; @@ -618,7 +618,7 @@ static int net_open(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; /* Set the configuration register 0 to 32K 100ns. byte-wide memory, 16 bit @@ -649,7 +649,7 @@ static void net_tx_timeout (struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; printk ("%s: transmit timed out with status %04x, %s?\n", dev->name, @@ -683,7 +683,7 @@ static int net_send_packet (struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = (struct net_local *) dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; short len = skb->len; @@ -748,7 +748,7 @@ } ioaddr = dev->base_addr; - lp = (struct net_local *)dev->priv; + lp = netdev_priv(dev); spin_lock (&lp->lock); @@ -808,7 +808,7 @@ static void net_rx(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int boguscount = 5; @@ -891,7 +891,7 @@ /* The inverse routine to net_open(). */ static int net_close(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; netif_stop_queue(dev); @@ -919,7 +919,7 @@ static struct net_device_stats * net_get_stats(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); return &lp->stats; } @@ -931,7 +931,7 @@ set_rx_mode(struct net_device *dev) { int ioaddr = dev->base_addr; - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned char mc_filter[8]; /* Multicast hash filter */ unsigned long flags; int i; diff -Nru a/drivers/net/atari_bionet.c b/drivers/net/atari_bionet.c --- a/drivers/net/atari_bionet.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/atari_bionet.c Sun Mar 14 14:20:07 2004 @@ -408,7 +408,7 @@ */ static int bionet_open(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if (bionet_debug > 0) printk("bionet_open\n"); @@ -433,7 +433,7 @@ static int bionet_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned long flags; /* Block a timer-based transmit from overlapping. This could better be @@ -499,7 +499,7 @@ */ static void bionet_poll_rx(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int boguscount = 10; int pkt_len, status; unsigned long flags; @@ -601,7 +601,7 @@ static void bionet_tick(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if( bionet_debug > 0 && (lp->open_time++ & 7) == 8 ) printk("bionet_tick: %ld\n", lp->open_time); @@ -616,7 +616,7 @@ */ static int bionet_close(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if (bionet_debug > 0) printk("bionet_close, open_time=%ld\n", lp->open_time); @@ -638,7 +638,7 @@ */ static struct net_device_stats *net_get_stats(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); return &lp->stats; } diff -Nru a/drivers/net/atari_pamsnet.c b/drivers/net/atari_pamsnet.c --- a/drivers/net/atari_pamsnet.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/atari_pamsnet.c Sun Mar 14 14:20:06 2004 @@ -667,7 +667,7 @@ */ static int pamsnet_open(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if (pamsnet_debug > 0) printk("pamsnet_open\n"); @@ -696,7 +696,7 @@ static int pamsnet_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned long flags; /* Block a timer-based transmit from overlapping. This could better be @@ -742,7 +742,7 @@ */ static void pamsnet_poll_rx(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int boguscount; int pkt_len; struct sk_buff *skb; @@ -817,7 +817,7 @@ static void pamsnet_tick(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if( pamsnet_debug > 0 && (lp->open_time++ & 7) == 8 ) printk("pamsnet_tick: %ld\n", lp->open_time); @@ -832,7 +832,7 @@ */ static int pamsnet_close(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if (pamsnet_debug > 0) printk("pamsnet_close, open_time=%ld\n", lp->open_time); @@ -859,7 +859,7 @@ */ static struct net_device_stats *net_get_stats(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); return &lp->stats; } diff -Nru a/drivers/net/atp.c b/drivers/net/atp.c --- a/drivers/net/atp.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/atp.c Sun Mar 14 14:20:08 2004 @@ -335,7 +335,7 @@ /* Reset the ethernet hardware and activate the printer pass-through. */ write_reg_high(ioaddr, CMR1, CMR1h_RESET | CMR1h_MUX); - lp = (struct net_local *)dev->priv; + lp = netdev_priv(dev); lp->chip_type = RTL8002; lp->addr_mode = CMR2h_Normal; spin_lock_init(&lp->lock); @@ -432,7 +432,7 @@ */ static int net_open(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ret; /* The interrupt line is turned off (tri-stated) when the device isn't in @@ -458,7 +458,7 @@ the hardware may have been temporarily detached. */ static void hardware_init(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); long ioaddr = dev->base_addr; int i; @@ -541,7 +541,7 @@ static void tx_timeout(struct net_device *dev) { - struct net_local *np = (struct net_local *)dev->priv; + struct net_local *np = netdev_priv(dev); long ioaddr = dev->base_addr; printk(KERN_WARNING "%s: Transmit timed out, %s?\n", dev->name, @@ -557,7 +557,7 @@ static int atp_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); long ioaddr = dev->base_addr; int length; unsigned long flags; @@ -611,7 +611,7 @@ return IRQ_NONE; } ioaddr = dev->base_addr; - lp = (struct net_local *)dev->priv; + lp = netdev_priv(dev); spin_lock(&lp->lock); @@ -726,7 +726,7 @@ { struct net_device *dev = (struct net_device *)data; long ioaddr = dev->base_addr; - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int tickssofar = jiffies - lp->last_rx_time; int i; @@ -740,7 +740,7 @@ for (i = 0; i < 6; i++) if (read_cmd_byte(ioaddr, PAR0 + i) != atp_timed_dev->dev_addr[i]) { - struct net_local *lp = (struct net_local *)atp_timed_dev->priv; + struct net_local *lp = netdev_priv(atp_timed_dev); write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]); if (i == 2) lp->stats.tx_errors++; @@ -762,7 +762,7 @@ /* We have a good packet(s), get it/them out of the buffers. */ static void net_rx(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); long ioaddr = dev->base_addr; struct rx_header rx_head; @@ -838,7 +838,7 @@ static int net_close(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); long ioaddr = dev->base_addr; netif_stop_queue(dev); @@ -863,7 +863,7 @@ static struct net_device_stats * net_get_stats(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); return &lp->stats; } @@ -873,7 +873,7 @@ static void set_rx_mode_8002(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); long ioaddr = dev->base_addr; if ( dev->mc_count > 0 || (dev->flags & (IFF_ALLMULTI|IFF_PROMISC))) { @@ -890,7 +890,7 @@ static void set_rx_mode_8012(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); long ioaddr = dev->base_addr; unsigned char new_mode, mc_filter[8]; /* Multicast hash filter */ int i; diff -Nru a/drivers/net/b44.c b/drivers/net/b44.c --- a/drivers/net/b44.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/b44.c Sun Mar 14 14:20:07 2004 @@ -667,6 +667,10 @@ dest_desc->ctrl = ctrl; dest_desc->addr = src_desc->addr; src_map->skb = NULL; + + pci_dma_sync_single_for_device(bp->pdev, src_desc->addr, + RX_PKT_BUF_SZ, + PCI_DMA_FROMDEVICE); } static int b44_rx(struct b44 *bp, int budget) @@ -686,9 +690,9 @@ struct rx_header *rh; u16 len; - pci_dma_sync_single(bp->pdev, map, - RX_PKT_BUF_SZ, - PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(bp->pdev, map, + RX_PKT_BUF_SZ, + PCI_DMA_FROMDEVICE); rh = (struct rx_header *) skb->data; len = cpu_to_le16(rh->len); if ((len > (RX_PKT_BUF_SZ - bp->rx_offset)) || diff -Nru a/drivers/net/bagetlance.c b/drivers/net/bagetlance.c --- a/drivers/net/bagetlance.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/bagetlance.c Sun Mar 14 14:20:06 2004 @@ -594,7 +594,7 @@ return( 0 ); probe_ok: - lp = (struct lance_private *)dev->priv; + lp = netdev_priv(dev); MEM = (struct lance_memory *)memaddr; IO = lp->iobase = (struct lance_ioreg *)ioaddr; dev->base_addr = (unsigned long)ioaddr; /* informational only */ @@ -736,7 +736,7 @@ static int lance_open( struct net_device *dev ) -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ struct lance_private *lp = netdev_priv(dev); struct lance_ioreg *IO = lp->iobase; int i; @@ -778,7 +778,7 @@ static void lance_init_ring( struct net_device *dev ) -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ struct lance_private *lp = netdev_priv(dev); int i; unsigned offset; @@ -834,7 +834,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ struct lance_private *lp = netdev_priv(dev); struct lance_ioreg *IO = lp->iobase; int entry, len; struct lance_tx_head *head; @@ -988,7 +988,7 @@ return IRQ_NONE; } - lp = (struct lance_private *)dev->priv; + lp = netdev_priv(dev); IO = lp->iobase; AREG = CSR0; @@ -1101,7 +1101,7 @@ static int lance_rx( struct net_device *dev ) -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ struct lance_private *lp = netdev_priv(dev); int entry = lp->cur_rx & RX_RING_MOD_MASK; int i; @@ -1225,7 +1225,7 @@ static int lance_close( struct net_device *dev ) -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ struct lance_private *lp = netdev_priv(dev); struct lance_ioreg *IO = lp->iobase; dev->start = 0; @@ -1247,7 +1247,7 @@ static struct net_device_stats *lance_get_stats( struct net_device *dev ) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); return &lp->stats; } @@ -1261,7 +1261,7 @@ static void set_multicast_list( struct net_device *dev ) -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ struct lance_private *lp = netdev_priv(dev); struct lance_ioreg *IO = lp->iobase; if (!dev->start) @@ -1303,7 +1303,7 @@ static int lance_set_mac_address( struct net_device *dev, void *addr ) -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ struct lance_private *lp = netdev_priv(dev); struct sockaddr *saddr = addr; int i; diff -Nru a/drivers/net/bmac.c b/drivers/net/bmac.c --- a/drivers/net/bmac.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/bmac.c Sun Mar 14 14:20:06 2004 @@ -226,7 +226,7 @@ static void bmac_enable_and_reset_chip(struct net_device *dev) { - struct bmac_data *bp = (struct bmac_data *) dev->priv; + struct bmac_data *bp = netdev_priv(dev); volatile struct dbdma_regs *rd = bp->rx_dma; volatile struct dbdma_regs *td = bp->tx_dma; @@ -310,7 +310,7 @@ static void bmac_init_registers(struct net_device *dev) { - struct bmac_data *bp = (struct bmac_data *) dev->priv; + struct bmac_data *bp = netdev_priv(dev); volatile unsigned short regValue; unsigned short *pWord16; int i; @@ -405,7 +405,7 @@ static void bmac_start_chip(struct net_device *dev) { - struct bmac_data *bp = (struct bmac_data *) dev->priv; + struct bmac_data *bp = netdev_priv(dev); volatile struct dbdma_regs *rd = bp->rx_dma; unsigned short oldConfig; @@ -425,7 +425,7 @@ bmac_init_phy(struct net_device *dev) { unsigned int addr; - struct bmac_data *bp = (struct bmac_data *) dev->priv; + struct bmac_data *bp = netdev_priv(dev); printk(KERN_DEBUG "phy registers:"); for (addr = 0; addr < 32; ++addr) { @@ -458,7 +458,7 @@ static int bmac_suspend(struct macio_dev *mdev, u32 state) { struct net_device* dev = macio_get_drvdata(mdev); - struct bmac_data *bp = dev->priv; + struct bmac_data *bp = netdev_priv(dev); unsigned long flags; unsigned short config; int i; @@ -508,7 +508,7 @@ static int bmac_resume(struct macio_dev *mdev) { struct net_device* dev = macio_get_drvdata(mdev); - struct bmac_data *bp = dev->priv; + struct bmac_data *bp = netdev_priv(dev); /* see if this is enough */ if (bp->opened) @@ -525,7 +525,7 @@ static int bmac_set_address(struct net_device *dev, void *addr) { - struct bmac_data *bp = (struct bmac_data *) dev->priv; + struct bmac_data *bp = netdev_priv(dev); unsigned char *p = addr; unsigned short *pWord16; unsigned long flags; @@ -550,7 +550,7 @@ static inline void bmac_set_timeout(struct net_device *dev) { - struct bmac_data *bp = (struct bmac_data *) dev->priv; + struct bmac_data *bp = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&bp->lock, flags); @@ -656,7 +656,7 @@ static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev) { - struct bmac_data *bp = (struct bmac_data *) dev->priv; + struct bmac_data *bp = netdev_priv(dev); volatile struct dbdma_regs *td = bp->tx_dma; int i; @@ -692,7 +692,7 @@ static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; - struct bmac_data *bp = (struct bmac_data *) dev->priv; + struct bmac_data *bp = netdev_priv(dev); volatile struct dbdma_regs *rd = bp->rx_dma; volatile struct dbdma_cmd *cp; int i, nb, stat; @@ -769,7 +769,7 @@ static irqreturn_t bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; - struct bmac_data *bp = (struct bmac_data *) dev->priv; + struct bmac_data *bp = netdev_priv(dev); volatile struct dbdma_cmd *cp; int stat; unsigned long flags; @@ -822,7 +822,7 @@ static struct net_device_stats *bmac_stats(struct net_device *dev) { - struct bmac_data *p = (struct bmac_data *) dev->priv; + struct bmac_data *p = netdev_priv(dev); return &p->stats; } @@ -995,7 +995,7 @@ static void bmac_set_multicast(struct net_device *dev) { struct dev_mc_list *dmi; - struct bmac_data *bp = (struct bmac_data *) dev->priv; + struct bmac_data *bp = netdev_priv(dev); int num_addrs = dev->mc_count; unsigned short rx_cfg; int i; @@ -1086,7 +1086,7 @@ static irqreturn_t bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; - struct bmac_data *bp = (struct bmac_data *)dev->priv; + struct bmac_data *bp = netdev_priv(dev); unsigned int status = bmread(dev, STATUS); if (miscintcount++ < 10) { XXDEBUG(("bmac_misc_intr\n")); @@ -1232,7 +1232,7 @@ static void bmac_reset_and_enable(struct net_device *dev) { - struct bmac_data *bp = dev->priv; + struct bmac_data *bp = netdev_priv(dev); unsigned long flags; struct sk_buff *skb; unsigned char *data; @@ -1288,7 +1288,7 @@ return -ENOMEM; } - bp = (struct bmac_data *) dev->priv; + bp = netdev_priv(dev); SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &mdev->ofdev.dev); macio_set_drvdata(mdev, dev); @@ -1408,7 +1408,7 @@ static int bmac_open(struct net_device *dev) { - struct bmac_data *bp = (struct bmac_data *) dev->priv; + struct bmac_data *bp = netdev_priv(dev); /* XXDEBUG(("bmac: enter open\n")); */ /* reset the chip */ bp->opened = 1; @@ -1420,7 +1420,7 @@ static int bmac_close(struct net_device *dev) { - struct bmac_data *bp = (struct bmac_data *) dev->priv; + struct bmac_data *bp = netdev_priv(dev); volatile struct dbdma_regs *rd = bp->rx_dma; volatile struct dbdma_regs *td = bp->tx_dma; unsigned short config; @@ -1469,7 +1469,7 @@ static void bmac_start(struct net_device *dev) { - struct bmac_data *bp = dev->priv; + struct bmac_data *bp = netdev_priv(dev); int i; struct sk_buff *skb; unsigned long flags; @@ -1495,7 +1495,7 @@ static int bmac_output(struct sk_buff *skb, struct net_device *dev) { - struct bmac_data *bp = dev->priv; + struct bmac_data *bp = netdev_priv(dev); skb_queue_tail(bp->queue, skb); bmac_start(dev); return 0; @@ -1504,7 +1504,7 @@ static void bmac_tx_timeout(unsigned long data) { struct net_device *dev = (struct net_device *) data; - struct bmac_data *bp = (struct bmac_data *) dev->priv; + struct bmac_data *bp = netdev_priv(dev); volatile struct dbdma_regs *td = bp->tx_dma; volatile struct dbdma_regs *rd = bp->rx_dma; volatile struct dbdma_cmd *cp; @@ -1630,7 +1630,7 @@ static int __devexit bmac_remove(struct macio_dev *mdev) { struct net_device *dev = macio_get_drvdata(mdev); - struct bmac_data *bp = dev->priv; + struct bmac_data *bp = netdev_priv(dev); unregister_netdev(dev); diff -Nru a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c --- a/drivers/net/cs89x0.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/cs89x0.c Sun Mar 14 14:20:08 2004 @@ -399,7 +399,7 @@ static int __init cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); static unsigned version_printed; int i; unsigned rev_type = 0; @@ -735,7 +735,7 @@ static void get_dma_channel(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if (lp->dma) { dev->dma = lp->dma; @@ -757,7 +757,7 @@ static void write_dma(struct net_device *dev, int chip_type, int dma) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if ((lp->isa_config & ANY_ISA_DMA) == 0) return; if (chip_type == CS8900) { @@ -770,7 +770,7 @@ static void set_dma_cfg(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if (lp->use_dma) { if ((lp->isa_config & ANY_ISA_DMA) == 0) { @@ -793,7 +793,7 @@ static int dma_bufcfg(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if (lp->use_dma) return (lp->isa_config & ANY_ISA_DMA)? RX_DMA_ENBL : 0; else @@ -804,7 +804,7 @@ dma_busctl(struct net_device *dev) { int retval = 0; - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if (lp->use_dma) { if (lp->isa_config & ANY_ISA_DMA) retval |= RESET_RX_DMA; /* Reset the DMA pointer */ @@ -820,7 +820,7 @@ static void dma_rx(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); struct sk_buff *skb; int status, length; unsigned char *bp = lp->rx_dma_ptr; @@ -882,7 +882,7 @@ void __init reset_chip(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int reset_start_time; @@ -912,7 +912,7 @@ static void control_dc_dc(struct net_device *dev, int on_not_off) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned int selfcontrol; int timenow = jiffies; /* control the DC to DC convertor in the SelfControl register. @@ -940,7 +940,7 @@ static int detect_tp(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int timenow = jiffies; int fdx; @@ -1055,7 +1055,7 @@ static int detect_aui(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if (net_debug > 1) printk("%s: Attempting AUI\n", dev->name); control_dc_dc(dev, 0); @@ -1071,7 +1071,7 @@ static int detect_bnc(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if (net_debug > 1) printk("%s: Attempting BNC\n", dev->name); control_dc_dc(dev, 1); @@ -1117,7 +1117,7 @@ static int net_open(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int result = 0; int i; int ret; @@ -1358,7 +1358,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if (net_debug > 3) { printk("%s: sent %d byte packet of type %x\n", @@ -1419,7 +1419,7 @@ int handled = 0; ioaddr = dev->base_addr; - lp = (struct net_local *)dev->priv; + lp = netdev_priv(dev); /* we MUST read all the events out of the ISQ, otherwise we'll never get interrupted again. As a consequence, we can't have any limit @@ -1517,7 +1517,7 @@ static void net_rx(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); struct sk_buff *skb; int status, length; @@ -1573,7 +1573,7 @@ static int net_close(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); netif_stop_queue(dev); @@ -1600,7 +1600,7 @@ static struct net_device_stats * net_get_stats(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&lp->lock, flags); @@ -1614,7 +1614,7 @@ static void set_multicast_list(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&lp->lock, flags); @@ -1758,7 +1758,7 @@ dev->irq = irq; dev->base_addr = io; - lp = dev->priv; + lp = netdev_priv(dev); #if ALLOW_DMA if (use_dma) { diff -Nru a/drivers/net/declance.c b/drivers/net/declance.c --- a/drivers/net/declance.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/declance.c Sun Mar 14 14:20:07 2004 @@ -433,7 +433,7 @@ /* Setup the Lance Rx and Tx rings */ static void lance_init_ring(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib; int leptr; int i; @@ -530,7 +530,7 @@ static int lance_rx(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib; volatile struct lance_rx_desc *rd = 0; unsigned char bits; @@ -617,7 +617,7 @@ static void lance_tx(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib; volatile struct lance_regs *ll = lp->ll; volatile struct lance_tx_desc *td; @@ -709,7 +709,7 @@ lance_interrupt(const int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; int csr0; @@ -757,7 +757,7 @@ static int lance_open(struct net_device *dev) { volatile struct lance_init_block *ib = (struct lance_init_block *) (dev->mem_start); - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; int status = 0; @@ -822,7 +822,7 @@ static int lance_close(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; netif_stop_queue(dev); @@ -856,7 +856,7 @@ static inline int lance_reset(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; int status; @@ -873,7 +873,7 @@ static void lance_tx_timeout(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; printk(KERN_ERR "%s: transmit timed out, status %04x, reset\n", @@ -884,7 +884,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_regs *ll = lp->ll; volatile struct lance_init_block *ib = (struct lance_init_block *) (dev->mem_start); int entry, skblen, len; @@ -936,7 +936,7 @@ static struct net_device_stats *lance_get_stats(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); return &lp->stats; } @@ -982,7 +982,7 @@ static void lance_set_multicast(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib; volatile struct lance_regs *ll = lp->ll; @@ -1048,7 +1048,7 @@ * alloc_etherdev ensures the data structures used by the LANCE * are aligned. */ - lp = (struct lance_private *) dev->priv; + lp = netdev_priv(dev); spin_lock_init(&lp->lock); lp->type = type; @@ -1287,7 +1287,7 @@ { while (root_lance_dev) { struct net_device *dev = root_lance_dev; - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); unregister_netdev(dev); #ifdef CONFIG_TC if (lp->slot >= 0) diff -Nru a/drivers/net/dl2k.c b/drivers/net/dl2k.c --- a/drivers/net/dl2k.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/dl2k.c Sun Mar 14 14:20:07 2004 @@ -874,8 +874,6 @@ frame_status = le64_to_cpu (desc->status); if (--cnt < 0) break; - pci_dma_sync_single (np->pdev, desc->fraginfo, np->rx_buf_sz, - PCI_DMA_FROMDEVICE); /* Update rx error statistics, drop packet. */ if (frame_status & RFS_Errors) { np->stats.rx_errors++; @@ -898,6 +896,10 @@ skb_put (skb = np->rx_skbuff[entry], pkt_len); np->rx_skbuff[entry] = NULL; } else if ((skb = dev_alloc_skb (pkt_len + 2)) != NULL) { + pci_dma_sync_single_for_cpu(np->pdev, + desc->fraginfo, + np->rx_buf_sz, + PCI_DMA_FROMDEVICE); skb->dev = dev; /* 16 byte align the IP header */ skb_reserve (skb, 2); @@ -905,6 +907,10 @@ np->rx_skbuff[entry]->tail, pkt_len, 0); skb_put (skb, pkt_len); + pci_dma_sync_single_for_device(np->pdev, + desc->fraginfo, + np->rx_buf_sz, + PCI_DMA_FROMDEVICE); } skb->protocol = eth_type_trans (skb, dev); #if 0 diff -Nru a/drivers/net/e100.c b/drivers/net/e100.c --- a/drivers/net/e100.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/e100.c Sun Mar 14 14:20:08 2004 @@ -158,7 +158,7 @@ #define DRV_NAME "e100" -#define DRV_VERSION "3.0.16" +#define DRV_VERSION "3.0.17" #define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver" #define DRV_COPYRIGHT "Copyright(c) 1999-2004 Intel Corporation" #define PFX DRV_NAME ": " @@ -1285,6 +1285,7 @@ le16_to_cpu(cb->u.tcb.tbd.size), PCI_DMA_TODEVICE); dev_kfree_skb_any(cb->skb); + cb->skb = NULL; tx_cleaned = 1; } cb->status = 0; @@ -1347,6 +1348,7 @@ cb->dma_addr = nic->cbs_dma_addr + i * sizeof(struct cb); cb->link = cpu_to_le32(nic->cbs_dma_addr + ((i+1) % count) * sizeof(struct cb)); + cb->skb = NULL; } nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = nic->cbs; @@ -1387,8 +1389,8 @@ (u32 *)&prev_rfd->link); wmb(); prev_rfd->command &= ~cpu_to_le16(cb_el); - pci_dma_sync_single(nic->pdev, rx->prev->dma_addr, - sizeof(struct rfd), PCI_DMA_TODEVICE); + pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr, + sizeof(struct rfd), PCI_DMA_TODEVICE); } return 0; @@ -1405,8 +1407,8 @@ return -EAGAIN; /* Need to sync before taking a peek at cb_complete bit */ - pci_dma_sync_single(nic->pdev, rx->dma_addr, - sizeof(struct rfd), PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(nic->pdev, rx->dma_addr, + sizeof(struct rfd), PCI_DMA_FROMDEVICE); rfd_status = le16_to_cpu(rfd->status); DPRINTK(RX_STATUS, DEBUG, "status=0x%04X\n", rfd_status); @@ -1421,11 +1423,8 @@ actual_size = RFD_BUF_LEN - sizeof(struct rfd); /* Get data */ - pci_dma_sync_single(nic->pdev, rx->dma_addr, - sizeof(struct rfd) + actual_size, - PCI_DMA_FROMDEVICE); pci_unmap_single(nic->pdev, rx->dma_addr, - RFD_BUF_LEN, PCI_DMA_FROMDEVICE); + RFD_BUF_LEN, PCI_DMA_FROMDEVICE); /* Pull off the RFD and put the actual data (minus eth hdr) */ skb_reserve(skb, sizeof(struct rfd)); diff -Nru a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c --- a/drivers/net/e1000/e1000_ethtool.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/e1000/e1000_ethtool.c Sun Mar 14 14:20:07 2004 @@ -1191,16 +1191,16 @@ for(i = 0; i < 64; i++) { e1000_create_lbtest_frame(txdr->buffer_info[i].skb, 1024); - pci_dma_sync_single(pdev, txdr->buffer_info[i].dma, - txdr->buffer_info[i].length, - PCI_DMA_TODEVICE); + pci_dma_sync_single_for_device(pdev, txdr->buffer_info[i].dma, + txdr->buffer_info[i].length, + PCI_DMA_TODEVICE); } E1000_WRITE_REG(&adapter->hw, TDT, i); msec_delay(200); - pci_dma_sync_single(pdev, rxdr->buffer_info[0].dma, - rxdr->buffer_info[0].length, PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(pdev, rxdr->buffer_info[0].dma, + rxdr->buffer_info[0].length, PCI_DMA_FROMDEVICE); return e1000_check_lbtest_frame(rxdr->buffer_info[0].skb, 1024); } diff -Nru a/drivers/net/e2100.c b/drivers/net/e2100.c --- a/drivers/net/e2100.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/e2100.c Sun Mar 14 14:20:08 2004 @@ -269,6 +269,9 @@ ei_status.get_8390_hdr = &e21_get_8390_hdr; dev->open = &e21_open; dev->stop = &e21_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; diff -Nru a/drivers/net/eepro.c b/drivers/net/eepro.c --- a/drivers/net/eepro.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/eepro.c Sun Mar 14 14:20:08 2004 @@ -662,7 +662,7 @@ { struct eepro_local * lp; - lp = dev->priv; + lp = netdev_priv(dev); lp->xmt_ram = RAM_SIZE - lp->rcv_ram; if (lp->eepro == LAN595FX_10ISA) { @@ -680,9 +680,9 @@ } /* prints boot-time info */ -static void eepro_print_info (struct net_device *dev) +static void __init eepro_print_info (struct net_device *dev) { - struct eepro_local * lp = dev->priv; + struct eepro_local * lp = netdev_priv(dev); int i; const char * ifmap[] = {"AUI", "10Base2", "10BaseT"}; @@ -769,7 +769,7 @@ if ((inb(ioaddr + ID_REG) & R_ROBIN_BITS) != (counter + 0x40)) goto exit; - lp = (struct eepro_local *)dev->priv; + lp = netdev_priv(dev); memset(lp, 0, sizeof(struct eepro_local)); lp->xmt_bar = XMT_BAR_PRO; lp->xmt_lower_limit_reg = XMT_LOWER_LIMIT_REG_PRO; @@ -932,7 +932,7 @@ unsigned short temp_reg, old8, old9; int irqMask; int i, ioaddr = dev->base_addr; - struct eepro_local *lp = (struct eepro_local *)dev->priv; + struct eepro_local *lp = netdev_priv(dev); if (net_debug > 3) printk(KERN_DEBUG "%s: entering eepro_open routine.\n", dev->name); @@ -1106,7 +1106,7 @@ static void eepro_tx_timeout (struct net_device *dev) { - struct eepro_local *lp = (struct eepro_local *) dev->priv; + struct eepro_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; /* if (net_debug > 1) */ @@ -1122,7 +1122,7 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct eepro_local *lp = (struct eepro_local *)dev->priv; + struct eepro_local *lp = netdev_priv(dev); unsigned long flags; int ioaddr = dev->base_addr; short length = skb->len; @@ -1187,7 +1187,7 @@ return IRQ_NONE; } - lp = (struct eepro_local *)dev->priv; + lp = netdev_priv(dev); spin_lock(&lp->lock); @@ -1235,7 +1235,7 @@ static int eepro_close(struct net_device *dev) { - struct eepro_local *lp = (struct eepro_local *)dev->priv; + struct eepro_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; short temp_reg; @@ -1280,7 +1280,7 @@ static struct net_device_stats * eepro_get_stats(struct net_device *dev) { - struct eepro_local *lp = (struct eepro_local *)dev->priv; + struct eepro_local *lp = netdev_priv(dev); return &lp->stats; } @@ -1290,7 +1290,7 @@ static void set_multicast_list(struct net_device *dev) { - struct eepro_local *lp = (struct eepro_local *)dev->priv; + struct eepro_local *lp = netdev_priv(dev); short ioaddr = dev->base_addr; unsigned short mode; struct dev_mc_list *dmi=dev->mc_list; @@ -1424,7 +1424,7 @@ { int i; unsigned short retval = 0; - struct eepro_local *lp = dev->priv; + struct eepro_local *lp = netdev_priv(dev); short ee_addr = ioaddr + lp->eeprom_reg; int read_cmd = location | EE_READ_CMD; short ctrl_val = EECS ; @@ -1468,7 +1468,7 @@ static int hardware_send_packet(struct net_device *dev, void *buf, short length) { - struct eepro_local *lp = (struct eepro_local *)dev->priv; + struct eepro_local *lp = netdev_priv(dev); short ioaddr = dev->base_addr; unsigned status, tx_available, last, end; @@ -1553,7 +1553,7 @@ static void eepro_rx(struct net_device *dev) { - struct eepro_local *lp = (struct eepro_local *)dev->priv; + struct eepro_local *lp = netdev_priv(dev); short ioaddr = dev->base_addr; short boguscount = 20; short rcv_car = lp->rx_start; @@ -1651,7 +1651,7 @@ static void eepro_transmit_interrupt(struct net_device *dev) { - struct eepro_local *lp = (struct eepro_local *)dev->priv; + struct eepro_local *lp = netdev_priv(dev); short ioaddr = dev->base_addr; short boguscount = 25; short xmt_status; diff -Nru a/drivers/net/eepro100.c b/drivers/net/eepro100.c --- a/drivers/net/eepro100.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/eepro100.c Sun Mar 14 14:20:07 2004 @@ -654,6 +654,23 @@ return -ENODEV; } +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling 'interrupt' - used by things like netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ + +static void poll_speedo (struct net_device *dev) +{ + /* disable_irq is not very nice, but with the funny lockless design + we have no other choice. */ + disable_irq(dev->irq); + speedo_interrupt (dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif + static int __devinit speedo_found1(struct pci_dev *pdev, long ioaddr, int card_idx, int acpi_idle_state) { @@ -839,7 +856,7 @@ dev->irq = pdev->irq; - sp = dev->priv; + sp = netdev_priv(dev); sp->pdev = pdev; sp->msg_enable = DEBUG; sp->acpi_pwr = acpi_idle_state; @@ -885,6 +902,9 @@ dev->get_stats = &speedo_get_stats; dev->set_multicast_list = &set_rx_mode; dev->do_ioctl = &speedo_ioctl; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = &poll_speedo; +#endif if (register_netdevice(dev)) goto err_free_unlock; @@ -995,7 +1015,7 @@ static int speedo_open(struct net_device *dev) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); long ioaddr = dev->base_addr; int retval; @@ -1082,7 +1102,7 @@ /* Start the chip hardware after a full reset. */ static void speedo_resume(struct net_device *dev) { - struct speedo_private *sp = dev->priv; + struct speedo_private *sp = netdev_priv(dev); long ioaddr = dev->base_addr; /* Start with a Tx threshold of 256 (0x..20.... 8 byte units). */ @@ -1162,7 +1182,7 @@ static void speedo_rx_soft_reset(struct net_device *dev) { - struct speedo_private *sp = dev->priv; + struct speedo_private *sp = netdev_priv(dev); struct RxFD *rfd; long ioaddr; @@ -1194,7 +1214,7 @@ static void speedo_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); long ioaddr = dev->base_addr; int phy_num = sp->phy[0] & 0x1f; @@ -1239,7 +1259,7 @@ static void speedo_show_state(struct net_device *dev) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); int i; if (netif_msg_pktdata(sp)) { @@ -1282,7 +1302,7 @@ static void speedo_init_rx_ring(struct net_device *dev) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); struct RxFD *rxf, *last_rxf = NULL; dma_addr_t last_rxf_dma = 0 /* to shut up the compiler */; int i; @@ -1306,8 +1326,8 @@ skb_reserve(skb, sizeof(struct RxFD)); if (last_rxf) { last_rxf->link = cpu_to_le32(sp->rx_ring_dma[i]); - pci_dma_sync_single(sp->pdev, last_rxf_dma, - sizeof(struct RxFD), PCI_DMA_TODEVICE); + pci_dma_sync_single_for_device(sp->pdev, last_rxf_dma, + sizeof(struct RxFD), PCI_DMA_TODEVICE); } last_rxf = rxf; last_rxf_dma = sp->rx_ring_dma[i]; @@ -1316,21 +1336,21 @@ /* This field unused by i82557. */ rxf->rx_buf_addr = 0xffffffff; rxf->count = cpu_to_le32(PKT_BUF_SZ << 16); - pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[i], - sizeof(struct RxFD), PCI_DMA_TODEVICE); + pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[i], + sizeof(struct RxFD), PCI_DMA_TODEVICE); } sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); /* Mark the last entry as end-of-list. */ last_rxf->status = cpu_to_le32(0xC0000002); /* '2' is flag value only. */ - pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[RX_RING_SIZE-1], - sizeof(struct RxFD), PCI_DMA_TODEVICE); + pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[RX_RING_SIZE-1], + sizeof(struct RxFD), PCI_DMA_TODEVICE); sp->last_rxf = last_rxf; sp->last_rxf_dma = last_rxf_dma; } static void speedo_purge_tx(struct net_device *dev) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); int entry; while ((int)(sp->cur_tx - sp->dirty_tx) > 0) { @@ -1362,7 +1382,7 @@ static void reset_mii(struct net_device *dev) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); /* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */ if ((sp->phy[0] & 0x8000) == 0) { @@ -1385,7 +1405,7 @@ static void speedo_tx_timeout(struct net_device *dev) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); long ioaddr = dev->base_addr; int status = inw(ioaddr + SCBStatus); unsigned long flags; @@ -1447,7 +1467,7 @@ static int speedo_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); long ioaddr = dev->base_addr; int entry; @@ -1518,7 +1538,7 @@ static void speedo_tx_buffer_gc(struct net_device *dev) { unsigned int dirty_tx; - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); dirty_tx = sp->dirty_tx; while ((int)(sp->cur_tx - dirty_tx) > 0) { @@ -1585,7 +1605,7 @@ unsigned int handled = 0; ioaddr = dev->base_addr; - sp = (struct speedo_private *)dev->priv; + sp = netdev_priv(dev); #ifndef final_version /* A lock to prevent simultaneous entry on SMP machines. */ @@ -1677,7 +1697,7 @@ static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); struct RxFD *rxf; struct sk_buff *skb; /* Get a fresh skbuff to replace the consumed one. */ @@ -1696,29 +1716,29 @@ skb->dev = dev; skb_reserve(skb, sizeof(struct RxFD)); rxf->rx_buf_addr = 0xffffffff; - pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry], - sizeof(struct RxFD), PCI_DMA_TODEVICE); + pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[entry], + sizeof(struct RxFD), PCI_DMA_TODEVICE); return rxf; } static inline void speedo_rx_link(struct net_device *dev, int entry, struct RxFD *rxf, dma_addr_t rxf_dma) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); rxf->status = cpu_to_le32(0xC0000001); /* '1' for driver use only. */ rxf->link = 0; /* None yet. */ rxf->count = cpu_to_le32(PKT_BUF_SZ << 16); sp->last_rxf->link = cpu_to_le32(rxf_dma); sp->last_rxf->status &= cpu_to_le32(~0xC0000000); - pci_dma_sync_single(sp->pdev, sp->last_rxf_dma, - sizeof(struct RxFD), PCI_DMA_TODEVICE); + pci_dma_sync_single_for_device(sp->pdev, sp->last_rxf_dma, + sizeof(struct RxFD), PCI_DMA_TODEVICE); sp->last_rxf = rxf; sp->last_rxf_dma = rxf_dma; } static int speedo_refill_rx_buf(struct net_device *dev, int force) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); int entry; struct RxFD *rxf; @@ -1760,7 +1780,7 @@ static void speedo_refill_rx_buffers(struct net_device *dev, int force) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); /* Refill the RX ring. */ while ((int)(sp->cur_rx - sp->dirty_rx) > 0 && @@ -1770,7 +1790,7 @@ static int speedo_rx(struct net_device *dev) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); int entry = sp->cur_rx % RX_RING_SIZE; int rx_work_limit = sp->dirty_rx + RX_RING_SIZE - sp->cur_rx; int alloc_ok = 1; @@ -1783,8 +1803,8 @@ int status; int pkt_len; - pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry], - sizeof(struct RxFD), PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(sp->pdev, sp->rx_ring_dma[entry], + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); status = le32_to_cpu(sp->rx_ringp[entry]->status); pkt_len = le32_to_cpu(sp->rx_ringp[entry]->count) & 0x3fff; @@ -1830,8 +1850,9 @@ skb->dev = dev; skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ /* 'skb_put()' points to the start of sk_buff data area. */ - pci_dma_sync_single(sp->pdev, sp->rx_ring_dma[entry], - sizeof(struct RxFD) + pkt_len, PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(sp->pdev, sp->rx_ring_dma[entry], + sizeof(struct RxFD) + pkt_len, + PCI_DMA_FROMDEVICE); #if 1 || USE_IP_CSUM /* Packet is in one chunk -- we can copy + cksum. */ @@ -1841,6 +1862,9 @@ memcpy(skb_put(skb, pkt_len), sp->rx_skbuff[entry]->tail, pkt_len); #endif + pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[entry], + sizeof(struct RxFD) + pkt_len, + PCI_DMA_FROMDEVICE); npkts++; } else { /* Pass up the already-filled skbuff. */ @@ -1855,7 +1879,8 @@ npkts++; sp->rx_ringp[entry] = NULL; pci_unmap_single(sp->pdev, sp->rx_ring_dma[entry], - PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); + PKT_BUF_SZ + sizeof(struct RxFD), + PCI_DMA_FROMDEVICE); } skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); @@ -1884,7 +1909,7 @@ speedo_close(struct net_device *dev) { long ioaddr = dev->base_addr; - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); int i; netdevice_stop(dev); @@ -1962,7 +1987,7 @@ static struct net_device_stats * speedo_get_stats(struct net_device *dev) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); long ioaddr = dev->base_addr; /* Update only if the previous dump finished. */ @@ -1995,7 +2020,7 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) { u32 ethcmd; - struct speedo_private *sp = dev->priv; + struct speedo_private *sp = netdev_priv(dev); if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) return -EFAULT; @@ -2070,7 +2095,7 @@ static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); struct mii_ioctl_data *data = (struct mii_ioctl_data *)&rq->ifr_data; int phy = sp->phy[0] & 0x1f; int saved_acpi; @@ -2121,7 +2146,7 @@ */ static void set_rx_mode(struct net_device *dev) { - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); long ioaddr = dev->base_addr; struct descriptor *last_cmd; char new_rx_mode; @@ -2287,8 +2312,8 @@ mc_setup_frm->link = cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE)); - pci_dma_sync_single(sp->pdev, mc_blk->frame_dma, - mc_blk->len, PCI_DMA_TODEVICE); + pci_dma_sync_single_for_device(sp->pdev, mc_blk->frame_dma, + mc_blk->len, PCI_DMA_TODEVICE); wait_for_cmd_done(dev); clear_suspend(last_cmd); @@ -2313,7 +2338,7 @@ static int eepro100_suspend(struct pci_dev *pdev, u32 state) { struct net_device *dev = pci_get_drvdata (pdev); - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); long ioaddr = dev->base_addr; pci_save_state(pdev, sp->pm_state); @@ -2333,7 +2358,7 @@ static int eepro100_resume(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata (pdev); - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); long ioaddr = dev->base_addr; pci_restore_state(pdev, sp->pm_state); @@ -2363,7 +2388,7 @@ static void __devexit eepro100_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata (pdev); - struct speedo_private *sp = (struct speedo_private *)dev->priv; + struct speedo_private *sp = netdev_priv(dev); unregister_netdev(dev); diff -Nru a/drivers/net/eexpress.c b/drivers/net/eexpress.c --- a/drivers/net/eexpress.c Sun Mar 14 14:20:05 2004 +++ b/drivers/net/eexpress.c Sun Mar 14 14:20:05 2004 @@ -452,7 +452,7 @@ { int ret; unsigned short ioaddr = dev->base_addr; - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); #if NET_DEBUG > 6 printk(KERN_DEBUG "%s: eexp_open()\n", dev->name); @@ -515,7 +515,7 @@ static int eexp_close(struct net_device *dev) { unsigned short ioaddr = dev->base_addr; - struct net_local *lp = dev->priv; + struct net_local *lp = netdev_priv(dev); int irq = dev->irq; @@ -541,7 +541,7 @@ static struct net_device_stats *eexp_stats(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); return &lp->stats; } @@ -553,7 +553,7 @@ static void unstick_cu(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned short ioaddr = dev->base_addr; if (lp->started) @@ -627,7 +627,7 @@ static void eexp_timeout(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); #ifdef CONFIG_SMP unsigned long flags; #endif @@ -667,7 +667,7 @@ */ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); short length = buf->len; #ifdef CONFIG_SMP unsigned long flags; @@ -728,7 +728,7 @@ unsigned short status) { unsigned short ack_cmd = SCB_ack(status); - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned short ioaddr = dev->base_addr; if ((dev->flags & IFF_UP) && !(lp->started & STARTED_CU)) { short diag_status, tdr_status; @@ -806,7 +806,7 @@ return IRQ_NONE; } - lp = (struct net_local *)dev->priv; + lp = netdev_priv(dev); ioaddr = dev->base_addr; spin_lock(&lp->lock); @@ -925,7 +925,7 @@ static void eexp_hw_rx_pio(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned short rx_block = lp->rx_ptr; unsigned short boguscount = lp->num_rx_bufs; unsigned short ioaddr = dev->base_addr; @@ -1022,7 +1022,7 @@ static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf, unsigned short len) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned short ioaddr = dev->base_addr; if (LOCKUP16 || lp->width) { @@ -1090,7 +1090,7 @@ unsigned int memory_size; int i; unsigned short xsum = 0; - struct net_local *lp = dev->priv; + struct net_local *lp = netdev_priv(dev); printk("%s: EtherExpress 16 at %#x ",dev->name,ioaddr); @@ -1262,7 +1262,7 @@ static unsigned short eexp_hw_lasttxstat(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned short tx_block = lp->tx_reap; unsigned short status; @@ -1332,7 +1332,7 @@ static void eexp_hw_txrestart(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned short ioaddr = dev->base_addr; lp->last_tx_restart = lp->tx_link; @@ -1377,7 +1377,7 @@ static void eexp_hw_txinit(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned short tx_block = TX_BUF_START; unsigned short curtbuf; unsigned short ioaddr = dev->base_addr; @@ -1419,7 +1419,7 @@ static void eexp_hw_rxinit(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned short rx_block = lp->rx_buf_start; unsigned short ioaddr = dev->base_addr; @@ -1478,7 +1478,7 @@ static void eexp_hw_init586(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned short ioaddr = dev->base_addr; int i; @@ -1639,7 +1639,7 @@ eexp_set_multicast(struct net_device *dev) { unsigned short ioaddr = dev->base_addr; - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int kick = 0, i; if ((dev->flags & IFF_PROMISC) != lp->was_promisc) { outw(CONF_PROMISC & ~31, ioaddr+SM_PTR); diff -Nru a/drivers/net/epic100.c b/drivers/net/epic100.c --- a/drivers/net/epic100.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/epic100.c Sun Mar 14 14:20:07 2004 @@ -1199,8 +1199,6 @@ short pkt_len = (status >> 16) - 4; struct sk_buff *skb; - pci_dma_sync_single(ep->pci_dev, ep->rx_ring[entry].bufaddr, - ep->rx_buf_sz, PCI_DMA_FROMDEVICE); if (pkt_len > PKT_BUF_SZ - 4) { printk(KERN_ERR "%s: Oversized Ethernet frame, status %x " "%d bytes.\n", @@ -1213,6 +1211,10 @@ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ + pci_dma_sync_single_for_cpu(ep->pci_dev, + ep->rx_ring[entry].bufaddr, + ep->rx_buf_sz, + PCI_DMA_FROMDEVICE); #if 1 /* HAS_IP_COPYSUM */ eth_copy_and_sum(skb, ep->rx_skbuff[entry]->tail, pkt_len, 0); skb_put(skb, pkt_len); @@ -1220,6 +1222,10 @@ memcpy(skb_put(skb, pkt_len), ep->rx_skbuff[entry]->tail, pkt_len); #endif + pci_dma_sync_single_for_device(ep->pci_dev, + ep->rx_ring[entry].bufaddr, + ep->rx_buf_sz, + PCI_DMA_FROMDEVICE); } else { pci_unmap_single(ep->pci_dev, ep->rx_ring[entry].bufaddr, diff -Nru a/drivers/net/es3210.c b/drivers/net/es3210.c --- a/drivers/net/es3210.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/es3210.c Sun Mar 14 14:20:08 2004 @@ -298,6 +298,9 @@ dev->open = &es_open; dev->stop = &es_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; out1: diff -Nru a/drivers/net/eth16i.c b/drivers/net/eth16i.c --- a/drivers/net/eth16i.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/eth16i.c Sun Mar 14 14:20:08 2004 @@ -486,7 +486,7 @@ static int __init eth16i_probe1(struct net_device *dev, int ioaddr) { - struct eth16i_local *lp = dev->priv; + struct eth16i_local *lp = netdev_priv(dev); static unsigned version_printed; int retval; @@ -950,7 +950,7 @@ static int eth16i_open(struct net_device *dev) { - struct eth16i_local *lp = (struct eth16i_local *)dev->priv; + struct eth16i_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; /* Powerup the chip */ @@ -986,7 +986,7 @@ static int eth16i_close(struct net_device *dev) { - struct eth16i_local *lp = (struct eth16i_local *)dev->priv; + struct eth16i_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; eth16i_reset(dev); @@ -1012,7 +1012,7 @@ static void eth16i_timeout(struct net_device *dev) { - struct eth16i_local *lp = (struct eth16i_local *)dev->priv; + struct eth16i_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; /* If we get here, some higher level has decided that @@ -1053,7 +1053,7 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev) { - struct eth16i_local *lp = (struct eth16i_local *)dev->priv; + struct eth16i_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int status = 0; ushort length = skb->len; @@ -1130,7 +1130,7 @@ static void eth16i_rx(struct net_device *dev) { - struct eth16i_local *lp = (struct eth16i_local *)dev->priv; + struct eth16i_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int boguscount = MAX_RX_LOOP; @@ -1232,7 +1232,7 @@ int handled = 0; ioaddr = dev->base_addr; - lp = (struct eth16i_local *)dev->priv; + lp = netdev_priv(dev); /* Turn off all interrupts from adapter */ outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG); @@ -1340,7 +1340,7 @@ static void eth16i_reset(struct net_device *dev) { - struct eth16i_local *lp = (struct eth16i_local *)dev->priv; + struct eth16i_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; if(eth16i_debug > 1) @@ -1372,7 +1372,7 @@ static struct net_device_stats *eth16i_get_stats(struct net_device *dev) { - struct eth16i_local *lp = (struct eth16i_local *)dev->priv; + struct eth16i_local *lp = netdev_priv(dev); return &lp->stats; } diff -Nru a/drivers/net/ethertap.c b/drivers/net/ethertap.c --- a/drivers/net/ethertap.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/ethertap.c Sun Mar 14 14:20:06 2004 @@ -121,7 +121,7 @@ static int ethertap_open(struct net_device *dev) { - struct net_local *lp = (struct net_local*)dev->priv; + struct net_local *lp = netdev_priv(dev); if (ethertap_debug > 2) printk(KERN_DEBUG "%s: Doing ethertap_open()...", dev->name); @@ -150,7 +150,7 @@ static void set_multicast_list(struct net_device *dev) { unsigned groups = ~0; - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if (!(dev->flags&(IFF_NOARP|IFF_PROMISC|IFF_ALLMULTI))) { struct dev_mc_list *dmi; @@ -176,7 +176,7 @@ static int ethertap_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); #ifdef CONFIG_ETHERTAP_MC struct ethhdr *eth = (struct ethhdr*)skb->data; #endif @@ -234,7 +234,7 @@ static __inline__ int ethertap_rx_skb(struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); #ifdef CONFIG_ETHERTAP_MC struct ethhdr *eth = (struct ethhdr*)(skb->data + 2); #endif @@ -320,7 +320,7 @@ static int ethertap_close(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); struct sock *sk = lp->nl; if (ethertap_debug > 2) @@ -338,7 +338,7 @@ static struct net_device_stats *ethertap_get_stats(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); return &lp->stats; } diff -Nru a/drivers/net/fc/iph5526.c b/drivers/net/fc/iph5526.c --- a/drivers/net/fc/iph5526.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/fc/iph5526.c Sun Mar 14 14:20:06 2004 @@ -238,7 +238,7 @@ static int __init iph5526_probe_pci(struct net_device *dev) { - struct fc_info *fi = (struct fc_info *)dev->priv; + struct fc_info *fi = netdev_priv(dev); fi->dev = dev; dev->base_addr = fi->base_addr; dev->irq = fi->irq; @@ -2908,7 +2908,7 @@ static void iph5526_timeout(struct net_device *dev) { - struct fc_info *fi = (struct fc_info*)dev->priv; + struct fc_info *fi = netdev_priv(dev); printk(KERN_WARNING "%s: timed out on send.\n", dev->name); fi->fc_stats.rx_dropped++; dev->trans_start = jiffies; @@ -2917,7 +2917,7 @@ static int iph5526_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct fc_info *fi = (struct fc_info*)dev->priv; + struct fc_info *fi = netdev_priv(dev); int status = 0; short type = 0; u_long flags; @@ -3688,7 +3688,7 @@ static struct net_device_stats * iph5526_get_stats(struct net_device *dev) { -struct fc_info *fi = (struct fc_info*)dev->priv; +struct fc_info *fi = netdev_priv(dev); return (struct net_device_stats *) &fi->fc_stats; } diff -Nru a/drivers/net/fealnx.c b/drivers/net/fealnx.c --- a/drivers/net/fealnx.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/fealnx.c Sun Mar 14 14:20:07 2004 @@ -1647,10 +1647,6 @@ printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d" " status %x.\n", pkt_len, rx_status); #endif - pci_dma_sync_single(np->pci_dev, np->cur_rx->buffer, - np->rx_buf_sz, PCI_DMA_FROMDEVICE); - pci_unmap_single(np->pci_dev, np->cur_rx->buffer, - np->rx_buf_sz, PCI_DMA_FROMDEVICE); /* Check if the packet is long enough to accept without copying to a minimally-sized skbuff. */ @@ -1658,6 +1654,10 @@ (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ + pci_dma_sync_single_for_cpu(np->pci_dev, + np->cur_rx->buffer, + np->rx_buf_sz, + PCI_DMA_FROMDEVICE); /* Call copy + cksum if available. */ #if ! defined(__alpha__) @@ -1668,7 +1668,15 @@ memcpy(skb_put(skb, pkt_len), np->cur_rx->skbuff->tail, pkt_len); #endif + pci_dma_sync_single_for_device(np->pci_dev, + np->cur_rx->buffer, + np->rx_buf_sz, + PCI_DMA_FROMDEVICE); } else { + pci_unmap_single(np->pci_dev, + np->cur_rx->buffer, + np->rx_buf_sz, + PCI_DMA_FROMDEVICE); skb_put(skb = np->cur_rx->skbuff, pkt_len); np->cur_rx->skbuff = NULL; if (np->really_rx_count == RX_RING_SIZE) @@ -1689,8 +1697,10 @@ if (skb != NULL) { skb->dev = dev; /* Mark as being used by this device. */ - np->cur_rx->buffer = pci_map_single(np->pci_dev, skb->tail, - np->rx_buf_sz, PCI_DMA_FROMDEVICE); + np->cur_rx->buffer = pci_map_single(np->pci_dev, + skb->tail, + np->rx_buf_sz, + PCI_DMA_FROMDEVICE); np->cur_rx->skbuff = skb; ++np->really_rx_count; } diff -Nru a/drivers/net/fec.c b/drivers/net/fec.c --- a/drivers/net/fec.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/fec.c Sun Mar 14 14:20:06 2004 @@ -269,7 +269,7 @@ volatile fec_t *fecp; volatile cbd_t *bdp; - fep = dev->priv; + fep = netdev_priv(dev); fecp = (volatile fec_t*)dev->base_addr; if (!fep->link) { @@ -349,7 +349,7 @@ static void fec_timeout(struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); printk("%s: transmit timed out.\n", dev->name); fep->stats.tx_errors++; @@ -445,7 +445,7 @@ volatile cbd_t *bdp; struct sk_buff *skb; - fep = dev->priv; + fep = netdev_priv(dev); spin_lock(&fep->lock); bdp = fep->dirty_tx; @@ -524,7 +524,7 @@ ushort pkt_len; __u8 *data; - fep = dev->priv; + fep = netdev_priv(dev); fecp = (volatile fec_t*)dev->base_addr; /* First, grab all of the stats for the incoming packet. @@ -645,7 +645,7 @@ mii_list_t *mip; uint mii_reg; - fep = (struct fec_enet_private *)dev->priv; + fep = netdev_priv(dev); ep = fec_hwp; mii_reg = ep->fec_mii_data; @@ -675,7 +675,7 @@ /* Add PHY address to register command. */ - fep = dev->priv; + fep = netdev_priv(dev); regval |= fep->phy_addr << 23; retval = 0; @@ -720,7 +720,7 @@ static void mii_parse_sr(uint mii_reg, struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); *s &= ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC); @@ -735,7 +735,7 @@ static void mii_parse_cr(uint mii_reg, struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); *s &= ~(PHY_CONF_ANE | PHY_CONF_LOOP); @@ -748,7 +748,7 @@ static void mii_parse_anar(uint mii_reg, struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); *s &= ~(PHY_CONF_SPMASK); @@ -774,7 +774,7 @@ static void mii_parse_lxt970_csr(uint mii_reg, struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); *s &= ~(PHY_STAT_SPMASK); @@ -841,7 +841,7 @@ static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); *s &= ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC); @@ -919,7 +919,7 @@ static void mii_parse_qs6612_pcr(uint mii_reg, struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); *s &= ~(PHY_STAT_SPMASK); @@ -983,7 +983,7 @@ static void mii_parse_am79c874_dr(uint mii_reg, struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); *s &= ~(PHY_STAT_SPMASK | PHY_STAT_ANC); @@ -1280,7 +1280,7 @@ static void mii_display_status(struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); if (!fep->link && !fep->old_link) { @@ -1316,7 +1316,7 @@ static void mii_display_config(struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); printk("%s: config: auto-negotiation ", dev->name); @@ -1347,7 +1347,7 @@ static void mii_relink(struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); int duplex; fep->link = (fep->phy_status & PHY_STAT_LINK) ? 1 : 0; @@ -1372,7 +1372,7 @@ static void mii_queue_relink(uint mii_reg, struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); INIT_WORK(&fep->phy_task, (void*)mii_relink, dev); schedule_work(&fep->phy_task); @@ -1380,7 +1380,7 @@ static void mii_queue_config(uint mii_reg, struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); INIT_WORK(&fep->phy_task, (void*)mii_display_config, dev); schedule_work(&fep->phy_task); @@ -1403,7 +1403,7 @@ struct fec_enet_private *fep; int i; - fep = dev->priv; + fep = netdev_priv(dev); fep->phy_id |= (mii_reg & 0xffff); printk("fec: PHY @ 0x%x, ID 0x%08x", fep->phy_addr, fep->phy_id); @@ -1431,7 +1431,7 @@ volatile fec_t *fecp; uint phytype; - fep = dev->priv; + fep = netdev_priv(dev); fecp = fec_hwp; if (fep->phy_addr < 32) { @@ -1466,7 +1466,7 @@ #endif { struct net_device *dev = dev_id; - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); fec_phy_ack_intr(); @@ -1482,7 +1482,7 @@ static int fec_enet_open(struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); /* I should reset the ring buffers here, but I don't yet know * a simple way to do that. @@ -1531,7 +1531,7 @@ static struct net_device_stats *fec_enet_get_stats(struct net_device *dev) { - struct fec_enet_private *fep = (struct fec_enet_private *)dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); return &fep->stats; } @@ -1557,7 +1557,7 @@ unsigned int i, j, bit, data, crc; unsigned char hash; - fep = (struct fec_enet_private *)dev->priv; + fep = netdev_priv(dev); ep = fec_hwp; if (dev->flags&IFF_PROMISC) { @@ -1643,7 +1643,7 @@ */ int __init fec_enet_init(struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); unsigned long mem_addr; volatile cbd_t *bdp; cbd_t *cbd_base; @@ -1807,7 +1807,7 @@ fecp = fec_hwp; - fep = dev->priv; + fep = netdev_priv(dev); /* Whack a reset. We should wait for this. */ @@ -1924,7 +1924,7 @@ struct fec_enet_private *fep; fecp = fec_hwp; - fep = dev->priv; + fep = netdev_priv(dev); fecp->fec_x_cntrl = 0x01; /* Graceful transmit stop */ diff -Nru a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c --- a/drivers/net/forcedeth.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/forcedeth.c Sun Mar 14 14:20:06 2004 @@ -11,6 +11,7 @@ * countries. * * Copyright (C) 2003 Manfred Spraul + * Copyright (C) 2004 Andrew de Quincey (wol support) * * 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 @@ -28,7 +29,7 @@ * * Changelog: * 0.01: 05 Oct 2003: First release that compiles without warnings. - * 0.02: 05 Oct 2003: Fix bug for drain_tx: do not try to free NULL skbs. + * 0.02: 05 Oct 2003: Fix bug for nv_drain_tx: do not try to free NULL skbs. * Check all PCI BARs for the register window. * udelay added to mii_rw. * 0.03: 06 Oct 2003: Initialize dev->irq. @@ -37,7 +38,7 @@ * 0.06: 10 Oct 2003: MAC Address read updated, pff flag generation updated, * irq mask updated * 0.07: 14 Oct 2003: Further irq mask updates. - * 0.08: 20 Oct 2003: rx_desc.Length initialization added, alloc_rx refill + * 0.08: 20 Oct 2003: rx_desc.Length initialization added, nv_alloc_rx refill * added into irq handler, NULL check for drain_ring. * 0.09: 20 Oct 2003: Basic link speed irq implementation. Only handle the * requested interrupt sources. @@ -47,7 +48,7 @@ * 0.12: 23 Oct 2003: Cleanups for release. * 0.13: 25 Oct 2003: Limit for concurrent tx packets increased to 10. * Set link speed correctly. start rx before starting - * tx (start_rx sets the link speed). + * tx (nv_start_rx sets the link speed). * 0.14: 25 Oct 2003: Nic dependant irq mask. * 0.15: 08 Nov 2003: fix smp deadlock with set_multicast_list during * open. @@ -58,7 +59,7 @@ * 0.18: 17 Nov 2003: fix oops due to late initialization of dev_stats * 0.19: 29 Nov 2003: Handle RxNoBuf, detect & handle invalid mac * addresses, really stop rx if already running - * in start_rx, clean up a bit. + * in nv_start_rx, clean up a bit. * (C) Carl-Daniel Hailfinger * 0.20: 07 Dec 2003: alloc fixes * 0.21: 12 Jan 2004: additional alloc fix, nic polling fix. @@ -66,6 +67,8 @@ * on close. * (C) Carl-Daniel Hailfinger, Manfred Spraul * 0.23: 26 Jan 2004: various small cleanups + * 0.24: 27 Feb 2004: make driver even less anonymous in backtraces + * 0.25: 09 Mar 2004: wol support * * Known bugs: * We suspect that on some hardware no TX done interrupts are generated. @@ -77,7 +80,7 @@ * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few * superfluous timer interrupts from the nic. */ -#define FORCEDETH_VERSION "0.23" +#define FORCEDETH_VERSION "0.25" #include #include @@ -232,6 +235,7 @@ #define NVREG_WAKEUPFLAGS_ACCEPT_MAGPAT 0x01 #define NVREG_WAKEUPFLAGS_ACCEPT_WAKEUPPAT 0x02 #define NVREG_WAKEUPFLAGS_ACCEPT_LINKCHANGE 0x04 +#define NVREG_WAKEUPFLAGS_ENABLE 0x1111 NvRegPatternCRC = 0x204, NvRegPatternMask = 0x208, @@ -340,6 +344,7 @@ u32 linkspeed; int duplex; int phyaddr; + int wolenabled; /* General data: RO fields */ dma_addr_t ring_addr; @@ -468,12 +473,12 @@ return retval; } -static void start_rx(struct net_device *dev) +static void nv_start_rx(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); u8 *base = get_hwbase(dev); - dprintk(KERN_DEBUG "%s: start_rx\n", dev->name); + dprintk(KERN_DEBUG "%s: nv_start_rx\n", dev->name); /* Already running? Stop it. */ if (readl(base + NvRegReceiverControl) & NVREG_RCVCTL_START) { writel(0, base + NvRegReceiverControl); @@ -485,48 +490,48 @@ pci_push(base); } -static void stop_rx(struct net_device *dev) +static void nv_stop_rx(struct net_device *dev) { u8 *base = get_hwbase(dev); - dprintk(KERN_DEBUG "%s: stop_rx\n", dev->name); + dprintk(KERN_DEBUG "%s: nv_stop_rx\n", dev->name); writel(0, base + NvRegReceiverControl); reg_delay(dev, NvRegReceiverStatus, NVREG_RCVSTAT_BUSY, 0, NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX, - KERN_INFO "stop_rx: ReceiverStatus remained busy"); + KERN_INFO "nv_stop_rx: ReceiverStatus remained busy"); udelay(NV_RXSTOP_DELAY2); writel(0, base + NvRegLinkSpeed); } -static void start_tx(struct net_device *dev) +static void nv_start_tx(struct net_device *dev) { u8 *base = get_hwbase(dev); - dprintk(KERN_DEBUG "%s: start_tx\n", dev->name); + dprintk(KERN_DEBUG "%s: nv_start_tx\n", dev->name); writel(NVREG_XMITCTL_START, base + NvRegTransmitterControl); pci_push(base); } -static void stop_tx(struct net_device *dev) +static void nv_stop_tx(struct net_device *dev) { u8 *base = get_hwbase(dev); - dprintk(KERN_DEBUG "%s: stop_tx\n", dev->name); + dprintk(KERN_DEBUG "%s: nv_stop_tx\n", dev->name); writel(0, base + NvRegTransmitterControl); reg_delay(dev, NvRegTransmitterStatus, NVREG_XMITSTAT_BUSY, 0, NV_TXSTOP_DELAY1, NV_TXSTOP_DELAY1MAX, - KERN_INFO "stop_tx: TransmitterStatus remained busy"); + KERN_INFO "nv_stop_tx: TransmitterStatus remained busy"); udelay(NV_TXSTOP_DELAY2); writel(0, base + NvRegUnknownTransmitterReg); } -static void txrx_reset(struct net_device *dev) +static void nv_txrx_reset(struct net_device *dev) { u8 *base = get_hwbase(dev); - dprintk(KERN_DEBUG "%s: txrx_reset\n", dev->name); + dprintk(KERN_DEBUG "%s: nv_txrx_reset\n", dev->name); writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET, base + NvRegTxRxControl); pci_push(base); udelay(NV_TXRX_RESET_DELAY); @@ -551,9 +556,10 @@ return &np->stats; } -static int nv_ethtool_ioctl (struct net_device *dev, void *useraddr) +static int nv_ethtool_ioctl(struct net_device *dev, void *useraddr) { struct fe_priv *np = get_nvpriv(dev); + u8 *base = get_hwbase(dev); u32 ethcmd; if (copy_from_user(ðcmd, useraddr, sizeof (ethcmd))) @@ -580,6 +586,39 @@ return -EFAULT; return 0; } + case ETHTOOL_GWOL: + { + struct ethtool_wolinfo wolinfo; + memset(&wolinfo, 0, sizeof(wolinfo)); + wolinfo.supported = WAKE_MAGIC; + + spin_lock_irq(&np->lock); + if (np->wolenabled) + wolinfo.wolopts = WAKE_MAGIC; + spin_unlock_irq(&np->lock); + + if (copy_to_user(useraddr, &wolinfo, sizeof(wolinfo))) + return -EFAULT; + return 0; + } + case ETHTOOL_SWOL: + { + struct ethtool_wolinfo wolinfo; + if (copy_from_user(&wolinfo, useraddr, sizeof(wolinfo))) + return -EFAULT; + + spin_lock_irq(&np->lock); + if (wolinfo.wolopts == 0) { + writel(0, base + NvRegWakeUpFlags); + np->wolenabled = 0; + } + if (wolinfo.wolopts & WAKE_MAGIC) { + writel(NVREG_WAKEUPFLAGS_ENABLE, base + NvRegWakeUpFlags); + np->wolenabled = 1; + } + spin_unlock_irq(&np->lock); + return 0; + } default: break; @@ -603,11 +642,11 @@ } /* - * alloc_rx: fill rx ring entries. + * nv_alloc_rx: fill rx ring entries. * Return 1 if the allocations for the skbs failed and the * rx engine is without Available descriptors */ -static int alloc_rx(struct net_device *dev) +static int nv_alloc_rx(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); unsigned int refill_rx = np->refill_rx; @@ -633,7 +672,7 @@ np->rx_ring[nr].Length = cpu_to_le16(RX_NIC_BUFSIZE); wmb(); np->rx_ring[nr].Flags = cpu_to_le16(NV_RX_AVAIL); - dprintk(KERN_DEBUG "%s: alloc_rx: Packet %d marked as Available\n", + dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n", dev->name, refill_rx); refill_rx++; } @@ -643,13 +682,13 @@ return 0; } -static void do_rx_refill(unsigned long data) +static void nv_do_rx_refill(unsigned long data) { struct net_device *dev = (struct net_device *) data; struct fe_priv *np = get_nvpriv(dev); disable_irq(dev->irq); - if (alloc_rx(dev)) { + if (nv_alloc_rx(dev)) { spin_lock(&np->lock); if (!np->in_shutdown) mod_timer(&np->oom_kick, jiffies + OOM_REFILL); @@ -658,7 +697,7 @@ enable_irq(dev->irq); } -static int init_ring(struct net_device *dev) +static int nv_init_ring(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); int i; @@ -673,10 +712,10 @@ for (i = 0; i < RX_RING; i++) { np->rx_ring[i].Flags = 0; } - return alloc_rx(dev); + return nv_alloc_rx(dev); } -static void drain_tx(struct net_device *dev) +static void nv_drain_tx(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); int i; @@ -693,7 +732,7 @@ } } -static void drain_rx(struct net_device *dev) +static void nv_drain_rx(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); int i; @@ -712,8 +751,8 @@ static void drain_ring(struct net_device *dev) { - drain_tx(dev); - drain_rx(dev); + nv_drain_tx(dev); + nv_drain_rx(dev); } /* @@ -759,11 +798,11 @@ } /* - * tx_done: check for completed packets, release the skbs. + * nv_tx_done: check for completed packets, release the skbs. * * Caller must own np->lock. */ -static void tx_done(struct net_device *dev) +static void nv_tx_done(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); @@ -773,7 +812,7 @@ prd = &np->tx_ring[i]; - dprintk(KERN_DEBUG "%s: tx_done: looking at packet %d, Flags 0x%x.\n", + dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, Flags 0x%x.\n", dev->name, np->nic_tx, prd->Flags); if (prd->Flags & cpu_to_le16(NV_TX_VALID)) break; @@ -814,26 +853,26 @@ spin_lock_irq(&np->lock); /* 1) stop tx engine */ - stop_tx(dev); + nv_stop_tx(dev); /* 2) check that the packets were not sent already: */ - tx_done(dev); + nv_tx_done(dev); /* 3) if there are dead entries: clear everything */ if (np->next_tx != np->nic_tx) { printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name); - drain_tx(dev); + nv_drain_tx(dev); np->next_tx = np->nic_tx = 0; writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); netif_wake_queue(dev); } /* 4) restart tx engine */ - start_tx(dev); + nv_start_tx(dev); spin_unlock_irq(&np->lock); } -static void rx_process(struct net_device *dev) +static void nv_rx_process(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); @@ -847,7 +886,7 @@ i = np->cur_rx % RX_RING; prd = &np->rx_ring[i]; - dprintk(KERN_DEBUG "%s: rx_process: looking at packet %d, Flags 0x%x.\n", + dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, Flags 0x%x.\n", dev->name, np->cur_rx, prd->Flags); if (prd->Flags & cpu_to_le16(NV_RX_AVAIL)) @@ -915,7 +954,7 @@ skb_put(skb, len); skb->protocol = eth_type_trans(skb, dev); - dprintk(KERN_DEBUG "%s: rx_process: packet %d with %d bytes, proto %d accepted.\n", + dprintk(KERN_DEBUG "%s: nv_rx_process: packet %d with %d bytes, proto %d accepted.\n", dev->name, np->cur_rx, len, skb->protocol); netif_rx(skb); dev->last_rx = jiffies; @@ -990,24 +1029,24 @@ addr[0] |= NVREG_MCASTADDRA_FORCE; pff |= NVREG_PFF_ALWAYS; spin_lock_irq(&np->lock); - stop_rx(dev); + nv_stop_rx(dev); writel(addr[0], base + NvRegMulticastAddrA); writel(addr[1], base + NvRegMulticastAddrB); writel(mask[0], base + NvRegMulticastMaskA); writel(mask[1], base + NvRegMulticastMaskB); writel(pff, base + NvRegPacketFilterFlags); - start_rx(dev); + nv_start_rx(dev); spin_unlock_irq(&np->lock); } -static int update_linkspeed(struct net_device *dev) +static int nv_update_linkspeed(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); int adv, lpa, newls, newdup; adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); lpa = mii_rw(dev, np->phyaddr, MII_LPA, MII_READ); - dprintk(KERN_DEBUG "%s: update_linkspeed: PHY advertises 0x%04x, lpa 0x%04x.\n", + dprintk(KERN_DEBUG "%s: nv_update_linkspeed: PHY advertises 0x%04x, lpa 0x%04x.\n", dev->name, adv, lpa); /* FIXME: handle parallel detection properly, handle gigabit ethernet */ @@ -1037,7 +1076,7 @@ return 0; } -static void link_irq(struct net_device *dev) +static void nv_link_irq(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); u8 *base = get_hwbase(dev); @@ -1050,29 +1089,29 @@ miival = mii_rw(dev, np->phyaddr, MII_BMSR, MII_READ); if (miival & BMSR_ANEGCOMPLETE) { - update_linkspeed(dev); + nv_update_linkspeed(dev); if (netif_carrier_ok(dev)) { - stop_rx(dev); + nv_stop_rx(dev); } else { netif_carrier_on(dev); printk(KERN_INFO "%s: link up.\n", dev->name); } writel(NVREG_MISC1_FORCE | ( np->duplex ? 0 : NVREG_MISC1_HD), base + NvRegMisc1); - start_rx(dev); + nv_start_rx(dev); } else { if (netif_carrier_ok(dev)) { netif_carrier_off(dev); printk(KERN_INFO "%s: link down.\n", dev->name); - stop_rx(dev); + nv_stop_rx(dev); } writel(np->linkspeed, base + NvRegLinkSpeed); pci_push(base); } } -static irqreturn_t nic_irq(int foo, void *data, struct pt_regs *regs) +static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) data; struct fe_priv *np = get_nvpriv(dev); @@ -1080,7 +1119,7 @@ u32 events; int i; - dprintk(KERN_DEBUG "%s: nic_irq\n", dev->name); + dprintk(KERN_DEBUG "%s: nv_nic_irq\n", dev->name); for (i=0; ; i++) { events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK; @@ -1092,13 +1131,13 @@ if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX2|NVREG_IRQ_TX_ERR)) { spin_lock(&np->lock); - tx_done(dev); + nv_tx_done(dev); spin_unlock(&np->lock); } if (events & (NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF)) { - rx_process(dev); - if (alloc_rx(dev)) { + nv_rx_process(dev); + if (nv_alloc_rx(dev)) { spin_lock(&np->lock); if (!np->in_shutdown) mod_timer(&np->oom_kick, jiffies + OOM_REFILL); @@ -1108,7 +1147,7 @@ if (events & NVREG_IRQ_LINK) { spin_lock(&np->lock); - link_irq(dev); + nv_link_irq(dev); spin_unlock(&np->lock); } if (events & (NVREG_IRQ_TX_ERR)) { @@ -1127,31 +1166,32 @@ if (!np->in_shutdown) mod_timer(&np->nic_poll, jiffies + POLL_WAIT); - printk(KERN_DEBUG "%s: too many iterations (%d) in nic_irq.\n", dev->name, i); + printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i); spin_unlock(&np->lock); break; } } - dprintk(KERN_DEBUG "%s: nic_irq completed\n", dev->name); + dprintk(KERN_DEBUG "%s: nv_nic_irq completed\n", dev->name); return IRQ_RETVAL(i); } -static void do_nic_poll(unsigned long data) +static void nv_do_nic_poll(unsigned long data) { struct net_device *dev = (struct net_device *) data; struct fe_priv *np = get_nvpriv(dev); u8 *base = get_hwbase(dev); disable_irq(dev->irq); + /* FIXME: Do we need synchronize_irq(dev->irq) here? */ /* * reenable interrupts on the nic, we have to do this before calling - * nic_irq because that may decide to do otherwise + * nv_nic_irq because that may decide to do otherwise */ writel(np->irqmask, base + NvRegIrqMask); pci_push(base); - nic_irq((int) 0, (void *) data, (struct pt_regs *) NULL); + nv_nic_irq((int) 0, (void *) data, (struct pt_regs *) NULL); enable_irq(dev->irq); } @@ -1173,12 +1213,12 @@ writel(0, base + NvRegAdapterControl); writel(0, base + NvRegLinkSpeed); writel(0, base + NvRegUnknownTransmitterReg); - txrx_reset(dev); + nv_txrx_reset(dev); writel(0, base + NvRegUnknownSetupReg6); /* 2) initialize descriptor rings */ np->in_shutdown = 0; - oom = init_ring(dev); + oom = nv_init_ring(dev); /* 3) set mac address */ { @@ -1224,7 +1264,7 @@ np->phyaddr = i; spin_lock_irq(&np->lock); - update_linkspeed(dev); + nv_update_linkspeed(dev); spin_unlock_irq(&np->lock); break; @@ -1279,7 +1319,7 @@ writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); pci_push(base); - ret = request_irq(dev->irq, &nic_irq, SA_SHIRQ, dev->name, dev); + ret = request_irq(dev->irq, &nv_nic_irq, SA_SHIRQ, dev->name, dev); if (ret) goto out_drain; @@ -1291,8 +1331,8 @@ writel(0, base + NvRegMulticastMaskA); writel(0, base + NvRegMulticastMaskB); writel(NVREG_PFF_ALWAYS|NVREG_PFF_MYADDR, base + NvRegPacketFilterFlags); - start_rx(dev); - start_tx(dev); + nv_start_rx(dev); + nv_start_tx(dev); netif_start_queue(dev); if (oom) mod_timer(&np->oom_kick, jiffies + OOM_REFILL); @@ -1326,8 +1366,8 @@ netif_stop_queue(dev); spin_lock_irq(&np->lock); - stop_tx(dev); - stop_rx(dev); + nv_stop_tx(dev); + nv_stop_rx(dev); base = get_hwbase(dev); /* disable interrupts on the nic or we will lock up */ @@ -1341,6 +1381,9 @@ drain_ring(dev); + if (np->wolenabled) + nv_start_rx(dev); + /* FIXME: power down nic */ return 0; @@ -1367,10 +1410,10 @@ init_timer(&np->oom_kick); np->oom_kick.data = (unsigned long) dev; - np->oom_kick.function = &do_rx_refill; /* timer handler */ + np->oom_kick.function = &nv_do_rx_refill; /* timer handler */ init_timer(&np->nic_poll); np->nic_poll.data = (unsigned long) dev; - np->nic_poll.function = &do_nic_poll; /* timer handler */ + np->nic_poll.function = &nv_do_nic_poll; /* timer handler */ err = pci_enable_device(pci_dev); if (err) { @@ -1458,6 +1501,10 @@ dprintk(KERN_DEBUG "%s: MAC Address %02x:%02x:%02x:%02x:%02x:%02x\n", pci_name(pci_dev), dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + + /* disable WOL */ + writel(0, base + NvRegWakeUpFlags); + np->wolenabled = 0; np->tx_flags = cpu_to_le16(NV_TX_LASTPACKET|NV_TX_LASTPACKET1|NV_TX_VALID); if (id->driver_data & DEV_NEED_LASTPACKET1) diff -Nru a/drivers/net/gt96100eth.c b/drivers/net/gt96100eth.c --- a/drivers/net/gt96100eth.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/gt96100eth.c Sun Mar 14 14:20:08 2004 @@ -277,7 +277,7 @@ static void dump_tx_desc(int dbg_lvl, struct net_device *dev, int i) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); gt96100_td_t *td = &gp->tx_ring[i]; dbg(dbg_lvl, "Tx descriptor at 0x%08lx:\n", virt_to_phys(td)); @@ -292,7 +292,7 @@ static void dump_rx_desc(int dbg_lvl, struct net_device *dev, int i) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); gt96100_rd_t *rd = &gp->rx_ring[i]; dbg(dbg_lvl, "Rx descriptor at 0x%08lx:\n", virt_to_phys(rd)); @@ -332,7 +332,7 @@ static void dump_tx_ring(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); int i; dbg(0, "%s: txno/txni/cnt=%d/%d/%d\n", __FUNCTION__, @@ -345,7 +345,7 @@ static void dump_rx_ring(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); int i; dbg(0, "%s: rxno=%d\n", __FUNCTION__, gp->rx_next_out); @@ -359,7 +359,7 @@ dump_MII(int dbg_lvl, struct net_device *dev) { int i, val; - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); if (dbg_lvl <= GT96100_DEBUG) { for (i=0; i<7; i++) { @@ -419,7 +419,7 @@ static int gt96100_add_hash_entry(struct net_device *dev, unsigned char* addr) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); //u16 hashResult, stmp; //unsigned char ctmp, hash_ea[6]; u32 tblEntry1, tblEntry0, *tblEntryAddr; @@ -544,7 +544,7 @@ static void abort(struct net_device *dev, u32 abort_bits) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); int timedout = 100; // wait up to 100 msec for hard stop to complete dbg(3, "%s\n", __FUNCTION__); @@ -582,7 +582,7 @@ static void hard_stop(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); dbg(3, "%s\n", __FUNCTION__); @@ -598,7 +598,7 @@ static void enable_ether_irq(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); u32 intMask; /* * route ethernet interrupt to GT_SERINT0 for port 0, @@ -631,7 +631,7 @@ static void disable_ether_irq(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); u32 intMask; int intr_mask_reg = (gp->port_num == 0) ? GT96100_SERINT0_MASK : GT96100_INT0_HIGH_MASK; @@ -745,7 +745,7 @@ goto out1; } - gp = dev->priv; + gp = netdev_priv(dev); memset(gp, 0, sizeof(*gp)); // clear it @@ -839,7 +839,7 @@ static void reset_tx(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); int i; abort(dev, sdcmrAT); @@ -877,7 +877,7 @@ static void reset_rx(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); int i; abort(dev, sdcmrAR); @@ -934,7 +934,7 @@ static int gt96100_init(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); u32 tmp; u16 mii_reg; @@ -1115,7 +1115,7 @@ static int gt96100_tx(struct sk_buff *skb, struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); unsigned long flags; int nextIn; @@ -1187,7 +1187,7 @@ static int gt96100_rx(struct net_device *dev, u32 status) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); struct sk_buff *skb; int pkt_len, nextOut, cdp; gt96100_rd_t *rd; @@ -1296,7 +1296,7 @@ static void gt96100_tx_complete(struct net_device *dev, u32 status) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); int nextOut, cdp; gt96100_td_t *td; u32 cmdstat; @@ -1385,7 +1385,7 @@ gt96100_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_id; - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); u32 status; int handled = 0; @@ -1486,7 +1486,7 @@ static void gt96100_tx_timeout(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&gp->lock, flags); @@ -1511,7 +1511,7 @@ static void gt96100_set_rx_mode(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); unsigned long flags; //struct dev_mc_list *mcptr; @@ -1555,7 +1555,7 @@ static struct net_device_stats * gt96100_get_stats(struct net_device *dev) { - struct gt96100_private *gp = (struct gt96100_private *)dev->priv; + struct gt96100_private *gp = netdev_priv(dev); unsigned long flags; dbg(3, "%s: dev=%p\n", __FUNCTION__, dev); diff -Nru a/drivers/net/hamachi.c b/drivers/net/hamachi.c --- a/drivers/net/hamachi.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/hamachi.c Sun Mar 14 14:20:08 2004 @@ -1498,8 +1498,10 @@ if (desc_status & DescOwn) break; - pci_dma_sync_single(hmp->pci_dev, desc->addr, hmp->rx_buf_sz, - PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(hmp->pci_dev, + desc->addr, + hmp->rx_buf_sz, + PCI_DMA_FROMDEVICE); buf_addr = desc_to_virt(desc->addr); frame_status = le32_to_cpu(get_unaligned((s32*)&(buf_addr[data_size - 12]))); if (hamachi_debug > 4) @@ -1563,6 +1565,10 @@ #endif skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ + pci_dma_sync_single_for_cpu(hmp->pci_dev, + hmp->rx_ring[entry].addr, + hmp->rx_buf_sz, + PCI_DMA_FROMDEVICE); /* Call copy + cksum if available. */ #if 1 || USE_IP_COPYSUM eth_copy_and_sum(skb, @@ -1572,10 +1578,14 @@ memcpy(skb_put(skb, pkt_len), hmp->rx_ring_dma + entry*sizeof(*desc), pkt_len); #endif + pci_dma_sync_single_for_device(hmp->pci_dev, + hmp->rx_ring[entry].addr, + hmp->rx_buf_sz, + PCI_DMA_FROMDEVICE); } else { pci_unmap_single(hmp->pci_dev, - hmp->rx_ring[entry].addr, - hmp->rx_buf_sz, PCI_DMA_FROMDEVICE); + hmp->rx_ring[entry].addr, + hmp->rx_buf_sz, PCI_DMA_FROMDEVICE); skb_put(skb = hmp->rx_skbuff[entry], pkt_len); hmp->rx_skbuff[entry] = NULL; } diff -Nru a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c --- a/drivers/net/hamradio/baycom_epp.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/hamradio/baycom_epp.c Sun Mar 14 14:20:08 2004 @@ -646,7 +646,7 @@ static void do_rxpacket(struct net_device *dev) { - struct baycom_state *bc = (struct baycom_state *)dev->priv; + struct baycom_state *bc = netdev_priv(dev); struct sk_buff *skb; unsigned char *cp; unsigned pktlen; @@ -705,7 +705,7 @@ static int receive(struct net_device *dev, int cnt) { - struct baycom_state *bc = (struct baycom_state *)dev->priv; + struct baycom_state *bc = netdev_priv(dev); struct parport *pp = bc->pdev->port; unsigned int bitbuf, notbitstream, bitstream, numbits, state; unsigned char tmp[128]; @@ -790,7 +790,7 @@ int cnt, cnt2; baycom_paranoia_check_void(dev, "epp_bh"); - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); if (!bc->work_running) return; baycom_int_freq(bc); @@ -908,7 +908,7 @@ struct baycom_state *bc; baycom_paranoia_check(dev, "baycom_send_packet", 0); - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); if (skb->data[0] != 0) { do_kiss_params(bc, skb->data, skb->len); dev_kfree_skb(skb); @@ -944,7 +944,7 @@ struct baycom_state *bc; baycom_paranoia_check(dev, "baycom_get_stats", NULL); - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); /* * Get the current statistics. This may be called with the * card open or closed. @@ -960,7 +960,7 @@ struct baycom_state *bc; baycom_paranoia_check_void(dev, "epp_wakeup"); - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); printk(KERN_DEBUG "baycom_epp: %s: why am I being woken up?\n", dev->name); if (!parport_claim(bc->pdev)) printk(KERN_DEBUG "baycom_epp: %s: I'm broken.\n", dev->name); @@ -987,7 +987,7 @@ unsigned long tstart; baycom_paranoia_check(dev, "epp_open", -ENXIO); - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); pp = parport_find_base(dev->base_addr); if (!pp) { printk(KERN_ERR "%s: parport at 0x%lx unknown\n", bc_drvname, dev->base_addr); @@ -1102,7 +1102,7 @@ unsigned char tmp[1]; baycom_paranoia_check(dev, "epp_close", -EINVAL); - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); pp = bc->pdev->port; bc->work_running = 0; flush_scheduled_work(); @@ -1163,7 +1163,7 @@ struct hdlcdrv_ioctl hi; baycom_paranoia_check(dev, "baycom_ioctl", -EINVAL); - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); if (cmd != SIOCDEVPRIVATE) return -ENOIOCTLCMD; if (get_user(cmd, (int *)ifr->ifr_data)) @@ -1290,7 +1290,7 @@ /* * not a real probe! only initialize data structures */ - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); /* * initialize the baycom_state struct */ @@ -1351,7 +1351,7 @@ static void __init baycom_epp_dev_setup(struct net_device *dev) { - struct baycom_state *bc = dev->priv; + struct baycom_state *bc = netdev_priv(dev); /* * initialize part of the baycom_state struct @@ -1415,7 +1415,7 @@ struct net_device *dev = baycom_device[i]; if (dev) { - struct baycom_state *bc = dev->priv; + struct baycom_state *bc = netdev_priv(dev); if (bc->magic == BAYCOM_MAGIC) { unregister_netdev(dev); free_netdev(dev); diff -Nru a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c --- a/drivers/net/hamradio/baycom_par.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/hamradio/baycom_par.c Sun Mar 14 14:20:08 2004 @@ -272,7 +272,7 @@ static void par96_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_id; - struct baycom_state *bc = (struct baycom_state *)dev->priv; + struct baycom_state *bc = netdev_priv(dev); if (!dev || !bc || bc->hdrv.magic != HDLCDRV_MAGIC) return; @@ -302,7 +302,7 @@ static void par96_wakeup(void *handle) { struct net_device *dev = (struct net_device *)handle; - struct baycom_state *bc = (struct baycom_state *)dev->priv; + struct baycom_state *bc = netdev_priv(dev); printk(KERN_DEBUG "baycom_par: %s: why am I being woken up?\n", dev->name); if (!parport_claim(bc->pdev)) @@ -313,7 +313,7 @@ static int par96_open(struct net_device *dev) { - struct baycom_state *bc = (struct baycom_state *)dev->priv; + struct baycom_state *bc = netdev_priv(dev); struct parport *pp; if (!dev || !bc) @@ -362,7 +362,7 @@ static int par96_close(struct net_device *dev) { - struct baycom_state *bc = (struct baycom_state *)dev->priv; + struct baycom_state *bc = netdev_priv(dev); struct parport *pp; if (!dev || !bc) @@ -424,7 +424,7 @@ printk(KERN_ERR "bc_ioctl: invalid device struct\n"); return -EINVAL; } - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); if (cmd != SIOCDEVPRIVATE) return -ENOIOCTLCMD; @@ -524,7 +524,7 @@ if (IS_ERR(dev)) break; - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); if (set_hw && baycom_setmode(bc, mode[i])) set_hw = 0; found++; diff -Nru a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c --- a/drivers/net/hamradio/baycom_ser_fdx.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/hamradio/baycom_ser_fdx.c Sun Mar 14 14:20:07 2004 @@ -281,7 +281,7 @@ static irqreturn_t ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_id; - struct baycom_state *bc = (struct baycom_state *)dev->priv; + struct baycom_state *bc = netdev_priv(dev); struct timeval tv; unsigned char iir, msr; unsigned int txcount = 0; @@ -407,7 +407,7 @@ static int ser12_open(struct net_device *dev) { - struct baycom_state *bc = (struct baycom_state *)dev->priv; + struct baycom_state *bc = netdev_priv(dev); enum uart u; if (!dev || !bc) @@ -466,7 +466,7 @@ static int ser12_close(struct net_device *dev) { - struct baycom_state *bc = (struct baycom_state *)dev->priv; + struct baycom_state *bc = netdev_priv(dev); if (!dev || !bc) return -EINVAL; @@ -536,7 +536,7 @@ printk(KERN_ERR "bc_ioctl: invalid device struct\n"); return -EINVAL; } - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); if (cmd != SIOCDEVPRIVATE) return -ENOIOCTLCMD; @@ -644,7 +644,7 @@ if (IS_ERR(dev)) break; - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); if (set_hw && baycom_setmode(bc, mode[i])) set_hw = 0; bc->baud = baud[i]; diff -Nru a/drivers/net/hamradio/baycom_ser_hdx.c b/drivers/net/hamradio/baycom_ser_hdx.c --- a/drivers/net/hamradio/baycom_ser_hdx.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/hamradio/baycom_ser_hdx.c Sun Mar 14 14:20:06 2004 @@ -375,7 +375,7 @@ static irqreturn_t ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_id; - struct baycom_state *bc = (struct baycom_state *)dev->priv; + struct baycom_state *bc = netdev_priv(dev); unsigned char iir; if (!dev || !bc || bc->hdrv.magic != HDLCDRV_MAGIC) @@ -468,7 +468,7 @@ static int ser12_open(struct net_device *dev) { - struct baycom_state *bc = (struct baycom_state *)dev->priv; + struct baycom_state *bc = netdev_priv(dev); enum uart u; if (!dev || !bc) @@ -511,7 +511,7 @@ static int ser12_close(struct net_device *dev) { - struct baycom_state *bc = (struct baycom_state *)dev->priv; + struct baycom_state *bc = netdev_priv(dev); if (!dev || !bc) return -EINVAL; @@ -576,7 +576,7 @@ printk(KERN_ERR "bc_ioctl: invalid device struct\n"); return -EINVAL; } - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); if (cmd != SIOCDEVPRIVATE) return -ENOIOCTLCMD; @@ -681,7 +681,7 @@ if (IS_ERR(dev)) break; - bc = (struct baycom_state *)dev->priv; + bc = netdev_priv(dev); if (set_hw && baycom_setmode(bc, mode[i])) set_hw = 0; found++; diff -Nru a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c --- a/drivers/net/hp-plus.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/hp-plus.c Sun Mar 14 14:20:06 2004 @@ -236,6 +236,9 @@ dev->open = &hpp_open; dev->stop = &hpp_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif ei_status.name = name; ei_status.word16 = 0; /* Agggghhhhh! Debug time: 2 days! */ diff -Nru a/drivers/net/hp.c b/drivers/net/hp.c --- a/drivers/net/hp.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/hp.c Sun Mar 14 14:20:06 2004 @@ -207,6 +207,9 @@ dev->base_addr = ioaddr + NIC_OFFSET; dev->open = &hp_open; dev->stop = &hp_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif ei_status.name = name; ei_status.word16 = wordmode; diff -Nru a/drivers/net/hplance.c b/drivers/net/hplance.c --- a/drivers/net/hplance.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/hplance.c Sun Mar 14 14:20:07 2004 @@ -63,7 +63,7 @@ static void cleanup_card(struct net_device *dev) { - struct hplance_private *lp = dev->priv; + struct hplance_private *lp = netdev_priv(dev); dio_unconfig_board(lp->scode); } @@ -97,7 +97,7 @@ dio_config_board(scode); hplance_init(dev, scode); if (!register_netdev(dev)) { - struct hplance_private *lp = dev->priv; + struct hplance_private *lp = netdev_priv(dev); lp->next_module = root_hplance_dev; root_hplance_dev = lp; return dev; @@ -141,7 +141,7 @@ printk("%c%2.2x", i == 0 ? ' ' : ':', dev->dev_addr[i]); } - lp = (struct hplance_private *)dev->priv; + lp = netdev_priv(dev); lp->lance.name = (char*)name; /* discards const, shut up gcc */ lp->lance.ll = (struct lance_regs *)(va + HPLANCE_REGOFF); lp->lance.init_block = (struct lance_init_block *)(va + HPLANCE_MEMOFF); /* CPU addr */ @@ -195,7 +195,7 @@ static int hplance_open(struct net_device *dev) { int status; - struct hplance_private *lp = (struct hplance_private *)dev->priv; + struct hplance_private *lp = netdev_priv(dev); struct hplance_reg *hpregs = (struct hplance_reg *)lp->base; status = lance_open(dev); /* call generic lance open code */ @@ -209,7 +209,7 @@ static int hplance_close(struct net_device *dev) { - struct hplance_private *lp = (struct hplance_private *)dev->priv; + struct hplance_private *lp = netdev_priv(dev); struct hplance_reg *hpregs = (struct hplance_reg *)lp->base; out_8(&(hpregs->status), 8); /* disable interrupts at boardlevel */ lance_close(dev); diff -Nru a/drivers/net/hydra.c b/drivers/net/hydra.c --- a/drivers/net/hydra.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/hydra.c Sun Mar 14 14:20:07 2004 @@ -142,6 +142,10 @@ ei_status.reg_offset = hydra_offsets; dev->open = &hydra_open; dev->stop = &hydra_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif + NS8390_init(dev, 0); err = register_netdev(dev); diff -Nru a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c --- a/drivers/net/irda/vlsi_ir.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/irda/vlsi_ir.c Sun Mar 14 14:20:06 2004 @@ -173,7 +173,7 @@ PCIDEV_NAME(pdev), (int)pdev->vendor, (int)pdev->device); out += sprintf(out, "pci-power-state: %u\n", (unsigned) pdev->current_state); out += sprintf(out, "resources: irq=%u / io=0x%04x / dma_mask=0x%016Lx\n", - pdev->irq, (unsigned)pci_resource_start(pdev, 0), (u64)pdev->dma_mask); + pdev->irq, (unsigned)pci_resource_start(pdev, 0), (unsigned long long)pdev->dma_mask); out += sprintf(out, "hw registers: "); for (i = 0; i < 0x20; i++) out += sprintf(out, "%02x", (unsigned)inb((iobase+i))); @@ -566,7 +566,6 @@ return NULL; } rd_set_addr_status(rd, busaddr, 0); - pci_dma_sync_single(pdev, busaddr, len, dir); /* initially, the dma buffer is owned by the CPU */ rd->skb = NULL; } @@ -660,7 +659,7 @@ struct net_device *ndev = (struct net_device *)pci_get_drvdata(r->pdev); vlsi_irda_dev_t *idev = ndev->priv; - pci_dma_sync_single(r->pdev, rd_get_addr(rd), r->len, r->dir); + pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir); /* dma buffer now owned by the CPU */ status = rd_get_status(rd); if (status & RD_RX_ERROR) { @@ -746,7 +745,7 @@ break; /* probably not worth logging? */ } /* give dma buffer back to busmaster */ - pci_dma_prep_single(r->pdev, rd_get_addr(rd), r->len, r->dir); + pci_dma_sync_single_for_device(r->pdev, rd_get_addr(rd), r->len, r->dir); rd_activate(rd); } } @@ -816,7 +815,7 @@ ret = -VLSI_RX_DROP; } rd_set_count(rd, 0); - pci_dma_sync_single(r->pdev, rd_get_addr(rd), r->len, r->dir); + pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir); if (rd->skb) { dev_kfree_skb_any(rd->skb); rd->skb = NULL; @@ -854,7 +853,7 @@ int len; int ret; - pci_dma_sync_single(r->pdev, rd_get_addr(rd), r->len, r->dir); + pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir); /* dma buffer now owned by the CPU */ status = rd_get_status(rd); if (status & RD_TX_UNDRN) @@ -1077,8 +1076,8 @@ } } - /* tx buffer already owned by CPU due to pci_dma_sync_single() either - * after initial pci_map_single or after subsequent tx-completion + /* tx buffer already owned by CPU due to pci_dma_sync_single_for_cpu() + * after subsequent tx-completion */ if (idev->mode == IFF_SIR) { @@ -1120,7 +1119,7 @@ * CPU-driven changes visible from the pci bus). */ - pci_dma_prep_single(r->pdev, rd_get_addr(rd), r->len, r->dir); + pci_dma_sync_single_for_device(r->pdev, rd_get_addr(rd), r->len, r->dir); /* Switching to TX mode here races with the controller * which may stop TX at any time when fetching an inactive descriptor @@ -1248,7 +1247,7 @@ if (rd_is_active(rd)) { rd_set_status(rd, 0); rd_set_count(rd, 0); - pci_dma_sync_single(r->pdev, rd_get_addr(rd), r->len, r->dir); + pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir); if (rd->skb) { dev_kfree_skb_any(rd->skb); rd->skb = NULL; diff -Nru a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c --- a/drivers/net/isa-skeleton.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/isa-skeleton.c Sun Mar 14 14:20:08 2004 @@ -303,7 +303,7 @@ } #endif /* jumpered DMA */ - np = (struct net_local *)dev->priv; + np = netdev_priv(dev); spin_lock_init(&np->lock); dev->open = net_open; @@ -326,7 +326,7 @@ static void net_tx_timeout(struct net_device *dev) { - struct net_local *np = (struct net_local *)dev->priv; + struct net_local *np = netdev_priv(dev); printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, tx_done(dev) ? "IRQ conflict" : "network cable problem"); @@ -361,7 +361,7 @@ static int net_open(struct net_device *dev) { - struct net_local *np = (struct net_local *)dev->priv; + struct net_local *np = netdev_priv(dev); int ioaddr = dev->base_addr; /* * This is used if the interrupt line can turned off (shared). @@ -399,7 +399,7 @@ */ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct net_local *np = (struct net_local *)dev->priv; + struct net_local *np = netdev_priv(dev); int ioaddr = dev->base_addr; short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned char *buf = skb->data; @@ -465,7 +465,7 @@ */ void net_tx(struct net_device *dev) { - struct net_local *np = (struct net_local *)dev->priv; + struct net_local *np = netdev_priv(dev); int entry; /* This protects us from concurrent execution of @@ -508,7 +508,7 @@ ioaddr = dev->base_addr; - np = (struct net_local *)dev->priv; + np = netdev_priv(dev); status = inw(ioaddr + 0); if (status == 0) @@ -539,7 +539,7 @@ static void net_rx(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int boguscount = 10; @@ -591,7 +591,7 @@ static int net_close(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; lp->open_time = 0; @@ -620,7 +620,7 @@ */ static struct net_device_stats *net_get_stats(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); short ioaddr = dev->base_addr; /* Update the statistics from the device registers. */ diff -Nru a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c --- a/drivers/net/lasi_82596.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/lasi_82596.c Sun Mar 14 14:20:06 2004 @@ -426,7 +426,7 @@ static inline void MPU_PORT(struct net_device *dev, int c, dma_addr_t x) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = netdev_priv(dev); u32 v = (u32) (c) | (u32) (x); u16 a, b; @@ -481,7 +481,7 @@ static void i596_display_data(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = netdev_priv(dev); struct i596_cmd *cmd; struct i596_rfd *rfd; struct i596_rbd *rbd; @@ -541,7 +541,7 @@ static inline void init_rx_bufs(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *)dev->priv; + struct i596_private *lp = netdev_priv(dev); int i; struct i596_rfd *rfd; struct i596_rbd *rbd; @@ -595,7 +595,7 @@ static inline void remove_rx_bufs(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *)dev->priv; + struct i596_private *lp = netdev_priv(dev); struct i596_rbd *rbd; int i; @@ -612,7 +612,7 @@ static void rebuild_rx_bufs(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = netdev_priv(dev); int i; /* Ensure rx frame/buffer descriptors are tidy */ @@ -633,7 +633,7 @@ static int init_i596_mem(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = netdev_priv(dev); unsigned long flags; disable_irq(dev->irq); /* disable IRQs from LAN */ @@ -727,7 +727,7 @@ static inline int i596_rx(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *)dev->priv; + struct i596_private *lp = netdev_priv(dev); struct i596_rfd *rfd; struct i596_rbd *rbd; int frames = 0; @@ -802,9 +802,10 @@ skb->dev = dev; if (!rx_in_place) { /* 16 byte align the data fields */ - dma_sync_single(lp->dev, (dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, DMA_FROM_DEVICE); + dma_sync_single_for_cpu(lp->dev, (dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, DMA_FROM_DEVICE); skb_reserve(skb, 2); memcpy(skb_put(skb,pkt_len), rbd->v_data, pkt_len); + dma_sync_single_for_device(lp->dev, (dma_addr_t)WSWAPchar(rbd->b_data), PKT_BUF_SZ, DMA_FROM_DEVICE); } skb->len = pkt_len; skb->protocol=eth_type_trans(skb,dev); @@ -939,7 +940,7 @@ static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = netdev_priv(dev); unsigned long flags; DEB(DEB_ADDCMD,printk("i596_add_cmd cmd_head %p\n", lp->cmd_head)); @@ -987,7 +988,7 @@ device list */ static int i596_test(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = netdev_priv(dev); volatile int *tint; u32 data; @@ -1041,7 +1042,7 @@ static void i596_tx_timeout (struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = netdev_priv(dev); /* Transmitter timeout, serious problems. */ DEB(DEB_ERRORS,printk("%s: transmit timed out, status resetting.\n", @@ -1070,7 +1071,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = netdev_priv(dev); struct tx_cmd *tx_cmd; struct i596_tbd *tbd; short length = skb->len; @@ -1219,7 +1220,7 @@ dev->priv = (void *)(dev->mem_start); - lp = (struct i596_private *) dev->priv; + lp = netdev_priv(dev); DEB(DEB_INIT,printk ("%s: lp at 0x%08lx (%d bytes), lp->scb at 0x%08lx\n", dev->name, (unsigned long)lp, sizeof(struct i596_private), (unsigned long)&lp->scb)); @@ -1249,7 +1250,7 @@ return IRQ_NONE; } - lp = (struct i596_private *) dev->priv; + lp = netdev_priv(dev); spin_lock (&lp->lock); @@ -1395,7 +1396,7 @@ static int i596_close(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = netdev_priv(dev); unsigned long flags; netif_stop_queue(dev); @@ -1429,7 +1430,7 @@ static struct net_device_stats * i596_get_stats(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = netdev_priv(dev); return &lp->stats; } @@ -1440,7 +1441,7 @@ static void set_multicast_list(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = netdev_priv(dev); int config = 0, cnt; DEB(DEB_MULTI,printk("%s: set multicast list, %d entries, promisc %s, allmulti %s\n", dev->name, dev->mc_count, dev->flags & IFF_PROMISC ? "ON" : "OFF", dev->flags & IFF_ALLMULTI ? "ON" : "OFF")); @@ -1540,7 +1541,7 @@ retval = register_netdev(netdevice); if (retval) { - struct i596_private *lp = netdevice->priv; + struct i596_private *lp = netdev_priv(netdevice); printk(KERN_WARNING __FILE__ ": register_netdevice ret'd %d\n", retval); dma_free_noncoherent(lp->dev, sizeof(struct i596_private), (void *)netdevice->mem_start, lp->dma_addr); @@ -1594,7 +1595,7 @@ unregister_netdev(netdevice); - lp = (struct i596_private *) netdevice->priv; + lp = netdev_priv(netdevice); dma_free_noncoherent(lp->dev, sizeof(struct i596_private), (void *)netdevice->mem_start, lp->dma_addr); free_netdev(netdevice); diff -Nru a/drivers/net/lne390.c b/drivers/net/lne390.c --- a/drivers/net/lne390.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/lne390.c Sun Mar 14 14:20:08 2004 @@ -299,6 +299,9 @@ dev->open = &lne390_open; dev->stop = &lne390_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; cleanup: diff -Nru a/drivers/net/loopback.c b/drivers/net/loopback.c --- a/drivers/net/loopback.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/loopback.c Sun Mar 14 14:20:06 2004 @@ -123,7 +123,7 @@ */ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) { - struct net_device_stats *stats = (struct net_device_stats *)dev->priv; + struct net_device_stats *stats = netdev_priv(dev); skb_orphan(skb); diff -Nru a/drivers/net/mac8390.c b/drivers/net/mac8390.c --- a/drivers/net/mac8390.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/mac8390.c Sun Mar 14 14:20:07 2004 @@ -442,6 +442,9 @@ /* Now fill in our stuff */ dev->open = &mac8390_open; dev->stop = &mac8390_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif /* GAR, ei_status is actually a macro even though it looks global */ ei_status.name = cardname[type]; diff -Nru a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c --- a/drivers/net/mac89x0.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/mac89x0.c Sun Mar 14 14:20:07 2004 @@ -225,7 +225,7 @@ goto out; /* Initialize the net_device structure. */ - lp = (struct net_local *)dev->priv; + lp = netdev_priv(dev); /* Fill in the 'dev' fields. */ dev->base_addr = ioaddr; @@ -328,7 +328,7 @@ static int net_open(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int i; /* Disable the interrupt for now */ @@ -392,7 +392,7 @@ if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned long flags; if (net_debug > 3) @@ -446,7 +446,7 @@ dev->interrupt = 1; ioaddr = dev->base_addr; - lp = (struct net_local *)dev->priv; + lp = netdev_priv(dev); /* we MUST read all the events out of the ISQ, otherwise we'll never get interrupted again. As a consequence, we can't have any limit @@ -505,7 +505,7 @@ static void net_rx(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); struct sk_buff *skb; int status, length; @@ -571,7 +571,7 @@ static struct net_device_stats * net_get_stats(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); unsigned long flags; local_irq_save(flags); @@ -585,7 +585,7 @@ static void set_multicast_list(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); if(dev->flags&IFF_PROMISC) { diff -Nru a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c --- a/drivers/net/myri_sbus.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/myri_sbus.c Sun Mar 14 14:20:06 2004 @@ -435,9 +435,9 @@ /* Check for errors. */ DRX(("rxd[%d]: %p len[%d] csum[%08x] ", entry, rxd, len, csum)); - sbus_dma_sync_single(mp->myri_sdev, - sbus_readl(&rxd->myri_scatters[0].addr), - RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE); + sbus_dma_sync_single_for_cpu(mp->myri_sdev, + sbus_readl(&rxd->myri_scatters[0].addr), + RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE); if (len < (ETH_HLEN + MYRI_PAD_LEN) || (skb->data[0] != MYRI_PAD_LEN)) { DRX(("ERROR[")); mp->enet_stats.rx_errors++; @@ -454,6 +454,10 @@ drops++; DRX(("DROP ")); mp->enet_stats.rx_dropped++; + sbus_dma_sync_single_for_device(mp->myri_sdev, + sbus_readl(&rxd->myri_scatters[0].addr), + RX_ALLOC_SIZE, + SBUS_DMA_FROMDEVICE); sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len); sbus_writel(index, &rxd->ctx); sbus_writel(1, &rxd->num_sg); @@ -508,6 +512,10 @@ /* Reuse original ring buffer. */ DRX(("reuse ")); + sbus_dma_sync_single_for_device(mp->myri_sdev, + sbus_readl(&rxd->myri_scatters[0].addr), + RX_ALLOC_SIZE, + SBUS_DMA_FROMDEVICE); sbus_writel(RX_ALLOC_SIZE, &rxd->myri_scatters[0].len); sbus_writel(index, &rxd->ctx); sbus_writel(1, &rxd->num_sg); diff -Nru a/drivers/net/natsemi.c b/drivers/net/natsemi.c --- a/drivers/net/natsemi.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/natsemi.c Sun Mar 14 14:20:06 2004 @@ -1789,7 +1789,7 @@ skb->dev = dev; /* 16 byte align the IP header */ skb_reserve(skb, 2); - pci_dma_sync_single(np->pci_dev, + pci_dma_sync_single_for_cpu(np->pci_dev, np->rx_dma[entry], np->rx_skbuff[entry]->len, PCI_DMA_FROMDEVICE); @@ -1801,6 +1801,10 @@ memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail, pkt_len); #endif + pci_dma_sync_single_for_device(np->pci_dev, + np->rx_dma[entry], + np->rx_skbuff[entry]->len, + PCI_DMA_FROMDEVICE); } else { pci_unmap_single(np->pci_dev, np->rx_dma[entry], np->rx_skbuff[entry]->len, diff -Nru a/drivers/net/ne.c b/drivers/net/ne.c --- a/drivers/net/ne.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/ne.c Sun Mar 14 14:20:07 2004 @@ -498,6 +498,9 @@ ei_status.priv = 0; dev->open = &ne_open; dev->stop = &ne_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; diff -Nru a/drivers/net/ne2.c b/drivers/net/ne2.c --- a/drivers/net/ne2.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/ne2.c Sun Mar 14 14:20:08 2004 @@ -509,6 +509,9 @@ dev->open = &ne_open; dev->stop = &ne_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; out: diff -Nru a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c --- a/drivers/net/ne2k-pci.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/ne2k-pci.c Sun Mar 14 14:20:06 2004 @@ -359,6 +359,9 @@ dev->open = &ne2k_pci_open; dev->stop = &ne2k_pci_close; dev->ethtool_ops = &ne2k_pci_ethtool_ops; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); i = register_netdev(dev); diff -Nru a/drivers/net/ne2k_cbus.c b/drivers/net/ne2k_cbus.c --- a/drivers/net/ne2k_cbus.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/ne2k_cbus.c Sun Mar 14 14:20:06 2004 @@ -534,6 +534,9 @@ ei_status.priv = 0; dev->open = &ne_open; dev->stop = &ne_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; diff -Nru a/drivers/net/ne3210.c b/drivers/net/ne3210.c --- a/drivers/net/ne3210.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/ne3210.c Sun Mar 14 14:20:07 2004 @@ -205,6 +205,9 @@ dev->open = &ne3210_open; dev->stop = &ne3210_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif dev->if_port = ifmap_val[port_index]; if ((retval = register_netdev (dev))) diff -Nru a/drivers/net/netconsole.c b/drivers/net/netconsole.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/netconsole.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,127 @@ +/* + * linux/drivers/net/netconsole.c + * + * Copyright (C) 2001 Ingo Molnar + * + * This file contains the implementation of an IRQ-safe, crash-safe + * kernel console implementation that outputs kernel messages to the + * network. + * + * Modification history: + * + * 2001-09-17 started by Ingo Molnar. + * 2003-08-11 2.6 port by Matt Mackall + * simplified options + * generic card hooks + * works non-modular + * 2003-09-07 rewritten with netpoll api + */ + +/**************************************************************** + * 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, 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. + * + ****************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Maintainer: Matt Mackall "); +MODULE_DESCRIPTION("Console driver for network interfaces"); +MODULE_LICENSE("GPL"); + +static char config[256]; +module_param_string(netconsole, config, 256, 0); +MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@/[tgt-macaddr]\n"); + +static struct netpoll np = { + .name = "netconsole", + .dev_name = "eth0", + .local_port = 6665, + .remote_port = 6666, + .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, +}; +static int configured = 0; + +#define MAX_PRINT_CHUNK 1000 + +static void write_msg(struct console *con, const char *msg, unsigned int len) +{ + int frag, left; + unsigned long flags; + + if (!np.dev) + return; + + local_irq_save(flags); + + for(left = len; left; ) { + frag = min(left, MAX_PRINT_CHUNK); + netpoll_send_udp(&np, msg, frag); + msg += frag; + left -= frag; + } + + local_irq_restore(flags); +} + +static struct console netconsole = { + .flags = CON_ENABLED | CON_PRINTBUFFER, + .write = write_msg +}; + +static int option_setup(char *opt) +{ + configured = !netpoll_parse_options(&np, opt); + return 0; +} + +__setup("netconsole=", option_setup); + +static int init_netconsole(void) +{ + if(strlen(config)) + option_setup(config); + + if(!configured) { + printk("netconsole: not configured, aborting\n"); + return -EINVAL; + } + + if(netpoll_setup(&np)) + return -EINVAL; + + register_console(&netconsole); + printk(KERN_INFO "netconsole: network logging started\n"); + return 0; +} + +static void cleanup_netconsole(void) +{ + unregister_console(&netconsole); + netpoll_cleanup(&np); +} + +module_init(init_netconsole); +module_exit(cleanup_netconsole); diff -Nru a/drivers/net/ni5010.c b/drivers/net/ni5010.c --- a/drivers/net/ni5010.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/ni5010.c Sun Mar 14 14:20:07 2004 @@ -309,7 +309,7 @@ PRINTK2((KERN_DEBUG "%s: I/O #9 passed!\n", dev->name)); /* DMA is not supported (yet?), so no use detecting it */ - lp = (struct ni5010_local*)dev->priv; + lp = netdev_priv(dev); spin_lock_init(&lp->lock); @@ -484,7 +484,7 @@ PRINTK2((KERN_DEBUG "%s: entering ni5010_interrupt\n", dev->name)); ioaddr = dev->base_addr; - lp = (struct ni5010_local *)dev->priv; + lp = netdev_priv(dev); spin_lock(&lp->lock); status = inb(IE_ISTAT); @@ -527,7 +527,7 @@ /* We have a good packet, get it out of the buffer. */ static void ni5010_rx(struct net_device *dev) { - struct ni5010_local *lp = (struct ni5010_local *)dev->priv; + struct ni5010_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; unsigned char rcv_stat; struct sk_buff *skb; @@ -592,7 +592,7 @@ static int process_xmt_interrupt(struct net_device *dev) { - struct ni5010_local *lp = (struct ni5010_local *)dev->priv; + struct ni5010_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int xmit_stat; @@ -651,7 +651,7 @@ closed. */ static struct net_device_stats *ni5010_get_stats(struct net_device *dev) { - struct ni5010_local *lp = (struct ni5010_local *)dev->priv; + struct ni5010_local *lp = netdev_priv(dev); PRINTK2((KERN_DEBUG "%s: entering ni5010_get_stats\n", dev->name)); @@ -693,7 +693,7 @@ static void hardware_send_packet(struct net_device *dev, char *buf, int length, int pad) { - struct ni5010_local *lp = (struct ni5010_local *)dev->priv; + struct ni5010_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; unsigned long flags; unsigned int buf_offs; diff -Nru a/drivers/net/oaknet.c b/drivers/net/oaknet.c --- a/drivers/net/oaknet.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/oaknet.c Sun Mar 14 14:20:08 2004 @@ -192,6 +192,9 @@ dev->open = oaknet_open; dev->stop = oaknet_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, FALSE); ret = register_netdev(dev); diff -Nru a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c --- a/drivers/net/pcmcia/3c574_cs.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/pcmcia/3c574_cs.c Sun Mar 14 14:20:06 2004 @@ -283,7 +283,7 @@ dev = alloc_etherdev(sizeof(struct el3_private)); if (!dev) return NULL; - lp = dev->priv; + lp = netdev_priv(dev); link = &lp->link; link->priv = dev; @@ -388,7 +388,7 @@ { client_handle_t handle = link->handle; struct net_device *dev = link->priv; - struct el3_private *lp = dev->priv; + struct el3_private *lp = netdev_priv(dev); tuple_t tuple; cisparse_t parse; unsigned short buf[32]; @@ -733,7 +733,7 @@ /* Reset and restore all of the 3c574 registers. */ static void tc574_reset(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); int i, ioaddr = dev->base_addr; unsigned long flags; @@ -814,7 +814,7 @@ static int el3_open(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); dev_link_t *link = &lp->link; if (!DEV_OK(link)) @@ -837,7 +837,7 @@ static void el3_tx_timeout(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; printk(KERN_NOTICE "%s: Transmit timed out!\n", dev->name); @@ -852,7 +852,7 @@ static void pop_tx_status(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; int i; @@ -877,7 +877,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev) { ioaddr_t ioaddr = dev->base_addr; - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); unsigned long flags; DEBUG(3, "%s: el3_start_xmit(length = %ld) called, " @@ -909,7 +909,7 @@ static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; - struct el3_private *lp = dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr, status; int work_budget = max_interrupt_work; int handled = 0; @@ -1002,7 +1002,7 @@ static void media_check(unsigned long arg) { struct net_device *dev = (struct net_device *) arg; - struct el3_private *lp = dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; unsigned long flags; unsigned short /* cable, */ media, partner; @@ -1074,7 +1074,7 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); if (netif_device_present(dev)) { unsigned long flags; @@ -1091,7 +1091,7 @@ */ static void update_stats(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; u8 rx, tx, up; @@ -1128,7 +1128,7 @@ static int el3_rx(struct net_device *dev, int worklimit) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; short rx_status; @@ -1190,7 +1190,7 @@ /* Provide ioctl() calls to examine the MII xcvr state. */ static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; u16 *data = (u16 *)&rq->ifr_data; int phy = lp->phys & 0x1f; @@ -1259,7 +1259,7 @@ static int el3_close(struct net_device *dev) { ioaddr_t ioaddr = dev->base_addr; - struct el3_private *lp = dev->priv; + struct el3_private *lp = netdev_priv(dev); dev_link_t *link = &lp->link; DEBUG(2, "%s: shutting down ethercard.\n", dev->name); diff -Nru a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c --- a/drivers/net/pcmcia/3c589_cs.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/pcmcia/3c589_cs.c Sun Mar 14 14:20:08 2004 @@ -196,7 +196,7 @@ dev = alloc_etherdev(sizeof(struct el3_private)); if (!dev) return NULL; - lp = dev->priv; + lp = netdev_priv(dev); link = &lp->link; link->priv = dev; @@ -304,7 +304,7 @@ { client_handle_t handle = link->handle; struct net_device *dev = link->priv; - struct el3_private *lp = dev->priv; + struct el3_private *lp = netdev_priv(dev); tuple_t tuple; cisparse_t parse; u16 buf[32], *phys_addr; @@ -526,7 +526,7 @@ */ static void tc589_set_xcvr(struct net_device *dev, int if_port) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; EL3WINDOW(0); @@ -648,7 +648,7 @@ static int el3_open(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); dev_link_t *link = &lp->link; if (!DEV_OK(link)) @@ -672,7 +672,7 @@ static void el3_tx_timeout(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; printk(KERN_WARNING "%s: Transmit timed out!\n", dev->name); @@ -687,7 +687,7 @@ static void pop_tx_status(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; int i; @@ -741,7 +741,7 @@ static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; - struct el3_private *lp = dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr, status; int i = 0, handled = 1; @@ -826,7 +826,7 @@ static void media_check(unsigned long arg) { struct net_device *dev = (struct net_device *)(arg); - struct el3_private *lp = dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; u16 media, errs; unsigned long flags; @@ -906,7 +906,7 @@ static struct net_device_stats *el3_get_stats(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); unsigned long flags; dev_link_t *link = &lp->link; @@ -928,7 +928,7 @@ */ static void update_stats(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; DEBUG(2, "%s: updating the statistics.\n", dev->name); @@ -955,7 +955,7 @@ static int el3_rx(struct net_device *dev) { - struct el3_private *lp = (struct el3_private *)dev->priv; + struct el3_private *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; int worklimit = 32; short rx_status; @@ -1009,7 +1009,7 @@ static void set_multicast_list(struct net_device *dev) { - struct el3_private *lp = dev->priv; + struct el3_private *lp = netdev_priv(dev); dev_link_t *link = &lp->link; ioaddr_t ioaddr = dev->base_addr; u16 opts = SetRxFilter | RxStation | RxBroadcast; @@ -1024,7 +1024,7 @@ static int el3_close(struct net_device *dev) { - struct el3_private *lp = dev->priv; + struct el3_private *lp = netdev_priv(dev); dev_link_t *link = &lp->link; ioaddr_t ioaddr = dev->base_addr; diff -Nru a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c --- a/drivers/net/pcmcia/com20020_cs.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/pcmcia/com20020_cs.c Sun Mar 14 14:20:07 2004 @@ -179,7 +179,7 @@ memset(info, 0, sizeof(struct com20020_dev_t)); memset(link, 0, sizeof(struct dev_link_t)); - lp = dev->priv; + lp = netdev_priv(dev); lp->timeout = timeout; lp->backplane = backplane; lp->clockp = clockp; @@ -394,7 +394,7 @@ goto failed; } - lp = dev->priv; + lp = netdev_priv(dev); lp->card_name = "PCMCIA COM20020"; lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */ @@ -492,7 +492,7 @@ pcmcia_request_configuration(link->handle, &link->conf); if (link->open) { int ioaddr = dev->base_addr; - struct arcnet_local *lp = (struct arcnet_local *)dev->priv; + struct arcnet_local *lp = netdev_priv(dev); ARCRESET; } } diff -Nru a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c --- a/drivers/net/pcmcia/fmvj18x_cs.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/pcmcia/fmvj18x_cs.c Sun Mar 14 14:20:07 2004 @@ -256,7 +256,7 @@ dev = alloc_etherdev(sizeof(local_info_t)); if (!dev) return NULL; - lp = dev->priv; + lp = netdev_priv(dev); link = &lp->link; link->priv = dev; @@ -394,7 +394,7 @@ { client_handle_t handle = link->handle; struct net_device *dev = link->priv; - local_info_t *lp = dev->priv; + local_info_t *lp = netdev_priv(dev); tuple_t tuple; cisparse_t parse; u_short buf[32]; @@ -803,7 +803,7 @@ static irqreturn_t fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; - local_info_t *lp = dev->priv; + local_info_t *lp = netdev_priv(dev); ioaddr_t ioaddr; unsigned short tx_stat, rx_stat; @@ -862,7 +862,7 @@ static void fjn_tx_timeout(struct net_device *dev) { - struct local_info_t *lp = (struct local_info_t *)dev->priv; + struct local_info_t *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; printk(KERN_NOTICE "%s: transmit timed out with status %04x, %s?\n", @@ -892,7 +892,7 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct local_info_t *lp = (struct local_info_t *)dev->priv; + struct local_info_t *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; short length = skb->len; @@ -966,7 +966,7 @@ static void fjn_reset(struct net_device *dev) { - struct local_info_t *lp = (struct local_info_t *)dev->priv; + struct local_info_t *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; int i; @@ -1052,7 +1052,7 @@ static void fjn_rx(struct net_device *dev) { - struct local_info_t *lp = (struct local_info_t *)dev->priv; + struct local_info_t *lp = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; int boguscount = 10; /* 5 -> 10: by agy 19940922 */ @@ -1181,7 +1181,7 @@ static int fjn_open(struct net_device *dev) { - struct local_info_t *lp = (struct local_info_t *)dev->priv; + struct local_info_t *lp = netdev_priv(dev); dev_link_t *link = &lp->link; DEBUG(4, "fjn_open('%s').\n", dev->name); @@ -1206,7 +1206,7 @@ static int fjn_close(struct net_device *dev) { - struct local_info_t *lp = (struct local_info_t *)dev->priv; + struct local_info_t *lp = netdev_priv(dev); dev_link_t *link = &lp->link; ioaddr_t ioaddr = dev->base_addr; @@ -1239,7 +1239,7 @@ static struct net_device_stats *fjn_get_stats(struct net_device *dev) { - local_info_t *lp = (local_info_t *)dev->priv; + local_info_t *lp = netdev_priv(dev); return &lp->stats; } /* fjn_get_stats */ @@ -1252,7 +1252,7 @@ static void set_rx_mode(struct net_device *dev) { ioaddr_t ioaddr = dev->base_addr; - struct local_info_t *lp = (struct local_info_t *)dev->priv; + struct local_info_t *lp = netdev_priv(dev); u_char mc_filter[8]; /* Multicast hash filter */ u_long flags; int i; diff -Nru a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c --- a/drivers/net/pcmcia/ibmtr_cs.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/pcmcia/ibmtr_cs.c Sun Mar 14 14:20:07 2004 @@ -178,7 +178,7 @@ link = &info->link; link->priv = info; - info->ti = dev->priv; + info->ti = netdev_priv(dev); link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts1 = 4; @@ -256,7 +256,7 @@ unregister_netdev(dev); { - struct tok_info *ti = (struct tok_info *)dev->priv; + struct tok_info *ti = netdev_priv(dev); del_timer_sync(&(ti->tr_timer)); } if (link->state & DEV_CONFIG) @@ -287,7 +287,7 @@ client_handle_t handle = link->handle; ibmtr_dev_t *info = link->priv; struct net_device *dev = info->dev; - struct tok_info *ti = dev->priv; + struct tok_info *ti = netdev_priv(dev); tuple_t tuple; cisparse_t parse; win_req_t req; @@ -412,7 +412,7 @@ pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); if (link->win) { - struct tok_info *ti = dev->priv; + struct tok_info *ti = netdev_priv(dev); iounmap((void *)ti->mmio); pcmcia_release_window(link->win); pcmcia_release_window(info->sram_win_handle); diff -Nru a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c --- a/drivers/net/pcmcia/smc91c92_cs.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/pcmcia/smc91c92_cs.c Sun Mar 14 14:20:07 2004 @@ -327,7 +327,7 @@ dev = alloc_etherdev(sizeof(struct smc_private)); if (!dev) return NULL; - smc = dev->priv; + smc = netdev_priv(dev); link = &smc->link; link->priv = dev; @@ -483,7 +483,7 @@ static int mhz_3288_power(dev_link_t *link) { struct net_device *dev = link->priv; - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); u_char tmp; /* Read the ISR twice... */ @@ -505,7 +505,7 @@ static int mhz_mfc_config(dev_link_t *link) { struct net_device *dev = link->priv; - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); tuple_t tuple; cisparse_t parse; u_char buf[255]; @@ -618,7 +618,7 @@ static void mot_config(dev_link_t *link) { struct net_device *dev = link->priv; - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; ioaddr_t iouart = link->io.BasePort2; @@ -894,7 +894,7 @@ { client_handle_t handle = link->handle; struct net_device *dev = link->priv; - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); tuple_t tuple; cisparse_t parse; u_short buf[32]; @@ -1069,7 +1069,7 @@ pcmcia_release_irq(link->handle, &link->irq); if (link->win) { struct net_device *dev = link->priv; - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); iounmap(smc->base); pcmcia_release_window(link->win); } @@ -1091,7 +1091,7 @@ { dev_link_t *link = args->client_data; struct net_device *dev = link->priv; - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); int i; DEBUG(1, "smc91c92_event(0x%06x)\n", event); @@ -1240,7 +1240,7 @@ static int smc_open(struct net_device *dev) { - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); dev_link_t *link = &smc->link; #ifdef PCMCIA_DEBUG @@ -1277,7 +1277,7 @@ static int smc_close(struct net_device *dev) { - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); dev_link_t *link = &smc->link; ioaddr_t ioaddr = dev->base_addr; @@ -1314,7 +1314,7 @@ static void smc_hardware_send_packet(struct net_device * dev) { - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); struct sk_buff *skb = smc->saved_skb; ioaddr_t ioaddr = dev->base_addr; u_char packet_no; @@ -1379,7 +1379,7 @@ static void smc_tx_timeout(struct net_device *dev) { - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; printk(KERN_NOTICE "%s: SMC91c92 transmit timed out, " @@ -1394,7 +1394,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; u_short num_pages; short time_out, ir; @@ -1460,7 +1460,7 @@ static void smc_tx_err(struct net_device * dev) { - struct smc_private *smc = (struct smc_private *)dev->priv; + struct smc_private *smc = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; int saved_packet = inw(ioaddr + PNR_ARR) & 0xff; int packet_no = inw(ioaddr + FIFO_PORTS) & 0x7f; @@ -1504,7 +1504,7 @@ static void smc_eph_irq(struct net_device *dev) { - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; u_short card_stats, ephs; @@ -1539,7 +1539,7 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = dev_id; - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); ioaddr_t ioaddr; u_short saved_bank, saved_pointer, mask, status; unsigned int handled = 1; @@ -1657,7 +1657,7 @@ static void smc_rx(struct net_device *dev) { - struct smc_private *smc = (struct smc_private *)dev->priv; + struct smc_private *smc = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; int rx_status; int packet_length; /* Caution: not frame length, rather words @@ -1725,7 +1725,7 @@ static struct net_device_stats *smc_get_stats(struct net_device *dev) { - struct smc_private *smc = (struct smc_private *)dev->priv; + struct smc_private *smc = netdev_priv(dev); /* Nothing to update - the 91c92 is a pretty primative chip. */ return &smc->stats; } @@ -1765,7 +1765,7 @@ static void set_rx_mode(struct net_device *dev) { ioaddr_t ioaddr = dev->base_addr; - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); u_int multicast_table[ 2 ] = { 0, }; unsigned long flags; u_short rx_cfg_setting; @@ -1804,7 +1804,7 @@ static int s9k_config(struct net_device *dev, struct ifmap *map) { - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) { if (smc->cfg & CFG_MII_SELECT) return -EOPNOTSUPP; @@ -1830,7 +1830,7 @@ */ static void smc_set_xcvr(struct net_device *dev, int if_port) { - struct smc_private *smc = (struct smc_private *)dev->priv; + struct smc_private *smc = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; u_short saved_bank; @@ -1855,7 +1855,7 @@ static void smc_reset(struct net_device *dev) { ioaddr_t ioaddr = dev->base_addr; - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); int i; DEBUG(0, "%s: smc91c92 reset called.\n", dev->name); @@ -1930,7 +1930,7 @@ static void media_check(u_long arg) { struct net_device *dev = (struct net_device *) arg; - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); ioaddr_t ioaddr = dev->base_addr; u_short i, media, saved_bank; u_short link; @@ -2044,7 +2044,7 @@ static int smc_link_ok(struct net_device *dev) { ioaddr_t ioaddr = dev->base_addr; - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); if (smc->cfg & CFG_MII_SELECT) { return mii_link_ok(&smc->mii_if); @@ -2109,7 +2109,7 @@ static int smc_ethtool_ioctl (struct net_device *dev, void *useraddr) { u32 ethcmd; - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); if (get_user(ethcmd, (u32 *)useraddr)) return -EFAULT; @@ -2202,7 +2202,7 @@ static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) { - struct smc_private *smc = dev->priv; + struct smc_private *smc = netdev_priv(dev); struct mii_ioctl_data *mii; int rc = 0; u_short saved_bank; diff -Nru a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c --- a/drivers/net/pcmcia/xirc2ps_cs.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/pcmcia/xirc2ps_cs.c Sun Mar 14 14:20:07 2004 @@ -1666,6 +1666,7 @@ struct ethtool_drvinfo *info) { strcpy(info->driver, "xirc2ps_cs"); + sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr); } static struct ethtool_ops netdev_ethtool_ops = { diff -Nru a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c --- a/drivers/net/pcnet32.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/pcnet32.c Sun Mar 14 14:20:06 2004 @@ -225,10 +225,12 @@ * v1.27b Sep 30 2002 Kent Yoder * Added timer for cable connection state changes. * v1.28 20 Feb 2004 Don Fry - * Jon Lewis , Chinmay Albal + * Jon Mason , Chinmay Albal * Now uses ethtool_ops, netif_msg_* and generic_mii_ioctl. * Fixes bogus 'Bus master arbitration failure', pci_[un]map_single * length errors, and transmit hangs. Cleans up after errors in open. + * Jim Lewis added ethernet loopback test. + * Thomas Munck Steenholdt non-mii ioctl corrections. */ @@ -479,6 +481,14 @@ .reset = pcnet32_dwio_reset }; +#ifdef CONFIG_NET_POLL_CONTROLLER +static void pcnet32_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + pcnet32_interrupt(0, dev, NULL); + enable_irq(dev->irq); +} +#endif static int pcnet32_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) @@ -1106,6 +1116,10 @@ dev->tx_timeout = pcnet32_tx_timeout; dev->watchdog_timeo = (5*HZ); +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = pcnet32_poll_controller; +#endif + /* Fill in the generic fields of the device structure. */ if (register_netdev(dev)) goto err_free_consistent; @@ -1733,13 +1747,17 @@ if (!rx_in_place) { skb_reserve(skb,2); /* 16 byte align */ skb_put(skb,pkt_len); /* Make room */ - pci_dma_sync_single(lp->pci_dev, - lp->rx_dma_addr[entry], - PKT_BUF_SZ-2, - PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(lp->pci_dev, + lp->rx_dma_addr[entry], + PKT_BUF_SZ-2, + PCI_DMA_FROMDEVICE); eth_copy_and_sum(skb, (unsigned char *)(lp->rx_skbuff[entry]->tail), pkt_len,0); + pci_dma_sync_single_for_device(lp->pci_dev, + lp->rx_dma_addr[entry], + PKT_BUF_SZ-2, + PCI_DMA_FROMDEVICE); } lp->stats.rx_bytes += skb->len; skb->protocol=eth_type_trans(skb,dev); diff -Nru a/drivers/net/plip.c b/drivers/net/plip.c --- a/drivers/net/plip.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/plip.c Sun Mar 14 14:20:08 2004 @@ -280,7 +280,7 @@ static void plip_init_netdev(struct net_device *dev) { - struct net_local *nl = dev->priv; + struct net_local *nl = netdev_priv(dev); /* Then, override parts of it */ dev->hard_start_xmit = plip_tx_packet; @@ -323,7 +323,7 @@ static void plip_kick_bh(struct net_device *dev) { - struct net_local *nl = (struct net_local *)dev->priv; + struct net_local *nl = netdev_priv(dev); if (nl->is_deferred) schedule_work(&nl->immediate); @@ -366,7 +366,7 @@ static void plip_bh(struct net_device *dev) { - struct net_local *nl = (struct net_local *)dev->priv; + struct net_local *nl = netdev_priv(dev); struct plip_local *snd = &nl->snd_data; struct plip_local *rcv = &nl->rcv_data; plip_func f; @@ -384,7 +384,7 @@ static void plip_timer_bh(struct net_device *dev) { - struct net_local *nl = (struct net_local *)dev->priv; + struct net_local *nl = netdev_priv(dev); if (!(atomic_read (&nl->kill_timer))) { plip_interrupt (-1, dev, NULL); @@ -917,7 +917,7 @@ return; } - nl = (struct net_local *)dev->priv; + nl = netdev_priv(dev); rcv = &nl->rcv_data; spin_lock_irq (&nl->lock); @@ -961,7 +961,7 @@ static int plip_tx_packet(struct sk_buff *skb, struct net_device *dev) { - struct net_local *nl = (struct net_local *)dev->priv; + struct net_local *nl = netdev_priv(dev); struct plip_local *snd = &nl->snd_data; if (netif_queue_stopped(dev)) @@ -1021,7 +1021,7 @@ unsigned short type, void *daddr, void *saddr, unsigned len) { - struct net_local *nl = (struct net_local *)dev->priv; + struct net_local *nl = netdev_priv(dev); int ret; if ((ret = nl->orig_hard_header(skb, dev, type, daddr, saddr, len)) >= 0) @@ -1033,7 +1033,7 @@ int plip_hard_header_cache(struct neighbour *neigh, struct hh_cache *hh) { - struct net_local *nl = (struct net_local *)neigh->dev->priv; + struct net_local *nl = neigh->dev->priv; int ret; if ((ret = nl->orig_hard_header_cache(neigh, hh)) == 0) @@ -1057,7 +1057,7 @@ static int plip_open(struct net_device *dev) { - struct net_local *nl = (struct net_local *)dev->priv; + struct net_local *nl = netdev_priv(dev); struct in_device *in_dev; /* Grab the port */ @@ -1116,7 +1116,7 @@ static int plip_close(struct net_device *dev) { - struct net_local *nl = (struct net_local *)dev->priv; + struct net_local *nl = netdev_priv(dev); struct plip_local *snd = &nl->snd_data; struct plip_local *rcv = &nl->rcv_data; @@ -1163,7 +1163,7 @@ plip_preempt(void *handle) { struct net_device *dev = (struct net_device *)handle; - struct net_local *nl = (struct net_local *)dev->priv; + struct net_local *nl = netdev_priv(dev); /* Stand our ground if a datagram is on the wire */ if (nl->connection != PLIP_CN_NONE) { @@ -1179,7 +1179,7 @@ plip_wakeup(void *handle) { struct net_device *dev = (struct net_device *)handle; - struct net_local *nl = (struct net_local *)dev->priv; + struct net_local *nl = netdev_priv(dev); if (nl->port_owner) { /* Why are we being woken up? */ @@ -1207,7 +1207,7 @@ static struct net_device_stats * plip_get_stats(struct net_device *dev) { - struct net_local *nl = (struct net_local *)dev->priv; + struct net_local *nl = netdev_priv(dev); struct net_device_stats *r = &nl->enet_stats; return r; @@ -1216,7 +1216,7 @@ static int plip_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); struct plipconf *pc = (struct plipconf *) &rq->ifr_data; switch(pc->pcmd) { @@ -1288,7 +1288,7 @@ "which is fairly inefficient!\n", port->name); } - nl = dev->priv; + nl = netdev_priv(dev); nl->pardev = parport_register_device(port, name, plip_preempt, plip_wakeup, plip_interrupt, 0, dev); @@ -1348,7 +1348,7 @@ for (i=0; i < PLIP_MAX; i++) { if ((dev = dev_plip[i])) { - struct net_local *nl = dev->priv; + struct net_local *nl = netdev_priv(dev); unregister_netdev(dev); if (nl->port_owner) parport_release(nl->pardev); diff -Nru a/drivers/net/rrunner.c b/drivers/net/rrunner.c --- a/drivers/net/rrunner.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/rrunner.c Sun Mar 14 14:20:06 2004 @@ -108,7 +108,7 @@ goto out2; } - rrpriv = (struct rr_private *)dev->priv; + rrpriv = netdev_priv(dev); SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); @@ -236,7 +236,7 @@ struct net_device *dev = pci_get_drvdata(pdev); if (dev) { - struct rr_private *rr = dev->priv; + struct rr_private *rr = netdev_priv(dev); if (!(readl(&rr->regs->HostCtrl) & NIC_HALTED)){ printk(KERN_ERR "%s: trying to unload running NIC\n", @@ -308,7 +308,7 @@ u32 start_pc; int i; - rrpriv = (struct rr_private *)dev->priv; + rrpriv = netdev_priv(dev); regs = rrpriv->regs; rr_load_firmware(dev); @@ -524,7 +524,7 @@ u32 sram_size, rev; int i; - rrpriv = (struct rr_private *)dev->priv; + rrpriv = netdev_priv(dev); regs = rrpriv->regs; rev = readl(®s->FwRev); @@ -595,7 +595,7 @@ int ecode = 0; short i; - rrpriv = (struct rr_private *)dev->priv; + rrpriv = netdev_priv(dev); regs = rrpriv->regs; spin_lock_irqsave(&rrpriv->lock, flags); @@ -761,7 +761,7 @@ struct rr_regs *regs; u32 tmp; - rrpriv = (struct rr_private *)dev->priv; + rrpriv = netdev_priv(dev); regs = rrpriv->regs; while (prodidx != eidx){ @@ -960,7 +960,7 @@ static void rx_int(struct net_device *dev, u32 rxlimit, u32 index) { - struct rr_private *rrpriv = (struct rr_private *)dev->priv; + struct rr_private *rrpriv = netdev_priv(dev); struct rr_regs *regs = rrpriv->regs; do { @@ -983,18 +983,26 @@ rx_skb = rrpriv->rx_skbuff[index]; - pci_dma_sync_single(rrpriv->pci_dev, desc->addr.addrlo, - pkt_len, PCI_DMA_FROMDEVICE); - if (pkt_len < PKT_COPY_THRESHOLD) { skb = alloc_skb(pkt_len, GFP_ATOMIC); if (skb == NULL){ printk(KERN_WARNING "%s: Unable to allocate skb (%i bytes), deferring packet\n", dev->name, pkt_len); rrpriv->stats.rx_dropped++; goto defer; - }else + } else { + pci_dma_sync_single_for_cpu(rrpriv->pci_dev, + desc->addr.addrlo, + pkt_len, + PCI_DMA_FROMDEVICE); + memcpy(skb_put(skb, pkt_len), rx_skb->data, pkt_len); + + pci_dma_sync_single_for_device(rrpriv->pci_dev, + desc->addr.addrlo, + pkt_len, + PCI_DMA_FROMDEVICE); + } }else{ struct sk_buff *newskb; @@ -1052,7 +1060,7 @@ struct net_device *dev = (struct net_device *)dev_id; u32 prodidx, rxindex, eidx, txcsmr, rxlimit, txcon; - rrpriv = (struct rr_private *)dev->priv; + rrpriv = netdev_priv(dev); regs = rrpriv->regs; if (!(readl(®s->HostCtrl) & RR_INT)) @@ -1133,7 +1141,7 @@ static void rr_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct rr_private *rrpriv = (struct rr_private *)dev->priv; + struct rr_private *rrpriv = netdev_priv(dev); struct rr_regs *regs = rrpriv->regs; unsigned long flags; @@ -1160,7 +1168,7 @@ static int rr_open(struct net_device *dev) { - struct rr_private *rrpriv = (struct rr_private *)dev->priv; + struct rr_private *rrpriv = netdev_priv(dev); struct pci_dev *pdev = rrpriv->pci_dev; struct rr_regs *regs; int ecode = 0; @@ -1296,7 +1304,7 @@ short i; int len; - rrpriv = (struct rr_private *)dev->priv; + rrpriv = netdev_priv(dev); regs = rrpriv->regs; printk("%s: dumping NIC TX rings\n", dev->name); @@ -1361,7 +1369,7 @@ netif_stop_queue(dev); - rrpriv = (struct rr_private *)dev->priv; + rrpriv = netdev_priv(dev); regs = rrpriv->regs; /* @@ -1418,7 +1426,7 @@ static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct rr_private *rrpriv = (struct rr_private *)dev->priv; + struct rr_private *rrpriv = netdev_priv(dev); struct rr_regs *regs = rrpriv->regs; struct ring_ctrl *txctrl; unsigned long flags; @@ -1488,7 +1496,7 @@ { struct rr_private *rrpriv; - rrpriv = (struct rr_private *)dev->priv; + rrpriv = netdev_priv(dev); return(&rrpriv->stats); } @@ -1511,7 +1519,7 @@ u32 p2len, p2size, nr_seg, revision, io, sram_size; struct eeprom *hw = NULL; - rrpriv = (struct rr_private *)dev->priv; + rrpriv = netdev_priv(dev); regs = rrpriv->regs; if (dev->flags & IFF_UP) @@ -1614,7 +1622,7 @@ unsigned int i; int error = -EOPNOTSUPP; - rrpriv = dev->priv; + rrpriv = netdev_priv(dev); switch(cmd){ case SIOCRRGFW: diff -Nru a/drivers/net/sb1000.c b/drivers/net/sb1000.c --- a/drivers/net/sb1000.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/sb1000.c Sun Mar 14 14:20:06 2004 @@ -746,7 +746,7 @@ int ioaddr, ns; unsigned int skbsize; struct sk_buff *skb; - struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + struct sb1000_private *lp = netdev_priv(dev); struct net_device_stats *stats = &lp->stats; /* SB1000 frame constants */ @@ -905,7 +905,7 @@ char *name; unsigned char st[5]; int ioaddr[2]; - struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + struct sb1000_private *lp = netdev_priv(dev); const unsigned char Command0[6] = {0x80, 0x26, 0x00, 0x00, 0x00, 0x00}; const int ErrorDpcCounterInitialize = 200; @@ -932,7 +932,7 @@ { char *name; int ioaddr[2], status; - struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + struct sb1000_private *lp = netdev_priv(dev); const unsigned short FirmwareVersion[] = {0x01, 0x01}; ioaddr[0] = dev->base_addr; @@ -998,7 +998,7 @@ short PID[4]; int ioaddr[2], status, frequency; unsigned int stats[5]; - struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + struct sb1000_private *lp = netdev_priv(dev); if (!(dev && dev->flags & IFF_UP)) return -ENODEV; @@ -1092,7 +1092,7 @@ unsigned char st; int ioaddr[2]; struct net_device *dev = (struct net_device *) dev_id; - struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + struct sb1000_private *lp = netdev_priv(dev); const unsigned char Command0[6] = {0x80, 0x2c, 0x00, 0x00, 0x00, 0x00}; const unsigned char Command1[6] = {0x80, 0x2e, 0x00, 0x00, 0x00, 0x00}; @@ -1148,7 +1148,7 @@ static struct net_device_stats *sb1000_stats(struct net_device *dev) { - struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + struct sb1000_private *lp = netdev_priv(dev); return &lp->stats; } @@ -1156,7 +1156,7 @@ { int i; int ioaddr[2]; - struct sb1000_private *lp = (struct sb1000_private *)dev->priv; + struct sb1000_private *lp = netdev_priv(dev); if (sb1000_debug > 2) printk(KERN_DEBUG "%s: Shutting down sb1000.\n", dev->name); diff -Nru a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c --- a/drivers/net/sb1250-mac.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/sb1250-mac.c Sun Mar 14 14:20:08 2004 @@ -2080,7 +2080,7 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs) { struct net_device *dev = (struct net_device *) dev_instance; - struct sbmac_softc *sc = (struct sbmac_softc *) (dev->priv); + struct sbmac_softc *sc = netdev_priv(dev); uint64_t isr; int handled = 0; @@ -2150,7 +2150,7 @@ ********************************************************************* */ static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev) { - struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + struct sbmac_softc *sc = netdev_priv(dev); /* lock eth irq */ spin_lock_irq (&sc->sbm_lock); @@ -2374,7 +2374,7 @@ int i; int err; - sc = (struct sbmac_softc *)dev->priv; + sc = netdev_priv(dev); /* Determine controller base address */ @@ -2454,7 +2454,7 @@ static int sbmac_open(struct net_device *dev) { - struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + struct sbmac_softc *sc = netdev_priv(dev); if (debug > 1) { printk(KERN_DEBUG "%s: sbmac_open() irq %d.\n", dev->name, dev->irq); @@ -2609,7 +2609,7 @@ static void sbmac_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + struct sbmac_softc *sc = netdev_priv(dev); int next_tick = HZ; int mii_status; @@ -2655,7 +2655,7 @@ static void sbmac_tx_timeout (struct net_device *dev) { - struct sbmac_softc *sc = (struct sbmac_softc *) dev->priv; + struct sbmac_softc *sc = netdev_priv(dev); spin_lock_irq (&sc->sbm_lock); @@ -2673,7 +2673,7 @@ static struct net_device_stats *sbmac_get_stats(struct net_device *dev) { - struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + struct sbmac_softc *sc = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&sc->sbm_lock, flags); @@ -2691,7 +2691,7 @@ { unsigned long flags; int msg_flag = 0; - struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + struct sbmac_softc *sc = netdev_priv(dev); spin_lock_irqsave(&sc->sbm_lock, flags); if ((dev->flags ^ sc->sbm_devflags) & IFF_PROMISC) { @@ -2726,7 +2726,7 @@ static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + struct sbmac_softc *sc = netdev_priv(dev); u16 *data = (u16 *)&rq->ifr_data; unsigned long flags; int retval; @@ -2762,7 +2762,7 @@ static int sbmac_close(struct net_device *dev) { - struct sbmac_softc *sc = (struct sbmac_softc *)dev->priv; + struct sbmac_softc *sc = netdev_priv(dev); unsigned long flags; int irq; @@ -2911,7 +2911,7 @@ for (idx = 0; idx < MAX_UNITS; idx++) { dev = dev_sbmac[idx]; if (!dev) { - struct sbmac_softc *sc = dev->priv; + struct sbmac_softc *sc = netdev_priv(dev); unregister_netdev(dev); sbmac_uninitctx(sc); free_netdev(dev); diff -Nru a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c --- a/drivers/net/seeq8005.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/seeq8005.c Sun Mar 14 14:20:08 2004 @@ -357,7 +357,7 @@ */ static int seeq8005_open(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); { int irqval = request_irq(dev->irq, &seeq8005_interrupt, 0, "seeq8005", dev); @@ -390,7 +390,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); short length = skb->len; unsigned char *buf; @@ -424,7 +424,7 @@ int handled = 0; ioaddr = dev->base_addr; - lp = (struct net_local *)dev->priv; + lp = netdev_priv(dev); status = inw(SEEQ_STATUS); do { @@ -462,7 +462,7 @@ /* We have a good packet(s), get it/them out of the buffers. */ static void seeq8005_rx(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int boguscount = 10; int pkt_hdr; int ioaddr = dev->base_addr; @@ -561,7 +561,7 @@ /* The inverse routine to net_open(). */ static int seeq8005_close(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; lp->open_time = 0; @@ -583,7 +583,7 @@ closed. */ static struct net_device_stats *seeq8005_get_stats(struct net_device *dev) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); return &lp->stats; } @@ -618,7 +618,7 @@ void seeq8005_init(struct net_device *dev, int startp) { - struct net_local *lp = (struct net_local *)dev->priv; + struct net_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int i; diff -Nru a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c --- a/drivers/net/sgiseeq.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/sgiseeq.c Sun Mar 14 14:20:08 2004 @@ -151,7 +151,7 @@ static int seeq_init_ring(struct net_device *dev) { - struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; + struct sgiseeq_private *sp = netdev_priv(dev); volatile struct sgiseeq_init_block *ib = &sp->srings; int i; @@ -423,7 +423,7 @@ static irqreturn_t sgiseeq_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; - struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; + struct sgiseeq_private *sp = netdev_priv(dev); struct hpc3_ethregs *hregs = sp->hregs; struct sgiseeq_regs *sregs = sp->sregs; @@ -445,7 +445,7 @@ static int sgiseeq_open(struct net_device *dev) { - struct sgiseeq_private *sp = (struct sgiseeq_private *)dev->priv; + struct sgiseeq_private *sp = netdev_priv(dev); struct sgiseeq_regs *sregs = sp->sregs; int err = init_seeq(dev, sp, sregs); @@ -459,7 +459,7 @@ static int sgiseeq_close(struct net_device *dev) { - struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; + struct sgiseeq_private *sp = netdev_priv(dev); struct sgiseeq_regs *sregs = sp->sregs; netif_stop_queue(dev); @@ -472,7 +472,7 @@ static inline int sgiseeq_reset(struct net_device *dev) { - struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; + struct sgiseeq_private *sp = netdev_priv(dev); struct sgiseeq_regs *sregs = sp->sregs; int err; @@ -494,7 +494,7 @@ static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; + struct sgiseeq_private *sp = netdev_priv(dev); struct hpc3_ethregs *hregs = sp->hregs; unsigned long flags; struct sgiseeq_tx_desc *td; @@ -560,7 +560,7 @@ static struct net_device_stats *sgiseeq_get_stats(struct net_device *dev) { - struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; + struct sgiseeq_private *sp = netdev_priv(dev); return &sp->stats; } @@ -710,7 +710,7 @@ struct net_device *next, *dev = root_sgiseeq_dev; while (dev) { - sp = (struct sgiseeq_private *) dev->priv; + sp = netdev_priv(dev); next = sp->next_module; unregister_netdev(dev); free_irq(dev->irq, dev); diff -Nru a/drivers/net/sis190.c b/drivers/net/sis190.c --- a/drivers/net/sis190.c Sun Mar 14 14:20:09 2004 +++ b/drivers/net/sis190.c Sun Mar 14 14:20:09 2004 @@ -1016,14 +1016,20 @@ int pkt_size; pkt_size = (int) (desc->PSize & 0x0000FFFF) - 4; - pci_dma_sync_single(tp->pci_dev, desc->buf_addr, - RX_BUF_SIZE, PCI_DMA_FROMDEVICE); skb = dev_alloc_skb(pkt_size + 2); if (skb != NULL) { skb->dev = dev; skb_reserve(skb, 2); // 16 byte align the IP fields. // + pci_dma_sync_single_for_cpu(tp->pci_dev, + desc->buf_addr, + RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); eth_copy_and_sum(skb, tp->RxBufferRing[cur_rx], pkt_size, 0); + pci_dma_sync_single_for_device(tp->pci_dev, + desc->buf_addr, + RX_BUF_SIZE, + PCI_DMA_FROMDEVICE); skb_put(skb, pkt_size); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); diff -Nru a/drivers/net/sis900.c b/drivers/net/sis900.c --- a/drivers/net/sis900.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/sis900.c Sun Mar 14 14:20:07 2004 @@ -1650,9 +1650,6 @@ break; } - pci_dma_sync_single(sis_priv->pci_dev, - sis_priv->rx_ring[entry].bufptr, RX_BUF_SIZE, - PCI_DMA_FROMDEVICE); pci_unmap_single(sis_priv->pci_dev, sis_priv->rx_ring[entry].bufptr, RX_BUF_SIZE, PCI_DMA_FROMDEVICE); diff -Nru a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c --- a/drivers/net/sk98lin/skge.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/sk98lin/skge.c Sun Mar 14 14:20:06 2004 @@ -2533,12 +2533,6 @@ "Control: %x\nRxStat: %x\n", Control, FrameStat)); - PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; - PhysAddr |= (SK_U64) pRxd->VDataLow; - pci_dma_sync_single(pAC->PciDev, - (dma_addr_t) PhysAddr, - FrameLength, - PCI_DMA_FROMDEVICE); ReQueueRxBuffer(pAC, pRxPort, pMsg, pRxd->VDataHigh, pRxd->VDataLow); @@ -2559,12 +2553,16 @@ PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32; PhysAddr |= (SK_U64) pRxd->VDataLow; - pci_dma_sync_single(pAC->PciDev, - (dma_addr_t) PhysAddr, - FrameLength, - PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(pAC->PciDev, + (dma_addr_t) PhysAddr, + FrameLength, + PCI_DMA_FROMDEVICE); eth_copy_and_sum(pNewMsg, pMsg->data, FrameLength, 0); + pci_dma_sync_single_for_device(pAC->PciDev, + (dma_addr_t) PhysAddr, + FrameLength, + PCI_DMA_FROMDEVICE); ReQueueRxBuffer(pAC, pRxPort, pMsg, pRxd->VDataHigh, pRxd->VDataLow); diff -Nru a/drivers/net/sk_g16.c b/drivers/net/sk_g16.c --- a/drivers/net/sk_g16.c Sun Mar 14 14:20:09 2004 +++ b/drivers/net/sk_g16.c Sun Mar 14 14:20:09 2004 @@ -650,7 +650,7 @@ int sk_addr_flag = 0; /* SK ADDR correct? 1 - no, 0 - yes */ unsigned int rom_addr; /* used to store RAM address used for POS_ADDR */ - struct priv *p = dev->priv; /* SK_G16 private structure */ + struct priv *p = netdev_priv(dev); /* SK_G16 private structure */ if (inb(SK_POS0) != SK_IDLOW || inb(SK_POS1) != SK_IDHIGH) return -ENODEV; @@ -869,7 +869,7 @@ int irqtab[] = SK_IRQS; - struct priv *p = (struct priv *)dev->priv; + struct priv *p = netdev_priv(dev); PRINTK(("## %s: At beginning of SK_open(). CSR0: %#06x\n", SK_NAME, SK_read_reg(CSR0))); @@ -1023,7 +1023,7 @@ { int i; unsigned long flags; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); struct tmd *tmdp; struct rmd *rmdp; @@ -1196,7 +1196,7 @@ static int SK_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); struct tmd *tmdp; static char pad[64]; @@ -1285,7 +1285,7 @@ { int csr0; struct net_device *dev = dev_id; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); PRINTK2(("## %s: SK_interrupt(). status: %#06x\n", @@ -1355,7 +1355,7 @@ { int tmdstat; struct tmd *tmdp; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); PRINTK2(("## %s: SK_txintr() status: %#06x\n", @@ -1469,7 +1469,7 @@ struct rmd *rmdp; int rmdstat; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); PRINTK2(("## %s: SK_rxintr(). CSR0: %#06x\n", SK_NAME, SK_read_reg(CSR0))); @@ -1653,7 +1653,7 @@ static struct net_device_stats *SK_get_stats(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); PRINTK(("## %s: SK_get_stats(). CSR0: %#06x\n", SK_NAME, SK_read_reg(CSR0))); @@ -2030,7 +2030,7 @@ { int i; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); printk("## %s: RAM Details.\n" "## RAM at %#08x tmdhead: %#08x rmdhead: %#08x initblock: %#08x\n", diff -Nru a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c --- a/drivers/net/smc-mca.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/smc-mca.c Sun Mar 14 14:20:06 2004 @@ -324,6 +324,9 @@ dev->open = &ultramca_open; dev->stop = &ultramca_close_card; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); diff -Nru a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c --- a/drivers/net/smc-ultra.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/smc-ultra.c Sun Mar 14 14:20:06 2004 @@ -121,6 +121,14 @@ #define ULTRA_IO_EXTENT 32 #define EN0_ERWCNT 0x08 /* Early receive warning count. */ +#ifdef CONFIG_NET_POLL_CONTROLLER +static void ultra_poll(struct net_device *dev) +{ + disable_irq(dev->irq); + ei_interrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif /* Probe for the Ultra. This looks like a 8013 with the station address PROM at I/O ports +8 to +13, with a checksum following. @@ -134,6 +142,9 @@ SET_MODULE_OWNER(dev); +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = &ultra_poll; +#endif if (base_addr > 0x1ff) /* Check a single specified location. */ return ultra_probe1(dev, base_addr); else if (base_addr != 0) /* Don't probe at all. */ @@ -301,6 +312,9 @@ ei_status.reset_8390 = &ultra_reset_8390; dev->open = &ultra_open; dev->stop = &ultra_close_card; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; diff -Nru a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c --- a/drivers/net/smc-ultra32.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/smc-ultra32.c Sun Mar 14 14:20:08 2004 @@ -268,6 +268,9 @@ ei_status.reset_8390 = &ultra32_reset_8390; dev->open = &ultra32_open; dev->stop = &ultra32_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); return 0; diff -Nru a/drivers/net/smc9194.c b/drivers/net/smc9194.c --- a/drivers/net/smc9194.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/smc9194.c Sun Mar 14 14:20:08 2004 @@ -465,7 +465,7 @@ */ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * dev ) { - struct smc_local *lp = (struct smc_local *)dev->priv; + struct smc_local *lp = netdev_priv(dev); unsigned short ioaddr = dev->base_addr; word length; unsigned short numPages; @@ -576,7 +576,7 @@ */ static void smc_hardware_send_packet( struct net_device * dev ) { - struct smc_local *lp = (struct smc_local *)dev->priv; + struct smc_local *lp = netdev_priv(dev); byte packet_no; struct sk_buff * skb = lp->saved_skb; word length; @@ -1150,7 +1150,7 @@ { struct net_device *dev = dev_id; int ioaddr = dev->base_addr; - struct smc_local *lp = (struct smc_local *)dev->priv; + struct smc_local *lp = netdev_priv(dev); byte status; word card_stats; @@ -1274,7 +1274,7 @@ */ static void smc_rcv(struct net_device *dev) { - struct smc_local *lp = (struct smc_local *)dev->priv; + struct smc_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; int packet_number; word status; @@ -1401,7 +1401,7 @@ static void smc_tx( struct net_device * dev ) { int ioaddr = dev->base_addr; - struct smc_local *lp = (struct smc_local *)dev->priv; + struct smc_local *lp = netdev_priv(dev); byte saved_packet; byte packet_no; word tx_status; @@ -1474,7 +1474,7 @@ . This may be called with the card open or closed. .-------------------------------------------------------------*/ static struct net_device_stats* smc_query_statistics(struct net_device *dev) { - struct smc_local *lp = (struct smc_local *)dev->priv; + struct smc_local *lp = netdev_priv(dev); return &lp->stats; } diff -Nru a/drivers/net/starfire.c b/drivers/net/starfire.c --- a/drivers/net/starfire.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/starfire.c Sun Mar 14 14:20:06 2004 @@ -1637,10 +1637,13 @@ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ - pci_dma_sync_single(np->pci_dev, - np->rx_info[entry].mapping, - pkt_len, PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(np->pci_dev, + np->rx_info[entry].mapping, + pkt_len, PCI_DMA_FROMDEVICE); eth_copy_and_sum(skb, np->rx_info[entry].skb->tail, pkt_len, 0); + pci_dma_sync_single_for_device(np->pci_dev, + np->rx_info[entry].mapping, + pkt_len, PCI_DMA_FROMDEVICE); skb_put(skb, pkt_len); } else { pci_unmap_single(np->pci_dev, np->rx_info[entry].mapping, np->rx_buf_sz, PCI_DMA_FROMDEVICE); diff -Nru a/drivers/net/stnic.c b/drivers/net/stnic.c --- a/drivers/net/stnic.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/stnic.c Sun Mar 14 14:20:07 2004 @@ -124,6 +124,9 @@ dev->irq = IRQ_STNIC; dev->open = &stnic_open; dev->stop = &stnic_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif /* Snarf the interrupt now. There's no point in waiting since we cannot share and the board will usually be enabled. */ diff -Nru a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c --- a/drivers/net/sun3lance.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/sun3lance.c Sun Mar 14 14:20:08 2004 @@ -332,7 +332,7 @@ return 0; } - lp = (struct lance_private *)dev->priv; + lp = netdev_priv(dev); /* XXX - leak? */ MEM = dvma_malloc_align(sizeof(struct lance_memory), 0x10000); @@ -402,7 +402,7 @@ static int lance_open( struct net_device *dev ) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); int i; DPRINTK( 2, ( "%s: lance_open()\n", dev->name )); @@ -439,7 +439,7 @@ static void lance_init_ring( struct net_device *dev ) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); int i; lp->lock = 0; @@ -499,7 +499,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); int entry, len; struct lance_tx_head *head; unsigned long flags; @@ -646,7 +646,7 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id, struct pt_regs *fp) { struct net_device *dev = dev_id; - struct lance_private *lp = dev->priv; + struct lance_private *lp = netdev_priv(dev); int csr0; static int in_interrupt; @@ -772,7 +772,7 @@ /* get packet, toss into skbuff */ static int lance_rx( struct net_device *dev ) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); int entry = lp->new_rx; /* If we own the next entry, it's a new packet. Send it up. */ @@ -870,7 +870,7 @@ static int lance_close( struct net_device *dev ) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); netif_stop_queue(dev); @@ -888,7 +888,7 @@ static struct net_device_stats *lance_get_stats( struct net_device *dev ) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); return &lp->stats; } @@ -904,7 +904,7 @@ /* completely untested on a sun3 */ static void set_multicast_list( struct net_device *dev ) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); if(netif_queue_stopped(dev)) /* Only possible if board is already started */ diff -Nru a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c --- a/drivers/net/sunbmac.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/sunbmac.c Sun Mar 14 14:20:07 2004 @@ -849,9 +849,13 @@ copy_skb->dev = bp->dev; skb_reserve(copy_skb, 2); skb_put(copy_skb, len); - sbus_dma_sync_single(bp->bigmac_sdev, - this->rx_addr, len, SBUS_DMA_FROMDEVICE); + sbus_dma_sync_single_for_cpu(bp->bigmac_sdev, + this->rx_addr, len, + SBUS_DMA_FROMDEVICE); eth_copy_and_sum(copy_skb, (unsigned char *)skb->data, len, 0); + sbus_dma_sync_single_for_device(bp->bigmac_sdev, + this->rx_addr, len, + SBUS_DMA_FROMDEVICE); /* Reuse original ring buffer. */ this->rx_flags = diff -Nru a/drivers/net/sundance.c b/drivers/net/sundance.c --- a/drivers/net/sundance.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/sundance.c Sun Mar 14 14:20:07 2004 @@ -1331,9 +1331,6 @@ if (netif_msg_rx_status(np)) printk(KERN_DEBUG " netdev_rx() status was %8.8x.\n", frame_status); - pci_dma_sync_single(np->pci_dev, desc->frag[0].addr, - np->rx_buf_sz, PCI_DMA_FROMDEVICE); - if (frame_status & 0x001f4000) { /* There was a error. */ if (netif_msg_rx_err(np)) @@ -1363,7 +1360,16 @@ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ + pci_dma_sync_single_for_cpu(np->pci_dev, + desc->frag[0].addr, + np->rx_buf_sz, + PCI_DMA_FROMDEVICE); + eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0); + pci_dma_sync_single_for_device(np->pci_dev, + desc->frag[0].addr, + np->rx_buf_sz, + PCI_DMA_FROMDEVICE); skb_put(skb, pkt_len); } else { pci_unmap_single(np->pci_dev, diff -Nru a/drivers/net/sungem.c b/drivers/net/sungem.c --- a/drivers/net/sungem.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/sungem.c Sun Mar 14 14:20:08 2004 @@ -763,8 +763,9 @@ copy_skb->dev = gp->dev; skb_reserve(copy_skb, 2); skb_put(copy_skb, len); - pci_dma_sync_single(gp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(gp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE); memcpy(copy_skb->data, skb->data, len); + pci_dma_sync_single_for_device(gp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE); /* We'll reuse the original ring buffer. */ skb = copy_skb; diff -Nru a/drivers/net/sunhme.c b/drivers/net/sunhme.c --- a/drivers/net/sunhme.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/sunhme.c Sun Mar 14 14:20:06 2004 @@ -273,8 +273,10 @@ ((__hp)->dma_map((__hp)->happy_dev, (__ptr), (__size), (__dir))) #define hme_dma_unmap(__hp, __addr, __size, __dir) \ ((__hp)->dma_unmap((__hp)->happy_dev, (__addr), (__size), (__dir))) -#define hme_dma_sync(__hp, __addr, __size, __dir) \ - ((__hp)->dma_sync((__hp)->happy_dev, (__addr), (__size), (__dir))) +#define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \ + ((__hp)->dma_sync_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir))) +#define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \ + ((__hp)->dma_sync_for_device((__hp)->happy_dev, (__addr), (__size), (__dir))) #else #ifdef CONFIG_SBUS /* SBUS only compilation */ @@ -297,8 +299,10 @@ sbus_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir)) #define hme_dma_unmap(__hp, __addr, __size, __dir) \ sbus_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir)) -#define hme_dma_sync(__hp, __addr, __size, __dir) \ - sbus_dma_sync_single((__hp)->happy_dev, (__addr), (__size), (__dir)) +#define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \ + sbus_dma_sync_single_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir)) +#define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \ + sbus_dma_sync_single_for_device((__hp)->happy_dev, (__addr), (__size), (__dir)) #else /* PCI only compilation */ #define hme_write32(__hp, __reg, __val) \ @@ -320,8 +324,10 @@ pci_map_single((__hp)->happy_dev, (__ptr), (__size), (__dir)) #define hme_dma_unmap(__hp, __addr, __size, __dir) \ pci_unmap_single((__hp)->happy_dev, (__addr), (__size), (__dir)) -#define hme_dma_sync(__hp, __addr, __size, __dir) \ - pci_dma_sync_single((__hp)->happy_dev, (__addr), (__size), (__dir)) +#define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \ + pci_dma_sync_single_for_cpu((__hp)->happy_dev, (__addr), (__size), (__dir)) +#define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \ + pci_dma_sync_single_for_device((__hp)->happy_dev, (__addr), (__size), (__dir)) #endif #endif @@ -2069,8 +2075,9 @@ copy_skb->dev = dev; skb_reserve(copy_skb, 2); skb_put(copy_skb, len); - hme_dma_sync(hp, dma_addr, len, DMA_FROMDEVICE); + hme_dma_sync_for_cpu(hp, dma_addr, len, DMA_FROMDEVICE); memcpy(copy_skb->data, skb->data, len); + hme_dma_sync_for_device(hp, dma_addr, len, DMA_FROMDEVICE); /* Reuse original ring buffer. */ hme_write_rxd(hp, this, @@ -2838,7 +2845,10 @@ hp->write_rxd = sbus_hme_write_rxd; hp->dma_map = (u32 (*)(void *, void *, long, int))sbus_map_single; hp->dma_unmap = (void (*)(void *, u32, long, int))sbus_unmap_single; - hp->dma_sync = (void (*)(void *, u32, long, int))sbus_dma_sync_single; + hp->dma_sync_for_cpu = (void (*)(void *, u32, long, int)) + sbus_dma_sync_single_for_cpu; + hp->dma_sync_for_device = (void (*)(void *, u32, long, int)) + sbus_dma_sync_single_for_device; hp->read32 = sbus_hme_read32; hp->write32 = sbus_hme_write32; #endif @@ -3182,7 +3192,10 @@ hp->write_rxd = pci_hme_write_rxd; hp->dma_map = (u32 (*)(void *, void *, long, int))pci_map_single; hp->dma_unmap = (void (*)(void *, u32, long, int))pci_unmap_single; - hp->dma_sync = (void (*)(void *, u32, long, int))pci_dma_sync_single; + hp->dma_sync_for_cpu = (void (*)(void *, u32, long, int)) + pci_dma_sync_single_for_cpu; + hp->dma_sync_for_device = (void (*)(void *, u32, long, int)) + pci_dma_sync_single_for_device; hp->read32 = pci_hme_read32; hp->write32 = pci_hme_write32; #endif diff -Nru a/drivers/net/sunhme.h b/drivers/net/sunhme.h --- a/drivers/net/sunhme.h Sun Mar 14 14:20:07 2004 +++ b/drivers/net/sunhme.h Sun Mar 14 14:20:07 2004 @@ -406,7 +406,8 @@ void (*write_rxd)(struct happy_meal_rxd *, u32, u32); u32 (*dma_map)(void *, void *, long, int); void (*dma_unmap)(void *, u32, long, int); - void (*dma_sync)(void *, u32, long, int); + void (*dma_sync_for_cpu)(void *, u32, long, int); + void (*dma_sync_for_device)(void *, u32, long, int); #endif /* This is either a sbus_dev or a pci_dev. */ diff -Nru a/drivers/net/sunlance.c b/drivers/net/sunlance.c --- a/drivers/net/sunlance.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/sunlance.c Sun Mar 14 14:20:06 2004 @@ -313,7 +313,7 @@ /* Setup the Lance Rx and Tx rings */ static void lance_init_ring_dvma(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; dma_addr_t aib = lp->init_block_dvma; __u32 leptr; @@ -370,7 +370,7 @@ static void lance_init_ring_pio(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; u32 leptr; int i; @@ -500,7 +500,7 @@ static void lance_rx_dvma(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; volatile struct lance_rx_desc *rd; u8 bits; @@ -563,7 +563,7 @@ static void lance_tx_dvma(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; int i, j; @@ -673,7 +673,7 @@ static void lance_rx_pio(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; volatile struct lance_rx_desc *rd; unsigned char bits; @@ -735,7 +735,7 @@ static void lance_tx_pio(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; int i, j; @@ -816,7 +816,7 @@ static irqreturn_t lance_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_id; - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); int csr0; sbus_writew(LE_CSR0, lp->lregs + RAP); @@ -915,7 +915,7 @@ static int lance_open(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *)dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; int status = 0; @@ -968,7 +968,7 @@ static int lance_close(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); netif_stop_queue(dev); del_timer_sync(&lp->multicast_timer); @@ -981,7 +981,7 @@ static int lance_reset(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); int status; STOP_LANCE(lp); @@ -1102,7 +1102,7 @@ static void lance_tx_timeout(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); printk(KERN_ERR "%s: transmit timed out, status %04x, reset\n", dev->name, sbus_readw(lp->lregs + RDP)); @@ -1112,7 +1112,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; int entry, skblen, len; @@ -1165,7 +1165,7 @@ static struct net_device_stats *lance_get_stats(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); return &lp->stats; } @@ -1173,7 +1173,7 @@ /* taken from the depca driver */ static void lance_load_multicast(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; volatile u16 *mcast_table = (u16 *) &ib->filter; struct dev_mc_list *dmi = dev->mc_list; @@ -1223,7 +1223,7 @@ static void lance_set_multicast(struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); volatile struct lance_init_block *ib = lp->init_block; u16 mode; @@ -1291,7 +1291,7 @@ /* Ethtool support... */ static void sparc_lance_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct lance_private *lp = dev->priv; + struct lance_private *lp = netdev_priv(dev); strcpy(info->driver, "sunlance"); strcpy(info->version, "2.02"); @@ -1325,7 +1325,7 @@ if (!dev) return -ENOMEM; - lp = dev->priv; + lp = netdev_priv(dev); if (sparc_lance_debug && version_printed++ == 0) printk (KERN_INFO "%s", version); diff -Nru a/drivers/net/tg3.c b/drivers/net/tg3.c --- a/drivers/net/tg3.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/tg3.c Sun Mar 14 14:20:07 2004 @@ -2280,8 +2280,9 @@ copy_skb->dev = tp->dev; skb_reserve(copy_skb, 2); skb_put(copy_skb, len); - pci_dma_sync_single(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE); memcpy(copy_skb->data, skb->data, len); + pci_dma_sync_single_for_device(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE); /* We'll reuse the original ring buffer. */ skb = copy_skb; @@ -2466,6 +2467,13 @@ static int tg3_init_hw(struct tg3 *); static int tg3_halt(struct tg3 *); +#ifdef CONFIG_NET_POLL_CONTROLLER +static void tg3_poll_controller(struct net_device *dev) +{ + tg3_interrupt(dev->irq, dev, NULL); +} +#endif + static void tg3_reset_task(void *_data) { struct tg3 *tp = _data; @@ -7614,6 +7622,9 @@ dev->watchdog_timeo = TG3_TX_TIMEOUT; dev->change_mtu = tg3_change_mtu; dev->irq = pdev->irq; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = tg3_poll_controller; +#endif err = tg3_get_invariants(tp); if (err) { diff -Nru a/drivers/net/tlan.c b/drivers/net/tlan.c --- a/drivers/net/tlan.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/tlan.c Sun Mar 14 14:20:06 2004 @@ -814,6 +814,14 @@ } /* TLan_EisaProbe */ +#ifdef CONFIG_NET_POLL_CONTROLLER +static void TLan_Poll(struct net_device *dev) +{ + disable_irq(dev->irq); + TLan_HandleInterrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif @@ -893,6 +901,9 @@ dev->get_stats = &TLan_GetStats; dev->set_multicast_list = &TLan_SetMulticastList; dev->do_ioctl = &TLan_ioctl; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = &TLan_Poll; +#endif dev->tx_timeout = &TLan_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; diff -Nru a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c --- a/drivers/net/tokenring/3c359.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/tokenring/3c359.c Sun Mar 14 14:20:08 2004 @@ -937,15 +937,17 @@ while (xl_priv->rx_ring_tail != temp_ring_loc) { copy_len = xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfraglen & 0x7FFF ; frame_length -= copy_len ; - pci_dma_sync_single(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; + pci_dma_sync_single_for_cpu(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; memcpy(skb_put(skb,copy_len), xl_priv->rx_ring_skb[xl_priv->rx_ring_tail]->data, copy_len) ; + pci_dma_sync_single_for_device(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; adv_rx_ring(dev) ; } /* Now we have found the last fragment */ - pci_dma_sync_single(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; + pci_dma_sync_single_for_cpu(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; memcpy(skb_put(skb,copy_len), xl_priv->rx_ring_skb[xl_priv->rx_ring_tail]->data, frame_length) ; /* memcpy(skb_put(skb,frame_length), bus_to_virt(xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr), frame_length) ; */ + pci_dma_sync_single_for_device(xl_priv->pdev,xl_priv->xl_rx_ring[xl_priv->rx_ring_tail].upfragaddr,xl_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; adv_rx_ring(dev) ; skb->protocol = tr_type_trans(skb,dev) ; netif_rx(skb) ; diff -Nru a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c --- a/drivers/net/tokenring/abyss.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/tokenring/abyss.c Sun Mar 14 14:20:06 2004 @@ -154,7 +154,7 @@ printk(":%2.2x", dev->dev_addr[i]); printk("\n"); - tp = dev->priv; + tp = netdev_priv(dev); tp->setnselout = abyss_setnselout_pins; tp->sifreadb = abyss_sifreadb; tp->sifreadw = abyss_sifreadw; @@ -188,7 +188,7 @@ static unsigned short abyss_setnselout_pins(struct net_device *dev) { unsigned short val = 0; - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(tp->DataRate == SPEED_4) val |= 0x01; /* Set 4Mbps */ @@ -398,7 +398,7 @@ unsigned short val; int i; - tp = (struct net_local *)dev->priv; + tp = netdev_priv(dev); ioaddr = dev->base_addr; /* Must enable glue chip first */ diff -Nru a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c --- a/drivers/net/tokenring/madgemc.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/tokenring/madgemc.c Sun Mar 14 14:20:08 2004 @@ -365,7 +365,7 @@ return 0; return -1; } - tp = (struct net_local *)dev->priv; + tp = netdev_priv(dev); /* * The MC16 is physically a 32bit card. However, Madge @@ -504,7 +504,7 @@ unsigned short madgemc_setnselout_pins(struct net_device *dev) { unsigned char reg1; - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); reg1 = inb(dev->base_addr + MC_CONTROL_REG1); @@ -731,7 +731,7 @@ } len += sprintf(buf+len, "-------\n"); if (curcard) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int i; len += sprintf(buf+len, "Card Revision: %d\n", curcard->cardrev); diff -Nru a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c --- a/drivers/net/tokenring/olympic.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/tokenring/olympic.c Sun Mar 14 14:20:08 2004 @@ -842,10 +842,13 @@ olympic_priv->rx_ring_skb[rx_ring_last_received] = skb ; netif_rx(skb2) ; } else { - pci_dma_sync_single(olympic_priv->pdev, + pci_dma_sync_single_for_cpu(olympic_priv->pdev, le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer), olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; memcpy(skb_put(skb,length-4),olympic_priv->rx_ring_skb[rx_ring_last_received]->data,length-4) ; + pci_dma_sync_single_for_device(olympic_priv->pdev, + le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer), + olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; skb->protocol = tr_type_trans(skb,dev) ; netif_rx(skb) ; } @@ -854,12 +857,15 @@ olympic_priv->rx_ring_last_received++ ; olympic_priv->rx_ring_last_received &= (OLYMPIC_RX_RING_SIZE -1); rx_ring_last_received = olympic_priv->rx_ring_last_received ; - pci_dma_sync_single(olympic_priv->pdev, + pci_dma_sync_single_for_cpu(olympic_priv->pdev, le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer), olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; rx_desc = &(olympic_priv->olympic_rx_ring[rx_ring_last_received]); cpy_length = (i == 1 ? frag_len : le32_to_cpu(rx_desc->res_length)); memcpy(skb_put(skb, cpy_length), olympic_priv->rx_ring_skb[rx_ring_last_received]->data, cpy_length) ; + pci_dma_sync_single_for_device(olympic_priv->pdev, + le32_to_cpu(olympic_priv->olympic_rx_ring[rx_ring_last_received].buffer), + olympic_priv->pkt_buf_sz,PCI_DMA_FROMDEVICE) ; } while (--i) ; skb_trim(skb,skb->len-4) ; skb->protocol = tr_type_trans(skb,dev); diff -Nru a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c --- a/drivers/net/tokenring/proteon.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/tokenring/proteon.c Sun Mar 14 14:20:08 2004 @@ -158,7 +158,7 @@ printk(":%2.2x", dev->dev_addr[j]); printk("\n"); - tp = (struct net_local *)dev->priv; + tp = netdev_priv(dev); tp->setnselout = proteon_setnselout_pins; tp->sifreadb = proteon_sifreadb; @@ -316,7 +316,7 @@ static int proteon_open(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned short val = 0; int i; diff -Nru a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c --- a/drivers/net/tokenring/skisa.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/tokenring/skisa.c Sun Mar 14 14:20:06 2004 @@ -175,7 +175,7 @@ printk(":%2.2x", dev->dev_addr[j]); printk("\n"); - tp = (struct net_local *)dev->priv; + tp = netdev_priv(dev); tp->setnselout = sk_isa_setnselout_pins; tp->sifreadb = sk_isa_sifreadb; @@ -332,7 +332,7 @@ static int sk_isa_open(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned short val = 0; unsigned short oldval; int i; diff -Nru a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c --- a/drivers/net/tokenring/smctr.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/tokenring/smctr.c Sun Mar 14 14:20:07 2004 @@ -327,7 +327,7 @@ */ static int smctr_alloc_shared_memory(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(smctr_debug > 10) printk(KERN_DEBUG "%s: smctr_alloc_shared_memory\n", dev->name); @@ -454,7 +454,7 @@ static int smctr_checksum_firmware(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); __u16 i, checksum = 0; if(smctr_debug > 10) @@ -477,10 +477,10 @@ return (0); } -static int smctr_chk_mca(struct net_device *dev) +static int __init smctr_chk_mca(struct net_device *dev) { #ifdef CONFIG_MCA - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int current_slot; __u8 r1, r2, r3, r4, r5; @@ -631,7 +631,7 @@ static int smctr_chg_rx_mask(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err = 0; if(smctr_debug > 10) @@ -694,7 +694,7 @@ static int smctr_clear_int(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); outb((tp->trc_mask | CSR_CLRTINT), dev->base_addr + CSR); @@ -716,7 +716,7 @@ */ static int smctr_close(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); struct sk_buff *skb; int err; @@ -752,7 +752,7 @@ static int smctr_decode_firmware(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); short bit = 0x80, shift = 12; DECODE_TREE_NODE *tree; short branch, tsize; @@ -823,7 +823,7 @@ */ static int smctr_disable_adapter_ctrl_store(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int ioaddr = dev->base_addr; if(smctr_debug > 10) @@ -837,7 +837,7 @@ static int smctr_disable_bic_int(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int ioaddr = dev->base_addr; tp->trc_mask = CSR_MSK_ALL | CSR_MSKCBUSY @@ -849,7 +849,7 @@ static int smctr_enable_16bit(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); __u8 r; if(tp->adapter_bus == BUS_ISA16_TYPE) @@ -869,7 +869,7 @@ */ static int smctr_enable_adapter_ctrl_store(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int ioaddr = dev->base_addr; if(smctr_debug > 10) @@ -900,7 +900,7 @@ static int smctr_enable_bic_int(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int ioaddr = dev->base_addr; __u8 r; @@ -926,7 +926,7 @@ static int __init smctr_chk_isa(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int ioaddr = dev->base_addr; __u8 r1, r2, b, chksum = 0; __u16 r; @@ -1155,7 +1155,7 @@ static int __init smctr_get_boardid(struct net_device *dev, int mca) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int ioaddr = dev->base_addr; __u8 r, r1, IdByte; __u16 BoardIdMask; @@ -1273,7 +1273,7 @@ */ static unsigned int smctr_get_num_rx_bdbs(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int mem_used = 0; /* Allocate System Control Blocks. */ @@ -1358,7 +1358,7 @@ static __u8 * smctr_get_rx_pointer(struct net_device *dev, short queue) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); BDBlock *bdb; bdb = (BDBlock *)((__u32)tp->ram_access @@ -1382,7 +1382,7 @@ */ static struct net_device_stats *smctr_get_stats(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); return ((struct net_device_stats *)&tp->MacStat); } @@ -1390,7 +1390,7 @@ static FCBlock *smctr_get_tx_fcb(struct net_device *dev, __u16 queue, __u16 bytes_count) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); FCBlock *pFCB; BDBlock *pbdb; unsigned short alloc_size; @@ -1513,7 +1513,7 @@ static int smctr_init_acbs(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int i; ACBlock *acb; @@ -1557,7 +1557,7 @@ static int smctr_init_adapter(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err; if(smctr_debug > 10) @@ -1640,7 +1640,7 @@ static int smctr_init_card_real(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err = 0; if(smctr_debug > 10) @@ -1716,7 +1716,7 @@ static int smctr_init_rx_bdbs(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int i, j; BDBlock *bdb; __u16 *buf; @@ -1768,7 +1768,7 @@ static int smctr_init_rx_fcbs(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int i, j; FCBlock *fcb; @@ -1818,7 +1818,7 @@ static int smctr_init_shared_memory(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int i; __u32 *iscpb; @@ -1876,7 +1876,7 @@ static int smctr_init_tx_bdbs(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int i, j; BDBlock *bdb; @@ -1906,7 +1906,7 @@ static int smctr_init_tx_fcbs(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int i, j; FCBlock *fcb; @@ -1945,7 +1945,7 @@ static int smctr_internal_self_test(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err; if((err = smctr_issue_test_internal_rom_cmd(dev))) @@ -1998,7 +1998,7 @@ } ioaddr = dev->base_addr; - tp = (struct net_local *)dev->priv; + tp = netdev_priv(dev); if(tp->status == NOT_INITIALIZED) @@ -2471,7 +2471,7 @@ static int smctr_issue_enable_int_cmd(struct net_device *dev, __u16 interrupt_enable_mask) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err; if((err = smctr_wait_while_cbusy(dev))) @@ -2487,7 +2487,7 @@ static int smctr_issue_int_ack(struct net_device *dev, __u16 iack_code, __u16 ibits) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(smctr_wait_while_cbusy(dev)) return (-1); @@ -2503,7 +2503,7 @@ static int smctr_issue_init_timers_cmd(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int i; int err; __u16 *pTimer_Struc = (__u16 *)tp->misc_command_data; @@ -2660,7 +2660,7 @@ static int smctr_issue_init_txrx_cmd(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int i; int err; void **txrx_ptrs = (void *)tp->misc_command_data; @@ -2748,7 +2748,7 @@ static int smctr_issue_remove_cmd(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err; if((err = smctr_wait_while_cbusy(dev))) @@ -2764,7 +2764,7 @@ static int smctr_issue_resume_acb_cmd(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err; if((err = smctr_wait_while_cbusy(dev))) @@ -2782,7 +2782,7 @@ static int smctr_issue_resume_rx_bdb_cmd(struct net_device *dev, __u16 queue) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err; if((err = smctr_wait_while_cbusy(dev))) @@ -2802,7 +2802,7 @@ static int smctr_issue_resume_rx_fcb_cmd(struct net_device *dev, __u16 queue) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(smctr_debug > 10) printk(KERN_DEBUG "%s: smctr_issue_resume_rx_fcb_cmd\n", dev->name); @@ -2824,7 +2824,7 @@ static int smctr_issue_resume_tx_fcb_cmd(struct net_device *dev, __u16 queue) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(smctr_debug > 10) printk(KERN_DEBUG "%s: smctr_issue_resume_tx_fcb_cmd\n", dev->name); @@ -2893,7 +2893,7 @@ static int smctr_issue_write_byte_cmd(struct net_device *dev, short aword_cnt, void *byte) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int iword, ibyte; int err; @@ -2917,7 +2917,7 @@ static int smctr_issue_write_word_cmd(struct net_device *dev, short aword_cnt, void *word) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int i, err; if((err = smctr_wait_while_cbusy(dev))) @@ -2947,7 +2947,7 @@ static int smctr_link_tx_fcbs_to_bdbs(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int i, j; FCBlock *fcb; BDBlock *bdb; @@ -2971,7 +2971,7 @@ static int smctr_load_firmware(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); __u16 i, checksum = 0; int err = 0; @@ -3071,7 +3071,7 @@ */ static int smctr_lobe_media_test(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int i, perror = 0; unsigned short saved_rcv_mask; @@ -3146,7 +3146,7 @@ static int smctr_lobe_media_test_cmd(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err; if(smctr_debug > 10) @@ -3230,7 +3230,7 @@ static int smctr_make_access_pri(struct net_device *dev, MAC_SUB_VECTOR *tsv) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); tsv->svi = AUTHORIZED_ACCESS_PRIORITY; tsv->svl = S_AUTHORIZED_ACCESS_PRIORITY; @@ -3255,7 +3255,7 @@ static int smctr_make_auth_funct_class(struct net_device *dev, MAC_SUB_VECTOR *tsv) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); tsv->svi = AUTHORIZED_FUNCTION_CLASS; tsv->svl = S_AUTHORIZED_FUNCTION_CLASS; @@ -3280,7 +3280,7 @@ static int smctr_make_funct_addr(struct net_device *dev, MAC_SUB_VECTOR *tsv) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); smctr_get_functional_address(dev); @@ -3298,7 +3298,7 @@ static int smctr_make_group_addr(struct net_device *dev, MAC_SUB_VECTOR *tsv) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); smctr_get_group_address(dev); @@ -3324,7 +3324,7 @@ static int smctr_make_phy_drop_num(struct net_device *dev, MAC_SUB_VECTOR *tsv) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); smctr_get_physical_drop_number(dev); @@ -3355,7 +3355,7 @@ static int smctr_make_station_id(struct net_device *dev, MAC_SUB_VECTOR *tsv) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); smctr_get_station_id(dev); @@ -3393,7 +3393,7 @@ static int smctr_make_ring_station_version(struct net_device *dev, MAC_SUB_VECTOR *tsv) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); tsv->svi = RING_STATION_VERSION_NUMBER; tsv->svl = S_RING_STATION_VERSION_NUMBER; @@ -3433,7 +3433,7 @@ static int smctr_make_upstream_neighbor_addr(struct net_device *dev, MAC_SUB_VECTOR *tsv) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); smctr_get_upstream_neighbor_addr(dev); @@ -3485,7 +3485,7 @@ /* Interrupt driven open of Token card. */ static int smctr_open_tr(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned long flags; int err; @@ -3618,7 +3618,7 @@ return dev; out1: #ifdef CONFIG_MCA - { struct net_local *tp = (struct net_local *)dev->priv; + { struct net_local *tp = netdev_priv(dev); if (tp->slot_num) mca_mark_as_unused(tp->slot_num); } @@ -3634,7 +3634,7 @@ static int __init smctr_probe1(struct net_device *dev, int ioaddr) { static unsigned version_printed; - struct net_local *tp = dev->priv; + struct net_local *tp = netdev_priv(dev); int err; __u32 *ram; @@ -3654,7 +3654,7 @@ } } - tp = (struct net_local *)dev->priv; + tp = netdev_priv(dev); dev->mem_start = tp->ram_base; dev->mem_end = dev->mem_start + 0x10000; ram = (__u32 *)phys_to_virt(dev->mem_start); @@ -3696,7 +3696,7 @@ static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size, struct net_device *dev, __u16 rx_status) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); struct sk_buff *skb; __u16 rcode, correlator; int err = 0; @@ -3917,7 +3917,7 @@ /* Adapter RAM test. Incremental word ODD boundary data test. */ static int smctr_ram_memory_test(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); __u16 page, pages_of_ram, start_pattern = 0, word_pattern = 0, word_read = 0, err_word = 0, err_pattern = 0; unsigned int err_offset; @@ -4310,7 +4310,7 @@ */ static int smctr_reset_adapter(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int ioaddr = dev->base_addr; /* Reseting the NIC will put it in a halted and un-initialized state. */ smctr_set_trc_reset(ioaddr); @@ -4329,7 +4329,7 @@ static int smctr_restart_tx_chain(struct net_device *dev, short queue) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err = 0; if(smctr_debug > 10) @@ -4347,7 +4347,7 @@ static int smctr_ring_status_chg(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(smctr_debug > 10) printk(KERN_DEBUG "%s: smctr_ring_status_chg\n", dev->name); @@ -4449,7 +4449,7 @@ static int smctr_rx_frame(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); __u16 queue, status, rx_size, err = 0; __u8 *pbuff; @@ -4516,7 +4516,7 @@ static int smctr_send_dat(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int i, err; MAC_HEADER *tmf; FCBlock *fcb; @@ -4596,7 +4596,7 @@ */ static int smctr_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(smctr_debug > 10) printk(KERN_DEBUG "%s: smctr_send_packet\n", dev->name); @@ -4621,7 +4621,7 @@ static int smctr_send_lobe_media_test(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); MAC_SUB_VECTOR *tsv; MAC_HEADER *tmf; FCBlock *fcb; @@ -4917,7 +4917,7 @@ static int smctr_send_rq_init(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); MAC_HEADER *tmf; MAC_SUB_VECTOR *tsv; FCBlock *fcb; @@ -5001,7 +5001,7 @@ static int smctr_send_tx_forward(struct net_device *dev, MAC_HEADER *rmf, __u16 *tx_fstatus) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); FCBlock *fcb; unsigned int i; int err; @@ -5065,7 +5065,7 @@ static int smctr_set_auth_access_pri(struct net_device *dev, MAC_SUB_VECTOR *rsv) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(rsv->svl != S_AUTHORIZED_ACCESS_PRIORITY) return (E_SUB_VECTOR_LENGTH_ERROR); @@ -5078,7 +5078,7 @@ static int smctr_set_auth_funct_class(struct net_device *dev, MAC_SUB_VECTOR *rsv) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(rsv->svl != S_AUTHORIZED_FUNCTION_CLASS) return (E_SUB_VECTOR_LENGTH_ERROR); @@ -5139,7 +5139,7 @@ static int smctr_set_local_ring_num(struct net_device *dev, MAC_SUB_VECTOR *rsv) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(rsv->svl != S_LOCAL_RING_NUMBER) return (E_SUB_VECTOR_LENGTH_ERROR); @@ -5153,7 +5153,7 @@ static unsigned short smctr_set_ctrl_attention(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int ioaddr = dev->base_addr; if(tp->bic_type == BIC_585_CHIP) @@ -5177,7 +5177,7 @@ static int smctr_set_page(struct net_device *dev, __u8 *buf) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); __u8 amask; __u32 tptr; @@ -5207,7 +5207,7 @@ */ static int smctr_set_ring_speed(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err; if(tp->media_type == MEDIA_UTP_16) @@ -5235,7 +5235,7 @@ static int smctr_set_rx_look_ahead(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); __u16 sword, rword; if(smctr_debug > 10) @@ -5278,7 +5278,7 @@ static int smctr_setup_single_cmd(struct net_device *dev, __u16 command, __u16 subcommand) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int err; if(smctr_debug > 10) @@ -5305,7 +5305,7 @@ static int smctr_setup_single_cmd_w_data(struct net_device *dev, __u16 command, __u16 subcommand) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); tp->acb_head->cmd_done_status = ACB_COMMAND_NOT_DONE; tp->acb_head->cmd = command; @@ -5318,7 +5318,7 @@ static char *smctr_malloc(struct net_device *dev, __u16 size) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); char *m; m = (char *)(tp->ram_access + tp->sh_mem_used); @@ -5329,7 +5329,7 @@ static int smctr_status_chg(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(smctr_debug > 10) printk(KERN_DEBUG "%s: smctr_status_chg\n", dev->name); @@ -5365,7 +5365,7 @@ static int smctr_trc_send_packet(struct net_device *dev, FCBlock *fcb, __u16 queue) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err = 0; if(smctr_debug > 10) @@ -5386,7 +5386,7 @@ static __u16 smctr_tx_complete(struct net_device *dev, __u16 queue) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); __u16 status, err = 0; int cstatus; @@ -5441,7 +5441,7 @@ static unsigned short smctr_tx_move_frame(struct net_device *dev, struct sk_buff *skb, __u8 *pbuff, unsigned int bytes) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int ram_usable; __u32 flen, len, offset = 0; __u8 *frag, *page; @@ -5482,7 +5482,7 @@ /* Update the error statistic counters for this adapter. */ static int smctr_update_err_stats(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); struct tr_statistics *tstat = &tp->MacStat; if(tstat->internal_errors) @@ -5524,7 +5524,7 @@ static int smctr_update_rx_chain(struct net_device *dev, __u16 queue) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); FCBlock *fcb; BDBlock *bdb; __u16 size, len; @@ -5562,7 +5562,7 @@ static int smctr_update_tx_chain(struct net_device *dev, FCBlock *fcb, __u16 queue) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(smctr_debug > 20) printk(KERN_DEBUG "smctr_update_tx_chain\n"); @@ -5598,7 +5598,7 @@ static int smctr_wait_cmd(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int loop_count = 0x20000; if(smctr_debug > 10) @@ -5623,7 +5623,7 @@ static int smctr_wait_while_cbusy(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int timeout = 0x20000; int ioaddr = dev->base_addr; __u8 r; @@ -5686,7 +5686,7 @@ return dev; out1: #ifdef CONFIG_MCA - { struct net_local *tp = (struct net_local *)dev->priv; + { struct net_local *tp = netdev_priv(dev); if (tp->slot_num) mca_mark_as_unused(tp->slot_num); } @@ -5726,7 +5726,7 @@ unregister_netdev(dev); #ifdef CONFIG_MCA - { struct net_local *tp = dev->priv; + { struct net_local *tp = netdev_priv(dev); if (tp->slot_num) mca_mark_as_unused(tp->slot_num); } diff -Nru a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c --- a/drivers/net/tokenring/tms380tr.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/tokenring/tms380tr.c Sun Mar 14 14:20:07 2004 @@ -243,7 +243,7 @@ */ int tms380tr_open(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err; /* init the spinlock */ @@ -313,7 +313,7 @@ static void tms380tr_timer_end_wait(unsigned long data) { struct net_device *dev = (struct net_device*)data; - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(tp->Sleeping) { @@ -329,7 +329,7 @@ */ static int tms380tr_chipset_init(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err; tms380tr_init_ipb(tp); @@ -364,7 +364,7 @@ */ static void tms380tr_init_net_local(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int i; dma_addr_t dmabuf; @@ -492,7 +492,7 @@ unsigned short BufferSize = BUFFER_SIZE; int i; - tp = (struct net_local *)dev->priv; + tp = netdev_priv(dev); tp->ocpl.OPENOptions = 0; tp->ocpl.OPENOptions |= ENABLE_FULL_DUPLEX_SELECTION; @@ -531,7 +531,7 @@ */ static void tms380tr_open_adapter(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); if(tp->OpenCommandIssued) return; @@ -569,7 +569,7 @@ */ static void tms380tr_exec_cmd(struct net_device *dev, unsigned short Command) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); tp->CMDqueue |= Command; tms380tr_chk_outstanding_cmds(dev); @@ -596,7 +596,7 @@ */ static int tms380tr_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); int err; err = tms380tr_hardware_send_packet(skb, dev); @@ -616,7 +616,7 @@ unsigned long flags; int i; dma_addr_t dmabuf, newbuf; - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); /* Try to get a free TPL from the chain. * @@ -715,7 +715,7 @@ static void tms380tr_timer_chk(unsigned long data) { struct net_device *dev = (struct net_device*)data; - struct net_local *tp = (struct net_local*)dev->priv; + struct net_local *tp = netdev_priv(dev); if(tp->HaltInProgress) return; @@ -755,7 +755,7 @@ return IRQ_NONE; } - tp = (struct net_local *)dev->priv; + tp = netdev_priv(dev); irq_type = SIFREADW(SIFSTS); @@ -843,7 +843,7 @@ */ static void tms380tr_reset_interrupt(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); SSB *ssb = &tp->ssb; /* @@ -929,7 +929,7 @@ */ static void tms380tr_cmd_status_irq(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned short ssb_cmd, ssb_parm_0; unsigned short ssb_parm_1; char *open_err = "Open error -"; @@ -1126,7 +1126,7 @@ */ int tms380tr_close(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); netif_stop_queue(dev); del_timer(&tp->timer); @@ -1172,7 +1172,7 @@ */ static struct net_device_stats *tms380tr_get_stats(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); return ((struct net_device_stats *)&tp->MacStat); } @@ -1182,7 +1182,7 @@ */ static void tms380tr_set_multicast_list(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned int OpenOptions; OpenOptions = tp->ocpl.OPENOptions & @@ -1275,7 +1275,7 @@ */ static int tms380tr_reset_adapter(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned short *fw_ptr; unsigned short count, c, count2; const struct firmware *fw_entry = NULL; @@ -1428,7 +1428,7 @@ */ static int tms380tr_init_adapter(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); const unsigned char SCB_Test[6] = {0x00, 0x00, 0xC1, 0xE2, 0xD4, 0x8B}; const unsigned char SSB_Test[8] = {0xFF, 0xFF, 0xD1, 0xD7, @@ -1541,7 +1541,7 @@ */ static void tms380tr_chk_outstanding_cmds(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned long Addr = 0; if(tp->CMDqueue == 0) @@ -1713,7 +1713,7 @@ */ static void tms380tr_ring_status_irq(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); tp->CurrentRingStatus = be16_to_cpu((unsigned short)tp->ssb.Parm[0]); @@ -1785,7 +1785,7 @@ { int i; unsigned short AdapterCheckBlock[4]; - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); tp->AdapterOpenFlag = 0; /* Adapter closed now */ @@ -1941,7 +1941,7 @@ */ static int tms380tr_read_ptr(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned short adapterram; tms380tr_read_ram(dev, (unsigned char *)&tp->intptrs.BurnedInAddrPtr, @@ -2031,7 +2031,7 @@ */ static void tms380tr_tx_status_irq(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned char HighByte, HighAc, LowAc; TPL *tpl; @@ -2102,7 +2102,7 @@ */ static void tms380tr_rcv_status_irq(struct net_device *dev) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); unsigned char *ReceiveDataPtr; struct sk_buff *skb; unsigned int Length, Length2; @@ -2293,7 +2293,7 @@ static int tms380tr_set_mac_address(struct net_device *dev, void *addr) { - struct net_local *tp = (struct net_local *)dev->priv; + struct net_local *tp = netdev_priv(dev); struct sockaddr *saddr = addr; if (tp->AdapterOpenFlag || tp->AdapterVirtOpenFlag) { @@ -2327,7 +2327,7 @@ { struct net_local *tp; - tp = (struct net_local *) dev->priv; + tp = netdev_priv(dev); pci_unmap_single(tp->pdev, tp->dmabuffer, sizeof(struct net_local), PCI_DMA_BIDIRECTIONAL); } @@ -2338,7 +2338,7 @@ struct net_local *tms_local; memset(dev->priv, 0, sizeof(struct net_local)); - tms_local = (struct net_local *)dev->priv; + tms_local = netdev_priv(dev); init_waitqueue_head(&tms_local->wait_for_tok_int); tms_local->dmalimit = dmalimit; tms_local->pdev = pdev; diff -Nru a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c --- a/drivers/net/tulip/21142.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/tulip/21142.c Sun Mar 14 14:20:06 2004 @@ -29,7 +29,7 @@ void t21142_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; int csr12 = inl(ioaddr + CSR12); int next_tick = 60*HZ; @@ -103,7 +103,7 @@ void t21142_start_nway(struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; int csr14 = ((tp->sym_advertise & 0x0780) << 9) | ((tp->sym_advertise & 0x0020) << 1) | 0xffbf; @@ -131,7 +131,7 @@ void t21142_lnk_change(struct net_device *dev, int csr5) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; int csr12 = inl(ioaddr + CSR12); diff -Nru a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c --- a/drivers/net/tulip/de2104x.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/tulip/de2104x.c Sun Mar 14 14:20:08 2004 @@ -457,9 +457,11 @@ buflen, PCI_DMA_FROMDEVICE); de->rx_skb[rx_tail].skb = copy_skb; } else { - pci_dma_sync_single(de->pdev, mapping, len, PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(de->pdev, mapping, len, PCI_DMA_FROMDEVICE); skb_reserve(copy_skb, RX_OFFSET); memcpy(skb_put(copy_skb, len), skb->tail, len); + + pci_dma_sync_single_for_device(de->pdev, mapping, len, PCI_DMA_FROMDEVICE); /* We'll reuse the original ring buffer. */ skb = copy_skb; diff -Nru a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c --- a/drivers/net/tulip/de4x5.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/tulip/de4x5.c Sun Mar 14 14:20:06 2004 @@ -1086,7 +1086,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev) { char name[DE4X5_NAME_LENGTH + 1]; - struct de4x5_private *lp = dev->priv; + struct de4x5_private *lp = netdev_priv(dev); struct pci_dev *pdev = NULL; int i, status=0; @@ -1294,7 +1294,7 @@ static int de4x5_open(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int i, status = 0; s32 omr; @@ -1384,7 +1384,7 @@ static int de4x5_sw_reset(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int i, j, status = 0; s32 bmr, omr; @@ -1462,7 +1462,7 @@ static int de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int status = 0; u_long flags = 0; @@ -1551,7 +1551,7 @@ printk ("de4x5_interrupt(): irq %d for unknown device.\n", irq); return IRQ_NONE; } - lp = (struct de4x5_private *)dev->priv; + lp = netdev_priv(dev); spin_lock(&lp->lock); iobase = dev->base_addr; @@ -1610,7 +1610,7 @@ static int de4x5_rx(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int entry; s32 status; @@ -1701,7 +1701,7 @@ static int de4x5_tx(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int entry; s32 status; @@ -1753,7 +1753,7 @@ static int de4x5_ast(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int next_tick = DE4X5_AUTOSENSE_MS; disable_ast(dev); @@ -1776,7 +1776,7 @@ static int de4x5_txur(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int omr; @@ -1799,7 +1799,7 @@ static int de4x5_rx_ovfc(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int omr; @@ -1820,7 +1820,7 @@ static int de4x5_close(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; s32 imr, omr; @@ -1856,7 +1856,7 @@ static struct net_device_stats * de4x5_get_stats(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; lp->stats.rx_missed_errors = (int)(inl(DE4X5_MFC) & (MFC_OVFL | MFC_CNTR)); @@ -1867,7 +1867,7 @@ static void de4x5_local_stats(struct net_device *dev, char *buf, int pkt_len) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int i; for (i=1; ipriv; + struct de4x5_private *lp = netdev_priv(dev); int entry = (lp->tx_new ? lp->tx_new-1 : lp->txRingSize-1); dma_addr_t buf_dma = dma_map_single(lp->gendev, buf, flags & TD_TBS1, DMA_TO_DEVICE); @@ -1927,7 +1927,7 @@ static void set_multicast_list(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; /* First, double check that the adapter is open */ @@ -1957,7 +1957,7 @@ static void SetMulticastFilter(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); struct dev_mc_list *dmi=dev->mc_list; u_long iobase = dev->base_addr; int i, j, bit, byte; @@ -2036,7 +2036,7 @@ status = -ENOMEM; goto release_reg_2; } - lp = dev->priv; + lp = netdev_priv(dev); cfid = (u32) inl(PCI_CFID); lp->cfrv = (u_short) inl(PCI_CFRV); @@ -2142,7 +2142,7 @@ u_int irq = 0, device; u_long iobase = 0; /* Clear upper 32 bits in Alphas */ int i, j, cfrv; - struct de4x5_private *lp = dev->priv; + struct de4x5_private *lp = netdev_priv(dev); struct list_head *walk = &pdev->bus_list; for (walk = walk->next; walk != &pdev->bus_list; walk = walk->next) { @@ -2245,7 +2245,7 @@ if (!(dev = alloc_etherdev (sizeof (struct de4x5_private)))) return -ENOMEM; - lp = dev->priv; + lp = netdev_priv(dev); lp->bus = PCI; lp->bus_num = 0; @@ -2374,7 +2374,7 @@ static int autoconf_media(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int next_tick = DE4X5_AUTOSENSE_MS; @@ -2415,7 +2415,7 @@ static int dc21040_autoconf(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int next_tick = DE4X5_AUTOSENSE_MS; s32 imr; @@ -2488,7 +2488,7 @@ int next_state, int suspect_state, int (*fn)(struct net_device *, int)) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int next_tick = DE4X5_AUTOSENSE_MS; int linkBad; @@ -2527,7 +2527,7 @@ int (*fn)(struct net_device *, int), int (*asfn)(struct net_device *)) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int next_tick = DE4X5_AUTOSENSE_MS; int linkBad; @@ -2569,7 +2569,7 @@ static int dc21041_autoconf(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; s32 sts, irqs, irq_mask, imr, omr; int next_tick = DE4X5_AUTOSENSE_MS; @@ -2771,7 +2771,7 @@ static int dc21140m_autoconf(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int ana, anlpa, cap, cr, slnk, sr; int next_tick = DE4X5_AUTOSENSE_MS; u_long imr, omr, iobase = dev->base_addr; @@ -2955,7 +2955,7 @@ static int dc2114x_autoconf(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; s32 cr, anlpa, ana, cap, irqs, irq_mask, imr, omr, slnk, sr, sts; int next_tick = DE4X5_AUTOSENSE_MS; @@ -3206,7 +3206,7 @@ static int srom_autoconf(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); return lp->infoleaf_fn(dev); } @@ -3219,7 +3219,7 @@ static int srom_map_media(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); lp->fdx = 0; if (lp->infoblock_media == lp->media) @@ -3284,7 +3284,7 @@ static void de4x5_init_connection(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; u_long flags = 0; @@ -3313,7 +3313,7 @@ static int de4x5_reset_phy(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int next_tick = 0; @@ -3347,7 +3347,7 @@ static int test_media(struct net_device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; s32 sts, csr12; @@ -3385,7 +3385,7 @@ static int test_tp(struct net_device *dev, s32 msec) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int sisr; @@ -3414,7 +3414,7 @@ static int test_for_100Mb(struct net_device *dev, int msec) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int gep = 0, ret = ((lp->chipset & ~0x00ff)==DC2114x? -1 :GEP_SLNK); if (lp->timeout < 0) { @@ -3445,7 +3445,7 @@ static int wait_for_link(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); if (lp->timeout < 0) { lp->timeout = 1; @@ -3467,7 +3467,7 @@ static int test_mii_reg(struct net_device *dev, int reg, int mask, int pol, long msec) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int test; u_long iobase = dev->base_addr; @@ -3491,7 +3491,7 @@ static int is_spd_100(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int spd; @@ -3515,7 +3515,7 @@ static int is_100_up(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; if (lp->useMII) { @@ -3536,7 +3536,7 @@ static int is_10_up(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; if (lp->useMII) { @@ -3559,7 +3559,7 @@ static int is_anc_capable(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; if (lp->phy[lp->active].id && (!lp->useSROM || lp->useMII)) { @@ -3578,7 +3578,7 @@ static int ping_media(struct net_device *dev, int msec) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int sisr; @@ -3619,7 +3619,7 @@ static struct sk_buff * de4x5_alloc_rx_buff(struct net_device *dev, int index, int len) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); struct sk_buff *p; #if !defined(__alpha__) && !defined(__powerpc__) && !defined(__sparc_v9__) && !defined(DE4X5_DO_MEMCPY) @@ -3667,7 +3667,7 @@ static void de4x5_free_rx_buffs(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int i; for (i=0; irxRingSize; i++) { @@ -3684,7 +3684,7 @@ static void de4x5_free_tx_buffs(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int i; for (i=0; itxRingSize; i++) { @@ -3711,7 +3711,7 @@ static void de4x5_save_skbs(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; s32 omr; @@ -3732,7 +3732,7 @@ static void de4x5_rst_desc_ring(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int i; s32 omr; @@ -3765,7 +3765,7 @@ static void de4x5_cache_state(struct net_device *dev, int flag) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; switch(flag) { @@ -3795,7 +3795,7 @@ static void de4x5_put_cache(struct net_device *dev, struct sk_buff *skb) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); struct sk_buff *p; if (lp->cache.skb) { @@ -3812,7 +3812,7 @@ static void de4x5_putb_cache(struct net_device *dev, struct sk_buff *skb) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); struct sk_buff *p = lp->cache.skb; lp->cache.skb = skb; @@ -3824,7 +3824,7 @@ static struct sk_buff * de4x5_get_cache(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); struct sk_buff *p = lp->cache.skb; if (p) { @@ -3842,7 +3842,7 @@ static int test_ans(struct net_device *dev, s32 irqs, s32 irq_mask, s32 msec) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; s32 sts, ans; @@ -3870,7 +3870,7 @@ static void de4x5_setup_intr(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; s32 imr, sts; @@ -3891,7 +3891,7 @@ static void reset_init_sia(struct net_device *dev, s32 csr13, s32 csr14, s32 csr15) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; RESET_SIA; @@ -4014,7 +4014,7 @@ DevicePresent(struct net_device *dev, u_long aprom_addr) { int i, j=0; - struct de4x5_private *lp = (struct de4x5_private *) dev->priv; + struct de4x5_private *lp = netdev_priv(dev); if (lp->chipset == DC21040) { if (lp->bus == EISA) { @@ -4095,7 +4095,7 @@ u_long iobase = dev->base_addr; int broken, i, k, tmp, status = 0; u_short j,chksum; - struct de4x5_private *lp = dev->priv; + struct de4x5_private *lp = netdev_priv(dev); broken = de4x5_bad_srom(lp); @@ -4210,7 +4210,7 @@ static void srom_repair(struct net_device *dev, int card) { - struct de4x5_private *lp = dev->priv; + struct de4x5_private *lp = netdev_priv(dev); switch(card) { case SMC: @@ -4231,7 +4231,7 @@ static int test_bad_enet(struct net_device *dev, int status) { - struct de4x5_private *lp = dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int i, tmp; for (tmp=0,i=0; idev_addr[i]; @@ -4384,7 +4384,7 @@ static int srom_infoleaf_info(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int i, count; u_char *p; @@ -4432,7 +4432,7 @@ static void srom_init(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset; u_char count; @@ -4477,7 +4477,7 @@ static void srom_exec(struct net_device *dev, u_char *p) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; u_char count = (p ? *p++ : 0); u_short *w = (u_short *)p; @@ -4514,7 +4514,7 @@ static int dc21140_infoleaf(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_char count = 0; u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset; int next_tick = DE4X5_AUTOSENSE_MS; @@ -4552,7 +4552,7 @@ static int dc21142_infoleaf(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_char count = 0; u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset; int next_tick = DE4X5_AUTOSENSE_MS; @@ -4587,7 +4587,7 @@ static int dc21143_infoleaf(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_char count = 0; u_char *p = (u_char *)&lp->srom + lp->infoleaf_offset; int next_tick = DE4X5_AUTOSENSE_MS; @@ -4625,7 +4625,7 @@ static int compact_infoblock(struct net_device *dev, u_char count, u_char *p) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_char flags, csr6; /* Recursively figure out the info blocks */ @@ -4665,7 +4665,7 @@ static int type0_infoblock(struct net_device *dev, u_char count, u_char *p) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_char flags, csr6, len = (*p & BLOCK_LEN)+1; /* Recursively figure out the info blocks */ @@ -4705,7 +4705,7 @@ static int type1_infoblock(struct net_device *dev, u_char count, u_char *p) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_char len = (*p & BLOCK_LEN)+1; /* Recursively figure out the info blocks */ @@ -4744,7 +4744,7 @@ static int type2_infoblock(struct net_device *dev, u_char count, u_char *p) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_char len = (*p & BLOCK_LEN)+1; /* Recursively figure out the info blocks */ @@ -4785,7 +4785,7 @@ static int type3_infoblock(struct net_device *dev, u_char count, u_char *p) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_char len = (*p & BLOCK_LEN)+1; /* Recursively figure out the info blocks */ @@ -4827,7 +4827,7 @@ static int type4_infoblock(struct net_device *dev, u_char count, u_char *p) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_char flags, csr6, len = (*p & BLOCK_LEN)+1; /* Recursively figure out the info blocks */ @@ -4872,7 +4872,7 @@ static int type5_infoblock(struct net_device *dev, u_char count, u_char *p) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_char len = (*p & BLOCK_LEN)+1; /* Recursively figure out the info blocks */ @@ -5072,7 +5072,7 @@ static int mii_get_phy(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; int i, j, k, n, limit=sizeof(phy_info)/sizeof(struct phy_table); int id; @@ -5136,7 +5136,7 @@ static char * build_setup_frame(struct net_device *dev, int mode) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int i; char *pa = lp->setup_frame; @@ -5176,7 +5176,7 @@ static void disable_ast(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); del_timer(&lp->timer); @@ -5186,7 +5186,7 @@ static long de4x5_switch_mac_port(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; s32 omr; @@ -5222,7 +5222,7 @@ static void gep_wr(s32 data, struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; if (lp->chipset == DC21140) { @@ -5237,7 +5237,7 @@ static int gep_rd(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; if (lp->chipset == DC21140) { @@ -5252,7 +5252,7 @@ static void timeout(struct net_device *dev, void (*fn)(u_long data), u_long data, u_long msec) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int dt; /* First, cancel any pending timer events */ @@ -5275,7 +5275,7 @@ static void yawn(struct net_device *dev, int state) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; if ((lp->chipset == DC21040) || (lp->chipset == DC21140)) return; @@ -5321,7 +5321,7 @@ static void de4x5_parse_params(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); char *p, *q, t; lp->params.fdx = 0; @@ -5364,7 +5364,7 @@ static void de4x5_dbg_open(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); int i; if (de4x5_debug & DEBUG_OPEN) { @@ -5415,7 +5415,7 @@ static void de4x5_dbg_mii(struct net_device *dev, int k) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); u_long iobase = dev->base_addr; if (de4x5_debug & DEBUG_MII) { @@ -5443,7 +5443,7 @@ static void de4x5_dbg_media(struct net_device *dev) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); if (lp->media != lp->c_media) { if (de4x5_debug & DEBUG_MEDIA) { @@ -5534,7 +5534,7 @@ static int de4x5_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct de4x5_private *lp = netdev_priv(dev); struct de4x5_ioctl *ioc = (struct de4x5_ioctl *) &rq->ifr_data; u_long iobase = dev->base_addr; int i, j, status = 0; diff -Nru a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c --- a/drivers/net/tulip/dmfe.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/tulip/dmfe.c Sun Mar 14 14:20:08 2004 @@ -392,7 +392,7 @@ } /* Init system & device */ - db = dev->priv; + db = netdev_priv(dev); /* Allocate Tx/Rx descriptor memory */ db->desc_pool_ptr = pci_alloc_consistent(pdev, sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20, &db->desc_pool_dma_ptr); @@ -466,7 +466,7 @@ static void __devexit dmfe_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct dmfe_board_info *db = dev->priv; + struct dmfe_board_info *db = netdev_priv(dev); DMFE_DBUG(0, "dmfe_remove_one()", 0); @@ -494,7 +494,7 @@ static int dmfe_open(struct DEVICE *dev) { int ret; - struct dmfe_board_info *db = dev->priv; + struct dmfe_board_info *db = netdev_priv(dev); DMFE_DBUG(0, "dmfe_open", 0); @@ -552,7 +552,7 @@ static void dmfe_init_dm910x(struct DEVICE *dev) { - struct dmfe_board_info *db = dev->priv; + struct dmfe_board_info *db = netdev_priv(dev); unsigned long ioaddr = db->ioaddr; DMFE_DBUG(0, "dmfe_init_dm910x()", 0); @@ -618,7 +618,7 @@ static int dmfe_start_xmit(struct sk_buff *skb, struct DEVICE *dev) { - struct dmfe_board_info *db = dev->priv; + struct dmfe_board_info *db = netdev_priv(dev); struct tx_desc *txptr; unsigned long flags; @@ -687,7 +687,7 @@ static int dmfe_stop(struct DEVICE *dev) { - struct dmfe_board_info *db = dev->priv; + struct dmfe_board_info *db = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; DMFE_DBUG(0, "dmfe_stop", 0); @@ -730,7 +730,7 @@ static irqreturn_t dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct DEVICE *dev = dev_id; - struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv; + struct dmfe_board_info *db = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; unsigned long flags; @@ -957,7 +957,7 @@ static struct net_device_stats * dmfe_get_stats(struct DEVICE *dev) { - struct dmfe_board_info *db = (struct dmfe_board_info *)dev->priv; + struct dmfe_board_info *db = netdev_priv(dev); DMFE_DBUG(0, "dmfe_get_stats", 0); return &db->stats; @@ -970,7 +970,7 @@ static void dmfe_set_filter_mode(struct DEVICE * dev) { - struct dmfe_board_info *db = dev->priv; + struct dmfe_board_info *db = netdev_priv(dev); unsigned long flags; DMFE_DBUG(0, "dmfe_set_filter_mode()", 0); @@ -1003,7 +1003,7 @@ static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct dmfe_board_info *np = dev->priv; + struct dmfe_board_info *np = netdev_priv(dev); strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); @@ -1028,7 +1028,7 @@ u32 tmp_cr8; unsigned char tmp_cr12; struct DEVICE *dev = (struct DEVICE *) data; - struct dmfe_board_info *db = (struct dmfe_board_info *) dev->priv; + struct dmfe_board_info *db = netdev_priv(dev); unsigned long flags; DMFE_DBUG(0, "dmfe_timer()", 0); @@ -1160,7 +1160,7 @@ static void dmfe_dynamic_reset(struct DEVICE *dev) { - struct dmfe_board_info *db = dev->priv; + struct dmfe_board_info *db = netdev_priv(dev); DMFE_DBUG(0, "dmfe_dynamic_reset()", 0); @@ -1358,7 +1358,7 @@ static void send_filter_frame(struct DEVICE *dev, int mc_cnt) { - struct dmfe_board_info *db = dev->priv; + struct dmfe_board_info *db = netdev_priv(dev); struct dev_mc_list *mcptr; struct tx_desc *txptr; u16 * addrptr; diff -Nru a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c --- a/drivers/net/tulip/eeprom.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/tulip/eeprom.c Sun Mar 14 14:20:08 2004 @@ -136,7 +136,7 @@ static struct mediatable *last_mediatable; static unsigned char *last_ee_data; static int controller_index; - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); unsigned char *ee_data = tp->eeprom; int i; diff -Nru a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c --- a/drivers/net/tulip/interrupt.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/tulip/interrupt.c Sun Mar 14 14:20:06 2004 @@ -63,7 +63,7 @@ int tulip_refill_rx(struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); int entry; int refilled = 0; @@ -109,7 +109,7 @@ int tulip_poll(struct net_device *dev, int *budget) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); int entry = tp->cur_rx % RX_RING_SIZE; int rx_work_limit = *budget; int received = 0; @@ -191,9 +191,9 @@ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ - pci_dma_sync_single(tp->pdev, - tp->rx_buffers[entry].mapping, - pkt_len, PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(tp->pdev, + tp->rx_buffers[entry].mapping, + pkt_len, PCI_DMA_FROMDEVICE); #if ! defined(__alpha__) eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->tail, pkt_len, 0); @@ -203,6 +203,9 @@ tp->rx_buffers[entry].skb->tail, pkt_len); #endif + pci_dma_sync_single_for_device(tp->pdev, + tp->rx_buffers[entry].mapping, + pkt_len, PCI_DMA_FROMDEVICE); } else { /* Pass up the skb already on the Rx ring. */ char *temp = skb_put(skb = tp->rx_buffers[entry].skb, pkt_len); @@ -354,7 +357,7 @@ static int tulip_rx(struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); int entry = tp->cur_rx % RX_RING_SIZE; int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx; int received = 0; @@ -412,9 +415,9 @@ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ - pci_dma_sync_single(tp->pdev, - tp->rx_buffers[entry].mapping, - pkt_len, PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(tp->pdev, + tp->rx_buffers[entry].mapping, + pkt_len, PCI_DMA_FROMDEVICE); #if ! defined(__alpha__) eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->tail, pkt_len, 0); @@ -424,6 +427,9 @@ tp->rx_buffers[entry].skb->tail, pkt_len); #endif + pci_dma_sync_single_for_device(tp->pdev, + tp->rx_buffers[entry].mapping, + pkt_len, PCI_DMA_FROMDEVICE); } else { /* Pass up the skb already on the Rx ring. */ char *temp = skb_put(skb = tp->rx_buffers[entry].skb, pkt_len); @@ -465,7 +471,7 @@ { #ifdef __hppa__ int csr12 = inl(dev->base_addr + CSR12) & 0xff; - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); if (csr12 != tp->csr12_shadow) { /* ack interrupt */ @@ -490,7 +496,7 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_instance; - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; int csr5; int missed; diff -Nru a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c --- a/drivers/net/tulip/media.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/tulip/media.c Sun Mar 14 14:20:06 2004 @@ -48,7 +48,7 @@ int tulip_mdio_read(struct net_device *dev, int phy_id, int location) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); int i; int read_cmd = (0xf6 << 10) | ((phy_id & 0x1f) << 5) | location; int retval = 0; @@ -111,7 +111,7 @@ void tulip_mdio_write(struct net_device *dev, int phy_id, int location, int val) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); int i; int cmd = (0x5002 << 16) | ((phy_id & 0x1f) << 23) | (location<<18) | (val & 0xffff); long ioaddr = dev->base_addr; @@ -171,7 +171,7 @@ void tulip_select_media(struct net_device *dev, int startup) { long ioaddr = dev->base_addr; - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); struct mediatable *mtable = tp->mtable; u32 new_csr6; int i; @@ -374,7 +374,7 @@ */ int tulip_check_duplex(struct net_device *dev) { - struct tulip_private *tp = dev->priv; + struct tulip_private *tp = netdev_priv(dev); unsigned int bmsr, lpa, negotiated, new_csr6; bmsr = tulip_mdio_read(dev, tp->phys[0], MII_BMSR); @@ -420,7 +420,7 @@ void __devinit tulip_find_mii (struct net_device *dev, int board_idx) { - struct tulip_private *tp = dev->priv; + struct tulip_private *tp = netdev_priv(dev); int phyn, phy_idx = 0; int mii_reg0; int mii_advert; diff -Nru a/drivers/net/tulip/pnic.c b/drivers/net/tulip/pnic.c --- a/drivers/net/tulip/pnic.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/tulip/pnic.c Sun Mar 14 14:20:07 2004 @@ -20,7 +20,7 @@ void pnic_do_nway(struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; u32 phy_reg = inl(ioaddr + 0xB8); u32 new_csr6 = tp->csr6 & ~0x40C40200; @@ -53,7 +53,7 @@ void pnic_lnk_change(struct net_device *dev, int csr5) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; int phy_reg = inl(ioaddr + 0xB8); @@ -89,7 +89,7 @@ void pnic_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; int next_tick = 60*HZ; diff -Nru a/drivers/net/tulip/pnic2.c b/drivers/net/tulip/pnic2.c --- a/drivers/net/tulip/pnic2.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/tulip/pnic2.c Sun Mar 14 14:20:06 2004 @@ -84,7 +84,7 @@ void pnic2_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; int next_tick = 60*HZ; @@ -100,7 +100,7 @@ void pnic2_start_nway(struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; int csr14; int csr12; @@ -175,7 +175,7 @@ void pnic2_lnk_change(struct net_device *dev, int csr5) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; int csr14; diff -Nru a/drivers/net/tulip/timer.c b/drivers/net/tulip/timer.c --- a/drivers/net/tulip/timer.c Sun Mar 14 14:20:05 2004 +++ b/drivers/net/tulip/timer.c Sun Mar 14 14:20:05 2004 @@ -20,7 +20,7 @@ void tulip_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; u32 csr12 = inl(ioaddr + CSR12); int next_tick = 2*HZ; @@ -135,7 +135,7 @@ void mxic_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; int next_tick = 60*HZ; @@ -152,7 +152,7 @@ void comet_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; int next_tick = 60*HZ; diff -Nru a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c --- a/drivers/net/tulip/tulip_core.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/tulip/tulip_core.c Sun Mar 14 14:20:07 2004 @@ -253,7 +253,7 @@ static struct net_device_stats *tulip_get_stats(struct net_device *dev); static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static void set_rx_mode(struct net_device *dev); - +static void poll_tulip(struct net_device *dev); static void tulip_set_power_state (struct tulip_private *tp, @@ -276,7 +276,7 @@ static void tulip_up(struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; int next_tick = 3*HZ; int i; @@ -499,7 +499,7 @@ static void tulip_tx_timeout(struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; unsigned long flags; @@ -587,7 +587,7 @@ /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ static void tulip_init_ring(struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); int i; tp->susp_rx = 0; @@ -638,7 +638,7 @@ static int tulip_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); int entry; u32 flag; dma_addr_t mapping; @@ -724,7 +724,7 @@ static void tulip_down (struct net_device *dev) { long ioaddr = dev->base_addr; - struct tulip_private *tp = (struct tulip_private *) dev->priv; + struct tulip_private *tp = netdev_priv(dev); unsigned long flags; del_timer_sync (&tp->timer); @@ -764,7 +764,7 @@ static int tulip_close (struct net_device *dev) { long ioaddr = dev->base_addr; - struct tulip_private *tp = (struct tulip_private *) dev->priv; + struct tulip_private *tp = netdev_priv(dev); int i; netif_stop_queue (dev); @@ -811,7 +811,7 @@ static struct net_device_stats *tulip_get_stats(struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; if (netif_running(dev)) { @@ -830,7 +830,7 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) { - struct tulip_private *np = dev->priv; + struct tulip_private *np = netdev_priv(dev); u32 ethcmd; if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) @@ -855,7 +855,7 @@ /* Provide ioctl() calls to examine the MII xcvr state. */ static int private_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) { - struct tulip_private *tp = dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data; const unsigned int phy_idx = 0; @@ -964,7 +964,7 @@ static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); u16 hash_table[32]; struct dev_mc_list *mclist; int i; @@ -995,7 +995,7 @@ static void build_setup_frame_perfect(u16 *setup_frm, struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); struct dev_mc_list *mclist; int i; u16 *eaddrs; @@ -1023,7 +1023,7 @@ static void set_rx_mode(struct net_device *dev) { - struct tulip_private *tp = (struct tulip_private *)dev->priv; + struct tulip_private *tp = netdev_priv(dev); long ioaddr = dev->base_addr; int csr6; @@ -1150,7 +1150,7 @@ static void __devinit tulip_mwi_config (struct pci_dev *pdev, struct net_device *dev) { - struct tulip_private *tp = dev->priv; + struct tulip_private *tp = netdev_priv(dev); u8 cache; u16 pci_command; u32 csr0; @@ -1373,7 +1373,7 @@ * initialize private data structure 'tp' * it is zeroed and aligned in alloc_etherdev */ - tp = dev->priv; + tp = netdev_priv(dev); tp->rx_ring = pci_alloc_consistent(pdev, sizeof(struct tulip_rx_desc) * RX_RING_SIZE + @@ -1618,6 +1618,9 @@ dev->get_stats = tulip_get_stats; dev->do_ioctl = private_ioctl; dev->set_multicast_list = set_rx_mode; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = &poll_tulip; +#endif if (register_netdev(dev)) goto err_out_free_ring; @@ -1756,7 +1759,7 @@ if (!dev) return; - tp = dev->priv; + tp = netdev_priv(dev); pci_free_consistent (pdev, sizeof (struct tulip_rx_desc) * RX_RING_SIZE + sizeof (struct tulip_tx_desc) * TX_RING_SIZE, @@ -1774,6 +1777,22 @@ /* pci_power_off (pdev, -1); */ } +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling 'interrupt' - used by things like netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ + +static void poll_tulip (struct net_device *dev) +{ + /* disable_irq here is not very nice, but with the lockless + interrupt handler we have no other choice. */ + disable_irq(dev->irq); + tulip_interrupt (dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif static struct pci_driver tulip_driver = { .name = DRV_NAME, diff -Nru a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c --- a/drivers/net/tulip/winbond-840.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/tulip/winbond-840.c Sun Mar 14 14:20:06 2004 @@ -1289,9 +1289,9 @@ && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ - pci_dma_sync_single(np->pci_dev,np->rx_addr[entry], - np->rx_skbuff[entry]->len, - PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(np->pci_dev,np->rx_addr[entry], + np->rx_skbuff[entry]->len, + PCI_DMA_FROMDEVICE); /* Call copy + cksum if available. */ #if HAS_IP_COPYSUM eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0); @@ -1300,6 +1300,9 @@ memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail, pkt_len); #endif + pci_dma_sync_single_for_device(np->pci_dev,np->rx_addr[entry], + np->rx_skbuff[entry]->len, + PCI_DMA_FROMDEVICE); } else { pci_unmap_single(np->pci_dev,np->rx_addr[entry], np->rx_skbuff[entry]->len, diff -Nru a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c --- a/drivers/net/tulip/xircom_cb.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/tulip/xircom_cb.c Sun Mar 14 14:20:08 2004 @@ -178,7 +178,7 @@ static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct xircom_private *private = dev->priv; + struct xircom_private *private = netdev_priv(dev); strcpy(info->driver, "xircom_cb"); strcpy(info->bus_info, pci_name(private->pdev)); @@ -235,7 +235,7 @@ printk(KERN_ERR "xircom_probe: failed to allocate etherdev\n"); goto device_fail; } - private = dev->priv; + private = netdev_priv(dev); /* Allocate the send/receive buffers */ private->rx_buffer = pci_alloc_consistent(pdev,8192,&private->rx_dma_handle); @@ -312,7 +312,7 @@ static void __devexit xircom_remove(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct xircom_private *card = dev->priv; + struct xircom_private *card = netdev_priv(dev); enter("xircom_remove"); pci_free_consistent(pdev,8192,card->rx_buffer,card->rx_dma_handle); @@ -328,7 +328,7 @@ static irqreturn_t xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_instance; - struct xircom_private *card = (struct xircom_private *) dev->priv; + struct xircom_private *card = netdev_priv(dev); unsigned int status; int i; @@ -385,7 +385,7 @@ int desc; enter("xircom_start_xmit"); - card = (struct xircom_private*)dev->priv; + card = netdev_priv(dev); spin_lock_irqsave(&card->lock,flags); /* First see if we can free some descriptors */ @@ -444,7 +444,7 @@ static int xircom_open(struct net_device *dev) { - struct xircom_private *xp = (struct xircom_private *) dev->priv; + struct xircom_private *xp = netdev_priv(dev); int retval; enter("xircom_open"); printk(KERN_INFO "xircom cardbus adaptor found, registering as %s, using irq %i \n",dev->name,dev->irq); @@ -466,7 +466,7 @@ unsigned long flags; enter("xircom_close"); - card = dev->priv; + card = netdev_priv(dev); netif_stop_queue(dev); /* we don't want new packets */ @@ -495,7 +495,7 @@ static struct net_device_stats *xircom_get_stats(struct net_device *dev) { - struct xircom_private *card = (struct xircom_private *)dev->priv; + struct xircom_private *card = netdev_priv(dev); return &card->stats; } diff -Nru a/drivers/net/tun.c b/drivers/net/tun.c --- a/drivers/net/tun.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/tun.c Sun Mar 14 14:20:07 2004 @@ -70,7 +70,7 @@ /* Net device start xmit */ static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev) { - struct tun_struct *tun = (struct tun_struct *)dev->priv; + struct tun_struct *tun = netdev_priv(dev); DBG(KERN_INFO "%s: tun_net_xmit %d\n", tun->dev->name, skb->len); @@ -113,14 +113,14 @@ static struct net_device_stats *tun_net_stats(struct net_device *dev) { - struct tun_struct *tun = (struct tun_struct *)dev->priv; + struct tun_struct *tun = netdev_priv(dev); return &tun->stats; } /* Initialize net device. */ static void tun_net_init(struct net_device *dev) { - struct tun_struct *tun = (struct tun_struct *)dev->priv; + struct tun_struct *tun = netdev_priv(dev); switch (tun->flags & TUN_TYPE_MASK) { case TUN_TUN_DEV: @@ -153,7 +153,7 @@ /* Poll */ static unsigned int tun_chr_poll(struct file *file, poll_table * wait) { - struct tun_struct *tun = (struct tun_struct *)file->private_data; + struct tun_struct *tun = file->private_data; unsigned int mask = POLLOUT | POLLWRNORM; if (!tun) @@ -217,7 +217,7 @@ static ssize_t tun_chr_writev(struct file * file, const struct iovec *iv, unsigned long count, loff_t *pos) { - struct tun_struct *tun = (struct tun_struct *)file->private_data; + struct tun_struct *tun = file->private_data; unsigned long i; size_t len; @@ -279,7 +279,7 @@ static ssize_t tun_chr_readv(struct file *file, const struct iovec *iv, unsigned long count, loff_t *pos) { - struct tun_struct *tun = (struct tun_struct *)file->private_data; + struct tun_struct *tun = file->private_data; DECLARE_WAITQUEUE(wait, current); struct sk_buff *skb; ssize_t len, ret = 0; @@ -341,7 +341,7 @@ static void tun_setup(struct net_device *dev) { - struct tun_struct *tun = dev->priv; + struct tun_struct *tun = netdev_priv(dev); skb_queue_head_init(&tun->readq); init_waitqueue_head(&tun->read_wait); @@ -413,7 +413,7 @@ if (!dev) return -ENOMEM; - tun = dev->priv; + tun = netdev_priv(dev); tun->dev = dev; tun->flags = flags; @@ -455,7 +455,7 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct tun_struct *tun = (struct tun_struct *)file->private_data; + struct tun_struct *tun = file->private_data; if (cmd == TUNSETIFF && !tun) { struct ifreq ifr; @@ -527,7 +527,7 @@ static int tun_chr_fasync(int fd, struct file *file, int on) { - struct tun_struct *tun = (struct tun_struct *)file->private_data; + struct tun_struct *tun = file->private_data; int ret; if (!tun) @@ -558,7 +558,7 @@ static int tun_chr_close(struct inode *inode, struct file *file) { - struct tun_struct *tun = (struct tun_struct *)file->private_data; + struct tun_struct *tun = file->private_data; if (!tun) return 0; diff -Nru a/drivers/net/typhoon.c b/drivers/net/typhoon.c --- a/drivers/net/typhoon.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/typhoon.c Sun Mar 14 14:20:07 2004 @@ -1701,9 +1701,13 @@ (new_skb = dev_alloc_skb(pkt_len + 2)) != NULL) { new_skb->dev = tp->dev; skb_reserve(new_skb, 2); - pci_dma_sync_single(tp->pdev, dma_addr, PKT_BUF_SZ, - PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(tp->pdev, dma_addr, + PKT_BUF_SZ, + PCI_DMA_FROMDEVICE); eth_copy_and_sum(new_skb, skb->tail, pkt_len, 0); + pci_dma_sync_single_for_device(tp->pdev, dma_addr, + PKT_BUF_SZ, + PCI_DMA_FROMDEVICE); skb_put(new_skb, pkt_len); typhoon_recycle_rx_skb(tp, idx); } else { diff -Nru a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c --- a/drivers/net/via-rhine.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/via-rhine.c Sun Mar 14 14:20:08 2004 @@ -615,6 +615,15 @@ break; } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void via_rhine_poll(struct net_device *dev) +{ + disable_irq(dev->irq); + via_rhine_interrupt(dev->irq, (void *)dev, NULL); + enable_irq(dev->irq); +} +#endif + static int __devinit via_rhine_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -784,6 +793,9 @@ dev->ethtool_ops = &netdev_ethtool_ops; dev->tx_timeout = via_rhine_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = via_rhine_poll; +#endif if (np->drv_flags & ReqTxAlign) dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM; @@ -1524,7 +1536,7 @@ (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { skb->dev = dev; skb_reserve(skb, 2); /* 16 byte align the IP header */ - pci_dma_sync_single(np->pdev, np->rx_skbuff_dma[entry], + pci_dma_sync_single_for_cpu(np->pdev, np->rx_skbuff_dma[entry], np->rx_buf_sz, PCI_DMA_FROMDEVICE); /* *_IP_COPYSUM isn't defined anywhere and eth_copy_and_sum @@ -1537,6 +1549,8 @@ memcpy(skb_put(skb, pkt_len), np->rx_skbuff[entry]->tail, pkt_len); #endif + pci_dma_sync_single_for_device(np->pdev, np->rx_skbuff_dma[entry], + np->rx_buf_sz, PCI_DMA_FROMDEVICE); } else { skb = np->rx_skbuff[entry]; if (skb == NULL) { diff -Nru a/drivers/net/wan/comx-hw-locomx.c b/drivers/net/wan/comx-hw-locomx.c --- a/drivers/net/wan/comx-hw-locomx.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/wan/comx-hw-locomx.c Sun Mar 14 14:20:07 2004 @@ -77,7 +77,7 @@ static int LOCOMX_txe(struct net_device *dev) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct locomx_data *hw = ch->HW_privdata; return (!hw->board.chanA.tx_next_skb); @@ -86,8 +86,8 @@ static void locomx_rx(struct z8530_channel *c, struct sk_buff *skb) { - struct net_device *dev=c->netdevice; - struct comx_channel *ch=dev->priv; + struct net_device *dev = c->netdevice; + struct comx_channel *ch = netdev_priv(dev); if (ch->debug_flags & DEBUG_HW_RX) { comx_debug_skb(dev, skb, "locomx_rx receiving"); @@ -97,7 +97,7 @@ static int LOCOMX_send_packet(struct net_device *dev, struct sk_buff *skb) { - struct comx_channel *ch = (struct comx_channel *)dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct locomx_data *hw = ch->HW_privdata; if (ch->debug_flags & DEBUG_HW_TX) { @@ -126,9 +126,9 @@ static void locomx_status_timerfun(unsigned long d) { - struct net_device *dev=(struct net_device *)d; - struct comx_channel *ch=dev->priv; - struct locomx_data *hw=ch->HW_privdata; + struct net_device *dev = (struct net_device *)d; + struct comx_channel *ch = netdev_priv(dev); + struct locomx_data *hw = ch->HW_privdata; if(!(ch->line_status & LINE_UP) && (hw->board.chanA.status & CTS)) { @@ -144,7 +144,7 @@ static int LOCOMX_open(struct net_device *dev) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct locomx_data *hw = ch->HW_privdata; struct proc_dir_entry *procfile = ch->procdir->subdir; unsigned long flags; @@ -256,7 +256,7 @@ static int LOCOMX_close(struct net_device *dev) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct locomx_data *hw = ch->HW_privdata; struct proc_dir_entry *procfile = ch->procdir->subdir; @@ -376,7 +376,7 @@ static int LOCOMX_init(struct net_device *dev) { - struct comx_channel *ch = (struct comx_channel *)dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct locomx_data *hw; struct proc_dir_entry *new_file; @@ -449,7 +449,7 @@ static int LOCOMX_exit(struct net_device *dev) { - struct comx_channel *ch = (struct comx_channel *)dev->priv; + struct comx_channel *ch = netdev_priv(dev); ch->HW_access_board = NULL; ch->HW_release_board = NULL; diff -Nru a/drivers/net/wan/comx-hw-munich.c b/drivers/net/wan/comx-hw-munich.c --- a/drivers/net/wan/comx-hw-munich.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/wan/comx-hw-munich.c Sun Mar 14 14:20:06 2004 @@ -373,7 +373,7 @@ void rework_idle_channels(struct net_device *dev) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct slicecom_privdata *hw = ch->HW_privdata; munich_board_t *board = slicecom_boards + hw->boardnum; munich_ccb_t *ccb = board->ccb; @@ -731,7 +731,7 @@ { munich_board_t *board = (munich_board_t *) b; struct net_device *dev = board->twins[0]; - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); unsigned long regs; regs = readl((void *)(&board->bar1[GPDATA])); @@ -765,7 +765,7 @@ static int MUNICH_txe(struct net_device *dev) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct slicecom_privdata *hw = ch->HW_privdata; return (hw->busy < TX_DESC_MAX - 1); @@ -905,7 +905,7 @@ #if 0 static int slicecom_reset(struct net_device *dev) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); printk("slicecom_reset: resetting the hardware\n"); @@ -933,7 +933,7 @@ static int MUNICH_send_packet(struct net_device *dev, struct sk_buff *skb) { - struct comx_channel *ch = (struct comx_channel *)dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct slicecom_privdata *hw = ch->HW_privdata; /* Send it to the debug facility too if needed: */ @@ -1085,7 +1085,7 @@ goto go_for_next_interrupt; } - ch = (struct comx_channel *)dev->priv; + ch = netdev_priv(dev); hw = (struct slicecom_privdata *)ch->HW_privdata; // printk("Rx STAT=0x%08x int_info=0x%08x rx_desc_ptr=%d rx_desc.status=0x%01x\n", @@ -1125,7 +1125,7 @@ if (dev != NULL) { - ch = (struct comx_channel *)dev->priv; + ch = netdev_priv(dev); hw = (struct slicecom_privdata *)ch->HW_privdata; rx_status = hw->rx_desc[hw->rx_desc_ptr].status; @@ -1261,7 +1261,7 @@ goto go_for_next_tx_interrupt; } - ch = (struct comx_channel *)dev->priv; + ch = netdev_priv(dev); hw = (struct slicecom_privdata *)ch->HW_privdata; // printk("Tx STAT=0x%08x int_info=0x%08x tiq_ptr=%d\n", stat, int_info.all, board->tiq_ptr ); @@ -1295,7 +1295,7 @@ { int newbusy; - ch = (struct comx_channel *)dev->priv; + ch = netdev_priv(dev); hw = (struct slicecom_privdata *)ch->HW_privdata; /* We don't trust the "Tx available" info from the TIQ, but check */ @@ -1398,7 +1398,7 @@ static int MUNICH_open(struct net_device *dev) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct slicecom_privdata *hw = ch->HW_privdata; struct proc_dir_entry *procfile = ch->procdir->subdir; munich_board_t *board; @@ -1891,7 +1891,7 @@ static int MUNICH_close(struct net_device *dev) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct slicecom_privdata *hw = ch->HW_privdata; struct proc_dir_entry *procfile = ch->procdir->subdir; munich_board_t *board; @@ -2028,7 +2028,7 @@ static int MUNICH_minden(struct net_device *dev, char *page) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct slicecom_privdata *hw = ch->HW_privdata; munich_board_t *board; struct net_device *devp; @@ -2290,7 +2290,7 @@ { struct proc_dir_entry *file = (struct proc_dir_entry *)data; struct net_device *dev = file->parent->data; - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct slicecom_privdata *hw = ch->HW_privdata; munich_board_t *board; @@ -2388,7 +2388,7 @@ { struct proc_dir_entry *entry = (struct proc_dir_entry *)data; struct net_device *dev = (struct net_device *)entry->parent->data; - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct slicecom_privdata *hw = ch->HW_privdata; munich_board_t *board; @@ -2656,7 +2656,7 @@ static int BOARD_init(struct net_device *dev) { - struct comx_channel *ch = (struct comx_channel *)dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct slicecom_privdata *hw; struct proc_dir_entry *new_file; @@ -2772,7 +2772,7 @@ */ static int BOARD_exit(struct net_device *dev) { - struct comx_channel *ch = (struct comx_channel *)dev->priv; + struct comx_channel *ch = netdev_priv(dev); /* Free private data area */ // board = hw->boardnum + (ch->hardware == &pcicomhw ? pcicom_boards : slicecom_boards); diff -Nru a/drivers/net/wan/comx.c b/drivers/net/wan/comx.c --- a/drivers/net/wan/comx.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/wan/comx.c Sun Mar 14 14:20:07 2004 @@ -119,7 +119,7 @@ int comx_debug(struct net_device *dev, char *fmt, ...) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); char *page,*str; va_list args; int len; @@ -162,7 +162,7 @@ int comx_debug_skb(struct net_device *dev, struct sk_buff *skb, char *msg) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); if (!ch->debug_area) return 0; if (!skb) comx_debug(dev, "%s: %s NULL skb\n\n", dev->name, msg); @@ -175,7 +175,7 @@ char *msg) { int pos = 0; - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); if (!ch->debug_area) return 0; @@ -207,7 +207,7 @@ static void comx_loadavg_timerfun(unsigned long d) { struct net_device *dev = (struct net_device *)d; - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); ch->avg_bytes[ch->loadavg_counter] = ch->current_stats->rx_bytes; ch->avg_bytes[ch->loadavg_counter + ch->loadavg_size] = @@ -222,7 +222,7 @@ static void comx_reset_timerfun(unsigned long d) { struct net_device *dev = (struct net_device *)d; - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); if(!(ch->line_status & (PROTO_LOOP | PROTO_UP))) { if(test_and_set_bit(0,&ch->reset_pending) && ch->HW_reset) { @@ -236,7 +236,7 @@ static int comx_open(struct net_device *dev) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct proc_dir_entry *comxdir = ch->procdir->subdir; int ret=0; @@ -268,7 +268,7 @@ static int comx_close(struct net_device *dev) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); struct proc_dir_entry *comxdir = ch->procdir->subdir; int ret = -ENODEV; @@ -303,7 +303,7 @@ void comx_status(struct net_device *dev, int status) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); #if 0 if(status & (PROTO_UP | PROTO_LOOP)) { @@ -321,7 +321,7 @@ static int comx_xmit(struct sk_buff *skb, struct net_device *dev) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); int rc; if (skb->len > dev->mtu + dev->hard_header_len) { @@ -342,7 +342,7 @@ static int comx_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); if (ch->LINE_header) { return (ch->LINE_header(skb, dev, type, daddr, saddr, len)); @@ -354,7 +354,7 @@ static int comx_rebuild_header(struct sk_buff *skb) { struct net_device *dev = skb->dev; - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); if (ch->LINE_rebuild_header) { return(ch->LINE_rebuild_header(skb)); @@ -365,7 +365,7 @@ int comx_rx(struct net_device *dev, struct sk_buff *skb) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); if (ch->debug_flags & DEBUG_COMX_RX) { comx_debug_skb(dev, skb, "comx_rx skb"); @@ -379,7 +379,7 @@ static struct net_device_stats *comx_stats(struct net_device *dev) { - struct comx_channel *ch = (struct comx_channel *)dev->priv; + struct comx_channel *ch = netdev_priv(dev); return ch->current_stats; } @@ -387,7 +387,7 @@ void comx_lineup_func(unsigned long d) { struct net_device *dev = (struct net_device *)d; - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); del_timer(&ch->lineup_timer); clear_bit(0, &ch->lineup_pending); @@ -405,7 +405,7 @@ static int comx_statistics(struct net_device *dev, char *page) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); int len = 0; int tmp; int i = 0; @@ -472,7 +472,7 @@ static int comx_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct comx_channel *ch = dev->priv; + struct comx_channel *ch = netdev_priv(dev); if (ch->LINE_ioctl) { return(ch->LINE_ioctl(dev, ifr, cmd)); @@ -535,7 +535,7 @@ { struct proc_dir_entry *file = (struct proc_dir_entry *)data; struct net_device *dev = file->parent->data; - struct comx_channel *ch=(struct comx_channel *)dev->priv; + struct comx_channel *ch = netdev_priv(dev); int len = 0; if (strcmp(file->name, FILENAME_STATUS) == 0) { @@ -599,7 +599,7 @@ { struct proc_dir_entry *entry = (struct proc_dir_entry *)data; struct net_device *dev = (struct net_device *)entry->parent->data; - struct comx_channel *ch=(struct comx_channel *)dev->priv; + struct comx_channel *ch = netdev_priv(dev); char *page; struct comx_hardware *hw = comx_channels; struct comx_protocol *line = comx_lines; @@ -821,7 +821,7 @@ if (register_netdevice(dev)) { goto cleanup_filename_debug; } - ch=dev->priv; + ch = netdev_priv(dev); if((ch->if_ptr = (void *)kmalloc(sizeof(struct ppp_device), GFP_KERNEL)) == NULL) { goto cleanup_register; @@ -874,7 +874,7 @@ lock_kernel(); dev = entry->data; - ch = dev->priv; + ch = netdev_priv(dev); if (dev->flags & IFF_UP) { printk(KERN_ERR "%s: down interface before removing it\n", dev->name); unlock_kernel(); diff -Nru a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c --- a/drivers/net/wan/cosa.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/wan/cosa.c Sun Mar 14 14:20:06 2004 @@ -639,7 +639,7 @@ static int cosa_sppp_open(struct net_device *d) { - struct channel_data *chan = d->priv; + struct channel_data *chan = netdev_priv(d); int err; unsigned long flags; @@ -679,7 +679,7 @@ static int cosa_sppp_tx(struct sk_buff *skb, struct net_device *dev) { - struct channel_data *chan = dev->priv; + struct channel_data *chan = netdev_priv(dev); netif_stop_queue(dev); @@ -690,7 +690,7 @@ static void cosa_sppp_timeout(struct net_device *dev) { - struct channel_data *chan = dev->priv; + struct channel_data *chan = netdev_priv(dev); if (test_bit(RXBIT, &chan->cosa->rxtx)) { chan->stats.rx_errors++; @@ -709,7 +709,7 @@ static int cosa_sppp_close(struct net_device *d) { - struct channel_data *chan = d->priv; + struct channel_data *chan = netdev_priv(d); unsigned long flags; netif_stop_queue(d); @@ -789,7 +789,7 @@ static struct net_device_stats *cosa_net_stats(struct net_device *dev) { - struct channel_data *chan = dev->priv; + struct channel_data *chan = netdev_priv(dev); return &chan->stats; } @@ -807,7 +807,7 @@ { DECLARE_WAITQUEUE(wait, current); unsigned long flags; - struct channel_data *chan = (struct channel_data *)file->private_data; + struct channel_data *chan = file->private_data; struct cosa_data *cosa = chan->cosa; char *kbuf; @@ -881,7 +881,7 @@ const char *buf, size_t count, loff_t *ppos) { DECLARE_WAITQUEUE(wait, current); - struct channel_data *chan = (struct channel_data *)file->private_data; + struct channel_data *chan = file->private_data; struct cosa_data *cosa = chan->cosa; unsigned long flags; char *kbuf; @@ -990,7 +990,7 @@ static int cosa_release(struct inode *inode, struct file *file) { - struct channel_data *channel = (struct channel_data *)file->private_data; + struct channel_data *channel = file->private_data; struct cosa_data *cosa; unsigned long flags; @@ -1205,7 +1205,7 @@ int cmd) { int rv; - struct channel_data *chan = (struct channel_data *)dev->priv; + struct channel_data *chan = netdev_priv(dev); rv = cosa_ioctl_common(chan->cosa, chan, cmd, (unsigned long)ifr->ifr_data); if (rv == -ENOIOCTLCMD) { return sppp_do_ioctl(dev, ifr, cmd); @@ -1216,7 +1216,7 @@ static int cosa_chardev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct channel_data *channel = (struct channel_data *)file->private_data; + struct channel_data *channel = file->private_data; struct cosa_data *cosa = channel->cosa; return cosa_ioctl_common(cosa, channel, cmd, arg); } diff -Nru a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c --- a/drivers/net/wan/dscc4.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/wan/dscc4.c Sun Mar 14 14:20:06 2004 @@ -652,7 +652,6 @@ goto refill; } pkt_len = TO_SIZE(rx_fd->state2); - pci_dma_sync_single(pdev, rx_fd->data, pkt_len, PCI_DMA_FROMDEVICE); pci_unmap_single(pdev, rx_fd->data, RX_MAX(HDLC_MAX_MRU), PCI_DMA_FROMDEVICE); if ((skb->data[--pkt_len] & FrameOk) == FrameOk) { stats->rx_packets++; diff -Nru a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c --- a/drivers/net/wan/lapbether.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/wan/lapbether.c Sun Mar 14 14:20:07 2004 @@ -198,7 +198,7 @@ static void lapbeth_data_transmit(struct net_device *ndev, struct sk_buff *skb) { - struct lapbethdev *lapbeth = ndev->priv; + struct lapbethdev *lapbeth = netdev_priv(ndev); unsigned char *ptr; struct net_device *dev; int size = skb->len; @@ -269,7 +269,7 @@ */ static struct net_device_stats *lapbeth_get_stats(struct net_device *dev) { - struct lapbethdev *lapbeth = (struct lapbethdev *)dev->priv; + struct lapbethdev *lapbeth = netdev_priv(dev); return &lapbeth->stats; } @@ -278,7 +278,7 @@ */ static int lapbeth_set_mac_address(struct net_device *dev, void *addr) { - struct sockaddr *sa = (struct sockaddr *)addr; + struct sockaddr *sa = addr; memcpy(dev->dev_addr, sa->sa_data, dev->addr_len); return 0; } @@ -355,7 +355,7 @@ if (!ndev) goto out; - lapbeth = ndev->priv; + lapbeth = netdev_priv(ndev); lapbeth->axdev = ndev; dev_hold(dev); @@ -397,7 +397,7 @@ unsigned long event, void *ptr) { struct lapbethdev *lapbeth; - struct net_device *dev = (struct net_device *)ptr; + struct net_device *dev = ptr; if (!dev_is_ethdev(dev)) return NOTIFY_DONE; diff -Nru a/drivers/net/wd.c b/drivers/net/wd.c --- a/drivers/net/wd.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/wd.c Sun Mar 14 14:20:06 2004 @@ -333,6 +333,9 @@ ei_status.get_8390_hdr = &wd_get_8390_hdr; dev->open = &wd_open; dev->stop = &wd_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif NS8390_init(dev, 0); #if 1 diff -Nru a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig --- a/drivers/net/wireless/Kconfig Sun Mar 14 14:20:06 2004 +++ b/drivers/net/wireless/Kconfig Sun Mar 14 14:20:06 2004 @@ -307,6 +307,53 @@ It has basic support for Linux wireless extensions and initial micro support for ethtool. +comment "Prism GT/Duette 802.11(a/b/g) PCI/PCMCIA support" + depends on NET_RADIO && PCI +config PRISM54 + tristate 'Intersil Prism GT/Duette/Indigo PCI/PCMCIA' + depends on PCI && NET_RADIO && EXPERIMENTAL && HOTPLUG + select FW_LOADER + ---help--- + Enable PCI and Cardbus support for the following chipset based cards: + + ISL3880 - Prism GT 802.11 b/g + ISL3877 - Prism Indigo 802.11 a + ISL3890 - Prism Duette 802.11 a/b/g + + For a complete list of supported cards visit . + Here is the latest confirmed list of supported cards: + + 3com OfficeConnect 11g Cardbus Card aka 3CRWE154G72 + Allnet ALL0271 PCI Card + Compex WL54G Cardbus Card + Corega CG-WLCB54GT Cardbus Card + D-Link Air Plus Xtreme G A1 Cardbus Card aka DWL-g650 + I-O Data WN-G54/CB Cardbus Card + Kobishi XG-300 aka Z-Com Cardbus Card + Netgear WG511 Cardbus Card + Ovislink WL-5400PCI PCI Card + Peabird WLG-PCI PCI Card + Sitecom WL-100i Cardbus Card + Sitecom WL-110i PCI Card + SMC2802W - EZ Connect g 2.4GHz 54 Mbps Wireless PCI Card + SMC2835W - EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Card + Z-Com XG-900 PCI Card + Zyxel G-100 Cardbus Card + + If you enable this you will need a firmware file as well. + You will need to copy this to /usr/lib/hotplug/firmware/isl3890. + You can get this non-GPL'd firmware file from the Prism54 project page: + + You will also need the /etc/hotplug/firmware.agent script from + a current hotplug package. + + Note: You need a motherboard with DMA support to use any of these cards + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read . The module + will be called prism54.ko. + # yes, this works even when no drivers are selected config NET_WIRELESS bool diff -Nru a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile --- a/drivers/net/wireless/Makefile Sun Mar 14 14:20:09 2004 +++ b/drivers/net/wireless/Makefile Sun Mar 14 14:20:09 2004 @@ -26,6 +26,8 @@ obj-$(CONFIG_PCI_ATMEL) += atmel_pci.o obj-$(CONFIG_PCMCIA_ATMEL) += atmel_cs.o +obj-$(CONFIG_PRISM54) += prism54/ + # 16-bit wireless PCMCIA client drivers obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o diff -Nru a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c --- a/drivers/net/wireless/airo.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/wireless/airo.c Sun Mar 14 14:20:06 2004 @@ -1505,7 +1505,7 @@ seq = micSeq - (context->window - 33); //Too old of a SEQ number to check. - if ((u32)seq < 0) + if ((s32)seq < 0) return ERROR; if ( seq > 64 ) { diff -Nru a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c --- a/drivers/net/wireless/atmel.c Sun Mar 14 14:20:06 2004 +++ b/drivers/net/wireless/atmel.c Sun Mar 14 14:20:06 2004 @@ -796,7 +796,7 @@ static int start_tx (struct sk_buff *skb, struct net_device *dev) { - struct atmel_private *priv = (struct atmel_private *)dev->priv; + struct atmel_private *priv = netdev_priv(dev); struct ieee802_11_hdr header; unsigned long flags; u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; @@ -1167,7 +1167,7 @@ static irqreturn_t service_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; - struct atmel_private *priv = (struct atmel_private *) dev->priv; + struct atmel_private *priv = netdev_priv(dev); u8 isr; if (priv->card && priv->present_callback && @@ -1234,13 +1234,13 @@ static struct net_device_stats *atmel_get_stats (struct net_device *dev) { - struct atmel_private *priv = (struct atmel_private *)dev->priv; + struct atmel_private *priv = netdev_priv(dev); return &priv->stats; } static struct iw_statistics *atmel_get_wireless_stats (struct net_device *dev) { - struct atmel_private *priv = (struct atmel_private *)dev->priv; + struct atmel_private *priv = netdev_priv(dev); /* update the link quality here in case we are seeing no beacons at all to drive the process */ @@ -1287,7 +1287,7 @@ static int atmel_open (struct net_device *dev) { - struct atmel_private *priv = (struct atmel_private *) dev->priv; + struct atmel_private *priv = netdev_priv(dev); priv->station_state = STATION_STATE_INITIALIZING; if (!reset_atmel_card(dev)) { priv->station_state = STATION_STATE_DOWN; @@ -1298,7 +1298,7 @@ static int atmel_close (struct net_device *dev) { - struct atmel_private *priv = (struct atmel_private *) dev->priv; + struct atmel_private *priv = netdev_priv(dev); netif_carrier_off(dev); if (netif_running(dev)) @@ -1378,7 +1378,7 @@ static int atmel_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { - struct atmel_private *priv = (struct atmel_private *)data; + struct atmel_private *priv = data; int len = atmel_proc_output (page, priv); if (len <= off+count) *eof = 1; *start = page + off; @@ -1406,7 +1406,7 @@ goto err_out_free; } - priv = dev->priv; + priv = netdev_priv(dev); priv->dev = dev; priv->sys_dev = sys_dev; priv->present_callback = card_present; @@ -1525,7 +1525,7 @@ void stop_atmel_card(struct net_device *dev, int freeres) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); /* put a brick on it... */ if (priv->bus_type == BUS_TYPE_PCCARD) @@ -1582,7 +1582,7 @@ struct iw_point *dwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); /* Check if we asked for `any' */ if(dwrq->flags == 0) { @@ -1610,7 +1610,7 @@ struct iw_point *dwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); /* Get the current SSID */ if (priv->SSID_size == 0) { @@ -1633,7 +1633,7 @@ struct sockaddr *awrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); memcpy(awrq->sa_data, priv->CurrentBSSID, 6); awrq->sa_family = ARPHRD_ETHER; @@ -1645,7 +1645,7 @@ struct iw_point *dwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); /* Basic checking: do we have a key to set ? * Note : with the new API, it's impossible to get a NULL pointer. @@ -1736,7 +1736,7 @@ struct iw_point *dwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; if (!priv->wep_is_on) @@ -1776,7 +1776,7 @@ struct iw_param *vwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); if (vwrq->fixed == 0) { priv->tx_rate = 3; @@ -1808,7 +1808,7 @@ __u32 *uwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); if (*uwrq != IW_MODE_ADHOC && *uwrq != IW_MODE_INFRA) return -EINVAL; @@ -1822,7 +1822,7 @@ __u32 *uwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); *uwrq = priv->operating_mode; return 0; @@ -1833,7 +1833,7 @@ struct iw_param *vwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); if (priv->auto_tx_rate) { vwrq->fixed = 0; @@ -1855,7 +1855,7 @@ struct iw_param *vwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); priv->power_mode = vwrq->disabled ? 0 : 1; return -EINPROGRESS; } @@ -1865,7 +1865,7 @@ struct iw_param *vwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); vwrq->disabled = priv->power_mode ? 0 : 1; vwrq->flags = IW_POWER_ON; return 0; @@ -1876,7 +1876,7 @@ struct iw_param *vwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); if(!vwrq->disabled && (vwrq->flags & IW_RETRY_LIMIT)) { if(vwrq->flags & IW_RETRY_MAX) @@ -1899,7 +1899,7 @@ struct iw_param *vwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); vwrq->disabled = 0; /* Can't be disabled */ @@ -1922,7 +1922,7 @@ struct iw_param *vwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); int rthr = vwrq->value; if(vwrq->disabled) @@ -1940,7 +1940,7 @@ struct iw_param *vwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); vwrq->value = priv->rts_threshold; vwrq->disabled = (vwrq->value >= 2347); @@ -1954,7 +1954,7 @@ struct iw_param *vwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); int fthr = vwrq->value; if(vwrq->disabled) @@ -1973,7 +1973,7 @@ struct iw_param *vwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); vwrq->value = priv->frag_threshold; vwrq->disabled = (vwrq->value >= 2346); @@ -1990,7 +1990,7 @@ struct iw_freq *fwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); int rc = -EINPROGRESS; /* Call commit handler */ /* If setting by frequency, convert to a channel */ @@ -2024,7 +2024,7 @@ struct iw_freq *fwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); fwrq->m = priv->channel; fwrq->e = 0; @@ -2036,7 +2036,7 @@ struct iw_param *vwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); /* Note : you may have realised that, as this is a SET operation, * this is privileged and therefore a normal user can't @@ -2074,7 +2074,7 @@ struct iw_point *dwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); int i; char *current_ev = extra; struct iw_event iwe; @@ -2126,7 +2126,7 @@ struct iw_point *dwrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); struct iw_range *range = (struct iw_range *) extra; int k,i,j; @@ -2193,7 +2193,7 @@ struct sockaddr *awrq, char *extra) { - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); int i; static const u8 bcast[] = { 255, 255, 255, 255, 255, 255 }; @@ -2318,7 +2318,7 @@ static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { int rc = 0; - struct atmel_private *priv = (struct atmel_private *) dev->priv; + struct atmel_private *priv = netdev_priv(dev); atmel_priv_ioctl com; struct iwreq *wrq = (struct iwreq *) rq; unsigned char *new_firmware; @@ -3053,7 +3053,7 @@ static void atmel_management_timer(u_long a) { struct net_device *dev = (struct net_device *) a; - struct atmel_private *priv = (struct atmel_private *)dev->priv; + struct atmel_private *priv = netdev_priv(dev); unsigned long flags; /* Check if the card has been yanked. */ @@ -3297,7 +3297,7 @@ static int probe_atmel_card(struct net_device *dev) { int rc = 0; - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); /* reset pccard */ if (priv->bus_type == BUS_TYPE_PCCARD) @@ -3486,7 +3486,7 @@ which is the route into the rest of the firmare datastructures. */ int channel; - struct atmel_private *priv = dev->priv; + struct atmel_private *priv = netdev_priv(dev); u8 configuration; /* data to add to the firmware names, in priority order diff -Nru a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c --- a/drivers/net/wireless/orinoco.c Sun Mar 14 14:20:08 2004 +++ b/drivers/net/wireless/orinoco.c Sun Mar 14 14:20:09 2004 @@ -599,7 +599,7 @@ int __orinoco_up(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct hermes *hw = &priv->hw; int err; @@ -626,7 +626,7 @@ int __orinoco_down(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct hermes *hw = &priv->hw; int err; @@ -657,7 +657,7 @@ int orinoco_reinit_firmware(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct hermes *hw = &priv->hw; int err; @@ -685,7 +685,7 @@ static int orinoco_open(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); unsigned long flags; int err; @@ -705,7 +705,7 @@ int orinoco_stop(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int err = 0; /* We mustn't use orinoco_lock() here, because we need to be @@ -724,7 +724,7 @@ static int __orinoco_program_rids(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int err; struct hermes_idstring idbuf; @@ -912,7 +912,7 @@ /* xyzzy */ static int orinoco_reconfigure(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct hermes *hw = &priv->hw; unsigned long flags; int err = 0; @@ -965,7 +965,7 @@ * schedule_work() */ static void orinoco_reset(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct hermes *hw = &priv->hw; int err; unsigned long flags; @@ -1070,7 +1070,7 @@ static void orinoco_set_multicast_list(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); unsigned long flags; if (orinoco_lock(priv, &flags) != 0) { @@ -1433,7 +1433,7 @@ irqreturn_t orinoco_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *)dev_id; - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int count = MAX_IRQLOOPS_PER_IRQ; u16 evstat, events; @@ -1561,7 +1561,7 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); u16 infofid; struct { u16 len; @@ -1662,7 +1662,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct net_device_stats *stats = &priv->stats; struct iw_statistics *wstats = &priv->wstats; struct sk_buff *skb = NULL; @@ -1814,7 +1814,7 @@ static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct net_device_stats *stats = &priv->stats; u16 fid = hermes_read_regn(hw, TXCOMPLFID); struct hermes_tx_descriptor desc; @@ -1840,7 +1840,7 @@ static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct net_device_stats *stats = &priv->stats; stats->tx_packets++; @@ -1850,7 +1850,7 @@ static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); u16 fid = hermes_read_regn(hw, ALLOCFID); @@ -1886,7 +1886,7 @@ static void determine_firmware(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int err; struct sta_id sta_id; @@ -2024,7 +2024,7 @@ static int orinoco_init(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int err = 0; struct hermes_idstring nickbuf; @@ -2204,7 +2204,7 @@ struct net_device_stats * orinoco_get_stats(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); return &priv->stats; } @@ -2212,7 +2212,7 @@ struct iw_statistics * orinoco_get_wireless_stats(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; struct iw_statistics *wstats = &priv->wstats; int err = 0; @@ -2271,7 +2271,7 @@ static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac, int level, int noise) { - struct orinoco_private *priv = (struct orinoco_private *)dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int i; /* Gather wireless spy statistics: for each packet, compare the @@ -2290,7 +2290,7 @@ struct sk_buff *skb, struct hermes_rx_descriptor *desc) { - struct orinoco_private *priv = (struct orinoco_private *)dev->priv; + struct orinoco_private *priv = netdev_priv(dev); /* Using spy support with lots of Rx packets, like in an * infrastructure (AP), will really slow down everything, because @@ -2311,7 +2311,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) { - struct orinoco_private *priv = (struct orinoco_private *)dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct net_device_stats *stats = &priv->stats; hermes_t *hw = &priv->hw; int err = 0; @@ -2449,7 +2449,7 @@ static void orinoco_tx_timeout(struct net_device *dev) { - struct orinoco_private *priv = (struct orinoco_private *)dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct net_device_stats *stats = &priv->stats; struct hermes *hw = &priv->hw; @@ -2466,7 +2466,7 @@ static int orinoco_change_mtu(struct net_device *dev, int new_mtu) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) ) return -EINVAL; @@ -2484,7 +2484,7 @@ static void __orinoco_set_multicast_list(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int err = 0; int promisc, mc_count; @@ -2554,7 +2554,7 @@ static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int err = 0; int mode; struct iw_range range; @@ -2699,7 +2699,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int index = (erq->flags & IW_ENCODE_INDEX) - 1; int setindex = priv->tx_key; int enable = priv->wep_on; @@ -2794,7 +2794,7 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int index = (erq->flags & IW_ENCODE_INDEX) - 1; u16 xlen = 0; char keybuf[ORINOCO_MAX_KEY_SIZE]; @@ -2841,7 +2841,7 @@ static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); char essidbuf[IW_ESSID_MAX_SIZE+1]; int err; unsigned long flags; @@ -2874,7 +2874,7 @@ static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); char essidbuf[IW_ESSID_MAX_SIZE+1]; int active; int err = 0; @@ -2907,7 +2907,7 @@ static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); char nickbuf[IW_ESSID_MAX_SIZE+1]; int err; unsigned long flags; @@ -2935,7 +2935,7 @@ static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); char nickbuf[IW_ESSID_MAX_SIZE+1]; int err; unsigned long flags; @@ -2957,7 +2957,7 @@ static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int chan = -1; int err; unsigned long flags; @@ -2999,7 +2999,7 @@ static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; u16 val; int err; @@ -3025,7 +3025,7 @@ static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int val = srq->value; int err; unsigned long flags; @@ -3047,7 +3047,7 @@ static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int val = rrq->value; int err; unsigned long flags; @@ -3070,7 +3070,7 @@ static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int err = 0; unsigned long flags; @@ -3105,7 +3105,7 @@ static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int err = 0; u16 val; @@ -3143,7 +3143,7 @@ static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *rrq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int err = 0; int ratemode = -1; int bitrate; /* 100s of kilobits */ @@ -3186,7 +3186,7 @@ static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *rrq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int err = 0; int ratemode; @@ -3253,7 +3253,7 @@ static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int err = 0; unsigned long flags; @@ -3306,7 +3306,7 @@ static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int err = 0; u16 enable, period, timeout, mcast; @@ -3356,7 +3356,7 @@ #if WIRELESS_EXT > 10 static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; int err = 0; u16 short_limit, long_limit, lifetime; @@ -3409,7 +3409,7 @@ static int orinoco_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int val = *( (int *) wrq->u.name ); int err; unsigned long flags; @@ -3429,7 +3429,7 @@ static int orinoco_ioctl_getibssport(struct net_device *dev, struct iwreq *wrq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int *val = (int *)wrq->u.name; int err; unsigned long flags; @@ -3446,7 +3446,7 @@ static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int val = *( (int *) wrq->u.name ); int err = 0; unsigned long flags; @@ -3488,7 +3488,7 @@ static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); int *val = (int *)wrq->u.name; int err; unsigned long flags; @@ -3507,7 +3507,7 @@ * Jean II */ static int orinoco_ioctl_setspy(struct net_device *dev, struct iw_point *srq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct sockaddr address[IW_MAX_SPY]; int number = srq->length; int i; @@ -3554,7 +3554,7 @@ static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct sockaddr address[IW_MAX_SPY]; struct iw_quality spy_stat[IW_MAX_SPY]; int number; @@ -3601,7 +3601,7 @@ static int orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); struct iwreq *wrq = (struct iwreq *)rq; int err = 0; int tmp; @@ -4057,7 +4057,7 @@ static int orinoco_debug_dump_recs(struct net_device *dev) { - struct orinoco_private *priv = dev->priv; + struct orinoco_private *priv = netdev_priv(dev); hermes_t *hw = &priv->hw; u8 *val8; u16 *val16; @@ -4131,7 +4131,7 @@ dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card); if (!dev) return NULL; - priv = (struct orinoco_private *)dev->priv; + priv = netdev_priv(dev); priv->ndev = dev; if (sizeof_card) priv->card = (void *)((unsigned long)dev->priv + sizeof(struct orinoco_private)); diff -Nru a/drivers/net/wireless/prism54/Makefile b/drivers/net/wireless/prism54/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/Makefile Sun Mar 14 14:20:09 2004 @@ -0,0 +1,10 @@ +# $Id: Makefile.k26,v 1.7 2004/01/30 16:24:00 ajfa Exp $ + +prism54-objs := islpci_eth.o islpci_mgt.o \ + isl_38xx.o isl_ioctl.o islpci_dev.o \ + islpci_hotplug.o oid_mgt.o + +obj-$(CONFIG_PRISM54) += prism54.o + +EXTRA_CFLAGS = -I$(PWD) #-DCONFIG_PRISM54_WDS + diff -Nru a/drivers/net/wireless/prism54/isl_38xx.c b/drivers/net/wireless/prism54/isl_38xx.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/isl_38xx.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,397 @@ +/* $Header: /var/lib/cvs/prism54-ng/ksrc/isl_38xx.c,v 1.22 2004/02/28 03:06:07 mcgrof Exp $ + * + * Copyright (C) 2002 Intersil Americas Inc. + * Copyright (C) 2003-2004 Luis R. Rodriguez _ + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define __KERNEL_SYSCALLS__ + +#include +#include +#include +#include + +#include "isl_38xx.h" +#include + +#include +#include + +#include +#if !defined(CONFIG_FW_LOADER) && !defined(CONFIG_FW_LOADER_MODULE) +#error No Firmware Loading configured in the kernel ! +#endif + +#include "islpci_dev.h" +#include "islpci_mgt.h" + +/****************************************************************************** + Device Interface & Control functions +******************************************************************************/ + +/** + * isl38xx_disable_interrupts - disable all interrupts + * @device: pci memory base address + * + * Instructs the device to disable all interrupt reporting by asserting + * the IRQ line. New events may still show up in the interrupt identification + * register located at offset %ISL38XX_INT_IDENT_REG. + */ +void +isl38xx_disable_interrupts(void *device) +{ + isl38xx_w32_flush(device, 0x00000000, ISL38XX_INT_EN_REG); + udelay(ISL38XX_WRITEIO_DELAY); +} + +void +isl38xx_handle_sleep_request(isl38xx_control_block *control_block, + int *powerstate, void *device_base) +{ + /* device requests to go into sleep mode + * check whether the transmit queues for data and management are empty */ + if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ)) + /* data tx queue not empty */ + return; + + if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ)) + /* management tx queue not empty */ + return; + + /* check also whether received frames are pending */ + if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_DATA_LQ)) + /* data rx queue not empty */ + return; + + if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_MGMTQ)) + /* management rx queue not empty */ + return; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "Device going to sleep mode\n"); +#endif + + /* all queues are empty, allow the device to go into sleep mode */ + *powerstate = ISL38XX_PSM_POWERSAVE_STATE; + + /* assert the Sleep interrupt in the Device Interrupt Register */ + isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_SLEEP, + ISL38XX_DEV_INT_REG); + udelay(ISL38XX_WRITEIO_DELAY); +} + +void +isl38xx_handle_wakeup(isl38xx_control_block *control_block, + int *powerstate, void *device_base) +{ + /* device is in active state, update the powerstate flag */ + *powerstate = ISL38XX_PSM_ACTIVE_STATE; + + /* now check whether there are frames pending for the card */ + if (!isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ) + && !isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ)) + return; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_ANYTHING, "Wake up handler trigger the device\n"); +#endif + + /* either data or management transmit queue has a frame pending + * trigger the device by setting the Update bit in the Device Int reg */ + isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE, + ISL38XX_DEV_INT_REG); + udelay(ISL38XX_WRITEIO_DELAY); +} + +void +isl38xx_trigger_device(int asleep, void *device_base) +{ + struct timeval current_time; + u32 reg, counter = 0; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "isl38xx trigger device\n"); +#endif + + /* check whether the device is in power save mode */ + if (asleep) { + /* device is in powersave, trigger the device for wakeup */ +#if VERBOSE > SHOW_ERROR_MESSAGES + do_gettimeofday(¤t_time); + DEBUG(SHOW_TRACING, "%08li.%08li Device wakeup triggered\n", + current_time.tv_sec, current_time.tv_usec); +#endif + + DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n", + current_time.tv_sec, current_time.tv_usec, + readl(device_base + ISL38XX_CTRL_STAT_REG)); + udelay(ISL38XX_WRITEIO_DELAY); + + if (reg = readl(device_base + ISL38XX_INT_IDENT_REG), + reg == 0xabadface) { +#if VERBOSE > SHOW_ERROR_MESSAGES + do_gettimeofday(¤t_time); + DEBUG(SHOW_TRACING, + "%08li.%08li Device register abadface\n", + current_time.tv_sec, current_time.tv_usec); +#endif + /* read the Device Status Register until Sleepmode bit is set */ + while (reg = readl(device_base + ISL38XX_CTRL_STAT_REG), + (reg & ISL38XX_CTRL_STAT_SLEEPMODE) == 0) { + udelay(ISL38XX_WRITEIO_DELAY); + counter++; + } + + DEBUG(SHOW_TRACING, + "%08li.%08li Device register read %08x\n", + current_time.tv_sec, current_time.tv_usec, + readl(device_base + ISL38XX_CTRL_STAT_REG)); + udelay(ISL38XX_WRITEIO_DELAY); + +#if VERBOSE > SHOW_ERROR_MESSAGES + do_gettimeofday(¤t_time); + DEBUG(SHOW_TRACING, + "%08li.%08li Device asleep counter %i\n", + current_time.tv_sec, current_time.tv_usec, + counter); +#endif + } + /* assert the Wakeup interrupt in the Device Interrupt Register */ + isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_WAKEUP, + ISL38XX_DEV_INT_REG); + udelay(ISL38XX_WRITEIO_DELAY); + + /* perform another read on the Device Status Register */ + reg = readl(device_base + ISL38XX_CTRL_STAT_REG); + udelay(ISL38XX_WRITEIO_DELAY); + +#if VERBOSE > SHOW_ERROR_MESSAGES + do_gettimeofday(¤t_time); + DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n", + current_time.tv_sec, current_time.tv_usec, reg); +#endif + } else { + /* device is (still) awake */ +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "Device is in active state\n"); +#endif + /* trigger the device by setting the Update bit in the Device Int reg */ + + isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE, + ISL38XX_DEV_INT_REG); + udelay(ISL38XX_WRITEIO_DELAY); + } +} + +void +isl38xx_interface_reset(void *device_base, dma_addr_t host_address) +{ + u32 reg; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "isl38xx_interface_reset \n"); +#endif + + /* load the address of the control block in the device */ + isl38xx_w32_flush(device_base, host_address, ISL38XX_CTRL_BLK_BASE_REG); + udelay(ISL38XX_WRITEIO_DELAY); + + /* set the reset bit in the Device Interrupt Register */ + isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_RESET, + ISL38XX_DEV_INT_REG); + udelay(ISL38XX_WRITEIO_DELAY); + + /* enable the interrupt for detecting initialization */ + + /* Note: Do not enable other interrupts here. We want the + * device to have come up first 100% before allowing any other + * interrupts. */ + reg = ISL38XX_INT_IDENT_INIT; + + isl38xx_w32_flush(device_base, reg, ISL38XX_INT_EN_REG); + udelay(ISL38XX_WRITEIO_DELAY); /* allow complete full reset */ +} + +void +isl38xx_enable_common_interrupts(void *device_base) { + u32 reg; + reg = ( ISL38XX_INT_IDENT_UPDATE | + ISL38XX_INT_IDENT_SLEEP | ISL38XX_INT_IDENT_WAKEUP); + isl38xx_w32_flush(device_base, reg, ISL38XX_INT_EN_REG); + udelay(ISL38XX_WRITEIO_DELAY); +} + +int +isl38xx_upload_firmware(char *fw_id, _REQ_FW_DEV_T dev, void *device_base, + dma_addr_t host_address) +{ + u32 reg, rc; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_ERROR_MESSAGES, "isl38xx_upload_firmware(0x%lx, 0x%lx)\n", + (long) device_base, (long) host_address); +#endif + + /* clear the RAMBoot and the Reset bit */ + reg = readl(device_base + ISL38XX_CTRL_STAT_REG); + reg &= ~ISL38XX_CTRL_STAT_RESET; + reg &= ~ISL38XX_CTRL_STAT_RAMBOOT; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + /* set the Reset bit without reading the register ! */ + reg |= ISL38XX_CTRL_STAT_RESET; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + /* clear the Reset bit */ + reg &= ~ISL38XX_CTRL_STAT_RESET; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + wmb(); + + /* wait a while for the device to reboot */ + mdelay(50); + + { + const struct firmware *fw_entry = 0; + long fw_len; + const u32 *fw_ptr; + + rc = request_firmware(&fw_entry, fw_id, dev); + if (rc) { + printk(KERN_ERR + "%s: request_firmware() failed for '%s'\n", + "prism54", fw_id); + return rc; + } + /* prepare the Direct Memory Base register */ + reg = ISL38XX_DEV_FIRMWARE_ADDRES; + + fw_ptr = (u32 *) fw_entry->data; + fw_len = fw_entry->size; + + if (fw_len % 4) { + printk(KERN_ERR + "%s: firmware '%s' size is not multiple of 32bit, aborting!\n", + "prism54", fw_id); + release_firmware(fw_entry); + return EILSEQ; /* Illegal byte sequence */; + } + + while (fw_len > 0) { + long _fw_len = + (fw_len > + ISL38XX_MEMORY_WINDOW_SIZE) ? + ISL38XX_MEMORY_WINDOW_SIZE : fw_len; + u32 *dev_fw_ptr = device_base + ISL38XX_DIRECT_MEM_WIN; + + /* set the cards base address for writting the data */ + isl38xx_w32_flush(device_base, reg, + ISL38XX_DIR_MEM_BASE_REG); + wmb(); /* be paranoid */ + + /* increment the write address for next iteration */ + reg += _fw_len; + fw_len -= _fw_len; + + /* write the data to the Direct Memory Window 32bit-wise */ + /* memcpy_toio() doesn't guarantee 32bit writes :-| */ + while (_fw_len > 0) { + /* use non-swapping writel() */ + __raw_writel(*fw_ptr, dev_fw_ptr); + fw_ptr++, dev_fw_ptr++; + _fw_len -= 4; + } + + /* flush PCI posting */ + (void) readl(device_base + ISL38XX_PCI_POSTING_FLUSH); + wmb(); /* be paranoid again */ + + BUG_ON(_fw_len != 0); + } + + BUG_ON(fw_len != 0); + + release_firmware(fw_entry); + } + + /* now reset the device + * clear the Reset & ClkRun bit, set the RAMBoot bit */ + reg = readl(device_base + ISL38XX_CTRL_STAT_REG); + reg &= ~ISL38XX_CTRL_STAT_CLKRUN; + reg &= ~ISL38XX_CTRL_STAT_RESET; + reg |= ISL38XX_CTRL_STAT_RAMBOOT; + isl38xx_w32_flush(device_base, reg, ISL38XX_CTRL_STAT_REG); + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + /* set the reset bit latches the host override and RAMBoot bits + * into the device for operation when the reset bit is reset */ + reg |= ISL38XX_CTRL_STAT_RESET; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + /* don't do flush PCI posting here! */ + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + /* clear the reset bit should start the whole circus */ + reg &= ~ISL38XX_CTRL_STAT_RESET; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + /* don't do flush PCI posting here! */ + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + return 0; +} + +int +isl38xx_in_queue(isl38xx_control_block *cb, int queue) +{ + const s32 delta = (le32_to_cpu(cb->driver_curr_frag[queue]) - + le32_to_cpu(cb->device_curr_frag[queue])); + + /* determine the amount of fragments in the queue depending on the type + * of the queue, either transmit or receive */ + + BUG_ON(delta < 0); /* driver ptr must be ahead of device ptr */ + + switch (queue) { + /* send queues */ + case ISL38XX_CB_TX_MGMTQ: + BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE); + case ISL38XX_CB_TX_DATA_LQ: + case ISL38XX_CB_TX_DATA_HQ: + BUG_ON(delta > ISL38XX_CB_TX_QSIZE); + return delta; + break; + + /* receive queues */ + case ISL38XX_CB_RX_MGMTQ: + BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE); + return ISL38XX_CB_MGMT_QSIZE - delta; + break; + + case ISL38XX_CB_RX_DATA_LQ: + case ISL38XX_CB_RX_DATA_HQ: + BUG_ON(delta > ISL38XX_CB_RX_QSIZE); + return ISL38XX_CB_RX_QSIZE - delta; + break; + } + BUG(); + return 0; +} diff -Nru a/drivers/net/wireless/prism54/isl_38xx.h b/drivers/net/wireless/prism54/isl_38xx.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/isl_38xx.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,179 @@ +/* $Header: /var/lib/cvs/prism54-ng/ksrc/isl_38xx.h,v 1.22 2004/02/28 03:06:07 mcgrof Exp $ + * + * Copyright (C) 2002 Intersil Americas Inc. + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _ISL_38XX_H +#define _ISL_38XX_H + +#include +#include + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,75)) +#include +# define _REQ_FW_DEV_T struct device * +#else +# define _REQ_FW_DEV_T char * +#endif + +#include + +#define ISL38XX_CB_RX_QSIZE 8 +#define ISL38XX_CB_TX_QSIZE 32 + +/* ISL38XX Access Point Specific definitions */ +#define ISL38XX_MAX_WDS_LINKS 8 + +/* ISL38xx Client Specific definitions */ +#define ISL38XX_PSM_ACTIVE_STATE 0 +#define ISL38XX_PSM_POWERSAVE_STATE 1 + +/* ISL38XX Host Interface Definitions */ +#define ISL38XX_PCI_MEM_SIZE 0x02000 +#define ISL38XX_MEMORY_WINDOW_SIZE 0x01000 +#define ISL38XX_DEV_FIRMWARE_ADDRES 0x20000 +#define ISL38XX_WRITEIO_DELAY 10 /* in us */ +#define ISL38XX_RESET_DELAY 50 /* in ms */ +#define ISL38XX_WAIT_CYCLE 10 /* in 10ms */ +#define ISL38XX_MAX_WAIT_CYCLES 10 + +/* PCI Memory Area */ +#define ISL38XX_HARDWARE_REG 0x0000 +#define ISL38XX_CARDBUS_CIS 0x0800 +#define ISL38XX_DIRECT_MEM_WIN 0x1000 + +/* Hardware registers */ +#define ISL38XX_DEV_INT_REG 0x0000 +#define ISL38XX_INT_IDENT_REG 0x0010 +#define ISL38XX_INT_ACK_REG 0x0014 +#define ISL38XX_INT_EN_REG 0x0018 +#define ISL38XX_GEN_PURP_COM_REG_1 0x0020 +#define ISL38XX_GEN_PURP_COM_REG_2 0x0024 +#define ISL38XX_CTRL_BLK_BASE_REG ISL38XX_GEN_PURP_COM_REG_1 +#define ISL38XX_DIR_MEM_BASE_REG 0x0030 +#define ISL38XX_CTRL_STAT_REG 0x0078 + +/* High end mobos queue up pci writes, the following + * is used to "read" from after a write to force flush */ +#define ISL38XX_PCI_POSTING_FLUSH ISL38XX_INT_EN_REG + +/** + * isl38xx_w32_flush - PCI iomem write helper + * @base: (host) memory base address of the device + * @val: 32bit value (host order) to write + * @offset: byte offset into @base to write value to + * + * This helper takes care of writing a 32bit datum to the + * specified offset into the device's pci memory space, and making sure + * the pci memory buffers get flushed by performing one harmless read + * from the %ISL38XX_PCI_POSTING_FLUSH offset. + */ +static inline void +isl38xx_w32_flush(void *base, u32 val, unsigned long offset) +{ + writel(val, base + offset); + (void) readl(base + ISL38XX_PCI_POSTING_FLUSH); +} + +/* Device Interrupt register bits */ +#define ISL38XX_DEV_INT_RESET 0x0001 +#define ISL38XX_DEV_INT_UPDATE 0x0002 +#define ISL38XX_DEV_INT_WAKEUP 0x0008 +#define ISL38XX_DEV_INT_SLEEP 0x0010 + +/* Interrupt Identification/Acknowledge/Enable register bits */ +#define ISL38XX_INT_IDENT_UPDATE 0x0002 +#define ISL38XX_INT_IDENT_INIT 0x0004 +#define ISL38XX_INT_IDENT_WAKEUP 0x0008 +#define ISL38XX_INT_IDENT_SLEEP 0x0010 +#define ISL38XX_INT_SOURCES 0x001E + +/* Control/Status register bits */ +#define ISL38XX_CTRL_STAT_SLEEPMODE 0x00000200 +#define ISL38XX_CTRL_STAT_CLKRUN 0x00800000 +#define ISL38XX_CTRL_STAT_RESET 0x10000000 +#define ISL38XX_CTRL_STAT_RAMBOOT 0x20000000 +#define ISL38XX_CTRL_STAT_STARTHALTED 0x40000000 +#define ISL38XX_CTRL_STAT_HOST_OVERRIDE 0x80000000 + +/* Control Block definitions */ +#define ISL38XX_CB_RX_DATA_LQ 0 +#define ISL38XX_CB_TX_DATA_LQ 1 +#define ISL38XX_CB_RX_DATA_HQ 2 +#define ISL38XX_CB_TX_DATA_HQ 3 +#define ISL38XX_CB_RX_MGMTQ 4 +#define ISL38XX_CB_TX_MGMTQ 5 +#define ISL38XX_CB_QCOUNT 6 +#define ISL38XX_CB_MGMT_QSIZE 4 +#define ISL38XX_MIN_QTHRESHOLD 4 /* fragments */ + +/* Memory Manager definitions */ +#define MGMT_FRAME_SIZE 1500 /* >= size struct obj_bsslist */ +#define MGMT_TX_FRAME_COUNT 24 /* max 4 + spare 4 + 8 init */ +#define MGMT_RX_FRAME_COUNT 24 /* 4*4 + spare 8 */ +#define MGMT_FRAME_COUNT (MGMT_TX_FRAME_COUNT + MGMT_RX_FRAME_COUNT) +#define CONTROL_BLOCK_SIZE 1024 /* should be enough */ +#define PSM_FRAME_SIZE 1536 +#define PSM_MINIMAL_STATION_COUNT 64 +#define PSM_FRAME_COUNT PSM_MINIMAL_STATION_COUNT +#define PSM_BUFFER_SIZE PSM_FRAME_SIZE * PSM_FRAME_COUNT +#define MAX_TRAP_RX_QUEUE 4 +#define HOST_MEM_BLOCK CONTROL_BLOCK_SIZE + PSM_BUFFER_SIZE + +/* Fragment package definitions */ +#define FRAGMENT_FLAG_MF 0x0001 +#define MAX_FRAGMENT_SIZE 1536 + +/* In monitor mode frames have a header. I don't know exactly how big those + * frame can be but I've never seen any frame bigger than 1584... : + */ +#define MAX_FRAGMENT_SIZE_RX 1600 + +typedef struct { + u32 address; /* physical address on host */ + u16 size; /* packet size */ + u16 flags; /* set of bit-wise flags */ +} isl38xx_fragment; + +struct isl38xx_cb { + u32 driver_curr_frag[ISL38XX_CB_QCOUNT]; + u32 device_curr_frag[ISL38XX_CB_QCOUNT]; + isl38xx_fragment rx_data_low[ISL38XX_CB_RX_QSIZE]; + isl38xx_fragment tx_data_low[ISL38XX_CB_TX_QSIZE]; + isl38xx_fragment rx_data_high[ISL38XX_CB_RX_QSIZE]; + isl38xx_fragment tx_data_high[ISL38XX_CB_TX_QSIZE]; + isl38xx_fragment rx_data_mgmt[ISL38XX_CB_MGMT_QSIZE]; + isl38xx_fragment tx_data_mgmt[ISL38XX_CB_MGMT_QSIZE]; +}; + +typedef struct isl38xx_cb isl38xx_control_block; + +/* determine number of entries currently in queue */ +int isl38xx_in_queue(isl38xx_control_block *cb, int queue); + +void isl38xx_disable_interrupts(void *); +void isl38xx_enable_common_interrupts(void *); + +void isl38xx_handle_sleep_request(isl38xx_control_block *, int *, + void *); +void isl38xx_handle_wakeup(isl38xx_control_block *, int *, void *); +void isl38xx_trigger_device(int, void *); +void isl38xx_interface_reset(void *, dma_addr_t); + +int isl38xx_upload_firmware(char *, _REQ_FW_DEV_T, void *, dma_addr_t); + +#endif /* _ISL_38XX_H */ diff -Nru a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/isl_ioctl.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,2155 @@ +/* $Header: /var/lib/cvs/prism54-ng/ksrc/isl_ioctl.c,v 1.140 2004/02/28 03:06:07 mcgrof Exp $ + * + * Copyright (C) 2002 Intersil Americas Inc. + * (C) 2003 Aurelien Alleaume + * (C) 2003 Herbert Valerio Riedel + * (C) 2003 Luis R. Rodriguez + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include + +#include + +#include "isl_ioctl.h" +#include "islpci_mgt.h" +#include "isl_oid.h" /* additional types and defs for isl38xx fw */ +#include "oid_mgt.h" + +#include /* New driver API */ + +static int init_mode = CARD_DEFAULT_IW_MODE; +static int init_channel = CARD_DEFAULT_CHANNEL; +static int init_wep = CARD_DEFAULT_WEP; +static int init_filter = CARD_DEFAULT_FILTER; +static int init_authen = CARD_DEFAULT_AUTHEN; +static int init_dot1x = CARD_DEFAULT_DOT1X; +static int init_conformance = CARD_DEFAULT_CONFORMANCE; +static int init_mlme = CARD_DEFAULT_MLME_MODE; + +MODULE_PARM(init_mode, "i"); +MODULE_PARM_DESC(init_mode, + "Set card mode:\n0: Auto\n1: Ad-Hoc\n2: Managed Client (Default)\n3: Master / Access Point\n4: Repeater (Not supported yet)\n5: Secondary (Not supported yet)\n6: Monitor"); + +MODULE_PARM(init_channel, "i"); +MODULE_PARM_DESC(init_channel, + "Check `iwpriv ethx channel` for available channels"); + +MODULE_PARM(init_wep, "i"); +MODULE_PARM(init_filter, "i"); + +MODULE_PARM(init_authen, "i"); +MODULE_PARM_DESC(init_authen, + "Authentication method. Can be of seven types:\n0 0x0000: None\n1 0x0001: DOT11_AUTH_OS (Default)\n2 0x0002: DOT11_AUTH_SK\n3 0x0003: DOT11_AUTH_BOTH"); + +MODULE_PARM(init_dot1x, "i"); +MODULE_PARM_DESC(init_dot1x, + "\n0: None/not set (Default)\n1: DOT11_DOT1X_AUTHENABLED\n2: DOT11_DOT1X_KEYTXENABLED"); + +MODULE_PARM(init_mlme, "i"); +MODULE_PARM_DESC(init_mlme, + "Sets the MAC layer management entity (MLME) mode of operation,\n0: DOT11_MLME_AUTO (Default)\n1: DOT11_MLME_INTERMEDIATE\n2: DOT11_MLME_EXTENDED"); + +/** + * prism54_mib_mode_helper - MIB change mode helper function + * @mib: the &struct islpci_mib object to modify + * @iw_mode: new mode (%IW_MODE_*) + * + * This is a helper function, hence it does not lock. Make sure + * caller deals with locking *if* necessary. This function sets the + * mode-dependent mib values and does the mapping of the Linux + * Wireless API modes to Device firmware modes. It also checks for + * correct valid Linux wireless modes. + */ +int +prism54_mib_mode_helper(islpci_private *priv, u32 iw_mode) +{ + u32 config = INL_CONFIG_MANUALRUN; + u32 mode, bsstype; + + /* For now, just catch early the Repeater and Secondary modes here */ + if (iw_mode == IW_MODE_REPEAT || iw_mode == IW_MODE_SECOND) { + printk(KERN_DEBUG "%s(): Sorry, Repeater mode and Secondary mode " + "are not yet supported by this driver.\n", + __FUNCTION__); + return -EINVAL; + } + + priv->iw_mode = iw_mode; + + switch (iw_mode) { + case IW_MODE_AUTO: + mode = INL_MODE_CLIENT; + bsstype = DOT11_BSSTYPE_ANY; + break; + case IW_MODE_ADHOC: + mode = INL_MODE_CLIENT; + bsstype = DOT11_BSSTYPE_IBSS; + break; + case IW_MODE_INFRA: + mode = INL_MODE_CLIENT; + bsstype = DOT11_BSSTYPE_INFRA; + break; + case IW_MODE_MASTER: + mode = INL_MODE_AP; + bsstype = DOT11_BSSTYPE_INFRA; + break; + case IW_MODE_MONITOR: + mode = INL_MODE_PROMISCUOUS; + bsstype = DOT11_BSSTYPE_ANY; + config |= INL_CONFIG_RXANNEX; + break; + default: + return -EINVAL; + } + + if (init_wds) + config |= INL_CONFIG_WDS; + mgt_set(priv, DOT11_OID_BSSTYPE, &bsstype); + mgt_set(priv, OID_INL_CONFIG, &config); + mgt_set(priv, OID_INL_MODE, &mode); + + return 0; +} + +/** + * prism54_mib_init - fill MIB cache with defaults + * + * this function initializes the struct given as @mib with defaults, + * of which many are retrieved from the global module parameter + * variables. + */ + +void +prism54_mib_init(islpci_private *priv) +{ + u32 t; + struct obj_buffer psm_buffer = { + .size = cpu_to_le32(PSM_BUFFER_SIZE), + .addr = cpu_to_le32(priv->device_psm_buffer) + }; + + mgt_set(priv, DOT11_OID_CHANNEL, &init_channel); + mgt_set(priv, DOT11_OID_AUTHENABLE, &init_authen); + mgt_set(priv, DOT11_OID_PRIVACYINVOKED, &init_wep); + + mgt_set(priv, DOT11_OID_PSMBUFFER, &psm_buffer); + mgt_set(priv, DOT11_OID_EXUNENCRYPTED, &init_filter); + mgt_set(priv, DOT11_OID_DOT1XENABLE, &init_dot1x); + mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &init_mlme); + mgt_set(priv, OID_INL_DOT11D_CONFORMANCE, &init_conformance); + + t = 127; + mgt_set(priv, OID_INL_OUTPUTPOWER, &t); + + /* Important: we are setting a default wireless mode and we are + * forcing a valid one, so prism54_mib_mode_helper should just set + * mib values depending on what the wireless mode given is. No need + * for it save old values */ + if (init_mode > IW_MODE_MONITOR || init_mode < IW_MODE_AUTO) { + printk(KERN_DEBUG "%s(): You passed a non-valid init_mode. " + "Using default mode\n", __FUNCTION__); + init_mode = CARD_DEFAULT_IW_MODE; + } + /* This sets all of the mode-dependent values */ + prism54_mib_mode_helper(priv, init_mode); +} + +void +prism54_mib_init_work(islpci_private *priv) +{ + down_write(&priv->mib_sem); + mgt_commit(priv); + up_write(&priv->mib_sem); +} + +/* this will be executed outside of atomic context thanks to + * schedule_work(), thus we can as well use sleeping semaphore + * locking */ +void +prism54_update_stats(islpci_private *priv) +{ + char *data; + int j; + struct obj_bss bss, *bss2; + union oid_res_t r; + + if (down_interruptible(&priv->stats_sem)) + return; + +/* missing stats are : + * iwstatistics.qual.updated + * iwstatistics.discard.nwid + * iwstatistics.discard.fragment + * iwstatistics.discard.misc + * iwstatistics.miss.beacon */ + +/* Noise floor. + * I'm not sure if the unit is dBm. + * Note : If we are not connected, this value seems to be irrevelant. */ + + mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r); + priv->local_iwstatistics.qual.noise = r.u; + +/* Get the rssi of the link. To do this we need to retrieve a bss. */ + + /* First get the MAC address of the AP we are associated with. */ + mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r); + data = r.ptr; + + /* copy this MAC to the bss */ + for (j = 0; j < 6; j++) + bss.address[j] = data[j]; + kfree(data); + + /* now ask for the corresponding bss */ + j = mgt_get_request(priv, DOT11_OID_BSSFIND, 0, (void *) &bss, &r); + bss2 = r.ptr; + /* report the rssi and use it to calculate + * link quality through a signal-noise + * ratio */ + priv->local_iwstatistics.qual.level = bss2->rssi; + priv->local_iwstatistics.qual.qual = + bss2->rssi - priv->iwstatistics.qual.noise; + + kfree(bss2); + + /* report that the stats are new */ + priv->local_iwstatistics.qual.updated = 0x7; + +/* Rx : unable to decrypt the MPDU */ + mgt_get_request(priv, DOT11_OID_PRIVRXFAILED, 0, NULL, &r); + priv->local_iwstatistics.discard.code = r.u; + +/* Tx : Max MAC retries num reached */ + mgt_get_request(priv, DOT11_OID_MPDUTXFAILED, 0, NULL, &r); + priv->local_iwstatistics.discard.retries = r.u; + + up(&priv->stats_sem); + + return; +} + +struct iw_statistics * +prism54_get_wireless_stats(struct net_device *ndev) +{ + islpci_private *priv = ndev->priv; + + /* If the stats are being updated return old data */ + if (down_trylock(&priv->stats_sem) == 0) { + memcpy(&priv->iwstatistics, &priv->local_iwstatistics, + sizeof (struct iw_statistics)); + /* They won't be marked updated for the next time */ + priv->local_iwstatistics.qual.updated = 0; + up(&priv->stats_sem); + } else + priv->iwstatistics.qual.updated = 0; + + /* Update our wireless stats, but do not schedule to often + * (max 1 HZ) */ + if ((priv->stats_timestamp == 0) || + time_after(jiffies, priv->stats_timestamp + 1 * HZ)) { + schedule_work(&priv->stats_work); + priv->stats_timestamp = jiffies; + } + + return &priv->iwstatistics; +} + +static int +prism54_commit(struct net_device *ndev, struct iw_request_info *info, + char *cwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + + /* simply re-set the last set SSID, this should commit most stuff */ + + /* Commit in Monitor mode is not necessary, also setting essid + * in Monitor mode does not make sense and isn't allowed for this + * device's firmware */ + if(priv->iw_mode != IW_MODE_MONITOR) + return mgt_set_request(priv, DOT11_OID_SSID, 0, NULL); + return 0; +} + +static int +prism54_get_name(struct net_device *ndev, struct iw_request_info *info, + char *cwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + char *capabilities; + union oid_res_t r; + int rvalue; + + if (islpci_get_state(priv) < PRV_STATE_INIT) { + strncpy(cwrq, "NOT READY!", IFNAMSIZ); + return 0; + } + rvalue = mgt_get_request(priv, OID_INL_PHYCAPABILITIES, 0, NULL, &r); + + switch (r.u) { + case INL_PHYCAP_5000MHZ: + capabilities = "IEEE 802.11a/b/g"; + break; + case INL_PHYCAP_FAA: + capabilities = "IEEE 802.11b/g - FAA Support"; + break; + case INL_PHYCAP_2400MHZ: + default: + capabilities = "IEEE 802.11b/g"; /* Default */ + break; + } + strncpy(cwrq, capabilities, IFNAMSIZ); + return rvalue; +} + +static int +prism54_set_freq(struct net_device *ndev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + int rvalue; + u32 c = 0; + + /* prepare the structure for the set object */ + if (fwrq->m < 1000) + /* structure value contains a channel indication */ + c = fwrq->m; + else { + /* structure contains a frequency indication and fwrq->e = 1 */ + int f = fwrq->m / 100000; + + if (fwrq->e != 1) + return -EINVAL; + if ((f >= 2412) && (f <= 2484)) { + while ((c < 14) && (f != frequency_list_bg[c])) + c++; + if (c >= 14) + return -EINVAL; + } else if ((f >= (int) 5170) && (f <= (int) 5320)) { + while ((c < 12) && (f != frequency_list_a[c])) + c++; + if (c >= 12) + return -EINVAL; + } else + return -EINVAL; + c++; + } + + rvalue = mgt_set_request(priv, DOT11_OID_CHANNEL, 0, &c); + + /* Call commit handler */ + return (rvalue ? rvalue : -EINPROGRESS); +} + +static int +prism54_get_freq(struct net_device *ndev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + union oid_res_t r; + int rvalue; + + rvalue = mgt_get_request(priv, DOT11_OID_CHANNEL, 0, NULL, &r); + + fwrq->m = r.u; + fwrq->e = 0; + + return rvalue; +} + +static int +prism54_set_mode(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + u32 mlmeautolevel = CARD_DEFAULT_MLME_MODE; + + /* Let's see if the user passed a valid Linux Wireless mode */ + if (*uwrq > IW_MODE_MONITOR || *uwrq < IW_MODE_AUTO) { + printk(KERN_DEBUG + "%s: %s() You passed a non-valid init_mode.\n", + priv->ndev->name, __FUNCTION__); + return -EINVAL; + } + + down_write(&priv->mib_sem); + + if (prism54_mib_mode_helper(priv, *uwrq)) { + up_write(&priv->mib_sem); + return -EOPNOTSUPP; + } + + /* the ACL code needs an intermediate mlmeautolevel. The wpa stuff an + * extended one. + */ + if ((*uwrq == IW_MODE_MASTER) && (priv->acl.policy != MAC_POLICY_OPEN)) + mlmeautolevel = DOT11_MLME_INTERMEDIATE; + if (priv->wpa) + mlmeautolevel = DOT11_MLME_EXTENDED; + + mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel); + + mgt_commit(priv); + priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) + ? ARPHRD_IEEE80211 : ARPHRD_ETHER; + up_write(&priv->mib_sem); + + return 0; +} + +/* Use mib cache */ +static int +prism54_get_mode(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + + BUG_ON((priv->iw_mode < IW_MODE_AUTO) || (priv->iw_mode > + IW_MODE_MONITOR)); + *uwrq = priv->iw_mode; + + return 0; +} + +/* we use DOT11_OID_EDTHRESHOLD. From what I guess the card will not try to + * emit data if (sensitivity > rssi - noise) (in dBm). + * prism54_set_sens does not seem to work. + */ + +static int +prism54_set_sens(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + u32 sens; + + /* by default the card sets this to 20. */ + sens = vwrq->disabled ? 20 : vwrq->value; + + /* set the ed threshold. */ + return mgt_set_request(priv, DOT11_OID_EDTHRESHOLD, 0, &sens); +} + +static int +prism54_get_sens(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + union oid_res_t r; + int rvalue; + + rvalue = mgt_get_request(priv, DOT11_OID_EDTHRESHOLD, 0, NULL, &r); + + vwrq->value = r.u; + vwrq->disabled = (vwrq->value == 0); + vwrq->fixed = 1; + + return rvalue; +} + +static int +prism54_get_range(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + struct iw_range *range = (struct iw_range *) extra; + islpci_private *priv = ndev->priv; + char *data; + int i, m, rvalue; + struct obj_frequencies *freq; + union oid_res_t r; + + memset(range, 0, sizeof (struct iw_range)); + dwrq->length = sizeof (struct iw_range); + + /* set the wireless extension version number */ + range->we_version_source = SUPPORTED_WIRELESS_EXT; + range->we_version_compiled = WIRELESS_EXT; + + /* Now the encoding capabilities */ + range->num_encoding_sizes = 3; + /* 64(40) bits WEP */ + range->encoding_size[0] = 5; + /* 128(104) bits WEP */ + range->encoding_size[1] = 13; + /* 256 bits for WPA-PSK */ + range->encoding_size[2] = 32; + /* 4 keys are allowed */ + range->max_encoding_tokens = 4; + + /* we don't know the quality range... */ + range->max_qual.level = 0; + range->max_qual.noise = 0; + range->max_qual.qual = 0; + /* these value describe an average quality. Needs more tweaking... */ + range->avg_qual.level = -80; /* -80 dBm */ + range->avg_qual.noise = 0; /* don't know what to put here */ + range->avg_qual.qual = 0; + + range->sensitivity = 200; + + /* retry limit capabilities */ + range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME; + range->retry_flags = IW_RETRY_LIMIT; + range->r_time_flags = IW_RETRY_LIFETIME; + + /* I don't know the range. Put stupid things here */ + range->min_retry = 1; + range->max_retry = 65535; + range->min_r_time = 1024; + range->max_r_time = 65535 * 1024; + + /* txpower is supported in dBm's */ + range->txpower_capa = IW_TXPOW_DBM; + + if (islpci_get_state(priv) < PRV_STATE_INIT) + return 0; + + /* Request the device for the supported frequencies + * not really revelant since some devices will report the 5 GHz band + * frequencies even if they don't support them. + */ + rvalue = + mgt_get_request(priv, DOT11_OID_SUPPORTEDFREQUENCIES, 0, NULL, &r); + freq = r.ptr; + + range->num_channels = le16_to_cpu(freq->nr); + range->num_frequency = le16_to_cpu(freq->nr); + + /* Frequencies are not listed in the right order. The reordering is probably + * firmware dependant and thus should work for everyone. + */ + m = min(IW_MAX_FREQUENCIES, (int) le16_to_cpu(freq->nr)); + for (i = 0; i < m - 12; i++) { + range->freq[i].m = le16_to_cpu(freq->mhz[12 + i]); + range->freq[i].e = 6; + range->freq[i].i = i + 1; + } + for (i = m - 12; i < m; i++) { + range->freq[i].m = le16_to_cpu(freq->mhz[i - m + 12]); + range->freq[i].e = 6; + range->freq[i].i = i + 23; + } + + kfree(freq); + + rvalue |= mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r); + data = r.ptr; + + /* We got an array of char. It is NULL terminated. */ + i = 0; + while ((i < IW_MAX_BITRATES) && (*data != 0)) { + /* the result must be in bps. The card gives us 500Kbps */ + range->bitrate[i] = (__s32) (*data >> 1); + range->bitrate[i] *= 1000000; + i++; + data++; + } + + range->num_bitrates = i; + + kfree(r.ptr); + + return rvalue; +} + +/* Set AP address*/ + +static int +prism54_set_wap(struct net_device *ndev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + islpci_private *priv = ndev->priv; + char bssid[6]; + int rvalue; + + if (awrq->sa_family != ARPHRD_ETHER) + return -EINVAL; + + /* prepare the structure for the set object */ + memcpy(&bssid[0], awrq->sa_data, 6); + + /* set the bssid -- does this make sense when in AP mode? */ + rvalue = mgt_set_request(priv, DOT11_OID_BSSID, 0, &bssid); + + return (rvalue ? rvalue : -EINPROGRESS); /* Call commit handler */ +} + +/* get AP address*/ + +static int +prism54_get_wap(struct net_device *ndev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + islpci_private *priv = ndev->priv; + union oid_res_t r; + int rvalue; + + rvalue = mgt_get_request(priv, DOT11_OID_BSSID, 0, NULL, &r); + + memcpy(awrq->sa_data, r.ptr, 6); + awrq->sa_family = ARPHRD_ETHER; + kfree(r.ptr); + + return rvalue; +} + +static int +prism54_set_scan(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + /* hehe the device does this automagicaly */ + return 0; +} + +/* a little helper that will translate our data into a card independent + * format that the Wireless Tools will understand. This was inspired by + * the "Aironet driver for 4500 and 4800 series cards" (GPL) + */ + +inline char * +prism54_translate_bss(struct net_device *ndev, char *current_ev, + char *end_buf, struct obj_bss *bss, char noise) +{ + struct iw_event iwe; /* Temporary buffer */ + short cap; + islpci_private *priv = ndev->priv; + + /* The first entry must be the MAC address */ + memcpy(iwe.u.ap_addr.sa_data, bss->address, 6); + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + iwe.cmd = SIOCGIWAP; + current_ev = + iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN); + + /* The following entries will be displayed in the same order we give them */ + + /* The ESSID. */ + iwe.u.data.length = bss->ssid.length; + iwe.u.data.flags = 1; + iwe.cmd = SIOCGIWESSID; + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, bss->ssid.octets); + + /* Capabilities */ +#define CAP_ESS 0x01 +#define CAP_IBSS 0x02 +#define CAP_CRYPT 0x10 + + /* Mode */ + cap = le16_to_cpu(bss->capinfo); + iwe.u.mode = 0; + if (cap & CAP_ESS) + iwe.u.mode = IW_MODE_MASTER; + else if (cap & CAP_IBSS) + iwe.u.mode = IW_MODE_ADHOC; + iwe.cmd = SIOCGIWMODE; + if (iwe.u.mode) + current_ev = + iwe_stream_add_event(current_ev, end_buf, &iwe, + IW_EV_UINT_LEN); + + /* Encryption capability */ + if (cap & CAP_CRYPT) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + iwe.u.data.length = 0; + iwe.cmd = SIOCGIWENCODE; + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, NULL); + + /* Add frequency. (short) bss->channel is the frequency in MHz */ + iwe.u.freq.m = bss->channel; + iwe.u.freq.e = 6; + iwe.cmd = SIOCGIWFREQ; + current_ev = + iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); + + /* Add quality statistics */ + iwe.u.qual.level = bss->rssi; + iwe.u.qual.noise = noise; + /* do a simple SNR for quality */ + iwe.u.qual.qual = bss->rssi - noise; + iwe.cmd = IWEVQUAL; + current_ev = + iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); + + if (priv->wpa) { + u8 wpa_ie[MAX_WPA_IE_LEN]; + char *buf, *p; + size_t wpa_ie_len; + int i; + + wpa_ie_len = prism54_wpa_ie_get(priv, bss->address, wpa_ie); + if (wpa_ie_len > 0 && + (buf = kmalloc(wpa_ie_len * 2 + 10, GFP_ATOMIC))) { + p = buf; + p += sprintf(p, "wpa_ie="); + for (i = 0; i < wpa_ie_len; i++) { + p += sprintf(p, "%02x", wpa_ie[i]); + } + memset(&iwe, 0, sizeof (iwe)); + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, buf); + kfree(buf); + } + } + + return current_ev; +} + +int +prism54_get_scan(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + int i, rvalue; + struct obj_bsslist *bsslist; + u32 noise = 0; + char *current_ev = extra; + union oid_res_t r; + + if (islpci_get_state(priv) < PRV_STATE_INIT) { + /* device is not ready, fail gently */ + dwrq->length = 0; + return 0; + } + + /* first get the noise value. We will use it to report the link quality */ + rvalue = mgt_get_request(priv, DOT11_OID_NOISEFLOOR, 0, NULL, &r); + noise = r.u; + + /* Ask the device for a list of known bss. We can report at most + * IW_MAX_AP=64 to the range struct. But the device won't repport anything + * if you change the value of MAXBSS=24. Anyway 24 AP It is probably enough. + */ + rvalue |= mgt_get_request(priv, DOT11_OID_BSSLIST, 0, NULL, &r); + bsslist = r.ptr; + + /* ok now, scan the list and translate its info */ + for (i = 0; i < min(IW_MAX_AP, (int) le32_to_cpu(bsslist->nr)); i++) + current_ev = prism54_translate_bss(ndev, current_ev, + extra + IW_SCAN_MAX_DATA, + &(bsslist->bsslist[i]), + noise); + kfree(bsslist); + dwrq->length = (current_ev - extra); + dwrq->flags = 0; /* todo */ + + return rvalue; +} + +static int +prism54_set_essid(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + struct obj_ssid essid; + + memset(essid.octets, 0, 33); + + /* Check if we were asked for `any' */ + if (dwrq->flags && dwrq->length) { + if (dwrq->length > min(33, IW_ESSID_MAX_SIZE + 1)) + return -E2BIG; + essid.length = dwrq->length - 1; + memcpy(essid.octets, extra, dwrq->length); + } else + essid.length = 0; + + if (priv->iw_mode != IW_MODE_MONITOR) + return mgt_set_request(priv, DOT11_OID_SSID, 0, &essid); + + /* If in monitor mode, just save to mib */ + mgt_set(priv, DOT11_OID_SSID, &essid); + return 0; + +} + +static int +prism54_get_essid(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + struct obj_ssid *essid; + union oid_res_t r; + int rvalue; + + rvalue = mgt_get_request(priv, DOT11_OID_SSID, 0, NULL, &r); + essid = r.ptr; + + if (essid->length) { + dwrq->flags = 1; /* set ESSID to ON for Wireless Extensions */ + /* if it is to big, trunk it */ + dwrq->length = min(IW_ESSID_MAX_SIZE, essid->length + 1); + } else { + dwrq->flags = 0; + dwrq->length = 0; + } + essid->octets[essid->length] = '\0'; + memcpy(extra, essid->octets, dwrq->length); + kfree(essid); + + return rvalue; +} + +/* Provides no functionality, just completes the ioctl. In essence this is a + * just a cosmetic ioctl. + */ +static int +prism54_set_nick(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + + if (dwrq->length > IW_ESSID_MAX_SIZE) + return -E2BIG; + + down_write(&priv->mib_sem); + memset(priv->nickname, 0, sizeof (priv->nickname)); + memcpy(priv->nickname, extra, dwrq->length); + up_write(&priv->mib_sem); + + return 0; +} + +static int +prism54_get_nick(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + + dwrq->length = 0; + + down_read(&priv->mib_sem); + dwrq->length = strlen(priv->nickname) + 1; + memcpy(extra, priv->nickname, dwrq->length); + up_read(&priv->mib_sem); + + return 0; +} + +/* Set the allowed Bitrates */ + +static int +prism54_set_rate(struct net_device *ndev, + struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + + islpci_private *priv = ndev->priv; + u32 rate, profile; + char *data; + int ret, i; + union oid_res_t r; + + if (vwrq->value == -1) { + /* auto mode. No limit. */ + profile = 1; + return mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile); + } + + if((ret = mgt_get_request(priv, DOT11_OID_SUPPORTEDRATES, 0, NULL, &r))) + return ret; + + rate = (u32) (vwrq->value / 500000); + data = r.ptr; + i = 0; + + while(data[i]) { + if(rate && (data[i] == rate)) { + break; + } + if(vwrq->value == i) { + break; + } + data[i] |= 0x80; + i++; + } + + if(!data[i]) { + return -EINVAL; + } + + data[i] |= 0x80; + data[i + 1] = 0; + + /* Now, check if we want a fixed or auto value */ + if (vwrq->fixed) { + data[0] = data[i]; + data[1] = 0; + } + +/* + i = 0; + printk("prism54 rate: "); + while(data[i]) { + printk("%u ", data[i]); + i++; + } + printk("0\n"); +*/ + profile = -1; + ret = mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile); + ret |= mgt_set_request(priv, DOT11_OID_EXTENDEDRATES, 0, data); + ret |= mgt_set_request(priv, DOT11_OID_RATES, 0, data); + + kfree(r.ptr); + + return ret; +} + +/* Get the current bit rate */ +static int +prism54_get_rate(struct net_device *ndev, + struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + int rvalue; + char *data; + union oid_res_t r; + + /* Get the current bit rate */ + if((rvalue = mgt_get_request(priv, GEN_OID_LINKSTATE, 0, NULL, &r))) + return rvalue; + vwrq->value = r.u * 500000; + + /* request the device for the enabled rates */ + if((rvalue = mgt_get_request(priv, DOT11_OID_RATES, 0, NULL, &r))) + return rvalue; + data = r.ptr; + vwrq->fixed = (data[0] != 0) && (data[1] == 0); + kfree(r.ptr); + + return 0; +} + +static int +prism54_set_rts(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + + return mgt_set_request(priv, DOT11_OID_RTSTHRESH, 0, &vwrq->value); +} + +static int +prism54_get_rts(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + union oid_res_t r; + int rvalue; + + /* get the rts threshold */ + rvalue = mgt_get_request(priv, DOT11_OID_RTSTHRESH, 0, NULL, &r); + vwrq->value = r.u; + + return rvalue; +} + +static int +prism54_set_frag(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + + return mgt_set_request(priv, DOT11_OID_FRAGTHRESH, 0, &vwrq->value); +} + +static int +prism54_get_frag(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + union oid_res_t r; + int rvalue; + + rvalue = mgt_get_request(priv, DOT11_OID_FRAGTHRESH, 0, NULL, &r); + vwrq->value = r.u; + + return rvalue; +} + +/* Here we have (min,max) = max retries for (small frames, big frames). Where + * big frame <=> bigger than the rts threshold + * small frame <=> smaller than the rts threshold + * This is not really the behavior expected by the wireless tool but it seems + * to be a common behavior in other drivers. + * + * It seems that playing with this tends to hang the card -> DISABLED + */ + +static int +prism54_set_retry(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + u32 slimit = 0, llimit = 0; /* short and long limit */ + u32 lifetime = 0; + int rvalue = 0; + + if (vwrq->disabled) + /* we cannot disable this feature */ + return -EINVAL; + + if (vwrq->flags & IW_RETRY_LIMIT) { + if (vwrq->flags & IW_RETRY_MIN) + slimit = vwrq->value; + else if (vwrq->flags & IW_RETRY_MAX) + llimit = vwrq->value; + else { + /* we are asked to set both */ + slimit = vwrq->value; + llimit = vwrq->value; + } + } + if (vwrq->flags & IW_RETRY_LIFETIME) + /* Wireless tools use us unit while the device uses 1024 us unit */ + lifetime = vwrq->value / 1024; + + /* now set what is requested */ + + if (slimit != 0) + rvalue = + mgt_set_request(priv, DOT11_OID_SHORTRETRIES, 0, &slimit); + if (llimit != 0) + rvalue |= + mgt_set_request(priv, DOT11_OID_LONGRETRIES, 0, &llimit); + if (lifetime != 0) + rvalue |= + mgt_set_request(priv, DOT11_OID_MAXTXLIFETIME, 0, + &lifetime); + + return rvalue; +} + +static int +prism54_get_retry(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + union oid_res_t r; + int rvalue = 0; + vwrq->disabled = 0; /* It cannot be disabled */ + + if ((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { + /* we are asked for the life time */ + rvalue = + mgt_get_request(priv, DOT11_OID_MAXTXLIFETIME, 0, NULL, &r); + vwrq->value = r.u * 1024; + vwrq->flags = IW_RETRY_LIFETIME; + } else if ((vwrq->flags & IW_RETRY_MAX)) { + /* we are asked for the long retry limit */ + rvalue |= + mgt_get_request(priv, DOT11_OID_LONGRETRIES, 0, NULL, &r); + vwrq->value = r.u; + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + } else { + /* default. get the short retry limit */ + rvalue |= + mgt_get_request(priv, DOT11_OID_SHORTRETRIES, 0, NULL, &r); + vwrq->value = r.u; + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MIN; + } + + return rvalue; +} + +static int +prism54_set_encode(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + int rvalue = 0, force = 0; + int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0; + union oid_res_t r; + + /* with the new API, it's impossible to get a NULL pointer. + * New version of iwconfig set the IW_ENCODE_NOKEY flag + * when no key is given, but older versions don't. */ + + if (dwrq->length > 0) { + /* we have a key to set */ + int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + int current_index; + struct obj_key key = { DOT11_PRIV_WEP, 0, "" }; + + /* get the current key index */ + rvalue = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); + current_index = r.u; + /* Verify that the key is not marked as invalid */ + if (!(dwrq->flags & IW_ENCODE_NOKEY)) { + key.length = dwrq->length > sizeof (key.key) ? + sizeof (key.key) : dwrq->length; + memcpy(key.key, extra, key.length); + if (key.length == 32) + /* we want WPA-PSK */ + key.type = DOT11_PRIV_TKIP; + if ((index < 0) || (index > 3)) + /* no index provided use the current one */ + index = current_index; + + /* now send the key to the card */ + rvalue |= + mgt_set_request(priv, DOT11_OID_DEFKEYX, index, + &key); + } + /* + * If a valid key is set, encryption should be enabled + * (user may turn it off later). + * This is also how "iwconfig ethX key on" works + */ + if ((index == current_index) && (key.length > 0)) + force = 1; + } else { + int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + if ((index >= 0) && (index <= 3)) { + /* we want to set the key index */ + rvalue |= + mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, + &index); + } else { + if (!dwrq->flags & IW_ENCODE_MODE) { + /* we cannot do anything. Complain. */ + return -EINVAL; + } + } + } + + /* now read the flags */ + if (dwrq->flags & IW_ENCODE_DISABLED) { + /* Encoding disabled, + * authen = DOT11_AUTH_OS; + * invoke = 0; + * exunencrypt = 0; */ + } + if (dwrq->flags & IW_ENCODE_OPEN) + /* Encode but accept non-encoded packets. No auth */ + invoke = 1; + if ((dwrq->flags & IW_ENCODE_RESTRICTED) || force) { + /* Refuse non-encoded packets. Auth */ + authen = DOT11_AUTH_BOTH; + invoke = 1; + exunencrypt = 1; + } + /* do the change if requested */ + if ((dwrq->flags & IW_ENCODE_MODE) || force) { + rvalue |= + mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen); + rvalue |= + mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &invoke); + rvalue |= + mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, + &exunencrypt); + } + return rvalue; +} + +static int +prism54_get_encode(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + struct obj_key *key; + u32 devindex, index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + u32 authen = 0, invoke = 0, exunencrypt = 0; + int rvalue; + union oid_res_t r; + + /* first get the flags */ + rvalue = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r); + authen = r.u; + rvalue |= mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r); + invoke = r.u; + rvalue |= mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r); + exunencrypt = r.u; + + if (invoke && (authen == DOT11_AUTH_BOTH) && exunencrypt) + dwrq->flags = IW_ENCODE_RESTRICTED; + else if ((authen == DOT11_AUTH_OS) && !exunencrypt) { + if (invoke) + dwrq->flags = IW_ENCODE_OPEN; + else + dwrq->flags = IW_ENCODE_DISABLED; + } else + /* The card should not work in this state */ + dwrq->flags = 0; + + /* get the current device key index */ + rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r); + devindex = r.u; + /* Now get the key, return it */ + if ((index < 0) || (index > 3)) + /* no index provided, use the current one */ + index = devindex; + rvalue |= mgt_get_request(priv, DOT11_OID_DEFKEYX, index, NULL, &r); + key = r.ptr; + dwrq->length = key->length; + memcpy(extra, key->key, dwrq->length); + kfree(key); + /* return the used key index */ + dwrq->flags |= devindex + 1; + + return rvalue; +} + +static int +prism54_get_txpower(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + union oid_res_t r; + int rvalue; + + rvalue = mgt_get_request(priv, OID_INL_OUTPUTPOWER, 0, NULL, &r); + /* intersil firmware operates in 0.25 dBm (1/4 dBm) */ + vwrq->value = (s32)r.u / 4; + vwrq->fixed = 1; + /* radio is not turned of + * btw: how is possible to turn off only the radio + */ + vwrq->disabled = 0; + + return rvalue; +} + +static int +prism54_set_txpower(struct net_device *ndev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + s32 u = vwrq->value; + + /* intersil firmware operates in 0.25 dBm (1/4) */ + u *= 4; + if (vwrq->disabled) { + /* don't know how to disable radio */ + printk(KERN_DEBUG + "%s: %s() disabling radio is not yet supported.\n", + priv->ndev->name, __FUNCTION__); + return -ENOTSUPP; + } else if (vwrq->fixed) + /* currently only fixed value is supported */ + return mgt_set_request(priv, OID_INL_OUTPUTPOWER, 0, &u); + else { + printk(KERN_DEBUG + "%s: %s() auto power will be implemented later.\n", + priv->ndev->name, __FUNCTION__); + return -ENOTSUPP; + } +} + +static int +prism54_reset(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_reset(ndev->priv, 0); + + return 0; +} + +static int +prism54_set_beacon(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + int rvalue = mgt_set_request((islpci_private *) ndev->priv, + DOT11_OID_BEACONPERIOD, 0, uwrq); + + return (rvalue ? rvalue : -EINPROGRESS); +} + +static int +prism54_get_beacon(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + union oid_res_t r; + int rvalue; + + rvalue = + mgt_get_request((islpci_private *) ndev->priv, + DOT11_OID_BEACONPERIOD, 0, NULL, &r); + *uwrq = r.u; + + return rvalue; +} + +void +prism54_acl_init(struct islpci_acl *acl) +{ + sema_init(&acl->sem, 1); + INIT_LIST_HEAD(&acl->mac_list); + acl->size = 0; + acl->policy = MAC_POLICY_OPEN; +} + +static void +prism54_clear_mac(struct islpci_acl *acl) +{ + struct list_head *ptr, *next; + struct mac_entry *entry; + + if (down_interruptible(&acl->sem)) + return; + + if (acl->size == 0) { + up(&acl->sem); + return; + } + + for (ptr = acl->mac_list.next, next = ptr->next; + ptr != &acl->mac_list; ptr = next, next = ptr->next) { + entry = list_entry(ptr, struct mac_entry, _list); + list_del(ptr); + kfree(entry); + } + acl->size = 0; + up(&acl->sem); +} + +void +prism54_acl_clean(struct islpci_acl *acl) +{ + prism54_clear_mac(acl); +} + +static int +prism54_add_mac(struct net_device *ndev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + islpci_private *priv = ndev->priv; + struct islpci_acl *acl = &priv->acl; + struct mac_entry *entry; + struct sockaddr *addr = (struct sockaddr *) extra; + + if (addr->sa_family != ARPHRD_ETHER) + return -EOPNOTSUPP; + + entry = kmalloc(sizeof (struct mac_entry), GFP_KERNEL); + if (entry == NULL) + return -ENOMEM; + + memcpy(entry->addr, addr->sa_data, ETH_ALEN); + + if (down_interruptible(&acl->sem)) { + kfree(entry); + return -ERESTARTSYS; + } + list_add_tail(&entry->_list, &acl->mac_list); + acl->size++; + up(&acl->sem); + + return 0; +} + +static int +prism54_del_mac(struct net_device *ndev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + islpci_private *priv = ndev->priv; + struct islpci_acl *acl = &priv->acl; + struct mac_entry *entry; + struct list_head *ptr; + struct sockaddr *addr = (struct sockaddr *) extra; + + if (addr->sa_family != ARPHRD_ETHER) + return -EOPNOTSUPP; + + if (down_interruptible(&acl->sem)) + return -ERESTARTSYS; + for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) { + entry = list_entry(ptr, struct mac_entry, _list); + + if (memcmp(entry->addr, addr->sa_data, ETH_ALEN) == 0) { + list_del(ptr); + acl->size--; + kfree(entry); + up(&acl->sem); + return 0; + } + } + up(&acl->sem); + return -EINVAL; +} + +static int +prism54_get_mac(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + struct islpci_acl *acl = &priv->acl; + struct mac_entry *entry; + struct list_head *ptr; + struct sockaddr *dst = (struct sockaddr *) extra; + + dwrq->length = 0; + + if (down_interruptible(&acl->sem)) + return -ERESTARTSYS; + + for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) { + entry = list_entry(ptr, struct mac_entry, _list); + + memcpy(dst->sa_data, entry->addr, ETH_ALEN); + dst->sa_family = ARPHRD_ETHER; + dwrq->length++; + dst++; + } + up(&acl->sem); + return 0; +} + +/* Setting policy also clears the MAC acl, even if we don't change the defaut + * policy + */ + +static int +prism54_set_policy(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + struct islpci_acl *acl = &priv->acl; + u32 mlmeautolevel; + + prism54_clear_mac(acl); + + if ((*uwrq < MAC_POLICY_OPEN) || (*uwrq > MAC_POLICY_REJECT)) + return -EINVAL; + + down_write(&priv->mib_sem); + + acl->policy = *uwrq; + + /* the ACL code needs an intermediate mlmeautolevel */ + if ((priv->iw_mode == IW_MODE_MASTER) && + (acl->policy != MAC_POLICY_OPEN)) + mlmeautolevel = DOT11_MLME_INTERMEDIATE; + else + mlmeautolevel = CARD_DEFAULT_MLME_MODE; + if (priv->wpa) + mlmeautolevel = DOT11_MLME_EXTENDED; + mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &mlmeautolevel); + /* restart the card with our new policy */ + mgt_commit(priv); + up_write(&priv->mib_sem); + + return 0; +} + +static int +prism54_get_policy(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + struct islpci_acl *acl = &priv->acl; + + *uwrq = acl->policy; + + return 0; +} + +/* Return 1 only if client should be accepted. */ + +static int +prism54_mac_accept(struct islpci_acl *acl, char *mac) +{ + struct list_head *ptr; + struct mac_entry *entry; + int res = 0; + + if (down_interruptible(&acl->sem)) + return -ERESTARTSYS; + + if (acl->policy == MAC_POLICY_OPEN) { + up(&acl->sem); + return 1; + } + + for (ptr = acl->mac_list.next; ptr != &acl->mac_list; ptr = ptr->next) { + entry = list_entry(ptr, struct mac_entry, _list); + if (memcmp(entry->addr, mac, ETH_ALEN) == 0) { + res = 1; + break; + } + } + res = (acl->policy == MAC_POLICY_ACCEPT) ? !res : res; + up(&acl->sem); + + return res; +} + +static int +prism54_kick_all(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + struct obj_mlme *mlme; + int rvalue; + + mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL); + if (mlme == NULL) + return -ENOMEM; + + /* Tell the card to kick every client */ + mlme->id = cpu_to_le16(0); + rvalue = mgt_set_request(ndev->priv, DOT11_OID_DISASSOCIATE, 0, mlme); + kfree(mlme); + + return rvalue; +} + +static int +prism54_kick_mac(struct net_device *ndev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + struct obj_mlme *mlme; + struct sockaddr *addr = (struct sockaddr *) extra; + int rvalue; + + if (addr->sa_family != ARPHRD_ETHER) + return -EOPNOTSUPP; + + mlme = kmalloc(sizeof (struct obj_mlme), GFP_KERNEL); + if (mlme == NULL) + return -ENOMEM; + + /* Tell the card to only kick the corresponding bastard */ + memcpy(mlme->address, addr->sa_data, ETH_ALEN); + mlme->id = cpu_to_le16(-1); + rvalue = mgt_set_request(ndev->priv, DOT11_OID_DISASSOCIATE, 0, mlme); + + kfree(mlme); + + return rvalue; +} + +/* Translate a TRAP oid into a wireless event. Called in islpci_mgt_receive. */ + +static inline void +format_event(islpci_private *priv, char *dest, const char *str, + const struct obj_mlme *mlme, u16 *length, int error) +{ + const u8 *a = mlme->address; + int n = snprintf(dest, IW_CUSTOM_MAX, + "%s %s %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X %s", + str, + ((priv->iw_mode == IW_MODE_MASTER) ? "to" : "from"), + a[0], a[1], a[2], a[3], a[4], a[5], + (error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ") + : "")); + BUG_ON(n > IW_CUSTOM_MAX); + *length = n; +} + +static void +send_formatted_event(islpci_private *priv, const char *str, + const struct obj_mlme *mlme, int error) +{ + union iwreq_data wrqu; + + wrqu.data.pointer = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL); + if (!wrqu.data.pointer) + return; + wrqu.data.length = 0; + format_event(priv, wrqu.data.pointer, str, mlme, &wrqu.data.length, + error); + wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, wrqu.data.pointer); + kfree(wrqu.data.pointer); +} + +static void +send_simple_event(islpci_private *priv, const char *str) +{ + union iwreq_data wrqu; + int n = strlen(str); + + wrqu.data.pointer = kmalloc(IW_CUSTOM_MAX, GFP_KERNEL); + if (!wrqu.data.pointer) + return; + BUG_ON(n > IW_CUSTOM_MAX); + wrqu.data.length = n; + strcpy(wrqu.data.pointer, str); + wireless_send_event(priv->ndev, IWEVCUSTOM, &wrqu, wrqu.data.pointer); + kfree(wrqu.data.pointer); +} + +static void +link_changed(struct net_device *ndev, u32 bitrate) +{ + islpci_private *priv = ndev->priv; + + if (le32_to_cpu(bitrate)) { + if (priv->iw_mode == IW_MODE_INFRA) { + union iwreq_data uwrq; + prism54_get_wap(ndev, NULL, (struct sockaddr *) &uwrq, + NULL); + wireless_send_event(ndev, SIOCGIWAP, &uwrq, NULL); + } else + send_simple_event(ndev->priv, "Link established"); + } else + send_simple_event(ndev->priv, "Link lost"); +} + +/* Beacon/ProbeResp payload header */ +struct ieee80211_beacon_phdr { + u8 timestamp[8]; + u16 beacon_int; + u16 capab_info; +} __attribute__ ((packed)); + +#define WLAN_EID_GENERIC 0xdd +static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 }; + +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" + +void +prism54_wpa_ie_add(islpci_private *priv, u8 *bssid, + u8 *wpa_ie, size_t wpa_ie_len) +{ + struct list_head *ptr; + struct islpci_bss_wpa_ie *bss = NULL; + + if (wpa_ie_len > MAX_WPA_IE_LEN) + wpa_ie_len = MAX_WPA_IE_LEN; + + if (down_interruptible(&priv->wpa_sem)) + return; + + /* try to use existing entry */ + list_for_each(ptr, &priv->bss_wpa_list) { + bss = list_entry(ptr, struct islpci_bss_wpa_ie, list); + if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) { + list_move(&bss->list, &priv->bss_wpa_list); + break; + } + bss = NULL; + } + + if (bss == NULL) { + /* add a new BSS entry; if max number of entries is already + * reached, replace the least recently updated */ + if (priv->num_bss_wpa >= MAX_BSS_WPA_IE_COUNT) { + bss = list_entry(priv->bss_wpa_list.prev, + struct islpci_bss_wpa_ie, list); + list_del(&bss->list); + } else { + bss = kmalloc(sizeof (*bss), GFP_ATOMIC); + if (bss != NULL) { + priv->num_bss_wpa++; + memset(bss, 0, sizeof (*bss)); + } + } + if (bss != NULL) { + memcpy(bss->bssid, bssid, ETH_ALEN); + list_add(&bss->list, &priv->bss_wpa_list); + } + } + + if (bss != NULL) { + memcpy(bss->wpa_ie, wpa_ie, wpa_ie_len); + bss->wpa_ie_len = wpa_ie_len; + bss->last_update = jiffies; + } else { + printk(KERN_DEBUG "Failed to add BSS WPA entry for " MACSTR + "\n", MAC2STR(bssid)); + } + + /* expire old entries from WPA list */ + while (priv->num_bss_wpa > 0) { + bss = list_entry(priv->bss_wpa_list.prev, + struct islpci_bss_wpa_ie, list); + if (!time_after(jiffies, bss->last_update + 60 * HZ)) + break; + + list_del(&bss->list); + priv->num_bss_wpa--; + kfree(bss); + } + + up(&priv->wpa_sem); +} + +size_t +prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie) +{ + struct list_head *ptr; + struct islpci_bss_wpa_ie *bss = NULL; + size_t len = 0; + + if (down_interruptible(&priv->wpa_sem)) + return 0; + + list_for_each(ptr, &priv->bss_wpa_list) { + bss = list_entry(ptr, struct islpci_bss_wpa_ie, list); + if (memcmp(bss->bssid, bssid, ETH_ALEN) == 0) + break; + bss = NULL; + } + if (bss) { + len = bss->wpa_ie_len; + memcpy(wpa_ie, bss->wpa_ie, len); + } + up(&priv->wpa_sem); + + return len; +} + +void +prism54_wpa_ie_init(islpci_private *priv) +{ + INIT_LIST_HEAD(&priv->bss_wpa_list); + sema_init(&priv->wpa_sem, 1); +} + +void +prism54_wpa_ie_clean(islpci_private *priv) +{ + struct list_head *ptr, *n; + + list_for_each_safe(ptr, n, &priv->bss_wpa_list) { + struct islpci_bss_wpa_ie *bss; + bss = list_entry(ptr, struct islpci_bss_wpa_ie, list); + kfree(bss); + } +} + +static void +prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr, + u8 *payload, size_t len) +{ + struct ieee80211_beacon_phdr *hdr; + u8 *pos, *end; + + if (!priv->wpa) + return; + + hdr = (struct ieee80211_beacon_phdr *) payload; + pos = (u8 *) (hdr + 1); + end = payload + len; + while (pos < end) { + if (pos + 2 + pos[1] > end) { + printk(KERN_DEBUG "Parsing Beacon/ProbeResp failed " + "for " MACSTR "\n", MAC2STR(addr)); + return; + } + if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 && + memcmp(pos + 2, wpa_oid, 4) == 0) { + prism54_wpa_ie_add(priv, addr, pos, pos[1] + 2); + return; + } + pos += 2 + pos[1]; + } +} + +static void +handle_request(islpci_private *priv, struct obj_mlme *mlme, enum oid_num_t oid) +{ + if (((le16_to_cpu(mlme->state) == DOT11_STATE_AUTHING) || + (le16_to_cpu(mlme->state) == DOT11_STATE_ASSOCING)) + && mgt_mlme_answer(priv)) { + /* Someone is requesting auth and we must respond. Just send back + * the trap with error code set accordingly. + */ + mlme->code = cpu_to_le16(prism54_mac_accept(&priv->acl, + mlme-> + address) ? 0 : 1); + mgt_set_request(priv, oid, 0, mlme); + } +} + +int +prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, + char *data) +{ + struct obj_mlme *mlme = (struct obj_mlme *) data; + size_t len; + u8 *payload, *pos = (u8 *) (mlme + 1); + + len = pos[0] | (pos[1] << 8); /* little endian data length */ + payload = pos + 2; + + /* I think all trapable objects are listed here. + * Some oids have a EX version. The difference is that they are emitted + * in DOT11_MLME_EXTENDED mode (set with DOT11_OID_MLMEAUTOLEVEL) + * with more info. + * The few events already defined by the wireless tools are not really + * suited. We use the more flexible custom event facility. + */ + + switch (oid) { + + case GEN_OID_LINKSTATE: + link_changed(priv->ndev, (u32) *data); + break; + + case DOT11_OID_MICFAILURE: + send_simple_event(priv, "Mic failure"); + break; + + case DOT11_OID_DEAUTHENTICATE: + send_formatted_event(priv, "DeAuthenticate request", mlme, 0); + break; + + case DOT11_OID_AUTHENTICATE: + handle_request(priv, mlme, oid); + send_formatted_event(priv, "Authenticate request", mlme, 1); + break; + + case DOT11_OID_DISASSOCIATE: + send_formatted_event(priv, "Disassociate request", mlme, 0); + break; + + case DOT11_OID_ASSOCIATE: + handle_request(priv, mlme, oid); + send_formatted_event(priv, "Associate request", mlme, 1); + break; + + case DOT11_OID_REASSOCIATE: + handle_request(priv, mlme, oid); + send_formatted_event(priv, "ReAssociate request", mlme, 1); + break; + + case DOT11_OID_BEACON: + prism54_process_bss_data(priv, oid, mlme->address, + payload, len); + send_formatted_event(priv, + "Received a beacon from an unkown AP", + mlme, 0); + break; + + case DOT11_OID_PROBE: + /* we received a probe from a client. */ + prism54_process_bss_data(priv, oid, mlme->address, + payload, len); + send_formatted_event(priv, "Received a probe from client", mlme, + 0); + break; + + /* Note : the following should never happen since we don't run the card in + * extended mode. + * Note : "mlme" is actually a "struct obj_mlmeex *" here, but this + * is backward compatible layout-wise with "struct obj_mlme". + */ + + case DOT11_OID_DEAUTHENTICATEEX: + send_formatted_event(priv, "DeAuthenticate request", mlme, 0); + break; + + case DOT11_OID_AUTHENTICATEEX: + handle_request(priv, mlme, oid); + send_formatted_event(priv, "Authenticate request", mlme, 1); + break; + + case DOT11_OID_DISASSOCIATEEX: + send_formatted_event(priv, "Disassociate request", mlme, 0); + break; + + case DOT11_OID_ASSOCIATEEX: + handle_request(priv, mlme, oid); + send_formatted_event(priv, "Associate request", mlme, 1); + break; + + case DOT11_OID_REASSOCIATEEX: + handle_request(priv, mlme, oid); + send_formatted_event(priv, "Reassociate request", mlme, 1); + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* + * Process a device trap. This is called via schedule_work(), outside of + * interrupt context, no locks held. + */ +void +prism54_process_trap(void *data) +{ + struct islpci_mgmtframe *frame = data; + enum oid_num_t n = mgt_oidtonum(frame->header->oid); + + prism54_process_trap_helper(frame->ndev->priv, n, frame->data); + islpci_mgt_release(frame); +} + +int +prism54_set_mac_address(struct net_device *ndev, void *addr) +{ + islpci_private *priv = ndev->priv; + int ret; + + if (ndev->addr_len != 6) + return -EINVAL; + ret = mgt_set_request(priv, GEN_OID_MACADDRESS, 0, + &((struct sockaddr *) addr)->sa_data); + if (!ret) + memcpy(priv->ndev->dev_addr, + &((struct sockaddr *) addr)->sa_data, 6); + + return ret; +} + +int +prism54_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) +{ + /* should we really support this old stuff ? */ + return -EOPNOTSUPP; +} + +int +prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + + down_write(&priv->mib_sem); + + priv->wpa = *uwrq; + if (priv->wpa) { + u32 l = DOT11_MLME_EXTENDED; + mgt_set(priv, DOT11_OID_MLMEAUTOLEVEL, &l); + } + /* restart the card with new level. Needed ? */ + mgt_commit(priv); + up_write(&priv->mib_sem); + + return 0; +} + +int +prism54_get_wpa(struct net_device *ndev, struct iw_request_info *info, + __u32 * uwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + *uwrq = priv->wpa; + return 0; +} + +int +prism54_oid(struct net_device *ndev, struct iw_request_info *info, + __u32 *uwrq, char *extra) +{ + islpci_private *priv = ndev->priv; + + priv->priv_oid = *uwrq; + printk("%s: oid 0x%08X\n", ndev->name, *uwrq); + + return 0; +} + +int +prism54_get_oid(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + islpci_private *priv = ndev->priv; + struct islpci_mgmtframe *response = NULL; + int ret = -EIO, response_op = PIMFOR_OP_ERROR; + + printk("%s: get_oid 0x%08X\n", ndev->name, priv->priv_oid); + data->length = 0; + + if (islpci_get_state(priv) >= PRV_STATE_INIT) { + ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET, priv->priv_oid, extra, 256, &response); + response_op = response->header->operation; + printk("%s: ret: %i\n", ndev->name, ret); + printk("%s: response_op: %i\n", ndev->name, response_op); + if (ret || !response || response->header->operation == PIMFOR_OP_ERROR) { + if (response) { + islpci_mgt_release(response); + } + printk("%s: EIO\n", ndev->name); + ret = -EIO; + } + if (!ret) { + data->length = response->header->length; + memcpy(extra, response->data, data->length); + islpci_mgt_release(response); + printk("%s: len: %i\n", ndev->name, data->length); + } + } + + return ret; +} + +int +prism54_set_oid(struct net_device *ndev, struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + islpci_private *priv = ndev->priv; + struct islpci_mgmtframe *response = NULL; + int ret = 0, response_op = PIMFOR_OP_ERROR; + + printk("%s: set_oid 0x%08X\tlen: %d\n", ndev->name, priv->priv_oid, data->length); + + if (islpci_get_state(priv) >= PRV_STATE_INIT) { + ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, priv->priv_oid, extra, data->length, &response); + printk("%s: ret: %i\n", ndev->name, ret); + if (!ret) { + response_op = response->header->operation; + printk("%s: response_op: %i\n", ndev->name, response_op); + islpci_mgt_release(response); + } + if (ret || response_op == PIMFOR_OP_ERROR) { + printk("%s: EIO\n", ndev->name); + ret = -EIO; + } + } + + return ret; +} + +static const iw_handler prism54_handler[] = { + (iw_handler) prism54_commit, /* SIOCSIWCOMMIT */ + (iw_handler) prism54_get_name, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) prism54_set_freq, /* SIOCSIWFREQ */ + (iw_handler) prism54_get_freq, /* SIOCGIWFREQ */ + (iw_handler) prism54_set_mode, /* SIOCSIWMODE */ + (iw_handler) prism54_get_mode, /* SIOCGIWMODE */ + (iw_handler) prism54_set_sens, /* SIOCSIWSENS */ + (iw_handler) prism54_get_sens, /* SIOCGIWSENS */ + (iw_handler) NULL, /* SIOCSIWRANGE */ + (iw_handler) prism54_get_range, /* SIOCGIWRANGE */ + (iw_handler) NULL, /* SIOCSIWPRIV */ + (iw_handler) NULL, /* SIOCGIWPRIV */ + (iw_handler) NULL, /* SIOCSIWSTATS */ + (iw_handler) NULL, /* SIOCGIWSTATS */ + iw_handler_set_spy, /* SIOCSIWSPY */ + iw_handler_get_spy, /* SIOCGIWSPY */ + iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ + iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ + (iw_handler) prism54_set_wap, /* SIOCSIWAP */ + (iw_handler) prism54_get_wap, /* SIOCGIWAP */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* SIOCGIWAPLIST depreciated */ + (iw_handler) prism54_set_scan, /* SIOCSIWSCAN */ + (iw_handler) prism54_get_scan, /* SIOCGIWSCAN */ + (iw_handler) prism54_set_essid, /* SIOCSIWESSID */ + (iw_handler) prism54_get_essid, /* SIOCGIWESSID */ + (iw_handler) prism54_set_nick, /* SIOCSIWNICKN */ + (iw_handler) prism54_get_nick, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) prism54_set_rate, /* SIOCSIWRATE */ + (iw_handler) prism54_get_rate, /* SIOCGIWRATE */ + (iw_handler) prism54_set_rts, /* SIOCSIWRTS */ + (iw_handler) prism54_get_rts, /* SIOCGIWRTS */ + (iw_handler) prism54_set_frag, /* SIOCSIWFRAG */ + (iw_handler) prism54_get_frag, /* SIOCGIWFRAG */ + (iw_handler) prism54_set_txpower, /* SIOCSIWTXPOW */ + (iw_handler) prism54_get_txpower, /* SIOCGIWTXPOW */ + (iw_handler) prism54_set_retry, /* SIOCSIWRETRY */ + (iw_handler) prism54_get_retry, /* SIOCGIWRETRY */ + (iw_handler) prism54_set_encode, /* SIOCSIWENCODE */ + (iw_handler) prism54_get_encode, /* SIOCGIWENCODE */ + (iw_handler) NULL, /* SIOCSIWPOWER */ + (iw_handler) NULL, /* SIOCGIWPOWER */ +}; + +/* The low order bit identify a SET (0) or a GET (1) ioctl. */ + +#define PRISM54_RESET SIOCIWFIRSTPRIV +#define PRISM54_GET_BEACON SIOCIWFIRSTPRIV+1 +#define PRISM54_SET_BEACON SIOCIWFIRSTPRIV+2 +#define PRISM54_GET_POLICY SIOCIWFIRSTPRIV+3 +#define PRISM54_SET_POLICY SIOCIWFIRSTPRIV+4 +#define PRISM54_GET_MAC SIOCIWFIRSTPRIV+5 +#define PRISM54_ADD_MAC SIOCIWFIRSTPRIV+6 + +#define PRISM54_DEL_MAC SIOCIWFIRSTPRIV+8 + +#define PRISM54_KICK_MAC SIOCIWFIRSTPRIV+10 + +#define PRISM54_KICK_ALL SIOCIWFIRSTPRIV+12 + +#define PRISM54_GET_WPA SIOCIWFIRSTPRIV+13 +#define PRISM54_SET_WPA SIOCIWFIRSTPRIV+14 + +#define PRISM54_OID SIOCIWFIRSTPRIV+16 +#define PRISM54_GET_OID SIOCIWFIRSTPRIV+17 +#define PRISM54_SET_OID SIOCIWFIRSTPRIV+18 + +static const struct iw_priv_args prism54_private_args[] = { +/*{ cmd, set_args, get_args, name } */ + {PRISM54_RESET, 0, 0, "reset"}, + {PRISM54_GET_BEACON, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getBeaconPeriod"}, + {PRISM54_SET_BEACON, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "setBeaconPeriod"}, + {PRISM54_GET_POLICY, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getPolicy"}, + {PRISM54_SET_POLICY, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "setPolicy"}, + {PRISM54_GET_MAC, 0, IW_PRIV_TYPE_ADDR | 64, "getMac"}, + {PRISM54_ADD_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, + "addMac"}, + {PRISM54_DEL_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, + "delMac"}, + {PRISM54_KICK_MAC, IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, + "kickMac"}, + {PRISM54_KICK_ALL, 0, 0, "kickAll"}, + {PRISM54_GET_WPA, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_wpa"}, + {PRISM54_SET_WPA, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "set_wpa"}, + {PRISM54_OID, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "oid"}, + {PRISM54_GET_OID, 0, IW_PRIV_TYPE_BYTE | 256, "get_oid"}, + {PRISM54_SET_OID, IW_PRIV_TYPE_BYTE | 256, 0, "set_oid"}, +}; + +static const iw_handler prism54_private_handler[] = { + (iw_handler) prism54_reset, + (iw_handler) prism54_get_beacon, + (iw_handler) prism54_set_beacon, + (iw_handler) prism54_get_policy, + (iw_handler) prism54_set_policy, + (iw_handler) prism54_get_mac, + (iw_handler) prism54_add_mac, + (iw_handler) NULL, + (iw_handler) prism54_del_mac, + (iw_handler) NULL, + (iw_handler) prism54_kick_mac, + (iw_handler) NULL, + (iw_handler) prism54_kick_all, + (iw_handler) prism54_get_wpa, + (iw_handler) prism54_set_wpa, + (iw_handler) NULL, + (iw_handler) prism54_oid, + (iw_handler) prism54_get_oid, + (iw_handler) prism54_set_oid, +}; + +const struct iw_handler_def prism54_handler_def = { + .num_standard = sizeof (prism54_handler) / sizeof (iw_handler), + .num_private = sizeof (prism54_private_handler) / sizeof (iw_handler), + .num_private_args = + sizeof (prism54_private_args) / sizeof (struct iw_priv_args), + .standard = (iw_handler *) prism54_handler, + .private = (iw_handler *) prism54_private_handler, + .private_args = (struct iw_priv_args *) prism54_private_args, +}; + diff -Nru a/drivers/net/wireless/prism54/isl_ioctl.h b/drivers/net/wireless/prism54/isl_ioctl.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/isl_ioctl.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,55 @@ +/* $Header: /var/lib/cvs/prism54-ng/ksrc/isl_ioctl.h,v 1.30 2004/01/30 16:24:00 ajfa Exp $ + * + * Copyright (C) 2002 Intersil Americas Inc. + * (C) 2003 Aurelien Alleaume + * (C) 2003 Luis R. Rodriguez + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _ISL_IOCTL_H +#define _ISL_IOCTL_H + +#include "islpci_mgt.h" +#include "islpci_dev.h" + +#include /* New driver API */ + +#define SUPPORTED_WIRELESS_EXT 16 + +void prism54_mib_init(islpci_private *); +void prism54_mib_init_work(islpci_private *); + +struct iw_statistics *prism54_get_wireless_stats(struct net_device *); +void prism54_update_stats(islpci_private *); + +void prism54_acl_init(struct islpci_acl *); +void prism54_acl_clean(struct islpci_acl *); + +void prism54_process_trap(void *); + +void prism54_wpa_ie_init(islpci_private *priv); +void prism54_wpa_ie_clean(islpci_private *priv); +void prism54_wpa_ie_add(islpci_private *priv, u8 *bssid, + u8 *wpa_ie, size_t wpa_ie_len); +size_t prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie); + +int prism54_set_mac_address(struct net_device *, void *); + +int prism54_ioctl(struct net_device *, struct ifreq *, int); + +extern const struct iw_handler_def prism54_handler_def; + +#endif /* _ISL_IOCTL_H */ diff -Nru a/drivers/net/wireless/prism54/isl_oid.h b/drivers/net/wireless/prism54/isl_oid.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/isl_oid.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,365 @@ +/* + * $Id: isl_oid.h,v 1.2 2004/01/30 16:24:00 ajfa Exp $ + * + * Copyright (C) 2003 Herbert Valerio Riedel + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#if !defined(_ISL_OID_H) +#define _ISL_OID_H + +/* + * MIB related constant and structure definitions for communicating + * with the device firmware + */ + +struct obj_ssid { + u8 length; + char octets[33]; +} __attribute__ ((packed)); + +struct obj_key { + u8 type; /* dot11_priv_t */ + u8 length; + char key[32]; +} __attribute__ ((packed)); + +struct obj_mlme { + u8 address[6]; + u16 id; + u16 state; + u16 code; +} __attribute__ ((packed)); + +struct obj_mlmeex { + u8 address[6]; + u16 id; + u16 state; + u16 code; + u16 size; + u8 data[0]; +} __attribute__ ((packed)); + +struct obj_buffer { + u32 size; + u32 addr; /* 32bit bus address */ +} __attribute__ ((packed)); + +struct obj_bss { + u8 address[6]; + int:16; /* padding */ + + char state; + char reserved; + short age; + + char quality; + char rssi; + + struct obj_ssid ssid; + short channel; + char beacon_period; + char dtim_period; + short capinfo; + short rates; + short basic_rates; + int:16; /* padding */ +} __attribute__ ((packed)); + +struct obj_bsslist { + u32 nr; + struct obj_bss bsslist[0]; +} __attribute__ ((packed)); + +struct obj_frequencies { + u16 nr; + u16 mhz[0]; +} __attribute__ ((packed)); + +/* + * in case everything's ok, the inlined function below will be + * optimized away by the compiler... + */ +static inline void +__bug_on_wrong_struct_sizes(void) +{ + BUG_ON(sizeof (struct obj_ssid) != 34); + BUG_ON(sizeof (struct obj_key) != 34); + BUG_ON(sizeof (struct obj_mlme) != 12); + BUG_ON(sizeof (struct obj_mlmeex) != 14); + BUG_ON(sizeof (struct obj_buffer) != 8); + BUG_ON(sizeof (struct obj_bss) != 60); + BUG_ON(sizeof (struct obj_bsslist) != 4); + BUG_ON(sizeof (struct obj_frequencies) != 2); +} + +enum dot11_state_t { + DOT11_STATE_NONE = 0, + DOT11_STATE_AUTHING = 1, + DOT11_STATE_AUTH = 2, + DOT11_STATE_ASSOCING = 3, + + DOT11_STATE_ASSOC = 5, + DOT11_STATE_IBSS = 6, + DOT11_STATE_WDS = 7 +}; + +enum dot11_bsstype_t { + DOT11_BSSTYPE_NONE = 0, + DOT11_BSSTYPE_INFRA = 1, + DOT11_BSSTYPE_IBSS = 2, + DOT11_BSSTYPE_ANY = 3 +}; + +enum dot11_auth_t { + DOT11_AUTH_NONE = 0, + DOT11_AUTH_OS = 1, + DOT11_AUTH_SK = 2, + DOT11_AUTH_BOTH = 3 +}; + +enum dot11_mlme_t { + DOT11_MLME_AUTO = 0, + DOT11_MLME_INTERMEDIATE = 1, + DOT11_MLME_EXTENDED = 2 +}; + +enum dot11_priv_t { + DOT11_PRIV_WEP = 0, + DOT11_PRIV_TKIP = 1 +}; + +/* The dot11d conformance level configures the 802.11d conformance levels. + * The following conformance levels exist:*/ +enum oid_inl_conformance_t { + OID_INL_CONFORMANCE_NONE = 0, /* Perform active scanning */ + OID_INL_CONFORMANCE_STRICT = 1, /* Strictly adhere to 802.11d */ + OID_INL_CONFORMANCE_FLEXIBLE = 2, /* Use passed 802.11d info to + * determine channel AND/OR just make + * assumption that active + * channels are valid channels */ +}; + +enum oid_inl_mode_t { + INL_MODE_NONE = -1, + INL_MODE_PROMISCUOUS = 0, + INL_MODE_CLIENT = 1, + INL_MODE_AP = 2, + INL_MODE_SNIFFER = 3 +}; + +enum oid_inl_config_t { + INL_CONFIG_NOTHING = 0x00, + INL_CONFIG_MANUALRUN = 0x01, + INL_CONFIG_FRAMETRAP = 0x02, + INL_CONFIG_RXANNEX = 0x04, + INL_CONFIG_TXANNEX = 0x08, + INL_CONFIG_WDS = 0x10 +}; + +enum oid_inl_phycap_t { + INL_PHYCAP_2400MHZ = 1, + INL_PHYCAP_5000MHZ = 2, + INL_PHYCAP_FAA = 0x80000000, /* Means card supports the FAA switch */ +}; + +enum oid_num_t { + GEN_OID_MACADDRESS = 0, + GEN_OID_LINKSTATE, + GEN_OID_WATCHDOG, + GEN_OID_MIBOP, + GEN_OID_OPTIONS, + GEN_OID_LEDCONFIG, + + /* 802.11 */ + DOT11_OID_BSSTYPE, + DOT11_OID_BSSID, + DOT11_OID_SSID, + DOT11_OID_STATE, + DOT11_OID_AID, + DOT11_OID_COUNTRYSTRING, + DOT11_OID_SSIDOVERRIDE, + + DOT11_OID_MEDIUMLIMIT, + DOT11_OID_BEACONPERIOD, + DOT11_OID_DTIMPERIOD, + DOT11_OID_ATIMWINDOW, + DOT11_OID_LISTENINTERVAL, + DOT11_OID_CFPPERIOD, + DOT11_OID_CFPDURATION, + + DOT11_OID_AUTHENABLE, + DOT11_OID_PRIVACYINVOKED, + DOT11_OID_EXUNENCRYPTED, + DOT11_OID_DEFKEYID, + DOT11_OID_DEFKEYX, /* DOT11_OID_DEFKEY1,...DOT11_OID_DEFKEY4 */ + DOT11_OID_STAKEY, + DOT11_OID_REKEYTHRESHOLD, + DOT11_OID_STASC, + + DOT11_OID_PRIVTXREJECTED, + DOT11_OID_PRIVRXPLAIN, + DOT11_OID_PRIVRXFAILED, + DOT11_OID_PRIVRXNOKEY, + + DOT11_OID_RTSTHRESH, + DOT11_OID_FRAGTHRESH, + DOT11_OID_SHORTRETRIES, + DOT11_OID_LONGRETRIES, + DOT11_OID_MAXTXLIFETIME, + DOT11_OID_MAXRXLIFETIME, + DOT11_OID_AUTHRESPTIMEOUT, + DOT11_OID_ASSOCRESPTIMEOUT, + + DOT11_OID_ALOFT_TABLE, + DOT11_OID_ALOFT_CTRL_TABLE, + DOT11_OID_ALOFT_RETREAT, + DOT11_OID_ALOFT_PROGRESS, + DOT11_OID_ALOFT_FIXEDRATE, + DOT11_OID_ALOFT_RSSIGRAPH, + DOT11_OID_ALOFT_CONFIG, + + DOT11_OID_VDCFX, + DOT11_OID_MAXFRAMEBURST, + + DOT11_OID_PSM, + DOT11_OID_CAMTIMEOUT, + DOT11_OID_RECEIVEDTIMS, + DOT11_OID_ROAMPREFERENCE, + + DOT11_OID_BRIDGELOCAL, + DOT11_OID_CLIENTS, + DOT11_OID_CLIENTSASSOCIATED, + DOT11_OID_CLIENTX, /* DOT11_OID_CLIENTX,...DOT11_OID_CLIENT2007 */ + + DOT11_OID_CLIENTFIND, + DOT11_OID_WDSLINKADD, + DOT11_OID_WDSLINKREMOVE, + DOT11_OID_EAPAUTHSTA, + DOT11_OID_EAPUNAUTHSTA, + DOT11_OID_DOT1XENABLE, + DOT11_OID_MICFAILURE, + DOT11_OID_REKEYINDICATE, + + DOT11_OID_MPDUTXSUCCESSFUL, + DOT11_OID_MPDUTXONERETRY, + DOT11_OID_MPDUTXMULTIPLERETRIES, + DOT11_OID_MPDUTXFAILED, + DOT11_OID_MPDURXSUCCESSFUL, + DOT11_OID_MPDURXDUPS, + DOT11_OID_RTSSUCCESSFUL, + DOT11_OID_RTSFAILED, + DOT11_OID_ACKFAILED, + DOT11_OID_FRAMERECEIVES, + DOT11_OID_FRAMEERRORS, + DOT11_OID_FRAMEABORTS, + DOT11_OID_FRAMEABORTSPHY, + + DOT11_OID_SLOTTIME, + DOT11_OID_CWMIN, + DOT11_OID_CWMAX, + DOT11_OID_ACKWINDOW, + DOT11_OID_ANTENNARX, + DOT11_OID_ANTENNATX, + DOT11_OID_ANTENNADIVERSITY, + DOT11_OID_CHANNEL, + DOT11_OID_EDTHRESHOLD, + DOT11_OID_PREAMBLESETTINGS, + DOT11_OID_RATES, + DOT11_OID_CCAMODESUPPORTED, + DOT11_OID_CCAMODE, + DOT11_OID_RSSIVECTOR, + DOT11_OID_OUTPUTPOWERTABLE, + DOT11_OID_OUTPUTPOWER, + DOT11_OID_SUPPORTEDRATES, + DOT11_OID_FREQUENCY, + DOT11_OID_SUPPORTEDFREQUENCIES, + DOT11_OID_NOISEFLOOR, + DOT11_OID_FREQUENCYACTIVITY, + DOT11_OID_IQCALIBRATIONTABLE, + DOT11_OID_NONERPPROTECTION, + DOT11_OID_SLOTSETTINGS, + DOT11_OID_NONERPTIMEOUT, + DOT11_OID_PROFILES, + DOT11_OID_EXTENDEDRATES, + + DOT11_OID_DEAUTHENTICATE, + DOT11_OID_AUTHENTICATE, + DOT11_OID_DISASSOCIATE, + DOT11_OID_ASSOCIATE, + DOT11_OID_SCAN, + DOT11_OID_BEACON, + DOT11_OID_PROBE, + DOT11_OID_DEAUTHENTICATEEX, + DOT11_OID_AUTHENTICATEEX, + DOT11_OID_DISASSOCIATEEX, + DOT11_OID_ASSOCIATEEX, + DOT11_OID_REASSOCIATE, + DOT11_OID_REASSOCIATEEX, + + DOT11_OID_NONERPSTATUS, + + DOT11_OID_STATIMEOUT, + DOT11_OID_MLMEAUTOLEVEL, + DOT11_OID_BSSTIMEOUT, + DOT11_OID_ATTACHMENT, + DOT11_OID_PSMBUFFER, + + DOT11_OID_BSSS, + DOT11_OID_BSSX, /*DOT11_OID_BSS1,...,DOT11_OID_BSS64 */ + DOT11_OID_BSSFIND, + DOT11_OID_BSSLIST, + + OID_INL_TUNNEL, + OID_INL_MEMADDR, + OID_INL_MEMORY, + OID_INL_MODE, + OID_INL_COMPONENT_NR, + OID_INL_VERSION, + OID_INL_INTERFACE_ID, + OID_INL_COMPONENT_ID, + OID_INL_CONFIG, + OID_INL_DOT11D_CONFORMANCE, + OID_INL_PHYCAPABILITIES, + OID_INL_OUTPUTPOWER, + + OID_NUM_LAST +}; + +/* We could add more flags. eg: in which mode are they allowed, ro, rw, ...*/ +#define OID_FLAG_CACHED 0x01 +#define OID_FLAG_U32 0x02 +#define OID_FLAG_MLMEEX 0x04 /* this type is special because of a variable + size field when sending. Not yet implemented (not used in driver). */ + +struct oid_t { + enum oid_num_t oid; + short range; /* to define a range of oid */ + short size; /* size of the associated data */ + char flags; +}; + +union oid_res_t { + void *ptr; + u32 u; +}; + +#define IWMAX_BITRATES 20 +#define IWMAX_BSS 24 +#define IWMAX_FREQ 30 + +#endif /* !defined(_ISL_OID_H) */ +/* EOF */ diff -Nru a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/islpci_dev.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,826 @@ +/* $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_dev.c,v 1.68 2004/02/28 03:06:07 mcgrof Exp $ + * + * Copyright (C) 2002 Intersil Americas Inc. + * Copyright (C) 2003 Herbert Valerio Riedel + * Copyright (C) 2003 Luis R. Rodriguez + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "isl_38xx.h" +#include "isl_ioctl.h" +#include "islpci_dev.h" +#include "islpci_mgt.h" +#include "islpci_eth.h" +#include "oid_mgt.h" + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0) +#define prism54_synchronize_irq(irq) synchronize_irq() +#else +#define prism54_synchronize_irq(irq) synchronize_irq(irq) +#endif + +#define ISL3877_IMAGE_FILE "isl3877" +#define ISL3890_IMAGE_FILE "isl3890" + +/* Temporary dummy MAC address to use until firmware is loaded. + * The idea there is that some tools (such as nameif) may query + * the MAC address before the netdev is 'open'. By using a valid + * OUI prefix, they can process the netdev properly. + * Of course, this is not the final/real MAC address. It doesn't + * matter, as you are suppose to be able to change it anytime via + * ndev->set_mac_address. Jean II */ +const unsigned char dummy_mac[6] = { 0x00, 0x30, 0xB4, 0x00, 0x00, 0x00 }; + +/****************************************************************************** + Device Interrupt Handler +******************************************************************************/ + +irqreturn_t +islpci_interrupt(int irq, void *config, struct pt_regs *regs) +{ + u32 reg; + islpci_private *priv = config; + struct net_device *ndev = priv->ndev; + void *device = priv->device_base; + int powerstate = ISL38XX_PSM_POWERSAVE_STATE; + + /* received an interrupt request on a shared IRQ line + * first check whether the device is in sleep mode */ + reg = readl(device + ISL38XX_CTRL_STAT_REG); + if (reg & ISL38XX_CTRL_STAT_SLEEPMODE) + /* device is in sleep mode, IRQ was generated by someone else */ + { + printk(KERN_DEBUG "Assuming someone else called the IRQ\n"); + return IRQ_NONE; + } + + if (islpci_get_state(priv) != PRV_STATE_SLEEP) + powerstate = ISL38XX_PSM_ACTIVE_STATE; + + /* lock the interrupt handler */ + spin_lock(&priv->slock); + + /* check whether there is any source of interrupt on the device */ + reg = readl(device + ISL38XX_INT_IDENT_REG); + + /* also check the contents of the Interrupt Enable Register, because this + * will filter out interrupt sources from other devices on the same irq ! */ + reg &= readl(device + ISL38XX_INT_EN_REG); + reg &= ISL38XX_INT_SOURCES; + + if (reg != 0) { + /* reset the request bits in the Identification register */ + isl38xx_w32_flush(device, reg, ISL38XX_INT_ACK_REG); + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, + "IRQ: Identification register 0x%p 0x%x \n", device, reg); +#endif + + /* check for each bit in the register separately */ + if (reg & ISL38XX_INT_IDENT_UPDATE) { +#if VERBOSE > SHOW_ERROR_MESSAGES + /* Queue has been updated */ + DEBUG(SHOW_TRACING, "IRQ: Update flag \n"); + + DEBUG(SHOW_QUEUE_INDEXES, + "CB drv Qs: [%i][%i][%i][%i][%i][%i]\n", + le32_to_cpu(priv->control_block-> + driver_curr_frag[0]), + le32_to_cpu(priv->control_block-> + driver_curr_frag[1]), + le32_to_cpu(priv->control_block-> + driver_curr_frag[2]), + le32_to_cpu(priv->control_block-> + driver_curr_frag[3]), + le32_to_cpu(priv->control_block-> + driver_curr_frag[4]), + le32_to_cpu(priv->control_block-> + driver_curr_frag[5]) + ); + + DEBUG(SHOW_QUEUE_INDEXES, + "CB dev Qs: [%i][%i][%i][%i][%i][%i]\n", + le32_to_cpu(priv->control_block-> + device_curr_frag[0]), + le32_to_cpu(priv->control_block-> + device_curr_frag[1]), + le32_to_cpu(priv->control_block-> + device_curr_frag[2]), + le32_to_cpu(priv->control_block-> + device_curr_frag[3]), + le32_to_cpu(priv->control_block-> + device_curr_frag[4]), + le32_to_cpu(priv->control_block-> + device_curr_frag[5]) + ); +#endif + + /* cleanup the data low transmit queue */ + islpci_eth_cleanup_transmit(priv, priv->control_block); + + /* device is in active state, update the + * powerstate flag if necessary */ + powerstate = ISL38XX_PSM_ACTIVE_STATE; + + /* check all three queues in priority order + * call the PIMFOR receive function until the + * queue is empty */ + if (isl38xx_in_queue(priv->control_block, + ISL38XX_CB_RX_MGMTQ) != 0) { +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, + "Received frame in Management Queue\n"); +#endif + islpci_mgt_receive(ndev); + + islpci_mgt_cleanup_transmit(ndev); + + /* Refill slots in receive queue */ + islpci_mgmt_rx_fill(ndev); + + /* no need to trigger the device, next + islpci_mgt_transaction does it */ + } + + while (isl38xx_in_queue(priv->control_block, + ISL38XX_CB_RX_DATA_LQ) != 0) { +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, + "Received frame in Data Low Queue \n"); +#endif + islpci_eth_receive(priv); + } + + /* check whether the data transmit queues were full */ + if (priv->data_low_tx_full) { + /* check whether the transmit is not full anymore */ + if (ISL38XX_CB_TX_QSIZE - + isl38xx_in_queue(priv->control_block, + ISL38XX_CB_TX_DATA_LQ) >= + ISL38XX_MIN_QTHRESHOLD) { + /* nope, the driver is ready for more network frames */ + netif_wake_queue(priv->ndev); + + /* reset the full flag */ + priv->data_low_tx_full = 0; + } + } + } + + if (reg & ISL38XX_INT_IDENT_INIT) { + /* Device has been initialized */ +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, + "IRQ: Init flag, device initialized \n"); +#endif + wake_up(&priv->reset_done); + } + + if (reg & ISL38XX_INT_IDENT_SLEEP) { + /* Device intends to move to powersave state */ +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "IRQ: Sleep flag \n"); +#endif + isl38xx_handle_sleep_request(priv->control_block, + &powerstate, + priv->device_base); + } + + if (reg & ISL38XX_INT_IDENT_WAKEUP) { + /* Device has been woken up to active state */ +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "IRQ: Wakeup flag \n"); +#endif + + isl38xx_handle_wakeup(priv->control_block, + &powerstate, priv->device_base); + } + } + + /* sleep -> ready */ + if (islpci_get_state(priv) == PRV_STATE_SLEEP + && powerstate == ISL38XX_PSM_ACTIVE_STATE) + islpci_set_state(priv, PRV_STATE_READY); + + /* !sleep -> sleep */ + if (islpci_get_state(priv) != PRV_STATE_SLEEP + && powerstate == ISL38XX_PSM_POWERSAVE_STATE) + islpci_set_state(priv, PRV_STATE_SLEEP); + + /* unlock the interrupt handler */ + spin_unlock(&priv->slock); + + return IRQ_HANDLED; +} + +/****************************************************************************** + Network Interface Control & Statistical functions +******************************************************************************/ +static int +islpci_open(struct net_device *ndev) +{ + u32 rc; + islpci_private *priv = ndev->priv; + + printk(KERN_DEBUG "%s: islpci_open()\n", ndev->name); + + /* reset data structures, upload firmware and reset device */ + rc = islpci_reset(priv,1); + if (rc) { + prism54_bring_down(priv); + return rc; /* Returns informative message */ + } + + netif_start_queue(ndev); +/* netif_mark_up( ndev ); */ + + return 0; +} + +static int +islpci_close(struct net_device *ndev) +{ + islpci_private *priv = ndev->priv; + + printk(KERN_DEBUG "%s: islpci_close ()\n", ndev->name); + + netif_stop_queue(ndev); + + return prism54_bring_down(priv); +} + +int +prism54_bring_down(islpci_private *priv) +{ + void *device_base = priv->device_base; + u32 reg; + /* we are going to shutdown the device */ + islpci_set_state(priv, PRV_STATE_PREBOOT); + + /* disable all device interrupts in case they weren't */ + isl38xx_disable_interrupts(priv->device_base); + + /* For safety reasons, we may want to ensure that no DMA transfer is + * currently in progress by emptying the TX and RX queues. */ + + /* wait until interrupts have finished executing on other CPUs */ + prism54_synchronize_irq(priv->pdev->irq); + + reg = readl(device_base + ISL38XX_CTRL_STAT_REG); + reg &= ~(ISL38XX_CTRL_STAT_RESET | ISL38XX_CTRL_STAT_RAMBOOT); + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + reg |= ISL38XX_CTRL_STAT_RESET; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + wmb(); + udelay(ISL38XX_WRITEIO_DELAY); + + /* clear the Reset bit */ + reg &= ~ISL38XX_CTRL_STAT_RESET; + writel(reg, device_base + ISL38XX_CTRL_STAT_REG); + wmb(); + + /* wait a while for the device to reset */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(50*HZ/1000); + + return 0; +} + +static int +islpci_upload_fw(islpci_private *priv) +{ + islpci_state_t old_state; + u32 rc; + + old_state = islpci_set_state(priv, PRV_STATE_BOOT); + + printk(KERN_DEBUG "%s: uploading firmware...\n", priv->ndev->name); + + rc = isl38xx_upload_firmware(priv->firmware, +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,75)) + &priv->pdev->dev, +#else + pci_name(priv->pdev), +#endif + priv->device_base, + priv->device_host_address); + if (rc) { + /* error uploading the firmware */ + printk(KERN_ERR "%s: could not upload firmware ('%s')\n", + priv->ndev->name, priv->firmware); + + islpci_set_state(priv, old_state); + return rc; + } + + printk(KERN_DEBUG + "%s: firmware uploaded done, now triggering reset...\n", + priv->ndev->name); + + islpci_set_state(priv, PRV_STATE_POSTBOOT); + + return 0; +} + +static int +islpci_reset_if(islpci_private *priv) +{ + long remaining; + int result = -ETIME; + int count; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + /* This is 2.6 specific, nicer, shorter, but not in 2.4 yet */ + DEFINE_WAIT(wait); + prepare_to_wait(&priv->reset_done, &wait, TASK_UNINTERRUPTIBLE); +#else + DECLARE_WAITQUEUE(wait, current); + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&priv->reset_done, &wait); +#endif + + /* now the last step is to reset the interface */ + isl38xx_interface_reset(priv->device_base, priv->device_host_address); + islpci_set_state(priv, PRV_STATE_PREINIT); + + for(count = 0; count < 2 && result; count++) { + /* The software reset acknowledge needs about 220 msec here. + * Be conservative and wait for up to one second. */ + + remaining = schedule_timeout(HZ); + + if(remaining > 0) { + result = 0; + break; + } + + /* If we're here it's because our IRQ hasn't yet gone through. + * Retry a bit more... + */ + printk(KERN_ERR "%s: device soft reset timed out\n", + priv->ndev->name); + + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + /* 2.6 specific too */ + finish_wait(&priv->reset_done, &wait); +#else + remove_wait_queue(&priv->reset_done, &wait); + set_current_state(TASK_RUNNING); +#endif + + if(result) + return result; + + islpci_set_state(priv, PRV_STATE_INIT); + + /* Now that the device is 100% up, let's allow + * for the other interrupts -- + * NOTE: this is not *yet* true since we've only allowed the + * INIT interrupt on the IRQ line. We can perhaps poll + * the IRQ line until we know for sure the reset went through */ + isl38xx_enable_common_interrupts(priv->device_base); + + prism54_mib_init_work(priv); + + islpci_set_state(priv, PRV_STATE_READY); + + return 0; +} + +int +islpci_reset(islpci_private *priv, int reload_firmware) +{ + isl38xx_control_block *cb = /* volatile not needed */ + (isl38xx_control_block *) priv->control_block; + unsigned counter; + int rc; + + if (reload_firmware) + islpci_set_state(priv, PRV_STATE_PREBOOT); + else + islpci_set_state(priv, PRV_STATE_POSTBOOT); + + printk(KERN_DEBUG "%s: resetting device...\n", priv->ndev->name); + + /* disable all device interrupts in case they weren't */ + isl38xx_disable_interrupts(priv->device_base); + + /* flush all management queues */ + priv->index_mgmt_tx = 0; + priv->index_mgmt_rx = 0; + + /* clear the indexes in the frame pointer */ + for (counter = 0; counter < ISL38XX_CB_QCOUNT; counter++) { + cb->driver_curr_frag[counter] = cpu_to_le32(0); + cb->device_curr_frag[counter] = cpu_to_le32(0); + } + + /* reset the mgmt receive queue */ + for (counter = 0; counter < ISL38XX_CB_MGMT_QSIZE; counter++) { + isl38xx_fragment *frag = &cb->rx_data_mgmt[counter]; + frag->size = MGMT_FRAME_SIZE; + frag->flags = 0; + frag->address = priv->mgmt_rx[counter].pci_addr; + } + + for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) { + cb->rx_data_low[counter].address = + cpu_to_le32((u32) priv->pci_map_rx_address[counter]); + } + + /* since the receive queues are filled with empty fragments, now we can + * set the corresponding indexes in the Control Block */ + priv->control_block->driver_curr_frag[ISL38XX_CB_RX_DATA_LQ] = + cpu_to_le32(ISL38XX_CB_RX_QSIZE); + priv->control_block->driver_curr_frag[ISL38XX_CB_RX_MGMTQ] = + cpu_to_le32(ISL38XX_CB_MGMT_QSIZE); + + /* reset the remaining real index registers and full flags */ + priv->free_data_rx = 0; + priv->free_data_tx = 0; + priv->data_low_tx_full = 0; + + if (reload_firmware) { /* Should we load the firmware ? */ + /* now that the data structures are cleaned up, upload + * firmware and reset interface */ + rc = islpci_upload_fw(priv); + if (rc) + return rc; + } + + /* finally reset interface */ + rc = islpci_reset_if(priv); + if (!rc) /* If successful */ + return rc; + + printk(KERN_DEBUG "prism54: Your card/socket may be faulty, or IRQ line too busy :(\n"); + return rc; + +} + +struct net_device_stats * +islpci_statistics(struct net_device *ndev) +{ + islpci_private *priv = ndev->priv; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_statistics \n"); +#endif + + return &priv->statistics; +} + +/****************************************************************************** + Network device configuration functions +******************************************************************************/ +int +islpci_alloc_memory(islpci_private *priv) +{ + int counter; + +#if VERBOSE > SHOW_ERROR_MESSAGES + printk(KERN_DEBUG "islpci_alloc_memory\n"); +#endif + + /* remap the PCI device base address to accessable */ + if (!(priv->device_base = + ioremap(pci_resource_start(priv->pdev, 0), + ISL38XX_PCI_MEM_SIZE))) { + /* error in remapping the PCI device memory address range */ + printk(KERN_ERR "PCI memory remapping failed \n"); + return -1; + } + + /* memory layout for consistent DMA region: + * + * Area 1: Control Block for the device interface + * Area 2: Power Save Mode Buffer for temporary frame storage. Be aware that + * the number of supported stations in the AP determines the minimal + * size of the buffer ! + */ + + /* perform the allocation */ + priv->driver_mem_address = pci_alloc_consistent(priv->pdev, + HOST_MEM_BLOCK, + &priv-> + device_host_address); + + if (!priv->driver_mem_address) { + /* error allocating the block of PCI memory */ + printk(KERN_ERR "%s: could not allocate DMA memory, aborting!", + "prism54"); + return -1; + } + + /* assign the Control Block to the first address of the allocated area */ + priv->control_block = + (isl38xx_control_block *) priv->driver_mem_address; + + /* set the Power Save Buffer pointer directly behind the CB */ + priv->device_psm_buffer = + priv->device_host_address + CONTROL_BLOCK_SIZE; + + /* make sure all buffer pointers are initialized */ + for (counter = 0; counter < ISL38XX_CB_QCOUNT; counter++) { + priv->control_block->driver_curr_frag[counter] = cpu_to_le32(0); + priv->control_block->device_curr_frag[counter] = cpu_to_le32(0); + } + + priv->index_mgmt_rx = 0; + memset(priv->mgmt_rx, 0, sizeof(priv->mgmt_rx)); + memset(priv->mgmt_tx, 0, sizeof(priv->mgmt_tx)); + + /* allocate rx queue for management frames */ + if (islpci_mgmt_rx_fill(priv->ndev) < 0) + goto out_free; + + /* now get the data rx skb's */ + memset(priv->data_low_rx, 0, sizeof (priv->data_low_rx)); + memset(priv->pci_map_rx_address, 0, sizeof (priv->pci_map_rx_address)); + + for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) { + struct sk_buff *skb; + + /* allocate an sk_buff for received data frames storage + * each frame on receive size consists of 1 fragment + * include any required allignment operations */ + if (!(skb = dev_alloc_skb(MAX_FRAGMENT_SIZE_RX + 2))) { + /* error allocating an sk_buff structure elements */ + printk(KERN_ERR "Error allocating skb.\n"); + goto out_free; + } + /* add the new allocated sk_buff to the buffer array */ + priv->data_low_rx[counter] = skb; + + /* map the allocated skb data area to pci */ + priv->pci_map_rx_address[counter] = + pci_map_single(priv->pdev, (void *) skb->data, + MAX_FRAGMENT_SIZE_RX + 2, + PCI_DMA_FROMDEVICE); + if (!priv->pci_map_rx_address[counter]) { + /* error mapping the buffer to device + accessable memory address */ + printk(KERN_ERR "failed to map skb DMA'able\n"); + goto out_free; + } + } + + prism54_acl_init(&priv->acl); + prism54_wpa_ie_init(priv); + if (mgt_init(priv)) + goto out_free; + + return 0; + out_free: + islpci_free_memory(priv); + return -1; +} + +int +islpci_free_memory(islpci_private *priv) +{ + int counter; + + if (priv->device_base) + iounmap(priv->device_base); + priv->device_base = 0; + + /* free consistent DMA area... */ + if (priv->driver_mem_address) + pci_free_consistent(priv->pdev, HOST_MEM_BLOCK, + priv->driver_mem_address, + priv->device_host_address); + + /* clear some dangling pointers */ + priv->driver_mem_address = 0; + priv->device_host_address = 0; + priv->device_psm_buffer = 0; + priv->control_block = 0; + + /* clean up mgmt rx buffers */ + for (counter = 0; counter < ISL38XX_CB_MGMT_QSIZE; counter++) { + struct islpci_membuf *buf = &priv->mgmt_rx[counter]; + if (buf->pci_addr) + pci_unmap_single(priv->pdev, buf->pci_addr, + buf->size, PCI_DMA_FROMDEVICE); + buf->pci_addr = 0; + if (buf->mem) + kfree(buf->mem); + buf->size = 0; + buf->mem = NULL; + } + + /* clean up data rx buffers */ + for (counter = 0; counter < ISL38XX_CB_RX_QSIZE; counter++) { + if (priv->pci_map_rx_address[counter]) + pci_unmap_single(priv->pdev, + priv->pci_map_rx_address[counter], + MAX_FRAGMENT_SIZE_RX + 2, + PCI_DMA_FROMDEVICE); + priv->pci_map_rx_address[counter] = 0; + + if (priv->data_low_rx[counter]) + dev_kfree_skb(priv->data_low_rx[counter]); + priv->data_low_rx[counter] = 0; + } + + /* Free the acces control list and the WPA list */ + prism54_acl_clean(&priv->acl); + prism54_wpa_ie_clean(priv); + mgt_clean(priv); + + return 0; +} + +#if 0 +static void +islpci_set_multicast_list(struct net_device *dev) +{ + /* put device into promisc mode and let network layer handle it */ +} +#endif + +struct net_device * +islpci_setup(struct pci_dev *pdev) +{ + islpci_private *priv; + struct net_device *ndev = alloc_etherdev(sizeof (islpci_private)); + + if (!ndev) + return ndev; + + SET_MODULE_OWNER(ndev); + pci_set_drvdata(pdev, ndev); +#if defined(SET_NETDEV_DEV) + SET_NETDEV_DEV(ndev, &pdev->dev); +#endif + + /* setup the structure members */ + ndev->base_addr = pci_resource_start(pdev, 0); + ndev->irq = pdev->irq; + + /* initialize the function pointers */ + ndev->open = &islpci_open; + ndev->stop = &islpci_close; + ndev->get_stats = &islpci_statistics; + ndev->get_wireless_stats = &prism54_get_wireless_stats; + ndev->do_ioctl = &prism54_ioctl; + ndev->wireless_handlers = + (struct iw_handler_def *) &prism54_handler_def; + + ndev->hard_start_xmit = &islpci_eth_transmit; + /* ndev->set_multicast_list = &islpci_set_multicast_list; */ + ndev->addr_len = ETH_ALEN; + ndev->set_mac_address = &prism54_set_mac_address; + /* Get a non-zero dummy MAC address for nameif. Jean II */ + memcpy(ndev->dev_addr, dummy_mac, 6); + +#ifdef HAVE_TX_TIMEOUT + ndev->watchdog_timeo = ISLPCI_TX_TIMEOUT; + ndev->tx_timeout = &islpci_eth_tx_timeout; +#endif + + /* allocate a private device structure to the network device */ + priv = ndev->priv; + priv->ndev = ndev; + priv->pdev = pdev; + + priv->ndev->type = (priv->iw_mode == IW_MODE_MONITOR) ? + ARPHRD_IEEE80211: ARPHRD_ETHER; + + /* save the start and end address of the PCI memory area */ + ndev->mem_start = (unsigned long) priv->device_base; + ndev->mem_end = ndev->mem_start + ISL38XX_PCI_MEM_SIZE; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "PCI Memory remapped to 0x%p\n", priv->device_base); +#endif + + init_waitqueue_head(&priv->reset_done); + + /* init the queue read locks, process wait counter */ + sema_init(&priv->mgmt_sem, 1); + priv->mgmt_received = NULL; + init_waitqueue_head(&priv->mgmt_wqueue); + sema_init(&priv->stats_sem, 1); + spin_lock_init(&priv->slock); + + /* init state machine with off#1 state */ + priv->state = PRV_STATE_OFF; + priv->state_off = 1; + + /* initialize workqueue's */ + INIT_WORK(&priv->stats_work, + (void (*)(void *)) prism54_update_stats, priv); + + priv->stats_timestamp = 0; + + /* allocate various memory areas */ + if (islpci_alloc_memory(priv)) + goto do_free_netdev; + + /* select the firmware file depending on the device id */ + switch (pdev->device) { + case PCIDEVICE_ISL3890: + case PCIDEVICE_3COM6001: + strcpy(priv->firmware, ISL3890_IMAGE_FILE); + break; + case PCIDEVICE_ISL3877: + strcpy(priv->firmware, ISL3877_IMAGE_FILE); + break; + + default: + strcpy(priv->firmware, ISL3890_IMAGE_FILE); + break; + } + + if (register_netdev(ndev)) { + DEBUG(SHOW_ERROR_MESSAGES, + "ERROR: register_netdev() failed \n"); + goto do_islpci_free_memory; + } + + return ndev; + + do_islpci_free_memory: + islpci_free_memory(priv); + do_free_netdev: + pci_set_drvdata(pdev, 0); + free_netdev(ndev); + priv = 0; + return NULL; +} + +islpci_state_t +islpci_set_state(islpci_private *priv, islpci_state_t new_state) +{ + islpci_state_t old_state; + + /* lock */ + old_state = priv->state; + + /* this means either a race condition or some serious error in + * the driver code */ + switch (new_state) { + case PRV_STATE_OFF: + priv->state_off++; + default: + priv->state = new_state; + break; + + case PRV_STATE_PREBOOT: + /* there are actually many off-states, enumerated by + * state_off */ + if (old_state == PRV_STATE_OFF) + priv->state_off--; + + /* only if hw_unavailable is zero now it means we either + * were in off#1 state, or came here from + * somewhere else */ + if (!priv->state_off) + priv->state = new_state; + break; + }; +#if 0 + printk(KERN_DEBUG "%s: state transition %d -> %d (off#%d)\n", + priv->ndev->name, old_state, new_state, priv->state_off); +#endif + + /* invariants */ + BUG_ON(priv->state_off < 0); + BUG_ON(priv->state_off && (priv->state != PRV_STATE_OFF)); + BUG_ON(!priv->state_off && (priv->state == PRV_STATE_OFF)); + + /* unlock */ + return old_state; +} diff -Nru a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/islpci_dev.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,228 @@ +/* $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_dev.h,v 1.53 2004/02/28 03:06:07 mcgrof Exp $ + * + * Copyright (C) 2002 Intersil Americas Inc. + * Copyright (C) 2003 Herbert Valerio Riedel + * Copyright (C) 2003 Luis R. Rodriguez + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _ISLPCI_DEV_H +#define _ISLPCI_DEV_H + +#include +#include +#include +#include + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41) +# include +#else +# include +# define work_struct tq_struct +# define INIT_WORK INIT_TQUEUE +# define schedule_work schedule_task +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,23) +#define free_netdev(x) kfree(x) +#define pci_name(x) x->slot_name +#endif + +#include "isl_38xx.h" +#include "isl_oid.h" +#include "islpci_mgt.h" + +/* some states might not be superflous and may be removed when + design is finalized (hvr) */ +typedef enum { + PRV_STATE_OFF = 0, /* this means hw_unavailable is != 0 */ + PRV_STATE_PREBOOT, /* we are in a pre-boot state (empty RAM) */ + PRV_STATE_BOOT, /* boot state (fw upload, run fw) */ + PRV_STATE_POSTBOOT, /* after boot state, need reset now */ + PRV_STATE_PREINIT, /* pre-init state */ + PRV_STATE_INIT, /* init state (restore MIB backup to device) */ + PRV_STATE_READY, /* driver&device are in operational state */ + PRV_STATE_SLEEP /* device in sleep mode */ +} islpci_state_t; + +/* ACL using MAC address */ +struct mac_entry { + struct list_head _list; + char addr[ETH_ALEN]; +}; + +struct islpci_acl { + enum { MAC_POLICY_OPEN=0, MAC_POLICY_ACCEPT=1, MAC_POLICY_REJECT=2 } policy; + struct list_head mac_list; /* a list of mac_entry */ + int size; /* size of queue */ + struct semaphore sem; /* accessed in ioctls and trap_work */ +}; + +struct islpci_membuf { + int size; /* size of memory */ + void *mem; /* address of memory as seen by CPU */ + dma_addr_t pci_addr; /* address of memory as seen by device */ +}; + +#define MAX_BSS_WPA_IE_COUNT 64 +#define MAX_WPA_IE_LEN 64 +struct islpci_bss_wpa_ie { + struct list_head list; + unsigned long last_update; + u8 bssid[ETH_ALEN]; + u8 wpa_ie[MAX_WPA_IE_LEN]; + size_t wpa_ie_len; + +}; + +typedef struct { + spinlock_t slock; /* generic spinlock; */ + + u32 priv_oid; + + /* our mib cache */ + u32 iw_mode; + struct rw_semaphore mib_sem; + void **mib; + char nickname[IW_ESSID_MAX_SIZE+1]; + + /* Take care of the wireless stats */ + struct work_struct stats_work; + struct semaphore stats_sem; + /* remember when we last updated the stats */ + unsigned long stats_timestamp; + /* The first is accessed under semaphore locking. + * The second is the clean one we return to iwconfig. + */ + struct iw_statistics local_iwstatistics; + struct iw_statistics iwstatistics; + + struct islpci_acl acl; + + /* PCI bus allocation & configuration members */ + struct pci_dev *pdev; /* PCI structure information */ + u32 pci_state[16]; /* used for suspend/resume */ + char firmware[33]; + + void *device_base; /* ioremapped device base address */ + + /* consistent DMA region */ + void *driver_mem_address; /* base DMA address */ + dma_addr_t device_host_address; /* base DMA address (bus address) */ + dma_addr_t device_psm_buffer; /* host memory for PSM buffering (bus address) */ + + /* our network_device structure */ + struct net_device *ndev; + + /* device queue interface members */ + struct isl38xx_cb *control_block; /* device control block + (== driver_mem_address!) */ + + /* Each queue has three indexes: + * free/index_mgmt/data_rx/tx (called index, see below), + * driver_curr_frag, and device_curr_frag (in the control block) + * All indexes are ever-increasing, but interpreted modulo the + * device queue size when used. + * index <= device_curr_frag <= driver_curr_frag at all times + * For rx queues, [index, device_curr_frag) contains fragments + * that the interrupt processing needs to handle (owned by driver). + * [device_curr_frag, driver_curr_frag) is the free space in the + * rx queue, waiting for data (owned by device). The driver + * increments driver_curr_frag to indicate to the device that more + * buffers are available. + * If device_curr_frag == driver_curr_frag, no more rx buffers are + * available, and the rx DMA engine of the device is halted. + * For tx queues, [index, device_curr_frag) contains fragments + * where tx is done; they need to be freed (owned by driver). + * [device_curr_frag, driver_curr_frag) contains the frames + * that are being transferred (owned by device). The driver + * increments driver_curr_frag to indicate that more tx work + * needs to be done. + */ + u32 index_mgmt_rx; /* real index mgmt rx queue */ + u32 index_mgmt_tx; /* read index mgmt tx queue */ + u32 free_data_rx; /* free pointer data rx queue */ + u32 free_data_tx; /* free pointer data tx queue */ + u32 data_low_tx_full; /* full detected flag */ + + /* frame memory buffers for the device queues */ + struct islpci_membuf mgmt_tx[ISL38XX_CB_MGMT_QSIZE]; + struct islpci_membuf mgmt_rx[ISL38XX_CB_MGMT_QSIZE]; + struct sk_buff *data_low_tx[ISL38XX_CB_TX_QSIZE]; + struct sk_buff *data_low_rx[ISL38XX_CB_RX_QSIZE]; + dma_addr_t pci_map_tx_address[ISL38XX_CB_TX_QSIZE]; + dma_addr_t pci_map_rx_address[ISL38XX_CB_RX_QSIZE]; + + /* driver network interface members */ + struct net_device_stats statistics; + + /* wait for a reset interrupt */ + wait_queue_head_t reset_done; + + /* used by islpci_mgt_transaction */ + struct semaphore mgmt_sem; /* serialize access to mailbox and wqueue */ + struct islpci_mgmtframe *mgmt_received; /* mbox for incoming frame */ + wait_queue_head_t mgmt_wqueue; /* waitqueue for mbox */ + + /* state machine */ + islpci_state_t state; + int state_off; /* enumeration of off-state, if 0 then + * we're not in any off-state */ + + /* WPA stuff */ + int wpa; /* WPA mode enabled */ + struct list_head bss_wpa_list; + int num_bss_wpa; + struct semaphore wpa_sem; +} islpci_private; + +static inline islpci_state_t +islpci_get_state(islpci_private *priv) +{ + /* lock */ + return priv->state; + /* unlock */ +} + +islpci_state_t islpci_set_state(islpci_private *priv, islpci_state_t new_state); + +#define ISLPCI_TX_TIMEOUT (2*HZ) + +#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,75)) +# define irqreturn_t void +# define IRQ_HANDLED +# define IRQ_NONE +#endif + +irqreturn_t islpci_interrupt(int, void *, struct pt_regs *); + +int prism54_post_setup(islpci_private *, int); +int islpci_reset(islpci_private *, int); + +static inline void +islpci_trigger(islpci_private *priv) +{ + isl38xx_trigger_device(islpci_get_state(priv) == PRV_STATE_SLEEP, + priv->device_base); +} + +struct net_device_stats *islpci_statistics(struct net_device *); + +int prism54_bring_down(islpci_private *); +int islpci_alloc_memory(islpci_private *); +int islpci_free_memory(islpci_private *); +struct net_device *islpci_setup(struct pci_dev *); +#endif /* _ISLPCI_DEV_H */ diff -Nru a/drivers/net/wireless/prism54/islpci_eth.c b/drivers/net/wireless/prism54/islpci_eth.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/islpci_eth.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,429 @@ +/* $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_eth.c,v 1.27 2004/01/30 16:24:00 ajfa Exp $ + * + * Copyright (C) 2002 Intersil Americas Inc. + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include + +#include +#include +#include +#include + +#include "isl_38xx.h" +#include "islpci_eth.h" +#include "islpci_mgt.h" + +/****************************************************************************** + Network Interface functions +******************************************************************************/ +void +islpci_eth_cleanup_transmit(islpci_private *priv, + isl38xx_control_block *control_block) +{ + struct sk_buff *skb; + u32 index; + + /* compare the control block read pointer with the free pointer */ + while (priv->free_data_tx != + le32_to_cpu(control_block-> + device_curr_frag[ISL38XX_CB_TX_DATA_LQ])) { + /* read the index of the first fragment to be freed */ + index = priv->free_data_tx % ISL38XX_CB_TX_QSIZE; + + /* check for holes in the arrays caused by multi fragment frames + * searching for the last fragment of a frame */ + if (priv->pci_map_tx_address[index] != (dma_addr_t) NULL) { + /* entry is the last fragment of a frame + * free the skb structure and unmap pci memory */ + skb = priv->data_low_tx[index]; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, + "cleanup skb %p skb->data %p skb->len %u truesize %u\n ", + skb, skb->data, skb->len, skb->truesize); +#endif + + pci_unmap_single(priv->pdev, + priv->pci_map_tx_address[index], + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); + } + /* increment the free data low queue pointer */ + priv->free_data_tx++; + } +} + +int +islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev) +{ + islpci_private *priv = ndev->priv; + isl38xx_control_block *cb = priv->control_block; + u32 index; + dma_addr_t pci_map_address; + int frame_size; + isl38xx_fragment *fragment; + int offset; + struct sk_buff *newskb; + int newskb_offset; + unsigned long flags; + unsigned char wds_mac[6]; + u32 curr_frag; + int err = 0; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_transmit \n"); +#endif + + /* lock the driver code */ + spin_lock_irqsave(&priv->slock, flags); + + /* determine the amount of fragments needed to store the frame */ + + frame_size = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; + if (init_wds) + frame_size += 6; + + /* check whether the destination queue has enough fragments for the frame */ + curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ]); + if (curr_frag - priv->free_data_tx >= ISL38XX_CB_TX_QSIZE) { + printk(KERN_ERR "%s: transmit device queue full when awake\n", + ndev->name); + netif_stop_queue(ndev); + + /* trigger the device */ + isl38xx_w32_flush(priv->device_base, ISL38XX_DEV_INT_UPDATE, + ISL38XX_DEV_INT_REG); + udelay(ISL38XX_WRITEIO_DELAY); + + err = -EBUSY; + goto drop_free; + } + /* Check alignment and WDS frame formatting. The start of the packet should + * be aligned on a 4-byte boundary. If WDS is enabled add another 6 bytes + * and add WDS address information */ + if (((long) skb->data & 0x03) | init_wds) { + /* get the number of bytes to add and re-allign */ + offset = (4 - (long) skb->data) & 0x03; + offset += init_wds ? 6 : 0; + + /* check whether the current skb can be used */ + if (!skb_cloned(skb) && (skb_tailroom(skb) >= offset)) { + unsigned char *src = skb->data; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "skb offset %i wds %i\n", offset, + init_wds); +#endif + + /* align the buffer on 4-byte boundary */ + skb_reserve(skb, (4 - (long) skb->data) & 0x03); + if (init_wds) { + /* wds requires an additional address field of 6 bytes */ + skb_put(skb, 6); +#ifdef ISLPCI_ETH_DEBUG + printk("islpci_eth_transmit:wds_mac\n"); +#endif + memmove(skb->data + 6, src, skb->len); + memcpy(skb->data, wds_mac, 6); + } else { + memmove(skb->data, src, skb->len); + } + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "memmove %p %p %i \n", skb->data, + src, skb->len); +#endif + } else { + newskb = + dev_alloc_skb(init_wds ? skb->len + 6 : skb->len); + newskb_offset = (4 - (long) newskb->data) & 0x03; + + /* Check if newskb->data is aligned */ + if (newskb_offset) + skb_reserve(newskb, newskb_offset); + + skb_put(newskb, init_wds ? skb->len + 6 : skb->len); + if (init_wds) { + memcpy(newskb->data + 6, skb->data, skb->len); + memcpy(newskb->data, wds_mac, 6); +#ifdef ISLPCI_ETH_DEBUG + printk("islpci_eth_transmit:wds_mac\n"); +#endif + } else + memcpy(newskb->data, skb->data, skb->len); + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "memcpy %p %p %i wds %i\n", + newskb->data, skb->data, skb->len, init_wds); +#endif + + newskb->dev = skb->dev; + dev_kfree_skb(skb); + skb = newskb; + } + } + /* display the buffer contents for debugging */ +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_BUFFER_CONTENTS, "\ntx %p ", skb->data); + display_buffer((char *) skb->data, skb->len); +#endif + + /* map the skb buffer to pci memory for DMA operation */ + pci_map_address = pci_map_single(priv->pdev, + (void *) skb->data, skb->len, + PCI_DMA_TODEVICE); + if (pci_map_address == 0) { + printk(KERN_WARNING "%s: cannot map buffer to PCI\n", + ndev->name); + + err = -EIO; + goto drop_free; + } + /* Place the fragment in the control block structure. */ + index = curr_frag % ISL38XX_CB_TX_QSIZE; + fragment = &cb->tx_data_low[index]; + + priv->pci_map_tx_address[index] = pci_map_address; + /* store the skb address for future freeing */ + priv->data_low_tx[index] = skb; + /* set the proper fragment start address and size information */ + fragment->size = cpu_to_le16(frame_size); + fragment->flags = cpu_to_le16(0); /* set to 1 if more fragments */ + fragment->address = cpu_to_le32(pci_map_address); + curr_frag++; + + /* The fragment address in the control block must have been + * written before announcing the frame buffer to device. */ + wmb(); + cb->driver_curr_frag[ISL38XX_CB_TX_DATA_LQ] = cpu_to_le32(curr_frag); + + if (curr_frag - priv->free_data_tx + ISL38XX_MIN_QTHRESHOLD + > ISL38XX_CB_TX_QSIZE) { + /* stop sends from upper layers */ + netif_stop_queue(ndev); + + /* set the full flag for the transmission queue */ + priv->data_low_tx_full = 1; + } + + /* trigger the device */ + islpci_trigger(priv); + + /* unlock the driver code */ + spin_unlock_irqrestore(&priv->slock, flags); + + /* set the transmission time */ + ndev->trans_start = jiffies; + priv->statistics.tx_packets++; + priv->statistics.tx_bytes += skb->len; + + return 0; + + drop_free: + /* free the skbuf structure before aborting */ + dev_kfree_skb(skb); + + priv->statistics.tx_dropped++; + spin_unlock_irqrestore(&priv->slock, flags); + return err; +} + +int +islpci_eth_receive(islpci_private *priv) +{ + struct net_device *ndev = priv->ndev; + isl38xx_control_block *control_block = priv->control_block; + struct sk_buff *skb; + u16 size; + u32 index, offset; + unsigned char *src; + int discard = 0; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_eth_receive \n"); +#endif + + /* the device has written an Ethernet frame in the data area + * of the sk_buff without updating the structure, do it now */ + index = priv->free_data_rx % ISL38XX_CB_RX_QSIZE; + size = le16_to_cpu(control_block->rx_data_low[index].size); + skb = priv->data_low_rx[index]; + offset = ((unsigned long) le32_to_cpu(control_block->rx_data_low[index].address) - + (unsigned long) skb->data) & 3; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, + "frq->addr %x skb->data %p skb->len %u offset %u truesize %u\n ", + control_block->rx_data_low[priv->free_data_rx].address, skb->data, + skb->len, offset, skb->truesize); +#endif + + /* delete the streaming DMA mapping before processing the skb */ + pci_unmap_single(priv->pdev, + priv->pci_map_rx_address[index], + MAX_FRAGMENT_SIZE_RX + 2, PCI_DMA_FROMDEVICE); + + /* update the skb structure and allign the buffer */ + skb_put(skb, size); + if (offset) { + /* shift the buffer allocation offset bytes to get the right frame */ + skb_pull(skb, 2); + skb_put(skb, 2); + } +#if VERBOSE > SHOW_ERROR_MESSAGES + /* display the buffer contents for debugging */ + DEBUG(SHOW_BUFFER_CONTENTS, "\nrx %p ", skb->data); + display_buffer((char *) skb->data, skb->len); +#endif + + /* check whether WDS is enabled and whether the data frame is a WDS frame */ + + if (init_wds) { + /* WDS enabled, check for the wds address on the first 6 bytes of the buffer */ + src = skb->data + 6; + memmove(skb->data, src, skb->len - 6); + skb_trim(skb, skb->len - 6); + } +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "Fragment size %i in skb at %p\n", size, skb); + DEBUG(SHOW_TRACING, "Skb data at %p, length %i\n", skb->data, skb->len); + + /* display the buffer contents for debugging */ + DEBUG(SHOW_BUFFER_CONTENTS, "\nrx %p ", skb->data); + display_buffer((char *) skb->data, skb->len); +#endif + + /* do some additional sk_buff and network layer parameters */ + skb->dev = ndev; + + /* take care of monitor mode */ + if (priv->iw_mode == IW_MODE_MONITOR) { + /* The card reports full 802.11 packets but with a 20 bytes + * header and without the FCS. But there a is a bit that + * indicates if the packet is corrupted :-) */ + /* int i; */ + if (skb->data[8] & 0x01){ + /* This one is bad. Drop it !*/ + discard = 1; + /* printk("BAD\n");*/ + } + /* + for(i=0;i<50;i++) + printk("%2.2X:",skb->data[i]); + printk("\n"); + */ + skb_pull(skb, 20); + skb->protocol = htons(ETH_P_802_2); + skb->mac.raw = skb->data; + skb->pkt_type = PACKET_OTHERHOST; + } else + skb->protocol = eth_type_trans(skb, ndev); + + skb->ip_summed = CHECKSUM_NONE; + priv->statistics.rx_packets++; + priv->statistics.rx_bytes += size; + + /* deliver the skb to the network layer */ +#ifdef ISLPCI_ETH_DEBUG + printk + ("islpci_eth_receive:netif_rx %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", + skb->data[0], skb->data[1], skb->data[2], skb->data[3], + skb->data[4], skb->data[5]); +#endif + if (discard) + dev_kfree_skb(skb); + else + netif_rx(skb); + + /* increment the read index for the rx data low queue */ + priv->free_data_rx++; + + /* add one or more sk_buff structures */ + while (index = + le32_to_cpu(control_block-> + driver_curr_frag[ISL38XX_CB_RX_DATA_LQ]), + index - priv->free_data_rx < ISL38XX_CB_RX_QSIZE) { + /* allocate an sk_buff for received data frames storage + * include any required allignment operations */ + if (skb = dev_alloc_skb(MAX_FRAGMENT_SIZE_RX + 2), skb == NULL) { + /* error allocating an sk_buff structure elements */ + DEBUG(SHOW_ERROR_MESSAGES, "Error allocating skb \n"); + break; + } + /* store the new skb structure pointer */ + index = index % ISL38XX_CB_RX_QSIZE; + priv->data_low_rx[index] = skb; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, + "new alloc skb %p skb->data %p skb->len %u index %u truesize %u\n ", + skb, skb->data, skb->len, index, skb->truesize); +#endif + + /* set the streaming DMA mapping for proper PCI bus operation */ + priv->pci_map_rx_address[index] = + pci_map_single(priv->pdev, (void *) skb->data, + MAX_FRAGMENT_SIZE_RX + 2, + PCI_DMA_FROMDEVICE); + if (priv->pci_map_rx_address[index] == (dma_addr_t) NULL) { + /* error mapping the buffer to device accessable memory address */ + DEBUG(SHOW_ERROR_MESSAGES, + "Error mapping DMA address\n"); + + /* free the skbuf structure before aborting */ + dev_kfree_skb((struct sk_buff *) skb); + break; + } + /* update the fragment address */ + control_block->rx_data_low[index].address = cpu_to_le32((u32) + priv-> + pci_map_rx_address + [index]); + wmb(); + + /* increment the driver read pointer */ + add_le32p((u32 *) & control_block-> + driver_curr_frag[ISL38XX_CB_RX_DATA_LQ], 1); + } + + /* trigger the device */ + islpci_trigger(priv); + + return 0; +} + +void +islpci_eth_tx_timeout(struct net_device *ndev) +{ + islpci_private *priv = ndev->priv; + struct net_device_stats *statistics = &priv->statistics; + + /* increment the transmit error counter */ + statistics->tx_errors++; + +#if 0 + /* don't do this here! we are not allowed to sleep since we are in interrupt context */ + if (islpci_reset(priv)) + printk(KERN_ERR "%s: error on TX timeout card reset!\n", + ndev->name); +#endif + + /* netif_wake_queue(ndev); */ + return; +} diff -Nru a/drivers/net/wireless/prism54/islpci_eth.h b/drivers/net/wireless/prism54/islpci_eth.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/islpci_eth.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,31 @@ +/* $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_eth.h,v 1.5 2004/01/12 22:16:32 jmaurer Exp $ + * + * Copyright (C) 2002 Intersil Americas Inc. + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _ISLPCI_ETH_H +#define _ISLPCI_ETH_H + +#include "isl_38xx.h" +#include "islpci_dev.h" + +void islpci_eth_cleanup_transmit(islpci_private *, isl38xx_control_block *); +int islpci_eth_transmit(struct sk_buff *, struct net_device *); +int islpci_eth_receive(islpci_private *); +void islpci_eth_tx_timeout(struct net_device *); + +#endif /* _ISL_GEN_H */ diff -Nru a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/islpci_hotplug.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,428 @@ +/* $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_hotplug.c,v 1.56 2004/02/26 23:33:02 mcgrof Exp $ + * + * Copyright (C) 2002 Intersil Americas Inc. + * Copyright (C) 2003 Herbert Valerio Riedel + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include /* For __init, __exit */ + +#include "islpci_dev.h" +#include "islpci_mgt.h" /* for pc_debug */ +#include "isl_oid.h" + +#define DRV_NAME "prism54" +#define DRV_VERSION "1.0.2.2" + +MODULE_AUTHOR("W.Termorshuizen, R.Bastings, H.V.Riedel, prism54.org team"); +MODULE_DESCRIPTION("Intersil 802.11 Wireless LAN adapter"); +MODULE_LICENSE("GPL"); + +/* In this order: vendor, device, subvendor, subdevice, class, class_mask, + * driver_data + * Note: for driver_data we put the device's name + * If you have an update for this please contact prism54-devel@prism54.org + * The latest list can be found at http://prism54.org/supported_cards.php */ +static const struct pci_device_id prism54_id_tbl[] = { + { + PCIVENDOR_3COM, PCIDEVICE_3COM6001, + PCIVENDOR_3COM, PCIDEVICE_3COM6001, + 0, 0, + (unsigned long) "3COM 3CRWE154G72 Wireless LAN adapter"}, + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_DLINK, 0x3202UL, + 0, 0, + (unsigned long) "D-Link Air Plus Xtreme G A1 - DWL-g650 A1"}, + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_IODATA, 0xd019UL, + 0, 0, + (unsigned long) "I-O Data WN-G54/CB - WN-G54/CB"}, + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_NETGEAR, 0x4800UL, + 0, 0, + (unsigned long) "Netgear WG511"}, + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_I4, 0x0020UL, + 0, 0, + (unsigned long) "PLANEX GW-DS54G"}, + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_SMC, 0x2802UL, + 0, 0, + (unsigned long) "EZ Connect g 2.4GHz 54 Mbps Wireless PCI Card - SMC2802W"}, + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_SMC, 0x2835UL, + 0, 0, + (unsigned long) "EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Adapter - SMC2835W"}, + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_INTERSIL, 0x0000UL, /* This was probably a bogus reading... */ + 0, 0, + (unsigned long) "SparkLAN WL-850F"}, + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_I4, 0x0014UL, + 0, 0, + (unsigned long) "I4 Z-Com XG-600"}, + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_I4, 0x0020UL, + 0, 0, + (unsigned long) "I4 Z-Com XG-900/PLANEX GW-DS54G"}, + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCIVENDOR_ACCTON, 0xee03UL, + 0, 0, + (unsigned long) "SMC 2802Wv2"}, + { + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3877, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + (unsigned long) "Intersil PRISM Indigo Wireless LAN adapter"}, + { /* Default */ + PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, + (unsigned long) "Intersil PRISM Duette/Prism GT Wireless LAN adapter"}, + {0,} +}; + +/* register the device with the Hotplug facilities of the kernel */ +MODULE_DEVICE_TABLE(pci, prism54_id_tbl); + +static int prism54_probe(struct pci_dev *, const struct pci_device_id *); +static void prism54_remove(struct pci_dev *); +static int prism54_suspend(struct pci_dev *, u32 state); +static int prism54_resume(struct pci_dev *); + +static struct pci_driver prism54_driver = { + .name = DRV_NAME, + .id_table = prism54_id_tbl, + .probe = prism54_probe, + .remove = prism54_remove, + .suspend = prism54_suspend, + .resume = prism54_resume, + /* .enable_wake ; we don't support this yet */ +}; + +static void +prism54_get_card_model(struct net_device *ndev) +{ + islpci_private *priv; + char *modelp; + + priv = ndev->priv; + switch (priv->pdev->subsystem_device) { + case PCIDEVICE_ISL3877: + modelp = "PRISM Indigo"; + break; + case PCIDEVICE_3COM6001: + modelp = "3COM 3CRWE154G72"; + break; + case 0x3202UL: + modelp = "D-Link DWL-g650 A1"; + break; + case 0xd019UL: + modelp = "WN-G54/CB"; + break; + case 0x4800UL: + modelp = "Netgear WG511"; + break; + case 0x2802UL: + modelp = "SMC2802W"; + break; + case 0xee03UL: + modelp = "SMC2802W V2"; + break; + case 0x2835UL: + modelp = "SMC2835W"; + break; + /* Let's leave this one out for now since it seems bogus/wrong + * Even if the manufacturer did use 0x0000UL it may not be correct + * by their part, therefore deserving no name ;) */ + /* case 0x0000UL: + * modelp = "SparkLAN WL-850F"; + * break;*/ + + /* We have two reported for the one below :( */ + case 0x0014UL: + modelp = "XG-600"; + break; + case 0x0020UL: + modelp = "XG-900/GW-DS54G"; + break; +/* Default it */ +/* + case PCIDEVICE_ISL3890: + modelp = "PRISM Duette/GT"; + break; +*/ + default: + modelp = "PRISM Duette/GT"; + } + printk(KERN_DEBUG "%s: %s driver detected card model: %s\n", + ndev->name, DRV_NAME, modelp); + return; +} + +/****************************************************************************** + Module initialization functions +******************************************************************************/ + +int +prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct net_device *ndev; + u8 latency_tmr; + u32 mem_addr; + islpci_private *priv; + int rvalue; + + /* TRACE(DRV_NAME); */ + + + /* Enable the pci device */ + if (pci_enable_device(pdev)) { + printk(KERN_ERR "%s: pci_enable_device() failed.\n", DRV_NAME); + return -ENODEV; + } + + /* check whether the latency timer is set correctly */ + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency_tmr); +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, "latency timer: %x\n", latency_tmr); +#endif + if (latency_tmr < PCIDEVICE_LATENCY_TIMER_MIN) { + /* set the latency timer */ + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, + PCIDEVICE_LATENCY_TIMER_VAL); + } + + /* enable PCI DMA */ + if (pci_set_dma_mask(pdev, 0xffffffff)) { + printk(KERN_ERR "%s: 32-bit PCI DMA not supported", DRV_NAME); + goto do_pci_disable_device; + } + + /* 0x40 is the programmable timer to configure the response timeout (TRDY_TIMEOUT) + * 0x41 is the programmable timer to configure the retry timeout (RETRY_TIMEOUT) + * The RETRY_TIMEOUT is used to set the number of retries that the core, as a + * Master, will perform before abandoning a cycle. The default value for + * RETRY_TIMEOUT is 0x80, which far exceeds the PCI 2.1 requirement for new + * devices. A write of zero to the RETRY_TIMEOUT register disables this + * function to allow use with any non-compliant legacy devices that may + * execute more retries. + * + * Writing zero to both these two registers will disable both timeouts and + * *can* solve problems caused by devices that are slow to respond. + */ + pci_write_config_byte(pdev, 0x40, 0); + pci_write_config_byte(pdev, 0x41, 0); + + /* request the pci device I/O regions */ + rvalue = pci_request_regions(pdev, DRV_NAME); + if (rvalue) { + printk(KERN_ERR "%s: pci_request_regions failure (rc=%d)\n", + DRV_NAME, rvalue); + goto do_pci_disable_device; + } + + /* check if the memory window is indeed set */ + rvalue = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &mem_addr); + if (rvalue || !mem_addr) { + printk(KERN_ERR "%s: PCI device memory region not configured; fix your BIOS or CardBus bridge/drivers\n", + DRV_NAME); + goto do_pci_disable_device; + } + + /* enable PCI bus-mastering */ + DEBUG(SHOW_TRACING, "%s: pci_set_master(pdev)\n", DRV_NAME); + pci_set_master(pdev); + + /* setup the network device interface and its structure */ + if (!(ndev = islpci_setup(pdev))) { + /* error configuring the driver as a network device */ + printk(KERN_ERR "%s: could not configure network device\n", + DRV_NAME); + goto do_pci_release_regions; + } + + priv = ndev->priv; + islpci_set_state(priv, PRV_STATE_PREBOOT); /* we are attempting to boot */ + + /* card is in unknown state yet, might have some interrupts pending */ + isl38xx_disable_interrupts(priv->device_base); + + /* request for the interrupt before uploading the firmware */ + rvalue = request_irq(pdev->irq, &islpci_interrupt, + SA_SHIRQ, ndev->name, priv); + + if (rvalue) { + /* error, could not hook the handler to the irq */ + printk(KERN_ERR "%s: could not install IRQ handler\n", + ndev->name); + goto do_unregister_netdev; + } + + /* firmware upload is triggered in islpci_open */ + + /* Pretty card model discovery output */ + prism54_get_card_model(ndev); + + return 0; + + do_unregister_netdev: + unregister_netdev(ndev); + islpci_free_memory(priv); + pci_set_drvdata(pdev, 0); + free_netdev(ndev); + priv = 0; + do_pci_release_regions: + pci_release_regions(pdev); + do_pci_disable_device: + pci_disable_device(pdev); + return -EIO; +} + +/* set by cleanup_module */ +static volatile int __in_cleanup_module = 0; + +/* this one removes one(!!) instance only */ +void +prism54_remove(struct pci_dev *pdev) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + islpci_private *priv = ndev ? ndev->priv : 0; + BUG_ON(!priv); + + if (!__in_cleanup_module) { + printk(KERN_DEBUG "%s: hot unplug detected\n", ndev->name); + islpci_set_state(priv, PRV_STATE_OFF); + } + + printk(KERN_DEBUG "%s: removing device\n", ndev->name); + + unregister_netdev(ndev); + + /* free the interrupt request */ + + if (islpci_get_state(priv) != PRV_STATE_OFF) { + isl38xx_disable_interrupts(priv->device_base); + islpci_set_state(priv, PRV_STATE_OFF); + /* This bellow causes a lockup at rmmod time. It might be + * because some interrupts still linger after rmmod time, + * see bug #17 */ + /* pci_set_power_state(pdev, 3);*/ /* try to power-off */ + } + + free_irq(pdev->irq, priv); + + /* free the PCI memory and unmap the remapped page */ + islpci_free_memory(priv); + + pci_set_drvdata(pdev, 0); + free_netdev(ndev); + priv = 0; + + pci_release_regions(pdev); + + pci_disable_device(pdev); +} + +int +prism54_suspend(struct pci_dev *pdev, u32 state) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + islpci_private *priv = ndev ? ndev->priv : 0; + BUG_ON(!priv); + + printk(KERN_NOTICE "%s: got suspend request (state %d)\n", + ndev->name, state); + + pci_save_state(pdev, priv->pci_state); + + /* tell the device not to trigger interrupts for now... */ + isl38xx_disable_interrupts(priv->device_base); + + /* from now on assume the hardware was already powered down + and don't touch it anymore */ + islpci_set_state(priv, PRV_STATE_OFF); + + netif_stop_queue(ndev); + netif_device_detach(ndev); + + return 0; +} + +int +prism54_resume(struct pci_dev *pdev) +{ + struct net_device *ndev = pci_get_drvdata(pdev); + islpci_private *priv = ndev ? ndev->priv : 0; + BUG_ON(!priv); + + printk(KERN_NOTICE "%s: got resume request\n", ndev->name); + + pci_restore_state(pdev, priv->pci_state); + + /* alright let's go into the PREBOOT state */ + islpci_reset(priv, 1); + + netif_device_attach(ndev); + netif_start_queue(ndev); + + return 0; +} + +static int __init +prism54_module_init(void) +{ + printk(KERN_INFO "Loaded %s driver, version %s\n", + DRV_NAME, DRV_VERSION); + + __bug_on_wrong_struct_sizes (); + + return pci_module_init(&prism54_driver); +} + +/* by the time prism54_module_exit() terminates, as a postcondition + * all instances will have been destroyed by calls to + * prism54_remove() */ +static void __exit +prism54_module_exit(void) +{ + __in_cleanup_module = 1; + + pci_unregister_driver(&prism54_driver); + + printk(KERN_INFO "Unloaded %s driver\n", DRV_NAME); + + __in_cleanup_module = 0; +} + +/* register entry points */ +module_init(prism54_module_init); +module_exit(prism54_module_exit); +/* EOF */ diff -Nru a/drivers/net/wireless/prism54/islpci_mgt.c b/drivers/net/wireless/prism54/islpci_mgt.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/islpci_mgt.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,510 @@ +/* $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_mgt.c,v 1.40 2004/02/01 10:57:23 mcgrof Exp $ + * + * Copyright (C) 2002 Intersil Americas Inc. + * Copyright 2004 Jens Maurer + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include "isl_38xx.h" +#include "islpci_mgt.h" +#include "isl_oid.h" /* additional types and defs for isl38xx fw */ +#include "isl_ioctl.h" + +#include + +/****************************************************************************** + Global variable definition section +******************************************************************************/ +int pc_debug = VERBOSE; +MODULE_PARM(pc_debug, "i"); + +/****************************************************************************** + Driver general functions +******************************************************************************/ +void +display_buffer(char *buffer, int length) +{ + if ((pc_debug & SHOW_BUFFER_CONTENTS) == 0) + return; + + while (length > 0) { + printk("[%02x]", *buffer & 255); + length--; + buffer++; + } + + printk("\n"); +} + +/***************************************************************************** + Queue handling for management frames +******************************************************************************/ + + +/* + * Helper function to create a PIMFOR management frame header. + */ +static void +pimfor_encode_header(int operation, u32 oid, u32 length, pimfor_header_t *h) +{ + h->version = PIMFOR_VERSION; + h->operation = operation; + h->device_id = PIMFOR_DEV_ID_MHLI_MIB; + h->flags = 0; + h->oid = cpu_to_be32(oid); + h->length = cpu_to_be32(length); +} + +/* + * Helper function to analyze a PIMFOR management frame header. + */ +static pimfor_header_t * +pimfor_decode_header(void *data, int len) +{ + pimfor_header_t *h = data; + + while ((void *) h < data + len) { + if(h->flags & PIMFOR_FLAG_LITTLE_ENDIAN) { + le32_to_cpus(&h->oid); + le32_to_cpus(&h->length); + } else { + be32_to_cpus(&h->oid); + be32_to_cpus(&h->length); + } + if (h->oid != OID_INL_TUNNEL) + return h; + h++; + } + return NULL; +} + +/* + * Fill the receive queue for management frames with fresh buffers. + */ +int +islpci_mgmt_rx_fill(struct net_device *ndev) +{ + islpci_private *priv = ndev->priv; + isl38xx_control_block *cb = /* volatile not needed */ + (isl38xx_control_block *) priv->control_block; + u32 curr = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_RX_MGMTQ]); + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgmt_rx_fill \n"); +#endif + + while (curr - priv->index_mgmt_rx < ISL38XX_CB_MGMT_QSIZE) { + u32 index = curr % ISL38XX_CB_MGMT_QSIZE; + struct islpci_membuf *buf = &priv->mgmt_rx[index]; + isl38xx_fragment *frag = &cb->rx_data_mgmt[index]; + + if (buf->mem == NULL) { + buf->mem = kmalloc(MGMT_FRAME_SIZE, GFP_ATOMIC); + if (!buf->mem) { + printk(KERN_WARNING "Error allocating management frame.\n"); + return -ENOMEM; + } + buf->size = MGMT_FRAME_SIZE; + } + if (buf->pci_addr == 0) { + buf->pci_addr = pci_map_single(priv->pdev, buf->mem, + MGMT_FRAME_SIZE, + PCI_DMA_FROMDEVICE); + if(!buf->pci_addr) { + printk(KERN_WARNING "Failed to make memory DMA'able\n."); + return -ENOMEM; + } + } + + /* be safe: always reset control block information */ + frag->size = cpu_to_le16(MGMT_FRAME_SIZE); + frag->flags = 0; + frag->address = cpu_to_le32(buf->pci_addr); + curr++; + + /* The fragment address in the control block must have + * been written before announcing the frame buffer to + * device */ + wmb(); + cb->driver_curr_frag[ISL38XX_CB_RX_MGMTQ] = + cpu_to_le32(curr); + } + return 0; +} + +/* + * Create and transmit a management frame using "operation" and "oid", + * with arguments data/length. + * We either return an error and free the frame, or we return 0 and + * islpci_mgt_cleanup_transmit() frees the frame in the tx-done + * interrupt. + */ +static int +islpci_mgt_transmit(struct net_device *ndev, int operation, unsigned long oid, + void *data, int length) +{ + islpci_private *priv = ndev->priv; + isl38xx_control_block *cb = + (isl38xx_control_block *) priv->control_block; + void *p; + int err = -EINVAL; + unsigned long flags; + isl38xx_fragment *frag; + struct islpci_membuf buf; + u32 curr_frag; + int index; + int frag_len = length + PIMFOR_HEADER_SIZE; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_transmit\n"); +#endif + + if (frag_len > MGMT_FRAME_SIZE) { + printk(KERN_DEBUG "%s: mgmt frame too large %d\n", + ndev->name, frag_len); + goto error; + } + + err = -ENOMEM; + p = buf.mem = kmalloc(frag_len, GFP_KERNEL); + if (!buf.mem) { + printk(KERN_DEBUG "%s: cannot allocate mgmt frame\n", + ndev->name); + goto error; + } + buf.size = frag_len; + + /* create the header directly in the fragment data area */ + pimfor_encode_header(operation, oid, length, (pimfor_header_t *) p); + p += PIMFOR_HEADER_SIZE; + + if (data) + memcpy(p, data, length); + else + memset(p, 0, length); + +#if VERBOSE > SHOW_ERROR_MESSAGES + { + pimfor_header_t *h = buf.mem; + DEBUG(SHOW_PIMFOR_FRAMES, + "PIMFOR: op %i, oid 0x%08lx, device %i, flags 0x%x length 0x%x \n", + h->operation, oid, h->device_id, h->flags, length); + + /* display the buffer contents for debugging */ + display_buffer((char *) h, sizeof (pimfor_header_t)); + display_buffer(p, length); + } +#endif + + err = -ENOMEM; + buf.pci_addr = pci_map_single(priv->pdev, buf.mem, frag_len, + PCI_DMA_TODEVICE); + if (!buf.pci_addr) { + printk(KERN_WARNING "%s: cannot map PCI memory for mgmt\n", + ndev->name); + goto error_free; + } + + /* Protect the control block modifications against interrupts. */ + spin_lock_irqsave(&priv->slock, flags); + curr_frag = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_TX_MGMTQ]); + if (curr_frag - priv->index_mgmt_tx >= ISL38XX_CB_MGMT_QSIZE) { + printk(KERN_WARNING "%s: mgmt tx queue is still full\n", + ndev->name); + goto error_unlock; + } + + /* commit the frame to the tx device queue */ + index = curr_frag % ISL38XX_CB_MGMT_QSIZE; + priv->mgmt_tx[index] = buf; + frag = &cb->tx_data_mgmt[index]; + frag->size = cpu_to_le16(frag_len); + frag->flags = 0; /* for any other than the last fragment, set to 1 */ + frag->address = cpu_to_le32(buf.pci_addr); + + /* The fragment address in the control block must have + * been written before announcing the frame buffer to + * device */ + wmb(); + cb->driver_curr_frag[ISL38XX_CB_TX_MGMTQ] = cpu_to_le32(curr_frag+1); + spin_unlock_irqrestore(&priv->slock, flags); + + /* trigger the device */ + islpci_trigger(priv); + return 0; + + error_unlock: + spin_unlock_irqrestore(&priv->slock, flags); + error_free: + kfree(buf.mem); + error: + return err; +} + +/* + * Receive a management frame from the device. + * This can be an arbitrary number of traps, and at most one response + * frame for a previous request sent via islpci_mgt_transmit(). + */ +int +islpci_mgt_receive(struct net_device *ndev) +{ + islpci_private *priv = ndev->priv; + isl38xx_control_block *cb = + (isl38xx_control_block *) priv->control_block; + u32 curr_frag; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_receive \n"); +#endif + + + /* Only once per interrupt, determine fragment range to + * process. This avoids an endless loop (i.e. lockup) if + * frames come in faster than we can process them. */ + curr_frag = le32_to_cpu(cb->device_curr_frag[ISL38XX_CB_RX_MGMTQ]); + barrier(); + + for ( ; priv->index_mgmt_rx < curr_frag; priv->index_mgmt_rx++) { + pimfor_header_t *header; + u32 index = priv->index_mgmt_rx % ISL38XX_CB_MGMT_QSIZE; + struct islpci_membuf *buf = &priv->mgmt_rx[index]; + u16 frag_len; + int size; + struct islpci_mgmtframe *frame; + + /* I have no idea (and no documentation) if flags != 0 + * is possible. Drop the frame, reuse the buffer. */ + if(le16_to_cpu(cb->rx_data_mgmt[index].flags) != 0) { + printk(KERN_WARNING "%s: unknown flags 0x%04x\n", + ndev->name, + le16_to_cpu(cb->rx_data_mgmt[index].flags)); + continue; + } + + /* The device only returns the size of the header(s) here. */ + frag_len = le16_to_cpu(cb->rx_data_mgmt[index].size); + + /* + * We appear to have no way to tell the device the + * size of a receive buffer. Thus, if this check + * triggers, we likely have kernel heap corruption. */ + if (frag_len > MGMT_FRAME_SIZE) { + printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\ +n", + ndev->name, frag_len, frag_len); + frag_len = MGMT_FRAME_SIZE; + } + + /* Ensure the results of device DMA are visible to the CPU. */ + pci_dma_sync_single(priv->pdev, buf->pci_addr, + buf->size, PCI_DMA_FROMDEVICE); + + /* Perform endianess conversion for PIMFOR header in-place. */ + header = pimfor_decode_header(buf->mem, frag_len); + if (!header) { + printk(KERN_WARNING "%s: no PIMFOR header found\n", + ndev->name); + continue; + } + + /* The device ID from the PIMFOR packet received from + * the MVC is always 0. We forward a sensible device_id. + * Not that anyone upstream would care... */ + header->device_id = priv->ndev->ifindex; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_PIMFOR_FRAMES, + "PIMFOR: op %i, oid 0x%08x, device %i, flags 0x%x length 0x%x \n", + header->operation, header->oid, header->device_id, + header->flags, header->length); + + /* display the buffer contents for debugging */ + display_buffer((char *) header, PIMFOR_HEADER_SIZE); + display_buffer((char *) header + PIMFOR_HEADER_SIZE, header->length); +#endif + + /* nobody sends these */ + if (header->flags & PIMFOR_FLAG_APPLIC_ORIGIN) { + printk(KERN_DEBUG "%s: errant PIMFOR application frame\n", + ndev->name); + continue; + } + + /* Determine frame size, skipping OID_INL_TUNNEL headers. */ + size = PIMFOR_HEADER_SIZE + header->length; + frame = kmalloc(sizeof(struct islpci_mgmtframe) + size, + GFP_ATOMIC); + if (!frame) { + printk(KERN_WARNING "%s: Out of memory, cannot handle oid 0x%08x\n", + + ndev->name, header->oid); + continue; + } + frame->ndev = ndev; + memcpy(&frame->buf, header, size); + frame->header = (pimfor_header_t *) frame->buf; + frame->data = frame->buf + PIMFOR_HEADER_SIZE; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_PIMFOR_FRAMES, + "frame: header: %p, data: %p, size: %d\n", + frame->header, frame->data, size); +#endif + + if (header->operation == PIMFOR_OP_TRAP) { +#if VERBOSE > SHOW_ERROR_MESSAGES + printk(KERN_DEBUG + "TRAP: oid 0x%x, device %i, flags 0x%x length %i\n", + header->oid, header->device_id, header->flags, + header->length); +#endif + + /* Create work to handle trap out of interrupt + * context. */ + INIT_WORK(&frame->ws, prism54_process_trap, frame); + schedule_work(&frame->ws); + + } else { + /* Signal the one waiting process that a response + * has been received. */ + if ((frame = xchg(&priv->mgmt_received, frame)) != NULL) { + printk(KERN_WARNING "%s: mgmt response not collected\n", + ndev->name); + kfree(frame); + } + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_TRACING, + "Wake up Mgmt Queue\n"); +#endif + wake_up(&priv->mgmt_wqueue); + } + + } + + return 0; +} + +/* + * Cleanup the transmit queue by freeing all frames handled by the device. + */ +void +islpci_mgt_cleanup_transmit(struct net_device *ndev) +{ + islpci_private *priv = ndev->priv; + isl38xx_control_block *cb = /* volatile not needed */ + (isl38xx_control_block *) priv->control_block; + u32 curr_frag; + +#if VERBOSE > SHOW_ERROR_MESSAGES + DEBUG(SHOW_FUNCTION_CALLS, "islpci_mgt_cleanup_transmit\n"); +#endif + + /* Only once per cleanup, determine fragment range to + * process. This avoids an endless loop (i.e. lockup) if + * the device became confused, incrementing device_curr_frag + * rapidly. */ + curr_frag = le32_to_cpu(cb->device_curr_frag[ISL38XX_CB_TX_MGMTQ]); + barrier(); + + for ( ; priv->index_mgmt_tx < curr_frag; priv->index_mgmt_tx++) { + int index = priv->index_mgmt_tx % ISL38XX_CB_MGMT_QSIZE; + struct islpci_membuf *buf = &priv->mgmt_tx[index]; + pci_unmap_single(priv->pdev, buf->pci_addr, buf->size, + PCI_DMA_TODEVICE); + buf->pci_addr = 0; + kfree(buf->mem); + buf->mem = NULL; + buf->size = 0; + } +} + +/* + * Perform one request-response transaction to the device. + */ +int +islpci_mgt_transaction(struct net_device *ndev, + int operation, unsigned long oid, + void *senddata, int sendlen, + struct islpci_mgmtframe **recvframe) +{ + islpci_private *priv = ndev->priv; + const long wait_cycle_jiffies = (ISL38XX_WAIT_CYCLE * 10 * HZ) / 1000; + long timeout_left = ISL38XX_MAX_WAIT_CYCLES * wait_cycle_jiffies; + int err; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + DEFINE_WAIT(wait); +#else + DECLARE_WAITQUEUE(wait, current); +#endif + + if (down_interruptible(&priv->mgmt_sem)) + return -ERESTARTSYS; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + prepare_to_wait(&priv->mgmt_wqueue, &wait, TASK_UNINTERRUPTIBLE); +#else + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&priv->mgmt_wqueue, &wait); +#endif + err = islpci_mgt_transmit(ndev, operation, oid, senddata, sendlen); + if(err) + goto out; + + err = -ETIMEDOUT; + while (timeout_left > 0) { + int timeleft; + struct islpci_mgmtframe *frame; + + timeleft = schedule_timeout(wait_cycle_jiffies); + frame = xchg(&priv->mgmt_received, NULL); + if (frame) { + *recvframe = frame; + err = 0; + goto out; + } + if(timeleft == 0) { + printk(KERN_DEBUG "%s: timeout waiting for mgmt response %lu, trigging device\n", + ndev->name, timeout_left); + islpci_trigger(priv); + } + timeout_left += timeleft - wait_cycle_jiffies; + } + printk(KERN_WARNING "%s: timeout waiting for mgmt response\n", + ndev->name); + + /* TODO: we should reset the device here */ + out: +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) + finish_wait(&priv->mgmt_wqueue, &wait); +#else + remove_wait_queue(&priv->mgmt_wqueue, &wait); + set_current_state(TASK_RUNNING); +#endif + up(&priv->mgmt_sem); + return err; +} + diff -Nru a/drivers/net/wireless/prism54/islpci_mgt.h b/drivers/net/wireless/prism54/islpci_mgt.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/islpci_mgt.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,166 @@ +/* $Header: /var/lib/cvs/prism54-ng/ksrc/islpci_mgt.h,v 1.22 2004/01/30 16:24:00 ajfa Exp $ + * + * Copyright (C) 2002 Intersil Americas Inc. + * Copyright (C) 2003 Luis R. Rodriguez + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _ISLPCI_MGT_H +#define _ISLPCI_MGT_H + +#include +#include + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41) +# include +#else +# include +# define work_struct tq_struct +# define INIT_WORK INIT_TQUEUE +# define schedule_work schedule_task +#endif + +/* + * Function definitions + */ + +#define K_DEBUG(f, m, args...) do { if(f & m) printk(KERN_DEBUG args); } while(0) +#define DEBUG(f, args...) K_DEBUG(f, pc_debug, args) + +#define TRACE(devname) K_DEBUG(SHOW_TRACING, VERBOSE, "%s: -> " __FUNCTION__ "()\n", devname) + +extern int pc_debug; +static const int init_wds = 0; /* help compiler optimize away dead code */ + + +/* General driver definitions */ +#define PCIVENDOR_INTERSIL 0x1260UL +#define PCIVENDOR_3COM 0x10b7UL +#define PCIVENDOR_DLINK 0x1186UL +#define PCIVENDOR_I4 0x17cfUL +#define PCIVENDOR_IODATA 0x10fcUL +#define PCIVENDOR_NETGEAR 0x1385UL +#define PCIVENDOR_SMC 0x10b8UL +#define PCIVENDOR_ACCTON 0x1113UL + +#define PCIDEVICE_ISL3877 0x3877UL +#define PCIDEVICE_ISL3890 0x3890UL +#define PCIDEVICE_3COM6001 0x6001UL +#define PCIDEVICE_LATENCY_TIMER_MIN 0x40 +#define PCIDEVICE_LATENCY_TIMER_VAL 0x50 + +/* Debugging verbose definitions */ +#define SHOW_NOTHING 0x00 /* overrules everything */ +#define SHOW_ANYTHING 0xFF +#define SHOW_ERROR_MESSAGES 0x01 +#define SHOW_TRAPS 0x02 +#define SHOW_FUNCTION_CALLS 0x04 +#define SHOW_TRACING 0x08 +#define SHOW_QUEUE_INDEXES 0x10 +#define SHOW_PIMFOR_FRAMES 0x20 +#define SHOW_BUFFER_CONTENTS 0x40 +#define VERBOSE 0x01 + +/* Default card definitions */ +#define CARD_DEFAULT_CHANNEL 6 +#define CARD_DEFAULT_MODE INL_MODE_CLIENT +#define CARD_DEFAULT_IW_MODE IW_MODE_INFRA +#define CARD_DEFAULT_BSSTYPE DOT11_BSSTYPE_INFRA +#define CARD_DEFAULT_CLIENT_SSID "" +#define CARD_DEFAULT_AP_SSID "default" +#define CARD_DEFAULT_KEY1 "default_key_1" +#define CARD_DEFAULT_KEY2 "default_key_2" +#define CARD_DEFAULT_KEY3 "default_key_3" +#define CARD_DEFAULT_KEY4 "default_key_4" +#define CARD_DEFAULT_WEP 0 +#define CARD_DEFAULT_FILTER 0 +# define CARD_DEFAULT_WDS 0 +#define CARD_DEFAULT_AUTHEN DOT11_AUTH_OS +#define CARD_DEFAULT_DOT1X 0 +#define CARD_DEFAULT_MLME_MODE DOT11_MLME_AUTO +#define CARD_DEFAULT_CONFORMANCE OID_INL_CONFORMANCE_NONE + +/* PIMFOR package definitions */ +#define PIMFOR_ETHERTYPE 0x8828 +#define PIMFOR_HEADER_SIZE 12 +#define PIMFOR_VERSION 1 +#define PIMFOR_OP_GET 0 +#define PIMFOR_OP_SET 1 +#define PIMFOR_OP_RESPONSE 2 +#define PIMFOR_OP_ERROR 3 +#define PIMFOR_OP_TRAP 4 +#define PIMFOR_OP_RESERVED 5 /* till 255 */ +#define PIMFOR_DEV_ID_MHLI_MIB 0 +#define PIMFOR_FLAG_APPLIC_ORIGIN 0x01 +#define PIMFOR_FLAG_LITTLE_ENDIAN 0x02 + +static inline void +add_le32p(u32 * le_number, u32 add) +{ + *le_number = cpu_to_le32(le32_to_cpup(le_number) + add); +} + +void display_buffer(char *, int); + +/* + * Type definition section + * + * the structure defines only the header allowing copyless + * frame handling + */ +typedef struct { + u8 version; + u8 operation; + u32 oid; + u8 device_id; + u8 flags; + u32 length; +} __attribute__ ((packed)) +pimfor_header_t; + +/* A received and interrupt-processed management frame, either for + * schedule_work(prism54_process_trap) or for priv->mgmt_received, + * processed by islpci_mgt_transaction(). */ +struct islpci_mgmtframe { + struct net_device *ndev; /* pointer to network device */ + pimfor_header_t *header; /* payload header, points into buf */ + void *data; /* payload ex header, points into buf */ + struct work_struct ws; /* argument for schedule_work() */ + char buf[0]; /* fragment buffer */ +}; + +int +islpci_mgt_receive(struct net_device *ndev); + +int +islpci_mgmt_rx_fill(struct net_device *ndev); + +void +islpci_mgt_cleanup_transmit(struct net_device *ndev); + +int +islpci_mgt_transaction(struct net_device *ndev, + int operation, unsigned long oid, + void *senddata, int sendlen, + struct islpci_mgmtframe **recvframe); + +static inline void +islpci_mgt_release(struct islpci_mgmtframe *frame) +{ + kfree(frame); +} + +#endif /* _ISLPCI_MGT_H */ diff -Nru a/drivers/net/wireless/prism54/oid_mgt.c b/drivers/net/wireless/prism54/oid_mgt.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/oid_mgt.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,532 @@ +/* + * Copyright (C) 2003 Aurelien Alleaume + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "islpci_dev.h" +#include "islpci_mgt.h" +#include "isl_oid.h" +#include "oid_mgt.h" +#include "isl_ioctl.h" + +/* to convert between channel and freq */ +const int frequency_list_bg[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 +}; + +const int frequency_list_a[] = { 5170, 5180, 5190, 5200, 5210, 5220, 5230, + 5240, 5260, 5280, 5300, 5320 +}; + +#define OID_U32(x) {x, 0, sizeof(u32), OID_FLAG_U32} +#define OID_U32_C(x) {x, 0, sizeof(u32), OID_FLAG_U32 | OID_FLAG_CACHED} +#define OID_STRUCT(x,s) {x, 0, sizeof(s), 0} +#define OID_STRUCT_C(x,s) {x, 0, sizeof(s), OID_FLAG_CACHED} +#define OID_STRUCT_MLME(x){x, 0, sizeof(struct obj_mlme), 0} +#define OID_STRUCT_MLMEEX(x){x, 0, sizeof(struct obj_mlmeex), OID_FLAG_MLMEEX} + +#define OID_UNKNOWN(x) {x, 0, 0, 0} + +struct oid_t isl_oid[] = { + [GEN_OID_MACADDRESS] = OID_STRUCT(0x00000000, u8[6]), + [GEN_OID_LINKSTATE] = OID_U32(0x00000001), + [GEN_OID_WATCHDOG] = OID_UNKNOWN(0x00000002), + [GEN_OID_MIBOP] = OID_UNKNOWN(0x00000003), + [GEN_OID_OPTIONS] = OID_UNKNOWN(0x00000004), + [GEN_OID_LEDCONFIG] = OID_UNKNOWN(0x00000005), + + /* 802.11 */ + [DOT11_OID_BSSTYPE] = OID_U32_C(0x10000000), + [DOT11_OID_BSSID] = OID_STRUCT_C(0x10000001, u8[6]), + [DOT11_OID_SSID] = OID_STRUCT_C(0x10000002, struct obj_ssid), + [DOT11_OID_STATE] = OID_U32(0x10000003), + [DOT11_OID_AID] = OID_U32(0x10000004), + [DOT11_OID_COUNTRYSTRING] = OID_STRUCT(0x10000005, u8[4]), + [DOT11_OID_SSIDOVERRIDE] = OID_STRUCT_C(0x10000006, struct obj_ssid), + + [DOT11_OID_MEDIUMLIMIT] = OID_U32(0x11000000), + [DOT11_OID_BEACONPERIOD] = OID_U32_C(0x11000001), + [DOT11_OID_DTIMPERIOD] = OID_U32(0x11000002), + [DOT11_OID_ATIMWINDOW] = OID_U32(0x11000003), + [DOT11_OID_LISTENINTERVAL] = OID_U32(0x11000004), + [DOT11_OID_CFPPERIOD] = OID_U32(0x11000005), + [DOT11_OID_CFPDURATION] = OID_U32(0x11000006), + + [DOT11_OID_AUTHENABLE] = OID_U32_C(0x12000000), + [DOT11_OID_PRIVACYINVOKED] = OID_U32_C(0x12000001), + [DOT11_OID_EXUNENCRYPTED] = OID_U32_C(0x12000002), + [DOT11_OID_DEFKEYID] = OID_U32_C(0x12000003), + [DOT11_OID_DEFKEYX] = {0x12000004, 3, sizeof (struct obj_key), OID_FLAG_CACHED}, /* DOT11_OID_DEFKEY1,...DOT11_OID_DEFKEY4 */ + [DOT11_OID_STAKEY] = OID_UNKNOWN(0x12000008), + [DOT11_OID_REKEYTHRESHOLD] = OID_U32(0x12000009), + [DOT11_OID_STASC] = OID_UNKNOWN(0x1200000a), + + [DOT11_OID_PRIVTXREJECTED] = OID_U32(0x1a000000), + [DOT11_OID_PRIVRXPLAIN] = OID_U32(0x1a000001), + [DOT11_OID_PRIVRXFAILED] = OID_U32(0x1a000002), + [DOT11_OID_PRIVRXNOKEY] = OID_U32(0x1a000003), + + [DOT11_OID_RTSTHRESH] = OID_U32_C(0x13000000), + [DOT11_OID_FRAGTHRESH] = OID_U32_C(0x13000001), + [DOT11_OID_SHORTRETRIES] = OID_U32_C(0x13000002), + [DOT11_OID_LONGRETRIES] = OID_U32_C(0x13000003), + [DOT11_OID_MAXTXLIFETIME] = OID_U32_C(0x13000004), + [DOT11_OID_MAXRXLIFETIME] = OID_U32(0x13000005), + [DOT11_OID_AUTHRESPTIMEOUT] = OID_U32(0x13000006), + [DOT11_OID_ASSOCRESPTIMEOUT] = OID_U32(0x13000007), + + [DOT11_OID_ALOFT_TABLE] = OID_UNKNOWN(0x1d000000), + [DOT11_OID_ALOFT_CTRL_TABLE] = OID_UNKNOWN(0x1d000001), + [DOT11_OID_ALOFT_RETREAT] = OID_UNKNOWN(0x1d000002), + [DOT11_OID_ALOFT_PROGRESS] = OID_UNKNOWN(0x1d000003), + [DOT11_OID_ALOFT_FIXEDRATE] = OID_U32(0x1d000004), + [DOT11_OID_ALOFT_RSSIGRAPH] = OID_UNKNOWN(0x1d000005), + [DOT11_OID_ALOFT_CONFIG] = OID_UNKNOWN(0x1d000006), + + [DOT11_OID_VDCFX] = {0x1b000000, 7, 0, 0}, + [DOT11_OID_MAXFRAMEBURST] = OID_U32(0x1b000008), + + [DOT11_OID_PSM] = OID_U32(0x14000000), + [DOT11_OID_CAMTIMEOUT] = OID_U32(0x14000001), + [DOT11_OID_RECEIVEDTIMS] = OID_U32(0x14000002), + [DOT11_OID_ROAMPREFERENCE] = OID_U32(0x14000003), + + [DOT11_OID_BRIDGELOCAL] = OID_U32(0x15000000), + [DOT11_OID_CLIENTS] = OID_U32(0x15000001), + [DOT11_OID_CLIENTSASSOCIATED] = OID_U32(0x15000002), + [DOT11_OID_CLIENTX] = {0x15000003, 2006, 0, 0}, /* DOT11_OID_CLIENTX,...DOT11_OID_CLIENT2007 */ + + [DOT11_OID_CLIENTFIND] = OID_STRUCT(0x150007DB, u8[6]), + [DOT11_OID_WDSLINKADD] = OID_STRUCT(0x150007DC, u8[6]), + [DOT11_OID_WDSLINKREMOVE] = OID_STRUCT(0x150007DD, u8[6]), + [DOT11_OID_EAPAUTHSTA] = OID_STRUCT(0x150007DE, u8[6]), + [DOT11_OID_EAPUNAUTHSTA] = OID_STRUCT(0x150007DF, u8[6]), + [DOT11_OID_DOT1XENABLE] = OID_U32_C(0x150007E0), + [DOT11_OID_MICFAILURE] = OID_UNKNOWN(0x150007E1), + [DOT11_OID_REKEYINDICATE] = OID_UNKNOWN(0x150007E2), + + [DOT11_OID_MPDUTXSUCCESSFUL] = OID_U32(0x16000000), + [DOT11_OID_MPDUTXONERETRY] = OID_U32(0x16000001), + [DOT11_OID_MPDUTXMULTIPLERETRIES] = OID_U32(0x16000002), + [DOT11_OID_MPDUTXFAILED] = OID_U32(0x16000003), + [DOT11_OID_MPDURXSUCCESSFUL] = OID_U32(0x16000004), + [DOT11_OID_MPDURXDUPS] = OID_U32(0x16000005), + [DOT11_OID_RTSSUCCESSFUL] = OID_U32(0x16000006), + [DOT11_OID_RTSFAILED] = OID_U32(0x16000007), + [DOT11_OID_ACKFAILED] = OID_U32(0x16000008), + [DOT11_OID_FRAMERECEIVES] = OID_U32(0x16000009), + [DOT11_OID_FRAMEERRORS] = OID_U32(0x1600000A), + [DOT11_OID_FRAMEABORTS] = OID_U32(0x1600000B), + [DOT11_OID_FRAMEABORTSPHY] = OID_U32(0x1600000C), + + [DOT11_OID_SLOTTIME] = OID_U32(0x17000000), + [DOT11_OID_CWMIN] = OID_U32(0x17000001), + [DOT11_OID_CWMAX] = OID_U32(0x17000002), + [DOT11_OID_ACKWINDOW] = OID_U32(0x17000003), + [DOT11_OID_ANTENNARX] = OID_U32(0x17000004), + [DOT11_OID_ANTENNATX] = OID_U32(0x17000005), + [DOT11_OID_ANTENNADIVERSITY] = OID_U32(0x17000006), + [DOT11_OID_CHANNEL] = OID_U32_C(0x17000007), + [DOT11_OID_EDTHRESHOLD] = OID_U32_C(0x17000008), + [DOT11_OID_PREAMBLESETTINGS] = OID_U32(0x17000009), + [DOT11_OID_RATES] = OID_STRUCT(0x1700000A, u8[IWMAX_BITRATES + 1]), + [DOT11_OID_CCAMODESUPPORTED] = OID_U32(0x1700000B), + [DOT11_OID_CCAMODE] = OID_U32(0x1700000C), + [DOT11_OID_RSSIVECTOR] = OID_U32(0x1700000D), + [DOT11_OID_OUTPUTPOWERTABLE] = OID_U32(0x1700000E), + [DOT11_OID_OUTPUTPOWER] = OID_U32_C(0x1700000F), + [DOT11_OID_SUPPORTEDRATES] = + OID_STRUCT(0x17000010, u8[IWMAX_BITRATES + 1]), + [DOT11_OID_FREQUENCY] = OID_U32_C(0x17000011), + [DOT11_OID_SUPPORTEDFREQUENCIES] = {0x17000012, 0, sizeof (struct + obj_frequencies) + + sizeof (u16) * IWMAX_FREQ, 0}, + + [DOT11_OID_NOISEFLOOR] = OID_U32(0x17000013), + [DOT11_OID_FREQUENCYACTIVITY] = + OID_STRUCT(0x17000014, u8[IWMAX_FREQ + 1]), + [DOT11_OID_IQCALIBRATIONTABLE] = OID_UNKNOWN(0x17000015), + [DOT11_OID_NONERPPROTECTION] = OID_U32(0x17000016), + [DOT11_OID_SLOTSETTINGS] = OID_U32(0x17000017), + [DOT11_OID_NONERPTIMEOUT] = OID_U32(0x17000018), + [DOT11_OID_PROFILES] = OID_U32(0x17000019), + [DOT11_OID_EXTENDEDRATES] = + OID_STRUCT(0x17000020, u8[IWMAX_BITRATES + 1]), + + [DOT11_OID_DEAUTHENTICATE] = OID_STRUCT_MLME(0x18000000), + [DOT11_OID_AUTHENTICATE] = OID_STRUCT_MLME(0x18000001), + [DOT11_OID_DISASSOCIATE] = OID_STRUCT_MLME(0x18000002), + [DOT11_OID_ASSOCIATE] = OID_STRUCT_MLME(0x18000003), + [DOT11_OID_SCAN] = OID_UNKNOWN(0x18000004), + [DOT11_OID_BEACON] = OID_STRUCT_MLMEEX(0x18000005), + [DOT11_OID_PROBE] = OID_STRUCT_MLMEEX(0x18000006), + [DOT11_OID_DEAUTHENTICATEEX] = OID_STRUCT_MLMEEX(0x18000007), + [DOT11_OID_AUTHENTICATEEX] = OID_STRUCT_MLMEEX(0x18000008), + [DOT11_OID_DISASSOCIATEEX] = OID_STRUCT_MLMEEX(0x18000009), + [DOT11_OID_ASSOCIATEEX] = OID_STRUCT_MLMEEX(0x1800000A), + [DOT11_OID_REASSOCIATE] = OID_STRUCT_MLMEEX(0x1800000B), + [DOT11_OID_REASSOCIATEEX] = OID_STRUCT_MLMEEX(0x1800000C), + + [DOT11_OID_NONERPSTATUS] = OID_U32(0x1E000000), + + [DOT11_OID_STATIMEOUT] = OID_U32(0x19000000), + [DOT11_OID_MLMEAUTOLEVEL] = OID_U32_C(0x19000001), + [DOT11_OID_BSSTIMEOUT] = OID_U32(0x19000002), + [DOT11_OID_ATTACHMENT] = OID_UNKNOWN(0x19000003), + [DOT11_OID_PSMBUFFER] = OID_STRUCT_C(0x19000004, struct obj_buffer), + + [DOT11_OID_BSSS] = OID_U32(0x1C000000), + [DOT11_OID_BSSX] = {0x1C000001, 63, sizeof (struct obj_bss), 0}, /*DOT11_OID_BSS1,...,DOT11_OID_BSS64 */ + [DOT11_OID_BSSFIND] = OID_STRUCT(0x1C000042, struct obj_bss), + [DOT11_OID_BSSLIST] = {0x1C000043, 0, sizeof (struct + obj_bsslist) + + sizeof (struct obj_bss[IWMAX_BSS]), 0}, + + [OID_INL_TUNNEL] = OID_UNKNOWN(0xFF020000), + [OID_INL_MEMADDR] = OID_UNKNOWN(0xFF020001), + [OID_INL_MEMORY] = OID_UNKNOWN(0xFF020002), + [OID_INL_MODE] = OID_U32_C(0xFF020003), + [OID_INL_COMPONENT_NR] = OID_UNKNOWN(0xFF020004), + [OID_INL_VERSION] = OID_UNKNOWN(0xFF020005), + [OID_INL_INTERFACE_ID] = OID_UNKNOWN(0xFF020006), + [OID_INL_COMPONENT_ID] = OID_UNKNOWN(0xFF020007), + [OID_INL_CONFIG] = OID_U32_C(0xFF020008), + [OID_INL_DOT11D_CONFORMANCE] = OID_U32_C(0xFF02000C), + [OID_INL_PHYCAPABILITIES] = OID_U32(0xFF02000D), + [OID_INL_OUTPUTPOWER] = OID_U32_C(0xFF02000F), + +}; + +int +mgt_init(islpci_private *priv) +{ + int i; + + priv->mib = kmalloc(OID_NUM_LAST * sizeof (void *), GFP_KERNEL); + if (!priv->mib) + return -ENOMEM; + + memset(priv->mib, 0, OID_NUM_LAST * sizeof (void *)); + + /* Alloc the cache */ + for (i = 0; i < OID_NUM_LAST; i++) { + if (isl_oid[i].flags & OID_FLAG_CACHED) { + priv->mib[i] = kmalloc(isl_oid[i].size * + (isl_oid[i].range + 1), + GFP_KERNEL); + if (!priv->mib[i]) + return -ENOMEM; + memset(priv->mib[i], 0, + isl_oid[i].size * (isl_oid[i].range + 1)); + } else + priv->mib[i] = NULL; + } + + init_rwsem(&priv->mib_sem); + prism54_mib_init(priv); + + return 0; +} + +void +mgt_clean(islpci_private *priv) +{ + int i; + + if (!priv->mib) + return; + for (i = 0; i < OID_NUM_LAST; i++) + if (priv->mib[i]) { + kfree(priv->mib[i]); + priv->mib[i] = NULL; + } + kfree(priv->mib); + priv->mib = NULL; +} + +int +mgt_set_request(islpci_private *priv, enum oid_num_t n, int extra, void *data) +{ + int ret = 0; + struct islpci_mgmtframe *response; + int response_op = PIMFOR_OP_ERROR; + int dlen; + void *cache, *_data = data; + u32 oid, u; + + BUG_ON(OID_NUM_LAST <= n); + BUG_ON(extra > isl_oid[n].range); + + if (!priv->mib) + /* memory has been freed */ + return -1; + + dlen = isl_oid[n].size; + cache = priv->mib[n]; + cache += (cache ? extra * dlen : 0); + oid = isl_oid[n].oid + extra; + + if (data == NULL) + /* we are requested to re-set a cached value */ + _data = cache; + if ((isl_oid[n].flags & OID_FLAG_U32) && data) { + u = cpu_to_le32(*(u32 *) data); + _data = &u; + } + /* If we are going to write to the cache, we don't want anyone to read + * it -> acquire write lock. + * Else we could acquire a read lock to be sure we don't bother the + * commit process (which takes a write lock). But I'm not sure if it's + * needed. + */ + if (cache) + down_write(&priv->mib_sem); + + if (islpci_get_state(priv) >= PRV_STATE_INIT) { + ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, oid, + _data, dlen, &response); + if (!ret) { + response_op = response->header->operation; + islpci_mgt_release(response); + } + if (ret || response_op == PIMFOR_OP_ERROR) + ret = -EIO; + } else if (!cache) + ret = -EIO; + + if (cache) { + if (!ret && data) + memcpy(cache, _data, dlen); + up_write(&priv->mib_sem); + } + + return ret; +} + +int +mgt_get_request(islpci_private *priv, enum oid_num_t n, int extra, void *data, + union oid_res_t *res) +{ + + int ret = -EIO; + int reslen = 0; + struct islpci_mgmtframe *response = NULL; + + int dlen; + void *cache, *_res=NULL; + u32 oid; + + BUG_ON(OID_NUM_LAST <= n); + BUG_ON(extra > isl_oid[n].range); + + if (!priv->mib) + /* memory has been freed */ + return -1; + + dlen = isl_oid[n].size; + cache = priv->mib[n]; + cache += cache ? extra * dlen : 0; + oid = isl_oid[n].oid + extra; + reslen = dlen; + + if (cache) + down_read(&priv->mib_sem); + + if (islpci_get_state(priv) >= PRV_STATE_INIT) { + ret = islpci_mgt_transaction(priv->ndev, PIMFOR_OP_GET, + oid, data, dlen, &response); + if (ret || !response || + response->header->operation == PIMFOR_OP_ERROR) { + if (response) + islpci_mgt_release(response); + ret = -EIO; + } + if (!ret) { + _res = response->data; + reslen = response->header->length; + } + } else if (cache) { + _res = cache; + ret = 0; + } + if (isl_oid[n].flags & OID_FLAG_U32) { + if (ret) + res->u = 0; + else + res->u = le32_to_cpu(*(u32 *) _res); + } else { + res->ptr = kmalloc(reslen, GFP_KERNEL); + BUG_ON(res->ptr == NULL); + if (ret) + memset(res->ptr, 0, reslen); + else + memcpy(res->ptr, _res, reslen); + } + + if (cache) + up_read(&priv->mib_sem); + + if (response && !ret) + islpci_mgt_release(response); + + if (reslen > isl_oid[n].size) + printk(KERN_DEBUG + "mgt_get_request(0x%x): received data length was bigger " + "than expected (%d > %d). Memory is probably corrupted... ", + oid, reslen, isl_oid[n].size); + + return ret; +} + +/* lock outside */ +int +mgt_commit_list(islpci_private *priv, enum oid_num_t *l, int n) +{ + int i, ret = 0; + struct islpci_mgmtframe *response; + + for (i = 0; i < n; i++) { + struct oid_t *t = &(isl_oid[l[i]]); + void *data = priv->mib[l[i]]; + int j = 0; + u32 oid = t->oid; + BUG_ON(data == NULL); + while (j <= t->range){ + response = NULL; + ret |= islpci_mgt_transaction(priv->ndev, PIMFOR_OP_SET, + oid, data, t->size, + &response); + if (response) { + ret |= (response->header->operation == + PIMFOR_OP_ERROR); + islpci_mgt_release(response); + } + j++; + oid++; + data += t->size; + } + } + return ret; +} + +/* Lock outside */ + +void +mgt_set(islpci_private *priv, enum oid_num_t n, void *data) +{ + BUG_ON(OID_NUM_LAST <= n); + BUG_ON(priv->mib[n] == NULL); + + memcpy(priv->mib[n], data, isl_oid[n].size); + if (isl_oid[n].flags & OID_FLAG_U32) + *(u32 *) priv->mib[n] = cpu_to_le32(*(u32 *) priv->mib[n]); +} + +/* Commits the cache. If something goes wrong, it restarts the device. Lock + * outside + */ + +static enum oid_num_t commit_part1[] = { + OID_INL_CONFIG, + OID_INL_MODE, + DOT11_OID_BSSTYPE, + DOT11_OID_CHANNEL, + DOT11_OID_MLMEAUTOLEVEL +}; + +static enum oid_num_t commit_part2[] = { + DOT11_OID_SSID, + DOT11_OID_PSMBUFFER, + DOT11_OID_AUTHENABLE, + DOT11_OID_PRIVACYINVOKED, + DOT11_OID_EXUNENCRYPTED, + DOT11_OID_DEFKEYX, /* MULTIPLE */ + DOT11_OID_DEFKEYID, + DOT11_OID_DOT1XENABLE, + OID_INL_DOT11D_CONFORMANCE, + OID_INL_OUTPUTPOWER, +}; + +void +mgt_commit(islpci_private *priv) +{ + int rvalue; + u32 u; + union oid_res_t r; + + if (islpci_get_state(priv) < PRV_STATE_INIT) + return; + + rvalue = mgt_commit_list(priv, commit_part1, + sizeof (commit_part1) / + sizeof (commit_part1[0])); + + if (priv->iw_mode != IW_MODE_MONITOR) + rvalue |= mgt_commit_list(priv, commit_part2, + sizeof (commit_part2) / + sizeof (commit_part2[0])); + + u = OID_INL_MODE; + rvalue |= mgt_commit_list(priv, &u, 1); + + if (rvalue) { + /* some request have failed. The device might be in an + incoherent state. We should reset it ! */ + printk(KERN_DEBUG "%s: mgt_commit has failed. Restart the " + "device \n", priv->ndev->name); + } + + /* update the MAC addr. As it's not cached, no lock will be acquired by + * the mgt_get_request + */ + mgt_get_request(priv, GEN_OID_MACADDRESS, 0, NULL, &r); + memcpy(priv->ndev->dev_addr, r.ptr, 6); + kfree(r.ptr); + +} + +/* This will tell you if you are allowed to answer a mlme(ex) request .*/ + +inline int +mgt_mlme_answer(islpci_private *priv) +{ + u32 mlmeautolevel; + /* Acquire a read lock because if we are in a mode change, it's + * possible to answer true, while the card is leaving master to managed + * mode. Answering to a mlme in this situation could hang the card. + */ + down_read(&priv->mib_sem); + mlmeautolevel = + le32_to_cpu(*(u32 *) priv->mib[DOT11_OID_MLMEAUTOLEVEL]); + up_read(&priv->mib_sem); + + return ((priv->iw_mode == IW_MODE_MASTER) && + (mlmeautolevel >= DOT11_MLME_INTERMEDIATE)); +} + +inline enum oid_num_t +mgt_oidtonum(u32 oid) +{ + int i; + + for (i = 0; i < OID_NUM_LAST - 1; i++) + if (isl_oid[i].oid == oid) + return i; + + printk(KERN_DEBUG "looking for an unknown oid 0x%x", oid); + + return 0; +} diff -Nru a/drivers/net/wireless/prism54/oid_mgt.h b/drivers/net/wireless/prism54/oid_mgt.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/prism54/oid_mgt.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2003 Aurelien Alleaume + * + * 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#if !defined(_OID_MGT_H) +#define _OID_MGT_H + +#include "isl_oid.h" +#include "islpci_dev.h" + +extern struct oid_t isl_oid[]; + +int mgt_init(islpci_private *); + +void mgt_clean(islpci_private *); + +extern const int frequency_list_bg[]; + +extern const int frequency_list_a[]; + +int mgt_set_request(islpci_private *, enum oid_num_t, int, void *); + +int mgt_get_request(islpci_private *, enum oid_num_t, int, void *, + union oid_res_t *); + +int mgt_commit_list(islpci_private *, enum oid_num_t *, int); + +void mgt_set(islpci_private *, enum oid_num_t, void *); + +void mgt_commit(islpci_private *); + +int mgt_mlme_answer(islpci_private *); + +enum oid_num_t mgt_oidtonum(u32 oid); + +#endif /* !defined(_OID_MGT_H) */ +/* EOF */ diff -Nru a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c --- a/drivers/net/yellowfin.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/yellowfin.c Sun Mar 14 14:20:07 2004 @@ -1124,7 +1124,7 @@ if(!desc->result_status) break; - pci_dma_sync_single(yp->pci_dev, desc->addr, + pci_dma_sync_single_for_cpu(yp->pci_dev, desc->addr, yp->rx_buf_sz, PCI_DMA_FROMDEVICE); desc_status = le32_to_cpu(desc->result_status) >> 16; buf_addr = rx_skb->tail; @@ -1208,6 +1208,9 @@ memcpy(skb_put(skb, pkt_len), rx_skb->tail, pkt_len); #endif + pci_dma_sync_single_for_device(yp->pci_dev, desc->addr, + yp->rx_buf_sz, + PCI_DMA_FROMDEVICE); } skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); diff -Nru a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c --- a/drivers/net/zorro8390.c Sun Mar 14 14:20:07 2004 +++ b/drivers/net/zorro8390.c Sun Mar 14 14:20:07 2004 @@ -227,6 +227,10 @@ ei_status.reg_offset = zorro8390_offsets; dev->open = &zorro8390_open; dev->stop = &zorro8390_close; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ei_poll; +#endif + NS8390_init(dev, 0); err = register_netdev(dev); if (err) diff -Nru a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c --- a/drivers/parisc/ccio-dma.c Sun Mar 14 14:20:06 2004 +++ b/drivers/parisc/ccio-dma.c Sun Mar 14 14:20:06 2004 @@ -38,9 +38,8 @@ #include #include #include -#define PCI_DEBUG #include -#undef PCI_DEBUG +#include #include #include /* for L1_CACHE_BYTES */ @@ -63,6 +62,18 @@ #undef DEBUG_CCIO_INIT #undef DEBUG_CCIO_RUN_SG +#ifdef CONFIG_PROC_FS +/* + * CCIO_SEARCH_TIME can help measure how fast the bitmap search is. + * impacts performance though - ditch it if you don't use it. + */ +#define CCIO_SEARCH_TIME +#undef CCIO_MAP_STATS +#else +#undef CCIO_SEARCH_TIME +#undef CCIO_MAP_STATS +#endif + #include #include /* for proc_runway_root */ @@ -219,15 +230,18 @@ struct ioa_registers *ioc_hpa; /* I/O MMU base address */ u8 *res_map; /* resource map, bit == pdir entry */ u64 *pdir_base; /* physical base address */ + u32 pdir_size; /* bytes, function of IOV Space size */ u32 res_hint; /* next available IOVP - circular search */ u32 res_size; /* size of resource map in bytes */ spinlock_t res_lock; -#ifdef CONFIG_PROC_FS +#ifdef CCIO_SEARCH_TIME #define CCIO_SEARCH_SAMPLE 0x100 unsigned long avg_search[CCIO_SEARCH_SAMPLE]; unsigned long avg_idx; /* current index into avg_search */ +#endif +#ifdef CCIO_MAP_STATS unsigned long used_pages; unsigned long msingle_calls; unsigned long msingle_pages; @@ -237,12 +251,10 @@ unsigned long usingle_pages; unsigned long usg_calls; unsigned long usg_pages; - - unsigned short cujo20_bug; #endif + unsigned short cujo20_bug; /* STUFF We don't need in performance path */ - u32 pdir_size; /* in bytes, determined by IOV Space size */ u32 chainid_shift; /* specify bit location of chain_id */ struct ioc *next; /* Linked list of discovered iocs */ const char *name; /* device name from firmware */ @@ -289,11 +301,11 @@ ** If the search wraps around, and passes the res_hint, it will ** cause the kernel to panic anyhow. */ -#define CCIO_SEARCH_LOOP(ioc, res_idx, mask_ptr, size) \ +#define CCIO_SEARCH_LOOP(ioc, res_idx, mask, size) \ for(; res_ptr < res_end; ++res_ptr) { \ - if(0 == (*res_ptr & *mask_ptr)) { \ - *res_ptr |= *mask_ptr; \ - res_idx = (int)((unsigned long)res_ptr - (unsigned long)ioc->res_map); \ + if(0 == (*res_ptr & mask)) { \ + *res_ptr |= mask; \ + res_idx = (unsigned int)((unsigned long)res_ptr - (unsigned long)ioc->res_map); \ ioc->res_hint = res_idx + (size >> 3); \ goto resource_found; \ } \ @@ -302,10 +314,9 @@ #define CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, size) \ u##size *res_ptr = (u##size *)&((ioc)->res_map[ioa->res_hint & ~((size >> 3) - 1)]); \ u##size *res_end = (u##size *)&(ioc)->res_map[ioa->res_size]; \ - u##size *mask_ptr = (u##size *)&mask; \ - CCIO_SEARCH_LOOP(ioc, res_idx, mask_ptr, size); \ + CCIO_SEARCH_LOOP(ioc, res_idx, mask, size); \ res_ptr = (u##size *)&(ioc)->res_map[0]; \ - CCIO_SEARCH_LOOP(ioa, res_idx, mask_ptr, size); + CCIO_SEARCH_LOOP(ioa, res_idx, mask, size); /* ** Find available bit in this ioa's resource map. @@ -331,40 +342,51 @@ * of available pages for the requested size. */ static int -ccio_alloc_range(struct ioc *ioc, unsigned long pages_needed) +ccio_alloc_range(struct ioc *ioc, size_t size) { - int res_idx; - unsigned long mask; -#ifdef CONFIG_PROC_FS + unsigned int pages_needed = size >> IOVP_SHIFT; + unsigned int res_idx; +#ifdef CCIO_SEARCH_TIME unsigned long cr_start = mfctl(16); #endif - ASSERT(pages_needed); - ASSERT((pages_needed * IOVP_SIZE) <= DMA_CHUNK_SIZE); - ASSERT(pages_needed <= BITS_PER_LONG); - - mask = ~(~0UL >> pages_needed); + BUG_ON(pages_needed == 0); + BUG_ON((pages_needed * IOVP_SIZE) > DMA_CHUNK_SIZE); - DBG_RES("%s() size: %d pages_needed %d mask 0x%08lx\n", - __FUNCTION__, size, pages_needed, mask); + DBG_RES("%s() size: %d pages_needed %d\n", + __FUNCTION__, size, pages_needed); /* ** "seek and ye shall find"...praying never hurts either... ** ggg sacrifices another 710 to the computer gods. */ - if(pages_needed <= 8) { + if (pages_needed <= 8) { + /* + * LAN traffic will not thrash the TLB IFF the same NIC + * uses 8 adjacent pages to map seperate payload data. + * ie the same byte in the resource bit map. + */ +#if 0 + /* FIXME: bit search should shift it's way through + * an unsigned long - not byte at a time. As it is now, + * we effectively allocate this byte to this mapping. + */ + unsigned long mask = ~(~0UL >> pages_needed); CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 8); - } else if(pages_needed <= 16) { - CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 16); - } else if(pages_needed <= 32) { - CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 32); +#else + CCIO_FIND_FREE_MAPPING(ioc, res_idx, 0xff, 8); +#endif + } else if (pages_needed <= 16) { + CCIO_FIND_FREE_MAPPING(ioc, res_idx, 0xffff, 16); + } else if (pages_needed <= 32) { + CCIO_FIND_FREE_MAPPING(ioc, res_idx, ~(unsigned int)0, 32); #ifdef __LP64__ - } else if(pages_needed <= 64) { - CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 64); + } else if (pages_needed <= 64) { + CCIO_FIND_FREE_MAPPING(ioc, res_idx, ~0UL, 64); #endif } else { - panic("%s: %s() Too many pages to map. pages_needed: %ld\n", + panic("%s: %s() Too many pages to map. pages_needed: %u\n", __FILE__, __FUNCTION__, pages_needed); } @@ -373,10 +395,10 @@ resource_found: - DBG_RES("%s() res_idx %d mask 0x%08lx res_hint: %d\n", - __FUNCTION__, res_idx, mask, ioc->res_hint); + DBG_RES("%s() res_idx %d res_hint: %d\n", + __FUNCTION__, res_idx, ioc->res_hint); -#ifdef CONFIG_PROC_FS +#ifdef CCIO_SEARCH_TIME { unsigned long cr_end = mfctl(16); unsigned long tmp = cr_end - cr_start; @@ -385,10 +407,10 @@ } ioc->avg_search[ioc->avg_idx++] = cr_start; ioc->avg_idx &= CCIO_SEARCH_SAMPLE - 1; - +#endif +#ifdef CCIO_MAP_STATS ioc->used_pages += pages_needed; #endif - /* ** return the bit address. */ @@ -397,9 +419,8 @@ #define CCIO_FREE_MAPPINGS(ioc, res_idx, mask, size) \ u##size *res_ptr = (u##size *)&((ioc)->res_map[res_idx]); \ - u##size *mask_ptr = (u##size *)&mask; \ - ASSERT((*res_ptr & *mask_ptr) == *mask_ptr); \ - *res_ptr &= ~(*mask_ptr); + BUG_ON((*res_ptr & mask) != mask); \ + *res_ptr &= ~(mask); /** * ccio_free_range - Free pages from the ioc's resource map. @@ -413,32 +434,35 @@ static void ccio_free_range(struct ioc *ioc, dma_addr_t iova, unsigned long pages_mapped) { - unsigned long mask; unsigned long iovp = CCIO_IOVP(iova); unsigned int res_idx = PDIR_INDEX(iovp) >> 3; - ASSERT(pages_mapped); - ASSERT((pages_mapped * IOVP_SIZE) <= DMA_CHUNK_SIZE); - ASSERT(pages_mapped <= BITS_PER_LONG); + BUG_ON(pages_mapped == 0); + BUG_ON((pages_mapped * IOVP_SIZE) > DMA_CHUNK_SIZE); + BUG_ON(pages_mapped > BITS_PER_LONG); - mask = ~(~0UL >> pages_mapped); + DBG_RES("%s(): res_idx: %d pages_mapped %d\n", + __FUNCTION__, res_idx, pages_mapped); - DBG_RES("%s(): res_idx: %d pages_mapped %d mask 0x%08lx\n", - __FUNCTION__, res_idx, pages_mapped, mask); - -#ifdef CONFIG_PROC_FS +#ifdef CCIO_MAP_STATS ioc->used_pages -= pages_mapped; #endif if(pages_mapped <= 8) { +#if 0 + /* see matching comments in alloc_range */ + unsigned long mask = ~(~0UL >> pages_mapped); CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 8); +#else + CCIO_FREE_MAPPINGS(ioc, res_idx, 0xff, 8); +#endif } else if(pages_mapped <= 16) { - CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 16); + CCIO_FREE_MAPPINGS(ioc, res_idx, 0xffff, 16); } else if(pages_mapped <= 32) { - CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 32); + CCIO_FREE_MAPPINGS(ioc, res_idx, ~(unsigned int)0, 32); #ifdef __LP64__ } else if(pages_mapped <= 64) { - CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 64); + CCIO_FREE_MAPPINGS(ioc, res_idx, ~0UL, 64); #endif } else { panic("%s:%s() Too many pages to unmap.\n", __FILE__, @@ -533,13 +557,14 @@ * index are bits 12:19 of the value returned by LCI. */ void CCIO_INLINE -ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, void * vba, unsigned long hints) +ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, + unsigned long hints) { register unsigned long pa = (volatile unsigned long) vba; register unsigned long ci; /* coherent index */ /* We currently only support kernel addresses */ - ASSERT(sid == KERNEL_SPACE); + BUG_ON(sid != KERNEL_SPACE); mtsp(sid,1); @@ -652,7 +677,7 @@ unsigned int idx = PDIR_INDEX(iovp); char *pdir_ptr = (char *) &(ioc->pdir_base[idx]); - ASSERT(idx < (ioc->pdir_size / sizeof(u64))); + BUG_ON(idx >= (ioc->pdir_size / sizeof(u64))); pdir_ptr[7] = 0; /* clear only VALID bit */ /* ** FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360) @@ -722,7 +747,7 @@ BUG_ON(!dev); ioc = GET_IOC(dev); - ASSERT(size > 0); + BUG_ON(size <= 0); /* save offset bits */ offset = ((unsigned long) addr) & ~IOVP_MASK; @@ -731,12 +756,12 @@ size = ROUNDUP(size + offset, IOVP_SIZE); spin_lock_irqsave(&ioc->res_lock, flags); -#ifdef CONFIG_PROC_FS +#ifdef CCIO_MAP_STATS ioc->msingle_calls++; ioc->msingle_pages += size >> IOVP_SHIFT; #endif - idx = ccio_alloc_range(ioc, (size >> IOVP_SHIFT)); + idx = ccio_alloc_range(ioc, size); iovp = (dma_addr_t)MKIOVP(idx); pdir_start = &(ioc->pdir_base[idx]); @@ -749,7 +774,7 @@ hint |= HINT_SAFE_DMA; while(size > 0) { - ccio_io_pdir_entry(pdir_start, KERNEL_SPACE, addr, hint); + ccio_io_pdir_entry(pdir_start, KERNEL_SPACE, (unsigned long)addr, hint); DBG_RUN(" pdir %p %08x%08x\n", pdir_start, @@ -795,7 +820,7 @@ spin_lock_irqsave(&ioc->res_lock, flags); -#ifdef CONFIG_PROC_FS +#ifdef CCIO_MAP_STATS ioc->usingle_calls++; ioc->usingle_pages += size >> IOVP_SHIFT; #endif @@ -861,180 +886,10 @@ */ #define PIDE_FLAG 0x80000000UL -/** - * ccio_fill_pdir - Insert coalesced scatter/gather chunks into the I/O Pdir. - * @ioc: The I/O Controller. - * @startsg: The scatter/gather list of coalesced chunks. - * @nents: The number of entries in the scatter/gather list. - * @hint: The DMA Hint. - * - * This function inserts the coalesced scatter/gather list chunks into the - * I/O Controller's I/O Pdir. - */ -static CCIO_INLINE int -ccio_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents, - unsigned long hint) -{ - struct scatterlist *dma_sg = startsg; /* pointer to current DMA */ - int n_mappings = 0; - u64 *pdirp = 0; - unsigned long dma_offset = 0; - - dma_sg--; - while (nents-- > 0) { - int cnt = sg_dma_len(startsg); - sg_dma_len(startsg) = 0; - - DBG_RUN_SG(" %d : %08lx/%05x %08lx/%05x\n", nents, - (unsigned long)sg_dma_address(startsg), cnt, - sg_virt_addr(startsg), startsg->length - ); - - /* - ** Look for the start of a new DMA stream - */ - if(sg_dma_address(startsg) & PIDE_FLAG) { - u32 pide = sg_dma_address(startsg) & ~PIDE_FLAG; - dma_offset = (unsigned long) pide & ~IOVP_MASK; - sg_dma_address(startsg) = 0; - dma_sg++; - sg_dma_address(dma_sg) = pide; - pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]); - n_mappings++; - } - - /* - ** Look for a VCONTIG chunk - */ - if (cnt) { - unsigned long vaddr = sg_virt_addr(startsg); - ASSERT(pdirp); - - /* Since multiple Vcontig blocks could make up - ** one DMA stream, *add* cnt to dma_len. - */ - sg_dma_len(dma_sg) += cnt; - cnt += dma_offset; - dma_offset=0; /* only want offset on first chunk */ - cnt = ROUNDUP(cnt, IOVP_SIZE); -#ifdef CONFIG_PROC_FS - ioc->msg_pages += cnt >> IOVP_SHIFT; +#ifdef CCIO_MAP_STATS +#define IOMMU_MAP_STATS #endif - do { - ccio_io_pdir_entry(pdirp, KERNEL_SPACE, - (void *)vaddr, hint); - vaddr += IOVP_SIZE; - cnt -= IOVP_SIZE; - pdirp++; - } while (cnt > 0); - } - startsg++; - } - return(n_mappings); -} - -/* -** First pass is to walk the SG list and determine where the breaks are -** in the DMA stream. Allocates PDIR entries but does not fill them. -** Returns the number of DMA chunks. -** -** Doing the fill separate from the coalescing/allocation keeps the -** code simpler. Future enhancement could make one pass through -** the sglist do both. -*/ - -static CCIO_INLINE int -ccio_coalesce_chunks(struct ioc *ioc, struct scatterlist *startsg, int nents) -{ - struct scatterlist *vcontig_sg; /* VCONTIG chunk head */ - unsigned long vcontig_len; /* len of VCONTIG chunk */ - unsigned long vcontig_end; - struct scatterlist *dma_sg; /* next DMA stream head */ - unsigned long dma_offset, dma_len; /* start/len of DMA stream */ - int n_mappings = 0; - - while (nents > 0) { - - /* - ** Prepare for first/next DMA stream - */ - dma_sg = vcontig_sg = startsg; - dma_len = vcontig_len = vcontig_end = startsg->length; - vcontig_end += sg_virt_addr(startsg); - dma_offset = sg_virt_addr(startsg) & ~IOVP_MASK; - - /* PARANOID: clear entries */ - sg_dma_address(startsg) = 0; - sg_dma_len(startsg) = 0; - - /* - ** This loop terminates one iteration "early" since - ** it's always looking one "ahead". - */ - while(--nents > 0) { - unsigned long startsg_end; - - startsg++; - startsg_end = sg_virt_addr(startsg) + - startsg->length; - - /* PARANOID: clear entries */ - sg_dma_address(startsg) = 0; - sg_dma_len(startsg) = 0; - - /* - ** First make sure current dma stream won't - ** exceed DMA_CHUNK_SIZE if we coalesce the - ** next entry. - */ - if(ROUNDUP(dma_len + dma_offset + startsg->length, - IOVP_SIZE) > DMA_CHUNK_SIZE) - break; - - /* - ** Append the next transaction? - */ - if (vcontig_end == sg_virt_addr(startsg)) { - vcontig_len += startsg->length; - vcontig_end += startsg->length; - dma_len += startsg->length; - continue; - } - - /* - ** Not virtually contigous. - ** Terminate prev chunk. - ** Start a new chunk. - ** - ** Once we start a new VCONTIG chunk, dma_offset - ** can't change. And we need the offset from the first - ** chunk - not the last one. Ergo Successive chunks - ** must start on page boundaries and dove tail - ** with its predecessor. - */ - sg_dma_len(vcontig_sg) = vcontig_len; - - vcontig_sg = startsg; - vcontig_len = startsg->length; - break; - } - - /* - ** End of DMA Stream - ** Terminate last VCONTIG block. - ** Allocate space for DMA stream. - */ - sg_dma_len(vcontig_sg) = vcontig_len; - dma_len = ROUNDUP(dma_len + dma_offset, IOVP_SIZE); - sg_dma_address(dma_sg) = - PIDE_FLAG - | (ccio_alloc_range(ioc, (dma_len >> IOVP_SHIFT)) << IOVP_SHIFT) - | dma_offset; - n_mappings++; - } - - return n_mappings; -} +#include "iommu-helpers.h" /** * ccio_map_sg - Map the scatter/gather list into the IOMMU. @@ -1053,6 +908,8 @@ int coalesced, filled = 0; unsigned long flags; unsigned long hint = hint_lookup[(int)direction]; + unsigned long prev_len = 0, current_len = 0; + int i; BUG_ON(!dev); ioc = GET_IOC(dev); @@ -1067,10 +924,13 @@ sg_dma_len(sglist) = sglist->length; return 1; } + + for(i = 0; i < nents; i++) + prev_len += sglist[i].length; spin_lock_irqsave(&ioc->res_lock, flags); -#ifdef CONFIG_PROC_FS +#ifdef CCIO_MAP_STATS ioc->msg_calls++; #endif @@ -1082,7 +942,7 @@ ** w/o this association, we wouldn't have coherent DMA! ** Access to the virtual address is what forces a two pass algorithm. */ - coalesced = ccio_coalesce_chunks(ioc, sglist, nents); + coalesced = iommu_coalesce_chunks(ioc, sglist, nents, ccio_alloc_range); /* ** Program the I/O Pdir @@ -1092,13 +952,19 @@ ** o dma_len will contain the number of bytes to map ** o page/offset contain the virtual address. */ - filled = ccio_fill_pdir(ioc, sglist, nents, hint); + filled = iommu_fill_pdir(ioc, sglist, nents, hint, ccio_io_pdir_entry); spin_unlock_irqrestore(&ioc->res_lock, flags); - ASSERT(coalesced == filled); + BUG_ON(coalesced != filled); + DBG_RUN_SG("%s() DONE %d mappings\n", __FUNCTION__, filled); + for (i = 0; i < filled; i++) + current_len += sg_dma_len(sglist + i); + + BUG_ON(current_len != prev_len); + return filled; } @@ -1123,13 +989,13 @@ DBG_RUN_SG("%s() START %d entries, %08lx,%x\n", __FUNCTION__, nents, sg_virt_addr(sglist), sglist->length); -#ifdef CONFIG_PROC_FS +#ifdef CCIO_MAP_STATS ioc->usg_calls++; #endif while(sg_dma_len(sglist) && nents--) { -#ifdef CONFIG_PROC_FS +#ifdef CCIO_MAP_STATS ioc->usg_pages += sg_dma_len(sglist) >> PAGE_SHIFT; #endif ccio_unmap_single(dev, sg_dma_address(sglist), @@ -1149,8 +1015,10 @@ .unmap_single = ccio_unmap_single, .map_sg = ccio_map_sg, .unmap_sg = ccio_unmap_sg, - .dma_sync_single = NULL, /* NOP for U2/Uturn */ - .dma_sync_sg = NULL, /* ditto */ + .dma_sync_single_for_cpu = NULL, /* NOP for U2/Uturn */ + .dma_sync_single_for_device = NULL, /* NOP for U2/Uturn */ + .dma_sync_sg_for_cpu = NULL, /* ditto */ + .dma_sync_sg_for_device = NULL, /* ditto */ }; #ifdef CONFIG_PROC_FS @@ -1199,18 +1067,18 @@ total_pages * 8, total_pages); if (proc_append(tmp, len, &buf, &offset, &count)) break; - +#ifdef CCIO_MAP_STATS len = sprintf(tmp, "IO PDIR entries : %ld free %ld used (%d%%)\n", total_pages - ioc->used_pages, ioc->used_pages, (int)(ioc->used_pages * 100 / total_pages)); if (proc_append(tmp, len, &buf, &offset, &count)) break; - +#endif len = sprintf(tmp, "Resource bitmap : %d bytes (%d pages)\n", ioc->res_size, total_pages); if (proc_append(tmp, len, &buf, &offset, &count)) break; - +#ifdef CCIO_SEARCH_TIME min = max = ioc->avg_search[0]; for(j = 0; j < CCIO_SEARCH_SAMPLE; ++j) { avg += ioc->avg_search[j]; @@ -1224,7 +1092,8 @@ min, avg, max); if (proc_append(tmp, len, &buf, &offset, &count)) break; - +#endif +#ifdef CCIO_MAP_STATS len = sprintf(tmp, "pci_map_single(): %8ld calls %8ld pages (avg %d/1000)\n", ioc->msingle_calls, ioc->msingle_pages, (int)((ioc->msingle_pages * 1000)/ioc->msingle_calls)); @@ -1250,7 +1119,7 @@ (int)((ioc->usg_pages * 1000)/ioc->usg_calls)); if (proc_append(tmp, len, &buf, &offset, &count)) break; - +#endif /* CCIO_MAP_STATS */ ioc = ioc->next; } @@ -1336,9 +1205,7 @@ struct ioc *ioc = ccio_get_iommu(dev); u8 *res_ptr; -#ifdef CONFIG_PROC_FS ioc->cujo20_bug = 1; -#endif res_ptr = ioc->res_map; idx = PDIR_INDEX(iovp) >> 3; @@ -1429,16 +1296,16 @@ */ iov_order = get_order(iova_space_size) >> (IOVP_SHIFT - PAGE_SHIFT); - ASSERT(iov_order <= (30 - IOVP_SHIFT)); /* iova_space_size <= 1GB */ - ASSERT(iov_order >= (20 - IOVP_SHIFT)); /* iova_space_size >= 1MB */ + BUG_ON(iov_order > (30 - IOVP_SHIFT)); /* iova_space_size <= 1GB */ + BUG_ON(iov_order < (20 - IOVP_SHIFT)); /* iova_space_size >= 1MB */ iova_space_size = 1 << (iov_order + IOVP_SHIFT); ioc->pdir_size = (iova_space_size / IOVP_SIZE) * sizeof(u64); - ASSERT(ioc->pdir_size < 4 * 1024 * 1024); /* max pdir size < 4MB */ + BUG_ON(ioc->pdir_size >= 4 * 1024 * 1024); /* max pdir size < 4MB */ /* Verify it's a power of two */ - ASSERT((1 << get_order(ioc->pdir_size)) == (ioc->pdir_size >> PAGE_SHIFT)); + BUG_ON((1 << get_order(ioc->pdir_size)) != (ioc->pdir_size >> PAGE_SHIFT)); DBG_INIT("%s() hpa 0x%p mem %luMB IOV %dMB (%d bits) PDIR size 0x%0x", __FUNCTION__, ioc->ioc_hpa, physmem>>20, iova_space_size>>20, @@ -1452,7 +1319,7 @@ } memset(ioc->pdir_base, 0, ioc->pdir_size); - ASSERT((((unsigned long)ioc->pdir_base) & PAGE_MASK) == (unsigned long)ioc->pdir_base); + BUG_ON((((unsigned long)ioc->pdir_base) & PAGE_MASK) != (unsigned long)ioc->pdir_base); DBG_INIT(" base %p", ioc->pdir_base); /* resource map size dictated by pdir_size */ @@ -1684,13 +1551,14 @@ if (ioc_count == 0) { - /* XXX: Create separate entries for each ioc */ + /* FIXME: Create separate entries for each ioc */ create_proc_read_entry(MODULE_NAME, S_IRWXU, proc_runway_root, ccio_proc_info, NULL); create_proc_read_entry(MODULE_NAME"-bitmap", S_IRWXU, proc_runway_root, ccio_resource_map, NULL); } - + parisc_vmerge_boundary = IOVP_SIZE; + parisc_vmerge_max_size = BITS_PER_LONG * IOVP_SIZE; ioc_count++; return 0; } diff -Nru a/drivers/parisc/ccio-rm-dma.c b/drivers/parisc/ccio-rm-dma.c --- a/drivers/parisc/ccio-rm-dma.c Sun Mar 14 14:20:06 2004 +++ b/drivers/parisc/ccio-rm-dma.c Sun Mar 14 14:20:06 2004 @@ -151,8 +151,10 @@ ccio_unmap_single, ccio_map_sg, ccio_unmap_sg, - NULL, /* dma_sync_single : NOP for U2 */ - NULL, /* dma_sync_sg : ditto */ + NULL, /* dma_sync_single_for_cpu : NOP for U2 */ + NULL, /* dma_sync_single_for_device : NOP for U2 */ + NULL, /* dma_sync_sg_for_cpu : ditto */ + NULL, /* dma_sync_sg_for_device : ditto */ }; diff -Nru a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c --- a/drivers/parisc/eisa.c Sun Mar 14 14:20:05 2004 +++ b/drivers/parisc/eisa.c Sun Mar 14 14:20:05 2004 @@ -116,6 +116,16 @@ gsc_writel(cpu_to_le32(data), eisa_permute(port)); } +#ifndef CONFIG_PCI +/* We call these directly without PCI. See asm/io.h. */ +EXPORT_SYMBOL(eisa_in8); +EXPORT_SYMBOL(eisa_in16); +EXPORT_SYMBOL(eisa_in32); +EXPORT_SYMBOL(eisa_out8); +EXPORT_SYMBOL(eisa_out16); +EXPORT_SYMBOL(eisa_out32); +#endif + /* Interrupt handling */ /* cached interrupt mask registers */ diff -Nru a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c --- a/drivers/parisc/gsc.c Sun Mar 14 14:20:08 2004 +++ b/drivers/parisc/gsc.c Sun Mar 14 14:20:08 2004 @@ -29,6 +29,11 @@ #include "gsc.h" +/* This sets the vmerge boundary and size, it's here because it has to + * be available on all platforms (zero means no-virtual merging) */ +unsigned long parisc_vmerge_boundary = 0; +unsigned long parisc_vmerge_max_size = 0; + #undef DEBUG #ifdef DEBUG diff -Nru a/drivers/parisc/iommu-helpers.h b/drivers/parisc/iommu-helpers.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/parisc/iommu-helpers.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,163 @@ +/** + * iommu_fill_pdir - Insert coalesced scatter/gather chunks into the I/O Pdir. + * @ioc: The I/O Controller. + * @startsg: The scatter/gather list of coalesced chunks. + * @nents: The number of entries in the scatter/gather list. + * @hint: The DMA Hint. + * + * This function inserts the coalesced scatter/gather list chunks into the + * I/O Controller's I/O Pdir. + */ +static inline unsigned int +iommu_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents, + unsigned long hint, + void (*iommu_io_pdir_entry)(u64 *, space_t, unsigned long, + unsigned long)) +{ + struct scatterlist *dma_sg = startsg; /* pointer to current DMA */ + unsigned int n_mappings = 0; + unsigned long dma_offset = 0, dma_len = 0; + u64 *pdirp = NULL; + + /* Horrible hack. For efficiency's sake, dma_sg starts one + * entry below the true start (it is immediately incremented + * in the loop) */ + dma_sg--; + + while (nents-- > 0) { + unsigned long vaddr; + long size; + + DBG_RUN_SG(" %d : %08lx/%05x %08lx/%05x\n", nents, + (unsigned long)sg_dma_address(startsg), cnt, + sg_virt_addr(startsg), startsg->length + ); + + + /* + ** Look for the start of a new DMA stream + */ + + if (sg_dma_address(startsg) & PIDE_FLAG) { + u32 pide = sg_dma_address(startsg) & ~PIDE_FLAG; + + BUG_ON(pdirp && (dma_len != sg_dma_len(dma_sg))); + + dma_sg++; + + dma_len = sg_dma_len(startsg); + sg_dma_len(startsg) = 0; + dma_offset = (unsigned long) pide & ~IOVP_MASK; + n_mappings++; + sg_dma_address(dma_sg) = pide; + pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]); + prefetchw(pdirp); + } + + BUG_ON(pdirp == NULL); + + vaddr = sg_virt_addr(startsg); + sg_dma_len(dma_sg) += startsg->length; + size = startsg->length + dma_offset; + dma_offset = 0; +#ifdef IOMMU_MAP_STATS + ioc->msg_pages += startsg->length >> IOVP_SHIFT; +#endif + do { + iommu_io_pdir_entry(pdirp, KERNEL_SPACE, + vaddr, hint); + vaddr += IOVP_SIZE; + size -= IOVP_SIZE; + pdirp++; + } while(unlikely(size > 0)); + startsg++; + } + return(n_mappings); +} + + +/* +** First pass is to walk the SG list and determine where the breaks are +** in the DMA stream. Allocates PDIR entries but does not fill them. +** Returns the number of DMA chunks. +** +** Doing the fill separate from the coalescing/allocation keeps the +** code simpler. Future enhancement could make one pass through +** the sglist do both. +*/ + +static inline unsigned int +iommu_coalesce_chunks(struct ioc *ioc, struct scatterlist *startsg, int nents, + int (*iommu_alloc_range)(struct ioc *, size_t)) +{ + struct scatterlist *contig_sg; /* contig chunk head */ + unsigned long dma_offset, dma_len; /* start/len of DMA stream */ + unsigned int n_mappings = 0; + + while (nents > 0) { + + /* + ** Prepare for first/next DMA stream + */ + contig_sg = startsg; + dma_len = startsg->length; + dma_offset = sg_virt_addr(startsg) & ~IOVP_MASK; + + /* PARANOID: clear entries */ + sg_dma_address(startsg) = 0; + sg_dma_len(startsg) = 0; + + /* + ** This loop terminates one iteration "early" since + ** it's always looking one "ahead". + */ + while(--nents > 0) { + unsigned long prevstartsg_end, startsg_end; + + prevstartsg_end = sg_virt_addr(startsg) + + startsg->length; + + startsg++; + startsg_end = sg_virt_addr(startsg) + + startsg->length; + + /* PARANOID: clear entries */ + sg_dma_address(startsg) = 0; + sg_dma_len(startsg) = 0; + + /* + ** First make sure current dma stream won't + ** exceed DMA_CHUNK_SIZE if we coalesce the + ** next entry. + */ + if(unlikely(ROUNDUP(dma_len + dma_offset + startsg->length, + IOVP_SIZE) > DMA_CHUNK_SIZE)) + break; + + /* + ** Next see if we can append the next chunk (i.e. + ** it must end on one page and begin on another + */ + if (unlikely(((prevstartsg_end | sg_virt_addr(startsg)) & ~PAGE_MASK) != 0)) + break; + + dma_len += startsg->length; + } + + /* + ** End of DMA Stream + ** Terminate last VCONTIG block. + ** Allocate space for DMA stream. + */ + sg_dma_len(contig_sg) = dma_len; + dma_len = ROUNDUP(dma_len + dma_offset, IOVP_SIZE); + sg_dma_address(contig_sg) = + PIDE_FLAG + | (iommu_alloc_range(ioc, dma_len) << IOVP_SHIFT) + | dma_offset; + n_mappings++; + } + + return n_mappings; +} + diff -Nru a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c --- a/drivers/parisc/lba_pci.c Sun Mar 14 14:20:07 2004 +++ b/drivers/parisc/lba_pci.c Sun Mar 14 14:20:07 2004 @@ -533,10 +533,10 @@ */ LBA_CFG_TR4_ADDR_SETUP(d, tok | pos); switch(size) { - case 1: *(u8 *) data = READ_REG8(d->hba.base_addr + LBA_PCI_CFG_DATA); - break; - case 2: *(u16 *) data = READ_REG16(d->hba.base_addr + LBA_PCI_CFG_DATA); - break; + case 1: *(u8 *) data = READ_REG8(d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & 3)); + break; + case 2: *(u16 *) data = READ_REG16(d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & 2)); + break; case 4: *(u32 *) data = READ_REG32(d->hba.base_addr + LBA_PCI_CFG_DATA); break; } @@ -613,13 +613,14 @@ /* Basic Algorithm */ LBA_CFG_TR4_ADDR_SETUP(d, tok | pos); switch(size) { - case 1: WRITE_REG8 (data, d->hba.base_addr + LBA_PCI_CFG_DATA); + case 1: WRITE_REG8 (data, d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & 3)); break; - case 2: WRITE_REG16(data, d->hba.base_addr + LBA_PCI_CFG_DATA); + case 2: WRITE_REG16(data, d->hba.base_addr + LBA_PCI_CFG_DATA + (pos & 2)); break; case 4: WRITE_REG32(data, d->hba.base_addr + LBA_PCI_CFG_DATA); break; } + /* flush posted write */ lba_t32 = READ_REG32(d->hba.base_addr + LBA_PCI_CFG_ADDR); return 0; } diff -Nru a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c --- a/drivers/parisc/sba_iommu.c Sun Mar 14 14:20:08 2004 +++ b/drivers/parisc/sba_iommu.c Sun Mar 14 14:20:08 2004 @@ -700,7 +700,8 @@ void SBA_INLINE -sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba) +sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, + unsigned long hint) { u64 pa; /* physical address */ register unsigned ci; /* coherent index */ @@ -874,7 +875,7 @@ while (size > 0) { ASSERT(((u8 *)pdir_start)[7] == 0); /* verify availability */ - sba_io_pdir_entry(pdir_start, KERNEL_SPACE, (unsigned long) addr); + sba_io_pdir_entry(pdir_start, KERNEL_SPACE, (unsigned long) addr, 0); DBG_RUN(" pdir 0x%p %02x%02x%02x%02x%02x%02x%02x%02x\n", pdir_start, @@ -1027,243 +1028,15 @@ */ #define PIDE_FLAG 0x80000000UL -#ifdef DEBUG_LARGE_SG_ENTRIES -int dump_run_sg = 0; -#endif - - -/** - * sba_fill_pdir - write allocated SG entries into IO PDIR - * @ioc: IO MMU structure which owns the pdir we are interested in. - * @startsg: list of IOVA/size pairs - * @nents: number of entries in startsg list - * - * Take preprocessed SG list and write corresponding entries - * in the IO PDIR. - */ - -static SBA_INLINE int -sba_fill_pdir( - struct ioc *ioc, - struct scatterlist *startsg, - int nents) -{ - struct scatterlist *dma_sg = startsg; /* pointer to current DMA */ - int n_mappings = 0; - u64 *pdirp = 0; - unsigned long dma_offset = 0; - - dma_sg--; - while (nents-- > 0) { - int cnt = sg_dma_len(startsg); - sg_dma_len(startsg) = 0; - -#ifdef DEBUG_LARGE_SG_ENTRIES - if (dump_run_sg) - printk(KERN_DEBUG " %2d : %08lx/%05x %p/%05x\n", - nents, - (unsigned long) sg_dma_address(startsg), cnt, - sg_virt_addr(startsg), startsg->length - ); -#else - DBG_RUN_SG(" %d : %08lx/%05x %p/%05x\n", - nents, - (unsigned long) sg_dma_address(startsg), cnt, - sg_virt_addr(startsg), startsg->length - ); -#endif - /* - ** Look for the start of a new DMA stream - */ - if (sg_dma_address(startsg) & PIDE_FLAG) { - u32 pide = sg_dma_address(startsg) & ~PIDE_FLAG; - dma_offset = (unsigned long) pide & ~IOVP_MASK; - sg_dma_address(startsg) = 0; - dma_sg++; - sg_dma_address(dma_sg) = pide; - pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]); - n_mappings++; - } - - /* - ** Look for a VCONTIG chunk - */ - if (cnt) { - unsigned long vaddr = (unsigned long) sg_virt_addr(startsg); - ASSERT(pdirp); - - /* Since multiple Vcontig blocks could make up - ** one DMA stream, *add* cnt to dma_len. - */ - sg_dma_len(dma_sg) += cnt; - cnt += dma_offset; - dma_offset=0; /* only want offset on first chunk */ - cnt = ROUNDUP(cnt, IOVP_SIZE); #ifdef SBA_COLLECT_STATS - ioc->msg_pages += cnt >> IOVP_SHIFT; -#endif - do { - sba_io_pdir_entry(pdirp, KERNEL_SPACE, vaddr); - vaddr += IOVP_SIZE; - cnt -= IOVP_SIZE; - pdirp++; - } while (cnt > 0); - } - startsg++; - } -#ifdef DEBUG_LARGE_SG_ENTRIES - dump_run_sg = 0; +#define IOMMU_MAP_STATS #endif - return(n_mappings); -} - - -/* -** Two address ranges are DMA contiguous *iff* "end of prev" and -** "start of next" are both on a page boundary. -** -** (shift left is a quick trick to mask off upper bits) -*/ -#define DMA_CONTIG(__X, __Y) \ - (((((unsigned long) __X) | ((unsigned long) __Y)) << (BITS_PER_LONG - PAGE_SHIFT)) == 0UL) - - -/** - * sba_coalesce_chunks - preprocess the SG list - * @ioc: IO MMU structure which owns the pdir we are interested in. - * @startsg: list of IOVA/size pairs - * @nents: number of entries in startsg list - * - * First pass is to walk the SG list and determine where the breaks are - * in the DMA stream. Allocates PDIR entries but does not fill them. - * Returns the number of DMA chunks. - * - * Doing the fill separate from the coalescing/allocation keeps the - * code simpler. Future enhancement could make one pass through - * the sglist do both. - */ -static SBA_INLINE int -sba_coalesce_chunks( struct ioc *ioc, - struct scatterlist *startsg, - int nents) -{ - struct scatterlist *vcontig_sg; /* VCONTIG chunk head */ - unsigned long vcontig_len; /* len of VCONTIG chunk */ - unsigned long vcontig_end; - struct scatterlist *dma_sg; /* next DMA stream head */ - unsigned long dma_offset, dma_len; /* start/len of DMA stream */ - int n_mappings = 0; - - while (nents > 0) { - unsigned long vaddr = (unsigned long) sg_virt_addr(startsg); - - /* - ** Prepare for first/next DMA stream - */ - dma_sg = vcontig_sg = startsg; - dma_len = vcontig_len = vcontig_end = startsg->length; - vcontig_end += vaddr; - dma_offset = vaddr & ~IOVP_MASK; - - /* PARANOID: clear entries */ - sg_dma_address(startsg) = 0; - sg_dma_len(startsg) = 0; - - /* - ** This loop terminates one iteration "early" since - ** it's always looking one "ahead". - */ - while (--nents > 0) { - unsigned long vaddr; /* tmp */ - - startsg++; - - /* PARANOID: clear entries */ - sg_dma_address(startsg) = 0; - sg_dma_len(startsg) = 0; - - /* catch brokenness in SCSI layer */ - ASSERT(startsg->length <= DMA_CHUNK_SIZE); - - /* - ** First make sure current dma stream won't - ** exceed DMA_CHUNK_SIZE if we coalesce the - ** next entry. - */ - if (((dma_len + dma_offset + startsg->length + ~IOVP_MASK) & IOVP_MASK) > DMA_CHUNK_SIZE) - break; - - /* - ** Then look for virtually contiguous blocks. - ** PARISC needs to associate a virtual address - ** with each IO address mapped. The CPU cache is - ** virtually tagged and the IOMMU uses part - ** of the virtual address to participate in - ** CPU cache coherency. - ** - ** append the next transaction? - */ - vaddr = (unsigned long) sg_virt_addr(startsg); - if (vcontig_end == vaddr) - { - vcontig_len += startsg->length; - vcontig_end += startsg->length; - dma_len += startsg->length; - continue; - } +#include "iommu-helpers.h" #ifdef DEBUG_LARGE_SG_ENTRIES - dump_run_sg = (vcontig_len > IOVP_SIZE); +int dump_run_sg = 0; #endif - /* - ** Not virtually contigous. - ** Terminate prev chunk. - ** Start a new chunk. - ** - ** Once we start a new VCONTIG chunk, dma_offset - ** can't change. And we need the offset from the first - ** chunk - not the last one. Ergo Successive chunks - ** must start on page boundaries and dove tail - ** with its predecessor. - */ - sg_dma_len(vcontig_sg) = vcontig_len; - - vcontig_sg = startsg; - vcontig_len = startsg->length; - - /* - ** 3) do the entries end/start on page boundaries? - ** Don't update vcontig_end until we've checked. - */ - if (DMA_CONTIG(vcontig_end, vaddr)) - { - vcontig_end = vcontig_len + vaddr; - dma_len += vcontig_len; - continue; - } else { - break; - } - } - - /* - ** End of DMA Stream - ** Terminate last VCONTIG block. - ** Allocate space for DMA stream. - */ - sg_dma_len(vcontig_sg) = vcontig_len; - dma_len = (dma_len + dma_offset + ~IOVP_MASK) & IOVP_MASK; - ASSERT(dma_len <= DMA_CHUNK_SIZE); - sg_dma_address(dma_sg) = - PIDE_FLAG - | (sba_alloc_range(ioc, dma_len) << IOVP_SHIFT) - | dma_offset; - n_mappings++; - } - - return n_mappings; -} - /** * sba_map_sg - map Scatter/Gather list @@ -1318,7 +1091,7 @@ ** w/o this association, we wouldn't have coherent DMA! ** Access to the virtual address is what forces a two pass algorithm. */ - coalesced = sba_coalesce_chunks(ioc, sglist, nents); + coalesced = iommu_coalesce_chunks(ioc, sglist, nents, sba_alloc_range); /* ** Program the I/O Pdir @@ -1328,7 +1101,7 @@ ** o dma_len will contain the number of bytes to map ** o address contains the virtual address. */ - filled = sba_fill_pdir(ioc, sglist, nents); + filled = iommu_fill_pdir(ioc, sglist, nents, 0, sba_io_pdir_entry); #ifdef ASSERT_PDIR_SANITY if (sba_check_pdir(ioc,"Check after sba_map_sg()")) @@ -1410,8 +1183,10 @@ .unmap_single = sba_unmap_single, .map_sg = sba_map_sg, .unmap_sg = sba_unmap_sg, - .dma_sync_single = NULL, - .dma_sync_sg = NULL, + .dma_sync_single_for_cpu = NULL, + .dma_sync_single_for_device = NULL, + .dma_sync_sg_for_cpu = NULL, + .dma_sync_sg_for_device = NULL, }; @@ -2045,6 +1820,9 @@ create_proc_info_entry("bitmap", 0, proc_runway_root, sba_resource_map); #endif #endif + parisc_vmerge_boundary = IOVP_SIZE; + parisc_vmerge_max_size = IOVP_SIZE * BITS_PER_LONG; + return 0; } diff -Nru a/drivers/parisc/superio.c b/drivers/parisc/superio.c --- a/drivers/parisc/superio.c Sun Mar 14 14:20:07 2004 +++ b/drivers/parisc/superio.c Sun Mar 14 14:20:07 2004 @@ -69,11 +69,15 @@ #include #include #include +#include +#include #include #include #include #include +#define SUPERIO_IDE_MAX_RETRIES 25 + static struct superio_device sio_dev; @@ -161,7 +165,6 @@ printk (KERN_INFO "SuperIO: Found NS87560 Legacy I/O device at %s (IRQ %i) \n", pci_name(pdev),pdev->irq); - /* Find our I/O devices */ pci_read_config_dword (pdev, SIO_SP1BAR, &sio->sp1_base); sio->sp1_base &= ~1; printk (KERN_INFO "SuperIO: Serial port 1 at 0x%x\n", sio->sp1_base); @@ -462,16 +465,72 @@ } -int -superio_get_ide_irq(void) +static u8 superio_ide_inb (unsigned long port); +static unsigned long superio_ide_status[2]; +static unsigned long superio_ide_select[2]; +static unsigned long superio_ide_dma_status[2]; + +void superio_fixup_pci(struct pci_dev *pdev) { - if (sio_dev.irq_region) - return sio_dev.irq_region->data.irqbase + IDE_IRQ; - else - return 0; + u8 prog; + + pdev->class |= 0x5; + pci_write_config_byte(pdev, PCI_CLASS_PROG, pdev->class); + + pci_read_config_byte(pdev, PCI_CLASS_PROG, &prog); + printk("PCI: Enabled native mode for NS87415 (pif=0x%x)\n", prog); } -EXPORT_SYMBOL(superio_get_ide_irq); +/* Because of a defect in Super I/O, all reads of the PCI DMA status + * registers, IDE status register and the IDE select register need to be + * retried + */ +static u8 superio_ide_inb (unsigned long port) +{ + if (port == superio_ide_status[0] || + port == superio_ide_status[1] || + port == superio_ide_select[0] || + port == superio_ide_select[1] || + port == superio_ide_dma_status[0] || + port == superio_ide_dma_status[1]) { + u8 tmp; + int retries = SUPERIO_IDE_MAX_RETRIES; + + /* printk(" [ reading port 0x%x with retry ] ", port); */ + + do { + tmp = inb(port); + if (tmp == 0) + udelay(50); + } while (tmp == 0 && retries-- > 0); + + return tmp; + } + + return inb(port); +} + +void __init superio_ide_init_iops (struct hwif_s *hwif) +{ + u32 base, dmabase; + u8 tmp; + struct pci_dev *pdev = hwif->pci_dev; + u8 port = hwif->channel; + + base = pci_resource_start(pdev, port * 2) & ~3; + dmabase = pci_resource_start(pdev, 4) & ~3; + + superio_ide_status[port] = base + IDE_STATUS_OFFSET; + superio_ide_select[port] = base + IDE_SELECT_OFFSET; + superio_ide_dma_status[port] = dmabase + (!port ? 2 : 0xa); + + /* Clear error/interrupt, enable dma */ + tmp = superio_ide_inb(superio_ide_dma_status[port]); + outb(tmp | 0x66, superio_ide_dma_status[port]); + + /* We need to override inb to workaround a SuperIO errata */ + hwif->INB = superio_ide_inb; +} static int __devinit superio_probe(struct pci_dev *dev, const struct pci_device_id *id) { diff -Nru a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c --- a/drivers/parport/parport_gsc.c Sun Mar 14 14:20:08 2004 +++ b/drivers/parport/parport_gsc.c Sun Mar 14 14:20:08 2004 @@ -476,7 +476,7 @@ return 0; } -static void __devexit parport_remove_chip(struct parisc_device *dev) +static int __devexit parport_remove_chip(struct parisc_device *dev) { struct parport *p = dev->dev.driver_data; if (p) { @@ -495,6 +495,7 @@ parport_put_port(p); kfree (ops); /* hope no-one cached it */ } + return 0; } static struct parisc_device_id parport_tbl[] = { @@ -508,7 +509,7 @@ .name = "Parallel", .id_table = parport_tbl, .probe = parport_init_chip, - .remove = parport_remove_chip, + .remove = __devexit_p(parport_remove_chip), }; int __devinit parport_gsc_init(void) diff -Nru a/drivers/pci/pci.c b/drivers/pci/pci.c --- a/drivers/pci/pci.c Sun Mar 14 14:20:06 2004 +++ b/drivers/pci/pci.c Sun Mar 14 14:20:06 2004 @@ -686,7 +686,7 @@ if (!pci_dma_supported(dev, mask)) return -EIO; - dev->consistent_dma_mask = mask; + dev->dev.coherent_dma_mask = mask; return 0; } diff -Nru a/drivers/pci/probe.c b/drivers/pci/probe.c --- a/drivers/pci/probe.c Sun Mar 14 14:20:08 2004 +++ b/drivers/pci/probe.c Sun Mar 14 14:20:08 2004 @@ -570,7 +570,6 @@ /* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer) set this higher, assuming the system even supports it. */ dev->dma_mask = 0xffffffff; - dev->consistent_dma_mask = 0xffffffff; if (pci_setup_device(dev) < 0) { kfree(dev); return NULL; @@ -582,6 +581,7 @@ pci_name_device(dev); dev->dev.dma_mask = &dev->dma_mask; + dev->dev.coherent_dma_mask = 0xffffffffull; return dev; } diff -Nru a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c --- a/drivers/scsi/53c700.c Sun Mar 14 14:20:06 2004 +++ b/drivers/scsi/53c700.c Sun Mar 14 14:20:06 2004 @@ -137,6 +137,9 @@ #include "scsi.h" #include "hosts.h" +#include +#include + #include "53c700.h" /* NOTE: For 64 bit drivers there are points in the code where we use @@ -173,6 +176,8 @@ STATIC struct device_attribute *NCR_700_dev_attrs[]; +STATIC struct scsi_transport_template *NCR_700_transport_template = NULL; + static char *NCR_700_phase[] = { "", "after selection", @@ -236,6 +241,53 @@ NCR_700_MAX_OFFSET }; +/* This translates the SDTR message offset and period to a value + * which can be loaded into the SXFER_REG. + * + * NOTE: According to SCSI-2, the true transfer period (in ns) is + * actually four times this period value */ +static inline __u8 +NCR_700_offset_period_to_sxfer(struct NCR_700_Host_Parameters *hostdata, + __u8 offset, __u8 period) +{ + int XFERP; + + __u8 min_xferp = (hostdata->chip710 + ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP); + __u8 max_offset = (hostdata->chip710 + ? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET); + + if(offset == 0) + return 0; + + if(period < hostdata->min_period) { + printk(KERN_WARNING "53c700: Period %dns is less than this chip's minimum, setting to %d\n", period*4, NCR_700_SDTR_msg[3]*4); + period = hostdata->min_period; + } + XFERP = (period*4 * hostdata->sync_clock)/1000 - 4; + if(offset > max_offset) { + printk(KERN_WARNING "53c700: Offset %d exceeds chip maximum, setting to %d\n", + offset, max_offset); + offset = max_offset; + } + if(XFERP < min_xferp) { + printk(KERN_WARNING "53c700: XFERP %d is less than minium, setting to %d\n", + XFERP, min_xferp); + XFERP = min_xferp; + } + return (offset & 0x0f) | (XFERP & 0x07)<<4; +} + +static inline __u8 +NCR_700_get_SXFER(Scsi_Device *SDp) +{ + struct NCR_700_Host_Parameters *hostdata = + (struct NCR_700_Host_Parameters *)SDp->host->hostdata[0]; + + return NCR_700_offset_period_to_sxfer(hostdata, spi_offset(SDp), + spi_period(SDp)); +} + struct Scsi_Host * NCR_700_detect(Scsi_Host_Template *tpnt, struct NCR_700_Host_Parameters *hostdata) @@ -321,11 +373,13 @@ hostdata->script = script; hostdata->pScript = pScript; - dma_sync_single(hostdata->dev, pScript, sizeof(SCRIPT), DMA_TO_DEVICE); + dma_sync_single_for_device(hostdata->dev, pScript, sizeof(SCRIPT), DMA_TO_DEVICE); hostdata->state = NCR_700_HOST_FREE; hostdata->cmd = NULL; host->max_id = 7; host->max_lun = NCR_700_MAX_LUNS; + BUG_ON(NCR_700_transport_template == NULL); + host->transportt = NCR_700_transport_template; host->unique_id = hostdata->base; host->base = hostdata->base; hostdata->eh_complete = NULL; @@ -520,40 +574,6 @@ hostdata->cmd = NULL; } -/* This translates the SDTR message offset and period to a value - * which can be loaded into the SXFER_REG. - * - * NOTE: According to SCSI-2, the true transfer period (in ns) is - * actually four times this period value */ -STATIC inline __u8 -NCR_700_offset_period_to_sxfer(struct NCR_700_Host_Parameters *hostdata, - __u8 offset, __u8 period) -{ - int XFERP; - __u8 min_xferp = (hostdata->chip710 - ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP); - __u8 max_offset = (hostdata->chip710 - ? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET); - /* NOTE: NCR_700_SDTR_msg[3] contains our offer of the minimum - * period. It is set in NCR_700_chip_setup() */ - if(period < NCR_700_SDTR_msg[3]) { - printk(KERN_WARNING "53c700: Period %dns is less than this chip's minimum, setting to %d\n", period*4, NCR_700_SDTR_msg[3]*4); - period = NCR_700_SDTR_msg[3]; - } - XFERP = (period*4 * hostdata->sync_clock)/1000 - 4; - if(offset > max_offset) { - printk(KERN_WARNING "53c700: Offset %d exceeds chip maximum, setting to %d\n", - offset, max_offset); - offset = max_offset; - } - if(XFERP < min_xferp) { - printk(KERN_WARNING "53c700: XFERP %d is less than minium, setting to %d\n", - XFERP, min_xferp); - XFERP = min_xferp; - } - return (offset & 0x0f) | (XFERP & 0x07)<<4; -} - STATIC inline void NCR_700_unmap(struct NCR_700_Host_Parameters *hostdata, Scsi_Cmnd *SCp, struct NCR_700_command_slot *slot) @@ -724,11 +744,9 @@ * exact details of this calculation which is based on a * setting of the SXFER register */ min_period = 1000*(4+min_xferp)/(4*hostdata->sync_clock); - if(min_period > NCR_700_MIN_PERIOD) { - NCR_700_SDTR_msg[3] = min_period; - } - if(hostdata->chip710) - NCR_700_SDTR_msg[4] = NCR_710_MAX_OFFSET; + hostdata->min_period = NCR_700_MIN_PERIOD; + if(min_period > NCR_700_MIN_PERIOD) + hostdata->min_period = min_period; } STATIC void @@ -777,20 +795,25 @@ if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) { __u8 period = hostdata->msgin[3]; __u8 offset = hostdata->msgin[4]; - __u8 sxfer; - if(offset != 0 && period != 0) - sxfer = NCR_700_offset_period_to_sxfer(hostdata, offset, period); - else - sxfer = 0; + if(offset == 0 || period == 0) { + offset = 0; + period = 0; + } - if(sxfer != NCR_700_get_SXFER(SCp->device)) { - printk(KERN_INFO "scsi%d: (%d:%d) Synchronous at offset %d, period %dns\n", - host->host_no, pun, lun, - offset, period*4); - - NCR_700_set_SXFER(SCp->device, sxfer); + if(NCR_700_is_flag_set(SCp->device, NCR_700_DEV_PRINT_SYNC_NEGOTIATION)) { + if(spi_offset(SCp->device) != 0) + printk(KERN_INFO "scsi%d: (%d:%d) Synchronous at offset %d, period %dns\n", + host->host_no, pun, lun, + offset, period*4); + else + printk(KERN_INFO "scsi%d: (%d:%d) Asynchronous\n", + host->host_no, pun, lun); + NCR_700_clear_flag(SCp->device, NCR_700_DEV_PRINT_SYNC_NEGOTIATION); } + + spi_offset(SCp->device) = offset; + spi_period(SCp->device) = period; NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC); @@ -870,7 +893,7 @@ case A_REJECT_MSG: if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) { /* Rejected our sync negotiation attempt */ - NCR_700_set_SXFER(SCp->device, 0); + spi_period(SCp->device) = spi_offset(SCp->device) = 0; NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC); NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION); } else if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING)) { @@ -982,8 +1005,8 @@ SCp->cmnd[7] = hostdata->status[0]; SCp->use_sg = 0; SCp->sc_data_direction = SCSI_DATA_READ; - dma_sync_single(hostdata->dev, slot->pCmd, - SCp->cmd_len, DMA_TO_DEVICE); + dma_sync_single_for_device(hostdata->dev, slot->pCmd, + SCp->cmd_len, DMA_TO_DEVICE); SCp->request_bufflen = sizeof(SCp->sense_buffer); slot->dma_handle = dma_map_single(hostdata->dev, SCp->sense_buffer, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE); slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | sizeof(SCp->sense_buffer)); @@ -1007,7 +1030,7 @@ // SCp->cmnd[0] == INQUIRY && SCp->use_sg == 0) { // /* Piggy back the tag queueing support // * on this command */ - // dma_sync_single(hostdata->dev, + // dma_sync_single_for_cpu(hostdata->dev, // slot->dma_handle, // SCp->request_bufflen, // DMA_FROM_DEVICE); @@ -1396,6 +1419,8 @@ NCR_700_is_flag_clear(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC)) { memcpy(&hostdata->msgout[count], NCR_700_SDTR_msg, sizeof(NCR_700_SDTR_msg)); + hostdata->msgout[count+3] = spi_period(SCp->device); + hostdata->msgout[count+4] = spi_offset(SCp->device); count += sizeof(NCR_700_SDTR_msg); NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION); } @@ -1497,6 +1522,8 @@ printk(KERN_ERR "scsi%d: Bus Reset detected, executing command %p, slot %p, dsp %08x[%04x]\n", host->host_no, SCp, SCp == NULL ? NULL : SCp->host_scribble, dsp, dsp - hostdata->pScript); + scsi_report_bus_reset(host, 0); + /* clear all the negotiated parameters */ __shost_for_each_device(SDp, host) SDp->hostdata = 0; @@ -1942,6 +1969,9 @@ wait_for_completion(&complete); spin_lock_irq(SCp->device->host->host_lock); hostdata->eh_complete = NULL; + /* Revalidate the transport parameters of the failing device */ + if(hostdata->fast) + spi_schedule_dv_device(SCp->device); return SUCCESS; } @@ -1967,9 +1997,57 @@ return SUCCESS; } +STATIC void +NCR_700_set_period(struct scsi_device *SDp, int period) +{ + struct NCR_700_Host_Parameters *hostdata = + (struct NCR_700_Host_Parameters *)SDp->host->hostdata[0]; + + if(!hostdata->fast) + return; + + if(period < hostdata->min_period) + period = hostdata->min_period; + + spi_period(SDp) = period; + NCR_700_clear_flag(SDp, NCR_700_DEV_NEGOTIATED_SYNC); + NCR_700_clear_flag(SDp, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION); + NCR_700_set_flag(SDp, NCR_700_DEV_PRINT_SYNC_NEGOTIATION); +} + +STATIC void +NCR_700_set_offset(struct scsi_device *SDp, int offset) +{ + struct NCR_700_Host_Parameters *hostdata = + (struct NCR_700_Host_Parameters *)SDp->host->hostdata[0]; + int max_offset = hostdata->chip710 + ? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET; + + if(!hostdata->fast) + return; + + if(offset > max_offset) + offset = max_offset; + + /* if we're currently async, make sure the period is reasonable */ + if(spi_offset(SDp) == 0 && (spi_period(SDp) < hostdata->min_period || + spi_period(SDp) > 0xff)) + spi_period(SDp) = hostdata->min_period; + + spi_offset(SDp) = offset; + NCR_700_clear_flag(SDp, NCR_700_DEV_NEGOTIATED_SYNC); + NCR_700_clear_flag(SDp, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION); + NCR_700_set_flag(SDp, NCR_700_DEV_PRINT_SYNC_NEGOTIATION); +} + + + STATIC int NCR_700_slave_configure(Scsi_Device *SDp) { + struct NCR_700_Host_Parameters *hostdata = + (struct NCR_700_Host_Parameters *)SDp->host->hostdata[0]; + /* to do here: allocate memory; build a queue_full list */ if(SDp->tagged_supported) { /* do TCQ stuff here */ @@ -1977,6 +2055,13 @@ /* initialise to default depth */ scsi_adjust_queue_depth(SDp, 0, SDp->host->cmd_per_lun); } + if(hostdata->fast) { + /* Find the correct offset and period via domain validation */ + spi_dv_device(SDp); + } else { + spi_offset(SDp) = 0; + spi_period(SDp) = 0; + } return 0; } @@ -2033,3 +2118,27 @@ EXPORT_SYMBOL(NCR_700_detect); EXPORT_SYMBOL(NCR_700_release); EXPORT_SYMBOL(NCR_700_intr); + +static struct spi_function_template NCR_700_transport_functions = { + .set_period = NCR_700_set_period, + .show_period = 1, + .set_offset = NCR_700_set_offset, + .show_offset = 1, +}; + +static int __init NCR_700_init(void) +{ + NCR_700_transport_template = spi_attach_transport(&NCR_700_transport_functions); + if(!NCR_700_transport_template) + return -ENODEV; + return 0; +} + +static void __exit NCR_700_exit(void) +{ + spi_release_transport(NCR_700_transport_template); +} + +module_init(NCR_700_init); +module_exit(NCR_700_exit); + diff -Nru a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h --- a/drivers/scsi/53c700.h Sun Mar 14 14:20:06 2004 +++ b/drivers/scsi/53c700.h Sun Mar 14 14:20:06 2004 @@ -99,19 +99,9 @@ #define NCR_700_DEV_NEGOTIATED_SYNC (1<<16) #define NCR_700_DEV_BEGIN_SYNC_NEGOTIATION (1<<17) #define NCR_700_DEV_BEGIN_TAG_QUEUEING (1<<18) -#define NCR_700_DEV_TAG_STARVATION_WARNED (1<<19) +#define NCR_700_DEV_PRINT_SYNC_NEGOTIATION (1<<19) static inline void -NCR_700_set_SXFER(Scsi_Device *SDp, __u8 sxfer) -{ - SDp->hostdata = (void *)(((long)SDp->hostdata & 0xffffff00) | - (sxfer & 0xff)); -} -static inline __u8 NCR_700_get_SXFER(Scsi_Device *SDp) -{ - return (((unsigned long)SDp->hostdata) & 0xff); -} -static inline void NCR_700_set_depth(Scsi_Device *SDp, __u8 depth) { long l = (long)SDp->hostdata; @@ -215,6 +205,7 @@ __u8 tag_negotiated; __u8 rev; __u8 reselection_id; + __u8 min_period; /* Free list, singly linked by ITL_forw elements */ struct NCR_700_command_slot *free_list; @@ -438,6 +429,7 @@ #symbol, A_##symbol##_used[i], val)); \ } \ } + static inline __u8 NCR_700_mem_readb(struct Scsi_Host *host, __u32 reg) diff -Nru a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c --- a/drivers/scsi/BusLogic.c Sun Mar 14 14:20:08 2004 +++ b/drivers/scsi/BusLogic.c Sun Mar 14 14:20:08 2004 @@ -140,7 +140,7 @@ Name, Copyright Notice, and Electronic Mail Address. */ -static void __init BusLogic_AnnounceDriver(struct BusLogic_HostAdapter *HostAdapter) +static void BusLogic_AnnounceDriver(struct BusLogic_HostAdapter *HostAdapter) { BusLogic_Announce("***** BusLogic SCSI Driver Version " BusLogic_DriverVersion " of " diff -Nru a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig --- a/drivers/scsi/Kconfig Sun Mar 14 14:20:08 2004 +++ b/drivers/scsi/Kconfig Sun Mar 14 14:20:08 2004 @@ -196,6 +196,25 @@ there should be no noticeable performance impact as long as you have logging turned off. +menu "SCSI Transport Attributes" + depends on SCSI + +config SCSI_SPI_ATTRS + tristate "Parallel SCSI (SPI) Transport Attributes" + depends on SCSI + help + If you wish to export transport-specific information about + each attached SCSI device to sysfs, say Y. Otherwise, say N. + +config SCSI_FC_ATTRS + tristate "FiberChannel Transport Attributes" + depends on SCSI + help + If you wish to export transport-specific information about + each attached FiberChannel device to sysfs, say Y. + Otherwise, say N. + +endmenu menu "SCSI low-level drivers" depends on SCSI!=n @@ -438,6 +457,14 @@ If unsure, say N. +config SCSI_SATA_VITESSE + tristate "VITESSE VSC-7174 SATA support" + depends on SCSI_SATA && PCI && EXPERIMENTAL + help + This option enables support for Vitesse VSC7174 Serial ATA. + + If unsure, say N. + config SCSI_BUSLOGIC tristate "BusLogic SCSI support" depends on (PCI || ISA || MCA) && SCSI @@ -845,6 +872,7 @@ config SCSI_NCR_D700 tristate "NCR Dual 700 MCA SCSI support" depends on MCA && SCSI + select SCSI_SPI_ATTRS help This is a driver for the MicroChannel Dual 700 card produced by NCR and commonly used in 345x/35xx/4100 class machines. It always @@ -861,6 +889,7 @@ config SCSI_LASI700 tristate "HP Lasi SCSI support for 53c700/710" depends on GSC && SCSI + select SCSI_SPI_ATTRS help This is a driver for the SCSI controller in the Lasi chip found in many PA-RISC workstations & servers. If you do not know whether you @@ -1212,6 +1241,7 @@ config SCSI_SIM710 tristate "Simple 53c710 SCSI support (Compaq, NCR machines)" depends on (EISA || MCA) && SCSI + select SCSI_SPI_ATTRS ---help--- This driver for NCR53c710 based SCSI host adapters. diff -Nru a/drivers/scsi/Makefile b/drivers/scsi/Makefile --- a/drivers/scsi/Makefile Sun Mar 14 14:20:08 2004 +++ b/drivers/scsi/Makefile Sun Mar 14 14:20:08 2004 @@ -22,6 +22,14 @@ obj-$(CONFIG_SCSI) += scsi_mod.o +# --- NOTE ORDERING HERE --- +# For kernel non-modular link, transport attributes need to +# be initialised before drivers +# -------------------------- +obj-$(CONFIG_SCSI_SPI_ATTRS) += scsi_transport_spi.o +obj-$(CONFIG_SCSI_FC_ATTRS) += scsi_transport_fc.o + + obj-$(CONFIG_SCSI_AMIGA7XX) += amiga7xx.o 53c7xx.o obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o obj-$(CONFIG_A2091_SCSI) += a2091.o wd33c93.o @@ -41,7 +49,7 @@ obj-$(CONFIG_SUN3_SCSI) += sun3_scsi.o sun3_scsi_vme.o obj-$(CONFIG_MVME16x_SCSI) += mvme16x.o 53c7xx.o obj-$(CONFIG_BVME6000_SCSI) += bvme6000.o 53c7xx.o -obj-$(CONFIG_SCSI_SIM710) += sim710.o 53c700.o +obj-$(CONFIG_SCSI_SIM710) += 53c700.o sim710.o obj-$(CONFIG_SCSI_ADVANSYS) += advansys.o obj-$(CONFIG_SCSI_PCI2000) += pci2000.o obj-$(CONFIG_SCSI_PCI2220I) += pci2220i.o @@ -64,7 +72,7 @@ obj-$(CONFIG_SCSI_GENERIC_NCR5380) += g_NCR5380.o obj-$(CONFIG_SCSI_GENERIC_NCR5380_MMIO) += g_NCR5380_mmio.o obj-$(CONFIG_SCSI_NCR53C406A) += NCR53c406a.o -obj-$(CONFIG_SCSI_NCR_D700) += NCR_D700.o 53c700.o +obj-$(CONFIG_SCSI_NCR_D700) += 53c700.o NCR_D700.o obj-$(CONFIG_SCSI_NCR_Q720) += NCR_Q720_mod.o obj-$(CONFIG_SCSI_SYM53C416) += sym53c416.o obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas.o @@ -107,13 +115,14 @@ obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o obj-$(CONFIG_SCSI_FCAL) += fcal.o obj-$(CONFIG_SCSI_CPQFCTS) += cpqfc.o -obj-$(CONFIG_SCSI_LASI700) += lasi700.o 53c700.o +obj-$(CONFIG_SCSI_LASI700) += 53c700.o lasi700.o obj-$(CONFIG_SCSI_NSP32) += nsp32.o obj-$(CONFIG_SCSI_SATA_SVW) += libata.o sata_svw.o obj-$(CONFIG_SCSI_ATA_PIIX) += libata.o ata_piix.o obj-$(CONFIG_SCSI_SATA_PROMISE) += libata.o sata_promise.o obj-$(CONFIG_SCSI_SATA_SIL) += libata.o sata_sil.o obj-$(CONFIG_SCSI_SATA_VIA) += libata.o sata_via.o +obj-$(CONFIG_SCSI_SATA_VITESSE) += libata.o sata_vsc.o obj-$(CONFIG_ARM) += arm/ @@ -130,7 +139,7 @@ scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o scsi_mod-$(CONFIG_X86_PC9800) += scsi_pc98.o - + sd_mod-objs := sd.o sr_mod-objs := sr.o sr_ioctl.o sr_vendor.o initio-objs := ini9100u.o i91uscsi.o diff -Nru a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c --- a/drivers/scsi/aacraid/linit.c Sun Mar 14 14:20:07 2004 +++ b/drivers/scsi/aacraid/linit.c Sun Mar 14 14:20:07 2004 @@ -99,8 +99,8 @@ { 0x9005, 0x0285, 0x9005, 0x0288, 0, 0, 16 }, /* Adaptec 3230S (Harrier)*/ { 0x9005, 0x0285, 0x9005, 0x0289, 0, 0, 17 }, /* Adaptec 3240S (Tornado)*/ - { 0x9005, 0x0285, 0x9005, 0x028a, 0, 0, 18 }, /* ASR-2020S PCI-X ZCR (Skyhawk)*/ - { 0x9005, 0x0285, 0x9005, 0x028b, 0, 0, 19 }, /* ASR-2020S SO-DIMM PCI-X ZCR(Terminator)*/ + { 0x9005, 0x0285, 0x9005, 0x028a, 0, 0, 18 }, /* ASR-2020 ZCR PCI-X U320 */ + { 0x9005, 0x0285, 0x9005, 0x028b, 0, 0, 19 }, /* ASR-2025 ZCR DIMM U320 */ { 0x9005, 0x0285, 0x9005, 0x0290, 0, 0, 20 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II)*/ { 0x9005, 0x0285, 0x1028, 0x0287, 0, 0, 21 }, /* Perc 320/DC*/ @@ -116,6 +116,8 @@ { 0x9005, 0x0285, 0x0E11, 0x0295, 0, 0, 30 }, /* SATA 6Ch (Bearcat) */ { 0x9005, 0x0286, 0x9005, 0x028c, 0, 0, 31 }, /* ASR-2230S + ASR-2230SLP PCI-X (Lancer) */ + { 0x9005, 0x0285, 0x9005, 0x028e, 0, 0, 32 }, /* ASR-2020SA (ZCR PCI-X SATA) */ + { 0x9005, 0x0285, 0x9005, 0x028f, 0, 0, 33 }, /* ASR-2025SA (ZCR DIMM SATA) */ { 0,} }; MODULE_DEVICE_TABLE(pci, aac_pci_tbl); @@ -145,8 +147,8 @@ { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 3230S ", 2 }, /* Adaptec 3230S (Harrier)*/ { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 3240S ", 2 }, /* Adaptec 3240S (Tornado)*/ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2020S PCI-X ", 2 }, /* ASR-2020S PCI-X ZCR (Skyhawk)*/ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2020S PCI-X ", 2 }, /* ASR-2020S SO-DIMM PCI-X ZCR(Terminator)*/ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2020ZCR ", 2 }, /* ASR-2020 ZCR PCI-X U320 */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2025ZCR ", 2 }, /* ASR-2025 ZCR DIMM U320 */ { aac_rx_init, "aacraid", "ADAPTEC ", "AAR-2410SA SATA ", 2 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II)*/ { aac_rx_init, "percraid", "DELL ", "PERC 320/DC ", 2, AAC_QUIRK_31BIT }, /* Perc 320/DC*/ @@ -162,6 +164,8 @@ { aac_rx_init, "aacraid", "ADAPTEC ", "SATA 6Channel ", 1 }, /* SATA 6Ch (Bearcat) */ { aac_rkt_init,"aacraid", "ADAPTEC ", "ASR-2230S PCI-X ", 2 }, /* ASR-2230S + ASR-2230SLP PCI-X (Lancer) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2020SA ", 1 }, /* ASR-2020SA (ZCR PCI-X SATA) */ + { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2025SA ", 1 }, /* ASR-2025SA (ZCR DIMM SATA) */ }; /** diff -Nru a/drivers/scsi/aacraid/rkt.c b/drivers/scsi/aacraid/rkt.c --- a/drivers/scsi/aacraid/rkt.c Sun Mar 14 14:20:08 2004 +++ b/drivers/scsi/aacraid/rkt.c Sun Mar 14 14:20:08 2004 @@ -427,6 +427,7 @@ dev->a_ops.adapter_disable_int = aac_rkt_disable_interrupt; dev->a_ops.adapter_notify = aac_rkt_notify_adapter; dev->a_ops.adapter_sync_cmd = rkt_sync_cmd; + dev->a_ops.adapter_check_health = aac_rkt_check_health; if (aac_init_adapter(dev) == NULL) return -1; diff -Nru a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c --- a/drivers/scsi/aacraid/rx.c Sun Mar 14 14:20:09 2004 +++ b/drivers/scsi/aacraid/rx.c Sun Mar 14 14:20:09 2004 @@ -427,6 +427,7 @@ dev->a_ops.adapter_disable_int = aac_rx_disable_interrupt; dev->a_ops.adapter_notify = aac_rx_notify_adapter; dev->a_ops.adapter_sync_cmd = rx_sync_cmd; + dev->a_ops.adapter_check_health = aac_rx_check_health; if (aac_init_adapter(dev) == NULL) return -1; diff -Nru a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c --- a/drivers/scsi/aacraid/sa.c Sun Mar 14 14:20:07 2004 +++ b/drivers/scsi/aacraid/sa.c Sun Mar 14 14:20:07 2004 @@ -407,6 +407,7 @@ dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt; dev->a_ops.adapter_notify = aac_sa_notify_adapter; dev->a_ops.adapter_sync_cmd = sa_sync_cmd; + dev->a_ops.adapter_check_health = aac_sa_check_health; dprintk(("FUNCDONE\n")); diff -Nru a/drivers/scsi/aic7xxx/Kconfig.aic79xx b/drivers/scsi/aic7xxx/Kconfig.aic79xx --- a/drivers/scsi/aic7xxx/Kconfig.aic79xx Sun Mar 14 14:20:07 2004 +++ b/drivers/scsi/aic7xxx/Kconfig.aic79xx Sun Mar 14 14:20:07 2004 @@ -4,7 +4,7 @@ # config SCSI_AIC79XX tristate "Adaptec AIC79xx U320 support" - depends on PCI + depends on PCI && SCSI help This driver supports all of Adaptec's Ultra 320 PCI-X based SCSI controllers. diff -Nru a/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/drivers/scsi/aic7xxx/Kconfig.aic7xxx --- a/drivers/scsi/aic7xxx/Kconfig.aic7xxx Sun Mar 14 14:20:06 2004 +++ b/drivers/scsi/aic7xxx/Kconfig.aic7xxx Sun Mar 14 14:20:06 2004 @@ -4,7 +4,7 @@ # config SCSI_AIC7XXX tristate "Adaptec AIC7xxx Fast -> U160 support (New Driver)" - depends on PCI || EISA + depends on (PCI || EISA) && SCSI ---help--- This driver supports all of Adaptec's Fast through Ultra 160 PCI based SCSI controllers as well as the aic7770 based EISA and VLB diff -Nru a/drivers/scsi/constants.c b/drivers/scsi/constants.c --- a/drivers/scsi/constants.c Sun Mar 14 14:20:08 2004 +++ b/drivers/scsi/constants.c Sun Mar 14 14:20:08 2004 @@ -1135,7 +1135,7 @@ static const char * hostbyte_table[]={ "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", "DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR", -"DID_PASSTHROUGH", "DID_SOFT_ERROR", NULL}; +"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY", NULL}; void print_hostbyte(int scsiresult) { static int maxcode=0; diff -Nru a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c --- a/drivers/scsi/cpqfcTSinit.c Sun Mar 14 14:20:06 2004 +++ b/drivers/scsi/cpqfcTSinit.c Sun Mar 14 14:20:06 2004 @@ -46,10 +46,6 @@ #include // request_region() prototype #include -#ifdef __alpha__ -#define __KERNEL_SYSCALLS__ -#endif -#include #include #include // ioctl related #include diff -Nru a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c --- a/drivers/scsi/dc395x.c Sun Mar 14 14:20:06 2004 +++ b/drivers/scsi/dc395x.c Sun Mar 14 14:20:06 2004 @@ -62,6 +62,10 @@ #include #include +#define DC395X_NAME "dc395x" +#define DC395X_BANNER "Tekram DC395(U/UW/F), DC315(U) - ASIC TRM-S1040" +#define DC395X_VERSION "v2.05, 2004/03/08" + /*--------------------------------------------------------------------------- Features ---------------------------------------------------------------------------*/ @@ -82,22 +86,16 @@ #define DBG_KG 0x0001 #define DBG_0 0x0002 #define DBG_1 0x0004 -#define DBG_DCB 0x0008 -#define DBG_PARSE 0x0010 /* debug command line parsing */ -#define DBG_SGPARANOIA 0x0020 +#define DBG_SG 0x0020 #define DBG_FIFO 0x0040 #define DBG_PIO 0x0080 -#define DBG_RECURSION 0x0100 /* check for excessive recursion */ -#define DBG_MALLOC 0x0200 /* report on memory allocations */ -#define DBG_TRACE 0x0400 -#define DBG_TRACEALL 0x0800 /* * Set set of things to output debugging for. * Undefine to remove all debugging */ -/*#define DEBUG_MASK (DBG_0|DBG_1|DBG_DCB|DBG_PARSE|DBG_SGPARANOIA|DBG_FIFO|DBG_PIO|DBG_TRACE|DBG_TRACEALL)*/ +/*#define DEBUG_MASK (DBG_0|DBG_1|DBG_SG|DBG_FIFO|DBG_PIO)*/ /*#define DEBUG_MASK DBG_0*/ @@ -138,72 +136,6 @@ #endif -/* - * The recursion debugging just counts entries into the driver and - * prints out a messge if it exceeds a certain limit. This variable - * hold the count. - */ -#if debug_enabled(DBG_RECURSION) -static int dbg_in_driver = 0; -#endif - - -/* - * Memory allocation debugging - * Just reports when memory is allocated and/or released. - */ -#if debug_enabled(DBG_MALLOC) -inline void *dc395x_kmalloc(size_t sz, int fl) -{ - void *ptr = kmalloc(sz, fl); - dprintkl(KERN_DEBUG, "Alloc %i bytes @ %p w/ fl %08x\n", sz, ptr, fl); - return ptr; -} -inline void dc395x_kfree(const void *adr) -{ - dprintkl(KERN_DEBUG, "Free mem @ %p\n", adr); - kfree(adr); -} -#else -#define dc395x_kmalloc(sz, fl) kmalloc(sz, fl) -#define dc395x_kfree(adr) kfree(adr) -#endif - - -/* - * Debug/trace stuff - */ -#if debug_enabled(DBG_TRACEALL) -# define TRACEOUTALL(x...) printk ( x) -#else -# define TRACEOUTALL(x...) do {} while (0) -#endif - -#if debug_enabled(DBG_TRACE|DBG_TRACEALL) -# define DEBUGTRACEBUFSZ 512 -static char tracebuf[64]; -static char traceoverflow[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; -# define TRACEPRINTF(x...) \ - do { \ - int ln = sprintf(tracebuf, x); \ - if (srb->debugpos + ln >= DEBUGTRACEBUFSZ) { \ - srb->debugtrace[srb->debugpos] = 0; \ - srb->debugpos = DEBUGTRACEBUFSZ/5; \ - srb->debugtrace[srb->debugpos++] = '>'; \ - } \ - sprintf(srb->debugtrace + srb->debugpos, "%s", tracebuf); \ - srb->debugpos += ln - 1; \ - } while (0) -# define TRACEOUT(x...) printk (x) -#else -# define TRACEPRINTF(x...) do {} while (0) -# define TRACEOUT(x...) do {} while (0) -#endif - - -/*--------------------------------------------------------------------------- - ---------------------------------------------------------------------------*/ - #ifndef PCI_VENDOR_ID_TEKRAM #define PCI_VENDOR_ID_TEKRAM 0x1DE1 /* Vendor ID */ #endif @@ -212,32 +144,16 @@ #endif - #define DC395x_LOCK_IO(dev,flags) spin_lock_irqsave(((struct Scsi_Host *)dev)->host_lock, flags) #define DC395x_UNLOCK_IO(dev,flags) spin_unlock_irqrestore(((struct Scsi_Host *)dev)->host_lock, flags) -#define DC395x_ACB_INITLOCK(acb) spin_lock_init(&acb->smp_lock) -#define DC395x_ACB_LOCK(acb,acb_flags) if (!acb->lock_level_count[cpuid]) { spin_lock_irqsave(&acb->smp_lock,acb_flags); acb->lock_level_count[cpuid]++; } else { acb->lock_level_count[cpuid]++; } -#define DC395x_ACB_UNLOCK(acb,acb_flags) if (--acb->lock_level_count[cpuid] == 0) { spin_unlock_irqrestore(&acb->smp_lock,acb_flags); } - -#define DC395x_SMP_IO_LOCK(dev,irq_flags) spin_lock_irqsave(((struct Scsi_Host*)dev)->host_lock,irq_flags) -#define DC395x_SMP_IO_UNLOCK(dev,irq_flags) spin_unlock_irqrestore(((struct Scsi_Host*)dev)->host_lock,irq_flags) - - #define DC395x_read8(acb,address) (u8)(inb(acb->io_port_base + (address))) -#define DC395x_read8_(address, base) (u8)(inb((USHORT)(base) + (address))) #define DC395x_read16(acb,address) (u16)(inw(acb->io_port_base + (address))) #define DC395x_read32(acb,address) (u32)(inl(acb->io_port_base + (address))) #define DC395x_write8(acb,address,value) outb((value), acb->io_port_base + (address)) -#define DC395x_write8_(address,value,base) outb((value), (USHORT)(base) + (address)) #define DC395x_write16(acb,address,value) outw((value), acb->io_port_base + (address)) #define DC395x_write32(acb,address,value) outl((value), acb->io_port_base + (address)) - -#define BUS_ADDR(sg) sg_dma_address(&(sg)) -#define CPU_ADDR(sg) (page_address((sg).page)+(sg).offset) -#define PAGE_ADDRESS(sg) page_address((sg)->page) - /* cmd->result */ #define RES_TARGET 0x000000FF /* Target State */ #define RES_TARGET_LNX STATUS_MASK /* Only official ... */ @@ -254,20 +170,22 @@ #define SET_RES_DID(who,did) { who &= ~RES_DID; who |= (int)(did) << 16; } #define SET_RES_DRV(who,drv) { who &= ~RES_DRV; who |= (int)(drv) << 24; } -/* -************************************************************************** -*/ #define TAG_NONE 255 +/* + * srb->segement_x is the hw sg list. It is always allocated as a + * DC395x_MAX_SG_LISTENTRY entries in a linear block which does not + * cross a page boundy. + */ +#define SEGMENTX_LEN (sizeof(struct SGentry)*DC395x_MAX_SG_LISTENTRY) + + struct SGentry { u32 address; /* bus! address */ u32 length; }; - -/* - * The SEEPROM structure for TRM_S1040 - */ +/* The SEEPROM structure for TRM_S1040 */ struct NVRamTarget { u8 cfg0; /* Target configuration byte 0 */ u8 period; /* Target period */ @@ -275,7 +193,6 @@ u8 cfg3; /* Target configuration byte 3 */ }; - struct NvRamType { u8 sub_vendor_id[2]; /* 0,1 Sub Vendor ID */ u8 sub_sys_id[2]; /* 2,3 Sub System ID */ @@ -302,28 +219,31 @@ u16 cksum; /* 126,127 */ }; - -/*----------------------------------------------------------------------- - SCSI Request Block - -----------------------------------------------------------------------*/ struct ScsiReqBlk { struct list_head list; /* next/prev ptrs for srb lists */ struct DeviceCtlBlk *dcb; - - /* HW scatter list (up to 64 entries) */ - struct SGentry *segment_x; Scsi_Cmnd *cmd; - unsigned char *virt_addr; /* set by update_sg_list */ + struct SGentry *segment_x; /* Linear array of hw sg entries (up to 64 entries) */ + u32 sg_bus_addr; /* Bus address of sg list (ie, of segment_x) */ - u32 total_xfer_length; - u32 xferred; /* Backup for the already xferred len */ + u8 sg_count; /* No of HW sg entries for this request */ + u8 sg_index; /* Index of HW sg entry for this request */ + u32 total_xfer_length; /* Total number of bytes remaining to be transfered */ + unsigned char *virt_addr; /* Virtual address of current transfer position */ - u32 sg_bus_addr; /* bus address of DC395x scatterlist */ + /* + * The sense buffer handling function, request_sense, uses + * the first hw sg entry (segment_x[0]) and the transfer + * length (total_xfer_length). While doing this it stores the + * original values into the last sg hw list + * (srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1] and the + * total_xfer_length in xferred. These values are restored in + * pci_unmap_srb_sense. This is the only place xferred is used. + */ + u32 xferred; /* Saved copy of total_xfer_length */ u16 state; - u8 sg_count; - u8 sg_index; u8 msgin_buf[6]; u8 msgout_buf[6]; @@ -339,17 +259,8 @@ u8 flag; u8 scsi_phase; - -#if debug_enabled(DBG_TRACE|DBG_TRACEALL) - u16 debugpos; - char *debugtrace; -#endif }; - -/*----------------------------------------------------------------------- - Device Control Block - -----------------------------------------------------------------------*/ struct DeviceCtlBlk { struct list_head list; /* next/prev ptrs for the dcb list */ struct AdapterCtlBlk *acb; @@ -377,9 +288,6 @@ u8 init_tcq_flag; }; -/*----------------------------------------------------------------------- - Adapter Control Block - -----------------------------------------------------------------------*/ struct AdapterCtlBlk { struct Scsi_Host *scsi_host; @@ -423,80 +331,63 @@ }; - - /*--------------------------------------------------------------------------- Forward declarations ---------------------------------------------------------------------------*/ -static void data_out_phase0(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, - u16 * pscsi_status); -static void data_in_phase0(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, - u16 * pscsi_status); -static void command_phase0(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, - u16 * pscsi_status); -static void status_phase0(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, - u16 * pscsi_status); -static void msgout_phase0(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, - u16 * pscsi_status); -static void msgin_phase0(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, - u16 * pscsi_status); -static void data_out_phase1(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, - u16 * pscsi_status); -static void data_in_phase1(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, - u16 * pscsi_status); -static void command_phase1(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, - u16 * pscsi_status); -static void status_phase1(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, - u16 * pscsi_status); -static void msgout_phase1(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, - u16 * pscsi_status); -static void msgin_phase1(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, - u16 * pscsi_status); +static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status); +static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status); +static void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status); +static void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status); +static void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status); +static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status); +static void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status); +static void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status); +static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status); +static void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status); +static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status); +static void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status); static void nop0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status); -static void nop1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status); + u16 *pscsi_status); +static void nop1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status); static void set_basic_config(struct AdapterCtlBlk *acb); static void cleanup_after_transfer(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb); + struct ScsiReqBlk *srb); static void reset_scsi_bus(struct AdapterCtlBlk *acb); static void data_io_transfer(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, u16 io_dir); + struct ScsiReqBlk *srb, u16 io_dir); static void disconnect(struct AdapterCtlBlk *acb); static void reselect(struct AdapterCtlBlk *acb); static u8 start_scsi(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb); -static void build_srb(Scsi_Cmnd * cmd, struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb); + struct ScsiReqBlk *srb); +static void build_srb(Scsi_Cmnd *cmd, struct DeviceCtlBlk *dcb, + struct ScsiReqBlk *srb); static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_code, - Scsi_Cmnd * cmd, u8 force); + Scsi_Cmnd *cmd, u8 force); static void scsi_reset_detect(struct AdapterCtlBlk *acb); -static void pci_unmap_srb(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb); +static void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb); static void pci_unmap_srb_sense(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb); + struct ScsiReqBlk *srb); static inline void enable_msgout_abort(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb); -static void srb_done(struct AdapterCtlBlk *acb, - struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb); -static void request_sense(struct AdapterCtlBlk *acb, - struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb); + struct ScsiReqBlk *srb); +static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, + struct ScsiReqBlk *srb); +static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, + struct ScsiReqBlk *srb); static inline void set_xfer_rate(struct AdapterCtlBlk *acb, - struct DeviceCtlBlk *dcb); + struct DeviceCtlBlk *dcb); static void waiting_timeout(unsigned long ptr); @@ -504,11 +395,7 @@ Static Data ---------------------------------------------------------------------------*/ static u16 current_sync_offset = 0; -static char monitor_next_irq = 0; -/* - * dc395x_statev = (void *)dc395x_scsi_phase0[phase] - */ static void *dc395x_scsi_phase0[] = { data_out_phase0,/* phase:0 */ data_in_phase0, /* phase:1 */ @@ -520,9 +407,6 @@ msgin_phase0, /* phase:7 */ }; -/* - * dc395x_statev = (void *)dc395x_scsi_phase1[phase] - */ static void *dc395x_scsi_phase1[] = { data_out_phase1,/* phase:0 */ data_in_phase1, /* phase:1 */ @@ -558,8 +442,6 @@ /* real period:48ns,76ns,100ns,124ns,148ns,176ns,200ns,248ns */ static u8 clock_period[] = { 12, 18, 25, 31, 37, 43, 50, 62 }; static u16 clock_speed[] = { 200, 133, 100, 80, 67, 58, 50, 40 }; -/* real period:48ns,72ns,100ns,124ns,148ns,172ns,200ns,248ns */ - /*--------------------------------------------------------------------------- @@ -655,8 +537,9 @@ /* - * Safe settings. If set to zero the the BIOS/default values with command line - * overrides will be used. If set to 1 then safe and slow settings will be used. + * Safe settings. If set to zero the the BIOS/default values with + * command line overrides will be used. If set to 1 then safe and + * slow settings will be used. */ static int use_safe_settings = 0; module_param_named(safe, use_safe_settings, bool, 0); @@ -686,8 +569,7 @@ * set_safe_settings - if the use_safe_settings option is set then * set all values to the safe and slow values. **/ -static -void __init set_safe_settings(void) +static void __init set_safe_settings(void) { if (use_safe_settings) { @@ -706,25 +588,24 @@ * fix_settings - reset any boot parameters which are out of range * back to the default values. **/ -static -void __init fix_settings(void) +static void __init fix_settings(void) { int i; - dprintkdbg(DBG_PARSE, "setup %08x %08x %08x %08x %08x %08x\n", - cfg_data[CFG_ADAPTER_ID].value, - cfg_data[CFG_MAX_SPEED].value, - cfg_data[CFG_DEV_MODE].value, - cfg_data[CFG_ADAPTER_MODE].value, - cfg_data[CFG_TAGS].value, - cfg_data[CFG_RESET_DELAY].value); + dprintkdbg(DBG_1, + "setup: AdapterId=%08x MaxSpeed=%08x DevMode=%08x " + "AdapterMode=%08x Tags=%08x ResetDelay=%08x\n", + cfg_data[CFG_ADAPTER_ID].value, + cfg_data[CFG_MAX_SPEED].value, + cfg_data[CFG_DEV_MODE].value, + cfg_data[CFG_ADAPTER_MODE].value, + cfg_data[CFG_TAGS].value, + cfg_data[CFG_RESET_DELAY].value); for (i = 0; i < CFG_NUM; i++) { - if (cfg_data[i].value < cfg_data[i].min || - cfg_data[i].value > cfg_data[i].max) - { + if (cfg_data[i].value < cfg_data[i].min + || cfg_data[i].value > cfg_data[i].max) cfg_data[i].value = cfg_data[i].def; - } } } @@ -734,8 +615,8 @@ * Mapping from the eeprom delay index value (index into this array) * to the the number of actual seconds that the delay should be for. */ -static -char __initdata eeprom_index_to_delay_map[] = { 1, 3, 5, 10, 16, 30, 60, 120 }; +static char __initdata eeprom_index_to_delay_map[] = + { 1, 3, 5, 10, 16, 30, 60, 120 }; /** @@ -744,25 +625,24 @@ * * @eeprom: The eeprom structure in which we find the delay index to map. **/ -static -void __init eeprom_index_to_delay(struct NvRamType *eeprom) +static void __init eeprom_index_to_delay(struct NvRamType *eeprom) { eeprom->delay_time = eeprom_index_to_delay_map[eeprom->delay_time]; } /** - * delay_to_eeprom_index - Take a delay in seconds and return the closest - * eeprom index which will delay for at least that amount of seconds. + * delay_to_eeprom_index - Take a delay in seconds and return the + * closest eeprom index which will delay for at least that amount of + * seconds. * * @delay: The delay, in seconds, to find the eeprom index for. **/ static int __init delay_to_eeprom_index(int delay) { u8 idx = 0; - while (idx < 7 && eeprom_index_to_delay_map[idx] < delay) { + while (idx < 7 && eeprom_index_to_delay_map[idx] < delay) idx++; - } return idx; } @@ -774,38 +654,34 @@ * * @eeprom: The eeprom data to override with command line options. **/ -static -void __init eeprom_override(struct NvRamType *eeprom) +static void __init eeprom_override(struct NvRamType *eeprom) { u8 id; /* Adapter Settings */ - if (cfg_data[CFG_ADAPTER_ID].value != CFG_PARAM_UNSET) { - eeprom->scsi_id = - (u8)cfg_data[CFG_ADAPTER_ID].value; - } - if (cfg_data[CFG_ADAPTER_MODE].value != CFG_PARAM_UNSET) { - eeprom->channel_cfg = - (u8)cfg_data[CFG_ADAPTER_MODE].value; - } - if (cfg_data[CFG_RESET_DELAY].value != CFG_PARAM_UNSET) { - eeprom->delay_time = - delay_to_eeprom_index(cfg_data[CFG_RESET_DELAY].value); - } - if (cfg_data[CFG_TAGS].value != CFG_PARAM_UNSET) { + if (cfg_data[CFG_ADAPTER_ID].value != CFG_PARAM_UNSET) + eeprom->scsi_id = (u8)cfg_data[CFG_ADAPTER_ID].value; + + if (cfg_data[CFG_ADAPTER_MODE].value != CFG_PARAM_UNSET) + eeprom->channel_cfg = (u8)cfg_data[CFG_ADAPTER_MODE].value; + + if (cfg_data[CFG_RESET_DELAY].value != CFG_PARAM_UNSET) + eeprom->delay_time = delay_to_eeprom_index( + cfg_data[CFG_RESET_DELAY].value); + + if (cfg_data[CFG_TAGS].value != CFG_PARAM_UNSET) eeprom->max_tag = (u8)cfg_data[CFG_TAGS].value; - } /* Device Settings */ for (id = 0; id < DC395x_MAX_SCSI_ID; id++) { - if (cfg_data[CFG_DEV_MODE].value != CFG_PARAM_UNSET) { + if (cfg_data[CFG_DEV_MODE].value != CFG_PARAM_UNSET) eeprom->target[id].cfg0 = - (u8)cfg_data[CFG_DEV_MODE].value; - } - if (cfg_data[CFG_MAX_SPEED].value != CFG_PARAM_UNSET) { + (u8)cfg_data[CFG_DEV_MODE].value; + + if (cfg_data[CFG_MAX_SPEED].value != CFG_PARAM_UNSET) eeprom->target[id].period = - (u8)cfg_data[CFG_MAX_SPEED].value; - } + (u8)cfg_data[CFG_MAX_SPEED].value; + } } @@ -813,39 +689,21 @@ /*--------------------------------------------------------------------------- ---------------------------------------------------------------------------*/ -/** - * list_size - Returns the size (in number of entries) of the - * supplied list. - * - * @head: The pointer to the head of the list to count the items in. - **/ -static -unsigned int list_size(struct list_head *head) +static unsigned int list_size(struct list_head *head) { unsigned int count = 0; struct list_head *pos; list_for_each(pos, head) count++; return count; -} +} -/** - * dcb_get_next - Given a dcb return the next dcb in the list of - * dcb's, wrapping back to the start of the dcb list if required. - * Returns the supplied dcb if there is only one dcb in the list. - * - * @head: The pointer to the head of the list to count the items in. - * @pos: The pointer the dcb for which we are searching for the - * following dcb. - **/ -static -struct DeviceCtlBlk *dcb_get_next( - struct list_head *head, +static struct DeviceCtlBlk *dcb_get_next(struct list_head *head, struct DeviceCtlBlk *pos) { int use_next = 0; - struct DeviceCtlBlk* next = NULL; + struct DeviceCtlBlk* next = NULL; struct DeviceCtlBlk* i; if (list_empty(head)) @@ -870,22 +728,7 @@ } -/* - * Queueing philosphy: - * There are a couple of lists: - * - Waiting: Contains a list of SRBs not yet sent (per DCB) - * - Free: List of free SRB slots - * - * If there are no waiting commands for the DCB, the new one is sent to the bus - * otherwise the oldest one is taken from the Waiting list and the new one is - * queued to the Waiting List - * - * Lists are managed using two pointers and eventually a counter - */ - -/* Nomen est omen ... */ -static inline -void free_tag(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) +static void free_tag(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { if (srb->tag_number < 255) { dcb->tag_mask &= ~(1 << srb->tag_number); /* free tag mask */ @@ -895,9 +738,8 @@ /* Find cmd in SRB list */ -inline static -struct ScsiReqBlk *find_cmd(Scsi_Cmnd *cmd, - struct list_head *head) +inline static struct ScsiReqBlk *find_cmd(Scsi_Cmnd *cmd, + struct list_head *head) { struct ScsiReqBlk *i; list_for_each_entry(i, head, list) @@ -907,88 +749,59 @@ } -/* - * srb_get_free - Return a free srb from the list of free SRBs that - * is stored with the acb. - */ -static -struct ScsiReqBlk *srb_get_free(struct AdapterCtlBlk *acb) +static struct ScsiReqBlk *srb_get_free(struct AdapterCtlBlk *acb) { struct list_head *head = &acb->srb_free_list; - struct ScsiReqBlk *srb; + struct ScsiReqBlk *srb = NULL; if (!list_empty(head)) { srb = list_entry(head->next, struct ScsiReqBlk, list); list_del(head->next); - dprintkdbg(DBG_0, "srb_get_free: got srb %p\n", srb); - } else { - srb = NULL; - dprintkl(KERN_ERR, "Out of Free SRBs :-(\n"); + dprintkdbg(DBG_0, "srb_get_free: srb=%p\n", srb); } return srb; } -/* - * srb_free_insert - Insert an srb to the head of the free list - * stored in the acb. - */ -static -void srb_free_insert(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) +static void srb_free_insert(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) { - dprintkdbg(DBG_0, "srb_free_insert: put srb %p\n", srb); - list_add_tail(&srb->list, &acb->srb_free_list); + dprintkdbg(DBG_0, "srb_free_insert: srb=%p\n", srb); + list_add_tail(&srb->list, &acb->srb_free_list); } -/* - * srb_waiting_insert - Insert an srb to the head of the wiating list - * stored in the dcb. - */ -static -void srb_waiting_insert(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) +static void srb_waiting_insert(struct DeviceCtlBlk *dcb, + struct ScsiReqBlk *srb) { - dprintkdbg(DBG_0, "srb_waiting_insert: srb %p cmd %li\n", srb, srb->cmd->pid); - list_add(&srb->list, &dcb->srb_waiting_list); + dprintkdbg(DBG_0, "srb_waiting_insert: (pid#%li) <%02i-%i> srb=%p\n", + srb->cmd->pid, dcb->target_id, dcb->target_lun, srb); + list_add(&srb->list, &dcb->srb_waiting_list); } -/* - * srb_waiting_append - Append an srb to the tail of the waiting list - * stored in the dcb. - */ -static inline -void srb_waiting_append(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) +static void srb_waiting_append(struct DeviceCtlBlk *dcb, + struct ScsiReqBlk *srb) { - dprintkdbg(DBG_0, "srb_waiting_append: srb %p cmd %li\n", srb, srb->cmd->pid); - list_add_tail(&srb->list, &dcb->srb_waiting_list); + dprintkdbg(DBG_0, "srb_waiting_append: (pid#%li) <%02i-%i> srb=%p\n", + srb->cmd->pid, dcb->target_id, dcb->target_lun, srb); + list_add_tail(&srb->list, &dcb->srb_waiting_list); } -/* - * srb_going_append - Append an srb to the tail of the going list - * stored in the dcb. - */ -static inline -void srb_going_append(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) +static void srb_going_append(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { - dprintkdbg(DBG_0, "srb_going_append: srb %p\n", srb); - list_add_tail(&srb->list, &dcb->srb_going_list); + dprintkdbg(DBG_0, "srb_going_append: (pid#%li) <%02i-%i> srb=%p\n", + srb->cmd->pid, dcb->target_id, dcb->target_lun, srb); + list_add_tail(&srb->list, &dcb->srb_going_list); } - -/* - * srb_going_remove - Remove an srb from the going list stored in the - * dcb. - */ -static -void srb_going_remove(struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) +static void srb_going_remove(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { struct ScsiReqBlk *i; struct ScsiReqBlk *tmp; - dprintkdbg(DBG_0, "srb_going_remove: srb %p\n", srb); + dprintkdbg(DBG_0, "srb_going_remove: (pid#%li) <%02i-%i> srb=%p\n", + srb->cmd->pid, dcb->target_id, dcb->target_lun, srb); list_for_each_entry_safe(i, tmp, &dcb->srb_going_list, list) if (i == srb) { @@ -998,17 +811,13 @@ } -/* - * srb_waiting_remove - Remove an srb from the waiting list stored in the - * dcb. - */ -static -void srb_waiting_remove(struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) +static void srb_waiting_remove(struct DeviceCtlBlk *dcb, + struct ScsiReqBlk *srb) { struct ScsiReqBlk *i; struct ScsiReqBlk *tmp; - dprintkdbg(DBG_0, "srb_waiting_remove: srb %p\n", srb); + dprintkdbg(DBG_0, "srb_waiting_remove: (pid#%li) <%02i-%i> srb=%p\n", + srb->cmd->pid, dcb->target_id, dcb->target_lun, srb); list_for_each_entry_safe(i, tmp, &dcb->srb_waiting_list, list) if (i == srb) { @@ -1018,37 +827,28 @@ } -/* - * srb_going_to_waiting_move - Remove an srb from the going list in - * the dcb and insert it at the head of the waiting list in the dcb. - */ -static -void srb_going_to_waiting_move(struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) +static void srb_going_to_waiting_move(struct DeviceCtlBlk *dcb, + struct ScsiReqBlk *srb) { - dprintkdbg(DBG_0, "srb_going_waiting_move: srb %p, pid = %li\n", srb, srb->cmd->pid); + dprintkdbg(DBG_0, + "srb_going_to_waiting_move: (pid#%li) <%02i-%i> srb=%p\n", + srb->cmd->pid, dcb->target_id, dcb->target_lun, srb); list_move(&srb->list, &dcb->srb_waiting_list); } -/* - * srb_waiting_to_going_move - Remove an srb from the waiting list in - * the dcb and insert it at the head of the going list in the dcb. - */ -static -void srb_waiting_to_going_move(struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) -{ - /* Remove from waiting list */ - dprintkdbg(DBG_0, "srb_waiting_to_going: srb %p\n", srb); - TRACEPRINTF("WtG *"); +static void srb_waiting_to_going_move(struct DeviceCtlBlk *dcb, + struct ScsiReqBlk *srb) +{ + dprintkdbg(DBG_0, + "srb_waiting_to_going_move: (pid#%li) <%02i-%i> srb=%p\n", + srb->cmd->pid, dcb->target_id, dcb->target_lun, srb); list_move(&srb->list, &dcb->srb_going_list); } /* Sets the timer to wake us up */ -static -void waiting_set_timer(struct AdapterCtlBlk *acb, unsigned long to) +static void waiting_set_timer(struct AdapterCtlBlk *acb, unsigned long to) { if (timer_pending(&acb->waiting_timer)) return; @@ -1065,8 +865,7 @@ /* Send the next command from the waiting list to the bus */ -static -void waiting_process_next(struct AdapterCtlBlk *acb) +static void waiting_process_next(struct AdapterCtlBlk *acb) { struct DeviceCtlBlk *start = NULL; struct DeviceCtlBlk *pos; @@ -1074,7 +873,7 @@ struct ScsiReqBlk *srb; struct list_head *dcb_list_head = &acb->dcb_list; - if ((acb->active_dcb) + if (acb->active_dcb || (acb->acb_flag & (RESET_DETECT + RESET_DONE + RESET_DEV))) return; @@ -1135,8 +934,9 @@ static void waiting_timeout(unsigned long ptr) { unsigned long flags; - struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *) ptr; - dprintkdbg(DBG_KG, "Debug: Waiting queue woken up by timer.\n"); + struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)ptr; + dprintkdbg(DBG_1, + "waiting_timeout: Queue woken up by timer. acb=%p\n", acb); DC395x_LOCK_IO(acb->scsi_host, flags); waiting_process_next(acb); DC395x_UNLOCK_IO(acb->scsi_host, flags); @@ -1144,28 +944,17 @@ /* Get the DCB for a given ID/LUN combination */ -static inline -struct DeviceCtlBlk *find_dcb(struct AdapterCtlBlk *acb, u8 id, u8 lun) +static struct DeviceCtlBlk *find_dcb(struct AdapterCtlBlk *acb, u8 id, u8 lun) { return acb->children[id][lun]; } -/*********************************************************************** - * Function: static void send_srb (struct AdapterCtlBlk* acb, struct ScsiReqBlk* srb) - * - * Purpose: Send SCSI Request Block (srb) to adapter (acb) - * - * dc395x_queue_command - * waiting_process_next - * - ***********************************************************************/ -static -void send_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) +/* Send SCSI Request Block (srb) to adapter (acb) */ +static void send_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) { - struct DeviceCtlBlk *dcb; + struct DeviceCtlBlk *dcb = srb->dcb; - dcb = srb->dcb; if (dcb->max_command <= list_size(&dcb->srb_going_list) || acb->active_dcb || (acb->acb_flag & (RESET_DETECT + RESET_DONE + RESET_DEV))) { @@ -1174,130 +963,29 @@ return; } - if (!start_scsi(acb, dcb, srb)) { + if (!start_scsi(acb, dcb, srb)) srb_going_append(dcb, srb); - } else { + else { srb_waiting_insert(dcb, srb); waiting_set_timer(acb, HZ / 50); } } -/* - ********************************************************************* - * - * Function: static void build_srb (Scsi_Cmd *cmd, struct DeviceCtlBlk* dcb, struct ScsiReqBlk* srb) - * - * Purpose: Prepare SRB for being sent to Device DCB w/ command *cmd - * - ********************************************************************* - */ -static -void build_srb(Scsi_Cmnd * cmd, struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) -{ - int i, max; - struct SGentry *sgp; - struct scatterlist *sl; - u32 request_size; - int dir; +/* Prepare SRB for being sent to Device DCB w/ command *cmd */ +static void build_srb(Scsi_Cmnd *cmd, struct DeviceCtlBlk *dcb, + struct ScsiReqBlk *srb) +{ + int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + dprintkdbg(DBG_0, "build_srb: (pid#%li) <%02i-%i>\n", + cmd->pid, dcb->target_id, dcb->target_lun); - dprintkdbg(DBG_0, "build_srb..............\n"); - /*memset (srb, 0, sizeof (struct ScsiReqBlk)); */ srb->dcb = dcb; srb->cmd = cmd; - /* Find out about direction */ - dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); - - if (cmd->use_sg && dir != PCI_DMA_NONE) { - unsigned int len = 0; - /* TODO: In case usg_sg and the no of segments differ, things - * will probably go wrong. */ - max = srb->sg_count = - pci_map_sg(dcb->acb->dev, - (struct scatterlist *) cmd->request_buffer, - cmd->use_sg, dir); - sgp = srb->segment_x; - request_size = cmd->request_bufflen; - dprintkdbg(DBG_SGPARANOIA, - "BuildSRB: Bufflen = %d, buffer = %p, use_sg = %d\n", - cmd->request_bufflen, cmd->request_buffer, - cmd->use_sg); - dprintkdbg(DBG_SGPARANOIA, - "Mapped %i Segments to %i\n", cmd->use_sg, - srb->sg_count); - sl = (struct scatterlist *) cmd->request_buffer; - - srb->virt_addr = page_address(sl->page); - for (i = 0; i < max; i++) { - u32 busaddr = (u32) sg_dma_address(&sl[i]); - u32 seglen = (u32) sl[i].length; - sgp[i].address = busaddr; - sgp[i].length = seglen; - len += seglen; - dprintkdbg(DBG_SGPARANOIA, - "Setting up sgp %d, address = 0x%08x, length = %d, tot len = %d\n", - i, busaddr, seglen, len); - } - sgp += max - 1; - /* Fixup for last buffer too big as it is allocated on even page boundaries */ - if (len > request_size) { -#if debug_enabled(DBG_KG) || debug_enabled(DBG_SGPARANOIA) - dprintkdbg(DBG_KG|DBG_SGPARANOIA, - "Fixup SG total length: %d->%d, last seg %d->%d\n", - len, request_size, sgp->length, - sgp->length - (len - request_size)); -#endif - sgp->length -= (len - request_size); - len = request_size; - } - /* WIDE padding */ - if (dcb->sync_period & WIDE_SYNC && len % 2) { - len++; - sgp->length++; - } - srb->total_xfer_length = len; /*? */ - /* Hopefully this does not cross a page boundary ... */ - srb->sg_bus_addr = - pci_map_single(dcb->acb->dev, srb->segment_x, - sizeof(struct SGentry) * - DC395x_MAX_SG_LISTENTRY, - PCI_DMA_TODEVICE); - dprintkdbg(DBG_SGPARANOIA, - "Map SG descriptor list %p (%05x) to %08x\n", - srb->segment_x, - sizeof(struct SGentry) * DC395x_MAX_SG_LISTENTRY, - srb->sg_bus_addr); - } else { - if (cmd->request_buffer && dir != PCI_DMA_NONE) { - u32 len = cmd->request_bufflen; /* Actual request size */ - srb->sg_count = 1; - srb->segment_x[0].address = - pci_map_single(dcb->acb->dev, - cmd->request_buffer, len, dir); - /* WIDE padding */ - if (dcb->sync_period & WIDE_SYNC && len % 2) - len++; - srb->segment_x[0].length = len; - srb->total_xfer_length = len; - srb->virt_addr = cmd->request_buffer; - srb->sg_bus_addr = 0; - dprintkdbg(DBG_SGPARANOIA, - "BuildSRB: len = %d, buffer = %p, use_sg = %d, map %08x\n", - len, cmd->request_buffer, cmd->use_sg, - srb->segment_x[0].address); - } else { - srb->sg_count = 0; - srb->total_xfer_length = 0; - srb->sg_bus_addr = 0; - srb->virt_addr = 0; - dprintkdbg(DBG_SGPARANOIA, - "BuildSRB: buflen = %d, buffer = %p, use_sg = %d, NOMAP %08x\n", - cmd->bufflen, cmd->request_buffer, - cmd->use_sg, srb->segment_x[0].address); - } - } - + srb->sg_count = 0; + srb->total_xfer_length = 0; + srb->sg_bus_addr = 0; + srb->virt_addr = 0; srb->sg_index = 0; srb->adapter_status = 0; srb->target_status = 0; @@ -1306,29 +994,80 @@ srb->flag = 0; srb->state = 0; srb->retry_count = 0; - -#if debug_enabled(DBG_TRACE|DBG_TRACEALL) && debug_enabled(DBG_SGPARANOIA) - if ((unsigned long)srb->debugtrace & (DEBUGTRACEBUFSZ - 1)) { - dprintkdbg(DBG_SGPARANOIA, - "SRB %i (%p): debugtrace %p corrupt!\n", - (srb - dcb->acb->srb_array) / - sizeof(struct ScsiReqBlk), srb, srb->debugtrace); - } -#endif -#if debug_enabled(DBG_TRACE|DBG_TRACEALL) - srb->debugpos = 0; - srb->debugtrace = 0; -#endif - TRACEPRINTF("pid %li(%li):%02x %02x..(%i-%i) *", cmd->pid, - jiffies, cmd->cmnd[0], cmd->cmnd[1], - cmd->device->id, cmd->device->lun); srb->tag_number = TAG_NONE; - srb->scsi_phase = PH_BUS_FREE; /* initial phase */ srb->end_message = 0; - return; -} + if (dir == PCI_DMA_NONE || !cmd->request_buffer) { + dprintkdbg(DBG_0, + "build_srb: [0] len=%d buf=%p use_sg=%d !MAP=%08x\n", + cmd->bufflen, cmd->request_buffer, + cmd->use_sg, srb->segment_x[0].address); + } else if (cmd->use_sg) { + int i; + u32 reqlen = cmd->request_bufflen; + struct scatterlist *sl = (struct scatterlist *) + cmd->request_buffer; + struct SGentry *sgp = srb->segment_x; + srb->sg_count = pci_map_sg(dcb->acb->dev, sl, cmd->use_sg, + dir); + dprintkdbg(DBG_0, + "build_srb: [n] len=%d buf=%p use_sg=%d segs=%d\n", + reqlen, cmd->request_buffer, cmd->use_sg, + srb->sg_count); + + srb->virt_addr = page_address(sl->page); + for (i = 0; i < srb->sg_count; i++) { + u32 busaddr = (u32)sg_dma_address(&sl[i]); + u32 seglen = (u32)sl[i].length; + sgp[i].address = busaddr; + sgp[i].length = seglen; + srb->total_xfer_length += seglen; + } + sgp += srb->sg_count - 1; + + /* + * adjust last page if too big as it is allocated + * on even page boundaries + */ + if (srb->total_xfer_length > reqlen) { + sgp->length -= (srb->total_xfer_length - reqlen); + srb->total_xfer_length = reqlen; + } + + /* Fixup for WIDE padding - make sure length is even */ + if (dcb->sync_period & WIDE_SYNC && + srb->total_xfer_length % 2) { + srb->total_xfer_length++; + sgp->length++; + } + + srb->sg_bus_addr = pci_map_single(dcb->acb->dev, + srb->segment_x, + SEGMENTX_LEN, + PCI_DMA_TODEVICE); + + dprintkdbg(DBG_SG, "build_srb: [n] map sg %p->%08x(%05x)\n", + srb->segment_x, srb->sg_bus_addr, SEGMENTX_LEN); + } else { + srb->total_xfer_length = cmd->request_bufflen; + srb->sg_count = 1; + srb->segment_x[0].address = + pci_map_single(dcb->acb->dev, cmd->request_buffer, + srb->total_xfer_length, dir); + + /* Fixup for WIDE padding - make sure length is even */ + if (dcb->sync_period & WIDE_SYNC && srb->total_xfer_length % 2) + srb->total_xfer_length++; + + srb->segment_x[0].length = srb->total_xfer_length; + srb->virt_addr = cmd->request_buffer; + dprintkdbg(DBG_0, + "build_srb: [1] len=%d buf=%p use_sg=%d map=%08x\n", + srb->total_xfer_length, cmd->request_buffer, + cmd->use_sg, srb->segment_x[0].address); + } +} /** @@ -1350,27 +1089,14 @@ * and is expected to be held on return. * **/ -static int -dc395x_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) +static int dc395x_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) { struct DeviceCtlBlk *dcb; struct ScsiReqBlk *srb; struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)cmd->device->host->hostdata; - - dprintkdbg(DBG_0, "Queue Cmd=%02x,Tgt=%d,LUN=%d (pid=%li)\n", - cmd->cmnd[0], - cmd->device->id, - cmd->device->lun, - cmd->pid); - -#if debug_enabled(DBG_RECURSION) - if (dbg_in_driver++ > NORM_REC_LVL) { - dprintkl(KERN_DEBUG, - "%i queue_command () recursion? (pid=%li)\n", - dbg_in_driver, cmd->pid); - } -#endif + dprintkdbg(DBG_0, "queue_command: (pid#%li) <%02i-%i> cmnd=0x%02x\n", + cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); /* Assume BAD_TARGET; will be cleared later */ cmd->result = DID_BAD_TARGET << 16; @@ -1384,8 +1110,8 @@ /* does the specified lun on the specified device exist */ if (!(acb->dcb_map[cmd->device->id] & (1 << cmd->device->lun))) { - dprintkl(KERN_INFO, "Ignore target %02x lun %02x\n", cmd->device->id, - cmd->device->lun); + dprintkl(KERN_INFO, "queue_command: Ignore target <%02i-%i>\n", + cmd->device->id, cmd->device->lun); goto complete; } @@ -1393,9 +1119,8 @@ dcb = find_dcb(acb, cmd->device->id, cmd->device->lun); if (!dcb) { /* should never happen */ - dprintkl(KERN_ERR, "no DCB failed, target %02x lun %02x\n", - cmd->device->id, cmd->device->lun); - dprintkl(KERN_ERR, "No DCB in queuecommand (2)!\n"); + dprintkl(KERN_ERR, "queue_command: No such device <%02i-%i>", + cmd->device->id, cmd->device->lun); goto complete; } @@ -1403,7 +1128,6 @@ cmd->scsi_done = done; cmd->result = 0; - /* get a free SRB */ srb = srb_get_free(acb); if (!srb) { @@ -1411,11 +1135,10 @@ * Return 1 since we are unable to queue this command at this * point in time. */ - dprintkdbg(DBG_0, "No free SRB's in queuecommand\n"); + dprintkdbg(DBG_0, "queue_command: No free srb's\n"); return 1; } - /* build srb for the command */ build_srb(cmd, dcb, srb); if (!list_empty(&dcb->srb_waiting_list)) { @@ -1426,11 +1149,7 @@ /* process immediately */ send_srb(acb, srb); } - dprintkdbg(DBG_1, "... command (pid %li) queued successfully.\n", cmd->pid); - -#if debug_enabled(DBG_RECURSION) - dbg_in_driver-- -#endif + dprintkdbg(DBG_1, "queue_command: (pid#%li) done\n", cmd->pid); return 0; complete: @@ -1440,28 +1159,16 @@ * done when the commad is for things like non existent * devices. */ -#if debug_enabled(DBG_RECURSION) - dbg_in_driver-- -#endif done(cmd); return 0; } - - /* - ********************************************************************* - * - * Function : dc395x_bios_param - * Description: Return the disk geometry for the given SCSI device. - ********************************************************************* + * Return the disk geometry for the given SCSI device. */ -static -int dc395x_bios_param(struct scsi_device *sdev, - struct block_device *bdev, - sector_t capacity, - int *info) +static int dc395x_bios_param(struct scsi_device *sdev, + struct block_device *bdev, sector_t capacity, int *info) { #ifdef CONFIG_SCSI_DC395x_TRMS1040_TRADMAP int heads, sectors, cylinders; @@ -1469,7 +1176,7 @@ int size = capacity; dprintkdbg(DBG_0, "dc395x_bios_param..............\n"); - acb = (struct AdapterCtlBlk *) sdev->host->hostdata; + acb = (struct AdapterCtlBlk *)sdev->host->hostdata; heads = 64; sectors = 32; cylinders = size / (heads * sectors); @@ -1489,12 +1196,8 @@ } -/* - * DC395x register dump - */ -static -void dump_register_info(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) +static void dump_register_info(struct AdapterCtlBlk *acb, + struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { u16 pstat; struct pci_dev *dev = acb->dev; @@ -1504,64 +1207,58 @@ if (!srb && dcb) srb = dcb->active_srb; if (srb) { - if (!(srb->cmd)) - dprintkl(KERN_INFO, "dump: SRB %p: cmd %p OOOPS!\n", srb, - srb->cmd); + if (!srb->cmd) + dprintkl(KERN_INFO, "dump: srb=%p cmd=%p OOOPS!\n", + srb, srb->cmd); else - dprintkl(KERN_INFO, "dump: SRB %p: cmd %p pid %li: %02x (%02i-%i)\n", - srb, srb->cmd, srb->cmd->pid, - srb->cmd->cmnd[0], srb->cmd->device->id, - srb->cmd->device->lun); - printk(" SGList %p Cnt %i Idx %i Len %i\n", + dprintkl(KERN_INFO, "dump: srb=%p cmd=%p (pid#%li) " + "cmnd=0x%02x <%02i-%i>\n", + srb, srb->cmd, srb->cmd->pid, + srb->cmd->cmnd[0], srb->cmd->device->id, + srb->cmd->device->lun); + printk(" sglist=%p cnt=%i idx=%i len=%i\n", srb->segment_x, srb->sg_count, srb->sg_index, srb->total_xfer_length); - printk - (" State %04x Status %02x Phase %02x (%sconn.)\n", - srb->state, srb->status, srb->scsi_phase, - (acb->active_dcb) ? "" : "not"); - TRACEOUT(" %s\n", srb->debugtrace); - } - dprintkl(KERN_INFO, "dump: SCSI block\n"); - printk - (" Status %04x FIFOCnt %02x Signals %02x IRQStat %02x\n", - DC395x_read16(acb, TRM_S1040_SCSI_STATUS), - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), - DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL), - DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS)); - printk - (" Sync %02x Target %02x RSelID %02x SCSICtr %08x\n", - DC395x_read8(acb, TRM_S1040_SCSI_SYNC), - DC395x_read8(acb, TRM_S1040_SCSI_TARGETID), - DC395x_read8(acb, TRM_S1040_SCSI_IDMSG), - DC395x_read32(acb, TRM_S1040_SCSI_COUNTER)); - printk - (" IRQEn %02x Config %04x Cfg2 %02x Cmd %02x SelTO %02x\n", - DC395x_read8(acb, TRM_S1040_SCSI_INTEN), - DC395x_read16(acb, TRM_S1040_SCSI_CONFIG0), - DC395x_read8(acb, TRM_S1040_SCSI_CONFIG2), - DC395x_read8(acb, TRM_S1040_SCSI_COMMAND), - DC395x_read8(acb, TRM_S1040_SCSI_TIMEOUT)); - dprintkl(KERN_INFO, "dump: DMA block\n"); - printk - (" Cmd %04x FIFOCnt %02x FStat %02x IRQStat %02x IRQEn %02x Cfg %04x\n", - DC395x_read16(acb, TRM_S1040_DMA_COMMAND), - DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), - DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), - DC395x_read8(acb, TRM_S1040_DMA_STATUS), - DC395x_read8(acb, TRM_S1040_DMA_INTEN), - DC395x_read16(acb, TRM_S1040_DMA_CONFIG)); - printk(" TCtr %08x CTCtr %08x Addr %08x%08x\n", - DC395x_read32(acb, TRM_S1040_DMA_XCNT), - DC395x_read32(acb, TRM_S1040_DMA_CXCNT), - DC395x_read32(acb, TRM_S1040_DMA_XHIGHADDR), - DC395x_read32(acb, TRM_S1040_DMA_XLOWADDR)); - dprintkl(KERN_INFO, "dump: Misc: GCtrl %02x GStat %02x GTmr %02x\n", - DC395x_read8(acb, TRM_S1040_GEN_CONTROL), - DC395x_read8(acb, TRM_S1040_GEN_STATUS), - DC395x_read8(acb, TRM_S1040_GEN_TIMER)); - dprintkl(KERN_INFO, "dump: PCI Status %04x\n", pstat); - - + printk(" state=0x%04x status=0x%02x phase=0x%02x (%sconn.)\n", + srb->state, srb->status, srb->scsi_phase, + (acb->active_dcb) ? "" : "not"); + } + dprintkl(KERN_INFO, "dump: SCSI{status=0x%04x fifocnt=0x%02x " + "signals=0x%02x irqstat=0x%02x sync=0x%02x target=0x%02x " + "rselid=0x%02x ctr=0x%08x irqen=0x%02x config=0x%04x " + "config2=0x%02x cmd=0x%02x selto=0x%02x}\n", + DC395x_read16(acb, TRM_S1040_SCSI_STATUS), + DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), + DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL), + DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS), + DC395x_read8(acb, TRM_S1040_SCSI_SYNC), + DC395x_read8(acb, TRM_S1040_SCSI_TARGETID), + DC395x_read8(acb, TRM_S1040_SCSI_IDMSG), + DC395x_read32(acb, TRM_S1040_SCSI_COUNTER), + DC395x_read8(acb, TRM_S1040_SCSI_INTEN), + DC395x_read16(acb, TRM_S1040_SCSI_CONFIG0), + DC395x_read8(acb, TRM_S1040_SCSI_CONFIG2), + DC395x_read8(acb, TRM_S1040_SCSI_COMMAND), + DC395x_read8(acb, TRM_S1040_SCSI_TIMEOUT)); + dprintkl(KERN_INFO, "dump: DMA{cmd=0x%04x fifocnt=0x%02x fstat=0x%02x " + "irqstat=0x%02x irqen=0x%02x cfg=0x%04x tctr=0x%08x " + "ctctr=0x%08x addr=0x%08x:0x%08x}\n", + DC395x_read16(acb, TRM_S1040_DMA_COMMAND), + DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), + DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), + DC395x_read8(acb, TRM_S1040_DMA_STATUS), + DC395x_read8(acb, TRM_S1040_DMA_INTEN), + DC395x_read16(acb, TRM_S1040_DMA_CONFIG), + DC395x_read32(acb, TRM_S1040_DMA_XCNT), + DC395x_read32(acb, TRM_S1040_DMA_CXCNT), + DC395x_read32(acb, TRM_S1040_DMA_XHIGHADDR), + DC395x_read32(acb, TRM_S1040_DMA_XLOWADDR)); + dprintkl(KERN_INFO, "dump: gen{gctrl=0x%02x gstat=0x%02x gtmr=0x%02x} " + "pci{status=0x%04x}\n", + DC395x_read8(acb, TRM_S1040_GEN_CONTROL), + DC395x_read8(acb, TRM_S1040_GEN_STATUS), + DC395x_read8(acb, TRM_S1040_GEN_TIMER), + pstat); } @@ -1572,32 +1269,19 @@ u8 fifocnt = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT); if (!(fifocnt & 0x40)) dprintkdbg(DBG_FIFO, - "Clr FIFO (%i bytes) on phase %02x in %s\n", + "clear_fifo: (%i bytes) on phase %02x in %s\n", fifocnt & 0x3f, lines, txt); #endif -#if debug_enabled(DBG_TRACE) - if (acb->active_dcb && acb->active_dcb->active_srb) { - struct ScsiReqBlk *srb = acb->active_dcb->active_srb; - TRACEPRINTF("#*"); - } -#endif DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_CLRFIFO); } -/* - ******************************************************************** - * - * DC395x_reset scsi_reset_detect - * - ******************************************************************** - */ static void reset_dev_param(struct AdapterCtlBlk *acb) { struct DeviceCtlBlk *dcb; struct NvRamType *eeprom = &acb->eeprom; + dprintkdbg(DBG_0, "reset_dev_param: acb=%p\n", acb); - dprintkdbg(DBG_0, "reset_dev_param..............\n"); list_for_each_entry(dcb, &acb->dcb_list, list) { u8 period_index; @@ -1616,22 +1300,17 @@ /* - ********************************************************************* - * Function : int dc395x_eh_bus_reset(Scsi_Cmnd *cmd) - * Purpose : perform a hard reset on the SCSI bus - * Inputs : cmd - some command for this host (for fetching hooks) - * Returns : SUCCESS (0x2002) on success, else FAILED (0x2003). - ********************************************************************* + * perform a hard reset on the SCSI bus + * @cmd - some command for this host (for fetching hooks) + * Returns: SUCCESS (0x2002) on success, else FAILED (0x2003). */ -static int dc395x_eh_bus_reset(Scsi_Cmnd * cmd) +static int dc395x_eh_bus_reset(Scsi_Cmnd *cmd) { - struct AdapterCtlBlk *acb; - /*u32 acb_flags=0; */ - - dprintkl(KERN_INFO, "reset requested!\n"); - acb = (struct AdapterCtlBlk *) cmd->device->host->hostdata; - /* mid level guarantees no recursion */ - /*DC395x_ACB_LOCK(acb,acb_flags); */ + struct AdapterCtlBlk *acb = + (struct AdapterCtlBlk *)cmd->device->host->hostdata; + dprintkl(KERN_INFO, + "eh_bus_reset: (pid#%li) target=<%02i-%i> cmd=%p\n", + cmd->pid, cmd->device->id, cmd->device->lun, cmd); if (timer_pending(&acb->waiting_timer)) del_timer(&acb->waiting_timer); @@ -1657,52 +1336,42 @@ */ /* Clear SCSI FIFO */ DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO); - clear_fifo(acb, "reset"); + clear_fifo(acb, "eh_bus_reset"); /* Delete pending IRQ */ DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS); set_basic_config(acb); reset_dev_param(acb); doing_srb_done(acb, DID_RESET, cmd, 0); - acb->active_dcb = NULL; - acb->acb_flag = 0; /* RESET_DETECT, RESET_DONE ,RESET_DEV */ waiting_process_next(acb); - /*DC395x_ACB_LOCK(acb,acb_flags); */ return SUCCESS; } /* - ********************************************************************* - * Function : int dc395x_eh_abort(Scsi_Cmnd *cmd) - * Purpose : abort an errant SCSI command - * Inputs : cmd - command to be aborted - * Returns : SUCCESS (0x2002) on success, else FAILED (0x2003). - ********************************************************************* + * abort an errant SCSI command + * @cmd - command to be aborted + * Returns: SUCCESS (0x2002) on success, else FAILED (0x2003). */ -static int dc395x_eh_abort(Scsi_Cmnd * cmd) +static int dc395x_eh_abort(Scsi_Cmnd *cmd) { /* * Look into our command queues: If it has not been sent already, * we remove it and return success. Otherwise fail. */ struct AdapterCtlBlk *acb = - (struct AdapterCtlBlk *) cmd->device->host->hostdata; + (struct AdapterCtlBlk *)cmd->device->host->hostdata; struct DeviceCtlBlk *dcb; struct ScsiReqBlk *srb; - - dprintkl(KERN_INFO, "eh abort: cmd %p (pid %li, %02i-%i) ", - cmd, - cmd->pid, - cmd->device->id, - cmd->device->lun); + dprintkl(KERN_INFO, "eh_abort: (pid#%li) target=<%02i-%i> cmd=%p\n", + cmd->pid, cmd->device->id, cmd->device->lun, cmd); dcb = find_dcb(acb, cmd->device->id, cmd->device->lun); if (!dcb) { - dprintkl(KERN_DEBUG, "abort - no DCB found"); + dprintkl(KERN_DEBUG, "eh_abort: No such device\n"); return FAILED; } @@ -1713,32 +1382,31 @@ pci_unmap_srb(acb, srb); free_tag(dcb, srb); srb_free_insert(acb, srb); - dprintkl(KERN_DEBUG, "abort - command found in waiting commands queue"); + dprintkl(KERN_DEBUG, "eh_abort: Command was waiting\n"); cmd->result = DID_ABORT << 16; return SUCCESS; } srb = find_cmd(cmd, &dcb->srb_going_list); if (srb) { - dprintkl(KERN_DEBUG, "abort - command currently in progress"); + dprintkl(KERN_DEBUG, "eh_abort: Command in progress"); /* XXX: Should abort the command here */ } else { - dprintkl(KERN_DEBUG, "abort - command not found"); + dprintkl(KERN_DEBUG, "eh_abort: Command not found"); } return FAILED; } /* SDTR */ -static -void build_sdtr(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, +static void build_sdtr(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { u8 *ptr = srb->msgout_buf + srb->msg_count; if (srb->msg_count > 1) { dprintkl(KERN_INFO, - "Build_SDTR: msgout_buf BUSY (%i: %02x %02x)\n", - srb->msg_count, srb->msgout_buf[0], - srb->msgout_buf[1]); + "build_sdtr: msgout_buf BUSY (%i: %02x %02x)\n", + srb->msg_count, srb->msgout_buf[0], + srb->msgout_buf[1]); return; } if (!(dcb->dev_mode & NTC_DO_SYNC_NEGO)) { @@ -1754,25 +1422,21 @@ *ptr++ = dcb->sync_offset; /* Transfer period (max. REQ/ACK dist) */ srb->msg_count += 5; srb->state |= SRB_DO_SYNC_NEGO; - TRACEPRINTF("S *"); } -/* SDTR */ -static -void build_wdtr(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, +/* WDTR */ +static void build_wdtr(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) { - u8 wide = - ((dcb->dev_mode & NTC_DO_WIDE_NEGO) & (acb-> - config & HCC_WIDE_CARD)) - ? 1 : 0; + u8 wide = ((dcb->dev_mode & NTC_DO_WIDE_NEGO) & + (acb->config & HCC_WIDE_CARD)) ? 1 : 0; u8 *ptr = srb->msgout_buf + srb->msg_count; if (srb->msg_count > 1) { dprintkl(KERN_INFO, - "Build_WDTR: msgout_buf BUSY (%i: %02x %02x)\n", - srb->msg_count, srb->msgout_buf[0], - srb->msgout_buf[1]); + "build_wdtr: msgout_buf BUSY (%i: %02x %02x)\n", + srb->msg_count, srb->msgout_buf[0], + srb->msgout_buf[1]); return; } *ptr++ = MSG_EXTENDED; /* (01h) */ @@ -1781,7 +1445,6 @@ *ptr++ = wide; srb->msg_count += 4; srb->state |= SRB_DO_WIDE_NEGO; - TRACEPRINTF("W *"); } @@ -1809,7 +1472,7 @@ void selection_timeout_missed(unsigned long ptr) { unsigned long flags; - struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *) ptr; + struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)ptr; struct ScsiReqBlk *srb; dprintkl(KERN_DEBUG, "Chip forgot to produce SelTO IRQ!\n"); if (!acb->active_dcb || !acb->active_dcb->active_srb) { @@ -1818,39 +1481,30 @@ } DC395x_LOCK_IO(acb->scsi_host, flags); srb = acb->active_dcb->active_srb; - TRACEPRINTF("N/TO *"); disconnect(acb); DC395x_UNLOCK_IO(acb->scsi_host, flags); } #endif -/* - * scsiio - * DC395x_DoWaitingSRB srb_done - * send_srb request_sense - */ -static -u8 start_scsi(struct AdapterCtlBlk * acb, struct DeviceCtlBlk * dcb, - struct ScsiReqBlk * srb) +static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, + struct ScsiReqBlk* srb) { u16 s_stat2, return_code; u8 s_stat, scsicommand, i, identify_message; u8 *ptr; + dprintkdbg(DBG_0, "start_scsi: (pid#%li) <%02i-%i> srb=%p\n", + srb->cmd->pid, dcb->target_id, dcb->target_lun, srb); - dprintkdbg(DBG_0, "start_scsi..............\n"); srb->tag_number = TAG_NONE; /* acb->tag_max_num: had error read in eeprom */ s_stat = DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL); s_stat2 = 0; s_stat2 = DC395x_read16(acb, TRM_S1040_SCSI_STATUS); - TRACEPRINTF("Start %02x *", s_stat); #if 1 if (s_stat & 0x20 /* s_stat2 & 0x02000 */ ) { - dprintkdbg(DBG_KG, - "StartSCSI: pid %li(%02i-%i): BUSY %02x %04x\n", - srb->cmd->pid, dcb->target_id, dcb->target_lun, - s_stat, s_stat2); + dprintkdbg(DBG_KG, "start_scsi: (pid#%li) BUSY %02x %04x\n", + srb->cmd->pid, s_stat, s_stat2); /* * Try anyway? * @@ -1861,41 +1515,32 @@ * Instead let this fail and have the timer make sure the command is * tried again after a short time */ - TRACEPRINTF("^*"); /*selto_timer (acb); */ - /*monitor_next_irq = 1; */ return 1; } #endif if (acb->active_dcb) { - dprintkl(KERN_DEBUG, "We try to start a SCSI command (%li)!\n", - srb->cmd->pid); - dprintkl(KERN_DEBUG, "While another one (%li) is active!!\n", - (acb->active_dcb->active_srb ? acb->active_dcb-> - active_srb->cmd->pid : 0)); - TRACEOUT(" %s\n", srb->debugtrace); - if (acb->active_dcb->active_srb) - TRACEOUT(" %s\n", - acb->active_dcb->active_srb->debugtrace); + dprintkl(KERN_DEBUG, "start_scsi: (pid#%li) Attempt to start a" + "command while another command (pid#%li) is active.", + srb->cmd->pid, + acb->active_dcb->active_srb ? + acb->active_dcb->active_srb->cmd->pid : 0); return 1; } if (DC395x_read16(acb, TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) { - dprintkdbg(DBG_KG, - "StartSCSI failed (busy) for pid %li(%02i-%i)\n", - srb->cmd->pid, dcb->target_id, dcb->target_lun); - TRACEPRINTF("°*"); + dprintkdbg(DBG_KG, "start_scsi: (pid#%li) Failed (busy)\n", + srb->cmd->pid); return 1; } /* Allow starting of SCSI commands half a second before we allow the mid-level * to queue them again after a reset */ if (time_before(jiffies, acb->scsi_host->last_reset - HZ / 2)) { - dprintkdbg(DBG_KG, - "We were just reset and don't accept commands yet!\n"); + dprintkdbg(DBG_KG, "start_scsi: Refuse cmds (reset wait)\n"); return 1; } /* Flush FIFO */ - clear_fifo(acb, "Start"); + clear_fifo(acb, "start_scsi"); DC395x_write8(acb, TRM_S1040_SCSI_HOSTID, acb->scsi_host->this_id); DC395x_write8(acb, TRM_S1040_SCSI_TARGETID, dcb->target_id); DC395x_write8(acb, TRM_S1040_SCSI_SYNC, dcb->sync_period); @@ -1939,9 +1584,7 @@ } srb->msg_count = 0; } - /* - ** Send identify message - */ + /* Send identify message */ DC395x_write8(acb, TRM_S1040_SCSI_FIFO, identify_message); scsicommand = SCMD_SEL_ATN; @@ -1958,37 +1601,29 @@ tag_number++; } if (tag_number >= dcb->max_command) { - dprintkl(KERN_WARNING, - "Start_SCSI: Out of tags for pid %li (%i-%i)\n", - srb->cmd->pid, srb->cmd->device->id, - srb->cmd->device->lun); + dprintkl(KERN_WARNING, "start_scsi: (pid#%li) " + "Out of tags target=<%02i-%i>)\n", + srb->cmd->pid, srb->cmd->device->id, + srb->cmd->device->lun); srb->state = SRB_READY; DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT); return 1; } - /* - ** Send Tag id - */ + /* Send Tag id */ DC395x_write8(acb, TRM_S1040_SCSI_FIFO, MSG_SIMPLE_QTAG); DC395x_write8(acb, TRM_S1040_SCSI_FIFO, tag_number); dcb->tag_mask |= tag_mask; srb->tag_number = tag_number; - TRACEPRINTF("Tag %i *", tag_number); - scsicommand = SCMD_SEL_ATN3; srb->state = SRB_START_; } #endif /*polling:*/ - /* - * Send CDB ..command block ......... - */ - dprintkdbg(DBG_KG, - "StartSCSI (pid %li) %02x (%i-%i): Tag %i\n", - srb->cmd->pid, srb->cmd->cmnd[0], - srb->cmd->device->id, srb->cmd->device->lun, - srb->tag_number); + /* Send CDB ..command block ......... */ + dprintkdbg(DBG_KG, "start_scsi: (pid#%li) <%02i-%i> cmnd=0x%02x tag=%i\n", + srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun, + srb->cmd->cmnd[0], srb->tag_number); if (srb->flag & AUTO_REQSENSE) { DC395x_write8(acb, TRM_S1040_SCSI_FIFO, REQUEST_SENSE); DC395x_write8(acb, TRM_S1040_SCSI_FIFO, (dcb->target_lun << 5)); @@ -1998,7 +1633,7 @@ sizeof(srb->cmd->sense_buffer)); DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); } else { - ptr = (u8 *) srb->cmd->cmnd; + ptr = (u8 *)srb->cmd->cmnd; for (i = 0; i < srb->cmd->cmd_len; i++) DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *ptr++); } @@ -2011,10 +1646,8 @@ * we caught an interrupt (must be reset or reselection ... ) * : Let's process it first! */ - dprintkdbg(DBG_0, "Debug: StartSCSI failed (busy) for pid %li(%02i-%i)!\n", + dprintkdbg(DBG_0, "start_scsi: (pid#%li) <%02i-%i> Failed - busy\n", srb->cmd->pid, dcb->target_id, dcb->target_lun); - /*clear_fifo (acb, "Start2"); */ - /*DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_HWRESELECT | DO_DATALATCH); */ srb->state = SRB_READY; free_tag(dcb, srb); srb->msg_count = 0; @@ -2032,23 +1665,13 @@ /* it's important for atn stop */ DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH | DO_HWRESELECT); - /* - ** SCSI command - */ - TRACEPRINTF("%02x *", scsicommand); + /* SCSI command */ DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, scsicommand); } return return_code; } -/* - ******************************************************************** - * scsiio - * init_adapter - ******************************************************************** - */ - /** * dc395x_handle_interrupt - Handle an interrupt that has been confirmed to * have been triggered for this card. @@ -2056,37 +1679,29 @@ * @acb: a pointer to the adpter control block * @scsi_status: the status return when we checked the card **/ -static void dc395x_handle_interrupt(struct AdapterCtlBlk *acb, u16 scsi_status) +static void dc395x_handle_interrupt(struct AdapterCtlBlk *acb, + u16 scsi_status) { struct DeviceCtlBlk *dcb; struct ScsiReqBlk *srb; u16 phase; u8 scsi_intstatus; unsigned long flags; - void (*dc395x_statev) (struct AdapterCtlBlk *, struct ScsiReqBlk *, - u16 *); + void (*dc395x_statev)(struct AdapterCtlBlk *, struct ScsiReqBlk *, + u16 *); DC395x_LOCK_IO(acb->scsi_host, flags); /* This acknowledges the IRQ */ scsi_intstatus = DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS); if ((scsi_status & 0x2007) == 0x2002) - dprintkl(KERN_DEBUG, "COP after COP completed? %04x\n", - scsi_status); -#if 1 /*def DBG_0 */ - if (monitor_next_irq) { - dprintkl(KERN_INFO, - "status=%04x intstatus=%02x\n", scsi_status, - scsi_intstatus); - monitor_next_irq--; - } -#endif - /*DC395x_ACB_LOCK(acb,acb_flags); */ + dprintkl(KERN_DEBUG, + "COP after COP completed? %04x\n", scsi_status); if (debug_enabled(DBG_KG)) { if (scsi_intstatus & INT_SELTIMEOUT) - dprintkdbg(DBG_KG, "Sel Timeout IRQ\n"); + dprintkdbg(DBG_KG, "handle_interrupt: Selection timeout\n"); } - /*dprintkl(KERN_DEBUG, "DC395x_IRQ: intstatus = %02x ", scsi_intstatus); */ + /*dprintkl(KERN_DEBUG, "handle_interrupt: intstatus = 0x%02x ", scsi_intstatus); */ if (timer_pending(&acb->selto_timer)) del_timer(&acb->selto_timer); @@ -2111,8 +1726,8 @@ dcb = acb->active_dcb; if (!dcb) { dprintkl(KERN_DEBUG, - "Oops: BusService (%04x %02x) w/o ActiveDCB!\n", - scsi_status, scsi_intstatus); + "Oops: BusService (%04x %02x) w/o ActiveDCB!\n", + scsi_status, scsi_intstatus); goto out_unlock; } srb = dcb->active_srb; @@ -2120,12 +1735,10 @@ dprintkdbg(DBG_0, "MsgOut Abort Device.....\n"); enable_msgout_abort(acb, srb); } - /* - ************************************************************ - * software sequential machine - ************************************************************ - */ - phase = (u16) srb->scsi_phase; + + /* software sequential machine */ + phase = (u16)srb->scsi_phase; + /* * 62037 or 62137 * call dc395x_scsi_phase0[]... "phase entry" @@ -2139,22 +1752,20 @@ /* nop0, phase:5 PH_BUS_FREE .. initial phase */ /* msgout_phase0, phase:6 */ /* msgin_phase0, phase:7 */ - dc395x_statev = (void *) dc395x_scsi_phase0[phase]; + dc395x_statev = dc395x_scsi_phase0[phase]; dc395x_statev(acb, srb, &scsi_status); + /* - *$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ - * - * if there were any exception occured - * scsi_status will be modify to bus free phase - * new scsi_status transfer out from ... previous dc395x_statev - * - *$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ + * if there were any exception occured scsi_status + * will be modify to bus free phase new scsi_status + * transfer out from ... previous dc395x_statev */ srb->scsi_phase = scsi_status & PHASEMASK; - phase = (u16) scsi_status & PHASEMASK; + phase = (u16)scsi_status & PHASEMASK; + /* - * call dc395x_scsi_phase1[]... "phase entry" - * handle every phase do transfer + * call dc395x_scsi_phase1[]... "phase entry" handle + * every phase to do transfer */ /* data_out_phase1, phase:0 */ /* data_in_phase1, phase:1 */ @@ -2164,30 +1775,22 @@ /* nop1, phase:5 PH_BUS_FREE .. initial phase */ /* msgout_phase1, phase:6 */ /* msgin_phase1, phase:7 */ - dc395x_statev = (void *) dc395x_scsi_phase1[phase]; + dc395x_statev = dc395x_scsi_phase1[phase]; dc395x_statev(acb, srb, &scsi_status); } out_unlock: DC395x_UNLOCK_IO(acb->scsi_host, flags); - return; } -static -irqreturn_t dc395x_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t dc395x_interrupt(int irq, void *dev_id, + struct pt_regs *regs) { struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)dev_id; u16 scsi_status; u8 dma_status; irqreturn_t handled = IRQ_NONE; - dprintkdbg(DBG_0, "dc395x_interrupt..............\n"); -#if debug_enabled(DBG_RECURSION) - if (dbg_in_driver++ > NORM_REC_LVL) { - dprintkl(KERN_DEBUG, "%i interrupt recursion?\n", dbg_in_driver); - } -#endif - /* * Check for pending interupt */ @@ -2200,7 +1803,7 @@ } else if (dma_status & 0x20) { /* Error from the DMA engine */ - dprintkl(KERN_INFO, "Interrupt from DMA engine: %02x!\n", dma_status); + dprintkl(KERN_INFO, "Interrupt from DMA engine: 0x%02x!\n", dma_status); #if 0 dprintkl(KERN_INFO, "This means DMA error! Try to handle ...\n"); if (acb->active_dcb) { @@ -2216,135 +1819,75 @@ handled = IRQ_HANDLED; } -#if debug_enabled(DBG_RECURSION) - dbg_in_driver-- -#endif return handled; } -/* - ******************************************************************** - * scsiio - * msgout_phase0: one of dc395x_scsi_phase0[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase0[phase] - * if phase =6 - ******************************************************************** - */ -static -void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) +static void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) { - dprintkdbg(DBG_0, "msgout_phase0.....\n"); - if (srb->state & (SRB_UNEXPECT_RESEL + SRB_ABORT_SENT)) { + dprintkdbg(DBG_0, "msgout_phase0: (pid#%li)\n", srb->cmd->pid); + if (srb->state & (SRB_UNEXPECT_RESEL + SRB_ABORT_SENT)) *pscsi_status = PH_BUS_FREE; /*.. initial phase */ - } + DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ srb->state &= ~SRB_MSGOUT; - TRACEPRINTF("MOP0 *"); } -/* - ******************************************************************** - * scsiio - * msgout_phase1: one of dc395x_scsi_phase0[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase0[phase] - * if phase =6 - ******************************************************************** - */ -static -void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) +static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) { u16 i; u8 *ptr; - struct DeviceCtlBlk *dcb; + dprintkdbg(DBG_0, "msgout_phase1: (pid#%li)\n", srb->cmd->pid); - dprintkdbg(DBG_0, "msgout_phase1..............\n"); - TRACEPRINTF("MOP1*"); - dcb = acb->active_dcb; - clear_fifo(acb, "MOP1"); + clear_fifo(acb, "msgout_phase1"); if (!(srb->state & SRB_MSGOUT)) { srb->state |= SRB_MSGOUT; - dprintkl(KERN_DEBUG, "Debug: pid %li: MsgOut Phase unexpected.\n", srb->cmd->pid); /* So what ? */ + dprintkl(KERN_DEBUG, + "msgout_phase1: (pid#%li) Phase unexpected\n", + srb->cmd->pid); /* So what ? */ } if (!srb->msg_count) { - dprintkdbg(DBG_0, "Debug: pid %li: NOP Msg (no output message there).\n", + dprintkdbg(DBG_0, "msgout_phase1: (pid#%li) NOP msg\n", srb->cmd->pid); DC395x_write8(acb, TRM_S1040_SCSI_FIFO, MSG_NOP); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT); - TRACEPRINTF("\\*"); - TRACEOUT(" %s\n", srb->debugtrace); return; } - ptr = (u8 *) srb->msgout_buf; - TRACEPRINTF("(*"); - /*dprintkl(KERN_DEBUG, "Send msg: "); print_msg (ptr, srb->msg_count); */ - /*dprintkl(KERN_DEBUG, "MsgOut: "); */ - for (i = 0; i < srb->msg_count; i++) { - TRACEPRINTF("%02x *", *ptr); + ptr = (u8 *)srb->msgout_buf; + for (i = 0; i < srb->msg_count; i++) DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *ptr++); - } - TRACEPRINTF(")*"); srb->msg_count = 0; - /*printk("\n"); */ - if (/*(dcb->flag & ABORT_DEV_) && */ - (srb->msgout_buf[0] == MSG_ABORT)) + if (srb->msgout_buf[0] == MSG_ABORT) srb->state = SRB_ABORT_SENT; - /*1.25 */ - /*DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_DATALATCH); *//* it's important for atn stop */ - /* - ** SCSI command - */ - /*TRACEPRINTF (".*"); */ DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT); } -/* - ******************************************************************** - * scsiio - * command_phase0: one of dc395x_scsi_phase0[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase0[phase] - * if phase =2 - ******************************************************************** - */ -static -void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) +static void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) { - TRACEPRINTF("COP0 *"); - /*1.25 */ - /*clear_fifo (acb, COP0); */ + dprintkdbg(DBG_0, "command_phase0: (pid#%li)\n", srb->cmd->pid); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); } -/* - ******************************************************************** - * scsiio - * command_phase1: one of dc395x_scsi_phase1[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase1[phase] - * if phase =2 - ******************************************************************** - */ -static -void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) +static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) { struct DeviceCtlBlk *dcb; u8 *ptr; u16 i; + dprintkdbg(DBG_0, "command_phase1: (pid#%li)\n", srb->cmd->pid); - dprintkdbg(DBG_0, "command_phase1..............\n"); - TRACEPRINTF("COP1*"); - clear_fifo(acb, "COP1"); + clear_fifo(acb, "command_phase1"); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_CLRATN); if (!(srb->flag & AUTO_REQSENSE)) { - ptr = (u8 *) srb->cmd->cmnd; + ptr = (u8 *)srb->cmd->cmnd; for (i = 0; i < srb->cmd->cmd_len; i++) { DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *ptr); ptr++; @@ -2364,22 +1907,24 @@ /* it's important for atn stop */ DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* SCSI command */ - TRACEPRINTF(".*"); DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT); } -/* Do sanity checks for S/G list */ -static inline void check_sg_list(struct ScsiReqBlk *srb) +/* + * Verify that the remaining space in the hw sg lists is the same as + * the count of remaining bytes in srb->total_xfer_length + */ +static void sg_verify_length(struct ScsiReqBlk *srb) { - if (debug_enabled(DBG_SGPARANOIA)) { + if (debug_enabled(DBG_SG)) { unsigned len = 0; unsigned idx = srb->sg_index; struct SGentry *psge = srb->segment_x + idx; for (; idx < srb->sg_count; psge++, idx++) len += psge->length; if (len != srb->total_xfer_length) - dprintkdbg(DBG_SGPARANOIA, + dprintkdbg(DBG_SG, "Inconsistent SRB S/G lengths (Tot=%i, Count=%i) !!\n", srb->total_xfer_length, len); } @@ -2390,75 +1935,90 @@ * Compute the next Scatter Gather list index and adjust its length * and address if necessary; also compute virt_addr */ -static void update_sg_list(struct ScsiReqBlk *srb, u32 left) +static void sg_update_list(struct ScsiReqBlk *srb, u32 left) { - struct SGentry *psge; - u32 xferred = 0; u8 idx; - Scsi_Cmnd *cmd = srb->cmd; struct scatterlist *sg; + Scsi_Cmnd *cmd = srb->cmd; int segment = cmd->use_sg; + u32 xferred = srb->total_xfer_length - left; /* bytes transfered */ + struct SGentry *psge = srb->segment_x + srb->sg_index; - dprintkdbg(DBG_KG, "Update SG: Total %i, Left %i\n", - srb->total_xfer_length, left); - check_sg_list(srb); - psge = srb->segment_x + srb->sg_index; - /* data that has already been transferred */ - xferred = srb->total_xfer_length - left; - if (srb->total_xfer_length != left) { - /*check_sg_list_TX (srb, xferred); */ - /* Remaining */ - srb->total_xfer_length = left; - /* parsing from last time disconnect SGIndex */ - for (idx = srb->sg_index; idx < srb->sg_count; idx++) { + dprintkdbg(DBG_0, + "sg_update_list: Transfered %i of %i bytes, %i remain\n", + xferred, srb->total_xfer_length, left); + if (xferred == 0) { + /* nothing to update since we did not transfer any data */ + return; + } + + sg_verify_length(srb); + srb->total_xfer_length = left; /* update remaining count */ + for (idx = srb->sg_index; idx < srb->sg_count; idx++) { + if (xferred >= psge->length) { /* Complete SG entries done */ - if (xferred >= psge->length) - xferred -= psge->length; - /* Partial SG entries done */ - else { - psge->length -= xferred; /* residue data length */ - psge->address += xferred; /* residue data pointer */ - srb->sg_index = idx; - pci_dma_sync_single(srb->dcb-> - acb->dev, - srb->sg_bus_addr, - sizeof(struct SGentry) - * - DC395x_MAX_SG_LISTENTRY, - PCI_DMA_TODEVICE); - break; - } - psge++; + xferred -= psge->length; + } else { + /* Partial SG entry done */ + psge->length -= xferred; + psge->address += xferred; + srb->sg_index = idx; + pci_dma_sync_single_for_device(srb->dcb-> + acb->dev, + srb->sg_bus_addr, + SEGMENTX_LEN, + PCI_DMA_TODEVICE); + break; } - check_sg_list(srb); + psge++; } - /* We need the corresponding virtual address sg_to_virt */ - /*dprintkl(KERN_DEBUG, "sg_to_virt: bus %08x -> virt ", psge->address); */ + sg_verify_length(srb); + + /* we need the corresponding virtual address */ if (!segment) { srb->virt_addr += xferred; - /*printk("%p\n", srb->virt_addr); */ return; } + /* We have to walk the scatterlist to find it */ - sg = (struct scatterlist *) cmd->request_buffer; + sg = (struct scatterlist *)cmd->request_buffer; while (segment--) { - /*printk("(%08x)%p ", BUS_ADDR(*sg), PAGE_ADDRESS(sg)); */ unsigned long mask = - ~((unsigned long) sg->length - 1) & PAGE_MASK; - if ((BUS_ADDR(*sg) & mask) == (psge->address & mask)) { - srb->virt_addr = (PAGE_ADDRESS(sg) + ~((unsigned long)sg->length - 1) & PAGE_MASK; + if ((sg_dma_address(sg) & mask) == (psge->address & mask)) { + srb->virt_addr = (page_address(sg->page) + psge->address - (psge->address & PAGE_MASK)); - /*printk("%p\n", srb->virt_addr); */ return; } ++sg; } - dprintkl(KERN_ERR, "sg_to_virt failed!\n"); + + dprintkl(KERN_ERR, "sg_update_list: sg_to_virt failed\n"); srb->virt_addr = 0; } +/* + * We have transfered a single byte (PIO mode?) and need to update + * the count of bytes remaining (total_xfer_length) and update the sg + * entry to either point to next byte in the current sg entry, or of + * already at the end to point to the start of the next sg entry + */ +static void sg_subtract_one(struct ScsiReqBlk *srb) +{ + srb->total_xfer_length--; + srb->segment_x[srb->sg_index].length--; + if (srb->total_xfer_length && + !srb->segment_x[srb->sg_index].length) { + if (debug_enabled(DBG_PIO)) + printk(" (next segment)"); + srb->sg_index++; + sg_update_list(srb, srb->total_xfer_length); + } +} + + /* * cleanup_after_transfer * @@ -2467,27 +2027,21 @@ * Should probably also be called from other places * Best might be to call it in DataXXPhase0, if new phase will differ */ -static -void cleanup_after_transfer(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb) +static void cleanup_after_transfer(struct AdapterCtlBlk *acb, + struct ScsiReqBlk *srb) { - TRACEPRINTF(" Cln*"); /*DC395x_write8 (TRM_S1040_DMA_STATUS, FORCEDMACOMP); */ if (DC395x_read16(acb, TRM_S1040_DMA_COMMAND) & 0x0001) { /* read */ if (!(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x40)) - clear_fifo(acb, "ClnIn"); - + clear_fifo(acb, "cleanup/in"); if (!(DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT) & 0x80)) DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO); } else { /* write */ if (!(DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT) & 0x80)) DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO); - if (!(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x40)) - clear_fifo(acb, "ClnOut"); - + clear_fifo(acb, "cleanup/out"); } - /*1.25 */ DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); } @@ -2497,26 +2051,16 @@ * Seems to be needed for unknown reasons; could be a hardware bug :-( */ #define DC395x_LASTPIO 4 -/* - ******************************************************************** - * scsiio - * data_out_phase0: one of dc395x_scsi_phase0[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase0[phase] - * if phase =0 - ******************************************************************** - */ -static -void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) + + +static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) { - u16 scsi_status; - u32 d_left_counter = 0; struct DeviceCtlBlk *dcb = srb->dcb; - - dprintkdbg(DBG_0, "data_out_phase0.....\n"); - TRACEPRINTF("DOP0*"); - dcb = srb->dcb; - scsi_status = *pscsi_status; + u16 scsi_status = *pscsi_status; + u32 d_left_counter = 0; + dprintkdbg(DBG_0, "data_out_phase0: (pid#%li) <%02i-%i>\n", + srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun); /* * KG: We need to drain the buffers before we draw any conclusions! @@ -2530,12 +2074,14 @@ * KG: Stop DMA engine pushing more data into the SCSI FIFO * If we need more data, the DMA SG list will be freshly set up, anyway */ - dprintkdbg(DBG_PIO, "DOP0: DMA_FCNT: %02x, DMA_FSTAT: %02x, SCSI_FCNT: %02x, CTR %06x, stat %04x, Tot: %06x\n", - DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), - DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), - DC395x_read32(acb, TRM_S1040_SCSI_COUNTER), scsi_status, - srb->total_xfer_length); + dprintkdbg(DBG_PIO, "data_out_phase0: " + "DMA{fifcnt=0x%02x fifostat=0x%02x} " + "SCSI{fifocnt=0x%02x cnt=0x%06x status=0x%04x} total=0x%06x\n", + DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), + DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), + DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), + DC395x_read32(acb, TRM_S1040_SCSI_COUNTER), scsi_status, + srb->total_xfer_length); DC395x_write8(acb, TRM_S1040_DMA_CONTROL, STOPDMAXFER | CLRXFIFO); if (!(srb->state & SRB_XFERPAD)) { @@ -2554,31 +2100,21 @@ * if there was some data left in SCSI FIFO */ d_left_counter = - (u32) (DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & - 0x1F); + (u32)(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & + 0x1F); if (dcb->sync_period & WIDE_SYNC) d_left_counter <<= 1; - dprintkdbg(DBG_KG, - "Debug: SCSI FIFO contains %i %s in DOP0\n", - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), - (dcb-> - sync_period & WIDE_SYNC) ? "words" : - "bytes"); - dprintkdbg(DBG_KG, - "SCSI FIFOCNT %02x, SCSI CTR %08x\n", - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), - DC395x_read32(acb, TRM_S1040_SCSI_COUNTER)); - dprintkdbg(DBG_KG, - "DMA FIFOCNT %04x, FIFOSTAT %02x, DMA CTR %08x\n", - DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), - DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), - DC395x_read32(acb, TRM_S1040_DMA_CXCNT)); - - /* - * if WIDE scsi SCSI FIFOCNT unit is word !!! - * so need to *= 2 - */ + dprintkdbg(DBG_KG, "data_out_phase0: FIFO contains %i %s\n" + "SCSI{fifocnt=0x%02x cnt=0x%08x} " + "DMA{fifocnt=0x%04x cnt=0x%02x ctr=0x%08x}\n", + DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), + (dcb->sync_period & WIDE_SYNC) ? "words" : "bytes", + DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), + DC395x_read32(acb, TRM_S1040_SCSI_COUNTER), + DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), + DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), + DC395x_read32(acb, TRM_S1040_DMA_CXCNT)); } /* * calculate all the residue data that not yet tranfered @@ -2592,16 +2128,16 @@ if (srb->total_xfer_length > DC395x_LASTPIO) d_left_counter += DC395x_read32(acb, TRM_S1040_SCSI_COUNTER); - TRACEPRINTF("%06x *", d_left_counter); /* Is this a good idea? */ - /*clear_fifo (acb, "DOP1"); */ + /*clear_fifo(acb, "DOP1"); */ /* KG: What is this supposed to be useful for? WIDE padding stuff? */ if (d_left_counter == 1 && dcb->sync_period & WIDE_SYNC && srb->cmd->request_bufflen % 2) { d_left_counter = 0; - dprintkl(KERN_INFO, "DOP0: Discard 1 byte. (%02x)\n", - scsi_status); + dprintkl(KERN_INFO, + "data_out_phase0: Discard 1 byte (0x%02x)\n", + scsi_status); } /* * KG: Oops again. Same thinko as above: The SCSI might have been @@ -2613,19 +2149,9 @@ * KG: This is nonsense: We have been WRITING data to the bus * If the SCSI engine has no bytes left, how should the DMA engine? */ - if ((d_left_counter == - 0) /*|| (scsi_status & SCSIXFERCNT_2_ZERO) ) */ ) { - /* - * int ctr = 6000000; u8 TempDMAstatus; - * do - * { - * TempDMAstatus = DC395x_read8(acb, TRM_S1040_DMA_STATUS); - * } while( !(TempDMAstatus & DMAXFERCOMP) && --ctr); - * if (ctr < 6000000-1) dprintkl(KERN_DEBUG, "DMA should be complete ... in DOP1\n"); - * if (!ctr) dprintkl(KERN_ERR, "Deadlock in DataOutPhase0 !!\n"); - */ + if (d_left_counter == 0) { srb->total_xfer_length = 0; - } else { /* Update SG list */ + } else { /* * if transfer not yet complete * there were some data residue in SCSI FIFO or @@ -2635,18 +2161,18 @@ srb->total_xfer_length - d_left_counter; const int diff = (dcb->sync_period & WIDE_SYNC) ? 2 : 1; - update_sg_list(srb, d_left_counter); + sg_update_list(srb, d_left_counter); /* KG: Most ugly hack! Apparently, this works around a chip bug */ if ((srb->segment_x[srb->sg_index].length == diff && srb->cmd->use_sg) || ((oldxferred & ~PAGE_MASK) == (PAGE_SIZE - diff)) ) { - dprintkl(KERN_INFO, - "Work around chip bug (%i)?\n", diff); + dprintkl(KERN_INFO, "data_out_phase0: " + "Work around chip bug (%i)?\n", diff); d_left_counter = srb->total_xfer_length - diff; - update_sg_list(srb, d_left_counter); + sg_update_list(srb, d_left_counter); /*srb->total_xfer_length -= diff; */ /*srb->virt_addr += diff; */ /*if (srb->cmd->use_sg) */ @@ -2654,71 +2180,30 @@ } } } -#if 0 - if (!(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x40)) - dprintkl(KERN_DEBUG, - "DOP0(%li): %i bytes in SCSI FIFO! (Clear!)\n", - srb->cmd->pid, - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x1f); -#endif - /*clear_fifo (acb, "DOP0"); */ - /*DC395x_write8 (TRM_S1040_DMA_CONTROL, CLRXFIFO | ABORTXFER); */ -#if 1 if ((*pscsi_status & PHASEMASK) != PH_DATA_OUT) { - /*dprintkl(KERN_DEBUG, "Debug: Clean up after Data Out ...\n"); */ cleanup_after_transfer(acb, srb); } -#endif - TRACEPRINTF(".*"); } -/* - ******************************************************************** - * scsiio - * data_out_phase1: one of dc395x_scsi_phase0[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase0[phase] - * if phase =0 - * 62037 - ******************************************************************** - */ -static -void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) +static void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) { - - dprintkdbg(DBG_0, "data_out_phase1.....\n"); - /*1.25 */ - TRACEPRINTF("DOP1*"); - clear_fifo(acb, "DOP1"); - /* - ** do prepare befor transfer when data out phase - */ + dprintkdbg(DBG_0, "data_out_phase1: (pid#%li) <%02i-%i>\n", + srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun); + clear_fifo(acb, "data_out_phase1"); + /* do prepare before transfer when data out phase */ data_io_transfer(acb, srb, XFERDATAOUT); - TRACEPRINTF(".*"); } -/* - ******************************************************************** - * scsiio - * data_in_phase0: one of dc395x_scsi_phase1[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase1[phase] - * if phase =1 - ******************************************************************** - */ -static -void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) +static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) { - u16 scsi_status; + u16 scsi_status = *pscsi_status; u32 d_left_counter = 0; - /*struct DeviceCtlBlk* dcb = srb->dcb; */ - /*u8 bval; */ - - dprintkdbg(DBG_0, "data_in_phase0..............\n"); - TRACEPRINTF("DIP0*"); - scsi_status = *pscsi_status; + dprintkdbg(DBG_0, "data_in_phase0: (pid#%li) <%02i-%i>\n", + srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun); /* * KG: DataIn is much more tricky than DataOut. When the device is finished @@ -2735,10 +2220,8 @@ */ if (!(srb->state & SRB_XFERPAD)) { if (scsi_status & PARITYERROR) { - dprintkl(KERN_INFO, - "Parity Error (pid %li, target %02i-%i)\n", - srb->cmd->pid, srb->cmd->device->id, - srb->cmd->device->lun); + dprintkl(KERN_INFO, "data_in_phase0: (pid#%li) " + "Parity Error\n", srb->cmd->pid); srb->status |= PARITY_ERROR; } /* @@ -2751,7 +2234,7 @@ #if 0 int ctr = 6000000; dprintkl(KERN_DEBUG, - "DIP0: Wait for DMA FIFO to flush ...\n"); + "DIP0: Wait for DMA FIFO to flush ...\n"); /*DC395x_write8 (TRM_S1040_DMA_CONTROL, STOPDMAXFER); */ /*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 7); */ /*DC395x_write8 (TRM_S1040_SCSI_COMMAND, SCMD_DMA_IN); */ @@ -2766,73 +2249,56 @@ "Deadlock in DIP0 waiting for DMA FIFO empty!!\n"); /*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 0); */ #endif - dprintkdbg(DBG_KG, "DIP0: DMA_FIFO: %02x %02x\n", - DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), - DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT)); + dprintkdbg(DBG_KG, "data_in_phase0: " + "DMA{fifocnt=0x%02x fifostat=0x%02x}\n", + DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), + DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT)); } /* Now: Check remainig data: The SCSI counters should tell us ... */ d_left_counter = DC395x_read32(acb, TRM_S1040_SCSI_COUNTER) + ((DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x1f) << ((srb->dcb->sync_period & WIDE_SYNC) ? 1 : 0)); - - dprintkdbg(DBG_KG, "SCSI FIFO contains %i %s in DIP0\n", - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x1f, - (srb->dcb-> - sync_period & WIDE_SYNC) ? "words" : "bytes"); - dprintkdbg(DBG_KG, "SCSI FIFOCNT %02x, SCSI CTR %08x\n", - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), - DC395x_read32(acb, TRM_S1040_SCSI_COUNTER)); - dprintkdbg(DBG_KG, "DMA FIFOCNT %02x,%02x DMA CTR %08x\n", - DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), - DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), - DC395x_read32(acb, TRM_S1040_DMA_CXCNT)); - dprintkdbg(DBG_KG, "Remaining: TotXfer: %i, SCSI FIFO+Ctr: %i\n", - srb->total_xfer_length, d_left_counter); + dprintkdbg(DBG_KG, "data_in_phase0: " + "SCSI{fifocnt=0x%02x%s ctr=0x%08x} " + "DMA{fifocnt=0x%02x fifostat=0x%02x ctr=0x%08x} " + "Remain{totxfer=%i scsi_fifo+ctr=%i}\n", + DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), + (srb->dcb->sync_period & WIDE_SYNC) ? "words" : "bytes", + DC395x_read32(acb, TRM_S1040_SCSI_COUNTER), + DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), + DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), + DC395x_read32(acb, TRM_S1040_DMA_CXCNT), + srb->total_xfer_length, d_left_counter); #if DC395x_LASTPIO /* KG: Less than or equal to 4 bytes can not be transfered via DMA, it seems. */ if (d_left_counter && srb->total_xfer_length <= DC395x_LASTPIO) { /*u32 addr = (srb->segment_x[srb->sg_index].address); */ - /*update_sg_list (srb, d_left_counter); */ - dprintkdbg(DBG_PIO, "DIP0: PIO (%i %s) to %p for remaining %i bytes:", - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & - 0x1f, - (srb->dcb-> - sync_period & WIDE_SYNC) ? "words" : - "bytes", srb->virt_addr, - srb->total_xfer_length); - + /*sg_update_list (srb, d_left_counter); */ + dprintkdbg(DBG_PIO, "data_in_phase0: PIO (%i %s) to " + "%p for remaining %i bytes:", + DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x1f, + (srb->dcb->sync_period & WIDE_SYNC) ? + "words" : "bytes", + srb->virt_addr, + srb->total_xfer_length); if (srb->dcb->sync_period & WIDE_SYNC) DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, CFG2_WIDEFIFO); - - while (DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) != - 0x40) { - u8 byte = - DC395x_read8(acb, TRM_S1040_SCSI_FIFO); + while (DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) != 0x40) { + u8 byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); *(srb->virt_addr)++ = byte; if (debug_enabled(DBG_PIO)) printk(" %02x", byte); - srb->total_xfer_length--; d_left_counter--; - srb->segment_x[srb->sg_index].length--; - if (srb->total_xfer_length - && !srb->segment_x[srb->sg_index]. - length) { - if (debug_enabled(DBG_PIO)) - printk(" (next segment)"); - srb->sg_index++; - update_sg_list(srb, - d_left_counter); - } + sg_subtract_one(srb); } if (srb->dcb->sync_period & WIDE_SYNC) { -#if 1 /* Read the last byte ... */ +#if 1 + /* Read the last byte ... */ if (srb->total_xfer_length > 0) { - u8 byte = - DC395x_read8 - (acb, TRM_S1040_SCSI_FIFO); + u8 byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); *(srb->virt_addr)++ = byte; srb->total_xfer_length--; if (debug_enabled(DBG_PIO)) @@ -2859,8 +2325,8 @@ * if there was some data left in SCSI FIFO */ d_left_counter = - (u32) (DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & - 0x1F); + (u32)(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & + 0x1F); if (srb->dcb->sync_period & WIDE_SYNC) d_left_counter <<= 1; /* @@ -2870,19 +2336,8 @@ */ } #endif - /*d_left_counter += DC395x_read32(acb, TRM_S1040_SCSI_COUNTER); */ -#if 0 - dprintkl(KERN_DEBUG, - "DIP0: ctr=%08x, DMA_FIFO=%02x,%02x SCSI_FIFO=%02x\n", - d_left_counter, DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), - DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT)); - dprintkl(KERN_DEBUG, "DIP0: DMAStat %02x\n", - DC395x_read8(acb, TRM_S1040_DMA_STATUS)); -#endif - /* KG: This should not be needed any more! */ - if ((d_left_counter == 0) + if (d_left_counter == 0 || (scsi_status & SCSIXFERCNT_2_ZERO)) { #if 0 int ctr = 6000000; @@ -2896,12 +2351,6 @@ "Deadlock in DataInPhase0 waiting for DMA!!\n"); srb->total_xfer_length = 0; #endif -#if 0 /*def DBG_KG */ - dprintkl(KERN_DEBUG, - "DIP0: DMA not yet ready: %02x: %i -> %i bytes\n", - DC395x_read8(acb, TRM_S1040_DMA_STATUS), - srb->total_xfer_length, d_left_counter); -#endif srb->total_xfer_length = d_left_counter; } else { /* phase changed */ /* @@ -2912,333 +2361,209 @@ * there were some data residue in SCSI FIFO or * SCSI transfer counter not empty */ - update_sg_list(srb, d_left_counter); + sg_update_list(srb, d_left_counter); } } /* KG: The target may decide to disconnect: Empty FIFO before! */ if ((*pscsi_status & PHASEMASK) != PH_DATA_IN) { - /*dprintkl(KERN_DEBUG, "Debug: Clean up after Data In ...\n"); */ cleanup_after_transfer(acb, srb); } -#if 0 - /* KG: Make sure, no previous transfers are pending! */ - bval = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT); - if (!(bval & 0x40)) { - bval &= 0x1f; - dprintkl(KERN_DEBUG, - "DIP0(%li): %i bytes in SCSI FIFO (stat %04x) (left %08x)!!\n", - srb->cmd->pid, bval & 0x1f, scsi_status, - d_left_counter); - if ((d_left_counter == 0) - || (scsi_status & SCSIXFERCNT_2_ZERO)) { - dprintkl(KERN_DEBUG, "Clear FIFO!\n"); - clear_fifo(acb, "DIP0"); - } - } -#endif - /*DC395x_write8 (TRM_S1040_DMA_CONTROL, CLRXFIFO | ABORTXFER); */ - - /*clear_fifo (acb, "DIP0"); */ - /*DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_DATALATCH); */ - TRACEPRINTF(".*"); } -/* - ******************************************************************** - * scsiio - * data_in_phase1: one of dc395x_scsi_phase0[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase0[phase] - * if phase =1 - ******************************************************************** - */ -static -void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) -{ - dprintkdbg(DBG_0, "data_in_phase1.....\n"); - /* FIFO should be cleared, if previous phase was not DataPhase */ - /*clear_fifo (acb, "DIP1"); */ - /* Allow data in! */ - /*DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_DATALATCH); */ - TRACEPRINTF("DIP1:*"); - /* - ** do prepare before transfer when data in phase - */ +static void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) +{ + dprintkdbg(DBG_0, "data_in_phase1: (pid#%li) <%02i-%i>\n", + srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun); data_io_transfer(acb, srb, XFERDATAIN); - TRACEPRINTF(".*"); } -/* - ******************************************************************** - * scsiio - * data_out_phase1 - * data_in_phase1 - ******************************************************************** - */ -static -void data_io_transfer(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 io_dir) +static void data_io_transfer(struct AdapterCtlBlk *acb, + struct ScsiReqBlk *srb, u16 io_dir) { + struct DeviceCtlBlk *dcb = srb->dcb; u8 bval; - struct DeviceCtlBlk *dcb; - - dprintkdbg(DBG_0, "DataIO_transfer %c (pid %li): len = %i, SG: %i/%i\n", - ((io_dir & DMACMD_DIR) ? 'r' : 'w'), srb->cmd->pid, - srb->total_xfer_length, srb->sg_index, - srb->sg_count); - TRACEPRINTF("%05x(%i/%i)*", srb->total_xfer_length, - srb->sg_index, srb->sg_count); - dcb = srb->dcb; - if (srb == acb->tmp_srb) { - dprintkl(KERN_ERR, "Using tmp_srb in DataPhase!\n"); - } - if (srb->sg_index < srb->sg_count) { - if (srb->total_xfer_length > DC395x_LASTPIO) { - u8 dma_status = DC395x_read8(acb, TRM_S1040_DMA_STATUS); - /* - * KG: What should we do: Use SCSI Cmd 0x90/0x92? - * Maybe, even ABORTXFER would be appropriate - */ - if (dma_status & XFERPENDING) { - dprintkl(KERN_DEBUG, "Xfer pending! Expect trouble!!\n"); - dump_register_info(acb, dcb, srb); - DC395x_write8(acb, TRM_S1040_DMA_CONTROL, - CLRXFIFO); - } - /*clear_fifo (acb, "IO"); */ - /* - * load what physical address of Scatter/Gather list table want to be - * transfer - */ - srb->state |= SRB_DATA_XFER; - DC395x_write32(acb, TRM_S1040_DMA_XHIGHADDR, 0); - if (srb->cmd->use_sg) { /* with S/G */ - io_dir |= DMACMD_SG; - DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR, - srb->sg_bus_addr + - sizeof(struct SGentry) * - srb->sg_index); - /* load how many bytes in the Scatter/Gather list table */ - DC395x_write32(acb, TRM_S1040_DMA_XCNT, - ((u32) - (srb->sg_count - - srb->sg_index) << 3)); - } else { /* without S/G */ - io_dir &= ~DMACMD_SG; - DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR, - srb->segment_x[0].address); - DC395x_write32(acb, TRM_S1040_DMA_XCNT, - srb->segment_x[0].length); - } - /* load total transfer length (24bits) max value 16Mbyte */ - DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, - srb->total_xfer_length); - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ - if (io_dir & DMACMD_DIR) { /* read */ - DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, - SCMD_DMA_IN); - DC395x_write16(acb, TRM_S1040_DMA_COMMAND, - io_dir); - } else { - DC395x_write16(acb, TRM_S1040_DMA_COMMAND, - io_dir); - DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, - SCMD_DMA_OUT); - } + dprintkdbg(DBG_0, + "data_io_transfer: (pid#%li) <%02i-%i> %c len=%i, sg=(%i/%i)\n", + srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun, + ((io_dir & DMACMD_DIR) ? 'r' : 'w'), + srb->total_xfer_length, srb->sg_index, srb->sg_count); + if (srb == acb->tmp_srb) + dprintkl(KERN_ERR, "data_io_transfer: Using tmp_srb!\n"); + if (srb->sg_index >= srb->sg_count) { + /* can't happen? out of bounds error */ + return; + } + if (srb->total_xfer_length > DC395x_LASTPIO) { + u8 dma_status = DC395x_read8(acb, TRM_S1040_DMA_STATUS); + /* + * KG: What should we do: Use SCSI Cmd 0x90/0x92? + * Maybe, even ABORTXFER would be appropriate + */ + if (dma_status & XFERPENDING) { + dprintkl(KERN_DEBUG, "data_io_transfer: Xfer pending! " + "Expect trouble!\n"); + dump_register_info(acb, dcb, srb); + DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO); } + /* clear_fifo(acb, "IO"); */ + /* + * load what physical address of Scatter/Gather list table + * want to be transfer + */ + srb->state |= SRB_DATA_XFER; + DC395x_write32(acb, TRM_S1040_DMA_XHIGHADDR, 0); + if (srb->cmd->use_sg) { /* with S/G */ + io_dir |= DMACMD_SG; + DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR, + srb->sg_bus_addr + + sizeof(struct SGentry) * + srb->sg_index); + /* load how many bytes in the sg list table */ + DC395x_write32(acb, TRM_S1040_DMA_XCNT, + ((u32)(srb->sg_count - + srb->sg_index) << 3)); + } else { /* without S/G */ + io_dir &= ~DMACMD_SG; + DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR, + srb->segment_x[0].address); + DC395x_write32(acb, TRM_S1040_DMA_XCNT, + srb->segment_x[0].length); + } + /* load total transfer length (24bits) max value 16Mbyte */ + DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, + srb->total_xfer_length); + DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ + if (io_dir & DMACMD_DIR) { /* read */ + DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, + SCMD_DMA_IN); + DC395x_write16(acb, TRM_S1040_DMA_COMMAND, io_dir); + } else { + DC395x_write16(acb, TRM_S1040_DMA_COMMAND, io_dir); + DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, + SCMD_DMA_OUT); + } + + } #if DC395x_LASTPIO - else if (srb->total_xfer_length > 0) { /* The last four bytes: Do PIO */ - /*clear_fifo (acb, "IO"); */ - /* - * load what physical address of Scatter/Gather list table want to be - * transfer - */ - srb->state |= SRB_DATA_XFER; - /* load total transfer length (24bits) max value 16Mbyte */ - DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, - srb->total_xfer_length); - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ - if (io_dir & DMACMD_DIR) { /* read */ - DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, - SCMD_FIFO_IN); - } else { /* write */ - int ln = srb->total_xfer_length; - if (srb->dcb->sync_period & WIDE_SYNC) - DC395x_write8 - (acb, TRM_S1040_SCSI_CONFIG2, - CFG2_WIDEFIFO); - dprintkdbg(DBG_PIO, "DOP1: PIO %i bytes from %p:", - srb->total_xfer_length, - srb->virt_addr); - while (srb->total_xfer_length) { - if (debug_enabled(DBG_PIO)) - printk(" %02x", (unsigned char) *(srb->virt_addr)); - DC395x_write8 - (acb, TRM_S1040_SCSI_FIFO, - *(srb->virt_addr)++); - srb->total_xfer_length--; - srb->segment_x[srb->sg_index]. - length--; - if (srb->total_xfer_length - && !srb->segment_x[srb-> - sg_index]. - length) { - if (debug_enabled(DBG_PIO)) - printk(" (next segment)"); - srb->sg_index++; - update_sg_list(srb, - srb->total_xfer_length); - } - } - if (srb->dcb->sync_period & WIDE_SYNC) { - if (ln % 2) { - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); - if (debug_enabled(DBG_PIO)) - printk(" |00"); - } - DC395x_write8 - (acb, TRM_S1040_SCSI_CONFIG2, 0); - } - /*DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, ln); */ + else if (srb->total_xfer_length > 0) { /* The last four bytes: Do PIO */ + /* + * load what physical address of Scatter/Gather list table + * want to be transfer + */ + srb->state |= SRB_DATA_XFER; + /* load total transfer length (24bits) max value 16Mbyte */ + DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, + srb->total_xfer_length); + DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ + if (io_dir & DMACMD_DIR) { /* read */ + DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, + SCMD_FIFO_IN); + } else { /* write */ + int ln = srb->total_xfer_length; + if (srb->dcb->sync_period & WIDE_SYNC) + DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, + CFG2_WIDEFIFO); + dprintkdbg(DBG_PIO, + "data_io_transfer: PIO %i bytes from %p:", + srb->total_xfer_length, srb->virt_addr); + + while (srb->total_xfer_length) { if (debug_enabled(DBG_PIO)) - printk("\n"); - DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, - SCMD_FIFO_OUT); - } - } -#endif /* DC395x_LASTPIO */ - else { /* xfer pad */ + printk(" %02x", (unsigned char) *(srb->virt_addr)); - u8 data = 0, data2 = 0; - if (srb->sg_count) { - srb->adapter_status = H_OVER_UNDER_RUN; - srb->status |= OVER_RUN; + DC395x_write8(acb, TRM_S1040_SCSI_FIFO, + *(srb->virt_addr)++); + + sg_subtract_one(srb); } - /* - * KG: despite the fact that we are using 16 bits I/O ops - * the SCSI FIFO is only 8 bits according to the docs - * (we can set bit 1 in 0x8f to serialize FIFO access ...) - */ - if (dcb->sync_period & WIDE_SYNC) { - DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 2); - DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, - CFG2_WIDEFIFO); - if (io_dir & DMACMD_DIR) { /* read */ - data = - DC395x_read8 - (acb, TRM_S1040_SCSI_FIFO); - data2 = - DC395x_read8 - (acb, TRM_S1040_SCSI_FIFO); - /*dprintkl(KERN_DEBUG, "DataIO: Xfer pad: %02x %02x\n", data, data2); */ - } else { - /* Danger, Robinson: If you find KGs scattered over the wide - * disk, the driver or chip is to blame :-( */ - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, - 'K'); - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, - 'G'); + if (srb->dcb->sync_period & WIDE_SYNC) { + if (ln % 2) { + DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); + if (debug_enabled(DBG_PIO)) + printk(" |00"); } DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0); + } + /*DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, ln); */ + if (debug_enabled(DBG_PIO)) + printk("\n"); + DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, + SCMD_FIFO_OUT); + } + } +#endif /* DC395x_LASTPIO */ + else { /* xfer pad */ + u8 data = 0, data2 = 0; + if (srb->sg_count) { + srb->adapter_status = H_OVER_UNDER_RUN; + srb->status |= OVER_RUN; + } + /* + * KG: despite the fact that we are using 16 bits I/O ops + * the SCSI FIFO is only 8 bits according to the docs + * (we can set bit 1 in 0x8f to serialize FIFO access ...) + */ + if (dcb->sync_period & WIDE_SYNC) { + DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 2); + DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, + CFG2_WIDEFIFO); + if (io_dir & DMACMD_DIR) { + data = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); + data2 = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); } else { - DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1); - /* Danger, Robinson: If you find a collection of Ks on your disk - * something broke :-( */ - if (io_dir & DMACMD_DIR) { /* read */ - data = - DC395x_read8 - (acb, TRM_S1040_SCSI_FIFO); - /*dprintkl(KERN_DEBUG, "DataIO: Xfer pad: %02x\n", data); */ - } else { - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, - 'K'); - } + /* Danger, Robinson: If you find KGs + * scattered over the wide disk, the driver + * or chip is to blame :-( */ + DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'K'); + DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'G'); } - srb->state |= SRB_XFERPAD; - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ - /* - * SCSI command - */ - bval = - (io_dir & DMACMD_DIR) ? SCMD_FIFO_IN : - SCMD_FIFO_OUT; - DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, bval); + DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0); + } else { + DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1); + /* Danger, Robinson: If you find a collection of Ks on your disk + * something broke :-( */ + if (io_dir & DMACMD_DIR) + data = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); + else + DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'K'); } + srb->state |= SRB_XFERPAD; + DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ + /* SCSI command */ + bval = (io_dir & DMACMD_DIR) ? SCMD_FIFO_IN : SCMD_FIFO_OUT; + DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, bval); } - /*monitor_next_irq = 2; */ - /*printk(" done\n"); */ } -/* - ******************************************************************** - * scsiio - * status_phase0: one of dc395x_scsi_phase0[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase0[phase] - * if phase =3 - ******************************************************************** - */ -static -void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) +static void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) { - dprintkdbg(DBG_0, "StatusPhase0 (pid %li)\n", srb->cmd->pid); - TRACEPRINTF("STP0 *"); + dprintkdbg(DBG_0, "status_phase0: (pid#%li) <%02i-%i>\n", + srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun); srb->target_status = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); srb->end_message = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); /* get message */ srb->state = SRB_COMPLETED; *pscsi_status = PH_BUS_FREE; /*.. initial phase */ - /*1.25 */ - /*clear_fifo (acb, "STP0"); */ DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ - /* - ** SCSI command - */ DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT); } -/* - ******************************************************************** - * scsiio - * status_phase1: one of dc395x_scsi_phase1[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase1[phase] - * if phase =3 - ******************************************************************** - */ -static -void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) -{ - dprintkdbg(DBG_0, "StatusPhase1 (pid=%li)\n", srb->cmd->pid); - TRACEPRINTF("STP1 *"); - /* Cleanup is now done at the end of DataXXPhase0 */ - /*cleanup_after_transfer (acb, srb); */ - +static void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) +{ + dprintkdbg(DBG_0, "status_phase1: (pid#%li) <%02i-%i>\n", + srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun); srb->state = SRB_STATUS; DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ - /* - * SCSI command - */ DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_COMP); } -/* Message handling */ - -#if 0 -/* Print received message */ -static void print_msg(u8 * msg_buf, u32 len) -{ - int i; - printk(" %02x", msg_buf[0]); - for (i = 1; i < len; i++) - printk(" %02x", msg_buf[i]); - printk("\n"); -} -#endif /* Check if the message is complete */ static inline u8 msgin_completed(u8 * msgbuf, u32 len) @@ -3260,53 +2585,44 @@ /* reject_msg */ -static inline -void msgin_reject(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) +static inline void msgin_reject(struct AdapterCtlBlk *acb, + struct ScsiReqBlk *srb) { srb->msgout_buf[0] = MESSAGE_REJECT; srb->msg_count = 1; DC395x_ENABLE_MSGOUT; srb->state &= ~SRB_MSGIN; srb->state |= SRB_MSGOUT; - dprintkl(KERN_INFO, - "Reject message %02x from %02i-%i\n", srb->msgin_buf[0], - srb->dcb->target_id, srb->dcb->target_lun); - TRACEPRINTF("\\*"); + dprintkl(KERN_INFO, "msgin_reject: 0x%02x <%02i-%i>\n", + srb->msgin_buf[0], + srb->dcb->target_id, srb->dcb->target_lun); } /* abort command */ -static inline -void enable_msgout_abort(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb) +static inline void enable_msgout_abort(struct AdapterCtlBlk *acb, + struct ScsiReqBlk *srb) { srb->msgout_buf[0] = ABORT; srb->msg_count = 1; DC395x_ENABLE_MSGOUT; srb->state &= ~SRB_MSGIN; srb->state |= SRB_MSGOUT; - /* - if (srb->dcb) - srb->dcb->flag &= ~ABORT_DEV_; - */ - TRACEPRINTF("#*"); } -static -struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb, - struct DeviceCtlBlk *dcb, - u8 tag) +static struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb, + struct DeviceCtlBlk *dcb, u8 tag) { struct ScsiReqBlk *srb = NULL; struct ScsiReqBlk *i; - + dprintkdbg(DBG_0, "msgin_qtag: (pid#%li) tag=%i srb=%p\n", + srb->cmd->pid, tag, srb); - dprintkdbg(DBG_0, "QTag Msg (SRB %p): %i\n", srb, tag); if (!(dcb->tag_mask & (1 << tag))) dprintkl(KERN_DEBUG, - "MsgIn_QTag: tag_mask (%08x) does not reserve tag %i!\n", - dcb->tag_mask, tag); + "msgin_qtag: tag_mask=0x%08x does not reserve tag %i!\n", + dcb->tag_mask, tag); if (list_empty(&dcb->srb_going_list)) goto mingx0; @@ -3319,8 +2635,8 @@ if (!srb) goto mingx0; - dprintkdbg(DBG_0, "pid %li (%i-%i)\n", srb->cmd->pid, - srb->dcb->target_id, srb->dcb->target_lun); + dprintkdbg(DBG_0, "msgin_qtag: (pid#%li) <%02i-%i>\n", + srb->cmd->pid, srb->dcb->target_id, srb->dcb->target_lun); if (dcb->flag & ABORT_DEV_) { /*srb->state = SRB_ABORT_SENT; */ enable_msgout_abort(acb, srb); @@ -3329,20 +2645,6 @@ if (!(srb->state & SRB_DISCONNECT)) goto mingx0; - /* Tag found */ - { - struct ScsiReqBlk *last_srb; - - TRACEPRINTF("[%s]*", dcb->active_srb->debugtrace); - TRACEPRINTF("RTag*"); - /* Just for debugging ... */ - - last_srb = srb; - srb = dcb->active_srb; - TRACEPRINTF("Found.*"); - srb = last_srb; - } - memcpy(srb->msgin_buf, dcb->active_srb->msgin_buf, acb->msg_len); srb->state |= dcb->active_srb->state; srb->state |= SRB_DATA_XFER; @@ -3357,15 +2659,13 @@ srb->msgout_buf[0] = MSG_ABORT_TAG; srb->msg_count = 1; DC395x_ENABLE_MSGOUT; - TRACEPRINTF("?*"); - dprintkl(KERN_DEBUG, "Unknown tag received: %i: abort !!\n", tag); + dprintkl(KERN_DEBUG, "msgin_qtag: Unknown tag %i - abort\n", tag); return srb; } -/* Reprogram registers */ -static inline void -reprogram_regs(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb) +static inline void reprogram_regs(struct AdapterCtlBlk *acb, + struct DeviceCtlBlk *dcb) { DC395x_write8(acb, TRM_S1040_SCSI_TARGETID, dcb->target_id); DC395x_write8(acb, TRM_S1040_SCSI_SYNC, dcb->sync_period); @@ -3375,12 +2675,12 @@ /* set async transfer mode */ -static -void msgin_set_async(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) +static void msgin_set_async(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) { struct DeviceCtlBlk *dcb = srb->dcb; - dprintkl(KERN_DEBUG, "Target %02i: No sync transfers\n", dcb->target_id); - TRACEPRINTF("!S *"); + dprintkl(KERN_DEBUG, "msgin_set_async: No sync transfers <%02i-%i>\n", + dcb->target_id, dcb->target_lun); + dcb->sync_mode &= ~(SYNC_NEGO_ENABLE); dcb->sync_mode |= SYNC_NEGO_DONE; /*dcb->sync_period &= 0; */ @@ -3392,26 +2692,23 @@ && !(dcb->sync_mode & WIDE_NEGO_DONE)) { build_wdtr(acb, dcb, srb); DC395x_ENABLE_MSGOUT; - dprintkdbg(DBG_0, "SDTR(rej): Try WDTR anyway ...\n"); + dprintkdbg(DBG_0, "msgin_set_async(rej): Try WDTR anyway\n"); } } /* set sync transfer mode */ -static -void msgin_set_sync(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) +static void msgin_set_sync(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) { + struct DeviceCtlBlk *dcb = srb->dcb; u8 bval; int fact; - struct DeviceCtlBlk *dcb = srb->dcb; - /*u8 oldsyncperiod = dcb->sync_period; */ - /*u8 oldsyncoffset = dcb->sync_offset; */ - - dprintkdbg(DBG_1, "Target %02i: Sync: %ins (%02i.%01i MHz) Offset %i\n", - dcb->target_id, srb->msgin_buf[3] << 2, - (250 / srb->msgin_buf[3]), - ((250 % srb->msgin_buf[3]) * 10) / srb->msgin_buf[3], - srb->msgin_buf[4]); + dprintkdbg(DBG_1, "msgin_set_sync: <%02i> Sync: %ins " + "(%02i.%01i MHz) Offset %i\n", + dcb->target_id, srb->msgin_buf[3] << 2, + (250 / srb->msgin_buf[3]), + ((250 % srb->msgin_buf[3]) * 10) / srb->msgin_buf[3], + srb->msgin_buf[4]); if (srb->msgin_buf[4] > 15) srb->msgin_buf[4] = 15; @@ -3430,8 +2727,8 @@ bval++; if (srb->msgin_buf[3] < clock_period[bval]) dprintkl(KERN_INFO, - "Increase sync nego period to %ins\n", - clock_period[bval] << 2); + "msgin_set_sync: Increase sync nego period to %ins\n", + clock_period[bval] << 2); srb->msgin_buf[3] = clock_period[bval]; dcb->sync_period &= 0xf0; dcb->sync_period |= ALT_SYNC | bval; @@ -3443,18 +2740,17 @@ fact = 250; dprintkl(KERN_INFO, - "Target %02i: %s Sync: %ins Offset %i (%02i.%01i MB/s)\n", - dcb->target_id, (fact == 500) ? "Wide16" : "", - dcb->min_nego_period << 2, dcb->sync_offset, - (fact / dcb->min_nego_period), - ((fact % dcb->min_nego_period) * 10 + + "Target %02i: %s Sync: %ins Offset %i (%02i.%01i MB/s)\n", + dcb->target_id, (fact == 500) ? "Wide16" : "", + dcb->min_nego_period << 2, dcb->sync_offset, + (fact / dcb->min_nego_period), + ((fact % dcb->min_nego_period) * 10 + dcb->min_nego_period / 2) / dcb->min_nego_period); - TRACEPRINTF("S%i *", dcb->min_nego_period << 2); if (!(srb->state & SRB_DO_SYNC_NEGO)) { /* Reply with corrected SDTR Message */ - dprintkl(KERN_DEBUG, " .. answer w/ %ins %i\n", - srb->msgin_buf[3] << 2, srb->msgin_buf[4]); + dprintkl(KERN_DEBUG, "msgin_set_sync: answer w/%ins %i\n", + srb->msgin_buf[3] << 2, srb->msgin_buf[4]); memcpy(srb->msgout_buf, srb->msgin_buf, 5); srb->msg_count = 5; @@ -3465,7 +2761,7 @@ && !(dcb->sync_mode & WIDE_NEGO_DONE)) { build_wdtr(acb, dcb, srb); DC395x_ENABLE_MSGOUT; - dprintkdbg(DBG_0, "SDTR: Also try WDTR ...\n"); + dprintkdbg(DBG_0, "msgin_set_sync: Also try WDTR\n"); } } srb->state &= ~SRB_DO_SYNC_NEGO; @@ -3475,14 +2771,12 @@ } -static inline -void msgin_set_nowide(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb) +static inline void msgin_set_nowide(struct AdapterCtlBlk *acb, + struct ScsiReqBlk *srb) { struct DeviceCtlBlk *dcb = srb->dcb; - dprintkdbg(DBG_KG, "WDTR got rejected from target %02i\n", - dcb->target_id); - TRACEPRINTF("!W *"); + dprintkdbg(DBG_1, "msgin_set_nowide: <%02i>\n", dcb->target_id); + dcb->sync_period &= ~WIDE_SYNC; dcb->sync_mode &= ~(WIDE_NEGO_ENABLE); dcb->sync_mode |= WIDE_NEGO_DONE; @@ -3492,23 +2786,24 @@ && !(dcb->sync_mode & SYNC_NEGO_DONE)) { build_sdtr(acb, dcb, srb); DC395x_ENABLE_MSGOUT; - dprintkdbg(DBG_0, "WDTR(rej): Try SDTR anyway ...\n"); + dprintkdbg(DBG_0, "msgin_set_nowide: Rejected. Try SDTR anyway\n"); } } -static -void msgin_set_wide(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) +static void msgin_set_wide(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) { struct DeviceCtlBlk *dcb = srb->dcb; u8 wide = (dcb->dev_mode & NTC_DO_WIDE_NEGO && acb->config & HCC_WIDE_CARD) ? 1 : 0; + dprintkdbg(DBG_1, "msgin_set_wide: <%02i>\n", dcb->target_id); + if (srb->msgin_buf[3] > wide) srb->msgin_buf[3] = wide; /* Completed */ if (!(srb->state & SRB_DO_WIDE_NEGO)) { dprintkl(KERN_DEBUG, - "Target %02i initiates Wide Nego ...\n", - dcb->target_id); + "msgin_set_wide: Wide nego initiated <%02i>\n", + dcb->target_id); memcpy(srb->msgout_buf, srb->msgin_buf, 4); srb->msg_count = 4; srb->state |= SRB_DO_WIDE_NEGO; @@ -3521,28 +2816,21 @@ else dcb->sync_period &= ~WIDE_SYNC; srb->state &= ~SRB_DO_WIDE_NEGO; - TRACEPRINTF("W%i *", (dcb->sync_period & WIDE_SYNC ? 1 : 0)); /*dcb->sync_mode &= ~(WIDE_NEGO_ENABLE+WIDE_NEGO_DONE); */ - dprintkdbg(DBG_KG, - "Wide transfers (%i bit) negotiated with target %02i\n", - (8 << srb->msgin_buf[3]), dcb->target_id); + dprintkdbg(DBG_1, + "msgin_set_wide: Wide (%i bit) negotiated <%02i>\n", + (8 << srb->msgin_buf[3]), dcb->target_id); reprogram_regs(acb, dcb); if ((dcb->sync_mode & SYNC_NEGO_ENABLE) && !(dcb->sync_mode & SYNC_NEGO_DONE)) { build_sdtr(acb, dcb, srb); DC395x_ENABLE_MSGOUT; - dprintkdbg(DBG_0, "WDTR: Also try SDTR ...\n"); + dprintkdbg(DBG_0, "msgin_set_wide: Also try SDTR.\n"); } } /* - ******************************************************************** - * scsiio - * msgin_phase0: one of dc395x_scsi_phase0[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase0[phase] - * if phase =7 - * * extended message codes: * * code description @@ -3553,25 +2841,15 @@ * 03h WIDE DATA TRANSFER REQUEST * 04h - 7Fh Reserved * 80h - FFh Vendor specific - * - ******************************************************************** */ -static -void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) +static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) { - struct DeviceCtlBlk *dcb; - - dprintkdbg(DBG_0, "msgin_phase0..............\n"); - TRACEPRINTF("MIP0*"); - dcb = acb->active_dcb; + struct DeviceCtlBlk *dcb = acb->active_dcb; + dprintkdbg(DBG_0, "msgin_phase0: (pid#%li)\n", srb->cmd->pid); srb->msgin_buf[acb->msg_len++] = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); if (msgin_completed(srb->msgin_buf, acb->msg_len)) { - TRACEPRINTF("(%02x)*", srb->msgin_buf[0]); - /*dprintkl(KERN_INFO, "MsgIn:"); */ - /*print_msg (srb->msgin_buf, acb->msg_len); */ - /* Now eval the msg */ switch (srb->msgin_buf[0]) { case DISCONNECT: @@ -3581,7 +2859,6 @@ case SIMPLE_QUEUE_TAG: case HEAD_OF_QUEUE_TAG: case ORDERED_QUEUE_TAG: - TRACEPRINTF("(%02x)*", srb->msgin_buf[1]); srb = msgin_qtag(acb, dcb, srb->msgin_buf[1]); @@ -3605,7 +2882,6 @@ break; case EXTENDED_MESSAGE: - TRACEPRINTF("(%02x)*", srb->msgin_buf[2]); /* SDTR */ if (srb->msgin_buf[1] == 3 && srb->msgin_buf[2] == EXTENDED_SDTR) { @@ -3613,52 +2889,51 @@ break; } /* WDTR */ - if (srb->msgin_buf[1] == 2 && srb->msgin_buf[2] == EXTENDED_WDTR && srb->msgin_buf[3] <= 2) { /* sanity check ... */ + if (srb->msgin_buf[1] == 2 + && srb->msgin_buf[2] == EXTENDED_WDTR + && srb->msgin_buf[3] <= 2) { /* sanity check ... */ msgin_set_wide(acb, srb); break; } msgin_reject(acb, srb); break; - /* Discard wide residual */ case MSG_IGNOREWIDE: - dprintkdbg(DBG_0, "Ignore Wide Residual!\n"); - /*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 1); */ - /*DC395x_read8 (TRM_S1040_SCSI_FIFO); */ + /* Discard wide residual */ + dprintkdbg(DBG_0, "msgin_phase0: Ignore Wide Residual!\n"); break; - /* nothing has to be done */ case COMMAND_COMPLETE: + /* nothing has to be done */ break; + case SAVE_POINTERS: /* - * SAVE POINTER may be ignored as we have the struct ScsiReqBlk* associated with the - * scsi command. Thanks, Gérard, for pointing it out. + * SAVE POINTER may be ignored as we have the struct + * ScsiReqBlk* associated with the scsi command. */ - case SAVE_POINTERS: - dprintkdbg(DBG_0, "SAVE POINTER message received (pid %li: rem.%i) ... ignore :-(\n", - srb->cmd->pid, srb->total_xfer_length); - /*srb->Saved_Ptr = srb->TotalxferredLen; */ + dprintkdbg(DBG_0, "msgin_phase0: (pid#%li) " + "SAVE POINTER rem=%i Ignore\n", + srb->cmd->pid, srb->total_xfer_length); break; - /* The device might want to restart transfer with a RESTORE */ + case RESTORE_POINTERS: - dprintkl(KERN_DEBUG, - "RESTORE POINTER message received ... ignore :-(\n"); - /*dc395x_restore_ptr (acb, srb); */ + dprintkdbg(DBG_0, "msgin_phase0: RESTORE POINTER. Ignore\n"); break; + case ABORT: - dprintkl(KERN_DEBUG, - "ABORT msg received (pid %li %02i-%i)\n", - srb->cmd->pid, dcb->target_id, - dcb->target_lun); + dprintkdbg(DBG_0, "msgin_phase0: (pid#%li) " + "<%02i-%i> ABORT msg\n", + srb->cmd->pid, dcb->target_id, + dcb->target_lun); dcb->flag |= ABORT_DEV_; enable_msgout_abort(acb, srb); break; - /* reject unknown messages */ + default: + /* reject unknown messages */ if (srb->msgin_buf[0] & IDENTIFY_BASE) { - dprintkl(KERN_DEBUG, "Identify Message received?\n"); - /*TRACEOUT (" %s\n", srb->debugtrace); */ + dprintkdbg(DBG_0, "msgin_phase0: Identify msg\n"); srb->msg_count = 1; srb->msgout_buf[0] = dcb->identify_msg; DC395x_ENABLE_MSGOUT; @@ -3666,104 +2941,51 @@ /*break; */ } msgin_reject(acb, srb); - TRACEOUT(" %s\n", srb->debugtrace); } - TRACEPRINTF(".*"); /* Clear counter and MsgIn state */ srb->state &= ~SRB_MSGIN; acb->msg_len = 0; } - - /*1.25 */ - if ((*pscsi_status & PHASEMASK) != PH_MSG_IN) -#if 0 - clear_fifo(acb, "MIP0_"); -#else - TRACEPRINTF("N/Cln *"); -#endif *pscsi_status = PH_BUS_FREE; DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important ... you know! */ DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT); } -/* - ******************************************************************** - * scsiio - * msgin_phase1: one of dc395x_scsi_phase1[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase1[phase] - * if phase =7 - ******************************************************************** - */ -static -void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) -{ - dprintkdbg(DBG_0, "msgin_phase1..............\n"); - TRACEPRINTF("MIP1 *"); - clear_fifo(acb, "MIP1"); +static void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) +{ + dprintkdbg(DBG_0, "msgin_phase1: (pid#%li)\n", srb->cmd->pid); + clear_fifo(acb, "msgin_phase1"); DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1); if (!(srb->state & SRB_MSGIN)) { srb->state &= ~SRB_DISCONNECT; srb->state |= SRB_MSGIN; } DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ - /* - * SCSI command - */ + /* SCSI command */ DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_IN); } -/* - ******************************************************************** - * scsiio - * nop0: one of dc395x_scsi_phase1[] ,dc395x_scsi_phase0[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase0[phase] - * dc395x_statev = (void *)dc395x_scsi_phase1[phase] - * if phase =4 ..PH_BUS_FREE - ******************************************************************** - */ -static -void nop0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) +static void nop0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) { - /*TRACEPRINTF("NOP0 *"); */ } -/* - ******************************************************************** - * scsiio - * nop1: one of dc395x_scsi_phase0[] ,dc395x_scsi_phase1[] vectors - * dc395x_statev = (void *)dc395x_scsi_phase0[phase] - * dc395x_statev = (void *)dc395x_scsi_phase1[phase] - * if phase =5 - ******************************************************************** - */ -static -void nop1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 * pscsi_status) +static void nop1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, + u16 *pscsi_status) { - /*TRACEPRINTF("NOP1 *"); */ } -/* - ******************************************************************** - * scsiio - * msgin_phase0 - ******************************************************************** - */ -static -void set_xfer_rate(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb) +static void set_xfer_rate(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb) { struct DeviceCtlBlk *i; - /* - * set all lun device's period , offset - */ + /* set all lun device's period, offset */ if (dcb->identify_msg & 0x07) return; @@ -3782,47 +3004,39 @@ } -/* - ******************************************************************** - * scsiio - * dc395x_interrupt - ******************************************************************** - */ static void disconnect(struct AdapterCtlBlk *acb) { - struct DeviceCtlBlk *dcb; + struct DeviceCtlBlk *dcb = acb->active_dcb; struct ScsiReqBlk *srb; - dprintkdbg(DBG_0, "Disconnect (pid=%li)\n", acb->active_dcb->active_srb->cmd->pid); - dcb = acb->active_dcb; if (!dcb) { - dprintkl(KERN_ERR, "Disc: Exception Disconnect dcb=NULL !!\n "); + dprintkl(KERN_ERR, "disconnect: No such device\n"); udelay(500); /* Suspend queue for a while */ acb->scsi_host->last_reset = jiffies + HZ / 2 + HZ * acb->eeprom.delay_time; - clear_fifo(acb, "DiscEx"); + clear_fifo(acb, "disconnectEx"); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT); return; } srb = dcb->active_srb; acb->active_dcb = NULL; - TRACEPRINTF("DISC *"); + dprintkdbg(DBG_0, "disconnect: (pid#%li)\n", srb->cmd->pid); srb->scsi_phase = PH_BUS_FREE; /* initial phase */ - clear_fifo(acb, "Disc"); + clear_fifo(acb, "disconnect"); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT); if (srb->state & SRB_UNEXPECT_RESEL) { - dprintkl(KERN_ERR, "Disc: Unexpected Reselection (%i-%i)\n", - dcb->target_id, dcb->target_lun); + dprintkl(KERN_ERR, + "disconnect: Unexpected reselection <%02i-%i>\n", + dcb->target_id, dcb->target_lun); srb->state = 0; waiting_process_next(acb); } else if (srb->state & SRB_ABORT_SENT) { - /*Scsi_Cmnd* cmd = srb->cmd; */ dcb->flag &= ~ABORT_DEV_; acb->scsi_host->last_reset = jiffies + HZ / 2 + 1; - dprintkl(KERN_ERR, "Disc: SRB_ABORT_SENT!\n"); + dprintkl(KERN_ERR, "disconnect: SRB_ABORT_SENT\n"); doing_srb_done(acb, DID_ABORT, srb->cmd, 1); waiting_process_next(acb); } else { @@ -3837,19 +3051,16 @@ if (srb->state != SRB_START_ && srb->state != SRB_MSGOUT) { srb->state = SRB_READY; - dprintkl(KERN_DEBUG, "Unexpected Disconnection (pid %li)!\n", - srb->cmd->pid); + dprintkl(KERN_DEBUG, + "disconnect: (pid#%li) Unexpected\n", + srb->cmd->pid); srb->target_status = SCSI_STAT_SEL_TIMEOUT; - TRACEPRINTF("UnExpD *"); - TRACEOUT("%s\n", srb->debugtrace); goto disc1; } else { /* Normal selection timeout */ - TRACEPRINTF("SlTO *"); - dprintkdbg(DBG_KG, - "Disc: SelTO (pid=%li) for dev %02i-%i\n", - srb->cmd->pid, dcb->target_id, - dcb->target_lun); + dprintkdbg(DBG_KG, "disconnect: (pid#%li) " + "<%02i-%i> SelTO\n", srb->cmd->pid, + dcb->target_id, dcb->target_lun); if (srb->retry_count++ > DC395x_MAX_RETRIES || acb->scan_devices) { srb->target_status = @@ -3858,8 +3069,9 @@ } free_tag(dcb, srb); srb_going_to_waiting_move(dcb, srb); - dprintkdbg(DBG_KG, "Retry pid %li ...\n", - srb->cmd->pid); + dprintkdbg(DBG_KG, + "disconnect: (pid#%li) Retry\n", + srb->cmd->pid); waiting_set_timer(acb, HZ / 20); } } else if (srb->state & SRB_DISCONNECT) { @@ -3867,18 +3079,11 @@ /* * SRB_DISCONNECT (This is what we expect!) */ - /* dprintkl(KERN_DEBUG, "DoWaitingSRB (pid=%li)\n", srb->cmd->pid); */ - TRACEPRINTF("+*"); if (bval & 0x40) { - dprintkdbg(DBG_0, "Debug: DISC: SCSI bus stat %02x: ACK set! Other controllers?\n", + dprintkdbg(DBG_0, "disconnect: SCSI bus stat " + " 0x%02x: ACK set! Other controllers?\n", bval); /* It could come from another initiator, therefore don't do much ! */ - TRACEPRINTF("ACK(%02x) *", bval); - /*dump_register_info (acb, dcb, srb); */ - /*TRACEOUT (" %s\n", srb->debugtrace); */ - /*dcb->flag |= ABORT_DEV_; */ - /*enable_msgout_abort (acb, srb); */ - /*DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_CLRFIFO | DO_CLRATN | DO_HWRESELECT); */ } else waiting_process_next(acb); } else if (srb->state & SRB_COMPLETED) { @@ -3889,51 +3094,40 @@ free_tag(dcb, srb); dcb->active_srb = NULL; srb->state = SRB_FREE; - /*dprintkl(KERN_DEBUG, "done (pid=%li)\n", srb->cmd->pid); */ srb_done(acb, dcb, srb); } } - return; } -/* - ******************************************************************** - * scsiio - * reselect - ******************************************************************** - */ static void reselect(struct AdapterCtlBlk *acb) { - struct DeviceCtlBlk *dcb; + struct DeviceCtlBlk *dcb = acb->active_dcb; struct ScsiReqBlk *srb = NULL; u16 rsel_tar_lun_id; u8 id, lun; u8 arblostflag = 0; + dprintkdbg(DBG_0, "reselect: acb=%p\n", acb); - dprintkdbg(DBG_0, "reselect..............\n"); - - clear_fifo(acb, "Resel"); + clear_fifo(acb, "reselect"); /*DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT | DO_DATALATCH); */ /* Read Reselected Target ID and LUN */ rsel_tar_lun_id = DC395x_read16(acb, TRM_S1040_SCSI_TARGETID); - dcb = acb->active_dcb; if (dcb) { /* Arbitration lost but Reselection win */ srb = dcb->active_srb; if (!srb) { - dprintkl(KERN_DEBUG, "Arb lost Resel won, but active_srb == NULL!\n"); + dprintkl(KERN_DEBUG, "reselect: Arb lost Resel won, " + "but active_srb == NULL\n"); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ return; } /* Why the if ? */ - if (!(acb->scan_devices)) { - dprintkdbg(DBG_KG, - "Arb lost but Resel win pid %li (%02i-%i) Rsel %04x Stat %04x\n", - srb->cmd->pid, dcb->target_id, - dcb->target_lun, rsel_tar_lun_id, - DC395x_read16(acb, TRM_S1040_SCSI_STATUS)); - TRACEPRINTF("ArbLResel!*"); - /*TRACEOUT (" %s\n", srb->debugtrace); */ + if (!acb->scan_devices) { + dprintkdbg(DBG_KG, "reselect: (pid#%li) <%02i-%i> " + "Arb lost but Resel win rsel=%i stat=0x%04x\n", + srb->cmd->pid, dcb->target_id, + dcb->target_lun, rsel_tar_lun_id, + DC395x_read16(acb, TRM_S1040_SCSI_STATUS)); arblostflag = 1; /*srb->state |= SRB_DISCONNECT; */ @@ -3947,47 +3141,37 @@ } /* Read Reselected Target Id and LUN */ if (!(rsel_tar_lun_id & (IDENTIFY_BASE << 8))) - dprintkl(KERN_DEBUG, "Resel expects identify msg! Got %04x!\n", - rsel_tar_lun_id); + dprintkl(KERN_DEBUG, "reselect: Expects identify msg. " + "Got %i!\n", rsel_tar_lun_id); id = rsel_tar_lun_id & 0xff; lun = (rsel_tar_lun_id >> 8) & 7; dcb = find_dcb(acb, id, lun); if (!dcb) { - dprintkl(KERN_ERR, "Reselect from non existing device (%02i-%i)\n", - id, lun); + dprintkl(KERN_ERR, "reselect: From non existent device " + "<%02i-%i>\n", id, lun); DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ return; } - acb->active_dcb = dcb; if (!(dcb->dev_mode & NTC_DO_DISCONNECT)) - dprintkl(KERN_DEBUG, "Reselection in spite of forbidden disconnection? (%02i-%i)\n", - dcb->target_id, dcb->target_lun); + dprintkl(KERN_DEBUG, "reselect: in spite of forbidden " + "disconnection? <%02i-%i>\n", + dcb->target_id, dcb->target_lun); - if ((dcb->sync_mode & EN_TAG_QUEUEING) /*&& !arblostflag */ ) { - struct ScsiReqBlk *oldSRB = srb; + if (dcb->sync_mode & EN_TAG_QUEUEING /*&& !arblostflag */) { srb = acb->tmp_srb; -#if debug_enabled(DBG_TRACE|DBG_TRACEALL) - srb->debugpos = 0; - srb->debugtrace[0] = 0; -#endif dcb->active_srb = srb; - if (oldSRB) - TRACEPRINTF("ArbLResel(%li):*", oldSRB->cmd->pid); - /*if (arblostflag) dprintkl(KERN_DEBUG, "Reselect: Wait for Tag ... \n"); */ } else { /* There can be only one! */ srb = dcb->active_srb; - if (srb) - TRACEPRINTF("RSel *"); if (!srb || !(srb->state & SRB_DISCONNECT)) { /* * abort command */ dprintkl(KERN_DEBUG, - "Reselected w/o disconnected cmds from %02i-%i?\n", - dcb->target_id, dcb->target_lun); + "reselect: w/o disconnected cmds <%02i-%i>\n", + dcb->target_id, dcb->target_lun); srb = acb->tmp_srb; srb->state = SRB_UNEXPECT_RESEL; dcb->active_srb = srb; @@ -4000,14 +3184,11 @@ srb->state = SRB_DATA_XFER; } - /*if (arblostflag) TRACEOUT (" %s\n", srb->debugtrace); */ } srb->scsi_phase = PH_BUS_FREE; /* initial phase */ - /* - *********************************************** - ** Program HA ID, target ID, period and offset - *********************************************** - */ + + /* Program HA ID, target ID, period and offset */ + dprintkdbg(DBG_0, "reselect: select <%i>\n", dcb->target_id); DC395x_write8(acb, TRM_S1040_SCSI_HOSTID, acb->scsi_host->this_id); /* host ID */ DC395x_write8(acb, TRM_S1040_SCSI_TARGETID, dcb->target_id); /* target ID */ DC395x_write8(acb, TRM_S1040_SCSI_OFFSET, dcb->sync_offset); /* offset */ @@ -4018,10 +3199,6 @@ } - - - - static inline u8 tagq_blacklist(char *name) { #ifndef DC395x_NO_TAGQ @@ -4038,8 +3215,7 @@ } -static -void disc_tagq_set(struct DeviceCtlBlk *dcb, struct ScsiInqData *ptr) +static void disc_tagq_set(struct DeviceCtlBlk *dcb, struct ScsiInqData *ptr) { /* Check for SCSI format (ANSI and Response data format) */ if ((ptr->Vers & 0x07) >= 2 || (ptr->RDF & 0x0F) == 2) { @@ -4048,7 +3224,7 @@ /*(dcb->dev_mode & NTC_DO_DISCONNECT) */ /* ((dcb->dev_type == TYPE_DISK) || (dcb->dev_type == TYPE_MOD)) && */ - !tagq_blacklist(((char *) ptr) + 8)) { + !tagq_blacklist(((char *)ptr) + 8)) { if (dcb->max_command == 1) dcb->max_command = dcb->acb->tag_max_num; @@ -4060,9 +3236,8 @@ } -static -void add_dev(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, - struct ScsiInqData *ptr) +static void add_dev(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, + struct ScsiInqData *ptr) { u8 bval1 = ptr->DevType & SCSI_DEVTYPE; dcb->dev_type = bval1; @@ -4071,59 +3246,45 @@ } -/* - ******************************************************************** - * unmap mapped pci regions from SRB - ******************************************************************** - */ -static -void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) +/* unmap mapped pci regions from SRB */ +static void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) { - int dir; Scsi_Cmnd *cmd = srb->cmd; - dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + int dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); if (cmd->use_sg && dir != PCI_DMA_NONE) { /* unmap DC395x SG list */ - dprintkdbg(DBG_SGPARANOIA, - "Unmap SG descriptor list %08x (%05x)\n", - srb->sg_bus_addr, - sizeof(struct SGentry) * DC395x_MAX_SG_LISTENTRY); + dprintkdbg(DBG_SG, "pci_unmap_srb: list=%08x(%05x)\n", + srb->sg_bus_addr, SEGMENTX_LEN); pci_unmap_single(acb->dev, srb->sg_bus_addr, - sizeof(struct SGentry) * - DC395x_MAX_SG_LISTENTRY, + SEGMENTX_LEN, PCI_DMA_TODEVICE); - dprintkdbg(DBG_SGPARANOIA, "Unmap %i SG segments from %p\n", - cmd->use_sg, cmd->request_buffer); + dprintkdbg(DBG_SG, "pci_unmap_srb: segs=%i buffer=%p\n", + cmd->use_sg, cmd->request_buffer); /* unmap the sg segments */ pci_unmap_sg(acb->dev, - (struct scatterlist *) cmd->request_buffer, + (struct scatterlist *)cmd->request_buffer, cmd->use_sg, dir); } else if (cmd->request_buffer && dir != PCI_DMA_NONE) { - dprintkdbg(DBG_SGPARANOIA, "Unmap buffer at %08x (%05x)\n", - srb->segment_x[0].address, cmd->request_bufflen); + dprintkdbg(DBG_SG, "pci_unmap_srb: buffer=%08x(%05x)\n", + srb->segment_x[0].address, cmd->request_bufflen); pci_unmap_single(acb->dev, srb->segment_x[0].address, cmd->request_bufflen, dir); } } -/* - ******************************************************************** - * unmap mapped pci sense buffer from SRB - ******************************************************************** - */ -static -void pci_unmap_srb_sense(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) +/* unmap mapped pci sense buffer from SRB */ +static void pci_unmap_srb_sense(struct AdapterCtlBlk *acb, + struct ScsiReqBlk *srb) { if (!(srb->flag & AUTO_REQSENSE)) return; /* Unmap sense buffer */ - dprintkdbg(DBG_SGPARANOIA, "Unmap sense buffer from %08x\n", + dprintkdbg(DBG_SG, "pci_unmap_srb_sense: buffer=%08x\n", srb->segment_x[0].address); pci_unmap_single(acb->dev, srb->segment_x[0].address, srb->segment_x[0].length, PCI_DMA_FROMDEVICE); /* Restore SG stuff */ - /*printk ("Auto_ReqSense finished: Restore Counters ...\n"); */ srb->total_xfer_length = srb->xferred; srb->segment_x[0].address = srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].address; @@ -4133,42 +3294,33 @@ /* - ******************************************************************** - * scsiio - * disconnect - * Complete execution of a SCSI command - * Signal completion to the generic SCSI driver - ******************************************************************** + * Complete execution of a SCSI command + * Signal completion to the generic SCSI driver */ -static -void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) +static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, + struct ScsiReqBlk *srb) { u8 tempcnt, status; - Scsi_Cmnd *cmd; + Scsi_Cmnd *cmd = srb->cmd; struct ScsiInqData *ptr; - /*u32 drv_flags=0; */ int dir; - cmd = srb->cmd; - TRACEPRINTF("DONE *"); - dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); - ptr = (struct ScsiInqData *) (cmd->request_buffer); - if (cmd->use_sg) - ptr = - (struct ScsiInqData *) CPU_ADDR(*(struct scatterlist *) - ptr); - dprintkdbg(DBG_SGPARANOIA, - "SRBdone SG=%i (%i/%i), req_buf = %p, adr = %p\n", - cmd->use_sg, srb->sg_index, srb->sg_count, - cmd->request_buffer, ptr); - dprintkdbg(DBG_KG, - "SRBdone (pid %li, target %02i-%i): ", srb->cmd->pid, - srb->cmd->device->id, srb->cmd->device->lun); + if (cmd->use_sg) { + struct scatterlist* sg = (struct scatterlist *)cmd->request_buffer; + ptr = (struct ScsiInqData *)(page_address(sg->page) + sg->offset); + } else { + ptr = (struct ScsiInqData *)(cmd->request_buffer); + } + + dprintkdbg(DBG_1, "srb_done: (pid#%li) <%02i-%i>\n", srb->cmd->pid, + srb->cmd->device->id, srb->cmd->device->lun); + dprintkdbg(DBG_SG, "srb_done: srb=%p sg=%i(%i/%i) buf=%p addr=%p\n", + srb, cmd->use_sg, srb->sg_index, srb->sg_count, + cmd->request_buffer, ptr); status = srb->target_status; if (srb->flag & AUTO_REQSENSE) { - dprintkdbg(DBG_0, "AUTO_REQSENSE1..............\n"); + dprintkdbg(DBG_0, "srb_done: AUTO_REQSENSE1\n"); pci_unmap_srb_sense(acb, srb); /* ** target status.......................... @@ -4176,61 +3328,60 @@ srb->flag &= ~AUTO_REQSENSE; srb->adapter_status = 0; srb->target_status = CHECK_CONDITION << 1; - if (debug_enabled(DBG_KG)) { + if (debug_enabled(DBG_1)) { switch (cmd->sense_buffer[2] & 0x0f) { case NOT_READY: dprintkl(KERN_DEBUG, - "ReqSense: NOT_READY (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ", + "ReqSense: NOT_READY cmnd=0x%02x <%02i-%i> stat=%i scan=%i ", cmd->cmnd[0], dcb->target_id, dcb->target_lun, status, acb->scan_devices); break; case UNIT_ATTENTION: dprintkl(KERN_DEBUG, - "ReqSense: UNIT_ATTENTION (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ", + "ReqSense: UNIT_ATTENTION cmnd=0x%02x <%02i-%i> stat=%i scan=%i ", cmd->cmnd[0], dcb->target_id, dcb->target_lun, status, acb->scan_devices); break; case ILLEGAL_REQUEST: dprintkl(KERN_DEBUG, - "ReqSense: ILLEGAL_REQUEST (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ", + "ReqSense: ILLEGAL_REQUEST cmnd=0x%02x <%02i-%i> stat=%i scan=%i ", cmd->cmnd[0], dcb->target_id, dcb->target_lun, status, acb->scan_devices); break; case MEDIUM_ERROR: dprintkl(KERN_DEBUG, - "ReqSense: MEDIUM_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ", + "ReqSense: MEDIUM_ERROR cmnd=0x%02x <%02i-%i> stat=%i scan=%i ", cmd->cmnd[0], dcb->target_id, dcb->target_lun, status, acb->scan_devices); break; case HARDWARE_ERROR: dprintkl(KERN_DEBUG, - "ReqSense: HARDWARE_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ", + "ReqSense: HARDWARE_ERROR cmnd=0x%02x <%02i-%i> stat=%i scan=%i ", cmd->cmnd[0], dcb->target_id, dcb->target_lun, status, acb->scan_devices); break; } if (cmd->sense_buffer[7] >= 6) - dprintkl(KERN_DEBUG, - "Sense=%02x, ASC=%02x, ASCQ=%02x (%08x %08x) ", - cmd->sense_buffer[2], cmd->sense_buffer[12], - cmd->sense_buffer[13], - *((unsigned int *) (cmd->sense_buffer + 3)), - *((unsigned int *) (cmd->sense_buffer + 8))); + printk("sense=0x%02x ASC=0x%02x ASCQ=0x%02x " + "(0x%08x 0x%08x)\n", + cmd->sense_buffer[2], cmd->sense_buffer[12], + cmd->sense_buffer[13], + *((unsigned int *)(cmd->sense_buffer + 3)), + *((unsigned int *)(cmd->sense_buffer + 8))); else - dprintkl(KERN_DEBUG, - "Sense=%02x, No ASC/ASCQ (%08x) ", - cmd->sense_buffer[2], - *((unsigned int *) (cmd->sense_buffer + 3))); + printk("sense=0x%02x No ASC/ASCQ (0x%08x)\n", + cmd->sense_buffer[2], + *((unsigned int *)(cmd->sense_buffer + 3))); } if (status == (CHECK_CONDITION << 1)) { cmd->result = DID_BAD_TARGET << 16; goto ckc_e; } - dprintkdbg(DBG_0, "AUTO_REQSENSE2..............\n"); + dprintkdbg(DBG_0, "srb_done: AUTO_REQSENSE2\n"); - if ((srb->total_xfer_length) - && (srb->total_xfer_length >= cmd->underflow)) + if (srb->total_xfer_length + && srb->total_xfer_length >= cmd->underflow) cmd->result = MK_RES_LNX(DRIVER_SENSE, DID_OK, srb->end_message, CHECK_CONDITION); @@ -4253,8 +3404,7 @@ return; } else if (status_byte(status) == QUEUE_FULL) { tempcnt = (u8)list_size(&dcb->srb_going_list); - printk - ("\nDC395x: QUEUE_FULL for dev %02i-%i with %i cmnds\n", + dprintkl(KERN_INFO, "QUEUE_FULL for dev <%02i-%i> with %i cmnds\n", dcb->target_id, dcb->target_lun, tempcnt); if (tempcnt > 1) tempcnt--; @@ -4298,11 +3448,11 @@ if (dir != PCI_DMA_NONE) { if (cmd->use_sg) - pci_dma_sync_sg(acb->dev, - (struct scatterlist *) cmd-> + pci_dma_sync_sg_for_cpu(acb->dev, + (struct scatterlist *)cmd-> request_buffer, cmd->use_sg, dir); else if (cmd->request_buffer) - pci_dma_sync_single(acb->dev, + pci_dma_sync_single_for_cpu(acb->dev, srb->segment_x[0].address, cmd->request_bufflen, dir); } @@ -4336,48 +3486,35 @@ cmd->SCp.buffers_residual = 0; if (debug_enabled(DBG_KG)) { if (srb->total_xfer_length) - dprintkdbg(DBG_KG, "pid %li: %02x (%02i-%i): Missed %i bytes\n", - cmd->pid, cmd->cmnd[0], cmd->device->id, - cmd->device->lun, srb->total_xfer_length); + dprintkdbg(DBG_KG, "srb_done: (pid#%li) <%02i-%i> " + "cmnd=0x%02x Missed %i bytes\n", + cmd->pid, cmd->device->id, cmd->device->lun, + cmd->cmnd[0], srb->total_xfer_length); } srb_going_remove(dcb, srb); /* Add to free list */ if (srb == acb->tmp_srb) - dprintkl(KERN_ERR, "ERROR! Completed Cmnd with tmp_srb!\n"); - else + dprintkl(KERN_ERR, "srb_done: ERROR! Completed cmd with tmp_srb\n"); + else { + dprintkdbg(DBG_0, "srb_done: (pid#%li) done result=0x%08x\n", + cmd->pid, cmd->result); srb_free_insert(acb, srb); - - dprintkdbg(DBG_0, "SRBdone: done pid %li\n", cmd->pid); - if (debug_enabled(DBG_KG)) { - printk(" 0x%08x\n", cmd->result); } - TRACEPRINTF("%08x(%li)*", cmd->result, jiffies); pci_unmap_srb(acb, srb); - /*DC395x_UNLOCK_ACB_NI; */ - cmd->scsi_done(cmd); - /*DC395x_LOCK_ACB_NI; */ - TRACEOUTALL(KERN_INFO " %s\n", srb->debugtrace); + cmd->scsi_done(cmd); waiting_process_next(acb); - return; } -/* - ******************************************************************** - * scsiio - * DC395x_reset - * abort all cmds in our queues - ******************************************************************** - */ -static -void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag, - Scsi_Cmnd * cmd, u8 force) +/* abort all cmds in our queues */ +static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag, + Scsi_Cmnd *cmd, u8 force) { struct DeviceCtlBlk *dcb; - dprintkl(KERN_INFO, "doing_srb_done: pids "); + list_for_each_entry(dcb, &acb->dcb_list, list) { struct ScsiReqBlk *srb; struct ScsiReqBlk *tmp; @@ -4390,16 +3527,8 @@ p = srb->cmd; dir = scsi_to_pci_dma_dir(p->sc_data_direction); result = MK_RES(0, did_flag, 0, 0); - - /*result = MK_RES(0,DID_RESET,0,0); */ - TRACEPRINTF("Reset(%li):%08x*", jiffies, result); - printk(" (G)"); -#if 1 /*ndef DC395x_DEBUGTRACE */ - printk("%li(%02i-%i) ", p->pid, + printk("G:%li(%02i-%i) ", p->pid, p->device->id, p->device->lun); -#endif - TRACEOUT("%s\n", srb->debugtrace); - srb_going_remove(dcb, srb); free_tag(dcb, srb); srb_free_insert(acb, srb); @@ -4414,11 +3543,11 @@ } if (!list_empty(&dcb->srb_going_list)) dprintkl(KERN_DEBUG, - "How could the ML send cmnds to the Going queue? (%02i-%i)!!\n", + "How could the ML send cmnds to the Going queue? <%02i-%i>\n", dcb->target_id, dcb->target_lun); if (dcb->tag_mask) dprintkl(KERN_DEBUG, - "tag_mask for %02i-%i should be empty, is %08x!\n", + "tag_mask for <%02i-%i> should be empty, is %08x!\n", dcb->target_id, dcb->target_lun, dcb->tag_mask); @@ -4428,16 +3557,10 @@ p = srb->cmd; result = MK_RES(0, did_flag, 0, 0); - TRACEPRINTF("Reset(%li):%08x*", jiffies, result); - printk(" (W)"); -#if 1 /*ndef DC395x_DEBUGTRACE */ - printk("%li(%i-%i)", p->pid, p->device->id, + printk("W:%li<%02i-%i>", p->pid, p->device->id, p->device->lun); -#endif - TRACEOUT("%s\n", srb->debugtrace); srb_waiting_remove(dcb, srb); srb_free_insert(acb, srb); - p->result = result; pci_unmap_srb_sense(acb, srb); pci_unmap_srb(acb, srb); @@ -4448,41 +3571,26 @@ } } if (!list_empty(&dcb->srb_waiting_list)) - printk - ("\nDC395x: Debug: ML queued %i cmnds again to %02i-%i\n", + dprintkl(KERN_DEBUG, "ML queued %i cmnds again to <%02i-%i>\n", list_size(&dcb->srb_waiting_list), dcb->target_id, dcb->target_lun); - dcb->flag &= ~ABORT_DEV_; } printk("\n"); } -/* - ******************************************************************** - * scsiio - * DC395x_shutdown DC395x_reset - ******************************************************************** - */ static void reset_scsi_bus(struct AdapterCtlBlk *acb) { - /*u32 drv_flags=0; */ - - dprintkdbg(DBG_0, "reset_scsi_bus..............\n"); - - /*DC395x_DRV_LOCK(drv_flags); */ + dprintkdbg(DBG_0, "reset_scsi_bus: acb=%p\n", acb); acb->acb_flag |= RESET_DEV; /* RESET_DETECT, RESET_DONE, RESET_DEV */ - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_RSTSCSI); - while (!(DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS) & INT_SCSIRESET)); - /*DC395x_DRV_UNLOCK(drv_flags); */ - return; + while (!(DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS) & INT_SCSIRESET)) + /* nothing */; } -/* Set basic config */ static void set_basic_config(struct AdapterCtlBlk *acb) { u8 bval; @@ -4508,7 +3616,6 @@ wval = DC395x_read16(acb, TRM_S1040_DMA_CONFIG) & ~DMA_FIFO_CTRL; wval |= DMA_FIFO_HALF_HALF | DMA_ENHANCE /*| DMA_MEM_MULTI_READ */ ; - /*dprintkl(KERN_INFO, "DMA_Config: %04x\n", wval); */ DC395x_write16(acb, TRM_S1040_DMA_CONFIG, wval); /* Clear pending interrupt status */ DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS); @@ -4520,15 +3627,9 @@ } -/* - ******************************************************************** - * scsiio - * dc395x_interrupt - ******************************************************************** - */ static void scsi_reset_detect(struct AdapterCtlBlk *acb) { - dprintkl(KERN_INFO, "scsi_reset_detect\n"); + dprintkl(KERN_INFO, "scsi_reset_detect: acb=%p\n", acb); /* delay half a second */ if (timer_pending(&acb->waiting_timer)) del_timer(&acb->waiting_timer); @@ -4542,7 +3643,7 @@ jiffies + 5 * HZ / 2 + HZ * acb->eeprom.delay_time; - clear_fifo(acb, "RstDet"); + clear_fifo(acb, "scsi_reset_detect"); set_basic_config(acb); /*1.25 */ /*DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT); */ @@ -4558,28 +3659,16 @@ acb->acb_flag = 0; waiting_process_next(acb); } - - return; } -/* - ******************************************************************** - * scsiio - * srb_done - ******************************************************************** - */ -static -void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) +static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, + struct ScsiReqBlk *srb) { - Scsi_Cmnd *cmd; + Scsi_Cmnd *cmd = srb->cmd; + dprintkdbg(DBG_1, "request_sense: (pid#%li) <%02i-%i>\n", + cmd->pid, cmd->device->id, cmd->device->lun); - cmd = srb->cmd; - dprintkdbg(DBG_KG, - "request_sense for pid %li, target %02i-%i\n", - cmd->pid, cmd->device->id, cmd->device->lun); - TRACEPRINTF("RqSn*"); srb->flag |= AUTO_REQSENSE; srb->adapter_status = 0; srb->target_status = 0; @@ -4600,27 +3689,22 @@ srb->segment_x[0].address = pci_map_single(acb->dev, cmd->sense_buffer, sizeof(cmd->sense_buffer), PCI_DMA_FROMDEVICE); - dprintkdbg(DBG_SGPARANOIA, "Map sense buffer at %p (%05x) to %08x\n", - cmd->sense_buffer, sizeof(cmd->sense_buffer), - srb->segment_x[0].address); + dprintkdbg(DBG_SG, "request_sense: map buffer %p->%08x(%05x)\n", + cmd->sense_buffer, srb->segment_x[0].address, + sizeof(cmd->sense_buffer)); srb->sg_count = 1; srb->sg_index = 0; if (start_scsi(acb, dcb, srb)) { /* Should only happen, if sb. else grabs the bus */ dprintkl(KERN_DEBUG, - "Request Sense failed for pid %li (%02i-%i)!\n", - srb->cmd->pid, dcb->target_id, dcb->target_lun); - TRACEPRINTF("?*"); + "request_sense: (pid#%li) failed <%02i-%i>\n", + srb->cmd->pid, dcb->target_id, dcb->target_lun); srb_going_to_waiting_move(dcb, srb); waiting_set_timer(acb, HZ / 100); } - TRACEPRINTF(".*"); } - - - /** * device_alloc - Allocate a new device instance. This create the * devices instance and sets up all the data items. The adapter @@ -4634,18 +3718,17 @@ * * Return the new device if succesfull or NULL on failure. **/ -static -struct DeviceCtlBlk *device_alloc(struct AdapterCtlBlk *acb, u8 target, u8 lun) +static struct DeviceCtlBlk *device_alloc(struct AdapterCtlBlk *acb, + u8 target, u8 lun) { struct NvRamType *eeprom = &acb->eeprom; u8 period_index = eeprom->target[target].period & 0x07; struct DeviceCtlBlk *dcb; - dcb = dc395x_kmalloc(sizeof(struct DeviceCtlBlk), GFP_ATOMIC); - dprintkdbg(DBG_0, "device_alloc: device %p\n", dcb); - if (!dcb) { + dcb = kmalloc(sizeof(struct DeviceCtlBlk), GFP_ATOMIC); + dprintkdbg(DBG_0, "device_alloc: <%02i-%i>\n", target, lun); + if (!dcb) return NULL; - } dcb->acb = NULL; INIT_LIST_HEAD(&dcb->srb_going_list); INIT_LIST_HEAD(&dcb->srb_waiting_list); @@ -4684,10 +3767,10 @@ list_for_each_entry(p, &acb->dcb_list, list) if (p->target_id == dcb->target_id) break; - dprintkdbg(DBG_KG, - "Copy settings from %02i-%02i to %02i-%02i\n", - p->target_id, p->target_lun, - dcb->target_id, dcb->target_lun); + dprintkdbg(DBG_1, + "device_alloc: <%02i-%i> copy from <%02i-%i>\n", + dcb->target_id, dcb->target_lun, + p->target_id, p->target_lun); dcb->sync_mode = p->sync_mode; dcb->sync_period = p->sync_period; dcb->min_nego_period = p->min_nego_period; @@ -4704,8 +3787,8 @@ * @acb: The adapter device to be updated * @dcb: A newly created and intialised device instance to add. **/ -static -void adapter_add_device(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb) +static void adapter_add_device(struct AdapterCtlBlk *acb, + struct DeviceCtlBlk *dcb) { /* backpointer to adapter */ dcb->acb = acb; @@ -4732,13 +3815,13 @@ * @acb: The adapter device to be updated * @dcb: A device that has previously been added to the adapter. **/ -static -void adapter_remove_device(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb) +static void adapter_remove_device(struct AdapterCtlBlk *acb, + struct DeviceCtlBlk *dcb) { struct DeviceCtlBlk *i; struct DeviceCtlBlk *tmp; - dprintkdbg(DBG_0, "adapter_remove_device: Remove device (ID %i, LUN %i): %p\n", - dcb->target_id, dcb->target_lun, dcb); + dprintkdbg(DBG_0, "adapter_remove_device: <%02i-%i>\n", + dcb->target_id, dcb->target_lun); /* fix up any pointers to this device that we have in the adapter */ if (acb->active_dcb == dcb) @@ -4767,17 +3850,18 @@ * @acb: The adapter device to be updated * @dcb: A device that has previously been added to the adapter. */ -static -void adapter_remove_and_free_device(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb) +static void adapter_remove_and_free_device(struct AdapterCtlBlk *acb, + struct DeviceCtlBlk *dcb) { if (list_size(&dcb->srb_going_list) > 1) { - dprintkdbg(DBG_DCB, "adapter_remove_and_free_device: " - "Won't remove because of %i active requests\n", + dprintkdbg(DBG_1, "adapter_remove_and_free_device: <%02i-%i> " + "Won't remove because of %i active requests.\n", + dcb->target_id, dcb->target_lun, list_size(&dcb->srb_going_list)); return; } adapter_remove_device(acb, dcb); - dc395x_kfree(dcb); + kfree(dcb); } @@ -4787,12 +3871,11 @@ * * @acb: The adapter from which all devices should be removed. **/ -static -void adapter_remove_and_free_all_devices(struct AdapterCtlBlk* acb) +static void adapter_remove_and_free_all_devices(struct AdapterCtlBlk* acb) { struct DeviceCtlBlk *dcb; struct DeviceCtlBlk *tmp; - dprintkdbg(DBG_DCB, "adapter_remove_and_free_all_devices: Free all devices (%i devices)\n", + dprintkdbg(DBG_1, "adapter_remove_and_free_all_devices: num=%i\n", list_size(&acb->dcb_list)); list_for_each_entry_safe(dcb, tmp, &acb->dcb_list, list) @@ -4807,8 +3890,7 @@ * * @scsi_device: The new scsi device that we need to handle. **/ -static -int dc395x_slave_alloc(struct scsi_device *scsi_device) +static int dc395x_slave_alloc(struct scsi_device *scsi_device) { struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)scsi_device->host->hostdata; struct DeviceCtlBlk *dcb; @@ -4828,8 +3910,7 @@ * * @scsi_device: The new scsi device that we need to handle. **/ -static -void dc395x_slave_destroy(struct scsi_device *scsi_device) +static void dc395x_slave_destroy(struct scsi_device *scsi_device) { struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)scsi_device->host->hostdata; struct DeviceCtlBlk *dcb = find_dcb(acb, scsi_device->id, scsi_device->lun); @@ -4847,14 +3928,12 @@ * * @io_port: base I/O address **/ -static -void __init trms1040_wait_30us(u16 io_port) +static void __init trms1040_wait_30us(u16 io_port) { /* ScsiPortStallExecution(30); wait 30 us */ outb(5, io_port + TRM_S1040_GEN_TIMER); while (!(inb(io_port + TRM_S1040_GEN_STATUS) & GTIMEOUT)) /* nothing */ ; - return; } @@ -4866,8 +3945,7 @@ * @cmd: SB + op code (command) to send * @addr: address to send **/ -static -void __init trms1040_write_cmd(u16 io_port, u8 cmd, u8 addr) +static void __init trms1040_write_cmd(u16 io_port, u8 cmd, u8 addr) { int i; u8 send_data; @@ -4912,8 +3990,7 @@ * @addr: offset into EEPROM * @byte: bytes to write **/ -static -void __init trms1040_set_data(u16 io_port, u8 addr, u8 byte) +static void __init trms1040_set_data(u16 io_port, u8 addr, u8 byte) { int i; u8 send_data; @@ -4967,10 +4044,9 @@ * @eeprom: the data to write * @io_port: the base io port **/ -static -void __init trms1040_write_all(struct NvRamType *eeprom, u16 io_port) +static void __init trms1040_write_all(struct NvRamType *eeprom, u16 io_port) { - u8 *b_eeprom = (u8 *) eeprom; + u8 *b_eeprom = (u8 *)eeprom; u8 addr; /* Enable SEEPROM */ @@ -4983,9 +4059,8 @@ trms1040_wait_30us(io_port); /* write */ - for (addr = 0; addr < 128; addr++, b_eeprom++) { + for (addr = 0; addr < 128; addr++, b_eeprom++) trms1040_set_data(io_port, addr, *b_eeprom); - } /* write disable */ trms1040_write_cmd(io_port, 0x04, 0x00); @@ -5009,8 +4084,7 @@ * * Returns the the byte read. **/ -static -u8 __init trms1040_get_data(u16 io_port, u8 addr) +static u8 __init trms1040_get_data(u16 io_port, u8 addr) { int i; u8 read_byte; @@ -5048,10 +4122,9 @@ * @eeprom: where to store the data * @io_port: the base io port **/ -static -void __init trms1040_read_all(struct NvRamType *eeprom, u16 io_port) +static void __init trms1040_read_all(struct NvRamType *eeprom, u16 io_port) { - u8 *b_eeprom = (u8 *) eeprom; + u8 *b_eeprom = (u8 *)eeprom; u8 addr; /* Enable SEEPROM */ @@ -5059,9 +4132,8 @@ io_port + TRM_S1040_GEN_CONTROL); /* read details */ - for (addr = 0; addr < 128; addr++, b_eeprom++) { + for (addr = 0; addr < 128; addr++, b_eeprom++) *b_eeprom = trms1040_get_data(io_port, addr); - } /* Disable SEEPROM */ outb((inb(io_port + TRM_S1040_GEN_CONTROL) & ~EN_EEPROM), @@ -5080,10 +4152,9 @@ * @eeprom: caller allocated strcuture to read the eeprom data into * @io_port: io port to read from **/ -static -void __init check_eeprom(struct NvRamType *eeprom, u16 io_port) +static void __init check_eeprom(struct NvRamType *eeprom, u16 io_port) { - u16 *w_eeprom = (u16 *) eeprom; + u16 *w_eeprom = (u16 *)eeprom; u16 w_addr; u16 cksum; u32 d_addr; @@ -5092,7 +4163,7 @@ trms1040_read_all(eeprom, io_port); /* read eeprom */ cksum = 0; - for (w_addr = 0, w_eeprom = (u16 *) eeprom; w_addr < 64; + for (w_addr = 0, w_eeprom = (u16 *)eeprom; w_addr < 64; w_addr++, w_eeprom++) cksum += *w_eeprom; if (cksum != 0x1234) { @@ -5101,21 +4172,21 @@ * Load a set of defaults into the eeprom buffer */ dprintkl(KERN_WARNING, - "EEProm checksum error: using default values and options.\n"); - eeprom->sub_vendor_id[0] = (u8) PCI_VENDOR_ID_TEKRAM; - eeprom->sub_vendor_id[1] = (u8) (PCI_VENDOR_ID_TEKRAM >> 8); - eeprom->sub_sys_id[0] = (u8) PCI_DEVICE_ID_TEKRAM_TRMS1040; + "EEProm checksum error: using default values and options.\n"); + eeprom->sub_vendor_id[0] = (u8)PCI_VENDOR_ID_TEKRAM; + eeprom->sub_vendor_id[1] = (u8)(PCI_VENDOR_ID_TEKRAM >> 8); + eeprom->sub_sys_id[0] = (u8)PCI_DEVICE_ID_TEKRAM_TRMS1040; eeprom->sub_sys_id[1] = - (u8) (PCI_DEVICE_ID_TEKRAM_TRMS1040 >> 8); + (u8)(PCI_DEVICE_ID_TEKRAM_TRMS1040 >> 8); eeprom->sub_class = 0x00; - eeprom->vendor_id[0] = (u8) PCI_VENDOR_ID_TEKRAM; - eeprom->vendor_id[1] = (u8) (PCI_VENDOR_ID_TEKRAM >> 8); - eeprom->device_id[0] = (u8) PCI_DEVICE_ID_TEKRAM_TRMS1040; + eeprom->vendor_id[0] = (u8)PCI_VENDOR_ID_TEKRAM; + eeprom->vendor_id[1] = (u8)(PCI_VENDOR_ID_TEKRAM >> 8); + eeprom->device_id[0] = (u8)PCI_DEVICE_ID_TEKRAM_TRMS1040; eeprom->device_id[1] = - (u8) (PCI_DEVICE_ID_TEKRAM_TRMS1040 >> 8); + (u8)(PCI_DEVICE_ID_TEKRAM_TRMS1040 >> 8); eeprom->reserved = 0x00; - for (d_addr = 0, d_eeprom = (u32 *) eeprom->target; + for (d_addr = 0, d_eeprom = (u32 *)eeprom->target; d_addr < 16; d_addr++, d_eeprom++) *d_eeprom = 0x00000077; /* cfg3,cfg2,period,cfg0 */ @@ -5130,7 +4201,7 @@ eeprom_override(eeprom); eeprom->cksum = 0x00; - for (w_addr = 0, cksum = 0, w_eeprom = (u16 *) eeprom; + for (w_addr = 0, cksum = 0, w_eeprom = (u16 *)eeprom; w_addr < 63; w_addr++, w_eeprom++) cksum += *w_eeprom; @@ -5145,113 +4216,47 @@ } - - /** * print_eeprom_settings - output the eeprom settings * to the kernel log so people can see what they were. * * @eeprom: The eeprom data strucutre to show details for. **/ -static -void __init print_eeprom_settings(struct NvRamType *eeprom) +static void __init print_eeprom_settings(struct NvRamType *eeprom) { dprintkl(KERN_INFO, "Used settings: AdapterID=%02i, Speed=%i(%02i.%01iMHz), dev_mode=0x%02x\n", - eeprom->scsi_id, - eeprom->target[0].period, - clock_speed[eeprom->target[0].period] / 10, - clock_speed[eeprom->target[0].period] % 10, - eeprom->target[0].cfg0); + eeprom->scsi_id, + eeprom->target[0].period, + clock_speed[eeprom->target[0].period] / 10, + clock_speed[eeprom->target[0].period] % 10, + eeprom->target[0].cfg0); dprintkl(KERN_INFO, " AdaptMode=0x%02x, Tags=%i(%02i), DelayReset=%is\n", - eeprom->channel_cfg, - eeprom->max_tag, - 1 << eeprom->max_tag, - eeprom->delay_time); + eeprom->channel_cfg, eeprom->max_tag, + 1 << eeprom->max_tag, eeprom->delay_time); } - -#if debug_enabled(DBG_TRACE|DBG_TRACEALL) -/* - * Memory for trace buffers - */ -static -void free_tracebufs(struct AdapterCtlBlk *acb) -{ - int i; - const unsigned bufs_per_page = PAGE_SIZE / DEBUGTRACEBUFSZ; - - for (i = 0; i < srb_idx; i += bufs_per_page) - if (acb->srb_array[i].debugtrace) - dc395x_kfree(acb->srb_array[i].debugtrace); -} - - -static -int alloc_tracebufs(struct AdapterCtlBlk *acb) -{ - const unsigned mem_needed = - (DC395x_MAX_SRB_CNT + 1) * DEBUGTRACEBUFSZ; - int pages = (mem_needed + (PAGE_SIZE - 1)) / PAGE_SIZE; - const unsigned bufs_per_page = PAGE_SIZE / DEBUGTRACEBUFSZ; - int srb_idx = 0; - unsigned i = 0; - unsigned char *ptr; - - for (i = 0; i < DC395x_MAX_SRB_CNT; i++) - acb->srb_array[i].debugtrace = NULL; - - while (pages--) { - ptr = dc395x_kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!ptr) { - free_tracebufs(acb); - return 1; - } - /*dprintkl(KERN_DEBUG, "Alloc %li bytes at %p for tracebuf %i\n", */ - /* PAGE_SIZE, ptr, srb_idx); */ - i = 0; - while (i < bufs_per_page && srb_idx < DC395x_MAX_SRB_CNT) - acb->srb_array[srb_idx++].debugtrace = - ptr + (i++ * DEBUGTRACEBUFSZ); - } - if (i < bufs_per_page) { - acb->srb.debugtrace = ptr + (i * DEBUGTRACEBUFSZ); - acb->srb.debugtrace[0] = 0; - } else - dprintkl(KERN_DEBUG, "No space for tmsrb tracebuf reserved?!\n"); - return 0; -} -#else -static void free_tracebufs(struct AdapterCtlBlk *acb) {} -static int alloc_tracebufs(struct AdapterCtlBlk *acb) { return 0; } -#endif - /* Free SG tables */ -static -void adapter_sg_tables_free(struct AdapterCtlBlk *acb) +static void adapter_sg_tables_free(struct AdapterCtlBlk *acb) { int i; - const unsigned srbs_per_page = PAGE_SIZE/(DC395x_MAX_SG_LISTENTRY - *sizeof(struct SGentry)); + const unsigned srbs_per_page = PAGE_SIZE/SEGMENTX_LEN; for (i = 0; i < DC395x_MAX_SRB_CNT; i += srbs_per_page) if (acb->srb_array[i].segment_x) - dc395x_kfree(acb->srb_array[i].segment_x); + kfree(acb->srb_array[i].segment_x); } /* * Allocate SG tables; as we have to pci_map them, an SG list (struct SGentry*) * should never cross a page boundary */ -static -int __init adapter_sg_tables_alloc(struct AdapterCtlBlk *acb) +static int __init adapter_sg_tables_alloc(struct AdapterCtlBlk *acb) { const unsigned mem_needed = (DC395x_MAX_SRB_CNT+1) - *DC395x_MAX_SG_LISTENTRY - *sizeof(struct SGentry); + *SEGMENTX_LEN; int pages = (mem_needed+(PAGE_SIZE-1))/PAGE_SIZE; - const unsigned srbs_per_page = PAGE_SIZE/(DC395x_MAX_SG_LISTENTRY - *sizeof(struct SGentry)); + const unsigned srbs_per_page = PAGE_SIZE/SEGMENTX_LEN; int srb_idx = 0; unsigned i = 0; struct SGentry *ptr; @@ -5261,13 +4266,13 @@ dprintkdbg(DBG_1, "Allocate %i pages for SG tables\n", pages); while (pages--) { - ptr = (struct SGentry *)dc395x_kmalloc(PAGE_SIZE, GFP_KERNEL); + ptr = (struct SGentry *)kmalloc(PAGE_SIZE, GFP_KERNEL); if (!ptr) { adapter_sg_tables_free(acb); return 1; } dprintkdbg(DBG_1, "Allocate %li bytes at %p for SG segments %i\n", - PAGE_SIZE, ptr, srb_idx); + PAGE_SIZE, ptr, srb_idx); i = 0; while (i < srbs_per_page && srb_idx < DC395x_MAX_SRB_CNT) acb->srb_array[srb_idx++].segment_x = @@ -5292,14 +4297,13 @@ * * @acb: The adapter to print the information for. **/ -static -void __init adapter_print_config(struct AdapterCtlBlk *acb) +static void __init adapter_print_config(struct AdapterCtlBlk *acb) { u8 bval; bval = DC395x_read8(acb, TRM_S1040_GEN_STATUS); - dprintkl(KERN_INFO, "%s Connectors: ", - ((bval & WIDESCSI) ? "(Wide)" : "")); + dprintkl(KERN_INFO, "%sConnectors: ", + ((bval & WIDESCSI) ? "(Wide) " : "")); if (!(bval & CON5068)) printk("ext%s ", !(bval & EXT68HIGH) ? "68" : "50"); if (!(bval & CON68)) @@ -5337,8 +4341,7 @@ * * @acb: The adapter to initialize. **/ -static -void __init adapter_init_params(struct AdapterCtlBlk *acb) +static void __init adapter_init_params(struct AdapterCtlBlk *acb) { struct NvRamType *eeprom = &acb->eeprom; int i; @@ -5400,8 +4403,7 @@ * * @host: The scsi host instance to fill in the values for. **/ -static -void __init adapter_init_scsi_host(struct Scsi_Host *host) +static void __init adapter_init_scsi_host(struct Scsi_Host *host) { struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)host->hostdata; struct NvRamType *eeprom = &acb->eeprom; @@ -5495,8 +4497,8 @@ * Returns 0 if the initialization succeeds, any other value on * failure. **/ -static -int __init adapter_init(struct AdapterCtlBlk *acb, u32 io_port, u32 io_port_len, u8 irq) +static int __init adapter_init(struct AdapterCtlBlk *acb, u32 io_port, + u32 io_port_len, u8 irq) { if (!request_region(io_port, io_port_len, DC395X_NAME)) { dprintkl(KERN_ERR, "Failed to reserve IO region 0x%x\n", io_port); @@ -5528,19 +4530,15 @@ dprintkl(KERN_DEBUG, "Memory allocation for SG tables failed\n"); goto failed; } - if (alloc_tracebufs(acb)) { - dprintkl(KERN_DEBUG, "Memory allocation for trace buffers failed\n"); - goto failed; - } adapter_init_scsi_host(acb->scsi_host); adapter_init_chip(acb); set_basic_config(acb); - dprintkdbg(DBG_0, "adapter_init: acb=%p, pdcb_map=%p " - "psrb_array=%p ACB size=%04x, DCB size=%04x " - "SRB size=%04x\n", - acb, acb->dcb_map, acb->srb_array, sizeof(struct AdapterCtlBlk), - sizeof(struct DeviceCtlBlk), sizeof(struct ScsiReqBlk)); + dprintkdbg(DBG_0, + "adapter_init: acb=%p, pdcb_map=%p psrb_array=%p " + "size{acb=0x%04x dcb=0x%04x srb=0x%04x}\n", + acb, acb->dcb_map, acb->srb_array, sizeof(struct AdapterCtlBlk), + sizeof(struct DeviceCtlBlk), sizeof(struct ScsiReqBlk)); return 0; failed: @@ -5549,7 +4547,6 @@ if (acb->io_port_base) release_region(acb->io_port_base, acb->io_port_len); adapter_sg_tables_free(acb); - free_tracebufs(acb); return 1; } @@ -5562,8 +4559,7 @@ * * @acb: The adapter which we are to shutdown. **/ -static -void adapter_uninit_chip(struct AdapterCtlBlk *acb) +static void adapter_uninit_chip(struct AdapterCtlBlk *acb) { /* disable interrupts */ DC395x_write8(acb, TRM_S1040_DMA_INTEN, 0); @@ -5586,8 +4582,7 @@ * * @acb: The adapter which we are to un-initialize. **/ -static -void adapter_uninit(struct AdapterCtlBlk *acb) +static void adapter_uninit(struct AdapterCtlBlk *acb) { unsigned long flags; DC395x_LOCK_IO(acb->scsi_host, flags); @@ -5608,31 +4603,9 @@ release_region(acb->io_port_base, acb->io_port_len); adapter_sg_tables_free(acb); - free_tracebufs(acb); } -/* - ****************************************************************** - * Function: dc395x_proc_info(char* buffer, char **start, - * off_t offset, int length, int hostno, int inout) - * Purpose: return SCSI Adapter/Device Info - * Input: - * buffer: Pointer to a buffer where to write info - * start : - * offset: - * hostno: Host adapter index - * inout : Read (=0) or set(!=0) info - * Output: - * buffer: contains info length - * - * return value: length of info in buffer - * - ****************************************************************** - */ - -/* KG: dc395x_proc_info taken from driver aha152x.c */ - #undef SPRINTF #define SPRINTF(args...) pos += sprintf(pos, args) @@ -5641,9 +4614,8 @@ if (YN) SPRINTF(" Yes ");\ else SPRINTF(" No ") -static -int dc395x_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, - int inout) +static int dc395x_proc_info(struct Scsi_Host *host, char *buffer, + char **start, off_t offset, int length, int inout) { struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)host->hostdata; int spd, spd1; @@ -5741,16 +4713,12 @@ dcb->target_id, dcb->target_lun, list_size(&dcb->srb_going_list)); list_for_each_entry(srb, &dcb->srb_going_list, list) -#if debug_enabled(DBG_TRACE|DBG_TRACEALL) - SPRINTF("\n %s", srb->debugtrace); -#else SPRINTF(" %li", srb->cmd->pid); -#endif if (!list_empty(&dcb->srb_waiting_list) || !list_empty(&dcb->srb_going_list)) SPRINTF("\n"); } - if (debug_enabled(DBG_DCB)) { + if (debug_enabled(DBG_1)) { SPRINTF("DCB list for ACB %p:\n", acb); list_for_each_entry(dcb, &acb->dcb_list, list) { SPRINTF("%p -> ", dcb); @@ -5770,11 +4738,6 @@ } - - -/* - * SCSI host template - */ static Scsi_Host_Template dc395x_driver_template = { .module = THIS_MODULE, .proc_name = DC395X_NAME, @@ -5799,8 +4762,7 @@ * banner_display - Display banner on first instance of driver * initialized. **/ -static -void banner_display(void) +static void banner_display(void) { static int banner_done = 0; if (!banner_done) @@ -5824,9 +4786,8 @@ * * Returns 0 on success, or an error code (-ve) on failure. **/ -static -int __devinit dc395x_init_one(struct pci_dev *dev, - const struct pci_device_id *id) +static int __devinit dc395x_init_one(struct pci_dev *dev, + const struct pci_device_id *id) { struct Scsi_Host *scsi_host; struct AdapterCtlBlk *acb; @@ -5859,7 +4820,7 @@ /* initialise the adapter and everything we need */ if (adapter_init(acb, io_port_base, io_port_len, irq)) { - dprintkl(KERN_INFO, "DC395x_initAdapter initial ERROR\n"); + dprintkl(KERN_INFO, "adapter init failed\n"); scsi_host_put(scsi_host); return -ENODEV; } @@ -5870,7 +4831,7 @@ if (scsi_add_host(scsi_host, &dev->dev)) { dprintkl(KERN_ERR, "scsi_add_host failed\n"); adapter_uninit(acb); - scsi_host_put(scsi_host); + scsi_host_put(scsi_host); return -ENODEV; } pci_set_drvdata(dev, scsi_host); @@ -5891,7 +4852,7 @@ struct Scsi_Host *scsi_host = pci_get_drvdata(dev); struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)(scsi_host->hostdata); - dprintkdbg(DBG_0, "Removing instance\n"); + dprintkdbg(DBG_0, "dc395x_remove_one: acb=%p\n", acb); scsi_remove_host(scsi_host); adapter_uninit(acb); @@ -5900,10 +4861,6 @@ } -/* - * Table which identifies the PCI devices which - * are handled by this device driver. - */ static struct pci_device_id dc395x_pci_table[] = { { .vendor = PCI_VENDOR_ID_TEKRAM, @@ -5916,10 +4873,6 @@ MODULE_DEVICE_TABLE(pci, dc395x_pci_table); -/* - * PCI driver operations. - * Tells the PCI sub system what can be done with the card. - */ static struct pci_driver dc395x_driver = { .name = DC395X_NAME, .id_table = dc395x_pci_table, @@ -5933,8 +4886,7 @@ * * Used by both module and built-in driver to initialise this driver. **/ -static -int __init dc395x_module_init(void) +static int __init dc395x_module_init(void) { return pci_module_init(&dc395x_driver); } @@ -5943,8 +4895,7 @@ /** * dc395x_module_exit - Module cleanup function. **/ -static -void __exit dc395x_module_exit(void) +static void __exit dc395x_module_exit(void) { pci_unregister_driver(&dc395x_driver); } diff -Nru a/drivers/scsi/dc395x.h b/drivers/scsi/dc395x.h --- a/drivers/scsi/dc395x.h Sun Mar 14 14:20:08 2004 +++ b/drivers/scsi/dc395x.h Sun Mar 14 14:20:08 2004 @@ -7,18 +7,8 @@ /* (SCSI chip set used Tekram ASIC TRM-S1040) */ /* */ /************************************************************************/ - #ifndef DC395x_H #define DC395x_H - -/************************************************************************/ -/* */ -/* Name, Banner and Version */ -/* */ -/************************************************************************/ -#define DC395X_NAME "dc395x" -#define DC395X_BANNER "Tekram DC395(U/UW/F), DC315(U) - ASIC TRM-S1040" -#define DC395X_VERSION "v2.04, 2003/05/19" /************************************************************************/ /* */ diff -Nru a/drivers/scsi/eata.c b/drivers/scsi/eata.c --- a/drivers/scsi/eata.c Sun Mar 14 14:20:08 2004 +++ b/drivers/scsi/eata.c Sun Mar 14 14:20:08 2004 @@ -1598,17 +1598,17 @@ pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction); if (DEV2H(cpp->sense_addr)) - pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->sense_addr), + pci_dma_sync_single_for_cpu(HD(j)->pdev, DEV2H(cpp->sense_addr), DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); if (SCpnt->use_sg) - pci_dma_sync_sg(HD(j)->pdev, SCpnt->request_buffer, + pci_dma_sync_sg_for_cpu(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir); if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL; if (DEV2H(cpp->data_address)) - pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address), + pci_dma_sync_single_for_cpu(HD(j)->pdev, DEV2H(cpp->data_address), DEV2H(cpp->data_len), pci_dir); } diff -Nru a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c --- a/drivers/scsi/hosts.c Sun Mar 14 14:20:06 2004 +++ b/drivers/scsi/hosts.c Sun Mar 14 14:20:06 2004 @@ -32,6 +32,7 @@ #include #include +#include #include "scsi.h" #include "scsi_priv.h" @@ -221,6 +222,11 @@ shost->max_channel = 0; shost->max_id = 8; shost->max_lun = 8; + + /* Give each shost a default transportt if the driver + * doesn't yet support Transport Attributes */ + if (!shost->transportt) + shost->transportt = &blank_transport_template; /* * All drivers right now should be able to handle 12 byte diff -Nru a/drivers/scsi/ini9100u.c b/drivers/scsi/ini9100u.c --- a/drivers/scsi/ini9100u.c Sun Mar 14 14:20:06 2004 +++ b/drivers/scsi/ini9100u.c Sun Mar 14 14:20:06 2004 @@ -180,15 +180,6 @@ static char *setup_str = (char *) NULL; -static irqreturn_t i91u_intr0(int irq, void *dev_id, struct pt_regs *); -static irqreturn_t i91u_intr1(int irq, void *dev_id, struct pt_regs *); -static irqreturn_t i91u_intr2(int irq, void *dev_id, struct pt_regs *); -static irqreturn_t i91u_intr3(int irq, void *dev_id, struct pt_regs *); -static irqreturn_t i91u_intr4(int irq, void *dev_id, struct pt_regs *); -static irqreturn_t i91u_intr5(int irq, void *dev_id, struct pt_regs *); -static irqreturn_t i91u_intr6(int irq, void *dev_id, struct pt_regs *); -static irqreturn_t i91u_intr7(int irq, void *dev_id, struct pt_regs *); - static void i91u_panic(char *msg); static void i91uSCBPost(BYTE * pHcb, BYTE * pScb); @@ -278,7 +269,7 @@ unsigned long flags; spin_lock_irqsave(dev->host_lock, flags); - tul_isr((HCS *)hreg->base); + tul_isr((HCS *)dev->base); spin_unlock_irqrestore(dev->host_lock, flags); return IRQ_HANDLED; } diff -Nru a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c --- a/drivers/scsi/libata-core.c Sun Mar 14 14:20:05 2004 +++ b/drivers/scsi/libata-core.c Sun Mar 14 14:20:05 2004 @@ -141,7 +141,7 @@ } if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { - outb(tf->hob_feature, ioaddr->error_addr); + outb(tf->hob_feature, ioaddr->feature_addr); outb(tf->hob_nsect, ioaddr->nsect_addr); outb(tf->hob_lbal, ioaddr->lbal_addr); outb(tf->hob_lbam, ioaddr->lbam_addr); @@ -155,7 +155,7 @@ } if (is_addr) { - outb(tf->feature, ioaddr->error_addr); + outb(tf->feature, ioaddr->feature_addr); outb(tf->nsect, ioaddr->nsect_addr); outb(tf->lbal, ioaddr->lbal_addr); outb(tf->lbam, ioaddr->lbam_addr); @@ -199,7 +199,7 @@ } if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { - writeb(tf->hob_feature, (void *) ioaddr->error_addr); + writeb(tf->hob_feature, (void *) ioaddr->feature_addr); writeb(tf->hob_nsect, (void *) ioaddr->nsect_addr); writeb(tf->hob_lbal, (void *) ioaddr->lbal_addr); writeb(tf->hob_lbam, (void *) ioaddr->lbam_addr); @@ -213,7 +213,7 @@ } if (is_addr) { - writeb(tf->feature, (void *) ioaddr->error_addr); + writeb(tf->feature, (void *) ioaddr->feature_addr); writeb(tf->nsect, (void *) ioaddr->nsect_addr); writeb(tf->lbal, (void *) ioaddr->lbal_addr); writeb(tf->lbam, (void *) ioaddr->lbam_addr); @@ -250,7 +250,7 @@ { DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command); - outb(tf->command, ap->ioaddr.cmdstat_addr); + outb(tf->command, ap->ioaddr.command_addr); ata_pause(ap); } @@ -271,7 +271,7 @@ { DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command); - writeb(tf->command, (void *) ap->ioaddr.cmdstat_addr); + writeb(tf->command, (void *) ap->ioaddr.command_addr); ata_pause(ap); } @@ -417,7 +417,7 @@ */ u8 ata_check_status_pio(struct ata_port *ap) { - return inb(ap->ioaddr.cmdstat_addr); + return inb(ap->ioaddr.status_addr); } /** @@ -433,7 +433,7 @@ */ u8 ata_check_status_mmio(struct ata_port *ap) { - return readb((void *) ap->ioaddr.cmdstat_addr); + return readb((void *) ap->ioaddr.status_addr); } static const char * udma_str[] = { @@ -1346,12 +1346,6 @@ DPRINTK("ENTER, host %u, port %u\n", ap->id, ap->port_no); - /* set up device control */ - if (ap->flags & ATA_FLAG_MMIO) - writeb(ap->ctl, ioaddr->ctl_addr); - else - outb(ap->ctl, ioaddr->ctl_addr); - /* determine if device 0/1 are present */ if (ap->flags & ATA_FLAG_SATA_RESET) dev0 = 1; @@ -1372,8 +1366,14 @@ /* issue bus reset */ if (ap->flags & ATA_FLAG_SRST) rc = ata_bus_softreset(ap, devmask); - else if ((ap->flags & ATA_FLAG_SATA_RESET) == 0) + else if ((ap->flags & ATA_FLAG_SATA_RESET) == 0) { + /* set up device control */ + if (ap->flags & ATA_FLAG_MMIO) + writeb(ap->ctl, ioaddr->ctl_addr); + else + outb(ap->ctl, ioaddr->ctl_addr); rc = ata_bus_edd(ap); + } if (rc) goto err_out; @@ -1399,6 +1399,14 @@ (ap->device[1].class == ATA_DEV_NONE)) goto err_out; + if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) { + /* set up device control for ATA_FLAG_SATA_RESET */ + if (ap->flags & ATA_FLAG_MMIO) + writeb(ap->ctl, ioaddr->ctl_addr); + else + outb(ap->ctl, ioaddr->ctl_addr); + } + DPRINTK("EXIT\n"); return; @@ -1445,7 +1453,8 @@ if (ata_dev_present(&ap->device[i])) { ap->device[i].pio_mode = (pio == 3) ? XFER_PIO_3 : XFER_PIO_4; - ap->ops->set_piomode(ap, &ap->device[i], pio); + if (ap->ops->set_piomode) + ap->ops->set_piomode(ap, &ap->device[i], pio); } return; @@ -1509,7 +1518,9 @@ for (i = 0; i < ATA_MAX_DEVICES; i++) if (ata_dev_present(&ap->device[i])) { ap->device[i].udma_mode = udma_mode; - ap->ops->set_udmamode(ap, &ap->device[i], udma_mode); + if (ap->ops->set_udmamode) + ap->ops->set_udmamode(ap, &ap->device[i], + udma_mode); } return; @@ -2369,8 +2380,8 @@ * One if interrupt was handled, zero if not (shared irq). */ -static inline unsigned int ata_host_intr (struct ata_port *ap, - struct ata_queued_cmd *qc) +inline unsigned int ata_host_intr (struct ata_port *ap, + struct ata_queued_cmd *qc) { u8 status, host_stat; unsigned int handled = 0; @@ -2728,7 +2739,7 @@ if (!ap->prd) return -ENOMEM; - DPRINTK("prd alloc, virt %p, dma %x\n", ap->prd, ap->prd_dma); + DPRINTK("prd alloc, virt %p, dma %llx\n", ap->prd, (unsigned long long) ap->prd_dma); return 0; } @@ -3026,12 +3037,14 @@ { ioaddr->data_addr = ioaddr->cmd_addr + ATA_REG_DATA; ioaddr->error_addr = ioaddr->cmd_addr + ATA_REG_ERR; + ioaddr->feature_addr = ioaddr->cmd_addr + ATA_REG_FEATURE; ioaddr->nsect_addr = ioaddr->cmd_addr + ATA_REG_NSECT; ioaddr->lbal_addr = ioaddr->cmd_addr + ATA_REG_LBAL; ioaddr->lbam_addr = ioaddr->cmd_addr + ATA_REG_LBAM; ioaddr->lbah_addr = ioaddr->cmd_addr + ATA_REG_LBAH; ioaddr->device_addr = ioaddr->cmd_addr + ATA_REG_DEVICE; - ioaddr->cmdstat_addr = ioaddr->cmd_addr + ATA_REG_CMD; + ioaddr->status_addr = ioaddr->cmd_addr + ATA_REG_STATUS; + ioaddr->command_addr = ioaddr->cmd_addr + ATA_REG_CMD; } /** @@ -3153,12 +3166,14 @@ if (legacy_mode) { probe_ent->port[0].cmd_addr = 0x1f0; + probe_ent->port[0].altstatus_addr = probe_ent->port[0].ctl_addr = 0x3f6; probe_ent->n_ports = 1; probe_ent->irq = 14; ata_std_ports(&probe_ent->port[0]); probe_ent2->port[0].cmd_addr = 0x170; + probe_ent2->port[0].altstatus_addr = probe_ent2->port[0].ctl_addr = 0x376; probe_ent2->port[0].bmdma_addr = pci_resource_start(pdev, 4)+8; probe_ent2->n_ports = 1; @@ -3173,11 +3188,13 @@ } else { probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); ata_std_ports(&probe_ent->port[0]); + probe_ent->port[0].altstatus_addr = probe_ent->port[0].ctl_addr = pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2); ata_std_ports(&probe_ent->port[1]); + probe_ent->port[1].altstatus_addr = probe_ent->port[1].ctl_addr = pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8; @@ -3367,4 +3384,4 @@ EXPORT_SYMBOL_GPL(ata_scsi_error); EXPORT_SYMBOL_GPL(ata_scsi_slave_config); EXPORT_SYMBOL_GPL(ata_scsi_release); - +EXPORT_SYMBOL_GPL(ata_host_intr); diff -Nru a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c --- a/drivers/scsi/megaraid.c Sun Mar 14 14:20:05 2004 +++ b/drivers/scsi/megaraid.c Sun Mar 14 14:20:05 2004 @@ -261,10 +261,6 @@ "megaraid: Product_info cmd failed with error: %d\n", retval); - pci_dma_sync_single(adapter->dev, prod_info_dma_handle, - sizeof(mega_product_info), - PCI_DMA_FROMDEVICE); - pci_unmap_single(adapter->dev, prod_info_dma_handle, sizeof(mega_product_info), PCI_DMA_FROMDEVICE); } @@ -1651,26 +1647,11 @@ case MEGA_BULK_DATA: pci_unmap_page(adapter->dev, scb->dma_h_bulkdata, scb->cmd->request_bufflen, scb->dma_direction); - - if( scb->dma_direction == PCI_DMA_FROMDEVICE ) { - pci_dma_sync_single(adapter->dev, - scb->dma_h_bulkdata, - scb->cmd->request_bufflen, - PCI_DMA_FROMDEVICE); - } - break; case MEGA_SGLIST: pci_unmap_sg(adapter->dev, scb->cmd->request_buffer, scb->cmd->use_sg, scb->dma_direction); - - if( scb->dma_direction == PCI_DMA_FROMDEVICE ) { - pci_dma_sync_sg(adapter->dev, - scb->cmd->request_buffer, - scb->cmd->use_sg, PCI_DMA_FROMDEVICE); - } - break; default: @@ -1758,14 +1739,6 @@ *buf = (u32)scb->dma_h_bulkdata; *len = (u32)cmd->request_bufflen; } - - if( scb->dma_direction == PCI_DMA_TODEVICE ) { - pci_dma_sync_single(adapter->dev, - scb->dma_h_bulkdata, - cmd->request_bufflen, - PCI_DMA_TODEVICE); - } - return 0; } @@ -1804,11 +1777,6 @@ */ *len = (u32)cmd->request_bufflen; - if( scb->dma_direction == PCI_DMA_TODEVICE ) { - pci_dma_sync_sg(adapter->dev, sgl, cmd->use_sg, - PCI_DMA_TODEVICE); - } - /* Return count of SG requests */ return sgcnt; } @@ -5118,10 +5086,6 @@ if (max_mbox_busy_wait > MBOX_BUSY_WAIT) max_mbox_busy_wait = MBOX_BUSY_WAIT; - error = pci_module_init(&megaraid_pci_driver); - if (error) - return error; - #ifdef CONFIG_PROC_FS mega_proc_dir_entry = proc_mkdir("megaraid", &proc_root); if (!mega_proc_dir_entry) { @@ -5129,6 +5093,13 @@ "megaraid: failed to create megaraid root\n"); } #endif + error = pci_module_init(&megaraid_pci_driver); + if (error) { +#ifdef CONFIG_PROC_FS + remove_proc_entry("megaraid", &proc_root); +#endif + return error; + } /* * Register the driver as a character device, for applications diff -Nru a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c --- a/drivers/scsi/ncr53c8xx.c Sun Mar 14 14:20:06 2004 +++ b/drivers/scsi/ncr53c8xx.c Sun Mar 14 14:20:06 2004 @@ -5140,9 +5140,10 @@ */ if (cmd->cmnd[0] == 0x12 && !(cmd->cmnd[1] & 0x3) && cmd->cmnd[4] >= 7 && !cmd->use_sg) { - sync_scsi_data(np, cmd); /* SYNC the data */ + sync_scsi_data_for_cpu(np, cmd); /* SYNC the data */ ncr_setup_lcb (np, cmd->device->id, cmd->device->lun, (char *) cmd->request_buffer); + sync_scsi_data_for_device(np, cmd); /* SYNC the data */ } tp->bytes += cp->data_len; diff -Nru a/drivers/scsi/oktagon_esp.c b/drivers/scsi/oktagon_esp.c --- a/drivers/scsi/oktagon_esp.c Sun Mar 14 14:20:06 2004 +++ b/drivers/scsi/oktagon_esp.c Sun Mar 14 14:20:06 2004 @@ -12,7 +12,6 @@ #define USE_BOTTOM_HALF #endif -#define __KERNEL_SYSCALLS__ #include #include @@ -42,8 +41,6 @@ #include #include #endif - -#include /* The controller registers can be found in the Z2 config area at these * offsets: diff -Nru a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c --- a/drivers/scsi/pcmcia/qlogic_stub.c Sun Mar 14 14:20:07 2004 +++ b/drivers/scsi/pcmcia/qlogic_stub.c Sun Mar 14 14:20:07 2004 @@ -43,9 +43,11 @@ #include #include #include +#include #include "scsi.h" #include "hosts.h" +#include "../qlogicfas.h" #include #include @@ -57,8 +59,10 @@ extern Scsi_Host_Template qlogicfas_driver_template; extern void qlogicfas_preset(int port, int irq); -extern struct Scsi_Host *__qlogicfas_detect(Scsi_Host_Template *); extern int qlogicfas_bus_reset(Scsi_Cmnd *); +extern irqreturn_t do_ql_ihandl(int irq, void *dev_id, struct pt_regs *regs); + +static char *qlogic_name = "qlogic_cs"; #ifdef PCMCIA_DEBUG static int pc_debug = PCMCIA_DEBUG; @@ -100,6 +104,71 @@ static dev_info_t dev_info = "qlogic_cs"; +static struct Scsi_Host *qlogic_detect(Scsi_Host_Template *host, + dev_link_t *link, int qbase, int qlirq) +{ + int qltyp; /* type of chip */ + int qinitid; + struct Scsi_Host *shost; /* registered host structure */ + qlogicfas_priv_t priv; + + qltyp = inb(qbase + 0xe) & 0xf8; + qinitid = host->this_id; + if (qinitid < 0) + qinitid = 7; /* if no ID, use 7 */ + outb(1, qbase + 8); /* set for PIO pseudo DMA */ + REG0; + outb(0x40 | qlcfg8 | qinitid, qbase + 8); /* (ini) bus id, disable scsi rst */ + outb(qlcfg5, qbase + 5); /* select timer */ + outb(qlcfg9, qbase + 9); /* prescaler */ + +#if QL_RESET_AT_START + outb(3, qbase + 3); + REG1; + /* FIXME: timeout */ + while (inb(qbase + 0xf) & 4) + cpu_relax(); + REG0; +#endif + + host->name = qlogic_name; + shost = scsi_host_alloc(host, sizeof(struct qlogicfas_priv)); + if (!shost) + goto err; + shost->io_port = qbase; + shost->n_io_port = 16; + shost->dma_channel = -1; + if (qlirq != -1) + shost->irq = qlirq; + + priv = (qlogicfas_priv_t)&(shost->hostdata[0]); + priv->qlirq = qlirq; + priv->qbase = qbase; + priv->qinitid = qinitid; + + if (request_irq(qlirq, do_ql_ihandl, 0, qlogic_name, shost)) + goto free_scsi_host; + + sprintf(priv->qinfo, + "Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d", + qltyp, qbase, qlirq, QL_TURBO_PDMA); + + if (scsi_add_host(shost, NULL)) + goto free_interrupt; + + scsi_scan_host(shost); + + return shost; + +free_interrupt: + free_irq(qlirq, shost); + +free_scsi_host: + scsi_host_put(shost); + +err: + return NULL; +} static dev_link_t *qlogic_attach(void) { scsi_info_t *info; @@ -238,18 +307,19 @@ outb(0x04, link->io.BasePort1 + 0xd); } - /* A bad hack... */ - release_region(link->io.BasePort1, link->io.NumPorts1); + qlogicfas_driver_template.name = qlogic_name; + qlogicfas_driver_template.proc_name = qlogic_name; /* The KXL-810AN has a bigger IO port window */ if (link->io.NumPorts1 == 32) - qlogicfas_preset(link->io.BasePort1 + 16, link->irq.AssignedIRQ); + host = qlogic_detect(&qlogicfas_driver_template, link, + link->io.BasePort1 + 16, link->irq.AssignedIRQ); else - qlogicfas_preset(link->io.BasePort1, link->irq.AssignedIRQ); - - host = __qlogicfas_detect(&qlogicfas_driver_template); + host = qlogic_detect(&qlogicfas_driver_template, link, + link->io.BasePort1, link->irq.AssignedIRQ); + if (!host) { - printk(KERN_INFO "qlogic_cs: no SCSI devices found\n"); + printk(KERN_INFO "%s: no SCSI devices found\n", qlogic_name); goto out; } @@ -257,16 +327,17 @@ link->dev = &info->node; info->host = host; - scsi_add_host(host, NULL); /* XXX handle failure */ - scsi_scan_host(host); - out: link->state &= ~DEV_CONFIG_PENDING; return; cs_failed: cs_error(link->handle, last_fn, last_ret); - qlogic_release(link); + link->dev = NULL; + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); + link->state &= ~DEV_CONFIG; return; } /* qlogic_config */ @@ -282,11 +353,13 @@ scsi_remove_host(info->host); link->dev = NULL; + free_irq(link->irq.AssignedIRQ, info->host); + pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); - scsi_unregister(info->host); + scsi_host_put(info->host); link->state &= ~DEV_CONFIG; } @@ -340,7 +413,7 @@ static struct pcmcia_driver qlogic_cs_driver = { .owner = THIS_MODULE, .drv = { - .name = "qlogic_cs", + .name = "qlogic_cs", }, .attach = qlogic_attach, .detach = qlogic_detach, @@ -360,5 +433,8 @@ qlogic_detach(dev_list); } +MODULE_AUTHOR("Tom Zerucha, Michael Griffith"); +MODULE_DESCRIPTION("Driver for the PCMCIA Qlogic FAS SCSI controllers"); +MODULE_LICENSE("GPL"); module_init(init_qlogic_cs); module_exit(exit_qlogic_cs); diff -Nru a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c --- a/drivers/scsi/qlogicfas.c Sun Mar 14 14:20:08 2004 +++ b/drivers/scsi/qlogicfas.c Sun Mar 14 14:20:08 2004 @@ -27,7 +27,6 @@ SCSI driver cleanup and audit. This driver still needs work on the following - Non terminating hardware waits - - Support multiple cards at a time - Some layering violations with its pcmcia stub Redistributable under terms of the GNU General Public License @@ -39,92 +38,6 @@ are deemed to be part of the source code. */ -/*----------------------------------------------------------------*/ -/* Configuration */ - -/* Set the following to 2 to use normal interrupt (active high/totempole- - tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open - drain */ - -#define QL_INT_ACTIVE_HIGH 2 - -/* Set the following to 1 to enable the use of interrupts. Note that 0 tends - to be more stable, but slower (or ties up the system more) */ - -#define QL_USE_IRQ 1 - -/* Set the following to max out the speed of the PIO PseudoDMA transfers, - again, 0 tends to be slower, but more stable. */ - -#define QL_TURBO_PDMA 1 - -/* This should be 1 to enable parity detection */ - -#define QL_ENABLE_PARITY 1 - -/* This will reset all devices when the driver is initialized (during bootup). - The other linux drivers don't do this, but the DOS drivers do, and after - using DOS or some kind of crash or lockup this will bring things back - without requiring a cold boot. It does take some time to recover from a - reset, so it is slower, and I have seen timeouts so that devices weren't - recognized when this was set. */ - -#define QL_RESET_AT_START 0 - -/* crystal frequency in megahertz (for offset 5 and 9) - Please set this for your card. Most Qlogic cards are 40 Mhz. The - Control Concepts ISA (not VLB) is 24 Mhz */ - -#define XTALFREQ 40 - -/**********/ -/* DANGER! modify these at your own risk */ -/* SLOWCABLE can usually be reset to zero if you have a clean setup and - proper termination. The rest are for synchronous transfers and other - advanced features if your device can transfer faster than 5Mb/sec. - If you are really curious, email me for a quick howto until I have - something official */ -/**********/ - -/*****/ -/* config register 1 (offset 8) options */ -/* This needs to be set to 1 if your cabling is long or noisy */ -#define SLOWCABLE 1 - -/*****/ -/* offset 0xc */ -/* This will set fast (10Mhz) synchronous timing when set to 1 - For this to have an effect, FASTCLK must also be 1 */ -#define FASTSCSI 0 - -/* This when set to 1 will set a faster sync transfer rate */ -#define FASTCLK 0 /*(XTALFREQ>25?1:0)*/ - -/*****/ -/* offset 6 */ -/* This is the sync transfer divisor, XTALFREQ/X will be the maximum - achievable data rate (assuming the rest of the system is capable - and set properly) */ -#define SYNCXFRPD 5 /*(XTALFREQ/5)*/ - -/*****/ -/* offset 7 */ -/* This is the count of how many synchronous transfers can take place - i.e. how many reqs can occur before an ack is given. - The maximum value for this is 15, the upper bits can modify - REQ/ACK assertion and deassertion during synchronous transfers - If this is 0, the bus will only transfer asynchronously */ -#define SYNCOFFST 0 -/* for the curious, bits 7&6 control the deassertion delay in 1/2 cycles - of the 40Mhz clock. If FASTCLK is 1, specifying 01 (1/2) will - cause the deassertion to be early by 1/2 clock. Bits 5&4 control - the assertion delay, also in 1/2 clocks (FASTCLK is ignored here). */ - -/*----------------------------------------------------------------*/ -#ifdef PCMCIA -#undef QL_INT_ACTIVE_HIGH -#define QL_INT_ACTIVE_HIGH 0 -#endif #include #include /* to get disk capacity */ @@ -144,42 +57,21 @@ #include "scsi.h" #include "hosts.h" +#include "qlogicfas.h" /*----------------------------------------------------------------*/ -/* driver state info, local to driver */ -static int qbase; /* Port */ -static int qinitid; /* initiator ID */ -static int qabort; /* Flag to cause an abort */ -static int qlirq = -1; /* IRQ being used */ -static char qinfo[80]; /* description */ -static Scsi_Cmnd *qlcmd; /* current command being processed */ - -static int qlcfg5 = (XTALFREQ << 5); /* 15625/512 */ -static int qlcfg6 = SYNCXFRPD; -static int qlcfg7 = SYNCOFFST; -static int qlcfg8 = (SLOWCABLE << 7) | (QL_ENABLE_PARITY << 4); -static int qlcfg9 = ((XTALFREQ + 4) / 5); -static int qlcfgc = (FASTCLK << 3) | (FASTSCSI << 4); - -int qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)); +int qlcfg5 = (XTALFREQ << 5); /* 15625/512 */ +int qlcfg6 = SYNCXFRPD; +int qlcfg7 = SYNCOFFST; +int qlcfg8 = (SLOWCABLE << 7) | (QL_ENABLE_PARITY << 4); +int qlcfg9 = ((XTALFREQ + 4) / 5); +int qlcfgc = (FASTCLK << 3) | (FASTSCSI << 4); -/*----------------------------------------------------------------*/ -/* The qlogic card uses two register maps - These macros select which one */ -#define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd )) -#define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd )) +static char qlogicfas_name[] = "qlogicfas"; -/* following is watchdog timeout in microseconds */ -#define WATCHDOG 5000000 +int qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)); /*----------------------------------------------------------------*/ -/* the following will set the monitor border color (useful to find - where something crashed or gets stuck at and as a simple profiler) */ - -#if 0 -#define rtrc(i) {inb(0x3da);outb(0x31,0x3c0);outb((i),0x3c0);} -#else -#define rtrc(i) {} -#endif /*----------------------------------------------------------------*/ /* local functions */ @@ -187,9 +79,10 @@ /* error recovery - reset everything */ -static void ql_zap(void) +static void ql_zap(qlogicfas_priv_t priv) { int x; + int qbase = priv->qbase; x = inb(qbase + 0xd); REG0; @@ -203,9 +96,10 @@ * Do a pseudo-dma tranfer */ -static int ql_pdma(int phase, char *request, int reqlen) +static int ql_pdma(qlogicfas_priv_t priv, int phase, char *request, int reqlen) { int j; + int qbase = priv->qbase; j = 0; if (phase & 1) { /* in */ #if QL_TURBO_PDMA @@ -287,23 +181,25 @@ * Wait for interrupt flag (polled - not real hardware interrupt) */ -static int ql_wai(void) +static int ql_wai(qlogicfas_priv_t priv) { int k; + int qbase = priv->qbase; unsigned long i; k = 0; i = jiffies + WATCHDOG; - while (time_before(jiffies, i) && !qabort && !((k = inb(qbase + 4)) & 0xe0)) { + while (time_before(jiffies, i) && !priv->qabort && + !((k = inb(qbase + 4)) & 0xe0)) { barrier(); cpu_relax(); } if (time_after_eq(jiffies, i)) return (DID_TIME_OUT); - if (qabort) - return (qabort == 1 ? DID_ABORT : DID_RESET); + if (priv->qabort) + return (priv->qabort == 1 ? DID_ABORT : DID_RESET); if (k & 0x60) - ql_zap(); + ql_zap(priv); if (k & 0x20) return (DID_PARITY); if (k & 0x40) @@ -318,9 +214,11 @@ static void ql_icmd(Scsi_Cmnd * cmd) { + qlogicfas_priv_t priv = (qlogicfas_priv_t)&(cmd->device->host->hostdata[0]); + int qbase = priv->qbase; unsigned int i; - qabort = 0; + priv->qabort = 0; REG0; /* clearing of interrupts and the fifo is needed */ @@ -341,7 +239,7 @@ /* configurables */ outb(qlcfgc, qbase + 0xc); /* config: no reset interrupt, (initiator) bus id */ - outb(0x40 | qlcfg8 | qinitid, qbase + 8); + outb(0x40 | qlcfg8 | priv->qinitid, qbase + 8); outb(qlcfg7, qbase + 7); outb(qlcfg6, qbase + 6); /**/ outb(qlcfg5, qbase + 5); /* select timer */ @@ -352,7 +250,7 @@ for (i = 0; i < cmd->cmd_len; i++) outb(cmd->cmnd[i], qbase + 2); - qlcmd = cmd; + priv->qlcmd = cmd; outb(0x41, qbase + 3); /* select and send command */ } @@ -372,6 +270,8 @@ struct scatterlist *sglist; /* scatter-gather list pointer */ unsigned int sgcount; /* sg counter */ char *buf; + qlogicfas_priv_t priv = (qlogicfas_priv_t)&(cmd->device->host->hostdata[0]); + int qbase = priv->qbase; rtrc(1) j = inb(qbase + 6); @@ -382,7 +282,7 @@ i |= inb(qbase + 5); /* the 0x10 bit can be set after the 0x08 */ if (i != 0x18) { printk(KERN_ERR "Ql:Bad Interrupt status:%02x\n", i); - ql_zap(); + ql_zap(priv); return (DID_BAD_INTR << 16); } j &= 7; /* j = inb( qbase + 7 ) >> 5; */ @@ -395,7 +295,7 @@ if (j != 3 && j != 4) { printk(KERN_ERR "Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n", j, i, inb(qbase + 7) & 0x1f); - ql_zap(); + ql_zap(priv); return (DID_ERROR << 16); } result = DID_OK; @@ -413,18 +313,19 @@ /* PIO pseudo DMA to buffer or sglist */ REG1; if (!cmd->use_sg) - ql_pdma(phase, cmd->request_buffer, + ql_pdma(priv, phase, cmd->request_buffer, cmd->request_bufflen); else { sgcount = cmd->use_sg; sglist = cmd->request_buffer; while (sgcount--) { - if (qabort) { + if (priv->qabort) { REG0; - return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16); + return ((priv->qabort == 1 ? + DID_ABORT : DID_RESET) << 16); } buf = page_address(sglist->page) + sglist->offset; - if (ql_pdma(phase, buf, sglist->length)) + if (ql_pdma(priv, phase, buf, sglist->length)) break; sglist++; } @@ -435,7 +336,7 @@ * Wait for irq (split into second state of irq handler * if this can take time) */ - if ((k = ql_wai())) + if ((k = ql_wai(priv))) return (k << 16); k = inb(qbase + 5); /* should be 0x10, bus service */ } @@ -446,11 +347,12 @@ k = jiffies + WATCHDOG; - while (time_before(jiffies, k) && !qabort && !(inb(qbase + 4) & 6)) + while (time_before(jiffies, k) && !priv->qabort && + !(inb(qbase + 4) & 6)) cpu_relax(); /* wait for status phase */ if (time_after_eq(jiffies, k)) { - ql_zap(); + ql_zap(priv); return (DID_TIME_OUT << 16); } @@ -458,11 +360,11 @@ while (inb(qbase + 5)) cpu_relax(); /* clear pending ints */ - if (qabort) - return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16); + if (priv->qabort) + return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16); outb(0x11, qbase + 3); /* get status and message */ - if ((k = ql_wai())) + if ((k = ql_wai(priv))) return (k << 16); i = inb(qbase + 5); /* get chip irq stat */ j = inb(qbase + 7) & 0x1f; /* and bytes rec'd */ @@ -479,7 +381,7 @@ } outb(0x12, qbase + 3); /* done, disconnect */ rtrc(1) - if ((k = ql_wai())) + if ((k = ql_wai(priv))) return (k << 16); /* @@ -487,21 +389,19 @@ */ i = inb(qbase + 5); /* should be bus service */ - while (!qabort && ((i & 0x20) != 0x20)) { + while (!priv->qabort && ((i & 0x20) != 0x20)) { barrier(); cpu_relax(); i |= inb(qbase + 5); } rtrc(0) - if (qabort) - return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16); + if (priv->qabort) + return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16); return (result << 16) | (message << 8) | (status & STATUS_MASK); } -#if QL_USE_IRQ - /* * Interrupt handler */ @@ -509,20 +409,23 @@ static void ql_ihandl(int irq, void *dev_id, struct pt_regs *regs) { Scsi_Cmnd *icmd; + struct Scsi_Host *host = (struct Scsi_Host *)dev_id; + qlogicfas_priv_t priv = (qlogicfas_priv_t)&(host->hostdata[0]); + int qbase = priv->qbase; REG0; if (!(inb(qbase + 4) & 0x80)) /* false alarm? */ return; - if (qlcmd == NULL) { /* no command to process? */ + if (priv->qlcmd == NULL) { /* no command to process? */ int i; i = 16; while (i-- && inb(qbase + 5)); /* maybe also ql_zap() */ return; } - icmd = qlcmd; + icmd = priv->qlcmd; icmd->result = ql_pcmd(icmd); - qlcmd = NULL; + priv->qlcmd = NULL; /* * If result is CHECK CONDITION done calls qcommand to request * sense @@ -530,7 +433,7 @@ (icmd->scsi_done) (icmd); } -static irqreturn_t do_ql_ihandl(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t do_ql_ihandl(int irq, void *dev_id, struct pt_regs *regs) { unsigned long flags; struct Scsi_Host *host = dev_id; @@ -541,17 +444,14 @@ return IRQ_HANDLED; } -#endif - -#if QL_USE_IRQ - /* * Queued command */ int qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) { - if (cmd->device->id == qinitid) { + qlogicfas_priv_t priv = (qlogicfas_priv_t)&(cmd->device->host->hostdata[0]); + if (cmd->device->id == priv->qinitid) { cmd->result = DID_BAD_TARGET << 16; done(cmd); return 0; @@ -559,44 +459,27 @@ cmd->scsi_done = done; /* wait for the last command's interrupt to finish */ - while (qlcmd != NULL) { + while (priv->qlcmd != NULL) { barrier(); cpu_relax(); } ql_icmd(cmd); return 0; } -#else -int qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) -{ - return 1; -} -#endif - -#ifdef PCMCIA - -/* - * Allow PCMCIA code to preset the port - * port should be 0 and irq to -1 respectively for autoprobing - */ - -void qlogicfas_preset(int port, int irq) -{ - qbase = port; - qlirq = irq; -} - -#endif +#ifndef PCMCIA /* * Look for qlogic card and init if found */ -struct Scsi_Host *__qlogicfas_detect(Scsi_Host_Template *host) +struct Scsi_Host *__qlogicfas_detect(Scsi_Host_Template *host, int qbase, + int qlirq) { int i, j; /* these are only used by IRQ detect */ int qltyp; /* type of chip */ + int qinitid; struct Scsi_Host *hreg; /* registered host structure */ + qlogicfas_priv_t priv; /* Qlogic Cards only exist at 0x230 or 0x330 (the chip itself * decodes the address - I check 230 first since MIDI cards are @@ -609,7 +492,7 @@ if (!qbase) { for (qbase = 0x230; qbase < 0x430; qbase += 0x100) { - if (!request_region(qbase, 0x10, "qlogicfas")) + if (!request_region(qbase, 0x10, qlogicfas_name)) continue; REG1; if (((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7) @@ -641,7 +524,6 @@ REG0; #endif -#if QL_USE_IRQ /* * IRQ probe - toggle pin and check request pending */ @@ -668,49 +550,98 @@ } else printk(KERN_INFO "Ql: Using preset IRQ %d\n", qlirq); - if (qlirq >= 0 && !request_irq(qlirq, do_ql_ihandl, 0, "qlogicfas", NULL)) - host->can_queue = 1; -#endif - hreg = scsi_register(host, 0); /* no host data */ + hreg = scsi_host_alloc(host, sizeof(struct qlogicfas_priv)); if (!hreg) goto err_release_mem; + priv = (qlogicfas_priv_t)&(hreg->hostdata[0]); hreg->io_port = qbase; hreg->n_io_port = 16; hreg->dma_channel = -1; if (qlirq != -1) hreg->irq = qlirq; + priv->qbase = qbase; + priv->qlirq = qlirq; + priv->qinitid = qinitid; + priv->shost = hreg; - sprintf(qinfo, + sprintf(priv->qinfo, "Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d", qltyp, qbase, qlirq, QL_TURBO_PDMA); - host->name = qinfo; + host->name = qlogicfas_name; + + if (request_irq(qlirq, do_ql_ihandl, 0, qlogicfas_name, hreg)) + goto free_scsi_host; + + if (scsi_add_host(hreg, NULL)) + goto free_interrupt; + + scsi_scan_host(hreg); return hreg; +free_interrupt: + free_irq(qlirq, hreg); + +free_scsi_host: + scsi_host_put(hreg); + err_release_mem: release_region(qbase, 0x10); - if (host->can_queue) - free_irq(qlirq, do_ql_ihandl); - return NULL;; - + return NULL; } +#define MAX_QLOGICFAS 8 +static qlogicfas_priv_t cards; +static int iobase[MAX_QLOGICFAS]; +static int irq[MAX_QLOGICFAS] = { [0 ... MAX_QLOGICFAS-1] = -1 }; +MODULE_PARM(iobase, "1-" __MODULE_STRING(MAX_QLOGICFAS) "i"); +MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_QLOGICFAS) "i"); +MODULE_PARM_DESC(iobase, "I/O address"); +MODULE_PARM_DESC(irq, "IRQ"); + int __devinit qlogicfas_detect(Scsi_Host_Template *sht) { - return (__qlogicfas_detect(sht) != NULL); + struct Scsi_Host *shost; + qlogicfas_priv_t priv; + int i, + num = 0; + + for (i = 0; i < MAX_QLOGICFAS; i++) { + shost = __qlogicfas_detect(sht, iobase[num], irq[num]); + if (shost == NULL) { + /* no more devices */ + break; + } + priv = (qlogicfas_priv_t)&(shost->hostdata[0]); + priv->next = cards; + cards = priv; + num++; + } + + return num; } static int qlogicfas_release(struct Scsi_Host *shost) { - if (shost->irq) - free_irq(shost->irq, NULL); + qlogicfas_priv_t priv = (qlogicfas_priv_t)&(shost->hostdata[0]); + int qbase = priv->qbase; + + if (shost->irq) { + REG1; + outb(0, qbase + 0xb); /* disable ints */ + + free_irq(shost->irq, shost); + } if (shost->dma_channel != 0xff) free_dma(shost->dma_channel); if (shost->io_port && shost->n_io_port) release_region(shost->io_port, shost->n_io_port); - scsi_unregister(shost); + scsi_remove_host(shost); + scsi_host_put(shost); + return 0; } +#endif /* ifndef PCMCIA */ /* * Return bios parameters @@ -742,8 +673,9 @@ static int qlogicfas_abort(Scsi_Cmnd * cmd) { - qabort = 1; - ql_zap(); + qlogicfas_priv_t priv = (qlogicfas_priv_t)&(cmd->device->host->hostdata[0]); + priv->qabort = 1; + ql_zap(priv); return SUCCESS; } @@ -755,8 +687,9 @@ int qlogicfas_bus_reset(Scsi_Cmnd * cmd) { - qabort = 2; - ql_zap(); + qlogicfas_priv_t priv = (qlogicfas_priv_t)&(cmd->device->host->hostdata[0]); + priv->qabort = 2; + ql_zap(priv); return SUCCESS; } @@ -784,22 +717,17 @@ static const char *qlogicfas_info(struct Scsi_Host *host) { - return qinfo; + qlogicfas_priv_t priv = (qlogicfas_priv_t)&(host->hostdata[0]); + return priv->qinfo; } -MODULE_AUTHOR("Tom Zerucha, Michael Griffith"); -MODULE_DESCRIPTION("Driver for the Qlogic FAS SCSI controllers"); -MODULE_LICENSE("GPL"); - /* * The driver template is also needed for PCMCIA */ Scsi_Host_Template qlogicfas_driver_template = { .module = THIS_MODULE, - .name = "qlogicfas", - .proc_name = "qlogicfas", - .detect = qlogicfas_detect, - .release = qlogicfas_release, + .name = qlogicfas_name, + .proc_name = qlogicfas_name, .info = qlogicfas_info, .queuecommand = qlogicfas_queuecommand, .eh_abort_handler = qlogicfas_abort, @@ -807,7 +735,7 @@ .eh_device_reset_handler= qlogicfas_device_reset, .eh_host_reset_handler = qlogicfas_host_reset, .bios_param = qlogicfas_biosparam, - .can_queue = 0, + .can_queue = 1, .this_id = -1, .sg_tablesize = SG_ALL, .cmd_per_lun = 1, @@ -815,6 +743,28 @@ }; #ifndef PCMCIA -#define driver_template qlogicfas_driver_template -#include "scsi_module.c" -#endif +static __init int qlogicfas_init(void) +{ + if (!qlogicfas_detect(&qlogicfas_driver_template)) { + /* no cards found */ + return -ENODEV; + } + + return 0; +} + +static __exit void qlogicfas_exit(void) +{ + qlogicfas_priv_t priv; + + for (priv = cards; priv != NULL; priv = priv->next) + qlogicfas_release(priv->shost); +} + +MODULE_AUTHOR("Tom Zerucha, Michael Griffith"); +MODULE_DESCRIPTION("Driver for the Qlogic FAS SCSI controllers"); +MODULE_LICENSE("GPL"); +module_init(qlogicfas_init); +module_exit(qlogicfas_exit); +#endif /* ifndef PCMCIA */ + diff -Nru a/drivers/scsi/qlogicfas.h b/drivers/scsi/qlogicfas.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/scsi/qlogicfas.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,124 @@ +/* to be used by qlogicfas and qlogic_cs */ +#ifndef __QLOGICFAS_H +#define __QLOGICFAS_H + +/*----------------------------------------------------------------*/ +/* Configuration */ + +/* Set the following to 2 to use normal interrupt (active high/totempole- + tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open + drain */ + +#define QL_INT_ACTIVE_HIGH 2 + +/* Set the following to max out the speed of the PIO PseudoDMA transfers, + again, 0 tends to be slower, but more stable. */ + +#define QL_TURBO_PDMA 1 + +/* This should be 1 to enable parity detection */ + +#define QL_ENABLE_PARITY 1 + +/* This will reset all devices when the driver is initialized (during bootup). + The other linux drivers don't do this, but the DOS drivers do, and after + using DOS or some kind of crash or lockup this will bring things back + without requiring a cold boot. It does take some time to recover from a + reset, so it is slower, and I have seen timeouts so that devices weren't + recognized when this was set. */ + +#define QL_RESET_AT_START 0 + +/* crystal frequency in megahertz (for offset 5 and 9) + Please set this for your card. Most Qlogic cards are 40 Mhz. The + Control Concepts ISA (not VLB) is 24 Mhz */ + +#define XTALFREQ 40 + +/**********/ +/* DANGER! modify these at your own risk */ +/* SLOWCABLE can usually be reset to zero if you have a clean setup and + proper termination. The rest are for synchronous transfers and other + advanced features if your device can transfer faster than 5Mb/sec. + If you are really curious, email me for a quick howto until I have + something official */ +/**********/ + +/*****/ +/* config register 1 (offset 8) options */ +/* This needs to be set to 1 if your cabling is long or noisy */ +#define SLOWCABLE 1 + +/*****/ +/* offset 0xc */ +/* This will set fast (10Mhz) synchronous timing when set to 1 + For this to have an effect, FASTCLK must also be 1 */ +#define FASTSCSI 0 + +/* This when set to 1 will set a faster sync transfer rate */ +#define FASTCLK 0 /*(XTALFREQ>25?1:0)*/ + +/*****/ +/* offset 6 */ +/* This is the sync transfer divisor, XTALFREQ/X will be the maximum + achievable data rate (assuming the rest of the system is capable + and set properly) */ +#define SYNCXFRPD 5 /*(XTALFREQ/5)*/ + +/*****/ +/* offset 7 */ +/* This is the count of how many synchronous transfers can take place + i.e. how many reqs can occur before an ack is given. + The maximum value for this is 15, the upper bits can modify + REQ/ACK assertion and deassertion during synchronous transfers + If this is 0, the bus will only transfer asynchronously */ +#define SYNCOFFST 0 +/* for the curious, bits 7&6 control the deassertion delay in 1/2 cycles + of the 40Mhz clock. If FASTCLK is 1, specifying 01 (1/2) will + cause the deassertion to be early by 1/2 clock. Bits 5&4 control + the assertion delay, also in 1/2 clocks (FASTCLK is ignored here). */ + +/*----------------------------------------------------------------*/ +#ifdef PCMCIA +#undef QL_INT_ACTIVE_HIGH +#define QL_INT_ACTIVE_HIGH 0 +#endif + +struct qlogicfas_priv; +typedef struct qlogicfas_priv *qlogicfas_priv_t; +struct qlogicfas_priv { + int qbase; /* Port */ + int qinitid; /* initiator ID */ + int qabort; /* Flag to cause an abort */ + int qlirq; /* IRQ being used */ + char qinfo[80]; /* description */ + Scsi_Cmnd *qlcmd; /* current command being processed */ + struct Scsi_Host *shost; /* pointer back to host */ + qlogicfas_priv_t next; /* next private struct */ +}; + +extern int qlcfg5; +extern int qlcfg6; +extern int qlcfg7; +extern int qlcfg8; +extern int qlcfg9; +extern int qlcfgc; + +/* The qlogic card uses two register maps - These macros select which one */ +#define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd )) +#define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd )) + +/* following is watchdog timeout in microseconds */ +#define WATCHDOG 5000000 + +/*----------------------------------------------------------------*/ +/* the following will set the monitor border color (useful to find + where something crashed or gets stuck at and as a simple profiler) */ + +#if 0 +#define rtrc(i) {inb(0x3da);outb(0x31,0x3c0);outb((i),0x3c0);} +#else +#define rtrc(i) {} +#endif +#endif /* __QLOGICFAS_H */ + diff -Nru a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c --- a/drivers/scsi/sata_promise.c Sun Mar 14 14:20:08 2004 +++ b/drivers/scsi/sata_promise.c Sun Mar 14 14:20:08 2004 @@ -146,10 +146,6 @@ static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg); static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); -static void pdc_sata_set_piomode (struct ata_port *ap, struct ata_device *adev, - unsigned int pio); -static void pdc_sata_set_udmamode (struct ata_port *ap, struct ata_device *adev, - unsigned int udma); static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static void pdc_dma_start(struct ata_queued_cmd *qc); static void pdc20621_dma_start(struct ata_queued_cmd *qc); @@ -200,8 +196,6 @@ static struct ata_port_operations pdc_sata_ops = { .port_disable = ata_port_disable, - .set_piomode = pdc_sata_set_piomode, - .set_udmamode = pdc_sata_set_udmamode, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read_mmio, .check_status = ata_check_status_mmio, @@ -220,8 +214,6 @@ static struct ata_port_operations pdc_20621_ops = { .port_disable = ata_port_disable, - .set_piomode = pdc_sata_set_piomode, - .set_udmamode = pdc_sata_set_udmamode, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read_mmio, .check_status = ata_check_status_mmio, @@ -378,19 +370,6 @@ writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4)); } -static void pdc_sata_set_piomode (struct ata_port *ap, struct ata_device *adev, - unsigned int pio) -{ - /* dummy */ -} - - -static void pdc_sata_set_udmamode (struct ata_port *ap, struct ata_device *adev, - unsigned int udma) -{ - /* dummy */ -} - enum pdc_packet_bits { PDC_PKT_READ = (1 << 2), PDC_PKT_NODATA = (1 << 3), @@ -1172,13 +1151,16 @@ { port->cmd_addr = base; port->data_addr = base; + port->feature_addr = port->error_addr = base + 0x4; port->nsect_addr = base + 0x8; port->lbal_addr = base + 0xc; port->lbam_addr = base + 0x10; port->lbah_addr = base + 0x14; port->device_addr = base + 0x18; - port->cmdstat_addr = base + 0x1c; + port->command_addr = + port->status_addr = base + 0x1c; + port->altstatus_addr = port->ctl_addr = base + 0x38; } diff -Nru a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c --- a/drivers/scsi/sata_sil.c Sun Mar 14 14:20:05 2004 +++ b/drivers/scsi/sata_sil.c Sun Mar 14 14:20:05 2004 @@ -75,10 +75,6 @@ SIL_QUIRK_UDMA5MAX = (1 << 1), }; -static void sil_set_piomode (struct ata_port *ap, struct ata_device *adev, - unsigned int pio); -static void sil_set_udmamode (struct ata_port *ap, struct ata_device *adev, - unsigned int udma); static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static void sil_dev_config(struct ata_port *ap, struct ata_device *dev); static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg); @@ -141,8 +137,6 @@ static struct ata_port_operations sil_ops = { .port_disable = ata_port_disable, .dev_config = sil_dev_config, - .set_piomode = sil_set_piomode, - .set_udmamode = sil_set_udmamode, .tf_load = ata_tf_load_mmio, .tf_read = ata_tf_read_mmio, .check_status = ata_check_status_mmio, @@ -287,22 +281,6 @@ } } -static void sil_set_piomode (struct ata_port *ap, struct ata_device *adev, - unsigned int pio) -{ - /* We need empty implementation, the core doesn't test for NULL - * function pointer - */ -} - -static void sil_set_udmamode (struct ata_port *ap, struct ata_device *adev, - unsigned int udma) -{ - /* We need empty implementation, the core doesn't test for NULL - * function pointer - */ -} - static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; @@ -360,12 +338,14 @@ base = (unsigned long) mmio_base; probe_ent->port[0].cmd_addr = base + SIL_IDE0_TF; + probe_ent->port[0].altstatus_addr = probe_ent->port[0].ctl_addr = base + SIL_IDE0_CTL; probe_ent->port[0].bmdma_addr = base + SIL_IDE0_BMDMA; probe_ent->port[0].scr_addr = base + SIL_IDE0_SCR; ata_std_ports(&probe_ent->port[0]); probe_ent->port[1].cmd_addr = base + SIL_IDE1_TF; + probe_ent->port[1].altstatus_addr = probe_ent->port[1].ctl_addr = base + SIL_IDE1_CTL; probe_ent->port[1].bmdma_addr = base + SIL_IDE1_BMDMA; probe_ent->port[1].scr_addr = base + SIL_IDE1_SCR; @@ -373,12 +353,14 @@ if (ent->driver_data == sil_3114) { probe_ent->port[2].cmd_addr = base + SIL_IDE2_TF; + probe_ent->port[2].altstatus_addr = probe_ent->port[2].ctl_addr = base + SIL_IDE2_CTL; probe_ent->port[2].bmdma_addr = base + SIL_IDE2_BMDMA; probe_ent->port[2].scr_addr = base + SIL_IDE2_SCR; ata_std_ports(&probe_ent->port[2]); probe_ent->port[3].cmd_addr = base + SIL_IDE3_TF; + probe_ent->port[3].altstatus_addr = probe_ent->port[3].ctl_addr = base + SIL_IDE3_CTL; probe_ent->port[3].bmdma_addr = base + SIL_IDE3_BMDMA; probe_ent->port[3].scr_addr = base + SIL_IDE3_SCR; diff -Nru a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c --- a/drivers/scsi/sata_svw.c Sun Mar 14 14:20:07 2004 +++ b/drivers/scsi/sata_svw.c Sun Mar 14 14:20:07 2004 @@ -103,13 +103,13 @@ ata_wait_idle(ap); } if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { - writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->error_addr); + writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->feature_addr); writew(tf->nsect | (((u16)tf->hob_nsect) << 8), ioaddr->nsect_addr); writew(tf->lbal | (((u16)tf->hob_lbal) << 8), ioaddr->lbal_addr); writew(tf->lbam | (((u16)tf->hob_lbam) << 8), ioaddr->lbam_addr); writew(tf->lbah | (((u16)tf->hob_lbah) << 8), ioaddr->lbah_addr); } else if (is_addr) { - writew(tf->feature, ioaddr->error_addr); + writew(tf->feature, ioaddr->feature_addr); writew(tf->nsect, ioaddr->nsect_addr); writew(tf->lbal, ioaddr->lbal_addr); writew(tf->lbam, ioaddr->lbam_addr); @@ -146,27 +146,9 @@ static u8 k2_stat_check_status(struct ata_port *ap) { - return readl((void *) ap->ioaddr.cmdstat_addr); + return readl((void *) ap->ioaddr.status_addr); } -static void k2_sata_set_piomode (struct ata_port *ap, struct ata_device *adev, - unsigned int pio) -{ - /* We need empty implementation, the core doesn't test for NULL - * function pointer - */ -} - - -static void k2_sata_set_udmamode (struct ata_port *ap, struct ata_device *adev, - unsigned int udma) -{ - /* We need empty implementation, the core doesn't test for NULL - * function pointer - */ -} - - #ifdef CONFIG_PPC_OF /* * k2_sata_proc_info @@ -239,8 +221,6 @@ static struct ata_port_operations k2_sata_ops = { .port_disable = ata_port_disable, - .set_piomode = k2_sata_set_piomode, - .set_udmamode = k2_sata_set_udmamode, .tf_load = k2_sata_tf_load, .tf_read = k2_sata_tf_read, .check_status = k2_stat_check_status, @@ -261,13 +241,16 @@ { port->cmd_addr = base + K2_SATA_TF_CMD_OFFSET; port->data_addr = base + K2_SATA_TF_DATA_OFFSET; + port->feature_addr = port->error_addr = base + K2_SATA_TF_ERROR_OFFSET; port->nsect_addr = base + K2_SATA_TF_NSECT_OFFSET; port->lbal_addr = base + K2_SATA_TF_LBAL_OFFSET; port->lbam_addr = base + K2_SATA_TF_LBAM_OFFSET; port->lbah_addr = base + K2_SATA_TF_LBAH_OFFSET; port->device_addr = base + K2_SATA_TF_DEVICE_OFFSET; - port->cmdstat_addr = base + K2_SATA_TF_CMDSTAT_OFFSET; + port->command_addr = + port->status_addr = base + K2_SATA_TF_CMDSTAT_OFFSET; + port->altstatus_addr = port->ctl_addr = base + K2_SATA_TF_CTL_OFFSET; port->bmdma_addr = base + K2_SATA_DMA_CMD_OFFSET; port->scr_addr = base + K2_SATA_SCR_STATUS_OFFSET; diff -Nru a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c --- a/drivers/scsi/sata_via.c Sun Mar 14 14:20:06 2004 +++ b/drivers/scsi/sata_via.c Sun Mar 14 14:20:06 2004 @@ -43,10 +43,6 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static void svia_sata_phy_reset(struct ata_port *ap); static void svia_port_disable(struct ata_port *ap); -static void svia_set_piomode (struct ata_port *ap, struct ata_device *adev, - unsigned int pio); -static void svia_set_udmamode (struct ata_port *ap, struct ata_device *adev, - unsigned int udma); static unsigned int in_module_init = 1; @@ -83,8 +79,6 @@ static struct ata_port_operations svia_sata_ops = { .port_disable = svia_port_disable, - .set_piomode = svia_set_piomode, - .set_udmamode = svia_set_udmamode, .tf_load = ata_tf_load_pio, .tf_read = ata_tf_read_pio, @@ -164,38 +158,6 @@ ata_port_disable(ap); /* FIXME */ -} - -/** - * svia_set_piomode - - * @ap: - * @adev: - * @pio: - * - * LOCKING: - * - */ - -static void svia_set_piomode (struct ata_port *ap, struct ata_device *adev, - unsigned int pio) -{ - /* FIXME: needed? */ -} - -/** - * svia_set_udmamode - - * @ap: - * @adev: - * @udma: - * - * LOCKING: - * - */ - -static void svia_set_udmamode (struct ata_port *ap, struct ata_device *adev, - unsigned int udma) -{ - /* FIXME: needed? */ } /** diff -Nru a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/scsi/sata_vsc.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,392 @@ +/* + * sata_vsc.c - Vitesse VSC7174 4 port DPA SATA + * + * Copyright 2004 SGI + * + * Bits from Jeff Garzik, Copyright RedHat, Inc. + * + * The contents of this file are subject to the Open + * Software License version 1.1 that can be found at + * http://www.opensource.org/licenses/osl-1.1.txt and is included herein + * by reference. + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public License version 2 (the "GPL") as distributed + * in the kernel source COPYING file, 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 OSL, 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 OSL or the GPL. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" +#include + +#define DRV_NAME "sata_vsc" +#define DRV_VERSION "0.01" + +/* Interrupt register offsets (from chip base address) */ +#define VSC_SATA_INT_STAT_OFFSET 0x00 +#define VSC_SATA_INT_MASK_OFFSET 0x04 + +/* Taskfile registers offsets */ +#define VSC_SATA_TF_CMD_OFFSET 0x00 +#define VSC_SATA_TF_DATA_OFFSET 0x00 +#define VSC_SATA_TF_ERROR_OFFSET 0x04 +#define VSC_SATA_TF_FEATURE_OFFSET 0x06 +#define VSC_SATA_TF_NSECT_OFFSET 0x08 +#define VSC_SATA_TF_LBAL_OFFSET 0x0c +#define VSC_SATA_TF_LBAM_OFFSET 0x10 +#define VSC_SATA_TF_LBAH_OFFSET 0x14 +#define VSC_SATA_TF_DEVICE_OFFSET 0x18 +#define VSC_SATA_TF_STATUS_OFFSET 0x1c +#define VSC_SATA_TF_COMMAND_OFFSET 0x1d +#define VSC_SATA_TF_ALTSTATUS_OFFSET 0x28 +#define VSC_SATA_TF_CTL_OFFSET 0x29 + +/* DMA base */ +#define VSC_SATA_DMA_CMD_OFFSET 0x70 + +/* SCRs base */ +#define VSC_SATA_SCR_STATUS_OFFSET 0x100 +#define VSC_SATA_SCR_ERROR_OFFSET 0x104 +#define VSC_SATA_SCR_CONTROL_OFFSET 0x108 + +/* Port stride */ +#define VSC_SATA_PORT_OFFSET 0x200 + + +static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) +{ + if (sc_reg > SCR_CONTROL) + return 0xffffffffU; + return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4)); +} + + +static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, + u32 val) +{ + if (sc_reg > SCR_CONTROL) + return; + writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4)); +} + + +static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl) +{ + unsigned long mask_addr; + u8 mask; + + mask_addr = (unsigned long) ap->host_set->mmio_base + + VSC_SATA_INT_MASK_OFFSET + ap->port_no; + mask = readb(mask_addr); + if (ctl & ATA_NIEN) + mask |= 0x80; + else + mask &= 0x7F; + writeb(mask, mask_addr); +} + + +static void vsc_sata_tf_load(struct ata_port *ap, struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; + + /* + * The only thing the ctl register is used for is SRST. + * That is not enabled or disabled via tf_load. + * However, if ATA_NIEN is changed, then we need to change the interrupt register. + */ + if ((tf->ctl & ATA_NIEN) != (ap->last_ctl & ATA_NIEN)) { + ap->last_ctl = tf->ctl; + vsc_intr_mask_update(ap, tf->ctl & ATA_NIEN); + } + if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { + writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->feature_addr); + writew(tf->nsect | (((u16)tf->hob_nsect) << 8), ioaddr->nsect_addr); + writew(tf->lbal | (((u16)tf->hob_lbal) << 8), ioaddr->lbal_addr); + writew(tf->lbam | (((u16)tf->hob_lbam) << 8), ioaddr->lbam_addr); + writew(tf->lbah | (((u16)tf->hob_lbah) << 8), ioaddr->lbah_addr); + } else if (is_addr) { + writew(tf->feature, ioaddr->feature_addr); + writew(tf->nsect, ioaddr->nsect_addr); + writew(tf->lbal, ioaddr->lbal_addr); + writew(tf->lbam, ioaddr->lbam_addr); + writew(tf->lbah, ioaddr->lbah_addr); + } + + if (tf->flags & ATA_TFLAG_DEVICE) + writeb(tf->device, ioaddr->device_addr); + + ata_wait_idle(ap); +} + + +static void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) +{ + struct ata_ioports *ioaddr = &ap->ioaddr; + u16 nsect, lbal, lbam, lbah; + + nsect = tf->nsect = readw(ioaddr->nsect_addr); + lbal = tf->lbal = readw(ioaddr->lbal_addr); + lbam = tf->lbam = readw(ioaddr->lbam_addr); + lbah = tf->lbah = readw(ioaddr->lbah_addr); + tf->device = readw(ioaddr->device_addr); + + if (tf->flags & ATA_TFLAG_LBA48) { + tf->hob_feature = readb(ioaddr->error_addr); + tf->hob_nsect = nsect >> 8; + tf->hob_lbal = lbal >> 8; + tf->hob_lbam = lbam >> 8; + tf->hob_lbah = lbah >> 8; + } +} + + +/* + * vsc_sata_interrupt + * + * Read the interrupt register and process for the devices that have them pending. + */ +irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance, struct pt_regs *regs) +{ + struct ata_host_set *host_set = dev_instance; + unsigned int i; + unsigned int handled = 0; + u32 int_status; + + spin_lock(&host_set->lock); + + int_status = readl(host_set->mmio_base + VSC_SATA_INT_STAT_OFFSET); + + for (i = 0; i < host_set->n_ports; i++) { + if (int_status & ((u32) 0xFF << (8 * i))) { + struct ata_port *ap; + + ap = host_set->ports[i]; + if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { + struct ata_queued_cmd *qc; + + qc = ata_qc_from_tag(ap, ap->active_tag); + if (qc && ((qc->flags & ATA_QCFLAG_POLL) == 0)) + handled += ata_host_intr(ap, qc); + } + } + } + + spin_unlock(&host_set->lock); + + return IRQ_RETVAL(handled); +} + + +static Scsi_Host_Template vsc_sata_sht = { + .module = THIS_MODULE, + .name = DRV_NAME, + .queuecommand = ata_scsi_queuecmd, + .eh_strategy_handler = ata_scsi_error, + .can_queue = ATA_DEF_QUEUE, + .this_id = ATA_SHT_THIS_ID, + .sg_tablesize = LIBATA_MAX_PRD, + .max_sectors = ATA_MAX_SECTORS, + .cmd_per_lun = ATA_SHT_CMD_PER_LUN, + .emulated = ATA_SHT_EMULATED, + .use_clustering = ATA_SHT_USE_CLUSTERING, + .proc_name = DRV_NAME, + .dma_boundary = ATA_DMA_BOUNDARY, + .slave_configure = ata_scsi_slave_config, + .bios_param = ata_std_bios_param, +}; + + +static struct ata_port_operations vsc_sata_ops = { + .port_disable = ata_port_disable, + .tf_load = vsc_sata_tf_load, + .tf_read = vsc_sata_tf_read, + .exec_command = ata_exec_command_mmio, + .check_status = ata_check_status_mmio, + .phy_reset = sata_phy_reset, + .phy_config = pata_phy_config, /* not a typo */ + .bmdma_start = ata_bmdma_start_mmio, + .fill_sg = ata_fill_sg, + .eng_timeout = ata_eng_timeout, + .irq_handler = vsc_sata_interrupt, + .scr_read = vsc_sata_scr_read, + .scr_write = vsc_sata_scr_write, + .port_start = ata_port_start, + .port_stop = ata_port_stop, +}; + +static void vsc_sata_setup_port(struct ata_ioports *port, unsigned long base) +{ + port->cmd_addr = base + VSC_SATA_TF_CMD_OFFSET; + port->data_addr = base + VSC_SATA_TF_DATA_OFFSET; + port->error_addr = base + VSC_SATA_TF_ERROR_OFFSET; + port->feature_addr = base + VSC_SATA_TF_FEATURE_OFFSET; + port->nsect_addr = base + VSC_SATA_TF_NSECT_OFFSET; + port->lbal_addr = base + VSC_SATA_TF_LBAL_OFFSET; + port->lbam_addr = base + VSC_SATA_TF_LBAM_OFFSET; + port->lbah_addr = base + VSC_SATA_TF_LBAH_OFFSET; + port->device_addr = base + VSC_SATA_TF_DEVICE_OFFSET; + port->status_addr = base + VSC_SATA_TF_STATUS_OFFSET; + port->command_addr = base + VSC_SATA_TF_COMMAND_OFFSET; + port->altstatus_addr = base + VSC_SATA_TF_ALTSTATUS_OFFSET; + port->ctl_addr = base + VSC_SATA_TF_CTL_OFFSET; + port->bmdma_addr = base + VSC_SATA_DMA_CMD_OFFSET; + port->scr_addr = base + VSC_SATA_SCR_STATUS_OFFSET; +} + + +static int vsc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) +{ + static int printed_version; + struct ata_probe_ent *probe_ent = NULL; + unsigned long base; + void *mmio_base; + int rc; + + if (!printed_version++) + printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + + rc = pci_enable_device(pdev); + if (rc) + return rc; + + /* + * Check if we have needed resource mapped. + */ + if (pci_resource_len(pdev, 0) == 0) { + rc = -ENODEV; + goto err_out; + } + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc) + goto err_out; + + /* + * Use 32 bit DMA mask, because 64 bit address support is poor. + */ + rc = pci_set_dma_mask(pdev, 0xFFFFFFFF); + if (rc) + goto err_out_regions; + rc = pci_set_consistent_dma_mask(pdev, 0xFFFFFFFF); + if (rc) + goto err_out_regions; + + probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + if (probe_ent == NULL) { + rc = -ENOMEM; + goto err_out_regions; + } + memset(probe_ent, 0, sizeof(*probe_ent)); + probe_ent->pdev = pdev; + INIT_LIST_HEAD(&probe_ent->node); + + mmio_base = ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (mmio_base == NULL) { + rc = -ENOMEM; + goto err_out_free_ent; + } + base = (unsigned long) mmio_base; + + /* + * Due to a bug in the chip, the default cache line size can't be used + */ + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x80); + + probe_ent->sht = &vsc_sata_sht; + probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_MMIO | ATA_FLAG_SATA_RESET; + probe_ent->port_ops = &vsc_sata_ops; + probe_ent->n_ports = 4; + probe_ent->irq = pdev->irq; + probe_ent->irq_flags = SA_SHIRQ; + probe_ent->mmio_base = mmio_base; + + /* We don't care much about the PIO/UDMA masks, but the core won't like us + * if we don't fill these + */ + probe_ent->pio_mask = 0x1f; + probe_ent->udma_mask = 0x3f; + + /* We have 4 ports per PCI function */ + vsc_sata_setup_port(&probe_ent->port[0], base + 1 * VSC_SATA_PORT_OFFSET); + vsc_sata_setup_port(&probe_ent->port[1], base + 2 * VSC_SATA_PORT_OFFSET); + vsc_sata_setup_port(&probe_ent->port[2], base + 3 * VSC_SATA_PORT_OFFSET); + vsc_sata_setup_port(&probe_ent->port[3], base + 4 * VSC_SATA_PORT_OFFSET); + + pci_set_master(pdev); + + /* FIXME: check ata_device_add return value */ + ata_device_add(probe_ent); + kfree(probe_ent); + + return 0; + +err_out_free_ent: + kfree(probe_ent); +err_out_regions: + pci_release_regions(pdev); +err_out: + pci_disable_device(pdev); + return rc; +} + + +static struct pci_device_id vsc_sata_pci_tbl[] = { + { 0x1725, 0x7174, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, + { 0x8086, 0x3200, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, + { } +}; + + +static struct pci_driver vsc_sata_pci_driver = { + .name = DRV_NAME, + .id_table = vsc_sata_pci_tbl, + .probe = vsc_sata_init_one, + .remove = ata_pci_remove_one, +}; + + +static int __init vsc_sata_init(void) +{ + int rc; + + rc = pci_module_init(&vsc_sata_pci_driver); + if (rc) + return rc; + + return 0; +} + + +static void __exit vsc_sata_exit(void) +{ + pci_unregister_driver(&vsc_sata_pci_driver); +} + + +MODULE_AUTHOR("Jeremy Higdon"); +MODULE_DESCRIPTION("low-level driver for Vitesse VSC7174 SATA controller"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, vsc_sata_pci_tbl); + +module_init(vsc_sata_init); +module_exit(vsc_sata_exit); diff -Nru a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c --- a/drivers/scsi/scsi.c Sun Mar 14 14:20:07 2004 +++ b/drivers/scsi/scsi.c Sun Mar 14 14:20:07 2004 @@ -104,7 +104,7 @@ "Communications ", "Unknown ", "Unknown ", - "Unknown ", + "RAID ", "Enclosure ", }; @@ -1097,7 +1097,7 @@ struct list_head *lh, *lh_sf; unsigned long flags; - sdev->sdev_state = SDEV_CANCEL; + scsi_device_set_state(sdev, SDEV_CANCEL); spin_lock_irqsave(&sdev->list_lock, flags); list_for_each_entry(scmd, &sdev->cmd_list, list) { diff -Nru a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c --- a/drivers/scsi/scsi_devinfo.c Sun Mar 14 14:20:06 2004 +++ b/drivers/scsi/scsi_devinfo.c Sun Mar 14 14:20:06 2004 @@ -94,95 +94,93 @@ * The following causes a failed REQUEST SENSE on lun 1 for * seagate controller, which causes SCSI code to reset bus. */ - {"TEXEL", "CD-ROM", "1.06", BLIST_NOLUN}, + {"HP", "C1750A", "3226", BLIST_NOLUN}, /* scanjet iic */ + {"HP", "C1790A", "", BLIST_NOLUN}, /* scanjet iip */ + {"HP", "C2500A", "", BLIST_NOLUN}, /* scanjet iicx */ + {"MEDIAVIS", "CDR-H93MV", "1.31", BLIST_NOLUN}, /* locks up */ + {"MICROTEK", "ScanMaker II", "5.61", BLIST_NOLUN}, /* responds to all lun */ + {"MITSUMI", "CD-R CR-2201CS", "6119", BLIST_NOLUN}, /* locks up */ + {"NEC", "D3856", "0009", BLIST_NOLUN}, {"QUANTUM", "LPS525S", "3110", BLIST_NOLUN}, /* locks up */ {"QUANTUM", "PD1225S", "3110", BLIST_NOLUN}, /* locks up */ {"QUANTUM", "FIREBALL ST4.3S", "0F0C", BLIST_NOLUN}, /* locks up */ - {"MEDIAVIS", "CDR-H93MV", "1.31", BLIST_NOLUN}, /* locks up */ + {"RELISYS", "Scorpio", NULL, BLIST_NOLUN}, /* responds to all lun */ {"SANKYO", "CP525", "6.64", BLIST_NOLUN}, /* causes failed REQ SENSE, extra reset */ - {"HP", "C1750A", "3226", BLIST_NOLUN}, /* scanjet iic */ - {"HP", "C1790A", "", BLIST_NOLUN}, /* scanjet iip */ - {"HP", "C2500A", "", BLIST_NOLUN}, /* scanjet iicx */ + {"TEXEL", "CD-ROM", "1.06", BLIST_NOLUN}, {"YAMAHA", "CDR100", "1.00", BLIST_NOLUN}, /* locks up */ {"YAMAHA", "CDR102", "1.00", BLIST_NOLUN}, /* locks up */ {"YAMAHA", "CRW8424S", "1.0", BLIST_NOLUN}, /* locks up */ {"YAMAHA", "CRW6416S", "1.0c", BLIST_NOLUN}, /* locks up */ - {"MITSUMI", "CD-R CR-2201CS", "6119", BLIST_NOLUN}, /* locks up */ - {"RELISYS", "Scorpio", NULL, BLIST_NOLUN}, /* responds to all lun */ - {"MICROTEK", "ScanMaker II", "5.61", BLIST_NOLUN}, /* responds to all lun */ - {"NEC", "D3856", "0009", BLIST_NOLUN}, /* * Other types of devices that have special flags. */ - {"SONY", "CD-ROM CDU-8001", NULL, BLIST_BORKEN}, - {"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN}, - {"IOMEGA", "Io20S *F", NULL, BLIST_KEY}, - {"INSITE", "Floptical F*8I", NULL, BLIST_KEY}, - {"INSITE", "I325VM", NULL, BLIST_KEY}, - {"LASOUND", "CDX7405", "3.10", BLIST_MAX5LUN | BLIST_SINGLELUN}, - {"MICROP", "4110", NULL, BLIST_NOTQ}, - {"NRC", "MBR-7", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"NRC", "MBR-7.4", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN}, - {"NAKAMICH", "MJ-4.8S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"NAKAMICH", "MJ-5.16S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"PIONEER", "CD-ROM DRM-600", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"PIONEER", "CD-ROM DRM-602X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"PIONEER", "CD-ROM DRM-604X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"EMULEX", "MD21/S2 ESDI", NULL, BLIST_SINGLELUN}, + {"ADAPTEC", "AACRAID", NULL, BLIST_FORCELUN}, + {"ADAPTEC", "Adaptec 5400S", NULL, BLIST_FORCELUN}, {"CANON", "IPUBJD", NULL, BLIST_SPARSELUN}, - {"nCipher", "Fastness Crypto", NULL, BLIST_FORCELUN}, - {"DEC", "HSG80", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, + {"CMD", "CRA-7280", NULL, BLIST_SPARSELUN}, /* CMD RAID Controller */ + {"CNSI", "G7324", NULL, BLIST_SPARSELUN}, /* Chaparral G7324 RAID */ + {"CNSi", "G8324", NULL, BLIST_SPARSELUN}, /* Chaparral G8324 RAID */ {"COMPAQ", "LOGICAL VOLUME", NULL, BLIST_FORCELUN}, {"COMPAQ", "CR3500", NULL, BLIST_FORCELUN}, - {"NEC", "PD-1 ODX654P", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"MATSHITA", "PD-1", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN}, - {"TOSHIBA", "CDROM", NULL, BLIST_ISROM}, - {"TOSHIBA", "CD-ROM", NULL, BLIST_ISROM}, - {"MegaRAID", "LD", NULL, BLIST_FORCELUN}, - {"DGC", "RAID", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, storage on LUN 0 */ - {"DGC", "DISK", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, no storage on LUN 0 */ + {"COMPAQ", "MSA1000", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, + {"COMPAQ", "MSA1000 VOLUME", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, + {"COMPAQ", "HSV110", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, + {"DDN", "SAN DataDirector", "*", BLIST_SPARSELUN}, + {"DEC", "HSG80", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, {"DELL", "PV660F", NULL, BLIST_SPARSELUN}, {"DELL", "PV660F PSEUDO", NULL, BLIST_SPARSELUN}, {"DELL", "PSEUDO DEVICE .", NULL, BLIST_SPARSELUN}, /* Dell PV 530F */ {"DELL", "PV530F", NULL, BLIST_SPARSELUN}, + {"DELL", "PERCRAID", NULL, BLIST_FORCELUN}, + {"DGC", "RAID", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, storage on LUN 0 */ + {"DGC", "DISK", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, no storage on LUN 0 */ {"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN}, + {"EMULEX", "MD21/S2 ESDI", NULL, BLIST_SINGLELUN}, + {"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"Generic", "USB Storage-SMC", "0207", BLIST_FORCELUN}, + {"HITACHI", "DF400", "*", BLIST_SPARSELUN}, + {"HITACHI", "DF500", "*", BLIST_SPARSELUN}, + {"HITACHI", "DF600", "*", BLIST_SPARSELUN}, {"HP", "A6189A", NULL, BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP VA7400 */ {"HP", "OPEN-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP XP Arrays */ - {"CMD", "CRA-7280", NULL, BLIST_SPARSELUN}, /* CMD RAID Controller */ - {"CNSI", "G7324", NULL, BLIST_SPARSELUN}, /* Chaparral G7324 RAID */ - {"CNSi", "G8324", NULL, BLIST_SPARSELUN}, /* Chaparral G8324 RAID */ - {"Zzyzx", "RocketStor 500S", NULL, BLIST_SPARSELUN}, - {"Zzyzx", "RocketStor 2000", NULL, BLIST_SPARSELUN}, - {"SONY", "TSL", NULL, BLIST_FORCELUN}, /* DDS3 & DDS4 autoloaders */ - {"DELL", "PERCRAID", NULL, BLIST_FORCELUN}, {"HP", "NetRAID-4M", NULL, BLIST_FORCELUN}, - {"ADAPTEC", "AACRAID", NULL, BLIST_FORCELUN}, - {"ADAPTEC", "Adaptec 5400S", NULL, BLIST_FORCELUN}, - {"COMPAQ", "MSA1000", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, - {"COMPAQ", "MSA1000 VOLUME", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, - {"COMPAQ", "HSV110", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, {"HP", "HSV100", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, {"HP", "C1557A", NULL, BLIST_FORCELUN}, {"IBM", "AuSaV1S2", NULL, BLIST_FORCELUN}, - {"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"DDN", "SAN DataDirector", "*", BLIST_SPARSELUN}, - {"HITACHI", "DF400", "*", BLIST_SPARSELUN}, - {"HITACHI", "DF500", "*", BLIST_SPARSELUN}, - {"HITACHI", "DF600", "*", BLIST_SPARSELUN}, {"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"SUN", "T300", "*", BLIST_SPARSELUN}, - {"SUN", "T4", "*", BLIST_SPARSELUN}, + {"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN}, + {"IOMEGA", "Io20S *F", NULL, BLIST_KEY}, + {"INSITE", "Floptical F*8I", NULL, BLIST_KEY}, + {"INSITE", "I325VM", NULL, BLIST_KEY}, + {"LASOUND", "CDX7405", "3.10", BLIST_MAX5LUN | BLIST_SINGLELUN}, + {"MATSHITA", "PD-1", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, + {"MegaRAID", "LD", NULL, BLIST_FORCELUN}, + {"MICROP", "4110", NULL, BLIST_NOTQ}, + {"MYLEX", "DACARMRB", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"nCipher", "Fastness Crypto", NULL, BLIST_FORCELUN}, + {"NAKAMICH", "MJ-4.8S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, + {"NAKAMICH", "MJ-5.16S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, + {"NEC", "PD-1 ODX654P", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, + {"NRC", "MBR-7", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, + {"NRC", "MBR-7.4", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, + {"PIONEER", "CD-ROM DRM-600", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, + {"PIONEER", "CD-ROM DRM-602X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, + {"PIONEER", "CD-ROM DRM-604X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, + {"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN}, {"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}, + {"SONY", "CD-ROM CDU-8001", NULL, BLIST_BORKEN}, + {"SONY", "TSL", NULL, BLIST_FORCELUN}, /* DDS3 & DDS4 autoloaders */ + {"SUN", "T300", "*", BLIST_SPARSELUN}, + {"SUN", "T4", "*", BLIST_SPARSELUN}, + {"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN}, + {"TOSHIBA", "CDROM", NULL, BLIST_ISROM}, + {"TOSHIBA", "CD-ROM", NULL, BLIST_ISROM}, {"XYRATEX", "RS", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, + {"Zzyzx", "RocketStor 500S", NULL, BLIST_SPARSELUN}, + {"Zzyzx", "RocketStor 2000", NULL, BLIST_SPARSELUN}, { NULL, NULL, NULL, 0 }, }; diff -Nru a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c --- a/drivers/scsi/scsi_error.c Sun Mar 14 14:20:05 2004 +++ b/drivers/scsi/scsi_error.c Sun Mar 14 14:20:05 2004 @@ -37,6 +37,8 @@ #define SENSE_TIMEOUT (10*HZ) #endif +#define START_UNIT_TIMEOUT (30*HZ) + /* * These should *probably* be handled by the host itself. * Since it is allowed to sleep, it probably should. @@ -282,6 +284,15 @@ (scmd->sense_buffer[13] == 0x01)) { return NEEDS_RETRY; } + /* + * if the device is not started, we need to wake + * the error handler to start the motor + */ + if (scmd->device->allow_restart && + (scmd->sense_buffer[12] == 0x04) && + (scmd->sense_buffer[13] == 0x02)) { + return FAILED; + } return SUCCESS; /* these three are not supported */ @@ -829,6 +840,105 @@ } /** + * scsi_eh_try_stu - Send START_UNIT to device. + * @scmd: Scsi cmd to send START_UNIT + * + * Return value: + * 0 - Device is ready. 1 - Device NOT ready. + **/ +static int scsi_eh_try_stu(struct scsi_cmnd *scmd) +{ + static unsigned char stu_command[6] = {START_STOP, 0, 0, 0, 1, 0}; + int rtn; + + if (!scmd->device->allow_restart) + return 1; + + memcpy(scmd->cmnd, stu_command, sizeof(stu_command)); + + /* + * zero the sense buffer. the scsi spec mandates that any + * untransferred sense data should be interpreted as being zero. + */ + memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer)); + + scmd->request_buffer = NULL; + scmd->request_bufflen = 0; + scmd->use_sg = 0; + scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]); + scmd->underflow = 0; + scmd->sc_data_direction = DMA_NONE; + + rtn = scsi_send_eh_cmnd(scmd, START_UNIT_TIMEOUT); + + /* + * when we eventually call scsi_finish, we really wish to complete + * the original request, so let's restore the original data. (db) + */ + scsi_setup_cmd_retry(scmd); + + /* + * hey, we are done. let's look to see what happened. + */ + SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n", + __FUNCTION__, scmd, rtn)); + if (rtn == SUCCESS) + return 0; + return 1; +} + + /** + * scsi_eh_stu - send START_UNIT if needed + * @shost: scsi host being recovered. + * @eh_done_q: list_head for processed commands. + * + * Notes: + * If commands are failing due to not ready, initializing command required, + * try revalidating the device, which will end up sending a start unit. + **/ +static int scsi_eh_stu(struct Scsi_Host *shost, + struct list_head *work_q, + struct list_head *done_q) +{ + struct list_head *lh, *lh_sf; + struct scsi_cmnd *scmd, *stu_scmd; + struct scsi_device *sdev; + + shost_for_each_device(sdev, shost) { + stu_scmd = NULL; + list_for_each_entry(scmd, work_q, eh_entry) + if (scmd->device == sdev && SCSI_SENSE_VALID(scmd) && + scsi_check_sense(scmd) == FAILED ) { + stu_scmd = scmd; + break; + } + + if (!stu_scmd) + continue; + + SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending START_UNIT to sdev:" + " 0x%p\n", current->comm, sdev)); + + if (!scsi_eh_try_stu(stu_scmd)) { + if (!sdev->online || !scsi_eh_tur(stu_scmd)) { + list_for_each_safe(lh, lh_sf, work_q) { + scmd = list_entry(lh, struct scsi_cmnd, eh_entry); + if (scmd->device == sdev) + scsi_eh_finish_cmd(scmd, done_q); + } + } + } else { + SCSI_LOG_ERROR_RECOVERY(3, + printk("%s: START_UNIT failed to sdev:" + " 0x%p\n", current->comm, sdev)); + } + } + + return list_empty(work_q); +} + + +/** * scsi_eh_bus_device_reset - send bdr if needed * @shost: scsi host being recovered. * @eh_done_q: list_head for processed commands. @@ -1033,7 +1143,9 @@ if (rtn == SUCCESS) { list_for_each_safe(lh, lh_sf, work_q) { scmd = list_entry(lh, struct scsi_cmnd, eh_entry); - if (!scmd->device->online || !scsi_eh_tur(scmd)) + if (!scmd->device->online || + (!scsi_eh_try_stu(scmd) && !scsi_eh_tur(scmd)) || + !scsi_eh_tur(scmd)) scsi_eh_finish_cmd(scmd, done_q); } } else { @@ -1181,6 +1293,8 @@ */ case DID_SOFT_ERROR: goto maybe_retry; + case DID_IMM_RETRY: + return NEEDS_RETRY; case DID_ERROR: if (msg_byte(scmd->result) == COMMAND_COMPLETE && @@ -1401,10 +1515,11 @@ struct list_head *work_q, struct list_head *done_q) { - if (!scsi_eh_bus_device_reset(shost, work_q, done_q)) - if (!scsi_eh_bus_reset(shost, work_q, done_q)) - if (!scsi_eh_host_reset(work_q, done_q)) - scsi_eh_offline_sdevs(work_q, done_q); + if (!scsi_eh_stu(shost, work_q, done_q)) + if (!scsi_eh_bus_device_reset(shost, work_q, done_q)) + if (!scsi_eh_bus_reset(shost, work_q, done_q)) + if (!scsi_eh_host_reset(work_q, done_q)) + scsi_eh_offline_sdevs(work_q, done_q); } /** diff -Nru a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c --- a/drivers/scsi/scsi_lib.c Sun Mar 14 14:20:07 2004 +++ b/drivers/scsi/scsi_lib.c Sun Mar 14 14:20:07 2004 @@ -24,7 +24,7 @@ #include "scsi_logging.h" -#define SG_MEMPOOL_NR 5 +#define SG_MEMPOOL_NR (sizeof(scsi_sg_pools)/sizeof(struct scsi_host_sg_pool)) #define SG_MEMPOOL_SIZE 32 struct scsi_host_sg_pool { @@ -34,9 +34,27 @@ mempool_t *pool; }; +#if (SCSI_MAX_PHYS_SEGMENTS < 32) +#error SCSI_MAX_PHYS_SEGMENTS is too small +#endif + #define SP(x) { x, "sgpool-" #x } -struct scsi_host_sg_pool scsi_sg_pools[SG_MEMPOOL_NR] = { - SP(8), SP(16), SP(32), SP(64), SP(MAX_PHYS_SEGMENTS) +struct scsi_host_sg_pool scsi_sg_pools[] = { + SP(8), + SP(16), + SP(32), +#if (SCSI_MAX_PHYS_SEGMENTS > 32) + SP(64), +#if (SCSI_MAX_PHYS_SEGMENTS > 64) + SP(128), +#if (SCSI_MAX_PHYS_SEGMENTS > 128) + SP(256), +#if (SCSI_MAX_PHYS_SEGMENTS > 256) +#error SCSI_MAX_PHYS_SEGMENTS is too large +#endif +#endif +#endif +#endif }; #undef SP @@ -172,6 +190,10 @@ * like ioctls and character device requests - this is because * we essentially just inject a request into the queue for the * device. + * + * In order to support the scsi_device_quiesce function, we + * now inject requests on the *head* of the device queue + * rather than the tail. */ void scsi_do_req(struct scsi_request *sreq, const void *cmnd, void *buffer, unsigned bufflen, @@ -202,11 +224,9 @@ sreq->sr_cmd_len = COMMAND_SIZE(sreq->sr_cmnd[0]); /* - * At this point, we merely set up the command, stick it in the normal - * request queue, and return. Eventually that request will come to the - * top of the list, and will be dispatched. + * head injection *required* here otherwise quiesce won't work */ - scsi_insert_special_req(sreq, 0); + scsi_insert_special_req(sreq, 1); } static void scsi_wait_done(struct scsi_cmnd *cmd) @@ -558,12 +578,21 @@ case 17 ... 32: cmd->sglist_len = 2; break; +#if (SCSI_MAX_PHYS_SEGMENTS > 32) case 33 ... 64: cmd->sglist_len = 3; break; - case 65 ... MAX_PHYS_SEGMENTS: +#if (SCSI_MAX_PHYS_SEGMENTS > 64) + case 65 ... 128: cmd->sglist_len = 4; break; +#if (SCSI_MAX_PHYS_SEGMENTS > 128) + case 129 ... 256: + cmd->sglist_len = 5; + break; +#endif +#endif +#endif default: return NULL; } @@ -917,6 +946,7 @@ req->current_nr_sectors); /* release the command and kill it */ + scsi_release_buffers(cmd); scsi_put_command(cmd); return BLKPREP_KILL; } @@ -939,7 +969,7 @@ } /* OK, we only allow special commands (i.e. not * user initiated ones */ - specials_only = 1; + specials_only = sdev->sdev_state; } /* @@ -965,6 +995,9 @@ } else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) { if(unlikely(specials_only)) { + if(specials_only == SDEV_QUIESCE) + return BLKPREP_DEFER; + printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to device being removed\n", sdev->host->host_no, sdev->id, sdev->lun); return BLKPREP_KILL; @@ -1285,7 +1318,7 @@ blk_queue_prep_rq(q, scsi_prep_fn); blk_queue_max_hw_segments(q, shost->sg_tablesize); - blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS); + blk_queue_max_phys_segments(q, SCSI_MAX_PHYS_SEGMENTS); blk_queue_max_sectors(q, shost->max_sectors); blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost)); blk_queue_segment_boundary(q, shost->dma_boundary); @@ -1508,3 +1541,95 @@ return ret; } + +/** + * scsi_device_set_state - Take the given device through the device + * state model. + * @sdev: scsi device to change the state of. + * @state: state to change to. + * + * Returns zero if unsuccessful or an error if the requested + * transition is illegal. + **/ +int +scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state) +{ + enum scsi_device_state oldstate = sdev->sdev_state; + + /* FIXME: eventually we will enforce all the state model + * transitions here */ + + if(oldstate == state) + return 0; + + switch(state) { + case SDEV_RUNNING: + if(oldstate != SDEV_CREATED && oldstate != SDEV_QUIESCE) + return -EINVAL; + break; + + case SDEV_QUIESCE: + if(oldstate != SDEV_RUNNING) + return -EINVAL; + break; + + default: + break; + } + sdev->sdev_state = state; + + return 0; +} +EXPORT_SYMBOL(scsi_device_set_state); + +/** + * scsi_device_quiesce - Block user issued commands. + * @sdev: scsi device to quiesce. + * + * This works by trying to transition to the SDEV_QUIESCE state + * (which must be a legal transition). When the device is in this + * state, only special requests will be accepted, all others will + * be deferred. Since special requests may also be requeued requests, + * a successful return doesn't guarantee the device will be + * totally quiescent. + * + * Must be called with user context, may sleep. + * + * Returns zero if unsuccessful or an error if not. + **/ +int +scsi_device_quiesce(struct scsi_device *sdev) +{ + int err = scsi_device_set_state(sdev, SDEV_QUIESCE); + if(err) + return err; + + scsi_run_queue(sdev->request_queue); + while(sdev->device_busy) { + schedule_timeout(HZ/5); + scsi_run_queue(sdev->request_queue); + } + return 0; +} +EXPORT_SYMBOL(scsi_device_quiesce); + +/** + * scsi_device_resume - Restart user issued commands to a quiesced device. + * @sdev: scsi device to resume. + * + * Moves the device from quiesced back to running and restarts the + * queues. + * + * Must be called with user context, may sleep. + **/ +void +scsi_device_resume(struct scsi_device *sdev) +{ + if(sdev->sdev_state != SDEV_QUIESCE) + return; + + scsi_device_set_state(sdev, SDEV_RUNNING); + scsi_run_queue(sdev->request_queue); +} +EXPORT_SYMBOL(scsi_device_resume); + diff -Nru a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h --- a/drivers/scsi/scsi_priv.h Sun Mar 14 14:20:07 2004 +++ b/drivers/scsi/scsi_priv.h Sun Mar 14 14:20:07 2004 @@ -155,6 +155,7 @@ extern int scsi_sysfs_add_host(struct Scsi_Host *); extern int scsi_sysfs_register(void); extern void scsi_sysfs_unregister(void); +extern struct scsi_transport_template blank_transport_template; extern struct class sdev_class; extern struct bus_type scsi_bus_type; diff -Nru a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c --- a/drivers/scsi/scsi_scan.c Sun Mar 14 14:20:08 2004 +++ b/drivers/scsi/scsi_scan.c Sun Mar 14 14:20:08 2004 @@ -35,6 +35,7 @@ #include #include #include +#include #include "scsi.h" #include "scsi_priv.h" @@ -192,7 +193,7 @@ struct scsi_device *sdev, *device; unsigned long flags; - sdev = kmalloc(sizeof(*sdev), GFP_ATOMIC); + sdev = kmalloc(sizeof(*sdev) + shost->transportt->size, GFP_ATOMIC); if (!sdev) goto out; @@ -237,6 +238,11 @@ goto out_free_queue; } + if (shost->transportt->setup) { + if (shost->transportt->setup(sdev)) + goto out_cleanup_slave; + } + if (get_device(&sdev->host->shost_gendev)) { device_initialize(&sdev->sdev_gendev); @@ -253,8 +259,15 @@ snprintf(sdev->sdev_classdev.class_id, BUS_ID_SIZE, "%d:%d:%d:%d", sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); + + class_device_initialize(&sdev->transport_classdev); + sdev->transport_classdev.dev = &sdev->sdev_gendev; + sdev->transport_classdev.class = sdev->host->transportt->class; + snprintf(sdev->transport_classdev.class_id, BUS_ID_SIZE, + "%d:%d:%d:%d", sdev->host->host_no, + sdev->channel, sdev->id, sdev->lun); } else - goto out_cleanup_slave; + goto out_cleanup_transport; /* * If there are any same target siblings, add this to the @@ -283,6 +296,9 @@ spin_unlock_irqrestore(shost->host_lock, flags); return sdev; +out_cleanup_transport: + if (shost->transportt->cleanup) + shost->transportt->cleanup(sdev); out_cleanup_slave: if (shost->hostt->slave_destroy) shost->hostt->slave_destroy(sdev); @@ -627,6 +643,10 @@ if (*bflags & BLIST_USE_10_BYTE_MS) sdev->use_10_for_ms = 1; + /* set the device running here so that slave configure + * may do I/O */ + scsi_device_set_state(sdev, SDEV_RUNNING); + if(sdev->host->hostt->slave_configure) sdev->host->hostt->slave_configure(sdev); @@ -744,6 +764,8 @@ } else { if (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy(sdev); + if (sdev->host->transportt->cleanup) + sdev->host->transportt->cleanup(sdev); put_device(&sdev->sdev_gendev); } out: @@ -1300,5 +1322,7 @@ if (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy(sdev); + if (sdev->host->transportt->cleanup) + sdev->host->transportt->cleanup(sdev); put_device(&sdev->sdev_gendev); } diff -Nru a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c --- a/drivers/scsi/scsi_sysfs.c Sun Mar 14 14:20:06 2004 +++ b/drivers/scsi/scsi_sysfs.c Sun Mar 14 14:20:06 2004 @@ -13,6 +13,7 @@ #include #include +#include #include "scsi.h" #include "scsi_priv.h" @@ -58,21 +59,24 @@ * shost_show_function: macro to create an attr function that can be used to * show a non-bit field. */ -#define shost_show_function(field, format_string) \ +#define shost_show_function(name, field, format_string) \ static ssize_t \ -show_##field (struct class_device *class_dev, char *buf) \ +show_##name (struct class_device *class_dev, char *buf) \ { \ struct Scsi_Host *shost = class_to_shost(class_dev); \ - return snprintf (buf, 20, format_string, shost->field); \ + return snprintf (buf, 20, format_string, shost->field); \ } /* * shost_rd_attr: macro to create a function and attribute variable for a * read only field. */ -#define shost_rd_attr(field, format_string) \ - shost_show_function(field, format_string) \ -static CLASS_DEVICE_ATTR(field, S_IRUGO, show_##field, NULL) +#define shost_rd_attr2(name, field, format_string) \ + shost_show_function(name, field, format_string) \ +static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL) + +#define shost_rd_attr(field, format_string) \ +shost_rd_attr2(field, field, format_string) /* * Create the actual show/store functions and data structures. @@ -96,6 +100,7 @@ shost_rd_attr(cmd_per_lun, "%hd\n"); shost_rd_attr(sg_tablesize, "%hu\n"); shost_rd_attr(unchecked_isa_dma, "%d\n"); +shost_rd_attr2(proc_name, hostt->proc_name, "%s\n"); static struct class_device_attribute *scsi_sysfs_shost_attrs[] = { &class_device_attr_unique_id, @@ -103,6 +108,7 @@ &class_device_attr_cmd_per_lun, &class_device_attr_sg_tablesize, &class_device_attr_unchecked_isa_dma, + &class_device_attr_proc_name, &class_device_attr_scan, NULL }; @@ -344,13 +350,12 @@ **/ int scsi_sysfs_add_sdev(struct scsi_device *sdev) { - int error = -EINVAL, i; + struct class_device_attribute **attrs; + int error, i; - if (sdev->sdev_state != SDEV_CREATED) + if ((error = scsi_device_set_state(sdev, SDEV_RUNNING)) != 0) return error; - sdev->sdev_state = SDEV_RUNNING; - error = device_add(&sdev->sdev_gendev); if (error) { printk(KERN_INFO "error 1\n"); @@ -362,9 +367,20 @@ printk(KERN_INFO "error 2\n"); goto clean_device; } - + /* take a reference for the sdev_classdev; this is + * released by the sdev_class .release */ get_device(&sdev->sdev_gendev); + if (sdev->transport_classdev.class) { + error = class_device_add(&sdev->transport_classdev); + if (error) + goto clean_device2; + /* take a reference for the transport_classdev; this + * is released by the transport_class .release */ + get_device(&sdev->sdev_gendev); + + } + if (sdev->host->hostt->sdev_attrs) { for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) { error = attr_add(&sdev->sdev_gendev, @@ -388,11 +404,25 @@ } } + if (sdev->transport_classdev.class) { + attrs = sdev->host->transportt->attrs; + for (i = 0; attrs[i]; i++) { + error = class_device_create_file(&sdev->transport_classdev, + attrs[i]); + if (error) { + scsi_remove_device(sdev); + goto out; + } + } + } + out: return error; -clean_device: - sdev->sdev_state = SDEV_CANCEL; + clean_device2: + class_device_del(&sdev->sdev_classdev); + clean_device: + scsi_device_set_state(sdev, SDEV_CANCEL); device_del(&sdev->sdev_gendev); put_device(&sdev->sdev_gendev); @@ -407,11 +437,15 @@ void scsi_remove_device(struct scsi_device *sdev) { if (sdev->sdev_state == SDEV_RUNNING || sdev->sdev_state == SDEV_CANCEL) { - sdev->sdev_state = SDEV_DEL; + scsi_device_set_state(sdev, SDEV_DEL); class_device_unregister(&sdev->sdev_classdev); + if(sdev->transport_classdev.class) + class_device_unregister(&sdev->transport_classdev); device_del(&sdev->sdev_gendev); if (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy(sdev); + if (sdev->host->transportt->cleanup) + sdev->host->transportt->cleanup(sdev); put_device(&sdev->sdev_gendev); } } @@ -498,3 +532,7 @@ return 0; } + +/* A blank transport template that is used in drivers that don't + * yet implement Transport Attributes */ +struct scsi_transport_template blank_transport_template = { 0, }; diff -Nru a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/scsi/scsi_transport_fc.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,104 @@ +/* + * FiberChannel transport specific attributes exported to sysfs. + * + * Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include + +static void transport_class_release(struct class_device *class_dev); + +struct class fc_transport_class = { + .name = "fc_transport", + .release = transport_class_release, +}; + +static __init int fc_transport_init(void) +{ + return class_register(&fc_transport_class); +} + +static void __exit fc_transport_exit(void) +{ + class_unregister(&fc_transport_class); +} + +static int fc_setup_transport_attrs(struct scsi_device *sdev) +{ + /* FIXME: Callback into the driver */ + fc_node_name(sdev) = -1; + fc_port_name(sdev) = -1; + fc_port_id(sdev) = -1; + + return 0; +} + +static void transport_class_release(struct class_device *class_dev) +{ + struct scsi_device *sdev = transport_class_to_sdev(class_dev); + put_device(&sdev->sdev_gendev); +} + +#define fc_transport_show_function(field, format_string, cast) \ +static ssize_t \ +show_fc_transport_##field (struct class_device *cdev, char *buf) \ +{ \ + struct scsi_device *sdev = transport_class_to_sdev(cdev); \ + struct fc_transport_attrs *tp; \ + tp = (struct fc_transport_attrs *)&sdev->transport_data; \ + return snprintf(buf, 20, format_string, cast tp->field); \ +} + +#define fc_transport_rd_attr(field, format_string) \ + fc_transport_show_function(field, format_string, ) \ +static CLASS_DEVICE_ATTR( field, S_IRUGO, show_fc_transport_##field, NULL) + +#define fc_transport_rd_attr_cast(field, format_string, cast) \ + fc_transport_show_function(field, format_string, (cast)) \ +static CLASS_DEVICE_ATTR( field, S_IRUGO, show_fc_transport_##field, NULL) + +/* the FiberChannel Tranport Attributes: */ +fc_transport_rd_attr_cast(node_name, "0x%llx\n", unsigned long long); +fc_transport_rd_attr_cast(port_name, "0x%llx\n", unsigned long long); +fc_transport_rd_attr(port_id, "0x%06x\n"); + +struct class_device_attribute *fc_transport_attrs[] = { + &class_device_attr_node_name, + &class_device_attr_port_name, + &class_device_attr_port_id, + NULL +}; + +struct scsi_transport_template fc_transport_template = { + .attrs = fc_transport_attrs, + .class = &fc_transport_class, + .setup = &fc_setup_transport_attrs, + .cleanup = NULL, + .size = sizeof(struct fc_transport_attrs) - sizeof(unsigned long), +}; +EXPORT_SYMBOL(fc_transport_template); + +MODULE_AUTHOR("Martin Hicks"); +MODULE_DESCRIPTION("FC Transport Attributes"); +MODULE_LICENSE("GPL"); + +module_init(fc_transport_init); +module_exit(fc_transport_exit); diff -Nru a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/scsi/scsi_transport_spi.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,673 @@ +/* + * Parallel SCSI (SPI) transport specific attributes exported to sysfs. + * + * Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SPI_PRINTK(x, l, f, a...) printk(l "scsi(%d:%d:%d:%d): " f, (x)->host->host_no, (x)->channel, (x)->id, (x)->lun, ##a) + +static void transport_class_release(struct class_device *class_dev); + +#define SPI_NUM_ATTRS 10 /* increase this if you add attributes */ + +#define SPI_MAX_ECHO_BUFFER_SIZE 4096 + +#define spi_dv_pending(x) (((struct spi_transport_attrs *)&(x)->transport_data)->dv_pending) + +struct spi_internal { + struct scsi_transport_template t; + struct spi_function_template *f; + /* The actual attributes */ + struct class_device_attribute private_attrs[SPI_NUM_ATTRS]; + /* The array of null terminated pointers to attributes + * needed by scsi_sysfs.c */ + struct class_device_attribute *attrs[SPI_NUM_ATTRS + 1]; +}; + +#define to_spi_internal(tmpl) container_of(tmpl, struct spi_internal, t) + +static const char *const ppr_to_ns[] = { + /* The PPR values 0-6 are reserved, fill them in when + * the committee defines them */ + NULL, /* 0x00 */ + NULL, /* 0x01 */ + NULL, /* 0x02 */ + NULL, /* 0x03 */ + NULL, /* 0x04 */ + NULL, /* 0x05 */ + NULL, /* 0x06 */ + "3.125", /* 0x07 */ + "6.25", /* 0x08 */ + "12.5", /* 0x09 */ + "25", /* 0x0a */ + "30.3", /* 0x0b */ + "50", /* 0x0c */ +}; +/* The PPR values at which you calculate the period in ns by multiplying + * by 4 */ +#define SPI_STATIC_PPR 0x0c + +struct class spi_transport_class = { + .name = "spi_transport", + .release = transport_class_release, +}; + +static __init int spi_transport_init(void) +{ + return class_register(&spi_transport_class); +} + +static void __exit spi_transport_exit(void) +{ + class_unregister(&spi_transport_class); +} + +static int spi_setup_transport_attrs(struct scsi_device *sdev) +{ + spi_period(sdev) = -1; /* illegal value */ + spi_offset(sdev) = 0; /* async */ + spi_width(sdev) = 0; /* narrow */ + spi_iu(sdev) = 0; /* no IU */ + spi_dt(sdev) = 0; /* ST */ + spi_qas(sdev) = 0; + spi_wr_flow(sdev) = 0; + spi_rd_strm(sdev) = 0; + spi_rti(sdev) = 0; + spi_pcomp_en(sdev) = 0; + spi_dv_pending(sdev) = 0; + + return 0; +} + +static void transport_class_release(struct class_device *class_dev) +{ + struct scsi_device *sdev = transport_class_to_sdev(class_dev); + put_device(&sdev->sdev_gendev); +} + +#define spi_transport_show_function(field, format_string) \ + \ +static ssize_t \ +show_spi_transport_##field(struct class_device *cdev, char *buf) \ +{ \ + struct scsi_device *sdev = transport_class_to_sdev(cdev); \ + struct spi_transport_attrs *tp; \ + struct spi_internal *i = to_spi_internal(sdev->host->transportt); \ + tp = (struct spi_transport_attrs *)&sdev->transport_data; \ + if (i->f->get_##field) \ + i->f->get_##field(sdev); \ + return snprintf(buf, 20, format_string, tp->field); \ +} + +#define spi_transport_store_function(field, format_string) \ +static ssize_t \ +store_spi_transport_##field(struct class_device *cdev, const char *buf, \ + size_t count) \ +{ \ + int val; \ + struct scsi_device *sdev = transport_class_to_sdev(cdev); \ + struct spi_internal *i = to_spi_internal(sdev->host->transportt); \ + \ + val = simple_strtoul(buf, NULL, 0); \ + i->f->set_##field(sdev, val); \ + return count; \ +} + +#define spi_transport_rd_attr(field, format_string) \ + spi_transport_show_function(field, format_string) \ + spi_transport_store_function(field, format_string) \ +static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR, \ + show_spi_transport_##field, \ + store_spi_transport_##field) + +/* The Parallel SCSI Tranport Attributes: */ +spi_transport_rd_attr(offset, "%d\n"); +spi_transport_rd_attr(width, "%d\n"); +spi_transport_rd_attr(iu, "%d\n"); +spi_transport_rd_attr(dt, "%d\n"); +spi_transport_rd_attr(qas, "%d\n"); +spi_transport_rd_attr(wr_flow, "%d\n"); +spi_transport_rd_attr(rd_strm, "%d\n"); +spi_transport_rd_attr(rti, "%d\n"); +spi_transport_rd_attr(pcomp_en, "%d\n"); + +/* Translate the period into ns according to the current spec + * for SDTR/PPR messages */ +static ssize_t show_spi_transport_period(struct class_device *cdev, char *buf) + +{ + struct scsi_device *sdev = transport_class_to_sdev(cdev); + struct spi_transport_attrs *tp; + const char *str; + struct spi_internal *i = to_spi_internal(sdev->host->transportt); + + tp = (struct spi_transport_attrs *)&sdev->transport_data; + + if (i->f->get_period) + i->f->get_period(sdev); + + switch(tp->period) { + + case 0x07 ... SPI_STATIC_PPR: + str = ppr_to_ns[tp->period]; + if(!str) + str = "reserved"; + break; + + + case (SPI_STATIC_PPR+1) ... 0xff: + return sprintf(buf, "%d\n", tp->period * 4); + + default: + str = "unknown"; + } + return sprintf(buf, "%s\n", str); +} + +static ssize_t +store_spi_transport_period(struct class_device *cdev, const char *buf, + size_t count) +{ + struct scsi_device *sdev = transport_class_to_sdev(cdev); + struct spi_internal *i = to_spi_internal(sdev->host->transportt); + int j, period = -1; + + for (j = 0; j < SPI_STATIC_PPR; j++) { + int len; + + if(ppr_to_ns[j] == NULL) + continue; + + len = strlen(ppr_to_ns[j]); + + if(strncmp(ppr_to_ns[j], buf, len) != 0) + continue; + + if(buf[len] != '\n') + continue; + + period = j; + break; + } + + if (period == -1) { + int val = simple_strtoul(buf, NULL, 0); + + + /* Should probably check limits here, but this + * gets reasonably close to OK for most things */ + period = val/4; + } + + if (period > 0xff) + period = 0xff; + + i->f->set_period(sdev, period); + + return count; +} + +static CLASS_DEVICE_ATTR(period, S_IRUGO | S_IWUSR, + show_spi_transport_period, + store_spi_transport_period); + +#define DV_SET(x, y) \ + if(i->f->set_##x) \ + i->f->set_##x(sdev, y) + +#define DV_LOOPS 3 +#define DV_TIMEOUT (10*HZ) +#define DV_RETRIES 5 + + +/* This is for read/write Domain Validation: If the device supports + * an echo buffer, we do read/write tests to it */ +static int +spi_dv_device_echo_buffer(struct scsi_request *sreq, u8 *buffer, + u8 *ptr, const int retries) +{ + struct scsi_device *sdev = sreq->sr_device; + int len = ptr - buffer; + int j, k, r; + unsigned int pattern = 0x0000ffff; + + const char spi_write_buffer[] = { + WRITE_BUFFER, 0x0a, 0, 0, 0, 0, 0, len >> 8, len & 0xff, 0 + }; + const char spi_read_buffer[] = { + READ_BUFFER, 0x0a, 0, 0, 0, 0, 0, len >> 8, len & 0xff, 0 + }; + + /* set up the pattern buffer. Doesn't matter if we spill + * slightly beyond since that's where the read buffer is */ + for (j = 0; j < len; ) { + + /* fill the buffer with counting (test a) */ + for ( ; j < min(len, 32); j++) + buffer[j] = j; + k = j; + /* fill the buffer with alternating words of 0x0 and + * 0xffff (test b) */ + for ( ; j < min(len, k + 32); j += 2) { + u16 *word = (u16 *)&buffer[j]; + + *word = (j & 0x02) ? 0x0000 : 0xffff; + } + k = j; + /* fill with crosstalk (alternating 0x5555 0xaaa) + * (test c) */ + for ( ; j < min(len, k + 32); j += 2) { + u16 *word = (u16 *)&buffer[j]; + + *word = (j & 0x02) ? 0x5555 : 0xaaaa; + } + k = j; + /* fill with shifting bits (test d) */ + for ( ; j < min(len, k + 32); j += 4) { + u32 *word = (unsigned int *)&buffer[j]; + u32 roll = (pattern & 0x80000000) ? 1 : 0; + + *word = pattern; + pattern = (pattern << 1) | roll; + } + /* don't bother with random data (test e) */ + } + + for (r = 0; r < retries; r++) { + sreq->sr_cmd_len = 0; /* wait_req to fill in */ + sreq->sr_data_direction = DMA_TO_DEVICE; + scsi_wait_req(sreq, spi_write_buffer, buffer, len, + DV_TIMEOUT, DV_RETRIES); + if(sreq->sr_result) { + SPI_PRINTK(sdev, KERN_ERR, "Write Buffer failure %x\n", sreq->sr_result); + return 0; + } + + memset(ptr, 0, len); + sreq->sr_cmd_len = 0; /* wait_req to fill in */ + sreq->sr_data_direction = DMA_FROM_DEVICE; + scsi_wait_req(sreq, spi_read_buffer, ptr, len, + DV_TIMEOUT, DV_RETRIES); + + if (memcmp(buffer, ptr, len) != 0) + return 0; + } + return 1; +} + +/* This is for the simplest form of Domain Validation: a read test + * on the inquiry data from the device */ +static int +spi_dv_device_compare_inquiry(struct scsi_request *sreq, u8 *buffer, + u8 *ptr, const int retries) +{ + int r; + const int len = sreq->sr_device->inquiry_len; + const char spi_inquiry[] = { + INQUIRY, 0, 0, 0, len, 0 + }; + + for (r = 0; r < retries; r++) { + sreq->sr_cmd_len = 0; /* wait_req to fill in */ + sreq->sr_data_direction = DMA_FROM_DEVICE; + + memset(ptr, 0, len); + + scsi_wait_req(sreq, spi_inquiry, ptr, len, + DV_TIMEOUT, DV_RETRIES); + + /* If we don't have the inquiry data already, the + * first read gets it */ + if (ptr == buffer) { + ptr += len; + --r; + continue; + } + + if (memcmp(buffer, ptr, len) != 0) + /* failure */ + return 0; + } + return 1; +} + +static int +spi_dv_retrain(struct scsi_request *sreq, u8 *buffer, u8 *ptr, + int (*compare_fn)(struct scsi_request *, u8 *, u8 *, int)) +{ + struct spi_internal *i = to_spi_internal(sreq->sr_host->transportt); + struct scsi_device *sdev = sreq->sr_device; + int period, prevperiod = 0; + + + for (;;) { + if (compare_fn(sreq, buffer, ptr, DV_LOOPS)) + /* Successful DV */ + break; + + /* OK, retrain, fallback */ + if (i->f->get_period) + i->f->get_period(sdev); + period = spi_period(sdev); + if (period < 0x0d) + period++; + else + period += period >> 1; + + if (unlikely(period > 0xff || period == prevperiod)) { + /* Total failure; set to async and return */ + SPI_PRINTK(sdev, KERN_ERR, "Domain Validation Failure, dropping back to Asynchronous\n"); + DV_SET(offset, 0); + return 0; + } + SPI_PRINTK(sdev, KERN_ERR, "Domain Validation detected failure, dropping back\n"); + DV_SET(period, period); + prevperiod = period; + } + return 1; +} + +static int +spi_dv_device_get_echo_buffer(struct scsi_request *sreq, u8 *buffer) +{ + int l; + + /* first off do a test unit ready. This can error out + * because of reservations or some other reason. If it + * fails, the device won't let us write to the echo buffer + * so just return failure */ + + const char spi_test_unit_ready[] = { + TEST_UNIT_READY, 0, 0, 0, 0, 0 + }; + + const char spi_read_buffer_descriptor[] = { + READ_BUFFER, 0x0b, 0, 0, 0, 0, 0, 0, 4, 0 + }; + + + sreq->sr_cmd_len = 0; + sreq->sr_data_direction = DMA_NONE; + + /* We send a set of three TURs to clear any outstanding + * unit attention conditions if they exist (Otherwise the + * buffer tests won't be happy). If the TUR still fails + * (reservation conflict, device not ready, etc) just + * skip the write tests */ + for (l = 0; ; l++) { + scsi_wait_req(sreq, spi_test_unit_ready, NULL, 0, + DV_TIMEOUT, DV_RETRIES); + + if(sreq->sr_result) { + if(l >= 3) + return 0; + } else { + /* TUR succeeded */ + break; + } + } + + sreq->sr_cmd_len = 0; + sreq->sr_data_direction = DMA_FROM_DEVICE; + + scsi_wait_req(sreq, spi_read_buffer_descriptor, buffer, 4, + DV_TIMEOUT, DV_RETRIES); + + if (sreq->sr_result) + /* Device has no echo buffer */ + return 0; + + return buffer[3] + ((buffer[2] & 0x1f) << 8); +} + +static void +spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer) +{ + struct spi_internal *i = to_spi_internal(sreq->sr_host->transportt); + struct scsi_device *sdev = sreq->sr_device; + int len = sdev->inquiry_len; + /* first set us up for narrow async */ + DV_SET(offset, 0); + DV_SET(width, 0); + + if (!spi_dv_device_compare_inquiry(sreq, buffer, buffer, DV_LOOPS)) { + SPI_PRINTK(sdev, KERN_ERR, "Domain Validation Initial Inquiry Failed\n"); + /* FIXME: should probably offline the device here? */ + return; + } + + /* test width */ + if (i->f->set_width) { + i->f->set_width(sdev, 1); + + if (!spi_dv_device_compare_inquiry(sreq, buffer, + buffer + len, + DV_LOOPS)) { + SPI_PRINTK(sdev, KERN_ERR, "Wide Transfers Fail\n"); + i->f->set_width(sdev, 0); + } + } + + if (!i->f->set_period) + return; + + /* now set up to the maximum */ + DV_SET(offset, 255); + DV_SET(period, 1); + if (!spi_dv_retrain(sreq, buffer, buffer + len, + spi_dv_device_compare_inquiry)) + return; + + /* OK, now we have our initial speed set by the read only inquiry + * test, now try an echo buffer test (if the device allows it) */ + + if ((len = spi_dv_device_get_echo_buffer(sreq, buffer)) == 0) { + SPI_PRINTK(sdev, KERN_INFO, "Domain Validation skipping write tests\n"); + return; + } + if (len > SPI_MAX_ECHO_BUFFER_SIZE) { + SPI_PRINTK(sdev, KERN_WARNING, "Echo buffer size %d is too big, trimming to %d\n", len, SPI_MAX_ECHO_BUFFER_SIZE); + len = SPI_MAX_ECHO_BUFFER_SIZE; + } + + spi_dv_retrain(sreq, buffer, buffer + len, + spi_dv_device_echo_buffer); +} + + +/** spi_dv_device - Do Domain Validation on the device + * @sdev: scsi device to validate + * + * Performs the domain validation on the given device in the + * current execution thread. Since DV operations may sleep, + * the current thread must have user context. Also no SCSI + * related locks that would deadlock I/O issued by the DV may + * be held. + */ +void +spi_dv_device(struct scsi_device *sdev) +{ + struct scsi_request *sreq = scsi_allocate_request(sdev, GFP_KERNEL); + u8 *buffer; + const int len = SPI_MAX_ECHO_BUFFER_SIZE*2; + + if (unlikely(!sreq)) + return; + + if (unlikely(scsi_device_get(sdev))) + goto out_free_req; + + buffer = kmalloc(len, GFP_KERNEL); + + if (unlikely(!buffer)) + goto out_put; + + memset(buffer, 0, len); + + if (unlikely(scsi_device_quiesce(sdev))) + goto out_free; + + SPI_PRINTK(sdev, KERN_INFO, "Beginning Domain Validation\n"); + + spi_dv_device_internal(sreq, buffer); + + SPI_PRINTK(sdev, KERN_INFO, "Ending Domain Validation\n"); + + scsi_device_resume(sdev); + + out_free: + kfree(buffer); + out_put: + scsi_device_put(sdev); + out_free_req: + scsi_release_request(sreq); +} +EXPORT_SYMBOL(spi_dv_device); + +struct work_queue_wrapper { + struct work_struct work; + struct scsi_device *sdev; +}; + +static void +spi_dv_device_work_wrapper(void *data) +{ + struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data; + struct scsi_device *sdev = wqw->sdev; + + kfree(wqw); + spi_dv_device(sdev); + spi_dv_pending(sdev) = 0; + scsi_device_put(sdev); +} + + +/** + * spi_schedule_dv_device - schedule domain validation to occur on the device + * @sdev: The device to validate + * + * Identical to spi_dv_device() above, except that the DV will be + * scheduled to occur in a workqueue later. All memory allocations + * are atomic, so may be called from any context including those holding + * SCSI locks. + */ +void +spi_schedule_dv_device(struct scsi_device *sdev) +{ + struct work_queue_wrapper *wqw = + kmalloc(sizeof(struct work_queue_wrapper), GFP_ATOMIC); + + if (unlikely(!wqw)) + return; + + if (unlikely(spi_dv_pending(sdev))) { + kfree(wqw); + return; + } + + if (unlikely(scsi_device_get(sdev))) { + kfree(wqw); + spi_dv_pending(sdev) = 0; + return; + } + + INIT_WORK(&wqw->work, spi_dv_device_work_wrapper, wqw); + wqw->sdev = sdev; + + schedule_work(&wqw->work); +} +EXPORT_SYMBOL(spi_schedule_dv_device); + +#define SETUP_ATTRIBUTE(field) \ + i->private_attrs[count] = class_device_attr_##field; \ + if (!i->f->set_##field) { \ + i->private_attrs[count].attr.mode = S_IRUGO; \ + i->private_attrs[count].store = NULL; \ + } \ + i->attrs[count] = &i->private_attrs[count]; \ + if (i->f->show_##field) \ + count++ + +struct scsi_transport_template * +spi_attach_transport(struct spi_function_template *ft) +{ + struct spi_internal *i = kmalloc(sizeof(struct spi_internal), + GFP_KERNEL); + int count = 0; + if (unlikely(!i)) + return NULL; + + memset(i, 0, sizeof(struct spi_internal)); + + + i->t.attrs = &i->attrs[0]; + i->t.class = &spi_transport_class; + i->t.setup = &spi_setup_transport_attrs; + i->t.size = sizeof(struct spi_transport_attrs) - sizeof(unsigned long); + i->f = ft; + + SETUP_ATTRIBUTE(period); + SETUP_ATTRIBUTE(offset); + SETUP_ATTRIBUTE(width); + SETUP_ATTRIBUTE(iu); + SETUP_ATTRIBUTE(dt); + SETUP_ATTRIBUTE(qas); + SETUP_ATTRIBUTE(wr_flow); + SETUP_ATTRIBUTE(rd_strm); + SETUP_ATTRIBUTE(rti); + SETUP_ATTRIBUTE(pcomp_en); + + /* if you add an attribute but forget to increase SPI_NUM_ATTRS + * this bug will trigger */ + BUG_ON(count > SPI_NUM_ATTRS); + + i->attrs[count] = NULL; + + return &i->t; +} +EXPORT_SYMBOL(spi_attach_transport); + +void spi_release_transport(struct scsi_transport_template *t) +{ + struct spi_internal *i = to_spi_internal(t); + + kfree(i); +} +EXPORT_SYMBOL(spi_release_transport); + + +MODULE_AUTHOR("Martin Hicks"); +MODULE_DESCRIPTION("SPI Transport Attributes"); +MODULE_LICENSE("GPL"); + +module_init(spi_transport_init); +module_exit(spi_transport_exit); diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c --- a/drivers/scsi/sd.c Sun Mar 14 14:20:08 2004 +++ b/drivers/scsi/sd.c Sun Mar 14 14:20:08 2004 @@ -19,6 +19,9 @@ * not being read in sd_open. Fix problem where removable media * could be ejected after sd_open. * - Douglas Gilbert cleanup for lk 2.5.x + * - Badari Pulavarty , Matthew Wilcox + * , Kurt Garloff : + * Support 32k/1M disks. * * Logging policy (needs CONFIG_SCSI_LOGGING defined): * - setting up transfer: SCSI_LOG_HLQUEUE levels 1 and 2 @@ -61,7 +64,7 @@ * Remaining dev_t-handling stuff */ #define SD_MAJORS 16 -#define SD_DISKS (SD_MAJORS << 4) +#define SD_DISKS 32768 /* anything between 256 and 262144 */ /* * Time out in seconds for disks and Magneto-opticals (which are slower). @@ -121,6 +124,20 @@ .init_command = sd_init_command, }; +/* Device no to disk mapping: + * + * major disc2 disc p1 + * |............|.............|....|....| <- dev_t + * 31 20 19 8 7 4 3 0 + * + * Inside a major, we have 16k disks, however mapped non- + * contiguously. The first 16 disks are for major0, the next + * ones with major1, ... Disk 256 is for major0 again, disk 272 + * for major1, ... + * As we stay compatible with our numbering scheme, we can reuse + * the well-know SCSI majors 8, 65--71, 136--143. + */ + static int sd_major(int major_idx) { switch (major_idx) { @@ -136,6 +153,14 @@ } } +static unsigned int make_sd_dev(unsigned int sd_nr, unsigned int part) +{ + return (part & 0xf) | ((sd_nr & 0xf) << 4) | + (sd_major((sd_nr & 0xf0) >> 4) << 20) | (sd_nr & 0xfff00); +} + +/* reverse mapping dev -> (sd_nr, part) not currently needed */ + #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,kobj); static inline struct scsi_disk *scsi_disk(struct gendisk *disk) @@ -1301,7 +1326,7 @@ struct scsi_disk *sdkp; struct gendisk *gd; u32 index; - int error; + int error, devno; error = -ENODEV; if ((sdp->type != TYPE_DISK) && (sdp->type != TYPE_MOD)) @@ -1319,6 +1344,12 @@ kobject_init(&sdkp->kobj); sdkp->kobj.ktype = &scsi_disk_kobj_type; + /* Note: We can accomodate 64 partitions, but the genhd code + * assumes partitions allocate consecutive minors, which they don't. + * So for now stay with max 16 partitions and leave two spare bits. + * Later, we may change the genhd code and the alloc_disk() call + * and the ->minors assignment here. KG, 2004-02-10 + */ gd = alloc_disk(16); if (!gd) goto out_free; @@ -1339,16 +1370,23 @@ sdkp->index = index; sdkp->openers = 0; - gd->major = sd_major(index >> 4); - gd->first_minor = (index & 15) << 4; + devno = make_sd_dev(index, 0); + gd->major = MAJOR(devno); + gd->first_minor = MINOR(devno); gd->minors = 16; gd->fops = &sd_fops; - if (index >= 26) { + if (index < 26) { + sprintf(gd->disk_name, "sd%c", 'a' + index % 26); + } else if (index < (26*27)) { sprintf(gd->disk_name, "sd%c%c", - 'a' + index/26-1,'a' + index % 26); + 'a' + index / 26 - 1,'a' + index % 26); } else { - sprintf(gd->disk_name, "sd%c", 'a' + index % 26); + const unsigned int m1 = (index / 26 - 1) / 26 - 1; + const unsigned int m2 = (index / 26 - 1) % 26; + const unsigned int m3 = index % 26; + sprintf(gd->disk_name, "sd%c%c%c", + 'a' + m1, 'a' + m2, 'a' + m3); } strcpy(gd->devfs_name, sdp->devfs_name); diff -Nru a/drivers/scsi/sr.c b/drivers/scsi/sr.c --- a/drivers/scsi/sr.c Sun Mar 14 14:20:06 2004 +++ b/drivers/scsi/sr.c Sun Mar 14 14:20:06 2004 @@ -566,10 +566,13 @@ snprintf(disk->devfs_name, sizeof(disk->devfs_name), "%s/cd", sdev->devfs_name); disk->driverfs_dev = &sdev->sdev_gendev; - register_cdrom(&cd->cdi); set_capacity(disk, cd->capacity); disk->private_data = &cd->driver; disk->queue = sdev->request_queue; + cd->cdi.disk = disk; + + if (register_cdrom(&cd->cdi)) + goto fail_put; dev_set_drvdata(dev, cd); add_disk(disk); diff -Nru a/drivers/scsi/st.c b/drivers/scsi/st.c --- a/drivers/scsi/st.c Sun Mar 14 14:20:07 2004 +++ b/drivers/scsi/st.c Sun Mar 14 14:20:07 2004 @@ -17,7 +17,7 @@ Last modified: 18-JAN-1998 Richard Gooch Devfs support */ -static char *verstr = "20040213"; +static char *verstr = "20040226"; #include @@ -121,7 +121,15 @@ }; #endif -static char *st_formats[ST_NBR_MODES] ={"", "l", "m", "a"}; +/* Restrict the number of modes so that names for all are assigned */ +#if ST_NBR_MODES > 16 +#error "Maximum number of modes is 16" +#endif +/* Bit reversed order to get same names for same minors with all + mode counts */ +static char *st_formats[] = { + "", "r", "k", "s", "l", "t", "o", "u", + "m", "v", "p", "x", "a", "y", "q", "z"}; /* The default definitions have been moved to st_options.h */ @@ -3888,8 +3896,11 @@ dev_num); goto out_free_tape; } - snprintf(cdev->kobj.name, KOBJ_NAME_LEN, "%sm%d%s", disk->disk_name, - mode, j ? "n" : ""); + /* Make sure that the minor numbers corresponding to the four + first modes always get the same names */ + i = mode << (4 - ST_NBR_MODE_BITS); + snprintf(cdev->kobj.name, KOBJ_NAME_LEN, "%s%s%s", j ? "n" : "", + disk->disk_name, st_formats[i]); cdev->owner = THIS_MODULE; cdev->ops = &st_fops; @@ -3909,22 +3920,26 @@ } for (mode = 0; mode < ST_NBR_MODES; ++mode) { + /* Make sure that the minor numbers corresponding to the four + first modes always get the same names */ + i = mode << (4 - ST_NBR_MODE_BITS); /* Rewind entry */ - devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, dev_num + (mode << 5)), + devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, 0)), S_IFCHR | S_IRUGO | S_IWUGO, - "%s/mt%s", SDp->devfs_name, st_formats[mode]); + "%s/mt%s", SDp->devfs_name, st_formats[i]); /* No-rewind entry */ - devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, dev_num + (mode << 5) + 128), + devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, 1)), S_IFCHR | S_IRUGO | S_IWUGO, - "%s/mt%sn", SDp->devfs_name, st_formats[mode]); + "%s/mt%sn", SDp->devfs_name, st_formats[i]); } disk->number = devfs_register_tape(SDp->devfs_name); printk(KERN_WARNING "Attached scsi tape %s at scsi%d, channel %d, id %d, lun %d\n", tape_name(tpnt), SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); - printk(KERN_WARNING "%s: try direct i/o: %s, max page reachable by HBA %lu\n", - tape_name(tpnt), tpnt->try_dio ? "yes" : "no", tpnt->max_pfn); + printk(KERN_WARNING "%s: try direct i/o: %s (alignment %d B), max page reachable by HBA %lu\n", + tape_name(tpnt), tpnt->try_dio ? "yes" : "no", + queue_dma_alignment(SDp->request_queue) + 1, tpnt->max_pfn); return 0; @@ -3977,8 +3992,9 @@ sysfs_remove_link(&tpnt->device->sdev_gendev.kobj, "tape"); for (mode = 0; mode < ST_NBR_MODES; ++mode) { - devfs_remove("%s/mt%s", SDp->devfs_name, st_formats[mode]); - devfs_remove("%s/mt%sn", SDp->devfs_name, st_formats[mode]); + j = mode << (4 - ST_NBR_MODE_BITS); + devfs_remove("%s/mt%s", SDp->devfs_name, st_formats[j]); + devfs_remove("%s/mt%sn", SDp->devfs_name, st_formats[j]); for (j=0; j < 2; j++) { class_simple_device_remove(MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(i, mode, j))); diff -Nru a/drivers/scsi/st.h b/drivers/scsi/st.h --- a/drivers/scsi/st.h Sun Mar 14 14:20:08 2004 +++ b/drivers/scsi/st.h Sun Mar 14 14:20:08 2004 @@ -50,6 +50,8 @@ struct cdev *cdevs[2]; /* Auto-rewind and non-rewind devices */ } ST_mode; +/* Number of modes can be changed by changing ST_NBR_MODE_BITS. The maximum + number of modes is 16 (ST_NBR_MODE_BITS 4) */ #define ST_NBR_MODE_BITS 2 #define ST_NBR_MODES (1 << ST_NBR_MODE_BITS) #define ST_MODE_SHIFT (7 - ST_NBR_MODE_BITS) diff -Nru a/drivers/scsi/sym53c8xx_2/sym53c8xx.h b/drivers/scsi/sym53c8xx_2/sym53c8xx.h --- a/drivers/scsi/sym53c8xx_2/sym53c8xx.h Sun Mar 14 14:20:08 2004 +++ b/drivers/scsi/sym53c8xx_2/sym53c8xx.h Sun Mar 14 14:20:08 2004 @@ -70,13 +70,6 @@ #define SYM_CONF_DMA_ADDRESSING_MODE CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE /* - * NCR PQS/PDS special device support. - */ -#if 1 -#define SYM_CONF_PQS_PDS_SUPPORT -#endif - -/* * NVRAM support. */ #if 1 diff -Nru a/drivers/scsi/sym53c8xx_2/sym_defs.h b/drivers/scsi/sym53c8xx_2/sym_defs.h --- a/drivers/scsi/sym53c8xx_2/sym_defs.h Sun Mar 14 14:20:07 2004 +++ b/drivers/scsi/sym53c8xx_2/sym_defs.h Sun Mar 14 14:20:07 2004 @@ -127,135 +127,6 @@ }; /* - * Symbios NVRAM data format - */ -#define SYMBIOS_NVRAM_SIZE 368 -#define SYMBIOS_NVRAM_ADDRESS 0x100 - -struct Symbios_nvram { -/* Header 6 bytes */ - u_short type; /* 0x0000 */ - u_short byte_count; /* excluding header/trailer */ - u_short checksum; - -/* Controller set up 20 bytes */ - u_char v_major; /* 0x00 */ - u_char v_minor; /* 0x30 */ - u32 boot_crc; - u_short flags; -#define SYMBIOS_SCAM_ENABLE (1) -#define SYMBIOS_PARITY_ENABLE (1<<1) -#define SYMBIOS_VERBOSE_MSGS (1<<2) -#define SYMBIOS_CHS_MAPPING (1<<3) -#define SYMBIOS_NO_NVRAM (1<<3) /* ??? */ - u_short flags1; -#define SYMBIOS_SCAN_HI_LO (1) - u_short term_state; -#define SYMBIOS_TERM_CANT_PROGRAM (0) -#define SYMBIOS_TERM_ENABLED (1) -#define SYMBIOS_TERM_DISABLED (2) - u_short rmvbl_flags; -#define SYMBIOS_RMVBL_NO_SUPPORT (0) -#define SYMBIOS_RMVBL_BOOT_DEVICE (1) -#define SYMBIOS_RMVBL_MEDIA_INSTALLED (2) - u_char host_id; - u_char num_hba; /* 0x04 */ - u_char num_devices; /* 0x10 */ - u_char max_scam_devices; /* 0x04 */ - u_char num_valid_scam_devices; /* 0x00 */ - u_char flags2; -#define SYMBIOS_AVOID_BUS_RESET (1<<2) - -/* Boot order 14 bytes * 4 */ - struct Symbios_host{ - u_short type; /* 4:8xx / 0:nok */ - u_short device_id; /* PCI device id */ - u_short vendor_id; /* PCI vendor id */ - u_char bus_nr; /* PCI bus number */ - u_char device_fn; /* PCI device/function number << 3*/ - u_short word8; - u_short flags; -#define SYMBIOS_INIT_SCAN_AT_BOOT (1) - u_short io_port; /* PCI io_port address */ - } host[4]; - -/* Targets 8 bytes * 16 */ - struct Symbios_target { - u_char flags; -#define SYMBIOS_DISCONNECT_ENABLE (1) -#define SYMBIOS_SCAN_AT_BOOT_TIME (1<<1) -#define SYMBIOS_SCAN_LUNS (1<<2) -#define SYMBIOS_QUEUE_TAGS_ENABLED (1<<3) - u_char rsvd; - u_char bus_width; /* 0x08/0x10 */ - u_char sync_offset; - u_short sync_period; /* 4*period factor */ - u_short timeout; - } target[16]; -/* Scam table 8 bytes * 4 */ - struct Symbios_scam { - u_short id; - u_short method; -#define SYMBIOS_SCAM_DEFAULT_METHOD (0) -#define SYMBIOS_SCAM_DONT_ASSIGN (1) -#define SYMBIOS_SCAM_SET_SPECIFIC_ID (2) -#define SYMBIOS_SCAM_USE_ORDER_GIVEN (3) - u_short status; -#define SYMBIOS_SCAM_UNKNOWN (0) -#define SYMBIOS_SCAM_DEVICE_NOT_FOUND (1) -#define SYMBIOS_SCAM_ID_NOT_SET (2) -#define SYMBIOS_SCAM_ID_VALID (3) - u_char target_id; - u_char rsvd; - } scam[4]; - - u_char spare_devices[15*8]; - u_char trailer[6]; /* 0xfe 0xfe 0x00 0x00 0x00 0x00 */ -}; -typedef struct Symbios_nvram Symbios_nvram; -typedef struct Symbios_host Symbios_host; -typedef struct Symbios_target Symbios_target; -typedef struct Symbios_scam Symbios_scam; - -/* - * Tekram NvRAM data format. - */ -#define TEKRAM_NVRAM_SIZE 64 -#define TEKRAM_93C46_NVRAM_ADDRESS 0 -#define TEKRAM_24C16_NVRAM_ADDRESS 0x40 - -struct Tekram_nvram { - struct Tekram_target { - u_char flags; -#define TEKRAM_PARITY_CHECK (1) -#define TEKRAM_SYNC_NEGO (1<<1) -#define TEKRAM_DISCONNECT_ENABLE (1<<2) -#define TEKRAM_START_CMD (1<<3) -#define TEKRAM_TAGGED_COMMANDS (1<<4) -#define TEKRAM_WIDE_NEGO (1<<5) - u_char sync_index; - u_short word2; - } target[16]; - u_char host_id; - u_char flags; -#define TEKRAM_MORE_THAN_2_DRIVES (1) -#define TEKRAM_DRIVES_SUP_1GB (1<<1) -#define TEKRAM_RESET_ON_POWER_ON (1<<2) -#define TEKRAM_ACTIVE_NEGATION (1<<3) -#define TEKRAM_IMMEDIATE_SEEK (1<<4) -#define TEKRAM_SCAN_LUNS (1<<5) -#define TEKRAM_REMOVABLE_FLAGS (3<<6) /* 0: disable; */ - /* 1: boot device; 2:all */ - u_char boot_delay_index; - u_char max_tags_index; - u_short flags1; -#define TEKRAM_F2_F6_ENABLED (1) - u_short spare[29]; -}; -typedef struct Tekram_nvram Tekram_nvram; -typedef struct Tekram_target Tekram_target; - -/* * SYM53C8XX IO register data structure. */ struct sym_reg { diff -Nru a/drivers/scsi/sym53c8xx_2/sym_fw.c b/drivers/scsi/sym53c8xx_2/sym_fw.c --- a/drivers/scsi/sym53c8xx_2/sym_fw.c Sun Mar 14 14:20:08 2004 +++ b/drivers/scsi/sym53c8xx_2/sym_fw.c Sun Mar 14 14:20:08 2004 @@ -135,7 +135,7 @@ * Patch routine for firmware #1. */ static void -sym_fw1_patch(hcb_p np) +sym_fw1_patch(struct sym_hcb *np) { struct sym_fw1a_scr *scripta0; struct sym_fw1b_scr *scriptb0; @@ -176,7 +176,7 @@ * Patch routine for firmware #2. */ static void -sym_fw2_patch(hcb_p np) +sym_fw2_patch(struct sym_hcb *np) { struct sym_fw2a_scr *scripta0; struct sym_fw2b_scr *scriptb0; @@ -282,7 +282,7 @@ * To be done for all firmwares. */ static void -sym_fw_setup_bus_addresses(hcb_p np, struct sym_fw *fw) +sym_fw_setup_bus_addresses(struct sym_hcb *np, struct sym_fw *fw) { u32 *pa; u_short *po; @@ -319,7 +319,7 @@ * Setup routine for firmware #1. */ static void -sym_fw1_setup(hcb_p np, struct sym_fw *fw) +sym_fw1_setup(struct sym_hcb *np, struct sym_fw *fw) { struct sym_fw1a_scr *scripta0; struct sym_fw1b_scr *scriptb0; @@ -343,7 +343,7 @@ * Setup routine for firmware #2. */ static void -sym_fw2_setup(hcb_p np, struct sym_fw *fw) +sym_fw2_setup(struct sym_hcb *np, struct sym_fw *fw) { struct sym_fw2a_scr *scripta0; struct sym_fw2b_scr *scriptb0; @@ -389,7 +389,7 @@ /* * Bind a script to physical addresses. */ -void sym_fw_bind_script (hcb_p np, u32 *start, int len) +void sym_fw_bind_script(struct sym_hcb *np, u32 *start, int len) { u32 opcode, new, old, tmp1, tmp2; u32 *end, *cur; diff -Nru a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c --- a/drivers/scsi/sym53c8xx_2/sym_glue.c Sun Mar 14 14:20:09 2004 +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c Sun Mar 14 14:20:09 2004 @@ -57,7 +57,9 @@ #include #include #include + #include "sym_glue.h" +#include "sym_nvram.h" #define NAME53C "sym53c" #define NAME53C8XX "sym53c8xx" @@ -212,17 +214,32 @@ return use_sg; } -static void __sync_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd) +static void __sync_scsi_data_for_cpu(struct pci_dev *pdev, struct scsi_cmnd *cmd) { int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); switch(SYM_UCMD_PTR(cmd)->data_mapped) { case 2: - pci_dma_sync_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir); + pci_dma_sync_sg_for_cpu(pdev, cmd->buffer, cmd->use_sg, dma_dir); break; case 1: - pci_dma_sync_single(pdev, SYM_UCMD_PTR(cmd)->data_mapping, - cmd->request_bufflen, dma_dir); + pci_dma_sync_single_for_cpu(pdev, SYM_UCMD_PTR(cmd)->data_mapping, + cmd->request_bufflen, dma_dir); + break; + } +} + +static void __sync_scsi_data_for_device(struct pci_dev *pdev, struct scsi_cmnd *cmd) +{ + int dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction); + + switch(SYM_UCMD_PTR(cmd)->data_mapped) { + case 2: + pci_dma_sync_sg_for_device(pdev, cmd->buffer, cmd->use_sg, dma_dir); + break; + case 1: + pci_dma_sync_single_for_device(pdev, SYM_UCMD_PTR(cmd)->data_mapping, + cmd->request_bufflen, dma_dir); break; } } @@ -233,8 +250,10 @@ __map_scsi_single_data(np->s.device, cmd) #define map_scsi_sg_data(np, cmd) \ __map_scsi_sg_data(np->s.device, cmd) -#define sync_scsi_data(np, cmd) \ - __sync_scsi_data(np->s.device, cmd) +#define sync_scsi_data_for_cpu(np, cmd) \ + __sync_scsi_data_for_cpu(np->s.device, cmd) +#define sync_scsi_data_for_device(np, cmd) \ + __sync_scsi_data_for_device(np->s.device, cmd) /* * Complete a pending CAM CCB. @@ -394,10 +413,11 @@ if (!cmd || cmd->use_sg) return; - sync_scsi_data(np, cmd); + sync_scsi_data_for_cpu(np, cmd); retv = __sym_sniff_inquiry(np, cmd->device->id, cmd->device->lun, (u_char *) cmd->request_buffer, cmd->request_bufflen - resid); + sync_scsi_data_for_device(np, cmd); if (retv < 0) return; else if (retv) @@ -532,7 +552,7 @@ /* * Setup buffers and pointers that address the CDB. */ -static int __inline sym_setup_cdb(struct sym_hcb *np, struct scsi_cmnd *ccb, struct sym_ccb *cp) +static inline int sym_setup_cdb(struct sym_hcb *np, struct scsi_cmnd *ccb, struct sym_ccb *cp) { u32 cmd_ba; int cmd_len; @@ -1281,7 +1301,7 @@ { int verb_len = strlen(verb); - if (len >= strlen(verb) && !memcmp(verb, ptr, verb_len)) + if (len >= verb_len && !memcmp(verb, ptr, verb_len)) return verb_len; else return 0; @@ -1938,7 +1958,7 @@ char *cur = str; char *pc, *pv; unsigned long val; - int i, c; + unsigned int i, c; int xi = 0; while (cur != NULL && (pc = strchr(cur, ':')) != NULL) { @@ -2171,6 +2191,55 @@ return 0; } +/* + * The NCR PQS and PDS cards are constructed as a DEC bridge + * behind which sits a proprietary NCR memory controller and + * either four or two 53c875s as separate devices. We can tell + * if an 875 is part of a PQS/PDS or not since if it is, it will + * be on the same bus as the memory controller. In its usual + * mode of operation, the 875s are slaved to the memory + * controller for all transfers. To operate with the Linux + * driver, the memory controller is disabled and the 875s + * freed to function independently. The only wrinkle is that + * the preset SCSI ID (which may be zero) must be read in from + * a special configuration space register of the 875. + */ +void sym_config_pqs(struct pci_dev *pdev, struct sym_device *sym_dev) +{ + int slot; + + for (slot = 0; slot < 256; slot++) { + u8 tmp; + struct pci_dev *memc = pci_get_slot(pdev->bus, slot); + + if (!memc || memc->vendor != 0x101a || memc->device == 0x0009) { + pci_dev_put(memc); + continue; + } + + /* + * We set these bits in the memory controller once per 875. + * This isn't a problem in practice. + */ + + /* bit 1: allow individual 875 configuration */ + pci_read_config_byte(memc, 0x44, &tmp); + tmp |= 0x2; + pci_write_config_byte(memc, 0x44, tmp); + + /* bit 2: drive individual 875 interrupts to the bus */ + pci_read_config_byte(memc, 0x45, &tmp); + tmp |= 0x4; + pci_write_config_byte(memc, 0x45, tmp); + + pci_read_config_byte(pdev, 0x84, &tmp); + sym_dev->host_id = tmp; + + pci_dev_put(memc); + + break; + } +} /* * Called before unloading the module. @@ -2221,79 +2290,6 @@ #endif }; -#ifdef _SYM_CONF_PQS_PDS_SUPPORT -#if 0 -/* - * Detect all NCR PQS/PDS boards and keep track of their bus nr. - * - * The NCR PQS or PDS card is constructed as a DEC bridge - * behind which sit a proprietary NCR memory controller and - * four or two 53c875s as separate devices. In its usual mode - * of operation, the 875s are slaved to the memory controller - * for all transfers. We can tell if an 875 is part of a - * PQS/PDS or not since if it is, it will be on the same bus - * as the memory controller. To operate with the Linux - * driver, the memory controller is disabled and the 875s - * freed to function independently. The only wrinkle is that - * the preset SCSI ID (which may be zero) must be read in from - * a special configuration space register of the 875 - */ -#ifndef SYM_CONF_MAX_PQS_BUS -#define SYM_CONF_MAX_PQS_BUS 16 -#endif -static int pqs_bus[SYM_CONF_MAX_PQS_BUS] __initdata = { 0 }; - -static void __init sym_detect_pqs_pds(void) -{ - short index; - struct pci_dev *dev = NULL; - - for(index=0; index < SYM_CONF_MAX_PQS_BUS; index++) { - u_char tmp; - - dev = pci_find_device(0x101a, 0x0009, dev); - if (dev == NULL) { - pqs_bus[index] = -1; - break; - } - printf_info(NAME53C8XX ": NCR PQS/PDS memory controller detected on bus %d\n", dev->bus->number); - pci_read_config_byte(dev, 0x44, &tmp); - /* bit 1: allow individual 875 configuration */ - tmp |= 0x2; - pci_write_config_byte(dev, 0x44, tmp); - pci_read_config_byte(dev, 0x45, &tmp); - /* bit 2: drive individual 875 interrupts to the bus */ - tmp |= 0x4; - pci_write_config_byte(dev, 0x45, tmp); - - pqs_bus[index] = dev->bus->number; - } -} -#endif - -static int pqs_probe() -{ -} - -static void pqs_remove() -{ -} - -static struct pci_device_id pqs_id_table[] __devinitdata = { - { 0x101a, 0x0009, }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, pqs_id_table); - -static struct pci_driver pqs_driver = { - .name = NAME53C8XX " (PQS)", - .id_table = pqs_id_table, - .probe = pqs_probe, - .remove = __devexit_p(pqs_remove), -}; -#endif /* PQS */ - static int attach_count; static int __devinit sym2_probe(struct pci_dev *pdev, @@ -2318,6 +2314,8 @@ if (sym53c8xx_pci_init(pdev, &sym_dev)) goto free; + sym_config_pqs(pdev, &sym_dev); + sym_get_nvram(&sym_dev, &nvram); instance = sym_attach(&sym2_template, attach_count, &sym_dev); @@ -2406,9 +2404,6 @@ static int __init sym2_init(void) { -#ifdef _SYM_CONF_PQS_PDS_SUPPORT - pci_register_driver(&pqs_driver); -#endif pci_register_driver(&sym2_driver); return 0; } @@ -2416,9 +2411,6 @@ static void __exit sym2_exit(void) { pci_unregister_driver(&sym2_driver); -#ifdef _SYM_CONF_PQS_PDS_SUPPORT - pci_unregister_driver(&pqs_driver); -#endif } module_init(sym2_init); diff -Nru a/drivers/scsi/sym53c8xx_2/sym_glue.h b/drivers/scsi/sym53c8xx_2/sym_glue.h --- a/drivers/scsi/sym53c8xx_2/sym_glue.h Sun Mar 14 14:20:08 2004 +++ b/drivers/scsi/sym53c8xx_2/sym_glue.h Sun Mar 14 14:20:08 2004 @@ -77,9 +77,9 @@ /* * General driver includes. */ -#include "sym_misc.h" #include "sym_conf.h" #include "sym_defs.h" +#include "sym_misc.h" /* * Configuration addendum for Linux. @@ -113,6 +113,26 @@ #define sym_mdelay(ms) mdelay(ms) /* + * A 'read barrier' flushes any data that have been prefetched + * by the processor due to out of order execution. Such a barrier + * must notably be inserted prior to looking at data that have + * been DMAed, assuming that program does memory READs in proper + * order and that the device ensured proper ordering of WRITEs. + * + * A 'write barrier' prevents any previous WRITEs to pass further + * WRITEs. Such barriers must be inserted each time another agent + * relies on ordering of WRITEs. + * + * Note that, due to posting of PCI memory writes, we also must + * insert dummy PCI read transactions when some ordering involving + * both directions over the PCI does matter. PCI transactions are + * fully ordered in each direction. + */ + +#define MEMORY_READ_BARRIER() rmb() +#define MEMORY_WRITE_BARRIER() wmb() + +/* * Let the compiler know about driver data structure names. */ typedef struct sym_tcb *tcb_p; @@ -413,6 +433,8 @@ char inst_name[16]; }; +struct sym_nvram; + struct sym_device { struct pci_dev *pdev; struct sym_slot s; @@ -420,12 +442,7 @@ struct sym_nvram *nvram; u_short device_id; u_char host_id; -#ifdef SYM_CONF_PQS_PDS_SUPPORT - u_char pqs_pds; -#endif }; - -typedef struct sym_device *sdev_p; /* * The driver definitions (sym_hipd.h) must know about a diff -Nru a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c Sun Mar 14 14:20:05 2004 +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c Sun Mar 14 14:20:05 2004 @@ -50,13 +50,10 @@ * SUCH DAMAGE. */ -#define SYM_DRIVER_NAME "sym-2.1.18f" +#define SYM_DRIVER_NAME "sym-2.1.18i" -#ifdef __FreeBSD__ -#include -#else #include "sym_glue.h" -#endif +#include "sym_nvram.h" #if 0 #define SYM_DEBUG_GENERIC_SUPPORT @@ -616,8 +613,7 @@ if (dt) { fak = (kpc - 1) / (div_10M[div] << 1) + 1 - 2; /* ret = ((2+fak)*div_10M[div])/np->clock_khz; */ - } - else { + } else { fak = (kpc - 1) / div_10M[div] + 1 - 4; /* ret = ((4+fak)*div_10M[div])/np->clock_khz; */ } @@ -625,8 +621,10 @@ /* * Check against our hardware limits, or bugs :). */ - if (fak < 0) {fak = 0; ret = -1;} - if (fak > 2) {fak = 2; ret = -1;} + if (fak > 2) { + fak = 2; + ret = -1; + } /* * Compute and return sync parameters. @@ -1054,8 +1052,9 @@ sym_nvram_setup_target (np, i, nvram); /* - * For now, guess PPR/DT support from the period - * and BUS width. + * Some single-ended devices may crash on receiving a + * PPR negotiation attempt. Only try PPR if we're in + * LVD mode. */ if (np->features & FE_ULTRA3) { tp->tinfo.user.options |= PPR_OPT_DT; diff -Nru a/drivers/scsi/sym53c8xx_2/sym_hipd.h b/drivers/scsi/sym53c8xx_2/sym_hipd.h --- a/drivers/scsi/sym53c8xx_2/sym_hipd.h Sun Mar 14 14:20:07 2004 +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.h Sun Mar 14 14:20:07 2004 @@ -171,6 +171,15 @@ #define SYM_CONF_MIN_ASYNC (40) /* + * Shortest memory chunk is (1<hcb_ba + offsetof(struct sym_hcb, lbl)) -/* - * NVRAM reading (sym_nvram.c). - */ -#if SYM_CONF_NVRAM_SUPPORT -void sym_nvram_setup_host (hcb_p np, struct sym_nvram *nvram); -void sym_nvram_setup_target (hcb_p np, int target, struct sym_nvram *nvp); -int sym_read_nvram (sdev_p np, struct sym_nvram *nvp); -#else -static inline void sym_nvram_setup_host(hcb_p np, struct sym_nvram *nvram) { } -static inline void sym_nvram_setup_target(hcb_p np, struct sym_nvram *nvram) { } -static inline int sym_read_nvram(sdev_p np, struct sym_nvram *nvp) -{ - nvp->type = 0; - return 0; -} -#endif - /* * FIRMWARES (sym_fw.c) @@ -1257,8 +1234,8 @@ * Set up data pointers used by SCRIPTS. * Called from O/S specific code. */ -static void __inline -sym_setup_data_pointers(hcb_p np, ccb_p cp, int dir) +static inline void sym_setup_data_pointers(struct sym_hcb *np, + struct sym_ccb *cp, int dir) { u32 lastp, goalp; @@ -1321,15 +1298,6 @@ /* * MEMORY ALLOCATOR. */ - -/* - * Shortest memory chunk is (1<inq_byte56; if (inq_version >= 4 && inq_len > 56) - tp->inq_byte56 = inq_data[56]; + inq_byte56 = inq_data[56]; #if 0 printf("XXXXXX [%d] inq_version=%x inq_byte7=%x inq_byte56=%x XXXXX\n", inq_len, inq_version, inq_byte7, inq_byte56); @@ -328,6 +328,7 @@ tp->inq_byte56 != inq_byte56) { tp->inq_version = inq_version; tp->inq_byte7 = inq_byte7; + tp->inq_byte56 = inq_byte56; return 1; } return 0; diff -Nru a/drivers/scsi/sym53c8xx_2/sym_misc.h b/drivers/scsi/sym53c8xx_2/sym_misc.h --- a/drivers/scsi/sym53c8xx_2/sym_misc.h Sun Mar 14 14:20:08 2004 +++ b/drivers/scsi/sym53c8xx_2/sym_misc.h Sun Mar 14 14:20:08 2004 @@ -54,41 +54,6 @@ #define SYM_MISC_H /* - * A 'read barrier' flushes any data that have been prefetched - * by the processor due to out of order execution. Such a barrier - * must notably be inserted prior to looking at data that have - * been DMAed, assuming that program does memory READs in proper - * order and that the device ensured proper ordering of WRITEs. - * - * A 'write barrier' prevents any previous WRITEs to pass further - * WRITEs. Such barriers must be inserted each time another agent - * relies on ordering of WRITEs. - * - * Note that, due to posting of PCI memory writes, we also must - * insert dummy PCI read transactions when some ordering involving - * both directions over the PCI does matter. PCI transactions are - * fully ordered in each direction. - * - * IA32 processors insert implicit barriers when the processor - * accesses unchacheable either for reading or writing, and - * donnot reorder WRITEs. As a result, some 'read barriers' can - * be avoided (following access to uncacheable), and 'write - * barriers' should be useless (preventing compiler optimizations - * should be enough). - */ - -#define __READ_BARRIER() rmb() -#define __WRITE_BARRIER() wmb() - -#ifndef MEMORY_READ_BARRIER -#define MEMORY_READ_BARRIER() __READ_BARRIER() -#endif -#ifndef MEMORY_WRITE_BARRIER -#define MEMORY_WRITE_BARRIER() __WRITE_BARRIER() -#endif - - -/* * A la VMS/CAM-3 queue management. */ typedef struct sym_quehead { @@ -222,48 +187,11 @@ #define sym_is_bit(p, n) (((u32 *)(p))[(n)>>5] & (1<<((n)&0x1f))) /* - * Portable but silly implemented byte order primitives. - */ -#if BYTE_ORDER == BIG_ENDIAN - -#define __revb16(x) ( (((u16)(x) & (u16)0x00ffU) << 8) | \ - (((u16)(x) & (u16)0xff00U) >> 8) ) -#define __revb32(x) ( (((u32)(x) & 0x000000ffU) << 24) | \ - (((u32)(x) & 0x0000ff00U) << 8) | \ - (((u32)(x) & 0x00ff0000U) >> 8) | \ - (((u32)(x) & 0xff000000U) >> 24) ) - -#define __htole16(v) __revb16(v) -#define __htole32(v) __revb32(v) -#define __le16toh(v) __htole16(v) -#define __le32toh(v) __htole32(v) - -static __inline u16 _htole16(u16 v) { return __htole16(v); } -static __inline u32 _htole32(u32 v) { return __htole32(v); } -#define _le16toh _htole16 -#define _le32toh _htole32 - -#else /* LITTLE ENDIAN */ - -#define __htole16(v) (v) -#define __htole32(v) (v) -#define __le16toh(v) (v) -#define __le32toh(v) (v) - -#define _htole16(v) (v) -#define _htole32(v) (v) -#define _le16toh(v) (v) -#define _le32toh(v) (v) - -#endif /* BYTE_ORDER */ - -/* * The below round up/down macros are to be used with a constant * as argument (sizeof(...) for example), for the compiler to * optimize the whole thing. */ #define _U_(a,m) (a)<=(1< -#else #include "sym_glue.h" -#endif +#include "sym_nvram.h" /* * Some poor and bogus sync table that refers to Tekram NVRAM layout. @@ -246,8 +243,8 @@ } } #else -static void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram) { } -static void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram) { } +static void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram) { (void)np; (void)nvram; } +static void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram) { (void)np; (void)nvram; } #endif /* SYM_CONF_DEBUG_NVRAM */ @@ -382,6 +379,61 @@ S24C16_write_ack(np, ack_data, gpreg, gpcntl); } + +#if SYM_CONF_NVRAM_WRITE_SUPPORT +/* + * Write 'len' bytes starting at 'offset'. + */ +static int sym_write_S24C16_nvram(struct sym_device *np, int offset, + u_char *data, int len) +{ + u_char gpcntl, gpreg; + u_char old_gpcntl, old_gpreg; + u_char ack_data; + int x; + + /* save current state of GPCNTL and GPREG */ + old_gpreg = INB (nc_gpreg); + old_gpcntl = INB (nc_gpcntl); + gpcntl = old_gpcntl & 0x1c; + + /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */ + OUTB (nc_gpreg, old_gpreg); + OUTB (nc_gpcntl, gpcntl); + + /* this is to set NVRAM into a known state with GPIO0/1 both low */ + gpreg = old_gpreg; + S24C16_set_bit(np, 0, &gpreg, CLR_CLK); + S24C16_set_bit(np, 0, &gpreg, CLR_BIT); + + /* now set NVRAM inactive with GPIO0/1 both high */ + S24C16_stop(np, &gpreg); + + /* NVRAM has to be written in segments of 16 bytes */ + for (x = 0; x < len ; x += 16) { + do { + S24C16_start(np, &gpreg); + S24C16_write_byte(np, &ack_data, + 0xa0 | (((offset+x) >> 7) & 0x0e), + &gpreg, &gpcntl); + } while (ack_data & 0x01); + + S24C16_write_byte(np, &ack_data, (offset+x) & 0xff, + &gpreg, &gpcntl); + + for (y = 0; y < 16; y++) + S24C16_write_byte(np, &ack_data, data[x+y], + &gpreg, &gpcntl); + S24C16_stop(np, &gpreg); + } + + /* return GPIO0/1 to original states after having accessed NVRAM */ + OUTB (nc_gpcntl, old_gpcntl); + OUTB (nc_gpreg, old_gpreg); + + return 0; +} +#endif /* SYM_CONF_NVRAM_WRITE_SUPPORT */ /* * Read 'len' bytes starting at 'offset'. diff -Nru a/drivers/scsi/sym53c8xx_2/sym_nvram.h b/drivers/scsi/sym53c8xx_2/sym_nvram.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/scsi/sym53c8xx_2/sym_nvram.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,216 @@ +/* + * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family + * of PCI-SCSI IO processors. + * + * Copyright (C) 1999-2001 Gerard Roudier + * + * This driver is derived from the Linux sym53c8xx driver. + * Copyright (C) 1998-2000 Gerard Roudier + * + * The sym53c8xx driver is derived from the ncr53c8xx driver that had been + * a port of the FreeBSD ncr driver to Linux-1.2.13. + * + * The original ncr driver has been written for 386bsd and FreeBSD by + * Wolfgang Stanglmeier + * Stefan Esser + * Copyright (C) 1994 Wolfgang Stanglmeier + * + * Other major contributions: + * + * NVRAM detection and reading. + * Copyright (C) 1997 Richard Waltham + * + *----------------------------------------------------------------------------- + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Where this Software is combined with software released under the terms of + * the GNU Public License ("GPL") and the terms of the GPL would require the + * combined work to also be released under the terms of the GPL, the terms + * and conditions of this License will apply in addition to those of the + * GPL with the exception of any terms or conditions of this License that + * conflict with, or are expressly prohibited by, the GPL. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef SYM_NVRAM_H +#define SYM_NVRAM_H + +#include "sym_conf.h" + +/* + * Symbios NVRAM data format + */ +#define SYMBIOS_NVRAM_SIZE 368 +#define SYMBIOS_NVRAM_ADDRESS 0x100 + +struct Symbios_nvram { +/* Header 6 bytes */ + u_short type; /* 0x0000 */ + u_short byte_count; /* excluding header/trailer */ + u_short checksum; + +/* Controller set up 20 bytes */ + u_char v_major; /* 0x00 */ + u_char v_minor; /* 0x30 */ + u32 boot_crc; + u_short flags; +#define SYMBIOS_SCAM_ENABLE (1) +#define SYMBIOS_PARITY_ENABLE (1<<1) +#define SYMBIOS_VERBOSE_MSGS (1<<2) +#define SYMBIOS_CHS_MAPPING (1<<3) +#define SYMBIOS_NO_NVRAM (1<<3) /* ??? */ + u_short flags1; +#define SYMBIOS_SCAN_HI_LO (1) + u_short term_state; +#define SYMBIOS_TERM_CANT_PROGRAM (0) +#define SYMBIOS_TERM_ENABLED (1) +#define SYMBIOS_TERM_DISABLED (2) + u_short rmvbl_flags; +#define SYMBIOS_RMVBL_NO_SUPPORT (0) +#define SYMBIOS_RMVBL_BOOT_DEVICE (1) +#define SYMBIOS_RMVBL_MEDIA_INSTALLED (2) + u_char host_id; + u_char num_hba; /* 0x04 */ + u_char num_devices; /* 0x10 */ + u_char max_scam_devices; /* 0x04 */ + u_char num_valid_scam_devices; /* 0x00 */ + u_char flags2; +#define SYMBIOS_AVOID_BUS_RESET (1<<2) + +/* Boot order 14 bytes * 4 */ + struct Symbios_host{ + u_short type; /* 4:8xx / 0:nok */ + u_short device_id; /* PCI device id */ + u_short vendor_id; /* PCI vendor id */ + u_char bus_nr; /* PCI bus number */ + u_char device_fn; /* PCI device/function number << 3*/ + u_short word8; + u_short flags; +#define SYMBIOS_INIT_SCAN_AT_BOOT (1) + u_short io_port; /* PCI io_port address */ + } host[4]; + +/* Targets 8 bytes * 16 */ + struct Symbios_target { + u_char flags; +#define SYMBIOS_DISCONNECT_ENABLE (1) +#define SYMBIOS_SCAN_AT_BOOT_TIME (1<<1) +#define SYMBIOS_SCAN_LUNS (1<<2) +#define SYMBIOS_QUEUE_TAGS_ENABLED (1<<3) + u_char rsvd; + u_char bus_width; /* 0x08/0x10 */ + u_char sync_offset; + u_short sync_period; /* 4*period factor */ + u_short timeout; + } target[16]; +/* Scam table 8 bytes * 4 */ + struct Symbios_scam { + u_short id; + u_short method; +#define SYMBIOS_SCAM_DEFAULT_METHOD (0) +#define SYMBIOS_SCAM_DONT_ASSIGN (1) +#define SYMBIOS_SCAM_SET_SPECIFIC_ID (2) +#define SYMBIOS_SCAM_USE_ORDER_GIVEN (3) + u_short status; +#define SYMBIOS_SCAM_UNKNOWN (0) +#define SYMBIOS_SCAM_DEVICE_NOT_FOUND (1) +#define SYMBIOS_SCAM_ID_NOT_SET (2) +#define SYMBIOS_SCAM_ID_VALID (3) + u_char target_id; + u_char rsvd; + } scam[4]; + + u_char spare_devices[15*8]; + u_char trailer[6]; /* 0xfe 0xfe 0x00 0x00 0x00 0x00 */ +}; +typedef struct Symbios_nvram Symbios_nvram; +typedef struct Symbios_host Symbios_host; +typedef struct Symbios_target Symbios_target; +typedef struct Symbios_scam Symbios_scam; + +/* + * Tekram NvRAM data format. + */ +#define TEKRAM_NVRAM_SIZE 64 +#define TEKRAM_93C46_NVRAM_ADDRESS 0 +#define TEKRAM_24C16_NVRAM_ADDRESS 0x40 + +struct Tekram_nvram { + struct Tekram_target { + u_char flags; +#define TEKRAM_PARITY_CHECK (1) +#define TEKRAM_SYNC_NEGO (1<<1) +#define TEKRAM_DISCONNECT_ENABLE (1<<2) +#define TEKRAM_START_CMD (1<<3) +#define TEKRAM_TAGGED_COMMANDS (1<<4) +#define TEKRAM_WIDE_NEGO (1<<5) + u_char sync_index; + u_short word2; + } target[16]; + u_char host_id; + u_char flags; +#define TEKRAM_MORE_THAN_2_DRIVES (1) +#define TEKRAM_DRIVES_SUP_1GB (1<<1) +#define TEKRAM_RESET_ON_POWER_ON (1<<2) +#define TEKRAM_ACTIVE_NEGATION (1<<3) +#define TEKRAM_IMMEDIATE_SEEK (1<<4) +#define TEKRAM_SCAN_LUNS (1<<5) +#define TEKRAM_REMOVABLE_FLAGS (3<<6) /* 0: disable; */ + /* 1: boot device; 2:all */ + u_char boot_delay_index; + u_char max_tags_index; + u_short flags1; +#define TEKRAM_F2_F6_ENABLED (1) + u_short spare[29]; +}; +typedef struct Tekram_nvram Tekram_nvram; +typedef struct Tekram_target Tekram_target; + +/* + * Union of supported NVRAM formats. + */ +struct sym_nvram { + int type; +#define SYM_SYMBIOS_NVRAM (1) +#define SYM_TEKRAM_NVRAM (2) +#if SYM_CONF_NVRAM_SUPPORT + union { + Symbios_nvram Symbios; + Tekram_nvram Tekram; + } data; +#endif +}; + +#if SYM_CONF_NVRAM_SUPPORT +void sym_nvram_setup_host (struct sym_hcb *np, struct sym_nvram *nvram); +void sym_nvram_setup_target (struct sym_hcb *np, int target, struct sym_nvram *nvp); +int sym_read_nvram (struct sym_device *np, struct sym_nvram *nvp); +#else +static inline void sym_nvram_setup_host(struct sym_hcb *np, struct sym_nvram *nvram) { } +static inline void sym_nvram_setup_target(struct sym_hcb *np, struct sym_nvram *nvram) { } +static inline int sym_read_nvram(struct sym_device *np, struct sym_nvram *nvp) +{ + nvp->type = 0; + return 0; +} +#endif + +#endif /* SYM_NVRAM_H */ diff -Nru a/drivers/scsi/sym53c8xx_comm.h b/drivers/scsi/sym53c8xx_comm.h --- a/drivers/scsi/sym53c8xx_comm.h Sun Mar 14 14:20:07 2004 +++ b/drivers/scsi/sym53c8xx_comm.h Sun Mar 14 14:20:07 2004 @@ -703,7 +703,8 @@ #define __unmap_scsi_data(dev, cmd) do {; } while (0) #define __map_scsi_single_data(dev, cmd) (__vtobus(dev,(cmd)->request_buffer)) #define __map_scsi_sg_data(dev, cmd) ((cmd)->use_sg) -#define __sync_scsi_data(dev, cmd) do {; } while (0) +#define __sync_scsi_data_for_cpu(dev, cmd) do {; } while (0) +#define __sync_scsi_data_for_device(dev, cmd) do {; } while (0) #define scsi_sg_dma_address(sc) vtobus((sc)->address) #define scsi_sg_dma_len(sc) ((sc)->length) @@ -767,18 +768,34 @@ return use_sg; } -static void __sync_scsi_data(struct device *dev, Scsi_Cmnd *cmd) +static void __sync_scsi_data_for_cpu(struct device *dev, Scsi_Cmnd *cmd) { enum dma_data_direction dma_dir = (enum dma_data_direction)scsi_to_pci_dma_dir(cmd->sc_data_direction); switch(cmd->__data_mapped) { case 2: - dma_sync_sg(dev, cmd->buffer, cmd->use_sg, dma_dir); + dma_sync_sg_for_cpu(dev, cmd->buffer, cmd->use_sg, dma_dir); break; case 1: - dma_sync_single(dev, cmd->__data_mapping, - cmd->request_bufflen, dma_dir); + dma_sync_single_for_cpu(dev, cmd->__data_mapping, + cmd->request_bufflen, dma_dir); + break; + } +} + +static void __sync_scsi_data_for_device(struct device *dev, Scsi_Cmnd *cmd) +{ + enum dma_data_direction dma_dir = + (enum dma_data_direction)scsi_to_pci_dma_dir(cmd->sc_data_direction); + + switch(cmd->__data_mapped) { + case 2: + dma_sync_sg_for_device(dev, cmd->buffer, cmd->use_sg, dma_dir); + break; + case 1: + dma_sync_single_for_device(dev, cmd->__data_mapping, + cmd->request_bufflen, dma_dir); break; } } @@ -791,7 +808,8 @@ #define unmap_scsi_data(np, cmd) __unmap_scsi_data(np->dev, cmd) #define map_scsi_single_data(np, cmd) __map_scsi_single_data(np->dev, cmd) #define map_scsi_sg_data(np, cmd) __map_scsi_sg_data(np->dev, cmd) -#define sync_scsi_data(np, cmd) __sync_scsi_data(np->dev, cmd) +#define sync_scsi_data_for_cpu(np, cmd) __sync_scsi_data_for_cpu(np->dev, cmd) +#define sync_scsi_data_for_device(np, cmd) __sync_scsi_data_for_device(np->dev, cmd) /*========================================================== ** diff -Nru a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c --- a/drivers/scsi/u14-34f.c Sun Mar 14 14:20:06 2004 +++ b/drivers/scsi/u14-34f.c Sun Mar 14 14:20:06 2004 @@ -1184,17 +1184,17 @@ pci_dir = scsi_to_pci_dma_dir(SCpnt->sc_data_direction); if (DEV2H(cpp->sense_addr)) - pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->sense_addr), + pci_dma_sync_single_for_cpu(HD(j)->pdev, DEV2H(cpp->sense_addr), DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); if (SCpnt->use_sg) - pci_dma_sync_sg(HD(j)->pdev, SCpnt->request_buffer, + pci_dma_sync_sg_for_cpu(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir); if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL; if (DEV2H(cpp->data_address)) - pci_dma_sync_single(HD(j)->pdev, DEV2H(cpp->data_address), + pci_dma_sync_single_for_cpu(HD(j)->pdev, DEV2H(cpp->data_address), DEV2H(cpp->data_len), pci_dir); } diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c --- a/drivers/usb/core/usb.c Sun Mar 14 14:20:07 2004 +++ b/drivers/usb/core/usb.c Sun Mar 14 14:20:07 2004 @@ -1297,6 +1297,13 @@ return urb; } +/* XXX DISABLED, no users currently. If you wish to re-enable this + * XXX please determine whether the sync is to transfer ownership of + * XXX the buffer from device to cpu or vice verse, and thusly use the + * XXX appropriate _for_{cpu,device}() method. -DaveM + */ +#if 0 + /** * usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s) * @urb: urb whose transfer_buffer/setup_packet will be synchronized @@ -1325,6 +1332,7 @@ DMA_TO_DEVICE); } } +#endif /** * usb_buffer_unmap - free DMA mapping(s) for an urb @@ -1403,6 +1411,13 @@ usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } +/* XXX DISABLED, no users currently. If you wish to re-enable this + * XXX please determine whether the sync is to transfer ownership of + * XXX the buffer from device to cpu or vice verse, and thusly use the + * XXX appropriate _for_{cpu,device}() method. -DaveM + */ +#if 0 + /** * usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s) * @dev: device to which the scatterlist will be mapped @@ -1428,6 +1443,7 @@ dma_sync_sg (controller, sg, n_hw_ents, usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); } +#endif /** * usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist @@ -1595,11 +1611,15 @@ EXPORT_SYMBOL (usb_buffer_free); EXPORT_SYMBOL (usb_buffer_map); +#if 0 EXPORT_SYMBOL (usb_buffer_dmasync); +#endif EXPORT_SYMBOL (usb_buffer_unmap); EXPORT_SYMBOL (usb_buffer_map_sg); +#if 0 EXPORT_SYMBOL (usb_buffer_dmasync_sg); +#endif EXPORT_SYMBOL (usb_buffer_unmap_sg); MODULE_LICENSE("GPL"); diff -Nru a/drivers/video/aty/radeon_monitor.c b/drivers/video/aty/radeon_monitor.c --- a/drivers/video/aty/radeon_monitor.c Sun Mar 14 14:20:05 2004 +++ b/drivers/video/aty/radeon_monitor.c Sun Mar 14 14:20:05 2004 @@ -757,7 +757,7 @@ && rinfo->mon1_EDID) { struct fb_var_screeninfo var; RTRACE("Parsing EDID data for panel info\n"); - if (parse_edid(rinfo->mon1_EDID, &var) == 0) { + if (fb_parse_edid(rinfo->mon1_EDID, &var) == 0) { if (var.xres >= rinfo->panel_info.xres && var.yres >= rinfo->panel_info.yres) radeon_var_to_panel_info(rinfo, &var); diff -Nru a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c --- a/drivers/video/console/fbcon.c Sun Mar 14 14:20:07 2004 +++ b/drivers/video/console/fbcon.c Sun Mar 14 14:20:07 2004 @@ -2345,6 +2345,7 @@ { if (!num_registered_fb) return -ENODEV; + take_over_console(&fb_con, first_fb_vc, last_fb_vc, fbcon_is_default); acquire_console_sem(); if (!fbcon_event_notifier_registered) { @@ -2352,10 +2353,11 @@ fbcon_event_notifier_registered = 1; } release_console_sem(); - return 0; } +#ifdef MODULE + void __exit fb_console_exit(void) { acquire_console_sem(); @@ -2369,6 +2371,8 @@ module_init(fb_console_init); module_exit(fb_console_exit); + +#endif /* * Visible symbols for modules diff -Nru a/drivers/video/dnfb.c b/drivers/video/dnfb.c --- a/drivers/video/dnfb.c Sun Mar 14 14:20:08 2004 +++ b/drivers/video/dnfb.c Sun Mar 14 14:20:08 2004 @@ -103,8 +103,6 @@ #define SWAP(A) ((A>>8) | ((A&0xff) <<8)) -static struct fb_info fb_info; - /* frame buffer operations */ static int dnfb_blank(int blank, struct fb_info *info); @@ -119,7 +117,7 @@ .fb_cursor = soft_cursor, }; -struct fb_var_screeninfo dnfb_var __initdata = { +struct fb_var_screeninfo dnfb_var __devinitdata = { .xres 1280, .yres 1024, .xres_virtual 2048, @@ -130,7 +128,7 @@ .vmode FB_VMODE_NONINTERLACED, }; -static struct fb_fix_screeninfo dnfb_fix __initdata = { +static struct fb_fix_screeninfo dnfb_fix __devinitdata = { .id "Apollo Mono", .smem_start (FRAME_BUFFER_START + IO_BASE), .smem_len FRAME_BUFFER_LEN, @@ -148,7 +146,7 @@ return 0; } -static +static void dnfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) { @@ -224,21 +222,38 @@ out_8(AP_CONTROL_0, NORMAL_MODE); } +/* + * Initialization + */ -unsigned long __init dnfb_init(unsigned long mem_start) +static int __devinit dnfb_probe(struct device *device) { - int err; + struct platform_device *dev = to_platform_device(device); + struct fb_info *info; + int err = 0; + + info = framebuffer_alloc(0, &dev->dev); + if (!info) + return -ENOMEM; + + info->fbops = &dn_fb_ops; + info->fix = dnfb_fix; + info->var = dnfb_var; + info->screen_base = (u_char *) info->fix.smem_start; + + err = fb_alloc_cmap(&info->cmap, 2, 0); + if (err < 0) { + framebuffer_release(info); + return err; + } - fb_info.fbops = &dn_fb_ops; - fb_info.fix = dnfb_fix; - fb_info.var = dnfb_var; - fb_info.screen_base = (u_char *) fb_info.fix.smem_start; - - fb_alloc_cmap(&fb_info.cmap, 2, 0); - - err = register_framebuffer(&fb_info); - if (err < 0) - panic("unable to register apollo frame buffer\n"); + err = register_framebuffer(info); + if (err < 0) { + fb_dealloc_cmap(&info->cmap); + framebuffer_release(info); + return err; + } + dev_set_drvdata(&dev->dev, info); /* now we have registered we can safely setup the hardware */ out_8(AP_CONTROL_3A, RESET_CREG); @@ -249,7 +264,31 @@ out_be16(AP_ROP_1, SWAP(0x3)); printk("apollo frame buffer alive and kicking !\n"); - return mem_start; + return err; +} + +static struct device_driver dnfb_driver = { + .name = "dnfb", + .bus = &platform_bus_type, + .probe = dnfb_probe, +}; + +static struct platform_device dnfb_device = { + .name = "dnfb", +}; + +int __init dnfb_init(void) +{ + int ret; + + ret = driver_register(&dnfb_driver); + + if (!ret) { + ret = platform_device_register(&dnfb_device); + if (ret) + driver_unregister(&dnfb_driver); + } + return ret; } MODULE_LICENSE("GPL"); diff -Nru a/drivers/video/fbmon.c b/drivers/video/fbmon.c --- a/drivers/video/fbmon.c Sun Mar 14 14:20:08 2004 +++ b/drivers/video/fbmon.c Sun Mar 14 14:20:08 2004 @@ -41,6 +41,15 @@ * EDID parser */ +#undef DEBUG /* define this for verbose EDID parsing output */ + +#ifdef DEBUG +#define DPRINTK(fmt, args...) printk(fmt,## args) +#else +#define DPRINTK(fmt, args...) +#endif + + const unsigned char edid_v1_header[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }; @@ -84,203 +93,93 @@ return 1; } -static void parse_vendor_block(unsigned char *block) +static void parse_vendor_block(unsigned char *block, struct fb_monspecs *specs) { - unsigned char c[4]; - - c[0] = ((block[0] & 0x7c) >> 2) + '@'; - c[1] = ((block[0] & 0x03) << 3) + ((block[1] & 0xe0) >> 5) + '@'; - c[2] = (block[1] & 0x1f) + '@'; - c[3] = 0; - printk(" Manufacturer: %s ", c); - printk("Model: %x ", block[2] + (block[3] << 8)); - printk("Serial#: %u\n", block[4] + (block[5] << 8) + - (block[6] << 16) + (block[7] << 24)); - printk(" Year: %u Week %u\n", block[9] + 1990, block[8]); -} - -static void parse_dpms_capabilities(unsigned char flags) -{ - printk(" DPMS: Active %s, Suspend %s, Standby %s\n", + specs->manufacturer[0] = ((block[0] & 0x7c) >> 2) + '@'; + specs->manufacturer[1] = ((block[0] & 0x03) << 3) + + ((block[1] & 0xe0) >> 5) + '@'; + specs->manufacturer[2] = (block[1] & 0x1f) + '@'; + specs->manufacturer[3] = 0; + specs->model = block[2] + (block[3] << 8); + specs->serial = block[4] + (block[5] << 8) + + (block[6] << 16) + (block[7] << 24); + specs->year = block[9] + 1990; + specs->week = block[8]; + DPRINTK(" Manufacturer: %s\n", specs->manufacturer); + DPRINTK(" Model: %x\n", specs->model); + DPRINTK(" Serial#: %u\n", specs->serial); + DPRINTK(" Year: %u Week %u\n", specs->year, specs->week); +} + +static void get_dpms_capabilities(unsigned char flags, + struct fb_monspecs *specs) +{ + specs->dpms = 0; + if (flags & DPMS_ACTIVE_OFF) + specs->dpms |= FB_DPMS_ACTIVE_OFF; + if (flags & DPMS_SUSPEND) + specs->dpms |= FB_DPMS_SUSPEND; + if (flags & DPMS_STANDBY) + specs->dpms |= FB_DPMS_STANDBY; + DPRINTK(" DPMS: Active %s, Suspend %s, Standby %s\n", (flags & DPMS_ACTIVE_OFF) ? "yes" : "no", (flags & DPMS_SUSPEND) ? "yes" : "no", (flags & DPMS_STANDBY) ? "yes" : "no"); } -static void print_chroma(unsigned char *block) +static void get_chroma(unsigned char *block, struct fb_monspecs *specs) { int tmp; + DPRINTK(" Chroma\n"); /* Chromaticity data */ - printk(" Chromaticity: "); tmp = ((block[5] & (3 << 6)) >> 6) | (block[0x7] << 2); tmp *= 1000; tmp += 512; - printk("RedX: 0.%03d ", tmp/1024); + specs->chroma.redx = tmp/1024; + DPRINTK(" RedX: 0.%03d ", specs->chroma.redx); tmp = ((block[5] & (3 << 4)) >> 4) | (block[0x8] << 2); tmp *= 1000; tmp += 512; - printk("RedY: 0.%03d\n", tmp/1024); + specs->chroma.redy = tmp/1024; + DPRINTK("RedY: 0.%03d\n", specs->chroma.redy); tmp = ((block[5] & (3 << 2)) >> 2) | (block[0x9] << 2); tmp *= 1000; tmp += 512; - printk(" GreenX: 0.%03d ", tmp/1024); + specs->chroma.greenx = tmp/1024; + DPRINTK(" GreenX: 0.%03d ", specs->chroma.greenx); tmp = (block[5] & 3) | (block[0xa] << 2); tmp *= 1000; tmp += 512; - printk("GreenY: 0.%03d\n", tmp/1024); + specs->chroma.greeny = tmp/1024; + DPRINTK("GreenY: 0.%03d\n", specs->chroma.greeny); tmp = ((block[6] & (3 << 6)) >> 6) | (block[0xb] << 2); tmp *= 1000; tmp += 512; - printk(" BlueX: 0.%03d ", tmp/1024); + specs->chroma.bluex = tmp/1024; + DPRINTK(" BlueX: 0.%03d ", specs->chroma.bluex); tmp = ((block[6] & (3 << 4)) >> 4) | (block[0xc] << 2); tmp *= 1000; tmp += 512; - printk("BlueY: 0.%03d\n", tmp/1024); + specs->chroma.bluey = tmp/1024; + DPRINTK("BlueY: 0.%03d\n", specs->chroma.bluey); tmp = ((block[6] & (3 << 2)) >> 2) | (block[0xd] << 2); tmp *= 1000; tmp += 512; - printk(" WhiteX: 0.%03d ", tmp/1024); + specs->chroma.whitex = tmp/1024; + DPRINTK(" WhiteX: 0.%03d ", specs->chroma.whitex); tmp = (block[6] & 3) | (block[0xe] << 2); tmp *= 1000; tmp += 512; - printk("WhiteY: 0.%03d\n", tmp/1024); -} - -static void parse_display_block(unsigned char *block) -{ - unsigned char c; - - c = (block[0] & 0x80) >> 7; - if (c) - printk(" Digital Display Input"); - else { - printk(" Analog Display Input: Input Voltage - "); - switch ((block[0] & 0x60) >> 5) { - case 0: - printk("0.700V/0.300V"); - break; - case 1: - printk("0.714V/0.286V"); - break; - case 2: - printk("1.000V/0.400V"); - break; - case 3: - printk("0.700V/0.000V"); - break; - default: - printk("unknown"); - } - printk("\n"); - } - c = (block[0] & 0x10) >> 4; - if (c) - printk(" Configurable signal level\n"); - printk(" Sync: "); - c = block[0] & 0x0f; - if (c & 0x10) - printk("Blank to Blank "); - if (c & 0x08) - printk("Separate "); - if (c & 0x04) - printk("Composite "); - if (c & 0x02) - printk("Sync on Green "); - if (c & 0x01) - printk("Serration on "); - printk("\n"); - - printk(" Max H-size in cm: "); - c = block[1]; - if (c) - printk("%d\n", c); - else - printk("variable\n"); - - printk(" Max V-size in cm: "); - c = block[2]; - if (c) - printk("%d\n", c); - else - printk("variable\n"); - - c = block[3]; - printk(" Gamma: "); - printk("%d.%d\n", (c + 100)/100, (c+100) % 100); - - parse_dpms_capabilities(block[4]); - - switch ((block[4] & 0x18) >> 3) { - case 0: - printk(" Monochrome/Grayscale\n"); - break; - case 1: - printk(" RGB Color Display\n"); - break; - case 2: - printk(" Non-RGB Multicolor Display\n"); - break; - default: - printk(" Unknown\n"); - break; - } - - print_chroma(block); - - c = block[4] & 0x7; - if (c & 0x04) - printk(" Default color format is primary\n"); - if (c & 0x02) - printk(" First DETAILED Timing is preferred\n"); - if (c & 0x01) - printk(" Display is GTF capable\n"); -} - -static void parse_std_md_block(unsigned char *block) -{ - unsigned char c; - - c = block[0]; - if (c&0x80) printk(" 720x400@70Hz\n"); - if (c&0x40) printk(" 720x400@88Hz\n"); - if (c&0x20) printk(" 640x480@60Hz\n"); - if (c&0x10) printk(" 640x480@67Hz\n"); - if (c&0x08) printk(" 640x480@72Hz\n"); - if (c&0x04) printk(" 640x480@75Hz\n"); - if (c&0x02) printk(" 800x600@56Hz\n"); - if (c&0x01) printk(" 800x600@60Hz\n"); - - c = block[1]; - if (c&0x80) printk(" 800x600@72Hz\n"); - if (c&0x40) printk(" 800x600@75Hz\n"); - if (c&0x20) printk(" 832x624@75Hz\n"); - if (c&0x10) printk(" 1024x768@87Hz (interlaced)\n"); - if (c&0x08) printk(" 1024x768@60Hz\n"); - if (c&0x04) printk(" 1024x768@70Hz\n"); - if (c&0x02) printk(" 1024x768@75Hz\n"); - if (c&0x01) printk(" 1280x1024@75Hz\n"); - - c = block[2]; - if (c&0x80) printk(" 1152x870@75Hz\n"); - printk(" Manufacturer's mask: %x\n",c&0x7F); -} - - -static int edid_is_timing_block(unsigned char *block) -{ - if ((block[0] != 0x00) || (block[1] != 0x00) || - (block[2] != 0x00) || (block[4] != 0x00)) - return 1; - else - return 0; + specs->chroma.whitey = tmp/1024; + DPRINTK("WhiteY: 0.%03d\n", specs->chroma.whitey); } static int edid_is_serial_block(unsigned char *block) @@ -323,154 +222,6 @@ return 0; } -static int edid_is_color_block(unsigned char *block) -{ - if ((block[0] == 0x00) && (block[1] == 0x00) && - (block[2] == 0x00) && (block[3] == 0xfb) && - (block[4] == 0x00)) - return 1; - else - return 0; -} - -static int edid_is_std_timings_block(unsigned char *block) -{ - if ((block[0] == 0x00) && (block[1] == 0x00) && - (block[2] == 0x00) && (block[3] == 0xfa) && - (block[4] == 0x00)) - return 1; - else - return 0; -} - -static void parse_serial_block(unsigned char *block) -{ - unsigned char c[13]; - - copy_string(block, c); - printk(" Serial No : %s\n", c); -} - -static void parse_ascii_block(unsigned char *block) -{ - unsigned char c[13]; - - copy_string(block, c); - printk(" %s\n", c); -} - -static void parse_limits_block(unsigned char *block) -{ - printk(" HorizSync : %d-%d KHz\n", H_MIN_RATE, H_MAX_RATE); - printk(" VertRefresh : %d-%d Hz\n", V_MIN_RATE, V_MAX_RATE); - if (MAX_PIXEL_CLOCK != 10*0xff) - printk(" Max Pixelclock: %d MHz\n", (int) MAX_PIXEL_CLOCK); -} - -static void parse_monitor_block(unsigned char *block) -{ - unsigned char c[13]; - - copy_string(block, c); - printk(" Monitor Name : %s\n", c); -} - -static void parse_color_block(unsigned char *block) -{ - printk(" Color Point : unimplemented\n"); -} - -static void parse_std_timing_block(unsigned char *block) -{ - int xres, yres = 0, refresh, ratio, err = 1; - - xres = (block[0] + 31) * 8; - if (xres <= 256) - return; - - ratio = (block[1] & 0xc0) >> 6; - switch (ratio) { - case 0: - yres = xres; - break; - case 1: - yres = (xres * 3)/4; - break; - case 2: - yres = (xres * 4)/5; - break; - case 3: - yres = (xres * 9)/16; - break; - } - refresh = (block[1] & 0x3f) + 60; - printk(" %dx%d@%dHz\n", xres, yres, refresh); - err = 0; -} - -static void parse_dst_timing_block(unsigned char *block) -{ - int i; - - block += 5; - for (i = 0; i < 5; i++, block += STD_TIMING_DESCRIPTION_SIZE) - parse_std_timing_block(block); -} - -static void parse_detailed_timing_block(unsigned char *block) -{ - printk(" %d MHz ", PIXEL_CLOCK/1000000); - printk("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET, - H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING); - printk("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET, - V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING); - printk("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-", - (VSYNC_POSITIVE) ? "+" : "-"); -} - -int parse_edid(unsigned char *edid, struct fb_var_screeninfo *var) -{ - int i; - unsigned char *block; - - if (edid == NULL || var == NULL) - return 1; - - if (!(edid_checksum(edid))) - return 1; - - if (!(edid_check_header(edid))) - return 1; - - block = edid + DETAILED_TIMING_DESCRIPTIONS_START; - - for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) { - if (edid_is_timing_block(block)) { - var->xres = var->xres_virtual = H_ACTIVE; - var->yres = var->yres_virtual = V_ACTIVE; - var->height = var->width = -1; - var->right_margin = H_SYNC_OFFSET; - var->left_margin = (H_ACTIVE + H_BLANKING) - - (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH); - var->upper_margin = V_BLANKING - V_SYNC_OFFSET - - V_SYNC_WIDTH; - var->lower_margin = V_SYNC_OFFSET; - var->hsync_len = H_SYNC_WIDTH; - var->vsync_len = V_SYNC_WIDTH; - var->pixclock = PIXEL_CLOCK; - var->pixclock /= 1000; - var->pixclock = KHZ2PICOS(var->pixclock); - - if (HSYNC_POSITIVE) - var->sync |= FB_SYNC_HOR_HIGH_ACT; - if (VSYNC_POSITIVE) - var->sync |= FB_SYNC_VERT_HIGH_ACT; - return 0; - } - } - return 1; -} - static void calc_mode_timings(int xres, int yres, int refresh, struct fb_videomode *mode) { struct fb_var_screeninfo var; @@ -500,45 +251,82 @@ unsigned char c; c = block[0]; - if (c&0x80) - calc_mode_timings(720, 400, 70, &mode[num++]); - if (c&0x40) - calc_mode_timings(720, 400, 88, &mode[num++]); - if (c&0x20) + if (c&0x80) { + calc_mode_timings(720, 400, 70, &mode[num]); + mode[num++].flag = FB_MODE_IS_CALCULATED; + DPRINTK(" 720x400@70Hz\n"); + } + if (c&0x40) { + calc_mode_timings(720, 400, 88, &mode[num]); + mode[num++].flag = FB_MODE_IS_CALCULATED; + DPRINTK(" 720x400@88Hz\n"); + } + if (c&0x20) { mode[num++] = vesa_modes[3]; - if (c&0x10) - calc_mode_timings(640, 480, 67, &mode[num++]); - if (c&0x08) + DPRINTK(" 640x480@60Hz\n"); + } + if (c&0x10) { + calc_mode_timings(640, 480, 67, &mode[num]); + mode[num++].flag = FB_MODE_IS_CALCULATED; + DPRINTK(" 640x480@67Hz\n"); + } + if (c&0x08) { mode[num++] = vesa_modes[4]; - if (c&0x04) + DPRINTK(" 640x480@72Hz\n"); + } + if (c&0x04) { mode[num++] = vesa_modes[5]; - if (c&0x02) + DPRINTK(" 640x480@75Hz\n"); + } + if (c&0x02) { mode[num++] = vesa_modes[7]; - if (c&0x01) + DPRINTK(" 800x600@56Hz\n"); + } + if (c&0x01) { mode[num++] = vesa_modes[8]; + DPRINTK(" 800x600@60Hz\n"); + } c = block[1]; - if (c&0x80) + if (c&0x80) { mode[num++] = vesa_modes[9]; - if (c&0x40) + DPRINTK(" 800x600@72Hz\n"); + } + if (c&0x40) { mode[num++] = vesa_modes[10]; - if (c&0x20) - calc_mode_timings(832, 624, 75, &mode[num++]); - if (c&0x10) + DPRINTK(" 800x600@75Hz\n"); + } + if (c&0x20) { + calc_mode_timings(832, 624, 75, &mode[num]); + mode[num++].flag = FB_MODE_IS_CALCULATED; + DPRINTK(" 832x624@75Hz\n"); + } + if (c&0x10) { mode[num++] = vesa_modes[12]; - if (c&0x08) + DPRINTK(" 1024x768@87Hz Interlaced\n"); + } + if (c&0x08) { mode[num++] = vesa_modes[13]; - if (c&0x04) + DPRINTK(" 1024x768@60Hz\n"); + } + if (c&0x04) { mode[num++] = vesa_modes[14]; - if (c&0x02) + DPRINTK(" 1024x768@70Hz\n"); + } + if (c&0x02) { mode[num++] = vesa_modes[15]; - if (c&0x01) + DPRINTK(" 1024x768@75Hz\n"); + } + if (c&0x01) { mode[num++] = vesa_modes[21]; - + DPRINTK(" 1280x1024@75Hz\n"); + } c = block[2]; - if (c&0x80) + if (c&0x80) { mode[num++] = vesa_modes[17]; - + DPRINTK(" 1152x870@75Hz\n"); + } + DPRINTK(" Manufacturer's mask: %x\n",c&0x7F); return num; } @@ -567,17 +355,17 @@ } refresh = (block[1] & 0x3f) + 60; + DPRINTK(" %dx%d@%dHz\n", xres, yres, refresh); for (i = 0; i < VESA_MODEDB_SIZE; i++) { if (vesa_modes[i].xres == xres && vesa_modes[i].yres == yres && vesa_modes[i].refresh == refresh) { *mode = vesa_modes[i]; - break; - } else { - calc_mode_timings(xres, yres, refresh, mode); - break; + mode->flag |= FB_MODE_IS_STANDARD; + return 1; } } + calc_mode_timings(xres, yres, refresh, mode); return 1; } @@ -615,6 +403,15 @@ mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) * (V_ACTIVE + V_BLANKING)); mode->vmode = 0; + mode->flag = FB_MODE_IS_DETAILED; + + DPRINTK(" %d MHz ", PIXEL_CLOCK/1000000); + DPRINTK("%d %d %d %d ", H_ACTIVE, H_ACTIVE + H_SYNC_OFFSET, + H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH, H_ACTIVE + H_BLANKING); + DPRINTK("%d %d %d %d ", V_ACTIVE, V_ACTIVE + V_SYNC_OFFSET, + V_ACTIVE + V_SYNC_OFFSET + V_SYNC_WIDTH, V_ACTIVE + V_BLANKING); + DPRINTK("%sHSync %sVSync\n\n", (HSYNC_POSITIVE) ? "+" : "-", + (VSYNC_POSITIVE) ? "+" : "-"); } /** @@ -647,21 +444,30 @@ *dbsize = 0; + DPRINTK(" Supported VESA Modes\n"); block = edid + ESTABLISHED_TIMING_1; num += get_est_timing(block, &mode[num]); + DPRINTK(" Standard Timings\n"); block = edid + STD_TIMING_DESCRIPTIONS_START; for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE) num += get_std_timing(block, &mode[num]); + DPRINTK(" Detailed Timings\n"); block = edid + DETAILED_TIMING_DESCRIPTIONS_START; for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) { + int first = 1; + if (block[0] == 0x00 && block[1] == 0x00) { if (block[3] == 0xfa) { num += get_dst_timing(block + 5, &mode[num]); } } else { get_detailed_timing(block, &mode[num]); + if (first) { + mode[num].flag |= FB_MODE_IS_FIRST; + first = 0; + } num++; } } @@ -694,45 +500,24 @@ kfree(modedb); } -/** - * fb_get_monitor_limits - get monitor operating limits - * @edid: EDID data - * @specs: fb_monspecs structure pointer - * - * DESCRIPTION: - * Gets monitor operating limits from EDID data and places them in - * @specs - */ int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs) { int i, retval = 1; unsigned char *block; - if (edid == NULL || specs == NULL) - return 1; - - if (!(edid_checksum(edid))) - return 1; - - if (!(edid_check_header(edid))) - return 1; - - memset(specs, 0, sizeof(struct fb_monspecs)); block = edid + DETAILED_TIMING_DESCRIPTIONS_START; - printk("Monitor Operating Limits: "); + DPRINTK(" Monitor Operating Limits: "); for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) { if (edid_is_limits_block(block)) { specs->hfmin = H_MIN_RATE * 1000; specs->hfmax = H_MAX_RATE * 1000; specs->vfmin = V_MIN_RATE; specs->vfmax = V_MAX_RATE; - specs->dclkmax = (MAX_PIXEL_CLOCK != 10*0xff) ? - MAX_PIXEL_CLOCK * 1000000 : 0; + specs->dclkmax = MAX_PIXEL_CLOCK * 1000000; specs->gtf = (GTF_SUPPORT) ? 1 : 0; - specs->dpms = edid[DPMS_FLAGS]; retval = 0; - printk("From EDID\n"); + DPRINTK("From EDID\n"); break; } } @@ -744,7 +529,7 @@ modes = fb_create_modedb(edid, &num_modes); if (!modes) { - printk("None Available\n"); + DPRINTK("None Available\n"); return 1; } @@ -767,15 +552,189 @@ if (specs->vfmin == 0 || specs->vfmin > hz) specs->vfmin = hz; } - printk("Extrapolated\n"); + DPRINTK("Extrapolated\n"); fb_destroy_modedb(modes); } - printk(" H: %d-%dKHz V: %d-%dHz DCLK: %dMHz\n", specs->hfmin/1000, specs->hfmax/1000, - specs->vfmin, specs->vfmax, specs->dclkmax/1000000); + DPRINTK(" H: %d-%dKHz V: %d-%dHz DCLK: %dMHz\n", + specs->hfmin/1000, specs->hfmax/1000, specs->vfmin, + specs->vfmax, specs->dclkmax/1000000); return retval; } -void show_edid(unsigned char *edid) +static void get_monspecs(unsigned char *edid, struct fb_monspecs *specs) +{ + unsigned char c, *block; + + block = edid + EDID_STRUCT_DISPLAY; + + fb_get_monitor_limits(edid, specs); + + c = (block[0] & 0x80) >> 7; + specs->input = 0; + if (c) { + specs->input |= FB_DISP_DDI; + DPRINTK(" Digital Display Input"); + } else { + DPRINTK(" Analog Display Input: Input Voltage - "); + switch ((block[0] & 0x60) >> 5) { + case 0: + DPRINTK("0.700V/0.300V"); + specs->input |= FB_DISP_ANA_700_300; + break; + case 1: + DPRINTK("0.714V/0.286V"); + specs->input |= FB_DISP_ANA_714_286; + break; + case 2: + DPRINTK("1.000V/0.400V"); + specs->input |= FB_DISP_ANA_1000_400; + break; + case 3: + DPRINTK("0.700V/0.000V"); + specs->input |= FB_DISP_ANA_700_000; + break; + default: + DPRINTK("unknown"); + specs->input |= FB_DISP_UNKNOWN; + } + } + DPRINTK("\n Sync: "); + c = (block[0] & 0x10) >> 4; + if (c) + DPRINTK(" Configurable signal level\n"); + c = block[0] & 0x0f; + specs->signal = 0; + if (c & 0x10) { + DPRINTK("Blank to Blank "); + specs->signal |= FB_SIGNAL_BLANK_BLANK; + } + if (c & 0x08) { + DPRINTK("Separate "); + specs->signal |= FB_SIGNAL_SEPARATE; + } + if (c & 0x04) { + DPRINTK("Composite "); + specs->signal |= FB_SIGNAL_COMPOSITE; + } + if (c & 0x02) { + DPRINTK("Sync on Green "); + specs->signal |= FB_SIGNAL_SYNC_ON_GREEN; + } + if (c & 0x01) { + DPRINTK("Serration on "); + specs->signal |= FB_SIGNAL_SERRATION_ON; + } + DPRINTK("\n"); + specs->max_x = block[1]; + specs->max_y = block[2]; + DPRINTK(" Max H-size in cm: "); + if (specs->max_x) + DPRINTK("%d\n", specs->max_x); + else + DPRINTK("variable\n"); + DPRINTK(" Max V-size in cm: "); + if (specs->max_y) + DPRINTK("%d\n", specs->max_y); + else + DPRINTK("variable\n"); + + c = block[3]; + specs->gamma = c+100; + DPRINTK(" Gamma: "); + DPRINTK("%d.%d\n", specs->gamma/100, specs->gamma % 100); + + get_dpms_capabilities(block[4], specs); + + switch ((block[4] & 0x18) >> 3) { + case 0: + DPRINTK(" Monochrome/Grayscale\n"); + specs->input |= FB_DISP_MONO; + break; + case 1: + DPRINTK(" RGB Color Display\n"); + specs->input |= FB_DISP_RGB; + break; + case 2: + DPRINTK(" Non-RGB Multicolor Display\n"); + specs->input |= FB_DISP_MULTI; + break; + default: + DPRINTK(" Unknown\n"); + specs->input |= FB_DISP_UNKNOWN; + break; + } + + get_chroma(block, specs); + + specs->misc = 0; + c = block[4] & 0x7; + if (c & 0x04) { + DPRINTK(" Default color format is primary\n"); + specs->misc |= FB_MISC_PRIM_COLOR; + } + if (c & 0x02) { + DPRINTK(" First DETAILED Timing is preferred\n"); + specs->misc |= FB_MISC_1ST_DETAIL; + } + if (c & 0x01) { + printk(" Display is GTF capable\n"); + specs->gtf = 1; + } +} + +static int edid_is_timing_block(unsigned char *block) +{ + if ((block[0] != 0x00) || (block[1] != 0x00) || + (block[2] != 0x00) || (block[4] != 0x00)) + return 1; + else + return 0; +} + +int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var) +{ + int i; + unsigned char *block; + + if (edid == NULL || var == NULL) + return 1; + + if (!(edid_checksum(edid))) + return 1; + + if (!(edid_check_header(edid))) + return 1; + + block = edid + DETAILED_TIMING_DESCRIPTIONS_START; + + for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) { + if (edid_is_timing_block(block)) { + var->xres = var->xres_virtual = H_ACTIVE; + var->yres = var->yres_virtual = V_ACTIVE; + var->height = var->width = -1; + var->right_margin = H_SYNC_OFFSET; + var->left_margin = (H_ACTIVE + H_BLANKING) - + (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH); + var->upper_margin = V_BLANKING - V_SYNC_OFFSET - + V_SYNC_WIDTH; + var->lower_margin = V_SYNC_OFFSET; + var->hsync_len = H_SYNC_WIDTH; + var->vsync_len = V_SYNC_WIDTH; + var->pixclock = PIXEL_CLOCK; + var->pixclock /= 1000; + var->pixclock = KHZ2PICOS(var->pixclock); + + if (HSYNC_POSITIVE) + var->sync |= FB_SYNC_HOR_HIGH_ACT; + if (VSYNC_POSITIVE) + var->sync |= FB_SYNC_VERT_HIGH_ACT; + return 0; + } + } + return 1; +} + +void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs) { unsigned char *block; int i; @@ -788,83 +747,52 @@ if (!(edid_check_header(edid))) return; - printk("========================================\n"); - printk("Display Information (EDID)\n"); - printk("========================================\n"); - printk(" EDID Version %d.%d\n", (int) edid[EDID_STRUCT_VERSION], - (int) edid[EDID_STRUCT_REVISION]); - parse_vendor_block(edid + ID_MANUFACTURER_NAME); + memset(specs, 0, sizeof(struct fb_monspecs)); - printk(" Display Characteristics:\n"); - parse_display_block(edid + EDID_STRUCT_DISPLAY); + specs->version = edid[EDID_STRUCT_VERSION]; + specs->revision = edid[EDID_STRUCT_REVISION]; - printk(" Standard Timings\n"); - block = edid + STD_TIMING_DESCRIPTIONS_START; - for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE) - parse_std_timing_block(block); + DPRINTK("========================================\n"); + DPRINTK("Display Information (EDID)\n"); + DPRINTK("========================================\n"); + DPRINTK(" EDID Version %d.%d\n", (int) specs->version, + (int) specs->revision); - printk(" Supported VESA Modes\n"); - parse_std_md_block(edid + ESTABLISHED_TIMING_1); + parse_vendor_block(edid + ID_MANUFACTURER_NAME, specs); - printk(" Detailed Monitor Information\n"); block = edid + DETAILED_TIMING_DESCRIPTIONS_START; for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) { if (edid_is_serial_block(block)) { - parse_serial_block(block); + copy_string(block, specs->serial_no); + DPRINTK(" Serial Number: %s\n", specs->serial_no); } else if (edid_is_ascii_block(block)) { - parse_ascii_block(block); - } else if (edid_is_limits_block(block)) { - parse_limits_block(block); + copy_string(block, specs->ascii); + DPRINTK(" ASCII Block: %s\n", specs->ascii); } else if (edid_is_monitor_block(block)) { - parse_monitor_block(block); - } else if (edid_is_color_block(block)) { - parse_color_block(block); - } else if (edid_is_std_timings_block(block)) { - parse_dst_timing_block(block); - } else if (edid_is_timing_block(block)) { - parse_detailed_timing_block(block); + copy_string(block, specs->monitor); + DPRINTK(" Monitor Name: %s\n", specs->monitor); } } - printk("========================================\n"); -} -#ifdef CONFIG_PPC_OF -char *get_EDID_from_OF(struct pci_dev *pdev) -{ - static char *propnames[] = - { "DFP,EDID", "LCD,EDID", "EDID", "EDID1", NULL }; - unsigned char *pedid = NULL; - struct device_node *dp; - int i; + DPRINTK(" Display Characteristics:\n"); + get_monspecs(edid, specs); - if (pdev == NULL) - return NULL; - dp = pci_device_to_OF_node(pdev); - while (dp != NULL) { - for (i = 0; propnames[i] != NULL; ++i) { - pedid = (unsigned char *) get_property(dp, propnames[i], NULL); - if (pedid != NULL) - return pedid; - } - dp = dp->child; - } - show_edid(pedid); - return pedid; + specs->modedb = fb_create_modedb(edid, &specs->modedb_len); + DPRINTK("========================================\n"); } -#endif -#ifdef CONFIG_X86 -char *get_EDID_from_BIOS(void *dummy) +char *get_EDID_from_firmware(struct device *dev) { - unsigned char *pedid = edid_info.dummy; - + unsigned char *pedid = NULL; + +#if defined(CONFIG_EDID_FIRMWARE) && defined(CONFIG_X86) + pedid = edid_info.dummy; if (!pedid) return NULL; - show_edid(pedid); - return pedid; -} #endif + return pedid; +} /* * VESA Generalized Timing Formula (GTF) @@ -1179,7 +1107,7 @@ * REQUIRES: * A valid info->monspecs. */ -int fb_validate_mode(struct fb_var_screeninfo *var, struct fb_info *info) +int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info) { u32 hfreq, vfreq, htotal, vtotal, pixclock; u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax; @@ -1228,16 +1156,12 @@ -EINVAL : 0; } -EXPORT_SYMBOL(parse_edid); -EXPORT_SYMBOL(show_edid); -#ifdef CONFIG_X86 -EXPORT_SYMBOL(get_EDID_from_BIOS); -#endif -#ifdef CONFIG_PPC_OF -EXPORT_SYMBOL(get_EDID_from_OF); -#endif -EXPORT_SYMBOL(fb_get_monitor_limits); +EXPORT_SYMBOL(fb_parse_edid); +EXPORT_SYMBOL(fb_edid_to_monspecs); +EXPORT_SYMBOL(get_EDID_from_firmware); + EXPORT_SYMBOL(fb_get_mode); EXPORT_SYMBOL(fb_validate_mode); EXPORT_SYMBOL(fb_create_modedb); EXPORT_SYMBOL(fb_destroy_modedb); +EXPORT_SYMBOL(fb_get_monitor_limits); diff -Nru a/drivers/video/fm2fb.c b/drivers/video/fm2fb.c --- a/drivers/video/fm2fb.c Sun Mar 14 14:20:07 2004 +++ b/drivers/video/fm2fb.c Sun Mar 14 14:20:07 2004 @@ -49,7 +49,7 @@ * not assembled with memory for the alpha channel. In this * case it could be possible to add the frame buffer into the * normal memory pool. - * + * * At relative address 0x1ffff8 of the frame buffers base address * there exists a control register with the number of * four control bits. They have the following meaning: @@ -64,7 +64,7 @@ * is not very much information about the FrameMaster II in * the world so I add these information for completeness. * - * JP1 interlace selection (1-2 non interlaced/2-3 interlaced) + * JP1 interlace selection (1-2 non interlaced/2-3 interlaced) * JP2 wait state creation (leave as is!) * JP3 wait state creation (leave as is!) * JP4 modulate composite sync on green output (1-2 composite @@ -127,12 +127,7 @@ static volatile unsigned char *fm2fb_reg; -#define arraysize(x) (sizeof(x)/sizeof(*(x))) - -static struct fb_info fb_info; -static u32 pseudo_palette[17]; - -static struct fb_fix_screeninfo fb_fix __initdata = { +static struct fb_fix_screeninfo fb_fix __devinitdata = { .smem_len = FRAMEMASTER_REG, .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_TRUECOLOR, @@ -141,12 +136,12 @@ .accel = FB_ACCEL_NONE, }; -static int fm2fb_mode __initdata = -1; +static int fm2fb_mode __devinitdata = -1; #define FM2FB_MODE_PAL 0 #define FM2FB_MODE_NTSC 1 -static struct fb_var_screeninfo fb_var_modes[] __initdata = { +static struct fb_var_screeninfo fb_var_modes[] __devinitdata = { { /* 768 x 576, 32 bpp (PAL) */ 768, 576, 768, 576, 0, 0, 32, 0, @@ -161,11 +156,10 @@ 33333, 10, 102, 10, 5, 80, 34, FB_SYNC_COMP_HIGH_ACT, 0 } }; - + /* * Interface used by the world */ -int fm2fb_init(void); static int fm2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info); @@ -174,7 +168,7 @@ static struct fb_ops fm2fb_ops = { .owner = THIS_MODULE, .fb_setcolreg = fm2fb_setcolreg, - .fb_blank = fm2fb_blank, + .fb_blank = fm2fb_blank, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, @@ -202,7 +196,7 @@ static int fm2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info) { - if (regno > 15) + if (regno > info->cmap.len) return 1; red >>= 8; green >>= 8; @@ -216,66 +210,91 @@ * Initialisation */ -int __init fm2fb_init(void) +static int __devinit fm2fb_probe(struct zorro_dev *z, + const struct zorro_device_id *id); + +static struct zorro_device_id fm2fb_devices[] __devinitdata = { + { ZORRO_PROD_BSC_FRAMEMASTER_II }, + { ZORRO_PROD_HELFRICH_RAINBOW_II }, + { 0 } +}; + +static struct zorro_driver fm2fb_driver = { + .name = "fm2fb", + .id_table = fm2fb_devices, + .probe = fm2fb_probe, +}; + +static int __devinit fm2fb_probe(struct zorro_dev *z, + const struct zorro_device_id *id) { - struct zorro_dev *z = NULL; + struct fb_info *info; unsigned long *ptr; int is_fm; int x, y; - while ((z = zorro_find_device(ZORRO_WILDCARD, z))) { - if (z->id == ZORRO_PROD_BSC_FRAMEMASTER_II) - is_fm = 1; - else if (z->id == ZORRO_PROD_HELFRICH_RAINBOW_II) - is_fm = 0; - else - continue; - - if (!request_mem_region(z->resource.start, FRAMEMASTER_SIZE, "fm2fb")) - continue; - - /* assigning memory to kernel space */ - fb_fix.smem_start = z->resource.start; - fb_info.screen_base = ioremap(fb_fix.smem_start, FRAMEMASTER_SIZE); - fb_fix.mmio_start = fb_fix.smem_start + FRAMEMASTER_REG; - fm2fb_reg = (unsigned char *)(fb_info.screen_base+FRAMEMASTER_REG); - - strcpy(fb_fix.id, is_fm ? "FrameMaster II" : "Rainbow II"); - - /* make EBU color bars on display */ - ptr = (unsigned long *)fb_fix.smem_start; - for (y = 0; y < 576; y++) { - for (x = 0; x < 96; x++) *ptr++ = 0xffffff;/* white */ - for (x = 0; x < 96; x++) *ptr++ = 0xffff00;/* yellow */ - for (x = 0; x < 96; x++) *ptr++ = 0x00ffff;/* cyan */ - for (x = 0; x < 96; x++) *ptr++ = 0x00ff00;/* green */ - for (x = 0; x < 96; x++) *ptr++ = 0xff00ff;/* magenta */ - for (x = 0; x < 96; x++) *ptr++ = 0xff0000;/* red */ - for (x = 0; x < 96; x++) *ptr++ = 0x0000ff;/* blue */ - for (x = 0; x < 96; x++) *ptr++ = 0x000000;/* black */ - } - fm2fb_blank(0, NULL); - - if (fm2fb_mode == -1) - fm2fb_mode = FM2FB_MODE_PAL; - - fb_info.fbops = &fm2fb_ops; - fb_info.var = fb_var_modes[fm2fb_mode]; - fb_info.screen_base = (char *)fb_fix.smem_start; - fb_info.pseudo_palette = pseudo_palette; - fb_info.fix = fb_fix; - fb_info.flags = FBINFO_FLAG_DEFAULT; + is_fm = z->id == ZORRO_PROD_BSC_FRAMEMASTER_II; + + if (!zorro_request_device(z,"fm2fb")) + return -ENXIO; - /* The below fields will go away !!!! */ - fb_alloc_cmap(&fb_info.cmap, 16, 0); + info = framebuffer_alloc(256 * sizeof(u32), &z->dev); + if (!info) { + zorro_release_device(z); + return -ENOMEM; + } - if (register_framebuffer(&fb_info) < 0) - return -EINVAL; + if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) { + framebuffer_release(info); + zorro_release_device(z); + return -ENOMEM; + } - printk("fb%d: %s frame buffer device\n", fb_info.node, fb_fix.id); - return 0; + /* assigning memory to kernel space */ + fb_fix.smem_start = zorro_resource_start(z); + info->screen_base = ioremap(fb_fix.smem_start, FRAMEMASTER_SIZE); + fb_fix.mmio_start = fb_fix.smem_start + FRAMEMASTER_REG; + fm2fb_reg = (unsigned char *)(info->screen_base+FRAMEMASTER_REG); + + strcpy(fb_fix.id, is_fm ? "FrameMaster II" : "Rainbow II"); + + /* make EBU color bars on display */ + ptr = (unsigned long *)fb_fix.smem_start; + for (y = 0; y < 576; y++) { + for (x = 0; x < 96; x++) *ptr++ = 0xffffff;/* white */ + for (x = 0; x < 96; x++) *ptr++ = 0xffff00;/* yellow */ + for (x = 0; x < 96; x++) *ptr++ = 0x00ffff;/* cyan */ + for (x = 0; x < 96; x++) *ptr++ = 0x00ff00;/* green */ + for (x = 0; x < 96; x++) *ptr++ = 0xff00ff;/* magenta */ + for (x = 0; x < 96; x++) *ptr++ = 0xff0000;/* red */ + for (x = 0; x < 96; x++) *ptr++ = 0x0000ff;/* blue */ + for (x = 0; x < 96; x++) *ptr++ = 0x000000;/* black */ + } + fm2fb_blank(0, info); + + if (fm2fb_mode == -1) + fm2fb_mode = FM2FB_MODE_PAL; + + info->fbops = &fm2fb_ops; + info->var = fb_var_modes[fm2fb_mode]; + info->pseudo_palette = info->par; + info->par = NULL; + info->fix = fb_fix; + info->flags = FBINFO_FLAG_DEFAULT; + + if (register_framebuffer(info) < 0) { + fb_dealloc_cmap(&info->cmap); + framebuffer_release(info); + zorro_release_device(z); + return -EINVAL; } - return -ENXIO; + printk("fb%d: %s frame buffer device\n", info->node, fb_fix.id); + return 0; +} + +int __init fm2fb_init(void) +{ + return zorro_register_driver(&fm2fb_driver); } int __init fm2fb_setup(char *options) @@ -285,7 +304,7 @@ if (!options || !*options) return 0; - while ((this_opt = strsep(&options, ",")) != NULL) { + while ((this_opt = strsep(&options, ",")) != NULL) { if (!strncmp(this_opt, "pal", 3)) fm2fb_mode = FM2FB_MODE_PAL; else if (!strncmp(this_opt, "ntsc", 4)) diff -Nru a/drivers/video/i810/i810_main.h b/drivers/video/i810/i810_main.h --- a/drivers/video/i810/i810_main.h Sun Mar 14 14:20:07 2004 +++ b/drivers/video/i810/i810_main.h Sun Mar 14 14:20:07 2004 @@ -84,7 +84,7 @@ extern void i810fb_load_front (u32 offset, struct fb_info *info); /* Conditionals */ -#if defined(__i386__) +#ifdef CONFIG_X86 inline void flush_cache(void) { asm volatile ("wbinvd":::"memory"); diff -Nru a/drivers/video/modedb.c b/drivers/video/modedb.c --- a/drivers/video/modedb.c Sun Mar 14 14:20:07 2004 +++ b/drivers/video/modedb.c Sun Mar 14 14:20:07 2004 @@ -39,7 +39,7 @@ #define DEFAULT_MODEDB_INDEX 0 -static const struct fb_videomode modedb[] __initdata = { +static const struct fb_videomode modedb[] = { { /* 640x400 @ 70 Hz, 31.5 kHz hsync */ NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2, @@ -130,11 +130,11 @@ 0, FB_VMODE_NONINTERLACED }, { /* 1400x1050 @ 75,107 Hz, 82,392 kHz +hsync +vsync*/ - "LCD_XGA_75", 75, 1400, 1050, 9271, 120, 56, 13, 0, 112, 3, + NULL, 75, 1400, 1050, 9271, 120, 56, 13, 0, 112, 3, FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, { /* 1400x1050 @ 60 Hz, ? kHz +hsync +vsync*/ - "LCD_XGA_60", 60, 1400, 1050, 9259, 128, 40, 12, 0, 112, 3, + NULL, 60, 1400, 1050, 9259, 128, 40, 12, 0, 112, 3, FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, { /* 1024x768 @ 85 Hz, 70.24 kHz hsync */ @@ -254,109 +254,128 @@ const struct fb_videomode vesa_modes[] = { /* 0 640x350-85 VESA */ { NULL, 85, 640, 350, 31746, 96, 32, 60, 32, 64, 3, - FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA}, /* 1 640x400-85 VESA */ { NULL, 85, 640, 400, 31746, 96, 32, 41, 01, 64, 3, - FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 2 720x400-85 VESA */ { NULL, 85, 721, 400, 28169, 108, 36, 42, 01, 72, 3, - FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 3 640x480-60 VESA */ { NULL, 60, 640, 480, 39682, 48, 16, 33, 10, 96, 2, - 0, FB_VMODE_NONINTERLACED }, + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 4 640x480-72 VESA */ { NULL, 72, 640, 480, 31746, 128, 24, 29, 9, 40, 2, - 0, FB_VMODE_NONINTERLACED }, + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 5 640x480-75 VESA */ { NULL, 75, 640, 480, 31746, 120, 16, 16, 01, 64, 3, - 0, FB_VMODE_NONINTERLACED }, + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 6 640x480-85 VESA */ { NULL, 85, 640, 480, 27777, 80, 56, 25, 01, 56, 3, - 0, FB_VMODE_NONINTERLACED }, + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 7 800x600-56 VESA */ { NULL, 56, 800, 600, 27777, 128, 24, 22, 01, 72, 2, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 8 800x600-60 VESA */ { NULL, 60, 800, 600, 25000, 88, 40, 23, 01, 128, 4, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 9 800x600-72 VESA */ { NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 10 800x600-75 VESA */ { NULL, 75, 800, 600, 20202, 160, 16, 21, 01, 80, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 11 800x600-85 VESA */ { NULL, 85, 800, 600, 17761, 152, 32, 27, 01, 64, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 12 1024x768i-43 VESA */ { NULL, 53, 1024, 768, 22271, 56, 8, 41, 0, 176, 8, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_INTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_INTERLACED, FB_MODE_IS_VESA }, /* 13 1024x768-60 VESA */ { NULL, 60, 1024, 768, 15384, 160, 24, 29, 3, 136, 6, - 0, FB_VMODE_NONINTERLACED }, + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 14 1024x768-70 VESA */ { NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6, - 0, FB_VMODE_NONINTERLACED }, + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 15 1024x768-75 VESA */ { NULL, 75, 1024, 768, 12690, 176, 16, 28, 1, 96, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 16 1024x768-85 VESA */ { NULL, 85, 1024, 768, 10582, 208, 48, 36, 1, 96, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 17 1152x864-75 VESA */ { NULL, 75, 1153, 864, 9259, 256, 64, 32, 1, 128, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 18 1280x960-60 VESA */ { NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 19 1280x960-85 VESA */ { NULL, 85, 1280, 960, 6734, 224, 64, 47, 1, 160, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 20 1280x1024-60 VESA */ { NULL, 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 21 1280x1024-75 VESA */ { NULL, 75, 1280, 1024, 7407, 248, 16, 38, 1, 144, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 22 1280x1024-85 VESA */ { NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 23 1600x1200-60 VESA */ { NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 24 1600x1200-65 VESA */ { NULL, 65, 1600, 1200, 5698, 304, 64, 46, 1, 192, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 25 1600x1200-70 VESA */ { NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 26 1600x1200-75 VESA */ { NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 27 1600x1200-85 VESA */ { NULL, 85, 1600, 1200, 4357, 304, 64, 46, 1, 192, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 28 1792x1344-60 VESA */ { NULL, 60, 1792, 1344, 4882, 328, 128, 46, 1, 200, 3, - FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 29 1792x1344-75 VESA */ { NULL, 75, 1792, 1344, 3831, 352, 96, 69, 1, 216, 3, - FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 30 1856x1392-60 VESA */ { NULL, 60, 1856, 1392, 4580, 352, 96, 43, 1, 224, 3, - FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 31 1856x1392-75 VESA */ { NULL, 75, 1856, 1392, 3472, 352, 128, 104, 1, 224, 3, - FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 32 1920x1440-60 VESA */ { NULL, 60, 1920, 1440, 4273, 344, 128, 56, 1, 200, 3, - FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, /* 33 1920x1440-75 VESA */ { NULL, 60, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3, - FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }, + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA }, }; -static int __init my_atoi(const char *name) +static int my_atoi(const char *name) { int val = 0; @@ -447,11 +466,11 @@ * */ -int __init fb_find_mode(struct fb_var_screeninfo *var, - struct fb_info *info, const char *mode_option, - const struct fb_videomode *db, unsigned int dbsize, - const struct fb_videomode *default_mode, - unsigned int default_bpp) +int fb_find_mode(struct fb_var_screeninfo *var, + struct fb_info *info, const char *mode_option, + const struct fb_videomode *db, unsigned int dbsize, + const struct fb_videomode *default_mode, + unsigned int default_bpp) { int i, j; diff -Nru a/fs/Kconfig b/fs/Kconfig --- a/fs/Kconfig Sun Mar 14 14:20:07 2004 +++ b/fs/Kconfig Sun Mar 14 14:20:07 2004 @@ -1227,6 +1227,9 @@ experimental "UFS file system write support", below. Please read the file for more information. + The recently released UFS2 variant (used in FreeBSD 5.x) is + READ-ONLY supported. + If you only intend to mount files from some other Unix over the network using NFS, you don't need the UFS file system support (but you need NFS file system support obviously). @@ -1302,15 +1305,18 @@ Say Y here if you want your NFS client to be able to speak the newer version 3 of the NFS protocol. - If unsure, say N. + If unsure, say Y. config NFS_V4 bool "Provide NFSv4 client support (EXPERIMENTAL)" depends on NFS_FS && EXPERIMENTAL + select RPCSEC_GSS_KRB5 help Say Y here if you want your NFS client to be able to speak the newer - version 4 of the NFS protocol. This feature is experimental, and - should only be used if you are interested in helping to test NFSv4. + version 4 of the NFS protocol. + + Note: Requires auxiliary userspace daemons which may be found on + http://www.citi.umich.edu/projects/nfsv4/ If unsure, say N. @@ -1419,28 +1425,24 @@ tristate config SUNRPC_GSS - tristate "Provide RPCSEC_GSS authentication (EXPERIMENTAL)" + tristate + +config RPCSEC_GSS_KRB5 + tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)" depends on SUNRPC && EXPERIMENTAL - default SUNRPC if NFS_V4=y + select SUNRPC_GSS + select CRYPTO + select CRYPTO_MD5 + select CRYPTO_DES help - Provides cryptographic authentication for NFS rpc requests. To - make this useful, you must also select at least one rpcsec_gss - mechanism. - Note: You should always select this option if you wish to use + Provides for secure RPC calls by means of a gss-api + mechanism based on Kerberos V5. This is required for NFSv4. -config RPCSEC_GSS_KRB5 - tristate "Kerberos V mechanism for RPCSEC_GSS (EXPERIMENTAL)" - depends on SUNRPC_GSS && CRYPTO_DES && CRYPTO_MD5 - default SUNRPC_GSS if NFS_V4=y - help - Provides a gss-api mechanism based on Kerberos V5 (this is - mandatory for RFC3010-compliant NFSv4 implementations). - Requires a userspace daemon; - see http://www.citi.umich.edu/projects/nfsv4/. + Note: Requires an auxiliary userspace daemon which may be found on + http://www.citi.umich.edu/projects/nfsv4/ - Note: If you select this option, please ensure that you also - enable the MD5 and DES crypto ciphers. + If unsure, say N. config SMB_FS tristate "SMB file system support (to mount Windows shares etc.)" diff -Nru a/fs/adfs/super.c b/fs/adfs/super.c --- a/fs/adfs/super.c Sun Mar 14 14:20:05 2004 +++ b/fs/adfs/super.c Sun Mar 14 14:20:05 2004 @@ -335,6 +335,8 @@ struct adfs_sb_info *asb; struct inode *root; + sb->s_flags |= MS_NODIRATIME; + asb = kmalloc(sizeof(*asb), GFP_KERNEL); if (!asb) return -ENOMEM; diff -Nru a/fs/affs/super.c b/fs/affs/super.c --- a/fs/affs/super.c Sun Mar 14 14:20:07 2004 +++ b/fs/affs/super.c Sun Mar 14 14:20:07 2004 @@ -293,6 +293,7 @@ sb->s_magic = AFFS_SUPER_MAGIC; sb->s_op = &affs_sops; + sb->s_flags |= MS_NODIRATIME; sbi = kmalloc(sizeof(struct affs_sb_info), GFP_KERNEL); if (!sbi) diff -Nru a/fs/afs/inode.c b/fs/afs/inode.c --- a/fs/afs/inode.c Sun Mar 14 14:20:06 2004 +++ b/fs/afs/inode.c Sun Mar 14 14:20:06 2004 @@ -188,6 +188,7 @@ #endif /* okay... it's a new inode */ + inode->i_flags |= S_NOATIME; vnode->flags |= AFS_VNODE_CHANGED; ret = afs_inode_fetch_status(inode); if (ret<0) diff -Nru a/fs/afs/super.c b/fs/afs/super.c --- a/fs/afs/super.c Sun Mar 14 14:20:07 2004 +++ b/fs/afs/super.c Sun Mar 14 14:20:07 2004 @@ -53,6 +53,7 @@ .name = "afs", .get_sb = afs_get_sb, .kill_sb = kill_anon_super, + .fs_flags = FS_BINARY_MOUNTDATA, }; static struct super_operations afs_super_ops = { diff -Nru a/fs/bfs/dir.c b/fs/bfs/dir.c --- a/fs/bfs/dir.c Sun Mar 14 14:20:08 2004 +++ b/fs/bfs/dir.c Sun Mar 14 14:20:08 2004 @@ -65,7 +65,6 @@ brelse(bh); } - update_atime(dir); unlock_kernel(); return 0; } diff -Nru a/fs/binfmt_elf.c b/fs/binfmt_elf.c --- a/fs/binfmt_elf.c Sun Mar 14 14:20:07 2004 +++ b/fs/binfmt_elf.c Sun Mar 14 14:20:07 2004 @@ -830,9 +830,8 @@ and some applications "depend" upon this behavior. Since we do not have the power to recompile these, we emulate the SVr4 behavior. Sigh. */ - /* N.B. Shouldn't the size here be PAGE_SIZE?? */ down_write(¤t->mm->mmap_sem); - error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC, + error = do_mmap(NULL, 0, PAGE_SIZE, PROT_READ | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, 0); up_write(¤t->mm->mmap_sem); } diff -Nru a/fs/block_dev.c b/fs/block_dev.c --- a/fs/block_dev.c Sun Mar 14 14:20:09 2004 +++ b/fs/block_dev.c Sun Mar 14 14:20:09 2004 @@ -116,9 +116,18 @@ blkdev_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh, int create) { - if (iblock >= max_block(I_BDEV(inode))) - return -EIO; - + if (iblock >= max_block(I_BDEV(inode))) { + if (create) + return -EIO; + + /* + * for reads, we're just trying to fill a partial page. + * return a hole, they will have to call get_block again + * before they can fill it, and they will get -EIO at that + * time + */ + return 0; + } bh->b_bdev = I_BDEV(inode); bh->b_blocknr = iblock; set_buffer_mapped(bh); @@ -522,7 +531,7 @@ EXPORT_SYMBOL(check_disk_change); -static void bd_set_size(struct block_device *bdev, loff_t size) +void bd_set_size(struct block_device *bdev, loff_t size) { unsigned bsize = bdev_hardsect_size(bdev); @@ -535,6 +544,7 @@ bdev->bd_block_size = bsize; bdev->bd_inode->i_blkbits = blksize_bits(bsize); } +EXPORT_SYMBOL(bd_set_size); static int do_open(struct block_device *bdev, struct file *file) { diff -Nru a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c --- a/fs/cifs/cifsfs.c Sun Mar 14 14:20:07 2004 +++ b/fs/cifs/cifsfs.c Sun Mar 14 14:20:07 2004 @@ -77,6 +77,7 @@ struct cifs_sb_info *cifs_sb; int rc = 0; + sb->s_flags |= MS_NODIRATIME; /* and probably even noatime */ sb->s_fs_info = kmalloc(sizeof(struct cifs_sb_info),GFP_KERNEL); cifs_sb = CIFS_SB(sb); if(cifs_sb == NULL) diff -Nru a/fs/coda/dir.c b/fs/coda/dir.c --- a/fs/coda/dir.c Sun Mar 14 14:20:06 2004 +++ b/fs/coda/dir.c Sun Mar 14 14:20:06 2004 @@ -510,8 +510,10 @@ goto out; ret = -ENOENT; - if (!IS_DEADDIR(host_inode)) + if (!IS_DEADDIR(host_inode)) { ret = host_file->f_op->readdir(host_file, filldir, dirent); + update_atime(host_inode); + } } out: coda_file->f_pos = host_file->f_pos; diff -Nru a/fs/coda/inode.c b/fs/coda/inode.c --- a/fs/coda/inode.c Sun Mar 14 14:20:07 2004 +++ b/fs/coda/inode.c Sun Mar 14 14:20:07 2004 @@ -171,6 +171,7 @@ sbi->sbi_vcomm = vc; sb->s_fs_info = sbi; + sb->s_flags |= MS_NODIRATIME; /* probably even noatime */ sb->s_blocksize = 1024; /* XXXXX what do we put here?? */ sb->s_blocksize_bits = 10; sb->s_magic = CODA_SUPER_MAGIC; @@ -308,5 +309,6 @@ .name = "coda", .get_sb = coda_get_sb, .kill_sb = kill_anon_super, + .fs_flags = FS_BINARY_MOUNTDATA, }; diff -Nru a/fs/cramfs/inode.c b/fs/cramfs/inode.c --- a/fs/cramfs/inode.c Sun Mar 14 14:20:06 2004 +++ b/fs/cramfs/inode.c Sun Mar 14 14:20:06 2004 @@ -201,6 +201,8 @@ struct cramfs_sb_info *sbi; struct inode *root; + sb->s_flags |= MS_RDONLY; + sbi = kmalloc(sizeof(struct cramfs_sb_info), GFP_KERNEL); if (!sbi) return -ENOMEM; diff -Nru a/fs/ext2/acl.c b/fs/ext2/acl.c --- a/fs/ext2/acl.c Sun Mar 14 14:20:08 2004 +++ b/fs/ext2/acl.c Sun Mar 14 14:20:08 2004 @@ -154,10 +154,9 @@ static struct posix_acl * ext2_get_acl(struct inode *inode, int type) { - const size_t max_size = ext2_acl_size(EXT2_ACL_MAX_ENTRIES); struct ext2_inode_info *ei = EXT2_I(inode); int name_index; - char *value; + char *value = NULL; struct posix_acl *acl; int retval; @@ -182,17 +181,21 @@ default: return ERR_PTR(-EINVAL); } - value = kmalloc(max_size, GFP_KERNEL); - if (!value) - return ERR_PTR(-ENOMEM); - - retval = ext2_xattr_get(inode, name_index, "", value, max_size); - acl = ERR_PTR(retval); - if (retval >= 0) + retval = ext2_xattr_get(inode, name_index, "", NULL, 0); + if (retval > 0) { + value = kmalloc(retval, GFP_KERNEL); + if (!value) + return ERR_PTR(-ENOMEM); + retval = ext2_xattr_get(inode, name_index, "", value, retval); + } + if (retval > 0) acl = ext2_acl_from_disk(value, retval); else if (retval == -ENODATA || retval == -ENOSYS) acl = NULL; - kfree(value); + else + acl = ERR_PTR(retval); + if (value) + kfree(value); if (!IS_ERR(acl)) { switch(type) { diff -Nru a/fs/ext2/dir.c b/fs/ext2/dir.c --- a/fs/ext2/dir.c Sun Mar 14 14:20:07 2004 +++ b/fs/ext2/dir.c Sun Mar 14 14:20:07 2004 @@ -310,7 +310,6 @@ done: filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset; filp->f_version = inode->i_version; - update_atime(inode); return 0; } diff -Nru a/fs/ext3/acl.c b/fs/ext3/acl.c --- a/fs/ext3/acl.c Sun Mar 14 14:20:06 2004 +++ b/fs/ext3/acl.c Sun Mar 14 14:20:06 2004 @@ -157,10 +157,9 @@ static struct posix_acl * ext3_get_acl(struct inode *inode, int type) { - const size_t max_size = ext3_acl_size(EXT3_ACL_MAX_ENTRIES); struct ext3_inode_info *ei = EXT3_I(inode); int name_index; - char *value; + char *value = NULL; struct posix_acl *acl; int retval; @@ -185,17 +184,21 @@ default: return ERR_PTR(-EINVAL); } - value = kmalloc(max_size, GFP_KERNEL); - if (!value) - return ERR_PTR(-ENOMEM); - - retval = ext3_xattr_get(inode, name_index, "", value, max_size); - acl = ERR_PTR(retval); + retval = ext3_xattr_get(inode, name_index, "", NULL, 0); + if (retval > 0) { + value = kmalloc(retval, GFP_KERNEL); + if (!value) + return ERR_PTR(-ENOMEM); + retval = ext3_xattr_get(inode, name_index, "", value, retval); + } if (retval > 0) acl = ext3_acl_from_disk(value, retval); else if (retval == -ENODATA || retval == -ENOSYS) acl = NULL; - kfree(value); + else + acl = ERR_PTR(retval); + if (value) + kfree(value); if (!IS_ERR(acl)) { switch(type) { diff -Nru a/fs/ext3/dir.c b/fs/ext3/dir.c --- a/fs/ext3/dir.c Sun Mar 14 14:20:07 2004 +++ b/fs/ext3/dir.c Sun Mar 14 14:20:07 2004 @@ -224,7 +224,6 @@ offset = 0; brelse (bh); } - update_atime(inode); out: return ret; } @@ -506,7 +505,6 @@ } finished: info->last_pos = filp->f_pos; - update_atime(inode); return 0; } diff -Nru a/fs/fat/inode.c b/fs/fat/inode.c --- a/fs/fat/inode.c Sun Mar 14 14:20:07 2004 +++ b/fs/fat/inode.c Sun Mar 14 14:20:07 2004 @@ -778,6 +778,7 @@ sb->s_fs_info = sbi; memset(sbi, 0, sizeof(struct msdos_sb_info)); + sb->s_flags |= MS_NODIRATIME; sb->s_magic = MSDOS_SUPER_MAGIC; sb->s_op = &fat_sops; sb->s_export_op = &fat_export_ops; diff -Nru a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c --- a/fs/freevxfs/vxfs_super.c Sun Mar 14 14:20:08 2004 +++ b/fs/freevxfs/vxfs_super.c Sun Mar 14 14:20:08 2004 @@ -145,6 +145,8 @@ u_long bsize; struct inode *root; + sbp->s_flags |= MS_RDONLY; + infp = kmalloc(sizeof(*infp), GFP_KERNEL); if (!infp) { printk(KERN_WARNING "vxfs: unable to allocate incore superblock\n"); diff -Nru a/fs/hfs/super.c b/fs/hfs/super.c --- a/fs/hfs/super.c Sun Mar 14 14:20:06 2004 +++ b/fs/hfs/super.c Sun Mar 14 14:20:06 2004 @@ -268,6 +268,7 @@ } sb->s_op = &hfs_super_operations; + sb->s_flags |= MS_NODIRATIME; init_MUTEX(&sbi->bitmap_lock); res = hfs_mdb_get(sb); diff -Nru a/fs/inode.c b/fs/inode.c --- a/fs/inode.c Sun Mar 14 14:20:08 2004 +++ b/fs/inode.c Sun Mar 14 14:20:08 2004 @@ -1178,6 +1178,8 @@ struct timespec now; int sync_it = 0; + if (IS_NOCMTIME(inode)) + return; if (IS_RDONLY(inode)) return; diff -Nru a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c --- a/fs/jffs/inode-v23.c Sun Mar 14 14:20:07 2004 +++ b/fs/jffs/inode-v23.c Sun Mar 14 14:20:07 2004 @@ -70,6 +70,8 @@ struct inode *root_inode; struct jffs_control *c; + sb->s_flags |= MS_NODIRATIME; + D1(printk(KERN_NOTICE "JFFS: Trying to mount device %s.\n", sb->s_id)); diff -Nru a/fs/jffs2/super.c b/fs/jffs2/super.c --- a/fs/jffs2/super.c Sun Mar 14 14:20:06 2004 +++ b/fs/jffs2/super.c Sun Mar 14 14:20:06 2004 @@ -129,6 +129,7 @@ mtd->index, mtd->name)); sb->s_op = &jffs2_super_operations; + sb->s_flags |= MS_NODIRATIME; ret = jffs2_do_fill_super(sb, data, (flags&MS_VERBOSE)?1:0); diff -Nru a/fs/libfs.c b/fs/libfs.c --- a/fs/libfs.c Sun Mar 14 14:20:05 2004 +++ b/fs/libfs.c Sun Mar 14 14:20:05 2004 @@ -155,7 +155,6 @@ } spin_unlock(&dcache_lock); } - update_atime(dentry->d_inode); return 0; } diff -Nru a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c --- a/fs/lockd/clntproc.c Sun Mar 14 14:20:06 2004 +++ b/fs/lockd/clntproc.c Sun Mar 14 14:20:06 2004 @@ -443,7 +443,7 @@ } if (status < 0) return status; - } while (resp->status == NLM_LCK_BLOCKED); + } while (resp->status == NLM_LCK_BLOCKED && req->a_args.block); if (resp->status == NLM_LCK_GRANTED) { fl->fl_u.nfs_fl.state = host->h_state; diff -Nru a/fs/lockd/host.c b/fs/lockd/host.c --- a/fs/lockd/host.c Sun Mar 14 14:20:07 2004 +++ b/fs/lockd/host.c Sun Mar 14 14:20:07 2004 @@ -188,14 +188,14 @@ } } else { xprt = xprt_create_proto(host->h_proto, &host->h_addr, NULL); - if (xprt == NULL) + if (IS_ERR(xprt)) goto forgetit; xprt_set_timeout(&xprt->timeout, 5, nlmsvc_timeout); clnt = rpc_create_client(xprt, host->h_name, &nlm_program, host->h_version, host->h_authflavor); - if (clnt == NULL) { + if (IS_ERR(clnt)) { xprt_destroy(xprt); goto forgetit; } diff -Nru a/fs/lockd/mon.c b/fs/lockd/mon.c --- a/fs/lockd/mon.c Sun Mar 14 14:20:08 2004 +++ b/fs/lockd/mon.c Sun Mar 14 14:20:08 2004 @@ -36,10 +36,11 @@ int status; struct nsm_args args; - status = -EACCES; clnt = nsm_create(); - if (!clnt) + if (IS_ERR(clnt)) { + status = PTR_ERR(clnt); goto out; + } args.addr = host->h_addr.sin_addr.s_addr; args.proto= (host->h_proto<<1) | host->h_server; @@ -104,7 +105,7 @@ nsm_create(void) { struct rpc_xprt *xprt; - struct rpc_clnt *clnt = NULL; + struct rpc_clnt *clnt; struct sockaddr_in sin; sin.sin_family = AF_INET; @@ -112,24 +113,23 @@ sin.sin_port = 0; xprt = xprt_create_proto(IPPROTO_UDP, &sin, NULL); - if (!xprt) - goto out; + if (IS_ERR(xprt)) + return (struct rpc_clnt *)xprt; clnt = rpc_create_client(xprt, "localhost", &nsm_program, SM_VERSION, RPC_AUTH_NULL); - if (!clnt) + if (IS_ERR(clnt)) goto out_destroy; clnt->cl_softrtry = 1; clnt->cl_chatty = 1; clnt->cl_oneshot = 1; xprt->resvport = 1; /* NSM requires a reserved port */ -out: return clnt; out_destroy: xprt_destroy(xprt); - goto out; + return clnt; } /* diff -Nru a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c --- a/fs/lockd/svc4proc.c Sun Mar 14 14:20:07 2004 +++ b/fs/lockd/svc4proc.c Sun Mar 14 14:20:07 2004 @@ -453,6 +453,24 @@ } /* + * client sent a GRANTED_RES, let's remove the associated block + */ +static int +nlm4svc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp, + void *resp) +{ + if (!nlmsvc_ops) + return rpc_success; + + dprintk("lockd: GRANTED_RES called\n"); + + nlmsvc_grant_reply(rqstp, &argp->cookie, argp->status); + return rpc_success; +} + + + +/* * This is the generic lockd callback for async RPC calls */ static u32 @@ -515,7 +533,6 @@ #define nlm4svc_proc_lock_res nlm4svc_proc_null #define nlm4svc_proc_cancel_res nlm4svc_proc_null #define nlm4svc_proc_unlock_res nlm4svc_proc_null -#define nlm4svc_proc_granted_res nlm4svc_proc_null struct nlm_void { int dummy; }; @@ -548,7 +565,7 @@ PROC(lock_res, lockres, norep, res, void, 1), PROC(cancel_res, cancelres, norep, res, void, 1), PROC(unlock_res, unlockres, norep, res, void, 1), - PROC(granted_res, grantedres, norep, res, void, 1), + PROC(granted_res, res, norep, res, void, 1), /* statd callback */ PROC(sm_notify, reboot, void, reboot, void, 1), PROC(none, void, void, void, void, 0), diff -Nru a/fs/lockd/svclock.c b/fs/lockd/svclock.c --- a/fs/lockd/svclock.c Sun Mar 14 14:20:06 2004 +++ b/fs/lockd/svclock.c Sun Mar 14 14:20:06 2004 @@ -64,7 +64,7 @@ if (when != NLM_NEVER) { if ((when += jiffies) == NLM_NEVER) when ++; - while ((b = *bp) && time_before_eq(b->b_when,when)) + while ((b = *bp) && time_before_eq(b->b_when,when) && b->b_when != NLM_NEVER) bp = &b->b_next; } else while ((b = *bp)) @@ -143,14 +143,15 @@ * Find a block with a given NLM cookie. */ static inline struct nlm_block * -nlmsvc_find_block(struct nlm_cookie *cookie) +nlmsvc_find_block(struct nlm_cookie *cookie, struct sockaddr_in *sin) { struct nlm_block *block; for (block = nlm_blocked; block; block = block->b_next) { dprintk("cookie: head of blocked queue %p, block %p\n", nlm_blocked, block); - if (nlm_cookie_match(&block->b_call.a_args.cookie,cookie)) + if (nlm_cookie_match(&block->b_call.a_args.cookie,cookie) + && nlm_cmp_addr(sin, &block->b_host->h_addr)) break; } @@ -566,12 +567,16 @@ struct nlm_rqst *call = (struct nlm_rqst *) task->tk_calldata; struct nlm_block *block; unsigned long timeout; + struct sockaddr_in *peer_addr = RPC_PEERADDR(task->tk_client); dprintk("lockd: GRANT_MSG RPC callback\n"); - dprintk("callback: looking for cookie %x \n", - *(unsigned int *)(call->a_args.cookie.data)); - if (!(block = nlmsvc_find_block(&call->a_args.cookie))) { - dprintk("lockd: no block for cookie %x\n", *(u32 *)(call->a_args.cookie.data)); + dprintk("callback: looking for cookie %x, host (%08x)\n", + *(unsigned int *)(call->a_args.cookie.data), + ntohl(peer_addr->sin_addr.s_addr)); + if (!(block = nlmsvc_find_block(&call->a_args.cookie, peer_addr))) { + dprintk("lockd: no block for cookie %x, host (%08x)\n", + *(u32 *)(call->a_args.cookie.data), + ntohl(peer_addr->sin_addr.s_addr)); return; } @@ -600,18 +605,21 @@ * block. */ void -nlmsvc_grant_reply(struct nlm_cookie *cookie, u32 status) +nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status) { struct nlm_block *block; struct nlm_file *file; - if (!(block = nlmsvc_find_block(cookie))) + dprintk("grant_reply: looking for cookie %x, host (%08x), s=%d \n", + *(unsigned int *)(cookie->data), + ntohl(rqstp->rq_addr.sin_addr.s_addr), status); + if (!(block = nlmsvc_find_block(cookie, &rqstp->rq_addr))) return; file = block->b_file; file->f_count++; down(&file->f_sema); - if ((block = nlmsvc_find_block(cookie)) != NULL) { + if ((block = nlmsvc_find_block(cookie,&rqstp->rq_addr)) != NULL) { if (status == NLM_LCK_DENIED_GRACE_PERIOD) { /* Try again in a couple of seconds */ nlmsvc_insert_block(block, 10 * HZ); diff -Nru a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c --- a/fs/lockd/svcproc.c Sun Mar 14 14:20:07 2004 +++ b/fs/lockd/svcproc.c Sun Mar 14 14:20:07 2004 @@ -479,6 +479,22 @@ } /* + * client sent a GRANTED_RES, let's remove the associated block + */ +static int +nlmsvc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp, + void *resp) +{ + if (!nlmsvc_ops) + return rpc_success; + + dprintk("lockd: GRANTED_RES called\n"); + + nlmsvc_grant_reply(rqstp, &argp->cookie, argp->status); + return rpc_success; +} + +/* * This is the generic lockd callback for async RPC calls */ static u32 @@ -541,7 +557,6 @@ #define nlmsvc_proc_lock_res nlmsvc_proc_null #define nlmsvc_proc_cancel_res nlmsvc_proc_null #define nlmsvc_proc_unlock_res nlmsvc_proc_null -#define nlmsvc_proc_granted_res nlmsvc_proc_null struct nlm_void { int dummy; }; @@ -576,7 +591,7 @@ PROC(lock_res, lockres, norep, res, void, 1), PROC(cancel_res, cancelres, norep, res, void, 1), PROC(unlock_res, unlockres, norep, res, void, 1), - PROC(granted_res, grantedres, norep, res, void, 1), + PROC(granted_res, res, norep, res, void, 1), /* statd callback */ PROC(sm_notify, reboot, void, reboot, void, 1), PROC(none, void, void, void, void, 1), diff -Nru a/fs/minix/dir.c b/fs/minix/dir.c --- a/fs/minix/dir.c Sun Mar 14 14:20:08 2004 +++ b/fs/minix/dir.c Sun Mar 14 14:20:08 2004 @@ -127,7 +127,6 @@ done: filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset; - update_atime(inode); unlock_kernel(); return 0; } diff -Nru a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c --- a/fs/ncpfs/inode.c Sun Mar 14 14:20:07 2004 +++ b/fs/ncpfs/inode.c Sun Mar 14 14:20:07 2004 @@ -479,6 +479,7 @@ else default_bufsize = 1024; + sb->s_flags |= MS_NODIRATIME; /* probably even noatime */ sb->s_maxbytes = 0xFFFFFFFFU; sb->s_blocksize = 1024; /* Eh... Is this correct? */ sb->s_blocksize_bits = 10; diff -Nru a/fs/nfs/dir.c b/fs/nfs/dir.c --- a/fs/nfs/dir.c Sun Mar 14 14:20:07 2004 +++ b/fs/nfs/dir.c Sun Mar 14 14:20:07 2004 @@ -139,11 +139,13 @@ struct file *file = desc->file; struct inode *inode = file->f_dentry->d_inode; struct rpc_cred *cred = nfs_file_cred(file); + unsigned long timestamp; int error; dfprintk(VFS, "NFS: nfs_readdir_filler() reading cookie %Lu into page %lu.\n", (long long)desc->entry->cookie, page->index); again: + timestamp = jiffies; error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, desc->entry->cookie, page, NFS_SERVER(inode)->dtsize, desc->plus); if (error < 0) { @@ -157,18 +159,21 @@ goto error; } SetPageUptodate(page); + NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME; /* Ensure consistent page alignment of the data. * Note: assumes we have exclusive access to this mapping either * throught inode->i_sem or some other mechanism. */ - if (page->index == 0) + if (page->index == 0) { invalidate_inode_pages(inode->i_mapping); + NFS_I(inode)->readdir_timestamp = timestamp; + } unlock_page(page); return 0; error: SetPageError(page); unlock_page(page); - invalidate_inode_pages(inode->i_mapping); + nfs_zap_caches(inode); desc->error = error; return -EIO; } @@ -381,6 +386,7 @@ page, NFS_SERVER(inode)->dtsize, desc->plus); + NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME; desc->page = page; desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ if (desc->error >= 0) { @@ -459,7 +465,15 @@ } res = 0; break; - } else if (res < 0) + } + if (res == -ETOOSMALL && desc->plus) { + NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS; + nfs_zap_caches(inode); + desc->plus = 0; + desc->entry->eof = 0; + continue; + } + if (res < 0) break; res = nfs_do_filldir(desc, dirent, filldir); @@ -481,14 +495,19 @@ * In the case it has, we assume that the dentries are untrustworthy * and may need to be looked up again. */ -static inline -int nfs_check_verifier(struct inode *dir, struct dentry *dentry) +static inline int nfs_check_verifier(struct inode *dir, struct dentry *dentry) { if (IS_ROOT(dentry)) return 1; - if (nfs_revalidate_inode(NFS_SERVER(dir), dir)) + if ((NFS_FLAGS(dir) & NFS_INO_INVALID_ATTR) != 0 + || nfs_attribute_timeout(dir)) return 0; - return time_after(dentry->d_time, NFS_MTIME_UPDATE(dir)); + return nfs_verify_change_attribute(dir, (unsigned long)dentry->d_fsdata); +} + +static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf) +{ + dentry->d_fsdata = (void *)verf; } /* @@ -528,9 +547,7 @@ /* Don't revalidate a negative dentry if we're creating a new file */ if ((ndflags & LOOKUP_CREATE) && !(ndflags & LOOKUP_CONTINUE)) return 0; - if (!nfs_check_verifier(dir, dentry)) - return 1; - return time_after(jiffies, dentry->d_time + NFS_ATTRTIMEO(dir)); + return !nfs_check_verifier(dir, dentry); } /* @@ -552,6 +569,7 @@ int error; struct nfs_fh fhandle; struct nfs_fattr fattr; + unsigned long verifier; int isopen = 0; parent = dget_parent(dentry); @@ -574,6 +592,9 @@ goto out_bad; } + /* Revalidate parent directory attribute cache */ + nfs_revalidate_inode(NFS_SERVER(dir), dir); + /* Force a full look up iff the parent directory has changed */ if (nfs_check_verifier(dir, dentry)) { if (nfs_lookup_verify_inode(inode, isopen)) @@ -581,6 +602,12 @@ goto out_valid; } + /* + * Note: we're not holding inode->i_sem and so may be racing with + * operations that change the directory. We therefore save the + * change attribute *before* we do the RPC call. + */ + verifier = nfs_save_change_attribute(dir); error = nfs_cached_lookup(dir, dentry, &fhandle, &fattr); if (!error) { if (memcmp(NFS_FH(inode), &fhandle, sizeof(struct nfs_fh))!= 0) @@ -603,6 +630,7 @@ out_valid_renew: nfs_renew_times(dentry); + nfs_set_verifier(dentry, verifier); out_valid: unlock_kernel(); dput(parent); @@ -638,6 +666,11 @@ /* Unhash it, so that ->d_iput() would be called */ return 1; } + if (!(dentry->d_sb->s_flags & MS_ACTIVE)) { + /* Unhash it, so that ancestors of killed async unlink + * files will be cleaned up during umount */ + return 1; + } return 0; } @@ -693,6 +726,8 @@ dentry->d_op = NFS_PROTO(dir)->dentry_ops; lock_kernel(); + /* Revalidate parent directory attribute cache */ + nfs_revalidate_inode(NFS_SERVER(dir), dir); /* If we're doing an exclusive create, optimize away the lookup */ if (nfs_is_exclusive_create(dir, nd)) @@ -715,6 +750,7 @@ error = 0; d_add(dentry, inode); nfs_renew_times(dentry); + nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); out_unlock: unlock_kernel(); out: @@ -768,7 +804,15 @@ /* Open the file on the server */ lock_kernel(); - inode = nfs4_atomic_open(dir, dentry, nd); + /* Revalidate parent directory attribute cache */ + nfs_revalidate_inode(NFS_SERVER(dir), dir); + + if (nd->intent.open.flags & O_CREAT) { + nfs_begin_data_update(dir); + inode = nfs4_atomic_open(dir, dentry, nd); + nfs_end_data_update(dir); + } else + inode = nfs4_atomic_open(dir, dentry, nd); unlock_kernel(); if (IS_ERR(inode)) { error = PTR_ERR(inode); @@ -790,6 +834,7 @@ no_entry: d_add(dentry, inode); nfs_renew_times(dentry); + nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); out: BUG_ON(error > 0); return ERR_PTR(error); @@ -801,13 +846,16 @@ { struct dentry *parent = NULL; struct inode *inode = dentry->d_inode; + struct inode *dir; + unsigned long verifier; int openflags, ret = 0; /* NFS only supports OPEN for regular files */ if (inode && !S_ISREG(inode->i_mode)) goto no_open; parent = dget_parent(dentry); - if (!is_atomic_open(parent->d_inode, nd)) + dir = parent->d_inode; + if (!is_atomic_open(dir, nd)) goto no_open; openflags = nd->intent.open.flags; if (openflags & O_CREAT) { @@ -821,8 +869,16 @@ /* We can't create new files, or truncate existing ones here */ openflags &= ~(O_CREAT|O_TRUNC); + /* + * Note: we're not holding inode->i_sem and so may be racing with + * operations that change the directory. We therefore save the + * change attribute *before* we do the RPC call. + */ lock_kernel(); - ret = nfs4_open_revalidate(parent->d_inode, dentry, openflags); + verifier = nfs_save_change_attribute(dir); + ret = nfs4_open_revalidate(dir, dentry, openflags); + if (!ret) + nfs_set_verifier(dentry, verifier); unlock_kernel(); out: dput(parent); @@ -869,15 +925,20 @@ struct nfs_server *server; struct nfs_entry entry; struct page *page; - unsigned long timestamp = NFS_MTIME_UPDATE(dir); + unsigned long timestamp; int res; if (!NFS_USE_READDIRPLUS(dir)) return -ENOENT; server = NFS_SERVER(dir); - if (server->flags & NFS_MOUNT_NOAC) + /* Don't use readdirplus unless the cache is stable */ + if ((server->flags & NFS_MOUNT_NOAC) != 0 + || nfs_caches_unstable(dir) + || nfs_attribute_timeout(dir)) + return -ENOENT; + if ((NFS_FLAGS(dir) & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA)) != 0) return -ENOENT; - nfs_revalidate_inode(server, dir); + timestamp = NFS_I(dir)->readdir_timestamp; entry.fh = fh; entry.fattr = fattr; @@ -931,9 +992,10 @@ if (inode) { d_instantiate(dentry, inode); nfs_renew_times(dentry); - error = 0; + nfs_set_verifier(dentry, nfs_save_change_attribute(dentry->d_parent->d_inode)); + return 0; } - return error; + error = -ENOMEM; out_err: d_drop(dentry); return error; @@ -969,11 +1031,13 @@ * does not pass the create flags. */ lock_kernel(); - nfs_zap_caches(dir); + nfs_begin_data_update(dir); inode = NFS_PROTO(dir)->create(dir, &dentry->d_name, &attr, open_flags); + nfs_end_data_update(dir); if (!IS_ERR(inode)) { d_instantiate(dentry, inode); nfs_renew_times(dentry); + nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); error = 0; } else { error = PTR_ERR(inode); @@ -1004,9 +1068,10 @@ attr.ia_valid = ATTR_MODE; lock_kernel(); - nfs_zap_caches(dir); + nfs_begin_data_update(dir); error = NFS_PROTO(dir)->mknod(dir, &dentry->d_name, &attr, rdev, &fhandle, &fattr); + nfs_end_data_update(dir); if (!error) error = nfs_instantiate(dentry, &fhandle, &fattr); else @@ -1041,9 +1106,10 @@ */ d_drop(dentry); #endif - nfs_zap_caches(dir); + nfs_begin_data_update(dir); error = NFS_PROTO(dir)->mkdir(dir, &dentry->d_name, &attr, &fhandle, &fattr); + nfs_end_data_update(dir); if (!error) error = nfs_instantiate(dentry, &fhandle, &fattr); else @@ -1060,10 +1126,12 @@ dir->i_ino, dentry->d_name.name); lock_kernel(); - nfs_zap_caches(dir); + nfs_begin_data_update(dir); error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name); - if (!error) + /* Ensure the VFS deletes this inode */ + if (error == 0 && dentry->d_inode != NULL) dentry->d_inode->i_nlink = 0; + nfs_end_data_update(dir); unlock_kernel(); return error; @@ -1119,12 +1187,21 @@ goto out; } while(sdentry->d_inode != NULL); /* need negative lookup */ - nfs_zap_caches(dir); qsilly.name = silly; qsilly.len = strlen(silly); - error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, dir, &qsilly); + nfs_begin_data_update(dir); + if (dentry->d_inode) { + nfs_begin_data_update(dentry->d_inode); + error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, + dir, &qsilly); + nfs_end_data_update(dentry->d_inode); + } else + error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, + dir, &qsilly); + nfs_end_data_update(dir); if (!error) { nfs_renew_times(dentry); + nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); d_move(dentry, sdentry); error = nfs_async_unlink(dentry); /* If we return 0 we don't unlink */ @@ -1156,14 +1233,17 @@ goto out; } - nfs_zap_caches(dir); - if (inode) - NFS_CACHEINV(inode); - error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); - if (error < 0) - goto out; - if (inode) - inode->i_nlink--; + nfs_begin_data_update(dir); + if (inode != NULL) { + nfs_begin_data_update(inode); + error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); + /* The VFS may want to delete this inode */ + if (error == 0) + inode->i_nlink--; + nfs_end_data_update(inode); + } else + error = NFS_PROTO(dir)->remove(dir, &dentry->d_name); + nfs_end_data_update(dir); out: return error; } @@ -1198,9 +1278,10 @@ spin_unlock(&dentry->d_lock); spin_unlock(&dcache_lock); error = nfs_safe_remove(dentry); - if (!error) + if (!error) { nfs_renew_times(dentry); - else if (need_rehash) + nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); + } else if (need_rehash) d_rehash(dentry); unlock_kernel(); return error; @@ -1247,9 +1328,10 @@ qsymname.len = strlen(symname); lock_kernel(); - nfs_zap_caches(dir); + nfs_begin_data_update(dir); error = NFS_PROTO(dir)->symlink(dir, &dentry->d_name, &qsymname, &attr, &sym_fh, &sym_attr); + nfs_end_data_update(dir); if (!error) { error = nfs_instantiate(dentry, &sym_fh, &sym_attr); } else { @@ -1281,9 +1363,12 @@ */ lock_kernel(); d_drop(dentry); - nfs_zap_caches(dir); - NFS_CACHEINV(inode); + + nfs_begin_data_update(dir); + nfs_begin_data_update(inode); error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name); + nfs_end_data_update(inode); + nfs_end_data_update(dir); unlock_kernel(); return error; } @@ -1388,16 +1473,23 @@ if (new_inode) d_delete(new_dentry); - nfs_zap_caches(new_dir); - nfs_zap_caches(old_dir); + nfs_begin_data_update(old_dir); + nfs_begin_data_update(new_dir); + nfs_begin_data_update(old_inode); error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name, new_dir, &new_dentry->d_name); + nfs_end_data_update(old_inode); + nfs_end_data_update(new_dir); + nfs_end_data_update(old_dir); out: if (rehash) d_rehash(rehash); - if (!error && !S_ISDIR(old_inode->i_mode)) - d_move(old_dentry, new_dentry); - nfs_renew_times(new_dentry); + if (!error) { + if (!S_ISDIR(old_inode->i_mode)) + d_move(old_dentry, new_dentry); + nfs_renew_times(new_dentry); + nfs_set_verifier(new_dentry, nfs_save_change_attribute(new_dir)); + } /* new dentry created? */ if (dentry) @@ -1451,7 +1543,8 @@ cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0); if (cache->cred == cred - && time_before(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode))) { + && time_before(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode)) + && !(NFS_FLAGS(inode) & NFS_INO_INVALID_ATTR)) { if (!(res = cache->err)) { /* Is the mask a subset of an accepted mask? */ if ((cache->mask & mask) == mask) diff -Nru a/fs/nfs/direct.c b/fs/nfs/direct.c --- a/fs/nfs/direct.c Sun Mar 14 14:20:08 2004 +++ b/fs/nfs/direct.c Sun Mar 14 14:20:08 2004 @@ -269,6 +269,7 @@ if (IS_SYNC(inode) || NFS_PROTO(inode)->version == 2 || count <= wsize) wdata.args.stable = NFS_FILE_SYNC; + nfs_begin_data_update(inode); retry: need_commit = 0; tot_bytes = 0; @@ -334,6 +335,8 @@ VERF_SIZE) != 0) goto sync_retry; } + nfs_end_data_update(inode); + NFS_FLAGS(inode) |= NFS_INO_INVALID_DATA; return tot_bytes; diff -Nru a/fs/nfs/file.c b/fs/nfs/file.c --- a/fs/nfs/file.c Sun Mar 14 14:20:07 2004 +++ b/fs/nfs/file.c Sun Mar 14 14:20:07 2004 @@ -104,11 +104,16 @@ dfprintk(VFS, "nfs: flush(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino); + if ((file->f_mode & FMODE_WRITE) == 0) + return 0; lock_kernel(); - status = nfs_wb_file(inode, file); + /* Ensure that data+attribute caches are up to date after close() */ + status = nfs_wb_all(inode); if (!status) { status = file->f_error; file->f_error = 0; + if (!status) + __nfs_revalidate_inode(NFS_SERVER(inode), inode); } unlock_kernel(); return status; @@ -179,7 +184,7 @@ dfprintk(VFS, "nfs: fsync(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino); lock_kernel(); - status = nfs_wb_file(inode, file); + status = nfs_wb_all(inode); if (!status) { status = file->f_error; file->f_error = 0; diff -Nru a/fs/nfs/inode.c b/fs/nfs/inode.c --- a/fs/nfs/inode.c Sun Mar 14 14:20:08 2004 +++ b/fs/nfs/inode.c Sun Mar 14 14:20:08 2004 @@ -47,14 +47,11 @@ * their needs. People that do NFS over a slow network, might for * instance want to reduce it to something closer to 1 for improved * interactive response. - * - * For the moment, though, we instead set it to RPC_MAXREQS, which - * is the maximum number of simultaneous RPC requests on the wire. */ -#define NFS_MAX_READAHEAD RPC_MAXREQS +#define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1) -void nfs_zap_caches(struct inode *); static void nfs_invalidate_inode(struct inode *); +static int nfs_update_inode(struct inode *, struct nfs_fattr *, unsigned long); static struct inode *nfs_alloc_inode(struct super_block *sb); static void nfs_destroy_inode(struct inode *); @@ -118,7 +115,7 @@ { int flags = sync ? FLUSH_WAIT : 0; - nfs_commit_file(inode, NULL, 0, 0, flags); + nfs_commit_inode(inode, 0, 0, flags); } static void @@ -151,6 +148,7 @@ cred = nfsi->cache_access.cred; if (cred) put_rpccred(cred); + BUG_ON(atomic_read(&nfsi->data_updates) != 0); } void @@ -230,50 +228,23 @@ /* * Obtain the root inode of the file system. */ -static int -nfs_get_root(struct inode **rooti, rpc_authflavor_t authflavor, struct super_block *sb, struct nfs_fh *rootfh) +static struct inode * +nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *fsinfo) { struct nfs_server *server = NFS_SB(sb); - struct nfs_fattr fattr = { }; + struct inode *rooti; int error; - error = server->rpc_ops->getroot(server, rootfh, &fattr); - if (error == -EACCES && authflavor > RPC_AUTH_MAXFLAVOR) { - /* - * Some authentication types (gss/krb5, most notably) - * are such that root won't be able to present a - * credential for GETATTR (ie, getroot()). - * - * We still want the mount to succeed. - * - * So we fake the attr values and mark the inode as such. - * On the first succesful traversal, we fix everything. - * The auth type test isn't quite correct, but whatever. - */ - dfprintk(VFS, "NFS: faking root inode\n"); - - fattr.fileid = 1; - fattr.nlink = 2; /* minimum for a dir */ - fattr.type = NFDIR; - fattr.mode = S_IFDIR|S_IRUGO|S_IXUGO; - fattr.size = 4096; - fattr.du.nfs3.used = 1; - fattr.valid = NFS_ATTR_FATTR|NFS_ATTR_FATTR_V3; - } else if (error < 0) { + error = server->rpc_ops->getroot(server, rootfh, fsinfo); + if (error < 0) { printk(KERN_NOTICE "nfs_get_root: getattr error = %d\n", -error); - *rooti = NULL; /* superfluous ... but safe */ - return error; + return ERR_PTR(error); } - *rooti = nfs_fhget(sb, rootfh, &fattr); - if (error == -EACCES && authflavor > RPC_AUTH_MAXFLAVOR) { - if (*rooti) { - NFS_FLAGS(*rooti) |= NFS_INO_FAKE_ROOT; - NFS_CACHEINV((*rooti)); - error = 0; - } - } - return error; + rooti = nfs_fhget(sb, rootfh, fsinfo->fattr); + if (!rooti) + return ERR_PTR(-ENOMEM); + return rooti; } /* @@ -283,7 +254,7 @@ nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor) { struct nfs_server *server; - struct inode *root_inode = NULL; + struct inode *root_inode; struct nfs_fattr fattr; struct nfs_fsinfo fsinfo = { .fattr = &fattr, @@ -299,8 +270,9 @@ sb->s_magic = NFS_SUPER_MAGIC; + root_inode = nfs_get_root(sb, &server->fh, &fsinfo); /* Did getting the root inode fail? */ - if (nfs_get_root(&root_inode, authflavor, sb, &server->fh) < 0) + if (IS_ERR(root_inode)) goto out_no_root; sb->s_root = d_alloc_root(root_inode); if (!sb->s_root) @@ -309,10 +281,6 @@ sb->s_root->d_op = server->rpc_ops->dentry_ops; /* Get some general file system info */ - if (server->rpc_ops->fsinfo(server, &server->fh, &fsinfo) < 0) { - printk(KERN_NOTICE "NFS: cannot retrieve file system info.\n"); - goto out_no_root; - } if (server->namelen == 0 && server->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0) server->namelen = pathinfo.max_namelen; @@ -368,13 +336,11 @@ rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100); return 0; /* Yargs. It didn't work out. */ -out_free_all: - if (root_inode) - iput(root_inode); - return -EINVAL; out_no_root: printk("nfs_read_super: get root inode failed\n"); - goto out_free_all; + if (!IS_ERR(root_inode)) + iput(root_inode); + return -EINVAL; } /* @@ -402,13 +368,13 @@ /* create transport and client */ xprt = xprt_create_proto(tcp ? IPPROTO_TCP : IPPROTO_UDP, &server->addr, &timeparms); - if (xprt == NULL) { + if (IS_ERR(xprt)) { printk(KERN_WARNING "NFS: cannot create RPC transport.\n"); - goto out_fail; + return (struct rpc_clnt *)xprt; } clnt = rpc_create_client(xprt, server->hostname, &nfs_program, server->rpc_ops->version, data->pseudoflavor); - if (clnt == NULL) { + if (IS_ERR(clnt)) { printk(KERN_WARNING "NFS: cannot create RPC client.\n"); goto out_fail; } @@ -421,9 +387,8 @@ return clnt; out_fail: - if (xprt) - xprt_destroy(xprt); - return NULL; + xprt_destroy(xprt); + return clnt; } /* @@ -627,13 +592,17 @@ void nfs_zap_caches(struct inode *inode) { + struct nfs_inode *nfsi = NFS_I(inode); + int mode = inode->i_mode; + NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); NFS_ATTRTIMEO_UPDATE(inode) = jiffies; - invalidate_remote_inode(inode); - memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode))); - NFS_CACHEINV(inode); + if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) + nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; + else + nfsi->flags |= NFS_INO_INVALID_ATTR; } /* @@ -673,9 +642,6 @@ return 0; if (is_bad_inode(inode)) return 0; - /* Force an attribute cache update if inode->i_count == 0 */ - if (!atomic_read(&inode->i_count)) - NFS_CACHEINV(inode); return 1; } @@ -729,7 +695,7 @@ inode->i_ino = hash; /* We can't support update_atime(), since the server will reset it */ - inode->i_flags |= S_NOATIME; + inode->i_flags |= S_NOATIME|S_NOCMTIME; inode->i_mode = fattr->mode; /* Why so? Because we want revalidate for devices/FIFOs, and * that's precisely what we have in nfs_file_inode_operations. @@ -754,10 +720,6 @@ inode->i_atime = fattr->atime; inode->i_mtime = fattr->mtime; inode->i_ctime = fattr->ctime; - nfsi->read_cache_ctime = fattr->ctime; - nfsi->read_cache_mtime = fattr->mtime; - nfsi->cache_mtime_jiffies = fattr->timestamp; - nfsi->read_cache_isize = fattr->size; if (fattr->valid & NFS_ATTR_FATTR_V4) nfsi->change_attr = fattr->change_attr; inode->i_size = nfs_size_to_loff_t(fattr->size); @@ -804,70 +766,50 @@ struct nfs_fattr fattr; int error; + if (attr->ia_valid & ATTR_SIZE) { + if (!S_ISREG(inode->i_mode) || attr->ia_size == i_size_read(inode)) + attr->ia_valid &= ~ATTR_SIZE; + } + /* Optimization: if the end result is no change, don't RPC */ attr->ia_valid &= NFS_VALID_ATTRS; if (attr->ia_valid == 0) return 0; lock_kernel(); - - /* - * Make sure the inode is up-to-date. - */ - error = nfs_revalidate_inode(NFS_SERVER(inode),inode); - if (error) { -#ifdef NFS_PARANOIA -printk("nfs_setattr: revalidate failed, error=%d\n", error); -#endif - goto out; - } - - if (!S_ISREG(inode->i_mode)) { - attr->ia_valid &= ~ATTR_SIZE; - if (attr->ia_valid == 0) - goto out; - } else { - filemap_fdatawrite(inode->i_mapping); - error = nfs_wb_all(inode); - filemap_fdatawait(inode->i_mapping); - if (error) - goto out; - /* Optimize away unnecessary truncates */ - if ((attr->ia_valid & ATTR_SIZE) && i_size_read(inode) == attr->ia_size) - attr->ia_valid &= ~ATTR_SIZE; + nfs_begin_data_update(inode); + /* Write all dirty data if we're changing file permissions or size */ + if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE)) != 0) { + if (filemap_fdatawrite(inode->i_mapping) == 0) + filemap_fdatawait(inode->i_mapping); + nfs_wb_all(inode); } - if (!attr->ia_valid) - goto out; - error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr); - if (error) - goto out; - /* - * If we changed the size or mtime, update the inode - * now to avoid invalidating the page cache. - */ - if (attr->ia_valid & ATTR_SIZE) { - if (attr->ia_size != fattr.size) - printk("nfs_setattr: attr=%Ld, fattr=%Ld??\n", - (long long) attr->ia_size, (long long)fattr.size); - vmtruncate(inode, attr->ia_size); + if (error == 0) { + nfs_refresh_inode(inode, &fattr); + if ((attr->ia_valid & ATTR_MODE) != 0) { + int mode; + mode = inode->i_mode & ~S_IALLUGO; + mode |= attr->ia_mode & S_IALLUGO; + inode->i_mode = mode; + } + if ((attr->ia_valid & ATTR_UID) != 0) + inode->i_uid = attr->ia_uid; + if ((attr->ia_valid & ATTR_GID) != 0) + inode->i_gid = attr->ia_gid; + if ((attr->ia_valid & ATTR_SIZE) != 0) { + inode->i_size = attr->ia_size; + vmtruncate(inode, attr->ia_size); + } } - - /* - * If we changed the size or mtime, update the inode - * now to avoid invalidating the page cache. - */ - if (!(fattr.valid & NFS_ATTR_WCC)) { - struct nfs_inode *nfsi = NFS_I(inode); - fattr.pre_size = nfsi->read_cache_isize; - fattr.pre_mtime = nfsi->read_cache_mtime; - fattr.pre_ctime = nfsi->read_cache_ctime; - fattr.valid |= NFS_ATTR_WCC; - } - /* Force an attribute cache update */ - NFS_CACHEINV(inode); - error = nfs_refresh_inode(inode, &fattr); -out: + if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) { + struct rpc_cred **cred = &NFS_I(inode)->cache_access.cred; + if (*cred) { + put_rpccred(*cred); + *cred = NULL; + } + } + nfs_end_data_update(inode); unlock_kernel(); return error; } @@ -895,7 +837,19 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { struct inode *inode = dentry->d_inode; - int err = nfs_revalidate_inode(NFS_SERVER(inode), inode); + struct nfs_inode *nfsi = NFS_I(inode); + int need_atime = nfsi->flags & NFS_INO_INVALID_ATIME; + int err; + + if (__IS_FLG(inode, MS_NOATIME)) + need_atime = 0; + else if (__IS_FLG(inode, MS_NODIRATIME) && S_ISDIR(inode->i_mode)) + need_atime = 0; + /* We may force a getattr if the user cares about atime */ + if (need_atime) + err = __nfs_revalidate_inode(NFS_SERVER(inode), inode); + else + err = nfs_revalidate_inode(NFS_SERVER(inode), inode); if (!err) generic_fillattr(inode, stat); return err; @@ -930,8 +884,10 @@ auth = NFS_CLIENT(inode)->cl_auth; cred = rpcauth_lookupcred(auth, 0); filp->private_data = cred; - if (filp->f_mode & FMODE_WRITE) + if ((filp->f_mode & FMODE_WRITE) != 0) { nfs_set_mmcred(inode, cred); + nfs_begin_data_update(inode); + } return 0; } @@ -940,6 +896,8 @@ struct rpc_cred *cred; lock_kernel(); + if ((filp->f_mode & FMODE_WRITE) != 0) + nfs_end_data_update(inode); cred = nfs_file_cred(filp); if (cred) put_rpccred(cred); @@ -956,6 +914,9 @@ { int status = -ESTALE; struct nfs_fattr fattr; + struct nfs_inode *nfsi = NFS_I(inode); + unsigned long verifier; + unsigned int flags; dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)\n", inode->i_sb->s_id, (long long)NFS_FILEID(inode)); @@ -965,23 +926,22 @@ goto out_nowait; if (NFS_STALE(inode) && inode != inode->i_sb->s_root->d_inode) goto out_nowait; - if (NFS_FAKE_ROOT(inode)) { - dfprintk(VFS, "NFS: not revalidating fake root\n"); - status = 0; - goto out_nowait; - } while (NFS_REVALIDATING(inode)) { status = nfs_wait_on_inode(inode, NFS_INO_REVALIDATING); if (status < 0) goto out_nowait; - if (time_before(jiffies,NFS_READTIME(inode)+NFS_ATTRTIMEO(inode))) { - status = NFS_STALE(inode) ? -ESTALE : 0; - goto out_nowait; - } + if (NFS_SERVER(inode)->flags & NFS_MOUNT_NOAC) + continue; + if (NFS_FLAGS(inode) & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ATIME)) + continue; + status = NFS_STALE(inode) ? -ESTALE : 0; + goto out_nowait; } NFS_FLAGS(inode) |= NFS_INO_REVALIDATING; + /* Protect against RPC races by saving the change attribute */ + verifier = nfs_save_change_attribute(inode); status = NFS_PROTO(inode)->getattr(inode, &fattr); if (status) { dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n", @@ -995,13 +955,36 @@ goto out; } - status = nfs_refresh_inode(inode, &fattr); + status = nfs_update_inode(inode, &fattr, verifier); if (status) { dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n", inode->i_sb->s_id, (long long)NFS_FILEID(inode), status); goto out; } + flags = nfsi->flags; + /* + * We may need to keep the attributes marked as invalid if + * we raced with nfs_end_attr_update(). + */ + if (verifier == nfsi->cache_change_attribute) + nfsi->flags &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME); + /* Do the page cache invalidation */ + if (flags & NFS_INO_INVALID_DATA) { + if (S_ISREG(inode->i_mode)) { + if (filemap_fdatawrite(inode->i_mapping) == 0) + filemap_fdatawait(inode->i_mapping); + nfs_wb_all(inode); + } + nfsi->flags &= ~NFS_INO_INVALID_DATA; + invalidate_inode_pages2(inode->i_mapping); + memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode))); + dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n", + inode->i_sb->s_id, + (long long)NFS_FILEID(inode)); + /* This ensures we revalidate dentries */ + nfsi->cache_change_attribute++; + } dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n", inode->i_sb->s_id, (long long)NFS_FILEID(inode)); @@ -1009,41 +992,107 @@ NFS_FLAGS(inode) &= ~NFS_INO_STALE; out: NFS_FLAGS(inode) &= ~NFS_INO_REVALIDATING; - wake_up(&NFS_I(inode)->nfs_i_wait); + wake_up(&nfsi->nfs_i_wait); out_nowait: unlock_kernel(); return status; } -/* - * nfs_fattr_obsolete - Test if attribute data is newer than cached data - * @inode: inode - * @fattr: attributes to test +/** + * nfs_begin_data_update + * @inode - pointer to inode + * Declare that a set of operations will update file data on the server + */ +void nfs_begin_data_update(struct inode *inode) +{ + atomic_inc(&NFS_I(inode)->data_updates); +} + +/** + * nfs_end_data_update + * @inode - pointer to inode + * Declare end of the operations that will update file data + */ +void nfs_end_data_update(struct inode *inode) +{ + struct nfs_inode *nfsi = NFS_I(inode); + + /* Mark the attribute cache for revalidation */ + nfsi->flags |= NFS_INO_INVALID_ATTR; + /* Directories and symlinks: invalidate page cache too */ + if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) + nfsi->flags |= NFS_INO_INVALID_DATA; + nfsi->cache_change_attribute ++; + atomic_dec(&nfsi->data_updates); +} + +/** + * nfs_refresh_inode - verify consistency of the inode attribute cache + * @inode - pointer to inode + * @fattr - updated attributes * - * Avoid stuffing the attribute cache with obsolete information. - * We always accept updates if the attribute cache timed out, or if - * fattr->ctime is newer than our cached value. - * If fattr->ctime matches the cached value, we still accept the update - * if it increases the file size. + * Verifies the attribute cache. If we have just changed the attributes, + * so that fattr carries weak cache consistency data, then it may + * also update the ctime/mtime/change_attribute. */ -static inline -int nfs_fattr_obsolete(struct inode *inode, struct nfs_fattr *fattr) +int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) { struct nfs_inode *nfsi = NFS_I(inode); - long cdif; + loff_t cur_size, new_isize; + int data_unstable; - if (time_after(jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo)) - goto out_valid; - cdif = fattr->ctime.tv_sec - nfsi->read_cache_ctime.tv_sec; - if (cdif == 0) - cdif = fattr->ctime.tv_nsec - nfsi->read_cache_ctime.tv_nsec; - if (cdif > 0) - goto out_valid; - /* Ugh... */ - if (cdif == 0 && fattr->size > nfsi->read_cache_isize) - goto out_valid; - return -1; - out_valid: + /* Are we in the process of updating data on the server? */ + data_unstable = nfs_caches_unstable(inode); + + if (fattr->valid & NFS_ATTR_FATTR_V4) { + if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0 + && nfsi->change_attr == fattr->pre_change_attr) + nfsi->change_attr = fattr->change_attr; + if (!data_unstable && nfsi->change_attr != fattr->change_attr) + nfsi->flags |= NFS_INO_INVALID_ATTR; + } + + if ((fattr->valid & NFS_ATTR_FATTR) == 0) + return 0; + + /* Has the inode gone and changed behind our back? */ + if (nfsi->fileid != fattr->fileid + || (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) + return -EIO; + + cur_size = i_size_read(inode); + new_isize = nfs_size_to_loff_t(fattr->size); + + /* If we have atomic WCC data, we may update some attributes */ + if ((fattr->valid & NFS_ATTR_WCC) != 0) { + if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime)) + memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); + if (timespec_equal(&inode->i_mtime, &fattr->pre_mtime)) + memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); + } + + /* Verify a few of the more important attributes */ + if (!data_unstable) { + if (!timespec_equal(&inode->i_mtime, &fattr->mtime) + || cur_size != new_isize) + nfsi->flags |= NFS_INO_INVALID_ATTR; + } else if (S_ISREG(inode->i_mode) && new_isize > cur_size) + nfsi->flags |= NFS_INO_INVALID_ATTR; + + /* Have any file permissions changed? */ + if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) + || inode->i_uid != fattr->uid + || inode->i_gid != fattr->gid) + nfsi->flags |= NFS_INO_INVALID_ATTR; + + /* Has the link count changed? */ + if (inode->i_nlink != fattr->nlink) + nfsi->flags |= NFS_INO_INVALID_ATTR; + + if (!timespec_equal(&inode->i_atime, &fattr->atime)) + nfsi->flags |= NFS_INO_INVALID_ATIME; + + nfsi->read_cache_jiffies = fattr->timestamp; return 0; } @@ -1059,65 +1108,66 @@ * * A very similar scenario holds for the dir cache. */ -int -__nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) +static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsigned long verifier) { struct nfs_inode *nfsi = NFS_I(inode); __u64 new_size; loff_t new_isize; - int invalid = 0; - int mtime_update = 0; + unsigned int invalid = 0; loff_t cur_isize; + int data_unstable; - dfprintk(VFS, "NFS: refresh_inode(%s/%ld ct=%d info=0x%x)\n", - inode->i_sb->s_id, inode->i_ino, + dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", + __FUNCTION__, inode->i_sb->s_id, inode->i_ino, atomic_read(&inode->i_count), fattr->valid); - /* First successful call after mount, fill real data. */ - if (NFS_FAKE_ROOT(inode)) { - dfprintk(VFS, "NFS: updating fake root\n"); - nfsi->fileid = fattr->fileid; - NFS_FLAGS(inode) &= ~NFS_INO_FAKE_ROOT; - } + if ((fattr->valid & NFS_ATTR_FATTR) == 0) + return 0; if (nfsi->fileid != fattr->fileid) { - printk(KERN_ERR "nfs_refresh_inode: inode number mismatch\n" + printk(KERN_ERR "%s: inode number mismatch\n" "expected (%s/0x%Lx), got (%s/0x%Lx)\n", + __FUNCTION__, inode->i_sb->s_id, (long long)nfsi->fileid, inode->i_sb->s_id, (long long)fattr->fileid); goto out_err; } - /* Throw out obsolete READDIRPLUS attributes */ - if (time_before(fattr->timestamp, NFS_READTIME(inode))) - return 0; /* * Make sure the inode's type hasn't changed. */ if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) goto out_changed; - new_size = fattr->size; - new_isize = nfs_size_to_loff_t(fattr->size); - - /* Avoid races */ - if (nfs_fattr_obsolete(inode, fattr)) - goto out_nochange; - /* * Update the read time so we don't revalidate too often. */ nfsi->read_cache_jiffies = fattr->timestamp; - /* - * Note: NFS_CACHE_ISIZE(inode) reflects the state of the cache. - * NOT inode->i_size!!! - */ - if (nfsi->read_cache_isize != new_size) { + /* Are we racing with known updates of the metadata on the server? */ + data_unstable = ! nfs_verify_change_attribute(inode, verifier); + + /* Check if the file size agrees */ + new_size = fattr->size; + new_isize = nfs_size_to_loff_t(fattr->size); + cur_isize = i_size_read(inode); + if (cur_isize != new_size) { #ifdef NFS_DEBUG_VERBOSE printk(KERN_DEBUG "NFS: isize change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino); #endif - invalid = 1; + /* + * If we have pending writebacks, things can get + * messy. + */ + if (S_ISREG(inode->i_mode) && data_unstable) { + if (new_isize > cur_isize) { + inode->i_size = new_isize; + invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; + } + } else { + inode->i_size = new_isize; + invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; + } } /* @@ -1125,12 +1175,13 @@ * can change this value in VFS without requiring a * cache revalidation. */ - if (!timespec_equal(&nfsi->read_cache_mtime, &fattr->mtime)) { + if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) { + memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime)); #ifdef NFS_DEBUG_VERBOSE printk(KERN_DEBUG "NFS: mtime change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino); #endif - invalid = 1; - mtime_update = 1; + if (!data_unstable) + invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; } if ((fattr->valid & NFS_ATTR_FATTR_V4) @@ -1139,47 +1190,15 @@ printk(KERN_DEBUG "NFS: change_attr change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino); #endif - invalid = 1; - } - - /* Check Weak Cache Consistency data. - * If size and mtime match the pre-operation values, we can - * assume that any attribute changes were caused by our NFS - * operation, so there's no need to invalidate the caches. - */ - if ((fattr->valid & NFS_ATTR_PRE_CHANGE) - && nfsi->change_attr == fattr->pre_change_attr) { - invalid = 0; - } - else if ((fattr->valid & NFS_ATTR_WCC) - && nfsi->read_cache_isize == fattr->pre_size - && timespec_equal(&nfsi->read_cache_mtime, &fattr->pre_mtime)) { - invalid = 0; - } - - /* - * If we have pending writebacks, things can get - * messy. - */ - cur_isize = i_size_read(inode); - if (nfs_have_writebacks(inode) && new_isize < cur_isize) - new_isize = cur_isize; - - nfsi->read_cache_ctime = fattr->ctime; - inode->i_ctime = fattr->ctime; - inode->i_atime = fattr->atime; - - if (mtime_update) { - if (invalid) - nfsi->cache_mtime_jiffies = fattr->timestamp; - nfsi->read_cache_mtime = fattr->mtime; - inode->i_mtime = fattr->mtime; + nfsi->change_attr = fattr->change_attr; + if (!data_unstable) + invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA; } - nfsi->read_cache_isize = new_size; - i_size_write(inode, new_isize); + memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime)); + memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); - if (inode->i_mode != fattr->mode || + if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) || inode->i_uid != fattr->uid || inode->i_gid != fattr->gid) { struct rpc_cred **cred = &NFS_I(inode)->cache_access.cred; @@ -1187,11 +1206,9 @@ put_rpccred(*cred); *cred = NULL; } + invalid |= NFS_INO_INVALID_ATTR; } - if (fattr->valid & NFS_ATTR_FATTR_V4) - nfsi->change_attr = fattr->change_attr; - inode->i_mode = fattr->mode; inode->i_nlink = fattr->nlink; inode->i_uid = fattr->uid; @@ -1207,31 +1224,30 @@ inode->i_blocks = fattr->du.nfs2.blocks; inode->i_blksize = fattr->du.nfs2.blocksize; } - - /* Update attrtimeo value */ - if (invalid) { + + /* Update attrtimeo value if we're out of the unstable period */ + if (invalid & NFS_INO_INVALID_ATTR) { nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); nfsi->attrtimeo_timestamp = jiffies; - invalidate_remote_inode(inode); - memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode))); } else if (time_after(jiffies, nfsi->attrtimeo_timestamp+nfsi->attrtimeo)) { if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode)) nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode); nfsi->attrtimeo_timestamp = jiffies; } + /* Don't invalidate the data if we were to blame */ + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) + || S_ISLNK(inode->i_mode))) + invalid &= ~NFS_INO_INVALID_DATA; + nfsi->flags |= invalid; return 0; - out_nochange: - if (!timespec_equal(&fattr->atime, &inode->i_atime)) - inode->i_atime = fattr->atime; - return 0; out_changed: /* * Big trouble! The inode has become a different object. */ #ifdef NFS_PARANOIA - printk(KERN_DEBUG "nfs_refresh_inode: inode %ld mode changed, %07o to %07o\n", - inode->i_ino, inode->i_mode, fattr->mode); + printk(KERN_DEBUG "%s: inode %ld mode changed, %07o to %07o\n", + __FUNCTION__, inode->i_ino, inode->i_mode, fattr->mode); #endif /* * No need to worry about unhashing the dentry, as the @@ -1352,7 +1368,7 @@ .name = "nfs", .get_sb = nfs_get_sb, .kill_sb = nfs_kill_super, - .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT, + .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, }; #ifdef CONFIG_NFS_V4 @@ -1391,8 +1407,8 @@ inode->i_sb->s_id, (long long)NFS_FILEID(inode), state); - list_del(&state->inode_states); - nfs4_put_open_state(state); + BUG_ON(atomic_read(&state->count) != 1); + nfs4_close_state(state, state->state); } /* Now call standard NFS clear_inode() code */ nfs_clear_inode(inode); @@ -1472,17 +1488,19 @@ down_write(&clp->cl_sem); if (clp->cl_rpcclient == NULL) { xprt = xprt_create_proto(proto, &server->addr, &timeparms); - if (xprt == NULL) { + if (IS_ERR(xprt)) { up_write(&clp->cl_sem); printk(KERN_WARNING "NFS: cannot create RPC transport.\n"); + err = PTR_ERR(xprt); goto out_fail; } clnt = rpc_create_client(xprt, server->hostname, &nfs_program, server->rpc_ops->version, authflavour); - if (clnt == NULL) { + if (IS_ERR(clnt)) { up_write(&clp->cl_sem); printk(KERN_WARNING "NFS: cannot create RPC client.\n"); xprt_destroy(xprt); + err = PTR_ERR(clnt); goto out_fail; } clnt->cl_chatty = 1; @@ -1495,14 +1513,17 @@ clear_bit(NFS4CLNT_OK, &clp->cl_state); list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks); clnt = rpc_clone_client(clp->cl_rpcclient); - server->nfs4_state = clp; + if (!IS_ERR(clnt)) + server->nfs4_state = clp; up_write(&clp->cl_sem); clp = NULL; - if (clnt == NULL) { + if (IS_ERR(clnt)) { printk(KERN_WARNING "NFS: cannot create RPC client.\n"); + err = PTR_ERR(clnt); goto out_remove_list; } + err = -ENOMEM; if (server->nfs4_state->cl_idmap == NULL) { printk(KERN_WARNING "NFS: failed to create idmapper.\n"); goto out_shutdown; @@ -1601,7 +1622,7 @@ if (data->version != NFS4_MOUNT_VERSION) { printk("nfs warning: mount version %s than kernel\n", - data->version < NFS_MOUNT_VERSION ? "older" : "newer"); + data->version < NFS4_MOUNT_VERSION ? "older" : "newer"); } p = nfs_copy_user_string(NULL, &data->hostname, 256); @@ -1666,7 +1687,7 @@ .name = "nfs4", .get_sb = nfs4_get_sb, .kill_sb = nfs_kill_super, - .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT, + .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, }; #define nfs4_zero_state(nfsi) \ @@ -1718,6 +1739,7 @@ INIT_LIST_HEAD(&nfsi->dirty); INIT_LIST_HEAD(&nfsi->commit); INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC); + atomic_set(&nfsi->data_updates, 0); nfsi->ndirty = 0; nfsi->ncommit = 0; nfsi->npages = 0; diff -Nru a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c --- a/fs/nfs/mount_clnt.c Sun Mar 14 14:20:06 2004 +++ b/fs/nfs/mount_clnt.c Sun Mar 14 14:20:06 2004 @@ -57,8 +57,9 @@ (unsigned)ntohl(addr->sin_addr.s_addr), path); sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(addr->sin_addr.s_addr)); - if (!(mnt_clnt = mnt_create(hostname, addr, version, protocol))) - return -EACCES; + mnt_clnt = mnt_create(hostname, addr, version, protocol); + if (IS_ERR(mnt_clnt)) + return PTR_ERR(mnt_clnt); call = (version == NFS_MNT3_VERSION) ? MOUNTPROC3_MNT : MNTPROC_MNT; status = rpc_call(mnt_clnt, call, path, &result, 0); @@ -72,13 +73,14 @@ struct rpc_xprt *xprt; struct rpc_clnt *clnt; - if (!(xprt = xprt_create_proto(protocol, srvaddr, NULL))) - return NULL; + xprt = xprt_create_proto(protocol, srvaddr, NULL); + if (IS_ERR(xprt)) + return (struct rpc_clnt *)xprt; clnt = rpc_create_client(xprt, hostname, &mnt_program, version, - RPC_AUTH_NULL); - if (!clnt) { + RPC_AUTH_UNIX); + if (IS_ERR(clnt)) { xprt_destroy(xprt); } else { clnt->cl_softrtry = 1; diff -Nru a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c --- a/fs/nfs/nfs2xdr.c Sun Mar 14 14:20:07 2004 +++ b/fs/nfs/nfs2xdr.c Sun Mar 14 14:20:07 2004 @@ -36,33 +36,33 @@ * Declare the space requirements for NFS arguments and replies as * number of 32bit-words */ -#define NFS_fhandle_sz 8 -#define NFS_sattr_sz 8 -#define NFS_filename_sz 1+(NFS2_MAXNAMLEN>>2) -#define NFS_path_sz 1+(NFS2_MAXPATHLEN>>2) -#define NFS_fattr_sz 17 -#define NFS_info_sz 5 -#define NFS_entry_sz NFS_filename_sz+3 +#define NFS_fhandle_sz (8) +#define NFS_sattr_sz (8) +#define NFS_filename_sz (1+(NFS2_MAXNAMLEN>>2)) +#define NFS_path_sz (1+(NFS2_MAXPATHLEN>>2)) +#define NFS_fattr_sz (17) +#define NFS_info_sz (5) +#define NFS_entry_sz (NFS_filename_sz+3) -#define NFS_diropargs_sz NFS_fhandle_sz+NFS_filename_sz -#define NFS_sattrargs_sz NFS_fhandle_sz+NFS_sattr_sz -#define NFS_readlinkargs_sz NFS_fhandle_sz -#define NFS_readargs_sz NFS_fhandle_sz+3 -#define NFS_writeargs_sz NFS_fhandle_sz+4 -#define NFS_createargs_sz NFS_diropargs_sz+NFS_sattr_sz -#define NFS_renameargs_sz NFS_diropargs_sz+NFS_diropargs_sz -#define NFS_linkargs_sz NFS_fhandle_sz+NFS_diropargs_sz -#define NFS_symlinkargs_sz NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz -#define NFS_readdirargs_sz NFS_fhandle_sz+2 +#define NFS_diropargs_sz (NFS_fhandle_sz+NFS_filename_sz) +#define NFS_sattrargs_sz (NFS_fhandle_sz+NFS_sattr_sz) +#define NFS_readlinkargs_sz (NFS_fhandle_sz) +#define NFS_readargs_sz (NFS_fhandle_sz+3) +#define NFS_writeargs_sz (NFS_fhandle_sz+4) +#define NFS_createargs_sz (NFS_diropargs_sz+NFS_sattr_sz) +#define NFS_renameargs_sz (NFS_diropargs_sz+NFS_diropargs_sz) +#define NFS_linkargs_sz (NFS_fhandle_sz+NFS_diropargs_sz) +#define NFS_symlinkargs_sz (NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz) +#define NFS_readdirargs_sz (NFS_fhandle_sz+2) -#define NFS_attrstat_sz 1+NFS_fattr_sz -#define NFS_diropres_sz 1+NFS_fhandle_sz+NFS_fattr_sz -#define NFS_readlinkres_sz 1 -#define NFS_readres_sz 1+NFS_fattr_sz+1 -#define NFS_writeres_sz NFS_attrstat_sz -#define NFS_stat_sz 1 -#define NFS_readdirres_sz 1 -#define NFS_statfsres_sz 1+NFS_info_sz +#define NFS_attrstat_sz (1+NFS_fattr_sz) +#define NFS_diropres_sz (1+NFS_fhandle_sz+NFS_fattr_sz) +#define NFS_readlinkres_sz (1) +#define NFS_readres_sz (1+NFS_fattr_sz+1) +#define NFS_writeres_sz (NFS_attrstat_sz) +#define NFS_stat_sz (1) +#define NFS_readdirres_sz (1) +#define NFS_statfsres_sz (1+NFS_info_sz) /* * Common NFS XDR functions as inlines diff -Nru a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c --- a/fs/nfs/nfs3proc.c Sun Mar 14 14:20:07 2004 +++ b/fs/nfs/nfs3proc.c Sun Mar 14 14:20:07 2004 @@ -68,20 +68,6 @@ return 1; } -static void -nfs3_write_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) -{ - if (fattr->valid & NFS_ATTR_FATTR) { - if (!(fattr->valid & NFS_ATTR_WCC)) { - fattr->pre_size = NFS_CACHE_ISIZE(inode); - fattr->pre_mtime = NFS_CACHE_MTIME(inode); - fattr->pre_ctime = NFS_CACHE_CTIME(inode); - fattr->valid |= NFS_ATTR_WCC; - } - nfs_refresh_inode(inode, fattr); - } -} - static struct rpc_cred * nfs_cred(struct inode *inode, struct file *filp) { @@ -99,14 +85,18 @@ */ static int nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, - struct nfs_fattr *fattr) + struct nfs_fsinfo *info) { int status; - dprintk("NFS call getroot\n"); - fattr->valid = 0; - status = rpc_call(server->client, NFS3PROC_GETATTR, fhandle, fattr, 0); - dprintk("NFS reply getroot\n"); + dprintk("%s: call fsinfo\n", __FUNCTION__); + info->fattr->valid = 0; + status = rpc_call(server->client_sys, NFS3PROC_FSINFO, fhandle, info, 0); + dprintk("%s: reply fsinfo %d\n", __FUNCTION__, status); + if (!(info->fattr->valid & NFS_ATTR_FATTR)) { + status = rpc_call(server->client_sys, NFS3PROC_GETATTR, fhandle, info->fattr, 0); + dprintk("%s: reply getattr %d\n", __FUNCTION__, status); + } return status; } @@ -280,7 +270,7 @@ msg.rpc_cred = nfs_cred(inode, filp); status = rpc_call_sync(NFS_CLIENT(inode), &msg, rpcflags); if (status >= 0) - nfs3_write_refresh_inode(inode, fattr); + nfs_refresh_inode(inode, fattr); dprintk("NFS reply write: %d\n", status); return status < 0? status : wdata->res.count; } @@ -303,7 +293,7 @@ msg.rpc_cred = nfs_cred(inode, filp); status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); if (status >= 0) - nfs3_write_refresh_inode(inode, fattr); + nfs_refresh_inode(inode, fattr); dprintk("NFS reply commit: %d\n", status); return status; } @@ -777,12 +767,13 @@ static void nfs3_write_done(struct rpc_task *task) { - struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata; + struct nfs_write_data *data; if (nfs3_async_handle_jukebox(task)) return; + data = (struct nfs_write_data *)task->tk_calldata; if (task->tk_status >= 0) - nfs3_write_refresh_inode(data->inode, data->res.fattr); + nfs_refresh_inode(data->inode, data->res.fattr); nfs_writeback_done(task); } @@ -835,12 +826,13 @@ static void nfs3_commit_done(struct rpc_task *task) { - struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata; + struct nfs_write_data *data; if (nfs3_async_handle_jukebox(task)) return; + data = (struct nfs_write_data *)task->tk_calldata; if (task->tk_status >= 0) - nfs3_write_refresh_inode(data->inode, data->res.fattr); + nfs_refresh_inode(data->inode, data->res.fattr); nfs_commit_done(task); } diff -Nru a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c --- a/fs/nfs/nfs3xdr.c Sun Mar 14 14:20:08 2004 +++ b/fs/nfs/nfs3xdr.c Sun Mar 14 14:20:08 2004 @@ -33,51 +33,51 @@ * Declare the space requirements for NFS arguments and replies as * number of 32bit-words */ -#define NFS3_fhandle_sz 1+16 -#define NFS3_fh_sz NFS3_fhandle_sz /* shorthand */ -#define NFS3_sattr_sz 15 -#define NFS3_filename_sz 1+(NFS3_MAXNAMLEN>>2) -#define NFS3_path_sz 1+(NFS3_MAXPATHLEN>>2) -#define NFS3_fattr_sz 21 -#define NFS3_wcc_attr_sz 6 -#define NFS3_pre_op_attr_sz 1+NFS3_wcc_attr_sz -#define NFS3_post_op_attr_sz 1+NFS3_fattr_sz -#define NFS3_wcc_data_sz NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz +#define NFS3_fhandle_sz (1+16) +#define NFS3_fh_sz (NFS3_fhandle_sz) /* shorthand */ +#define NFS3_sattr_sz (15) +#define NFS3_filename_sz (1+(NFS3_MAXNAMLEN>>2)) +#define NFS3_path_sz (1+(NFS3_MAXPATHLEN>>2)) +#define NFS3_fattr_sz (21) +#define NFS3_wcc_attr_sz (6) +#define NFS3_pre_op_attr_sz (1+NFS3_wcc_attr_sz) +#define NFS3_post_op_attr_sz (1+NFS3_fattr_sz) +#define NFS3_wcc_data_sz (NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz) #define NFS3_fsstat_sz #define NFS3_fsinfo_sz #define NFS3_pathconf_sz -#define NFS3_entry_sz NFS3_filename_sz+3 +#define NFS3_entry_sz (NFS3_filename_sz+3) -#define NFS3_sattrargs_sz NFS3_fh_sz+NFS3_sattr_sz+3 -#define NFS3_diropargs_sz NFS3_fh_sz+NFS3_filename_sz -#define NFS3_accessargs_sz NFS3_fh_sz+1 -#define NFS3_readlinkargs_sz NFS3_fh_sz -#define NFS3_readargs_sz NFS3_fh_sz+3 -#define NFS3_writeargs_sz NFS3_fh_sz+5 -#define NFS3_createargs_sz NFS3_diropargs_sz+NFS3_sattr_sz -#define NFS3_mkdirargs_sz NFS3_diropargs_sz+NFS3_sattr_sz -#define NFS3_symlinkargs_sz NFS3_diropargs_sz+NFS3_path_sz+NFS3_sattr_sz -#define NFS3_mknodargs_sz NFS3_diropargs_sz+2+NFS3_sattr_sz -#define NFS3_renameargs_sz NFS3_diropargs_sz+NFS3_diropargs_sz -#define NFS3_linkargs_sz NFS3_fh_sz+NFS3_diropargs_sz -#define NFS3_readdirargs_sz NFS3_fh_sz+2 -#define NFS3_commitargs_sz NFS3_fh_sz+3 +#define NFS3_sattrargs_sz (NFS3_fh_sz+NFS3_sattr_sz+3) +#define NFS3_diropargs_sz (NFS3_fh_sz+NFS3_filename_sz) +#define NFS3_accessargs_sz (NFS3_fh_sz+1) +#define NFS3_readlinkargs_sz (NFS3_fh_sz) +#define NFS3_readargs_sz (NFS3_fh_sz+3) +#define NFS3_writeargs_sz (NFS3_fh_sz+5) +#define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) +#define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz) +#define NFS3_symlinkargs_sz (NFS3_diropargs_sz+NFS3_path_sz+NFS3_sattr_sz) +#define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz) +#define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz) +#define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz) +#define NFS3_readdirargs_sz (NFS3_fh_sz+2) +#define NFS3_commitargs_sz (NFS3_fh_sz+3) -#define NFS3_attrstat_sz 1+NFS3_fattr_sz -#define NFS3_wccstat_sz 1+NFS3_wcc_data_sz -#define NFS3_lookupres_sz 1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz) -#define NFS3_accessres_sz 1+NFS3_post_op_attr_sz+1 -#define NFS3_readlinkres_sz 1+NFS3_post_op_attr_sz -#define NFS3_readres_sz 1+NFS3_post_op_attr_sz+3 -#define NFS3_writeres_sz 1+NFS3_wcc_data_sz+4 -#define NFS3_createres_sz 1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz -#define NFS3_renameres_sz 1+(2 * NFS3_wcc_data_sz) -#define NFS3_linkres_sz 1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz -#define NFS3_readdirres_sz 1+NFS3_post_op_attr_sz+2 -#define NFS3_fsstatres_sz 1+NFS3_post_op_attr_sz+13 -#define NFS3_fsinfores_sz 1+NFS3_post_op_attr_sz+12 -#define NFS3_pathconfres_sz 1+NFS3_post_op_attr_sz+6 -#define NFS3_commitres_sz 1+NFS3_wcc_data_sz+2 +#define NFS3_attrstat_sz (1+NFS3_fattr_sz) +#define NFS3_wccstat_sz (1+NFS3_wcc_data_sz) +#define NFS3_lookupres_sz (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz)) +#define NFS3_accessres_sz (1+NFS3_post_op_attr_sz+1) +#define NFS3_readlinkres_sz (1+NFS3_post_op_attr_sz) +#define NFS3_readres_sz (1+NFS3_post_op_attr_sz+3) +#define NFS3_writeres_sz (1+NFS3_wcc_data_sz+4) +#define NFS3_createres_sz (1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz) +#define NFS3_renameres_sz (1+(2 * NFS3_wcc_data_sz)) +#define NFS3_linkres_sz (1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz) +#define NFS3_readdirres_sz (1+NFS3_post_op_attr_sz+2) +#define NFS3_fsstatres_sz (1+NFS3_post_op_attr_sz+13) +#define NFS3_fsinfores_sz (1+NFS3_post_op_attr_sz+12) +#define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6) +#define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2) /* * Map file type to S_IFMT bits @@ -103,9 +103,7 @@ static inline u32 * xdr_encode_fhandle(u32 *p, struct nfs_fh *fh) { - *p++ = htonl(fh->size); - memcpy(p, fh->data, fh->size); - return p + XDR_QUADLEN(fh->size); + return xdr_encode_array(p, fh->data, fh->size); } static inline u32 * diff -Nru a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c --- a/fs/nfs/nfs4proc.c Sun Mar 14 14:20:08 2004 +++ b/fs/nfs/nfs4proc.c Sun Mar 14 14:20:08 2004 @@ -54,12 +54,24 @@ #define GET_OP(cp,name) &cp->ops[cp->req_nops].u.name #define OPNUM(cp) cp->ops[cp->req_nops].opnum +static int nfs4_proc_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); static int nfs4_async_handle_error(struct rpc_task *, struct nfs_server *); extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus); extern struct rpc_procinfo nfs4_procedures[]; extern nfs4_stateid zero_stateid; +/* Prevent leaks of NFSv4 errors into userland */ +static inline int nfs4_map_errors(int err) +{ + if (err < -1000) { + printk(KERN_WARNING "%s could not handle NFSv4 error %d\n", + __FUNCTION__, -err); + return -EIO; + } + return err; +} + static void nfs4_setup_compound(struct nfs4_compound *cp, struct nfs4_op *ops, struct nfs_server *server, char *tag) @@ -505,6 +517,8 @@ status = rpc_call_sync(server->client, &msg, 0); nfs4_increment_seqid(status, sp); + if (status == 0) + memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid)); /* Update the inode attributes */ nfs_refresh_inode(inode, &fattr); return status; @@ -689,12 +703,12 @@ retry: fattr->valid = 0; - if (state) + if (sattr->ia_valid & ATTR_SIZE) nfs4_copy_stateid(&arg.stateid, state, 0); - else + else memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); - status = rpc_call_sync(server->client, &msg, 0); + status = rpc_call_sync(server->client, &msg, 0); if (status) { status = nfs4_handle_error(server, status); if (!status) @@ -822,10 +836,11 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, - struct nfs_fattr *fattr) + struct nfs_fsinfo *info) { struct nfs4_compound compound; struct nfs4_op ops[4]; + struct nfs_fattr * fattr = info->fattr; unsigned char * p; struct qstr q; int status; @@ -869,7 +884,9 @@ break; } out: - return status; + if (status) + return nfs4_map_errors(status); + return nfs4_proc_fsinfo(server, fhandle, info); } static int @@ -883,7 +900,7 @@ nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "getattr"); nfs4_setup_putfh(&compound, NFS_FH(inode)); nfs4_setup_getattr(&compound, fattr); - return nfs4_call_compound(&compound, NULL, 0); + return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0)); } /* @@ -969,7 +986,7 @@ if (status >= 0) status = nfs_refresh_inode(dir, &dir_attr); - return status; + return nfs4_map_errors(status); } static int @@ -1016,7 +1033,7 @@ else if (req_access != resp_access) status = -EACCES; } - return status; + return nfs4_map_errors(status); } /* @@ -1052,7 +1069,7 @@ nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "readlink"); nfs4_setup_putfh(&compound, NFS_FH(inode)); nfs4_setup_readlink(&compound, PAGE_CACHE_SIZE, &page); - return nfs4_call_compound(&compound, NULL, 0); + return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0)); } static int @@ -1088,14 +1105,10 @@ fattr->valid = 0; status = rpc_call_sync(server->client, &msg, flags); - if (!status) { + if (!status) renew_lease(server, timestamp); - /* Check cache consistency */ - if (fattr->change_attr != NFS_CHANGE_ATTR(inode)) - nfs_zap_caches(inode); - } dprintk("NFS reply read: %d\n", status); - return status; + return nfs4_map_errors(status); } static int @@ -1130,9 +1143,8 @@ fattr->valid = 0; status = rpc_call_sync(server->client, &msg, rpcflags); - NFS_CACHEINV(inode); dprintk("NFS reply write: %d\n", status); - return status; + return nfs4_map_errors(status); } static int @@ -1167,7 +1179,7 @@ fattr->valid = 0; status = rpc_call_sync(server->client, &msg, 0); dprintk("NFS reply commit: %d\n", status); - return status; + return nfs4_map_errors(status); } /* @@ -1234,7 +1246,7 @@ process_cinfo(&dir_cinfo, &dir_attr); nfs_refresh_inode(dir, &dir_attr); } - return status; + return nfs4_map_errors(status); } struct unlink_desc { @@ -1312,7 +1324,7 @@ nfs_refresh_inode(old_dir, &old_dir_attr); nfs_refresh_inode(new_dir, &new_dir_attr); } - return status; + return nfs4_map_errors(status); } static int @@ -1342,7 +1354,7 @@ nfs_refresh_inode(dir, &dir_attr); nfs_refresh_inode(inode, &fattr); } - return status; + return nfs4_map_errors(status); } static int @@ -1373,7 +1385,7 @@ process_cinfo(&dir_cinfo, &dir_attr); nfs_refresh_inode(dir, &dir_attr); } - return status; + return nfs4_map_errors(status); } static int @@ -1403,7 +1415,7 @@ process_cinfo(&dir_cinfo, &dir_attr); nfs_refresh_inode(dir, &dir_attr); } - return status; + return nfs4_map_errors(status); } static int @@ -1421,9 +1433,11 @@ nfs4_setup_putfh(&compound, NFS_FH(dir)); nfs4_setup_readdir(&compound, cookie, NFS_COOKIEVERF(dir), &page, count, dentry); status = nfs4_call_compound(&compound, cred, 0); + if (status == 0) + memcpy(NFS_COOKIEVERF(dir), ops[1].u.readdir.rd_resp_verifier.data, NFS4_VERIFIER_SIZE); unlock_kernel(); - return status; + return nfs4_map_errors(status); } static int @@ -1453,7 +1467,7 @@ process_cinfo(&dir_cinfo, &dir_attr); nfs_refresh_inode(dir, &dir_attr); } - return status; + return nfs4_map_errors(status); } static int @@ -1463,11 +1477,10 @@ struct nfs4_compound compound; struct nfs4_op ops[2]; - memset(fsstat, 0, sizeof(*fsstat)); nfs4_setup_compound(&compound, ops, server, "statfs"); nfs4_setup_putfh(&compound, fhandle); nfs4_setup_statfs(&compound, fsstat); - return nfs4_call_compound(&compound, NULL, 0); + return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0)); } static int @@ -1480,8 +1493,7 @@ .rpc_resp = fsinfo, }; - memset(fsinfo, 0, sizeof(*fsinfo)); - return rpc_call_sync(server->client, &msg, 0); + return nfs4_map_errors(rpc_call_sync(server->client, &msg, 0)); } static int @@ -1491,11 +1503,10 @@ struct nfs4_compound compound; struct nfs4_op ops[2]; - memset(pathconf, 0, sizeof(*pathconf)); nfs4_setup_compound(&compound, ops, server, "statfs"); nfs4_setup_putfh(&compound, fhandle); nfs4_setup_pathconf(&compound, pathconf); - return nfs4_call_compound(&compound, NULL, 0); + return nfs4_map_errors(nfs4_call_compound(&compound, NULL, 0)); } static void @@ -1517,7 +1528,6 @@ { struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata; struct inode *inode = data->inode; - struct nfs_fattr *fattr = data->res.fattr; if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) { task->tk_action = nfs4_restart_read; @@ -1525,11 +1535,6 @@ } if (task->tk_status > 0) renew_lease(NFS_SERVER(inode), data->timestamp); - /* Check cache consistency */ - if (fattr->change_attr != NFS_CHANGE_ATTR(inode)) - nfs_zap_caches(inode); - if (fattr->bitmap[1] & FATTR4_WORD1_TIME_ACCESS) - inode->i_atime = fattr->atime; /* Call back common NFS readpage processing */ nfs_readpage_result(task); } @@ -1577,21 +1582,6 @@ } static void -nfs4_write_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) -{ - /* Check cache consistency */ - if (fattr->pre_change_attr != NFS_CHANGE_ATTR(inode)) - nfs_zap_caches(inode); - NFS_CHANGE_ATTR(inode) = fattr->change_attr; - if (fattr->bitmap[1] & FATTR4_WORD1_SPACE_USED) - inode->i_blocks = (fattr->du.nfs3.used + 511) >> 9; - if (fattr->bitmap[1] & FATTR4_WORD1_TIME_METADATA) - inode->i_ctime = fattr->ctime; - if (fattr->bitmap[1] & FATTR4_WORD1_TIME_MODIFY) - inode->i_mtime = fattr->mtime; -} - -static void nfs4_restart_write(struct rpc_task *task) { struct nfs_write_data *data = (struct nfs_write_data *)task->tk_calldata; @@ -1617,7 +1607,6 @@ } if (task->tk_status >= 0) renew_lease(NFS_SERVER(inode), data->timestamp); - nfs4_write_refresh_inode(inode, data->res.fattr); /* Call back common NFS writeback processing */ nfs_writeback_done(task); } @@ -1684,7 +1673,6 @@ task->tk_action = nfs4_restart_write; return; } - nfs4_write_refresh_inode(inode, data->res.fattr); /* Call back common NFS writeback processing */ nfs_commit_done(task); } @@ -1807,6 +1795,7 @@ if (filp->f_mode & FMODE_WRITE) { lock_kernel(); nfs_set_mmcred(inode, state->owner->so_cred); + nfs_begin_data_update(inode); unlock_kernel(); } filp->private_data = state; @@ -1823,6 +1812,11 @@ if (state) nfs4_close_state(state, filp->f_mode); + if (filp->f_mode & FMODE_WRITE) { + lock_kernel(); + nfs_end_data_update(inode); + unlock_kernel(); + } return 0; } @@ -1850,7 +1844,7 @@ { struct nfs4_client *clp = server->nfs4_state; - if (!clp) + if (!clp || task->tk_status >= 0) return 0; switch(task->tk_status) { case -NFS4ERR_STALE_CLIENTID: @@ -1869,6 +1863,7 @@ task->tk_status = 0; return -EAGAIN; } + task->tk_status = nfs4_map_errors(task->tk_status); return 0; } @@ -1946,16 +1941,9 @@ break; case -NFS4ERR_OLD_STATEID: ret = 0; - break; - default: - if (errorcode <= -1000) { - printk(KERN_WARNING "%s could not handle NFSv4 error %d\n", - __FUNCTION__, -errorcode); - ret = -EIO; - } } /* We failed to handle the error */ - return ret; + return nfs4_map_errors(ret); } @@ -2130,7 +2118,7 @@ if (lsp) nfs4_put_lock_state(lsp); up(&state->lock_sema); - return status; + return nfs4_map_errors(status); } int @@ -2175,7 +2163,7 @@ nfs4_put_lock_state(lsp); out: up(&state->lock_sema); - return status; + return nfs4_map_errors(status); } static int @@ -2251,7 +2239,7 @@ nfs4_put_lock_state(lsp); out: up(&state->lock_sema); - return status; + return nfs4_map_errors(status); } static int diff -Nru a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c --- a/fs/nfs/nfs4state.c Sun Mar 14 14:20:05 2004 +++ b/fs/nfs/nfs4state.c Sun Mar 14 14:20:05 2004 @@ -411,18 +411,20 @@ return state; } -void -nfs4_put_open_state(struct nfs4_state *state) +static void +__nfs4_put_open_state(struct nfs4_state *state) { struct inode *inode = state->inode; struct nfs4_state_owner *owner = state->owner; int status = 0; - if (!atomic_dec_and_lock(&state->count, &inode->i_lock)) + if (!atomic_dec_and_lock(&state->count, &inode->i_lock)) { + up(&owner->so_sema); return; - list_del(&state->inode_states); + } + if (!list_empty(&state->inode_states)) + list_del(&state->inode_states); spin_unlock(&inode->i_lock); - down(&owner->so_sema); list_del(&state->open_states); if (state->state != 0) { do { @@ -440,6 +442,13 @@ } void +nfs4_put_open_state(struct nfs4_state *state) +{ + down(&state->owner->so_sema); + __nfs4_put_open_state(state); +} + +void nfs4_close_state(struct nfs4_state *state, mode_t mode) { struct inode *inode = state->inode; @@ -479,8 +488,7 @@ status = nfs4_handle_error(NFS_SERVER(inode), status); down(&owner->so_sema); } while (!status); - up(&owner->so_sema); - nfs4_put_open_state(state); + __nfs4_put_open_state(state); } /* @@ -790,7 +798,7 @@ restart_loop: spin_lock(&clp->cl_lock); list_for_each_entry(sp, &clp->cl_state_owners, so_list) { - if (sp->so_generation - generation <= 0) + if (sp->so_generation - generation >= 0) continue; atomic_inc(&sp->so_count); spin_unlock(&clp->cl_lock); diff -Nru a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c --- a/fs/nfs/nfs4xdr.c Sun Mar 14 14:20:08 2004 +++ b/fs/nfs/nfs4xdr.c Sun Mar 14 14:20:08 2004 @@ -69,84 +69,84 @@ /* lock,open owner id: * we currently use size 1 (u32) out of (NFS4_OPAQUE_LIMIT >> 2) */ -#define owner_id_maxsz 1 + 1 -#define compound_encode_hdr_maxsz 3 + (NFS4_MAXTAGLEN >> 2) -#define compound_decode_hdr_maxsz 2 + (NFS4_MAXTAGLEN >> 2) -#define op_encode_hdr_maxsz 1 -#define op_decode_hdr_maxsz 2 -#define encode_putfh_maxsz op_encode_hdr_maxsz + 1 + \ - (NFS4_FHSIZE >> 2) -#define decode_putfh_maxsz op_decode_hdr_maxsz -#define encode_putrootfh_maxsz op_encode_hdr_maxsz -#define decode_putrootfh_maxsz op_decode_hdr_maxsz -#define encode_getfh_maxsz op_encode_hdr_maxsz -#define decode_getfh_maxsz op_decode_hdr_maxsz + 1 + \ - (NFS4_FHSIZE >> 2) -#define encode_getattr_maxsz op_encode_hdr_maxsz + 3 -#define nfs4_fattr_bitmap_maxsz 26 + 2 * ((NFS4_MAXNAMLEN +1) >> 2) -#define decode_getattr_maxsz op_decode_hdr_maxsz + 3 + \ - nfs4_fattr_bitmap_maxsz -#define encode_savefh_maxsz op_encode_hdr_maxsz -#define decode_savefh_maxsz op_decode_hdr_maxsz -#define encode_restorefh_maxsz op_encode_hdr_maxsz -#define decode_restorefh_maxsz op_decode_hdr_maxsz -#define encode_read_getattr_maxsz op_encode_hdr_maxsz + 2 -#define decode_read_getattr_maxsz op_decode_hdr_maxsz + 8 -#define encode_pre_write_getattr_maxsz op_encode_hdr_maxsz + 2 -#define decode_pre_write_getattr_maxsz op_decode_hdr_maxsz + 5 -#define encode_post_write_getattr_maxsz op_encode_hdr_maxsz + 2 -#define decode_post_write_getattr_maxsz op_decode_hdr_maxsz + 13 -#define encode_fsinfo_maxsz op_encode_hdr_maxsz + 2 -#define decode_fsinfo_maxsz op_decode_hdr_maxsz + 11 -#define encode_renew_maxsz op_encode_hdr_maxsz + 3 -#define decode_renew_maxsz op_decode_hdr_maxsz +#define owner_id_maxsz (1 + 1) +#define compound_encode_hdr_maxsz (3 + (NFS4_MAXTAGLEN >> 2)) +#define compound_decode_hdr_maxsz (3 + (NFS4_MAXTAGLEN >> 2)) +#define op_encode_hdr_maxsz (1) +#define op_decode_hdr_maxsz (2) +#define encode_putfh_maxsz (op_encode_hdr_maxsz + 1 + \ + (NFS4_FHSIZE >> 2)) +#define decode_putfh_maxsz (op_decode_hdr_maxsz) +#define encode_putrootfh_maxsz (op_encode_hdr_maxsz) +#define decode_putrootfh_maxsz (op_decode_hdr_maxsz) +#define encode_getfh_maxsz (op_encode_hdr_maxsz) +#define decode_getfh_maxsz (op_decode_hdr_maxsz + 1 + \ + (NFS4_FHSIZE >> 2)) +#define encode_getattr_maxsz (op_encode_hdr_maxsz + 3) +#define nfs4_fattr_bitmap_maxsz (26 + 2 * ((NFS4_MAXNAMLEN +1) >> 2)) +#define decode_getattr_maxsz (op_decode_hdr_maxsz + 3 + \ + nfs4_fattr_bitmap_maxsz) +#define encode_savefh_maxsz (op_encode_hdr_maxsz) +#define decode_savefh_maxsz (op_decode_hdr_maxsz) +#define encode_restorefh_maxsz (op_encode_hdr_maxsz) +#define decode_restorefh_maxsz (op_decode_hdr_maxsz) +#define encode_read_getattr_maxsz (op_encode_hdr_maxsz + 2) +#define decode_read_getattr_maxsz (op_decode_hdr_maxsz + 8) +#define encode_pre_write_getattr_maxsz (op_encode_hdr_maxsz + 2) +#define decode_pre_write_getattr_maxsz (op_decode_hdr_maxsz + 5) +#define encode_post_write_getattr_maxsz (op_encode_hdr_maxsz + 2) +#define decode_post_write_getattr_maxsz (op_decode_hdr_maxsz + 13) +#define encode_fsinfo_maxsz (op_encode_hdr_maxsz + 2) +#define decode_fsinfo_maxsz (op_decode_hdr_maxsz + 11) +#define encode_renew_maxsz (op_encode_hdr_maxsz + 3) +#define decode_renew_maxsz (op_decode_hdr_maxsz) #define encode_setclientid_maxsz \ - op_encode_hdr_maxsz + \ + (op_encode_hdr_maxsz + \ 4 /*server->ip_addr*/ + \ 1 /*Netid*/ + \ 6 /*uaddr*/ + \ - 6 + (NFS4_VERIFIER_SIZE >> 2) + 6 + (NFS4_VERIFIER_SIZE >> 2)) #define decode_setclientid_maxsz \ - op_decode_hdr_maxsz + \ + (op_decode_hdr_maxsz + \ 2 + \ - 1024 /* large value for CLID_INUSE */ + 1024) /* large value for CLID_INUSE */ #define encode_setclientid_confirm_maxsz \ - op_encode_hdr_maxsz + \ - 3 + (NFS4_VERIFIER_SIZE >> 2) + (op_encode_hdr_maxsz + \ + 3 + (NFS4_VERIFIER_SIZE >> 2)) #define decode_setclientid_confirm_maxsz \ - op_decode_hdr_maxsz + (op_decode_hdr_maxsz) -#define NFS4_enc_compound_sz 1024 /* XXX: large enough? */ -#define NFS4_dec_compound_sz 1024 /* XXX: large enough? */ -#define NFS4_enc_read_sz compound_encode_hdr_maxsz + \ +#define NFS4_enc_compound_sz (1024) /* XXX: large enough? */ +#define NFS4_dec_compound_sz (1024) /* XXX: large enough? */ +#define NFS4_enc_read_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ encode_read_getattr_maxsz + \ - op_encode_hdr_maxsz + 7 -#define NFS4_dec_read_sz compound_decode_hdr_maxsz + \ + op_encode_hdr_maxsz + 7) +#define NFS4_dec_read_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ decode_read_getattr_maxsz + \ - op_decode_hdr_maxsz + 2 -#define NFS4_enc_write_sz compound_encode_hdr_maxsz + \ + op_decode_hdr_maxsz + 2) +#define NFS4_enc_write_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ encode_pre_write_getattr_maxsz + \ op_encode_hdr_maxsz + 8 + \ - encode_post_write_getattr_maxsz -#define NFS4_dec_write_sz compound_decode_hdr_maxsz + \ + encode_post_write_getattr_maxsz) +#define NFS4_dec_write_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ decode_pre_write_getattr_maxsz + \ op_decode_hdr_maxsz + 4 + \ - decode_post_write_getattr_maxsz -#define NFS4_enc_commit_sz compound_encode_hdr_maxsz + \ + decode_post_write_getattr_maxsz) +#define NFS4_enc_commit_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ encode_pre_write_getattr_maxsz + \ op_encode_hdr_maxsz + 3 + \ - encode_post_write_getattr_maxsz -#define NFS4_dec_commit_sz compound_decode_hdr_maxsz + \ + encode_post_write_getattr_maxsz) +#define NFS4_dec_commit_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ decode_pre_write_getattr_maxsz + \ op_decode_hdr_maxsz + 2 + \ - decode_post_write_getattr_maxsz -#define NFS4_enc_open_sz compound_encode_hdr_maxsz + \ + decode_post_write_getattr_maxsz) +#define NFS4_enc_open_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ encode_savefh_maxsz + \ op_encode_hdr_maxsz + \ @@ -154,107 +154,107 @@ encode_getattr_maxsz + \ encode_getfh_maxsz + \ encode_restorefh_maxsz + \ - encode_getattr_maxsz -#define NFS4_dec_open_sz compound_decode_hdr_maxsz + \ + encode_getattr_maxsz) +#define NFS4_dec_open_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ decode_savefh_maxsz + \ op_decode_hdr_maxsz + 4 + 5 + 2 + 3 + \ decode_getattr_maxsz + \ decode_getfh_maxsz + \ decode_restorefh_maxsz + \ - decode_getattr_maxsz + decode_getattr_maxsz) #define NFS4_enc_open_confirm_sz \ - compound_encode_hdr_maxsz + \ + (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - op_encode_hdr_maxsz + 5 -#define NFS4_dec_open_confirm_sz compound_decode_hdr_maxsz + \ + op_encode_hdr_maxsz + 5) +#define NFS4_dec_open_confirm_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - op_decode_hdr_maxsz + 4 -#define NFS4_enc_open_reclaim_sz compound_encode_hdr_maxsz + \ + op_decode_hdr_maxsz + 4) +#define NFS4_enc_open_reclaim_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ op_encode_hdr_maxsz + \ 11 + \ - encode_getattr_maxsz -#define NFS4_dec_open_reclaim_sz compound_decode_hdr_maxsz + \ + encode_getattr_maxsz) +#define NFS4_dec_open_reclaim_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ op_decode_hdr_maxsz + \ 4 + 5 + 2 + 3 + \ - decode_getattr_maxsz + decode_getattr_maxsz) #define NFS4_enc_open_downgrade_sz \ - compound_encode_hdr_maxsz + \ + (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - op_encode_hdr_maxsz + 7 + op_encode_hdr_maxsz + 7) #define NFS4_dec_open_downgrade_sz \ - compound_decode_hdr_maxsz + \ + (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - op_decode_hdr_maxsz + 4 -#define NFS4_enc_close_sz compound_encode_hdr_maxsz + \ + op_decode_hdr_maxsz + 4) +#define NFS4_enc_close_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - op_encode_hdr_maxsz + 5 -#define NFS4_dec_close_sz compound_decode_hdr_maxsz + \ + op_encode_hdr_maxsz + 5) +#define NFS4_dec_close_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - op_decode_hdr_maxsz + 4 -#define NFS4_enc_setattr_sz compound_encode_hdr_maxsz + \ + op_decode_hdr_maxsz + 4) +#define NFS4_enc_setattr_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ op_encode_hdr_maxsz + 4 + \ nfs4_fattr_bitmap_maxsz + \ - encode_getattr_maxsz -#define NFS4_dec_setattr_sz compound_decode_hdr_maxsz + \ + encode_getattr_maxsz) +#define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - op_decode_hdr_maxsz + 3 -#define NFS4_enc_fsinfo_sz compound_encode_hdr_maxsz + \ + op_decode_hdr_maxsz + 3) +#define NFS4_enc_fsinfo_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ - encode_fsinfo_maxsz -#define NFS4_dec_fsinfo_sz compound_decode_hdr_maxsz + \ + encode_fsinfo_maxsz) +#define NFS4_dec_fsinfo_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ - decode_fsinfo_maxsz -#define NFS4_enc_renew_sz compound_encode_hdr_maxsz + \ - encode_renew_maxsz -#define NFS4_dec_renew_sz compound_decode_hdr_maxsz + \ - decode_renew_maxsz -#define NFS4_enc_setclientid_sz compound_encode_hdr_maxsz + \ - encode_setclientid_maxsz -#define NFS4_dec_setclientid_sz compound_decode_hdr_maxsz + \ - decode_setclientid_maxsz + decode_fsinfo_maxsz) +#define NFS4_enc_renew_sz (compound_encode_hdr_maxsz + \ + encode_renew_maxsz) +#define NFS4_dec_renew_sz (compound_decode_hdr_maxsz + \ + decode_renew_maxsz) +#define NFS4_enc_setclientid_sz (compound_encode_hdr_maxsz + \ + encode_setclientid_maxsz) +#define NFS4_dec_setclientid_sz (compound_decode_hdr_maxsz + \ + decode_setclientid_maxsz) #define NFS4_enc_setclientid_confirm_sz \ - compound_encode_hdr_maxsz + \ + (compound_encode_hdr_maxsz + \ encode_setclientid_confirm_maxsz + \ encode_putrootfh_maxsz + \ - encode_fsinfo_maxsz + encode_fsinfo_maxsz) #define NFS4_dec_setclientid_confirm_sz \ - compound_decode_hdr_maxsz + \ + (compound_decode_hdr_maxsz + \ decode_setclientid_confirm_maxsz + \ decode_putrootfh_maxsz + \ - decode_fsinfo_maxsz -#define NFS4_enc_lock_sz compound_encode_hdr_maxsz + \ + decode_fsinfo_maxsz) +#define NFS4_enc_lock_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ encode_getattr_maxsz + \ op_encode_hdr_maxsz + \ 1 + 1 + 2 + 2 + \ 1 + 4 + 1 + 2 + \ - owner_id_maxsz -#define NFS4_dec_lock_sz compound_decode_hdr_maxsz + \ + owner_id_maxsz) +#define NFS4_dec_lock_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ decode_getattr_maxsz + \ op_decode_hdr_maxsz + \ 2 + 2 + 1 + 2 + \ - owner_id_maxsz -#define NFS4_enc_lockt_sz compound_encode_hdr_maxsz + \ + owner_id_maxsz) +#define NFS4_enc_lockt_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ encode_getattr_maxsz + \ op_encode_hdr_maxsz + \ 1 + 2 + 2 + 2 + \ - owner_id_maxsz -#define NFS4_dec_lockt_sz NFS4_dec_lock_sz -#define NFS4_enc_locku_sz compound_encode_hdr_maxsz + \ + owner_id_maxsz) +#define NFS4_dec_lockt_sz (NFS4_dec_lock_sz) +#define NFS4_enc_locku_sz (compound_encode_hdr_maxsz + \ encode_putfh_maxsz + \ encode_getattr_maxsz + \ op_encode_hdr_maxsz + \ - 1 + 1 + 4 + 2 + 2 -#define NFS4_dec_locku_sz compound_decode_hdr_maxsz + \ + 1 + 1 + 4 + 2 + 2) +#define NFS4_dec_locku_sz (compound_decode_hdr_maxsz + \ decode_putfh_maxsz + \ decode_getattr_maxsz + \ - op_decode_hdr_maxsz + 4 + op_decode_hdr_maxsz + 4) @@ -324,7 +324,7 @@ dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag); BUG_ON(hdr->taglen > NFS4_MAXTAGLEN); - RESERVE_SPACE(12+XDR_QUADLEN(hdr->taglen)); + RESERVE_SPACE(12+(XDR_QUADLEN(hdr->taglen)<<2)); WRITE32(hdr->taglen); WRITEMEM(hdr->tag, hdr->taglen); WRITE32(NFS4_MINOR_VERSION); @@ -3165,6 +3165,10 @@ { NFS4ERR_SYMLINK, ELOOP }, { NFS4ERR_OP_ILLEGAL, EOPNOTSUPP }, { NFS4ERR_DEADLOCK, EDEADLK }, + { NFS4ERR_WRONGSEC, EPERM }, /* FIXME: this needs + * to be handled by a + * middle-layer. + */ { -1, EIO } }; @@ -3179,6 +3183,10 @@ for (i = 0; nfs_errtbl[i].stat != -1; i++) { if (nfs_errtbl[i].stat == stat) return nfs_errtbl[i].errno; + } + if (stat < 0) { + /* The server is looney tunes. */ + return ESERVERFAULT; } /* If we cannot translate the error, the recovery routines should * handle it. diff -Nru a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c --- a/fs/nfs/nfsroot.c Sun Mar 14 14:20:08 2004 +++ b/fs/nfs/nfsroot.c Sun Mar 14 14:20:08 2004 @@ -166,37 +166,6 @@ /* - * Extract IP address from the parameter string if needed. Note that we - * need to have root_server_addr set _before_ IPConfig gets called as it - * can override it. - */ -static void __init root_nfs_parse_addr(char *name) -{ - int octets = 0; - char *cp, *cq; - - cp = cq = name; - while (octets < 4) { - while (*cp >= '0' && *cp <= '9') - cp++; - if (cp == cq || cp - cq > 3) - break; - if (*cp == '.' || octets == 3) - octets++; - if (octets < 4) - cp++; - cq = cp; - } - if (octets == 4 && (*cp == ':' || *cp == '\0')) { - if (*cp == ':') - *cp++ = '\0'; - root_server_addr = in_aton(name); - strcpy(name, cp); - } -} - - -/* * Parse option string. */ static void __init root_nfs_parse(char *name, char *buf) @@ -345,7 +314,7 @@ line[sizeof(nfs_root_name) - strlen(NFS_ROOT) - 1] = '\0'; sprintf(nfs_root_name, NFS_ROOT, line); } - root_nfs_parse_addr(nfs_root_name); + root_server_addr = root_nfs_parse_addr(nfs_root_name); return 1; } diff -Nru a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c --- a/fs/nfs/pagelist.c Sun Mar 14 14:20:08 2004 +++ b/fs/nfs/pagelist.c Sun Mar 14 14:20:08 2004 @@ -246,7 +246,6 @@ * nfs_scan_list - Scan a list for matching requests * @head: One of the NFS inode request lists * @dst: Destination list - * @file: if set, ensure we match requests from this file * @idx_start: lower bound of page->index to scan * @npages: idx_start + npages sets the upper bound to scan. * @@ -258,7 +257,6 @@ */ int nfs_scan_list(struct list_head *head, struct list_head *dst, - struct file *file, unsigned long idx_start, unsigned int npages) { struct list_head *pos, *tmp; @@ -275,9 +273,6 @@ list_for_each_safe(pos, tmp, head) { req = nfs_list_entry(pos); - - if (file && req->wb_file != file) - continue; if (req->wb_index < idx_start) continue; diff -Nru a/fs/nfs/proc.c b/fs/nfs/proc.c --- a/fs/nfs/proc.c Sun Mar 14 14:20:08 2004 +++ b/fs/nfs/proc.c Sun Mar 14 14:20:08 2004 @@ -49,18 +49,6 @@ extern struct rpc_procinfo nfs_procedures[]; -static void -nfs_write_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) -{ - if (!(fattr->valid & NFS_ATTR_WCC)) { - fattr->pre_size = NFS_CACHE_ISIZE(inode); - fattr->pre_mtime = NFS_CACHE_MTIME(inode); - fattr->pre_ctime = NFS_CACHE_CTIME(inode); - fattr->valid |= NFS_ATTR_WCC; - } - nfs_refresh_inode(inode, fattr); -} - static struct rpc_cred * nfs_cred(struct inode *inode, struct file *filp) { @@ -78,15 +66,33 @@ */ static int nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, - struct nfs_fattr *fattr) + struct nfs_fsinfo *info) { - int status; + struct nfs_fattr *fattr = info->fattr; + struct nfs2_fsstat fsinfo; + int status; - dprintk("NFS call getroot\n"); + dprintk("%s: call getattr\n", __FUNCTION__); fattr->valid = 0; - status = rpc_call(server->client, NFSPROC_GETATTR, fhandle, fattr, 0); - dprintk("NFS reply getroot\n"); - return status; + status = rpc_call(server->client_sys, NFSPROC_GETATTR, fhandle, fattr, 0); + dprintk("%s: reply getattr %d\n", __FUNCTION__, status); + if (status) + return status; + dprintk("%s: call statfs\n", __FUNCTION__); + status = rpc_call(server->client_sys, NFSPROC_STATFS, fhandle, &fsinfo, 0); + dprintk("%s: reply statfs %d\n", __FUNCTION__, status); + if (status) + return status; + info->rtmax = NFS_MAXDATA; + info->rtpref = fsinfo.tsize; + info->rtmult = fsinfo.bsize; + info->wtmax = NFS_MAXDATA; + info->wtpref = fsinfo.tsize; + info->wtmult = fsinfo.bsize; + info->dtpref = fsinfo.tsize; + info->maxfilesize = 0x7FFFFFFF; + info->lease_time = 0; + return 0; } /* @@ -180,8 +186,14 @@ msg.rpc_cred = nfs_cred(inode, filp); status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); - if (status >= 0) + if (status >= 0) { nfs_refresh_inode(inode, fattr); + /* Emulate the eof flag, which isn't normally needed in NFSv2 + * as it is guaranteed to always return the file attributes + */ + if (rdata->args.offset + rdata->args.count >= fattr->size) + rdata->res.eof = 1; + } dprintk("NFS reply read: %d\n", status); return status; } @@ -205,7 +217,7 @@ msg.rpc_cred = nfs_cred(inode, filp); status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags); if (status >= 0) { - nfs_write_refresh_inode(inode, fattr); + nfs_refresh_inode(inode, fattr); wdata->res.count = wdata->args.count; wdata->verf.committed = NFS_FILE_SYNC; } @@ -331,10 +343,8 @@ { struct rpc_message *msg = &task->tk_msg; - if (msg->rpc_argp) { - NFS_CACHEINV(dir->d_inode); + if (msg->rpc_argp) kfree(msg->rpc_argp); - } return 0; } @@ -537,8 +547,14 @@ { struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata; - if (task->tk_status >= 0) + if (task->tk_status >= 0) { nfs_refresh_inode(data->inode, data->res.fattr); + /* Emulate the eof flag, which isn't normally needed in NFSv2 + * as it is guaranteed to always return the file attributes + */ + if (data->args.offset + data->args.count >= data->res.fattr->size) + data->res.eof = 1; + } nfs_readpage_result(task); } @@ -584,7 +600,7 @@ struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata; if (task->tk_status >= 0) - nfs_write_refresh_inode(data->inode, data->res.fattr); + nfs_refresh_inode(data->inode, data->res.fattr); nfs_writeback_done(task); } diff -Nru a/fs/nfs/read.c b/fs/nfs/read.c --- a/fs/nfs/read.c Sun Mar 14 14:20:05 2004 +++ b/fs/nfs/read.c Sun Mar 14 14:20:05 2004 @@ -121,9 +121,13 @@ } count -= result; rdata.args.pgbase += result; - if (result < rdata.args.count) /* NFSv2ism */ + /* Note: result == 0 should only happen if we're caching + * a write that extends the file and punches a hole. + */ + if (rdata.res.eof != 0 || result == 0) break; } while (count); + NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME; if (count) memclear_highpage_flush(page, rdata.args.pgbase, count); @@ -266,6 +270,7 @@ dprintk("NFS: %4d nfs_readpage_result, (status %d)\n", task->tk_pid, task->tk_status); + NFS_FLAGS(data->inode) |= NFS_INO_INVALID_ATIME; while (!list_empty(&data->pages)) { struct nfs_page *req = nfs_list_entry(data->pages.next); struct page *page = req->wb_page; diff -Nru a/fs/nfs/unlink.c b/fs/nfs/unlink.c --- a/fs/nfs/unlink.c Sun Mar 14 14:20:08 2004 +++ b/fs/nfs/unlink.c Sun Mar 14 14:20:08 2004 @@ -104,6 +104,7 @@ status = NFS_PROTO(dir->d_inode)->unlink_setup(&msg, dir, &data->name); if (status < 0) goto out_err; + nfs_begin_data_update(dir->d_inode); rpc_call_setup(task, &msg, 0); return; out_err: @@ -126,7 +127,7 @@ if (!dir) return; dir_i = dir->d_inode; - nfs_zap_caches(dir_i); + nfs_end_data_update(dir_i); if (NFS_PROTO(dir_i)->unlink_done(dir, task)) return; put_rpccred(data->cred); diff -Nru a/fs/nfs/write.c b/fs/nfs/write.c --- a/fs/nfs/write.c Sun Mar 14 14:20:08 2004 +++ b/fs/nfs/write.c Sun Mar 14 14:20:08 2004 @@ -74,7 +74,6 @@ static struct nfs_page * nfs_update_request(struct file*, struct inode *, struct page *, unsigned int, unsigned int); -static void nfs_strategy(struct inode *inode); static kmem_cache_t *nfs_wdata_cachep; static mempool_t *nfs_wdata_mempool; @@ -124,6 +123,52 @@ nfs_commit_free(wdata); } +/* Adjust the file length if we're writing beyond the end */ +static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int count) +{ + struct inode *inode = page->mapping->host; + loff_t end, i_size = i_size_read(inode); + unsigned long end_index = (i_size - 1) >> PAGE_CACHE_SHIFT; + + if (i_size > 0 && page->index < end_index) + return; + end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + ((loff_t)offset+count); + if (i_size >= end) + return; + i_size_write(inode, end); +} + +/* We can set the PG_uptodate flag if we see that a write request + * covers the full page. + */ +static void nfs_mark_uptodate(struct page *page, unsigned int base, unsigned int count) +{ + loff_t end_offs; + + if (PageUptodate(page)) + return; + if (base != 0) + return; + if (count == PAGE_CACHE_SIZE) { + SetPageUptodate(page); + return; + } + + end_offs = i_size_read(page->mapping->host) - 1; + if (end_offs < 0) + return; + /* Is this the last page? */ + if (page->index != (unsigned long)(end_offs >> PAGE_CACHE_SHIFT)) + return; + /* This is the last page: set PG_uptodate if we cover the entire + * extent of the data, then zero the rest of the page. + */ + if (count == (unsigned int)(end_offs & (PAGE_CACHE_SIZE - 1)) + 1) { + memclear_highpage_flush(page, count, PAGE_CACHE_SIZE - count); + SetPageUptodate(page); + } +} + /* * Write a page synchronously. * Offset is the data offset within the page. @@ -157,6 +202,7 @@ (long long)NFS_FILEID(inode), count, (long long)(page_offset(page) + offset)); + nfs_begin_data_update(inode); do { if (count < wsize && !swapfile) wdata.args.count = count; @@ -177,43 +223,38 @@ wdata.args.pgbase += result; written += result; count -= result; - - /* - * If we've extended the file, update the inode - * now so we don't invalidate the cache. - */ - if (wdata.args.offset > i_size_read(inode)) - i_size_write(inode, wdata.args.offset); } while (count); + /* Update file length */ + nfs_grow_file(page, offset, written); + /* Set the PG_uptodate flag? */ + nfs_mark_uptodate(page, offset, written); if (PageError(page)) ClearPageError(page); io_error: + nfs_end_data_update(inode); if (wdata.cred) put_rpccred(wdata.cred); return written ? written : result; } -static int -nfs_writepage_async(struct file *file, struct inode *inode, struct page *page, - unsigned int offset, unsigned int count) +static int nfs_writepage_async(struct file *file, struct inode *inode, + struct page *page, unsigned int offset, unsigned int count) { struct nfs_page *req; - loff_t end; int status; req = nfs_update_request(file, inode, page, offset, count); status = (IS_ERR(req)) ? PTR_ERR(req) : 0; if (status < 0) goto out; + /* Update file length */ + nfs_grow_file(page, offset, count); + /* Set the PG_uptodate flag? */ + nfs_mark_uptodate(page, offset, count); nfs_unlock_request(req); - nfs_strategy(inode); - end = ((loff_t)page->index<sync_mode == WB_SYNC_HOLD) @@ -294,7 +335,7 @@ if (is_sync && wbc->sync_mode == WB_SYNC_ALL) { err = nfs_wb_all(inode); } else - nfs_commit_file(inode, NULL, 0, 0, 0); + nfs_commit_inode(inode, 0, 0, 0); out: return err; } @@ -312,8 +353,10 @@ BUG_ON(error == -EEXIST); if (error) return error; - if (!nfsi->npages) + if (!nfsi->npages) { igrab(inode); + nfs_begin_data_update(inode); + } nfsi->npages++; req->wb_count++; return 0; @@ -336,6 +379,7 @@ nfsi->npages--; if (!nfsi->npages) { spin_unlock(&nfs_wreq_lock); + nfs_end_data_update(inode); iput(inode); } else spin_unlock(&nfs_wreq_lock); @@ -421,7 +465,7 @@ * Interruptible by signals only if mounted with intr flag. */ static int -nfs_wait_on_requests(struct inode *inode, struct file *file, unsigned long idx_start, unsigned int npages) +nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, unsigned int npages) { struct nfs_inode *nfsi = NFS_I(inode); struct nfs_page *req; @@ -441,8 +485,6 @@ break; next = req->wb_index + 1; - if (file && req->wb_file != file) - continue; if (!NFS_WBACK_BUSY(req)) continue; @@ -453,7 +495,6 @@ if (error < 0) return error; spin_lock(&nfs_wreq_lock); - next = idx_start; res++; } spin_unlock(&nfs_wreq_lock); @@ -464,7 +505,6 @@ * nfs_scan_dirty - Scan an inode for dirty requests * @inode: NFS inode to scan * @dst: destination list - * @file: if set, ensure we match requests from this file * @idx_start: lower bound of page->index to scan. * @npages: idx_start + npages sets the upper bound to scan. * @@ -472,11 +512,11 @@ * The requests are *not* checked to ensure that they form a contiguous set. */ static int -nfs_scan_dirty(struct inode *inode, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages) +nfs_scan_dirty(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) { struct nfs_inode *nfsi = NFS_I(inode); int res; - res = nfs_scan_list(&nfsi->dirty, dst, file, idx_start, npages); + res = nfs_scan_list(&nfsi->dirty, dst, idx_start, npages); nfsi->ndirty -= res; sub_page_state(nr_dirty,res); if ((nfsi->ndirty == 0) != list_empty(&nfsi->dirty)) @@ -489,7 +529,6 @@ * nfs_scan_commit - Scan an inode for commit requests * @inode: NFS inode to scan * @dst: destination list - * @file: if set, ensure we collect requests from this file only. * @idx_start: lower bound of page->index to scan. * @npages: idx_start + npages sets the upper bound to scan. * @@ -497,11 +536,11 @@ * The requests are *not* checked to ensure that they form a contiguous set. */ static int -nfs_scan_commit(struct inode *inode, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages) +nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) { struct nfs_inode *nfsi = NFS_I(inode); int res; - res = nfs_scan_list(&nfsi->commit, dst, file, idx_start, npages); + res = nfs_scan_list(&nfsi->commit, dst, idx_start, npages); nfsi->ncommit -= res; if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit)) printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n"); @@ -600,46 +639,6 @@ return req; } -/* - * This is the strategy routine for NFS. - * It is called by nfs_updatepage whenever the user wrote up to the end - * of a page. - * - * We always try to submit a set of requests in parallel so that the - * server's write code can gather writes. This is mainly for the benefit - * of NFSv2. - * - * We never submit more requests than we think the remote can handle. - * For UDP sockets, we make sure we don't exceed the congestion window; - * for TCP, we limit the number of requests to 8. - * - * NFS_STRATEGY_PAGES gives the minimum number of requests for NFSv2 that - * should be sent out in one go. This is for the benefit of NFSv2 servers - * that perform write gathering. - * - * FIXME: Different servers may have different sweet spots. - * Record the average congestion window in server struct? - */ -#define NFS_STRATEGY_PAGES 8 -static void -nfs_strategy(struct inode *inode) -{ - unsigned int dirty, wpages; - - dirty = NFS_I(inode)->ndirty; - wpages = NFS_SERVER(inode)->wpages; -#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) - if (NFS_PROTO(inode)->version == 2) { - if (dirty >= NFS_STRATEGY_PAGES * wpages) - nfs_flush_file(inode, NULL, 0, 0, 0); - } else if (dirty >= wpages) - nfs_flush_file(inode, NULL, 0, 0, 0); -#else - if (dirty >= NFS_STRATEGY_PAGES * wpages) - nfs_flush_file(inode, NULL, 0, 0, 0); -#endif -} - int nfs_flush_incompatible(struct file *file, struct page *page) { @@ -675,7 +674,6 @@ struct dentry *dentry = file->f_dentry; struct inode *inode = page->mapping->host; struct nfs_page *req; - loff_t end; int status = 0; dprintk("NFS: nfs_updatepage(%s/%s %d@%Ld)\n", @@ -696,6 +694,27 @@ return status; } + /* If we're not using byte range locks, and we know the page + * is entirely in cache, it may be more efficient to avoid + * fragmenting write requests. + */ + if (PageUptodate(page) && inode->i_flock == NULL) { + loff_t end_offs = i_size_read(inode) - 1; + unsigned long end_index = end_offs >> PAGE_CACHE_SHIFT; + + count += offset; + offset = 0; + if (unlikely(end_offs < 0)) { + /* Do nothing */ + } else if (page->index == end_index) { + unsigned int pglen; + pglen = (unsigned int)(end_offs & (PAGE_CACHE_SIZE-1)) + 1; + if (count < pglen) + count = pglen; + } else if (page->index < end_index) + count = PAGE_CACHE_SIZE; + } + /* * Try to find an NFS request corresponding to this page * and update it. @@ -714,20 +733,12 @@ goto done; status = 0; - end = ((loff_t)page->index<wb_pgbase == 0 && req->wb_bytes == PAGE_CACHE_SIZE) { - SetPageUptodate(page); - nfs_unlock_request(req); - nfs_strategy(inode); - } else - nfs_unlock_request(req); + + /* Update file length */ + nfs_grow_file(page, offset, count); + /* Set the PG_uptodate flag? */ + nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes); + nfs_unlock_request(req); done: dprintk("NFS: nfs_updatepage returns %d (isize %Ld)\n", status, (long long)i_size_read(inode)); @@ -891,10 +902,7 @@ #endif /* - * Update attributes as result of writeback. - * FIXME: There is an inherent race with invalidate_inode_pages and - * writebacks since the page->count is kept > 1 for as long - * as the page has a write request pending. + * Process the nfs_page list */ while (!list_empty(&data->pages)) { req = nfs_list_entry(data->pages.next); @@ -1061,7 +1069,7 @@ } #endif -int nfs_flush_file(struct inode *inode, struct file *file, unsigned long idx_start, +int nfs_flush_inode(struct inode *inode, unsigned long idx_start, unsigned int npages, int how) { LIST_HEAD(head); @@ -1069,7 +1077,7 @@ error = 0; spin_lock(&nfs_wreq_lock); - res = nfs_scan_dirty(inode, &head, file, idx_start, npages); + res = nfs_scan_dirty(inode, &head, idx_start, npages); spin_unlock(&nfs_wreq_lock); if (res) error = nfs_flush_list(&head, NFS_SERVER(inode)->wpages, how); @@ -1079,7 +1087,7 @@ } #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) -int nfs_commit_file(struct inode *inode, struct file *file, unsigned long idx_start, +int nfs_commit_inode(struct inode *inode, unsigned long idx_start, unsigned int npages, int how) { LIST_HEAD(head); @@ -1087,9 +1095,9 @@ error = 0; spin_lock(&nfs_wreq_lock); - res = nfs_scan_commit(inode, &head, file, idx_start, npages); + res = nfs_scan_commit(inode, &head, idx_start, npages); if (res) { - res += nfs_scan_commit(inode, &head, NULL, 0, 0); + res += nfs_scan_commit(inode, &head, 0, 0); spin_unlock(&nfs_wreq_lock); error = nfs_commit_list(&head, how); } else @@ -1100,7 +1108,7 @@ } #endif -int nfs_sync_file(struct inode *inode, struct file *file, unsigned long idx_start, +int nfs_sync_inode(struct inode *inode, unsigned long idx_start, unsigned int npages, int how) { int error, @@ -1109,18 +1117,15 @@ wait = how & FLUSH_WAIT; how &= ~FLUSH_WAIT; - if (!inode && file) - inode = file->f_dentry->d_inode; - do { error = 0; if (wait) - error = nfs_wait_on_requests(inode, file, idx_start, npages); + error = nfs_wait_on_requests(inode, idx_start, npages); if (error == 0) - error = nfs_flush_file(inode, file, idx_start, npages, how); + error = nfs_flush_inode(inode, idx_start, npages, how); #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) if (error == 0) - error = nfs_commit_file(inode, file, idx_start, npages, how); + error = nfs_commit_inode(inode, idx_start, npages, how); #endif } while (error > 0); return error; diff -Nru a/fs/open.c b/fs/open.c --- a/fs/open.c Sun Mar 14 14:20:06 2004 +++ b/fs/open.c Sun Mar 14 14:20:06 2004 @@ -954,6 +954,7 @@ fd = error; goto out; } +EXPORT_SYMBOL_GPL(sys_open); #ifndef __alpha__ diff -Nru a/fs/proc/generic.c b/fs/proc/generic.c --- a/fs/proc/generic.c Sun Mar 14 14:20:08 2004 +++ b/fs/proc/generic.c Sun Mar 14 14:20:08 2004 @@ -661,6 +661,7 @@ proc_alloc_map); proc_kill_inodes(de); de->nlink = 0; + WARN_ON(de->subdir); if (!atomic_read(&de->count)) free_proc_entry(de); else { diff -Nru a/fs/proc/inode.c b/fs/proc/inode.c --- a/fs/proc/inode.c Sun Mar 14 14:20:08 2004 +++ b/fs/proc/inode.c Sun Mar 14 14:20:08 2004 @@ -231,6 +231,7 @@ { struct inode * root_inode; + s->s_flags |= MS_NODIRATIME; s->s_blocksize = 1024; s->s_blocksize_bits = 10; s->s_magic = PROC_SUPER_MAGIC; diff -Nru a/fs/proc/kmsg.c b/fs/proc/kmsg.c --- a/fs/proc/kmsg.c Sun Mar 14 14:20:08 2004 +++ b/fs/proc/kmsg.c Sun Mar 14 14:20:08 2004 @@ -33,6 +33,8 @@ static ssize_t kmsg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { + if ((file->f_flags & O_NONBLOCK) && !do_syslog(9, 0, 0)) + return -EAGAIN; return do_syslog(2, buf, count); } diff -Nru a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c --- a/fs/proc/proc_misc.c Sun Mar 14 14:20:06 2004 +++ b/fs/proc/proc_misc.c Sun Mar 14 14:20:06 2004 @@ -361,7 +361,8 @@ int i; extern unsigned long total_forks; unsigned long jif; - unsigned int sum = 0, user = 0, nice = 0, system = 0, idle = 0, iowait = 0, irq = 0, softirq = 0; + u64 sum = 0, user = 0, nice = 0, system = 0, + idle = 0, iowait = 0, irq = 0, softirq = 0; jif = - wall_to_monotonic.tv_sec; if (wall_to_monotonic.tv_nsec) @@ -381,26 +382,35 @@ sum += kstat_cpu(i).irqs[j]; } - seq_printf(p, "cpu %u %u %u %u %u %u %u\n", - jiffies_to_clock_t(user), - jiffies_to_clock_t(nice), - jiffies_to_clock_t(system), - jiffies_to_clock_t(idle), - jiffies_to_clock_t(iowait), - jiffies_to_clock_t(irq), - jiffies_to_clock_t(softirq)); + seq_printf(p, "cpu %llu %llu %llu %llu %llu %llu %llu\n", + (unsigned long long)jiffies_64_to_clock_t(user), + (unsigned long long)jiffies_64_to_clock_t(nice), + (unsigned long long)jiffies_64_to_clock_t(system), + (unsigned long long)jiffies_64_to_clock_t(idle), + (unsigned long long)jiffies_64_to_clock_t(iowait), + (unsigned long long)jiffies_64_to_clock_t(irq), + (unsigned long long)jiffies_64_to_clock_t(softirq)); for_each_cpu(i) { - seq_printf(p, "cpu%d %u %u %u %u %u %u %u\n", + /* two separate calls here to work around gcc-2.95.3 ICE */ + seq_printf(p, "cpu%d %llu %llu %llu ", i, - jiffies_to_clock_t(kstat_cpu(i).cpustat.user), - jiffies_to_clock_t(kstat_cpu(i).cpustat.nice), - jiffies_to_clock_t(kstat_cpu(i).cpustat.system), - jiffies_to_clock_t(kstat_cpu(i).cpustat.idle), - jiffies_to_clock_t(kstat_cpu(i).cpustat.iowait), - jiffies_to_clock_t(kstat_cpu(i).cpustat.irq), - jiffies_to_clock_t(kstat_cpu(i).cpustat.softirq)); + (unsigned long long) + jiffies_64_to_clock_t(kstat_cpu(i).cpustat.user), + (unsigned long long) + jiffies_64_to_clock_t(kstat_cpu(i).cpustat.nice), + (unsigned long long) + jiffies_64_to_clock_t(kstat_cpu(i).cpustat.system)); + seq_printf(p, "%llu %llu %llu %llu\n", + (unsigned long long) + jiffies_64_to_clock_t(kstat_cpu(i).cpustat.idle), + (unsigned long long) + jiffies_64_to_clock_t(kstat_cpu(i).cpustat.iowait), + (unsigned long long) + jiffies_64_to_clock_t(kstat_cpu(i).cpustat.irq), + (unsigned long long) + jiffies_64_to_clock_t(kstat_cpu(i).cpustat.softirq)); } - seq_printf(p, "intr %u", sum); + seq_printf(p, "intr %llu", (unsigned long long)sum); #if !defined(CONFIG_PPC64) && !defined(CONFIG_ALPHA) for (i = 0; i < NR_IRQS; i++) @@ -408,7 +418,7 @@ #endif seq_printf(p, - "\nctxt %lu\n" + "\nctxt %llu\n" "btime %lu\n" "processes %lu\n" "procs_running %lu\n" diff -Nru a/fs/qnx4/dir.c b/fs/qnx4/dir.c --- a/fs/qnx4/dir.c Sun Mar 14 14:20:07 2004 +++ b/fs/qnx4/dir.c Sun Mar 14 14:20:07 2004 @@ -76,8 +76,6 @@ } brelse(bh); } - update_atime(inode); - out: unlock_kernel(); return 0; diff -Nru a/fs/read_write.c b/fs/read_write.c --- a/fs/read_write.c Sun Mar 14 14:20:07 2004 +++ b/fs/read_write.c Sun Mar 14 14:20:07 2004 @@ -143,6 +143,7 @@ bad: return retval; } +EXPORT_SYMBOL_GPL(sys_lseek); #if !defined(__alpha__) asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high, @@ -281,6 +282,7 @@ return ret; } +EXPORT_SYMBOL_GPL(sys_read); asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_t count) { diff -Nru a/fs/readdir.c b/fs/readdir.c --- a/fs/readdir.c Sun Mar 14 14:20:07 2004 +++ b/fs/readdir.c Sun Mar 14 14:20:07 2004 @@ -32,6 +32,7 @@ res = -ENOENT; if (!IS_DEADDIR(inode)) { res = file->f_op->readdir(file, buf, filler); + update_atime(inode); } up(&inode->i_sem); out: diff -Nru a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c --- a/fs/reiserfs/dir.c Sun Mar 14 14:20:07 2004 +++ b/fs/reiserfs/dir.c Sun Mar 14 14:20:07 2004 @@ -186,7 +186,6 @@ filp->f_pos = next_pos; pathrelse (&path_to_entry); reiserfs_check_path(&path_to_entry) ; - update_atime(inode) ; out: reiserfs_write_unlock(inode->i_sb); return ret; diff -Nru a/fs/smbfs/inode.c b/fs/smbfs/inode.c --- a/fs/smbfs/inode.c Sun Mar 14 14:20:06 2004 +++ b/fs/smbfs/inode.c Sun Mar 14 14:20:06 2004 @@ -499,6 +499,7 @@ if (ver != SMB_MOUNT_OLDVERSION && cpu_to_be32(ver) != SMB_MOUNT_ASCII) goto out_wrong_data; + sb->s_flags |= MS_NODIRATIME; sb->s_blocksize = 1024; /* Eh... Is this correct? */ sb->s_blocksize_bits = 10; sb->s_magic = SMB_SUPER_MAGIC; @@ -778,6 +779,7 @@ .name = "smbfs", .get_sb = smb_get_sb, .kill_sb = kill_anon_super, + .fs_flags = FS_BINARY_MOUNTDATA, }; static int __init init_smb_fs(void) diff -Nru a/fs/super.c b/fs/super.c --- a/fs/super.c Sun Mar 14 14:20:07 2004 +++ b/fs/super.c Sun Mar 14 14:20:07 2004 @@ -745,7 +745,7 @@ goto out_mnt; } - error = security_sb_copy_data(fstype, data, secdata); + error = security_sb_copy_data(type, data, secdata); if (error) { sb = ERR_PTR(error); goto out_free_secdata; diff -Nru a/fs/sysv/dir.c b/fs/sysv/dir.c --- a/fs/sysv/dir.c Sun Mar 14 14:20:06 2004 +++ b/fs/sysv/dir.c Sun Mar 14 14:20:06 2004 @@ -116,7 +116,6 @@ done: filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset; - update_atime(inode); unlock_kernel(); return 0; } diff -Nru a/fs/udf/dir.c b/fs/udf/dir.c --- a/fs/udf/dir.c Sun Mar 14 14:20:06 2004 +++ b/fs/udf/dir.c Sun Mar 14 14:20:06 2004 @@ -15,7 +15,7 @@ * ftp://prep.ai.mit.edu/pub/gnu/GPL * Each contributing author retains all rights to their own work. * - * (C) 1998-2001 Ben Fennema + * (C) 1998-2004 Ben Fennema * * HISTORY * @@ -98,7 +98,6 @@ } result = do_udf_readdir(dir, filp, filldir, dirent); - update_atime(dir); unlock_kernel(); return result; } @@ -112,7 +111,7 @@ int block, iblock; loff_t nf_pos = filp->f_pos - 1; int flen; - char fname[255]; + char fname[UDF_NAME_LEN]; char *nameptr; uint16_t liu; uint8_t lfi; diff -Nru a/fs/udf/file.c b/fs/udf/file.c --- a/fs/udf/file.c Sun Mar 14 14:20:07 2004 +++ b/fs/udf/file.c Sun Mar 14 14:20:07 2004 @@ -16,7 +16,7 @@ * Each contributing author retains all rights to their own work. * * (C) 1998-1999 Dave Boynton - * (C) 1998-2001 Ben Fennema + * (C) 1998-2004 Ben Fennema * (C) 1999-2000 Stelias Computing Inc * * HISTORY @@ -247,9 +247,9 @@ { if (filp->f_mode & FMODE_WRITE) { - lock_kernel(); + down(&inode->i_sem); udf_discard_prealloc(inode); - unlock_kernel(); + up(&inode->i_sem); } return 0; } diff -Nru a/fs/udf/inode.c b/fs/udf/inode.c --- a/fs/udf/inode.c Sun Mar 14 14:20:09 2004 +++ b/fs/udf/inode.c Sun Mar 14 14:20:09 2004 @@ -16,7 +16,7 @@ * Each contributing author retains all rights to their own work. * * (C) 1998 Dave Boynton - * (C) 1998-2001 Ben Fennema + * (C) 1998-2004 Ben Fennema * (C) 1999-2000 Stelias Computing Inc * * HISTORY @@ -84,9 +84,9 @@ { if (!(inode->i_sb->s_flags & MS_RDONLY)) { - lock_kernel(); + down(&inode->i_sem); udf_discard_prealloc(inode); - unlock_kernel(); + up(&inode->i_sem); } } @@ -130,15 +130,6 @@ UDF_I_DATA(inode) = NULL; } -void udf_discard_prealloc(struct inode * inode) -{ - if (inode->i_size && inode->i_size != UDF_I_LENEXTENTS(inode) && - UDF_I_ALLOCTYPE(inode) != ICBTAG_FLAG_AD_IN_ICB) - { - udf_truncate_extents(inode); - } -} - static int udf_writepage(struct page *page, struct writeback_control *wbc) { return block_write_full_page(page, udf_get_block, wbc); @@ -516,11 +507,8 @@ else lastblock = 1; } + udf_release_data(cbh); udf_release_data(nbh); - if (!pbh) - pbh = cbh; - else - udf_release_data(cbh); /* if the current extent is not recorded but allocated, get the block in the extent corresponding to the requested block */ @@ -595,7 +583,7 @@ int curr = *c; int blen = ((laarr[curr].extLength & UDF_EXTENT_LENGTH_MASK) + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits; - int type = laarr[curr].extLength & ~UDF_EXTENT_LENGTH_MASK; + int8_t etype = (laarr[curr].extLength >> 30); if (blen == 1) ; @@ -612,7 +600,7 @@ if (offset) { - if ((type >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30)) + if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) { udf_free_blocks(inode->i_sb, inode, laarr[curr].extLocation, 0, offset); laarr[curr].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | @@ -621,7 +609,7 @@ laarr[curr].extLocation.partitionReferenceNum = 0; } else - laarr[curr].extLength = type | + laarr[curr].extLength = (etype << 30) | (offset << inode->i_sb->s_blocksize_bits); curr ++; (*c) ++; @@ -629,7 +617,7 @@ } laarr[curr].extLocation.logicalBlockNum = newblocknum; - if ((type >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) + if (etype == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) laarr[curr].extLocation.partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum; laarr[curr].extLength = EXT_RECORDED_ALLOCATED | @@ -638,9 +626,9 @@ if (blen != offset + 1) { - if ((type >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30)) + if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) laarr[curr].extLocation.logicalBlockNum += (offset + 1); - laarr[curr].extLength = type | + laarr[curr].extLength = (etype << 30) | ((blen - (offset + 1)) << inode->i_sb->s_blocksize_bits); curr ++; (*endnum) ++; @@ -761,8 +749,8 @@ laarr[i+1].extLength = (laarr[i+1].extLength - (laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) + UDF_EXTENT_LENGTH_MASK) & ~(inode->i_sb->s_blocksize-1); - laarr[i].extLength = (UDF_EXTENT_LENGTH_MASK + 1) - - inode->i_sb->s_blocksize; + laarr[i].extLength = (laarr[i].extLength & UDF_EXTENT_FLAG_MASK) + + (UDF_EXTENT_LENGTH_MASK + 1) - inode->i_sb->s_blocksize; laarr[i+1].extLocation.logicalBlockNum = laarr[i].extLocation.logicalBlockNum + ((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) >> @@ -781,6 +769,47 @@ } } } + else if (((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30)) && + ((laarr[i+1].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))) + { + udf_free_blocks(inode->i_sb, inode, laarr[i].extLocation, 0, + ((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) + + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits); + laarr[i].extLocation.logicalBlockNum = 0; + laarr[i].extLocation.partitionReferenceNum = 0; + + if (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) + + (laarr[i+1].extLength & UDF_EXTENT_LENGTH_MASK) + + inode->i_sb->s_blocksize - 1) & ~UDF_EXTENT_LENGTH_MASK) + { + laarr[i+1].extLength = (laarr[i+1].extLength - + (laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) + + UDF_EXTENT_LENGTH_MASK) & ~(inode->i_sb->s_blocksize-1); + laarr[i].extLength = (laarr[i].extLength & UDF_EXTENT_FLAG_MASK) + + (UDF_EXTENT_LENGTH_MASK + 1) - inode->i_sb->s_blocksize; + } + else + { + laarr[i].extLength = laarr[i+1].extLength + + (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) + + inode->i_sb->s_blocksize - 1) & ~(inode->i_sb->s_blocksize-1)); + if (*endnum > (i+2)) + memmove(&laarr[i+1], &laarr[i+2], + sizeof(long_ad) * (*endnum - (i+2))); + i --; + (*endnum) --; + } + } + else if ((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30)) + { + udf_free_blocks(inode->i_sb, inode, laarr[i].extLocation, 0, + ((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) + + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits); + laarr[i].extLocation.logicalBlockNum = 0; + laarr[i].extLocation.partitionReferenceNum = 0; + laarr[i].extLength = (laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) | + EXT_NOT_RECORDED_NOT_ALLOCATED; + } } } @@ -1014,7 +1043,7 @@ struct extendedFileEntry *efe; time_t convtime; long convtime_usec; - int offset, alen; + int offset; fe = (struct fileEntry *)bh->b_data; efe = (struct extendedFileEntry *)bh->b_data; @@ -1115,7 +1144,6 @@ UDF_I_LENEATTR(inode) = le32_to_cpu(fe->lengthExtendedAttr); UDF_I_LENALLOC(inode) = le32_to_cpu(fe->lengthAllocDescs); offset = sizeof(struct fileEntry) + UDF_I_LENEATTR(inode); - alen = offset + UDF_I_LENALLOC(inode); } else { @@ -1170,7 +1198,6 @@ UDF_I_LENEATTR(inode) = le32_to_cpu(efe->lengthExtendedAttr); UDF_I_LENALLOC(inode) = le32_to_cpu(efe->lengthAllocDescs); offset = sizeof(struct extendedFileEntry) + UDF_I_LENEATTR(inode); - alen = offset + UDF_I_LENALLOC(inode); } switch (fe->icbTag.fileType) @@ -1211,6 +1238,11 @@ init_special_inode(inode, inode->i_mode | S_IFIFO, 0); break; } + case ICBTAG_FILE_TYPE_SOCKET: + { + init_special_inode(inode, inode->i_mode | S_IFSOCK, 0); + break; + } case ICBTAG_FILE_TYPE_SYMLINK: { inode->i_data.a_ops = &udf_symlink_aops; @@ -1228,19 +1260,16 @@ } if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { - struct buffer_head *tbh = NULL; struct deviceSpec *dsea = (struct deviceSpec *) - udf_get_extendedattr(inode, 12, 1, &tbh); + udf_get_extendedattr(inode, 12, 1); if (dsea) { init_special_inode(inode, inode->i_mode, MKDEV( le32_to_cpu(dsea->majorDeviceIdent), - le32_to_cpu(dsea->minorDeviceIdent) - )); + le32_to_cpu(dsea->minorDeviceIdent))); /* Developer ID ??? */ - udf_release_data(tbh); } else { @@ -1372,17 +1401,16 @@ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { regid *eid; - struct buffer_head *tbh = NULL; struct deviceSpec *dsea = (struct deviceSpec *) - udf_get_extendedattr(inode, 12, 1, &tbh); + udf_get_extendedattr(inode, 12, 1); if (!dsea) { dsea = (struct deviceSpec *) udf_add_extendedattr(inode, sizeof(struct deviceSpec) + - sizeof(regid), 12, 0x3, &tbh); + sizeof(regid), 12, 0x3); dsea->attrType = 12; dsea->attrSubtype = 1; dsea->attrLength = sizeof(struct deviceSpec) + @@ -1396,8 +1424,6 @@ eid->identSuffix[1] = UDF_OS_ID_LINUX; dsea->majorDeviceIdent = cpu_to_le32(imajor(inode)); dsea->minorDeviceIdent = cpu_to_le32(iminor(inode)); - mark_buffer_dirty_inode(tbh, inode); - udf_release_data(tbh); } if (UDF_I_EFE(inode) == 0) @@ -1493,6 +1519,8 @@ fe->icbTag.fileType = ICBTAG_FILE_TYPE_CHAR; else if (S_ISFIFO(inode->i_mode)) fe->icbTag.fileType = ICBTAG_FILE_TYPE_FIFO; + else if (S_ISSOCK(inode->i_mode)) + fe->icbTag.fileType = ICBTAG_FILE_TYPE_SOCKET; icbflags = UDF_I_ALLOCTYPE(inode) | ((inode->i_mode & S_ISUID) ? ICBTAG_FLAG_SETUID : 0) | @@ -1625,7 +1653,7 @@ int err, loffset; lb_addr obloc = *bloc; - if (!(bloc->logicalBlockNum = udf_new_block(inode->i_sb, inode, + if (!(bloc->logicalBlockNum = udf_new_block(inode->i_sb, NULL, obloc.partitionReferenceNum, obloc.logicalBlockNum, &err))) { return -1; @@ -1833,7 +1861,7 @@ if (!(*extoffset)) *extoffset = sizeof(struct allocExtDesc); ptr = (*bh)->b_data + *extoffset; - alen = le32_to_cpu(((struct allocExtDesc *)(*bh)->b_data)->lengthAllocDescs); + alen = sizeof(struct allocExtDesc) + le32_to_cpu(((struct allocExtDesc *)(*bh)->b_data)->lengthAllocDescs); } switch (UDF_I_ALLOCTYPE(inode)) diff -Nru a/fs/udf/misc.c b/fs/udf/misc.c --- a/fs/udf/misc.c Sun Mar 14 14:20:07 2004 +++ b/fs/udf/misc.c Sun Mar 14 14:20:07 2004 @@ -16,7 +16,7 @@ * Each contributing author retains all rights to their own work. * * (C) 1998 Dave Boynton - * (C) 1998-2001 Ben Fennema + * (C) 1998-2004 Ben Fennema * (C) 1999-2000 Stelias Computing Inc * * HISTORY @@ -34,18 +34,6 @@ #include "udf_i.h" #include "udf_sb.h" -uint32_t -udf64_low32(uint64_t indat) -{ - return indat & 0x00000000FFFFFFFFULL; -} - -uint32_t -udf64_high32(uint64_t indat) -{ - return indat >> 32; -} - extern struct buffer_head * udf_tgetblk(struct super_block *sb, int block) { @@ -66,42 +54,24 @@ extern struct genericFormat * udf_add_extendedattr(struct inode * inode, uint32_t size, uint32_t type, - uint8_t loc, struct buffer_head **bh) + uint8_t loc) { uint8_t *ea = NULL, *ad = NULL; - long_ad eaicb; int offset; + uint16_t crclen; + int i; - *bh = udf_tread(inode->i_sb, inode->i_ino); - - if (UDF_I_EFE(inode) == 0) - { - struct fileEntry *fe; - - fe = (struct fileEntry *)(*bh)->b_data; - eaicb = lela_to_cpu(fe->extendedAttrICB); - offset = sizeof(struct fileEntry); - } - else - { - struct extendedFileEntry *efe; - - efe = (struct extendedFileEntry *)(*bh)->b_data; - eaicb = lela_to_cpu(efe->extendedAttrICB); - offset = sizeof(struct extendedFileEntry); - } - - ea = &(*bh)->b_data[offset]; + ea = UDF_I_DATA(inode); if (UDF_I_LENEATTR(inode)) - offset += UDF_I_LENEATTR(inode); + ad = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode); else + { + ad = ea; size += sizeof(struct extendedAttrHeaderDesc); + } - ad = &(*bh)->b_data[offset]; - if (UDF_I_LENALLOC(inode)) - offset += UDF_I_LENALLOC(inode); - - offset = inode->i_sb->s_blocksize - offset; + offset = inode->i_sb->s_blocksize - udf_file_entry_alloc_offset(inode) - + UDF_I_LENALLOC(inode); /* TODO - Check for FreeEASpace */ @@ -121,7 +91,6 @@ if (le16_to_cpu(eahd->descTag.tagIdent) != TAG_IDENT_EAHD || le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum) { - udf_release_data(*bh); return NULL; } } @@ -130,8 +99,11 @@ size -= sizeof(struct extendedAttrHeaderDesc); UDF_I_LENEATTR(inode) += sizeof(struct extendedAttrHeaderDesc); eahd->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EAHD); - eahd->descTag.descVersion = cpu_to_le16(2); - eahd->descTag.tagSerialNum = cpu_to_le16(1); + if (UDF_SB_UDFREV(inode->i_sb) >= 0x0200) + eahd->descTag.descVersion = cpu_to_le16(3); + else + eahd->descTag.descVersion = cpu_to_le16(2); + eahd->descTag.tagSerialNum = cpu_to_le16(UDF_SB_SERIALNUM(inode->i_sb)); eahd->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum); eahd->impAttrLocation = cpu_to_le32(0xFFFFFFFF); eahd->appAttrLocation = cpu_to_le32(0xFFFFFFFF); @@ -169,45 +141,30 @@ } } /* rewrite CRC + checksum of eahd */ + crclen = sizeof(struct extendedAttrHeaderDesc) - sizeof(tag); + eahd->descTag.descCRCLength = cpu_to_le16(crclen); + eahd->descTag.descCRC = cpu_to_le16(udf_crc((char *)eahd + sizeof(tag), crclen, 0)); + eahd->descTag.tagChecksum = 0; + for (i=0; i<16; i++) + if (i != 4) + eahd->descTag.tagChecksum += ((uint8_t *)&(eahd->descTag))[i]; UDF_I_LENEATTR(inode) += size; return (struct genericFormat *)&ea[offset]; } if (loc & 0x02) { } - udf_release_data(*bh); return NULL; } extern struct genericFormat * -udf_get_extendedattr(struct inode * inode, uint32_t type, uint8_t subtype, - struct buffer_head **bh) +udf_get_extendedattr(struct inode *inode, uint32_t type, uint8_t subtype) { struct genericFormat *gaf; uint8_t *ea = NULL; - long_ad eaicb; uint32_t offset; - *bh = udf_tread(inode->i_sb, inode->i_ino); - - if (UDF_I_EFE(inode) == 0) - { - struct fileEntry *fe; - - fe = (struct fileEntry *)(*bh)->b_data; - eaicb = lela_to_cpu(fe->extendedAttrICB); - if (UDF_I_LENEATTR(inode)) - ea = fe->extendedAttr; - } - else - { - struct extendedFileEntry *efe; - - efe = (struct extendedFileEntry *)(*bh)->b_data; - eaicb = lela_to_cpu(efe->extendedAttrICB); - if (UDF_I_LENEATTR(inode)) - ea = efe->extendedAttr; - } + ea = UDF_I_DATA(inode); if (UDF_I_LENEATTR(inode)) { @@ -218,7 +175,6 @@ if (le16_to_cpu(eahd->descTag.tagIdent) != TAG_IDENT_EAHD || le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum) { - udf_release_data(*bh); return NULL; } @@ -237,12 +193,6 @@ else offset += le32_to_cpu(gaf->attrLength); } - } - - udf_release_data(*bh); - if (eaicb.extLength) - { - /* TODO */ } return NULL; } diff -Nru a/fs/udf/namei.c b/fs/udf/namei.c --- a/fs/udf/namei.c Sun Mar 14 14:20:08 2004 +++ b/fs/udf/namei.c Sun Mar 14 14:20:08 2004 @@ -15,7 +15,7 @@ * ftp://prep.ai.mit.edu/pub/gnu/GPL * Each contributing author retains all rights to their own work. * - * (C) 1998-2001 Ben Fennema + * (C) 1998-2004 Ben Fennema * (C) 1999-2000 Stelias Computing Inc * * HISTORY @@ -36,11 +36,11 @@ #include #include -static inline int udf_match(int len, const char * const name, struct qstr *qs) +static inline int udf_match(int len1, const char *name1, int len2, const char *name2) { - if (len != qs->len) + if (len1 != len2) return 0; - return !memcmp(name, qs->name, len); + return !memcmp(name1, name2, len1); } int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi, @@ -154,8 +154,8 @@ { struct fileIdentDesc *fi=NULL; loff_t f_pos; - int block, flen; - char fname[255]; + int block, namelen; + char name[UDF_NAME_LEN], fname[UDF_NAME_LEN]; char *nameptr; uint8_t lfi; uint16_t liu; @@ -167,6 +167,9 @@ if (!dir) return NULL; + if ( !(namelen = udf_put_filename(dir->i_sb, dentry->d_name.name, name, dentry->d_name.len))) + return NULL; + f_pos = (udf_ext0_offset(dir) >> 2); fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2; @@ -250,13 +253,10 @@ if (!lfi) continue; - if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi))) + if (udf_match(namelen, name, lfi, nameptr)) { - if (udf_match(flen, fname, &(dentry->d_name))) - { - udf_release_data(bh); - return fi; - } + udf_release_data(bh); + return fi; } } if (fibh->sbh != fibh->ebh) @@ -306,7 +306,7 @@ struct fileIdentDesc cfi, *fi; struct udf_fileident_bh fibh; - if (dentry->d_name.len > UDF_NAME_LEN) + if (dentry->d_name.len > UDF_NAME_LEN-2) return ERR_PTR(-ENAMETOOLONG); lock_kernel(); @@ -353,7 +353,6 @@ char name[UDF_NAME_LEN], fname[UDF_NAME_LEN]; int namelen; loff_t f_pos; - int flen; char *nameptr; loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2; int nfidlen; @@ -481,8 +480,7 @@ if (!lfi || !dentry) continue; - if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi)) && - udf_match(flen, fname, &(dentry->d_name))) + if (udf_match(namelen, name, lfi, nameptr)) { if (fibh->sbh != fibh->ebh) udf_release_data(fibh->ebh); @@ -674,8 +672,8 @@ { struct inode * inode; struct udf_fileident_bh fibh; - int err; struct fileIdentDesc cfi, *fi; + int err; if (!old_valid_dev(rdev)) return -EINVAL; @@ -721,8 +719,8 @@ { struct inode * inode; struct udf_fileident_bh fibh; - int err; struct fileIdentDesc cfi, *fi; + int err; lock_kernel(); err = -EMLINK; @@ -1119,8 +1117,8 @@ { struct inode *inode = old_dentry->d_inode; struct udf_fileident_bh fibh; - int err; struct fileIdentDesc cfi, *fi; + int err; lock_kernel(); if (inode->i_nlink >= (256<i_nlink))-1) diff -Nru a/fs/udf/osta_udf.h b/fs/udf/osta_udf.h --- a/fs/udf/osta_udf.h Sun Mar 14 14:20:07 2004 +++ b/fs/udf/osta_udf.h Sun Mar 14 14:20:07 2004 @@ -1,10 +1,10 @@ /* * osta_udf.h * - * This file is based on OSTA UDF(tm) 2.01 (March 15, 2000) + * This file is based on OSTA UDF(tm) 2.50 (April 30, 2003) * http://www.osta.org * - * Copyright (c) 2001-2002 Ben Fennema + * Copyright (c) 2001-2004 Ben Fennema * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,12 +37,12 @@ #ifndef _OSTA_UDF_H #define _OSTA_UDF_H 1 -/* OSTA CS0 Charspec (UDF 2.01 2.1.2) */ +/* OSTA CS0 Charspec (UDF 2.50 2.1.2) */ #define UDF_CHAR_SET_TYPE 0 #define UDF_CHAR_SET_INFO "OSTA Compressed Unicode" -/* Entity Identifier (UDF 2.01 2.1.5) */ -/* Identifiers (UDF 2.01 2.1.5.2) */ +/* Entity Identifier (UDF 2.50 2.1.5) */ +/* Identifiers (UDF 2.50 2.1.5.2) */ #define UDF_ID_DEVELOPER "*Linux UDFFS" #define UDF_ID_COMPLIANT "*OSTA UDF Compliant" #define UDF_ID_LV_INFO "*UDF LV Info" @@ -59,8 +59,9 @@ #define UDF_ID_SPARABLE "*UDF Sparable Partition" #define UDF_ID_ALLOC "*UDF Virtual Alloc Tbl" #define UDF_ID_SPARING "*UDF Sparing Table" +#define UDF_ID_METADATA "*UDF Metadata Partition" -/* Identifier Suffix (UDF 2.01 2.1.5.3) */ +/* Identifier Suffix (UDF 2.50 2.1.5.3) */ #define IS_DF_HARD_WRITE_PROTECT 0x01 #define IS_DF_SOFT_WRITE_PROTECT 0x02 @@ -84,8 +85,8 @@ uint8_t impUse[8]; } __attribute__ ((packed)); -/* Logical Volume Integrity Descriptor (UDF 2.01 2.2.6) */ -/* Implementation Use (UDF 2.01 2.2.6.4) */ +/* Logical Volume Integrity Descriptor (UDF 2.50 2.2.6) */ +/* Implementation Use (UDF 2.50 2.2.6.4) */ struct logicalVolIntegrityDescImpUse { regid impIdent; @@ -97,8 +98,8 @@ uint8_t impUse[0]; } __attribute__ ((packed)); -/* Implementation Use Volume Descriptor (UDF 2.01 2.2.7) */ -/* Implementation Use (UDF 2.01 2.2.7.2) */ +/* Implementation Use Volume Descriptor (UDF 2.50 2.2.7) */ +/* Implementation Use (UDF 2.50 2.2.7.2) */ struct impUseVolDescImpUse { charspec LVICharset; @@ -120,7 +121,7 @@ uint16_t partitionNum; } __attribute__ ((packed)); -/* Virtual Partition Map (UDF 2.01 2.2.8) */ +/* Virtual Partition Map (UDF 2.50 2.2.8) */ struct virtualPartitionMap { uint8_t partitionMapType; @@ -132,7 +133,7 @@ uint8_t reserved2[24]; } __attribute__ ((packed)); -/* Sparable Partition Map (UDF 2.01 2.2.9) */ +/* Sparable Partition Map (UDF 2.50 2.2.9) */ struct sparablePartitionMap { uint8_t partitionMapType; @@ -148,25 +149,43 @@ uint32_t locSparingTable[4]; } __attribute__ ((packed)); +/* Metadata Partition Map (UDF 2.4.0 2.2.10) */ +struct metadataPartitionMap +{ + uint8_t partitionMapType; + uint8_t partitionMapLength; + uint8_t reserved1[2]; + regid partIdent; + uint16_t volSeqNum; + uint16_t partitionNum; + uint32_t metadataFileLoc; + uint32_t metadataMirrorFileLoc; + uint32_t metadataBitmapFileLoc; + uint32_t allocUnitSize; + uint16_t alignUnitSize; + uint8_t flags; + uint8_t reserved2[5]; +} __attribute__ ((packed)); + /* Virtual Allocation Table (UDF 1.5 2.2.10) */ struct virtualAllocationTable15 { uint32_t VirtualSector[0]; - regid ident; - uint32_t previousVATICB; + regid vatIdent; + uint32_t previousVATICBLoc; } __attribute__ ((packed)); #define ICBTAG_FILE_TYPE_VAT15 0x00U -/* Virtual Allocation Table (UDF 2.01 2.2.10) */ +/* Virtual Allocation Table (UDF 2.50 2.2.11) */ struct virtualAllocationTable20 { uint16_t lengthHeader; uint16_t lengthImpUse; dstring logicalVolIdent[128]; - uint32_t previousVatICBLoc; - uint32_t numFIDSFiles; - uint32_t numFIDSDirectories; + uint32_t previousVATICBLoc; + uint32_t numFiles; + uint32_t numDirs; uint16_t minReadRevision; uint16_t minWriteRevision; uint16_t maxWriteRevision; @@ -177,7 +196,7 @@ #define ICBTAG_FILE_TYPE_VAT20 0xF8U -/* Sparing Table (UDF 2.01 2.2.11) */ +/* Sparing Table (UDF 2.50 2.2.12) */ struct sparingEntry { uint32_t origLocation; @@ -195,7 +214,12 @@ mapEntry[0]; } __attribute__ ((packed)); -/* struct long_ad ICB - ADImpUse (UDF 2.01 2.2.4.3) */ +/* Metadata File (and Metadata Mirror File) (UDF 2.50 2.2.13.1) */ +#define ICBTAG_FILE_TYPE_MAIN 0xFA +#define ICBTAG_FILE_TYPE_MIRROR 0xFB +#define ICBTAG_FILE_TYPE_BITMAP 0xFC + +/* struct long_ad ICB - ADImpUse (UDF 2.50 2.2.4.3) */ struct allocDescImpUse { uint16_t flags; @@ -204,18 +228,18 @@ #define AD_IU_EXT_ERASED 0x0001 -/* Real-Time Files (UDF 2.01 6.11) */ +/* Real-Time Files (UDF 2.50 6.11) */ #define ICBTAG_FILE_TYPE_REALTIME 0xF9U -/* Implementation Use Extended Attribute (UDF 2.01 3.3.4.5) */ -/* FreeEASpace (UDF 2.01 3.3.4.5.1.1) */ +/* Implementation Use Extended Attribute (UDF 2.50 3.3.4.5) */ +/* FreeEASpace (UDF 2.50 3.3.4.5.1.1) */ struct freeEaSpace { uint16_t headerChecksum; uint8_t freeEASpace[0]; } __attribute__ ((packed)); -/* DVD Copyright Management Information (UDF 2.01 3.3.4.5.1.2) */ +/* DVD Copyright Management Information (UDF 2.50 3.3.4.5.1.2) */ struct DVDCopyrightImpUse { uint16_t headerChecksum; @@ -224,21 +248,21 @@ uint8_t protectionSystemInfo[4]; } __attribute__ ((packed)); -/* Application Use Extended Attribute (UDF 2.01 3.3.4.6) */ -/* FreeAppEASpace (UDF 2.01 3.3.4.6.1) */ +/* Application Use Extended Attribute (UDF 2.50 3.3.4.6) */ +/* FreeAppEASpace (UDF 2.50 3.3.4.6.1) */ struct freeAppEASpace { uint16_t headerChecksum; uint8_t freeEASpace[0]; } __attribute__ ((packed)); -/* UDF Defined System Stream (UDF 2.01 3.3.7) */ +/* UDF Defined System Stream (UDF 2.50 3.3.7) */ #define UDF_ID_UNIQUE_ID "*UDF Unique ID Mapping Data" #define UDF_ID_NON_ALLOC "*UDF Non-Allocatable Space" #define UDF_ID_POWER_CAL "*UDF Power Cal Table" #define UDF_ID_BACKUP "*UDF Backup" -/* Operating System Identifiers (UDF 2.01 6.3) */ +/* Operating System Identifiers (UDF 2.50 6.3) */ #define UDF_OS_CLASS_UNDEF 0x00U #define UDF_OS_CLASS_DOS 0x01U #define UDF_OS_CLASS_OS2 0x02U @@ -254,6 +278,7 @@ #define UDF_OS_ID_DOS 0x00U #define UDF_OS_ID_OS2 0x00U #define UDF_OS_ID_MAC 0x00U +#define UDF_OS_ID_MAX_OSX 0x01U #define UDF_OS_ID_UNIX 0x00U #define UDF_OS_ID_AIX 0x01U #define UDF_OS_ID_SOLARIS 0x02U diff -Nru a/fs/udf/super.c b/fs/udf/super.c --- a/fs/udf/super.c Sun Mar 14 14:20:07 2004 +++ b/fs/udf/super.c Sun Mar 14 14:20:07 2004 @@ -26,7 +26,7 @@ * Each contributing author retains all rights to their own work. * * (C) 1998 Dave Boynton - * (C) 1998-2001 Ben Fennema + * (C) 1998-2004 Ben Fennema * (C) 2000 Stelias Computing Inc * * HISTORY @@ -57,6 +57,7 @@ #include #include #include +#include #include #include @@ -133,7 +134,8 @@ struct udf_inode_info *ei = (struct udf_inode_info *) foo; if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == - SLAB_CTOR_CONSTRUCTOR) { + SLAB_CTOR_CONSTRUCTOR) + { ei->i_ext.i_data = NULL; inode_init_once(&ei->vfs_inode); } @@ -324,106 +326,106 @@ if (!options) return 1; - while ((p = strsep(&options, ",")) != NULL) { + while ((p = strsep(&options, ",")) != NULL) + { substring_t args[MAX_OPT_ARGS]; int token; if (!*p) continue; token = match_token(p, tokens, args); - switch (token) { - case Opt_novrs: - uopt->novrs = 1; - break; - case Opt_bs: - if (match_int(&args[0], &option)) - return 0; - uopt->blocksize = option; - break; - case Opt_unhide: - uopt->flags |= (1 << UDF_FLAG_UNHIDE); - break; - case Opt_undelete: - uopt->flags |= (1 << UDF_FLAG_UNDELETE); - break; - case Opt_noadinicb: - uopt->flags &= ~(1 << UDF_FLAG_USE_AD_IN_ICB); - break; - case Opt_adinicb: - uopt->flags |= (1 << UDF_FLAG_USE_AD_IN_ICB); - break; - case Opt_shortad: - uopt->flags |= (1 << UDF_FLAG_USE_SHORT_AD); - break; - case Opt_longad: - uopt->flags &= ~(1 << UDF_FLAG_USE_SHORT_AD); - break; - case Opt_gid: - if (match_int(args, &option)) - return 0; - uopt->gid = option; - break; - case Opt_uid: - if (match_int(args, &option)) - return 0; - uopt->uid = option; - break; - case Opt_umask: - if (match_octal(args, &option)) - return 0; - uopt->umask = option; - break; - case Opt_nostrict: - uopt->flags &= ~(1 << UDF_FLAG_STRICT); - break; - case Opt_session: - if (match_int(args, &option)) - return 0; - uopt->session = option; - break; - case Opt_lastblock: - if (match_int(args, &option)) - return 0; - uopt->lastblock = option; - break; - case Opt_anchor: - if (match_int(args, &option)) - return 0; - uopt->anchor = option; - break; - case Opt_volume: - if (match_int(args, &option)) - return 0; - uopt->volume = option; - break; - case Opt_partition: - if (match_int(args, &option)) - return 0; - uopt->partition = option; - break; - case Opt_fileset: - if (match_int(args, &option)) - return 0; - uopt->fileset = option; - break; - case Opt_rootdir: - if (match_int(args, &option)) - return 0; - uopt->rootdir = option; - break; - case Opt_utf8: - uopt->flags |= (1 << UDF_FLAG_UTF8); - break; + switch (token) + { + case Opt_novrs: + uopt->novrs = 1; + case Opt_bs: + if (match_int(&args[0], &option)) + return 0; + uopt->blocksize = option; + break; + case Opt_unhide: + uopt->flags |= (1 << UDF_FLAG_UNHIDE); + break; + case Opt_undelete: + uopt->flags |= (1 << UDF_FLAG_UNDELETE); + break; + case Opt_noadinicb: + uopt->flags &= ~(1 << UDF_FLAG_USE_AD_IN_ICB); + break; + case Opt_adinicb: + uopt->flags |= (1 << UDF_FLAG_USE_AD_IN_ICB); + break; + case Opt_shortad: + uopt->flags |= (1 << UDF_FLAG_USE_SHORT_AD); + break; + case Opt_longad: + uopt->flags &= ~(1 << UDF_FLAG_USE_SHORT_AD); + break; + case Opt_gid: + if (match_int(args, &option)) + return 0; + uopt->gid = option; + break; + case Opt_uid: + if (match_int(args, &option)) + return 0; + uopt->uid = option; + break; + case Opt_umask: + if (match_octal(args, &option)) + return 0; + uopt->umask = option; + break; + case Opt_nostrict: + uopt->flags &= ~(1 << UDF_FLAG_STRICT); + break; + case Opt_session: + if (match_int(args, &option)) + return 0; + uopt->session = option; + break; + case Opt_lastblock: + if (match_int(args, &option)) + return 0; + uopt->lastblock = option; + break; + case Opt_anchor: + if (match_int(args, &option)) + return 0; + uopt->anchor = option; + break; + case Opt_volume: + if (match_int(args, &option)) + return 0; + uopt->volume = option; + break; + case Opt_partition: + if (match_int(args, &option)) + return 0; + uopt->partition = option; + break; + case Opt_fileset: + if (match_int(args, &option)) + return 0; + uopt->fileset = option; + break; + case Opt_rootdir: + if (match_int(args, &option)) + return 0; + uopt->rootdir = option; + break; + case Opt_utf8: + uopt->flags |= (1 << UDF_FLAG_UTF8); + break; #if defined(CONFIG_NLS) || defined(CONFIG_NLS_MODULE) - case Opt_iocharset: - uopt->nls_map = load_nls(args[0].from); - uopt->flags |= (1 << UDF_FLAG_NLS_MAP); - break; + case Opt_iocharset: + uopt->nls_map = load_nls(args[0].from); + uopt->flags |= (1 << UDF_FLAG_NLS_MAP); + break; #endif - default: - printk(KERN_ERR "udf: bad mount option \"%s\" " - "or missing value\n", - p); + default: + printk(KERN_ERR "udf: bad mount option \"%s\" " + "or missing value\n", p); return 0; } } @@ -1651,23 +1653,9 @@ if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE) iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table); if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP) - { - for (i=0; inumDirs)) : 0) + buf->f_bfree; buf->f_ffree = buf->f_bfree; /* __kernel_fsid_t f_fsid */ - buf->f_namelen = UDF_NAME_LEN; + buf->f_namelen = UDF_NAME_LEN-2; return 0; } diff -Nru a/fs/udf/truncate.c b/fs/udf/truncate.c --- a/fs/udf/truncate.c Sun Mar 14 14:20:07 2004 +++ b/fs/udf/truncate.c Sun Mar 14 14:20:07 2004 @@ -15,7 +15,7 @@ * ftp://prep.ai.mit.edu/pub/gnu/GPL * Each contributing author retains all rights to their own work. * - * (C) 1999-2001 Ben Fennema + * (C) 1999-2004 Ben Fennema * (C) 1999 Stelias Computing Inc * * HISTORY @@ -64,6 +64,67 @@ udf_free_blocks(inode->i_sb, inode, eloc, first_block, last_block - first_block); } } +} + +void udf_discard_prealloc(struct inode * inode) +{ + lb_addr bloc, eloc; + uint32_t extoffset = 0, elen, nelen; + uint64_t lbcount = 0; + int8_t etype = -1, netype; + struct buffer_head *bh = NULL; + int adsize; + + if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB || + inode->i_size == UDF_I_LENEXTENTS(inode)) + { + return; + } + + if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT) + adsize = sizeof(short_ad); + else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG) + adsize = sizeof(long_ad); + else + adsize = 0; + + bloc = UDF_I_LOCATION(inode); + + while ((netype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1) + { + etype = netype; + lbcount += elen; + if (lbcount > inode->i_size && lbcount - inode->i_size < inode->i_sb->s_blocksize) + { + nelen = elen - (lbcount - inode->i_size); + extent_trunc(inode, bloc, extoffset-adsize, eloc, etype, elen, bh, nelen); + lbcount = inode->i_size; + } + } + if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) + { + extoffset -= adsize; + lbcount -= elen; + extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, 0); + if (!bh) + { + UDF_I_LENALLOC(inode) = extoffset - udf_file_entry_alloc_offset(inode); + mark_inode_dirty(inode); + } + else + { + struct allocExtDesc *aed = (struct allocExtDesc *)(bh->b_data); + aed->lengthAllocDescs = cpu_to_le32(extoffset - sizeof(struct allocExtDesc)); + if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) + udf_update_tag(bh->b_data, extoffset); + else + udf_update_tag(bh->b_data, sizeof(struct allocExtDesc)); + mark_buffer_dirty_inode(bh, inode); + } + } + UDF_I_LENEXTENTS(inode) = lbcount; + + udf_release_data(bh); } void udf_truncate_extents(struct inode * inode) diff -Nru a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h --- a/fs/udf/udf_sb.h Sun Mar 14 14:20:08 2004 +++ b/fs/udf/udf_sb.h Sun Mar 14 14:20:08 2004 @@ -64,13 +64,14 @@ {\ int nr_groups = ((UDF_SB_PARTLEN((X),(Y)) + (sizeof(struct spaceBitmapDesc) << 3) +\ ((X)->s_blocksize * 8) - 1) / ((X)->s_blocksize * 8));\ - UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap = kmalloc(sizeof(struct udf_bitmap) +\ - sizeof(struct buffer_head *) * nr_groups,\ - GFP_KERNEL);\ + int size = sizeof(struct udf_bitmap) + (sizeof(struct buffer_head *) * nr_groups);\ + if (size <= PAGE_SIZE)\ + UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap = kmalloc(size, GFP_KERNEL);\ + else\ + UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap = vmalloc(size);\ if (UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap != NULL)\ {\ - memset(UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap, 0x00,\ - sizeof(struct udf_bitmap) + sizeof(struct buffer_head *) * nr_groups);\ + memset(UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap, 0x00, size);\ UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_block_bitmap =\ (struct buffer_head **)(UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap + 1);\ UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_nr_groups = nr_groups;\ @@ -81,6 +82,21 @@ }\ } +#define UDF_SB_FREE_BITMAP(X,Y,Z)\ +{\ + int i;\ + int nr_groups = UDF_SB_BITMAP_NR_GROUPS(X,Y,Z);\ + int size = sizeof(struct udf_bitmap) + (sizeof(struct buffer_head *) * nr_groups);\ + for (i=0; is_flags & ( 1 << (Y) ) ) #define UDF_SET_FLAG(X,Y) ( UDF_SB(X)->s_flags |= ( 1 << (Y) ) ) @@ -99,7 +115,7 @@ #define UDF_SB_PARTFUNC(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_partition_func ) #define UDF_SB_PARTFLAGS(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_partition_flags ) #define UDF_SB_BITMAP(X,Y,Z,I) ( UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_block_bitmap[I] ) -#define UDF_SB_BITMAP_NR_GROUPS(X,Y,Z) ( UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_nr_groups ) +#define UDF_SB_BITMAP_NR_GROUPS(X,Y,Z) ( UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_nr_groups ) #define UDF_SB_VOLIDENT(X) ( UDF_SB(X)->s_volident ) #define UDF_SB_NUMPARTS(X) ( UDF_SB(X)->s_partitions ) diff -Nru a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h --- a/fs/udf/udfdecl.h Sun Mar 14 14:20:07 2004 +++ b/fs/udf/udfdecl.h Sun Mar 14 14:20:07 2004 @@ -21,7 +21,7 @@ #define UDF_EXTENT_FLAG_MASK 0xC0000000 #define UDF_NAME_PAD 4 -#define UDF_NAME_LEN 255 +#define UDF_NAME_LEN 256 #define UDF_PATH_LEN 1023 #define udf_file_entry_alloc_offset(inode)\ @@ -59,13 +59,6 @@ int eoffset; }; -struct udf_directory_record -{ - uint32_t d_parent; - uint32_t d_inode; - uint32_t d_name[255]; -}; - struct udf_vds_record { uint32_t block; @@ -81,7 +74,7 @@ struct ustr { uint8_t u_cmpID; - uint8_t u_name[UDF_NAME_LEN]; + uint8_t u_name[UDF_NAME_LEN-2]; uint8_t u_len; }; @@ -116,19 +109,16 @@ extern int8_t udf_delete_aext(struct inode *, lb_addr, int, lb_addr, uint32_t, struct buffer_head *); extern int8_t udf_next_aext(struct inode *, lb_addr *, int *, lb_addr *, uint32_t *, struct buffer_head **, int); extern int8_t udf_current_aext(struct inode *, lb_addr *, int *, lb_addr *, uint32_t *, struct buffer_head **, int); -extern void udf_discard_prealloc(struct inode *); /* misc.c */ extern int udf_read_tagged_data(char *, int size, int fd, int block, int partref); extern struct buffer_head *udf_tgetblk(struct super_block *, int); extern struct buffer_head *udf_tread(struct super_block *, int); -extern struct genericFormat *udf_add_extendedattr(struct inode *, uint32_t, uint32_t, uint8_t, struct buffer_head **); -extern struct genericFormat *udf_get_extendedattr(struct inode *, uint32_t, uint8_t, struct buffer_head **); +extern struct genericFormat *udf_add_extendedattr(struct inode *, uint32_t, uint32_t, uint8_t); +extern struct genericFormat *udf_get_extendedattr(struct inode *, uint32_t, uint8_t); extern struct buffer_head *udf_read_tagged(struct super_block *, uint32_t, uint32_t, uint16_t *); extern struct buffer_head *udf_read_ptagged(struct super_block *, lb_addr, uint32_t, uint16_t *); extern void udf_release_data(struct buffer_head *); -extern uint32_t udf64_low32(uint64_t); -extern uint32_t udf64_high32(uint64_t); extern void udf_update_tag(char *, int); extern void udf_new_tag(char *, uint16_t, uint16_t, uint16_t, uint32_t, int); @@ -154,6 +144,7 @@ extern struct inode * udf_new_inode (struct inode *, int, int *); /* truncate.c */ +extern void udf_discard_prealloc(struct inode *); extern void udf_truncate_extents(struct inode *); /* balloc.c */ diff -Nru a/fs/udf/unicode.c b/fs/udf/unicode.c --- a/fs/udf/unicode.c Sun Mar 14 14:20:08 2004 +++ b/fs/udf/unicode.c Sun Mar 14 14:20:08 2004 @@ -36,7 +36,7 @@ static int udf_char_to_ustr(struct ustr *dest, const uint8_t *src, int strlen) { - if ( (!dest) || (!src) || (!strlen) || (strlen >= UDF_NAME_LEN) ) + if ( (!dest) || (!src) || (!strlen) || (strlen > UDF_NAME_LEN-2) ) return 0; memset(dest, 0, sizeof(struct ustr)); memcpy(dest->u_name, src, strlen); @@ -181,14 +181,14 @@ static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length) { unsigned c, i, max_val, utf_char; - int utf_cnt; - int u_len = 0; + int utf_cnt, u_len; memset(ocu, 0, sizeof(dstring) * length); ocu[0] = 8; max_val = 0xffU; try_again: + u_len = 0U; utf_char = 0U; utf_cnt = 0U; for (i = 0U; i < utf->u_len; i++) @@ -264,8 +264,8 @@ if (utf_cnt) { error_out: - printk(KERN_ERR "udf: bad UTF-8 character\n"); - return 0; + ocu[++u_len] = '?'; + printk(KERN_DEBUG "udf: bad UTF-8 character\n"); } ocu[length - 1] = (uint8_t)u_len + 1; @@ -318,21 +318,21 @@ { unsigned len, i, max_val; uint16_t uni_char; - int uni_cnt; - int u_len = 0; + int u_len; memset(ocu, 0, sizeof(dstring) * length); ocu[0] = 8; max_val = 0xffU; try_again: - uni_char = 0U; - uni_cnt = 0U; + u_len = 0U; for (i = 0U; i < uni->u_len; i++) { len = nls->char2uni(&uni->u_name[i], uni->u_len-i, &uni_char); + if (len <= 0) + continue; - if (len == 2 && max_val == 0xff) + if (uni_char > max_val) { max_val = 0xffffU; ocu[0] = (uint8_t)0x10U; @@ -340,11 +340,9 @@ } if (max_val == 0xffffU) - { ocu[++u_len] = (uint8_t)(uni_char >> 8); - i++; - } ocu[++u_len] = (uint8_t)(uni_char & 0xffU); + i += len - 1; } ocu[length - 1] = (uint8_t)u_len + 1; diff -Nru a/fs/ufs/dir.c b/fs/ufs/dir.c --- a/fs/ufs/dir.c Sun Mar 14 14:20:08 2004 +++ b/fs/ufs/dir.c Sun Mar 14 14:20:08 2004 @@ -166,7 +166,6 @@ offset = 0; brelse (bh); } - update_atime(inode); unlock_kernel(); return 0; } diff -Nru a/fs/ufs/inode.c b/fs/ufs/inode.c --- a/fs/ufs/inode.c Sun Mar 14 14:20:06 2004 +++ b/fs/ufs/inode.c Sun Mar 14 14:20:06 2004 @@ -82,7 +82,12 @@ return n; } -int ufs_frag_map(struct inode *inode, int frag) +/* + * Returns the location of the fragment from + * the begining of the filesystem. + */ + +u64 ufs_frag_map(struct inode *inode, int frag) { struct ufs_inode_info *ufsi = UFS_I(inode); struct super_block *sb = inode->i_sb; @@ -93,6 +98,9 @@ int depth = ufs_block_to_path(inode, frag >> uspi->s_fpbshift, offsets); int ret = 0; u32 block; + u64 u2_block = 0; + unsigned flags = UFS_SB(sb)->s_flags; + u64 temp = 0; if (depth == 0) return 0; @@ -100,6 +108,9 @@ p = offsets; lock_kernel(); + if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) + goto ufs2; + block = ufsi->i_u1.i_data[*p++]; if (!block) goto out; @@ -116,6 +127,28 @@ goto out; } ret = uspi->s_sbbase + fs32_to_cpu(sb, block) + (frag & uspi->s_fpbmask); + goto out; +ufs2: + u2_block = ufsi->i_u1.u2_i_data[*p++]; + if (!u2_block) + goto out; + + temp = (u64)uspi->s_sbbase + fs64_to_cpu(sb, u2_block); + + while (--depth) { + struct buffer_head *bh; + u64 n = *p++; + + bh = sb_bread(sb, temp +(n>>shift)); + if (!bh) + goto out; + u2_block = ((u64*)bh->b_data)[n & mask]; + brelse(bh); + if (!u2_block) + goto out; + } + ret = temp + (frag & uspi->s_fpbmask); + out: unlock_kernel(); return ret; @@ -132,12 +165,20 @@ unsigned block, blockoff, lastfrag, lastblock, lastblockoff; unsigned tmp, goal; u32 * p, * p2; + unsigned flags = 0; UFSD(("ENTER, ino %lu, fragment %u, new_fragment %u, required %u\n", inode->i_ino, fragment, new_fragment, required)) sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; + + flags = UFS_SB(sb)->s_flags; + /* TODO : to be done for write support + if ( (flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) + goto ufs2; + */ + block = ufs_fragstoblks (fragment); blockoff = ufs_fragnum (fragment); p = ufsi->i_u1.i_data + block; @@ -230,6 +271,21 @@ mark_inode_dirty(inode); UFSD(("EXIT, result %u\n", tmp + blockoff)) return result; + + /* This part : To be implemented .... + Required only for writing, not required for READ-ONLY. +ufs2: + + u2_block = ufs_fragstoblks(fragment); + u2_blockoff = ufs_fragnum(fragment); + p = ufsi->i_u1.u2_i_data + block; + goal = 0; + +repeat2: + tmp = fs32_to_cpu(sb, *p); + lastfrag = ufsi->i_lastfrag; + + */ } static struct buffer_head * ufs_block_getfrag (struct inode *inode, @@ -308,21 +364,28 @@ return result; } +/* + * This function gets the block which contains the fragment. + */ + static int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create) { struct super_block * sb = inode->i_sb; struct ufs_sb_private_info * uspi = UFS_SB(sb)->s_uspi; struct buffer_head * bh; int ret, err, new; - unsigned long ptr, phys; + unsigned long ptr,phys; + u64 phys64 = 0; if (!create) { - phys = ufs_frag_map(inode, fragment); - if (phys) - map_bh(bh_result, sb, phys); + phys64 = ufs_frag_map(inode, fragment); + if (phys64) + map_bh(bh_result, sb, phys64); return 0; } + /* This code entered only while writing ....? */ + err = -EIO; new = 0; ret = 0; @@ -474,6 +537,7 @@ struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_inode * ufs_inode; + struct ufs2_inode *ufs2_inode; struct buffer_head * bh; mode_t mode; unsigned i; @@ -496,6 +560,9 @@ ufs_warning (sb, "ufs_read_inode", "unable to read inode %lu\n", inode->i_ino); goto bad_inode; } + if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) + goto ufs2_inode; + ufs_inode = (struct ufs_inode *) (bh->b_data + sizeof(struct ufs_inode) * ufs_inotofsbo(inode->i_ino)); /* @@ -563,6 +630,78 @@ bad_inode: make_bad_inode(inode); + return; + +ufs2_inode : + UFSD(("Reading ufs2 inode, ino %lu\n", inode->i_ino)) + + ufs2_inode = (struct ufs2_inode *)(bh->b_data + sizeof(struct ufs2_inode) * ufs_inotofsbo(inode->i_ino)); + + /* + * Copy data to the in-core inode. + */ + inode->i_mode = mode = fs16_to_cpu(sb, ufs2_inode->ui_mode); + inode->i_nlink = fs16_to_cpu(sb, ufs2_inode->ui_nlink); + if (inode->i_nlink == 0) + ufs_error (sb, "ufs_read_inode", "inode %lu has zero nlink\n", inode->i_ino); + + /* + * Linux now has 32-bit uid and gid, so we can support EFT. + */ + inode->i_uid = fs32_to_cpu(sb, ufs2_inode->ui_uid); + inode->i_gid = fs32_to_cpu(sb, ufs2_inode->ui_gid); + + inode->i_size = fs64_to_cpu(sb, ufs2_inode->ui_size); + inode->i_atime.tv_sec = fs32_to_cpu(sb, ufs2_inode->ui_atime.tv_sec); + inode->i_ctime.tv_sec = fs32_to_cpu(sb, ufs2_inode->ui_ctime.tv_sec); + inode->i_mtime.tv_sec = fs32_to_cpu(sb, ufs2_inode->ui_mtime.tv_sec); + inode->i_mtime.tv_nsec = 0; + inode->i_atime.tv_nsec = 0; + inode->i_ctime.tv_nsec = 0; + inode->i_blocks = fs64_to_cpu(sb, ufs2_inode->ui_blocks); + inode->i_blksize = PAGE_SIZE; /*This is the optimal IO size(for stat)*/ + + inode->i_version++; + ufsi->i_flags = fs32_to_cpu(sb, ufs2_inode->ui_flags); + ufsi->i_gen = fs32_to_cpu(sb, ufs2_inode->ui_gen); + /* + ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow); + ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag); + */ + ufsi->i_lastfrag= (inode->i_size + uspi->s_fsize- 1) >> uspi->s_fshift; + + if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) { + for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++) + ufsi->i_u1.u2_i_data[i] = + ufs2_inode->ui_u2.ui_addr.ui_db[i]; + } + else { + for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++) + ufsi->i_u1.i_symlink[i] = ufs2_inode->ui_u2.ui_symlink[i]; + } + ufsi->i_osync = 0; + + if (S_ISREG(inode->i_mode)) { + inode->i_op = &ufs_file_inode_operations; + inode->i_fop = &ufs_file_operations; + inode->i_mapping->a_ops = &ufs_aops; + } else if (S_ISDIR(inode->i_mode)) { + inode->i_op = &ufs_dir_inode_operations; + inode->i_fop = &ufs_dir_operations; + } else if (S_ISLNK(inode->i_mode)) { + if (!inode->i_blocks) + inode->i_op = &ufs_fast_symlink_inode_operations; + else { + inode->i_op = &page_symlink_inode_operations; + inode->i_mapping->a_ops = &ufs_aops; + } + } else /* TODO : here ...*/ + init_special_inode(inode, inode->i_mode, + old_decode_dev(fs32_to_cpu(sb, ufsi->i_u1.i_data[0]))); + + brelse(bh); + + UFSD(("EXIT\n")) return; } diff -Nru a/fs/ufs/namei.c b/fs/ufs/namei.c --- a/fs/ufs/namei.c Sun Mar 14 14:20:08 2004 +++ b/fs/ufs/namei.c Sun Mar 14 14:20:08 2004 @@ -31,7 +31,10 @@ #include #include "swab.h" /* will go away - see comment in mknod() */ +/* #undef UFS_NAMEI_DEBUG +*/ +#define UFS_NAMEI_DEBUG #ifdef UFS_NAMEI_DEBUG #define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x; diff -Nru a/fs/ufs/super.c b/fs/ufs/super.c --- a/fs/ufs/super.c Sun Mar 14 14:20:05 2004 +++ b/fs/ufs/super.c Sun Mar 14 14:20:05 2004 @@ -58,6 +58,9 @@ * HP/UX hfs filesystem support added by * Martin K. Petersen , August 1999 * + * UFS2 (of FreeBSD 5.x) support added by + * Niraj Kumar , Jan 2004 + * */ @@ -142,6 +145,28 @@ printk("\n"); } +/* + * Print contents of ufs2 ufs_super_block, useful for debugging + */ +void ufs2_print_super_stuff( + struct super_block *sb, + struct ufs_super_block *usb) +{ + printk("ufs_print_super_stuff\n"); + printk("size of usb: %u\n", sizeof(struct ufs_super_block)); + printk(" magic: 0x%x\n", fs32_to_cpu(sb, usb->fs_magic)); + printk(" fs_size: %u\n",fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_size)); + printk(" fs_dsize: %u\n",fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_dsize)); + printk(" fs_volname: %s\n", usb->fs_u11.fs_u2.fs_volname); + printk(" fs_fsmnt: %s\n", usb->fs_u11.fs_u2.fs_fsmnt); + printk(" fs_sblockloc: %u\n",fs64_to_cpu(sb, + usb->fs_u11.fs_u2.fs_sblockloc)); + printk(" cs_ndir(No of dirs): %u\n",fs64_to_cpu(sb, + usb->fs_u11.fs_u2.fs_cstotal.cs_ndir)); + printk(" cs_nbfree(No of free blocks): %u\n",fs64_to_cpu(sb, + usb->fs_u11.fs_u2.fs_cstotal.cs_nbfree)); + printk("\n"); +} /* * Print contents of ufs_cylinder_group, useful for debugging @@ -253,7 +278,7 @@ enum { Opt_type_old, Opt_type_sunx86, Opt_type_sun, Opt_type_44bsd, - Opt_type_hp, Opt_type_nextstepcd, Opt_type_nextstep, + Opt_type_ufs2, Opt_type_hp, Opt_type_nextstepcd, Opt_type_nextstep, Opt_type_openstep, Opt_onerror_panic, Opt_onerror_lock, Opt_onerror_umount, Opt_onerror_repair, Opt_err }; @@ -263,6 +288,8 @@ {Opt_type_sunx86, "ufstype=sunx86"}, {Opt_type_sun, "ufstype=sun"}, {Opt_type_44bsd, "ufstype=44bsd"}, + {Opt_type_ufs2, "ufstype=ufs2"}, + {Opt_type_ufs2, "ufstype=5xbsd"}, {Opt_type_hp, "ufstype=hp"}, {Opt_type_nextstepcd, "ufstype=nextstep-cd"}, {Opt_type_nextstep, "ufstype=nextstep"}, @@ -307,6 +334,10 @@ ufs_clear_opt (*mount_options, UFSTYPE); ufs_set_opt (*mount_options, UFSTYPE_44BSD); break; + case Opt_type_ufs2: + ufs_clear_opt(*mount_options, UFSTYPE); + ufs_set_opt(*mount_options, UFSTYPE_UFS2); + break; case Opt_type_hp: ufs_clear_opt (*mount_options, UFSTYPE); ufs_set_opt (*mount_options, UFSTYPE_HP); @@ -356,13 +387,20 @@ int ufs_read_cylinder_structures (struct super_block * sb) { struct ufs_sb_info * sbi = UFS_SB(sb); struct ufs_sb_private_info * uspi; + struct ufs_super_block *usb; struct ufs_buffer_head * ubh; unsigned char * base, * space; unsigned size, blks, i; + unsigned flags = 0; UFSD(("ENTER\n")) uspi = sbi->s_uspi; + + usb = (struct ufs_super_block *) + ((struct ufs_buffer_head *)uspi)->bh[0]->b_data; + + flags = UFS_SB(sb)->s_flags; /* * Read cs structures from (usually) first data block @@ -377,11 +415,22 @@ size = uspi->s_bsize; if (i + uspi->s_fpb > blks) size = (blks - i) * uspi->s_fsize; - ubh = ubh_bread(sb, uspi->s_csaddr + i, size); - if (!ubh) - goto failed; - ubh_ubhcpymem (space, ubh, size); - sbi->s_csp[ufs_fragstoblks(i)] = (struct ufs_csum *)space; + + if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) { + ubh = ubh_bread(sb, + fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_csaddr) + i, size); + if (!ubh) + goto failed; + ubh_ubhcpymem (space, ubh, size); + sbi->s_csp[ufs_fragstoblks(i)]=(struct ufs_csum *)space; + } + else { + ubh = ubh_bread(sb, uspi->s_csaddr + i, size); + if (!ubh) + goto failed; + ubh_ubhcpymem(space, ubh, size); + sbi->s_csp[ufs_fragstoblks(i)]=(struct ufs_csum *)space; + } space += size; ubh_brelse (ubh); ubh = NULL; @@ -480,6 +529,7 @@ struct ufs_super_block_first * usb1; struct ufs_super_block_second * usb2; struct ufs_super_block_third * usb3; + struct ufs_super_block *usb; struct ufs_buffer_head * ubh; struct inode *inode; unsigned block_size, super_block_size; @@ -520,7 +570,7 @@ if (!silent) printk("You didn't specify the type of your ufs filesystem\n\n" "mount -t ufs -o ufstype=" - "sun|sunx86|44bsd|old|hp|nextstep|netxstep-cd|openstep ...\n\n" + "sun|sunx86|44bsd|ufs2|5xbsd|old|hp|nextstep|netxstep-cd|openstep ...\n\n" ">>>WARNING<<< Wrong ufstype may corrupt your filesystem, " "default is ufstype=old\n"); ufs_set_opt (sbi->s_mount_opt, UFSTYPE_OLD); @@ -545,6 +595,19 @@ uspi->s_sbbase = 0; flags |= UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD; break; + case UFS_MOUNT_UFSTYPE_UFS2: + UFSD(("ufstype=ufs2\n")) + uspi->s_fsize = block_size = 512; + uspi->s_fmask = ~(512 - 1); + uspi->s_fshift = 9; + uspi->s_sbsize = super_block_size = 1536; + uspi->s_sbbase = 0; + flags |= UFS_TYPE_UFS2 | UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD; + if (!(sb->s_flags & MS_RDONLY)) { + printk(KERN_INFO "ufstype=ufs2 is supported read-only\n"); + sb->s_flags |= MS_RDONLY; + } + break; case UFS_MOUNT_UFSTYPE_SUN: UFSD(("ufstype=sun\n")) @@ -657,27 +720,37 @@ /* * read ufs super block from device */ - ubh = ubh_bread_uspi (uspi, sb, uspi->s_sbbase + UFS_SBLOCK/block_size, super_block_size); + if ( (flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) { + ubh = ubh_bread_uspi(uspi, sb, uspi->s_sbbase + SBLOCK_UFS2/block_size, super_block_size); + } + else { + ubh = ubh_bread_uspi(uspi, sb, uspi->s_sbbase + UFS_SBLOCK/block_size, super_block_size); + } if (!ubh) - goto failed; + goto failed; + usb1 = ubh_get_usb_first(USPI_UBH); usb2 = ubh_get_usb_second(USPI_UBH); usb3 = ubh_get_usb_third(USPI_UBH); + usb = (struct ufs_super_block *) + ((struct ufs_buffer_head *)uspi)->bh[0]->b_data ; /* * Check ufs magic number */ - switch (__constant_le32_to_cpu(usb3->fs_magic)) { + switch ((uspi->fs_magic = __constant_le32_to_cpu(usb3->fs_magic))) { case UFS_MAGIC: + case UFS2_MAGIC: case UFS_MAGIC_LFN: case UFS_MAGIC_FEA: case UFS_MAGIC_4GB: sbi->s_bytesex = BYTESEX_LE; goto magic_found; } - switch (__constant_be32_to_cpu(usb3->fs_magic)) { + switch ((uspi->fs_magic = __constant_be32_to_cpu(usb3->fs_magic))) { case UFS_MAGIC: + case UFS2_MAGIC: case UFS_MAGIC_LFN: case UFS_MAGIC_FEA: case UFS_MAGIC_4GB: @@ -748,7 +821,10 @@ } #ifdef UFS_SUPER_DEBUG_MORE - ufs_print_super_stuff(sb, usb1, usb2, usb3); + if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) + ufs2_print_super_stuff(sb,usb); + else + ufs_print_super_stuff(sb, usb1, usb2, usb3); #endif /* @@ -802,8 +878,16 @@ uspi->s_dblkno = fs32_to_cpu(sb, usb1->fs_dblkno); uspi->s_cgoffset = fs32_to_cpu(sb, usb1->fs_cgoffset); uspi->s_cgmask = fs32_to_cpu(sb, usb1->fs_cgmask); - uspi->s_size = fs32_to_cpu(sb, usb1->fs_size); - uspi->s_dsize = fs32_to_cpu(sb, usb1->fs_dsize); + + if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) { + uspi->s_u2_size = fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_size); + uspi->s_u2_dsize = fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_dsize); + } + else { + uspi->s_size = fs32_to_cpu(sb, usb1->fs_size); + uspi->s_dsize = fs32_to_cpu(sb, usb1->fs_dsize); + } + uspi->s_ncg = fs32_to_cpu(sb, usb1->fs_ncg); /* s_bsize already set */ /* s_fsize already set */ @@ -1021,21 +1105,36 @@ { struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; + struct ufs_super_block * usb; + unsigned flags = 0; lock_kernel(); uspi = UFS_SB(sb)->s_uspi; usb1 = ubh_get_usb_first (USPI_UBH); + usb = (struct ufs_super_block *) + ((struct ufs_buffer_head *)uspi)->bh[0]->b_data ; - buf->f_type = UFS_MAGIC; + flags = UFS_SB(sb)->s_flags; + if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) { + buf->f_type = UFS2_MAGIC; + buf->f_blocks = usb->fs_u11.fs_u2.fs_dsize; + buf->f_bfree = ufs_blkstofrags(fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_cstotal.cs_nbfree)) + + fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_cstotal.cs_nffree); + buf->f_ffree = fs64_to_cpu(sb, + usb->fs_u11.fs_u2.fs_cstotal.cs_nifree); + } + else { + buf->f_type = UFS_MAGIC; + buf->f_blocks = uspi->s_dsize; + buf->f_bfree = ufs_blkstofrags(fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree)) + + fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree); + buf->f_ffree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree); + } buf->f_bsize = sb->s_blocksize; - buf->f_blocks = uspi->s_dsize; - buf->f_bfree = ufs_blkstofrags(fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree)) + - fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree); buf->f_bavail = (buf->f_bfree > (((long)buf->f_blocks / 100) * uspi->s_minfree)) ? (buf->f_bfree - (((long)buf->f_blocks / 100) * uspi->s_minfree)) : 0; buf->f_files = uspi->s_ncg * uspi->s_ipg; - buf->f_ffree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree); buf->f_namelen = UFS_MAXNAMLEN; unlock_kernel(); diff -Nru a/fs/ufs/util.c b/fs/ufs/util.c --- a/fs/ufs/util.c Sun Mar 14 14:20:07 2004 +++ b/fs/ufs/util.c Sun Mar 14 14:20:07 2004 @@ -24,10 +24,11 @@ struct ufs_buffer_head * _ubh_bread_ (struct ufs_sb_private_info * uspi, - struct super_block *sb, unsigned fragment, unsigned size) + struct super_block *sb, u64 fragment, u64 size) { struct ufs_buffer_head * ubh; - unsigned i, j, count; + unsigned i, j ; + u64 count = 0; if (size & ~uspi->s_fmask) return NULL; count = size >> uspi->s_fshift; @@ -53,9 +54,10 @@ } struct ufs_buffer_head * ubh_bread_uspi (struct ufs_sb_private_info * uspi, - struct super_block *sb, unsigned fragment, unsigned size) + struct super_block *sb, u64 fragment, u64 size) { - unsigned i, j, count; + unsigned i, j; + u64 count = 0; if (size & ~uspi->s_fmask) return NULL; count = size >> uspi->s_fshift; diff -Nru a/fs/ufs/util.h b/fs/ufs/util.h --- a/fs/ufs/util.h Sun Mar 14 14:20:07 2004 +++ b/fs/ufs/util.h Sun Mar 14 14:20:07 2004 @@ -228,8 +228,8 @@ * These functions manipulate ufs buffers */ #define ubh_bread(sb,fragment,size) _ubh_bread_(uspi,sb,fragment,size) -extern struct ufs_buffer_head * _ubh_bread_(struct ufs_sb_private_info *, struct super_block *, unsigned, unsigned); -extern struct ufs_buffer_head * ubh_bread_uspi(struct ufs_sb_private_info *, struct super_block *, unsigned, unsigned); +extern struct ufs_buffer_head * _ubh_bread_(struct ufs_sb_private_info *, struct super_block *, u64 , u64); +extern struct ufs_buffer_head * ubh_bread_uspi(struct ufs_sb_private_info *, struct super_block *, u64, u64); extern void ubh_brelse (struct ufs_buffer_head *); extern void ubh_brelse_uspi (struct ufs_sb_private_info *); extern void ubh_mark_buffer_dirty (struct ufs_buffer_head *); diff -Nru a/include/acpi/acconfig.h b/include/acpi/acconfig.h --- a/include/acpi/acconfig.h Sun Mar 14 14:20:08 2004 +++ b/include/acpi/acconfig.h Sun Mar 14 14:20:08 2004 @@ -64,7 +64,7 @@ /* Version string */ -#define ACPI_CA_VERSION 0x20040220 +#define ACPI_CA_VERSION 0x20040311 /* Maximum objects in the various object caches */ @@ -184,6 +184,10 @@ /* SMBus bidirectional buffer size */ #define ACPI_SMBUS_BUFFER_SIZE 34 + +/* Number of strings associated with the _OSI reserved method */ + +#define ACPI_NUM_OSI_STRINGS 4 /****************************************************************************** diff -Nru a/include/acpi/acglobal.h b/include/acpi/acglobal.h --- a/include/acpi/acglobal.h Sun Mar 14 14:20:05 2004 +++ b/include/acpi/acglobal.h Sun Mar 14 14:20:05 2004 @@ -79,6 +79,14 @@ extern u32 acpi_gbl_nesting_level; +/***************************************************************************** + * + * Runtime configuration + * + ****************************************************************************/ + +ACPI_EXTERN u8 acpi_gbl_create_osi_method; +ACPI_EXTERN u8 acpi_gbl_all_methods_serialized; /***************************************************************************** * @@ -169,6 +177,7 @@ extern const char *acpi_gbl_highest_dstate_names[4]; extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES]; extern const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS]; +extern const char *acpi_gbl_valid_osi_strings[ACPI_NUM_OSI_STRINGS]; /***************************************************************************** @@ -179,7 +188,7 @@ #define NUM_NS_TYPES ACPI_TYPE_INVALID+1 -#if defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY) +#if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY) #define NUM_PREDEFINED_NAMES 10 #else #define NUM_PREDEFINED_NAMES 9 diff -Nru a/include/acpi/acmacros.h b/include/acpi/acmacros.h --- a/include/acpi/acmacros.h Sun Mar 14 14:20:07 2004 +++ b/include/acpi/acmacros.h Sun Mar 14 14:20:07 2004 @@ -681,7 +681,4 @@ #endif /* ACPI_DBG_TRACK_ALLOCATIONS */ - -#define ACPI_GET_STACK_POINTER _asm {mov eax, ebx} - #endif /* ACMACROS_H */ diff -Nru a/include/acpi/acobject.h b/include/acpi/acobject.h --- a/include/acpi/acobject.h Sun Mar 14 14:20:06 2004 +++ b/include/acpi/acobject.h Sun Mar 14 14:20:06 2004 @@ -180,7 +180,11 @@ }; -#define INFINITE_CONCURRENCY 0xFF +#define ACPI_INFINITE_CONCURRENCY 0xFF + +typedef +acpi_status (*ACPI_INTERNAL_METHOD) ( + struct acpi_walk_state *walk_state); struct acpi_object_method { @@ -190,6 +194,7 @@ u32 aml_length; void *semaphore; u8 *aml_start; + ACPI_INTERNAL_METHOD implementation; u8 concurrency; u8 thread_count; acpi_owner_id owning_id; diff -Nru a/include/acpi/acpixf.h b/include/acpi/acpixf.h --- a/include/acpi/acpixf.h Sun Mar 14 14:20:05 2004 +++ b/include/acpi/acpixf.h Sun Mar 14 14:20:05 2004 @@ -450,7 +450,7 @@ acpi_enter_sleep_state ( u8 sleep_state); -acpi_status +acpi_status asmlinkage acpi_enter_sleep_state_s4bios ( void); diff -Nru a/include/acpi/actypes.h b/include/acpi/actypes.h --- a/include/acpi/actypes.h Sun Mar 14 14:20:07 2004 +++ b/include/acpi/actypes.h Sun Mar 14 14:20:07 2004 @@ -349,7 +349,6 @@ /* * Power state values */ - #define ACPI_STATE_UNKNOWN (u8) 0xFF #define ACPI_STATE_S0 (u8) 0 @@ -393,7 +392,6 @@ #define ACPI_NOTIFY_BUS_MODE_MISMATCH (u8) 6 #define ACPI_NOTIFY_POWER_FAULT (u8) 7 - /* * Table types. These values are passed to the table related APIs */ @@ -409,7 +407,6 @@ #define ACPI_TABLE_MAX 6 #define NUM_ACPI_TABLE_TYPES (ACPI_TABLE_MAX+1) - /* * Types associated with ACPI names and objects. The first group of * values (up to ACPI_TYPE_EXTERNAL_MAX) correspond to the definition @@ -794,7 +791,7 @@ #define ACPI_INIT_DEVICE_INI 1 -/* Address Spaces (Operation Regions */ +/* Address Spaces (For Operation Regions) */ typedef acpi_status (*acpi_adr_space_handler) ( diff -Nru a/include/acpi/acutils.h b/include/acpi/acutils.h --- a/include/acpi/acutils.h Sun Mar 14 14:20:05 2004 +++ b/include/acpi/acutils.h Sun Mar 14 14:20:05 2004 @@ -52,7 +52,6 @@ union acpi_generic_state *state, void *context); - acpi_status acpi_ut_walk_package_tree ( union acpi_operand_object *source_object, @@ -60,7 +59,6 @@ acpi_pkg_callback walk_callback, void *context); - struct acpi_pkg_info { u8 *free_space; @@ -474,6 +472,10 @@ #define METHOD_NAME__CRS "_CRS" #define METHOD_NAME__PRS "_PRS" + +acpi_status +acpi_ut_osi_implementation ( + struct acpi_walk_state *walk_state); acpi_status acpi_ut_evaluate_object ( diff -Nru a/include/acpi/amlcode.h b/include/acpi/amlcode.h --- a/include/acpi/amlcode.h Sun Mar 14 14:20:07 2004 +++ b/include/acpi/amlcode.h Sun Mar 14 14:20:07 2004 @@ -496,11 +496,17 @@ } AML_ACCESS_ATTRIBUTE; -/* bit fields in method_flags byte */ +/* Bit fields in method_flags byte */ -#define METHOD_FLAGS_ARG_COUNT 0x07 -#define METHOD_FLAGS_SERIALIZED 0x08 -#define METHOD_FLAGS_SYNCH_LEVEL 0xF0 +#define AML_METHOD_ARG_COUNT 0x07 +#define AML_METHOD_SERIALIZED 0x08 +#define AML_METHOD_SYNCH_LEVEL 0xF0 + +/* METHOD_FLAGS_ARG_COUNT is not used internally, define additional flags */ + +#define AML_METHOD_INTERNAL_ONLY 0x01 +#define AML_METHOD_RESERVED1 0x02 +#define AML_METHOD_RESERVED2 0x04 #endif /* __AMLCODE_H__ */ diff -Nru a/include/asm-alpha/pci.h b/include/asm-alpha/pci.h --- a/include/asm-alpha/pci.h Sun Mar 14 14:20:05 2004 +++ b/include/asm-alpha/pci.h Sun Mar 14 14:20:05 2004 @@ -88,7 +88,7 @@ /* Map a single buffer of the indicate size for PCI DMA in streaming mode. The 32-bit PCI bus mastering address to use is returned. Once the device is given the dma address, the device owns this memory - until either pci_unmap_single or pci_dma_sync_single is performed. */ + until either pci_unmap_single or pci_dma_sync_single_for_cpu is performed. */ extern dma_addr_t pci_map_single(struct pci_dev *, void *, size_t, int); @@ -142,28 +142,44 @@ extern void pci_unmap_sg(struct pci_dev *, struct scatterlist *, int, int); /* Make physical memory consistent for a single streaming mode DMA - translation after a transfer. + translation after a transfer and device currently has ownership + of the buffer. If you perform a pci_map_single() but wish to interrogate the buffer using the cpu, yet do not wish to teardown the PCI dma mapping, you must call this function before doing so. At the next - point you give the PCI dma address back to the card, the device - again owns the buffer. */ + point you give the PCI dma address back to the card, you must first + perform a pci_dma_sync_for_device, and then the device again owns + the buffer. */ static inline void -pci_dma_sync_single(struct pci_dev *dev, dma_addr_t dma_addr, long size, - int direction) +pci_dma_sync_single_for_cpu(struct pci_dev *dev, dma_addr_t dma_addr, long size, + int direction) +{ + /* Nothing to do. */ +} + +static inline void +pci_dma_sync_single_for_device(struct pci_dev *dev, dma_addr_t dma_addr, long size, + int direction) { /* Nothing to do. */ } /* Make physical memory consistent for a set of streaming mode DMA - translations after a transfer. The same as pci_dma_sync_single but - for a scatter-gather list, same rules and usage. */ + translations after a transfer. The same as pci_dma_sync_single_* + but for a scatter-gather list, same rules and usage. */ static inline void -pci_dma_sync_sg(struct pci_dev *dev, struct scatterlist *sg, int nents, - int direction) +pci_dma_sync_sg_for_cpu(struct pci_dev *dev, struct scatterlist *sg, int nents, + int direction) +{ + /* Nothing to do. */ +} + +static inline void +pci_dma_sync_sg_for_device(struct pci_dev *dev, struct scatterlist *sg, int nents, + int direction) { /* Nothing to do. */ } @@ -184,8 +200,14 @@ extern struct page *pci_dac_dma_to_page(struct pci_dev *, dma64_addr_t); extern unsigned long pci_dac_dma_to_offset(struct pci_dev *, dma64_addr_t); -static __inline__ void -pci_dac_dma_sync_single(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction) +static inline void +pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction) +{ + /* Nothing to do. */ +} + +static inline void +pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction) { /* Nothing to do. */ } diff -Nru a/include/asm-arm/dma-mapping.h b/include/asm-arm/dma-mapping.h --- a/include/asm-arm/dma-mapping.h Sun Mar 14 14:20:06 2004 +++ b/include/asm-arm/dma-mapping.h Sun Mar 14 14:20:06 2004 @@ -26,8 +26,10 @@ void sa1111_unmap_single(struct device *dev, dma_addr_t, size_t, enum dma_data_direction); int sa1111_map_sg(struct device *dev, struct scatterlist *, int, enum dma_data_direction); void sa1111_unmap_sg(struct device *dev, struct scatterlist *, int, enum dma_data_direction); -void sa1111_dma_sync_single(struct device *dev, dma_addr_t, size_t, enum dma_data_direction); -void sa1111_dma_sync_sg(struct device *dev, struct scatterlist *, int, enum dma_data_direction); +void sa1111_dma_sync_single_for_cpu(struct device *dev, dma_addr_t, size_t, enum dma_data_direction); +void sa1111_dma_sync_single_for_device(struct device *dev, dma_addr_t, size_t, enum dma_data_direction); +void sa1111_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *, int, enum dma_data_direction); +void sa1111_dma_sync_sg_for_device(struct device *dev, struct scatterlist *, int, enum dma_data_direction); #ifdef CONFIG_SA1111 @@ -115,7 +117,8 @@ * or written back. * * The device owns this memory once this call has completed. The CPU - * can regain ownership by calling dma_unmap_single() or dma_sync_single(). + * can regain ownership by calling dma_unmap_single() or + * dma_sync_single_for_cpu(). */ static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, size_t size, @@ -140,7 +143,8 @@ * or written back. * * The device owns this memory once this call has completed. The CPU - * can regain ownership by calling dma_unmap_page() or dma_sync_single(). + * can regain ownership by calling dma_unmap_page() or + * dma_sync_single_for_cpu(). */ static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, @@ -204,7 +208,7 @@ * * Map a set of buffers described by scatterlist in streaming * mode for DMA. This is the scatter-gather version of the - * above pci_map_single interface. Here the scatter gather list + * above dma_map_single interface. Here the scatter gather list * elements are each tagged with the appropriate dma address * and length. They are obtained via sg_dma_{address,length}(SG). * @@ -214,7 +218,7 @@ * The routine returns the number of addr/length pairs actually * used, at most nents. * - * Device ownership issues as mentioned above for pci_map_single are + * Device ownership issues as mentioned above for dma_map_single are * the same here. */ static inline int @@ -246,7 +250,7 @@ * * Unmap a set of streaming mode DMA translations. * Again, CPU read rules concerning calls here are the same as for - * pci_unmap_single() above. + * dma_unmap_single() above. */ static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, @@ -261,7 +265,7 @@ } /** - * dma_sync_single + * dma_sync_single_for_cpu * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices * @handle: DMA address of buffer * @size: size of buffer to map @@ -270,18 +274,31 @@ * Make physical memory consistent for a single streaming mode DMA * translation after a transfer. * - * If you perform a pci_map_single() but wish to interrogate the + * If you perform a dma_map_single() but wish to interrogate the * buffer using the cpu, yet do not wish to teardown the PCI dma * mapping, you must call this function before doing so. At the - * next point you give the PCI dma address back to the card, the + * next point you give the PCI dma address back to the card, you + * must first the perform a dma_sync_for_device, and then the * device again owns the buffer. */ static inline void -dma_sync_single(struct device *dev, dma_addr_t handle, size_t size, - enum dma_data_direction dir) +dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle, size_t size, + enum dma_data_direction dir) { if (dmadev_is_sa1111(dev)) { - sa1111_dma_sync_single(dev, handle, size, dir); + sa1111_dma_sync_single_for_cpu(dev, handle, size, dir); + return; + } + + consistent_sync((void *)__bus_to_virt(handle), size, dir); +} + +static inline void +dma_sync_single_for_device(struct device *dev, dma_addr_t handle, size_t size, + enum dma_data_direction dir) +{ + if (dmadev_is_sa1111(dev)) { + sa1111_dma_sync_single_for_device(dev, handle, size, dir); return; } @@ -289,7 +306,7 @@ } /** - * dma_sync_sg + * dma_sync_sg_for_cpu * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices * @sg: list of buffers * @nents: number of buffers to map @@ -298,17 +315,34 @@ * Make physical memory consistent for a set of streaming * mode DMA translations after a transfer. * - * The same as pci_dma_sync_single but for a scatter-gather list, + * The same as dma_sync_single_for_* but for a scatter-gather list, * same rules and usage. */ static inline void -dma_sync_sg(struct device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction dir) +dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction dir) +{ + int i; + + if (dmadev_is_sa1111(dev)) { + sa1111_dma_sync_sg_for_cpu(dev, sg, nents, dir); + return; + } + + for (i = 0; i < nents; i++, sg++) { + char *virt = page_address(sg->page) + sg->offset; + consistent_sync(virt, sg->length, dir); + } +} + +static inline void +dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction dir) { int i; if (dmadev_is_sa1111(dev)) { - sa1111_dma_sync_sg(dev, sg, nents, dir); + sa1111_dma_sync_sg_for_device(dev, sg, nents, dir); return; } diff -Nru a/include/asm-generic/dma-mapping.h b/include/asm-generic/dma-mapping.h --- a/include/asm-generic/dma-mapping.h Sun Mar 14 14:20:08 2004 +++ b/include/asm-generic/dma-mapping.h Sun Mar 14 14:20:08 2004 @@ -103,21 +103,41 @@ } static inline void -dma_sync_single(struct device *dev, dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction) +dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) { BUG_ON(dev->bus != &pci_bus_type); - pci_dma_sync_single(to_pci_dev(dev), dma_handle, size, (int)direction); + pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle, + size, (int)direction); } static inline void -dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems, - enum dma_data_direction direction) +dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) { BUG_ON(dev->bus != &pci_bus_type); - pci_dma_sync_sg(to_pci_dev(dev), sg, nelems, (int)direction); + pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle, + size, (int)direction); +} + +static inline void +dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg, nelems, (int)direction); +} + +static inline void +dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ + BUG_ON(dev->bus != &pci_bus_type); + + pci_dma_sync_sg_for_device(to_pci_dev(dev), sg, nelems, (int)direction); } /* Now for the API extensions over the pci_ one */ @@ -135,12 +155,21 @@ } static inline void -dma_sync_single_range(struct device *dev, dma_addr_t dma_handle, - unsigned long offset, size_t size, - enum dma_data_direction direction) +dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + /* just sync everything, that's all the pci API can do */ + dma_sync_single_for_cpu(dev, dma_handle, offset+size, direction); +} + +static inline void +dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, + enum dma_data_direction direction) { /* just sync everything, that's all the pci API can do */ - dma_sync_single(dev, dma_handle, offset+size, direction); + dma_sync_single_for_device(dev, dma_handle, offset+size, direction); } static inline void diff -Nru a/include/asm-generic/pci-dma-compat.h b/include/asm-generic/pci-dma-compat.h --- a/include/asm-generic/pci-dma-compat.h Sun Mar 14 14:20:06 2004 +++ b/include/asm-generic/pci-dma-compat.h Sun Mar 14 14:20:06 2004 @@ -71,17 +71,31 @@ } static inline void -pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, +pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction) { - dma_sync_single(hwdev == NULL ? NULL : &hwdev->dev, dma_handle, size, (enum dma_data_direction)direction); + dma_sync_single_for_cpu(hwdev == NULL ? NULL : &hwdev->dev, dma_handle, size, (enum dma_data_direction)direction); } static inline void -pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, +pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle, + size_t size, int direction) +{ + dma_sync_single_for_device(hwdev == NULL ? NULL : &hwdev->dev, dma_handle, size, (enum dma_data_direction)direction); +} + +static inline void +pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, + int nelems, int direction) +{ + dma_sync_sg_for_cpu(hwdev == NULL ? NULL : &hwdev->dev, sg, nelems, (enum dma_data_direction)direction); +} + +static inline void +pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) { - dma_sync_sg(hwdev == NULL ? NULL : &hwdev->dev, sg, nelems, (enum dma_data_direction)direction); + dma_sync_sg_for_device(hwdev == NULL ? NULL : &hwdev->dev, sg, nelems, (enum dma_data_direction)direction); } #endif diff -Nru a/include/asm-h8300/unistd.h b/include/asm-h8300/unistd.h --- a/include/asm-h8300/unistd.h Sun Mar 14 14:20:07 2004 +++ b/include/asm-h8300/unistd.h Sun Mar 14 14:20:07 2004 @@ -490,7 +490,6 @@ int dummy, ...); asmlinkage int sys_pipe(unsigned long *fildes); asmlinkage int sys_ptrace(long request, long pid, long addr, long data); -asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on); struct sigaction; asmlinkage long sys_rt_sigaction(int sig, const struct sigaction __user *act, diff -Nru a/include/asm-i386/acpi.h b/include/asm-i386/acpi.h --- a/include/asm-i386/acpi.h Sun Mar 14 14:20:08 2004 +++ b/include/asm-i386/acpi.h Sun Mar 14 14:20:08 2004 @@ -28,6 +28,8 @@ #ifdef __KERNEL__ +#include /* defines cmpxchg */ + #define COMPILER_DEPENDENT_INT64 long long #define COMPILER_DEPENDENT_UINT64 unsigned long long @@ -61,33 +63,36 @@ * Immediate values in the assembly are preceded by "$" as in "$0x1" * The final asm parameter are the operation altered non-output registers. */ + +static inline int +__acpi_acquire_global_lock (unsigned int *lock) +{ + unsigned int old, new, val; + do { + old = *lock; + new = (((old & ~0x3) + 2) + ((old >> 1) & 0x1)); + val = cmpxchg(lock, old, new); + } while (unlikely (val != old)); + return (new < 3) ? -1 : 0; +} + +static inline int +__acpi_release_global_lock (unsigned int *lock) +{ + unsigned int old, new, val; + do { + old = *lock; + new = old & ~0x3; + val = cmpxchg(lock, old, new); + } while (unlikely (val != old)); + return old & 0x1; +} + #define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \ - do { \ - int dummy; \ - asm("1: movl (%1),%%eax;" \ - "movl %%eax,%%edx;" \ - "andl %2,%%edx;" \ - "btsl $0x1,%%edx;" \ - "adcl $0x0,%%edx;" \ - "lock; cmpxchgl %%edx,(%1);" \ - "jnz 1b;" \ - "cmpb $0x3,%%dl;" \ - "sbbl %%eax,%%eax" \ - :"=a"(Acq),"=c"(dummy):"c"(GLptr),"i"(~1L):"dx"); \ - } while(0) + ((Acq) = __acpi_acquire_global_lock((unsigned int *) GLptr)) #define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \ - do { \ - int dummy; \ - asm("1: movl (%1),%%eax;" \ - "movl %%eax,%%edx;" \ - "andl %2,%%edx;" \ - "lock; cmpxchgl %%edx,(%1);" \ - "jnz 1b;" \ - "andl $0x1,%%eax" \ - :"=a"(Acq),"=c"(dummy):"c"(GLptr),"i"(~3L):"dx"); \ - } while(0) - + ((Acq) = __acpi_release_global_lock((unsigned int *) GLptr)) /* * Math helper asm macros diff -Nru a/include/asm-i386/dma-mapping.h b/include/asm-i386/dma-mapping.h --- a/include/asm-i386/dma-mapping.h Sun Mar 14 14:20:08 2004 +++ b/include/asm-i386/dma-mapping.h Sun Mar 14 14:20:08 2004 @@ -70,24 +70,42 @@ } static inline void -dma_sync_single(struct device *dev, dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction) +dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) +{ +} + +static inline void +dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) { flush_write_buffers(); } static inline void -dma_sync_single_range(struct device *dev, dma_addr_t dma_handle, - unsigned long offset, size_t size, - enum dma_data_direction direction) +dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ +} + +static inline void +dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, + enum dma_data_direction direction) { flush_write_buffers(); } +static inline void +dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ +} static inline void -dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems, - enum dma_data_direction direction) +dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction direction) { flush_write_buffers(); } diff -Nru a/include/asm-i386/edd.h b/include/asm-i386/edd.h --- a/include/asm-i386/edd.h Sun Mar 14 14:20:06 2004 +++ b/include/asm-i386/edd.h Sun Mar 14 14:20:06 2004 @@ -34,10 +34,11 @@ in empty_zero_block - treat this as 1 byte */ #define EDDBUF 0x600 /* addr of edd_info structs in empty_zero_block */ #define EDDMAXNR 6 /* number of edd_info structs starting at EDDBUF */ -#define EDDEXTSIZE 4 /* change these if you muck with the structures */ +#define EDDEXTSIZE 8 /* change these if you muck with the structures */ #define EDDPARMSIZE 74 #define CHECKEXTENSIONSPRESENT 0x41 #define GETDEVICEPARAMETERS 0x48 +#define LEGACYGETDEVICEPARAMETERS 0x08 #define EDDMAGIC1 0x55AA #define EDDMAGIC2 0xAA55 @@ -165,6 +166,9 @@ u8 device; u8 version; u16 interface_support; + u16 legacy_cylinders; + u8 legacy_heads; + u8 legacy_sectors; struct edd_device_params params; } __attribute__ ((packed)); diff -Nru a/include/asm-i386/io.h b/include/asm-i386/io.h --- a/include/asm-i386/io.h Sun Mar 14 14:20:08 2004 +++ b/include/asm-i386/io.h Sun Mar 14 14:20:08 2004 @@ -45,17 +45,6 @@ #include -/* - * Temporary debugging check to catch old code using - * unmapped ISA addresses. Will be removed in 2.4. - */ -#ifdef CONFIG_DEBUG_IOVIRT - extern void *__io_virt_debug(unsigned long x, const char *file, int line); - #define __io_virt(x) __io_virt_debug((unsigned long)(x), __FILE__, __LINE__) -#else - #define __io_virt(x) ((void *)(x)) -#endif - /** * virt_to_phys - map virtual addresses to physical * @address: address to remap @@ -150,9 +139,9 @@ * memory location directly. */ -#define readb(addr) (*(volatile unsigned char *) __io_virt(addr)) -#define readw(addr) (*(volatile unsigned short *) __io_virt(addr)) -#define readl(addr) (*(volatile unsigned int *) __io_virt(addr)) +#define readb(addr) (*(volatile unsigned char *) (addr)) +#define readw(addr) (*(volatile unsigned short *) (addr)) +#define readl(addr) (*(volatile unsigned int *) (addr)) #define readb_relaxed(addr) readb(addr) #define readw_relaxed(addr) readw(addr) #define readl_relaxed(addr) readl(addr) @@ -160,16 +149,16 @@ #define __raw_readw readw #define __raw_readl readl -#define writeb(b,addr) (*(volatile unsigned char *) __io_virt(addr) = (b)) -#define writew(b,addr) (*(volatile unsigned short *) __io_virt(addr) = (b)) -#define writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b)) +#define writeb(b,addr) (*(volatile unsigned char *) (addr) = (b)) +#define writew(b,addr) (*(volatile unsigned short *) (addr) = (b)) +#define writel(b,addr) (*(volatile unsigned int *) (addr) = (b)) #define __raw_writeb writeb #define __raw_writew writew #define __raw_writel writel -#define memset_io(a,b,c) memset(__io_virt(a),(b),(c)) -#define memcpy_fromio(a,b,c) __memcpy((a),__io_virt(b),(c)) -#define memcpy_toio(a,b,c) __memcpy(__io_virt(a),(b),(c)) +#define memset_io(a,b,c) memset((void *)(a),(b),(c)) +#define memcpy_fromio(a,b,c) __memcpy((a),(void *)(b),(c)) +#define memcpy_toio(a,b,c) __memcpy((void *)(a),(b),(c)) /* * ISA space is 'always mapped' on a typical x86 system, no need to @@ -196,8 +185,8 @@ * Again, i386 does not require mem IO specific function. */ -#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),__io_virt(b),(c),(d)) -#define isa_eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),__io_virt(__ISA_IO_base + (b)),(c),(d)) +#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void *)(b),(c),(d)) +#define isa_eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void *)(__ISA_IO_base + (b)),(c),(d)) /** * check_signature - find BIOS signatures diff -Nru a/include/asm-i386/module.h b/include/asm-i386/module.h --- a/include/asm-i386/module.h Sun Mar 14 14:20:06 2004 +++ b/include/asm-i386/module.h Sun Mar 14 14:20:06 2004 @@ -36,7 +36,7 @@ #define MODULE_PROC_FAMILY "K7 " #elif defined CONFIG_MK8 #define MODULE_PROC_FAMILY "K8 " -#elif defined CONFIG_MELAN +#elif defined CONFIG_X86_ELAN #define MODULE_PROC_FAMILY "ELAN " #elif defined CONFIG_MCRUSOE #define MODULE_PROC_FAMILY "CRUSOE " diff -Nru a/include/asm-i386/pci.h b/include/asm-i386/pci.h --- a/include/asm-i386/pci.h Sun Mar 14 14:20:07 2004 +++ b/include/asm-i386/pci.h Sun Mar 14 14:20:07 2004 @@ -60,27 +60,32 @@ /* This is always fine. */ #define pci_dac_dma_supported(pci_dev, mask) (1) -static __inline__ dma64_addr_t +static inline dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, unsigned long offset, int direction) { return ((dma64_addr_t) page_to_phys(page) + (dma64_addr_t) offset); } -static __inline__ struct page * +static inline struct page * pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr) { return pfn_to_page(dma_addr >> PAGE_SHIFT); } -static __inline__ unsigned long +static inline unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr) { return (dma_addr & ~PAGE_MASK); } -static __inline__ void -pci_dac_dma_sync_single(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction) +static inline void +pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction) +{ +} + +static inline void +pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction) { flush_write_buffers(); } diff -Nru a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h --- a/include/asm-i386/pgtable.h Sun Mar 14 14:20:08 2004 +++ b/include/asm-i386/pgtable.h Sun Mar 14 14:20:08 2004 @@ -173,8 +173,8 @@ */ #undef TEST_VERIFY_AREA -/* page table for 0-4MB for everybody */ -extern unsigned long pg0[1024]; +/* The boot page tables (all created as a single array) */ +extern unsigned long pg0[]; #define pte_present(x) ((x).pte_low & (_PAGE_PRESENT | _PAGE_PROTNONE)) #define pte_clear(xp) do { set_pte(xp, __pte(0)); } while (0) diff -Nru a/include/asm-i386/topology.h b/include/asm-i386/topology.h --- a/include/asm-i386/topology.h Sun Mar 14 14:20:06 2004 +++ b/include/asm-i386/topology.h Sun Mar 14 14:20:06 2004 @@ -66,6 +66,9 @@ return node_to_cpumask(mp_bus_id_to_node[bus]); } +/* Node-to-Node distance */ +#define node_distance(from, to) (from != to) + /* Cross-node load balancing interval. */ #define NODE_BALANCE_RATE 100 diff -Nru a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h --- a/include/asm-i386/unistd.h Sun Mar 14 14:20:07 2004 +++ b/include/asm-i386/unistd.h Sun Mar 14 14:20:07 2004 @@ -375,6 +375,7 @@ #include #include +#include #include /* diff -Nru a/include/asm-ia64/dma-mapping.h b/include/asm-ia64/dma-mapping.h --- a/include/asm-ia64/dma-mapping.h Sun Mar 14 14:20:08 2004 +++ b/include/asm-ia64/dma-mapping.h Sun Mar 14 14:20:08 2004 @@ -14,8 +14,10 @@ #define dma_map_sg platform_dma_map_sg #define dma_unmap_single platform_dma_unmap_single #define dma_unmap_sg platform_dma_unmap_sg -#define dma_sync_single platform_dma_sync_single -#define dma_sync_sg platform_dma_sync_sg +#define dma_sync_single_for_cpu platform_dma_sync_single_for_cpu +#define dma_sync_sg_for_cpu platform_dma_sync_sg_for_cpu +#define dma_sync_single_for_device platform_dma_sync_single_for_device +#define dma_sync_sg_for_device platform_dma_sync_sg_for_device #define dma_map_page(dev, pg, off, size, dir) \ dma_map_single(dev, page_address(pg) + (off), (size), (dir)) @@ -27,8 +29,10 @@ * See Documentation/DMA-API.txt for details. */ -#define dma_sync_single_range(dev, dma_handle, offset, size, dir) \ - dma_sync_single(dev, dma_handle, size, dir) +#define dma_sync_single_range_for_cpu(dev, dma_handle, offset, size, dir) \ + dma_sync_single_for_cpu(dev, dma_handle, size, dir) +#define dma_sync_single_range_for_device(dev, dma_handle, offset, size, dir) \ + dma_sync_single_for_device(dev, dma_handle, size, dir) #define dma_supported platform_dma_supported diff -Nru a/include/asm-ia64/hardirq.h b/include/asm-ia64/hardirq.h --- a/include/asm-ia64/hardirq.h Sun Mar 14 14:20:06 2004 +++ b/include/asm-ia64/hardirq.h Sun Mar 14 14:20:06 2004 @@ -2,7 +2,7 @@ #define _ASM_IA64_HARDIRQ_H /* - * Copyright (C) 1998-2002 Hewlett-Packard Co + * Modified 1998-2002, 2004 Hewlett-Packard Co * David Mosberger-Tang */ @@ -86,8 +86,6 @@ #define hardirq_trylock() (!in_interrupt()) #define hardirq_endlock() do { } while (0) -#define irq_enter() (preempt_count() += HARDIRQ_OFFSET) - #ifdef CONFIG_PREEMPT # include # define in_atomic() ((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked()) @@ -96,14 +94,6 @@ # define in_atomic() (preempt_count() != 0) # define IRQ_EXIT_OFFSET HARDIRQ_OFFSET #endif - -#define irq_exit() \ -do { \ - preempt_count() -= IRQ_EXIT_OFFSET; \ - if (!in_interrupt() && local_softirq_pending()) \ - do_softirq(); \ - preempt_enable_no_resched(); \ -} while (0) #ifdef CONFIG_SMP extern void synchronize_irq (unsigned int irq); diff -Nru a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h --- a/include/asm-ia64/machvec.h Sun Mar 14 14:20:07 2004 +++ b/include/asm-ia64/machvec.h Sun Mar 14 14:20:07 2004 @@ -42,8 +42,10 @@ typedef void ia64_mv_dma_unmap_single (struct device *, dma_addr_t, size_t, int); typedef int ia64_mv_dma_map_sg (struct device *, struct scatterlist *, int, int); typedef void ia64_mv_dma_unmap_sg (struct device *, struct scatterlist *, int, int); -typedef void ia64_mv_dma_sync_single (struct device *, dma_addr_t, size_t, int); -typedef void ia64_mv_dma_sync_sg (struct device *, struct scatterlist *, int, int); +typedef void ia64_mv_dma_sync_single_for_cpu (struct device *, dma_addr_t, size_t, int); +typedef void ia64_mv_dma_sync_sg_for_cpu (struct device *, struct scatterlist *, int, int); +typedef void ia64_mv_dma_sync_single_for_device (struct device *, dma_addr_t, size_t, int); +typedef void ia64_mv_dma_sync_sg_for_device (struct device *, struct scatterlist *, int, int); typedef int ia64_mv_dma_supported (struct device *, u64); /* @@ -104,8 +106,10 @@ # define platform_dma_unmap_single ia64_mv.dma_unmap_single # define platform_dma_map_sg ia64_mv.dma_map_sg # define platform_dma_unmap_sg ia64_mv.dma_unmap_sg -# define platform_dma_sync_single ia64_mv.dma_sync_single -# define platform_dma_sync_sg ia64_mv.dma_sync_sg +# define platform_dma_sync_single_for_cpu ia64_mv.dma_sync_single_for_cpu +# define platform_dma_sync_sg_for_cpu ia64_mv.dma_sync_sg_for_cpu +# define platform_dma_sync_single_for_device ia64_mv.dma_sync_single_for_device +# define platform_dma_sync_sg_for_device ia64_mv.dma_sync_sg_for_device # define platform_dma_supported ia64_mv.dma_supported # define platform_irq_desc ia64_mv.irq_desc # define platform_irq_to_vector ia64_mv.irq_to_vector @@ -150,8 +154,10 @@ ia64_mv_dma_unmap_single *dma_unmap_single; ia64_mv_dma_map_sg *dma_map_sg; ia64_mv_dma_unmap_sg *dma_unmap_sg; - ia64_mv_dma_sync_single *dma_sync_single; - ia64_mv_dma_sync_sg *dma_sync_sg; + ia64_mv_dma_sync_single *dma_sync_single_for_cpu; + ia64_mv_dma_sync_sg *dma_sync_sg_for_cpu; + ia64_mv_dma_sync_single *dma_sync_single_for_device; + ia64_mv_dma_sync_sg *dma_sync_sg_for_device; ia64_mv_dma_supported *dma_supported; ia64_mv_irq_desc *irq_desc; ia64_mv_irq_to_vector *irq_to_vector; @@ -192,8 +198,10 @@ platform_dma_unmap_single, \ platform_dma_map_sg, \ platform_dma_unmap_sg, \ - platform_dma_sync_single, \ - platform_dma_sync_sg, \ + platform_dma_sync_single_for_cpu, \ + platform_dma_sync_sg_for_cpu, \ + platform_dma_sync_single_for_device, \ + platform_dma_sync_sg_for_device, \ platform_dma_supported, \ platform_irq_desc, \ platform_irq_to_vector, \ @@ -231,8 +239,10 @@ extern ia64_mv_dma_unmap_single swiotlb_unmap_single; extern ia64_mv_dma_map_sg swiotlb_map_sg; extern ia64_mv_dma_unmap_sg swiotlb_unmap_sg; -extern ia64_mv_dma_sync_single swiotlb_sync_single; -extern ia64_mv_dma_sync_sg swiotlb_sync_sg; +extern ia64_mv_dma_sync_single_for_cpu swiotlb_sync_single_for_cpu; +extern ia64_mv_dma_sync_sg_for_cpu swiotlb_sync_sg_for_cpu; +extern ia64_mv_dma_sync_single_for_device swiotlb_sync_single_for_device; +extern ia64_mv_dma_sync_sg_for_device swiotlb_sync_sg_for_device; extern ia64_mv_dma_supported swiotlb_dma_supported; /* @@ -290,11 +300,17 @@ #ifndef platform_dma_unmap_sg # define platform_dma_unmap_sg swiotlb_unmap_sg #endif -#ifndef platform_dma_sync_single -# define platform_dma_sync_single swiotlb_sync_single +#ifndef platform_dma_sync_single_for_cpu +# define platform_dma_sync_single_for_cpu swiotlb_sync_single_for_cpu #endif -#ifndef platform_dma_sync_sg -# define platform_dma_sync_sg swiotlb_sync_sg +#ifndef platform_dma_sync_sg_for_cpu +# define platform_dma_sync_sg_for_cpu swiotlb_sync_sg_for_cpu +#endif +#ifndef platform_dma_sync_single_for_device +# define platform_dma_sync_single_for_device swiotlb_sync_single_for_device +#endif +#ifndef platform_dma_sync_sg_for_device +# define platform_dma_sync_sg_for_device swiotlb_sync_sg_for_device #endif #ifndef platform_dma_supported # define platform_dma_supported swiotlb_dma_supported diff -Nru a/include/asm-ia64/machvec_hpzx1.h b/include/asm-ia64/machvec_hpzx1.h --- a/include/asm-ia64/machvec_hpzx1.h Sun Mar 14 14:20:06 2004 +++ b/include/asm-ia64/machvec_hpzx1.h Sun Mar 14 14:20:06 2004 @@ -26,8 +26,10 @@ #define platform_dma_unmap_single sba_unmap_single #define platform_dma_map_sg sba_map_sg #define platform_dma_unmap_sg sba_unmap_sg -#define platform_dma_sync_single ((ia64_mv_dma_sync_single *) machvec_memory_fence) -#define platform_dma_sync_sg ((ia64_mv_dma_sync_sg *) machvec_memory_fence) +#define platform_dma_sync_single_for_cpu ((ia64_mv_dma_sync_single_for_cpu *) machvec_memory_fence) +#define platform_dma_sync_sg_for_cpu ((ia64_mv_dma_sync_sg_for_cpu *) machvec_memory_fence) +#define platform_dma_sync_single_for_device ((ia64_mv_dma_sync_single_for_device *) machvec_memory_fence) +#define platform_dma_sync_sg_for_device ((ia64_mv_dma_sync_sg_for_device *) machvec_memory_fence) #define platform_dma_supported sba_dma_supported #endif /* _ASM_IA64_MACHVEC_HPZX1_h */ diff -Nru a/include/asm-ia64/machvec_sn2.h b/include/asm-ia64/machvec_sn2.h --- a/include/asm-ia64/machvec_sn2.h Sun Mar 14 14:20:07 2004 +++ b/include/asm-ia64/machvec_sn2.h Sun Mar 14 14:20:07 2004 @@ -62,8 +62,10 @@ extern ia64_mv_dma_unmap_single sn_dma_unmap_single; extern ia64_mv_dma_map_sg sn_dma_map_sg; extern ia64_mv_dma_unmap_sg sn_dma_unmap_sg; -extern ia64_mv_dma_sync_single sn_dma_sync_single; -extern ia64_mv_dma_sync_sg sn_dma_sync_sg; +extern ia64_mv_dma_sync_single_for_cpu sn_dma_sync_single_for_cpu; +extern ia64_mv_dma_sync_sg_for_cpu sn_dma_sync_sg_for_cpu; +extern ia64_mv_dma_sync_single_for_device sn_dma_sync_single_for_device; +extern ia64_mv_dma_sync_sg_for_device sn_dma_sync_sg_for_device; extern ia64_mv_dma_supported sn_dma_supported; /* @@ -105,8 +107,10 @@ #define platform_dma_unmap_single sn_dma_unmap_single #define platform_dma_map_sg sn_dma_map_sg #define platform_dma_unmap_sg sn_dma_unmap_sg -#define platform_dma_sync_single sn_dma_sync_single -#define platform_dma_sync_sg sn_dma_sync_sg +#define platform_dma_sync_single_for_cpu sn_dma_sync_single_for_cpu +#define platform_dma_sync_sg_for_cpu sn_dma_sync_sg_for_cpu +#define platform_dma_sync_single_for_device sn_dma_sync_single_for_device +#define platform_dma_sync_sg_for_device sn_dma_sync_sg_for_device #define platform_dma_supported sn_dma_supported #include diff -Nru a/include/asm-ia64/pci.h b/include/asm-ia64/pci.h --- a/include/asm-ia64/pci.h Sun Mar 14 14:20:08 2004 +++ b/include/asm-ia64/pci.h Sun Mar 14 14:20:08 2004 @@ -76,7 +76,8 @@ #define pci_dac_page_to_dma(dev,pg,off,dir) ((dma_addr_t) page_to_bus(pg) + (off)) #define pci_dac_dma_to_page(dev,dma_addr) (virt_to_page(bus_to_virt(dma_addr))) #define pci_dac_dma_to_offset(dev,dma_addr) offset_in_page(dma_addr) -#define pci_dac_dma_sync_single(dev,dma_addr,len,dir) do { mb(); } while (0) +#define pci_dac_dma_sync_single_for_cpu(dev,dma_addr,len,dir) do { } while (0) +#define pci_dac_dma_sync_single_for_device(dev,dma_addr,len,dir) do { mb(); } while (0) #define sg_dma_len(sg) ((sg)->dma_length) #define sg_dma_address(sg) ((sg)->dma_address) diff -Nru a/include/asm-ia64/sal.h b/include/asm-ia64/sal.h --- a/include/asm-ia64/sal.h Sun Mar 14 14:20:08 2004 +++ b/include/asm-ia64/sal.h Sun Mar 14 14:20:08 2004 @@ -35,6 +35,7 @@ #ifndef __ASSEMBLY__ +#include #include #include @@ -229,6 +230,10 @@ extern ia64_sal_handler ia64_sal; extern struct ia64_sal_desc_ptc *ia64_ptc_domain_info; +extern unsigned short sal_revision; /* supported SAL spec revision */ +extern unsigned short sal_version; /* SAL version; OEM dependent */ +#define SAL_VERSION_CODE(major, minor) ((BIN2BCD(major) << 8) | BIN2BCD(minor)) + extern const char *ia64_sal_strerror (long status); extern void ia64_sal_init (struct ia64_sal_systab *sal_systab); @@ -741,10 +746,10 @@ /* Read from PCI configuration space */ static inline s64 -ia64_sal_pci_config_read (u64 pci_config_addr, u64 size, u64 *value) +ia64_sal_pci_config_read (u64 pci_config_addr, int type, u64 size, u64 *value) { struct ia64_sal_retval isrv; - SAL_CALL(isrv, SAL_PCI_CONFIG_READ, pci_config_addr, size, 0, 0, 0, 0, 0); + SAL_CALL(isrv, SAL_PCI_CONFIG_READ, pci_config_addr, size, type, 0, 0, 0, 0); if (value) *value = isrv.v0; return isrv.status; @@ -752,11 +757,11 @@ /* Write to PCI configuration space */ static inline s64 -ia64_sal_pci_config_write (u64 pci_config_addr, u64 size, u64 value) +ia64_sal_pci_config_write (u64 pci_config_addr, int type, u64 size, u64 value) { struct ia64_sal_retval isrv; SAL_CALL(isrv, SAL_PCI_CONFIG_WRITE, pci_config_addr, size, value, - 0, 0, 0, 0); + type, 0, 0, 0); return isrv.status; } diff -Nru a/include/asm-ia64/sn/router.h b/include/asm-ia64/sn/router.h --- a/include/asm-ia64/sn/router.h Sun Mar 14 14:20:06 2004 +++ b/include/asm-ia64/sn/router.h Sun Mar 14 14:20:06 2004 @@ -20,6 +20,7 @@ #include #include #include +#include typedef uint64_t router_reg_t; diff -Nru a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h --- a/include/asm-ia64/unistd.h Sun Mar 14 14:20:06 2004 +++ b/include/asm-ia64/unistd.h Sun Mar 14 14:20:06 2004 @@ -248,6 +248,9 @@ #define __NR_clock_nanosleep 1256 #define __NR_fstatfs64 1257 #define __NR_statfs64 1258 +#define __NR_reserved1 1259 /* reserved for NUMA interface */ +#define __NR_reserved2 1260 /* reserved for NUMA interface */ +#define __NR_reserved3 1261 /* reserved for NUMA interface */ #ifdef __KERNEL__ diff -Nru a/include/asm-m68k/bitops.h b/include/asm-m68k/bitops.h --- a/include/asm-m68k/bitops.h Sun Mar 14 14:20:09 2004 +++ b/include/asm-m68k/bitops.h Sun Mar 14 14:20:09 2004 @@ -21,6 +21,8 @@ __constant_test_and_set_bit(nr, vaddr) : \ __generic_test_and_set_bit(nr, vaddr)) +#define __test_and_set_bit(nr,vaddr) test_and_set_bit(nr,vaddr) + static inline int __constant_test_and_set_bit(int nr, volatile unsigned long *vaddr) { diff -Nru a/include/asm-m68k/irq.h b/include/asm-m68k/irq.h --- a/include/asm-m68k/irq.h Sun Mar 14 14:20:07 2004 +++ b/include/asm-m68k/irq.h Sun Mar 14 14:20:07 2004 @@ -76,10 +76,10 @@ struct pt_regs; -extern int sys_request_irq(unsigned int, - irqreturn_t (*)(int, void *, struct pt_regs *), - unsigned long, const char *, void *); -extern void sys_free_irq(unsigned int, void *); +extern int cpu_request_irq(unsigned int, + irqreturn_t (*)(int, void *, struct pt_regs *), + unsigned long, const char *, void *); +extern void cpu_free_irq(unsigned int, void *); /* * various flags for request_irq() - the Amiga now uses the standard diff -Nru a/include/asm-m68k/unistd.h b/include/asm-m68k/unistd.h --- a/include/asm-m68k/unistd.h Sun Mar 14 14:20:07 2004 +++ b/include/asm-m68k/unistd.h Sun Mar 14 14:20:07 2004 @@ -374,7 +374,6 @@ asmlinkage int sys_execve(char *name, char **argv, char **envp); asmlinkage int sys_pipe(unsigned long *fildes); asmlinkage int sys_ptrace(long request, long pid, long addr, long data); -asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on); struct pt_regs; struct sigaction; asmlinkage long sys_rt_sigaction(int sig, diff -Nru a/include/asm-m68knommu/unistd.h b/include/asm-m68knommu/unistd.h --- a/include/asm-m68knommu/unistd.h Sun Mar 14 14:20:07 2004 +++ b/include/asm-m68knommu/unistd.h Sun Mar 14 14:20:07 2004 @@ -416,7 +416,6 @@ asmlinkage int sys_execve(char *name, char **argv, char **envp); asmlinkage int sys_pipe(unsigned long *fildes); asmlinkage int sys_ptrace(long request, long pid, long addr, long data); -asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on); struct pt_regs; int sys_request_irq(unsigned int, irqreturn_t (*)(int, void *, struct pt_regs *), diff -Nru a/include/asm-mips/dma-mapping.h b/include/asm-mips/dma-mapping.h --- a/include/asm-mips/dma-mapping.h Sun Mar 14 14:20:07 2004 +++ b/include/asm-mips/dma-mapping.h Sun Mar 14 14:20:07 2004 @@ -29,11 +29,17 @@ size_t size, enum dma_data_direction direction); extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, enum dma_data_direction direction); -extern void dma_sync_single(struct device *dev, dma_addr_t dma_handle, +extern void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, enum dma_data_direction direction); -extern void dma_sync_single_range(struct device *dev, dma_addr_t dma_handle, +extern void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, + size_t size, enum dma_data_direction direction); +extern void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, enum dma_data_direction direction); +extern void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, unsigned long offset, size_t size, enum dma_data_direction direction); -extern void dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems, +extern void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction direction); +extern void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, enum dma_data_direction direction); extern int dma_supported(struct device *dev, u64 mask); diff -Nru a/include/asm-mips/pci.h b/include/asm-mips/pci.h --- a/include/asm-mips/pci.h Sun Mar 14 14:20:07 2004 +++ b/include/asm-mips/pci.h Sun Mar 14 14:20:07 2004 @@ -82,7 +82,9 @@ dma64_addr_t dma_addr); extern unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr); -extern void pci_dac_dma_sync_single(struct pci_dev *pdev, +extern void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, + dma64_addr_t dma_addr, size_t len, int direction); +extern void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction); #endif /* __KERNEL__ */ diff -Nru a/include/asm-parisc/dma-mapping.h b/include/asm-parisc/dma-mapping.h --- a/include/asm-parisc/dma-mapping.h Sun Mar 14 14:20:07 2004 +++ b/include/asm-parisc/dma-mapping.h Sun Mar 14 14:20:07 2004 @@ -15,8 +15,10 @@ void (*unmap_single)(struct device *dev, dma_addr_t iova, size_t size, enum dma_data_direction direction); int (*map_sg)(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction direction); void (*unmap_sg)(struct device *dev, struct scatterlist *sg, int nhwents, enum dma_data_direction direction); - void (*dma_sync_single)(struct device *dev, dma_addr_t iova, unsigned long offset, size_t size, enum dma_data_direction direction); - void (*dma_sync_sg)(struct device *dev, struct scatterlist *sg, int nelems, enum dma_data_direction direction); + void (*dma_sync_single_for_cpu)(struct device *dev, dma_addr_t iova, unsigned long offset, size_t size, enum dma_data_direction direction); + void (*dma_sync_single_for_device)(struct device *dev, dma_addr_t iova, unsigned long offset, size_t size, enum dma_data_direction direction); + void (*dma_sync_sg_for_cpu)(struct device *dev, struct scatterlist *sg, int nelems, enum dma_data_direction direction); + void (*dma_sync_sg_for_device)(struct device *dev, struct scatterlist *sg, int nelems, enum dma_data_direction direction); }; /* @@ -116,28 +118,53 @@ static inline void -dma_sync_single(struct device *dev, dma_addr_t dma_handle, size_t size, +dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, enum dma_data_direction direction) { - if(hppa_dma_ops->dma_sync_single) - hppa_dma_ops->dma_sync_single(dev, dma_handle, 0, size, direction); + if(hppa_dma_ops->dma_sync_single_for_cpu) + hppa_dma_ops->dma_sync_single_for_cpu(dev, dma_handle, 0, size, direction); } static inline void -dma_sync_single_range(struct device *dev, dma_addr_t dma_handle, +dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) +{ + if(hppa_dma_ops->dma_sync_single_for_device) + hppa_dma_ops->dma_sync_single_for_device(dev, dma_handle, 0, size, direction); +} + +static inline void +dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + if(hppa_dma_ops->dma_sync_single_for_cpu) + hppa_dma_ops->dma_sync_single_for_cpu(dev, dma_handle, offset, size, direction); +} + +static inline void +dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, unsigned long offset, size_t size, enum dma_data_direction direction) { - if(hppa_dma_ops->dma_sync_single) - hppa_dma_ops->dma_sync_single(dev, dma_handle, offset, size, direction); + if(hppa_dma_ops->dma_sync_single_for_device) + hppa_dma_ops->dma_sync_single_for_device(dev, dma_handle, offset, size, direction); +} + +static inline void +dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, + enum dma_data_direction direction) +{ + if(hppa_dma_ops->dma_sync_sg_for_cpu) + hppa_dma_ops->dma_sync_sg_for_cpu(dev, sg, nelems, direction); } static inline void -dma_sync_sg(struct device *dev, struct scatterlist *sg, int nelems, +dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, enum dma_data_direction direction) { - if(hppa_dma_ops->dma_sync_sg) - hppa_dma_ops->dma_sync_sg(dev, sg, nelems, direction); + if(hppa_dma_ops->dma_sync_sg_for_device) + hppa_dma_ops->dma_sync_sg_for_device(dev, sg, nelems, direction); } static inline int @@ -166,14 +193,14 @@ static inline int dma_is_consistent(dma_addr_t dma_addr) { - return (hppa_dma_ops->dma_sync_single == NULL); + return (hppa_dma_ops->dma_sync_single_for_cpu == NULL); } static inline void dma_cache_sync(void *vaddr, size_t size, enum dma_data_direction direction) { - if(hppa_dma_ops->dma_sync_single) + if(hppa_dma_ops->dma_sync_single_for_cpu) flush_kernel_dcache_range((unsigned long)vaddr, size); } diff -Nru a/include/asm-parisc/floppy.h b/include/asm-parisc/floppy.h --- a/include/asm-parisc/floppy.h Sun Mar 14 14:20:07 2004 +++ b/include/asm-parisc/floppy.h Sun Mar 14 14:20:07 2004 @@ -1,11 +1,22 @@ -/* - * Architecture specific parts of the Floppy driver +/* Architecture specific parts of the Floppy driver * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. + * Linux/PA-RISC Project (http://www.parisc-linux.org/) + * Copyright (C) 2000 Matthew Wilcox (willy a debian . org) + * Copyright (C) 2000 Dave Kennedy * - * Copyright (C) 1995 + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __ASM_PARISC_FLOPPY_H #define __ASM_PARISC_FLOPPY_H diff -Nru a/include/asm-parisc/grfioctl.h b/include/asm-parisc/grfioctl.h --- a/include/asm-parisc/grfioctl.h Sun Mar 14 14:20:06 2004 +++ b/include/asm-parisc/grfioctl.h Sun Mar 14 14:20:06 2004 @@ -1,7 +1,23 @@ -/* - * Architecture specific parts of HP's STI (framebuffer) driver - * structures are HP-UX compatible for XFree86 usage - */ +/* Architecture specific parts of HP's STI (framebuffer) driver. + * Structures are HP-UX compatible for XFree86 usage. + * + * Linux/PA-RISC Project (http://www.parisc-linux.org/) + * Copyright (C) 2001 Helge Deller (deller a parisc-linux org) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ #ifndef __ASM_PARISC_GRFIOCTL_H #define __ASM_PARISC_GRFIOCTL_H diff -Nru a/include/asm-parisc/ide.h b/include/asm-parisc/ide.h --- a/include/asm-parisc/ide.h Sun Mar 14 14:20:07 2004 +++ b/include/asm-parisc/ide.h Sun Mar 14 14:20:07 2004 @@ -14,36 +14,13 @@ #ifdef __KERNEL__ #include -#include #ifndef MAX_HWIFS #define MAX_HWIFS 2 #endif -static __inline__ int ide_default_irq(ide_ioreg_t base) -{ - switch (base) { -#ifdef CONFIG_SUPERIO - case 0x1f0: - case 0x170: - return superio_get_ide_irq(); -#endif /* CONFIG_SUPERIO */ - default: - return 0; - } -} - -static __inline__ ide_ioreg_t ide_default_io_base(int index) -{ - switch (index) { -#ifdef CONFIG_SUPERIO - case 0: return (superio_get_ide_irq() ? 0x1f0 : 0); - case 1: return (superio_get_ide_irq() ? 0x170 : 0); -#endif /* CONFIG_SUPERIO */ - default: - return 0; - } -} +#define ide_default_irq(base) (0) +#define ide_default_io_base(index) ((ide_ioreg_t)0) static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) { @@ -93,7 +70,7 @@ static __inline__ void __ide_mm_insw(unsigned long port, void *addr, u32 count) { while (count--) { - *(u16 *)addr = readw(port); + *(u16 *)addr = __raw_readw(port); addr += 2; } } @@ -101,7 +78,7 @@ static __inline__ void __ide_mm_insl(unsigned long port, void *addr, u32 count) { while (count--) { - *(u32 *)addr = readl(port); + *(u32 *)addr = __raw_readl(port); addr += 4; } } @@ -109,7 +86,7 @@ static __inline__ void __ide_mm_outsw(unsigned long port, void *addr, u32 count) { while (count--) { - writew(*(u16 *)addr, port); + __raw_writew(*(u16 *)addr, port); addr += 2; } } @@ -117,7 +94,7 @@ static __inline__ void __ide_mm_outsl(unsigned long port, void *addr, u32 count) { while (count--) { - writel(*(u32 *)addr, port); + __raw_writel(*(u32 *)addr, port); addr += 4; } } diff -Nru a/include/asm-parisc/io.h b/include/asm-parisc/io.h --- a/include/asm-parisc/io.h Sun Mar 14 14:20:06 2004 +++ b/include/asm-parisc/io.h Sun Mar 14 14:20:06 2004 @@ -13,6 +13,12 @@ #include #include +extern unsigned long parisc_vmerge_boundary; +extern unsigned long parisc_vmerge_max_size; + +#define BIO_VMERGE_BOUNDARY parisc_vmerge_boundary +#define BIO_VMERGE_MAX_SIZE parisc_vmerge_max_size + #define virt_to_phys(a) ((unsigned long)__pa(a)) #define phys_to_virt(a) __va(a) #define virt_to_bus virt_to_phys diff -Nru a/include/asm-parisc/ioctl.h b/include/asm-parisc/ioctl.h --- a/include/asm-parisc/ioctl.h Sun Mar 14 14:20:05 2004 +++ b/include/asm-parisc/ioctl.h Sun Mar 14 14:20:05 2004 @@ -1,7 +1,23 @@ -/* $Id: ioctl.h,v 1.2 1999/12/29 22:18:15 willy Exp $ +/* + * Linux/PA-RISC Project (http://www.parisc-linux.org/) + * Copyright (C) 1999,2003 Matthew Wilcox < willy at debian . org > + * portions from "linux/ioctl.h for Linux" by H.H. Bergman. * - * linux/ioctl.h for Linux by H.H. Bergman. + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + #ifndef _ASM_PARISC_IOCTL_H #define _ASM_PARISC_IOCTL_H diff -Nru a/include/asm-parisc/keyboard.h b/include/asm-parisc/keyboard.h --- a/include/asm-parisc/keyboard.h Sun Mar 14 14:20:06 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,82 +0,0 @@ -/* - * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING - * --------------------------------------------------------------- - * This file will be removed as soon as we have converted - * hp_psaux.c and hp_keyb.c to the input layer ! - * - */ - - -/* - * linux/include/asm-parisc/keyboard.h - * - * Original by Geert Uytterhoeven - * updates by Alex deVries - * portions copyright (1999) The Puffin Group - * mostly rewritten by Philipp Rumpf , - * Copyright 2000 Philipp Rumpf - */ - -/* - * We try to keep the amount of generic code as low as possible - - * we want to support all HIL, PS/2, and untranslated USB keyboards - */ - -#ifndef _PARISC_KEYBOARD_H -#define _PARISC_KEYBOARD_H - -#ifdef __KERNEL__ - -#include -#include - -/* These are basically the generic functions / variables. The only - * unexpected detail is the initialization sequence for the keyboard - * driver is something like this: - * - * detect keyboard port - * detect keyboard - * call register_kbd_ops - * wait for init_hw - * - * only after init_hw has been called you're allowed to call - * handle_scancode. This means you either have to be extremely - * careful or use a global flag or something - I strongly suggest - * the latter. prumpf */ - -extern struct kbd_ops { - int (*setkeycode)(unsigned int, unsigned int); - int (*getkeycode)(unsigned int); - int (*translate)(unsigned char, unsigned char *, char); - char (*unexpected_up)(unsigned char); - void (*leds)(unsigned char); - void (*init_hw)(void); - - /* Keyboard driver resource allocation */ - int (*kbd_request_irq)(void (*handler)(int, void *, struct pt_regs *)); - - unsigned char sysrq_key; - unsigned char *sysrq_xlate; -} kbd_ops; - -#define kbd_setkeycode (*kbd_ops->setkeycode) -#define kbd_getkeycode (*kbd_ops->getkeycode) -#define kbd_translate (*kbd_ops->translate) -#define kbd_unexpected_up (*kbd_ops->unexpected_up) -#define kbd_leds (*kbd_ops->leds) -#define kbd_init_hw (*kbd_ops->init_hw) - -#define SYSRQ_KEY (kbd_ops->sysrq_key) -#define kbd_sysrq_xlate (kbd_ops->sysrq_xlate) - -/* Do the actual calls via kbd_ops vector */ -#define kbd_request_irq(handler) kbd_ops->kbd_request_irq(handler) - -extern unsigned char hp_ps2kbd_sysrq_xlate[128]; /* from drivers/char/hp_keyb.c */ - -extern void unregister_kbd_ops(void); -extern void register_kbd_ops(struct kbd_ops *ops); - -#endif /* __KERNEL__ */ - -#endif /* __ASMPARISC_KEYBOARD_H */ diff -Nru a/include/asm-parisc/md.h b/include/asm-parisc/md.h --- a/include/asm-parisc/md.h Sun Mar 14 14:20:06 2004 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,13 +0,0 @@ -/* $Id: md.h,v 1.1.1.1 1999/03/15 19:41:02 pjlahaie Exp $ - * md.h: High speed xor_block operation for RAID4/5 - * - */ - -#ifndef __ASM_MD_H -#define __ASM_MD_H - -/* #define HAVE_ARCH_XORBLOCK */ - -#define MD_XORBLOCK_ALIGNMENT sizeof(long) - -#endif /* __ASM_MD_H */ diff -Nru a/include/asm-parisc/namei.h b/include/asm-parisc/namei.h --- a/include/asm-parisc/namei.h Sun Mar 14 14:20:07 2004 +++ b/include/asm-parisc/namei.h Sun Mar 14 14:20:07 2004 @@ -1,4 +1,4 @@ -/* $Id: namei.h,v 1.1.1.1 1999/03/15 19:41:02 pjlahaie Exp $ +/* $Id: namei.h,v 1.1 1996/12/13 14:48:21 jj Exp $ * linux/include/asm-parisc/namei.h * * Included from linux/fs/namei.c diff -Nru a/include/asm-parisc/pci.h b/include/asm-parisc/pci.h --- a/include/asm-parisc/pci.h Sun Mar 14 14:20:08 2004 +++ b/include/asm-parisc/pci.h Sun Mar 14 14:20:08 2004 @@ -43,7 +43,7 @@ ** ** This is the "common" or "base" data structure which HBA drivers ** (eg Dino or LBA) are required to place at the top of their own -** dev->sysdata structure. I've heard this called "C inheritance" too. +** platform_data structure. I've heard this called "C inheritance" too. ** ** Data needed by pcibios layer belongs here. */ diff -Nru a/include/asm-parisc/semaphore.h b/include/asm-parisc/semaphore.h --- a/include/asm-parisc/semaphore.h Sun Mar 14 14:20:05 2004 +++ b/include/asm-parisc/semaphore.h Sun Mar 14 14:20:05 2004 @@ -1,14 +1,28 @@ -#ifndef _ASM_PARISC_SEMAPHORE_H -#define _ASM_PARISC_SEMAPHORE_H - -/* - * SMP- and interrupt-safe semaphores. +/* SMP- and interrupt-safe semaphores. + * PA-RISC version by Matthew Wilcox + * + * Linux/PA-RISC Project (http://www.parisc-linux.org/) + * Copyright (C) 1996 Linus Torvalds + * Copyright (C) 1999-2001 Matthew Wilcox < willy at debian d0T org > + * Copyright (C) 2000 Grant Grundler < grundler a debian org > * - * (C) Copyright 1996 Linus Torvalds + * 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. * - * PA-RISC version by Matthew Wilcox + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#ifndef _ASM_PARISC_SEMAPHORE_H +#define _ASM_PARISC_SEMAPHORE_H #include #include diff -Nru a/include/asm-parisc/superio.h b/include/asm-parisc/superio.h --- a/include/asm-parisc/superio.h Sun Mar 14 14:20:06 2004 +++ b/include/asm-parisc/superio.h Sun Mar 14 14:20:06 2004 @@ -81,9 +81,12 @@ || ((x)->device == PCI_DEVICE_ID_NS_87560_LIO) \ || ((x)->device == PCI_DEVICE_ID_NS_87560_USB) ) ) +struct hwif_s; + extern void superio_inform_irq(int irq); extern void superio_serial_init(void); /* called by rs_init() */ extern int superio_fixup_irq(struct pci_dev *pcidev); /* called by iosapic */ -extern int superio_get_ide_irq(void); +extern void superio_fixup_pci(struct pci_dev *pdev); +extern void superio_ide_init_iops (struct hwif_s *hwif); #endif /* _PARISC_SUPERIO_H */ diff -Nru a/include/asm-parisc/unistd.h b/include/asm-parisc/unistd.h --- a/include/asm-parisc/unistd.h Sun Mar 14 14:20:05 2004 +++ b/include/asm-parisc/unistd.h Sun Mar 14 14:20:05 2004 @@ -909,7 +909,6 @@ int sys_vfork(struct pt_regs *regs); int sys_pipe(int *fildes); long sys_ptrace(long request, pid_t pid, long addr, long data); -asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on); struct sigaction; asmlinkage long sys_rt_sigaction(int sig, const struct sigaction __user *act, diff -Nru a/include/asm-ppc/pci.h b/include/asm-ppc/pci.h --- a/include/asm-ppc/pci.h Sun Mar 14 14:20:08 2004 +++ b/include/asm-ppc/pci.h Sun Mar 14 14:20:08 2004 @@ -91,7 +91,7 @@ * The 32-bit bus address to use is returned. * * Once the device is given the dma address, the device owns this memory - * until either pci_unmap_single or pci_dma_sync_single is performed. + * until either pci_unmap_single or pci_dma_sync_single_for_cpu is performed. */ static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction) @@ -190,35 +190,58 @@ * If you perform a pci_map_single() but wish to interrogate the * buffer using the cpu, yet do not wish to teardown the PCI dma * mapping, you must call this function before doing so. At the - * next point you give the PCI dma address back to the card, the - * device again owns the buffer. + * next point you give the PCI dma address back to the card, you + * must first perform a pci_dma_sync_for_device, and then the device + * again owns the buffer. */ -static inline void pci_dma_sync_single(struct pci_dev *hwdev, - dma_addr_t dma_handle, - size_t size, int direction) +static inline void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, + dma_addr_t dma_handle, + size_t size, int direction) { BUG_ON(direction == PCI_DMA_NONE); - consistent_sync(bus_to_virt(dma_handle), size, direction); + consistent_sync_for_cpu(bus_to_virt(dma_handle), size, direction); +} + +static inline void pci_dma_sync_single_for_device(struct pci_dev *hwdev, + dma_addr_t dma_handle, + size_t size, int direction) +{ + BUG_ON(direction == PCI_DMA_NONE); + + consistent_sync_for_device(bus_to_virt(dma_handle), size, direction); } /* Make physical memory consistent for a set of streaming * mode DMA translations after a transfer. * - * The same as pci_dma_sync_single but for a scatter-gather list, + * The same as pci_dma_sync_single_for_* but for a scatter-gather list, * same rules and usage. */ -static inline void pci_dma_sync_sg(struct pci_dev *hwdev, - struct scatterlist *sg, - int nelems, int direction) +static inline void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, + struct scatterlist *sg, + int nelems, int direction) { int i; BUG_ON(direction == PCI_DMA_NONE); for (i = 0; i < nelems; i++, sg++) - consistent_sync_page(sg->page, sg->offset, - sg->length, direction); + consistent_sync_page_for_cpu(sg->page, sg->offset, + sg->length, direction); +} + +static inline void pci_dma_sync_sg_for_device(struct pci_dev *hwdev, + struct scatterlist *sg, + int nelems, int direction) +{ + int i; + + BUG_ON(direction == PCI_DMA_NONE); + + for (i = 0; i < nelems; i++, sg++) + consistent_sync_page_for_device(sg->page, sg->offset, + sg->length, direction); } /* Return whether the given PCI device DMA address mask can @@ -237,26 +260,32 @@ */ #define pci_dac_dma_supported(pci_dev, mask) (0) -static __inline__ dma64_addr_t +static inline dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, unsigned long offset, int direction) { return (dma64_addr_t) page_to_bus(page) + offset; } -static __inline__ struct page * +static inline struct page * pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr) { return mem_map + (unsigned long)(dma_addr >> PAGE_SHIFT); } -static __inline__ unsigned long +static inline unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr) { return (dma_addr & ~PAGE_MASK); } -static __inline__ void -pci_dac_dma_sync_single(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction) +static inline void +pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction) +{ + /* Nothing to do. */ +} + +static inline void +pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction) { /* Nothing to do. */ } diff -Nru a/include/asm-ppc64/mmzone.h b/include/asm-ppc64/mmzone.h --- a/include/asm-ppc64/mmzone.h Sun Mar 14 14:20:08 2004 +++ b/include/asm-ppc64/mmzone.h Sun Mar 14 14:20:08 2004 @@ -28,7 +28,8 @@ #define MEMORY_INCREMENT_SHIFT 28 #define MEMORY_INCREMENT (1UL << MEMORY_INCREMENT_SHIFT) -#define DEBUG_NUMA +/* NUMA debugging, will not work on a DLPAR machine */ +#undef DEBUG_NUMA static inline int pa_to_nid(unsigned long pa) { diff -Nru a/include/asm-ppc64/pci.h b/include/asm-ppc64/pci.h --- a/include/asm-ppc64/pci.h Sun Mar 14 14:20:07 2004 +++ b/include/asm-ppc64/pci.h Sun Mar 14 14:20:07 2004 @@ -112,17 +112,33 @@ pci_dma_ops.pci_unmap_sg(hwdev, sg, nents, direction); } -static inline void pci_dma_sync_single(struct pci_dev *hwdev, - dma_addr_t dma_handle, - size_t size, int direction) +static inline void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, + dma_addr_t dma_handle, + size_t size, int direction) { BUG_ON(direction == PCI_DMA_NONE); /* nothing to do */ } -static inline void pci_dma_sync_sg(struct pci_dev *hwdev, - struct scatterlist *sg, - int nelems, int direction) +static inline void pci_dma_sync_single_for_device(struct pci_dev *hwdev, + dma_addr_t dma_handle, + size_t size, int direction) +{ + BUG_ON(direction == PCI_DMA_NONE); + /* nothing to do */ +} + +static inline void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, + struct scatterlist *sg, + int nelems, int direction) +{ + BUG_ON(direction == PCI_DMA_NONE); + /* nothing to do */ +} + +static inline void pci_dma_sync_sg_for_device(struct pci_dev *hwdev, + struct scatterlist *sg, + int nelems, int direction) { BUG_ON(direction == PCI_DMA_NONE); /* nothing to do */ diff -Nru a/include/asm-ppc64/unistd.h b/include/asm-ppc64/unistd.h --- a/include/asm-ppc64/unistd.h Sun Mar 14 14:20:05 2004 +++ b/include/asm-ppc64/unistd.h Sun Mar 14 14:20:05 2004 @@ -399,15 +399,19 @@ /* * System call prototypes. */ -extern pid_t setsid(void); -extern int write(int fd, const char *buf, off_t count); -extern int read(int fd, char *buf, off_t count); -extern off_t lseek(int fd, off_t offset, int count); -extern int dup(int fd); -extern int execve(const char *file, char **argv, char **envp); -extern int open(const char *file, int flag, int mode); -extern int close(int fd); -extern pid_t waitpid(pid_t pid, int *wait_stat, int options); +static inline _syscall3(int, execve, __const__ char *, file, char **, argv, + char **,envp) +static inline _syscall3(int, open, __const__ char *, file, int, flag, int, mode) +static inline _syscall1(int, close, int, fd) +static inline _syscall1(int, dup, int, fd) +static inline _syscall3(int, read, int, fd, char *, buf , off_t, count) +static inline _syscall3(int, write, int, fd, __const__ char *, buf, off_t, + count) +static inline _syscall0(pid_t, setsid) +static inline _syscall3(off_t, lseek, int, fd, off_t, offset, int, count) +static inline _syscall3(pid_t, waitpid, pid_t, pid, int *, wait_stat, int, + options) + #endif /* __KERNEL_SYSCALLS__ */ asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, diff -Nru a/include/asm-s390/unistd.h b/include/asm-s390/unistd.h --- a/include/asm-s390/unistd.h Sun Mar 14 14:20:09 2004 +++ b/include/asm-s390/unistd.h Sun Mar 14 14:20:09 2004 @@ -553,7 +553,6 @@ #endif /* CONFIG_ARCH_S390X */ asmlinkage __SYS_RETTYPE sys_pipe(unsigned long *fildes); asmlinkage int sys_ptrace(long request, long pid, long addr, long data); -asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on); struct sigaction; asmlinkage long sys_rt_sigaction(int sig, const struct sigaction __user *act, diff -Nru a/include/asm-sh/pci.h b/include/asm-sh/pci.h --- a/include/asm-sh/pci.h Sun Mar 14 14:20:07 2004 +++ b/include/asm-sh/pci.h Sun Mar 14 14:20:07 2004 @@ -84,7 +84,7 @@ * The 32-bit bus address to use is returned. * * Once the device is given the dma address, the device owns this memory - * until either pci_unmap_single or pci_dma_sync_single is performed. + * until either pci_unmap_single or pci_dma_sync_single_for_cpu is performed. */ static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction) @@ -184,12 +184,21 @@ * If you perform a pci_map_single() but wish to interrogate the * buffer using the cpu, yet do not wish to teardown the PCI dma * mapping, you must call this function before doing so. At the - * next point you give the PCI dma address back to the card, the - * device again owns the buffer. - */ -static inline void pci_dma_sync_single(struct pci_dev *hwdev, - dma_addr_t dma_handle, - size_t size, int direction) + * next point you give the PCI dma address back to the card, you + * must first perform a pci_dma_sync_for_device, and then the device + * again owns the buffer. + */ +static inline void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, + dma_addr_t dma_handle, + size_t size, int direction) +{ + if (direction == PCI_DMA_NONE) + BUG(); +} + +static inline void pci_dma_sync_single_for_device(struct pci_dev *hwdev, + dma_addr_t dma_handle, + size_t size, int direction) { if (direction == PCI_DMA_NONE) BUG(); @@ -203,12 +212,20 @@ /* Make physical memory consistent for a set of streaming * mode DMA translations after a transfer. * - * The same as pci_dma_sync_single but for a scatter-gather list, + * The same as pci_dma_sync_single_* but for a scatter-gather list, * same rules and usage. */ -static inline void pci_dma_sync_sg(struct pci_dev *hwdev, - struct scatterlist *sg, - int nelems, int direction) +static inline void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, + struct scatterlist *sg, + int nelems, int direction) +{ + if (direction == PCI_DMA_NONE) + BUG(); +} + +static inline void pci_dma_sync_sg_for_device(struct pci_dev *hwdev, + struct scatterlist *sg, + int nelems, int direction) { if (direction == PCI_DMA_NONE) BUG(); diff -Nru a/include/asm-sparc/pci.h b/include/asm-sparc/pci.h --- a/include/asm-sparc/pci.h Sun Mar 14 14:20:08 2004 +++ b/include/asm-sparc/pci.h Sun Mar 14 14:20:08 2004 @@ -52,7 +52,7 @@ * The 32-bit bus address to use is returned. * * Once the device is given the dma address, the device owns this memory - * until either pci_unmap_single or pci_dma_sync_single is performed. + * until either pci_unmap_single or pci_dma_sync_single_for_cpu is performed. */ extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction); @@ -116,18 +116,21 @@ * If you perform a pci_map_single() but wish to interrogate the * buffer using the cpu, yet do not wish to teardown the PCI dma * mapping, you must call this function before doing so. At the - * next point you give the PCI dma address back to the card, the - * device again owns the buffer. + * next point you give the PCI dma address back to the card, you + * must first perform a pci_dma_sync_for_device, and then the device + * again owns the buffer. */ -extern void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction); +extern void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction); +extern void pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction); /* Make physical memory consistent for a set of streaming * mode DMA translations after a transfer. * - * The same as pci_dma_sync_single but for a scatter-gather list, + * The same as pci_dma_sync_single_* but for a scatter-gather list, * same rules and usage. */ -extern void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction); +extern void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction); +extern void pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction); /* Return whether the given PCI device DMA address mask can * be supported properly. For example, if your device can diff -Nru a/include/asm-sparc/sbus.h b/include/asm-sparc/sbus.h --- a/include/asm-sparc/sbus.h Sun Mar 14 14:20:06 2004 +++ b/include/asm-sparc/sbus.h Sun Mar 14 14:20:06 2004 @@ -118,8 +118,12 @@ extern void sbus_unmap_sg(struct sbus_dev *, struct scatterlist *, int, int); /* Finally, allow explicit synchronization of streamable mappings. */ -extern void sbus_dma_sync_single(struct sbus_dev *, dma_addr_t, size_t, int); -extern void sbus_dma_sync_sg(struct sbus_dev *, struct scatterlist *, int, int); +extern void sbus_dma_sync_single_for_cpu(struct sbus_dev *, dma_addr_t, size_t, int); +#define sbus_dma_sync_single sbus_dma_sync_single_for_cpu +extern void sbus_dma_sync_single_for_device(struct sbus_dev *, dma_addr_t, size_t, int); +extern void sbus_dma_sync_sg_for_cpu(struct sbus_dev *, struct scatterlist *, int, int); +#define sbus_dma_sync_sg sbus_dma_sync_sg_for_cpu +extern void sbus_dma_sync_sg_for_device(struct sbus_dev *, struct scatterlist *, int, int); /* Eric Brower (ebrower@usa.net) * Translate SBus interrupt levels to ino values-- diff -Nru a/include/asm-sparc64/pci.h b/include/asm-sparc64/pci.h --- a/include/asm-sparc64/pci.h Sun Mar 14 14:20:06 2004 +++ b/include/asm-sparc64/pci.h Sun Mar 14 14:20:06 2004 @@ -60,7 +60,7 @@ * The 32-bit bus address to use is returned. * * Once the device is given the dma address, the device owns this memory - * until either pci_unmap_single or pci_dma_sync_single is performed. + * until either pci_unmap_single or pci_dma_sync_single_for_cpu is performed. */ extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction); @@ -123,19 +123,36 @@ * If you perform a pci_map_single() but wish to interrogate the * buffer using the cpu, yet do not wish to teardown the PCI dma * mapping, you must call this function before doing so. At the - * next point you give the PCI dma address back to the card, the + * next point you give the PCI dma address back to the card, you + * must first perform a pci_dma_sync_for_device, and then the * device again owns the buffer. */ -extern void pci_dma_sync_single(struct pci_dev *hwdev, dma_addr_t dma_handle, - size_t size, int direction); +extern void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle, + size_t size, int direction); + +static inline void +pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle, + size_t size, int direction) +{ + /* No flushing needed to sync cpu writes to the device. */ + BUG_ON(direction == PCI_DMA_NONE); +} /* Make physical memory consistent for a set of streaming * mode DMA translations after a transfer. * - * The same as pci_dma_sync_single but for a scatter-gather list, + * The same as pci_dma_sync_single_* but for a scatter-gather list, * same rules and usage. */ -extern void pci_dma_sync_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction); +extern void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction); + +static inline void +pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg, + int nelems, int direction) +{ + /* No flushing needed to sync cpu writes to the device. */ + BUG_ON(direction == PCI_DMA_NONE); +} /* Return whether the given PCI device DMA address mask can * be supported properly. For example, if your device can @@ -159,14 +176,14 @@ #define pci_dac_dma_supported(pci_dev, mask) \ ((((mask) & PCI64_REQUIRED_MASK) == PCI64_REQUIRED_MASK) ? 1 : 0) -static __inline__ dma64_addr_t +static inline dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, unsigned long offset, int direction) { return (PCI64_ADDR_BASE + __pa(page_address(page)) + offset); } -static __inline__ struct page * +static inline struct page * pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr) { unsigned long paddr = (dma_addr & PAGE_MASK) - PCI64_ADDR_BASE; @@ -174,14 +191,22 @@ return virt_to_page(__va(paddr)); } -static __inline__ unsigned long +static inline unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr) { return (dma_addr & ~PAGE_MASK); } -static __inline__ void -pci_dac_dma_sync_single(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction) +static inline void +pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction) +{ + /* DAC cycle addressing does not make use of the + * PCI controller's streaming cache, so nothing to do. + */ +} + +static inline void +pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction) { /* DAC cycle addressing does not make use of the * PCI controller's streaming cache, so nothing to do. diff -Nru a/include/asm-sparc64/sbus.h b/include/asm-sparc64/sbus.h --- a/include/asm-sparc64/sbus.h Sun Mar 14 14:20:06 2004 +++ b/include/asm-sparc64/sbus.h Sun Mar 14 14:20:06 2004 @@ -111,7 +111,11 @@ extern void sbus_unmap_sg(struct sbus_dev *, struct scatterlist *, int, int); /* Finally, allow explicit synchronization of streamable mappings. */ -extern void sbus_dma_sync_single(struct sbus_dev *, dma_addr_t, size_t, int); -extern void sbus_dma_sync_sg(struct sbus_dev *, struct scatterlist *, int, int); +extern void sbus_dma_sync_single_for_cpu(struct sbus_dev *, dma_addr_t, size_t, int); +#define sbus_dma_sync_single sbus_dma_sync_single_for_cpu +extern void sbus_dma_sync_single_for_device(struct sbus_dev *, dma_addr_t, size_t, int); +extern void sbus_dma_sync_sg_for_cpu(struct sbus_dev *, struct scatterlist *, int, int); +#define sbus_dma_sync_sg sbus_dma_sync_sg_for_cpu +extern void sbus_dma_sync_sg_for_device(struct sbus_dev *, struct scatterlist *, int, int); #endif /* !(_SPARC64_SBUS_H) */ diff -Nru a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h --- a/include/asm-sparc64/unistd.h Sun Mar 14 14:20:06 2004 +++ b/include/asm-sparc64/unistd.h Sun Mar 14 14:20:06 2004 @@ -447,7 +447,6 @@ unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long off); -asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on); struct sigaction; asmlinkage long sys_rt_sigaction(int sig, const struct sigaction __user *act, diff -Nru a/include/asm-v850/pci.h b/include/asm-v850/pci.h --- a/include/asm-v850/pci.h Sun Mar 14 14:20:06 2004 +++ b/include/asm-v850/pci.h Sun Mar 14 14:20:06 2004 @@ -27,7 +27,7 @@ /* `Grant' to PDEV the memory block at CPU_ADDR, for doing DMA. The 32-bit PCI bus mastering address to use is returned. the device owns - this memory until either pci_unmap_single or pci_dma_sync_single is + this memory until either pci_unmap_single or pci_dma_sync_single_for_cpu is performed. */ extern dma_addr_t pci_map_single (struct pci_dev *pdev, void *cpu_addr, size_t size, int dir); @@ -44,10 +44,15 @@ If you perform a pci_map_single() but wish to interrogate the buffer using the cpu, yet do not wish to teardown the PCI dma mapping, you must call this function before doing so. At the next - point you give the PCI dma address back to the card, the device - again owns the buffer. */ + point you give the PCI dma address back to the card, you must first + perform a pci_dma_sync_for_device, and then the device again owns + the buffer. */ extern void -pci_dma_sync_single (struct pci_dev *dev, dma_addr_t dma_addr, size_t size, +pci_dma_sync_single_for_cpu (struct pci_dev *dev, dma_addr_t dma_addr, size_t size, + int dir); + +extern void +pci_dma_sync_single_for_device (struct pci_dev *dev, dma_addr_t dma_addr, size_t size, int dir); diff -Nru a/include/asm-x86_64/acpi.h b/include/asm-x86_64/acpi.h --- a/include/asm-x86_64/acpi.h Sun Mar 14 14:20:07 2004 +++ b/include/asm-x86_64/acpi.h Sun Mar 14 14:20:07 2004 @@ -60,7 +60,7 @@ do { old = *lock; new = (((old & ~0x3) + 2) + ((old >> 1) & 0x1)); - val = cmpxchg4_locked(lock, new, old); + val = cmpxchg(lock, old, new); } while (unlikely (val != old)); return (new < 3) ? -1 : 0; } @@ -72,7 +72,7 @@ do { old = *lock; new = old & ~0x3; - val = cmpxchg4_locked(lock, new, old); + val = cmpxchg(lock, old, new); } while (unlikely (val != old)); return old & 0x1; } diff -Nru a/include/asm-x86_64/calling.h b/include/asm-x86_64/calling.h --- a/include/asm-x86_64/calling.h Sun Mar 14 14:20:07 2004 +++ b/include/asm-x86_64/calling.h Sun Mar 14 14:20:07 2004 @@ -31,7 +31,7 @@ #define ARGOFFSET R11 #define SWFRAME ORIG_RAX - .macro SAVE_ARGS addskip=0,norcx=0 + .macro SAVE_ARGS addskip=0,norcx=0,nor891011=0 subq $9*8+\addskip,%rsp CFI_ADJUST_CFA_OFFSET 9*8+\addskip movq %rdi,8*8(%rsp) @@ -47,6 +47,8 @@ .endif movq %rax,4*8(%rsp) CFI_OFFSET rax,4*8-(9*8+\addskip) + .if \nor891011 + .else movq %r8,3*8(%rsp) CFI_OFFSET r8,3*8-(9*8+\addskip) movq %r9,2*8(%rsp) @@ -55,17 +57,21 @@ CFI_OFFSET r10,1*8-(9*8+\addskip) movq %r11,(%rsp) CFI_OFFSET r11,-(9*8+\addskip) + .endif .endm #define ARG_SKIP 9*8 - .macro RESTORE_ARGS skiprax=0,addskip=0,skiprcx=0,skipr11=0 + .macro RESTORE_ARGS skiprax=0,addskip=0,skiprcx=0,skipr11=0,skipr8910=0,skiprdx=0 .if \skipr11 .else movq (%rsp),%r11 .endif + .if \skipr8910 + .else movq 1*8(%rsp),%r10 movq 2*8(%rsp),%r9 movq 3*8(%rsp),%r8 + .endif .if \skiprax .else movq 4*8(%rsp),%rax @@ -74,7 +80,10 @@ .else movq 5*8(%rsp),%rcx .endif + .if \skiprdx + .else movq 6*8(%rsp),%rdx + .endif movq 7*8(%rsp),%rsi movq 8*8(%rsp),%rdi .if ARG_SKIP+\addskip > 0 diff -Nru a/include/asm-x86_64/io.h b/include/asm-x86_64/io.h --- a/include/asm-x86_64/io.h Sun Mar 14 14:20:07 2004 +++ b/include/asm-x86_64/io.h Sun Mar 14 14:20:07 2004 @@ -109,17 +109,6 @@ #include -/* - * Temporary debugging check to catch old code using - * unmapped ISA addresses. Will be removed in 2.4. - */ -#ifdef CONFIG_IO_DEBUG - extern void *__io_virt_debug(unsigned long x, const char *file, int line); - #define __io_virt(x) __io_virt_debug((unsigned long)(x), __FILE__, __LINE__) -#else - #define __io_virt(x) ((void *)(x)) -#endif - #ifndef __i386__ /* * Change virtual addresses to physical addresses and vv. @@ -184,10 +173,10 @@ * memory location directly. */ -#define readb(addr) (*(volatile unsigned char *) __io_virt(addr)) -#define readw(addr) (*(volatile unsigned short *) __io_virt(addr)) -#define readl(addr) (*(volatile unsigned int *) __io_virt(addr)) -#define readq(addr) (*(volatile unsigned long *) __io_virt(addr)) +#define readb(addr) (*(volatile unsigned char *) (addr)) +#define readw(addr) (*(volatile unsigned short *) (addr)) +#define readl(addr) (*(volatile unsigned int *) (addr)) +#define readq(addr) (*(volatile unsigned long *) (addr)) #define readb_relaxed(a) readb(a) #define readw_relaxed(a) readw(a) #define readl_relaxed(a) readl(a) @@ -197,10 +186,10 @@ #define __raw_readl readl #define __raw_readq readq -#define writeb(b,addr) (*(volatile unsigned char *) __io_virt(addr) = (b)) -#define writew(b,addr) (*(volatile unsigned short *) __io_virt(addr) = (b)) -#define writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b)) -#define writeq(b,addr) (*(volatile unsigned long *) __io_virt(addr) = (b)) +#define writeb(b,addr) (*(volatile unsigned char *) (addr) = (b)) +#define writew(b,addr) (*(volatile unsigned short *) (addr) = (b)) +#define writel(b,addr) (*(volatile unsigned int *) (addr) = (b)) +#define writeq(b,addr) (*(volatile unsigned long *) (addr) = (b)) #define __raw_writeb writeb #define __raw_writew writew #define __raw_writel writel @@ -208,7 +197,7 @@ void *memcpy_fromio(void*,const void*,unsigned); void *memcpy_toio(void*,const void*,unsigned); -#define memset_io(a,b,c) memset(__io_virt(a),(b),(c)) +#define memset_io(a,b,c) memset((void *)(a),(b),(c)) /* * ISA space is 'always mapped' on a typical x86 system, no need to @@ -235,8 +224,8 @@ * Again, x86-64 does not require mem IO specific function. */ -#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),__io_virt(b),(c),(d)) -#define isa_eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),__io_virt(__ISA_IO_base + (b)),(c),(d)) +#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void *)(b),(c),(d)) +#define isa_eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void *)(__ISA_IO_base + (b)),(c),(d)) /** * check_signature - find BIOS signatures diff -Nru a/include/asm-x86_64/msr.h b/include/asm-x86_64/msr.h --- a/include/asm-x86_64/msr.h Sun Mar 14 14:20:08 2004 +++ b/include/asm-x86_64/msr.h Sun Mar 14 14:20:08 2004 @@ -156,6 +156,10 @@ #define MSR_MTRRcap 0x0fe #define MSR_IA32_BBL_CR_CTL 0x119 +#define MSR_IA32_SYSENTER_CS 0x174 +#define MSR_IA32_SYSENTER_ESP 0x175 +#define MSR_IA32_SYSENTER_EIP 0x176 + #define MSR_IA32_MCG_CAP 0x179 #define MSR_IA32_MCG_STATUS 0x17a #define MSR_IA32_MCG_CTL 0x17b diff -Nru a/include/asm-x86_64/page.h b/include/asm-x86_64/page.h --- a/include/asm-x86_64/page.h Sun Mar 14 14:20:06 2004 +++ b/include/asm-x86_64/page.h Sun Mar 14 14:20:06 2004 @@ -137,6 +137,13 @@ #define VM_STACK_DEFAULT_FLAGS \ (test_thread_flag(TIF_IA32) ? vm_stack_flags32 : vm_stack_flags) +#define CONFIG_ARCH_GATE_AREA 1 + +#ifndef __ASSEMBLY__ +struct task_struct; +struct vm_area_struct *get_gate_vma(struct task_struct *tsk); +int in_gate_area(struct task_struct *task, unsigned long addr); +#endif #endif /* __KERNEL__ */ diff -Nru a/include/asm-x86_64/pci.h b/include/asm-x86_64/pci.h --- a/include/asm-x86_64/pci.h Sun Mar 14 14:20:07 2004 +++ b/include/asm-x86_64/pci.h Sun Mar 14 14:20:07 2004 @@ -78,10 +78,18 @@ int dir); extern void swiotlb_unmap_single (struct device *hwdev, dma_addr_t dev_addr, size_t size, int dir); -extern void swiotlb_sync_single (struct device *hwdev, dma_addr_t dev_addr, - size_t size, int dir); -extern void swiotlb_sync_sg (struct device *hwdev, struct scatterlist *sg, int nelems, - int dir); +extern void swiotlb_sync_single_for_cpu (struct device *hwdev, + dma_addr_t dev_addr, + size_t size, int dir); +extern void swiotlb_sync_single_for_device (struct device *hwdev, + dma_addr_t dev_addr, + size_t size, int dir); +extern void swiotlb_sync_sg_for_cpu (struct device *hwdev, + struct scatterlist *sg, int nelems, + int dir); +extern void swiotlb_sync_sg_for_device (struct device *hwdev, + struct scatterlist *sg, int nelems, + int dir); extern int swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, int nents, int direction); extern void swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg, @@ -95,7 +103,7 @@ * The 32-bit bus address to use is returned. * * Once the device is given the dma address, the device owns this memory - * until either pci_unmap_single or pci_dma_sync_single is performed. + * until either pci_unmap_single or pci_dma_sync_single_for_cpu is performed. */ extern dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction); @@ -125,29 +133,56 @@ #define pci_unmap_len_set(PTR, LEN_NAME, VAL) \ (((PTR)->LEN_NAME) = (VAL)) -static inline void pci_dma_sync_single(struct pci_dev *hwdev, - dma_addr_t dma_handle, - size_t size, int direction) +static inline void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, + dma_addr_t dma_handle, + size_t size, int direction) { BUG_ON(direction == PCI_DMA_NONE); #ifdef CONFIG_SWIOTLB if (swiotlb) - return swiotlb_sync_single(&hwdev->dev,dma_handle,size,direction); + return swiotlb_sync_single_for_cpu(&hwdev->dev,dma_handle,size,direction); #endif flush_write_buffers(); } -static inline void pci_dma_sync_sg(struct pci_dev *hwdev, - struct scatterlist *sg, - int nelems, int direction) +static inline void pci_dma_sync_single_for_device(struct pci_dev *hwdev, + dma_addr_t dma_handle, + size_t size, int direction) +{ + BUG_ON(direction == PCI_DMA_NONE); + +#ifdef CONFIG_SWIOTLB + if (swiotlb) + return swiotlb_sync_single_for_device(&hwdev->dev,dma_handle,size,direction); +#endif + + flush_write_buffers(); +} + +static inline void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, + struct scatterlist *sg, + int nelems, int direction) +{ + BUG_ON(direction == PCI_DMA_NONE); + +#ifdef CONFIG_SWIOTLB + if (swiotlb) + return swiotlb_sync_sg_for_cpu(&hwdev->dev,sg,nelems,direction); +#endif + flush_write_buffers(); +} + +static inline void pci_dma_sync_sg_for_device(struct pci_dev *hwdev, + struct scatterlist *sg, + int nelems, int direction) { BUG_ON(direction == PCI_DMA_NONE); #ifdef CONFIG_SWIOTLB if (swiotlb) - return swiotlb_sync_sg(&hwdev->dev,sg,nelems,direction); + return swiotlb_sync_sg_for_device(&hwdev->dev,sg,nelems,direction); #endif flush_write_buffers(); } @@ -218,12 +253,21 @@ * If you perform a pci_map_single() but wish to interrogate the * buffer using the cpu, yet do not wish to teardown the PCI dma * mapping, you must call this function before doing so. At the - * next point you give the PCI dma address back to the card, the + * next point you give the PCI dma address back to the card, you + * must first perform a pci_dma_sync_for_device, and then the * device again owns the buffer. */ -static inline void pci_dma_sync_single(struct pci_dev *hwdev, - dma_addr_t dma_handle, - size_t size, int direction) +static inline void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, + dma_addr_t dma_handle, + size_t size, int direction) +{ + if (direction == PCI_DMA_NONE) + out_of_line_bug(); +} + +static inline void pci_dma_sync_single_for_device(struct pci_dev *hwdev, + dma_addr_t dma_handle, + size_t size, int direction) { if (direction == PCI_DMA_NONE) out_of_line_bug(); @@ -233,12 +277,20 @@ /* Make physical memory consistent for a set of streaming * mode DMA translations after a transfer. * - * The same as pci_dma_sync_single but for a scatter-gather list, + * The same as pci_dma_sync_single_* but for a scatter-gather list, * same rules and usage. */ -static inline void pci_dma_sync_sg(struct pci_dev *hwdev, - struct scatterlist *sg, - int nelems, int direction) +static inline void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, + struct scatterlist *sg, + int nelems, int direction) +{ + if (direction == PCI_DMA_NONE) + out_of_line_bug(); +} + +static inline void pci_dma_sync_sg_for_device(struct pci_dev *hwdev, + struct scatterlist *sg, + int nelems, int direction) { if (direction == PCI_DMA_NONE) out_of_line_bug(); @@ -264,27 +316,32 @@ */ extern int pci_dma_supported(struct pci_dev *hwdev, u64 mask); -static __inline__ dma64_addr_t +static inline dma64_addr_t pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page, unsigned long offset, int direction) { return ((dma64_addr_t) page_to_phys(page) + (dma64_addr_t) offset); } -static __inline__ struct page * +static inline struct page * pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr) { return virt_to_page(__va(dma_addr)); } -static __inline__ unsigned long +static inline unsigned long pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr) { return (dma_addr & ~PAGE_MASK); } -static __inline__ void -pci_dac_dma_sync_single(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction) +static inline void +pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction) +{ +} + +static inline void +pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr, size_t len, int direction) { flush_write_buffers(); } diff -Nru a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h --- a/include/asm-x86_64/processor.h Sun Mar 14 14:20:08 2004 +++ b/include/asm-x86_64/processor.h Sun Mar 14 14:20:08 2004 @@ -173,7 +173,7 @@ * space during mmap's. */ #define IA32_PAGE_OFFSET ((current->personality & ADDR_LIMIT_3GB) ? 0xc0000000 : 0xFFFFe000) -#define TASK_UNMAPPED_32 (PAGE_ALIGN(0xc5000000)) +#define TASK_UNMAPPED_32 PAGE_ALIGN(IA32_PAGE_OFFSET/3) #define TASK_UNMAPPED_64 PAGE_ALIGN(TASK_SIZE/3) #define TASK_UNMAPPED_BASE \ (test_thread_flag(TIF_IA32) ? TASK_UNMAPPED_32 : TASK_UNMAPPED_64) @@ -262,7 +262,9 @@ #define STACKFAULT_STACK 1 #define DOUBLEFAULT_STACK 2 #define NMI_STACK 3 -#define N_EXCEPTION_STACKS 3 /* hw limit: 7 */ +#define DEBUG_STACK 4 +#define MCE_STACK 5 +#define N_EXCEPTION_STACKS 5 /* hw limit: 7 */ #define EXCEPTION_STKSZ (PAGE_SIZE << EXCEPTION_STACK_ORDER) #define EXCEPTION_STACK_ORDER 0 @@ -450,5 +452,7 @@ asm("andq %%rsp,%0; ":"=r" (ti) : "0" (CURRENT_MASK)); \ ti->task; \ }) + +#define cache_line_size() (boot_cpu_data.x86_clflush_size) #endif /* __ASM_X86_64_PROCESSOR_H */ diff -Nru a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h --- a/include/asm-x86_64/proto.h Sun Mar 14 14:20:08 2004 +++ b/include/asm-x86_64/proto.h Sun Mar 14 14:20:08 2004 @@ -21,6 +21,7 @@ extern void ia32_syscall(void); extern void ia32_cstar_target(void); +extern void ia32_sysenter_target(void); extern void calibrate_delay(void); extern void cpu_idle(void); @@ -37,6 +38,8 @@ extern int setup_early_printk(char *); extern void early_printk(const char *fmt, ...) __attribute__((format(printf,1,2))); +extern void early_identify_cpu(struct cpuinfo_x86 *c); + extern int k8_scan_nodes(unsigned long start, unsigned long end); extern int numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn); @@ -68,6 +71,7 @@ extern int map_syscall32(struct mm_struct *mm, unsigned long address); extern char *syscall32_page; +extern void syscall32_cpu_init(void); extern void setup_node_bootmem(int nodeid, unsigned long start, unsigned long end); diff -Nru a/include/asm-x86_64/smp.h b/include/asm-x86_64/smp.h --- a/include/asm-x86_64/smp.h Sun Mar 14 14:20:05 2004 +++ b/include/asm-x86_64/smp.h Sun Mar 14 14:20:05 2004 @@ -47,7 +47,7 @@ extern void (*mtrr_hook) (void); extern void zap_low_mappings(void); void smp_stop_cpu(void); -extern int cpu_sibling_map[]; +extern char cpu_sibling_map[]; #define SMP_TRAMPOLINE_BASE 0x6000 @@ -74,7 +74,15 @@ return GET_APIC_ID(*(unsigned int *)(APIC_BASE+APIC_ID)); } -#define safe_smp_processor_id() (disable_apic ? 0 : hard_smp_processor_id()) +/* + * Some lowlevel functions might want to know about + * the real APIC ID <-> CPU # mapping. + * AK: why is this volatile? + */ +extern volatile char x86_apicid_to_cpu[NR_CPUS]; +extern volatile char x86_cpu_to_apicid[NR_CPUS]; + +#define safe_smp_processor_id() (disable_apic ? 0 : x86_apicid_to_cpu[hard_smp_processor_id()]) #define cpu_online(cpu) cpu_isset(cpu, cpu_online_map) #endif /* !ASSEMBLY */ diff -Nru a/include/asm-x86_64/system.h b/include/asm-x86_64/system.h --- a/include/asm-x86_64/system.h Sun Mar 14 14:20:08 2004 +++ b/include/asm-x86_64/system.h Sun Mar 14 14:20:08 2004 @@ -276,13 +276,6 @@ ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\ (unsigned long)(n),sizeof(*(ptr)))) -static inline __u32 cmpxchg4_locked(__u32 *ptr, __u32 old, __u32 new) -{ - asm volatile("lock ; cmpxchgl %k1,%2" : - "=r" (new) : "0" (old), "m" (*(__u32 *)ptr) : "memory"); - return new; -} - #ifdef CONFIG_SMP #define smp_mb() mb() #define smp_rmb() rmb() diff -Nru a/include/asm-x86_64/thread_info.h b/include/asm-x86_64/thread_info.h --- a/include/asm-x86_64/thread_info.h Sun Mar 14 14:20:07 2004 +++ b/include/asm-x86_64/thread_info.h Sun Mar 14 14:20:07 2004 @@ -82,7 +82,6 @@ #else /* !__ASSEMBLY__ */ /* how to get the thread information struct from ASM */ -/* only works on the process stack. otherwise get it via the PDA. */ #define GET_THREAD_INFO(reg) \ movq %gs:pda_kernelstack,reg ; \ subq $(THREAD_SIZE-PDA_STACKOFFSET),reg @@ -118,8 +117,10 @@ #define _TIF_FORK (1< /* not really needed, later.. */ #include +/* + * _OLD will use PIO transfer on atapi devices, _BPC_* will use DMA + */ +#define CDDA_OLD 0 /* old style */ +#define CDDA_BPC_SINGLE 1 /* single frame block pc */ +#define CDDA_BPC_FULL 2 /* multi frame block pc */ + /* Uniform cdrom data structures for cdrom.c */ struct cdrom_device_info { struct cdrom_device_ops *ops; /* link to device_ops */ struct cdrom_device_info *next; /* next device_info for this major */ + struct gendisk *disk; /* matching block layer disk */ void *handle; /* driver-dependent data */ /* specifications */ int mask; /* mask of capability: disables them */ @@ -894,6 +902,8 @@ /* per-device flags */ __u8 sanyo_slot : 2; /* Sanyo 3 CD changer support */ __u8 reserved : 6; /* not used yet */ + int cdda_method; /* see flags */ + __u8 last_sense; int for_data; int (*exit)(struct cdrom_device_info *); int mrw_mode_page; diff -Nru a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h --- a/include/linux/compat_ioctl.h Sun Mar 14 14:20:08 2004 +++ b/include/linux/compat_ioctl.h Sun Mar 14 14:20:08 2004 @@ -134,6 +134,7 @@ COMPATIBLE_IOCTL(DM_TABLE_CLEAR) COMPATIBLE_IOCTL(DM_TABLE_DEPS) COMPATIBLE_IOCTL(DM_TABLE_STATUS) +COMPATIBLE_IOCTL(DM_LIST_VERSIONS) /* Big K */ COMPATIBLE_IOCTL(PIO_FONT) COMPATIBLE_IOCTL(GIO_FONT) diff -Nru a/include/linux/compiler.h b/include/linux/compiler.h --- a/include/linux/compiler.h Sun Mar 14 14:20:07 2004 +++ b/include/linux/compiler.h Sun Mar 14 14:20:07 2004 @@ -39,6 +39,20 @@ #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) +/* Optimization barrier */ +#ifndef barrier +# define barrier() __memory_barrier() +#endif + +#ifndef RELOC_HIDE +# define RELOC_HIDE(ptr, off) \ + ({ unsigned long __ptr; \ + __ptr = (unsigned long) (ptr); \ + (typeof(ptr)) (__ptr + (off)); }) +#endif + +#endif /* __KERNEL__ */ + /* * Allow us to mark functions as 'deprecated' and have gcc emit a nice * warning for each use, in hopes of speeding the functions removal. @@ -99,19 +113,5 @@ #ifndef noinline #define noinline #endif - -/* Optimization barrier */ -#ifndef barrier -# define barrier() __memory_barrier() -#endif - -#ifndef RELOC_HIDE -# define RELOC_HIDE(ptr, off) \ - ({ unsigned long __ptr; \ - __ptr = (unsigned long) (ptr); \ - (typeof(ptr)) (__ptr + (off)); }) -#endif - -#endif /* __KERNEL__ */ #endif /* __LINUX_COMPILER_H */ diff -Nru a/include/linux/device-mapper.h b/include/linux/device-mapper.h --- a/include/linux/device-mapper.h Sun Mar 14 14:20:07 2004 +++ b/include/linux/device-mapper.h Sun Mar 14 14:20:07 2004 @@ -13,6 +13,11 @@ typedef enum { STATUSTYPE_INFO, STATUSTYPE_TABLE } status_type_t; +union map_info { + void *ptr; + unsigned long long ll; +}; + /* * In the constructor the target parameter will already have the * table, type, begin and len fields filled in. @@ -32,7 +37,19 @@ * = 0: The target will handle the io by resubmitting it later * > 0: simple remap complete */ -typedef int (*dm_map_fn) (struct dm_target *ti, struct bio *bio); +typedef int (*dm_map_fn) (struct dm_target *ti, struct bio *bio, + union map_info *map_context); + +/* + * Returns: + * < 0 : error (currently ignored) + * 0 : ended successfully + * 1 : for some reason the io has still not completed (eg, + * multipath target might want to requeue a failed io). + */ +typedef int (*dm_endio_fn) (struct dm_target *ti, + struct bio *bio, int error, + union map_info *map_context); typedef void (*dm_suspend_fn) (struct dm_target *ti); typedef void (*dm_resume_fn) (struct dm_target *ti); @@ -57,9 +74,11 @@ struct target_type { const char *name; struct module *module; + unsigned version[3]; dm_ctr_fn ctr; dm_dtr_fn dtr; dm_map_fn map; + dm_endio_fn end_io; dm_suspend_fn suspend; dm_resume_fn resume; dm_status_fn status; @@ -86,7 +105,7 @@ sector_t split_io; /* - * These are automaticall filled in by + * These are automatically filled in by * dm_table_get_device. */ struct io_restrictions limits; diff -Nru a/include/linux/device.h b/include/linux/device.h --- a/include/linux/device.h Sun Mar 14 14:20:08 2004 +++ b/include/linux/device.h Sun Mar 14 14:20:08 2004 @@ -285,6 +285,12 @@ detached from its driver. */ u64 *dma_mask; /* dma mask (if dma'able device) */ + u64 coherent_dma_mask;/* Like dma_mask, but for + alloc_coherent mappings as + not all hardware supports + 64 bit addresses for consistent + allocations such descriptors. */ + struct list_head dma_pools; /* dma pools (if dma'ble) */ void (*release)(struct device * dev); diff -Nru a/include/linux/dm-ioctl.h b/include/linux/dm-ioctl.h --- a/include/linux/dm-ioctl.h Sun Mar 14 14:20:05 2004 +++ b/include/linux/dm-ioctl.h Sun Mar 14 14:20:05 2004 @@ -163,6 +163,16 @@ }; /* + * Used to retrieve the target versions + */ +struct dm_target_versions { + uint32_t next; + uint32_t version[3]; + + char name[0]; +}; + +/* * If you change this make sure you make the corresponding change * to dm-ioctl.c:lookup_ioctl() */ @@ -185,6 +195,9 @@ DM_TABLE_CLEAR_CMD, DM_TABLE_DEPS_CMD, DM_TABLE_STATUS_CMD, + + /* Added later */ + DM_LIST_VERSIONS_CMD, }; #define DM_IOCTL 0xfd @@ -205,10 +218,12 @@ #define DM_TABLE_DEPS _IOWR(DM_IOCTL, DM_TABLE_DEPS_CMD, struct dm_ioctl) #define DM_TABLE_STATUS _IOWR(DM_IOCTL, DM_TABLE_STATUS_CMD, struct dm_ioctl) +#define DM_LIST_VERSIONS _IOWR(DM_IOCTL, DM_LIST_VERSIONS_CMD, struct dm_ioctl) + #define DM_VERSION_MAJOR 4 -#define DM_VERSION_MINOR 0 +#define DM_VERSION_MINOR 1 #define DM_VERSION_PATCHLEVEL 0 -#define DM_VERSION_EXTRA "-ioctl (2003-06-04)" +#define DM_VERSION_EXTRA "-ioctl (2003-12-10)" /* Status bits */ #define DM_READONLY_FLAG (1 << 0) /* In/Out */ diff -Nru a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h --- a/include/linux/dma-mapping.h Sun Mar 14 14:20:08 2004 +++ b/include/linux/dma-mapping.h Sun Mar 14 14:20:08 2004 @@ -12,6 +12,10 @@ #include +/* Backwards compat, remove in 2.7.x */ +#define dma_sync_single dma_sync_single_for_cpu +#define dma_sync_sg dma_sync_sg_for_cpu + #endif diff -Nru a/include/linux/fb.h b/include/linux/fb.h --- a/include/linux/fb.h Sun Mar 14 14:20:06 2004 +++ b/include/linux/fb.h Sun Mar 14 14:20:06 2004 @@ -236,15 +236,71 @@ #define VESA_HSYNC_SUSPEND 2 #define VESA_POWERDOWN 3 +/* Definitions below are used in the parsed monitor specs */ +#define FB_DPMS_ACTIVE_OFF 1 +#define FB_DPMS_SUSPEND 2 +#define FB_DPMS_STANDBY 4 + +#define FB_DISP_DDI 1 +#define FB_DISP_ANA_700_300 2 +#define FB_DISP_ANA_714_286 4 +#define FB_DISP_ANA_1000_400 8 +#define FB_DISP_ANA_700_000 16 + +#define FB_DISP_MONO 32 +#define FB_DISP_RGB 64 +#define FB_DISP_MULTI 128 +#define FB_DISP_UNKNOWN 256 + +#define FB_SIGNAL_NONE 0 +#define FB_SIGNAL_BLANK_BLANK 1 +#define FB_SIGNAL_SEPARATE 2 +#define FB_SIGNAL_COMPOSITE 4 +#define FB_SIGNAL_SYNC_ON_GREEN 8 +#define FB_SIGNAL_SERRATION_ON 16 + +#define FB_MISC_PRIM_COLOR 1 +#define FB_MISC_1ST_DETAIL 2 /* First Detailed Timing is preferred */ + +struct fb_chroma { + __u32 redx; /* in fraction of 1024 */ + __u32 greenx; + __u32 bluex; + __u32 whitex; + __u32 redy; + __u32 greeny; + __u32 bluey; + __u32 whitey; +}; + struct fb_monspecs { + struct fb_chroma chroma; + struct fb_videomode *modedb; /* mode database */ + __u8 manufacturer[4]; /* Manufacturer */ + __u8 monitor[14]; /* Monitor String */ + __u8 serial_no[14]; /* Serial Number */ + __u8 ascii[14]; /* ? */ + __u32 modedb_len; /* mode database length */ + __u32 model; /* Monitor Model */ + __u32 serial; /* Serial Number - Integer */ + __u32 year; /* Year manufactured */ + __u32 week; /* Week Manufactured */ __u32 hfmin; /* hfreq lower limit (Hz) */ - __u32 hfmax; /* hfreq upper limit (Hz) */ + __u32 hfmax; /* hfreq upper limit (Hz) */ + __u32 dclkmin; /* pixelclock lower limit (Hz) */ + __u32 dclkmax; /* pixelclock upper limit (Hz) */ + __u16 input; /* display type - see FB_DISP_* */ + __u16 dpms; /* DPMS support - see FB_DPMS_ */ + __u16 signal; /* Signal Type - see FB_SIGNAL_* */ __u16 vfmin; /* vfreq lower limit (Hz) */ __u16 vfmax; /* vfreq upper limit (Hz) */ - __u32 dclkmin; /* pixelclock lower limit (Hz) */ - __u32 dclkmax; /* pixelclock upper limit (Hz) */ - unsigned gtf : 1; /* supports GTF */ - unsigned dpms : 1; /* supports DPMS */ + __u16 gamma; /* Gamma - in fractions of 100 */ + __u16 gtf : 1; /* supports GTF */ + __u16 misc; /* Misc flags - see FB_MISC_* */ + __u8 version; /* EDID version... */ + __u8 revision; /* ...and revision */ + __u8 max_x; /* Maximum horizontal size (cm) */ + __u8 max_y; /* Maximum vertical size (cm) */ }; #define FB_VBLANK_VBLANKING 0x001 /* currently in a vertical blank */ @@ -379,14 +435,19 @@ u32 scan_align; /* alignment per scanline */ u32 access_align; /* alignment per read/write */ u32 flags; /* see FB_PIXMAP_* */ - /* access methods */ + /* access methods */ void (*outbuf)(struct fb_info *info, u8 *addr, u8 *src, unsigned int size); u8 (*inbuf) (struct fb_info *info, u8 *addr); }; - /* - * Frame buffer operations - */ + +/* + * Frame buffer operations + * + * LOCKING NOTE: those functions must _ALL_ be called with the console + * semaphore held, this is the only suitable locking mecanism we have + * in 2.6. Some may be called at interrupt time at this point though. + */ struct fb_ops { /* open/release and usage marking */ @@ -394,13 +455,16 @@ int (*fb_open)(struct fb_info *info, int user); int (*fb_release)(struct fb_info *info, int user); - /* For framebuffers with strange non linear layouts */ + /* For framebuffers with strange non linear layouts or that do not + * work with normal memory mapped access + */ ssize_t (*fb_read)(struct file *file, char *buf, size_t count, loff_t *ppos); ssize_t (*fb_write)(struct file *file, const char *buf, size_t count, loff_t *ppos); /* checks var and eventually tweaks it to something supported, * DO NOT MODIFY PAR */ int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info); + /* set the video mode according to info->var */ int (*fb_set_par)(struct fb_info *info); @@ -441,15 +505,14 @@ struct fb_info { int node; int flags; - int open; /* Has this been open already ? */ #define FBINFO_FLAG_MODULE 1 /* Low-level driver is a module */ struct fb_var_screeninfo var; /* Current var */ struct fb_fix_screeninfo fix; /* Current fix */ struct fb_monspecs monspecs; /* Current Monitor specs */ struct fb_cursor cursor; /* Current cursor */ struct work_struct queue; /* Framebuffer event queue */ - struct fb_pixmap pixmap; /* Image Hardware Mapper */ - struct fb_pixmap sprite; /* Cursor hardware Mapper */ + struct fb_pixmap pixmap; /* Image hardware mapper */ + struct fb_pixmap sprite; /* Cursor hardware mapper */ struct fb_cmap cmap; /* Current cmap */ struct fb_ops *fbops; char *screen_base; /* Virtual address */ @@ -459,6 +522,7 @@ #define FBINFO_STATE_RUNNING 0 #define FBINFO_STATE_SUSPENDED 1 u32 state; /* Hardware state i.e suspend */ + /* From here on everything is device dependent */ void *par; }; @@ -469,12 +533,14 @@ #define FBINFO_FLAG_DEFAULT 0 #endif +// This will go away #if defined(__sparc__) /* We map all of our framebuffers such that big-endian accesses * are what we want, so the following is sufficient. */ +// This will go away #define fb_readb sbus_readb #define fb_readw sbus_readw #define fb_readl sbus_readl @@ -485,7 +551,7 @@ #define fb_writeq sbus_writeq #define fb_memset sbus_memset_io -#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || defined(__sh__) +#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || defined(__hppa__) || defined(__sh__) || defined(__powerpc__) #define fb_readb __raw_readb #define fb_readw __raw_readw @@ -546,24 +612,32 @@ extern void framebuffer_release(struct fb_info *info); /* drivers/video/fbmon.c */ -#define FB_MAXTIMINGS 0 -#define FB_VSYNCTIMINGS 1 -#define FB_HSYNCTIMINGS 2 -#define FB_DCLKTIMINGS 3 -#define FB_IGNOREMON 0x100 +#define FB_MAXTIMINGS 0 +#define FB_VSYNCTIMINGS 1 +#define FB_HSYNCTIMINGS 2 +#define FB_DCLKTIMINGS 3 +#define FB_IGNOREMON 0x100 + +#define FB_MODE_IS_UNKNOWN 0 +#define FB_MODE_IS_DETAILED 1 +#define FB_MODE_IS_STANDARD 2 +#define FB_MODE_IS_VESA 4 +#define FB_MODE_IS_CALCULATED 8 +#define FB_MODE_IS_FIRST 16 extern int fbmon_valid_timings(u_int pixclock, u_int htotal, u_int vtotal, const struct fb_info *fb_info); extern int fbmon_dpms(const struct fb_info *fb_info); extern int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_info *info); -extern int fb_validate_mode(struct fb_var_screeninfo *var, +extern int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info); -extern int parse_edid(unsigned char *edid, struct fb_var_screeninfo *var); +extern int fb_parse_edid(unsigned char *edid, struct fb_var_screeninfo *var); +extern int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs); +extern void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs); extern int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs); extern struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize); extern void fb_destroy_modedb(struct fb_videomode *modedb); -extern void show_edid(unsigned char *edid); /* drivers/video/modedb.c */ #define VESA_MODEDB_SIZE 34 @@ -578,58 +652,28 @@ extern void fb_invert_cmaps(void); struct fb_videomode { - const char *name; /* optional */ - u32 refresh; /* optional */ - u32 xres; - u32 yres; - u32 pixclock; - u32 left_margin; - u32 right_margin; - u32 upper_margin; - u32 lower_margin; - u32 hsync_len; - u32 vsync_len; - u32 sync; - u32 vmode; -}; - -#ifdef MODULE -static inline int fb_find_mode(struct fb_var_screeninfo *var, - struct fb_info *info, - const char *mode_option, - const struct fb_videomode *db, - unsigned int dbsize, - const struct fb_videomode *default_mode, - unsigned int default_bpp) -{ - extern int __fb_try_mode(struct fb_var_screeninfo *var, - struct fb_info *info, - const struct fb_videomode *mode, - unsigned int bpp); - /* - * FIXME: How to make the compiler optimize vga640x400 away if - * default_mode is non-NULL? - */ - static const struct fb_videomode vga640x400 = { - /* 640x400 @ 70 Hz, 31.5 kHz hsync */ - NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2, - 0, FB_VMODE_NONINTERLACED - }; - if (!default_mode) - default_mode = &vga640x400; - if (!default_bpp) - default_bpp = 8; - return __fb_try_mode(var, info, default_mode, default_bpp); -} -#else -extern int __init fb_find_mode(struct fb_var_screeninfo *var, - struct fb_info *info, - const char *mode_option, - const struct fb_videomode *db, - unsigned int dbsize, - const struct fb_videomode *default_mode, - unsigned int default_bpp); -#endif + const char *name; /* optional */ + u32 refresh; /* optional */ + u32 xres; + u32 yres; + u32 pixclock; + u32 left_margin; + u32 right_margin; + u32 upper_margin; + u32 lower_margin; + u32 hsync_len; + u32 vsync_len; + u32 sync; + u32 vmode; + u32 flag; +}; + +extern int fb_find_mode(struct fb_var_screeninfo *var, + struct fb_info *info, const char *mode_option, + const struct fb_videomode *db, + unsigned int dbsize, + const struct fb_videomode *default_mode, + unsigned int default_bpp); #endif /* __KERNEL__ */ diff -Nru a/include/linux/fs.h b/include/linux/fs.h --- a/include/linux/fs.h Sun Mar 14 14:20:06 2004 +++ b/include/linux/fs.h Sun Mar 14 14:20:06 2004 @@ -89,6 +89,7 @@ /* public flags for file_system_type */ #define FS_REQUIRES_DEV 1 +#define FS_BINARY_MOUNTDATA 2 #define FS_REVAL_DOT 16384 /* Check the paths ".", ".." for staleness */ #define FS_ODD_RENAME 32768 /* Temporary stuff; will go away as soon * as nfs_rename() will be cleaned up @@ -137,6 +138,7 @@ #define S_DEAD 32 /* removed, but still open directory */ #define S_NOQUOTA 64 /* Inode is not counted to quota */ #define S_DIRSYNC 128 /* Directory modifications are synchronous */ +#define S_NOCMTIME 256 /* Do not update file c/mtime */ /* * Note that nosuid etc flags are inode-specific: setting some file-system @@ -170,6 +172,7 @@ #define IS_ONE_SECOND(inode) __IS_FLG(inode, MS_ONE_SECOND) #define IS_DEADDIR(inode) ((inode)->i_flags & S_DEAD) +#define IS_NOCMTIME(inode) ((inode)->i_flags & S_NOCMTIME) /* the read-only stuff doesn't really belong here, but any other place is probably as bad and I don't want to create yet another include file. */ @@ -507,6 +510,8 @@ unsigned long prev_page; /* Cache last read() position */ unsigned long ahead_start; /* Ahead window */ unsigned long ahead_size; + unsigned long serial_cnt; /* measure of sequentiality */ + unsigned long average; /* another measure of sequentiality */ unsigned long ra_pages; /* Maximum readahead window */ unsigned long mmap_hit; /* Cache hit stat for mmap accesses */ unsigned long mmap_miss; /* Cache miss stat for mmap accesses */ @@ -1133,6 +1138,7 @@ extern int register_blkdev(unsigned int, const char *); extern int unregister_blkdev(unsigned int, const char *); extern struct block_device *bdget(dev_t); +extern void bd_set_size(struct block_device *, loff_t size); extern void bd_forget(struct inode *inode); extern void bdput(struct block_device *); extern int blkdev_open(struct inode *, struct file *); diff -Nru a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h --- a/include/linux/kernel_stat.h Sun Mar 14 14:20:08 2004 +++ b/include/linux/kernel_stat.h Sun Mar 14 14:20:08 2004 @@ -14,13 +14,13 @@ */ struct cpu_usage_stat { - unsigned int user; - unsigned int nice; - unsigned int system; - unsigned int softirq; - unsigned int irq; - unsigned int idle; - unsigned int iowait; + u64 user; + u64 nice; + u64 system; + u64 softirq; + u64 irq; + u64 idle; + u64 iowait; }; struct kernel_stat { @@ -34,7 +34,7 @@ /* Must have preemption disabled for this to be meaningful. */ #define kstat_this_cpu __get_cpu_var(kstat) -extern unsigned long nr_context_switches(void); +extern unsigned long long nr_context_switches(void); /* * Number of interrupts per specific IRQ source, since bootup diff -Nru a/include/linux/libata.h b/include/linux/libata.h --- a/include/linux/libata.h Sun Mar 14 14:20:06 2004 +++ b/include/linux/libata.h Sun Mar 14 14:20:06 2004 @@ -183,12 +183,15 @@ unsigned long cmd_addr; unsigned long data_addr; unsigned long error_addr; + unsigned long feature_addr; unsigned long nsect_addr; unsigned long lbal_addr; unsigned long lbam_addr; unsigned long lbah_addr; unsigned long device_addr; - unsigned long cmdstat_addr; + unsigned long status_addr; + unsigned long command_addr; + unsigned long altstatus_addr; unsigned long ctl_addr; unsigned long bmdma_addr; unsigned long scr_addr; @@ -408,6 +411,7 @@ extern int ata_scsi_error(struct Scsi_Host *host); extern int ata_scsi_release(struct Scsi_Host *host); extern int ata_scsi_slave_config(struct scsi_device *sdev); +extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc); /* * Default driver ops implementations */ @@ -465,8 +469,8 @@ static inline u8 ata_altstatus(struct ata_port *ap) { if (ap->flags & ATA_FLAG_MMIO) - return readb(ap->ioaddr.ctl_addr); - return inb(ap->ioaddr.ctl_addr); + return readb(ap->ioaddr.altstatus_addr); + return inb(ap->ioaddr.altstatus_addr); } static inline void ata_pause(struct ata_port *ap) @@ -494,7 +498,7 @@ u8 status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); if (status & (ATA_BUSY | ATA_DRQ)) { - unsigned long l = ap->ioaddr.cmdstat_addr; + unsigned long l = ap->ioaddr.status_addr; printk(KERN_WARNING "ATA: abnormal status 0x%X on port 0x%lX\n", status, l); diff -Nru a/include/linux/lockd/debug.h b/include/linux/lockd/debug.h --- a/include/linux/lockd/debug.h Sun Mar 14 14:20:08 2004 +++ b/include/linux/lockd/debug.h Sun Mar 14 14:20:08 2004 @@ -23,7 +23,7 @@ #undef ifdebug #if defined(RPC_DEBUG) && defined(LOCKD_DEBUG) -# define ifdebug(flag) if (nlm_debug & NLMDBG_##flag) +# define ifdebug(flag) if (unlikely(nlm_debug & NLMDBG_##flag)) #else # define ifdebug(flag) if (0) #endif diff -Nru a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h --- a/include/linux/lockd/lockd.h Sun Mar 14 14:20:06 2004 +++ b/include/linux/lockd/lockd.h Sun Mar 14 14:20:06 2004 @@ -165,6 +165,7 @@ unsigned long nlmsvc_retry_blocked(void); int nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *, int action); +void nlmsvc_grant_reply(struct svc_rqst *, struct nlm_cookie *, u32); /* * File handling for the server personality diff -Nru a/include/linux/loop.h b/include/linux/loop.h --- a/include/linux/loop.h Sun Mar 14 14:20:08 2004 +++ b/include/linux/loop.h Sun Mar 14 14:20:08 2004 @@ -153,5 +153,6 @@ #define LOOP_GET_STATUS 0x4C03 #define LOOP_SET_STATUS64 0x4C04 #define LOOP_GET_STATUS64 0x4C05 +#define LOOP_CHANGE_FD 0x4C06 #endif diff -Nru a/include/linux/mmzone.h b/include/linux/mmzone.h --- a/include/linux/mmzone.h Sun Mar 14 14:20:07 2004 +++ b/include/linux/mmzone.h Sun Mar 14 14:20:07 2004 @@ -76,7 +76,8 @@ spinlock_t lru_lock; struct list_head active_list; struct list_head inactive_list; - atomic_t refill_counter; + atomic_t nr_scan_active; + atomic_t nr_scan_inactive; unsigned long nr_active; unsigned long nr_inactive; int all_unreclaimable; /* All pages pinned */ @@ -286,6 +287,11 @@ static inline int is_highmem(struct zone *zone) { return (zone - zone->zone_pgdat->node_zones == ZONE_HIGHMEM); +} + +static inline int is_normal(struct zone *zone) +{ + return (zone - zone->zone_pgdat->node_zones == ZONE_NORMAL); } /* These two functions are used to setup the per zone pages min values */ diff -Nru a/include/linux/netdevice.h b/include/linux/netdevice.h --- a/include/linux/netdevice.h Sun Mar 14 14:20:08 2004 +++ b/include/linux/netdevice.h Sun Mar 14 14:20:08 2004 @@ -456,6 +456,12 @@ unsigned char *haddr); int (*neigh_setup)(struct net_device *dev, struct neigh_parms *); int (*accept_fastpath)(struct net_device *, struct dst_entry*); +#ifdef CONFIG_NETPOLL_RX + int netpoll_rx; +#endif +#ifdef CONFIG_NET_POLL_CONTROLLER + void (*poll_controller)(struct net_device *dev); +#endif /* bridge stuff */ struct net_bridge_port *br_port; @@ -540,6 +546,9 @@ extern struct net_device *dev_get_by_index(int ifindex); extern struct net_device *__dev_get_by_index(int ifindex); extern int dev_restart(struct net_device *dev); +#ifdef CONFIG_NETPOLL_TRAP +extern int netpoll_trap(void); +#endif typedef int gifconf_func_t(struct net_device * dev, char * bufptr, int len); extern int register_gifconf(unsigned int family, gifconf_func_t * gifconf); @@ -598,12 +607,20 @@ static inline void netif_wake_queue(struct net_device *dev) { +#ifdef CONFIG_NETPOLL_TRAP + if (netpoll_trap()) + return; +#endif if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state)) __netif_schedule(dev); } static inline void netif_stop_queue(struct net_device *dev) { +#ifdef CONFIG_NETPOLL_TRAP + if (netpoll_trap()) + return; +#endif set_bit(__LINK_STATE_XOFF, &dev->state); } @@ -773,6 +790,17 @@ #define netif_msg_pktdata(p) ((p)->msg_enable & NETIF_MSG_PKTDATA) #define netif_msg_hw(p) ((p)->msg_enable & NETIF_MSG_HW) #define netif_msg_wol(p) ((p)->msg_enable & NETIF_MSG_WOL) + +static inline u32 netif_msg_init(int debug_value, int default_msg_enable_bits) +{ + /* use default */ + if (debug_value < 0 || debug_value >= (sizeof(u32) * 8)) + return default_msg_enable_bits; + if (debug_value == 0) /* no output */ + return 0; + /* set low N bits */ + return (1 << debug_value) - 1; +} /* Schedule rx intr now? */ diff -Nru a/include/linux/netpoll.h b/include/linux/netpoll.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/netpoll.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,38 @@ +/* + * Common code for low-level network console, dump, and debugger code + * + * Derived from netconsole, kgdb-over-ethernet, and netdump patches + */ + +#ifndef _LINUX_NETPOLL_H +#define _LINUX_NETPOLL_H + +#include +#include +#include +#include + +struct netpoll; + +struct netpoll { + struct net_device *dev; + char dev_name[16], *name; + void (*rx_hook)(struct netpoll *, int, char *, int); + u32 local_ip, remote_ip; + u16 local_port, remote_port; + unsigned char local_mac[6], remote_mac[6]; + struct list_head rx_list; +}; + +void netpoll_poll(struct netpoll *np); +void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb); +void netpoll_send_udp(struct netpoll *np, const char *msg, int len); +int netpoll_parse_options(struct netpoll *np, char *opt); +int netpoll_setup(struct netpoll *np); +int netpoll_trap(void); +void netpoll_set_trap(int trap); +void netpoll_cleanup(struct netpoll *np); +int netpoll_rx(struct sk_buff *skb); + + +#endif diff -Nru a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h --- a/include/linux/nfs_fs.h Sun Mar 14 14:20:07 2004 +++ b/include/linux/nfs_fs.h Sun Mar 14 14:20:07 2004 @@ -99,7 +99,7 @@ /* * Various flags */ - unsigned short flags; + unsigned int flags; /* * read_cache_jiffies is when we started read-caching this inode, @@ -118,19 +118,22 @@ * * mtime != read_cache_mtime */ + unsigned long readdir_timestamp; unsigned long read_cache_jiffies; - struct timespec read_cache_ctime; - struct timespec read_cache_mtime; - __u64 read_cache_isize; unsigned long attrtimeo; unsigned long attrtimeo_timestamp; __u64 change_attr; /* v4 only */ + /* "Generation counter" for the attribute cache. This is + * bumped whenever we update the metadata on the + * server. + */ + unsigned long cache_change_attribute; /* - * Timestamp that dates the change made to read_cache_mtime. - * This is of use for dentry revalidation + * Counter indicating the number of outstanding requests that + * will cause a file data update. */ - unsigned long cache_mtime_jiffies; + atomic_t data_updates; struct nfs_access_cache cache_access; @@ -170,8 +173,9 @@ #define NFS_INO_STALE 0x0001 /* possible stale inode */ #define NFS_INO_ADVISE_RDPLUS 0x0002 /* advise readdirplus */ #define NFS_INO_REVALIDATING 0x0004 /* revalidating attrs */ -#define NFS_INO_FLUSH 0x0008 /* inode is due for flushing */ -#define NFS_INO_FAKE_ROOT 0x0080 /* root inode placeholder */ +#define NFS_INO_INVALID_ATTR 0x0008 /* cached attrs are invalid */ +#define NFS_INO_INVALID_DATA 0x0010 /* cached data is invalid */ +#define NFS_INO_INVALID_ATIME 0x0020 /* cached atime is invalid */ static inline struct nfs_inode *NFS_I(struct inode *inode) { @@ -186,15 +190,7 @@ #define NFS_ADDR(inode) (RPC_PEERADDR(NFS_CLIENT(inode))) #define NFS_COOKIEVERF(inode) (NFS_I(inode)->cookieverf) #define NFS_READTIME(inode) (NFS_I(inode)->read_cache_jiffies) -#define NFS_MTIME_UPDATE(inode) (NFS_I(inode)->cache_mtime_jiffies) -#define NFS_CACHE_CTIME(inode) (NFS_I(inode)->read_cache_ctime) -#define NFS_CACHE_MTIME(inode) (NFS_I(inode)->read_cache_mtime) -#define NFS_CACHE_ISIZE(inode) (NFS_I(inode)->read_cache_isize) #define NFS_CHANGE_ATTR(inode) (NFS_I(inode)->change_attr) -#define NFS_CACHEINV(inode) \ -do { \ - NFS_READTIME(inode) = jiffies - NFS_MAXATTRTIMEO(inode) - 1; \ -} while (0) #define NFS_ATTRTIMEO(inode) (NFS_I(inode)->attrtimeo) #define NFS_MINATTRTIMEO(inode) \ (S_ISDIR(inode->i_mode)? NFS_SERVER(inode)->acdirmin \ @@ -207,10 +203,20 @@ #define NFS_FLAGS(inode) (NFS_I(inode)->flags) #define NFS_REVALIDATING(inode) (NFS_FLAGS(inode) & NFS_INO_REVALIDATING) #define NFS_STALE(inode) (NFS_FLAGS(inode) & NFS_INO_STALE) -#define NFS_FAKE_ROOT(inode) (NFS_FLAGS(inode) & NFS_INO_FAKE_ROOT) #define NFS_FILEID(inode) (NFS_I(inode)->fileid) +static inline int nfs_caches_unstable(struct inode *inode) +{ + return atomic_read(&NFS_I(inode)->data_updates) != 0; +} + +static inline void NFS_CACHEINV(struct inode *inode) +{ + if (!nfs_caches_unstable(inode)) + NFS_FLAGS(inode) |= NFS_INO_INVALID_ATTR; +} + static inline int nfs_server_capable(struct inode *inode, int cap) { return NFS_SERVER(inode)->caps & cap; @@ -227,13 +233,37 @@ return ((loff_t)page->index) << PAGE_CACHE_SHIFT; } +/** + * nfs_save_change_attribute - Returns the inode attribute change cookie + * @inode - pointer to inode + * The "change attribute" is updated every time we finish an operation + * that will result in a metadata change on the server. + */ +static inline long nfs_save_change_attribute(struct inode *inode) +{ + return NFS_I(inode)->cache_change_attribute; +} + +/** + * nfs_verify_change_attribute - Detects NFS inode cache updates + * @inode - pointer to inode + * @chattr - previously saved change attribute + * Return "false" if metadata has been updated (or is in the process of + * being updated) since the change attribute was saved. + */ +static inline int nfs_verify_change_attribute(struct inode *inode, unsigned long chattr) +{ + return !nfs_caches_unstable(inode) + && chattr == NFS_I(inode)->cache_change_attribute; +} + /* * linux/fs/nfs/inode.c */ extern void nfs_zap_caches(struct inode *); extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *, struct nfs_fattr *); -extern int __nfs_refresh_inode(struct inode *, struct nfs_fattr *); +extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *); extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *); extern int nfs_permission(struct inode *, int, struct nameidata *); extern void nfs_set_mmcred(struct inode *, struct rpc_cred *); @@ -241,6 +271,13 @@ extern int nfs_release(struct inode *, struct file *); extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *); extern int nfs_setattr(struct dentry *, struct iattr *); +extern void nfs_begin_attr_update(struct inode *); +extern void nfs_end_attr_update(struct inode *); +extern void nfs_begin_data_update(struct inode *); +extern void nfs_end_data_update(struct inode *); + +/* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */ +extern u32 root_nfs_parse_addr(char *name); /*__init*/ /* * linux/fs/nfs/file.c @@ -309,16 +346,15 @@ * Try to write back everything synchronously (but check the * return value!) */ -extern int nfs_sync_file(struct inode *, struct file *, unsigned long, unsigned int, int); -extern int nfs_flush_file(struct inode *, struct file *, unsigned long, unsigned int, int); +extern int nfs_sync_inode(struct inode *, unsigned long, unsigned int, int); +extern int nfs_flush_inode(struct inode *, unsigned long, unsigned int, int); extern int nfs_flush_list(struct list_head *, int, int); #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) -extern int nfs_commit_file(struct inode *, struct file *, unsigned long, unsigned int, int); +extern int nfs_commit_inode(struct inode *, unsigned long, unsigned int, int); extern int nfs_commit_list(struct list_head *, int); #else static inline int -nfs_commit_file(struct inode *inode, struct file *file, unsigned long offset, - unsigned int len, int flags) +nfs_commit_inode(struct inode *inode, unsigned long idx_start, unsigned int npages, int how) { return 0; } @@ -333,7 +369,7 @@ static inline int nfs_wb_all(struct inode *inode) { - int error = nfs_sync_file(inode, 0, 0, 0, FLUSH_WAIT); + int error = nfs_sync_inode(inode, 0, 0, FLUSH_WAIT); return (error < 0) ? error : 0; } @@ -343,21 +379,11 @@ static inline int nfs_wb_page(struct inode *inode, struct page* page) { - int error = nfs_sync_file(inode, 0, page->index, 1, + int error = nfs_sync_inode(inode, page->index, 1, FLUSH_WAIT | FLUSH_STABLE); return (error < 0) ? error : 0; } -/* - * Write back all pending writes for one user.. - */ -static inline int -nfs_wb_file(struct inode *inode, struct file *file) -{ - int error = nfs_sync_file(inode, file, 0, 0, FLUSH_WAIT); - return (error < 0) ? error : 0; -} - /* Hack for future NFS swap support */ #ifndef IS_SWAPFILE # define IS_SWAPFILE(inode) (0) @@ -383,20 +409,27 @@ /* * inline functions */ -static inline int -nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) + +static inline int nfs_attribute_timeout(struct inode *inode) { - if (time_before(jiffies, NFS_READTIME(inode)+NFS_ATTRTIMEO(inode))) - return NFS_STALE(inode) ? -ESTALE : 0; - return __nfs_revalidate_inode(server, inode); + struct nfs_inode *nfsi = NFS_I(inode); + + return time_after(jiffies, nfsi->read_cache_jiffies+nfsi->attrtimeo); } -static inline int -nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) +/** + * nfs_revalidate_inode - Revalidate the inode attributes + * @server - pointer to nfs_server struct + * @inode - pointer to inode struct + * + * Updates inode attribute information by retrieving the data from the server. + */ +static inline int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) { - if ((fattr->valid & NFS_ATTR_FATTR) == 0) - return 0; - return __nfs_refresh_inode(inode,fattr); + if (!(NFS_FLAGS(inode) & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA)) + && !nfs_attribute_timeout(inode)) + return NFS_STALE(inode) ? -ESTALE : 0; + return __nfs_revalidate_inode(server, inode); } static inline loff_t @@ -661,7 +694,7 @@ #ifdef __KERNEL__ # undef ifdebug # ifdef NFS_DEBUG -# define ifdebug(fac) if (nfs_debug & NFSDBG_##fac) +# define ifdebug(fac) if (unlikely(nfs_debug & NFSDBG_##fac)) # else # define ifdebug(fac) if (0) # endif diff -Nru a/include/linux/nfs_page.h b/include/linux/nfs_page.h --- a/include/linux/nfs_page.h Sun Mar 14 14:20:06 2004 +++ b/include/linux/nfs_page.h Sun Mar 14 14:20:06 2004 @@ -53,7 +53,7 @@ extern void nfs_list_add_request(struct nfs_page *, struct list_head *); extern int nfs_scan_list(struct list_head *, struct list_head *, - struct file *, unsigned long, unsigned int); + unsigned long, unsigned int); extern int nfs_coalesce_requests(struct list_head *, struct list_head *, unsigned int); extern int nfs_wait_on_request(struct nfs_page *); diff -Nru a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h --- a/include/linux/nfs_xdr.h Sun Mar 14 14:20:08 2004 +++ b/include/linux/nfs_xdr.h Sun Mar 14 14:20:08 2004 @@ -700,7 +700,7 @@ struct inode_operations *dir_inode_ops; int (*getroot) (struct nfs_server *, struct nfs_fh *, - struct nfs_fattr *); + struct nfs_fsinfo *); int (*getattr) (struct inode *, struct nfs_fattr *); int (*setattr) (struct dentry *, struct nfs_fattr *, struct iattr *); diff -Nru a/include/linux/page-flags.h b/include/linux/page-flags.h --- a/include/linux/page-flags.h Sun Mar 14 14:20:07 2004 +++ b/include/linux/page-flags.h Sun Mar 14 14:20:07 2004 @@ -80,6 +80,9 @@ /* * Global page accounting. One instance per CPU. Only unsigned longs are * allowed. + * + * NOTE: if this structure is changed then mm/page_alloc.c and + * arch/s390/appldata/appldata_mem.c must be updated accordingly */ struct page_state { unsigned long nr_dirty; /* Dirty writeable pages */ @@ -98,23 +101,38 @@ unsigned long pgpgout; /* Disk writes */ unsigned long pswpin; /* swap reads */ unsigned long pswpout; /* swap writes */ - unsigned long pgalloc; /* page allocations */ + unsigned long pgalloc_high; /* page allocations */ + unsigned long pgalloc_normal; + unsigned long pgalloc_dma; unsigned long pgfree; /* page freeings */ unsigned long pgactivate; /* pages moved inactive->active */ unsigned long pgdeactivate; /* pages moved active->inactive */ + unsigned long pgfault; /* faults (major+minor) */ unsigned long pgmajfault; /* faults (major only) */ - - unsigned long pgscan; /* pages scanned by page reclaim */ - unsigned long pgrefill; /* inspected in refill_inactive_zone */ - unsigned long pgsteal; /* total pages reclaimed */ + unsigned long pgrefill_high; /* inspected in refill_inactive_zone */ + unsigned long pgrefill_normal; + unsigned long pgrefill_dma; + + unsigned long pgsteal_high; /* total highmem pages reclaimed */ + unsigned long pgsteal_normal; + unsigned long pgsteal_dma; + unsigned long pgscan_kswapd_high;/* total highmem pages scanned */ + unsigned long pgscan_kswapd_normal; + + unsigned long pgscan_kswapd_dma; + unsigned long pgscan_direct_high;/* total highmem pages scanned */ + unsigned long pgscan_direct_normal; + unsigned long pgscan_direct_dma; unsigned long pginodesteal; /* pages reclaimed via inode freeing */ - unsigned long kswapd_steal; /* pages reclaimed by kswapd */ + unsigned long slabs_scanned; /* slab objects scanned */ + unsigned long kswapd_steal; /* pages reclaimed by kswapd */ unsigned long kswapd_inodesteal;/* reclaimed via kswapd inode freeing */ unsigned long pageoutrun; /* kswapd's calls to page reclaim */ unsigned long allocstall; /* direct reclaim calls */ + unsigned long pgrotated; /* pages rotated to tail of the LRU */ } ____cacheline_aligned; @@ -131,11 +149,24 @@ local_irq_restore(flags); \ } while (0) + #define inc_page_state(member) mod_page_state(member, 1UL) #define dec_page_state(member) mod_page_state(member, 0UL - 1) #define add_page_state(member,delta) mod_page_state(member, (delta)) #define sub_page_state(member,delta) mod_page_state(member, 0UL - (delta)) +#define mod_page_state_zone(zone, member, delta) \ + do { \ + unsigned long flags; \ + local_irq_save(flags); \ + if (is_highmem(zone)) \ + __get_cpu_var(page_states).member##_high += (delta);\ + else if (is_normal(zone)) \ + __get_cpu_var(page_states).member##_normal += (delta);\ + else \ + __get_cpu_var(page_states).member##_dma += (delta);\ + local_irq_restore(flags); \ + } while (0) /* * Manipulation of page state flags diff -Nru a/include/linux/pci.h b/include/linux/pci.h --- a/include/linux/pci.h Sun Mar 14 14:20:07 2004 +++ b/include/linux/pci.h Sun Mar 14 14:20:07 2004 @@ -393,11 +393,6 @@ this if your device has broken DMA or supports 64-bit transfers. */ - u64 consistent_dma_mask;/* Like dma_mask, but for - pci_alloc_consistent mappings as - not all hardware supports - 64 bit addresses for consistent - allocations such descriptors. */ u32 current_state; /* Current operating state. In ACPI-speak, this is D0-D3, D0 being fully functional, and D3 being off. */ @@ -723,6 +718,10 @@ /* Include architecture-dependent settings and functions */ #include + +/* Backwards compat, remove in 2.7.x */ +#define pci_dma_sync_single pci_dma_sync_single_for_cpu +#define pci_dma_sync_sg pci_dma_sync_sg_for_cpu /* * If the system does not have PCI, clearly these return errors. Define diff -Nru a/include/linux/security.h b/include/linux/security.h --- a/include/linux/security.h Sun Mar 14 14:20:08 2004 +++ b/include/linux/security.h Sun Mar 14 14:20:08 2004 @@ -177,7 +177,7 @@ * options cleanly (a filesystem may modify the data e.g. with strsep()). * This also allows the original mount data to be stripped of security- * specific options to avoid having to make filesystems aware of them. - * @fstype the type of filesystem being mounted. + * @type the type of filesystem being mounted. * @orig the original mount data copied from userspace. * @copy copied data which will be passed to the security module. * Returns 0 if the copy was successful. @@ -1033,7 +1033,8 @@ int (*sb_alloc_security) (struct super_block * sb); void (*sb_free_security) (struct super_block * sb); - int (*sb_copy_data)(const char *fstype, void *orig, void *copy); + int (*sb_copy_data)(struct file_system_type *type, + void *orig, void *copy); int (*sb_kern_mount) (struct super_block *sb, void *data); int (*sb_statfs) (struct super_block * sb); int (*sb_mount) (char *dev_name, struct nameidata * nd, @@ -1318,9 +1319,10 @@ security_ops->sb_free_security (sb); } -static inline int security_sb_copy_data (const char *fstype, void *orig, void *copy) +static inline int security_sb_copy_data (struct file_system_type *type, + void *orig, void *copy) { - return security_ops->sb_copy_data (fstype, orig, copy); + return security_ops->sb_copy_data (type, orig, copy); } static inline int security_sb_kern_mount (struct super_block *sb, void *data) @@ -1988,7 +1990,8 @@ static inline void security_sb_free (struct super_block *sb) { } -static inline int security_sb_copy_data (const char *fstype, void *orig, void *copy) +static inline int security_sb_copy_data (struct file_system_type *type, + void *orig, void *copy) { return 0; } diff -Nru a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h --- a/include/linux/sunrpc/debug.h Sun Mar 14 14:20:09 2004 +++ b/include/linux/sunrpc/debug.h Sun Mar 14 14:20:09 2004 @@ -54,7 +54,7 @@ #undef ifdebug #ifdef RPC_DEBUG -# define ifdebug(fac) if (rpc_debug & RPCDBG_##fac) +# define ifdebug(fac) if (unlikely(rpc_debug & RPCDBG_##fac)) # define dfprintk(fac, args...) do { ifdebug(fac) printk(args); } while(0) # define RPC_IFDEBUG(x) x #else @@ -92,6 +92,8 @@ CTL_NFSDEBUG, CTL_NFSDDEBUG, CTL_NLMDEBUG, + CTL_SLOTTABLE_UDP, + CTL_SLOTTABLE_TCP, }; #endif /* _LINUX_SUNRPC_DEBUG_H_ */ diff -Nru a/include/linux/sunrpc/timer.h b/include/linux/sunrpc/timer.h --- a/include/linux/sunrpc/timer.h Sun Mar 14 14:20:07 2004 +++ b/include/linux/sunrpc/timer.h Sun Mar 14 14:20:07 2004 @@ -25,9 +25,18 @@ static inline void rpc_set_timeo(struct rpc_rtt *rt, int timer, int ntimeo) { + int *t; if (!timer) return; - rt->ntimeouts[timer-1] = ntimeo; + t = &rt->ntimeouts[timer-1]; + if (ntimeo < *t) { + if (*t > 0) + (*t)--; + } else { + if (ntimeo > 8) + ntimeo = 8; + *t = ntimeo; + } } static inline int rpc_ntimeo(struct rpc_rtt *rt, int timer) diff -Nru a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h --- a/include/linux/sunrpc/xdr.h Sun Mar 14 14:20:08 2004 +++ b/include/linux/sunrpc/xdr.h Sun Mar 14 14:20:08 2004 @@ -87,7 +87,7 @@ /* * Miscellaneous XDR helper functions */ -u32 * xdr_encode_array(u32 *p, const char *s, unsigned int len); +u32 * xdr_encode_array(u32 *p, const void *s, unsigned int len); u32 * xdr_encode_string(u32 *p, const char *s); u32 * xdr_decode_string(u32 *p, char **sp, int *lenp, int maxlen); u32 * xdr_decode_string_inplace(u32 *p, char **sp, int *lenp, int maxlen); diff -Nru a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h --- a/include/linux/sunrpc/xprt.h Sun Mar 14 14:20:08 2004 +++ b/include/linux/sunrpc/xprt.h Sun Mar 14 14:20:08 2004 @@ -28,16 +28,18 @@ * * Upper procedures may check whether a request would block waiting for * a free RPC slot by using the RPC_CONGESTED() macro. - * - * Note: on machines with low memory we should probably use a smaller - * MAXREQS value: At 32 outstanding reqs with 8 megs of RAM, fragment - * reassembly will frequently run out of memory. - */ -#define RPC_MAXCONG (16) -#define RPC_MAXREQS RPC_MAXCONG -#define RPC_CWNDSCALE (256) -#define RPC_MAXCWND (RPC_MAXCONG * RPC_CWNDSCALE) + */ +extern unsigned int xprt_udp_slot_table_entries; +extern unsigned int xprt_tcp_slot_table_entries; + +#define RPC_MIN_SLOT_TABLE (2U) +#define RPC_DEF_SLOT_TABLE (16U) +#define RPC_MAX_SLOT_TABLE (128U) + +#define RPC_CWNDSHIFT (8U) +#define RPC_CWNDSCALE (1U << RPC_CWNDSHIFT) #define RPC_INITCWND RPC_CWNDSCALE +#define RPC_MAXCWND(xprt) ((xprt)->max_reqs << RPC_CWNDSHIFT) #define RPCXPRT_CONGESTED(xprt) ((xprt)->cong >= (xprt)->cwnd) /* Default timeout values */ @@ -92,7 +94,6 @@ */ struct rpc_task * rq_task; /* RPC task data */ __u32 rq_xid; /* request XID */ - struct rpc_rqst * rq_next; /* free list */ int rq_cong; /* has incremented xprt->cong */ int rq_received; /* receive completed */ u32 rq_seqno; /* gss seq no. used on req. */ @@ -102,7 +103,6 @@ struct xdr_buf rq_private_buf; /* The receive buffer * used in the softirq. */ - /* * For authentication (e.g. auth_des) */ @@ -146,8 +146,9 @@ struct rpc_wait_queue resend; /* requests waiting to resend */ struct rpc_wait_queue pending; /* requests in flight */ struct rpc_wait_queue backlog; /* waiting for slot */ - struct rpc_rqst * free; /* free slots */ - struct rpc_rqst slot[RPC_MAXREQS]; + struct list_head free; /* free slots */ + struct rpc_rqst * slot; /* slot table storage */ + unsigned int max_reqs; /* total slots */ unsigned long sockstate; /* Socket state */ unsigned char shutdown : 1, /* being shut down */ nocong : 1, /* no congestion control */ @@ -155,6 +156,11 @@ stream : 1; /* TCP */ /* + * XID + */ + __u32 xid; /* Next XID value to use */ + + /* * State of TCP reply receive stuff */ u32 tcp_recm, /* Fragment header */ @@ -163,6 +169,11 @@ tcp_offset; /* fragment offset */ unsigned long tcp_copied, /* copied to request */ tcp_flags; + /* + * Connection of sockets + */ + struct work_struct sock_connect; + unsigned short port; /* * Disconnection of idle sockets */ diff -Nru a/include/linux/topology.h b/include/linux/topology.h --- a/include/linux/topology.h Sun Mar 14 14:20:07 2004 +++ b/include/linux/topology.h Sun Mar 14 14:20:07 2004 @@ -54,4 +54,11 @@ #define for_each_node_with_cpus(node) \ for (node = 0; node < numnodes; node = __next_node_with_cpus(node)) +#ifndef node_distance +#define node_distance(from,to) (from != to) +#endif +#ifndef PENALTY_FOR_NODE_WITH_CPUS +#define PENALTY_FOR_NODE_WITH_CPUS (1) +#endif + #endif /* _LINUX_TOPOLOGY_H */ diff -Nru a/include/linux/udf_fs.h b/include/linux/udf_fs.h --- a/include/linux/udf_fs.h Sun Mar 14 14:20:06 2004 +++ b/include/linux/udf_fs.h Sun Mar 14 14:20:06 2004 @@ -8,7 +8,7 @@ * OSTA-UDF(tm) = Optical Storage Technology Association * Universal Disk Format. * - * This code is based on version 2.00 of the UDF specification, + * This code is based on version 2.50 of the UDF specification, * and revision 3 of the ECMA 167 standard [equivalent to ISO 13346]. * http://www.osta.org/ * http://www.ecma.ch/ * http://www.iso.org/ @@ -24,7 +24,7 @@ * ftp://prep.ai.mit.edu/pub/gnu/GPL * Each contributing author retains all rights to their own work. * - * (C) 1999-2000 Ben Fennema + * (C) 1999-2004 Ben Fennema * (C) 1999-2000 Stelias Computing Inc * * HISTORY @@ -37,8 +37,8 @@ #define UDF_PREALLOCATE #define UDF_DEFAULT_PREALLOC_BLOCKS 8 -#define UDFFS_DATE "2002/11/15" -#define UDFFS_VERSION "0.9.7" +#define UDFFS_DATE "2004/29/09" +#define UDFFS_VERSION "0.9.8.1" #define UDFFS_DEBUG diff -Nru a/include/linux/ufs_fs.h b/include/linux/ufs_fs.h --- a/include/linux/ufs_fs.h Sun Mar 14 14:20:08 2004 +++ b/include/linux/ufs_fs.h Sun Mar 14 14:20:08 2004 @@ -22,6 +22,9 @@ * HP/UX hfs filesystem support added by * Martin K. Petersen , August 1999 * + * UFS2 (of FreeBSD 5.x) support added by + * Niraj Kumar , Jan 2004 + * */ #ifndef __LINUX_UFS_FS_H @@ -43,8 +46,50 @@ #define UFS_SECTOR_SIZE 512 #define UFS_SECTOR_BITS 9 -#define UFS_MAGIC 0x00011954 -#define UFS_CIGAM 0x54190100 /* byteswapped MAGIC */ +#define UFS_MAGIC 0x00011954 +#define UFS2_MAGIC 0x19540119 +#define UFS_CIGAM 0x54190100 /* byteswapped MAGIC */ + +/* Copied from FreeBSD */ +/* + * Each disk drive contains some number of filesystems. + * A filesystem consists of a number of cylinder groups. + * Each cylinder group has inodes and data. + * + * A filesystem is described by its super-block, which in turn + * describes the cylinder groups. The super-block is critical + * data and is replicated in each cylinder group to protect against + * catastrophic loss. This is done at `newfs' time and the critical + * super-block data does not change, so the copies need not be + * referenced further unless disaster strikes. + * + * For filesystem fs, the offsets of the various blocks of interest + * are given in the super block as: + * [fs->fs_sblkno] Super-block + * [fs->fs_cblkno] Cylinder group block + * [fs->fs_iblkno] Inode blocks + * [fs->fs_dblkno] Data blocks + * The beginning of cylinder group cg in fs, is given by + * the ``cgbase(fs, cg)'' macro. + * + * Depending on the architecture and the media, the superblock may + * reside in any one of four places. For tiny media where every block + * counts, it is placed at the very front of the partition. Historically, + * UFS1 placed it 8K from the front to leave room for the disk label and + * a small bootstrap. For UFS2 it got moved to 64K from the front to leave + * room for the disk label and a bigger bootstrap, and for really piggy + * systems we check at 256K from the front if the first three fail. In + * all cases the size of the superblock will be SBLOCKSIZE. All values are + * given in byte-offset form, so they do not imply a sector size. The + * SBLOCKSEARCH specifies the order in which the locations should be searched. + */ +#define SBLOCK_FLOPPY 0 +#define SBLOCK_UFS1 8192 +#define SBLOCK_UFS2 65536 +#define SBLOCK_PIGGY 262144 +#define SBLOCKSIZE 8192 +#define SBLOCKSEARCH \ + { SBLOCK_UFS2, SBLOCK_UFS1, SBLOCK_FLOPPY, SBLOCK_PIGGY, -1 } /* HP specific MAGIC values */ @@ -120,6 +165,11 @@ #define UFS_CG_OLD 0x00000000 #define UFS_CG_44BSD 0x00002000 #define UFS_CG_SUN 0x00001000 +/* filesystem type encoding */ +#define UFS_TYPE_MASK 0x00010000 /* mask for the following */ +#define UFS_TYPE_UFS1 0x00000000 +#define UFS_TYPE_UFS2 0x00010000 + /* fs_inodefmt options */ #define UFS_42INODEFMT -1 @@ -132,7 +182,7 @@ #define UFS_MOUNT_ONERROR_UMOUNT 0x00000004 #define UFS_MOUNT_ONERROR_REPAIR 0x00000008 -#define UFS_MOUNT_UFSTYPE 0x00000FF0 +#define UFS_MOUNT_UFSTYPE 0x0000FFF0 #define UFS_MOUNT_UFSTYPE_OLD 0x00000010 #define UFS_MOUNT_UFSTYPE_44BSD 0x00000020 #define UFS_MOUNT_UFSTYPE_SUN 0x00000040 @@ -141,6 +191,7 @@ #define UFS_MOUNT_UFSTYPE_OPENSTEP 0x00000200 #define UFS_MOUNT_UFSTYPE_SUNx86 0x00000400 #define UFS_MOUNT_UFSTYPE_HP 0x00000800 +#define UFS_MOUNT_UFSTYPE_UFS2 0x00001000 #define ufs_clear_opt(o,opt) o &= ~UFS_MOUNT_##opt #define ufs_set_opt(o,opt) o |= UFS_MOUNT_##opt @@ -173,7 +224,8 @@ * They calc file system addresses of cylinder group data structures. */ #define ufs_cgbase(c) (uspi->s_fpg * (c)) -#define ufs_cgstart(c) (ufs_cgbase(c) + uspi->s_cgoffset * ((c) & ~uspi->s_cgmask)) +#define ufs_cgstart(c) ((uspi)->fs_magic == UFS2_MAGIC ? ufs_cgbase(c) : \ + (ufs_cgbase(c) + uspi->s_cgoffset * ((c) & ~uspi->s_cgmask))) #define ufs_cgsblock(c) (ufs_cgstart(c) + uspi->s_sblkno) /* super blk */ #define ufs_cgcmin(c) (ufs_cgstart(c) + uspi->s_cblkno) /* cg block */ #define ufs_cgimin(c) (ufs_cgstart(c) + uspi->s_iblkno) /* inode blk */ @@ -227,8 +279,14 @@ #define UFS_MAXNAMLEN 255 #define UFS_MAXMNTLEN 512 +#define UFS2_MAXMNTLEN 468 +#define UFS2_MAXVOLLEN 32 /* #define UFS_MAXCSBUFS 31 */ #define UFS_LINK_MAX 32000 +/* +#define UFS2_NOCSPTRS ((128 / sizeof(void *)) - 4) +*/ +#define UFS2_NOCSPTRS 28 /* * UFS_DIR_PAD defines the directory entries boundaries @@ -262,6 +320,14 @@ __u32 cs_nifree; /* number of free inodes */ __u32 cs_nffree; /* number of free frags */ }; +struct ufs2_csum_total { + __u64 cs_ndir; /* number of directories */ + __u64 cs_nbfree; /* number of free blocks */ + __u64 cs_nifree; /* number of free inodes */ + __u64 cs_nffree; /* number of free frags */ + __u64 cs_numclusters; /* number of free clusters */ + __u64 cs_spare[3]; /* future expansion */ +}; /* * This is the actual superblock, as it is laid out on the disk. @@ -333,7 +399,7 @@ __u32 fs_ncyl; /* cylinders in file system */ /* these fields can be computed from the others */ __u32 fs_cpg; /* cylinders per group */ - __u32 fs_ipg; /* inodes per group */ + __u32 fs_ipg; /* inodes per cylinder group */ __u32 fs_fpg; /* blocks per group * fs_frag */ /* this data must be re-computed after crashes */ struct ufs_csum fs_cstotal; /* cylinder summary information */ @@ -342,13 +408,39 @@ __s8 fs_clean; /* file system is clean flag */ __s8 fs_ronly; /* mounted read-only flag */ __s8 fs_flags; /* currently unused flag */ - __s8 fs_fsmnt[UFS_MAXMNTLEN]; /* name mounted on */ -/* these fields retain the current block allocation info */ - __u32 fs_cgrotor; /* last cg searched */ - __u32 fs_csp[UFS_MAXCSBUFS]; /* list of fs_cs info buffers */ - __u32 fs_maxcluster; - __u32 fs_cpc; /* cyl per cycle in postbl */ - __u16 fs_opostbl[16][8]; /* old rotation block list head */ + union { + struct { + __s8 fs_fsmnt[UFS_MAXMNTLEN];/* name mounted on */ + __u32 fs_cgrotor; /* last cg searched */ + __u32 fs_csp[UFS_MAXCSBUFS];/*list of fs_cs info buffers */ + __u32 fs_maxcluster; + __u32 fs_cpc; /* cyl per cycle in postbl */ + __u16 fs_opostbl[16][8]; /* old rotation block list head */ + } fs_u1; + struct { + __s8 fs_fsmnt[UFS2_MAXMNTLEN]; /* name mounted on */ + __u8 fs_volname[UFS2_MAXVOLLEN]; /* volume name */ + __u64 fs_swuid; /* system-wide uid */ + __s32 fs_pad; /* due to alignment of fs_swuid */ + __u32 fs_cgrotor; /* last cg searched */ + __u32 fs_ocsp[UFS2_NOCSPTRS]; /*list of fs_cs info buffers */ + __u32 fs_contigdirs;/*# of contiguously allocated dirs */ + __u32 fs_csp; /* cg summary info buffer for fs_cs */ + __u32 fs_maxcluster; + __u32 fs_active;/* used by snapshots to track fs */ + __s32 fs_old_cpc; /* cyl per cycle in postbl */ + __s32 fs_maxbsize;/*maximum blocking factor permitted */ + __s64 fs_sparecon64[17];/*old rotation block list head */ + __s64 fs_sblockloc; /* byte offset of standard superblock */ + struct ufs2_csum_total fs_cstotal;/*cylinder summary information*/ + struct ufs_timeval fs_time; /* last time written */ + __s64 fs_size; /* number of blocks in fs */ + __s64 fs_dsize; /* number of data blocks in fs */ + __u64 fs_csaddr; /* blk addr of cyl grp summary area */ + __s64 fs_pendingblocks;/* blocks in process of being freed */ + __s32 fs_pendinginodes;/*inodes in process of being freed */ + } fs_u2; + } fs_u11; union { struct { __s32 fs_sparecon[53];/* reserved for future constants */ @@ -441,6 +533,16 @@ __u32 cg_nclusterblks; /* number of clusters this cg */ __u32 cg_sparecon[13]; /* reserved for future use */ } cg_44; + struct { + __u32 cg_clustersumoff;/* (u_int32) counts of avail clusters */ + __u32 cg_clusteroff; /* (u_int8) free cluster map */ + __u32 cg_nclusterblks;/* number of clusters this cg */ + __u32 cg_niblk; /* number of inode blocks this cg */ + __u32 cg_initediblk; /* last initialized inode */ + __u32 cg_sparecon32[3];/* reserved for future use */ + __u64 cg_time; /* time last written */ + __u64 cg_sparecon[3]; /* reserved for future use */ + } cg_u2; __u32 cg_sparecon[16]; /* reserved for future use */ } cg_u; __u8 cg_space[1]; /* space for cylinder group maps */ @@ -497,6 +599,39 @@ } ui_u3; }; +#define UFS_NXADDR 2 /* External addresses in inode. */ +struct ufs2_inode { + __u16 ui_mode; /* 0: IFMT, permissions; see below. */ + __s16 ui_nlink; /* 2: File link count. */ + __u32 ui_uid; /* 4: File owner. */ + __u32 ui_gid; /* 8: File group. */ + __u32 ui_blksize; /* 12: Inode blocksize. */ + __u64 ui_size; /* 16: File byte count. */ + __u64 ui_blocks; /* 24: Bytes actually held. */ + struct ufs_timeval ui_atime; /* 32: Last access time. */ + struct ufs_timeval ui_mtime; /* 40: Last modified time. */ + struct ufs_timeval ui_ctime; /* 48: Last inode change time. */ + struct ufs_timeval ui_birthtime; /* 56: Inode creation time. */ + __s32 ui_mtimensec; /* 64: Last modified time. */ + __s32 ui_atimensec; /* 68: Last access time. */ + __s32 ui_ctimensec; /* 72: Last inode change time. */ + __s32 ui_birthnsec; /* 76: Inode creation time. */ + __s32 ui_gen; /* 80: Generation number. */ + __u32 ui_kernflags; /* 84: Kernel flags. */ + __u32 ui_flags; /* 88: Status flags (chflags). */ + __s32 ui_extsize; /* 92: External attributes block. */ + __s64 ui_extb[UFS_NXADDR];/* 96: External attributes block. */ + union { + struct { + __s64 ui_db[UFS_NDADDR]; /* 112: Direct disk blocks. */ + __s64 ui_ib[UFS_NINDIR];/* 208: Indirect disk blocks.*/ + } ui_addr; + __u8 ui_symlink[2*4*(UFS_NDADDR+UFS_NINDIR)];/* 0x28 fast symlink */ + } ui_u2; + __s64 ui_spare[3]; /* 232: Reserved; currently unused */ +}; + + /* FreeBSD has these in sys/stat.h */ /* ui_flags that can be set by a file owner */ #define UFS_UF_SETTABLE 0x0000ffff @@ -517,8 +652,8 @@ * than the size of fragment. */ struct ufs_buffer_head { - unsigned fragment; /* first fragment */ - unsigned count; /* number of fragments */ + __u64 fragment; /* first fragment */ + __u64 count; /* number of fragments */ struct buffer_head * bh[UFS_MAXFRAG]; /* buffers */ }; @@ -551,6 +686,8 @@ __u32 s_cgmask; /* used to calc mod fs_ntrak */ __u32 s_size; /* number of blocks (fragments) in fs */ __u32 s_dsize; /* number of data blocks in fs */ + __u64 s_u2_size; /* ufs2: number of blocks (fragments) in fs */ + __u64 s_u2_dsize; /*ufs2: number of data blocks in fs */ __u32 s_ncg; /* number of cylinder groups */ __u32 s_bsize; /* size of basic blocks */ __u32 s_fsize; /* size of fragments */ @@ -577,7 +714,7 @@ __u32 s_ntrak; /* tracks per cylinder */ __u32 s_nsect; /* sectors per track */ __u32 s_spc; /* sectors per cylinder */ - __u32 s_ipg; /* inodes per group */ + __u32 s_ipg; /* inodes per cylinder group */ __u32 s_fpg; /* fragments per group */ __u32 s_cpc; /* cyl per cycle in postbl */ __s32 s_contigsumsize;/* size of cluster summary array, 44bsd */ @@ -605,6 +742,7 @@ __u32 s_bpfmask; /* bits per fragment mask */ __u32 s_maxsymlinklen;/* upper limit on fast symlinks' size */ + __s32 fs_magic; /* filesystem magic */ }; /* @@ -758,7 +896,7 @@ extern struct inode * ufs_new_inode (struct inode *, int); /* inode.c */ -extern int ufs_frag_map (struct inode *, int); +extern u64 ufs_frag_map (struct inode *, int); extern void ufs_read_inode (struct inode *); extern void ufs_put_inode (struct inode *); extern void ufs_write_inode (struct inode *, int); diff -Nru a/include/linux/ufs_fs_i.h b/include/linux/ufs_fs_i.h --- a/include/linux/ufs_fs_i.h Sun Mar 14 14:20:07 2004 +++ b/include/linux/ufs_fs_i.h Sun Mar 14 14:20:07 2004 @@ -17,6 +17,7 @@ union { __u32 i_data[15]; __u8 i_symlink[4*15]; + __u64 u2_i_data[15]; } i_u1; __u32 i_flags; __u32 i_gen; diff -Nru a/include/linux/usb.h b/include/linux/usb.h --- a/include/linux/usb.h Sun Mar 14 14:20:07 2004 +++ b/include/linux/usb.h Sun Mar 14 14:20:07 2004 @@ -830,14 +830,18 @@ void *addr, dma_addr_t dma); struct urb *usb_buffer_map (struct urb *urb); +#if 0 void usb_buffer_dmasync (struct urb *urb); +#endif void usb_buffer_unmap (struct urb *urb); struct scatterlist; int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe, struct scatterlist *sg, int nents); +#if 0 void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe, struct scatterlist *sg, int n_hw_ents); +#endif void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, struct scatterlist *sg, int n_hw_ents); diff -Nru a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h --- a/include/linux/usb_gadget.h Sun Mar 14 14:20:07 2004 +++ b/include/linux/usb_gadget.h Sun Mar 14 14:20:07 2004 @@ -117,7 +117,7 @@ void (*free_buffer) (struct usb_ep *ep, void *buf, dma_addr_t dma, unsigned bytes); // NOTE: on 2.5, drivers may also use dma_map() and - // dma_sync_single() to manage dma overhead. + // dma_sync_single_*() to manage dma overhead. int (*queue) (struct usb_ep *ep, struct usb_request *req, int gfp_flags); diff -Nru a/include/net/irda/vlsi_ir.h b/include/net/irda/vlsi_ir.h --- a/include/net/irda/vlsi_ir.h Sun Mar 14 14:20:07 2004 +++ b/include/net/irda/vlsi_ir.h Sun Mar 14 14:20:07 2004 @@ -41,19 +41,6 @@ #define PCI_CLASS_SUBCLASS_MASK 0xffff #endif -/* missing pci-dma api call to give streaming dma buffer back to hw - * patch was floating on lkml around 2.5.2x and might be present later. - * Defining it this way is ok, since the vlsi-ir is only - * used on two oldish x86-based notebooks which are cache-coherent - * (and flush_write_buffers also handles PPro errata and C3 OOstore) - */ -#ifdef CONFIG_X86 -#include -#define pci_dma_prep_single(dev, addr, size, direction) flush_write_buffers() -#else -#error missing pci dma api call -#endif - /* in recent 2.5 interrupt handlers have non-void return value */ #ifndef IRQ_RETVAL typedef void irqreturn_t; diff -Nru a/include/scsi/scsi.h b/include/scsi/scsi.h --- a/include/scsi/scsi.h Sun Mar 14 14:20:08 2004 +++ b/include/scsi/scsi.h Sun Mar 14 14:20:08 2004 @@ -10,6 +10,12 @@ #include +/* + * The maximum sg list length SCSI can cope with + * (currently must be a power of 2 between 32 and 256) + */ +#define SCSI_MAX_PHYS_SEGMENTS MAX_PHYS_SEGMENTS + /* * SCSI command lengths @@ -200,6 +206,7 @@ #define TYPE_MEDIUM_CHANGER 0x08 #define TYPE_COMM 0x09 /* Communications device */ #define TYPE_ENCLOSURE 0x0d /* Enclosure Services Device */ +#define TYPE_RAID 0x0c #define TYPE_NO_LUN 0x7f /* @@ -273,6 +280,7 @@ #define DID_BAD_INTR 0x09 /* Got an interrupt we weren't expecting. */ #define DID_PASSTHROUGH 0x0a /* Force command past mid-layer */ #define DID_SOFT_ERROR 0x0b /* The low level driver just wish a retry */ +#define DID_IMM_RETRY 0x0c /* Retry without decrementing retry count */ #define DRIVER_OK 0x00 /* Driver status */ /* diff -Nru a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h --- a/include/scsi/scsi_device.h Sun Mar 14 14:20:06 2004 +++ b/include/scsi/scsi_device.h Sun Mar 14 14:20:06 2004 @@ -15,7 +15,7 @@ * sdev state */ enum scsi_device_state { - SDEV_CREATED, /* device created but not added to sysfs + SDEV_CREATED = 1, /* device created but not added to sysfs * Only internal commands allowed (for inq) */ SDEV_RUNNING, /* device properly configured * All commands allowed */ @@ -23,6 +23,9 @@ * Only error handler commands allowed */ SDEV_DEL, /* device deleted * no commands allowed */ + SDEV_QUIESCE, /* Device quiescent. No block commands + * will be accepted, only specials (which + * originate in the mid-layer) */ }; struct scsi_device { @@ -94,6 +97,7 @@ unsigned skip_ms_page_8:1; /* do not use MODE SENSE page 0x08 */ unsigned skip_ms_page_3f:1; /* do not use MODE SENSE page 0x3f */ unsigned no_start_on_add:1; /* do not issue start on add */ + unsigned allow_restart:1; /* issue START_UNIT in error handler */ unsigned int device_blocked; /* Device returned QUEUE_FULL. */ @@ -103,12 +107,17 @@ struct device sdev_gendev; struct class_device sdev_classdev; + struct class_device transport_classdev; + enum scsi_device_state sdev_state; -}; + unsigned long transport_data[0]; +} __attribute__((aligned(sizeof(unsigned long)))); #define to_scsi_device(d) \ container_of(d, struct scsi_device, sdev_gendev) #define class_to_sdev(d) \ container_of(d, struct scsi_device, sdev_classdev) +#define transport_class_to_sdev(class_dev) \ + container_of(class_dev, struct scsi_device, transport_classdev) extern struct scsi_device *scsi_add_device(struct Scsi_Host *, uint, uint, uint); @@ -164,4 +173,8 @@ extern int scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, unsigned char *buffer, int len, int timeout, int retries, struct scsi_mode_data *data); +extern int scsi_device_set_state(struct scsi_device *sdev, + enum scsi_device_state state); +extern int scsi_device_quiesce(struct scsi_device *sdev); +extern void scsi_device_resume(struct scsi_device *sdev); #endif /* _SCSI_SCSI_DEVICE_H */ diff -Nru a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h --- a/include/scsi/scsi_host.h Sun Mar 14 14:20:06 2004 +++ b/include/scsi/scsi_host.h Sun Mar 14 14:20:06 2004 @@ -11,6 +11,7 @@ struct scsi_device; struct Scsi_Host; struct scsi_host_cmd_pool; +struct scsi_transport_template; /* @@ -395,6 +396,7 @@ unsigned int eh_kill:1; /* set when killing the eh thread */ wait_queue_head_t host_wait; struct scsi_host_template *hostt; + struct scsi_transport_template *transportt; volatile unsigned short host_busy; /* commands actually active on low-level */ volatile unsigned short host_failed; /* commands that failed. */ diff -Nru a/include/scsi/scsi_transport.h b/include/scsi/scsi_transport.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/scsi/scsi_transport.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,41 @@ +/* + * Transport specific attributes. + * + * Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef SCSI_TRANSPORT_H +#define SCSI_TRANSPORT_H + +struct scsi_transport_template { + /* The NULL terminated list of transport attributes + * that should be exported. + */ + struct class_device_attribute **attrs; + + /* The transport class that the device is in */ + struct class *class; + + /* Constructor/Destructor functions */ + int (* setup)(struct scsi_device *); + void (* cleanup)(struct scsi_device *); + /* The size of the specific transport attribute structure (a + * space of this size will be left at the end of the + * scsi_device structure */ + int size; +}; + +#endif /* SCSI_TRANSPORT_H */ diff -Nru a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/scsi/scsi_transport_fc.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,38 @@ +/* + * FiberChannel transport specific attributes exported to sysfs. + * + * Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef SCSI_TRANSPORT_FC_H +#define SCSI_TRANSPORT_FC_H + +struct scsi_transport_template; + +struct fc_transport_attrs { + int port_id; + uint64_t node_name; + uint64_t port_name; +}; + +/* accessor functions */ +#define fc_port_id(x) (((struct fc_transport_attrs *)&(x)->transport_data)->port_id) +#define fc_node_name(x) (((struct fc_transport_attrs *)&(x)->transport_data)->node_name) +#define fc_port_name(x) (((struct fc_transport_attrs *)&(x)->transport_data)->port_name) + +extern struct scsi_transport_template fc_transport_template; + +#endif /* SCSI_TRANSPORT_FC_H */ diff -Nru a/include/scsi/scsi_transport_spi.h b/include/scsi/scsi_transport_spi.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/scsi/scsi_transport_spi.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,96 @@ +/* + * Parallel SCSI (SPI) transport specific attributes exported to sysfs. + * + * Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef SCSI_TRANSPORT_SPI_H +#define SCSI_TRANSPORT_SPI_H + +#include + +struct scsi_transport_template; + +struct spi_transport_attrs { + int period; /* value in the PPR/SDTR command */ + int offset; + unsigned int width:1; /* 0 - narrow, 1 - wide */ + unsigned int iu:1; /* Information Units enabled */ + unsigned int dt:1; /* DT clocking enabled */ + unsigned int qas:1; /* Quick Arbitration and Selection enabled */ + unsigned int wr_flow:1; /* Write Flow control enabled */ + unsigned int rd_strm:1; /* Read streaming enabled */ + unsigned int rti:1; /* Retain Training Information */ + unsigned int pcomp_en:1;/* Precompensation enabled */ + unsigned int dv_pending:1; /* Internal flag */ +}; + +/* accessor functions */ +#define spi_period(x) (((struct spi_transport_attrs *)&(x)->transport_data)->period) +#define spi_offset(x) (((struct spi_transport_attrs *)&(x)->transport_data)->offset) +#define spi_width(x) (((struct spi_transport_attrs *)&(x)->transport_data)->width) +#define spi_iu(x) (((struct spi_transport_attrs *)&(x)->transport_data)->iu) +#define spi_dt(x) (((struct spi_transport_attrs *)&(x)->transport_data)->dt) +#define spi_qas(x) (((struct spi_transport_attrs *)&(x)->transport_data)->qas) +#define spi_wr_flow(x) (((struct spi_transport_attrs *)&(x)->transport_data)->wr_flow) +#define spi_rd_strm(x) (((struct spi_transport_attrs *)&(x)->transport_data)->rd_strm) +#define spi_rti(x) (((struct spi_transport_attrs *)&(x)->transport_data)->rti) +#define spi_pcomp_en(x) (((struct spi_transport_attrs *)&(x)->transport_data)->pcomp_en) + +/* The functions by which the transport class and the driver communicate */ +struct spi_function_template { + void (*get_period)(struct scsi_device *); + void (*set_period)(struct scsi_device *, int); + void (*get_offset)(struct scsi_device *); + void (*set_offset)(struct scsi_device *, int); + void (*get_width)(struct scsi_device *); + void (*set_width)(struct scsi_device *, int); + void (*get_iu)(struct scsi_device *); + void (*set_iu)(struct scsi_device *, int); + void (*get_dt)(struct scsi_device *); + void (*set_dt)(struct scsi_device *, int); + void (*get_qas)(struct scsi_device *); + void (*set_qas)(struct scsi_device *, int); + void (*get_wr_flow)(struct scsi_device *); + void (*set_wr_flow)(struct scsi_device *, int); + void (*get_rd_strm)(struct scsi_device *); + void (*set_rd_strm)(struct scsi_device *, int); + void (*get_rti)(struct scsi_device *); + void (*set_rti)(struct scsi_device *, int); + void (*get_pcomp_en)(struct scsi_device *); + void (*set_pcomp_en)(struct scsi_device *, int); + /* The driver sets these to tell the transport class it + * wants the attributes displayed in sysfs. If the show_ flag + * is not set, the attribute will be private to the transport + * class */ + unsigned long show_period:1; + unsigned long show_offset:1; + unsigned long show_width:1; + unsigned long show_iu:1; + unsigned long show_dt:1; + unsigned long show_qas:1; + unsigned long show_wr_flow:1; + unsigned long show_rd_strm:1; + unsigned long show_rti:1; + unsigned long show_pcomp_en:1; +}; + +struct scsi_transport_template *spi_attach_transport(struct spi_function_template *); +void spi_release_transport(struct scsi_transport_template *); +void spi_schedule_dv_device(struct scsi_device *); +void spi_dv_device(struct scsi_device *); + +#endif /* SCSI_TRANSPORT_SPI_H */ diff -Nru a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h --- a/include/sound/ac97_codec.h Sun Mar 14 14:20:07 2004 +++ b/include/sound/ac97_codec.h Sun Mar 14 14:20:07 2004 @@ -484,7 +484,8 @@ AC97_TUNE_HP_ONLY, /* headphone (true line-out) control as master only */ AC97_TUNE_SWAP_HP, /* swap headphone and master controls */ AC97_TUNE_SWAP_SURROUND, /* swap master and surround controls */ - AC97_TUNE_AD_SHARING /* for AD1985, turn on OMS bit and use headphone */ + AC97_TUNE_AD_SHARING, /* for AD1985, turn on OMS bit and use headphone */ + AC97_TUNE_ALC_JACK, /* for Realtek, enable JACK detection */ }; struct ac97_quirk { diff -Nru a/include/sound/ak4117.h b/include/sound/ak4117.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/sound/ak4117.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,191 @@ +#ifndef __SOUND_AK4117_H +#define __SOUND_AK4117_H + +/* + * Routines for Asahi Kasei AK4117 + * Copyright (c) by Jaroslav Kysela , + * + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define AK4117_REG_PWRDN 0x00 /* power down */ +#define AK4117_REG_CLOCK 0x01 /* clock control */ +#define AK4117_REG_IO 0x02 /* input/output control */ +#define AK4117_REG_INT0_MASK 0x03 /* interrupt0 mask */ +#define AK4117_REG_INT1_MASK 0x04 /* interrupt1 mask */ +#define AK4117_REG_RCS0 0x05 /* receiver status 0 */ +#define AK4117_REG_RCS1 0x06 /* receiver status 1 */ +#define AK4117_REG_RCS2 0x07 /* receiver status 2 */ +#define AK4117_REG_RXCSB0 0x08 /* RX channel status byte 0 */ +#define AK4117_REG_RXCSB1 0x09 /* RX channel status byte 1 */ +#define AK4117_REG_RXCSB2 0x0a /* RX channel status byte 2 */ +#define AK4117_REG_RXCSB3 0x0b /* RX channel status byte 3 */ +#define AK4117_REG_RXCSB4 0x0c /* RX channel status byte 4 */ +#define AK4117_REG_Pc0 0x0d /* burst preamble Pc byte 0 */ +#define AK4117_REG_Pc1 0x0e /* burst preamble Pc byte 1 */ +#define AK4117_REG_Pd0 0x0f /* burst preamble Pd byte 0 */ +#define AK4117_REG_Pd1 0x10 /* burst preamble Pd byte 1 */ +#define AK4117_REG_QSUB_ADDR 0x11 /* Q-subcode address + control */ +#define AK4117_REG_QSUB_TRACK 0x12 /* Q-subcode track */ +#define AK4117_REG_QSUB_INDEX 0x13 /* Q-subcode index */ +#define AK4117_REG_QSUB_MINUTE 0x14 /* Q-subcode minute */ +#define AK4117_REG_QSUB_SECOND 0x15 /* Q-subcode second */ +#define AK4117_REG_QSUB_FRAME 0x16 /* Q-subcode frame */ +#define AK4117_REG_QSUB_ZERO 0x17 /* Q-subcode zero */ +#define AK4117_REG_QSUB_ABSMIN 0x18 /* Q-subcode absolute minute */ +#define AK4117_REG_QSUB_ABSSEC 0x19 /* Q-subcode absolute second */ +#define AK4117_REG_QSUB_ABSFRM 0x1a /* Q-subcode absolute frame */ + +/* sizes */ +#define AK4117_REG_RXCSB_SIZE ((AK4117_REG_RXCSB4-AK4117_REG_RXCSB0)+1) +#define AK4117_REG_QSUB_SIZE ((AK4117_REG_QSUB_ABSFRM-AK4117_REG_QSUB_ADDR)+1) + +/* AK4117_REG_PWRDN bits */ +#define AK4117_EXCT (1<<4) /* 0 = X'tal mode, 1 = external clock mode */ +#define AK4117_XTL1 (1<<3) /* XTL1=0,XTL0=0 -> 11.2896Mhz; XTL1=0,XTL0=1 -> 12.288Mhz */ +#define AK4117_XTL0 (1<<2) /* XTL1=1,XTL0=0 -> 24.576Mhz; XTL1=1,XTL0=1 -> use channel status */ +#define AK4117_XTL_11_2896M (0) +#define AK4117_XTL_12_288M AK4117_XTL0 +#define AK4117_XTL_24_576M AK4117_XTL1 +#define AK4117_XTL_EXT (AK4117_XTL1|AK4117_XTL0) +#define AK4117_PWN (1<<1) /* 0 = power down, 1 = normal operation */ +#define AK4117_RST (1<<0) /* 0 = reset & initialize (except this register), 1 = normal operation */ + +/* AK4117_REQ_CLOCK bits */ +#define AK4117_LP (1<<7) /* 0 = normal mode, 1 = low power mode (Fs up to 48kHz only) */ +#define AK4117_PKCS1 (1<<6) /* master clock frequency at PLL mode (when LP == 0) */ +#define AK4117_PKCS0 (1<<5) +#define AK4117_PKCS_512fs (0) +#define AK4117_PKCS_256fs AK4117_PKCS0 +#define AK4117_PKCS_128fs AK4117_PKCS1 +#define AK4117_DIV (1<<4) /* 0 = MCKO == Fs, 1 = MCKO == Fs / 2; X'tal mode only */ +#define AK4117_XCKS1 (1<<3) /* master clock frequency at X'tal mode */ +#define AK4117_XCKS0 (1<<2) +#define AK4117_XCKS_128fs (0) +#define AK4117_XCKS_256fs AK4117_XCKS0 +#define AK4117_XCKS_512fs AK4117_XCKS1 +#define AK4117_XCKS_1024fs (AK4117_XCKS1|AK4117_XCKS0) +#define AK4117_CM1 (1<<1) /* MCKO operation mode select */ +#define AK4117_CM0 (1<<0) +#define AK4117_CM_PLL (0) /* use RX input as master clock */ +#define AK4117_CM_XTAL (AK4117_CM0) /* use X'tal as master clock */ +#define AK4117_CM_PLL_XTAL (AK4117_CM1) /* use Rx input but X'tal when PLL loses lock */ +#define AK4117_CM_MONITOR (AK4117_CM0|AK4117_CM1) /* use X'tal as master clock, but use PLL for monitoring */ + +/* AK4117_REG_IO */ +#define AK4117_IPS (1<<7) /* Input Recovery Data Select, 0 = RX0, 1 = RX1 */ +#define AK4117_UOUTE (1<<6) /* U-bit output enable to UOUT, 0 = disable, 1 = enable */ +#define AK4117_CS12 (1<<5) /* channel status select, 0 = channel1, 1 = channel2 */ +#define AK4117_EFH2 (1<<4) /* INT0 pin hold count select */ +#define AK4117_EFH1 (1<<3) +#define AK4117_EFH_512LRCLK (0) +#define AK4117_EFH_1024LRCLK (AK4117_EFH1) +#define AK4117_EFH_2048LRCLK (AK4117_EFH2) +#define AK4117_EFH_4096LRCLK (AK4117_EFH1|AK4117_EFH2) +#define AK4117_DIF2 (1<<2) /* audio data format control */ +#define AK4117_DIF1 (1<<1) +#define AK4117_DIF0 (1<<0) +#define AK4117_DIF_16R (0) /* STDO: 16-bit, right justified */ +#define AK4117_DIF_18R (AK4117_DIF0) /* STDO: 18-bit, right justified */ +#define AK4117_DIF_20R (AK4117_DIF1) /* STDO: 20-bit, right justified */ +#define AK4117_DIF_24R (AK4117_DIF1|AK4117_DIF0) /* STDO: 24-bit, right justified */ +#define AK4117_DIF_24L (AK4117_DIF2) /* STDO: 24-bit, left justified */ +#define AK4117_DIF_24I2S (AK4117_DIF2|AK4117_DIF0) /* STDO: I2S */ + +/* AK4117_REG_INT0_MASK & AK4117_INT1_MASK */ +#define AK4117_MULK (1<<7) /* mask enable for UNLOCK bit */ +#define AK4117_MPAR (1<<6) /* mask enable for PAR bit */ +#define AK4117_MAUTO (1<<5) /* mask enable for AUTO bit */ +#define AK4117_MV (1<<4) /* mask enable for V bit */ +#define AK4117_MAUD (1<<3) /* mask enable for AUDION bit */ +#define AK4117_MSTC (1<<2) /* mask enable for STC bit */ +#define AK4117_MCIT (1<<1) /* mask enable for CINT bit */ +#define AK4117_MQIT (1<<0) /* mask enable for QINT bit */ + +/* AK4117_REG_RCS0 */ +#define AK4117_UNLCK (1<<7) /* PLL lock status, 0 = lock, 1 = unlock */ +#define AK4117_PAR (1<<6) /* parity error or biphase error status, 0 = no error, 1 = error */ +#define AK4117_AUTO (1<<5) /* Non-PCM or DTS stream auto detection, 0 = no detect, 1 = detect */ +#define AK4117_V (1<<4) /* Validity bit, 0 = valid, 1 = invalid */ +#define AK4117_AUDION (1<<3) /* audio bit output, 0 = audio, 1 = non-audio */ +#define AK4117_STC (1<<2) /* sampling frequency or Pre-emphasis change, 0 = no detect, 1 = detect */ +#define AK4117_CINT (1<<1) /* channel status buffer interrupt, 0 = no change, 1 = change */ +#define AK4117_QINT (1<<0) /* Q-subcode buffer interrupt, 0 = no change, 1 = changed */ + +/* AK4117_REG_RCS1 */ +#define AK4117_DTSCD (1<<6) /* DTS-CD bit audio stream detect, 0 = no detect, 1 = detect */ +#define AK4117_NPCM (1<<5) /* Non-PCM bit stream detection, 0 = no detect, 1 = detect */ +#define AK4117_PEM (1<<4) /* Pre-emphasis detect, 0 = OFF, 1 = ON */ +#define AK4117_FS3 (1<<3) /* sampling frequency detection */ +#define AK4117_FS2 (1<<2) +#define AK4117_FS1 (1<<1) +#define AK4117_FS0 (1<<0) +#define AK4117_FS_44100HZ (0) +#define AK4117_FS_48000HZ (AK4117_FS1) +#define AK4117_FS_32000HZ (AK4117_FS1|AK4117_FS0) +#define AK4117_FS_88200HZ (AK4117_FS3) +#define AK4117_FS_96000HZ (AK4117_FS3|AK4117_FS1) +#define AK4117_FS_176400HZ (AK4117_FS3|AK4117_FS2) +#define AK4117_FS_192000HZ (AK4117_FS3|AK4117_FS2|AK4117_FS1) + +/* AK4117_REG_RCS2 */ +#define AK4117_CCRC (1<<1) /* CRC for channel status, 0 = no error, 1 = error */ +#define AK4117_QCRC (1<<0) /* CRC for Q-subcode, 0 = no error, 1 = error */ + +/* flags for snd_ak4117_check_rate_and_errors() */ +#define AK4117_CHECK_NO_STAT (1<<0) /* no statistics */ +#define AK4117_CHECK_NO_RATE (1<<1) /* no rate check */ + +#define AK4117_CONTROLS 13 + +typedef void (ak4117_write_t)(void *private_data, unsigned char addr, unsigned char data); +typedef unsigned char (ak4117_read_t)(void *private_data, unsigned char addr); + +typedef struct ak4117 ak4117_t; + +struct ak4117 { + snd_card_t * card; + ak4117_write_t * write; + ak4117_read_t * read; + void * private_data; + unsigned int init: 1; + spinlock_t lock; + unsigned char regmap[5]; + snd_kcontrol_t *kctls[AK4117_CONTROLS]; + snd_pcm_substream_t *substream; + unsigned long parity_errors; + unsigned long v_bit_errors; + unsigned long qcrc_errors; + unsigned long ccrc_errors; + unsigned char rcs0; + unsigned char rcs1; + unsigned char rcs2; + struct timer_list timer; /* statistic timer */ + void *change_callback_private; + void (*change_callback)(ak4117_t *ak4117, unsigned char c0, unsigned char c1); +}; + +int snd_ak4117_create(snd_card_t *card, ak4117_read_t *read, ak4117_write_t *write, + unsigned char pgm[5], void *private_data, ak4117_t **r_ak4117); +void snd_ak4117_reg_write(ak4117_t *chip, unsigned char reg, unsigned char mask, unsigned char val); +void snd_ak4117_reinit(ak4117_t *chip); +int snd_ak4117_build(ak4117_t *ak4117, snd_pcm_substream_t *capture_substream); +int snd_ak4117_external_rate(ak4117_t *ak4117); +int snd_ak4117_check_rate_and_errors(ak4117_t *ak4117, unsigned int flags); + +#endif /* __SOUND_AK4117_H */ + diff -Nru a/include/sound/asequencer.h b/include/sound/asequencer.h --- a/include/sound/asequencer.h Sun Mar 14 14:20:07 2004 +++ b/include/sound/asequencer.h Sun Mar 14 14:20:07 2004 @@ -594,6 +594,7 @@ #define SNDRV_SEQ_PORT_TYPE_MIDI_GS (1<<3) /* GS compatible device */ #define SNDRV_SEQ_PORT_TYPE_MIDI_XG (1<<4) /* XG compatible device */ #define SNDRV_SEQ_PORT_TYPE_MIDI_MT32 (1<<5) /* MT-32 compatible device */ +#define SNDRV_SEQ_PORT_TYPE_MIDI_GM2 (1<<6) /* General MIDI 2 compatible device */ /* other standards...*/ #define SNDRV_SEQ_PORT_TYPE_SYNTH (1<<10) /* Synth device (no MIDI compatible - direct wavetable) */ @@ -605,7 +606,7 @@ /* misc. conditioning flags */ #define SNDRV_SEQ_PORT_FLG_GIVEN_PORT (1<<0) #define SNDRV_SEQ_PORT_FLG_TIMESTAMP (1<<1) -#define SNDRV_SEQ_PORT_FLG_TIME_REAL (1<<1) +#define SNDRV_SEQ_PORT_FLG_TIME_REAL (1<<2) struct sndrv_seq_port_info { struct sndrv_seq_addr addr; /* client/port numbers */ diff -Nru a/include/sound/asound.h b/include/sound/asound.h --- a/include/sound/asound.h Sun Mar 14 14:20:07 2004 +++ b/include/sound/asound.h Sun Mar 14 14:20:07 2004 @@ -153,7 +153,7 @@ * * *****************************************************************************/ -#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 5) +#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 6) typedef unsigned long sndrv_pcm_uframes_t; typedef long sndrv_pcm_sframes_t; diff -Nru a/include/sound/cs46xx.h b/include/sound/cs46xx.h --- a/include/sound/cs46xx.h Sun Mar 14 14:20:06 2004 +++ b/include/sound/cs46xx.h Sun Mar 14 14:20:06 2004 @@ -1646,9 +1646,7 @@ typedef struct _snd_cs46xx cs46xx_t; typedef struct _snd_cs46xx_pcm_t { - unsigned char *hw_area; - dma_addr_t hw_addr; /* PCI bus address, not accessible */ - unsigned long hw_size; + struct snd_dma_buffer hw_buf; unsigned int ctl; unsigned int shift; /* Shift count to trasform frames in bytes */ @@ -1693,9 +1691,7 @@ unsigned int mode; struct { - unsigned char *hw_area; - dma_addr_t hw_addr; /* PCI bus address, not accessible */ - unsigned long hw_size; + struct snd_dma_buffer hw_buf; unsigned int ctl; unsigned int shift; /* Shift count to trasform frames in bytes */ @@ -1726,6 +1722,8 @@ spinlock_t reg_lock; unsigned int midcr; unsigned int uartm; + + struct snd_dma_device dma_dev; int amplifier; void (*amplifier_ctrl)(cs46xx_t *, int); diff -Nru a/include/sound/emu10k1.h b/include/sound/emu10k1.h --- a/include/sound/emu10k1.h Sun Mar 14 14:20:06 2004 +++ b/include/sound/emu10k1.h Sun Mar 14 14:20:06 2004 @@ -644,9 +644,13 @@ #define SOLEH 0x5d /* Stop on loop enable high register */ #define SPBYPASS 0x5e /* SPDIF BYPASS mode register */ -#define SPBYPASS_ENABLE 0x00000001 /* Enable SPDIF bypass mode */ +#define SPBYPASS_SPDIF0_MASK 0x00000003 /* SPDIF 0 bypass mode */ +#define SPBYPASS_SPDIF1_MASK 0x0000000c /* SPDIF 1 bypass mode */ +/* bypass mode: 0 - DSP; 1 - SPDIF A, 2 - SPDIF B, 3 - SPDIF C */ +#define SPBYPASS_FORMAT 0x00000f00 /* If 1, SPDIF XX uses 24 bit, if 0 - 20 bit */ #define AC97SLOT 0x5f /* additional AC97 slots enable bits */ +#define AC97SLOT_10K2 0x03 #define AC97SLOT_CNTR 0x10 /* Center enable */ #define AC97SLOT_LFE 0x20 /* LFE enable */ @@ -837,7 +841,7 @@ typedef struct snd_emu10k1_memblk { snd_util_memblk_t mem; /* private part */ - short first_page, last_page, pages, mapped_page; + int first_page, last_page, pages, mapped_page; unsigned int map_locked; struct list_head mapped_link; struct list_head mapped_order_link; @@ -897,9 +901,7 @@ unsigned short extout_mask; /* used external outputs (bitmask) */ unsigned short pad1; unsigned int itram_size; /* internal TRAM size in samples */ - unsigned int etram_size; /* external TRAM size in samples */ - void *etram_pages; /* allocated pages for external TRAM */ - dma_addr_t etram_pages_dmaaddr; + struct snd_dma_buffer etram_pages; /* external TRAM pages and size */ unsigned int dbg; /* FX debugger register */ unsigned char name[128]; int gpr_size; /* size of allocated GPR controls */ @@ -943,11 +945,10 @@ unsigned int card_type; /* EMU10K1_CARD_* */ unsigned int ecard_ctrl; /* ecard control bits */ unsigned long dma_mask; /* PCI DMA mask */ + struct snd_dma_device dma_dev; /* DMA device description */ int max_cache_pages; /* max memory size / PAGE_SIZE */ - void *silent_page; /* silent page */ - dma_addr_t silent_page_dmaaddr; - volatile u32 *ptb_pages; /* page table pages */ - dma_addr_t ptb_pages_dmaaddr; + struct snd_dma_buffer silent_page; /* silent page */ + struct snd_dma_buffer ptb_pages; /* page table pages */ snd_util_memhdr_t *memhdr; /* page allocation list */ emu10k1_memblk_t *reserved_page; /* reserved page */ diff -Nru a/include/sound/info.h b/include/sound/info.h --- a/include/sound/info.h Sun Mar 14 14:20:08 2004 +++ b/include/sound/info.h Sun Mar 14 14:20:08 2004 @@ -171,7 +171,7 @@ struct proc_dir_entry *de) { ; } #define snd_card_proc_new(card,name,entryp) 0 /* always success */ -#define snd_info_set_text_ops(entry,private_data,read) /*NOP*/ +#define snd_info_set_text_ops(entry,private_data,read_size,read) /*NOP*/ #endif diff -Nru a/include/sound/memalloc.h b/include/sound/memalloc.h --- a/include/sound/memalloc.h Sun Mar 14 14:20:06 2004 +++ b/include/sound/memalloc.h Sun Mar 14 14:20:06 2004 @@ -24,49 +24,33 @@ #ifndef __SOUND_MEMALLOC_H #define __SOUND_MEMALLOC_H -#include -#ifdef CONFIG_SBUS -#include -#endif +struct device; /* * buffer device info */ struct snd_dma_device { int type; /* SNDRV_MEM_TYPE_XXX */ - union { - struct pci_dev *pci; /* for PCI and PCI-SG types */ - unsigned int flags; /* GFP_XXX for continous and ISA types */ -#ifdef CONFIG_SBUS - struct sbus_dev *sbus; /* for SBUS type */ -#endif - } dev; + struct device *dev; /* generic device */ unsigned int id; /* a unique ID */ }; +#ifndef snd_dma_pci_data +#define snd_dma_pci_data(pci) (&(pci)->dev) +#define snd_dma_isa_data() NULL +#define snd_dma_sbus_data(sbus) ((struct device *)(sbus)) +#define snd_dma_continuous_data(x) ((struct device *)(unsigned long)(x)) +#endif + + /* * buffer types */ #define SNDRV_DMA_TYPE_UNKNOWN 0 /* not defined */ #define SNDRV_DMA_TYPE_CONTINUOUS 1 /* continuous no-DMA memory */ -#define SNDRV_DMA_TYPE_ISA 2 /* ISA continuous */ -#define SNDRV_DMA_TYPE_PCI 3 /* PCI continuous */ +#define SNDRV_DMA_TYPE_DEV 2 /* generic device continuous */ +#define SNDRV_DMA_TYPE_DEV_SG 3 /* generic device SG-buffer */ #define SNDRV_DMA_TYPE_SBUS 4 /* SBUS continuous */ -#define SNDRV_DMA_TYPE_PCI_SG 5 /* PCI SG-buffer */ - -#ifdef CONFIG_PCI -/* - * compose a snd_dma_device struct for the PCI device - */ -static inline void snd_dma_device_pci(struct snd_dma_device *dev, struct pci_dev *pci, unsigned int id) -{ - memset(dev, 0, sizeof(*dev)); - dev->type = SNDRV_DMA_TYPE_PCI; - dev->dev.pci = pci; - dev->id = id; -} -#endif - /* * info for buffer allocation @@ -78,67 +62,8 @@ void *private_data; /* private for allocator; don't touch */ }; -/* allocate/release a buffer */ -int snd_dma_alloc_pages(const struct snd_dma_device *dev, size_t size, struct snd_dma_buffer *dmab); -void snd_dma_free_pages(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab); - -/* buffer-preservation managements */ -size_t snd_dma_get_reserved(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab); -int snd_dma_free_reserved(const struct snd_dma_device *dev); -int snd_dma_set_reserved(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab); - - -/* - * Generic memory allocators - */ - -/* - * continuous pages - */ -void *snd_malloc_pages(size_t size, unsigned int gfp_flags); -void *snd_malloc_pages_fallback(size_t size, unsigned int gfp_flags, size_t *res_size); -void snd_free_pages(void *ptr, size_t size); - -#ifdef CONFIG_PCI -/* - * PCI continuous pages - */ -void *snd_malloc_pci_pages(struct pci_dev *pci, size_t size, dma_addr_t *dma_addr); -void *snd_malloc_pci_pages_fallback(struct pci_dev *pci, size_t size, dma_addr_t *dma_addr, size_t *res_size); -void snd_free_pci_pages(struct pci_dev *pci, size_t size, void *ptr, dma_addr_t dma_addr); -/* one page allocation */ -void *snd_malloc_pci_page(struct pci_dev *pci, dma_addr_t *dma_addr); -#define snd_free_pci_page(pci,ptr,addr) snd_free_pci_pages(pci,PAGE_SIZE,ptr,addr) -#endif - -#ifdef CONFIG_SBUS -/* - * SBUS continuous pages - */ -void *snd_malloc_sbus_pages(struct sbus_dev *sdev, size_t size, dma_addr_t *dma_addr); -void *snd_malloc_sbus_pages_fallback(struct sbus_dev *sdev, size_t size, dma_addr_t *dma_addr, size_t *res_size); -void snd_free_sbus_pages(struct sbus_dev *sdev, size_t size, void *ptr, dma_addr_t dma_addr); -#endif - -#ifdef CONFIG_ISA /* - * ISA continuous pages - */ -void *snd_malloc_isa_pages(size_t size, dma_addr_t *dma_addr); -void *snd_malloc_isa_pages_fallback(size_t size, dma_addr_t *dma_addr, size_t *res_size); -void snd_free_isa_pages(size_t size, void *ptr, dma_addr_t addr); -#ifdef CONFIG_PCI -#define snd_malloc_isa_pages(size, dma_addr) snd_malloc_pci_pages(NULL, size, dma_addr) -#define snd_malloc_isa_pages_fallback(size, dma_addr, res_size) snd_malloc_pci_pages_fallback(NULL, size, dma_addr, res_size) -#define snd_free_isa_pages(size, ptr, dma_addr) snd_free_pci_pages(NULL, size, ptr, dma_addr) -#else /* !CONFIG_PCI */ -#define snd_free_isa_pages(size, ptr, dma_addr) snd_free_pages(ptr, size) -#endif /* CONFIG_PCI */ -#endif /* CONFIG_ISA */ - -#ifdef CONFIG_PCI -/* - * Scatter-Gather PCI pages + * Scatter-Gather generic device pages */ struct snd_sg_page { void *buf; @@ -151,12 +76,9 @@ int tblsize; /* allocated table size */ struct snd_sg_page *table; /* address table */ struct page **page_table; /* page table (for vmap/vunmap) */ - struct pci_dev *pci; + struct snd_dma_device dev; }; -void *snd_malloc_sgbuf_pages(struct pci_dev *pci, size_t size, struct snd_dma_buffer *dmab); -int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab); - /* * return the pages matching with the given byte size */ @@ -172,6 +94,24 @@ { return sgbuf->table[offset >> PAGE_SHIFT].addr + offset % PAGE_SIZE; } -#endif /* CONFIG_PCI */ + + +/* allocate/release a buffer */ +int snd_dma_alloc_pages(const struct snd_dma_device *dev, size_t size, + struct snd_dma_buffer *dmab); +int snd_dma_alloc_pages_fallback(const struct snd_dma_device *dev, size_t size, + struct snd_dma_buffer *dmab); +void snd_dma_free_pages(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab); + +/* buffer-preservation managements */ +size_t snd_dma_get_reserved(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab); +int snd_dma_free_reserved(const struct snd_dma_device *dev); +int snd_dma_set_reserved(const struct snd_dma_device *dev, struct snd_dma_buffer *dmab); + +/* basic memory allocation functions */ +void *snd_malloc_pages(size_t size, unsigned int gfp_flags); +void *snd_malloc_pages_fallback(size_t size, unsigned int gfp_flags, size_t *res_size); +void snd_free_pages(void *ptr, size_t size); #endif /* __SOUND_MEMALLOC_H */ + diff -Nru a/include/sound/pcm.h b/include/sound/pcm.h --- a/include/sound/pcm.h Sun Mar 14 14:20:07 2004 +++ b/include/sound/pcm.h Sun Mar 14 14:20:07 2004 @@ -889,6 +889,9 @@ snd_pcm_sframes_t snd_pcm_lib_readv(snd_pcm_substream_t *substream, void **bufs, snd_pcm_uframes_t frames); +int snd_pcm_limit_hw_rates(snd_pcm_runtime_t *runtime); + + /* * Timer interface */ @@ -904,49 +907,18 @@ int snd_pcm_lib_preallocate_free(snd_pcm_substream_t *substream); int snd_pcm_lib_preallocate_free_for_all(snd_pcm_t *pcm); int snd_pcm_lib_preallocate_pages(snd_pcm_substream_t *substream, - size_t size, size_t max, - unsigned int flags); + int type, struct device *data, + size_t size, size_t max); int snd_pcm_lib_preallocate_pages_for_all(snd_pcm_t *pcm, - size_t size, size_t max, - unsigned int flags); + int type, void *data, + size_t size, size_t max); int snd_pcm_lib_malloc_pages(snd_pcm_substream_t *substream, size_t size); int snd_pcm_lib_free_pages(snd_pcm_substream_t *substream); -#ifdef CONFIG_ISA -int snd_pcm_lib_preallocate_isa_pages(snd_pcm_substream_t *substream, - size_t size, size_t max); -int snd_pcm_lib_preallocate_isa_pages_for_all(snd_pcm_t *pcm, - size_t size, size_t max); -#endif -#ifdef CONFIG_PCI -int snd_pcm_lib_preallocate_pci_pages(struct pci_dev *pci, - snd_pcm_substream_t *substream, - size_t size, size_t max); -int snd_pcm_lib_preallocate_pci_pages_for_all(struct pci_dev *pci, - snd_pcm_t *pcm, - size_t size, - size_t max); -int snd_pcm_lib_preallocate_sg_pages(struct pci_dev *pci, - snd_pcm_substream_t *substream, - size_t size, size_t max); -int snd_pcm_lib_preallocate_sg_pages_for_all(struct pci_dev *pci, - snd_pcm_t *pcm, - size_t size, size_t max); #define snd_pcm_substream_sgbuf(substream) ((substream)->runtime->dma_private) #define snd_pcm_sgbuf_pages(size) snd_sgbuf_aligned_pages(size) #define snd_pcm_sgbuf_get_addr(sgbuf,ofs) snd_sgbuf_get_addr(sgbuf,ofs) struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset); -#endif - -#ifdef CONFIG_SBUS -int snd_pcm_lib_preallocate_sbus_pages(struct sbus_dev *sdev, - snd_pcm_substream_t *substream, - size_t size, size_t max); -int snd_pcm_lib_preallocate_sbus_pages_for_all(struct sbus_dev *sdev, - snd_pcm_t *pcm, - size_t size, - size_t max); -#endif static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max) { diff -Nru a/include/sound/pcm_oss.h b/include/sound/pcm_oss.h --- a/include/sound/pcm_oss.h Sun Mar 14 14:20:08 2004 +++ b/include/sound/pcm_oss.h Sun Mar 14 14:20:08 2004 @@ -50,6 +50,7 @@ unsigned int maxfrags; unsigned int subdivision; /* requested subdivision */ size_t period_bytes; /* requested period size */ + size_t period_frames; /* period frames for poll */ size_t period_ptr; /* actual write pointer to period */ unsigned int periods; size_t buffer_bytes; /* requested buffer size */ diff -Nru a/include/sound/sndmagic.h b/include/sound/sndmagic.h --- a/include/sound/sndmagic.h Sun Mar 14 14:20:06 2004 +++ b/include/sound/sndmagic.h Sun Mar 14 14:20:06 2004 @@ -200,6 +200,9 @@ #define azf3328_t_magic 0xa15a4200 #define snd_card_harmony_t_magic 0xa15a4300 #define bt87x_t_magic 0xa15a4400 +#define pdacf_t_magic 0xa15a4500 +#define vortex_t_magic 0xa15a4601 +#define atiixp_t_magic 0xa15a4701 #else diff -Nru a/include/sound/trident.h b/include/sound/trident.h --- a/include/sound/trident.h Sun Mar 14 14:20:07 2004 +++ b/include/sound/trident.h Sun Mar 14 14:20:07 2004 @@ -308,11 +308,9 @@ unsigned int * entries; /* 16k-aligned TLB table */ dma_addr_t entries_dmaaddr; /* 16k-aligned PCI address to TLB table */ unsigned long * shadow_entries; /* shadow entries with virtual addresses */ - void * buffer; /* pointer for table calloc */ - dma_addr_t buffer_dmaaddr; /* not accessible PCI BUS physical address */ + struct snd_dma_buffer buffer; snd_util_memhdr_t * memhdr; /* page allocation list */ - void * silent_page; /* silent page */ - dma_addr_t silent_page_dmaaddr; /* not accessible PCI BUS physical address */ + struct snd_dma_buffer silent_page; } snd_trident_tlb_t; struct _snd_trident_voice { @@ -434,6 +432,8 @@ spinlock_t event_lock; spinlock_t voice_alloc; + + struct snd_dma_device dma_dev; struct pci_dev *pci; snd_card_t *card; diff -Nru a/include/sound/version.h b/include/sound/version.h --- a/include/sound/version.h Sun Mar 14 14:20:07 2004 +++ b/include/sound/version.h Sun Mar 14 14:20:07 2004 @@ -1,3 +1,3 @@ /* include/version.h. Generated by configure. */ -#define CONFIG_SND_VERSION "1.0.2c" -#define CONFIG_SND_DATE " (Thu Feb 05 15:41:49 2004 UTC)" +#define CONFIG_SND_VERSION "1.0.3" +#define CONFIG_SND_DATE " (Mon Mar 01 10:12:14 2004 UTC)" diff -Nru a/include/sound/ymfpci.h b/include/sound/ymfpci.h --- a/include/sound/ymfpci.h Sun Mar 14 14:20:07 2004 +++ b/include/sound/ymfpci.h Sun Mar 14 14:20:07 2004 @@ -316,9 +316,8 @@ struct gameport gameport; #endif - void *work_ptr; - dma_addr_t work_ptr_addr; - unsigned long work_ptr_size; + struct snd_dma_device dma_dev; + struct snd_dma_buffer work_ptr; unsigned int bank_size_playback; unsigned int bank_size_capture; @@ -333,8 +332,7 @@ dma_addr_t bank_base_capture_addr; dma_addr_t bank_base_effect_addr; dma_addr_t work_base_addr; - void *ac3_tmp_base; - dma_addr_t ac3_tmp_base_addr; + struct snd_dma_buffer ac3_tmp_base; u32 *ctrl_playback; snd_ymfpci_playback_bank_t *bank_playback[YDSXG_PLAYBACK_VOICES][2]; diff -Nru a/init/do_mounts.c b/init/do_mounts.c --- a/init/do_mounts.c Sun Mar 14 14:20:07 2004 +++ b/init/do_mounts.c Sun Mar 14 14:20:07 2004 @@ -66,11 +66,11 @@ /* read device number from .../dev */ sprintf(path, "/sys/block/%s/dev", name); - fd = open(path, 0, 0); + fd = sys_open(path, 0, 0); if (fd < 0) goto fail; - len = read(fd, buf, 32); - close(fd); + len = sys_read(fd, buf, 32); + sys_close(fd); if (len <= 0 || len == 32 || buf[len - 1] != '\n') goto fail; buf[len - 1] = '\0'; @@ -96,11 +96,11 @@ /* otherwise read range from .../range */ sprintf(path, "/sys/block/%s/range", name); - fd = open(path, 0, 0); + fd = sys_open(path, 0, 0); if (fd < 0) goto fail; - len = read(fd, buf, 32); - close(fd); + len = sys_read(fd, buf, 32); + sys_close(fd); if (len <= 0 || len == 32 || buf[len - 1] != '\n') goto fail; buf[len - 1] = '\0'; @@ -163,6 +163,9 @@ res = Root_NFS; if (strcmp(name, "nfs") == 0) goto done; + res = Root_RAM0; + if (strcmp(name, "ram") == 0) + goto done; if (strlen(name) > 31) goto fail; @@ -285,7 +288,7 @@ continue; } /* - * Allow the user to distinguish between failed open + * Allow the user to distinguish between failed sys_open * and bad superblock on root device. */ __bdevname(ROOT_DEV, b); @@ -324,21 +327,21 @@ va_start(args, fmt); vsprintf(buf, fmt, args); va_end(args); - fd = open("/dev/root", O_RDWR | O_NDELAY, 0); + fd = sys_open("/dev/root", O_RDWR | O_NDELAY, 0); if (fd >= 0) { sys_ioctl(fd, FDEJECT, 0); - close(fd); + sys_close(fd); } printk(KERN_NOTICE "VFS: Insert %s and press ENTER\n", buf); - fd = open("/dev/console", O_RDWR, 0); + fd = sys_open("/dev/console", O_RDWR, 0); if (fd >= 0) { sys_ioctl(fd, TCGETS, (long)&termios); termios.c_lflag &= ~ICANON; sys_ioctl(fd, TCSETSF, (long)&termios); - read(fd, &c, 1); + sys_read(fd, &c, 1); termios.c_lflag |= ICANON; sys_ioctl(fd, TCSETSF, (long)&termios); - close(fd); + sys_close(fd); } } #endif diff -Nru a/init/do_mounts.h b/init/do_mounts.h --- a/init/do_mounts.h Sun Mar 14 14:20:07 2004 +++ b/init/do_mounts.h Sun Mar 14 14:20:07 2004 @@ -1,4 +1,3 @@ -#define __KERNEL_SYSCALLS__ #include #include #include diff -Nru a/init/do_mounts_devfs.c b/init/do_mounts_devfs.c --- a/init/do_mounts_devfs.c Sun Mar 14 14:20:08 2004 +++ b/init/do_mounts_devfs.c Sun Mar 14 14:20:08 2004 @@ -24,7 +24,7 @@ { long bytes, n; char *p = buf; - lseek(fd, 0, 0); + sys_lseek(fd, 0, 0); for (bytes = 0; bytes < len; bytes += n) { n = sys_getdents64(fd, (struct linux_dirent64 *)(p + bytes), @@ -45,7 +45,7 @@ static void * __init read_dir(char *path, int *len) { int size; - int fd = open(path, 0, 0); + int fd = sys_open(path, 0, 0); *len = 0; if (fd < 0) @@ -58,7 +58,7 @@ break; n = do_read_dir(fd, p, size); if (n > 0) { - close(fd); + sys_close(fd); *len = n; return p; } @@ -68,7 +68,7 @@ if (n < 0) break; } - close(fd); + sys_close(fd); return NULL; } diff -Nru a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c --- a/init/do_mounts_initrd.c Sun Mar 14 14:20:06 2004 +++ b/init/do_mounts_initrd.c Sun Mar 14 14:20:06 2004 @@ -1,4 +1,5 @@ - +#define __KERNEL_SYSCALLS__ +#include #include #include #include @@ -28,12 +29,12 @@ static char *argv[] = { "linuxrc", NULL, }; extern char * envp_init[]; - close(old_fd);close(root_fd); - close(0);close(1);close(2); - setsid(); - (void) open("/dev/console",O_RDWR,0); - (void) dup(0); - (void) dup(0); + sys_close(old_fd);sys_close(root_fd); + sys_close(0);sys_close(1);sys_close(2); + sys_setsid(); + (void) sys_open("/dev/console",O_RDWR,0); + (void) sys_dup(0); + (void) sys_dup(0); return execve(shell, argv, envp_init); } @@ -47,8 +48,8 @@ /* mount initrd on rootfs' /root */ mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY); sys_mkdir("/old", 0700); - root_fd = open("/", 0, 0); - old_fd = open("/old", 0, 0); + root_fd = sys_open("/", 0, 0); + old_fd = sys_open("/old", 0, 0); /* move initrd over / and chdir/chroot in initrd root */ sys_chdir("/root"); sys_mount(".", "/", NULL, MS_MOVE, NULL); @@ -57,7 +58,7 @@ pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD); if (pid > 0) { - while (pid != waitpid(-1, &i, 0)) + while (pid != sys_wait4(-1, &i, 0, 0)) yield(); } @@ -67,8 +68,8 @@ /* switch root and cwd back to / of rootfs */ sys_fchdir(root_fd); sys_chroot("."); - close(old_fd); - close(root_fd); + sys_close(old_fd); + sys_close(root_fd); umount_devfs("/old/dev"); if (new_decode_dev(real_root_dev) == Root_RAM0) { @@ -84,7 +85,7 @@ if (!error) printk("okay\n"); else { - int fd = open("/dev/root.old", O_RDWR, 0); + int fd = sys_open("/dev/root.old", O_RDWR, 0); printk("failed\n"); printk(KERN_NOTICE "Unmounting old root\n"); sys_umount("/old", MNT_DETACH); @@ -93,7 +94,7 @@ error = fd; } else { error = sys_ioctl(fd, BLKFLSBUF, 0); - close(fd); + sys_close(fd); } printk(!error ? "okay\n" : "failed\n"); } diff -Nru a/init/do_mounts_md.c b/init/do_mounts_md.c --- a/init/do_mounts_md.c Sun Mar 14 14:20:08 2004 +++ b/init/do_mounts_md.c Sun Mar 14 14:20:08 2004 @@ -12,15 +12,19 @@ * The code for that is here. */ -static int __initdata raid_noautodetect; +static int __initdata raid_noautodetect, raid_autopart; static struct { - char device_set [MAX_MD_DEVS]; - int pers[MAX_MD_DEVS]; - int chunk[MAX_MD_DEVS]; - char *device_names[MAX_MD_DEVS]; -} md_setup_args __initdata; + int minor; + int partitioned; + int pers; + int chunk; + char *device_names; +} md_setup_args[MAX_MD_DEVS] __initdata; +static int md_setup_ents __initdata; + +extern int mdp_major; /* * Parse the command-line parameters given our kernel, but do not * actually try to invoke the MD device now; that is handled by @@ -43,21 +47,37 @@ */ static int __init md_setup(char *str) { - int minor, level, factor, fault, pers; + int minor, level, factor, fault, pers, partitioned = 0; char *pername = ""; - char *str1 = str; + char *str1; + int ent; + if (*str == 'd') { + partitioned = 1; + str++; + } if (get_option(&str, &minor) != 2) { /* MD Number */ printk(KERN_WARNING "md: Too few arguments supplied to md=.\n"); return 0; } + str1 = str; if (minor >= MAX_MD_DEVS) { printk(KERN_WARNING "md: md=%d, Minor device number too high.\n", minor); return 0; - } else if (md_setup_args.device_names[minor]) { - printk(KERN_WARNING "md: md=%d, Specified more than once. " - "Replacing previous definition.\n", minor); } + for (ent=0 ; ent< md_setup_ents ; ent++) + if (md_setup_args[ent].minor == minor && + md_setup_args[ent].partitioned == partitioned) { + printk(KERN_WARNING "md: md=%s%d, Specified more than once. " + "Replacing previous definition.\n", partitioned?"d":"", minor); + break; + } + if (ent >= MAX_MD_DEVS) { + printk(KERN_WARNING "md: md=%s%d - too many md initialisations\n", partitioned?"d":"", minor); + return 0; + } + if (ent >= md_setup_ents) + md_setup_ents++; switch (get_option(&str, &level)) { /* RAID Personality */ case 2: /* could be 0 or -1.. */ if (level == 0 || level == LEVEL_LINEAR) { @@ -66,24 +86,16 @@ printk(KERN_WARNING "md: Too few arguments supplied to md=.\n"); return 0; } - md_setup_args.pers[minor] = level; - md_setup_args.chunk[minor] = 1 << (factor+12); - switch(level) { - case LEVEL_LINEAR: + md_setup_args[ent].pers = level; + md_setup_args[ent].chunk = 1 << (factor+12); + if (level == LEVEL_LINEAR) { pers = LINEAR; pername = "linear"; - break; - case 0: + } else { pers = RAID0; pername = "raid0"; - break; - default: - printk(KERN_WARNING - "md: The kernel has not been configured for raid%d support!\n", - level); - return 0; } - md_setup_args.pers[minor] = pers; + md_setup_args[ent].pers = pers; break; } /* FALL THROUGH */ @@ -91,36 +103,45 @@ str = str1; /* FALL THROUGH */ case 0: - md_setup_args.pers[minor] = 0; + md_setup_args[ent].pers = 0; pername="super-block"; } printk(KERN_INFO "md: Will configure md%d (%s) from %s, below.\n", minor, pername, str); - md_setup_args.device_names[minor] = str; + md_setup_args[ent].device_names = str; + md_setup_args[ent].partitioned = partitioned; + md_setup_args[ent].minor = minor; return 1; } +#define MdpMinorShift 6 + static void __init md_setup_drive(void) { - int minor, i; + int minor, i, ent, partitioned; dev_t dev; dev_t devices[MD_SB_DISKS+1]; - for (minor = 0; minor < MAX_MD_DEVS; minor++) { + for (ent = 0; ent < md_setup_ents ; ent++) { int fd; int err = 0; char *devname; mdu_disk_info_t dinfo; char name[16], devfs_name[16]; - if (!(devname = md_setup_args.device_names[minor])) - continue; - - sprintf(name, "/dev/md%d", minor); - sprintf(devfs_name, "/dev/md/%d", minor); - create_dev(name, MKDEV(MD_MAJOR, minor), devfs_name); + minor = md_setup_args[ent].minor; + partitioned = md_setup_args[ent].partitioned; + devname = md_setup_args[ent].device_names; + + sprintf(name, "/dev/md%s%d", partitioned?"_d":"", minor); + sprintf(devfs_name, "/dev/md/%s%d", partitioned?"d":"", minor); + if (partitioned) + dev = MKDEV(mdp_major, minor << MdpMinorShift); + else + dev = MKDEV(MD_MAJOR, minor); + create_dev(name, dev, devfs_name); for (i = 0; i < MD_SB_DISKS && devname != 0; i++) { char *p; char comp_name[64]; @@ -143,34 +164,36 @@ } devices[i] = dev; - md_setup_args.device_set[minor] = 1; devname = p; } devices[i] = 0; - if (!md_setup_args.device_set[minor]) + if (!i) continue; - printk(KERN_INFO "md: Loading md%d: %s\n", minor, md_setup_args.device_names[minor]); + printk(KERN_INFO "md: Loading md%s%d: %s\n", + partitioned ? "_d" : "", minor, + md_setup_args[ent].device_names); - fd = open(name, 0, 0); + fd = sys_open(name, 0, 0); if (fd < 0) { - printk(KERN_ERR "md: open failed - cannot start array %d\n", minor); + printk(KERN_ERR "md: open failed - cannot start " + "array %s\n", name); continue; } if (sys_ioctl(fd, SET_ARRAY_INFO, 0) == -EBUSY) { printk(KERN_WARNING "md: Ignoring md=%d, already autodetected. (Use raid=noautodetect)\n", minor); - close(fd); + sys_close(fd); continue; } - if (md_setup_args.pers[minor]) { + if (md_setup_args[ent].pers) { /* non-persistent */ mdu_array_info_t ainfo; - ainfo.level = pers_to_level(md_setup_args.pers[minor]); + ainfo.level = pers_to_level(md_setup_args[ent].pers); ainfo.size = 0; ainfo.nr_disks =0; ainfo.raid_disks =0; @@ -181,7 +204,7 @@ ainfo.state = (1 << MD_SB_CLEAN); ainfo.layout = 0; - ainfo.chunk_size = md_setup_args.chunk[minor]; + ainfo.chunk_size = md_setup_args[ent].chunk; err = sys_ioctl(fd, SET_ARRAY_INFO, (long)&ainfo); for (i = 0; !err && i <= MD_SB_DISKS; i++) { dev = devices[i]; @@ -209,7 +232,7 @@ err = sys_ioctl(fd, RUN_ARRAY, 0); if (err) printk(KERN_WARNING "md: starting md%d failed\n", minor); - close(fd); + sys_close(fd); } } @@ -229,6 +252,10 @@ if (!strncmp(str, "noautodetect", wlen)) raid_noautodetect = 1; + if (strncmp(str, "partitionable", wlen)==0) + raid_autopart = 1; + if (strncmp(str, "part", wlen)==0) + raid_autopart = 1; pos += wlen+1; } return 1; @@ -243,10 +270,10 @@ if (raid_noautodetect) printk(KERN_INFO "md: Skipping autodetection of RAID arrays. (raid=noautodetect)\n"); else { - int fd = open("/dev/md0", 0, 0); + int fd = sys_open("/dev/md0", 0, 0); if (fd >= 0) { - sys_ioctl(fd, RAID_AUTORUN, 0); - close(fd); + sys_ioctl(fd, RAID_AUTORUN, raid_autopart); + sys_close(fd); } } md_setup_drive(); diff -Nru a/init/do_mounts_rd.c b/init/do_mounts_rd.c --- a/init/do_mounts_rd.c Sun Mar 14 14:20:08 2004 +++ b/init/do_mounts_rd.c Sun Mar 14 14:20:08 2004 @@ -69,8 +69,8 @@ /* * Read block 0 to test for gzipped kernel */ - lseek(fd, start_block * BLOCK_SIZE, 0); - read(fd, buf, size); + sys_lseek(fd, start_block * BLOCK_SIZE, 0); + sys_read(fd, buf, size); /* * If it matches the gzip magic numbers, return -1 @@ -104,8 +104,8 @@ /* * Read block 1 to test for minix and ext2 superblock */ - lseek(fd, (start_block+1) * BLOCK_SIZE, 0); - read(fd, buf, size); + sys_lseek(fd, (start_block+1) * BLOCK_SIZE, 0); + sys_read(fd, buf, size); /* Try minix */ if (minixsb->s_magic == MINIX_SUPER_MAGIC || @@ -131,7 +131,7 @@ start_block); done: - lseek(fd, start_block * BLOCK_SIZE, 0); + sys_lseek(fd, start_block * BLOCK_SIZE, 0); kfree(buf); return nblocks; } @@ -148,11 +148,11 @@ char rotator[4] = { '|' , '/' , '-' , '\\' }; #endif - out_fd = open("/dev/ram", O_RDWR, 0); + out_fd = sys_open("/dev/ram", O_RDWR, 0); if (out_fd < 0) goto out; - in_fd = open(from, O_RDONLY, 0); + in_fd = sys_open(from, O_RDONLY, 0); if (in_fd < 0) goto noclose_input; @@ -217,20 +217,20 @@ if (i && (i % devblocks == 0)) { printk("done disk #%d.\n", disk++); rotate = 0; - if (close(in_fd)) { + if (sys_close(in_fd)) { printk("Error closing the disk.\n"); goto noclose_input; } change_floppy("disk #%d", disk); - in_fd = open(from, O_RDONLY, 0); + in_fd = sys_open(from, O_RDONLY, 0); if (in_fd < 0) { printk("Error opening disk.\n"); goto noclose_input; } printk("Loading disk #%d... ", disk); } - read(in_fd, buf, BLOCK_SIZE); - write(out_fd, buf, BLOCK_SIZE); + sys_read(in_fd, buf, BLOCK_SIZE); + sys_write(out_fd, buf, BLOCK_SIZE); #if !defined(CONFIG_ARCH_S390) && !defined(CONFIG_PPC_ISERIES) if (!(i % 16)) { printk("%c\b", rotator[rotate & 0x3]); @@ -243,9 +243,9 @@ successful_load: res = 1; done: - close(in_fd); + sys_close(in_fd); noclose_input: - close(out_fd); + sys_close(out_fd); out: kfree(buf); sys_unlink("/dev/ram"); @@ -342,7 +342,7 @@ { if (exit_code) return -1; - insize = read(crd_infd, inbuf, INBUFSIZ); + insize = sys_read(crd_infd, inbuf, INBUFSIZ); if (insize == 0) { error("RAMDISK: ran out of compressed data"); return -1; @@ -363,7 +363,7 @@ unsigned n, written; uch *in, ch; - written = write(crd_outfd, window, outcnt); + written = sys_write(crd_outfd, window, outcnt); if (written != outcnt && unzip_error == 0) { printk(KERN_ERR "RAMDISK: incomplete write (%d != %d) %ld\n", written, outcnt, bytes_out); diff -Nru a/init/initramfs.c b/init/initramfs.c --- a/init/initramfs.c Sun Mar 14 14:20:06 2004 +++ b/init/initramfs.c Sun Mar 14 14:20:06 2004 @@ -1,10 +1,8 @@ -#define __KERNEL_SYSCALLS__ #include #include #include #include #include -#include #include #include #include diff -Nru a/init/main.c b/init/main.c --- a/init/main.c Sun Mar 14 14:20:06 2004 +++ b/init/main.c Sun Mar 14 14:20:06 2004 @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -42,6 +41,7 @@ #include #include #include +#include #include #include @@ -612,11 +612,11 @@ unlock_kernel(); system_running = 1; - if (open("/dev/console", O_RDWR, 0) < 0) + if (sys_open("/dev/console", O_RDWR, 0) < 0) printk("Warning: unable to open an initial console.\n"); - (void) dup(0); - (void) dup(0); + (void) sys_dup(0); + (void) sys_dup(0); /* * We try each of these until one succeeds. diff -Nru a/ipc/sem.c b/ipc/sem.c --- a/ipc/sem.c Sun Mar 14 14:20:07 2004 +++ b/ipc/sem.c Sun Mar 14 14:20:07 2004 @@ -993,7 +993,6 @@ } error = sem_revalidate(semid, sma, nsems, 0); if (error) { - sem_unlock(sma); unlock_semundo(); kfree(new); un = ERR_PTR(error); diff -Nru a/kernel/kthread.c b/kernel/kthread.c --- a/kernel/kthread.c Sun Mar 14 14:20:08 2004 +++ b/kernel/kthread.c Sun Mar 14 14:20:08 2004 @@ -91,7 +91,6 @@ } else { wait_for_completion(&create->started); create->result = find_task_by_pid(pid); - wait_task_inactive(create->result); } complete(&create->done); } @@ -131,7 +130,9 @@ void kthread_bind(struct task_struct *k, unsigned int cpu) { BUG_ON(k->state != TASK_INTERRUPTIBLE); - k->thread_info->cpu = cpu; + /* Must have done schedule() in kthread() before we set_task_cpu */ + wait_task_inactive(k); + set_task_cpu(k, cpu); k->cpus_allowed = cpumask_of_cpu(cpu); } diff -Nru a/kernel/module.c b/kernel/module.c --- a/kernel/module.c Sun Mar 14 14:20:08 2004 +++ b/kernel/module.c Sun Mar 14 14:20:08 2004 @@ -596,7 +596,9 @@ wait_for_zero_refcount(mod); /* Final destruction now noone is using it. */ + up(&module_mutex); mod->exit(); + down(&module_mutex); free_module(mod); out: diff -Nru a/kernel/sched.c b/kernel/sched.c --- a/kernel/sched.c Sun Mar 14 14:20:08 2004 +++ b/kernel/sched.c Sun Mar 14 14:20:08 2004 @@ -201,8 +201,9 @@ */ struct runqueue { spinlock_t lock; - unsigned long nr_running, nr_switches, expired_timestamp, - nr_uninterruptible, timestamp_last_tick; + unsigned long long nr_switches; + unsigned long nr_running, expired_timestamp, nr_uninterruptible, + timestamp_last_tick; task_t *curr, *idle; struct mm_struct *prev_mm; prio_array_t *active, *expired, arrays[2]; @@ -950,9 +951,9 @@ return sum; } -unsigned long nr_context_switches(void) +unsigned long long nr_context_switches(void) { - unsigned long i, sum = 0; + unsigned long long i, sum = 0; for_each_cpu(i) sum += cpu_rq(i)->nr_switches; diff -Nru a/kernel/signal.c b/kernel/signal.c --- a/kernel/signal.c Sun Mar 14 14:20:07 2004 +++ b/kernel/signal.c Sun Mar 14 14:20:07 2004 @@ -1051,17 +1051,23 @@ struct task_struct *p; struct list_head *l; struct pid *pid; - int err, retval = -ESRCH; + int retval; + int found; if (pgrp <= 0) return -EINVAL; + found = 0; + retval = 0; for_each_task_pid(pgrp, PIDTYPE_PGID, p, l, pid) { + int err; + + found = 1; err = group_send_sig_info(sig, info, p); - if (retval) + if (!retval) retval = err; } - return retval; + return found ? retval : -ESRCH; } int diff -Nru a/kernel/timer.c b/kernel/timer.c --- a/kernel/timer.c Sun Mar 14 14:20:08 2004 +++ b/kernel/timer.c Sun Mar 14 14:20:08 2004 @@ -677,7 +677,6 @@ if (xtime.tv_nsec >= 1000000000) { xtime.tv_nsec -= 1000000000; xtime.tv_sec++; - time_interpolator_update(NSEC_PER_SEC); second_overflow(); } } diff -Nru a/kernel/workqueue.c b/kernel/workqueue.c --- a/kernel/workqueue.c Sun Mar 14 14:20:08 2004 +++ b/kernel/workqueue.c Sun Mar 14 14:20:08 2004 @@ -333,16 +333,17 @@ int current_is_keventd(void) { struct cpu_workqueue_struct *cwq; - int cpu; + int cpu = smp_processor_id(); /* preempt-safe: keventd is per-cpu */ + int ret = 0; BUG_ON(!keventd_wq); - for_each_cpu(cpu) { - cwq = keventd_wq->cpu_wq + cpu; - if (current == cwq->thread) - return 1; - } - return 0; + cwq = keventd_wq->cpu_wq + cpu; + if (current == cwq->thread) + ret = 1; + + return ret; + } void init_workqueues(void) diff -Nru a/mm/fadvise.c b/mm/fadvise.c --- a/mm/fadvise.c Sun Mar 14 14:20:07 2004 +++ b/mm/fadvise.c Sun Mar 14 14:20:07 2004 @@ -65,9 +65,8 @@ case POSIX_FADV_DONTNEED: if (!bdi_write_congested(mapping->backing_dev_info)) filemap_flush(mapping); - start_index = offset >> PAGE_CACHE_SHIFT; - end_index = (offset + len + PAGE_CACHE_SIZE - 1) >> - PAGE_CACHE_SHIFT; + start_index = (offset + PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT; + end_index = ((offset + len) >> PAGE_CACHE_SHIFT) - 1; invalidate_mapping_pages(mapping, start_index, end_index); break; default: diff -Nru a/mm/memory.c b/mm/memory.c --- a/mm/memory.c Sun Mar 14 14:20:07 2004 +++ b/mm/memory.c Sun Mar 14 14:20:07 2004 @@ -222,7 +222,7 @@ if (is_vm_hugetlb_page(vma)) return copy_hugetlb_page_range(dst, src, vma); - pte_chain = pte_chain_alloc(GFP_ATOMIC); + pte_chain = pte_chain_alloc(GFP_ATOMIC | __GFP_NOWARN); if (!pte_chain) { spin_unlock(&dst->page_table_lock); pte_chain = pte_chain_alloc(GFP_KERNEL); @@ -335,7 +335,7 @@ pte_chain); if (pte_chain) goto cont_copy_pte_range_noset; - pte_chain = pte_chain_alloc(GFP_ATOMIC); + pte_chain = pte_chain_alloc(GFP_ATOMIC | __GFP_NOWARN); if (pte_chain) goto cont_copy_pte_range_noset; @@ -1336,7 +1336,7 @@ struct pte_chain *pte_chain; int ret; - pte_chain = pte_chain_alloc(GFP_ATOMIC); + pte_chain = pte_chain_alloc(GFP_ATOMIC | __GFP_NOWARN); if (!pte_chain) { pte_unmap(page_table); spin_unlock(&mm->page_table_lock); diff -Nru a/mm/mempool.c b/mm/mempool.c --- a/mm/mempool.c Sun Mar 14 14:20:07 2004 +++ b/mm/mempool.c Sun Mar 14 14:20:07 2004 @@ -209,6 +209,7 @@ * If the pool is less than 50% full and we can perform effective * page reclaim then try harder to allocate an element. */ + mb(); if ((gfp_mask & __GFP_FS) && (gfp_mask != gfp_nowait) && (pool->curr_nr <= pool->min_nr/2)) { element = pool->alloc(gfp_mask, pool->pool_data); @@ -236,6 +237,7 @@ blk_run_queues(); prepare_to_wait(&pool->wait, &wait, TASK_UNINTERRUPTIBLE); + mb(); if (!pool->curr_nr) io_schedule(); finish_wait(&pool->wait, &wait); @@ -256,6 +258,7 @@ { unsigned long flags; + mb(); if (pool->curr_nr < pool->min_nr) { spin_lock_irqsave(&pool->lock, flags); if (pool->curr_nr < pool->min_nr) { diff -Nru a/mm/mmap.c b/mm/mmap.c --- a/mm/mmap.c Sun Mar 14 14:20:07 2004 +++ b/mm/mmap.c Sun Mar 14 14:20:07 2004 @@ -138,17 +138,34 @@ } #ifdef DEBUG_MM_RB -static int browse_rb(struct rb_node * rb_node) { - int i = 0; - if (rb_node) { +static int browse_rb(struct rb_root *root) { + int i, j; + struct rb_node *nd, *pn = NULL; + i = 0; + unsigned long prev = 0, pend = 0; + + for (nd = rb_first(root); nd; nd = rb_next(nd)) { + struct vm_area_struct *vma; + vma = rb_entry(nd, struct vm_area_struct, vm_rb); + if (vma->vm_start < prev) + printk("vm_start %lx prev %lx\n", vma->vm_start, prev), i = -1; + if (vma->vm_start < pend) + printk("vm_start %lx pend %lx\n", vma->vm_start, pend); + if (vma->vm_start > vma->vm_end) + printk("vm_end %lx < vm_start %lx\n", vma->vm_end, vma->vm_start); i++; - i += browse_rb(rb_node->rb_left); - i += browse_rb(rb_node->rb_right); + pn = nd; + } + j = 0; + for (nd = pn; nd; nd = rb_prev(nd)) { + j++; } + if (i != j) + printk("backwards %d, forwards %d\n", j, i), i = 0; return i; } -static void validate_mm(struct mm_struct * mm) { +void validate_mm(struct mm_struct * mm) { int bug = 0; int i = 0; struct vm_area_struct * tmp = mm->mmap; @@ -158,7 +175,7 @@ } if (i != mm->map_count) printk("map_count %d vm_next %d\n", mm->map_count, i), bug = 1; - i = browse_rb(mm->mm_rb.rb_node); + i = browse_rb(&mm->mm_rb); if (i != mm->map_count) printk("map_count %d rb %d\n", mm->map_count, i), bug = 1; if (bug) diff -Nru a/mm/page_alloc.c b/mm/page_alloc.c --- a/mm/page_alloc.c Sun Mar 14 14:20:06 2004 +++ b/mm/page_alloc.c Sun Mar 14 14:20:06 2004 @@ -518,7 +518,7 @@ if (page != NULL) { BUG_ON(bad_range(zone, page)); - mod_page_state(pgalloc, 1 << order); + mod_page_state_zone(zone, pgalloc, 1 << order); prep_new_page(page, order); } return page; @@ -690,6 +690,42 @@ EXPORT_SYMBOL(__alloc_pages); +#ifdef CONFIG_NUMA +/* Early boot: Everything is done by one cpu, but the data structures will be + * used by all cpus - spread them on all nodes. + */ +static __init unsigned long get_boot_pages(unsigned int gfp_mask, unsigned int order) +{ +static int nodenr; + int i = nodenr; + struct page *page; + + for (;;) { + if (i > nodenr + numnodes) + return 0; + if (node_present_pages(i%numnodes)) { + struct zone **z; + /* The node contains memory. Check that there is + * memory in the intended zonelist. + */ + z = NODE_DATA(i%numnodes)->node_zonelists[gfp_mask & GFP_ZONEMASK].zones; + while (*z) { + if ( (*z)->free_pages > (1UL<name, K(zone->free_pages), @@ -1028,7 +1069,8 @@ K(zone->pages_low), K(zone->pages_high), K(zone->nr_active), - K(zone->nr_inactive) + K(zone->nr_inactive), + K(zone->present_pages) ); } @@ -1088,6 +1130,112 @@ return j; } +#ifdef CONFIG_NUMA +#define MAX_NODE_LOAD (numnodes) +static int __initdata node_load[MAX_NUMNODES]; +/** + * find_next_best_node - find the next node that should appear in a given + * node's fallback list + * @node: node whose fallback list we're appending + * @used_node_mask: pointer to the bitmap of already used nodes + * + * We use a number of factors to determine which is the next node that should + * appear on a given node's fallback list. The node should not have appeared + * already in @node's fallback list, and it should be the next closest node + * according to the distance array (which contains arbitrary distance values + * from each node to each node in the system), and should also prefer nodes + * with no CPUs, since presumably they'll have very little allocation pressure + * on them otherwise. + * It returns -1 if no node is found. + */ +static int __init find_next_best_node(int node, void *used_node_mask) +{ + int i, n, val; + int min_val = INT_MAX; + int best_node = -1; + + for (i = 0; i < numnodes; i++) { + cpumask_t tmp; + + /* Start from local node */ + n = (node+i)%numnodes; + + /* Don't want a node to appear more than once */ + if (test_bit(n, used_node_mask)) + continue; + + /* Use the distance array to find the distance */ + val = node_distance(node, n); + + /* Give preference to headless and unused nodes */ + tmp = node_to_cpumask(n); + if (!cpus_empty(tmp)) + val += PENALTY_FOR_NODE_WITH_CPUS; + + /* Slight preference for less loaded node */ + val *= (MAX_NODE_LOAD*MAX_NUMNODES); + val += node_load[n]; + + if (val < min_val) { + min_val = val; + best_node = n; + } + } + + if (best_node >= 0) + set_bit(best_node, used_node_mask); + + return best_node; +} + +static void __init build_zonelists(pg_data_t *pgdat) +{ + int i, j, k, node, local_node; + int prev_node, load; + struct zonelist *zonelist; + DECLARE_BITMAP(used_mask, MAX_NUMNODES); + + /* initialize zonelists */ + for (i = 0; i < MAX_NR_ZONES; i++) { + zonelist = pgdat->node_zonelists + i; + memset(zonelist, 0, sizeof(*zonelist)); + zonelist->zones[0] = NULL; + } + + /* NUMA-aware ordering of nodes */ + local_node = pgdat->node_id; + load = numnodes; + prev_node = local_node; + CLEAR_BITMAP(used_mask, MAX_NUMNODES); + while ((node = find_next_best_node(local_node, used_mask)) >= 0) { + /* + * We don't want to pressure a particular node. + * So adding penalty to the first node in same + * distance group to make it round-robin. + */ + if (node_distance(local_node, node) != + node_distance(local_node, prev_node)) + node_load[node] += load; + prev_node = node; + load--; + for (i = 0; i < MAX_NR_ZONES; i++) { + zonelist = pgdat->node_zonelists + i; + for (j = 0; zonelist->zones[j] != NULL; j++); + + k = ZONE_NORMAL; + if (i & __GFP_HIGHMEM) + k = ZONE_HIGHMEM; + if (i & __GFP_DMA) + k = ZONE_DMA; + + j = build_zonelists_node(NODE_DATA(node), zonelist, j, k); + zonelist->zones[j] = NULL; + } + } +} + +#else /* CONFIG_NUMA */ + static void __init build_zonelists(pg_data_t *pgdat) { int i, j, k, node, local_node; @@ -1124,6 +1272,8 @@ } } +#endif /* CONFIG_NUMA */ + void __init build_all_zonelists(void) { int i; @@ -1298,7 +1448,8 @@ zone_names[j], realsize, batch); INIT_LIST_HEAD(&zone->active_list); INIT_LIST_HEAD(&zone->inactive_list); - atomic_set(&zone->refill_counter, 0); + atomic_set(&zone->nr_scan_active, 0); + atomic_set(&zone->nr_scan_inactive, 0); zone->nr_active = 0; zone->nr_inactive = 0; if (!size) @@ -1481,23 +1632,38 @@ "pgpgout", "pswpin", "pswpout", - "pgalloc", + "pgalloc_high", + "pgalloc_normal", + "pgalloc_dma", "pgfree", "pgactivate", "pgdeactivate", + "pgfault", "pgmajfault", - - "pgscan", - "pgrefill", - "pgsteal", + "pgrefill_high", + "pgrefill_normal", + "pgrefill_dma", + + "pgsteal_high", + "pgsteal_normal", + "pgsteal_dma", + "pgscan_kswapd_high", + "pgscan_kswapd_normal", + + "pgscan_kswapd_dma", + "pgscan_direct_high", + "pgscan_direct_normal", + "pgscan_direct_dma", "pginodesteal", - "kswapd_steal", + "slabs_scanned", + "kswapd_steal", "kswapd_inodesteal", "pageoutrun", "allocstall", + "pgrotated", }; diff -Nru a/mm/readahead.c b/mm/readahead.c --- a/mm/readahead.c Sun Mar 14 14:20:06 2004 +++ b/mm/readahead.c Sun Mar 14 14:20:06 2004 @@ -30,6 +30,7 @@ { memset(ra, 0, sizeof(*ra)); ra->ra_pages = mapping->backing_dev_info->ra_pages; + ra->average = ra->ra_pages / 2; } EXPORT_SYMBOL(file_ra_state_init); @@ -380,9 +381,18 @@ */ first_access=1; ra->next_size = max / 2; + ra->prev_page = offset; + ra->serial_cnt++; goto do_io; } + if (offset == ra->prev_page + 1) { + if (ra->serial_cnt <= (max * 2)) + ra->serial_cnt++; + } else { + ra->average = (ra->average + ra->serial_cnt) / 2; + ra->serial_cnt = 1; + } preoffset = ra->prev_page; ra->prev_page = offset; @@ -449,8 +459,12 @@ * accessed in the current window, there * is a high probability that around 'n' pages * shall be used in the next current window. + * + * To minimize lazy-readahead triggered + * in the next current window, read in + * an extra page. */ - ra->next_size = preoffset - ra->start + 1; + ra->next_size = preoffset - ra->start + 2; } ra->start = offset; ra->size = ra->next_size; @@ -468,17 +482,34 @@ } } else { /* - * This read request is within the current window. It is time - * to submit I/O for the ahead window while the application is - * crunching through the current window. + * This read request is within the current window. It may be + * time to submit I/O for the ahead window while the + * application is about to step into the ahead window. */ if (ra->ahead_start == 0) { - ra->ahead_start = ra->start + ra->size; - ra->ahead_size = ra->next_size; - actual = do_page_cache_readahead(mapping, filp, + /* + * if the average io-size is less than maximum + * readahead size of the file the io pattern is + * sequential. Hence bring in the readahead window + * immediately. + * Else the i/o pattern is random. Bring + * in the readahead window only if the last page of + * the current window is accessed (lazy readahead). + */ + unsigned long average = ra->average; + + if (ra->serial_cnt > average) + average = (ra->serial_cnt + ra->average) / 2; + + if ((average >= max) || (offset == (ra->start + + ra->size - 1))) { + ra->ahead_start = ra->start + ra->size; + ra->ahead_size = ra->next_size; + actual = do_page_cache_readahead(mapping, filp, ra->ahead_start, ra->ahead_size); - check_ra_success(ra, ra->ahead_size, - actual, orig_next_size); + check_ra_success(ra, ra->ahead_size, + actual, orig_next_size); + } } } out: diff -Nru a/mm/slab.c b/mm/slab.c --- a/mm/slab.c Sun Mar 14 14:20:08 2004 +++ b/mm/slab.c Sun Mar 14 14:20:08 2004 @@ -445,8 +445,8 @@ /* * Do not go above this order unless 0 objects fit into the slab. */ -#define BREAK_GFP_ORDER_HI 2 -#define BREAK_GFP_ORDER_LO 1 +#define BREAK_GFP_ORDER_HI 1 +#define BREAK_GFP_ORDER_LO 0 static int slab_break_gfp_order = BREAK_GFP_ORDER_LO; /* Macros for storing/retrieving the cachep and or slab from the diff -Nru a/mm/truncate.c b/mm/truncate.c --- a/mm/truncate.c Sun Mar 14 14:20:08 2004 +++ b/mm/truncate.c Sun Mar 14 14:20:08 2004 @@ -219,6 +219,8 @@ ret += invalidate_complete_page(mapping, page); unlock: unlock_page(page); + if (next > end) + break; } pagevec_release(&pvec); cond_resched(); diff -Nru a/mm/vmscan.c b/mm/vmscan.c --- a/mm/vmscan.c Sun Mar 14 14:20:06 2004 +++ b/mm/vmscan.c Sun Mar 14 14:20:06 2004 @@ -43,14 +43,15 @@ int vm_swappiness = 60; static long total_memory; +#define lru_to_page(_head) (list_entry((_head)->prev, struct page, lru)) + #ifdef ARCH_HAS_PREFETCH #define prefetch_prev_lru_page(_page, _base, _field) \ do { \ if ((_page)->lru.prev != _base) { \ struct page *prev; \ \ - prev = list_entry(_page->lru.prev, \ - struct page, lru); \ + prev = lru_to_page(&(_page->lru)); \ prefetch(&prev->_field); \ } \ } while (0) @@ -64,8 +65,7 @@ if ((_page)->lru.prev != _base) { \ struct page *prev; \ \ - prev = list_entry(_page->lru.prev, \ - struct page, lru); \ + prev = lru_to_page(&(_page->lru)); \ prefetchw(&prev->_field); \ } \ } while (0) @@ -135,7 +135,7 @@ * * We do weird things to avoid (scanned*seeks*entries) overflowing 32 bits. */ -static int shrink_slab(long scanned, unsigned int gfp_mask) +static int shrink_slab(unsigned long scanned, unsigned int gfp_mask) { struct shrinker *shrinker; long pages; @@ -147,7 +147,7 @@ list_for_each_entry(shrinker, &shrinker_list, list) { unsigned long long delta; - delta = 4 * (scanned / shrinker->seeks); + delta = (4 * scanned) / shrinker->seeks; delta *= (*shrinker->shrinker)(0, gfp_mask); do_div(delta, pages + 1); shrinker->nr += delta; @@ -155,6 +155,7 @@ long nr_to_scan = shrinker->nr; shrinker->nr = 0; + mod_page_state(slabs_scanned, nr_to_scan); while (nr_to_scan) { long this_scan = nr_to_scan; @@ -243,8 +244,7 @@ * shrink_list returns the number of reclaimed pages */ static int -shrink_list(struct list_head *page_list, unsigned int gfp_mask, - int *max_scan, int *nr_mapped) +shrink_list(struct list_head *page_list, unsigned int gfp_mask, int *nr_scanned) { struct address_space *mapping; LIST_HEAD(ret_pages); @@ -260,7 +260,7 @@ int may_enter_fs; int referenced; - page = list_entry(page_list->prev, struct page, lru); + page = lru_to_page(page_list); list_del(&page->lru); if (TestSetPageLocked(page)) @@ -268,7 +268,7 @@ /* Double the slab pressure for mapped and swapcache pages */ if (page_mapped(page) || PageSwapCache(page)) - (*nr_mapped)++; + (*nr_scanned)++; BUG_ON(PageActive(page)); @@ -459,9 +459,6 @@ list_splice(&ret_pages, page_list); if (pagevec_count(&freed_pvec)) __pagevec_release_nonlru(&freed_pvec); - mod_page_state(pgsteal, ret); - if (current_is_kswapd()) - mod_page_state(kswapd_steal, ret); mod_page_state(pgactivate, pgactivate); return ret; } @@ -471,42 +468,33 @@ * a batch of pages and working on them outside the lock. Any pages which were * not freed will be added back to the LRU. * - * shrink_cache() is passed the number of pages to try to free, and returns - * the number of pages which were reclaimed. + * shrink_cache() is passed the number of pages to scan and returns the number + * of pages which were reclaimed. * * For pagecache intensive workloads, the first loop here is the hottest spot * in the kernel (apart from the copy_*_user functions). */ static int -shrink_cache(const int nr_pages, struct zone *zone, - unsigned int gfp_mask, int max_scan, int *nr_mapped) +shrink_cache(struct zone *zone, unsigned int gfp_mask, + int max_scan, int *total_scanned) { LIST_HEAD(page_list); struct pagevec pvec; - int nr_to_process; int ret = 0; - /* - * Try to ensure that we free `nr_pages' pages in one pass of the loop. - */ - nr_to_process = nr_pages; - if (nr_to_process < SWAP_CLUSTER_MAX) - nr_to_process = SWAP_CLUSTER_MAX; - pagevec_init(&pvec, 1); lru_add_drain(); spin_lock_irq(&zone->lru_lock); - while (max_scan > 0 && ret < nr_pages) { + while (max_scan > 0) { struct page *page; int nr_taken = 0; int nr_scan = 0; int nr_freed; - while (nr_scan++ < nr_to_process && + while (nr_scan++ < SWAP_CLUSTER_MAX && !list_empty(&zone->inactive_list)) { - page = list_entry(zone->inactive_list.prev, - struct page, lru); + page = lru_to_page(&zone->inactive_list); prefetchw_prev_lru_page(page, &zone->inactive_list, flags); @@ -532,9 +520,16 @@ goto done; max_scan -= nr_scan; - mod_page_state(pgscan, nr_scan); - nr_freed = shrink_list(&page_list, gfp_mask, - &max_scan, nr_mapped); + if (current_is_kswapd()) + mod_page_state_zone(zone, pgscan_kswapd, nr_scan); + else + mod_page_state_zone(zone, pgscan_direct, nr_scan); + nr_freed = shrink_list(&page_list, gfp_mask, total_scanned); + *total_scanned += nr_taken; + if (current_is_kswapd()) + mod_page_state(kswapd_steal, nr_freed); + mod_page_state_zone(zone, pgsteal, nr_freed); + ret += nr_freed; if (nr_freed <= 0 && list_empty(&page_list)) goto done; @@ -544,7 +539,7 @@ * Put back any unfreeable pages. */ while (!list_empty(&page_list)) { - page = list_entry(page_list.prev, struct page, lru); + page = lru_to_page(&page_list); if (TestSetPageLRU(page)) BUG(); list_del(&page->lru); @@ -584,7 +579,7 @@ */ static void refill_inactive_zone(struct zone *zone, const int nr_pages_in, - struct page_state *ps, int priority) + struct page_state *ps) { int pgmoved; int pgdeactivate = 0; @@ -603,7 +598,7 @@ pgmoved = 0; spin_lock_irq(&zone->lru_lock); while (nr_pages && !list_empty(&zone->active_list)) { - page = list_entry(zone->active_list.prev, struct page, lru); + page = lru_to_page(&zone->active_list); prefetchw_prev_lru_page(page, &zone->active_list, flags); if (!TestClearPageLRU(page)) BUG(); @@ -654,20 +649,20 @@ reclaim_mapped = 1; while (!list_empty(&l_hold)) { - page = list_entry(l_hold.prev, struct page, lru); + page = lru_to_page(&l_hold); list_del(&page->lru); if (page_mapped(page)) { - pte_chain_lock(page); - if (page_mapped(page) && page_referenced(page)) { - pte_chain_unlock(page); + if (!reclaim_mapped) { list_add(&page->lru, &l_active); continue; } - pte_chain_unlock(page); - if (!reclaim_mapped) { + pte_chain_lock(page); + if (page_referenced(page)) { + pte_chain_unlock(page); list_add(&page->lru, &l_active); continue; } + pte_chain_unlock(page); } /* * FIXME: need to consider page_count(page) here if/when we @@ -685,7 +680,7 @@ pgmoved = 0; spin_lock_irq(&zone->lru_lock); while (!list_empty(&l_inactive)) { - page = list_entry(l_inactive.prev, struct page, lru); + page = lru_to_page(&l_inactive); prefetchw_prev_lru_page(page, &l_inactive, flags); if (TestSetPageLRU(page)) BUG(); @@ -714,7 +709,7 @@ pgmoved = 0; while (!list_empty(&l_active)) { - page = list_entry(l_active.prev, struct page, lru); + page = lru_to_page(&l_active); prefetchw_prev_lru_page(page, &l_active, flags); if (TestSetPageLRU(page)) BUG(); @@ -733,20 +728,20 @@ spin_unlock_irq(&zone->lru_lock); pagevec_release(&pvec); - mod_page_state(pgrefill, nr_pages_in - nr_pages); + mod_page_state_zone(zone, pgrefill, nr_pages_in - nr_pages); mod_page_state(pgdeactivate, pgdeactivate); } /* - * Try to reclaim `nr_pages' from this zone. Returns the number of reclaimed - * pages. This is a basic per-zone page freer. Used by both kswapd and - * direct reclaim. + * Scan `nr_pages' from this zone. Returns the number of reclaimed pages. + * This is a basic per-zone page freer. Used by both kswapd and direct reclaim. */ static int shrink_zone(struct zone *zone, int max_scan, unsigned int gfp_mask, - const int nr_pages, int *nr_mapped, struct page_state *ps, int priority) + int *total_scanned, struct page_state *ps) { unsigned long ratio; + int count; /* * Try to keep the active list 2/3 of the size of the cache. And @@ -758,26 +753,23 @@ * just to make sure that the kernel will slowly sift through the * active list. */ - ratio = (unsigned long)nr_pages * zone->nr_active / + ratio = (unsigned long)SWAP_CLUSTER_MAX * zone->nr_active / ((zone->nr_inactive | 1) * 2); - atomic_add(ratio+1, &zone->refill_counter); - if (atomic_read(&zone->refill_counter) > SWAP_CLUSTER_MAX) { - int count; - /* - * Don't try to bring down too many pages in one attempt. - * If this fails, the caller will increase `priority' and - * we'll try again, with an increased chance of reclaiming - * mapped memory. - */ - count = atomic_read(&zone->refill_counter); - if (count > SWAP_CLUSTER_MAX * 4) - count = SWAP_CLUSTER_MAX * 4; - atomic_set(&zone->refill_counter, 0); - refill_inactive_zone(zone, count, ps, priority); + atomic_add(ratio+1, &zone->nr_scan_active); + count = atomic_read(&zone->nr_scan_active); + if (count >= SWAP_CLUSTER_MAX) { + atomic_set(&zone->nr_scan_active, 0); + refill_inactive_zone(zone, count, ps); } - return shrink_cache(nr_pages, zone, gfp_mask, - max_scan, nr_mapped); + + atomic_add(max_scan, &zone->nr_scan_inactive); + count = atomic_read(&zone->nr_scan_inactive); + if (count >= SWAP_CLUSTER_MAX) { + atomic_set(&zone->nr_scan_inactive, 0); + return shrink_cache(zone, gfp_mask, count, total_scanned); + } + return 0; } /* @@ -798,15 +790,13 @@ */ static int shrink_caches(struct zone **zones, int priority, int *total_scanned, - int gfp_mask, int nr_pages, struct page_state *ps) + int gfp_mask, struct page_state *ps) { int ret = 0; int i; for (i = 0; zones[i] != NULL; i++) { - int to_reclaim = max(nr_pages, SWAP_CLUSTER_MAX); struct zone *zone = zones[i]; - int nr_mapped = 0; int max_scan; if (zone->free_pages < zone->pages_high) @@ -815,18 +805,8 @@ if (zone->all_unreclaimable && priority != DEF_PRIORITY) continue; /* Let kswapd poll it */ - /* - * If we cannot reclaim `nr_pages' pages by scanning twice - * that many pages then fall back to the next zone. - */ max_scan = zone->nr_inactive >> priority; - if (max_scan < to_reclaim * 2) - max_scan = to_reclaim * 2; - ret += shrink_zone(zone, max_scan, gfp_mask, - to_reclaim, &nr_mapped, ps, priority); - *total_scanned += max_scan + nr_mapped; - if (ret >= nr_pages) - break; + ret += shrink_zone(zone, max_scan, gfp_mask, total_scanned, ps); } return ret; } @@ -853,7 +833,6 @@ { int priority; int ret = 0; - const int nr_pages = SWAP_CLUSTER_MAX; int nr_reclaimed = 0; struct reclaim_state *reclaim_state = current->reclaim_state; int i; @@ -869,8 +848,13 @@ get_page_state(&ps); nr_reclaimed += shrink_caches(zones, priority, &total_scanned, - gfp_mask, nr_pages, &ps); - if (nr_reclaimed >= nr_pages) { + gfp_mask, &ps); + shrink_slab(total_scanned, gfp_mask); + if (reclaim_state) { + nr_reclaimed += reclaim_state->reclaimed_slab; + reclaim_state->reclaimed_slab = 0; + } + if (nr_reclaimed >= SWAP_CLUSTER_MAX) { ret = 1; goto out; } @@ -884,14 +868,8 @@ wakeup_bdflush(total_scanned); /* Take a nap, wait for some writeback to complete */ - blk_congestion_wait(WRITE, HZ/10); - if (zones[0] - zones[0]->zone_pgdat->node_zones < ZONE_HIGHMEM) { - shrink_slab(total_scanned, gfp_mask); - if (reclaim_state) { - nr_reclaimed += reclaim_state->reclaimed_slab; - reclaim_state->reclaimed_slab = 0; - } - } + if (total_scanned && priority < DEF_PRIORITY - 2) + blk_congestion_wait(WRITE, HZ/10); } if ((gfp_mask & __GFP_FS) && !(gfp_mask & __GFP_NORETRY)) out_of_memory(); @@ -918,6 +896,13 @@ * scanned twice and there has been zero successful reclaim. Mark the zone as * dead and from now on, only perform a short scan. Basically we're polling * the zone for when the problem goes away. + * + * kswapd scans the zones in the highmem->normal->dma direction. It skips + * zones which have free_pages > pages_high, but once a zone is found to have + * free_pages <= pages_high, we scan that zone and the lower zones regardless + * of the number of free pages in the lower zones. This interoperates with + * the page allocator fallback scheme to ensure that aging of pages is balanced + * across the zones. */ static int balance_pgdat(pg_data_t *pgdat, int nr_pages, struct page_state *ps) { @@ -936,48 +921,80 @@ for (priority = DEF_PRIORITY; priority; priority--) { int all_zones_ok = 1; + int pages_scanned = 0; + int end_zone = 0; /* Inclusive. 0 = ZONE_DMA */ + + + if (nr_pages == 0) { + /* + * Scan in the highmem->dma direction for the highest + * zone which needs scanning + */ + for (i = pgdat->nr_zones - 1; i >= 0; i--) { + struct zone *zone = pgdat->node_zones + i; - for (i = 0; i < pgdat->nr_zones; i++) { + if (zone->all_unreclaimable && + priority != DEF_PRIORITY) + continue; + + if (zone->free_pages <= zone->pages_high) { + end_zone = i; + goto scan; + } + } + goto out; + } else { + end_zone = pgdat->nr_zones - 1; + } +scan: + /* + * Now scan the zone in the dma->highmem direction, stopping + * at the last zone which needs scanning. + * + * We do this because the page allocator works in the opposite + * direction. This prevents the page allocator from allocating + * pages behind kswapd's direction of progress, which would + * cause too much scanning of the lower zones. + */ + for (i = 0; i <= end_zone; i++) { struct zone *zone = pgdat->node_zones + i; - int nr_mapped = 0; + int total_scanned = 0; int max_scan; - int to_reclaim; + int reclaimed; if (zone->all_unreclaimable && priority != DEF_PRIORITY) continue; - if (nr_pages && to_free > 0) { /* Software suspend */ - to_reclaim = min(to_free, SWAP_CLUSTER_MAX*8); - } else { /* Zone balancing */ - to_reclaim = zone->pages_high-zone->free_pages; - if (to_reclaim <= 0) - continue; + if (nr_pages == 0) { /* Not software suspend */ + if (zone->free_pages <= zone->pages_high) + all_zones_ok = 0; } zone->temp_priority = priority; - all_zones_ok = 0; max_scan = zone->nr_inactive >> priority; - if (max_scan < to_reclaim * 2) - max_scan = to_reclaim * 2; - if (max_scan < SWAP_CLUSTER_MAX) - max_scan = SWAP_CLUSTER_MAX; - to_free -= shrink_zone(zone, max_scan, GFP_KERNEL, - to_reclaim, &nr_mapped, ps, priority); - if (i < ZONE_HIGHMEM) { - reclaim_state->reclaimed_slab = 0; - shrink_slab(max_scan + nr_mapped, GFP_KERNEL); - to_free -= reclaim_state->reclaimed_slab; - } + reclaimed = shrink_zone(zone, max_scan, GFP_KERNEL, + &total_scanned, ps); + total_scanned += pages_scanned; + reclaim_state->reclaimed_slab = 0; + shrink_slab(total_scanned, GFP_KERNEL); + reclaimed += reclaim_state->reclaimed_slab; + to_free -= reclaimed; if (zone->all_unreclaimable) continue; if (zone->pages_scanned > zone->present_pages * 2) zone->all_unreclaimable = 1; } + if (nr_pages && to_free > 0) + continue; /* swsusp: need to do more work */ if (all_zones_ok) - break; - if (to_free > 0) + break; /* kswapd: all done */ + /* + * OK, kswapd is getting into trouble. Take a nap, then take + * another pass across the zones. + */ + if (pages_scanned && priority < DEF_PRIORITY - 2) blk_congestion_wait(WRITE, HZ/10); } - +out: for (i = 0; i < pgdat->nr_zones; i++) { struct zone *zone = pgdat->node_zones + i; diff -Nru a/net/Kconfig b/net/Kconfig --- a/net/Kconfig Sun Mar 14 14:20:06 2004 +++ b/net/Kconfig Sun Mar 14 14:20:06 2004 @@ -658,4 +658,20 @@ source "net/bluetooth/Kconfig" +config NETPOLL + def_bool NETCONSOLE + +config NETPOLL_RX + bool "Netpoll support for trapping incoming packets" + default n + depends on NETPOLL + +config NETPOLL_TRAP + bool "Netpoll traffic trapping" + default n + depends on NETPOLL + +config NET_POLL_CONTROLLER + def_bool NETPOLL + endmenu diff -Nru a/net/core/Makefile b/net/core/Makefile --- a/net/core/Makefile Sun Mar 14 14:20:08 2004 +++ b/net/core/Makefile Sun Mar 14 14:20:08 2004 @@ -13,3 +13,4 @@ obj-$(CONFIG_NET_DIVERT) += dv.o obj-$(CONFIG_NET_PKTGEN) += pktgen.o obj-$(CONFIG_NET_RADIO) += wireless.o +obj-$(CONFIG_NETPOLL) += netpoll.o diff -Nru a/net/core/dev.c b/net/core/dev.c --- a/net/core/dev.c Sun Mar 14 14:20:07 2004 +++ b/net/core/dev.c Sun Mar 14 14:20:07 2004 @@ -105,6 +105,7 @@ #include #include #include +#include #ifdef CONFIG_NET_RADIO #include /* Note : will define WIRELESS_EXT */ #include @@ -1538,6 +1539,13 @@ struct softnet_data *queue; unsigned long flags; +#ifdef CONFIG_NETPOLL_RX + if (skb->dev->netpoll_rx && netpoll_rx(skb)) { + kfree_skb(skb); + return NET_RX_DROP; + } +#endif + if (!skb->stamp.tv_sec) do_gettimeofday(&skb->stamp); @@ -1692,6 +1700,13 @@ struct packet_type *ptype, *pt_prev; int ret = NET_RX_DROP; unsigned short type; + +#ifdef CONFIG_NETPOLL_RX + if (skb->dev->netpoll_rx && skb->dev->poll && netpoll_rx(skb)) { + kfree_skb(skb); + return NET_RX_DROP; + } +#endif if (!skb->stamp.tv_sec) do_gettimeofday(&skb->stamp); diff -Nru a/net/core/netpoll.c b/net/core/netpoll.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/core/netpoll.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,651 @@ +/* + * Common framework for low-level network console, dump, and debugger code + * + * Sep 8 2003 Matt Mackall + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * We maintain a small pool of fully-sized skbs, to make sure the + * message gets out even in extreme OOM situations. + */ + +#define MAX_SKBS 32 +#define MAX_UDP_CHUNK 1460 + +static spinlock_t skb_list_lock = SPIN_LOCK_UNLOCKED; +static int nr_skbs; +static struct sk_buff *skbs; + +static spinlock_t rx_list_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD(rx_list); + +static int trapped; + +#define MAX_SKB_SIZE \ + (MAX_UDP_CHUNK + sizeof(struct udphdr) + \ + sizeof(struct iphdr) + sizeof(struct ethhdr)) + +static void zap_completion_queue(void); + +static int checksum_udp(struct sk_buff *skb, struct udphdr *uh, + unsigned short ulen, u32 saddr, u32 daddr) +{ + if (uh->check == 0) + return 0; + + if (skb->ip_summed == CHECKSUM_HW) + return csum_tcpudp_magic( + saddr, daddr, ulen, IPPROTO_UDP, skb->csum); + + skb->csum = csum_tcpudp_nofold(saddr, daddr, ulen, IPPROTO_UDP, 0); + + return csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)); +} + +void netpoll_poll(struct netpoll *np) +{ + int budget = 1; + + if(!np->dev || !netif_running(np->dev) || !np->dev->poll_controller) + return; + + /* Process pending work on NIC */ + np->dev->poll_controller(np->dev); + + /* If scheduling is stopped, tickle NAPI bits */ + if(trapped && np->dev->poll && + test_bit(__LINK_STATE_RX_SCHED, &np->dev->state)) + np->dev->poll(np->dev, &budget); + zap_completion_queue(); +} + +static void refill_skbs(void) +{ + struct sk_buff *skb; + unsigned long flags; + + spin_lock_irqsave(&skb_list_lock, flags); + while (nr_skbs < MAX_SKBS) { + skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC); + if (!skb) + break; + + skb->next = skbs; + skbs = skb; + nr_skbs++; + } + spin_unlock_irqrestore(&skb_list_lock, flags); +} + +static void zap_completion_queue(void) +{ + unsigned long flags; + struct softnet_data *sd = &get_cpu_var(softnet_data); + + if (sd->completion_queue) { + struct sk_buff *clist; + + local_irq_save(flags); + clist = sd->completion_queue; + sd->completion_queue = NULL; + local_irq_restore(flags); + + while (clist != NULL) { + struct sk_buff *skb = clist; + clist = clist->next; + __kfree_skb(skb); + } + } + + put_cpu_var(softnet_data); +} + +static struct sk_buff * find_skb(struct netpoll *np, int len, int reserve) +{ + int once = 1, count = 0; + unsigned long flags; + struct sk_buff *skb = NULL; + + zap_completion_queue(); +repeat: + if (nr_skbs < MAX_SKBS) + refill_skbs(); + + skb = alloc_skb(len, GFP_ATOMIC); + + if (!skb) { + spin_lock_irqsave(&skb_list_lock, flags); + skb = skbs; + if (skb) + skbs = skb->next; + skb->next = NULL; + nr_skbs--; + spin_unlock_irqrestore(&skb_list_lock, flags); + } + + if(!skb) { + count++; + if (once && (count == 1000000)) { + printk("out of netpoll skbs!\n"); + once = 0; + } + netpoll_poll(np); + goto repeat; + } + + atomic_set(&skb->users, 1); + skb_reserve(skb, reserve); + return skb; +} + +void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) +{ + int status; + +repeat: + if(!np || !np->dev || !netif_running(np->dev)) { + __kfree_skb(skb); + return; + } + + spin_lock(&np->dev->xmit_lock); + np->dev->xmit_lock_owner = smp_processor_id(); + + if (netif_queue_stopped(np->dev)) { + np->dev->xmit_lock_owner = -1; + spin_unlock(&np->dev->xmit_lock); + + netpoll_poll(np); + goto repeat; + } + + status = np->dev->hard_start_xmit(skb, np->dev); + np->dev->xmit_lock_owner = -1; + spin_unlock(&np->dev->xmit_lock); + + /* transmit busy */ + if(status) + goto repeat; +} + +void netpoll_send_udp(struct netpoll *np, const char *msg, int len) +{ + int total_len, eth_len, ip_len, udp_len; + struct sk_buff *skb; + struct udphdr *udph; + struct iphdr *iph; + struct ethhdr *eth; + + udp_len = len + sizeof(*udph); + ip_len = eth_len = udp_len + sizeof(*iph); + total_len = eth_len + ETH_HLEN; + + skb = find_skb(np, total_len, total_len - len); + if (!skb) + return; + + memcpy(skb->data, msg, len); + skb->len += len; + + udph = (struct udphdr *) skb_push(skb, sizeof(*udph)); + udph->source = htons(np->local_port); + udph->dest = htons(np->remote_port); + udph->len = htons(udp_len); + udph->check = 0; + + iph = (struct iphdr *)skb_push(skb, sizeof(*iph)); + + iph->version = 4; + iph->ihl = 5; + iph->tos = 0; + iph->tot_len = htons(ip_len); + iph->id = 0; + iph->frag_off = 0; + iph->ttl = 64; + iph->protocol = IPPROTO_UDP; + iph->check = 0; + iph->saddr = htonl(np->local_ip); + iph->daddr = htonl(np->remote_ip); + iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); + + eth = (struct ethhdr *) skb_push(skb, ETH_HLEN); + + eth->h_proto = htons(ETH_P_IP); + memcpy(eth->h_source, np->local_mac, 6); + memcpy(eth->h_dest, np->remote_mac, 6); + + netpoll_send_skb(np, skb); +} + +static void arp_reply(struct sk_buff *skb) +{ + struct in_device *in_dev = (struct in_device *) skb->dev->ip_ptr; + struct arphdr *arp; + unsigned char *arp_ptr, *sha, *tha; + int size, type = ARPOP_REPLY, ptype = ETH_P_ARP; + u32 sip, tip; + struct sk_buff *send_skb; + unsigned long flags; + struct list_head *p; + struct netpoll *np = 0; + + spin_lock_irqsave(&rx_list_lock, flags); + list_for_each(p, &rx_list) { + np = list_entry(p, struct netpoll, rx_list); + if ( np->dev == skb->dev ) + break; + np = 0; + } + spin_unlock_irqrestore(&rx_list_lock, flags); + + if (!np) return; + + /* No arp on this interface */ + if (!in_dev || skb->dev->flags & IFF_NOARP) + return; + + if (!pskb_may_pull(skb, (sizeof(struct arphdr) + + (2 * skb->dev->addr_len) + + (2 * sizeof(u32))))) + return; + + skb->h.raw = skb->nh.raw = skb->data; + arp = skb->nh.arph; + + if ((arp->ar_hrd != htons(ARPHRD_ETHER) && + arp->ar_hrd != htons(ARPHRD_IEEE802)) || + arp->ar_pro != htons(ETH_P_IP) || + arp->ar_op != htons(ARPOP_REQUEST)) + return; + + arp_ptr= (unsigned char *)(arp+1); + sha = arp_ptr; + arp_ptr += skb->dev->addr_len; + memcpy(&sip, arp_ptr, 4); + arp_ptr += 4; + tha = arp_ptr; + arp_ptr += skb->dev->addr_len; + memcpy(&tip, arp_ptr, 4); + + /* Should we ignore arp? */ + if (tip != in_dev->ifa_list->ifa_address || + LOOPBACK(tip) || MULTICAST(tip)) + return; + + + size = sizeof(struct arphdr) + 2 * (skb->dev->addr_len + 4); + send_skb = find_skb(np, size + LL_RESERVED_SPACE(np->dev), + LL_RESERVED_SPACE(np->dev)); + + if (!send_skb) + return; + + send_skb->nh.raw = send_skb->data; + arp = (struct arphdr *) skb_put(send_skb, size); + send_skb->dev = skb->dev; + send_skb->protocol = htons(ETH_P_ARP); + + /* Fill the device header for the ARP frame */ + + if (np->dev->hard_header && + np->dev->hard_header(send_skb, skb->dev, ptype, + np->remote_mac, np->local_mac, + send_skb->len) < 0) { + kfree_skb(send_skb); + return; + } + + /* + * Fill out the arp protocol part. + * + * we only support ethernet device type, + * which (according to RFC 1390) should always equal 1 (Ethernet). + */ + + arp->ar_hrd = htons(np->dev->type); + arp->ar_pro = htons(ETH_P_IP); + arp->ar_hln = np->dev->addr_len; + arp->ar_pln = 4; + arp->ar_op = htons(type); + + arp_ptr=(unsigned char *)(arp + 1); + memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len); + arp_ptr += np->dev->addr_len; + memcpy(arp_ptr, &tip, 4); + arp_ptr += 4; + memcpy(arp_ptr, np->local_mac, np->dev->addr_len); + arp_ptr += np->dev->addr_len; + memcpy(arp_ptr, &sip, 4); + + netpoll_send_skb(np, send_skb); +} + +int netpoll_rx(struct sk_buff *skb) +{ + int proto, len, ulen; + struct iphdr *iph; + struct udphdr *uh; + struct netpoll *np; + struct list_head *p; + unsigned long flags; + + if (skb->dev->type != ARPHRD_ETHER) + goto out; + + /* check if netpoll clients need ARP */ + if (skb->protocol == __constant_htons(ETH_P_ARP) && trapped) { + arp_reply(skb); + return 1; + } + + proto = ntohs(skb->mac.ethernet->h_proto); + if (proto != ETH_P_IP) + goto out; + if (skb->pkt_type == PACKET_OTHERHOST) + goto out; + if (skb_shared(skb)) + goto out; + + iph = (struct iphdr *)skb->data; + if (!pskb_may_pull(skb, sizeof(struct iphdr))) + goto out; + if (iph->ihl < 5 || iph->version != 4) + goto out; + if (!pskb_may_pull(skb, iph->ihl*4)) + goto out; + if (ip_fast_csum((u8 *)iph, iph->ihl) != 0) + goto out; + + len = ntohs(iph->tot_len); + if (skb->len < len || len < iph->ihl*4) + goto out; + + if (iph->protocol != IPPROTO_UDP) + goto out; + + len -= iph->ihl*4; + uh = (struct udphdr *)(((char *)iph) + iph->ihl*4); + ulen = ntohs(uh->len); + + if (ulen != len) + goto out; + if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr) < 0) + goto out; + + spin_lock_irqsave(&rx_list_lock, flags); + list_for_each(p, &rx_list) { + np = list_entry(p, struct netpoll, rx_list); + if (np->dev && np->dev != skb->dev) + continue; + if (np->local_ip && np->local_ip != ntohl(iph->daddr)) + continue; + if (np->remote_ip && np->remote_ip != ntohl(iph->saddr)) + continue; + if (np->local_port && np->local_port != ntohs(uh->dest)) + continue; + + spin_unlock_irqrestore(&rx_list_lock, flags); + + if (np->rx_hook) + np->rx_hook(np, ntohs(uh->source), + (char *)(uh+1), + ulen - sizeof(struct udphdr)); + + return 1; + } + spin_unlock_irqrestore(&rx_list_lock, flags); + +out: + return trapped; +} + +int netpoll_parse_options(struct netpoll *np, char *opt) +{ + char *cur=opt, *delim; + + if(*cur != '@') { + if ((delim = strchr(cur, '@')) == NULL) + goto parse_failed; + *delim=0; + np->local_port=simple_strtol(cur, 0, 10); + cur=delim; + } + cur++; + printk(KERN_INFO "%s: local port %d\n", np->name, np->local_port); + + if(*cur != '/') { + if ((delim = strchr(cur, '/')) == NULL) + goto parse_failed; + *delim=0; + np->local_ip=ntohl(in_aton(cur)); + cur=delim; + + printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n", + np->name, HIPQUAD(np->local_ip)); + } + cur++; + + if ( *cur != ',') { + /* parse out dev name */ + if ((delim = strchr(cur, ',')) == NULL) + goto parse_failed; + *delim=0; + strlcpy(np->dev_name, cur, sizeof(np->dev_name)); + cur=delim; + } + cur++; + + printk(KERN_INFO "%s: interface %s\n", np->name, np->dev_name); + + if ( *cur != '@' ) { + /* dst port */ + if ((delim = strchr(cur, '@')) == NULL) + goto parse_failed; + *delim=0; + np->remote_port=simple_strtol(cur, 0, 10); + cur=delim; + } + cur++; + printk(KERN_INFO "%s: remote port %d\n", np->name, np->remote_port); + + /* dst ip */ + if ((delim = strchr(cur, '/')) == NULL) + goto parse_failed; + *delim=0; + np->remote_ip=ntohl(in_aton(cur)); + cur=delim+1; + + printk(KERN_INFO "%s: remote IP %d.%d.%d.%d\n", + np->name, HIPQUAD(np->remote_ip)); + + if( *cur != 0 ) + { + /* MAC address */ + if ((delim = strchr(cur, ':')) == NULL) + goto parse_failed; + *delim=0; + np->remote_mac[0]=simple_strtol(cur, 0, 16); + cur=delim+1; + if ((delim = strchr(cur, ':')) == NULL) + goto parse_failed; + *delim=0; + np->remote_mac[1]=simple_strtol(cur, 0, 16); + cur=delim+1; + if ((delim = strchr(cur, ':')) == NULL) + goto parse_failed; + *delim=0; + np->remote_mac[2]=simple_strtol(cur, 0, 16); + cur=delim+1; + if ((delim = strchr(cur, ':')) == NULL) + goto parse_failed; + *delim=0; + np->remote_mac[3]=simple_strtol(cur, 0, 16); + cur=delim+1; + if ((delim = strchr(cur, ':')) == NULL) + goto parse_failed; + *delim=0; + np->remote_mac[4]=simple_strtol(cur, 0, 16); + cur=delim+1; + np->remote_mac[5]=simple_strtol(cur, 0, 16); + } + + printk(KERN_INFO "%s: remote ethernet address " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + np->name, + np->remote_mac[0], + np->remote_mac[1], + np->remote_mac[2], + np->remote_mac[3], + np->remote_mac[4], + np->remote_mac[5]); + + return 0; + + parse_failed: + printk(KERN_INFO "%s: couldn't parse config at %s!\n", + np->name, cur); + return -1; +} + +int netpoll_setup(struct netpoll *np) +{ + struct net_device *ndev = NULL; + struct in_device *in_dev; + + if (np->dev_name) + ndev = dev_get_by_name(np->dev_name); + if (!ndev) { + printk(KERN_ERR "%s: %s doesn't exist, aborting.\n", + np->name, np->dev_name); + return -1; + } + if (!ndev->poll_controller) { + printk(KERN_ERR "%s: %s doesn't support polling, aborting.\n", + np->name, np->dev_name); + goto release; + } + + if (!(ndev->flags & IFF_UP)) { + unsigned short oflags; + unsigned long atmost, atleast; + + printk(KERN_INFO "%s: device %s not up yet, forcing it\n", + np->name, np->dev_name); + + oflags = ndev->flags; + + rtnl_shlock(); + if (dev_change_flags(ndev, oflags | IFF_UP) < 0) { + printk(KERN_ERR "%s: failed to open %s\n", + np->name, np->dev_name); + rtnl_shunlock(); + goto release; + } + rtnl_shunlock(); + + atleast = jiffies + HZ/10; + atmost = jiffies + 10*HZ; + while (!netif_carrier_ok(ndev)) { + if (time_after(jiffies, atmost)) { + printk(KERN_NOTICE + "%s: timeout waiting for carrier\n", + np->name); + break; + } + cond_resched(); + } + + if (time_before(jiffies, atleast)) { + printk(KERN_NOTICE "%s: carrier detect appears flaky," + " waiting 10 seconds\n", + np->name); + while (time_before(jiffies, atmost)) + cond_resched(); + } + } + + if (!memcmp(np->local_mac, "\0\0\0\0\0\0", 6) && ndev->dev_addr) + memcpy(np->local_mac, ndev->dev_addr, 6); + + if (!np->local_ip) { + in_dev = in_dev_get(ndev); + + if (!in_dev) { + printk(KERN_ERR "%s: no IP address for %s, aborting\n", + np->name, np->dev_name); + goto release; + } + + np->local_ip = ntohl(in_dev->ifa_list->ifa_local); + in_dev_put(in_dev); + printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n", + np->name, HIPQUAD(np->local_ip)); + } + + np->dev = ndev; + + if(np->rx_hook) { + unsigned long flags; + +#ifdef CONFIG_NETPOLL_RX + np->dev->netpoll_rx = 1; +#endif + + spin_lock_irqsave(&rx_list_lock, flags); + list_add(&np->rx_list, &rx_list); + spin_unlock_irqrestore(&rx_list_lock, flags); + } + + return 0; + release: + dev_put(ndev); + return -1; +} + +void netpoll_cleanup(struct netpoll *np) +{ + if(np->rx_hook) { + unsigned long flags; + + spin_lock_irqsave(&rx_list_lock, flags); + list_del(&np->rx_list); +#ifdef CONFIG_NETPOLL_RX + np->dev->netpoll_rx = 0; +#endif + spin_unlock_irqrestore(&rx_list_lock, flags); + } + + dev_put(np->dev); + np->dev = 0; +} + +int netpoll_trap() +{ + return trapped; +} + +void netpoll_set_trap(int trap) +{ + trapped = trap; +} + +EXPORT_SYMBOL(netpoll_set_trap); +EXPORT_SYMBOL(netpoll_trap); +EXPORT_SYMBOL(netpoll_parse_options); +EXPORT_SYMBOL(netpoll_setup); +EXPORT_SYMBOL(netpoll_cleanup); +EXPORT_SYMBOL(netpoll_send_skb); +EXPORT_SYMBOL(netpoll_send_udp); +EXPORT_SYMBOL(netpoll_poll); diff -Nru a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c --- a/net/ipv4/ipconfig.c Sun Mar 14 14:20:06 2004 +++ b/net/ipv4/ipconfig.c Sun Mar 14 14:20:06 2004 @@ -1189,12 +1189,47 @@ #endif /* CONFIG_PROC_FS */ /* + * Extract IP address from the parameter string if needed. Note that we + * need to have root_server_addr set _before_ IPConfig gets called as it + * can override it. + */ +u32 __init root_nfs_parse_addr(char *name) +{ + u32 addr; + int octets = 0; + char *cp, *cq; + + cp = cq = name; + while (octets < 4) { + while (*cp >= '0' && *cp <= '9') + cp++; + if (cp == cq || cp - cq > 3) + break; + if (*cp == '.' || octets == 3) + octets++; + if (octets < 4) + cp++; + cq = cp; + } + if (octets == 4 && (*cp == ':' || *cp == '\0')) { + if (*cp == ':') + *cp++ = '\0'; + addr = in_aton(name); + strcpy(name, cp); + } else + addr = INADDR_NONE; + + return addr; +} + +/* * IP Autoconfig dispatcher. */ static int __init ip_auto_config(void) { unsigned long jiff; + u32 addr; #ifdef CONFIG_PROC_FS proc_net_fops_create("pnp", S_IRUGO, &pnp_seq_fops); @@ -1282,6 +1317,10 @@ /* Device selected manually or only one device -> use it */ ic_dev = ic_first_dev->dev; } + + addr = root_nfs_parse_addr(root_server_path); + if (root_server_addr == INADDR_NONE) + root_server_addr = addr; /* * Use defaults whereever applicable. diff -Nru a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c --- a/net/sunrpc/auth_unix.c Sun Mar 14 14:20:07 2004 +++ b/net/sunrpc/auth_unix.c Sun Mar 14 14:20:07 2004 @@ -149,7 +149,7 @@ struct rpc_clnt *clnt = task->tk_client; struct unx_cred *cred = (struct unx_cred *) task->tk_msg.rpc_cred; u32 *base, *hold; - int i, n; + int i; *p++ = htonl(RPC_AUTH_UNIX); base = p++; @@ -158,10 +158,7 @@ /* * Copy the UTS nodename captured when the client was created. */ - n = clnt->cl_nodelen; - *p++ = htonl(n); - memcpy(p, clnt->cl_nodename, n); - p += (n + 3) >> 2; + p = xdr_encode_array(p, clnt->cl_nodename, clnt->cl_nodelen); /* Note: we don't use real uid if it involves raising privilege */ if (ruid && cred->uc_puid != 0 && cred->uc_pgid != 0) { diff -Nru a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c --- a/net/sunrpc/clnt.c Sun Mar 14 14:20:07 2004 +++ b/net/sunrpc/clnt.c Sun Mar 14 14:20:07 2004 @@ -102,19 +102,22 @@ { struct rpc_version *version; struct rpc_clnt *clnt = NULL; + int err; int len; dprintk("RPC: creating %s client for %s (xprt %p)\n", program->name, servname, xprt); + err = -EINVAL; if (!xprt) - goto out; + goto out_err; if (vers >= program->nrvers || !(version = program->version[vers])) - goto out; + goto out_err; + err = -ENOMEM; clnt = (struct rpc_clnt *) kmalloc(sizeof(*clnt), GFP_KERNEL); if (!clnt) - goto out_no_clnt; + goto out_err; memset(clnt, 0, sizeof(*clnt)); atomic_set(&clnt->cl_users, 0); atomic_set(&clnt->cl_count, 1); @@ -149,9 +152,11 @@ clnt->cl_rtt = &clnt->cl_rtt_default; rpc_init_rtt(&clnt->cl_rtt_default, xprt->timeout.to_initval); - if (rpc_setup_pipedir(clnt, program->pipe_dir_name) < 0) + err = rpc_setup_pipedir(clnt, program->pipe_dir_name); + if (err < 0) goto out_no_path; + err = -ENOMEM; if (!rpcauth_create(flavor, clnt)) { printk(KERN_INFO "RPC: Couldn't create auth handle (flavor %u)\n", flavor); @@ -163,20 +168,16 @@ if (clnt->cl_nodelen > UNX_MAXNODENAME) clnt->cl_nodelen = UNX_MAXNODENAME; memcpy(clnt->cl_nodename, system_utsname.nodename, clnt->cl_nodelen); -out: return clnt; -out_no_clnt: - printk(KERN_INFO "RPC: out of memory in rpc_create_client\n"); - goto out; out_no_auth: rpc_rmdir(clnt->cl_pathname); out_no_path: if (clnt->cl_server != clnt->cl_inline_name) kfree(clnt->cl_server); kfree(clnt); - clnt = NULL; - goto out; +out_err: + return ERR_PTR(err); } /* @@ -198,11 +199,10 @@ atomic_inc(&new->cl_parent->cl_count); if (new->cl_auth) atomic_inc(&new->cl_auth->au_count); -out: return new; out_no_clnt: printk(KERN_INFO "RPC: out of memory in %s\n", __FUNCTION__); - goto out; + return ERR_PTR(-ENOMEM); } /* @@ -610,9 +610,6 @@ rcvbuf->tail[0].iov_len = 0; rcvbuf->page_len = 0; rcvbuf->len = bufsiz; - - /* Zero buffer so we have automatic zero-padding of opaque & string */ - memset(task->tk_buffer, 0, bufsiz); /* Encode header and provided arguments */ encode = task->tk_msg.rpc_proc->p_encode; diff -Nru a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c --- a/net/sunrpc/pmap_clnt.c Sun Mar 14 14:20:07 2004 +++ b/net/sunrpc/pmap_clnt.c Sun Mar 14 14:20:07 2004 @@ -65,9 +65,11 @@ map->pm_binding = 1; spin_unlock(&pmap_lock); - task->tk_status = -EACCES; /* why set this? returns -EIO below */ - if (!(pmap_clnt = pmap_create(clnt->cl_server, sap, map->pm_prot))) + pmap_clnt = pmap_create(clnt->cl_server, sap, map->pm_prot); + if (IS_ERR(pmap_clnt)) { + task->tk_status = PTR_ERR(pmap_clnt); goto bailout; + } task->tk_status = 0; /* @@ -110,8 +112,9 @@ NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot); sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(sin->sin_addr.s_addr)); - if (!(pmap_clnt = pmap_create(hostname, sin, prot))) - return -EACCES; + pmap_clnt = pmap_create(hostname, sin, prot); + if (IS_ERR(pmap_clnt)) + return PTR_ERR(pmap_clnt); /* Setup the call info struct */ status = rpc_call(pmap_clnt, PMAP_GETPORT, &map, &map.pm_port, 0); @@ -161,16 +164,18 @@ struct sockaddr_in sin; struct rpc_portmap map; struct rpc_clnt *pmap_clnt; - unsigned int error = 0; + int error = 0; dprintk("RPC: registering (%d, %d, %d, %d) with portmapper.\n", prog, vers, prot, port); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - if (!(pmap_clnt = pmap_create("localhost", &sin, IPPROTO_UDP))) { - dprintk("RPC: couldn't create pmap client\n"); - return -EACCES; + pmap_clnt = pmap_create("localhost", &sin, IPPROTO_UDP); + if (IS_ERR(pmap_clnt)) { + error = PTR_ERR(pmap_clnt); + dprintk("RPC: couldn't create pmap client. Error = %d\n", error); + return error; } map.pm_prog = prog; @@ -199,15 +204,16 @@ struct rpc_clnt *clnt; /* printk("pmap: create xprt\n"); */ - if (!(xprt = xprt_create_proto(proto, srvaddr, NULL))) - return NULL; + xprt = xprt_create_proto(proto, srvaddr, NULL); + if (IS_ERR(xprt)) + return (struct rpc_clnt *)xprt; xprt->addr.sin_port = htons(RPC_PMAP_PORT); /* printk("pmap: create clnt\n"); */ clnt = rpc_create_client(xprt, hostname, &pmap_program, RPC_PMAP_VERSION, RPC_AUTH_NULL); - if (!clnt) { + if (IS_ERR(clnt)) { xprt_destroy(xprt); } else { clnt->cl_softrtry = 1; diff -Nru a/net/sunrpc/sched.c b/net/sunrpc/sched.c --- a/net/sunrpc/sched.c Sun Mar 14 14:20:07 2004 +++ b/net/sunrpc/sched.c Sun Mar 14 14:20:07 2004 @@ -530,6 +530,9 @@ if (!task->tk_action) break; task->tk_action(task); + /* micro-optimization to avoid spinlock */ + if (RPC_IS_RUNNING(task)) + continue; } /* @@ -545,29 +548,31 @@ } spin_unlock_bh(&rpc_queue_lock); - while (RPC_IS_SLEEPING(task)) { - /* sync task: sleep here */ - dprintk("RPC: %4d sync task going to sleep\n", - task->tk_pid); - if (current->pid == rpciod_pid) - printk(KERN_ERR "RPC: rpciod waiting on sync task!\n"); + if (!RPC_IS_SLEEPING(task)) + continue; + /* sync task: sleep here */ + dprintk("RPC: %4d sync task going to sleep\n", task->tk_pid); + if (current->pid == rpciod_pid) + printk(KERN_ERR "RPC: rpciod waiting on sync task!\n"); + if (!task->tk_client->cl_intr) { __wait_event(task->tk_wait, !RPC_IS_SLEEPING(task)); - dprintk("RPC: %4d sync task resuming\n", task->tk_pid); - + } else { + __wait_event_interruptible(task->tk_wait, !RPC_IS_SLEEPING(task), status); /* * When a sync task receives a signal, it exits with * -ERESTARTSYS. In order to catch any callbacks that * clean up after sleeping on some queue, we don't * break the loop here, but go around once more. */ - if (task->tk_client->cl_intr && signalled()) { + if (status == -ERESTARTSYS) { dprintk("RPC: %4d got signal\n", task->tk_pid); task->tk_flags |= RPC_TASK_KILLED; rpc_exit(task, -ERESTARTSYS); rpc_wake_up_task(task); } } + dprintk("RPC: %4d sync task resuming\n", task->tk_pid); } if (task->tk_exit) { diff -Nru a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c --- a/net/sunrpc/sunrpc_syms.c Sun Mar 14 14:20:08 2004 +++ b/net/sunrpc/sunrpc_syms.c Sun Mar 14 14:20:08 2004 @@ -63,6 +63,8 @@ EXPORT_SYMBOL(xprt_create_proto); EXPORT_SYMBOL(xprt_destroy); EXPORT_SYMBOL(xprt_set_timeout); +EXPORT_SYMBOL(xprt_udp_slot_table_entries); +EXPORT_SYMBOL(xprt_tcp_slot_table_entries); /* Client credential cache */ EXPORT_SYMBOL(rpcauth_register); diff -Nru a/net/sunrpc/sysctl.c b/net/sunrpc/sysctl.c --- a/net/sunrpc/sysctl.c Sun Mar 14 14:20:06 2004 +++ b/net/sunrpc/sysctl.c Sun Mar 14 14:20:06 2004 @@ -1,7 +1,7 @@ /* * linux/net/sunrpc/sysctl.c * - * Sysctl interface to sunrpc module. This is for debugging only now. + * Sysctl interface to sunrpc module. * * I would prefer to register the sunrpc table below sys/net, but that's * impossible at the moment. @@ -19,6 +19,7 @@ #include #include #include +#include /* * Declare the debug flags here @@ -117,6 +118,9 @@ return 0; } +static unsigned int min_slot_table_size = RPC_MIN_SLOT_TABLE; +static unsigned int max_slot_table_size = RPC_MAX_SLOT_TABLE; + static ctl_table debug_table[] = { { .ctl_name = CTL_RPCDEBUG, @@ -150,6 +154,28 @@ .mode = 0644, .proc_handler = &proc_dodebug }, + { + .ctl_name = CTL_SLOTTABLE_UDP, + .procname = "udp_slot_table_entries", + .data = &xprt_udp_slot_table_entries, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &min_slot_table_size, + .extra2 = &max_slot_table_size + }, + { + .ctl_name = CTL_SLOTTABLE_TCP, + .procname = "tcp_slot_table_entries", + .data = &xprt_tcp_slot_table_entries, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &min_slot_table_size, + .extra2 = &max_slot_table_size + }, { .ctl_name = 0 } }; diff -Nru a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c --- a/net/sunrpc/xdr.c Sun Mar 14 14:20:07 2004 +++ b/net/sunrpc/xdr.c Sun Mar 14 14:20:07 2004 @@ -54,7 +54,7 @@ } u32 * -xdr_encode_array(u32 *p, const char *array, unsigned int len) +xdr_encode_array(u32 *p, const void *array, unsigned int len) { int quadlen = XDR_QUADLEN(len); diff -Nru a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c --- a/net/sunrpc/xprt.c Sun Mar 14 14:20:07 2004 +++ b/net/sunrpc/xprt.c Sun Mar 14 14:20:07 2004 @@ -57,6 +57,7 @@ #include #include #include +#include #include #include @@ -74,6 +75,7 @@ #define XPRT_MAX_BACKOFF (8) #define XPRT_IDLE_TIMEOUT (5*60*HZ) +#define XPRT_MAX_RESVPORT (800) /* * Local functions @@ -84,7 +86,7 @@ static void xprt_connect_status(struct rpc_task *task); static struct rpc_xprt * xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to); -static struct socket *xprt_create_socket(int, struct rpc_timeout *, int); +static struct socket *xprt_create_socket(struct rpc_xprt *, int, int); static void xprt_bind_socket(struct rpc_xprt *, struct socket *); static int __xprt_get_cong(struct rpc_xprt *, struct rpc_task *); @@ -336,8 +338,8 @@ /* The (cwnd >> 1) term makes sure * the result gets rounded properly. */ cwnd += (RPC_CWNDSCALE * RPC_CWNDSCALE + (cwnd >> 1)) / cwnd; - if (cwnd > RPC_MAXCWND) - cwnd = RPC_MAXCWND; + if (cwnd > RPC_MAXCWND(xprt)) + cwnd = RPC_MAXCWND(xprt); __xprt_lock_write_next(xprt); } else if (result == -ETIMEDOUT) { cwnd >>= 1; @@ -452,17 +454,74 @@ spin_unlock(&xprt->sock_lock); } +static void xprt_socket_connect(void *args) +{ + struct rpc_xprt *xprt = (struct rpc_xprt *)args; + struct socket *sock = xprt->sock; + int status = -EIO; + + if (xprt->shutdown) { + rpc_wake_up_status(&xprt->pending, -EIO); + return; + } + if (!xprt->addr.sin_port) + goto out_err; + + /* + * Start by resetting any existing state + */ + xprt_close(xprt); + sock = xprt_create_socket(xprt, xprt->prot, xprt->resvport); + if (sock == NULL) { + /* couldn't create socket or bind to reserved port; + * this is likely a permanent error, so cause an abort */ + goto out_err; + return; + } + xprt_bind_socket(xprt, sock); + xprt_sock_setbufsize(xprt); + + if (!xprt->stream) + goto out; + + /* + * Tell the socket layer to start connecting... + */ + status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr, + sizeof(xprt->addr), O_NONBLOCK); + dprintk("RPC: %p connect status %d connected %d sock state %d\n", + xprt, -status, xprt_connected(xprt), sock->sk->sk_state); + if (status >= 0) + goto out; + switch (status) { + case -EINPROGRESS: + case -EALREADY: + return; + default: + goto out_err; + } +out: + spin_lock_bh(&xprt->sock_lock); + if (xprt->snd_task) + rpc_wake_up_task(xprt->snd_task); + spin_unlock_bh(&xprt->sock_lock); + return; +out_err: + spin_lock_bh(&xprt->sock_lock); + if (xprt->snd_task) { + xprt->snd_task->tk_status = status; + rpc_wake_up_task(xprt->snd_task); + } + spin_unlock_bh(&xprt->sock_lock); +} + /* * Attempt to connect a TCP socket. * */ -void -xprt_connect(struct rpc_task *task) +void xprt_connect(struct rpc_task *task) { struct rpc_xprt *xprt = task->tk_xprt; - struct socket *sock = xprt->sock; - struct sock *inet; - int status; dprintk("RPC: %4d xprt_connect xprt %p %s connected\n", task->tk_pid, xprt, (xprt_connected(xprt) ? "is" : "is not")); @@ -483,79 +542,9 @@ if (task->tk_rqstp) task->tk_rqstp->rq_bytes_sent = 0; - /* - * We're here because the xprt was marked disconnected. - * Start by resetting any existing state. - */ - xprt_close(xprt); - if (!(sock = xprt_create_socket(xprt->prot, &xprt->timeout, xprt->resvport))) { - /* couldn't create socket or bind to reserved port; - * this is likely a permanent error, so cause an abort */ - task->tk_status = -EIO; - goto out_write; - } - xprt_bind_socket(xprt, sock); - xprt_sock_setbufsize(xprt); - - if (!xprt->stream) - goto out_write; - - inet = sock->sk; - - /* - * Tell the socket layer to start connecting... - */ - status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr, - sizeof(xprt->addr), O_NONBLOCK); - dprintk("RPC: %4d connect status %d connected %d sock state %d\n", - task->tk_pid, -status, xprt_connected(xprt), inet->sk_state); - - if (status >= 0) - return; - - switch (status) { - case -EINPROGRESS: - case -EALREADY: - /* Protect against TCP socket state changes */ - lock_sock(inet); - if (inet->sk_state != TCP_ESTABLISHED) { - dprintk("RPC: %4d waiting for connection\n", - task->tk_pid); - task->tk_timeout = RPC_CONNECT_TIMEOUT; - /* if the socket is already closing, delay briefly */ - if ((1 << inet->sk_state) & - ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) - task->tk_timeout = RPC_REESTABLISH_TIMEOUT; - rpc_sleep_on(&xprt->pending, task, xprt_connect_status, - NULL); - } - release_sock(inet); - break; - case -ECONNREFUSED: - case -ECONNRESET: - case -ENOTCONN: - if (!RPC_IS_SOFT(task)) { - rpc_delay(task, RPC_REESTABLISH_TIMEOUT); - task->tk_status = -ENOTCONN; - break; - } - default: - /* Report myriad other possible returns. If this file - * system is soft mounted, just error out, like Solaris. */ - if (RPC_IS_SOFT(task)) { - printk(KERN_WARNING - "RPC: error %d connecting to server %s, exiting\n", - -status, task->tk_client->cl_server); - task->tk_status = -EIO; - goto out_write; - } - printk(KERN_WARNING "RPC: error %d connecting to server %s\n", - -status, task->tk_client->cl_server); - /* This will prevent anybody else from reconnecting */ - rpc_delay(task, RPC_REESTABLISH_TIMEOUT); - task->tk_status = status; - break; - } + task->tk_timeout = RPC_CONNECT_TIMEOUT; + rpc_sleep_on(&xprt->pending, task, xprt_connect_status, NULL); + schedule_work(&xprt->sock_connect); return; out_write: xprt_release_write(xprt, task); @@ -580,6 +569,8 @@ task->tk_status = -EIO; switch (task->tk_status) { + case -ECONNREFUSED: + case -ECONNRESET: case -ENOTCONN: rpc_delay(task, RPC_REESTABLISH_TIMEOUT); return; @@ -1313,10 +1304,9 @@ task->tk_status = 0; if (task->tk_rqstp) return; - if (xprt->free) { - struct rpc_rqst *req = xprt->free; - xprt->free = req->rq_next; - req->rq_next = NULL; + if (!list_empty(&xprt->free)) { + struct rpc_rqst *req = list_entry(xprt->free.next, struct rpc_rqst, rq_list); + list_del_init(&req->rq_list); task->tk_rqstp = req; xprt_request_init(task, xprt); return; @@ -1330,22 +1320,14 @@ /* * Allocate a 'unique' XID */ -static u32 -xprt_alloc_xid(void) +static inline u32 xprt_alloc_xid(struct rpc_xprt *xprt) { - static spinlock_t xid_lock = SPIN_LOCK_UNLOCKED; - static int need_init = 1; - static u32 xid; - u32 ret; - - spin_lock(&xid_lock); - if (unlikely(need_init)) { - xid = get_seconds() << 12; - need_init = 0; - } - ret = xid++; - spin_unlock(&xid_lock); - return ret; + return xprt->xid++; +} + +static inline void xprt_init_xid(struct rpc_xprt *xprt) +{ + get_random_bytes(&xprt->xid, sizeof(xprt->xid)); } /* @@ -1359,8 +1341,7 @@ req->rq_timeout = xprt->timeout; req->rq_task = task; req->rq_xprt = xprt; - req->rq_xid = xprt_alloc_xid(); - INIT_LIST_HEAD(&req->rq_list); + req->rq_xid = xprt_alloc_xid(xprt); dprintk("RPC: %4d reserved req %p xid %08x\n", task->tk_pid, req, req->rq_xid); } @@ -1391,9 +1372,7 @@ dprintk("RPC: %4d release request %p\n", task->tk_pid, req); spin_lock(&xprt->xprt_lock); - req->rq_next = xprt->free; - xprt->free = req; - + list_add(&req->rq_list, &xprt->free); xprt_clear_backlog(xprt); spin_unlock(&xprt->xprt_lock); } @@ -1424,6 +1403,9 @@ to->to_exponential = 0; } +unsigned int xprt_udp_slot_table_entries = RPC_DEF_SLOT_TABLE; +unsigned int xprt_tcp_slot_table_entries = RPC_DEF_SLOT_TABLE; + /* * Initialize an RPC client */ @@ -1431,21 +1413,33 @@ xprt_setup(int proto, struct sockaddr_in *ap, struct rpc_timeout *to) { struct rpc_xprt *xprt; + unsigned int entries; + size_t slot_table_size; struct rpc_rqst *req; - int i; dprintk("RPC: setting up %s transport...\n", proto == IPPROTO_UDP? "UDP" : "TCP"); + entries = (proto == IPPROTO_TCP)? + xprt_tcp_slot_table_entries : xprt_udp_slot_table_entries; + if ((xprt = kmalloc(sizeof(struct rpc_xprt), GFP_KERNEL)) == NULL) - return NULL; + return ERR_PTR(-ENOMEM); memset(xprt, 0, sizeof(*xprt)); /* Nnnngh! */ + xprt->max_reqs = entries; + slot_table_size = entries * sizeof(xprt->slot[0]); + xprt->slot = kmalloc(slot_table_size, GFP_KERNEL); + if (xprt->slot == NULL) { + kfree(xprt); + return ERR_PTR(-ENOMEM); + } + memset(xprt->slot, 0, slot_table_size); xprt->addr = *ap; xprt->prot = proto; xprt->stream = (proto == IPPROTO_TCP)? 1 : 0; if (xprt->stream) { - xprt->cwnd = RPC_MAXCWND; + xprt->cwnd = RPC_MAXCWND(xprt); xprt->nocong = 1; } else xprt->cwnd = RPC_INITCWND; @@ -1453,12 +1447,15 @@ spin_lock_init(&xprt->xprt_lock); init_waitqueue_head(&xprt->cong_wait); + INIT_LIST_HEAD(&xprt->free); INIT_LIST_HEAD(&xprt->recv); + INIT_WORK(&xprt->sock_connect, xprt_socket_connect, xprt); INIT_WORK(&xprt->task_cleanup, xprt_socket_autoclose, xprt); init_timer(&xprt->timer); xprt->timer.function = xprt_init_autodisconnect; xprt->timer.data = (unsigned long) xprt; xprt->last_used = jiffies; + xprt->port = XPRT_MAX_RESVPORT; /* Set timeout parameters */ if (to) { @@ -1473,15 +1470,16 @@ INIT_RPC_WAITQ(&xprt->backlog, "xprt_backlog"); /* initialize free list */ - for (i = 0, req = xprt->slot; i < RPC_MAXREQS-1; i++, req++) - req->rq_next = req + 1; - req->rq_next = NULL; - xprt->free = xprt->slot; + for (req = &xprt->slot[entries-1]; req >= &xprt->slot[0]; req--) + list_add(&req->rq_list, &xprt->free); + + xprt_init_xid(xprt); /* Check whether we want to use a reserved port */ xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0; - dprintk("RPC: created transport %p\n", xprt); + dprintk("RPC: created transport %p with %u slots\n", xprt, + xprt->max_reqs); return xprt; } @@ -1489,31 +1487,28 @@ /* * Bind to a reserved port */ -static inline int -xprt_bindresvport(struct socket *sock) +static inline int xprt_bindresvport(struct rpc_xprt *xprt, struct socket *sock) { - struct sockaddr_in myaddr; + struct sockaddr_in myaddr = { + .sin_family = AF_INET, + }; int err, port; - kernel_cap_t saved_cap = current->cap_effective; - /* Override capabilities. - * They were checked in xprt_create_proto i.e. at mount time - */ - cap_raise(current->cap_effective, CAP_NET_BIND_SERVICE); - - memset(&myaddr, 0, sizeof(myaddr)); - myaddr.sin_family = AF_INET; - port = 800; + /* Were we already bound to a given port? Try to reuse it */ + port = xprt->port; do { myaddr.sin_port = htons(port); err = sock->ops->bind(sock, (struct sockaddr *) &myaddr, sizeof(myaddr)); - } while (err == -EADDRINUSE && --port > 0); - current->cap_effective = saved_cap; - - if (err < 0) - printk("RPC: Can't bind to reserved port (%d).\n", -err); + if (err == 0) { + xprt->port = port; + return 0; + } + if (--port == 0) + port = XPRT_MAX_RESVPORT; + } while (err == -EADDRINUSE && port != xprt->port); + printk("RPC: Can't bind to reserved port (%d).\n", -err); return err; } @@ -1563,11 +1558,11 @@ return; if (xprt->rcvsize) { sk->sk_userlocks |= SOCK_RCVBUF_LOCK; - sk->sk_rcvbuf = xprt->rcvsize * RPC_MAXCONG * 2; + sk->sk_rcvbuf = xprt->rcvsize * xprt->max_reqs * 2; } if (xprt->sndsize) { sk->sk_userlocks |= SOCK_SNDBUF_LOCK; - sk->sk_sndbuf = xprt->sndsize * RPC_MAXCONG * 2; + sk->sk_sndbuf = xprt->sndsize * xprt->max_reqs * 2; sk->sk_write_space(sk); } } @@ -1576,8 +1571,7 @@ * Datastream sockets are created here, but xprt_connect will create * and connect stream sockets. */ -static struct socket * -xprt_create_socket(int proto, struct rpc_timeout *to, int resvport) +static struct socket * xprt_create_socket(struct rpc_xprt *xprt, int proto, int resvport) { struct socket *sock; int type, err; @@ -1593,7 +1587,7 @@ } /* If the caller has the capability, bind to a reserved port */ - if (resvport && xprt_bindresvport(sock) < 0) { + if (resvport && xprt_bindresvport(xprt, sock) < 0) { printk("RPC: can't bind to reserved port.\n"); goto failed; } @@ -1614,16 +1608,11 @@ struct rpc_xprt *xprt; xprt = xprt_setup(proto, sap, to); - if (!xprt) - goto out_bad; - - dprintk("RPC: xprt_create_proto created xprt %p\n", xprt); + if (IS_ERR(xprt)) + dprintk("RPC: xprt_create_proto failed\n"); + else + dprintk("RPC: xprt_create_proto created xprt %p\n", xprt); return xprt; - out_bad: - dprintk("RPC: xprt_create_proto failed\n"); - if (xprt) - kfree(xprt); - return NULL; } /* @@ -1662,6 +1651,7 @@ dprintk("RPC: destroying transport %p\n", xprt); xprt_shutdown(xprt); xprt_close(xprt); + kfree(xprt->slot); kfree(xprt); return 0; diff -Nru a/scripts/modpost.c b/scripts/modpost.c --- a/scripts/modpost.c Sun Mar 14 14:20:06 2004 +++ b/scripts/modpost.c Sun Mar 14 14:20:06 2004 @@ -64,17 +64,20 @@ { struct module *mod; char *p; + size_t len; mod = NOFAIL(malloc(sizeof(*mod))); memset(mod, 0, sizeof(*mod)); - mod->name = NOFAIL(strdup(modname)); + p = NOFAIL(strdup(modname)); + + len = strlen(p); /* strip trailing .o */ - p = strstr(mod->name, ".o"); - if (p) - *p = 0; + if (len > 2 && p[len-2] == '.' && p[len-1] == 'o') + p[len -2] = '\0'; /* add to list */ + mod->name = NOFAIL(strdup(p)); mod->next = modules; modules = mod; diff -Nru a/security/dummy.c b/security/dummy.c --- a/security/dummy.c Sun Mar 14 14:20:06 2004 +++ b/security/dummy.c Sun Mar 14 14:20:06 2004 @@ -194,7 +194,8 @@ return; } -static int dummy_sb_copy_data (const char *fstype, void *orig, void *copy) +static int dummy_sb_copy_data (struct file_system_type *type, + void *orig, void *copy) { return 0; } diff -Nru a/security/selinux/hooks.c b/security/selinux/hooks.c --- a/security/selinux/hooks.c Sun Mar 14 14:20:08 2004 +++ b/security/selinux/hooks.c Sun Mar 14 14:20:08 2004 @@ -331,25 +331,24 @@ name = sb->s_type->name; - /* Ignore these fileystems with binary mount option data. */ - if (!strcmp(name, "coda") || - !strcmp(name, "afs") || !strcmp(name, "smbfs")) - goto out; + if (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) { - /* NFS we understand. */ - if (!strcmp(name, "nfs")) { - struct nfs_mount_data *d = data; + /* NFS we understand. */ + if (!strcmp(name, "nfs")) { + struct nfs_mount_data *d = data; - if (d->version < NFS_MOUNT_VERSION) - goto out; + if (d->version < NFS_MOUNT_VERSION) + goto out; - if (d->context[0]) { - context = d->context; - seen |= Opt_context; - } + if (d->context[0]) { + context = d->context; + seen |= Opt_context; + } + } else + goto out; - /* Standard string-based options. */ } else { + /* Standard string-based options. */ char *p, *options = data; while ((p = strsep(&options, ",")) != NULL) { @@ -1885,7 +1884,7 @@ *to += len; } -static int selinux_sb_copy_data(const char *fstype, void *orig, void *copy) +static int selinux_sb_copy_data(struct file_system_type *type, void *orig, void *copy) { int fnosec, fsec, rc = 0; char *in_save, *in_curr, *in_end; @@ -1895,8 +1894,7 @@ sec_curr = copy; /* Binary mount data: just copy */ - if (!strcmp(fstype, "nfs") || !strcmp(fstype, "coda") || - !strcmp(fstype, "smbfs") || !strcmp(fstype, "afs")) { + if (type->fs_flags & FS_BINARY_MOUNTDATA) { copy_page(sec_curr, in_curr); goto out; } diff -Nru a/sound/arm/Kconfig b/sound/arm/Kconfig --- a/sound/arm/Kconfig Sun Mar 14 14:20:08 2004 +++ b/sound/arm/Kconfig Sun Mar 14 14:20:08 2004 @@ -6,6 +6,7 @@ config SND_SA11XX_UDA1341 tristate "SA11xx UDA1341TS driver (H3600)" depends on ARCH_SA1100 && SND && L3 + select SND_PCM help Say Y or M if you have a Compaq iPaq H3x00 handheld computer and want to use its Philips UDA 1341 audio chip. diff -Nru a/sound/arm/sa11xx-uda1341.c b/sound/arm/sa11xx-uda1341.c --- a/sound/arm/sa11xx-uda1341.c Sun Mar 14 14:20:06 2004 +++ b/sound/arm/sa11xx-uda1341.c Sun Mar 14 14:20:06 2004 @@ -21,7 +21,7 @@ * merged HAL layer (patches from Brian) */ -/* $Id: sa11xx-uda1341.c,v 1.12 2003/08/13 13:14:31 tiwai Exp $ */ +/* $Id: sa11xx-uda1341.c,v 1.13 2004/03/02 15:32:35 perex Exp $ */ /*************************************************************************************************** * @@ -840,7 +840,9 @@ * isa works but I'm not sure why (or if) it's the right choice * this may be too large, trying it for now */ - snd_pcm_lib_preallocate_isa_pages_for_all(pcm, 64*1024, 64*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_ISA, + snd_pcm_dma_flags(0), + 64*1024, 64*1024); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_sa11xx_uda1341_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_sa11xx_uda1341_capture_ops); diff -Nru a/sound/core/Kconfig b/sound/core/Kconfig --- a/sound/core/Kconfig Sun Mar 14 14:20:08 2004 +++ b/sound/core/Kconfig Sun Mar 14 14:20:08 2004 @@ -3,9 +3,23 @@ tristate "Emulation for 32-bit applications" depends on SND && (SPARC64 || PPC64 || X86_64 && IA32_EMULATION) +config SND_TIMER + tristate + +config SND_PCM + tristate + select SND_TIMER + +config SND_HWDEP + tristate + +config SND_RAWMIDI + tristate + config SND_SEQUENCER tristate "Sequencer support" depends on SND + select SND_TIMER help Say 'Y' or 'M' to enable MIDI sequencer and router support. This feature allows routing and enqueing MIDI events. Events can be processed at given @@ -20,26 +34,27 @@ immediately. config SND_OSSEMUL - bool "OSS API emulation" - depends on SND - help - Say 'Y' to enable OSS (Open Sound System) API emulation code. + bool config SND_MIXER_OSS tristate "OSS Mixer API" - depends on SND_OSSEMUL && SND + depends on SND + select SND_OSSEMUL help Say 'Y' or 'M' to enable mixer OSS API emulation (/dev/mixer*). config SND_PCM_OSS tristate "OSS PCM (digital audio) API" - depends on SND_OSSEMUL && SND + depends on SND + select SND_OSSEMUL + select SND_PCM help Say 'Y' or 'M' to enable digital audio (PCM) OSS API emulation (/dev/dsp*). config SND_SEQUENCER_OSS bool "OSS Sequencer API" - depends on SND_OSSEMUL && SND_SEQUENCER + depends on SND_SEQUENCER + select SND_OSSEMUL help Say 'Y' to enable OSS sequencer emulation (both /dev/sequencer and /dev/music interfaces). @@ -47,6 +62,7 @@ config SND_RTCTIMER tristate "RTC Timer support" depends on SND && RTC + select SND_TIMER help Say 'Y' or 'M' to enable RTC timer support for ALSA. ALSA code uses RTC timer as precise timing source and maps the RTC timer to the ALSA's timer diff -Nru a/sound/core/Makefile b/sound/core/Makefile --- a/sound/core/Makefile Sun Mar 14 14:20:07 2004 +++ b/sound/core/Makefile Sun Mar 14 14:20:07 2004 @@ -15,97 +15,20 @@ snd-pcm-objs := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \ pcm_memory.o -snd-page-alloc-objs := memalloc.o -ifeq ($(CONFIG_PCI),y) -snd-page-alloc-objs += sgbuf.o -endif +snd-page-alloc-objs := memalloc.o sgbuf.o snd-rawmidi-objs := rawmidi.o snd-timer-objs := timer.o snd-rtctimer-objs := rtctimer.o snd-hwdep-objs := hwdep.o -obj-$(CONFIG_SND) += snd.o -ifeq ($(subst m,y,$(CONFIG_RTC)),y) - obj-$(CONFIG_SND_RTCTIMER) += snd-timer.o - obj-$(CONFIG_SND_RTCTIMER) += snd-rtctimer.o -endif -obj-$(CONFIG_SND_HWDEP) += snd-hwdep.o +obj-$(CONFIG_SND) += snd.o +obj-$(CONFIG_SND_HWDEP) += snd-hwdep.o +obj-$(CONFIG_SND_TIMER) += snd-timer.o +obj-$(CONFIG_SND_RTCTIMER) += snd-rtctimer.o +obj-$(CONFIG_SND_PCM) += snd-pcm.o snd-page-alloc.o +obj-$(CONFIG_SND_RAWMIDI) += snd-rawmidi.o -obj-$(CONFIG_SND_MIXER_OSS) += oss/ -obj-$(CONFIG_SND_PCM_OSS) += snd-pcm.o snd-timer.o snd-page-alloc.o oss/ -obj-$(CONFIG_SND_SEQUENCER) += snd-timer.o seq/ +obj-$(CONFIG_SND_OSSEMUL) += oss/ +obj-$(CONFIG_SND_SEQUENCER) += seq/ obj-$(CONFIG_SND_BIT32_EMUL) += ioctl32/ - -# Toplevel Module Dependency -obj-$(CONFIG_SND_DUMMY) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o -obj-$(CONFIG_SND_VIRMIDI) += snd-rawmidi.o snd.o snd-timer.o -obj-$(CONFIG_SND_SERIAL_U16550) += snd-rawmidi.o snd.o snd-timer.o -obj-$(CONFIG_SND_MTPAV) += snd-rawmidi.o snd.o snd-timer.o -obj-$(CONFIG_SND_MPU401) += snd-rawmidi.o snd.o snd-timer.o -obj-$(CONFIG_SND_ALS100) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_AZT2320) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_AZT3328) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_CMI8330) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o -obj-$(CONFIG_SND_DT019X) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_ES18XX) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_OPL3SA2) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_SGALAXY) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o -obj-$(CONFIG_SND_AD1816A) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_AD1848) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o -obj-$(CONFIG_SND_CS4231) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o -obj-$(CONFIG_SND_CS4232) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_CS4236) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_ES1688) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_GUSCLASSIC) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o -obj-$(CONFIG_SND_GUSMAX) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o -obj-$(CONFIG_SND_GUSEXTREME) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_INTERWAVE) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o -obj-$(CONFIG_SND_INTERWAVE_STB) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o -obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_OPTI93X) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_SB8) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_SB16) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_SBAWE) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_ES968) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o -obj-$(CONFIG_SND_WAVEFRONT) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_SSCAPE) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_ALS4000) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_CMIPCI) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_CS4281) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_ENS1370) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o -obj-$(CONFIG_SND_ENS1371) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o -obj-$(CONFIG_SND_ES1938) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-hwdep.o snd-rawmidi.o -obj-$(CONFIG_SND_ES1968) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o -obj-$(CONFIG_SND_FM801) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_ICE1712) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o -obj-$(CONFIG_SND_ICE1724) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o -obj-$(CONFIG_SND_INTEL8X0) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o -obj-$(CONFIG_SND_MAESTRO3) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o -obj-$(CONFIG_SND_RME32) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o -obj-$(CONFIG_SND_RME96) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o -obj-$(CONFIG_SND_SONICVIBES) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_VIA82XX) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o -obj-$(CONFIG_SND_ALI5451) += snd.o snd-rawmidi.o snd-timer.o snd-page-alloc.o snd-pcm.o -obj-$(CONFIG_SND_CS46XX) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o -obj-$(CONFIG_SND_EMU10K1) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_KORG1212) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o -obj-$(CONFIG_SND_NM256) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o -obj-$(CONFIG_SND_RME9652) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o -obj-$(CONFIG_SND_HDSP) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_TRIDENT) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o -obj-$(CONFIG_SND_YMFPCI) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_POWERMAC) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o -obj-$(CONFIG_SND_SA11XX_UDA1341) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o -obj-$(CONFIG_SND_PC98_CS4232) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o -obj-$(CONFIG_SND_USB_AUDIO) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o -obj-$(CONFIG_SND_SUN_AMD7930) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o -obj-$(CONFIG_SND_SUN_CS4231) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o -obj-$(CONFIG_SND_HARMONY) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o -obj-$(CONFIG_SND_VXPOCKET) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-hwdep.o -obj-$(CONFIG_SND_VXP440) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-hwdep.o -obj-$(CONFIG_SND_VX222) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-hwdep.o -obj-$(CONFIG_SND_BT87X) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o - -obj-m := $(sort $(obj-m)) diff -Nru a/sound/core/init.c b/sound/core/init.c --- a/sound/core/init.c Sun Mar 14 14:20:06 2004 +++ b/sound/core/init.c Sun Mar 14 14:20:06 2004 @@ -79,6 +79,7 @@ goto __error; strlcpy(card->id, xid, sizeof(card->id)); } + err = 0; write_lock(&snd_card_rwlock); if (idx < 0) { int idx2; @@ -94,15 +95,14 @@ idx = snd_ecards_limit++; } else if (idx < snd_ecards_limit) { if (snd_cards_lock & (1 << idx)) - idx = -1; /* invalid */ + err = -ENODEV; /* invalid */ } else if (idx < SNDRV_CARDS) snd_ecards_limit = idx + 1; /* increase the limit */ else - idx = -1; - if (idx < 0) { + err = -ENODEV; + if (idx < 0 || err < 0) { write_unlock(&snd_card_rwlock); - if (idx >= snd_ecards_limit) - snd_printk(KERN_ERR "card %i is out of range (0-%i)\n", idx, snd_ecards_limit-1); + snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i)\n", idx, snd_ecards_limit - 1); goto __error; } snd_cards_lock |= 1 << idx; /* lock it */ @@ -281,7 +281,7 @@ } if (card->private_free) card->private_free(card); - snd_info_free_entry(card->proc_id); + snd_info_unregister(card->proc_id); if (snd_info_card_free(card) < 0) { snd_printk(KERN_WARNING "unable to free card info\n"); /* Not fatal error */ diff -Nru a/sound/core/memalloc.c b/sound/core/memalloc.c --- a/sound/core/memalloc.c Sun Mar 14 14:20:08 2004 +++ b/sound/core/memalloc.c Sun Mar 14 14:20:08 2004 @@ -25,10 +25,15 @@ #include #include #include +#include #include #include +#include #include #include +#ifdef CONFIG_SBUS +#include +#endif MODULE_AUTHOR("Takashi Iwai , Jaroslav Kysela "); @@ -43,6 +48,13 @@ MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(enable, "Enable cards to allocate buffers."); +/* + */ + +void *snd_malloc_sgbuf_pages(const struct snd_dma_device *dev, + size_t size, struct snd_dma_buffer *dmab, + size_t *res_size); +int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab); /* */ @@ -73,14 +85,40 @@ #define snd_assert(expr, args...) /**/ #endif -#ifdef CONFIG_PCI +/* + * Hacks + */ + +static void *snd_dma_alloc_coherent1(struct device *dev, size_t size, + dma_addr_t *dma_handle, int flags) +{ + if (dev) + return dma_alloc_coherent(dev, size, dma_handle, flags); + else /* FIXME: dma_alloc_coherent does't always accept dev=NULL */ + return pci_alloc_consistent(NULL, size, dma_handle); +} + +static void snd_dma_free_coherent1(struct device *dev, size_t size, void *dma_addr, + dma_addr_t dma_handle) +{ + if (dev) + return dma_free_coherent(dev, size, dma_addr, dma_handle); + else + return pci_free_consistent(NULL, size, dma_addr, dma_handle); +} + +#undef dma_alloc_coherent +#define dma_alloc_coherent snd_dma_alloc_coherent1 +#undef dma_free_coherent +#define dma_free_coherent snd_dma_free_coherent1 + + #if defined(__i386__) || defined(__ppc__) || defined(__x86_64__) -#define HACK_PCI_ALLOC_CONSISTENT /* - * A hack to allocate large buffers via pci_alloc_consistent() + * A hack to allocate large buffers via dma_alloc_coherent() * - * since pci_alloc_consistent always tries GFP_DMA when the requested + * since dma_alloc_coherent always tries GFP_DMA when the requested * pci memory region is below 32bit, it happens quite often that even * 2 order of pages cannot be allocated. * @@ -88,46 +126,248 @@ * allocation will be done without GFP_DMA. if the area doesn't match * with the requested region, then realloate with the original dma_mask * again. + * + * Really, we want to move this type of thing into dma_alloc_coherent() + * so dma_mask doesn't have to be messed with. */ -static void *snd_pci_hack_alloc_consistent(struct pci_dev *hwdev, size_t size, - dma_addr_t *dma_handle) +static void *snd_dma_hack_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, int flags) { void *ret; - u64 dma_mask, cdma_mask; - unsigned long mask; + u64 dma_mask; - if (hwdev == NULL) - return pci_alloc_consistent(hwdev, size, dma_handle); - dma_mask = hwdev->dma_mask; - cdma_mask = hwdev->consistent_dma_mask; - mask = (unsigned long)dma_mask && (unsigned long)cdma_mask; - hwdev->dma_mask = 0xffffffff; /* do without masking */ - hwdev->consistent_dma_mask = 0xffffffff; /* do without masking */ - ret = pci_alloc_consistent(hwdev, size, dma_handle); - hwdev->dma_mask = dma_mask; /* restore */ - hwdev->consistent_dma_mask = cdma_mask; /* restore */ + if (dev == NULL || !dev->dma_mask) + return dma_alloc_coherent(dev, size, dma_handle, flags); + dma_mask = *dev->dma_mask; + *dev->dma_mask = 0xffffffff; /* do without masking */ + ret = dma_alloc_coherent(dev, size, dma_handle, flags); + *dev->dma_mask = dma_mask; /* restore */ if (ret) { /* obtained address is out of range? */ - if (((unsigned long)*dma_handle + size - 1) & ~mask) { + if (((unsigned long)*dma_handle + size - 1) & ~dma_mask) { /* reallocate with the proper mask */ - pci_free_consistent(hwdev, size, ret, *dma_handle); - ret = pci_alloc_consistent(hwdev, size, dma_handle); + dma_free_coherent(dev, size, ret, *dma_handle); + ret = dma_alloc_coherent(dev, size, dma_handle, flags); } } else { /* wish to success now with the proper mask... */ - if (mask != 0xffffffffUL) - ret = pci_alloc_consistent(hwdev, size, dma_handle); + if (dma_mask != 0xffffffffUL) + ret = dma_alloc_coherent(dev, size, dma_handle, flags); } return ret; } -/* redefine pci_alloc_consistent for some architectures */ -#undef pci_alloc_consistent -#define pci_alloc_consistent snd_pci_hack_alloc_consistent +/* redefine dma_alloc_coherent for some architectures */ +#undef dma_alloc_coherent +#define dma_alloc_coherent snd_dma_hack_alloc_coherent #endif /* arch */ -#endif /* CONFIG_PCI */ + +/* + * + * Generic memory allocators + * + */ + +static long snd_allocated_pages; /* holding the number of allocated pages */ + +static void mark_pages(void *res, int order) +{ + struct page *page = virt_to_page(res); + struct page *last_page = page + (1 << order); + while (page < last_page) + SetPageReserved(page++); + snd_allocated_pages += 1 << order; +} + +static void unmark_pages(void *res, int order) +{ + struct page *page = virt_to_page(res); + struct page *last_page = page + (1 << order); + while (page < last_page) + ClearPageReserved(page++); + snd_allocated_pages -= 1 << order; +} + +/** + * snd_malloc_pages - allocate pages with the given size + * @size: the size to allocate in bytes + * @gfp_flags: the allocation conditions, GFP_XXX + * + * Allocates the physically contiguous pages with the given size. + * + * Returns the pointer of the buffer, or NULL if no enoguh memory. + */ +void *snd_malloc_pages(size_t size, unsigned int gfp_flags) +{ + int pg; + void *res; + + snd_assert(size > 0, return NULL); + snd_assert(gfp_flags != 0, return NULL); + for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++); + if ((res = (void *) __get_free_pages(gfp_flags, pg)) != NULL) { + mark_pages(res, pg); + } + return res; +} + +/** + * snd_malloc_pages_fallback - allocate pages with the given size with fallback + * @size: the requested size to allocate in bytes + * @gfp_flags: the allocation conditions, GFP_XXX + * @res_size: the pointer to store the size of buffer actually allocated + * + * Allocates the physically contiguous pages with the given request + * size. When no space is left, this function reduces the size and + * tries to allocate again. The size actually allocated is stored in + * res_size argument. + * + * Returns the pointer of the buffer, or NULL if no enoguh memory. + */ +void *snd_malloc_pages_fallback(size_t size, unsigned int gfp_flags, size_t *res_size) +{ + void *res; + + snd_assert(size > 0, return NULL); + snd_assert(res_size != NULL, return NULL); + do { + if ((res = snd_malloc_pages(size, gfp_flags)) != NULL) { + *res_size = size; + return res; + } + size >>= 1; + } while (size >= PAGE_SIZE); + return NULL; +} + +/** + * snd_free_pages - release the pages + * @ptr: the buffer pointer to release + * @size: the allocated buffer size + * + * Releases the buffer allocated via snd_malloc_pages(). + */ +void snd_free_pages(void *ptr, size_t size) +{ + int pg; + + if (ptr == NULL) + return; + for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++); + unmark_pages(ptr, pg); + free_pages((unsigned long) ptr, pg); +} + +/* + * + * Bus-specific memory allocators + * + */ + +static void *snd_malloc_dev_pages(struct device *dev, size_t size, dma_addr_t *dma) +{ + int pg; + void *res; + unsigned int gfp_flags; + + snd_assert(size > 0, return NULL); + snd_assert(dma != NULL, return NULL); + pg = get_order(size); + gfp_flags = GFP_KERNEL; + if (pg > 0) + gfp_flags |= __GFP_NOWARN; + res = dma_alloc_coherent(dev, PAGE_SIZE << pg, dma, gfp_flags); + if (res != NULL) + mark_pages(res, pg); + + return res; +} + +static void *snd_malloc_dev_pages_fallback(struct device *dev, size_t size, + dma_addr_t *dma, size_t *res_size) +{ + void *res; + + snd_assert(res_size != NULL, return NULL); + do { + if ((res = snd_malloc_dev_pages(dev, size, dma)) != NULL) { + *res_size = size; + return res; + } + size >>= 1; + } while (size >= PAGE_SIZE); + return NULL; +} + +static void snd_free_dev_pages(struct device *dev, size_t size, void *ptr, + dma_addr_t dma) +{ + int pg; + + if (ptr == NULL) + return; + pg = get_order(size); + unmark_pages(ptr, pg); + dma_free_coherent(dev, PAGE_SIZE << pg, ptr, dma); +} + +#ifdef CONFIG_SBUS + +static void *snd_malloc_sbus_pages(struct device *dev, size_t size, + dma_addr_t *dma_addr) +{ + struct sbus_dev *sdev = (struct sbus_dev *)dev; + int pg; + void *res; + + snd_assert(size > 0, return NULL); + snd_assert(dma_addr != NULL, return NULL); + for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++); + res = sbus_alloc_consistent(sdev, PAGE_SIZE * (1 << pg), dma_addr); + if (res != NULL) { + mark_pages(res, pg); + } + return res; +} + +static void *snd_malloc_sbus_pages_fallback(struct device *dev, size_t size, + dma_addr_t *dma_addr, size_t *res_size) +{ + void *res; + + snd_assert(res_size != NULL, return NULL); + do { + if ((res = snd_malloc_sbus_pages(dev, size, dma_addr)) != NULL) { + *res_size = size; + return res; + } + size >>= 1; + } while (size >= PAGE_SIZE); + return NULL; +} + +static void snd_free_sbus_pages(struct device *dev, size_t size, + void *ptr, dma_addr_t dma_addr) +{ + struct sbus_dev *sdev = (struct sbus_dev *)dev; + int pg; + + if (ptr == NULL) + return; + for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++); + unmark_pages(ptr, pg); + sbus_free_consistent(sdev, PAGE_SIZE * (1 << pg), ptr, dma_addr); +} + +#endif /* CONFIG_SBUS */ + +/* + * + * ALSA generic memory management + * + */ /* @@ -142,23 +382,7 @@ if (! allow_unused || (a->id != SNDRV_DMA_DEVICE_UNUSED && b->id != SNDRV_DMA_DEVICE_UNUSED)) return 0; } - switch (a->type) { - case SNDRV_DMA_TYPE_CONTINUOUS: -#ifdef CONFIG_ISA - case SNDRV_DMA_TYPE_ISA: -#endif - return a->dev.flags == b->dev.flags; -#ifdef CONFIG_PCI - case SNDRV_DMA_TYPE_PCI: - case SNDRV_DMA_TYPE_PCI_SG: - return a->dev.pci == b->dev.pci; -#endif -#ifdef CONFIG_SBUS - case SNDRV_DMA_TYPE_SBUS: - return a->dev.sbus == b->dev.sbus; -#endif - } - return 0; + return a->dev == b->dev; } /** @@ -183,27 +407,70 @@ dmab->bytes = 0; switch (dev->type) { case SNDRV_DMA_TYPE_CONTINUOUS: - dmab->area = snd_malloc_pages(size, dev->dev.flags); + dmab->area = snd_malloc_pages(size, (unsigned long)dev->dev); dmab->addr = 0; break; -#ifdef CONFIG_ISA - case SNDRV_DMA_TYPE_ISA: - dmab->area = snd_malloc_isa_pages(size, &dmab->addr); +#ifdef CONFIG_SBUS + case SNDRV_DMA_TYPE_SBUS: + dmab->area = snd_malloc_sbus_pages(dev->dev, size, &dmab->addr); break; #endif -#ifdef CONFIG_PCI - case SNDRV_DMA_TYPE_PCI: - dmab->area = snd_malloc_pci_pages(dev->dev.pci, size, &dmab->addr); + case SNDRV_DMA_TYPE_DEV: + dmab->area = snd_malloc_dev_pages(dev->dev, size, &dmab->addr); break; - case SNDRV_DMA_TYPE_PCI_SG: - snd_malloc_sgbuf_pages(dev->dev.pci, size, dmab); + case SNDRV_DMA_TYPE_DEV_SG: + snd_malloc_sgbuf_pages(dev, size, dmab, NULL); + break; + default: + printk(KERN_ERR "snd-malloc: invalid device type %d\n", dev->type); + dmab->area = NULL; + dmab->addr = 0; + return -ENXIO; + } + if (! dmab->area) + return -ENOMEM; + dmab->bytes = size; + return 0; +} + +/** + * snd_dma_alloc_pages_fallback - allocate the buffer area according to the given type with fallback + * @dev: the buffer device info + * @size: the buffer size to allocate + * @dmab: buffer allocation record to store the allocated data + * + * Calls the memory-allocator function for the corresponding + * buffer type. When no space is left, this function reduces the size and + * tries to allocate again. The size actually allocated is stored in + * res_size argument. + * + * Returns zero if the buffer with the given size is allocated successfuly, + * other a negative value at error. + */ +int snd_dma_alloc_pages_fallback(const struct snd_dma_device *dev, size_t size, + struct snd_dma_buffer *dmab) +{ + snd_assert(dev != NULL, return -ENXIO); + snd_assert(size > 0, return -ENXIO); + snd_assert(dmab != NULL, return -ENXIO); + + dmab->bytes = 0; + switch (dev->type) { + case SNDRV_DMA_TYPE_CONTINUOUS: + dmab->area = snd_malloc_pages_fallback(size, (unsigned long)dev->dev, &dmab->bytes); + dmab->addr = 0; break; -#endif #ifdef CONFIG_SBUS case SNDRV_DMA_TYPE_SBUS: - dmab->area = snd_malloc_sbus_pages(dev->dev.sbus, size, &dmab->addr); + dmab->area = snd_malloc_sbus_pages_fallback(dev->dev, size, &dmab->addr, &dmab->bytes); break; #endif + case SNDRV_DMA_TYPE_DEV: + dmab->area = snd_malloc_dev_pages_fallback(dev->dev, size, &dmab->addr, &dmab->bytes); + break; + case SNDRV_DMA_TYPE_DEV_SG: + snd_malloc_sgbuf_pages(dev, size, dmab, &dmab->bytes); + break; default: printk(KERN_ERR "snd-malloc: invalid device type %d\n", dev->type); dmab->area = NULL; @@ -212,7 +479,6 @@ } if (! dmab->area) return -ENOMEM; - dmab->bytes = size; return 0; } @@ -230,24 +496,17 @@ case SNDRV_DMA_TYPE_CONTINUOUS: snd_free_pages(dmab->area, dmab->bytes); break; -#ifdef CONFIG_ISA - case SNDRV_DMA_TYPE_ISA: - snd_free_isa_pages(dmab->bytes, dmab->area, dmab->addr); +#ifdef CONFIG_SBUS + case SNDRV_DMA_TYPE_SBUS: + snd_free_sbus_pages(dev->dev, dmab->bytes, dmab->area, dmab->addr); break; #endif -#ifdef CONFIG_PCI - case SNDRV_DMA_TYPE_PCI: - snd_free_pci_pages(dev->dev.pci, dmab->bytes, dmab->area, dmab->addr); + case SNDRV_DMA_TYPE_DEV: + snd_free_dev_pages(dev->dev, dmab->bytes, dmab->area, dmab->addr); break; - case SNDRV_DMA_TYPE_PCI_SG: + case SNDRV_DMA_TYPE_DEV_SG: snd_free_sgbuf_pages(dmab); break; -#endif -#ifdef CONFIG_SBUS - case SNDRV_DMA_TYPE_SBUS: - snd_free_sbus_pages(dev->dev.sbus, dmab->bytes, dmab->area, dmab->addr); - break; -#endif default: printk(KERN_ERR "snd-malloc: invalid device type %d\n", dev->type); } @@ -396,394 +655,6 @@ } -/* - * - * Generic memory allocators - * - */ - -static long snd_allocated_pages; /* holding the number of allocated pages */ - -static void mark_pages(void *res, int order) -{ - struct page *page = virt_to_page(res); - struct page *last_page = page + (1 << order); - while (page < last_page) - SetPageReserved(page++); - snd_allocated_pages += 1 << order; -} - -static void unmark_pages(void *res, int order) -{ - struct page *page = virt_to_page(res); - struct page *last_page = page + (1 << order); - while (page < last_page) - ClearPageReserved(page++); - snd_allocated_pages -= 1 << order; -} - -/** - * snd_malloc_pages - allocate pages with the given size - * @size: the size to allocate in bytes - * @gfp_flags: the allocation conditions, GFP_XXX - * - * Allocates the physically contiguous pages with the given size. - * - * Returns the pointer of the buffer, or NULL if no enoguh memory. - */ -void *snd_malloc_pages(size_t size, unsigned int gfp_flags) -{ - int pg; - void *res; - - snd_assert(size > 0, return NULL); - snd_assert(gfp_flags != 0, return NULL); - for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++); - if ((res = (void *) __get_free_pages(gfp_flags, pg)) != NULL) { - mark_pages(res, pg); - } - return res; -} - -/** - * snd_malloc_pages_fallback - allocate pages with the given size with fallback - * @size: the requested size to allocate in bytes - * @gfp_flags: the allocation conditions, GFP_XXX - * @res_size: the pointer to store the size of buffer actually allocated - * - * Allocates the physically contiguous pages with the given request - * size. When no space is left, this function reduces the size and - * tries to allocate again. The size actually allocated is stored in - * res_size argument. - * - * Returns the pointer of the buffer, or NULL if no enoguh memory. - */ -void *snd_malloc_pages_fallback(size_t size, unsigned int gfp_flags, size_t *res_size) -{ - void *res; - - snd_assert(size > 0, return NULL); - snd_assert(res_size != NULL, return NULL); - do { - if ((res = snd_malloc_pages(size, gfp_flags)) != NULL) { - *res_size = size; - return res; - } - size >>= 1; - } while (size >= PAGE_SIZE); - return NULL; -} - -/** - * snd_free_pages - release the pages - * @ptr: the buffer pointer to release - * @size: the allocated buffer size - * - * Releases the buffer allocated via snd_malloc_pages(). - */ -void snd_free_pages(void *ptr, size_t size) -{ - int pg; - - if (ptr == NULL) - return; - for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++); - unmark_pages(ptr, pg); - free_pages((unsigned long) ptr, pg); -} - -#if defined(CONFIG_ISA) && ! defined(CONFIG_PCI) - -/** - * snd_malloc_isa_pages - allocate pages for ISA bus with the given size - * @size: the size to allocate in bytes - * @dma_addr: the pointer to store the physical address of the buffer - * - * Allocates the physically contiguous pages with the given size for - * ISA bus. - * - * Returns the pointer of the buffer, or NULL if no enoguh memory. - */ -void *snd_malloc_isa_pages(size_t size, dma_addr_t *dma_addr) -{ - void *dma_area; - dma_area = snd_malloc_pages(size, GFP_ATOMIC|GFP_DMA); - *dma_addr = dma_area ? isa_virt_to_bus(dma_area) : 0UL; - return dma_area; -} - -/** - * snd_malloc_isa_pages_fallback - allocate pages with the given size with fallback for ISA bus - * @size: the requested size to allocate in bytes - * @dma_addr: the pointer to store the physical address of the buffer - * @res_size: the pointer to store the size of buffer actually allocated - * - * Allocates the physically contiguous pages with the given request - * size for PCI bus. When no space is left, this function reduces the size and - * tries to allocate again. The size actually allocated is stored in - * res_size argument. - * - * Returns the pointer of the buffer, or NULL if no enoguh memory. - */ -void *snd_malloc_isa_pages_fallback(size_t size, - dma_addr_t *dma_addr, - size_t *res_size) -{ - void *dma_area; - dma_area = snd_malloc_pages_fallback(size, GFP_ATOMIC|GFP_DMA, res_size); - *dma_addr = dma_area ? isa_virt_to_bus(dma_area) : 0UL; - return dma_area; -} - -#endif /* CONFIG_ISA && !CONFIG_PCI */ - -#ifdef CONFIG_PCI - -/** - * snd_malloc_pci_pages - allocate pages for PCI bus with the given size - * @pci: the pci device pointer - * @size: the size to allocate in bytes - * @dma_addr: the pointer to store the physical address of the buffer - * - * Allocates the physically contiguous pages with the given size for - * PCI bus. - * - * Returns the pointer of the buffer, or NULL if no enoguh memory. - */ -void *snd_malloc_pci_pages(struct pci_dev *pci, - size_t size, - dma_addr_t *dma_addr) -{ - int pg; - void *res; - - snd_assert(size > 0, return NULL); - snd_assert(dma_addr != NULL, return NULL); - for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++); - res = pci_alloc_consistent(pci, PAGE_SIZE * (1 << pg), dma_addr); - if (res != NULL) { - mark_pages(res, pg); - } - return res; -} - -/** - * snd_malloc_pci_pages_fallback - allocate pages with the given size with fallback for PCI bus - * @pci: pci device pointer - * @size: the requested size to allocate in bytes - * @dma_addr: the pointer to store the physical address of the buffer - * @res_size: the pointer to store the size of buffer actually allocated - * - * Allocates the physically contiguous pages with the given request - * size for PCI bus. When no space is left, this function reduces the size and - * tries to allocate again. The size actually allocated is stored in - * res_size argument. - * - * Returns the pointer of the buffer, or NULL if no enoguh memory. - */ -void *snd_malloc_pci_pages_fallback(struct pci_dev *pci, - size_t size, - dma_addr_t *dma_addr, - size_t *res_size) -{ - void *res; - - snd_assert(res_size != NULL, return NULL); - do { - if ((res = snd_malloc_pci_pages(pci, size, dma_addr)) != NULL) { - *res_size = size; - return res; - } - size >>= 1; - } while (size >= PAGE_SIZE); - return NULL; -} - -/** - * snd_free_pci_pages - release the pages - * @pci: pci device pointer - * @size: the allocated buffer size - * @ptr: the buffer pointer to release - * @dma_addr: the physical address of the buffer - * - * Releases the buffer allocated via snd_malloc_pci_pages(). - */ -void snd_free_pci_pages(struct pci_dev *pci, - size_t size, - void *ptr, - dma_addr_t dma_addr) -{ - int pg; - - if (ptr == NULL) - return; - for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++); - unmark_pages(ptr, pg); - pci_free_consistent(pci, PAGE_SIZE * (1 << pg), ptr, dma_addr); -} - - -#if defined(__i386__) -/* - * on ix86, we allocate a page with GFP_KERNEL to assure the - * allocation. the code is almost same with kernel/i386/pci-dma.c but - * it allocates only a single page and checks the validity of the - * page address with the given pci dma mask. - */ - -/** - * snd_malloc_pci_page - allocate a page in the valid pci dma mask - * @pci: pci device pointer - * @addrp: the pointer to store the physical address of the buffer - * - * Allocates a single page for the given PCI device and returns - * the virtual address and stores the physical address on addrp. - * - * This function cannot be called from interrupt handlers or - * within spinlocks. - */ -void *snd_malloc_pci_page(struct pci_dev *pci, dma_addr_t *addrp) -{ - void *ptr; - dma_addr_t addr; - unsigned long mask; - - mask = pci ? (unsigned long)pci->consistent_dma_mask : 0x00ffffffUL; - ptr = (void *)__get_free_page(GFP_KERNEL); - if (ptr) { - addr = virt_to_phys(ptr); - if (((unsigned long)addr + PAGE_SIZE - 1) & ~mask) { - /* try to reallocate with the GFP_DMA */ - free_page((unsigned long)ptr); - /* use GFP_ATOMIC for the DMA zone to avoid stall */ - ptr = (void *)__get_free_page(GFP_ATOMIC | GFP_DMA); - if (ptr) /* ok, the address must be within lower 16MB... */ - addr = virt_to_phys(ptr); - else - addr = 0; - } - } else - addr = 0; - if (ptr) { - memset(ptr, 0, PAGE_SIZE); - mark_pages(ptr, 0); - } - *addrp = addr; - return ptr; -} -#else - -/* on other architectures, call snd_malloc_pci_pages() helper function - * which uses pci_alloc_consistent(). - */ -void *snd_malloc_pci_page(struct pci_dev *pci, dma_addr_t *addrp) -{ - return snd_malloc_pci_pages(pci, PAGE_SIZE, addrp); -} - -#endif - -#if 0 /* for kernel-doc */ -/** - * snd_free_pci_page - release a page - * @pci: pci device pointer - * @ptr: the buffer pointer to release - * @dma_addr: the physical address of the buffer - * - * Releases the buffer allocated via snd_malloc_pci_page(). - */ -void snd_free_pci_page(struct pci_dev *pci, void *ptr, dma_addr_t dma_addr); -#endif /* for kernel-doc */ - -#endif /* CONFIG_PCI */ - -#ifdef CONFIG_SBUS - -/** - * snd_malloc_sbus_pages - allocate pages for SBUS with the given size - * @sdev: sbus device pointer - * @size: the size to allocate in bytes - * @dma_addr: the pointer to store the physical address of the buffer - * - * Allocates the physically contiguous pages with the given size for - * SBUS. - * - * Returns the pointer of the buffer, or NULL if no enoguh memory. - */ -void *snd_malloc_sbus_pages(struct sbus_dev *sdev, - size_t size, - dma_addr_t *dma_addr) -{ - int pg; - void *res; - - snd_assert(size > 0, return NULL); - snd_assert(dma_addr != NULL, return NULL); - for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++); - res = sbus_alloc_consistent(sdev, PAGE_SIZE * (1 << pg), dma_addr); - if (res != NULL) { - mark_pages(res, pg); - } - return res; -} - -/** - * snd_malloc_pci_pages_fallback - allocate pages with the given size with fallback for SBUS - * @sdev: sbus device pointer - * @size: the requested size to allocate in bytes - * @dma_addr: the pointer to store the physical address of the buffer - * @res_size: the pointer to store the size of buffer actually allocated - * - * Allocates the physically contiguous pages with the given request - * size for SBUS. When no space is left, this function reduces the size and - * tries to allocate again. The size actually allocated is stored in - * res_size argument. - * - * Returns the pointer of the buffer, or NULL if no enoguh memory. - */ -void *snd_malloc_sbus_pages_fallback(struct sbus_dev *sdev, - size_t size, - dma_addr_t *dma_addr, - size_t *res_size) -{ - void *res; - - snd_assert(res_size != NULL, return NULL); - do { - if ((res = snd_malloc_sbus_pages(sdev, size, dma_addr)) != NULL) { - *res_size = size; - return res; - } - size >>= 1; - } while (size >= PAGE_SIZE); - return NULL; -} - -/** - * snd_free_sbus_pages - release the pages - * @sdev: sbus device pointer - * @size: the allocated buffer size - * @ptr: the buffer pointer to release - * @dma_addr: the physical address of the buffer - * - * Releases the buffer allocated via snd_malloc_pci_pages(). - */ -void snd_free_sbus_pages(struct sbus_dev *sdev, - size_t size, - void *ptr, - dma_addr_t dma_addr) -{ - int pg; - - if (ptr == NULL) - return; - for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++); - unmark_pages(ptr, pg); - sbus_free_consistent(sdev, PAGE_SIZE * (1 << pg), ptr, dma_addr); -} - -#endif /* CONFIG_SBUS */ - /* * allocation of buffers for pre-defined devices @@ -821,6 +692,17 @@ { }, /* terminator */ }; +/* + * compose a snd_dma_device struct for the PCI device + */ +static inline void snd_dma_device_pci(struct snd_dma_device *dev, struct pci_dev *pci, unsigned int id) +{ + memset(dev, 0, sizeof(*dev)); + dev->type = SNDRV_DMA_TYPE_DEV; + dev->dev = snd_dma_pci_data(pci); + dev->id = id; +} + static void __init preallocate_cards(void) { struct pci_dev *pci = NULL; @@ -902,29 +784,25 @@ len += sprintf(page + len, " : type "); switch (mem->dev.type) { case SNDRV_DMA_TYPE_CONTINUOUS: - len += sprintf(page + len, "CONT [%x]", mem->dev.dev.flags); - break; -#ifdef CONFIG_PCI - case SNDRV_DMA_TYPE_PCI: - case SNDRV_DMA_TYPE_PCI_SG: - if (mem->dev.dev.pci) { - len += sprintf(page + len, "%s [%04x:%04x]", - mem->dev.type == SNDRV_DMA_TYPE_PCI ? "PCI" : "PCI-SG", - mem->dev.dev.pci->vendor, - mem->dev.dev.pci->device); - } - break; -#endif -#ifdef CONFIG_ISA - case SNDRV_DMA_TYPE_ISA: - len += sprintf(page + len, "ISA [%x]", mem->dev.dev.flags); + len += sprintf(page + len, "CONT [%p]", mem->dev.dev); break; -#endif #ifdef CONFIG_SBUS case SNDRV_DMA_TYPE_SBUS: - len += sprintf(page + len, "SBUS [%x]", mem->dev.dev.sbus->slot); + { + struct sbus_dev *sdev = (struct sbus_dev *)(mem->dev.dev); + len += sprintf(page + len, "SBUS [%x]", sbus->slot); + } break; #endif + case SNDRV_DMA_TYPE_DEV: + case SNDRV_DMA_TYPE_DEV_SG: + if (mem->dev.dev) { + len += sprintf(page + len, "%s [%s]", + mem->dev.type == SNDRV_DMA_TYPE_DEV_SG ? "DEV-SG" : "DEV", + mem->dev.dev->bus_id); + } else + len += sprintf(page + len, "ISA"); + break; default: len += sprintf(page + len, "UNKNOWN"); break; @@ -987,7 +865,9 @@ * exports */ EXPORT_SYMBOL(snd_dma_alloc_pages); +EXPORT_SYMBOL(snd_dma_alloc_pages_fallback); EXPORT_SYMBOL(snd_dma_free_pages); + EXPORT_SYMBOL(snd_dma_get_reserved); EXPORT_SYMBOL(snd_dma_free_reserved); EXPORT_SYMBOL(snd_dma_set_reserved); @@ -995,20 +875,3 @@ EXPORT_SYMBOL(snd_malloc_pages); EXPORT_SYMBOL(snd_malloc_pages_fallback); EXPORT_SYMBOL(snd_free_pages); -#if defined(CONFIG_ISA) && ! defined(CONFIG_PCI) -EXPORT_SYMBOL(snd_malloc_isa_pages); -EXPORT_SYMBOL(snd_malloc_isa_pages_fallback); -#endif -#ifdef CONFIG_PCI -EXPORT_SYMBOL(snd_malloc_pci_pages); -EXPORT_SYMBOL(snd_malloc_pci_pages_fallback); -EXPORT_SYMBOL(snd_malloc_pci_page); -EXPORT_SYMBOL(snd_free_pci_pages); -EXPORT_SYMBOL(snd_malloc_sgbuf_pages); -EXPORT_SYMBOL(snd_free_sgbuf_pages); -#endif -#ifdef CONFIG_SBUS -EXPORT_SYMBOL(snd_malloc_sbus_pages); -EXPORT_SYMBOL(snd_malloc_sbus_pages_fallback); -EXPORT_SYMBOL(snd_free_sbus_pages); -#endif diff -Nru a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c --- a/sound/core/oss/pcm_oss.c Sun Mar 14 14:20:08 2004 +++ b/sound/core/oss/pcm_oss.c Sun Mar 14 14:20:08 2004 @@ -133,6 +133,15 @@ return (runtime->oss.buffer_bytes * frames) / buffer_size; } +static long snd_pcm_alsa_frames(snd_pcm_substream_t *substream, long bytes) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + snd_pcm_uframes_t buffer_size = snd_pcm_lib_buffer_bytes(substream); + if (buffer_size == runtime->oss.buffer_bytes) + return bytes_to_frames(runtime, bytes); + return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes); +} + static int snd_pcm_oss_format_from(int format) { switch (format) { @@ -254,6 +263,7 @@ snd_assert(oss_period_size >= 16, return -EINVAL); runtime->oss.period_bytes = oss_period_size; + runtime->oss.period_frames = 1; runtime->oss.periods = oss_periods; return 0; } @@ -511,6 +521,8 @@ if (runtime->dma_area) snd_pcm_format_set_silence(runtime->format, runtime->dma_area, bytes_to_samples(runtime, runtime->dma_bytes)); + runtime->oss.period_frames = snd_pcm_alsa_frames(substream, oss_period_size); + err = 0; failure: if (sw_params) @@ -2098,7 +2110,7 @@ if (atomic_read(&runtime->mmap_count)) return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt; else - return snd_pcm_playback_ready(substream); + return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames; } static int snd_pcm_oss_capture_ready(snd_pcm_substream_t *substream) @@ -2107,7 +2119,7 @@ if (atomic_read(&runtime->mmap_count)) return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt; else - return snd_pcm_capture_ready(substream); + return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames; } static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait) diff -Nru a/sound/core/pcm.c b/sound/core/pcm.c --- a/sound/core/pcm.c Sun Mar 14 14:20:08 2004 +++ b/sound/core/pcm.c Sun Mar 14 14:20:08 2004 @@ -327,8 +327,9 @@ snd_iprintf(buffer, "OSS format: %s\n", snd_pcm_oss_format_name(runtime->oss.format)); snd_iprintf(buffer, "OSS channels: %u\n", runtime->oss.channels); snd_iprintf(buffer, "OSS rate: %u\n", runtime->oss.rate); - snd_iprintf(buffer, "OSS period bytes: %lu\n", (unsigned long)runtime->oss.period_bytes); + snd_iprintf(buffer, "OSS period bytes: %lu\n", (unsigned long)runtime->oss.period_bytes); snd_iprintf(buffer, "OSS periods: %u\n", runtime->oss.periods); + snd_iprintf(buffer, "OSS period frames: %lu\n", (unsigned long)runtime->oss.period_frames); } #endif snd_pcm_stream_unlock_irq(substream); @@ -1060,3 +1061,4 @@ EXPORT_SYMBOL(snd_pcm_format_silence_64); EXPORT_SYMBOL(snd_pcm_format_set_silence); EXPORT_SYMBOL(snd_pcm_build_linear_format); +EXPORT_SYMBOL(snd_pcm_limit_hw_rates); diff -Nru a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c --- a/sound/core/pcm_lib.c Sun Mar 14 14:20:07 2004 +++ b/sound/core/pcm_lib.c Sun Mar 14 14:20:07 2004 @@ -67,8 +67,11 @@ frames = runtime->silence_size; } else { if (new_hw_ptr == ULONG_MAX) { /* initialization */ - runtime->silence_filled = 0; - runtime->silence_start = runtime->control->appl_ptr; + snd_pcm_sframes_t avail = snd_pcm_playback_hw_avail(runtime); + runtime->silence_filled = avail > 0 ? avail : 0; + runtime->silence_start = (runtime->status->hw_ptr + + runtime->silence_filled) % + runtime->boundary; } else { ofs = runtime->status->hw_ptr; frames = new_hw_ptr - ofs; @@ -2659,20 +2662,6 @@ EXPORT_SYMBOL(snd_pcm_lib_preallocate_free_for_all); EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages); EXPORT_SYMBOL(snd_pcm_lib_preallocate_pages_for_all); +EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page); EXPORT_SYMBOL(snd_pcm_lib_malloc_pages); EXPORT_SYMBOL(snd_pcm_lib_free_pages); -#ifdef CONFIG_ISA -EXPORT_SYMBOL(snd_pcm_lib_preallocate_isa_pages); -EXPORT_SYMBOL(snd_pcm_lib_preallocate_isa_pages_for_all); -#endif -#ifdef CONFIG_PCI -EXPORT_SYMBOL(snd_pcm_lib_preallocate_pci_pages); -EXPORT_SYMBOL(snd_pcm_lib_preallocate_pci_pages_for_all); -EXPORT_SYMBOL(snd_pcm_lib_preallocate_sg_pages); -EXPORT_SYMBOL(snd_pcm_lib_preallocate_sg_pages_for_all); -EXPORT_SYMBOL(snd_pcm_sgbuf_ops_page); -#endif -#ifdef CONFIG_SBUS -EXPORT_SYMBOL(snd_pcm_lib_preallocate_sbus_pages); -EXPORT_SYMBOL(snd_pcm_lib_preallocate_sbus_pages_for_all); -#endif diff -Nru a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c --- a/sound/core/pcm_memory.c Sun Mar 14 14:20:07 2004 +++ b/sound/core/pcm_memory.c Sun Mar 14 14:20:07 2004 @@ -229,97 +229,71 @@ } /** - * snd_pcm_lib_preallocate_pages - pre-allocation for the continuous memory type + * snd_pcm_lib_preallocate_pages - pre-allocation for the given DMA type * @substream: the pcm substream instance + * @type: DMA type (SNDRV_DMA_TYPE_*) + * @data: DMA type dependant data * @size: the requested pre-allocation size in bytes * @max: the max. allowed pre-allocation size - * @flags: allocation condition, GFP_XXX * - * Do pre-allocation for the continuous memory type. + * Do pre-allocation for the given DMA type. * * Returns zero if successful, or a negative error code on failure. */ int snd_pcm_lib_preallocate_pages(snd_pcm_substream_t *substream, - size_t size, size_t max, - unsigned int flags) + int type, struct device *data, + size_t size, size_t max) { - substream->dma_device.type = SNDRV_DMA_TYPE_CONTINUOUS; - substream->dma_device.dev.flags = flags; + substream->dma_device.type = type; + substream->dma_device.dev = data; setup_pcm_id(substream); return snd_pcm_lib_preallocate_pages1(substream, size, max); } /** * snd_pcm_lib_preallocate_pages_for_all - pre-allocation for continous memory type (all substreams) - * @pcm: pcm to assign the buffer + * @substream: the pcm substream instance + * @type: DMA type (SNDRV_DMA_TYPE_*) + * @data: DMA type dependant data * @size: the requested pre-allocation size in bytes - * @max: max. buffer size acceptable for the changes via proc file - * @flags: allocation condition, GFP_XXX + * @max: the max. allowed pre-allocation size * * Do pre-allocation to all substreams of the given pcm for the - * continuous memory type. + * specified DMA type. * * Returns zero if successful, or a negative error code on failure. */ int snd_pcm_lib_preallocate_pages_for_all(snd_pcm_t *pcm, - size_t size, size_t max, - unsigned int flags) + int type, void *data, + size_t size, size_t max) { snd_pcm_substream_t *substream; int stream, err; for (stream = 0; stream < 2; stream++) for (substream = pcm->streams[stream].substream; substream; substream = substream->next) - if ((err = snd_pcm_lib_preallocate_pages(substream, size, max, flags)) < 0) + if ((err = snd_pcm_lib_preallocate_pages(substream, type, data, size, max)) < 0) return err; return 0; } -#ifdef CONFIG_ISA /** - * snd_pcm_lib_preallocate_isa_pages - pre-allocation for the ISA bus - * @substream: substream to assign the buffer - * @size: the requested pre-allocation size in bytes - * @max: max. buffer size acceptable for the changes via proc file - * - * Do pre-allocation for the ISA bus. - * - * Returns zero if successful, or a negative error code on failure. - */ -int snd_pcm_lib_preallocate_isa_pages(snd_pcm_substream_t *substream, - size_t size, size_t max) -{ - substream->dma_device.type = SNDRV_DMA_TYPE_ISA; - substream->dma_device.dev.flags = 0; /* FIXME: any good identifier? */ - setup_pcm_id(substream); - return snd_pcm_lib_preallocate_pages1(substream, size, max); -} - -/* - * FIXME: the function name is too long for docbook! - * - * snd_pcm_lib_preallocate_isa_pages_for_all - pre-allocation for the ISA bus (all substreams) - * @pcm: pcm to assign the buffer - * @max: max. buffer size acceptable for the changes via proc file - * - * Do pre-allocation to all substreams of the given pcm for the - * ISA bus. + * snd_pcm_sgbuf_ops_page - get the page struct at the given offset + * @substream: the pcm substream instance + * @offset: the buffer offset * - * Returns zero if successful, or a negative error code on failure. + * Returns the page struct at the given buffer offset. + * Used as the page callback of PCM ops. */ -int snd_pcm_lib_preallocate_isa_pages_for_all(snd_pcm_t *pcm, - size_t size, size_t max) +struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset) { - snd_pcm_substream_t *substream; - int stream, err; + struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream); - for (stream = 0; stream < 2; stream++) - for (substream = pcm->streams[stream].substream; substream; substream = substream->next) - if ((err = snd_pcm_lib_preallocate_isa_pages(substream, size, max)) < 0) - return err; - return 0; + unsigned int idx = offset >> PAGE_SHIFT; + if (idx >= (unsigned int)sgbuf->pages) + return NULL; + return sgbuf->page_table[idx]; } -#endif /* CONFIG_ISA */ /** * snd_pcm_lib_malloc_pages - allocate the DMA buffer @@ -397,183 +371,6 @@ runtime->dma_private = NULL; return 0; } - -#ifdef CONFIG_PCI -/** - * snd_pcm_lib_preallocate_pci_pages - pre-allocation for the PCI bus - * - * @pci: pci device - * @substream: substream to assign the buffer - * @size: the requested pre-allocation size in bytes - * @max: max. buffer size acceptable for the changes via proc file - * - * Do pre-allocation for the PCI bus. - * - * Returns zero if successful, or a negative error code on failure. - */ -int snd_pcm_lib_preallocate_pci_pages(struct pci_dev *pci, - snd_pcm_substream_t *substream, - size_t size, size_t max) -{ - substream->dma_device.type = SNDRV_DMA_TYPE_PCI; - substream->dma_device.dev.pci = pci; - setup_pcm_id(substream); - return snd_pcm_lib_preallocate_pages1(substream, size, max); -} - -/* - * FIXME: the function name is too long for docbook! - * - * snd_pcm_lib_preallocate_pci_pages_for_all - pre-allocation for the PCI bus (all substreams) - * @pci: pci device - * @pcm: pcm to assign the buffer - * @size: the requested pre-allocation size in bytes - * @max: max. buffer size acceptable for the changes via proc file - * - * Do pre-allocation to all substreams of the given pcm for the - * PCI bus. - * - * Returns zero if successful, or a negative error code on failure. - */ -int snd_pcm_lib_preallocate_pci_pages_for_all(struct pci_dev *pci, - snd_pcm_t *pcm, - size_t size, size_t max) -{ - snd_pcm_substream_t *substream; - int stream, err; - - for (stream = 0; stream < 2; stream++) - for (substream = pcm->streams[stream].substream; substream; substream = substream->next) - if ((err = snd_pcm_lib_preallocate_pci_pages(pci, substream, size, max)) < 0) - return err; - return 0; -} - -#endif /* CONFIG_PCI */ - -#ifdef CONFIG_SBUS -/** - * snd_pcm_lib_preallocate_sbus_pages - pre-allocation for the SBUS bus - * - * @sbus: SBUS device - * @substream: substream to assign the buffer - * @max: max. buffer size acceptable for the changes via proc file - * - * Do pre-allocation for the SBUS. - * - * Returns zero if successful, or a negative error code on failure. - */ -int snd_pcm_lib_preallocate_sbus_pages(struct sbus_dev *sdev, - snd_pcm_substream_t *substream, - size_t size, size_t max) -{ - substream->dma_device.type = SNDRV_DMA_TYPE_SBUS; - substream->dma_device.dev.sbus = sdev; - setup_pcm_id(substream); - return snd_pcm_lib_preallocate_pages1(substream, size, max); -} - -/* - * FIXME: the function name is too long for docbook! - * - * snd_pcm_lib_preallocate_sbus_pages_for_all - pre-allocation for the SBUS bus (all substreams) - * @sbus: SBUS device - * @pcm: pcm to assign the buffer - * @size: the requested pre-allocation size in bytes - * @max: max. buffer size acceptable for the changes via proc file - * - * Do pre-allocation to all substreams of the given pcm for the - * SUBS. - * - * Returns zero if successful, or a negative error code on failure. - */ -int snd_pcm_lib_preallocate_sbus_pages_for_all(struct sbus_dev *sdev, - snd_pcm_t *pcm, - size_t size, size_t max) -{ - snd_pcm_substream_t *substream; - int stream, err; - - for (stream = 0; stream < 2; stream++) - for (substream = pcm->streams[stream].substream; substream; substream = substream->next) - if ((err = snd_pcm_lib_preallocate_sbus_pages(sdev, substream, size, max)) < 0) - return err; - return 0; -} - -#endif /* CONFIG_SBUS */ - - -#ifdef CONFIG_PCI -/** - * snd_pcm_lib_preallocate_sg_pages - initialize SG-buffer for the PCI bus - * - * @pci: pci device - * @substream: substream to assign the buffer - * @size: the requested pre-allocation size in bytes - * @max: max. buffer size acceptable for the changes via proc file - * - * Initializes SG-buffer for the PCI bus. - * - * Returns zero if successful, or a negative error code on failure. - */ -int snd_pcm_lib_preallocate_sg_pages(struct pci_dev *pci, - snd_pcm_substream_t *substream, - size_t size, size_t max) -{ - substream->dma_device.type = SNDRV_DMA_TYPE_PCI_SG; - substream->dma_device.dev.pci = pci; - setup_pcm_id(substream); - return snd_pcm_lib_preallocate_pages1(substream, size, max); -} - -/* - * FIXME: the function name is too long for docbook! - * - * snd_pcm_lib_preallocate_sg_pages_for_all - initialize SG-buffer for the PCI bus (all substreams) - * @pci: pci device - * @pcm: pcm to assign the buffer - * @size: the requested pre-allocation size in bytes - * @max: max. buffer size acceptable for the changes via proc file - * - * Initialize the SG-buffer to all substreams of the given pcm for the - * PCI bus. - * - * Returns zero if successful, or a negative error code on failure. - */ -int snd_pcm_lib_preallocate_sg_pages_for_all(struct pci_dev *pci, - snd_pcm_t *pcm, - size_t size, size_t max) -{ - snd_pcm_substream_t *substream; - int stream, err; - - for (stream = 0; stream < 2; stream++) - for (substream = pcm->streams[stream].substream; substream; substream = substream->next) - if ((err = snd_pcm_lib_preallocate_sg_pages(pci, substream, size, max)) < 0) - return err; - return 0; -} - -/** - * snd_pcm_sgbuf_ops_page - get the page struct at the given offset - * @substream: the pcm substream instance - * @offset: the buffer offset - * - * Returns the page struct at the given buffer offset. - * Used as the page callback of PCM ops. - */ -struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset) -{ - struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream); - - unsigned int idx = offset >> PAGE_SHIFT; - if (idx >= (unsigned int)sgbuf->pages) - return NULL; - return sgbuf->page_table[idx]; -} - -#endif /* CONFIG_PCI */ #ifndef MODULE diff -Nru a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c --- a/sound/core/pcm_misc.c Sun Mar 14 14:20:08 2004 +++ b/sound/core/pcm_misc.c Sun Mar 14 14:20:08 2004 @@ -654,3 +654,35 @@ } return snd_int_to_enum(((int(*)[2][2])linear_formats)[width][!!unsignd][!!big_endian]); } + +/** + * snd_pcm_limit_hw_rates - determine rate_min/rate_max fields + * @runtime: the runtime instance + * + * Determines the rate_min and rate_max fields from the rates bits of + * the given runtime->hw. + * + * Returns zero if successful. + */ +int snd_pcm_limit_hw_rates(snd_pcm_runtime_t *runtime) +{ + static unsigned rates[] = { + /* ATTENTION: these values depend on the definition in pcm.h! */ + 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, + 64000, 88200, 96000, 176400, 192000 + }; + int i; + for (i = 0; i < (int)ARRAY_SIZE(rates); i++) { + if (runtime->hw.rates & (1 << i)) { + runtime->hw.rate_min = rates[i]; + break; + } + } + for (i = (int)ARRAY_SIZE(rates) - 1; i >= 0; i--) { + if (runtime->hw.rates & (1 << i)) { + runtime->hw.rate_max = rates[i]; + break; + } + } + return 0; +} diff -Nru a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c --- a/sound/core/seq/oss/seq_oss_init.c Sun Mar 14 14:20:06 2004 +++ b/sound/core/seq/oss/seq_oss_init.c Sun Mar 14 14:20:06 2004 @@ -349,18 +349,11 @@ static int delete_port(seq_oss_devinfo_t *dp) { - snd_seq_port_info_t port_info; - if (dp->port < 0) return 0; debug_printk(("delete_port %i\n", dp->port)); - memset(&port_info, 0, sizeof(port_info)); - port_info.addr.client = dp->cseq; - port_info.addr.port = dp->port; - return snd_seq_kernel_client_ctl(dp->cseq, - SNDRV_SEQ_IOCTL_DELETE_PORT, - &port_info); + return snd_seq_event_port_detach(dp->cseq, dp->port); } /* diff -Nru a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c --- a/sound/core/seq/oss/seq_oss_midi.c Sun Mar 14 14:20:05 2004 +++ b/sound/core/seq/oss/seq_oss_midi.c Sun Mar 14 14:20:05 2004 @@ -491,7 +491,7 @@ } } } - snd_seq_oss_midi_close(dp, dev); + // snd_seq_oss_midi_close(dp, dev); snd_use_lock_free(&mdev->use_lock); } @@ -578,6 +578,7 @@ ossev.v.code = EV_CHN_VOICE; ossev.v.note = ev->data.note.note; ossev.v.parm = ev->data.note.velocity; + ossev.v.chn = ev->data.note.channel; break; case SNDRV_SEQ_EVENT_CONTROLLER: case SNDRV_SEQ_EVENT_PGMCHANGE: @@ -585,10 +586,12 @@ ossev.l.code = EV_CHN_COMMON; ossev.l.p1 = ev->data.control.param; ossev.l.val = ev->data.control.value; + ossev.l.chn = ev->data.control.channel; break; case SNDRV_SEQ_EVENT_PITCHBEND: ossev.l.code = EV_CHN_COMMON; ossev.l.val = ev->data.control.value + 8192; + ossev.l.chn = ev->data.control.channel; break; } diff -Nru a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c --- a/sound/core/seq/oss/seq_oss_synth.c Sun Mar 14 14:20:06 2004 +++ b/sound/core/seq/oss/seq_oss_synth.c Sun Mar 14 14:20:06 2004 @@ -410,6 +410,8 @@ if (midi_synth_dev.opened <= 0) return; snd_seq_oss_midi_reset(dp, info->midi_mapped); + /* reopen the device */ + snd_seq_oss_midi_close(dp, dev); if (snd_seq_oss_midi_open(dp, info->midi_mapped, dp->file_mode) < 0) { midi_synth_dev.opened--; diff -Nru a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c --- a/sound/core/seq/seq_clientmgr.c Sun Mar 14 14:20:06 2004 +++ b/sound/core/seq/seq_clientmgr.c Sun Mar 14 14:20:06 2004 @@ -547,6 +547,36 @@ /* + * expand a quoted event. + */ +static int expand_quoted_event(snd_seq_event_t *event) +{ + snd_seq_event_t *quoted; + + quoted = event->data.quote.event; + if (quoted == NULL) { + snd_printd("seq: quoted event is NULL\n"); + return -EINVAL; + } + + event->type = quoted->type; + event->tag = quoted->tag; + event->source = quoted->source; + /* don't use quoted destination */ + event->data = quoted->data; + /* use quoted timestamp only if subscription/port didn't update it */ + if (event->queue == SNDRV_SEQ_QUEUE_DIRECT) { + event->flags = quoted->flags; + event->queue = quoted->queue; + event->time = quoted->time; + } else { + event->flags = (event->flags & SNDRV_SEQ_TIME_STAMP_MASK) + | (quoted->flags & ~SNDRV_SEQ_TIME_STAMP_MASK); + } + return 0; +} + +/* * deliver an event to the specified destination. * if filter is non-zero, client filter bitmap is tested. * @@ -581,12 +611,9 @@ update_timestamp_of_queue(event, dest_port->time_queue, dest_port->time_real); - /* expand the quoted event */ if (event->type == SNDRV_SEQ_EVENT_KERNEL_QUOTE) { quoted = 1; - event = event->data.quote.event; - if (event == NULL) { - snd_printd("seq: quoted event is NULL\n"); + if (expand_quoted_event(event) < 0) { result = 0; /* do not send bounce error */ goto __skip; } @@ -694,8 +721,8 @@ if (dest_client == NULL) return 0; /* no matching destination */ - read_lock(&client->ports_lock); - list_for_each(p, &client->ports_list_head) { + read_lock(&dest_client->ports_lock); + list_for_each(p, &dest_client->ports_list_head) { client_port_t *port = list_entry(p, client_port_t, list); event->dest.port = port->addr.port; /* pass NULL as source client to avoid error bounce */ @@ -706,7 +733,7 @@ break; num_ev++; } - read_unlock(&client->ports_lock); + read_unlock(&dest_client->ports_lock); snd_seq_client_unlock(dest_client); event->dest.port = SNDRV_SEQ_ADDRESS_BROADCAST; /* restore */ return (err < 0) ? err : num_ev; diff -Nru a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c --- a/sound/core/seq/seq_fifo.c Sun Mar 14 14:20:07 2004 +++ b/sound/core/seq/seq_fifo.c Sun Mar 14 14:20:07 2004 @@ -171,10 +171,12 @@ { snd_seq_event_cell_t *cell; unsigned long flags; + wait_queue_t wait; snd_assert(f != NULL, return -EINVAL); *cellp = NULL; + init_waitqueue_entry(&wait, current); spin_lock_irqsave(&f->lock, flags); while ((cell = fifo_cell_out(f)) == NULL) { if (nonblock) { @@ -182,17 +184,19 @@ spin_unlock_irqrestore(&f->lock, flags); return -EAGAIN; } - spin_unlock(&f->lock); - interruptible_sleep_on(&f->input_sleep); - spin_lock(&f->lock); - + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&f->input_sleep, &wait); + spin_unlock_irq(&f->lock); + schedule(); + spin_lock_irq(&f->lock); + remove_wait_queue(&f->input_sleep, &wait); if (signal_pending(current)) { spin_unlock_irqrestore(&f->lock, flags); return -ERESTARTSYS; } } - *cellp = cell; spin_unlock_irqrestore(&f->lock, flags); + *cellp = cell; return 0; } diff -Nru a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c --- a/sound/core/seq/seq_memory.c Sun Mar 14 14:20:06 2004 +++ b/sound/core/seq/seq_memory.c Sun Mar 14 14:20:06 2004 @@ -220,12 +220,14 @@ snd_seq_event_cell_t *cell; unsigned long flags; int err = -EAGAIN; + wait_queue_t wait; if (pool == NULL) return -EINVAL; *cellp = NULL; + init_waitqueue_entry(&wait, current); spin_lock_irqsave(&pool->lock, flags); if (pool->ptr == NULL) { /* not initialized */ snd_printd("seq: pool is not initialized\n"); @@ -234,9 +236,12 @@ } while (pool->free == NULL && ! nonblock && ! pool->closing) { - spin_unlock(&pool->lock); - interruptible_sleep_on(&pool->output_sleep); - spin_lock(&pool->lock); + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&pool->output_sleep, &wait); + spin_unlock_irq(&pool->lock); + schedule(); + spin_lock_irq(&pool->lock); + remove_wait_queue(&pool->output_sleep, &wait); /* interrupted? */ if (signal_pending(current)) { err = -ERESTARTSYS; diff -Nru a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c --- a/sound/core/seq/seq_midi.c Sun Mar 14 14:20:08 2004 +++ b/sound/core/seq/seq_midi.c Sun Mar 14 14:20:08 2004 @@ -257,17 +257,12 @@ /* delete given midi synth port */ static void snd_seq_midisynth_delete(seq_midisynth_t *msynth) { - snd_seq_port_info_t port; - if (msynth == NULL) return; if (msynth->seq_client > 0) { /* delete port */ - memset(&port, 0, sizeof(port)); - port.addr.client = msynth->seq_client; - port.addr.port = msynth->seq_port; - snd_seq_kernel_client_ctl(port.addr.client, SNDRV_SEQ_IOCTL_DELETE_PORT, &port); + snd_seq_event_port_detach(msynth->seq_client, msynth->seq_port); } if (msynth->parser) @@ -285,7 +280,7 @@ cinfo.client = client->seq_client; cinfo.type = KERNEL_CLIENT; name = rmidi->name[0] ? (const char *)rmidi->name : "External MIDI"; - snprintf(cinfo.name, sizeof(cinfo.name), "Rawmidi %d - %s", card->number, name); + snprintf(cinfo.name, sizeof(cinfo.name), "%s - Rawmidi %d", name, card->number); return snd_seq_kernel_client_ctl(client->seq_client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &cinfo); } @@ -443,7 +438,6 @@ up(®ister_mutex); return -ENODEV; } - snd_seq_event_port_detach(client->seq_client, client->ports[device]->seq_port); ports = client->ports_per_device[device]; client->ports_per_device[device] = 0; msynth = client->ports[device]; diff -Nru a/sound/core/sgbuf.c b/sound/core/sgbuf.c --- a/sound/core/sgbuf.c Sun Mar 14 14:20:07 2004 +++ b/sound/core/sgbuf.c Sun Mar 14 14:20:07 2004 @@ -20,7 +20,6 @@ */ #include -#include #include #include #include @@ -31,27 +30,42 @@ #define SGBUF_TBL_ALIGN 32 #define sgbuf_align_table(tbl) ((((tbl) + SGBUF_TBL_ALIGN - 1) / SGBUF_TBL_ALIGN) * SGBUF_TBL_ALIGN) +int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab) +{ + struct snd_sg_buf *sgbuf = dmab->private_data; + struct snd_dma_buffer tmpb; + int i; + + if (! sgbuf) + return -EINVAL; + + for (i = 0; i < sgbuf->pages; i++) { + tmpb.area = sgbuf->table[i].buf; + tmpb.addr = sgbuf->table[i].addr; + tmpb.bytes = PAGE_SIZE; + snd_dma_free_pages(&sgbuf->dev, &tmpb); + } + if (dmab->area) + vunmap(dmab->area); + dmab->area = NULL; + + if (sgbuf->table) + kfree(sgbuf->table); + if (sgbuf->page_table) + kfree(sgbuf->page_table); + kfree(sgbuf); + dmab->private_data = NULL; + + return 0; +} -/** - * snd_malloc_sgbuf_pages - allocate the pages for the PCI SG buffer - * @pci: the pci device pointer - * @size: the requested buffer size in bytes - * @dmab: the buffer record to store - * - * Initializes the SG-buffer table and allocates the buffer pages - * for the given size. - * The pages are mapped to the virtually continuous memory. - * - * This function is usually called from the middle-level functions such as - * snd_pcm_lib_malloc_pages(). - * - * Returns the mapped virtual address of the buffer if allocation was - * successful, or NULL at error. - */ -void *snd_malloc_sgbuf_pages(struct pci_dev *pci, size_t size, struct snd_dma_buffer *dmab) +void *snd_malloc_sgbuf_pages(const struct snd_dma_device *dev, + size_t size, struct snd_dma_buffer *dmab, + size_t *res_size) { struct snd_sg_buf *sgbuf; unsigned int i, pages; + struct snd_dma_buffer tmpb; dmab->area = NULL; dmab->addr = 0; @@ -59,7 +73,8 @@ if (! sgbuf) return NULL; memset(sgbuf, 0, sizeof(*sgbuf)); - sgbuf->pci = pci; + sgbuf->dev = *dev; + sgbuf->dev.type = SNDRV_DMA_TYPE_DEV; pages = snd_sgbuf_aligned_pages(size); sgbuf->tblsize = sgbuf_align_table(pages); sgbuf->table = kmalloc(sizeof(*sgbuf->table) * sgbuf->tblsize, GFP_KERNEL); @@ -73,14 +88,15 @@ /* allocate each page */ for (i = 0; i < pages; i++) { - void *ptr; - dma_addr_t addr; - ptr = snd_malloc_pci_page(sgbuf->pci, &addr); - if (! ptr) - goto _failed; - sgbuf->table[i].buf = ptr; - sgbuf->table[i].addr = addr; - sgbuf->page_table[i] = virt_to_page(ptr); + if (snd_dma_alloc_pages(&sgbuf->dev, PAGE_SIZE, &tmpb) < 0) { + if (res_size == NULL) + goto _failed; + *res_size = size = sgbuf->pages * PAGE_SIZE; + break; + } + sgbuf->table[i].buf = tmpb.area; + sgbuf->table[i].addr = tmpb.addr; + sgbuf->page_table[i] = virt_to_page(tmpb.area); sgbuf->pages++; } @@ -93,39 +109,4 @@ _failed: snd_free_sgbuf_pages(dmab); /* free the table */ return NULL; -} - -/** - * snd_free_sgbuf_pages - free the sg buffer - * @dmab: buffer record - * - * Releases the pages and the SG-buffer table. - * - * This function is called usually from the middle-level function - * such as snd_pcm_lib_free_pages(). - * - * Returns zero if successful, or a negative error code on failure. - */ -int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab) -{ - struct snd_sg_buf *sgbuf = dmab->private_data; - int i; - - if (! sgbuf) - return -EINVAL; - - for (i = 0; i < sgbuf->pages; i++) - snd_free_pci_page(sgbuf->pci, sgbuf->table[i].buf, sgbuf->table[i].addr); - if (dmab->area) - vunmap(dmab->area); - dmab->area = NULL; - - if (sgbuf->table) - kfree(sgbuf->table); - if (sgbuf->page_table) - kfree(sgbuf->page_table); - kfree(sgbuf); - dmab->private_data = NULL; - - return 0; } diff -Nru a/sound/drivers/Kconfig b/sound/drivers/Kconfig --- a/sound/drivers/Kconfig Sun Mar 14 14:20:08 2004 +++ b/sound/drivers/Kconfig Sun Mar 14 14:20:08 2004 @@ -3,17 +3,41 @@ menu "Generic devices" depends on SND!=n + +config SND_MPU401_UART + tristate + select SND_TIMER + select SND_RAWMIDI + +config SND_OPL3_LIB + tristate + select SND_TIMER + select SND_HWDEP + +config SND_OPL4_LIB + tristate + select SND_TIMER + select SND_HWDEP + +config SND_VX_LIB + tristate + select SND_HWDEP + select SND_PCM + + config SND_DUMMY tristate "Dummy (/dev/null) soundcard" depends on SND + select SND_PCM help Say 'Y' or 'M' to include dummy driver. This driver does nothing, but emulates various mixer controls and PCM devices. - config SND_VIRMIDI tristate "Virtual MIDI soundcard" depends on SND_SEQUENCER + select SND_TIMER + select SND_RAWMIDI help Say 'Y' or 'M' to include virtual MIDI driver. This driver allows to connect applications using raw MIDI devices to sequencer. @@ -21,6 +45,8 @@ config SND_MTPAV tristate "MOTU MidiTimePiece AV multiport MIDI" depends on SND + select SND_TIMER + select SND_RAWMIDI help Say 'Y' or 'M' to include support for MOTU MidiTimePiece AV multiport MIDI adapter. @@ -28,6 +54,8 @@ config SND_SERIAL_U16550 tristate "UART16550 - MIDI only driver" depends on SND + select SND_TIMER + select SND_RAWMIDI help Say 'Y' or 'M' to include support for MIDI serial port driver. It works with serial UARTs 16550 and better. @@ -35,8 +63,8 @@ config SND_MPU401 tristate "Generic MPU-401 UART driver" depends on SND + select SND_MPU401_UART help Say 'Y' or 'M' to include support for MPU401 hardware using UART access. endmenu - diff -Nru a/sound/drivers/mpu401/Makefile b/sound/drivers/mpu401/Makefile --- a/sound/drivers/mpu401/Makefile Sun Mar 14 14:20:08 2004 +++ b/sound/drivers/mpu401/Makefile Sun Mar 14 14:20:08 2004 @@ -6,40 +6,7 @@ snd-mpu401-objs := mpu401.o snd-mpu401-uart-objs := mpu401_uart.o -# Toplevel Module Dependency -obj-$(CONFIG_SND_MPU401) += snd-mpu401.o snd-mpu401-uart.o -obj-$(CONFIG_SND_ALS100) += snd-mpu401-uart.o -obj-$(CONFIG_SND_AZT2320) += snd-mpu401-uart.o -obj-$(CONFIG_SND_AZT3328) += snd-mpu401-uart.o -obj-$(CONFIG_SND_DT019X) += snd-mpu401-uart.o -obj-$(CONFIG_SND_ES18XX) += snd-mpu401-uart.o -obj-$(CONFIG_SND_OPL3SA2) += snd-mpu401-uart.o -obj-$(CONFIG_SND_AD1816A) += snd-mpu401-uart.o -obj-$(CONFIG_SND_CS4231) += snd-mpu401-uart.o -obj-$(CONFIG_SND_CS4232) += snd-mpu401-uart.o -obj-$(CONFIG_SND_CS4236) += snd-mpu401-uart.o -obj-$(CONFIG_SND_ES1688) += snd-mpu401-uart.o -obj-$(CONFIG_SND_GUSEXTREME) += snd-mpu401-uart.o -obj-$(CONFIG_SND_OPTI92X_AD1848) += snd-mpu401-uart.o -obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-mpu401-uart.o -obj-$(CONFIG_SND_OPTI93X) += snd-mpu401-uart.o -obj-$(CONFIG_SND_SB16) += snd-mpu401-uart.o -obj-$(CONFIG_SND_SBAWE) += snd-mpu401-uart.o -obj-$(CONFIG_SND_WAVEFRONT) += snd-mpu401-uart.o -obj-$(CONFIG_SND_ALS4000) += snd-mpu401-uart.o -obj-$(CONFIG_SND_CMIPCI) += snd-mpu401-uart.o -obj-$(CONFIG_SND_ES1938) += snd-mpu401-uart.o -obj-$(CONFIG_SND_ES1968) += snd-mpu401-uart.o -obj-$(CONFIG_SND_FM801) += snd-mpu401-uart.o -obj-$(CONFIG_SND_ICE1712) += snd-mpu401-uart.o -obj-$(CONFIG_SND_ICE1724) += snd-mpu401-uart.o -obj-$(CONFIG_SND_INTEL8X0) += snd-mpu401-uart.o -obj-$(CONFIG_SND_SONICVIBES) += snd-mpu401-uart.o -obj-$(CONFIG_SND_VIA82XX) += snd-mpu401-uart.o -obj-$(CONFIG_SND_ALI5451) += snd-mpu401-uart.o -obj-$(CONFIG_SND_TRIDENT) += snd-mpu401-uart.o -obj-$(CONFIG_SND_YMFPCI) += snd-mpu401-uart.o -obj-$(CONFIG_SND_PC98_CS4232) += snd-mpu401-uart.o -obj-$(CONFIG_SND_SSCAPE) += snd-mpu401-uart.o +obj-$(CONFIG_SND_MPU401_UART) += snd-mpu401-uart.o -obj-m := $(sort $(obj-m)) +# Toplevel Module Dependency +obj-$(CONFIG_SND_MPU401) += snd-mpu401.o diff -Nru a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c --- a/sound/drivers/mpu401/mpu401_uart.c Sun Mar 14 14:20:07 2004 +++ b/sound/drivers/mpu401/mpu401_uart.c Sun Mar 14 14:20:07 2004 @@ -528,9 +528,9 @@ mpu->irq = irq; mpu->irq_flags = irq_flags; if (card->shortname[0]) - snprintf(rmidi->name, sizeof(rmidi->name), "%s MPU-401", card->shortname); + snprintf(rmidi->name, sizeof(rmidi->name), "%s MIDI", card->shortname); else - sprintf(rmidi->name, "MPU-401 (UART) %d-%d", card->number, device); + sprintf(rmidi->name, "MPU-401 MIDI %d-%d", card->number, device); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_mpu401_uart_output); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_mpu401_uart_input); rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | diff -Nru a/sound/drivers/opl3/Makefile b/sound/drivers/opl3/Makefile --- a/sound/drivers/opl3/Makefile Sun Mar 14 14:20:05 2004 +++ b/sound/drivers/opl3/Makefile Sun Mar 14 14:20:05 2004 @@ -9,37 +9,13 @@ snd-opl3-synth-objs += opl3_oss.o endif -OPL3_OBJS = snd-opl3-lib.o -ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y) -OPL3_OBJS += snd-opl3-synth.o -endif +# +# this function returns: +# "m" - CONFIG_SND_SEQUENCER is m +# - CONFIG_SND_SEQUENCER is undefined +# otherwise parameter #1 value +# +sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) -# Toplevel Module Dependency -obj-$(CONFIG_SND_ALS100) += $(OPL3_OBJS) -obj-$(CONFIG_SND_AZT2320) += $(OPL3_OBJS) -obj-$(CONFIG_SND_AZT3328) += $(OPL3_OBJS) -obj-$(CONFIG_SND_DT019X) += $(OPL3_OBJS) -obj-$(CONFIG_SND_ES18XX) += $(OPL3_OBJS) -obj-$(CONFIG_SND_OPL3SA2) += $(OPL3_OBJS) -obj-$(CONFIG_SND_AD1816A) += $(OPL3_OBJS) -obj-$(CONFIG_SND_CS4232) += $(OPL3_OBJS) -obj-$(CONFIG_SND_PC98_CS4232) += $(OPL3_OBJS) -obj-$(CONFIG_SND_CS4236) += $(OPL3_OBJS) -obj-$(CONFIG_SND_ES1688) += $(OPL3_OBJS) -obj-$(CONFIG_SND_GUSEXTREME) += $(OPL3_OBJS) -obj-$(CONFIG_SND_OPTI92X_AD1848) += $(OPL3_OBJS) -obj-$(CONFIG_SND_OPTI92X_CS4231) += $(OPL3_OBJS) -obj-$(CONFIG_SND_OPTI93X) += $(OPL3_OBJS) -obj-$(CONFIG_SND_SB8) += $(OPL3_OBJS) -obj-$(CONFIG_SND_SB16) += $(OPL3_OBJS) -obj-$(CONFIG_SND_SBAWE) += $(OPL3_OBJS) -obj-$(CONFIG_SND_WAVEFRONT) += $(OPL3_OBJS) -obj-$(CONFIG_SND_ALS4000) += $(OPL3_OBJS) -obj-$(CONFIG_SND_CMIPCI) += $(OPL3_OBJS) -obj-$(CONFIG_SND_CS4281) += $(OPL3_OBJS) -obj-$(CONFIG_SND_ES1938) += $(OPL3_OBJS) -obj-$(CONFIG_SND_FM801) += $(OPL3_OBJS) -obj-$(CONFIG_SND_SONICVIBES) += $(OPL3_OBJS) -obj-$(CONFIG_SND_YMFPCI) += $(OPL3_OBJS) - -obj-m := $(sort $(obj-m)) +obj-$(CONFIG_SND_OPL3_LIB) += snd-opl3-lib.o +obj-$(call sequencer,$(CONFIG_SND_OPL3_LIB)) += snd-opl3-synth.o diff -Nru a/sound/drivers/opl4/Makefile b/sound/drivers/opl4/Makefile --- a/sound/drivers/opl4/Makefile Sun Mar 14 14:20:08 2004 +++ b/sound/drivers/opl4/Makefile Sun Mar 14 14:20:08 2004 @@ -6,10 +6,13 @@ snd-opl4-lib-objs := opl4_lib.o opl4_mixer.o opl4_proc.o snd-opl4-synth-objs := opl4_seq.o opl4_synth.o yrw801.o -OPL4_OBJS := snd-opl4-lib.o -ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y) - OPL4_OBJS += snd-opl4-synth.o -endif +# +# this function returns: +# "m" - CONFIG_SND_SEQUENCER is m +# - CONFIG_SND_SEQUENCER is undefined +# otherwise parameter #1 value +# +sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) -obj-$(CONFIG_SND_OPTI92X_AD1848) += $(OPL4_OBJS) -obj-$(CONFIG_SND_OPTI92X_CS4231) += $(OPL4_OBJS) +obj-$(CONFIG_SND_OPL4_LIB) += snd-opl4-lib.o +obj-$(call sequencer,$(CONFIG_SND_OPL4_LIB)) += snd-opl4-synth.o \ No newline at end of file diff -Nru a/sound/drivers/vx/Makefile b/sound/drivers/vx/Makefile --- a/sound/drivers/vx/Makefile Sun Mar 14 14:20:06 2004 +++ b/sound/drivers/vx/Makefile Sun Mar 14 14:20:06 2004 @@ -5,7 +5,4 @@ snd-vx-lib-objs := vx_core.o vx_hwdep.o vx_pcm.o vx_mixer.o vx_cmd.o vx_uer.o -obj-$(CONFIG_SND_VXPOCKET) += snd-vx-lib.o -obj-$(CONFIG_SND_VXP440) += snd-vx-lib.o -obj-$(CONFIG_SND_VX222) += snd-vx-lib.o - +obj-$(CONFIG_SND_VX_LIB) += snd-vx-lib.o diff -Nru a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c --- a/sound/drivers/vx/vx_core.c Sun Mar 14 14:20:08 2004 +++ b/sound/drivers/vx/vx_core.c Sun Mar 14 14:20:08 2004 @@ -355,11 +355,12 @@ */ int vx_send_msg(vx_core_t *chip, struct vx_rmh *rmh) { + unsigned long flags; int err; - spin_lock_bh(&chip->lock); + spin_lock_irqsave(&chip->lock, flags); err = vx_send_msg_nolock(chip, rmh); - spin_unlock_bh(&chip->lock); + spin_unlock_irqrestore(&chip->lock, flags); return err; } @@ -414,11 +415,12 @@ */ int vx_send_rih(vx_core_t *chip, int cmd) { + unsigned long flags; int err; - spin_lock_bh(&chip->lock); + spin_lock_irqsave(&chip->lock, flags); err = vx_send_rih_nolock(chip, cmd); - spin_unlock_bh(&chip->lock); + spin_unlock_irqrestore(&chip->lock, flags); return err; } diff -Nru a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c --- a/sound/drivers/vx/vx_mixer.c Sun Mar 14 14:20:06 2004 +++ b/sound/drivers/vx/vx_mixer.c Sun Mar 14 14:20:06 2004 @@ -919,7 +919,7 @@ if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_iec958, chip))) < 0) return err; /* VU, peak, saturation meters */ - for (c = 0; c < 1; c++) { + for (c = 0; c < 2; c++) { static char *dir[2] = { "Output", "Input" }; for (i = 0; i < chip->hw->num_ins; i++) { int val = (i * 2) | (c << 8); diff -Nru a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c --- a/sound/drivers/vx/vx_pcm.c Sun Mar 14 14:20:06 2004 +++ b/sound/drivers/vx/vx_pcm.c Sun Mar 14 14:20:06 2004 @@ -561,7 +561,7 @@ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rate_min = 5000, .rate_max = 48000, - .channels_min = 2, + .channels_min = 1, .channels_max = 2, .buffer_bytes_max = (128*1024), .period_bytes_min = 126, @@ -958,7 +958,7 @@ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, .rate_min = 5000, .rate_max = 48000, - .channels_min = 2, + .channels_min = 1, .channels_max = 2, .buffer_bytes_max = (128*1024), .period_bytes_min = 126, diff -Nru a/sound/i2c/other/Makefile b/sound/i2c/other/Makefile --- a/sound/i2c/other/Makefile Sun Mar 14 14:20:06 2004 +++ b/sound/i2c/other/Makefile Sun Mar 14 14:20:06 2004 @@ -3,10 +3,12 @@ # Copyright (c) 2003 by Jaroslav Kysela # +snd-ak4117-objs := ak4117.o snd-ak4xxx-adda-objs := ak4xxx-adda.o snd-tea575x-tuner-objs := tea575x-tuner.o # Module Dependency +obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o obj-$(CONFIG_SND_ICE1724) += snd-ak4xxx-adda.o obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o diff -Nru a/sound/i2c/other/ak4117.c b/sound/i2c/other/ak4117.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/i2c/other/ak4117.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,561 @@ +/* + * Routines for control of the AK4117 via 4-wire serial interface + * IEC958 (S/PDIF) receiver by Asahi Kasei + * Copyright (c) by Jaroslav Kysela + * + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Jaroslav Kysela "); +MODULE_DESCRIPTION("AK4117 IEC958 (S/PDIF) receiver by Asahi Kasei"); +MODULE_LICENSE("GPL"); + +#define chip_t ak4117_t + +#define AK4117_ADDR 0x00 /* fixed address */ + +static void snd_ak4117_timer(unsigned long data); + +static void reg_write(ak4117_t *ak4117, unsigned char reg, unsigned char val) +{ + ak4117->write(ak4117->private_data, reg, val); + if (reg < sizeof(ak4117->regmap)) + ak4117->regmap[reg] = val; +} + +static inline unsigned char reg_read(ak4117_t *ak4117, unsigned char reg) +{ + return ak4117->read(ak4117->private_data, reg); +} + +#if 0 +static void reg_dump(ak4117_t *ak4117) +{ + int i; + + printk("AK4117 REG DUMP:\n"); + for (i = 0; i < 0x1b; i++) + printk("reg[%02x] = %02x (%02x)\n", i, reg_read(ak4117, i), i < sizeof(ak4117->regmap) ? ak4117->regmap[i] : 0); +} +#endif + +static void snd_ak4117_free(ak4117_t *chip) +{ + del_timer(&chip->timer); + snd_magic_kfree(chip); +} + +static int snd_ak4117_dev_free(snd_device_t *device) +{ + ak4117_t *chip = snd_magic_cast(ak4117_t, device->device_data, return -ENXIO); + snd_ak4117_free(chip); + return 0; +} + +int snd_ak4117_create(snd_card_t *card, ak4117_read_t *read, ak4117_write_t *write, + unsigned char pgm[5], void *private_data, ak4117_t **r_ak4117) +{ + ak4117_t *chip; + int err = 0; + unsigned char reg; + static snd_device_ops_t ops = { + .dev_free = snd_ak4117_dev_free, + }; + + chip = (ak4117_t *)snd_magic_kcalloc(ak4117_t, 0, GFP_KERNEL); + if (chip == NULL) + return -ENOMEM; + spin_lock_init(&chip->lock); + chip->card = card; + chip->read = read; + chip->write = write; + chip->private_data = private_data; + init_timer(&chip->timer); + chip->timer.data = (unsigned long)chip; + chip->timer.function = snd_ak4117_timer; + + for (reg = 0; reg < 5; reg++) + chip->regmap[reg] = pgm[reg]; + snd_ak4117_reinit(chip); + + chip->rcs0 = reg_read(chip, AK4117_REG_RCS0) & ~(AK4117_QINT | AK4117_CINT | AK4117_STC); + chip->rcs1 = reg_read(chip, AK4117_REG_RCS1); + chip->rcs2 = reg_read(chip, AK4117_REG_RCS2); + + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) + goto __fail; + + if (r_ak4117) + *r_ak4117 = chip; + return 0; + + __fail: + snd_ak4117_free(chip); + return err < 0 ? err : -EIO; +} + +void snd_ak4117_reg_write(ak4117_t *chip, unsigned char reg, unsigned char mask, unsigned char val) +{ + if (reg >= 5) + return; + reg_write(chip, reg, (chip->regmap[reg] & ~mask) | val); +} + +void snd_ak4117_reinit(ak4117_t *chip) +{ + unsigned char old = chip->regmap[AK4117_REG_PWRDN], reg; + + del_timer(&chip->timer); + chip->init = 1; + /* bring the chip to reset state and powerdown state */ + reg_write(chip, AK4117_REG_PWRDN, 0); + udelay(200); + /* release reset, but leave powerdown */ + reg_write(chip, AK4117_REG_PWRDN, (old | AK4117_RST) & ~AK4117_PWN); + udelay(200); + for (reg = 1; reg < 5; reg++) + reg_write(chip, reg, chip->regmap[reg]); + /* release powerdown, everything is initialized now */ + reg_write(chip, AK4117_REG_PWRDN, old | AK4117_RST | AK4117_PWN); + chip->init = 0; + chip->timer.expires = 1 + jiffies; + add_timer(&chip->timer); +} + +static unsigned int external_rate(unsigned char rcs1) +{ + switch (rcs1 & (AK4117_FS0|AK4117_FS1|AK4117_FS2|AK4117_FS3)) { + case AK4117_FS_32000HZ: return 32000; + case AK4117_FS_44100HZ: return 44100; + case AK4117_FS_48000HZ: return 48000; + case AK4117_FS_88200HZ: return 88200; + case AK4117_FS_96000HZ: return 96000; + case AK4117_FS_176400HZ: return 176400; + case AK4117_FS_192000HZ: return 192000; + default: return 0; + } +} + +static int snd_ak4117_in_error_info(snd_kcontrol_t *kcontrol, + snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = LONG_MAX; + return 0; +} + +static int snd_ak4117_in_error_get(snd_kcontrol_t *kcontrol, + snd_ctl_elem_value_t *ucontrol) +{ + ak4117_t *chip = snd_kcontrol_chip(kcontrol); + long *ptr; + + spin_lock_irq(&chip->lock); + ptr = (long *)(((char *)chip) + kcontrol->private_value); + ucontrol->value.integer.value[0] = *ptr; + *ptr = 0; + spin_unlock_irq(&chip->lock); + return 0; +} + +static int snd_ak4117_in_bit_info(snd_kcontrol_t *kcontrol, + snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_ak4117_in_bit_get(snd_kcontrol_t *kcontrol, + snd_ctl_elem_value_t *ucontrol) +{ + ak4117_t *chip = snd_kcontrol_chip(kcontrol); + unsigned char reg = kcontrol->private_value & 0xff; + unsigned char bit = (kcontrol->private_value >> 8) & 0xff; + unsigned char inv = (kcontrol->private_value >> 31) & 1; + + ucontrol->value.integer.value[0] = ((reg_read(chip, reg) & (1 << bit)) ? 1 : 0) ^ inv; + return 0; +} + +static int snd_ak4117_rx_info(snd_kcontrol_t *kcontrol, + snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int snd_ak4117_rx_get(snd_kcontrol_t *kcontrol, + snd_ctl_elem_value_t *ucontrol) +{ + ak4117_t *chip = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = (chip->regmap[AK4117_REG_IO] & AK4117_IPS) ? 1 : 0; + return 0; +} + +static int snd_ak4117_rx_put(snd_kcontrol_t *kcontrol, + snd_ctl_elem_value_t *ucontrol) +{ + ak4117_t *chip = snd_kcontrol_chip(kcontrol); + int change; + u8 old_val; + + spin_lock_irq(&chip->lock); + old_val = chip->regmap[AK4117_REG_IO]; + change = !!ucontrol->value.integer.value[0] != ((old_val & AK4117_IPS) ? 1 : 0); + if (change) + reg_write(chip, AK4117_REG_IO, (old_val & ~AK4117_IPS) | (ucontrol->value.integer.value[0] ? AK4117_IPS : 0)); + spin_unlock_irq(&chip->lock); + return change; +} + +static int snd_ak4117_rate_info(snd_kcontrol_t *kcontrol, + snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 192000; + return 0; +} + +static int snd_ak4117_rate_get(snd_kcontrol_t *kcontrol, + snd_ctl_elem_value_t *ucontrol) +{ + ak4117_t *chip = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = external_rate(reg_read(chip, AK4117_REG_RCS1)); + return 0; +} + +static int snd_ak4117_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; + uinfo->count = 1; + return 0; +} + +static int snd_ak4117_spdif_get(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + ak4117_t *chip = snd_kcontrol_chip(kcontrol); + unsigned i; + + for (i = 0; i < AK4117_REG_RXCSB_SIZE; i++) + ucontrol->value.iec958.status[i] = reg_read(chip, AK4117_REG_RXCSB0 + i); + return 0; +} + +static int snd_ak4117_spdif_mask_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; + uinfo->count = 1; + return 0; +} + +static int snd_ak4117_spdif_mask_get(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + memset(ucontrol->value.iec958.status, 0xff, AK4117_REG_RXCSB_SIZE); + return 0; +} + +static int snd_ak4117_spdif_pinfo(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 0xffff; + uinfo->count = 4; + return 0; +} + +static int snd_ak4117_spdif_pget(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + ak4117_t *chip = snd_kcontrol_chip(kcontrol); + unsigned short tmp; + + ucontrol->value.integer.value[0] = 0xf8f2; + ucontrol->value.integer.value[1] = 0x4e1f; + tmp = reg_read(chip, AK4117_REG_Pc0) | (reg_read(chip, AK4117_REG_Pc1) << 8); + ucontrol->value.integer.value[2] = tmp; + tmp = reg_read(chip, AK4117_REG_Pd0) | (reg_read(chip, AK4117_REG_Pd1) << 8); + ucontrol->value.integer.value[3] = tmp; + return 0; +} + +static int snd_ak4117_spdif_qinfo(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = AK4117_REG_QSUB_SIZE; + return 0; +} + +static int snd_ak4117_spdif_qget(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + ak4117_t *chip = snd_kcontrol_chip(kcontrol); + unsigned i; + + for (i = 0; i < AK4117_REG_QSUB_SIZE; i++) + ucontrol->value.bytes.data[i] = reg_read(chip, AK4117_REG_QSUB_ADDR + i); + return 0; +} + +/* Don't forget to change AK4117_CONTROLS define!!! */ +static snd_kcontrol_new_t snd_ak4117_iec958_controls[] = { +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 Parity Errors", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4117_in_error_info, + .get = snd_ak4117_in_error_get, + .private_value = offsetof(ak4117_t, parity_errors), +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 V-Bit Errors", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4117_in_error_info, + .get = snd_ak4117_in_error_get, + .private_value = offsetof(ak4117_t, v_bit_errors), +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 C-CRC Errors", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4117_in_error_info, + .get = snd_ak4117_in_error_get, + .private_value = offsetof(ak4117_t, ccrc_errors), +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 Q-CRC Errors", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4117_in_error_info, + .get = snd_ak4117_in_error_get, + .private_value = offsetof(ak4117_t, qcrc_errors), +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 External Rate", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4117_rate_info, + .get = snd_ak4117_rate_get, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,MASK), + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .info = snd_ak4117_spdif_mask_info, + .get = snd_ak4117_spdif_mask_get, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT), + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4117_spdif_info, + .get = snd_ak4117_spdif_get, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 Preample Capture Default", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4117_spdif_pinfo, + .get = snd_ak4117_spdif_pget, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 Q-subcode Capture Default", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4117_spdif_qinfo, + .get = snd_ak4117_spdif_qget, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 Audio", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4117_in_bit_info, + .get = snd_ak4117_in_bit_get, + .private_value = (1<<31) | (3<<8) | AK4117_REG_RCS0, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 Non-PCM Bitstream", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4117_in_bit_info, + .get = snd_ak4117_in_bit_get, + .private_value = (5<<8) | AK4117_REG_RCS1, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 DTS Bitstream", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4117_in_bit_info, + .get = snd_ak4117_in_bit_get, + .private_value = (6<<8) | AK4117_REG_RCS1, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "AK4117 Input Select", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE, + .info = snd_ak4117_rx_info, + .get = snd_ak4117_rx_get, + .put = snd_ak4117_rx_put, +} +}; + +int snd_ak4117_build(ak4117_t *ak4117, snd_pcm_substream_t *cap_substream) +{ + snd_kcontrol_t *kctl; + unsigned int idx; + int err; + + snd_assert(cap_substream, return -EINVAL); + ak4117->substream = cap_substream; + for (idx = 0; idx < AK4117_CONTROLS; idx++) { + kctl = snd_ctl_new1(&snd_ak4117_iec958_controls[idx], ak4117); + if (kctl == NULL) + return -ENOMEM; + kctl->id.device = cap_substream->pcm->device; + kctl->id.subdevice = cap_substream->number; + err = snd_ctl_add(ak4117->card, kctl); + if (err < 0) + return err; + ak4117->kctls[idx] = kctl; + } + return 0; +} + +int snd_ak4117_external_rate(ak4117_t *ak4117) +{ + unsigned char rcs1; + + rcs1 = reg_read(ak4117, AK4117_REG_RCS1); + return external_rate(rcs1); +} + +int snd_ak4117_check_rate_and_errors(ak4117_t *ak4117, unsigned int flags) +{ + snd_pcm_runtime_t *runtime = ak4117->substream ? ak4117->substream->runtime : NULL; + unsigned long _flags; + int res = 0; + unsigned char rcs0, rcs1, rcs2; + unsigned char c0, c1; + + rcs1 = reg_read(ak4117, AK4117_REG_RCS1); + if (flags & AK4117_CHECK_NO_STAT) + goto __rate; + rcs0 = reg_read(ak4117, AK4117_REG_RCS0); + rcs2 = reg_read(ak4117, AK4117_REG_RCS2); + // printk("AK IRQ: rcs0 = 0x%x, rcs1 = 0x%x, rcs2 = 0x%x\n", rcs0, rcs1, rcs2); + spin_lock_irqsave(&ak4117->lock, _flags); + if (rcs0 & AK4117_PAR) + ak4117->parity_errors++; + if (rcs0 & AK4117_V) + ak4117->v_bit_errors++; + if (rcs2 & AK4117_CCRC) + ak4117->ccrc_errors++; + if (rcs2 & AK4117_QCRC) + ak4117->qcrc_errors++; + c0 = (ak4117->rcs0 & (AK4117_QINT | AK4117_CINT | AK4117_STC | AK4117_AUDION | AK4117_AUTO | AK4117_UNLCK)) ^ + (rcs0 & (AK4117_QINT | AK4117_CINT | AK4117_STC | AK4117_AUDION | AK4117_AUTO | AK4117_UNLCK)); + c1 = (ak4117->rcs1 & (AK4117_DTSCD | AK4117_NPCM | AK4117_PEM | 0x0f)) ^ + (rcs1 & (AK4117_DTSCD | AK4117_NPCM | AK4117_PEM | 0x0f)); + ak4117->rcs0 = rcs0 & ~(AK4117_QINT | AK4117_CINT | AK4117_STC); + ak4117->rcs1 = rcs1; + ak4117->rcs2 = rcs2; + spin_unlock_irqrestore(&ak4117->lock, _flags); + + if (rcs0 & AK4117_PAR) + snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[0]->id); + if (rcs0 & AK4117_V) + snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[1]->id); + if (rcs2 & AK4117_CCRC) + snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[2]->id); + if (rcs2 & AK4117_QCRC) + snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[3]->id); + + /* rate change */ + if (c1 & 0x0f) + snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[4]->id); + + if ((c1 & AK4117_PEM) | (c0 & AK4117_CINT)) + snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[6]->id); + if (c0 & AK4117_QINT) + snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[8]->id); + + if (c0 & AK4117_AUDION) + snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[9]->id); + if (c1 & AK4117_NPCM) + snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[10]->id); + if (c1 & AK4117_DTSCD) + snd_ctl_notify(ak4117->card, SNDRV_CTL_EVENT_MASK_VALUE, &ak4117->kctls[11]->id); + + if (ak4117->change_callback && (c0 | c1) != 0) + ak4117->change_callback(ak4117, c0, c1); + + __rate: + /* compare rate */ + res = external_rate(rcs1); + if (!(flags & AK4117_CHECK_NO_RATE) && runtime && runtime->rate != res) { + snd_pcm_stream_lock_irqsave(ak4117->substream, _flags); + if (snd_pcm_running(ak4117->substream)) { + // printk("rate changed (%i <- %i)\n", runtime->rate, res); + snd_pcm_stop(ak4117->substream, SNDRV_PCM_STATE_DRAINING); + wake_up(&runtime->sleep); + res = 1; + } + snd_pcm_stream_unlock_irqrestore(ak4117->substream, _flags); + } + return res; +} + +static void snd_ak4117_timer(unsigned long data) +{ + ak4117_t *chip = snd_magic_cast(ak4117_t, (void *)data, return); + + if (chip->init) + return; + snd_ak4117_check_rate_and_errors(chip, 0); + chip->timer.expires = 1 + jiffies; + add_timer(&chip->timer); +} + +EXPORT_SYMBOL(snd_ak4117_create); +EXPORT_SYMBOL(snd_ak4117_reg_write); +EXPORT_SYMBOL(snd_ak4117_reinit); +EXPORT_SYMBOL(snd_ak4117_build); +EXPORT_SYMBOL(snd_ak4117_external_rate); +EXPORT_SYMBOL(snd_ak4117_check_rate_and_errors); diff -Nru a/sound/isa/Kconfig b/sound/isa/Kconfig --- a/sound/isa/Kconfig Sun Mar 14 14:20:08 2004 +++ b/sound/isa/Kconfig Sun Mar 14 14:20:08 2004 @@ -6,6 +6,9 @@ config SND_AD1816A tristate "Analog Devices SoundPort AD1816A" depends on SND && ISAPNP + select SND_OPL3_LIB + select SND_MPU401_UART + select SND_PCM help Say 'Y' or 'M' to include support for Analog Devices SoundPort AD1816A or compatible sound chips. @@ -13,6 +16,7 @@ config SND_AD1848 tristate "Generic AD1848/CS4248 driver" depends on SND + select SND_PCM help Say 'Y' or 'M' to include support for AD1848 (Analog Devices) or CS4248 (Cirrus Logic - Crystal Semiconductors) chips. Please, for newer chips @@ -21,6 +25,8 @@ config SND_CS4231 tristate "Generic Cirrus Logic CS4231 driver" depends on SND + select SND_MPU401_UART + select SND_PCM help Say 'Y' or 'M' to include support for CS4231 chips from Cirrus Logic - Crystal Semiconductors. @@ -28,6 +34,9 @@ config SND_CS4232 tristate "Generic Cirrus Logic CS4232 driver" depends on SND + select SND_OPL3_LIB + select SND_MPU401_UART + select SND_PCM help Say 'Y' or 'M' to include support for CS4232 chips from Cirrus Logic - Crystal Semiconductors. @@ -35,6 +44,9 @@ config SND_CS4236 tristate "Generic Cirrus Logic CS4236+ driver" depends on SND + select SND_OPL3_LIB + select SND_MPU401_UART + select SND_PCM help Say 'Y' or 'M' to include support for CS4235,CS4236,CS4237B,CS4238B,CS4239 chips from Cirrus Logic - Crystal Semiconductors. @@ -42,6 +54,9 @@ config SND_PC98_CS4232 tristate "NEC PC9800 CS4232 driver" depends on SND && X86_PC9800 + select SND_OPL3_LIB + select SND_MPU401_UART + select SND_PCM help Say 'Y' or 'M' to include support for NEC PC-9801/PC-9821 on-board soundchip based on CS4232. @@ -49,42 +64,59 @@ config SND_ES968 tristate "Generic ESS ES968 driver" depends on SND && ISAPNP + select SND_MPU401_UART + select SND_PCM help Say 'Y' or 'M' to include support for ESS AudioDrive ES968 chip. config SND_ES1688 tristate "Generic ESS ES688/ES1688 driver" depends on SND + select SND_OPL3_LIB + select SND_MPU401_UART + select SND_PCM help Say 'Y' or 'M' to include support for ESS AudioDrive ES688 or ES1688 chips. config SND_ES18XX tristate "Generic ESS ES18xx driver" depends on SND + select SND_OPL3_LIB + select SND_MPU401_UART + select SND_PCM help Say 'Y' or 'M' to include support for ESS AudioDrive ES18xx chips. config SND_GUSCLASSIC tristate "Gravis UltraSound Classic" depends on SND + select SND_RAWMIDI + select SND_PCM help Say 'Y' or 'M' to include support for Gravis UltraSound Classic soundcard. config SND_GUSEXTREME tristate "Gravis UltraSound Extreme" depends on SND + select SND_HWDEP + select SND_MPU401_UART + select SND_PCM help Say 'Y' or 'M' to include support for Gravis UltraSound Extreme soundcard. config SND_GUSMAX tristate "Gravis UltraSound MAX" depends on SND + select SND_RAWMIDI + select SND_PCM help Say 'Y' or 'M' to include support for Gravis UltraSound MAX soundcard. config SND_INTERWAVE tristate "AMD InterWave, Gravis UltraSound PnP" depends on SND + select SND_RAWMIDI + select SND_PCM help Say 'Y' or 'M' to include support for AMD InterWave based soundcards (Gravis UltraSound Plug & Play, STB SoundRage32, MED3210, Dynasonic Pro, @@ -93,6 +125,8 @@ config SND_INTERWAVE_STB tristate "AMD InterWave + TEA6330T (UltraSound 32-Pro)" depends on SND + select SND_RAWMIDI + select SND_PCM help Say 'Y' or 'M' to include support for AMD InterWave based soundcards with TEA6330T bass and treble regulator (UltraSound 32-Pro). @@ -100,6 +134,10 @@ config SND_OPTI92X_AD1848 tristate "OPTi 82C92x - AD1848" depends on SND + select SND_OPL3_LIB + select SND_OPL4_LIB + select SND_MPU401_UART + select SND_PCM help Say 'Y' or 'M' to include support for Opti92x soundcards equiped with AD1848 codec. @@ -107,6 +145,10 @@ config SND_OPTI92X_CS4231 tristate "OPTi 82C92x - CS4231" depends on SND + select SND_OPL3_LIB + select SND_OPL4_LIB + select SND_MPU401_UART + select SND_PCM help Say 'Y' or 'M' to include support for Opti92x soundcards equiped with CS4231 codec. @@ -114,12 +156,18 @@ config SND_OPTI93X tristate "OPTi 82C93x" depends on SND + select SND_OPL3_LIB + select SND_MPU401_UART + select SND_PCM help Say 'Y' or 'M' to include support for Opti93x soundcards. config SND_SB8 tristate "Sound Blaster 1.0/2.0/Pro (8-bit)" depends on SND + select SND_OPL3_LIB + select SND_RAWMIDI + select SND_PCM help Say 'Y' or 'M' to include support for Sound Blaster 1.0/2.0/Pro (8-bit) soundcards or 100% compatible from Creative. @@ -127,6 +175,9 @@ config SND_SB16 tristate "Sound Blaster 16 (PnP)" depends on SND + select SND_OPL3_LIB + select SND_MPU401_UART + select SND_PCM help Say 'Y' or 'M' to include support for Sound Blaster 16 (including Plug and Play version). @@ -134,6 +185,9 @@ config SND_SBAWE tristate "Sound Blaster AWE (32,64) (PnP)" depends on SND + select SND_OPL3_LIB + select SND_MPU401_UART + select SND_PCM help Say 'Y' or 'M' to include support for Sound Blaster AWE (including Plug and Play version). @@ -149,6 +203,9 @@ config SND_WAVEFRONT tristate "Turtle Beach Maui,Tropez,Tropez+ (Wavefront)" depends on SND + select SND_OPL3_LIB + select SND_MPU401_UART + select SND_PCM help Say 'Y' or 'M' to include support for Turtle Beach Maui, Tropez and Tropez+ soundcards based on Wavefront chip. @@ -156,6 +213,9 @@ config SND_ALS100 tristate "Avance Logic ALS100/ALS120" depends on SND && ISAPNP + select SND_OPL3_LIB + select SND_MPU401_UART + select SND_PCM help Say 'Y' or 'M' to include support for Avance Logic ALS100, ALS110, ALS120 and ALS200 soundcards. @@ -163,18 +223,25 @@ config SND_AZT2320 tristate "Aztech Systems AZT2320" depends on SND && ISAPNP + select SND_OPL3_LIB + select SND_MPU401_UART + select SND_PCM help Say 'Y' or 'M' to include support for Aztech Systems AZT2320 soundcard. config SND_CMI8330 tristate "C-Media CMI8330" depends on SND + select SND_PCM help Say 'Y' or 'M' to include support for C-Media CMI8330 based soundcards. config SND_DT019X tristate "Diamond Technologies DT-019X, Avance Logic ALS-007" depends on SND && ISAPNP + select SND_OPL3_LIB + select SND_MPU401_UART + select SND_PCM help Say 'Y' or 'M' to include support for Diamond Technologies DT-019X and Avance Logic ALS-007 soundcards. @@ -182,18 +249,25 @@ config SND_OPL3SA2 tristate "Yamaha OPL3-SA2/SA3" depends on SND + select SND_OPL3_LIB + select SND_MPU401_UART + select SND_PCM help Say 'Y' or 'M' to include support for Yamaha OPL3SA2 or OPL3SA3 chips. config SND_SGALAXY tristate "Aztech Sound Galaxy" depends on SND + select SND_PCM help Say 'Y' or 'M' to include support for Aztech Sound Galaxy. config SND_SSCAPE tristate "Ensoniq SoundScape PnP driver" depends on SND + select SND_HWDEP + select SND_MPU401_UART + select SND_PCM help Say 'Y' or 'M' to include support for Ensoniq SoundScape PnP soundcard. diff -Nru a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c --- a/sound/isa/ad1816a/ad1816a_lib.c Sun Mar 14 14:20:07 2004 +++ b/sound/isa/ad1816a/ad1816a_lib.c Sun Mar 14 14:20:07 2004 @@ -684,7 +684,9 @@ strcpy(pcm->name, snd_ad1816a_chip_id(chip)); snd_ad1816a_init(chip); - snd_pcm_lib_preallocate_isa_pages_for_all(pcm, 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_isa_data(), + 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024); chip->pcm = pcm; if (rpcm) diff -Nru a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c --- a/sound/isa/ad1848/ad1848_lib.c Sun Mar 14 14:20:08 2004 +++ b/sound/isa/ad1848/ad1848_lib.c Sun Mar 14 14:20:08 2004 @@ -1043,7 +1043,9 @@ pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX; strcpy(pcm->name, snd_ad1848_chip_id(chip)); - snd_pcm_lib_preallocate_isa_pages_for_all(pcm, 64*1024, chip->dma > 3 ? 128*1024 : 64*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_isa_data(), + 64*1024, chip->dma > 3 ? 128*1024 : 64*1024); chip->pcm = pcm; if (rpcm) diff -Nru a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c --- a/sound/isa/cmi8330.c Sun Mar 14 14:20:06 2004 +++ b/sound/isa/cmi8330.c Sun Mar 14 14:20:06 2004 @@ -438,7 +438,9 @@ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &chip->streams[SNDRV_PCM_STREAM_PLAYBACK].ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &chip->streams[SNDRV_PCM_STREAM_CAPTURE].ops); - snd_pcm_lib_preallocate_isa_pages_for_all(pcm, 64*1024, 128*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_isa_data(), + 64*1024, 128*1024); chip->pcm = pcm; return 0; diff -Nru a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c --- a/sound/isa/cs423x/cs4231_lib.c Sun Mar 14 14:20:06 2004 +++ b/sound/isa/cs423x/cs4231_lib.c Sun Mar 14 14:20:06 2004 @@ -1653,17 +1653,21 @@ strcpy(pcm->name, snd_cs4231_chip_id(chip)); #ifdef LEGACY_SUPPORT - snd_pcm_lib_preallocate_isa_pages_for_all(pcm, 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_isa_data(), + 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024); #else # ifdef EBUS_SUPPORT if (chip->ebus_flag) { - snd_pcm_lib_preallocate_pci_pages_for_all(chip->dev_u.pdev, pcm, - 64*1024, 128*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_PCI, + chip->dev_u.pdev, + 64*1024, 128*1024); } else { # endif # ifdef SBUS_SUPPORT - snd_pcm_lib_preallocate_sbus_pages_for_all(chip->dev_u.sdev, pcm, - 64*1024, 128*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_SBUS, + chip->dev_u.sdev, + 64*1024, 128*1024); # endif # ifdef EBUS_SUPPORT } diff -Nru a/sound/isa/dt019x.c b/sound/isa/dt019x.c --- a/sound/isa/dt019x.c Sun Mar 14 14:20:07 2004 +++ b/sound/isa/dt019x.c Sun Mar 14 14:20:07 2004 @@ -143,7 +143,7 @@ port[dev] = pnp_port_start(pdev, 0); dma8[dev] = pnp_dma(pdev, 0); irq[dev] = pnp_irq(pdev, 0); - snd_printdd("dt019x: found audio interface: port=0x%lx, irq=0x%lx, dma=0x%lx\n", + snd_printdd("dt019x: found audio interface: port=0x%lx, irq=0x%x, dma=0x%x\n", port[dev],irq[dev],dma8[dev]); pdev = acard->devmpu; @@ -164,7 +164,7 @@ } mpu_port[dev] = pnp_port_start(pdev, 0); mpu_irq[dev] = pnp_irq(pdev, 0); - snd_printdd("dt019x: found MPU-401: port=0x%lx, irq=0x%lx\n", + snd_printdd("dt019x: found MPU-401: port=0x%lx, irq=0x%x\n", mpu_port[dev],mpu_irq[dev]); } else { __mpu_error: diff -Nru a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c --- a/sound/isa/es1688/es1688_lib.c Sun Mar 14 14:20:07 2004 +++ b/sound/isa/es1688/es1688_lib.c Sun Mar 14 14:20:07 2004 @@ -752,7 +752,9 @@ sprintf(pcm->name, snd_es1688_chip_id(chip)); chip->pcm = pcm; - snd_pcm_lib_preallocate_isa_pages_for_all(pcm, 64*1024, 64*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_isa_data(), + 64*1024, 64*1024); if (rpcm) *rpcm = pcm; diff -Nru a/sound/isa/es18xx.c b/sound/isa/es18xx.c --- a/sound/isa/es18xx.c Sun Mar 14 14:20:07 2004 +++ b/sound/isa/es18xx.c Sun Mar 14 14:20:07 2004 @@ -1598,7 +1598,10 @@ sprintf(pcm->name, "ESS AudioDrive ES%x", chip->version); chip->pcm = pcm; - snd_pcm_lib_preallocate_isa_pages_for_all(pcm, 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_isa_data(), + 64*1024, + chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024); if (rpcm) *rpcm = pcm; diff -Nru a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c --- a/sound/isa/gus/gus_pcm.c Sun Mar 14 14:20:07 2004 +++ b/sound/isa/gus/gus_pcm.c Sun Mar 14 14:20:07 2004 @@ -874,7 +874,9 @@ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_gf1_pcm_playback_ops); for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) - snd_pcm_lib_preallocate_isa_pages(substream, 64*1024, gus->gf1.dma1 > 3 ? 128*1024 : 64*1024); + snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, + snd_dma_isa_data(), + 64*1024, gus->gf1.dma1 > 3 ? 128*1024 : 64*1024); pcm->info_flags = 0; pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; @@ -882,7 +884,9 @@ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_gf1_pcm_capture_ops); if (gus->gf1.dma2 == gus->gf1.dma1) pcm->info_flags |= SNDRV_PCM_INFO_HALF_DUPLEX; - snd_pcm_lib_preallocate_isa_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, 64*1024, gus->gf1.dma2 > 3 ? 128*1024 : 64*1024); + snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, + SNDRV_DMA_TYPE_DEV, snd_dma_isa_data(), + 64*1024, gus->gf1.dma2 > 3 ? 128*1024 : 64*1024); } strcpy(pcm->name, pcm->id); if (gus->interwave) { diff -Nru a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c --- a/sound/isa/opti9xx/opti92x-ad1848.c Sun Mar 14 14:20:06 2004 +++ b/sound/isa/opti9xx/opti92x-ad1848.c Sun Mar 14 14:20:06 2004 @@ -311,8 +311,12 @@ static long snd_legacy_find_free_ioport(long *port_table, long size) { while (*port_table != -1) { - if (!check_region(*port_table, size)) + struct resource *res; + if ((res = request_region(*port_table, size, "ALSA test")) != NULL) { + release_resource(res); + kfree_nocheck(res); return *port_table; + } port_table++; } return -1; @@ -1399,7 +1403,9 @@ strcpy(pcm->name, snd_opti93x_chip_id(codec)); - snd_pcm_lib_preallocate_isa_pages_for_all(pcm, 64*1024, codec->dma1 > 3 || codec->dma2 > 3 ? 128*1024 : 64*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_isa_data(), + 64*1024, codec->dma1 > 3 || codec->dma2 > 3 ? 128*1024 : 64*1024); codec->pcm = pcm; if (rpcm) @@ -1672,13 +1678,18 @@ if ((err = snd_opti9xx_init(chip, i)) < 0) return err; - if (check_region(chip->mc_base, chip->mc_base_size)) + if ((chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, "OPTi9xx MC")) == NULL) continue; value = snd_opti9xx_read(chip, OPTi9XX_MC_REG(1)); if ((value != 0xff) && (value != inb(chip->mc_base + 1))) if (value == snd_opti9xx_read(chip, OPTi9XX_MC_REG(1))) return 1; + + release_resource(chip->res_mc_base); + kfree_nocheck(chip->res_mc_base); + chip->res_mc_base = NULL; + } #else /* OPTi93X */ for (i = OPTi9XX_HW_82C931; i >= OPTi9XX_HW_82C930; i--) { @@ -1688,7 +1699,7 @@ if ((err = snd_opti9xx_init(chip, i)) < 0) return err; - if (check_region(chip->mc_base, chip->mc_base_size)) + if ((chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, "OPTi9xx MC")) == NULL) continue; spin_lock_irqsave(&chip->lock, flags); @@ -1701,6 +1712,10 @@ snd_opti9xx_write(chip, OPTi9XX_MC_REG(7), 0xff - value); if (snd_opti9xx_read(chip, OPTi9XX_MC_REG(7)) == 0xff - value) return 1; + + release_resource(chip->res_mc_base); + kfree_nocheck(chip->res_mc_base); + chip->res_mc_base = NULL; } #endif /* OPTi93X */ @@ -1984,7 +1999,8 @@ } #endif /* CONFIG_PNP */ - if ((chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, "OPTi9xx MC")) == NULL) { + if (! chip->res_mc_base && + (chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, "OPTi9xx MC")) == NULL) { snd_card_free(card); return -ENOMEM; } diff -Nru a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c --- a/sound/isa/sb/sb16_main.c Sun Mar 14 14:20:07 2004 +++ b/sound/isa/sb/sb16_main.c Sun Mar 14 14:20:07 2004 @@ -881,7 +881,9 @@ else pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX; - snd_pcm_lib_preallocate_isa_pages_for_all(pcm, 64*1024, 128*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_isa_data(), + 64*1024, 128*1024); if (rpcm) *rpcm = pcm; diff -Nru a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c --- a/sound/isa/sb/sb8_main.c Sun Mar 14 14:20:07 2004 +++ b/sound/isa/sb/sb8_main.c Sun Mar 14 14:20:07 2004 @@ -535,7 +535,9 @@ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb8_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb8_capture_ops); - snd_pcm_lib_preallocate_isa_pages_for_all(pcm, 64*1024, 64*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_isa_data(), + 64*1024, 64*1024); if (rpcm) *rpcm = pcm; diff -Nru a/sound/isa/sscape.c b/sound/isa/sscape.c --- a/sound/isa/sscape.c Sun Mar 14 14:20:06 2004 +++ b/sound/isa/sscape.c Sun Mar 14 14:20:06 2004 @@ -168,23 +168,20 @@ } -struct dmabuf { - size_t size; - unsigned char *data; - dma_addr_t addr; -}; - /* * Allocates some kernel memory that we can use for DMA. * I think this means that the memory has to map to * contiguous pages of physical memory. */ -static struct dmabuf *get_dmabuf(struct dmabuf *buf, unsigned long s) +static struct snd_dma_buffer *get_dmabuf(struct snd_dma_buffer *buf, unsigned long size) { if (buf) { - buf->data = snd_malloc_isa_pages_fallback(s, &buf->addr, &buf->size); - if (!buf->data) { - snd_printk(KERN_ERR "sscape: Failed to allocate %lu bytes for DMA\n", s); + struct snd_dma_device dev; + memset(&dev, 0, sizeof(dev)); + dev.type = SNDRV_DMA_TYPE_DEV; + dev.dev = snd_dma_isa_data(); + if (snd_dma_alloc_pages_fallback(&dev, size, buf) < 0) { + snd_printk(KERN_ERR "sscape: Failed to allocate %lu bytes for DMA\n", size); return NULL; } } @@ -195,10 +192,15 @@ /* * Release the DMA-able kernel memory ... */ -static void free_dmabuf(struct dmabuf *buf) +static void free_dmabuf(struct snd_dma_buffer *buf) { - if (buf && buf->data) - snd_free_isa_pages(buf->size, buf->data, buf->addr); + if (buf && buf->area) { + struct snd_dma_device dev; + memset(&dev, 0, sizeof(dev)); + dev.type = SNDRV_DMA_TYPE_DEV; + dev.dev = snd_dma_isa_data(); + snd_dma_free_pages(&dev, buf); + } } @@ -456,7 +458,7 @@ size_t size) { unsigned long flags; - struct dmabuf dma; + struct snd_dma_buffer dma; int ret; if (!get_dmabuf(&dma, PAGE_ALIGN(size))) @@ -500,8 +502,8 @@ * comes from USERSPACE. We have already verified * the userspace pointer ... */ - len = min(size, dma.size); - __copy_from_user(dma.data, data, len); + len = min(size, dma.bytes); + __copy_from_user(dma.area, data, len); data += len; size -= len; diff -Nru a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c --- a/sound/isa/wavefront/wavefront_synth.c Sun Mar 14 14:20:07 2004 +++ b/sound/isa/wavefront/wavefront_synth.c Sun Mar 14 14:20:07 2004 @@ -1913,11 +1913,11 @@ return (1); } -#define __KERNEL_SYSCALLS__ #include #include #include #include +#include #include static int errno; @@ -1947,7 +1947,7 @@ fs = get_fs(); set_fs (get_ds()); - if ((fd = open (path, 0, 0)) < 0) { + if ((fd = sys_open (path, 0, 0)) < 0) { snd_printk ("Unable to load \"%s\".\n", path); return 1; @@ -1956,7 +1956,7 @@ while (1) { int x; - if ((x = read (fd, §ion_length, sizeof (section_length))) != + if ((x = sys_read (fd, §ion_length, sizeof (section_length))) != sizeof (section_length)) { snd_printk ("firmware read error.\n"); goto failure; @@ -1966,7 +1966,7 @@ break; } - if (read (fd, section, section_length) != section_length) { + if (sys_read (fd, section, section_length) != section_length) { snd_printk ("firmware section " "read error.\n"); goto failure; @@ -2005,12 +2005,12 @@ } - close (fd); + sys_close (fd); set_fs (fs); return 0; failure: - close (fd); + sys_close (fd); set_fs (fs); snd_printk ("firmware download failed!!!\n"); return 1; diff -Nru a/sound/oss/wavfront.c b/sound/oss/wavfront.c --- a/sound/oss/wavfront.c Sun Mar 14 14:20:07 2004 +++ b/sound/oss/wavfront.c Sun Mar 14 14:20:07 2004 @@ -75,6 +75,7 @@ #include #include #include +#include #include #include #include @@ -2489,11 +2490,9 @@ } #include "os.h" -#define __KERNEL_SYSCALLS__ #include #include #include -#include #include static int errno; @@ -2523,7 +2522,7 @@ fs = get_fs(); set_fs (get_ds()); - if ((fd = open (path, 0, 0)) < 0) { + if ((fd = sys_open (path, 0, 0)) < 0) { printk (KERN_WARNING LOGNAME "Unable to load \"%s\".\n", path); return 1; @@ -2532,7 +2531,7 @@ while (1) { int x; - if ((x = read (fd, §ion_length, sizeof (section_length))) != + if ((x = sys_read (fd, §ion_length, sizeof (section_length))) != sizeof (section_length)) { printk (KERN_ERR LOGNAME "firmware read error.\n"); goto failure; @@ -2542,7 +2541,7 @@ break; } - if (read (fd, section, section_length) != section_length) { + if (sys_read (fd, section, section_length) != section_length) { printk (KERN_ERR LOGNAME "firmware section " "read error.\n"); goto failure; @@ -2581,12 +2580,12 @@ } - close (fd); + sys_close (fd); set_fs (fs); return 0; failure: - close (fd); + sys_close (fd); set_fs (fs); printk (KERN_ERR "\nWaveFront: firmware download failed!!!\n"); return 1; diff -Nru a/sound/parisc/Kconfig b/sound/parisc/Kconfig --- a/sound/parisc/Kconfig Sun Mar 14 14:20:07 2004 +++ b/sound/parisc/Kconfig Sun Mar 14 14:20:07 2004 @@ -6,6 +6,7 @@ config SND_HARMONY tristate "Harmony/Vivace sound chip" depends on SND + select SND_PCM help Say 'Y' or 'M' to include support for Harmony/Vivace soundchip on HP712s, 715/new and many other GSC based machines. diff -Nru a/sound/parisc/harmony.c b/sound/parisc/harmony.c --- a/sound/parisc/harmony.c Sun Mar 14 14:20:07 2004 +++ b/sound/parisc/harmony.c Sun Mar 14 14:20:07 2004 @@ -205,6 +205,7 @@ unsigned char *silence_addr; dma_addr_t silence_dma; int silence_count; + struct snd_dma_device dma_dev; /* alsa stuff */ snd_card_t *card; @@ -357,7 +358,7 @@ * The interrupt routine must provide adresse of next physical pages * used by harmony */ -void snd_card_harmony_interrupt(int irq, void *dev, struct pt_regs *regs) +static int snd_card_harmony_interrupt(int irq, void *dev, struct pt_regs *regs) { snd_card_harmony_t *harmony = (snd_card_harmony_t *)dev; u32 dstatus = 0; @@ -413,6 +414,8 @@ } } snd_harmony_enable_interrupts(harmony); + + return IRQ_HANDLED; } /* @@ -844,22 +847,27 @@ harmony->pcm = pcm; /* initialize graveyard buffer */ - harmony->graveyard_addr = snd_malloc_pci_pages(harmony->fake_pci_dev, + harmony->dma_dev.type = SNDRV_DMA_TYPE_PCI; + harmony->dma_dev.dev = snd_dma_pci_data(harmony->fake_pci_dev); + harmony->graveyard_addr = snd_dma_alloc_pages(&chip->dma_dev, HARMONY_BUF_SIZE*GRAVEYARD_BUFS, &harmony->graveyard_dma); harmony->graveyard_count = 0; /* initialize silence buffers */ - harmony->silence_addr = snd_malloc_pci_pages(harmony->fake_pci_dev, + harmony->silence_addr = snd_dma_alloc_pages(&chip->dma_dev, HARMONY_BUF_SIZE*SILENCE_BUFS, &harmony->silence_dma); harmony->silence_count = 0; - harmony->ply_stopped = harmony->cap_stopped = 1; harmony->playback_substream = NULL; harmony->capture_substream = NULL; harmony->graveyard_count = 0; + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(harmony->fake_pci_dev), + 64 * 1024, 128 * 1024); + return 0; } diff -Nru a/sound/pci/Kconfig b/sound/pci/Kconfig --- a/sound/pci/Kconfig Sun Mar 14 14:20:07 2004 +++ b/sound/pci/Kconfig Sun Mar 14 14:20:07 2004 @@ -3,21 +3,62 @@ menu "PCI devices" depends on SND!=n && PCI +config SND_AC97_CODEC + tristate + select SND_PCM + config SND_ALI5451 tristate "ALi PCI Audio M5451" depends on SND + select SND_MPU401_UART + select SND_AC97_CODEC help Say 'Y' or 'M' to include support for ALI PCI Audio M5451 sound core. +config SND_ATIIXP + tristate "ATI IXP 150/200/250" + depends on SND + select SND_AC97_CODEC + help + Say 'Y' or 'M' to include support for ATI IXP 150/200/250 AC97 controller. + +config SND_AU8810 + tristate "Aureal Advantage" + depends on SND + select SND_MPU401_UART + select SND_AC97_CODEC + help + Say 'Y' or 'M' to include support for Aureal Advantage soundcards. + +config SND_AU8820 + tristate "Aureal Vortex" + depends on SND + select SND_MPU401_UART + select SND_AC97_CODEC + help + Say 'Y' or 'M' to include support for Aureal Vortex soundcards. + +config SND_AU8830 + tristate "Aureal Vortex 2" + depends on SND + select SND_MPU401_UART + select SND_AC97_CODEC + help + Say 'Y' or 'M' to include support for Aureal Vortex 2 soundcards. + config SND_AZT3328 tristate "Aztech AZF3328 / PCI168 (EXPERIMENTAL)" depends on SND && EXPERIMENTAL + select SND_OPL3_LIB + select SND_MPU401_UART + select SND_PCM help Say 'Y' or 'M' to include support for Aztech AZF3328 (PCI168) soundcards. config SND_BT87X tristate "Bt87x Audio Capture" depends on SND + select SND_PCM help Say 'Y' or 'M' to include support for recording audio from TV cards based on Brooktree Bt878/Bt879 chips. @@ -25,7 +66,8 @@ config SND_CS46XX tristate "Cirrus Logic (Sound Fusion) CS4280/CS461x/CS462x/CS463x" depends on SND - select GAMEPORT + select SND_RAWMIDI + select SND_AC97_CODEC help Say 'Y' or 'M' to include support for Cirrus Logic CS4610 / CS4612 / CS4614 / CS4615 / CS4622 / CS4624 / CS4630 / CS4280 chips. @@ -39,12 +81,18 @@ config SND_CS4281 tristate "Cirrus Logic (Sound Fusion) CS4281" depends on SND + select SND_OPL3_LIB + select SND_RAWMIDI + select SND_AC97_CODEC help Say 'Y' or 'M' to include support for Cirrus Logic CS4281. config SND_EMU10K1 tristate "EMU10K1 (SB Live! & Audigy, E-mu APS)" depends on SND + select SND_HWDEP + select SND_RAWMIDI + select SND_AC97_CODEC help Say 'Y' or 'M' to include support for Sound Blaster PCI 512, Live!, Audigy and E-mu APS (partially supported). @@ -52,18 +100,29 @@ config SND_KORG1212 tristate "Korg 1212 IO" depends on SND + select SND_PCM help Say 'Y' or 'M' to include support for Korg 1212IO. +config SND_MIXART + tristate "Digigram miXart" + depends on SND + select SND_HWDEP + select SND_PCM + help + Say 'Y' or 'M' to include support for Digigram miXart soundcard. + config SND_NM256 tristate "NeoMagic NM256AV/ZX" depends on SND + select SND_AC97_CODEC help Say 'Y' or 'M' to include support for NeoMagic NM256AV/ZX chips. config SND_RME32 tristate "RME Digi32, 32/8, 32 PRO" depends on SND + select SND_PCM help Say 'Y' or 'M' to include support for RME Digi32, Digi32 PRO and Digi32/8 (Sek'd Prodif32, Prodif96 and Prodif Gold) audio devices. @@ -71,6 +130,7 @@ config SND_RME96 tristate "RME Digi96, 96/8, 96/8 PRO" depends on SND + select SND_PCM help Say 'Y' or 'M' to include support for RME Digi96, Digi96/8 and Digi96/8 PRO/PAD/PST. @@ -78,6 +138,7 @@ config SND_RME9652 tristate "RME Digi9652 (Hammerfall)" depends on SND + select SND_PCM help Say 'Y' or 'M' to include support for RME Hammerfall (RME Digi9652 / Digi9636) soundcards. @@ -85,6 +146,9 @@ config SND_HDSP tristate "RME Hammerfall DSP Audio" depends on SND + select SND_HWDEP + select SND_RAWMIDI + select SND_PCM help Say 'Y' or 'M' to include support for RME Hammerfall DSP Audio soundcards. @@ -92,6 +156,8 @@ config SND_TRIDENT tristate "Trident 4D-Wave DX/NX; SiS 7018" depends on SND + select SND_MPU401_UART + select SND_AC97_CODEC help Say 'Y' or 'M' to include support for Trident 4D-Wave DX/NX and SiS 7018 soundcards. @@ -99,6 +165,9 @@ config SND_YMFPCI tristate "Yamaha YMF724/740/744/754" depends on SND + select SND_OPL3_LIB + select SND_MPU401_UART + select SND_AC97_CODEC help Say 'Y' or 'M' to include support for Yamaha PCI audio chips - YMF724, YMF724F, YMF740, YMF740C, YMF744, YMF754. @@ -106,12 +175,18 @@ config SND_ALS4000 tristate "Avance Logic ALS4000" depends on SND + select SND_OPL3_LIB + select SND_MPU401_UART + select SND_PCM help Say 'Y' or 'M' to include support for Avance Logic ALS4000. config SND_CMIPCI tristate "C-Media 8738, 8338" depends on SND + select SND_OPL3_LIB + select SND_MPU401_UART + select SND_PCM help Say 'Y' or 'M' to include support for C-Media CMI8338 and 8738 PCI soundcards. @@ -119,12 +194,16 @@ config SND_ENS1370 tristate "(Creative) Ensoniq AudioPCI 1370" depends on SND + select SND_RAWMIDI + select SND_PCM help Say 'Y' or 'M' to include support for Ensoniq AudioPCI ES1370. config SND_ENS1371 tristate "(Creative) Ensoniq AudioPCI 1371/1373" depends on SND + select SND_RAWMIDI + select SND_AC97_CODEC help Say 'Y' or 'M' to include support for Ensoniq AudioPCI ES1371 and Sound Blaster PCI 64 or 128 soundcards. @@ -132,6 +211,9 @@ config SND_ES1938 tristate "ESS ES1938/1946/1969 (Solo-1)" depends on SND + select SND_OPL3_LIB + select SND_MPU401_UART + select SND_AC97_CODEC help Say 'Y' or 'M' to include support for ESS Solo-1 (ES1938, ES1946, ES1969) soundcard. @@ -139,24 +221,31 @@ config SND_ES1968 tristate "ESS ES1968/1978 (Maestro-1/2/2E)" depends on SND + select SND_MPU401_UART + select SND_AC97_CODEC help Say 'Y' or 'M' to include support for ESS Maestro 1/2/2E. config SND_MAESTRO3 tristate "ESS Allegro/Maestro3" depends on SND + select SND_AC97_CODEC help Say 'Y' or 'M' to include support for ESS Maestro 3 (Allegro) soundcard. config SND_FM801 tristate "ForteMedia FM801" depends on SND + select SND_OPL3_LIB + select SND_MPU401_UART + select SND_AC97_CODEC help Say 'Y' or 'M' to include support for ForteMedia FM801 based soundcards. -config CONFIG_SND_FM801_TEA575X +config SND_FM801_TEA575X tristate "ForteMedia FM801 + TEA5757 tuner" - depends on SND_FM801 && CONFIG_VIDEO_DEV + depends on SND_FM801 + select VIDEO_DEV help Say 'Y' or 'M' to include support for ForteMedia FM801 based soundcards with TEA5757 tuner connected to GPIO1-3 pins (Media Forte SF256-PCS-02). @@ -164,6 +253,8 @@ config SND_ICE1712 tristate "ICEnsemble ICE1712 (Envy24)" depends on SND + select SND_MPU401_UART + select SND_AC97_CODEC help Say 'Y' or 'M' to include support for ICE1712 (Envy24) based soundcards. Currently supported hardware is: MidiMan M Audio - Delta 1010(LT), Dio 2496, @@ -173,6 +264,8 @@ config SND_ICE1724 tristate "ICE/VT1724 (Envy24HT)" depends on SND + select SND_MPU401_UART + select SND_AC97_CODEC help Say 'Y' or 'M' to include support for ICE/VT1724 (Envy24HT) based soundcards. @@ -182,25 +275,41 @@ config SND_INTEL8X0 tristate "Intel i8x0/MX440, SiS 7012; Ali 5455; NForce Audio; AMD768/8111" depends on SND + select SND_MPU401_UART + select SND_AC97_CODEC help Say 'Y' or 'M' to include support for Intel8x0 based soundcards, SiS 7012, AMD768/8111, NVidia NForce and ALi 5455 chips. +config SND_INTEL8X0M + tristate "Intel i8x0/MX440; AMD768/8111 modems (EXPERIMENTAL)" + depends on SND && EXPERIMENTAL + select SND_AC97_CODEC + help + Say 'Y' or 'M' to include support for Intel8x0 and AMD768/8111 based + modems. + config SND_SONICVIBES tristate "S3 SonicVibes" depends on SND + select SND_OPL3_LIB + select SND_MPU401_UART + select SND_AC97_CODEC help Say 'Y' or 'M' to include support for S3 SonicVibes based soundcards. config SND_VIA82XX tristate "VIA 82C686A/B, 8233 South Bridge" depends on SND + select SND_MPU401_UART + select SND_AC97_CODEC help Say 'Y' or 'M' to include support for VIA VT82C686A/B, VT8233 South Bridge. config SND_VX222 tristate "Digigram VX222" depends on SND + select SND_VX_LIB help Say 'Y' or 'M' to include support for Digigram VX222 soundcards. diff -Nru a/sound/pci/Makefile b/sound/pci/Makefile --- a/sound/pci/Makefile Sun Mar 14 14:20:05 2004 +++ b/sound/pci/Makefile Sun Mar 14 14:20:05 2004 @@ -4,6 +4,7 @@ # snd-als4000-objs := als4000.o +snd-atiixp-objs := atiixp.o snd-azt3328-objs := azt3328.o snd-bt87x-objs := bt87x.o snd-cmipci-objs := cmipci.o @@ -14,6 +15,7 @@ snd-es1968-objs := es1968.o snd-fm801-objs := fm801.o snd-intel8x0-objs := intel8x0.o +snd-intel8x0m-objs := intel8x0m.o snd-maestro3-objs := maestro3.o snd-rme32-objs := rme32.o snd-rme96-objs := rme96.o @@ -22,6 +24,7 @@ # Toplevel Module Dependency obj-$(CONFIG_SND_ALS4000) += snd-als4000.o +obj-$(CONFIG_SND_ATIIXP) += snd-atiixp.o obj-$(CONFIG_SND_AZT3328) += snd-azt3328.o obj-$(CONFIG_SND_BT87X) += snd-bt87x.o obj-$(CONFIG_SND_CMIPCI) += snd-cmipci.o @@ -32,10 +35,24 @@ obj-$(CONFIG_SND_ES1968) += snd-es1968.o obj-$(CONFIG_SND_FM801) += snd-fm801.o obj-$(CONFIG_SND_INTEL8X0) += snd-intel8x0.o +obj-$(CONFIG_SND_INTEL8X0M) += snd-intel8x0m.o obj-$(CONFIG_SND_MAESTRO3) += snd-maestro3.o obj-$(CONFIG_SND_RME32) += snd-rme32.o obj-$(CONFIG_SND_RME96) += snd-rme96.o obj-$(CONFIG_SND_SONICVIBES) += snd-sonicvibes.o obj-$(CONFIG_SND_VIA82XX) += snd-via82xx.o -obj-$(CONFIG_SND) += ac97/ ali5451/ cs46xx/ emu10k1/ korg1212/ nm256/ rme9652/ trident/ ymfpci/ ice1712/ vx222/ +obj-$(CONFIG_SND) += \ + ac97/ \ + ali5451/ \ + au88x0/ \ + cs46xx/ \ + emu10k1/ \ + ice1712/ \ + korg1212/ \ + mixart/ \ + nm256/ \ + rme9652/ \ + trident/ \ + ymfpci/ \ + vx222/ diff -Nru a/sound/pci/ac97/Makefile b/sound/pci/ac97/Makefile --- a/sound/pci/ac97/Makefile Sun Mar 14 14:20:07 2004 +++ b/sound/pci/ac97/Makefile Sun Mar 14 14:20:07 2004 @@ -7,21 +7,7 @@ snd-ak4531-codec-objs := ak4531_codec.o # Toplevel Module Dependency -obj-$(CONFIG_SND_CS4281) += snd-ac97-codec.o +obj-$(CONFIG_SND_AC97_CODEC) += snd-ac97-codec.o obj-$(CONFIG_SND_ENS1370) += snd-ak4531-codec.o -obj-$(CONFIG_SND_ENS1371) += snd-ac97-codec.o -obj-$(CONFIG_SND_ES1968) += snd-ac97-codec.o -obj-$(CONFIG_SND_FM801) += snd-ac97-codec.o -obj-$(CONFIG_SND_ICE1712) += snd-ac97-codec.o -obj-$(CONFIG_SND_ICE1724) += snd-ac97-codec.o -obj-$(CONFIG_SND_INTEL8X0) += snd-ac97-codec.o -obj-$(CONFIG_SND_MAESTRO3) += snd-ac97-codec.o -obj-$(CONFIG_SND_VIA82XX) += snd-ac97-codec.o -obj-$(CONFIG_SND_ALI5451) += snd-ac97-codec.o -obj-$(CONFIG_SND_CS46XX) += snd-ac97-codec.o -obj-$(CONFIG_SND_EMU10K1) += snd-ac97-codec.o -obj-$(CONFIG_SND_NM256) += snd-ac97-codec.o -obj-$(CONFIG_SND_TRIDENT) += snd-ac97-codec.o -obj-$(CONFIG_SND_YMFPCI) += snd-ac97-codec.o obj-m := $(sort $(obj-m)) diff -Nru a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c --- a/sound/pci/ac97/ac97_codec.c Sun Mar 14 14:20:07 2004 +++ b/sound/pci/ac97/ac97_codec.c Sun Mar 14 14:20:07 2004 @@ -100,13 +100,12 @@ { 0x41445361, 0xffffffff, "AD1886", patch_ad1886, NULL }, { 0x41445362, 0xffffffff, "AD1887", patch_ad1881, NULL }, { 0x41445363, 0xffffffff, "AD1886A", patch_ad1881, NULL }, +{ 0x41445368, 0xffffffff, "AD1888", patch_ad1888, NULL }, { 0x41445370, 0xffffffff, "AD1980", patch_ad1980, NULL }, { 0x41445372, 0xffffffff, "AD1981A", patch_ad1981a, NULL }, { 0x41445374, 0xffffffff, "AD1981B", patch_ad1981b, NULL }, { 0x41445375, 0xffffffff, "AD1985", patch_ad1985, NULL }, -{ 0x414c4300, 0xfffffff0, "RL5306", NULL, NULL }, -{ 0x414c4310, 0xfffffff0, "RL5382", NULL, NULL }, -{ 0x414c4320, 0xfffffff0, "RL5383", NULL, NULL }, +{ 0x414c4300, 0xffffff00, "ALC100/100P", NULL, NULL }, { 0x414c4710, 0xfffffff0, "ALC200/200P", NULL, NULL }, { 0x414c4720, 0xfffffff0, "ALC650", patch_alc650, NULL }, { 0x414c4721, 0xfffffff0, "ALC650D", patch_alc650, NULL }, @@ -273,6 +272,11 @@ { if (!snd_ac97_valid_reg(ac97, reg)) return; + if ((ac97->id & 0xffffff00) == 0x414c4300) { + /* Fix H/W bug of ALC100/100P */ + if (reg == AC97_MASTER || reg == AC97_HEADPHONE) + ac97->bus->write(ac97, AC97_RESET, 0); /* reset audio codec */ + } ac97->bus->write(ac97, reg, value); } @@ -688,7 +692,7 @@ }; static const snd_kcontrol_new_t snd_ac97_control_eapd = -AC97_SINGLE("External Amplifier Power Down", AC97_POWERDOWN, 15, 1, 0); +AC97_SINGLE("External Amplifier", AC97_POWERDOWN, 15, 1, 1); static int snd_ac97_spdif_mask_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { @@ -1526,38 +1530,40 @@ return 0; } -static int snd_ac97_test_rate(ac97_t *ac97, int reg, int rate) +static int snd_ac97_test_rate(ac97_t *ac97, int reg, int shadow_reg, int rate) { unsigned short val; unsigned int tmp; tmp = ((unsigned int)rate * ac97->bus->clock) / 48000; snd_ac97_write_cache(ac97, reg, tmp & 0xffff); + if (shadow_reg) + snd_ac97_write_cache(ac97, shadow_reg, tmp & 0xffff); val = snd_ac97_read(ac97, reg); return val == (tmp & 0xffff); } -static void snd_ac97_determine_rates(ac97_t *ac97, int reg, unsigned int *r_result) +static void snd_ac97_determine_rates(ac97_t *ac97, int reg, int shadow_reg, unsigned int *r_result) { unsigned int result = 0; /* test a non-standard rate */ - if (snd_ac97_test_rate(ac97, reg, 11000)) + if (snd_ac97_test_rate(ac97, reg, shadow_reg, 11000)) result |= SNDRV_PCM_RATE_CONTINUOUS; /* let's try to obtain standard rates */ - if (snd_ac97_test_rate(ac97, reg, 8000)) + if (snd_ac97_test_rate(ac97, reg, shadow_reg, 8000)) result |= SNDRV_PCM_RATE_8000; - if (snd_ac97_test_rate(ac97, reg, 11025)) + if (snd_ac97_test_rate(ac97, reg, shadow_reg, 11025)) result |= SNDRV_PCM_RATE_11025; - if (snd_ac97_test_rate(ac97, reg, 16000)) + if (snd_ac97_test_rate(ac97, reg, shadow_reg, 16000)) result |= SNDRV_PCM_RATE_16000; - if (snd_ac97_test_rate(ac97, reg, 22050)) + if (snd_ac97_test_rate(ac97, reg, shadow_reg, 22050)) result |= SNDRV_PCM_RATE_22050; - if (snd_ac97_test_rate(ac97, reg, 32000)) + if (snd_ac97_test_rate(ac97, reg, shadow_reg, 32000)) result |= SNDRV_PCM_RATE_32000; - if (snd_ac97_test_rate(ac97, reg, 44100)) + if (snd_ac97_test_rate(ac97, reg, shadow_reg, 44100)) result |= SNDRV_PCM_RATE_44100; - if (snd_ac97_test_rate(ac97, reg, 48000)) + if (snd_ac97_test_rate(ac97, reg, shadow_reg, 48000)) result |= SNDRV_PCM_RATE_48000; *r_result = result; } @@ -1866,8 +1872,8 @@ if (ac97->ext_id & 0x0189) /* L/R, MIC, SDAC, LDAC VRA support */ snd_ac97_write_cache(ac97, AC97_EXTENDED_STATUS, ac97->ext_id & 0x0189); if (ac97->ext_id & AC97_EI_VRA) { /* VRA support */ - snd_ac97_determine_rates(ac97, AC97_PCM_FRONT_DAC_RATE, &ac97->rates[AC97_RATES_FRONT_DAC]); - snd_ac97_determine_rates(ac97, AC97_PCM_LR_ADC_RATE, &ac97->rates[AC97_RATES_ADC]); + snd_ac97_determine_rates(ac97, AC97_PCM_FRONT_DAC_RATE, 0, &ac97->rates[AC97_RATES_FRONT_DAC]); + snd_ac97_determine_rates(ac97, AC97_PCM_LR_ADC_RATE, 0, &ac97->rates[AC97_RATES_ADC]); } else { ac97->rates[AC97_RATES_FRONT_DAC] = SNDRV_PCM_RATE_48000; ac97->rates[AC97_RATES_ADC] = SNDRV_PCM_RATE_48000; @@ -1884,16 +1890,16 @@ SNDRV_PCM_RATE_32000; } if (ac97->ext_id & AC97_EI_VRM) { /* MIC VRA support */ - snd_ac97_determine_rates(ac97, AC97_PCM_MIC_ADC_RATE, &ac97->rates[AC97_RATES_MIC_ADC]); + snd_ac97_determine_rates(ac97, AC97_PCM_MIC_ADC_RATE, 0, &ac97->rates[AC97_RATES_MIC_ADC]); } else { ac97->rates[AC97_RATES_MIC_ADC] = SNDRV_PCM_RATE_48000; } if (ac97->ext_id & AC97_EI_SDAC) { /* SDAC support */ - snd_ac97_determine_rates(ac97, AC97_PCM_SURR_DAC_RATE, &ac97->rates[AC97_RATES_SURR_DAC]); + snd_ac97_determine_rates(ac97, AC97_PCM_SURR_DAC_RATE, AC97_PCM_FRONT_DAC_RATE, &ac97->rates[AC97_RATES_SURR_DAC]); ac97->scaps |= AC97_SCAP_SURROUND_DAC; } if (ac97->ext_id & AC97_EI_LDAC) { /* LDAC support */ - snd_ac97_determine_rates(ac97, AC97_PCM_LFE_DAC_RATE, &ac97->rates[AC97_RATES_LFE_DAC]); + snd_ac97_determine_rates(ac97, AC97_PCM_LFE_DAC_RATE, AC97_PCM_FRONT_DAC_RATE, &ac97->rates[AC97_RATES_LFE_DAC]); ac97->scaps |= AC97_SCAP_CENTER_LFE_DAC; } /* additional initializations */ @@ -1937,6 +1943,15 @@ return -ENOMEM; } } + /* make sure the proper powerdown bits are cleared */ + if (ac97->scaps) { + reg = snd_ac97_read(ac97, AC97_EXTENDED_ID); + if (ac97->scaps & AC97_SCAP_SURROUND_DAC) + reg &= ~AC97_EA_PRJ; + if (ac97->scaps & AC97_SCAP_CENTER_LFE_DAC) + reg &= ~(AC97_EA_PRI | AC97_EA_PRK); + snd_ac97_write_cache(ac97, AC97_EXTENDED_ID, reg); + } snd_ac97_proc_init(ac97); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ac97, &ops)) < 0) { snd_ac97_free(ac97); @@ -1991,11 +2006,18 @@ snd_ac97_write(ac97, AC97_GENERAL_PURPOSE, 0); snd_ac97_write(ac97, AC97_POWERDOWN, ac97->regs[AC97_POWERDOWN]); - snd_ac97_write(ac97, AC97_MASTER, 0x8101); + ac97->bus->write(ac97, AC97_MASTER, 0x8101); for (i = 0; i < 10; i++) { if (snd_ac97_read(ac97, AC97_MASTER) == 0x8101) break; - mdelay(1); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + /* FIXME: extra delay */ + ac97->bus->write(ac97, AC97_MASTER, 0x8000); + if (snd_ac97_read(ac97, AC97_MASTER) != 0x8000) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/4); } __reset_ready: @@ -2112,6 +2134,8 @@ { /* FIXME: error checks.. */ if (remove_master) { + if (ctl_find(ac97, "Headphone Playback Switch") == NULL) + return 0; snd_ac97_remove_ctl(ac97, "Master Playback Switch"); snd_ac97_remove_ctl(ac97, "Master Playback Volume"); } else { @@ -2134,12 +2158,30 @@ static int tune_ad_sharing(ac97_t *ac97) { unsigned short scfg; + if ((ac97->id & 0xffffff00) != 0x41445300) { + snd_printk(KERN_ERR "ac97_quirk AD_SHARING is only for AD codecs\n"); + return -EINVAL; + } /* Turn on OMS bit to route microphone to back panel */ scfg = snd_ac97_read(ac97, AC97_AD_SERIAL_CFG); snd_ac97_write_cache(ac97, AC97_AD_SERIAL_CFG, scfg | 0x0200); return 0; } +static const snd_kcontrol_new_t snd_ac97_alc_jack_detect = +AC97_SINGLE("Jack Detect", AC97_ALC650_CLOCK, 5, 1, 0); + +static int tune_alc_jack(ac97_t *ac97) +{ + if ((ac97->id & 0xffffff00) != 0x414c4700) { + snd_printk(KERN_ERR "ac97_quirk ALC_JACK is only for Realtek codecs\n"); + return -EINVAL; + } + snd_ac97_update_bits(ac97, 0x7a, 0x20, 0x20); /* select jack detect function */ + snd_ac97_update_bits(ac97, 0x7a, 0x01, 0x01); /* Line-out auto mute */ + return snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&snd_ac97_alc_jack_detect, ac97)); +} + static int apply_quirk(ac97_t *ac97, int quirk) { switch (quirk) { @@ -2153,6 +2195,8 @@ return swap_surround(ac97); case AC97_TUNE_AD_SHARING: return tune_ad_sharing(ac97); + case AC97_TUNE_ALC_JACK: + return tune_alc_jack(ac97); } return -EINVAL; } diff -Nru a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c --- a/sound/pci/ac97/ac97_patch.c Sun Mar 14 14:20:08 2004 +++ b/sound/pci/ac97/ac97_patch.c Sun Mar 14 14:20:08 2004 @@ -292,6 +292,9 @@ return 0; } +/* + * Tritech codec + */ int patch_tritech_tr28028(ac97_t * ac97) { snd_ac97_write_cache(ac97, 0x26, 0x0300); @@ -301,6 +304,9 @@ return 0; } +/* + * Sigmatel STAC97xx codecs + */ static int patch_sigmatel_stac9700_3d(ac97_t * ac97) { snd_kcontrol_t *kctl; @@ -441,6 +447,9 @@ return 0; } +/* + * Cirrus Logic CS42xx codecs + */ static const snd_kcontrol_new_t snd_ac97_cirrus_controls_spdif[2] = { AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), AC97_CSR_SPDIF, 15, 1, 0), AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "AC97-SPSA", AC97_CSR_ACMODE, 0, 3, 0) @@ -499,6 +508,9 @@ return patch_cirrus_spdif(ac97); } +/* + * Conexant codecs + */ static const snd_kcontrol_new_t snd_ac97_conexant_controls_spdif[1] = { AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), AC97_CXR_AUDIO_MISC, 3, 1, 0), }; @@ -530,6 +542,9 @@ return 0; } +/* + * Analog Device AD18xx, AD19xx codecs + */ int patch_ad1819(ac97_t * ac97) { // patch for Analog Devices @@ -652,7 +667,7 @@ static const snd_kcontrol_new_t snd_ac97_controls_ad1885[] = { AC97_SINGLE("Digital Mono Direct", AC97_AD_MISC, 11, 1, 0), - AC97_SINGLE("Digital Audio Mode", AC97_AD_MISC, 12, 1, 0), + /* AC97_SINGLE("Digital Audio Mode", AC97_AD_MISC, 12, 1, 0), */ /* seems problematic */ AC97_SINGLE("Low Power Mixer", AC97_AD_MISC, 14, 1, 0), AC97_SINGLE("Zero Fill DAC", AC97_AD_MISC, 15, 1, 0), }; @@ -682,6 +697,9 @@ jack = snd_ac97_read(ac97, AC97_AD_JACK_SPDIF); snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, jack | 0x0300); + /* set default */ + snd_ac97_write_cache(ac97, AC97_AD_MISC, 0x0404); + ac97->build_ops = &patch_ad1885_build_ops; return 0; } @@ -799,7 +817,7 @@ return 0; } -static int snd_ac97_ad1980_lohpsel_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +static int snd_ac97_ad1888_lohpsel_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; @@ -808,7 +826,7 @@ return 0; } -static int snd_ac97_ad1980_lohpsel_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t* ucontrol) +static int snd_ac97_ad1888_lohpsel_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t* ucontrol) { ac97_t *ac97 = snd_kcontrol_chip(kcontrol); unsigned short val; @@ -818,7 +836,7 @@ return 0; } -static int snd_ac97_ad1980_lohpsel_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +static int snd_ac97_ad1888_lohpsel_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { ac97_t *ac97 = snd_kcontrol_chip(kcontrol); unsigned short val; @@ -829,7 +847,7 @@ AC97_AD198X_LOSEL | AC97_AD198X_HPSEL, val); } -static int snd_ac97_ad1980_downmix_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +static int snd_ac97_ad1888_downmix_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { static char *texts[3] = {"Off", "6 -> 4", "6 -> 2"}; @@ -842,7 +860,7 @@ return 0; } -static int snd_ac97_ad1980_downmix_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t* ucontrol) +static int snd_ac97_ad1888_downmix_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t* ucontrol) { ac97_t *ac97 = snd_kcontrol_chip(kcontrol); unsigned short val; @@ -855,7 +873,7 @@ return 0; } -static int snd_ac97_ad1980_downmix_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +static int snd_ac97_ad1888_downmix_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { ac97_t *ac97 = snd_kcontrol_chip(kcontrol); unsigned short val; @@ -871,51 +889,47 @@ AC97_AD198X_DMIX0 | AC97_AD198X_DMIX1, val); } -static const snd_kcontrol_new_t snd_ac97_ad1980_controls[] = { +static const snd_kcontrol_new_t snd_ac97_ad1888_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Exchange Front/Surround", - .info = snd_ac97_ad1980_lohpsel_info, - .get = snd_ac97_ad1980_lohpsel_get, - .put = snd_ac97_ad1980_lohpsel_put + .info = snd_ac97_ad1888_lohpsel_info, + .get = snd_ac97_ad1888_lohpsel_get, + .put = snd_ac97_ad1888_lohpsel_put }, AC97_SINGLE("Spread Front to Surround and Center/LFE", AC97_AD_MISC, 7, 1, 0), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Downmix", - .info = snd_ac97_ad1980_downmix_info, - .get = snd_ac97_ad1980_downmix_get, - .put = snd_ac97_ad1980_downmix_put + .info = snd_ac97_ad1888_downmix_info, + .get = snd_ac97_ad1888_downmix_get, + .put = snd_ac97_ad1888_downmix_put }, AC97_SINGLE("Surround Jack as Input", AC97_AD_MISC, 12, 1, 0), AC97_SINGLE("Center/LFE Jack as Input", AC97_AD_MISC, 11, 1, 0), }; -static int patch_ad1980_specific(ac97_t *ac97) +static int patch_ad1888_specific(ac97_t *ac97) { - int err; - /* rename 0x04 as "Master" and 0x02 as "Master Surround" */ snd_ac97_rename_ctl(ac97, "Master Playback Switch", "Master Surround Playback Switch"); snd_ac97_rename_ctl(ac97, "Master Playback Volume", "Master Surround Playback Volume"); snd_ac97_rename_ctl(ac97, "Headphone Playback Switch", "Master Playback Switch"); snd_ac97_rename_ctl(ac97, "Headphone Playback Volume", "Master Playback Volume"); - if ((err = patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1)) < 0) - return err; - return patch_build_controls(ac97, snd_ac97_ad1980_controls, ARRAY_SIZE(snd_ac97_ad1980_controls)); + return patch_build_controls(ac97, snd_ac97_ad1888_controls, ARRAY_SIZE(snd_ac97_ad1888_controls)); } -static struct snd_ac97_build_ops patch_ad1980_build_ops = { +static struct snd_ac97_build_ops patch_ad1888_build_ops = { .build_post_spdif = patch_ad198x_post_spdif, - .build_specific = patch_ad1980_specific + .build_specific = patch_ad1888_specific }; -int patch_ad1980(ac97_t * ac97) +int patch_ad1888(ac97_t * ac97) { unsigned short misc; patch_ad1881(ac97); - ac97->build_ops = &patch_ad1980_build_ops; + ac97->build_ops = &patch_ad1888_build_ops; /* Switch FRONT/SURROUND LINE-OUT/HP-OUT default connection */ /* it seems that most vendors connect line-out connector to headphone out of AC'97 */ /* AD-compatible mode */ @@ -930,6 +944,27 @@ return 0; } +static int patch_ad1980_specific(ac97_t *ac97) +{ + int err; + + if ((err = patch_ad1888_specific(ac97)) < 0) + return err; + return patch_build_controls(ac97, &snd_ac97_ad198x_2cmic, 1); +} + +static struct snd_ac97_build_ops patch_ad1980_build_ops = { + .build_post_spdif = patch_ad198x_post_spdif, + .build_specific = patch_ad1980_specific +}; + +int patch_ad1980(ac97_t * ac97) +{ + patch_ad1888(ac97); + ac97->build_ops = &patch_ad1980_build_ops; + return 0; +} + static const snd_kcontrol_new_t snd_ac97_ad1985_controls[] = { AC97_SINGLE("Center/LFE Jack as Mic", AC97_AD_SERIAL_CFG, 9, 1, 0), AC97_SINGLE("Exchange Center/LFE", AC97_AD_SERIAL_CFG, 3, 1, 0) @@ -972,6 +1007,36 @@ return 0; } +/* + * realtek ALC65x codecs + */ +static int snd_ac97_alc650_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1; + return 0; +} + +static int snd_ac97_alc650_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + int change, val; + val = !!(snd_ac97_read(ac97, AC97_ALC650_MULTICH) & (1 << 10)); + change = (ucontrol->value.integer.value[0] != val); + if (change) { + /* disable/enable vref */ + snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, + ucontrol->value.integer.value[0] ? (1 << 12) : 0); + /* turn on/off center-on-mic */ + snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10, + ucontrol->value.integer.value[0] ? (1 << 10) : 0); + /* GPIO0 high for mic */ + snd_ac97_update_bits(ac97, AC97_ALC650_GPIO_STATUS, 0x100, + ucontrol->value.integer.value[0] ? 0 : 0x100); + } + return change; +} + static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = { AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0), AC97_SINGLE("Surround Down Mix", AC97_ALC650_MULTICH, 1, 1, 0), @@ -994,42 +1059,13 @@ AC97_SINGLE("Center/LFE DAC Switch", AC97_ALC650_LFE_DAC_VOL, 15, 1, 1), AC97_DOUBLE("Center/LFE DAC Volume", AC97_ALC650_LFE_DAC_VOL, 8, 0, 31, 1), #endif -}; - -static const snd_kcontrol_new_t snd_ac97_control_alc650_mic = -AC97_SINGLE("Mic As Center/LFE", AC97_ALC650_MULTICH, 10, 1, 0); - -static int snd_ac97_alc650_mic_gpio_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1; - return 0; -} - -static int snd_ac97_alc650_mic_gpio_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) -{ - ac97_t *ac97 = snd_kcontrol_chip(kcontrol); - int change; - change = snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10, - ucontrol->value.integer.value[0] ? (1 << 10) : 0); - if (change) { - /* GPIO0 write for mic */ - snd_ac97_update_bits(ac97, 0x76, 0x01, - ucontrol->value.integer.value[0] ? 0 : 0x01); - /* GPIO0 high for mic */ - snd_ac97_update_bits(ac97, 0x78, 0x100, - ucontrol->value.integer.value[0] ? 0 : 0x100); - } - return change; -} - -static const snd_kcontrol_new_t snd_ac97_control_alc650_mic_gpio = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Mic As Center/LFE", - .info = snd_ac97_info_single, - .get = snd_ac97_alc650_mic_gpio_get, - .put = snd_ac97_alc650_mic_gpio_put, - .private_value = (1 << 16), /* for info */ + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Mic As Center/LFE", + .info = snd_ac97_info_single, + .get = snd_ac97_alc650_mic_get, + .put = snd_ac97_alc650_mic_put, + }, }; static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc650[] = { @@ -1044,11 +1080,6 @@ if ((err = patch_build_controls(ac97, snd_ac97_controls_alc650, ARRAY_SIZE(snd_ac97_controls_alc650))) < 0) return err; - if ((err = patch_build_controls(ac97, - ac97->spec.dev_flags ? - &snd_ac97_control_alc650_mic : - &snd_ac97_control_alc650_mic_gpio, 1)) < 0) - return err; if (ac97->ext_id & AC97_EI_SPDIF) { if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc650, ARRAY_SIZE(snd_ac97_spdif_controls_alc650))) < 0) return err; @@ -1076,34 +1107,25 @@ snd_ac97_read(ac97, AC97_ALC650_GPIO_STATUS) | 0x8000); /* Enable SPDIF-IN only on Rev.E and above */ - if (ac97->spec.dev_flags) { - /* enable spdif in */ - snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK, - snd_ac97_read(ac97, AC97_ALC650_CLOCK) | 0x03); - } + val = snd_ac97_read(ac97, AC97_ALC650_CLOCK); + /* SPDIF IN with pin 47 */ + if (ac97->spec.dev_flags) + val |= 0x03; /* enable */ + else + val &= ~0x03; /* disable */ + snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK, val); val = snd_ac97_read(ac97, AC97_ALC650_MULTICH); val &= ~0xc000; /* slot: 3,4,7,8,6,9 */ + val &= ~(1 << 10); /* center-on-mic off */ snd_ac97_write_cache(ac97, AC97_ALC650_MULTICH, val); - if (! ac97->spec.dev_flags) { - /* set GPIO */ - int mic_off; - mic_off = snd_ac97_read(ac97, AC97_ALC650_MULTICH) & (1 << 10); - /* GPIO0 direction */ - val = snd_ac97_read(ac97, AC97_ALC650_GPIO_SETUP); - if (mic_off) - val &= ~0x01; - else - val |= 0x01; - snd_ac97_write_cache(ac97, AC97_ALC650_GPIO_SETUP, val); - val = snd_ac97_read(ac97, AC97_ALC650_GPIO_STATUS); - if (mic_off) - val &= ~0x100; - else - val = val | 0x100; - snd_ac97_write_cache(ac97, AC97_ALC650_GPIO_STATUS, val); - } + /* set GPIO0 for mic bias */ + /* GPIO0 pin output, no interrupt, high */ + snd_ac97_write_cache(ac97, AC97_ALC650_GPIO_SETUP, + snd_ac97_read(ac97, AC97_ALC650_GPIO_SETUP) | 0x01); + snd_ac97_write_cache(ac97, AC97_ALC650_GPIO_STATUS, + (snd_ac97_read(ac97, AC97_ALC650_GPIO_STATUS) | 0x100) & ~0x10); /* full DAC volume */ snd_ac97_write_cache(ac97, AC97_ALC650_SURR_DAC_VOL, 0x0808); @@ -1111,10 +1133,37 @@ return 0; } +static int snd_ac97_alc655_mic_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1; + return 0; +} + +static int snd_ac97_alc655_mic_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + int change; + + /* misc control; vrefout disable */ + snd_ac97_update_bits(ac97, AC97_ALC650_CLOCK, 1 << 12, + ucontrol->value.integer.value[0] ? (1 << 12) : 0); + change = snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10, + ucontrol->value.integer.value[0] ? (1 << 10) : 0); + return change; +} + + static const snd_kcontrol_new_t snd_ac97_controls_alc655[] = { AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0), AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0), - AC97_SINGLE("Mic As Center/LFE", AC97_ALC650_MULTICH, 10, 1, 0), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Mic As Center/LFE", + .info = snd_ac97_info_single, + .get = snd_ac97_alc655_mic_get, + .put = snd_ac97_alc655_mic_put, + }, }; static int alc655_iec958_route_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) @@ -1187,15 +1236,21 @@ int patch_alc655(ac97_t * ac97) { + unsigned int val; + ac97->spec.dev_flags = (ac97->id == 0x414c4780); /* ALC658 */ ac97->build_ops = &patch_alc655_ops; - /* enable spdif in */ - snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK, - snd_ac97_read(ac97, AC97_ALC650_MULTICH) | 0x8000); - snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK, - snd_ac97_read(ac97, AC97_ALC650_CLOCK) | 0x02); + /* adjust default values */ + val = snd_ac97_read(ac97, 0x7a); /* misc control */ + val |= (1 << 1); /* spdif input pin */ + val &= ~(1 << 12); /* vref enable */ + snd_ac97_write_cache(ac97, 0x7a, val); + val = snd_ac97_read(ac97, AC97_ALC650_MULTICH); + val |= (1 << 15); /* enable spdif in */ + val &= ~(1 << 10); /* disable center on mic */ + snd_ac97_write_cache(ac97, AC97_ALC650_MULTICH, val); /* full DAC volume */ snd_ac97_write_cache(ac97, AC97_ALC650_SURR_DAC_VOL, 0x0808); @@ -1203,6 +1258,9 @@ return 0; } +/* + * C-Media CM97xx codecs + */ static const snd_kcontrol_new_t snd_ac97_cm9738_controls[] = { AC97_SINGLE("Line-In As Surround", AC97_CM9738_VENDOR_CTRL, 10, 1, 0), AC97_SINGLE("Duplicate Front", AC97_CM9738_VENDOR_CTRL, 13, 1, 0), @@ -1312,7 +1370,10 @@ /* bit 13: enable internal vref output for mic */ /* bit 12: enable center/lfe */ /* bit 14: 0 = SPDIF, 1 = EAPD */ - snd_ac97_write_cache(ac97, AC97_CM9739_MULTI_CHAN, 0x3000); + val = (1 << 12) | (1 << 13); + if (! (ac97->ext_id & AC97_EI_SPDIF)) + val |= (1 << 14); + snd_ac97_write_cache(ac97, AC97_CM9739_MULTI_CHAN, val); /* FIXME: set up GPIO */ snd_ac97_write_cache(ac97, 0x70, 0x0100); @@ -1321,6 +1382,9 @@ return 0; } +/* + * VIA VT1616 codec + */ static const snd_kcontrol_new_t snd_ac97_controls_vt1616[] = { AC97_SINGLE("DC Offset removal", 0x5a, 10, 1, 0), AC97_SINGLE("Alternate Level to Surround Out", 0x5a, 15, 1, 0), diff -Nru a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h --- a/sound/pci/ac97/ac97_patch.h Sun Mar 14 14:20:05 2004 +++ b/sound/pci/ac97/ac97_patch.h Sun Mar 14 14:20:05 2004 @@ -41,6 +41,7 @@ int patch_ad1881(ac97_t * ac97); int patch_ad1885(ac97_t * ac97); int patch_ad1886(ac97_t * ac97); +int patch_ad1888(ac97_t * ac97); int patch_ad1980(ac97_t * ac97); int patch_ad1981a(ac97_t * ac97); int patch_ad1981b(ac97_t * ac97); diff -Nru a/sound/pci/ac97/ac97_pcm.c b/sound/pci/ac97/ac97_pcm.c --- a/sound/pci/ac97/ac97_pcm.c Sun Mar 14 14:20:06 2004 +++ b/sound/pci/ac97/ac97_pcm.c Sun Mar 14 14:20:06 2004 @@ -31,6 +31,7 @@ #include #include #include +#include #include "ac97_patch.h" #include "ac97_id.h" #include "ac97_local.h" @@ -176,6 +177,7 @@ static int set_spdif_rate(ac97_t *ac97, unsigned short rate) { unsigned short old, bits, reg, mask; + unsigned int sbits; if (! (ac97->ext_id & AC97_EI_SPDIF)) return -ENODEV; @@ -213,6 +215,26 @@ if (old != bits) { snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); snd_ac97_update_bits(ac97, reg, mask, bits); + /* update the internal spdif bits */ + spin_lock(&ac97->reg_lock); + sbits = ac97->spdif_status; + if (sbits & IEC958_AES0_PROFESSIONAL) { + sbits &= ~IEC958_AES0_PRO_FS; + switch (rate) { + case 44100: sbits |= IEC958_AES0_PRO_FS_44100; break; + case 48000: sbits |= IEC958_AES0_PRO_FS_48000; break; + case 32000: sbits |= IEC958_AES0_PRO_FS_32000; break; + } + } else { + sbits &= ~(IEC958_AES3_CON_FS << 24); + switch (rate) { + case 44100: sbits |= IEC958_AES3_CON_FS_44100<<24; break; + case 48000: sbits |= IEC958_AES3_CON_FS_48000<<24; break; + case 32000: sbits |= IEC958_AES3_CON_FS_32000<<24; break; + } + } + ac97->spdif_status = sbits; + spin_unlock(&ac97->reg_lock); } snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, AC97_EA_SPDIF); return 0; diff -Nru a/sound/pci/ac97/ak4531_codec.c b/sound/pci/ac97/ak4531_codec.c --- a/sound/pci/ac97/ak4531_codec.c Sun Mar 14 14:20:06 2004 +++ b/sound/pci/ac97/ak4531_codec.c Sun Mar 14 14:20:06 2004 @@ -285,7 +285,7 @@ AK4531_DOUBLE("Aux Switch", 0, AK4531_LAUXA, AK4531_RAUXA, 7, 7, 1, 1), AK4531_DOUBLE("Aux Volume", 0, AK4531_LAUXA, AK4531_RAUXA, 0, 0, 0x1f, 1), AK4531_DOUBLE("Aux Playback Switch", 0, AK4531_OUT_SW2, AK4531_OUT_SW2, 5, 4, 1, 0), -AK4531_INPUT_SW("Aux Input Route", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 4, 3), +AK4531_INPUT_SW("Aux Capture Route", 0, AK4531_LIN_SW2, AK4531_RIN_SW2, 4, 3), AK4531_SINGLE("Mono Switch", 0, AK4531_MONO1, 7, 1, 1), AK4531_SINGLE("Mono Volume", 0, AK4531_MONO1, 0, 0x1f, 1), diff -Nru a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c --- a/sound/pci/ali5451/ali5451.c Sun Mar 14 14:20:08 2004 +++ b/sound/pci/ali5451/ali5451.c Sun Mar 14 14:20:08 2004 @@ -1742,7 +1742,8 @@ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_ali_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_ali_capture_ops); - snd_pcm_lib_preallocate_pci_pages_for_all(codec->pci, pcm, 64*1024, 128*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(codec->pci), 64*1024, 128*1024); pcm->info_flags = 0; pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; diff -Nru a/sound/pci/als4000.c b/sound/pci/als4000.c --- a/sound/pci/als4000.c Sun Mar 14 14:20:08 2004 +++ b/sound/pci/als4000.c Sun Mar 14 14:20:08 2004 @@ -99,9 +99,11 @@ MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(enable, "Enable ALS4000 soundcard."); MODULE_PARM_SYNTAX(enable, SNDRV_INDEX_DESC); +#ifdef SUPPORT_JOYSTICK MODULE_PARM(joystick_port, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(joystick_port, "Joystick port address for ALS4000 soundcard. (0 = disabled)"); MODULE_PARM_SYNTAX(joystick_port, SNDRV_ENABLED); +#endif #define chip_t sb_t @@ -521,7 +523,8 @@ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_als4000_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_als4000_capture_ops); - snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 64*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), + 64*1024, 64*1024); chip->pcm = pcm; diff -Nru a/sound/pci/atiixp.c b/sound/pci/atiixp.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/atiixp.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,1569 @@ +/* + * ALSA driver for ATI IXP 150/200/250 AC97 controllers + * + * Copyright (c) 2004 Takashi Iwai + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define SNDRV_GET_ID +#include + +MODULE_AUTHOR("Takashi Iwai "); +MODULE_DESCRIPTION("ATI IXP AC97 controller"); +MODULE_LICENSE("GPL"); +MODULE_CLASSES("{sound}"); +MODULE_DEVICES("{{ATI,IXP150/200/250}}"); + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ +static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 48000}; +static int spdif_aclink[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; + +MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(index, "Index value for ATI IXP controller."); +MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); +MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s"); +MODULE_PARM_DESC(id, "ID string for ATI IXP controller."); +MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); +MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(enable, "Enable audio part of ATI IXP controller."); +MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); +MODULE_PARM(ac97_clock, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz)."); +MODULE_PARM_SYNTAX(ac97_clock, SNDRV_ENABLED ",default:48000"); +MODULE_PARM(spdif_aclink, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(spdif_aclink, "S/PDIF over AC-link."); +MODULE_PARM_SYNTAX(spdif_aclink, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC); + + +/* + */ + +#define ATI_REG_ISR 0x00 /* interrupt source */ +#define ATI_REG_ISR_IN_XRUN (1U<<0) +#define ATI_REG_ISR_IN_STATUS (1U<<1) +#define ATI_REG_ISR_OUT_XRUN (1U<<2) +#define ATI_REG_ISR_OUT_STATUS (1U<<3) +#define ATI_REG_ISR_SPDF_XRUN (1U<<4) +#define ATI_REG_ISR_SPDF_STATUS (1U<<5) +#define ATI_REG_ISR_PHYS_INTR (1U<<8) +#define ATI_REG_ISR_PHYS_MISMATCH (1U<<9) +#define ATI_REG_ISR_CODEC0_NOT_READY (1U<<10) +#define ATI_REG_ISR_CODEC1_NOT_READY (1U<<11) +#define ATI_REG_ISR_CODEC2_NOT_READY (1U<<12) +#define ATI_REG_ISR_NEW_FRAME (1U<<13) + +#define ATI_REG_IER 0x04 /* interrupt enable */ +#define ATI_REG_IER_IN_XRUN_EN (1U<<0) +#define ATI_REG_IER_IO_STATUS_EN (1U<<1) +#define ATI_REG_IER_OUT_XRUN_EN (1U<<2) +#define ATI_REG_IER_OUT_XRUN_COND (1U<<3) +#define ATI_REG_IER_SPDF_XRUN_EN (1U<<4) +#define ATI_REG_IER_SPDF_STATUS_EN (1U<<5) +#define ATI_REG_IER_PHYS_INTR_EN (1U<<8) +#define ATI_REG_IER_PHYS_MISMATCH_EN (1U<<9) +#define ATI_REG_IER_CODEC0_INTR_EN (1U<<10) +#define ATI_REG_IER_CODEC1_INTR_EN (1U<<11) +#define ATI_REG_IER_CODEC2_INTR_EN (1U<<12) +#define ATI_REG_IER_NEW_FRAME_EN (1U<<13) /* (RO */ +#define ATI_REG_IER_SET_BUS_BUSY (1U<<14) /* (WO) audio is running */ + +#define ATI_REG_CMD 0x08 /* command */ +#define ATI_REG_CMD_POWERDOWN (1U<<0) +#define ATI_REG_CMD_RECEIVE_EN (1U<<1) +#define ATI_REG_CMD_SEND_EN (1U<<2) +#define ATI_REG_CMD_STATUS_MEM (1U<<3) +#define ATI_REG_CMD_SPDF_OUT_EN (1U<<4) +#define ATI_REG_CMD_SPDF_STATUS_MEM (1U<<5) +#define ATI_REG_CMD_SPDF_THRESHOLD (3U<<6) +#define ATI_REG_CMD_SPDF_THRESHOLD_SHIFT 6 +#define ATI_REG_CMD_IN_DMA_EN (1U<<8) +#define ATI_REG_CMD_OUT_DMA_EN (1U<<9) +#define ATI_REG_CMD_SPDF_DMA_EN (1U<<10) +#define ATI_REG_CMD_SPDF_OUT_STOPPED (1U<<11) +#define ATI_REG_CMD_SPDF_CONFIG_MASK (7U<<12) +#define ATI_REG_CMD_SPDF_CONFIG_34 (1U<<12) +#define ATI_REG_CMD_SPDF_CONFIG_78 (2U<<12) +#define ATI_REG_CMD_SPDF_CONFIG_69 (3U<<12) +#define ATI_REG_CMD_SPDF_CONFIG_01 (4U<<12) +#define ATI_REG_CMD_INTERLEAVE_SPDF (1U<<16) +#define ATI_REG_CMD_AUDIO_PRESENT (1U<<20) +#define ATI_REG_CMD_INTERLEAVE_IN (1U<<21) +#define ATI_REG_CMD_INTERLEAVE_OUT (1U<<22) +#define ATI_REG_CMD_LOOPBACK_EN (1U<<23) +#define ATI_REG_CMD_PACKED_DIS (1U<<24) +#define ATI_REG_CMD_BURST_EN (1U<<25) +#define ATI_REG_CMD_PANIC_EN (1U<<26) +#define ATI_REG_CMD_MODEM_PRESENT (1U<<27) +#define ATI_REG_CMD_ACLINK_ACTIVE (1U<<28) +#define ATI_REG_CMD_AC_SOFT_RESET (1U<<29) +#define ATI_REG_CMD_AC_SYNC (1U<<30) +#define ATI_REG_CMD_AC_RESET (1U<<31) + +#define ATI_REG_PHYS_OUT_ADDR 0x0c +#define ATI_REG_PHYS_OUT_CODEC_MASK (3U<<0) +#define ATI_REG_PHYS_OUT_RW (1U<<2) +#define ATI_REG_PHYS_OUT_ADDR_EN (1U<<8) +#define ATI_REG_PHYS_OUT_ADDR_SHIFT 9 +#define ATI_REG_PHYS_OUT_DATA_SHIFT 16 + +#define ATI_REG_PHYS_IN_ADDR 0x10 +#define ATI_REG_PHYS_IN_READ_FLAG (1U<<8) +#define ATI_REG_PHYS_IN_ADDR_SHIFT 9 +#define ATI_REG_PHYS_IN_DATA_SHIFT 16 + +#define ATI_REG_SLOTREQ 0x14 + +#define ATI_REG_COUNTER 0x18 +#define ATI_REG_COUNTER_SLOT (3U<<0) /* slot # */ +#define ATI_REG_COUNTER_BITCLOCK (31U<<8) + +#define ATI_REG_IN_FIFO_THRESHOLD 0x1c + +#define ATI_REG_IN_DMA_LINKPTR 0x20 +#define ATI_REG_IN_DMA_DT_START 0x24 /* RO */ +#define ATI_REG_IN_DMA_DT_NEXT 0x28 /* RO */ +#define ATI_REG_IN_DMA_DT_CUR 0x2c /* RO */ +#define ATI_REG_IN_DMA_DT_SIZE 0x30 + +#define ATI_REG_OUT_DMA_SLOT 0x34 +#define ATI_REG_OUT_DMA_SLOT_BIT(x) (1U << ((x) - 3)) +#define ATI_REG_OUT_DMA_SLOT_MASK 0x1ff +#define ATI_REG_OUT_DMA_THRESHOLD_MASK 0xf800 +#define ATI_REG_OUT_DMA_THRESHOLD_SHIFT 11 + +#define ATI_REG_OUT_DMA_LINKPTR 0x38 +#define ATI_REG_OUT_DMA_DT_START 0x3c /* RO */ +#define ATI_REG_OUT_DMA_DT_NEXT 0x40 /* RO */ +#define ATI_REG_OUT_DMA_DT_CUR 0x44 /* RO */ +#define ATI_REG_OUT_DMA_DT_SIZE 0x48 + +#define ATI_REG_SPDF_CMD 0x4c +#define ATI_REG_SPDF_CMD_LFSR (1U<<4) +#define ATI_REG_SPDF_CMD_SINGLE_CH (1U<<5) +#define ATI_REG_SPDF_CMD_LFSR_ACC (0xff<<8) /* RO */ + +#define ATI_REG_SPDF_DMA_LINKPTR 0x50 +#define ATI_REG_SPDF_DMA_DT_START 0x54 /* RO */ +#define ATI_REG_SPDF_DMA_DT_NEXT 0x58 /* RO */ +#define ATI_REG_SPDF_DMA_DT_CUR 0x5c /* RO */ +#define ATI_REG_SPDF_DMA_DT_SIZE 0x60 + +#define ATI_REG_MODEM_MIRROR 0x7c +#define ATI_REG_AUDIO_MIRROR 0x80 + +#define ATI_REG_6CH_REORDER 0x84 /* reorder slots for 6ch */ +#define ATI_REG_6CH_REORDER_EN (1U<<0) /* 3,4,7,8,6,9 -> 3,4,6,9,7,8 */ + +#define ATI_REG_FIFO_FLUSH 0x88 +#define ATI_REG_FIFO_OUT_FLUSH (1U<<0) +#define ATI_REG_FIFO_IN_FLUSH (1U<<1) + +/* LINKPTR */ +#define ATI_REG_LINKPTR_EN (1U<<0) + +/* [INT|OUT|SPDIF]_DMA_DT_SIZE */ +#define ATI_REG_DMA_DT_SIZE (0xffffU<<0) +#define ATI_REG_DMA_FIFO_USED (0x1fU<<16) +#define ATI_REG_DMA_FIFO_FREE (0x1fU<<21) +#define ATI_REG_DMA_STATE (7U<<26) + + +#define ATI_MEM_REGION 256 /* i/o memory size */ +#define ATI_MAX_DESCRIPTORS 256 /* max number of descriptor packets */ + + +/* + */ + +typedef struct snd_atiixp atiixp_t; +typedef struct snd_atiixp_dma atiixp_dma_t; +typedef struct snd_atiixp_dma_ops atiixp_dma_ops_t; +#define chip_t atiixp_t + + +/* + * DMA packate descriptor + */ + +typedef struct atiixp_dma_desc { + u32 addr; /* DMA buffer address */ + u16 status; /* status bits */ + u16 size; /* size of the packet in dwords */ + u32 next; /* address of the next packet descriptor */ +} atiixp_dma_desc_t; + +/* + * stream enum + */ +enum { ATI_DMA_PLAYBACK, ATI_DMA_CAPTURE, ATI_DMA_SPDIF }; + +/* + * constants and callbacks for each DMA type + */ +struct snd_atiixp_dma_ops { + int type; /* ATI_DMA_XXX */ + unsigned int llp_offset; /* LINKPTR offset */ + void (*enable_dma)(atiixp_t *chip, int on); /* called from open callback */ + void (*enable_transfer)(atiixp_t *chip, int on); /* called from trigger (START/STOP) */ + void (*flush_dma)(atiixp_t *chip); /* called from trigger (STOP only) */ +}; + +/* + * DMA stream + */ +struct snd_atiixp_dma { + const atiixp_dma_ops_t *ops; + struct snd_dma_device desc_dev; + struct snd_dma_buffer desc_buf; + snd_pcm_substream_t *substream; /* assigned PCM substream */ + unsigned int buf_addr, buf_bytes; /* DMA buffer address, bytes */ + unsigned int period_bytes, periods; + int running; + struct ac97_pcm *pcm; + int pcm_open_flag; +}; + +/* + * ATI IXP chip + */ +struct snd_atiixp { + snd_card_t *card; + struct pci_dev *pci; + + struct resource *res; /* memory i/o */ + unsigned long addr; + unsigned long remap_addr; + int irq; + + ac97_bus_t *ac97_bus; + ac97_t *ac97[3]; /* IXP can have up to 3 codecs */ + + spinlock_t reg_lock; + spinlock_t ac97_lock; + + atiixp_dma_t dmas[3]; /* playback, capture, spdif */ + + int max_channels; /* max. channels for PCM out */ + + unsigned int codec_not_ready_bits; /* for codec detection */ + + int spdif_over_aclink; /* passed from the module option */ +}; + + +/* + */ +static struct pci_device_id snd_atiixp_ids[] = { + { 0x1002, 0x4341, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, +}; + +MODULE_DEVICE_TABLE(pci, snd_atiixp_ids); + + +/* + * lowlevel functions + */ + +/* + * update the bits of the given register. + * return 1 if the bits changed. + */ +static int snd_atiixp_update_bits(atiixp_t *chip, unsigned int reg, + unsigned int mask, unsigned int value) +{ + unsigned long addr = chip->remap_addr + reg; + unsigned int data, old_data; + old_data = data = readl(addr); + data &= ~mask; + data |= value; + if (old_data == data) + return 0; + writel(data, addr); + return 1; +} + +/* + * macros for easy use + */ +#define atiixp_write(chip,reg,value) \ + writel(value, chip->remap_addr + ATI_REG_##reg) +#define atiixp_read(chip,reg) \ + readl(chip->remap_addr + ATI_REG_##reg) +#define atiixp_update(chip,reg,mask,val) \ + snd_atiixp_update_bits(chip, ATI_REG_##reg, mask, val) + +/* delay for one tick */ +#define do_delay() do { \ + set_current_state(TASK_UNINTERRUPTIBLE); \ + schedule_timeout(1); \ +} while (0) + + +/* + * handling DMA packets + * + * we allocate a linear buffer for the DMA, and split it to each packet. + * in a future version, a scatter-gather buffer should be implemented. + */ + +#define ATI_DESC_LIST_SIZE \ + PAGE_ALIGN(ATI_MAX_DESCRIPTORS * sizeof(atiixp_dma_desc_t)) + +/* + * build packets ring for the given buffer size. + * + * IXP handles the buffer descriptors, which are connected as a linked + * list. although we can change the list dynamically, in this version, + * a static RING of buffer descriptors is used. + * + * the ring is built in this function, and is set up to the hardware. + */ +static int atiixp_build_dma_packets(atiixp_t *chip, atiixp_dma_t *dma, + snd_pcm_substream_t *substream, + unsigned int periods, + unsigned int period_bytes) +{ + unsigned int i; + u32 addr, desc_addr; + unsigned long flags; + + if (periods > ATI_MAX_DESCRIPTORS) + return -ENOMEM; + + if (dma->desc_buf.area == NULL) { + memset(&dma->desc_dev, 0, sizeof(dma->desc_dev)); + dma->desc_dev.type = SNDRV_DMA_TYPE_DEV; + dma->desc_dev.dev = snd_dma_pci_data(chip->pci); + if (snd_dma_alloc_pages(&dma->desc_dev, ATI_DESC_LIST_SIZE, &dma->desc_buf) < 0) + return -ENOMEM; + dma->period_bytes = dma->periods = 0; /* clear */ + } + + if (dma->periods == dma->periods && dma->period_bytes == period_bytes) + return 0; + + /* reset DMA before changing the descriptor table */ + spin_lock_irqsave(&chip->reg_lock, flags); + writel(0, chip->remap_addr + dma->ops->llp_offset); + dma->ops->enable_dma(chip, 0); + dma->ops->enable_dma(chip, 1); + spin_unlock_irqrestore(&chip->reg_lock, flags); + + /* fill the entries */ + addr = (u32)substream->runtime->dma_addr; + desc_addr = (u32)dma->desc_buf.addr; + for (i = 0; i < periods; i++) { + atiixp_dma_desc_t *desc = &((atiixp_dma_desc_t *)dma->desc_buf.area)[i]; + desc->addr = cpu_to_le32(addr); + desc->status = 0; + desc->size = period_bytes >> 2; /* in dwords */ + desc_addr += sizeof(atiixp_dma_desc_t); + if (i == periods - 1) + desc->next = cpu_to_le32((u32)dma->desc_buf.addr); + else + desc->next = cpu_to_le32(desc_addr); + addr += period_bytes; + } + + writel(cpu_to_le32((u32)dma->desc_buf.addr | ATI_REG_LINKPTR_EN), + chip->remap_addr + dma->ops->llp_offset); + + dma->period_bytes = period_bytes; + dma->periods = periods; + + return 0; +} + +/* + * remove the ring buffer and release it if assigned + */ +static void atiixp_clear_dma_packets(atiixp_t *chip, atiixp_dma_t *dma, snd_pcm_substream_t *substream) +{ + if (dma->desc_buf.area) { + writel(0, chip->remap_addr + dma->ops->llp_offset); + snd_dma_free_pages(&dma->desc_dev, &dma->desc_buf); + dma->desc_buf.area = NULL; + } +} + +/* + * AC97 interface + */ +static int snd_atiixp_acquire_codec(atiixp_t *chip) +{ + int timeout = 1000; + + while (atiixp_read(chip, PHYS_OUT_ADDR) & ATI_REG_PHYS_OUT_ADDR_EN) { + if (! timeout--) { + snd_printk(KERN_WARNING "atiixp: codec acquire timeout\n"); + return -EBUSY; + } + udelay(1); + } + return 0; +} + +static unsigned short snd_atiixp_codec_read(atiixp_t *chip, unsigned short codec, unsigned short reg) +{ + unsigned int data; + int timeout; + + if (snd_atiixp_acquire_codec(chip) < 0) + return 0xffff; + data = (reg << ATI_REG_PHYS_OUT_ADDR_SHIFT) | + ATI_REG_PHYS_OUT_ADDR_EN | + ATI_REG_PHYS_OUT_RW | + codec; + atiixp_write(chip, PHYS_OUT_ADDR, data); + if (snd_atiixp_acquire_codec(chip) < 0) + return 0xffff; + timeout = 1000; + do { + data = atiixp_read(chip, PHYS_IN_ADDR); + if (data & ATI_REG_PHYS_IN_READ_FLAG) + return data >> ATI_REG_PHYS_IN_DATA_SHIFT; + udelay(1); + } while (--timeout); + snd_printk(KERN_WARNING "atiixp: codec read timeout\n"); + return 0xffff; +} + + +static void snd_atiixp_codec_write(atiixp_t *chip, unsigned short codec, unsigned short reg, unsigned short val) +{ + unsigned int data; + + if (snd_atiixp_acquire_codec(chip) < 0) + return; + data = ((unsigned int)val << ATI_REG_PHYS_OUT_DATA_SHIFT) | + ((unsigned int)reg << ATI_REG_PHYS_OUT_ADDR_SHIFT) | + ATI_REG_PHYS_OUT_ADDR_EN | codec; + atiixp_write(chip, PHYS_OUT_ADDR, data); +} + + +static unsigned short snd_atiixp_ac97_read(ac97_t *ac97, unsigned short reg) +{ + atiixp_t *chip = snd_magic_cast(atiixp_t, ac97->private_data, return 0xffff); + unsigned short data; + spin_lock(&chip->ac97_lock); + data = snd_atiixp_codec_read(chip, ac97->num, reg); + spin_unlock(&chip->ac97_lock); + return data; + +} + +static void snd_atiixp_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) +{ + atiixp_t *chip = snd_magic_cast(atiixp_t, ac97->private_data, return); + spin_lock(&chip->ac97_lock); + snd_atiixp_codec_write(chip, ac97->num, reg, val); + spin_unlock(&chip->ac97_lock); +} + +/* + * reset AC link + */ +static int snd_atiixp_aclink_reset(atiixp_t *chip) +{ + int timeout; + + /* reset powerdoewn */ + if (atiixp_update(chip, CMD, ATI_REG_CMD_POWERDOWN, 0)) + udelay(10); + + /* perform a software reset */ + atiixp_update(chip, CMD, ATI_REG_CMD_AC_SOFT_RESET, ATI_REG_CMD_AC_SOFT_RESET); + atiixp_read(chip, CMD); + udelay(10); + atiixp_update(chip, CMD, ATI_REG_CMD_AC_SOFT_RESET, 0); + + timeout = 10; + while (! (atiixp_read(chip, CMD) & ATI_REG_CMD_ACLINK_ACTIVE)) { + /* do a hard reset */ + atiixp_update(chip, CMD, ATI_REG_CMD_AC_SYNC|ATI_REG_CMD_AC_RESET, + ATI_REG_CMD_AC_SYNC); + atiixp_read(chip, CMD); + do_delay(); + atiixp_update(chip, CMD, ATI_REG_CMD_AC_RESET, ATI_REG_CMD_AC_RESET); + if (--timeout) { + snd_printk(KERN_ERR "atiixp: codec reset timeout\n"); + break; + } + } + + /* deassert RESET and assert SYNC to make sure */ + atiixp_update(chip, CMD, ATI_REG_CMD_AC_SYNC|ATI_REG_CMD_AC_RESET, + ATI_REG_CMD_AC_SYNC|ATI_REG_CMD_AC_RESET); + + return 0; +} + +#if 0 /* for P/M */ +static int snd_atiixp_aclink_down(atiixp_t *chip) +{ + unsigned long flags; + + if (atiixp_read(chip, MODEM_MIRROR) & ATI_REG_MODEM_MIRROR_RUNNING) + return -EBUSY; + atiixp_update(chip, CMD, + ATI_REG_CMD_POWERDOWN | ATI_REG_CMD_AC_RESET, + ATI_REG_CMD_POWERDOWN); + return 0; +} +#endif + +/* + * auto-detection of codecs + * + * the IXP chip can generate interrupts for the non-existing codecs. + * NEW_FRAME interrupt is used to make sure that the interrupt is generated + * even if all three codecs are connected. + */ + +#define ALL_CODEC_NOT_READY \ + (ATI_REG_ISR_CODEC0_NOT_READY |\ + ATI_REG_ISR_CODEC1_NOT_READY |\ + ATI_REG_ISR_CODEC2_NOT_READY) +#define CODEC_CHECK_BITS (ALL_CODEC_NOT_READY|ATI_REG_ISR_NEW_FRAME) + +static int snd_atiixp_codec_detect(atiixp_t *chip) +{ + int timeout; + + chip->codec_not_ready_bits = 0; + atiixp_write(chip, IER, CODEC_CHECK_BITS); + /* wait for the interrupts */ + timeout = HZ / 10; + while (timeout-- > 0) { + do_delay(); + if (chip->codec_not_ready_bits) + break; + } + atiixp_write(chip, IER, 0); /* disable irqs */ + + if ((chip->codec_not_ready_bits & ALL_CODEC_NOT_READY) == ALL_CODEC_NOT_READY) { + snd_printk(KERN_ERR "atiixp: no codec detected!\n"); + return -ENXIO; + } + return 0; +} + + +/* + * enable DMA and irqs + */ +static int snd_atiixp_chip_start(atiixp_t *chip) +{ + unsigned int reg; + + /* enable burst mode */ + reg = atiixp_read(chip, CMD); + reg |= 0x02 << ATI_REG_CMD_SPDF_THRESHOLD_SHIFT; + reg |= ATI_REG_CMD_BURST_EN; + atiixp_write(chip, CMD, reg); + + /* clear all interrupt source */ + atiixp_write(chip, ISR, 0xffffffff); + /* enable irqs */ + atiixp_write(chip, IER, + ATI_REG_IER_IO_STATUS_EN | + ATI_REG_IER_IN_XRUN_EN | + ATI_REG_IER_OUT_XRUN_EN | + ATI_REG_IER_SPDF_XRUN_EN | + ATI_REG_IER_SPDF_STATUS_EN); + return 0; +} + + +/* + * disable DMA and IRQs + */ +static int snd_atiixp_chip_stop(atiixp_t *chip) +{ + /* clear interrupt source */ + atiixp_write(chip, ISR, atiixp_read(chip, ISR)); + /* disable irqs */ + atiixp_write(chip, IER, 0); + return 0; +} + + +/* + * PCM section + */ + +/* + * pointer callback simplly reads XXX_DMA_DT_CUR register as the current + * position. when SG-buffer is implemented, the offset must be calculated + * correctly... + */ +static snd_pcm_uframes_t snd_atiixp_pcm_pointer(snd_pcm_substream_t *substream) +{ + atiixp_t *chip = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + atiixp_dma_t *dma = (atiixp_dma_t *)runtime->private_data; + unsigned int curptr; + unsigned long flags; + + spin_lock_irqsave(&chip->reg_lock, flags); + curptr = readl(chip->remap_addr + dma->ops->llp_offset + 12); /* XXX_DMA_DT_CUR */ + if (curptr < dma->buf_addr) { + snd_printdd("curptr = %x, base = %x\n", curptr, dma->buf_addr); + curptr = 0; + } else { + curptr -= dma->buf_addr; + if (curptr >= dma->buf_bytes) { + snd_printdd("curptr = %x, size = %x\n", curptr, dma->buf_bytes); + curptr = 0; + } + } + spin_unlock_irqrestore(&chip->reg_lock, flags); + return bytes_to_frames(runtime, curptr); +} + +/* + * XRUN detected, and stop the PCM substream + */ +static void snd_atiixp_xrun_dma(atiixp_t *chip, atiixp_dma_t *dma) +{ + if (! dma->substream || ! dma->running) + return; + snd_printd(KERN_DEBUG "atiixp: XRUN detected (DMA %d)\n", dma->ops->type); + snd_pcm_stop(dma->substream, SNDRV_PCM_STATE_XRUN); +} + +/* + * the period ack. update the substream. + */ +static void snd_atiixp_update_dma(atiixp_t *chip, atiixp_dma_t *dma) +{ + if (! dma->substream || ! dma->running) + return; + snd_pcm_period_elapsed(dma->substream); +} + +/* set BUS_BUSY interrupt bit if any DMA is running */ +/* call with spinlock held */ +static void snd_atiixp_check_bus_busy(atiixp_t *chip) +{ + unsigned int bus_busy; + if (atiixp_read(chip, CMD) & (ATI_REG_CMD_SEND_EN | + ATI_REG_CMD_RECEIVE_EN | + ATI_REG_CMD_SPDF_OUT_EN)) + bus_busy = ATI_REG_IER_SET_BUS_BUSY; + else + bus_busy = 0; + atiixp_update(chip, IER, ATI_REG_IER_SET_BUS_BUSY, bus_busy); +} + +/* common trigger callback + * calling the lowlevel callbacks in it + */ +static int snd_atiixp_pcm_trigger(snd_pcm_substream_t *substream, int cmd) +{ + atiixp_t *chip = snd_pcm_substream_chip(substream); + atiixp_dma_t *dma = (atiixp_dma_t *)substream->runtime->private_data; + int err = 0; + + snd_assert(dma->ops->enable_transfer && dma->ops->flush_dma, return -EINVAL); + + spin_lock(&chip->reg_lock); + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + dma->ops->enable_transfer(chip, 1); + dma->running = 1; + break; + case SNDRV_PCM_TRIGGER_STOP: + dma->ops->enable_transfer(chip, 0); + dma->running = 0; + break; + default: + err = -EINVAL; + break; + } + if (! err) { + snd_atiixp_check_bus_busy(chip); + if (cmd == SNDRV_PCM_TRIGGER_STOP) { + dma->ops->flush_dma(chip); + snd_atiixp_check_bus_busy(chip); + } + } + spin_unlock(&chip->reg_lock); + return err; +} + + +/* + * lowlevel callbacks for each DMA type + * + * every callback is supposed to be called in chip->reg_lock spinlock + */ + +/* flush FIFO of analog OUT DMA */ +static void atiixp_out_flush_dma(atiixp_t *chip) +{ + atiixp_write(chip, FIFO_FLUSH, ATI_REG_FIFO_OUT_FLUSH); +} + +/* enable/disable analog OUT DMA */ +static void atiixp_out_enable_dma(atiixp_t *chip, int on) +{ + unsigned int data; + data = atiixp_read(chip, CMD); + if (on) { + if (data & ATI_REG_CMD_OUT_DMA_EN) + return; + atiixp_out_flush_dma(chip); + data |= ATI_REG_CMD_OUT_DMA_EN; + } else + data &= ~ATI_REG_CMD_OUT_DMA_EN; + atiixp_write(chip, CMD, data); +} + +/* start/stop transfer over OUT DMA */ +static void atiixp_out_enable_transfer(atiixp_t *chip, int on) +{ + atiixp_update(chip, CMD, ATI_REG_CMD_SEND_EN, + on ? ATI_REG_CMD_SEND_EN : 0); +} + +/* enable/disable analog IN DMA */ +static void atiixp_in_enable_dma(atiixp_t *chip, int on) +{ + atiixp_update(chip, CMD, ATI_REG_CMD_IN_DMA_EN, + on ? ATI_REG_CMD_IN_DMA_EN : 0); +} + +/* start/stop analog IN DMA */ +static void atiixp_in_enable_transfer(atiixp_t *chip, int on) +{ + if (on) { + unsigned int data = atiixp_read(chip, CMD); + if (! (data & ATI_REG_CMD_RECEIVE_EN)) { + data |= ATI_REG_CMD_RECEIVE_EN; +#if 0 /* FIXME: this causes the endless loop */ + /* wait until slot 3/4 are finished */ + while ((atiixp_read(chip, COUNTER) & + ATI_REG_COUNTER_SLOT) != 5) + ; +#endif + atiixp_write(chip, CMD, data); + } + } else + atiixp_update(chip, CMD, ATI_REG_CMD_RECEIVE_EN, 0); +} + +/* flush FIFO of analog IN DMA */ +static void atiixp_in_flush_dma(atiixp_t *chip) +{ + atiixp_write(chip, FIFO_FLUSH, ATI_REG_FIFO_IN_FLUSH); +} + +/* enable/disable SPDIF OUT DMA */ +static void atiixp_spdif_enable_dma(atiixp_t *chip, int on) +{ + atiixp_update(chip, CMD, ATI_REG_CMD_SPDF_DMA_EN, + on ? ATI_REG_CMD_SPDF_DMA_EN : 0); +} + +/* start/stop SPDIF OUT DMA */ +static void atiixp_spdif_enable_transfer(atiixp_t *chip, int on) +{ + unsigned int data; + data = atiixp_read(chip, CMD); + if (on) { + data |= ATI_REG_CMD_SPDF_OUT_EN; + if (chip->spdif_over_aclink) + data |= ATI_REG_CMD_SEND_EN; + } else { + data &= ~ATI_REG_CMD_SPDF_OUT_EN; + if (chip->spdif_over_aclink) + data &= ~ATI_REG_CMD_SEND_EN; + } + atiixp_write(chip, CMD, data); +} + +/* flush FIFO of SPDIF OUT DMA */ +static void atiixp_spdif_flush_dma(atiixp_t *chip) +{ + int timeout; + + /* DMA off, transfer on */ + atiixp_spdif_enable_dma(chip, 0); + atiixp_spdif_enable_transfer(chip, 1); + + timeout = 100; + do { + if (! (atiixp_read(chip, SPDF_DMA_DT_SIZE) & ATI_REG_DMA_FIFO_USED)) + break; + udelay(1); + } while (timeout-- > 0); + + atiixp_spdif_enable_transfer(chip, 0); +} + +/* set up slots and formats for SPDIF OUT */ +static int snd_atiixp_spdif_prepare(snd_pcm_substream_t *substream) +{ + atiixp_t *chip = snd_pcm_substream_chip(substream); + unsigned int data; + + spin_lock(&chip->reg_lock); + if (chip->spdif_over_aclink) { + /* enable slots 10/11 */ + atiixp_update(chip, CMD, ATI_REG_CMD_SPDF_CONFIG_MASK, + ATI_REG_CMD_SPDF_CONFIG_01); + data = atiixp_read(chip, OUT_DMA_SLOT); + data |= ATI_REG_OUT_DMA_SLOT_BIT(10) | + ATI_REG_OUT_DMA_SLOT_BIT(11); + data |= 0x04 << ATI_REG_OUT_DMA_THRESHOLD_SHIFT; + atiixp_write(chip, OUT_DMA_SLOT, data); + } else { + atiixp_update(chip, CMD, ATI_REG_CMD_SPDF_CONFIG_MASK, 0); + } + + atiixp_update(chip, CMD, ATI_REG_CMD_INTERLEAVE_SPDF, + substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE ? + ATI_REG_CMD_INTERLEAVE_SPDF : 0); + spin_unlock(&chip->reg_lock); + return 0; +} + +/* set up slots and formats for analog OUT */ +static int snd_atiixp_playback_prepare(snd_pcm_substream_t *substream) +{ + atiixp_t *chip = snd_pcm_substream_chip(substream); + unsigned int data; + + spin_lock(&chip->reg_lock); + data = atiixp_read(chip, OUT_DMA_SLOT) & ~ATI_REG_OUT_DMA_SLOT_MASK; + switch (substream->runtime->channels) { + case 8: + data |= ATI_REG_OUT_DMA_SLOT_BIT(10) | + ATI_REG_OUT_DMA_SLOT_BIT(11); + /* fallthru */ + case 6: + data |= ATI_REG_OUT_DMA_SLOT_BIT(7) | + ATI_REG_OUT_DMA_SLOT_BIT(8); + /* fallthru */ + case 4: + data |= ATI_REG_OUT_DMA_SLOT_BIT(6) | + ATI_REG_OUT_DMA_SLOT_BIT(9); + /* fallthru */ + default: + data |= ATI_REG_OUT_DMA_SLOT_BIT(3) | + ATI_REG_OUT_DMA_SLOT_BIT(4); + break; + } + + /* set output threshold */ + data |= 0x04 << ATI_REG_OUT_DMA_THRESHOLD_SHIFT; + atiixp_write(chip, OUT_DMA_SLOT, data); + + atiixp_update(chip, CMD, ATI_REG_CMD_INTERLEAVE_OUT, + substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE ? + ATI_REG_CMD_INTERLEAVE_OUT : 0); + + /* + * enable 6 channel re-ordering bit if needed + */ + atiixp_update(chip, 6CH_REORDER, ATI_REG_6CH_REORDER_EN, + substream->runtime->channels >= 6 ? ATI_REG_6CH_REORDER_EN: 0); + + spin_unlock(&chip->reg_lock); + return 0; +} + +/* set up slots and formats for analog IN */ +static int snd_atiixp_capture_prepare(snd_pcm_substream_t *substream) +{ + atiixp_t *chip = snd_pcm_substream_chip(substream); + + spin_lock(&chip->reg_lock); + atiixp_update(chip, CMD, ATI_REG_CMD_INTERLEAVE_IN, + substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE ? + ATI_REG_CMD_INTERLEAVE_IN : 0); + spin_unlock(&chip->reg_lock); + return 0; +} + +/* + * hw_params - allocate the buffer and set up buffer descriptors + */ +static int snd_atiixp_pcm_hw_params(snd_pcm_substream_t *substream, + snd_pcm_hw_params_t *hw_params) +{ + atiixp_t *chip = snd_pcm_substream_chip(substream); + atiixp_dma_t *dma = (atiixp_dma_t *)substream->runtime->private_data; + int err; + + err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); + if (err < 0) + return err; + dma->buf_addr = substream->runtime->dma_addr; + dma->buf_bytes = params_buffer_bytes(hw_params); + + err = atiixp_build_dma_packets(chip, dma, substream, + params_periods(hw_params), + params_period_bytes(hw_params)); + if (err < 0) + return err; + + if (dma->pcm) { + /* PCM is bound to AC97 codec(s) + * set up the AC97 codecs + */ + if (dma->pcm_open_flag) { + snd_ac97_pcm_close(dma->pcm); + dma->pcm_open_flag = 0; + } + err = snd_ac97_pcm_open(dma->pcm, params_rate(hw_params), + params_channels(hw_params), + dma->pcm->r[0].slots); + if (err >= 0) + dma->pcm_open_flag = 1; + } + + return err; +} + +static int snd_atiixp_pcm_hw_free(snd_pcm_substream_t * substream) +{ + atiixp_t *chip = snd_pcm_substream_chip(substream); + atiixp_dma_t *dma = (atiixp_dma_t *)substream->runtime->private_data; + + if (dma->pcm_open_flag) { + snd_ac97_pcm_close(dma->pcm); + dma->pcm_open_flag = 0; + } + atiixp_clear_dma_packets(chip, dma, substream); + snd_pcm_lib_free_pages(substream); + return 0; +} + + +/* + * pcm hardware definition, identical for all DMA types + */ +static snd_pcm_hardware_t snd_atiixp_pcm_hw = +{ + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 256 * 1024, + .period_bytes_min = 32, + .period_bytes_max = 128 * 1024, + .periods_min = 2, + .periods_max = ATI_MAX_DESCRIPTORS, +}; + +static int snd_atiixp_pcm_open(snd_pcm_substream_t *substream, atiixp_dma_t *dma) +{ + atiixp_t *chip = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + unsigned long flags; + int err; + + snd_assert(dma->ops && dma->ops->enable_dma, return -EINVAL); + + dma->substream = substream; + runtime->hw = snd_atiixp_pcm_hw; + if (dma->pcm) { + runtime->hw.rates = dma->pcm->rates; + snd_pcm_limit_hw_rates(runtime); + } else { + /* SPDIF */ + runtime->hw.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_32000; + runtime->hw.rate_min = 32000; + } + if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) + return err; + runtime->private_data = dma; + + /* enable DMA bits */ + spin_lock_irqsave(&chip->reg_lock, flags); + dma->ops->enable_dma(chip, 1); + spin_unlock_irqrestore(&chip->reg_lock, flags); + + return 0; +} + +static int snd_atiixp_pcm_close(snd_pcm_substream_t *substream, atiixp_dma_t *dma) +{ + atiixp_t *chip = snd_pcm_substream_chip(substream); + /* disable DMA bits */ + snd_assert(dma->ops && dma->ops->enable_dma, return -EINVAL); + spin_lock_irq(&chip->reg_lock); + dma->ops->enable_dma(chip, 0); + spin_unlock_irq(&chip->reg_lock); + dma->substream = NULL; + return 0; +} + +/* + */ +static int snd_atiixp_playback_open(snd_pcm_substream_t *substream) +{ + atiixp_t *chip = snd_pcm_substream_chip(substream); + int err; + + err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK]); + substream->runtime->hw.channels_max = chip->max_channels; + if (chip->max_channels > 2) + /* channels must be even */ + snd_pcm_hw_constraint_step(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, 2); + + return 0; +} + +static int snd_atiixp_playback_close(snd_pcm_substream_t *substream) +{ + atiixp_t *chip = snd_pcm_substream_chip(substream); + return snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]); +} + +static int snd_atiixp_capture_open(snd_pcm_substream_t *substream) +{ + atiixp_t *chip = snd_pcm_substream_chip(substream); + return snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_CAPTURE]); +} + +static int snd_atiixp_capture_close(snd_pcm_substream_t *substream) +{ + atiixp_t *chip = snd_pcm_substream_chip(substream); + return snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_CAPTURE]); +} + +static int snd_atiixp_spdif_open(snd_pcm_substream_t *substream) +{ + atiixp_t *chip = snd_pcm_substream_chip(substream); + return snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_SPDIF]); +} + +static int snd_atiixp_spdif_close(snd_pcm_substream_t *substream) +{ + atiixp_t *chip = snd_pcm_substream_chip(substream); + return snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_SPDIF]); +} + +/* AC97 playback */ +static snd_pcm_ops_t snd_atiixp_playback_ops = { + .open = snd_atiixp_playback_open, + .close = snd_atiixp_playback_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_atiixp_pcm_hw_params, + .hw_free = snd_atiixp_pcm_hw_free, + .prepare = snd_atiixp_playback_prepare, + .trigger = snd_atiixp_pcm_trigger, + .pointer = snd_atiixp_pcm_pointer, +}; + +/* AC97 capture */ +static snd_pcm_ops_t snd_atiixp_capture_ops = { + .open = snd_atiixp_capture_open, + .close = snd_atiixp_capture_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_atiixp_pcm_hw_params, + .hw_free = snd_atiixp_pcm_hw_free, + .prepare = snd_atiixp_capture_prepare, + .trigger = snd_atiixp_pcm_trigger, + .pointer = snd_atiixp_pcm_pointer, +}; + +/* SPDIF playback */ +static snd_pcm_ops_t snd_atiixp_spdif_ops = { + .open = snd_atiixp_spdif_open, + .close = snd_atiixp_spdif_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_atiixp_pcm_hw_params, + .hw_free = snd_atiixp_pcm_hw_free, + .prepare = snd_atiixp_spdif_prepare, + .trigger = snd_atiixp_pcm_trigger, + .pointer = snd_atiixp_pcm_pointer, +}; + +static struct ac97_pcm atiixp_pcm_defs[] __devinitdata = { + /* front PCM */ + { + .exclusive = 1, + .r = { { + .slots = (1 << AC97_SLOT_PCM_LEFT) | + (1 << AC97_SLOT_PCM_RIGHT) | + (1 << AC97_SLOT_PCM_CENTER) | + (1 << AC97_SLOT_PCM_SLEFT) | + (1 << AC97_SLOT_PCM_SRIGHT) | + (1 << AC97_SLOT_LFE) + } + } + }, + /* PCM IN #1 */ + { + .stream = 1, + .exclusive = 1, + .r = { { + .slots = (1 << AC97_SLOT_PCM_LEFT) | + (1 << AC97_SLOT_PCM_RIGHT) + } + } + }, + /* S/PDIF OUT (optional) */ + { + .exclusive = 1, + .spdif = 1, + .r = { { + .slots = (1 << AC97_SLOT_SPDIF_LEFT2) | + (1 << AC97_SLOT_SPDIF_RIGHT2) + } + } + }, +}; + +static atiixp_dma_ops_t snd_atiixp_playback_dma_ops = { + .type = ATI_DMA_PLAYBACK, + .llp_offset = ATI_REG_OUT_DMA_LINKPTR, + .enable_dma = atiixp_out_enable_dma, + .enable_transfer = atiixp_out_enable_transfer, + .flush_dma = atiixp_out_flush_dma, +}; + +static atiixp_dma_ops_t snd_atiixp_capture_dma_ops = { + .type = ATI_DMA_CAPTURE, + .llp_offset = ATI_REG_IN_DMA_LINKPTR, + .enable_dma = atiixp_in_enable_dma, + .enable_transfer = atiixp_in_enable_transfer, + .flush_dma = atiixp_in_flush_dma, +}; + +static atiixp_dma_ops_t snd_atiixp_spdif_dma_ops = { + .type = ATI_DMA_SPDIF, + .llp_offset = ATI_REG_SPDF_DMA_LINKPTR, + .enable_dma = atiixp_spdif_enable_dma, + .enable_transfer = atiixp_spdif_enable_transfer, + .flush_dma = atiixp_spdif_flush_dma, +}; + + +static int __devinit snd_atiixp_pcm_new(atiixp_t *chip) +{ + snd_pcm_t *pcm; + ac97_bus_t *pbus = chip->ac97_bus; + int err, i, num_pcms; + + /* initialize constants */ + chip->dmas[ATI_DMA_PLAYBACK].ops = &snd_atiixp_playback_dma_ops; + chip->dmas[ATI_DMA_CAPTURE].ops = &snd_atiixp_capture_dma_ops; + chip->dmas[ATI_DMA_SPDIF].ops = &snd_atiixp_spdif_dma_ops; + + /* assign AC97 pcm */ + if (chip->spdif_over_aclink) + num_pcms = 3; + else + num_pcms = 2; + err = snd_ac97_pcm_assign(pbus, num_pcms, atiixp_pcm_defs); + if (err < 0) + return err; + + chip->max_channels = 2; + if (pbus->pcms[0].r[0].slots & (1 << AC97_SLOT_PCM_SLEFT)) { + if (pbus->pcms[0].r[0].slots & (1 << AC97_SLOT_LFE)) + chip->max_channels = 6; + else + chip->max_channels = 4; + } + + chip->dmas[ATI_DMA_PLAYBACK].pcm = &pbus->pcms[0]; + chip->dmas[ATI_DMA_CAPTURE].pcm = &pbus->pcms[1]; + if (chip->spdif_over_aclink) + chip->dmas[ATI_DMA_SPDIF].pcm = &pbus->pcms[2]; + + /* PCM #0: analog I/O */ + err = snd_pcm_new(chip->card, "ATI IXP AC97", 0, 1, 1, &pcm); + if (err < 0) + return err; + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_atiixp_playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_atiixp_capture_ops); + pcm->private_data = chip; + strcpy(pcm->name, "ATI IXP AC97"); + + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), 64*1024, 128*1024); + + /* no SPDIF support on codec? */ + if (chip->dmas[ATI_DMA_SPDIF].pcm && ! chip->dmas[ATI_DMA_SPDIF].pcm->rates) + return 0; + + /* PCM #1: spdif playback */ + err = snd_pcm_new(chip->card, "ATI IXP IEC958", 1, 1, 0, &pcm); + if (err < 0) + return err; + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_atiixp_spdif_ops); + pcm->private_data = chip; + strcpy(pcm->name, "ATI IXP IEC958"); + + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), 64*1024, 128*1024); + + /* pre-select AC97 SPDIF slots 10/11 */ + for (i = 0; i < 3; i++) { + if (chip->ac97[i]) + snd_ac97_update_bits(chip->ac97[i], AC97_EXTENDED_STATUS, 0x03 << 4, 0x03 << 4); + } + + return 0; +} + + + +/* + * interrupt handler + */ +static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + atiixp_t *chip = snd_magic_cast(atiixp_t, dev_id, return IRQ_NONE); + unsigned int status; + + status = atiixp_read(chip, ISR); + + if (! status) + return IRQ_NONE; + + /* process audio DMA */ + if (status & ATI_REG_ISR_OUT_XRUN) + snd_atiixp_xrun_dma(chip, &chip->dmas[ATI_DMA_PLAYBACK]); + else if (status & ATI_REG_ISR_OUT_STATUS) + snd_atiixp_update_dma(chip, &chip->dmas[ATI_DMA_PLAYBACK]); + if (status & ATI_REG_ISR_IN_XRUN) + snd_atiixp_xrun_dma(chip, &chip->dmas[ATI_DMA_CAPTURE]); + else if (status & ATI_REG_ISR_IN_STATUS) + snd_atiixp_update_dma(chip, &chip->dmas[ATI_DMA_CAPTURE]); + if (status & ATI_REG_ISR_SPDF_XRUN) + snd_atiixp_xrun_dma(chip, &chip->dmas[ATI_DMA_SPDIF]); + else if (status & ATI_REG_ISR_SPDF_STATUS) + snd_atiixp_update_dma(chip, &chip->dmas[ATI_DMA_SPDIF]); + + /* for codec detection */ + if (status & CODEC_CHECK_BITS) { + unsigned int detected; + detected = status & CODEC_CHECK_BITS; + spin_lock(&chip->reg_lock); + chip->codec_not_ready_bits |= detected; + atiixp_update(chip, IER, detected, 0); /* disable the detected irqs */ + spin_unlock(&chip->reg_lock); + } + + /* ack */ + atiixp_write(chip, ISR, status); + + return IRQ_HANDLED; +} + + +/* + * ac97 mixer section + */ + +static int __devinit snd_atiixp_mixer_new(atiixp_t *chip, int clock) +{ + ac97_bus_t bus, *pbus; + ac97_t ac97; + int i, err; + static unsigned int codec_skip[3] = { + ATI_REG_ISR_CODEC0_NOT_READY, + ATI_REG_ISR_CODEC1_NOT_READY, + ATI_REG_ISR_CODEC2_NOT_READY, + }; + + if (snd_atiixp_codec_detect(chip) < 0) + return -ENXIO; + + memset(&bus, 0, sizeof(bus)); + bus.write = snd_atiixp_ac97_write; + bus.read = snd_atiixp_ac97_read; + bus.private_data = chip; + bus.clock = clock; + if ((err = snd_ac97_bus(chip->card, &bus, &pbus)) < 0) + return err; + chip->ac97_bus = pbus; + + for (i = 0; i < 3; i++) { + if (chip->codec_not_ready_bits & codec_skip[i]) + continue; + memset(&ac97, 0, sizeof(ac97)); + ac97.private_data = chip; + ac97.pci = chip->pci; + ac97.num = i; + if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) + return err; + } + + /* snd_ac97_tune_hardware(chip->ac97, ac97_quirks); */ + + return 0; +} + + +/* + * proc interface for register dump + */ + +static void snd_atiixp_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) +{ + atiixp_t *chip = snd_magic_cast(atiixp_t, entry->private_data, return); + int i; + + for (i = 0; i < 256; i += 4) + snd_iprintf(buffer, "%02x: %08x\n", i, readl(chip->remap_addr + i)); +} + +static void __devinit snd_atiixp_proc_init(atiixp_t *chip) +{ + snd_info_entry_t *entry; + + if (! snd_card_proc_new(chip->card, "atiixp", &entry)) + snd_info_set_text_ops(entry, chip, 1024, snd_atiixp_proc_read); +} + + + +/* + * destructor + */ + +static int snd_atiixp_free(atiixp_t *chip) +{ + if (chip->irq < 0) + goto __hw_end; + snd_atiixp_chip_stop(chip); + synchronize_irq(chip->irq); + __hw_end: + if (chip->remap_addr) + iounmap((void *) chip->remap_addr); + if (chip->res) { + release_resource(chip->res); + kfree_nocheck(chip->res); + } + if (chip->irq >= 0) + free_irq(chip->irq, (void *)chip); + snd_magic_kfree(chip); + return 0; +} + +static int snd_atiixp_dev_free(snd_device_t *device) +{ + atiixp_t *chip = snd_magic_cast(atiixp_t, device->device_data, return -ENXIO); + return snd_atiixp_free(chip); +} + +/* + * constructor for chip instance + */ +static int __devinit snd_atiixp_create(snd_card_t *card, + struct pci_dev *pci, + atiixp_t **r_chip) +{ + static snd_device_ops_t ops = { + .dev_free = snd_atiixp_dev_free, + }; + atiixp_t *chip; + int err; + + if ((err = pci_enable_device(pci)) < 0) + return err; + + chip = snd_magic_kcalloc(atiixp_t, 0, GFP_KERNEL); + if (chip == NULL) + return -ENOMEM; + + spin_lock_init(&chip->reg_lock); + spin_lock_init(&chip->ac97_lock); + chip->card = card; + chip->pci = pci; + chip->irq = -1; + chip->addr = pci_resource_start(pci, 0); + if ((chip->res = request_mem_region(chip->addr, ATI_MEM_REGION, "ATI IXP AC97")) == NULL) { + snd_printk("unable to grab I/O memory 0x%lx\n", chip->addr); + snd_atiixp_free(chip); + return -EBUSY; + } + chip->remap_addr = (unsigned long) ioremap_nocache(chip->addr, ATI_MEM_REGION); + if (chip->remap_addr == 0) { + snd_printk("AC'97 space ioremap problem\n"); + snd_atiixp_free(chip); + return -EIO; + } + + if (request_irq(pci->irq, snd_atiixp_interrupt, SA_INTERRUPT|SA_SHIRQ, card->shortname, (void *)chip)) { + snd_printk("unable to grab IRQ %d\n", pci->irq); + snd_atiixp_free(chip); + return -EBUSY; + } + chip->irq = pci->irq; + pci_set_master(pci); + synchronize_irq(chip->irq); + + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + snd_atiixp_free(chip); + return err; + } + + snd_card_set_dev(card, &pci->dev); + + *r_chip = chip; + return 0; +} + + +static int __devinit snd_atiixp_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) +{ + static int dev; + snd_card_t *card; + atiixp_t *chip; + unsigned char revision; + int err; + + if (dev >= SNDRV_CARDS) + return -ENODEV; + if (!enable[dev]) { + dev++; + return -ENOENT; + } + + card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); + if (card == NULL) + return -ENOMEM; + + pci_read_config_byte(pci, PCI_REVISION_ID, &revision); + + strcpy(card->driver, "ATIIXP"); + strcpy(card->shortname, "ATI IXP"); + if ((err = snd_atiixp_create(card, pci, &chip)) < 0) + goto __error; + + if ((err = snd_atiixp_aclink_reset(chip)) < 0) + goto __error; + + chip->spdif_over_aclink = spdif_aclink[dev]; + + if ((err = snd_atiixp_mixer_new(chip, ac97_clock[dev])) < 0) + goto __error; + + if ((err = snd_atiixp_pcm_new(chip)) < 0) + goto __error; + + snd_atiixp_proc_init(chip); + + snd_atiixp_chip_start(chip); + + sprintf(card->longname, "%s rev %x at 0x%lx, irq %i", + card->shortname, revision, chip->addr, chip->irq); + + if ((err = snd_card_register(card)) < 0) + goto __error; + + pci_set_drvdata(pci, chip); + dev++; + return 0; + + __error: + snd_card_free(card); + return err; +} + +static void __devexit snd_atiixp_remove(struct pci_dev *pci) +{ + atiixp_t *chip = snd_magic_cast(atiixp_t, pci_get_drvdata(pci), return); + if (chip) + snd_card_free(chip->card); + pci_set_drvdata(pci, NULL); +} + +static struct pci_driver driver = { + .name = "ATI IXP AC97 controller", + .id_table = snd_atiixp_ids, + .probe = snd_atiixp_probe, + .remove = __devexit_p(snd_atiixp_remove), +}; + + +static int __init alsa_card_atiixp_init(void) +{ + int err; + + if ((err = pci_module_init(&driver)) < 0) { +#ifdef MODULE + printk(KERN_ERR "ATI IXP AC97 controller not found or device busy\n"); +#endif + return err; + } + + return 0; +} + +static void __exit alsa_card_atiixp_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_atiixp_init) +module_exit(alsa_card_atiixp_exit) + +#ifndef MODULE + +/* format is: snd-atiixp=enable,index,id,ac97_clock,spdif_aclink */ + +static int __init alsa_card_atiixp_setup(char *str) +{ + static unsigned __initdata nr_dev = 0; + + if (nr_dev >= SNDRV_CARDS) + return 0; + (void)(get_option(&str,&enable[nr_dev]) == 2 && + get_option(&str,&index[nr_dev]) == 2 && + get_id(&str,&id[nr_dev]) == 2 && + get_option(&str,&ac97_clock[nr_dev]) == 2 && + get_option(&str,&spdif_aclink[nr_dev]) == 2 + ); + nr_dev++; + return 1; +} + +__setup("snd-atiixp=", alsa_card_atiixp_setup); + +#endif /* ifndef MODULE */ diff -Nru a/sound/pci/au88x0/Makefile b/sound/pci/au88x0/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/au88x0/Makefile Sun Mar 14 14:20:09 2004 @@ -0,0 +1,7 @@ +snd-au8810-objs := au8810.o +snd-au8820-objs := au8820.o +snd-au8830-objs := au8830.o + +obj-$(CONFIG_SND_AU8810) += snd-au8810.o +obj-$(CONFIG_SND_AU8820) += snd-au8820.o +obj-$(CONFIG_SND_AU8830) += snd-au8830.o diff -Nru a/sound/pci/au88x0/au8810.c b/sound/pci/au88x0/au8810.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/au88x0/au8810.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,17 @@ +#include "au8810.h" +#include "au88x0.h" +static struct pci_device_id snd_vortex_ids[] = { + {PCI_VENDOR_ID_AUREAL, PCI_DEVICE_ID_AUREAL_ADVANTAGE, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1,}, + {0,} +}; + +#include "au88x0_core.c" +#include "au88x0_pcm.c" +#include "au88x0_mixer.c" +#include "au88x0_mpu401.c" +#include "au88x0_game.c" +#include "au88x0_eq.c" +#include "au88x0_a3d.c" +#include "au88x0_xtalk.c" +#include "au88x0.c" diff -Nru a/sound/pci/au88x0/au8810.h b/sound/pci/au88x0/au8810.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/au88x0/au8810.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,221 @@ +/* + Aureal Advantage Soundcard driver. + */ + +#define CHIP_AU8810 + +#define CARD_NAME "Aureal Advantage 3D Sound Processor" +#define CARD_NAME_SHORT "au8810" + +#ifndef PCI_VENDOR_ID_AUREAL +#define PCI_VENDOR_ID_AUREAL 0x12eb +#endif +#ifndef PCI_VENDOR_ID_AUREAL_ADVANTAGE +#define PCI_DEVICE_ID_AUREAL_ADVANTAGE 0x0003 +#endif + +#define hwread(x,y) readl((x)+((y)>>2)) +#define hwwrite(x,y,z) writel((z),(x)+((y)>>2)) + +#define NR_ADB 0x20 +#define NR_WT 0x00 +#define NR_SRC 0x10 +#define NR_A3D 0x10 +#define NR_MIXIN 0x20 +#define NR_MIXOUT 0x10 + + +/* ADBDMA */ +#define VORTEX_ADBDMA_STAT 0x27e00 /* read only, subbuffer, DMA pos */ +#define POS_MASK 0x00000fff +#define POS_SHIFT 0x0 +#define ADB_SUBBUF_MASK 0x00003000 /* ADB only. */ +#define ADB_SUBBUF_SHIFT 0xc /* ADB only. */ +#define VORTEX_ADBDMA_CTRL 0x27180 /* write only; format, flags, DMA pos */ +#define OFFSET_MASK 0x00000fff +#define OFFSET_SHIFT 0x0 +#define IE_MASK 0x00001000 /* interrupt enable. */ +#define IE_SHIFT 0xc +#define DIR_MASK 0x00002000 /* Direction */ +#define DIR_SHIFT 0xd +#define FMT_MASK 0x0003c000 +#define FMT_SHIFT 0xe +// The ADB masks and shift also are valid for the wtdma, except if specified otherwise. +#define VORTEX_ADBDMA_BUFCFG0 0x27100 +#define VORTEX_ADBDMA_BUFCFG1 0x27104 +#define VORTEX_ADBDMA_BUFBASE 0x27000 +#define VORTEX_ADBDMA_START 0x27c00 /* Which subbuffer starts */ + +#define VORTEX_ADBDMA_STATUS 0x27A90 /* stored at AdbDma->this_10 / 2 DWORD in size. */ + +/* WTDMA */ +#define VORTEX_WTDMA_CTRL 0x27fd8 /* format, DMA pos */ +#define VORTEX_WTDMA_STAT 0x27fe8 /* DMA subbuf, DMA pos */ +#define WT_SUBBUF_MASK 0x3 +#define WT_SUBBUF_SHIFT 0xc +#define VORTEX_WTDMA_BUFBASE 0x27fc0 +#define VORTEX_WTDMA_BUFCFG0 0x27fd0 +#define VORTEX_WTDMA_BUFCFG1 0x27fd4 +#define VORTEX_WTDMA_START 0x27fe4 /* which subbuffer is first */ + +/* ADB */ +#define VORTEX_ADB_SR 0x28400 /* Samplerates enable/disable */ +#define VORTEX_ADB_RTBASE 0x28000 +#define VORTEX_ADB_RTBASE_SIZE (VORTEX_ADB_CHNBASE - VORTEX_ADB_RTBASE) +#define VORTEX_ADB_CHNBASE 0x282b4 +#define VORTEX_ADB_CHNBASE_SIZE (ADB_MASK - VORTEX_ADB_RTBASE_SIZE) +#define ROUTE_MASK 0xffff +#define SOURCE_MASK 0xff00 +#define ADB_MASK 0xff +#define ADB_SHIFT 0x8 +/* ADB address */ +#define OFFSET_ADBDMA 0x00 +#define OFFSET_SRCIN 0x40 +#define OFFSET_SRCOUT 0x20 +#define OFFSET_MIXIN 0x50 +#define OFFSET_MIXOUT 0x30 +#define OFFSET_CODECIN 0x70 +#define OFFSET_CODECOUT 0x88 +#define OFFSET_SPORTIN 0x78 /* ch 0x13 */ +#define OFFSET_SPORTOUT 0x90 +#define OFFSET_SPDIFOUT 0x92 /* ch 0x14 check this! */ +#define OFFSET_EQIN 0xa0 +#define OFFSET_EQOUT 0x7e /* 2 routes on ch 0x11 */ +#define OFFSET_XTALKOUT 0x66 /* crosstalk canceller (source) */ +#define OFFSET_XTALKIN 0x96 /* crosstalk canceller (sink) */ +#define OFFSET_EFXIN 0x80 /* ADB sink. */ +#define OFFSET_EFXOUT 0x68 /* ADB source. */ + +/* ADB route translate helper */ +#define ADB_DMA(x) (x) +#define ADB_SRCOUT(x) (x + OFFSET_SRCOUT) +#define ADB_SRCIN(x) (x + OFFSET_SRCIN) +#define ADB_MIXOUT(x) (x + OFFSET_MIXOUT) +#define ADB_MIXIN(x) (x + OFFSET_MIXIN) +#define ADB_CODECIN(x) (x + OFFSET_CODECIN) +#define ADB_CODECOUT(x) (x + OFFSET_CODECOUT) +#define ADB_SPORTIN(x) (x + OFFSET_SPORTIN) +#define ADB_SPORTOUT(x) (x + OFFSET_SPORTOUT) +#define ADB_SPDIFOUT(x) (x + OFFSET_SPDIFOUT) +#define ADB_EQIN(x) (x + OFFSET_EQIN) +#define ADB_EQOUT(x) (x + OFFSET_EQOUT) +#define ADB_A3DOUT(x) (x + 0x50) /* A3D blocks */ +#define ADB_A3DIN(x) (x + 0x70) +#define ADB_XTALKIN(x) (x + OFFSET_XTALKIN) +#define ADB_XTALKOUT(x) (x + OFFSET_XTALKOUT) + +#define MIX_OUTL 0xe +#define MIX_OUTR 0xf +#define MIX_INL 0x1e +#define MIX_INR 0x1f +#define MIX_DEFIGAIN 0x08 /* 0x8 => 6dB */ +#define MIX_DEFOGAIN 0x08 + +/* MIXER */ +#define VORTEX_MIXER_SR 0x21f00 +#define VORTEX_MIXER_CLIP 0x21f80 +#define VORTEX_MIXER_CHNBASE 0x21e40 +#define VORTEX_MIXER_RTBASE 0x21e00 +#define MIXER_RTBASE_SIZE 0x38 +#define VORTEX_MIX_ENIN 0x21a00 /* Input enable bits. 4 bits wide. */ +#define VORTEX_MIX_SMP 0x21c00 /* AU8820: 0x9c00 */ + +/* MIX */ +#define VORTEX_MIX_INVOL_A 0x21000 /* in? */ +#define VORTEX_MIX_INVOL_B 0x20000 /* out? */ +#define VORTEX_MIX_VOL_A 0x21800 +#define VORTEX_MIX_VOL_B 0x20800 + +#define VOL_MIN 0x80 /* Input volume when muted. */ +#define VOL_MAX 0x7f /* FIXME: Not confirmed! Just guessed. */ + +/* SRC */ +#define VORTEX_SRCBLOCK_SR 0x26cc0 +#define VORTEX_SRC_CHNBASE 0x26c40 +#define VORTEX_SRC_RTBASE 0x26c00 +#define VORTEX_SRC_SOURCE 0x26cc4 +#define VORTEX_SRC_SOURCESIZE 0x26cc8 +#define VORTEX_SRC_CONVRATIO 0x26e40 +#define VORTEX_SRC_DRIFT0 0x26e80 +#define VORTEX_SRC_DRIFT1 0x26ec0 +#define VORTEX_SRC_DRIFT2 0x26f40 +#define VORTEX_SRC_U0 0x26e00 +#define VORTEX_SRC_U1 0x26f00 +#define VORTEX_SRC_U2 0x26f80 +#define VORTEX_SRC_DATA 0x26800 /* 0xc800 */ +#define VORTEX_SRC_DATA0 0x26000 + +/* FIFO */ +#define VORTEX_FIFO_ADBCTRL 0x16100 /* Control bits. */ +#define VORTEX_FIFO_WTCTRL 0x16000 +#define FIFO_RDONLY 0x00000001 +#define FIFO_CTRL 0x00000002 /* Allow ctrl. ? */ +#define FIFO_VALID 0x00000010 +#define FIFO_EMPTY 0x00000020 +#define FIFO_U0 0x00001000 /* Unknown. */ +#define FIFO_U1 0x00010000 +#define FIFO_SIZE_BITS 5 +#define FIFO_SIZE (1<this_10 / 2 DWORD in size. */ + +/* ADB */ +#define VORTEX_ADB_SR 0x10a00 /* Samplerates enable/disable */ +#define VORTEX_ADB_RTBASE 0x10800 +#define VORTEX_ADB_RTBASE_SIZE (VORTEX_ADB_CHNBASE - VORTEX_ADB_RTBASE) +#define VORTEX_ADB_CHNBASE 0x1099c +#define VORTEX_ADB_CHNBASE_SIZE (ADB_MASK - VORTEX_ADB_RTBASE_SIZE) +#define ROUTE_MASK 0x3fff +#define ADB_MASK 0x7f +#define ADB_SHIFT 0x7 +//#define ADB_MIX_MASK 0xf +/* ADB address */ +#define OFFSET_ADBDMA 0x00 +#define OFFSET_SRCOUT 0x10 /* on channel 0x11 */ +#define OFFSET_SRCIN 0x10 /* on channel < 0x11 */ +#define OFFSET_MIXOUT 0x20 /* source */ +#define OFFSET_MIXIN 0x30 /* sink */ +#define OFFSET_CODECIN 0x48 /* ADB source */ +#define OFFSET_CODECOUT 0x58 /* ADB sink/target */ +#define OFFSET_SPORTOUT 0x60 /* sink */ +#define OFFSET_SPORTIN 0x50 /* source */ +#define OFFSET_EFXOUT 0x50 /* sink */ +#define OFFSET_EFXIN 0x40 /* source */ +#define OFFSET_A3DOUT 0x00 /* This card has no HRTF :( */ +#define OFFSET_A3DIN 0x00 +#define OFFSET_WTOUT 0x58 /* */ + +/* ADB route translate helper */ +#define ADB_DMA(x) (x + OFFSET_ADBDMA) +#define ADB_SRCOUT(x) (x + OFFSET_SRCOUT) +#define ADB_SRCIN(x) (x + OFFSET_SRCIN) +#define ADB_MIXOUT(x) (x + OFFSET_MIXOUT) +#define ADB_MIXIN(x) (x + OFFSET_MIXIN) +#define ADB_CODECIN(x) (x + OFFSET_CODECIN) +#define ADB_CODECOUT(x) (x + OFFSET_CODECOUT) +#define ADB_SPORTOUT(x) (x + OFFSET_SPORTOUT) +#define ADB_SPORTIN(x) (x + OFFSET_SPORTIN) /* */ +#define ADB_A3DOUT(x) (x + OFFSET_A3DOUT) /* 8 A3D blocks */ +#define ADB_A3DIN(x) (x + OFFSET_A3DIN) +#define ADB_WTOUT(x,y) (y + OFFSET_WTOUT) + +/* WTDMA */ +#define VORTEX_WTDMA_CTRL 0x10500 /* format, DMA pos */ +#define VORTEX_WTDMA_STAT 0x10500 /* DMA subbuf, DMA pos */ +#define WT_SUBBUF_MASK (0x3 << WT_SUBBUF_SHIFT) +#define WT_SUBBUF_SHIFT 0x15 +#define VORTEX_WTDMA_BUFBASE 0x10000 +#define VORTEX_WTDMA_BUFCFG0 0x10300 +#define VORTEX_WTDMA_BUFCFG1 0x10304 +#define VORTEX_WTDMA_START 0x10640 /* which subbuffer is first */ + +#define VORTEX_WT_BASE 0x9000 + +/* MIXER */ +#define VORTEX_MIXER_SR 0x9f00 +#define VORTEX_MIXER_CLIP 0x9f80 +#define VORTEX_MIXER_CHNBASE 0x9e40 +#define VORTEX_MIXER_RTBASE 0x9e00 +#define MIXER_RTBASE_SIZE 0x26 +#define VORTEX_MIX_ENIN 0x9a00 /* Input enable bits. 4 bits wide. */ +#define VORTEX_MIX_SMP 0x9c00 + +/* MIX */ +#define VORTEX_MIX_INVOL_A 0x9000 /* in? */ +#define VORTEX_MIX_INVOL_B 0x8000 /* out? */ +#define VORTEX_MIX_VOL_A 0x9800 +#define VORTEX_MIX_VOL_B 0x8800 + +#define VOL_MIN 0x80 /* Input volume when muted. */ +#define VOL_MAX 0x7f /* FIXME: Not confirmed! Just guessed. */ + +//#define MIX_OUTL 0xe +//#define MIX_OUTR 0xf +//#define MIX_INL 0xe +//#define MIX_INR 0xf +#define MIX_DEFIGAIN 0x08 /* 0x8 => 6dB */ +#define MIX_DEFOGAIN 0x08 + +/* SRC */ +#define VORTEX_SRCBLOCK_SR 0xccc0 +#define VORTEX_SRC_CHNBASE 0xcc40 +#define VORTEX_SRC_RTBASE 0xcc00 +#define VORTEX_SRC_SOURCE 0xccc4 +#define VORTEX_SRC_SOURCESIZE 0xccc8 +#define VORTEX_SRC_U0 0xce00 +#define VORTEX_SRC_DRIFT0 0xce80 +#define VORTEX_SRC_DRIFT1 0xcec0 +#define VORTEX_SRC_U1 0xcf00 +#define VORTEX_SRC_DRIFT2 0xcf40 +#define VORTEX_SRC_U2 0xcf80 +#define VORTEX_SRC_DATA 0xc800 +#define VORTEX_SRC_DATA0 0xc000 +#define VORTEX_SRC_CONVRATIO 0xce40 +//#define SRC_RATIO(x) ((((x<<15)/48000) + 1)/2) /* Playback */ +//#define SRC_RATIO2(x) ((((48000<<15)/x) + 1)/2) /* Recording */ + +/* FIFO */ +#define VORTEX_FIFO_ADBCTRL 0xf800 /* Control bits. */ +#define VORTEX_FIFO_WTCTRL 0xf840 +#define FIFO_RDONLY 0x00000001 +#define FIFO_CTRL 0x00000002 /* Allow ctrl. ? */ +#define FIFO_VALID 0x00000010 +#define FIFO_EMPTY 0x00000020 +#define FIFO_U0 0x00001000 /* Unknown. */ +#define FIFO_U1 0x00010000 +#define FIFO_SIZE_BITS 5 +#define FIFO_SIZE (1<>2)) +#define hwwrite(x,y,z) writel((z),(x)+((y)>>2)) + +#define NR_ADB 0x20 +#define NR_SRC 0x10 +#define NR_A3D 0x10 +#define NR_MIXIN 0x20 +#define NR_MIXOUT 0x10 +#define NR_WT 0x40 + +/* ADBDMA */ +#define VORTEX_ADBDMA_STAT 0x27e00 /* read only, subbuffer, DMA pos */ +#define POS_MASK 0x00000fff +#define POS_SHIFT 0x0 +#define ADB_SUBBUF_MASK 0x00003000 /* ADB only. */ +#define ADB_SUBBUF_SHIFT 0xc /* ADB only. */ +#define VORTEX_ADBDMA_CTRL 0x27a00 /* write only; format, flags, DMA pos */ +#define OFFSET_MASK 0x00000fff +#define OFFSET_SHIFT 0x0 +#define IE_MASK 0x00001000 /* interrupt enable. */ +#define IE_SHIFT 0xc +#define DIR_MASK 0x00002000 /* Direction. */ +#define DIR_SHIFT 0xd +#define FMT_MASK 0x0003c000 +#define FMT_SHIFT 0xe +#define ADB_FIFO_EN_SHIFT 0x15 +#define ADB_FIFO_EN (1 << 0x15) +// The ADB masks and shift also are valid for the wtdma, except if specified otherwise. +#define VORTEX_ADBDMA_BUFCFG0 0x27800 +#define VORTEX_ADBDMA_BUFCFG1 0x27804 +#define VORTEX_ADBDMA_BUFBASE 0x27400 +#define VORTEX_ADBDMA_START 0x27c00 /* Which subbuffer starts */ + +#define VORTEX_ADBDMA_STATUS 0x27A90 /* stored at AdbDma->this_10 / 2 DWORD in size. */ +/* Starting at MSB, each pair seem to be the current DMA page. */ +/* This current page bits are consistent (same value) with VORTEX_ADBDMA_STAT) */ + +/* DMA */ +#define VORTEX_ENGINE_CTRL 0x27ae8 +#define ENGINE_INIT 0x1380000 + +/* WTDMA */ +#define VORTEX_WTDMA_CTRL 0x27900 /* format, DMA pos */ +#define VORTEX_WTDMA_STAT 0x27d00 /* DMA subbuf, DMA pos */ +#define WT_SUBBUF_MASK 0x3 +#define WT_SUBBUF_SHIFT 0xc +#define VORTEX_WTDMA_BUFBASE 0x27000 +#define VORTEX_WTDMA_BUFCFG0 0x27600 +#define VORTEX_WTDMA_BUFCFG1 0x27604 +#define VORTEX_WTDMA_START 0x27b00 /* which subbuffer is first */ + +/* ADB */ +#define VORTEX_ADB_SR 0x28400 /* Samplerates enable/disable */ +#define VORTEX_ADB_RTBASE 0x28000 +#define VORTEX_ADB_RTBASE_SIZE (VORTEX_ADB_CHNBASE - VORTEX_ADB_RTBASE) +#define VORTEX_ADB_CHNBASE 0x282b4 +#define VORTEX_ADB_CHNBASE_SIZE (ADB_MASK - VORTEX_ADB_RTBASE_SIZE) +#define ROUTE_MASK 0xffff +#define SOURCE_MASK 0xff00 +#define ADB_MASK 0xff +#define ADB_SHIFT 0x8 +/* ADB address */ +#define OFFSET_ADBDMA 0x00 +#define OFFSET_ADBDMAB 0x20 +#define OFFSET_SRCIN 0x40 +#define OFFSET_SRCOUT 0x20 /* ch 0x11 */ +#define OFFSET_MIXIN 0x50 /* ch 0x11 */ +#define OFFSET_MIXOUT 0x30 /* ch 0x11 */ +#define OFFSET_CODECIN 0x70 /* ch 0x11 */ /* adb source */ +#define OFFSET_CODECOUT 0x88 /* ch 0x11 */ /* adb target */ +#define OFFSET_SPORTIN 0x78 /* ch 0x13 ADB source. 2 routes. */ +#define OFFSET_SPORTOUT 0x90 /* ch 0x13 ADB sink. 2 routes. */ +#define OFFSET_SPDIFIN 0x7A /* ch 0x14 ADB source. */ +#define OFFSET_SPDIFOUT 0x92 /* ch 0x14 ADB sink. */ +#define OFFSET_AC98IN 0x7c /* ch 0x14 ADB source. */ +#define OFFSET_AC98OUT 0x94 /* ch 0x14 ADB sink. */ +#define OFFSET_EQIN 0xa0 /* ch 0x11 */ +#define OFFSET_EQOUT 0x7e /* ch 0x11 */ /* 2 routes on ch 0x11 */ +#define OFFSET_A3DIN 0x70 /* ADB sink. */ +#define OFFSET_A3DOUT 0xA6 /* ADB source. 2 routes per slice = 8 */ +#define OFFSET_WT0 0x40 /* WT bank 0 output. 0x40 - 0x65 */ +#define OFFSET_WT1 0x80 /* WT bank 1 output. 0x80 - 0xA5 */ +/* WT sources offset : 0x00-0x1f Direct stream. */ +/* WT sources offset : 0x20-0x25 Mixed Output. */ +#define OFFSET_XTALKOUT 0x66 /* crosstalk canceller (source) 2 routes */ +#define OFFSET_XTALKIN 0x96 /* crosstalk canceller (sink). 10 routes */ +#define OFFSET_EFXOUT 0x68 /* ADB source. 8 routes. */ +#define OFFSET_EFXIN 0x80 /* ADB sink. 8 routes. */ + +/* ADB route translate helper */ +#define ADB_DMA(x) (x) +#define ADB_SRCOUT(x) (x + OFFSET_SRCOUT) +#define ADB_SRCIN(x) (x + OFFSET_SRCIN) +#define ADB_MIXOUT(x) (x + OFFSET_MIXOUT) +#define ADB_MIXIN(x) (x + OFFSET_MIXIN) +#define ADB_CODECIN(x) (x + OFFSET_CODECIN) +#define ADB_CODECOUT(x) (x + OFFSET_CODECOUT) +#define ADB_SPORTIN(x) (x + OFFSET_SPORTIN) +#define ADB_SPORTOUT(x) (x + OFFSET_SPORTOUT) +#define ADB_SPDIFIN(x) (x + OFFSET_SPDIFIN) +#define ADB_SPDIFOUT(x) (x + OFFSET_SPDIFOUT) +#define ADB_EQIN(x) (x + OFFSET_EQIN) +#define ADB_EQOUT(x) (x + OFFSET_EQOUT) +#define ADB_A3DOUT(x) (x + OFFSET_A3DOUT) /* 0x10 A3D blocks */ +#define ADB_A3DIN(x) (x + OFFSET_A3DIN) +//#define ADB_WTOUT(x) ((x6dB (6dB = x4) 16 to 18 bit conversion? */ + +/* MIXER */ +#define VORTEX_MIXER_SR 0x21f00 +#define VORTEX_MIXER_CLIP 0x21f80 +#define VORTEX_MIXER_CHNBASE 0x21e40 +#define VORTEX_MIXER_RTBASE 0x21e00 +#define MIXER_RTBASE_SIZE 0x38 +#define VORTEX_MIX_ENIN 0x21a00 /* Input enable bits. 4 bits wide. */ +#define VORTEX_MIX_SMP 0x21c00 /* wave data buffers. AU8820: 0x9c00 */ + +/* MIX */ +#define VORTEX_MIX_INVOL_B 0x20000 /* Input volume current */ +#define VORTEX_MIX_VOL_B 0x20800 /* Output Volume current */ +#define VORTEX_MIX_INVOL_A 0x21000 /* Input Volume target */ +#define VORTEX_MIX_VOL_A 0x21800 /* Output Volume target */ + +#define VOL_MIN 0x80 /* Input volume when muted. */ +#define VOL_MAX 0x7f /* FIXME: Not confirmed! Just guessed. */ + +/* SRC */ +#define VORTEX_SRC_CHNBASE 0x26c40 +#define VORTEX_SRC_RTBASE 0x26c00 +#define VORTEX_SRCBLOCK_SR 0x26cc0 +#define VORTEX_SRC_SOURCE 0x26cc4 +#define VORTEX_SRC_SOURCESIZE 0x26cc4 +/* Params + 0x26e00 : 1 U0 + 0x26e40 : 2 CR + 0x26e80 : 3 U3 + 0x26ec0 : 4 DRIFT1 + 0x26f00 : 5 U1 + 0x26f40 : 6 DRIFT2 + 0x26f80 : 7 U2 : Target rate, direction +*/ + +#define VORTEX_SRC_CONVRATIO 0x26e40 +#define VORTEX_SRC_DRIFT0 0x26e80 +#define VORTEX_SRC_DRIFT1 0x26ec0 +#define VORTEX_SRC_DRIFT2 0x26f40 +#define VORTEX_SRC_U0 0x26e00 +#define U0_SLOWLOCK 0x200 +#define VORTEX_SRC_U1 0x26f00 +#define VORTEX_SRC_U2 0x26f80 +#define VORTEX_SRC_DATA 0x26800 /* 0xc800 */ +#define VORTEX_SRC_DATA0 0x26000 + +/* FIFO */ +#define VORTEX_FIFO_ADBCTRL 0x16100 /* Control bits. */ +#define VORTEX_FIFO_WTCTRL 0x16000 +#define FIFO_RDONLY 0x00000001 +#define FIFO_CTRL 0x00000002 /* Allow ctrl. ? */ +#define FIFO_VALID 0x00000010 +#define FIFO_EMPTY 0x00000020 +#define FIFO_U0 0x00002000 /* Unknown. */ +#define FIFO_U1 0x00040000 +#define FIFO_SIZE_BITS 6 +#define FIFO_SIZE (1<<(FIFO_SIZE_BITS)) // 0x40 +#define FIFO_MASK (FIFO_SIZE-1) //0x3f /* at shift left 0xc */ +#define FIFO_BITS 0x1c400000 +#define VORTEX_FIFO_ADBDATA 0x14000 +#define VORTEX_FIFO_WTDATA 0x10000 + +#define VORTEX_FIFO_GIRT 0x17000 /* wt0, wt1, adb */ +#define GIRT_COUNT 3 + +/* CODEC */ + +#define VORTEX_CODEC_CHN 0x29080 /* The name "CHN" is wrong. */ + +#define VORTEX_CODEC_CTRL 0x29184 +#define VORTEX_CODEC_IO 0x29188 +#define VORTEX_CODEC_WRITE 0x00800000 +#define VORTEX_CODEC_ADDSHIFT 16 +#define VORTEX_CODEC_ADDMASK 0x7f0000 /* 0x000f0000 */ +#define VORTEX_CODEC_DATSHIFT 0 +#define VORTEX_CODEC_DATMASK 0xffff + +#define VORTEX_CODEC_SPORTCTRL 0x2918c + +#define VORTEX_CODEC_EN 0x29190 +#define EN_AUDIO0 0x00000300 +#define EN_MODEM 0x00000c00 +#define EN_AUDIO1 0x00003000 +#define EN_SPORT 0x00030000 +#define EN_SPDIF 0x000c0000 +#define EN_CODEC (EN_AUDIO1 | EN_AUDIO0) + +#define VORTEX_SPDIF_SMPRATE 0x29194 + +#define VORTEX_SPDIF_FLAGS 0x2205c +#define VORTEX_SPDIF_CFG0 0x291D0 /* status data */ +#define VORTEX_SPDIF_CFG1 0x291D4 + +#define VORTEX_SMP_TIME 0x29198 /* Sample counter/timer */ +#define VORTEX_SMP_TIMER 0x2919c +#define VORTEX_CODEC2_CTRL 0x291a0 + +#define VORTEX_MODEM_CTRL 0x291ac + +/* IRQ */ +#define VORTEX_IRQ_SOURCE 0x2a000 /* Interrupt source flags. */ +#define VORTEX_IRQ_CTRL 0x2a004 /* Interrupt source mask. */ + +//#define VORTEX_IRQ_U0 0x2a008 /* ?? */ +#define VORTEX_STAT 0x2a008 /* Some sort of status */ +#define STAT_IRQ 0x00000001 /* This bitis set if the IRQ is valid. */ + +#define VORTEX_CTRL 0x2a00c +#define CTRL_MIDI_EN 0x00000001 +#define CTRL_MIDI_PORT 0x00000060 +#define CTRL_GAME_EN 0x00000008 +#define CTRL_GAME_PORT 0x00000e00 +#define CTRL_IRQ_ENABLE 0x00004000 +#define CTRL_SPDIF 0x00000000 /* unknown. Please find this value */ +#define CTRL_SPORT 0x00200000 +#define CTRL_RST 0x00800000 +#define CTRL_UNKNOWN 0x01000000 + +/* write: Timer period config / read: TIMER IRQ ack. */ +#define VORTEX_IRQ_STAT 0x2919c + + /* MIDI *//* GAME. */ +#define VORTEX_MIDI_DATA 0x28800 +#define VORTEX_MIDI_CMD 0x28804 /* Write command / Read status */ + +#define VORTEX_GAME_LEGACY 0x28808 +#define VORTEX_CTRL2 0x2880c +#define CTRL2_GAME_ADCMODE 0x40 +#define VORTEX_GAME_AXIS 0x28810 /* Axis base register. 4 axis's */ +#define AXIS_SIZE 4 +#define AXIS_RANGE 0x1fff diff -Nru a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/au88x0/au88x0.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,419 @@ +/* + * ALSA driver for the Aureal Vortex family of soundprocessors. + * Author: Manuel Jander (mjander@embedded.cl) + * + * This driver is the result of the OpenVortex Project from Savannah + * (savannah.nongnu.org/projects/openvortex). I would like to thank + * the developers of OpenVortex, Jeff Muizelar and Kester Maddock, from + * whom i got plenty of help, and their codebase was invaluable. + * Thanks to the ALSA developers, they helped a lot working out + * the ALSA part. + * Thanks also to Sourceforge for maintaining the old binary drivers, + * and the forum, where developers could comunicate. + * + * Now at least i can play Legacy DOOM with MIDI music :-) + */ + +#include "au88x0.h" +#include +#include +#include +#include +#define SNDRV_GET_ID +#include + +// module parameters (see "Module Parameters") +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; +static int pcifix[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 255 }; + +MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); +MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); +MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s"); +MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); +MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); +MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); +MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); +MODULE_PARM(pcifix, "1-255i"); +MODULE_PARM_DESC(pcifix, "Enable VIA-workaround for " CARD_NAME " soundcard."); +MODULE_PARM_SYNTAX(pcifix, + SNDRV_ENABLED + ",allows:{{0,Disabled},{1,Latency},{2,Bridge},{3,Both},{255,Auto}},default:4,dialog:check"); + +MODULE_DESCRIPTION("Aureal vortex"); +MODULE_CLASSES("{sound}"); +MODULE_LICENSE("GPL"); +MODULE_DEVICES("{{Aureal Semiconductor Inc., Aureal Vortex Sound Processor}}"); + +#ifndef MODULE +/* format is: snd-mychip=enable,index,id */ +static int __init alsa_card_vortex_setup(char *str) +{ + static unsigned __initdata nr_dev = 0; + + if (nr_dev >= SNDRV_CARDS) + return 0; + (void)(get_option(&str, &enable[nr_dev]) == 2 && + get_option(&str, &index[nr_dev]) == 2 && + get_id(&str, &id[nr_dev]) == 2); + nr_dev++; + return 1; +} + +__setup("snd-au88x0=", alsa_card_vortex_setup); +#endif /* ifndef MODULE */ + +MODULE_DEVICE_TABLE(pci, snd_vortex_ids); + +static void __devinit snd_vortex_workaround(struct pci_dev *vortex, int fix) +{ + struct pci_dev *via = NULL; + /* autodetect if workarounds are required */ + while ((via = pci_find_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_8365_1, via))) { + if (fix == 255) { + printk(KERN_INFO CARD_NAME + ": detected VIA KT133/KM133. activating workaround...\n"); + fix = 3; // do latency and via bridge workaround + } + break; + } + + /* do not do anything if autodetection was enabled and found no VIA */ + if (fix == 255) + return; + + int rc; + + /* fix vortex latency */ + if (fix & 0x01) { + if (!(rc = pci_write_config_byte(vortex, 0x40, 0xff))) { + printk(KERN_INFO CARD_NAME + ": vortex latency is 0xff\n"); + } else { + printk(KERN_WARNING CARD_NAME + ": could not set vortex latency: pci error 0x%x\n", + rc); + } + } + + /* fix via agp bridge */ + if (via && (fix & 0x02)) { + u8 value; + + /* + * only set the bit (Extend PCI#2 Internal Master for + * Efficient Handling of Dummy Requests) if the can + * read the config and it is not already set + */ + + if (!(rc = pci_read_config_byte(via, 0x42, &value)) + && ((value & 0x10) + || !(rc = + pci_write_config_byte(via, 0x42, value | 0x10)))) { + + printk(KERN_INFO CARD_NAME + ": bridge config is 0x%x\n", value | 0x10); + } else { + printk(KERN_WARNING CARD_NAME + ": could not set vortex latency: pci error 0x%x\n", + rc); + } + } +} + +// component-destructor +// (see "Management of Cards and Components") +static int snd_vortex_dev_free(snd_device_t * device) +{ + vortex_t *vortex = snd_magic_cast(vortex_t, device->device_data, + return -ENXIO); + + vortex_gameport_unregister(vortex); + vortex_core_shutdown(vortex); + // Take down PCI interface. + synchronize_irq(vortex->irq); + free_irq(vortex->irq, vortex); + pci_release_regions(vortex->pci_dev); + pci_disable_device(vortex->pci_dev); + snd_magic_kfree(vortex); + + return 0; +} + +// chip-specific constructor +// (see "Management of Cards and Components") +static int __devinit +snd_vortex_create(snd_card_t * card, struct pci_dev *pci, vortex_t ** rchip) +{ + vortex_t *chip; + int err; + static snd_device_ops_t ops = { + .dev_free = snd_vortex_dev_free, + }; + + *rchip = NULL; + + // check PCI availability (DMA). + if ((err = pci_enable_device(pci)) < 0) + return err; + if (!pci_dma_supported(pci, VORTEX_DMA_MASK)) { + printk(KERN_ERR "error to set DMA mask\n"); + return -ENXIO; + } + pci_set_dma_mask(pci, VORTEX_DMA_MASK); + + chip = snd_magic_kcalloc(vortex_t, 0, GFP_KERNEL); + if (chip == NULL) + return -ENOMEM; + + chip->card = card; + + // initialize the stuff + chip->pci_dev = pci; + chip->io = pci_resource_start(pci, 0); + chip->vendor = pci->vendor; + chip->device = pci->device; + chip->card = card; + chip->irq = -1; + + // (1) PCI resource allocation + // Get MMIO area + // + if ((err = pci_request_regions(pci, CARD_NAME_SHORT)) != 0) + goto regions_out; + + chip->mmio = + ioremap_nocache(pci_resource_start(pci, 0), + pci_resource_len(pci, 0)); + if (!chip->mmio) { + printk(KERN_ERR "MMIO area remap failed.\n"); + err = -ENOMEM; + goto ioremap_out; + } + + /* Init audio core. + * This must be done before we do request_irq otherwise we can get spurious + * interupts that we do not handle properly and make a mess of things */ + if ((err = vortex_core_init(chip)) != 0) { + printk(KERN_ERR "hw core init failed\n"); + goto core_out; + } + + if ((err = + request_irq(pci->irq, vortex_interrupt, + SA_INTERRUPT | SA_SHIRQ, CARD_NAME_SHORT, + (void *)chip)) != 0) { + printk(KERN_ERR "cannot grab irq\n"); + goto irq_out; + } + chip->irq = pci->irq; + + pci_set_master(pci); + // End of PCI setup. + + // Register alsa root device. + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + goto alloc_out; + } + + *rchip = chip; + + return 0; + + alloc_out: + synchronize_irq(chip->irq); + free_irq(chip->irq, chip); + irq_out: + vortex_core_shutdown(chip); + core_out: + //FIXME: the type of chip->mmio might need to be changed?? + iounmap((void *)chip->mmio); + ioremap_out: + pci_release_regions(chip->pci_dev); + regions_out: + pci_disable_device(chip->pci_dev); + //FIXME: this not the right place to unregister the gameport + vortex_gameport_unregister(chip); + return err; +} + +// constructor -- see "Constructor" sub-section +static int __devinit +snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) +{ + static int dev; + snd_card_t *card; + vortex_t *chip; + int err; + + // (1) + if (dev >= SNDRV_CARDS) + return -ENODEV; + if (!enable[dev]) { + dev++; + return -ENOENT; + } + // (2) + card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); + if (card == NULL) + return -ENOMEM; + + // (3) + if ((err = snd_vortex_create(card, pci, &chip)) < 0) { + snd_card_free(card); + return err; + } + snd_vortex_workaround(pci, pcifix[dev]); + // (4) Alloc components. + // ADB pcm. + if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_ADB, NR_ADB)) < 0) { + snd_card_free(card); + return err; + } +#ifndef CHIP_AU8820 + // ADB SPDIF + if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_SPDIF, 1)) < 0) { + snd_card_free(card); + return err; + } + // A3D + if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_A3D, NR_A3D)) < 0) { + snd_card_free(card); + return err; + } +#endif + /* + // ADB I2S + if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_I2S, 1)) < 0) { + snd_card_free(card); + return err; + } + */ +#ifndef CHIP_AU8810 + // WT pcm. + if ((err = snd_vortex_new_pcm(chip, VORTEX_PCM_WT, NR_WT)) < 0) { + snd_card_free(card); + return err; + } +#endif + // snd_ac97_mixer and Vortex mixer. + if ((err = snd_vortex_mixer(chip)) < 0) { + snd_card_free(card); + return err; + } + if ((err = snd_vortex_midi(chip)) < 0) { + snd_card_free(card); + return err; + } + if ((err = vortex_gameport_register(chip)) < 0) { + snd_card_free(card); + return err; + } +#if 0 + if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_VORTEX_SYNTH, + sizeof(snd_vortex_synth_arg_t), &wave) < 0 + || wave == NULL) { + snd_printk("Can't initialize Aureal wavetable synth\n"); + } else { + snd_vortex_synth_arg_t *arg; + + arg = SNDRV_SEQ_DEVICE_ARGPTR(wave); + strcpy(wave->name, "Aureal Synth"); + arg->hwptr = vortex; + arg->index = 1; + arg->seq_ports = seq_ports[dev]; + arg->max_voices = max_synth_voices[dev]; + } +#endif + + // (5) + strcpy(card->driver, "Aureal Vortex"); + strcpy(card->shortname, CARD_NAME_SHORT); + sprintf(card->longname, "%s at 0x%lx irq %i", + card->shortname, chip->io, chip->irq); + +#ifdef CHIP_AU8830 + { + unsigned char revision; + if ((err = + pci_read_config_byte(pci, PCI_REVISION_ID, + &revision)) < 0) { + snd_card_free(card); + return err; + } + + if (revision != 0xfe && revision != 0xfa) { + printk(KERN_ALERT + "vortex: The revision (%x) of your card has not been seen before.\n", + revision); + printk(KERN_ALERT + "vortex: Please email the results of 'lspci -vv' to openvortex-dev@nongnu.org.\n"); + snd_card_free(card); + err = -ENODEV; + return err; + } + } +#endif + // (6) + if ((err = snd_card_register(card)) < 0) { + snd_card_free(card); + return err; + } + // (7) + pci_set_drvdata(pci, chip); + dev++; + vortex_connect_default(chip, 1); + vortex_enable_int(chip); + return 0; +} + +// destructor -- see "Destructor" sub-section +static void __devexit snd_vortex_remove(struct pci_dev *pci) +{ + vortex_t *vortex = snd_magic_cast(vortex_t, + pci_get_drvdata(pci), return); + + if (vortex) { + // Release ALSA stuff. + snd_card_free(vortex->card); + // Free Vortex struct. + pci_set_drvdata(pci, NULL); + } else + printk("snd_vortex_remove called more than one time!\n"); +} + +// pci_driver definition +static struct pci_driver driver = { + .name = CARD_NAME_SHORT, + .id_table = snd_vortex_ids, + .probe = snd_vortex_probe, + .remove = __devexit_p(snd_vortex_remove), +}; + +// initialization of the module +static int __init alsa_card_vortex_init(void) +{ + int err; + + if ((err = pci_module_init(&driver)) < 0) { +#ifdef MODULE + printk(KERN_ERR "Aureal soundcard not found " + "or device busy\n"); +#endif + return err; + } + return 0; +} + +// clean up the module +static void __exit alsa_card_vortex_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_vortex_init) +module_exit(alsa_card_vortex_exit) diff -Nru a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/au88x0/au88x0.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,286 @@ +/* + Aureal Vortex Soundcard driver. + + IO addr collected from asp4core.vxd: + function address + 0005D5A0 13004 + 00080674 14004 + 00080AFF 12818 + + */ + +#ifndef __SOUND_AU88X0_H +#define __SOUND_AU88X0_H + +#ifdef __KERNEL__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* +#ifndef PCI_VENDOR_ID_AUREAL +#define PCI_VENDOR_ID_AUREAL 0x12eb +#endif +#ifndef PCI_VENDOR_ID_AUREAL_VORTEX +#define PCI_DEVICE_ID_AUREAL_VORTEX 0x0001 +#endif +#ifndef PCI_VENDOR_ID_AUREAL_VORTEX2 +#define PCI_DEVICE_ID_AUREAL_VORTEX2 0x0002 +#endif +#ifndef PCI_VENDOR_ID_AUREAL_ADVANTAGE +#define PCI_DEVICE_ID_AUREAL_ADVANTAGE 0x0003 +#endif +*/ +#endif + +#ifndef CHIP_AU8820 +#include "au88x0_eq.h" +#include "au88x0_a3d.h" +#endif +#ifndef CHIP_AU8810 +#include "au88x0_wt.h" +#endif + +#define VORTEX_DMA_MASK 0xffffffff + +#define hwread(x,y) readl((x)+((y)>>2)) +#define hwwrite(x,y,z) writel((z),(x)+((y)>>2)) + +/* Vortex MPU401 defines. */ +#define MIDI_CLOCK_DIV 0x61 +/* Standart MPU401 defines. */ +#define MPU401_RESET 0xff +#define MPU401_ENTER_UART 0x3f +#define MPU401_ACK 0xfe + +// Get src register value to convert from x to y. +#define SRC_RATIO(x,y) ((((x<<15)/y) + 1)/2) + +/* FIFO software state constants. */ +#define FIFO_STOP 0 +#define FIFO_START 1 +#define FIFO_PAUSE 2 + +/* IRQ flags */ +#define IRQ_ERR_MASK 0x00ff +#define IRQ_FATAL 0x0001 +#define IRQ_PARITY 0x0002 +#define IRQ_REG 0x0004 +#define IRQ_FIFO 0x0008 +#define IRQ_DMA 0x0010 +#define IRQ_PCMOUT 0x0020 /* PCM OUT page crossing */ +#define IRQ_TIMER 0x1000 +#define IRQ_MIDI 0x2000 +#define IRQ_MODEM 0x4000 + +/* ADB Resource */ +#define VORTEX_RESOURCE_DMA 0x00000000 +#define VORTEX_RESOURCE_SRC 0x00000001 +#define VORTEX_RESOURCE_MIXIN 0x00000002 +#define VORTEX_RESOURCE_MIXOUT 0x00000003 +#define VORTEX_RESOURCE_A3D 0x00000004 +#define VORTEX_RESOURCE_LAST 0x00000005 + +/* Check for SDAC bit in "Extended audio ID" AC97 register */ +#define VORTEX_IS_QUAD(x) ((x->codec == NULL) ? 0 : (x->codec->ext_id|0x80)) + +/* PCM devices */ +#define VORTEX_PCM_ADB 0 +#define VORTEX_PCM_SPDIF 1 +#define VORTEX_PCM_A3D 2 +#define VORTEX_PCM_WT 3 +#define VORTEX_PCM_I2S 4 +#define VORTEX_PCM_LAST 5 + +#define MIX_CAPT(x) (vortex->mixcapt[x]) +#define MIX_PLAYB(x) (vortex->mixplayb[x]) +#define MIX_SPDIF(x) (vortex->mixspdif[x]) + +#define NR_WTPB 0x20 /* WT channels per eahc bank. */ + +/* Structs */ +typedef struct { + //int this_08; /* Still unknown */ + int fifo_enabled; /* this_24 */ + int fifo_status; /* this_1c */ + int dma_ctrl; /* this_78 (ADB), this_7c (WT) */ + int dma_unknown; /* this_74 (ADB), this_78 (WT). WDM: +8 */ + int cfg0; + int cfg1; + + int nr_ch; /* Nr of PCM channels in use */ + int type; /* Output type (ac97, a3d, spdif, i2s, dsp) */ + int dma; /* Hardware DMA index. */ + int dir; /* Stream Direction. */ + u32 resources[5]; + + /* Virtual page extender stuff */ + int nr_periods; + int period_bytes; + snd_pcm_sgbuf_t *sgbuf; /* DMA Scatter Gather struct */ + int period_real; + int period_virt; + + snd_pcm_substream_t *substream; +} stream_t; + +typedef struct snd_vortex vortex_t; +struct snd_vortex { + /* ALSA structs. */ + snd_card_t *card; + snd_pcm_t *pcm[VORTEX_PCM_LAST]; + + snd_rawmidi_t *rmidi; /* Legacy Midi interface. */ + ac97_t *codec; + + /* Stream structs. */ + stream_t dma_adb[NR_ADB]; + int spdif_sr; +#ifndef CHIP_AU8810 + stream_t dma_wt[NR_WT]; + wt_voice_t wt_voice[NR_WT]; /* WT register cache. */ + char mixwt[(NR_WT / NR_WTPB) * 6]; /* WT mixin objects */ +#endif + + /* Global resources */ + char mixcapt[2]; + char mixplayb[4]; +#ifndef CHIP_AU8820 + char mixspdif[2]; + char mixa3d[2]; /* mixers which collect all a3d streams. */ + char mixxtlk[2]; /* crosstalk canceler mixer inputs. */ +#endif + u32 fixed_res[5]; + +#ifndef CHIP_AU8820 + /* Hardware equalizer structs */ + eqlzr_t eq; + /* A3D structs */ + a3dsrc_t a3d[NR_A3D]; + /* Xtalk canceler */ + int xt_mode; /* 1: speakers, 0:headphones. */ +#endif + + /* Gameport stuff. */ + struct gameport *gameport; + + /* PCI hardware resources */ + unsigned long io; + unsigned long *mmio; + unsigned int irq; + spinlock_t lock; + + /* PCI device */ + struct pci_dev *pci_dev; + u16 vendor; + u16 device; + u8 rev; +}; + +#define chip_t vortex_t + +/* Functions. */ + +/* SRC */ +static void vortex_adb_setsrc(vortex_t * vortex, int adbdma, + unsigned int cvrt, int dir); + +/* DMA Engines. */ +static void vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma, + snd_pcm_sgbuf_t * sgbuf, int size, + int count); +static void vortex_adbdma_setmode(vortex_t * vortex, int adbdma, int ie, + int dir, int fmt, int d, + unsigned long offset); +static void vortex_adbdma_setstartbuffer(vortex_t * vortex, int adbdma, int sb); +#ifndef CHIP_AU8810 +static void vortex_wtdma_setbuffers(vortex_t * vortex, int wtdma, + snd_pcm_sgbuf_t * sgbuf, int size, + int count); +static void vortex_wtdma_setmode(vortex_t * vortex, int wtdma, int ie, int fmt, int d, /*int e, */ + unsigned long offset); +static void vortex_wtdma_setstartbuffer(vortex_t * vortex, int wtdma, int sb); +#endif + +static void vortex_adbdma_startfifo(vortex_t * vortex, int adbdma); +//static void vortex_adbdma_stopfifo(vortex_t *vortex, int adbdma); +static void vortex_adbdma_pausefifo(vortex_t * vortex, int adbdma); +static void vortex_adbdma_resumefifo(vortex_t * vortex, int adbdma); +static int inline vortex_adbdma_getlinearpos(vortex_t * vortex, int adbdma); + +#ifndef CHIP_AU8810 +static void vortex_wtdma_startfifo(vortex_t * vortex, int wtdma); +static void vortex_wtdma_stopfifo(vortex_t * vortex, int wtdma); +static void vortex_wtdma_pausefifo(vortex_t * vortex, int wtdma); +static void vortex_wtdma_resumefifo(vortex_t * vortex, int wtdma); +static int inline vortex_wtdma_getlinearpos(vortex_t * vortex, int wtdma); +#endif + +/* global stuff. */ +static void vortex_codec_init(vortex_t * vortex); +static void vortex_codec_write(ac97_t * codec, unsigned short addr, + unsigned short data); +static unsigned short vortex_codec_read(ac97_t * codec, unsigned short addr); +static void vortex_spdif_init(vortex_t * vortex, int spdif_sr, int spdif_mode); + +static int vortex_core_init(vortex_t * card); +static int vortex_core_shutdown(vortex_t * card); +static void vortex_enable_int(vortex_t * card); +static irqreturn_t vortex_interrupt(int irq, void *dev_id, + struct pt_regs *regs); +static int vortex_alsafmt_aspfmt(int alsafmt); + +/* Connection stuff. */ +static void vortex_connect_default(vortex_t * vortex, int en); +static int vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, + int dir, int type); +static char vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, + int restype); +#ifndef CHIP_AU8810 +static int vortex_wt_allocroute(vortex_t * vortex, int dma, int nr_ch); +static void vortex_wt_connect(vortex_t * vortex, int en); +static void vortex_wt_init(vortex_t * vortex); +#endif + +static void vortex_route(vortex_t * vortex, int en, unsigned char channel, + unsigned char source, unsigned char dest); +#if 0 +static void vortex_routes(vortex_t * vortex, int en, unsigned char channel, + unsigned char source, unsigned char dest0, + unsigned char dest1); +#endif +static void vortex_connection_mixin_mix(vortex_t * vortex, int en, + unsigned char mixin, + unsigned char mix, int a); +static void vortex_mix_setinputvolumebyte(vortex_t * vortex, + unsigned char mix, int mixin, + unsigned char vol); +static void vortex_mix_setvolumebyte(vortex_t * vortex, unsigned char mix, + unsigned char vol); + +/* A3D functions. */ +#ifndef CHIP_AU8820 +static void vortex_Vort3D(vortex_t * v, int en); +static void vortex_Vort3D_connect(vortex_t * vortex, int en); +static void vortex_Vort3D_InitializeSource(a3dsrc_t * a, int en); +#endif + +/* Driver stuff. */ +static int __devinit vortex_gameport_register(vortex_t * card); +static int __devexit vortex_gameport_unregister(vortex_t * card); +#ifndef CHIP_AU8820 +static int __devinit vortex_eq_init(vortex_t * vortex); +static int __devexit vortex_eq_free(vortex_t * vortex); +#endif +/* ALSA stuff. */ +static int __devinit snd_vortex_new_pcm(vortex_t * vortex, int idx, int nr); +static int __devinit snd_vortex_mixer(vortex_t * vortex); +static int __devinit snd_vortex_midi(vortex_t * vortex); +#endif diff -Nru a/sound/pci/au88x0/au88x0_a3d.c b/sound/pci/au88x0/au88x0_a3d.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/au88x0/au88x0_a3d.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,912 @@ +/*************************************************************************** + * au88x0_a3d.c + * + * Fri Jul 18 14:16:22 2003 + * Copyright 2003 mjander + * mjander@users.sourceforge.net + * + * A3D. You may think i'm crazy, but this may work someday. Who knows... + ****************************************************************************/ + +/* + * 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "au88x0_a3d.h" +#include "au88x0_a3ddata.c" +#include "au88x0_xtalk.h" +#include "au88x0.h" + +static void +a3dsrc_SetTimeConsts(a3dsrc_t * a, short HrtfTrack, short ItdTrack, + short GTrack, short CTrack) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + hwwrite(vortex->mmio, + a3d_addrA(a->slice, a->source, A3D_A_HrtfTrackTC), HrtfTrack); + hwwrite(vortex->mmio, + a3d_addrA(a->slice, a->source, A3D_A_ITDTrackTC), ItdTrack); + hwwrite(vortex->mmio, + a3d_addrA(a->slice, a->source, A3D_A_GainTrackTC), GTrack); + hwwrite(vortex->mmio, + a3d_addrA(a->slice, a->source, A3D_A_CoeffTrackTC), CTrack); +} + +#if 0 +static void +a3dsrc_GetTimeConsts(a3dsrc_t * a, short *HrtfTrack, short *ItdTrack, + short *GTrack, short *CTrack) +{ + // stub! +} + +#endif +/* Atmospheric absorbtion. */ + +static void +a3dsrc_SetAtmosTarget(a3dsrc_t * a, short aa, short b, short c, short d, + short e) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + hwwrite(vortex->mmio, + a3d_addrB(a->slice, a->source, A3D_B_A21Target), + (e << 0x10) | d); + hwwrite(vortex->mmio, + a3d_addrB(a->slice, a->source, A3D_B_B10Target), + (b << 0x10) | aa); + hwwrite(vortex->mmio, + a3d_addrB(a->slice, a->source, A3D_B_B2Target), c); +} + +static void +a3dsrc_SetAtmosCurrent(a3dsrc_t * a, short aa, short b, short c, short d, + short e) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + hwwrite(vortex->mmio, + a3d_addrB(a->slice, a->source, A3D_B_A12Current), + (e << 0x10) | d); + hwwrite(vortex->mmio, + a3d_addrB(a->slice, a->source, A3D_B_B01Current), + (b << 0x10) | aa); + hwwrite(vortex->mmio, + a3d_addrB(a->slice, a->source, A3D_B_B2Current), c); +} + +static void +a3dsrc_SetAtmosState(a3dsrc_t * a, short x1, short x2, short y1, short y2) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_x1), x1); + hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_x2), x2); + hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_y1), y1); + hwwrite(vortex->mmio, a3d_addrA(a->slice, a->source, A3D_A_y2), y2); +} + +#if 0 +static void +a3dsrc_GetAtmosTarget(a3dsrc_t * a, short *aa, short *b, short *c, + short *d, short *e) +{ +} +static void +a3dsrc_GetAtmosCurrent(a3dsrc_t * a, short *bb01, short *ab01, short *b2, + short *aa12, short *ba12) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + *aa12 = + hwread(vortex->mmio, + a3d_addrA(a->slice, a->source, A3D_A_A12Current)); + *ba12 = + hwread(vortex->mmio, + a3d_addrB(a->slice, a->source, A3D_B_A12Current)); + *ab01 = + hwread(vortex->mmio, + a3d_addrA(a->slice, a->source, A3D_A_B01Current)); + *bb01 = + hwread(vortex->mmio, + a3d_addrB(a->slice, a->source, A3D_B_B01Current)); + *b2 = + hwread(vortex->mmio, + a3d_addrA(a->slice, a->source, A3D_A_B2Current)); +} + +static void +a3dsrc_GetAtmosState(a3dsrc_t * a, short *x1, short *x2, short *y1, short *y2) +{ + +} + +#endif +/* HRTF */ + +static void +a3dsrc_SetHrtfTarget(a3dsrc_t * a, a3d_Hrtf_t const aa, a3d_Hrtf_t const b) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + int i; + + for (i = 0; i < HRTF_SZ; i++) + hwwrite(vortex->mmio, + a3d_addrB(a->slice, a->source, + A3D_B_HrtfTarget) + (i << 2), + (b[i] << 0x10) | aa[i]); +} + +static void +a3dsrc_SetHrtfCurrent(a3dsrc_t * a, a3d_Hrtf_t const aa, a3d_Hrtf_t const b) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + int i; + + for (i = 0; i < HRTF_SZ; i++) + hwwrite(vortex->mmio, + a3d_addrB(a->slice, a->source, + A3D_B_HrtfCurrent) + (i << 2), + (b[i] << 0x10) | aa[i]); +} + +static void +a3dsrc_SetHrtfState(a3dsrc_t * a, a3d_Hrtf_t const aa, a3d_Hrtf_t const b) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + int i; + + for (i = 0; i < HRTF_SZ; i++) + hwwrite(vortex->mmio, + a3d_addrB(a->slice, a->source, + A3D_B_HrtfDelayLine) + (i << 2), + (b[i] << 0x10) | aa[i]); +} + +static void a3dsrc_SetHrtfOutput(a3dsrc_t * a, short left, short right) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + hwwrite(vortex->mmio, + a3d_addrA(a->slice, a->source, A3D_A_HrtfOutL), left); + hwwrite(vortex->mmio, + a3d_addrA(a->slice, a->source, A3D_A_HrtfOutR), right); +} + +#if 0 +static void a3dsrc_GetHrtfTarget(a3dsrc_t * a, a3d_Hrtf_t aa, a3d_Hrtf_t b) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + int i; + + for (i = 0; i < HRTF_SZ; i++) + aa[i] = + hwread(vortex->mmio, + a3d_addrA(a->slice, a->source, + A3D_A_HrtfTarget + (i << 2))); + for (i = 0; i < HRTF_SZ; i++) + b[i] = + hwread(vortex->mmio, + a3d_addrB(a->slice, a->source, + A3D_B_HrtfTarget + (i << 2))); +} + +static void a3dsrc_GetHrtfCurrent(a3dsrc_t * a, a3d_Hrtf_t aa, a3d_Hrtf_t b) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + int i; + + for (i = 0; i < HRTF_SZ; i++) + aa[i] = + hwread(vortex->mmio, + a3d_addrA(a->slice, a->source, + A3D_A_HrtfCurrent + (i << 2))); + for (i = 0; i < HRTF_SZ; i++) + b[i] = + hwread(vortex->mmio, + a3d_addrB(a->slice, a->source, + A3D_B_HrtfCurrent + (i << 2))); +} + +static void a3dsrc_GetHrtfState(a3dsrc_t * a, a3d_Hrtf_t aa, a3d_Hrtf_t b) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + int i; + // FIXME: verify this! + for (i = 0; i < HRTF_SZ; i++) + aa[i] = + hwread(vortex->mmio, + a3d_addrA(a->slice, a->source, + A3D_A_HrtfDelayLine + (i << 2))); + for (i = 0; i < HRTF_SZ; i++) + b[i] = + hwread(vortex->mmio, + a3d_addrB(a->slice, a->source, + A3D_B_HrtfDelayLine + (i << 2))); +} + +static void a3dsrc_GetHrtfOutput(a3dsrc_t * a, short *left, short *right) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + *left = + hwread(vortex->mmio, + a3d_addrA(a->slice, a->source, A3D_A_HrtfOutL)); + *right = + hwread(vortex->mmio, + a3d_addrA(a->slice, a->source, A3D_A_HrtfOutR)); +} + +#endif + +/* Interaural Time Difference. + * "The other main clue that humans use to locate sounds, is called + * Interaural Time Difference (ITD). The differences in distance from + * the sound source to a listeners ears means that the sound will + * reach one ear slightly before the other....", found somewhere with google.*/ +static void a3dsrc_SetItdTarget(a3dsrc_t * a, short litd, short ritd) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + + if (litd < 0) + litd = 0; + if (litd > 0x57FF) + litd = 0x57FF; + if (ritd < 0) + ritd = 0; + if (ritd > 0x57FF) + ritd = 0x57FF; + hwwrite(vortex->mmio, + a3d_addrB(a->slice, a->source, A3D_B_ITDTarget), + (ritd << 0x10) | litd); + //hwwrite(vortex->mmio, addr(0x191DF+5, this04, this08), (ritd<<0x10)|litd); +} + +static void a3dsrc_SetItdCurrent(a3dsrc_t * a, short litd, short ritd) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + + if (litd < 0) + litd = 0; + if (litd > 0x57FF) + litd = 0x57FF; + if (ritd < 0) + ritd = 0; + if (ritd > 0x57FF) + ritd = 0x57FF; + hwwrite(vortex->mmio, + a3d_addrB(a->slice, a->source, A3D_B_ITDCurrent), + (ritd << 0x10) | litd); + //hwwrite(vortex->mmio, addr(0x191DF+1, this04, this08), (ritd<<0x10)|litd); +} + +static void a3dsrc_SetItdDline(a3dsrc_t * a, a3d_ItdDline_t const dline) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + int i; + /* 45 != 40 -> Check this ! */ + for (i = 0; i < DLINE_SZ; i++) + hwwrite(vortex->mmio, + a3d_addrA(a->slice, a->source, + A3D_A_ITDDelayLine) + (i << 2), dline[i]); +} + +#if 0 +static void a3dsrc_GetItdTarget(a3dsrc_t * a, short *litd, short *ritd) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + *ritd = + hwread(vortex->mmio, + a3d_addrA(a->slice, a->source, A3D_A_ITDTarget)); + *litd = + hwread(vortex->mmio, + a3d_addrB(a->slice, a->source, A3D_B_ITDTarget)); +} + +static void a3dsrc_GetItdCurrent(a3dsrc_t * a, short *litd, short *ritd) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + + *ritd = + hwread(vortex->mmio, + a3d_addrA(a->slice, a->source, A3D_A_ITDCurrent)); + *litd = + hwread(vortex->mmio, + a3d_addrB(a->slice, a->source, A3D_B_ITDCurrent)); +} + +static void a3dsrc_GetItdDline(a3dsrc_t * a, a3d_ItdDline_t dline) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + int i; + + for (i = 0; i < DLINE_SZ; i++) + dline[i] = + hwread(vortex->mmio, + a3d_addrA(a->slice, a->source, + A3D_A_ITDDelayLine + (i << 2))); +} + +#endif +/* This is may be used for ILD Interaural Level Difference. */ + +static void a3dsrc_SetGainTarget(a3dsrc_t * a, short left, short right) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + hwwrite(vortex->mmio, + a3d_addrB(a->slice, a->source, A3D_B_GainTarget), + (right << 0x10) | left); +} + +static void a3dsrc_SetGainCurrent(a3dsrc_t * a, short left, short right) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + hwwrite(vortex->mmio, + a3d_addrB(a->slice, a->source, A3D_B_GainCurrent), + (right << 0x10) | left); +} + +#if 0 +static void a3dsrc_GetGainTarget(a3dsrc_t * a, short *left, short *right) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + *right = + hwread(vortex->mmio, + a3d_addrA(a->slice, a->source, A3D_A_GainTarget)); + *left = + hwread(vortex->mmio, + a3d_addrB(a->slice, a->source, A3D_B_GainTarget)); +} + +static void a3dsrc_GetGainCurrent(a3dsrc_t * a, short *left, short *right) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + *right = + hwread(vortex->mmio, + a3d_addrA(a->slice, a->source, A3D_A_GainCurrent)); + *left = + hwread(vortex->mmio, + a3d_addrB(a->slice, a->source, A3D_B_GainCurrent)); +} + +/* CA3dIO this func seems to be inlined all over this place. */ +static void CA3dIO_WriteReg(a3dsrc_t * a, unsigned long addr, short aa, short b) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + hwwrite(vortex->mmio, addr, (aa << 0x10) | b); +} + +#endif +/* Generic A3D stuff */ + +static void a3dsrc_SetA3DSampleRate(a3dsrc_t * a, int sr) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + int esp0 = 0; + + esp0 = (((esp0 & 0x7fffffff) | 0xB8000000) & 0x7) | ((sr & 0x1f) << 3); + hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd), esp0); + //hwwrite(vortex->mmio, 0x19C38 + (this08<<0xd), esp0); +} + +static void a3dsrc_EnableA3D(a3dsrc_t * a) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd), + 0xF0000001); + //hwwrite(vortex->mmio, 0x19C38 + (this08<<0xd), 0xF0000001); +} + +static void a3dsrc_DisableA3D(a3dsrc_t * a) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd), + 0xF0000000); +} + +static void a3dsrc_SetA3DControlReg(a3dsrc_t * a, unsigned long ctrl) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + hwwrite(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd), ctrl); +} + +static void a3dsrc_SetA3DPointerReg(a3dsrc_t * a, unsigned long ptr) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + hwwrite(vortex->mmio, A3D_SLICE_Pointers + ((a->slice) << 0xd), ptr); +} + +#if 0 +static void a3dsrc_GetA3DSampleRate(a3dsrc_t * a, int *sr) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + *sr = ((hwread(vortex->mmio, A3D_SLICE_Control + (a->slice << 0xd)) + >> 3) & 0x1f); + //*sr = ((hwread(vortex->mmio, 0x19C38 + (this08<<0xd))>>3)&0x1f); +} + +static void a3dsrc_GetA3DControlReg(a3dsrc_t * a, unsigned long *ctrl) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + *ctrl = hwread(vortex->mmio, A3D_SLICE_Control + ((a->slice) << 0xd)); +} + +static void a3dsrc_GetA3DPointerReg(a3dsrc_t * a, unsigned long *ptr) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + *ptr = hwread(vortex->mmio, A3D_SLICE_Pointers + ((a->slice) << 0xd)); +} + +#endif +static void a3dsrc_ZeroSliceIO(a3dsrc_t * a) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + int i; + + for (i = 0; i < 8; i++) + hwwrite(vortex->mmio, + A3D_SLICE_VDBDest + + ((((a->slice) << 0xb) + i) << 2), 0); + for (i = 0; i < 4; i++) + hwwrite(vortex->mmio, + A3D_SLICE_VDBSource + + ((((a->slice) << 0xb) + i) << 2), 0); +} + +/* Reset Single A3D source. */ +static void a3dsrc_ZeroState(a3dsrc_t * a) +{ + + //printk("vortex: ZeroState slice: %d, source %d\n", a->slice, a->source); + + a3dsrc_SetAtmosState(a, 0, 0, 0, 0); + a3dsrc_SetHrtfState(a, A3dHrirZeros, A3dHrirZeros); + a3dsrc_SetItdDline(a, A3dItdDlineZeros); + a3dsrc_SetHrtfOutput(a, 0, 0); + a3dsrc_SetTimeConsts(a, 0, 0, 0, 0); + + a3dsrc_SetAtmosCurrent(a, 0, 0, 0, 0, 0); + a3dsrc_SetAtmosTarget(a, 0, 0, 0, 0, 0); + a3dsrc_SetItdCurrent(a, 0, 0); + a3dsrc_SetItdTarget(a, 0, 0); + a3dsrc_SetGainCurrent(a, 0, 0); + a3dsrc_SetGainTarget(a, 0, 0); + + a3dsrc_SetHrtfCurrent(a, A3dHrirZeros, A3dHrirZeros); + a3dsrc_SetHrtfTarget(a, A3dHrirZeros, A3dHrirZeros); +} + +/* Reset entire A3D engine */ +static void a3dsrc_ZeroStateA3D(a3dsrc_t * a) +{ + int i, var, var2; + + if ((a->vortex) == NULL) { + printk("vortex: ZeroStateA3D: ERROR: a->vortex is NULL\n"); + return; + } + + a3dsrc_SetA3DControlReg(a, 0); + a3dsrc_SetA3DPointerReg(a, 0); + + var = a->slice; + var2 = a->source; + for (i = 0; i < 4; i++) { + a->slice = i; + a3dsrc_ZeroSliceIO(a); + //a3dsrc_ZeroState(a); + } + a->source = var2; + a->slice = var; +} + +/* Program A3D block as pass through */ +static void a3dsrc_ProgramPipe(a3dsrc_t * a) +{ + a3dsrc_SetTimeConsts(a, 0, 0, 0, 0); + a3dsrc_SetAtmosCurrent(a, 0, 0x4000, 0, 0, 0); + a3dsrc_SetAtmosTarget(a, 0x4000, 0, 0, 0, 0); + a3dsrc_SetItdCurrent(a, 0, 0); + a3dsrc_SetItdTarget(a, 0, 0); + a3dsrc_SetGainCurrent(a, 0x7fff, 0x7fff); + a3dsrc_SetGainTarget(a, 0x7fff, 0x7fff); + + /* SET HRTF HERE */ + + /* Single spike leads to identity transfer function. */ + a3dsrc_SetHrtfCurrent(a, A3dHrirImpulse, A3dHrirImpulse); + a3dsrc_SetHrtfTarget(a, A3dHrirImpulse, A3dHrirImpulse); + + /* Test: Sounds saturated. */ + //a3dsrc_SetHrtfCurrent(a, A3dHrirSatTest, A3dHrirSatTest); + //a3dsrc_SetHrtfTarget(a, A3dHrirSatTest, A3dHrirSatTest); +} + +/* VDB = Vortex audio Dataflow Bus */ +#if 0 +static void a3dsrc_ClearVDBData(a3dsrc_t * a, unsigned long aa) +{ + vortex_t *vortex = (vortex_t *) (a->vortex); + + // ((aa >> 2) << 8) - (aa >> 2) + hwwrite(vortex->mmio, + a3d_addrS(a->slice, A3D_SLICE_VDBDest) + (a->source << 2), 0); + hwwrite(vortex->mmio, + a3d_addrS(a->slice, + A3D_SLICE_VDBDest + 4) + (a->source << 2), 0); + /* + hwwrite(vortex->mmio, 0x19c00 + (((aa>>2)*255*4)+aa)*8, 0); + hwwrite(vortex->mmio, 0x19c04 + (((aa>>2)*255*4)+aa)*8, 0); + */ +} +#endif + +/* A3D HwSource stuff. */ + +static void vortex_A3dSourceHw_Initialize(vortex_t * v, int source, int slice) +{ + a3dsrc_t *a3dsrc = &(v->a3d[source + (slice * 4)]); + //a3dsrc_t *a3dsrc = &(v->a3d[source + (slice*4)]); + + a3dsrc->vortex = (void *)v; + a3dsrc->source = source; /* source */ + a3dsrc->slice = slice; /* slice */ + a3dsrc_ZeroState(a3dsrc); + /* Added by me. */ + a3dsrc_SetA3DSampleRate(a3dsrc, 0x11); +} + +int Vort3DRend_Initialize(vortex_t * v, unsigned short mode) +{ + v->xt_mode = mode; /* this_14 */ + + vortex_XtalkHw_init(v); + vortex_XtalkHw_SetGains(v, asXtalkGainsAllChan); + switch (v->xt_mode) { + case XT_SPEAKER0: + vortex_XtalkHw_ProgramXtalkNarrow(v); + break; + case XT_SPEAKER1: + vortex_XtalkHw_ProgramXtalkWide(v); + break; + default: + case XT_HEADPHONE: + vortex_XtalkHw_ProgramPipe(v); + break; + case XT_DIAMOND: + vortex_XtalkHw_ProgramDiamondXtalk(v); + break; + } + vortex_XtalkHw_SetSampleRate(v, 0x11); + vortex_XtalkHw_Enable(v); + return 0; +} + +/* 3D Sound entry points. */ + +static int vortex_a3d_register_controls(vortex_t * vortex); +static void vortex_a3d_unregister_controls(vortex_t * vortex); +/* A3D base support init/shudown */ +static void vortex_Vort3D(vortex_t * v, int en) +{ + int i; + if (en) { + Vort3DRend_Initialize(v, XT_HEADPHONE); + for (i = 0; i < NR_A3D; i++) { + vortex_A3dSourceHw_Initialize(v, i % 4, i >> 2); + a3dsrc_ZeroStateA3D(&(v->a3d[0])); + } + } else { + vortex_XtalkHw_Disable(v); + } + /* Register ALSA controls */ + if (en) { + vortex_a3d_register_controls(v); + } else { + vortex_a3d_unregister_controls(v); + } +} + +/* Make A3D subsystem connections. */ +static void vortex_Vort3D_connect(vortex_t * v, int en) +{ + int i; +#if 1 + /* Alloc Xtalk mixin resources */ + v->mixxtlk[0] = + vortex_adb_checkinout(v, v->fixed_res, en, VORTEX_RESOURCE_MIXIN); + if (v->mixxtlk[0] < 0) { + printk + ("vortex: vortex_Vort3D: ERROR: not enough free mixer resources.\n"); + return; + } + v->mixxtlk[1] = + vortex_adb_checkinout(v, v->fixed_res, en, VORTEX_RESOURCE_MIXIN); + if (v->mixxtlk[1] < 0) { + printk + ("vortex: vortex_Vort3D: ERROR: not enough free mixer resources.\n"); + return; + } +#endif + + /* Connect A3D -> XTALK */ + for (i = 0; i < 4; i++) { + // 2 outputs per each A3D slice. + vortex_route(v, en, 0x11, ADB_A3DOUT(i * 2), ADB_XTALKIN(i)); + vortex_route(v, en, 0x11, ADB_A3DOUT(i * 2) + 1, ADB_XTALKIN(5 + i)); + } +#if 0 + vortex_route(v, en, 0x11, ADB_XTALKOUT(0), ADB_EQIN(2)); + vortex_route(v, en, 0x11, ADB_XTALKOUT(1), ADB_EQIN(3)); +#else + /* Connect XTalk -> mixer */ + vortex_route(v, en, 0x11, ADB_XTALKOUT(0), ADB_MIXIN(v->mixxtlk[0])); + vortex_route(v, en, 0x11, ADB_XTALKOUT(1), ADB_MIXIN(v->mixxtlk[1])); + vortex_connection_mixin_mix(v, en, v->mixxtlk[0], v->mixplayb[0], 0); + vortex_connection_mixin_mix(v, en, v->mixxtlk[1], v->mixplayb[1], 0); + vortex_mix_setinputvolumebyte(v, v->mixplayb[0], v->mixxtlk[0], + en ? MIX_DEFIGAIN : VOL_MIN); + vortex_mix_setinputvolumebyte(v, v->mixplayb[1], v->mixxtlk[1], + en ? MIX_DEFIGAIN : VOL_MIN); + if (VORTEX_IS_QUAD(v)) { + vortex_connection_mixin_mix(v, en, v->mixxtlk[0], + v->mixplayb[2], 0); + vortex_connection_mixin_mix(v, en, v->mixxtlk[1], + v->mixplayb[3], 0); + vortex_mix_setinputvolumebyte(v, v->mixplayb[2], + v->mixxtlk[0], + en ? MIX_DEFIGAIN : VOL_MIN); + vortex_mix_setinputvolumebyte(v, v->mixplayb[3], + v->mixxtlk[1], + en ? MIX_DEFIGAIN : VOL_MIN); + } +#endif +} + +/* Initialize one single A3D source. */ +static void vortex_Vort3D_InitializeSource(a3dsrc_t * a, int en) +{ + if (a->vortex == NULL) { + printk + ("vortex: Vort3D_InitializeSource: A3D source not initialized\n"); + return; + } + if (en) { + a3dsrc_ProgramPipe(a); + a3dsrc_SetA3DSampleRate(a, 0x11); + a3dsrc_SetTimeConsts(a, HrtfTCDefault, + ItdTCDefault, GainTCDefault, + CoefTCDefault); + /* Remark: zero gain is muted. */ + //a3dsrc_SetGainTarget(a,0,0); + //a3dsrc_SetGainCurrent(a,0,0); + a3dsrc_EnableA3D(a); + } else { + a3dsrc_DisableA3D(a); + a3dsrc_ZeroState(a); + } +} + +/* Conversion of coordinates into 3D parameters. */ + +static void vortex_a3d_coord2hrtf(a3d_Hrtf_t hrtf, int *coord) +{ + /* FIXME: implement this. */ + +} +static void vortex_a3d_coord2itd(a3d_Itd_t itd, int *coord) +{ + /* FIXME: implement this. */ + +} +static void vortex_a3d_coord2ild(a3d_LRGains_t ild, int left, int right) +{ + /* FIXME: implement this. */ + +} +static void vortex_a3d_translate_filter(a3d_atmos_t filter, int *params) +{ + /* FIXME: implement this. */ + +} + +/* ALSA control interface. */ + +static int +snd_vortex_a3d_hrtf_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 6; + uinfo->value.integer.min = 0x00000000; + uinfo->value.integer.max = 0xffffffff; + return 0; +} +static int +snd_vortex_a3d_itd_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0x00000000; + uinfo->value.integer.max = 0xffffffff; + return 0; +} +static int +snd_vortex_a3d_ild_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0x00000000; + uinfo->value.integer.max = 0xffffffff; + return 0; +} +static int +snd_vortex_a3d_filter_info(snd_kcontrol_t * + kcontrol, snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 4; + uinfo->value.integer.min = 0x00000000; + uinfo->value.integer.max = 0xffffffff; + return 0; +} + +static int +snd_vortex_a3d_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + //a3dsrc_t *a = (a3dsrc_t*)(kcontrol->private_value); + /* No read yet. Would this be really useable/needed ? */ + + return 0; +} + +static int +snd_vortex_a3d_hrtf_put(snd_kcontrol_t * + kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + a3dsrc_t *a = (a3dsrc_t *) (kcontrol->private_value); + int changed = 1, i; + int coord[6]; + for (i = 0; i < 6; i++) + coord[i] = ucontrol->value.integer.value[i]; + /* Translate orientation coordinates to a3d params. */ + vortex_a3d_coord2hrtf(a->hrtf[0], coord); + vortex_a3d_coord2hrtf(a->hrtf[1], coord); + a3dsrc_SetHrtfTarget(a, a->hrtf[0], a->hrtf[1]); + a3dsrc_SetHrtfCurrent(a, a->hrtf[0], a->hrtf[1]); + return changed; +} + +static int +snd_vortex_a3d_itd_put(snd_kcontrol_t * + kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + a3dsrc_t *a = (a3dsrc_t *) (kcontrol->private_value); + int coord[6]; + int i, changed = 1; + for (i = 0; i < 6; i++) + coord[i] = ucontrol->value.integer.value[i]; + /* Translate orientation coordinates to a3d params. */ + vortex_a3d_coord2itd(a->hrtf[0], coord); + vortex_a3d_coord2itd(a->hrtf[1], coord); + /* Inter aural time difference. */ + a3dsrc_SetItdTarget(a, a->itd[0], a->itd[1]); + a3dsrc_SetItdCurrent(a, a->itd[0], a->itd[1]); + a3dsrc_SetItdDline(a, a->dline); + return changed; +} + +static int +snd_vortex_a3d_ild_put(snd_kcontrol_t * + kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + a3dsrc_t *a = (a3dsrc_t *) (kcontrol->private_value); + int changed = 1; + int l, r; + /* There may be some scale tranlation needed here. */ + l = ucontrol->value.integer.value[0]; + r = ucontrol->value.integer.value[1]; + vortex_a3d_coord2ild(a->ild, l, r); + /* Left Right panning. */ + a3dsrc_SetGainTarget(a, l, r); + a3dsrc_SetGainCurrent(a, l, r); + return changed; +} + +static int +snd_vortex_a3d_filter_put(snd_kcontrol_t + * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + a3dsrc_t *a = (a3dsrc_t *) (kcontrol->private_value); + int i, changed = 1; + int params[6]; + for (i = 0; i < 6; i++) + params[i] = ucontrol->value.integer.value[i]; + /* Translate generic filter params to a3d filter params. */ + vortex_a3d_translate_filter(a->filter, params); + /* Atmospheric absorbtion and filtering. */ + a3dsrc_SetAtmosTarget(a, a->filter[0], + a->filter[1], a->filter[2], + a->filter[3], a->filter[4]); + a3dsrc_SetAtmosCurrent(a, a->filter[0], + a->filter[1], a->filter[2], + a->filter[3], a->filter[4]); + return changed; +} + +static snd_kcontrol_new_t vortex_a3d_kcontrol __devinitdata = { + .iface = SNDRV_CTL_ELEM_IFACE_PCM,.name = + "Playback PCM advanced processing",.index = + 0,.access = + SNDRV_CTL_ELEM_ACCESS_READWRITE,.private_value = + 0,.info = snd_vortex_a3d_hrtf_info,.get = + snd_vortex_a3d_get,.put = snd_vortex_a3d_hrtf_put +}; + +/* Control (un)registration. */ +static int vortex_a3d_register_controls(vortex_t * vortex) +{ + snd_kcontrol_t *kcontrol; + int err, i; + /* HRTF controls. */ + for (i = 0; i < NR_A3D; i++) { + if ((kcontrol = + snd_ctl_new1(&vortex_a3d_kcontrol, vortex)) == NULL) + return -ENOMEM; + kcontrol->private_value = (int)&(vortex->a3d[i]); + kcontrol->id.numid = CTRLID_HRTF; + kcontrol->info = snd_vortex_a3d_hrtf_info; + kcontrol->put = snd_vortex_a3d_hrtf_put; + if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0) + return err; + } + /* ITD controls. */ + for (i = 0; i < NR_A3D; i++) { + if ((kcontrol = + snd_ctl_new1(&vortex_a3d_kcontrol, vortex)) == NULL) + return -ENOMEM; + kcontrol->private_value = (int)&(vortex->a3d[i]); + kcontrol->id.numid = CTRLID_ITD; + kcontrol->info = snd_vortex_a3d_itd_info; + kcontrol->put = snd_vortex_a3d_itd_put; + if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0) + return err; + } + /* ILD (gains) controls. */ + for (i = 0; i < NR_A3D; i++) { + if ((kcontrol = + snd_ctl_new1(&vortex_a3d_kcontrol, vortex)) == NULL) + return -ENOMEM; + kcontrol->private_value = (int)&(vortex->a3d[i]); + kcontrol->id.numid = CTRLID_GAINS; + kcontrol->info = snd_vortex_a3d_ild_info; + kcontrol->put = snd_vortex_a3d_ild_put; + if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0) + return err; + } + /* Filter controls. */ + for (i = 0; i < NR_A3D; i++) { + if ((kcontrol = + snd_ctl_new1(&vortex_a3d_kcontrol, vortex)) == NULL) + return -ENOMEM; + kcontrol->private_value = (int)&(vortex->a3d[i]); + kcontrol->id.numid = CTRLID_FILTER; + kcontrol->info = snd_vortex_a3d_filter_info; + kcontrol->put = snd_vortex_a3d_filter_put; + if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0) + return err; + } + return 0; +} + +static void vortex_a3d_unregister_controls(vortex_t * vortex) +{ + +} + +/* End of File*/ diff -Nru a/sound/pci/au88x0/au88x0_a3d.h b/sound/pci/au88x0/au88x0_a3d.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/au88x0/au88x0_a3d.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,123 @@ +/*************************************************************************** + * au88x0_a3d.h + * + * Fri Jul 18 14:16:03 2003 + * Copyright 2003 mjander + * mjander@users.sourceforge.net + ****************************************************************************/ + +/* + * 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _AU88X0_A3D_H +#define _AU88X0_A3D_H + +//#include + +#define HRTF_SZ 0x38 +#define DLINE_SZ 0x28 + +#define CTRLID_HRTF 1 +#define CTRLID_ITD 2 +#define CTRLID_ILD 4 +#define CTRLID_FILTER 8 +#define CTRLID_GAINS 16 + +/* 3D parameter structs */ +typedef unsigned short int a3d_Hrtf_t[HRTF_SZ]; +typedef unsigned short int a3d_ItdDline_t[DLINE_SZ]; +typedef unsigned short int a3d_atmos_t[5]; +typedef unsigned short int a3d_LRGains_t[2]; +typedef unsigned short int a3d_Itd_t[2]; +typedef unsigned short int a3d_Ild_t[2]; + +typedef struct { + void *vortex; // Formerly CAsp4HwIO*, now vortex_t*. + unsigned int source; /* this_04 */ + unsigned int slice; /* this_08 */ + a3d_Hrtf_t hrtf[2]; + a3d_Itd_t itd; + a3d_Ild_t ild; + a3d_ItdDline_t dline; + a3d_atmos_t filter; +} a3dsrc_t; + +/* First Register bank */ + +#define A3D_A_HrtfCurrent 0x18000 /* 56 ULONG */ +#define A3D_A_GainCurrent 0x180E0 +#define A3D_A_GainTarget 0x180E4 +#define A3D_A_A12Current 0x180E8 /* Atmospheric current. */ +#define A3D_A_A21Target 0x180EC /* Atmospheric target */ +#define A3D_A_B01Current 0x180F0 /* Atmospheric current */ +#define A3D_A_B10Target 0x180F4 /* Atmospheric target */ +#define A3D_A_B2Current 0x180F8 /* Atmospheric current */ +#define A3D_A_B2Target 0x180FC /* Atmospheric target */ +#define A3D_A_HrtfTarget 0x18100 /* 56 ULONG */ +#define A3D_A_ITDCurrent 0x181E0 +#define A3D_A_ITDTarget 0x181E4 +#define A3D_A_HrtfDelayLine 0x181E8 /* 56 ULONG */ +#define A3D_A_ITDDelayLine 0x182C8 /* 40/45 ULONG */ +#define A3D_A_HrtfTrackTC 0x1837C /* Time Constants */ +#define A3D_A_GainTrackTC 0x18380 +#define A3D_A_CoeffTrackTC 0x18384 +#define A3D_A_ITDTrackTC 0x18388 +#define A3D_A_x1 0x1838C +#define A3D_A_x2 0x18390 +#define A3D_A_y1 0x18394 +#define A3D_A_y2 0x18398 +#define A3D_A_HrtfOutL 0x1839C +#define A3D_A_HrtfOutR 0x183A0 +#define A3D_A_TAIL 0x183A4 + +/* Second register bank */ +#define A3D_B_HrtfCurrent 0x19000 /* 56 ULONG */ +#define A3D_B_GainCurrent 0x190E0 +#define A3D_B_GainTarget 0x190E4 +#define A3D_B_A12Current 0x190E8 +#define A3D_B_A21Target 0x190EC +#define A3D_B_B01Current 0x190F0 +#define A3D_B_B10Target 0x190F4 +#define A3D_B_B2Current 0x190F8 +#define A3D_B_B2Target 0x190FC +#define A3D_B_HrtfTarget 0x19100 /* 56 ULONG */ +#define A3D_B_ITDCurrent 0x191E0 +#define A3D_B_ITDTarget 0x191E4 +#define A3D_B_HrtfDelayLine 0x191E8 /* 56 ULONG */ +#define A3D_B_TAIL 0x192C8 + +/* There are 4 slices, 4 a3d each = 16 a3d sources. */ +#define A3D_SLICE_BANK_A 0x18000 /* 4 sources */ +#define A3D_SLICE_BANK_B 0x19000 /* 4 sources */ +#define A3D_SLICE_VDBDest 0x19C00 /* 8 ULONG */ +#define A3D_SLICE_VDBSource 0x19C20 /* 4 ULONG */ +#define A3D_SLICE_ABReg 0x19C30 +#define A3D_SLICE_CReg 0x19C34 +#define A3D_SLICE_Control 0x19C38 +#define A3D_SLICE_DebugReserved 0x19C3c /* Dangerous! */ +#define A3D_SLICE_Pointers 0x19C40 +#define A3D_SLICE_TAIL 0x1A000 + +// Slice size: 0x2000 +// Source size: 0x3A4, 0x2C8 + +/* Address generator macro. */ +#define a3d_addrA(slice,source,reg) (((slice)<<0xd)+((source)*0x3A4)+(reg)) +#define a3d_addrB(slice,source,reg) (((slice)<<0xd)+((source)*0x2C8)+(reg)) +#define a3d_addrS(slice,reg) (((slice)<<0xd)+(reg)) +//#define a3d_addr(slice,source,reg) (((reg)>=0x19000) ? a3d_addr2((slice),(source),(reg)) : a3d_addr1((slice),(source),(reg))) + +#endif /* _AU88X0_A3D_H */ diff -Nru a/sound/pci/au88x0/au88x0_a3ddata.c b/sound/pci/au88x0/au88x0_a3ddata.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/au88x0/au88x0_a3ddata.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,91 @@ +/*************************************************************************** + * au88x0_a3ddata.c + * + * Wed Nov 19 21:11:32 2003 + * Copyright 2003 mjander + * mjander@users.sourceforge.org + ****************************************************************************/ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Constant initializer values. */ + +static const a3d_Hrtf_t A3dHrirZeros = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + 0, 0, 0 +}; + +static const a3d_Hrtf_t A3dHrirImpulse = { + 0x7fff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + 0, 0, 0 +}; + +static const a3d_Hrtf_t A3dHrirOnes = { + 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, + 0x7fff, + 0x7fff, + 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, + 0x7fff, + 0x7fff, + 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, + 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, + 0x7fff, + 0x7fff, + 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, + 0x7fff, + 0x7fff, + 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff +}; + +static const a3d_Hrtf_t A3dHrirSatTest = { + 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, + 0x7fff, + 0x7fff, + 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, 0x8001, + 0x8001, + 0x8001, + 0x7fff, 0x0000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static const a3d_Hrtf_t A3dHrirDImpulse = { + 0, 0x7fff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + 0, 0, 0 +}; + +static const a3d_ItdDline_t A3dItdDlineZeros = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static short const GainTCDefault = 0x300; +static short const ItdTCDefault = 0x0C8; +static short const HrtfTCDefault = 0x147; +static short const CoefTCDefault = 0x300; diff -Nru a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/au88x0/au88x0_core.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,2822 @@ +/* + * 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Vortex core low level functions. + + Author: Manuel Jander (mjander@users.sourceforge.cl) + These functions are mainly the result of translations made + from the original disassembly of the au88x0 binary drivers, + written by Aureal before they went down. + Many thanks to the Jeff Muizelar, Kester Maddock, and whoever + contributed to the OpenVortex project. + The author of this file, put the few available pieces together + and translated the rest of the riddle (Mix, Src and connection stuff). + Some things are still to be discovered, and their meanings are unclear. + + Some of these functions aren't intended to be really used, rather + to help to understand how does the AU88X0 chips work. Keep them in, because + they could be used somewhere in the future. + + This code hasn't been tested or proof read thoroughly. If you wanna help, + take a look at the AU88X0 assembly and check if this matches. + Functions tested ok so far are (they show the desired effect + at least): + vortex_routes(); (1 bug fixed). + vortex_adb_addroute(); + vortex_adb_addroutes(); + vortex_connect_codecplay(); + vortex_src_flushbuffers(); + vortex_adbdma_setmode(); note: still some unknown arguments! + vortex_adbdma_startfifo(); + vortex_adbdma_stopfifo(); + vortex_fifo_setadbctrl(); note: still some unknown arguments! + vortex_mix_setinputvolumebyte(); + vortex_mix_enableinput(); + vortex_mixer_addWTD(); (fixed) + vortex_connection_adbdma_src_src(); + vortex_connection_adbdma_src(); + vortex_src_change_convratio(); + vortex_src_addWTD(); (fixed) + + History: + + 01-03-2003 First revision. + 01-21-2003 Some bug fixes. + 17-02-2003 many bugfixes after a big versioning mess. + 18-02-2003 JAAAAAHHHUUUUUU!!!! The mixer works !! I'm just so happy ! + (2 hours later...) I cant believe it! Im really lucky today. + Now the SRC is working too! Yeah! XMMS works ! + 20-02-2003 First steps into the ALSA world. + 28-02-2003 As my birthday present, i discovered how the DMA buffer pages really + work :-). It was all wrong. + 12-03-2003 ALSA driver starts working (2 channels). + 16-03-2003 More srcblock_setupchannel discoveries. + 12-04-2003 AU8830 playback support. Recording in the works. + 17-04-2003 vortex_route() and vortex_routes() bug fixes. AU8830 recording + works now, but chipn' dale effect is still there. + 16-05-2003 SrcSetupChannel cleanup. Moved the Src setup stuff entirely + into au88x0_pcm.c . + 06-06-2003 Buffer shifter bugfix. Mixer volume fix. + 07-12-2003 A3D routing finally fixed. Believed to be OK. + +*/ + +#include "au88x0.h" +#include "au88x0_a3d.h" +#include + +/* MIXER (CAsp4Mix.s and CAsp4Mixer.s) */ + +// FIXME: get rid of this. +int mchannels[NR_MIXIN]; +int rampchs[NR_MIXIN]; + +static void vortex_mixer_en_sr(vortex_t * vortex, int channel) +{ + hwwrite(vortex->mmio, VORTEX_MIXER_SR, + hwread(vortex->mmio, VORTEX_MIXER_SR) | (0x1 << channel)); +} +static void vortex_mixer_dis_sr(vortex_t * vortex, int channel) +{ + hwwrite(vortex->mmio, VORTEX_MIXER_SR, + hwread(vortex->mmio, VORTEX_MIXER_SR) & ~(0x1 << channel)); +} + +#if 0 +static void +vortex_mix_muteinputgain(vortex_t * vortex, unsigned char mix, + unsigned char channel) +{ + hwwrite(vortex->mmio, VORTEX_MIX_INVOL_A + ((mix << 5) + channel), + 0x80); + hwwrite(vortex->mmio, VORTEX_MIX_INVOL_B + ((mix << 5) + channel), + 0x80); +} + +static int vortex_mix_getvolume(vortex_t * vortex, unsigned char mix) +{ + int a; + a = hwread(vortex->mmio, VORTEX_MIX_VOL_A + (mix << 2)) & 0xff; + //FP2LinearFrac(a); + return (a); +} + +static int +vortex_mix_getinputvolume(vortex_t * vortex, unsigned char mix, + int channel, int *vol) +{ + int a; + if (!(mchannels[mix] & (1 << channel))) + return 0; + a = hwread(vortex->mmio, + VORTEX_MIX_INVOL_A + (((mix << 5) + channel) << 2)); + /* + if (rampchs[mix] == 0) + a = FP2LinearFrac(a); + else + a = FP2LinearFracWT(a); + */ + *vol = a; + return (0); +} + +static unsigned int vortex_mix_boost6db(unsigned char vol) +{ + return (vol + 8); /* WOW! what a complex function! */ +} + +static void vortex_mix_rampvolume(vortex_t * vortex, int mix) +{ + int ch; + char a; + // This function is intended for ramping down only (see vortex_disableinput()). + for (ch = 0; ch < 0x20; ch++) { + if (((1 << ch) & rampchs[mix]) == 0) + continue; + a = hwread(vortex->mmio, + VORTEX_MIX_INVOL_B + (((mix << 5) + ch) << 2)); + if (a > -126) { + a -= 2; + hwwrite(vortex->mmio, + VORTEX_MIX_INVOL_A + + (((mix << 5) + ch) << 2), a); + hwwrite(vortex->mmio, + VORTEX_MIX_INVOL_B + + (((mix << 5) + ch) << 2), a); + } else + vortex_mix_killinput(vortex, mix, ch); + } +} + +static int +vortex_mix_getenablebit(vortex_t * vortex, unsigned char mix, int mixin) +{ + int addr, temp; + if (mixin >= 0) + addr = mixin; + else + addr = mixin + 3; + addr = ((mix << 3) + (addr >> 2)) << 2; + temp = hwread(vortex->mmio, VORTEX_MIX_ENIN + addr); + return ((temp >> (mixin & 3)) & 1); +} +#endif +static void +vortex_mix_setvolumebyte(vortex_t * vortex, unsigned char mix, + unsigned char vol) +{ + int temp; + hwwrite(vortex->mmio, VORTEX_MIX_VOL_A + (mix << 2), vol); + if (1) { /*if (this_10) */ + temp = hwread(vortex->mmio, VORTEX_MIX_VOL_B + (mix << 2)); + if ((temp != 0x80) || (vol == 0x80)) + return; + } + hwwrite(vortex->mmio, VORTEX_MIX_VOL_B + (mix << 2), vol); +} + +static void +vortex_mix_setinputvolumebyte(vortex_t * vortex, unsigned char mix, + int mixin, unsigned char vol) +{ + int temp; + + hwwrite(vortex->mmio, + VORTEX_MIX_INVOL_A + (((mix << 5) + mixin) << 2), vol); + if (1) { /* this_10, initialized to 1. */ + temp = + hwread(vortex->mmio, + VORTEX_MIX_INVOL_B + (((mix << 5) + mixin) << 2)); + if ((temp != 0x80) || (vol == 0x80)) + return; + } + hwwrite(vortex->mmio, + VORTEX_MIX_INVOL_B + (((mix << 5) + mixin) << 2), vol); +} + +static void +vortex_mix_setenablebit(vortex_t * vortex, unsigned char mix, int mixin, int en) +{ + int temp, addr; + + if (mixin < 0) + addr = (mixin + 3); + else + addr = mixin; + addr = ((mix << 3) + (addr >> 2)) << 2; + temp = hwread(vortex->mmio, VORTEX_MIX_ENIN + addr); + if (en) + temp |= (1 << (mixin & 3)); + else + temp &= ~(1 << (mixin & 3)); + /* Mute input. Astatic void crackling? */ + hwwrite(vortex->mmio, + VORTEX_MIX_INVOL_B + (((mix << 5) + mixin) << 2), 0x80); + /* Looks like clear buffer. */ + hwwrite(vortex->mmio, VORTEX_MIX_SMP + (mixin << 2), 0x0); + hwwrite(vortex->mmio, VORTEX_MIX_SMP + 4 + (mixin << 2), 0x0); + /* Write enable bit. */ + hwwrite(vortex->mmio, VORTEX_MIX_ENIN + addr, temp); +} + +static void +vortex_mix_killinput(vortex_t * vortex, unsigned char mix, int mixin) +{ + rampchs[mix] &= ~(1 << mixin); + vortex_mix_setinputvolumebyte(vortex, mix, mixin, 0x80); + mchannels[mix] &= ~(1 << mixin); + vortex_mix_setenablebit(vortex, mix, mixin, 0); +} + +static void +vortex_mix_enableinput(vortex_t * vortex, unsigned char mix, int mixin) +{ + vortex_mix_killinput(vortex, mix, mixin); + if ((mchannels[mix] & (1 << mixin)) == 0) { + vortex_mix_setinputvolumebyte(vortex, mix, mixin, 0x80); /*0x80 : mute */ + mchannels[mix] |= (1 << mixin); + } + vortex_mix_setenablebit(vortex, mix, mixin, 1); +} + +static void +vortex_mix_disableinput(vortex_t * vortex, unsigned char mix, int channel, + int ramp) +{ + if (ramp) { + rampchs[mix] |= (1 << channel); + // Register callback. + //vortex_mix_startrampvolume(vortex); + vortex_mix_killinput(vortex, mix, channel); + } else + vortex_mix_killinput(vortex, mix, channel); +} + +static int +vortex_mixer_addWTD(vortex_t * vortex, unsigned char mix, unsigned char ch) +{ + int temp, lifeboat = 0, prev; + + temp = hwread(vortex->mmio, VORTEX_MIXER_SR); + if ((temp & (1 << ch)) == 0) { + hwwrite(vortex->mmio, VORTEX_MIXER_CHNBASE + (ch << 2), mix); + vortex_mixer_en_sr(vortex, ch); + return 1; + } + prev = VORTEX_MIXER_CHNBASE + (ch << 2); + temp = hwread(vortex->mmio, prev); + while (temp & 0x10) { + prev = VORTEX_MIXER_RTBASE + ((temp & 0xf) << 2); + temp = hwread(vortex->mmio, prev); + //printk(KERN_INFO "vortex: mixAddWTD: while addr=%x, val=%x\n", prev, temp); + if ((++lifeboat) > 0xf) { + printk(KERN_ERR + "vortex_mixer_addWTD: lifeboat overflow\n"); + return 0; + } + } + hwwrite(vortex->mmio, VORTEX_MIXER_RTBASE + ((temp & 0xf) << 2), mix); + hwwrite(vortex->mmio, prev, (temp & 0xf) | 0x10); + return 1; +} + +static int +vortex_mixer_delWTD(vortex_t * vortex, unsigned char mix, unsigned char ch) +{ + int esp14 = -1, esp18, eax, ebx, edx, ebp, esi = 0; + //int esp1f=edi(while)=src, esp10=ch; + + eax = hwread(vortex->mmio, VORTEX_MIXER_SR); + if (((1 << ch) & eax) == 0) { + printk(KERN_ERR "mix ALARM %x\n", eax); + return 0; + } + ebp = VORTEX_MIXER_CHNBASE + (ch << 2); + esp18 = hwread(vortex->mmio, ebp); + if (esp18 & 0x10) { + ebx = (esp18 & 0xf); + if (mix == ebx) { + ebx = VORTEX_MIXER_RTBASE + (mix << 2); + edx = hwread(vortex->mmio, ebx); + //7b60 + hwwrite(vortex->mmio, ebp, edx); + hwwrite(vortex->mmio, ebx, 0); + } else { + //7ad3 + edx = + hwread(vortex->mmio, + VORTEX_MIXER_RTBASE + (ebx << 2)); + //printk(KERN_INFO "vortex: mixdelWTD: 1 addr=%x, val=%x, src=%x\n", ebx, edx, src); + while ((edx & 0xf) != mix) { + if ((esi) > 0xf) { + printk(KERN_ERR + "vortex: mixdelWTD: error lifeboat overflow\n"); + return 0; + } + esp14 = ebx; + ebx = edx & 0xf; + ebp = ebx << 2; + edx = + hwread(vortex->mmio, + VORTEX_MIXER_RTBASE + ebp); + //printk(KERN_INFO "vortex: mixdelWTD: while addr=%x, val=%x\n", ebp, edx); + esi++; + } + //7b30 + ebp = ebx << 2; + if (edx & 0x10) { /* Delete entry in between others */ + ebx = VORTEX_MIXER_RTBASE + ((edx & 0xf) << 2); + edx = hwread(vortex->mmio, ebx); + //7b60 + hwwrite(vortex->mmio, + VORTEX_MIXER_RTBASE + ebp, edx); + hwwrite(vortex->mmio, ebx, 0); + //printk(KERN_INFO "vortex mixdelWTD between addr= 0x%x, val= 0x%x\n", ebp, edx); + } else { /* Delete last entry */ + //7b83 + if (esp14 == -1) + hwwrite(vortex->mmio, + VORTEX_MIXER_CHNBASE + + (ch << 2), esp18 & 0xef); + else { + ebx = (0xffffffe0 & edx) | (0xf & ebx); + hwwrite(vortex->mmio, + VORTEX_MIXER_RTBASE + + (esp14 << 2), ebx); + //printk(KERN_INFO "vortex mixdelWTD last addr= 0x%x, val= 0x%x\n", esp14, ebx); + } + hwwrite(vortex->mmio, + VORTEX_MIXER_RTBASE + ebp, 0); + return 1; + } + } + } else { + //printk(KERN_INFO "removed last mix\n"); + //7be0 + vortex_mixer_dis_sr(vortex, ch); + hwwrite(vortex->mmio, ebp, 0); + } + return 1; +} + +static void vortex_mixer_init(vortex_t * vortex) +{ + unsigned long addr; + int x; + + // FIXME: get rid of this crap. + memset(mchannels, 0, NR_MIXOUT * sizeof(int)); + memset(rampchs, 0, NR_MIXOUT * sizeof(int)); + + addr = VORTEX_MIX_SMP + 0x17c; + for (x = 0x5f; x >= 0; x--) { + hwwrite(vortex->mmio, addr, 0); + addr -= 4; + } + addr = VORTEX_MIX_ENIN + 0x1fc; + for (x = 0x7f; x >= 0; x--) { + hwwrite(vortex->mmio, addr, 0); + addr -= 4; + } + addr = VORTEX_MIX_SMP + 0x17c; + for (x = 0x5f; x >= 0; x--) { + hwwrite(vortex->mmio, addr, 0); + addr -= 4; + } + addr = VORTEX_MIX_INVOL_A + 0x7fc; + for (x = 0x1ff; x >= 0; x--) { + hwwrite(vortex->mmio, addr, 0x80); + addr -= 4; + } + addr = VORTEX_MIX_VOL_A + 0x3c; + for (x = 0xf; x >= 0; x--) { + hwwrite(vortex->mmio, addr, 0x80); + addr -= 4; + } + addr = VORTEX_MIX_INVOL_B + 0x7fc; + for (x = 0x1ff; x >= 0; x--) { + hwwrite(vortex->mmio, addr, 0x80); + addr -= 4; + } + addr = VORTEX_MIX_VOL_B + 0x3c; + for (x = 0xf; x >= 0; x--) { + hwwrite(vortex->mmio, addr, 0x80); + addr -= 4; + } + addr = VORTEX_MIXER_RTBASE + (MIXER_RTBASE_SIZE - 1) * 4; + for (x = (MIXER_RTBASE_SIZE - 1); x >= 0; x--) { + hwwrite(vortex->mmio, addr, 0x0); + addr -= 4; + } + hwwrite(vortex->mmio, VORTEX_MIXER_SR, 0); + + /* Set clipping ceiling (this may be all wrong). */ + /* + for (x = 0; x > 0x80; x++) { + hwwrite(vortex->mmio, VORTEX_MIXER_CLIP + (x << 2), 0x3ffff); + } + */ + /* + call CAsp4Mix__Initialize_CAsp4HwIO____CAsp4Mixer____ + Register ISR callback for volume smooth fade out. + Maybe this avoids clicks when press "stop" ? + */ +} + +/* SRC (CAsp4Src.s and CAsp4SrcBlock) */ + +static void vortex_src_en_sr(vortex_t * vortex, int channel) +{ + hwwrite(vortex->mmio, VORTEX_SRCBLOCK_SR, + hwread(vortex->mmio, VORTEX_SRCBLOCK_SR) | (0x1 << channel)); +} + +static void vortex_src_dis_sr(vortex_t * vortex, int channel) +{ + hwwrite(vortex->mmio, VORTEX_SRCBLOCK_SR, + hwread(vortex->mmio, VORTEX_SRCBLOCK_SR) & ~(0x1 << channel)); +} + +static void vortex_src_flushbuffers(vortex_t * vortex, unsigned char src) +{ + int i; + + for (i = 0x1f; i >= 0; i--) + hwwrite(vortex->mmio, + VORTEX_SRC_DATA0 + (src << 7) + (i << 2), 0); + hwwrite(vortex->mmio, VORTEX_SRC_DATA + (src << 3), 0); + hwwrite(vortex->mmio, VORTEX_SRC_DATA + (src << 3) + 4, 0); +} + +static void vortex_src_cleardrift(vortex_t * vortex, unsigned char src) +{ + hwwrite(vortex->mmio, VORTEX_SRC_DRIFT0 + (src << 2), 0); + hwwrite(vortex->mmio, VORTEX_SRC_DRIFT1 + (src << 2), 0); + hwwrite(vortex->mmio, VORTEX_SRC_DRIFT2 + (src << 2), 1); +} + +static void +vortex_src_set_throttlesource(vortex_t * vortex, unsigned char src, int en) +{ + int temp; + + temp = hwread(vortex->mmio, VORTEX_SRC_SOURCE); + if (en) + temp |= 1 << src; + else + temp &= ~(1 << src); + hwwrite(vortex->mmio, VORTEX_SRC_SOURCE, temp); +} + +static int +vortex_src_persist_convratio(vortex_t * vortex, unsigned char src, int ratio) +{ + int temp, lifeboat = 0; + + do { + hwwrite(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2), ratio); + temp = hwread(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2)); + if ((++lifeboat) > 0x9) { + printk(KERN_ERR "Vortex: Src cvr fail\n"); + break; + } + } + while (temp != ratio); + return temp; +} + +#if 0 +static void vortex_src_slowlock(vortex_t * vortex, unsigned char src) +{ + int temp; + + hwwrite(vortex->mmio, VORTEX_SRC_DRIFT2 + (src << 2), 1); + hwwrite(vortex->mmio, VORTEX_SRC_DRIFT0 + (src << 2), 0); + temp = hwread(vortex->mmio, VORTEX_SRC_U0 + (src << 2)); + if (temp & 0x200) + hwwrite(vortex->mmio, VORTEX_SRC_U0 + (src << 2), + temp & ~0x200L); +} + +static void +vortex_src_change_convratio(vortex_t * vortex, unsigned char src, int ratio) +{ + int temp, a; + + if ((ratio & 0x10000) && (ratio != 0x10000)) { + if (ratio & 0x3fff) + a = (0x11 - ((ratio >> 0xe) & 0x3)) - 1; + else + a = (0x11 - ((ratio >> 0xe) & 0x3)) - 2; + } else + a = 0xc; + temp = hwread(vortex->mmio, VORTEX_SRC_U0 + (src << 2)); + if (((temp >> 4) & 0xf) != a) + hwwrite(vortex->mmio, VORTEX_SRC_U0 + (src << 2), + (temp & 0xf) | ((a & 0xf) << 4)); + + vortex_src_persist_convratio(vortex, src, ratio); +} + +static int +vortex_src_checkratio(vortex_t * vortex, unsigned char src, + unsigned int desired_ratio) +{ + int hw_ratio, lifeboat = 0; + + hw_ratio = hwread(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2)); + + while (hw_ratio != desired_ratio) { + hwwrite(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2), desired_ratio); + + if ((lifeboat++) > 15) { + printk(KERN_ERR "Vortex: could not set src-%d from %d to %d\n", + src, hw_ratio, desired_ratio); + break; + } + } + + return hw_ratio; +} + +#endif +/* + Objective: Set samplerate for given SRC module. + Arguments: + card: pointer to vortex_t strcut. + src: Integer index of the SRC module. + cr: Current sample rate conversion factor. + b: unknown 16 bit value. + sweep: Enable Samplerate fade from cr toward tr flag. + dirplay: 1: playback, 0: recording. + sl: Slow Lock flag. + tr: Target samplerate conversion. + thsource: Throttle source flag (no idea what that means). +*/ +static void vortex_src_setupchannel(vortex_t * card, unsigned char src, + unsigned int cr, unsigned int b, int sweep, int d, + int dirplay, int sl, unsigned int tr, int thsource) +{ + // noplayback: d=2,4,7,0xa,0xb when using first 2 src's. + // c: enables pitch sweep. + // looks like g is c related. Maybe g is a sweep parameter ? + // g = cvr + // dirplay: 0 = recording, 1 = playback + // d = src hw index. + + int esi, ebp = 0, esp10; + + vortex_src_flushbuffers(card, src); + + if (sweep) { + if ((tr & 0x10000) && (tr != 0x10000)) { + tr = 0; + esi = 0x7; + } else { + if ((((short)tr) < 0) && (tr != 0x8000)) { + tr = 0; + esi = 0x8; + } else { + tr = 1; + esi = 0xc; + } + } + } else { + if ((cr & 0x10000) && (cr != 0x10000)) { + tr = 0; /*ebx = 0 */ + esi = 0x11 - ((cr >> 0xe) & 7); + if (cr & 0x3fff) + esi -= 1; + else + esi -= 2; + } else { + tr = 1; + esi = 0xc; + } + } + vortex_src_cleardrift(card, src); + vortex_src_set_throttlesource(card, src, thsource); + + if ((dirplay == 0) && (sweep == 0)) { + if (tr) + esp10 = 0xf; + else + esp10 = 0xc; + ebp = 0; + } else { + if (tr) + ebp = 0xf; + else + ebp = 0xc; + esp10 = 0; + } + hwwrite(card->mmio, VORTEX_SRC_U0 + (src << 2), + (sl << 0x9) | (sweep << 0x8) | ((esi & 0xf) << 4) | d); + /* 0xc0 esi=0xc c=f=0 d=0 */ + vortex_src_persist_convratio(card, src, cr); + hwwrite(card->mmio, VORTEX_SRC_U1 + (src << 2), b & 0xffff); + /* 0 b=0 */ + hwwrite(card->mmio, VORTEX_SRC_U2 + (src << 2), + (tr << 0x11) | (dirplay << 0x10) | (ebp << 0x8) | esp10); + /* 0x30f00 e=g=1 esp10=0 ebp=f */ + //printk(KERN_INFO "vortex: SRC %d, d=0x%x, esi=0x%x, esp10=0x%x, ebp=0x%x\n", src, d, esi, esp10, ebp); +} + +static void vortex_srcblock_init(vortex_t * vortex) +{ + unsigned long addr; + int x; + hwwrite(vortex->mmio, VORTEX_SRC_SOURCESIZE, 0x1ff); + /* + for (x=0; x<0x10; x++) { + vortex_src_init(&vortex_src[x], x); + } + */ + //addr = 0xcc3c; + //addr = 0x26c3c; + addr = VORTEX_SRC_RTBASE + 0x3c; + for (x = 0xf; x >= 0; x--) { + hwwrite(vortex->mmio, addr, 0); + addr -= 4; + } + //addr = 0xcc94; + //addr = 0x26c94; + addr = VORTEX_SRC_CHNBASE + 0x54; + for (x = 0x15; x >= 0; x--) { + hwwrite(vortex->mmio, addr, 0); + addr -= 4; + } +} + +static int +vortex_src_addWTD(vortex_t * vortex, unsigned char src, unsigned char ch) +{ + int temp, lifeboat = 0, prev; + // esp13 = src + + temp = hwread(vortex->mmio, VORTEX_SRCBLOCK_SR); + if ((temp & (1 << ch)) == 0) { + hwwrite(vortex->mmio, VORTEX_SRC_CHNBASE + (ch << 2), src); + vortex_src_en_sr(vortex, ch); + return 1; + } + prev = VORTEX_SRC_CHNBASE + (ch << 2); /*ebp */ + temp = hwread(vortex->mmio, prev); + //while (temp & NR_SRC) { + while (temp & 0x10) { + prev = VORTEX_SRC_RTBASE + ((temp & 0xf) << 2); /*esp12 */ + //prev = VORTEX_SRC_RTBASE + ((temp & (NR_SRC-1)) << 2); /*esp12*/ + temp = hwread(vortex->mmio, prev); + //printk(KERN_INFO "vortex: srcAddWTD: while addr=%x, val=%x\n", prev, temp); + if ((++lifeboat) > 0xf) { + printk(KERN_ERR + "vortex_src_addWTD: lifeboat overflow\n"); + return 0; + } + } + hwwrite(vortex->mmio, VORTEX_SRC_RTBASE + ((temp & 0xf) << 2), src); + //hwwrite(vortex->mmio, prev, (temp & (NR_SRC-1)) | NR_SRC); + hwwrite(vortex->mmio, prev, (temp & 0xf) | 0x10); + return 1; +} + +static int +vortex_src_delWTD(vortex_t * vortex, unsigned char src, unsigned char ch) +{ + int esp14 = -1, esp18, eax, ebx, edx, ebp, esi = 0; + //int esp1f=edi(while)=src, esp10=ch; + + eax = hwread(vortex->mmio, VORTEX_SRCBLOCK_SR); + if (((1 << ch) & eax) == 0) { + printk(KERN_ERR "src alarm\n"); + return 0; + } + ebp = VORTEX_SRC_CHNBASE + (ch << 2); + esp18 = hwread(vortex->mmio, ebp); + if (esp18 & 0x10) { + ebx = (esp18 & 0xf); + if (src == ebx) { + ebx = VORTEX_SRC_RTBASE + (src << 2); + edx = hwread(vortex->mmio, ebx); + //7b60 + hwwrite(vortex->mmio, ebp, edx); + hwwrite(vortex->mmio, ebx, 0); + } else { + //7ad3 + edx = + hwread(vortex->mmio, + VORTEX_SRC_RTBASE + (ebx << 2)); + //printk(KERN_INFO "vortex: srcdelWTD: 1 addr=%x, val=%x, src=%x\n", ebx, edx, src); + while ((edx & 0xf) != src) { + if ((esi) > 0xf) { + printk + ("vortex: srcdelWTD: error, lifeboat overflow\n"); + return 0; + } + esp14 = ebx; + ebx = edx & 0xf; + ebp = ebx << 2; + edx = + hwread(vortex->mmio, + VORTEX_SRC_RTBASE + ebp); + //printk(KERN_INFO "vortex: srcdelWTD: while addr=%x, val=%x\n", ebp, edx); + esi++; + } + //7b30 + ebp = ebx << 2; + if (edx & 0x10) { /* Delete entry in between others */ + ebx = VORTEX_SRC_RTBASE + ((edx & 0xf) << 2); + edx = hwread(vortex->mmio, ebx); + //7b60 + hwwrite(vortex->mmio, + VORTEX_SRC_RTBASE + ebp, edx); + hwwrite(vortex->mmio, ebx, 0); + //printk(KERN_INFO "vortex srcdelWTD between addr= 0x%x, val= 0x%x\n", ebp, edx); + } else { /* Delete last entry */ + //7b83 + if (esp14 == -1) + hwwrite(vortex->mmio, + VORTEX_SRC_CHNBASE + + (ch << 2), esp18 & 0xef); + else { + ebx = (0xffffffe0 & edx) | (0xf & ebx); + hwwrite(vortex->mmio, + VORTEX_SRC_RTBASE + + (esp14 << 2), ebx); + //printk(KERN_INFO"vortex srcdelWTD last addr= 0x%x, val= 0x%x\n", esp14, ebx); + } + hwwrite(vortex->mmio, + VORTEX_SRC_RTBASE + ebp, 0); + return 1; + } + } + } else { + //7be0 + vortex_src_dis_sr(vortex, ch); + hwwrite(vortex->mmio, ebp, 0); + } + return 1; +} + + /*FIFO*/ static void +vortex_fifo_clearadbdata(vortex_t * vortex, int fifo, int x) +{ + for (x--; x >= 0; x--) + hwwrite(vortex->mmio, + VORTEX_FIFO_ADBDATA + + (((fifo << FIFO_SIZE_BITS) + x) << 2), 0); +} + +#if 0 +static void vortex_fifo_adbinitialize(vortex_t * vortex, int fifo, int j) +{ + vortex_fifo_clearadbdata(vortex, fifo, FIFO_SIZE); +#ifdef CHIP_AU8820 + hwwrite(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2), + (FIFO_U1 | ((j & FIFO_MASK) << 0xb))); +#else + hwwrite(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2), + (FIFO_U1 | ((j & FIFO_MASK) << 0xc))); +#endif +} +#endif +static void vortex_fifo_setadbvalid(vortex_t * vortex, int fifo, int en) +{ + hwwrite(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2), + (hwread(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2)) & + 0xffffffef) | ((1 & en) << 4) | FIFO_U1); +} + +static void +vortex_fifo_setadbctrl(vortex_t * vortex, int fifo, int b, int priority, + int empty, int valid, int f) +{ + int temp, lifeboat = 0; + //int this_8[NR_ADB] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* position */ + int this_4 = 0x2; + /* f seems priority related. + * CAsp4AdbDma::SetPriority is the only place that calls SetAdbCtrl with f set to 1 + * every where else it is set to 0. It seems, however, that CAsp4AdbDma::SetPriority + * is never called, thus the f related bits remain a mystery for now. + */ + do { + temp = hwread(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2)); + if (lifeboat++ > 0xbb8) { + printk(KERN_ERR + "Vortex: vortex_fifo_setadbctrl fail\n"); + break; + } + } + while (temp & FIFO_RDONLY); + + // AU8830 semes to take some special care about fifo content (data). + // But i'm just to lazy to translate that :) + if (valid) { + if ((temp & FIFO_VALID) == 0) { + //this_8[fifo] = 0; + vortex_fifo_clearadbdata(vortex, fifo, FIFO_SIZE); // this_4 +#ifdef CHIP_AU8820 + temp = (this_4 & 0x1f) << 0xb; +#else + temp = (this_4 & 0x3f) << 0xc; +#endif + temp = (temp & 0xfffffffd) | ((b & 1) << 1); + temp = (temp & 0xfffffff3) | ((priority & 3) << 2); + temp = (temp & 0xffffffef) | ((valid & 1) << 4); + temp |= FIFO_U1; + temp = (temp & 0xffffffdf) | ((empty & 1) << 5); +#ifdef CHIP_AU8820 + temp = (temp & 0xfffbffff) | ((f & 1) << 0x12); +#endif +#ifdef CHIP_AU8830 + temp = (temp & 0xf7ffffff) | ((f & 1) << 0x1b); + temp = (temp & 0xefffffff) | ((f & 1) << 0x1c); +#endif +#ifdef CHIP_AU8810 + temp = (temp & 0xfeffffff) | ((f & 1) << 0x18); + temp = (temp & 0xfdffffff) | ((f & 1) << 0x19); +#endif + } + } else { + if (temp & FIFO_VALID) { +#ifdef CHIP_AU8820 + temp = ((f & 1) << 0x12) | (temp & 0xfffbffef); +#endif +#ifdef CHIP_AU8830 + temp = + ((f & 1) << 0x1b) | (temp & 0xe7ffffef) | FIFO_BITS; +#endif +#ifdef CHIP_AU8810 + temp = + ((f & 1) << 0x18) | (temp & 0xfcffffef) | FIFO_BITS; +#endif + } else + /*if (this_8[fifo]) */ + vortex_fifo_clearadbdata(vortex, fifo, FIFO_SIZE); + } + hwwrite(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2), temp); + hwread(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2)); +} + +#ifndef CHIP_AU8810 +static void vortex_fifo_clearwtdata(vortex_t * vortex, int fifo, int x) +{ + if (x < 1) + return; + for (x--; x >= 0; x--) + hwwrite(vortex->mmio, + VORTEX_FIFO_WTDATA + + (((fifo << FIFO_SIZE_BITS) + x) << 2), 0); +} + +static void vortex_fifo_wtinitialize(vortex_t * vortex, int fifo, int j) +{ + vortex_fifo_clearwtdata(vortex, fifo, FIFO_SIZE); +#ifdef CHIP_AU8820 + hwwrite(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2), + (FIFO_U1 | ((j & FIFO_MASK) << 0xb))); +#else + hwwrite(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2), + (FIFO_U1 | ((j & FIFO_MASK) << 0xc))); +#endif +} + +static void vortex_fifo_setwtvalid(vortex_t * vortex, int fifo, int en) +{ + hwwrite(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2), + (hwread(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2)) & + 0xffffffef) | ((en & 1) << 4) | FIFO_U1); +} + +static void +vortex_fifo_setwtctrl(vortex_t * vortex, int fifo, int ctrl, int priority, + int empty, int valid, int f) +{ + int temp = 0, lifeboat = 0; + int this_4 = 2; + + do { + temp = hwread(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2)); + if (lifeboat++ > 0xbb8) { + printk(KERN_ERR "Vortex: vortex_fifo_setwtctrl fail\n"); + break; + } + } + while (temp & FIFO_RDONLY); + + if (valid) { + if ((temp & FIFO_VALID) == 0) { + vortex_fifo_clearwtdata(vortex, fifo, FIFO_SIZE); // this_4 +#ifdef CHIP_AU8820 + temp = (this_4 & 0x1f) << 0xb; +#else + temp = (this_4 & 0x3f) << 0xc; +#endif + temp = (temp & 0xfffffffd) | ((ctrl & 1) << 1); + temp = (temp & 0xfffffff3) | ((priority & 3) << 2); + temp = (temp & 0xffffffef) | ((valid & 1) << 4); + temp |= FIFO_U1; + temp = (temp & 0xffffffdf) | ((empty & 1) << 5); +#ifdef CHIP_AU8820 + temp = (temp & 0xfffbffff) | ((f & 1) << 0x12); +#endif +#ifdef CHIP_AU8830 + temp = (temp & 0xf7ffffff) | ((f & 1) << 0x1b); + temp = (temp & 0xefffffff) | ((f & 1) << 0x1c); +#endif +#ifdef CHIP_AU8810 + temp = (temp & 0xfeffffff) | ((f & 1) << 0x18); + temp = (temp & 0xfdffffff) | ((f & 1) << 0x19); +#endif + } + } else { + if (temp & FIFO_VALID) { +#ifdef CHIP_AU8820 + temp = ((f & 1) << 0x12) | (temp & 0xfffbffef); +#endif +#ifdef CHIP_AU8830 + temp = + ((f & 1) << 0x1b) | (temp & 0xe7ffffef) | FIFO_BITS; +#endif +#ifdef CHIP_AU8810 + temp = + ((f & 1) << 0x18) | (temp & 0xfcffffef) | FIFO_BITS; +#endif + } else + /*if (this_8[fifo]) */ + vortex_fifo_clearwtdata(vortex, fifo, FIFO_SIZE); + } + hwwrite(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2), temp); + hwread(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2)); + +/* + do { + temp = hwread(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2)); + if (lifeboat++ > 0xbb8) { + printk(KERN_ERR "Vortex: vortex_fifo_setwtctrl fail (hanging)\n"); + break; + } + } while ((temp & FIFO_RDONLY)&&(temp & FIFO_VALID)&&(temp != 0xFFFFFFFF)); + + + if (valid) { + if (temp & FIFO_VALID) { + temp = 0x40000; + //temp |= 0x08000000; + //temp |= 0x10000000; + //temp |= 0x04000000; + //temp |= 0x00400000; + temp |= 0x1c400000; + temp &= 0xFFFFFFF3; + temp &= 0xFFFFFFEF; + temp |= (valid & 1) << 4; + hwwrite(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2), temp); + return; + } else { + vortex_fifo_clearwtdata(vortex, fifo, FIFO_SIZE); + return; + } + } else { + temp &= 0xffffffef; + temp |= 0x08000000; + temp |= 0x10000000; + temp |= 0x04000000; + temp |= 0x00400000; + hwwrite(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2), temp); + temp = hwread(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2)); + //((temp >> 6) & 0x3f) + + priority = 0; + if (((temp & 0x0fc0) ^ ((temp >> 6) & 0x0fc0)) & 0FFFFFFC0) + vortex_fifo_clearwtdata(vortex, fifo, FIFO_SIZE); + valid = 0xfb; + temp = (temp & 0xfffffffd) | ((ctrl & 1) << 1); + temp = (temp & 0xfffdffff) | ((f & 1) << 0x11); + temp = (temp & 0xfffffff3) | ((priority & 3) << 2); + temp = (temp & 0xffffffef) | ((valid & 1) << 4); + temp = (temp & 0xffffffdf) | ((empty & 1) << 5); + hwwrite(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2), temp); + } + + */ + + /* + temp = (temp & 0xfffffffd) | ((ctrl & 1) << 1); + temp = (temp & 0xfffdffff) | ((f & 1) << 0x11); + temp = (temp & 0xfffffff3) | ((priority & 3) << 2); + temp = (temp & 0xffffffef) | ((valid & 1) << 4); + temp = (temp & 0xffffffdf) | ((empty & 1) << 5); + #ifdef FIFO_BITS + temp = temp | FIFO_BITS | 40000; + #endif + // 0x1c440010, 0x1c400000 + hwwrite(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2), temp); + */ +} + +#endif +static void vortex_fifo_init(vortex_t * vortex) +{ + int x; + unsigned long addr; + + /* ADB DMA channels fifos. */ + addr = VORTEX_FIFO_ADBCTRL + ((NR_ADB - 1) * 4); + for (x = NR_ADB - 1; x >= 0; x--) { + hwwrite(vortex->mmio, addr, (FIFO_U0 | FIFO_U1)); + if (hwread(vortex->mmio, addr) != (FIFO_U0 | FIFO_U1)) + printk(KERN_ERR "bad adb fifo reset!"); + vortex_fifo_clearadbdata(vortex, x, FIFO_SIZE); + addr -= 4; + } + +#ifndef CHIP_AU8810 + /* WT DMA channels fifos. */ + addr = VORTEX_FIFO_WTCTRL + ((NR_WT - 1) * 4); + for (x = NR_WT - 1; x >= 0; x--) { + hwwrite(vortex->mmio, addr, FIFO_U0); + if (hwread(vortex->mmio, addr) != FIFO_U0) + printk(KERN_ERR + "bad wt fifo reset (0x%08lx, 0x%08x)!\n", + addr, hwread(vortex->mmio, addr)); + vortex_fifo_clearwtdata(vortex, x, FIFO_SIZE); + addr -= 4; + } +#endif + /* trigger... */ +#ifdef CHIP_AU8820 + hwwrite(vortex->mmio, 0xf8c0, 0xd03); //0x0843 0xd6b +#else +#ifdef CHIP_AU8830 + hwwrite(vortex->mmio, 0x17000, 0x61); /* wt a */ + hwwrite(vortex->mmio, 0x17004, 0x61); /* wt b */ +#endif + hwwrite(vortex->mmio, 0x17008, 0x61); /* adb */ +#endif +} + +/* ADBDMA */ + +static void vortex_adbdma_init(vortex_t * vortex) +{ +} + +static void vortex_adbdma_setfirstbuffer(vortex_t * vortex, int adbdma) +{ + stream_t *dma = &vortex->dma_adb[adbdma]; + + hwwrite(vortex->mmio, VORTEX_ADBDMA_CTRL + (adbdma << 2), + dma->dma_ctrl); +} + +static void vortex_adbdma_setstartbuffer(vortex_t * vortex, int adbdma, int sb) +{ + stream_t *dma = &vortex->dma_adb[adbdma]; + //hwwrite(vortex->mmio, VORTEX_ADBDMA_START + (adbdma << 2), sb << (((NR_ADB-1)-((adbdma&0xf)*2)))); + hwwrite(vortex->mmio, VORTEX_ADBDMA_START + (adbdma << 2), + sb << ((0xf - (adbdma & 0xf)) * 2)); + dma->period_real = dma->period_virt = sb; +} + +static void +vortex_adbdma_setbuffers(vortex_t * vortex, int adbdma, + snd_pcm_sgbuf_t * sgbuf, int psize, int count) +{ + stream_t *dma = &vortex->dma_adb[adbdma]; + + if (sgbuf == NULL) { + printk(KERN_INFO "vortex: FATAL: sgbuf is NULL!\n"); + return; + } + //printk(KERN_INFO "vortex: page count = %d, tblcount = %d\n", count, sgbuf->tblsize); + + dma->period_bytes = psize; + dma->nr_periods = count; + dma->sgbuf = sgbuf; + + dma->cfg0 = 0; + dma->cfg1 = 0; + switch (count) { + /* Four or more pages */ + default: + case 4: + dma->cfg1 |= 0x88000000 | 0x44000000 | 0x30000000 | (psize - 1); + hwwrite(vortex->mmio, + VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0xc, + snd_sgbuf_get_addr(sgbuf, psize * 3)); + /* 3 pages */ + case 3: + dma->cfg0 |= 0x12000000; + dma->cfg1 |= 0x80000000 | 0x40000000 | ((psize - 1) << 0xc); + hwwrite(vortex->mmio, + VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0x8, + snd_sgbuf_get_addr(sgbuf, psize * 2)); + /* 2 pages */ + case 2: + dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | (psize - 1); + hwwrite(vortex->mmio, + VORTEX_ADBDMA_BUFBASE + (adbdma << 4) + 0x4, + snd_sgbuf_get_addr(sgbuf, psize)); + /* 1 page */ + case 1: + dma->cfg0 |= 0x80000000 | 0x40000000 | ((psize - 1) << 0xc); + hwwrite(vortex->mmio, + VORTEX_ADBDMA_BUFBASE + (adbdma << 4), + snd_sgbuf_get_addr(sgbuf, 0)); + break; + } + //printk("vortex: cfg0 = 0x%x\nvortex: cfg1=0x%x\n", dma->cfg0, dma->cfg1); + hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFCFG0 + (adbdma << 3), dma->cfg0); + hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFCFG1 + (adbdma << 3), dma->cfg1); + + vortex_adbdma_setfirstbuffer(vortex, adbdma); + vortex_adbdma_setstartbuffer(vortex, adbdma, 0); +} + +static void +vortex_adbdma_setmode(vortex_t * vortex, int adbdma, int ie, int dir, + int fmt, int d, unsigned long offset) +{ + stream_t *dma = &vortex->dma_adb[adbdma]; + + dma->dma_unknown = d; + dma->dma_ctrl = + ((offset & OFFSET_MASK) | (dma->dma_ctrl & ~OFFSET_MASK)); + /* Enable PCMOUT interrupts. */ + dma->dma_ctrl = + (dma->dma_ctrl & ~IE_MASK) | ((ie << IE_SHIFT) & IE_MASK); + + dma->dma_ctrl = + (dma->dma_ctrl & ~DIR_MASK) | ((dir << DIR_SHIFT) & DIR_MASK); + dma->dma_ctrl = + (dma->dma_ctrl & ~FMT_MASK) | ((fmt << FMT_SHIFT) & FMT_MASK); + + hwwrite(vortex->mmio, VORTEX_ADBDMA_CTRL + (adbdma << 2), + dma->dma_ctrl); + hwread(vortex->mmio, VORTEX_ADBDMA_CTRL + (adbdma << 2)); +} + +static int vortex_adbdma_bufshift(vortex_t * vortex, int adbdma) +{ + stream_t *dma = &vortex->dma_adb[adbdma]; + int page, p, pp, delta, i; + + page = + (hwread(vortex->mmio, VORTEX_ADBDMA_STAT + (adbdma << 2)) & + ADB_SUBBUF_MASK) >> ADB_SUBBUF_SHIFT; + if (dma->nr_periods >= 4) + delta = (page - dma->period_real) & 3; + else { + delta = (page - dma->period_real); + if (delta < 0) + delta += dma->nr_periods; + } + if (delta == 0) + return 0; + + /* refresh hw page table */ + if (dma->nr_periods > 4) { + for (i = 0; i < delta; i++) { + /* p: audio buffer page index */ + p = dma->period_virt + i + 4; + if (p >= dma->nr_periods) + p -= dma->nr_periods; + /* pp: hardware DMA page index. */ + pp = dma->period_real + i; + if (pp >= 4) + pp -= 4; + //hwwrite(vortex->mmio, VORTEX_ADBDMA_BUFBASE+(((adbdma << 2)+pp) << 2), dma->table[p].addr); + hwwrite(vortex->mmio, + VORTEX_ADBDMA_BUFBASE + (((adbdma << 2) + pp) << 2), + snd_sgbuf_get_addr(dma->sgbuf, + dma->period_bytes * p)); + /* Force write thru cache. */ + hwread(vortex->mmio, VORTEX_ADBDMA_BUFBASE + + (((adbdma << 2) + pp) << 2)); + } + } + dma->period_virt += delta; + dma->period_real = page; + if (dma->period_virt >= dma->nr_periods) + dma->period_virt -= dma->nr_periods; + if (delta != 1) + printk(KERN_INFO "vortex: %d virt=%d, real=%d, delta=%d\n", + adbdma, dma->period_virt, dma->period_real, delta); + + return delta; +} + +static int inline vortex_adbdma_getlinearpos(vortex_t * vortex, int adbdma) +{ + stream_t *dma = &vortex->dma_adb[adbdma]; + int temp; + + temp = hwread(vortex->mmio, VORTEX_ADBDMA_STAT + (adbdma << 2)); + temp = (dma->period_virt * dma->period_bytes) + (temp & POS_MASK); + return (temp); +} + +static void vortex_adbdma_startfifo(vortex_t * vortex, int adbdma) +{ + int this_8 = 0 /*empty */ , this_4 = 0 /*priority */ ; + stream_t *dma = &vortex->dma_adb[adbdma]; + + switch (dma->fifo_status) { + case FIFO_START: + vortex_fifo_setadbvalid(vortex, adbdma, + dma->fifo_enabled ? 1 : 0); + break; + case FIFO_STOP: + this_8 = 1; + hwwrite(vortex->mmio, VORTEX_ADBDMA_CTRL + (adbdma << 2), + dma->dma_ctrl); + vortex_fifo_setadbctrl(vortex, adbdma, dma->dma_unknown, + this_4, this_8, + dma->fifo_enabled ? 1 : 0, 0); + break; + case FIFO_PAUSE: + vortex_fifo_setadbctrl(vortex, adbdma, dma->dma_unknown, + this_4, this_8, + dma->fifo_enabled ? 1 : 0, 0); + break; + } + dma->fifo_status = FIFO_START; +} + +static void vortex_adbdma_resumefifo(vortex_t * vortex, int adbdma) +{ + stream_t *dma = &vortex->dma_adb[adbdma]; + + int this_8 = 1, this_4 = 0; + switch (dma->fifo_status) { + case FIFO_STOP: + hwwrite(vortex->mmio, VORTEX_ADBDMA_CTRL + (adbdma << 2), + dma->dma_ctrl); + vortex_fifo_setadbctrl(vortex, adbdma, dma->dma_unknown, + this_4, this_8, + dma->fifo_enabled ? 1 : 0, 0); + break; + case FIFO_PAUSE: + vortex_fifo_setadbctrl(vortex, adbdma, dma->dma_unknown, + this_4, this_8, + dma->fifo_enabled ? 1 : 0, 0); + break; + } + dma->fifo_status = FIFO_START; +} + +static void vortex_adbdma_pausefifo(vortex_t * vortex, int adbdma) +{ + stream_t *dma = &vortex->dma_adb[adbdma]; + + int this_8 = 0, this_4 = 0; + switch (dma->fifo_status) { + case FIFO_START: + vortex_fifo_setadbctrl(vortex, adbdma, dma->dma_unknown, + this_4, this_8, 0, 0); + break; + case FIFO_STOP: + hwwrite(vortex->mmio, VORTEX_ADBDMA_CTRL + (adbdma << 2), + dma->dma_ctrl); + vortex_fifo_setadbctrl(vortex, adbdma, dma->dma_unknown, + this_4, this_8, 0, 0); + break; + } + dma->fifo_status = FIFO_PAUSE; +} + +#if 0 // Using pause instead +static void vortex_adbdma_stopfifo(vortex_t * vortex, int adbdma) +{ + stream_t *dma = &vortex->dma_adb[adbdma]; + + int this_4 = 0, this_8 = 0; + if (dma->fifo_status == FIFO_START) + vortex_fifo_setadbctrl(vortex, adbdma, dma->dma_unknown, + this_4, this_8, 0, 0); + else if (dma->fifo_status == FIFO_STOP) + return; + dma->fifo_status = FIFO_STOP; + dma->fifo_enabled = 0; +} + +#endif +/* WTDMA */ + +#ifndef CHIP_AU8810 +static void vortex_wtdma_setfirstbuffer(vortex_t * vortex, int wtdma) +{ + //int this_7c=dma_ctrl; + stream_t *dma = &vortex->dma_wt[wtdma]; + + hwwrite(vortex->mmio, VORTEX_WTDMA_CTRL + (wtdma << 2), dma->dma_ctrl); +} + +static void vortex_wtdma_setstartbuffer(vortex_t * vortex, int wtdma, int sb) +{ + stream_t *dma = &vortex->dma_wt[wtdma]; + //hwwrite(vortex->mmio, VORTEX_WTDMA_START + (wtdma << 2), sb << ((0x1f-(wtdma&0xf)*2))); + hwwrite(vortex->mmio, VORTEX_WTDMA_START + (wtdma << 2), + sb << ((0xf - (wtdma & 0xf)) * 2)); + dma->period_real = dma->period_virt = sb; +} + +static void +vortex_wtdma_setbuffers(vortex_t * vortex, int wtdma, + snd_pcm_sgbuf_t * sgbuf, int psize, int count) +{ + stream_t *dma = &vortex->dma_wt[wtdma]; + + dma->period_bytes = psize; + dma->nr_periods = count; + dma->sgbuf = sgbuf; + + psize--; + + dma->cfg0 = 0; + dma->cfg1 = 0; + switch (count) { + /* Four or more pages */ + default: + case 4: + dma->cfg1 |= 0x88000000 | 0x44000000 | 0x30000000 | psize; + hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4), + snd_sgbuf_get_addr(sgbuf, psize * 3)); + /* 3 pages */ + case 3: + dma->cfg0 |= 0x12000000; + dma->cfg1 |= 0x80000000 | 0x40000000 | (psize << 0xc); + hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4), + snd_sgbuf_get_addr(sgbuf, psize * 2)); + /* 2 pages */ + case 2: + dma->cfg0 |= 0x88000000 | 0x44000000 | 0x10000000 | psize; + hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4), + snd_sgbuf_get_addr(sgbuf, psize)); + /* 1 page */ + case 1: + dma->cfg0 |= 0x80000000 | 0x40000000 | (psize << 0xc); + hwwrite(vortex->mmio, VORTEX_WTDMA_BUFBASE + (wtdma << 4), + snd_sgbuf_get_addr(sgbuf, 0)); + break; + } + hwwrite(vortex->mmio, VORTEX_WTDMA_BUFCFG0 + (wtdma << 3), dma->cfg0); + hwwrite(vortex->mmio, VORTEX_WTDMA_BUFCFG1 + (wtdma << 3), dma->cfg1); + + vortex_wtdma_setfirstbuffer(vortex, wtdma); + vortex_wtdma_setstartbuffer(vortex, wtdma, 0); +} + +static void +vortex_wtdma_setmode(vortex_t * vortex, int wtdma, int ie, int fmt, int d, + /*int e, */ unsigned long offset) +{ + stream_t *dma = &vortex->dma_wt[wtdma]; + + //dma->this_08 = e; + dma->dma_unknown = d; + dma->dma_ctrl = 0; + dma->dma_ctrl = + ((offset & OFFSET_MASK) | (dma->dma_ctrl & ~OFFSET_MASK)); + /* PCMOUT interrupt */ + dma->dma_ctrl = + (dma->dma_ctrl & ~IE_MASK) | ((ie << IE_SHIFT) & IE_MASK); + /* Always playback. */ + dma->dma_ctrl |= (1 << DIR_SHIFT); + /* Audio Format */ + dma->dma_ctrl = + (dma->dma_ctrl & FMT_MASK) | ((fmt << FMT_SHIFT) & FMT_MASK); + /* Write into hardware */ + hwwrite(vortex->mmio, VORTEX_WTDMA_CTRL + (wtdma << 2), dma->dma_ctrl); +} + +static int vortex_wtdma_bufshift(vortex_t * vortex, int wtdma) +{ + stream_t *dma = &vortex->dma_wt[wtdma]; + int page, p, pp, delta, i; + + page = + (hwread(vortex->mmio, VORTEX_WTDMA_STAT + (wtdma << 2)) & + WT_SUBBUF_MASK) + >> WT_SUBBUF_SHIFT; + if (dma->nr_periods >= 4) + delta = (page - dma->period_real) & 3; + else { + delta = (page - dma->period_real); + if (delta < 0) + delta += dma->nr_periods; + } + if (delta == 0) + return 0; + + /* refresh hw page table */ + if (dma->nr_periods > 4) { + for (i = 0; i < delta; i++) { + /* p: audio buffer page index */ + p = dma->period_virt + i + 4; + if (p >= dma->nr_periods) + p -= dma->nr_periods; + /* pp: hardware DMA page index. */ + pp = dma->period_real + i; + if (pp >= 4) + pp -= 4; + hwwrite(vortex->mmio, + VORTEX_WTDMA_BUFBASE + + (((wtdma << 2) + pp) << 2), + snd_sgbuf_get_addr(dma->sgbuf, dma->period_bytes * p)); + /* Force write thru cache. */ + hwread(vortex->mmio, VORTEX_WTDMA_BUFBASE + + (((wtdma << 2) + pp) << 2)); + } + } + dma->period_virt += delta; + if (dma->period_virt >= dma->nr_periods) + dma->period_virt -= dma->nr_periods; + dma->period_real = page; + + if (delta != 1) + printk(KERN_WARNING "vortex: wt virt = %d, delta = %d\n", + dma->period_virt, delta); + + return delta; +} + +#if 0 +static void +vortex_wtdma_getposition(vortex_t * vortex, int wtdma, int *subbuf, int *pos) +{ + int temp; + temp = hwread(vortex->mmio, VORTEX_WTDMA_STAT + (wtdma << 2)); + *subbuf = (temp >> WT_SUBBUF_SHIFT) & WT_SUBBUF_MASK; + *pos = temp & POS_MASK; +} + +static int vortex_wtdma_getcursubuffer(vortex_t * vortex, int wtdma) +{ + return ((hwread(vortex->mmio, VORTEX_WTDMA_STAT + (wtdma << 2)) >> + POS_SHIFT) & POS_MASK); +} +#endif +static int inline vortex_wtdma_getlinearpos(vortex_t * vortex, int wtdma) +{ + stream_t *dma = &vortex->dma_wt[wtdma]; + int temp; + + temp = hwread(vortex->mmio, VORTEX_WTDMA_STAT + (wtdma << 2)); + //temp = (temp & POS_MASK) + (((temp>>WT_SUBBUF_SHIFT) & WT_SUBBUF_MASK)*(dma->cfg0&POS_MASK)); + temp = (temp & POS_MASK) + ((dma->period_virt) * (dma->period_bytes)); + return temp; +} + +static void vortex_wtdma_startfifo(vortex_t * vortex, int wtdma) +{ + stream_t *dma = &vortex->dma_wt[wtdma]; + int this_8 = 0, this_4 = 0; + + switch (dma->fifo_status) { + case FIFO_START: + vortex_fifo_setwtvalid(vortex, wtdma, + dma->fifo_enabled ? 1 : 0); + break; + case FIFO_STOP: + this_8 = 1; + hwwrite(vortex->mmio, VORTEX_WTDMA_CTRL + (wtdma << 2), + dma->dma_ctrl); + vortex_fifo_setwtctrl(vortex, wtdma, dma->dma_unknown, + this_4, this_8, + dma->fifo_enabled ? 1 : 0, 0); + break; + case FIFO_PAUSE: + vortex_fifo_setwtctrl(vortex, wtdma, dma->dma_unknown, + this_4, this_8, + dma->fifo_enabled ? 1 : 0, 0); + break; + } + dma->fifo_status = FIFO_START; +} + +static void vortex_wtdma_resumefifo(vortex_t * vortex, int wtdma) +{ + stream_t *dma = &vortex->dma_wt[wtdma]; + + int this_8 = 0, this_4 = 0; + switch (dma->fifo_status) { + case FIFO_STOP: + hwwrite(vortex->mmio, VORTEX_WTDMA_CTRL + (wtdma << 2), + dma->dma_ctrl); + vortex_fifo_setwtctrl(vortex, wtdma, dma->dma_unknown, + this_4, this_8, + dma->fifo_enabled ? 1 : 0, 0); + break; + case FIFO_PAUSE: + vortex_fifo_setwtctrl(vortex, wtdma, dma->dma_unknown, + this_4, this_8, + dma->fifo_enabled ? 1 : 0, 0); + break; + } + dma->fifo_status = FIFO_START; +} + +static void vortex_wtdma_pausefifo(vortex_t * vortex, int wtdma) +{ + stream_t *dma = &vortex->dma_wt[wtdma]; + + int this_8 = 0, this_4 = 0; + switch (dma->fifo_status) { + case FIFO_START: + vortex_fifo_setwtctrl(vortex, wtdma, dma->dma_unknown, + this_4, this_8, 0, 0); + break; + case FIFO_STOP: + hwwrite(vortex->mmio, VORTEX_WTDMA_CTRL + (wtdma << 2), + dma->dma_ctrl); + vortex_fifo_setwtctrl(vortex, wtdma, dma->dma_unknown, + this_4, this_8, 0, 0); + break; + } + dma->fifo_status = FIFO_PAUSE; +} + +static void vortex_wtdma_stopfifo(vortex_t * vortex, int wtdma) +{ + stream_t *dma = &vortex->dma_wt[wtdma]; + + int this_4 = 0, this_8 = 0; + if (dma->fifo_status == FIFO_START) + vortex_fifo_setwtctrl(vortex, wtdma, dma->dma_unknown, + this_4, this_8, 0, 0); + else if (dma->fifo_status == FIFO_STOP) + return; + dma->fifo_status = FIFO_STOP; + dma->fifo_enabled = 0; +} + +#endif +/* ADB Routes */ + +typedef int ADBRamLink; +static void vortex_adb_init(vortex_t * vortex) +{ + int i; + /* it looks like we are writing more than we need to... + * if we write what we are supposed to it breaks things... */ + hwwrite(vortex->mmio, VORTEX_ADB_SR, 0); + for (i = 0; i < VORTEX_ADB_RTBASE_SIZE; i++) + hwwrite(vortex->mmio, VORTEX_ADB_RTBASE + (i << 2), + hwread(vortex->mmio, + VORTEX_ADB_RTBASE + (i << 2)) | ROUTE_MASK); + for (i = 0; i < VORTEX_ADB_CHNBASE_SIZE; i++) { + hwwrite(vortex->mmio, VORTEX_ADB_CHNBASE + (i << 2), + hwread(vortex->mmio, + VORTEX_ADB_CHNBASE + (i << 2)) | ROUTE_MASK); + } +} + +static void vortex_adb_en_sr(vortex_t * vortex, int channel) +{ + hwwrite(vortex->mmio, VORTEX_ADB_SR, + hwread(vortex->mmio, VORTEX_ADB_SR) | (0x1 << channel)); +} + +static void vortex_adb_dis_sr(vortex_t * vortex, int channel) +{ + hwwrite(vortex->mmio, VORTEX_ADB_SR, + hwread(vortex->mmio, VORTEX_ADB_SR) & ~(0x1 << channel)); +} + +static void +vortex_adb_addroutes(vortex_t * vortex, unsigned char channel, + ADBRamLink * route, int rnum) +{ + int temp, prev, lifeboat = 0; + + if ((rnum <= 0) || (route == NULL)) + return; + /* Write last routes. */ + rnum--; + hwwrite(vortex->mmio, + VORTEX_ADB_RTBASE + ((route[rnum] & ADB_MASK) << 2), + ROUTE_MASK); + while (rnum > 0) { + hwwrite(vortex->mmio, + VORTEX_ADB_RTBASE + + ((route[rnum - 1] & ADB_MASK) << 2), route[rnum]); + rnum--; + } + /* Write first route. */ + temp = + hwread(vortex->mmio, + VORTEX_ADB_CHNBASE + (channel << 2)) & ADB_MASK; + if (temp == ADB_MASK) { + /* First entry on this channel. */ + hwwrite(vortex->mmio, VORTEX_ADB_CHNBASE + (channel << 2), + route[0]); + vortex_adb_en_sr(vortex, channel); + return; + } + /* Not first entry on this channel. Need to link. */ + do { + prev = temp; + temp = + hwread(vortex->mmio, + VORTEX_ADB_RTBASE + (temp << 2)) & ADB_MASK; + if ((lifeboat++) > ADB_MASK) { + printk(KERN_ERR + "vortex_adb_addroutes: unending route! 0x%x\n", + *route); + return; + } + } + while (temp != ADB_MASK); + hwwrite(vortex->mmio, VORTEX_ADB_RTBASE + (prev << 2), route[0]); +} + +static void +vortex_adb_delroutes(vortex_t * vortex, unsigned char channel, + ADBRamLink route0, ADBRamLink route1) +{ + int temp, lifeboat = 0, prev; + + /* Find route. */ + temp = + hwread(vortex->mmio, + VORTEX_ADB_CHNBASE + (channel << 2)) & ADB_MASK; + if (temp == (route0 & ADB_MASK)) { + temp = + hwread(vortex->mmio, + VORTEX_ADB_RTBASE + ((route1 & ADB_MASK) << 2)); + if ((temp & ADB_MASK) == ADB_MASK) + vortex_adb_dis_sr(vortex, channel); + hwwrite(vortex->mmio, VORTEX_ADB_CHNBASE + (channel << 2), + temp); + return; + } + do { + prev = temp; + temp = + hwread(vortex->mmio, + VORTEX_ADB_RTBASE + (prev << 2)) & ADB_MASK; + if (((lifeboat++) > ADB_MASK) || (temp == ADB_MASK)) { + printk(KERN_ERR + "vortex_adb_delroutes: route not found! 0x%x\n", + route0); + return; + } + } + while (temp != (route0 & ADB_MASK)); + temp = hwread(vortex->mmio, VORTEX_ADB_RTBASE + (temp << 2)); + if ((temp & ADB_MASK) == route1) + temp = hwread(vortex->mmio, VORTEX_ADB_RTBASE + (temp << 2)); + /* Make bridge over deleted route. */ + hwwrite(vortex->mmio, VORTEX_ADB_RTBASE + (prev << 2), temp); +} + +static void +vortex_route(vortex_t * vortex, int en, unsigned char channel, + unsigned char source, unsigned char dest) +{ + ADBRamLink route; + + route = ((source & ADB_MASK) << ADB_SHIFT) | (dest & ADB_MASK); + if (en) { + vortex_adb_addroutes(vortex, channel, &route, 1); + if ((source < (OFFSET_SRCOUT + NR_SRC)) + && (source >= OFFSET_SRCOUT)) + vortex_src_addWTD(vortex, (source - OFFSET_SRCOUT), + channel); + else if ((source < (OFFSET_MIXOUT + NR_MIXOUT)) + && (source >= OFFSET_MIXOUT)) + vortex_mixer_addWTD(vortex, + (source - OFFSET_MIXOUT), channel); + } else { + vortex_adb_delroutes(vortex, channel, route, route); + if ((source < (OFFSET_SRCOUT + NR_SRC)) + && (source >= OFFSET_SRCOUT)) + vortex_src_delWTD(vortex, (source - OFFSET_SRCOUT), + channel); + else if ((source < (OFFSET_MIXOUT + NR_MIXOUT)) + && (source >= OFFSET_MIXOUT)) + vortex_mixer_delWTD(vortex, + (source - OFFSET_MIXOUT), channel); + } +} + +#if 0 +static void +vortex_routes(vortex_t * vortex, int en, unsigned char channel, + unsigned char source, unsigned char dest0, unsigned char dest1) +{ + ADBRamLink route[2]; + + route[0] = ((source & ADB_MASK) << ADB_SHIFT) | (dest0 & ADB_MASK); + route[1] = ((source & ADB_MASK) << ADB_SHIFT) | (dest1 & ADB_MASK); + + if (en) { + vortex_adb_addroutes(vortex, channel, route, 2); + if ((source < (OFFSET_SRCOUT + NR_SRC)) + && (source >= (OFFSET_SRCOUT))) + vortex_src_addWTD(vortex, (source - OFFSET_SRCOUT), + channel); + else if ((source < (OFFSET_MIXOUT + NR_MIXOUT)) + && (source >= (OFFSET_MIXOUT))) + vortex_mixer_addWTD(vortex, + (source - OFFSET_MIXOUT), channel); + } else { + vortex_adb_delroutes(vortex, channel, route[0], route[1]); + if ((source < (OFFSET_SRCOUT + NR_SRC)) + && (source >= (OFFSET_SRCOUT))) + vortex_src_delWTD(vortex, (source - OFFSET_SRCOUT), + channel); + else if ((source < (OFFSET_MIXOUT + NR_MIXOUT)) + && (source >= (OFFSET_MIXOUT))) + vortex_mixer_delWTD(vortex, + (source - OFFSET_MIXOUT), channel); + } +} + +#endif +/* Route two sources to same target. Sources must be of same class !!! */ +static void +vortex_routeLRT(vortex_t * vortex, int en, unsigned char ch, + unsigned char source0, unsigned char source1, + unsigned char dest) +{ + ADBRamLink route[2]; + + route[0] = ((source0 & ADB_MASK) << ADB_SHIFT) | (dest & ADB_MASK); + route[1] = ((source1 & ADB_MASK) << ADB_SHIFT) | (dest & ADB_MASK); + + if (dest < 0x10) + route[1] = (route[1] & ~ADB_MASK) | (dest + 0x20); /* fifo A */ + + if (en) { + vortex_adb_addroutes(vortex, ch, route, 2); + if ((source0 < (OFFSET_SRCOUT + NR_SRC)) + && (source0 >= OFFSET_SRCOUT)) { + vortex_src_addWTD(vortex, + (source0 - OFFSET_SRCOUT), ch); + vortex_src_addWTD(vortex, + (source1 - OFFSET_SRCOUT), ch); + } else if ((source0 < (OFFSET_MIXOUT + NR_MIXOUT)) + && (source0 >= OFFSET_MIXOUT)) { + vortex_mixer_addWTD(vortex, + (source0 - OFFSET_MIXOUT), ch); + vortex_mixer_addWTD(vortex, + (source1 - OFFSET_MIXOUT), ch); + } + } else { + vortex_adb_delroutes(vortex, ch, route[0], route[1]); + if ((source0 < (OFFSET_SRCOUT + NR_SRC)) + && (source0 >= OFFSET_SRCOUT)) { + vortex_src_delWTD(vortex, + (source0 - OFFSET_SRCOUT), ch); + vortex_src_delWTD(vortex, + (source1 - OFFSET_SRCOUT), ch); + } else if ((source0 < (OFFSET_MIXOUT + NR_MIXOUT)) + && (source0 >= OFFSET_MIXOUT)) { + vortex_mixer_delWTD(vortex, + (source0 - OFFSET_MIXOUT), ch); + vortex_mixer_delWTD(vortex, + (source1 - OFFSET_MIXOUT), ch); + } + } +} + +/* Connection stuff */ + +// Connect adbdma to src('s). +static void +vortex_connection_adbdma_src(vortex_t * vortex, int en, unsigned char ch, + unsigned char adbdma, unsigned char src) +{ + vortex_route(vortex, en, ch, ADB_DMA(adbdma), ADB_SRCIN(src)); +} + +// Connect SRC to mixin. +static void +vortex_connection_src_mixin(vortex_t * vortex, int en, + unsigned char channel, unsigned char src, + unsigned char mixin) +{ + vortex_route(vortex, en, channel, ADB_SRCOUT(src), ADB_MIXIN(mixin)); +} + +// Connect mixin with mix output. +static void +vortex_connection_mixin_mix(vortex_t * vortex, int en, unsigned char mixin, + unsigned char mix, int a) +{ + if (en) { + vortex_mix_enableinput(vortex, mix, mixin); + vortex_mix_setinputvolumebyte(vortex, mix, mixin, MIX_DEFIGAIN); // added to original code. + } else + vortex_mix_disableinput(vortex, mix, mixin, a); +} + +// Connect absolut address to mixin. +static void +vortex_connection_adb_mixin(vortex_t * vortex, int en, + unsigned char channel, unsigned char source, + unsigned char mixin) +{ + vortex_route(vortex, en, channel, source, ADB_MIXIN(mixin)); +} + +static void +vortex_connection_src_adbdma(vortex_t * vortex, int en, unsigned char ch, + unsigned char src, unsigned char adbdma) +{ + vortex_route(vortex, en, ch, ADB_SRCOUT(src), ADB_DMA(adbdma)); +} + +static void +vortex_connection_src_src_adbdma(vortex_t * vortex, int en, + unsigned char ch, unsigned char src0, + unsigned char src1, unsigned char adbdma) +{ + + vortex_routeLRT(vortex, en, ch, ADB_SRCOUT(src0), ADB_SRCOUT(src1), + ADB_DMA(adbdma)); +} + +// mix to absolut address. +static void +vortex_connection_mix_adb(vortex_t * vortex, int en, unsigned char ch, + unsigned char mix, unsigned char dest) +{ + vortex_route(vortex, en, ch, ADB_MIXOUT(mix), dest); + vortex_mix_setvolumebyte(vortex, mix, MIX_DEFOGAIN); // added to original code. +} + +// mixer to src. +static void +vortex_connection_mix_src(vortex_t * vortex, int en, unsigned char ch, + unsigned char mix, unsigned char src) +{ + vortex_route(vortex, en, ch, ADB_MIXOUT(mix), ADB_SRCIN(src)); + vortex_mix_setvolumebyte(vortex, mix, MIX_DEFOGAIN); // added to original code. +} + +#if 0 +static void +vortex_connection_adbdma_src_src(vortex_t * vortex, int en, + unsigned char channel, + unsigned char adbdma, unsigned char src0, + unsigned char src1) +{ + vortex_routes(vortex, en, channel, ADB_DMA(adbdma), + ADB_SRCIN(src0), ADB_SRCIN(src1)); +} + +// Connect two mix to AdbDma. +static void +vortex_connection_mix_mix_adbdma(vortex_t * vortex, int en, + unsigned char ch, unsigned char mix0, + unsigned char mix1, unsigned char adbdma) +{ + + ADBRamLink routes[2]; + routes[0] = + (((mix0 + + OFFSET_MIXOUT) & ADB_MASK) << ADB_SHIFT) | (adbdma & ADB_MASK); + routes[1] = + (((mix1 + OFFSET_MIXOUT) & ADB_MASK) << ADB_SHIFT) | ((adbdma + + 0x20) & + ADB_MASK); + if (en) { + vortex_adb_addroutes(vortex, ch, routes, 0x2); + vortex_mixer_addWTD(vortex, mix0, ch); + vortex_mixer_addWTD(vortex, mix1, ch); + } else { + vortex_adb_delroutes(vortex, ch, routes[0], routes[1]); + vortex_mixer_delWTD(vortex, mix0, ch); + vortex_mixer_delWTD(vortex, mix1, ch); + } +} +#endif + +/* CODEC connect. */ + +static void +vortex_connect_codecplay(vortex_t * vortex, int en, unsigned char mixers[]) +{ +#ifdef CHIP_AU8820 + vortex_connection_mix_adb(vortex, en, 0x11, mixers[0], ADB_CODECOUT(0)); + vortex_connection_mix_adb(vortex, en, 0x11, mixers[1], ADB_CODECOUT(1)); +#else +#if 1 + // Connect front channels through EQ. + vortex_connection_mix_adb(vortex, en, 0x11, mixers[0], ADB_EQIN(0)); + vortex_connection_mix_adb(vortex, en, 0x11, mixers[1], ADB_EQIN(1)); + vortex_route(vortex, en, 0x11, ADB_EQOUT(0), ADB_CODECOUT(0)); + vortex_route(vortex, en, 0x11, ADB_EQOUT(1), ADB_CODECOUT(1)); + + /* Check if reg 0x28 has SDAC bit set. */ + if (VORTEX_IS_QUAD(vortex)) { + /* Rear channel. Note: ADB_CODECOUT(0+2) and (1+2) is for AC97 modem */ + vortex_connection_mix_adb(vortex, en, 0x11, mixers[2], + ADB_CODECOUT(0 + 4)); + vortex_connection_mix_adb(vortex, en, 0x11, mixers[3], + ADB_CODECOUT(1 + 4)); + //printk("SDAC detected "); + } +#else + // Use plain direct output to codec. + vortex_connection_mix_adb(vortex, en, 0x11, mixers[0], ADB_CODECOUT(0)); + vortex_connection_mix_adb(vortex, en, 0x11, mixers[1], ADB_CODECOUT(1)); +#endif +#endif +} + +static void +vortex_connect_codecrec(vortex_t * vortex, int en, unsigned char mixin0, + unsigned char mixin1) +{ + /* + Enable: 0x1, 0x1 + Channel: 0x11, 0x11 + ADB Source address: 0x48, 0x49 + Destination Asp4Topology_0x9c,0x98 + */ + vortex_connection_adb_mixin(vortex, en, 0x11, ADB_CODECIN(0), mixin0); + vortex_connection_adb_mixin(vortex, en, 0x11, ADB_CODECIN(1), mixin1); +} + +// Higher level ADB audio path (de)allocator. + +/* Resource manager */ +static int resnum[VORTEX_RESOURCE_LAST] = + { NR_ADB, NR_SRC, NR_MIXIN, NR_MIXOUT, NR_A3D }; +/* + Checkout/Checkin resource of given type. + resmap: resource map to be used. If NULL means that we want to allocate + a DMA resource (root of all other resources of a dma channel). + out: Mean checkout if != 0. Else mean Checkin resource. + restype: Indicates type of resource to be checked in or out. +*/ +static char +vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, int restype) +{ + int i, qty = resnum[restype], resinuse = 0; + + if (out) { + /* Gather used resources by all streams. */ + for (i = 0; i < NR_ADB; i++) { + resinuse |= vortex->dma_adb[i].resources[restype]; + } + resinuse |= vortex->fixed_res[restype]; + /* Find and take free resource. */ + for (i = 0; i < qty; i++) { + if ((resinuse & (1 << i)) == 0) { + if (resmap != NULL) + resmap[restype] |= (1 << i); + else + vortex->dma_adb[i].resources[restype] |= (1 << i); + //printk("vortex: ResManager: type %d out %d\n", restype, i); + return i; + } + } + } else { + if (resmap == NULL) + return -EINVAL; + /* Checkin first resource of type restype. */ + for (i = 0; i < qty; i++) { + if (resmap[restype] & (1 << i)) { + resmap[restype] &= ~(1 << i); + //printk("vortex: ResManager: type %d in %d\n",restype, i); + return i; + } + } + } + printk("vortex: FATAL: ResManager: resource type %d exhausted.\n", restype); + return -ENOMEM; +} + +/* Default Connections */ +static void vortex_connect_default(vortex_t * vortex, int en) +{ + // FIXME: check if checkout was succesful. + // Connect AC97 codec. + vortex->mixplayb[0] = vortex_adb_checkinout(vortex, vortex->fixed_res, en, + VORTEX_RESOURCE_MIXOUT); + vortex->mixplayb[1] = vortex_adb_checkinout(vortex, vortex->fixed_res, en, + VORTEX_RESOURCE_MIXOUT); + if (VORTEX_IS_QUAD(vortex)) { + vortex->mixplayb[2] = vortex_adb_checkinout(vortex, vortex->fixed_res, en, + VORTEX_RESOURCE_MIXOUT); + vortex->mixplayb[3] = vortex_adb_checkinout(vortex, vortex->fixed_res, en, + VORTEX_RESOURCE_MIXOUT); + } + vortex_connect_codecplay(vortex, en, vortex->mixplayb); + + vortex->mixcapt[0] = vortex_adb_checkinout(vortex, vortex->fixed_res, en, + VORTEX_RESOURCE_MIXIN); + vortex->mixcapt[1] = vortex_adb_checkinout(vortex, vortex->fixed_res, en, + VORTEX_RESOURCE_MIXIN); + vortex_connect_codecrec(vortex, en, MIX_CAPT(0), MIX_CAPT(1)); + + // Connect SPDIF +#ifndef CHIP_AU8820 + vortex->mixspdif[0] = vortex_adb_checkinout(vortex, vortex->fixed_res, en, + VORTEX_RESOURCE_MIXOUT); + vortex->mixspdif[1] = vortex_adb_checkinout(vortex, vortex->fixed_res, en, + VORTEX_RESOURCE_MIXOUT); + vortex_connection_mix_adb(vortex, en, 0x14, vortex->mixspdif[0], + ADB_SPDIFOUT(0)); + vortex_connection_mix_adb(vortex, en, 0x14, vortex->mixspdif[1], + ADB_SPDIFOUT(1)); +#endif + // Connect WT +#ifndef CHIP_AU8810 + vortex_wt_connect(vortex, en); +#endif + // A3D (crosstalk canceler and A3D slices). +#ifndef CHIP_AU8820 + vortex_Vort3D_connect(vortex, en); +#endif + // Connect I2S + + // Connect DSP interface for SQ3500 turbo (not here i think...) + + // Connect AC98 modem codec + + /* Fast Play Workaround */ +#ifndef CHIP_AU8820 + vortex->fixed_res[VORTEX_RESOURCE_DMA] = 0x00000001; +#endif + // Channel swapping workaround. We are nuking registers somewhere, or + // its a hardware bug. + vortex->fixed_res[VORTEX_RESOURCE_SRC] = 0x00000001; +} + +/* + Allocate nr_ch pcm audio routes if dma < 0. If dma >= 0, existing routes + are deallocated. + dma: DMA engine routes to be deallocated when dma >= 0. + nr_ch: Number of channels to be de/allocated. + dir: direction of stream. Uses same values as substream->stream. + type: Type of audio output/source (codec, spdif, i2s, dsp, etc) + Return: Return allocated DMA or same DMA passed as "dma" when dma >= 0. +*/ +static int +vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, int dir, int type) +{ + stream_t *stream; + int i, en; + + if ((nr_ch == 3) + || ((dir == SNDRV_PCM_STREAM_CAPTURE) && (nr_ch > 2))) + return -EBUSY; + + spin_lock(&vortex->lock); + if (dma >= 0) { + en = 0; + vortex_adb_checkinout(vortex, + vortex->dma_adb[dma].resources, en, + VORTEX_RESOURCE_DMA); + } else { + en = 1; + if ((dma = + vortex_adb_checkinout(vortex, NULL, en, + VORTEX_RESOURCE_DMA)) < 0) + return -EBUSY; + } + + stream = &vortex->dma_adb[dma]; + stream->dma = dma; + stream->dir = dir; + stream->type = type; + + // FIXME: check for success of checkout or checkin. + /* PLAYBACK ROUTES. */ + if (dir == SNDRV_PCM_STREAM_PLAYBACK) { + int src[4], mix[4], ch_top; +#ifndef CHIP_AU8820 + int a3d = 0; +#endif + /* Get SRC and MIXER hardware resources. */ + if (stream->type != VORTEX_PCM_SPDIF) { + for (i = 0; i < nr_ch; i++) { + if ((src[i] = vortex_adb_checkinout(vortex, + stream->resources, en, + VORTEX_RESOURCE_SRC)) < 0) { + memset(stream->resources, 0, + sizeof(unsigned char) * + VORTEX_RESOURCE_LAST); + return -EBUSY; + } + if (stream->type != VORTEX_PCM_A3D) { + if ((mix[i] = vortex_adb_checkinout(vortex, + stream->resources, + en, + VORTEX_RESOURCE_MIXIN)) < 0) { + memset(stream->resources, + 0, + sizeof(unsigned char) * VORTEX_RESOURCE_LAST); + return -EBUSY; + } + } + } + } +#ifndef CHIP_AU8820 + if (stream->type == VORTEX_PCM_A3D) { + if ((a3d = + vortex_adb_checkinout(vortex, + stream->resources, en, + VORTEX_RESOURCE_A3D)) < 0) { + memset(stream->resources, 0, + sizeof(unsigned char) * + VORTEX_RESOURCE_LAST); + printk("vortex: out of A3D sources. Sorry\n"); + return -EBUSY; + } + /* (De)Initialize A3D hardware source. */ + vortex_Vort3D_InitializeSource(&(vortex->a3d[a3d]), en); + } + /* Make SPDIF out exclusive to "spdif" device when in use. */ + if ((stream->type == VORTEX_PCM_SPDIF) && (en)) { + vortex_route(vortex, 0, 0x14, + ADB_MIXOUT(vortex->mixspdif[0]), + ADB_SPDIFOUT(0)); + vortex_route(vortex, 0, 0x14, + ADB_MIXOUT(vortex->mixspdif[1]), + ADB_SPDIFOUT(1)); + } +#endif + /* Make playback routes. */ + for (i = 0; i < nr_ch; i++) { + if (stream->type == VORTEX_PCM_ADB) { + vortex_connection_adbdma_src(vortex, en, + //src[nr_ch - 1], + src[0], + dma, + src[i]); + vortex_connection_src_mixin(vortex, en, + 0x11, src[i], + mix[i]); + vortex_connection_mixin_mix(vortex, en, + mix[i], + MIX_PLAYB(i), 0); +#ifndef CHIP_AU8820 + vortex_connection_mixin_mix(vortex, en, + mix[i], + MIX_SPDIF(i % 2), 0); + vortex_mix_setinputvolumebyte(vortex, + MIX_SPDIF(i % 2), + mix[i], + MIX_DEFIGAIN); +#endif + } +#ifndef CHIP_AU8820 + if (stream->type == VORTEX_PCM_A3D) { + vortex_connection_adbdma_src(vortex, en, + src[0], + dma, + src[i]); + vortex_route(vortex, en, 0x11, ADB_SRCOUT(src[i]), ADB_A3DIN(a3d)); + /* XTalk test. */ + //vortex_route(vortex, en, 0x11, dma, ADB_XTALKIN(i?9:4)); + //vortex_route(vortex, en, 0x11, ADB_SRCOUT(src[i]), ADB_XTALKIN(i?4:9)); + } + if (stream->type == VORTEX_PCM_SPDIF) + vortex_route(vortex, en, 0x14, + ADB_DMA(stream->dma), + ADB_SPDIFOUT(i)); +#endif + } + if (stream->type != VORTEX_PCM_SPDIF && stream->type != VORTEX_PCM_A3D) { + ch_top = (VORTEX_IS_QUAD(vortex) ? 4 : 2); + for (i = nr_ch; i < ch_top; i++) { + vortex_connection_mixin_mix(vortex, en, + mix[i % nr_ch], + MIX_PLAYB(i), 0); +#ifndef CHIP_AU8820 + vortex_connection_mixin_mix(vortex, en, + mix[i % nr_ch], + MIX_SPDIF(i % 2), + 0); + vortex_mix_setinputvolumebyte(vortex, + MIX_SPDIF(i % 2), + mix[i % nr_ch], + MIX_DEFIGAIN); +#endif + } + } +#ifndef CHIP_AU8820 + else { + if (nr_ch == 1 && stream->type == VORTEX_PCM_SPDIF) + vortex_route(vortex, en, 0x14, + ADB_DMA(stream->dma), + ADB_SPDIFOUT(1)); + } + /* Reconnect SPDIF out when "spdif" device is down. */ + if ((stream->type == VORTEX_PCM_SPDIF) && (!en)) { + vortex_route(vortex, 1, 0x14, + ADB_MIXOUT(vortex->mixspdif[0]), + ADB_SPDIFOUT(0)); + vortex_route(vortex, 1, 0x14, + ADB_MIXOUT(vortex->mixspdif[1]), + ADB_SPDIFOUT(1)); + } +#endif + /* CAPTURE ROUTES. */ + } else { + int src[2], mix[2]; + + /* Get SRC and MIXER hardware resources. */ + for (i = 0; i < nr_ch; i++) { + if ((mix[i] = + vortex_adb_checkinout(vortex, + stream->resources, en, + VORTEX_RESOURCE_MIXOUT)) + < 0) { + memset(stream->resources, 0, + sizeof(unsigned char) * + VORTEX_RESOURCE_LAST); + return -EBUSY; + } + if ((src[i] = + vortex_adb_checkinout(vortex, + stream->resources, en, + VORTEX_RESOURCE_SRC)) < 0) { + memset(stream->resources, 0, + sizeof(unsigned char) * + VORTEX_RESOURCE_LAST); + return -EBUSY; + } + } + + /* Make capture routes. */ + vortex_connection_mixin_mix(vortex, en, MIX_CAPT(0), mix[0], 0); + vortex_connection_mix_src(vortex, en, 0x11, mix[0], src[0]); + if (nr_ch == 1) { + vortex_connection_mixin_mix(vortex, en, + MIX_CAPT(1), mix[0], 0); + vortex_connection_src_adbdma(vortex, en, + src[nr_ch - 1], + src[0], dma); + } else { + vortex_connection_mixin_mix(vortex, en, + MIX_CAPT(1), mix[1], 0); + vortex_connection_mix_src(vortex, en, 0x11, mix[1], + src[1]); + vortex_connection_src_src_adbdma(vortex, en, + src[0], src[0], + src[1], dma); + } + } + vortex->dma_adb[dma].nr_ch = nr_ch; + spin_unlock(&vortex->lock); + +#if 0 + /* AC97 Codec channel setup. FIXME: this has no effect on some cards !! */ + if (nr_ch < 4) { + /* Copy stereo to rear channel (surround) */ + snd_ac97_write_cache(vortex->codec, + AC97_SIGMATEL_DAC2INVERT, + snd_ac97_read(vortex->codec, + AC97_SIGMATEL_DAC2INVERT) + | 4); + } else { + /* Allow separate front and rear channels. */ + snd_ac97_write_cache(vortex->codec, + AC97_SIGMATEL_DAC2INVERT, + snd_ac97_read(vortex->codec, + AC97_SIGMATEL_DAC2INVERT) + & ~((u32) + 4)); + } +#endif + return dma; +} + +/* + Set the SampleRate of the SRC's attached to the given DMA engine. + */ +static void +vortex_adb_setsrc(vortex_t * vortex, int adbdma, unsigned int rate, int dir) +{ + stream_t *stream = &(vortex->dma_adb[adbdma]); + int i, cvrt; + + /* dir=1:play ; dir=0:rec */ + if (dir) + cvrt = SRC_RATIO(rate, 48000); + else + cvrt = SRC_RATIO(48000, rate); + + /* Setup SRC's */ + for (i = 0; i < NR_SRC; i++) { + if (stream->resources[VORTEX_RESOURCE_SRC] & (1 << i)) + vortex_src_setupchannel(vortex, i, cvrt, 0, 0, i, dir, 1, cvrt, dir); + } +} + +// Timer and ISR functions. + +static void vortex_settimer(vortex_t * vortex, int period) +{ + //set the timer period to 48000ths of a second. + hwwrite(vortex->mmio, VORTEX_IRQ_STAT, period); +} + +#if 0 +static void vortex_enable_timer_int(vortex_t * card) +{ + hwwrite(card->mmio, VORTEX_IRQ_CTRL, + hwread(card->mmio, VORTEX_IRQ_CTRL) | IRQ_TIMER | 0x60); +} + +static void vortex_disable_timer_int(vortex_t * card) +{ + hwwrite(card->mmio, VORTEX_IRQ_CTRL, + hwread(card->mmio, VORTEX_IRQ_CTRL) & ~IRQ_TIMER); +} + +#endif +static void vortex_enable_int(vortex_t * card) +{ + // CAsp4ISR__EnableVortexInt_void_ + hwwrite(card->mmio, VORTEX_CTRL, + hwread(card->mmio, VORTEX_CTRL) | CTRL_IRQ_ENABLE); + hwwrite(card->mmio, VORTEX_IRQ_CTRL, + (hwread(card->mmio, VORTEX_IRQ_CTRL) & 0xffffefc0) | 0x24); +} + +static void vortex_disable_int(vortex_t * card) +{ + hwwrite(card->mmio, VORTEX_CTRL, + hwread(card->mmio, VORTEX_CTRL) & ~CTRL_IRQ_ENABLE); +} + +static irqreturn_t vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + vortex_t *vortex = snd_magic_cast(vortex_t, dev_id, return IRQ_NONE); + int i, handled; + u32 source; + + //check if the interrupt is ours. + if (!(hwread(vortex->mmio, VORTEX_STAT) & 0x1)) + return IRQ_NONE; + + // This is the Interrrupt Enable flag we set before (consistency check). + if (!(hwread(vortex->mmio, VORTEX_CTRL) & CTRL_IRQ_ENABLE)) + return IRQ_NONE; + + source = hwread(vortex->mmio, VORTEX_IRQ_SOURCE); + // Reset IRQ flags. + hwwrite(vortex->mmio, VORTEX_IRQ_SOURCE, source); + hwread(vortex->mmio, VORTEX_IRQ_SOURCE); + // Is at least one IRQ flag set? + if (source == 0) { + printk(KERN_ERR "vortex: missing irq source\n"); + return IRQ_NONE; + } + + handled = 0; + // Attend every interrupt source. + if (unlikely(source & IRQ_ERR_MASK)) { + if (source & IRQ_FATAL) { + printk(KERN_ERR "vortex: IRQ fatal error\n"); + } + if (source & IRQ_PARITY) { + printk(KERN_ERR "vortex: IRQ parity error\n"); + } + if (source & IRQ_REG) { + printk(KERN_ERR "vortex: IRQ reg error\n"); + } + if (source & IRQ_FIFO) { + printk(KERN_ERR "vortex: IRQ fifo error\n"); + } + if (source & IRQ_DMA) { + printk(KERN_ERR "vortex: IRQ dma error\n"); + } + handled = 1; + } + if (source & IRQ_PCMOUT) { + /* ALSA period acknowledge. */ + for (i = 0; i < NR_ADB; i++) { + if (vortex->dma_adb[i].fifo_status == FIFO_START) { + if (vortex_adbdma_bufshift(vortex, i)) ; + snd_pcm_period_elapsed(vortex->dma_adb[i]. + substream); + } + } +#ifndef CHIP_AU8810 + for (i = 0; i < NR_WT; i++) { + if (vortex->dma_wt[i].fifo_status == FIFO_START) { + if (vortex_wtdma_bufshift(vortex, i)) ; + snd_pcm_period_elapsed(vortex->dma_wt[i]. + substream); + } + } +#endif + handled = 1; + } + //Acknowledge the Timer interrupt + if (source & IRQ_TIMER) { + hwread(vortex->mmio, VORTEX_IRQ_STAT); + handled = 1; + } + if (source & IRQ_MIDI) { + snd_mpu401_uart_interrupt(vortex->irq, + vortex->rmidi->private_data, regs); + handled = 1; + } + + if (!handled) { + printk(KERN_ERR "vortex: unknown irq source %x\n", source); + } + return IRQ_RETVAL(handled); +} + +/* Codec */ + +#define POLL_COUNT 1000 +static void vortex_codec_init(vortex_t * vortex) +{ + int i; + + for (i = 0; i < 32; i++) { + hwwrite(vortex->mmio, (VORTEX_CODEC_CHN + (i << 2)), 0); + udelay(2000); + } + if (0) { + hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0x8068); + udelay(1000); + hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0x00e8); + udelay(1000); + } else { + hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0x00a8); + udelay(2000); + hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0x80a8); + udelay(2000); + hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0x80e8); + udelay(2000); + hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0x80a8); + udelay(2000); + hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0x00a8); + udelay(2000); + hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0x00e8); + } + for (i = 0; i < 32; i++) { + hwwrite(vortex->mmio, (VORTEX_CODEC_CHN + (i << 2)), 0); + udelay(5000); + } + hwwrite(vortex->mmio, VORTEX_CODEC_CTRL, 0xe8); + udelay(1000); + /* Enable codec channels 0 and 1. */ + hwwrite(vortex->mmio, VORTEX_CODEC_EN, + hwread(vortex->mmio, VORTEX_CODEC_EN) | EN_CODEC); +} + +static void +vortex_codec_write(ac97_t * codec, unsigned short addr, unsigned short data) +{ + + vortex_t *card = (vortex_t *) codec->private_data; + unsigned long flags; + unsigned int lifeboat = 0; + spin_lock_irqsave(&card->lock, flags); + + /* wait for transactions to clear */ + while (!(hwread(card->mmio, VORTEX_CODEC_CTRL) & 0x100)) { + udelay(100); + if (lifeboat++ > POLL_COUNT) { + printk(KERN_ERR "vortex: ac97 codec stuck busy\n"); + spin_unlock_irqrestore(&card->lock, flags); + return; + } + } + /* write register */ + hwwrite(card->mmio, VORTEX_CODEC_IO, + ((addr << VORTEX_CODEC_ADDSHIFT) & VORTEX_CODEC_ADDMASK) | + ((data << VORTEX_CODEC_DATSHIFT) & VORTEX_CODEC_DATMASK) | + VORTEX_CODEC_WRITE); + + /* Flush Caches. */ + hwread(card->mmio, VORTEX_CODEC_IO); + + spin_unlock_irqrestore(&card->lock, flags); +} + +static unsigned short vortex_codec_read(ac97_t * codec, unsigned short addr) +{ + + vortex_t *card = (vortex_t *) codec->private_data; + u32 read_addr, data; + unsigned long flags; + unsigned lifeboat = 0; + + spin_lock_irqsave(&card->lock, flags); + + /* wait for transactions to clear */ + while (!(hwread(card->mmio, VORTEX_CODEC_CTRL) & 0x100)) { + udelay(100); + if (lifeboat++ > POLL_COUNT) { + printk(KERN_ERR "vortex: ac97 codec stuck busy\n"); + spin_unlock_irqrestore(&card->lock, flags); + return 0xffff; + } + } + /* set up read address */ + read_addr = ((addr << VORTEX_CODEC_ADDSHIFT) & VORTEX_CODEC_ADDMASK); + hwwrite(card->mmio, VORTEX_CODEC_IO, read_addr); + + /* wait for address */ + { + udelay(100); + data = hwread(card->mmio, VORTEX_CODEC_IO); + if (lifeboat++ > POLL_COUNT) { + printk(KERN_ERR "vortex: ac97 address never arrived\n"); + spin_unlock_irqrestore(&card->lock, flags); + return 0xffff; + } + } + while ((data & VORTEX_CODEC_ADDMASK) != + (addr << VORTEX_CODEC_ADDSHIFT)) ; + + /* Unlock. */ + spin_unlock_irqrestore(&card->lock, flags); + + /* return data. */ + return (u16) (data & VORTEX_CODEC_DATMASK); +} + +/* SPDIF support */ + +static void vortex_spdif_init(vortex_t * vortex, int spdif_sr, int spdif_mode) +{ + int i, this_38 = 0, this_04 = 0, this_08 = 0, this_0c = 0; + + /* CAsp4Spdif::InitializeSpdifHardware(void) */ + hwwrite(vortex->mmio, VORTEX_SPDIF_FLAGS, + hwread(vortex->mmio, VORTEX_SPDIF_FLAGS) & 0xfff3fffd); + //for (i=0x291D4; i<0x29200; i+=4) + for (i = 0; i < 11; i++) + hwwrite(vortex->mmio, VORTEX_SPDIF_CFG1 + (i << 2), 0); + //hwwrite(vortex->mmio, 0x29190, hwread(vortex->mmio, 0x29190) | 0xc0000); + hwwrite(vortex->mmio, VORTEX_CODEC_EN, + hwread(vortex->mmio, VORTEX_CODEC_EN) | EN_SPDIF); + + /* CAsp4Spdif::ProgramSRCInHardware(enum SPDIF_SR,enum SPDIFMODE) */ + if (this_04 && this_08) { + int edi; + + i = (((0x5DC00000 / spdif_sr) + 1) >> 1); + if (i > 0x800) { + if (i < 0x1ffff) + edi = (i >> 1); + else + edi = 0x1ffff; + } else { + i = edi = 0x800; + } + /* this_04 and this_08 are the CASp4Src's (samplerate converters) */ + vortex_src_setupchannel(vortex, this_04, edi, 0, 1, + this_0c, 1, 0, edi, 1); + vortex_src_setupchannel(vortex, this_08, edi, 0, 1, + this_0c, 1, 0, edi, 1); + } + + i = spdif_sr; + spdif_sr |= 0x8c; + switch (i) { + case 32000: + this_38 &= 0xFFFFFFFE; + this_38 &= 0xFFFFFFFD; + this_38 &= 0xF3FFFFFF; + this_38 |= 0x03000000; /* set 32khz samplerate */ + this_38 &= 0xFFFFFF3F; + spdif_sr &= 0xFFFFFFFD; + spdif_sr |= 1; + break; + case 44100: + this_38 &= 0xFFFFFFFE; + this_38 &= 0xFFFFFFFD; + this_38 &= 0xF0FFFFFF; + this_38 |= 0x03000000; + this_38 &= 0xFFFFFF3F; + spdif_sr &= 0xFFFFFFFC; + break; + case 48000: + if (spdif_mode == 1) { + this_38 &= 0xFFFFFFFE; + this_38 &= 0xFFFFFFFD; + this_38 &= 0xF2FFFFFF; + this_38 |= 0x02000000; /* set 48khz samplerate */ + this_38 &= 0xFFFFFF3F; + } else { + /* J. Gordon Wolfe: I think this stuff is for AC3 */ + this_38 |= 0x00000003; + this_38 &= 0xFFFFFFBF; + this_38 |= 0x80; + } + spdif_sr |= 2; + spdif_sr &= 0xFFFFFFFE; + break; + + } + /* looks like the next 2 lines transfer a 16-bit value into 2 8-bit + registers. seems to be for the standard IEC/SPDIF initialization + stuff */ + hwwrite(vortex->mmio, VORTEX_SPDIF_CFG0, this_38 & 0xffff); + hwwrite(vortex->mmio, VORTEX_SPDIF_CFG1, this_38 >> 0x10); + hwwrite(vortex->mmio, VORTEX_SPDIF_SMPRATE, spdif_sr); +} + +/* Initialization */ + +static int vortex_core_init(vortex_t * vortex) +{ + + printk(KERN_INFO "Vortex: hardware init.... "); + /* Hardware Init. */ + hwwrite(vortex->mmio, VORTEX_CTRL, 0xffffffff); + udelay(5000); + hwwrite(vortex->mmio, VORTEX_CTRL, + hwread(vortex->mmio, VORTEX_CTRL) & 0xffdfffff); + udelay(5000); + /* Reset IRQ flags */ + hwwrite(vortex->mmio, VORTEX_IRQ_SOURCE, 0xffffffff); + hwread(vortex->mmio, VORTEX_IRQ_STAT); + + vortex_codec_init(vortex); + +#ifdef CHIP_AU8830 + hwwrite(vortex->mmio, VORTEX_CTRL, + hwread(vortex->mmio, VORTEX_CTRL) | 0x1000000); +#endif + + /* Init audio engine. */ + vortex_adbdma_init(vortex); + hwwrite(vortex->mmio, VORTEX_ENGINE_CTRL, 0x0); //, 0xc83c7e58, 0xc5f93e58 + vortex_adb_init(vortex); + /* Init processing blocks. */ + vortex_fifo_init(vortex); + vortex_mixer_init(vortex); + vortex_srcblock_init(vortex); +#ifndef CHIP_AU8820 + vortex_eq_init(vortex); + vortex_spdif_init(vortex, 48000, 1); + vortex_Vort3D(vortex, 1); +#endif +#ifndef CHIP_AU8810 + vortex_wt_init(vortex); +#endif + // Moved to au88x0.c + //vortex_connect_default(vortex, 1); + + vortex_settimer(vortex, 0x90); + // Enable Interrupts. + // vortex_enable_int() must be first !! + // hwwrite(vortex->mmio, VORTEX_IRQ_CTRL, 0); + // vortex_enable_int(vortex); + //vortex_enable_timer_int(vortex); + //vortex_disable_timer_int(vortex); + + printk(KERN_INFO "done.\n"); + spin_lock_init(&vortex->lock); + + return 0; +} + +static int vortex_core_shutdown(vortex_t * vortex) +{ + + printk(KERN_INFO "Vortex: hardware shutdown..."); +#ifndef CHIP_AU8820 + vortex_eq_free(vortex); + vortex_Vort3D(vortex, 0); +#endif + //vortex_disable_timer_int(vortex); + vortex_disable_int(vortex); + vortex_connect_default(vortex, 0); + /* Reset all DMA fifos. */ + vortex_fifo_init(vortex); + /* Erase all audio routes. */ + vortex_adb_init(vortex); + + /* Disable MPU401 */ + //hwwrite(vortex->mmio, VORTEX_IRQ_CTRL, hwread(vortex->mmio, VORTEX_IRQ_CTRL) & ~IRQ_MIDI); + //hwwrite(vortex->mmio, VORTEX_CTRL, hwread(vortex->mmio, VORTEX_CTRL) & ~CTRL_MIDI_EN); + + hwwrite(vortex->mmio, VORTEX_IRQ_CTRL, 0); + hwwrite(vortex->mmio, VORTEX_CTRL, 0); + udelay(5000); + hwwrite(vortex->mmio, VORTEX_IRQ_SOURCE, 0xffff); + + printk(KERN_INFO "done.\n"); + return 0; +} + +/* Alsa support. */ + +static int vortex_alsafmt_aspfmt(int alsafmt) +{ + int fmt; + + switch (alsafmt) { + case SNDRV_PCM_FORMAT_U8: + fmt = 0x1; + break; + case SNDRV_PCM_FORMAT_MU_LAW: + fmt = 0x2; + break; + case SNDRV_PCM_FORMAT_A_LAW: + fmt = 0x3; + break; + case SNDRV_PCM_FORMAT_SPECIAL: + fmt = 0x4; /* guess. */ + break; + case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: + fmt = 0x5; /* guess. */ + break; + case SNDRV_PCM_FORMAT_S16_LE: + fmt = 0x8; + break; + case SNDRV_PCM_FORMAT_S16_BE: + fmt = 0x9; /* check this... */ + break; + default: + fmt = 0x8; + printk(KERN_ERR "vortex: format unsupported %d\n", alsafmt); + break; + } + return fmt; +} + +/* Some not yet useful translations. */ +#if 0 +typedef enum { + ASPFMTLINEAR16 = 0, /* 0x8 */ + ASPFMTLINEAR8, /* 0x1 */ + ASPFMTULAW, /* 0x2 */ + ASPFMTALAW, /* 0x3 */ + ASPFMTSPORT, /* ? */ + ASPFMTSPDIF, /* ? */ +} ASPENCODING; + +static int +vortex_translateformat(vortex_t * vortex, char bits, char nch, int encod) +{ + int a, this_194; + + if ((bits != 8) || (bits != 16)) + return -1; + + switch (encod) { + case 0: + if (bits == 0x10) + a = 8; // 16 bit + break; + case 1: + if (bits == 8) + a = 1; // 8 bit + break; + case 2: + a = 2; // U_LAW + break; + case 3: + a = 3; // A_LAW + break; + } + switch (nch) { + case 1: + this_194 = 0; + break; + case 2: + this_194 = 1; + break; + case 4: + this_194 = 1; + break; + case 6: + this_194 = 1; + break; + } + return (a); +} + +static void vortex_cdmacore_setformat(vortex_t * vortex, int bits, int nch) +{ + short int d, this_148; + + d = ((bits >> 3) * nch); + this_148 = 0xbb80 / d; +} +#endif diff -Nru a/sound/pci/au88x0/au88x0_eq.c b/sound/pci/au88x0/au88x0_eq.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/au88x0/au88x0_eq.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,1001 @@ +/*************************************************************************** + * au88x0_eq.c + * Aureal Vortex Hardware EQ control/access. + * + * Sun Jun 8 18:19:19 2003 + * 2003 Manuel Jander (mjander@users.sourceforge.net) + * + * 02 July 2003: First time something works :) + * November 2003: A3D Bypass code completed but untested. + * + * TODO: + * - Debug (testing) + * - Test peak visualization support. + * + ****************************************************************************/ + +/* + * 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + The Aureal Hardware EQ is found on AU8810 and AU8830 chips only. + it has 4 inputs (2 for general mix, 2 for A3D) and 2 outputs (supposed + to be routed to the codec). +*/ + +#include "au88x0.h" +#include "au88x0_eq.h" +#include "au88x0_eqdata.c" + +/* CEqHw.s */ +static void vortex_EqHw_SetTimeConsts(vortex_t * vortex, u16 a, u16 b) +{ + hwwrite(vortex->mmio, 0x2b3c4, a); + hwwrite(vortex->mmio, 0x2b3c8, b); +} + +static void vortex_EqHw_SetLeftCoefs(vortex_t * vortex, u16 a[]) +{ + eqhw_t *eqhw = &(vortex->eq.this04); + int eax, i = 0, n /*esp2c */ = 0; + + if (eqhw->this04 <= n) + return; + + do { + hwwrite(vortex->mmio, 0x2b000 + n * 0x30, a[i + 0]); + hwwrite(vortex->mmio, 0x2b004 + n * 0x30, a[i + 1]); + + if (eqhw->this08 == 0) { + hwwrite(vortex->mmio, 0x2b008 + n * 0x30, a[i + 2]); + hwwrite(vortex->mmio, 0x2b00c + n * 0x30, a[i + 3]); + eax = a[i + 4]; //esp24; + } else { + if (a[2 + i] == 0x8000) + eax = 0x7fff; + else + eax = ~a[2 + i]; + hwwrite(vortex->mmio, 0x2b008 + n * 0x30, eax & 0xffff); + if (a[3 + i] == 0x8000) + eax = 0x7fff; + else + eax = ~a[3 + i]; + hwwrite(vortex->mmio, 0x2b00c + n * 0x30, eax & 0xffff); + if (a[4 + i] == 0x8000) + eax = 0x7fff; + else + eax = ~a[4 + i]; + } + hwwrite(vortex->mmio, 0x2b010 + n * 0x30, eax); + + n++; + i += 5; + } + while (n < eqhw->this04); +} + +static void vortex_EqHw_SetRightCoefs(vortex_t * vortex, u16 a[]) +{ + eqhw_t *eqhw = &(vortex->eq.this04); + int i = 0, n /*esp2c */ = 0, eax; + + if (eqhw->this04 <= n) + return; + + do { + hwwrite(vortex->mmio, 0x2b1e0 + n * 0x30, a[0 + i]); + hwwrite(vortex->mmio, 0x2b1e4 + n * 0x30, a[1 + i]); + + if (eqhw->this08 == 0) { + hwwrite(vortex->mmio, 0x2b1e8 + n * 0x30, a[2 + i]); + hwwrite(vortex->mmio, 0x2b1ec + n * 0x30, a[3 + i]); + eax = a[4 + i]; //*esp24; + } else { + if (a[2 + i] == 0x8000) + eax = 0x7fff; + else + eax = ~(a[2 + i]); + hwwrite(vortex->mmio, 0x2b1e8 + n * 0x30, eax & 0xffff); + if (a[3 + i] == 0x8000) + eax = 0x7fff; + else + eax = ~a[3 + i]; + hwwrite(vortex->mmio, 0x2b1ec + n * 0x30, eax & 0xffff); + if (a[4 + i] == 0x8000) + eax = 0x7fff; + else + eax = ~a[4 + i]; + } + hwwrite(vortex->mmio, 0x2b1f0 + n * 0x30, eax); + i += 5; + n++; + } + while (n < eqhw->this04); + +} + +static void vortex_EqHw_SetLeftStates(vortex_t * vortex, u16 a[], u16 b[]) +{ + eqhw_t *eqhw = &(vortex->eq.this04); + int i = 0, ebx = 0; + + hwwrite(vortex->mmio, 0x2b3fc, a[0]); + hwwrite(vortex->mmio, 0x2b400, a[1]); + + if (eqhw->this04 < 0) + return; + + do { + hwwrite(vortex->mmio, 0x2b014 + (i * 0xc), b[i]); + hwwrite(vortex->mmio, 0x2b018 + (i * 0xc), b[1 + i]); + hwwrite(vortex->mmio, 0x2b01c + (i * 0xc), b[2 + i]); + hwwrite(vortex->mmio, 0x2b020 + (i * 0xc), b[3 + i]); + i += 4; + ebx++; + } + while (eqhw->this04 > ebx); +} + +static void vortex_EqHw_SetRightStates(vortex_t * vortex, u16 a[], u16 b[]) +{ + eqhw_t *eqhw = &(vortex->eq.this04); + int i = 0, ebx = 0; + + hwwrite(vortex->mmio, 0x2b404, a[0]); + hwwrite(vortex->mmio, 0x2b408, a[1]); + + if (eqhw->this04 < 0) + return; + + do { + hwwrite(vortex->mmio, 0x2b1f4 + (i * 0xc), b[i]); + hwwrite(vortex->mmio, 0x2b1f8 + (i * 0xc), b[1 + i]); + hwwrite(vortex->mmio, 0x2b1fc + (i * 0xc), b[2 + i]); + hwwrite(vortex->mmio, 0x2b200 + (i * 0xc), b[3 + i]); + i += 4; + ebx++; + } + while (ebx < eqhw->this04); +} + +#if 0 +static void vortex_EqHw_GetTimeConsts(vortex_t * vortex, u16 * a, u16 * b) +{ + *a = hwread(vortex->mmio, 0x2b3c4); + *b = hwread(vortex->mmio, 0x2b3c8); +} + +static void vortex_EqHw_GetLeftCoefs(vortex_t * vortex, u16 a[]) +{ + +} + +static void vortex_EqHw_GetRightCoefs(vortex_t * vortex, u16 a[]) +{ + +} + +static void vortex_EqHw_GetLeftStates(vortex_t * vortex, u16 * a, u16 b[]) +{ + +} + +static void vortex_EqHw_GetRightStates(vortex_t * vortex, u16 * a, u16 b[]) +{ + +} + +#endif +/* Mix Gains */ +static void vortex_EqHw_SetBypassGain(vortex_t * vortex, u16 a, u16 b) +{ + eqhw_t *eqhw = &(vortex->eq.this04); + int eax; + + if (eqhw->this08 == 0) { + hwwrite(vortex->mmio, 0x2b3d4, a); + hwwrite(vortex->mmio, 0x2b3ec, b); + } else { + if (a == 0x8000) + eax = 0x7fff; + else + eax = ~a; + hwwrite(vortex->mmio, 0x2b3d4, eax & 0xffff); + if (b == 0x8000) + eax = 0x7fff; + else + eax = ~b; + hwwrite(vortex->mmio, 0x2b3ec, eax & 0xffff); + } +} + +static void vortex_EqHw_SetA3DBypassGain(vortex_t * vortex, u16 a, u16 b) +{ + + hwwrite(vortex->mmio, 0x2b3e0, a); + hwwrite(vortex->mmio, 0x2b3f8, b); +} + +#if 0 +static void vortex_EqHw_SetCurrBypassGain(vortex_t * vortex, u16 a, u16 b) +{ + + hwwrite(vortex->mmio, 0x2b3d0, a); + hwwrite(vortex->mmio, 0x2b3e8, b); +} + +static void vortex_EqHw_SetCurrA3DBypassGain(vortex_t * vortex, u16 a, u16 b) +{ + + hwwrite(vortex->mmio, 0x2b3dc, a); + hwwrite(vortex->mmio, 0x2b3f4, b); +} + +#endif +static void +vortex_EqHw_SetLeftGainsSingleTarget(vortex_t * vortex, u16 index, u16 b) +{ + hwwrite(vortex->mmio, 0x2b02c + (index * 0x30), b); +} + +static void +vortex_EqHw_SetRightGainsSingleTarget(vortex_t * vortex, u16 index, u16 b) +{ + hwwrite(vortex->mmio, 0x2b20c + (index * 0x30), b); +} + +static void vortex_EqHw_SetLeftGainsTarget(vortex_t * vortex, u16 a[]) +{ + eqhw_t *eqhw = &(vortex->eq.this04); + int ebx = 0; + + if (eqhw->this04 < 0) + return; + do { + hwwrite(vortex->mmio, 0x2b02c + ebx * 0x30, a[ebx]); + ebx++; + } + while (ebx < eqhw->this04); +} + +static void vortex_EqHw_SetRightGainsTarget(vortex_t * vortex, u16 a[]) +{ + eqhw_t *eqhw = &(vortex->eq.this04); + int ebx = 0; + + if (eqhw->this04 < 0) + return; + + do { + hwwrite(vortex->mmio, 0x2b20c + ebx * 0x30, a[ebx]); + ebx++; + } + while (ebx < eqhw->this04); +} + +static void vortex_EqHw_SetLeftGainsCurrent(vortex_t * vortex, u16 a[]) +{ + eqhw_t *eqhw = &(vortex->eq.this04); + int ebx = 0; + + if (eqhw->this04 < 0) + return; + + do { + hwwrite(vortex->mmio, 0x2b028 + ebx * 0x30, a[ebx]); + ebx++; + } + while (ebx < eqhw->this04); +} + +static void vortex_EqHw_SetRightGainsCurrent(vortex_t * vortex, u16 a[]) +{ + eqhw_t *eqhw = &(vortex->eq.this04); + int ebx = 0; + + if (eqhw->this04 < 0) + return; + + do { + hwwrite(vortex->mmio, 0x2b208 + ebx * 0x30, a[ebx]); + ebx++; + } + while (ebx < eqhw->this04); +} + +#if 0 +static void vortex_EqHw_GetLeftGainsTarget(vortex_t * vortex, u16 a[]) +{ + eqhw_t *eqhw = &(vortex->eq.this04); + int ebx = 0; + + if (eqhw->this04 < 0) + return; + + do { + a[ebx] = hwread(vortex->mmio, 0x2b02c + ebx * 0x30); + ebx++; + } + while (ebx < eqhw->this04); +} + +static void vortex_EqHw_GetRightGainsTarget(vortex_t * vortex, u16 a[]) +{ + eqhw_t *eqhw = &(vortex->eq.this04); + int ebx = 0; + + if (eqhw->this04 < 0) + return; + + do { + a[ebx] = hwread(vortex->mmio, 0x2b20c + ebx * 0x30); + ebx++; + } + while (ebx < eqhw->this04); +} + +static void vortex_EqHw_GetLeftGainsCurrent(vortex_t * vortex, u16 a[]) +{ + eqhw_t *eqhw = &(vortex->eq.this04); + int ebx = 0; + + if (eqhw->this04 < 0) + return; + + do { + a[ebx] = hwread(vortex->mmio, 0x2b028 + ebx * 0x30); + ebx++; + } + while (ebx < eqhw->this04); +} + +static void vortex_EqHw_GetRightGainsCurrent(vortex_t * vortex, u16 a[]) +{ + eqhw_t *eqhw = &(vortex->eq.this04); + int ebx = 0; + + if (eqhw->this04 < 0) + return; + + do { + a[ebx] = hwread(vortex->mmio, 0x2b208 + ebx * 0x30); + ebx++; + } + while (ebx < eqhw->this04); +} + +#endif +/* EQ band levels settings */ +static void vortex_EqHw_SetLevels(vortex_t * vortex, u16 a[]) +{ + eqhw_t *eqhw = &(vortex->eq.this04); + int ebx; + + if (eqhw->this04 < 0) + return; + + ebx = 0; + do { + hwwrite(vortex->mmio, 0x2b024 + ebx * 0x30, a[ebx]); + ebx++; + } + while (ebx < eqhw->this04); + + hwwrite(vortex->mmio, 0x2b3cc, a[eqhw->this04]); + hwwrite(vortex->mmio, 0x2b3d8, a[eqhw->this04 + 1]); + + ebx = 0; + do { + hwwrite(vortex->mmio, 0x2b204 + ebx * 0x30, + a[ebx + (eqhw->this04 + 2)]); + ebx++; + } + while (ebx < eqhw->this04); + + hwwrite(vortex->mmio, 0x2b3e4, a[2 + (eqhw->this04 * 2)]); + hwwrite(vortex->mmio, 0x2b3f0, a[3 + (eqhw->this04 * 2)]); +} + +#if 0 +static void vortex_EqHw_GetLevels(vortex_t * vortex, u16 a[]) +{ + eqhw_t *eqhw = &(vortex->eq.this04); + int ebx; + + if (eqhw->this04 < 0) + return; + + ebx = 0; + do { + a[ebx] = hwread(vortex->mmio, 0x2b024 + ebx * 0x30); + ebx++; + } + while (ebx < eqhw->this04); + + a[eqhw->this04] = hwread(vortex->mmio, 0x2b3cc); + a[eqhw->this04 + 1] = hwread(vortex->mmio, 0x2b3d8); + + ebx = 0; + do { + a[ebx + (eqhw->this04 + 2)] = + hwread(vortex->mmio, 0x2b204 + ebx * 0x30); + ebx++; + } + while (ebx < eqhw->this04); + + a[2 + (eqhw->this04 * 2)] = hwread(vortex->mmio, 0x2b3e4); + a[3 + (eqhw->this04 * 2)] = hwread(vortex->mmio, 0x2b3f0); +} + +#endif +/* Global Control */ +static void vortex_EqHw_SetControlReg(vortex_t * vortex, unsigned long reg) +{ + hwwrite(vortex->mmio, 0x2b440, reg); +} + +static void vortex_EqHw_SetSampleRate(vortex_t * vortex, int sr) +{ + hwwrite(vortex->mmio, 0x2b440, ((sr & 0x1f) << 3) | 0xb800); +} + +#if 0 +static void vortex_EqHw_GetControlReg(vortex_t * vortex, unsigned long *reg) +{ + *reg = hwread(vortex->mmio, 0x2b440); +} + +static void vortex_EqHw_GetSampleRate(vortex_t * vortex, int *sr) +{ + *sr = (hwread(vortex->mmio, 0x2b440) >> 3) & 0x1f; +} + +#endif +static void vortex_EqHw_Enable(vortex_t * vortex) +{ + hwwrite(vortex->mmio, 0x2b440, 0xf001); +} + +static void vortex_EqHw_Disable(vortex_t * vortex) +{ + hwwrite(vortex->mmio, 0x2b440, 0xf000); +} + +/* Reset (zero) buffers */ +static void vortex_EqHw_ZeroIO(vortex_t * vortex) +{ + int i; + for (i = 0; i < 0x8; i++) + hwwrite(vortex->mmio, 0x2b410 + (i << 2), 0x0); + for (i = 0; i < 0x4; i++) + hwwrite(vortex->mmio, 0x2b430 + (i << 2), 0x0); +} + +static void vortex_EqHw_ZeroA3DIO(vortex_t * vortex) +{ + int i; + for (i = 0; i < 0x4; i++) + hwwrite(vortex->mmio, 0x2b410 + (i << 2), 0x0); +} + +static void vortex_EqHw_ZeroState(vortex_t * vortex) +{ + + vortex_EqHw_SetControlReg(vortex, 0); + vortex_EqHw_ZeroIO(vortex); + hwwrite(vortex->mmio, 0x2b3c0, 0); + + vortex_EqHw_SetTimeConsts(vortex, 0, 0); + + vortex_EqHw_SetLeftCoefs(vortex, asEqCoefsZeros); + vortex_EqHw_SetRightCoefs(vortex, asEqCoefsZeros); + + vortex_EqHw_SetLeftGainsCurrent(vortex, eq_gains_zero); + vortex_EqHw_SetRightGainsCurrent(vortex, eq_gains_zero); + vortex_EqHw_SetLeftGainsTarget(vortex, eq_gains_zero); + vortex_EqHw_SetRightGainsTarget(vortex, eq_gains_zero); + + vortex_EqHw_SetBypassGain(vortex, 0, 0); + //vortex_EqHw_SetCurrBypassGain(vortex, 0, 0); + vortex_EqHw_SetA3DBypassGain(vortex, 0, 0); + //vortex_EqHw_SetCurrA3DBypassGain(vortex, 0, 0); + vortex_EqHw_SetLeftStates(vortex, eq_states_zero, asEqOutStateZeros); + vortex_EqHw_SetRightStates(vortex, eq_states_zero, asEqOutStateZeros); + vortex_EqHw_SetLevels(vortex, (u16 *) eq_levels); +} + +/* Program coeficients as pass through */ +static void vortex_EqHw_ProgramPipe(vortex_t * vortex) +{ + vortex_EqHw_SetTimeConsts(vortex, 0, 0); + + vortex_EqHw_SetLeftCoefs(vortex, asEqCoefsPipes); + vortex_EqHw_SetRightCoefs(vortex, asEqCoefsPipes); + + vortex_EqHw_SetLeftGainsCurrent(vortex, eq_gains_current); + vortex_EqHw_SetRightGainsCurrent(vortex, eq_gains_current); + vortex_EqHw_SetLeftGainsTarget(vortex, eq_gains_current); + vortex_EqHw_SetRightGainsTarget(vortex, eq_gains_current); +} + +/* Program EQ block as 10 band Equalizer */ +static void +vortex_EqHw_Program10Band(vortex_t * vortex, auxxEqCoeffSet_t * coefset) +{ + + vortex_EqHw_SetTimeConsts(vortex, 0xc, 0x7fe0); + + vortex_EqHw_SetLeftCoefs(vortex, coefset->LeftCoefs); + vortex_EqHw_SetRightCoefs(vortex, coefset->RightCoefs); + + vortex_EqHw_SetLeftGainsCurrent(vortex, coefset->LeftGains); + + vortex_EqHw_SetRightGainsTarget(vortex, coefset->RightGains); + vortex_EqHw_SetLeftGainsTarget(vortex, coefset->LeftGains); + + vortex_EqHw_SetRightGainsCurrent(vortex, coefset->RightGains); +} + +/* Read all EQ peaks. (think VU meter) */ +static void vortex_EqHw_GetTenBandLevels(vortex_t * vortex, u16 peaks[]) +{ + eqhw_t *eqhw = &(vortex->eq.this04); + int i; + + if (eqhw->this04 <= 0) + return; + + for (i = 0; i < eqhw->this04; i++) + peaks[i] = hwread(vortex->mmio, 0x2B024 + i * 0x30); + for (i = 0; i < eqhw->this04; i++) + peaks[i + eqhw->this04] = + hwread(vortex->mmio, 0x2B204 + i * 0x30); +} + +/* CEqlzr.s */ + +static int vortex_Eqlzr_GetLeftGain(vortex_t * vortex, u16 index, u16 * gain) +{ + eqlzr_t *eq = &(vortex->eq); + + if (eq->this28) { + *gain = eq->this130[index]; + return 0; + } + return 1; +} + +static void vortex_Eqlzr_SetLeftGain(vortex_t * vortex, u16 index, u16 gain) +{ + eqlzr_t *eq = &(vortex->eq); + + if (eq->this28 == 0) + return; + + eq->this130[index] = gain; + if (eq->this54) + return; + + vortex_EqHw_SetLeftGainsSingleTarget(vortex, index, gain); +} + +static int vortex_Eqlzr_GetRightGain(vortex_t * vortex, u16 index, u16 * gain) +{ + eqlzr_t *eq = &(vortex->eq); + + if (eq->this28) { + *gain = eq->this130[index + eq->this10]; + return 0; + } + return 1; +} + +static void vortex_Eqlzr_SetRightGain(vortex_t * vortex, u16 index, u16 gain) +{ + eqlzr_t *eq = &(vortex->eq); + + if (eq->this28 == 0) + return; + + eq->this130[index + eq->this10] = gain; + if (eq->this54) + return; + + vortex_EqHw_SetRightGainsSingleTarget(vortex, index, gain); +} + +#if 0 +static int +vortex_Eqlzr_GetAllBands(vortex_t * vortex, u16 * gains, unsigned long *cnt) +{ + eqlzr_t *eq = &(vortex->eq); + int si = 0; + + if (eq->this10 == 0) + return 1; + + { + if (vortex_Eqlzr_GetLeftGain(vortex, si, &gains[si])) + return 1; + if (vortex_Eqlzr_GetRightGain + (vortex, si, &gains[si + eq->this10])) + return 1; + si++; + } + while (eq->this10 > si) ; + *cnt = si * 2; + return 0; +} +#endif +static int vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex_t * vortex) +{ + eqlzr_t *eq = &(vortex->eq); + + vortex_EqHw_SetLeftGainsTarget(vortex, eq->this130); + vortex_EqHw_SetRightGainsTarget(vortex, &(eq->this130[eq->this10])); + + return 0; +} + +static int +vortex_Eqlzr_SetAllBands(vortex_t * vortex, u16 gains[], unsigned long count) +{ + eqlzr_t *eq = &(vortex->eq); + int i; + + if (((eq->this10) * 2 != count) || (eq->this28 == 0)) + return 1; + + if (0 < count) { + for (i = 0; i < count; i++) { + eq->this130[i] = gains[i]; + } + } + if (eq->this54) + return 0; + return vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex); +} + +static void +vortex_Eqlzr_SetA3dBypassGain(vortex_t * vortex, unsigned long a, + unsigned long b) +{ + eqlzr_t *eq = &(vortex->eq); + int eax, ebx; + + eq->this58 = a; + eq->this5c = b; + if (eq->this54) + eax = eq->this0e; + else + eax = eq->this0a; + ebx = (eax * eq->this58) >> 0x10; + eax = (eax * eq->this5c) >> 0x10; + vortex_EqHw_SetA3DBypassGain(vortex, ebx, eax); +} + +static void vortex_Eqlzr_ProgramA3dBypassGain(vortex_t * vortex) +{ + eqlzr_t *eq = &(vortex->eq); + int eax, ebx; + + if (eq->this54) + eax = eq->this0e; + else + eax = eq->this0a; + ebx = (eax * eq->this58) >> 0x10; + eax = (eax * eq->this5c) >> 0x10; + vortex_EqHw_SetA3DBypassGain(vortex, ebx, eax); +} + +static void vortex_Eqlzr_ShutDownA3d(vortex_t * vortex) +{ + if (vortex != NULL) + vortex_EqHw_ZeroA3DIO(vortex); +} + +static void vortex_Eqlzr_SetBypass(vortex_t * vortex, long bp) +{ + eqlzr_t *eq = &(vortex->eq); + + if ((eq->this28) && (bp == 0)) { + vortex_Eqlzr_SetAllBandsFromActiveCoeffSet(vortex); + vortex_EqHw_SetBypassGain(vortex, eq->this08, eq->this08); + } else { + vortex_EqHw_SetLeftGainsTarget(vortex, (u16 *) (eq->this14)); + vortex_EqHw_SetRightGainsTarget(vortex, (u16 *) (eq->this14)); + vortex_EqHw_SetBypassGain(vortex, eq->this0c, eq->this0c); + } + vortex_Eqlzr_ProgramA3dBypassGain(vortex); +} + +static void vortex_Eqlzr_ReadAndSetActiveCoefSet(vortex_t * vortex) +{ + eqlzr_t *eq = &(vortex->eq); + + /* Set EQ BiQuad filter coeficients */ + memcpy(&(eq->coefset), &asEqCoefsNormal, sizeof(auxxEqCoeffSet_t)); + /* Set EQ Band gain levels and dump into hardware registers. */ + vortex_Eqlzr_SetAllBands(vortex, eq_gains_normal, eq->this10 * 2); +} + +static int vortex_Eqlzr_GetAllPeaks(vortex_t * vortex, u16 * peaks, int *count) +{ + eqlzr_t *eq = &(vortex->eq); + + if (eq->this10 == 0) + return 1; + *count = eq->this10 * 2; + vortex_EqHw_GetTenBandLevels(vortex, peaks); + return 0; +} + +#if 0 +static auxxEqCoeffSet_t *vortex_Eqlzr_GetActiveCoefSet(vortex_t * vortex) +{ + eqlzr_t *eq = &(vortex->eq); + + return (&(eq->coefset)); +} +#endif +static void vortex_Eqlzr_init(vortex_t * vortex) +{ + eqlzr_t *eq = &(vortex->eq); + + /* Object constructor */ + //eq->this04 = 0; + eq->this08 = 0; /* Bypass gain with EQ in use. */ + eq->this0a = 0x5999; + eq->this0c = 0x5999; /* Bypass gain with EQ disabled. */ + eq->this0e = 0x5999; + + eq->this10 = 0xa; /* 10 eq frequency bands. */ + eq->this04.this04 = eq->this10; + eq->this28 = 0x1; /* if 1 => Allow read access to this130 (gains) */ + eq->this54 = 0x0; /* if 1 => Dont Allow access to hardware (gains) */ + eq->this58 = 0xffff; + eq->this5c = 0xffff; + + /* Set gains. */ + memset(eq->this14, 0, 2 * 10); + + /* Actual init. */ + vortex_EqHw_ZeroState(vortex); + vortex_EqHw_SetSampleRate(vortex, 0x11); + vortex_Eqlzr_ReadAndSetActiveCoefSet(vortex); + + vortex_EqHw_Program10Band(vortex, &(eq->coefset)); + vortex_Eqlzr_SetBypass(vortex, eq->this54); + vortex_Eqlzr_SetA3dBypassGain(vortex, 0, 0); + vortex_EqHw_Enable(vortex); +} + +static void vortex_Eqlzr_shutdown(vortex_t * vortex) +{ + vortex_Eqlzr_ShutDownA3d(vortex); + vortex_EqHw_ProgramPipe(vortex); + vortex_EqHw_Disable(vortex); +} + +/* ALSA interface */ + +/* Control interface */ +static int +snd_vortex_eqtoggle_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int +snd_vortex_eqtoggle_get(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + vortex_t *vortex = snd_kcontrol_chip(kcontrol); + eqlzr_t *eq = &(vortex->eq); + //int i = kcontrol->private_value; + + ucontrol->value.integer.value[0] = eq->this54 ? 0 : 1; + + return 0; +} + +static int +snd_vortex_eqtoggle_put(snd_kcontrol_t * kcontrol, + snd_ctl_elem_value_t * ucontrol) +{ + vortex_t *vortex = snd_kcontrol_chip(kcontrol); + eqlzr_t *eq = &(vortex->eq); + //int i = kcontrol->private_value; + + eq->this54 = ucontrol->value.integer.value[0] ? 0 : 1; + vortex_Eqlzr_SetBypass(vortex, eq->this54); + + return 1; /* Allways changes */ +} + +static snd_kcontrol_new_t vortex_eqtoggle_kcontrol __devinitdata = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "EQ Enable", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .private_value = 0, + .info = snd_vortex_eqtoggle_info, + .get = snd_vortex_eqtoggle_get, + .put = snd_vortex_eqtoggle_put +}; + +static int +snd_vortex_eq_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0x0000; + uinfo->value.integer.max = 0x7fff; + return 0; +} + +static int +snd_vortex_eq_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + vortex_t *vortex = snd_kcontrol_chip(kcontrol); + int i = kcontrol->private_value; + u16 gainL, gainR; + + vortex_Eqlzr_GetLeftGain(vortex, i, &gainL); + vortex_Eqlzr_GetRightGain(vortex, i, &gainR); + ucontrol->value.integer.value[0] = gainL; + ucontrol->value.integer.value[1] = gainR; + return 0; +} + +static int +snd_vortex_eq_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + vortex_t *vortex = snd_kcontrol_chip(kcontrol); + int changed = 0, i = kcontrol->private_value; + u16 gainL, gainR; + + vortex_Eqlzr_GetLeftGain(vortex, i, &gainL); + vortex_Eqlzr_GetRightGain(vortex, i, &gainR); + + if (gainL != ucontrol->value.integer.value[0]) { + vortex_Eqlzr_SetLeftGain(vortex, i, + ucontrol->value.integer.value[0]); + changed = 1; + } + if (gainR != ucontrol->value.integer.value[1]) { + vortex_Eqlzr_SetRightGain(vortex, i, + ucontrol->value.integer.value[1]); + changed = 1; + } + return changed; +} + +static snd_kcontrol_new_t vortex_eq_kcontrol __devinitdata = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = " .", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .private_value = 0, + .info = snd_vortex_eq_info, + .get = snd_vortex_eq_get, + .put = snd_vortex_eq_put +}; + +static int +snd_vortex_peaks_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 20; + uinfo->value.integer.min = 0x0000; + uinfo->value.integer.max = 0x7fff; + return 0; +} + +static int +snd_vortex_peaks_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + vortex_t *vortex = snd_kcontrol_chip(kcontrol); + int i, count; + u16 peaks[20]; + + vortex_Eqlzr_GetAllPeaks(vortex, peaks, &count); + if (count != 20) { + printk("vortex: peak count error 20 != %d \n", count); + return -1; + } + for (i = 0; i < 20; i++) + ucontrol->value.integer.value[i] = peaks[i]; + + return 0; +} + +static snd_kcontrol_new_t vortex_levels_kcontrol __devinitdata = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "EQ Peaks", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_vortex_peaks_info, + .get = snd_vortex_peaks_get, +}; + +/* EQ band gain labels. */ +static char *EqBandLabels[10] __devinitdata = { + "EQ0 31Hz\0", + "EQ1 63Hz\0", + "EQ2 125Hz\0", + "EQ3 250Hz\0", + "EQ4 500Hz\0", + "EQ5 1KHz\0", + "EQ6 2KHz\0", + "EQ7 4KHz\0", + "EQ8 8KHz\0", + "EQ9 16KHz\0", +}; + +/* ALSA driver entry points. Init and exit. */ +static int vortex_eq_init(vortex_t * vortex) +{ + snd_kcontrol_t *kcontrol; + int err, i; + + vortex_Eqlzr_init(vortex); + + if ((kcontrol = + snd_ctl_new1(&vortex_eqtoggle_kcontrol, vortex)) == NULL) + return -ENOMEM; + kcontrol->private_value = 0; + if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0) + return err; + + /* EQ gain controls */ + for (i = 0; i < 10; i++) { + if ((kcontrol = + snd_ctl_new1(&vortex_eq_kcontrol, vortex)) == NULL) + return -ENOMEM; + strcpy(kcontrol->id.name, EqBandLabels[i]); + kcontrol->private_value = i; + if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0) + return err; + //vortex->eqctrl[i] = kcontrol; + } + /* EQ band levels */ + if ((kcontrol = snd_ctl_new1(&vortex_levels_kcontrol, vortex)) == NULL) + return -ENOMEM; + if ((err = snd_ctl_add(vortex->card, kcontrol)) < 0) + return err; + + return 0; +} + +static int vortex_eq_free(vortex_t * vortex) +{ + /* + //FIXME: segfault because vortex->eqctrl[i] == 4 + int i; + for (i=0; i<10; i++) { + if (vortex->eqctrl[i]) + snd_ctl_remove(vortex->card, vortex->eqctrl[i]); + } + */ + vortex_Eqlzr_shutdown(vortex); + return 0; +} + +/* End */ diff -Nru a/sound/pci/au88x0/au88x0_eq.h b/sound/pci/au88x0/au88x0_eq.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/au88x0/au88x0_eq.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,46 @@ +#ifndef AU88X0_EQ_H +#define AU88X0_EQ_H + +/*************************************************************************** + * au88x0_eq.h + * + * Definitions and constant data for the Aureal Hardware EQ. + * + * Sun Jun 8 18:23:38 2003 + * Author: Manuel Jander (mjander@users.sourceforge.net) + ****************************************************************************/ + +typedef struct { + u16 LeftCoefs[50]; //0x4 + u16 RightCoefs[50]; // 0x68 + u16 LeftGains[20]; //0xd0 + u16 RightGains[20]; //0xe4 +} auxxEqCoeffSet_t; + +typedef struct { + unsigned int *this00; /*CAsp4HwIO */ + long this04; /* How many filters for each side (default = 10) */ + long this08; /* inited to cero. Stereo flag? */ +} eqhw_t; + +typedef struct { + unsigned int *this00; /*CAsp4Core */ + eqhw_t this04; /* CHwEq */ + short this08; /* Bad codec flag ? SetBypassGain: bypass gain */ + short this0a; + short this0c; /* SetBypassGain: bypass gain when this28 is not set. */ + short this0e; + + long this10; /* How many gains are used for each side (right or left). */ + u16 this14[32]; /* SetLeftGainsTarget: Left (and right?) EQ gains */ + long this24; + long this28; /* flag related to EQ enabled or not. Gang flag ? */ + long this54; /* SetBypass */ + long this58; + long this5c; + /*0x60 */ auxxEqCoeffSet_t coefset; + /* 50 u16 word each channel. */ + u16 this130[20]; /* Left and Right gains */ +} eqlzr_t; + +#endif diff -Nru a/sound/pci/au88x0/au88x0_eqdata.c b/sound/pci/au88x0/au88x0_eqdata.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/au88x0/au88x0_eqdata.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,112 @@ +/* Data structs */ + +static u16 asEqCoefsZeros[50] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; + +static u16 asEqCoefsPipes[64] = { + 0x0000, 0x0000, + 0x0000, 0x0666, 0x0000, 0x0000, 0x0666, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0666, 0x0000, 0x0000, 0x0666, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0666, 0x0000, 0x0000, 0x0666, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0666, 0x0000, 0x0000, 0x0666, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0666, 0x0000, 0x0000, 0x066a, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000 +}; + +/* More coef sets can be found in the win2k "inf" file. */ +static auxxEqCoeffSet_t asEqCoefsNormal = { + .LeftCoefs = { + 0x7e60, 0xc19e, 0x0001, 0x0002, 0x0001, + 0x7fa0, 0xc05f, 0x004f, 0x0000, 0xffb1, + 0x7f3f, 0xc0bc, 0x00c2, 0x0000, 0xff3e, + 0x7e78, 0xc177, 0x011f, 0x0000, 0xfee1, + 0x7cd6, 0xc2e5, 0x025c, 0x0000, 0xfda4, + 0x7949, 0xc5aa, 0x0467, 0x0000, 0xfb99, + 0x7120, 0xcadf, 0x0864, 0x0000, 0xf79c, + 0x5d33, 0xd430, 0x0f7e, 0x0000, 0xf082, + 0x2beb, 0xe3ca, 0x1bd3, 0x0000, 0xe42d, + 0xd740, 0xf01d, 0x2ac5, 0x0000, 0xd53b}, + + .RightCoefs = { + 0x7e60, 0xc19e, 0x0001, 0x0002, 0x0001, + 0x7fa0, 0xc05f, 0x004f, 0x0000, 0xffb1, + 0x7f3f, 0xc0bc, 0x00c2, 0x0000, 0xff3e, + 0x7e78, 0xc177, 0x011f, 0x0000, 0xfee1, + 0x7cd6, 0xc2e5, 0x025c, 0x0000, 0xfda4, + 0x7949, 0xc5aa, 0x0467, 0x0000, 0xfb99, + 0x7120, 0xcadf, 0x0864, 0x0000, 0xf79c, + 0x5d33, 0xd430, 0x0f7e, 0x0000, 0xf082, + 0x2beb, 0xe3ca, 0x1bd3, 0x0000, 0xe42d, + 0xd740, 0xf01d, 0x2ac5, 0x0000, 0xd53b}, + + .LeftGains = { + 0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96, + 0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96}, + .RightGains = { + 0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96, + 0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96} +}; + +static u16 eq_gains_normal[20] = { + 0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96, + 0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96, + 0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96, + 0x3e96, 0x3e96, 0x3e96, 0x3e96, 0x3e96 +}; + +/* _rodatab60 */ +static u16 eq_gains_zero[10] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +}; + +/* _rodatab7c: ProgramPipe */ +static u16 eq_gains_current[12] = { + 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, + 0x7fff, + 0x7fff, 0x7fff, 0x7fff +}; + +/* _rodatab78 */ +static u16 eq_states_zero[2] = { 0x0000, 0x0000 }; + +static u16 asEqOutStateZeros[48] = { + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000 +}; + +/*_rodataba0:*/ +static long eq_levels[32] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +}; diff -Nru a/sound/pci/au88x0/au88x0_game.c b/sound/pci/au88x0/au88x0_game.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/au88x0/au88x0_game.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,121 @@ +/* + * $Id: au88x0_game.c,v 1.9 2003/09/22 03:51:28 mjander Exp $ + * + * Manuel Jander. + * + * Based on the work of: + * Vojtech Pavlik + * Raymond Ingles + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * + * Based 90% on Vojtech Pavlik pcigame driver. + * Merged and modified by Manuel Jander, for the OpenVortex + * driver. (email: mjander@embedded.cl). + */ + +#include +#include +#include +#include +#include "au88x0.h" +#include + +#define VORTEX_GAME_DWAIT 20 /* 20 ms */ + +static struct gameport gameport; + +static unsigned char vortex_game_read(struct gameport *gameport) +{ + vortex_t *vortex = gameport->driver; + return hwread(vortex->mmio, VORTEX_GAME_LEGACY); +} + +static void vortex_game_trigger(struct gameport *gameport) +{ + vortex_t *vortex = gameport->driver; + hwwrite(vortex->mmio, VORTEX_GAME_LEGACY, 0xff); +} + +static int +vortex_game_cooked_read(struct gameport *gameport, int *axes, int *buttons) +{ + vortex_t *vortex = gameport->driver; + int i; + + *buttons = (~hwread(vortex->mmio, VORTEX_GAME_LEGACY) >> 4) & 0xf; + + for (i = 0; i < 4; i++) { + axes[i] = + hwread(vortex->mmio, VORTEX_GAME_AXIS + (i * AXIS_SIZE)); + if (axes[i] == AXIS_RANGE) + axes[i] = -1; + } + return 0; +} + +static int vortex_game_open(struct gameport *gameport, int mode) +{ + vortex_t *vortex = gameport->driver; + + switch (mode) { + case GAMEPORT_MODE_COOKED: + hwwrite(vortex->mmio, VORTEX_CTRL2, + hwread(vortex->mmio, + VORTEX_CTRL2) | CTRL2_GAME_ADCMODE); + wait_ms(VORTEX_GAME_DWAIT); + return 0; + case GAMEPORT_MODE_RAW: + hwwrite(vortex->mmio, VORTEX_CTRL2, + hwread(vortex->mmio, + VORTEX_CTRL2) & ~CTRL2_GAME_ADCMODE); + return 0; + default: + return -1; + } + + return 0; +} + +static int vortex_gameport_register(vortex_t * vortex) +{ + vortex->gameport = &gameport; + + vortex->gameport->driver = vortex; + vortex->gameport->fuzz = 64; + + vortex->gameport->read = vortex_game_read; + vortex->gameport->trigger = vortex_game_trigger; + vortex->gameport->cooked_read = vortex_game_cooked_read; + vortex->gameport->open = vortex_game_open; + + gameport_register_port((struct gameport *)vortex->gameport); + +/* printk(KERN_INFO "gameport%d: %s at speed %d kHz\n", + vortex->gameport->number, vortex->pci_dev->name, vortex->gameport->speed); +*/ + return 0; +} + +static int vortex_gameport_unregister(vortex_t * vortex) +{ + if (vortex->gameport != NULL) + gameport_unregister_port(vortex->gameport); + return 0; +} diff -Nru a/sound/pci/au88x0/au88x0_mixer.c b/sound/pci/au88x0/au88x0_mixer.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/au88x0/au88x0_mixer.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,29 @@ +/* + * Vortex Mixer support. + * + * There is much more than just the AC97 mixer... + * + */ + +#include +#include +#include +#include +#include "au88x0.h" + +static int __devinit snd_vortex_mixer(vortex_t * vortex) +{ + ac97_bus_t bus, *pbus; + ac97_t ac97; + int err; + + memset(&bus, 0, sizeof(bus)); + bus.write = vortex_codec_write; + bus.read = vortex_codec_read; + if ((err = snd_ac97_bus(vortex->card, &bus, &pbus)) < 0) + return err; + memset(&ac97, 0, sizeof(ac97)); + // Intialize AC97 codec stuff. + ac97.private_data = vortex; + return snd_ac97_mixer(pbus, &ac97, &vortex->codec); +} diff -Nru a/sound/pci/au88x0/au88x0_mpu401.c b/sound/pci/au88x0/au88x0_mpu401.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/au88x0/au88x0_mpu401.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,112 @@ +/* + * Copyright (c) by Jaroslav Kysela + * Routines for control of MPU-401 in UART mode + * + * Modified for the Aureal Vortex based Soundcards + * by Manuel Jander (mjande@embedded.cl). + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include "au88x0.h" + +/* Check for mpu401 mmio support. */ +/* MPU401 legacy support is only provided as a emergency fallback * + * for older versions of ALSA. Its usage is strongly discouraged. */ +#ifndef MPU401_HW_AUREAL +#define VORTEX_MPU401_LEGACY +#endif + +/* Vortex MPU401 defines. */ +#define MIDI_CLOCK_DIV 0x61 +/* Standart MPU401 defines. */ +#define MPU401_RESET 0xff +#define MPU401_ENTER_UART 0x3f +#define MPU401_ACK 0xfe + +static int __devinit snd_vortex_midi(vortex_t * vortex) +{ + snd_rawmidi_t *rmidi; + int temp, mode; + mpu401_t *mpu; + int port; + +#ifdef VORTEX_MPU401_LEGACY + /* EnableHardCodedMPU401Port() */ + /* Enable Legacy MIDI Interface port. */ + port = (0x03 << 5); /* FIXME: static address. 0x330 */ + temp = + (hwread(vortex->mmio, VORTEX_CTRL) & ~CTRL_MIDI_PORT) | + CTRL_MIDI_EN | port; + hwwrite(vortex->mmio, VORTEX_CTRL, temp); +#else + /* Disable Legacy MIDI Interface port. */ + temp = + (hwread(vortex->mmio, VORTEX_CTRL) & ~CTRL_MIDI_PORT) & + ~CTRL_MIDI_EN; + hwwrite(vortex->mmio, VORTEX_CTRL, temp); +#endif + /* Mpu401UartInit() */ + mode = 1; + temp = hwread(vortex->mmio, VORTEX_CTRL2) & 0xffff00cf; + temp |= (MIDI_CLOCK_DIV << 8) | ((mode >> 24) & 0xff) << 4; + hwwrite(vortex->mmio, VORTEX_CTRL2, temp); + hwwrite(vortex->mmio, VORTEX_MIDI_CMD, MPU401_RESET); + /* Set some kind of mode */ + if (mode) + hwwrite(vortex->mmio, VORTEX_MIDI_CMD, MPU401_ENTER_UART); + + /* Check if anything is OK. */ + temp = hwread(vortex->mmio, VORTEX_MIDI_DATA); + if (temp != MPU401_ACK /*0xfe */ ) { + printk(KERN_ERR "midi port doesn't acknowledge!\n"); + return -ENODEV; + } + /* Enable MPU401 interrupts. */ + hwwrite(vortex->mmio, VORTEX_IRQ_CTRL, + hwread(vortex->mmio, VORTEX_IRQ_CTRL) | IRQ_MIDI); + + /* Create MPU401 instance. */ +#ifdef VORTEX_MPU401_LEGACY + if ((temp = + snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_MPU401, 0x330, + 0, 0, 0, &rmidi)) != 0) { + hwwrite(vortex->mmio, VORTEX_CTRL, + (hwread(vortex->mmio, VORTEX_CTRL) & + ~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN); + return temp; + } +#else + port = (unsigned long)(vortex->mmio + (VORTEX_MIDI_DATA >> 2)); + if ((temp = + snd_mpu401_uart_new(vortex->card, 0, MPU401_HW_AUREAL, port, + 1, 0, 0, &rmidi)) != 0) { + hwwrite(vortex->mmio, VORTEX_CTRL, + (hwread(vortex->mmio, VORTEX_CTRL) & + ~CTRL_MIDI_PORT) & ~CTRL_MIDI_EN); + return temp; + } + mpu = snd_magic_cast(mpu401_t, rmidi->private_data, return -ENOMEM); + mpu->cport = (unsigned long)(vortex->mmio + (VORTEX_MIDI_CMD >> 2)); +#endif + vortex->rmidi = rmidi; + return 0; +} diff -Nru a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/au88x0/au88x0_pcm.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,509 @@ +/* + * Vortex PCM ALSA driver. + * + * Supports ADB and WT DMA. Unfortunately, WT routing is still a + * mistery. To discover that, we need to disassemble the windoze + * driver too. + * + * + */ + +#include +#include +#include +#include +#include +#include "au88x0.h" + +#define chip_t vortex_t +#define VORTEX_PCM_TYPE(x) (x->name[40]) + +/* hardware definition */ +static snd_pcm_hardware_t snd_vortex_playback_hw_adb = { + .info = + (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 | + SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 5000, + .rate_max = 48000, + .channels_min = 1, +#ifdef CHIP_AU8830 + .channels_max = 4, +#else + .channels_max = 2, +#endif + .buffer_bytes_max = 0x10000, + .period_bytes_min = 0x1, + .period_bytes_max = 0x1000, + .periods_min = 2, + .periods_max = 32, +}; + +#ifndef CHIP_AU8820 +static snd_pcm_hardware_t snd_vortex_playback_hw_a3d = { + .info = + (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 | + SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 5000, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 1, + .buffer_bytes_max = 0x10000, + .period_bytes_min = 0x100, + .period_bytes_max = 0x1000, + .periods_min = 2, + .periods_max = 64, +}; +#endif +static snd_pcm_hardware_t snd_vortex_playback_hw_spdif = { + .info = + (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U8 | + SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | SNDRV_PCM_FMTBIT_MU_LAW | + SNDRV_PCM_FMTBIT_A_LAW, + .rates = + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, + .rate_min = 32000, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = 0x10000, + .period_bytes_min = 0x100, + .period_bytes_max = 0x1000, + .periods_min = 2, + .periods_max = 64, +}; + +#ifndef CHIP_AU8810 +static snd_pcm_hardware_t snd_vortex_playback_hw_wt = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_CONTINUOUS, // SNDRV_PCM_RATE_48000, + .rate_min = 8000, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = 0x10000, + .period_bytes_min = 0x0400, + .period_bytes_max = 0x1000, + .periods_min = 2, + .periods_max = 64, +}; +#endif +/* open callback */ +static int snd_vortex_pcm_open(snd_pcm_substream_t * substream) +{ + vortex_t *vortex = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + int err; + + /* Force equal size periods */ + if ((err = + snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS)) < 0) + return err; + /* Avoid PAGE_SIZE boundary to fall inside of a period. */ + if ((err = + snd_pcm_hw_constraint_pow2(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0) + return err; + + if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { +#ifndef CHIP_AU8820 + if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_A3D) { + runtime->hw = snd_vortex_playback_hw_a3d; + } +#endif + if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_SPDIF) { + runtime->hw = snd_vortex_playback_hw_spdif; + switch (vortex->spdif_sr) { + case 32000: + runtime->hw.rates = SNDRV_PCM_RATE_32000; + break; + case 44100: + runtime->hw.rates = SNDRV_PCM_RATE_44100; + break; + case 48000: + runtime->hw.rates = SNDRV_PCM_RATE_48000; + break; + } + } + if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB + || VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_I2S) + runtime->hw = snd_vortex_playback_hw_adb; + substream->runtime->private_data = NULL; + } +#ifndef CHIP_AU8810 + else { + runtime->hw = snd_vortex_playback_hw_wt; + substream->runtime->private_data = NULL; + } +#endif + return 0; +} + +/* close callback */ +static int snd_vortex_pcm_close(snd_pcm_substream_t * substream) +{ + //vortex_t *chip = snd_pcm_substream_chip(substream); + stream_t *stream = (stream_t *) substream->runtime->private_data; + + // the hardware-specific codes will be here + if (stream != NULL) { + stream->substream = NULL; + stream->nr_ch = 0; + } + substream->runtime->private_data = NULL; + return 0; +} + +/* hw_params callback */ +static int +snd_vortex_pcm_hw_params(snd_pcm_substream_t * substream, + snd_pcm_hw_params_t * hw_params) +{ + chip_t *chip = snd_pcm_substream_chip(substream); + stream_t *stream = (stream_t *) (substream->runtime->private_data); + snd_pcm_sgbuf_t *sgbuf; + int err; + + // Alloc buffer memory. + err = + snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); + if (err < 0) { + printk(KERN_ERR "Vortex: pcm page alloc failed!\n"); + return err; + } + //sgbuf = (snd_pcm_sgbuf_t *) substream->runtime->dma_private; + sgbuf = snd_pcm_substream_sgbuf(substream); + /* + printk(KERN_INFO "Vortex: periods %d, period_bytes %d, channels = %d\n", params_periods(hw_params), + params_period_bytes(hw_params), params_channels(hw_params)); + */ + // Make audio routes and config buffer DMA. + if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { + int dma, type = VORTEX_PCM_TYPE(substream->pcm); + /* Dealloc any routes. */ + if (stream != NULL) + vortex_adb_allocroute(chip, stream->dma, + stream->nr_ch, stream->dir, + stream->type); + /* Alloc routes. */ + dma = + vortex_adb_allocroute(chip, -1, + params_channels(hw_params), + substream->stream, type); + if (dma < 0) + return dma; + stream = substream->runtime->private_data = &chip->dma_adb[dma]; + stream->substream = substream; + /* Setup Buffers. */ + vortex_adbdma_setbuffers(chip, dma, sgbuf, + params_period_bytes(hw_params), + params_periods(hw_params)); + } +#ifndef CHIP_AU8810 + else { + /*if (stream != NULL) + vortex_wt_allocroute(chip, substream->number, 0); */ + vortex_wt_allocroute(chip, substream->number, + params_channels(hw_params)); + stream = substream->runtime->private_data = + &chip->dma_wt[substream->number]; + stream->substream = substream; + vortex_wtdma_setbuffers(chip, substream->number, sgbuf, + params_period_bytes(hw_params), + params_periods(hw_params)); + } +#endif + return 0; +} + +/* hw_free callback */ +static int snd_vortex_pcm_hw_free(snd_pcm_substream_t * substream) +{ + chip_t *chip = snd_pcm_substream_chip(substream); + stream_t *stream = (stream_t *) (substream->runtime->private_data); + + // Delete audio routes. + if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { + if (stream != NULL) + vortex_adb_allocroute(chip, stream->dma, + stream->nr_ch, stream->dir, + stream->type); + } +#ifndef CHIP_AU8810 + else { + if (stream != NULL) + vortex_wt_allocroute(chip, stream->dma, 0); + } +#endif + substream->runtime->private_data = NULL; + + return snd_pcm_lib_free_pages(substream); +} + +/* prepare callback */ +static int snd_vortex_pcm_prepare(snd_pcm_substream_t * substream) +{ + vortex_t *chip = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + stream_t *stream = (stream_t *) substream->runtime->private_data; + int dma = stream->dma, fmt, dir; + + // set up the hardware with the current configuration. + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + dir = 1; + else + dir = 0; + fmt = vortex_alsafmt_aspfmt(runtime->format); + if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { + vortex_adbdma_setmode(chip, dma, 1, dir, fmt, 0 /*? */ , + 0); + vortex_adbdma_setstartbuffer(chip, dma, 0); + if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_SPDIF) + vortex_adb_setsrc(chip, dma, runtime->rate, dir); + } +#ifndef CHIP_AU8810 + else { + vortex_wtdma_setmode(chip, dma, 1, fmt, 0, 0); + // FIXME: Set rate (i guess using vortex_wt_writereg() somehow). + vortex_wtdma_setstartbuffer(chip, dma, 0); + } +#endif + return 0; +} + +/* trigger callback */ +static int snd_vortex_pcm_trigger(snd_pcm_substream_t * substream, int cmd) +{ + chip_t *chip = snd_pcm_substream_chip(substream); + stream_t *stream = (stream_t *) substream->runtime->private_data; + int dma = stream->dma; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + // do something to start the PCM engine + //printk(KERN_INFO "vortex: start %d\n", dma); + stream->fifo_enabled = 1; + if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) + vortex_adbdma_startfifo(chip, dma); +#ifndef CHIP_AU8810 + else { + printk(KERN_INFO "vortex: wt start %d\n", dma); + vortex_wtdma_startfifo(chip, dma); + } +#endif + break; + case SNDRV_PCM_TRIGGER_STOP: + // do something to stop the PCM engine + //printk(KERN_INFO "vortex: stop %d\n", dma) + stream->fifo_enabled = 0; + if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) + vortex_adbdma_pausefifo(chip, dma); + //vortex_adbdma_stopfifo(chip, dma); +#ifndef CHIP_AU8810 + else { + printk(KERN_INFO "vortex: wt stop %d\n", dma); + vortex_wtdma_stopfifo(chip, dma); + } +#endif + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + //printk(KERN_INFO "vortex: pause %d\n", dma); + if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) + vortex_adbdma_pausefifo(chip, dma); +#ifndef CHIP_AU8810 + else + vortex_wtdma_pausefifo(chip, dma); +#endif + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + //printk(KERN_INFO "vortex: resume %d\n", dma); + if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) + vortex_adbdma_resumefifo(chip, dma); +#ifndef CHIP_AU8810 + else + vortex_wtdma_resumefifo(chip, dma); +#endif + break; + default: + return -EINVAL; + } + return 0; +} + +/* pointer callback */ +static snd_pcm_uframes_t snd_vortex_pcm_pointer(snd_pcm_substream_t * substream) +{ + vortex_t *chip = snd_pcm_substream_chip(substream); + stream_t *stream = (stream_t *) substream->runtime->private_data; + int dma = stream->dma; + snd_pcm_uframes_t current_ptr = 0; + + spin_lock(&chip->lock); + if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) + current_ptr = vortex_adbdma_getlinearpos(chip, dma); +#ifndef CHIP_AU8810 + else + current_ptr = vortex_wtdma_getlinearpos(chip, dma); +#endif + //printk(KERN_INFO "vortex: pointer = 0x%x\n", current_ptr); + spin_unlock(&chip->lock); + return (bytes_to_frames(substream->runtime, current_ptr)); +} + +/* Page callback. */ +/* +static struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset) { + + +} +*/ +/* operators */ +static snd_pcm_ops_t snd_vortex_playback_ops = { + .open = snd_vortex_pcm_open, + .close = snd_vortex_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_vortex_pcm_hw_params, + .hw_free = snd_vortex_pcm_hw_free, + .prepare = snd_vortex_pcm_prepare, + .trigger = snd_vortex_pcm_trigger, + .pointer = snd_vortex_pcm_pointer, + .page = snd_pcm_sgbuf_ops_page, +}; + +/* +* definitions of capture are omitted here... +*/ + +static char *vortex_pcm_prettyname[VORTEX_PCM_LAST] = { + "AU88x0 ADB", + "AU88x0 SPDIF", + "AU88x0 A3D", + "AU88x0 WT", + "AU88x0 I2S", +}; +static char *vortex_pcm_name[VORTEX_PCM_LAST] = { + "adb", + "spdif", + "a3d", + "wt", + "i2s", +}; + +/* SPDIF kcontrol */ +static int +snd_vortex_spdif_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo) +{ + static char *texts[] = { "32000", "44100", "48000" }; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 3; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = + uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + return 0; +} +static int +snd_vortex_spdif_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + vortex_t *vortex = snd_kcontrol_chip(kcontrol); + + if (vortex->spdif_sr == 32000) + ucontrol->value.enumerated.item[0] = 0; + if (vortex->spdif_sr == 44100) + ucontrol->value.enumerated.item[0] = 1; + if (vortex->spdif_sr == 48000) + ucontrol->value.enumerated.item[0] = 2; + return 0; +} +static int +snd_vortex_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + vortex_t *vortex = snd_kcontrol_chip(kcontrol); + static unsigned int sr[3] = { 32000, 44100, 48000 }; + + //printk("vortex: spdif sr = %d\n", ucontrol->value.enumerated.item[0]); + vortex->spdif_sr = sr[ucontrol->value.enumerated.item[0] % 3]; + vortex_spdif_init(vortex, + sr[ucontrol->value.enumerated.item[0] % 3], 1); + return 1; +} +static snd_kcontrol_new_t vortex_spdif_kcontrol __devinitdata = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "SPDIF SR", + .index = 0, + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .private_value = 0, + .info = snd_vortex_spdif_info, + .get = snd_vortex_spdif_get, + .put = snd_vortex_spdif_put +}; + +/* create a pcm device */ +static int __devinit snd_vortex_new_pcm(vortex_t * chip, int idx, int nr) +{ + snd_pcm_t *pcm; + int err, nr_capt; + + if ((chip == 0) || (idx < 0) || (idx > VORTEX_PCM_LAST)) + return -ENODEV; + + /* idx indicates which kind of PCM device. ADB, SPDIF, I2S and A3D share the + * same dma engine. WT uses it own separate dma engine whcih cant capture. */ + if (idx == VORTEX_PCM_ADB) + nr_capt = nr; + else + nr_capt = 0; + if ((err = + snd_pcm_new(chip->card, vortex_pcm_prettyname[idx], idx, nr, + nr_capt, &pcm)) < 0) + return err; + strcpy(pcm->name, vortex_pcm_name[idx]); + chip->pcm[idx] = pcm; + // This is an evil hack, but it saves a lot of duplicated code. + VORTEX_PCM_TYPE(pcm) = idx; + pcm->private_data = chip; + /* set operators */ + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, + &snd_vortex_playback_ops); + if (idx == VORTEX_PCM_ADB) + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, + &snd_vortex_playback_ops); + /* pre-allocation of linear buffers */ + //snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + // snd_dma_pci_data(chip->pci_dev), 0x10000, 0x10000); + /* pre-allocation of Scatter-Gather buffers */ + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, + snd_dma_pci_data(chip->pci_dev), + 0x10000, 0x10000); + + if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_SPDIF) { + snd_kcontrol_t *kcontrol; + + if ((kcontrol = + snd_ctl_new1(&vortex_spdif_kcontrol, chip)) == NULL) + return -ENOMEM; + if ((err = snd_ctl_add(chip->card, kcontrol)) < 0) + return err; + } + return 0; +} diff -Nru a/sound/pci/au88x0/au88x0_sb.h b/sound/pci/au88x0/au88x0_sb.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/au88x0/au88x0_sb.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,40 @@ +/*************************************************************************** + * au88x0_sb.h + * + * Wed Oct 29 22:10:42 2003 + * + ****************************************************************************/ + +#ifdef CHIP_AU8820 +/* AU8820 starting @ 64KiB offset */ +#define SBEMU_BASE 0x10000 +#else +/* AU8810? and AU8830 starting @ 164KiB offset */ +#define SBEMU_BASE 0x29000 +#endif + +#define FM_A_STATUS (SBEMU_BASE + 0x00) /* read */ +#define FM_A_ADDRESS (SBEMU_BASE + 0x00) /* write */ +#define FM_A_DATA (SBEMU_BASE + 0x04) +#define FM_B_STATUS (SBEMU_BASE + 0x08) +#define FM_B_ADDRESS (SBEMU_BASE + 0x08) +#define FM_B_DATA (SBEMU_BASE + 0x0C) +#define SB_MIXER_ADDR (SBEMU_BASE + 0x10) +#define SB_MIXER_DATA (SBEMU_BASE + 0x14) +#define SB_RESET (SBEMU_BASE + 0x18) +#define SB_RESET_ALIAS (SBEMU_BASE + 0x1C) +#define FM_STATUS2 (SBEMU_BASE + 0x20) +#define FM_ADDR2 (SBEMU_BASE + 0x20) +#define FM_DATA2 (SBEMU_BASE + 0x24) +#define SB_DSP_READ (SBEMU_BASE + 0x28) +#define SB_DSP_WRITE (SBEMU_BASE + 0x30) +#define SB_DSP_WRITE_STATUS (SBEMU_BASE + 0x30) /* bit 7 */ +#define SB_DSP_READ_STATUS (SBEMU_BASE + 0x38) /* bit 7 */ +#define SB_LACR (SBEMU_BASE + 0x40) /* ? */ +#define SB_LADCR (SBEMU_BASE + 0x44) /* ? */ +#define SB_LAMR (SBEMU_BASE + 0x48) /* ? */ +#define SB_LARR (SBEMU_BASE + 0x4C) /* ? */ +#define SB_VERSION (SBEMU_BASE + 0x50) +#define SB_CTRLSTAT (SBEMU_BASE + 0x54) +#define SB_TIMERSTAT (SBEMU_BASE + 0x58) +#define FM_RAM (SBEMU_BASE + 0x100) /* 0x40 ULONG */ diff -Nru a/sound/pci/au88x0/au88x0_synth.c b/sound/pci/au88x0/au88x0_synth.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/au88x0/au88x0_synth.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,393 @@ +/* + * 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * Someday its supposed to make use of the WT DMA engine + * for a Wavetable synthesizer. + */ + +#include "au88x0.h" +#include "au88x0_wt.h" + +static void vortex_fifo_setwtvalid(vortex_t * vortex, int fifo, int en); +static void vortex_connection_adb_mixin(vortex_t * vortex, int en, + unsigned char channel, + unsigned char source, + unsigned char mixin); +static void vortex_connection_mixin_mix(vortex_t * vortex, int en, + unsigned char mixin, + unsigned char mix, int a); +static void vortex_fifo_wtinitialize(vortex_t * vortex, int fifo, int j); +static int vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt, + unsigned long val); + +/* WT */ + +static void vortex_wt_setstereo(vortex_t * vortex, u32 wt, u32 stereo) +{ + int temp; + + //temp = hwread(vortex->mmio, 0x80 + ((wt >> 0x5)<< 0xf) + (((wt & 0x1f) >> 1) << 2)); + temp = hwread(vortex->mmio, WT_STEREO(wt)); + temp = (temp & 0xfe) | (stereo & 1); + //hwwrite(vortex->mmio, 0x80 + ((wt >> 0x5)<< 0xf) + (((wt & 0x1f) >> 1) << 2), temp); + hwwrite(vortex->mmio, WT_STEREO(wt), temp); +} + +static void vortex_wt_setdsout(vortex_t * vortex, u32 wt, int en) +{ + int temp; + + /* There is one DSREG register for each bank (32 voices each). */ + temp = hwread(vortex->mmio, WT_DSREG((wt >= 0x20) ? 1 : 0)); + if (en) + temp |= (1 << (wt & 0x1f)); + else + temp &= (1 << ~(wt & 0x1f)); + hwwrite(vortex->mmio, WT_DSREG((wt >= 0x20) ? 1 : 0), temp); +} + +// WT routing is still a mistery. +static int vortex_wt_allocroute(vortex_t * vortex, int wt, int nr_ch) +{ + wt_voice_t *voice = &(vortex->wt_voice[wt]); + int temp; + + //FIXME: WT audio routing. + if (nr_ch) { + vortex_fifo_wtinitialize(vortex, wt, 2); + vortex_fifo_setwtvalid(vortex, wt, 1); + vortex_wt_setstereo(vortex, wt, nr_ch - 1); + } else + vortex_fifo_setwtvalid(vortex, wt, 0); + + vortex_wt_setdsout(vortex, wt, 0); + hwwrite(vortex->mmio, WT_SRAMP(0), 0x880000); + //hwwrite(vortex->mmio, WT_GMODE(0), 0xffffffff); +#ifdef CHIP_AU8830 + hwwrite(vortex->mmio, WT_SRAMP(1), 0x880000); + //hwwrite(vortex->mmio, WT_GMODE(1), 0xffffffff); +#endif + hwwrite(vortex->mmio, WT_PARM(wt, 0), 0); + hwwrite(vortex->mmio, WT_PARM(wt, 1), 0); + hwwrite(vortex->mmio, WT_PARM(wt, 2), 0); + + temp = hwread(vortex->mmio, WT_PARM(wt, 3)); + printk("vortex: WT PARM3: %x\n", temp); + hwwrite(vortex->mmio, WT_PARM(wt, 3), temp); + + hwwrite(vortex->mmio, WT_DELAY(wt, 0), 0); + hwwrite(vortex->mmio, WT_DELAY(wt, 1), 0); + hwwrite(vortex->mmio, WT_DELAY(wt, 2), 0); + hwwrite(vortex->mmio, WT_DELAY(wt, 3), 0); + + printk("vortex: WT GMODE: %x\n", hwread(vortex->mmio, WT_GMODE(wt))); + + hwwrite(vortex->mmio, WT_PARM(wt, 2), 0xffffffff); + hwwrite(vortex->mmio, WT_PARM(wt, 3), 0xcff1c810); + + voice->parm0 = voice->parm1 = 0xcfb23e2f; + hwwrite(vortex->mmio, WT_PARM(wt, 0), voice->parm0); + hwwrite(vortex->mmio, WT_PARM(wt, 1), voice->parm1); + printk("vortex: WT GMODE 2 : %x\n", hwread(vortex->mmio, WT_GMODE(wt))); + return 0; +} + +static void vortex_wt_connect(vortex_t * vortex, int en) +{ + int i, ii, mix; + +#define NR_WTROUTES 6 +#ifdef CHIP_AU8830 +#define NR_WTBLOCKS 2 +#else +#define NR_WTBLOCKS 1 +#endif + + for (i = 0; i < NR_WTBLOCKS; i++) { + for (ii = 0; ii < NR_WTROUTES; ii++) { + mix = + vortex_adb_checkinout(vortex, + vortex->fixed_res, en, + VORTEX_RESOURCE_MIXIN); + vortex->mixwt[(i * NR_WTROUTES) + ii] = mix; + + vortex_route(vortex, en, 0x11, + ADB_WTOUT(i, ii + 0x20), ADB_MIXIN(mix)); + + vortex_connection_mixin_mix(vortex, en, mix, + vortex->mixplayb[ii % + 2], 0); + if (VORTEX_IS_QUAD(vortex)) + vortex_connection_mixin_mix(vortex, en, + mix, + vortex-> + mixplayb[2 + + (ii % + 2)], 0); + } + } + for (i = 0; i < NR_WT; i++) { + hwwrite(vortex->mmio, WT_RUN(i), 1); + } +} + +/* Read WT Register */ +#if 0 +static int vortex_wt_GetReg(vortex_t * vortex, char reg, int wt) +{ + //int eax, esi; + + if (reg == 4) { + return hwread(vortex->mmio, WT_PARM(wt, 3)); + } + if (reg == 7) { + return hwread(vortex->mmio, WT_GMODE(wt));; + } + + return 0; +} + +/* WT hardware abstraction layer generic register interface. */ +static int +vortex_wt_SetReg2(vortex_t * vortex, unsigned char reg, int wt, + unsigned short val) +{ + /* + int eax, edx; + + if (wt >= NR_WT) // 0x40 -> NR_WT + return 0; + + if ((reg - 0x20) > 0) { + if ((reg - 0x21) != 0) + return 0; + eax = ((((b & 0xff) << 0xb) + (edx & 0xff)) << 4) + 0x208; // param 2 + } else { + eax = ((((b & 0xff) << 0xb) + (edx & 0xff)) << 4) + 0x20a; // param 3 + } + hwwrite(vortex->mmio, eax, c); + */ + return 1; +} + +/*public: static void __thiscall CWTHal::SetReg(unsigned char,int,unsigned long) */ +#endif +static int +vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt, + unsigned long val) +{ + int ecx; + + if ((reg == 5) || ((reg >= 7) && (reg <= 10)) || (reg == 0xc)) { + if (wt >= (NR_WT / NR_WT_PB)) { + printk + ("vortex: WT SetReg: bank out of range. reg=0x%x, wt=%d\n", + reg, wt); + return 0; + } + } else { + if (wt >= NR_WT) { + printk("vortex: WT SetReg: voice out of range\n"); + return 0; + } + } + if (reg > 0xc) + return 0; + + switch (reg) { + /* Voice specific parameters */ + case 0: /* running */ + //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_RUN(wt), (int)val); + hwwrite(vortex->mmio, WT_RUN(wt), val); + return 0xc; + break; + case 1: /* param 0 */ + //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_PARM(wt,0), (int)val); + hwwrite(vortex->mmio, WT_PARM(wt, 0), val); + return 0xc; + break; + case 2: /* param 1 */ + //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_PARM(wt,1), (int)val); + hwwrite(vortex->mmio, WT_PARM(wt, 1), val); + return 0xc; + break; + case 3: /* param 2 */ + //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_PARM(wt,2), (int)val); + hwwrite(vortex->mmio, WT_PARM(wt, 2), val); + return 0xc; + break; + case 4: /* param 3 */ + //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_PARM(wt,3), (int)val); + hwwrite(vortex->mmio, WT_PARM(wt, 3), val); + return 0xc; + break; + case 6: /* mute */ + //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_MUTE(wt), (int)val); + hwwrite(vortex->mmio, WT_MUTE(wt), val); + return 0xc; + break; + case 0xb: + { /* delay */ + //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", WT_DELAY(wt,0), (int)val); + hwwrite(vortex->mmio, WT_DELAY(wt, 3), val); + hwwrite(vortex->mmio, WT_DELAY(wt, 2), val); + hwwrite(vortex->mmio, WT_DELAY(wt, 1), val); + hwwrite(vortex->mmio, WT_DELAY(wt, 0), val); + return 0xc; + } + break; + /* Global WT block parameters */ + case 5: /* sramp */ + ecx = WT_SRAMP(wt); + break; + case 8: /* aramp */ + ecx = WT_ARAMP(wt); + break; + case 9: /* mramp */ + ecx = WT_MRAMP(wt); + break; + case 0xa: /* ctrl */ + ecx = WT_CTRL(wt); + break; + case 0xc: /* ds_reg */ + ecx = WT_DSREG(wt); + break; + default: + return 0; + break; + } + //printk("vortex: WT SetReg(0x%x) = 0x%08x\n", ecx, (int)val); + hwwrite(vortex->mmio, ecx, val); + return 1; +} + +static void vortex_wt_init(vortex_t * vortex) +{ + int var4, var8, varc, var10 = 0, edi; + + var10 &= 0xFFFFFFE3; + var10 |= 0x22; + var10 &= 0xFFFFFEBF; + var10 |= 0x80; + var10 |= 0x200; + var10 &= 0xfffffffe; + var10 &= 0xfffffbff; + var10 |= 0x1800; + // var10 = 0x1AA2 + var4 = 0x10000000; + varc = 0x00830000; + var8 = 0x00830000; + + /* Init Bank registers. */ + for (edi = 0; edi < (NR_WT / NR_WT_PB); edi++) { + vortex_wt_SetReg(vortex, 0xc, edi, 0); /* ds_reg */ + vortex_wt_SetReg(vortex, 0xa, edi, var10); /* ctrl */ + vortex_wt_SetReg(vortex, 0x9, edi, var4); /* mramp */ + vortex_wt_SetReg(vortex, 0x8, edi, varc); /* aramp */ + vortex_wt_SetReg(vortex, 0x5, edi, var8); /* sramp */ + } + /* Init Voice registers. */ + for (edi = 0; edi < NR_WT; edi++) { + vortex_wt_SetReg(vortex, 0x4, edi, 0); /* param 3 0x20c */ + vortex_wt_SetReg(vortex, 0x3, edi, 0); /* param 2 0x208 */ + vortex_wt_SetReg(vortex, 0x2, edi, 0); /* param 1 0x204 */ + vortex_wt_SetReg(vortex, 0x1, edi, 0); /* param 0 0x200 */ + vortex_wt_SetReg(vortex, 0xb, edi, 0); /* delay 0x400 - 0x40c */ + } + var10 |= 1; + for (edi = 0; edi < (NR_WT / NR_WT_PB); edi++) + vortex_wt_SetReg(vortex, 0xa, edi, var10); /* ctrl */ +} + +/* Extract of CAdbTopology::SetVolume(struct _ASPVOLUME *) */ +#if 0 +static void vortex_wt_SetVolume(vortex_t * vortex, int wt, int vol[]) +{ + wt_voice_t *voice = &(vortex->wt_voice[wt]); + int ecx = vol[1], eax = vol[0]; + + /* This is pure guess */ + voice->parm0 &= 0xff00ffff; + voice->parm0 |= (vol[0] & 0xff) << 0x10; + voice->parm1 &= 0xff00ffff; + voice->parm1 |= (vol[1] & 0xff) << 0x10; + + /* This is real */ + hwwrite(vortex, WT_PARM(wt, 0), voice->parm0); + hwwrite(vortex, WT_PARM(wt, 1), voice->parm0); + + if (voice->this_1D0 & 4) { + eax >>= 8; + ecx = eax; + if (ecx < 0x80) + ecx = 0x7f; + voice->parm3 &= 0xFFFFC07F; + voice->parm3 |= (ecx & 0x7f) << 7; + voice->parm3 &= 0xFFFFFF80; + voice->parm3 |= (eax & 0x7f); + } else { + voice->parm3 &= 0xFFE03FFF; + voice->parm3 |= (eax & 0xFE00) << 5; + } + + hwwrite(vortex, WT_PARM(wt, 3), voice->parm3); +} + +/* Extract of CAdbTopology::SetFrequency(unsigned long arg_0) */ +static void vortex_wt_SetFrequency(vortex_t * vortex, int wt, unsigned int sr) +{ + wt_voice_t *voice = &(vortex->wt_voice[wt]); + long int eax, edx; + + //FIXME: 64 bit operation. + eax = ((sr << 0xf) * 0x57619F1) & 0xffffffff; + edx = (((sr << 0xf) * 0x57619F1)) >> 0x20; + + edx >>= 0xa; + edx <<= 1; + if (edx) { + if (edx & 0x0FFF80000) + eax = 0x7fff; + else { + edx <<= 0xd; + eax = 7; + while ((edx & 0x80000000) == 0) { + edx <<= 1; + eax--; + if (eax == 0) ; + break; + } + if (eax) + edx <<= 1; + eax <<= 0xc; + edx >>= 0x14; + eax |= edx; + } + } else + eax = 0; + voice->parm0 &= 0xffff0001; + voice->parm0 |= (eax & 0x7fff) << 1; + voice->parm1 = voice->parm0 | 1; + // Wt: this_1D4 + //AuWt::WriteReg((ulong)(this_1DC<<4)+0x200, (ulong)this_1E4); + //AuWt::WriteReg((ulong)(this_1DC<<4)+0x204, (ulong)this_1E8); + hwwrite(vortex->mmio, WT_PARM(wt, 0), voice->parm0); + hwwrite(vortex->mmio, WT_PARM(wt, 1), voice->parm1); +} +#endif + +/* End of File */ diff -Nru a/sound/pci/au88x0/au88x0_wt.h b/sound/pci/au88x0/au88x0_wt.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/au88x0/au88x0_wt.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,65 @@ +/*************************************************************************** + * WT register offsets. + * + * Wed Oct 22 13:50:20 2003 + * Copyright 2003 mjander + * mjander@users.sourceforge.org + ****************************************************************************/ +#ifndef _AU88X0_WT_H +#define _AU88X0_WT_H + +/* WT channels are grouped in banks. Each bank has 0x20 channels. */ +/* Bank register address boundary is 0x8000 */ + +#define NR_WT_PB 0x20 + +/* WT bank base register (as dword address). */ +#define WT_BAR(x) (((x)&0xffe0)<<0x8) +#define WT_BANK(x) (x>>5) +/* WT Bank registers */ +#define WT_CTRL(bank) (((((bank)&1)<<0xd) + 0x00)<<2) /* 0x0000 */ +#define WT_SRAMP(bank) (((((bank)&1)<<0xd) + 0x01)<<2) /* 0x0004 */ +#define WT_DSREG(bank) (((((bank)&1)<<0xd) + 0x02)<<2) /* 0x0008 */ +#define WT_MRAMP(bank) (((((bank)&1)<<0xd) + 0x03)<<2) /* 0x000c */ +#define WT_GMODE(bank) (((((bank)&1)<<0xd) + 0x04)<<2) /* 0x0010 */ +#define WT_ARAMP(bank) (((((bank)&1)<<0xd) + 0x05)<<2) /* 0x0014 */ +/* WT Voice registers */ +#define WT_STEREO(voice) ((WT_BAR(voice)+ 0x20 +(((voice)&0x1f)>>1))<<2) /* 0x0080 */ +#define WT_MUTE(voice) ((WT_BAR(voice)+ 0x40 +((voice)&0x1f))<<2) /* 0x0100 */ +#define WT_RUN(voice) ((WT_BAR(voice)+ 0x60 +((voice)&0x1f))<<2) /* 0x0180 */ +/* Some kind of parameters. */ +/* PARM0, PARM1 : Filter (0xFF000000), SampleRate (0x0000FFFF) */ +/* PARM2, PARM3 : Still unknown */ +#define WT_PARM(x,y) (((WT_BAR(x))+ 0x80 +(((x)&0x1f)<<2)+(y))<<2) /* 0x0200 */ +#define WT_DELAY(x,y) (((WT_BAR(x))+ 0x100 +(((x)&0x1f)<<2)+(y))<<2) /* 0x0400 */ + +/* Numeric indexes used by SetReg() and GetReg() */ +#if 0 +enum { + run = 0, /* 0 W 1:run 0:stop */ + parm0, /* 1 W filter, samplerate */ + parm1, /* 2 W filter, samplerate */ + parm2, /* 3 W */ + parm3, /* 4 RW volume. This value is calculated using floating point ops. */ + sramp, /* 5 W */ + mute, /* 6 W 1:mute, 0:unmute */ + gmode, /* 7 RO Looks like only bit0 is used. */ + aramp, /* 8 W */ + mramp, /* 9 W */ + ctrl, /* a W */ + delay, /* b W All 4 values are written at once with same value. */ + dsreg, /* c (R)W */ +} wt_reg; +#endif + +typedef struct { + unsigned int parm0; /* this_1E4 */ + unsigned int parm1; /* this_1E8 */ + unsigned int parm2; /* this_1EC */ + unsigned int parm3; /* this_1F0 */ + unsigned int this_1D0; +} wt_voice_t; + +#endif /* _AU88X0_WT_H */ + +/* End of file */ diff -Nru a/sound/pci/au88x0/au88x0_xtalk.c b/sound/pci/au88x0/au88x0_xtalk.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/au88x0/au88x0_xtalk.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,781 @@ +/*************************************************************************** + * au88x0_cxtalk.c + * + * Wed Nov 19 16:29:47 2003 + * Copyright 2003 mjander + * mjander@users.sourceforge.org + ****************************************************************************/ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "au88x0_xtalk.h" + +/* Data (a whole lot of data.... ) */ + +static short const sXtalkWideKLeftEq = 0x269C; +static short const sXtalkWideKRightEq = 0x269C; +static short const sXtalkWideKLeftXt = 0xF25E; +static short const sXtalkWideKRightXt = 0xF25E; +static short const sXtalkWideShiftLeftEq = 1; +static short const sXtalkWideShiftRightEq = 1; +static short const sXtalkWideShiftLeftXt = 0; +static short const sXtalkWideShiftRightXt = 0; +static unsigned short const wXtalkWideLeftDelay = 0xd; +static unsigned short const wXtalkWideRightDelay = 0xd; +static short const sXtalkNarrowKLeftEq = 0x468D; +static short const sXtalkNarrowKRightEq = 0x468D; +static short const sXtalkNarrowKLeftXt = 0xF82E; +static short const sXtalkNarrowKRightXt = 0xF82E; +static short const sXtalkNarrowShiftLeftEq = 0x3; +static short const sXtalkNarrowShiftRightEq = 0x3; +static short const sXtalkNarrowShiftLeftXt = 0; +static short const sXtalkNarrowShiftRightXt = 0; +static unsigned short const wXtalkNarrowLeftDelay = 0x7; +static unsigned short const wXtalkNarrowRightDelay = 0x7; + +static xtalk_gains_t const asXtalkGainsDefault = { + 0x4000, 0x4000, 4000, 0x4000, 4000, 0x4000, 4000, 0x4000, 4000, + 0x4000 +}; + +static xtalk_gains_t const asXtalkGainsTest = { + 0x8000, 0x7FFF, 0, 0xFFFF, 0x0001, 0xC000, 0x4000, 0xFFFE, 0x0002, + 0 +}; +static xtalk_gains_t const asXtalkGains1Chan = { + 0x7FFF, 0, 0, 0, 0x7FFF, 0, 0, 0, 0, 0 +}; + +// Input gain for 4 A3D slices. One possible input pair is left zero. +static xtalk_gains_t const asXtalkGainsAllChan = { + 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, + 0 + //0x7FFF,0x7FFF,0x7FFF,0x7FFF,0x7fff,0x7FFF,0x7FFF,0x7FFF,0x7FFF,0x7fff +}; +static xtalk_gains_t const asXtalkGainsZeros = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static xtalk_dline_t const alXtalkDlineZeros = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 +}; +static xtalk_dline_t const alXtalkDlineTest = { + 0xFC18, 0x03E8FFFF, 0x186A0, 0x7960FFFE, 1, 0xFFFFFFFF, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0 +}; + +static xtalk_instate_t const asXtalkInStateZeros = { 0, 0, 0, 0 }; +static xtalk_instate_t const asXtalkInStateTest = + { 0xFF80, 0x0080, 0xFFFF, 0x0001 }; +static xtalk_state_t const asXtalkOutStateZeros = { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0} +}; +static short const sDiamondKLeftEq = 0x401d; +static short const sDiamondKRightEq = 0x401d; +static short const sDiamondKLeftXt = 0xF90E; +static short const sDiamondKRightXt = 0xF90E; +static short const sDiamondShiftLeftEq = 1; /* 0xF90E Is this a bug ??? */ +static short const sDiamondShiftRightEq = 1; +static short const sDiamondShiftLeftXt = 0; +static short const sDiamondShiftRightXt = 0; +static unsigned short const wDiamondLeftDelay = 0xb; +static unsigned short const wDiamondRightDelay = 0xb; + +static xtalk_coefs_t const asXtalkWideCoefsLeftEq = { + {0xEC4C, 0xDCE9, 0xFDC2, 0xFEEC, 0}, + {0x5F60, 0xCBCB, 0xFC26, 0x0305, 0}, + {0x340B, 0xf504, 0x6CE8, 0x0D23, 0x00E4}, + {0xD500, 0x8D76, 0xACC7, 0x5B05, 0x00FA}, + {0x7F04, 0xC0FA, 0x0263, 0xFDA2, 0} +}; +static xtalk_coefs_t const asXtalkWideCoefsRightEq = { + {0xEC4C, 0xDCE9, 0xFDC2, 0xFEEC, 0}, + {0x5F60, 0xCBCB, 0xFC26, 0x0305, 0}, + {0x340B, 0xF504, 0x6CE8, 0x0D23, 0x00E4}, + {0xD500, 0x8D76, 0xACC7, 0x5B05, 0x00FA}, + {0x7F04, 0xC0FA, 0x0263, 0xFDA2, 0} +}; +static xtalk_coefs_t const asXtalkWideCoefsLeftXt = { + {0x86C3, 0x7B55, 0x89C3, 0x005B, 0x0047}, + {0x6000, 0x206A, 0xC6CA, 0x40FF, 0}, + {0x1100, 0x1164, 0xA1D7, 0x90FC, 0x0001}, + {0xDC00, 0x9E77, 0xB8C7, 0x0AFF, 0}, + {0, 0, 0, 0, 0} +}; +static xtalk_coefs_t const asXtalkWideCoefsRightXt = { + {0x86C3, 0x7B55, 0x89C3, 0x005B, 0x0047}, + {0x6000, 0x206A, 0xC6CA, 0x40FF, 0}, + {0x1100, 0x1164, 0xA1D7, 0x90FC, 0x0001}, + {0xDC00, 0x9E77, 0xB8C7, 0x0AFF, 0}, + {0, 0, 0, 0, 0} +}; +static xtalk_coefs_t const asXtalkNarrowCoefsLeftEq = { + {0x50B5, 0xD07C, 0x026D, 0xFD21, 0}, + {0x460F, 0xE44F, 0xF75E, 0xEFA6, 0}, + {0x556D, 0xDCAB, 0x2098, 0xF0F2, 0}, + {0x7E03, 0xC1F0, 0x007D, 0xFF89, 0}, + {0x383E, 0xFD9D, 0xB278, 0x4547, 0} +}; + +static xtalk_coefs_t const asXtalkNarrowCoefsRightEq = { + {0x50B5, 0xD07C, 0x026D, 0xFD21, 0}, + {0x460F, 0xE44F, 0xF75E, 0xEFA6, 0}, + {0x556D, 0xDCAB, 0x2098, 0xF0F2, 0}, + {0x7E03, 0xC1F0, 0x007D, 0xFF89, 0}, + {0x383E, 0xFD9D, 0xB278, 0x4547, 0} +}; + +static xtalk_coefs_t const asXtalkNarrowCoefsLeftXt = { + {0x3CB2, 0xDF49, 0xF6EA, 0x095B, 0}, + {0x6777, 0xC915, 0xFEAF, 0x00B1, 0}, + {0x7762, 0xC7D9, 0x025B, 0xFDA6, 0}, + {0x6B7A, 0xD2AA, 0xF2FB, 0x0B64, 0}, + {0, 0, 0, 0, 0} +}; + +static xtalk_coefs_t const asXtalkNarrowCoefsRightXt = { + {0x3CB2, 0xDF49, 0xF6EA, 0x095B, 0}, + {0x6777, 0xC915, 0xFEAF, 0x00B1, 0}, + {0x7762, 0xC7D9, 0x025B, 0xFDA6, 0}, + {0x6B7A, 0xD2AA, 0xF2FB, 0x0B64, 0}, + {0, 0, 0, 0, 0} +}; + +static xtalk_coefs_t const asXtalkCoefsZeros = { + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0} +}; +static xtalk_coefs_t const asXtalkCoefsPipe = { + {0, 0, 0x0FA0, 0, 0}, + {0, 0, 0x0FA0, 0, 0}, + {0, 0, 0x0FA0, 0, 0}, + {0, 0, 0x0FA0, 0, 0}, + {0, 0, 0x1180, 0, 0}, +}; +static xtalk_coefs_t const asXtalkCoefsNegPipe = { + {0, 0, 0xF380, 0, 0}, + {0, 0, 0xF380, 0, 0}, + {0, 0, 0xF380, 0, 0}, + {0, 0, 0xF380, 0, 0}, + {0, 0, 0xF200, 0, 0} +}; + +static xtalk_coefs_t const asXtalkCoefsNumTest = { + {0, 0, 0xF380, 0x8000, 0x6D60}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0} +}; + +static xtalk_coefs_t const asXtalkCoefsDenTest = { + {0xC000, 0x2000, 0x4000, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0} +}; + +static xtalk_state_t const asXtalkOutStateTest = { + {0x7FFF, 0x0004, 0xFFFC, 0}, + {0xFE00, 0x0008, 0xFFF8, 0x4000}, + {0x200, 0x0010, 0xFFF0, 0xC000}, + {0x8000, 0x0020, 0xFFE0, 0}, + {0, 0, 0, 0} +}; + +static xtalk_coefs_t const asDiamondCoefsLeftEq = { + {0x0F1E, 0x2D05, 0xF8E3, 0x07C8, 0}, + {0x45E2, 0xCA51, 0x0448, 0xFCE7, 0}, + {0xA93E, 0xDBD5, 0x022C, 0x028A, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0} +}; + +static xtalk_coefs_t const asDiamondCoefsRightEq = { + {0x0F1E, 0x2D05, 0xF8E3, 0x07C8, 0}, + {0x45E2, 0xCA51, 0x0448, 0xFCE7, 0}, + {0xA93E, 0xDBD5, 0x022C, 0x028A, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0} +}; + +static xtalk_coefs_t const asDiamondCoefsLeftXt = { + {0x3B50, 0xFE08, 0xF959, 0x0060, 0}, + {0x9FCB, 0xD8F1, 0x00A2, 0x003A, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0} +}; + +static xtalk_coefs_t const asDiamondCoefsRightXt = { + {0x3B50, 0xFE08, 0xF959, 0x0060, 0}, + {0x9FCB, 0xD8F1, 0x00A2, 0x003A, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0} +}; + + /**/ +/* XTalk EQ and XT */ +static void +vortex_XtalkHw_SetLeftEQ(vortex_t * vortex, short arg_0, short arg_4, + xtalk_coefs_t const coefs) +{ + int i; + + for (i = 0; i < 5; i++) { + hwwrite(vortex->mmio, 0x24200 + i * 0x24, coefs[i][0]); + hwwrite(vortex->mmio, 0x24204 + i * 0x24, coefs[i][1]); + hwwrite(vortex->mmio, 0x24208 + i * 0x24, coefs[i][2]); + hwwrite(vortex->mmio, 0x2420c + i * 0x24, coefs[i][3]); + hwwrite(vortex->mmio, 0x24210 + i * 0x24, coefs[i][4]); + } + hwwrite(vortex->mmio, 0x24538, arg_0 & 0xffff); + hwwrite(vortex->mmio, 0x2453C, arg_4 & 0xffff); +} + +static void +vortex_XtalkHw_SetRightEQ(vortex_t * vortex, short arg_0, short arg_4, + xtalk_coefs_t const coefs) +{ + int i; + + for (i = 0; i < 5; i++) { + hwwrite(vortex->mmio, 0x242b4 + i * 0x24, coefs[i][0]); + hwwrite(vortex->mmio, 0x242b8 + i * 0x24, coefs[i][1]); + hwwrite(vortex->mmio, 0x242bc + i * 0x24, coefs[i][2]); + hwwrite(vortex->mmio, 0x242c0 + i * 0x24, coefs[i][3]); + hwwrite(vortex->mmio, 0x242c4 + i * 0x24, coefs[i][4]); + } + hwwrite(vortex->mmio, 0x24540, arg_0 & 0xffff); + hwwrite(vortex->mmio, 0x24544, arg_4 & 0xffff); +} + +static void +vortex_XtalkHw_SetLeftXT(vortex_t * vortex, short arg_0, short arg_4, + xtalk_coefs_t const coefs) +{ + int i; + + for (i = 0; i < 5; i++) { + hwwrite(vortex->mmio, 0x24368 + i * 0x24, coefs[i][0]); + hwwrite(vortex->mmio, 0x2436c + i * 0x24, coefs[i][1]); + hwwrite(vortex->mmio, 0x24370 + i * 0x24, coefs[i][2]); + hwwrite(vortex->mmio, 0x24374 + i * 0x24, coefs[i][3]); + hwwrite(vortex->mmio, 0x24378 + i * 0x24, coefs[i][4]); + } + hwwrite(vortex->mmio, 0x24548, arg_0 & 0xffff); + hwwrite(vortex->mmio, 0x2454C, arg_4 & 0xffff); +} + +static void +vortex_XtalkHw_SetRightXT(vortex_t * vortex, short arg_0, short arg_4, + xtalk_coefs_t const coefs) +{ + int i; + + for (i = 0; i < 5; i++) { + hwwrite(vortex->mmio, 0x2441C + i * 0x24, coefs[i][0]); + hwwrite(vortex->mmio, 0x24420 + i * 0x24, coefs[i][1]); + hwwrite(vortex->mmio, 0x24424 + i * 0x24, coefs[i][2]); + hwwrite(vortex->mmio, 0x24428 + i * 0x24, coefs[i][3]); + hwwrite(vortex->mmio, 0x2442C + i * 0x24, coefs[i][4]); + } + hwwrite(vortex->mmio, 0x24550, arg_0 & 0xffff); + hwwrite(vortex->mmio, 0x24554, arg_4 & 0xffff); +} + +static void +vortex_XtalkHw_SetLeftEQStates(vortex_t * vortex, + xtalk_instate_t const arg_0, + xtalk_state_t const coefs) +{ + int i; + + for (i = 0; i < 5; i++) { + hwwrite(vortex->mmio, 0x24214 + i * 0x24, coefs[i][0]); + hwwrite(vortex->mmio, 0x24218 + i * 0x24, coefs[i][1]); + hwwrite(vortex->mmio, 0x2421C + i * 0x24, coefs[i][2]); + hwwrite(vortex->mmio, 0x24220 + i * 0x24, coefs[i][3]); + } + hwwrite(vortex->mmio, 0x244F8 + i * 0x24, arg_0[0]); + hwwrite(vortex->mmio, 0x244FC + i * 0x24, arg_0[1]); + hwwrite(vortex->mmio, 0x24500 + i * 0x24, arg_0[2]); + hwwrite(vortex->mmio, 0x24504 + i * 0x24, arg_0[3]); +} + +static void +vortex_XtalkHw_SetRightEQStates(vortex_t * vortex, + xtalk_instate_t const arg_0, + xtalk_state_t const coefs) +{ + int i; + + for (i = 0; i < 5; i++) { + hwwrite(vortex->mmio, 0x242C8 + i * 0x24, coefs[i][0]); + hwwrite(vortex->mmio, 0x242CC + i * 0x24, coefs[i][1]); + hwwrite(vortex->mmio, 0x242D0 + i * 0x24, coefs[i][2]); + hwwrite(vortex->mmio, 0x244D4 + i * 0x24, coefs[i][3]); + } + hwwrite(vortex->mmio, 0x24508 + i * 0x24, arg_0[0]); + hwwrite(vortex->mmio, 0x2450C + i * 0x24, arg_0[1]); + hwwrite(vortex->mmio, 0x24510 + i * 0x24, arg_0[2]); + hwwrite(vortex->mmio, 0x24514 + i * 0x24, arg_0[3]); +} + +static void +vortex_XtalkHw_SetLeftXTStates(vortex_t * vortex, + xtalk_instate_t const arg_0, + xtalk_state_t const coefs) +{ + int i; + + for (i = 0; i < 5; i++) { + hwwrite(vortex->mmio, 0x2437C + i * 0x24, coefs[i][0]); + hwwrite(vortex->mmio, 0x24380 + i * 0x24, coefs[i][1]); + hwwrite(vortex->mmio, 0x24384 + i * 0x24, coefs[i][2]); + hwwrite(vortex->mmio, 0x24388 + i * 0x24, coefs[i][3]); + } + hwwrite(vortex->mmio, 0x24518 + i * 0x24, arg_0[0]); + hwwrite(vortex->mmio, 0x2451C + i * 0x24, arg_0[1]); + hwwrite(vortex->mmio, 0x24520 + i * 0x24, arg_0[2]); + hwwrite(vortex->mmio, 0x24524 + i * 0x24, arg_0[3]); +} + +static void +vortex_XtalkHw_SetRightXTStates(vortex_t * vortex, + xtalk_instate_t const arg_0, + xtalk_state_t const coefs) +{ + int i; + + for (i = 0; i < 5; i++) { + hwwrite(vortex->mmio, 0x24430 + i * 0x24, coefs[i][0]); + hwwrite(vortex->mmio, 0x24434 + i * 0x24, coefs[i][1]); + hwwrite(vortex->mmio, 0x24438 + i * 0x24, coefs[i][2]); + hwwrite(vortex->mmio, 0x2443C + i * 0x24, coefs[i][3]); + } + hwwrite(vortex->mmio, 0x24528 + i * 0x24, arg_0[0]); + hwwrite(vortex->mmio, 0x2452C + i * 0x24, arg_0[1]); + hwwrite(vortex->mmio, 0x24530 + i * 0x24, arg_0[2]); + hwwrite(vortex->mmio, 0x24534 + i * 0x24, arg_0[3]); +} + +#if 0 +static void +vortex_XtalkHw_GetLeftEQ(vortex_t * vortex, short *arg_0, short *arg_4, + xtalk_coefs_t coefs) +{ + int i; + + for (i = 0; i < 5; i++) { + coefs[i][0] = hwread(vortex->mmio, 0x24200 + i * 0x24); + coefs[i][1] = hwread(vortex->mmio, 0x24204 + i * 0x24); + coefs[i][2] = hwread(vortex->mmio, 0x24208 + i * 0x24); + coefs[i][3] = hwread(vortex->mmio, 0x2420c + i * 0x24); + coefs[i][4] = hwread(vortex->mmio, 0x24210 + i * 0x24); + } + *arg_0 = hwread(vortex->mmio, 0x24538) & 0xffff; + *arg_4 = hwread(vortex->mmio, 0x2453c) & 0xffff; +} + +static void +vortex_XtalkHw_GetRightEQ(vortex_t * vortex, short *arg_0, short *arg_4, + xtalk_coefs_t coefs) +{ + int i; + + for (i = 0; i < 5; i++) { + coefs[i][0] = hwread(vortex->mmio, 0x242b4 + i * 0x24); + coefs[i][1] = hwread(vortex->mmio, 0x242b8 + i * 0x24); + coefs[i][2] = hwread(vortex->mmio, 0x242bc + i * 0x24); + coefs[i][3] = hwread(vortex->mmio, 0x242c0 + i * 0x24); + coefs[i][4] = hwread(vortex->mmio, 0x242c4 + i * 0x24); + } + *arg_0 = hwread(vortex->mmio, 0x24540) & 0xffff; + *arg_4 = hwread(vortex->mmio, 0x24544) & 0xffff; +} + +static void +vortex_XtalkHw_GetLeftXT(vortex_t * vortex, short *arg_0, short *arg_4, + xtalk_coefs_t coefs) +{ + int i; + + for (i = 0; i < 5; i++) { + coefs[i][0] = hwread(vortex->mmio, 0x24368 + i * 0x24); + coefs[i][1] = hwread(vortex->mmio, 0x2436C + i * 0x24); + coefs[i][2] = hwread(vortex->mmio, 0x24370 + i * 0x24); + coefs[i][3] = hwread(vortex->mmio, 0x24374 + i * 0x24); + coefs[i][4] = hwread(vortex->mmio, 0x24378 + i * 0x24); + } + *arg_0 = hwread(vortex->mmio, 0x24548) & 0xffff; + *arg_4 = hwread(vortex->mmio, 0x2454C) & 0xffff; +} + +static void +vortex_XtalkHw_GetRightXT(vortex_t * vortex, short *arg_0, short *arg_4, + xtalk_coefs_t coefs) +{ + int i; + + for (i = 0; i < 5; i++) { + coefs[i][0] = hwread(vortex->mmio, 0x2441C + i * 0x24); + coefs[i][1] = hwread(vortex->mmio, 0x24420 + i * 0x24); + coefs[i][2] = hwread(vortex->mmio, 0x24424 + i * 0x24); + coefs[i][3] = hwread(vortex->mmio, 0x24428 + i * 0x24); + coefs[i][4] = hwread(vortex->mmio, 0x2442C + i * 0x24); + } + *arg_0 = hwread(vortex->mmio, 0x24550) & 0xffff; + *arg_4 = hwread(vortex->mmio, 0x24554) & 0xffff; +} + +static void +vortex_XtalkHw_GetLeftEQStates(vortex_t * vortex, xtalk_instate_t arg_0, + xtalk_state_t coefs) +{ + int i; + + for (i = 0; i < 5; i++) { + coefs[i][0] = hwread(vortex->mmio, 0x24214 + i * 0x24); + coefs[i][1] = hwread(vortex->mmio, 0x24218 + i * 0x24); + coefs[i][2] = hwread(vortex->mmio, 0x2421C + i * 0x24); + coefs[i][3] = hwread(vortex->mmio, 0x24220 + i * 0x24); + } + arg_0[0] = hwread(vortex->mmio, 0x244F8 + i * 0x24); + arg_0[1] = hwread(vortex->mmio, 0x244FC + i * 0x24); + arg_0[2] = hwread(vortex->mmio, 0x24500 + i * 0x24); + arg_0[3] = hwread(vortex->mmio, 0x24504 + i * 0x24); +} + +static void +vortex_XtalkHw_GetRightEQStates(vortex_t * vortex, xtalk_instate_t arg_0, + xtalk_state_t coefs) +{ + int i; + + for (i = 0; i < 5; i++) { + coefs[i][0] = hwread(vortex->mmio, 0x242C8 + i * 0x24); + coefs[i][1] = hwread(vortex->mmio, 0x242CC + i * 0x24); + coefs[i][2] = hwread(vortex->mmio, 0x242D0 + i * 0x24); + coefs[i][3] = hwread(vortex->mmio, 0x242D4 + i * 0x24); + } + arg_0[0] = hwread(vortex->mmio, 0x24508 + i * 0x24); + arg_0[1] = hwread(vortex->mmio, 0x2450C + i * 0x24); + arg_0[2] = hwread(vortex->mmio, 0x24510 + i * 0x24); + arg_0[3] = hwread(vortex->mmio, 0x24514 + i * 0x24); +} + +static void +vortex_XtalkHw_GetLeftXTStates(vortex_t * vortex, xtalk_instate_t arg_0, + xtalk_state_t coefs) +{ + int i; + + for (i = 0; i < 5; i++) { + coefs[i][0] = hwread(vortex->mmio, 0x2437C + i * 0x24); + coefs[i][1] = hwread(vortex->mmio, 0x24380 + i * 0x24); + coefs[i][2] = hwread(vortex->mmio, 0x24384 + i * 0x24); + coefs[i][3] = hwread(vortex->mmio, 0x24388 + i * 0x24); + } + arg_0[0] = hwread(vortex->mmio, 0x24518 + i * 0x24); + arg_0[1] = hwread(vortex->mmio, 0x2451C + i * 0x24); + arg_0[2] = hwread(vortex->mmio, 0x24520 + i * 0x24); + arg_0[3] = hwread(vortex->mmio, 0x24524 + i * 0x24); +} + +static void +vortex_XtalkHw_GetRightXTStates(vortex_t * vortex, xtalk_instate_t arg_0, + xtalk_state_t coefs) +{ + int i; + + for (i = 0; i < 5; i++) { + coefs[i][0] = hwread(vortex->mmio, 0x24430 + i * 0x24); + coefs[i][1] = hwread(vortex->mmio, 0x24434 + i * 0x24); + coefs[i][2] = hwread(vortex->mmio, 0x24438 + i * 0x24); + coefs[i][3] = hwread(vortex->mmio, 0x2443C + i * 0x24); + } + arg_0[0] = hwread(vortex->mmio, 0x24528 + i * 0x24); + arg_0[1] = hwread(vortex->mmio, 0x2452C + i * 0x24); + arg_0[2] = hwread(vortex->mmio, 0x24530 + i * 0x24); + arg_0[3] = hwread(vortex->mmio, 0x24534 + i * 0x24); +} + +#endif +/* Gains */ + +static void +vortex_XtalkHw_SetGains(vortex_t * vortex, xtalk_gains_t const gains) +{ + int i; + + for (i = 0; i < XTGAINS_SZ; i++) { + hwwrite(vortex->mmio, 0x244D0 + (i * 4), gains[i]); + } +} + +#if 0 +static void vortex_XtalkHw_GetGains(vortex_t * vortex, xtalk_gains_t gains) +{ + int i; + + for (i = 0; i < XTGAINS_SZ; i++) + gains[i] = hwread(vortex->mmio, 0x244D0 + i * 4); +} + +#endif +/* Delay parameters */ + +static void +vortex_XtalkHw_SetDelay(vortex_t * vortex, unsigned short right, + unsigned short left) +{ + int esp0 = 0; + + esp0 &= 0x1FFFFFFF; + esp0 |= 0xA0000000; + esp0 = (esp0 & 0xffffE0ff) | ((right & 0x1F) << 8); + esp0 = (esp0 & 0xfffc1fff) | ((left & 0x1F) << 0xd); + + hwwrite(vortex->mmio, 0x24660, esp0); +} + +static void +vortex_XtalkHw_SetLeftDline(vortex_t * vortex, xtalk_dline_t const dline) +{ + int i; + + for (i = 0; i < 0x20; i++) { + hwwrite(vortex->mmio, 0x24000 + (i << 2), dline[i] & 0xffff); + hwwrite(vortex->mmio, 0x24080 + (i << 2), dline[i] >> 0x10); + } +} + +static void +vortex_XtalkHw_SetRightDline(vortex_t * vortex, xtalk_dline_t const dline) +{ + int i; + + for (i = 0; i < 0x20; i++) { + hwwrite(vortex->mmio, 0x24100 + (i << 2), dline[i] & 0xffff); + hwwrite(vortex->mmio, 0x24180 + (i << 2), dline[i] >> 0x10); + } +} + +#if 0 +static void +vortex_XtalkHw_GetDelay(vortex_t * vortex, unsigned short *right, + unsigned short *left) +{ + int esp0; + + esp0 = hwread(vortex->mmio, 0x24660); + *right = (esp0 >> 8) & 0x1f; + *left = (esp0 >> 0xd) & 0x1f; +} + +static void vortex_XtalkHw_GetLeftDline(vortex_t * vortex, xtalk_dline_t dline) +{ + int i; + + for (i = 0; i < 0x20; i++) { + dline[i] = + (hwread(vortex->mmio, 0x24000 + (i << 2)) & 0xffff) | + (hwread(vortex->mmio, 0x24080 + (i << 2)) << 0x10); + } +} + +static void vortex_XtalkHw_GetRightDline(vortex_t * vortex, xtalk_dline_t dline) +{ + int i; + + for (i = 0; i < 0x20; i++) { + dline[i] = + (hwread(vortex->mmio, 0x24100 + (i << 2)) & 0xffff) | + (hwread(vortex->mmio, 0x24180 + (i << 2)) << 0x10); + } +} + +#endif +/* Control/Global stuff */ + +#if 0 +static void vortex_XtalkHw_SetControlReg(vortex_t * vortex, unsigned long ctrl) +{ + hwwrite(vortex->mmio, 0x24660, ctrl); +} +static void vortex_XtalkHw_GetControlReg(vortex_t * vortex, unsigned long *ctrl) +{ + *ctrl = hwread(vortex->mmio, 0x24660); +} +#endif +static void vortex_XtalkHw_SetSampleRate(vortex_t * vortex, int sr) +{ + int temp; + + temp = (hwread(vortex->mmio, 0x24660) & 0x1FFFFFFF) | 0xC0000000; + temp = (temp & 0xffffff07) | ((sr & 0x1f) << 3); + hwwrite(vortex->mmio, 0x24660, temp); +} + +#if 0 +static void vortex_XtalkHw_GetSampleRate(vortex_t * vortex, int *sr) +{ + *sr = (hwread(vortex->mmio, 0x24660) >> 3) & 0x1f; +} + +#endif +static void vortex_XtalkHw_Enable(vortex_t * vortex) +{ + int temp; + + temp = (hwread(vortex->mmio, 0x24660) & 0x1FFFFFFF) | 0xC0000000; + temp |= 1; + hwwrite(vortex->mmio, 0x24660, temp); + +} + +static void vortex_XtalkHw_Disable(vortex_t * vortex) +{ + int temp; + + temp = (hwread(vortex->mmio, 0x24660) & 0x1FFFFFFF) | 0xC0000000; + temp &= 0xfffffffe; + hwwrite(vortex->mmio, 0x24660, temp); + +} + +static void vortex_XtalkHw_ZeroIO(vortex_t * vortex) +{ + int i; + + for (i = 0; i < 20; i++) + hwwrite(vortex->mmio, 0x24600 + (i << 2), 0); + for (i = 0; i < 4; i++) + hwwrite(vortex->mmio, 0x24650 + (i << 2), 0); +} + +static void vortex_XtalkHw_ZeroState(vortex_t * vortex) +{ + vortex_XtalkHw_ZeroIO(vortex); // inlined + + vortex_XtalkHw_SetLeftEQ(vortex, 0, 0, asXtalkCoefsZeros); + vortex_XtalkHw_SetRightEQ(vortex, 0, 0, asXtalkCoefsZeros); + + vortex_XtalkHw_SetLeftXT(vortex, 0, 0, asXtalkCoefsZeros); + vortex_XtalkHw_SetRightXT(vortex, 0, 0, asXtalkCoefsZeros); + + vortex_XtalkHw_SetGains(vortex, asXtalkGainsZeros); // inlined + + vortex_XtalkHw_SetDelay(vortex, 0, 0); // inlined + + vortex_XtalkHw_SetLeftDline(vortex, alXtalkDlineZeros); // inlined + vortex_XtalkHw_SetRightDline(vortex, alXtalkDlineZeros); // inlined + vortex_XtalkHw_SetLeftDline(vortex, alXtalkDlineZeros); // inlined + vortex_XtalkHw_SetRightDline(vortex, alXtalkDlineZeros); // inlined + + vortex_XtalkHw_SetLeftEQStates(vortex, asXtalkInStateZeros, + asXtalkOutStateZeros); + vortex_XtalkHw_SetRightEQStates(vortex, asXtalkInStateZeros, + asXtalkOutStateZeros); + vortex_XtalkHw_SetLeftXTStates(vortex, asXtalkInStateZeros, + asXtalkOutStateZeros); + vortex_XtalkHw_SetRightXTStates(vortex, asXtalkInStateZeros, + asXtalkOutStateZeros); +} + +static void vortex_XtalkHw_ProgramPipe(vortex_t * vortex) +{ + + vortex_XtalkHw_SetLeftEQ(vortex, 0, 1, asXtalkCoefsPipe); + vortex_XtalkHw_SetRightEQ(vortex, 0, 1, asXtalkCoefsPipe); + vortex_XtalkHw_SetLeftXT(vortex, 0, 0, asXtalkCoefsZeros); + vortex_XtalkHw_SetRightXT(vortex, 0, 0, asXtalkCoefsZeros); + + vortex_XtalkHw_SetDelay(vortex, 0, 0); // inlined +} + +static void vortex_XtalkHw_ProgramXtalkWide(vortex_t * vortex) +{ + + vortex_XtalkHw_SetLeftEQ(vortex, sXtalkWideKLeftEq, + sXtalkWideShiftLeftEq, asXtalkWideCoefsLeftEq); + vortex_XtalkHw_SetRightEQ(vortex, sXtalkWideKRightEq, + sXtalkWideShiftRightEq, + asXtalkWideCoefsRightEq); + vortex_XtalkHw_SetLeftXT(vortex, sXtalkWideKLeftXt, + sXtalkWideShiftLeftXt, asXtalkWideCoefsLeftXt); + vortex_XtalkHw_SetRightXT(vortex, sXtalkWideKLeftXt, + sXtalkWideShiftLeftXt, + asXtalkWideCoefsLeftXt); + + vortex_XtalkHw_SetDelay(vortex, wXtalkWideRightDelay, wXtalkWideLeftDelay); // inlined +} + +static void vortex_XtalkHw_ProgramXtalkNarrow(vortex_t * vortex) +{ + + vortex_XtalkHw_SetLeftEQ(vortex, sXtalkNarrowKLeftEq, + sXtalkNarrowShiftLeftEq, + asXtalkNarrowCoefsLeftEq); + vortex_XtalkHw_SetRightEQ(vortex, sXtalkNarrowKRightEq, + sXtalkNarrowShiftRightEq, + asXtalkNarrowCoefsRightEq); + vortex_XtalkHw_SetLeftXT(vortex, sXtalkNarrowKLeftXt, + sXtalkNarrowShiftLeftXt, + asXtalkNarrowCoefsLeftXt); + vortex_XtalkHw_SetRightXT(vortex, sXtalkNarrowKLeftXt, + sXtalkNarrowShiftLeftXt, + asXtalkNarrowCoefsLeftXt); + + vortex_XtalkHw_SetDelay(vortex, wXtalkNarrowRightDelay, wXtalkNarrowLeftDelay); // inlined +} + +static void vortex_XtalkHw_ProgramDiamondXtalk(vortex_t * vortex) +{ + + //sDiamondKLeftEq,sDiamondKRightXt,asDiamondCoefsLeftEq + vortex_XtalkHw_SetLeftEQ(vortex, sDiamondKLeftEq, + sDiamondShiftLeftEq, asDiamondCoefsLeftEq); + vortex_XtalkHw_SetRightEQ(vortex, sDiamondKRightEq, + sDiamondShiftRightEq, asDiamondCoefsRightEq); + vortex_XtalkHw_SetLeftXT(vortex, sDiamondKLeftXt, + sDiamondShiftLeftXt, asDiamondCoefsLeftXt); + vortex_XtalkHw_SetRightXT(vortex, sDiamondKLeftXt, + sDiamondShiftLeftXt, asDiamondCoefsLeftXt); + + vortex_XtalkHw_SetDelay(vortex, wDiamondRightDelay, wDiamondLeftDelay); // inlined +} + +static void vortex_XtalkHw_init(vortex_t * vortex) +{ + vortex_XtalkHw_ZeroState(vortex); +} + +/* End of file */ diff -Nru a/sound/pci/au88x0/au88x0_xtalk.h b/sound/pci/au88x0/au88x0_xtalk.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/au88x0/au88x0_xtalk.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,62 @@ +/*************************************************************************** + * au88x0_cxtalk.h + * + * Wed Nov 19 19:07:17 2003 + * Copyright 2003 mjander + * mjander@users.sourceforge.org + ****************************************************************************/ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* The crosstalk canceler supports 5 stereo input channels. The result is + available at one single output route pair (stereo). */ + +#ifndef _AU88X0_CXTALK_H +#define _AU88X0_CXTALK_H + +#include "au88x0.h" + +#define XTDLINE_SZ 32 +#define XTGAINS_SZ 10 +#define XTINST_SZ 4 + +#define XT_HEADPHONE 1 +#define XT_SPEAKER0 2 +#define XT_SPEAKER1 3 +#define XT_DIAMOND 4 + +typedef long xtalk_dline_t[XTDLINE_SZ]; +typedef short xtalk_gains_t[XTGAINS_SZ]; +typedef short xtalk_instate_t[XTINST_SZ]; +typedef short xtalk_coefs_t[5][5]; +typedef short xtalk_state_t[5][4]; + +extern xtalk_gains_t const asXtalkGainsAllChan; + +static void vortex_XtalkHw_SetGains(vortex_t * vortex, + xtalk_gains_t const gains); +static void vortex_XtalkHw_SetSampleRate(vortex_t * vortex, int sr); +static void vortex_XtalkHw_ProgramPipe(vortex_t * vortex); +static void vortex_XtalkHw_ProgramPipe(vortex_t * vortex); +static void vortex_XtalkHw_ProgramXtalkWide(vortex_t * vortex); +static void vortex_XtalkHw_ProgramXtalkNarrow(vortex_t * vortex); +static void vortex_XtalkHw_ProgramDiamondXtalk(vortex_t * vortex); +static void vortex_XtalkHw_Enable(vortex_t * vortex); +static void vortex_XtalkHw_Disable(vortex_t * vortex); +static void vortex_XtalkHw_init(vortex_t * vortex); + +#endif /* _AU88X0_CXTALK_H */ diff -Nru a/sound/pci/azt3328.c b/sound/pci/azt3328.c --- a/sound/pci/azt3328.c Sun Mar 14 14:20:07 2004 +++ b/sound/pci/azt3328.c Sun Mar 14 14:20:07 2004 @@ -1253,7 +1253,8 @@ strcpy(pcm->name, chip->card->shortname); chip->pcm = pcm; - snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 64*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), 64*1024, 64*1024); snd_azf3328_dbgcallleave(); return 0; diff -Nru a/sound/pci/bt87x.c b/sound/pci/bt87x.c --- a/sound/pci/bt87x.c Sun Mar 14 14:20:07 2004 +++ b/sound/pci/bt87x.c Sun Mar 14 14:20:07 2004 @@ -167,8 +167,8 @@ long opened; snd_pcm_substream_t *substream; - u32 *risc; - dma_addr_t risc_dma; + struct snd_dma_device dma_dev; + struct snd_dma_buffer dma_risc; unsigned int line_bytes; unsigned int lines; @@ -195,13 +195,14 @@ unsigned int i, offset; u32 *risc; - if (!chip->risc) { - chip->risc = (u32*)snd_malloc_pci_pages - (chip->pci, PAGE_ALIGN(MAX_RISC_SIZE), &chip->risc_dma); - if (!chip->risc) + if (chip->dma_risc.area == NULL) { + memset(&chip->dma_dev, 0, sizeof(chip->dma_dev)); + chip->dma_dev.type = SNDRV_DMA_TYPE_DEV; + chip->dma_dev.dev = snd_dma_pci_data(chip->pci); + if (snd_dma_alloc_pages(&chip->dma_dev, PAGE_ALIGN(MAX_RISC_SIZE), &chip->dma_risc) < 0) return -ENOMEM; } - risc = chip->risc; + risc = (u32 *)chip->dma_risc.area; offset = 0; *risc++ = cpu_to_le32(RISC_SYNC | RISC_SYNC_FM1); *risc++ = cpu_to_le32(0); @@ -233,7 +234,7 @@ *risc++ = cpu_to_le32(RISC_SYNC | RISC_SYNC_VRO); *risc++ = cpu_to_le32(0); *risc++ = cpu_to_le32(RISC_JUMP); - *risc++ = cpu_to_le32(chip->risc_dma); + *risc++ = cpu_to_le32(chip->dma_risc.addr); chip->line_bytes = period_bytes; chip->lines = periods; return 0; @@ -241,10 +242,9 @@ static void snd_bt87x_free_risc(bt87x_t *chip) { - if (chip->risc) { - snd_free_pci_pages(chip->pci, PAGE_ALIGN(MAX_RISC_SIZE), - chip->risc, chip->risc_dma); - chip->risc = NULL; + if (chip->dma_risc.area) { + snd_dma_free_pages(&chip->dma_dev, &chip->dma_risc); + chip->dma_risc.area = NULL; } } @@ -459,7 +459,7 @@ spin_lock_irqsave(&chip->reg_lock, flags); chip->current_line = 0; chip->reg_control |= CTL_FIFO_ENABLE | CTL_RISC_ENABLE | CTL_ACAP_EN; - snd_bt87x_writel(chip, REG_RISC_STRT_ADD, chip->risc_dma); + snd_bt87x_writel(chip, REG_RISC_STRT_ADD, chip->dma_risc.addr); snd_bt87x_writel(chip, REG_PACKET_LEN, chip->line_bytes | (chip->lines << 16)); snd_bt87x_writel(chip, REG_INT_MASK, MY_INTERRUPTS); @@ -681,7 +681,9 @@ pcm->private_data = chip; strcpy(pcm->name, name); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_bt87x_pcm_ops); - return snd_pcm_lib_preallocate_sg_pages_for_all(chip->pci, pcm, + return snd_pcm_lib_preallocate_pages_for_all(pcm, + SNDRV_DMA_TYPE_DEV_SG, + snd_dma_pci_data(chip->pci), 128 * 1024, (255 * 4092 + 1023) & ~1023); } diff -Nru a/sound/pci/cmipci.c b/sound/pci/cmipci.c --- a/sound/pci/cmipci.c Sun Mar 14 14:20:07 2004 +++ b/sound/pci/cmipci.c Sun Mar 14 14:20:07 2004 @@ -2087,7 +2087,8 @@ strcpy(pcm->name, "C-Media PCI DAC/ADC"); cm->pcm = pcm; - snd_pcm_lib_preallocate_pci_pages_for_all(cm->pci, pcm, 64*1024, 128*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(cm->pci), 64*1024, 128*1024); return 0; } @@ -2109,7 +2110,8 @@ strcpy(pcm->name, "C-Media PCI 2nd DAC"); cm->pcm2 = pcm; - snd_pcm_lib_preallocate_pci_pages_for_all(cm->pci, pcm, 64*1024, 128*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(cm->pci), 64*1024, 128*1024); return 0; } @@ -2139,7 +2141,8 @@ strcpy(pcm->name, "C-Media PCI IEC958"); cm->pcm_spdif = pcm; - snd_pcm_lib_preallocate_pci_pages_for_all(cm->pci, pcm, 64*1024, 128*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(cm->pci), 64*1024, 128*1024); return 0; } @@ -3151,7 +3154,7 @@ #ifdef SUPPORT_JOYSTICK if (joystick_port[dev] > 0) { if (joystick_port[dev] == 1) { /* auto-detect */ - static int ports[] = { 0x200, 0x201, 0 }; + static int ports[] = { 0x201, 0x200, 0 }; /* FIXME: majority is 0x201? */ int i; for (i = 0; ports[i]; i++) { joystick_port[dev] = ports[i]; diff -Nru a/sound/pci/cs4281.c b/sound/pci/cs4281.c --- a/sound/pci/cs4281.c Sun Mar 14 14:20:08 2004 +++ b/sound/pci/cs4281.c Sun Mar 14 14:20:08 2004 @@ -1039,7 +1039,8 @@ strcpy(pcm->name, "CS4281"); chip->pcm = pcm; - snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 512*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), 64*1024, 512*1024); if (rpcm) *rpcm = pcm; diff -Nru a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c --- a/sound/pci/cs46xx/cs46xx_lib.c Sun Mar 14 14:20:06 2004 +++ b/sound/pci/cs46xx/cs46xx_lib.c Sun Mar 14 14:20:06 2004 @@ -66,6 +66,8 @@ #include "cs46xx_lib.h" #include "dsp_spos.h" +static void amp_voyetra(cs46xx_t *chip, int change); + static unsigned short snd_cs46xx_codec_read(cs46xx_t *chip, unsigned short reg, int codec_index) @@ -203,6 +205,13 @@ chip->active_ctrl(chip, 1); val = snd_cs46xx_codec_read(chip, reg, codec_index); chip->active_ctrl(chip, -1); + + /* HACK: voyetra uses EAPD bit in the reverse way. + * we flip the bit to show the mixer status correctly + */ + if (reg == AC97_POWERDOWN && chip->amplifier_ctrl == amp_voyetra) + val ^= 0x8000; + return val; } @@ -284,6 +293,12 @@ else snd_assert(0,return); + /* HACK: voyetra uses EAPD bit in the reverse way. + * we flip the bit to show the mixer status correctly + */ + if (reg == AC97_POWERDOWN && chip->amplifier_ctrl == amp_voyetra) + val ^= 0x8000; + chip->active_ctrl(chip, 1); snd_cs46xx_codec_write(chip, reg, val, codec_index); chip->active_ctrl(chip, -1); @@ -699,7 +714,7 @@ bytes = hw_to_end; if (sw_to_end < bytes) bytes = sw_to_end; - memcpy(cpcm->hw_area + cpcm->hw_data, + memcpy(cpcm->hw_buf.area + cpcm->hw_data, runtime->dma_area + cpcm->sw_data, bytes); cpcm->hw_data += bytes; @@ -740,7 +755,7 @@ if (sw_to_end < bytes) bytes = sw_to_end; memcpy(runtime->dma_area + chip->capt.sw_data, - chip->capt.hw_area + chip->capt.hw_data, + chip->capt.hw_buf.area + chip->capt.hw_data, bytes); chip->capt.hw_data += bytes; if ((int)chip->capt.hw_data == buffer_size) @@ -766,7 +781,7 @@ #else ptr = snd_cs46xx_peek(chip, BA1_PBA); #endif - ptr -= cpcm->hw_addr; + ptr -= cpcm->hw_buf.addr; return ptr >> cpcm->shift; } @@ -784,7 +799,7 @@ #else ptr = snd_cs46xx_peek(chip, BA1_PBA); #endif - ptr -= cpcm->hw_addr; + ptr -= cpcm->hw_buf.addr; bytes = ptr - cpcm->hw_io; @@ -802,14 +817,14 @@ static snd_pcm_uframes_t snd_cs46xx_capture_direct_pointer(snd_pcm_substream_t * substream) { cs46xx_t *chip = snd_pcm_substream_chip(substream); - size_t ptr = snd_cs46xx_peek(chip, BA1_CBA) - chip->capt.hw_addr; + size_t ptr = snd_cs46xx_peek(chip, BA1_CBA) - chip->capt.hw_buf.addr; return ptr >> chip->capt.shift; } static snd_pcm_uframes_t snd_cs46xx_capture_indirect_pointer(snd_pcm_substream_t * substream) { cs46xx_t *chip = snd_pcm_substream_chip(substream); - size_t ptr = snd_cs46xx_peek(chip, BA1_CBA) - chip->capt.hw_addr; + size_t ptr = snd_cs46xx_peek(chip, BA1_CBA) - chip->capt.hw_buf.addr; ssize_t bytes = ptr - chip->capt.hw_io; int buffer_size = substream->runtime->period_size * CS46XX_FRAGS << chip->capt.shift; @@ -933,7 +948,7 @@ /* If PCMReaderSCB and SrcTaskSCB not created yet ... */ if ( cpcm->pcm_channel == NULL) { cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, sample_rate, - cpcm, cpcm->hw_addr,cpcm->pcm_channel_id); + cpcm, cpcm->hw_buf.addr,cpcm->pcm_channel_id); if (cpcm->pcm_channel == NULL) { snd_printk(KERN_ERR "cs46xx: failed to create virtual PCM channel\n"); return -ENOMEM; @@ -946,7 +961,7 @@ cs46xx_dsp_destroy_pcm_channel (chip,cpcm->pcm_channel); if ( (cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, sample_rate, cpcm, - cpcm->hw_addr, + cpcm->hw_buf.addr, cpcm->pcm_channel_id)) == NULL) { snd_printk(KERN_ERR "cs46xx: failed to re-create virtual PCM channel\n"); return -ENOMEM; @@ -1002,11 +1017,11 @@ #endif if (params_periods(hw_params) == CS46XX_FRAGS) { - if (runtime->dma_area != cpcm->hw_area) + if (runtime->dma_area != cpcm->hw_buf.area) snd_pcm_lib_free_pages(substream); - runtime->dma_area = cpcm->hw_area; - runtime->dma_addr = cpcm->hw_addr; - runtime->dma_bytes = cpcm->hw_size; + runtime->dma_area = cpcm->hw_buf.area; + runtime->dma_addr = cpcm->hw_buf.addr; + runtime->dma_bytes = cpcm->hw_buf.bytes; #ifdef CONFIG_SND_CS46XX_NEW_DSP @@ -1026,7 +1041,7 @@ #endif } else { - if (runtime->dma_area == cpcm->hw_area) { + if (runtime->dma_area == cpcm->hw_buf.area) { runtime->dma_area = NULL; runtime->dma_addr = 0; runtime->dma_bytes = 0; @@ -1075,7 +1090,7 @@ is called and cpcm can actually be NULL here */ if (!cpcm) return -ENXIO; - if (runtime->dma_area != cpcm->hw_area) + if (runtime->dma_area != cpcm->hw_buf.area) snd_pcm_lib_free_pages(substream); runtime->dma_area = NULL; @@ -1144,7 +1159,7 @@ /* playback format && interrupt enable */ snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 1) << 2, pfie | cpcm->pcm_channel->pcm_slot); #else - snd_cs46xx_poke(chip, BA1_PBA, cpcm->hw_addr); + snd_cs46xx_poke(chip, BA1_PBA, cpcm->hw_buf.addr); tmp = snd_cs46xx_peek(chip, BA1_PDTC); tmp &= ~0x000003ff; tmp |= (4 << cpcm->shift) - 1; @@ -1167,14 +1182,14 @@ cs46xx_dsp_pcm_ostream_set_period (chip, params_period_bytes(hw_params)); #endif if (runtime->periods == CS46XX_FRAGS) { - if (runtime->dma_area != chip->capt.hw_area) + if (runtime->dma_area != chip->capt.hw_buf.area) snd_pcm_lib_free_pages(substream); - runtime->dma_area = chip->capt.hw_area; - runtime->dma_addr = chip->capt.hw_addr; - runtime->dma_bytes = chip->capt.hw_size; + runtime->dma_area = chip->capt.hw_buf.area; + runtime->dma_addr = chip->capt.hw_buf.addr; + runtime->dma_bytes = chip->capt.hw_buf.bytes; substream->ops = &snd_cs46xx_capture_ops; } else { - if (runtime->dma_area == chip->capt.hw_area) { + if (runtime->dma_area == chip->capt.hw_buf.area) { runtime->dma_area = NULL; runtime->dma_addr = 0; runtime->dma_bytes = 0; @@ -1192,7 +1207,7 @@ cs46xx_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - if (runtime->dma_area != chip->capt.hw_area) + if (runtime->dma_area != chip->capt.hw_buf.area) snd_pcm_lib_free_pages(substream); runtime->dma_area = NULL; runtime->dma_addr = 0; @@ -1206,7 +1221,7 @@ cs46xx_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - snd_cs46xx_poke(chip, BA1_CBA, chip->capt.hw_addr); + snd_cs46xx_poke(chip, BA1_CBA, chip->capt.hw_buf.addr); chip->capt.shift = 2; chip->capt.sw_bufsize = snd_pcm_lib_buffer_bytes(substream); chip->capt.sw_data = chip->capt.sw_io = chip->capt.sw_ready = 0; @@ -1382,8 +1397,7 @@ cpcm = snd_magic_kcalloc(cs46xx_pcm_t, 0, GFP_KERNEL); if (cpcm == NULL) return -ENOMEM; - cpcm->hw_size = PAGE_SIZE; - if ((cpcm->hw_area = snd_malloc_pci_pages(chip->pci, cpcm->hw_size, &cpcm->hw_addr)) == NULL) { + if (snd_dma_alloc_pages(&chip->dma_dev, PAGE_SIZE, &cpcm->hw_buf) < 0) { snd_magic_kfree(cpcm); return -ENOMEM; } @@ -1472,7 +1486,7 @@ { cs46xx_t *chip = snd_pcm_substream_chip(substream); - if ((chip->capt.hw_area = snd_malloc_pci_pages(chip->pci, chip->capt.hw_size, &chip->capt.hw_addr)) == NULL) + if (snd_dma_alloc_pages(&chip->dma_dev, PAGE_SIZE, &chip->capt.hw_buf) < 0) return -ENOMEM; chip->capt.substream = substream; substream->runtime->hw = snd_cs46xx_capture; @@ -1513,7 +1527,7 @@ #endif cpcm->substream = NULL; - snd_free_pci_pages(chip->pci, cpcm->hw_size, cpcm->hw_area, cpcm->hw_addr); + snd_dma_free_pages(&chip->dma_dev, &cpcm->hw_buf); chip->active_ctrl(chip, -1); return 0; @@ -1524,7 +1538,7 @@ cs46xx_t *chip = snd_pcm_substream_chip(substream); chip->capt.substream = NULL; - snd_free_pci_pages(chip->pci, chip->capt.hw_size, chip->capt.hw_area, chip->capt.hw_addr); + snd_dma_free_pages(&chip->dma_dev, &chip->capt.hw_buf); chip->active_ctrl(chip, -1); return 0; @@ -1703,7 +1717,8 @@ strcpy(pcm->name, "CS46xx"); chip->pcm = pcm; - snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), 64*1024, 256*1024); if (rpcm) *rpcm = pcm; @@ -1734,7 +1749,8 @@ strcpy(pcm->name, "CS46xx - Rear"); chip->pcm_rear = pcm; - snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), 64*1024, 256*1024); if (rpcm) *rpcm = pcm; @@ -1763,7 +1779,8 @@ strcpy(pcm->name, "CS46xx - Center LFE"); chip->pcm_center_lfe = pcm; - snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), 64*1024, 256*1024); if (rpcm) *rpcm = pcm; @@ -1792,7 +1809,8 @@ strcpy(pcm->name, "CS46xx - IEC958"); chip->pcm_rear = pcm; - snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), 64*1024, 256*1024); if (rpcm) *rpcm = pcm; @@ -2547,7 +2565,7 @@ /* get EAPD mixer switch (for voyetra hack) */ memset(&id, 0, sizeof(id)); id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - strcpy(id.name, "External Amplifier Power Down"); + strcpy(id.name, "External Amplifier"); chip->eapd_switch = snd_ctl_find_id(chip->card, &id); #ifdef CONFIG_SND_CS46XX_NEW_DSP @@ -3877,7 +3895,6 @@ #endif chip->card = card; chip->pci = pci; - chip->capt.hw_size = PAGE_SIZE; chip->irq = -1; chip->ba0_addr = pci_resource_start(pci, 0); chip->ba1_addr = pci_resource_start(pci, 1); @@ -3912,6 +3929,10 @@ strcpy(region->name, "CS46xx_BA1_reg"); region->base = chip->ba1_addr + BA1_SP_REG; region->size = CS46XX_BA1_REG_SIZE; + + memset(&chip->dma_dev, 0, sizeof(chip->dma_dev)); + chip->dma_dev.type = SNDRV_DMA_TYPE_DEV; + chip->dma_dev.dev = snd_dma_pci_data(pci); /* set up amp and clkrun hack */ pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &ss_vendor); diff -Nru a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c --- a/sound/pci/emu10k1/emu10k1.c Sun Mar 14 14:20:05 2004 +++ b/sound/pci/emu10k1/emu10k1.c Sun Mar 14 14:20:05 2004 @@ -80,7 +80,9 @@ static struct pci_device_id snd_emu10k1_ids[] = { { 0x1102, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* EMU10K1 */ +#if 0 /* FIXME: not working! */ { 0x1102, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Dell OEM version (EMU10K1) */ +#endif { 0x1102, 0x0004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, /* Audigy */ { 0, } }; diff -Nru a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c --- a/sound/pci/emu10k1/emu10k1_callback.c Sun Mar 14 14:20:06 2004 +++ b/sound/pci/emu10k1/emu10k1_callback.c Sun Mar 14 14:20:06 2004 @@ -405,7 +405,7 @@ snd_emu10k1_ptr_write(hw, Z2, ch, 0); /* invalidate maps */ - temp = (hw->silent_page_dmaaddr << 1) | MAP_PTI_MASK; + temp = (hw->silent_page.addr << 1) | MAP_PTI_MASK; snd_emu10k1_ptr_write(hw, MAPA, ch, temp); snd_emu10k1_ptr_write(hw, MAPB, ch, temp); #if 0 diff -Nru a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c --- a/sound/pci/emu10k1/emu10k1_main.c Sun Mar 14 14:20:08 2004 +++ b/sound/pci/emu10k1/emu10k1_main.c Sun Mar 14 14:20:08 2004 @@ -97,7 +97,8 @@ unsigned int silent_page; emu->fx8010.itram_size = (16 * 1024)/2; - emu->fx8010.etram_size = 0; + emu->fx8010.etram_pages.area = NULL; + emu->fx8010.etram_pages.bytes = 0; /* disable audio and lock cache */ outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, emu->port + HCFG); @@ -184,15 +185,15 @@ /* * Clear page with silence & setup all pointers to this page */ - memset(emu->silent_page, 0, PAGE_SIZE); - silent_page = emu->silent_page_dmaaddr << 1; + memset(emu->silent_page.area, 0, PAGE_SIZE); + silent_page = emu->silent_page.addr << 1; for (idx = 0; idx < MAXPAGES; idx++) - emu->ptb_pages[idx] = cpu_to_le32(silent_page | idx); - snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages_dmaaddr); + ((u32 *)emu->ptb_pages.area)[idx] = cpu_to_le32(silent_page | idx); + snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr); snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */ snd_emu10k1_ptr_write(emu, TCBS, 0, 4); /* taken from original driver */ - silent_page = (emu->silent_page_dmaaddr << 1) | MAP_PTI_MASK; + silent_page = (emu->silent_page.addr << 1) | MAP_PTI_MASK; for (ch = 0; ch < NUM_G; ch++) { snd_emu10k1_ptr_write(emu, MAPA, ch, silent_page); snd_emu10k1_ptr_write(emu, MAPB, ch, silent_page); @@ -546,10 +547,10 @@ } if (emu->memhdr) snd_util_memhdr_free(emu->memhdr); - if (emu->silent_page) - snd_free_pci_pages(emu->pci, EMUPAGESIZE, emu->silent_page, emu->silent_page_dmaaddr); - if (emu->ptb_pages) - snd_free_pci_pages(emu->pci, 32 * 1024, (void *)emu->ptb_pages, emu->ptb_pages_dmaaddr); + if (emu->silent_page.area) + snd_dma_free_pages(&emu->dma_dev, &emu->silent_page); + if (emu->ptb_pages.area) + snd_dma_free_pages(&emu->dma_dev, &emu->ptb_pages); if (emu->page_ptr_table) vfree(emu->page_ptr_table); if (emu->page_addr_table) @@ -638,9 +639,12 @@ } emu->irq = pci->irq; + memset(&emu->dma_dev, 0, sizeof(emu->dma_dev)); + emu->dma_dev.type = SNDRV_DMA_TYPE_DEV; + emu->dma_dev.dev = snd_dma_pci_data(pci); + emu->max_cache_pages = max_cache_bytes >> PAGE_SHIFT; - emu->ptb_pages = snd_malloc_pci_pages(pci, 32 * 1024, &emu->ptb_pages_dmaaddr); - if (emu->ptb_pages == NULL) { + if (snd_dma_alloc_pages(&emu->dma_dev, 32 * 1024, &emu->ptb_pages) < 0) { snd_emu10k1_free(emu); return -ENOMEM; } @@ -652,8 +656,7 @@ return -ENOMEM; } - emu->silent_page = snd_malloc_pci_pages(pci, EMUPAGESIZE, &emu->silent_page_dmaaddr); - if (emu->silent_page == NULL) { + if (snd_dma_alloc_pages(&emu->dma_dev, EMUPAGESIZE, &emu->silent_page) < 0) { snd_emu10k1_free(emu); return -ENOMEM; } diff -Nru a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c --- a/sound/pci/emu10k1/emufx.c Sun Mar 14 14:20:07 2004 +++ b/sound/pci/emu10k1/emufx.c Sun Mar 14 14:20:07 2004 @@ -26,6 +26,7 @@ */ #include +#include #include #include #include @@ -506,16 +507,16 @@ while (frames > *tram_pos) { count = *tram_pos + 1; - snd_emu10k1_fx8010_playback_tram_poke1((unsigned short *)emu->fx8010.etram_pages + *tram_pos, - (unsigned short *)emu->fx8010.etram_pages + *tram_pos + tram_size / 2, + snd_emu10k1_fx8010_playback_tram_poke1((unsigned short *)emu->fx8010.etram_pages.area + *tram_pos, + (unsigned short *)emu->fx8010.etram_pages.area + *tram_pos + tram_size / 2, src, count, *tram_shift); src += count * 2; frames -= count; *tram_pos = (tram_size / 2) - 1; (*tram_shift)++; } - snd_emu10k1_fx8010_playback_tram_poke1((unsigned short *)emu->fx8010.etram_pages + *tram_pos, - (unsigned short *)emu->fx8010.etram_pages + *tram_pos + tram_size / 2, + snd_emu10k1_fx8010_playback_tram_poke1((unsigned short *)emu->fx8010.etram_pages.area + *tram_pos, + (unsigned short *)emu->fx8010.etram_pages.area + *tram_pos + tram_size / 2, src, frames, *tram_shift++); *tram_pos -= frames; } @@ -760,7 +761,7 @@ strcpy(pcm->name, "EMU10K1 FX8010"); emu->pcm_fx8010 = pcm; - snd_pcm_lib_preallocate_pci_pages_for_all(emu->pci, pcm, 64*1024, 0); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 0); if (rpcm) *rpcm = pcm; @@ -2218,32 +2219,30 @@ } size = 0x2000 << size_reg; } - if (emu->fx8010.etram_size == size) + if (emu->fx8010.etram_pages.bytes == size) return 0; spin_lock_irq(&emu->emu_lock); outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG); spin_unlock_irq(&emu->emu_lock); snd_emu10k1_ptr_write(emu, TCB, 0, 0); snd_emu10k1_ptr_write(emu, TCBS, 0, 0); - if (emu->fx8010.etram_pages != NULL) { - snd_free_pci_pages(emu->pci, emu->fx8010.etram_size * 2, emu->fx8010.etram_pages, emu->fx8010.etram_pages_dmaaddr); - emu->fx8010.etram_pages = NULL; - emu->fx8010.etram_size = 0; + if (emu->fx8010.etram_pages.area != NULL) { + snd_dma_free_pages(&emu->dma_dev, &emu->fx8010.etram_pages); + emu->fx8010.etram_pages.area = NULL; + emu->fx8010.etram_pages.bytes = 0; } if (size > 0) { - emu->fx8010.etram_pages = snd_malloc_pci_pages(emu->pci, size * 2, &emu->fx8010.etram_pages_dmaaddr); - if (emu->fx8010.etram_pages == NULL) + if (snd_dma_alloc_pages(&emu->dma_dev, size * 2, &emu->fx8010.etram_pages) < 0) return -ENOMEM; - memset(emu->fx8010.etram_pages, 0, size * 2); - snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages_dmaaddr); + memset(emu->fx8010.etram_pages.area, 0, size * 2); + snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr); snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg); spin_lock_irq(&emu->emu_lock); outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG); spin_unlock_irq(&emu->emu_lock); } - emu->fx8010.etram_size = size; return 0; } @@ -2269,7 +2268,7 @@ memset(info, 0, sizeof(info)); info->card = emu->card_type; info->internal_tram_size = emu->fx8010.itram_size; - info->external_tram_size = emu->fx8010.etram_size; + info->external_tram_size = emu->fx8010.etram_pages.bytes; fxbus = fxbuses; extin = emu->audigy ? audigy_ins : creative_ins; extout = emu->audigy ? audigy_outs : creative_outs; diff -Nru a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c --- a/sound/pci/emu10k1/emupcm.c Sun Mar 14 14:20:05 2004 +++ b/sound/pci/emu10k1/emupcm.c Sun Mar 14 14:20:05 2004 @@ -26,6 +26,7 @@ */ #include +#include #include #include #include @@ -323,7 +324,7 @@ snd_emu10k1_ptr_write(emu, Z1, voice, 0); snd_emu10k1_ptr_write(emu, Z2, voice, 0); // invalidate maps - silent_page = ((unsigned int)emu->silent_page_dmaaddr << 1) | MAP_PTI_MASK; + silent_page = ((unsigned int)emu->silent_page.addr << 1) | MAP_PTI_MASK; snd_emu10k1_ptr_write(emu, MAPA, voice, silent_page); snd_emu10k1_ptr_write(emu, MAPB, voice, silent_page); // modulation envelope @@ -998,11 +999,11 @@ emu->pcm = pcm; for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) - if ((err = snd_pcm_lib_preallocate_sg_pages(emu->pci, substream, 64*1024, 64*1024)) < 0) + if ((err = snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG, snd_dma_pci_data(emu->pci), 64*1024, 64*1024)) < 0) return err; for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next) - snd_pcm_lib_preallocate_pci_pages(emu->pci, substream, 64*1024, 64*1024); + snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024); if (rpcm) *rpcm = pcm; @@ -1048,7 +1049,7 @@ strcpy(pcm->name, "EMU10K1 MIC"); emu->pcm_mic = pcm; - snd_pcm_lib_preallocate_pci_pages_for_all(emu->pci, pcm, 64*1024, 64*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024); if (rpcm) *rpcm = pcm; @@ -1157,7 +1158,7 @@ emu->efx_voices_mask[1] = 0; snd_ctl_add(emu->card, snd_ctl_new1(&snd_emu10k1_pcm_efx_voices_mask, emu)); - snd_pcm_lib_preallocate_pci_pages_for_all(emu->pci, pcm, 64*1024, 64*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(emu->pci), 64*1024, 64*1024); return 0; } diff -Nru a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c --- a/sound/pci/emu10k1/emuproc.c Sun Mar 14 14:20:07 2004 +++ b/sound/pci/emu10k1/emuproc.c Sun Mar 14 14:20:07 2004 @@ -117,7 +117,7 @@ snd_iprintf(buffer, "Card : %s\n", emu->audigy ? "Audigy" : (emu->APS ? "EMU APS" : "Creative")); snd_iprintf(buffer, "Internal TRAM (words) : 0x%x\n", emu->fx8010.itram_size); - snd_iprintf(buffer, "External TRAM (words) : 0x%x\n", emu->fx8010.etram_size); + snd_iprintf(buffer, "External TRAM (words) : 0x%x\n", emu->fx8010.etram_pages.bytes); snd_iprintf(buffer, "\n"); if (emu->audigy) { snd_iprintf(buffer, "Effect Send Routing : A=%i, B=%i, C=%i, D=%i\n", diff -Nru a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c --- a/sound/pci/emu10k1/memory.c Sun Mar 14 14:20:08 2004 +++ b/sound/pci/emu10k1/memory.c Sun Mar 14 14:20:08 2004 @@ -30,7 +30,7 @@ * aligned pages in others */ #define __set_ptb_entry(emu,page,addr) \ - ((emu)->ptb_pages[page] = cpu_to_le32(((addr) << 1) | (page))) + (((u32 *)(emu)->ptb_pages.area)[page] = cpu_to_le32(((addr) << 1) | (page))) #define UNIT_PAGES (PAGE_SIZE / EMUPAGESIZE) #define MAX_ALIGN_PAGES (MAXPAGES / UNIT_PAGES) @@ -44,7 +44,7 @@ /* fill PTB entrie(s) corresponding to page with addr */ #define set_ptb_entry(emu,page,addr) __set_ptb_entry(emu,page,addr) /* fill PTB entrie(s) corresponding to page with silence pointer */ -#define set_silent_ptb(emu,page) __set_ptb_entry(emu,page,emu->silent_page_dmaaddr) +#define set_silent_ptb(emu,page) __set_ptb_entry(emu,page,emu->silent_page.addr) #else /* fill PTB entries -- we need to fill UNIT_PAGES entries */ static inline void set_ptb_entry(emu10k1_t *emu, int page, dma_addr_t addr) @@ -297,7 +297,6 @@ int page, err, idx; snd_assert(emu, return NULL); - snd_assert(substream->dma_device.type == SNDRV_DMA_TYPE_PCI_SG, return NULL); snd_assert(runtime->dma_bytes > 0 && runtime->dma_bytes < MAXPAGES * EMUPAGESIZE, return NULL); hdr = emu->memhdr; snd_assert(hdr, return NULL); @@ -436,22 +435,20 @@ static int synth_alloc_pages(emu10k1_t *emu, emu10k1_memblk_t *blk) { int page, first_page, last_page; - void *ptr; - dma_addr_t addr; + struct snd_dma_buffer dmab; emu10k1_memblk_init(blk); get_single_page_range(emu->memhdr, blk, &first_page, &last_page); /* allocate kernel pages */ for (page = first_page; page <= last_page; page++) { - ptr = snd_malloc_pci_page(emu->pci, &addr); - if (ptr == NULL) + if (snd_dma_alloc_pages(&emu->dma_dev, PAGE_SIZE, &dmab) < 0) goto __fail; - if (! is_valid_page(emu, addr)) { - snd_free_pci_page(emu->pci, ptr, addr); + if (! is_valid_page(emu, dmab.addr)) { + snd_dma_free_pages(&emu->dma_dev, &dmab); goto __fail; } - emu->page_addr_table[page] = addr; - emu->page_ptr_table[page] = ptr; + emu->page_addr_table[page] = dmab.addr; + emu->page_ptr_table[page] = dmab.area; } return 0; @@ -459,7 +456,10 @@ /* release allocated pages */ last_page = page - 1; for (page = first_page; page <= last_page; page++) { - snd_free_pci_page(emu->pci, emu->page_ptr_table[page], emu->page_addr_table[page]); + dmab.area = emu->page_ptr_table[page]; + dmab.addr = emu->page_addr_table[page]; + dmab.bytes = PAGE_SIZE; + snd_dma_free_pages(&emu->dma_dev, &dmab); emu->page_addr_table[page] = 0; emu->page_ptr_table[page] = NULL; } @@ -473,11 +473,16 @@ static int synth_free_pages(emu10k1_t *emu, emu10k1_memblk_t *blk) { int page, first_page, last_page; + struct snd_dma_buffer dmab; get_single_page_range(emu->memhdr, blk, &first_page, &last_page); for (page = first_page; page <= last_page; page++) { - if (emu->page_ptr_table[page]) - snd_free_pci_page(emu->pci, emu->page_ptr_table[page], emu->page_addr_table[page]); + if (emu->page_ptr_table[page] == NULL) + continue; + dmab.area = emu->page_ptr_table[page]; + dmab.addr = emu->page_addr_table[page]; + dmab.bytes = PAGE_SIZE; + snd_dma_free_pages(&emu->dma_dev, &dmab); emu->page_addr_table[page] = 0; emu->page_ptr_table[page] = NULL; } diff -Nru a/sound/pci/ens1370.c b/sound/pci/ens1370.c --- a/sound/pci/ens1370.c Sun Mar 14 14:20:08 2004 +++ b/sound/pci/ens1370.c Sun Mar 14 14:20:08 2004 @@ -434,8 +434,8 @@ unsigned int spdif_stream; #ifdef CHIP1370 - unsigned char *bugbuf; - dma_addr_t bugbuf_addr; + struct snd_dma_device dma_dev; + struct snd_dma_buffer dma_bug; #endif #ifdef SUPPORT_JOYSTICK @@ -1250,7 +1250,8 @@ #endif ensoniq->pcm1 = pcm; - snd_pcm_lib_preallocate_pci_pages_for_all(ensoniq->pci, pcm, 64*1024, 128*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(ensoniq->pci), 64*1024, 128*1024); if (rpcm) *rpcm = pcm; @@ -1294,7 +1295,8 @@ #endif ensoniq->pcm2 = pcm; - snd_pcm_lib_preallocate_pci_pages_for_all(ensoniq->pci, pcm, 64*1024, 128*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(ensoniq->pci), 64*1024, 128*1024); if (rpcm) *rpcm = pcm; @@ -1829,8 +1831,8 @@ pci_set_power_state(ensoniq->pci, 3); __hw_end: #ifdef CHIP1370 - if (ensoniq->bugbuf) - snd_free_pci_pages(ensoniq->pci, 16, ensoniq->bugbuf, ensoniq->bugbuf_addr); + if (ensoniq->dma_bug.area) + snd_dma_free_pages(&ensoniq->dma_dev, &ensoniq->dma_bug); #endif if (ensoniq->res_port) { release_resource(ensoniq->res_port); @@ -1911,8 +1913,11 @@ } ensoniq->irq = pci->irq; #ifdef CHIP1370 - if ((ensoniq->bugbuf = snd_malloc_pci_pages(pci, 16, &ensoniq->bugbuf_addr)) == NULL) { - snd_printk("unable to allocate space for phantom area - bugbuf\n"); + memset(&ensoniq->dma_dev, 0, sizeof(ensoniq->dma_dev)); + ensoniq->dma_dev.type = SNDRV_DMA_TYPE_DEV; + ensoniq->dma_dev.dev = snd_dma_pci_data(pci); + if (snd_dma_alloc_pages(&ensoniq->dma_dev, 16, &ensoniq->dma_bug) < 0) { + snd_printk("unable to allocate space for phantom area - dma_bug\n"); snd_ensoniq_free(ensoniq); return -EBUSY; } @@ -1936,7 +1941,7 @@ outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL)); outl(ES_MEM_PAGEO(ES_PAGE_ADC), ES_REG(ensoniq, MEM_PAGE)); - outl(ensoniq->bugbuf_addr, ES_REG(ensoniq, PHANTOM_FRAME)); + outl(ensoniq->dma_bug.addr, ES_REG(ensoniq, PHANTOM_FRAME)); outl(0, ES_REG(ensoniq, PHANTOM_COUNT)); #else ensoniq->ctrl = 0; diff -Nru a/sound/pci/es1938.c b/sound/pci/es1938.c --- a/sound/pci/es1938.c Sun Mar 14 14:20:07 2004 +++ b/sound/pci/es1938.c Sun Mar 14 14:20:07 2004 @@ -946,17 +946,14 @@ static int snd_es1938_capture_close(snd_pcm_substream_t * substream) { es1938_t *chip = snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; chip->capture_substream = NULL; - snd_free_pci_pages(chip->pci, runtime->dma_bytes, runtime->dma_area, runtime->dma_addr); return 0; } static int snd_es1938_playback_close(snd_pcm_substream_t * substream) { es1938_t *chip = snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; switch (substream->number) { case 0: @@ -969,7 +966,6 @@ snd_BUG(); return -EINVAL; } - snd_free_pci_pages(chip->pci, runtime->dma_bytes, runtime->dma_area, runtime->dma_addr); return 0; } @@ -1018,7 +1014,8 @@ pcm->info_flags = 0; strcpy(pcm->name, "ESS Solo-1"); - snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 64*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), 64*1024, 64*1024); if (rpcm) *rpcm = pcm; diff -Nru a/sound/pci/es1968.c b/sound/pci/es1968.c --- a/sound/pci/es1968.c Sun Mar 14 14:20:07 2004 +++ b/sound/pci/es1968.c Sun Mar 14 14:20:07 2004 @@ -1495,13 +1495,15 @@ static int __devinit snd_es1968_init_dmabuf(es1968_t *chip) { + int err; esm_memory_t *chunk; - snd_dma_device_pci(&chip->dma_dev, chip->pci, 0); + chip->dma_dev.type = SNDRV_DMA_TYPE_DEV; + chip->dma_dev.dev = snd_dma_pci_data(chip->pci); + chip->dma_dev.id = 0; if (! snd_dma_get_reserved(&chip->dma_dev, &chip->dma)) { - chip->dma.area = snd_malloc_pci_pages_fallback(chip->pci, chip->total_bufsize, - &chip->dma.addr, &chip->dma.bytes); - if (chip->dma.area == NULL) { + err = snd_dma_alloc_pages_fallback(&chip->dma_dev, chip->total_bufsize, &chip->dma); + if (err < 0 || ! chip->dma.area) { snd_printk("es1968: can't allocate dma pages for size %d\n", chip->total_bufsize); return -ENOMEM; diff -Nru a/sound/pci/fm801.c b/sound/pci/fm801.c --- a/sound/pci/fm801.c Sun Mar 14 14:20:08 2004 +++ b/sound/pci/fm801.c Sun Mar 14 14:20:08 2004 @@ -35,7 +35,7 @@ #include -#if defined(CONFIG_SND_FM801_TEA575X) && (defined(CONFIG_VIDEO_DEV) || defined(CONFIG_VIDEO_DEV_MODULE)) +#if (defined(CONFIG_SND_FM801_TEA575X) || defined(CONFIG_SND_FM801_TEA575X_MODULE)) && (defined(CONFIG_VIDEO_DEV) || defined(CONFIG_VIDEO_DEV_MODULE)) #include #define TEA575X_RADIO 1 #endif @@ -703,7 +703,9 @@ strcpy(pcm->name, "FM801"); chip->pcm = pcm; - snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, chip->multichannel ? 128*1024 : 64*1024, 128*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), + chip->multichannel ? 128*1024 : 64*1024, 128*1024); if (rpcm) *rpcm = pcm; diff -Nru a/sound/pci/ice1712/amp.c b/sound/pci/ice1712/amp.c --- a/sound/pci/ice1712/amp.c Sun Mar 14 14:20:07 2004 +++ b/sound/pci/ice1712/amp.c Sun Mar 14 14:20:07 2004 @@ -38,6 +38,7 @@ /* only use basic functionality for now */ ice->num_total_dacs = 2; /* only PSDOUT0 is connected */ + ice->num_total_adcs = 2; return 0; } diff -Nru a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c --- a/sound/pci/ice1712/aureon.c Sun Mar 14 14:20:06 2004 +++ b/sound/pci/ice1712/aureon.c Sun Mar 14 14:20:06 2004 @@ -409,10 +409,13 @@ unsigned int tmp; unsigned int i; - if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) + if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) { ice->num_total_dacs = 6; - else + ice->num_total_adcs = 6; + } else { ice->num_total_dacs = 8; + ice->num_total_adcs = 8; + } /* to remeber the register values */ ice->akm = snd_kcalloc(sizeof(akm4xxx_t), GFP_KERNEL); diff -Nru a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c --- a/sound/pci/ice1712/delta.c Sun Mar 14 14:20:06 2004 +++ b/sound/pci/ice1712/delta.c Sun Mar 14 14:20:06 2004 @@ -511,20 +511,25 @@ switch (ice->eeprom.subvendor) { case ICE1712_SUBDEVICE_AUDIOPHILE: ice->num_total_dacs = 2; + ice->num_total_adcs = 2; break; case ICE1712_SUBDEVICE_DELTA410: ice->num_total_dacs = 8; + ice->num_total_adcs = 2; break; case ICE1712_SUBDEVICE_DELTA44: case ICE1712_SUBDEVICE_DELTA66: ice->num_total_dacs = ice->omni ? 8 : 4; + ice->num_total_adcs = ice->omni ? 8 : 4; break; case ICE1712_SUBDEVICE_DELTA1010: case ICE1712_SUBDEVICE_DELTA1010LT: ice->num_total_dacs = 8; + ice->num_total_adcs = 8; break; case ICE1712_SUBDEVICE_VX442: ice->num_total_dacs = 4; + ice->num_total_adcs = 4; break; } diff -Nru a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c --- a/sound/pci/ice1712/ews.c Sun Mar 14 14:20:06 2004 +++ b/sound/pci/ice1712/ews.c Sun Mar 14 14:20:06 2004 @@ -406,15 +406,18 @@ switch (ice->eeprom.subvendor) { case ICE1712_SUBDEVICE_EWX2496: ice->num_total_dacs = 2; + ice->num_total_adcs = 2; break; case ICE1712_SUBDEVICE_EWS88MT: case ICE1712_SUBDEVICE_EWS88MT_NEW: ice->num_total_dacs = 8; + ice->num_total_adcs = 8; break; case ICE1712_SUBDEVICE_EWS88D: break; /* no analog */ case ICE1712_SUBDEVICE_DMX6FIRE: ice->num_total_dacs = 6; + ice->num_total_adcs = 6; break; } diff -Nru a/sound/pci/ice1712/hoontech.c b/sound/pci/ice1712/hoontech.c --- a/sound/pci/ice1712/hoontech.c Sun Mar 14 14:20:07 2004 +++ b/sound/pci/ice1712/hoontech.c Sun Mar 14 14:20:07 2004 @@ -153,6 +153,7 @@ int box, chn; ice->num_total_dacs = 8; + ice->num_total_adcs = 8; ice->hoontech_boxbits[0] = ice->hoontech_boxbits[1] = diff -Nru a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c --- a/sound/pci/ice1712/ice1712.c Sun Mar 14 14:20:06 2004 +++ b/sound/pci/ice1712/ice1712.c Sun Mar 14 14:20:06 2004 @@ -886,7 +886,8 @@ strcpy(pcm->name, "ICE1712 consumer"); ice->pcm = pcm; - snd_pcm_lib_preallocate_pci_pages_for_all(ice->pci, pcm, 64*1024, 64*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(ice->pci), 64*1024, 64*1024); if (rpcm) *rpcm = pcm; @@ -922,7 +923,8 @@ strcpy(pcm->name, "ICE1712 consumer (DS)"); ice->pcm_ds = pcm; - snd_pcm_lib_preallocate_pci_pages_for_all(ice->pci, pcm, 64*1024, 128*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(ice->pci), 64*1024, 128*1024); if (rpcm) *rpcm = pcm; @@ -1269,7 +1271,8 @@ pcm->info_flags = 0; strcpy(pcm->name, "ICE1712 multi"); - snd_pcm_lib_preallocate_pci_pages_for_all(ice->pci, pcm, 256*1024, 256*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(ice->pci), 256*1024, 256*1024); ice->pcm_pro = pcm; if (rpcm) @@ -1381,7 +1384,7 @@ } -static snd_kcontrol_new_t snd_ice1712_multi_ctrls[] __devinitdata = { +static snd_kcontrol_new_t snd_ice1712_multi_playback_ctrls[] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Playback Switch", @@ -1400,24 +1403,44 @@ .private_value = 0, .count = 10, }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Multi Capture Switch", - .info = snd_ice1712_pro_mixer_switch_info, - .get = snd_ice1712_pro_mixer_switch_get, - .put = snd_ice1712_pro_mixer_switch_put, - .private_value = 10, - .count = 10, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Multi Capture Volume", - .info = snd_ice1712_pro_mixer_volume_info, - .get = snd_ice1712_pro_mixer_volume_get, - .put = snd_ice1712_pro_mixer_volume_put, - .private_value = 10, - .count = 10, - }, +}; + +static snd_kcontrol_new_t snd_ice1712_multi_capture_analog_switch __devinitdata = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "H/W Multi Capture Switch", + .info = snd_ice1712_pro_mixer_switch_info, + .get = snd_ice1712_pro_mixer_switch_get, + .put = snd_ice1712_pro_mixer_switch_put, + .private_value = 10, +}; + +static snd_kcontrol_new_t snd_ice1712_multi_capture_spdif_switch __devinitdata = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "IEC958 Multi Capture Switch", + .info = snd_ice1712_pro_mixer_switch_info, + .get = snd_ice1712_pro_mixer_switch_get, + .put = snd_ice1712_pro_mixer_switch_put, + .private_value = 18, + .count = 2, +}; + +static snd_kcontrol_new_t snd_ice1712_multi_capture_analog_volume __devinitdata = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "H/W Multi Capture Volume", + .info = snd_ice1712_pro_mixer_volume_info, + .get = snd_ice1712_pro_mixer_volume_get, + .put = snd_ice1712_pro_mixer_volume_put, + .private_value = 10, +}; + +static snd_kcontrol_new_t snd_ice1712_multi_capture_spdif_volume __devinitdata = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "IEC958 Multi Capture Volume", + .info = snd_ice1712_pro_mixer_volume_info, + .get = snd_ice1712_pro_mixer_volume_get, + .put = snd_ice1712_pro_mixer_volume_put, + .private_value = 18, + .count = 2, }; static int __devinit snd_ice1712_build_pro_mixer(ice1712_t *ice) @@ -1427,14 +1450,46 @@ int err; /* multi-channel mixer */ - for (idx = 0; idx < ARRAY_SIZE(snd_ice1712_multi_ctrls); idx++) { - err = snd_ctl_add(card, snd_ctl_new1(&snd_ice1712_multi_ctrls[idx], ice)); + for (idx = 0; idx < ARRAY_SIZE(snd_ice1712_multi_playback_ctrls); idx++) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_ice1712_multi_playback_ctrls[idx], ice)); if (err < 0) return err; } + if (ice->num_total_adcs > 0) { + snd_kcontrol_new_t tmp = snd_ice1712_multi_capture_analog_switch; + tmp.count = ice->num_total_adcs; + err = snd_ctl_add(card, snd_ctl_new1(&tmp, ice)); + if (err < 0) + return err; + } + + err = snd_ctl_add(card, snd_ctl_new1(&snd_ice1712_multi_capture_spdif_switch, ice)); + if (err < 0) + return err; + + if (ice->num_total_adcs > 0) { + snd_kcontrol_new_t tmp = snd_ice1712_multi_capture_analog_volume; + tmp.count = ice->num_total_adcs; + err = snd_ctl_add(card, snd_ctl_new1(&tmp, ice)); + if (err < 0) + return err; + } + + err = snd_ctl_add(card, snd_ctl_new1(&snd_ice1712_multi_capture_spdif_volume, ice)); + if (err < 0) + return err; + /* initialize volumes */ - for (idx = 0; idx < 20; idx++) { + for (idx = 0; idx < 10; idx++) { + ice->pro_volumes[idx] = 0x80008000; /* mute */ + snd_ice1712_update_volume(ice, idx); + } + for (idx = 10; idx < 10 + ice->num_total_adcs; idx++) { + ice->pro_volumes[idx] = 0x80008000; /* mute */ + snd_ice1712_update_volume(ice, idx); + } + for (idx = 18; idx < 20; idx++) { ice->pro_volumes[idx] = 0x80008000; /* mute */ snd_ice1712_update_volume(ice, idx); } @@ -2375,6 +2430,7 @@ ice->omni = omni ? 1 : 0; spin_lock_init(&ice->reg_lock); init_MUTEX(&ice->gpio_mutex); + init_MUTEX(&ice->open_mutex); ice->gpio.set_mask = snd_ice1712_set_gpio_mask; ice->gpio.set_dir = snd_ice1712_set_gpio_dir; ice->gpio.set_data = snd_ice1712_set_gpio_data; diff -Nru a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h --- a/sound/pci/ice1712/ice1712.h Sun Mar 14 14:20:06 2004 +++ b/sound/pci/ice1712/ice1712.h Sun Mar 14 14:20:06 2004 @@ -330,10 +330,14 @@ unsigned int omni: 1; /* Delta Omni I/O */ unsigned int vt1724: 1; unsigned int num_total_dacs; /* total DACs */ + unsigned int num_total_adcs; /* total ADCs */ unsigned char hoontech_boxbits[4]; unsigned int hoontech_config; unsigned short hoontech_boxconfig[4]; unsigned int cur_rate; /* current rate */ + + struct semaphore open_mutex; + snd_pcm_substream_t *pcm_reserved[4]; unsigned int akm_codecs; akm4xxx_t *akm; diff -Nru a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c --- a/sound/pci/ice1712/ice1724.c Sun Mar 14 14:20:07 2004 +++ b/sound/pci/ice1712/ice1724.c Sun Mar 14 14:20:07 2004 @@ -237,6 +237,18 @@ if (ice->capture_pro_substream) snd_pcm_period_elapsed(ice->capture_pro_substream); } + if (mtstat & VT1724_MULTI_PDMA1) { + if (ice->playback_con_substream_ds[0]) + snd_pcm_period_elapsed(ice->playback_con_substream_ds[0]); + } + if (mtstat & VT1724_MULTI_PDMA2) { + if (ice->playback_con_substream_ds[1]) + snd_pcm_period_elapsed(ice->playback_con_substream_ds[1]); + } + if (mtstat & VT1724_MULTI_PDMA3) { + if (ice->playback_con_substream_ds[2]) + snd_pcm_period_elapsed(ice->playback_con_substream_ds[2]); + } if (mtstat & VT1724_MULTI_PDMA4) { if (ice->playback_con_substream) snd_pcm_period_elapsed(ice->playback_con_substream); @@ -282,16 +294,6 @@ .mask = 0, }; -static unsigned int hw_channels[] = { - 2, 4, 6, 8 -}; - -static snd_pcm_hw_constraint_list_t hw_constraints_channels = { - .count = ARRAY_SIZE(hw_channels), - .list = hw_channels, - .mask = 0, -}; - static int snd_vt1724_pcm_trigger(snd_pcm_substream_t *substream, int cmd) { ice1712_t *ice = snd_pcm_substream_chip(substream); @@ -300,21 +302,16 @@ struct list_head *pos; snd_pcm_substream_t *s; + what = 0; + snd_pcm_group_for_each(pos, substream) { + s = snd_pcm_group_substream_entry(pos); + what |= (unsigned long)(s->runtime->private_data); + snd_pcm_trigger_done(s, substream); + } + switch (cmd) { case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - what = 0; - snd_pcm_group_for_each(pos, substream) { - s = snd_pcm_group_substream_entry(pos); - if (s == ice->playback_pro_substream) - what |= VT1724_PDMA0_PAUSE; - else if (s == ice->capture_pro_substream) - what |= VT1724_RDMA0_PAUSE; - else if (s == ice->playback_con_substream) - what |= VT1724_PDMA4_PAUSE; - else if (s == ice->capture_con_substream) - what |= VT1724_RDMA1_PAUSE; - } spin_lock(&ice->reg_lock); old = inb(ICEMT1724(ice, DMA_PAUSE)); if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH) @@ -327,24 +324,6 @@ case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_STOP: - what = 0; - s = substream; - snd_pcm_group_for_each(pos, substream) { - s = snd_pcm_group_substream_entry(pos); - if (s == ice->playback_pro_substream) { - what |= VT1724_PDMA0_START; - snd_pcm_trigger_done(s, substream); - } else if (s == ice->capture_pro_substream) { - what |= VT1724_RDMA0_START; - snd_pcm_trigger_done(s, substream); - } else if (s == ice->playback_con_substream) { - what |= VT1724_PDMA4_START; - snd_pcm_trigger_done(s, substream); - } else if (s == ice->capture_con_substream) { - what |= VT1724_RDMA1_START; - snd_pcm_trigger_done(s, substream); - } - } spin_lock(&ice->reg_lock); old = inb(ICEMT1724(ice, DMA_CONTROL)); if (cmd == SNDRV_PCM_TRIGGER_START) @@ -364,8 +343,10 @@ /* */ -#define DMA_STARTS (VT1724_RDMA0_START|VT1724_PDMA0_START|VT1724_RDMA1_START|VT1724_PDMA4_START) -#define DMA_PAUSES (VT1724_RDMA0_PAUSE|VT1724_PDMA0_PAUSE|VT1724_RDMA1_PAUSE|VT1724_PDMA4_PAUSE) +#define DMA_STARTS (VT1724_RDMA0_START|VT1724_PDMA0_START|VT1724_RDMA1_START|\ + VT1724_PDMA1_START|VT1724_PDMA2_START|VT1724_PDMA3_START|VT1724_PDMA4_START) +#define DMA_PAUSES (VT1724_RDMA0_PAUSE|VT1724_PDMA0_PAUSE|VT1724_RDMA1_PAUSE|\ + VT1724_PDMA1_PAUSE|VT1724_PDMA2_PAUSE|VT1724_PDMA3_PAUSE|VT1724_PDMA4_PAUSE) static void snd_vt1724_set_pro_rate(ice1712_t *ice, unsigned int rate, int force) { @@ -448,13 +429,52 @@ snd_pcm_hw_params_t * hw_params) { ice1712_t *ice = snd_pcm_substream_chip(substream); + int i, chs; + chs = params_channels(hw_params); + down(&ice->open_mutex); + /* mark surround channels */ + if (substream == ice->playback_pro_substream) { + chs = chs / 2 - 1; + for (i = 0; i < chs; i++) { + if (ice->pcm_reserved[i] && ice->pcm_reserved[i] != substream) { + up(&ice->open_mutex); + return -EBUSY; + } + ice->pcm_reserved[i] = substream; + } + for (; i < 3; i++) { + if (ice->pcm_reserved[i] == substream) + ice->pcm_reserved[i] = NULL; + } + } else { + for (i = 0; i < 3; i++) { + if (ice->playback_con_substream_ds[i] == substream) { + if (ice->pcm_reserved[i] && ice->pcm_reserved[i] != substream) { + up(&ice->open_mutex); + return -EBUSY; + } + ice->pcm_reserved[i] = substream; + break; + } + } + } + up(&ice->open_mutex); snd_vt1724_set_pro_rate(ice, params_rate(hw_params), 0); return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); } static int snd_vt1724_pcm_hw_free(snd_pcm_substream_t * substream) { + ice1712_t *ice = snd_pcm_substream_chip(substream); + int i; + + down(&ice->open_mutex); + /* unmark surround channels */ + for (i = 0; i < 3; i++) + if (ice->pcm_reserved[i] == substream) + ice->pcm_reserved[i] = NULL; + up(&ice->open_mutex); return snd_pcm_lib_free_pages(substream); } @@ -593,14 +613,14 @@ .rate_max = 192000, .channels_min = 2, .channels_max = 8, - .buffer_bytes_max = (1UL << 21), /* 18bits dword */ + .buffer_bytes_max = (1UL << 21), /* 19bits dword */ .period_bytes_min = 8 * 4 * 2, /* FIXME: constraints needed */ .period_bytes_max = (1UL << 21), - .periods_min = 1, + .periods_min = 2, .periods_max = 1024, }; -static snd_pcm_hardware_t snd_vt1724_capture_pro = +static snd_pcm_hardware_t snd_vt1724_2ch_stereo = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | @@ -612,10 +632,10 @@ .rate_max = 192000, .channels_min = 2, .channels_max = 2, - .buffer_bytes_max = (256*1024), + .buffer_bytes_max = (1UL << 18), /* 16bits dword */ .period_bytes_min = 2 * 4 * 2, - .period_bytes_max = (256*1024), - .periods_min = 1, + .period_bytes_max = (1UL << 18), + .periods_min = 2, .periods_max = 1024, }; @@ -628,7 +648,9 @@ { snd_pcm_runtime_t *runtime = substream->runtime; ice1712_t *ice = snd_pcm_substream_chip(substream); + int chs; + runtime->private_data = (void*)VT1724_PDMA0_START; /* irq/status/trigger bit */ ice->playback_pro_substream = substream; runtime->hw = snd_vt1724_playback_pro; snd_pcm_set_sync(substream); @@ -639,7 +661,17 @@ else snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_96); - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels); + down(&ice->open_mutex); + /* calculate the currently available channels */ + for (chs = 0; chs < 3; chs++) { + if (ice->pcm_reserved[chs]) + break; + } + chs = (chs + 1) * 2; + runtime->hw.channels_max = chs; + if (chs > 2) /* channels must be even */ + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2); + up(&ice->open_mutex); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, VT1724_BUFFER_ALIGN); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, @@ -652,8 +684,9 @@ ice1712_t *ice = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; + runtime->private_data = (void*)VT1724_RDMA0_START; /* irq/status/trigger bit */ ice->capture_pro_substream = substream; - runtime->hw = snd_vt1724_capture_pro; + runtime->hw = snd_vt1724_2ch_stereo; snd_pcm_set_sync(substream); snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); if ((ice->eeprom.data[ICE_EEP2_ACLINK] & 0x80) && @@ -723,7 +756,8 @@ pcm->info_flags = 0; strcpy(pcm->name, "ICE1724"); - snd_pcm_lib_preallocate_pci_pages_for_all(ice->pci, pcm, 256*1024, 256*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(ice->pci), 256*1024, 256*1024); ice->pcm_pro = pcm; @@ -735,25 +769,6 @@ * SPDIF PCM */ -static snd_pcm_hardware_t snd_vt1724_playback_spdif = -{ - .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_SYNC_START), - .formats = SNDRV_PCM_FMTBIT_S32_LE, - .rates = SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_8000_192000, - .rate_min = 4000, - .rate_max = 192000, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = (256*1024), - .period_bytes_min = 2 * 4 * 2, - .period_bytes_max = (256*1024), - .periods_min = 1, - .periods_max = 1024, -}; - const static struct vt1724_pcm_reg vt1724_playback_spdif_reg = { .addr = VT1724_MT_PDMA4_ADDR, .size = VT1724_MT_PDMA4_SIZE, @@ -795,8 +810,9 @@ ice1712_t *ice = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; + runtime->private_data = (void*)VT1724_PDMA4_START; /* irq/status/trigger bit */ ice->playback_con_substream = substream; - runtime->hw = snd_vt1724_playback_spdif; + runtime->hw = snd_vt1724_2ch_stereo; snd_pcm_set_sync(substream); snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); @@ -820,8 +836,9 @@ ice1712_t *ice = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; + runtime->private_data = (void*)VT1724_RDMA1_START; /* irq/status/trigger bit */ ice->capture_con_substream = substream; - runtime->hw = snd_vt1724_playback_spdif; + runtime->hw = snd_vt1724_2ch_stereo; snd_pcm_set_sync(substream); snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_96); @@ -894,7 +911,8 @@ pcm->info_flags = 0; strcpy(pcm->name, "ICE1724 IEC958"); - snd_pcm_lib_preallocate_pci_pages_for_all(ice->pci, pcm, 64*1024, 64*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(ice->pci), 64*1024, 64*1024); ice->pcm = pcm; @@ -903,6 +921,128 @@ /* + * independent surround PCMs + */ + +const static struct vt1724_pcm_reg vt1724_playback_dma_regs[3] = { + { + .addr = VT1724_MT_PDMA1_ADDR, + .size = VT1724_MT_PDMA1_SIZE, + .count = VT1724_MT_PDMA1_COUNT, + .start = VT1724_PDMA1_START, + .pause = VT1724_PDMA1_PAUSE, + }, + { + .addr = VT1724_MT_PDMA2_ADDR, + .size = VT1724_MT_PDMA2_SIZE, + .count = VT1724_MT_PDMA2_COUNT, + .start = VT1724_PDMA2_START, + .pause = VT1724_PDMA2_PAUSE, + }, + { + .addr = VT1724_MT_PDMA3_ADDR, + .size = VT1724_MT_PDMA3_SIZE, + .count = VT1724_MT_PDMA3_COUNT, + .start = VT1724_PDMA3_START, + .pause = VT1724_PDMA3_PAUSE, + }, +}; + +static int snd_vt1724_playback_indep_prepare(snd_pcm_substream_t * substream) +{ + ice1712_t *ice = snd_pcm_substream_chip(substream); + unsigned char val; + + spin_lock(&ice->reg_lock); + val = 3 - substream->number; + if (inb(ICEMT1724(ice, BURST)) < val) + outb(val, ICEMT1724(ice, BURST)); + spin_unlock(&ice->reg_lock); + return snd_vt1724_pcm_prepare(substream, &vt1724_playback_dma_regs[substream->number]); +} + +static snd_pcm_uframes_t snd_vt1724_playback_indep_pointer(snd_pcm_substream_t * substream) +{ + return snd_vt1724_pcm_pointer(substream, &vt1724_playback_dma_regs[substream->number]); +} + +static int snd_vt1724_playback_indep_open(snd_pcm_substream_t *substream) +{ + ice1712_t *ice = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + + down(&ice->open_mutex); + /* already used by PDMA0? */ + if (ice->pcm_reserved[substream->number]) { + up(&ice->open_mutex); + return -EBUSY; /* FIXME: should handle blocking mode properly */ + } + up(&ice->open_mutex); + runtime->private_data = (void*)(1 << (substream->number + 4)); + ice->playback_con_substream_ds[substream->number] = substream; + runtime->hw = snd_vt1724_2ch_stereo; + snd_pcm_set_sync(substream); + snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); + + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates_192); + return 0; +} + +static int snd_vt1724_playback_indep_close(snd_pcm_substream_t * substream) +{ + ice1712_t *ice = snd_pcm_substream_chip(substream); + + if (PRO_RATE_RESET) + snd_vt1724_set_pro_rate(ice, PRO_RATE_DEFAULT, 0); + ice->playback_con_substream_ds[substream->number] = NULL; + ice->pcm_reserved[substream->number] = NULL; + + return 0; +} + +static snd_pcm_ops_t snd_vt1724_playback_indep_ops = { + .open = snd_vt1724_playback_indep_open, + .close = snd_vt1724_playback_indep_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_vt1724_pcm_hw_params, + .hw_free = snd_vt1724_pcm_hw_free, + .prepare = snd_vt1724_playback_indep_prepare, + .trigger = snd_vt1724_pcm_trigger, + .pointer = snd_vt1724_playback_indep_pointer, +}; + + +static int __devinit snd_vt1724_pcm_indep(ice1712_t * ice, int device) +{ + snd_pcm_t *pcm; + int play; + int err; + + play = ice->num_total_dacs / 2 - 1; + if (play <= 0) + return 0; + + err = snd_pcm_new(ice->card, "ICE1724 Surrounds", device, play, 0, &pcm); + if (err < 0) + return err; + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, + &snd_vt1724_playback_indep_ops); + + pcm->private_data = ice; + pcm->info_flags = 0; + strcpy(pcm->name, "ICE1724 Surround PCM"); + + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(ice->pci), 64*1024, 64*1024); + + ice->pcm_ds = pcm; + + return 0; +} + + +/* * Mixer section */ @@ -1808,6 +1948,7 @@ ice->vt1724 = 1; spin_lock_init(&ice->reg_lock); init_MUTEX(&ice->gpio_mutex); + init_MUTEX(&ice->open_mutex); ice->gpio.set_mask = snd_vt1724_set_gpio_mask; ice->gpio.set_dir = snd_vt1724_set_gpio_dir; ice->gpio.set_data = snd_vt1724_set_gpio_data; @@ -1932,6 +2073,11 @@ return err; } + if ((err = snd_vt1724_pcm_indep(ice, pcm_dev++)) < 0) { + snd_card_free(card); + return err; + } + if ((err = snd_vt1724_ac97_mixer(ice)) < 0) { snd_card_free(card); return err; diff -Nru a/sound/pci/ice1712/prodigy.c b/sound/pci/ice1712/prodigy.c --- a/sound/pci/ice1712/prodigy.c Sun Mar 14 14:20:08 2004 +++ b/sound/pci/ice1712/prodigy.c Sun Mar 14 14:20:08 2004 @@ -585,6 +585,7 @@ printk(KERN_INFO "ice1724: Apostolos Dimitromanolakis \n"); ice->num_total_dacs = 8; + ice->num_total_adcs = 8; /* to remeber the register values */ ice->akm = snd_kcalloc(sizeof(akm4xxx_t), GFP_KERNEL); diff -Nru a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c --- a/sound/pci/ice1712/revo.c Sun Mar 14 14:20:07 2004 +++ b/sound/pci/ice1712/revo.c Sun Mar 14 14:20:07 2004 @@ -128,6 +128,7 @@ switch (ice->eeprom.subvendor) { case VT1724_SUBDEVICE_REVOLUTION71: ice->num_total_dacs = 8; + ice->num_total_adcs = 4; break; default: snd_BUG(); diff -Nru a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c --- a/sound/pci/intel8x0.c Sun Mar 14 14:20:07 2004 +++ b/sound/pci/intel8x0.c Sun Mar 14 14:20:07 2004 @@ -143,6 +143,9 @@ #ifndef PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO #define PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO 0x00da #endif +#ifndef PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO +#define PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO 0x00ea +#endif enum { DEVICE_INTEL, DEVICE_INTEL_ICH4, DEVICE_SIS, DEVICE_ALI, DEVICE_NFORCE }; @@ -396,6 +399,8 @@ unsigned long remap_bmaddr; struct resource *res_bm; + struct snd_dma_device dma_dev; + struct pci_dev *pci; snd_card_t *card; @@ -420,8 +425,7 @@ spinlock_t ac97_lock; u32 bdbars_count; - u32 *bdbars; - dma_addr_t bdbars_addr; + struct snd_dma_buffer bdbars; u32 int_sta_reg; /* interrupt status register */ u32 int_sta_mask; /* interrupt status mask */ unsigned int pcm_pos_shift; @@ -443,6 +447,7 @@ { 0x10de, 0x01b1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* NFORCE */ { 0x10de, 0x006a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* NFORCE2 */ { 0x10de, 0x00da, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* NFORCE3 */ + { 0x10de, 0x00ea, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* CK8S */ { 0x1022, 0x746d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD8111 */ { 0x1022, 0x7445, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD768 */ { 0x10b9, 0x5455, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALI }, /* Ali5455 */ @@ -804,10 +809,20 @@ spin_lock(&chip->reg_lock); status = igetdword(chip, chip->int_sta_reg); if ((status & chip->int_sta_mask) == 0) { - if (status) + static int err_count = 10; + if (status) { + /* ack */ iputdword(chip, chip->int_sta_reg, status); + if (chip->device_type != DEVICE_NFORCE) + status ^= igetdword(chip, chip->int_sta_reg); + } spin_unlock(&chip->reg_lock); - return IRQ_NONE; + if (chip->device_type != DEVICE_NFORCE && status && err_count) { + err_count--; + snd_printd("intel8x0: unknown IRQ bits 0x%x (sta_mask=0x%x)\n", + status, chip->int_sta_mask); + } + return IRQ_RETVAL(status); } for (i = 0; i < chip->bdbars_count; i++) { @@ -1017,6 +1032,7 @@ { intel8x0_t *chip = snd_pcm_substream_chip(substream); ichdev_t *ichdev = get_ichdev(substream); + unsigned long flags; size_t ptr1, ptr; ptr1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << chip->pcm_pos_shift; @@ -1024,7 +1040,9 @@ ptr = ichdev->fragsize1 - ptr1; else ptr = 0; + spin_lock_irqsave(&chip->reg_lock, flags); ptr += ichdev->position; + spin_unlock_irqrestore(&chip->reg_lock, flags); if (ptr >= ichdev->size) return 0; return bytes_to_frames(substream->runtime, ptr); @@ -1079,21 +1097,12 @@ { intel8x0_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; - static unsigned int i, rates[] = { - /* ATTENTION: these values depend on the definition in pcm.h! */ - 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000 - }; int err; ichdev->substream = substream; runtime->hw = snd_intel8x0_stream; runtime->hw.rates = ichdev->pcm->rates; - for (i = 0; i < ARRAY_SIZE(rates); i++) { - if (runtime->hw.rates & (1 << i)) { - runtime->hw.rate_min = rates[i]; - break; - } - } + snd_pcm_limit_hw_rates(runtime); if (chip->device_type == DEVICE_SIS) { runtime->hw.buffer_bytes_max = 64*1024; runtime->hw.period_bytes_max = 64*1024; @@ -1443,8 +1452,8 @@ strcpy(pcm->name, chip->card->shortname); chip->pcm[device] = pcm; - snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, rec->prealloc_size, - rec->prealloc_max_size); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), + rec->prealloc_size, rec->prealloc_max_size); return 0; } @@ -1666,6 +1675,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { { + .vendor = 0x1014, + .device = 0x1f00, + .name = "MS-9128", + .type = AC97_TUNE_ALC_JACK + }, + { .vendor = 0x1028, .device = 0x00d8, .name = "Dell Precision 530", /* AD1885 */ @@ -1741,6 +1756,12 @@ }, { .vendor = 0x8086, + .device = 0x4856, + .name = "Intel D845WN (82801BA)", + .type = AC97_TUNE_SWAP_HP + }, + { + .vendor = 0x8086, .device = 0x4d44, .name = "Intel D850EMV2", /* AD1885 */ .type = AC97_TUNE_HP_ONLY @@ -1759,6 +1780,7 @@ .name = "Intel ICH5/AD1985", .type = AC97_TUNE_AD_SHARING }, +#if 0 /* FIXME: this seems wrong on most boards */ { .vendor = 0x8086, .device = 0xa000, @@ -1766,6 +1788,7 @@ .name = "Intel ICH5/AD1985", .type = AC97_TUNE_HP_ONLY }, +#endif { } /* terminator */ }; @@ -2116,10 +2139,10 @@ /* --- */ synchronize_irq(chip->irq); __hw_end: - if (chip->bdbars) { + if (chip->bdbars.area) { if (chip->fix_nocache) - fill_nocache(chip->bdbars, chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2, 0); - snd_free_pci_pages(chip->pci, chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2, chip->bdbars, chip->bdbars_addr); + fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 0); + snd_dma_free_pages(&chip->dma_dev, &chip->bdbars); } if (chip->remap_addr) iounmap((void *) chip->remap_addr); @@ -2509,23 +2532,27 @@ /* SIS7012 handles the pcm data in bytes, others are in words */ chip->pcm_pos_shift = (device_type == DEVICE_SIS) ? 0 : 1; + memset(&chip->dma_dev, 0, sizeof(chip->dma_dev)); + chip->dma_dev.type = SNDRV_DMA_TYPE_DEV; + chip->dma_dev.dev = snd_dma_pci_data(pci); + /* allocate buffer descriptor lists */ /* the start of each lists must be aligned to 8 bytes */ - chip->bdbars = (u32 *)snd_malloc_pci_pages(pci, chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2, &chip->bdbars_addr); - if (chip->bdbars == NULL) { + if (snd_dma_alloc_pages(&chip->dma_dev, chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2, &chip->bdbars) < 0) { snd_intel8x0_free(chip); + snd_printk(KERN_ERR "intel8x0: cannot allocate buffer descriptors\n"); return -ENOMEM; } /* tables must be aligned to 8 bytes here, but the kernel pages are much bigger, so we don't care (on i386) */ /* workaround for 440MX */ if (chip->fix_nocache) - fill_nocache(chip->bdbars, chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2, 1); + fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 1); int_sta_masks = 0; for (i = 0; i < chip->bdbars_count; i++) { ichdev = &chip->ichd[i]; - ichdev->bdbar = chip->bdbars + (i * ICH_MAX_FRAGS * 2); - ichdev->bdbar_addr = chip->bdbars_addr + (i * sizeof(u32) * ICH_MAX_FRAGS * 2); + ichdev->bdbar = ((u32 *)chip->bdbars.area) + (i * ICH_MAX_FRAGS * 2); + ichdev->bdbar_addr = chip->bdbars.addr + (i * sizeof(u32) * ICH_MAX_FRAGS * 2); int_sta_masks |= ichdev->int_sta_mask; } chip->int_sta_reg = device_type == DEVICE_ALI ? ICH_REG_ALI_INTERRUPTSR : ICH_REG_GLOB_STA; @@ -2567,6 +2594,7 @@ { PCI_DEVICE_ID_NVIDIA_MCP_AUDIO, "NVidia nForce" }, { PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO, "NVidia nForce2" }, { PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO, "NVidia nForce3" }, + { PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO, "NVidia CK8S" }, { 0x746d, "AMD AMD8111" }, { 0x7445, "AMD AMD768" }, { 0x5455, "ALi M5455" }, diff -Nru a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/intel8x0m.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,1507 @@ +/* + * ALSA modem driver for Intel ICH (i8x0) chipsets + * + * Copyright (c) 2000 Jaroslav Kysela + * + * This is modified (by Sasha Khapyorsky ) version + * of ALSA ICH sound driver intel8x0.c . + * + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define SNDRV_GET_ID +#include + +MODULE_AUTHOR("Jaroslav Kysela "); +MODULE_DESCRIPTION("Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440 modem"); +MODULE_LICENSE("GPL"); +MODULE_CLASSES("{sound}"); +MODULE_DEVICES("{{Intel,82801AA-ICH}," + "{Intel,82901AB-ICH0}," + "{Intel,82801BA-ICH2}," + "{Intel,82801CA-ICH3}," + "{Intel,82801DB-ICH4}," + "{Intel,ICH5}," + "{Intel,MX440}}"); + + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ +static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; + +MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(index, "Index value for Intel i8x0 modemcard."); +MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); +MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s"); +MODULE_PARM_DESC(id, "ID string for Intel i8x0 modemcard."); +MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); +MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(enable, "Enable Intel i8x0 modemcard."); +MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); +MODULE_PARM(ac97_clock, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = auto-detect)."); +MODULE_PARM_SYNTAX(ac97_clock, SNDRV_ENABLED ",default:0"); + +/* + * Direct registers + */ + +#ifndef PCI_DEVICE_ID_INTEL_82801_6 +#define PCI_DEVICE_ID_INTEL_82801_6 0x2416 +#endif +#ifndef PCI_DEVICE_ID_INTEL_82901_6 +#define PCI_DEVICE_ID_INTEL_82901_6 0x2426 +#endif +#ifndef PCI_DEVICE_ID_INTEL_82801BA_6 +#define PCI_DEVICE_ID_INTEL_82801BA_6 0x2446 +#endif +#ifndef PCI_DEVICE_ID_INTEL_440MX_6 +#define PCI_DEVICE_ID_INTEL_440MX_6 0x7196 +#endif +#ifndef PCI_DEVICE_ID_INTEL_ICH3_6 +#define PCI_DEVICE_ID_INTEL_ICH3_6 0x2486 +#endif +#ifndef PCI_DEVICE_ID_INTEL_ICH4_6 +#define PCI_DEVICE_ID_INTEL_ICH4_6 0x24c6 +#endif +#ifndef PCI_DEVICE_ID_INTEL_ICH5_6 +#define PCI_DEVICE_ID_INTEL_ICH5_6 0x24d6 +#endif +#ifndef PCI_DEVICE_ID_SI_7013 +#define PCI_DEVICE_ID_SI_7013 0x7013 +#endif +#if 0 +#ifndef PCI_DEVICE_ID_NVIDIA_MCP_AUDIO +#define PCI_DEVICE_ID_NVIDIA_MCP_AUDIO 0x01b1 +#endif +#ifndef PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO +#define PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO 0x006a +#endif +#ifndef PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO +#define PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO 0x00da +#endif +#endif + +enum { DEVICE_INTEL, DEVICE_SIS, DEVICE_ALI, DEVICE_NFORCE }; + +#define ICHREG(x) ICH_REG_##x + +#define DEFINE_REGSET(name,base) \ +enum { \ + ICH_REG_##name##_BDBAR = base + 0x0, /* dword - buffer descriptor list base address */ \ + ICH_REG_##name##_CIV = base + 0x04, /* byte - current index value */ \ + ICH_REG_##name##_LVI = base + 0x05, /* byte - last valid index */ \ + ICH_REG_##name##_SR = base + 0x06, /* byte - status register */ \ + ICH_REG_##name##_PICB = base + 0x08, /* word - position in current buffer */ \ + ICH_REG_##name##_PIV = base + 0x0a, /* byte - prefetched index value */ \ + ICH_REG_##name##_CR = base + 0x0b, /* byte - control register */ \ +}; + +/* busmaster blocks */ +DEFINE_REGSET(OFF, 0); /* offset */ + +/* values for each busmaster block */ + +/* LVI */ +#define ICH_REG_LVI_MASK 0x1f + +/* SR */ +#define ICH_FIFOE 0x10 /* FIFO error */ +#define ICH_BCIS 0x08 /* buffer completion interrupt status */ +#define ICH_LVBCI 0x04 /* last valid buffer completion interrupt */ +#define ICH_CELV 0x02 /* current equals last valid */ +#define ICH_DCH 0x01 /* DMA controller halted */ + +/* PIV */ +#define ICH_REG_PIV_MASK 0x1f /* mask */ + +/* CR */ +#define ICH_IOCE 0x10 /* interrupt on completion enable */ +#define ICH_FEIE 0x08 /* fifo error interrupt enable */ +#define ICH_LVBIE 0x04 /* last valid buffer interrupt enable */ +#define ICH_RESETREGS 0x02 /* reset busmaster registers */ +#define ICH_STARTBM 0x01 /* start busmaster operation */ + + +/* global block */ +#define ICH_REG_GLOB_CNT 0x3c /* dword - global control */ +#define ICH_TRIE 0x00000040 /* tertiary resume interrupt enable */ +#define ICH_SRIE 0x00000020 /* secondary resume interrupt enable */ +#define ICH_PRIE 0x00000010 /* primary resume interrupt enable */ +#define ICH_ACLINK 0x00000008 /* AClink shut off */ +#define ICH_AC97WARM 0x00000004 /* AC'97 warm reset */ +#define ICH_AC97COLD 0x00000002 /* AC'97 cold reset */ +#define ICH_GIE 0x00000001 /* GPI interrupt enable */ +#define ICH_REG_GLOB_STA 0x40 /* dword - global status */ +#define ICH_TRI 0x20000000 /* ICH4: tertiary (AC_SDIN2) resume interrupt */ +#define ICH_TCR 0x10000000 /* ICH4: tertiary (AC_SDIN2) codec ready */ +#define ICH_BCS 0x08000000 /* ICH4: bit clock stopped */ +#define ICH_SPINT 0x04000000 /* ICH4: S/PDIF interrupt */ +#define ICH_P2INT 0x02000000 /* ICH4: PCM2-In interrupt */ +#define ICH_M2INT 0x01000000 /* ICH4: Mic2-In interrupt */ +#define ICH_SAMPLE_CAP 0x00c00000 /* ICH4: sample capability bits (RO) */ +#define ICH_MULTICHAN_CAP 0x00300000 /* ICH4: multi-channel capability bits (RO) */ +#define ICH_MD3 0x00020000 /* modem power down semaphore */ +#define ICH_AD3 0x00010000 /* audio power down semaphore */ +#define ICH_RCS 0x00008000 /* read completion status */ +#define ICH_BIT3 0x00004000 /* bit 3 slot 12 */ +#define ICH_BIT2 0x00002000 /* bit 2 slot 12 */ +#define ICH_BIT1 0x00001000 /* bit 1 slot 12 */ +#define ICH_SRI 0x00000800 /* secondary (AC_SDIN1) resume interrupt */ +#define ICH_PRI 0x00000400 /* primary (AC_SDIN0) resume interrupt */ +#define ICH_SCR 0x00000200 /* secondary (AC_SDIN1) codec ready */ +#define ICH_PCR 0x00000100 /* primary (AC_SDIN0) codec ready */ +#define ICH_MCINT 0x00000080 /* MIC capture interrupt */ +#define ICH_POINT 0x00000040 /* playback interrupt */ +#define ICH_PIINT 0x00000020 /* capture interrupt */ +#define ICH_NVSPINT 0x00000010 /* nforce spdif interrupt */ +#define ICH_MOINT 0x00000004 /* modem playback interrupt */ +#define ICH_MIINT 0x00000002 /* modem capture interrupt */ +#define ICH_GSCI 0x00000001 /* GPI status change interrupt */ +#define ICH_REG_ACC_SEMA 0x44 /* byte - codec write semaphore */ +#define ICH_CAS 0x01 /* codec access semaphore */ + +#define ICH_MAX_FRAGS 32 /* max hw frags */ + + +/* + * + */ + +enum { ICHD_MDMIN, ICHD_MDMOUT, ICHD_MDMLAST = ICHD_MDMOUT }; +enum { ALID_MDMIN, ALID_MDMOUT, ALID_MDMLAST = ALID_MDMOUT }; + +#define get_ichdev(substream) (ichdev_t *)(substream->runtime->private_data) + +typedef struct { + unsigned int ichd; /* ich device number */ + unsigned long reg_offset; /* offset to bmaddr */ + u32 *bdbar; /* CPU address (32bit) */ + unsigned int bdbar_addr; /* PCI bus address (32bit) */ + snd_pcm_substream_t *substream; + unsigned int physbuf; /* physical address (32bit) */ + unsigned int size; + unsigned int fragsize; + unsigned int fragsize1; + unsigned int position; + int frags; + int lvi; + int lvi_frag; + int civ; + int ack; + int ack_reload; + unsigned int ack_bit; + unsigned int roff_sr; + unsigned int roff_picb; + unsigned int int_sta_mask; /* interrupt status mask */ + unsigned int ali_slot; /* ALI DMA slot */ + ac97_t *ac97; +} ichdev_t; + +typedef struct _snd_intel8x0m intel8x0_t; +#define chip_t intel8x0_t + +struct _snd_intel8x0m { + unsigned int device_type; + char ac97_name[64]; + char ctrl_name[64]; + + int irq; + + unsigned int mmio; + unsigned long addr; + unsigned long remap_addr; + struct resource *res; + unsigned int bm_mmio; + unsigned long bmaddr; + unsigned long remap_bmaddr; + struct resource *res_bm; + + struct pci_dev *pci; + snd_card_t *card; + + int pcm_devs; + snd_pcm_t *pcm[2]; + ichdev_t ichd[2]; + + int in_ac97_init: 1; + + ac97_bus_t *ac97_bus; + ac97_t *ac97; + + spinlock_t reg_lock; + spinlock_t ac97_lock; + + struct snd_dma_device dma_dev; + struct snd_dma_buffer bdbars; + u32 bdbars_count; + u32 int_sta_reg; /* interrupt status register */ + u32 int_sta_mask; /* interrupt status mask */ + unsigned int pcm_pos_shift; + +#ifdef CONFIG_PM + int in_suspend; +#endif +}; + +static struct pci_device_id snd_intel8x0m_ids[] = { + { 0x8086, 0x2416, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82801AA */ + { 0x8086, 0x2426, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82901AB */ + { 0x8086, 0x2446, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82801BA */ + { 0x8086, 0x2486, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH3 */ + { 0x8086, 0x24c6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH4 */ + { 0x8086, 0x24d6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH5 */ + { 0x8086, 0x7196, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 440MX */ + { 0x1022, 0x7446, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD768 */ +#if 0 + /* TODO: support needed */ + { 0x1039, 0x7013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_SIS }, /* SI7013 */ + { 0x10de, 0x01b1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* NFORCE */ + { 0x10de, 0x006a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* NFORCE2 */ + { 0x10de, 0x00da, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* NFORCE3 */ + { 0x1022, 0x746d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD8111 */ + { 0x10b9, 0x5455, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALI }, /* Ali5455 */ +#endif + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, snd_intel8x0m_ids); + +/* + * Lowlevel I/O - busmaster + */ + +static u8 igetbyte(intel8x0_t *chip, u32 offset) +{ + if (chip->bm_mmio) + return readb(chip->remap_bmaddr + offset); + else + return inb(chip->bmaddr + offset); +} + +static u16 igetword(intel8x0_t *chip, u32 offset) +{ + if (chip->bm_mmio) + return readw(chip->remap_bmaddr + offset); + else + return inw(chip->bmaddr + offset); +} + +static u32 igetdword(intel8x0_t *chip, u32 offset) +{ + if (chip->bm_mmio) + return readl(chip->remap_bmaddr + offset); + else + return inl(chip->bmaddr + offset); +} + +static void iputbyte(intel8x0_t *chip, u32 offset, u8 val) +{ + if (chip->bm_mmio) + writeb(val, chip->remap_bmaddr + offset); + else + outb(val, chip->bmaddr + offset); +} + +static void iputdword(intel8x0_t *chip, u32 offset, u32 val) +{ + if (chip->bm_mmio) + writel(val, chip->remap_bmaddr + offset); + else + outl(val, chip->bmaddr + offset); +} + +/* + * Lowlevel I/O - AC'97 registers + */ + +static u16 iagetword(intel8x0_t *chip, u32 offset) +{ + if (chip->mmio) + return readw(chip->remap_addr + offset); + else + return inw(chip->addr + offset); +} + +static void iaputword(intel8x0_t *chip, u32 offset, u16 val) +{ + if (chip->mmio) + writew(val, chip->remap_addr + offset); + else + outw(val, chip->addr + offset); +} + +/* + * Basic I/O + */ + +/* + * access to AC97 codec via normal i/o (for ICH and SIS7013) + */ + +/* return the GLOB_STA bit for the corresponding codec */ +static unsigned int get_ich_codec_bit(intel8x0_t *chip, unsigned int codec) +{ + static unsigned int codec_bit[3] = { + ICH_PCR, ICH_SCR, ICH_TCR + }; + snd_assert(codec < 3, return ICH_PCR); + return codec_bit[codec]; +} + +static int snd_intel8x0m_codec_semaphore(intel8x0_t *chip, unsigned int codec) +{ + int time; + + if (codec > 1) + return -EIO; + codec = get_ich_codec_bit(chip, codec); + + /* codec ready ? */ + if ((igetdword(chip, ICHREG(GLOB_STA)) & codec) == 0) + return -EIO; + + /* Anyone holding a semaphore for 1 msec should be shot... */ + time = 100; + do { + if (!(igetbyte(chip, ICHREG(ACC_SEMA)) & ICH_CAS)) + return 0; + udelay(10); + } while (time--); + + /* access to some forbidden (non existant) ac97 registers will not + * reset the semaphore. So even if you don't get the semaphore, still + * continue the access. We don't need the semaphore anyway. */ + snd_printk("codec_semaphore: semaphore is not ready [0x%x][0x%x]\n", + igetbyte(chip, ICHREG(ACC_SEMA)), igetdword(chip, ICHREG(GLOB_STA))); + iagetword(chip, 0); /* clear semaphore flag */ + /* I don't care about the semaphore */ + return -EBUSY; +} + +static void snd_intel8x0_codec_write(ac97_t *ac97, + unsigned short reg, + unsigned short val) +{ + intel8x0_t *chip = snd_magic_cast(intel8x0_t, ac97->private_data, return); + + spin_lock(&chip->ac97_lock); + if (snd_intel8x0m_codec_semaphore(chip, ac97->num) < 0) { + if (! chip->in_ac97_init) + snd_printk("codec_write %d: semaphore is not ready for register 0x%x\n", ac97->num, reg); + } + iaputword(chip, reg + ac97->num * 0x80, val); + spin_unlock(&chip->ac97_lock); +} + +static unsigned short snd_intel8x0_codec_read(ac97_t *ac97, + unsigned short reg) +{ + intel8x0_t *chip = snd_magic_cast(intel8x0_t, ac97->private_data, return ~0); + unsigned short res; + unsigned int tmp; + + spin_lock(&chip->ac97_lock); + if (snd_intel8x0m_codec_semaphore(chip, ac97->num) < 0) { + if (! chip->in_ac97_init) + snd_printk("codec_read %d: semaphore is not ready for register 0x%x\n", ac97->num, reg); + res = 0xffff; + } else { + res = iagetword(chip, reg + ac97->num * 0x80); + if ((tmp = igetdword(chip, ICHREG(GLOB_STA))) & ICH_RCS) { + /* reset RCS and preserve other R/WC bits */ + iputdword(chip, ICHREG(GLOB_STA), tmp & ~(ICH_SRI|ICH_PRI|ICH_TRI|ICH_GSCI)); + if (! chip->in_ac97_init) + snd_printk("codec_read %d: read timeout for register 0x%x\n", ac97->num, reg); + res = 0xffff; + } + } + spin_unlock(&chip->ac97_lock); + return res; +} + + +/* + * DMA I/O + */ +static void snd_intel8x0_setup_periods(intel8x0_t *chip, ichdev_t *ichdev) +{ + int idx; + u32 *bdbar = ichdev->bdbar; + unsigned long port = ichdev->reg_offset; + + iputdword(chip, port + ICH_REG_OFF_BDBAR, ichdev->bdbar_addr); + if (ichdev->size == ichdev->fragsize) { + ichdev->ack_reload = ichdev->ack = 2; + ichdev->fragsize1 = ichdev->fragsize >> 1; + for (idx = 0; idx < (ICH_REG_LVI_MASK + 1) * 2; idx += 4) { + bdbar[idx + 0] = cpu_to_le32(ichdev->physbuf); + bdbar[idx + 1] = cpu_to_le32(0x80000000 | /* interrupt on completion */ + ichdev->fragsize1 >> chip->pcm_pos_shift); + bdbar[idx + 2] = cpu_to_le32(ichdev->physbuf + (ichdev->size >> 1)); + bdbar[idx + 3] = cpu_to_le32(0x80000000 | /* interrupt on completion */ + ichdev->fragsize1 >> chip->pcm_pos_shift); + } + ichdev->frags = 2; + } else { + ichdev->ack_reload = ichdev->ack = 1; + ichdev->fragsize1 = ichdev->fragsize; + for (idx = 0; idx < (ICH_REG_LVI_MASK + 1) * 2; idx += 2) { + bdbar[idx + 0] = cpu_to_le32(ichdev->physbuf + (((idx >> 1) * ichdev->fragsize) % ichdev->size)); + bdbar[idx + 1] = cpu_to_le32(0x80000000 | /* interrupt on completion */ + ichdev->fragsize >> chip->pcm_pos_shift); + // printk("bdbar[%i] = 0x%x [0x%x]\n", idx + 0, bdbar[idx + 0], bdbar[idx + 1]); + } + ichdev->frags = ichdev->size / ichdev->fragsize; + } + iputbyte(chip, port + ICH_REG_OFF_LVI, ichdev->lvi = ICH_REG_LVI_MASK); + ichdev->civ = 0; + iputbyte(chip, port + ICH_REG_OFF_CIV, 0); + ichdev->lvi_frag = ICH_REG_LVI_MASK % ichdev->frags; + ichdev->position = 0; +#if 0 + printk("lvi_frag = %i, frags = %i, period_size = 0x%x, period_size1 = 0x%x\n", + ichdev->lvi_frag, ichdev->frags, ichdev->fragsize, ichdev->fragsize1); +#endif + /* clear interrupts */ + iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI); +} + +/* + * Interrupt handler + */ + +static inline void snd_intel8x0_update(intel8x0_t *chip, ichdev_t *ichdev) +{ + unsigned long port = ichdev->reg_offset; + int civ, i, step; + int ack = 0; + + civ = igetbyte(chip, port + ICH_REG_OFF_CIV); + if (civ == ichdev->civ) { + // snd_printd("civ same %d\n", civ); + step = 1; + ichdev->civ++; + ichdev->civ &= ICH_REG_LVI_MASK; + } else { + step = civ - ichdev->civ; + if (step < 0) + step += ICH_REG_LVI_MASK + 1; + // if (step != 1) + // snd_printd("step = %d, %d -> %d\n", step, ichdev->civ, civ); + ichdev->civ = civ; + } + + ichdev->position += step * ichdev->fragsize1; + ichdev->position %= ichdev->size; + ichdev->lvi += step; + ichdev->lvi &= ICH_REG_LVI_MASK; + iputbyte(chip, port + ICH_REG_OFF_LVI, ichdev->lvi); + for (i = 0; i < step; i++) { + ichdev->lvi_frag++; + ichdev->lvi_frag %= ichdev->frags; + ichdev->bdbar[ichdev->lvi * 2] = cpu_to_le32(ichdev->physbuf + ichdev->lvi_frag * ichdev->fragsize1); + // printk("new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, all = 0x%x, 0x%x\n", ichdev->lvi * 2, ichdev->bdbar[ichdev->lvi * 2], ichdev->bdbar[ichdev->lvi * 2 + 1], inb(ICH_REG_OFF_PIV + port), inl(port + 4), inb(port + ICH_REG_OFF_CR)); + if (--ichdev->ack == 0) { + ichdev->ack = ichdev->ack_reload; + ack = 1; + } + } + if (ack && ichdev->substream) { + spin_unlock(&chip->reg_lock); + snd_pcm_period_elapsed(ichdev->substream); + spin_lock(&chip->reg_lock); + } + iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI); +} + +static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + intel8x0_t *chip = snd_magic_cast(intel8x0_t, dev_id, return IRQ_NONE); + ichdev_t *ichdev; + unsigned int status; + unsigned int i; + + spin_lock(&chip->reg_lock); + status = igetdword(chip, chip->int_sta_reg); + if ((status & chip->int_sta_mask) == 0) { + if (status) + iputdword(chip, chip->int_sta_reg, status); + spin_unlock(&chip->reg_lock); + return IRQ_NONE; + } + + for (i = 0; i < chip->bdbars_count; i++) { + ichdev = &chip->ichd[i]; + if (status & ichdev->int_sta_mask) + snd_intel8x0_update(chip, ichdev); + } + + /* ack them */ + iputdword(chip, chip->int_sta_reg, status & chip->int_sta_mask); + spin_unlock(&chip->reg_lock); + + return IRQ_HANDLED; +} + +/* + * PCM part + */ + +static int snd_intel8x0_pcm_trigger(snd_pcm_substream_t *substream, int cmd) +{ + intel8x0_t *chip = snd_pcm_substream_chip(substream); + ichdev_t *ichdev = get_ichdev(substream); + unsigned char val = 0; + unsigned long port = ichdev->reg_offset; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + val = ICH_IOCE | ICH_STARTBM; + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + val = 0; + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + val = ICH_IOCE; + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + val = ICH_IOCE | ICH_STARTBM; + break; + default: + return -EINVAL; + } + iputbyte(chip, port + ICH_REG_OFF_CR, val); + if (cmd == SNDRV_PCM_TRIGGER_STOP) { + /* wait until DMA stopped */ + while (!(igetbyte(chip, port + ichdev->roff_sr) & ICH_DCH)) ; + /* reset whole DMA things */ + iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS); + } + return 0; +} + +static int snd_intel8x0_hw_params(snd_pcm_substream_t * substream, + snd_pcm_hw_params_t * hw_params) +{ + return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); +} + +static int snd_intel8x0_hw_free(snd_pcm_substream_t * substream) +{ + return snd_pcm_lib_free_pages(substream); +} + +static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(snd_pcm_substream_t * substream) +{ + intel8x0_t *chip = snd_pcm_substream_chip(substream); + ichdev_t *ichdev = get_ichdev(substream); + size_t ptr1, ptr; + + ptr1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << chip->pcm_pos_shift; + if (ptr1 != 0) + ptr = ichdev->fragsize1 - ptr1; + else + ptr = 0; + ptr += ichdev->position; + if (ptr >= ichdev->size) + return 0; + return bytes_to_frames(substream->runtime, ptr); +} + +static int snd_intel8x0m_pcm_trigger(snd_pcm_substream_t *substream, int cmd) +{ + ichdev_t *ichdev = get_ichdev(substream); + /* hook off/on on start/stop */ + /* TODO: move it to ac97 controls */ + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + snd_ac97_update_bits(ichdev->ac97, AC97_GPIO_STATUS, + AC97_GPIO_LINE1_OH, AC97_GPIO_LINE1_OH); + break; + case SNDRV_PCM_TRIGGER_STOP: + snd_ac97_update_bits(ichdev->ac97, AC97_GPIO_STATUS, + AC97_GPIO_LINE1_OH, ~AC97_GPIO_LINE1_OH); + break; + default: + return -EINVAL; + } + return snd_intel8x0_pcm_trigger(substream,cmd); +} + +static int snd_intel8x0m_pcm_prepare(snd_pcm_substream_t * substream) +{ + intel8x0_t *chip = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + ichdev_t *ichdev = get_ichdev(substream); + + ichdev->physbuf = runtime->dma_addr; + ichdev->size = snd_pcm_lib_buffer_bytes(substream); + ichdev->fragsize = snd_pcm_lib_period_bytes(substream); + snd_ac97_write(ichdev->ac97, AC97_LINE1_RATE, runtime->rate); + snd_ac97_write(ichdev->ac97, AC97_LINE1_LEVEL, 0); + snd_intel8x0_setup_periods(chip, ichdev); + return 0; +} + +static snd_pcm_hardware_t snd_intel8x0m_stream = +{ + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_KNOT, + .rate_min = 8000, + .rate_max = 16000, + .channels_min = 1, + .channels_max = 1, + .buffer_bytes_max = 32 * 1024, + .period_bytes_min = 32, + .period_bytes_max = 32 * 1024, + .periods_min = 1, + .periods_max = 1024, + .fifo_size = 0, +}; + + +static int snd_intel8x0m_pcm_open(snd_pcm_substream_t * substream, ichdev_t *ichdev) +{ + static unsigned int rates[] = { 8000, 9600, 12000, 16000 }; + static snd_pcm_hw_constraint_list_t hw_constraints_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0, + }; + snd_pcm_runtime_t *runtime = substream->runtime; + int err; + + ichdev->substream = substream; + runtime->hw = snd_intel8x0m_stream; + err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); + if ( err < 0 ) + return err; + runtime->private_data = ichdev; + return 0; +} + +static int snd_intel8x0m_playback_open(snd_pcm_substream_t * substream) +{ + intel8x0_t *chip = snd_pcm_substream_chip(substream); + + return snd_intel8x0m_pcm_open(substream, &chip->ichd[ICHD_MDMOUT]); +} + +static int snd_intel8x0m_playback_close(snd_pcm_substream_t * substream) +{ + intel8x0_t *chip = snd_pcm_substream_chip(substream); + + chip->ichd[ICHD_MDMOUT].substream = NULL; + return 0; +} + +static int snd_intel8x0m_capture_open(snd_pcm_substream_t * substream) +{ + intel8x0_t *chip = snd_pcm_substream_chip(substream); + + return snd_intel8x0m_pcm_open(substream, &chip->ichd[ICHD_MDMIN]); +} + +static int snd_intel8x0m_capture_close(snd_pcm_substream_t * substream) +{ + intel8x0_t *chip = snd_pcm_substream_chip(substream); + + chip->ichd[ICHD_MDMIN].substream = NULL; + return 0; +} + + +static snd_pcm_ops_t snd_intel8x0m_playback_ops = { + .open = snd_intel8x0m_playback_open, + .close = snd_intel8x0m_playback_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_intel8x0_hw_params, + .hw_free = snd_intel8x0_hw_free, + .prepare = snd_intel8x0m_pcm_prepare, + .trigger = snd_intel8x0m_pcm_trigger, + .pointer = snd_intel8x0_pcm_pointer, +}; + +static snd_pcm_ops_t snd_intel8x0m_capture_ops = { + .open = snd_intel8x0m_capture_open, + .close = snd_intel8x0m_capture_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_intel8x0_hw_params, + .hw_free = snd_intel8x0_hw_free, + .prepare = snd_intel8x0m_pcm_prepare, + .trigger = snd_intel8x0m_pcm_trigger, + .pointer = snd_intel8x0_pcm_pointer, +}; + + +struct ich_pcm_table { + char *suffix; + snd_pcm_ops_t *playback_ops; + snd_pcm_ops_t *capture_ops; + size_t prealloc_size; + size_t prealloc_max_size; + int ac97_idx; +}; + +static int __devinit snd_intel8x0_pcm1(intel8x0_t *chip, int device, struct ich_pcm_table *rec) +{ + snd_pcm_t *pcm; + int err; + char name[32]; + + if (rec->suffix) + sprintf(name, "Intel ICH - %s", rec->suffix); + else + strcpy(name, "Intel ICH"); + err = snd_pcm_new(chip->card, name, device, + rec->playback_ops ? 1 : 0, + rec->capture_ops ? 1 : 0, &pcm); + if (err < 0) + return err; + + if (rec->playback_ops) + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, rec->playback_ops); + if (rec->capture_ops) + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, rec->capture_ops); + + pcm->private_data = chip; + pcm->info_flags = 0; + if (rec->suffix) + sprintf(pcm->name, "%s - %s", chip->card->shortname, rec->suffix); + else + strcpy(pcm->name, chip->card->shortname); + chip->pcm[device] = pcm; + + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), + rec->prealloc_size, + rec->prealloc_max_size); + + return 0; +} + +static struct ich_pcm_table intel_pcms[] __devinitdata = { + { + .suffix = "Modem", + .playback_ops = &snd_intel8x0m_playback_ops, + .capture_ops = &snd_intel8x0m_capture_ops, + .prealloc_size = 4 * 1024, + .prealloc_max_size = 16 * 1024, + }, +}; + +static int __devinit snd_intel8x0_pcm(intel8x0_t *chip) +{ + int i, tblsize, device, err; + struct ich_pcm_table *tbl, *rec; + +#if 1 + tbl = intel_pcms; + tblsize = 1; +#else + switch (chip->device_type) { + case DEVICE_NFORCE: + tbl = nforce_pcms; + tblsize = ARRAY_SIZE(nforce_pcms); + break; + case DEVICE_ALI: + tbl = ali_pcms; + tblsize = ARRAY_SIZE(ali_pcms); + break; + default: + tbl = intel_pcms; + tblsize = 2; + break; + } +#endif + device = 0; + for (i = 0; i < tblsize; i++) { + rec = tbl + i; + if (i > 0 && rec->ac97_idx) { + /* activate PCM only when associated AC'97 codec */ + if (! chip->ichd[rec->ac97_idx].ac97) + continue; + } + err = snd_intel8x0_pcm1(chip, device, rec); + if (err < 0) + return err; + device++; + } + + chip->pcm_devs = device; + return 0; +} + + +/* + * Mixer part + */ + +static void snd_intel8x0_mixer_free_ac97_bus(ac97_bus_t *bus) +{ + intel8x0_t *chip = snd_magic_cast(intel8x0_t, bus->private_data, return); + chip->ac97_bus = NULL; +} + +static void snd_intel8x0_mixer_free_ac97(ac97_t *ac97) +{ + intel8x0_t *chip = snd_magic_cast(intel8x0_t, ac97->private_data, return); + chip->ac97 = NULL; +} + + +static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock) +{ + ac97_bus_t bus, *pbus; + ac97_t ac97, *x97; + int err; + unsigned int glob_sta = 0; + + chip->in_ac97_init = 1; + memset(&bus, 0, sizeof(bus)); + bus.private_data = chip; + bus.private_free = snd_intel8x0_mixer_free_ac97_bus; + if (ac97_clock >= 8000 && ac97_clock <= 48000) + bus.clock = ac97_clock; + else + bus.clock = 48000; + + memset(&ac97, 0, sizeof(ac97)); + ac97.private_data = chip; + ac97.private_free = snd_intel8x0_mixer_free_ac97; + + glob_sta = igetdword(chip, ICHREG(GLOB_STA)); + bus.write = snd_intel8x0_codec_write; + bus.read = snd_intel8x0_codec_read; + bus.vra = 1; + + if ((err = snd_ac97_bus(chip->card, &bus, &pbus)) < 0) + goto __err; + chip->ac97_bus = pbus; + ac97.pci = chip->pci; + ac97.num = glob_sta & ICH_SCR ? 1 : 0; + if ((err = snd_ac97_mixer(pbus, &ac97, &x97)) < 0) { + snd_printk(KERN_ERR "Unable to initialize codec #%d\n", ac97.num); + if (ac97.num == 0) + goto __err; + return err; + } + chip->ac97 = x97; + if(ac97_is_modem(x97) && !chip->ichd[ICHD_MDMIN].ac97 ) { + chip->ichd[ICHD_MDMIN].ac97 = x97; + chip->ichd[ICHD_MDMOUT].ac97 = x97; + } + + chip->in_ac97_init = 0; + return 0; + + __err: + /* clear the cold-reset bit for the next chance */ + if (chip->device_type != DEVICE_ALI) + iputdword(chip, ICHREG(GLOB_CNT), igetdword(chip, ICHREG(GLOB_CNT)) & ~ICH_AC97COLD); + return err; +} + + +/* + * + */ + +#define do_delay(chip) do {\ + set_current_state(TASK_UNINTERRUPTIBLE);\ + schedule_timeout(1);\ +} while (0) + +static int snd_intel8x0m_ich_chip_init(intel8x0_t *chip, int probing) +{ + unsigned long end_time; + unsigned int cnt, status, nstatus; + + /* put logic to right state */ + /* first clear status bits */ + status = ICH_RCS | ICH_MIINT | ICH_MOINT; + cnt = igetdword(chip, ICHREG(GLOB_STA)); + iputdword(chip, ICHREG(GLOB_STA), cnt & status); + + /* ACLink on, 2 channels */ + cnt = igetdword(chip, ICHREG(GLOB_CNT)); + cnt &= ~(ICH_ACLINK); + /* finish cold or do warm reset */ + cnt |= (cnt & ICH_AC97COLD) == 0 ? ICH_AC97COLD : ICH_AC97WARM; + iputdword(chip, ICHREG(GLOB_CNT), cnt); + end_time = (jiffies + (HZ / 4)) + 1; + do { + if ((igetdword(chip, ICHREG(GLOB_CNT)) & ICH_AC97WARM) == 0) + goto __ok; + do_delay(chip); + } while (time_after_eq(end_time, jiffies)); + snd_printk("AC'97 warm reset still in progress? [0x%x]\n", igetdword(chip, ICHREG(GLOB_CNT))); + return -EIO; + + __ok: + if (probing) { + /* wait for any codec ready status. + * Once it becomes ready it should remain ready + * as long as we do not disable the ac97 link. + */ + end_time = jiffies + HZ; + do { + status = igetdword(chip, ICHREG(GLOB_STA)) & (ICH_PCR | ICH_SCR | ICH_TCR); + if (status) + break; + do_delay(chip); + } while (time_after_eq(end_time, jiffies)); + if (! status) { + /* no codec is found */ + snd_printk(KERN_ERR "codec_ready: codec is not ready [0x%x]\n", igetdword(chip, ICHREG(GLOB_STA))); + return -EIO; + } + + /* up to two codecs (modem cannot be tertiary with ICH4) */ + nstatus = ICH_PCR | ICH_SCR; + + /* wait for other codecs ready status. */ + end_time = jiffies + HZ / 4; + while (status != nstatus && time_after_eq(end_time, jiffies)) { + do_delay(chip); + status |= igetdword(chip, ICHREG(GLOB_STA)) & nstatus; + } + + } else { + /* resume phase */ + status = 0; + if (chip->ac97) + status |= get_ich_codec_bit(chip, chip->ac97->num); + /* wait until all the probed codecs are ready */ + end_time = jiffies + HZ; + do { + nstatus = igetdword(chip, ICHREG(GLOB_STA)) & (ICH_PCR | ICH_SCR | ICH_TCR); + if (status == nstatus) + break; + do_delay(chip); + } while (time_after_eq(end_time, jiffies)); + } + + return 0; +} + +static int snd_intel8x0_chip_init(intel8x0_t *chip, int probing) +{ + unsigned int i; + int err; + + if ((err = snd_intel8x0m_ich_chip_init(chip, probing)) < 0) + return err; + iagetword(chip, 0); /* clear semaphore flag */ + + /* disable interrupts */ + for (i = 0; i < chip->bdbars_count; i++) + iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, 0x00); + /* reset channels */ + for (i = 0; i < chip->bdbars_count; i++) + iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, ICH_RESETREGS); + /* initialize Buffer Descriptor Lists */ + for (i = 0; i < chip->bdbars_count; i++) + iputdword(chip, ICH_REG_OFF_BDBAR + chip->ichd[i].reg_offset, chip->ichd[i].bdbar_addr); + return 0; +} + +static int snd_intel8x0_free(intel8x0_t *chip) +{ + unsigned int i; + + if (chip->irq < 0) + goto __hw_end; + /* disable interrupts */ + for (i = 0; i < chip->bdbars_count; i++) + iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, 0x00); + /* reset channels */ + for (i = 0; i < chip->bdbars_count; i++) + iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, ICH_RESETREGS); + /* --- */ + synchronize_irq(chip->irq); + __hw_end: + if (chip->bdbars.area) + snd_dma_free_pages(&chip->dma_dev, &chip->bdbars); + if (chip->remap_addr) + iounmap((void *) chip->remap_addr); + if (chip->remap_bmaddr) + iounmap((void *) chip->remap_bmaddr); + if (chip->res) { + release_resource(chip->res); + kfree_nocheck(chip->res); + } + if (chip->res_bm) { + release_resource(chip->res_bm); + kfree_nocheck(chip->res_bm); + } + if (chip->irq >= 0) + free_irq(chip->irq, (void *)chip); + snd_magic_kfree(chip); + return 0; +} + +#ifdef CONFIG_PM +/* + * power management + */ +static void intel8x0_suspend(intel8x0_t *chip) +{ + snd_card_t *card = chip->card; + int i; + + if (chip->in_suspend || + card->power_state == SNDRV_CTL_POWER_D3hot) + return; + + chip->in_suspend = 1; + for (i = 0; i < chip->pcm_devs; i++) + snd_pcm_suspend_all(chip->pcm[i]); + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); +} + +static void intel8x0_resume(intel8x0_t *chip) +{ + snd_card_t *card = chip->card; + + if (! chip->in_suspend || + card->power_state == SNDRV_CTL_POWER_D0) + return; + + pci_enable_device(chip->pci); + pci_set_master(chip->pci); + snd_intel8x0_chip_init(chip, 0); + if (chip->ac97) + snd_ac97_resume(chip->ac97); + + chip->in_suspend = 0; + snd_power_change_state(card, SNDRV_CTL_POWER_D0); +} + +static int snd_intel8x0m_suspend(struct pci_dev *dev, u32 state) +{ + intel8x0_t *chip = snd_magic_cast(intel8x0_t, pci_get_drvdata(dev), return -ENXIO); + intel8x0_suspend(chip); + return 0; +} +static int snd_intel8x0m_resume(struct pci_dev *dev) +{ + intel8x0_t *chip = snd_magic_cast(intel8x0_t, pci_get_drvdata(dev), return -ENXIO); + intel8x0_resume(chip); + return 0; +} + +/* callback */ +static int snd_intel8x0_set_power_state(snd_card_t *card, unsigned int power_state) +{ + intel8x0_t *chip = snd_magic_cast(intel8x0_t, card->power_state_private_data, return -ENXIO); + switch (power_state) { + case SNDRV_CTL_POWER_D0: + case SNDRV_CTL_POWER_D1: + case SNDRV_CTL_POWER_D2: + intel8x0_resume(chip); + break; + case SNDRV_CTL_POWER_D3hot: + case SNDRV_CTL_POWER_D3cold: + intel8x0_suspend(chip); + break; + default: + return -EINVAL; + } + return 0; +} + +#endif /* CONFIG_PM */ + +static void snd_intel8x0m_proc_read(snd_info_entry_t * entry, + snd_info_buffer_t * buffer) +{ + intel8x0_t *chip = snd_magic_cast(intel8x0_t, entry->private_data, return); + unsigned int tmp; + + snd_iprintf(buffer, "Intel8x0m\n\n"); + if (chip->device_type == DEVICE_ALI) + return; + tmp = igetdword(chip, ICHREG(GLOB_STA)); + snd_iprintf(buffer, "Global control : 0x%08x\n", igetdword(chip, ICHREG(GLOB_CNT))); + snd_iprintf(buffer, "Global status : 0x%08x\n", tmp); + snd_iprintf(buffer, "AC'97 codecs ready :%s%s%s%s\n", + tmp & ICH_PCR ? " primary" : "", + tmp & ICH_SCR ? " secondary" : "", + tmp & ICH_TCR ? " tertiary" : "", + (tmp & (ICH_PCR | ICH_SCR | ICH_TCR)) == 0 ? " none" : ""); +} + +static void __devinit snd_intel8x0m_proc_init(intel8x0_t * chip) +{ + snd_info_entry_t *entry; + + if (! snd_card_proc_new(chip->card, "intel8x0m", &entry)) + snd_info_set_text_ops(entry, chip, 1024, snd_intel8x0m_proc_read); +} + +static int snd_intel8x0_dev_free(snd_device_t *device) +{ + intel8x0_t *chip = snd_magic_cast(intel8x0_t, device->device_data, return -ENXIO); + return snd_intel8x0_free(chip); +} + +struct ich_reg_info { + unsigned int int_sta_mask; + unsigned int offset; +}; + +static int __devinit snd_intel8x0m_create(snd_card_t * card, + struct pci_dev *pci, + unsigned long device_type, + intel8x0_t ** r_intel8x0) +{ + intel8x0_t *chip; + int err; + unsigned int i; + unsigned int int_sta_masks; + ichdev_t *ichdev; + static snd_device_ops_t ops = { + .dev_free = snd_intel8x0_dev_free, + }; + static struct ich_reg_info intel_regs[2] = { + { ICH_MIINT, 0 }, + { ICH_MOINT, 0x10 }, + }; + struct ich_reg_info *tbl; + + *r_intel8x0 = NULL; + + if ((err = pci_enable_device(pci)) < 0) + return err; + + chip = snd_magic_kcalloc(intel8x0_t, 0, GFP_KERNEL); + if (chip == NULL) + return -ENOMEM; + spin_lock_init(&chip->reg_lock); + spin_lock_init(&chip->ac97_lock); + chip->device_type = device_type; + chip->card = card; + chip->pci = pci; + chip->irq = -1; + snd_intel8x0m_proc_init(chip); + sprintf(chip->ac97_name, "%s - AC'97", card->shortname); + sprintf(chip->ctrl_name, "%s - Controller", card->shortname); + if (device_type == DEVICE_ALI) { + /* ALI5455 has no ac97 region */ + chip->bmaddr = pci_resource_start(pci, 0); + if ((chip->res_bm = request_region(chip->bmaddr, 256, chip->ctrl_name)) == NULL) { + snd_printk("unable to grab ports 0x%lx-0x%lx\n", chip->bmaddr, chip->bmaddr + 256 - 1); + snd_intel8x0_free(chip); + return -EBUSY; + } + goto port_inited; + } + + if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) { /* ICH4 and Nforce */ + chip->mmio = 1; + chip->addr = pci_resource_start(pci, 2); + if ((chip->res = request_mem_region(chip->addr, 512, chip->ac97_name)) == NULL) { + snd_printk("unable to grab I/O memory 0x%lx-0x%lx\n", chip->addr, chip->addr + 512 - 1); + snd_intel8x0_free(chip); + return -EBUSY; + } + chip->remap_addr = (unsigned long) ioremap_nocache(chip->addr, 512); + if (chip->remap_addr == 0) { + snd_printk("AC'97 space ioremap problem\n"); + snd_intel8x0_free(chip); + return -EIO; + } + } else { + chip->addr = pci_resource_start(pci, 0); + if ((chip->res = request_region(chip->addr, 256, chip->ac97_name)) == NULL) { + snd_printk("unable to grab ports 0x%lx-0x%lx\n", chip->addr, chip->addr + 256 - 1); + snd_intel8x0_free(chip); + return -EBUSY; + } + } + if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) { /* ICH4 */ + chip->bm_mmio = 1; + chip->bmaddr = pci_resource_start(pci, 3); + if ((chip->res_bm = request_mem_region(chip->bmaddr, 256, chip->ctrl_name)) == NULL) { + snd_printk("unable to grab I/O memory 0x%lx-0x%lx\n", chip->bmaddr, chip->bmaddr + 512 - 1); + snd_intel8x0_free(chip); + return -EBUSY; + } + chip->remap_bmaddr = (unsigned long) ioremap_nocache(chip->bmaddr, 256); + if (chip->remap_bmaddr == 0) { + snd_printk("Controller space ioremap problem\n"); + snd_intel8x0_free(chip); + return -EIO; + } + } else { + chip->bmaddr = pci_resource_start(pci, 1); + if ((chip->res_bm = request_region(chip->bmaddr, 128, chip->ctrl_name)) == NULL) { + snd_printk("unable to grab ports 0x%lx-0x%lx\n", chip->bmaddr, chip->bmaddr + 128 - 1); + snd_intel8x0_free(chip); + return -EBUSY; + } + } + + port_inited: + if (request_irq(pci->irq, snd_intel8x0_interrupt, SA_INTERRUPT|SA_SHIRQ, card->shortname, (void *)chip)) { + snd_printk("unable to grab IRQ %d\n", pci->irq); + snd_intel8x0_free(chip); + return -EBUSY; + } + chip->irq = pci->irq; + pci_set_master(pci); + synchronize_irq(chip->irq); + + /* initialize offsets */ + chip->bdbars_count = 2; + tbl = intel_regs; + + for (i = 0; i < chip->bdbars_count; i++) { + ichdev = &chip->ichd[i]; + ichdev->ichd = i; + ichdev->reg_offset = tbl[i].offset; + ichdev->int_sta_mask = tbl[i].int_sta_mask; + if (device_type == DEVICE_SIS) { + /* SiS 7013 swaps the registers */ + ichdev->roff_sr = ICH_REG_OFF_PICB; + ichdev->roff_picb = ICH_REG_OFF_SR; + } else { + ichdev->roff_sr = ICH_REG_OFF_SR; + ichdev->roff_picb = ICH_REG_OFF_PICB; + } + if (device_type == DEVICE_ALI) + ichdev->ali_slot = (ichdev->reg_offset - 0x40) / 0x10; + } + /* SIS7013 handles the pcm data in bytes, others are in words */ + chip->pcm_pos_shift = (device_type == DEVICE_SIS) ? 0 : 1; + + /* allocate buffer descriptor lists */ + /* the start of each lists must be aligned to 8 bytes */ + memset(&chip->dma_dev, 0, sizeof(chip->dma_dev)); + chip->dma_dev.type = SNDRV_DMA_TYPE_DEV; + chip->dma_dev.dev = snd_dma_pci_data(pci); + if (snd_dma_alloc_pages(&chip->dma_dev, chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2, &chip->bdbars) < 0) { + snd_intel8x0_free(chip); + return -ENOMEM; + } + /* tables must be aligned to 8 bytes here, but the kernel pages + are much bigger, so we don't care (on i386) */ + int_sta_masks = 0; + for (i = 0; i < chip->bdbars_count; i++) { + ichdev = &chip->ichd[i]; + ichdev->bdbar = ((u32 *)chip->bdbars.area) + (i * ICH_MAX_FRAGS * 2); + ichdev->bdbar_addr = chip->bdbars.addr + (i * sizeof(u32) * ICH_MAX_FRAGS * 2); + int_sta_masks |= ichdev->int_sta_mask; + } + chip->int_sta_reg = ICH_REG_GLOB_STA; + chip->int_sta_mask = int_sta_masks; + + if ((err = snd_intel8x0_chip_init(chip, 1)) < 0) { + snd_intel8x0_free(chip); + return err; + } + +#ifdef CONFIG_PM + card->set_power_state = snd_intel8x0_set_power_state; + card->power_state_private_data = chip; +#endif + + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + snd_intel8x0_free(chip); + return err; + } + + snd_card_set_dev(card, &pci->dev); + + *r_intel8x0 = chip; + return 0; +} + +static struct shortname_table { + unsigned int id; + const char *s; +} shortnames[] __devinitdata = { + { PCI_DEVICE_ID_INTEL_82801_6, "Intel 82801AA-ICH" }, + { PCI_DEVICE_ID_INTEL_82901_6, "Intel 82901AB-ICH0" }, + { PCI_DEVICE_ID_INTEL_82801BA_6, "Intel 82801BA-ICH2" }, + { PCI_DEVICE_ID_INTEL_440MX_6, "Intel 440MX" }, + { PCI_DEVICE_ID_INTEL_ICH3_6, "Intel 82801CA-ICH3" }, + { PCI_DEVICE_ID_INTEL_ICH4_6, "Intel 82801DB-ICH4" }, + { PCI_DEVICE_ID_INTEL_ICH5_6, "Intel ICH5" }, + { 0x7446, "AMD AMD768" }, +#if 0 + { PCI_DEVICE_ID_SI_7013, "SiS SI7013" }, + { PCI_DEVICE_ID_NVIDIA_MCP_AUDIO, "NVidia nForce" }, + { PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO, "NVidia nForce2" }, + { PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO, "NVidia nForce3" }, + { 0x5455, "ALi M5455" }, + { 0x746d, "AMD AMD8111" }, +#endif + { 0, 0 }, +}; + +static int __devinit snd_intel8x0m_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) +{ + static int dev; + snd_card_t *card; + intel8x0_t *chip; + int err; + struct shortname_table *name; + + if (dev >= SNDRV_CARDS) + return -ENODEV; + if (!enable[dev]) { + dev++; + return -ENOENT; + } + + card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); + if (card == NULL) + return -ENOMEM; + + switch (pci_id->driver_data) { + case DEVICE_NFORCE: + strcpy(card->driver, "NFORCE"); + break; + default: + strcpy(card->driver, "ICH"); + break; + } + + strcpy(card->shortname, "Intel ICH"); + for (name = shortnames; name->id; name++) { + if (pci->device == name->id) { + strcpy(card->shortname, name->s); + break; + } + } + strcat(card->shortname," Modem"); + + if ((err = snd_intel8x0m_create(card, pci, pci_id->driver_data, &chip)) < 0) { + snd_card_free(card); + return err; + } + + if ((err = snd_intel8x0_mixer(chip, ac97_clock[dev])) < 0) { + snd_card_free(card); + return err; + } + if ((err = snd_intel8x0_pcm(chip)) < 0) { + snd_card_free(card); + return err; + } + + sprintf(card->longname, "%s at 0x%lx, irq %i", + card->shortname, chip->addr, chip->irq); + + if ((err = snd_card_register(card)) < 0) { + snd_card_free(card); + return err; + } + pci_set_drvdata(pci, chip); + dev++; + return 0; +} + +static void __devexit snd_intel8x0m_remove(struct pci_dev *pci) +{ + intel8x0_t *chip = snd_magic_cast(intel8x0_t, pci_get_drvdata(pci), return); + if (chip) + snd_card_free(chip->card); + pci_set_drvdata(pci, NULL); +} + +static struct pci_driver driver = { + .name = "Intel ICH Modem", + .id_table = snd_intel8x0m_ids, + .probe = snd_intel8x0m_probe, + .remove = __devexit_p(snd_intel8x0m_remove), +#ifdef CONFIG_PM + .suspend = snd_intel8x0m_suspend, + .resume = snd_intel8x0m_resume, +#endif +}; + + +static int __init alsa_card_intel8x0m_init(void) +{ + int err; + + if ((err = pci_module_init(&driver)) < 0) { +#ifdef MODULE + printk(KERN_ERR "Intel ICH modemcard not found or device busy\n"); +#endif + return err; + } + + return 0; +} + +static void __exit alsa_card_intel8x0m_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_intel8x0m_init) +module_exit(alsa_card_intel8x0m_exit) + +#ifndef MODULE + +/* format is: snd-intel8x0=enable,index,id,ac97_clock,mpu_port,joystick */ + +static int __init alsa_card_intel8x0m_setup(char *str) +{ + static unsigned __initdata nr_dev = 0; + + if (nr_dev >= SNDRV_CARDS) + return 0; + (void)(get_option(&str,&enable[nr_dev]) == 2 && + get_option(&str,&index[nr_dev]) == 2 && + get_id(&str,&id[nr_dev]) == 2 && + get_option(&str,&ac97_clock[nr_dev]) == 2 + ); + nr_dev++; + return 1; +} + +__setup("snd-intel8x0m=", alsa_card_intel8x0m_setup); + +#endif /* ifndef MODULE */ diff -Nru a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c --- a/sound/pci/korg1212/korg1212.c Sun Mar 14 14:20:05 2004 +++ b/sound/pci/korg1212/korg1212.c Sun Mar 14 14:20:05 2004 @@ -347,9 +347,14 @@ struct resource *res_ioport; struct resource *res_iomem2; + struct snd_dma_device dma_dev; + + struct snd_dma_buffer dma_dsp; + struct snd_dma_buffer dma_play; + struct snd_dma_buffer dma_rec; + struct snd_dma_buffer dma_shared; + u32 dspCodeSize; - u32 dspMemPhy; // DSP memory block handle (Physical Address) - void * dspMemPtr; // block memory (Virtual Address) u32 DataBufsSize; @@ -357,6 +362,7 @@ KorgAudioBuffer * recordDataBufsPtr; KorgSharedBuffer * sharedBufferPtr; + u32 RecDataPhy; u32 PlayDataPhy; unsigned long sharedBufferPhy; @@ -1238,10 +1244,10 @@ snd_korg1212_setCardState(korg1212, K1212_STATE_DSP_IN_PROCESS); - memcpy(korg1212->dspMemPtr, dspCode, korg1212->dspCodeSize); + memcpy(korg1212->dma_dsp.area, dspCode, korg1212->dspCodeSize); rc = snd_korg1212_Send1212Command(korg1212, K1212_DB_StartDSPDownload, - UpperWordSwap(korg1212->dspMemPhy), + UpperWordSwap(korg1212->dma_dsp.addr), 0, 0, 0); #if K1212_DEBUG_LEVEL > 0 @@ -2134,12 +2140,9 @@ // ---------------------------------------------------- // free up memory resources used for the DSP download. // ---------------------------------------------------- - if (korg1212->dspMemPtr) { - snd_free_pci_pages(korg1212->pci, korg1212->dspCodeSize, - korg1212->dspMemPtr, (dma_addr_t)korg1212->dspMemPhy); - korg1212->dspMemPhy = 0; - korg1212->dspMemPtr = 0; - korg1212->dspCodeSize = 0; + if (korg1212->dma_dsp.area) { + snd_dma_free_pages(&korg1212->dma_dev, &korg1212->dma_dsp); + korg1212->dma_dsp.area = NULL; } #ifndef K1212_LARGEALLOC @@ -2147,18 +2150,14 @@ // ------------------------------------------------------ // free up memory resources used for the Play/Rec Buffers // ------------------------------------------------------ - if (korg1212->playDataBufsPtr) { - snd_free_pci_pages(korg1212->pci, korg1212->DataBufsSize, - korg1212->playDataBufsPtr, (dma_addr_t)korg1212->PlayDataPhy); - korg1212->PlayDataPhy = 0; - korg1212->playDataBufsPtr = NULL; + if (korg1212->dma_play.area) { + snd_dma_free_pages(&korg1212->dma_dev, &korg1212->dma_play); + korg1212->dma_play.area = NULL; } - if (korg1212->recordDataBufsPtr) { - snd_free_pci_pages(korg1212->pci, korg1212->DataBufsSize, - korg1212->recordDataBufsPtr, (dma_addr_t)korg1212->RecDataPhy); - korg1212->RecDataPhy = 0; - korg1212->recordDataBufsPtr = NULL; + if (korg1212->dma_rec.area) { + snd_dma_free_pages(&korg1212->dma_dev, &korg1212->dma_rec); + korg1212->dma_rec.area = NULL; } #endif @@ -2166,11 +2165,9 @@ // ---------------------------------------------------- // free up memory resources used for the Shared Buffers // ---------------------------------------------------- - if (korg1212->sharedBufferPtr) { - snd_free_pci_pages(korg1212->pci, (u32) sizeof(KorgSharedBuffer), - korg1212->sharedBufferPtr, (dma_addr_t)korg1212->sharedBufferPhy); - korg1212->sharedBufferPhy = 0; - korg1212->sharedBufferPtr = NULL; + if (korg1212->dma_shared.area) { + snd_dma_free_pages(&korg1212->dma_dev, &korg1212->dma_shared); + korg1212->dma_shared.area = NULL; } snd_magic_kfree(korg1212); @@ -2193,7 +2190,6 @@ int err; unsigned int i; unsigned ioport_size, iomem_size, iomem2_size; - dma_addr_t phys_addr; korg1212_t * korg1212; static snd_device_ops_t ops = { @@ -2332,13 +2328,16 @@ stateName[korg1212->cardState]); #endif - korg1212->sharedBufferPtr = (KorgSharedBuffer *) snd_malloc_pci_pages(korg1212->pci, sizeof(KorgSharedBuffer), &phys_addr); - korg1212->sharedBufferPhy = (unsigned long)phys_addr; + memset(&korg1212->dma_dev, 0, sizeof(korg1212->dma_dev)); + korg1212->dma_dev.type = SNDRV_DMA_TYPE_DEV; + korg1212->dma_dev.dev = snd_dma_pci_data(korg1212->pci); - if (korg1212->sharedBufferPtr == NULL) { + if (snd_dma_alloc_pages(&korg1212->dma_dev, sizeof(KorgSharedBuffer), &korg1212->dma_shared) < 0) { snd_printk(KERN_ERR "can not allocate shared buffer memory (%Zd bytes)\n", sizeof(KorgSharedBuffer)); return -ENOMEM; } + korg1212->sharedBufferPtr = (KorgSharedBuffer *)korg1212->dma_shared.area; + korg1212->sharedBufferPhy = korg1212->dma_shared.addr; #if K1212_DEBUG_LEVEL > 0 K1212_DEBUG_PRINTK("K1212_DEBUG: Shared Buffer Area = 0x%p (0x%08lx), %d bytes\n", korg1212->sharedBufferPtr, korg1212->sharedBufferPhy, sizeof(KorgSharedBuffer)); @@ -2348,30 +2347,28 @@ korg1212->DataBufsSize = sizeof(KorgAudioBuffer) * kNumBuffers; - korg1212->playDataBufsPtr = (KorgAudioBuffer *) snd_malloc_pci_pages(korg1212->pci, korg1212->DataBufsSize, &phys_addr); - korg1212->PlayDataPhy = (u32)phys_addr; - - if (korg1212->playDataBufsPtr == NULL) { + if (snd_dma_alloc_pages(&korg1212->dma_dev, korg1212->DataBufsSize, &korg1212->dma_play) < 0) { snd_printk(KERN_ERR "can not allocate play data buffer memory (%d bytes)\n", korg1212->DataBufsSize); return -ENOMEM; } + korg1212->playDataBufsPtr = (KorgAudioBuffer *)korg1212->dma_play.area; + korg1212->PlayDataPhy = korg1212->dma_play.addr; #if K1212_DEBUG_LEVEL > 0 K1212_DEBUG_PRINTK("K1212_DEBUG: Play Data Area = 0x%p (0x%08x), %d bytes\n", korg1212->playDataBufsPtr, korg1212->PlayDataPhy, korg1212->DataBufsSize); #endif - korg1212->recordDataBufsPtr = (KorgAudioBuffer *) snd_malloc_pci_pages(korg1212->pci, korg1212->DataBufsSize, &phys_addr); - korg1212->RecDataPhy = (u32)phys_addr; - - if (korg1212->recordDataBufsPtr == NULL) { + if (snd_dma_alloc_pages(&korg1212->dma_dev, korg1212->DataBufsSize, &korg1212->dma_rec) < 0) { snd_printk(KERN_ERR "can not allocate record data buffer memory (%d bytes)\n", korg1212->DataBufsSize); return -ENOMEM; } + korg1212->recordDataBufsPtr = (KorgAudioBuffer *)korg1212->dma_rec.area; + korg1212->RecDataPhy = korg1212->dma_rec.addr; #if K1212_DEBUG_LEVEL > 0 K1212_DEBUG_PRINTK("K1212_DEBUG: Record Data Area = 0x%p (0x%08x), %d bytes\n", - korg1212->recordDataBufsPtr, korg1212->RecDataPhy, korg1212->DataBufsSize); + korg1212->recordDataBufsPtr, korg1212->RecDataBufsPhy, korg1212->DataBufsSize); #endif #else // K1212_LARGEALLOC @@ -2392,17 +2389,14 @@ korg1212->AdatTimeCodePhy = korg1212->sharedBufferPhy + offsetof(KorgSharedBuffer, AdatTimeCode); - korg1212->dspMemPtr = snd_malloc_pci_pages(korg1212->pci, korg1212->dspCodeSize, &phys_addr); - korg1212->dspMemPhy = (u32)phys_addr; - - if (korg1212->dspMemPtr == NULL) { + if (snd_dma_alloc_pages(&korg1212->dma_dev, korg1212->dspCodeSize, &korg1212->dma_dsp) < 0) { snd_printk(KERN_ERR "can not allocate dsp code memory (%d bytes)\n", korg1212->dspCodeSize); return -ENOMEM; } #if K1212_DEBUG_LEVEL > 0 K1212_DEBUG_PRINTK("K1212_DEBUG: DSP Code area = 0x%p (0x%08x) %d bytes [%s]\n", - korg1212->dspMemPtr, korg1212->dspMemPhy, korg1212->dspCodeSize, + korg1212->dma_dsp.area, korg1212->dma_dsp.addr, korg1212->dspCodeSize, stateName[korg1212->cardState]); #endif @@ -2425,7 +2419,7 @@ "VolumeTablePhy = %08x L[%08x]\n" "RoutingTablePhy = %08x L[%08x]\n" "AdatTimeCodePhy = %08x L[%08x]\n", - korg1212->dspMemPhy, UpperWordSwap(korg1212->dspMemPhy), + korg1212->dma_dsp.addr, UpperWordSwap(korg1212->dma_dsp.addr), korg1212->PlayDataPhy, LowerWordSwap(korg1212->PlayDataPhy), korg1212->RecDataPhy, LowerWordSwap(korg1212->RecDataPhy), korg1212->VolumeTablePhy, LowerWordSwap(korg1212->VolumeTablePhy), diff -Nru a/sound/pci/maestro3.c b/sound/pci/maestro3.c --- a/sound/pci/maestro3.c Sun Mar 14 14:20:07 2004 +++ b/sound/pci/maestro3.c Sun Mar 14 14:20:07 2004 @@ -1816,7 +1816,8 @@ strcpy(pcm->name, chip->card->driver); chip->pcm = pcm; - snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 64*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), 64*1024, 64*1024); return 0; } diff -Nru a/sound/pci/mixart/Makefile b/sound/pci/mixart/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/mixart/Makefile Sun Mar 14 14:20:09 2004 @@ -0,0 +1,8 @@ +# +# Makefile for ALSA +# Copyright (c) 2001 by Jaroslav Kysela +# + +snd-mixart-objs := mixart.o mixart_core.o mixart_hwdep.o mixart_mixer.o + +obj-$(CONFIG_SND_MIXART) += snd-mixart.o diff -Nru a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/mixart/mixart.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,1473 @@ +/* + * Driver for Digigram miXart soundcards + * + * main file with alsa callbacks + * + * Copyright (c) 2003 by Digigram + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include +#include +#include +#include +#define SNDRV_GET_ID +#include +#include +#include +#include +#include +#include "mixart.h" +#include "mixart_hwdep.h" +#include "mixart_core.h" +#include "mixart_mixer.h" + +#define CARD_NAME "miXart" + +MODULE_AUTHOR("Digigram "); +MODULE_DESCRIPTION("Digigram " CARD_NAME); +MODULE_LICENSE("GPL"); +MODULE_CLASSES("{sound}"); +MODULE_DEVICES("{{Digigram," CARD_NAME "}}"); + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ + +#define chip_t mixart_t + +MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(index, "Index value for Digigram " CARD_NAME " soundcard."); +MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); +MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s"); +MODULE_PARM_DESC(id, "ID string for Digigram " CARD_NAME " soundcard."); +MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); +MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(enable, "Enable Digigram " CARD_NAME " soundcard."); +MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); + +/* + */ + +static struct pci_device_id snd_mixart_ids[] = { + { 0x1057, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* MC8240 */ + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, snd_mixart_ids); + + +static int mixart_set_pipe_state(mixart_mgr_t *mgr, mixart_pipe_t* pipe, int start) +{ + mixart_group_state_req_t group_state; + mixart_group_state_resp_t group_state_resp; + mixart_msg_t request; + int err; + u32 system_msg_uid; + + switch(pipe->status) { + case PIPE_RUNNING: + case PIPE_CLOCK_SET: + if(start) return 0; /* already started */ + break; + case PIPE_STOPPED: + if(!start) return 0; /* already stopped */ + break; + default: + snd_printk(KERN_ERR "error mixart_set_pipe_state called with wrong pipe->status!\n"); + return -EINVAL; /* function called with wrong pipe status */ + } + + system_msg_uid = 0x12345678; /* the event ! (take care: the MSB and two LSB's have to be 0) */ + + /* wait on the last MSG_SYSTEM_SEND_SYNCHRO_CMD command to be really finished */ + + request.message_id = MSG_SYSTEM_WAIT_SYNCHRO_CMD; + request.uid = (mixart_uid_t){0,0}; + request.data = &system_msg_uid; + request.size = sizeof(system_msg_uid); + + err = snd_mixart_send_msg_wait_notif(mgr, &request, system_msg_uid); + if(err) { + snd_printk(KERN_ERR "error : MSG_SYSTEM_WAIT_SYNCHRO_CMD was not notified !\n"); + return err; + } + + /* start or stop the pipe (1 pipe) */ + + memset(&group_state, 0, sizeof(group_state)); + group_state.pipe_count = 1; + group_state.pipe_uid[0] = pipe->group_uid; + + if(start) + request.message_id = MSG_STREAM_START_STREAM_GRP_PACKET; + else + request.message_id = MSG_STREAM_STOP_STREAM_GRP_PACKET; + + request.uid = pipe->group_uid; /*(mixart_uid_t){0,0};*/ + request.data = &group_state; + request.size = sizeof(group_state); + + err = snd_mixart_send_msg(mgr, &request, sizeof(group_state_resp), &group_state_resp); + if (err < 0 || group_state_resp.txx_status != 0) { + snd_printk(KERN_ERR "error MSG_STREAM_ST***_STREAM_GRP_PACKET err=%x stat=%x !\n", err, group_state_resp.txx_status); + return -EINVAL; + } + + if(start) { + u32 stat; + + group_state.pipe_count = 0; /* in case of start same command once again with pipe_count=0 */ + + err = snd_mixart_send_msg(mgr, &request, sizeof(group_state_resp), &group_state_resp); + if (err < 0 || group_state_resp.txx_status != 0) { + snd_printk(KERN_ERR "error MSG_STREAM_START_STREAM_GRP_PACKET err=%x stat=%x !\n", err, group_state_resp.txx_status); + return -EINVAL; + } + + /* in case of start send a synchro top */ + + request.message_id = MSG_SYSTEM_SEND_SYNCHRO_CMD; + request.uid = (mixart_uid_t){0,0}; + request.data = NULL; + request.size = 0; + + err = snd_mixart_send_msg(mgr, &request, sizeof(stat), &stat); + if (err < 0 || stat != 0) { + snd_printk(KERN_ERR "error MSG_SYSTEM_SEND_SYNCHRO_CMD err=%x stat=%x !\n", err, stat); + return -EINVAL; + } + + pipe->status = PIPE_RUNNING; + } + else /* !start */ + pipe->status = PIPE_STOPPED; + + return 0; +} + + +static int mixart_set_clock(mixart_mgr_t *mgr, mixart_pipe_t *pipe, unsigned int rate) +{ + mixart_msg_t request; + mixart_clock_properties_t clock_properties; + mixart_clock_properties_resp_t clock_prop_resp; + int err; + + switch(pipe->status) { + case PIPE_CLOCK_SET: + break; + case PIPE_RUNNING: + if(rate != 0) + break; + default: + if(rate == 0) + return 0; /* nothing to do */ + else { + snd_printk(KERN_ERR "error mixart_set_clock(%d) called with wrong pipe->status !\n", rate); + return -EINVAL; + } + } + + memset(&clock_properties, 0, sizeof(clock_properties)); + clock_properties.clock_generic_type = (rate != 0) ? CGT_INTERNAL_CLOCK : CGT_NO_CLOCK; + clock_properties.clock_mode = CM_STANDALONE; + clock_properties.frequency = rate; + clock_properties.nb_callers = 1; /* only one entry in uid_caller ! */ + clock_properties.uid_caller[0] = pipe->group_uid; + + snd_printdd("mixart_set_clock to %d kHz\n", rate); + + request.message_id = MSG_CLOCK_SET_PROPERTIES; + request.uid = mgr->uid_console_manager; + request.data = &clock_properties; + request.size = sizeof(clock_properties); + + err = snd_mixart_send_msg(mgr, &request, sizeof(clock_prop_resp), &clock_prop_resp); + if (err < 0 || clock_prop_resp.status != 0 || clock_prop_resp.clock_mode != CM_STANDALONE) { + snd_printk(KERN_ERR "error MSG_CLOCK_SET_PROPERTIES err=%x stat=%x mod=%x !\n", err, clock_prop_resp.status, clock_prop_resp.clock_mode); + return -EINVAL; + } + + if(rate) pipe->status = PIPE_CLOCK_SET; + else pipe->status = PIPE_RUNNING; + + return 0; +} + + +/* + * Allocate or reference output pipe for analog IOs (pcmp0/1) + */ +mixart_pipe_t* snd_mixart_add_ref_pipe( mixart_t *chip, int pcm_number, int capture, int monitoring) +{ + int stream_count; + mixart_pipe_t *pipe; + mixart_msg_t request; + + if(capture) { + if (pcm_number == MIXART_PCM_ANALOG) { + pipe = &(chip->pipe_in_ana); /* analog inputs */ + } else { + pipe = &(chip->pipe_in_dig); /* digital inputs */ + } + request.message_id = MSG_STREAM_ADD_OUTPUT_GROUP; + stream_count = MIXART_CAPTURE_STREAMS; + } else { + if (pcm_number == MIXART_PCM_ANALOG) { + pipe = &(chip->pipe_out_ana); /* analog outputs */ + } else { + pipe = &(chip->pipe_out_dig); /* digital outputs */ + } + request.message_id = MSG_STREAM_ADD_INPUT_GROUP; + stream_count = MIXART_PLAYBACK_STREAMS; + } + + /* a new stream is opened and there are already all streams in use */ + if( (monitoring == 0) && (pipe->references >= stream_count) ) { + return NULL; + } + + /* pipe is not yet defined */ + if( pipe->status == PIPE_UNDEFINED ) { + int err, i; + mixart_streaming_group_t streaming_group_resp; + mixart_streaming_group_req_t streaming_group_req; + + snd_printdd("add_ref_pipe audio chip(%d) pcm(%d)\n", chip->chip_idx, pcm_number); + + request.uid = (mixart_uid_t){0,0}; /* should be StreamManagerUID, but zero is OK if there is only one ! */ + request.data = &streaming_group_req; + request.size = sizeof(streaming_group_req); + + memset(&streaming_group_req, 0, sizeof(streaming_group_req)); + + streaming_group_req.stream_count = stream_count; + streaming_group_req.channel_count = 2; + streaming_group_req.latency = 256; + streaming_group_req.connector = pipe->uid_left_connector; /* the left connector */ + + for (i=0; ichip_idx * MIXART_MAX_STREAM_PER_CARD) + (pcm_number * (MIXART_PLAYBACK_STREAMS + MIXART_CAPTURE_STREAMS)) + i; + if(capture) j += MIXART_PLAYBACK_STREAMS; /* in the array capture is behind playback */ + + streaming_group_req.flow_entry[i] = j; + + flowinfo = (struct mixart_flowinfo *)chip->mgr->flowinfo.area; + flowinfo[j].bufferinfo_array_phy_address = (u32)chip->mgr->bufferinfo.addr + (j * sizeof(mixart_bufferinfo_t)); + flowinfo[j].bufferinfo_count = 1; /* 1 will set the miXart to ring-buffer mode ! */ + + bufferinfo = (struct mixart_bufferinfo *)chip->mgr->bufferinfo.area; + bufferinfo[j].buffer_address = 0; /* buffer is not yet allocated */ + bufferinfo[j].available_length = 0; /* buffer is not yet allocated */ + + /* construct the identifier of the stream buffer received in the interrupts ! */ + bufferinfo[j].buffer_id = (chip->chip_idx << MIXART_NOTIFY_CARD_OFFSET) + (pcm_number << MIXART_NOTIFY_PCM_OFFSET ) + i; + if(capture) { + bufferinfo[j].buffer_id |= MIXART_NOTIFY_CAPT_MASK; + } + } + + err = snd_mixart_send_msg(chip->mgr, &request, sizeof(streaming_group_resp), &streaming_group_resp); + if((err < 0) || (streaming_group_resp.status != 0)) { + snd_printk(KERN_ERR "error MSG_STREAM_ADD_**PUT_GROUP err=%x stat=%x !\n", err, streaming_group_resp.status); + return NULL; + } + + pipe->group_uid = streaming_group_resp.group; /* id of the pipe, as returned by embedded */ + pipe->stream_count = streaming_group_resp.stream_count; + /* pipe->stream_uid[i] = streaming_group_resp.stream[i].stream_uid; */ + + pipe->status = PIPE_STOPPED; + } + + if(monitoring) pipe->monitoring = 1; + else pipe->references++; + + return pipe; +} + + +int snd_mixart_kill_ref_pipe( mixart_mgr_t *mgr, mixart_pipe_t *pipe, int monitoring) +{ + int err = 0; + + if(pipe->status == PIPE_UNDEFINED) + return 0; + + if(monitoring) + pipe->monitoring = 0; + else + pipe->references--; + + if((pipe->references <= 0) && (pipe->monitoring == 0)) { + + mixart_msg_t request; + mixart_delete_group_resp_t delete_resp; + + /* release the clock */ + err = mixart_set_clock( mgr, pipe, 0); + if( err < 0 ) { + snd_printk(KERN_ERR "mixart_set_clock(0) return error!\n"); + } + + /* stop the pipe */ + err = mixart_set_pipe_state(mgr, pipe, 0); + if( err < 0 ) { + snd_printk(KERN_ERR "error stopping pipe!\n"); + } + + request.message_id = MSG_STREAM_DELETE_GROUP; + request.uid = (mixart_uid_t){0,0}; + request.data = &pipe->group_uid; /* the streaming group ! */ + request.size = sizeof(pipe->group_uid); + + /* delete the pipe */ + err = snd_mixart_send_msg(mgr, &request, sizeof(delete_resp), &delete_resp); + if ((err < 0) || (delete_resp.status != 0)) { + snd_printk(KERN_ERR "error MSG_STREAM_DELETE_GROUP err(%x), status(%x)\n", err, delete_resp.status); + } + + pipe->group_uid = (mixart_uid_t){0,0}; + pipe->stream_count = 0; + pipe->status = PIPE_UNDEFINED; + } + + return err; +} + +static int mixart_set_stream_state(mixart_stream_t *stream, int start) +{ + mixart_t *chip; + mixart_stream_state_req_t stream_state_req; + mixart_msg_t request; + + if(!stream->substream) + return -EINVAL; + + memset(&stream_state_req, 0, sizeof(stream_state_req)); + stream_state_req.stream_count = 1; + stream_state_req.stream_info.stream_desc.uid_pipe = stream->pipe->group_uid; + stream_state_req.stream_info.stream_desc.stream_idx = stream->substream->number; + + if (stream->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + request.message_id = start ? MSG_STREAM_START_INPUT_STAGE_PACKET : MSG_STREAM_STOP_INPUT_STAGE_PACKET; + else + request.message_id = start ? MSG_STREAM_START_OUTPUT_STAGE_PACKET : MSG_STREAM_STOP_OUTPUT_STAGE_PACKET; + + request.uid = (mixart_uid_t){0,0}; + request.data = &stream_state_req; + request.size = sizeof(stream_state_req); + + stream->abs_period_elapsed = 0; /* reset stream pos */ + stream->buf_periods = 0; + stream->buf_period_frag = 0; + + chip = snd_pcm_substream_chip(stream->substream); + + return snd_mixart_send_msg_nonblock(chip->mgr, &request); +} + +/* + * Trigger callback + */ + +static int snd_mixart_trigger(snd_pcm_substream_t *subs, int cmd) +{ + mixart_stream_t *stream = (mixart_stream_t*)subs->runtime->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + + snd_printdd("SNDRV_PCM_TRIGGER_START\n"); + + /* START_STREAM */ + if( mixart_set_stream_state(stream, 1) ) + return -EINVAL; + + stream->status = MIXART_STREAM_STATUS_RUNNING; + + break; + case SNDRV_PCM_TRIGGER_STOP: + + /* STOP_STREAM */ + if( mixart_set_stream_state(stream, 0) ) + return -EINVAL; + + stream->status = MIXART_STREAM_STATUS_OPEN; + + snd_printdd("SNDRV_PCM_TRIGGER_STOP\n"); + + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + /* TODO */ + stream->status = MIXART_STREAM_STATUS_PAUSE; + snd_printdd("SNDRV_PCM_PAUSE_PUSH\n"); + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + /* TODO */ + stream->status = MIXART_STREAM_STATUS_RUNNING; + snd_printdd("SNDRV_PCM_PAUSE_RELEASE\n"); + break; + default: + return -EINVAL; + } + return 0; +} + +static int mixart_sync_nonblock_events(mixart_mgr_t *mgr) +{ + int timeout = HZ; + while (atomic_read(&mgr->msg_processed) > 0) { + if (! timeout--) { + snd_printk(KERN_ERR "mixart: cannot process nonblock events!\n"); + return -EBUSY; + } + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + return 0; +} + +/* + * prepare callback for all pcms + * + * NOTE: this callback is non-atomic (pcm->info_flags |= SNDRV_PCM_INFO_NONATOMIC_OPS) + */ +static int snd_mixart_prepare(snd_pcm_substream_t *subs) +{ + mixart_t *chip = snd_pcm_substream_chip(subs); + mixart_stream_t *stream = (mixart_stream_t*)subs->runtime->private_data; + + /* TODO de façon non bloquante, réappliquer les hw_params (rate, bits, codec) */ + + snd_printdd("snd_mixart_prepare\n"); + + mixart_sync_nonblock_events(chip->mgr); + + /* only the first stream can choose the sample rate */ + /* the further opened streams will be limited to its frequency (see open) */ + if(chip->mgr->ref_count_rate == 1) + chip->mgr->sample_rate = subs->runtime->rate; + + /* set the clock only once (first stream) on the same pipe */ + if(stream->pipe->references == 1) { + if( mixart_set_clock(chip->mgr, stream->pipe, subs->runtime->rate) ) + return -EINVAL; + } + + return 0; +} + + +static int mixart_set_format(mixart_stream_t *stream, snd_pcm_format_t format) +{ + int err; + mixart_t *chip; + mixart_msg_t request; + mixart_stream_param_desc_t stream_param; + mixart_return_uid_t resp; + + chip = snd_pcm_substream_chip(stream->substream); + + memset(&stream_param, 0, sizeof(stream_param)); + + stream_param.coding_type = CT_LINEAR; + stream_param.number_of_channel = stream->channels; + + stream_param.sampling_freq = chip->mgr->sample_rate; + if(stream_param.sampling_freq == 0) + stream_param.sampling_freq = 44100; /* if frequency not yet defined, use some default */ + + switch(format){ + case SNDRV_PCM_FORMAT_U8: + stream_param.sample_type = ST_INTEGER_8; + stream_param.sample_size = 8; + break; + case SNDRV_PCM_FORMAT_S16_LE: + stream_param.sample_type = ST_INTEGER_16LE; + stream_param.sample_size = 16; + break; + case SNDRV_PCM_FORMAT_S16_BE: + stream_param.sample_type = ST_INTEGER_16BE; + stream_param.sample_size = 16; + break; + case SNDRV_PCM_FORMAT_S24_3LE: + stream_param.sample_type = ST_INTEGER_24LE; + stream_param.sample_size = 24; + break; + case SNDRV_PCM_FORMAT_S24_3BE: + stream_param.sample_type = ST_INTEGER_24BE; + stream_param.sample_size = 24; + break; + case SNDRV_PCM_FMTBIT_FLOAT_LE: + stream_param.sample_type = ST_FLOATING_POINT_32LE; + stream_param.sample_size = 32; + break; + case SNDRV_PCM_FMTBIT_FLOAT_BE: + stream_param.sample_type = ST_FLOATING_POINT_32BE; + stream_param.sample_size = 32; + break; + default: + snd_printk(KERN_ERR "error mixart_set_format() : unknown format\n"); + return -EINVAL; + } + + snd_printdd("set SNDRV_PCM_FORMAT sample_type(%d) sample_size(%d) freq(%d) channels(%d)\n", + stream_param.sample_type, stream_param.sample_size, stream_param.sampling_freq, stream->channels); + + /* TODO: what else to configure ? */ + /* stream_param.samples_per_frame = 2; */ + /* stream_param.bytes_per_frame = 4; */ + /* stream_param.bytes_per_sample = 2; */ + + stream_param.pipe_count = 1; /* set to 1 */ + stream_param.stream_count = 1; /* set to 1 */ + stream_param.stream_desc[0].uid_pipe = stream->pipe->group_uid; + stream_param.stream_desc[0].stream_idx = stream->substream->number; + + request.message_id = MSG_STREAM_SET_INPUT_STAGE_PARAM; + request.uid = (mixart_uid_t){0,0}; + request.data = &stream_param; + request.size = sizeof(stream_param); + + err = snd_mixart_send_msg(chip->mgr, &request, sizeof(resp), &resp); + if((err < 0) || resp.error_code) { + snd_printk(KERN_ERR "MSG_STREAM_SET_INPUT_STAGE_PARAM err=%x; resp=%x\n", err, resp.error_code); + return -EINVAL; + } + return 0; +} + + +/* + * HW_PARAMS callback for all pcms + */ +static int snd_mixart_hw_params(snd_pcm_substream_t *subs, + snd_pcm_hw_params_t *hw) +{ + mixart_t *chip = snd_pcm_substream_chip(subs); + mixart_mgr_t *mgr = chip->mgr; + mixart_stream_t *stream = (mixart_stream_t*)subs->runtime->private_data; + snd_pcm_format_t format; + int err; + int channels; + + /* set up channels */ + channels = params_channels(hw); + + /* set up format for the stream */ + format = params_format(hw); + + down(&mgr->setup_mutex); + + /* update the stream levels */ + if( stream->pcm_number <= MIXART_PCM_DIGITAL ) { + int is_aes = stream->pcm_number > MIXART_PCM_ANALOG; + if( subs->stream == SNDRV_PCM_STREAM_PLAYBACK ) + mixart_update_playback_stream_level(chip, is_aes, subs->number); + else + mixart_update_capture_stream_level( chip, is_aes); + } + + stream->channels = channels; + + /* set the format to the board */ + err = mixart_set_format(stream, format); + if(err < 0) { + return err; + } + + /* allocate buffer */ + err = snd_pcm_lib_malloc_pages(subs, params_buffer_bytes(hw)); + + if (err > 0) { + struct mixart_bufferinfo *bufferinfo; + int i = (chip->chip_idx * MIXART_MAX_STREAM_PER_CARD) + (stream->pcm_number * (MIXART_PLAYBACK_STREAMS+MIXART_CAPTURE_STREAMS)) + subs->number; + if( subs->stream == SNDRV_PCM_STREAM_CAPTURE ) { + i += MIXART_PLAYBACK_STREAMS; /* in array capture is behind playback */ + } + + bufferinfo = (struct mixart_bufferinfo *)chip->mgr->bufferinfo.area; + bufferinfo[i].buffer_address = subs->runtime->dma_addr; + bufferinfo[i].available_length = subs->runtime->dma_bytes; + /* bufferinfo[i].buffer_id is already defined */ + + snd_printdd("snd_mixart_hw_params(pcm %d) : dma_addr(%x) dma_bytes(%x) subs-number(%d)\n", i, subs->runtime->dma_addr, subs->runtime->dma_bytes, subs->number); + } + up(&mgr->setup_mutex); + + return err; +} + +static int snd_mixart_hw_free(snd_pcm_substream_t *subs) +{ + mixart_t *chip = snd_pcm_substream_chip(subs); + snd_pcm_lib_free_pages(subs); + mixart_sync_nonblock_events(chip->mgr); + return 0; +} + + + +/* + * TODO CONFIGURATION SPACE for all pcms, mono pcm must update channels_max + */ +static snd_pcm_hardware_t snd_mixart_analog_caps = +{ + .info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START | + SNDRV_PCM_INFO_PAUSE), + .formats = ( SNDRV_PCM_FMTBIT_U8 | + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | + SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE ), + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, + .rate_min = 8000, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = (32*1024), + .period_bytes_min = 256, /* 256 frames U8 mono*/ + .period_bytes_max = (16*1024), + .periods_min = 2, + .periods_max = (32*1024/256), +}; + +static snd_pcm_hardware_t snd_mixart_digital_caps = +{ + .info = ( SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_SYNC_START | + SNDRV_PCM_INFO_PAUSE), + .formats = ( SNDRV_PCM_FMTBIT_U8 | + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | + SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE ), + .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, + .rate_min = 32000, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = (32*1024), + .period_bytes_min = 256, /* 256 frames U8 mono*/ + .period_bytes_max = (16*1024), + .periods_min = 2, + .periods_max = (32*1024/256), +}; + + +static int snd_mixart_playback_open(snd_pcm_substream_t *subs) +{ + mixart_t *chip = snd_pcm_substream_chip(subs); + mixart_mgr_t *mgr = chip->mgr; + snd_pcm_runtime_t *runtime = subs->runtime; + snd_pcm_t *pcm = subs->pcm; + mixart_stream_t *stream; + mixart_pipe_t *pipe; + int err = 0; + int pcm_number; + + down(&mgr->setup_mutex); + + if ( pcm == chip->pcm ) { + pcm_number = MIXART_PCM_ANALOG; + runtime->hw = snd_mixart_analog_caps; + } else { + snd_assert ( pcm == chip->pcm_dig ); + pcm_number = MIXART_PCM_DIGITAL; + runtime->hw = snd_mixart_digital_caps; + } + snd_printdd("snd_mixart_playback_open C%d/P%d/Sub%d\n", chip->chip_idx, pcm_number, subs->number); + + /* get stream info */ + stream = &(chip->playback_stream[pcm_number][subs->number]); + + if (stream->status != MIXART_STREAM_STATUS_FREE){ + /* streams in use */ + snd_printk(KERN_ERR "snd_mixart_playback_open C%d/P%d/Sub%d in use\n", chip->chip_idx, pcm_number, subs->number); + err = -EBUSY; + goto _exit_open; + } + + /* get pipe pointer (out pipe) */ + pipe = snd_mixart_add_ref_pipe(chip, pcm_number, 0, 0); + + if (pipe == NULL) { + err = -EINVAL; + goto _exit_open; + } + + /* start the pipe if necessary */ + err = mixart_set_pipe_state(chip->mgr, pipe, 1); + if( err < 0 ) { + snd_printk(KERN_ERR "error starting pipe!\n"); + snd_mixart_kill_ref_pipe(chip->mgr, pipe, 0); + err = -EINVAL; + goto _exit_open; + } + + stream->pipe = pipe; + stream->pcm_number = pcm_number; + stream->status = MIXART_STREAM_STATUS_OPEN; + stream->substream = subs; + stream->channels = 0; /* not configured yet */ + + runtime->private_data = stream; + + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 64); + + /* if a sample rate is already used, another stream cannot change */ + if(mgr->ref_count_rate++) { + if(mgr->sample_rate) { + runtime->hw.rate_min = runtime->hw.rate_max = mgr->sample_rate; + } + } + + _exit_open: + up(&mgr->setup_mutex); + + return err; +} + + +static int snd_mixart_capture_open(snd_pcm_substream_t *subs) +{ + mixart_t *chip = snd_pcm_substream_chip(subs); + mixart_mgr_t *mgr = chip->mgr; + snd_pcm_runtime_t *runtime = subs->runtime; + snd_pcm_t *pcm = subs->pcm; + mixart_stream_t *stream; + mixart_pipe_t *pipe; + int err = 0; + int pcm_number; + + down(&mgr->setup_mutex); + + if ( pcm == chip->pcm ) { + pcm_number = MIXART_PCM_ANALOG; + runtime->hw = snd_mixart_analog_caps; + } else { + snd_assert ( pcm == chip->pcm_dig ); + pcm_number = MIXART_PCM_DIGITAL; + runtime->hw = snd_mixart_digital_caps; + } + + runtime->hw.channels_min = 2; /* for instance, no mono */ + + snd_printdd("snd_mixart_capture_open C%d/P%d/Sub%d\n", chip->chip_idx, pcm_number, subs->number); + + /* get stream info */ + stream = &(chip->capture_stream[pcm_number]); + + if (stream->status != MIXART_STREAM_STATUS_FREE){ + /* streams in use */ + snd_printk(KERN_ERR "snd_mixart_capture_open C%d/P%d/Sub%d in use\n", chip->chip_idx, pcm_number, subs->number); + err = -EBUSY; + goto _exit_open; + } + + /* get pipe pointer (in pipe) */ + pipe = snd_mixart_add_ref_pipe(chip, pcm_number, 1, 0); + + if (pipe == NULL) { + err = -EINVAL; + goto _exit_open; + } + + /* start the pipe if necessary */ + err = mixart_set_pipe_state(chip->mgr, pipe, 1); + if( err < 0 ) { + snd_printk(KERN_ERR "error starting pipe!\n"); + snd_mixart_kill_ref_pipe(chip->mgr, pipe, 0); + err = -EINVAL; + goto _exit_open; + } + + stream->pipe = pipe; + stream->pcm_number = pcm_number; + stream->status = MIXART_STREAM_STATUS_OPEN; + stream->substream = subs; + stream->channels = 0; /* not configured yet */ + + runtime->private_data = stream; + + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 64); + + /* if a sample rate is already used, another stream cannot change */ + if(mgr->ref_count_rate++) { + if(mgr->sample_rate) { + runtime->hw.rate_min = runtime->hw.rate_max = mgr->sample_rate; + } + } + + _exit_open: + up(&mgr->setup_mutex); + + return err; +} + + + +static int snd_mixart_close(snd_pcm_substream_t *subs) +{ + mixart_t *chip = snd_pcm_substream_chip(subs); + mixart_mgr_t *mgr = chip->mgr; + mixart_stream_t *stream = (mixart_stream_t*)subs->runtime->private_data; + + down(&mgr->setup_mutex); + + snd_printdd("snd_mixart_close C%d/P%d/Sub%d\n", chip->chip_idx, stream->pcm_number, subs->number); + + /* sample rate released */ + if(--mgr->ref_count_rate == 0) { + mgr->sample_rate = 0; + } + + /* delete pipe */ + if (snd_mixart_kill_ref_pipe(mgr, stream->pipe, 0 ) < 0) { + + snd_printk(KERN_ERR "error snd_mixart_kill_ref_pipe C%dP%d\n", chip->chip_idx, stream->pcm_number); + } + + stream->pipe = NULL; + stream->status = MIXART_STREAM_STATUS_FREE; + stream->substream = NULL; + + up(&mgr->setup_mutex); + return 0; +} + + +static snd_pcm_uframes_t snd_mixart_stream_pointer(snd_pcm_substream_t * subs) +{ + snd_pcm_runtime_t *runtime = subs->runtime; + mixart_stream_t *stream = (mixart_stream_t*)runtime->private_data; + + return (snd_pcm_uframes_t)((stream->buf_periods * runtime->period_size) + stream->buf_period_frag); +} + + + +static snd_pcm_ops_t snd_mixart_playback_ops = { + .open = snd_mixart_playback_open, + .close = snd_mixart_close, + .ioctl = snd_pcm_lib_ioctl, + .prepare = snd_mixart_prepare, + .hw_params = snd_mixart_hw_params, + .hw_free = snd_mixart_hw_free, + .trigger = snd_mixart_trigger, + .pointer = snd_mixart_stream_pointer, +}; + +static snd_pcm_ops_t snd_mixart_capture_ops = { + .open = snd_mixart_capture_open, + .close = snd_mixart_close, + .ioctl = snd_pcm_lib_ioctl, + .prepare = snd_mixart_prepare, + .hw_params = snd_mixart_hw_params, + .hw_free = snd_mixart_hw_free, + .trigger = snd_mixart_trigger, + .pointer = snd_mixart_stream_pointer, +}; + +static void preallocate_buffers(mixart_t *chip, snd_pcm_t *pcm) +{ + snd_pcm_substream_t *subs; + int stream; + + for (stream = 0; stream < 2; stream++) { + int idx = 0; + for (subs = pcm->streams[stream].substream; subs; subs = subs->next, idx++) + /* set up the unique device id with the chip index */ + subs->dma_device.id = subs->pcm->device << 16 | + subs->stream << 8 | (subs->number + 1) | + (chip->chip_idx + 1) << 24; + } + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->mgr->pci), 32*1024, 32*1024); +} + +/* + */ +static int snd_mixart_pcm_analog(mixart_t *chip) +{ + int err; + snd_pcm_t *pcm; + char name[32]; + + sprintf(name, "miXart analog %d", chip->chip_idx); + if ((err = snd_pcm_new(chip->card, name, MIXART_PCM_ANALOG, + MIXART_PLAYBACK_STREAMS, + MIXART_CAPTURE_STREAMS, &pcm)) < 0) { + snd_printk(KERN_ERR "cannot create the analog pcm %d\n", chip->chip_idx); + return err; + } + + pcm->private_data = chip; + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_mixart_playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops); + + pcm->info_flags = SNDRV_PCM_INFO_NONATOMIC_OPS; + strcpy(pcm->name, name); + + preallocate_buffers(chip, pcm); + + chip->pcm = pcm; + return 0; +} + + +/* + */ +static int snd_mixart_pcm_digital(mixart_t *chip) +{ + int err; + snd_pcm_t *pcm; + char name[32]; + + sprintf(name, "miXart AES/EBU %d", chip->chip_idx); + if ((err = snd_pcm_new(chip->card, name, MIXART_PCM_DIGITAL, + MIXART_PLAYBACK_STREAMS, + MIXART_CAPTURE_STREAMS, &pcm)) < 0) { + snd_printk(KERN_ERR "cannot create the digital pcm %d\n", chip->chip_idx); + return err; + } + + pcm->private_data = chip; + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_mixart_playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops); + + pcm->info_flags = SNDRV_PCM_INFO_NONATOMIC_OPS; + strcpy(pcm->name, name); + + preallocate_buffers(chip, pcm); + + chip->pcm_dig = pcm; + return 0; +} + +static int snd_mixart_chip_free(mixart_t *chip) +{ + snd_magic_kfree(chip); + return 0; +} + +static int snd_mixart_chip_dev_free(snd_device_t *device) +{ + mixart_t *chip = snd_magic_cast(mixart_t, device->device_data, return -ENXIO); + return snd_mixart_chip_free(chip); +} + + +/* + */ +static int __devinit snd_mixart_create(mixart_mgr_t *mgr, snd_card_t *card, int idx) +{ + int err; + mixart_t *chip; + static snd_device_ops_t ops = { + .dev_free = snd_mixart_chip_dev_free, + }; + + mgr->chip[idx] = chip = snd_magic_kcalloc(mixart_t, 0, GFP_KERNEL); + if (! chip) { + snd_printk(KERN_ERR "cannot allocate chip\n"); + return -ENOMEM; + } + + chip->card = card; + chip->chip_idx = idx; + chip->mgr = mgr; + + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + snd_mixart_chip_free(chip); + return err; + } + + if (idx == 0) { + /* create a DSP loader only on first cardX*/ + err = snd_mixart_hwdep_new(mgr); + if (err < 0) + return err; + } + + snd_card_set_dev(card, &mgr->pci->dev); + + return 0; +} + +int snd_mixart_create_pcm(mixart_t* chip) +{ + int err; + + err = snd_mixart_pcm_analog(chip); + if (err < 0) + return err; + + if(chip->mgr->board_type == MIXART_DAUGHTER_TYPE_AES) { + + err = snd_mixart_pcm_digital(chip); + if (err < 0) + return err; + } + return err; +} + + +/* + * release all the cards assigned to a manager instance + */ +static int snd_mixart_free(mixart_mgr_t *mgr) +{ + unsigned int i; + + for (i = 0; i < mgr->num_cards; i++) { + if (mgr->chip[i]) + snd_card_free(mgr->chip[i]->card); + } + + /* stop mailbox */ + snd_mixart_exit_mailbox(mgr); + + /* release irq */ + if (mgr->irq >= 0) + free_irq(mgr->irq, (void *)mgr); + + /* reset board if some firmware was loaded */ + if(mgr->hwdep->dsp_loaded) { + snd_mixart_reset_board(mgr); + snd_printdd("reset miXart !\n"); + } + + /* release the i/o ports */ + for (i = 0; i < 2; i++) { + if (mgr->mem[i].virt) + iounmap((void *)mgr->mem[i].virt); + if (mgr->mem[i].res) { + release_resource(mgr->mem[i].res); + kfree_nocheck(mgr->mem[i].res); + } + } + + /* free flowarray */ + if(mgr->flowinfo.area) { + snd_dma_free_pages(&mgr->dma_dev, &mgr->flowinfo); + mgr->flowinfo.area = NULL; + } + /* free bufferarray */ + if(mgr->bufferinfo.area) { + snd_dma_free_pages(&mgr->dma_dev, &mgr->bufferinfo); + mgr->bufferinfo.area = NULL; + } + + snd_magic_kfree(mgr); + return 0; +} + +/* + * proc interface + */ +static long long snd_mixart_BA0_llseek(snd_info_entry_t *entry, + void *private_file_data, + struct file *file, + long long offset, + int orig) +{ + offset = offset & ~3; /* 4 bytes aligned */ + + switch(orig) { + case 0: /* SEEK_SET */ + file->f_pos = offset; + break; + case 1: /* SEEK_CUR */ + file->f_pos += offset; + break; + case 2: /* SEEK_END, offset is negative */ + file->f_pos = MIXART_BA0_SIZE + offset; + break; + default: + return -EINVAL; + } + if(file->f_pos > MIXART_BA0_SIZE) + file->f_pos = MIXART_BA0_SIZE; + return file->f_pos; +} + +static long long snd_mixart_BA1_llseek(snd_info_entry_t *entry, + void *private_file_data, + struct file *file, + long long offset, + int orig) +{ + offset = offset & ~3; /* 4 bytes aligned */ + + switch(orig) { + case 0: /* SEEK_SET */ + file->f_pos = offset; + break; + case 1: /* SEEK_CUR */ + file->f_pos += offset; + break; + case 2: /* SEEK_END, offset is negative */ + file->f_pos = MIXART_BA1_SIZE + offset; + break; + default: + return -EINVAL; + } + if(file->f_pos > MIXART_BA1_SIZE) + file->f_pos = MIXART_BA1_SIZE; + return file->f_pos; +} + +/* + mixart_BA0 proc interface for BAR 0 - read callback + */ +static long snd_mixart_BA0_read(snd_info_entry_t *entry, void *file_private_data, + struct file *file, char *buf, long count) +{ + mixart_mgr_t *mgr = snd_magic_cast(mixart_mgr_t, entry->private_data, return -ENXIO); + + count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ + if(count <= 0) + return 0; + if(file->f_pos + count > MIXART_BA0_SIZE) + count = (long)(MIXART_BA0_SIZE - file->f_pos); + if(copy_to_user_fromio(buf, MIXART_MEM( mgr, file->f_pos ), count)) + return -EFAULT; + file->f_pos += count; + return count; +} + +/* + mixart_BA1 proc interface for BAR 1 - read callback + */ +static long snd_mixart_BA1_read(snd_info_entry_t *entry, void *file_private_data, + struct file *file, char *buf, long count) +{ + mixart_mgr_t *mgr = snd_magic_cast(mixart_mgr_t, entry->private_data, return -ENXIO); + + count = count & ~3; /* make sure the read size is a multiple of 4 bytes */ + if(count <= 0) + return 0; + if(file->f_pos + count > MIXART_BA1_SIZE) + count = (long)(MIXART_BA1_SIZE - file->f_pos); + if(copy_to_user_fromio(buf, MIXART_REG( mgr, file->f_pos ), count)) + return -EFAULT; + file->f_pos += count; + return count; +} + +static struct snd_info_entry_ops snd_mixart_proc_ops_BA0 = { + .read = snd_mixart_BA0_read, + .llseek = snd_mixart_BA0_llseek +}; + +static struct snd_info_entry_ops snd_mixart_proc_ops_BA1 = { + .read = snd_mixart_BA1_read, + .llseek = snd_mixart_BA1_llseek +}; + + +static void snd_mixart_proc_read(snd_info_entry_t *entry, + snd_info_buffer_t * buffer) +{ + mixart_t *chip = snd_magic_cast(mixart_t, entry->private_data, return); + u32 ref; + + snd_iprintf(buffer, "Digigram miXart (alsa card %d)\n\n", chip->chip_idx); + + /* stats available when embedded OS is running */ + if (chip->mgr->hwdep->dsp_loaded & ( 1 << MIXART_MOTHERBOARD_ELF_INDEX)) { + snd_iprintf(buffer, "- hardware -\n"); + switch (chip->mgr->board_type ) { + case MIXART_DAUGHTER_TYPE_NONE : snd_iprintf(buffer, "\tmiXart8 (no daughter board)\n\n"); break; + case MIXART_DAUGHTER_TYPE_AES : snd_iprintf(buffer, "\tmiXart8 AES/EBU\n\n"); break; + case MIXART_DAUGHTER_TYPE_COBRANET : snd_iprintf(buffer, "\tmiXart8 Cobranet\n\n"); break; + default: snd_iprintf(buffer, "\tUNKNOWN!\n\n"); break; + } + + snd_iprintf(buffer, "- system load -\n"); + + /* get perf reference */ + + ref = readl_be( MIXART_MEM( chip->mgr, MIXART_PSEUDOREG_PERF_SYSTEM_LOAD_OFFSET)); + + if (ref) { + u32 mailbox = 100 * readl_be( MIXART_MEM( chip->mgr, MIXART_PSEUDOREG_PERF_MAILBX_LOAD_OFFSET)) / ref; + u32 streaming = 100 * readl_be( MIXART_MEM( chip->mgr, MIXART_PSEUDOREG_PERF_STREAM_LOAD_OFFSET)) / ref; + u32 interr = 100 * readl_be( MIXART_MEM( chip->mgr, MIXART_PSEUDOREG_PERF_INTERR_LOAD_OFFSET)) / ref; + + snd_iprintf(buffer, "\tstreaming : %d\n", streaming); + snd_iprintf(buffer, "\tmailbox : %d\n", mailbox); + snd_iprintf(buffer, "\tinterrups handling : %d\n\n", interr); + } + } /* endif elf loaded */ +} + +static void __devinit snd_mixart_proc_init(mixart_t *chip) +{ + snd_info_entry_t *entry; + + /* text interface to read perf and temp meters */ + if (! snd_card_proc_new(chip->card, "board_info", &entry)) { + entry->private_data = chip; + entry->c.text.read_size = 1024; + entry->c.text.read = snd_mixart_proc_read; + } + + if (! snd_card_proc_new(chip->card, "mixart_BA0", &entry)) { + entry->content = SNDRV_INFO_CONTENT_DATA; + entry->private_data = chip->mgr; + entry->c.ops = &snd_mixart_proc_ops_BA0; + entry->size = MIXART_BA0_SIZE; + } + if (! snd_card_proc_new(chip->card, "mixart_BA1", &entry)) { + entry->content = SNDRV_INFO_CONTENT_DATA; + entry->private_data = chip->mgr; + entry->c.ops = &snd_mixart_proc_ops_BA1; + entry->size = MIXART_BA1_SIZE; + } +} +/* end of proc interface */ + + +/* + * probe function - creates the card manager + */ +static int __devinit snd_mixart_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) +{ + static int dev; + mixart_mgr_t *mgr; + unsigned int i; + int err; + size_t size; + + /* + */ + if (dev >= SNDRV_CARDS) + return -ENODEV; + if (! enable[dev]) { + dev++; + return -ENOENT; + } + + /* enable PCI device */ + if ((err = pci_enable_device(pci)) < 0) + return err; + pci_set_master(pci); + + /* check if we can restrict PCI DMA transfers to 32 bits */ + if (!pci_dma_supported(pci, 0xffffffff)) { + snd_printk(KERN_ERR "architecture does not support 32bit PCI busmaster DMA\n"); + return -ENXIO; + } + pci_set_dma_mask(pci, 0xffffffff); + + /* + */ + mgr = snd_magic_kcalloc(mixart_mgr_t, 0, GFP_KERNEL); + if (! mgr) + return -ENOMEM; + + mgr->pci = pci; + mgr->irq = -1; + + /* resource assignment */ + for (i = 0; i < 2; i++) { + static int memory_sizes[2] = { + MIXART_BA0_SIZE, /* 16M */ + MIXART_BA1_SIZE /* 4 k */ + }; + mgr->mem[i].phys = pci_resource_start(pci, i); + mgr->mem[i].res = request_mem_region(mgr->mem[i].phys, memory_sizes[i], CARD_NAME); + if (! mgr->mem[i].res) { + snd_printk(KERN_ERR "unable to grab memory 0x%lx\n", mgr->mem[i].phys); + snd_mixart_free(mgr); + return -EBUSY; + } + mgr->mem[i].virt = (unsigned long)ioremap_nocache(mgr->mem[i].phys, memory_sizes[i]); + } + + if (request_irq(pci->irq, snd_mixart_interrupt, SA_INTERRUPT|SA_SHIRQ, CARD_NAME, (void *)mgr)) { + snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + snd_mixart_free(mgr); + return -EBUSY; + } + mgr->irq = pci->irq; + + sprintf(mgr->shortname, "Digigram miXart"); + sprintf(mgr->longname, "%s at 0x%lx & 0x%lx, irq %i", mgr->shortname, mgr->mem[0].phys, mgr->mem[1].phys, mgr->irq); + + /* ISR spinlock */ + mgr->lock = SPIN_LOCK_UNLOCKED; + + /* init mailbox */ + mgr->msg_fifo_readptr = 0; + mgr->msg_fifo_writeptr = 0; + + mgr->msg_lock = SPIN_LOCK_UNLOCKED; + init_MUTEX(&mgr->msg_mutex); + init_waitqueue_head(&mgr->msg_sleep); + atomic_set(&mgr->msg_processed, 0); + + /* init setup mutex*/ + init_MUTEX(&mgr->setup_mutex); + + /* init message taslket */ + tasklet_init( &mgr->msg_taskq, snd_mixart_msg_tasklet, (unsigned long) mgr); + + /* card assignment */ + mgr->num_cards = MIXART_MAX_CARDS; /* 4 FIXME: configurable? */ + for (i = 0; i < mgr->num_cards; i++) { + snd_card_t *card; + char tmpid[16]; + int idx; + + if (index[dev] < 0) + idx = index[dev]; + else + idx = index[dev] + i; + snprintf(tmpid, sizeof(tmpid), "%s-%d", id[dev], i); + card = snd_card_new(idx, tmpid, THIS_MODULE, 0); + + if (! card) { + snd_printk(KERN_ERR "cannot allocate the card %d\n", i); + snd_mixart_free(mgr); + return -ENOMEM; + } + + strcpy(card->driver, CARD_NAME); + sprintf(card->shortname, "%s [PCM #%d]", mgr->shortname, i); + sprintf(card->longname, "%s [PCM #%d]", mgr->longname, i); + + if ((err = snd_mixart_create(mgr, card, i)) < 0) { + snd_mixart_free(mgr); + return err; + } + + if(i==0) { + /* init proc interface only for chip0 */ + snd_mixart_proc_init(mgr->chip[i]); + } + + if ((err = snd_card_register(card)) < 0) { + snd_mixart_free(mgr); + return err; + } + } + + /* init firmware status (mgr->hwdep->dsp_loaded reset in hwdep_new) */ + mgr->board_type = MIXART_DAUGHTER_TYPE_NONE; + + memset(&mgr->dma_dev, 0, sizeof(mgr->dma_dev)); + mgr->dma_dev.type = SNDRV_DMA_TYPE_DEV; + mgr->dma_dev.dev = snd_dma_pci_data(mgr->pci); + + /* create array of streaminfo */ + size = PAGE_ALIGN( (MIXART_MAX_STREAM_PER_CARD * MIXART_MAX_CARDS * sizeof(mixart_flowinfo_t)) ); + if (snd_dma_alloc_pages(&mgr->dma_dev, size, &mgr->flowinfo) < 0) { + snd_mixart_free(mgr); + return -ENOMEM; + } + /* init streaminfo_array */ + memset(mgr->flowinfo.area, 0, size); + + /* create array of bufferinfo */ + size = PAGE_ALIGN( (MIXART_MAX_STREAM_PER_CARD * MIXART_MAX_CARDS * sizeof(mixart_bufferinfo_t)) ); + if (snd_dma_alloc_pages(&mgr->dma_dev, size, &mgr->bufferinfo) < 0) { + snd_mixart_free(mgr); + return -ENOMEM; + } + /* init bufferinfo_array */ + memset(mgr->bufferinfo.area, 0, size); + + pci_set_drvdata(pci, mgr); + dev++; + return 0; +} + +static void __devexit snd_mixart_remove(struct pci_dev *pci) +{ + snd_mixart_free(pci_get_drvdata(pci)); + pci_set_drvdata(pci, NULL); +} + +static struct pci_driver driver = { + .name = "Digigram miXart", + .id_table = snd_mixart_ids, + .probe = snd_mixart_probe, + .remove = __devexit_p(snd_mixart_remove), +}; + +static int __init alsa_card_mixart_init(void) +{ + int err; + + if ((err = pci_module_init(&driver)) < 0) { +#ifdef MODULE + snd_printk(KERN_ERR "Digigram miXart soundcard not found or device busy\n"); +#endif + return err; + } + return 0; +} + +static void __exit alsa_card_mixart_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_mixart_init) +module_exit(alsa_card_mixart_exit) + +#ifndef MODULE + +/* format is: snd-mixart=enable,index,id */ + +static int __init alsa_card_mixart_setup(char *str) +{ + static unsigned __initdata nr_dev = 0; + + if (nr_dev >= SNDRV_CARDS) + return 0; + (void)(get_option(&str,&enable[nr_dev]) == 2 && + get_option(&str,&index[nr_dev]) == 2 && + get_id(&str,&id[nr_dev]) == 2); + nr_dev++; + return 1; +} + +__setup("snd-mixart=", alsa_card_mixart_setup); + +#endif /* ifndef MODULE */ diff -Nru a/sound/pci/mixart/mixart.h b/sound/pci/mixart/mixart.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/mixart/mixart.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,242 @@ +/* + * Driver for Digigram miXart soundcards + * + * main header file + * + * Copyright (c) 2003 by Digigram + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __SOUND_MIXART_H +#define __SOUND_MIXART_H + +#include + +#define MIXART_DRIVER_VERSION 0x000100 /* 0.1.0 */ + + +/* + */ + +#define mixart_t_magic 0xa17a3e01 +#define mixart_mgr_t_magic 0xa17a3e02 + +typedef struct snd_mixart mixart_t; +typedef struct snd_mixart_mgr mixart_mgr_t; + +typedef struct snd_mixart_stream mixart_stream_t; +typedef struct snd_mixart_pipe mixart_pipe_t; + +typedef struct mixart_bufferinfo mixart_bufferinfo_t; +typedef struct mixart_flowinfo mixart_flowinfo_t; +typedef struct mixart_uid mixart_uid_t; + +struct mixart_uid +{ + u32 object_id; + u32 desc; +}; + +struct mem_area { + unsigned long phys; + unsigned long virt; + struct resource *res; +}; + + +typedef struct mixart_route mixart_route_t; +struct mixart_route { + unsigned char connected; + unsigned char phase_inv; + int volume; +}; + + +/* firmware status codes */ +#define MIXART_MOTHERBOARD_XLX_INDEX 0 +#define MIXART_MOTHERBOARD_ELF_INDEX 1 +#define MIXART_AESEBUBOARD_XLX_INDEX 2 +#define MIXART_HARDW_FILES_MAX_INDEX 3 /* xilinx, elf, AESEBU xilinx */ + +#define MIXART_MAX_CARDS 4 +#define MSG_FIFO_SIZE 16 + +#define MIXART_MAX_PHYS_CONNECTORS (MIXART_MAX_CARDS * 2 * 2) /* 4 * stereo * (analog+digital) */ + +struct snd_mixart_mgr { + unsigned int num_cards; + mixart_t *chip[MIXART_MAX_CARDS]; + + struct pci_dev *pci; + + int irq; + + /* memory-maps */ + struct mem_area mem[2]; + + /* share the name */ + char shortname[32]; /* short name of this soundcard */ + char longname[80]; /* name of this soundcard */ + + /* message tasklet */ + struct tasklet_struct msg_taskq; + + /* one and only blocking message or notification may be pending */ + u32 pending_event; + wait_queue_head_t msg_sleep; + + /* messages stored for tasklet */ + u32 msg_fifo[MSG_FIFO_SIZE]; + int msg_fifo_readptr; + int msg_fifo_writeptr; + atomic_t msg_processed; /* number of messages to be processed in takslet */ + + spinlock_t lock; /* interrupt spinlock */ + spinlock_t msg_lock; /* mailbox spinlock */ + struct semaphore msg_mutex; /* mutex for blocking_requests */ + + struct semaphore setup_mutex; /* mutex used in hw_params, open and close */ + + /* hardware interface */ + snd_hwdep_t *hwdep; + unsigned int board_type; /* read from embedded once elf file is loaded, 250 = miXart8, 251 = with AES, 252 = with Cobranet */ + + struct snd_dma_device dma_dev; + struct snd_dma_buffer flowinfo; + struct snd_dma_buffer bufferinfo; + + mixart_uid_t uid_console_manager; + int sample_rate; + int ref_count_rate; + + struct semaphore mixer_mutex; /* mutex for mixer */ + +}; + + +#define MIXART_STREAM_STATUS_FREE 0 +#define MIXART_STREAM_STATUS_OPEN 1 +#define MIXART_STREAM_STATUS_RUNNING 2 +#define MIXART_STREAM_STATUS_DRAINING 3 +#define MIXART_STREAM_STATUS_PAUSE 4 + +#define MIXART_PLAYBACK_STREAMS 4 +#define MIXART_CAPTURE_STREAMS 1 + +#define MIXART_PCM_ANALOG 0 +#define MIXART_PCM_DIGITAL 1 +#define MIXART_PCM_TOTAL 2 + +#define MIXART_MAX_STREAM_PER_CARD (MIXART_PCM_TOTAL * (MIXART_PLAYBACK_STREAMS + MIXART_CAPTURE_STREAMS) ) + + +#define MIXART_NOTIFY_CARD_MASK 0xF000 +#define MIXART_NOTIFY_CARD_OFFSET 12 +#define MIXART_NOTIFY_PCM_MASK 0x0F00 +#define MIXART_NOTIFY_PCM_OFFSET 8 +#define MIXART_NOTIFY_CAPT_MASK 0x0080 +#define MIXART_NOTIFY_SUBS_MASK 0x007F + + +struct snd_mixart_stream { + snd_pcm_substream_t *substream; + mixart_pipe_t *pipe; + int pcm_number; + + int status; /* nothing, running, draining */ + + u64 abs_period_elapsed; /* last absolute stream position where period_elapsed was called (multiple of runtime->period_size) */ + u32 buf_periods; /* periods counter in the buffer (< runtime->periods) */ + u32 buf_period_frag; /* defines with buf_period_pos the exact position in the buffer (< runtime->period_size) */ + + int channels; +}; + + +enum mixart_pipe_status { + PIPE_UNDEFINED, + PIPE_STOPPED, + PIPE_RUNNING, + PIPE_CLOCK_SET +}; + +struct snd_mixart_pipe { + mixart_uid_t group_uid; /* id of the pipe, as returned by embedded */ + int stream_count; + mixart_uid_t uid_left_connector; /* UID's for the audio connectors */ + mixart_uid_t uid_right_connector; + enum mixart_pipe_status status; + int references; /* number of subs openned */ + int monitoring; /* pipe used for monitoring issue */ +}; + + +struct snd_mixart { + snd_card_t *card; + mixart_mgr_t *mgr; + int chip_idx; /* zero based */ + snd_hwdep_t *hwdep; /* DSP loader, only for the first card */ + + snd_pcm_t *pcm; /* PCM analog i/o */ + snd_pcm_t *pcm_dig; /* PCM digital i/o */ + + /* allocate stereo pipe for instance */ + mixart_pipe_t pipe_in_ana; + mixart_pipe_t pipe_out_ana; + + /* if AES/EBU daughter board is available, additional pipes possible on pcm_dig */ + mixart_pipe_t pipe_in_dig; + mixart_pipe_t pipe_out_dig; + + mixart_stream_t playback_stream[MIXART_PCM_TOTAL][MIXART_PLAYBACK_STREAMS]; /* 0 = pcm, 1 = pcm_dig */ + mixart_stream_t capture_stream[MIXART_PCM_TOTAL]; /* 0 = pcm, 1 = pcm_dig */ + + /* UID's for the physical io's */ + mixart_uid_t uid_out_analog_physio; + mixart_uid_t uid_in_analog_physio; + + int analog_playback_active[2]; /* Mixer : Master Playback active (!mute) */ + int analog_playback_volume[2]; /* Mixer : Master Playback Volume */ + int analog_capture_volume[2]; /* Mixer : Master Capture Volume */ + int digital_playback_active[2*MIXART_PLAYBACK_STREAMS][2]; /* Mixer : Digital Playback Active [(analog+AES output)*streams][stereo]*/ + int digital_playback_volume[2*MIXART_PLAYBACK_STREAMS][2]; /* Mixer : Digital Playback Volume [(analog+AES output)*streams][stereo]*/ + int digital_capture_volume[2][2]; /* Mixer : Digital Capture Volume [analog+AES output][stereo] */ + int monitoring_active[2]; /* Mixer : Monitoring Active */ + int monitoring_volume[2]; /* Mixer : Monitoring Volume */ +}; + +struct mixart_bufferinfo +{ + u32 buffer_address; + u32 reserved[5]; + u32 available_length; + u32 buffer_id; +}; + +struct mixart_flowinfo +{ + u32 bufferinfo_array_phy_address; + u32 reserved[11]; + u32 bufferinfo_count; + u32 capture; +}; + +/* exported */ +int snd_mixart_create_pcm(mixart_t* chip); +mixart_pipe_t* snd_mixart_add_ref_pipe( mixart_t *chip, int pcm_number, int capture, int monitoring); +int snd_mixart_kill_ref_pipe( mixart_mgr_t *mgr, mixart_pipe_t *pipe, int monitoring); + +#endif /* __SOUND_MIXART_H */ diff -Nru a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/mixart/mixart_core.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,585 @@ +/* + * Driver for Digigram miXart soundcards + * + * low level interface with interrupt handling and mail box implementation + * + * Copyright (c) 2003 by Digigram + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include "mixart.h" +#include "mixart_hwdep.h" +#include "mixart_core.h" + + +#define MSG_TIMEOUT_JIFFIES (400 * HZ) / 1000 /* 400 ms */ + +#define MSG_DESCRIPTOR_SIZE 0x24 +#define MSG_HEADER_SIZE (MSG_DESCRIPTOR_SIZE + 4) + +#define MSG_DEFAULT_SIZE 512 + +#define MSG_TYPE_MASK 0x00000003 /* mask for following types */ +#define MSG_TYPE_NOTIFY 0 /* embedded -> driver (only notification, do not get_msg() !) */ +#define MSG_TYPE_COMMAND 1 /* driver <-> embedded (a command has no answer) */ +#define MSG_TYPE_REQUEST 2 /* driver -> embedded (request will get an answer back) */ +#define MSG_TYPE_ANSWER 3 /* embedded -> driver */ +#define MSG_CANCEL_NOTIFY_MASK 0x80000000 /* this bit is set for a notification that has been canceled */ + + +static int retrieve_msg_frame(mixart_mgr_t *mgr, u32 *msg_frame) +{ + /* read the message frame fifo */ + u32 headptr, tailptr; + + tailptr = readl_be(MIXART_MEM(mgr, MSG_OUTBOUND_POST_TAIL)); + headptr = readl_be(MIXART_MEM(mgr, MSG_OUTBOUND_POST_HEAD)); + + if (tailptr == headptr) + return 0; /* no message posted */ + + snd_assert( tailptr >= MSG_OUTBOUND_POST_STACK, return 0); /* error */ + snd_assert( tailptr < (MSG_OUTBOUND_POST_STACK+MSG_BOUND_STACK_SIZE), return 0); /* error */ + + *msg_frame = readl_be(MIXART_MEM(mgr, tailptr)); + + /* increment the tail index */ + tailptr += 4; + if( tailptr >= (MSG_OUTBOUND_POST_STACK+MSG_BOUND_STACK_SIZE) ) + tailptr = MSG_OUTBOUND_POST_STACK; + writel_be(tailptr, MIXART_MEM(mgr, MSG_OUTBOUND_POST_TAIL)); + + return 1; +} + +static int get_msg(mixart_mgr_t *mgr, mixart_msg_t *resp, u32 msg_frame_address ) +{ + unsigned long flags; + u32 headptr, i; + u32 size; + int err; + + spin_lock_irqsave(&mgr->msg_lock, flags); + err = 0; + + /* copy message descriptor from miXart to driver */ + size = readl_be(MIXART_MEM(mgr, msg_frame_address)); /* size of descriptor + response */ + resp->message_id = readl_be(MIXART_MEM(mgr, msg_frame_address + 4)); /* dwMessageID */ + resp->uid.object_id = readl_be(MIXART_MEM(mgr, msg_frame_address + 8)); /* uidDest */ + resp->uid.desc = readl_be(MIXART_MEM(mgr, msg_frame_address + 12)); /* */ + + if( (size < MSG_DESCRIPTOR_SIZE) || (resp->size < (size - MSG_DESCRIPTOR_SIZE))) { + err = -EINVAL; + snd_printk(KERN_ERR "problem with response size = %d\n", size); + goto _clean_exit; + } + size -= MSG_DESCRIPTOR_SIZE; + + memcpy_fromio(resp->data, (void *)MIXART_MEM(mgr, msg_frame_address + MSG_HEADER_SIZE ), size); + resp->size = size; + + /* swap if necessary */ +#ifndef __BIG_ENDIAN + size /= 4; /* u32 size */ + for(i=0; i < size; i++) { + ((u32*)resp->data)[i] = be32_to_cpu(((u32*)resp->data)[i]); + } +#endif + + /* + * free message frame address + */ + headptr = readl_be(MIXART_MEM(mgr, MSG_OUTBOUND_FREE_HEAD)); + + if( (headptr < MSG_OUTBOUND_FREE_STACK) || ( headptr >= (MSG_OUTBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE))) { + err = -EINVAL; + goto _clean_exit; + } + + /* give address back to outbound fifo */ + writel_be(msg_frame_address, MIXART_MEM(mgr, headptr)); + + /* increment the outbound free head */ + headptr += 4; + if( headptr >= (MSG_OUTBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE) ) + headptr = MSG_OUTBOUND_FREE_STACK; + + writel_be(headptr, MIXART_MEM(mgr, MSG_OUTBOUND_FREE_HEAD)); + + _clean_exit: + spin_unlock_irqrestore(&mgr->msg_lock, flags); + + return err; +} + + +/* + * send a message to miXart. return: the msg_frame used for this message + */ +/* call with mgr->msg_lock held! */ +static int send_msg( mixart_mgr_t *mgr, + mixart_msg_t *msg, + int max_answersize, + int mark_pending, + u32 *msg_event) +{ + u32 headptr, tailptr; + u32 msg_frame_address; + int err, i; + + snd_assert(msg->size % 4 == 0, return -EINVAL); + + err = 0; + + /* get message frame address */ + tailptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_FREE_TAIL)); + headptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_FREE_HEAD)); + + if (tailptr == headptr) { + snd_printk(KERN_ERR "error: no message frame available\n"); + return -EBUSY; + } + + if( (tailptr < MSG_INBOUND_FREE_STACK) || (tailptr >= (MSG_INBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE))) { + return -EINVAL; + } + + msg_frame_address = readl_be(MIXART_MEM(mgr, tailptr)); + writel(0, MIXART_MEM(mgr, tailptr)); /* set address to zero on this fifo position */ + + /* increment the inbound free tail */ + tailptr += 4; + if( tailptr >= (MSG_INBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE) ) + tailptr = MSG_INBOUND_FREE_STACK; + + writel_be(tailptr, MIXART_MEM(mgr, MSG_INBOUND_FREE_TAIL)); + + /* TODO : use memcpy_toio() with intermediate buffer to copy the message */ + + /* copy message descriptor to card memory */ + writel_be( msg->size + MSG_DESCRIPTOR_SIZE, MIXART_MEM(mgr, msg_frame_address) ); /* size of descriptor + request */ + writel_be( msg->message_id , MIXART_MEM(mgr, msg_frame_address + 4) ); /* dwMessageID */ + writel_be( msg->uid.object_id, MIXART_MEM(mgr, msg_frame_address + 8) ); /* uidDest */ + writel_be( msg->uid.desc, MIXART_MEM(mgr, msg_frame_address + 12) ); /* */ + writel_be( MSG_DESCRIPTOR_SIZE, MIXART_MEM(mgr, msg_frame_address + 16) ); /* SizeHeader */ + writel_be( MSG_DESCRIPTOR_SIZE, MIXART_MEM(mgr, msg_frame_address + 20) ); /* OffsetDLL_T16 */ + writel_be( msg->size, MIXART_MEM(mgr, msg_frame_address + 24) ); /* SizeDLL_T16 */ + writel_be( MSG_DESCRIPTOR_SIZE, MIXART_MEM(mgr, msg_frame_address + 28) ); /* OffsetDLL_DRV */ + writel_be( 0, MIXART_MEM(mgr, msg_frame_address + 32) ); /* SizeDLL_DRV */ + writel_be( MSG_DESCRIPTOR_SIZE + max_answersize, MIXART_MEM(mgr, msg_frame_address + 36) ); /* dwExpectedAnswerSize */ + + /* copy message data to card memory */ + for( i=0; i < msg->size; i+=4 ) { + writel_be( *(u32*)(msg->data + i), MIXART_MEM(mgr, MSG_HEADER_SIZE + msg_frame_address + i) ); + } + + if( mark_pending ) { + if( *msg_event ) { + /* the pending event is the notification we wait for ! */ + mgr->pending_event = *msg_event; + } + else { + /* the pending event is the answer we wait for (same address than the request)! */ + mgr->pending_event = msg_frame_address; + + /* copy address back to caller */ + *msg_event = msg_frame_address; + } + } + + /* mark the frame as a request (will have an answer) */ + msg_frame_address |= MSG_TYPE_REQUEST; + + /* post the frame */ + headptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_POST_HEAD)); + + if( (headptr < MSG_INBOUND_POST_STACK) || (headptr >= (MSG_INBOUND_POST_STACK+MSG_BOUND_STACK_SIZE))) { + return -EINVAL; + } + + writel_be(msg_frame_address, MIXART_MEM(mgr, headptr)); + + /* increment the inbound post head */ + headptr += 4; + if( headptr >= (MSG_INBOUND_POST_STACK+MSG_BOUND_STACK_SIZE) ) + headptr = MSG_INBOUND_POST_STACK; + + writel_be(headptr, MIXART_MEM(mgr, MSG_INBOUND_POST_HEAD)); + + return 0; +} + + +int snd_mixart_send_msg(mixart_mgr_t *mgr, mixart_msg_t *request, int max_resp_size, void *resp_data) +{ + mixart_msg_t resp; + u32 msg_frame = 0; /* set to 0, so it's no notification to wait for, but the answer */ + int err; + wait_queue_t wait; + long timeout; + + down(&mgr->msg_mutex); + + init_waitqueue_entry(&wait, current); + + spin_lock_irq(&mgr->msg_lock); + /* send the message */ + err = send_msg(mgr, request, max_resp_size, 1, &msg_frame); /* send and mark the answer pending */ + if (err) { + spin_unlock_irq(&mgr->msg_lock); + up(&mgr->msg_mutex); + return err; + } + + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&mgr->msg_sleep, &wait); + spin_unlock_irq(&mgr->msg_lock); + timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES); + remove_wait_queue(&mgr->msg_sleep, &wait); + + if (! timeout) { + /* error - no ack */ + up(&mgr->msg_mutex); + snd_printk(KERN_ERR "error: no reponse on msg %x\n", msg_frame); + return -EIO; + } + + /* retrieve the answer into the same mixart_msg_t */ + resp.message_id = 0; + resp.uid = (mixart_uid_t){0,0}; + resp.data = resp_data; + resp.size = max_resp_size; + + err = get_msg(mgr, &resp, msg_frame); + + if( request->message_id != resp.message_id ) + snd_printk(KERN_ERR "REPONSE ERROR!\n"); + + up(&mgr->msg_mutex); + return err; +} + + +int snd_mixart_send_msg_wait_notif(mixart_mgr_t *mgr, mixart_msg_t *request, u32 notif_event) +{ + int err; + wait_queue_t wait; + long timeout; + + snd_assert(notif_event != 0, return -EINVAL); + snd_assert((notif_event & MSG_TYPE_MASK) == MSG_TYPE_NOTIFY, return -EINVAL); + snd_assert((notif_event & MSG_CANCEL_NOTIFY_MASK) == 0, return -EINVAL); + + down(&mgr->msg_mutex); + + init_waitqueue_entry(&wait, current); + + spin_lock_irq(&mgr->msg_lock); + /* send the message */ + err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 1, ¬if_event); /* send and mark the notification event pending */ + if(err) { + spin_unlock_irq(&mgr->msg_lock); + up(&mgr->msg_mutex); + return err; + } + + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&mgr->msg_sleep, &wait); + spin_unlock_irq(&mgr->msg_lock); + timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES); + remove_wait_queue(&mgr->msg_sleep, &wait); + + if (! timeout) { + /* error - no ack */ + up(&mgr->msg_mutex); + snd_printk(KERN_ERR "error: notification %x not received\n", notif_event); + return -EIO; + } + + up(&mgr->msg_mutex); + return 0; +} + + +int snd_mixart_send_msg_nonblock(mixart_mgr_t *mgr, mixart_msg_t *request) +{ + u32 message_frame; + unsigned long flags; + int err; + + /* just send the message (do not mark it as a pending one) */ + spin_lock_irqsave(&mgr->msg_lock, flags); + err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 0, &message_frame); + spin_unlock_irqrestore(&mgr->msg_lock, flags); + + /* the answer will be handled by snd_mixart_msg_tasklet() */ + atomic_inc(&mgr->msg_processed); + + return err; +} + + +/* common buffer of tasklet and interrupt to send/receive messages */ +static u32 mixart_msg_data[MSG_DEFAULT_SIZE / 4]; + + +void snd_mixart_msg_tasklet( unsigned long arg) +{ + mixart_mgr_t *mgr = ( mixart_mgr_t*)(arg); + mixart_msg_t resp; + u32 msg, addr, type; + int err; + + spin_lock(&mgr->lock); + + while (mgr->msg_fifo_readptr != mgr->msg_fifo_writeptr) { + msg = mgr->msg_fifo[mgr->msg_fifo_readptr]; + mgr->msg_fifo_readptr++; + mgr->msg_fifo_readptr %= MSG_FIFO_SIZE; + + /* process the message ... */ + addr = msg & ~MSG_TYPE_MASK; + type = msg & MSG_TYPE_MASK; + + switch (type) { + case MSG_TYPE_ANSWER: + /* answer to a message on that we did not wait for (send_msg_nonblock) */ + resp.message_id = 0; + resp.data = mixart_msg_data; + resp.size = sizeof(mixart_msg_data); + err = get_msg(mgr, &resp, addr); + if( err < 0 ) { + snd_printk(KERN_ERR "tasklet: error(%d) reading mf %x\n", err, msg); + break; + } + + switch(resp.message_id) { + case MSG_STREAM_START_INPUT_STAGE_PACKET: + case MSG_STREAM_START_OUTPUT_STAGE_PACKET: + case MSG_STREAM_STOP_INPUT_STAGE_PACKET: + case MSG_STREAM_STOP_OUTPUT_STAGE_PACKET: + if(mixart_msg_data[0]) + snd_printk(KERN_ERR "tasklet : error MSG_STREAM_ST***_***PUT_STAGE_PACKET status=%x\n", mixart_msg_data[0]); + break; + default: + snd_printdd("tasklet received mf(%x) : msg_id(%x) uid(%x, %x) size(%d)\n", + msg, resp.message_id, resp.uid.object_id, resp.uid.desc, resp.size); + break; + } + break; + case MSG_TYPE_NOTIFY: + /* msg contains no address ! do not get_msg() ! */ + case MSG_TYPE_COMMAND: + /* get_msg() necessary */ + default: + snd_printk(KERN_ERR "tasklet doesn't know what to do with message %x\n", msg); + } /* switch type */ + + /* decrement counter */ + atomic_dec(&mgr->msg_processed); + + } /* while there is a msg in fifo */ + + spin_unlock(&mgr->lock); +} + + +irqreturn_t snd_mixart_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + mixart_mgr_t *mgr = snd_magic_cast(mixart_mgr_t, dev_id, return IRQ_NONE); + int err; + mixart_msg_t resp; + + u32 msg; + u32 it_reg; + + spin_lock(&mgr->lock); + + it_reg = readl_le(MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET)); + if( !(it_reg & MIXART_OIDI) ) { + /* this device did not cause the interrupt */ + spin_unlock(&mgr->lock); + return IRQ_NONE; + } + + /* mask all interrupts */ + writel_le(MIXART_HOST_ALL_INTERRUPT_MASKED, MIXART_REG(mgr, MIXART_PCI_OMIMR_OFFSET)); + + /* outdoorbell register clear */ + it_reg = readl(MIXART_REG(mgr, MIXART_PCI_ODBR_OFFSET)); + writel(it_reg, MIXART_REG(mgr, MIXART_PCI_ODBR_OFFSET)); + + /* clear interrupt */ + writel_le( MIXART_OIDI, MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET) ); + + /* process interrupt */ + while (retrieve_msg_frame(mgr, &msg)) { + + switch (msg & MSG_TYPE_MASK) { + case MSG_TYPE_COMMAND: + resp.message_id = 0; + resp.data = mixart_msg_data; + resp.size = sizeof(mixart_msg_data); + err = get_msg(mgr, &resp, msg & ~MSG_TYPE_MASK); + if( err < 0 ) { + snd_printk(KERN_ERR "interrupt: error(%d) reading mf %x\n", err, msg); + break; + } + + if(resp.message_id == MSG_SERVICES_TIMER_NOTIFY) { + int i; + mixart_timer_notify_t *notify = (mixart_timer_notify_t*)mixart_msg_data; + + for(i=0; istream_count; i++) { + + u32 buffer_id = notify->streams[i].buffer_id; + unsigned int chip_number = (buffer_id & MIXART_NOTIFY_CARD_MASK) >> MIXART_NOTIFY_CARD_OFFSET; /* card0 to 3 */ + unsigned int pcm_number = (buffer_id & MIXART_NOTIFY_PCM_MASK ) >> MIXART_NOTIFY_PCM_OFFSET; /* pcm0 to 3 */ + unsigned int sub_number = buffer_id & MIXART_NOTIFY_SUBS_MASK; /* 0 to MIXART_PLAYBACK_STREAMS */ + unsigned int is_capture = ((buffer_id & MIXART_NOTIFY_CAPT_MASK) != 0); /* playback == 0 / capture == 1 */ + + mixart_t *chip = mgr->chip[chip_number]; + mixart_stream_t *stream; + + if ((chip_number >= mgr->num_cards) || (pcm_number >= MIXART_PCM_TOTAL) || (sub_number >= MIXART_PLAYBACK_STREAMS)) { + snd_printk(KERN_ERR "error MSG_SERVICES_TIMER_NOTIFY buffer_id (%x) pos(%d)\n", + buffer_id, notify->streams[i].sample_pos_low_part); + break; + } + + if (is_capture) + stream = &chip->capture_stream[pcm_number]; + else + stream = &chip->playback_stream[pcm_number][sub_number]; + + if (stream->substream && (stream->status == MIXART_STREAM_STATUS_RUNNING)) { + snd_pcm_runtime_t *runtime = stream->substream->runtime; + int elapsed = 0; + u64 sample_count = ((u64)notify->streams[i].sample_pos_high_part) << 32; + sample_count |= notify->streams[i].sample_pos_low_part; + + while (1) { + u64 new_elapse_pos = stream->abs_period_elapsed + runtime->period_size; + + if (new_elapse_pos > sample_count) { + break; /* while */ + } + else { + elapsed = 1; + stream->buf_periods++; + if (stream->buf_periods >= runtime->periods) + stream->buf_periods = 0; + + stream->abs_period_elapsed = new_elapse_pos; + } + } + stream->buf_period_frag = (u32)( sample_count - stream->abs_period_elapsed ); + + if(elapsed) { + spin_unlock(&mgr->lock); + snd_pcm_period_elapsed(stream->substream); + spin_lock(&mgr->lock); + } + } + } + break; + } + if(resp.message_id == MSG_SERVICES_REPORT_TRACES) { + if(resp.size > 1) { +#ifndef __BIG_ENDIAN + /* Traces are text: the swapped msg_data has to be swapped back ! */ + int i; + for(i=0; i<(resp.size/4); i++) { + (mixart_msg_data)[i] = cpu_to_be32((mixart_msg_data)[i]); + } +#endif + ((char*)mixart_msg_data)[resp.size - 1] = 0; + snd_printdd("MIXART TRACE : %s\n", (char*)mixart_msg_data); + } + break; + } + + snd_printdd("command %x not handled\n", resp.message_id); + break; + + case MSG_TYPE_NOTIFY: + if(msg & MSG_CANCEL_NOTIFY_MASK) { + msg &= ~MSG_CANCEL_NOTIFY_MASK; + snd_printk(KERN_ERR "canceled notification %x !\n", msg); + } + /* no break, continue ! */ + case MSG_TYPE_ANSWER: + /* answer or notification to a message we are waiting for*/ + spin_lock(&mgr->msg_lock); + if( (msg & ~MSG_TYPE_MASK) == mgr->pending_event ) { + wake_up(&mgr->msg_sleep); + mgr->pending_event = 0; + } + /* answer to a message we did't want to wait for */ + else { + mgr->msg_fifo[mgr->msg_fifo_writeptr] = msg; + mgr->msg_fifo_writeptr++; + mgr->msg_fifo_writeptr %= MSG_FIFO_SIZE; + tasklet_hi_schedule(&mgr->msg_taskq); + } + spin_unlock(&mgr->msg_lock); + break; + case MSG_TYPE_REQUEST: + default: + snd_printdd("interrupt received request %x\n", msg); + /* TODO : are there things to do here ? */ + break; + } /* switch on msg type */ + } /* while there are msgs */ + + /* allow interrupt again */ + writel_le( MIXART_ALLOW_OUTBOUND_DOORBELL, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET)); + + spin_unlock(&mgr->lock); + + return IRQ_HANDLED; +} + + +void snd_mixart_init_mailbox(mixart_mgr_t *mgr) +{ + writel( 0, MIXART_MEM( mgr, MSG_HOST_RSC_PROTECTION ) ); + writel( 0, MIXART_MEM( mgr, MSG_AGENT_RSC_PROTECTION ) ); + + /* allow outbound messagebox to generate interrupts */ + if(mgr->irq >= 0) { + writel_le( MIXART_ALLOW_OUTBOUND_DOORBELL, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET)); + } + return; +} + +void snd_mixart_exit_mailbox(mixart_mgr_t *mgr) +{ + /* no more interrupts on outbound messagebox */ + writel_le( MIXART_HOST_ALL_INTERRUPT_MASKED, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET)); + return; +} + +void snd_mixart_reset_board(mixart_mgr_t *mgr) +{ + /* reset miXart */ + writel_be( 1, MIXART_REG(mgr, MIXART_BA1_BRUTAL_RESET_OFFSET) ); + return; +} diff -Nru a/sound/pci/mixart/mixart_core.h b/sound/pci/mixart/mixart_core.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/mixart/mixart_core.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,607 @@ +/* + * Driver for Digigram miXart soundcards + * + * low level interface with interrupt handling and mail box implementation + * + * Copyright (c) 2003 by Digigram + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __SOUND_MIXART_CORE_H +#define __SOUND_MIXART_CORE_H + + +enum mixart_message_id { + MSG_CONNECTOR_GET_AUDIO_INFO = 0x050008, + MSG_CONNECTOR_GET_OUT_AUDIO_LEVEL = 0x050009, + MSG_CONNECTOR_SET_OUT_AUDIO_LEVEL = 0x05000A, + + MSG_CONSOLE_MANAGER = 0x070000, + MSG_CONSOLE_GET_CLOCK_UID = 0x070003, + + MSG_PHYSICALIO_SET_LEVEL = 0x0F0008, + + MSG_STREAM_ADD_INPUT_GROUP = 0x130000, + MSG_STREAM_ADD_OUTPUT_GROUP = 0x130001, + MSG_STREAM_DELETE_GROUP = 0x130004, + MSG_STREAM_START_STREAM_GRP_PACKET = 0x130006, + MSG_STREAM_START_INPUT_STAGE_PACKET = 0x130007, + MSG_STREAM_START_OUTPUT_STAGE_PACKET = 0x130008, + MSG_STREAM_STOP_STREAM_GRP_PACKET = 0x130009, + MSG_STREAM_STOP_INPUT_STAGE_PACKET = 0x13000A, + MSG_STREAM_STOP_OUTPUT_STAGE_PACKET = 0x13000B, + MSG_STREAM_SET_INPUT_STAGE_PARAM = 0x13000F, + MSG_STREAM_SET_OUTPUT_STAGE_PARAM = 0x130010, + MSG_STREAM_SET_IN_AUDIO_LEVEL = 0x130015, + MSG_STREAM_SET_OUT_STREAM_LEVEL = 0x130017, + + MSG_SYSTEM_FIRST_ID = 0x160000, + MSG_SYSTEM_ENUM_PHYSICAL_IO = 0x16000E, + MSG_SYSTEM_ENUM_PLAY_CONNECTOR = 0x160017, + MSG_SYSTEM_ENUM_RECORD_CONNECTOR = 0x160018, + MSG_SYSTEM_WAIT_SYNCHRO_CMD = 0x16002C, + MSG_SYSTEM_SEND_SYNCHRO_CMD = 0x16002D, + + MSG_SERVICES_TIMER_NOTIFY = 0x1D0404, + MSG_SERVICES_REPORT_TRACES = 0x1D0700, + + MSG_CLOCK_CHECK_PROPERTIES = 0x200001, + MSG_CLOCK_SET_PROPERTIES = 0x200002, +}; + + +typedef struct mixart_msg mixart_msg_t; +struct mixart_msg +{ + u32 message_id; + mixart_uid_t uid; + void* data; + size_t size; +}; + +/* structs used to communicate with miXart */ + +typedef struct mixart_enum_connector_resp mixart_enum_connector_resp_t; +struct mixart_enum_connector_resp +{ + u32 error_code; + u32 first_uid_offset; + u32 uid_count; + u32 current_uid_index; + mixart_uid_t uid[MIXART_MAX_PHYS_CONNECTORS]; +} __attribute__((packed)); + + +/* used for following struct */ +#define MIXART_FLOAT_P_22_0_TO_HEX 0x41b00000 /* 22.0f */ +#define MIXART_FLOAT_M_20_0_TO_HEX 0xc1a00000 /* -20.0f */ +#define MIXART_FLOAT____0_0_TO_HEX 0x00000000 /* 0.0f */ + +typedef struct mixart_audio_info_req mixart_audio_info_req_t; +struct mixart_audio_info_req +{ + u32 line_max_level; /* float */ + u32 micro_max_level; /* float */ + u32 cd_max_level; /* float */ +} __attribute__((packed)); + +typedef struct mixart_analog_hw_info mixart_analog_hw_info_t; +struct mixart_analog_hw_info +{ + u32 is_present; + u32 hw_connection_type; + u32 max_level; /* float */ + u32 min_var_level; /* float */ + u32 max_var_level; /* float */ + u32 step_var_level; /* float */ + u32 fix_gain; /* float */ + u32 zero_var; /* float */ +} __attribute__((packed)); + +typedef struct mixart_digital_hw_info mixart_digital_hw_info_t; +struct mixart_digital_hw_info +{ + u32 hw_connection_type; + u32 presence; + u32 clock; + u32 reserved; +} __attribute__((packed)); + +typedef struct mixart_analog_info mixart_analog_info_t; +struct mixart_analog_info +{ + u32 type_mask; + mixart_analog_hw_info_t micro_info; + mixart_analog_hw_info_t line_info; + mixart_analog_hw_info_t cd_info; + u32 analog_level_present; +} __attribute__((packed)); + +typedef struct mixart_digital_info mixart_digital_info_t; +struct mixart_digital_info +{ + u32 type_mask; + mixart_digital_hw_info_t aes_info; + mixart_digital_hw_info_t adat_info; +} __attribute__((packed)); + +typedef struct mixart_audio_info mixart_audio_info_t; +struct mixart_audio_info +{ + u32 clock_type_mask; + mixart_analog_info_t analog_info; + mixart_digital_info_t digital_info; +} __attribute__((packed)); + +typedef struct mixart_audio_info_resp mixart_audio_info_resp_t; +struct mixart_audio_info_resp +{ + u32 txx_status; + mixart_audio_info_t info; +} __attribute__((packed)); + + +/* used for nb_bytes_max_per_sample */ +#define MIXART_FLOAT_P__4_0_TO_HEX 0x40800000 /* +4.0f */ +#define MIXART_FLOAT_P__8_0_TO_HEX 0x41000000 /* +8.0f */ + +typedef struct mixart_stream_info mixart_stream_info_t; +struct mixart_stream_info +{ + u32 size_max_byte_frame; + u32 size_max_sample_frame; + u32 nb_bytes_max_per_sample; /* float */ +} __attribute__((packed)); + +/* MSG_STREAM_ADD_INPUT_GROUP */ +/* MSG_STREAM_ADD_OUTPUT_GROUP */ + +typedef struct mixart_streaming_group_req mixart_streaming_group_req_t; +struct mixart_streaming_group_req +{ + u32 stream_count; + u32 channel_count; + u32 user_grp_number; + u32 first_phys_audio; + u32 latency; + mixart_stream_info_t stream_info[32]; + mixart_uid_t connector; + u32 flow_entry[32]; +} __attribute__((packed)); + +typedef struct mixart_stream_desc mixart_stream_desc_t; +struct mixart_stream_desc +{ + mixart_uid_t stream_uid; + u32 stream_desc; +} __attribute__((packed)); + +typedef struct mixart_streaming_group mixart_streaming_group_t; +struct mixart_streaming_group +{ + u32 status; + mixart_uid_t group; + u32 pipe_desc; + u32 stream_count; + mixart_stream_desc_t stream[32]; +} __attribute__((packed)); + +/* MSG_STREAM_DELETE_GROUP */ + +/* request : mixart_uid_t group */ + +typedef struct mixart_delete_group_resp mixart_delete_group_resp_t; +struct mixart_delete_group_resp +{ + u32 status; + u32 unused[2]; +} __attribute__((packed)); + + +/* MSG_STREAM_START_INPUT_STAGE_PACKET = 0x130000 + 7, + MSG_STREAM_START_OUTPUT_STAGE_PACKET = 0x130000 + 8, + MSG_STREAM_STOP_INPUT_STAGE_PACKET = 0x130000 + 10, + MSG_STREAM_STOP_OUTPUT_STAGE_PACKET = 0x130000 + 11, + */ + +typedef struct mixart_fx_couple_uid mixart_fx_couple_uid_t; +struct mixart_fx_couple_uid +{ + mixart_uid_t uid_fx_code; + mixart_uid_t uid_fx_data; +} __attribute__((packed)); + +typedef struct mixart_txx_stream_desc mixart_txx_stream_desc_t; +struct mixart_txx_stream_desc +{ + mixart_uid_t uid_pipe; + u32 stream_idx; + u32 fx_number; + mixart_fx_couple_uid_t uid_fx[4]; +} __attribute__((packed)); + +typedef struct mixart_flow_info mixart_flow_info_t; +struct mixart_flow_info +{ + mixart_txx_stream_desc_t stream_desc; + u32 flow_entry; + u32 flow_phy_addr; +} __attribute__((packed)); + +typedef struct mixart_stream_state_req mixart_stream_state_req_t; +struct mixart_stream_state_req +{ + u32 delayed; + u64 scheduler; + u32 reserved4np[3]; + u32 stream_count; /* set to 1 for instance */ + mixart_flow_info_t stream_info; /* could be an array[stream_count] */ +} __attribute__((packed)); + +/* MSG_STREAM_START_STREAM_GRP_PACKET = 0x130000 + 6 + MSG_STREAM_STOP_STREAM_GRP_PACKET = 0x130000 + 9 + */ + +typedef struct mixart_group_state_req mixart_group_state_req_t; +struct mixart_group_state_req +{ + u32 delayed; + u64 scheduler; + u32 reserved4np[2]; + u32 pipe_count; /* set to 1 for instance */ + mixart_uid_t pipe_uid[1]; /* could be an array[pipe_count] */ +} __attribute__((packed)); + +typedef struct mixart_group_state_resp mixart_group_state_resp_t; +struct mixart_group_state_resp +{ + u32 txx_status; + u64 scheduler; +} __attribute__((packed)); + + + +/* Structures used by the MSG_SERVICES_TIMER_NOTIFY command */ + +typedef struct mixart_sample_pos mixart_sample_pos_t; +struct mixart_sample_pos +{ + u32 buffer_id; + u32 validity; + u32 sample_pos_high_part; + u32 sample_pos_low_part; +} __attribute__((packed)); + +typedef struct mixart_timer_notify mixart_timer_notify_t; +struct mixart_timer_notify +{ + u32 stream_count; + mixart_sample_pos_t streams[MIXART_MAX_STREAM_PER_CARD * MIXART_MAX_CARDS]; +} __attribute__((packed)); + + +/* MSG_CONSOLE_GET_CLOCK_UID = 0x070003, + */ + +/* request is a uid with desc = MSG_CONSOLE_MANAGER | cardindex */ + +typedef struct mixart_return_uid mixart_return_uid_t; +struct mixart_return_uid +{ + u32 error_code; + mixart_uid_t uid; +} __attribute__((packed)); + +/* MSG_CLOCK_CHECK_PROPERTIES = 0x200001, + MSG_CLOCK_SET_PROPERTIES = 0x200002, +*/ + +enum mixart_clock_generic_type { + CGT_NO_CLOCK, + CGT_INTERNAL_CLOCK, + CGT_PROGRAMMABLE_CLOCK, + CGT_INTERNAL_ENSLAVED_CLOCK, + CGT_EXTERNAL_CLOCK, + CGT_CURRENT_CLOCK +}; + +enum mixart_clock_mode { + CM_UNDEFINED, + CM_MASTER, + CM_SLAVE, + CM_STANDALONE, + CM_NOT_CONCERNED +}; + + +typedef struct mixart_clock_properties mixart_clock_properties_t; +struct mixart_clock_properties +{ + u32 error_code; + u32 validation_mask; + u32 frequency; + u32 reference_frequency; + u32 clock_generic_type; + u32 clock_mode; + mixart_uid_t uid_clock_source; + mixart_uid_t uid_event_source; + u32 event_mode; + u32 synchro_signal_presence; + u32 format; + u32 board_mask; + u32 nb_callers; /* set to 1 (see below) */ + mixart_uid_t uid_caller[1]; +} __attribute__((packed)); + +typedef struct mixart_clock_properties_resp mixart_clock_properties_resp_t; +struct mixart_clock_properties_resp +{ + u32 status; + u32 clock_mode; +} __attribute__((packed)); + + +/* MSG_STREAM_SET_INPUT_STAGE_PARAM = 0x13000F */ +/* MSG_STREAM_SET_OUTPUT_STAGE_PARAM = 0x130010 */ + +enum mixart_coding_type { + CT_NOT_DEFINED, + CT_LINEAR, + CT_MPEG_L1, + CT_MPEG_L2, + CT_MPEG_L3, + CT_MPEG_L3_LSF, + CT_GSM +}; +enum mixart_sample_type { + ST_NOT_DEFINED, + ST_FLOATING_POINT_32BE, + ST_FLOATING_POINT_32LE, + ST_FLOATING_POINT_64BE, + ST_FLOATING_POINT_64LE, + ST_FIXED_POINT_8, + ST_FIXED_POINT_16BE, + ST_FIXED_POINT_16LE, + ST_FIXED_POINT_24BE, + ST_FIXED_POINT_24LE, + ST_FIXED_POINT_32BE, + ST_FIXED_POINT_32LE, + ST_INTEGER_8, + ST_INTEGER_16BE, + ST_INTEGER_16LE, + ST_INTEGER_24BE, + ST_INTEGER_24LE, + ST_INTEGER_32BE, + ST_INTEGER_32LE +}; + +typedef struct mixart_stream_param_desc mixart_stream_param_desc_t; +struct mixart_stream_param_desc +{ + u32 coding_type; /* use enum mixart_coding_type */ + u32 sample_type; /* use enum mixart_sample_type */ + + union { + struct { + u32 linear_endian_ness; + u32 linear_bits; + u32 is_signed; + u32 is_float; + } linear_format_info; + + struct { + u32 mpeg_layer; + u32 mpeg_mode; + u32 mpeg_mode_extension; + u32 mpeg_pre_emphasis; + u32 mpeg_has_padding_bit; + u32 mpeg_has_crc; + u32 mpeg_has_extension; + u32 mpeg_is_original; + u32 mpeg_has_copyright; + } mpeg_format_info; + } format_info; + + u32 delayed; + u64 scheduler; + u32 sample_size; + u32 has_header; + u32 has_suffix; + u32 has_bitrate; + u32 samples_per_frame; + u32 bytes_per_frame; + u32 bytes_per_sample; + u32 sampling_freq; + u32 number_of_channel; + u32 stream_number; + u32 buffer_size; + u32 differed_time; + u32 reserved4np[3]; + u32 pipe_count; /* set to 1 (array size !) */ + u32 stream_count; /* set to 1 (array size !) */ + mixart_txx_stream_desc_t stream_desc[1]; /* only one stream per command, but this could be an array */ + +} __attribute__((packed)); + + +/* MSG_CONNECTOR_GET_OUT_AUDIO_LEVEL = 0x050009, + */ + + +typedef struct mixart_get_out_audio_level mixart_get_out_audio_level_t; +struct mixart_get_out_audio_level +{ + u32 txx_status; + u32 digital_level; /* float */ + u32 analog_level; /* float */ + u32 monitor_level; /* float */ + u32 mute; + u32 monitor_mute1; + u32 monitor_mute2; +} __attribute__((packed)); + + +/* MSG_CONNECTOR_SET_OUT_AUDIO_LEVEL = 0x05000A, + */ + +/* used for valid_mask below */ +#define MIXART_AUDIO_LEVEL_ANALOG_MASK 0x01 +#define MIXART_AUDIO_LEVEL_DIGITAL_MASK 0x02 +#define MIXART_AUDIO_LEVEL_MONITOR_MASK 0x04 +#define MIXART_AUDIO_LEVEL_MUTE_MASK 0x08 +#define MIXART_AUDIO_LEVEL_MUTE_M1_MASK 0x10 +#define MIXART_AUDIO_LEVEL_MUTE_M2_MASK 0x20 + +typedef struct mixart_set_out_audio_level mixart_set_out_audio_level_t; +struct mixart_set_out_audio_level +{ + u32 delayed; + u64 scheduler; + u32 valid_mask1; + u32 valid_mask2; + u32 digital_level; /* float */ + u32 analog_level; /* float */ + u32 monitor_level; /* float */ + u32 mute; + u32 monitor_mute1; + u32 monitor_mute2; + u32 reserved4np; +} __attribute__((packed)); + + +/* MSG_SYSTEM_ENUM_PHYSICAL_IO = 0x16000E, + */ + +#define MIXART_MAX_PHYS_IO (MIXART_MAX_CARDS * 2 * 2) /* 4 * (analog+digital) * (playback+capture) */ + +typedef struct mixart_uid_enumeration mixart_uid_enumeration_t; +struct mixart_uid_enumeration +{ + u32 error_code; + u32 first_uid_offset; + u32 nb_uid; + u32 current_uid_index; + mixart_uid_t uid[MIXART_MAX_PHYS_IO]; +} __attribute__((packed)); + + +/* MSG_PHYSICALIO_SET_LEVEL = 0x0F0008, + MSG_PHYSICALIO_GET_LEVEL = 0x0F000C, +*/ + +typedef struct mixart_io_channel_level mixart_io_channel_level_t; +struct mixart_io_channel_level +{ + u32 analog_level; /* float */ + u32 unused[2]; +} __attribute__((packed)); + +typedef struct mixart_io_level mixart_io_level_t; +struct mixart_io_level +{ + s32 channel; /* 0=left, 1=right, -1=both, -2=both same */ + mixart_io_channel_level_t level[2]; +} __attribute__((packed)); + + +/* MSG_STREAM_SET_IN_AUDIO_LEVEL = 0x130015, + */ + +typedef struct mixart_in_audio_level_info mixart_in_audio_level_info_t; +struct mixart_in_audio_level_info +{ + mixart_uid_t connector; + u32 valid_mask1; + u32 valid_mask2; + u32 digital_level; + u32 analog_level; +} __attribute__((packed)); + +typedef struct mixart_set_in_audio_level_req mixart_set_in_audio_level_req_t; +struct mixart_set_in_audio_level_req +{ + u32 delayed; + u64 scheduler; + u32 audio_count; /* set to <= 2 */ + u32 reserved4np; + mixart_in_audio_level_info_t level[2]; +} __attribute__((packed)); + +/* response is a 32 bit status */ + + +/* MSG_STREAM_SET_OUT_STREAM_LEVEL = 0x130017, + */ + +/* defines used for valid_mask1 */ +#define MIXART_OUT_STREAM_SET_LEVEL_LEFT_AUDIO1 0x01 +#define MIXART_OUT_STREAM_SET_LEVEL_LEFT_AUDIO2 0x02 +#define MIXART_OUT_STREAM_SET_LEVEL_RIGHT_AUDIO1 0x04 +#define MIXART_OUT_STREAM_SET_LEVEL_RIGHT_AUDIO2 0x08 +#define MIXART_OUT_STREAM_SET_LEVEL_STREAM_1 0x10 +#define MIXART_OUT_STREAM_SET_LEVEL_STREAM_2 0x20 +#define MIXART_OUT_STREAM_SET_LEVEL_MUTE_1 0x40 +#define MIXART_OUT_STREAM_SET_LEVEL_MUTE_2 0x80 + +typedef struct mixart_out_stream_level_info mixart_out_stream_level_info_t; +struct mixart_out_stream_level_info +{ + u32 valid_mask1; + u32 valid_mask2; + u32 left_to_out1_level; + u32 left_to_out2_level; + u32 right_to_out1_level; + u32 right_to_out2_level; + u32 digital_level1; + u32 digital_level2; + u32 mute1; + u32 mute2; +} __attribute__((packed)); + +typedef struct mixart_set_out_stream_level mixart_set_out_stream_level_t; +struct mixart_set_out_stream_level +{ + mixart_txx_stream_desc_t desc; + mixart_out_stream_level_info_t out_level; +} __attribute__((packed)); + +typedef struct mixart_set_out_stream_level_req mixart_set_out_stream_level_req_t; +struct mixart_set_out_stream_level_req +{ + u32 delayed; + u64 scheduler; + u32 reserved4np[2]; + u32 nb_of_stream; /* set to 1 */ + mixart_set_out_stream_level_t stream_level; /* could be an array */ +} __attribute__((packed)); + +/* response to this request is a u32 status value */ + + +/* exported */ +void snd_mixart_init_mailbox(mixart_mgr_t *mgr); +void snd_mixart_exit_mailbox(mixart_mgr_t *mgr); + +int snd_mixart_send_msg(mixart_mgr_t *mgr, mixart_msg_t *request, int max_resp_size, void *resp_data); +int snd_mixart_send_msg_wait_notif(mixart_mgr_t *mgr, mixart_msg_t *request, u32 notif_event); +int snd_mixart_send_msg_nonblock(mixart_mgr_t *mgr, mixart_msg_t *request); + +irqreturn_t snd_mixart_interrupt(int irq, void *dev_id, struct pt_regs *regs); +void snd_mixart_msg_tasklet( unsigned long arg); + +void snd_mixart_reset_board(mixart_mgr_t *mgr); + +#endif /* __SOUND_MIXART_CORE_H */ diff -Nru a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/mixart/mixart_hwdep.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,572 @@ +/* + * Driver for Digigram miXart soundcards + * + * hwdep device manager + * + * Copyright (c) 2003 by Digigram + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include "mixart.h" +#include "mixart_mixer.h" +#include "mixart_core.h" +#include "mixart_hwdep.h" + + +/* miXart hwdep interface id string */ +#define SND_MIXART_HWDEP_ID "miXart Loader" + +static int mixart_hwdep_open(snd_hwdep_t *hw, struct file *file) +{ + return 0; +} + +static int mixart_hwdep_release(snd_hwdep_t *hw, struct file *file) +{ + return 0; +} + +/** + * wait for a value on a peudo register, exit with a timeout + * + * @param mgr pointer to miXart manager structure + * @param offset unsigned pseudo_register base + offset of value + * @param value value + * @param timeout timeout in centisenconds + */ +static int mixart_wait_nice_for_register_value(mixart_mgr_t *mgr, u32 offset, int is_egal, u32 value, unsigned long timeout) +{ + unsigned long end_time = jiffies + (timeout * HZ / 100); + u32 read; + + do { /* we may take too long time in this loop. + * so give controls back to kernel if needed. + */ + cond_resched(); + + read = readl_be( MIXART_MEM( mgr, offset )); + if(is_egal) { + if(read == value) return 0; + } + else { /* wait for different value */ + if(read != value) return 0; + } + } while ( time_after_eq(end_time, jiffies) ); + + return -EBUSY; +} + + +/* + structures needed to upload elf code packets + */ +typedef struct snd_mixart_elf32_ehdr snd_mixart_elf32_ehdr_t; + +struct snd_mixart_elf32_ehdr { + u8 e_ident[16]; + u16 e_type; + u16 e_machine; + u32 e_version; + u32 e_entry; + u32 e_phoff; + u32 e_shoff; + u32 e_flags; + u16 e_ehsize; + u16 e_phentsize; + u16 e_phnum; + u16 e_shentsize; + u16 e_shnum; + u16 e_shstrndx; +}; + +typedef struct snd_mixart_elf32_phdr snd_mixart_elf32_phdr_t; + +struct snd_mixart_elf32_phdr { + u32 p_type; + u32 p_offset; + u32 p_vaddr; + u32 p_paddr; + u32 p_filesz; + u32 p_memsz; + u32 p_flags; + u32 p_align; +}; + +static int mixart_load_elf(mixart_mgr_t *mgr, snd_hwdep_dsp_image_t *dsp ) +{ + char elf32_magic_number[4] = {0x7f,'E','L','F'}; + snd_mixart_elf32_ehdr_t elf_header; + int i; + + if ( copy_from_user(&elf_header, dsp->image , sizeof(snd_mixart_elf32_ehdr_t)) ) + return -EFAULT; + + for( i=0; i<4; i++ ) + if ( elf32_magic_number[i] != elf_header.e_ident[i] ) + return -EINVAL; + + if( elf_header.e_phoff != 0 ) { + snd_mixart_elf32_phdr_t elf_programheader; + + for( i=0; i < be16_to_cpu(elf_header.e_phnum); i++ ) { + u32 pos = be32_to_cpu(elf_header.e_phoff) + (u32)(i * be16_to_cpu(elf_header.e_phentsize)); + + if( copy_from_user( &elf_programheader, dsp->image + pos, sizeof(elf_programheader) ) ) + return -EFAULT; + + if(elf_programheader.p_type != 0) { + if( elf_programheader.p_filesz != 0 ) { + if(copy_from_user_toio( MIXART_MEM( mgr, be32_to_cpu(elf_programheader.p_vaddr)), + dsp->image + be32_to_cpu( elf_programheader.p_offset ), + be32_to_cpu( elf_programheader.p_filesz ))) + return -EFAULT; + } + } + } + } + return 0; +} + +static int mixart_hwdep_dsp_status(snd_hwdep_t *hw, snd_hwdep_dsp_status_t *info) +{ + mixart_mgr_t *mgr = snd_magic_cast(mixart_mgr_t, hw->private_data, return -ENXIO); + + strcpy(info->id, "miXart"); + info->num_dsps = MIXART_HARDW_FILES_MAX_INDEX; + + if (mgr->hwdep->dsp_loaded & (1 << MIXART_MOTHERBOARD_ELF_INDEX)) + info->chip_ready = 1; + + info->version = MIXART_DRIVER_VERSION; + return 0; +} + +/* + * get basic information and init miXart + */ + +/* audio IDs for request to the board */ +#define MIXART_FIRST_ANA_AUDIO_ID 0 +#define MIXART_FIRST_DIG_AUDIO_ID 8 + +static int mixart_enum_connectors(mixart_mgr_t *mgr) +{ + u32 k; + int err; + mixart_msg_t request; + mixart_enum_connector_resp_t connector; + mixart_audio_info_req_t audio_info_req; + mixart_audio_info_resp_t audio_info; + + audio_info_req.line_max_level = MIXART_FLOAT_P_22_0_TO_HEX; + audio_info_req.micro_max_level = MIXART_FLOAT_M_20_0_TO_HEX; + audio_info_req.cd_max_level = MIXART_FLOAT____0_0_TO_HEX; + + request.message_id = MSG_SYSTEM_ENUM_PLAY_CONNECTOR; + request.uid = (mixart_uid_t){0,0}; /* board num = 0 */ + request.data = NULL; + request.size = 0; + + err = snd_mixart_send_msg(mgr, &request, sizeof(connector), &connector); + if((err < 0) || (connector.error_code) || (connector.uid_count > MIXART_MAX_PHYS_CONNECTORS)) { + snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_PLAY_CONNECTOR\n"); + return -EINVAL; + } + + for(k=0; k < connector.uid_count; k++) { + mixart_pipe_t* pipe; + + if(k < MIXART_FIRST_DIG_AUDIO_ID) { + pipe = &mgr->chip[k/2]->pipe_out_ana; + } else { + pipe = &mgr->chip[(k-MIXART_FIRST_DIG_AUDIO_ID)/2]->pipe_out_dig; + } + if(k & 1) { + pipe->uid_right_connector = connector.uid[k]; /* odd */ + } else { + pipe->uid_left_connector = connector.uid[k]; /* even */ + } + + /* snd_printk(KERN_DEBUG "playback connector[%d].object_id = %x\n", k, connector.uid[k].object_id); */ + + /* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */ + request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO; + request.uid = connector.uid[k]; + request.data = &audio_info_req; + request.size = sizeof(audio_info_req); + + err = snd_mixart_send_msg(mgr, &request, sizeof(audio_info), &audio_info); + if( err < 0 ) { + snd_printk(KERN_ERR "error MSG_CONNECTOR_GET_AUDIO_INFO\n"); + return err; + } + /*snd_printk(KERN_DEBUG "play analog_info.analog_level_present = %x\n", audio_info.info.analog_info.analog_level_present);*/ + } + + request.message_id = MSG_SYSTEM_ENUM_RECORD_CONNECTOR; + request.uid = (mixart_uid_t){0,0}; /* board num = 0 */ + request.data = NULL; + request.size = 0; + + err = snd_mixart_send_msg(mgr, &request, sizeof(connector), &connector); + if((err < 0) || (connector.error_code) || (connector.uid_count > MIXART_MAX_PHYS_CONNECTORS)) { + snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_RECORD_CONNECTOR\n"); + return -EINVAL; + } + + for(k=0; k < connector.uid_count; k++) { + mixart_pipe_t* pipe; + + if(k < MIXART_FIRST_DIG_AUDIO_ID) { + pipe = &mgr->chip[k/2]->pipe_in_ana; + } else { + pipe = &mgr->chip[(k-MIXART_FIRST_DIG_AUDIO_ID)/2]->pipe_in_dig; + } + if(k & 1) { + pipe->uid_right_connector = connector.uid[k]; /* odd */ + } else { + pipe->uid_left_connector = connector.uid[k]; /* even */ + } + + /* snd_printk(KERN_DEBUG "capture connector[%d].object_id = %x\n", k, connector.uid[k].object_id); */ + + /* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */ + request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO; + request.uid = connector.uid[k]; + request.data = &audio_info_req; + request.size = sizeof(audio_info_req); + + err = snd_mixart_send_msg(mgr, &request, sizeof(audio_info), &audio_info); + if( err < 0 ) { + snd_printk(KERN_ERR "error MSG_CONNECTOR_GET_AUDIO_INFO\n"); + return err; + } + /*snd_printk(KERN_DEBUG "rec analog_info.analog_level_present = %x\n", audio_info.info.analog_info.analog_level_present);*/ + } + + return 0; +} + +static int mixart_enum_physio(mixart_mgr_t *mgr) +{ + u32 k; + int err; + mixart_msg_t request; + mixart_uid_t get_console_mgr; + mixart_return_uid_t console_mgr; + mixart_uid_enumeration_t phys_io; + + /* get the uid for the console manager */ + get_console_mgr.object_id = 0; + get_console_mgr.desc = MSG_CONSOLE_MANAGER | 0; /* cardindex = 0 */ + + request.message_id = MSG_CONSOLE_GET_CLOCK_UID; + request.uid = get_console_mgr; + request.data = &get_console_mgr; + request.size = sizeof(get_console_mgr); + + err = snd_mixart_send_msg(mgr, &request, sizeof(console_mgr), &console_mgr); + + if( (err < 0) || (console_mgr.error_code != 0) ) { + snd_printk(KERN_DEBUG "error MSG_CONSOLE_GET_CLOCK_UID : err=%x\n", console_mgr.error_code); + return -EINVAL; + } + + /* used later for clock issues ! */ + mgr->uid_console_manager = console_mgr.uid; + + request.message_id = MSG_SYSTEM_ENUM_PHYSICAL_IO; + request.uid = (mixart_uid_t){0,0}; + request.data = &console_mgr.uid; + request.size = sizeof(console_mgr.uid); + + err = snd_mixart_send_msg(mgr, &request, sizeof(phys_io), &phys_io); + if( (err < 0) || ( phys_io.error_code != 0 ) ) { + snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_PHYSICAL_IO err(%x) error_code(%x)\n", err, phys_io.error_code ); + return -EINVAL; + } + + snd_assert(phys_io.nb_uid >= (MIXART_MAX_CARDS * 2), return -EINVAL); /* min 2 phys io per card (analog in + analog out) */ + + for(k=0; knum_cards; k++) { + mgr->chip[k]->uid_in_analog_physio = phys_io.uid[k]; + mgr->chip[k]->uid_out_analog_physio = phys_io.uid[phys_io.nb_uid/2 + k]; + } + + return 0; +} + + +static int mixart_first_init(mixart_mgr_t *mgr) +{ + u32 k; + int err; + mixart_msg_t request; + + if((err = mixart_enum_connectors(mgr)) < 0) return err; + + if((err = mixart_enum_physio(mgr)) < 0) return err; + + /* send a synchro command to card (necessary to do this before first MSG_STREAM_START_STREAM_GRP_PACKET) */ + /* though why not here */ + request.message_id = MSG_SYSTEM_SEND_SYNCHRO_CMD; + request.uid = (mixart_uid_t){0,0}; + request.data = NULL; + request.size = 0; + /* this command has no data. response is a 32 bit status */ + err = snd_mixart_send_msg(mgr, &request, sizeof(k), &k); + if( (err < 0) || (k != 0) ) { + snd_printk(KERN_ERR "error MSG_SYSTEM_SEND_SYNCHRO_CMD\n"); + return err == 0 ? -EINVAL : err; + } + + return 0; +} + + +/* firmware base addresses (when hard coded) */ +#define MIXART_MOTHERBOARD_XLX_BASE_ADDRESS 0x00600000 + +static int mixart_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp) +{ + mixart_mgr_t* mgr = snd_magic_cast(mixart_mgr_t, hw->private_data, return -ENXIO); + int err, card_index; + u32 status_xilinx, status_elf, status_daught; + u32 val; + + /* read motherboard xilinx status */ + status_xilinx = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_MXLX_STATUS_OFFSET )); + /* read elf status */ + status_elf = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_ELF_STATUS_OFFSET )); + /* read daughterboard xilinx status */ + status_daught = readl_be( MIXART_MEM( mgr,MIXART_PSEUDOREG_DXLX_STATUS_OFFSET )); + + /* motherboard xilinx status 5 will say that the board is performing a reset */ + if( status_xilinx == 5 ) { + snd_printk( KERN_ERR "miXart is resetting !\n"); + return -EAGAIN; /* try again later */ + } + + switch (dsp->index) { + case MIXART_MOTHERBOARD_XLX_INDEX: + + /* xilinx already loaded ? */ + if( status_xilinx == 4 ) { + snd_printk( KERN_DEBUG "xilinx is already loaded !\n"); + return 0; + } + /* the status should be 0 == "idle" */ + if( status_xilinx != 0 ) { + snd_printk( KERN_ERR "xilinx load error ! status = %d\n", status_xilinx); + return -EIO; /* modprob -r may help ? */ + } + + /* check xilinx validity */ + snd_assert(((u32*)(dsp->image))[0]==0xFFFFFFFF, return -EINVAL); + snd_assert(dsp->length % 4 == 0, return -EINVAL); + + /* set xilinx status to copying */ + writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET )); + + /* setup xilinx base address */ + writel_be( MIXART_MOTHERBOARD_XLX_BASE_ADDRESS, MIXART_MEM( mgr,MIXART_PSEUDOREG_MXLX_BASE_ADDR_OFFSET )); + /* setup code size for xilinx file */ + writel_be( dsp->length, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_SIZE_OFFSET )); + + /* copy xilinx code */ + if (copy_from_user_toio( MIXART_MEM( mgr, MIXART_MOTHERBOARD_XLX_BASE_ADDRESS), dsp->image, dsp->length)) + return -EFAULT; + + /* set xilinx status to copy finished */ + writel_be( 2, MIXART_MEM( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET )); + + /* return, because no further processing needed */ + return 0; + + case MIXART_MOTHERBOARD_ELF_INDEX: + + if( status_elf == 4 ) { + snd_printk( KERN_DEBUG "elf file already loaded !\n"); + return 0; + } + + /* the status should be 0 == "idle" */ + if( status_elf != 0 ) { + snd_printk( KERN_ERR "elf load error ! status = %d\n", status_elf); + return -EIO; /* modprob -r may help ? */ + } + + /* wait for xilinx status == 4 */ + err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET, 1, 4, 500); /* 5sec */ + if (err < 0) { + snd_printk( KERN_ERR "xilinx was not loaded or could not be started\n"); + return err; + } + + /* init some data on the card */ + writel_be( 0, MIXART_MEM( mgr, MIXART_PSEUDOREG_BOARDNUMBER ) ); /* set miXart boardnumber to 0 */ + writel_be( 0, MIXART_MEM( mgr, MIXART_FLOWTABLE_PTR ) ); /* reset pointer to flow table on miXart */ + + /* set elf status to copying */ + writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET )); + + /* process the copying of the elf packets */ + err = mixart_load_elf( mgr, dsp); + if (err < 0) return err; + + /* set elf status to copy finished */ + writel_be( 2, MIXART_MEM( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET )); + + /* wait for elf status == 4 */ + err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET, 1, 4, 300); /* 3sec */ + if (err < 0) { + snd_printk( KERN_ERR "elf could not be started\n"); + return err; + } + + /* miXart waits at this point on the pointer to the flow table */ + writel_be( (u32)mgr->flowinfo.addr, MIXART_MEM( mgr, MIXART_FLOWTABLE_PTR ) ); /* give pointer of flow table to miXart */ + + return 0; /* return, another xilinx file has to be loaded before */ + + case MIXART_AESEBUBOARD_XLX_INDEX: + default: + + /* elf and xilinx should be loaded */ + if( (status_elf != 4) || (status_xilinx != 4) ) { + printk( KERN_ERR "xilinx or elf not successfully loaded\n"); + return -EIO; /* modprob -r may help ? */ + } + + /* wait for daughter detection != 0 */ + err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DBRD_PRESENCE_OFFSET, 0, 0, 30); /* 300msec */ + if (err < 0) { + snd_printk( KERN_ERR "error starting elf file\n"); + return err; + } + + /* the board type can now be retrieved */ + mgr->board_type = (DAUGHTER_TYPE_MASK & readl_be( MIXART_MEM( mgr, MIXART_PSEUDOREG_DBRD_TYPE_OFFSET))); + + if (mgr->board_type == MIXART_DAUGHTER_TYPE_NONE) + break; /* no daughter board; the file does not have to be loaded, continue after the switch */ + + /* only if aesebu daughter board presence (elf code must run) */ + if (mgr->board_type != MIXART_DAUGHTER_TYPE_AES ) + return -EINVAL; + + /* daughter should be idle */ + if( status_daught != 0 ) { + printk( KERN_ERR "daughter load error ! status = %d\n", status_daught); + return -EIO; /* modprob -r may help ? */ + } + + /* check daughterboard xilinx validity */ + snd_assert(((u32*)(dsp->image))[0]==0xFFFFFFFF, return -EINVAL); + snd_assert(dsp->length % 4 == 0, return -EINVAL); + + /* inform mixart about the size of the file */ + writel_be( dsp->length, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_SIZE_OFFSET )); + + /* set daughterboard status to 1 */ + writel_be( 1, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET )); + + /* wait for status == 2 */ + err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 2, 30); /* 300msec */ + if (err < 0) { + snd_printk( KERN_ERR "daughter board load error\n"); + return err; + } + + /* get the address where to write the file */ + val = readl_be( MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_BASE_ADDR_OFFSET )); + snd_assert(val != 0, return -EINVAL); + + /* copy daughterboard xilinx code */ + if (copy_from_user_toio( MIXART_MEM( mgr, val), dsp->image, dsp->length)) + return -EFAULT; + + /* set daughterboard status to 4 */ + writel_be( 4, MIXART_MEM( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET )); + + /* continue with init */ + break; + } /* end of switch file index*/ + + /* wait for daughter status == 3 */ + err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 3, 300); /* 3sec */ + if (err < 0) { + snd_printk( KERN_ERR "daughter board could not be initialised\n"); + return err; + } + + /* init mailbox (communication with embedded) */ + snd_mixart_init_mailbox(mgr); + + /* first communication with embedded */ + err = mixart_first_init(mgr); + if (err < 0) { + snd_printk( KERN_ERR "miXart could not be set up\n"); + return err; + } + + /* create devices and mixer in accordance with HW options*/ + for (card_index = 0; card_index < mgr->num_cards; card_index++) { + mixart_t *chip = mgr->chip[card_index]; + + if ((err = snd_mixart_create_pcm(chip)) < 0) + return err; + + if (card_index == 0) { + if ((err = snd_mixart_create_mixer(chip->mgr)) < 0) + return err; + } + + if ((err = snd_card_register(chip->card)) < 0) + return err; + }; + + snd_printdd("miXart firmware downloaded and successfully set up\n"); + + return 0; +} + + +int snd_mixart_hwdep_new(mixart_mgr_t *mgr) +{ + int err; + snd_hwdep_t *hw; + + /* only create hwdep interface for first cardX (see "index" module parameter)*/ + if ((err = snd_hwdep_new(mgr->chip[0]->card, SND_MIXART_HWDEP_ID, 0, &hw)) < 0) + return err; + + hw->iface = SNDRV_HWDEP_IFACE_MIXART; + hw->private_data = mgr; + hw->ops.open = mixart_hwdep_open; + hw->ops.release = mixart_hwdep_release; + hw->ops.dsp_status = mixart_hwdep_dsp_status; + hw->ops.dsp_load = mixart_hwdep_dsp_load; + hw->exclusive = 1; + sprintf(hw->name, SND_MIXART_HWDEP_ID); + mgr->hwdep = hw; + mgr->hwdep->dsp_loaded = 0; + return 0; +} diff -Nru a/sound/pci/mixart/mixart_hwdep.h b/sound/pci/mixart/mixart_hwdep.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/mixart/mixart_hwdep.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,146 @@ +/* + * Driver for Digigram miXart soundcards + * + * definitions and makros for basic card access + * + * Copyright (c) 2003 by Digigram + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __SOUND_MIXART_HWDEP_H +#define __SOUND_MIXART_HWDEP_H + +#include + +#define readl_be(x) be32_to_cpu(__raw_readl(x)) +#define writel_be(data,addr) __raw_writel(cpu_to_be32(data),addr) + +#define readl_le(x) le32_to_cpu(__raw_readl(x)) +#define writel_le(data,addr) __raw_writel(cpu_to_le32(data),addr) + +#define MIXART_MEM(mgr,x) ((mgr)->mem[0].virt + (x)) +#define MIXART_REG(mgr,x) ((mgr)->mem[1].virt + (x)) + + +/* Daughter board Type */ +#define DAUGHTER_TYPE_MASK 0x0F +#define DAUGHTER_VER_MASK 0xF0 +#define DAUGHTER_TYPEVER_MASK (DAUGHTER_TYPE_MASK|DAUGHTER_VER_MASK) + +#define MIXART_DAUGHTER_TYPE_NONE 0x00 +#define MIXART_DAUGHTER_TYPE_COBRANET 0x08 +#define MIXART_DAUGHTER_TYPE_AES 0x0E + + + +#define MIXART_BA0_SIZE (16 * 1024 * 1024) /* 16M */ +#define MIXART_BA1_SIZE (4 * 1024) /* 4k */ + +/* + * -----------BAR 0 -------------------------------------------------------------------------------------------------------- + */ +#define MIXART_PSEUDOREG 0x2000 /* base address for pseudoregister */ + +#define MIXART_PSEUDOREG_BOARDNUMBER MIXART_PSEUDOREG+0 /* board number */ + +/* perfmeter (available when elf loaded)*/ +#define MIXART_PSEUDOREG_PERF_STREAM_LOAD_OFFSET MIXART_PSEUDOREG+0x70 /* streaming load */ +#define MIXART_PSEUDOREG_PERF_SYSTEM_LOAD_OFFSET MIXART_PSEUDOREG+0x78 /* system load (reference)*/ +#define MIXART_PSEUDOREG_PERF_MAILBX_LOAD_OFFSET MIXART_PSEUDOREG+0x7C /* mailbox load */ +#define MIXART_PSEUDOREG_PERF_INTERR_LOAD_OFFSET MIXART_PSEUDOREG+0x74 /* interrupt handling load */ + +/* motherboard xilinx loader info */ +#define MIXART_PSEUDOREG_MXLX_BASE_ADDR_OFFSET MIXART_PSEUDOREG+0x9C /* 0x00600000 */ +#define MIXART_PSEUDOREG_MXLX_SIZE_OFFSET MIXART_PSEUDOREG+0xA0 /* xilinx size in bytes */ +#define MIXART_PSEUDOREG_MXLX_STATUS_OFFSET MIXART_PSEUDOREG+0xA4 /* status = EMBEBBED_STAT_XXX */ + +/* elf loader info */ +#define MIXART_PSEUDOREG_ELF_STATUS_OFFSET MIXART_PSEUDOREG+0xB0 /* status = EMBEBBED_STAT_XXX */ + +/* +* after the elf code is loaded, and the flowtable info was passed to it, +* the driver polls on this address, until it shows 1 (presence) or 2 (absence) +* once it is non-zero, the daughter board type may be read +*/ +#define MIXART_PSEUDOREG_DBRD_PRESENCE_OFFSET MIXART_PSEUDOREG+0x990 + +/* Global info structure */ +#define MIXART_PSEUDOREG_DBRD_TYPE_OFFSET MIXART_PSEUDOREG+0x994 /* Type and version of daughterboard */ + + +/* daughterboard xilinx loader info */ +#define MIXART_PSEUDOREG_DXLX_BASE_ADDR_OFFSET MIXART_PSEUDOREG+0x998 /* get the address here where to write the file */ +#define MIXART_PSEUDOREG_DXLX_SIZE_OFFSET MIXART_PSEUDOREG+0x99C /* xilinx size in bytes */ +#define MIXART_PSEUDOREG_DXLX_STATUS_OFFSET MIXART_PSEUDOREG+0x9A0 /* status = EMBEBBED_STAT_XXX */ + +/* */ +#define MIXART_FLOWTABLE_PTR 0x3000 /* pointer to flow table */ + +/* mailbox addresses */ + +/* message DRV -> EMB */ +#define MSG_INBOUND_POST_HEAD 0x010008 /* DRV posts MF + increment4 */ +#define MSG_INBOUND_POST_TAIL 0x01000C /* EMB gets MF + increment4 */ +/* message EMB -> DRV */ +#define MSG_OUTBOUND_POST_TAIL 0x01001C /* DRV gets MF + increment4 */ +#define MSG_OUTBOUND_POST_HEAD 0x010018 /* EMB posts MF + increment4 */ +/* Get Free Frames */ +#define MSG_INBOUND_FREE_TAIL 0x010004 /* DRV gets MFA + increment4 */ +#define MSG_OUTBOUND_FREE_TAIL 0x010014 /* EMB gets MFA + increment4 */ +/* Put Free Frames */ +#define MSG_OUTBOUND_FREE_HEAD 0x010010 /* DRV puts MFA + increment4 */ +#define MSG_INBOUND_FREE_HEAD 0x010000 /* EMB puts MFA + increment4 */ + +/* firmware addresses of the message fifos */ +#define MSG_BOUND_STACK_SIZE 0x004000 /* size of each following stack */ +/* posted messages */ +#define MSG_OUTBOUND_POST_STACK 0x108000 /* stack of messages to the DRV */ +#define MSG_INBOUND_POST_STACK 0x104000 /* stack of messages to the EMB */ +/* available empty messages */ +#define MSG_OUTBOUND_FREE_STACK 0x10C000 /* stack of free enveloped for EMB */ +#define MSG_INBOUND_FREE_STACK 0x100000 /* stack of free enveloped for DRV */ + + +/* defines for mailbox message frames */ +#define MSG_FRAME_OFFSET 0x64 +#define MSG_FRAME_SIZE 0x6400 +#define MSG_FRAME_NUMBER 32 +#define MSG_FROM_AGENT_ITMF_OFFSET (MSG_FRAME_OFFSET + (MSG_FRAME_SIZE * MSG_FRAME_NUMBER)) +#define MSG_TO_AGENT_ITMF_OFFSET (MSG_FROM_AGENT_ITMF_OFFSET + MSG_FRAME_SIZE) +#define MSG_HOST_RSC_PROTECTION (MSG_TO_AGENT_ITMF_OFFSET + MSG_FRAME_SIZE) +#define MSG_AGENT_RSC_PROTECTION (MSG_HOST_RSC_PROTECTION + 4) + + +/* + * -----------BAR 1 -------------------------------------------------------------------------------------------------------- + */ + +/* interrupt addresses and constants */ +#define MIXART_PCI_OMIMR_OFFSET 0x34 /* outbound message interrupt mask register */ +#define MIXART_PCI_OMISR_OFFSET 0x30 /* outbound message interrupt status register */ +#define MIXART_PCI_ODBR_OFFSET 0x60 /* outbound doorbell register */ + +#define MIXART_BA1_BRUTAL_RESET_OFFSET 0x68 /* write 1 in LSBit to reset board */ + +#define MIXART_HOST_ALL_INTERRUPT_MASKED 0x02B /* 0000 0010 1011 */ +#define MIXART_ALLOW_OUTBOUND_DOORBELL 0x023 /* 0000 0010 0011 */ +#define MIXART_OIDI 0x008 /* 0000 0000 1000 */ + + +/* exported */ +int snd_mixart_hwdep_new(mixart_mgr_t *mgr); + +#endif /* __SOUND_MIXART_HWDEP_H */ diff -Nru a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/mixart/mixart_mixer.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,1138 @@ +/* + * Driver for Digigram miXart soundcards + * + * mixer callbacks + * + * Copyright (c) 2003 by Digigram + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include "mixart.h" +#include "mixart_core.h" +#include "mixart_hwdep.h" +#include +#include "mixart_mixer.h" + +#define chip_t mixart_t + +static u32 mixart_analog_level[256] = { + 0xc2c00000, /* [000] -96.0 dB */ + 0xc2bf0000, /* [001] -95.5 dB */ + 0xc2be0000, /* [002] -95.0 dB */ + 0xc2bd0000, /* [003] -94.5 dB */ + 0xc2bc0000, /* [004] -94.0 dB */ + 0xc2bb0000, /* [005] -93.5 dB */ + 0xc2ba0000, /* [006] -93.0 dB */ + 0xc2b90000, /* [007] -92.5 dB */ + 0xc2b80000, /* [008] -92.0 dB */ + 0xc2b70000, /* [009] -91.5 dB */ + 0xc2b60000, /* [010] -91.0 dB */ + 0xc2b50000, /* [011] -90.5 dB */ + 0xc2b40000, /* [012] -90.0 dB */ + 0xc2b30000, /* [013] -89.5 dB */ + 0xc2b20000, /* [014] -89.0 dB */ + 0xc2b10000, /* [015] -88.5 dB */ + 0xc2b00000, /* [016] -88.0 dB */ + 0xc2af0000, /* [017] -87.5 dB */ + 0xc2ae0000, /* [018] -87.0 dB */ + 0xc2ad0000, /* [019] -86.5 dB */ + 0xc2ac0000, /* [020] -86.0 dB */ + 0xc2ab0000, /* [021] -85.5 dB */ + 0xc2aa0000, /* [022] -85.0 dB */ + 0xc2a90000, /* [023] -84.5 dB */ + 0xc2a80000, /* [024] -84.0 dB */ + 0xc2a70000, /* [025] -83.5 dB */ + 0xc2a60000, /* [026] -83.0 dB */ + 0xc2a50000, /* [027] -82.5 dB */ + 0xc2a40000, /* [028] -82.0 dB */ + 0xc2a30000, /* [029] -81.5 dB */ + 0xc2a20000, /* [030] -81.0 dB */ + 0xc2a10000, /* [031] -80.5 dB */ + 0xc2a00000, /* [032] -80.0 dB */ + 0xc29f0000, /* [033] -79.5 dB */ + 0xc29e0000, /* [034] -79.0 dB */ + 0xc29d0000, /* [035] -78.5 dB */ + 0xc29c0000, /* [036] -78.0 dB */ + 0xc29b0000, /* [037] -77.5 dB */ + 0xc29a0000, /* [038] -77.0 dB */ + 0xc2990000, /* [039] -76.5 dB */ + 0xc2980000, /* [040] -76.0 dB */ + 0xc2970000, /* [041] -75.5 dB */ + 0xc2960000, /* [042] -75.0 dB */ + 0xc2950000, /* [043] -74.5 dB */ + 0xc2940000, /* [044] -74.0 dB */ + 0xc2930000, /* [045] -73.5 dB */ + 0xc2920000, /* [046] -73.0 dB */ + 0xc2910000, /* [047] -72.5 dB */ + 0xc2900000, /* [048] -72.0 dB */ + 0xc28f0000, /* [049] -71.5 dB */ + 0xc28e0000, /* [050] -71.0 dB */ + 0xc28d0000, /* [051] -70.5 dB */ + 0xc28c0000, /* [052] -70.0 dB */ + 0xc28b0000, /* [053] -69.5 dB */ + 0xc28a0000, /* [054] -69.0 dB */ + 0xc2890000, /* [055] -68.5 dB */ + 0xc2880000, /* [056] -68.0 dB */ + 0xc2870000, /* [057] -67.5 dB */ + 0xc2860000, /* [058] -67.0 dB */ + 0xc2850000, /* [059] -66.5 dB */ + 0xc2840000, /* [060] -66.0 dB */ + 0xc2830000, /* [061] -65.5 dB */ + 0xc2820000, /* [062] -65.0 dB */ + 0xc2810000, /* [063] -64.5 dB */ + 0xc2800000, /* [064] -64.0 dB */ + 0xc27e0000, /* [065] -63.5 dB */ + 0xc27c0000, /* [066] -63.0 dB */ + 0xc27a0000, /* [067] -62.5 dB */ + 0xc2780000, /* [068] -62.0 dB */ + 0xc2760000, /* [069] -61.5 dB */ + 0xc2740000, /* [070] -61.0 dB */ + 0xc2720000, /* [071] -60.5 dB */ + 0xc2700000, /* [072] -60.0 dB */ + 0xc26e0000, /* [073] -59.5 dB */ + 0xc26c0000, /* [074] -59.0 dB */ + 0xc26a0000, /* [075] -58.5 dB */ + 0xc2680000, /* [076] -58.0 dB */ + 0xc2660000, /* [077] -57.5 dB */ + 0xc2640000, /* [078] -57.0 dB */ + 0xc2620000, /* [079] -56.5 dB */ + 0xc2600000, /* [080] -56.0 dB */ + 0xc25e0000, /* [081] -55.5 dB */ + 0xc25c0000, /* [082] -55.0 dB */ + 0xc25a0000, /* [083] -54.5 dB */ + 0xc2580000, /* [084] -54.0 dB */ + 0xc2560000, /* [085] -53.5 dB */ + 0xc2540000, /* [086] -53.0 dB */ + 0xc2520000, /* [087] -52.5 dB */ + 0xc2500000, /* [088] -52.0 dB */ + 0xc24e0000, /* [089] -51.5 dB */ + 0xc24c0000, /* [090] -51.0 dB */ + 0xc24a0000, /* [091] -50.5 dB */ + 0xc2480000, /* [092] -50.0 dB */ + 0xc2460000, /* [093] -49.5 dB */ + 0xc2440000, /* [094] -49.0 dB */ + 0xc2420000, /* [095] -48.5 dB */ + 0xc2400000, /* [096] -48.0 dB */ + 0xc23e0000, /* [097] -47.5 dB */ + 0xc23c0000, /* [098] -47.0 dB */ + 0xc23a0000, /* [099] -46.5 dB */ + 0xc2380000, /* [100] -46.0 dB */ + 0xc2360000, /* [101] -45.5 dB */ + 0xc2340000, /* [102] -45.0 dB */ + 0xc2320000, /* [103] -44.5 dB */ + 0xc2300000, /* [104] -44.0 dB */ + 0xc22e0000, /* [105] -43.5 dB */ + 0xc22c0000, /* [106] -43.0 dB */ + 0xc22a0000, /* [107] -42.5 dB */ + 0xc2280000, /* [108] -42.0 dB */ + 0xc2260000, /* [109] -41.5 dB */ + 0xc2240000, /* [110] -41.0 dB */ + 0xc2220000, /* [111] -40.5 dB */ + 0xc2200000, /* [112] -40.0 dB */ + 0xc21e0000, /* [113] -39.5 dB */ + 0xc21c0000, /* [114] -39.0 dB */ + 0xc21a0000, /* [115] -38.5 dB */ + 0xc2180000, /* [116] -38.0 dB */ + 0xc2160000, /* [117] -37.5 dB */ + 0xc2140000, /* [118] -37.0 dB */ + 0xc2120000, /* [119] -36.5 dB */ + 0xc2100000, /* [120] -36.0 dB */ + 0xc20e0000, /* [121] -35.5 dB */ + 0xc20c0000, /* [122] -35.0 dB */ + 0xc20a0000, /* [123] -34.5 dB */ + 0xc2080000, /* [124] -34.0 dB */ + 0xc2060000, /* [125] -33.5 dB */ + 0xc2040000, /* [126] -33.0 dB */ + 0xc2020000, /* [127] -32.5 dB */ + 0xc2000000, /* [128] -32.0 dB */ + 0xc1fc0000, /* [129] -31.5 dB */ + 0xc1f80000, /* [130] -31.0 dB */ + 0xc1f40000, /* [131] -30.5 dB */ + 0xc1f00000, /* [132] -30.0 dB */ + 0xc1ec0000, /* [133] -29.5 dB */ + 0xc1e80000, /* [134] -29.0 dB */ + 0xc1e40000, /* [135] -28.5 dB */ + 0xc1e00000, /* [136] -28.0 dB */ + 0xc1dc0000, /* [137] -27.5 dB */ + 0xc1d80000, /* [138] -27.0 dB */ + 0xc1d40000, /* [139] -26.5 dB */ + 0xc1d00000, /* [140] -26.0 dB */ + 0xc1cc0000, /* [141] -25.5 dB */ + 0xc1c80000, /* [142] -25.0 dB */ + 0xc1c40000, /* [143] -24.5 dB */ + 0xc1c00000, /* [144] -24.0 dB */ + 0xc1bc0000, /* [145] -23.5 dB */ + 0xc1b80000, /* [146] -23.0 dB */ + 0xc1b40000, /* [147] -22.5 dB */ + 0xc1b00000, /* [148] -22.0 dB */ + 0xc1ac0000, /* [149] -21.5 dB */ + 0xc1a80000, /* [150] -21.0 dB */ + 0xc1a40000, /* [151] -20.5 dB */ + 0xc1a00000, /* [152] -20.0 dB */ + 0xc19c0000, /* [153] -19.5 dB */ + 0xc1980000, /* [154] -19.0 dB */ + 0xc1940000, /* [155] -18.5 dB */ + 0xc1900000, /* [156] -18.0 dB */ + 0xc18c0000, /* [157] -17.5 dB */ + 0xc1880000, /* [158] -17.0 dB */ + 0xc1840000, /* [159] -16.5 dB */ + 0xc1800000, /* [160] -16.0 dB */ + 0xc1780000, /* [161] -15.5 dB */ + 0xc1700000, /* [162] -15.0 dB */ + 0xc1680000, /* [163] -14.5 dB */ + 0xc1600000, /* [164] -14.0 dB */ + 0xc1580000, /* [165] -13.5 dB */ + 0xc1500000, /* [166] -13.0 dB */ + 0xc1480000, /* [167] -12.5 dB */ + 0xc1400000, /* [168] -12.0 dB */ + 0xc1380000, /* [169] -11.5 dB */ + 0xc1300000, /* [170] -11.0 dB */ + 0xc1280000, /* [171] -10.5 dB */ + 0xc1200000, /* [172] -10.0 dB */ + 0xc1180000, /* [173] -9.5 dB */ + 0xc1100000, /* [174] -9.0 dB */ + 0xc1080000, /* [175] -8.5 dB */ + 0xc1000000, /* [176] -8.0 dB */ + 0xc0f00000, /* [177] -7.5 dB */ + 0xc0e00000, /* [178] -7.0 dB */ + 0xc0d00000, /* [179] -6.5 dB */ + 0xc0c00000, /* [180] -6.0 dB */ + 0xc0b00000, /* [181] -5.5 dB */ + 0xc0a00000, /* [182] -5.0 dB */ + 0xc0900000, /* [183] -4.5 dB */ + 0xc0800000, /* [184] -4.0 dB */ + 0xc0600000, /* [185] -3.5 dB */ + 0xc0400000, /* [186] -3.0 dB */ + 0xc0200000, /* [187] -2.5 dB */ + 0xc0000000, /* [188] -2.0 dB */ + 0xbfc00000, /* [189] -1.5 dB */ + 0xbf800000, /* [190] -1.0 dB */ + 0xbf000000, /* [191] -0.5 dB */ + 0x00000000, /* [192] 0.0 dB */ + 0x3f000000, /* [193] 0.5 dB */ + 0x3f800000, /* [194] 1.0 dB */ + 0x3fc00000, /* [195] 1.5 dB */ + 0x40000000, /* [196] 2.0 dB */ + 0x40200000, /* [197] 2.5 dB */ + 0x40400000, /* [198] 3.0 dB */ + 0x40600000, /* [199] 3.5 dB */ + 0x40800000, /* [200] 4.0 dB */ + 0x40900000, /* [201] 4.5 dB */ + 0x40a00000, /* [202] 5.0 dB */ + 0x40b00000, /* [203] 5.5 dB */ + 0x40c00000, /* [204] 6.0 dB */ + 0x40d00000, /* [205] 6.5 dB */ + 0x40e00000, /* [206] 7.0 dB */ + 0x40f00000, /* [207] 7.5 dB */ + 0x41000000, /* [208] 8.0 dB */ + 0x41080000, /* [209] 8.5 dB */ + 0x41100000, /* [210] 9.0 dB */ + 0x41180000, /* [211] 9.5 dB */ + 0x41200000, /* [212] 10.0 dB */ + 0x41280000, /* [213] 10.5 dB */ + 0x41300000, /* [214] 11.0 dB */ + 0x41380000, /* [215] 11.5 dB */ + 0x41400000, /* [216] 12.0 dB */ + 0x41480000, /* [217] 12.5 dB */ + 0x41500000, /* [218] 13.0 dB */ + 0x41580000, /* [219] 13.5 dB */ + 0x41600000, /* [220] 14.0 dB */ + 0x41680000, /* [221] 14.5 dB */ + 0x41700000, /* [222] 15.0 dB */ + 0x41780000, /* [223] 15.5 dB */ + 0x41800000, /* [224] 16.0 dB */ + 0x41840000, /* [225] 16.5 dB */ + 0x41880000, /* [226] 17.0 dB */ + 0x418c0000, /* [227] 17.5 dB */ + 0x41900000, /* [228] 18.0 dB */ + 0x41940000, /* [229] 18.5 dB */ + 0x41980000, /* [230] 19.0 dB */ + 0x419c0000, /* [231] 19.5 dB */ + 0x41a00000, /* [232] 20.0 dB */ + 0x41a40000, /* [233] 20.5 dB */ + 0x41a80000, /* [234] 21.0 dB */ + 0x41ac0000, /* [235] 21.5 dB */ + 0x41b00000, /* [236] 22.0 dB */ + 0x41b40000, /* [237] 22.5 dB */ + 0x41b80000, /* [238] 23.0 dB */ + 0x41bc0000, /* [239] 23.5 dB */ + 0x41c00000, /* [240] 24.0 dB */ + 0x41c40000, /* [241] 24.5 dB */ + 0x41c80000, /* [242] 25.0 dB */ + 0x41cc0000, /* [243] 25.5 dB */ + 0x41d00000, /* [244] 26.0 dB */ + 0x41d40000, /* [245] 26.5 dB */ + 0x41d80000, /* [246] 27.0 dB */ + 0x41dc0000, /* [247] 27.5 dB */ + 0x41e00000, /* [248] 28.0 dB */ + 0x41e40000, /* [249] 28.5 dB */ + 0x41e80000, /* [250] 29.0 dB */ + 0x41ec0000, /* [251] 29.5 dB */ + 0x41f00000, /* [252] 30.0 dB */ + 0x41f40000, /* [253] 30.5 dB */ + 0x41f80000, /* [254] 31.0 dB */ + 0x41fc0000, /* [255] 31.5 dB */ +}; + +#define MIXART_ANALOG_CAPTURE_LEVEL_MIN 0 /* -96.0 dB + 8.0 dB = -88.0 dB */ +#define MIXART_ANALOG_CAPTURE_LEVEL_MAX 255 /* 31.5 dB + 8.0 dB = 39.5 dB */ +#define MIXART_ANALOG_CAPTURE_ZERO_LEVEL 176 /* -8.0 dB + 8.0 dB = 0.0 dB */ + +#define MIXART_ANALOG_PLAYBACK_LEVEL_MIN 0 /* -96.0 dB + 1.5 dB = -94.5 dB (possible is down to (-114.0+1.5)dB) */ +#define MIXART_ANALOG_PLAYBACK_LEVEL_MAX 192 /* 0.0 dB + 1.5 dB = 1.5 dB */ +#define MIXART_ANALOG_PLAYBACK_ZERO_LEVEL 189 /* -1.5 dB + 1.5 dB = 0.0 dB */ + +static int mixart_update_analog_audio_level(mixart_t* chip, int is_capture) +{ + int i, err; + mixart_msg_t request; + mixart_io_level_t io_level; + mixart_return_uid_t resp; + + memset(&io_level, 0, sizeof(io_level)); + io_level.channel = -1; /* left and right */ + + for(i=0; i<2; i++) { + if(is_capture) { + io_level.level[i].analog_level = mixart_analog_level[chip->analog_capture_volume[i]]; + } else { + if(chip->analog_playback_active[i]) + io_level.level[i].analog_level = mixart_analog_level[chip->analog_playback_volume[i]]; + else + io_level.level[i].analog_level = mixart_analog_level[MIXART_ANALOG_PLAYBACK_LEVEL_MIN]; + } + } + + if(is_capture) request.uid = chip->uid_in_analog_physio; + else request.uid = chip->uid_out_analog_physio; + request.message_id = MSG_PHYSICALIO_SET_LEVEL; + request.data = &io_level; + request.size = sizeof(io_level); + + err = snd_mixart_send_msg(chip->mgr, &request, sizeof(resp), &resp); + if((err<0) || (resp.error_code)) { + snd_printk(KERN_DEBUG "error MSG_PHYSICALIO_SET_LEVEL card(%d) is_capture(%d) error_code(%x)\n", chip->chip_idx, is_capture, resp.error_code); + return -EINVAL; + } + return 0; +} + +/* + * analog level control + */ +static int mixart_analog_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + if(kcontrol->private_value == 0) { /* playback */ + uinfo->value.integer.min = MIXART_ANALOG_PLAYBACK_LEVEL_MIN; /* -96 dB */ + uinfo->value.integer.max = MIXART_ANALOG_PLAYBACK_LEVEL_MAX; /* 0 dB */ + } else { /* capture */ + uinfo->value.integer.min = MIXART_ANALOG_CAPTURE_LEVEL_MIN; /* -96 dB */ + uinfo->value.integer.max = MIXART_ANALOG_CAPTURE_LEVEL_MAX; /* 31.5 dB */ + } + return 0; +} + +static int mixart_analog_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + mixart_t *chip = snd_kcontrol_chip(kcontrol); + down(&chip->mgr->mixer_mutex); + if(kcontrol->private_value == 0) { /* playback */ + ucontrol->value.integer.value[0] = chip->analog_playback_volume[0]; + ucontrol->value.integer.value[1] = chip->analog_playback_volume[1]; + } else { /* capture */ + ucontrol->value.integer.value[0] = chip->analog_capture_volume[0]; + ucontrol->value.integer.value[1] = chip->analog_capture_volume[1]; + } + up(&chip->mgr->mixer_mutex); + return 0; +} + +static int mixart_analog_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + mixart_t *chip = snd_kcontrol_chip(kcontrol); + int changed = 0; + int is_capture, i; + + down(&chip->mgr->mixer_mutex); + is_capture = (kcontrol->private_value != 0); + for(i=0; i<2; i++) { + int new_volume = ucontrol->value.integer.value[i]; + int* stored_volume = is_capture ? &chip->analog_capture_volume[i] : &chip->analog_playback_volume[i]; + if(*stored_volume != new_volume) { + *stored_volume = new_volume; + changed = 1; + } + } + if(changed) mixart_update_analog_audio_level(chip, is_capture); + up(&chip->mgr->mixer_mutex); + return changed; +} + +static snd_kcontrol_new_t mixart_control_analog_level = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* name will be filled later */ + .info = mixart_analog_vol_info, + .get = mixart_analog_vol_get, + .put = mixart_analog_vol_put, +}; + +/* shared */ +static int mixart_sw_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int mixart_audio_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + mixart_t *chip = snd_kcontrol_chip(kcontrol); + + down(&chip->mgr->mixer_mutex); + ucontrol->value.integer.value[0] = chip->analog_playback_active[0]; + ucontrol->value.integer.value[1] = chip->analog_playback_active[1]; + up(&chip->mgr->mixer_mutex); + return 0; +} + +static int mixart_audio_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + mixart_t *chip = snd_kcontrol_chip(kcontrol); + int i, changed = 0; + down(&chip->mgr->mixer_mutex); + for(i=0; i<2; i++) { + if(chip->analog_playback_active[i] != ucontrol->value.integer.value[i]) { + chip->analog_playback_active[i] = ucontrol->value.integer.value[i]; + changed = 1; + } + } + if(changed) mixart_update_analog_audio_level(chip, 0); /* update playback levels */ + up(&chip->mgr->mixer_mutex); + return changed; +} + +static snd_kcontrol_new_t mixart_control_output_switch = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = mixart_sw_info, /* shared */ + .get = mixart_audio_sw_get, + .put = mixart_audio_sw_put +}; + +static u32 mixart_digital_level[256] = { + 0x00000000, /* [000] = 0.00e+000 = mute if <= -109.5dB */ + 0x366e1c7a, /* [001] = 3.55e-006 = pow(10.0, 0.05 * -109.0dB) */ + 0x367c3860, /* [002] = 3.76e-006 = pow(10.0, 0.05 * -108.5dB) */ + 0x36859525, /* [003] = 3.98e-006 = pow(10.0, 0.05 * -108.0dB) */ + 0x368d7f74, /* [004] = 4.22e-006 = pow(10.0, 0.05 * -107.5dB) */ + 0x3695e1d4, /* [005] = 4.47e-006 = pow(10.0, 0.05 * -107.0dB) */ + 0x369ec362, /* [006] = 4.73e-006 = pow(10.0, 0.05 * -106.5dB) */ + 0x36a82ba8, /* [007] = 5.01e-006 = pow(10.0, 0.05 * -106.0dB) */ + 0x36b222a0, /* [008] = 5.31e-006 = pow(10.0, 0.05 * -105.5dB) */ + 0x36bcb0c1, /* [009] = 5.62e-006 = pow(10.0, 0.05 * -105.0dB) */ + 0x36c7defd, /* [010] = 5.96e-006 = pow(10.0, 0.05 * -104.5dB) */ + 0x36d3b6d3, /* [011] = 6.31e-006 = pow(10.0, 0.05 * -104.0dB) */ + 0x36e0424e, /* [012] = 6.68e-006 = pow(10.0, 0.05 * -103.5dB) */ + 0x36ed8c14, /* [013] = 7.08e-006 = pow(10.0, 0.05 * -103.0dB) */ + 0x36fb9f6c, /* [014] = 7.50e-006 = pow(10.0, 0.05 * -102.5dB) */ + 0x37054423, /* [015] = 7.94e-006 = pow(10.0, 0.05 * -102.0dB) */ + 0x370d29a5, /* [016] = 8.41e-006 = pow(10.0, 0.05 * -101.5dB) */ + 0x371586f0, /* [017] = 8.91e-006 = pow(10.0, 0.05 * -101.0dB) */ + 0x371e631b, /* [018] = 9.44e-006 = pow(10.0, 0.05 * -100.5dB) */ + 0x3727c5ac, /* [019] = 1.00e-005 = pow(10.0, 0.05 * -100.0dB) */ + 0x3731b69a, /* [020] = 1.06e-005 = pow(10.0, 0.05 * -99.5dB) */ + 0x373c3e53, /* [021] = 1.12e-005 = pow(10.0, 0.05 * -99.0dB) */ + 0x374765c8, /* [022] = 1.19e-005 = pow(10.0, 0.05 * -98.5dB) */ + 0x3753366f, /* [023] = 1.26e-005 = pow(10.0, 0.05 * -98.0dB) */ + 0x375fba4f, /* [024] = 1.33e-005 = pow(10.0, 0.05 * -97.5dB) */ + 0x376cfc07, /* [025] = 1.41e-005 = pow(10.0, 0.05 * -97.0dB) */ + 0x377b06d5, /* [026] = 1.50e-005 = pow(10.0, 0.05 * -96.5dB) */ + 0x3784f352, /* [027] = 1.58e-005 = pow(10.0, 0.05 * -96.0dB) */ + 0x378cd40b, /* [028] = 1.68e-005 = pow(10.0, 0.05 * -95.5dB) */ + 0x37952c42, /* [029] = 1.78e-005 = pow(10.0, 0.05 * -95.0dB) */ + 0x379e030e, /* [030] = 1.88e-005 = pow(10.0, 0.05 * -94.5dB) */ + 0x37a75fef, /* [031] = 2.00e-005 = pow(10.0, 0.05 * -94.0dB) */ + 0x37b14ad5, /* [032] = 2.11e-005 = pow(10.0, 0.05 * -93.5dB) */ + 0x37bbcc2c, /* [033] = 2.24e-005 = pow(10.0, 0.05 * -93.0dB) */ + 0x37c6ecdd, /* [034] = 2.37e-005 = pow(10.0, 0.05 * -92.5dB) */ + 0x37d2b65a, /* [035] = 2.51e-005 = pow(10.0, 0.05 * -92.0dB) */ + 0x37df32a3, /* [036] = 2.66e-005 = pow(10.0, 0.05 * -91.5dB) */ + 0x37ec6c50, /* [037] = 2.82e-005 = pow(10.0, 0.05 * -91.0dB) */ + 0x37fa6e9b, /* [038] = 2.99e-005 = pow(10.0, 0.05 * -90.5dB) */ + 0x3804a2b3, /* [039] = 3.16e-005 = pow(10.0, 0.05 * -90.0dB) */ + 0x380c7ea4, /* [040] = 3.35e-005 = pow(10.0, 0.05 * -89.5dB) */ + 0x3814d1cc, /* [041] = 3.55e-005 = pow(10.0, 0.05 * -89.0dB) */ + 0x381da33c, /* [042] = 3.76e-005 = pow(10.0, 0.05 * -88.5dB) */ + 0x3826fa6f, /* [043] = 3.98e-005 = pow(10.0, 0.05 * -88.0dB) */ + 0x3830df51, /* [044] = 4.22e-005 = pow(10.0, 0.05 * -87.5dB) */ + 0x383b5a49, /* [045] = 4.47e-005 = pow(10.0, 0.05 * -87.0dB) */ + 0x3846743b, /* [046] = 4.73e-005 = pow(10.0, 0.05 * -86.5dB) */ + 0x38523692, /* [047] = 5.01e-005 = pow(10.0, 0.05 * -86.0dB) */ + 0x385eab48, /* [048] = 5.31e-005 = pow(10.0, 0.05 * -85.5dB) */ + 0x386bdcf1, /* [049] = 5.62e-005 = pow(10.0, 0.05 * -85.0dB) */ + 0x3879d6bc, /* [050] = 5.96e-005 = pow(10.0, 0.05 * -84.5dB) */ + 0x38845244, /* [051] = 6.31e-005 = pow(10.0, 0.05 * -84.0dB) */ + 0x388c2971, /* [052] = 6.68e-005 = pow(10.0, 0.05 * -83.5dB) */ + 0x3894778d, /* [053] = 7.08e-005 = pow(10.0, 0.05 * -83.0dB) */ + 0x389d43a4, /* [054] = 7.50e-005 = pow(10.0, 0.05 * -82.5dB) */ + 0x38a6952c, /* [055] = 7.94e-005 = pow(10.0, 0.05 * -82.0dB) */ + 0x38b0740f, /* [056] = 8.41e-005 = pow(10.0, 0.05 * -81.5dB) */ + 0x38bae8ac, /* [057] = 8.91e-005 = pow(10.0, 0.05 * -81.0dB) */ + 0x38c5fbe2, /* [058] = 9.44e-005 = pow(10.0, 0.05 * -80.5dB) */ + 0x38d1b717, /* [059] = 1.00e-004 = pow(10.0, 0.05 * -80.0dB) */ + 0x38de2440, /* [060] = 1.06e-004 = pow(10.0, 0.05 * -79.5dB) */ + 0x38eb4de8, /* [061] = 1.12e-004 = pow(10.0, 0.05 * -79.0dB) */ + 0x38f93f3a, /* [062] = 1.19e-004 = pow(10.0, 0.05 * -78.5dB) */ + 0x39040206, /* [063] = 1.26e-004 = pow(10.0, 0.05 * -78.0dB) */ + 0x390bd472, /* [064] = 1.33e-004 = pow(10.0, 0.05 * -77.5dB) */ + 0x39141d84, /* [065] = 1.41e-004 = pow(10.0, 0.05 * -77.0dB) */ + 0x391ce445, /* [066] = 1.50e-004 = pow(10.0, 0.05 * -76.5dB) */ + 0x39263027, /* [067] = 1.58e-004 = pow(10.0, 0.05 * -76.0dB) */ + 0x3930090d, /* [068] = 1.68e-004 = pow(10.0, 0.05 * -75.5dB) */ + 0x393a7753, /* [069] = 1.78e-004 = pow(10.0, 0.05 * -75.0dB) */ + 0x394583d2, /* [070] = 1.88e-004 = pow(10.0, 0.05 * -74.5dB) */ + 0x395137ea, /* [071] = 2.00e-004 = pow(10.0, 0.05 * -74.0dB) */ + 0x395d9d8a, /* [072] = 2.11e-004 = pow(10.0, 0.05 * -73.5dB) */ + 0x396abf37, /* [073] = 2.24e-004 = pow(10.0, 0.05 * -73.0dB) */ + 0x3978a814, /* [074] = 2.37e-004 = pow(10.0, 0.05 * -72.5dB) */ + 0x3983b1f8, /* [075] = 2.51e-004 = pow(10.0, 0.05 * -72.0dB) */ + 0x398b7fa6, /* [076] = 2.66e-004 = pow(10.0, 0.05 * -71.5dB) */ + 0x3993c3b2, /* [077] = 2.82e-004 = pow(10.0, 0.05 * -71.0dB) */ + 0x399c8521, /* [078] = 2.99e-004 = pow(10.0, 0.05 * -70.5dB) */ + 0x39a5cb5f, /* [079] = 3.16e-004 = pow(10.0, 0.05 * -70.0dB) */ + 0x39af9e4d, /* [080] = 3.35e-004 = pow(10.0, 0.05 * -69.5dB) */ + 0x39ba063f, /* [081] = 3.55e-004 = pow(10.0, 0.05 * -69.0dB) */ + 0x39c50c0b, /* [082] = 3.76e-004 = pow(10.0, 0.05 * -68.5dB) */ + 0x39d0b90a, /* [083] = 3.98e-004 = pow(10.0, 0.05 * -68.0dB) */ + 0x39dd1726, /* [084] = 4.22e-004 = pow(10.0, 0.05 * -67.5dB) */ + 0x39ea30db, /* [085] = 4.47e-004 = pow(10.0, 0.05 * -67.0dB) */ + 0x39f81149, /* [086] = 4.73e-004 = pow(10.0, 0.05 * -66.5dB) */ + 0x3a03621b, /* [087] = 5.01e-004 = pow(10.0, 0.05 * -66.0dB) */ + 0x3a0b2b0d, /* [088] = 5.31e-004 = pow(10.0, 0.05 * -65.5dB) */ + 0x3a136a16, /* [089] = 5.62e-004 = pow(10.0, 0.05 * -65.0dB) */ + 0x3a1c2636, /* [090] = 5.96e-004 = pow(10.0, 0.05 * -64.5dB) */ + 0x3a2566d5, /* [091] = 6.31e-004 = pow(10.0, 0.05 * -64.0dB) */ + 0x3a2f33cd, /* [092] = 6.68e-004 = pow(10.0, 0.05 * -63.5dB) */ + 0x3a399570, /* [093] = 7.08e-004 = pow(10.0, 0.05 * -63.0dB) */ + 0x3a44948c, /* [094] = 7.50e-004 = pow(10.0, 0.05 * -62.5dB) */ + 0x3a503a77, /* [095] = 7.94e-004 = pow(10.0, 0.05 * -62.0dB) */ + 0x3a5c9112, /* [096] = 8.41e-004 = pow(10.0, 0.05 * -61.5dB) */ + 0x3a69a2d7, /* [097] = 8.91e-004 = pow(10.0, 0.05 * -61.0dB) */ + 0x3a777ada, /* [098] = 9.44e-004 = pow(10.0, 0.05 * -60.5dB) */ + 0x3a83126f, /* [099] = 1.00e-003 = pow(10.0, 0.05 * -60.0dB) */ + 0x3a8ad6a8, /* [100] = 1.06e-003 = pow(10.0, 0.05 * -59.5dB) */ + 0x3a9310b1, /* [101] = 1.12e-003 = pow(10.0, 0.05 * -59.0dB) */ + 0x3a9bc784, /* [102] = 1.19e-003 = pow(10.0, 0.05 * -58.5dB) */ + 0x3aa50287, /* [103] = 1.26e-003 = pow(10.0, 0.05 * -58.0dB) */ + 0x3aaec98e, /* [104] = 1.33e-003 = pow(10.0, 0.05 * -57.5dB) */ + 0x3ab924e5, /* [105] = 1.41e-003 = pow(10.0, 0.05 * -57.0dB) */ + 0x3ac41d56, /* [106] = 1.50e-003 = pow(10.0, 0.05 * -56.5dB) */ + 0x3acfbc31, /* [107] = 1.58e-003 = pow(10.0, 0.05 * -56.0dB) */ + 0x3adc0b51, /* [108] = 1.68e-003 = pow(10.0, 0.05 * -55.5dB) */ + 0x3ae91528, /* [109] = 1.78e-003 = pow(10.0, 0.05 * -55.0dB) */ + 0x3af6e4c6, /* [110] = 1.88e-003 = pow(10.0, 0.05 * -54.5dB) */ + 0x3b02c2f2, /* [111] = 2.00e-003 = pow(10.0, 0.05 * -54.0dB) */ + 0x3b0a8276, /* [112] = 2.11e-003 = pow(10.0, 0.05 * -53.5dB) */ + 0x3b12b782, /* [113] = 2.24e-003 = pow(10.0, 0.05 * -53.0dB) */ + 0x3b1b690d, /* [114] = 2.37e-003 = pow(10.0, 0.05 * -52.5dB) */ + 0x3b249e76, /* [115] = 2.51e-003 = pow(10.0, 0.05 * -52.0dB) */ + 0x3b2e5f8f, /* [116] = 2.66e-003 = pow(10.0, 0.05 * -51.5dB) */ + 0x3b38b49f, /* [117] = 2.82e-003 = pow(10.0, 0.05 * -51.0dB) */ + 0x3b43a669, /* [118] = 2.99e-003 = pow(10.0, 0.05 * -50.5dB) */ + 0x3b4f3e37, /* [119] = 3.16e-003 = pow(10.0, 0.05 * -50.0dB) */ + 0x3b5b85e0, /* [120] = 3.35e-003 = pow(10.0, 0.05 * -49.5dB) */ + 0x3b6887cf, /* [121] = 3.55e-003 = pow(10.0, 0.05 * -49.0dB) */ + 0x3b764f0e, /* [122] = 3.76e-003 = pow(10.0, 0.05 * -48.5dB) */ + 0x3b8273a6, /* [123] = 3.98e-003 = pow(10.0, 0.05 * -48.0dB) */ + 0x3b8a2e77, /* [124] = 4.22e-003 = pow(10.0, 0.05 * -47.5dB) */ + 0x3b925e89, /* [125] = 4.47e-003 = pow(10.0, 0.05 * -47.0dB) */ + 0x3b9b0ace, /* [126] = 4.73e-003 = pow(10.0, 0.05 * -46.5dB) */ + 0x3ba43aa2, /* [127] = 5.01e-003 = pow(10.0, 0.05 * -46.0dB) */ + 0x3badf5d1, /* [128] = 5.31e-003 = pow(10.0, 0.05 * -45.5dB) */ + 0x3bb8449c, /* [129] = 5.62e-003 = pow(10.0, 0.05 * -45.0dB) */ + 0x3bc32fc3, /* [130] = 5.96e-003 = pow(10.0, 0.05 * -44.5dB) */ + 0x3bcec08a, /* [131] = 6.31e-003 = pow(10.0, 0.05 * -44.0dB) */ + 0x3bdb00c0, /* [132] = 6.68e-003 = pow(10.0, 0.05 * -43.5dB) */ + 0x3be7facc, /* [133] = 7.08e-003 = pow(10.0, 0.05 * -43.0dB) */ + 0x3bf5b9b0, /* [134] = 7.50e-003 = pow(10.0, 0.05 * -42.5dB) */ + 0x3c02248a, /* [135] = 7.94e-003 = pow(10.0, 0.05 * -42.0dB) */ + 0x3c09daac, /* [136] = 8.41e-003 = pow(10.0, 0.05 * -41.5dB) */ + 0x3c1205c6, /* [137] = 8.91e-003 = pow(10.0, 0.05 * -41.0dB) */ + 0x3c1aacc8, /* [138] = 9.44e-003 = pow(10.0, 0.05 * -40.5dB) */ + 0x3c23d70a, /* [139] = 1.00e-002 = pow(10.0, 0.05 * -40.0dB) */ + 0x3c2d8c52, /* [140] = 1.06e-002 = pow(10.0, 0.05 * -39.5dB) */ + 0x3c37d4dd, /* [141] = 1.12e-002 = pow(10.0, 0.05 * -39.0dB) */ + 0x3c42b965, /* [142] = 1.19e-002 = pow(10.0, 0.05 * -38.5dB) */ + 0x3c4e4329, /* [143] = 1.26e-002 = pow(10.0, 0.05 * -38.0dB) */ + 0x3c5a7bf1, /* [144] = 1.33e-002 = pow(10.0, 0.05 * -37.5dB) */ + 0x3c676e1e, /* [145] = 1.41e-002 = pow(10.0, 0.05 * -37.0dB) */ + 0x3c7524ac, /* [146] = 1.50e-002 = pow(10.0, 0.05 * -36.5dB) */ + 0x3c81d59f, /* [147] = 1.58e-002 = pow(10.0, 0.05 * -36.0dB) */ + 0x3c898712, /* [148] = 1.68e-002 = pow(10.0, 0.05 * -35.5dB) */ + 0x3c91ad39, /* [149] = 1.78e-002 = pow(10.0, 0.05 * -35.0dB) */ + 0x3c9a4efc, /* [150] = 1.88e-002 = pow(10.0, 0.05 * -34.5dB) */ + 0x3ca373af, /* [151] = 2.00e-002 = pow(10.0, 0.05 * -34.0dB) */ + 0x3cad2314, /* [152] = 2.11e-002 = pow(10.0, 0.05 * -33.5dB) */ + 0x3cb76563, /* [153] = 2.24e-002 = pow(10.0, 0.05 * -33.0dB) */ + 0x3cc24350, /* [154] = 2.37e-002 = pow(10.0, 0.05 * -32.5dB) */ + 0x3ccdc614, /* [155] = 2.51e-002 = pow(10.0, 0.05 * -32.0dB) */ + 0x3cd9f773, /* [156] = 2.66e-002 = pow(10.0, 0.05 * -31.5dB) */ + 0x3ce6e1c6, /* [157] = 2.82e-002 = pow(10.0, 0.05 * -31.0dB) */ + 0x3cf49003, /* [158] = 2.99e-002 = pow(10.0, 0.05 * -30.5dB) */ + 0x3d0186e2, /* [159] = 3.16e-002 = pow(10.0, 0.05 * -30.0dB) */ + 0x3d0933ac, /* [160] = 3.35e-002 = pow(10.0, 0.05 * -29.5dB) */ + 0x3d1154e1, /* [161] = 3.55e-002 = pow(10.0, 0.05 * -29.0dB) */ + 0x3d19f169, /* [162] = 3.76e-002 = pow(10.0, 0.05 * -28.5dB) */ + 0x3d231090, /* [163] = 3.98e-002 = pow(10.0, 0.05 * -28.0dB) */ + 0x3d2cba15, /* [164] = 4.22e-002 = pow(10.0, 0.05 * -27.5dB) */ + 0x3d36f62b, /* [165] = 4.47e-002 = pow(10.0, 0.05 * -27.0dB) */ + 0x3d41cd81, /* [166] = 4.73e-002 = pow(10.0, 0.05 * -26.5dB) */ + 0x3d4d494a, /* [167] = 5.01e-002 = pow(10.0, 0.05 * -26.0dB) */ + 0x3d597345, /* [168] = 5.31e-002 = pow(10.0, 0.05 * -25.5dB) */ + 0x3d6655c3, /* [169] = 5.62e-002 = pow(10.0, 0.05 * -25.0dB) */ + 0x3d73fbb4, /* [170] = 5.96e-002 = pow(10.0, 0.05 * -24.5dB) */ + 0x3d813856, /* [171] = 6.31e-002 = pow(10.0, 0.05 * -24.0dB) */ + 0x3d88e078, /* [172] = 6.68e-002 = pow(10.0, 0.05 * -23.5dB) */ + 0x3d90fcbf, /* [173] = 7.08e-002 = pow(10.0, 0.05 * -23.0dB) */ + 0x3d99940e, /* [174] = 7.50e-002 = pow(10.0, 0.05 * -22.5dB) */ + 0x3da2adad, /* [175] = 7.94e-002 = pow(10.0, 0.05 * -22.0dB) */ + 0x3dac5156, /* [176] = 8.41e-002 = pow(10.0, 0.05 * -21.5dB) */ + 0x3db68738, /* [177] = 8.91e-002 = pow(10.0, 0.05 * -21.0dB) */ + 0x3dc157fb, /* [178] = 9.44e-002 = pow(10.0, 0.05 * -20.5dB) */ + 0x3dcccccd, /* [179] = 1.00e-001 = pow(10.0, 0.05 * -20.0dB) */ + 0x3dd8ef67, /* [180] = 1.06e-001 = pow(10.0, 0.05 * -19.5dB) */ + 0x3de5ca15, /* [181] = 1.12e-001 = pow(10.0, 0.05 * -19.0dB) */ + 0x3df367bf, /* [182] = 1.19e-001 = pow(10.0, 0.05 * -18.5dB) */ + 0x3e00e9f9, /* [183] = 1.26e-001 = pow(10.0, 0.05 * -18.0dB) */ + 0x3e088d77, /* [184] = 1.33e-001 = pow(10.0, 0.05 * -17.5dB) */ + 0x3e10a4d3, /* [185] = 1.41e-001 = pow(10.0, 0.05 * -17.0dB) */ + 0x3e1936ec, /* [186] = 1.50e-001 = pow(10.0, 0.05 * -16.5dB) */ + 0x3e224b06, /* [187] = 1.58e-001 = pow(10.0, 0.05 * -16.0dB) */ + 0x3e2be8d7, /* [188] = 1.68e-001 = pow(10.0, 0.05 * -15.5dB) */ + 0x3e361887, /* [189] = 1.78e-001 = pow(10.0, 0.05 * -15.0dB) */ + 0x3e40e2bb, /* [190] = 1.88e-001 = pow(10.0, 0.05 * -14.5dB) */ + 0x3e4c509b, /* [191] = 2.00e-001 = pow(10.0, 0.05 * -14.0dB) */ + 0x3e586bd9, /* [192] = 2.11e-001 = pow(10.0, 0.05 * -13.5dB) */ + 0x3e653ebb, /* [193] = 2.24e-001 = pow(10.0, 0.05 * -13.0dB) */ + 0x3e72d424, /* [194] = 2.37e-001 = pow(10.0, 0.05 * -12.5dB) */ + 0x3e809bcc, /* [195] = 2.51e-001 = pow(10.0, 0.05 * -12.0dB) */ + 0x3e883aa8, /* [196] = 2.66e-001 = pow(10.0, 0.05 * -11.5dB) */ + 0x3e904d1c, /* [197] = 2.82e-001 = pow(10.0, 0.05 * -11.0dB) */ + 0x3e98da02, /* [198] = 2.99e-001 = pow(10.0, 0.05 * -10.5dB) */ + 0x3ea1e89b, /* [199] = 3.16e-001 = pow(10.0, 0.05 * -10.0dB) */ + 0x3eab8097, /* [200] = 3.35e-001 = pow(10.0, 0.05 * -9.5dB) */ + 0x3eb5aa1a, /* [201] = 3.55e-001 = pow(10.0, 0.05 * -9.0dB) */ + 0x3ec06dc3, /* [202] = 3.76e-001 = pow(10.0, 0.05 * -8.5dB) */ + 0x3ecbd4b4, /* [203] = 3.98e-001 = pow(10.0, 0.05 * -8.0dB) */ + 0x3ed7e89b, /* [204] = 4.22e-001 = pow(10.0, 0.05 * -7.5dB) */ + 0x3ee4b3b6, /* [205] = 4.47e-001 = pow(10.0, 0.05 * -7.0dB) */ + 0x3ef240e2, /* [206] = 4.73e-001 = pow(10.0, 0.05 * -6.5dB) */ + 0x3f004dce, /* [207] = 5.01e-001 = pow(10.0, 0.05 * -6.0dB) */ + 0x3f07e80b, /* [208] = 5.31e-001 = pow(10.0, 0.05 * -5.5dB) */ + 0x3f0ff59a, /* [209] = 5.62e-001 = pow(10.0, 0.05 * -5.0dB) */ + 0x3f187d50, /* [210] = 5.96e-001 = pow(10.0, 0.05 * -4.5dB) */ + 0x3f21866c, /* [211] = 6.31e-001 = pow(10.0, 0.05 * -4.0dB) */ + 0x3f2b1896, /* [212] = 6.68e-001 = pow(10.0, 0.05 * -3.5dB) */ + 0x3f353bef, /* [213] = 7.08e-001 = pow(10.0, 0.05 * -3.0dB) */ + 0x3f3ff911, /* [214] = 7.50e-001 = pow(10.0, 0.05 * -2.5dB) */ + 0x3f4b5918, /* [215] = 7.94e-001 = pow(10.0, 0.05 * -2.0dB) */ + 0x3f5765ac, /* [216] = 8.41e-001 = pow(10.0, 0.05 * -1.5dB) */ + 0x3f642905, /* [217] = 8.91e-001 = pow(10.0, 0.05 * -1.0dB) */ + 0x3f71adf9, /* [218] = 9.44e-001 = pow(10.0, 0.05 * -0.5dB) */ + 0x3f800000, /* [219] = 1.00e+000 = pow(10.0, 0.05 * 0.0dB) */ + 0x3f8795a0, /* [220] = 1.06e+000 = pow(10.0, 0.05 * 0.5dB) */ + 0x3f8f9e4d, /* [221] = 1.12e+000 = pow(10.0, 0.05 * 1.0dB) */ + 0x3f9820d7, /* [222] = 1.19e+000 = pow(10.0, 0.05 * 1.5dB) */ + 0x3fa12478, /* [223] = 1.26e+000 = pow(10.0, 0.05 * 2.0dB) */ + 0x3faab0d5, /* [224] = 1.33e+000 = pow(10.0, 0.05 * 2.5dB) */ + 0x3fb4ce08, /* [225] = 1.41e+000 = pow(10.0, 0.05 * 3.0dB) */ + 0x3fbf84a6, /* [226] = 1.50e+000 = pow(10.0, 0.05 * 3.5dB) */ + 0x3fcaddc8, /* [227] = 1.58e+000 = pow(10.0, 0.05 * 4.0dB) */ + 0x3fd6e30d, /* [228] = 1.68e+000 = pow(10.0, 0.05 * 4.5dB) */ + 0x3fe39ea9, /* [229] = 1.78e+000 = pow(10.0, 0.05 * 5.0dB) */ + 0x3ff11b6a, /* [230] = 1.88e+000 = pow(10.0, 0.05 * 5.5dB) */ + 0x3fff64c1, /* [231] = 2.00e+000 = pow(10.0, 0.05 * 6.0dB) */ + 0x40074368, /* [232] = 2.11e+000 = pow(10.0, 0.05 * 6.5dB) */ + 0x400f4735, /* [233] = 2.24e+000 = pow(10.0, 0.05 * 7.0dB) */ + 0x4017c496, /* [234] = 2.37e+000 = pow(10.0, 0.05 * 7.5dB) */ + 0x4020c2bf, /* [235] = 2.51e+000 = pow(10.0, 0.05 * 8.0dB) */ + 0x402a4952, /* [236] = 2.66e+000 = pow(10.0, 0.05 * 8.5dB) */ + 0x40346063, /* [237] = 2.82e+000 = pow(10.0, 0.05 * 9.0dB) */ + 0x403f1082, /* [238] = 2.99e+000 = pow(10.0, 0.05 * 9.5dB) */ + 0x404a62c2, /* [239] = 3.16e+000 = pow(10.0, 0.05 * 10.0dB) */ + 0x405660bd, /* [240] = 3.35e+000 = pow(10.0, 0.05 * 10.5dB) */ + 0x406314a0, /* [241] = 3.55e+000 = pow(10.0, 0.05 * 11.0dB) */ + 0x40708933, /* [242] = 3.76e+000 = pow(10.0, 0.05 * 11.5dB) */ + 0x407ec9e1, /* [243] = 3.98e+000 = pow(10.0, 0.05 * 12.0dB) */ + 0x4086f161, /* [244] = 4.22e+000 = pow(10.0, 0.05 * 12.5dB) */ + 0x408ef052, /* [245] = 4.47e+000 = pow(10.0, 0.05 * 13.0dB) */ + 0x4097688d, /* [246] = 4.73e+000 = pow(10.0, 0.05 * 13.5dB) */ + 0x40a06142, /* [247] = 5.01e+000 = pow(10.0, 0.05 * 14.0dB) */ + 0x40a9e20e, /* [248] = 5.31e+000 = pow(10.0, 0.05 * 14.5dB) */ + 0x40b3f300, /* [249] = 5.62e+000 = pow(10.0, 0.05 * 15.0dB) */ + 0x40be9ca5, /* [250] = 5.96e+000 = pow(10.0, 0.05 * 15.5dB) */ + 0x40c9e807, /* [251] = 6.31e+000 = pow(10.0, 0.05 * 16.0dB) */ + 0x40d5debc, /* [252] = 6.68e+000 = pow(10.0, 0.05 * 16.5dB) */ + 0x40e28aeb, /* [253] = 7.08e+000 = pow(10.0, 0.05 * 17.0dB) */ + 0x40eff755, /* [254] = 7.50e+000 = pow(10.0, 0.05 * 17.5dB) */ + 0x40fe2f5e, /* [255] = 7.94e+000 = pow(10.0, 0.05 * 18.0dB) */ +}; + +#define MIXART_DIGITAL_LEVEL_MIN 0 /* -109.5 dB */ +#define MIXART_DIGITAL_LEVEL_MAX 255 /* 18.0 dB */ +#define MIXART_DIGITAL_ZERO_LEVEL 219 /* 0.0 dB */ + + +int mixart_update_playback_stream_level(mixart_t* chip, int is_aes, int idx) +{ + int err, i; + int volume[2]; + mixart_msg_t request; + mixart_set_out_stream_level_req_t set_level; + u32 status; + mixart_pipe_t *pipe; + + memset(&set_level, 0, sizeof(set_level)); + set_level.nb_of_stream = 1; + set_level.stream_level.desc.stream_idx = idx; + + if(is_aes) { + pipe = &chip->pipe_out_dig; /* AES playback */ + idx += MIXART_PLAYBACK_STREAMS; + } else { + pipe = &chip->pipe_out_ana; /* analog playback */ + } + + /* only when pipe exists ! */ + if(pipe->status == PIPE_UNDEFINED) + return 0; + + set_level.stream_level.desc.uid_pipe = pipe->group_uid; + + for(i=0; i<2; i++) { + if(chip->digital_playback_active[idx][i]) + volume[i] = chip->digital_playback_volume[idx][i]; + else + volume[i] = MIXART_DIGITAL_LEVEL_MIN; + } + + set_level.stream_level.out_level.valid_mask1 = MIXART_OUT_STREAM_SET_LEVEL_LEFT_AUDIO1 | MIXART_OUT_STREAM_SET_LEVEL_RIGHT_AUDIO2; + set_level.stream_level.out_level.left_to_out1_level = mixart_digital_level[volume[0]]; + set_level.stream_level.out_level.right_to_out2_level = mixart_digital_level[volume[1]]; + + request.message_id = MSG_STREAM_SET_OUT_STREAM_LEVEL; + request.uid = (mixart_uid_t){0,0}; + request.data = &set_level; + request.size = sizeof(set_level); + + err = snd_mixart_send_msg(chip->mgr, &request, sizeof(status), &status); + if((err<0) || status) { + snd_printk(KERN_DEBUG "error MSG_STREAM_SET_OUT_STREAM_LEVEL card(%d) status(%x)\n", chip->chip_idx, status); + return -EINVAL; + } + return 0; +} + +int mixart_update_capture_stream_level(mixart_t* chip, int is_aes) +{ + int err, i, idx; + mixart_pipe_t* pipe; + mixart_msg_t request; + mixart_set_in_audio_level_req_t set_level; + u32 status; + + if(is_aes) { + idx = 1; + pipe = &chip->pipe_in_dig; + } else { + idx = 0; + pipe = &chip->pipe_in_ana; + } + + /* only when pipe exists ! */ + if(pipe->status == PIPE_UNDEFINED) + return 0; + + memset(&set_level, 0, sizeof(set_level)); + set_level.audio_count = 2; + set_level.level[0].connector = pipe->uid_left_connector; + set_level.level[1].connector = pipe->uid_right_connector; + + for(i=0; i<2; i++) { + set_level.level[i].valid_mask1 = MIXART_AUDIO_LEVEL_DIGITAL_MASK; + set_level.level[i].digital_level = mixart_digital_level[chip->digital_capture_volume[idx][i]]; + } + + request.message_id = MSG_STREAM_SET_IN_AUDIO_LEVEL; + request.uid = (mixart_uid_t){0,0}; + request.data = &set_level; + request.size = sizeof(set_level); + + err = snd_mixart_send_msg(chip->mgr, &request, sizeof(status), &status); + if((err<0) || status) { + snd_printk(KERN_DEBUG "error MSG_STREAM_SET_IN_AUDIO_LEVEL card(%d) status(%x)\n", chip->chip_idx, status); + return -EINVAL; + } + return 0; +} + + +/* shared */ +static int mixart_digital_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = MIXART_DIGITAL_LEVEL_MIN; /* -109.5 dB */ + uinfo->value.integer.max = MIXART_DIGITAL_LEVEL_MAX; /* 18.0 dB */ + return 0; +} + +#define MIXART_VOL_REC_MASK 1 +#define MIXART_VOL_AES_MASK 2 + +static int mixart_pcm_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + mixart_t *chip = snd_kcontrol_chip(kcontrol); + int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ + int *stored_volume; + int is_capture = kcontrol->private_value & MIXART_VOL_REC_MASK; + int is_aes = kcontrol->private_value & MIXART_VOL_AES_MASK; + down(&chip->mgr->mixer_mutex); + if(is_capture) { + if(is_aes) stored_volume = chip->digital_capture_volume[1]; /* AES capture */ + else stored_volume = chip->digital_capture_volume[0]; /* analog capture */ + } else { + snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); + if(is_aes) stored_volume = chip->digital_playback_volume[MIXART_PLAYBACK_STREAMS + idx]; /* AES playback */ + else stored_volume = chip->digital_playback_volume[idx]; /* analog playback */ + } + ucontrol->value.integer.value[0] = stored_volume[0]; + ucontrol->value.integer.value[1] = stored_volume[1]; + up(&chip->mgr->mixer_mutex); + return 0; +} + +static int mixart_pcm_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + mixart_t *chip = snd_kcontrol_chip(kcontrol); + int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ + int changed = 0; + int is_capture = kcontrol->private_value & MIXART_VOL_REC_MASK; + int is_aes = kcontrol->private_value & MIXART_VOL_AES_MASK; + int* stored_volume; + int i; + down(&chip->mgr->mixer_mutex); + if(is_capture) { + if(is_aes) stored_volume = chip->digital_capture_volume[1]; /* AES capture */ + else stored_volume = chip->digital_capture_volume[0]; /* analog capture */ + } else { + snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); + if(is_aes) stored_volume = chip->digital_playback_volume[MIXART_PLAYBACK_STREAMS + idx]; /* AES playback */ + else stored_volume = chip->digital_playback_volume[idx]; /* analog playback */ + } + for(i=0; i<2; i++) { + if(stored_volume[i] != ucontrol->value.integer.value[i]) { + stored_volume[i] = ucontrol->value.integer.value[i]; + changed = 1; + } + } + if(changed) { + if(is_capture) mixart_update_capture_stream_level(chip, is_aes); + else mixart_update_playback_stream_level(chip, is_aes, idx); + } + up(&chip->mgr->mixer_mutex); + return changed; +} + +static snd_kcontrol_new_t snd_mixart_pcm_vol = +{ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* name will be filled later */ + /* count will be filled later */ + .info = mixart_digital_vol_info, /* shared */ + .get = mixart_pcm_vol_get, + .put = mixart_pcm_vol_put, +}; + + +static int mixart_pcm_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + mixart_t *chip = snd_kcontrol_chip(kcontrol); + int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ + snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); + down(&chip->mgr->mixer_mutex); + if(kcontrol->private_value & MIXART_VOL_AES_MASK) /* AES playback */ + idx += MIXART_PLAYBACK_STREAMS; + ucontrol->value.integer.value[0] = chip->digital_playback_active[idx][0]; + ucontrol->value.integer.value[1] = chip->digital_playback_active[idx][1]; + up(&chip->mgr->mixer_mutex); + return 0; +} + +static int mixart_pcm_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + mixart_t *chip = snd_kcontrol_chip(kcontrol); + int changed = 0; + int is_aes = kcontrol->private_value & MIXART_VOL_AES_MASK; + int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); /* index */ + int i, j; + snd_assert ( idx < MIXART_PLAYBACK_STREAMS ); + down(&chip->mgr->mixer_mutex); + j = idx; + if(is_aes) j += MIXART_PLAYBACK_STREAMS; + for(i=0; i<2; i++) { + if(chip->digital_playback_active[j][i] != ucontrol->value.integer.value[i]) { + chip->digital_playback_active[j][i] = ucontrol->value.integer.value[i]; + changed = 1; + } + } + if(changed) mixart_update_playback_stream_level(chip, is_aes, idx); + up(&chip->mgr->mixer_mutex); + return changed; +} + +static snd_kcontrol_new_t mixart_control_pcm_switch = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* name will be filled later */ + .count = MIXART_PLAYBACK_STREAMS, + .info = mixart_sw_info, /* shared */ + .get = mixart_pcm_sw_get, + .put = mixart_pcm_sw_put +}; + +static int mixart_update_monitoring(mixart_t* chip, int channel) +{ + int err; + mixart_msg_t request; + mixart_set_out_audio_level_t audio_level; + u32 resp; + + if(chip->pipe_out_ana.status == PIPE_UNDEFINED) + return -EINVAL; /* no pipe defined */ + + if(!channel) request.uid = chip->pipe_out_ana.uid_left_connector; + else request.uid = chip->pipe_out_ana.uid_right_connector; + request.message_id = MSG_CONNECTOR_SET_OUT_AUDIO_LEVEL; + request.data = &audio_level; + request.size = sizeof(audio_level); + + memset(&audio_level, 0, sizeof(audio_level)); + audio_level.valid_mask1 = MIXART_AUDIO_LEVEL_MONITOR_MASK | MIXART_AUDIO_LEVEL_MUTE_M1_MASK; + audio_level.monitor_level = mixart_digital_level[chip->monitoring_volume[channel!=0]]; + audio_level.monitor_mute1 = !chip->monitoring_active[channel!=0]; + + err = snd_mixart_send_msg(chip->mgr, &request, sizeof(resp), &resp); + if((err<0) || resp) { + snd_printk(KERN_DEBUG "error MSG_CONNECTOR_SET_OUT_AUDIO_LEVEL card(%d) resp(%x)\n", chip->chip_idx, resp); + return -EINVAL; + } + return 0; +} + +/* + * monitoring level control + */ + +static int mixart_monitor_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + mixart_t *chip = snd_kcontrol_chip(kcontrol); + down(&chip->mgr->mixer_mutex); + ucontrol->value.integer.value[0] = chip->monitoring_volume[0]; + ucontrol->value.integer.value[1] = chip->monitoring_volume[1]; + up(&chip->mgr->mixer_mutex); + return 0; +} + +static int mixart_monitor_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + mixart_t *chip = snd_kcontrol_chip(kcontrol); + int changed = 0; + int i; + down(&chip->mgr->mixer_mutex); + for(i=0; i<2; i++) { + if(chip->monitoring_volume[i] != ucontrol->value.integer.value[i]) { + chip->monitoring_volume[i] = ucontrol->value.integer.value[i]; + mixart_update_monitoring(chip, i); + changed = 1; + } + } + up(&chip->mgr->mixer_mutex); + return changed; +} + +static snd_kcontrol_new_t mixart_control_monitor_vol = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Monitoring Volume", + .info = mixart_digital_vol_info, /* shared */ + .get = mixart_monitor_vol_get, + .put = mixart_monitor_vol_put, +}; + +/* + * monitoring switch control + */ + +static int mixart_monitor_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + mixart_t *chip = snd_kcontrol_chip(kcontrol); + down(&chip->mgr->mixer_mutex); + ucontrol->value.integer.value[0] = chip->monitoring_active[0]; + ucontrol->value.integer.value[1] = chip->monitoring_active[1]; + up(&chip->mgr->mixer_mutex); + return 0; +} + +static int mixart_monitor_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + mixart_t *chip = snd_kcontrol_chip(kcontrol); + int changed = 0; + int i; + down(&chip->mgr->mixer_mutex); + for(i=0; i<2; i++) { + if(chip->monitoring_active[i] != ucontrol->value.integer.value[i]) { + chip->monitoring_active[i] = ucontrol->value.integer.value[i]; + changed |= (1<monitoring_active[0] || chip->monitoring_active[1]; + if(allocate) { + snd_mixart_add_ref_pipe( chip, MIXART_PCM_ANALOG, 0, 1); /* allocate the playback pipe for monitoring */ + snd_mixart_add_ref_pipe( chip, MIXART_PCM_ANALOG, 1, 1); /* allocate the capture pipe for monitoring */ + } + if(changed & 0x01) mixart_update_monitoring(chip, 0); + if(changed & 0x02) mixart_update_monitoring(chip, 1); + if(!allocate) { + snd_mixart_kill_ref_pipe( chip->mgr, &chip->pipe_in_ana, 1); /* release the capture pipe for monitoring */ + snd_mixart_kill_ref_pipe( chip->mgr, &chip->pipe_out_ana, 1); /* release the playback pipe for monitoring */ + } + } + + up(&chip->mgr->mixer_mutex); + return (changed != 0); +} + +static snd_kcontrol_new_t mixart_control_monitor_sw = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Monitoring Switch", + .info = mixart_sw_info, /* shared */ + .get = mixart_monitor_sw_get, + .put = mixart_monitor_sw_put +}; + + +static void mixart_reset_audio_levels(mixart_t *chip) +{ + /* analog volumes can be set even if there is no pipe */ + mixart_update_analog_audio_level(chip, 0); + /* analog levels for capture only on the first two chips */ + if(chip->chip_idx < 2) { + mixart_update_analog_audio_level(chip, 1); + } + return; +} + + +int snd_mixart_create_mixer(mixart_mgr_t *mgr) +{ + mixart_t *chip; + int err, i; + + init_MUTEX(&mgr->mixer_mutex); /* can be in another place */ + + for(i=0; inum_cards; i++) { + snd_kcontrol_new_t temp; + chip = mgr->chip[i]; + + /* analog output level control */ + temp = mixart_control_analog_level; + temp.name = "Master Playback Volume"; + temp.private_value = 0; /* playback */ + if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) + return err; + /* output mute controls */ + if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&mixart_control_output_switch, chip))) < 0) + return err; + + /* analog input level control only on first two chips !*/ + if(i<2) { + temp = mixart_control_analog_level; + temp.name = "Master Capture Volume"; + temp.private_value = 1; /* capture */ + if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) + return err; + } + + temp = snd_mixart_pcm_vol; + temp.name = "PCM Playback Volume"; + temp.count = MIXART_PLAYBACK_STREAMS; + temp.private_value = 0; /* playback analog */ + if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) + return err; + + temp.name = "PCM Capture Volume"; + temp.count = 1; + temp.private_value = MIXART_VOL_REC_MASK; /* capture analog */ + if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) + return err; + + if(mgr->board_type == MIXART_DAUGHTER_TYPE_AES) { + temp.name = "AES Playback Volume"; + temp.count = MIXART_PLAYBACK_STREAMS; + temp.private_value = MIXART_VOL_AES_MASK; /* playback AES/EBU */ + if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) + return err; + + temp.name = "AES Capture Volume"; + temp.count = 0; + temp.private_value = MIXART_VOL_REC_MASK | MIXART_VOL_AES_MASK; /* capture AES/EBU */ + if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) + return err; + } + temp = mixart_control_pcm_switch; + temp.name = "PCM Playback Switch"; + temp.private_value = 0; /* playback analog */ + if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) + return err; + + if(mgr->board_type == MIXART_DAUGHTER_TYPE_AES) { + temp.name = "AES Playback Switch"; + temp.private_value = MIXART_VOL_AES_MASK; /* playback AES/EBU */ + if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&temp, chip))) < 0) + return err; + } + + /* monitoring */ + if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&mixart_control_monitor_vol, chip))) < 0) + return err; + if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&mixart_control_monitor_sw, chip))) < 0) + return err; + + /* init all mixer data and program the master volumes/switches */ + mixart_reset_audio_levels(chip); + } + return 0; +} diff -Nru a/sound/pci/mixart/mixart_mixer.h b/sound/pci/mixart/mixart_mixer.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/mixart/mixart_mixer.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,31 @@ +/* + * Driver for Digigram miXart soundcards + * + * include file for mixer + * + * Copyright (c) 2003 by Digigram + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __SOUND_MIXART_MIXER_H +#define __SOUND_MIXART_MIXER_H + +/* exported */ +int mixart_update_playback_stream_level(mixart_t* chip, int is_aes, int idx); +int mixart_update_capture_stream_level(mixart_t* chip, int is_aes); +int snd_mixart_create_mixer(mixart_mgr_t* mgr); + +#endif /* __SOUND_MIXART_MIXER_H */ diff -Nru a/sound/pci/rme32.c b/sound/pci/rme32.c --- a/sound/pci/rme32.c Sun Mar 14 14:20:08 2004 +++ b/sound/pci/rme32.c Sun Mar 14 14:20:08 2004 @@ -1378,9 +1378,10 @@ rme32->spdif_pcm->info_flags = 0; snd_pcm_lib_preallocate_pages_for_all(rme32->spdif_pcm, + SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), RME32_BUFFER_SIZE, - RME32_BUFFER_SIZE, - GFP_KERNEL); + RME32_BUFFER_SIZE); /* set up ALSA pcm device for ADAT */ if ((pci->device == PCI_DEVICE_ID_DIGI32) || @@ -1405,9 +1406,10 @@ rme32->adat_pcm->info_flags = 0; snd_pcm_lib_preallocate_pages_for_all(rme32->adat_pcm, + SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), RME32_BUFFER_SIZE, - RME32_BUFFER_SIZE, - GFP_KERNEL); + RME32_BUFFER_SIZE); } diff -Nru a/sound/pci/rme96.c b/sound/pci/rme96.c --- a/sound/pci/rme96.c Sun Mar 14 14:20:07 2004 +++ b/sound/pci/rme96.c Sun Mar 14 14:20:07 2004 @@ -1718,7 +1718,11 @@ rme96->spdif_pcm->info_flags = 0; - snd_pcm_lib_preallocate_pages_for_all(rme96->spdif_pcm, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE, GFP_KERNEL); + snd_pcm_lib_preallocate_pages_for_all(rme96->spdif_pcm, + SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), + RME96_BUFFER_SIZE, + RME96_BUFFER_SIZE); /* set up ALSA pcm device for ADAT */ if (pci->device == PCI_DEVICE_ID_DIGI96) { @@ -1738,7 +1742,11 @@ rme96->adat_pcm->info_flags = 0; - snd_pcm_lib_preallocate_pages_for_all(rme96->adat_pcm, RME96_BUFFER_SIZE, RME96_BUFFER_SIZE, GFP_KERNEL); + snd_pcm_lib_preallocate_pages_for_all(rme96->adat_pcm, + SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), + RME96_BUFFER_SIZE, + RME96_BUFFER_SIZE); } rme96->playback_periodsize = 0; diff -Nru a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c --- a/sound/pci/rme9652/hdsp.c Sun Mar 14 14:20:06 2004 +++ b/sound/pci/rme9652/hdsp.c Sun Mar 14 14:20:06 2004 @@ -568,7 +568,10 @@ struct snd_dma_device pdev; struct snd_dma_buffer dmbuf; - snd_dma_device_pci(&pdev, pci, capture); + memset(&pdev, 0, sizeof(pdev)); + pdev.type = SNDRV_DMA_TYPE_DEV; + pdev.dev = snd_dma_pci_data(pci); + pdev.id = capture; dmbuf.bytes = 0; if (! snd_dma_get_reserved(&pdev, &dmbuf)) { if (snd_dma_alloc_pages(&pdev, size, &dmbuf) < 0) @@ -581,9 +584,13 @@ static void snd_hammerfall_free_buffer(struct pci_dev *pci, size_t size, void *ptr, dma_addr_t addr, int capture) { - struct snd_dma_device dev; - snd_dma_device_pci(&dev, pci, capture); - snd_dma_free_reserved(&dev); + struct snd_dma_device pdev; + + memset(&pdev, 0, sizeof(pdev)); + pdev.type = SNDRV_DMA_TYPE_DEV; + pdev.dev = snd_dma_pci_data(pci); + pdev.id = capture; + snd_dma_free_reserved(&pdev); } #else @@ -3810,7 +3817,7 @@ { int mapped_channel; - snd_assert(channel >= 0 || channel < hdsp->max_channels, return NULL); + snd_assert(channel >= 0 && channel < hdsp->max_channels, return NULL); if ((mapped_channel = hdsp->channel_map[channel]) < 0) { return NULL; @@ -3833,7 +3840,8 @@ channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel); snd_assert(channel_buf != NULL, return -EIO); - copy_from_user(channel_buf + pos * 4, src, count * 4); + if (copy_from_user(channel_buf + pos * 4, src, count * 4)) + return -EFAULT; return count; } @@ -3847,7 +3855,8 @@ channel_buf = hdsp_channel_buffer_location (hdsp, substream->pstr->stream, channel); snd_assert(channel_buf != NULL, return -EIO); - copy_to_user(dst, channel_buf + pos * 4, count * 4); + if (copy_to_user(dst, channel_buf + pos * 4, count * 4)) + return -EFAULT; return count; } diff -Nru a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c --- a/sound/pci/rme9652/rme9652.c Sun Mar 14 14:20:07 2004 +++ b/sound/pci/rme9652/rme9652.c Sun Mar 14 14:20:07 2004 @@ -314,7 +314,10 @@ struct snd_dma_device pdev; struct snd_dma_buffer dmbuf; - snd_dma_device_pci(&pdev, pci, capture); + memset(&pdev, 0, sizeof(pdev)); + pdev.type = SNDRV_DMA_TYPE_DEV; + pdev.dev = snd_dma_pci_data(pci); + pdev.id = capture; dmbuf.bytes = 0; if (! snd_dma_get_reserved(&pdev, &dmbuf)) { if (snd_dma_alloc_pages(&pdev, size, &dmbuf) < 0) @@ -327,9 +330,13 @@ static void snd_hammerfall_free_buffer(struct pci_dev *pci, size_t size, void *ptr, dma_addr_t addr, int capture) { - struct snd_dma_device dev; - snd_dma_device_pci(&dev, pci, capture); - snd_dma_free_reserved(&dev); + struct snd_dma_device pdev; + + memset(&pdev, 0, sizeof(pdev)); + pdev.type = SNDRV_DMA_TYPE_DEV; + pdev.dev = snd_dma_pci_data(pci); + pdev.id = capture; + snd_dma_free_reserved(&pdev); } #else diff -Nru a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c --- a/sound/pci/sonicvibes.c Sun Mar 14 14:20:08 2004 +++ b/sound/pci/sonicvibes.c Sun Mar 14 14:20:08 2004 @@ -886,7 +886,8 @@ strcpy(pcm->name, "S3 SonicVibes"); sonic->pcm = pcm; - snd_pcm_lib_preallocate_pci_pages_for_all(sonic->pci, pcm, 64*1024, 128*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(sonic->pci), 64*1024, 128*1024); if (rpcm) *rpcm = pcm; diff -Nru a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c --- a/sound/pci/trident/trident_main.c Sun Mar 14 14:20:07 2004 +++ b/sound/pci/trident/trident_main.c Sun Mar 14 14:20:07 2004 @@ -1009,8 +1009,6 @@ snd_trident_voice_t *voice = (snd_trident_voice_t *) runtime->private_data; unsigned int val, ESO_bytes; - snd_assert(substream->dma_device.type == SNDRV_DMA_TYPE_PCI, return -EIO); - spin_lock(&trident->reg_lock); // Initilize the channel and set channel Mode @@ -2189,10 +2187,15 @@ if (trident->tlb.entries) { snd_pcm_substream_t *substream; for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) - snd_pcm_lib_preallocate_sg_pages(trident->pci, substream, 64*1024, 128*1024); - snd_pcm_lib_preallocate_pci_pages(trident->pci, pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, 64*1024, 128*1024); + snd_pcm_lib_preallocate_pages(substream, SNDRV_DMA_TYPE_DEV_SG, + snd_dma_pci_data(trident->pci), + 64*1024, 128*1024); + snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream, + SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci), + 64*1024, 128*1024); } else { - snd_pcm_lib_preallocate_pci_pages_for_all(trident->pci, pcm, 64*1024, 128*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(trident->pci), 64*1024, 128*1024); } if (rpcm) @@ -2246,9 +2249,11 @@ trident->foldback = foldback; if (trident->tlb.entries) - snd_pcm_lib_preallocate_sg_pages_for_all(trident->pci, foldback, 0, 128*1024); + snd_pcm_lib_preallocate_pages_for_all(foldback, SNDRV_DMA_TYPE_DEV_SG, + snd_dma_pci_data(trident->pci), 0, 128*1024); else - snd_pcm_lib_preallocate_pci_pages_for_all(trident->pci, foldback, 64*1024, 128*1024); + snd_pcm_lib_preallocate_pages_for_all(foldback, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(trident->pci), 64*1024, 128*1024); if (rpcm) *rpcm = foldback; @@ -2287,7 +2292,7 @@ strcpy(spdif->name, "Trident 4DWave IEC958"); trident->spdif = spdif; - snd_pcm_lib_preallocate_pci_pages_for_all(trident->pci, spdif, 64*1024, 128*1024); + snd_pcm_lib_preallocate_pages_for_all(spdif, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci), 64*1024, 128*1024); if (rpcm) *rpcm = spdif; @@ -3052,29 +3057,49 @@ } if (trident->device == TRIDENT_DEVICE_ID_NX || trident->device == TRIDENT_DEVICE_ID_SI7018) { - if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_trident_spdif_control, trident))) < 0) + kctl = snd_ctl_new1(&snd_trident_spdif_control, trident); + if (kctl == NULL) { + err = -ENOMEM; goto __out; + } if (trident->ac97->ext_id & AC97_EI_SPDIF) kctl->id.index++; if (trident->ac97_sec && (trident->ac97_sec->ext_id & AC97_EI_SPDIF)) kctl->id.index++; idx = kctl->id.index; + if ((err = snd_ctl_add(card, kctl)) < 0) + goto __out; kctl->put(kctl, uctl); - if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_trident_spdif_default, trident))) < 0) + kctl = snd_ctl_new1(&snd_trident_spdif_default, trident); + if (kctl == NULL) { + err = -ENOMEM; goto __out; + } kctl->id.index = idx; kctl->id.device = pcm_spdif_device; + if ((err = snd_ctl_add(card, kctl)) < 0) + goto __out; - if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_trident_spdif_mask, trident))) < 0) + kctl = snd_ctl_new1(&snd_trident_spdif_mask, trident); + if (kctl == NULL) { + err = -ENOMEM; goto __out; + } kctl->id.index = idx; kctl->id.device = pcm_spdif_device; + if ((err = snd_ctl_add(card, kctl)) < 0) + goto __out; - if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_trident_spdif_stream, trident))) < 0) + kctl = snd_ctl_new1(&snd_trident_spdif_stream, trident); + if (kctl == NULL) { + err = -ENOMEM; goto __out; + } kctl->id.index = idx; kctl->id.device = pcm_spdif_device; + if ((err = snd_ctl_add(card, kctl)) < 0) + goto __out; trident->spdif_pcm_ctl = kctl; } @@ -3328,13 +3353,12 @@ /* TLB array must be aligned to 16kB !!! so we allocate 32kB region and correct offset when necessary */ - trident->tlb.buffer = snd_malloc_pci_pages(trident->pci, 2 * SNDRV_TRIDENT_MAX_PAGES * 4, &trident->tlb.buffer_dmaaddr); - if (trident->tlb.buffer == NULL) { + if (snd_dma_alloc_pages(&trident->dma_dev, 2 * SNDRV_TRIDENT_MAX_PAGES * 4, &trident->tlb.buffer) < 0) { snd_printk(KERN_ERR "trident: unable to allocate TLB buffer\n"); return -ENOMEM; } - trident->tlb.entries = (unsigned int*)(((unsigned long)trident->tlb.buffer + SNDRV_TRIDENT_MAX_PAGES * 4 - 1) & ~(SNDRV_TRIDENT_MAX_PAGES * 4 - 1)); - trident->tlb.entries_dmaaddr = (trident->tlb.buffer_dmaaddr + SNDRV_TRIDENT_MAX_PAGES * 4 - 1) & ~(SNDRV_TRIDENT_MAX_PAGES * 4 - 1); + trident->tlb.entries = (unsigned int*)(((unsigned long)trident->tlb.buffer.area + SNDRV_TRIDENT_MAX_PAGES * 4 - 1) & ~(SNDRV_TRIDENT_MAX_PAGES * 4 - 1)); + trident->tlb.entries_dmaaddr = (trident->tlb.buffer.addr + SNDRV_TRIDENT_MAX_PAGES * 4 - 1) & ~(SNDRV_TRIDENT_MAX_PAGES * 4 - 1); /* allocate shadow TLB page table (virtual addresses) */ trident->tlb.shadow_entries = (unsigned long *)vmalloc(SNDRV_TRIDENT_MAX_PAGES*sizeof(unsigned long)); if (trident->tlb.shadow_entries == NULL) { @@ -3342,15 +3366,14 @@ return -ENOMEM; } /* allocate and setup silent page and initialise TLB entries */ - trident->tlb.silent_page = snd_malloc_pci_pages(trident->pci, SNDRV_TRIDENT_PAGE_SIZE, &trident->tlb.silent_page_dmaaddr); - if (trident->tlb.silent_page == 0UL) { + if (snd_dma_alloc_pages(&trident->dma_dev, SNDRV_TRIDENT_PAGE_SIZE, &trident->tlb.silent_page) < 0) { snd_printk(KERN_ERR "trident: unable to allocate silent page\n"); return -ENOMEM; } - memset(trident->tlb.silent_page, 0, SNDRV_TRIDENT_PAGE_SIZE); + memset(trident->tlb.silent_page.area, 0, SNDRV_TRIDENT_PAGE_SIZE); for (i = 0; i < SNDRV_TRIDENT_MAX_PAGES; i++) { - trident->tlb.entries[i] = cpu_to_le32(trident->tlb.silent_page_dmaaddr & ~(SNDRV_TRIDENT_PAGE_SIZE-1)); - trident->tlb.shadow_entries[i] = (unsigned long)trident->tlb.silent_page; + trident->tlb.entries[i] = cpu_to_le32(trident->tlb.silent_page.addr & ~(SNDRV_TRIDENT_PAGE_SIZE-1)); + trident->tlb.shadow_entries[i] = (unsigned long)trident->tlb.silent_page.area; } /* use emu memory block manager code to manage tlb page allocation */ @@ -3565,9 +3588,13 @@ } trident->irq = pci->irq; + memset(&trident->dma_dev, 0, sizeof(trident->dma_dev)); + trident->dma_dev.type = SNDRV_DMA_TYPE_DEV; + trident->dma_dev.dev = snd_dma_pci_data(pci); + /* allocate 16k-aligned TLB for NX cards */ trident->tlb.entries = NULL; - trident->tlb.buffer = NULL; + trident->tlb.buffer.area = NULL; if (trident->device == TRIDENT_DEVICE_ID_NX) { if ((err = snd_trident_tlb_alloc(trident)) < 0) { snd_trident_free(trident); @@ -3661,15 +3688,15 @@ else if (trident->device == TRIDENT_DEVICE_ID_SI7018) { outl(0, TRID_REG(trident, SI_SERIAL_INTF_CTRL)); } - if (trident->tlb.buffer) { + if (trident->tlb.buffer.area) { outl(0, TRID_REG(trident, NX_TLBC)); if (trident->tlb.memhdr) snd_util_memhdr_free(trident->tlb.memhdr); - if (trident->tlb.silent_page) - snd_free_pci_pages(trident->pci, SNDRV_TRIDENT_PAGE_SIZE, trident->tlb.silent_page, trident->tlb.silent_page_dmaaddr); + if (trident->tlb.silent_page.area) + snd_dma_free_pages(&trident->dma_dev, &trident->tlb.silent_page); if (trident->tlb.shadow_entries) vfree(trident->tlb.shadow_entries); - snd_free_pci_pages(trident->pci, 2 * SNDRV_TRIDENT_MAX_PAGES * 4, trident->tlb.buffer, trident->tlb.buffer_dmaaddr); + snd_dma_free_pages(&trident->dma_dev, &trident->tlb.buffer); } if (trident->irq >= 0) free_irq(trident->irq, (void *)trident); diff -Nru a/sound/pci/trident/trident_memory.c b/sound/pci/trident/trident_memory.c --- a/sound/pci/trident/trident_memory.c Sun Mar 14 14:20:07 2004 +++ b/sound/pci/trident/trident_memory.c Sun Mar 14 14:20:07 2004 @@ -47,7 +47,7 @@ /* fill TLB entrie(s) corresponding to page with ptr */ #define set_tlb_bus(trident,page,ptr,addr) __set_tlb_bus(trident,page,ptr,addr) /* fill TLB entrie(s) corresponding to page with silence pointer */ -#define set_silent_tlb(trident,page) __set_tlb_bus(trident, page, (unsigned long)trident->tlb.silent_page, trident->tlb.silent_page_dmaaddr) +#define set_silent_tlb(trident,page) __set_tlb_bus(trident, page, (unsigned long)trident->tlb.silent_page.area, trident->tlb.silent_page.addr) /* get aligned page from offset address */ #define get_aligned_page(offset) ((offset) >> 12) /* get offset address from aligned page */ @@ -191,7 +191,6 @@ int idx, page; struct snd_sg_buf *sgbuf = runtime->dma_private; - snd_assert(substream->dma_device.type == SNDRV_DMA_TYPE_PCI_SG, return NULL); snd_assert(runtime->dma_bytes > 0 && runtime->dma_bytes <= SNDRV_TRIDENT_MAX_PAGES * SNDRV_TRIDENT_PAGE_SIZE, return NULL); hdr = trident->tlb.memhdr; snd_assert(hdr != NULL, return NULL); @@ -240,7 +239,6 @@ dma_addr_t addr; unsigned long ptr; - snd_assert(substream->dma_device.type == SNDRV_DMA_TYPE_PCI, return NULL); snd_assert(runtime->dma_bytes> 0 && runtime->dma_bytes <= SNDRV_TRIDENT_MAX_PAGES * SNDRV_TRIDENT_PAGE_SIZE, return NULL); hdr = trident->tlb.memhdr; snd_assert(hdr != NULL, return NULL); @@ -276,7 +274,7 @@ { snd_assert(trident != NULL, return NULL); snd_assert(substream != NULL, return NULL); - if (substream->dma_device.type == SNDRV_DMA_TYPE_PCI_SG) + if (substream->dma_device.type == SNDRV_DMA_TYPE_DEV_SG) return snd_trident_alloc_sg_pages(trident, substream); else return snd_trident_alloc_cont_pages(trident, substream); @@ -367,8 +365,13 @@ void *ptr = page_to_ptr(trident, page); dma_addr_t addr = page_to_addr(trident, page); set_silent_tlb(trident, page); - if (ptr) - snd_free_pci_pages(trident->pci, ALIGN_PAGE_SIZE, ptr, addr); + if (ptr) { + struct snd_dma_buffer dmab; + dmab.area = ptr; + dmab.addr = addr; + dmab.bytes = ALIGN_PAGE_SIZE; + snd_dma_free_pages(&trident->dma_dev, &dmab); + } } /* check new allocation range */ @@ -399,8 +402,7 @@ static int synth_alloc_pages(trident_t *hw, snd_util_memblk_t *blk) { int page, first_page, last_page; - void *ptr; - dma_addr_t addr; + struct snd_dma_buffer dmab; firstpg(blk) = get_aligned_page(blk->offset); lastpg(blk) = get_aligned_page(blk->offset + blk->size - 1); @@ -410,14 +412,13 @@ * fortunately Trident page size and kernel PAGE_SIZE is identical! */ for (page = first_page; page <= last_page; page++) { - ptr = snd_malloc_pci_pages(hw->pci, ALIGN_PAGE_SIZE, &addr); - if (ptr == NULL) + if (snd_dma_alloc_pages(&hw->dma_dev, ALIGN_PAGE_SIZE, &dmab) < 0) goto __fail; - if (! is_valid_page(addr)) { - snd_free_pci_pages(hw->pci, ALIGN_PAGE_SIZE, ptr, addr); + if (! is_valid_page(dmab.addr)) { + snd_dma_free_pages(&hw->dma_dev, &dmab); goto __fail; } - set_tlb_bus(hw, page, (unsigned long)ptr, addr); + set_tlb_bus(hw, page, (unsigned long)dmab.area, dmab.addr); } return 0; diff -Nru a/sound/pci/trident/trident_synth.c b/sound/pci/trident/trident_synth.c --- a/sound/pci/trident/trident_synth.c Sun Mar 14 14:20:07 2004 +++ b/sound/pci/trident/trident_synth.c Sun Mar 14 14:20:07 2004 @@ -507,7 +507,6 @@ char *data, long len, int atomic) { trident_t *trident = snd_magic_cast(trident_t, private_data, return -ENXIO); - unsigned char *block = NULL; int size = instr->size; int shift = 0; @@ -530,7 +529,7 @@ if (trident->tlb.entries) { snd_util_memblk_t *memblk; - memblk = snd_trident_synth_alloc(trident,size); + memblk = snd_trident_synth_alloc(trident, size); if (memblk == NULL) return -ENOMEM; if (snd_trident_synth_copy_from_user(trident, memblk, 0, data, size) ) { @@ -540,17 +539,17 @@ instr->address.ptr = (unsigned char*)memblk; instr->address.memory = memblk->offset; } else { - dma_addr_t addr; - block = (unsigned char *) snd_malloc_pci_pages(trident->pci, size, &addr); - if (block == NULL) + struct snd_dma_buffer dmab; + + if (snd_dma_alloc_pages(&trident->dma_dev, size, &dmab) < 0) return -ENOMEM; - if (copy_from_user(block, data, size)) { - snd_free_pci_pages(trident->pci, size, block, addr); + if (copy_from_user(dmab.area, data, size)) { + snd_dma_free_pages(&trident->dma_dev, &dmab); return -EFAULT; } - instr->address.ptr = block; - instr->address.memory = addr; + instr->address.ptr = dmab.area; + instr->address.memory = dmab.addr; } trident->synth.current_size += size; diff -Nru a/sound/pci/via82xx.c b/sound/pci/via82xx.c --- a/sound/pci/via82xx.c Sun Mar 14 14:20:08 2004 +++ b/sound/pci/via82xx.c Sun Mar 14 14:20:08 2004 @@ -107,7 +107,7 @@ MODULE_PARM_SYNTAX(ac97_clock, SNDRV_ENABLED ",default:48000"); MODULE_PARM(ac97_quirk, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); -MODULE_PARM_SYNTAX(ac97_quirk, SNDRV_ENABLED ",allows:{{-1,3}},dialog:list,default:-1"); +MODULE_PARM_SYNTAX(ac97_quirk, SNDRV_ENABLED ",allows:{{-1,4}},dialog:list,default:-1"); MODULE_PARM(dxs_support, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA)"); MODULE_PARM_SYNTAX(dxs_support, SNDRV_ENABLED ",allows:{{0,4}},dialog:list"); @@ -337,8 +337,7 @@ snd_pcm_substream_t *substream; int running; unsigned int tbl_entries; /* # descriptors */ - u32 *table; /* physical address + flag */ - dma_addr_t table_addr; + struct snd_dma_buffer table; struct snd_via_sg_table *idx_table; /* for recovery from the unexpected pointer */ unsigned int lastpos; @@ -347,6 +346,74 @@ }; +enum { TYPE_CARD_VIA686 = 1, TYPE_CARD_VIA8233 }; +enum { TYPE_VIA686, TYPE_VIA8233, TYPE_VIA8233A }; + +#define VIA_MAX_DEVS 7 /* 4 playback, 1 multi, 2 capture */ + +struct via_rate_lock { + spinlock_t lock; + int rate; + int used; +}; + +struct _snd_via82xx { + int irq; + + unsigned long port; + struct resource *res_port; + struct resource *mpu_res; + int chip_type; + unsigned char revision; + + unsigned char old_legacy; + unsigned char old_legacy_cfg; + + unsigned char playback_volume[4][2]; /* for VIA8233/C/8235; default = 0 */ + + unsigned int intr_mask; /* SGD_SHADOW mask to check interrupts */ + + struct pci_dev *pci; + snd_card_t *card; + + unsigned int num_devs; + unsigned int playback_devno, multi_devno, capture_devno; + viadev_t devs[VIA_MAX_DEVS]; + struct via_rate_lock rates[2]; /* playback and capture */ + unsigned int dxs_fixed: 1; /* DXS channel accepts only 48kHz */ + unsigned int no_vra: 1; /* no need to set VRA on DXS channels */ + unsigned int spdif_on: 1; /* only spdif rates work to external DACs */ + + snd_rawmidi_t *rmidi; + + ac97_bus_t *ac97_bus; + ac97_t *ac97; + unsigned int ac97_clock; + unsigned int ac97_secondary; /* secondary AC'97 codec is present */ + + spinlock_t reg_lock; + spinlock_t ac97_lock; + snd_info_entry_t *proc_entry; + + struct snd_dma_device dma_dev; + +#ifdef SUPPORT_JOYSTICK + struct gameport gameport; + struct resource *res_joystick; +#endif +}; + +static struct pci_device_id snd_via82xx_ids[] = { + { 0x1106, 0x3058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_CARD_VIA686, }, /* 686A */ + { 0x1106, 0x3059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_CARD_VIA8233, }, /* VT8233 */ + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, snd_via82xx_ids); + +/* + */ + /* * allocate and initialize the descriptor buffers * periods = number of periods @@ -357,14 +424,14 @@ unsigned int periods, unsigned int fragsize) { unsigned int i, idx, ofs, rest; + via82xx_t *chip = snd_pcm_substream_chip(substream); struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream); - if (! dev->table) { + if (dev->table.area == NULL) { /* the start of each lists must be aligned to 8 bytes, * but the kernel pages are much bigger, so we don't care */ - dev->table = (u32*)snd_malloc_pci_pages(pci, PAGE_ALIGN(VIA_TABLE_SIZE * 2 * 8), &dev->table_addr); - if (! dev->table) + if (snd_dma_alloc_pages(&chip->dma_dev, PAGE_ALIGN(VIA_TABLE_SIZE * 2 * 8), &dev->table) < 0) return -ENOMEM; } if (! dev->idx_table) { @@ -390,7 +457,7 @@ snd_printk(KERN_ERR "via82xx: too much table size!\n"); return -EINVAL; } - dev->table[idx << 1] = cpu_to_le32((u32)snd_pcm_sgbuf_get_addr(sgbuf, ofs)); + ((u32 *)dev->table.area)[idx << 1] = cpu_to_le32((u32)snd_pcm_sgbuf_get_addr(sgbuf, ofs)); r = PAGE_SIZE - (ofs % PAGE_SIZE); if (rest < r) r = rest; @@ -403,7 +470,7 @@ } else flag = 0; /* period continues to the next */ // printk("via: tbl %d: at %d size %d (rest %d)\n", idx, ofs, r, rest); - dev->table[(idx<<1) + 1] = cpu_to_le32(r | flag); + ((u32 *)dev->table.area)[(idx<<1) + 1] = cpu_to_le32(r | flag); dev->idx_table[idx].offset = ofs; dev->idx_table[idx].size = r; ofs += r; @@ -417,85 +484,21 @@ } -static void clean_via_table(viadev_t *dev, snd_pcm_substream_t *substream, - struct pci_dev *pci) +static int clean_via_table(viadev_t *dev, snd_pcm_substream_t *substream, + struct pci_dev *pci) { - if (dev->table) { - snd_free_pci_pages(pci, PAGE_ALIGN(VIA_TABLE_SIZE * 2 * 8), dev->table, dev->table_addr); - dev->table = NULL; + via82xx_t *chip = snd_pcm_substream_chip(substream); + if (dev->table.area) { + snd_dma_free_pages(&chip->dma_dev, &dev->table); + dev->table.area = NULL; } if (dev->idx_table) { kfree(dev->idx_table); dev->idx_table = NULL; } + return 0; } - -/* - */ - -enum { TYPE_CARD_VIA686 = 1, TYPE_CARD_VIA8233 }; -enum { TYPE_VIA686, TYPE_VIA8233, TYPE_VIA8233A }; - -#define VIA_MAX_DEVS 7 /* 4 playback, 1 multi, 2 capture */ - -struct via_rate_lock { - spinlock_t lock; - int rate; - int used; -}; - -struct _snd_via82xx { - int irq; - - unsigned long port; - struct resource *res_port; - struct resource *mpu_res; - int chip_type; - unsigned char revision; - - unsigned char old_legacy; - unsigned char old_legacy_cfg; - - unsigned char playback_volume[4][2]; /* for VIA8233/C/8235; default = 0 */ - - unsigned int intr_mask; /* SGD_SHADOW mask to check interrupts */ - - struct pci_dev *pci; - snd_card_t *card; - - unsigned int num_devs; - unsigned int playback_devno, multi_devno, capture_devno; - viadev_t devs[VIA_MAX_DEVS]; - struct via_rate_lock rates[2]; /* playback and capture */ - unsigned int dxs_fixed: 1; /* DXS channel accepts only 48kHz */ - unsigned int no_vra: 1; /* no need to set VRA on DXS channels */ - - snd_rawmidi_t *rmidi; - - ac97_bus_t *ac97_bus; - ac97_t *ac97; - unsigned int ac97_clock; - unsigned int ac97_secondary; /* secondary AC'97 codec is present */ - - spinlock_t reg_lock; - spinlock_t ac97_lock; - snd_info_entry_t *proc_entry; - -#ifdef SUPPORT_JOYSTICK - struct gameport gameport; - struct resource *res_joystick; -#endif -}; - -static struct pci_device_id snd_via82xx_ids[] = { - { 0x1106, 0x3058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_CARD_VIA686, }, /* 686A */ - { 0x1106, 0x3059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_CARD_VIA8233, }, /* VT8233 */ - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, snd_via82xx_ids); - /* * Basic I/O */ @@ -756,10 +759,10 @@ * so we need to calculate the index from CURR_PTR. */ ptr = inl(VIADEV_REG(viadev, OFFSET_CURR_PTR)); - if (ptr <= (unsigned int)viadev->table_addr) + if (ptr <= (unsigned int)viadev->table.addr) idx = 0; else /* CURR_PTR holds the address + 8 */ - idx = ((ptr - (unsigned int)viadev->table_addr) / 8 - 1) % viadev->tbl_entries; + idx = ((ptr - (unsigned int)viadev->table.addr) / 8 - 1) % viadev->tbl_entries; res = calc_linear_pos(viadev, idx, count); spin_unlock(&chip->reg_lock); @@ -840,7 +843,7 @@ static void snd_via82xx_set_table_ptr(via82xx_t *chip, viadev_t *viadev) { snd_via82xx_codec_ready(chip, 0); - outl((u32)viadev->table_addr, VIADEV_REG(viadev, OFFSET_TABLE_PTR)); + outl((u32)viadev->table.addr, VIADEV_REG(viadev, OFFSET_TABLE_PTR)); udelay(20); snd_via82xx_codec_ready(chip, 0); } @@ -922,12 +925,10 @@ chip->no_vra ? 48000 : runtime->rate); snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate); } -#if 0 - if (chip->revision == VIA_REV_8233A) - rbits = 0; + if (runtime->rate == 48000) + rbits = 0xfffff; else -#endif - rbits = (0xfffff / 48000) * runtime->rate + ((0xfffff % 48000) * runtime->rate) / 48000; + rbits = (0x100000 / 48000) * runtime->rate + ((0x100000 % 48000) * runtime->rate) / 48000; snd_assert((rbits & ~0xfffff) == 0, return -EINVAL); snd_via82xx_channel_reset(chip, viadev); snd_via82xx_set_table_ptr(chip, viadev); @@ -1069,7 +1070,11 @@ ratep = &chip->rates[viadev->direction]; spin_lock_irqsave(&ratep->lock, flags); ratep->used++; - if (chip->dxs_fixed && viadev->reg_offset < 0x40) { + if (chip->spdif_on) { + runtime->hw.rates = SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000; + runtime->hw.rate_min = 32000; + runtime->hw.rate_max = 48000; + } else if (chip->dxs_fixed && viadev->reg_offset < 0x40) { /* fixed DXS playback rate */ runtime->hw.rates = SNDRV_PCM_RATE_48000; runtime->hw.rate_min = runtime->hw.rate_max = 48000; @@ -1290,7 +1295,8 @@ /* capture */ init_viadev(chip, chip->capture_devno, VIA_REG_CAPTURE_8233_STATUS, 1); - if ((err = snd_pcm_lib_preallocate_sg_pages_for_all(chip->pci, pcm, 64*1024, 128*1024)) < 0) + if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, + snd_dma_pci_data(chip->pci), 64*1024, 128*1024)) < 0) return err; /* PCM #1: multi-channel playback and 2nd capture */ @@ -1306,7 +1312,8 @@ /* set up capture */ init_viadev(chip, chip->capture_devno + 1, VIA_REG_CAPTURE_8233_STATUS + 0x10, 1); - if ((err = snd_pcm_lib_preallocate_sg_pages_for_all(chip->pci, pcm, 64*1024, 128*1024)) < 0) + if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, + snd_dma_pci_data(chip->pci), 64*1024, 128*1024)) < 0) return err; return 0; @@ -1339,7 +1346,8 @@ /* capture */ init_viadev(chip, chip->capture_devno, VIA_REG_CAPTURE_8233_STATUS, 1); - if ((err = snd_pcm_lib_preallocate_sg_pages_for_all(chip->pci, pcm, 64*1024, 128*1024)) < 0) + if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, + snd_dma_pci_data(chip->pci), 64*1024, 128*1024)) < 0) return err; /* PCM #1: DXS3 playback (for spdif) */ @@ -1352,7 +1360,8 @@ /* set up playback */ init_viadev(chip, chip->playback_devno, 0x30, 0); - if ((err = snd_pcm_lib_preallocate_sg_pages_for_all(chip->pci, pcm, 64*1024, 128*1024)) < 0) + if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, + snd_dma_pci_data(chip->pci), 64*1024, 128*1024)) < 0) return err; return 0; @@ -1381,7 +1390,8 @@ init_viadev(chip, 0, VIA_REG_PLAYBACK_STATUS, 0); init_viadev(chip, 1, VIA_REG_CAPTURE_STATUS, 1); - if ((err = snd_pcm_lib_preallocate_sg_pages_for_all(chip->pci, pcm, 64*1024, 128*1024)) < 0) + if ((err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, + snd_dma_pci_data(chip->pci), 64*1024, 128*1024)) < 0) return err; return 0; @@ -1468,6 +1478,8 @@ val = oval & ~VIA8233_SPDIF_DX3; if (ucontrol->value.integer.value[0]) val |= VIA8233_SPDIF_DX3; + /* save the spdif flag for rate filtering */ + chip->spdif_on = ucontrol->value.integer.value[0] ? 1 : 0; if (val != oval) { pci_write_config_byte(chip->pci, VIA8233_SPDIF_CTRL, val); return 1; @@ -1560,6 +1572,18 @@ .name = "ASRock K7VM2", .type = AC97_TUNE_HP_ONLY /* VT1616 */ }, + { + .vendor = 0x14cd, + .device = 0x7002, + .name = "Unknown", + .type = AC97_TUNE_ALC_JACK + }, + { + .vendor = 0x1071, + .device = 0x8590, + .name = "Mitac Mobo", + .type = AC97_TUNE_ALC_JACK + }, { } /* terminator */ }; @@ -1913,6 +1937,10 @@ chip->pci = pci; chip->irq = -1; + memset(&chip->dma_dev, 0, sizeof(chip->dma_dev)); + chip->dma_dev.type = SNDRV_DMA_TYPE_DEV; + chip->dma_dev.dev = snd_dma_pci_data(pci); + pci_read_config_byte(pci, VIA_FUNC_ENABLE, &chip->old_legacy); pci_read_config_byte(pci, VIA_PNP_CONTROL, &chip->old_legacy_cfg); @@ -1987,13 +2015,16 @@ { .vendor = 0x1043, .device = 0x80b0, .action = VIA_DXS_NO_VRA }, /* ASUS A7V600 & K8V*/ { .vendor = 0x10cf, .device = 0x118e, .action = VIA_DXS_ENABLE }, /* FSC laptop */ { .vendor = 0x1106, .device = 0x4161, .action = VIA_DXS_NO_VRA }, /* ASRock K7VT2 */ + { .vendor = 0x1106, .device = 0xaa01, .action = VIA_DXS_NO_VRA }, /* EPIA MII */ { .vendor = 0x1297, .device = 0xa232, .action = VIA_DXS_ENABLE }, /* Shuttle ?? */ { .vendor = 0x1297, .device = 0xc160, .action = VIA_DXS_ENABLE }, /* Shuttle SK41G */ - { .vendor = 0x1458, .device = 0xa002, .action = VIA_DXS_ENABLE }, /* Gigabyte GA-7VAXP */ + { .vendor = 0x1458, .device = 0xa002, .action = VIA_DXS_NO_VRA }, /* Gigabyte GA-7VAXP (FIXME: or DXS_ENABLE?) */ { .vendor = 0x147b, .device = 0x1401, .action = VIA_DXS_ENABLE }, /* ABIT KD7(-RAID) */ { .vendor = 0x14ff, .device = 0x0403, .action = VIA_DXS_ENABLE }, /* Twinhead mobo */ { .vendor = 0x1462, .device = 0x3800, .action = VIA_DXS_ENABLE }, /* MSI KT266 */ { .vendor = 0x1462, .device = 0x7120, .action = VIA_DXS_ENABLE }, /* MSI KT4V */ + { .vendor = 0x1462, .device = 0x5901, .action = VIA_DXS_NO_VRA }, /* MSI KT6 Delta-SR */ + { .vendor = 0x1584, .device = 0x8120, .action = VIA_DXS_ENABLE }, /* Gericom/Targa/Vobis/Uniwill laptop */ { .vendor = 0x1631, .device = 0xe004, .action = VIA_DXS_ENABLE }, /* Easy Note 3174, Packard Bell */ { .vendor = 0x1695, .device = 0x3005, .action = VIA_DXS_ENABLE }, /* EPoX EP-8K9A */ { .vendor = 0x1849, .device = 0x3059, .action = VIA_DXS_NO_VRA }, /* ASRock K7VM2 */ diff -Nru a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c --- a/sound/pci/ymfpci/ymfpci_main.c Sun Mar 14 14:20:08 2004 +++ b/sound/pci/ymfpci/ymfpci_main.c Sun Mar 14 14:20:08 2004 @@ -541,20 +541,15 @@ static int __devinit snd_ymfpci_ac3_init(ymfpci_t *chip) { - unsigned char *ptr; - dma_addr_t ptr_addr; - - if ((ptr = snd_malloc_pci_pages(chip->pci, 4096, &ptr_addr)) == NULL) + if (snd_dma_alloc_pages(&chip->dma_dev, 4096, &chip->ac3_tmp_base) < 0) return -ENOMEM; - chip->ac3_tmp_base = ptr; - chip->ac3_tmp_base_addr = ptr_addr; chip->bank_effect[3][0]->base = - chip->bank_effect[3][1]->base = cpu_to_le32(chip->ac3_tmp_base_addr); + chip->bank_effect[3][1]->base = cpu_to_le32(chip->ac3_tmp_base.addr); chip->bank_effect[3][0]->loop_end = chip->bank_effect[3][1]->loop_end = cpu_to_le32(1024); chip->bank_effect[4][0]->base = - chip->bank_effect[4][1]->base = cpu_to_le32(chip->ac3_tmp_base_addr + 2048); + chip->bank_effect[4][1]->base = cpu_to_le32(chip->ac3_tmp_base.addr + 2048); chip->bank_effect[4][0]->loop_end = chip->bank_effect[4][1]->loop_end = cpu_to_le32(1024); @@ -572,9 +567,9 @@ snd_ymfpci_readl(chip, YDSXGR_MAPOFEFFECT) & ~(3 << 3)); spin_unlock_irq(&chip->reg_lock); // snd_ymfpci_irq_wait(chip); - if (chip->ac3_tmp_base) { - snd_free_pci_pages(chip->pci, 4096, chip->ac3_tmp_base, chip->ac3_tmp_base_addr); - chip->ac3_tmp_base = NULL; + if (chip->ac3_tmp_base.area) { + snd_dma_free_pages(&chip->dma_dev, &chip->ac3_tmp_base); + chip->ac3_tmp_base.area = NULL; } return 0; } @@ -1104,7 +1099,8 @@ strcpy(pcm->name, "YMFPCI"); chip->pcm = pcm; - snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), 64*1024, 256*1024); if (rpcm) *rpcm = pcm; @@ -1149,7 +1145,8 @@ chip->device_id == PCI_DEVICE_ID_YAMAHA_754 ? "Direct Recording" : "AC'97"); chip->pcm2 = pcm; - snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), 64*1024, 256*1024); if (rpcm) *rpcm = pcm; @@ -1193,7 +1190,8 @@ strcpy(pcm->name, "YMFPCI - IEC958"); chip->pcm_spdif = pcm; - snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), 64*1024, 256*1024); if (rpcm) *rpcm = pcm; @@ -1237,7 +1235,8 @@ strcpy(pcm->name, "YMFPCI - Rear PCM"); chip->pcm_4ch = pcm; - snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), 64*1024, 256*1024); if (rpcm) *rpcm = pcm; @@ -1976,12 +1975,11 @@ chip->work_size; /* work_ptr must be aligned to 256 bytes, but it's already covered with the kernel page allocation mechanism */ - if ((ptr = snd_malloc_pci_pages(chip->pci, size, &ptr_addr)) == NULL) + if (snd_dma_alloc_pages(&chip->dma_dev, size, &chip->work_ptr) < 0) return -ENOMEM; + ptr = chip->work_ptr.area; + ptr_addr = chip->work_ptr.addr; memset(ptr, 0, size); /* for sure */ - chip->work_ptr = ptr; - chip->work_ptr_addr = ptr_addr; - chip->work_ptr_size = size; chip->bank_base_playback = ptr; chip->bank_base_playback_addr = ptr_addr; @@ -2024,7 +2022,7 @@ chip->work_base = ptr; chip->work_base_addr = ptr_addr; - snd_assert(ptr + chip->work_size == chip->work_ptr + chip->work_ptr_size, ); + snd_assert(ptr + chip->work_size == chip->work_ptr.area + chip->work_ptr.bytes, ); snd_ymfpci_writel(chip, YDSXGR_PLAYCTRLBASE, chip->bank_base_playback_addr); snd_ymfpci_writel(chip, YDSXGR_RECCTRLBASE, chip->bank_base_capture_addr); @@ -2107,8 +2105,8 @@ #endif if (chip->reg_area_virt) iounmap((void *)chip->reg_area_virt); - if (chip->work_ptr) - snd_free_pci_pages(chip->pci, chip->work_ptr_size, chip->work_ptr, chip->work_ptr_addr); + if (chip->work_ptr.area) + snd_dma_free_pages(&chip->dma_dev, &chip->work_ptr); if (chip->irq >= 0) free_irq(chip->irq, (void *)chip); @@ -2275,6 +2273,10 @@ return -EBUSY; } chip->irq = pci->irq; + + memset(&chip->dma_dev, 0, sizeof(chip->dma_dev)); + chip->dma_dev.type = SNDRV_DMA_TYPE_DEV; + chip->dma_dev.dev = snd_dma_pci_data(pci); snd_ymfpci_aclink_reset(pci); if (snd_ymfpci_codec_ready(chip, 0) < 0) { diff -Nru a/sound/pcmcia/Kconfig b/sound/pcmcia/Kconfig --- a/sound/pcmcia/Kconfig Sun Mar 14 14:20:07 2004 +++ b/sound/pcmcia/Kconfig Sun Mar 14 14:20:07 2004 @@ -6,13 +6,21 @@ config SND_VXPOCKET tristate "Digigram VXpocket" depends on SND && PCMCIA && ISA + select SND_VX_LIB help Say 'Y' or 'M' to include support for Digigram VXpocket soundcard. config SND_VXP440 tristate "Digigram VXpocket 440" depends on SND && PCMCIA && ISA + select SND_VX_LIB help Say 'Y' or 'M' to include support for Digigram VXpocket 440 soundcard. + +config SND_PDAUDIOCF + tristate "Sound Core PDAudioCF" + depends on SND && PCMCIA && ISA + help + Say 'Y' or 'M' to include support for Sound Core PDAudioCF soundcard. endmenu diff -Nru a/sound/pcmcia/Makefile b/sound/pcmcia/Makefile --- a/sound/pcmcia/Makefile Sun Mar 14 14:20:05 2004 +++ b/sound/pcmcia/Makefile Sun Mar 14 14:20:05 2004 @@ -3,6 +3,4 @@ # Copyright (c) 2001 by Jaroslav Kysela # -obj-$(CONFIG_SND) += vx/ - - +obj-$(CONFIG_SND) += vx/ pdaudiocf/ diff -Nru a/sound/pcmcia/pdaudiocf/Makefile b/sound/pcmcia/pdaudiocf/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pcmcia/pdaudiocf/Makefile Sun Mar 14 14:20:09 2004 @@ -0,0 +1,8 @@ +# +# Makefile for ALSA +# Copyright (c) 2004 by Jaroslav Kysela +# + +snd-pdaudiocf-objs := pdaudiocf.o pdaudiocf_core.o pdaudiocf_irq.o pdaudiocf_pcm.o + +obj-$(CONFIG_SND_PDAUDIOCF) += snd-pdaudiocf.o diff -Nru a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,426 @@ +/* + * Driver for Sound Core PDAudioCF soundcard + * + * Copyright (c) 2003 by Jaroslav Kysela + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include "pdaudiocf.h" +#define SNDRV_GET_ID +#include + +/* + */ + +#define CARD_NAME "PDAudio-CF" + +MODULE_AUTHOR("Jaroslav Kysela "); +MODULE_DESCRIPTION("Sound Core " CARD_NAME); +MODULE_LICENSE("GPL"); +MODULE_CLASSES("{sound}"); +MODULE_DEVICES("{{Sound Core," CARD_NAME "}}"); + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable switches */ +static unsigned int irq_mask = 0xffff; +static int irq_list[4] = { -1 }; + +MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); +MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); +MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s"); +MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); +MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); +MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); +MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); +MODULE_PARM(irq_mask, "i"); +MODULE_PARM_DESC(irq_mask, "IRQ bitmask for " CARD_NAME " soundcard."); +MODULE_PARM(irq_list, "1-4i"); +MODULE_PARM_DESC(irq_list, "List of Available interrupts for " CARD_NAME " soundcard."); + + +/* + */ + +static dev_info_t dev_info = "snd-pdaudiocf"; +static snd_card_t *card_list[SNDRV_CARDS]; +static dev_link_t *dev_list; + +/* + * prototypes + */ +static void pdacf_config(dev_link_t *link); +static int pdacf_event(event_t event, int priority, event_callback_args_t *args); +static void snd_pdacf_detach(dev_link_t *link); + +static void pdacf_release(dev_link_t *link) +{ + if (link->state & DEV_CONFIG) { + /* release cs resources */ + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); + link->state &= ~DEV_CONFIG; + } +} + +/* + * destructor + */ +static int snd_pdacf_free(pdacf_t *pdacf) +{ + dev_link_t *link = &pdacf->link; + + pdacf_release(link); + + /* Break the link with Card Services */ + if (link->handle) + pcmcia_deregister_client(link->handle); + + card_list[pdacf->index] = NULL; + pdacf->card = NULL; + + snd_magic_kfree(pdacf); + return 0; +} + +static int snd_pdacf_dev_free(snd_device_t *device) +{ + pdacf_t *chip = snd_magic_cast(pdacf_t, device->device_data, return -ENXIO); + return snd_pdacf_free(chip); +} + +/* + * snd_pdacf_attach - attach callback for cs + */ +static dev_link_t *snd_pdacf_attach(void) +{ + client_reg_t client_reg; /* Register with cardmgr */ + dev_link_t *link; /* Info for cardmgr */ + int i, ret; + pdacf_t *pdacf; + snd_card_t *card; + static snd_device_ops_t ops = { + .dev_free = snd_pdacf_dev_free, + }; + + snd_printdd(KERN_DEBUG "pdacf_attach called\n"); + /* find an empty slot from the card list */ + for (i = 0; i < SNDRV_CARDS; i++) { + if (! card_list[i]) + break; + } + if (i >= SNDRV_CARDS) { + snd_printk(KERN_ERR "pdacf: too many cards found\n"); + return NULL; + } + if (! enable[i]) + return NULL; /* disabled explicitly */ + + /* ok, create a card instance */ + card = snd_card_new(index[i], id[i], THIS_MODULE, 0); + if (card == NULL) { + snd_printk(KERN_ERR "pdacf: cannot create a card instance\n"); + return NULL; + } + + pdacf = snd_pdacf_create(card); + if (! pdacf) + return NULL; + + if (snd_device_new(card, SNDRV_DEV_LOWLEVEL, pdacf, &ops) < 0) { + snd_magic_kfree(pdacf); + snd_card_free(card); + return NULL; + } + + pdacf->index = i; + card_list[i] = card; + + link = &pdacf->link; + link->priv = pdacf; + + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + link->io.NumPorts1 = 16; + + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT | IRQ_FORCED_PULSE; + // link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; + + link->irq.IRQInfo1 = IRQ_INFO2_VALID /* | IRQ_LEVEL_ID */; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->irq.Handler = pdacf_interrupt; + link->irq.Instance = pdacf; + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.IntType = INT_MEMORY_AND_IO; + link->conf.ConfigIndex = 1; + link->conf.Present = PRESENT_OPTION; + + /* Chain drivers */ + link->next = dev_list; + dev_list = link; + + /* Register with Card Services */ + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL +#ifdef CONFIG_PM + | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET + | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME +#endif + ; + client_reg.event_handler = &pdacf_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + + ret = pcmcia_register_client(&link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + snd_pdacf_detach(link); + return NULL; + } + + return link; +} + + +/** + * snd_pdacf_assign_resources - initialize the hardware and card instance. + * @port: i/o port for the card + * @irq: irq number for the card + * + * this function assigns the specified port and irq, boot the card, + * create pcm and control instances, and initialize the rest hardware. + * + * returns 0 if successful, or a negative error code. + */ +static int snd_pdacf_assign_resources(pdacf_t *pdacf, int port, int irq) +{ + int err; + snd_card_t *card = pdacf->card; + + snd_printdd(KERN_DEBUG "pdacf assign resources: port = 0x%x, irq = %d\n", port, irq); + pdacf->port = port; + pdacf->irq = irq; + pdacf->chip_status |= PDAUDIOCF_STAT_IS_CONFIGURED; + + err = snd_pdacf_ak4117_create(pdacf); + if (err < 0) + return err; + + strcpy(card->driver, "PDAudio-CF"); + sprintf(card->shortname, "Core Sound %s", card->driver); + sprintf(card->longname, "%s at 0x%x, irq %i", + card->shortname, port, irq); + + err = snd_pdacf_pcm_new(pdacf); + if (err < 0) + return err; + +#ifdef CONFIG_PM + card->power_state_private_data = pdacf; + card->set_power_state = snd_pdacf_set_power_state; +#endif + + if ((err = snd_card_register(card)) < 0) + return err; + + return 0; +} + + +/* + * snd_pdacf_detach - detach callback for cs + */ +static void snd_pdacf_detach(dev_link_t *link) +{ + pdacf_t *chip = snd_magic_cast(pdacf_t, link->priv, return); + + snd_printdd(KERN_DEBUG "pdacf_detach called\n"); + /* Remove the interface data from the linked list */ + { + dev_link_t **linkp; + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) + break; + if (*linkp) + *linkp = link->next; + } + if (chip->chip_status & PDAUDIOCF_STAT_IS_CONFIGURED) + snd_pdacf_powerdown(chip); + chip->chip_status |= PDAUDIOCF_STAT_IS_STALE; /* to be sure */ + snd_card_disconnect(chip->card); + snd_card_free_in_thread(chip->card); +} + +/* + * snd_pdacf_detach_all - detach all instances linked to the hw + */ +static void snd_pdacf_detach_all(void) +{ + while (dev_list != NULL) + snd_pdacf_detach(dev_list); +} + +/* + * configuration callback + */ + +#define CS_CHECK(fn, ret) \ +do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) + +static void pdacf_config(dev_link_t *link) +{ + client_handle_t handle = link->handle; + pdacf_t *pdacf = snd_magic_cast(pdacf_t, link->priv, return); + tuple_t tuple; + cisparse_t parse; + config_info_t conf; + u_short buf[32]; + int last_fn, last_ret; + + snd_printdd(KERN_DEBUG "pdacf_config called\n"); + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + tuple.Attributes = 0; + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; + tuple.DesiredTuple = CISTPL_CONFIG; + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + link->conf.ConfigBase = parse.config.base; + link->conf.ConfigIndex = 0x5; + + CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); + link->conf.Vcc = conf.Vcc; + + /* Configure card */ + link->state |= DEV_CONFIG; + + CS_CHECK(RequestIO, pcmcia_request_io(handle, &link->io)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); + + if (snd_pdacf_assign_resources(pdacf, link->io.BasePort1, link->irq.AssignedIRQ) < 0) + goto failed; + + link->dev = &pdacf->node; + link->state &= ~DEV_CONFIG_PENDING; + return; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); +failed: + pcmcia_release_configuration(link->handle); + pcmcia_release_io(link->handle, &link->io); + pcmcia_release_irq(link->handle, &link->irq); +} + +/* + * event callback + */ +static int pdacf_event(event_t event, int priority, event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + pdacf_t *chip = link->priv; + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + snd_printdd(KERN_DEBUG "CARD_REMOVAL..\n"); + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + chip->chip_status |= PDAUDIOCF_STAT_IS_STALE; + } + break; + case CS_EVENT_CARD_INSERTION: + snd_printdd(KERN_DEBUG "CARD_INSERTION..\n"); + link->state |= DEV_PRESENT; + pdacf_config(link); + break; +#ifdef CONFIG_PM + case CS_EVENT_PM_SUSPEND: + snd_printdd(KERN_DEBUG "SUSPEND\n"); + link->state |= DEV_SUSPEND; + if (chip) { + snd_printdd(KERN_DEBUG "snd_pdacf_suspend calling\n"); + snd_pdacf_suspend(chip); + } + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + snd_printdd(KERN_DEBUG "RESET_PHYSICAL\n"); + if (link->state & DEV_CONFIG) + pcmcia_release_configuration(link->handle); + break; + case CS_EVENT_PM_RESUME: + snd_printdd(KERN_DEBUG "RESUME\n"); + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + snd_printdd(KERN_DEBUG "CARD_RESET\n"); + if (DEV_OK(link)) { + snd_printdd(KERN_DEBUG "requestconfig...\n"); + pcmcia_request_configuration(link->handle, &link->conf); + if (chip) { + snd_printdd(KERN_DEBUG "calling snd_pdacf_resume\n"); + snd_pdacf_resume(chip); + } + } + snd_printdd(KERN_DEBUG "resume done!\n"); + break; +#endif + } + return 0; +} + +/* + * Module entry points + */ +static struct pcmcia_driver pdacf_cs_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "snd-pdaudiocf", + }, + .attach = snd_pdacf_attach, + .detach = snd_pdacf_detach +}; + +static int __init init_pdacf(void) +{ + return pcmcia_register_driver(&pdacf_cs_driver); +} + +static void __exit exit_pdacf(void) +{ + pcmcia_unregister_driver(&pdacf_cs_driver); + snd_pdacf_detach_all(); +} + +module_init(init_pdacf); +module_exit(exit_pdacf); diff -Nru a/sound/pcmcia/pdaudiocf/pdaudiocf.h b/sound/pcmcia/pdaudiocf/pdaudiocf.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.h Sun Mar 14 14:20:09 2004 @@ -0,0 +1,148 @@ +/* + * Driver for Sound Cors PDAudioCF soundcard + * + * Copyright (c) 2003 by Jaroslav Kysela + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PDAUDIOCF_H +#define __PDAUDIOCF_H + +#include +#include +#include +#include +#include +#include +#include + +#include + +/* PDAUDIOCF registers */ +#define PDAUDIOCF_REG_MD 0x00 /* music data, R/O */ +#define PDAUDIOCF_REG_WDP 0x02 /* write data pointer / 2, R/O */ +#define PDAUDIOCF_REG_RDP 0x04 /* read data pointer / 2, R/O */ +#define PDAUDIOCF_REG_TCR 0x06 /* test control register W/O */ +#define PDAUDIOCF_REG_SCR 0x08 /* status and control, R/W (see bit description) */ +#define PDAUDIOCF_REG_ISR 0x0a /* interrupt status, R/O */ +#define PDAUDIOCF_REG_IER 0x0c /* interrupt enable, R/W */ +#define PDAUDIOCF_REG_AK_IFR 0x0e /* AK interface register, R/W */ + +/* PDAUDIOCF_REG_TCR */ +#define PDAUDIOCF_ELIMAKMBIT (1<<0) /* simulate AKM music data */ +#define PDAUDIOCF_TESTDATASEL (1<<1) /* test data selection, 0 = 0x55, 1 = pseudo-random */ + +/* PDAUDIOCF_REG_SCR */ +#define PDAUDIOCF_AK_SBP (1<<0) /* serial port busy flag */ +#define PDAUDIOCF_RST (1<<2) /* FPGA, AKM + SRAM buffer reset */ +#define PDAUDIOCF_PDN (1<<3) /* power down bit */ +#define PDAUDIOCF_CLKDIV0 (1<<4) /* choose 24.576Mhz clock divided by 1,2,3 or 4 */ +#define PDAUDIOCF_CLKDIV1 (1<<5) +#define PDAUDIOCF_RECORD (1<<6) /* start capturing to SRAM */ +#define PDAUDIOCF_AK_SDD (1<<7) /* music data detected */ +#define PDAUDIOCF_RED_LED_OFF (1<<8) /* red LED off override */ +#define PDAUDIOCF_BLUE_LED_OFF (1<<9) /* blue LED off override */ +#define PDAUDIOCF_DATAFMT0 (1<<10) /* data format bits: 00 = 16-bit, 01 = 18-bit */ +#define PDAUDIOCF_DATAFMT1 (1<<11) /* 10 = 20-bit, 11 = 24-bit, all right justified */ +#define PDAUDIOCF_FPGAREV(x) ((x>>12)&0x0f) /* FPGA revision */ + +/* PDAUDIOCF_REG_ISR */ +#define PDAUDIOCF_IRQLVL (1<<0) /* Buffer level IRQ */ +#define PDAUDIOCF_IRQOVR (1<<1) /* Overrun IRQ */ +#define PDAUDIOCF_IRQAKM (1<<2) /* AKM IRQ */ + +/* PDAUDIOCF_REG_IER */ +#define PDAUDIOCF_IRQLVLEN0 (1<<0) /* fill threshold levels; 00 = none, 01 = 1/8th of buffer */ +#define PDAUDIOCF_IRQLVLEN1 (1<<1) /* 10 = 1/4th of buffer, 11 = 1/2th of buffer */ +#define PDAUDIOCF_IRQOVREN (1<<2) /* enable overrun IRQ */ +#define PDAUDIOCF_IRQAKMEN (1<<3) /* enable AKM IRQ */ +#define PDAUDIOCF_BLUEDUTY0 (1<<8) /* blue LED duty cycle; 00 = 100%, 01 = 50% */ +#define PDAUDIOCF_BLUEDUTY1 (1<<9) /* 02 = 25%, 11 = 12% */ +#define PDAUDIOCF_REDDUTY0 (1<<10) /* red LED duty cycle; 00 = 100%, 01 = 50% */ +#define PDAUDIOCF_REDDUTY1 (1<<11) /* 02 = 25%, 11 = 12% */ +#define PDAUDIOCF_BLUESDD (1<<12) /* blue LED against SDD bit */ +#define PDAUDIOCF_BLUEMODULATE (1<<13) /* save power when 100% duty cycle selected */ +#define PDAUDIOCF_REDMODULATE (1<<14) /* save power when 100% duty cycle selected */ +#define PDAUDIOCF_HALFRATE (1<<15) /* slow both LED blinks by half (also spdif detect rate) */ + +/* chip status */ +#define PDAUDIOCF_STAT_IS_STALE (1<<0) +#define PDAUDIOCF_STAT_IS_CONFIGURED (1<<1) +#define PDAUDIOCF_STAT_IS_SUSPENDED (1<<2) + +typedef struct { + snd_card_t *card; + int index; + + unsigned long port; + int irq; + + spinlock_t reg_lock; + unsigned short regmap[8]; + unsigned short suspend_reg_scr; + struct tasklet_struct tq; + + spinlock_t ak4117_lock; + ak4117_t *ak4117; + + unsigned int chip_status; + + snd_pcm_t *pcm; + snd_pcm_substream_t *pcm_substream; + unsigned int pcm_running: 1; + unsigned int pcm_channels; + unsigned int pcm_swab; + unsigned int pcm_little; + unsigned int pcm_frame; + unsigned int pcm_sample; + unsigned int pcm_xor; + unsigned int pcm_size; + unsigned int pcm_period; + unsigned int pcm_tdone; + unsigned int pcm_hwptr; + void *pcm_area; + + /* pcmcia stuff */ + dev_link_t link; + dev_node_t node; +} pdacf_t; + +static inline void pdacf_reg_write(pdacf_t *chip, unsigned char reg, unsigned short val) +{ + outw(chip->regmap[reg>>1] = val, chip->port + reg); +} + +static inline unsigned short pdacf_reg_read(pdacf_t *chip, unsigned char reg) +{ + return inw(chip->port + reg); +} + +unsigned char pdacf_ak4117_read(void *private_data, unsigned char reg); +void pdacf_ak4117_write(void *private_data, unsigned char reg, unsigned char val); +pdacf_t *snd_pdacf_create(snd_card_t *card); +int snd_pdacf_ak4117_create(pdacf_t *pdacf); +void snd_pdacf_powerdown(pdacf_t *chip); +#ifdef CONFIG_PM +void snd_pdacf_suspend(pdacf_t *chip); +void snd_pdacf_resume(pdacf_t *chip); +int snd_pdacf_set_power_state(snd_card_t *card, unsigned int power_state); +#endif +int snd_pdacf_pcm_new(pdacf_t *chip); +void pdacf_interrupt(int irq, void *dev, struct pt_regs *regs); +void pdacf_tasklet(unsigned long private_data); +void pdacf_reinit(pdacf_t *chip, int resume); + +#endif /* __PDAUDIOCF_H */ diff -Nru a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,317 @@ +/* + * Driver for Sound Core PDAudioCF soundcard + * + * Copyright (c) 2003 by Jaroslav Kysela + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include "pdaudiocf.h" +#define SNDRV_GET_ID +#include + +/* + * + */ +unsigned char pdacf_ak4117_read(void *private_data, unsigned char reg) +{ + pdacf_t *chip = snd_magic_cast(pdacf_t, private_data, return 0); + unsigned long timeout; + unsigned long flags; + unsigned char res; + + spin_lock_irqsave(&chip->ak4117_lock, flags); + timeout = 1000; + while (pdacf_reg_read(chip, PDAUDIOCF_REG_SCR) & PDAUDIOCF_AK_SBP) { + udelay(5); + if (--timeout == 0) { + spin_unlock_irqrestore(&chip->ak4117_lock, flags); + snd_printk(KERN_ERR "AK4117 ready timeout (read)\n"); + return 0; + } + } + pdacf_reg_write(chip, PDAUDIOCF_REG_AK_IFR, (u16)reg << 8); + timeout = 1000; + while (pdacf_reg_read(chip, PDAUDIOCF_REG_SCR) & PDAUDIOCF_AK_SBP) { + udelay(5); + if (--timeout == 0) { + spin_unlock_irqrestore(&chip->ak4117_lock, flags); + snd_printk(KERN_ERR "AK4117 read timeout (read2)\n"); + return 0; + } + } + res = (unsigned char)pdacf_reg_read(chip, PDAUDIOCF_REG_AK_IFR); + spin_unlock_irqrestore(&chip->ak4117_lock, flags); + return res; +} + +void pdacf_ak4117_write(void *private_data, unsigned char reg, unsigned char val) +{ + pdacf_t *chip = snd_magic_cast(pdacf_t, private_data, return); + unsigned long timeout; + unsigned long flags; + + spin_lock_irqsave(&chip->ak4117_lock, flags); + timeout = 1000; + while (inw(chip->port + PDAUDIOCF_REG_SCR) & PDAUDIOCF_AK_SBP) { + udelay(5); + if (--timeout == 0) { + spin_unlock_irqrestore(&chip->ak4117_lock, flags); + snd_printk(KERN_ERR "AK4117 ready timeout (write)\n"); + return; + } + } + outw((u16)reg << 8 | val | (1<<13), chip->port + PDAUDIOCF_REG_AK_IFR); + spin_unlock_irqrestore(&chip->ak4117_lock, flags); +} + +#if 0 +void pdacf_dump(pdacf_t *chip) +{ + printk("PDAUDIOCF DUMP (0x%lx):\n", chip->port); + printk("WPD : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_WDP)); + printk("RDP : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_RDP)); + printk("TCR : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_TCR)); + printk("SCR : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_SCR)); + printk("ISR : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_ISR)); + printk("IER : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_IER)); + printk("AK_IFR : 0x%x\n", inw(chip->port + PDAUDIOCF_REG_AK_IFR)); +} +#endif + +static int pdacf_reset(pdacf_t *chip, int powerdown) +{ + u16 val; + + val = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR); + val |= PDAUDIOCF_PDN; + val &= ~PDAUDIOCF_RECORD; /* for sure */ + pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val); + udelay(5); + val |= PDAUDIOCF_RST; + pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val); + udelay(200); + val &= ~PDAUDIOCF_RST; + pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val); + udelay(5); + if (!powerdown) { + val &= ~PDAUDIOCF_PDN; + pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val); + udelay(200); + } + return 0; +} + +void pdacf_reinit(pdacf_t *chip, int resume) +{ + pdacf_reset(chip, 0); + if (resume) + pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, chip->suspend_reg_scr); + snd_ak4117_reinit(chip->ak4117); + pdacf_reg_write(chip, PDAUDIOCF_REG_TCR, chip->regmap[PDAUDIOCF_REG_TCR>>1]); + pdacf_reg_write(chip, PDAUDIOCF_REG_IER, chip->regmap[PDAUDIOCF_REG_IER>>1]); +} + +static void pdacf_proc_read(snd_info_entry_t * entry, + snd_info_buffer_t * buffer) +{ + pdacf_t *chip = snd_magic_cast(pdacf_t, entry->private_data, return); + u16 tmp; + + snd_iprintf(buffer, "PDAudioCF\n\n"); + tmp = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR); + snd_iprintf(buffer, "FPGA revision : 0x%x\n", PDAUDIOCF_FPGAREV(tmp)); + +} + +static void pdacf_proc_init(pdacf_t *chip) +{ + snd_info_entry_t *entry; + + if (! snd_card_proc_new(chip->card, "pdaudiocf", &entry)) + snd_info_set_text_ops(entry, chip, 1024, pdacf_proc_read); +} + +pdacf_t *snd_pdacf_create(snd_card_t *card) +{ + pdacf_t *chip; + + chip = snd_magic_kcalloc(pdacf_t, 0, GFP_KERNEL); + if (chip == NULL) + return NULL; + chip->card = card; + spin_lock_init(&chip->reg_lock); + spin_lock_init(&chip->ak4117_lock); + tasklet_init(&chip->tq, pdacf_tasklet, (unsigned long)chip); + card->private_data = chip; + + pdacf_proc_init(chip); + return chip; +} + +static void snd_pdacf_ak4117_change(ak4117_t *ak4117, unsigned char c0, unsigned char c1) +{ + pdacf_t *chip = ak4117->change_callback_private; + unsigned long flags; + u16 val; + + if (!(c0 & AK4117_UNLCK)) + return; + spin_lock_irqsave(&chip->reg_lock, flags); + val = chip->regmap[PDAUDIOCF_REG_SCR>>1]; + if (ak4117->rcs0 & AK4117_UNLCK) + val |= PDAUDIOCF_BLUE_LED_OFF; + else + val &= ~PDAUDIOCF_BLUE_LED_OFF; + pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val); + spin_unlock_irqrestore(&chip->reg_lock, flags); +} + +int snd_pdacf_ak4117_create(pdacf_t *chip) +{ + int err; + u16 val; + /* design note: if we unmask PLL unlock, parity, valid, audio or auto bit interrupts */ + /* from AK4117 then INT1 pin from AK4117 will be high all time, because PCMCIA interrupts are */ + /* egde based and FPGA does logical OR for all interrupt sources, we cannot use these */ + /* high-rate sources */ + static unsigned char pgm[5] = { + AK4117_XTL_24_576M | AK4117_EXCT, /* AK4117_REG_PWRDN */ + AK4117_CM_PLL_XTAL | AK4117_PKCS_128fs | AK4117_XCKS_128fs, /* AK4117_REQ_CLOCK */ + AK4117_EFH_1024LRCLK | AK4117_DIF_24R | AK4117_IPS, /* AK4117_REG_IO */ + 0xff, /* AK4117_REG_INT0_MASK */ + AK4117_MAUTO | AK4117_MAUD | AK4117_MULK | AK4117_MPAR | AK4117_MV, /* AK4117_REG_INT1_MASK */ + }; + + err = pdacf_reset(chip, 0); + if (err < 0) + return err; + err = snd_ak4117_create(chip->card, pdacf_ak4117_read, pdacf_ak4117_write, pgm, chip, &chip->ak4117); + if (err < 0) + return err; + + val = pdacf_reg_read(chip, PDAUDIOCF_REG_TCR); +#if 1 /* normal operation */ + val &= ~(PDAUDIOCF_ELIMAKMBIT|PDAUDIOCF_TESTDATASEL); +#else /* debug */ + val |= PDAUDIOCF_ELIMAKMBIT; + val &= ~PDAUDIOCF_TESTDATASEL; +#endif + pdacf_reg_write(chip, PDAUDIOCF_REG_TCR, val); + + /* setup the FPGA to match AK4117 setup */ + val = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR); + val &= ~(PDAUDIOCF_CLKDIV0 | PDAUDIOCF_CLKDIV1); /* use 24.576Mhz clock */ + val &= ~(PDAUDIOCF_RED_LED_OFF|PDAUDIOCF_BLUE_LED_OFF); + val |= PDAUDIOCF_DATAFMT0 | PDAUDIOCF_DATAFMT1; /* 24-bit data */ + pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val); + + /* setup LEDs and IRQ */ + val = pdacf_reg_read(chip, PDAUDIOCF_REG_IER); + val &= ~(PDAUDIOCF_IRQLVLEN0 | PDAUDIOCF_IRQLVLEN1); + val &= ~(PDAUDIOCF_BLUEDUTY0 | PDAUDIOCF_REDDUTY0 | PDAUDIOCF_REDDUTY1); + val |= PDAUDIOCF_BLUEDUTY1 | PDAUDIOCF_HALFRATE; + val |= PDAUDIOCF_IRQOVREN | PDAUDIOCF_IRQAKMEN; + pdacf_reg_write(chip, PDAUDIOCF_REG_IER, val); + + chip->ak4117->change_callback_private = chip; + chip->ak4117->change_callback = snd_pdacf_ak4117_change; + + /* update LED status */ + snd_pdacf_ak4117_change(chip->ak4117, AK4117_UNLCK, 0); + + return 0; +} + +void snd_pdacf_powerdown(pdacf_t *chip) +{ + u16 val; + + val = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR); + chip->suspend_reg_scr = val; + val |= PDAUDIOCF_RED_LED_OFF | PDAUDIOCF_BLUE_LED_OFF; + pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val); + /* disable interrupts, but use direct write to preserve old register value in chip->regmap */ + val = inw(chip->port + PDAUDIOCF_REG_IER); + val &= ~(PDAUDIOCF_IRQOVREN|PDAUDIOCF_IRQAKMEN|PDAUDIOCF_IRQLVLEN0|PDAUDIOCF_IRQLVLEN1); + outw(val, chip->port + PDAUDIOCF_REG_IER); + pdacf_reset(chip, 1); +} + +#ifdef CONFIG_PM + +void snd_pdacf_suspend(pdacf_t *chip) +{ + snd_card_t *card = chip->card; + u16 val; + + if (card->power_state == SNDRV_CTL_POWER_D3hot) + return; + snd_pcm_suspend_all(chip->pcm); + /* disable interrupts, but use direct write to preserve old register value in chip->regmap */ + val = inw(chip->port + PDAUDIOCF_REG_IER); + val &= ~(PDAUDIOCF_IRQOVREN|PDAUDIOCF_IRQAKMEN|PDAUDIOCF_IRQLVLEN0|PDAUDIOCF_IRQLVLEN1); + outw(val, chip->port + PDAUDIOCF_REG_IER); + chip->chip_status |= PDAUDIOCF_STAT_IS_SUSPENDED; /* ignore interrupts from now */ + snd_pdacf_powerdown(chip); + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); +} + +static inline int check_signal(pdacf_t *chip) +{ + return (chip->ak4117->rcs0 & AK4117_UNLCK) == 0; +} + +void snd_pdacf_resume(pdacf_t *chip) +{ + snd_card_t *card = chip->card; + int timeout = 40; + + if (card->power_state == SNDRV_CTL_POWER_D0) + return; + pdacf_reinit(chip, 1); + /* wait for AK4117's PLL */ + while (timeout-- > 0 && + (snd_ak4117_external_rate(chip->ak4117) <= 0 || !check_signal(chip))) + mdelay(1); + chip->chip_status &= ~PDAUDIOCF_STAT_IS_SUSPENDED; + snd_power_change_state(card, SNDRV_CTL_POWER_D0); +} + +int snd_pdacf_set_power_state(snd_card_t *card, unsigned int power_state) +{ + pdacf_t *chip = snd_magic_cast(pdacf_t, card->power_state_private_data, return -ENXIO); + + switch (power_state) { + case SNDRV_CTL_POWER_D0: + case SNDRV_CTL_POWER_D1: + case SNDRV_CTL_POWER_D2: + snd_pdacf_resume(chip); + break; + case SNDRV_CTL_POWER_D3hot: + case SNDRV_CTL_POWER_D3cold: + snd_pdacf_suspend(chip); + break; + default: + return -EINVAL; + } + return 0; +} + +#endif diff -Nru a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,325 @@ +/* + * Driver for Sound Core PDAudioCF soundcard + * + * Copyright (c) 2003 by Jaroslav Kysela + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include "pdaudiocf.h" +#define SNDRV_GET_ID +#include + +/* + * + */ +void pdacf_interrupt(int irq, void *dev, struct pt_regs *regs) +{ + pdacf_t *chip = snd_magic_cast(pdacf_t, dev, return); + unsigned short stat; + + if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE| + PDAUDIOCF_STAT_IS_CONFIGURED| + PDAUDIOCF_STAT_IS_SUSPENDED)) != PDAUDIOCF_STAT_IS_CONFIGURED) + return; + + stat = inw(chip->port + PDAUDIOCF_REG_ISR); + if (stat & (PDAUDIOCF_IRQLVL|PDAUDIOCF_IRQOVR)) { + if (stat & PDAUDIOCF_IRQOVR) /* should never happen */ + snd_printk(KERN_ERR "PDAUDIOCF SRAM buffer overrun detected!\n"); + if (chip->pcm_substream) + tasklet_hi_schedule(&chip->tq); + if (!(stat & PDAUDIOCF_IRQAKM)) + stat |= PDAUDIOCF_IRQAKM; /* check rate */ + } + if (regs != NULL) + snd_ak4117_check_rate_and_errors(chip->ak4117, 0); +} + +static inline void pdacf_transfer_mono16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port) +{ + while (size-- > 0) { + *dst++ = inw(rdp_port) ^ xor; + inw(rdp_port); + } +} + +static inline void pdacf_transfer_mono32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port) +{ + register u16 val1, val2; + + while (size-- > 0) { + val1 = inw(rdp_port); + val2 = inw(rdp_port); + inw(rdp_port); + *dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor; + } +} + +static inline void pdacf_transfer_stereo16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port) +{ + while (size-- > 0) { + *dst++ = inw(rdp_port) ^ xor; + *dst++ = inw(rdp_port) ^ xor; + } +} + +static inline void pdacf_transfer_stereo32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port) +{ + register u16 val1, val2, val3; + + while (size-- > 0) { + val1 = inw(rdp_port); + val2 = inw(rdp_port); + val3 = inw(rdp_port); + *dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor; + *dst++ = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor; + } +} + +static inline void pdacf_transfer_mono16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port) +{ + while (size-- > 0) { + *dst++ = swab16(inw(rdp_port) ^ xor); + inw(rdp_port); + } +} + +static inline void pdacf_transfer_mono32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port) +{ + register u16 val1, val2; + + while (size-- > 0) { + val1 = inw(rdp_port); + val2 = inw(rdp_port); + inw(rdp_port); + *dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor); + } +} + +static inline void pdacf_transfer_stereo16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port) +{ + while (size-- > 0) { + *dst++ = swab16(inw(rdp_port) ^ xor); + *dst++ = swab16(inw(rdp_port) ^ xor); + } +} + +static inline void pdacf_transfer_stereo32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port) +{ + register u16 val1, val2, val3; + + while (size-- > 0) { + val1 = inw(rdp_port); + val2 = inw(rdp_port); + val3 = inw(rdp_port); + *dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor); + *dst++ = swab32((((u32)val3 << 16) | (val2 & 0xff00)) ^ xor); + } +} + +static inline void pdacf_transfer_mono24le(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port) +{ + register u16 val1, val2; + register u32 xval1; + + while (size-- > 0) { + val1 = inw(rdp_port); + val2 = inw(rdp_port); + inw(rdp_port); + xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor; + *dst++ = (u8)(xval1 >> 8); + *dst++ = (u8)(xval1 >> 16); + *dst++ = (u8)(xval1 >> 24); + } +} + +static inline void pdacf_transfer_mono24be(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port) +{ + register u16 val1, val2; + register u32 xval1; + + while (size-- > 0) { + val1 = inw(rdp_port); + val2 = inw(rdp_port); + inw(rdp_port); + xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor; + *dst++ = (u8)(xval1 >> 24); + *dst++ = (u8)(xval1 >> 16); + *dst++ = (u8)(xval1 >> 8); + } +} + +static inline void pdacf_transfer_stereo24le(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port) +{ + register u16 val1, val2, val3; + register u32 xval1, xval2; + + while (size-- > 0) { + val1 = inw(rdp_port); + val2 = inw(rdp_port); + val3 = inw(rdp_port); + xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor; + xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor; + *dst++ = (u8)(xval1 >> 8); + *dst++ = (u8)(xval1 >> 16); + *dst++ = (u8)(xval1 >> 24); + *dst++ = (u8)(xval2 >> 8); + *dst++ = (u8)(xval2 >> 16); + *dst++ = (u8)(xval2 >> 24); + } +} + +static inline void pdacf_transfer_stereo24be(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port) +{ + register u16 val1, val2, val3; + register u32 xval1, xval2; + + while (size-- > 0) { + val1 = inw(rdp_port); + val2 = inw(rdp_port); + val3 = inw(rdp_port); + xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor; + xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor; + *dst++ = (u8)(xval1 >> 24); + *dst++ = (u8)(xval1 >> 16); + *dst++ = (u8)(xval1 >> 8); + *dst++ = (u8)(xval2 >> 24); + *dst++ = (u8)(xval2 >> 16); + *dst++ = (u8)(xval2 >> 8); + } +} + +static void pdacf_transfer(pdacf_t *chip, unsigned int size, unsigned int off) +{ + unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD; + unsigned int xor = chip->pcm_xor; + + if (chip->pcm_sample == 3) { + if (chip->pcm_little) { + if (chip->pcm_channels == 1) { + pdacf_transfer_mono24le((char *)chip->pcm_area + (off * 3), xor, size, rdp_port); + } else { + pdacf_transfer_stereo24le((char *)chip->pcm_area + (off * 6), xor, size, rdp_port); + } + } else { + if (chip->pcm_channels == 1) { + pdacf_transfer_mono24be((char *)chip->pcm_area + (off * 3), xor, size, rdp_port); + } else { + pdacf_transfer_stereo24be((char *)chip->pcm_area + (off * 6), xor, size, rdp_port); + } + } + return; + } + if (chip->pcm_swab == 0) { + if (chip->pcm_channels == 1) { + if (chip->pcm_frame == 2) { + pdacf_transfer_mono16((u16 *)chip->pcm_area + off, xor, size, rdp_port); + } else { + pdacf_transfer_mono32((u32 *)chip->pcm_area + off, xor, size, rdp_port); + } + } else { + if (chip->pcm_frame == 2) { + pdacf_transfer_stereo16((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port); + } else { + pdacf_transfer_stereo32((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port); + } + } + } else { + if (chip->pcm_channels == 1) { + if (chip->pcm_frame == 2) { + pdacf_transfer_mono16sw((u16 *)chip->pcm_area + off, xor, size, rdp_port); + } else { + pdacf_transfer_mono32sw((u32 *)chip->pcm_area + off, xor, size, rdp_port); + } + } else { + if (chip->pcm_frame == 2) { + pdacf_transfer_stereo16sw((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port); + } else { + pdacf_transfer_stereo32sw((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port); + } + } + } +} + +void pdacf_tasklet(unsigned long private_data) +{ + pdacf_t *chip = snd_magic_cast(pdacf_t, (void *)private_data, return); + int size, off, cont, rdp, wdp; + + if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|PDAUDIOCF_STAT_IS_CONFIGURED)) != PDAUDIOCF_STAT_IS_CONFIGURED) + return; + + if (chip->pcm_substream == NULL || chip->pcm_substream->runtime == NULL || !snd_pcm_running(chip->pcm_substream)) + return; + + rdp = inw(chip->port + PDAUDIOCF_REG_RDP); + wdp = inw(chip->port + PDAUDIOCF_REG_WDP); + // printk("TASKLET: rdp = %x, wdp = %x\n", rdp, wdp); + size = wdp - rdp; + if (size < 0) + size += 0x10000; + if (size == 0) + size = 0x10000; + size /= chip->pcm_frame; + if (size > 64) + size -= 32; + +#if 0 + chip->pcm_hwptr += size; + chip->pcm_hwptr %= chip->pcm_size; + chip->pcm_tdone += size; + if (chip->pcm_frame == 2) { + unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD; + while (size-- > 0) { + inw(rdp_port); + inw(rdp_port); + } + } else { + unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD; + while (size-- > 0) { + inw(rdp_port); + inw(rdp_port); + inw(rdp_port); + } + } +#else + off = chip->pcm_hwptr + chip->pcm_tdone; + off %= chip->pcm_size; + chip->pcm_tdone += size; + while (size > 0) { + cont = chip->pcm_size - off; + if (cont > size) + cont = size; + pdacf_transfer(chip, cont, off); + off += cont; + off %= chip->pcm_size; + size -= cont; + } +#endif + spin_lock(&chip->reg_lock); + while (chip->pcm_tdone >= chip->pcm_period) { + chip->pcm_hwptr += chip->pcm_period; + chip->pcm_hwptr %= chip->pcm_size; + chip->pcm_tdone -= chip->pcm_period; + spin_unlock(&chip->reg_lock); + snd_pcm_period_elapsed(chip->pcm_substream); + spin_lock(&chip->reg_lock); + } + spin_unlock(&chip->reg_lock); + // printk("TASKLET: end\n"); +} diff -Nru a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c Sun Mar 14 14:20:09 2004 @@ -0,0 +1,363 @@ +/* + * Driver for Sound Core PDAudioCF soundcards + * + * PCM part + * + * Copyright (c) 2003 by Jaroslav Kysela + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include "pdaudiocf.h" + +#define chip_t pdacf_t + + +/* + * we use a vmalloc'ed (sg-)buffer + */ + +/* get the physical page pointer on the given offset */ +static struct page *snd_pcm_get_vmalloc_page(snd_pcm_substream_t *subs, unsigned long offset) +{ + void *pageptr = subs->runtime->dma_area + offset; + return vmalloc_to_page(pageptr); +} + +/* + * hw_params callback + * NOTE: this may be called not only once per pcm open! + */ +static int snd_pcm_alloc_vmalloc_buffer(snd_pcm_substream_t *subs, size_t size) +{ + snd_pcm_runtime_t *runtime = subs->runtime; + if (runtime->dma_area) { + if (runtime->dma_bytes >= size) + return 0; /* already enough large */ + vfree_nocheck(runtime->dma_area); + } + runtime->dma_area = vmalloc_nocheck(size); + if (! runtime->dma_area) + return -ENOMEM; + runtime->dma_bytes = size; + return 0; +} + +/* + * hw_free callback + * NOTE: this may be called not only once per pcm open! + */ +static int snd_pcm_free_vmalloc_buffer(snd_pcm_substream_t *subs) +{ + snd_pcm_runtime_t *runtime = subs->runtime; + if (runtime->dma_area) { + vfree_nocheck(runtime->dma_area); + runtime->dma_area = NULL; + } + return 0; +} + +/* + * clear the SRAM contents + */ +static int pdacf_pcm_clear_sram(pdacf_t *chip) +{ + int max_loop = 64 * 1024; + + while (inw(chip->port + PDAUDIOCF_REG_RDP) != inw(chip->port + PDAUDIOCF_REG_WDP)) { + if (max_loop-- < 0) + return -EIO; + inw(chip->port + PDAUDIOCF_REG_MD); + } + return 0; +} + +/* + * pdacf_pcm_trigger - trigger callback for capture + */ +static int pdacf_pcm_trigger(snd_pcm_substream_t *subs, int cmd) +{ + pdacf_t *chip = snd_pcm_substream_chip(subs); + snd_pcm_runtime_t *runtime = subs->runtime; + int inc, ret = 0, rate; + unsigned short mask, val, tmp; + + if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE) + return -EBUSY; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + chip->pcm_hwptr = 0; + chip->pcm_tdone = 0; + /* fall thru */ + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + mask = 0; + val = PDAUDIOCF_RECORD; + inc = 1; + rate = snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_STAT|AK4117_CHECK_NO_RATE); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + mask = PDAUDIOCF_RECORD; + val = 0; + inc = -1; + rate = 0; + break; + default: + return -EINVAL; + } + spin_lock(&chip->reg_lock); + chip->pcm_running += inc; + tmp = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR); + if (chip->pcm_running) { + if ((chip->ak4117->rcs0 & AK4117_UNLCK) || runtime->rate != rate) { + chip->pcm_running -= inc; + ret = -EIO; + goto __end; + } + } + tmp &= ~mask; + tmp |= val; + pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, tmp); + __end: + spin_unlock(&chip->reg_lock); + snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_RATE); + return ret; +} + +/* + * pdacf_pcm_hw_params - hw_params callback for playback and capture + */ +static int pdacf_pcm_hw_params(snd_pcm_substream_t *subs, + snd_pcm_hw_params_t *hw_params) +{ + return snd_pcm_alloc_vmalloc_buffer(subs, params_buffer_bytes(hw_params)); +} + +/* + * pdacf_pcm_hw_free - hw_free callback for playback and capture + */ +static int pdacf_pcm_hw_free(snd_pcm_substream_t *subs) +{ + return snd_pcm_free_vmalloc_buffer(subs); +} + +/* + * pdacf_pcm_prepare - prepare callback for playback and capture + */ +static int pdacf_pcm_prepare(snd_pcm_substream_t *subs) +{ + pdacf_t *chip = snd_pcm_substream_chip(subs); + snd_pcm_runtime_t *runtime = subs->runtime; + u16 val, nval, aval; + + if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE) + return -EBUSY; + + chip->pcm_channels = runtime->channels; + + chip->pcm_little = snd_pcm_format_little_endian(runtime->format) > 0; +#ifdef SNDRV_LITTLE_ENDIAN + chip->pcm_swab = snd_pcm_format_big_endian(runtime->format) > 0; +#else + chip->pcm_swab = chip->pcm_little; +#endif + + if (snd_pcm_format_unsigned(runtime->format)) + chip->pcm_xor = 0x80008000; + + if (pdacf_pcm_clear_sram(chip) < 0) + return -EIO; + + val = nval = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR); + nval &= ~(PDAUDIOCF_DATAFMT0|PDAUDIOCF_DATAFMT1); + switch (runtime->format) { + case SNDRV_PCM_FORMAT_S16_LE: + case SNDRV_PCM_FORMAT_S16_BE: + break; + default: /* 24-bit */ + nval |= PDAUDIOCF_DATAFMT0 | PDAUDIOCF_DATAFMT1; + break; + } + aval = 0; + chip->pcm_sample = 4; + switch (runtime->format) { + case SNDRV_PCM_FORMAT_S16_LE: + case SNDRV_PCM_FORMAT_S16_BE: + aval = AK4117_DIF_16R; + chip->pcm_frame = 2; + chip->pcm_sample = 2; + break; + case SNDRV_PCM_FORMAT_S24_3LE: + case SNDRV_PCM_FORMAT_S24_3BE: + chip->pcm_sample = 3; + /* fall trough */ + default: /* 24-bit */ + aval = AK4117_DIF_24R; + chip->pcm_frame = 3; + chip->pcm_xor &= 0xffff0000; + break; + } + + if (val != nval) { + snd_ak4117_reg_write(chip->ak4117, AK4117_REG_IO, AK4117_DIF2|AK4117_DIF1|AK4117_DIF0, aval); + pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, nval); + } + + val = pdacf_reg_read(chip, PDAUDIOCF_REG_IER); + val &= ~(PDAUDIOCF_IRQLVLEN1); + val |= PDAUDIOCF_IRQLVLEN0; + pdacf_reg_write(chip, PDAUDIOCF_REG_IER, val); + + chip->pcm_size = runtime->buffer_size; + chip->pcm_period = runtime->period_size; + chip->pcm_area = runtime->dma_area; + + return 0; +} + + +/* + * capture hw information + */ + +static snd_pcm_hardware_t pdacf_pcm_capture_hw = { + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE, + .rates = SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_192000, + .rate_min = 32000, + .rate_max = 192000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = (512*1024), + .period_bytes_min = 8*1024, + .period_bytes_max = (64*1024), + .periods_min = 2, + .periods_max = 128, + .fifo_size = 0, +}; + + +/* + * pdacf_pcm_capture_open - open callback for capture + */ +static int pdacf_pcm_capture_open(snd_pcm_substream_t *subs) +{ + snd_pcm_runtime_t *runtime = subs->runtime; + pdacf_t *chip = snd_pcm_substream_chip(subs); + + if (chip->chip_status & PDAUDIOCF_STAT_IS_STALE) + return -EBUSY; + + runtime->hw = pdacf_pcm_capture_hw; + runtime->private_data = chip; + chip->pcm_substream = subs; + + return 0; +} + +/* + * pdacf_pcm_capture_close - close callback for capture + */ +static int pdacf_pcm_capture_close(snd_pcm_substream_t *subs) +{ + pdacf_t *chip = snd_pcm_substream_chip(subs); + + if (!chip) + return -EINVAL; + pdacf_reinit(chip, 0); + chip->pcm_substream = NULL; + return 0; +} + + +/* + * pdacf_pcm_capture_pointer - pointer callback for capture + */ +static snd_pcm_uframes_t pdacf_pcm_capture_pointer(snd_pcm_substream_t *subs) +{ + pdacf_t *chip = snd_pcm_substream_chip(subs); + return chip->pcm_hwptr; +} + +/* + * operators for PCM capture + */ +static snd_pcm_ops_t pdacf_pcm_capture_ops = { + .open = pdacf_pcm_capture_open, + .close = pdacf_pcm_capture_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = pdacf_pcm_hw_params, + .hw_free = pdacf_pcm_hw_free, + .prepare = pdacf_pcm_prepare, + .trigger = pdacf_pcm_trigger, + .pointer = pdacf_pcm_capture_pointer, + .page = snd_pcm_get_vmalloc_page, +}; + + +/* + * free callback for pcm + */ +static void snd_pdacf_pcm_free(snd_pcm_t *pcm) +{ + pdacf_t *chip = snd_magic_cast(pdacf_t, pcm->private_data, return); + chip->pcm = NULL; +} + +/* + * snd_pdacf_pcm_new - create and initialize a pcm + */ +int snd_pdacf_pcm_new(pdacf_t *chip) +{ + snd_pcm_t *pcm; + int err; + + err = snd_pcm_new(chip->card, "PDAudioCF", 0, 0, 1, &pcm); + if (err < 0) + return err; + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pdacf_pcm_capture_ops); + + pcm->private_data = chip; + pcm->private_free = snd_pdacf_pcm_free; + pcm->info_flags = 0; + strcpy(pcm->name, chip->card->shortname); + chip->pcm = pcm; + + err = snd_ak4117_build(chip->ak4117, pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream); + if (err < 0) + return err; + + return 0; +} diff -Nru a/sound/ppc/Kconfig b/sound/ppc/Kconfig --- a/sound/ppc/Kconfig Sun Mar 14 14:20:07 2004 +++ b/sound/ppc/Kconfig Sun Mar 14 14:20:07 2004 @@ -6,6 +6,7 @@ config SND_POWERMAC tristate "PowerMac (AWACS, DACA, Burgundy, Tumbler, Keywest)" depends on SND + select SND_PCM endmenu diff -Nru a/sound/ppc/pmac.c b/sound/ppc/pmac.c --- a/sound/ppc/pmac.c Sun Mar 14 14:20:09 2004 +++ b/sound/ppc/pmac.c Sun Mar 14 14:20:09 2004 @@ -664,7 +664,9 @@ chip->capture.cur_freqs = chip->freqs_ok; /* preallocate 64k buffer */ - snd_pcm_lib_preallocate_pages_for_all(pcm, 64 * 1024, 64 * 1024, GFP_KERNEL); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, + snd_pcm_dma_flags(GFP_KERNEL), + 64 * 1024, 64 * 1024); return 0; } diff -Nru a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c --- a/sound/ppc/tumbler.c Sun Mar 14 14:20:06 2004 +++ b/sound/ppc/tumbler.c Sun Mar 14 14:20:06 2004 @@ -94,6 +94,7 @@ unsigned int mix_vol[VOL_IDX_LAST_MIX][2]; /* stereo volumes for tas3004 */ int drc_range; int drc_enable; + int capture_source; } pmac_tumbler_t; @@ -135,7 +136,7 @@ TAS_REG_MCS, (1<<6)|(2<<4)|0, /* normal operation, all-pass mode */ TAS_REG_MCS2, (1<<1), - /* normal output, no deemphasis, A input, power-up */ + /* normal output, no deemphasis, A input, power-up, line-in */ TAS_REG_ACS, 0, 0, /* terminator */ }; @@ -681,6 +682,51 @@ return 0; } +static int snapper_set_capture_source(pmac_tumbler_t *mix) +{ + return snd_pmac_keywest_write_byte(&mix->i2c, TAS_REG_ACS, + mix->capture_source ? 2 : 0); +} + +static int snapper_info_capture_source(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + static char *texts[2] = { + "Line", "Mic" + }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 2; + if (uinfo->value.enumerated.item > 1) + uinfo->value.enumerated.item = 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snapper_get_capture_source(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + pmac_t *chip = snd_kcontrol_chip(kcontrol); + pmac_tumbler_t *mix = chip->mixer_data; + + snd_assert(mix, return -ENODEV); + ucontrol->value.integer.value[0] = mix->capture_source; + return 0; +} + +static int snapper_put_capture_source(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + pmac_t *chip = snd_kcontrol_chip(kcontrol); + pmac_tumbler_t *mix = chip->mixer_data; + int change; + + snd_assert(mix, return -ENODEV); + change = ucontrol->value.integer.value[0] != mix->capture_source; + if (change) { + mix->capture_source = !!ucontrol->value.integer.value[0]; + snapper_set_capture_source(mix); + } + return change; +} + #define DEFINE_SNAPPER_MIX(xname,idx,ofs) { \ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,\ .name = xname, \ @@ -754,6 +800,12 @@ .get = tumbler_get_drc_value, .put = tumbler_put_drc_value }, + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input Source", /* FIXME: "Capture Source" doesn't work properly */ + .info = snapper_info_capture_source, + .get = snapper_get_capture_source, + .put = snapper_put_capture_source + }, }; static snd_kcontrol_new_t tumbler_hp_sw __initdata = { @@ -929,9 +981,10 @@ snapper_set_mix_vol(mix, VOL_IDX_PCM); snapper_set_mix_vol(mix, VOL_IDX_PCM2); snapper_set_mix_vol(mix, VOL_IDX_ADC); - tumbler_set_mono_volume(mix, &tumbler_bass_vol_info); - tumbler_set_mono_volume(mix, &tumbler_treble_vol_info); + tumbler_set_mono_volume(mix, &snapper_bass_vol_info); + tumbler_set_mono_volume(mix, &snapper_treble_vol_info); snapper_set_drc(mix); + snapper_set_capture_source(mix); } tumbler_set_master_volume(mix); if (chip->update_automute) diff -Nru a/sound/sparc/Kconfig b/sound/sparc/Kconfig --- a/sound/sparc/Kconfig Sun Mar 14 14:20:08 2004 +++ b/sound/sparc/Kconfig Sun Mar 14 14:20:08 2004 @@ -6,11 +6,13 @@ config SND_SUN_AMD7930 tristate "Sun AMD7930" depends on SBUS && SND + select SND_PCM # dep_tristate 'Sun DBRI' CONFIG_SND_SUN_DBRI $CONFIG_SND config SND_SUN_CS4231 tristate "Sun CS4231" depends on SND + select SND_PCM endmenu diff -Nru a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c --- a/sound/sparc/amd7930.c Sun Mar 14 14:20:06 2004 +++ b/sound/sparc/amd7930.c Sun Mar 14 14:20:06 2004 @@ -791,7 +791,9 @@ strcpy(pcm->name, amd->card->shortname); amd->pcm = pcm; - snd_pcm_lib_preallocate_pages_for_all(pcm, 64*1024, 64*1024, GFP_KERNEL); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), + 64*1024, 64*1024); return 0; } diff -Nru a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c --- a/sound/sparc/cs4231.c Sun Mar 14 14:20:06 2004 +++ b/sound/sparc/cs4231.c Sun Mar 14 14:20:06 2004 @@ -1570,13 +1570,15 @@ #ifdef EBUS_SUPPORT if (chip->flags & CS4231_FLAG_EBUS) { - snd_pcm_lib_preallocate_pci_pages_for_all(chip->dev_u.pdev, pcm, - 64*1024, 128*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_PCI, + snd_dma_pci_data(chip->dev_u.pdev) + 64*1024, 128*1024); } else { #endif #ifdef SBUS_SUPPORT - snd_pcm_lib_preallocate_sbus_pages_for_all(chip->dev_u.sdev, pcm, - 64*1024, 128*1024); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_SBUS, + snd_dma_sbus_data(chip->dev_u.sdev), + 64*1024, 128*1024); #endif #ifdef EBUS_SUPPORT } diff -Nru a/sound/synth/Makefile b/sound/synth/Makefile --- a/sound/synth/Makefile Sun Mar 14 14:20:06 2004 +++ b/sound/synth/Makefile Sun Mar 14 14:20:06 2004 @@ -5,10 +5,16 @@ snd-util-mem-objs := util_mem.o +# +# this function returns: +# "m" - CONFIG_SND_SEQUENCER is m +# - CONFIG_SND_SEQUENCER is undefined +# otherwise parameter #1 value +# +sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) + # Toplevel Module Dependency obj-$(CONFIG_SND_EMU10K1) += snd-util-mem.o obj-$(CONFIG_SND_TRIDENT) += snd-util-mem.o -ifdef CONFIG_SND_SEQUENCER - obj-$(CONFIG_SND_SBAWE) += snd-util-mem.o - obj-$(CONFIG_SND) += emux/ -endif +obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += snd-util-mem.o +obj-$(call sequencer,$(CONFIG_SND)) += emux/ diff -Nru a/sound/usb/Kconfig b/sound/usb/Kconfig --- a/sound/usb/Kconfig Sun Mar 14 14:20:08 2004 +++ b/sound/usb/Kconfig Sun Mar 14 14:20:08 2004 @@ -6,6 +6,8 @@ config SND_USB_AUDIO tristate "USB Audio/MIDI driver" depends on SND && USB + select SND_RAWMIDI + select SND_PCM help Say 'Y' or 'M' to include support for USB audio and USB MIDI devices. diff -Nru a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c --- a/sound/usb/usbaudio.c Sun Mar 14 14:20:08 2004 +++ b/sound/usb/usbaudio.c Sun Mar 14 14:20:08 2004 @@ -45,7 +45,6 @@ #include #include #include -#include #include #include #include @@ -88,7 +87,7 @@ MODULE_PARM_SYNTAX(pid, SNDRV_ENABLED ",allows:{{-1,0xffff}},base:16"); MODULE_PARM(nrpacks, "i"); MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB."); -MODULE_PARM_SYNTAX(nrpacks, SNDRV_ENABLED ",allows:{{2,10}}"); +MODULE_PARM_SYNTAX(nrpacks, SNDRV_ENABLED ",allows:{{1,10}}"); MODULE_PARM(async_unlink, "i"); MODULE_PARM_DESC(async_unlink, "Use async unlink mode."); MODULE_PARM_SYNTAX(async_unlink, SNDRV_BOOLEAN_TRUE_DESC); @@ -117,7 +116,7 @@ struct list_head list; snd_pcm_format_t format; /* format type */ unsigned int channels; /* # channels */ - unsigned int nonaudio: 1; /* non-audio (type II) */ + unsigned int fmt_type; /* USB audio format type (1-3) */ unsigned int frame_size; /* samples per frame for non-audio */ int iface; /* interface number */ unsigned char altsetting; /* corresponding alternate setting */ @@ -171,7 +170,7 @@ unsigned int curpacksize; /* current packet size in bytes (for capture) */ unsigned int curframesize; /* current packet size in frames (for capture) */ unsigned int fill_max: 1; /* fill max packet size always */ - unsigned int nonaudio: 1; /* Type II format (MPEG, AC3) */ + unsigned int fmt_type; /* USB audio format type (1-3) */ unsigned int running: 1; /* running status */ @@ -201,6 +200,7 @@ snd_usb_audio_t *chip; snd_pcm_t *pcm; int pcm_index; + unsigned int fmt_type; /* USB audio format type (1-3) */ snd_usb_substream_t substream[2]; struct list_head list; }; @@ -477,7 +477,7 @@ subs->transfer_sched += counts; if (subs->transfer_sched >= runtime->period_size) { subs->transfer_sched -= runtime->period_size; - if (subs->nonaudio) { + if (subs->fmt_type == USB_FORMAT_TYPE_II) { if (subs->transfer_sched > 0) { /* FIXME: fill-max mode is not supported yet */ offs -= subs->transfer_sched; @@ -894,7 +894,7 @@ u->subs = subs; u->transfer = 0; u->packets = npacks[i]; - if (subs->nonaudio) + if (subs->fmt_type == USB_FORMAT_TYPE_II) u->packets++; /* for transfer delimiter */ if (! is_playback) { /* allocate a capture buffer per urb */ @@ -1129,15 +1129,20 @@ (! is_playback && attr == EP_ATTR_ADAPTIVE)) && altsd->bNumEndpoints >= 2) { /* check sync-pipe endpoint */ - if (get_endpoint(alts, 1)->bmAttributes != 0x01 || - get_endpoint(alts, 1)->bSynchAddress != 0) { + /* ... and check descriptor size before accessing bSynchAddress + because there is a version of the SB Audigy 2 NX firmware lacking + the audio fields in the endpoint descriptors */ + if ((get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != 0x01 || + (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && + get_endpoint(alts, 1)->bSynchAddress != 0)) { snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n", dev->devnum, fmt->iface, fmt->altsetting); return -EINVAL; } ep = get_endpoint(alts, 1)->bEndpointAddress; - if ((is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) || - (! is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN))) { + if (get_endpoint(alts, 0)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && + (( is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) || + (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)))) { snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n", dev->devnum, fmt->iface, fmt->altsetting); return -EINVAL; @@ -1588,7 +1593,7 @@ runtime->hw.channels_min = fp->channels; if (runtime->hw.channels_max < fp->channels) runtime->hw.channels_max = fp->channels; - if (fp->nonaudio && fp->frame_size > 0) { + if (fp->fmt_type == USB_FORMAT_TYPE_II && fp->frame_size > 0) { /* FIXME: there might be more than one audio formats... */ runtime->hw.period_bytes_min = runtime->hw.period_bytes_max = fp->frame_size; @@ -1832,9 +1837,11 @@ snd_iprintf(buffer, "%d ", subs->dataurb[i].packets); snd_iprintf(buffer, "]\n"); snd_iprintf(buffer, " Packet Size = %d\n", subs->curpacksize); - snd_iprintf(buffer, " Momentary freq = %d,%03d Hz\n", - subs->freqm >> 14, - ((subs->freqm & ((1 << 14) - 1)) * 1000) / ((1 << 14) - 1)); + snd_iprintf(buffer, " Momentary freq = %d.%d Hz\n", + (subs->freqm * 125) >> 11, + (subs->freqm >> 10) * 625 + + (((subs->freqm & ((1 << 10) - 1)) * 625) >> 10) + - 10 * ((subs->freqm * 125) >> 11)); } else { snd_iprintf(buffer, " Status: Stop\n"); } @@ -1886,7 +1893,9 @@ subs->dev = as->chip->dev; subs->ops = audio_urb_ops[stream]; snd_pcm_lib_preallocate_pages(as->pcm->streams[stream].substream, - 64 * 1024, 128 * 1024, GFP_ATOMIC); + SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), + 64 * 1024, 128 * 1024); snd_pcm_set_ops(as->pcm, stream, stream == SNDRV_PCM_STREAM_PLAYBACK ? &snd_usb_playback_ops : &snd_usb_capture_ops); @@ -1895,7 +1904,7 @@ subs->formats |= 1ULL << fp->format; subs->endpoint = fp->endpoint; subs->num_formats++; - subs->nonaudio = fp->nonaudio; + subs->fmt_type = fp->fmt_type; } @@ -1954,17 +1963,12 @@ list_for_each(p, &chip->pcm_list) { as = list_entry(p, snd_usb_stream_t, list); + if (as->fmt_type != fp->fmt_type) + continue; subs = &as->substream[stream]; if (! subs->endpoint) - break; + continue; if (subs->endpoint == fp->endpoint) { - if (fp->nonaudio) { - if (!subs->nonaudio || subs->formats != (1ULL << fp->format)) - continue; /* non-linear formats are handled exclusively */ - } else { - if (subs->nonaudio) - continue; - } list_add_tail(&fp->list, &subs->fmt_list); subs->num_formats++; subs->formats |= 1ULL << fp->format; @@ -1974,6 +1978,8 @@ /* look for an empty stream */ list_for_each(p, &chip->pcm_list) { as = list_entry(p, snd_usb_stream_t, list); + if (as->fmt_type != fp->fmt_type) + continue; subs = &as->substream[stream]; if (subs->endpoint) continue; @@ -1991,6 +1997,7 @@ memset(as, 0, sizeof(*as)); as->pcm_index = chip->pcm_devs; as->chip = chip; + as->fmt_type = fp->fmt_type; err = snd_pcm_new(chip->card, "USB Audio", chip->pcm_devs, stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0, stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1, @@ -2216,7 +2223,6 @@ break; } fp->channels = 1; - fp->nonaudio = 1; brate = combine_word(&fmt[4]); /* fmt[4,5] : wMaxBitRate (in kbps) */ framesize = combine_word(&fmt[6]); /* fmt[6,7]: wSamplesPerFrame */ snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize); @@ -2242,6 +2248,7 @@ dev->devnum, fp->iface, fp->altsetting, fmt[3]); return -1; } + fp->fmt_type = fmt[3]; if (err < 0) return err; #if 1 @@ -2326,6 +2333,9 @@ } csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT); + /* Creamware Noah has this descriptor after the 2nd endpoint */ + if (!csep && altsd->bNumEndpoints >= 2) + csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT); if (!csep || csep[0] < 7 || csep[2] != EP_GENERAL) { snd_printk(KERN_ERR "%d:%u:%d : no or invalid class specific endpoint descriptor\n", dev->devnum, iface_no, altno); @@ -2963,7 +2973,7 @@ static int __init snd_usb_audio_init(void) { - if (nrpacks < 2 || nrpacks > MAX_PACKS) { + if (nrpacks < MIN_PACKS_URB || nrpacks > MAX_PACKS) { printk(KERN_WARNING "invalid nrpacks value.\n"); return -EINVAL; } diff -Nru a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h --- a/sound/usb/usbaudio.h Sun Mar 14 14:20:07 2004 +++ b/sound/usb/usbaudio.h Sun Mar 14 14:20:07 2004 @@ -136,6 +136,8 @@ struct list_head midi_list; /* list of midi interfaces */ int next_midi_device; + + unsigned int ignore_ctl_error; /* for mixer */ }; /* diff -Nru a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c --- a/sound/usb/usbmidi.c Sun Mar 14 14:20:08 2004 +++ b/sound/usb/usbmidi.c Sun Mar 14 14:20:08 2004 @@ -1,7 +1,7 @@ /* * usbmidi.c - ALSA USB MIDI driver * - * Copyright (c) 2002 Clemens Ladisch + * Copyright (c) 2002-2004 Clemens Ladisch * All rights reserved. * * Based on the OSS usb-midi driver by NAGANO Daisuke, @@ -453,8 +453,16 @@ usbmidi_out_port_t* port = (usbmidi_out_port_t*)substream->runtime->private_data; port->active = up; - if (up) + if (up) { + if (port->ep->umidi->chip->shutdown) { + /* gobble up remaining bytes to prevent wait in + * snd_rawmidi_drain_output */ + while (!snd_rawmidi_transmit_empty(substream)) + snd_rawmidi_transmit_ack(substream, 1); + return; + } tasklet_hi_schedule(&port->ep->tasklet); + } } static int snd_usbmidi_input_open(snd_rawmidi_substream_t* substream) @@ -727,18 +735,118 @@ return NULL; } +/* + * This list specifies names for ports that do not fit into the standard + * "(product) MIDI (n)" schema because they aren't external MIDI ports, + * such as internal control or synthesizer ports. + */ +static struct { + __u16 vendor; + __u16 product; + int port; + const char *name_format; +} snd_usbmidi_port_names[] = { + /* Roland UA-100 */ + {0x0582, 0x0000, 2, "%s Control"}, + /* Roland SC-8850 */ + {0x0582, 0x0003, 0, "%s Part A"}, + {0x0582, 0x0003, 1, "%s Part B"}, + {0x0582, 0x0003, 2, "%s Part C"}, + {0x0582, 0x0003, 3, "%s Part D"}, + {0x0582, 0x0003, 4, "%s MIDI 1"}, + {0x0582, 0x0003, 5, "%s MIDI 2"}, + /* Roland U-8 */ + {0x0582, 0x0004, 0, "%s MIDI"}, + {0x0582, 0x0004, 1, "%s Control"}, + /* Roland SC-8820 */ + {0x0582, 0x0007, 0, "%s Part A"}, + {0x0582, 0x0007, 1, "%s Part B"}, + {0x0582, 0x0007, 2, "%s MIDI"}, + /* Roland SK-500 */ + {0x0582, 0x000b, 0, "%s Part A"}, + {0x0582, 0x000b, 1, "%s Part B"}, + {0x0582, 0x000b, 2, "%s MIDI"}, + /* Roland SC-D70 */ + {0x0582, 0x000c, 0, "%s Part A"}, + {0x0582, 0x000c, 1, "%s Part B"}, + {0x0582, 0x000c, 2, "%s MIDI"}, + /* Edirol UM-880 */ + {0x0582, 0x0014, 8, "%s Control"}, + /* Edirol SD-90 */ + {0x0582, 0x0016, 0, "%s Part A"}, + {0x0582, 0x0016, 1, "%s Part B"}, + {0x0582, 0x0016, 2, "%s MIDI 1"}, + {0x0582, 0x0016, 3, "%s MIDI 2"}, + /* Edirol UM-550 */ + {0x0582, 0x0023, 5, "%s Control"}, + /* Edirol SD-20 */ + {0x0582, 0x0027, 0, "%s Part A"}, + {0x0582, 0x0027, 1, "%s Part B"}, + {0x0582, 0x0027, 2, "%s MIDI"}, + /* Edirol SD-80 */ + {0x0582, 0x0029, 0, "%s Part A"}, + {0x0582, 0x0029, 1, "%s Part B"}, + {0x0582, 0x0029, 2, "%s MIDI 1"}, + {0x0582, 0x0029, 3, "%s MIDI 2"}, + /* Edirol UA-700 */ + {0x0582, 0x002b, 0, "%s MIDI"}, + {0x0582, 0x002b, 1, "%s Control"}, + /* Roland VariOS */ + {0x0582, 0x002f, 0, "%s MIDI"}, + {0x0582, 0x002f, 1, "%s External MIDI"}, + {0x0582, 0x002f, 2, "%s Sync"}, + /* Edirol PCR */ + {0x0582, 0x0033, 0, "%s MIDI"}, + {0x0582, 0x0033, 1, "%s 1"}, + {0x0582, 0x0033, 2, "%s 2"}, + /* BOSS GS-10 */ + {0x0582, 0x003b, 0, "%s MIDI"}, + {0x0582, 0x003b, 1, "%s Control"}, + /* Edirol UA-1000 */ + {0x0582, 0x0044, 0, "%s MIDI"}, + {0x0582, 0x0044, 1, "%s Control"}, + /* Edirol UR-80 */ + {0x0582, 0x0048, 0, "%s MIDI"}, + {0x0582, 0x0048, 1, "%s 1"}, + {0x0582, 0x0048, 2, "%s 2"}, + /* Edirol PCR-A */ + {0x0582, 0x004d, 0, "%s MIDI"}, + {0x0582, 0x004d, 1, "%s 1"}, + {0x0582, 0x004d, 2, "%s 2"}, + /* M-Audio MidiSport 8x8 */ + {0x0763, 0x1031, 8, "%s Control"}, + {0x0763, 0x1033, 8, "%s Control"}, +}; + static void snd_usbmidi_init_substream(snd_usb_midi_t* umidi, int stream, int number, snd_rawmidi_substream_t** rsubstream) { + int i; + __u16 vendor, product; + const char *name_format; + snd_rawmidi_substream_t* substream = snd_usbmidi_find_substream(umidi, stream, number); if (!substream) { snd_printd(KERN_ERR "substream %d:%d not found\n", stream, number); return; } + /* TODO: read port name from jack descriptor */ + name_format = "%s MIDI %d"; + vendor = umidi->chip->dev->descriptor.idVendor; + product = umidi->chip->dev->descriptor.idProduct; + for (i = 0; i < ARRAY_SIZE(snd_usbmidi_port_names); ++i) { + if (snd_usbmidi_port_names[i].vendor == vendor && + snd_usbmidi_port_names[i].product == product && + snd_usbmidi_port_names[i].port == number) { + name_format = snd_usbmidi_port_names[i].name_format; + break; + } + } snprintf(substream->name, sizeof(substream->name), - "%s Port %d", umidi->chip->card->shortname, number); + name_format, umidi->chip->card->shortname, number + 1); + *rsubstream = substream; } diff -Nru a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c --- a/sound/usb/usbmixer.c Sun Mar 14 14:20:06 2004 +++ b/sound/usb/usbmixer.c Sun Mar 14 14:20:06 2004 @@ -667,13 +667,11 @@ for (c = 0; c < MAX_CHANNELS; c++) { if (cval->cmask & (1 << c)) { err = get_cur_mix_value(cval, c + 1, &val); -#ifdef IGNORE_CTL_ERROR - if (err < 0) { - ucontrol->value.integer.value[0] = cval->min; - return 0; - } -#endif if (err < 0) { + if (cval->chip->ignore_ctl_error) { + ucontrol->value.integer.value[0] = cval->min; + return 0; + } snd_printd(KERN_ERR "cannot get current value for control %d ch %d: err = %d\n", cval->control, c + 1, err); return err; } @@ -685,13 +683,11 @@ } else { /* master channel */ err = get_cur_mix_value(cval, 0, &val); -#ifdef IGNORE_CTL_ERROR - if (err < 0) { - ucontrol->value.integer.value[0] = cval->min; - return 0; - } -#endif if (err < 0) { + if (cval->chip->ignore_ctl_error) { + ucontrol->value.integer.value[0] = cval->min; + return 0; + } snd_printd(KERN_ERR "cannot get current value for control %d master ch: err = %d\n", cval->control, err); return err; } @@ -713,12 +709,11 @@ for (c = 0; c < MAX_CHANNELS; c++) { if (cval->cmask & (1 << c)) { err = get_cur_mix_value(cval, c + 1, &oval); -#ifdef IGNORE_CTL_ERROR - if (err < 0) - return 0; -#endif - if (err < 0) + if (err < 0) { + if (cval->chip->ignore_ctl_error) + return 0; return err; + } val = ucontrol->value.integer.value[cnt]; val = get_abs_value(cval, val); if (oval != val) { @@ -732,10 +727,8 @@ } else { /* master channel */ err = get_cur_mix_value(cval, 0, &oval); -#ifdef IGNORE_CTL_ERROR - if (err < 0) + if (err < 0 && cval->chip->ignore_ctl_error) return 0; -#endif if (err < 0) return err; val = ucontrol->value.integer.value[0]; @@ -1025,12 +1018,10 @@ int err, val; err = get_cur_ctl_value(cval, cval->control << 8, &val); -#ifdef IGNORE_CTL_ERROR - if (err < 0) { + if (err < 0 && cval->chip->ignore_ctl_error) { ucontrol->value.integer.value[0] = cval->min; return 0; } -#endif if (err < 0) return err; val = get_relative_value(cval, val); @@ -1045,12 +1036,11 @@ int val, oval, err; err = get_cur_ctl_value(cval, cval->control << 8, &oval); -#ifdef IGNORE_CTL_ERROR - if (err < 0) - return 0; -#endif - if (err < 0) + if (err < 0) { + if (cval->chip->ignore_ctl_error) + return 0; return err; + } val = ucontrol->value.integer.value[0]; val = get_abs_value(cval, val); if (val != oval) { @@ -1274,14 +1264,13 @@ int val, err; err = get_cur_ctl_value(cval, 0, &val); -#ifdef IGNORE_CTL_ERROR if (err < 0) { - ucontrol->value.enumerated.item[0] = 0; - return 0; - } -#endif - if (err < 0) + if (cval->chip->ignore_ctl_error) { + ucontrol->value.enumerated.item[0] = 0; + return 0; + } return err; + } val = get_relative_value(cval, val); ucontrol->value.enumerated.item[0] = val; return 0; @@ -1294,12 +1283,11 @@ int val, oval, err; err = get_cur_ctl_value(cval, 0, &oval); -#ifdef IGNORE_CTL_ERROR - if (err < 0) - return 0; -#endif - if (err < 0) + if (err < 0) { + if (cval->chip->ignore_ctl_error) + return 0; return err; + } val = ucontrol->value.enumerated.item[0]; val = get_abs_value(cval, val); if (val != oval) { @@ -1509,9 +1497,13 @@ for (map = usbmix_ctl_maps; map->vendor; map++) { if (map->vendor == dev->idVendor && map->product == dev->idProduct) { state.map = map->map; + chip->ignore_ctl_error = map->ignore_ctl_error; break; } } +#ifdef IGNORE_CTL_ERROR + chip->ignore_ctl_error = 1; +#endif desc = NULL; while ((desc = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, desc, OUTPUT_TERMINAL)) != NULL) { diff -Nru a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c --- a/sound/usb/usbmixer_maps.c Sun Mar 14 14:20:08 2004 +++ b/sound/usb/usbmixer_maps.c Sun Mar 14 14:20:08 2004 @@ -30,6 +30,7 @@ int vendor; int product; const struct usbmix_name_map *map; + int ignore_ctl_error; }; /* @@ -86,6 +87,7 @@ { 26, "IEC958 Optical Playback" }, /* OT */ { 27, NULL }, /* DISABLED: EU (for what?) */ /* 28: FU speaker (mute) */ + { 29, NULL }, /* Digital Input Playback Source? */ { 0 } /* terminator */ }; @@ -117,8 +119,8 @@ */ static struct usbmix_ctl_map usbmix_ctl_maps[] = { - { 0x41e, 0x3000, extigy_map }, - { 0xc45, 0x1158, justlink_map }, + { 0x41e, 0x3000, extigy_map, 1 }, + { 0xc45, 0x1158, justlink_map, 0 }, { 0 } /* terminator */ }; diff -Nru a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h --- a/sound/usb/usbquirks.h Sun Mar 14 14:20:07 2004 +++ b/sound/usb/usbquirks.h Sun Mar 14 14:20:07 2004 @@ -104,7 +104,7 @@ #undef YAMAHA_INTERFACE /* - * Roland/RolandED/Edirol devices + * Roland/RolandED/Edirol/BOSS devices */ { USB_DEVICE(0x0582, 0x0000), @@ -196,8 +196,8 @@ .ifnum = 2, .type = QUIRK_MIDI_FIXED_ENDPOINT, .data = & (const snd_usb_midi_endpoint_info_t) { - .out_cables = 0x0003, - .in_cables = 0x0003 + .out_cables = 0x0005, + .in_cables = 0x0005 } } }, @@ -393,6 +393,32 @@ } }, { + USB_DEVICE(0x0582, 0x001b), + .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { + .vendor_name = "Roland", + .product_name = "MMP-2", + .ifnum = 2, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + } +}, +{ + USB_DEVICE(0x0582, 0x001d), + .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { + .vendor_name = "Roland", + .product_name = "V-SYNTH", + .ifnum = 0, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + } +}, +{ USB_DEVICE(0x0582, 0x0023), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "EDIROL", @@ -489,6 +515,19 @@ } }, { + USB_DEVICE(0x0582, 0x002f), + .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { + .vendor_name = "Roland", + .product_name = "VariOS", + .ifnum = 0, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0007, + .in_cables = 0x0007 + } + } +}, +{ USB_DEVICE(0x0582, 0x0033), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "EDIROL", @@ -502,6 +541,110 @@ } }, { + USB_DEVICE(0x0582, 0x0037), + .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { + .vendor_name = "Roland", + .product_name = "Digital Piano", + .ifnum = 0, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + } +}, +{ + USB_DEVICE_VENDOR_SPEC(0x0582, 0x003b), + .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { + .vendor_name = "BOSS", + .product_name = "GS-10", + .ifnum = 3, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0003, + .in_cables = 0x0003 + } + } +}, +{ + USB_DEVICE(0x0582, 0x0040), + .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { + .vendor_name = "Roland", + .product_name = "GI-20", + .ifnum = 0, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0001, + .in_cables = 0x0001 + } + } +}, +{ + USB_DEVICE(0x0582, 0x0048), + .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { + .vendor_name = "EDIROL", + .product_name = "UR-80", + .ifnum = 0, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0003, + .in_cables = 0x0007 + } + } +}, +{ + USB_DEVICE(0x0582, 0x004d), + .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { + .vendor_name = "EDIROL", + .product_name = "PCR-A", + .ifnum = 0, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0003, + .in_cables = 0x0007 + } + } +}, +{ + USB_DEVICE(0x0582, 0x0065), + .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { + .vendor_name = "EDIROL", + .product_name = "PCR-1", + .ifnum = 0, + .type = QUIRK_MIDI_FIXED_ENDPOINT, + .data = & (const snd_usb_midi_endpoint_info_t) { + .out_cables = 0x0001, + .in_cables = 0x0003 + } + } +}, +{ + /* + * This quirk is for the "Advanced Driver" mode. If off, the UA-3FX + * is standard compliant, but has only 16-bit PCM. + */ + USB_DEVICE(0x0582, 0x0050), + .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { + .vendor_name = "EDIROL", + .product_name = "UA-3FX", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = & (const snd_usb_audio_quirk_t[]) { + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 2, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = -1 + } + } + } +}, +{ USB_DEVICE(0x0582, 0x0052), .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { .vendor_name = "EDIROL", @@ -686,6 +829,16 @@ .ifnum = QUIRK_NO_INTERFACE } +}, + +{ + USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0013), + .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { + .vendor_name = "Terratec", + .product_name = "PHASE 26", + .ifnum = 3, + .type = QUIRK_MIDI_STANDARD_INTERFACE + } }, #undef USB_DEVICE_VENDOR_SPEC